send-email: Remove superfluous `my $editor = ...'
[gitweb.git] / parse-options.c
index ae88885d4da573c85dbfbeea3061f3b026223710..cf71bcffd2e1e9aeacb44df488b0825f09d54255 100644 (file)
@@ -1,16 +1,11 @@
 #include "git-compat-util.h"
 #include "parse-options.h"
 #include "cache.h"
+#include "commit.h"
 
 #define OPT_SHORT 1
 #define OPT_UNSET 2
 
-static inline const char *skip_prefix(const char *str, const char *prefix)
-{
-       size_t len = strlen(prefix);
-       return strncmp(str, prefix, len) ? NULL : str + len;
-}
-
 static int opterror(const struct option *opt, const char *reason, int flags)
 {
        if (flags & OPT_SHORT)
@@ -28,7 +23,7 @@ static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
                p->opt = NULL;
        } else if (p->argc == 1 && (opt->flags & PARSE_OPT_LASTARG_DEFAULT)) {
                *arg = (const char *)opt->defval;
-       } else if (p->argc) {
+       } else if (p->argc > 1) {
                p->argc--;
                *arg = *++p->argv;
        } else
@@ -220,7 +215,7 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
        return -2;
 }
 
-void check_typos(const char *arg, const struct option *options)
+static void check_typos(const char *arg, const struct option *options)
 {
        if (strlen(arg) < 3)
                return;
@@ -249,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 *,
@@ -258,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;
 
@@ -273,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:
@@ -297,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;
@@ -311,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;
 }
@@ -361,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++);
@@ -489,3 +498,53 @@ int parse_opt_approxidate_cb(const struct option *opt, const char *arg,
        *(unsigned long *)(opt->value) = approxidate(arg);
        return 0;
 }
+
+int parse_opt_verbosity_cb(const struct option *opt, const char *arg,
+                          int unset)
+{
+       int *target = opt->value;
+
+       if (unset)
+               /* --no-quiet, --no-verbose */
+               *target = 0;
+       else if (opt->short_name == 'v') {
+               if (*target >= 0)
+                       (*target)++;
+               else
+                       *target = 1;
+       } else {
+               if (*target <= 0)
+                       (*target)--;
+               else
+                       *target = -1;
+       }
+       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.
+ */
+extern const char *parse_options_fix_filename(const char *prefix, const char *file)
+{
+       if (!file || !prefix || is_absolute_path(file) || !strcmp("-", file))
+               return file;
+       return prefix_filename(prefix, strlen(prefix), file);
+}
+