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