test-lib: Replace uses of $(expr ...) by POSIX shell features.
[gitweb.git] / parse-options.c
index 9eb55cc8b5182495b687e133a938937db1bc3949..cf71bcffd2e1e9aeacb44df488b0825f09d54255 100644 (file)
@@ -1,6 +1,7 @@
 #include "git-compat-util.h"
 #include "parse-options.h"
 #include "cache.h"
+#include "commit.h"
 
 #define OPT_SHORT 1
 #define OPT_UNSET 2
@@ -243,6 +244,9 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,
        ctx->out  = argv;
        ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
        ctx->flags = flags;
+       if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
+           (flags & PARSE_OPT_STOP_AT_NON_OPTION))
+               die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
 }
 
 static int usage_with_options_internal(const char * const *,
@@ -252,6 +256,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
                       const struct option *options,
                       const char * const usagestr[])
 {
+       int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
+
        /* we must reset ->opt, unknown short option leave it dangling */
        ctx->opt = NULL;
 
@@ -267,18 +273,18 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
 
                if (arg[1] != '-') {
                        ctx->opt = arg + 1;
-                       if (*ctx->opt == 'h')
+                       if (internal_help && *ctx->opt == 'h')
                                return parse_options_usage(usagestr, options);
                        switch (parse_short_opt(ctx, options)) {
                        case -1:
                                return parse_options_usage(usagestr, options);
                        case -2:
-                               return PARSE_OPT_UNKNOWN;
+                               goto unknown;
                        }
                        if (ctx->opt)
                                check_typos(arg + 1, options);
                        while (ctx->opt) {
-                               if (*ctx->opt == 'h')
+                               if (internal_help && *ctx->opt == 'h')
                                        return parse_options_usage(usagestr, options);
                                switch (parse_short_opt(ctx, options)) {
                                case -1:
@@ -291,7 +297,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
                                         */
                                        ctx->argv[0] = xstrdup(ctx->opt - 1);
                                        *(char *)ctx->argv[0] = '-';
-                                       return PARSE_OPT_UNKNOWN;
+                                       goto unknown;
                                }
                        }
                        continue;
@@ -305,16 +311,22 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
                        break;
                }
 
-               if (!strcmp(arg + 2, "help-all"))
+               if (internal_help && !strcmp(arg + 2, "help-all"))
                        return usage_with_options_internal(usagestr, options, 1);
-               if (!strcmp(arg + 2, "help"))
+               if (internal_help && !strcmp(arg + 2, "help"))
                        return parse_options_usage(usagestr, options);
                switch (parse_long_opt(ctx, arg + 2, options)) {
                case -1:
                        return parse_options_usage(usagestr, options);
                case -2:
-                       return PARSE_OPT_UNKNOWN;
+                       goto unknown;
                }
+               continue;
+unknown:
+               if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
+                       return PARSE_OPT_UNKNOWN;
+               ctx->out[ctx->cpidx++] = ctx->argv[0];
+               ctx->opt = NULL;
        }
        return PARSE_OPT_DONE;
 }
@@ -355,6 +367,9 @@ int parse_options(int argc, const char **argv, const struct option *options,
 int usage_with_options_internal(const char * const *usagestr,
                                const struct option *opts, int full)
 {
+       if (!usagestr)
+               return PARSE_OPT_HELP;
+
        fprintf(stderr, "usage: %s\n", *usagestr++);
        while (*usagestr && **usagestr)
                fprintf(stderr, "   or: %s\n", *usagestr++);
@@ -506,6 +521,22 @@ int parse_opt_verbosity_cb(const struct option *opt, const char *arg,
        return 0;
 }
 
+int parse_opt_with_commit(const struct option *opt, const char *arg, int unset)
+{
+       unsigned char sha1[20];
+       struct commit *commit;
+
+       if (!arg)
+               return -1;
+       if (get_sha1(arg, sha1))
+               return error("malformed object name %s", arg);
+       commit = lookup_commit_reference(sha1);
+       if (!commit)
+               return error("no such commit %s", arg);
+       commit_list_insert(commit, opt->value);
+       return 0;
+}
+
 /*
  * This should really be OPTION_FILENAME type as a part of
  * parse_options that take prefix to do this while parsing.