From: Ian Jackson Date: Tue, 27 Apr 2010 16:35:30 +0000 (+0100) Subject: New option handling X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=inn-innduct.git;a=commitdiff_plain;h=94aac040526dc81c22957d46efcabb20bf9b8ffe New option handling --- diff --git a/backends/innduct.c b/backends/innduct.c index 858fa0e..37241d4 100644 --- a/backends/innduct.c +++ b/backends/innduct.c @@ -2500,12 +2500,19 @@ EVERY(period, -1,0, { /*========== option parsing ==========*/ -/*---------- generic option parser and logging ----------*/ - static void vbadusage(const char *fmt, va_list al) NORET_PRINTF(1,0); static void vbadusage(const char *fmt, va_list al) { - abort(); + char *m= xvasprintf(fmt,al); + fprintf(stderr, "bad usage: %s\n%s" + "say --help for help, or read the manpage\n", + m); + if (become_daemon) + syslog(LOG_CRIT,"innduct: invoked with bad usage: %s",m); + exit(8); } + +/*---------- generic option parser ----------*/ + static void badusage(const char *fmt, ...) NORET_PRINTF(1,2); static void badusage(const char *fmt, ...) { va_list al; @@ -2523,12 +2530,80 @@ typedef void OptionParser(const Option*, const char *val); struct Option { int shrt; - const char *lng; + const char *lng, *formarg; void *store; OptionParser *fn; - int noarg, intval; + int intval; }; +static void parse_options(const Option *options, char ***argvp) { + /* on return *argvp is first non-option arg; argc is not updated */ + + for (;;) { + const char *arg= *++(*argvp); + if (!arg) break; + if (*arg != '-') break; + if (!strcmp(arg,"--")) { arg= *++(*argvp); break; } + int a; + while ((a= *++arg)) { + const Option *o; + if (a=='-') { + arg++; + char *equals= strchr(arg,'='); + int len= equals ? (equals - arg) : strlen(arg); + for (o=options; o->shrt || o->lng; o++) + if (strlen(o->lng) == len && !memcmp(o->lng,arg,len)) + goto found_long; + badusage("unknown long option --%s",arg); + found_long: + if (!o->formarg) { + if (equals) badusage("option --%s does not take a value",o->lng); + arg= 0; + } else if (equals) { + arg= equals+1; + } else { + arg= *++(*argvp); + if (!arg) badusage("option --%s needs a value for %s", + o->lng, o->formarg); + } + o->fn(o, arg); + break; /* eaten the whole argument now */ + } + for (o=options; o->shrt || o->lng; o++) + if (a == o->shrt) + goto found_short; + badusage("unknown short option -%c",a); + found_short: + if (!o->formarg) { + o->fn(o,0); + } else { + if (!*++arg) { + arg= *++(*argvp); + if (!arg) badusage("option -%c needs a value for %s", + o->shrt, o->formarg); + } + o->fn(o,arg); + break; /* eaten the whole argument now */ + } + } + } +} + +#define DELIMPERHAPS(delim,str) (str) ? (delim) : "", (str) ? (str) : "" + +static void print_options(const Option *options, FILE *f) { + const Option *o; + for (o=options; o->shrt || o->lng; o++) { + char shrt[2] = { o->shrt, 0 }; + char *optspec= xasprintf("%s%s%s%s%s", + o->shrt ? "-" : "", o->shrt, + o->shrt && o->lng ? "|" : "", + DELIMPERHAPS("--", o->lng)); + fprintf(f, " %s%s%s\n", optspec, DELIMPERHAPS(" ", o->formarg)); + free(optspec); + } +} + /*---------- specific option types ----------*/ static void op_integer(const Option *o, const char *val) { @@ -2589,86 +2664,65 @@ static void op_setint(const Option *o, const char *val) { /*---------- specific options ----------*/ -static const Option options[]= { -{'f',"feedfile", &feedfile, op_string }, -{'q',"quiet-multiple", &quiet_multiple, op_setint, 1,1 }, +static void help(const Option *o, const char *val); -{ 0, "max-connections", &max_connections, op_integer }, -{ 0, "max-queue-per-conn", &max_queue_per_conn, op_integer }, +static const Option innduct_options[]= { +{'f',"feedfile", "F", &feedfile, op_string }, +{'q',"quiet-multiple", 0, &quiet_multiple, op_setint, 1 }, +{0,"help", 0, help }, +{0,"max-connections", "N", &max_connections, op_integer }, +{0,"max-queue-per-conn", "N", &max_queue_per_conn, op_integer }, -{ 0, "streaming", &try_stream, op_setint, 1,1 }, -{ 0, "no-streaming", &try_stream, op_setint, 1,0 }, -{'P',"port", &port, op_integer }, -{ 0, "inndconf", &inndconffile, op_string }, -{'d',"daemon", &become_daemon, op_setint, 1,1 }, -{ 0, "no-daemon", &become_daemon, op_setint, 1,0 }, -{ 0, "no-check-proportion", &nocheck_thresh_pct, op_double }, -{ 0, "no-check-filter", &nocheck_decay_articles, op_double }, +{0,"streaming", 0, &try_stream, op_setint, 1 }, +{0,"no-streaming", 0, &try_stream, op_setint, 0 }, +{'P',"port", "PORT",&port, op_integer }, +{0,"inndconf", "F", &inndconffile, op_string }, +{0,"no-daemon", 0, &become_daemon, op_setint, 0 }, -{ 0, "reconnect-interval", &reconnect_delay_periods, op_periods_rndup }, -{ 0, "flush-retry-interval", &flushfail_retry_periods, op_periods_rndup }, -{ 0, "inndcomm-timeout", &inndcomm_flush_timeout, op_seconds }, +{0,"no-check-proportion","PERCENT", &nocheck_thresh_pct, op_double }, +{0,"no-check-filter", "ARTICLES", &nocheck_decay_articles, op_double }, + +{0,"reconnect-interval", "TIME", &reconnect_delay_periods, op_periods_rndup }, +{0,"flush-retry-interval","TIME", &flushfail_retry_periods, op_periods_rndup }, +{0,"inndcomm-timeout", "TIME", &inndcomm_flush_timeout, op_seconds }, +{0,0} }; -int main(int argc, char **argv) { - const char *arg; +static void printusage(FILE *f) { + fputs("usage: innduct [options] site [fqdn]\n" + "available options are:\n", f); + print_options(innduct_options, f); +} - for (;;) { - arg= *++argv; - if (!arg) break; - if (*arg != '-') break; - if (!strcmp(arg,"--")) { arg= *++argv; break; } - int a; - while ((a= *++arg)) { - const Option *o; - if (a=='-') { - arg++; - char *equals= strchr(arg,'='); - int len= equals ? (equals - arg) : strlen(arg); - for (o=options; o->lng; o++) - if (strlen(o->lng) == len && !memcmp(o->lng,arg,len)) - goto found_long; - badusage("unknown long option --%s",arg); - found_long: - if (o->noarg) { - if (equals) badusage("option --%s does not take a value",o->lng); - arg= 0; - } else if (equals) { - arg= equals+1; - } else { - arg= *++argv; - if (!arg) badusage("option --%s needs a value",o->lng); - } - o->fn(o, arg); - break; /* eaten the whole argument now */ - } - for (o=options; o->lng; o++) - if (a == o->shrt) - goto found_short; - badusage("unknown short option -%c",a); - found_short: - if (o->noarg) { - o->fn(o,0); - } else { - if (!*++arg) { - arg= *++argv; - if (!arg) badusage("option -%c needs a value",o->shrt); - } - o->fn(o,arg); - break; /* eaten the whole argument now */ - } - } +static void help(const Option *o, const char *val) { + printusage(stdout); + if (ferror(stdout) || fflush(stdout)) { + perror("innduct: writing help"); + exit(12); } + exit(0); +} - if (!arg) badusage("need site name argument"); - sitename= arg; +int main(int argc, char **argv) { + if (!argv[1]) { + printusage(stderr); + exit(12); + } - if ((arg= *++argv)) - remote_host= arg; + parse_options(innduct_options, &argv); - if (*++argv) badusage("too many non-option arguments"); + /* arguments */ + + sitename= *argv++; + if (!sitename) badusage("need site name argument"); + remote_host= *argv++; + if (*argv) badusage("too many non-option arguments"); + + /* defaults */ + + if (!remote_host) remote_host= sitename; if (nocheck_thresh_pct < 0 || nocheck_thresh_pct > 100) badusage("nocheck threshold percentage must be between 0..100"); @@ -2695,6 +2749,8 @@ int main(int argc, char **argv) { if (strchr(feedfile, c)) badusage("feed filename may not contain metacharacter %c",c); + /* set things up */ + oop_source_sys *sysloop= oop_sys_new(); if (!sysloop) sysdie("could not create liboop event loop"); loop= (oop_source*)sysloop; @@ -2741,6 +2797,8 @@ int main(int argc, char **argv) { statemc_init(); + /* let's go */ + void *r= oop_sys_run(sysloop); assert(r == OOP_ERROR); sysdie("event loop failed");