~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/lib/subcmd/parse-options.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 #include <linux/compiler.h>
  3 #include <linux/string.h>
  4 #include <linux/types.h>
  5 #include <stdio.h>
  6 #include <stdlib.h>
  7 #include <stdint.h>
  8 #include <string.h>
  9 #include <ctype.h>
 10 #include "subcmd-util.h"
 11 #include "parse-options.h"
 12 #include "subcmd-config.h"
 13 #include "pager.h"
 14 
 15 #define OPT_SHORT 1
 16 #define OPT_UNSET 2
 17 
 18 char *error_buf;
 19 
 20 static int opterror(const struct option *opt, const char *reason, int flags)
 21 {
 22         if (flags & OPT_SHORT)
 23                 fprintf(stderr, " Error: switch `%c' %s", opt->short_name, reason);
 24         else if (flags & OPT_UNSET)
 25                 fprintf(stderr, " Error: option `no-%s' %s", opt->long_name, reason);
 26         else
 27                 fprintf(stderr, " Error: option `%s' %s", opt->long_name, reason);
 28 
 29         return -1;
 30 }
 31 
 32 static const char *skip_prefix(const char *str, const char *prefix)
 33 {
 34         size_t len = strlen(prefix);
 35         return strncmp(str, prefix, len) ? NULL : str + len;
 36 }
 37 
 38 static void optwarning(const struct option *opt, const char *reason, int flags)
 39 {
 40         if (flags & OPT_SHORT)
 41                 fprintf(stderr, " Warning: switch `%c' %s", opt->short_name, reason);
 42         else if (flags & OPT_UNSET)
 43                 fprintf(stderr, " Warning: option `no-%s' %s", opt->long_name, reason);
 44         else
 45                 fprintf(stderr, " Warning: option `%s' %s", opt->long_name, reason);
 46 }
 47 
 48 static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
 49                    int flags, const char **arg)
 50 {
 51         const char *res;
 52 
 53         if (p->opt) {
 54                 res = p->opt;
 55                 p->opt = NULL;
 56         } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
 57                     **(p->argv + 1) == '-')) {
 58                 res = (const char *)opt->defval;
 59         } else if (p->argc > 1) {
 60                 p->argc--;
 61                 res = *++p->argv;
 62         } else
 63                 return opterror(opt, "requires a value", flags);
 64         if (arg)
 65                 *arg = res;
 66         return 0;
 67 }
 68 
 69 static int get_value(struct parse_opt_ctx_t *p,
 70                      const struct option *opt, int flags)
 71 {
 72         const char *s, *arg = NULL;
 73         const int unset = flags & OPT_UNSET;
 74         int err;
 75 
 76         if (unset && p->opt)
 77                 return opterror(opt, "takes no value", flags);
 78         if (unset && (opt->flags & PARSE_OPT_NONEG))
 79                 return opterror(opt, "isn't available", flags);
 80         if (opt->flags & PARSE_OPT_DISABLED)
 81                 return opterror(opt, "is not usable", flags);
 82 
 83         if (opt->flags & PARSE_OPT_EXCLUSIVE) {
 84                 if (p->excl_opt && p->excl_opt != opt) {
 85                         char msg[128];
 86 
 87                         if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
 88                             p->excl_opt->long_name == NULL) {
 89                                 snprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
 90                                          p->excl_opt->short_name);
 91                         } else {
 92                                 snprintf(msg, sizeof(msg), "cannot be used with %s",
 93                                          p->excl_opt->long_name);
 94                         }
 95                         opterror(opt, msg, flags);
 96                         return -3;
 97                 }
 98                 p->excl_opt = opt;
 99         }
100         if (!(flags & OPT_SHORT) && p->opt) {
101                 switch (opt->type) {
102                 case OPTION_CALLBACK:
103                         if (!(opt->flags & PARSE_OPT_NOARG))
104                                 break;
105                         /* FALLTHROUGH */
106                 case OPTION_BOOLEAN:
107                 case OPTION_INCR:
108                 case OPTION_BIT:
109                 case OPTION_SET_UINT:
110                 case OPTION_SET_PTR:
111                         return opterror(opt, "takes no value", flags);
112                 case OPTION_END:
113                 case OPTION_ARGUMENT:
114                 case OPTION_GROUP:
115                 case OPTION_STRING:
116                 case OPTION_INTEGER:
117                 case OPTION_UINTEGER:
118                 case OPTION_LONG:
119                 case OPTION_ULONG:
120                 case OPTION_U64:
121                 default:
122                         break;
123                 }
124         }
125 
126         if (opt->flags & PARSE_OPT_NOBUILD) {
127                 char reason[128];
128                 bool noarg = false;
129 
130                 err = snprintf(reason, sizeof(reason),
131                                 opt->flags & PARSE_OPT_CANSKIP ?
132                                         "is being ignored because %s " :
133                                         "is not available because %s",
134                                 opt->build_opt);
135                 reason[sizeof(reason) - 1] = '\0';
136 
137                 if (err < 0)
138                         strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
139                                         "is being ignored" :
140                                         "is not available",
141                                         sizeof(reason));
142 
143                 if (!(opt->flags & PARSE_OPT_CANSKIP))
144                         return opterror(opt, reason, flags);
145 
146                 err = 0;
147                 if (unset)
148                         noarg = true;
149                 if (opt->flags & PARSE_OPT_NOARG)
150                         noarg = true;
151                 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
152                         noarg = true;
153 
154                 switch (opt->type) {
155                 case OPTION_BOOLEAN:
156                 case OPTION_INCR:
157                 case OPTION_BIT:
158                 case OPTION_SET_UINT:
159                 case OPTION_SET_PTR:
160                 case OPTION_END:
161                 case OPTION_ARGUMENT:
162                 case OPTION_GROUP:
163                         noarg = true;
164                         break;
165                 case OPTION_CALLBACK:
166                 case OPTION_STRING:
167                 case OPTION_INTEGER:
168                 case OPTION_UINTEGER:
169                 case OPTION_LONG:
170                 case OPTION_ULONG:
171                 case OPTION_U64:
172                 default:
173                         break;
174                 }
175 
176                 if (!noarg)
177                         err = get_arg(p, opt, flags, NULL);
178                 if (err)
179                         return err;
180 
181                 optwarning(opt, reason, flags);
182                 return 0;
183         }
184 
185         switch (opt->type) {
186         case OPTION_BIT:
187                 if (unset)
188                         *(int *)opt->value &= ~opt->defval;
189                 else
190                         *(int *)opt->value |= opt->defval;
191                 return 0;
192 
193         case OPTION_BOOLEAN:
194                 *(bool *)opt->value = unset ? false : true;
195                 if (opt->set)
196                         *(bool *)opt->set = true;
197                 return 0;
198 
199         case OPTION_INCR:
200                 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
201                 return 0;
202 
203         case OPTION_SET_UINT:
204                 *(unsigned int *)opt->value = unset ? 0 : opt->defval;
205                 return 0;
206 
207         case OPTION_SET_PTR:
208                 *(void **)opt->value = unset ? NULL : (void *)opt->defval;
209                 return 0;
210 
211         case OPTION_STRING:
212                 err = 0;
213                 if (unset)
214                         *(const char **)opt->value = NULL;
215                 else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
216                         *(const char **)opt->value = (const char *)opt->defval;
217                 else
218                         err = get_arg(p, opt, flags, (const char **)opt->value);
219 
220                 if (opt->set)
221                         *(bool *)opt->set = true;
222 
223                 /* PARSE_OPT_NOEMPTY: Allow NULL but disallow empty string. */
224                 if (opt->flags & PARSE_OPT_NOEMPTY) {
225                         const char *val = *(const char **)opt->value;
226 
227                         if (!val)
228                                 return err;
229 
230                         /* Similar to unset if we are given an empty string. */
231                         if (val[0] == '\0') {
232                                 *(const char **)opt->value = NULL;
233                                 return 0;
234                         }
235                 }
236 
237                 return err;
238 
239         case OPTION_CALLBACK:
240                 if (opt->set)
241                         *(bool *)opt->set = true;
242 
243                 if (unset)
244                         return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
245                 if (opt->flags & PARSE_OPT_NOARG)
246                         return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
247                 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
248                         return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
249                 if (get_arg(p, opt, flags, &arg))
250                         return -1;
251                 return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
252 
253         case OPTION_INTEGER:
254                 if (unset) {
255                         *(int *)opt->value = 0;
256                         return 0;
257                 }
258                 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
259                         *(int *)opt->value = opt->defval;
260                         return 0;
261                 }
262                 if (get_arg(p, opt, flags, &arg))
263                         return -1;
264                 *(int *)opt->value = strtol(arg, (char **)&s, 10);
265                 if (*s)
266                         return opterror(opt, "expects a numerical value", flags);
267                 return 0;
268 
269         case OPTION_UINTEGER:
270                 if (unset) {
271                         *(unsigned int *)opt->value = 0;
272                         return 0;
273                 }
274                 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
275                         *(unsigned int *)opt->value = opt->defval;
276                         return 0;
277                 }
278                 if (get_arg(p, opt, flags, &arg))
279                         return -1;
280                 if (arg[0] == '-')
281                         return opterror(opt, "expects an unsigned numerical value", flags);
282                 *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
283                 if (*s)
284                         return opterror(opt, "expects a numerical value", flags);
285                 return 0;
286 
287         case OPTION_LONG:
288                 if (unset) {
289                         *(long *)opt->value = 0;
290                         return 0;
291                 }
292                 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
293                         *(long *)opt->value = opt->defval;
294                         return 0;
295                 }
296                 if (get_arg(p, opt, flags, &arg))
297                         return -1;
298                 *(long *)opt->value = strtol(arg, (char **)&s, 10);
299                 if (*s)
300                         return opterror(opt, "expects a numerical value", flags);
301                 return 0;
302 
303         case OPTION_ULONG:
304                 if (unset) {
305                         *(unsigned long *)opt->value = 0;
306                         return 0;
307                 }
308                 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
309                         *(unsigned long *)opt->value = opt->defval;
310                         return 0;
311                 }
312                 if (get_arg(p, opt, flags, &arg))
313                         return -1;
314                 *(unsigned long *)opt->value = strtoul(arg, (char **)&s, 10);
315                 if (*s)
316                         return opterror(opt, "expects a numerical value", flags);
317                 return 0;
318 
319         case OPTION_U64:
320                 if (unset) {
321                         *(u64 *)opt->value = 0;
322                         return 0;
323                 }
324                 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
325                         *(u64 *)opt->value = opt->defval;
326                         return 0;
327                 }
328                 if (get_arg(p, opt, flags, &arg))
329                         return -1;
330                 if (arg[0] == '-')
331                         return opterror(opt, "expects an unsigned numerical value", flags);
332                 *(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
333                 if (*s)
334                         return opterror(opt, "expects a numerical value", flags);
335                 return 0;
336 
337         case OPTION_END:
338         case OPTION_ARGUMENT:
339         case OPTION_GROUP:
340         default:
341                 die("should not happen, someone must be hit on the forehead");
342         }
343 }
344 
345 static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
346 {
347 retry:
348         for (; options->type != OPTION_END; options++) {
349                 if (options->short_name == *p->opt) {
350                         p->opt = p->opt[1] ? p->opt + 1 : NULL;
351                         return get_value(p, options, OPT_SHORT);
352                 }
353         }
354 
355         if (options->parent) {
356                 options = options->parent;
357                 goto retry;
358         }
359 
360         return -2;
361 }
362 
363 static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
364                           const struct option *options)
365 {
366         const char *arg_end = strchr(arg, '=');
367         const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
368         int abbrev_flags = 0, ambiguous_flags = 0;
369 
370         if (!arg_end)
371                 arg_end = arg + strlen(arg);
372 
373 retry:
374         for (; options->type != OPTION_END; options++) {
375                 const char *rest;
376                 int flags = 0;
377 
378                 if (!options->long_name)
379                         continue;
380 
381                 rest = skip_prefix(arg, options->long_name);
382                 if (options->type == OPTION_ARGUMENT) {
383                         if (!rest)
384                                 continue;
385                         if (*rest == '=')
386                                 return opterror(options, "takes no value", flags);
387                         if (*rest)
388                                 continue;
389                         p->out[p->cpidx++] = arg - 2;
390                         return 0;
391                 }
392                 if (!rest) {
393                         if (strstarts(options->long_name, "no-")) {
394                                 /*
395                                  * The long name itself starts with "no-", so
396                                  * accept the option without "no-" so that users
397                                  * do not have to enter "no-no-" to get the
398                                  * negation.
399                                  */
400                                 rest = skip_prefix(arg, options->long_name + 3);
401                                 if (rest) {
402                                         flags |= OPT_UNSET;
403                                         goto match;
404                                 }
405                                 /* Abbreviated case */
406                                 if (strstarts(options->long_name + 3, arg)) {
407                                         flags |= OPT_UNSET;
408                                         goto is_abbreviated;
409                                 }
410                         }
411                         /* abbreviated? */
412                         if (!strncmp(options->long_name, arg, arg_end - arg)) {
413 is_abbreviated:
414                                 if (abbrev_option) {
415                                         /*
416                                          * If this is abbreviated, it is
417                                          * ambiguous. So when there is no
418                                          * exact match later, we need to
419                                          * error out.
420                                          */
421                                         ambiguous_option = abbrev_option;
422                                         ambiguous_flags = abbrev_flags;
423                                 }
424                                 if (!(flags & OPT_UNSET) && *arg_end)
425                                         p->opt = arg_end + 1;
426                                 abbrev_option = options;
427                                 abbrev_flags = flags;
428                                 continue;
429                         }
430                         /* negated and abbreviated very much? */
431                         if (strstarts("no-", arg)) {
432                                 flags |= OPT_UNSET;
433                                 goto is_abbreviated;
434                         }
435                         /* negated? */
436                         if (strncmp(arg, "no-", 3))
437                                 continue;
438                         flags |= OPT_UNSET;
439                         rest = skip_prefix(arg + 3, options->long_name);
440                         /* abbreviated and negated? */
441                         if (!rest && strstarts(options->long_name, arg + 3))
442                                 goto is_abbreviated;
443                         if (!rest)
444                                 continue;
445                 }
446 match:
447                 if (*rest) {
448                         if (*rest != '=')
449                                 continue;
450                         p->opt = rest + 1;
451                 }
452                 return get_value(p, options, flags);
453         }
454 
455         if (ambiguous_option) {
456                  fprintf(stderr,
457                          " Error: Ambiguous option: %s (could be --%s%s or --%s%s)\n",
458                          arg,
459                          (ambiguous_flags & OPT_UNSET) ?  "no-" : "",
460                          ambiguous_option->long_name,
461                          (abbrev_flags & OPT_UNSET) ?  "no-" : "",
462                          abbrev_option->long_name);
463                  return -1;
464         }
465         if (abbrev_option)
466                 return get_value(p, abbrev_option, abbrev_flags);
467 
468         if (options->parent) {
469                 options = options->parent;
470                 goto retry;
471         }
472 
473         return -2;
474 }
475 
476 static void check_typos(const char *arg, const struct option *options)
477 {
478         if (strlen(arg) < 3)
479                 return;
480 
481         if (strstarts(arg, "no-")) {
482                 fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)\n", arg);
483                 exit(129);
484         }
485 
486         for (; options->type != OPTION_END; options++) {
487                 if (!options->long_name)
488                         continue;
489                 if (strstarts(options->long_name, arg)) {
490                         fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)\n", arg);
491                         exit(129);
492                 }
493         }
494 }
495 
496 static void parse_options_start(struct parse_opt_ctx_t *ctx,
497                                 int argc, const char **argv, int flags)
498 {
499         memset(ctx, 0, sizeof(*ctx));
500         ctx->argc = argc - 1;
501         ctx->argv = argv + 1;
502         ctx->out  = argv;
503         ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
504         ctx->flags = flags;
505         if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
506             (flags & PARSE_OPT_STOP_AT_NON_OPTION))
507                 die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
508 }
509 
510 static int usage_with_options_internal(const char * const *,
511                                        const struct option *, int,
512                                        struct parse_opt_ctx_t *);
513 
514 static int parse_options_step(struct parse_opt_ctx_t *ctx,
515                               const struct option *options,
516                               const char * const usagestr[])
517 {
518         int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
519         int excl_short_opt = 1;
520         const char *arg;
521 
522         /* we must reset ->opt, unknown short option leave it dangling */
523         ctx->opt = NULL;
524 
525         for (; ctx->argc; ctx->argc--, ctx->argv++) {
526                 arg = ctx->argv[0];
527                 if (*arg != '-' || !arg[1]) {
528                         if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
529                                 break;
530                         ctx->out[ctx->cpidx++] = ctx->argv[0];
531                         continue;
532                 }
533 
534                 if (arg[1] != '-') {
535                         ctx->opt = ++arg;
536                         if (internal_help && *ctx->opt == 'h') {
537                                 return usage_with_options_internal(usagestr, options, 0, ctx);
538                         }
539                         switch (parse_short_opt(ctx, options)) {
540                         case -1:
541                                 return parse_options_usage(usagestr, options, arg, 1);
542                         case -2:
543                                 goto unknown;
544                         case -3:
545                                 goto exclusive;
546                         default:
547                                 break;
548                         }
549                         if (ctx->opt)
550                                 check_typos(arg, options);
551                         while (ctx->opt) {
552                                 if (internal_help && *ctx->opt == 'h')
553                                         return usage_with_options_internal(usagestr, options, 0, ctx);
554                                 arg = ctx->opt;
555                                 switch (parse_short_opt(ctx, options)) {
556                                 case -1:
557                                         return parse_options_usage(usagestr, options, arg, 1);
558                                 case -2:
559                                         /* fake a short option thing to hide the fact that we may have
560                                          * started to parse aggregated stuff
561                                          *
562                                          * This is leaky, too bad.
563                                          */
564                                         ctx->argv[0] = strdup(ctx->opt - 1);
565                                         *(char *)ctx->argv[0] = '-';
566                                         goto unknown;
567                                 case -3:
568                                         goto exclusive;
569                                 default:
570                                         break;
571                                 }
572                         }
573                         continue;
574                 }
575 
576                 if (!arg[2]) { /* "--" */
577                         if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
578                                 ctx->argc--;
579                                 ctx->argv++;
580                         }
581                         break;
582                 }
583 
584                 arg += 2;
585                 if (internal_help && !strcmp(arg, "help-all"))
586                         return usage_with_options_internal(usagestr, options, 1, ctx);
587                 if (internal_help && !strcmp(arg, "help"))
588                         return usage_with_options_internal(usagestr, options, 0, ctx);
589                 if (!strcmp(arg, "list-opts"))
590                         return PARSE_OPT_LIST_OPTS;
591                 if (!strcmp(arg, "list-cmds"))
592                         return PARSE_OPT_LIST_SUBCMDS;
593                 switch (parse_long_opt(ctx, arg, options)) {
594                 case -1:
595                         return parse_options_usage(usagestr, options, arg, 0);
596                 case -2:
597                         goto unknown;
598                 case -3:
599                         excl_short_opt = 0;
600                         goto exclusive;
601                 default:
602                         break;
603                 }
604                 continue;
605 unknown:
606                 if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
607                         return PARSE_OPT_UNKNOWN;
608                 ctx->out[ctx->cpidx++] = ctx->argv[0];
609                 ctx->opt = NULL;
610         }
611         return PARSE_OPT_DONE;
612 
613 exclusive:
614         parse_options_usage(usagestr, options, arg, excl_short_opt);
615         if ((excl_short_opt && ctx->excl_opt->short_name) ||
616             ctx->excl_opt->long_name == NULL) {
617                 char opt = ctx->excl_opt->short_name;
618                 parse_options_usage(NULL, options, &opt, 1);
619         } else {
620                 parse_options_usage(NULL, options, ctx->excl_opt->long_name, 0);
621         }
622         return PARSE_OPT_HELP;
623 }
624 
625 static int parse_options_end(struct parse_opt_ctx_t *ctx)
626 {
627         memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
628         ctx->out[ctx->cpidx + ctx->argc] = NULL;
629         return ctx->cpidx + ctx->argc;
630 }
631 
632 int parse_options_subcommand(int argc, const char **argv, const struct option *options,
633                         const char *const subcommands[], const char *usagestr[], int flags)
634 {
635         struct parse_opt_ctx_t ctx;
636         char *buf = NULL;
637 
638         /* build usage string if it's not provided */
639         if (subcommands && !usagestr[0]) {
640                 astrcatf(&buf, "%s %s [<options>] {", subcmd_config.exec_name, argv[0]);
641 
642                 for (int i = 0; subcommands[i]; i++) {
643                         if (i)
644                                 astrcat(&buf, "|");
645                         astrcat(&buf, subcommands[i]);
646                 }
647                 astrcat(&buf, "}");
648 
649                 usagestr[0] = buf;
650         }
651 
652         parse_options_start(&ctx, argc, argv, flags);
653         switch (parse_options_step(&ctx, options, usagestr)) {
654         case PARSE_OPT_HELP:
655                 exit(129);
656         case PARSE_OPT_DONE:
657                 break;
658         case PARSE_OPT_LIST_OPTS:
659                 while (options->type != OPTION_END) {
660                         if (options->long_name)
661                                 printf("--%s ", options->long_name);
662                         options++;
663                 }
664                 putchar('\n');
665                 exit(130);
666         case PARSE_OPT_LIST_SUBCMDS:
667                 if (subcommands) {
668                         for (int i = 0; subcommands[i]; i++)
669                                 printf("%s ", subcommands[i]);
670                 }
671                 putchar('\n');
672                 exit(130);
673         default: /* PARSE_OPT_UNKNOWN */
674                 if (ctx.argv[0][1] == '-')
675                         astrcatf(&error_buf, "unknown option `%s'",
676                                  ctx.argv[0] + 2);
677                 else
678                         astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt);
679                 usage_with_options(usagestr, options);
680         }
681         if (buf) {
682                 usagestr[0] = NULL;
683                 free(buf);
684         }
685         return parse_options_end(&ctx);
686 }
687 
688 int parse_options(int argc, const char **argv, const struct option *options,
689                   const char * const usagestr[], int flags)
690 {
691         return parse_options_subcommand(argc, argv, options, NULL,
692                                         (const char **) usagestr, flags);
693 }
694 
695 #define USAGE_OPTS_WIDTH 24
696 #define USAGE_GAP         2
697 
698 static void print_option_help(const struct option *opts, int full)
699 {
700         size_t pos;
701         int pad;
702 
703         if (opts->type == OPTION_GROUP) {
704                 fputc('\n', stderr);
705                 if (*opts->help)
706                         fprintf(stderr, "%s\n", opts->help);
707                 return;
708         }
709         if (!full && (opts->flags & PARSE_OPT_HIDDEN))
710                 return;
711         if (opts->flags & PARSE_OPT_DISABLED)
712                 return;
713 
714         pos = fprintf(stderr, "    ");
715         if (opts->short_name)
716                 pos += fprintf(stderr, "-%c", opts->short_name);
717         else
718                 pos += fprintf(stderr, "    ");
719 
720         if (opts->long_name && opts->short_name)
721                 pos += fprintf(stderr, ", ");
722         if (opts->long_name)
723                 pos += fprintf(stderr, "--%s", opts->long_name);
724 
725         switch (opts->type) {
726         case OPTION_ARGUMENT:
727                 break;
728         case OPTION_LONG:
729         case OPTION_ULONG:
730         case OPTION_U64:
731         case OPTION_INTEGER:
732         case OPTION_UINTEGER:
733                 if (opts->flags & PARSE_OPT_OPTARG)
734                         if (opts->long_name)
735                                 pos += fprintf(stderr, "[=<n>]");
736                         else
737                                 pos += fprintf(stderr, "[<n>]");
738                 else
739                         pos += fprintf(stderr, " <n>");
740                 break;
741         case OPTION_CALLBACK:
742                 if (opts->flags & PARSE_OPT_NOARG)
743                         break;
744                 /* FALLTHROUGH */
745         case OPTION_STRING:
746                 if (opts->argh) {
747                         if (opts->flags & PARSE_OPT_OPTARG)
748                                 if (opts->long_name)
749                                         pos += fprintf(stderr, "[=<%s>]", opts->argh);
750                                 else
751                                         pos += fprintf(stderr, "[<%s>]", opts->argh);
752                         else
753                                 pos += fprintf(stderr, " <%s>", opts->argh);
754                 } else {
755                         if (opts->flags & PARSE_OPT_OPTARG)
756                                 if (opts->long_name)
757                                         pos += fprintf(stderr, "[=...]");
758                                 else
759                                         pos += fprintf(stderr, "[...]");
760                         else
761                                 pos += fprintf(stderr, " ...");
762                 }
763                 break;
764         default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
765         case OPTION_END:
766         case OPTION_GROUP:
767         case OPTION_BIT:
768         case OPTION_BOOLEAN:
769         case OPTION_INCR:
770         case OPTION_SET_UINT:
771         case OPTION_SET_PTR:
772                 break;
773         }
774 
775         if (pos <= USAGE_OPTS_WIDTH)
776                 pad = USAGE_OPTS_WIDTH - pos;
777         else {
778                 fputc('\n', stderr);
779                 pad = USAGE_OPTS_WIDTH;
780         }
781         fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
782         if (opts->flags & PARSE_OPT_NOBUILD)
783                 fprintf(stderr, "%*s(not built-in because %s)\n",
784                         USAGE_OPTS_WIDTH + USAGE_GAP, "",
785                         opts->build_opt);
786 }
787 
788 static int option__cmp(const void *va, const void *vb)
789 {
790         const struct option *a = va, *b = vb;
791         int sa = tolower(a->short_name), sb = tolower(b->short_name), ret;
792 
793         if (sa == 0)
794                 sa = 'z' + 1;
795         if (sb == 0)
796                 sb = 'z' + 1;
797 
798         ret = sa - sb;
799 
800         if (ret == 0) {
801                 const char *la = a->long_name ?: "",
802                            *lb = b->long_name ?: "";
803                 ret = strcmp(la, lb);
804         }
805 
806         return ret;
807 }
808 
809 static struct option *options__order(const struct option *opts)
810 {
811         int nr_opts = 0, nr_group = 0, nr_parent = 0, len;
812         const struct option *o, *p = opts;
813         struct option *opt, *ordered = NULL, *group;
814 
815         /* flatten the options that have parents */
816         for (p = opts; p != NULL; p = o->parent) {
817                 for (o = p; o->type != OPTION_END; o++)
818                         ++nr_opts;
819 
820                 /*
821                  * the length is given by the number of options plus a null
822                  * terminator for the last loop iteration.
823                  */
824                 len = sizeof(*o) * (nr_opts + !o->parent);
825                 group = realloc(ordered, len);
826                 if (!group)
827                         goto out;
828                 ordered = group;
829                 memcpy(&ordered[nr_parent], p, sizeof(*o) * (nr_opts - nr_parent));
830 
831                 nr_parent = nr_opts;
832         }
833         /* copy the last OPTION_END */
834         memcpy(&ordered[nr_opts], o, sizeof(*o));
835 
836         /* sort each option group individually */
837         for (opt = group = ordered; opt->type != OPTION_END; opt++) {
838                 if (opt->type == OPTION_GROUP) {
839                         qsort(group, nr_group, sizeof(*opt), option__cmp);
840                         group = opt + 1;
841                         nr_group = 0;
842                         continue;
843                 }
844                 nr_group++;
845         }
846         qsort(group, nr_group, sizeof(*opt), option__cmp);
847 
848 out:
849         return ordered;
850 }
851 
852 static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx)
853 {
854         int i;
855 
856         for (i = 1; i < ctx->argc; ++i) {
857                 const char *arg = ctx->argv[i];
858 
859                 if (arg[0] != '-') {
860                         if (arg[1] == '\0') {
861                                 if (arg[0] == opt->short_name)
862                                         return true;
863                                 continue;
864                         }
865 
866                         if (opt->long_name && strcmp(opt->long_name, arg) == 0)
867                                 return true;
868 
869                         if (opt->help && strcasestr(opt->help, arg) != NULL)
870                                 return true;
871 
872                         continue;
873                 }
874 
875                 if (arg[1] == opt->short_name ||
876                     (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0))
877                         return true;
878         }
879 
880         return false;
881 }
882 
883 static int usage_with_options_internal(const char * const *usagestr,
884                                        const struct option *opts, int full,
885                                        struct parse_opt_ctx_t *ctx)
886 {
887         struct option *ordered;
888 
889         if (!usagestr)
890                 return PARSE_OPT_HELP;
891 
892         setup_pager();
893 
894         if (error_buf) {
895                 fprintf(stderr, "  Error: %s\n", error_buf);
896                 zfree(&error_buf);
897         }
898 
899         fprintf(stderr, "\n Usage: %s\n", *usagestr++);
900         while (*usagestr && **usagestr)
901                 fprintf(stderr, "    or: %s\n", *usagestr++);
902         while (*usagestr) {
903                 fprintf(stderr, "%s%s\n",
904                                 **usagestr ? "    " : "",
905                                 *usagestr);
906                 usagestr++;
907         }
908 
909         if (opts->type != OPTION_GROUP)
910                 fputc('\n', stderr);
911 
912         ordered = options__order(opts);
913         if (ordered)
914                 opts = ordered;
915 
916         for (  ; opts->type != OPTION_END; opts++) {
917                 if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx))
918                         continue;
919                 print_option_help(opts, full);
920         }
921 
922         fputc('\n', stderr);
923 
924         free(ordered);
925 
926         return PARSE_OPT_HELP;
927 }
928 
929 void usage_with_options(const char * const *usagestr,
930                         const struct option *opts)
931 {
932         usage_with_options_internal(usagestr, opts, 0, NULL);
933         exit(129);
934 }
935 
936 void usage_with_options_msg(const char * const *usagestr,
937                             const struct option *opts, const char *fmt, ...)
938 {
939         va_list ap;
940         char *tmp = error_buf;
941 
942         va_start(ap, fmt);
943         if (vasprintf(&error_buf, fmt, ap) == -1)
944                 die("vasprintf failed");
945         va_end(ap);
946 
947         free(tmp);
948 
949         usage_with_options_internal(usagestr, opts, 0, NULL);
950         exit(129);
951 }
952 
953 int parse_options_usage(const char * const *usagestr,
954                         const struct option *opts,
955                         const char *optstr, bool short_opt)
956 {
957         if (!usagestr)
958                 goto opt;
959 
960         fprintf(stderr, "\n Usage: %s\n", *usagestr++);
961         while (*usagestr && **usagestr)
962                 fprintf(stderr, "    or: %s\n", *usagestr++);
963         while (*usagestr) {
964                 fprintf(stderr, "%s%s\n",
965                                 **usagestr ? "    " : "",
966                                 *usagestr);
967                 usagestr++;
968         }
969         fputc('\n', stderr);
970 
971 opt:
972         for (  ; opts->type != OPTION_END; opts++) {
973                 if (short_opt) {
974                         if (opts->short_name == *optstr) {
975                                 print_option_help(opts, 0);
976                                 break;
977                         }
978                         continue;
979                 }
980 
981                 if (opts->long_name == NULL)
982                         continue;
983 
984                 if (strstarts(opts->long_name, optstr))
985                         print_option_help(opts, 0);
986                 if (strstarts("no-", optstr) &&
987                     strstarts(opts->long_name, optstr + 3))
988                         print_option_help(opts, 0);
989         }
990 
991         return PARSE_OPT_HELP;
992 }
993 
994 
995 int parse_opt_verbosity_cb(const struct option *opt,
996                            const char *arg __maybe_unused,
997                            int unset)
998 {
999         int *target = opt->value;
1000 
1001         if (unset)
1002                 /* --no-quiet, --no-verbose */
1003                 *target = 0;
1004         else if (opt->short_name == 'v') {
1005                 if (*target >= 0)
1006                         (*target)++;
1007                 else
1008                         *target = 1;
1009         } else {
1010                 if (*target <= 0)
1011                         (*target)--;
1012                 else
1013                         *target = -1;
1014         }
1015         return 0;
1016 }
1017 
1018 static struct option *
1019 find_option(struct option *opts, int shortopt, const char *longopt)
1020 {
1021         for (; opts->type != OPTION_END; opts++) {
1022                 if ((shortopt && opts->short_name == shortopt) ||
1023                     (opts->long_name && longopt &&
1024                      !strcmp(opts->long_name, longopt)))
1025                         return opts;
1026         }
1027         return NULL;
1028 }
1029 
1030 void set_option_flag(struct option *opts, int shortopt, const char *longopt,
1031                      int flag)
1032 {
1033         struct option *opt = find_option(opts, shortopt, longopt);
1034 
1035         if (opt)
1036                 opt->flags |= flag;
1037         return;
1038 }
1039 
1040 void set_option_nobuild(struct option *opts, int shortopt,
1041                         const char *longopt,
1042                         const char *build_opt,
1043                         bool can_skip)
1044 {
1045         struct option *opt = find_option(opts, shortopt, longopt);
1046 
1047         if (!opt)
1048                 return;
1049 
1050         opt->flags |= PARSE_OPT_NOBUILD;
1051         opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
1052         opt->build_opt = build_opt;
1053 }
1054 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php