parse-options: make some arguments optional, add callbacks.
[gitweb.git] / parse-options.c
index 57a2a1126613ad31ecb2d55c9ff37f58b42d1618..c751ebf601825c6354c6e2c7ed650f1693947a45 100644 (file)
@@ -1,6 +1,5 @@
 #include "git-compat-util.h"
 #include "parse-options.h"
-#include "strbuf.h"
 
 #define OPT_SHORT 1
 #define OPT_UNSET 2
@@ -40,7 +39,8 @@ static int opterror(const struct option *opt, const char *reason, int flags)
 static int get_value(struct optparse_t *p,
                      const struct option *opt, int flags)
 {
-       const char *s;
+       const char *s, *arg;
+       arg = p->opt ? p->opt : (p->argc > 1 ? p->argv[1] : NULL);
 
        if (p->opt && (flags & OPT_UNSET))
                return opterror(opt, "takes no value", flags);
@@ -60,17 +60,34 @@ static int get_value(struct optparse_t *p,
                        *(const char **)opt->value = (const char *)NULL;
                        return 0;
                }
-               if (!p->opt && p->argc <= 1)
+               if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-')) {
+                       *(const char **)opt->value = (const char *)opt->defval;
+                       return 0;
+               }
+               if (!arg)
                        return opterror(opt, "requires a value", flags);
                *(const char **)opt->value = get_arg(p);
                return 0;
 
+       case OPTION_CALLBACK:
+               if (flags & OPT_UNSET)
+                       return (*opt->callback)(opt, NULL, 1);
+               if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-'))
+                       return (*opt->callback)(opt, NULL, 0);
+               if (!arg)
+                       return opterror(opt, "requires a value", flags);
+               return (*opt->callback)(opt, get_arg(p), 0);
+
        case OPTION_INTEGER:
                if (flags & OPT_UNSET) {
                        *(int *)opt->value = 0;
                        return 0;
                }
-               if (!p->opt && p->argc <= 1)
+               if (opt->flags & PARSE_OPT_OPTARG && (!arg || !isdigit(*arg))) {
+                       *(int *)opt->value = opt->defval;
+                       return 0;
+               }
+               if (!arg)
                        return opterror(opt, "requires a value", flags);
                *(int *)opt->value = strtol(get_arg(p), (char **)&s, 10);
                if (*s)
@@ -172,59 +189,68 @@ int parse_options(int argc, const char **argv, const struct option *options,
 void usage_with_options(const char * const *usagestr,
                         const struct option *opts)
 {
-       struct strbuf sb;
-
-       strbuf_init(&sb, 4096);
-       strbuf_addstr(&sb, *usagestr);
-       strbuf_addch(&sb, '\n');
-       while (*++usagestr)
-               strbuf_addf(&sb, "    %s\n", *usagestr);
+       fprintf(stderr, "usage: %s\n", *usagestr++);
+       while (*usagestr && **usagestr)
+               fprintf(stderr, "   or: %s\n", *usagestr++);
+       while (*usagestr)
+               fprintf(stderr, "    %s\n", *usagestr++);
 
        if (opts->type != OPTION_GROUP)
-               strbuf_addch(&sb, '\n');
+               fputc('\n', stderr);
 
        for (; opts->type != OPTION_END; opts++) {
                size_t pos;
                int pad;
 
                if (opts->type == OPTION_GROUP) {
-                       strbuf_addch(&sb, '\n');
+                       fputc('\n', stderr);
                        if (*opts->help)
-                               strbuf_addf(&sb, "%s\n", opts->help);
+                               fprintf(stderr, "%s\n", opts->help);
                        continue;
                }
 
-               pos = sb.len;
-               strbuf_addstr(&sb, "    ");
+               pos = fprintf(stderr, "    ");
                if (opts->short_name)
-                       strbuf_addf(&sb, "-%c", opts->short_name);
+                       pos += fprintf(stderr, "-%c", opts->short_name);
                if (opts->long_name && opts->short_name)
-                       strbuf_addstr(&sb, ", ");
+                       pos += fprintf(stderr, ", ");
                if (opts->long_name)
-                       strbuf_addf(&sb, "--%s", opts->long_name);
+                       pos += fprintf(stderr, "--%s", opts->long_name);
 
                switch (opts->type) {
                case OPTION_INTEGER:
-                       strbuf_addstr(&sb, " <n>");
+                       if (opts->flags & PARSE_OPT_OPTARG)
+                               pos += fprintf(stderr, " [<n>]");
+                       else
+                               pos += fprintf(stderr, " <n>");
                        break;
                case OPTION_STRING:
-                       if (opts->argh)
-                               strbuf_addf(&sb, " <%s>", opts->argh);
-                       else
-                               strbuf_addstr(&sb, " ...");
+               case OPTION_CALLBACK:
+                       if (opts->argh) {
+                               if (opts->flags & PARSE_OPT_OPTARG)
+                                       pos += fprintf(stderr, " [<%s>]", opts->argh);
+                               else
+                                       pos += fprintf(stderr, " <%s>", opts->argh);
+                       } else {
+                               if (opts->flags & PARSE_OPT_OPTARG)
+                                       pos += fprintf(stderr, " [...]");
+                               else
+                                       pos += fprintf(stderr, " ...");
+                       }
                        break;
                default:
                        break;
                }
 
-               pad = sb.len - pos;
-               if (pad <= USAGE_OPTS_WIDTH)
-                       pad = USAGE_OPTS_WIDTH - pad;
+               if (pos <= USAGE_OPTS_WIDTH)
+                       pad = USAGE_OPTS_WIDTH - pos;
                else {
-                       strbuf_addch(&sb, '\n');
+                       fputc('\n', stderr);
                        pad = USAGE_OPTS_WIDTH;
                }
-               strbuf_addf(&sb, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
+               fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
        }
-       usage(sb.buf);
+       fputc('\n', stderr);
+
+       exit(129);
 }