xref: /minix3/external/bsd/flex/dist/scanopt.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: scanopt.c,v 1.6 2014/10/30 18:44:05 christos Exp $	*/
2357f1050SThomas Veerman 
3357f1050SThomas Veerman /* flex - tool to generate fast lexical analyzers */
4357f1050SThomas Veerman 
5357f1050SThomas Veerman /*  Copyright (c) 1990 The Regents of the University of California. */
6357f1050SThomas Veerman /*  All rights reserved. */
7357f1050SThomas Veerman 
8357f1050SThomas Veerman /*  This code is derived from software contributed to Berkeley by */
9357f1050SThomas Veerman /*  Vern Paxson. */
10357f1050SThomas Veerman 
11357f1050SThomas Veerman /*  The United States Government has rights in this work pursuant */
12357f1050SThomas Veerman /*  to contract no. DE-AC03-76SF00098 between the United States */
13357f1050SThomas Veerman /*  Department of Energy and the University of California. */
14357f1050SThomas Veerman 
15357f1050SThomas Veerman /*  This file is part of flex. */
16357f1050SThomas Veerman 
17357f1050SThomas Veerman /*  Redistribution and use in source and binary forms, with or without */
18357f1050SThomas Veerman /*  modification, are permitted provided that the following conditions */
19357f1050SThomas Veerman /*  are met: */
20357f1050SThomas Veerman 
21357f1050SThomas Veerman /*  1. Redistributions of source code must retain the above copyright */
22357f1050SThomas Veerman /*     notice, this list of conditions and the following disclaimer. */
23357f1050SThomas Veerman /*  2. Redistributions in binary form must reproduce the above copyright */
24357f1050SThomas Veerman /*     notice, this list of conditions and the following disclaimer in the */
25357f1050SThomas Veerman /*     documentation and/or other materials provided with the distribution. */
26357f1050SThomas Veerman 
27357f1050SThomas Veerman /*  Neither the name of the University nor the names of its contributors */
28357f1050SThomas Veerman /*  may be used to endorse or promote products derived from this software */
29357f1050SThomas Veerman /*  without specific prior written permission. */
30357f1050SThomas Veerman 
31357f1050SThomas Veerman /*  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */
32357f1050SThomas Veerman /*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
33357f1050SThomas Veerman /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
34357f1050SThomas Veerman /*  PURPOSE. */
35357f1050SThomas Veerman #include "flexdef.h"
36*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: scanopt.c,v 1.6 2014/10/30 18:44:05 christos Exp $");
37*0a6a1f1dSLionel Sambuc 
38357f1050SThomas Veerman #include "scanopt.h"
39357f1050SThomas Veerman 
40357f1050SThomas Veerman 
41357f1050SThomas Veerman /* Internal structures */
42357f1050SThomas Veerman 
43357f1050SThomas Veerman #ifdef HAVE_STRCASECMP
44357f1050SThomas Veerman #define STRCASECMP(a,b) strcasecmp(a,b)
45357f1050SThomas Veerman #else
46357f1050SThomas Veerman static int STRCASECMP PROTO ((const char *, const char *));
47357f1050SThomas Veerman 
STRCASECMP(a,b)48357f1050SThomas Veerman static int STRCASECMP (a, b)
49357f1050SThomas Veerman      const char *a;
50357f1050SThomas Veerman      const char *b;
51357f1050SThomas Veerman {
52357f1050SThomas Veerman 	while (tolower ((unsigned char)*a++) == tolower ((unsigned char)*b++)) ;
53357f1050SThomas Veerman 	return b - a;
54357f1050SThomas Veerman }
55357f1050SThomas Veerman #endif
56357f1050SThomas Veerman 
57357f1050SThomas Veerman #define ARG_NONE 0x01
58357f1050SThomas Veerman #define ARG_REQ  0x02
59357f1050SThomas Veerman #define ARG_OPT  0x04
60357f1050SThomas Veerman #define IS_LONG  0x08
61357f1050SThomas Veerman 
62357f1050SThomas Veerman struct _aux {
63357f1050SThomas Veerman 	int     flags;		/* The above hex flags. */
64357f1050SThomas Veerman 	int     namelen;	/* Length of the actual option word, e.g., "--file[=foo]" is 4 */
65357f1050SThomas Veerman 	int     printlen;	/* Length of entire string, e.g., "--file[=foo]" is 12 */
66357f1050SThomas Veerman };
67357f1050SThomas Veerman 
68357f1050SThomas Veerman 
69357f1050SThomas Veerman struct _scanopt_t {
70357f1050SThomas Veerman 	const optspec_t *options;	/* List of options. */
71357f1050SThomas Veerman 	struct _aux *aux;	/* Auxiliary data about options. */
72357f1050SThomas Veerman 	int     optc;		/* Number of options. */
73357f1050SThomas Veerman 	int     argc;		/* Number of args. */
74357f1050SThomas Veerman 	char  **argv;		/* Array of strings. */
75357f1050SThomas Veerman 	int     index;		/* Used as: argv[index][subscript]. */
76357f1050SThomas Veerman 	int     subscript;
77357f1050SThomas Veerman 	char    no_err_msg;	/* If true, do not print errors. */
78357f1050SThomas Veerman 	char    has_long;
79357f1050SThomas Veerman 	char    has_short;
80357f1050SThomas Veerman };
81357f1050SThomas Veerman 
82357f1050SThomas Veerman /* Accessor functions. These WOULD be one-liners, but portability calls. */
83357f1050SThomas Veerman static const char *NAME PROTO ((struct _scanopt_t *, int));
84357f1050SThomas Veerman static int PRINTLEN PROTO ((struct _scanopt_t *, int));
85357f1050SThomas Veerman static int RVAL PROTO ((struct _scanopt_t *, int));
86357f1050SThomas Veerman static int FLAGS PROTO ((struct _scanopt_t *, int));
87357f1050SThomas Veerman static const char *DESC PROTO ((struct _scanopt_t *, int));
88357f1050SThomas Veerman static int scanopt_err PROTO ((struct _scanopt_t *, int, int, int));
89357f1050SThomas Veerman static int matchlongopt PROTO ((char *, char **, int *, char **, int *));
90357f1050SThomas Veerman static int find_opt
91357f1050SThomas Veerman PROTO ((struct _scanopt_t *, int, char *, int, int *, int *opt_offset));
92357f1050SThomas Veerman 
NAME(s,i)93357f1050SThomas Veerman static const char *NAME (s, i)
94357f1050SThomas Veerman      struct _scanopt_t *s;
95357f1050SThomas Veerman      int     i;
96357f1050SThomas Veerman {
97357f1050SThomas Veerman 	return s->options[i].opt_fmt +
98357f1050SThomas Veerman 		((s->aux[i].flags & IS_LONG) ? 2 : 1);
99357f1050SThomas Veerman }
100357f1050SThomas Veerman 
PRINTLEN(s,i)101357f1050SThomas Veerman static int PRINTLEN (s, i)
102357f1050SThomas Veerman      struct _scanopt_t *s;
103357f1050SThomas Veerman      int     i;
104357f1050SThomas Veerman {
105357f1050SThomas Veerman 	return s->aux[i].printlen;
106357f1050SThomas Veerman }
107357f1050SThomas Veerman 
RVAL(s,i)108357f1050SThomas Veerman static int RVAL (s, i)
109357f1050SThomas Veerman      struct _scanopt_t *s;
110357f1050SThomas Veerman      int     i;
111357f1050SThomas Veerman {
112357f1050SThomas Veerman 	return s->options[i].r_val;
113357f1050SThomas Veerman }
114357f1050SThomas Veerman 
FLAGS(s,i)115357f1050SThomas Veerman static int FLAGS (s, i)
116357f1050SThomas Veerman      struct _scanopt_t *s;
117357f1050SThomas Veerman      int     i;
118357f1050SThomas Veerman {
119357f1050SThomas Veerman 	return s->aux[i].flags;
120357f1050SThomas Veerman }
121357f1050SThomas Veerman 
DESC(s,i)122357f1050SThomas Veerman static const char *DESC (s, i)
123357f1050SThomas Veerman      struct _scanopt_t *s;
124357f1050SThomas Veerman      int     i;
125357f1050SThomas Veerman {
126357f1050SThomas Veerman 	return s->options[i].desc ? s->options[i].desc : "";
127357f1050SThomas Veerman }
128357f1050SThomas Veerman 
129357f1050SThomas Veerman #ifndef NO_SCANOPT_USAGE
130357f1050SThomas Veerman static int get_cols PROTO ((void));
131357f1050SThomas Veerman 
get_cols()132357f1050SThomas Veerman static int get_cols ()
133357f1050SThomas Veerman {
134357f1050SThomas Veerman 	char   *env;
135357f1050SThomas Veerman 	int     cols = 80;	/* default */
136357f1050SThomas Veerman 
137357f1050SThomas Veerman #ifdef HAVE_NCURSES_H
138357f1050SThomas Veerman 	initscr ();
139357f1050SThomas Veerman 	endwin ();
140357f1050SThomas Veerman 	if (COLS > 0)
141357f1050SThomas Veerman 		return COLS;
142357f1050SThomas Veerman #endif
143357f1050SThomas Veerman 
144357f1050SThomas Veerman 	if ((env = getenv ("COLUMNS")) != NULL)
145357f1050SThomas Veerman 		cols = atoi (env);
146357f1050SThomas Veerman 
147357f1050SThomas Veerman 	return cols;
148357f1050SThomas Veerman }
149357f1050SThomas Veerman #endif
150357f1050SThomas Veerman 
151357f1050SThomas Veerman /* Macro to check for NULL before assigning a value. */
152357f1050SThomas Veerman #define SAFE_ASSIGN(ptr,val) \
153357f1050SThomas Veerman     do{                      \
154357f1050SThomas Veerman         if((ptr)!=NULL)      \
155357f1050SThomas Veerman             *(ptr) = val;    \
156357f1050SThomas Veerman     }while(0)
157357f1050SThomas Veerman 
158357f1050SThomas Veerman /* Macro to assure we reset subscript whenever we adjust s->index.*/
159357f1050SThomas Veerman #define INC_INDEX(s,n)     \
160357f1050SThomas Veerman     do{                    \
161357f1050SThomas Veerman        (s)->index += (n);  \
162357f1050SThomas Veerman        (s)->subscript= 0;  \
163357f1050SThomas Veerman     }while(0)
164357f1050SThomas Veerman 
scanopt_init(options,argc,argv,flags)165357f1050SThomas Veerman scanopt_t *scanopt_init (options, argc, argv, flags)
166357f1050SThomas Veerman      const optspec_t *options;
167357f1050SThomas Veerman      int     argc;
168357f1050SThomas Veerman      char  **argv;
169357f1050SThomas Veerman      int     flags;
170357f1050SThomas Veerman {
171357f1050SThomas Veerman 	int     i;
172357f1050SThomas Veerman 	struct _scanopt_t *s;
173357f1050SThomas Veerman 	s = (struct _scanopt_t *) malloc (sizeof (struct _scanopt_t));
174357f1050SThomas Veerman 
175357f1050SThomas Veerman 	s->options = options;
176357f1050SThomas Veerman 	s->optc = 0;
177357f1050SThomas Veerman 	s->argc = argc;
178357f1050SThomas Veerman 	s->argv = (char **) argv;
179357f1050SThomas Veerman 	s->index = 1;
180357f1050SThomas Veerman 	s->subscript = 0;
181357f1050SThomas Veerman 	s->no_err_msg = (flags & SCANOPT_NO_ERR_MSG);
182357f1050SThomas Veerman 	s->has_long = 0;
183357f1050SThomas Veerman 	s->has_short = 0;
184357f1050SThomas Veerman 
185357f1050SThomas Veerman 	/* Determine option count. (Find entry with all zeros). */
186357f1050SThomas Veerman 	s->optc = 0;
187357f1050SThomas Veerman 	while (options[s->optc].opt_fmt
188357f1050SThomas Veerman 	       || options[s->optc].r_val || options[s->optc].desc)
189357f1050SThomas Veerman 		s->optc++;
190357f1050SThomas Veerman 
191357f1050SThomas Veerman 	/* Build auxiliary data */
192357f1050SThomas Veerman 	s->aux = (struct _aux *) malloc (s->optc * sizeof (struct _aux));
193357f1050SThomas Veerman 
194357f1050SThomas Veerman 	for (i = 0; i < s->optc; i++) {
19584d9c625SLionel Sambuc 		const Char *p, *pname;
196357f1050SThomas Veerman 		const struct optspec_t *opt;
197357f1050SThomas Veerman 		struct _aux *aux;
198357f1050SThomas Veerman 
199357f1050SThomas Veerman 		opt = s->options + i;
200357f1050SThomas Veerman 		aux = s->aux + i;
201357f1050SThomas Veerman 
202357f1050SThomas Veerman 		aux->flags = ARG_NONE;
203357f1050SThomas Veerman 
204357f1050SThomas Veerman 		if (opt->opt_fmt[0] == '-' && opt->opt_fmt[1] == '-') {
205357f1050SThomas Veerman 			aux->flags |= IS_LONG;
20684d9c625SLionel Sambuc 			pname = (const Char *)(opt->opt_fmt + 2);
207357f1050SThomas Veerman 			s->has_long = 1;
208357f1050SThomas Veerman 		}
209357f1050SThomas Veerman 		else {
21084d9c625SLionel Sambuc 			pname = (const Char *)(opt->opt_fmt + 1);
211357f1050SThomas Veerman 			s->has_short = 1;
212357f1050SThomas Veerman 		}
213357f1050SThomas Veerman 		aux->printlen = strlen (opt->opt_fmt);
214357f1050SThomas Veerman 
215357f1050SThomas Veerman 		aux->namelen = 0;
216357f1050SThomas Veerman 		for (p = pname + 1; *p; p++) {
217357f1050SThomas Veerman 			/* detect required arg */
218357f1050SThomas Veerman 			if (*p == '=' || isspace ((unsigned char)*p)
219357f1050SThomas Veerman 			    || !(aux->flags & IS_LONG)) {
220357f1050SThomas Veerman 				if (aux->namelen == 0)
221357f1050SThomas Veerman 					aux->namelen = p - pname;
222357f1050SThomas Veerman 				aux->flags |= ARG_REQ;
223357f1050SThomas Veerman 				aux->flags &= ~ARG_NONE;
224357f1050SThomas Veerman 			}
225357f1050SThomas Veerman 			/* detect optional arg. This overrides required arg. */
226357f1050SThomas Veerman 			if (*p == '[') {
227357f1050SThomas Veerman 				if (aux->namelen == 0)
228357f1050SThomas Veerman 					aux->namelen = p - pname;
229357f1050SThomas Veerman 				aux->flags &= ~(ARG_REQ | ARG_NONE);
230357f1050SThomas Veerman 				aux->flags |= ARG_OPT;
231357f1050SThomas Veerman 				break;
232357f1050SThomas Veerman 			}
233357f1050SThomas Veerman 		}
234357f1050SThomas Veerman 		if (aux->namelen == 0)
235357f1050SThomas Veerman 			aux->namelen = p - pname;
236357f1050SThomas Veerman 	}
237357f1050SThomas Veerman 	return (scanopt_t *) s;
238357f1050SThomas Veerman }
239357f1050SThomas Veerman 
240357f1050SThomas Veerman #ifndef NO_SCANOPT_USAGE
241357f1050SThomas Veerman /* these structs are for scanopt_usage(). */
242357f1050SThomas Veerman struct usg_elem {
243357f1050SThomas Veerman 	int     idx;
244357f1050SThomas Veerman 	struct usg_elem *next;
245357f1050SThomas Veerman 	struct usg_elem *alias;
246357f1050SThomas Veerman };
247357f1050SThomas Veerman typedef struct usg_elem usg_elem;
248357f1050SThomas Veerman 
249357f1050SThomas Veerman 
250357f1050SThomas Veerman /* Prints a usage message based on contents of optlist.
251357f1050SThomas Veerman  * Parameters:
252357f1050SThomas Veerman  *   scanner  - The scanner, already initialized with scanopt_init().
253357f1050SThomas Veerman  *   fp       - The file stream to write to.
254357f1050SThomas Veerman  *   usage    - Text to be prepended to option list.
255357f1050SThomas Veerman  * Return:  Always returns 0 (zero).
256357f1050SThomas Veerman  * The output looks something like this:
257357f1050SThomas Veerman 
258357f1050SThomas Veerman [indent][option, alias1, alias2...][indent][description line1
259357f1050SThomas Veerman                                             description line2...]
260357f1050SThomas Veerman  */
scanopt_usage(scanner,fp,usage)261357f1050SThomas Veerman int     scanopt_usage (scanner, fp, usage)
262357f1050SThomas Veerman      scanopt_t *scanner;
263357f1050SThomas Veerman      FILE   *fp;
264357f1050SThomas Veerman      const char *usage;
265357f1050SThomas Veerman {
266357f1050SThomas Veerman 	struct _scanopt_t *s;
267357f1050SThomas Veerman 	int     i, columns, indent = 2;
268357f1050SThomas Veerman 	usg_elem *byr_val = NULL;	/* option indices sorted by r_val */
269357f1050SThomas Veerman 	usg_elem *store;	/* array of preallocated elements. */
270357f1050SThomas Veerman 	int     store_idx = 0;
271357f1050SThomas Veerman 	usg_elem *ue;
272357f1050SThomas Veerman 	int     maxlen[2];
273357f1050SThomas Veerman 	int     desccol = 0;
274357f1050SThomas Veerman 	int     print_run = 0;
275357f1050SThomas Veerman 
276357f1050SThomas Veerman 	maxlen[0] = 0;
277357f1050SThomas Veerman 	maxlen[1] = 0;
278357f1050SThomas Veerman 
279357f1050SThomas Veerman 	s = (struct _scanopt_t *) scanner;
280357f1050SThomas Veerman 
281357f1050SThomas Veerman 	if (usage) {
282357f1050SThomas Veerman 		fprintf (fp, "%s\n", usage);
283357f1050SThomas Veerman 	}
284357f1050SThomas Veerman 	else {
285357f1050SThomas Veerman 		/* Find the basename of argv[0] */
286357f1050SThomas Veerman 		const char *p;
287357f1050SThomas Veerman 
288357f1050SThomas Veerman 		p = s->argv[0] + strlen (s->argv[0]);
289357f1050SThomas Veerman 		while (p != s->argv[0] && *p != '/')
290357f1050SThomas Veerman 			--p;
291357f1050SThomas Veerman 		if (*p == '/')
292357f1050SThomas Veerman 			p++;
293357f1050SThomas Veerman 
294357f1050SThomas Veerman 		fprintf (fp, _("Usage: %s [OPTIONS]...\n"), p);
295357f1050SThomas Veerman 	}
296357f1050SThomas Veerman 	fprintf (fp, "\n");
297357f1050SThomas Veerman 
298357f1050SThomas Veerman 	/* Sort by r_val and string. Yes, this is O(n*n), but n is small. */
299357f1050SThomas Veerman 	store = (usg_elem *) malloc (s->optc * sizeof (usg_elem));
300357f1050SThomas Veerman 	for (i = 0; i < s->optc; i++) {
301357f1050SThomas Veerman 
302357f1050SThomas Veerman 		/* grab the next preallocate node. */
303357f1050SThomas Veerman 		ue = store + store_idx++;
304357f1050SThomas Veerman 		ue->idx = i;
305357f1050SThomas Veerman 		ue->next = ue->alias = NULL;
306357f1050SThomas Veerman 
307357f1050SThomas Veerman 		/* insert into list. */
308357f1050SThomas Veerman 		if (!byr_val)
309357f1050SThomas Veerman 			byr_val = ue;
310357f1050SThomas Veerman 		else {
311357f1050SThomas Veerman 			int     found_alias = 0;
312357f1050SThomas Veerman 			usg_elem **ue_curr, **ptr_if_no_alias = NULL;
313357f1050SThomas Veerman 
314357f1050SThomas Veerman 			ue_curr = &byr_val;
315357f1050SThomas Veerman 			while (*ue_curr) {
316357f1050SThomas Veerman 				if (RVAL (s, (*ue_curr)->idx) ==
317357f1050SThomas Veerman 				    RVAL (s, ue->idx)) {
318357f1050SThomas Veerman 					/* push onto the alias list. */
319357f1050SThomas Veerman 					ue_curr = &((*ue_curr)->alias);
320357f1050SThomas Veerman 					found_alias = 1;
321357f1050SThomas Veerman 					break;
322357f1050SThomas Veerman 				}
323357f1050SThomas Veerman 				if (!ptr_if_no_alias
324357f1050SThomas Veerman 				    &&
325357f1050SThomas Veerman 				    STRCASECMP (NAME (s, (*ue_curr)->idx),
326357f1050SThomas Veerman 						NAME (s, ue->idx)) > 0) {
327357f1050SThomas Veerman 					ptr_if_no_alias = ue_curr;
328357f1050SThomas Veerman 				}
329357f1050SThomas Veerman 				ue_curr = &((*ue_curr)->next);
330357f1050SThomas Veerman 			}
331357f1050SThomas Veerman 			if (!found_alias && ptr_if_no_alias)
332357f1050SThomas Veerman 				ue_curr = ptr_if_no_alias;
333357f1050SThomas Veerman 			ue->next = *ue_curr;
334357f1050SThomas Veerman 			*ue_curr = ue;
335357f1050SThomas Veerman 		}
336357f1050SThomas Veerman 	}
337357f1050SThomas Veerman 
338357f1050SThomas Veerman #if 0
339357f1050SThomas Veerman 	if (1) {
340357f1050SThomas Veerman 		printf ("ORIGINAL:\n");
341357f1050SThomas Veerman 		for (i = 0; i < s->optc; i++)
342357f1050SThomas Veerman 			printf ("%2d: %s\n", i, NAME (s, i));
343357f1050SThomas Veerman 		printf ("SORTED:\n");
344357f1050SThomas Veerman 		ue = byr_val;
345357f1050SThomas Veerman 		while (ue) {
346357f1050SThomas Veerman 			usg_elem *ue2;
347357f1050SThomas Veerman 
348357f1050SThomas Veerman 			printf ("%2d: %s\n", ue->idx, NAME (s, ue->idx));
349357f1050SThomas Veerman 			for (ue2 = ue->alias; ue2; ue2 = ue2->next)
350357f1050SThomas Veerman 				printf ("  +---> %2d: %s\n", ue2->idx,
351357f1050SThomas Veerman 					NAME (s, ue2->idx));
352357f1050SThomas Veerman 			ue = ue->next;
353357f1050SThomas Veerman 		}
354357f1050SThomas Veerman 	}
355357f1050SThomas Veerman #endif
356357f1050SThomas Veerman 
357357f1050SThomas Veerman 	/* Now build each row of output. */
358357f1050SThomas Veerman 
359357f1050SThomas Veerman 	/* first pass calculate how much room we need. */
360357f1050SThomas Veerman 	for (ue = byr_val; ue; ue = ue->next) {
361357f1050SThomas Veerman 		usg_elem *ap;
362357f1050SThomas Veerman 		int     len = 0;
363357f1050SThomas Veerman 		int     nshort = 0, nlong = 0;
364357f1050SThomas Veerman 
365357f1050SThomas Veerman 
366357f1050SThomas Veerman #define CALC_LEN(i) do {\
367357f1050SThomas Veerman           if(FLAGS(s,i) & IS_LONG) \
368357f1050SThomas Veerman               len +=  (nlong++||nshort) ? 2+PRINTLEN(s,i) : PRINTLEN(s,i);\
369357f1050SThomas Veerman           else\
370357f1050SThomas Veerman               len +=  (nshort++||nlong)? 2+PRINTLEN(s,i) : PRINTLEN(s,i);\
371357f1050SThomas Veerman         }while(0)
372357f1050SThomas Veerman 
373357f1050SThomas Veerman 		if (!(FLAGS (s, ue->idx) & IS_LONG))
374357f1050SThomas Veerman 			CALC_LEN (ue->idx);
375357f1050SThomas Veerman 
376357f1050SThomas Veerman 		/* do short aliases first. */
377357f1050SThomas Veerman 		for (ap = ue->alias; ap; ap = ap->next) {
378357f1050SThomas Veerman 			if (FLAGS (s, ap->idx) & IS_LONG)
379357f1050SThomas Veerman 				continue;
380357f1050SThomas Veerman 			CALC_LEN (ap->idx);
381357f1050SThomas Veerman 		}
382357f1050SThomas Veerman 
383357f1050SThomas Veerman 		if (FLAGS (s, ue->idx) & IS_LONG)
384357f1050SThomas Veerman 			CALC_LEN (ue->idx);
385357f1050SThomas Veerman 
386357f1050SThomas Veerman 		/* repeat the above loop, this time for long aliases. */
387357f1050SThomas Veerman 		for (ap = ue->alias; ap; ap = ap->next) {
388357f1050SThomas Veerman 			if (!(FLAGS (s, ap->idx) & IS_LONG))
389357f1050SThomas Veerman 				continue;
390357f1050SThomas Veerman 			CALC_LEN (ap->idx);
391357f1050SThomas Veerman 		}
392357f1050SThomas Veerman 
393357f1050SThomas Veerman 		if (len > maxlen[0])
394357f1050SThomas Veerman 			maxlen[0] = len;
395357f1050SThomas Veerman 
396357f1050SThomas Veerman 		/* It's much easier to calculate length for description column! */
397357f1050SThomas Veerman 		len = strlen (DESC (s, ue->idx));
398357f1050SThomas Veerman 		if (len > maxlen[1])
399357f1050SThomas Veerman 			maxlen[1] = len;
400357f1050SThomas Veerman 	}
401357f1050SThomas Veerman 
402357f1050SThomas Veerman 	/* Determine how much room we have, and how much we will allocate to each col.
403357f1050SThomas Veerman 	 * Do not address pathological cases. Output will just be ugly. */
404357f1050SThomas Veerman 	columns = get_cols () - 1;
405357f1050SThomas Veerman 	if (maxlen[0] + maxlen[1] + indent * 2 > columns) {
406357f1050SThomas Veerman 		/* col 0 gets whatever it wants. we'll wrap the desc col. */
407357f1050SThomas Veerman 		maxlen[1] = columns - (maxlen[0] + indent * 2);
408357f1050SThomas Veerman 		if (maxlen[1] < 14)	/* 14 is arbitrary lower limit on desc width. */
409357f1050SThomas Veerman 			maxlen[1] = INT_MAX;
410357f1050SThomas Veerman 	}
411357f1050SThomas Veerman 	desccol = maxlen[0] + indent * 2;
412357f1050SThomas Veerman 
413357f1050SThomas Veerman #define PRINT_SPACES(fp,n)\
414357f1050SThomas Veerman     do{\
415357f1050SThomas Veerman         int _n;\
416357f1050SThomas Veerman         _n=(n);\
417357f1050SThomas Veerman         while(_n-- > 0)\
418357f1050SThomas Veerman             fputc(' ',(fp));\
419357f1050SThomas Veerman     }while(0)
420357f1050SThomas Veerman 
421357f1050SThomas Veerman 
422357f1050SThomas Veerman 	/* Second pass (same as above loop), this time we print. */
423357f1050SThomas Veerman 	/* Sloppy hack: We iterate twice. The first time we print short and long options.
424357f1050SThomas Veerman 	   The second time we print those lines that have ONLY long options. */
425357f1050SThomas Veerman 	while (print_run++ < 2) {
426357f1050SThomas Veerman 		for (ue = byr_val; ue; ue = ue->next) {
427357f1050SThomas Veerman 			usg_elem *ap;
428357f1050SThomas Veerman 			int     nwords = 0, nchars = 0, has_short = 0;
429357f1050SThomas Veerman 
430357f1050SThomas Veerman /* TODO: get has_short schtick to work */
431357f1050SThomas Veerman 			has_short = !(FLAGS (s, ue->idx) & IS_LONG);
432357f1050SThomas Veerman 			for (ap = ue->alias; ap; ap = ap->next) {
433357f1050SThomas Veerman 				if (!(FLAGS (s, ap->idx) & IS_LONG)) {
434357f1050SThomas Veerman 					has_short = 1;
435357f1050SThomas Veerman 					break;
436357f1050SThomas Veerman 				}
437357f1050SThomas Veerman 			}
438357f1050SThomas Veerman 			if ((print_run == 1 && !has_short) ||
439357f1050SThomas Veerman 			    (print_run == 2 && has_short))
440357f1050SThomas Veerman 				continue;
441357f1050SThomas Veerman 
442357f1050SThomas Veerman 			PRINT_SPACES (fp, indent);
443357f1050SThomas Veerman 			nchars += indent;
444357f1050SThomas Veerman 
445357f1050SThomas Veerman /* Print, adding a ", " between aliases. */
446357f1050SThomas Veerman #define PRINT_IT(i) do{\
447357f1050SThomas Veerman                   if(nwords++)\
448357f1050SThomas Veerman                       nchars+=fprintf(fp,", ");\
449357f1050SThomas Veerman                   nchars+=fprintf(fp,"%s",s->options[i].opt_fmt);\
450357f1050SThomas Veerman             }while(0)
451357f1050SThomas Veerman 
452357f1050SThomas Veerman 			if (!(FLAGS (s, ue->idx) & IS_LONG))
453357f1050SThomas Veerman 				PRINT_IT (ue->idx);
454357f1050SThomas Veerman 
455357f1050SThomas Veerman 			/* print short aliases first. */
456357f1050SThomas Veerman 			for (ap = ue->alias; ap; ap = ap->next) {
457357f1050SThomas Veerman 				if (!(FLAGS (s, ap->idx) & IS_LONG))
458357f1050SThomas Veerman 					PRINT_IT (ap->idx);
459357f1050SThomas Veerman 			}
460357f1050SThomas Veerman 
461357f1050SThomas Veerman 
462357f1050SThomas Veerman 			if (FLAGS (s, ue->idx) & IS_LONG)
463357f1050SThomas Veerman 				PRINT_IT (ue->idx);
464357f1050SThomas Veerman 
465357f1050SThomas Veerman 			/* repeat the above loop, this time for long aliases. */
466357f1050SThomas Veerman 			for (ap = ue->alias; ap; ap = ap->next) {
467357f1050SThomas Veerman 				if (FLAGS (s, ap->idx) & IS_LONG)
468357f1050SThomas Veerman 					PRINT_IT (ap->idx);
469357f1050SThomas Veerman 			}
470357f1050SThomas Veerman 
471357f1050SThomas Veerman 			/* pad to desccol */
472357f1050SThomas Veerman 			PRINT_SPACES (fp, desccol - nchars);
473357f1050SThomas Veerman 
474357f1050SThomas Veerman 			/* Print description, wrapped to maxlen[1] columns. */
475357f1050SThomas Veerman 			if (1) {
476357f1050SThomas Veerman 				const char *pstart;
477357f1050SThomas Veerman 
478357f1050SThomas Veerman 				pstart = DESC (s, ue->idx);
479357f1050SThomas Veerman 				while (1) {
480357f1050SThomas Veerman 					int     n = 0;
481357f1050SThomas Veerman 					const char *lastws = NULL, *p;
482357f1050SThomas Veerman 
483357f1050SThomas Veerman 					p = pstart;
484357f1050SThomas Veerman 
485357f1050SThomas Veerman 					while (*p && n < maxlen[1]
486357f1050SThomas Veerman 					       && *p != '\n') {
48784d9c625SLionel Sambuc 						if (isspace ((Char)(*p))
488357f1050SThomas Veerman 						    || *p == '-') lastws =
489357f1050SThomas Veerman 								p;
490357f1050SThomas Veerman 						n++;
491357f1050SThomas Veerman 						p++;
492357f1050SThomas Veerman 					}
493357f1050SThomas Veerman 
494357f1050SThomas Veerman 					if (!*p) {	/* hit end of desc. done. */
495357f1050SThomas Veerman 						fprintf (fp, "%s\n",
496357f1050SThomas Veerman 							 pstart);
497357f1050SThomas Veerman 						break;
498357f1050SThomas Veerman 					}
499357f1050SThomas Veerman 					else if (*p == '\n') {	/* print everything up to here then wrap. */
500357f1050SThomas Veerman 						fprintf (fp, "%.*s\n", n,
501357f1050SThomas Veerman 							 pstart);
502357f1050SThomas Veerman 						PRINT_SPACES (fp, desccol);
503357f1050SThomas Veerman 						pstart = p + 1;
504357f1050SThomas Veerman 						continue;
505357f1050SThomas Veerman 					}
506357f1050SThomas Veerman 					else {	/* we hit the edge of the screen. wrap at space if possible. */
507357f1050SThomas Veerman 						if (lastws) {
508357f1050SThomas Veerman 							fprintf (fp,
509357f1050SThomas Veerman 								 "%.*s\n",
51084d9c625SLionel Sambuc 								 (int)(lastws - pstart),
511357f1050SThomas Veerman 								 pstart);
512357f1050SThomas Veerman 							pstart =
513357f1050SThomas Veerman 								lastws + 1;
514357f1050SThomas Veerman 						}
515357f1050SThomas Veerman 						else {
516357f1050SThomas Veerman 							fprintf (fp,
517357f1050SThomas Veerman 								 "%.*s\n",
518357f1050SThomas Veerman 								 n,
519357f1050SThomas Veerman 								 pstart);
520357f1050SThomas Veerman 							pstart = p + 1;
521357f1050SThomas Veerman 						}
522357f1050SThomas Veerman 						PRINT_SPACES (fp, desccol);
523357f1050SThomas Veerman 						continue;
524357f1050SThomas Veerman 					}
525357f1050SThomas Veerman 				}
526357f1050SThomas Veerman 			}
527357f1050SThomas Veerman 		}
528357f1050SThomas Veerman 	}			/* end while */
529357f1050SThomas Veerman 	free (store);
530357f1050SThomas Veerman 	return 0;
531357f1050SThomas Veerman }
532357f1050SThomas Veerman #endif /* no scanopt_usage */
533357f1050SThomas Veerman 
534357f1050SThomas Veerman 
scanopt_err(s,opt_offset,is_short,err)535357f1050SThomas Veerman static int scanopt_err (s, opt_offset, is_short, err)
536357f1050SThomas Veerman      struct _scanopt_t *s;
537357f1050SThomas Veerman      int     opt_offset;
538357f1050SThomas Veerman      int     is_short;
539357f1050SThomas Veerman      int     err;
540357f1050SThomas Veerman {
541357f1050SThomas Veerman 	const char *optname = "";
542357f1050SThomas Veerman 	char    optchar[2];
543357f1050SThomas Veerman 
544357f1050SThomas Veerman 	if (!s->no_err_msg) {
545357f1050SThomas Veerman 
546357f1050SThomas Veerman 		if (s->index > 0 && s->index < s->argc) {
547357f1050SThomas Veerman 			if (is_short) {
548357f1050SThomas Veerman 				optchar[0] =
549357f1050SThomas Veerman 					s->argv[s->index][s->subscript];
550357f1050SThomas Veerman 				optchar[1] = '\0';
551357f1050SThomas Veerman 				optname = optchar;
552357f1050SThomas Veerman 			}
553357f1050SThomas Veerman 			else {
554357f1050SThomas Veerman 				optname = s->argv[s->index];
555357f1050SThomas Veerman 			}
556357f1050SThomas Veerman 		}
557357f1050SThomas Veerman 
558357f1050SThomas Veerman 		fprintf (stderr, "%s: ", s->argv[0]);
559357f1050SThomas Veerman 		switch (err) {
560357f1050SThomas Veerman 		case SCANOPT_ERR_ARG_NOT_ALLOWED:
561357f1050SThomas Veerman 			fprintf (stderr,
562357f1050SThomas Veerman 				 _
563357f1050SThomas Veerman 				 ("option `%s' doesn't allow an argument\n"),
564357f1050SThomas Veerman 				 optname);
565357f1050SThomas Veerman 			break;
566357f1050SThomas Veerman 		case SCANOPT_ERR_ARG_NOT_FOUND:
567357f1050SThomas Veerman 			fprintf (stderr,
568357f1050SThomas Veerman 				 _("option `%s' requires an argument\n"),
569357f1050SThomas Veerman 				 optname);
570357f1050SThomas Veerman 			break;
571357f1050SThomas Veerman 		case SCANOPT_ERR_OPT_AMBIGUOUS:
572357f1050SThomas Veerman 			fprintf (stderr, _("option `%s' is ambiguous\n"),
573357f1050SThomas Veerman 				 optname);
574357f1050SThomas Veerman 			break;
575357f1050SThomas Veerman 		case SCANOPT_ERR_OPT_UNRECOGNIZED:
576357f1050SThomas Veerman 			fprintf (stderr, _("Unrecognized option `%s'\n"),
577357f1050SThomas Veerman 				 optname);
578357f1050SThomas Veerman 			break;
579357f1050SThomas Veerman 		default:
580357f1050SThomas Veerman 			fprintf (stderr, _("Unknown error=(%d)\n"), err);
581357f1050SThomas Veerman 			break;
582357f1050SThomas Veerman 		}
583357f1050SThomas Veerman 	}
584357f1050SThomas Veerman 	return err;
585357f1050SThomas Veerman }
586357f1050SThomas Veerman 
587357f1050SThomas Veerman 
588357f1050SThomas Veerman /* Internal. Match str against the regex  ^--([^=]+)(=(.*))?
589357f1050SThomas Veerman  * return 1 if *looks* like a long option.
590357f1050SThomas Veerman  * 'str' is the only input argument, the rest of the arguments are output only.
591357f1050SThomas Veerman  * optname will point to str + 2
592357f1050SThomas Veerman  *
593357f1050SThomas Veerman  */
matchlongopt(str,optname,optlen,arg,arglen)594357f1050SThomas Veerman static int matchlongopt (str, optname, optlen, arg, arglen)
595357f1050SThomas Veerman      char   *str;
596357f1050SThomas Veerman      char  **optname;
597357f1050SThomas Veerman      int    *optlen;
598357f1050SThomas Veerman      char  **arg;
599357f1050SThomas Veerman      int    *arglen;
600357f1050SThomas Veerman {
601357f1050SThomas Veerman 	char   *p;
602357f1050SThomas Veerman 
603357f1050SThomas Veerman 	*optname = *arg = (char *) 0;
604357f1050SThomas Veerman 	*optlen = *arglen = 0;
605357f1050SThomas Veerman 
606357f1050SThomas Veerman 	/* Match regex /--./   */
607357f1050SThomas Veerman 	p = str;
608357f1050SThomas Veerman 	if (p[0] != '-' || p[1] != '-' || !p[2])
609357f1050SThomas Veerman 		return 0;
610357f1050SThomas Veerman 
611357f1050SThomas Veerman 	p += 2;
612357f1050SThomas Veerman 	*optname = (char *) p;
613357f1050SThomas Veerman 
614357f1050SThomas Veerman 	/* find the end of optname */
615357f1050SThomas Veerman 	while (*p && *p != '=')
616357f1050SThomas Veerman 		++p;
617357f1050SThomas Veerman 
618357f1050SThomas Veerman 	*optlen = p - *optname;
619357f1050SThomas Veerman 
620357f1050SThomas Veerman 	if (!*p)
621357f1050SThomas Veerman 		/* an option with no '=...' part. */
622357f1050SThomas Veerman 		return 1;
623357f1050SThomas Veerman 
624357f1050SThomas Veerman 
625357f1050SThomas Veerman 	/* We saw an '=' char. The rest of p is the arg. */
626357f1050SThomas Veerman 	p++;
627357f1050SThomas Veerman 	*arg = p;
628357f1050SThomas Veerman 	while (*p)
629357f1050SThomas Veerman 		++p;
630357f1050SThomas Veerman 	*arglen = p - *arg;
631357f1050SThomas Veerman 
632357f1050SThomas Veerman 	return 1;
633357f1050SThomas Veerman }
634357f1050SThomas Veerman 
635357f1050SThomas Veerman 
636357f1050SThomas Veerman /* Internal. Look up long or short option by name.
637357f1050SThomas Veerman  * Long options must match a non-ambiguous prefix, or exact match.
638357f1050SThomas Veerman  * Short options must be exact.
639357f1050SThomas Veerman  * Return boolean true if found and no error.
640357f1050SThomas Veerman  * Error stored in err_code or zero if no error. */
find_opt(s,lookup_long,optstart,len,err_code,opt_offset)641357f1050SThomas Veerman static int find_opt (s, lookup_long, optstart, len, err_code, opt_offset)
642357f1050SThomas Veerman      struct _scanopt_t *s;
643357f1050SThomas Veerman      int     lookup_long;
644357f1050SThomas Veerman      char   *optstart;
645357f1050SThomas Veerman      int     len;
646357f1050SThomas Veerman      int    *err_code;
647357f1050SThomas Veerman      int    *opt_offset;
648357f1050SThomas Veerman {
649357f1050SThomas Veerman 	int     nmatch = 0, lastr_val = 0, i;
650357f1050SThomas Veerman 
651357f1050SThomas Veerman 	*err_code = 0;
652357f1050SThomas Veerman 	*opt_offset = -1;
653357f1050SThomas Veerman 
654357f1050SThomas Veerman 	if (!optstart)
655357f1050SThomas Veerman 		return 0;
656357f1050SThomas Veerman 
657357f1050SThomas Veerman 	for (i = 0; i < s->optc; i++) {
658357f1050SThomas Veerman 		char   *optname;
659357f1050SThomas Veerman 
660357f1050SThomas Veerman 		optname =
661357f1050SThomas Veerman 			(char *) (s->options[i].opt_fmt +
662357f1050SThomas Veerman 				  (lookup_long ? 2 : 1));
663357f1050SThomas Veerman 
664357f1050SThomas Veerman 		if (lookup_long && (s->aux[i].flags & IS_LONG)) {
665357f1050SThomas Veerman 			if (len > s->aux[i].namelen)
666357f1050SThomas Veerman 				continue;
667357f1050SThomas Veerman 
668357f1050SThomas Veerman 			if (strncmp (optname, optstart, len) == 0) {
669357f1050SThomas Veerman 				nmatch++;
670357f1050SThomas Veerman 				*opt_offset = i;
671357f1050SThomas Veerman 
672357f1050SThomas Veerman 				/* exact match overrides all. */
673357f1050SThomas Veerman 				if (len == s->aux[i].namelen) {
674357f1050SThomas Veerman 					nmatch = 1;
675357f1050SThomas Veerman 					break;
676357f1050SThomas Veerman 				}
677357f1050SThomas Veerman 
678357f1050SThomas Veerman 				/* ambiguity is ok between aliases. */
679357f1050SThomas Veerman 				if (lastr_val
680357f1050SThomas Veerman 				    && lastr_val ==
681357f1050SThomas Veerman 				    s->options[i].r_val) nmatch--;
682357f1050SThomas Veerman 				lastr_val = s->options[i].r_val;
683357f1050SThomas Veerman 			}
684357f1050SThomas Veerman 		}
685357f1050SThomas Veerman 		else if (!lookup_long && !(s->aux[i].flags & IS_LONG)) {
686357f1050SThomas Veerman 			if (optname[0] == optstart[0]) {
687357f1050SThomas Veerman 				nmatch++;
688357f1050SThomas Veerman 				*opt_offset = i;
689357f1050SThomas Veerman 			}
690357f1050SThomas Veerman 		}
691357f1050SThomas Veerman 	}
692357f1050SThomas Veerman 
693357f1050SThomas Veerman 	if (nmatch == 0) {
694357f1050SThomas Veerman 		*err_code = SCANOPT_ERR_OPT_UNRECOGNIZED;
695357f1050SThomas Veerman 		*opt_offset = -1;
696357f1050SThomas Veerman 	}
697357f1050SThomas Veerman 	else if (nmatch > 1) {
698357f1050SThomas Veerman 		*err_code = SCANOPT_ERR_OPT_AMBIGUOUS;
699357f1050SThomas Veerman 		*opt_offset = -1;
700357f1050SThomas Veerman 	}
701357f1050SThomas Veerman 
702357f1050SThomas Veerman 	return *err_code ? 0 : 1;
703357f1050SThomas Veerman }
704357f1050SThomas Veerman 
705357f1050SThomas Veerman 
scanopt(svoid,arg,optindex)706357f1050SThomas Veerman int     scanopt (svoid, arg, optindex)
707357f1050SThomas Veerman      scanopt_t *svoid;
708357f1050SThomas Veerman      char  **arg;
709357f1050SThomas Veerman      int    *optindex;
710357f1050SThomas Veerman {
711357f1050SThomas Veerman 	char   *optname = NULL, *optarg = NULL, *pstart;
712357f1050SThomas Veerman 	int     namelen = 0, arglen = 0;
713357f1050SThomas Veerman 	int     errcode = 0, has_next;
714357f1050SThomas Veerman 	const optspec_t *optp;
715357f1050SThomas Veerman 	struct _scanopt_t *s;
716357f1050SThomas Veerman 	struct _aux *auxp;
717357f1050SThomas Veerman 	int     is_short;
718357f1050SThomas Veerman 	int     opt_offset = -1;
71920a91f77SLionel Sambuc #if defined(__minix)
72020a91f77SLionel Sambuc 	/* triggers a 'may be used uninitialized', when compiled with gcc,
72120a91f77SLionel Sambuc 	 * asserts off, and -Os. */
72220a91f77SLionel Sambuc 	is_short = 0;
72320a91f77SLionel Sambuc #endif /* defined(__minix) */
724357f1050SThomas Veerman 
725357f1050SThomas Veerman 	s = (struct _scanopt_t *) svoid;
726357f1050SThomas Veerman 
727357f1050SThomas Veerman 	/* Normalize return-parameters. */
728357f1050SThomas Veerman 	SAFE_ASSIGN (arg, NULL);
729357f1050SThomas Veerman 	SAFE_ASSIGN (optindex, s->index);
730357f1050SThomas Veerman 
731357f1050SThomas Veerman 	if (s->index >= s->argc)
732357f1050SThomas Veerman 		return 0;
733357f1050SThomas Veerman 
734357f1050SThomas Veerman 	/* pstart always points to the start of our current scan. */
735357f1050SThomas Veerman 	pstart = s->argv[s->index] + s->subscript;
736357f1050SThomas Veerman 	if (!pstart)
737357f1050SThomas Veerman 		return 0;
738357f1050SThomas Veerman 
739357f1050SThomas Veerman 	if (s->subscript == 0) {
740357f1050SThomas Veerman 
741357f1050SThomas Veerman 		/* test for exact match of "--" */
742357f1050SThomas Veerman 		if (pstart[0] == '-' && pstart[1] == '-' && !pstart[2]) {
743357f1050SThomas Veerman 			SAFE_ASSIGN (optindex, s->index + 1);
744357f1050SThomas Veerman 			INC_INDEX (s, 1);
745357f1050SThomas Veerman 			return 0;
746357f1050SThomas Veerman 		}
747357f1050SThomas Veerman 
748357f1050SThomas Veerman 		/* Match an opt. */
749357f1050SThomas Veerman 		if (matchlongopt
750357f1050SThomas Veerman 		    (pstart, &optname, &namelen, &optarg, &arglen)) {
751357f1050SThomas Veerman 
752357f1050SThomas Veerman 			/* it LOOKS like an opt, but is it one?! */
753357f1050SThomas Veerman 			if (!find_opt
754357f1050SThomas Veerman 			    (s, 1, optname, namelen, &errcode,
755357f1050SThomas Veerman 			     &opt_offset)) {
756357f1050SThomas Veerman 				scanopt_err (s, opt_offset, 0, errcode);
757357f1050SThomas Veerman 				return errcode;
758357f1050SThomas Veerman 			}
759357f1050SThomas Veerman 			/* We handle this below. */
760357f1050SThomas Veerman 			is_short = 0;
761357f1050SThomas Veerman 
762357f1050SThomas Veerman 			/* Check for short opt.  */
763357f1050SThomas Veerman 		}
764357f1050SThomas Veerman 		else if (pstart[0] == '-' && pstart[1]) {
765357f1050SThomas Veerman 			/* Pass through to below. */
766357f1050SThomas Veerman 			is_short = 1;
767357f1050SThomas Veerman 			s->subscript++;
768357f1050SThomas Veerman 			pstart++;
769357f1050SThomas Veerman 		}
770357f1050SThomas Veerman 
771357f1050SThomas Veerman 		else {
772357f1050SThomas Veerman 			/* It's not an option. We're done. */
773357f1050SThomas Veerman 			return 0;
774357f1050SThomas Veerman 		}
775357f1050SThomas Veerman 	}
776357f1050SThomas Veerman 
777357f1050SThomas Veerman 	/* We have to re-check the subscript status because it
778357f1050SThomas Veerman 	 * may have changed above. */
779357f1050SThomas Veerman 
780357f1050SThomas Veerman 	if (s->subscript != 0) {
781357f1050SThomas Veerman 
782357f1050SThomas Veerman 		/* we are somewhere in a run of short opts,
783357f1050SThomas Veerman 		 * e.g., at the 'z' in `tar -xzf` */
784357f1050SThomas Veerman 
785357f1050SThomas Veerman 		optname = pstart;
786357f1050SThomas Veerman 		namelen = 1;
787357f1050SThomas Veerman 		is_short = 1;
788357f1050SThomas Veerman 
789357f1050SThomas Veerman 		if (!find_opt
790357f1050SThomas Veerman 		    (s, 0, pstart, namelen, &errcode, &opt_offset)) {
791357f1050SThomas Veerman 			return scanopt_err (s, opt_offset, 1, errcode);
792357f1050SThomas Veerman 		}
793357f1050SThomas Veerman 
794357f1050SThomas Veerman 		optarg = pstart + 1;
795357f1050SThomas Veerman 		if (!*optarg) {
796357f1050SThomas Veerman 			optarg = NULL;
797357f1050SThomas Veerman 			arglen = 0;
798357f1050SThomas Veerman 		}
799357f1050SThomas Veerman 		else
800357f1050SThomas Veerman 			arglen = strlen (optarg);
801357f1050SThomas Veerman 	}
802357f1050SThomas Veerman 
803357f1050SThomas Veerman 	/* At this point, we have a long or short option matched at opt_offset into
804357f1050SThomas Veerman 	 * the s->options array (and corresponding aux array).
805357f1050SThomas Veerman 	 * A trailing argument is in {optarg,arglen}, if any.
806357f1050SThomas Veerman 	 */
807357f1050SThomas Veerman 
808357f1050SThomas Veerman 	/* Look ahead in argv[] to see if there is something
809357f1050SThomas Veerman 	 * that we can use as an argument (if needed). */
810357f1050SThomas Veerman 	has_next = s->index + 1 < s->argc
811357f1050SThomas Veerman 		&& strcmp ("--", s->argv[s->index + 1]) != 0;
812357f1050SThomas Veerman 
813357f1050SThomas Veerman 	optp = s->options + opt_offset;
814357f1050SThomas Veerman 	auxp = s->aux + opt_offset;
815357f1050SThomas Veerman 
816357f1050SThomas Veerman 	/* case: no args allowed */
817357f1050SThomas Veerman 	if (auxp->flags & ARG_NONE) {
818357f1050SThomas Veerman 		if (optarg && !is_short) {
819357f1050SThomas Veerman 			scanopt_err (s, opt_offset, is_short, errcode =
820357f1050SThomas Veerman 				     SCANOPT_ERR_ARG_NOT_ALLOWED);
821357f1050SThomas Veerman 			INC_INDEX (s, 1);
822357f1050SThomas Veerman 			return errcode;
823357f1050SThomas Veerman 		}
824357f1050SThomas Veerman 		else if (!optarg)
825357f1050SThomas Veerman 			INC_INDEX (s, 1);
826357f1050SThomas Veerman 		else
827357f1050SThomas Veerman 			s->subscript++;
828357f1050SThomas Veerman 		return optp->r_val;
829357f1050SThomas Veerman 	}
830357f1050SThomas Veerman 
831357f1050SThomas Veerman 	/* case: required */
832357f1050SThomas Veerman 	if (auxp->flags & ARG_REQ) {
833357f1050SThomas Veerman 		if (!optarg && !has_next)
834357f1050SThomas Veerman 			return scanopt_err (s, opt_offset, is_short,
835357f1050SThomas Veerman 					    SCANOPT_ERR_ARG_NOT_FOUND);
836357f1050SThomas Veerman 
837357f1050SThomas Veerman 		if (!optarg) {
838357f1050SThomas Veerman 			/* Let the next argv element become the argument. */
839357f1050SThomas Veerman 			SAFE_ASSIGN (arg, s->argv[s->index + 1]);
840357f1050SThomas Veerman 			INC_INDEX (s, 2);
841357f1050SThomas Veerman 		}
842357f1050SThomas Veerman 		else {
843357f1050SThomas Veerman 			SAFE_ASSIGN (arg, (char *) optarg);
844357f1050SThomas Veerman 			INC_INDEX (s, 1);
845357f1050SThomas Veerman 		}
846357f1050SThomas Veerman 		return optp->r_val;
847357f1050SThomas Veerman 	}
848357f1050SThomas Veerman 
849357f1050SThomas Veerman 	/* case: optional */
850357f1050SThomas Veerman 	if (auxp->flags & ARG_OPT) {
851357f1050SThomas Veerman 		SAFE_ASSIGN (arg, optarg);
852357f1050SThomas Veerman 		INC_INDEX (s, 1);
853357f1050SThomas Veerman 		return optp->r_val;
854357f1050SThomas Veerman 	}
855357f1050SThomas Veerman 
856357f1050SThomas Veerman 
857357f1050SThomas Veerman 	/* Should not reach here. */
858357f1050SThomas Veerman 	return 0;
859357f1050SThomas Veerman }
860357f1050SThomas Veerman 
861357f1050SThomas Veerman 
scanopt_destroy(svoid)862357f1050SThomas Veerman int     scanopt_destroy (svoid)
863357f1050SThomas Veerman      scanopt_t *svoid;
864357f1050SThomas Veerman {
865357f1050SThomas Veerman 	struct _scanopt_t *s;
866357f1050SThomas Veerman 
867357f1050SThomas Veerman 	s = (struct _scanopt_t *) svoid;
868357f1050SThomas Veerman 	if (s) {
869357f1050SThomas Veerman 		if (s->aux)
870357f1050SThomas Veerman 			free (s->aux);
871357f1050SThomas Veerman 		free (s);
872357f1050SThomas Veerman 	}
873357f1050SThomas Veerman 	return 0;
874357f1050SThomas Veerman }
875357f1050SThomas Veerman 
876357f1050SThomas Veerman 
877357f1050SThomas Veerman /* vim:set tabstop=8 softtabstop=4 shiftwidth=4: */
878