diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-09-26 14:18:20 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-09-26 14:18:20 +0300 |
commit | 7bc88d60ab7398631be3f85750965e812ba7ceb0 (patch) | |
tree | f1e8c86da6d78dd44a780702c2959d304b55a7d3 /build-aux/getopt.m4 | |
parent | 934c30d3ec1b443feee7dbc711b998202d40f77c (diff) | |
download | grecs-7bc88d60ab7398631be3f85750965e812ba7ceb0.tar.gz grecs-7bc88d60ab7398631be3f85750965e812ba7ceb0.tar.bz2 |
Improve getopt interface.
* build-aux/getopt.m4: Move function declarations to the library.
Introduce new options: nopermute, nousage, noversion.
* src/grecsopt.h: New file.
* src/opthelp.c: New file.
* src/Make-shared.am: Add new files.
* src/Make-static.am: Likewise.
* src/Make.am: Likewise.
Diffstat (limited to 'build-aux/getopt.m4')
-rw-r--r-- | build-aux/getopt.m4 | 544 |
1 files changed, 49 insertions, 495 deletions
diff --git a/build-aux/getopt.m4 b/build-aux/getopt.m4 index 878504d..4dd0a5a 100644 --- a/build-aux/getopt.m4 +++ b/build-aux/getopt.m4 @@ -94,7 +94,7 @@ dnl define([<upcase>], [<translit([<$*>], [<a-z>], [<A-Z>])>]) dnl concat(ARGS...) -dnl Concatenate arguments, inserting ", " between each of pair of them. +dnl Concatenate arguments, inserting ", " between each pair of them. dnl define([<concat>],[<ifelse([<$#>],1,[<$1>],[<$1, concat(shift($@))>])>]) @@ -118,8 +118,8 @@ define([<escape>], [<patsubst([<concat($*)>],[<[\"]>],[<\\\&>])>]) dnl prep(ARG) -dnl Prepare ARG for including in C strings: replace newlines with any amount -dnl of preceding and following whitespace by a single space character, remove +dnl Prepare ARG for including in C strings: replace newlines and any +dnl preceding and following whitespace by a single space character, remove dnl leading whitespace, and escape double-quotes. dnl define([<prep>], @@ -129,7 +129,7 @@ define([<prep>], dnl SHORT_OPTS dnl Accumulator for the 3rd argument of getopt_long dnl -define([<SHORT_OPTS>],[<>]) +define([<SHORT_OPTS>],[<_getopt_if_option_set([<nopermute>],+)>]) dnl GROUP(STRING) dnl Begin a named group of options @@ -263,6 +263,8 @@ define([<GETOPT>],[< { int c; + optind = 0; + opterr = 0; #ifdef HAVE_GETOPT_LONG while ((c = getopt_long($1, $2, "SHORT_OPTS", long_options, NULL)) != EOF) @@ -294,486 +296,31 @@ define([<GETOPT>],[< >]) define([<STDFUNC>],[< -divert(0) -void print_help(void); -void print_usage(void); divert(5) -const char *program_version = [<$1>]; -static char doc[] = ifelse([<$3>],,"",N_("$3")); -static char args_doc[] = ifelse([<$4>],,"",N_("$4")); -const char *program_bug_address = "<" PACKAGE_BUGREPORT ">"; -struct grecs_node *cmdline_tree; -#define DESCRCOLUMN 30 -#define RMARGIN 79 -#define GROUPCOLUMN 2 -#define USAGECOLUMN 13 - -static void -indent (size_t start, size_t col) -{ - for (; start < col; start++) - putchar (' '); -} - -static void -print_option_descr (const char *descr, size_t lmargin, size_t rmargin) -{ - while (*descr) - { - size_t s = 0; - size_t i; - size_t width = rmargin - lmargin; - - for (i = 0; ; i++) - { - if (descr[i] == 0 || descr[i] == ' ' || descr[i] == '\t') - { - if (i > width) - break; - s = i; - if (descr[i] == 0) - break; - } - } - printf ("%*.*s\n", s, s, descr); - descr += s; - if (*descr) - { - indent (0, lmargin); - descr++; - } - } -} - -#define NOPTHELP (sizeof (opthelp) / sizeof (opthelp[0])) - -static int -optcmp (const void *a, const void *b) -{ - struct opthelp const *ap = (struct opthelp const *)a; - struct opthelp const *bp = (struct opthelp const *)b; - const char *opta, *optb; - size_t alen, blen; - - for (opta = ap->opt; *opta == '-'; opta++) - ; - alen = strcspn (opta, ","); - - for (optb = bp->opt; *optb == '-'; optb++) - ; - blen = strcspn (optb, ","); - - if (alen > blen) - blen = alen; - - return strncmp (opta, optb, blen); -} - -static void -sort_options (int start, int count) -{ - qsort (opthelp + start, count, sizeof (opthelp[0]), optcmp); -} - -static int -sort_group (int start) -{ - int i; - - for (i = start; i < NOPTHELP && opthelp[i].opt; i++) - ; - sort_options (start, i - start); - return i + 1; -} - -static void -sort_opthelp (void) -{ - int start; - - for (start = 0; start < NOPTHELP; ) - { - if (!opthelp[start].opt) - start = sort_group (start + 1); - else - start = sort_group (start); - } -} - -void (*print_help_hook) (FILE *stream); - -void -print_help (void) -{ - unsigned i; - int argsused = 0; - - printf ("%s %s [%s]... %s\n", _("Usage:"), [<$2>], _("[<OPTION>]"), - args_doc[0] ? gettext (args_doc) : args_doc); - if (doc[0]) - print_option_descr(gettext (doc), 0, RMARGIN); - putchar ('\n'); - - sort_opthelp (); - for (i = 0; i < NOPTHELP; i++) - { - unsigned n; - if (opthelp[i].opt) - { - n = printf (" %s", opthelp[i].opt); - if (opthelp[i].arg) - { - char *cb, *ce; - argsused = 1; - if (strlen (opthelp[i].opt) == 2) - { - if (!opthelp[i].is_optional) - { - putchar (' '); - n++; - } - } - else - { - putchar ('='); - n++; - } - if (opthelp[i].is_optional) - { - cb = "["; - ce = "]"; - } - else - cb = ce = ""; - n += printf ("%s%s%s", cb, gettext (opthelp[i].arg), ce); - } - if (n >= DESCRCOLUMN) - { - putchar ('\n'); - n = 0; - } - indent (n, DESCRCOLUMN); - print_option_descr (gettext (opthelp[i].descr), DESCRCOLUMN, RMARGIN); - } - else - { - if (i) - putchar ('\n'); - indent (0, GROUPCOLUMN); - print_option_descr (gettext (opthelp[i].descr), - GROUPCOLUMN, RMARGIN); - putchar ('\n'); - } - } - - putchar ('\n'); -dnl ************************************************************************** -dnl This string cannot be split over serveal lines, because this would trigger -dnl a bug in GNU M4 (version 1.4.9 and 1.4.10), which would insert #line -dnl directives between the lines. -dnl ************************************************************************** - if (argsused) - { - print_option_descr (_("Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options."), 0, RMARGIN); - putchar ('\n'); - } - - if (print_help_hook) - print_help_hook (stdout); - - /* TRANSLATORS: The placeholder indicates the bug-reporting address - for this package. Please add _another line_ saying - "Report translation bugs to <...>\n" with the address for translation - bugs (typically your translation team's web or email address). */ - printf (_("Report bugs to %s.\n"), program_bug_address); - -#ifdef PACKAGE_URL - printf (_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL); -_getopt_if_option_set([<gnupackage>],[<#else - printf (_("%s home page: <http://www.gnu.org/software/%s/>\n"), - PACKAGE_NAME, PACKAGE); -#endif - fputs (_("General help using GNU software: <http://www.gnu.org/gethelp/>\n"), - stdout);>], -[<#endif>]) -} - -static int -cmpidx_short (const void *a, const void *b) -{ - unsigned const *ai = (unsigned const *)a; - unsigned const *bi = (unsigned const *)b; - - return opthelp[*ai].opt[1] - opthelp[*bi].opt[1]; -} - -#ifdef HAVE_GETOPT_LONG -static int -cmpidx_long (const void *a, const void *b) -{ - unsigned const *ai = (unsigned const *)a; - unsigned const *bi = (unsigned const *)b; - struct opthelp const *ap = opthelp + *ai; - struct opthelp const *bp = opthelp + *bi; - char const *opta, *optb; - size_t lena, lenb; - - if (ap->opt[1] == '-') - opta = ap->opt; - else - opta = ap->opt + 4; - lena = strcspn (opta, ","); - - if (bp->opt[1] == '-') - optb = bp->opt; - else - optb = bp->opt + 4; - lenb = strcspn (optb, ","); - return strncmp (opta, optb, lena > lenb ? lenb : lena); -} -#endif - -void -print_usage (void) -{ - unsigned i; - unsigned n; - char buf[RMARGIN+1]; - unsigned *idxbuf; - unsigned nidx; - -#define FLUSH dnl - do dnl - { dnl - buf[n] = 0; dnl - printf ("%s\n", buf); dnl - n = USAGECOLUMN; dnl - memset (buf, ' ', n); dnl - } dnl - while (0) -#define ADDC(c) dnl - do { if (n == RMARGIN) FLUSH; buf[n++] = c; } while (0) - - idxbuf = calloc (NOPTHELP, sizeof (idxbuf[0])); - if (!idxbuf) - { - fprintf (stderr, "not enough memory"); - abort (); - } - - n = snprintf (buf, sizeof buf, "%s %s ", _("Usage:"), [<$2>]); - - /* Print a list of short options without arguments. */ - for (i = nidx = 0; i < NOPTHELP; i++) - if (opthelp[i].opt && opthelp[i].descr && opthelp[i].opt[1] != '-' - && opthelp[i].arg == NULL) - idxbuf[nidx++] = i; - - if (nidx) - { - qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short); - - ADDC ('['); - ADDC ('-'); - for (i = 0; i < nidx; i++) - { - ADDC (opthelp[idxbuf[i]].opt[1]); - } - ADDC (']'); - } - - /* Print a list of short options with arguments. */ - for (i = nidx = 0; i < NOPTHELP; i++) - { - if (opthelp[i].opt && opthelp[i].descr && opthelp[i].opt[1] != '-' - && opthelp[i].arg) - idxbuf[nidx++] = i; - } - - if (nidx) - { - qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short); - - for (i = 0; i < nidx; i++) - { - struct opthelp *opt = opthelp + idxbuf[i]; - size_t len = 5 + strlen (opt->arg) - + (opt->is_optional ? 2 : 1); - - if (n + len > RMARGIN) FLUSH; - buf[n++] = ' '; - buf[n++] = '['; - buf[n++] = '-'; - buf[n++] = opt->opt[1]; - if (opt->is_optional) - { - buf[n++] = '['; - strcpy (&buf[n], opt->arg); - n += strlen (opt->arg); - buf[n++] = ']'; - } - else - { - buf[n++] = ' '; - strcpy (&buf[n], opt->arg); - n += strlen (opt->arg); - } - buf[n++] = ']'; - } - } - -#ifdef HAVE_GETOPT_LONG - /* Print a list of long options */ - for (i = nidx = 0; i < NOPTHELP; i++) - { - if (opthelp[i].opt && opthelp[i].descr - && (opthelp[i].opt[1] == '-' || opthelp[i].opt[2] == ',')) - idxbuf[nidx++] = i; - } - - if (nidx) - { - qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_long); - - for (i = 0; i < nidx; i++) - { - struct opthelp *opt = opthelp + idxbuf[i]; - size_t len; - const char *longopt; - - if (opt->opt[1] == '-') - longopt = opt->opt; - else if (opt->opt[2] == ',') - longopt = opt->opt + 4; - else - continue; - - len = 3 + strlen (longopt) - + (opt->arg ? 1 + strlen (opt->arg) - + (opt->is_optional ? 2 : 0) : 0); - if (n + len > RMARGIN) FLUSH; - buf[n++] = ' '; - buf[n++] = '['; - strcpy (&buf[n], longopt); - n += strlen (longopt); - if (opt->arg) - { - buf[n++] = '='; - if (opt->is_optional) - { - buf[n++] = '['; - strcpy (&buf[n], opt->arg); - n += strlen (opt->arg); - buf[n++] = ']'; - } - else - { - strcpy (&buf[n], opt->arg); - n += strlen (opt->arg); - } - } - buf[n++] = ']'; - } - } -#endif - FLUSH; - free (idxbuf); -} - -const char version_etc_copyright[] = - /* Do *not* mark this string for translation. First %s is a copyright - symbol suitable for this locale, and second %s are the copyright - years. */ - "Copyright %s %s %s"; - -void -print_version_only(const char *program_version, FILE *stream) -{ - fprintf (stream, "%s\n", program_version); - /* TRANSLATORS: Translate "(C)" to the copyright symbol - (C-in-a-circle), if this symbol is available in the user's - locale. Otherwise, do not translate "(C)"; leave it as-is. */ - fprintf (stream, version_etc_copyright, _("(C)"), - "_getopt_get_option(copyright_year, 2010)", - "_getopt_get_option(copyright_holder)"); - fputc ('\n', stream); -} - -_getopt_if_option_set([<authors>],[< -char *program_author[] = { -format_authors(_getopt_get_option(authors)) -};>]) - -void (*print_version_hook)(FILE *stream); - -void -print_version(const char *program_version, FILE *stream) -{ - _getopt_if_option_set([<authors>],[<int i; - unsigned width; - const char *written_by = _("Written by "); - /* TRANSLATORS: This string is used as a delimiter between authors' names - as in: - - Written by Winnie the Pooh, Piglet ... - */ - const char *middle_delim = _(", "); - /* TRANSLATORS: This string acts as a delimiter before the last author's - names, e.g.: - - Written by Winnie the Pooh, Piglet and Christopher Robin. - */ - const char *final_delim = _(" and "); - ->]) - print_version_only(program_version, stream); - -dnl ************************************************************************** -dnl This string cannot be split over serveal lines, because this would trigger -dnl a bug in GNU M4 (version 1.4.9 and 1.4.10), which would insert #line -dnl directives between the lines. -dnl ************************************************************************** - fputs (_("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n\n"), - stream); - if (print_version_hook) - print_version_hook (stream); -_getopt_if_option_set([<authors>],[< - width = strlen (written_by); - fputs (written_by, stream); - for (i = 0; ; ) - { - char *author = program_author[i++]; - size_t len = strlen (author); - const char *delim = NULL; - - if (program_author[i]) - { - delim = program_author[i+1] ? middle_delim : final_delim; - len += strlen (delim); - } - else - len++; - if (width + len > RMARGIN) - { - fputc ('\n', stream); - width = 0; - } - fputs (author, stream); - width += len; - if (delim) - fputs (delim, stream); - else - break; - } - fputc ('.', stream); - fputc ('\n', stream); ->]) -} +static struct grecs_proginfo proginfo = { + $2, /* progname */ + ifelse([<$3>],,"",N_("$3")), /* docstring */ + ifelse([<$4>],,"",N_("$4")), /* args_doc */ + opthelp, /* opthelp */ + sizeof(opthelp)/sizeof(opthelp[0]), /* optcount */ + NULL, /* print_help_hook */ + NULL, /* print_version_hook */ + PACKAGE_NAME, /* package */ + PACKAGE_VERSION, /* version */ + NULL, /* license */ +_getopt_if_option_set([<copyright_year>],dnl + "[<_getopt_get_option(copyright_year)>]",NULL),/* copyright_year */ +_getopt_if_option_set([<copyright_holder>],dnl + "[<_getopt_get_option(copyright_holder)>]",NULL), /* copyright_holder */ + NULL, /* *authors */ + "<" PACKAGE_BUGREPORT ">", /* bug_address */ + PACKAGE_URL, /* url */ + NULL /* epilogue */ +}; +static struct grecs_node *cmdline_tree; divert(-1) -popdef([<ADDC>]) -popdef([<FLUSH>]) >]) define([<OPTIONS_BEGIN>], @@ -789,22 +336,34 @@ _getopt_if_option_set([<gnu>],[< GROUP([<Other options>]) OPTION([<help>],h,,[<Give this help list>]) BEGIN - print_help (); - exit (0); + grecs_print_help(&proginfo); + exit(0); END - OPTION([<usage>],,,[<Give a short usage message>]) +_getopt_if_option_set([<nousage>],,[< + OPTION([<usage>],,,[<Give a short usage message>]) BEGIN - print_usage (); - exit (0); - END + grecs_print_usage(&proginfo); + exit(0); + END>]) +_getopt_if_option_set([<noversion>],,[< OPTION([<version>],V,,[<Print program version>]) BEGIN /* Give version */ - print_version(program_version, stdout); - exit (0); - END>]) + grecs_print_version(&proginfo, stdout); + exit(0); + END>])>]) divert +_getopt_if_option_set([<nostdincl>],,[< +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#ifdef HAVE_GETOPT_H +# include <getopt.h> +#endif +#include <unistd.h> +>]) #include <grecs.h> +#include <grecsopt.h> /* Option codes */ enum { _OPTION_INIT=255, @@ -817,12 +376,7 @@ static struct option long_options[] = { {0, 0, 0, 0} }; #endif -static struct opthelp { - const char *opt; - const char *arg; - int is_optional; - const char *descr; -} opthelp[] = { +static struct grecs_opthelp opthelp[] = { undivert(3) }; undivert(5) |