はじめに
getoptの使い方を説明します。
getoptはmain関数の引数argc / argvを解析します。
argv[1]~argv[argc-1]の文字列をargument listといいます。
from Wikipedia
getopt is a C library function used to parse command-line options.
簡略化のためcommand-line optionsをoptionと表記します。
後半ではgetopt_longを説明します。
optionとは
"-"で始まる文字列はoptionです。いくつか例を示します。
commandはプログラム名です。
$ ./command -a
$ ./command -b optarg
$ ./command -b optarg nonopt
"-a" "-b"はoptionです。
"-" の後ろの1文字はoption characterです。
"a" "b"はoption-characterです。
optionにはoption argumentを指定できます。
"optarg"は"-b"のoption argumentです。
optionでもoption-argumentでもないargument-listの要素は
non-option argumentです。"nonopt"はnon-option argumentです。
option characterとoption argumentは空白なし連続して指定できます。
例えば次のように指定できます。
$ ./command -boptarg # -b optarg と同じ
$ ./command -aboptarg # -a -b optarg と同じ
getopt
getoptの関数プロトタイプと変数は次の通りです。
int getopt(
int argc,
char* const argv[],
const char* optstring
);
extern char* optarg;
extern int optind, opterr, optopt;
argc, argvはmain関数の引数です。
optstring
optstringはoption characterを表す文字列です。
例を示します。
const char* optstring = "ab:";
"a" "b"はoption characterです。
"b"はoption-argumentを持ちます。":"でそのことを示します。
$ ./command -a # OK
$ ./command -a bbb # OK bbb is non-option argument
$ ./command -accc # error invalid option
$ ./command -abbb # OK b treated as "-b". bb is option argument
$ ./command -b # error option requires an argument
$ ./command -b bbb # OK bbb is option argument
$ ./command -bbbb # OK bbb is option argument
$ ./command -c # error invalid option
optarg
getoptがoption argumentを持つoptionを解析すると、
optargにoption argumentへのポインタが設定されます。
optargを参照することでoption argumentを取得できます。
optind
optindはgetoptが次に処理するargv配列のindexです。初期値は1です。
よってgetoptの最初の呼び出しはargv[1]から解析をはじめます。
index = 1に設定することで再度argv[1]から解析を実行することができます。
opterr
opterrはエラーログの出力を制御します。
opterr != 0 : エラーログを出力する(初期値)
opterr == 0 : エラーログを出力しない
opterrに0を設定することでエラーログ出力を無効にできます。
optopt
optoptはエラーが発生したoption characterを保持します。
getoptの処理
getoptは成功するとoption characterを返します。
option-argumentありの場合、option-argumentをoptargに設定します。
エラーが発生すると'?'を返します。エラー要因は次の通りです。
- "-"で始まる文字列だがoption characterがない
- option-argumentを持つoptionであるがoption-argumentがない
次に処理するoptionがなくなれば-1を返します。
-1を返した後のoptindにはnon-option argumentがあればそれを示し、
なければargcと一致します。
例
option "-a" "-b"(option argument付き)を受けつける例を示します。
whileを-1で抜けた後、non-option argumentを処理します。
#include <stdio.h>
#include <unistd.h>
static void print_arg(int argc, char* argv[])
{
#if 0
int i;
for (i=0; i<argc; i++) {
printf("argv[%d]=%s ", i, argv[i]);
}
#endif
}
int main(int argc, char* argv[])
{
int c;
const char* optstring = "ab:" ; // optstringを定義します
opterr = 0; // disable error log
// non-option or end of argument list or error('?')までloop
while ((c=getopt(argc, argv, optstring)) != -1) {
print_arg(argc, argv);
printf("opt=%c ", c);
if (c == 'a') {
// without option argument
} else if (c == 'b') {
// with option argument
printf("optarg=%s ", optarg);
} else {
// '?'
printf("optopt=%c ", optopt);
if (optopt == 'b') {
// no option argument
} else {
// unknown option character
}
printf("\n");
return -1; // error
}
printf("\n");
}
// non-option or end of argument list
while (optind < argc) {
print_arg(argc, argv);
printf("non-opt=%s \n", argv[optind]);
optind++;
}
return 0;
}
argument listの並び替え
optionとnon-option argumentの順番を入れ替えても動作するようにするために、
argument listの並び替えを行う場合があります。
この動作は実装依存です。実装によっては並び替えしないgetoptもあります。
並び替えできる実装では(1)はOKになります。Ubuntu14.04ではOKでした。
並び替えできない実装では(1)はerrorになります。MinGWではerrorでした。
# const char* optstring = "a";
$ ./command bbb -a # (1)
getopt_long
getopt_longを説明します。この関数はlong optionを扱います。
long optionとは
"--"で始まる文字列はlong optionです。いくつか例を示します。
$ ./command --create
$ ./command --cre
$ ./command --delete value
$ ./command --delete=value
"--create" "--delete"はlong optionです。
long optionは一意に判定できる限り短くできます。
getopt_longは"--cre"は"--create"であると認識します。
long optionにはoption argumentを指定できます。
"value"は"--delete"のoption argumentです。
option argumentは"="指定できます。
"--delete=value"と"--delete value"は同じ意味です。
getopt_long
int getopt_long(
int argc,
char * const argv[],
const char *optstring,
const struct option *longopts,
int *longindex
);
struct option {
const char *name;
int has_arg; // no_argument or required_argument
int *flag;
int val;
};
argc, argv, optstringはgetoptと全く同じ意味です。
つまりgetopt_longはgetoptの機能をすべて含んでいます。
longoptsとlongindexがlong option用の引数です。
longoptsはstruct optionの配列です。配列末尾はnull terminateされます。
getopt_longは見つけたlong optionに対応するlongopts配列のindexを
longindexに設定して返します。
次にlongoptsの例を示します。
const struct option longopts[] = {
//{ *name, has_arg, *flag, val },
{ "create", no_argument, 0, 'c' },
{ "delete", required_argument, 0, 'd' },
{ "setflag", no_argument, &flag, 1 },
{ "clrflag", no_argument, &flag, 0 },
{ 0, 0, 0, 0 }, // termination
};
int longindex = 0;
nameはlong optionです "create"であれば"--create"を示します。
has_argはlong optionがoption argumentを持つかどうかを示します。
*flagが0であれば
nameが見つかるとgetopt_longはvalに指定した文字を返します。
*flagが0でなければ
nameが見つかるとgetopt_longは0を返します。
その時にflagのアドレスにvalで指定した値を設定します。
つまり上記例では
"--setflag"が指定されるとflag = 1
"--clrflag"が指定されるとflag = 0 となります。
例
#include <stdio.h>
#include <getopt.h>
static void print_arg(int argc, char* argv[])
{
#if 0
int i;
for (i=0; i<argc; i++) {
printf("argv[%d]=%s ", i, argv[i]);
}
#endif
}
int main(int argc, char* argv[])
{
int c, flag = 2;
const char* optstring = "ab:" ; // optstringを定義します
const struct option longopts[] = {
//{ *name, has_arg, *flag, val },
{ "create", no_argument, 0, 'c' },
{ "delete", required_argument, 0, 'd' },
{ "setflag", no_argument, &flag, 1 },
{ "clrflag", no_argument, &flag, 0 },
{ 0, 0, 0, 0 }, // termination
};
int longindex = 0;
opterr = 0; // disable error log
// non-option or end of argument list or error('?')までloop
while ((c=getopt_long(argc, argv, optstring, longopts, &longindex)) != -1) {
print_arg(argc, argv);
if (c == 0 || c == 'c' || c == 'd') {
const struct option* longopt = &longopts[longindex];
printf("longopt=%s ", longopt->name);
if (longopt->has_arg == required_argument) {
printf("optarg=%s ", optarg);
}
if (longopt->flag) {
printf("*flag=%d ", *longopt->flag);
}
} else {
printf("opt=%c ", c);
if (c == 'a') {
// without option argument
} else if (c == 'b') {
// with option argument
printf("optarg=%s ", optarg);
} else {
// '?'
printf("optopt=%c ", optopt);
if (optopt == 'b') {
// no option argument
} else {
// unknown option character
}
printf("\n");
return -1; // error
}
}
printf("\n");
}
// non-option or end of argument list
while (optind < argc) {
print_arg(argc, argv);
printf("non-opt=%s \n", argv[optind]);
optind++;
}
return 0;
}
reference