1 /* flex - tool to generate fast lexical analyzers */ 2 3 /* Copyright (c) 1990 The Regents of the University of California. */ 4 /* All rights reserved. */ 5 6 /* This code is derived from software contributed to Berkeley by */ 7 /* Vern Paxson. */ 8 9 /* The United States Government has rights in this work pursuant */ 10 /* to contract no. DE-AC03-76SF00098 between the United States */ 11 /* Department of Energy and the University of California. */ 12 13 /* This file is part of flex. */ 14 15 /* Redistribution and use in source and binary forms, with or without */ 16 /* modification, are permitted provided that the following conditions */ 17 /* are met: */ 18 19 /* 1. Redistributions of source code must retain the above copyright */ 20 /* notice, this list of conditions and the following disclaimer. */ 21 /* 2. Redistributions in binary form must reproduce the above copyright */ 22 /* notice, this list of conditions and the following disclaimer in the */ 23 /* documentation and/or other materials provided with the distribution. */ 24 25 /* Neither the name of the University nor the names of its contributors */ 26 /* may be used to endorse or promote products derived from this software */ 27 /* without specific prior written permission. */ 28 29 /* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */ 30 /* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */ 31 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */ 32 /* PURPOSE. */ 33 34 #include "flexdef.h" 36 #include "scanopt.h" 37 38 39 /* Internal structures */ 40 41 #ifdef HAVE_STRCASECMP 42 #define STRCASECMP(a,b) strcasecmp(a,b) 43 #else 44 static int STRCASECMP PROTO ((const char *, const char *)); 45 46 static int STRCASECMP (a, b) 47 const char *a; 48 const char *b; 49 { 50 while (tolower (*a++) == tolower (*b++)) ; 51 return b - a; 52 } 53 #endif 54 55 #define ARG_NONE 0x01 56 #define ARG_REQ 0x02 57 #define ARG_OPT 0x04 58 #define IS_LONG 0x08 59 60 struct _aux { 61 int flags; /* The above hex flags. */ 62 int namelen; /* Length of the actual option word, e.g., "--file[=foo]" is 4 */ 63 int printlen; /* Length of entire string, e.g., "--file[=foo]" is 12 */ 64 }; 65 66 67 struct _scanopt_t { 68 const optspec_t *options; /* List of options. */ 69 struct _aux *aux; /* Auxiliary data about options. */ 70 int optc; /* Number of options. */ 71 int argc; /* Number of args. */ 72 char **argv; /* Array of strings. */ 73 int index; /* Used as: argv[index][subscript]. */ 74 int subscript; 75 char no_err_msg; /* If true, do not print errors. */ 76 char has_long; 77 char has_short; 78 }; 79 80 /* Accessor functions. These WOULD be one-liners, but portability calls. */ 81 static const char *NAME PROTO ((struct _scanopt_t *, int)); 82 static int PRINTLEN PROTO ((struct _scanopt_t *, int)); 83 static int RVAL PROTO ((struct _scanopt_t *, int)); 84 static int FLAGS PROTO ((struct _scanopt_t *, int)); 85 static const char *DESC PROTO ((struct _scanopt_t *, int)); 86 static int scanopt_err PROTO ((struct _scanopt_t *, int, int, int)); 87 static int matchlongopt PROTO ((char *, char **, int *, char **, int *)); 88 static int find_opt 89 PROTO ((struct _scanopt_t *, int, char *, int, int *, int *opt_offset)); 90 91 static const char *NAME (s, i) 92 struct _scanopt_t *s; 93 int i; 94 { 95 return s->options[i].opt_fmt + 96 ((s->aux[i].flags & IS_LONG) ? 2 : 1); 97 } 98 99 static int PRINTLEN (s, i) 100 struct _scanopt_t *s; 101 int i; 102 { 103 return s->aux[i].printlen; 104 } 105 106 static int RVAL (s, i) 107 struct _scanopt_t *s; 108 int i; 109 { 110 return s->options[i].r_val; 111 } 112 113 static int FLAGS (s, i) 114 struct _scanopt_t *s; 115 int i; 116 { 117 return s->aux[i].flags; 118 } 119 120 static const char *DESC (s, i) 121 struct _scanopt_t *s; 122 int i; 123 { 124 return s->options[i].desc ? s->options[i].desc : ""; 125 } 126 127 #ifndef NO_SCANOPT_USAGE 128 static int get_cols PROTO ((void)); 129 130 static int get_cols () 131 { 132 char *env; 133 int cols = 80; /* default */ 134 135 #ifdef HAVE_NCURSES_H 136 initscr (); 137 endwin (); 138 if (COLS > 0) 139 return COLS; 140 #endif 141 142 if ((env = getenv ("COLUMNS")) != NULL) 143 cols = atoi (env); 144 145 return cols; 146 } 147 #endif 148 149 /* Macro to check for NULL before assigning a value. */ 150 #define SAFE_ASSIGN(ptr,val) \ 151 do{ \ 152 if((ptr)!=NULL) \ 153 *(ptr) = val; \ 154 }while(0) 155 156 /* Macro to assure we reset subscript whenever we adjust s->index.*/ 157 #define INC_INDEX(s,n) \ 158 do{ \ 159 (s)->index += (n); \ 160 (s)->subscript= 0; \ 161 }while(0) 162 163 scanopt_t *scanopt_init (options, argc, argv, flags) 164 const optspec_t *options; 165 int argc; 166 char **argv; 167 int flags; 168 { 169 int i; 170 struct _scanopt_t *s; 171 s = (struct _scanopt_t *) malloc (sizeof (struct _scanopt_t)); 172 173 s->options = options; 174 s->optc = 0; 175 s->argc = argc; 176 s->argv = (char **) argv; 177 s->index = 1; 178 s->subscript = 0; 179 s->no_err_msg = (flags & SCANOPT_NO_ERR_MSG); 180 s->has_long = 0; 181 s->has_short = 0; 182 183 /* Determine option count. (Find entry with all zeros). */ 184 s->optc = 0; 185 while (options[s->optc].opt_fmt 186 || options[s->optc].r_val || options[s->optc].desc) 187 s->optc++; 188 189 /* Build auxiliary data */ 190 s->aux = (struct _aux *) malloc (s->optc * sizeof (struct _aux)); 191 192 for (i = 0; i < s->optc; i++) { 193 const char *p, *pname; 194 const struct optspec_t *opt; 195 struct _aux *aux; 196 197 opt = s->options + i; 198 aux = s->aux + i; 199 200 aux->flags = ARG_NONE; 201 202 if (opt->opt_fmt[0] == '-' && opt->opt_fmt[1] == '-') { 203 aux->flags |= IS_LONG; 204 pname = opt->opt_fmt + 2; 205 s->has_long = 1; 206 } 207 else { 208 pname = opt->opt_fmt + 1; 209 s->has_short = 1; 210 } 211 aux->printlen = strlen (opt->opt_fmt); 212 213 aux->namelen = 0; 214 for (p = pname + 1; *p; p++) { 215 /* detect required arg */ 216 if (*p == '=' || isspace (*p) 217 || !(aux->flags & IS_LONG)) { 218 if (aux->namelen == 0) 219 aux->namelen = p - pname; 220 aux->flags |= ARG_REQ; 221 aux->flags &= ~ARG_NONE; 222 } 223 /* detect optional arg. This overrides required arg. */ 224 if (*p == '[') { 225 if (aux->namelen == 0) 226 aux->namelen = p - pname; 227 aux->flags &= ~(ARG_REQ | ARG_NONE); 228 aux->flags |= ARG_OPT; 229 break; 230 } 231 } 232 if (aux->namelen == 0) 233 aux->namelen = p - pname; 234 } 235 return (scanopt_t *) s; 236 } 237 238 #ifndef NO_SCANOPT_USAGE 239 /* these structs are for scanopt_usage(). */ 240 struct usg_elem { 241 int idx; 242 struct usg_elem *next; 243 struct usg_elem *alias; 244 }; 245 typedef struct usg_elem usg_elem; 246 247 248 /* Prints a usage message based on contents of optlist. 249 * Parameters: 250 * scanner - The scanner, already initialized with scanopt_init(). 251 * fp - The file stream to write to. 252 * usage - Text to be prepended to option list. 253 * Return: Always returns 0 (zero). 254 * The output looks something like this: 255 256 [indent][option, alias1, alias2...][indent][description line1 257 description line2...] 258 */ 259 int scanopt_usage (scanner, fp, usage) 260 scanopt_t *scanner; 261 FILE *fp; 262 const char *usage; 263 { 264 struct _scanopt_t *s; 265 int i, columns, indent = 2; 266 usg_elem *byr_val = NULL; /* option indices sorted by r_val */ 267 usg_elem *store; /* array of preallocated elements. */ 268 int store_idx = 0; 269 usg_elem *ue; 270 int maxlen[2]; 271 int desccol = 0; 272 int print_run = 0; 273 274 maxlen[0] = 0; 275 maxlen[1] = 0; 276 277 s = (struct _scanopt_t *) scanner; 278 279 if (usage) { 280 fprintf (fp, "%s\n", usage); 281 } 282 else { 283 /* Find the basename of argv[0] */ 284 const char *p; 285 286 p = s->argv[0] + strlen (s->argv[0]); 287 while (p != s->argv[0] && *p != '/') 288 --p; 289 if (*p == '/') 290 p++; 291 292 fprintf (fp, _("Usage: %s [OPTIONS]...\n"), p); 293 } 294 fprintf (fp, "\n"); 295 296 /* Sort by r_val and string. Yes, this is O(n*n), but n is small. */ 297 store = (usg_elem *) malloc (s->optc * sizeof (usg_elem)); 298 for (i = 0; i < s->optc; i++) { 299 300 /* grab the next preallocate node. */ 301 ue = store + store_idx++; 302 ue->idx = i; 303 ue->next = ue->alias = NULL; 304 305 /* insert into list. */ 306 if (!byr_val) 307 byr_val = ue; 308 else { 309 int found_alias = 0; 310 usg_elem **ue_curr, **ptr_if_no_alias = NULL; 311 312 ue_curr = &byr_val; 313 while (*ue_curr) { 314 if (RVAL (s, (*ue_curr)->idx) == 315 RVAL (s, ue->idx)) { 316 /* push onto the alias list. */ 317 ue_curr = &((*ue_curr)->alias); 318 found_alias = 1; 319 break; 320 } 321 if (!ptr_if_no_alias 322 && 323 STRCASECMP (NAME (s, (*ue_curr)->idx), 324 NAME (s, ue->idx)) > 0) { 325 ptr_if_no_alias = ue_curr; 326 } 327 ue_curr = &((*ue_curr)->next); 328 } 329 if (!found_alias && ptr_if_no_alias) 330 ue_curr = ptr_if_no_alias; 331 ue->next = *ue_curr; 332 *ue_curr = ue; 333 } 334 } 335 336 #if 0 337 if (1) { 338 printf ("ORIGINAL:\n"); 339 for (i = 0; i < s->optc; i++) 340 printf ("%2d: %s\n", i, NAME (s, i)); 341 printf ("SORTED:\n"); 342 ue = byr_val; 343 while (ue) { 344 usg_elem *ue2; 345 346 printf ("%2d: %s\n", ue->idx, NAME (s, ue->idx)); 347 for (ue2 = ue->alias; ue2; ue2 = ue2->next) 348 printf (" +---> %2d: %s\n", ue2->idx, 349 NAME (s, ue2->idx)); 350 ue = ue->next; 351 } 352 } 353 #endif 354 355 /* Now build each row of output. */ 356 357 /* first pass calculate how much room we need. */ 358 for (ue = byr_val; ue; ue = ue->next) { 359 usg_elem *ap; 360 int len = 0; 361 int nshort = 0, nlong = 0; 362 363 364 #define CALC_LEN(i) do {\ 365 if(FLAGS(s,i) & IS_LONG) \ 366 len += (nlong++||nshort) ? 2+PRINTLEN(s,i) : PRINTLEN(s,i);\ 367 else\ 368 len += (nshort++||nlong)? 2+PRINTLEN(s,i) : PRINTLEN(s,i);\ 369 }while(0) 370 371 if (!(FLAGS (s, ue->idx) & IS_LONG)) 372 CALC_LEN (ue->idx); 373 374 /* do short aliases first. */ 375 for (ap = ue->alias; ap; ap = ap->next) { 376 if (FLAGS (s, ap->idx) & IS_LONG) 377 continue; 378 CALC_LEN (ap->idx); 379 } 380 381 if (FLAGS (s, ue->idx) & IS_LONG) 382 CALC_LEN (ue->idx); 383 384 /* repeat the above loop, this time for long aliases. */ 385 for (ap = ue->alias; ap; ap = ap->next) { 386 if (!(FLAGS (s, ap->idx) & IS_LONG)) 387 continue; 388 CALC_LEN (ap->idx); 389 } 390 391 if (len > maxlen[0]) 392 maxlen[0] = len; 393 394 /* It's much easier to calculate length for description column! */ 395 len = strlen (DESC (s, ue->idx)); 396 if (len > maxlen[1]) 397 maxlen[1] = len; 398 } 399 400 /* Determine how much room we have, and how much we will allocate to each col. 401 * Do not address pathological cases. Output will just be ugly. */ 402 columns = get_cols () - 1; 403 if (maxlen[0] + maxlen[1] + indent * 2 > columns) { 404 /* col 0 gets whatever it wants. we'll wrap the desc col. */ 405 maxlen[1] = columns - (maxlen[0] + indent * 2); 406 if (maxlen[1] < 14) /* 14 is arbitrary lower limit on desc width. */ 407 maxlen[1] = INT_MAX; 408 } 409 desccol = maxlen[0] + indent * 2; 410 411 #define PRINT_SPACES(fp,n)\ 412 do{\ 413 int _n;\ 414 _n=(n);\ 415 while(_n-- > 0)\ 416 fputc(' ',(fp));\ 417 }while(0) 418 419 420 /* Second pass (same as above loop), this time we print. */ 421 /* Sloppy hack: We iterate twice. The first time we print short and long options. 422 The second time we print those lines that have ONLY long options. */ 423 while (print_run++ < 2) { 424 for (ue = byr_val; ue; ue = ue->next) { 425 usg_elem *ap; 426 int nwords = 0, nchars = 0, has_short = 0; 427 428 /* TODO: get has_short schtick to work */ 429 has_short = !(FLAGS (s, ue->idx) & IS_LONG); 430 for (ap = ue->alias; ap; ap = ap->next) { 431 if (!(FLAGS (s, ap->idx) & IS_LONG)) { 432 has_short = 1; 433 break; 434 } 435 } 436 if ((print_run == 1 && !has_short) || 437 (print_run == 2 && has_short)) 438 continue; 439 440 PRINT_SPACES (fp, indent); 441 nchars += indent; 442 443 /* Print, adding a ", " between aliases. */ 444 #define PRINT_IT(i) do{\ 445 if(nwords++)\ 446 nchars+=fprintf(fp,", ");\ 447 nchars+=fprintf(fp,"%s",s->options[i].opt_fmt);\ 448 }while(0) 449 450 if (!(FLAGS (s, ue->idx) & IS_LONG)) 451 PRINT_IT (ue->idx); 452 453 /* print short aliases first. */ 454 for (ap = ue->alias; ap; ap = ap->next) { 455 if (!(FLAGS (s, ap->idx) & IS_LONG)) 456 PRINT_IT (ap->idx); 457 } 458 459 460 if (FLAGS (s, ue->idx) & IS_LONG) 461 PRINT_IT (ue->idx); 462 463 /* repeat the above loop, this time for long aliases. */ 464 for (ap = ue->alias; ap; ap = ap->next) { 465 if (FLAGS (s, ap->idx) & IS_LONG) 466 PRINT_IT (ap->idx); 467 } 468 469 /* pad to desccol */ 470 PRINT_SPACES (fp, desccol - nchars); 471 472 /* Print description, wrapped to maxlen[1] columns. */ 473 if (1) { 474 const char *pstart; 475 476 pstart = DESC (s, ue->idx); 477 while (1) { 478 int n = 0; 479 const char *lastws = NULL, *p; 480 481 p = pstart; 482 483 while (*p && n < maxlen[1] 484 && *p != '\n') { 485 if (isspace (*p) 486 || *p == '-') lastws = 487 p; 488 n++; 489 p++; 490 } 491 492 if (!*p) { /* hit end of desc. done. */ 493 fprintf (fp, "%s\n", 494 pstart); 495 break; 496 } 497 else if (*p == '\n') { /* print everything up to here then wrap. */ 498 fprintf (fp, "%.*s\n", n, 499 pstart); 500 PRINT_SPACES (fp, desccol); 501 pstart = p + 1; 502 continue; 503 } 504 else { /* we hit the edge of the screen. wrap at space if possible. */ 505 if (lastws) { 506 fprintf (fp, 507 "%.*s\n", 508 lastws - 509 pstart, 510 pstart); 511 pstart = 512 lastws + 1; 513 } 514 else { 515 fprintf (fp, 516 "%.*s\n", 517 n, 518 pstart); 519 pstart = p + 1; 520 } 521 PRINT_SPACES (fp, desccol); 522 continue; 523 } 524 } 525 } 526 } 527 } /* end while */ 528 free (store); 529 return 0; 530 } 531 #endif /* no scanopt_usage */ 532 533 534 static int scanopt_err (s, opt_offset, is_short, err) 535 struct _scanopt_t *s; 536 int opt_offset; 537 int is_short; 538 int err; 539 { 540 const char *optname = ""; 541 char optchar[2]; 542 const optspec_t *opt = NULL; 543 544 if (opt_offset >= 0) 545 opt = s->options + opt_offset; 546 547 if (!s->no_err_msg) { 548 549 if (s->index > 0 && s->index < s->argc) { 550 if (is_short) { 551 optchar[0] = 552 s->argv[s->index][s->subscript]; 553 optchar[1] = '\0'; 554 optname = optchar; 555 } 556 else { 557 optname = s->argv[s->index]; 558 } 559 } 560 561 fprintf (stderr, "%s: ", s->argv[0]); 562 switch (err) { 563 case SCANOPT_ERR_ARG_NOT_ALLOWED: 564 fprintf (stderr, 565 _ 566 ("option `%s' doesn't allow an argument\n"), 567 optname); 568 break; 569 case SCANOPT_ERR_ARG_NOT_FOUND: 570 fprintf (stderr, 571 _("option `%s' requires an argument\n"), 572 optname); 573 break; 574 case SCANOPT_ERR_OPT_AMBIGUOUS: 575 fprintf (stderr, _("option `%s' is ambiguous\n"), 576 optname); 577 break; 578 case SCANOPT_ERR_OPT_UNRECOGNIZED: 579 fprintf (stderr, _("Unrecognized option `%s'\n"), 580 optname); 581 break; 582 default: 583 fprintf (stderr, _("Unknown error=(%d)\n"), err); 584 break; 585 } 586 } 587 return err; 588 } 589 590 592 /* Internal. Match str against the regex ^--([^=]+)(=(.*))? 593 * return 1 if *looks* like a long option. 594 * 'str' is the only input argument, the rest of the arguments are output only. 595 * optname will point to str + 2 596 * 597 */ 598 static int matchlongopt (str, optname, optlen, arg, arglen) 599 char *str; 600 char **optname; 601 int *optlen; 602 char **arg; 603 int *arglen; 604 { 605 char *p; 606 607 *optname = *arg = (char *) 0; 608 *optlen = *arglen = 0; 609 610 /* Match regex /--./ */ 611 p = str; 612 if (p[0] != '-' || p[1] != '-' || !p[2]) 613 return 0; 614 615 p += 2; 616 *optname = (char *) p; 617 618 /* find the end of optname */ 619 while (*p && *p != '=') 620 ++p; 621 622 *optlen = p - *optname; 623 624 if (!*p) 625 /* an option with no '=...' part. */ 626 return 1; 627 628 629 /* We saw an '=' char. The rest of p is the arg. */ 630 p++; 631 *arg = p; 632 while (*p) 633 ++p; 634 *arglen = p - *arg; 635 636 return 1; 637 } 638 639 641 /* Internal. Look up long or short option by name. 642 * Long options must match a non-ambiguous prefix, or exact match. 643 * Short options must be exact. 644 * Return boolean true if found and no error. 645 * Error stored in err_code or zero if no error. */ 646 static int find_opt (s, lookup_long, optstart, len, err_code, opt_offset) 647 struct _scanopt_t *s; 648 int lookup_long; 649 char *optstart; 650 int len; 651 int *err_code; 652 int *opt_offset; 653 { 654 int nmatch = 0, lastr_val = 0, i; 655 656 *err_code = 0; 657 *opt_offset = -1; 658 659 if (!optstart) 660 return 0; 661 662 for (i = 0; i < s->optc; i++) { 663 char *optname; 664 665 optname = 666 (char *) (s->options[i].opt_fmt + 667 (lookup_long ? 2 : 1)); 668 669 if (lookup_long && (s->aux[i].flags & IS_LONG)) { 670 if (len > s->aux[i].namelen) 671 continue; 672 673 if (strncmp (optname, optstart, len) == 0) { 674 nmatch++; 675 *opt_offset = i; 676 677 /* exact match overrides all. */ 678 if (len == s->aux[i].namelen) { 679 nmatch = 1; 680 break; 681 } 682 683 /* ambiguity is ok between aliases. */ 684 if (lastr_val 685 && lastr_val == 686 s->options[i].r_val) nmatch--; 687 lastr_val = s->options[i].r_val; 688 } 689 } 690 else if (!lookup_long && !(s->aux[i].flags & IS_LONG)) { 691 if (optname[0] == optstart[0]) { 692 nmatch++; 693 *opt_offset = i; 694 } 695 } 696 } 697 698 if (nmatch == 0) { 699 *err_code = SCANOPT_ERR_OPT_UNRECOGNIZED; 700 *opt_offset = -1; 701 } 702 else if (nmatch > 1) { 703 *err_code = SCANOPT_ERR_OPT_AMBIGUOUS; 704 *opt_offset = -1; 705 } 706 707 return *err_code ? 0 : 1; 708 } 709 710 712 int scanopt (svoid, arg, optindex) 713 scanopt_t *svoid; 714 char **arg; 715 int *optindex; 716 { 717 char *optname = NULL, *optarg = NULL, *pstart; 718 int namelen = 0, arglen = 0; 719 int errcode = 0, has_next; 720 const optspec_t *optp; 721 struct _scanopt_t *s; 722 struct _aux *auxp; 723 int is_short; 724 int opt_offset = -1; 725 726 s = (struct _scanopt_t *) svoid; 727 728 /* Normalize return-parameters. */ 729 SAFE_ASSIGN (arg, NULL); 730 SAFE_ASSIGN (optindex, s->index); 731 732 if (s->index >= s->argc) 733 return 0; 734 735 /* pstart always points to the start of our current scan. */ 736 pstart = s->argv[s->index] + s->subscript; 737 if (!pstart) 738 return 0; 739 740 if (s->subscript == 0) { 741 742 /* test for exact match of "--" */ 743 if (pstart[0] == '-' && pstart[1] == '-' && !pstart[2]) { 744 SAFE_ASSIGN (optindex, s->index + 1); 745 INC_INDEX (s, 1); 746 return 0; 747 } 748 749 /* Match an opt. */ 750 if (matchlongopt 751 (pstart, &optname, &namelen, &optarg, &arglen)) { 752 753 /* it LOOKS like an opt, but is it one?! */ 754 if (!find_opt 755 (s, 1, optname, namelen, &errcode, 756 &opt_offset)) { 757 scanopt_err (s, opt_offset, 0, errcode); 758 return errcode; 759 } 760 /* We handle this below. */ 761 is_short = 0; 762 763 /* Check for short opt. */ 764 } 765 else if (pstart[0] == '-' && pstart[1]) { 766 /* Pass through to below. */ 767 is_short = 1; 768 s->subscript++; 769 pstart++; 770 } 771 772 else { 773 /* It's not an option. We're done. */ 774 return 0; 775 } 776 } 777 778 /* We have to re-check the subscript status because it 779 * may have changed above. */ 780 781 if (s->subscript != 0) { 782 783 /* we are somewhere in a run of short opts, 784 * e.g., at the 'z' in `tar -xzf` */ 785 786 optname = pstart; 787 namelen = 1; 788 is_short = 1; 789 790 if (!find_opt 791 (s, 0, pstart, namelen, &errcode, &opt_offset)) { 792 return scanopt_err (s, opt_offset, 1, errcode); 793 } 794 795 optarg = pstart + 1; 796 if (!*optarg) { 797 optarg = NULL; 798 arglen = 0; 799 } 800 else 801 arglen = strlen (optarg); 802 } 803 804 /* At this point, we have a long or short option matched at opt_offset into 805 * the s->options array (and corresponding aux array). 806 * A trailing argument is in {optarg,arglen}, if any. 807 */ 808 809 /* Look ahead in argv[] to see if there is something 810 * that we can use as an argument (if needed). */ 811 has_next = s->index + 1 < s->argc 812 && strcmp ("--", s->argv[s->index + 1]) != 0; 813 814 optp = s->options + opt_offset; 815 auxp = s->aux + opt_offset; 816 817 /* case: no args allowed */ 818 if (auxp->flags & ARG_NONE) { 819 if (optarg && !is_short) { 820 scanopt_err (s, opt_offset, is_short, errcode = 821 SCANOPT_ERR_ARG_NOT_ALLOWED); 822 INC_INDEX (s, 1); 823 return errcode; 824 } 825 else if (!optarg) 826 INC_INDEX (s, 1); 827 else 828 s->subscript++; 829 return optp->r_val; 830 } 831 832 /* case: required */ 833 if (auxp->flags & ARG_REQ) { 834 if (!optarg && !has_next) 835 return scanopt_err (s, opt_offset, is_short, 836 SCANOPT_ERR_ARG_NOT_FOUND); 837 838 if (!optarg) { 839 /* Let the next argv element become the argument. */ 840 SAFE_ASSIGN (arg, s->argv[s->index + 1]); 841 INC_INDEX (s, 2); 842 } 843 else { 844 SAFE_ASSIGN (arg, (char *) optarg); 845 INC_INDEX (s, 1); 846 } 847 return optp->r_val; 848 } 849 850 /* case: optional */ 851 if (auxp->flags & ARG_OPT) { 852 SAFE_ASSIGN (arg, optarg); 853 INC_INDEX (s, 1); 854 return optp->r_val; 855 } 856 857 858 /* Should not reach here. */ 859 return 0; 860 } 861 862 863 int scanopt_destroy (svoid) 864 scanopt_t *svoid; 865 { 866 struct _scanopt_t *s; 867 868 s = (struct _scanopt_t *) svoid; 869 if (s) { 870 if (s->aux) 871 free (s->aux); 872 free (s); 873 } 874 return 0; 875 } 876 877 878 /* vim:set tabstop=8 softtabstop=4 shiftwidth=4: */ 879