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
NAME(struct _scanopt_t * s,int i)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
PRINTLEN(struct _scanopt_t * s,int i)81 static int PRINTLEN (struct _scanopt_t *s, int i)
82 {
83 return s->aux[i].printlen;
84 }
85
RVAL(struct _scanopt_t * s,int i)86 static int RVAL (struct _scanopt_t *s, int i)
87 {
88 return s->options[i].r_val;
89 }
90
FLAGS(struct _scanopt_t * s,int i)91 static int FLAGS (struct _scanopt_t *s, int i)
92 {
93 return s->aux[i].flags;
94 }
95
DESC(struct _scanopt_t * s,int i)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
get_cols(void)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
scanopt_init(const optspec_t * options,int argc,char ** argv,int flags)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 */
scanopt_usage(scanopt_t * scanner,FILE * fp,const char * usage)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
scanopt_err(struct _scanopt_t * s,int is_short,int err)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 */
matchlongopt(char * str,char ** optname,int * optlen,char ** arg,int * arglen)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. */
find_opt(struct _scanopt_t * s,int lookup_long,char * optstart,int len,int * err_code,int * opt_offset)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
scanopt(scanopt_t * svoid,char ** arg,int * optindex)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
scanopt_destroy(scanopt_t * svoid)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