Merge branch 'jc/parseopt-verify-short-name'
authorJunio C Hamano <gitster@pobox.com>
Fri, 19 Sep 2014 18:38:38 +0000 (11:38 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 19 Sep 2014 18:38:38 +0000 (11:38 -0700)
Add checks for a common programming mistake to assign the same
short option name to two separate options to help developers.

* jc/parseopt-verify-short-name:
parse-options: detect attempt to add a duplicate short option name

1  2 
parse-options.c
diff --combined parse-options.c
index e7dafa80d55adb9b863c23f711389e5eaa6b2c5e,34a15aa73be1f1b68fcde19b5390ea6d2113283e..80106c06bcc68782baad6afa5954b829ab17ba8d
@@@ -14,8 -14,12 +14,12 @@@ static int parse_options_usage(struct p
  
  int optbug(const struct option *opt, const char *reason)
  {
-       if (opt->long_name)
+       if (opt->long_name) {
+               if (opt->short_name)
+                       return error("BUG: switch '%c' (--%s) %s",
+                                    opt->short_name, opt->long_name, reason);
                return error("BUG: option '%s' %s", opt->long_name, reason);
+       }
        return error("BUG: switch '%c' %s", opt->short_name, reason);
  }
  
@@@ -231,8 -235,7 +235,8 @@@ static int parse_long_opt(struct parse_
                        continue;
  
  again:
 -              rest = skip_prefix(arg, long_name);
 +              if (!skip_prefix(arg, long_name, &rest))
 +                      rest = NULL;
                if (options->type == OPTION_ARGUMENT) {
                        if (!rest)
                                continue;
@@@ -281,13 -284,12 +285,13 @@@ is_abbreviated
                                continue;
                        }
                        flags |= OPT_UNSET;
 -                      rest = skip_prefix(arg + 3, long_name);
 -                      /* abbreviated and negated? */
 -                      if (!rest && starts_with(long_name, arg + 3))
 -                              goto is_abbreviated;
 -                      if (!rest)
 -                              continue;
 +                      if (!skip_prefix(arg + 3, long_name, &rest)) {
 +                              /* abbreviated and negated? */
 +                              if (starts_with(long_name, arg + 3))
 +                                      goto is_abbreviated;
 +                              else
 +                                      continue;
 +                      }
                }
                if (*rest) {
                        if (*rest != '=')
@@@ -347,12 -349,20 +351,20 @@@ static void check_typos(const char *arg
  static void parse_options_check(const struct option *opts)
  {
        int err = 0;
+       char short_opts[128];
  
+       memset(short_opts, '\0', sizeof(short_opts));
        for (; opts->type != OPTION_END; opts++) {
                if ((opts->flags & PARSE_OPT_LASTARG_DEFAULT) &&
                    (opts->flags & PARSE_OPT_OPTARG))
                        err |= optbug(opts, "uses incompatible flags "
                                        "LASTARG_DEFAULT and OPTARG");
+               if (opts->short_name) {
+                       if (0x7F <= opts->short_name)
+                               err |= optbug(opts, "invalid short name");
+                       else if (short_opts[opts->short_name]++)
+                               err |= optbug(opts, "short name already used");
+               }
                if (opts->flags & PARSE_OPT_NODASH &&
                    ((opts->flags & PARSE_OPT_OPTARG) ||
                     !(opts->flags & PARSE_OPT_NOARG) ||