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