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-2016 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) 2016 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 return -2; /* abbreviation is ambiguous */
907 return -1; /* Not found. */
911 arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
919 initialize( arg, NULL, NULL );
922 idx = arg->internal.idx;
924 if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
926 /* Skip the first argument. */
927 argc--; argv++; idx++;
935 goto leave; /* Ready. */
939 arg->internal.last = s;
941 if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL))
943 arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */
946 argc--; argv++; idx++; /* set to next one */
948 else if( arg->internal.stopped )
951 goto leave; /* Ready. */
953 else if ( *s == '-' && s[1] == '-' )
958 arg->internal.inarg = 0;
959 if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
961 /* Stop option processing. */
962 arg->internal.stopped = 1;
963 arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
964 argc--; argv++; idx++;
968 argpos = strchr( s+2, '=' );
971 i = find_long_option ( arg, opts, s+2 );
975 if ( i < 0 && !strcmp ( "help", s+2) )
976 show_help (opts, arg->flags);
977 else if ( i < 0 && !strcmp ( "version", s+2) )
979 if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
985 else if ( i < 0 && !strcmp( "warranty", s+2))
987 writestrings (0, strusage (16), "\n", NULL);
990 else if ( i < 0 && !strcmp( "dump-options", s+2) )
992 for (i=0; opts[i].short_opt; i++ )
994 if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
995 writestrings (0, "--", opts[i].long_opt, "\n", NULL);
997 writestrings (0, "--dump-options\n--help\n--version\n--warranty\n",
1003 arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
1006 arg->r_opt = ARGPARSE_INVALID_OPTION;
1007 arg->r.ret_str = s+2;
1010 arg->r_opt = opts[i].short_opt;
1013 else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
1023 if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1025 arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */
1029 arg->r_opt = ARGPARSE_MISSING_ARG;
1031 else if ( !argpos && *s2 == '-'
1032 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1034 /* The argument is optional and the next seems to be an
1035 option. We do not check this possible option but
1036 assume no argument */
1037 arg->r_type = ARGPARSE_TYPE_NONE;
1041 set_opt_arg (arg, opts[i].flags, s2);
1044 argc--; argv++; idx++; /* Skip one. */
1050 /* Does not take an argument. */
1052 arg->r_type = ARGPARSE_UNEXPECTED_ARG;
1056 argc--; argv++; idx++; /* Set to next one. */
1058 else if ( (*s == '-' && s[1]) || arg->internal.inarg )
1061 int dash_kludge = 0;
1064 if ( !arg->internal.inarg )
1066 arg->internal.inarg++;
1067 if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
1069 for (i=0; opts[i].short_opt; i++ )
1070 if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1))
1077 s += arg->internal.inarg;
1081 for (i=0; opts[i].short_opt; i++ )
1082 if ( opts[i].short_opt == *s )
1086 if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
1087 show_help (opts, arg->flags);
1089 arg->r_opt = opts[i].short_opt;
1090 if (!opts[i].short_opt )
1092 arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)?
1093 ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
1094 arg->internal.inarg++; /* Point to the next arg. */
1097 else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
1099 if ( s[1] && !dash_kludge )
1102 set_opt_arg (arg, opts[i].flags, s2);
1107 if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1109 arg->r_type = ARGPARSE_TYPE_NONE;
1113 arg->r_opt = ARGPARSE_MISSING_ARG;
1115 else if ( *s2 == '-' && s2[1]
1116 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1118 /* The argument is optional and the next seems to
1119 be an option. We do not check this possible
1120 option but assume no argument. */
1121 arg->r_type = ARGPARSE_TYPE_NONE;
1125 set_opt_arg (arg, opts[i].flags, s2);
1126 argc--; argv++; idx++; /* Skip one. */
1129 s = "x"; /* This is so that !s[1] yields false. */
1133 /* Does not take an argument. */
1134 arg->r_type = ARGPARSE_TYPE_NONE;
1135 arg->internal.inarg++; /* Point to the next arg. */
1137 if ( !s[1] || dash_kludge )
1139 /* No more concatenated short options. */
1140 arg->internal.inarg = 0;
1141 argc--; argv++; idx++;
1144 else if ( arg->flags & ARGPARSE_FLAG_MIXED )
1146 arg->r_opt = ARGPARSE_IS_ARG;
1149 argc--; argv++; idx++; /* Set to next one. */
1153 arg->internal.stopped = 1; /* Stop option processing. */
1160 arg->internal.idx = idx;
1165 /* Returns: -1 on error, 0 for an integer type and 1 for a non integer
1168 set_opt_arg (ARGPARSE_ARGS *arg, unsigned flags, char *s)
1170 int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
1173 switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
1175 case ARGPARSE_TYPE_LONG:
1176 case ARGPARSE_TYPE_INT:
1178 l = strtol (s, NULL, base);
1179 if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE)
1181 arg->r_opt = ARGPARSE_INVALID_ARG;
1184 if (arg->r_type == ARGPARSE_TYPE_LONG)
1185 arg->r.ret_long = l;
1186 else if ( (l < 0 && l < INT_MIN) || l > INT_MAX )
1188 arg->r_opt = ARGPARSE_INVALID_ARG;
1192 arg->r.ret_int = (int)l;
1195 case ARGPARSE_TYPE_ULONG:
1196 while (isascii (*s) && isspace(*s))
1200 arg->r.ret_ulong = 0;
1201 arg->r_opt = ARGPARSE_INVALID_ARG;
1205 arg->r.ret_ulong = strtoul (s, NULL, base);
1206 if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE)
1208 arg->r_opt = ARGPARSE_INVALID_ARG;
1213 case ARGPARSE_TYPE_STRING:
1222 long_opt_strlen( ARGPARSE_OPTS *o )
1224 size_t n = strlen (o->long_opt);
1226 if ( o->description && *o->description == '|' )
1229 int is_utf8 = is_native_utf8 ();
1234 /* For a (mostly) correct length calculation we exclude
1235 continuation bytes (10xxxxxx) if we are on a native utf8
1237 for (; *s && *s != '|'; s++ )
1238 if ( is_utf8 && (*s&0xc0) != 0x80 )
1246 * Print formatted help. The description string has some special
1248 * - A description string which is "@" suppresses help output for
1250 * - a description,ine which starts with a '@' and is followed by
1251 * any other characters is printed as is; this may be used for examples
1253 * - A description which starts with a '|' outputs the string between this
1254 * bar and the next one as arguments of the long option.
1257 show_help (ARGPARSE_OPTS *opts, unsigned int flags)
1263 writestrings (0, "\n", NULL);
1268 writestrings (1, s, NULL);
1269 if (*s && s[strlen(s)] != '\n')
1270 writestrings (1, "\n", NULL);
1273 writestrings (0, s, "\n", NULL);
1274 if ( opts[0].description )
1276 /* Auto format the option description. */
1279 /* Get max. length of long options. */
1280 for (i=indent=0; opts[i].short_opt; i++ )
1282 if ( opts[i].long_opt )
1283 if ( !opts[i].description || *opts[i].description != '@' )
1284 if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
1288 /* Example: " -v, --verbose Viele Sachen ausgeben" */
1290 if ( *opts[0].description != '@' )
1291 writestrings (0, "Options:", "\n", NULL);
1292 for (i=0; opts[i].short_opt; i++ )
1294 s = map_static_macro_string (_( opts[i].description ));
1295 if ( s && *s== '@' && !s[1] ) /* Hide this line. */
1297 if ( s && *s == '@' ) /* Unindented comment only line. */
1304 writestrings (0, "\n", NULL);
1310 writestrings (0, tmp, NULL);
1313 writestrings (0, "\n", NULL);
1318 if ( opts[i].short_opt < 256 )
1320 tmp[0] = opts[i].short_opt;
1322 writestrings (0, " -", tmp, NULL );
1323 if ( !opts[i].long_opt )
1325 if (s && *s == '|' )
1327 writestrings (0, " ", NULL); j++;
1328 for (s++ ; *s && *s != '|'; s++, j++ )
1332 writestrings (0, tmp, NULL);
1340 writestrings (0, " ", NULL);
1341 if ( opts[i].long_opt )
1343 tmp[0] = opts[i].short_opt < 256?',':' ';
1345 j += writestrings (0, tmp, " --", opts[i].long_opt, NULL);
1346 if (s && *s == '|' )
1350 writestrings (0, " ", NULL);
1353 for ( ; *s && *s != '|'; s++, j++ )
1357 writestrings (0, tmp, NULL);
1362 writestrings (0, " ", NULL);
1365 for (;j < indent; j++ )
1366 writestrings (0, " ", NULL);
1369 if ( *s && j > indent )
1371 writestrings (0, "\n", NULL);
1372 for (j=0;j < indent; j++ )
1373 writestrings (0, " ", NULL);
1381 writestrings (0, "\n", NULL);
1382 for (j=0; j < indent; j++ )
1383 writestrings (0, " ", NULL);
1390 writestrings (0, tmp, NULL);
1394 writestrings (0, "\n", NULL);
1396 if ( (flags & ARGPARSE_FLAG_ONEDASH) )
1397 writestrings (0, "\n(A single dash may be used "
1398 "instead of the double ones)\n", NULL);
1400 if ( (s=strusage(19)) )
1402 writestrings (0, "\n", NULL);
1403 writestrings (0, s, NULL);
1416 writestrings (0, strusage (11), NULL);
1417 if ((s=strusage (12)))
1418 writestrings (0, " (", s, ")", NULL);
1419 writestrings (0, " ", strusage (13), "\n", NULL);
1420 /* Additional version lines. */
1421 for (i=20; i < 30; i++)
1422 if ((s=strusage (i)))
1423 writestrings (0, s, "\n", NULL);
1424 /* Copyright string. */
1425 if ((s=strusage (14)))
1426 writestrings (0, s, "\n", NULL);
1427 /* Licence string. */
1428 if( (s=strusage (10)) )
1429 writestrings (0, s, "\n", NULL);
1430 /* Copying conditions. */
1431 if ( (s=strusage(15)) )
1432 writestrings (0, s, NULL);
1434 if ((s=strusage(18)))
1435 writestrings (0, s, NULL);
1436 /* Additional program info. */
1437 for (i=30; i < 40; i++ )
1438 if ( (s=strusage (i)) )
1439 writestrings (0, s, NULL);
1451 writestrings (1, strusage(11), " ", strusage(13), "; ",
1452 strusage (14), "\n", NULL);
1455 else if (level == 1)
1458 writestrings (1, p, NULL);
1459 if (*p && p[strlen(p)] != '\n')
1460 writestrings (1, "\n", NULL);
1463 else if (level == 2)
1469 writestrings (1, p, NULL);
1470 if (*p && p[strlen(p)] != '\n')
1471 writestrings (1, "\n", NULL);
1473 writestrings (0, strusage(41), "\n", NULL);
1479 * 0: Print copyright string to stderr
1480 * 1: Print a short usage hint to stderr and terminate
1481 * 2: Print a long usage hint to stdout and terminate
1482 * 10: Return license info string
1483 * 11: Return the name of the program
1484 * 12: Return optional name of package which includes this program.
1485 * 13: version string
1486 * 14: copyright string
1487 * 15: Short copying conditions (with LFs)
1488 * 16: Long copying conditions (with LFs)
1489 * 17: Optional printable OS name
1490 * 18: Optional thanks list (with LFs)
1491 * 19: Bug report info
1492 *20..29: Additional lib version strings.
1493 *30..39: Additional program info (with LFs)
1494 * 40: short usage note (with LF)
1495 * 41: long usage note (with LF)
1497 * First char is '1':
1498 * The short usage notes needs to be printed
1499 * before the long usage note.
1502 strusage( int level )
1504 const char *p = strusage_handler? strusage_handler(level) : NULL;
1507 return map_static_macro_string (p);
1513 #if ARGPARSE_GPL_VERSION == 3
1514 p = ("License GPLv3+: GNU GPL version 3 or later "
1515 "<https://gnu.org/licenses/gpl.html>");
1517 p = ("License GPLv2+: GNU GPL version 2 or later "
1518 "<https://gnu.org/licenses/>");
1521 case 11: p = "foo"; break;
1522 case 13: p = "0.0"; break;
1523 case 14: p = ARGPARSE_CRIGHT_STR; break;
1525 "This is free software: you are free to change and redistribute it.\n"
1526 "There is NO WARRANTY, to the extent permitted by law.\n";
1529 "This is free software; you can redistribute it and/or modify\n"
1530 "it under the terms of the GNU General Public License as published by\n"
1531 "the Free Software Foundation; either version "
1532 ARGPARSE_STR2(ARGPARSE_GPL_VERSION)
1533 " of the License, or\n"
1534 "(at your option) any later version.\n\n"
1535 "It is distributed in the hope that it will be useful,\n"
1536 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1537 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1538 "GNU General Public License for more details.\n\n"
1539 "You should have received a copy of the GNU General Public License\n"
1540 "along with this software. If not, see <https://gnu.org/licenses/>.\n";
1542 case 40: /* short and long usage */
1543 case 41: p = ""; break;
1550 /* Set the usage handler. This function is basically a constructor. */
1552 set_strusage ( const char *(*f)( int ) )
1554 strusage_handler = f;
1570 main(int argc, char **argv)
1572 ARGPARSE_OPTS opts[] = {
1573 ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"),
1574 ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, "
1575 "was wir eingegeben haben")),
1576 ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"),
1577 ARGPARSE_s_s('o', "output", 0 ),
1578 ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ),
1579 /* Note that on a non-utf8 terminal the ß might garble the output. */
1580 ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"),
1581 ARGPARSE_o_i('m', "my-option", 0),
1582 ARGPARSE_s_n(500, "a-long-option", 0 ),
1585 ARGPARSE_ARGS pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL
1586 | ARGPARSE_FLAG_MIXED
1587 | ARGPARSE_FLAG_ONEDASH) };
1590 while (arg_parse (&pargs, opts))
1592 switch (pargs.r_opt)
1594 case ARGPARSE_IS_ARG :
1595 printf ("arg='%s'\n", pargs.r.ret_str);
1597 case 'v': opt.verbose++; break;
1598 case 'e': opt.echo++; break;
1599 case 'd': opt.debug++; break;
1600 case 'o': opt.outfile = pargs.r.ret_str; break;
1601 case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
1602 case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
1603 case 500: opt.a_long_one++; break;
1604 default : pargs.err = ARGPARSE_PRINT_WARNING; break;
1607 for (i=0; i < argc; i++ )
1608 printf ("%3d -> (%s)\n", i, argv[i] );
1611 printf (" verbose=%d\n", opt.verbose );
1613 printf (" debug=%d\n", opt.debug );
1615 printf (" outfile='%s'\n", opt.outfile );
1617 printf (" crffile='%s'\n", opt.crf );
1619 printf (" myopt=%d\n", opt.myopt );
1621 printf (" a-long-one=%d\n", opt.a_long_one );
1623 printf (" echo=%d\n", opt.echo );
1629 /**** bottom of file ****/