1 /* [argparse.c wk 17.06.97] Argument Parser for option handling
2 * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
3 * Copyright (C) 1997-2001, 2006-2008, 2013-2017 Werner Koch
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify it
8 * under the terms of either
10 * - the GNU Lesser General Public License as published by the Free
11 * Software Foundation; either version 3 of the License, or (at
12 * your option) any later version.
16 * - the GNU General Public License as published by the Free
17 * Software Foundation; either version 2 of the License, or (at
18 * your option) any later version.
20 * or both in parallel, as here.
22 * GnuPG is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
27 * You should have received a copies of the GNU General Public License
28 * and the GNU Lesser General Public License along with this program;
29 * if not, see <https://gnu.org/licenses/>.
32 /* This file may be used as part of GnuPG or standalone. A GnuPG
33 build is detected by the presence of the macro GNUPG_MAJOR_VERSION.
34 Some feature are only availalbe in the GnuPG build mode.
49 #ifdef GNUPG_MAJOR_VERSION
51 # include "common-defs.h"
53 # include "mischelp.h"
54 # include "stringhelp.h"
56 # include "utf8conv.h"
57 #endif /*GNUPG_MAJOR_VERSION*/
61 /* GnuPG uses GPLv3+ but a standalone version of this defaults to
62 GPLv2+ because that is the license of this file. Change this if
63 you include it in a program which uses GPLv3. If you don't want to
64 set a a copyright string for your usage() you may also hardcode it
66 #ifndef GNUPG_MAJOR_VERSION
68 # define ARGPARSE_GPL_VERSION 2
69 # define ARGPARSE_CRIGHT_STR "Copyright (C) YEAR NAME"
71 #else /* Used by GnuPG */
73 # define ARGPARSE_GPL_VERSION 3
74 # define ARGPARSE_CRIGHT_STR "Copyright (C) 2017 Free Software Foundation, Inc."
76 #endif /*GNUPG_MAJOR_VERSION*/
78 /* Replacements for standalone builds. */
79 #ifndef GNUPG_MAJOR_VERSION
84 # define DIM(v) (sizeof(v)/sizeof((v)[0]))
86 # define xtrymalloc(a) malloc ((a))
87 # define xtryrealloc(a,b) realloc ((a), (b))
88 # define xtrystrdup(a) strdup ((a))
89 # define xfree(a) free ((a))
90 # define log_error my_log_error
91 # define log_bug my_log_bug
92 # define trim_spaces(a) my_trim_spaces ((a))
93 # define map_static_macro_string(a) (a)
94 #endif /*!GNUPG_MAJOR_VERSION*/
97 #define ARGPARSE_STR(v) #v
98 #define ARGPARSE_STR2(v) ARGPARSE_STR(v)
101 /* Replacements for standalone builds. */
102 #ifndef GNUPG_MAJOR_VERSION
104 my_log_error (const char *fmt, ...)
108 va_start (arg_ptr, fmt);
109 fprintf (stderr, "%s: ", strusage (11));
110 vfprintf (stderr, fmt, arg_ptr);
115 my_log_bug (const char *fmt, ...)
119 va_start (arg_ptr, fmt);
120 fprintf (stderr, "%s: Ohhhh jeeee: ", strusage (11));
121 vfprintf (stderr, fmt, arg_ptr);
126 /* Return true if the native charset is utf-8. */
128 is_native_utf8 (void)
134 my_trim_spaces (char *str)
136 char *string, *p, *mark;
139 /* Find first non space character. */
140 for (p=string; *p && isspace (*(unsigned char*)p) ; p++)
142 /* Move characters. */
143 for ((mark = NULL); (*string = *p); string++, p++)
144 if (isspace (*(unsigned char*)p))
152 *mark = '\0' ; /* Remove trailing spaces. */
157 #endif /*!GNUPG_MAJOR_VERSION*/
161 /*********************************
163 * #include "argparse.h"
166 * char *argc; pointer to argc (value subject to change)
167 * char ***argv; pointer to argv (value subject to change)
168 * unsigned flags; Global flags (DO NOT CHANGE)
169 * int err; print error about last option
170 * 1 = warning, 2 = abort
171 * int r_opt; return option
172 * int r_type; type of return value (0 = no argument found)
183 * } internal; DO NOT CHANGE
188 * const char *long_opt;
192 * int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
195 * This is my replacement for getopt(). See the example for a typical usage.
197 * Bit 0 : Do not remove options form argv
198 * Bit 1 : Do not stop at last option but return other args
199 * with r_opt set to -1.
200 * Bit 2 : Assume options and real args are mixed.
201 * Bit 3 : Do not use -- to stop option processing.
202 * Bit 4 : Do not skip the first arg.
203 * Bit 5 : allow usage of long option with only one dash
204 * Bit 6 : ignore --version
205 * all other bits must be set to zero, this value is modified by the
206 * function, so assume this is write only.
207 * Local flags (for each option):
208 * Bit 2-0 : 0 = does not take an argument
209 * 1 = takes int argument
210 * 2 = takes string argument
211 * 3 = takes long argument
212 * 4 = takes ulong argument
213 * Bit 3 : argument is optional (r_type will the be set to 0)
214 * Bit 4 : allow 0x etc. prefixed values.
215 * Bit 6 : Ignore this option
216 * Bit 7 : This is a command and not an option
217 * You stop the option processing by setting opts to NULL, the function will
220 * Returns the args.r_opt or 0 if ready
221 * r_opt may be -2/-7 to indicate an unknown option/command.
225 * You do not need to process the options 'h', '--help' or '--version'
226 * because this function includes standard help processing; but if you
227 * specify '-h', '--help' or '--version' you have to do it yourself.
228 * The option '--' stops argument processing; if bit 1 is set the function
229 * continues to return normal arguments.
230 * To process float args or unsigned args you must use a string args and do
231 * the conversion yourself.
234 * ARGPARSE_OPTS opts[] = {
235 * { 'v', "verbose", 0 },
236 * { 'd', "debug", 0 },
237 * { 'o', "output", 2 },
238 * { 'c', "cross-ref", 2|8 },
239 * { 'm', "my-option", 1|8 },
240 * { 300, "ignored-long-option, ARGPARSE_OP_IGNORE},
241 * { 500, "have-no-short-option-for-this-long-option", 0 },
243 * ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
245 * while( ArgParse( &pargs, &opts) ) {
246 * switch( pargs.r_opt ) {
247 * case 'v': opt.verbose++; break;
248 * case 'd': opt.debug++; break;
249 * case 'o': opt.outfile = pargs.r.ret_str; break;
250 * case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
251 * case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
252 * case 500: opt.a_long_one++; break
253 * default : pargs.err = 1; break; -- force warning output --
257 * log_fatal( "Too many args");
261 typedef struct alias_def_s *ALIAS_DEF;
264 char *name; /* malloced buffer with name, \0, value */
265 const char *value; /* ptr into name */
269 /* Object to store the names for the --ignore-invalid-option option.
270 This is a simple linked list. */
271 typedef struct iio_item_def_s *IIO_ITEM_DEF;
272 struct iio_item_def_s
275 char name[1]; /* String with the long option name. */
278 static const char *(*strusage_handler)( int ) = NULL;
279 static int (*custom_outfnc) (int, const char *);
281 static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
282 static void show_help(ARGPARSE_OPTS *opts, unsigned flags);
283 static void show_version(void);
284 static int writestrings (int is_error, const char *string, ...)
286 __attribute__ ((sentinel(0)))
292 argparse_register_outfnc (int (*fnc)(int, const char *))
298 /* Write STRING and all following const char * arguments either to
299 stdout or, if IS_ERROR is set, to stderr. The list of strings must
300 be terminated by a NULL. */
302 writestrings (int is_error, const char *string, ...)
311 va_start (arg_ptr, string);
315 custom_outfnc (is_error? 2:1, s);
317 fputs (s, is_error? stderr : stdout);
320 while ((s = va_arg (arg_ptr, const char *)));
328 flushstrings (int is_error)
331 custom_outfnc (is_error? 2:1, NULL);
333 fflush (is_error? stderr : stdout);
338 initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
340 if( !(arg->flags & (1<<15)) )
342 /* Initialize this instance. */
343 arg->internal.idx = 0;
344 arg->internal.last = NULL;
345 arg->internal.inarg = 0;
346 arg->internal.stopped = 0;
347 arg->internal.aliases = NULL;
348 arg->internal.cur_alias = NULL;
349 arg->internal.iio_list = NULL;
351 arg->flags |= 1<<15; /* Mark as initialized. */
352 if ( *arg->argc < 0 )
353 log_bug ("invalid argument for arg_parse\n");
359 /* Last option was erroneous. */
364 if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
365 s = _("argument not expected");
366 else if ( arg->r_opt == ARGPARSE_READ_ERROR )
368 else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG )
369 s = _("keyword too long");
370 else if ( arg->r_opt == ARGPARSE_MISSING_ARG )
371 s = _("missing argument");
372 else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
373 s = _("invalid argument");
374 else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
375 s = _("invalid command");
376 else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS )
377 s = _("invalid alias definition");
378 else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
379 s = _("out of core");
381 s = _("invalid option");
382 log_error ("%s:%u: %s\n", filename, *lineno, s);
386 s = arg->internal.last? arg->internal.last:"[??]";
388 if ( arg->r_opt == ARGPARSE_MISSING_ARG )
389 log_error (_("missing argument for option \"%.50s\"\n"), s);
390 else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
391 log_error (_("invalid argument for option \"%.50s\"\n"), s);
392 else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
393 log_error (_("option \"%.50s\" does not expect an argument\n"), s);
394 else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
395 log_error (_("invalid command \"%.50s\"\n"), s);
396 else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION )
397 log_error (_("option \"%.50s\" is ambiguous\n"), s);
398 else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND )
399 log_error (_("command \"%.50s\" is ambiguous\n"),s );
400 else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
401 log_error ("%s\n", _("out of core\n"));
403 log_error (_("invalid option \"%.50s\"\n"), s);
405 if (arg->err != ARGPARSE_PRINT_WARNING)
410 /* Zero out the return value union. */
411 arg->r.ret_str = NULL;
417 store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
419 /* TODO: replace this dummy function with a rea one
420 * and fix the probelms IRIX has with (ALIAS_DEV)arg..
427 ALIAS_DEF a = xmalloc( sizeof *a );
430 a->next = (ALIAS_DEF)arg->internal.aliases;
431 (ALIAS_DEF)arg->internal.aliases = a;
436 /* Return true if KEYWORD is in the ignore-invalid-option list. */
438 ignore_invalid_option_p (ARGPARSE_ARGS *arg, const char *keyword)
440 IIO_ITEM_DEF item = arg->internal.iio_list;
442 for (; item; item = item->next)
443 if (!strcmp (item->name, keyword))
449 /* Add the keywords up to the next LF to the list of to be ignored
450 options. After returning FP will either be at EOF or the next
451 character read wll be the first of a new line. The function
452 returns 0 on success or true on malloc failure. */
454 ignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp)
461 enum { skipWS, collectNAME, skipNAME, addNAME} state = skipWS;
477 if (!isascii (c) || !isspace(c))
491 else if (namelen < DIM(name)-1)
507 if (!ignore_invalid_option_p (arg, name))
509 item = xtrymalloc (sizeof *item + namelen);
512 strcpy (item->name, name);
513 item->next = (IIO_ITEM_DEF)arg->internal.iio_list;
514 arg->internal.iio_list = item;
524 /* Clear the entire ignore-invalid-option list. */
526 ignore_invalid_option_clear (ARGPARSE_ARGS *arg)
528 IIO_ITEM_DEF item, tmpitem;
530 for (item = arg->internal.iio_list; item; item = tmpitem)
532 tmpitem = item->next;
535 arg->internal.iio_list = NULL;
541 * Get options from a file.
542 * Lines starting with '#' are comment lines.
543 * Syntax is simply a keyword and the argument.
544 * Valid keywords are all keywords from the long_opt list without
545 * the leading dashes. The special keywords "help", "warranty" and "version"
546 * are not valid here.
547 * The special keyword "alias" may be used to store alias definitions,
548 * which are later expanded like long options.
550 * ignore-invalid-option OPTIONNAMEs
551 * is recognized and updates a list of option which should be ignored if they
553 * Caller must free returned strings.
554 * If called with FP set to NULL command line args are parse instead.
556 * Q: Should we allow the syntax
558 * and accept for boolean options a value of 1/0, yes/no or true/false?
559 * Note: Abbreviation of options is here not allowed.
562 optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
563 ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
571 int unread_buf[3]; /* We use an int so that we can store EOF. */
572 int unread_buf_count = 0;
574 if (!fp) /* Divert to to arg_parse() in this case. */
575 return arg_parse (arg, opts);
577 initialize (arg, filename, lineno);
579 /* If the LINENO is zero we assume that we are at the start of a
580 * file and we skip over a possible Byte Order Mark. */
583 unread_buf[0] = getc (fp);
584 unread_buf[1] = getc (fp);
585 unread_buf[2] = getc (fp);
586 if (unread_buf[0] != 0xef
587 || unread_buf[1] != 0xbb
588 || unread_buf[2] != 0xbf)
589 unread_buf_count = 3;
592 /* Find the next keyword. */
596 if (unread_buf_count)
597 c = unread_buf[3 - unread_buf_count--];
600 if (c == '\n' || c== EOF )
609 for (i=0; opts[i].short_opt; i++ )
611 if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
615 arg->r_opt = opts[idx].short_opt;
616 if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
621 else if (!opts[idx].short_opt )
623 if (!strcmp (keyword, "ignore-invalid-option"))
625 /* No argument - ignore this meta option. */
629 else if (ignore_invalid_option_p (arg, keyword))
631 /* This invalid option is in the iio list. */
635 arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
636 ? ARGPARSE_INVALID_COMMAND
637 : ARGPARSE_INVALID_OPTION);
639 else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
640 arg->r_type = 0; /* Does not take an arg. */
641 else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL) )
642 arg->r_type = 0; /* Arg is optional. */
644 arg->r_opt = ARGPARSE_MISSING_ARG;
650 /* No argument found. */
652 arg->r_opt = ARGPARSE_MISSING_ARG;
653 else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
654 arg->r_type = 0; /* Does not take an arg. */
655 else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL))
656 arg->r_type = 0; /* No optional argument. */
658 arg->r_opt = ARGPARSE_MISSING_ARG;
664 /* Has an argument. */
668 arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
674 p = strpbrk (buffer, " \t");
683 arg->r_opt = ARGPARSE_INVALID_ALIAS;
687 store_alias (arg, buffer, p);
691 else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
692 arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
700 buffer = xtrystrdup (keyword);
702 arg->r_opt = ARGPARSE_OUT_OF_CORE;
709 trim_spaces (buffer);
715 if (*p && p[strlen(p)-1] == '\"' )
718 if (!set_opt_arg (arg, opts[idx].flags, p))
721 gpgrt_annotate_leaked_object (buffer);
728 ignore_invalid_option_clear (arg);
730 arg->r_opt = ARGPARSE_READ_ERROR;
732 arg->r_opt = 0; /* EOF. */
738 else if (state == -1)
740 else if (state == 0 && isascii (c) && isspace(c))
741 ; /* Skip leading white space. */
742 else if (state == 0 && c == '#' )
743 state = 1; /* Start of a comment. */
745 ; /* Skip comments. */
746 else if (state == 2 && isascii (c) && isspace(c))
750 for (i=0; opts[i].short_opt; i++ )
751 if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
754 arg->r_opt = opts[idx].short_opt;
755 if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
757 state = 1; /* Process like a comment. */
759 else if (!opts[idx].short_opt)
761 if (!strcmp (keyword, "alias"))
766 else if (!strcmp (keyword, "ignore-invalid-option"))
768 if (ignore_invalid_option_add (arg, fp))
770 arg->r_opt = ARGPARSE_OUT_OF_CORE;
776 else if (ignore_invalid_option_p (arg, keyword))
777 state = 1; /* Process like a comment. */
780 arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
781 ? ARGPARSE_INVALID_COMMAND
782 : ARGPARSE_INVALID_OPTION);
783 state = -1; /* Skip rest of line and leave. */
791 /* Skip leading spaces of the argument. */
792 if (!isascii (c) || !isspace(c))
801 /* Collect the argument. */
809 size_t tmplen = buflen + 50;
811 tmp = xtryrealloc (buffer, tmplen);
821 arg->r_opt = ARGPARSE_OUT_OF_CORE;
826 else if (i < DIM(keyword)-1)
830 size_t tmplen = DIM(keyword) + 50;
831 buffer = xtrymalloc (tmplen);
835 memcpy(buffer, keyword, i);
840 arg->r_opt = ARGPARSE_OUT_OF_CORE;
845 else if (i >= DIM(keyword)-1)
847 arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG;
848 state = -1; /* Skip rest of line and leave. */
863 find_long_option( ARGPARSE_ARGS *arg,
864 ARGPARSE_OPTS *opts, const char *keyword )
871 /* Would be better if we can do a binary search, but it is not
872 possible to reorder our option table because we would mess
873 up our help strings - What we can do is: Build a nice option
874 lookup table when this function is first invoked */
877 for(i=0; opts[i].short_opt; i++ )
878 if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
883 /* see whether it is an alias */
884 for( a = args->internal.aliases; a; a = a->next ) {
885 if( !strcmp( a->name, keyword) ) {
886 /* todo: must parse the alias here */
887 args->internal.cur_alias = a;
888 return -3; /* alias available */
893 /* not found, see whether it is an abbreviation */
894 /* aliases may not be abbreviated */
895 n = strlen( keyword );
896 for(i=0; opts[i].short_opt; i++ ) {
897 if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) {
899 for(j=i+1; opts[j].short_opt; j++ ) {
901 && !strncmp( opts[j].long_opt, keyword, n )
902 && !(opts[j].short_opt == opts[i].short_opt
903 && opts[j].flags == opts[i].flags ) )
904 return -2; /* abbreviation is ambiguous */
909 return -1; /* Not found. */
913 arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
921 initialize( arg, NULL, NULL );
924 idx = arg->internal.idx;
926 if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
928 /* Skip the first argument. */
929 argc--; argv++; idx++;
937 goto leave; /* Ready. */
941 arg->internal.last = s;
943 if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL))
945 arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */
948 argc--; argv++; idx++; /* set to next one */
950 else if( arg->internal.stopped )
953 goto leave; /* Ready. */
955 else if ( *s == '-' && s[1] == '-' )
960 arg->internal.inarg = 0;
961 if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
963 /* Stop option processing. */
964 arg->internal.stopped = 1;
965 arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
966 argc--; argv++; idx++;
970 argpos = strchr( s+2, '=' );
973 i = find_long_option ( arg, opts, s+2 );
977 if ( i < 0 && !strcmp ( "help", s+2) )
978 show_help (opts, arg->flags);
979 else if ( i < 0 && !strcmp ( "version", s+2) )
981 if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
987 else if ( i < 0 && !strcmp( "warranty", s+2))
989 writestrings (0, strusage (16), "\n", NULL);
992 else if ( i < 0 && !strcmp( "dump-options", s+2) )
994 for (i=0; opts[i].short_opt; i++ )
996 if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
997 writestrings (0, "--", opts[i].long_opt, "\n", NULL);
999 writestrings (0, "--dump-options\n--help\n--version\n--warranty\n",
1005 arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
1008 arg->r_opt = ARGPARSE_INVALID_OPTION;
1009 arg->r.ret_str = s+2;
1012 arg->r_opt = opts[i].short_opt;
1015 else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
1025 if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1027 arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */
1031 arg->r_opt = ARGPARSE_MISSING_ARG;
1033 else if ( !argpos && *s2 == '-'
1034 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1036 /* The argument is optional and the next seems to be an
1037 option. We do not check this possible option but
1038 assume no argument */
1039 arg->r_type = ARGPARSE_TYPE_NONE;
1043 set_opt_arg (arg, opts[i].flags, s2);
1046 argc--; argv++; idx++; /* Skip one. */
1052 /* Does not take an argument. */
1054 arg->r_type = ARGPARSE_UNEXPECTED_ARG;
1058 argc--; argv++; idx++; /* Set to next one. */
1060 else if ( (*s == '-' && s[1]) || arg->internal.inarg )
1063 int dash_kludge = 0;
1066 if ( !arg->internal.inarg )
1068 arg->internal.inarg++;
1069 if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
1071 for (i=0; opts[i].short_opt; i++ )
1072 if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1))
1079 s += arg->internal.inarg;
1083 for (i=0; opts[i].short_opt; i++ )
1084 if ( opts[i].short_opt == *s )
1088 if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
1089 show_help (opts, arg->flags);
1091 arg->r_opt = opts[i].short_opt;
1092 if (!opts[i].short_opt )
1094 arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)?
1095 ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
1096 arg->internal.inarg++; /* Point to the next arg. */
1099 else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
1101 if ( s[1] && !dash_kludge )
1104 set_opt_arg (arg, opts[i].flags, s2);
1109 if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1111 arg->r_type = ARGPARSE_TYPE_NONE;
1115 arg->r_opt = ARGPARSE_MISSING_ARG;
1117 else if ( *s2 == '-' && s2[1]
1118 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1120 /* The argument is optional and the next seems to
1121 be an option. We do not check this possible
1122 option but assume no argument. */
1123 arg->r_type = ARGPARSE_TYPE_NONE;
1127 set_opt_arg (arg, opts[i].flags, s2);
1128 argc--; argv++; idx++; /* Skip one. */
1131 s = "x"; /* This is so that !s[1] yields false. */
1135 /* Does not take an argument. */
1136 arg->r_type = ARGPARSE_TYPE_NONE;
1137 arg->internal.inarg++; /* Point to the next arg. */
1139 if ( !s[1] || dash_kludge )
1141 /* No more concatenated short options. */
1142 arg->internal.inarg = 0;
1143 argc--; argv++; idx++;
1146 else if ( arg->flags & ARGPARSE_FLAG_MIXED )
1148 arg->r_opt = ARGPARSE_IS_ARG;
1151 argc--; argv++; idx++; /* Set to next one. */
1155 arg->internal.stopped = 1; /* Stop option processing. */
1162 arg->internal.idx = idx;
1167 /* Returns: -1 on error, 0 for an integer type and 1 for a non integer
1170 set_opt_arg (ARGPARSE_ARGS *arg, unsigned flags, char *s)
1172 int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
1175 switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
1177 case ARGPARSE_TYPE_LONG:
1178 case ARGPARSE_TYPE_INT:
1180 l = strtol (s, NULL, base);
1181 if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE)
1183 arg->r_opt = ARGPARSE_INVALID_ARG;
1186 if (arg->r_type == ARGPARSE_TYPE_LONG)
1187 arg->r.ret_long = l;
1188 else if ( (l < 0 && l < INT_MIN) || l > INT_MAX )
1190 arg->r_opt = ARGPARSE_INVALID_ARG;
1194 arg->r.ret_int = (int)l;
1197 case ARGPARSE_TYPE_ULONG:
1198 while (isascii (*s) && isspace(*s))
1202 arg->r.ret_ulong = 0;
1203 arg->r_opt = ARGPARSE_INVALID_ARG;
1207 arg->r.ret_ulong = strtoul (s, NULL, base);
1208 if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE)
1210 arg->r_opt = ARGPARSE_INVALID_ARG;
1215 case ARGPARSE_TYPE_STRING:
1224 long_opt_strlen( ARGPARSE_OPTS *o )
1226 size_t n = strlen (o->long_opt);
1228 if ( o->description && *o->description == '|' )
1231 int is_utf8 = is_native_utf8 ();
1236 /* For a (mostly) correct length calculation we exclude
1237 continuation bytes (10xxxxxx) if we are on a native utf8
1239 for (; *s && *s != '|'; s++ )
1240 if ( is_utf8 && (*s&0xc0) != 0x80 )
1248 * Print formatted help. The description string has some special
1250 * - A description string which is "@" suppresses help output for
1252 * - a description,ine which starts with a '@' and is followed by
1253 * any other characters is printed as is; this may be used for examples
1255 * - A description which starts with a '|' outputs the string between this
1256 * bar and the next one as arguments of the long option.
1259 show_help (ARGPARSE_OPTS *opts, unsigned int flags)
1265 writestrings (0, "\n", NULL);
1270 writestrings (1, s, NULL);
1271 if (*s && s[strlen(s)] != '\n')
1272 writestrings (1, "\n", NULL);
1275 writestrings (0, s, "\n", NULL);
1276 if ( opts[0].description )
1278 /* Auto format the option description. */
1281 /* Get max. length of long options. */
1282 for (i=indent=0; opts[i].short_opt; i++ )
1284 if ( opts[i].long_opt )
1285 if ( !opts[i].description || *opts[i].description != '@' )
1286 if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
1290 /* Example: " -v, --verbose Viele Sachen ausgeben" */
1292 if ( *opts[0].description != '@' )
1293 writestrings (0, "Options:", "\n", NULL);
1294 for (i=0; opts[i].short_opt; i++ )
1296 s = map_static_macro_string (_( opts[i].description ));
1297 if ( s && *s== '@' && !s[1] ) /* Hide this line. */
1299 if ( s && *s == '@' ) /* Unindented comment only line. */
1306 writestrings (0, "\n", NULL);
1312 writestrings (0, tmp, NULL);
1315 writestrings (0, "\n", NULL);
1320 if ( opts[i].short_opt < 256 )
1322 tmp[0] = opts[i].short_opt;
1324 writestrings (0, " -", tmp, NULL );
1325 if ( !opts[i].long_opt )
1327 if (s && *s == '|' )
1329 writestrings (0, " ", NULL); j++;
1330 for (s++ ; *s && *s != '|'; s++, j++ )
1334 writestrings (0, tmp, NULL);
1342 writestrings (0, " ", NULL);
1343 if ( opts[i].long_opt )
1345 tmp[0] = opts[i].short_opt < 256?',':' ';
1347 j += writestrings (0, tmp, " --", opts[i].long_opt, NULL);
1348 if (s && *s == '|' )
1352 writestrings (0, " ", NULL);
1355 for ( ; *s && *s != '|'; s++, j++ )
1359 writestrings (0, tmp, NULL);
1364 writestrings (0, " ", NULL);
1367 for (;j < indent; j++ )
1368 writestrings (0, " ", NULL);
1371 if ( *s && j > indent )
1373 writestrings (0, "\n", NULL);
1374 for (j=0;j < indent; j++ )
1375 writestrings (0, " ", NULL);
1383 writestrings (0, "\n", NULL);
1384 for (j=0; j < indent; j++ )
1385 writestrings (0, " ", NULL);
1392 writestrings (0, tmp, NULL);
1396 writestrings (0, "\n", NULL);
1398 if ( (flags & ARGPARSE_FLAG_ONEDASH) )
1399 writestrings (0, "\n(A single dash may be used "
1400 "instead of the double ones)\n", NULL);
1402 if ( (s=strusage(19)) )
1404 writestrings (0, "\n", NULL);
1405 writestrings (0, s, NULL);
1418 writestrings (0, strusage (11), NULL);
1419 if ((s=strusage (12)))
1420 writestrings (0, " (", s, ")", NULL);
1421 writestrings (0, " ", strusage (13), "\n", NULL);
1422 /* Additional version lines. */
1423 for (i=20; i < 30; i++)
1424 if ((s=strusage (i)))
1425 writestrings (0, s, "\n", NULL);
1426 /* Copyright string. */
1427 if ((s=strusage (14)))
1428 writestrings (0, s, "\n", NULL);
1429 /* Licence string. */
1430 if( (s=strusage (10)) )
1431 writestrings (0, s, "\n", NULL);
1432 /* Copying conditions. */
1433 if ( (s=strusage(15)) )
1434 writestrings (0, s, NULL);
1436 if ((s=strusage(18)))
1437 writestrings (0, s, NULL);
1438 /* Additional program info. */
1439 for (i=30; i < 40; i++ )
1440 if ( (s=strusage (i)) )
1441 writestrings (0, s, NULL);
1453 writestrings (1, strusage(11), " ", strusage(13), "; ",
1454 strusage (14), "\n", NULL);
1457 else if (level == 1)
1460 writestrings (1, p, NULL);
1461 if (*p && p[strlen(p)] != '\n')
1462 writestrings (1, "\n", NULL);
1465 else if (level == 2)
1471 writestrings (1, p, NULL);
1472 if (*p && p[strlen(p)] != '\n')
1473 writestrings (1, "\n", NULL);
1475 writestrings (0, strusage(41), "\n", NULL);
1481 * 0: Print copyright string to stderr
1482 * 1: Print a short usage hint to stderr and terminate
1483 * 2: Print a long usage hint to stdout and terminate
1484 * 10: Return license info string
1485 * 11: Return the name of the program
1486 * 12: Return optional name of package which includes this program.
1487 * 13: version string
1488 * 14: copyright string
1489 * 15: Short copying conditions (with LFs)
1490 * 16: Long copying conditions (with LFs)
1491 * 17: Optional printable OS name
1492 * 18: Optional thanks list (with LFs)
1493 * 19: Bug report info
1494 *20..29: Additional lib version strings.
1495 *30..39: Additional program info (with LFs)
1496 * 40: short usage note (with LF)
1497 * 41: long usage note (with LF)
1499 * First char is '1':
1500 * The short usage notes needs to be printed
1501 * before the long usage note.
1504 strusage( int level )
1506 const char *p = strusage_handler? strusage_handler(level) : NULL;
1509 return map_static_macro_string (p);
1515 #if ARGPARSE_GPL_VERSION == 3
1516 p = ("License GPLv3+: GNU GPL version 3 or later "
1517 "<https://gnu.org/licenses/gpl.html>");
1519 p = ("License GPLv2+: GNU GPL version 2 or later "
1520 "<https://gnu.org/licenses/>");
1523 case 11: p = "foo"; break;
1524 case 13: p = "0.0"; break;
1525 case 14: p = ARGPARSE_CRIGHT_STR; break;
1527 "This is free software: you are free to change and redistribute it.\n"
1528 "There is NO WARRANTY, to the extent permitted by law.\n";
1531 "This is free software; you can redistribute it and/or modify\n"
1532 "it under the terms of the GNU General Public License as published by\n"
1533 "the Free Software Foundation; either version "
1534 ARGPARSE_STR2(ARGPARSE_GPL_VERSION)
1535 " of the License, or\n"
1536 "(at your option) any later version.\n\n"
1537 "It is distributed in the hope that it will be useful,\n"
1538 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1539 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1540 "GNU General Public License for more details.\n\n"
1541 "You should have received a copy of the GNU General Public License\n"
1542 "along with this software. If not, see <https://gnu.org/licenses/>.\n";
1544 case 40: /* short and long usage */
1545 case 41: p = ""; break;
1552 /* Set the usage handler. This function is basically a constructor. */
1554 set_strusage ( const char *(*f)( int ) )
1556 strusage_handler = f;
1572 main(int argc, char **argv)
1574 ARGPARSE_OPTS opts[] = {
1575 ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"),
1576 ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, "
1577 "was wir eingegeben haben")),
1578 ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"),
1579 ARGPARSE_s_s('o', "output", 0 ),
1580 ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ),
1581 /* Note that on a non-utf8 terminal the ß might garble the output. */
1582 ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"),
1583 ARGPARSE_o_i('m', "my-option", 0),
1584 ARGPARSE_s_n(500, "a-long-option", 0 ),
1587 ARGPARSE_ARGS pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL
1588 | ARGPARSE_FLAG_MIXED
1589 | ARGPARSE_FLAG_ONEDASH) };
1592 while (arg_parse (&pargs, opts))
1594 switch (pargs.r_opt)
1596 case ARGPARSE_IS_ARG :
1597 printf ("arg='%s'\n", pargs.r.ret_str);
1599 case 'v': opt.verbose++; break;
1600 case 'e': opt.echo++; break;
1601 case 'd': opt.debug++; break;
1602 case 'o': opt.outfile = pargs.r.ret_str; break;
1603 case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
1604 case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
1605 case 500: opt.a_long_one++; break;
1606 default : pargs.err = ARGPARSE_PRINT_WARNING; break;
1609 for (i=0; i < argc; i++ )
1610 printf ("%3d -> (%s)\n", i, argv[i] );
1613 printf (" verbose=%d\n", opt.verbose );
1615 printf (" debug=%d\n", opt.debug );
1617 printf (" outfile='%s'\n", opt.outfile );
1619 printf (" crffile='%s'\n", opt.crf );
1621 printf (" myopt=%d\n", opt.myopt );
1623 printf (" a-long-one=%d\n", opt.a_long_one );
1625 printf (" echo=%d\n", opt.echo );
1631 /**** bottom of file ****/