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