toybox/toys/pending/getopt.c
<<
>>
Prefs
   1/* getopt.c - Parse command-line options
   2 *
   3 * Copyright 2019 The Android Open Source Project
   4
   5USE_GETOPT(NEWTOY(getopt, "^a(alternative)n:(name)o:(options)l*(long)(longoptions)Tu", TOYFLAG_USR|TOYFLAG_BIN))
   6
   7config GETOPT
   8  bool "getopt"
   9  default n
  10  help
  11    usage: getopt [OPTIONS] [--] ARG...
  12
  13    Parse command-line options for use in shell scripts.
  14
  15    -a  Allow long options starting with a single -.
  16    -l OPTS     Specify long options.
  17    -n NAME     Command name for error messages.
  18    -o OPTS     Specify short options.
  19    -T  Test whether this is a modern getopt.
  20    -u  Output options unquoted.
  21*/
  22
  23#define FOR_getopt
  24#include "toys.h"
  25
  26GLOBALS(
  27  struct arg_list *l;
  28  char *o, *n;
  29)
  30
  31static void out(char *s)
  32{
  33  if (FLAG(u)) printf(" %s", s);
  34  else {
  35    printf(" '");
  36    for (; *s; s++) {
  37      if (*s == '\'') printf("'\\''");
  38      else putchar(*s);
  39    }
  40    printf("'");
  41  }
  42}
  43
  44static char *parse_long_opt(void *data, char *str, int len)
  45{
  46  struct option **lopt_ptr = data, *lopt = *lopt_ptr;
  47
  48  // Trailing : or :: means this option takes a required or optional argument.
  49  // no_argument = 0, required_argument = 1, optional_argument = 2.
  50  for (lopt->has_arg = 0; len>0 && str[len-1] == ':'; lopt->has_arg++) len--;
  51  if (!len || lopt->has_arg>2) return str;
  52
  53  lopt->name = xstrndup(str, len);
  54
  55  (*lopt_ptr)++;
  56  return 0;
  57}
  58
  59void getopt_main(void)
  60{
  61  int argc = toys.optc+1;
  62  char **argv = xzalloc(sizeof(char *)*(argc+1));
  63  struct option *lopts = xzalloc(sizeof(struct option)*argc), *lopt = lopts;
  64  int i = 0, j = 0, ch;
  65
  66  if (FLAG(T)) {
  67    toys.exitval = 4;
  68    return;
  69  }
  70
  71  comma_args(TT.l, &lopt, "bad -l", parse_long_opt);
  72  argv[j++] = TT.n ? TT.n : "getopt";
  73
  74  // Legacy mode: don't quote output and take the first argument as OPTSTR.
  75  if (!FLAG(o)) {
  76    toys.optflags |= FLAG_u;
  77    TT.o = toys.optargs[i++];
  78    if (!TT.o) error_exit("no OPTSTR");
  79    --argc;
  80  }
  81
  82  while (i<toys.optc) argv[j++] = toys.optargs[i++];
  83
  84  // BSD getopts don't honor argv[0] (for -n), so handle errors ourselves.
  85  opterr = 0;
  86  optind = 1;
  87  while ((ch = (FLAG(a)?getopt_long_only:getopt_long)(argc, argv, TT.o,
  88          lopts, &i)) != -1) {
  89    if (ch == '?') {
  90      fprintf(stderr, "%s: invalid option '%c'\n", argv[0], optopt);
  91      toys.exitval = 1;
  92    } else if (!ch) {
  93      printf(" --%s", lopts[i].name);
  94      if (lopts[i].has_arg) out(optarg ? optarg : "");
  95    } else {
  96      printf(" -%c", ch);
  97      if (optarg) out(optarg);
  98    }
  99  }
 100
 101  printf(" --");
 102  for (; optind<argc; optind++) out(argv[optind]);
 103  printf("\n");
 104}
 105