Line data Source code
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-2015 Werner Koch
4 : *
5 : * This file is part of GnuPG.
6 : *
7 : * GnuPG is free software; you can redistribute it and/or modify it
8 : * under the terms of either
9 : *
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.
13 : *
14 : * or
15 : *
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.
19 : *
20 : * or both in parallel, as here.
21 : *
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.
26 : *
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 <http://www.gnu.org/licenses/>.
30 : */
31 :
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.
35 : */
36 :
37 : #ifdef HAVE_CONFIG_H
38 : #include <config.h>
39 : #endif
40 :
41 : #include <stdio.h>
42 : #include <stdlib.h>
43 : #include <ctype.h>
44 : #include <string.h>
45 : #include <stdarg.h>
46 : #include <limits.h>
47 : #include <errno.h>
48 :
49 : #ifdef GNUPG_MAJOR_VERSION
50 : # include "util.h"
51 : # include "common-defs.h"
52 : # include "i18n.h"
53 : # include "mischelp.h"
54 : # include "stringhelp.h"
55 : # include "logging.h"
56 : # include "utf8conv.h"
57 : #endif /*GNUPG_MAJOR_VERSION*/
58 :
59 : #include "argparse.h"
60 :
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
65 : here. */
66 : #ifndef GNUPG_MAJOR_VERSION
67 :
68 : # define ARGPARSE_GPL_VERSION 2
69 : # define ARGPARSE_CRIGHT_STR "Copyright (C) YEAR NAME"
70 :
71 : #else /* Used by GnuPG */
72 :
73 : # define ARGPARSE_GPL_VERSION 3
74 : # define ARGPARSE_CRIGHT_STR "Copyright (C) 2015 Free Software Foundation, Inc."
75 :
76 : #endif /*GNUPG_MAJOR_VERSION*/
77 :
78 : /* Replacements for standalone builds. */
79 : #ifndef GNUPG_MAJOR_VERSION
80 : # ifndef _
81 : # define _(a) (a)
82 : # endif
83 : # ifndef DIM
84 : # define DIM(v) (sizeof(v)/sizeof((v)[0]))
85 : # endif
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*/
95 :
96 :
97 : #define ARGPARSE_STR(v) #v
98 : #define ARGPARSE_STR2(v) ARGPARSE_STR(v)
99 :
100 :
101 : /* Replacements for standalone builds. */
102 : #ifndef GNUPG_MAJOR_VERSION
103 : static void
104 0 : my_log_error (const char *fmt, ...)
105 : {
106 : va_list arg_ptr ;
107 :
108 0 : va_start (arg_ptr, fmt);
109 0 : fprintf (stderr, "%s: ", strusage (11));
110 0 : vfprintf (stderr, fmt, arg_ptr);
111 0 : va_end (arg_ptr);
112 0 : }
113 :
114 : static void
115 0 : my_log_bug (const char *fmt, ...)
116 : {
117 : va_list arg_ptr ;
118 :
119 0 : va_start (arg_ptr, fmt);
120 0 : fprintf (stderr, "%s: Ohhhh jeeee: ", strusage (11));
121 0 : vfprintf (stderr, fmt, arg_ptr);
122 0 : va_end (arg_ptr);
123 0 : abort ();
124 : }
125 :
126 : /* Return true if the native charset is utf-8. */
127 : static int
128 0 : is_native_utf8 (void)
129 : {
130 0 : return 1;
131 : }
132 :
133 : static char *
134 0 : my_trim_spaces (char *str)
135 : {
136 : char *string, *p, *mark;
137 :
138 0 : string = str;
139 : /* Find first non space character. */
140 0 : for (p=string; *p && isspace (*(unsigned char*)p) ; p++)
141 : ;
142 : /* Move characters. */
143 0 : for ((mark = NULL); (*string = *p); string++, p++)
144 0 : if (isspace (*(unsigned char*)p))
145 : {
146 0 : if (!mark)
147 0 : mark = string;
148 : }
149 : else
150 0 : mark = NULL;
151 0 : if (mark)
152 0 : *mark = '\0' ; /* Remove trailing spaces. */
153 :
154 0 : return str ;
155 : }
156 :
157 : #endif /*!GNUPG_MAJOR_VERSION*/
158 :
159 :
160 :
161 : /*********************************
162 : * @Summary arg_parse
163 : * #include "argparse.h"
164 : *
165 : * typedef struct {
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)
173 : * union {
174 : * int ret_int;
175 : * long ret_long
176 : * ulong ret_ulong;
177 : * char *ret_str;
178 : * } r; Return values
179 : * struct {
180 : * int idx;
181 : * const char *last;
182 : * void *aliases;
183 : * } internal; DO NOT CHANGE
184 : * } ARGPARSE_ARGS;
185 : *
186 : * typedef struct {
187 : * int short_opt;
188 : * const char *long_opt;
189 : * unsigned flags;
190 : * } ARGPARSE_OPTS;
191 : *
192 : * int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
193 : *
194 : * @Description
195 : * This is my replacement for getopt(). See the example for a typical usage.
196 : * Global flags are:
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
218 : * then return 0.
219 : * @Return Value
220 : * Returns the args.r_opt or 0 if ready
221 : * r_opt may be -2/-7 to indicate an unknown option/command.
222 : * @See Also
223 : * ArgExpand
224 : * @Notes
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.
232 : * @Example
233 : *
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 },
242 : * {0} };
243 : * ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
244 : *
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 --
254 : * }
255 : * }
256 : * if( argc > 1 )
257 : * log_fatal( "Too many args");
258 : *
259 : */
260 :
261 : typedef struct alias_def_s *ALIAS_DEF;
262 : struct alias_def_s {
263 : ALIAS_DEF next;
264 : char *name; /* malloced buffer with name, \0, value */
265 : const char *value; /* ptr into name */
266 : };
267 :
268 :
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
273 : {
274 : IIO_ITEM_DEF next;
275 : char name[1]; /* String with the long option name. */
276 : };
277 :
278 : static const char *(*strusage_handler)( int ) = NULL;
279 : static int (*custom_outfnc) (int, const char *);
280 :
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, ...)
285 : #if __GNUC__ >= 4
286 : __attribute__ ((sentinel(0)))
287 : #endif
288 : ;
289 :
290 :
291 : void
292 0 : argparse_register_outfnc (int (*fnc)(int, const char *))
293 : {
294 0 : custom_outfnc = fnc;
295 0 : }
296 :
297 :
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. */
301 : static int
302 0 : writestrings (int is_error, const char *string, ...)
303 : {
304 : va_list arg_ptr;
305 : const char *s;
306 0 : int count = 0;
307 :
308 0 : if (string)
309 : {
310 0 : s = string;
311 0 : va_start (arg_ptr, string);
312 : do
313 : {
314 0 : if (custom_outfnc)
315 0 : custom_outfnc (is_error? 2:1, s);
316 : else
317 0 : fputs (s, is_error? stderr : stdout);
318 0 : count += strlen (s);
319 : }
320 0 : while ((s = va_arg (arg_ptr, const char *)));
321 0 : va_end (arg_ptr);
322 : }
323 0 : return count;
324 : }
325 :
326 :
327 : static void
328 0 : flushstrings (int is_error)
329 : {
330 0 : if (custom_outfnc)
331 0 : custom_outfnc (is_error? 2:1, NULL);
332 : else
333 0 : fflush (is_error? stderr : stdout);
334 0 : }
335 :
336 :
337 : static void
338 0 : initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
339 : {
340 0 : if( !(arg->flags & (1<<15)) )
341 : {
342 : /* Initialize this instance. */
343 0 : arg->internal.idx = 0;
344 0 : arg->internal.last = NULL;
345 0 : arg->internal.inarg = 0;
346 0 : arg->internal.stopped = 0;
347 0 : arg->internal.aliases = NULL;
348 0 : arg->internal.cur_alias = NULL;
349 0 : arg->internal.iio_list = NULL;
350 0 : arg->err = 0;
351 0 : arg->flags |= 1<<15; /* Mark as initialized. */
352 0 : if ( *arg->argc < 0 )
353 0 : log_bug ("invalid argument for arg_parse\n");
354 : }
355 :
356 :
357 0 : if (arg->err)
358 : {
359 : /* Last option was erroneous. */
360 : const char *s;
361 :
362 0 : if (filename)
363 : {
364 0 : if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
365 0 : s = _("argument not expected");
366 0 : else if ( arg->r_opt == ARGPARSE_READ_ERROR )
367 0 : s = _("read error");
368 0 : else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG )
369 0 : s = _("keyword too long");
370 0 : else if ( arg->r_opt == ARGPARSE_MISSING_ARG )
371 0 : s = _("missing argument");
372 0 : else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
373 0 : s = _("invalid argument");
374 0 : else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
375 0 : s = _("invalid command");
376 0 : else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS )
377 0 : s = _("invalid alias definition");
378 0 : else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
379 0 : s = _("out of core");
380 : else
381 0 : s = _("invalid option");
382 0 : log_error ("%s:%u: %s\n", filename, *lineno, s);
383 : }
384 : else
385 : {
386 0 : s = arg->internal.last? arg->internal.last:"[??]";
387 :
388 0 : if ( arg->r_opt == ARGPARSE_MISSING_ARG )
389 0 : log_error (_("missing argument for option \"%.50s\"\n"), s);
390 0 : else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
391 0 : log_error (_("invalid argument for option \"%.50s\"\n"), s);
392 0 : else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
393 0 : log_error (_("option \"%.50s\" does not expect an argument\n"), s);
394 0 : else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
395 0 : log_error (_("invalid command \"%.50s\"\n"), s);
396 0 : else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION )
397 0 : log_error (_("option \"%.50s\" is ambiguous\n"), s);
398 0 : else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND )
399 0 : log_error (_("command \"%.50s\" is ambiguous\n"),s );
400 0 : else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
401 0 : log_error ("%s\n", _("out of core\n"));
402 : else
403 0 : log_error (_("invalid option \"%.50s\"\n"), s);
404 : }
405 0 : if (arg->err != ARGPARSE_PRINT_WARNING)
406 0 : exit (2);
407 0 : arg->err = 0;
408 : }
409 :
410 : /* Zero out the return value union. */
411 0 : arg->r.ret_str = NULL;
412 0 : arg->r.ret_long = 0;
413 0 : }
414 :
415 :
416 : static void
417 0 : store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
418 : {
419 : /* TODO: replace this dummy function with a rea one
420 : * and fix the probelms IRIX has with (ALIAS_DEV)arg..
421 : * used as lvalue
422 : */
423 : (void)arg;
424 : (void)name;
425 : (void)value;
426 : #if 0
427 : ALIAS_DEF a = xmalloc( sizeof *a );
428 : a->name = name;
429 : a->value = value;
430 : a->next = (ALIAS_DEF)arg->internal.aliases;
431 : (ALIAS_DEF)arg->internal.aliases = a;
432 : #endif
433 0 : }
434 :
435 :
436 : /* Return true if KEYWORD is in the ignore-invalid-option list. */
437 : static int
438 0 : ignore_invalid_option_p (ARGPARSE_ARGS *arg, const char *keyword)
439 : {
440 0 : IIO_ITEM_DEF item = arg->internal.iio_list;
441 :
442 0 : for (; item; item = item->next)
443 0 : if (!strcmp (item->name, keyword))
444 0 : return 1;
445 0 : return 0;
446 : }
447 :
448 :
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. */
453 : static int
454 0 : ignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp)
455 : {
456 : IIO_ITEM_DEF item;
457 : int c;
458 : char name[100];
459 0 : int namelen = 0;
460 0 : int ready = 0;
461 0 : enum { skipWS, collectNAME, skipNAME, addNAME} state = skipWS;
462 :
463 0 : while (!ready)
464 : {
465 0 : c = getc (fp);
466 0 : if (c == '\n')
467 0 : ready = 1;
468 0 : else if (c == EOF)
469 : {
470 0 : c = '\n';
471 0 : ready = 1;
472 : }
473 : again:
474 0 : switch (state)
475 : {
476 : case skipWS:
477 0 : if (!isascii (c) || !isspace(c))
478 : {
479 0 : namelen = 0;
480 0 : state = collectNAME;
481 0 : goto again;
482 : }
483 0 : break;
484 :
485 : case collectNAME:
486 0 : if (isspace (c))
487 : {
488 0 : state = addNAME;
489 0 : goto again;
490 : }
491 0 : else if (namelen < DIM(name)-1)
492 0 : name[namelen++] = c;
493 : else /* Too long. */
494 0 : state = skipNAME;
495 0 : break;
496 :
497 : case skipNAME:
498 0 : if (isspace (c))
499 : {
500 0 : state = skipWS;
501 0 : goto again;
502 : }
503 0 : break;
504 :
505 : case addNAME:
506 0 : name[namelen] = 0;
507 0 : if (!ignore_invalid_option_p (arg, name))
508 : {
509 0 : item = xtrymalloc (sizeof *item + namelen);
510 0 : if (!item)
511 0 : return 1;
512 0 : strcpy (item->name, name);
513 0 : item->next = (IIO_ITEM_DEF)arg->internal.iio_list;
514 0 : arg->internal.iio_list = item;
515 : }
516 0 : state = skipWS;
517 0 : goto again;
518 : }
519 : }
520 0 : return 0;
521 : }
522 :
523 :
524 : /* Clear the entire ignore-invalid-option list. */
525 : static void
526 0 : ignore_invalid_option_clear (ARGPARSE_ARGS *arg)
527 : {
528 : IIO_ITEM_DEF item, tmpitem;
529 :
530 0 : for (item = arg->internal.iio_list; item; item = tmpitem)
531 : {
532 0 : tmpitem = item->next;
533 0 : xfree (item);
534 : }
535 0 : arg->internal.iio_list = NULL;
536 0 : }
537 :
538 :
539 :
540 : /****************
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.
549 : * The option
550 : * ignore-invalid-option OPTIONNAMEs
551 : * is recognized and updates a list of option which should be ignored if they
552 : * are not defined.
553 : * Caller must free returned strings.
554 : * If called with FP set to NULL command line args are parse instead.
555 : *
556 : * Q: Should we allow the syntax
557 : * keyword = value
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.
560 : */
561 : int
562 0 : optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
563 : ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
564 : {
565 : int state, i, c;
566 0 : int idx=0;
567 : char keyword[100];
568 0 : char *buffer = NULL;
569 0 : size_t buflen = 0;
570 0 : int in_alias=0;
571 :
572 0 : if (!fp) /* Divert to to arg_parse() in this case. */
573 0 : return arg_parse (arg, opts);
574 :
575 0 : initialize (arg, filename, lineno);
576 :
577 : /* Find the next keyword. */
578 0 : state = i = 0;
579 : for (;;)
580 : {
581 0 : c = getc (fp);
582 0 : if (c == '\n' || c== EOF )
583 : {
584 0 : if ( c != EOF )
585 0 : ++*lineno;
586 0 : if (state == -1)
587 0 : break;
588 0 : else if (state == 2)
589 : {
590 0 : keyword[i] = 0;
591 0 : for (i=0; opts[i].short_opt; i++ )
592 : {
593 0 : if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
594 0 : break;
595 : }
596 0 : idx = i;
597 0 : arg->r_opt = opts[idx].short_opt;
598 0 : if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
599 : {
600 0 : state = i = 0;
601 0 : continue;
602 : }
603 0 : else if (!opts[idx].short_opt )
604 : {
605 0 : if (!strcmp (keyword, "ignore-invalid-option"))
606 : {
607 : /* No argument - ignore this meta option. */
608 0 : state = i = 0;
609 0 : continue;
610 : }
611 0 : else if (ignore_invalid_option_p (arg, keyword))
612 : {
613 : /* This invalid option is in the iio list. */
614 0 : state = i = 0;
615 0 : continue;
616 : }
617 0 : arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
618 : ? ARGPARSE_INVALID_COMMAND
619 0 : : ARGPARSE_INVALID_OPTION);
620 : }
621 0 : else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
622 0 : arg->r_type = 0; /* Does not take an arg. */
623 0 : else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL) )
624 0 : arg->r_type = 0; /* Arg is optional. */
625 : else
626 0 : arg->r_opt = ARGPARSE_MISSING_ARG;
627 :
628 0 : break;
629 : }
630 0 : else if (state == 3)
631 : {
632 : /* No argument found. */
633 0 : if (in_alias)
634 0 : arg->r_opt = ARGPARSE_MISSING_ARG;
635 0 : else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
636 0 : arg->r_type = 0; /* Does not take an arg. */
637 0 : else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL))
638 0 : arg->r_type = 0; /* No optional argument. */
639 : else
640 0 : arg->r_opt = ARGPARSE_MISSING_ARG;
641 :
642 0 : break;
643 : }
644 0 : else if (state == 4)
645 : {
646 : /* Has an argument. */
647 0 : if (in_alias)
648 : {
649 0 : if (!buffer)
650 0 : arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
651 : else
652 : {
653 : char *p;
654 :
655 0 : buffer[i] = 0;
656 0 : p = strpbrk (buffer, " \t");
657 0 : if (p)
658 : {
659 0 : *p++ = 0;
660 0 : trim_spaces (p);
661 : }
662 0 : if (!p || !*p)
663 : {
664 0 : xfree (buffer);
665 0 : arg->r_opt = ARGPARSE_INVALID_ALIAS;
666 : }
667 : else
668 : {
669 0 : store_alias (arg, buffer, p);
670 : }
671 : }
672 : }
673 0 : else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
674 0 : arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
675 : else
676 : {
677 : char *p;
678 :
679 0 : if (!buffer)
680 : {
681 0 : keyword[i] = 0;
682 0 : buffer = xtrystrdup (keyword);
683 0 : if (!buffer)
684 0 : arg->r_opt = ARGPARSE_OUT_OF_CORE;
685 : }
686 : else
687 0 : buffer[i] = 0;
688 :
689 0 : if (buffer)
690 : {
691 0 : trim_spaces (buffer);
692 0 : p = buffer;
693 0 : if (*p == '"')
694 : {
695 : /* Remove quotes. */
696 0 : p++;
697 0 : if (*p && p[strlen(p)-1] == '\"' )
698 0 : p[strlen(p)-1] = 0;
699 : }
700 0 : if (!set_opt_arg (arg, opts[idx].flags, p))
701 0 : xfree (buffer);
702 : }
703 : }
704 0 : break;
705 : }
706 0 : else if (c == EOF)
707 : {
708 0 : ignore_invalid_option_clear (arg);
709 0 : if (ferror (fp))
710 0 : arg->r_opt = ARGPARSE_READ_ERROR;
711 : else
712 0 : arg->r_opt = 0; /* EOF. */
713 0 : break;
714 : }
715 0 : state = 0;
716 0 : i = 0;
717 : }
718 0 : else if (state == -1)
719 : ; /* Skip. */
720 0 : else if (state == 0 && isascii (c) && isspace(c))
721 : ; /* Skip leading white space. */
722 0 : else if (state == 0 && c == '#' )
723 0 : state = 1; /* Start of a comment. */
724 0 : else if (state == 1)
725 : ; /* Skip comments. */
726 0 : else if (state == 2 && isascii (c) && isspace(c))
727 : {
728 : /* Check keyword. */
729 0 : keyword[i] = 0;
730 0 : for (i=0; opts[i].short_opt; i++ )
731 0 : if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
732 0 : break;
733 0 : idx = i;
734 0 : arg->r_opt = opts[idx].short_opt;
735 0 : if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
736 : {
737 0 : state = 1; /* Process like a comment. */
738 : }
739 0 : else if (!opts[idx].short_opt)
740 : {
741 0 : if (!strcmp (keyword, "alias"))
742 : {
743 0 : in_alias = 1;
744 0 : state = 3;
745 : }
746 0 : else if (!strcmp (keyword, "ignore-invalid-option"))
747 : {
748 0 : if (ignore_invalid_option_add (arg, fp))
749 : {
750 0 : arg->r_opt = ARGPARSE_OUT_OF_CORE;
751 0 : break;
752 : }
753 0 : state = i = 0;
754 0 : ++*lineno;
755 : }
756 0 : else if (ignore_invalid_option_p (arg, keyword))
757 0 : state = 1; /* Process like a comment. */
758 : else
759 : {
760 0 : arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
761 : ? ARGPARSE_INVALID_COMMAND
762 0 : : ARGPARSE_INVALID_OPTION);
763 0 : state = -1; /* Skip rest of line and leave. */
764 : }
765 : }
766 : else
767 0 : state = 3;
768 : }
769 0 : else if (state == 3)
770 : {
771 : /* Skip leading spaces of the argument. */
772 0 : if (!isascii (c) || !isspace(c))
773 : {
774 0 : i = 0;
775 0 : keyword[i++] = c;
776 0 : state = 4;
777 : }
778 : }
779 0 : else if (state == 4)
780 : {
781 : /* Collect the argument. */
782 0 : if (buffer)
783 : {
784 0 : if (i < buflen-1)
785 0 : buffer[i++] = c;
786 : else
787 : {
788 : char *tmp;
789 0 : size_t tmplen = buflen + 50;
790 :
791 0 : tmp = xtryrealloc (buffer, tmplen);
792 0 : if (tmp)
793 : {
794 0 : buflen = tmplen;
795 0 : buffer = tmp;
796 0 : buffer[i++] = c;
797 : }
798 : else
799 : {
800 0 : xfree (buffer);
801 0 : arg->r_opt = ARGPARSE_OUT_OF_CORE;
802 0 : break;
803 : }
804 : }
805 : }
806 0 : else if (i < DIM(keyword)-1)
807 0 : keyword[i++] = c;
808 : else
809 : {
810 0 : size_t tmplen = DIM(keyword) + 50;
811 0 : buffer = xtrymalloc (tmplen);
812 0 : if (buffer)
813 : {
814 0 : buflen = tmplen;
815 0 : memcpy(buffer, keyword, i);
816 0 : buffer[i++] = c;
817 : }
818 : else
819 : {
820 0 : arg->r_opt = ARGPARSE_OUT_OF_CORE;
821 0 : break;
822 : }
823 : }
824 : }
825 0 : else if (i >= DIM(keyword)-1)
826 : {
827 0 : arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG;
828 0 : state = -1; /* Skip rest of line and leave. */
829 : }
830 : else
831 : {
832 0 : keyword[i++] = c;
833 0 : state = 2;
834 : }
835 0 : }
836 :
837 0 : return arg->r_opt;
838 : }
839 :
840 :
841 :
842 : static int
843 0 : find_long_option( ARGPARSE_ARGS *arg,
844 : ARGPARSE_OPTS *opts, const char *keyword )
845 : {
846 : int i;
847 : size_t n;
848 :
849 : (void)arg;
850 :
851 : /* Would be better if we can do a binary search, but it is not
852 : possible to reorder our option table because we would mess
853 : up our help strings - What we can do is: Build a nice option
854 : lookup table when this function is first invoked */
855 0 : if( !*keyword )
856 0 : return -1;
857 0 : for(i=0; opts[i].short_opt; i++ )
858 0 : if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
859 0 : return i;
860 : #if 0
861 : {
862 : ALIAS_DEF a;
863 : /* see whether it is an alias */
864 : for( a = args->internal.aliases; a; a = a->next ) {
865 : if( !strcmp( a->name, keyword) ) {
866 : /* todo: must parse the alias here */
867 : args->internal.cur_alias = a;
868 : return -3; /* alias available */
869 : }
870 : }
871 : }
872 : #endif
873 : /* not found, see whether it is an abbreviation */
874 : /* aliases may not be abbreviated */
875 0 : n = strlen( keyword );
876 0 : for(i=0; opts[i].short_opt; i++ ) {
877 0 : if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) {
878 : int j;
879 0 : for(j=i+1; opts[j].short_opt; j++ ) {
880 0 : if( opts[j].long_opt
881 0 : && !strncmp( opts[j].long_opt, keyword, n ) )
882 0 : return -2; /* abbreviation is ambiguous */
883 : }
884 0 : return i;
885 : }
886 : }
887 0 : return -1; /* Not found. */
888 : }
889 :
890 : int
891 0 : arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
892 : {
893 : int idx;
894 : int argc;
895 : char **argv;
896 : char *s, *s2;
897 : int i;
898 :
899 0 : initialize( arg, NULL, NULL );
900 0 : argc = *arg->argc;
901 0 : argv = *arg->argv;
902 0 : idx = arg->internal.idx;
903 :
904 0 : if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
905 : {
906 : /* Skip the first argument. */
907 0 : argc--; argv++; idx++;
908 : }
909 :
910 : next_one:
911 0 : if (!argc)
912 : {
913 : /* No more args. */
914 0 : arg->r_opt = 0;
915 0 : goto leave; /* Ready. */
916 : }
917 :
918 0 : s = *argv;
919 0 : arg->internal.last = s;
920 :
921 0 : if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL))
922 : {
923 0 : arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */
924 0 : arg->r_type = 2;
925 0 : arg->r.ret_str = s;
926 0 : argc--; argv++; idx++; /* set to next one */
927 : }
928 0 : else if( arg->internal.stopped )
929 : {
930 0 : arg->r_opt = 0;
931 0 : goto leave; /* Ready. */
932 : }
933 0 : else if ( *s == '-' && s[1] == '-' )
934 0 : {
935 : /* Long option. */
936 : char *argpos;
937 :
938 0 : arg->internal.inarg = 0;
939 0 : if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
940 : {
941 : /* Stop option processing. */
942 0 : arg->internal.stopped = 1;
943 0 : arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
944 0 : argc--; argv++; idx++;
945 0 : goto next_one;
946 : }
947 :
948 0 : argpos = strchr( s+2, '=' );
949 0 : if ( argpos )
950 0 : *argpos = 0;
951 0 : i = find_long_option ( arg, opts, s+2 );
952 0 : if ( argpos )
953 0 : *argpos = '=';
954 :
955 0 : if ( i < 0 && !strcmp ( "help", s+2) )
956 0 : show_help (opts, arg->flags);
957 0 : else if ( i < 0 && !strcmp ( "version", s+2) )
958 : {
959 0 : if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
960 : {
961 0 : show_version ();
962 0 : exit(0);
963 : }
964 : }
965 0 : else if ( i < 0 && !strcmp( "warranty", s+2))
966 : {
967 0 : writestrings (0, strusage (16), "\n", NULL);
968 0 : exit (0);
969 : }
970 0 : else if ( i < 0 && !strcmp( "dump-options", s+2) )
971 : {
972 0 : for (i=0; opts[i].short_opt; i++ )
973 : {
974 0 : if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
975 0 : writestrings (0, "--", opts[i].long_opt, "\n", NULL);
976 : }
977 0 : writestrings (0, "--dump-options\n--help\n--version\n--warranty\n",
978 : NULL);
979 0 : exit (0);
980 : }
981 :
982 0 : if ( i == -2 )
983 0 : arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
984 0 : else if ( i == -1 )
985 : {
986 0 : arg->r_opt = ARGPARSE_INVALID_OPTION;
987 0 : arg->r.ret_str = s+2;
988 : }
989 : else
990 0 : arg->r_opt = opts[i].short_opt;
991 0 : if ( i < 0 )
992 : ;
993 0 : else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
994 : {
995 0 : if ( argpos )
996 : {
997 0 : s2 = argpos+1;
998 0 : if ( !*s2 )
999 0 : s2 = NULL;
1000 : }
1001 : else
1002 0 : s2 = argv[1];
1003 0 : if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1004 : {
1005 0 : arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */
1006 : }
1007 0 : else if ( !s2 )
1008 : {
1009 0 : arg->r_opt = ARGPARSE_MISSING_ARG;
1010 : }
1011 0 : else if ( !argpos && *s2 == '-'
1012 0 : && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1013 : {
1014 : /* The argument is optional and the next seems to be an
1015 : option. We do not check this possible option but
1016 : assume no argument */
1017 0 : arg->r_type = ARGPARSE_TYPE_NONE;
1018 : }
1019 : else
1020 : {
1021 0 : set_opt_arg (arg, opts[i].flags, s2);
1022 0 : if ( !argpos )
1023 : {
1024 0 : argc--; argv++; idx++; /* Skip one. */
1025 : }
1026 : }
1027 : }
1028 : else
1029 : {
1030 : /* Does not take an argument. */
1031 0 : if ( argpos )
1032 0 : arg->r_type = ARGPARSE_UNEXPECTED_ARG;
1033 : else
1034 0 : arg->r_type = 0;
1035 : }
1036 0 : argc--; argv++; idx++; /* Set to next one. */
1037 : }
1038 0 : else if ( (*s == '-' && s[1]) || arg->internal.inarg )
1039 0 : {
1040 : /* Short option. */
1041 0 : int dash_kludge = 0;
1042 :
1043 0 : i = 0;
1044 0 : if ( !arg->internal.inarg )
1045 : {
1046 0 : arg->internal.inarg++;
1047 0 : if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
1048 : {
1049 0 : for (i=0; opts[i].short_opt; i++ )
1050 0 : if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1))
1051 : {
1052 0 : dash_kludge = 1;
1053 0 : break;
1054 : }
1055 : }
1056 : }
1057 0 : s += arg->internal.inarg;
1058 :
1059 0 : if (!dash_kludge )
1060 : {
1061 0 : for (i=0; opts[i].short_opt; i++ )
1062 0 : if ( opts[i].short_opt == *s )
1063 0 : break;
1064 : }
1065 :
1066 0 : if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
1067 0 : show_help (opts, arg->flags);
1068 :
1069 0 : arg->r_opt = opts[i].short_opt;
1070 0 : if (!opts[i].short_opt )
1071 : {
1072 0 : arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)?
1073 0 : ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
1074 0 : arg->internal.inarg++; /* Point to the next arg. */
1075 0 : arg->r.ret_str = s;
1076 : }
1077 0 : else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
1078 : {
1079 0 : if ( s[1] && !dash_kludge )
1080 : {
1081 0 : s2 = s+1;
1082 0 : set_opt_arg (arg, opts[i].flags, s2);
1083 : }
1084 : else
1085 : {
1086 0 : s2 = argv[1];
1087 0 : if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1088 : {
1089 0 : arg->r_type = ARGPARSE_TYPE_NONE;
1090 : }
1091 0 : else if ( !s2 )
1092 : {
1093 0 : arg->r_opt = ARGPARSE_MISSING_ARG;
1094 : }
1095 0 : else if ( *s2 == '-' && s2[1]
1096 0 : && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1097 : {
1098 : /* The argument is optional and the next seems to
1099 : be an option. We do not check this possible
1100 : option but assume no argument. */
1101 0 : arg->r_type = ARGPARSE_TYPE_NONE;
1102 : }
1103 : else
1104 : {
1105 0 : set_opt_arg (arg, opts[i].flags, s2);
1106 0 : argc--; argv++; idx++; /* Skip one. */
1107 : }
1108 : }
1109 0 : s = "x"; /* This is so that !s[1] yields false. */
1110 : }
1111 : else
1112 : {
1113 : /* Does not take an argument. */
1114 0 : arg->r_type = ARGPARSE_TYPE_NONE;
1115 0 : arg->internal.inarg++; /* Point to the next arg. */
1116 : }
1117 0 : if ( !s[1] || dash_kludge )
1118 : {
1119 : /* No more concatenated short options. */
1120 0 : arg->internal.inarg = 0;
1121 0 : argc--; argv++; idx++;
1122 : }
1123 : }
1124 0 : else if ( arg->flags & ARGPARSE_FLAG_MIXED )
1125 : {
1126 0 : arg->r_opt = ARGPARSE_IS_ARG;
1127 0 : arg->r_type = 2;
1128 0 : arg->r.ret_str = s;
1129 0 : argc--; argv++; idx++; /* Set to next one. */
1130 : }
1131 : else
1132 : {
1133 0 : arg->internal.stopped = 1; /* Stop option processing. */
1134 0 : goto next_one;
1135 : }
1136 :
1137 : leave:
1138 0 : *arg->argc = argc;
1139 0 : *arg->argv = argv;
1140 0 : arg->internal.idx = idx;
1141 0 : return arg->r_opt;
1142 : }
1143 :
1144 :
1145 : /* Returns: -1 on error, 0 for an integer type and 1 for a non integer
1146 : type argument. */
1147 : static int
1148 0 : set_opt_arg (ARGPARSE_ARGS *arg, unsigned flags, char *s)
1149 : {
1150 0 : int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
1151 : long l;
1152 :
1153 0 : switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
1154 : {
1155 : case ARGPARSE_TYPE_LONG:
1156 : case ARGPARSE_TYPE_INT:
1157 0 : errno = 0;
1158 0 : l = strtol (s, NULL, base);
1159 0 : if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE)
1160 : {
1161 0 : arg->r_opt = ARGPARSE_INVALID_ARG;
1162 0 : return -1;
1163 : }
1164 0 : if (arg->r_type == ARGPARSE_TYPE_LONG)
1165 0 : arg->r.ret_long = l;
1166 0 : else if ( (l < 0 && l < INT_MIN) || l > INT_MAX )
1167 : {
1168 0 : arg->r_opt = ARGPARSE_INVALID_ARG;
1169 0 : return -1;
1170 : }
1171 : else
1172 0 : arg->r.ret_int = (int)l;
1173 0 : return 0;
1174 :
1175 : case ARGPARSE_TYPE_ULONG:
1176 0 : while (isascii (*s) && isspace(*s))
1177 0 : s++;
1178 0 : if (*s == '-')
1179 : {
1180 0 : arg->r.ret_ulong = 0;
1181 0 : arg->r_opt = ARGPARSE_INVALID_ARG;
1182 0 : return -1;
1183 : }
1184 0 : errno = 0;
1185 0 : arg->r.ret_ulong = strtoul (s, NULL, base);
1186 0 : if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE)
1187 : {
1188 0 : arg->r_opt = ARGPARSE_INVALID_ARG;
1189 0 : return -1;
1190 : }
1191 0 : return 0;
1192 :
1193 : case ARGPARSE_TYPE_STRING:
1194 : default:
1195 0 : arg->r.ret_str = s;
1196 0 : return 1;
1197 : }
1198 : }
1199 :
1200 :
1201 : static size_t
1202 0 : long_opt_strlen( ARGPARSE_OPTS *o )
1203 : {
1204 0 : size_t n = strlen (o->long_opt);
1205 :
1206 0 : if ( o->description && *o->description == '|' )
1207 : {
1208 : const char *s;
1209 0 : int is_utf8 = is_native_utf8 ();
1210 :
1211 0 : s=o->description+1;
1212 0 : if ( *s != '=' )
1213 0 : n++;
1214 : /* For a (mostly) correct length calculation we exclude
1215 : continuation bytes (10xxxxxx) if we are on a native utf8
1216 : terminal. */
1217 0 : for (; *s && *s != '|'; s++ )
1218 0 : if ( is_utf8 && (*s&0xc0) != 0x80 )
1219 0 : n++;
1220 : }
1221 0 : return n;
1222 : }
1223 :
1224 :
1225 : /****************
1226 : * Print formatted help. The description string has some special
1227 : * meanings:
1228 : * - A description string which is "@" suppresses help output for
1229 : * this option
1230 : * - a description,ine which starts with a '@' and is followed by
1231 : * any other characters is printed as is; this may be used for examples
1232 : * ans such.
1233 : * - A description which starts with a '|' outputs the string between this
1234 : * bar and the next one as arguments of the long option.
1235 : */
1236 : static void
1237 0 : show_help (ARGPARSE_OPTS *opts, unsigned int flags)
1238 : {
1239 : const char *s;
1240 : char tmp[2];
1241 :
1242 0 : show_version ();
1243 0 : writestrings (0, "\n", NULL);
1244 0 : s = strusage (42);
1245 0 : if (s && *s == '1')
1246 : {
1247 0 : s = strusage (40);
1248 0 : writestrings (1, s, NULL);
1249 0 : if (*s && s[strlen(s)] != '\n')
1250 0 : writestrings (1, "\n", NULL);
1251 : }
1252 0 : s = strusage(41);
1253 0 : writestrings (0, s, "\n", NULL);
1254 0 : if ( opts[0].description )
1255 : {
1256 : /* Auto format the option description. */
1257 : int i,j, indent;
1258 :
1259 : /* Get max. length of long options. */
1260 0 : for (i=indent=0; opts[i].short_opt; i++ )
1261 : {
1262 0 : if ( opts[i].long_opt )
1263 0 : if ( !opts[i].description || *opts[i].description != '@' )
1264 0 : if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
1265 0 : indent = j;
1266 : }
1267 :
1268 : /* Example: " -v, --verbose Viele Sachen ausgeben" */
1269 0 : indent += 10;
1270 0 : if ( *opts[0].description != '@' )
1271 0 : writestrings (0, "Options:", "\n", NULL);
1272 0 : for (i=0; opts[i].short_opt; i++ )
1273 : {
1274 0 : s = map_static_macro_string (_( opts[i].description ));
1275 0 : if ( s && *s== '@' && !s[1] ) /* Hide this line. */
1276 0 : continue;
1277 0 : if ( s && *s == '@' ) /* Unindented comment only line. */
1278 : {
1279 0 : for (s++; *s; s++ )
1280 : {
1281 0 : if ( *s == '\n' )
1282 : {
1283 0 : if( s[1] )
1284 0 : writestrings (0, "\n", NULL);
1285 : }
1286 : else
1287 : {
1288 0 : tmp[0] = *s;
1289 0 : tmp[1] = 0;
1290 0 : writestrings (0, tmp, NULL);
1291 : }
1292 : }
1293 0 : writestrings (0, "\n", NULL);
1294 0 : continue;
1295 : }
1296 :
1297 0 : j = 3;
1298 0 : if ( opts[i].short_opt < 256 )
1299 : {
1300 0 : tmp[0] = opts[i].short_opt;
1301 0 : tmp[1] = 0;
1302 0 : writestrings (0, " -", tmp, NULL );
1303 0 : if ( !opts[i].long_opt )
1304 : {
1305 0 : if (s && *s == '|' )
1306 : {
1307 0 : writestrings (0, " ", NULL); j++;
1308 0 : for (s++ ; *s && *s != '|'; s++, j++ )
1309 : {
1310 0 : tmp[0] = *s;
1311 0 : tmp[1] = 0;
1312 0 : writestrings (0, tmp, NULL);
1313 : }
1314 0 : if ( *s )
1315 0 : s++;
1316 : }
1317 : }
1318 : }
1319 : else
1320 0 : writestrings (0, " ", NULL);
1321 0 : if ( opts[i].long_opt )
1322 : {
1323 0 : tmp[0] = opts[i].short_opt < 256?',':' ';
1324 0 : tmp[1] = 0;
1325 0 : j += writestrings (0, tmp, " --", opts[i].long_opt, NULL);
1326 0 : if (s && *s == '|' )
1327 : {
1328 0 : if ( *++s != '=' )
1329 : {
1330 0 : writestrings (0, " ", NULL);
1331 0 : j++;
1332 : }
1333 0 : for ( ; *s && *s != '|'; s++, j++ )
1334 : {
1335 0 : tmp[0] = *s;
1336 0 : tmp[1] = 0;
1337 0 : writestrings (0, tmp, NULL);
1338 : }
1339 0 : if ( *s )
1340 0 : s++;
1341 : }
1342 0 : writestrings (0, " ", NULL);
1343 0 : j += 3;
1344 : }
1345 0 : for (;j < indent; j++ )
1346 0 : writestrings (0, " ", NULL);
1347 0 : if ( s )
1348 : {
1349 0 : if ( *s && j > indent )
1350 : {
1351 0 : writestrings (0, "\n", NULL);
1352 0 : for (j=0;j < indent; j++ )
1353 0 : writestrings (0, " ", NULL);
1354 : }
1355 0 : for (; *s; s++ )
1356 : {
1357 0 : if ( *s == '\n' )
1358 : {
1359 0 : if ( s[1] )
1360 : {
1361 0 : writestrings (0, "\n", NULL);
1362 0 : for (j=0; j < indent; j++ )
1363 0 : writestrings (0, " ", NULL);
1364 : }
1365 : }
1366 : else
1367 : {
1368 0 : tmp[0] = *s;
1369 0 : tmp[1] = 0;
1370 0 : writestrings (0, tmp, NULL);
1371 : }
1372 : }
1373 : }
1374 0 : writestrings (0, "\n", NULL);
1375 : }
1376 0 : if ( (flags & ARGPARSE_FLAG_ONEDASH) )
1377 0 : writestrings (0, "\n(A single dash may be used "
1378 : "instead of the double ones)\n", NULL);
1379 : }
1380 0 : if ( (s=strusage(19)) )
1381 : {
1382 0 : writestrings (0, "\n", NULL);
1383 0 : writestrings (0, s, NULL);
1384 : }
1385 0 : flushstrings (0);
1386 0 : exit(0);
1387 : }
1388 :
1389 : static void
1390 0 : show_version ()
1391 : {
1392 : const char *s;
1393 : int i;
1394 :
1395 : /* Version line. */
1396 0 : writestrings (0, strusage (11), NULL);
1397 0 : if ((s=strusage (12)))
1398 0 : writestrings (0, " (", s, ")", NULL);
1399 0 : writestrings (0, " ", strusage (13), "\n", NULL);
1400 : /* Additional version lines. */
1401 0 : for (i=20; i < 30; i++)
1402 0 : if ((s=strusage (i)))
1403 0 : writestrings (0, s, "\n", NULL);
1404 : /* Copyright string. */
1405 0 : if ((s=strusage (14)))
1406 0 : writestrings (0, s, "\n", NULL);
1407 : /* Licence string. */
1408 0 : if( (s=strusage (10)) )
1409 0 : writestrings (0, s, "\n", NULL);
1410 : /* Copying conditions. */
1411 0 : if ( (s=strusage(15)) )
1412 0 : writestrings (0, s, NULL);
1413 : /* Thanks. */
1414 0 : if ((s=strusage(18)))
1415 0 : writestrings (0, s, NULL);
1416 : /* Additional program info. */
1417 0 : for (i=30; i < 40; i++ )
1418 0 : if ( (s=strusage (i)) )
1419 0 : writestrings (0, s, NULL);
1420 0 : flushstrings (0);
1421 0 : }
1422 :
1423 :
1424 : void
1425 0 : usage (int level)
1426 : {
1427 : const char *p;
1428 :
1429 0 : if (!level)
1430 : {
1431 0 : writestrings (1, strusage(11), " ", strusage(13), "; ",
1432 : strusage (14), "\n", NULL);
1433 0 : flushstrings (1);
1434 : }
1435 0 : else if (level == 1)
1436 : {
1437 0 : p = strusage (40);
1438 0 : writestrings (1, p, NULL);
1439 0 : if (*p && p[strlen(p)] != '\n')
1440 0 : writestrings (1, "\n", NULL);
1441 0 : exit (2);
1442 : }
1443 0 : else if (level == 2)
1444 : {
1445 0 : p = strusage (42);
1446 0 : if (p && *p == '1')
1447 : {
1448 0 : p = strusage (40);
1449 0 : writestrings (1, p, NULL);
1450 0 : if (*p && p[strlen(p)] != '\n')
1451 0 : writestrings (1, "\n", NULL);
1452 : }
1453 0 : writestrings (0, strusage(41), "\n", NULL);
1454 0 : exit (0);
1455 : }
1456 0 : }
1457 :
1458 : /* Level
1459 : * 0: Print copyright string to stderr
1460 : * 1: Print a short usage hint to stderr and terminate
1461 : * 2: Print a long usage hint to stdout and terminate
1462 : * 10: Return license info string
1463 : * 11: Return the name of the program
1464 : * 12: Return optional name of package which includes this program.
1465 : * 13: version string
1466 : * 14: copyright string
1467 : * 15: Short copying conditions (with LFs)
1468 : * 16: Long copying conditions (with LFs)
1469 : * 17: Optional printable OS name
1470 : * 18: Optional thanks list (with LFs)
1471 : * 19: Bug report info
1472 : *20..29: Additional lib version strings.
1473 : *30..39: Additional program info (with LFs)
1474 : * 40: short usage note (with LF)
1475 : * 41: long usage note (with LF)
1476 : * 42: Flag string:
1477 : * First char is '1':
1478 : * The short usage notes needs to be printed
1479 : * before the long usage note.
1480 : */
1481 : const char *
1482 0 : strusage( int level )
1483 : {
1484 0 : const char *p = strusage_handler? strusage_handler(level) : NULL;
1485 :
1486 0 : if ( p )
1487 0 : return map_static_macro_string (p);
1488 :
1489 0 : switch ( level )
1490 : {
1491 :
1492 : case 10:
1493 : #if ARGPARSE_GPL_VERSION == 3
1494 : p = ("License GPLv3+: GNU GPL version 3 or later "
1495 : "<http://gnu.org/licenses/gpl.html>");
1496 : #else
1497 0 : p = ("License GPLv2+: GNU GPL version 2 or later "
1498 : "<http://gnu.org/licenses/>");
1499 : #endif
1500 0 : break;
1501 0 : case 11: p = "foo"; break;
1502 0 : case 13: p = "0.0"; break;
1503 0 : case 14: p = ARGPARSE_CRIGHT_STR; break;
1504 0 : case 15: p =
1505 : "This is free software: you are free to change and redistribute it.\n"
1506 : "There is NO WARRANTY, to the extent permitted by law.\n";
1507 0 : break;
1508 0 : case 16: p =
1509 : "This is free software; you can redistribute it and/or modify\n"
1510 : "it under the terms of the GNU General Public License as published by\n"
1511 : "the Free Software Foundation; either version "
1512 : ARGPARSE_STR2(ARGPARSE_GPL_VERSION)
1513 : " of the License, or\n"
1514 : "(at your option) any later version.\n\n"
1515 : "It is distributed in the hope that it will be useful,\n"
1516 : "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1517 : "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1518 : "GNU General Public License for more details.\n\n"
1519 : "You should have received a copy of the GNU General Public License\n"
1520 : "along with this software. If not, see <http://www.gnu.org/licenses/>.\n";
1521 0 : break;
1522 : case 40: /* short and long usage */
1523 0 : case 41: p = ""; break;
1524 : }
1525 :
1526 0 : return p;
1527 : }
1528 :
1529 :
1530 : /* Set the usage handler. This function is basically a constructor. */
1531 : void
1532 0 : set_strusage ( const char *(*f)( int ) )
1533 : {
1534 0 : strusage_handler = f;
1535 0 : }
1536 :
1537 :
1538 : #ifdef TEST
1539 : static struct {
1540 : int verbose;
1541 : int debug;
1542 : char *outfile;
1543 : char *crf;
1544 : int myopt;
1545 : int echo;
1546 : int a_long_one;
1547 : } opt;
1548 :
1549 : int
1550 : main(int argc, char **argv)
1551 : {
1552 : ARGPARSE_OPTS opts[] = {
1553 : ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"),
1554 : ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, "
1555 : "was wir eingegeben haben")),
1556 : ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"),
1557 : ARGPARSE_s_s('o', "output", 0 ),
1558 : ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ),
1559 : /* Note that on a non-utf8 terminal the ß might garble the output. */
1560 : ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"),
1561 : ARGPARSE_o_i('m', "my-option", 0),
1562 : ARGPARSE_s_n(500, "a-long-option", 0 ),
1563 : ARGPARSE_end()
1564 : };
1565 : ARGPARSE_ARGS pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL
1566 : | ARGPARSE_FLAG_MIXED
1567 : | ARGPARSE_FLAG_ONEDASH) };
1568 : int i;
1569 :
1570 : while (arg_parse (&pargs, opts))
1571 : {
1572 : switch (pargs.r_opt)
1573 : {
1574 : case ARGPARSE_IS_ARG :
1575 : printf ("arg='%s'\n", pargs.r.ret_str);
1576 : break;
1577 : case 'v': opt.verbose++; break;
1578 : case 'e': opt.echo++; break;
1579 : case 'd': opt.debug++; break;
1580 : case 'o': opt.outfile = pargs.r.ret_str; break;
1581 : case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
1582 : case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
1583 : case 500: opt.a_long_one++; break;
1584 : default : pargs.err = ARGPARSE_PRINT_WARNING; break;
1585 : }
1586 : }
1587 : for (i=0; i < argc; i++ )
1588 : printf ("%3d -> (%s)\n", i, argv[i] );
1589 : puts ("Options:");
1590 : if (opt.verbose)
1591 : printf (" verbose=%d\n", opt.verbose );
1592 : if (opt.debug)
1593 : printf (" debug=%d\n", opt.debug );
1594 : if (opt.outfile)
1595 : printf (" outfile='%s'\n", opt.outfile );
1596 : if (opt.crf)
1597 : printf (" crffile='%s'\n", opt.crf );
1598 : if (opt.myopt)
1599 : printf (" myopt=%d\n", opt.myopt );
1600 : if (opt.a_long_one)
1601 : printf (" a-long-one=%d\n", opt.a_long_one );
1602 : if (opt.echo)
1603 : printf (" echo=%d\n", opt.echo );
1604 :
1605 : return 0;
1606 : }
1607 : #endif /*TEST*/
1608 :
1609 : /**** bottom of file ****/
|