1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
18*4887Schin *                  David Korn <dgk@research.att.com>                   *
19*4887Schin *                   Phong Vo <kpv@research.att.com>                    *
20*4887Schin *                                                                      *
21*4887Schin ***********************************************************************/
22*4887Schin #pragma prototyped
23*4887Schin /*
24*4887Schin  * Glenn Fowler
25*4887Schin  * AT&T Research
26*4887Schin  *
27*4887Schin  * command line option parser and usage formatter
28*4887Schin  * its a monster but its all in one place
29*4887Schin  * widen your window while you're at it
30*4887Schin  */
31*4887Schin 
32*4887Schin #include <optlib.h>
33*4887Schin #include <debug.h>
34*4887Schin #include <ccode.h>
35*4887Schin #include <ctype.h>
36*4887Schin #include <errno.h>
37*4887Schin 
38*4887Schin #define KEEP		"*[A-Za-z][A-Za-z]*"
39*4887Schin #define OMIT		"*@(\\[[-+]*\\?*\\]|\\@\\(#\\)|Copyright \\(c\\)|\\$\\I\\d\\: )*"
40*4887Schin 
41*4887Schin #define GO		'{'		/* group nest open		*/
42*4887Schin #define OG		'}'		/* group nest close		*/
43*4887Schin 
44*4887Schin #define OPT_WIDTH	80		/* default help text width	*/
45*4887Schin #define OPT_MARGIN	10		/* default help text margin	*/
46*4887Schin #define OPT_USAGE	7		/* usage continuation indent	*/
47*4887Schin 
48*4887Schin #define OPT_flag	0x001		/* flag ( 0 or 1 )		*/
49*4887Schin #define OPT_hidden	0x002		/* remaining are hidden		*/
50*4887Schin #define OPT_ignorecase	0x004		/* arg match ignores case	*/
51*4887Schin #define OPT_invert	0x008		/* flag inverts long sense	*/
52*4887Schin #define OPT_listof	0x010		/* arg is ' ' or ',' list	*/
53*4887Schin #define OPT_minus	0x021		/* '-' is an option flag	*/
54*4887Schin #define OPT_number	0x040		/* arg is strtonll() number	*/
55*4887Schin #define OPT_oneof	0x080		/* arg may be set once		*/
56*4887Schin #define OPT_optional	0x100		/* arg is optional		*/
57*4887Schin #define OPT_string	0x200		/* arg is string		*/
58*4887Schin 
59*4887Schin #define OPT_preformat	0001		/* output preformat string	*/
60*4887Schin 
61*4887Schin #define OPT_TYPE	(OPT_flag|OPT_number|OPT_string)
62*4887Schin 
63*4887Schin #define STYLE_posix	0		/* posix getopt usage		*/
64*4887Schin #define STYLE_short	1		/* [default] short usage	*/
65*4887Schin #define STYLE_long	2		/* long usage			*/
66*4887Schin #define STYLE_match	3		/* long description of matches	*/
67*4887Schin #define STYLE_options	4		/* short and long descriptions	*/
68*4887Schin #define STYLE_man	5		/* pretty details		*/
69*4887Schin #define STYLE_html	6		/* html details			*/
70*4887Schin #define STYLE_nroff	7		/* nroff details		*/
71*4887Schin #define STYLE_api	8		/* program details		*/
72*4887Schin #define STYLE_keys	9		/* translation key strings	*/
73*4887Schin #define STYLE_usage	10		/* escaped usage string		*/
74*4887Schin 
75*4887Schin #define FONT_BOLD	1
76*4887Schin #define FONT_ITALIC	2
77*4887Schin #define FONT_LITERAL	4
78*4887Schin 
79*4887Schin #define sep(c)		((c)=='-'||(c)=='_')
80*4887Schin 
81*4887Schin typedef struct Attr_s
82*4887Schin {
83*4887Schin 	const char*	name;
84*4887Schin 	int		flag;
85*4887Schin } Attr_t;
86*4887Schin 
87*4887Schin typedef struct Help_s
88*4887Schin {
89*4887Schin 	const char*	match;		/* builtin help match name	*/
90*4887Schin 	const char*	name;		/* builtin help name		*/
91*4887Schin 	int		style;		/* STYLE_*			*/
92*4887Schin 	const char*	text;		/* --? text			*/
93*4887Schin 	unsigned int	size;		/* strlen text			*/
94*4887Schin } Help_t;
95*4887Schin 
96*4887Schin typedef struct Font_s
97*4887Schin {
98*4887Schin 	const char*	html[2];
99*4887Schin 	const char*	nroff[2];
100*4887Schin 	const char*	term[2];
101*4887Schin } Font_t;
102*4887Schin 
103*4887Schin typedef struct List_s
104*4887Schin {
105*4887Schin 	int		type;		/* { - + : }			*/
106*4887Schin 	const char*	name;		/* list name			*/
107*4887Schin 	const char*	text;		/* help text			*/
108*4887Schin } List_t;
109*4887Schin 
110*4887Schin typedef struct Msg_s
111*4887Schin {
112*4887Schin 	const char*	text;		/* default message text		*/
113*4887Schin 	Dtlink_t	link;		/* cdt link			*/
114*4887Schin } Msg_t;
115*4887Schin 
116*4887Schin typedef struct Save_s
117*4887Schin {
118*4887Schin 	Dtlink_t	link;		/* cdt link			*/
119*4887Schin 	char		text[1];	/* saved text text		*/
120*4887Schin } Save_t;
121*4887Schin 
122*4887Schin typedef struct Push_s
123*4887Schin {
124*4887Schin 	struct Push_s*	next;		/* next string			*/
125*4887Schin 	char*		ob;		/* next char in old string	*/
126*4887Schin 	char*		oe;		/* end of old string		*/
127*4887Schin 	char*		nb;		/* next char in new string	*/
128*4887Schin 	char*		ne;		/* end of new string		*/
129*4887Schin 	int		ch;		/* localize() translation	*/
130*4887Schin } Push_t;
131*4887Schin 
132*4887Schin typedef struct Indent_s
133*4887Schin {
134*4887Schin 	int		stop;		/* tab column position		*/
135*4887Schin } Indent_t;
136*4887Schin 
137*4887Schin static Indent_t		indent[] =
138*4887Schin {
139*4887Schin 	0,2,	4,10,	12,18,	20,26,	28,34,	36,42,	44,50,	0,0
140*4887Schin };
141*4887Schin 
142*4887Schin static const char	term_off[] =	{CC_esc,'[','0','m',0};
143*4887Schin static const char	term_B_on[] =	{CC_esc,'[','1','m',0};
144*4887Schin static const char	term_I_on[] =	{CC_esc,'[','1',';','4','m',0};
145*4887Schin 
146*4887Schin static const Font_t	fonts[] =
147*4887Schin {
148*4887Schin 	"",	"",	"",	"",	"",			"",
149*4887Schin 	"</B>",	"<B>", "\\fP",	"\\fB",	&term_off[0],	&term_B_on[0],
150*4887Schin 	"</I>",	"<I>", "\\fP",	"\\fI",	&term_off[0],	&term_I_on[0],
151*4887Schin 	"",	"",	"",	"",	"",			"",
152*4887Schin 	"</TT>","<TT>","\\fP",	"\\f5",	"",			"",
153*4887Schin };
154*4887Schin 
155*4887Schin static char		native[] = "";
156*4887Schin 
157*4887Schin #if !_PACKAGE_astsa
158*4887Schin 
159*4887Schin #define ID		ast.id
160*4887Schin 
161*4887Schin #define C(s)		ERROR_catalog(s)
162*4887Schin #define D(s)		(opt_info.state->msgdict && dtmatch(opt_info.state->msgdict, (s)))
163*4887Schin #define T(i,c,m)	(X(c)?translate(i,c,C(m)):(m))
164*4887Schin #define X(c)		(ERROR_translating()&&(c)!=native)
165*4887Schin #define Z(x)		C(x),sizeof(x)-1
166*4887Schin 
167*4887Schin /*
168*4887Schin  * translate with C_LC_MESSAGES_libast[] check
169*4887Schin  */
170*4887Schin 
171*4887Schin static char*
172*4887Schin translate(const char* cmd, const char* cat, const char* msg)
173*4887Schin {
174*4887Schin 	if (!X(cat))
175*4887Schin 		return (char*)msg;
176*4887Schin 	if (cat != (const char*)ID && D(msg))
177*4887Schin 		cat = (const char*)ID;
178*4887Schin 	return errorx(NiL, cmd, cat, msg);
179*4887Schin }
180*4887Schin 
181*4887Schin #else
182*4887Schin 
183*4887Schin static char		ID[] = "ast";
184*4887Schin 
185*4887Schin #define C(s)		s
186*4887Schin #define D(s)		(opt_info.state->msgdict && dtmatch(opt_info.state->msgdict, (s)))
187*4887Schin #define T(i,c,m)	m
188*4887Schin #define X(c)		0
189*4887Schin #define Z(x)		C(x),sizeof(x)-1
190*4887Schin 
191*4887Schin #endif
192*4887Schin 
193*4887Schin static const List_t	help_head[] =
194*4887Schin {
195*4887Schin 	'-',	0,
196*4887Schin 		0,
197*4887Schin 	'+',	C("NAME"),
198*4887Schin 		C("options available to all \bast\b commands"),
199*4887Schin 	'+',	C("DESCRIPTION"),
200*4887Schin 		C("\b-?\b and \b--?\b* options are the same \
201*4887Schin for all \bast\b commands. For any \aitem\a below, if \b--\b\aitem\a is not \
202*4887Schin supported by a given command then it is equivalent to \b--\?\?\b\aitem\a. The \
203*4887Schin \b--\?\?\b form should be used for portability. All output is written to the \
204*4887Schin standard error."),
205*4887Schin };
206*4887Schin 
207*4887Schin static const Help_t	styles[] =
208*4887Schin {
209*4887Schin 	C("about"),	"-",		STYLE_match,
210*4887Schin 	Z("List all implementation info."),
211*4887Schin 	C("api"),	"?api",		STYLE_api,
212*4887Schin 	Z("List detailed info in program readable form."),
213*4887Schin 	C("help"),	"",		-1,
214*4887Schin 	Z("List detailed help option info."),
215*4887Schin 	C("html"),	"?html",	STYLE_html,
216*4887Schin 	Z("List detailed info in html."),
217*4887Schin 	C("keys"),	"?keys",	STYLE_keys,
218*4887Schin 	Z("List the usage translation key strings with C style escapes."),
219*4887Schin 	C("long"),	"?long",	STYLE_long,
220*4887Schin 	Z("List long option usage."),
221*4887Schin 	C("man"),	"?man",		STYLE_man,
222*4887Schin 	Z("List detailed info in displayed man page form."),
223*4887Schin 	C("nroff"),	"?nroff",	STYLE_nroff,
224*4887Schin 	Z("List detailed info in nroff."),
225*4887Schin 	C("options"),	"?options",	STYLE_options,
226*4887Schin 	Z("List short and long option details."),
227*4887Schin 	C("posix"),	"?posix",	STYLE_posix,
228*4887Schin 	Z("List posix getopt usage."),
229*4887Schin 	C("short"),	"?short",	STYLE_short,
230*4887Schin 	Z("List short option usage."),
231*4887Schin 	C("usage"),	"?usage",	STYLE_usage,
232*4887Schin 	Z("List the usage string with C style escapes."),
233*4887Schin };
234*4887Schin 
235*4887Schin static const List_t	help_tail[] =
236*4887Schin {
237*4887Schin 	':',	C("\?\?-\alabel\a"),
238*4887Schin 		C("List implementation info matching \alabel\a*."),
239*4887Schin 	':',	C("\?\?\aname\a"),
240*4887Schin 		C("Equivalent to \b--help=\b\aname\a."),
241*4887Schin 	':',	C("\?\?"),
242*4887Schin 		C("Equivalent to \b--\?\?options\b."),
243*4887Schin 	':',	C("\?\?\?\?"),
244*4887Schin 		C("Equivalent to \b--\?\?man\b."),
245*4887Schin 	':',	C("\?\?\?\?\?\?"),
246*4887Schin 		C("Equivalent to \b--\?\?help\b."),
247*4887Schin 	':',	C("\?\?\?\?\?\?\aitem\a"),
248*4887Schin 		C("If the next argument is \b--\b\aoption\a then list \
249*4887Schin the \aoption\a output in the \aitem\a style. Otherwise print \
250*4887Schin \bversion=\b\an\a where \an\a>0 if \b--\?\?\b\aitem\a is supported, \b0\b \
251*4887Schin if not."),
252*4887Schin 	':',	C("\?\?\?\?\?\?ESC"),
253*4887Schin 		C("Emit escape codes even if output is not a terminal."),
254*4887Schin 	':',	C("\?\?\?\?\?\?TEST"),
255*4887Schin 		C("Massage the output for regression testing."),
256*4887Schin };
257*4887Schin 
258*4887Schin static const Attr_t	attrs[] =
259*4887Schin {
260*4887Schin 	"flag",		OPT_flag,
261*4887Schin 	"hidden",	OPT_hidden,
262*4887Schin 	"ignorecase",	OPT_ignorecase,
263*4887Schin 	"invert",	OPT_invert,
264*4887Schin 	"listof",	OPT_listof,
265*4887Schin 	"number",	OPT_number,
266*4887Schin 	"oneof",	OPT_oneof,
267*4887Schin 	"optional",	OPT_optional,
268*4887Schin 	"string",	OPT_string,
269*4887Schin };
270*4887Schin 
271*4887Schin static const char	unknown[] = C("unknown option or attribute");
272*4887Schin 
273*4887Schin static const char*	heading[] =
274*4887Schin {
275*4887Schin 	C("INDEX"),
276*4887Schin 	C("USER COMMANDS"),
277*4887Schin 	C("SYSTEM LIBRARY"),
278*4887Schin 	C("USER LIBRARY"),
279*4887Schin 	C("FILE FORMATS"),
280*4887Schin 	C("MISCELLANEOUS"),
281*4887Schin 	C("GAMES and DEMOS"),
282*4887Schin 	C("SPECIAL FILES"),
283*4887Schin 	C("ADMINISTRATIVE COMMANDS"),
284*4887Schin 	C("GUIs"),
285*4887Schin };
286*4887Schin 
287*4887Schin /*
288*4887Schin  * list of common man page strings
289*4887Schin  * NOTE: add but do not delete from this table
290*4887Schin  */
291*4887Schin 
292*4887Schin static Msg_t		C_LC_MESSAGES_libast[] =
293*4887Schin {
294*4887Schin 	{ C("APPLICATION USAGE") },
295*4887Schin 	{ C("ASYNCHRONOUS EVENTS") },
296*4887Schin 	{ C("BUGS") },
297*4887Schin 	{ C("CAVEATS") },
298*4887Schin 	{ C("CONSEQUENCES OF ERRORS") },
299*4887Schin 	{ C("DESCRIPTION") },
300*4887Schin 	{ C("ENVIRONMENT VARIABLES") },
301*4887Schin 	{ C("EXAMPLES") },
302*4887Schin 	{ C("EXIT STATUS") },
303*4887Schin 	{ C("EXTENDED DESCRIPTION") },
304*4887Schin 	{ C("INPUT FILES") },
305*4887Schin 	{ C("LIBRARY") },
306*4887Schin 	{ C("NAME") },
307*4887Schin 	{ C("OPERANDS") },
308*4887Schin 	{ C("OPTIONS") },
309*4887Schin 	{ C("OUTPUT FILES") },
310*4887Schin 	{ C("SEE ALSO") },
311*4887Schin 	{ C("STDERR") },
312*4887Schin 	{ C("STDIN") },
313*4887Schin 	{ C("STDOUT") },
314*4887Schin 	{ C("SYNOPSIS") },
315*4887Schin 	{ C("author") },
316*4887Schin 	{ C("copyright") },
317*4887Schin 	{ C("license") },
318*4887Schin 	{ C("name") },
319*4887Schin 	{ C("path") },
320*4887Schin 	{ C("version") },
321*4887Schin };
322*4887Schin 
323*4887Schin static unsigned char	map[UCHAR_MAX];
324*4887Schin 
325*4887Schin static Optstate_t	state;
326*4887Schin 
327*4887Schin /*
328*4887Schin  * 2007-03-19 move opt_info from _opt_info_ to (*_opt_data_)
329*4887Schin  *	      to allow future Opt_t growth
330*4887Schin  *            by 2009 _opt_info_ can be static
331*4887Schin  */
332*4887Schin 
333*4887Schin #if _BLD_ast && defined(__EXPORT__)
334*4887Schin #define extern		extern __EXPORT__
335*4887Schin #endif
336*4887Schin 
337*4887Schin extern Opt_t	_opt_info_;
338*4887Schin 
339*4887Schin Opt_t		_opt_info_ = { 0,0,0,0,0,0,0,{0},{0},0,0,0,{0},{0},&state };
340*4887Schin 
341*4887Schin #undef	extern
342*4887Schin 
343*4887Schin __EXTERN__(Opt_t, _opt_info_);
344*4887Schin 
345*4887Schin __EXTERN__(Opt_t*, _opt_infop_);
346*4887Schin 
347*4887Schin Opt_t*		_opt_infop_ = &_opt_info_;
348*4887Schin 
349*4887Schin #if _BLD_DEBUG
350*4887Schin 
351*4887Schin /*
352*4887Schin  * debug usage string segment format
353*4887Schin  */
354*4887Schin 
355*4887Schin static char*
356*4887Schin show(register char* s)
357*4887Schin {
358*4887Schin 	register int	c;
359*4887Schin 	register char*	t;
360*4887Schin 	register char*	e;
361*4887Schin 
362*4887Schin 	static char	buf[32];
363*4887Schin 
364*4887Schin 	if (!s)
365*4887Schin 		return "(null)";
366*4887Schin 	t = buf;
367*4887Schin 	e = buf + sizeof(buf) - 2;
368*4887Schin 	while (t < e)
369*4887Schin 	{
370*4887Schin 		switch (c = *s++)
371*4887Schin 		{
372*4887Schin 		case 0:
373*4887Schin 			goto done;
374*4887Schin 		case '\a':
375*4887Schin 			*t++ = '\\';
376*4887Schin 			c = 'a';
377*4887Schin 			break;
378*4887Schin 		case '\b':
379*4887Schin 			*t++ = '\\';
380*4887Schin 			c = 'b';
381*4887Schin 			break;
382*4887Schin 		case '\f':
383*4887Schin 			*t++ = '\\';
384*4887Schin 			c = 'f';
385*4887Schin 			break;
386*4887Schin 		case '\v':
387*4887Schin 			*t++ = '\\';
388*4887Schin 			c = 'v';
389*4887Schin 			break;
390*4887Schin 		}
391*4887Schin 		*t++ = c;
392*4887Schin 	}
393*4887Schin  done:
394*4887Schin 	*t = 0;
395*4887Schin 	return buf;
396*4887Schin }
397*4887Schin 
398*4887Schin #endif
399*4887Schin 
400*4887Schin /*
401*4887Schin  * pop the push stack
402*4887Schin  */
403*4887Schin 
404*4887Schin static Push_t*
405*4887Schin pop(register Push_t* psp)
406*4887Schin {
407*4887Schin 	register Push_t*	tsp;
408*4887Schin 
409*4887Schin 	while (tsp = psp)
410*4887Schin 	{
411*4887Schin 		psp = psp->next;
412*4887Schin 		free(tsp);
413*4887Schin 	}
414*4887Schin 	return 0;
415*4887Schin }
416*4887Schin 
417*4887Schin /*
418*4887Schin  * skip over line space to the next token
419*4887Schin  */
420*4887Schin 
421*4887Schin static char*
422*4887Schin next(register char* s, int version)
423*4887Schin {
424*4887Schin 	register char*	b;
425*4887Schin 
426*4887Schin 	while (*s == '\t' || *s == '\r' || version >= 1 && *s == ' ')
427*4887Schin 		s++;
428*4887Schin 	if (*s == '\n')
429*4887Schin 	{
430*4887Schin 		b = s;
431*4887Schin 		while (*++s == ' ' || *s == '\t' || *s == '\r');
432*4887Schin 		if (*s == '\n')
433*4887Schin 			return b;
434*4887Schin 	}
435*4887Schin 	return s;
436*4887Schin }
437*4887Schin 
438*4887Schin /*
439*4887Schin  * skip to t1 or t2 or t3, whichever first, in s
440*4887Schin  *	n==0	outside [...]
441*4887Schin  *	n==1	inside [...] before ?
442*4887Schin  *	n==2	inside [...] after ?
443*4887Schin  *	b==0	outside {...}
444*4887Schin  *	b==1	inside {...}
445*4887Schin  * past skips past the terminator to the next token
446*4887Schin  * otherwise a pointer to the terminator is returned
447*4887Schin  *
448*4887Schin  * ]] for ] inside [...]
449*4887Schin  * ?? for ? inside [...] before ?
450*4887Schin  * :: for : inside [...] before ?
451*4887Schin  */
452*4887Schin 
453*4887Schin static char*
454*4887Schin skip(register char* s, register int t1, register int t2, register int t3, register int n, register int b, int past, int version)
455*4887Schin {
456*4887Schin 	register int	c;
457*4887Schin 	register int	on = n;
458*4887Schin 	register int	ob = b;
459*4887Schin 
460*4887Schin 	if (version < 1)
461*4887Schin 	{
462*4887Schin 		n = n >= 1;
463*4887Schin 		for (;;)
464*4887Schin 		{
465*4887Schin 			switch (*s++)
466*4887Schin 			{
467*4887Schin 			case 0:
468*4887Schin 				break;
469*4887Schin 			case '[':
470*4887Schin 				n++;
471*4887Schin 				continue;
472*4887Schin 			case ']':
473*4887Schin 				if (--n <= 0)
474*4887Schin 					break;
475*4887Schin 				continue;
476*4887Schin 			default:
477*4887Schin 				continue;
478*4887Schin 			}
479*4887Schin 			break;
480*4887Schin 		}
481*4887Schin 	}
482*4887Schin 	else while (c = *s++)
483*4887Schin 	{
484*4887Schin 		message((-22, "optget: skip t1=%c t2=%c t3=%c n=%d b=%d `%s'", t1 ? t1 : '@', t2 ? t2 : '@', t3 ? t3 : '@', n, b, show(s - 1)));
485*4887Schin 		if (c == '[')
486*4887Schin 		{
487*4887Schin 			if (!n)
488*4887Schin 				n = 1;
489*4887Schin 		}
490*4887Schin 		else if (c == ']')
491*4887Schin 		{
492*4887Schin 			if (n)
493*4887Schin 			{
494*4887Schin 				if (*s == ']')
495*4887Schin 					s++;
496*4887Schin 				else if (on == 1)
497*4887Schin 					break;
498*4887Schin 				else
499*4887Schin 					n = 0;
500*4887Schin 			}
501*4887Schin 		}
502*4887Schin 		else if (c == GO)
503*4887Schin 		{
504*4887Schin 			if (n == 0)
505*4887Schin 				b++;
506*4887Schin 		}
507*4887Schin 		else if (c == OG)
508*4887Schin 		{
509*4887Schin 			if (n == 0 && b-- == ob)
510*4887Schin 				break;
511*4887Schin 		}
512*4887Schin 		else if (c == '?')
513*4887Schin 		{
514*4887Schin 			if (n == 1)
515*4887Schin 			{
516*4887Schin 				if (*s == '?')
517*4887Schin 					s++;
518*4887Schin 				else
519*4887Schin 				{
520*4887Schin 					if (n == on && (c == t1 || c == t2 || c == t3))
521*4887Schin 						break;
522*4887Schin 					n = 2;
523*4887Schin 				}
524*4887Schin 			}
525*4887Schin 		}
526*4887Schin 		else if (n == on && (c == t1 || c == t2 || c == t3))
527*4887Schin 		{
528*4887Schin 			if (n == 1 && c == ':' && *s == c)
529*4887Schin 				s++;
530*4887Schin 			else
531*4887Schin 				break;
532*4887Schin 		}
533*4887Schin 	}
534*4887Schin 	return past && *(s - 1) ? next(s, version) : s - 1;
535*4887Schin }
536*4887Schin 
537*4887Schin /*
538*4887Schin  * match s with t
539*4887Schin  * t translated if possible
540*4887Schin  * imbedded { - _ ' } ignored
541*4887Schin  * * separates required prefix from optional suffix
542*4887Schin  * otherwise prefix match
543*4887Schin  */
544*4887Schin 
545*4887Schin static int
546*4887Schin match(char* s, char* t, int version, const char* catalog)
547*4887Schin {
548*4887Schin 	register char*	w;
549*4887Schin 	register char*	x;
550*4887Schin 	char*		xw;
551*4887Schin 	char*		ww;
552*4887Schin 	int		n;
553*4887Schin 	int		v;
554*4887Schin 	int		j;
555*4887Schin 
556*4887Schin 	for (n = 0; n < 2; n++)
557*4887Schin 	{
558*4887Schin 		if (n)
559*4887Schin 			x = t;
560*4887Schin 		else
561*4887Schin 		{
562*4887Schin 			if (catalog)
563*4887Schin 			{
564*4887Schin 				w = skip(t, ':', '?', 0, 1, 0, 0, version);
565*4887Schin 				w = sfprints("%-.*s", w - t, t);
566*4887Schin 				x = T(error_info.id, catalog, w);
567*4887Schin 				if (x == w)
568*4887Schin 					continue;
569*4887Schin 			}
570*4887Schin 			x = T(NiL, ID, t);
571*4887Schin 			if (x == t)
572*4887Schin 				continue;
573*4887Schin 		}
574*4887Schin 		do
575*4887Schin 		{
576*4887Schin 			v = 0;
577*4887Schin 			xw = x;
578*4887Schin 			w = ww = s;
579*4887Schin 			while (*x && *w)
580*4887Schin 			{
581*4887Schin 				if (isupper(*x))
582*4887Schin 					xw = x;
583*4887Schin 				if (isupper(*w))
584*4887Schin 					ww = w;
585*4887Schin 				if (*x == '*' && !v++ || *x == '\a')
586*4887Schin 				{
587*4887Schin 					if (*x == '\a')
588*4887Schin 						do
589*4887Schin 						{
590*4887Schin 							if (!*++x)
591*4887Schin 							{
592*4887Schin 								x--;
593*4887Schin 								break;
594*4887Schin 							}
595*4887Schin 						} while (*x != '\a');
596*4887Schin 					j = *(x + 1);
597*4887Schin 					if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
598*4887Schin 						while (*w)
599*4887Schin 							w++;
600*4887Schin 				}
601*4887Schin 				else if (sep(*x))
602*4887Schin 					xw = ++x;
603*4887Schin 				else if (sep(*w) && w != s)
604*4887Schin 					ww = ++w;
605*4887Schin 				else if (*x == *w)
606*4887Schin 				{
607*4887Schin 					x++;
608*4887Schin 					w++;
609*4887Schin 				}
610*4887Schin 				else if (w == ww && x == xw)
611*4887Schin 					break;
612*4887Schin 				else
613*4887Schin 				{
614*4887Schin 					if (x != xw)
615*4887Schin 					{
616*4887Schin 						while (*x && !sep(*x) && !isupper(*x))
617*4887Schin 							x++;
618*4887Schin 						if (!*x)
619*4887Schin 							break;
620*4887Schin 						if (sep(*x))
621*4887Schin 							x++;
622*4887Schin 						xw = x;
623*4887Schin 					}
624*4887Schin 					while (w > ww && *w != *x)
625*4887Schin 						w--;
626*4887Schin 				}
627*4887Schin 			}
628*4887Schin 			if (!*w)
629*4887Schin 			{
630*4887Schin 				if (!v)
631*4887Schin 				{
632*4887Schin 					for (;;)
633*4887Schin 					{
634*4887Schin 						switch (*x++)
635*4887Schin 						{
636*4887Schin 						case 0:
637*4887Schin 						case ':':
638*4887Schin 						case '|':
639*4887Schin 						case '?':
640*4887Schin 						case ']':
641*4887Schin 							return 1;
642*4887Schin 						case '*':
643*4887Schin 							break;
644*4887Schin 						default:
645*4887Schin 							continue;
646*4887Schin 						}
647*4887Schin 						break;
648*4887Schin 					}
649*4887Schin 					break;
650*4887Schin 				}
651*4887Schin 				return 1;
652*4887Schin 			}
653*4887Schin 		} while (*(x = skip(x, '|', 0, 0, 1, 0, 0, version)) == '|' && x++);
654*4887Schin 	}
655*4887Schin 	return 0;
656*4887Schin }
657*4887Schin 
658*4887Schin /*
659*4887Schin  * prefix search for s in tab with num elements of size
660*4887Schin  * with optional translation
661*4887Schin  */
662*4887Schin 
663*4887Schin static void*
664*4887Schin search(const void* tab, size_t num, size_t siz, char* s)
665*4887Schin {
666*4887Schin 	register char*	p;
667*4887Schin 	register char*	e;
668*4887Schin 
669*4887Schin 	for (e = (p = (char*)tab) + num * siz; p < e; p += siz)
670*4887Schin 		if (match(s, *((char**)p), -1, NiL))
671*4887Schin 			return (void*)p;
672*4887Schin 	return 0;
673*4887Schin }
674*4887Schin 
675*4887Schin /*
676*4887Schin  * save s and return the saved pointer
677*4887Schin  */
678*4887Schin 
679*4887Schin static char*
680*4887Schin save(const char* s)
681*4887Schin {
682*4887Schin 	Save_t*		p;
683*4887Schin 
684*4887Schin 	static Dtdisc_t	disc;
685*4887Schin 	static Dt_t*	dict;
686*4887Schin 
687*4887Schin 	if (!dict)
688*4887Schin 	{
689*4887Schin 		disc.key = offsetof(Save_t, text);
690*4887Schin 		if (!(dict = dtopen(&disc, Dthash)))
691*4887Schin 			return (char*)s;
692*4887Schin 	}
693*4887Schin 	if (!(p = (Save_t*)dtmatch(dict, s)))
694*4887Schin 	{
695*4887Schin 		if (!(p = newof(0, Save_t, 1, strlen(s))))
696*4887Schin 			return (char*)s;
697*4887Schin 		strcpy(p->text, s);
698*4887Schin 		dtinsert(dict, p);
699*4887Schin 	}
700*4887Schin 	return p->text;
701*4887Schin }
702*4887Schin 
703*4887Schin /*
704*4887Schin  * initialize the attributes for pass p from opt string s
705*4887Schin  */
706*4887Schin 
707*4887Schin static int
708*4887Schin init(register char* s, Optpass_t* p)
709*4887Schin {
710*4887Schin 	register char*	t;
711*4887Schin 	register int	c;
712*4887Schin 	register int	a;
713*4887Schin 	register int	n;
714*4887Schin 
715*4887Schin 	if (!opt_info.state->msgdict)
716*4887Schin 	{
717*4887Schin #if !_PACKAGE_astsa
718*4887Schin 		if (!ast.locale.serial)
719*4887Schin 			setlocale(LC_ALL, "");
720*4887Schin #endif
721*4887Schin 		opt_info.state->vp = sfstropen();
722*4887Schin 		opt_info.state->xp = sfstropen();
723*4887Schin 		opt_info.state->msgdisc.key = offsetof(Msg_t, text);
724*4887Schin 		opt_info.state->msgdisc.size = -1;
725*4887Schin 		opt_info.state->msgdisc.link = offsetof(Msg_t, link);
726*4887Schin 		if (opt_info.state->msgdict = dtopen(&opt_info.state->msgdisc, Dthash))
727*4887Schin 			for (n = 0; n < elementsof(C_LC_MESSAGES_libast); n++)
728*4887Schin 				dtinsert(opt_info.state->msgdict, C_LC_MESSAGES_libast + n);
729*4887Schin 		if (!map[OPT_FLAGS[0]])
730*4887Schin 			for (n = 0, t = OPT_FLAGS; *t; t++)
731*4887Schin 				map[*t] = ++n;
732*4887Schin 	}
733*4887Schin #if _BLD_DEBUG
734*4887Schin 	error(-1, "optget debug");
735*4887Schin #endif
736*4887Schin 	p->oopts = s;
737*4887Schin 	p->version = 0;
738*4887Schin 	p->prefix = 2;
739*4887Schin 	p->section = 1;
740*4887Schin 	p->flags = 0;
741*4887Schin 	p->catalog = 0;
742*4887Schin 	s = next(s, 0);
743*4887Schin 	if (*s == ':')
744*4887Schin 		s++;
745*4887Schin 	if (*s == '+')
746*4887Schin 		s++;
747*4887Schin 	s = next(s, 0);
748*4887Schin 	if (*s++ == '[')
749*4887Schin 	{
750*4887Schin 		if (*s == '+')
751*4887Schin 			p->version = 1;
752*4887Schin 		else if (*s++ == '-')
753*4887Schin 		{
754*4887Schin 			if (*s == '?' || *s == ']')
755*4887Schin 				p->version = 1;
756*4887Schin 			else
757*4887Schin 			{
758*4887Schin 				if (*s < '0' || *s > '9')
759*4887Schin 					p->version = 1;
760*4887Schin 				else
761*4887Schin 					while (*s >= '0' && *s <= '9')
762*4887Schin 						p->version = p->version * 10 + (*s++ - '0');
763*4887Schin 				while (*s && *s != '?' && *s != ']')
764*4887Schin 				{
765*4887Schin 					c = *s++;
766*4887Schin 					if (*s < '0' || *s > '9')
767*4887Schin 						n = 1;
768*4887Schin 					else
769*4887Schin 					{
770*4887Schin 						n = 0;
771*4887Schin 						while (*s >= '0' && *s <= '9')
772*4887Schin 							n = n * 10 + (*s++ - '0');
773*4887Schin 					}
774*4887Schin 					switch (c)
775*4887Schin 					{
776*4887Schin 					case 'c':
777*4887Schin 						p->flags |= OPT_cache;
778*4887Schin 						break;
779*4887Schin 					case 'i':
780*4887Schin 						p->flags |= OPT_ignore;
781*4887Schin 						break;
782*4887Schin 					case 'l':
783*4887Schin 						p->flags |= OPT_long;
784*4887Schin 						break;
785*4887Schin 					case 'o':
786*4887Schin 						p->flags |= OPT_old;
787*4887Schin 						break;
788*4887Schin 					case 'p':
789*4887Schin 						p->prefix = n;
790*4887Schin 						break;
791*4887Schin 					case 's':
792*4887Schin 						p->section = n;
793*4887Schin 						if (n > 1 && n < 6)
794*4887Schin 						{
795*4887Schin 							p->flags |= OPT_functions;
796*4887Schin 							p->prefix = 0;
797*4887Schin 						}
798*4887Schin 						break;
799*4887Schin 					}
800*4887Schin 				}
801*4887Schin 			}
802*4887Schin 		}
803*4887Schin 		while (*s)
804*4887Schin 			if (*s++ == ']' && *s++ == '[')
805*4887Schin 			{
806*4887Schin 				if (*s++ != '-')
807*4887Schin 				{
808*4887Schin 					if (!error_info.id && strneq(s - 1, "+NAME?", 6))
809*4887Schin 					{
810*4887Schin 						for (t = s += 5; *t && *t != ' ' && *t != ']'; t++);
811*4887Schin 						error_info.id = save(sfprints("%-.*s", t - s, s));
812*4887Schin 					}
813*4887Schin 					break;
814*4887Schin 				}
815*4887Schin 				if (*s == '-')
816*4887Schin 					s++;
817*4887Schin 				if (strneq(s, "catalog?", 8))
818*4887Schin 				{
819*4887Schin 					s += 8;
820*4887Schin 					if ((t = strchr(s, ']')) && (!error_info.id || (t - s) != strlen(error_info.id) || !strneq(s, error_info.id, t - s)))
821*4887Schin 						p->catalog = save(sfprints("%-.*s", t - s, s));
822*4887Schin 					if (error_info.id)
823*4887Schin 						break;
824*4887Schin 				}
825*4887Schin 			}
826*4887Schin 	}
827*4887Schin 	if (!p->catalog)
828*4887Schin 	{
829*4887Schin 		if (opt_info.disc && opt_info.disc->catalog && (!error_info.id || !streq(opt_info.disc->catalog, error_info.id)))
830*4887Schin 			p->catalog = opt_info.disc->catalog;
831*4887Schin 		else
832*4887Schin 			p->catalog = ID;
833*4887Schin 	}
834*4887Schin 	s = p->oopts;
835*4887Schin 	if (*s == ':')
836*4887Schin 		s++;
837*4887Schin 	if (*s == '+')
838*4887Schin 	{
839*4887Schin 		s++;
840*4887Schin 		p->flags |= OPT_plus;
841*4887Schin 	}
842*4887Schin 	if (*s != '[')
843*4887Schin 		for (t = s, a = 0; *t; t++)
844*4887Schin 			if (!a && *t == '-')
845*4887Schin 			{
846*4887Schin 				p->flags |= OPT_minus;
847*4887Schin 				break;
848*4887Schin 			}
849*4887Schin 			else if (*t == '[')
850*4887Schin 				a++;
851*4887Schin 			else if (*t == ']')
852*4887Schin 				a--;
853*4887Schin 	if (!p->version && (t = strchr(s, '(')) && strchr(t, ')') && (opt_info.state->cp || (opt_info.state->cp = sfstropen())))
854*4887Schin 	{
855*4887Schin 		/*
856*4887Schin 		 * solaris long option compatibility
857*4887Schin 		 */
858*4887Schin 
859*4887Schin 		p->version = 1;
860*4887Schin 		for (t = p->oopts; t < s; t++)
861*4887Schin 			sfputc(opt_info.state->cp, *t);
862*4887Schin 		n = t - p->oopts;
863*4887Schin 		sfputc(opt_info.state->cp, '[');
864*4887Schin 		sfputc(opt_info.state->cp, '-');
865*4887Schin 		sfputc(opt_info.state->cp, ']');
866*4887Schin 		while (c = *s++)
867*4887Schin 		{
868*4887Schin 			sfputc(opt_info.state->cp, '[');
869*4887Schin 			sfputc(opt_info.state->cp, c);
870*4887Schin 			if (a = (c = *s++) == ':')
871*4887Schin 				c = *s++;
872*4887Schin 			if (c == '(')
873*4887Schin 			{
874*4887Schin 				sfputc(opt_info.state->cp, ':');
875*4887Schin 				for (;;)
876*4887Schin 				{
877*4887Schin 					while ((c = *s++) && c != ')')
878*4887Schin 						sfputc(opt_info.state->cp, c);
879*4887Schin 					if (!c || *s != '(')
880*4887Schin 						break;
881*4887Schin 					sfputc(opt_info.state->cp, '|');
882*4887Schin 					s++;
883*4887Schin 				}
884*4887Schin 			}
885*4887Schin 			sfputc(opt_info.state->cp, ']');
886*4887Schin 			if (a)
887*4887Schin 				sfputr(opt_info.state->cp, ":[string]", -1);
888*4887Schin 			if (!c)
889*4887Schin 				break;
890*4887Schin 		}
891*4887Schin 		if (!(p->oopts = s = sfstruse(opt_info.state->cp)))
892*4887Schin 			return -1;
893*4887Schin 		s += n;
894*4887Schin 	}
895*4887Schin 	p->opts = s;
896*4887Schin 	return 0;
897*4887Schin }
898*4887Schin 
899*4887Schin /*
900*4887Schin  * return the bold set/unset sequence for style
901*4887Schin  */
902*4887Schin 
903*4887Schin static const char*
904*4887Schin font(int f, int style, int set)
905*4887Schin {
906*4887Schin 	switch (style)
907*4887Schin 	{
908*4887Schin 	case STYLE_html:
909*4887Schin 		return fonts[f].html[set];
910*4887Schin 	case STYLE_nroff:
911*4887Schin 		return fonts[f].nroff[set];
912*4887Schin 	case STYLE_short:
913*4887Schin 	case STYLE_long:
914*4887Schin 	case STYLE_posix:
915*4887Schin 	case STYLE_api:
916*4887Schin 		break;
917*4887Schin 	default:
918*4887Schin 		if (opt_info.state->emphasis > 0)
919*4887Schin 			return fonts[f].term[set];
920*4887Schin 		break;
921*4887Schin 	}
922*4887Schin 	return "";
923*4887Schin }
924*4887Schin 
925*4887Schin /*
926*4887Schin  * expand \f...\f info
927*4887Schin  * *p set to next char after second \f
928*4887Schin  * expanded value returned
929*4887Schin  */
930*4887Schin 
931*4887Schin static char*
932*4887Schin expand(register char* s, register char* e, char** p, Sfio_t* ip)
933*4887Schin {
934*4887Schin 	register int	c;
935*4887Schin 	register char*	b = s;
936*4887Schin 	int		n;
937*4887Schin 
938*4887Schin 	message((-23, "AHA#%d expand(%s)", __LINE__, show(s)));
939*4887Schin 	n = sfstrtell(ip);
940*4887Schin 	c = 1;
941*4887Schin 	while ((!e || s < e) && (c = *s++) && c != '\f');
942*4887Schin 	sfwrite(ip, b, s - b - 1);
943*4887Schin 	sfputc(ip, 0);
944*4887Schin 	b = sfstrbase(ip) + n;
945*4887Schin 	message((-23, "AHA#%d expand(%s)", __LINE__, b));
946*4887Schin 	n = sfstrtell(ip);
947*4887Schin 	if (!c)
948*4887Schin 		s--;
949*4887Schin 	if (*b == '?')
950*4887Schin 	{
951*4887Schin 		if (!*++b || streq(b, "NAME"))
952*4887Schin 		{
953*4887Schin 			if (!(b = error_info.id))
954*4887Schin 				b = "command";
955*4887Schin 			sfstrseek(ip, 0, SEEK_SET);
956*4887Schin 			sfputr(ip, b, -1);
957*4887Schin 			n = 0;
958*4887Schin 		}
959*4887Schin 		else
960*4887Schin 			n = 1;
961*4887Schin 	}
962*4887Schin 	else if (!opt_info.disc || !opt_info.disc->infof || (*opt_info.disc->infof)(&opt_info, ip, b, opt_info.disc) < 0)
963*4887Schin 		n = 0;
964*4887Schin 	*p = s;
965*4887Schin 	if (s = sfstruse(ip))
966*4887Schin 		s += n;
967*4887Schin 	else
968*4887Schin 		s = "error";
969*4887Schin 	return s;
970*4887Schin }
971*4887Schin 
972*4887Schin /*
973*4887Schin  * push \f...\f info
974*4887Schin  */
975*4887Schin 
976*4887Schin static Push_t*
977*4887Schin info(Push_t* psp, char* s, char* e, Sfio_t* ip)
978*4887Schin {
979*4887Schin 	register char*	b;
980*4887Schin 	int		n;
981*4887Schin 	Push_t*		tsp;
982*4887Schin 
983*4887Schin 	static Push_t	push;
984*4887Schin 
985*4887Schin 	b = expand(s, e, &s, ip);
986*4887Schin 	n = strlen(b);
987*4887Schin 	if (tsp = newof(0, Push_t, 1, n + 1))
988*4887Schin 	{
989*4887Schin 		tsp->nb = (char*)(tsp + 1);
990*4887Schin 		tsp->ne = tsp->nb + n;
991*4887Schin 		strcpy(tsp->nb, b);
992*4887Schin 	}
993*4887Schin 	else
994*4887Schin 		tsp = &push;
995*4887Schin 	tsp->next = psp;
996*4887Schin 	tsp->ob = s;
997*4887Schin 	tsp->oe = e;
998*4887Schin 	return tsp;
999*4887Schin }
1000*4887Schin 
1001*4887Schin /*
1002*4887Schin  * push translation
1003*4887Schin  */
1004*4887Schin 
1005*4887Schin static Push_t*
1006*4887Schin localize(Push_t* psp, char* s, char* e, int term, int n, char* catalog, int version, Sfio_t* ip)
1007*4887Schin {
1008*4887Schin 	char*		t;
1009*4887Schin 	char*		u;
1010*4887Schin 	Push_t*		tsp;
1011*4887Schin 	int		c;
1012*4887Schin 
1013*4887Schin 	t = skip(s, term, 0, 0, n, 0, 0, version);
1014*4887Schin 	if (e && t > e)
1015*4887Schin 		t = e;
1016*4887Schin 	while (s < t)
1017*4887Schin 	{
1018*4887Schin 		switch (c = *s++)
1019*4887Schin 		{
1020*4887Schin 		case ':':
1021*4887Schin 		case '?':
1022*4887Schin 			if (term && *s == c)
1023*4887Schin 				s++;
1024*4887Schin 			break;
1025*4887Schin 		case ']':
1026*4887Schin 			if (*s == c)
1027*4887Schin 				s++;
1028*4887Schin 			break;
1029*4887Schin 		}
1030*4887Schin 		sfputc(ip, c);
1031*4887Schin 	}
1032*4887Schin 	if (!(s = sfstruse(ip)) || (u = T(error_info.id, catalog, s)) == s)
1033*4887Schin 		return 0;
1034*4887Schin 	n = strlen(u);
1035*4887Schin 	if (tsp = newof(0, Push_t, 1, n + 1))
1036*4887Schin 	{
1037*4887Schin 		tsp->nb = (char*)(tsp + 1);
1038*4887Schin 		tsp->ne = tsp->nb + n;
1039*4887Schin 		strcpy(tsp->nb, u);
1040*4887Schin 		tsp->ob = t;
1041*4887Schin 		tsp->oe = e;
1042*4887Schin 		tsp->ch = 1;
1043*4887Schin 	}
1044*4887Schin 	tsp->next = psp;
1045*4887Schin 	return tsp;
1046*4887Schin }
1047*4887Schin 
1048*4887Schin /*
1049*4887Schin  * output label s from [ ...label...[?...] ] to sp
1050*4887Schin  * 1 returned if the label was translated
1051*4887Schin  */
1052*4887Schin 
1053*4887Schin static int
1054*4887Schin label(register Sfio_t* sp, int sep, register char* s, int z, int level, int style, int f, Sfio_t* ip, int version, char* catalog)
1055*4887Schin {
1056*4887Schin 	register int	c;
1057*4887Schin 	register char*	t;
1058*4887Schin 	register char*	e;
1059*4887Schin 	int		ostyle;
1060*4887Schin 	int		a;
1061*4887Schin 	int		i;
1062*4887Schin 	char*		p;
1063*4887Schin 	char*		w;
1064*4887Schin 	char*		y;
1065*4887Schin 	int		va;
1066*4887Schin 	Push_t*		tsp;
1067*4887Schin 
1068*4887Schin 	int		r = 0;
1069*4887Schin 	int		n = 1;
1070*4887Schin 	Push_t*		psp = 0;
1071*4887Schin 
1072*4887Schin 	if ((ostyle = style) > (STYLE_nroff - (sep <= 0)) && f != FONT_LITERAL)
1073*4887Schin 		style = 0;
1074*4887Schin 	if (z < 0)
1075*4887Schin 		e = s + strlen(s);
1076*4887Schin 	else
1077*4887Schin 		e = s + z;
1078*4887Schin 	if (sep > 0)
1079*4887Schin 	{
1080*4887Schin 		if (sep == ' ' && style == STYLE_nroff)
1081*4887Schin 			sfputc(sp, '\\');
1082*4887Schin 		sfputc(sp, sep);
1083*4887Schin 	}
1084*4887Schin 	sep = !sep || z < 0;
1085*4887Schin 	va = 0;
1086*4887Schin 	y = 0;
1087*4887Schin 	if (version < 1)
1088*4887Schin 	{
1089*4887Schin 		a = 0;
1090*4887Schin 		for (;;)
1091*4887Schin 		{
1092*4887Schin 			if (s >= e)
1093*4887Schin 				return r;
1094*4887Schin 			switch (c = *s++)
1095*4887Schin 			{
1096*4887Schin 			case '[':
1097*4887Schin 				a++;
1098*4887Schin 				break;
1099*4887Schin 			case ']':
1100*4887Schin 				if (--a < 0)
1101*4887Schin 					return r;
1102*4887Schin 				break;
1103*4887Schin 			}
1104*4887Schin 			sfputc(sp, c);
1105*4887Schin 		}
1106*4887Schin 	}
1107*4887Schin 	else if (level && (*(p = skip(s, 0, 0, 0, 1, level, 1, version)) == ':' || *p == '#'))
1108*4887Schin 	{
1109*4887Schin 		va = 0;
1110*4887Schin 		if (*++p == '?' || *p == *(p - 1))
1111*4887Schin 		{
1112*4887Schin 			p++;
1113*4887Schin 			va |= OPT_optional;
1114*4887Schin 		}
1115*4887Schin 		if (*(p = next(p, version)) == '[')
1116*4887Schin 			y = p + 1;
1117*4887Schin 	}
1118*4887Schin 	if (X(catalog) && (!level || *s == '\a' || *(s - 1) != '+') &&
1119*4887Schin 	    (tsp = localize(psp, s, e, (sep || level) ? '?' : 0, sep || level, catalog, version, ip)))
1120*4887Schin 	{
1121*4887Schin 		psp= tsp;
1122*4887Schin 		s = psp->nb;
1123*4887Schin 		e = psp->ne;
1124*4887Schin 		r = psp->ch > 0;
1125*4887Schin 	}
1126*4887Schin 	switch (*s)
1127*4887Schin 	{
1128*4887Schin 	case '\a':
1129*4887Schin 		if (f == FONT_ITALIC)
1130*4887Schin 			s++;
1131*4887Schin 		f = 0;
1132*4887Schin 		break;
1133*4887Schin 	case '\b':
1134*4887Schin 		if (f == FONT_BOLD)
1135*4887Schin 			s++;
1136*4887Schin 		f = 0;
1137*4887Schin 		break;
1138*4887Schin 	case '\v':
1139*4887Schin 		if (f == FONT_LITERAL)
1140*4887Schin 			s++;
1141*4887Schin 		f = 0;
1142*4887Schin 		break;
1143*4887Schin 	default:
1144*4887Schin 		if (f)
1145*4887Schin 			sfputr(sp, font(f, style, 1), -1);
1146*4887Schin 		break;
1147*4887Schin 	}
1148*4887Schin 	for (;;)
1149*4887Schin 	{
1150*4887Schin 		if (s >= e)
1151*4887Schin 		{
1152*4887Schin 			if (!(tsp = psp))
1153*4887Schin 				goto restore;
1154*4887Schin 			s = psp->ob;
1155*4887Schin 			e = psp->oe;
1156*4887Schin 			psp = psp->next;
1157*4887Schin 			free(tsp);
1158*4887Schin 			continue;
1159*4887Schin 		}
1160*4887Schin 		switch (c = *s++)
1161*4887Schin 		{
1162*4887Schin 		case '(':
1163*4887Schin 			if (n)
1164*4887Schin 			{
1165*4887Schin 				n = 0;
1166*4887Schin 				if (f)
1167*4887Schin 				{
1168*4887Schin 					sfputr(sp, font(f, style, 0), -1);
1169*4887Schin 					f = 0;
1170*4887Schin 				}
1171*4887Schin 			}
1172*4887Schin 			break;
1173*4887Schin 		case '?':
1174*4887Schin 		case ':':
1175*4887Schin 		case ']':
1176*4887Schin 			if (psp && psp->ch)
1177*4887Schin 				break;
1178*4887Schin 			if (y)
1179*4887Schin 			{
1180*4887Schin 				if (va & OPT_optional)
1181*4887Schin 					sfputc(sp, '[');
1182*4887Schin 				sfputc(sp, '=');
1183*4887Schin 				label(sp, 0, y, -1, 0, style, FONT_ITALIC, ip, version, catalog);
1184*4887Schin 				if (va & OPT_optional)
1185*4887Schin 					sfputc(sp, ']');
1186*4887Schin 				y = 0;
1187*4887Schin 			}
1188*4887Schin 			switch (c)
1189*4887Schin 			{
1190*4887Schin 			case '?':
1191*4887Schin 				if (*s == '?')
1192*4887Schin 					s++;
1193*4887Schin 				else if (*s == ']' && *(s + 1) != ']')
1194*4887Schin 					continue;
1195*4887Schin 				else if (sep)
1196*4887Schin 					goto restore;
1197*4887Schin 				else if (X(catalog) && (tsp = localize(psp, s, e, 0, 1, catalog, version, ip)))
1198*4887Schin 				{
1199*4887Schin 					psp = tsp;
1200*4887Schin 					s = psp->nb;
1201*4887Schin 					e = psp->ne;
1202*4887Schin 				}
1203*4887Schin 				break;
1204*4887Schin 			case ']':
1205*4887Schin 				if (sep && *s++ != ']')
1206*4887Schin 					goto restore;
1207*4887Schin 				break;
1208*4887Schin 			case ':':
1209*4887Schin 				if (sep && *s++ != ':')
1210*4887Schin 					goto restore;
1211*4887Schin 				break;
1212*4887Schin 			}
1213*4887Schin 			break;
1214*4887Schin 		case '\a':
1215*4887Schin 			a = FONT_ITALIC;
1216*4887Schin 		setfont:
1217*4887Schin 			if (f & ~a)
1218*4887Schin 			{
1219*4887Schin 				sfputr(sp, font(f, style, 0), -1);
1220*4887Schin 				f = 0;
1221*4887Schin 			}
1222*4887Schin 			if (!f && style == STYLE_html)
1223*4887Schin 			{
1224*4887Schin 				for (t = s; t < e && !isspace(*t) && !iscntrl(*t); t++);
1225*4887Schin 				if (*t == c && *++t == '(')
1226*4887Schin 				{
1227*4887Schin 					w = t;
1228*4887Schin 					while (++t < e && isdigit(*t));
1229*4887Schin 					if (t < e && *t == ')' && t > w + 1)
1230*4887Schin 					{
1231*4887Schin 						sfprintf(sp, "<NOBR><A href=\"../man%-.*s/%-.*s.html\">%s%-.*s%s</A>%-.*s</NOBR>"
1232*4887Schin 							, t - w - 1, w + 1
1233*4887Schin 							, w - s - 1, s
1234*4887Schin 							, font(a, style, 1)
1235*4887Schin 							, w - s - 1, s
1236*4887Schin 							, font(a, style, 0)
1237*4887Schin 							, t - w + 1, w
1238*4887Schin 							);
1239*4887Schin 						s = t + 1;
1240*4887Schin 						continue;
1241*4887Schin 					}
1242*4887Schin 				}
1243*4887Schin 			}
1244*4887Schin 			sfputr(sp, font(a, style, !!(f ^= a)), -1);
1245*4887Schin 			continue;
1246*4887Schin 		case '\b':
1247*4887Schin 			a = FONT_BOLD;
1248*4887Schin 			goto setfont;
1249*4887Schin 		case '\f':
1250*4887Schin 			psp = info(psp, s, e, ip);
1251*4887Schin 			if (psp->nb)
1252*4887Schin 			{
1253*4887Schin 				s = psp->nb;
1254*4887Schin 				e = psp->ne;
1255*4887Schin 			}
1256*4887Schin 			else
1257*4887Schin 			{
1258*4887Schin 				s = psp->ob;
1259*4887Schin 				psp = psp->next;
1260*4887Schin 			}
1261*4887Schin 			continue;
1262*4887Schin 		case '\n':
1263*4887Schin 			sfputc(sp, c);
1264*4887Schin 			for (i = 0; i < level; i++)
1265*4887Schin 				sfputc(sp, '\t');
1266*4887Schin 			continue;
1267*4887Schin 		case '\v':
1268*4887Schin 			a = FONT_LITERAL;
1269*4887Schin 			goto setfont;
1270*4887Schin 		case '<':
1271*4887Schin 			if (style == STYLE_html)
1272*4887Schin 			{
1273*4887Schin 				sfputr(sp, "&lt;", -1);
1274*4887Schin 				c = 0;
1275*4887Schin 				for (t = s; t < e; t++)
1276*4887Schin 					if (!isalnum(*t) && *t != '_' && *t != '.' && *t != '-')
1277*4887Schin 					{
1278*4887Schin 						if (*t == '@')
1279*4887Schin 						{
1280*4887Schin 							if (c)
1281*4887Schin 								break;
1282*4887Schin 							c = 1;
1283*4887Schin 						}
1284*4887Schin 						else if (*t == '>')
1285*4887Schin 						{
1286*4887Schin 							if (c)
1287*4887Schin 							{
1288*4887Schin 								sfprintf(sp, "<A href=\"mailto:%-.*s>%-.*s</A>&gt;", t - s, s, t - s, s);
1289*4887Schin 								s = t + 1;
1290*4887Schin 							}
1291*4887Schin 							break;
1292*4887Schin 						}
1293*4887Schin 						else
1294*4887Schin 							break;
1295*4887Schin 					}
1296*4887Schin 				continue;
1297*4887Schin 			}
1298*4887Schin 			break;
1299*4887Schin 		case '>':
1300*4887Schin 			if (style == STYLE_html)
1301*4887Schin 			{
1302*4887Schin 				sfputr(sp, "&gt;", -1);
1303*4887Schin 				continue;
1304*4887Schin 			}
1305*4887Schin 			break;
1306*4887Schin 		case '&':
1307*4887Schin 			if (style == STYLE_html)
1308*4887Schin 			{
1309*4887Schin 				sfputr(sp, "&amp;", -1);
1310*4887Schin 				continue;
1311*4887Schin 			}
1312*4887Schin 			break;
1313*4887Schin 		case '-':
1314*4887Schin 			if (ostyle == STYLE_nroff)
1315*4887Schin 				sfputc(sp, '\\');
1316*4887Schin 			break;
1317*4887Schin 		case '.':
1318*4887Schin 			if (ostyle == STYLE_nroff)
1319*4887Schin 			{
1320*4887Schin 				sfputc(sp, '\\');
1321*4887Schin 				sfputc(sp, '&');
1322*4887Schin 			}
1323*4887Schin 			break;
1324*4887Schin 		case '\\':
1325*4887Schin 			if (ostyle == STYLE_nroff)
1326*4887Schin 			{
1327*4887Schin 				c = 'e';
1328*4887Schin 				sfputc(sp, '\\');
1329*4887Schin 			}
1330*4887Schin 			break;
1331*4887Schin 		case ' ':
1332*4887Schin 			if (ostyle == STYLE_nroff)
1333*4887Schin 				sfputc(sp, '\\');
1334*4887Schin 			break;
1335*4887Schin 		}
1336*4887Schin 		sfputc(sp, c);
1337*4887Schin 	}
1338*4887Schin  restore:
1339*4887Schin 	if (f)
1340*4887Schin 		sfputr(sp, font(f, style, 0), -1);
1341*4887Schin 	if (psp)
1342*4887Schin 		pop(psp);
1343*4887Schin 	return r;
1344*4887Schin }
1345*4887Schin 
1346*4887Schin /*
1347*4887Schin  * output args description to sp from p of length n
1348*4887Schin  */
1349*4887Schin 
1350*4887Schin static void
1351*4887Schin args(register Sfio_t* sp, register char* p, register int n, int flags, int style, Sfio_t* ip, int version, char* catalog)
1352*4887Schin {
1353*4887Schin 	register int	i;
1354*4887Schin 	register char*	t;
1355*4887Schin 	register char*	o;
1356*4887Schin 	register char*	a = 0;
1357*4887Schin 	char*		b;
1358*4887Schin 	int		sep;
1359*4887Schin 
1360*4887Schin 	if (flags & OPT_functions)
1361*4887Schin 		sep = '\t';
1362*4887Schin 	else
1363*4887Schin 	{
1364*4887Schin 		sep = ' ';
1365*4887Schin 		o = T(NiL, ID, "options");
1366*4887Schin 		b = style == STYLE_nroff ? "\\ " : " ";
1367*4887Schin 		for (;;)
1368*4887Schin 		{
1369*4887Schin 			t = (char*)memchr(p, '\n', n);
1370*4887Schin 			if (style >= STYLE_man)
1371*4887Schin 			{
1372*4887Schin 				if (!(a = error_info.id))
1373*4887Schin 					a = "...";
1374*4887Schin 				sfprintf(sp, "\t%s%s%s%s[%s%s%s%s%s]", font(FONT_BOLD, style, 1), a, font(FONT_BOLD, style, 0), b, b, font(FONT_ITALIC, style, 1), o, font(FONT_ITALIC, style, 0), b);
1375*4887Schin 			}
1376*4887Schin 			else if (a)
1377*4887Schin 				sfprintf(sp, "%*.*s%s%s%s[%s%s%s]", OPT_USAGE - 1, OPT_USAGE - 1, T(NiL, ID, "Or:"), b, a, b, b, o, b);
1378*4887Schin 			else
1379*4887Schin 			{
1380*4887Schin 				if (!(a = error_info.id))
1381*4887Schin 					a = "...";
1382*4887Schin 				if (!sfstrtell(sp))
1383*4887Schin 					sfprintf(sp, "[%s%s%s]", b, o, b);
1384*4887Schin 			}
1385*4887Schin 			if (!t)
1386*4887Schin 				break;
1387*4887Schin 			i = ++t - p;
1388*4887Schin 			if (i)
1389*4887Schin 			{
1390*4887Schin 				sfputr(sp, b, -1);
1391*4887Schin 				if (X(catalog))
1392*4887Schin 				{
1393*4887Schin 					sfwrite(ip, p, i);
1394*4887Schin 					if (b = sfstruse(ip))
1395*4887Schin 						sfputr(sp, T(error_info.id, catalog, b), -1);
1396*4887Schin 					else
1397*4887Schin 						sfwrite(sp, p, i);
1398*4887Schin 				}
1399*4887Schin 				else
1400*4887Schin 					sfwrite(sp, p, i);
1401*4887Schin 			}
1402*4887Schin 			if (style == STYLE_html)
1403*4887Schin 				sfputr(sp, "<BR>", '\n');
1404*4887Schin 			else if (style == STYLE_nroff)
1405*4887Schin 				sfputr(sp, ".br", '\n');
1406*4887Schin 			else if (style == STYLE_api)
1407*4887Schin 				sfputr(sp, ".BR", '\n');
1408*4887Schin 			p = t;
1409*4887Schin 			n -= i;
1410*4887Schin 			while (n > 0 && (*p == ' ' || *p == '\t'))
1411*4887Schin 			{
1412*4887Schin 				p++;
1413*4887Schin 				n--;
1414*4887Schin 			}
1415*4887Schin 		}
1416*4887Schin 	}
1417*4887Schin 	if (n)
1418*4887Schin 		label(sp, sep, p, n, 0, style, 0, ip, version, catalog);
1419*4887Schin }
1420*4887Schin 
1421*4887Schin /*
1422*4887Schin  * output [+-...label...?...] label s to sp
1423*4887Schin  * according to {...} level and style
1424*4887Schin  * return 0:header 1:paragraph
1425*4887Schin  */
1426*4887Schin 
1427*4887Schin static int
1428*4887Schin item(Sfio_t* sp, char* s, int level, int style, Sfio_t* ip, int version, char* catalog)
1429*4887Schin {
1430*4887Schin 	register char*	t;
1431*4887Schin 	int		n;
1432*4887Schin 	int		par;
1433*4887Schin 
1434*4887Schin 	sfputc(sp, '\n');
1435*4887Schin 	if (*s == '\n')
1436*4887Schin 	{
1437*4887Schin 		par = 0;
1438*4887Schin 		if (style >= STYLE_nroff)
1439*4887Schin 			sfprintf(sp, ".DS\n");
1440*4887Schin 		else
1441*4887Schin 		{
1442*4887Schin 			if (style == STYLE_html)
1443*4887Schin 				sfprintf(sp, "<PRE>\n");
1444*4887Schin 			else
1445*4887Schin 				sfputc(sp, '\n');
1446*4887Schin 			for (n = 0; n < level; n++)
1447*4887Schin 				sfputc(sp, '\t');
1448*4887Schin 		}
1449*4887Schin 		label(sp, 0, s + 1, -1, level, style, FONT_LITERAL, ip, version, catalog);
1450*4887Schin 		sfputc(sp, '\n');
1451*4887Schin 		if (style >= STYLE_nroff)
1452*4887Schin 			sfprintf(sp, ".DE");
1453*4887Schin 		else if (style == STYLE_html)
1454*4887Schin 			sfprintf(sp, "</PRE>");
1455*4887Schin 	}
1456*4887Schin 	else if (*s != ']' && (*s != '?' || *(s + 1) == '?'))
1457*4887Schin 	{
1458*4887Schin 		par = 0;
1459*4887Schin 		if (level)
1460*4887Schin 		{
1461*4887Schin 			if (style >= STYLE_nroff)
1462*4887Schin 				sfprintf(sp, ".H%d ", (level + 1) / 2);
1463*4887Schin 			else
1464*4887Schin 				for (n = 0; n < level; n++)
1465*4887Schin 					sfputc(sp, '\t');
1466*4887Schin 		}
1467*4887Schin 		if (style == STYLE_html)
1468*4887Schin 		{
1469*4887Schin 			if (!level)
1470*4887Schin 				sfputr(sp, "<H4>", -1);
1471*4887Schin 			sfputr(sp, "<A name=\"", -1);
1472*4887Schin 			if (s[-1] == '-' && s[0] == 'l' && s[1] == 'i' && s[2] == 'c' && s[3] == 'e' && s[4] == 'n' && s[5] == 's' && s[6] == 'e' && s[7] == '?')
1473*4887Schin 				for (t = s + 8; *t && *t != ']'; t++)
1474*4887Schin 					if (t[0] == 'p' && (!strncmp(t, "proprietary", 11) || !strncmp(t, "private", 7)) || t[0] == 'n' && !strncmp(t, "noncommercial", 13))
1475*4887Schin 					{
1476*4887Schin 						opt_info.state->flags |= OPT_proprietary;
1477*4887Schin 						break;
1478*4887Schin 					}
1479*4887Schin 			label(sp, 0, s, -1, level, 0, 0, ip, version, catalog);
1480*4887Schin 			sfputr(sp, "\">", -1);
1481*4887Schin 			label(sp, 0, s, -1, level, style, level ? FONT_BOLD : 0, ip, version, catalog);
1482*4887Schin 			sfputr(sp, "</A>", -1);
1483*4887Schin 			if (!level)
1484*4887Schin 				sfputr(sp, "</H4>", -1);
1485*4887Schin 		}
1486*4887Schin 		else
1487*4887Schin 		{
1488*4887Schin 			if (!level)
1489*4887Schin 			{
1490*4887Schin 				if (style >= STYLE_nroff)
1491*4887Schin 					sfprintf(sp, ".SH ");
1492*4887Schin 				else if (style == STYLE_man)
1493*4887Schin 					sfputc(sp, '\n');
1494*4887Schin 				else if (style != STYLE_options && style != STYLE_match || *s == '-' || *s == '+')
1495*4887Schin 					sfputc(sp, '\t');
1496*4887Schin 			}
1497*4887Schin 			label(sp, 0, s, -1, level, style, FONT_BOLD, ip, version, catalog);
1498*4887Schin 		}
1499*4887Schin 	}
1500*4887Schin 	else
1501*4887Schin 	{
1502*4887Schin 		par = 1;
1503*4887Schin 		if (style >= STYLE_nroff)
1504*4887Schin 			sfputr(sp, ".PP", -1);
1505*4887Schin 	}
1506*4887Schin 	if (style >= STYLE_nroff || !level)
1507*4887Schin 		sfputc(sp, '\n');
1508*4887Schin 	if (par && style < STYLE_nroff)
1509*4887Schin 		for (n = 0; n < level; n++)
1510*4887Schin 			sfputc(sp, '\t');
1511*4887Schin 	return par;
1512*4887Schin }
1513*4887Schin 
1514*4887Schin /*
1515*4887Schin  * output text to sp from p according to style
1516*4887Schin  */
1517*4887Schin 
1518*4887Schin static char*
1519*4887Schin textout(Sfio_t* sp, register char* p, int style, int level, int bump, Sfio_t* ip, int version, char* catalog)
1520*4887Schin {
1521*4887Schin #if 0
1522*4887Schin #define textout(a,b,c,d,e,f,g,h)	(sfprintf(a,"(%d)",__LINE__),textout(a,b,c,d,e,f,g,h))
1523*4887Schin #endif
1524*4887Schin 	register char*	t;
1525*4887Schin 	register int	c;
1526*4887Schin 	register int	n;
1527*4887Schin 	char*		e;
1528*4887Schin 	int		a;
1529*4887Schin 	int		f;
1530*4887Schin 	int		par;
1531*4887Schin 	Push_t*		tsp;
1532*4887Schin 
1533*4887Schin 	int		ident = 0;
1534*4887Schin 	int		lev = level;
1535*4887Schin 	Push_t*		psp = 0;
1536*4887Schin 
1537*4887Schin  again:
1538*4887Schin 	if ((c = *p) == GO)
1539*4887Schin 	{
1540*4887Schin 		for (;;)
1541*4887Schin 		{
1542*4887Schin 			while (*(p = next(p + 1, version)) == '\n');
1543*4887Schin 			if (*p == GO)
1544*4887Schin 			{
1545*4887Schin 				if (level > 1)
1546*4887Schin 					level++;
1547*4887Schin 				level++;
1548*4887Schin 			}
1549*4887Schin 			else if (*p != OG)
1550*4887Schin 			{
1551*4887Schin 				if (level <= 1 || *p != '[' || *(p + 1) != '-')
1552*4887Schin 					break;
1553*4887Schin 				p = skip(p, 0, 0, 0, 1, level, 0, version);
1554*4887Schin 			}
1555*4887Schin 			else if ((level -= 2) <= lev)
1556*4887Schin 				return p + 1;
1557*4887Schin 		}
1558*4887Schin 		if (*p == '\f')
1559*4887Schin 		{
1560*4887Schin 			psp = info(psp, p + 1, NiL, ip);
1561*4887Schin 			if (psp->nb)
1562*4887Schin 				p = psp->nb;
1563*4887Schin 			else
1564*4887Schin 			{
1565*4887Schin 				p = psp->ob;
1566*4887Schin 				psp = psp->next;
1567*4887Schin 			}
1568*4887Schin 		}
1569*4887Schin 		if (*p != '[')
1570*4887Schin 			return p;
1571*4887Schin 		c = *++p;
1572*4887Schin 		if (level > 1)
1573*4887Schin 			level++;
1574*4887Schin 		level++;
1575*4887Schin 	}
1576*4887Schin 	if (c == '-' && level > 1)
1577*4887Schin 		return skip(p, 0, 0, 0, 1, level, 1, version);
1578*4887Schin 	if (c == '+' || c == '-' && (bump = 3) || c != ' ' && level > 1)
1579*4887Schin 	{
1580*4887Schin 		p = skip(t = p + 1, '?', 0, 0, 1, level, 0, version);
1581*4887Schin 		if (c == '-' && (*t == '?' || *t >= '0' && *t <= '9'))
1582*4887Schin 		{
1583*4887Schin 			if ((c = *p) != '?')
1584*4887Schin 				return skip(p, 0, 0, 0, 1, level, 1, version);
1585*4887Schin 			par = item(sp, C("version"), level, style, ip, version, ID);
1586*4887Schin 			for (;;)
1587*4887Schin 			{
1588*4887Schin 				while (isspace(*(p + 1)))
1589*4887Schin 					p++;
1590*4887Schin 				e = p;
1591*4887Schin 				if (e[1] == '@' && e[2] == '(' && e[3] == '#' && e[4] == ')')
1592*4887Schin 					p = e + 4;
1593*4887Schin 				else if (e[1] == '$' && e[2] == 'I' && e[3] == 'd' && e[4] == ':' && e[5] == ' ')
1594*4887Schin 				{
1595*4887Schin 					p = e + 5;
1596*4887Schin 					ident = 1;
1597*4887Schin 				}
1598*4887Schin 				else
1599*4887Schin 					break;
1600*4887Schin 			}
1601*4887Schin 		}
1602*4887Schin 		else
1603*4887Schin 		{
1604*4887Schin 			if (isdigit(c) && isdigit(*t))
1605*4887Schin 			{
1606*4887Schin 				while (isdigit(*t))
1607*4887Schin 					t++;
1608*4887Schin 				if (*t == ':')
1609*4887Schin 					t++;
1610*4887Schin 			}
1611*4887Schin 			else if (isalnum(c) && *t-- == ':')
1612*4887Schin 			{
1613*4887Schin 				if (X(catalog) || *t == *(t + 2))
1614*4887Schin 					t += 2;
1615*4887Schin 				else
1616*4887Schin 				{
1617*4887Schin 					sfprintf(ip, "%s", t);
1618*4887Schin 					if (e = sfstruse(ip))
1619*4887Schin 						*((t = e) + 1) = '|';
1620*4887Schin 				}
1621*4887Schin 			}
1622*4887Schin 			par = item(sp, t, level, style, ip, version, catalog);
1623*4887Schin 			c = *p;
1624*4887Schin 		}
1625*4887Schin 		if (level)
1626*4887Schin 			par = 0;
1627*4887Schin 	}
1628*4887Schin 	else
1629*4887Schin 	{
1630*4887Schin 		if (style >= STYLE_nroff)
1631*4887Schin 			sfputc(sp, '\n');
1632*4887Schin 		else if (c == '?')
1633*4887Schin 			for (n = 0; n < level; n++)
1634*4887Schin 				sfputc(sp, '\t');
1635*4887Schin 		par = 0;
1636*4887Schin 	}
1637*4887Schin 	if (c == ':')
1638*4887Schin 		c = *(p = skip(p, '?', 0, 0, 1, 0, 0, version));
1639*4887Schin 	if ((c == ']' || c == '?' && *(p + 1) == ']' && *(p + 2) != ']' && p++) && (c = *(p = next(p + 1, version))) == GO)
1640*4887Schin 		p = textout(sp, p, style, level + bump + par + 1, 0, ip, version, catalog);
1641*4887Schin 	else if (c == '?' || c == ' ')
1642*4887Schin 	{
1643*4887Schin 		p++;
1644*4887Schin 		if (c == ' ')
1645*4887Schin 			sfputc(sp, c);
1646*4887Schin 		else
1647*4887Schin 		{
1648*4887Schin 			if (X(catalog) && (tsp = localize(psp, p, NiL, 0, 1, catalog, version, ip)))
1649*4887Schin 			{
1650*4887Schin 				psp = tsp;
1651*4887Schin 				p = psp->nb;
1652*4887Schin 			}
1653*4887Schin 			if (style < STYLE_nroff)
1654*4887Schin 				for (n = 0; n < bump + 1; n++)
1655*4887Schin 					sfputc(sp, '\t');
1656*4887Schin 		}
1657*4887Schin 		f = 0;
1658*4887Schin 		for (;;)
1659*4887Schin 		{
1660*4887Schin 			switch (c = *p++)
1661*4887Schin 			{
1662*4887Schin 			case 0:
1663*4887Schin 				if (!(tsp = psp))
1664*4887Schin 				{
1665*4887Schin 					if (f)
1666*4887Schin 						sfputr(sp, font(f, style, 0), -1);
1667*4887Schin 					return p - 1;
1668*4887Schin 				}
1669*4887Schin 				p = psp->ob;
1670*4887Schin 				psp = psp->next;
1671*4887Schin 				free(tsp);
1672*4887Schin 				continue;
1673*4887Schin 			case ']':
1674*4887Schin 				if (psp && psp->ch)
1675*4887Schin 					break;
1676*4887Schin 				if (*p != ']')
1677*4887Schin 				{
1678*4887Schin 					if (f)
1679*4887Schin 					{
1680*4887Schin 						sfputr(sp, font(f, style, 0), -1);
1681*4887Schin 						f = 0;
1682*4887Schin 					}
1683*4887Schin 					for (;;)
1684*4887Schin 					{
1685*4887Schin 						if ((*p == '#' || *p == ':') && level > lev)
1686*4887Schin 						{
1687*4887Schin 							char*	o;
1688*4887Schin 							char*	v;
1689*4887Schin 							int	j;
1690*4887Schin 							int	m;
1691*4887Schin 							int	ol;
1692*4887Schin 							int	vl;
1693*4887Schin 
1694*4887Schin 							a = 0;
1695*4887Schin 							o = 0;
1696*4887Schin 							v = 0;
1697*4887Schin 							if (*++p == '?' || *p == *(p - 1))
1698*4887Schin 							{
1699*4887Schin 								p++;
1700*4887Schin 								a |= OPT_optional;
1701*4887Schin 							}
1702*4887Schin 							if (*(p = next(p, version)) == '[')
1703*4887Schin 							{
1704*4887Schin 								p = skip(p + 1, ':', '?', 0, 1, 0, 0, version);
1705*4887Schin 								while (*p == ':')
1706*4887Schin 								{
1707*4887Schin 									p = skip(t = p + 1, ':', '?', 0, 1, 0, 0, version);
1708*4887Schin 									m = p - t;
1709*4887Schin 									if (*t == '!')
1710*4887Schin 									{
1711*4887Schin 										o = t + 1;
1712*4887Schin 										ol = m - 1;
1713*4887Schin 									}
1714*4887Schin 									else if (*t == '=')
1715*4887Schin 									{
1716*4887Schin 										v = t + 1;
1717*4887Schin 										vl = m - 1;
1718*4887Schin 									}
1719*4887Schin 									else
1720*4887Schin 										for (j = 0; j < elementsof(attrs); j++)
1721*4887Schin 											if (strneq(t, attrs[j].name, m))
1722*4887Schin 											{
1723*4887Schin 												a |= attrs[j].flag;
1724*4887Schin 												break;
1725*4887Schin 											}
1726*4887Schin 								}
1727*4887Schin 							}
1728*4887Schin 							if (a & OPT_optional)
1729*4887Schin 							{
1730*4887Schin 								if (o)
1731*4887Schin 								{
1732*4887Schin 									sfprintf(sp, " %s ", T(NiL, ID, "If the option value is omitted then"));
1733*4887Schin 									sfputr(sp, font(FONT_BOLD, style, 1), -1);
1734*4887Schin 									t = o + ol;
1735*4887Schin 									while (o < t)
1736*4887Schin 									{
1737*4887Schin 										if (((c = *o++) == ':' || c == '?') && *o == c)
1738*4887Schin 											o++;
1739*4887Schin 										sfputc(sp, c);
1740*4887Schin 									}
1741*4887Schin 									sfputr(sp, font(FONT_BOLD, style, 0), -1);
1742*4887Schin 									sfprintf(sp, " %s.", T(NiL, ID, "is assumed"));
1743*4887Schin 								}
1744*4887Schin 								else
1745*4887Schin 									sfprintf(sp, " %s", T(NiL, ID, "The option value may be omitted."));
1746*4887Schin 							}
1747*4887Schin 							if (v)
1748*4887Schin 							{
1749*4887Schin 								sfprintf(sp, " %s ", T(NiL, ID, "The default value is"));
1750*4887Schin 								sfputr(sp, font(FONT_BOLD, style, 1), -1);
1751*4887Schin 								t = v + vl;
1752*4887Schin 								while (v < t)
1753*4887Schin 								{
1754*4887Schin 									if (((c = *v++) == ':' || c == '?') && *v == c)
1755*4887Schin 										v++;
1756*4887Schin 									sfputc(sp, c);
1757*4887Schin 								}
1758*4887Schin 								sfputr(sp, font(FONT_BOLD, style, 0), -1);
1759*4887Schin 								sfputc(sp, '.');
1760*4887Schin 							}
1761*4887Schin 							p = skip(p, 0, 0, 0, 1, 0, 1, version);
1762*4887Schin 						}
1763*4887Schin 						if (*(p = next(p, version)) == GO)
1764*4887Schin 							p = textout(sp, p, style, level + bump + !level, 0, ip, version, catalog);
1765*4887Schin 						else if (*p == '[' && level > lev)
1766*4887Schin 						{
1767*4887Schin 							p++;
1768*4887Schin 							goto again;
1769*4887Schin 						}
1770*4887Schin 						else if (*p == '\f')
1771*4887Schin 						{
1772*4887Schin 							p++;
1773*4887Schin 							if (style != STYLE_keys)
1774*4887Schin 							{
1775*4887Schin 								psp = info(psp, p, NiL, ip);
1776*4887Schin 								if (psp->nb)
1777*4887Schin 									p = psp->nb;
1778*4887Schin 								else
1779*4887Schin 								{
1780*4887Schin 									p = psp->ob;
1781*4887Schin 									psp = psp->next;
1782*4887Schin 								}
1783*4887Schin 							}
1784*4887Schin 						}
1785*4887Schin 						else if (!*p)
1786*4887Schin 						{
1787*4887Schin 							if (!(tsp = psp))
1788*4887Schin 								break;
1789*4887Schin 							p = psp->ob;
1790*4887Schin 							psp = psp->next;
1791*4887Schin 							free(tsp);
1792*4887Schin 						}
1793*4887Schin 						else if (*p != OG)
1794*4887Schin 							break;
1795*4887Schin 						else
1796*4887Schin 						{
1797*4887Schin 							p++;
1798*4887Schin 							if ((level -= 2) <= lev)
1799*4887Schin 								break;
1800*4887Schin 						}
1801*4887Schin 					}
1802*4887Schin 					return p;
1803*4887Schin 				}
1804*4887Schin 				p++;
1805*4887Schin 				break;
1806*4887Schin 			case '\a':
1807*4887Schin 				a = FONT_ITALIC;
1808*4887Schin 			setfont:
1809*4887Schin 				if (f & ~a)
1810*4887Schin 				{
1811*4887Schin 					sfputr(sp, font(f, style, 0), -1);
1812*4887Schin 					f = 0;
1813*4887Schin 				}
1814*4887Schin 				if (!f && style == STYLE_html)
1815*4887Schin 				{
1816*4887Schin 					for (t = p; *t && !isspace(*t) && !iscntrl(*t); t++);
1817*4887Schin 					if (*t == c && *++t == '(')
1818*4887Schin 					{
1819*4887Schin 						e = t;
1820*4887Schin 						while (isdigit(*++t));
1821*4887Schin 						if (*t == ')' && t > e + 1)
1822*4887Schin 						{
1823*4887Schin 							sfprintf(sp, "<NOBR><A href=\"../man%-.*s/%-.*s.html\">%s%-.*s%s</A>%-.*s</NOBR>"
1824*4887Schin 								, t - e - 1, e + 1
1825*4887Schin 								, e - p - 1, p
1826*4887Schin 								, font(a, style, 1)
1827*4887Schin 								, e - p - 1, p
1828*4887Schin 								, font(a, style, 0)
1829*4887Schin 								, t - e + 1, e
1830*4887Schin 								);
1831*4887Schin 							p = t + 1;
1832*4887Schin 							continue;
1833*4887Schin 						}
1834*4887Schin 					}
1835*4887Schin 				}
1836*4887Schin 				sfputr(sp, font(a, style, !!(f ^= a)), -1);
1837*4887Schin 				continue;
1838*4887Schin 			case '\b':
1839*4887Schin 				a = FONT_BOLD;
1840*4887Schin 				goto setfont;
1841*4887Schin 			case '\f':
1842*4887Schin 				if (style != STYLE_keys)
1843*4887Schin 				{
1844*4887Schin 					psp = info(psp, p, NiL, ip);
1845*4887Schin 					if (psp->nb)
1846*4887Schin 						p = psp->nb;
1847*4887Schin 					else
1848*4887Schin 					{
1849*4887Schin 						p = psp->ob;
1850*4887Schin 						psp = psp->next;
1851*4887Schin 					}
1852*4887Schin 				}
1853*4887Schin 				continue;
1854*4887Schin 			case '\v':
1855*4887Schin 				a = FONT_LITERAL;
1856*4887Schin 				goto setfont;
1857*4887Schin 			case ' ':
1858*4887Schin 				if (ident && *p == '$')
1859*4887Schin 				{
1860*4887Schin 					while (*++p)
1861*4887Schin 						if (*p == ']')
1862*4887Schin 						{
1863*4887Schin 							if (*(p + 1) != ']')
1864*4887Schin 								break;
1865*4887Schin 							p++;
1866*4887Schin 						}
1867*4887Schin 					continue;
1868*4887Schin 				}
1869*4887Schin 			case '\n':
1870*4887Schin 			case '\r':
1871*4887Schin 			case '\t':
1872*4887Schin 				while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
1873*4887Schin 					p++;
1874*4887Schin 				if (*p == ']' && *(p + 1) != ']' && (!psp || !psp->ch))
1875*4887Schin 					continue;
1876*4887Schin 				c = ' ';
1877*4887Schin 				break;
1878*4887Schin 			case '<':
1879*4887Schin 				if (style == STYLE_html)
1880*4887Schin 				{
1881*4887Schin 					sfputr(sp, "&lt;", -1);
1882*4887Schin 					c = 0;
1883*4887Schin 					for (t = p; *t; t++)
1884*4887Schin 						if (!isalnum(*t) && *t != '_' && *t != '.' && *t != '-')
1885*4887Schin 						{
1886*4887Schin 							if (*t == '@')
1887*4887Schin 							{
1888*4887Schin 								if (c)
1889*4887Schin 									break;
1890*4887Schin 								c = 1;
1891*4887Schin 							}
1892*4887Schin 							else if (*t == '>')
1893*4887Schin 							{
1894*4887Schin 								if (c)
1895*4887Schin 								{
1896*4887Schin 									sfprintf(sp, "<A href=\"mailto:%-.*s\">%-.*s</A>&gt;", t - p, p, t - p, p);
1897*4887Schin 									p = t + 1;
1898*4887Schin 								}
1899*4887Schin 								break;
1900*4887Schin 							}
1901*4887Schin 							else
1902*4887Schin 								break;
1903*4887Schin 						}
1904*4887Schin 					continue;
1905*4887Schin 				}
1906*4887Schin 				break;
1907*4887Schin 			case '>':
1908*4887Schin 				if (style == STYLE_html)
1909*4887Schin 				{
1910*4887Schin 					sfputr(sp, "&gt;", -1);
1911*4887Schin 					continue;
1912*4887Schin 				}
1913*4887Schin 				break;
1914*4887Schin 			case '&':
1915*4887Schin 				if (style == STYLE_html)
1916*4887Schin 				{
1917*4887Schin 					sfputr(sp, "&amp;", -1);
1918*4887Schin 					continue;
1919*4887Schin 				}
1920*4887Schin 				break;
1921*4887Schin 			case '-':
1922*4887Schin 				if (style == STYLE_nroff)
1923*4887Schin 					sfputc(sp, '\\');
1924*4887Schin 				break;
1925*4887Schin 			case '.':
1926*4887Schin 				if (style == STYLE_nroff)
1927*4887Schin 				{
1928*4887Schin 					sfputc(sp, '\\');
1929*4887Schin 					sfputc(sp, '&');
1930*4887Schin 				}
1931*4887Schin 				break;
1932*4887Schin 			case '\\':
1933*4887Schin 				if (style == STYLE_nroff)
1934*4887Schin 				{
1935*4887Schin 					sfputc(sp, c);
1936*4887Schin 					c = 'e';
1937*4887Schin 				}
1938*4887Schin 				break;
1939*4887Schin 			}
1940*4887Schin 			sfputc(sp, c);
1941*4887Schin 		}
1942*4887Schin 	}
1943*4887Schin 	else if (c == '[' && level > lev)
1944*4887Schin 	{
1945*4887Schin 		p++;
1946*4887Schin 		goto again;
1947*4887Schin 	}
1948*4887Schin 	return p;
1949*4887Schin }
1950*4887Schin 
1951*4887Schin /*
1952*4887Schin  * generate optget() help [...] list from lp
1953*4887Schin  */
1954*4887Schin 
1955*4887Schin static void
1956*4887Schin list(Sfio_t* sp, register const List_t* lp)
1957*4887Schin {
1958*4887Schin 	sfprintf(sp, "[%c", lp->type);
1959*4887Schin 	if (lp->name)
1960*4887Schin 	{
1961*4887Schin 		sfprintf(sp, "%s", lp->name);
1962*4887Schin 		if (lp->text)
1963*4887Schin 			sfprintf(sp, "?%s", lp->text);
1964*4887Schin 	}
1965*4887Schin 	sfputc(sp, ']');
1966*4887Schin }
1967*4887Schin 
1968*4887Schin /*
1969*4887Schin  * return pointer to help message sans `Usage: command'
1970*4887Schin  * if oopts is 0 then opt_info.state->pass is used
1971*4887Schin  * what:
1972*4887Schin  *	0	?short by default, ?long if any long options used
1973*4887Schin  *	*	otherwise see help_text[] (--???)
1974*4887Schin  * external formatter:
1975*4887Schin  *	\a...\a	italic
1976*4887Schin  *	\b...\b	bold
1977*4887Schin  *	\f...\f	discipline infof callback on ...
1978*4887Schin  *	\v...\v	literal
1979*4887Schin  * internal formatter:
1980*4887Schin  *	\t	indent
1981*4887Schin  *	\n	newline
1982*4887Schin  * margin flush pops to previous indent
1983*4887Schin  */
1984*4887Schin 
1985*4887Schin char*
1986*4887Schin opthelp(const char* oopts, const char* what)
1987*4887Schin {
1988*4887Schin 	register Sfio_t*	sp;
1989*4887Schin 	register Sfio_t*	mp;
1990*4887Schin 	register int		c;
1991*4887Schin 	register char*		p;
1992*4887Schin 	register Indent_t*	ip;
1993*4887Schin 	char*			t;
1994*4887Schin 	char*			x;
1995*4887Schin 	char*			w;
1996*4887Schin 	char*			u;
1997*4887Schin 	char*			y;
1998*4887Schin 	char*			s;
1999*4887Schin 	char*			d;
2000*4887Schin 	char*			v;
2001*4887Schin 	char*			ov;
2002*4887Schin 	char*			name;
2003*4887Schin 	char*			pp;
2004*4887Schin 	char*			rb;
2005*4887Schin 	char*			re;
2006*4887Schin 	int			f;
2007*4887Schin 	int			i;
2008*4887Schin 	int			j;
2009*4887Schin 	int			m;
2010*4887Schin 	int			n;
2011*4887Schin 	int			a;
2012*4887Schin 	int			sl;
2013*4887Schin 	int			vl;
2014*4887Schin 	int			ol;
2015*4887Schin 	int			wl;
2016*4887Schin 	int			xl;
2017*4887Schin 	int			rm;
2018*4887Schin 	int			ts;
2019*4887Schin 	int			co;
2020*4887Schin 	int			z;
2021*4887Schin 	int			style;
2022*4887Schin 	int			head;
2023*4887Schin 	int			mode;
2024*4887Schin 	int			mutex;
2025*4887Schin 	int			prefix;
2026*4887Schin 	int			version;
2027*4887Schin 	long			tp;
2028*4887Schin 	char*			catalog;
2029*4887Schin 	Optpass_t*		o;
2030*4887Schin 	Optpass_t*		q;
2031*4887Schin 	Optpass_t*		e;
2032*4887Schin 	Optpass_t		one;
2033*4887Schin 	Help_t*			hp;
2034*4887Schin 	short			ptstk[elementsof(indent) + 2];
2035*4887Schin 	short*			pt;
2036*4887Schin 	Sfio_t*			vp;
2037*4887Schin 	Push_t*			tsp;
2038*4887Schin 
2039*4887Schin 	char*			opts = (char*)oopts;
2040*4887Schin 	int			flags = 0;
2041*4887Schin 	int			matched = 0;
2042*4887Schin 	int			paragraph = 0;
2043*4887Schin 	int			section = 1;
2044*4887Schin 	Push_t*			psp = 0;
2045*4887Schin 	Sfio_t*			sp_help = 0;
2046*4887Schin 	Sfio_t*			sp_text = 0;
2047*4887Schin 	Sfio_t*			sp_plus = 0;
2048*4887Schin 	Sfio_t*			sp_head = 0;
2049*4887Schin 	Sfio_t*			sp_body = 0;
2050*4887Schin 	Sfio_t*			sp_info = 0;
2051*4887Schin 	Sfio_t*			sp_misc = 0;
2052*4887Schin 
2053*4887Schin 	if (!(mp = opt_info.state->mp) && !(mp = opt_info.state->mp = sfstropen()))
2054*4887Schin 		goto nospace;
2055*4887Schin 	if (!what)
2056*4887Schin 		style = opt_info.state->style;
2057*4887Schin 	else if (!*what)
2058*4887Schin 		style = STYLE_options;
2059*4887Schin 	else if (*what != '?')
2060*4887Schin 		style = STYLE_match;
2061*4887Schin 	else if (!*(what + 1))
2062*4887Schin 		style = STYLE_man;
2063*4887Schin 	else if ((hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), (char*)what + 1)) && hp->style >= 0)
2064*4887Schin 	{
2065*4887Schin 		style = hp->style;
2066*4887Schin 		if (*hp->name != '?')
2067*4887Schin 			what = hp->name;
2068*4887Schin 	}
2069*4887Schin 	else
2070*4887Schin 	{
2071*4887Schin 		if ((style = opt_info.state->force) < STYLE_man)
2072*4887Schin 			style = STYLE_man;
2073*4887Schin 		if (!(sp_help = sfstropen()))
2074*4887Schin 			goto nospace;
2075*4887Schin 		for (i = 0; i < elementsof(help_head); i++)
2076*4887Schin 			list(sp_help, &help_head[i]);
2077*4887Schin 		for (i = 0; i < elementsof(styles); i++)
2078*4887Schin 			sfprintf(sp_help, "[:%s?%s]", styles[i].match, styles[i].text);
2079*4887Schin 		for (i = 0; i < elementsof(help_tail); i++)
2080*4887Schin 			list(sp_help, &help_tail[i]);
2081*4887Schin 		if (!(opts = sfstruse(sp_help)))
2082*4887Schin 			goto nospace;
2083*4887Schin 	}
2084*4887Schin 	message((-20, "AHA#%d style=%d", __LINE__, style));
2085*4887Schin  again:
2086*4887Schin 	if (opts)
2087*4887Schin 	{
2088*4887Schin 		for (i = 0; i < opt_info.state->npass; i++)
2089*4887Schin 			if (opt_info.state->pass[i].oopts == opts)
2090*4887Schin 			{
2091*4887Schin 				o = &opt_info.state->pass[i];
2092*4887Schin 				break;
2093*4887Schin 			}
2094*4887Schin 		if (i >= opt_info.state->npass)
2095*4887Schin 		{
2096*4887Schin 			o = &one;
2097*4887Schin 			if (init((char*)opts, o))
2098*4887Schin 				goto nospace;
2099*4887Schin 		}
2100*4887Schin 		e = o + 1;
2101*4887Schin 	}
2102*4887Schin 	else if (opt_info.state->npass > 0)
2103*4887Schin 	{
2104*4887Schin 		o = opt_info.state->pass;
2105*4887Schin 		e = o + opt_info.state->npass;
2106*4887Schin 	}
2107*4887Schin 	else if (opt_info.state->npass < 0)
2108*4887Schin 	{
2109*4887Schin 		o = &opt_info.state->cache->pass;
2110*4887Schin 		e = o + 1;
2111*4887Schin 	}
2112*4887Schin 	else
2113*4887Schin 		return T(NiL, ID, "[* call optget() before opthelp() *]");
2114*4887Schin 	if (style < STYLE_usage)
2115*4887Schin 	{
2116*4887Schin 		if (!(sp_text = sfstropen()) || !(sp_info = sfstropen()))
2117*4887Schin 			goto nospace;
2118*4887Schin 		if (style >= STYLE_match && style < STYLE_keys && !(sp_body = sfstropen()))
2119*4887Schin 			goto nospace;
2120*4887Schin 	}
2121*4887Schin 	switch (style)
2122*4887Schin 	{
2123*4887Schin 	case STYLE_api:
2124*4887Schin 	case STYLE_html:
2125*4887Schin 	case STYLE_nroff:
2126*4887Schin 		opt_info.state->emphasis = 0;
2127*4887Schin 		break;
2128*4887Schin 	case STYLE_usage:
2129*4887Schin 	case STYLE_keys:
2130*4887Schin 		for (q = o; q < e; q++)
2131*4887Schin 			if (!(q->flags & OPT_ignore) && !streq(q->catalog, o->catalog))
2132*4887Schin 				o = q;
2133*4887Schin 		/*FALLTHROUGH*/
2134*4887Schin 	case STYLE_posix:
2135*4887Schin 		sfputc(mp, '\f');
2136*4887Schin 		break;
2137*4887Schin 	default:
2138*4887Schin 		if (!opt_info.state->emphasis)
2139*4887Schin 		{
2140*4887Schin 			if (x = getenv("ERROR_OPTIONS"))
2141*4887Schin 			{
2142*4887Schin 				if (strmatch(x, "*noemphasi*"))
2143*4887Schin 					break;
2144*4887Schin 				if (strmatch(x, "*emphasi*"))
2145*4887Schin 				{
2146*4887Schin 					opt_info.state->emphasis = 1;
2147*4887Schin 					break;
2148*4887Schin 				}
2149*4887Schin 			}
2150*4887Schin 			if ((x = getenv("TERM")) && strmatch(x, "(ansi|vt100|xterm)*") && isatty(sffileno(sfstderr)))
2151*4887Schin 				opt_info.state->emphasis = 1;
2152*4887Schin 		}
2153*4887Schin 		break;
2154*4887Schin 	}
2155*4887Schin 	x = "";
2156*4887Schin 	xl = 0;
2157*4887Schin 	for (q = o; q < e; q++)
2158*4887Schin 	{
2159*4887Schin 		if (q->flags & OPT_ignore)
2160*4887Schin 			continue;
2161*4887Schin 		if (section < q->section)
2162*4887Schin 			section = q->section;
2163*4887Schin 		section = q->section;
2164*4887Schin 		flags |= q->flags;
2165*4887Schin 		p = q->opts;
2166*4887Schin 		prefix = q->prefix;
2167*4887Schin 		version = q->version;
2168*4887Schin 		catalog = q->catalog;
2169*4887Schin 		switch (style)
2170*4887Schin 		{
2171*4887Schin 		case STYLE_usage:
2172*4887Schin 			if (xl)
2173*4887Schin 				sfputc(mp, '\n');
2174*4887Schin 			else
2175*4887Schin 				xl = 1;
2176*4887Schin 			while (c = *p++)
2177*4887Schin 			{
2178*4887Schin 				switch (c)
2179*4887Schin 				{
2180*4887Schin 				case '\a':
2181*4887Schin 					c = 'a';
2182*4887Schin 					break;
2183*4887Schin 				case '\b':
2184*4887Schin 					c = 'b';
2185*4887Schin 					break;
2186*4887Schin 				case '\f':
2187*4887Schin 					c = 'f';
2188*4887Schin 					break;
2189*4887Schin 				case '\n':
2190*4887Schin 					c = 'n';
2191*4887Schin 					break;
2192*4887Schin 				case '\r':
2193*4887Schin 					c = 'r';
2194*4887Schin 					break;
2195*4887Schin 				case '\t':
2196*4887Schin 					c = 't';
2197*4887Schin 					break;
2198*4887Schin 				case '\v':
2199*4887Schin 					c = 'v';
2200*4887Schin 					break;
2201*4887Schin 				case '"':
2202*4887Schin 					c = '"';
2203*4887Schin 					break;
2204*4887Schin 				case '\'':
2205*4887Schin 					c = '\'';
2206*4887Schin 					break;
2207*4887Schin 				case '\\':
2208*4887Schin 					c = '\\';
2209*4887Schin 					break;
2210*4887Schin 				default:
2211*4887Schin 					sfputc(mp, c);
2212*4887Schin 					continue;
2213*4887Schin 				}
2214*4887Schin 				sfputc(mp, '\\');
2215*4887Schin 				sfputc(mp, c);
2216*4887Schin 			}
2217*4887Schin 			continue;
2218*4887Schin 		case STYLE_keys:
2219*4887Schin 			a = 0;
2220*4887Schin 			psp = 0;
2221*4887Schin 			vl = 0;
2222*4887Schin 			for (;;)
2223*4887Schin 			{
2224*4887Schin 				if (!(c = *p++))
2225*4887Schin 				{
2226*4887Schin 					if (!(tsp = psp))
2227*4887Schin 						break;
2228*4887Schin 					p = psp->ob;
2229*4887Schin 					psp = psp->next;
2230*4887Schin 					free(tsp);
2231*4887Schin 					continue;
2232*4887Schin 				}
2233*4887Schin 				if (c == '\f')
2234*4887Schin 				{
2235*4887Schin 					psp = info(psp, p, NiL, sp_info);
2236*4887Schin 					if (psp->nb)
2237*4887Schin 						p = psp->nb;
2238*4887Schin 					else
2239*4887Schin 					{
2240*4887Schin 						p = psp->ob;
2241*4887Schin 						psp = psp->next;
2242*4887Schin 					}
2243*4887Schin 					continue;
2244*4887Schin 				}
2245*4887Schin 				f = z = 1;
2246*4887Schin 				t = 0;
2247*4887Schin 				if (a == 0 && (c == ' ' || c == '\n' && *p == '\n'))
2248*4887Schin 				{
2249*4887Schin 					if (c == ' ' && *p == ']')
2250*4887Schin 					{
2251*4887Schin 						p++;
2252*4887Schin 						continue;
2253*4887Schin 					}
2254*4887Schin 					if (*p == '\n')
2255*4887Schin 						p++;
2256*4887Schin 					a = c;
2257*4887Schin 				}
2258*4887Schin 				else if (c == '\n')
2259*4887Schin 				{
2260*4887Schin 					if (a == ' ')
2261*4887Schin 						a = -1;
2262*4887Schin 					else if (a == '\n' || *p == '\n')
2263*4887Schin 					{
2264*4887Schin 						a = -1;
2265*4887Schin 						p++;
2266*4887Schin 					}
2267*4887Schin 					continue;
2268*4887Schin 				}
2269*4887Schin 				else if ((c == ':' || c == '#') && (*p == '[' || *p == '?' && *(p + 1) == '[' && p++))
2270*4887Schin 					p++;
2271*4887Schin 				else if (c != '[')
2272*4887Schin 				{
2273*4887Schin 					if (c == '{')
2274*4887Schin 						vl++;
2275*4887Schin 					else if (c == '}')
2276*4887Schin 						vl--;
2277*4887Schin 					continue;
2278*4887Schin 				}
2279*4887Schin 				else if (*p == ' ')
2280*4887Schin 				{
2281*4887Schin 					p++;
2282*4887Schin 					continue;
2283*4887Schin 				}
2284*4887Schin 				else if (*p == '-')
2285*4887Schin 				{
2286*4887Schin 					z = 0;
2287*4887Schin 					if (*++p == '-')
2288*4887Schin 					{
2289*4887Schin 						p = skip(p, 0, 0, 0, 1, 0, 1, version);
2290*4887Schin 						continue;
2291*4887Schin 					}
2292*4887Schin 				}
2293*4887Schin 				else if (*p == '+')
2294*4887Schin 				{
2295*4887Schin 					p++;
2296*4887Schin 					if (vl > 0 && *p != '\a')
2297*4887Schin 					{
2298*4887Schin 						f = 0;
2299*4887Schin 						p = skip(p, '?', 0, 0, 1, 0, 0, version);
2300*4887Schin 						if (*p == '?')
2301*4887Schin 							p++;
2302*4887Schin 					}
2303*4887Schin 				}
2304*4887Schin 				else
2305*4887Schin 				{
2306*4887Schin 					if (*(p + 1) == '\f' && (vp = opt_info.state->vp))
2307*4887Schin 						p = expand(p + 2, NiL, &t, vp);
2308*4887Schin 					p = skip(p, ':', '?', 0, 1, 0, 0, version);
2309*4887Schin 					if (*p == ':')
2310*4887Schin 						p++;
2311*4887Schin 				}
2312*4887Schin 				if (f && *p == '?' && *(p + 1) != '?')
2313*4887Schin 				{
2314*4887Schin 					f = 0;
2315*4887Schin 					if (z)
2316*4887Schin 						p++;
2317*4887Schin 					else
2318*4887Schin 						p = skip(p, 0, 0, 0, 1, 0, 0, version);
2319*4887Schin 				}
2320*4887Schin 				if (*p == ']' && *(p + 1) != ']')
2321*4887Schin 				{
2322*4887Schin 					p++;
2323*4887Schin 					continue;
2324*4887Schin 				}
2325*4887Schin 				if (!*p)
2326*4887Schin 				{
2327*4887Schin 					if (!t)
2328*4887Schin 						break;
2329*4887Schin 					p = t;
2330*4887Schin 					t = 0;
2331*4887Schin 				}
2332*4887Schin 				m = sfstrtell(mp);
2333*4887Schin 				sfputc(mp, '"');
2334*4887Schin 				xl = 1;
2335*4887Schin 				/*UNDENT...*/
2336*4887Schin 
2337*4887Schin 	for (;;)
2338*4887Schin 	{
2339*4887Schin 		if (!(c = *p++))
2340*4887Schin 		{
2341*4887Schin 			if (t)
2342*4887Schin 			{
2343*4887Schin 				p = t;
2344*4887Schin 				t = 0;
2345*4887Schin 			}
2346*4887Schin 			if (!(tsp = psp))
2347*4887Schin 			{
2348*4887Schin 				p--;
2349*4887Schin 				break;
2350*4887Schin 			}
2351*4887Schin 			p = psp->ob;
2352*4887Schin 			psp = psp->next;
2353*4887Schin 			free(tsp);
2354*4887Schin 			continue;
2355*4887Schin 		}
2356*4887Schin 		if (a > 0)
2357*4887Schin 		{
2358*4887Schin 			if (c == '\n')
2359*4887Schin 			{
2360*4887Schin 				if (a == ' ')
2361*4887Schin 				{
2362*4887Schin 					a = -1;
2363*4887Schin 					break;
2364*4887Schin 				}
2365*4887Schin 				if (a == '\n' || *p == '\n')
2366*4887Schin 				{
2367*4887Schin 					a = -1;
2368*4887Schin 					p++;
2369*4887Schin 					break;
2370*4887Schin 				}
2371*4887Schin 			}
2372*4887Schin 		}
2373*4887Schin 		else if (c == ']')
2374*4887Schin 		{
2375*4887Schin 			if (*p != ']')
2376*4887Schin 			{
2377*4887Schin 				sfputc(mp, 0);
2378*4887Schin 				y = sfstrbase(mp) + m + 1;
2379*4887Schin 				if (D(y) || !strmatch(y, KEEP) || strmatch(y, OMIT))
2380*4887Schin 				{
2381*4887Schin 					sfstrseek(mp, m, SEEK_SET);
2382*4887Schin 					xl = 0;
2383*4887Schin 				}
2384*4887Schin 				else
2385*4887Schin 					sfstrseek(mp, -1, SEEK_CUR);
2386*4887Schin 				break;
2387*4887Schin 			}
2388*4887Schin 			sfputc(mp, *p++);
2389*4887Schin 			continue;
2390*4887Schin 		}
2391*4887Schin 		switch (c)
2392*4887Schin 		{
2393*4887Schin 		case '?':
2394*4887Schin 			if (f)
2395*4887Schin 			{
2396*4887Schin 				if (*p == '?')
2397*4887Schin 				{
2398*4887Schin 					p++;
2399*4887Schin 					sfputc(mp, c);
2400*4887Schin 				}
2401*4887Schin 				else
2402*4887Schin 				{
2403*4887Schin 					f = 0;
2404*4887Schin 					sfputc(mp, 0);
2405*4887Schin 					y = sfstrbase(mp) + m + 1;
2406*4887Schin 					if (D(y) || !strmatch(y, KEEP) || strmatch(y, OMIT))
2407*4887Schin 					{
2408*4887Schin 						sfstrseek(mp, m, SEEK_SET);
2409*4887Schin 						xl = 0;
2410*4887Schin 					}
2411*4887Schin 					else
2412*4887Schin 						sfstrseek(mp, -1, SEEK_CUR);
2413*4887Schin 					if (z && (*p != ']' || *(p + 1) == ']'))
2414*4887Schin 					{
2415*4887Schin 						if (xl)
2416*4887Schin 						{
2417*4887Schin 							sfputc(mp, '"');
2418*4887Schin 							sfputc(mp, '\n');
2419*4887Schin 						}
2420*4887Schin 						m = sfstrtell(mp);
2421*4887Schin 						sfputc(mp, '"');
2422*4887Schin 						xl = 1;
2423*4887Schin 					}
2424*4887Schin 					else
2425*4887Schin 					{
2426*4887Schin 						p = skip(p, 0, 0, 0, 1, 0, 0, version);
2427*4887Schin 						if (*p == '?')
2428*4887Schin 							p++;
2429*4887Schin 					}
2430*4887Schin 				}
2431*4887Schin 			}
2432*4887Schin 			else
2433*4887Schin 				sfputc(mp, c);
2434*4887Schin 			continue;
2435*4887Schin 		case ':':
2436*4887Schin 			if (f && *p == ':')
2437*4887Schin 				p++;
2438*4887Schin 			sfputc(mp, c);
2439*4887Schin 			continue;
2440*4887Schin 		case '\a':
2441*4887Schin 			c = 'a';
2442*4887Schin 			break;
2443*4887Schin 		case '\b':
2444*4887Schin 			c = 'b';
2445*4887Schin 			break;
2446*4887Schin 		case '\f':
2447*4887Schin 			c = 'f';
2448*4887Schin 			break;
2449*4887Schin 		case '\n':
2450*4887Schin 			c = 'n';
2451*4887Schin 			break;
2452*4887Schin 		case '\r':
2453*4887Schin 			c = 'r';
2454*4887Schin 			break;
2455*4887Schin 		case '\t':
2456*4887Schin 			c = 't';
2457*4887Schin 			break;
2458*4887Schin 		case '\v':
2459*4887Schin 			c = 'v';
2460*4887Schin 			break;
2461*4887Schin 		case '"':
2462*4887Schin 			c = '"';
2463*4887Schin 			break;
2464*4887Schin 		case '\\':
2465*4887Schin 			c = '\\';
2466*4887Schin 			break;
2467*4887Schin 		case CC_esc:
2468*4887Schin 			c = 'E';
2469*4887Schin 			break;
2470*4887Schin 		default:
2471*4887Schin 			sfputc(mp, c);
2472*4887Schin 			continue;
2473*4887Schin 		}
2474*4887Schin 		sfputc(mp, '\\');
2475*4887Schin 		sfputc(mp, c);
2476*4887Schin 	}
2477*4887Schin 
2478*4887Schin 				/*...INDENT*/
2479*4887Schin 				if (xl)
2480*4887Schin 				{
2481*4887Schin 					sfputc(mp, '"');
2482*4887Schin 					sfputc(mp, '\n');
2483*4887Schin 				}
2484*4887Schin 			}
2485*4887Schin 			continue;
2486*4887Schin 		}
2487*4887Schin 		z = 0;
2488*4887Schin 		head = 0;
2489*4887Schin 		mode = 0;
2490*4887Schin 		mutex = 0;
2491*4887Schin 		if (style > STYLE_short && style < STYLE_nroff && version < 1)
2492*4887Schin 		{
2493*4887Schin 			style = STYLE_short;
2494*4887Schin 			if (sp_body)
2495*4887Schin 			{
2496*4887Schin 				sfclose(sp_body);
2497*4887Schin 				sp_body = 0;
2498*4887Schin 			}
2499*4887Schin 		}
2500*4887Schin 		else if (style == STYLE_short && prefix < 2)
2501*4887Schin 			style = STYLE_long;
2502*4887Schin 		if (*p == ':')
2503*4887Schin 			p++;
2504*4887Schin 		if (*p == '+')
2505*4887Schin 		{
2506*4887Schin 			p++;
2507*4887Schin 			if (!(sp = sp_plus) && !(sp = sp_plus = sfstropen()))
2508*4887Schin 				goto nospace;
2509*4887Schin 		}
2510*4887Schin 		else if (style >= STYLE_match)
2511*4887Schin 			sp = sp_body;
2512*4887Schin 		else
2513*4887Schin 			sp = sp_text;
2514*4887Schin 		psp = 0;
2515*4887Schin 		for (;;)
2516*4887Schin 		{
2517*4887Schin 			if (!(*(p = next(p, version))))
2518*4887Schin 			{
2519*4887Schin 				if (!(tsp = psp))
2520*4887Schin 					break;
2521*4887Schin 				p = psp->ob;
2522*4887Schin 				psp = psp->next;
2523*4887Schin 				free(tsp);
2524*4887Schin 				continue;
2525*4887Schin 			}
2526*4887Schin 			if (*p == '\f')
2527*4887Schin 			{
2528*4887Schin 				psp = info(psp, p + 1, NiL, sp_info);
2529*4887Schin 				if (psp->nb)
2530*4887Schin 					p = psp->nb;
2531*4887Schin 				else
2532*4887Schin 				{
2533*4887Schin 					p = psp->ob;
2534*4887Schin 					psp = psp->next;
2535*4887Schin 				}
2536*4887Schin 				continue;
2537*4887Schin 			}
2538*4887Schin 			if (*p == '\n' || *p == ' ')
2539*4887Schin 			{
2540*4887Schin 				if (*(x = p = next(p + 1, version)))
2541*4887Schin 					while (*++p)
2542*4887Schin 						if (*p == '\n')
2543*4887Schin 						{
2544*4887Schin 							while (*++p == ' ' || *p == '\t' || *p == '\r');
2545*4887Schin 							if (*p == '\n')
2546*4887Schin 								break;
2547*4887Schin 						}
2548*4887Schin 				xl = p - x;
2549*4887Schin 				if (!*p)
2550*4887Schin 					break;
2551*4887Schin 				continue;
2552*4887Schin 			}
2553*4887Schin 			if (*p == '}')
2554*4887Schin 			{
2555*4887Schin 				p++;
2556*4887Schin 				continue;
2557*4887Schin 			}
2558*4887Schin 			message((-20, "opthelp: opt %s", show(p)));
2559*4887Schin 			if (z < 0)
2560*4887Schin 				z = 0;
2561*4887Schin 			a = 0;
2562*4887Schin 			f = 0;
2563*4887Schin 			w = 0;
2564*4887Schin 			d = 0;
2565*4887Schin 			s = 0;
2566*4887Schin 			sl = 0;
2567*4887Schin 			if (*p == '[')
2568*4887Schin 			{
2569*4887Schin 				if ((c = *(p = next(p + 1, version))) == '-')
2570*4887Schin 				{
2571*4887Schin 					if (style >= STYLE_man)
2572*4887Schin 					{
2573*4887Schin 						if (*(p + 1) != '-')
2574*4887Schin 						{
2575*4887Schin 							if (!sp_misc && !(sp_misc = sfstropen()))
2576*4887Schin 								goto nospace;
2577*4887Schin 							else
2578*4887Schin 								p = textout(sp_misc, p, style, 1, 3, sp_info, version, catalog);
2579*4887Schin 							continue;
2580*4887Schin 						}
2581*4887Schin 					}
2582*4887Schin 					else if (style == STYLE_match && *what == '-')
2583*4887Schin 					{
2584*4887Schin 						if (*(p + 1) == '?' || *(p + 1) >= '0' && *(p + 1) <= '9')
2585*4887Schin 							s = C("version");
2586*4887Schin 						else
2587*4887Schin 							s = p + 1;
2588*4887Schin 						w = (char*)what;
2589*4887Schin 						if (*s != '-' || *(w + 1) == '-')
2590*4887Schin 						{
2591*4887Schin 							if (*s == '-')
2592*4887Schin 								s++;
2593*4887Schin 							if (*(w + 1) == '-')
2594*4887Schin 								w++;
2595*4887Schin 							if (match(w + 1, s, version, catalog))
2596*4887Schin 							{
2597*4887Schin 								if (*(p + 1) == '-')
2598*4887Schin 									p++;
2599*4887Schin 								p = textout(sp, p, style, 1, 3, sp_info, version, catalog);
2600*4887Schin 								matched = -1;
2601*4887Schin 								continue;
2602*4887Schin 							}
2603*4887Schin 						}
2604*4887Schin 					}
2605*4887Schin 					if (!z)
2606*4887Schin 						z = -1;
2607*4887Schin 				}
2608*4887Schin 				else if (c == '+')
2609*4887Schin 				{
2610*4887Schin 					if (style >= STYLE_man)
2611*4887Schin 					{
2612*4887Schin 						p = textout(sp_body, p, style, 0, 0, sp_info, version, catalog);
2613*4887Schin 						if (!sp_head)
2614*4887Schin 						{
2615*4887Schin 							sp_head = sp_body;
2616*4887Schin 							if (!(sp_body = sfstropen()))
2617*4887Schin 								goto nospace;
2618*4887Schin 						}
2619*4887Schin 						continue;
2620*4887Schin 					}
2621*4887Schin 					else if (style == STYLE_match && *what == '+')
2622*4887Schin 					{
2623*4887Schin 						if (paragraph)
2624*4887Schin 						{
2625*4887Schin 							if (p[1] == '?')
2626*4887Schin 							{
2627*4887Schin 								p = textout(sp, p, style, 1, 3, sp_info, version, catalog);
2628*4887Schin 								continue;
2629*4887Schin 							}
2630*4887Schin 							paragraph = 0;
2631*4887Schin 						}
2632*4887Schin 						if (match((char*)what + 1, p + 1, version, catalog))
2633*4887Schin 						{
2634*4887Schin 							p = textout(sp, p, style, 1, 3, sp_info, version, catalog);
2635*4887Schin 							matched = -1;
2636*4887Schin 							paragraph = 1;
2637*4887Schin 							continue;
2638*4887Schin 						}
2639*4887Schin 					}
2640*4887Schin 					if (!z)
2641*4887Schin 						z = -1;
2642*4887Schin 				}
2643*4887Schin 				else if (c == '[' || version < 1)
2644*4887Schin 				{
2645*4887Schin 					mutex++;
2646*4887Schin 					continue;
2647*4887Schin 				}
2648*4887Schin 				else
2649*4887Schin 				{
2650*4887Schin 					if (c == '!')
2651*4887Schin 					{
2652*4887Schin 						a |= OPT_invert;
2653*4887Schin 						p++;
2654*4887Schin 					}
2655*4887Schin 					rb = p;
2656*4887Schin 					if (*p != ':')
2657*4887Schin 					{
2658*4887Schin 						s = p;
2659*4887Schin 						if (*(p + 1) == '|')
2660*4887Schin 						{
2661*4887Schin 							while (*++p && *p != '=' && *p != '!' && *p != ':' && *p != '?');
2662*4887Schin 							if ((p - s) > 1)
2663*4887Schin 								sl = p - s;
2664*4887Schin 							if (*p == '!')
2665*4887Schin 								a |= OPT_invert;
2666*4887Schin 						}
2667*4887Schin 						if (*(p + 1) == '\f')
2668*4887Schin 							p++;
2669*4887Schin 						else
2670*4887Schin 							p = skip(p, ':', '?', 0, 1, 0, 0, version);
2671*4887Schin 						if (sl || (p - s) == 1 || *(s + 1) == '=' || *(s + 1) == '!' && (a |= OPT_invert) || *(s + 1) == '|')
2672*4887Schin 							f = *s;
2673*4887Schin 					}
2674*4887Schin 					re = p;
2675*4887Schin 					if (style <= STYLE_short)
2676*4887Schin 					{
2677*4887Schin 						if (!z && !f)
2678*4887Schin 							z = -1;
2679*4887Schin 					}
2680*4887Schin 					else
2681*4887Schin 					{
2682*4887Schin 						if (*p == '\f' && (vp = opt_info.state->vp))
2683*4887Schin 							p = expand(p + 1, NiL, &t, vp);
2684*4887Schin 						else
2685*4887Schin 							t = 0;
2686*4887Schin 						if (*p == ':')
2687*4887Schin 						{
2688*4887Schin 							p = skip(w = p + 1, ':', '?', 0, 1, 0, 0, version);
2689*4887Schin 							if (!(wl = p - w))
2690*4887Schin 								w = 0;
2691*4887Schin 						}
2692*4887Schin 						else
2693*4887Schin 							wl = 0;
2694*4887Schin 						if (*p == ':' || *p == '?')
2695*4887Schin 						{
2696*4887Schin 							d = p;
2697*4887Schin 							p = skip(p, 0, 0, 0, 1, 0, 0, version);
2698*4887Schin 						}
2699*4887Schin 						else
2700*4887Schin 							d = 0;
2701*4887Schin 						if (style == STYLE_match)
2702*4887Schin 						{
2703*4887Schin 							if (wl && !match((char*)what, w, version, catalog))
2704*4887Schin 								wl = 0;
2705*4887Schin 							if ((!wl || *w == ':' || *w == '?') && (what[1] || sl && !memchr(s, what[0], sl) || !sl && what[0] != f))
2706*4887Schin 							{
2707*4887Schin 								w = 0;
2708*4887Schin 								if (!z)
2709*4887Schin 									z = -1;
2710*4887Schin 							}
2711*4887Schin 							else
2712*4887Schin 								matched = 1;
2713*4887Schin 						}
2714*4887Schin 						if (t)
2715*4887Schin 						{
2716*4887Schin 							p = t;
2717*4887Schin 							if (*p == ':' || *p == '?')
2718*4887Schin 							{
2719*4887Schin 								d = p;
2720*4887Schin 								p = skip(p, 0, 0, 0, 1, 0, 0, version);
2721*4887Schin 							}
2722*4887Schin 						}
2723*4887Schin 					}
2724*4887Schin 				}
2725*4887Schin 				p = skip(p, 0, 0, 0, 1, 0, 1, version);
2726*4887Schin 				if (*p == GO)
2727*4887Schin 					p = skip(p + 1, 0, 0, 0, 0, 1, 1, version);
2728*4887Schin 			}
2729*4887Schin 			else if (*p == ']')
2730*4887Schin 			{
2731*4887Schin 				if (mutex)
2732*4887Schin 				{
2733*4887Schin 					if (style >= STYLE_nroff)
2734*4887Schin 						sfputr(sp_body, "\n.OP - - anyof", '\n');
2735*4887Schin 					if (!(mutex & 1))
2736*4887Schin 					{
2737*4887Schin 						mutex--;
2738*4887Schin 						if (style <= STYLE_long)
2739*4887Schin 						{
2740*4887Schin 							sfputc(sp_body, ' ');
2741*4887Schin 							sfputc(sp_body, ']');
2742*4887Schin 						}
2743*4887Schin 					}
2744*4887Schin 					mutex--;
2745*4887Schin 				}
2746*4887Schin 				p++;
2747*4887Schin 				continue;
2748*4887Schin 			}
2749*4887Schin 			else if (*p == '?')
2750*4887Schin 			{
2751*4887Schin 				if (style < STYLE_match)
2752*4887Schin 					z = 1;
2753*4887Schin 				mode |= OPT_hidden;
2754*4887Schin 				p++;
2755*4887Schin 				continue;
2756*4887Schin 			}
2757*4887Schin 			else if (*p == '\\' && style==STYLE_posix)
2758*4887Schin 			{
2759*4887Schin 				if (*++p)
2760*4887Schin 					p++;
2761*4887Schin 				continue;
2762*4887Schin 			}
2763*4887Schin 			else
2764*4887Schin 			{
2765*4887Schin 				f = *p++;
2766*4887Schin 				s = 0;
2767*4887Schin 				if (style == STYLE_match && !z)
2768*4887Schin 					z = -1;
2769*4887Schin 			}
2770*4887Schin 			if (!z)
2771*4887Schin 			{
2772*4887Schin 				if (style == STYLE_long || prefix < 2 || (q->flags & OPT_long))
2773*4887Schin 					f = 0;
2774*4887Schin 				else if (style <= STYLE_short)
2775*4887Schin 					w = 0;
2776*4887Schin 				if (!f && !w)
2777*4887Schin 					z = -1;
2778*4887Schin 			}
2779*4887Schin 			ov = u = v = y = 0;
2780*4887Schin 			if (*p == ':' && (a |= OPT_string) || *p == '#' && (a |= OPT_number))
2781*4887Schin 			{
2782*4887Schin 				message((-21, "opthelp: arg %s", show(p)));
2783*4887Schin 				if (*++p == '?' || *p == *(p - 1))
2784*4887Schin 				{
2785*4887Schin 					p++;
2786*4887Schin 					a |= OPT_optional;
2787*4887Schin 				}
2788*4887Schin 				if (*(p = next(p, version)) == '[')
2789*4887Schin 				{
2790*4887Schin 					if (!z)
2791*4887Schin 					{
2792*4887Schin 						p = skip(y = p + 1, ':', '?', 0, 1, 0, 0, version);
2793*4887Schin 						while (*p == ':')
2794*4887Schin 						{
2795*4887Schin 							p = skip(t = p + 1, ':', '?', 0, 1, 0, 0, version);
2796*4887Schin 							m = p - t;
2797*4887Schin 							if (*t == '!')
2798*4887Schin 							{
2799*4887Schin 								ov = t + 1;
2800*4887Schin 								ol = m - 1;
2801*4887Schin 							}
2802*4887Schin 							else if (*t == '=')
2803*4887Schin 							{
2804*4887Schin 								v = t + 1;
2805*4887Schin 								vl = m - 1;
2806*4887Schin 							}
2807*4887Schin 							else
2808*4887Schin 								for (j = 0; j < elementsof(attrs); j++)
2809*4887Schin 									if (strneq(t, attrs[j].name, m))
2810*4887Schin 									{
2811*4887Schin 										a |= attrs[j].flag;
2812*4887Schin 										break;
2813*4887Schin 									}
2814*4887Schin 						}
2815*4887Schin 						if (*p == '?')
2816*4887Schin 							u = p;
2817*4887Schin 						p = skip(p, 0, 0, 0, 1, 0, 1, version);
2818*4887Schin 					}
2819*4887Schin 					else
2820*4887Schin 						p = skip(p + 1, 0, 0, 0, 1, 0, 1, version);
2821*4887Schin 				}
2822*4887Schin 				else
2823*4887Schin 					y = (a & OPT_number) ? T(NiL, ID, "#") : T(NiL, ID, "arg");
2824*4887Schin 			}
2825*4887Schin 			else
2826*4887Schin 				a |= OPT_flag;
2827*4887Schin 			if (!z)
2828*4887Schin 			{
2829*4887Schin 				if (style <= STYLE_short && !y && !mutex || style == STYLE_posix)
2830*4887Schin 				{
2831*4887Schin 					if (style != STYLE_posix && !sfstrtell(sp))
2832*4887Schin 					{
2833*4887Schin 						sfputc(sp, '[');
2834*4887Schin 						if (sp == sp_plus)
2835*4887Schin 							sfputc(sp, '+');
2836*4887Schin 						sfputc(sp, '-');
2837*4887Schin 					}
2838*4887Schin 					if (!sl)
2839*4887Schin 						sfputc(sp, f);
2840*4887Schin 					else
2841*4887Schin 						for (c = 0; c < sl; c++)
2842*4887Schin 							if (s[c] != '|')
2843*4887Schin 								sfputc(sp, s[c]);
2844*4887Schin 					if (style == STYLE_posix && y)
2845*4887Schin 						sfputc(sp, ':');
2846*4887Schin 				}
2847*4887Schin 				else
2848*4887Schin 				{
2849*4887Schin 					if (style >= STYLE_match)
2850*4887Schin 					{
2851*4887Schin 						sfputc(sp_body, '\n');
2852*4887Schin 						if (!head)
2853*4887Schin 						{
2854*4887Schin 							head = 1;
2855*4887Schin 							item(sp_body, (flags & OPT_functions) ? C("FUNCTIONS") : C("OPTIONS"), 0, style, sp_info, version, ID);
2856*4887Schin 						}
2857*4887Schin 						if (style >= STYLE_nroff)
2858*4887Schin 						{
2859*4887Schin 							if (mutex & 1)
2860*4887Schin 							{
2861*4887Schin 								mutex++;
2862*4887Schin 								sfputr(sp_body, "\n.OP - - oneof", '\n');
2863*4887Schin 							}
2864*4887Schin 						}
2865*4887Schin 						else
2866*4887Schin 							sfputc(sp_body, '\t');
2867*4887Schin 					}
2868*4887Schin 					else
2869*4887Schin 					{
2870*4887Schin 						if (sp_body)
2871*4887Schin 							sfputc(sp_body, ' ');
2872*4887Schin 						else if (!(sp_body = sfstropen()))
2873*4887Schin 							goto nospace;
2874*4887Schin 						if (mutex)
2875*4887Schin 						{
2876*4887Schin 							if (mutex & 1)
2877*4887Schin 							{
2878*4887Schin 								mutex++;
2879*4887Schin 								sfputc(sp_body, '[');
2880*4887Schin 							}
2881*4887Schin 							else
2882*4887Schin 								sfputc(sp_body, '|');
2883*4887Schin 							sfputc(sp_body, ' ');
2884*4887Schin 						}
2885*4887Schin 						else
2886*4887Schin 							sfputc(sp_body, '[');
2887*4887Schin 					}
2888*4887Schin 					if (style >= STYLE_nroff)
2889*4887Schin 					{
2890*4887Schin 						if (flags & OPT_functions)
2891*4887Schin 						{
2892*4887Schin 							sfputr(sp_body, ".FN", ' ');
2893*4887Schin 							if (re > rb)
2894*4887Schin 								sfwrite(sp_body, rb, re - rb);
2895*4887Schin 							else
2896*4887Schin 								sfputr(sp, "void", -1);
2897*4887Schin 							if (w)
2898*4887Schin 								label(sp_body, ' ', w, -1, 0, style, FONT_BOLD, sp_info, version, catalog);
2899*4887Schin 						}
2900*4887Schin 						else
2901*4887Schin 						{
2902*4887Schin 							sfputr(sp_body, ".OP", ' ');
2903*4887Schin 							if (sl)
2904*4887Schin 								sfwrite(sp_body, s, sl);
2905*4887Schin 							else
2906*4887Schin 								sfputc(sp_body, f ? f : '-');
2907*4887Schin 							sfputc(sp_body, ' ');
2908*4887Schin 							if (w)
2909*4887Schin 							{
2910*4887Schin 								if (label(sp_body, 0, w, -1, 0, style, 0, sp_info, version, catalog))
2911*4887Schin 								{
2912*4887Schin 									sfputc(sp_body, '|');
2913*4887Schin 									label(sp_body, 0, w, -1, 0, style, 0, sp_info, version, native);
2914*4887Schin 								}
2915*4887Schin 							}
2916*4887Schin 							else
2917*4887Schin 								sfputc(sp_body, '-');
2918*4887Schin 							sfputc(sp_body, ' ');
2919*4887Schin 							m = a & OPT_TYPE;
2920*4887Schin 							for (j = 0; j < elementsof(attrs); j++)
2921*4887Schin 								if (m & attrs[j].flag)
2922*4887Schin 								{
2923*4887Schin 									sfputr(sp_body, attrs[j].name, -1);
2924*4887Schin 									break;
2925*4887Schin 								}
2926*4887Schin 							if (m = (a & ~m) | mode)
2927*4887Schin 								for (j = 0; j < elementsof(attrs); j++)
2928*4887Schin 									if (m & attrs[j].flag)
2929*4887Schin 									{
2930*4887Schin 										sfputc(sp_body, ':');
2931*4887Schin 										sfputr(sp_body, attrs[j].name, -1);
2932*4887Schin 									}
2933*4887Schin 							sfputc(sp_body, ' ');
2934*4887Schin 							if (y)
2935*4887Schin 								label(sp_body, 0, y, -1, 0, style, 0, sp_info, version, catalog);
2936*4887Schin 							else
2937*4887Schin 								sfputc(sp_body, '-');
2938*4887Schin 							if (v)
2939*4887Schin 								sfprintf(sp_body, " %-.*s", vl, v);
2940*4887Schin 						}
2941*4887Schin 					}
2942*4887Schin 					else
2943*4887Schin 					{
2944*4887Schin 						if (f)
2945*4887Schin 						{
2946*4887Schin 							if (sp_body == sp_plus)
2947*4887Schin 								sfputc(sp_body, '+');
2948*4887Schin 							sfputc(sp_body, '-');
2949*4887Schin 							sfputr(sp_body, font(FONT_BOLD, style, 1), -1);
2950*4887Schin 							if (!sl)
2951*4887Schin 							{
2952*4887Schin 								sfputc(sp_body, f);
2953*4887Schin 								if (f == '-' && y)
2954*4887Schin 								{
2955*4887Schin 									y = 0;
2956*4887Schin 									sfputr(sp_body, C("long-option[=value]"), -1);
2957*4887Schin 								}
2958*4887Schin 							}
2959*4887Schin 							else
2960*4887Schin 								sfwrite(sp_body, s, sl);
2961*4887Schin 							sfputr(sp_body, font(FONT_BOLD, style, 0), -1);
2962*4887Schin 							if (w)
2963*4887Schin 							{
2964*4887Schin 								sfputc(sp_body, ',');
2965*4887Schin 								sfputc(sp_body, ' ');
2966*4887Schin 							}
2967*4887Schin 						}
2968*4887Schin 						else if ((flags & OPT_functions) && re > rb)
2969*4887Schin 						{
2970*4887Schin 							sfwrite(sp_body, rb, re - rb);
2971*4887Schin 							sfputc(sp_body, ' ');
2972*4887Schin 						}
2973*4887Schin 						if (w)
2974*4887Schin 						{
2975*4887Schin 							if (prefix > 0)
2976*4887Schin 							{
2977*4887Schin 								sfputc(sp_body, '-');
2978*4887Schin 								if (prefix > 1)
2979*4887Schin 									sfputc(sp_body, '-');
2980*4887Schin 							}
2981*4887Schin 							if (label(sp_body, 0, w, -1, 0, style, FONT_BOLD, sp_info, version, catalog))
2982*4887Schin 							{
2983*4887Schin 								sfputc(sp_body, '|');
2984*4887Schin 								label(sp_body, 0, w, -1, 0, style, FONT_BOLD, sp_info, version, native);
2985*4887Schin 							}
2986*4887Schin 						}
2987*4887Schin 						if (y)
2988*4887Schin 						{
2989*4887Schin 							if (a & OPT_optional)
2990*4887Schin 								sfputc(sp_body, '[');
2991*4887Schin 							else if (!w)
2992*4887Schin 								sfputc(sp_body, ' ');
2993*4887Schin 							if (w)
2994*4887Schin 								sfputc(sp_body, prefix == 1 ? ' ' : '=');
2995*4887Schin 							label(sp_body, 0, y, -1, 0, style, FONT_ITALIC, sp_info, version, catalog);
2996*4887Schin 							if (a & OPT_optional)
2997*4887Schin 								sfputc(sp_body, ']');
2998*4887Schin 						}
2999*4887Schin 					}
3000*4887Schin 					if (style >= STYLE_match)
3001*4887Schin 					{
3002*4887Schin 						if (d)
3003*4887Schin 							textout(sp_body, d, style, 0, 3, sp_info, version, catalog);
3004*4887Schin 						if (u)
3005*4887Schin 							textout(sp_body, u, style, 0, 3, sp_info, version, catalog);
3006*4887Schin 						if ((a & OPT_invert) && w && (d || u))
3007*4887Schin 						{
3008*4887Schin 							u = skip(w, ':', '?', 0, 1, 0, 0, version);
3009*4887Schin 							if (f)
3010*4887Schin 								sfprintf(sp_info, " %s; -\b%c\b %s --\bno%-.*s\b.", T(NiL, ID, "On by default"), f, T(NiL, ID, "means"), u - w, w);
3011*4887Schin 							else
3012*4887Schin 								sfprintf(sp_info, " %s %s\bno%-.*s\b %s.", T(NiL, ID, "On by default; use"), "--"+2-prefix, u - w, w, T(NiL, ID, "to turn off"));
3013*4887Schin 							if (!(t = sfstruse(sp_info)))
3014*4887Schin 								goto nospace;
3015*4887Schin 							textout(sp_body, t, style, 0, 0, sp_info, version, NiL);
3016*4887Schin 						}
3017*4887Schin 						if (*p == GO)
3018*4887Schin 						{
3019*4887Schin 							p = u ? skip(p + 1, 0, 0, 0, 0, 1, 1, version) : textout(sp_body, p, style, 4, 0, sp_info, version, catalog);
3020*4887Schin 							y = "+?";
3021*4887Schin 						}
3022*4887Schin 						else
3023*4887Schin 							y = " ";
3024*4887Schin 						if (a & OPT_optional)
3025*4887Schin 						{
3026*4887Schin 							if (ov)
3027*4887Schin 							{
3028*4887Schin 								sfprintf(sp_info, "%s%s \b", y, T(NiL, ID, "If the option value is omitted then"));
3029*4887Schin 								t = ov + ol;
3030*4887Schin 								while (ov < t)
3031*4887Schin 								{
3032*4887Schin 									if (((c = *ov++) == ':' || c == '?') && *ov == c)
3033*4887Schin 										ov++;
3034*4887Schin 									sfputc(sp_info, c);
3035*4887Schin 								}
3036*4887Schin 								sfprintf(sp_info, "\b %s.", T(NiL, ID, "is assumed"));
3037*4887Schin 							}
3038*4887Schin 							else
3039*4887Schin 								sfprintf(sp_info, "%s%s", y, T(NiL, ID, "The option value may be omitted."));
3040*4887Schin 							if (!(t = sfstruse(sp_info)))
3041*4887Schin 								goto nospace;
3042*4887Schin 							textout(sp_body, t, style, 4, 0, sp_info, version, NiL);
3043*4887Schin 							y = " ";
3044*4887Schin 						}
3045*4887Schin 						if (v)
3046*4887Schin 						{
3047*4887Schin 							sfprintf(sp_info, "%s%s \b", y, T(NiL, ID, "The default value is"));
3048*4887Schin 							t = v + vl;
3049*4887Schin 							while (v < t)
3050*4887Schin 							{
3051*4887Schin 								if (((c = *v++) == ':' || c == '?') && *v == c)
3052*4887Schin 									v++;
3053*4887Schin 								sfputc(sp_info, c);
3054*4887Schin 							}
3055*4887Schin 							sfputc(sp_info, '\b');
3056*4887Schin 							sfputc(sp_info, '.');
3057*4887Schin 							if (!(t = sfstruse(sp_info)))
3058*4887Schin 								goto nospace;
3059*4887Schin 							textout(sp_body, t, style, 4, 0, sp_info, version, NiL);
3060*4887Schin 						}
3061*4887Schin 					}
3062*4887Schin 					else if (!mutex)
3063*4887Schin 						sfputc(sp_body, ']');
3064*4887Schin 				}
3065*4887Schin 				if (*p == GO)
3066*4887Schin 				{
3067*4887Schin 					if (style >= STYLE_match)
3068*4887Schin 						p = textout(sp_body, p, style, 4, 0, sp_info, version, catalog);
3069*4887Schin 					else
3070*4887Schin 						p = skip(p + 1, 0, 0, 0, 0, 1, 1, version);
3071*4887Schin 				}
3072*4887Schin 			}
3073*4887Schin 			else if (*p == GO)
3074*4887Schin 				p = skip(p + 1, 0, 0, 0, 0, 1, 1, version);
3075*4887Schin 		}
3076*4887Schin 		psp = pop(psp);
3077*4887Schin 		if (sp_misc)
3078*4887Schin 		{
3079*4887Schin 			if (!(p = sfstruse(sp_misc)))
3080*4887Schin 				goto nospace;
3081*4887Schin 			for (t = p; *t == '\t' || *t == '\n'; t++);
3082*4887Schin 			if (*t)
3083*4887Schin 			{
3084*4887Schin 				item(sp_body, C("IMPLEMENTATION"), 0, style, sp_info, version, ID);
3085*4887Schin 				sfputr(sp_body, p, -1);
3086*4887Schin 			}
3087*4887Schin 		}
3088*4887Schin 	}
3089*4887Schin 	version = o->version;
3090*4887Schin 	catalog = o->catalog;
3091*4887Schin 	if (style >= STYLE_keys)
3092*4887Schin 	{
3093*4887Schin 		if (sp_info)
3094*4887Schin 			sfclose(sp_info);
3095*4887Schin 		if (style == STYLE_keys && sfstrtell(mp) > 1)
3096*4887Schin 			sfstrseek(mp, -1, SEEK_CUR);
3097*4887Schin 		if (!(p = sfstruse(mp)))
3098*4887Schin 			goto nospace;
3099*4887Schin 		return opt_info.msg = p;
3100*4887Schin 	}
3101*4887Schin 	sp = sp_text;
3102*4887Schin 	if (sfstrtell(sp) && style != STYLE_posix)
3103*4887Schin 		sfputc(sp, ']');
3104*4887Schin 	if (style == STYLE_nroff)
3105*4887Schin 	{
3106*4887Schin 		sfprintf(sp, "\
3107*4887Schin .\\\" format with nroff|troff|groff -man\n\
3108*4887Schin .fp 5 CW\n\
3109*4887Schin .nr mI 0\n\
3110*4887Schin .de mI\n\
3111*4887Schin .if \\\\n(mI>\\\\$1 \\{\n\
3112*4887Schin .	nr mI \\\\n(mI-1\n\
3113*4887Schin .	RE\n\
3114*4887Schin .mI \\\\$1\n\
3115*4887Schin .\\}\n\
3116*4887Schin .if \\\\n(mI<\\\\$1 \\{\n\
3117*4887Schin .	nr mI \\\\n(mI+1\n\
3118*4887Schin .	RS\n\
3119*4887Schin .mI \\\\$1\n\
3120*4887Schin .\\}\n\
3121*4887Schin ..\n\
3122*4887Schin .de H1\n\
3123*4887Schin .mI 1\n\
3124*4887Schin .TP\n\
3125*4887Schin \\fB\\\\$1\\fP\n\
3126*4887Schin ..\n\
3127*4887Schin .de H2\n\
3128*4887Schin .mI 2\n\
3129*4887Schin .TP\n\
3130*4887Schin \\fB\\\\$1\\fP\n\
3131*4887Schin ..\n\
3132*4887Schin .de H3\n\
3133*4887Schin .mI 3\n\
3134*4887Schin .TP\n\
3135*4887Schin \\fB\\\\$1\\fP\n\
3136*4887Schin ..\n\
3137*4887Schin .de H4\n\
3138*4887Schin .mI 4\n\
3139*4887Schin .TP\n\
3140*4887Schin \\fB\\\\$1\\fP\n\
3141*4887Schin ..\n\
3142*4887Schin .de OP\n\
3143*4887Schin .mI 0\n\
3144*4887Schin .ie !'\\\\$1'-' \\{\n\
3145*4887Schin .ds mO \\\\fB\\\\-\\\\$1\\\\fP\n\
3146*4887Schin .ds mS ,\\\\0\n\
3147*4887Schin .\\}\n\
3148*4887Schin .el \\{\n\
3149*4887Schin .ds mO \\\\&\n\
3150*4887Schin .ds mS \\\\&\n\
3151*4887Schin .\\}\n\
3152*4887Schin .ie '\\\\$2'-' \\{\n\
3153*4887Schin .if !'\\\\$4'-' .as mO \\\\0\\\\fI\\\\$4\\\\fP\n\
3154*4887Schin .\\}\n\
3155*4887Schin .el \\{\n\
3156*4887Schin .as mO \\\\*(mS\\\\fB%s\\\\$2\\\\fP\n\
3157*4887Schin .if !'\\\\$4'-' .as mO =\\\\fI\\\\$4\\\\fP\n\
3158*4887Schin .\\}\n\
3159*4887Schin .TP\n\
3160*4887Schin \\\\*(mO\n\
3161*4887Schin ..\n\
3162*4887Schin .de FN\n\
3163*4887Schin .mI 0\n\
3164*4887Schin .TP\n\
3165*4887Schin \\\\$1 \\\\$2\n\
3166*4887Schin ..\n\
3167*4887Schin .TH %s %d\n\
3168*4887Schin "
3169*4887Schin , o->prefix == 2 ? "\\\\-\\\\-" : o->prefix == 1 ? "\\\\-" : ""
3170*4887Schin , error_info.id
3171*4887Schin , section
3172*4887Schin );
3173*4887Schin 	}
3174*4887Schin 	if (style == STYLE_match)
3175*4887Schin 	{
3176*4887Schin 		if (!matched)
3177*4887Schin 		{
3178*4887Schin 			if (hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), (char*)what))
3179*4887Schin 			{
3180*4887Schin 				if (!sp_help && !(sp_help = sfstropen()))
3181*4887Schin 					goto nospace;
3182*4887Schin 				sfprintf(sp_help, "[-][:%s?%s]", hp->match, hp->text);
3183*4887Schin 				if (!(opts = sfstruse(sp_help)))
3184*4887Schin 					goto nospace;
3185*4887Schin 				goto again;
3186*4887Schin 			}
3187*4887Schin 			s = (char*)unknown;
3188*4887Schin 			goto nope;
3189*4887Schin 		}
3190*4887Schin 		else if (matched < 0)
3191*4887Schin 			x = 0;
3192*4887Schin 	}
3193*4887Schin 	if (sp_plus)
3194*4887Schin 	{
3195*4887Schin 		if (sfstrtell(sp_plus))
3196*4887Schin 		{
3197*4887Schin 			if (sfstrtell(sp))
3198*4887Schin 				sfputc(sp, ' ');
3199*4887Schin 			if (!(t = sfstruse(sp_plus)))
3200*4887Schin 				goto nospace;
3201*4887Schin 			sfputr(sp, t, ']');
3202*4887Schin 		}
3203*4887Schin 		sfclose(sp_plus);
3204*4887Schin 	}
3205*4887Schin 	if (style >= STYLE_man)
3206*4887Schin 	{
3207*4887Schin 		if (sp_head)
3208*4887Schin 		{
3209*4887Schin 			if (!(t = sfstruse(sp_head)))
3210*4887Schin 				goto nospace;
3211*4887Schin 			for (; *t == '\n'; t++);
3212*4887Schin 			sfputr(sp, t, '\n');
3213*4887Schin 			sfclose(sp_head);
3214*4887Schin 			sp_head = 0;
3215*4887Schin 		}
3216*4887Schin 		item(sp, C("SYNOPSIS"), 0, style, sp_info, version, ID);
3217*4887Schin 	}
3218*4887Schin 	if (x)
3219*4887Schin 	{
3220*4887Schin 		for (t = x + xl; t > x && (*(t - 1) == '\n' || *(t - 1) == '\r'); t--);
3221*4887Schin 		xl = t - x;
3222*4887Schin 		if (style >= STYLE_match)
3223*4887Schin 		{
3224*4887Schin 			args(sp, x, xl, flags, style, sp_info, version, catalog);
3225*4887Schin 			x = 0;
3226*4887Schin 		}
3227*4887Schin 	}
3228*4887Schin 	if (sp_body)
3229*4887Schin 	{
3230*4887Schin 		if (sfstrtell(sp_body))
3231*4887Schin 		{
3232*4887Schin 			if (style < STYLE_match && sfstrtell(sp))
3233*4887Schin 				sfputc(sp, ' ');
3234*4887Schin 			if (!(t = sfstruse(sp_body)))
3235*4887Schin 				goto nospace;
3236*4887Schin 			sfputr(sp, t, -1);
3237*4887Schin 		}
3238*4887Schin 		sfclose(sp_body);
3239*4887Schin 		sp_body = 0;
3240*4887Schin 	}
3241*4887Schin 	if (x && style != STYLE_posix)
3242*4887Schin 		args(sp, x, xl, flags, style, sp_info, version, catalog);
3243*4887Schin 	if (sp_info)
3244*4887Schin 	{
3245*4887Schin 		sfclose(sp_info);
3246*4887Schin 		sp_info = 0;
3247*4887Schin 	}
3248*4887Schin 	if (sp_misc)
3249*4887Schin 	{
3250*4887Schin 		sfclose(sp_misc);
3251*4887Schin 		sp_misc = 0;
3252*4887Schin 	}
3253*4887Schin 	if (!(p = sfstruse(sp)))
3254*4887Schin 		goto nospace;
3255*4887Schin 	name = error_info.id ? error_info.id : "command";
3256*4887Schin 	m = strlen(name) + 1;
3257*4887Schin 	if (!opt_info.state->width)
3258*4887Schin 	{
3259*4887Schin 		astwinsize(1, NiL, &opt_info.state->width);
3260*4887Schin 		if (opt_info.state->width < 20)
3261*4887Schin 			opt_info.state->width = OPT_WIDTH;
3262*4887Schin 	}
3263*4887Schin 	if (!(opt_info.state->flags & OPT_preformat))
3264*4887Schin 	{
3265*4887Schin 		if (style >= STYLE_man || matched < 0)
3266*4887Schin 		{
3267*4887Schin 			sfputc(mp, '\f');
3268*4887Schin 			ts = 0;
3269*4887Schin 		}
3270*4887Schin 		else
3271*4887Schin 			ts = OPT_USAGE + m;
3272*4887Schin 		if (style == STYLE_html)
3273*4887Schin 		{
3274*4887Schin 			sfprintf(mp, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n<HTML>\n<HEAD>\n<META name=\"generator\" content=\"optget (AT&T Research) 2000-04-01\">\n%s<TITLE>%s man document</TITLE>\n</HEAD>\n<BODY bgcolor=white>\n", (opt_info.state->flags & OPT_proprietary) ? "<!--INTERNAL-->\n" : "", name);
3275*4887Schin 			sfprintf(mp, "<H4><TABLE width=100%%><TR><TH align=left>&nbsp;%s&nbsp;(&nbsp;%d&nbsp;)&nbsp;<TH align=center><A href=\".\" title=\"Index\">%s</A><TH align=right>%s&nbsp;(&nbsp;%d&nbsp;)</TR></TABLE></H4>\n<HR>\n", name, section, T(NiL, ID, heading[section % 10]), name, section);
3276*4887Schin 			sfprintf(mp, "<DL compact>\n<DT>");
3277*4887Schin 			co = 2;
3278*4887Schin 			*(pt = ptstk) = 0;
3279*4887Schin 		}
3280*4887Schin 		else
3281*4887Schin 			co = 0;
3282*4887Schin 		if ((rm = opt_info.state->width - ts - 1) < OPT_MARGIN)
3283*4887Schin 			rm = OPT_MARGIN;
3284*4887Schin 		ip = indent;
3285*4887Schin 		ip->stop = (ip+1)->stop = style >= STYLE_html ? 0 : 2;
3286*4887Schin 		tp = 0;
3287*4887Schin 		n = 0;
3288*4887Schin 		head = 1;
3289*4887Schin 		while (*p == '\n')
3290*4887Schin 			p++;
3291*4887Schin 		while (c = *p++)
3292*4887Schin 		{
3293*4887Schin 			if (c == '\n')
3294*4887Schin 			{
3295*4887Schin 				ip = indent;
3296*4887Schin 				n = 0;
3297*4887Schin 				tp = 0;
3298*4887Schin 				sfputc(mp, '\n');
3299*4887Schin 				co = 0;
3300*4887Schin 				rm = opt_info.state->width - 1;
3301*4887Schin 				ts = ip->stop;
3302*4887Schin 				if (*p == '\n')
3303*4887Schin 				{
3304*4887Schin 					while (*++p == '\n');
3305*4887Schin 					if ((style == STYLE_man || style == STYLE_html) && (!head || *p != ' ' && *p != '\t'))
3306*4887Schin 					{
3307*4887Schin 						if (style == STYLE_man)
3308*4887Schin 							p--;
3309*4887Schin 						else
3310*4887Schin 							sfprintf(mp, "<P>\n");
3311*4887Schin 					}
3312*4887Schin 				}
3313*4887Schin 				head = *p != ' ' && *p != '\t';
3314*4887Schin 				if (style == STYLE_html && (*p != '<' || !strneq(p, "<BR>", 4) && !strneq(p, "<P>", 3)))
3315*4887Schin 				{
3316*4887Schin 					y = p;
3317*4887Schin 					while (*p == '\t')
3318*4887Schin 						p++;
3319*4887Schin 					if (*p == '\n')
3320*4887Schin 						continue;
3321*4887Schin 					j = p - y;
3322*4887Schin 					if (j > *pt)
3323*4887Schin 					{
3324*4887Schin 						if (pt > ptstk)
3325*4887Schin 							sfprintf(mp, "<DL compact>\n");
3326*4887Schin 						*++pt = j;
3327*4887Schin 						sfprintf(mp, "<DL compact>\n");
3328*4887Schin 					}
3329*4887Schin 					else while (j < *pt)
3330*4887Schin 					{
3331*4887Schin 						if (--pt > ptstk)
3332*4887Schin 							sfprintf(mp, "</DL>\n");
3333*4887Schin 						sfprintf(mp, "</DL>\n");
3334*4887Schin 					}
3335*4887Schin 					co += sfprintf(mp, "<DT>");
3336*4887Schin 				}
3337*4887Schin 			}
3338*4887Schin 			else if (c == '\t')
3339*4887Schin 			{
3340*4887Schin 				if (style == STYLE_html)
3341*4887Schin 				{
3342*4887Schin 					while (*p == '\t')
3343*4887Schin 						p++;
3344*4887Schin 					if (*p != '\n')
3345*4887Schin 						co += sfprintf(mp, "<DD>");
3346*4887Schin 				}
3347*4887Schin 				else
3348*4887Schin 				{
3349*4887Schin 					if ((ip+1)->stop)
3350*4887Schin 					{
3351*4887Schin 						do
3352*4887Schin 						{
3353*4887Schin 							ip++;
3354*4887Schin 							if (*p != '\t')
3355*4887Schin 								break;
3356*4887Schin 							p++;
3357*4887Schin 						} while ((ip+1)->stop);
3358*4887Schin 						if (*p == '\n')
3359*4887Schin 							continue;
3360*4887Schin 						ts = ip->stop;
3361*4887Schin 						if (co >= ts)
3362*4887Schin 						{
3363*4887Schin 							sfputc(mp, '\n');
3364*4887Schin 							co = 0;
3365*4887Schin 							rm = opt_info.state->width - 1;
3366*4887Schin 							ts = ip->stop;
3367*4887Schin 						}
3368*4887Schin 					}
3369*4887Schin 					while (co < ts)
3370*4887Schin 					{
3371*4887Schin 						sfputc(mp, ' ');
3372*4887Schin 						co++;
3373*4887Schin 					}
3374*4887Schin 				}
3375*4887Schin 			}
3376*4887Schin 			else
3377*4887Schin 			{
3378*4887Schin 				if (c == ' ' && !n)
3379*4887Schin 				{
3380*4887Schin 					if (co >= rm)
3381*4887Schin 						tp = 0;
3382*4887Schin 					else
3383*4887Schin 					{
3384*4887Schin 						tp = sfstrtell(mp);
3385*4887Schin 						pp = p;
3386*4887Schin 					}
3387*4887Schin 					if (style == STYLE_nroff && !co)
3388*4887Schin 						continue;
3389*4887Schin 				}
3390*4887Schin 				else if (style == STYLE_html)
3391*4887Schin 				{
3392*4887Schin 					if (c == '<')
3393*4887Schin 					{
3394*4887Schin 						if (strneq(p, "NOBR>", 5))
3395*4887Schin 							n++;
3396*4887Schin 						else if (n && strneq(p, "/NOBR>", 6) && !--n)
3397*4887Schin 						{
3398*4887Schin 							for (y = p += 6; (c = *p) && c != ' ' && c != '\t' && c != '\n' && c != '<'; p++)
3399*4887Schin 								if (c == '[')
3400*4887Schin 									sfputr(mp, "&#0091;", -1);
3401*4887Schin 								else if (c == ']')
3402*4887Schin 									sfputr(mp, "&#0093;", -1);
3403*4887Schin 								else
3404*4887Schin 									sfputc(mp, c);
3405*4887Schin 							sfwrite(mp, "</NOBR", 6);
3406*4887Schin 							c = '>';
3407*4887Schin 							tp = 0;
3408*4887Schin 							co += p - y + 6;
3409*4887Schin 						}
3410*4887Schin 					}
3411*4887Schin 					else if (c == '>' && !n)
3412*4887Schin 					{
3413*4887Schin 						for (y = --p; (c = *p) && c != ' ' && c != '\t' && c != '\n' && c != '<'; p++)
3414*4887Schin 							if (c == '[')
3415*4887Schin 								sfputr(mp, "&#0091;", -1);
3416*4887Schin 							else if (c == ']')
3417*4887Schin 								sfputr(mp, "&#0093;", -1);
3418*4887Schin 							else
3419*4887Schin 								sfputc(mp, c);
3420*4887Schin 						c = *sfstrseek(mp, -1, SEEK_CUR);
3421*4887Schin 						if (p > y + 1)
3422*4887Schin 						{
3423*4887Schin 							tp = 0;
3424*4887Schin 							co += p - y - 1;
3425*4887Schin 						}
3426*4887Schin 						if (co >= rm)
3427*4887Schin 							tp = 0;
3428*4887Schin 						else
3429*4887Schin 						{
3430*4887Schin 							tp = sfstrtell(mp);
3431*4887Schin 							pp = p;
3432*4887Schin 						}
3433*4887Schin 					}
3434*4887Schin 					else if (c == '[')
3435*4887Schin 					{
3436*4887Schin 						sfputr(mp, "&#0091", -1);
3437*4887Schin 						c = ';';
3438*4887Schin 					}
3439*4887Schin 					else if (c == ']')
3440*4887Schin 					{
3441*4887Schin 						sfputr(mp, "&#0093", -1);
3442*4887Schin 						c = ';';
3443*4887Schin 					}
3444*4887Schin 					else if (c == 'h')
3445*4887Schin 					{
3446*4887Schin 						y = p;
3447*4887Schin 						if (*y++ == 't' && *y++ == 't' && *y++ == 'p' && (*y == ':' || *y++ == 's' && *y == ':') && *y++ == ':' && *y++ == '/' && *y++ == '/')
3448*4887Schin 						{
3449*4887Schin 							while (isalnum(*y) || *y == '_' || *y == '/' || *y == '-' || *y == '.')
3450*4887Schin 								y++;
3451*4887Schin 							if (*y == '?')
3452*4887Schin 								while (isalnum(*y) || *y == '_' || *y == '/' || *y == '-' || *y == '.' || *y == '?' || *y == '=' || *y == '%' || *y == '&' || *y == ';' || *y == '#')
3453*4887Schin 									y++;
3454*4887Schin 							if (*(y - 1) == '.')
3455*4887Schin 								y--;
3456*4887Schin 							p--;
3457*4887Schin 							sfprintf(mp, "<A href=\"%-.*s\">%-.*s</A", y - p, p, y - p, p);
3458*4887Schin 							p = y;
3459*4887Schin 							c = '>';
3460*4887Schin 						}
3461*4887Schin 					}
3462*4887Schin 					else if (c == 'C')
3463*4887Schin 					{
3464*4887Schin 						y = p;
3465*4887Schin 						if (*y++ == 'o' && *y++ == 'p' && *y++ == 'y' && *y++ == 'r' && *y++ == 'i' && *y++ == 'g' && *y++ == 'h' && *y++ == 't' && *y++ == ' ' && *y++ == '(' && (*y++ == 'c' || *(y - 1) == 'C') && *y++ == ')')
3466*4887Schin 						{
3467*4887Schin 							sfputr(mp, "Copyright &copy", -1);
3468*4887Schin 							p = y;
3469*4887Schin 							c = ';';
3470*4887Schin 						}
3471*4887Schin 					}
3472*4887Schin 				}
3473*4887Schin 				else if (c == ']')
3474*4887Schin 				{
3475*4887Schin 					if (n)
3476*4887Schin 						n--;
3477*4887Schin 				}
3478*4887Schin 				else if (c == '[')
3479*4887Schin 					n++;
3480*4887Schin 				if (c == CC_esc)
3481*4887Schin 				{
3482*4887Schin 					sfputc(mp, c);
3483*4887Schin 					do
3484*4887Schin 					{
3485*4887Schin 						if (!(c = *p++))
3486*4887Schin 						{
3487*4887Schin 							p--;
3488*4887Schin 							break;
3489*4887Schin 						}
3490*4887Schin 						sfputc(mp, c);
3491*4887Schin 					} while (c < 'a' || c > 'z');
3492*4887Schin 				}
3493*4887Schin 				else if (co++ >= rm && !n)
3494*4887Schin 				{
3495*4887Schin 					if (tp)
3496*4887Schin 					{
3497*4887Schin 						if (*sfstrseek(mp, tp, SEEK_SET) != ' ')
3498*4887Schin 							sfstrseek(mp, 1, SEEK_CUR);
3499*4887Schin 						tp = 0;
3500*4887Schin 						p = pp;
3501*4887Schin 						n = 0;
3502*4887Schin 					}
3503*4887Schin 					else if (c != ' ' && c != '\n')
3504*4887Schin 						sfputc(mp, c);
3505*4887Schin 					if (*p == ' ')
3506*4887Schin 						p++;
3507*4887Schin 					if (*p != '\n')
3508*4887Schin 					{
3509*4887Schin 						sfputc(mp, '\n');
3510*4887Schin 						for (co = 0; co < ts; co++)
3511*4887Schin 							sfputc(mp, ' ');
3512*4887Schin 						rm = opt_info.state->width - 1;
3513*4887Schin 					}
3514*4887Schin 				}
3515*4887Schin 				else
3516*4887Schin 					sfputc(mp, c);
3517*4887Schin 			}
3518*4887Schin 		}
3519*4887Schin 		for (d = sfstrbase(mp), t = sfstrseek(mp, 0, SEEK_CUR); t > d && ((c = *(t - 1)) == '\n' || c == '\r' || c == ' ' || c == '\t'); t--);
3520*4887Schin 		sfstrseek(mp, t - d, SEEK_SET);
3521*4887Schin 		if (style == STYLE_html)
3522*4887Schin 		{
3523*4887Schin 			while (pt > ptstk)
3524*4887Schin 			{
3525*4887Schin 				if (--pt > ptstk)
3526*4887Schin 					sfprintf(mp, "\n</DL>");
3527*4887Schin 				sfprintf(mp, "\n</DL>");
3528*4887Schin 			}
3529*4887Schin 			sfprintf(mp, "</DL>\n</BODY>\n</HTML>");
3530*4887Schin 		}
3531*4887Schin 	}
3532*4887Schin 	else
3533*4887Schin 		sfputr(mp, p, 0);
3534*4887Schin 	if (!(p = sfstruse(mp)))
3535*4887Schin 		goto nospace;
3536*4887Schin 	if (sp)
3537*4887Schin 		sfclose(sp);
3538*4887Schin 	return opt_info.msg = p;
3539*4887Schin  nospace:
3540*4887Schin 	s = T(NiL, ID, "[* out of space *]");
3541*4887Schin  nope:
3542*4887Schin 	if (psp)
3543*4887Schin 		pop(psp);
3544*4887Schin 	if (sp_help)
3545*4887Schin 		sfclose(sp_help);
3546*4887Schin 	if (sp_text)
3547*4887Schin 		sfclose(sp_text);
3548*4887Schin 	if (sp_plus)
3549*4887Schin 		sfclose(sp_plus);
3550*4887Schin 	if (sp_info)
3551*4887Schin 		sfclose(sp_info);
3552*4887Schin 	if (sp_head)
3553*4887Schin 		sfclose(sp_head);
3554*4887Schin 	if (sp_body)
3555*4887Schin 		sfclose(sp_body);
3556*4887Schin 	if (sp_misc)
3557*4887Schin 		sfclose(sp_misc);
3558*4887Schin 	return s;
3559*4887Schin }
3560*4887Schin 
3561*4887Schin /*
3562*4887Schin  * compatibility wrapper to opthelp()
3563*4887Schin  */
3564*4887Schin 
3565*4887Schin char*
3566*4887Schin optusage(const char* opts)
3567*4887Schin {
3568*4887Schin 	return opthelp(opts, NiL);
3569*4887Schin }
3570*4887Schin 
3571*4887Schin /*
3572*4887Schin  * convert number using strtonll() *except* that
3573*4887Schin  * 0*[[:digit:]].* is treated as [[:digit:]].*
3574*4887Schin  * i.e., it looks octal but isn't, to meet
3575*4887Schin  * posix Utility Argument Syntax -- use
3576*4887Schin  * 0x.* or <base>#* for alternate bases
3577*4887Schin  */
3578*4887Schin 
3579*4887Schin static intmax_t
3580*4887Schin optnumber(const char* s, char** t, int* e)
3581*4887Schin {
3582*4887Schin 	intmax_t	n;
3583*4887Schin 	int		oerrno;
3584*4887Schin 
3585*4887Schin 	while (*s == '0' && isdigit(*(s + 1)))
3586*4887Schin 		s++;
3587*4887Schin 	oerrno = errno;
3588*4887Schin 	errno = 0;
3589*4887Schin 	n = strtonll(s, t, NiL, 0);
3590*4887Schin 	if (e)
3591*4887Schin 		*e = errno;
3592*4887Schin 	errno = oerrno;
3593*4887Schin 	return n;
3594*4887Schin }
3595*4887Schin 
3596*4887Schin /*
3597*4887Schin  * point opt_info.arg to an error/info message for opt_info.name
3598*4887Schin  * p points to opts location for opt_info.name
3599*4887Schin  * optget() return value is returned
3600*4887Schin  */
3601*4887Schin 
3602*4887Schin static int
3603*4887Schin opterror(register char* p, int version, char* catalog, int err)
3604*4887Schin {
3605*4887Schin 	register Sfio_t*	mp;
3606*4887Schin 	register Sfio_t*	tp;
3607*4887Schin 	register char*		s;
3608*4887Schin 	register int		c;
3609*4887Schin 
3610*4887Schin 	if (opt_info.num != LONG_MIN)
3611*4887Schin 		opt_info.num = opt_info.number = 0;
3612*4887Schin 	if (!p || !(mp = opt_info.state->mp) && !(mp = opt_info.state->mp = sfstropen()))
3613*4887Schin 		goto nospace;
3614*4887Schin 	s = *p == '-' ? p : opt_info.name;
3615*4887Schin 	if (*p == '!')
3616*4887Schin 	{
3617*4887Schin 		while (*s == '-')
3618*4887Schin 			sfputc(mp, *s++);
3619*4887Schin 		sfputc(mp, 'n');
3620*4887Schin 		sfputc(mp, 'o');
3621*4887Schin 	}
3622*4887Schin 	sfputr(mp, s, ':');
3623*4887Schin 	sfputc(mp, ' ');
3624*4887Schin 	if (*p == '#' || *p == ':')
3625*4887Schin 	{
3626*4887Schin 		if (*p == '#')
3627*4887Schin 		{
3628*4887Schin 			s = T(NiL, ID, "numeric");
3629*4887Schin 			sfputr(mp, s, ' ');
3630*4887Schin 		}
3631*4887Schin 		if (*(p = next(p + 1, version)) == '[')
3632*4887Schin 		{
3633*4887Schin 			p = skip(s = p + 1, ':', '?', 0, 1, 0, 0, version);
3634*4887Schin 			tp = X(catalog) ? opt_info.state->xp : mp;
3635*4887Schin 			while (s < p)
3636*4887Schin 			{
3637*4887Schin 				if ((c = *s++) == '?' || c == ']')
3638*4887Schin 					s++;
3639*4887Schin 				sfputc(tp, c);
3640*4887Schin 			}
3641*4887Schin 			if (!X(catalog))
3642*4887Schin 				sfputc(mp, ' ');
3643*4887Schin 			else if (p = sfstruse(tp))
3644*4887Schin 				sfputr(mp, T(error_info.id, catalog, p), ' ');
3645*4887Schin 			else
3646*4887Schin 				goto nospace;
3647*4887Schin 		}
3648*4887Schin 		p = opt_info.name[2] ? C("value expected") : C("argument expected");
3649*4887Schin 	}
3650*4887Schin 	else if (*p == '*' || *p == '&')
3651*4887Schin 	{
3652*4887Schin 		sfputr(mp, opt_info.arg, ':');
3653*4887Schin 		sfputc(mp, ' ');
3654*4887Schin 		p = *p == '&' ? C("ambiguous option argument value") : C("unknown option argument value");
3655*4887Schin 	}
3656*4887Schin 	else if (*p == '=' || *p == '!')
3657*4887Schin 		p = C("value not expected");
3658*4887Schin 	else if (*p == '?')
3659*4887Schin 		p = *(p + 1) == '?' ? C("optget: option not supported") : C("ambiguous option");
3660*4887Schin 	else if (*p == '+')
3661*4887Schin 		p = C("section not found");
3662*4887Schin 	else
3663*4887Schin 	{
3664*4887Schin 		if (opt_info.option[0] != '?' && opt_info.option[0] != '-' || opt_info.option[1] != '?' && opt_info.option[1] != '-')
3665*4887Schin 			opt_info.option[0] = 0;
3666*4887Schin 		p = C("unknown option");
3667*4887Schin 	}
3668*4887Schin 	p = T(NiL, ID, p);
3669*4887Schin 	sfputr(mp, p, -1);
3670*4887Schin 	if (err)
3671*4887Schin 		sfputr(mp, " -- out of range", -1);
3672*4887Schin 	if (opt_info.arg = sfstruse(mp))
3673*4887Schin 		return ':';
3674*4887Schin  nospace:
3675*4887Schin 	opt_info.arg = T(NiL, ID, "[* out of space *]");
3676*4887Schin 	return ':';
3677*4887Schin }
3678*4887Schin 
3679*4887Schin /*
3680*4887Schin  * argv:	command line argv where argv[0] is command name
3681*4887Schin  *
3682*4887Schin  * opts:	option control string
3683*4887Schin  *
3684*4887Schin  *	'[' [flag][=][index][:<long-name>[|<alias-name>...]['?'description]] ']'
3685*4887Schin  *			long option name, index, description; -index returned
3686*4887Schin  *	':'		option takes string arg
3687*4887Schin  *	'#'		option takes numeric arg (concat option may follow)
3688*4887Schin  *	'?'		(option) following options not in usage
3689*4887Schin  *			(following # or :) optional arg
3690*4887Schin  *	'[' '[' ... ] ... '[' ... ']' ']'
3691*4887Schin  *			mutually exclusive option grouping
3692*4887Schin  *	'[' name [:attr]* [?description] ']'
3693*4887Schin  *			(following # or :) optional option arg description
3694*4887Schin  *	'\n'[' '|'\t']*	ignored for legibility
3695*4887Schin  *	' ' ...		optional argument(s) description (to end of string)
3696*4887Schin  *			or after blank line
3697*4887Schin  *	']]'		literal ']' within '[' ... ']'
3698*4887Schin  *
3699*4887Schin  * return:
3700*4887Schin  *	0		no more options
3701*4887Schin  *	'?'		usage: opt_info.arg points to message sans
3702*4887Schin  *			`Usage: command '
3703*4887Schin  *	':'		error: opt_info.arg points to message sans `command: '
3704*4887Schin  *
3705*4887Schin  * '-' '+' '?' ':' '#' '[' ']' ' '
3706*4887Schin  *			invalid option chars
3707*4887Schin  *
3708*4887Schin  * -- terminates option list and returns 0
3709*4887Schin  *
3710*4887Schin  * + as first opts char makes + equivalent to -
3711*4887Schin  *
3712*4887Schin  * if any # option is specified then numeric options (e.g., -123)
3713*4887Schin  * are associated with the leftmost # option in opts
3714*4887Schin  *
3715*4887Schin  * usage info in placed opt_info.arg when '?' returned
3716*4887Schin  * see help_text[] (--???) for more info
3717*4887Schin  */
3718*4887Schin 
3719*4887Schin int
3720*4887Schin optget(register char** argv, const char* oopts)
3721*4887Schin {
3722*4887Schin 	register int	c;
3723*4887Schin 	register char*	s;
3724*4887Schin 	char*		a;
3725*4887Schin 	char*		b;
3726*4887Schin 	char*		e;
3727*4887Schin 	char*		f;
3728*4887Schin 	char*		g;
3729*4887Schin 	char*		v;
3730*4887Schin 	char*		w;
3731*4887Schin 	char*		p;
3732*4887Schin 	char*		q;
3733*4887Schin 	char*		t;
3734*4887Schin 	char*		y;
3735*4887Schin 	char*		numopt;
3736*4887Schin 	char*		opts;
3737*4887Schin 	char*		catalog;
3738*4887Schin 	int		n;
3739*4887Schin 	int		m;
3740*4887Schin 	int		k;
3741*4887Schin 	int		j;
3742*4887Schin 	int		x;
3743*4887Schin 	int		err;
3744*4887Schin 	int		no;
3745*4887Schin 	int		nov;
3746*4887Schin 	int		num;
3747*4887Schin 	int		numchr;
3748*4887Schin 	int		prefix;
3749*4887Schin 	int		version;
3750*4887Schin 	Help_t*		hp;
3751*4887Schin 	Push_t*		psp;
3752*4887Schin 	Push_t*		tsp;
3753*4887Schin 	Sfio_t*		vp;
3754*4887Schin 	Sfio_t*		xp;
3755*4887Schin 	Optcache_t*	cache;
3756*4887Schin 	Optcache_t*	pcache;
3757*4887Schin 	Optpass_t*	pass;
3758*4887Schin 
3759*4887Schin #if !_YOU_FIGURED_OUT_HOW_TO_GET_ALL_DLLS_TO_DO_THIS_
3760*4887Schin 	/*
3761*4887Schin 	 * these are not initialized by all dlls!
3762*4887Schin 	 */
3763*4887Schin 
3764*4887Schin 	extern Error_info_t	_error_info_;
3765*4887Schin 	extern Opt_t		_opt_info_;
3766*4887Schin 
3767*4887Schin 	if (!_error_infop_)
3768*4887Schin 		_error_infop_ = &_error_info_;
3769*4887Schin 	if (!_opt_infop_)
3770*4887Schin 		_opt_infop_ = &_opt_info_;
3771*4887Schin 	if (!opt_info.state)
3772*4887Schin 		opt_info.state = &state;
3773*4887Schin #endif
3774*4887Schin 	if (!oopts)
3775*4887Schin 		return 0;
3776*4887Schin 	opt_info.state->pindex = opt_info.index;
3777*4887Schin 	opt_info.state->poffset = opt_info.offset;
3778*4887Schin 	if (!opt_info.index)
3779*4887Schin 	{
3780*4887Schin 		opt_info.index = 1;
3781*4887Schin 		opt_info.offset = 0;
3782*4887Schin 		if (opt_info.state->npass)
3783*4887Schin 		{
3784*4887Schin 			opt_info.state->npass = 0;
3785*4887Schin 			opt_info.state->join = 0;
3786*4887Schin 		}
3787*4887Schin 	}
3788*4887Schin 	if (!argv)
3789*4887Schin 		cache = 0;
3790*4887Schin 	else
3791*4887Schin 		for (pcache = 0, cache = opt_info.state->cache; cache; pcache = cache, cache = cache->next)
3792*4887Schin 			if (cache->pass.oopts == (char*)oopts)
3793*4887Schin 				break;
3794*4887Schin 	if (cache)
3795*4887Schin 	{
3796*4887Schin 		if (pcache)
3797*4887Schin 		{
3798*4887Schin 			pcache->next = cache->next;
3799*4887Schin 			cache->next = opt_info.state->cache;
3800*4887Schin 			opt_info.state->cache = cache;
3801*4887Schin 		}
3802*4887Schin 		pass = &cache->pass;
3803*4887Schin 		opt_info.state->npass = -1;
3804*4887Schin 	}
3805*4887Schin 	else
3806*4887Schin 	{
3807*4887Schin 		if (!argv)
3808*4887Schin 			n = opt_info.state->npass ? opt_info.state->npass : 1;
3809*4887Schin 		else if ((n = opt_info.state->join - 1) < 0)
3810*4887Schin 			n = 0;
3811*4887Schin 		if (n >= opt_info.state->npass || opt_info.state->pass[n].oopts != (char*)oopts)
3812*4887Schin 		{
3813*4887Schin 			for (m = 0; m < opt_info.state->npass && opt_info.state->pass[m].oopts != (char*)oopts; m++);
3814*4887Schin 			if (m < opt_info.state->npass)
3815*4887Schin 				n = m;
3816*4887Schin 			else
3817*4887Schin 			{
3818*4887Schin 				if (n >= elementsof(opt_info.state->pass))
3819*4887Schin 					n = elementsof(opt_info.state->pass) - 1;
3820*4887Schin 				init((char*)oopts, &opt_info.state->pass[n]);
3821*4887Schin 				if (opt_info.state->npass <= n)
3822*4887Schin 					opt_info.state->npass = n + 1;
3823*4887Schin 			}
3824*4887Schin 		}
3825*4887Schin 		if (!argv)
3826*4887Schin 			return 0;
3827*4887Schin 		pass = &opt_info.state->pass[n];
3828*4887Schin 	}
3829*4887Schin 	opts = pass->opts;
3830*4887Schin 	prefix = pass->prefix;
3831*4887Schin 	version = pass->version;
3832*4887Schin 	if (!(xp = opt_info.state->xp) || (catalog = pass->catalog) && !X(catalog))
3833*4887Schin 		catalog = 0;
3834*4887Schin 	else /* if (!error_info.catalog) */
3835*4887Schin 		error_info.catalog = catalog;
3836*4887Schin  again:
3837*4887Schin 	psp = 0;
3838*4887Schin 
3839*4887Schin 	/*
3840*4887Schin 	 * check if any options remain and determine if the
3841*4887Schin 	 * next option is short or long
3842*4887Schin 	 */
3843*4887Schin 
3844*4887Schin 	opt_info.assignment = 0;
3845*4887Schin 	num = 1;
3846*4887Schin 	w = v = 0;
3847*4887Schin 	x = 0;
3848*4887Schin 	for (;;)
3849*4887Schin 	{
3850*4887Schin 		if (!opt_info.offset)
3851*4887Schin 		{
3852*4887Schin 			/*
3853*4887Schin 			 * finished with the previous arg
3854*4887Schin 			 */
3855*4887Schin 
3856*4887Schin 			if (opt_info.index == 1 && opt_info.argv != opt_info.state->strv)
3857*4887Schin 			{
3858*4887Schin 				opt_info.argv = 0;
3859*4887Schin 				opt_info.state->argv[0] = 0;
3860*4887Schin 				if (argv[0] && (opt_info.state->argv[0] = save(argv[0])))
3861*4887Schin 					opt_info.argv = opt_info.state->argv;
3862*4887Schin 				opt_info.state->style = STYLE_short;
3863*4887Schin 			}
3864*4887Schin 			if (!(s = argv[opt_info.index]))
3865*4887Schin 				return 0;
3866*4887Schin 			if (!prefix)
3867*4887Schin 			{
3868*4887Schin 				/*
3869*4887Schin 				 * long with no prefix (dd style)
3870*4887Schin 				 */
3871*4887Schin 
3872*4887Schin 				n = 2;
3873*4887Schin 				if ((c = *s) != '-' && c != '+')
3874*4887Schin 					c = '-';
3875*4887Schin 				else if (*++s == c)
3876*4887Schin 				{
3877*4887Schin 					if (!*++s)
3878*4887Schin 					{
3879*4887Schin 						opt_info.index++;
3880*4887Schin 						return 0;
3881*4887Schin 					}
3882*4887Schin 				}
3883*4887Schin 				else if (*s == '?')
3884*4887Schin 					n = 1;
3885*4887Schin 			}
3886*4887Schin 			else if ((c = *s++) != '-' && (c != '+' || !(pass->flags & OPT_plus) && (*s < '0' || *s > '9' || !strmatch(opts, version ? "*\\]#\\[*" : "*#*"))))
3887*4887Schin 			{
3888*4887Schin 				if (!(pass->flags & OPT_old) || !isalpha(c))
3889*4887Schin 					return 0;
3890*4887Schin 				s--;
3891*4887Schin 				n = 1;
3892*4887Schin 				opt_info.offset--;
3893*4887Schin 			}
3894*4887Schin 			else if (*s == c)
3895*4887Schin 			{
3896*4887Schin 				if (!*++s)
3897*4887Schin 				{
3898*4887Schin 					/*
3899*4887Schin 					 * -- or ++ end of options
3900*4887Schin 					 */
3901*4887Schin 
3902*4887Schin 					opt_info.index++;
3903*4887Schin 					return 0;
3904*4887Schin 				}
3905*4887Schin 				if (version || *s == '?' || !(pass->flags & OPT_minus))
3906*4887Schin 				{
3907*4887Schin 					/*
3908*4887Schin 					 * long with double prefix
3909*4887Schin 					 */
3910*4887Schin 
3911*4887Schin 					n = 2;
3912*4887Schin 				}
3913*4887Schin 				else
3914*4887Schin 				{
3915*4887Schin 					/*
3916*4887Schin 					 * short option char '-'
3917*4887Schin 					 */
3918*4887Schin 
3919*4887Schin 					s--;
3920*4887Schin 					n = 1;
3921*4887Schin 				}
3922*4887Schin 			}
3923*4887Schin 			else if (prefix == 1 && *s != '?')
3924*4887Schin 			{
3925*4887Schin 				/*
3926*4887Schin 				 * long with single prefix (find style)
3927*4887Schin 				 */
3928*4887Schin 
3929*4887Schin 				n = 2;
3930*4887Schin 			}
3931*4887Schin 			else
3932*4887Schin 			{
3933*4887Schin 				/*
3934*4887Schin 				 * short (always with single prefix)
3935*4887Schin 				 */
3936*4887Schin 
3937*4887Schin 				n = 1;
3938*4887Schin 			}
3939*4887Schin 
3940*4887Schin 			/*
3941*4887Schin 			 * just a prefix is an option (e.g., `-' == stdin)
3942*4887Schin 			 */
3943*4887Schin 
3944*4887Schin 			if (!*s)
3945*4887Schin 				return 0;
3946*4887Schin 			if (c == '+')
3947*4887Schin 				opt_info.arg = 0;
3948*4887Schin 			if (n == 2)
3949*4887Schin 			{
3950*4887Schin 				x = 0;
3951*4887Schin 				opt_info.state->style = STYLE_long;
3952*4887Schin 				opt_info.option[0] = opt_info.name[0] = opt_info.name[1] = c;
3953*4887Schin 				w = &opt_info.name[prefix];
3954*4887Schin 				if ((*s == 'n' || *s == 'N') && (*(s + 1) == 'o' || *(s + 1) == 'O') && *(s + 2) && *(s + 2) != '=')
3955*4887Schin 					no = *(s + 2) == '-' ? 3 : 2;
3956*4887Schin 				else
3957*4887Schin 					no = 0;
3958*4887Schin 				for (c = *s; *s; s++)
3959*4887Schin 				{
3960*4887Schin 					if (*s == '=')
3961*4887Schin 					{
3962*4887Schin 						if (*(s + 1) == '=')
3963*4887Schin 							s++;
3964*4887Schin 						if (!isalnum(*(s - 1)) && *(w - 1) == (opt_info.assignment = *(s - 1)))
3965*4887Schin 							w--;
3966*4887Schin 						v = ++s;
3967*4887Schin 						break;
3968*4887Schin 					}
3969*4887Schin 					if (w < &opt_info.name[elementsof(opt_info.name) - 1] && *s != ':' && *s != '|' && *s != '[' && *s != ']')
3970*4887Schin 						*w++ = *s;
3971*4887Schin 				}
3972*4887Schin 				*w = 0;
3973*4887Schin 				w = &opt_info.name[prefix];
3974*4887Schin 				c = *w;
3975*4887Schin 				opt_info.offset = 0;
3976*4887Schin 				opt_info.index++;
3977*4887Schin 				break;
3978*4887Schin 			}
3979*4887Schin 			opt_info.offset++;
3980*4887Schin 		}
3981*4887Schin 		if (!argv[opt_info.index])
3982*4887Schin 			return 0;
3983*4887Schin 		if (c = argv[opt_info.index][opt_info.offset++])
3984*4887Schin 		{
3985*4887Schin 			if ((k = argv[opt_info.index][0]) != '-' && k != '+')
3986*4887Schin 				k = '-';
3987*4887Schin 			opt_info.option[0] = opt_info.name[0] = k;
3988*4887Schin 			opt_info.option[1] = opt_info.name[1] = c;
3989*4887Schin 			opt_info.option[2] = opt_info.name[2] = 0;
3990*4887Schin 			break;
3991*4887Schin 		}
3992*4887Schin 		opt_info.offset = 0;
3993*4887Schin 		opt_info.index++;
3994*4887Schin 	}
3995*4887Schin 
3996*4887Schin 	/*
3997*4887Schin 	 * at this point:
3998*4887Schin 	 *
3999*4887Schin 	 *	c	the first character of the option
4000*4887Schin 	 *	w	long option name if != 0, otherwise short
4001*4887Schin 	 *	v	long option value (via =) if w != 0
4002*4887Schin 	 */
4003*4887Schin 
4004*4887Schin 	if (c == '?')
4005*4887Schin 	{
4006*4887Schin 		/*
4007*4887Schin 		 * ? always triggers internal help
4008*4887Schin 		 */
4009*4887Schin 
4010*4887Schin 		if (w && !v && (*(w + 1) || !(v = argv[opt_info.index]) || !++opt_info.index))
4011*4887Schin 			v = w + 1;
4012*4887Schin 		opt_info.option[1] = c;
4013*4887Schin 		opt_info.option[2] = 0;
4014*4887Schin 		if (!w)
4015*4887Schin 		{
4016*4887Schin 			opt_info.name[1] = c;
4017*4887Schin 			opt_info.name[2] = 0;
4018*4887Schin 		}
4019*4887Schin 		goto help;
4020*4887Schin 	}
4021*4887Schin 	numopt = 0;
4022*4887Schin 	f = 0;
4023*4887Schin 	s = opts;
4024*4887Schin 
4025*4887Schin 	/*
4026*4887Schin 	 * no option can start with these characters
4027*4887Schin 	 */
4028*4887Schin 
4029*4887Schin 	if (c == ':' || c == '#' || c == ' ' || c == '[' || c == ']')
4030*4887Schin 	{
4031*4887Schin 		if (c != *s)
4032*4887Schin 			s = "";
4033*4887Schin 	}
4034*4887Schin 	else
4035*4887Schin 	{
4036*4887Schin 		a = 0;
4037*4887Schin 		if (!w && (pass->flags & OPT_cache))
4038*4887Schin 		{
4039*4887Schin 			if (cache)
4040*4887Schin 			{
4041*4887Schin 				if (k = cache->flags[map[c]])
4042*4887Schin 				{
4043*4887Schin 					opt_info.arg = 0;
4044*4887Schin 
4045*4887Schin 					/*
4046*4887Schin 					 * this is a ksh getopts workaround
4047*4887Schin 					 */
4048*4887Schin 
4049*4887Schin 					if (opt_info.num != LONG_MIN)
4050*4887Schin 						opt_info.num = opt_info.number = !(k & OPT_cache_invert);
4051*4887Schin 					if (!(k & (OPT_cache_string|OPT_cache_numeric)))
4052*4887Schin 						return c;
4053*4887Schin 					if (*(opt_info.arg = &argv[opt_info.index++][opt_info.offset]))
4054*4887Schin 					{
4055*4887Schin 						if (!(k & OPT_cache_numeric))
4056*4887Schin 						{
4057*4887Schin 							opt_info.offset = 0;
4058*4887Schin 							return c;
4059*4887Schin 						}
4060*4887Schin 						opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
4061*4887Schin 						if (err || e == opt_info.arg)
4062*4887Schin 						{
4063*4887Schin 							if (!err && (k & OPT_cache_optional))
4064*4887Schin 							{
4065*4887Schin 								opt_info.arg = 0;
4066*4887Schin 								opt_info.index--;
4067*4887Schin 								return c;
4068*4887Schin 							}
4069*4887Schin 						}
4070*4887Schin 						else if (*e)
4071*4887Schin 						{
4072*4887Schin 							opt_info.offset += e - opt_info.arg;
4073*4887Schin 							opt_info.index--;
4074*4887Schin 							return c;
4075*4887Schin 						}
4076*4887Schin 						else
4077*4887Schin 						{
4078*4887Schin 							opt_info.offset = 0;
4079*4887Schin 							return c;
4080*4887Schin 						}
4081*4887Schin 					}
4082*4887Schin 					else if (opt_info.arg = argv[opt_info.index])
4083*4887Schin 					{
4084*4887Schin 						opt_info.index++;
4085*4887Schin 						if ((k & OPT_cache_optional) && (*opt_info.arg == '-' || (pass->flags & OPT_plus) && *opt_info.arg == '+') && *(opt_info.arg + 1))
4086*4887Schin 						{
4087*4887Schin 							opt_info.arg = 0;
4088*4887Schin 							opt_info.index--;
4089*4887Schin 							opt_info.offset = 0;
4090*4887Schin 							return c;
4091*4887Schin 						}
4092*4887Schin 						if (k & OPT_cache_string)
4093*4887Schin 						{
4094*4887Schin 							opt_info.offset = 0;
4095*4887Schin 							return c;
4096*4887Schin 						}
4097*4887Schin 						opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
4098*4887Schin 						if (!err)
4099*4887Schin 						{
4100*4887Schin 							if (!*e)
4101*4887Schin 							{
4102*4887Schin 								opt_info.offset = 0;
4103*4887Schin 								return c;
4104*4887Schin 							}
4105*4887Schin 							if (k & OPT_cache_optional)
4106*4887Schin 							{
4107*4887Schin 								opt_info.arg = 0;
4108*4887Schin 								opt_info.index--;
4109*4887Schin 								opt_info.offset = 0;
4110*4887Schin 								return c;
4111*4887Schin 							}
4112*4887Schin 						}
4113*4887Schin 					}
4114*4887Schin 					else if (k & OPT_cache_optional)
4115*4887Schin 					{
4116*4887Schin 						opt_info.offset = 0;
4117*4887Schin 						return c;
4118*4887Schin 					}
4119*4887Schin 					opt_info.index--;
4120*4887Schin 				}
4121*4887Schin 				cache = 0;
4122*4887Schin 			}
4123*4887Schin 			else if (cache = newof(0, Optcache_t, 1, 0))
4124*4887Schin 			{
4125*4887Schin 				cache->caching = c;
4126*4887Schin 				c = 0;
4127*4887Schin 				cache->pass = *pass;
4128*4887Schin 				cache->next = opt_info.state->cache;
4129*4887Schin 				opt_info.state->cache = cache;
4130*4887Schin 			}
4131*4887Schin 		}
4132*4887Schin 		else
4133*4887Schin 			cache = 0;
4134*4887Schin 		for (;;)
4135*4887Schin 		{
4136*4887Schin 			if (!(*(s = next(s, version))) || *s == '\n' || *s == ' ')
4137*4887Schin 			{
4138*4887Schin 				if (!(tsp = psp))
4139*4887Schin 				{
4140*4887Schin 					if (cache)
4141*4887Schin 					{
4142*4887Schin 						/*
4143*4887Schin 						 * the first loop pass
4144*4887Schin 						 * initialized the cache
4145*4887Schin 						 * so one more pass to
4146*4887Schin 						 * check the cache or
4147*4887Schin 						 * bail for a full scan
4148*4887Schin 						 */
4149*4887Schin 
4150*4887Schin 						cache->flags[0] = 0;
4151*4887Schin 						c = cache->caching;
4152*4887Schin 						cache->caching = 0;
4153*4887Schin 						cache = 0;
4154*4887Schin 						s = opts;
4155*4887Schin 						continue;
4156*4887Schin 					}
4157*4887Schin 					if (!x && catalog)
4158*4887Schin 					{
4159*4887Schin 						/*
4160*4887Schin 						 * the first loop pass
4161*4887Schin 						 * translated long
4162*4887Schin 						 * options and there
4163*4887Schin 						 * were no matches so
4164*4887Schin 						 * one more pass for C
4165*4887Schin 						 * locale
4166*4887Schin 						 */
4167*4887Schin 
4168*4887Schin 						catalog = 0;
4169*4887Schin 						s = opts;
4170*4887Schin 						continue;
4171*4887Schin 					}
4172*4887Schin 					s = "";
4173*4887Schin 					break;
4174*4887Schin 				}
4175*4887Schin 				s = psp->ob;
4176*4887Schin 				psp = psp->next;
4177*4887Schin 				free(tsp);
4178*4887Schin 				continue;
4179*4887Schin 			}
4180*4887Schin 			if (*s == '\f')
4181*4887Schin 			{
4182*4887Schin 				psp = info(psp, s + 1, NiL, opt_info.state->xp);
4183*4887Schin 				if (psp->nb)
4184*4887Schin 					s = psp->nb;
4185*4887Schin 				else
4186*4887Schin 				{
4187*4887Schin 					s = psp->ob;
4188*4887Schin 					psp = psp->next;
4189*4887Schin 				}
4190*4887Schin 				continue;
4191*4887Schin 			}
4192*4887Schin 			message((-20, "optget: opt %s w %s num %ld", show(s), w, num));
4193*4887Schin 			if (*s == c && !w)
4194*4887Schin 				break;
4195*4887Schin 			else if (*s == '[')
4196*4887Schin 			{
4197*4887Schin 				f = s = next(s + 1, version);
4198*4887Schin 				k = *f;
4199*4887Schin 				if (k == '+' || k == '-')
4200*4887Schin 					/* ignore */;
4201*4887Schin 				else if (k == '[' || version < 1)
4202*4887Schin 					continue;
4203*4887Schin 				else if (w && !cache)
4204*4887Schin 				{
4205*4887Schin 					nov = no;
4206*4887Schin 					if (*(s + 1) == '\f' && (vp = opt_info.state->vp))
4207*4887Schin 					{
4208*4887Schin 						sfputc(vp, k);
4209*4887Schin 						s = expand(s + 2, NiL, &t, vp);
4210*4887Schin 						if (*s)
4211*4887Schin 							*(f = s - 1) = k;
4212*4887Schin 						else
4213*4887Schin 						{
4214*4887Schin 							f = sfstrbase(vp);
4215*4887Schin 							if (s = strrchr(f, ':'))
4216*4887Schin 								f = s - 1;
4217*4887Schin 							else
4218*4887Schin 								s = f + 1;
4219*4887Schin 						}
4220*4887Schin 					}
4221*4887Schin 					else
4222*4887Schin 						t = 0;
4223*4887Schin 					if (*s != ':')
4224*4887Schin 						s = skip(s, ':', '?', 0, 1, 0, 0, version);
4225*4887Schin 					if (*s == ':')
4226*4887Schin 					{
4227*4887Schin 						if (catalog)
4228*4887Schin 						{
4229*4887Schin 							p = skip(s + 1, '?', 0, 0, 1, 0, 0, version);
4230*4887Schin 							e = sfprints("%-.*s", p - (s + 1), s + 1);
4231*4887Schin 							g = T(error_info.id, catalog, e);
4232*4887Schin 							if (g == e)
4233*4887Schin 								p = 0;
4234*4887Schin 							else
4235*4887Schin 							{
4236*4887Schin 								sfprintf(xp, ":%s|%s?", g, e);
4237*4887Schin 								if (!(s = sfstruse(xp)))
4238*4887Schin 									goto nospace;
4239*4887Schin 							}
4240*4887Schin 						}
4241*4887Schin 						else
4242*4887Schin 							p = 0;
4243*4887Schin 						y = w;
4244*4887Schin 						for (;;)
4245*4887Schin 						{
4246*4887Schin 							n = m = 0;
4247*4887Schin 							e = s + 1;
4248*4887Schin 							while (*++s)
4249*4887Schin 							{
4250*4887Schin 								if (*s == '*' || *s == '\a')
4251*4887Schin 								{
4252*4887Schin 									if (*s == '\a')
4253*4887Schin 										do
4254*4887Schin 										{
4255*4887Schin 											if (!*++s)
4256*4887Schin 											{
4257*4887Schin 												s--;
4258*4887Schin 												break;
4259*4887Schin 											}
4260*4887Schin 										} while (*s != '\a');
4261*4887Schin 									j = *(s + 1);
4262*4887Schin 									if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
4263*4887Schin 									{
4264*4887Schin 										while (*w)
4265*4887Schin 											w++;
4266*4887Schin 										m = 0;
4267*4887Schin 										break;
4268*4887Schin 									}
4269*4887Schin 									m = 1;
4270*4887Schin 								}
4271*4887Schin 								else if (*s == *w || sep(*s) && sep(*w))
4272*4887Schin 									w++;
4273*4887Schin 								else if (*w == 0)
4274*4887Schin 									break;
4275*4887Schin 								else if (!sep(*s))
4276*4887Schin 								{
4277*4887Schin 									if (sep(*w))
4278*4887Schin 									{
4279*4887Schin 										if (*++w == *s)
4280*4887Schin 										{
4281*4887Schin 											w++;
4282*4887Schin 											continue;
4283*4887Schin 										}
4284*4887Schin 									}
4285*4887Schin 									else if (w == y || sep(*(w - 1)) || isupper(*(w - 1)) && islower(*w))
4286*4887Schin 										break;
4287*4887Schin 									for (q = s; *q && !sep(*q) && *q != '|' && *q != '?' && *q != ']'; q++);
4288*4887Schin 									if (!sep(*q))
4289*4887Schin 										break;
4290*4887Schin 									for (s = q; w > y && *w != *(s + 1); w--);
4291*4887Schin 								}
4292*4887Schin 								else if (*w != *(s + 1))
4293*4887Schin 									break;
4294*4887Schin 							}
4295*4887Schin 							if (!*w)
4296*4887Schin 							{
4297*4887Schin 								nov = 0;
4298*4887Schin 								break;
4299*4887Schin 							}
4300*4887Schin 							if (n = no)
4301*4887Schin 							{
4302*4887Schin 								m = 0;
4303*4887Schin 								s = e - 1;
4304*4887Schin 								w = y + n;
4305*4887Schin 								while (*++s)
4306*4887Schin 								{
4307*4887Schin 									if (*s == '*' || *s == '\a')
4308*4887Schin 									{
4309*4887Schin 										if (*s == '\a')
4310*4887Schin 											do
4311*4887Schin 											{
4312*4887Schin 												if (!*++s)
4313*4887Schin 												{
4314*4887Schin 													s--;
4315*4887Schin 													break;
4316*4887Schin 												}
4317*4887Schin 											} while (*s != '\a');
4318*4887Schin 										j = *(s + 1);
4319*4887Schin 										if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
4320*4887Schin 										{
4321*4887Schin 											while (*w)
4322*4887Schin 												w++;
4323*4887Schin 											m = 0;
4324*4887Schin 											break;
4325*4887Schin 										}
4326*4887Schin 										m = 1;
4327*4887Schin 									}
4328*4887Schin 									else if (*s == *w || sep(*s) && sep(*w))
4329*4887Schin 										w++;
4330*4887Schin 									else if (*w == 0)
4331*4887Schin 										break;
4332*4887Schin 									else if (!sep(*s))
4333*4887Schin 									{
4334*4887Schin 										if (sep(*w))
4335*4887Schin 										{
4336*4887Schin 											if (*++w == *s)
4337*4887Schin 											{
4338*4887Schin 												w++;
4339*4887Schin 												continue;
4340*4887Schin 											}
4341*4887Schin 										}
4342*4887Schin 										else if (w == y || sep(*(w - 1)) || isupper(*(w - 1)) && islower(*w))
4343*4887Schin 											break;
4344*4887Schin 										for (q = s; *q && !sep(*q) && *q != '|' && *q != '?' && *q != ']'; q++);
4345*4887Schin 										if (!sep(*q))
4346*4887Schin 											break;
4347*4887Schin 										for (s = q; w > y && *w != *(s + 1); w--);
4348*4887Schin 									}
4349*4887Schin 									else if (*w != *(s + 1))
4350*4887Schin 										break;
4351*4887Schin 								}
4352*4887Schin 								if (!*w)
4353*4887Schin 									break;
4354*4887Schin 							}
4355*4887Schin 							if (*(s = skip(s, ':', '|', '?', 1, 0, 0, version)) != '|')
4356*4887Schin 								break;
4357*4887Schin 							w = y;
4358*4887Schin 						}
4359*4887Schin 						if (p)
4360*4887Schin 							s = p;
4361*4887Schin 						if (!*w)
4362*4887Schin 						{
4363*4887Schin 							if (n)
4364*4887Schin 								num = 0;
4365*4887Schin 							if (!(n = (m || *s == ':' || *s == '|' || *s == '?' || *s == ']' || *s == 0)) && x)
4366*4887Schin 							{
4367*4887Schin 								psp = pop(psp);
4368*4887Schin 								return opterror("?", version, catalog, 0);
4369*4887Schin 							}
4370*4887Schin 							for (x = k; *(f + 1) == '|' && (j = *(f + 2)) && j != '!' && j != '=' && j != ':' && j != '?' && j != ']'; f += 2);
4371*4887Schin 							if (*f == ':')
4372*4887Schin 							{
4373*4887Schin 								x = -1;
4374*4887Schin 								opt_info.option[1] = '-';
4375*4887Schin 								opt_info.option[2] = 0;
4376*4887Schin 							}
4377*4887Schin 							else if (*(f + 1) == ':' || *(f + 1) == '!' && *(f + 2) == ':')
4378*4887Schin 							{
4379*4887Schin 								opt_info.option[1] = x;
4380*4887Schin 								opt_info.option[2] = 0;
4381*4887Schin 							}
4382*4887Schin 							else
4383*4887Schin 							{
4384*4887Schin 								a = f;
4385*4887Schin 								if (*a == '=')
4386*4887Schin 									a++;
4387*4887Schin 								else
4388*4887Schin 								{
4389*4887Schin 									if (*(a + 1) == '!')
4390*4887Schin 										a++;
4391*4887Schin 									if (*(a + 1) == '=')
4392*4887Schin 										a += 2;
4393*4887Schin 								}
4394*4887Schin 								x = -strtol(a, &b, 0);
4395*4887Schin 								if ((b - a) > sizeof(opt_info.option) - 2)
4396*4887Schin 									b = a + sizeof(opt_info.option) - 2;
4397*4887Schin 								memcpy(&opt_info.option[1], a, b - a);
4398*4887Schin 								opt_info.option[b - a + 1] = 0;
4399*4887Schin 							}
4400*4887Schin 							b = e;
4401*4887Schin 							if (t)
4402*4887Schin 							{
4403*4887Schin 								s = t;
4404*4887Schin 								t = 0;
4405*4887Schin 							}
4406*4887Schin 							a = s = skip(s, 0, 0, 0, 1, 0, 0, version);
4407*4887Schin 							if (n)
4408*4887Schin 							{
4409*4887Schin 								w = y;
4410*4887Schin 								break;
4411*4887Schin 							}
4412*4887Schin 						}
4413*4887Schin 						w = y;
4414*4887Schin 					}
4415*4887Schin 					else if (k == c && prefix == 1)
4416*4887Schin 					{
4417*4887Schin 						w = 0;
4418*4887Schin 						opt_info.name[1] = c;
4419*4887Schin 						opt_info.name[2] = 0;
4420*4887Schin 						opt_info.offset = 2;
4421*4887Schin 						opt_info.index--;
4422*4887Schin 						break;
4423*4887Schin 					}
4424*4887Schin 					if (t)
4425*4887Schin 					{
4426*4887Schin 						s = t;
4427*4887Schin 						if (a)
4428*4887Schin 							a = t;
4429*4887Schin 					}
4430*4887Schin 				}
4431*4887Schin 				s = skip(s, 0, 0, 0, 1, 0, 1, version);
4432*4887Schin 				if (*s == GO)
4433*4887Schin 					s = skip(s + 1, 0, 0, 0, 0, 1, 1, version);
4434*4887Schin 				if (cache)
4435*4887Schin 				{
4436*4887Schin 					m = OPT_cache_flag;
4437*4887Schin 					v = s;
4438*4887Schin 					if (*v == '#')
4439*4887Schin 					{
4440*4887Schin 						v++;
4441*4887Schin 						m |= OPT_cache_numeric;
4442*4887Schin 					}
4443*4887Schin 					else if (*v == ':')
4444*4887Schin 					{
4445*4887Schin 						v++;
4446*4887Schin 						m |= OPT_cache_string;
4447*4887Schin 					}
4448*4887Schin 					if (*v == '?')
4449*4887Schin 					{
4450*4887Schin 						v++;
4451*4887Schin 						m |= OPT_cache_optional;
4452*4887Schin 					}
4453*4887Schin 					else if (*v == *(v - 1))
4454*4887Schin 						v++;
4455*4887Schin 					if (*(v = next(v, version)) == '[')
4456*4887Schin 						v = skip(v + 1, 0, 0, 0, 1, 0, 1, version);
4457*4887Schin 					if (*v != GO)
4458*4887Schin 					{
4459*4887Schin 						v = f;
4460*4887Schin 						for (;;)
4461*4887Schin 						{
4462*4887Schin 							if (isdigit(*f) && isdigit(*(f + 1)))
4463*4887Schin 								while (isdigit(*(f + 1)))
4464*4887Schin 									f++;
4465*4887Schin 							else if (*(f + 1) == '=')
4466*4887Schin 								break;
4467*4887Schin 							else
4468*4887Schin 								cache->flags[map[*f]] = m;
4469*4887Schin 							j = 0;
4470*4887Schin 							while (*(f + 1) == '|')
4471*4887Schin 							{
4472*4887Schin 								f += 2;
4473*4887Schin 								if (!(j = *f) || j == '!' || j == '=' || j == ':' || j == '?' || j == ']')
4474*4887Schin 									break;
4475*4887Schin 								cache->flags[map[j]] = m;
4476*4887Schin 							}
4477*4887Schin 							if (j != '!' || (m & OPT_cache_invert))
4478*4887Schin 								break;
4479*4887Schin 							f = v;
4480*4887Schin 							m |= OPT_cache_invert;
4481*4887Schin 						}
4482*4887Schin 					}
4483*4887Schin 				}
4484*4887Schin 				else
4485*4887Schin 				{
4486*4887Schin 					m = 0;
4487*4887Schin 					if (!w)
4488*4887Schin 					{
4489*4887Schin 						if (isdigit(*f) && isdigit(*(f + 1)))
4490*4887Schin 							k = -1;
4491*4887Schin 						if (c == k)
4492*4887Schin 							m = 1;
4493*4887Schin 						while (*(f + 1) == '|')
4494*4887Schin 						{
4495*4887Schin 							f += 2;
4496*4887Schin 							if (!(j = *f))
4497*4887Schin 							{
4498*4887Schin 								m = 0;
4499*4887Schin 								break;
4500*4887Schin 							}
4501*4887Schin 							else if (j == c)
4502*4887Schin 								m = 1;
4503*4887Schin 							else if (j == '!' || j == '=' || j == ':' || j == '?' || j == ']')
4504*4887Schin 								break;
4505*4887Schin 						}
4506*4887Schin 					}
4507*4887Schin 					if (m)
4508*4887Schin 					{
4509*4887Schin 						s--;
4510*4887Schin 						if (*++f == '!')
4511*4887Schin 						{
4512*4887Schin 							f++;
4513*4887Schin 							num = 0;
4514*4887Schin 						}
4515*4887Schin 						if (*f == '=')
4516*4887Schin 						{
4517*4887Schin 							c = -strtol(++f, &b, 0);
4518*4887Schin 							if ((b - f) > sizeof(opt_info.option) - 2)
4519*4887Schin 								b = f + sizeof(opt_info.option) - 2;
4520*4887Schin 							memcpy(&opt_info.option[1], f, b - f);
4521*4887Schin 							opt_info.option[b - f + 1] = 0;
4522*4887Schin 						}
4523*4887Schin 						else
4524*4887Schin 							c = k;
4525*4887Schin 						break;
4526*4887Schin 					}
4527*4887Schin 				}
4528*4887Schin 				if (*s == '#')
4529*4887Schin 				{
4530*4887Schin 					if (!numopt && s > opts)
4531*4887Schin 					{
4532*4887Schin 						numopt = s - 1;
4533*4887Schin 						numchr = k;
4534*4887Schin 						if (*f == ':')
4535*4887Schin 							numchr = -1;
4536*4887Schin 						else if (*(f + 1) != ':' && *(f + 1) != '!' && *(f + 1) != ']')
4537*4887Schin 						{
4538*4887Schin 							a = f;
4539*4887Schin 							if (*a == '=')
4540*4887Schin 								a++;
4541*4887Schin 							else
4542*4887Schin 							{
4543*4887Schin 								if (*(a + 1) == '!')
4544*4887Schin 									a++;
4545*4887Schin 								if (*(a + 1) == '=')
4546*4887Schin 									a += 2;
4547*4887Schin 							}
4548*4887Schin 							numchr = -strtol(a, NiL, 0);
4549*4887Schin 						}
4550*4887Schin 					}
4551*4887Schin 				}
4552*4887Schin 				else if (*s != ':')
4553*4887Schin 					continue;
4554*4887Schin 			}
4555*4887Schin 			else if (*s == ']')
4556*4887Schin 			{
4557*4887Schin 				s++;
4558*4887Schin 				continue;
4559*4887Schin 			}
4560*4887Schin 			else if (*s == '#')
4561*4887Schin 			{
4562*4887Schin 				if (!numopt && s > opts)
4563*4887Schin 					numchr = *(numopt = s - 1);
4564*4887Schin 			}
4565*4887Schin 			else if (*s != ':')
4566*4887Schin 			{
4567*4887Schin 				if (cache)
4568*4887Schin 				{
4569*4887Schin 					m = OPT_cache_flag;
4570*4887Schin 					if (*(s + 1) == '#')
4571*4887Schin 					{
4572*4887Schin 						m |= OPT_cache_numeric;
4573*4887Schin 						if (*(s + 2) == '?')
4574*4887Schin 							m |= OPT_cache_optional;
4575*4887Schin 					}
4576*4887Schin 					else if (*(s + 1) == ':')
4577*4887Schin 					{
4578*4887Schin 						m |= OPT_cache_string;
4579*4887Schin 						if (*(s + 2) == '?')
4580*4887Schin 							m |= OPT_cache_optional;
4581*4887Schin 					}
4582*4887Schin 					cache->flags[map[*s]] = m;
4583*4887Schin 				}
4584*4887Schin 				s++;
4585*4887Schin 				continue;
4586*4887Schin 			}
4587*4887Schin 			message((-21, "optget: opt %s", show(s)));
4588*4887Schin 			if (*++s == '?' || *s == *(s - 1))
4589*4887Schin 				s++;
4590*4887Schin 			if (*(s = next(s, version)) == '[')
4591*4887Schin 			{
4592*4887Schin 				s = skip(s + 1, 0, 0, 0, 1, 0, 1, version);
4593*4887Schin 				if (*s == GO)
4594*4887Schin 					s = skip(s + 1, 0, 0, 0, 0, 1, 1, version);
4595*4887Schin 			}
4596*4887Schin 		}
4597*4887Schin 		if (w && x)
4598*4887Schin 		{
4599*4887Schin 			s = skip(b, '|', '?', 0, 1, 0, 0, version);
4600*4887Schin 			if (v && (a == 0 || *a == 0 || *(a + 1) != ':' && *(a + 1) != '#') && (*v == '0' || *v == '1') && !*(v + 1))
4601*4887Schin 			{
4602*4887Schin 				if (*v == '0')
4603*4887Schin 					num = !num;
4604*4887Schin 				v = 0;
4605*4887Schin 			}
4606*4887Schin 			if ((s - b) >= elementsof(opt_info.name))
4607*4887Schin 				s = b + elementsof(opt_info.name) - 1;
4608*4887Schin 			for (;;)
4609*4887Schin 			{
4610*4887Schin 				if (b >= s)
4611*4887Schin 				{
4612*4887Schin 					*w = 0;
4613*4887Schin 					break;
4614*4887Schin 				}
4615*4887Schin 				if (*b == '*')
4616*4887Schin 					break;
4617*4887Schin 				*w++ = *b++;
4618*4887Schin 			}
4619*4887Schin 			if (!num && v)
4620*4887Schin 				return opterror(no ? "!" : "=", version, catalog, 0);
4621*4887Schin 			w = &opt_info.name[prefix];
4622*4887Schin 			c = x;
4623*4887Schin 			s = a;
4624*4887Schin 		}
4625*4887Schin 	}
4626*4887Schin 	if (!*s)
4627*4887Schin 	{
4628*4887Schin 		if (w)
4629*4887Schin 		{
4630*4887Schin 			if (hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), w))
4631*4887Schin 			{
4632*4887Schin 				if (!v)
4633*4887Schin 					v = (char*)hp->name;
4634*4887Schin 				goto help;
4635*4887Schin 			}
4636*4887Schin 			if (!v)
4637*4887Schin 			{
4638*4887Schin 				v = opt_info.name;
4639*4887Schin 				goto help;
4640*4887Schin 			}
4641*4887Schin 		}
4642*4887Schin 		if (w || c < '0' || c > '9' || !numopt)
4643*4887Schin 		{
4644*4887Schin 			pop(psp);
4645*4887Schin 			return opterror("", version, catalog, 0);
4646*4887Schin 		}
4647*4887Schin 		s = numopt;
4648*4887Schin 		c = opt_info.option[1] = numchr;
4649*4887Schin 		opt_info.offset--;
4650*4887Schin 	}
4651*4887Schin 	opt_info.arg = 0;
4652*4887Schin 
4653*4887Schin 	/*
4654*4887Schin 	 * this is a ksh getopts workaround
4655*4887Schin 	 */
4656*4887Schin 
4657*4887Schin 	if (opt_info.num != LONG_MIN)
4658*4887Schin 		opt_info.num = opt_info.number = num;
4659*4887Schin 	if ((n = *++s == '#') || *s == ':' || w && !nov && v && (optnumber(v, &e, NiL), n = !*e))
4660*4887Schin 	{
4661*4887Schin 		if (w)
4662*4887Schin 		{
4663*4887Schin 			if (nov)
4664*4887Schin 			{
4665*4887Schin 				if (v)
4666*4887Schin 				{
4667*4887Schin 					pop(psp);
4668*4887Schin 					return opterror("!", version, catalog, 0);
4669*4887Schin 				}
4670*4887Schin 				opt_info.num = opt_info.number = 0;
4671*4887Schin 			}
4672*4887Schin 			else
4673*4887Schin 			{
4674*4887Schin 				if (!v && *(s + 1) != '?' && (v = argv[opt_info.index]))
4675*4887Schin 				{
4676*4887Schin 					opt_info.index++;
4677*4887Schin 					opt_info.offset = 0;
4678*4887Schin 				}
4679*4887Schin 				if (!(opt_info.arg = v) || (*v == '0' || *v == '1') && !*(v + 1))
4680*4887Schin 				{
4681*4887Schin 					if (*(s + 1) != '?')
4682*4887Schin 					{
4683*4887Schin 						if (!opt_info.arg)
4684*4887Schin 						{
4685*4887Schin 							pop(psp);
4686*4887Schin 							return opterror(s, version, catalog, 0);
4687*4887Schin 						}
4688*4887Schin 					}
4689*4887Schin 					else if (*(t = next(s + 2, version)) == '[')
4690*4887Schin 						while (*(t = skip(t, ':', 0, 0, 1, 0, 0, version)) == ':')
4691*4887Schin 							if (*++t == '!')
4692*4887Schin 							{
4693*4887Schin 								if (!v || *v == '1')
4694*4887Schin 								{
4695*4887Schin 									e = skip(t, ':', '?', ']', 1, 0, 0, version);
4696*4887Schin 									opt_info.arg = sfprints("%-.*s", e - t - 1, t + 1);
4697*4887Schin 								}
4698*4887Schin 								else
4699*4887Schin 								{
4700*4887Schin 									opt_info.arg = 0;
4701*4887Schin 									opt_info.num = opt_info.number = 0;
4702*4887Schin 								}
4703*4887Schin 								break;
4704*4887Schin 							}
4705*4887Schin 				}
4706*4887Schin 				if (opt_info.arg && n)
4707*4887Schin 				{
4708*4887Schin 					opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
4709*4887Schin 					if (err || e == opt_info.arg)
4710*4887Schin 					{
4711*4887Schin 						pop(psp);
4712*4887Schin 						return opterror(s, version, catalog, err);
4713*4887Schin 					}
4714*4887Schin 				}
4715*4887Schin 			}
4716*4887Schin 			goto optarg;
4717*4887Schin 		}
4718*4887Schin 		else if (*(opt_info.arg = &argv[opt_info.index++][opt_info.offset]))
4719*4887Schin 		{
4720*4887Schin 			if (*s == '#')
4721*4887Schin 			{
4722*4887Schin 				opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
4723*4887Schin 				if (err || e == opt_info.arg)
4724*4887Schin 				{
4725*4887Schin 					if (!err && *(s + 1) == '?')
4726*4887Schin 					{
4727*4887Schin 						opt_info.arg = 0;
4728*4887Schin 						opt_info.index--;
4729*4887Schin 					}
4730*4887Schin 					else
4731*4887Schin 					{
4732*4887Schin 						opt_info.offset = 0;
4733*4887Schin 						c = opterror(s, version, catalog, err);
4734*4887Schin 					}
4735*4887Schin 					pop(psp);
4736*4887Schin 					return c;
4737*4887Schin 				}
4738*4887Schin 				else if (*e)
4739*4887Schin 				{
4740*4887Schin 					opt_info.offset += e - opt_info.arg;
4741*4887Schin 					opt_info.index--;
4742*4887Schin 					pop(psp);
4743*4887Schin 					return c;
4744*4887Schin 				}
4745*4887Schin 			}
4746*4887Schin 		}
4747*4887Schin 		else if (opt_info.arg = argv[opt_info.index])
4748*4887Schin 		{
4749*4887Schin 			opt_info.index++;
4750*4887Schin 			if (*(s + 1) == '?' && (*opt_info.arg == '-' || (pass->flags & OPT_plus) && *opt_info.arg == '+') && *(opt_info.arg + 1))
4751*4887Schin 			{
4752*4887Schin 				opt_info.index--;
4753*4887Schin 				opt_info.arg = 0;
4754*4887Schin 			}
4755*4887Schin 			else if (*s == '#')
4756*4887Schin 			{
4757*4887Schin 				opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
4758*4887Schin 				if (err || *e)
4759*4887Schin 				{
4760*4887Schin 					if (!err && *(s + 1) == '?')
4761*4887Schin 					{
4762*4887Schin 						opt_info.arg = 0;
4763*4887Schin 						opt_info.index--;
4764*4887Schin 					}
4765*4887Schin 					else
4766*4887Schin 					{
4767*4887Schin 						pop(psp);
4768*4887Schin 						opt_info.offset = 0;
4769*4887Schin 						return opterror(s, version, catalog, err);
4770*4887Schin 					}
4771*4887Schin 				}
4772*4887Schin 			}
4773*4887Schin 		}
4774*4887Schin 		else if (*(s + 1) != '?')
4775*4887Schin 		{
4776*4887Schin 			opt_info.index--;
4777*4887Schin 			pop(psp);
4778*4887Schin 			return opterror(s, version, catalog, 0);
4779*4887Schin 		}
4780*4887Schin 		opt_info.offset = 0;
4781*4887Schin 	optarg:
4782*4887Schin 		if (*s == ':' && *(s = skip(s, 0, 0, 0, 1, 0, 1, version)) == GO && *(s = next(s + 1, version)) == '[' && isalnum(*(s + 1)))
4783*4887Schin 		{
4784*4887Schin 			x = 0;
4785*4887Schin 			if (opt_info.arg)
4786*4887Schin 			{
4787*4887Schin 				do
4788*4887Schin 				{
4789*4887Schin 					w = y = opt_info.arg;
4790*4887Schin 					f = s = next(s + 1, version);
4791*4887Schin 					k = *f;
4792*4887Schin 					if (k == *w && isalpha(k) && !*(w + 1))
4793*4887Schin 					{
4794*4887Schin 						x = k;
4795*4887Schin 						break;
4796*4887Schin 					}
4797*4887Schin 					if (*s == '+' || *s == '-')
4798*4887Schin 						continue;
4799*4887Schin 					else if (*s == '[' || version < 1)
4800*4887Schin 						continue;
4801*4887Schin 					else
4802*4887Schin 					{
4803*4887Schin 						if (*s != ':')
4804*4887Schin 							s = skip(s, ':', '?', 0, 1, 0, 0, version);
4805*4887Schin 						if (*s == ':')
4806*4887Schin 						{
4807*4887Schin 							if (catalog)
4808*4887Schin 							{
4809*4887Schin 								p = skip(s + 1, '?', 0, 0, 1, 0, 0, version);
4810*4887Schin 								e = sfprints("%-.*s", p - (s + 1), s + 1);
4811*4887Schin 								b = T(error_info.id, catalog, e);
4812*4887Schin 								if (b == e)
4813*4887Schin 									p = 0;
4814*4887Schin 								else
4815*4887Schin 								{
4816*4887Schin 									sfprintf(xp, ":%s|%s?", b, e);
4817*4887Schin 									if (!(s = sfstruse(xp)))
4818*4887Schin 										goto nospace;
4819*4887Schin 								}
4820*4887Schin 							}
4821*4887Schin 							else
4822*4887Schin 								p = 0;
4823*4887Schin 							for (;;)
4824*4887Schin 							{
4825*4887Schin 								n = m = 0;
4826*4887Schin 								e = s + 1;
4827*4887Schin 								while (*++s)
4828*4887Schin 								{
4829*4887Schin 									if (*s == '*' || *s == '\a')
4830*4887Schin 									{
4831*4887Schin 										if (*s == '\a')
4832*4887Schin 											do
4833*4887Schin 											{
4834*4887Schin 												if (!*++s)
4835*4887Schin 												{
4836*4887Schin 													s--;
4837*4887Schin 													break;
4838*4887Schin 												}
4839*4887Schin 											} while (*s != '\a');
4840*4887Schin 										j = *(s + 1);
4841*4887Schin 										if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
4842*4887Schin 										{
4843*4887Schin 											while (*w)
4844*4887Schin 												w++;
4845*4887Schin 											m = 0;
4846*4887Schin 											break;
4847*4887Schin 										}
4848*4887Schin 										m = 1;
4849*4887Schin 									}
4850*4887Schin 									else if (*s == *w || sep(*s) && sep(*w))
4851*4887Schin 										w++;
4852*4887Schin 									else if (*w == 0)
4853*4887Schin 										break;
4854*4887Schin 									else if (!sep(*s))
4855*4887Schin 									{
4856*4887Schin 										if (sep(*w))
4857*4887Schin 										{
4858*4887Schin 											if (*++w == *s)
4859*4887Schin 											{
4860*4887Schin 												w++;
4861*4887Schin 												continue;
4862*4887Schin 											}
4863*4887Schin 										}
4864*4887Schin 										else if (w == y || sep(*(w - 1)) || isupper(*(w - 1)) && islower(*w))
4865*4887Schin 											break;
4866*4887Schin 										for (q = s; *q && !sep(*q) && *q != '|' && *q != '?' && *q != ']'; q++);
4867*4887Schin 										if (!sep(*q))
4868*4887Schin 											break;
4869*4887Schin 										for (s = q; w > y && *w != *(s + 1); w--);
4870*4887Schin 									}
4871*4887Schin 									else if (*w != *(s + 1))
4872*4887Schin 										break;
4873*4887Schin 								}
4874*4887Schin 								if (!*w)
4875*4887Schin 								{
4876*4887Schin 									nov = 0;
4877*4887Schin 									break;
4878*4887Schin 								}
4879*4887Schin 								if (*(s = skip(s, ':', '|', '?', 1, 0, 0, version)) != '|')
4880*4887Schin 									break;
4881*4887Schin 								w = y;
4882*4887Schin 							}
4883*4887Schin 							if (p)
4884*4887Schin 								s = p;
4885*4887Schin 							if (!*w)
4886*4887Schin 							{
4887*4887Schin 								if (n)
4888*4887Schin 									num = 0;
4889*4887Schin 								if (!(n = (m || *s == ':' || *s == '|' || *s == '?' || *s == ']')) && x)
4890*4887Schin 								{
4891*4887Schin 									pop(psp);
4892*4887Schin 									return opterror("&", version, catalog, 0);
4893*4887Schin 								}
4894*4887Schin 								for (x = k; *(f + 1) == '|' && (j = *(f + 2)) && j != '!' && j != '=' && j != ':' && j != '?' && j != ']'; f += 2);
4895*4887Schin 								if (*f == ':')
4896*4887Schin 									x = -1;
4897*4887Schin 								else if (*(f + 1) == ':' || *(f + 1) == '!' && *(f + 2) == ':')
4898*4887Schin 									/* ok */;
4899*4887Schin 								else
4900*4887Schin 								{
4901*4887Schin 									a = f;
4902*4887Schin 									if (*a == '=')
4903*4887Schin 										a++;
4904*4887Schin 									else
4905*4887Schin 									{
4906*4887Schin 										if (*(a + 1) == '!')
4907*4887Schin 											a++;
4908*4887Schin 										if (*(a + 1) == '=')
4909*4887Schin 											a += 2;
4910*4887Schin 									}
4911*4887Schin 									x = -strtol(a, &b, 0);
4912*4887Schin 								}
4913*4887Schin 								b = e;
4914*4887Schin 								a = s = skip(s, 0, 0, 0, 1, 0, 0, version);
4915*4887Schin 								if (n)
4916*4887Schin 									break;
4917*4887Schin 							}
4918*4887Schin 						}
4919*4887Schin 					}
4920*4887Schin 				} while (*(s = skip(s, 0, 0, 0, 1, 0, 1, version)) == '[');
4921*4887Schin 				if (!(opt_info.num = opt_info.number = x))
4922*4887Schin 				{
4923*4887Schin 					pop(psp);
4924*4887Schin 					return opterror("*", version, catalog, 0);
4925*4887Schin 				}
4926*4887Schin 			}
4927*4887Schin 		}
4928*4887Schin 	}
4929*4887Schin 	else if (w && v)
4930*4887Schin 	{
4931*4887Schin 		pop(psp);
4932*4887Schin 		return opterror("=", version, catalog, 0);
4933*4887Schin 	}
4934*4887Schin 	else
4935*4887Schin 	{
4936*4887Schin 		opt_info.num = opt_info.number = num;
4937*4887Schin 		if (!w && !argv[opt_info.index][opt_info.offset])
4938*4887Schin 		{
4939*4887Schin 			opt_info.offset = 0;
4940*4887Schin 			opt_info.index++;
4941*4887Schin 		}
4942*4887Schin 	}
4943*4887Schin 	pop(psp);
4944*4887Schin 	return c;
4945*4887Schin  help:
4946*4887Schin 	if (v && *v == '?' && *(v + 1) == '?' && *(v + 2))
4947*4887Schin 	{
4948*4887Schin 		s = v + 2;
4949*4887Schin 		if ((s[0] == 'n' || s[0] == 'N') && (s[1] == 'o' || s[1] == 'O'))
4950*4887Schin 		{
4951*4887Schin 			s += 2;
4952*4887Schin 			n = -1;
4953*4887Schin 		}
4954*4887Schin 		else
4955*4887Schin 			n = 1;
4956*4887Schin 		if (hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), s))
4957*4887Schin 		{
4958*4887Schin 			if (hp->style < STYLE_man || !(s = argv[opt_info.index]) || s[0] != '-' || s[1] != '-' || !s[2])
4959*4887Schin 			{
4960*4887Schin 				opt_info.arg = sfprints("\fversion=%d", version);
4961*4887Schin 				pop(psp);
4962*4887Schin 				return '?';
4963*4887Schin 			}
4964*4887Schin 			opt_info.state->force = hp->style;
4965*4887Schin 		}
4966*4887Schin 		else if (match(s, "ESC", -1, NiL) || match(s, "EMPHASIS", -1, NiL))
4967*4887Schin 			opt_info.state->emphasis = n;
4968*4887Schin 		else if (match(s, "PREFORMAT", -1, NiL))
4969*4887Schin 			opt_info.state->flags |= OPT_preformat;
4970*4887Schin 		else if (match(s, "TEST", -1, NiL))
4971*4887Schin 		{
4972*4887Schin 			opt_info.state->width = OPT_WIDTH;
4973*4887Schin 			opt_info.state->emphasis = 1;
4974*4887Schin 		}
4975*4887Schin 		else
4976*4887Schin 		{
4977*4887Schin 			pop(psp);
4978*4887Schin 			return opterror(v, version, catalog, 0);
4979*4887Schin 		}
4980*4887Schin 		psp = pop(psp);
4981*4887Schin 		if (argv == opt_info.state->strv)
4982*4887Schin 			return '#';
4983*4887Schin 		goto again;
4984*4887Schin 	}
4985*4887Schin 	if ((opt_info.arg = opthelp(NiL, v)) == (char*)unknown)
4986*4887Schin 	{
4987*4887Schin 		pop(psp);
4988*4887Schin 		return opterror(v, version, catalog, 0);
4989*4887Schin 	}
4990*4887Schin 	pop(psp);
4991*4887Schin 	return '?';
4992*4887Schin  nospace:
4993*4887Schin 	pop(psp);
4994*4887Schin 	return opterror(NiL, 0, NiL, 0);
4995*4887Schin }
4996*4887Schin 
4997*4887Schin /*
4998*4887Schin  * parse long options with 0,1,2 leading '-' or '+' from string and pass to optget()
4999*4887Schin  * syntax is the unquoted
5000*4887Schin  *
5001*4887Schin  *	<length> [-|+|--|++]<name>[[-+:|&=]=<value>\n (or \0 for the last)
5002*4887Schin  *
5003*4887Schin  * or the quoted
5004*4887Schin  *
5005*4887Schin  *	[-|+|--|++][no]name[[-+:|&=]=['"{(]value[)}"']][, ]...
5006*4887Schin  *
5007*4887Schin  * with \x escapes passed to chresc()
5008*4887Schin  *
5009*4887Schin  * return '#' for `label:', with opt_info.name==label
5010*4887Schin  * str[opt_info.offset]	next arg
5011*4887Schin  *
5012*4887Schin  *	optstr(s, 0)
5013*4887Schin  *		return '-' if arg, 0 otherwise
5014*4887Schin  *	optstr(0, opts)
5015*4887Schin  *		use previous parsed str
5016*4887Schin  */
5017*4887Schin 
5018*4887Schin int
5019*4887Schin optstr(const char* str, const char* opts)
5020*4887Schin {
5021*4887Schin 	register char*		s = (char*)str;
5022*4887Schin 	register Sfio_t*	mp;
5023*4887Schin 	register int		c;
5024*4887Schin 	register int		ql;
5025*4887Schin 	register int		qr;
5026*4887Schin 	register int		qc;
5027*4887Schin 	int			v;
5028*4887Schin 	char*			e;
5029*4887Schin 
5030*4887Schin  again:
5031*4887Schin 	if (s)
5032*4887Schin 	{
5033*4887Schin 		if (!(mp = opt_info.state->strp) && !(mp = opt_info.state->strp = sfstropen()))
5034*4887Schin 			return 0;
5035*4887Schin 		if (opt_info.state->str != s)
5036*4887Schin 			opt_info.state->str = s;
5037*4887Schin 		else if (opt_info.index == 1)
5038*4887Schin 			s += opt_info.offset;
5039*4887Schin 		while (*s == ',' || *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')
5040*4887Schin 			s++;
5041*4887Schin 		if (!*s)
5042*4887Schin 		{
5043*4887Schin 			opt_info.state->str = 0;
5044*4887Schin 			return 0;
5045*4887Schin 		}
5046*4887Schin 		if (*s == '-' || *s == '+')
5047*4887Schin 		{
5048*4887Schin 			c = *s++;
5049*4887Schin 			sfputc(mp, c);
5050*4887Schin 			if (*s == c)
5051*4887Schin 			{
5052*4887Schin 				sfputc(mp, c);
5053*4887Schin 				s++;
5054*4887Schin 			}
5055*4887Schin 		}
5056*4887Schin 		else
5057*4887Schin 		{
5058*4887Schin 			sfputc(mp, '-');
5059*4887Schin 			sfputc(mp, '-');
5060*4887Schin 		}
5061*4887Schin 		if (isdigit(*s) && (v = (int)strtol(s, &e, 10)) > 1 && isspace(*e) && --v <= strlen(s) && (s[v] == 0 || s[v] == '\n'))
5062*4887Schin 		{
5063*4887Schin 			s += v;
5064*4887Schin 			while (isspace(*++e));
5065*4887Schin 			sfwrite(mp, e, s - e);
5066*4887Schin 		}
5067*4887Schin 		else
5068*4887Schin 		{
5069*4887Schin 			while (*s && *s != ',' && *s != ' ' && *s != '\t' && *s != '\n' && *s != '\r' && *s != '=' && *s != ':')
5070*4887Schin 				sfputc(mp, *s++);
5071*4887Schin 			if ((c = *s) == ':' && *(s + 1) != '=')
5072*4887Schin 			{
5073*4887Schin 				opt_info.index = 1;
5074*4887Schin 				opt_info.offset = ++s - (char*)str;
5075*4887Schin 				if (!(s = sfstruse(mp)))
5076*4887Schin 					goto nospace;
5077*4887Schin 				s += 2;
5078*4887Schin 				e = opt_info.name;
5079*4887Schin 				while (e < &opt_info.name[sizeof(opt_info.name)-1] && (*e++ = *s++));
5080*4887Schin 				opt_info.arg = 0;
5081*4887Schin 				opt_info.num = opt_info.number = 0;
5082*4887Schin 				opt_info.option[0] = ':';
5083*4887Schin 				opt_info.option[1] = 0;
5084*4887Schin 				return '#';
5085*4887Schin 			}
5086*4887Schin 			if (c == ':' || c == '=')
5087*4887Schin 			{
5088*4887Schin 				sfputc(mp, c);
5089*4887Schin 				ql = qr = 0;
5090*4887Schin 				while (c = *++s)
5091*4887Schin 				{
5092*4887Schin 					if (c == '\\')
5093*4887Schin 					{
5094*4887Schin 						sfputc(mp, chresc(s, &e));
5095*4887Schin 						s = e - 1;
5096*4887Schin 					}
5097*4887Schin 					else if (c == qr)
5098*4887Schin 					{
5099*4887Schin 						if (qr != ql)
5100*4887Schin 							sfputc(mp, c);
5101*4887Schin 						if (--qc <= 0)
5102*4887Schin 							qr = ql = 0;
5103*4887Schin 					}
5104*4887Schin 					else if (c == ql)
5105*4887Schin 					{
5106*4887Schin 						sfputc(mp, c);
5107*4887Schin 						qc++;
5108*4887Schin 					}
5109*4887Schin 					else if (qr)
5110*4887Schin 						sfputc(mp, c);
5111*4887Schin 					else if (c == ',' || c == ' ' || c == '\t' || c == '\n' || c == '\r')
5112*4887Schin 						break;
5113*4887Schin 					else if (c == '"' || c == '\'')
5114*4887Schin 					{
5115*4887Schin 						ql = qr = c;
5116*4887Schin 						qc = 1;
5117*4887Schin 					}
5118*4887Schin 					else
5119*4887Schin 					{
5120*4887Schin 						sfputc(mp, c);
5121*4887Schin 						if (c == GO)
5122*4887Schin 						{
5123*4887Schin 							ql = c;
5124*4887Schin 							qr = OG;
5125*4887Schin 							qc = 1;
5126*4887Schin 						}
5127*4887Schin 						else if (c == '(')
5128*4887Schin 						{
5129*4887Schin 							ql = c;
5130*4887Schin 							qr = ')';
5131*4887Schin 							qc = 1;
5132*4887Schin 						}
5133*4887Schin 					}
5134*4887Schin 				}
5135*4887Schin 			}
5136*4887Schin 		}
5137*4887Schin 		opt_info.argv = opt_info.state->strv;
5138*4887Schin 		opt_info.state->strv[0] = T(NiL, ID, "option");
5139*4887Schin 		if (!(opt_info.state->strv[1] = sfstruse(mp)))
5140*4887Schin 			goto nospace;
5141*4887Schin 		opt_info.state->strv[2] = 0;
5142*4887Schin 		opt_info.offset = s - (char*)str;
5143*4887Schin 	}
5144*4887Schin 	if (opts)
5145*4887Schin 	{
5146*4887Schin 		if (!opt_info.state->strv[1])
5147*4887Schin 		{
5148*4887Schin 			opt_info.state->str = 0;
5149*4887Schin 			return 0;
5150*4887Schin 		}
5151*4887Schin 		opt_info.index = 1;
5152*4887Schin 		v = opt_info.offset;
5153*4887Schin 		opt_info.offset = 0;
5154*4887Schin 		c = optget(opt_info.state->strv, opts);
5155*4887Schin 		opt_info.index = 1;
5156*4887Schin 		opt_info.offset = v;
5157*4887Schin 		if (c == '#')
5158*4887Schin 		{
5159*4887Schin 			s = opt_info.state->str;
5160*4887Schin 			goto again;
5161*4887Schin 		}
5162*4887Schin 		if ((c == '?' || c == ':') && (opt_info.arg[0] == '-' && opt_info.arg[1] == '-'))
5163*4887Schin 			opt_info.arg += 2;
5164*4887Schin 		s = opt_info.name;
5165*4887Schin 		if (*s++ == '-' && *s++ == '-' && *s)
5166*4887Schin 		{
5167*4887Schin 			e = opt_info.name;
5168*4887Schin 			while (*e++ = *s++);
5169*4887Schin 		}
5170*4887Schin 	}
5171*4887Schin 	else
5172*4887Schin 		c = '-';
5173*4887Schin 	return c;
5174*4887Schin  nospace:
5175*4887Schin 	return opterror(NiL, 0, NiL, 0);
5176*4887Schin }
5177