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