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