/* Returns 1 if argument consumed, 0 if all done, -1 on error. */ int parse_one(int *argc, char *argv[], unsigned *offset, void (*errlog)(const char *fmt, ...)) { unsigned i, arg, len; const char *o, *optarg = NULL; char *problem; if (getenv("POSIXLY_CORRECT")) { /* Don't find options after non-options. */ arg = 1; } else { for (arg = 1; argv[arg]; arg++) { if (argv[arg][0] == '-') break; } } if (!argv[arg] || argv[arg][0] != '-') return 0; /* Special arg terminator option. */ if (strcmp(argv[arg], "--") == 0) { consume_option(argc, argv, arg); return 0; } /* Long options start with -- */ if (argv[arg][1] == '-') { assert(*offset == 0); for (o = first_lopt(&i, &len); o; o = next_lopt(o, &i, &len)) { if (strncmp(argv[arg] + 2, o, len) != 0) continue; if (argv[arg][2 + len] == '=') optarg = argv[arg] + 2 + len + 1; else if (argv[arg][2 + len] != '\0') continue; break; } if (!o) return parse_err(errlog, argv[0], argv[arg], strlen(argv[arg]), "unrecognized option"); /* For error messages, we include the leading '--' */ o -= 2; len += 2; } else { /* offset allows us to handle -abc */ for (o = first_sopt(&i); o; o = next_sopt(o, &i)) { if (argv[arg][*offset + 1] != *o) continue; (*offset)++; break; } if (!o) return parse_err(errlog, argv[0], argv[arg], strlen(argv[arg]), "unrecognized option"); /* For error messages, we include the leading '-' */ o--; len = 2; } if (opt_table[i].type == OPT_NOARG) { if (optarg) return parse_err(errlog, argv[0], o, len, "doesn't allow an argument"); problem = opt_table[i].cb(opt_table[i].u.arg); } else { if (!optarg) { /* Swallow any short options as optarg, eg -afile */ if (*offset && argv[arg][*offset + 1]) { optarg = argv[arg] + *offset + 1; *offset = 0; } else optarg = argv[arg+1]; } if (!optarg) return parse_err(errlog, argv[0], o, len, "requires an argument"); problem = opt_table[i].cb_arg(optarg, opt_table[i].u.arg); } if (problem) { parse_err(errlog, argv[0], o, len, problem); free(problem); return -1; } /* If no more letters in that short opt, reset offset. */ if (*offset && !argv[arg][*offset + 1]) *offset = 0; /* All finished with that option? */ if (*offset == 0) { consume_option(argc, argv, arg); if (optarg && optarg == argv[arg]) consume_option(argc, argv, arg); } return 1; }
/* Test iterators. */ int main(int argc, char *argv[]) { unsigned j, i, len = 0; const char *p; plan_tests(37 * 2); for (j = 0; j < 2; j ++) { reset_options(); /* Giving subtable a title makes an extra entry! */ opt_register_table(subtables, j == 0 ? NULL : "subtable"); p = first_lopt(&i, &len); ok1(i == j + 0); ok1(len == 3); ok1(strncmp(p, "jjj", len) == 0); p = next_lopt(p, &i, &len); ok1(i == j + 0); ok1(len == 3); ok1(strncmp(p, "lll", len) == 0); p = next_lopt(p, &i, &len); ok1(i == j + 1); ok1(len == 3); ok1(strncmp(p, "mmm", len) == 0); p = next_lopt(p, &i, &len); ok1(i == j + 5); ok1(len == 3); ok1(strncmp(p, "ddd", len) == 0); p = next_lopt(p, &i, &len); ok1(i == j + 6); ok1(len == 3); ok1(strncmp(p, "eee", len) == 0); p = next_lopt(p, &i, &len); ok1(i == j + 7); ok1(len == 3); ok1(strncmp(p, "ggg", len) == 0); p = next_lopt(p, &i, &len); ok1(i == j + 8); ok1(len == 3); ok1(strncmp(p, "hhh", len) == 0); p = next_lopt(p, &i, &len); ok1(!p); p = first_sopt(&i); ok1(i == j + 0); ok1(*p == 'j'); p = next_sopt(p, &i); ok1(i == j + 0); ok1(*p == 'l'); p = next_sopt(p, &i); ok1(i == j + 1); ok1(*p == 'm'); p = next_sopt(p, &i); ok1(i == j + 2); ok1(*p == 'a'); p = next_sopt(p, &i); ok1(i == j + 3); ok1(*p == 'b'); p = next_sopt(p, &i); ok1(i == j + 7); ok1(*p == 'g'); p = next_sopt(p, &i); ok1(i == j + 8); ok1(*p == 'h'); p = next_sopt(p, &i); ok1(!p); } return exit_status(); }