upload-pack: optionally allow fetching reachable sha1
[gitweb.git] / parse-options.c
index 7b8d3faa171309e84bff23c70206a9c8bd99cc71..80106c06bcc68782baad6afa5954b829ab17ba8d 100644 (file)
@@ -14,8 +14,12 @@ static int parse_options_usage(struct parse_opt_ctx_t *ctx,
 
 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);
 }
 
@@ -127,10 +131,6 @@ static int get_value(struct parse_opt_ctx_t *p,
                *(int *)opt->value = opt->defval;
                return 0;
 
-       case OPTION_SET_PTR:
-               *(void **)opt->value = unset ? NULL : (void *)opt->defval;
-               return 0;
-
        case OPTION_STRING:
                if (unset)
                        *(const char **)opt->value = NULL;
@@ -223,13 +223,10 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
                           const struct option *options)
 {
        const struct option *all_opts = options;
-       const char *arg_end = strchr(arg, '=');
+       const char *arg_end = strchrnul(arg, '=');
        const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
        int abbrev_flags = 0, ambiguous_flags = 0;
 
-       if (!arg_end)
-               arg_end = arg + strlen(arg);
-
        for (; options->type != OPTION_END; options++) {
                const char *rest, *long_name = options->long_name;
                int flags = 0, opt_flags = 0;
@@ -238,7 +235,8 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
                        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;
@@ -287,12 +285,13 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
                                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 != '=')
@@ -352,12 +351,20 @@ static void check_typos(const char *arg, const struct option *options)
 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) ||
@@ -370,7 +377,6 @@ static void parse_options_check(const struct option *opts)
                case OPTION_BIT:
                case OPTION_NEGBIT:
                case OPTION_SET_INT:
-               case OPTION_SET_PTR:
                case OPTION_NUMBER:
                        if ((opts->flags & PARSE_OPT_OPTARG) ||
                            !(opts->flags & PARSE_OPT_NOARG))
@@ -378,6 +384,9 @@ static void parse_options_check(const struct option *opts)
                default:
                        ; /* ok. (usually accepts an argument) */
                }
+               if (opts->argh &&
+                   strcspn(opts->argh, " _") != strlen(opts->argh))
+                       err |= optbug(opts, "multi-word argh should use dash to separate words");
        }
        if (err)
                exit(128);