1 /* This file is part of GDBM, the GNU data base manager.
2 Copyright (C) 2011, 2013 Free Software Foundation, Inc.
4 GDBM is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
9 GDBM is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
17 # include "autoconf.h"
20 # include "gdbmdefs.h"
33 static struct gdbm_option *option_tab;
34 static size_t option_count;
35 static size_t option_max;
36 static char *short_options;
37 static size_t short_option_count;
38 static size_t short_option_max;
39 #ifdef HAVE_GETOPT_LONG
40 static struct option *long_options;
41 static size_t long_option_count;
42 static size_t long_option_max;
47 struct gdbm_option parseopt_default_options[] = {
48 { 0, NULL, NULL, "" },
49 { 'h', "help", NULL, N_("give this help list") },
50 { 'V', "version", NULL, N_("print program version") },
51 { OPT_USAGE, "usage", NULL, N_("give a short usage message") },
55 #define OPT_END(opt) \
56 ((opt)->opt_short == 0 && (opt)->opt_long == 0 && (opt)->opt_descr == NULL)
57 #define IS_OPTION(opt) \
58 ((opt)->opt_short || (opt)->opt_long)
59 #define IS_GROUP_HEADER(opt) \
60 (!IS_OPTION(opt) && (opt)->opt_descr)
61 #define IS_VALID_SHORT_OPTION(opt) \
62 ((opt)->opt_short > 0 && (opt)->opt_short < 127 && \
63 isalnum ((opt)->opt_short))
64 #define IS_VALID_LONG_OPTION(opt) \
65 ((opt)->opt_long != NULL)
69 optcmp (const void *a, const void *b)
71 struct gdbm_option const *ap = (struct gdbm_option const *)a;
72 struct gdbm_option const *bp = (struct gdbm_option const *)b;
74 while (ap->opt_flags & PARSEOPT_ALIAS)
76 while (bp->opt_flags & PARSEOPT_ALIAS)
79 if (IS_VALID_SHORT_OPTION(ap) && IS_VALID_SHORT_OPTION(bp))
80 return ap->opt_short - bp->opt_short;
81 if (IS_VALID_LONG_OPTION(ap) && IS_VALID_LONG_OPTION(bp))
82 return strcmp (ap->opt_long, bp->opt_long);
83 if (IS_VALID_LONG_OPTION(ap))
89 sort_options (int start, int count)
91 qsort (option_tab + start, count, sizeof (option_tab[0]), optcmp);
95 sort_group (size_t start)
99 for (i = start; i < option_count && !IS_GROUP_HEADER (&option_tab[i]); i++)
101 sort_options (start, i - start);
106 sort_all_options (void)
110 /* Ensure sane start of options. This is necessary because optcmp backs up
111 until it finds an element with cleared PARSEOPT_ALIAS flag bit. */
112 option_tab[0].opt_flags &= PARSEOPT_ALIAS;
113 for (start = 0; start < option_count; )
115 if (IS_GROUP_HEADER (&option_tab[start]))
116 start = sort_group (start + 1);
118 start = sort_group (start);
123 add_options (struct gdbm_option *options)
128 struct gdbm_option *opt;
130 for (opt = options; !OPT_END(opt); opt++)
141 if (option_count + count + 1 > option_max)
143 option_max = option_count + count + 1;
144 option_tab = erealloc (option_tab,
145 sizeof (option_tab[0]) * option_max);
148 #ifdef HAVE_GETOPT_LONG
149 if (long_option_count + optcnt + 1 > long_option_max)
151 long_option_max = long_option_count + optcnt + 1;
152 long_options = erealloc (long_options,
153 sizeof (long_options[0]) * long_option_max);
156 if (short_option_count + optcnt + argcnt + 1 > short_option_max)
158 short_option_max = short_option_count + optcnt + argcnt + 1;
159 short_options = erealloc (short_options,
160 sizeof (short_options[0]) * short_option_max);
163 for (opt = options; !OPT_END(opt); opt++)
165 option_tab[option_count++] = *opt;
166 if (!IS_OPTION (opt))
168 if (IS_VALID_SHORT_OPTION (opt))
170 short_options[short_option_count++] = opt->opt_short;
172 short_options[short_option_count++] = ':';
174 #ifdef HAVE_GETOPT_LONG
175 if (IS_VALID_LONG_OPTION (opt))
177 long_options[long_option_count].name = opt->opt_long;
178 long_options[long_option_count].has_arg = opt->opt_arg != NULL;
179 long_options[long_option_count].flag = NULL;
180 long_options[long_option_count].val = opt->opt_short;
185 short_options[short_option_count] = 0;
186 #ifdef HAVE_GETOPT_LONG
187 memset (&long_options[long_option_count], 0,
188 sizeof long_options[long_option_count]);
193 parseopt_first (int pc, char **pv, struct gdbm_option *opts)
196 free (short_options);
197 short_option_count = short_option_max = 0;
198 #ifdef HAVE_GETOPT_LONG
200 long_option_count = long_option_max = 0;
203 add_options (parseopt_default_options);
207 return parseopt_next ();
211 #define DESCRCOLUMN 30
213 #define GROUPCOLUMN 2
214 #define USAGECOLUMN 13
217 indent (size_t start, size_t col)
219 for (; start < col; start++)
224 print_option_descr (const char *descr, size_t lmargin, size_t rmargin)
230 size_t width = rmargin - lmargin;
234 if (descr[i] == 0 || descr[i] == ' ' || descr[i] == '\t')
243 printf ("%*.*s\n", s, s, descr);
253 char *parseopt_program_name;
254 char *parseopt_program_doc;
255 char *parseopt_program_args;
256 const char *program_bug_address = "<" PACKAGE_BUGREPORT ">";
257 void (*parseopt_help_hook) (FILE *stream);
262 print_option (size_t num)
264 struct gdbm_option *opt = option_tab + num;
269 if (IS_GROUP_HEADER (opt))
273 indent (0, GROUPCOLUMN);
274 print_option_descr (gettext (opt->opt_descr),
275 GROUPCOLUMN, RMARGIN);
282 next < option_count && option_tab[next].opt_flags & PARSEOPT_ALIAS;
285 if (opt->opt_flags & PARSEOPT_HIDDEN)
289 for (i = num; i < next; i++)
291 if (IS_VALID_SHORT_OPTION (&option_tab[i]))
300 w += printf ("-%c", option_tab[i].opt_short);
304 #ifdef HAVE_GETOPT_LONG
305 for (i = num; i < next; i++)
307 if (IS_VALID_LONG_OPTION (&option_tab[i]))
316 w += printf ("--%s", option_tab[i].opt_long);
327 w += printf ("%c%s", delim, gettext (opt->opt_arg));
329 if (w >= DESCRCOLUMN)
334 indent (w, DESCRCOLUMN);
335 print_option_descr (gettext (opt->opt_descr), DESCRCOLUMN, RMARGIN);
341 parseopt_print_help (void)
347 printf ("%s %s [%s]... %s\n", _("Usage:"),
348 parseopt_program_name ? parseopt_program_name : progname,
350 gettext (parseopt_program_args));
351 if (parseopt_program_doc)
352 print_option_descr (gettext (parseopt_program_doc), 0, RMARGIN);
356 for (i = 0; i < option_count; )
358 i = print_option (i);
361 #ifdef HAVE_GETOPT_LONG
364 print_option_descr (_("Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options."), 0, RMARGIN);
368 if (parseopt_help_hook)
369 parseopt_help_hook (stdout);
371 /* TRANSLATORS: The placeholder indicates the bug-reporting address
372 for this package. Please add _another line_ saying
373 "Report translation bugs to <...>\n" with the address for translation
374 bugs (typically your translation team's web or email address). */
375 printf (_("Report bugs to %s.\n"), program_bug_address);
378 printf (_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
383 cmpidx_short (const void *a, const void *b)
385 unsigned const *ai = (unsigned const *)a;
386 unsigned const *bi = (unsigned const *)b;
388 return option_tab[*ai].opt_short - option_tab[*bi].opt_short;
391 #ifdef HAVE_GETOPT_LONG
393 cmpidx_long (const void *a, const void *b)
395 unsigned const *ai = (unsigned const *)a;
396 unsigned const *bi = (unsigned const *)b;
397 struct gdbm_option const *ap = option_tab + *ai;
398 struct gdbm_option const *bp = option_tab + *bi;
399 return strcmp (ap->opt_long, bp->opt_long);
416 printf ("%s\n", buf); \
418 memset (buf, ' ', n); \
424 if (n == RMARGIN) FLUSH; \
429 idxbuf = ecalloc (option_count, sizeof (idxbuf[0]));
431 n = snprintf (buf, sizeof buf, "%s %s ", _("Usage:"),
432 parseopt_program_name ? parseopt_program_name : progname);
434 /* Print a list of short options without arguments. */
435 for (i = nidx = 0; i < option_count; i++)
436 if (IS_VALID_SHORT_OPTION (&option_tab[i]) && !option_tab[i].opt_arg)
441 qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short);
445 for (i = 0; i < nidx; i++)
447 ADDC (option_tab[idxbuf[i]].opt_short);
452 /* Print a list of short options with arguments. */
453 for (i = nidx = 0; i < option_count; i++)
455 if (IS_VALID_SHORT_OPTION (&option_tab[i]) && option_tab[i].opt_arg)
461 qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short);
463 for (i = 0; i < nidx; i++)
465 struct gdbm_option *opt = option_tab + idxbuf[i];
466 const char *arg = gettext (opt->opt_arg);
467 size_t len = 5 + strlen (arg) + 1;
469 if (n + len > RMARGIN) FLUSH;
473 buf[n++] = opt->opt_short;
475 strcpy (&buf[n], arg);
481 #ifdef HAVE_GETOPT_LONG
482 /* Print a list of long options */
483 for (i = nidx = 0; i < option_count; i++)
485 if (IS_VALID_LONG_OPTION (&option_tab[i]))
491 qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_long);
493 for (i = 0; i < nidx; i++)
495 struct gdbm_option *opt = option_tab + idxbuf[i];
496 const char *arg = opt->opt_arg ? gettext (opt->opt_arg) : NULL;
497 size_t len = 3 + strlen (opt->opt_long)
498 + (arg ? 1 + strlen (arg) : 0);
499 if (n + len > RMARGIN) FLUSH;
504 strcpy (&buf[n], opt->opt_long);
505 n += strlen (opt->opt_long);
509 strcpy (&buf[n], arg);
520 const char version_etc_copyright[] =
521 /* Do *not* mark this string for translation. First %s is a copyright
522 symbol suitable for this locale, and second %s are the copyright
524 "Copyright %s %s Free Software Foundation, Inc";
526 const char license_text[] =
527 "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"
528 "This is free software: you are free to change and redistribute it.\n"
529 "There is NO WARRANTY, to the extent permitted by law.";
532 print_version_only (void)
534 printf ("%s (%s) %s\n",
535 parseopt_program_name ? parseopt_program_name : progname,
538 /* TRANSLATORS: Translate "(C)" to the copyright symbol
539 (C-in-a-circle), if this symbol is available in the user's
540 locale. Otherwise, do not translate "(C)"; leave it as-is. */
541 printf (version_etc_copyright, _("(C)"), "2011");
548 handle_option (int c)
553 parseopt_print_help ();
557 print_version_only ();
577 #ifdef HAVE_GETOPT_LONG
578 rc = getopt_long (argc, argv, short_options, long_options, NULL);
580 rc = getopt (argc, argv, short_options);
583 while (handle_option (rc));