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