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