getopt_long () - правильный способ его использования? - PullRequest
20 голосов
/ 20 сентября 2011

ОК, я искал и нашел следующие две темы StackOverflow, которые привели меня в правильном направлении:

Помощники синтаксического анализа аргументов для C / UNIX

Передача аргументов в программу C из командной строки

ПРИМЕЧАНИЕ. ВСЕ КОДЫ - ПСЕВДО-КОД.БУДЕТ ПОСТАВЛЯТЬ СОВМЕСТИМЫЙ КОД, КОГДА ЭТО РАБОТАЕТ.

Тем не менее, я все еще не совсем понимаю, как использовать getopt_long () в C. Программа, которую я пишу, определяется как имеющая следующие возможные теги (но может включатьстолько, сколько вам абсолютно необходимо, заполняя остальные пустыми значениями):

id3tagEd filename -title "title" -artist "artist" -year 1991 -comment "comment" -album "album" -track 1

Теперь, из того, что я прочитал, мне нужно использовать структуру для длинных опций, верно?Если это так, я написал что-то вроде этого:

struct fields field =
{
    char *[] title;
    char *[] artist;
    char *[] album;
    int year;
    char *[] comment;
    int track;
}


static struct options long_options[] =
{
    {"title", 0, &field.title, 't'},
    {"artist", 0, &field.artist, 'a'},
    {"album", 0, &field.album, 'b'},
    {"year", 0, &field.year, 'y'},
    {"comment", 0, &field.comment, 'c'},
    {"track", 0, &field.track, 'u'},
    {0, 0, 0, 0}
}

Теперь, исходя из того, что я собрал, я бы назвал это так:

int option_index = 0;

int values = getopt_long(argc, argv, "tabycu", long_options, &option_index);

Отсюда, могу ли ястрого использовать структуру поля и делать то, что мне нужно в моей программе?Однако, если это так, может кто-нибудь объяснить всю структуру long_options?Я читаю страницы руководства и тому подобное, и я просто в замешательстве.Перечитывая справочные страницы, я вижу, что могу установить переменные в null, и должны ли все мои требования к опциям устанавливать в «required_argument»?А затем установить структуры через цикл while ()?Тем не менее, я вижу, что Optarg используется.Это установлено getopt_long ()?Или это отсутствует в примере?

И еще одна проблема, у меня всегда будет безымянная обязательная опция: имя файла, я бы просто использовал argv [0], чтобы получить доступ к этому?(Так как я могу предположить, что это будет первым).

С другой стороны, это связано с проблемой домашней работы, но это не имеет никакого отношения к ее устранению, ее более важно понять.Передача аргументов и синтаксический анализ в C через командную строку.

Ответы [ 2 ]

29 голосов
/ 20 сентября 2011

Прежде всего, вы, вероятно, не хотите 0 для поля has_arg - оно должно быть одним из no_argument, required_arguemnt или optional_argument.В вашем случае все они будут required_argument.Кроме того, вы неправильно используете поле flag - это должен быть целочисленный указатель.Если установлен соответствующий флаг, getopt_long() заполнит его целым числом, которое вы передали через поле val.Я не думаю, что вам нужна эта функция вообще.Вот лучший (сокращенный) пример для вашего случая:

static struct option long_options[] =
{
    {"title", required_argument, NULL, 't'},
    {"artist", required_argument, NULL, 'a'},
    {NULL, 0, NULL, 0}
};

Затем, позже, вы можете использовать его соответствующим образом (прямо из man-страницы, я добавил несколько комментариев):

// loop over all of the options
while ((ch = getopt_long(argc, argv, "t:a:", long_options, NULL)) != -1)
{
    // check to see if a single character or long option came through
    switch (ch)
    {
         // short option 't'
         case 't':
             field.title = optarg; // or copy it if you want to
             break;
         // short option 'a'
         case 'a':
             field.artist = optarg; // or copy it if you want to
             break;
    }
}

Выможет расширяться для других ваших полей по мере необходимости (и добавить немного обработки ошибок, пожалуйста!).Примечание. Если вы хотите использовать -title и -artist, как в своем примере, вам нужно будет использовать getopt_long_only(), у которого нет коротких опций.

Что касается filename опция, вы получите это как '?' из getopt_long() вызова, так что вы можете обработать это в то время.Другие ваши варианты - требовать, чтобы это был либо первый, либо последний вариант, и обрабатывать их отдельно.

6 голосов
/ 17 июля 2014

Если вы используете библиотеку popt , вы сможете создать что-то умное, как вы делали это в своем псевдокоде:

#include <stdio.h>
#include "popt.h"

struct _field {
    char *title;
    char *artist;
    /* etc */
} field;

field.title = NULL;
field.artist = NULL;

/* HERE IS WHAT YOU WANTED IN YOUR PSEUDO-CODE */
struct poptOption optionsTable[] = {

   {"title", 't', POPT_ARG_STRING, &field.title, 't'
    "set the 'title' of the album" },
   {"artist", 'a', POPT_ARG_STRING, &field.artist, 'a'
    "set the 'artist' of the album" },
   POPT_AUTOHELP
   POPT_TABLEEND
};

poptContext optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
poptSetOtherOptionHelp(optCon, "[OPTIONS]");

char c;
while ((c = poptGetNextOpt(optCon)) >= 0) {
    switch (c) {
        case 't':
            /* do extra stuff only if you need */
            break;
        case 'a':
            /* do extra stuff only if you need */
            break;
        default:
            poptPrintUsage(optCon, stderr, 0);
            exit(1);
    }
}

if (field.title) printf("\nTitle is [%s]", field.title);
if (field.artist) printf("\nArtist is [%s]", field.artist)

Будь умнее, чем getopt;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...