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