getopt_long() - правильный способ его использования?
Хорошо, я обыскал и нашел следующие две темы StackOverflow, которые начали меня в правильном направлении:
Аргумент-синтаксический анализ для C/UNIX
Передача аргументов в программу C из командной строки
ПРИМЕЧАНИЕ. ВСЕ КОД - PSEUDO-CODE. ПОЛУЧИТЕ ПОДЛИННЫЙ КОД, КОГДА ЭТО РАБОТАЕТ.
Тем не менее, я все еще полностью смущен тем, как использовать 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? Я читал страницы руководства и т.д., И я просто совершенно смущен. Перечитывая страницы man, я могу видеть, что я могу установить переменные в null и должен ли устанавливать все мои требования к параметрам "required_argument"? А затем установка структур через цикл while()? Тем не менее, я вижу, что optarg используется. Установлено ли это getopt_long()? Или это отсутствует в примере?
И последний вопрос, у меня всегда будет необязательная опция: filename, я бы просто использовал argv [0], чтобы получить доступ к этому? (Поскольку я могу предположить, что это будет первым).
С другой стороны, это связано с проблемой домашней работы, но это не имеет никакого отношения к ее исправлению, ее более фундаментальному, необходимо понять передачу аргументов и синтаксический анализ в C по командной строке.
Ответы
Ответ 1
Во-первых, вы, вероятно, не хотите 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()
, чтобы вы могли обработать его в это время. Ваши другие параметры требуют, чтобы он был первым или последним вариантом и обрабатывал его отдельно.
Ответ 2
Если вы используете 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;)