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
45struct _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
52struct _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. */
66static const char *NAME(struct _scanopt_t *, int);
67static int PRINTLEN(struct _scanopt_t *, int);
68static int RVAL(struct _scanopt_t *, int);
69static int FLAGS(struct _scanopt_t *, int);
70static const char *DESC(struct _scanopt_t *, int);
71static int scanopt_err(struct _scanopt_t *, int, int);
72static int matchlongopt(char *, char **, int *, char **, int *);
73static int find_opt(struct _scanopt_t *, int, char *, int, int *, int *opt_offset);
74
75static 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
81static int PRINTLEN (struct _scanopt_t *s, int i)
82{
83	return s->aux[i].printlen;
84}
85
86static int RVAL (struct _scanopt_t *s, int i)
87{
88	return s->options[i].r_val;
89}
90
91static int FLAGS (struct _scanopt_t *s, int i)
92{
93	return s->aux[i].flags;
94}
95
96static 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
102static int get_cols (void);
103
104static 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
137scanopt_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(). */
210struct usg_elem {
211	int     idx;
212	struct usg_elem *next;
213	struct usg_elem *alias;
214};
215typedef 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 */
229int     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
500static 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 */
555static 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. */
597static 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
655int     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
801int     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