123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- /* Actual code to parse commandline. */
- #include <ccan/opt/opt.h>
- #include <string.h>
- #include <stdlib.h>
- #include <assert.h>
- #include "private.h"
- /* glibc does this as:
- /tmp/opt-example: invalid option -- 'x'
- /tmp/opt-example: unrecognized option '--long'
- /tmp/opt-example: option '--someflag' doesn't allow an argument
- /tmp/opt-example: option '--s' is ambiguous
- /tmp/opt-example: option requires an argument -- 's'
- */
- static int parse_err(void (*errlog)(const char *fmt, ...),
- const char *argv0, const char *arg, unsigned len,
- const char *problem)
- {
- errlog("%s: %.*s: %s", argv0, len, arg, problem);
- return -1;
- }
- static void consume_option(int *argc, char *argv[], unsigned optnum)
- {
- memmove(&argv[optnum], &argv[optnum+1],
- sizeof(argv[optnum]) * (*argc-optnum));
- (*argc)--;
- }
- /* 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");
- if (opt_table[i].type == OPT_PROCESSARG)
- opt_set_charp(optarg, opt_table[i].u.arg);
- 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;
- }
|