int getsubopt(char **optionp, char *const *tokens, char valuep);
tokens 引き数はトークンのリストへのポインタで、リストは NULL で終端される。 getsubopt() はこのトークンを optionp 内で探す。 それぞれのトークンは、NULL 終端された 1文字以上の文字列で、 他のトークンと区別できる必要がある。 また、等号とカンマを含んではならない。
getsubopt() は呼び出されるたびに、 optionp 中の次の未処理のサブオプションの情報を返す。 サブオプション内に等号があった場合、最初の等号は そのサブオプションの名前と値の区切りと解釈される。 区切りから次のカンマ (最後のサブオプションの場合、文字列の末尾) までが、サブオプションの値となる。 サブオプションの名前が tokens 内の名前と一致し、値を表す文字列が見つかった場合、 getsubopt() は *valuep を値を表す文字列のアドレスに設定する。 optionp 中の最初のカンマはヌルバイトで上書きされる。そのため、 *valuep はそのサブオプションの「値の文字列」そのものとなる。
サブオプションが認識されたが、値を表す文字列が見つからなかった場合、 *valuep は NULL に設定される。
getsubopt() が返る時、 optionp は次のサブオプションを指している。 ちょうど最後のサブオプションが処理された場合は、 文字列末尾のヌル文字を指している。
*optionp は変更されるので、 getsubopt() を呼び出す前の最初のサブオプションは getsubopt() を呼び出し後のサブオプションと必ずしも同じとは限らない。
getsubopt() は、文字列 *optionp 中に見つけたカンマを上書きするので、文字列 *optionp は書き込み可能でなければならず、 文字列定数にすることはできない。
#define _XOPEN_SOURCE 500 #include <stdlib.h> #include <assert.h> #include <stdio.h> int main(int argc, char **argv) { enum { RO_OPT = 0, RW_OPT, NAME_OPT }; char *const token[] = { [RO_OPT] = "ro", [RW_OPT] = "rw", [NAME_OPT] = "name", NULL }; char *subopts; char *value; int opt; int readonly = 0; int readwrite = 0; char *name = NULL; int errfnd = 0; while ((opt = getopt(argc, argv, "o:")) != -1) { switch (opt) { case 'o': subopts = optarg; while (*subopts != '\0' && !errfnd) { switch (getsubopt(&subopts, token, &value)) { case RO_OPT: readonly = 1; break; case RW_OPT: readwrite = 1; break; case NAME_OPT: if (value == NULL) { fprintf(stderr, "Missing value for " "suboption '%s'\n", token[NAME_OPT]); errfnd = 1; continue; } name = value; break; default: fprintf(stderr, "No match found " "for token: /%s/\n", value); errfnd = 1; break; } } if (readwrite && readonly) { fprintf(stderr, "Only one of '%s' and '%s' can be " "specified\n", token[RO_OPT], token[RW_OPT]); errfnd = 1; } break; default: errfnd = 1; } } if (errfnd || argc == 1) { fprintf(stderr, "\nUsage: %s -o <suboptstring>\n", argv[0]); fprintf(stderr, "suboptions are 'ro', 'rw', " "and 'name=<value>'\n"); exit(EXIT_FAILURE); } /* Remainder of program... */ exit(EXIT_SUCCESS); }