getopt_long () и параметры, которые не являются флагами? - PullRequest
0 голосов
/ 09 сентября 2010

Я пытаюсь использовать функцию getopt_long() только в первый раз, у меня проблемы с аргументами, которые не являются флагами. Например, в моем коде, когда задан неизвестный аргумент, я хочу использовать его в качестве входного файла. Когда я запускаю его только с именем файла, он не печатается, если я сначала использую флаг, любой флаг, то я могу его распечатать.

Как я могу это исправить?

 #include <stdio.h>
 #include <getopt.h>

 static struct option long_options[] = {
  {"help",  no_argument,       0, 'h'},
  {"input",  required_argument, 0, 'i'},
  {"output",  required_argument, 0, 'o'},
  {"algorithm",  required_argument, 0, 'a'},
  {0, 0, 0, 0}
 };

 int main(int argc, char *argv[]) {
  int c;
  int option_index = 0;

  while(42) {
   c = getopt_long(argc, argv, "hi:o:a:", long_options, 
     &option_index);
   if(c == -1)
    break;

   switch(c) {
    case 'h': /* --help */
     printf("--help flag\n");
     break;
    case 'i': /* --input */
     printf("--input flag\n");
     break;
    case 'o': /* --output */
     printf("--output flag\n");
     break;
    case 'a': /* --algorithm */
     printf("--algorithm flag \n");
     break;
    default: /* ??? */
     fprintf(stderr, "Invalid option");
     return 1;
   }

   if(optind < argc) {
    printf("other arguments: ");

    while(optind < argc) {
     printf ("%s ", argv[optind]);
     optind++;
    }

    printf("\n");
   }
  }

  return 0;
 }

Ответы [ 2 ]

5 голосов
/ 10 сентября 2010

Цикл должен содержать только переключатель. Обработайте остаточные аргументы в отдельном (не вложенном) цикле:

#include <stdio.h>
#include <getopt.h>

static struct option long_options[] =
{
    {"help",  no_argument,       0, 'h'},
    {"input",  required_argument, 0, 'i'},
    {"output",  required_argument, 0, 'o'},
    {"algorithm",  required_argument, 0, 'a'},
    {0, 0, 0, 0}
};

int main(int argc, char *argv[])
{
    int opt;
    int option_index = 0;
    int i;

    while ((opt = getopt_long(argc, argv, "hi:o:a:", long_options, &option_index)) != -1)
    {
        switch(opt)
        {
            case 'h': /* --help */
                printf("--help flag\n");
                break;
            case 'i': /* --input */
                printf("--input flag (%s)\n", optarg);
                break;
            case 'o': /* --output */
                printf("--output flag (%s)\n", optarg);
                break;
            case 'a': /* --algorithm */
                printf("--algorithm flag (%s)\n", optarg);
                break;
            default: /* ??? */
                fprintf(stderr, "Invalid option %c\n", opt);
                return 1;
        }
    }

    for (i = optind; i < argc; i++)
        printf("Process: %s\n", argv[i]);

    return 0;
}

Есть способ заставить GNU getopt() и getopt_long() возвращать аргументы имени файла, как если бы они были опциями с 'letter' ^ A '\ 1'; используйте '-' в качестве первого символа строки коротких опций и ловите '\1' в переключателе; значение optarg является именем файла.

#include <stdio.h>
#include <getopt.h>

static struct option long_options[] =
{
    {"help",  no_argument,       0, 'h'},
    {"input",  required_argument, 0, 'i'},
    {"output",  required_argument, 0, 'o'},
    {"algorithm",  required_argument, 0, 'a'},
    {0, 0, 0, 0}
};

int main(int argc, char *argv[])
{
    int opt;
    int option_index = 0;
    int i;

    while ((opt = getopt_long(argc, argv, "-hi:o:a:", long_options, &option_index)) != -1)
    {
        switch(opt)
        {
            case 'h': /* --help */
                printf("--help flag\n");
                break;
            case 'i': /* --input */
                printf("--input flag (%s)\n", optarg);
                break;
            case 'o': /* --output */
                printf("--output flag (%s)\n", optarg);
                break;
            case 'a': /* --algorithm */
                printf("--algorithm flag (%s)\n", optarg);
                break;
            case '\1':
                printf("File: %s\n", optarg);
                break;
            default: /* ??? */
                fprintf(stderr, "Invalid option %c\n", opt);
                return 1;
        }
    }

    for (i = optind; i < argc; i++)
        printf("Process: %s\n", argv[i]);

    return 0;
}

Однако вам нужен цикл после цикла обработки аргументов в случае, если ваш странный пользователь наберет:

program -- abc def

-- 'завершает цикл while() без обработки аргументов имени файла.

3 голосов
/ 10 сентября 2010

Это не работает, потому что вы выходите из внешнего цикла while, когда getopt_long возвращает -1 (что указывает на то, что больше нет вариантов).

Вам необходимо вывести блок if (optind < argc) из внешнего цикла while; это не принадлежит там так или иначе. Это может быть понятнее, если вы написали этот внешний цикл while как:

while ((c = getopt_long(...)) != -1)
{
    switch (c)
    {
        /* Deal with flags. */
    }
}
...