14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*10898Sroland.mainz@nrubsig.org *          Copyright (c) 1985-2009 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin  * Glenn Fowler
254887Schin  * AT&T Research
264887Schin  *
274887Schin  * command line option parser and usage formatter
284887Schin  * its a monster but its all in one place
294887Schin  * widen your window while you're at it
304887Schin  */
314887Schin 
324887Schin #include <optlib.h>
334887Schin #include <debug.h>
344887Schin #include <ccode.h>
354887Schin #include <ctype.h>
364887Schin #include <errno.h>
374887Schin 
384887Schin #define KEEP		"*[A-Za-z][A-Za-z]*"
394887Schin #define OMIT		"*@(\\[[-+]*\\?*\\]|\\@\\(#\\)|Copyright \\(c\\)|\\$\\I\\d\\: )*"
404887Schin 
414887Schin #define GO		'{'		/* group nest open		*/
424887Schin #define OG		'}'		/* group nest close		*/
434887Schin 
444887Schin #define OPT_WIDTH	80		/* default help text width	*/
454887Schin #define OPT_MARGIN	10		/* default help text margin	*/
464887Schin #define OPT_USAGE	7		/* usage continuation indent	*/
474887Schin 
484887Schin #define OPT_flag	0x001		/* flag ( 0 or 1 )		*/
494887Schin #define OPT_hidden	0x002		/* remaining are hidden		*/
504887Schin #define OPT_ignorecase	0x004		/* arg match ignores case	*/
514887Schin #define OPT_invert	0x008		/* flag inverts long sense	*/
524887Schin #define OPT_listof	0x010		/* arg is ' ' or ',' list	*/
53*10898Sroland.mainz@nrubsig.org #define OPT_number	0x020		/* arg is strtonll() number	*/
54*10898Sroland.mainz@nrubsig.org #define OPT_oneof	0x040		/* arg may be set once		*/
55*10898Sroland.mainz@nrubsig.org #define OPT_optional	0x080		/* arg is optional		*/
56*10898Sroland.mainz@nrubsig.org #define OPT_string	0x100		/* arg is string		*/
574887Schin 
584887Schin #define OPT_preformat	0001		/* output preformat string	*/
59*10898Sroland.mainz@nrubsig.org #define OPT_proprietary	0002		/* proprietary docs		*/
604887Schin 
614887Schin #define OPT_TYPE	(OPT_flag|OPT_number|OPT_string)
624887Schin 
634887Schin #define STYLE_posix	0		/* posix getopt usage		*/
644887Schin #define STYLE_short	1		/* [default] short usage	*/
654887Schin #define STYLE_long	2		/* long usage			*/
664887Schin #define STYLE_match	3		/* long description of matches	*/
674887Schin #define STYLE_options	4		/* short and long descriptions	*/
684887Schin #define STYLE_man	5		/* pretty details		*/
694887Schin #define STYLE_html	6		/* html details			*/
704887Schin #define STYLE_nroff	7		/* nroff details		*/
714887Schin #define STYLE_api	8		/* program details		*/
724887Schin #define STYLE_keys	9		/* translation key strings	*/
734887Schin #define STYLE_usage	10		/* escaped usage string		*/
744887Schin 
754887Schin #define FONT_BOLD	1
764887Schin #define FONT_ITALIC	2
774887Schin #define FONT_LITERAL	4
784887Schin 
794887Schin #define sep(c)		((c)=='-'||(c)=='_')
804887Schin 
814887Schin typedef struct Attr_s
824887Schin {
834887Schin 	const char*	name;
844887Schin 	int		flag;
854887Schin } Attr_t;
864887Schin 
874887Schin typedef struct Help_s
884887Schin {
894887Schin 	const char*	match;		/* builtin help match name	*/
904887Schin 	const char*	name;		/* builtin help name		*/
914887Schin 	int		style;		/* STYLE_*			*/
924887Schin 	const char*	text;		/* --? text			*/
934887Schin 	unsigned int	size;		/* strlen text			*/
944887Schin } Help_t;
954887Schin 
964887Schin typedef struct Font_s
974887Schin {
984887Schin 	const char*	html[2];
994887Schin 	const char*	nroff[2];
1004887Schin 	const char*	term[2];
1014887Schin } Font_t;
1024887Schin 
1034887Schin typedef struct List_s
1044887Schin {
1054887Schin 	int		type;		/* { - + : }			*/
1064887Schin 	const char*	name;		/* list name			*/
1074887Schin 	const char*	text;		/* help text			*/
1084887Schin } List_t;
1094887Schin 
1104887Schin typedef struct Msg_s
1114887Schin {
1124887Schin 	const char*	text;		/* default message text		*/
1134887Schin 	Dtlink_t	link;		/* cdt link			*/
1144887Schin } Msg_t;
1154887Schin 
1164887Schin typedef struct Save_s
1174887Schin {
1184887Schin 	Dtlink_t	link;		/* cdt link			*/
1194887Schin 	char		text[1];	/* saved text text		*/
1204887Schin } Save_t;
1214887Schin 
1224887Schin typedef struct Push_s
1234887Schin {
1244887Schin 	struct Push_s*	next;		/* next string			*/
1254887Schin 	char*		ob;		/* next char in old string	*/
1264887Schin 	char*		oe;		/* end of old string		*/
1274887Schin 	char*		nb;		/* next char in new string	*/
1284887Schin 	char*		ne;		/* end of new string		*/
1294887Schin 	int		ch;		/* localize() translation	*/
1304887Schin } Push_t;
1314887Schin 
1324887Schin typedef struct Indent_s
1334887Schin {
1344887Schin 	int		stop;		/* tab column position		*/
1354887Schin } Indent_t;
1364887Schin 
1374887Schin static Indent_t		indent[] =
1384887Schin {
1394887Schin 	0,2,	4,10,	12,18,	20,26,	28,34,	36,42,	44,50,	0,0
1404887Schin };
1414887Schin 
1424887Schin static const char	term_off[] =	{CC_esc,'[','0','m',0};
1434887Schin static const char	term_B_on[] =	{CC_esc,'[','1','m',0};
1444887Schin static const char	term_I_on[] =	{CC_esc,'[','1',';','4','m',0};
1454887Schin 
1464887Schin static const Font_t	fonts[] =
1474887Schin {
1484887Schin 	"",	"",	"",	"",	"",			"",
1494887Schin 	"</B>",	"<B>", "\\fP",	"\\fB",	&term_off[0],	&term_B_on[0],
1504887Schin 	"</I>",	"<I>", "\\fP",	"\\fI",	&term_off[0],	&term_I_on[0],
1514887Schin 	"",	"",	"",	"",	"",			"",
1524887Schin 	"</TT>","<TT>","\\fP",	"\\f5",	"",			"",
1534887Schin };
1544887Schin 
1554887Schin static char		native[] = "";
1564887Schin 
1574887Schin #if !_PACKAGE_astsa
1584887Schin 
1594887Schin #define ID		ast.id
1604887Schin 
1614887Schin #define C(s)		ERROR_catalog(s)
1624887Schin #define D(s)		(opt_info.state->msgdict && dtmatch(opt_info.state->msgdict, (s)))
1634887Schin #define T(i,c,m)	(X(c)?translate(i,c,C(m)):(m))
1644887Schin #define X(c)		(ERROR_translating()&&(c)!=native)
1654887Schin #define Z(x)		C(x),sizeof(x)-1
1664887Schin 
1674887Schin /*
1684887Schin  * translate with C_LC_MESSAGES_libast[] check
1694887Schin  */
1704887Schin 
1714887Schin static char*
1724887Schin translate(const char* cmd, const char* cat, const char* msg)
1734887Schin {
1744887Schin 	if (!X(cat))
1754887Schin 		return (char*)msg;
1764887Schin 	if (cat != (const char*)ID && D(msg))
1774887Schin 		cat = (const char*)ID;
1784887Schin 	return errorx(NiL, cmd, cat, msg);
1794887Schin }
1804887Schin 
1814887Schin #else
1824887Schin 
1834887Schin static char		ID[] = "ast";
1844887Schin 
1854887Schin #define C(s)		s
1864887Schin #define D(s)		(opt_info.state->msgdict && dtmatch(opt_info.state->msgdict, (s)))
1874887Schin #define T(i,c,m)	m
1884887Schin #define X(c)		0
1894887Schin #define Z(x)		C(x),sizeof(x)-1
1904887Schin 
1914887Schin #endif
1924887Schin 
1934887Schin static const List_t	help_head[] =
1944887Schin {
1954887Schin 	'-',	0,
1964887Schin 		0,
1974887Schin 	'+',	C("NAME"),
1984887Schin 		C("options available to all \bast\b commands"),
1994887Schin 	'+',	C("DESCRIPTION"),
2004887Schin 		C("\b-?\b and \b--?\b* options are the same \
2014887Schin for all \bast\b commands. For any \aitem\a below, if \b--\b\aitem\a is not \
2024887Schin supported by a given command then it is equivalent to \b--\?\?\b\aitem\a. The \
2034887Schin \b--\?\?\b form should be used for portability. All output is written to the \
2044887Schin standard error."),
2054887Schin };
2064887Schin 
2074887Schin static const Help_t	styles[] =
2084887Schin {
2094887Schin 	C("about"),	"-",		STYLE_match,
2104887Schin 	Z("List all implementation info."),
2114887Schin 	C("api"),	"?api",		STYLE_api,
2124887Schin 	Z("List detailed info in program readable form."),
2134887Schin 	C("help"),	"",		-1,
2144887Schin 	Z("List detailed help option info."),
2154887Schin 	C("html"),	"?html",	STYLE_html,
2164887Schin 	Z("List detailed info in html."),
2174887Schin 	C("keys"),	"?keys",	STYLE_keys,
2184887Schin 	Z("List the usage translation key strings with C style escapes."),
2194887Schin 	C("long"),	"?long",	STYLE_long,
2204887Schin 	Z("List long option usage."),
2214887Schin 	C("man"),	"?man",		STYLE_man,
2224887Schin 	Z("List detailed info in displayed man page form."),
2234887Schin 	C("nroff"),	"?nroff",	STYLE_nroff,
2244887Schin 	Z("List detailed info in nroff."),
2254887Schin 	C("options"),	"?options",	STYLE_options,
2264887Schin 	Z("List short and long option details."),
2274887Schin 	C("posix"),	"?posix",	STYLE_posix,
2284887Schin 	Z("List posix getopt usage."),
2294887Schin 	C("short"),	"?short",	STYLE_short,
2304887Schin 	Z("List short option usage."),
2314887Schin 	C("usage"),	"?usage",	STYLE_usage,
2324887Schin 	Z("List the usage string with C style escapes."),
2334887Schin };
2344887Schin 
2354887Schin static const List_t	help_tail[] =
2364887Schin {
2374887Schin 	':',	C("\?\?-\alabel\a"),
2384887Schin 		C("List implementation info matching \alabel\a*."),
2394887Schin 	':',	C("\?\?\aname\a"),
2404887Schin 		C("Equivalent to \b--help=\b\aname\a."),
2414887Schin 	':',	C("\?\?"),
2424887Schin 		C("Equivalent to \b--\?\?options\b."),
2434887Schin 	':',	C("\?\?\?\?"),
2444887Schin 		C("Equivalent to \b--\?\?man\b."),
2454887Schin 	':',	C("\?\?\?\?\?\?"),
2464887Schin 		C("Equivalent to \b--\?\?help\b."),
2474887Schin 	':',	C("\?\?\?\?\?\?\aitem\a"),
2484887Schin 		C("If the next argument is \b--\b\aoption\a then list \
2494887Schin the \aoption\a output in the \aitem\a style. Otherwise print \
2504887Schin \bversion=\b\an\a where \an\a>0 if \b--\?\?\b\aitem\a is supported, \b0\b \
2514887Schin if not."),
2524887Schin 	':',	C("\?\?\?\?\?\?ESC"),
2534887Schin 		C("Emit escape codes even if output is not a terminal."),
2544887Schin 	':',	C("\?\?\?\?\?\?TEST"),
2554887Schin 		C("Massage the output for regression testing."),
2564887Schin };
2574887Schin 
2584887Schin static const Attr_t	attrs[] =
2594887Schin {
2604887Schin 	"flag",		OPT_flag,
2614887Schin 	"hidden",	OPT_hidden,
2624887Schin 	"ignorecase",	OPT_ignorecase,
2634887Schin 	"invert",	OPT_invert,
2644887Schin 	"listof",	OPT_listof,
2654887Schin 	"number",	OPT_number,
2664887Schin 	"oneof",	OPT_oneof,
2674887Schin 	"optional",	OPT_optional,
2684887Schin 	"string",	OPT_string,
2694887Schin };
2704887Schin 
2714887Schin static const char	unknown[] = C("unknown option or attribute");
2724887Schin 
2734887Schin static const char*	heading[] =
2744887Schin {
2754887Schin 	C("INDEX"),
2764887Schin 	C("USER COMMANDS"),
2774887Schin 	C("SYSTEM LIBRARY"),
2784887Schin 	C("USER LIBRARY"),
2794887Schin 	C("FILE FORMATS"),
2804887Schin 	C("MISCELLANEOUS"),
2814887Schin 	C("GAMES and DEMOS"),
2824887Schin 	C("SPECIAL FILES"),
2834887Schin 	C("ADMINISTRATIVE COMMANDS"),
2844887Schin 	C("GUIs"),
2854887Schin };
2864887Schin 
2874887Schin /*
2884887Schin  * list of common man page strings
2894887Schin  * NOTE: add but do not delete from this table
2904887Schin  */
2914887Schin 
2924887Schin static Msg_t		C_LC_MESSAGES_libast[] =
2934887Schin {
2944887Schin 	{ C("APPLICATION USAGE") },
2954887Schin 	{ C("ASYNCHRONOUS EVENTS") },
2964887Schin 	{ C("BUGS") },
2974887Schin 	{ C("CAVEATS") },
2984887Schin 	{ C("CONSEQUENCES OF ERRORS") },
2994887Schin 	{ C("DESCRIPTION") },
3004887Schin 	{ C("ENVIRONMENT VARIABLES") },
3014887Schin 	{ C("EXAMPLES") },
3024887Schin 	{ C("EXIT STATUS") },
3034887Schin 	{ C("EXTENDED DESCRIPTION") },
3044887Schin 	{ C("INPUT FILES") },
3054887Schin 	{ C("LIBRARY") },
3064887Schin 	{ C("NAME") },
3074887Schin 	{ C("OPERANDS") },
3084887Schin 	{ C("OPTIONS") },
3094887Schin 	{ C("OUTPUT FILES") },
3104887Schin 	{ C("SEE ALSO") },
3114887Schin 	{ C("STDERR") },
3124887Schin 	{ C("STDIN") },
3134887Schin 	{ C("STDOUT") },
3144887Schin 	{ C("SYNOPSIS") },
3154887Schin 	{ C("author") },
3164887Schin 	{ C("copyright") },
3174887Schin 	{ C("license") },
3184887Schin 	{ C("name") },
3194887Schin 	{ C("path") },
3204887Schin 	{ C("version") },
3214887Schin };
3224887Schin 
3234887Schin static unsigned char	map[UCHAR_MAX];
3244887Schin 
3254887Schin static Optstate_t	state;
3264887Schin 
3274887Schin /*
3284887Schin  * 2007-03-19 move opt_info from _opt_info_ to (*_opt_data_)
3294887Schin  *	      to allow future Opt_t growth
3304887Schin  *            by 2009 _opt_info_ can be static
3314887Schin  */
3324887Schin 
3334887Schin #if _BLD_ast && defined(__EXPORT__)
3344887Schin #define extern		extern __EXPORT__
3354887Schin #endif
3364887Schin 
3374887Schin extern Opt_t	_opt_info_;
3384887Schin 
3394887Schin Opt_t		_opt_info_ = { 0,0,0,0,0,0,0,{0},{0},0,0,0,{0},{0},&state };
3404887Schin 
3414887Schin #undef	extern
3424887Schin 
3434887Schin __EXTERN__(Opt_t, _opt_info_);
3444887Schin 
3454887Schin __EXTERN__(Opt_t*, _opt_infop_);
3464887Schin 
3474887Schin Opt_t*		_opt_infop_ = &_opt_info_;
3484887Schin 
3494887Schin #if _BLD_DEBUG
3504887Schin 
3514887Schin /*
3524887Schin  * debug usage string segment format
3534887Schin  */
3544887Schin 
3554887Schin static char*
3564887Schin show(register char* s)
3574887Schin {
3584887Schin 	register int	c;
3594887Schin 	register char*	t;
3604887Schin 	register char*	e;
3614887Schin 
3624887Schin 	static char	buf[32];
3634887Schin 
3644887Schin 	if (!s)
3654887Schin 		return "(null)";
3664887Schin 	t = buf;
3674887Schin 	e = buf + sizeof(buf) - 2;
3684887Schin 	while (t < e)
3694887Schin 	{
3704887Schin 		switch (c = *s++)
3714887Schin 		{
3724887Schin 		case 0:
3734887Schin 			goto done;
3744887Schin 		case '\a':
3754887Schin 			*t++ = '\\';
3764887Schin 			c = 'a';
3774887Schin 			break;
3784887Schin 		case '\b':
3794887Schin 			*t++ = '\\';
3804887Schin 			c = 'b';
3814887Schin 			break;
3824887Schin 		case '\f':
3834887Schin 			*t++ = '\\';
3844887Schin 			c = 'f';
3854887Schin 			break;
3864887Schin 		case '\v':
3874887Schin 			*t++ = '\\';
3884887Schin 			c = 'v';
3894887Schin 			break;
3904887Schin 		}
3914887Schin 		*t++ = c;
3924887Schin 	}
3934887Schin  done:
3944887Schin 	*t = 0;
3954887Schin 	return buf;
3964887Schin }
3974887Schin 
3984887Schin #endif
3994887Schin 
4004887Schin /*
4014887Schin  * pop the push stack
4024887Schin  */
4034887Schin 
4044887Schin static Push_t*
4054887Schin pop(register Push_t* psp)
4064887Schin {
4074887Schin 	register Push_t*	tsp;
4084887Schin 
4094887Schin 	while (tsp = psp)
4104887Schin 	{
4114887Schin 		psp = psp->next;
4124887Schin 		free(tsp);
4134887Schin 	}
4144887Schin 	return 0;
4154887Schin }
4164887Schin 
4174887Schin /*
4184887Schin  * skip over line space to the next token
4194887Schin  */
4204887Schin 
4214887Schin static char*
4224887Schin next(register char* s, int version)
4234887Schin {
4244887Schin 	register char*	b;
4254887Schin 
4264887Schin 	while (*s == '\t' || *s == '\r' || version >= 1 && *s == ' ')
4274887Schin 		s++;
4284887Schin 	if (*s == '\n')
4294887Schin 	{
4304887Schin 		b = s;
4314887Schin 		while (*++s == ' ' || *s == '\t' || *s == '\r');
4324887Schin 		if (*s == '\n')
4334887Schin 			return b;
4344887Schin 	}
4354887Schin 	return s;
4364887Schin }
4374887Schin 
4384887Schin /*
4394887Schin  * skip to t1 or t2 or t3, whichever first, in s
4404887Schin  *	n==0	outside [...]
4414887Schin  *	n==1	inside [...] before ?
4424887Schin  *	n==2	inside [...] after ?
4434887Schin  *	b==0	outside {...}
4444887Schin  *	b==1	inside {...}
4454887Schin  * past skips past the terminator to the next token
4464887Schin  * otherwise a pointer to the terminator is returned
4474887Schin  *
4484887Schin  * ]] for ] inside [...]
4494887Schin  * ?? for ? inside [...] before ?
4504887Schin  * :: for : inside [...] before ?
4514887Schin  */
4524887Schin 
4534887Schin static char*
4544887Schin skip(register char* s, register int t1, register int t2, register int t3, register int n, register int b, int past, int version)
4554887Schin {
4564887Schin 	register int	c;
4574887Schin 	register int	on = n;
4584887Schin 	register int	ob = b;
4594887Schin 
4604887Schin 	if (version < 1)
4614887Schin 	{
4624887Schin 		n = n >= 1;
4634887Schin 		for (;;)
4644887Schin 		{
4654887Schin 			switch (*s++)
4664887Schin 			{
4674887Schin 			case 0:
4684887Schin 				break;
4694887Schin 			case '[':
4704887Schin 				n++;
4714887Schin 				continue;
4724887Schin 			case ']':
4734887Schin 				if (--n <= 0)
4744887Schin 					break;
4754887Schin 				continue;
4764887Schin 			default:
4774887Schin 				continue;
4784887Schin 			}
4794887Schin 			break;
4804887Schin 		}
4814887Schin 	}
4824887Schin 	else while (c = *s++)
4834887Schin 	{
4844887Schin 		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)));
4854887Schin 		if (c == '[')
4864887Schin 		{
4874887Schin 			if (!n)
4884887Schin 				n = 1;
4894887Schin 		}
4904887Schin 		else if (c == ']')
4914887Schin 		{
4924887Schin 			if (n)
4934887Schin 			{
4944887Schin 				if (*s == ']')
4954887Schin 					s++;
4964887Schin 				else if (on == 1)
4974887Schin 					break;
4984887Schin 				else
4994887Schin 					n = 0;
5004887Schin 			}
5014887Schin 		}
5024887Schin 		else if (c == GO)
5034887Schin 		{
5044887Schin 			if (n == 0)
5054887Schin 				b++;
5064887Schin 		}
5074887Schin 		else if (c == OG)
5084887Schin 		{
5094887Schin 			if (n == 0 && b-- == ob)
5104887Schin 				break;
5114887Schin 		}
5124887Schin 		else if (c == '?')
5134887Schin 		{
5144887Schin 			if (n == 1)
5154887Schin 			{
5164887Schin 				if (*s == '?')
5174887Schin 					s++;
5184887Schin 				else
5194887Schin 				{
5204887Schin 					if (n == on && (c == t1 || c == t2 || c == t3))
5214887Schin 						break;
5224887Schin 					n = 2;
5234887Schin 				}
5244887Schin 			}
5254887Schin 		}
5264887Schin 		else if (n == on && (c == t1 || c == t2 || c == t3))
5274887Schin 		{
5284887Schin 			if (n == 1 && c == ':' && *s == c)
5294887Schin 				s++;
5304887Schin 			else
5314887Schin 				break;
5324887Schin 		}
5334887Schin 	}
5344887Schin 	return past && *(s - 1) ? next(s, version) : s - 1;
5354887Schin }
5364887Schin 
5374887Schin /*
5384887Schin  * match s with t
5394887Schin  * t translated if possible
5404887Schin  * imbedded { - _ ' } ignored
5414887Schin  * * separates required prefix from optional suffix
5424887Schin  * otherwise prefix match
5434887Schin  */
5444887Schin 
5454887Schin static int
5464887Schin match(char* s, char* t, int version, const char* catalog)
5474887Schin {
5484887Schin 	register char*	w;
5494887Schin 	register char*	x;
5504887Schin 	char*		xw;
5514887Schin 	char*		ww;
5524887Schin 	int		n;
5534887Schin 	int		v;
5544887Schin 	int		j;
5554887Schin 
5564887Schin 	for (n = 0; n < 2; n++)
5574887Schin 	{
5584887Schin 		if (n)
5594887Schin 			x = t;
5604887Schin 		else
5614887Schin 		{
5624887Schin 			if (catalog)
5634887Schin 			{
5644887Schin 				w = skip(t, ':', '?', 0, 1, 0, 0, version);
5654887Schin 				w = sfprints("%-.*s", w - t, t);
5664887Schin 				x = T(error_info.id, catalog, w);
5674887Schin 				if (x == w)
5684887Schin 					continue;
5694887Schin 			}
5704887Schin 			x = T(NiL, ID, t);
5714887Schin 			if (x == t)
5724887Schin 				continue;
5734887Schin 		}
5744887Schin 		do
5754887Schin 		{
5764887Schin 			v = 0;
5774887Schin 			xw = x;
5784887Schin 			w = ww = s;
5794887Schin 			while (*x && *w)
5804887Schin 			{
5814887Schin 				if (isupper(*x))
5824887Schin 					xw = x;
5834887Schin 				if (isupper(*w))
5844887Schin 					ww = w;
5854887Schin 				if (*x == '*' && !v++ || *x == '\a')
5864887Schin 				{
5874887Schin 					if (*x == '\a')
5884887Schin 						do
5894887Schin 						{
5904887Schin 							if (!*++x)
5914887Schin 							{
5924887Schin 								x--;
5934887Schin 								break;
5944887Schin 							}
5954887Schin 						} while (*x != '\a');
5964887Schin 					j = *(x + 1);
5974887Schin 					if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
5984887Schin 						while (*w)
5994887Schin 							w++;
6004887Schin 				}
6014887Schin 				else if (sep(*x))
6024887Schin 					xw = ++x;
6034887Schin 				else if (sep(*w) && w != s)
6044887Schin 					ww = ++w;
6054887Schin 				else if (*x == *w)
6064887Schin 				{
6074887Schin 					x++;
6084887Schin 					w++;
6094887Schin 				}
6104887Schin 				else if (w == ww && x == xw)
6114887Schin 					break;
6124887Schin 				else
6134887Schin 				{
6144887Schin 					if (x != xw)
6154887Schin 					{
6164887Schin 						while (*x && !sep(*x) && !isupper(*x))
6174887Schin 							x++;
6184887Schin 						if (!*x)
6194887Schin 							break;
6204887Schin 						if (sep(*x))
6214887Schin 							x++;
6224887Schin 						xw = x;
6234887Schin 					}
6244887Schin 					while (w > ww && *w != *x)
6254887Schin 						w--;
6264887Schin 				}
6274887Schin 			}
6284887Schin 			if (!*w)
6294887Schin 			{
6304887Schin 				if (!v)
6314887Schin 				{
6324887Schin 					for (;;)
6334887Schin 					{
6344887Schin 						switch (*x++)
6354887Schin 						{
6364887Schin 						case 0:
6374887Schin 						case ':':
6384887Schin 						case '|':
6394887Schin 						case '?':
6404887Schin 						case ']':
6414887Schin 							return 1;
6424887Schin 						case '*':
6434887Schin 							break;
6444887Schin 						default:
6454887Schin 							continue;
6464887Schin 						}
6474887Schin 						break;
6484887Schin 					}
6494887Schin 					break;
6504887Schin 				}
6514887Schin 				return 1;
6524887Schin 			}
6534887Schin 		} while (*(x = skip(x, '|', 0, 0, 1, 0, 0, version)) == '|' && x++);
6544887Schin 	}
6554887Schin 	return 0;
6564887Schin }
6574887Schin 
6584887Schin /*
6594887Schin  * prefix search for s in tab with num elements of size
6604887Schin  * with optional translation
6614887Schin  */
6624887Schin 
6634887Schin static void*
6644887Schin search(const void* tab, size_t num, size_t siz, char* s)
6654887Schin {
6664887Schin 	register char*	p;
6674887Schin 	register char*	e;
6684887Schin 
6694887Schin 	for (e = (p = (char*)tab) + num * siz; p < e; p += siz)
6704887Schin 		if (match(s, *((char**)p), -1, NiL))
6714887Schin 			return (void*)p;
6724887Schin 	return 0;
6734887Schin }
6744887Schin 
6754887Schin /*
6764887Schin  * save s and return the saved pointer
6774887Schin  */
6784887Schin 
6794887Schin static char*
6804887Schin save(const char* s)
6814887Schin {
6824887Schin 	Save_t*		p;
6838462SApril.Chin@Sun.COM 	Dtdisc_t*	d;
6844887Schin 
6854887Schin 	static Dt_t*	dict;
6864887Schin 
6874887Schin 	if (!dict)
6884887Schin 	{
6898462SApril.Chin@Sun.COM 		if (!(d = newof(0, Dtdisc_t, 1, 0)))
6908462SApril.Chin@Sun.COM 			return (char*)s;
6918462SApril.Chin@Sun.COM 		d->key = offsetof(Save_t, text);
6928462SApril.Chin@Sun.COM 		if (!(dict = dtopen(d, Dthash)))
6934887Schin 			return (char*)s;
6944887Schin 	}
6954887Schin 	if (!(p = (Save_t*)dtmatch(dict, s)))
6964887Schin 	{
6974887Schin 		if (!(p = newof(0, Save_t, 1, strlen(s))))
6984887Schin 			return (char*)s;
6994887Schin 		strcpy(p->text, s);
7004887Schin 		dtinsert(dict, p);
7014887Schin 	}
7024887Schin 	return p->text;
7034887Schin }
7044887Schin 
7054887Schin /*
7064887Schin  * initialize the attributes for pass p from opt string s
7074887Schin  */
7084887Schin 
7094887Schin static int
7104887Schin init(register char* s, Optpass_t* p)
7114887Schin {
7124887Schin 	register char*	t;
7134887Schin 	register int	c;
7144887Schin 	register int	a;
7154887Schin 	register int	n;
7164887Schin 
7174887Schin 	if (!opt_info.state->msgdict)
7184887Schin 	{
7194887Schin #if !_PACKAGE_astsa
7204887Schin 		if (!ast.locale.serial)
7214887Schin 			setlocale(LC_ALL, "");
7224887Schin #endif
7234887Schin 		opt_info.state->vp = sfstropen();
7244887Schin 		opt_info.state->xp = sfstropen();
7254887Schin 		opt_info.state->msgdisc.key = offsetof(Msg_t, text);
7264887Schin 		opt_info.state->msgdisc.size = -1;
7274887Schin 		opt_info.state->msgdisc.link = offsetof(Msg_t, link);
7284887Schin 		if (opt_info.state->msgdict = dtopen(&opt_info.state->msgdisc, Dthash))
7294887Schin 			for (n = 0; n < elementsof(C_LC_MESSAGES_libast); n++)
7304887Schin 				dtinsert(opt_info.state->msgdict, C_LC_MESSAGES_libast + n);
7314887Schin 		if (!map[OPT_FLAGS[0]])
7324887Schin 			for (n = 0, t = OPT_FLAGS; *t; t++)
7334887Schin 				map[*t] = ++n;
7344887Schin 	}
7354887Schin #if _BLD_DEBUG
7364887Schin 	error(-1, "optget debug");
7374887Schin #endif
7384887Schin 	p->oopts = s;
7394887Schin 	p->version = 0;
7404887Schin 	p->prefix = 2;
7414887Schin 	p->section = 1;
7424887Schin 	p->flags = 0;
7434887Schin 	p->catalog = 0;
7444887Schin 	s = next(s, 0);
7454887Schin 	if (*s == ':')
7464887Schin 		s++;
7474887Schin 	if (*s == '+')
7484887Schin 		s++;
7494887Schin 	s = next(s, 0);
7504887Schin 	if (*s++ == '[')
7514887Schin 	{
7524887Schin 		if (*s == '+')
7534887Schin 			p->version = 1;
7544887Schin 		else if (*s++ == '-')
7554887Schin 		{
7564887Schin 			if (*s == '?' || *s == ']')
7574887Schin 				p->version = 1;
7584887Schin 			else
7594887Schin 			{
7608462SApril.Chin@Sun.COM 				if (!isdigit(*s))
7614887Schin 					p->version = 1;
7624887Schin 				else
7638462SApril.Chin@Sun.COM 					while (isdigit(*s))
7644887Schin 						p->version = p->version * 10 + (*s++ - '0');
7654887Schin 				while (*s && *s != '?' && *s != ']')
7664887Schin 				{
7674887Schin 					c = *s++;
7688462SApril.Chin@Sun.COM 					if (!isdigit(*s))
7694887Schin 						n = 1;
7704887Schin 					else
7714887Schin 					{
7724887Schin 						n = 0;
7738462SApril.Chin@Sun.COM 						while (isdigit(*s))
7744887Schin 							n = n * 10 + (*s++ - '0');
7754887Schin 					}
7764887Schin 					switch (c)
7774887Schin 					{
7788462SApril.Chin@Sun.COM 					case '+':
7798462SApril.Chin@Sun.COM 						p->flags |= OPT_plus;
7808462SApril.Chin@Sun.COM 						break;
7814887Schin 					case 'c':
7824887Schin 						p->flags |= OPT_cache;
7834887Schin 						break;
7844887Schin 					case 'i':
7854887Schin 						p->flags |= OPT_ignore;
7864887Schin 						break;
7874887Schin 					case 'l':
7884887Schin 						p->flags |= OPT_long;
7894887Schin 						break;
7908462SApril.Chin@Sun.COM 					case 'n':
7918462SApril.Chin@Sun.COM 						p->flags |= OPT_numeric;
7928462SApril.Chin@Sun.COM 						break;
7934887Schin 					case 'o':
7944887Schin 						p->flags |= OPT_old;
7954887Schin 						break;
7964887Schin 					case 'p':
7974887Schin 						p->prefix = n;
7984887Schin 						break;
7994887Schin 					case 's':
8004887Schin 						p->section = n;
8014887Schin 						if (n > 1 && n < 6)
8024887Schin 						{
8034887Schin 							p->flags |= OPT_functions;
8044887Schin 							p->prefix = 0;
8054887Schin 						}
8064887Schin 						break;
8074887Schin 					}
8084887Schin 				}
8094887Schin 			}
8104887Schin 		}
8114887Schin 		while (*s)
8124887Schin 			if (*s++ == ']' && *s++ == '[')
8134887Schin 			{
8144887Schin 				if (*s++ != '-')
8154887Schin 				{
8164887Schin 					if (!error_info.id && strneq(s - 1, "+NAME?", 6))
8174887Schin 					{
8184887Schin 						for (t = s += 5; *t && *t != ' ' && *t != ']'; t++);
8194887Schin 						error_info.id = save(sfprints("%-.*s", t - s, s));
8204887Schin 					}
8214887Schin 					break;
8224887Schin 				}
8234887Schin 				if (*s == '-')
8244887Schin 					s++;
8254887Schin 				if (strneq(s, "catalog?", 8))
8264887Schin 				{
8274887Schin 					s += 8;
8284887Schin 					if ((t = strchr(s, ']')) && (!error_info.id || (t - s) != strlen(error_info.id) || !strneq(s, error_info.id, t - s)))
8294887Schin 						p->catalog = save(sfprints("%-.*s", t - s, s));
8304887Schin 					if (error_info.id)
8314887Schin 						break;
8324887Schin 				}
8334887Schin 			}
8344887Schin 	}
8354887Schin 	if (!p->catalog)
8364887Schin 	{
8374887Schin 		if (opt_info.disc && opt_info.disc->catalog && (!error_info.id || !streq(opt_info.disc->catalog, error_info.id)))
8384887Schin 			p->catalog = opt_info.disc->catalog;
8394887Schin 		else
8404887Schin 			p->catalog = ID;
8414887Schin 	}
8424887Schin 	s = p->oopts;
8434887Schin 	if (*s == ':')
8444887Schin 		s++;
8454887Schin 	if (*s == '+')
8464887Schin 	{
8474887Schin 		s++;
8484887Schin 		p->flags |= OPT_plus;
8494887Schin 	}
8508462SApril.Chin@Sun.COM 	s = next(s, 0);
8514887Schin 	if (*s != '[')
8524887Schin 		for (t = s, a = 0; *t; t++)
8534887Schin 			if (!a && *t == '-')
8544887Schin 			{
8554887Schin 				p->flags |= OPT_minus;
8564887Schin 				break;
8574887Schin 			}
8584887Schin 			else if (*t == '[')
8594887Schin 				a++;
8604887Schin 			else if (*t == ']')
8614887Schin 				a--;
8624887Schin 	if (!p->version && (t = strchr(s, '(')) && strchr(t, ')') && (opt_info.state->cp || (opt_info.state->cp = sfstropen())))
8634887Schin 	{
8644887Schin 		/*
8654887Schin 		 * solaris long option compatibility
8664887Schin 		 */
8674887Schin 
8684887Schin 		p->version = 1;
8694887Schin 		for (t = p->oopts; t < s; t++)
8704887Schin 			sfputc(opt_info.state->cp, *t);
8714887Schin 		n = t - p->oopts;
8724887Schin 		sfputc(opt_info.state->cp, '[');
8734887Schin 		sfputc(opt_info.state->cp, '-');
8744887Schin 		sfputc(opt_info.state->cp, ']');
8754887Schin 		while (c = *s++)
8764887Schin 		{
8774887Schin 			sfputc(opt_info.state->cp, '[');
8784887Schin 			sfputc(opt_info.state->cp, c);
8794887Schin 			if (a = (c = *s++) == ':')
8804887Schin 				c = *s++;
8814887Schin 			if (c == '(')
8824887Schin 			{
8834887Schin 				sfputc(opt_info.state->cp, ':');
8844887Schin 				for (;;)
8854887Schin 				{
8864887Schin 					while ((c = *s++) && c != ')')
8874887Schin 						sfputc(opt_info.state->cp, c);
8884887Schin 					if (!c || *s != '(')
8894887Schin 						break;
8904887Schin 					sfputc(opt_info.state->cp, '|');
8914887Schin 					s++;
8924887Schin 				}
8934887Schin 			}
8944887Schin 			sfputc(opt_info.state->cp, ']');
8954887Schin 			if (a)
8964887Schin 				sfputr(opt_info.state->cp, ":[string]", -1);
8974887Schin 			if (!c)
8984887Schin 				break;
8994887Schin 		}
9004887Schin 		if (!(p->oopts = s = sfstruse(opt_info.state->cp)))
9014887Schin 			return -1;
9024887Schin 		s += n;
9034887Schin 	}
9044887Schin 	p->opts = s;
905*10898Sroland.mainz@nrubsig.org 	message((-1, "version=%d prefix=%d section=%d flags=%04x catalog=%s", p->version, p->prefix, p->section, p->flags, p->catalog));
9064887Schin 	return 0;
9074887Schin }
9084887Schin 
9094887Schin /*
9104887Schin  * return the bold set/unset sequence for style
9114887Schin  */
9124887Schin 
9134887Schin static const char*
9144887Schin font(int f, int style, int set)
9154887Schin {
9164887Schin 	switch (style)
9174887Schin 	{
9184887Schin 	case STYLE_html:
9194887Schin 		return fonts[f].html[set];
9204887Schin 	case STYLE_nroff:
9214887Schin 		return fonts[f].nroff[set];
9224887Schin 	case STYLE_short:
9234887Schin 	case STYLE_long:
9244887Schin 	case STYLE_posix:
9254887Schin 	case STYLE_api:
9264887Schin 		break;
9274887Schin 	default:
9284887Schin 		if (opt_info.state->emphasis > 0)
9294887Schin 			return fonts[f].term[set];
9304887Schin 		break;
9314887Schin 	}
9324887Schin 	return "";
9334887Schin }
9344887Schin 
9354887Schin /*
9364887Schin  * expand \f...\f info
9374887Schin  * *p set to next char after second \f
9384887Schin  * expanded value returned
9394887Schin  */
9404887Schin 
9414887Schin static char*
9424887Schin expand(register char* s, register char* e, char** p, Sfio_t* ip)
9434887Schin {
9444887Schin 	register int	c;
9454887Schin 	register char*	b = s;
9464887Schin 	int		n;
9474887Schin 
9484887Schin 	message((-23, "AHA#%d expand(%s)", __LINE__, show(s)));
9494887Schin 	n = sfstrtell(ip);
9504887Schin 	c = 1;
9514887Schin 	while ((!e || s < e) && (c = *s++) && c != '\f');
9524887Schin 	sfwrite(ip, b, s - b - 1);
9534887Schin 	sfputc(ip, 0);
9544887Schin 	b = sfstrbase(ip) + n;
9554887Schin 	message((-23, "AHA#%d expand(%s)", __LINE__, b));
9564887Schin 	n = sfstrtell(ip);
9574887Schin 	if (!c)
9584887Schin 		s--;
9594887Schin 	if (*b == '?')
9604887Schin 	{
9614887Schin 		if (!*++b || streq(b, "NAME"))
9624887Schin 		{
9634887Schin 			if (!(b = error_info.id))
9644887Schin 				b = "command";
9654887Schin 			sfstrseek(ip, 0, SEEK_SET);
9664887Schin 			sfputr(ip, b, -1);
9674887Schin 			n = 0;
9684887Schin 		}
9694887Schin 		else
9704887Schin 			n = 1;
9714887Schin 	}
9724887Schin 	else if (!opt_info.disc || !opt_info.disc->infof || (*opt_info.disc->infof)(&opt_info, ip, b, opt_info.disc) < 0)
9734887Schin 		n = 0;
9744887Schin 	*p = s;
9754887Schin 	if (s = sfstruse(ip))
9764887Schin 		s += n;
9774887Schin 	else
9784887Schin 		s = "error";
9794887Schin 	return s;
9804887Schin }
9814887Schin 
9824887Schin /*
9834887Schin  * push \f...\f info
9844887Schin  */
9854887Schin 
9864887Schin static Push_t*
9874887Schin info(Push_t* psp, char* s, char* e, Sfio_t* ip)
9884887Schin {
9894887Schin 	register char*	b;
9904887Schin 	int		n;
9914887Schin 	Push_t*		tsp;
9924887Schin 
9934887Schin 	static Push_t	push;
9944887Schin 
9954887Schin 	b = expand(s, e, &s, ip);
9964887Schin 	n = strlen(b);
9974887Schin 	if (tsp = newof(0, Push_t, 1, n + 1))
9984887Schin 	{
9994887Schin 		tsp->nb = (char*)(tsp + 1);
10004887Schin 		tsp->ne = tsp->nb + n;
10014887Schin 		strcpy(tsp->nb, b);
10024887Schin 	}
10034887Schin 	else
10044887Schin 		tsp = &push;
10054887Schin 	tsp->next = psp;
10064887Schin 	tsp->ob = s;
10074887Schin 	tsp->oe = e;
10084887Schin 	return tsp;
10094887Schin }
10104887Schin 
10114887Schin /*
10124887Schin  * push translation
10134887Schin  */
10144887Schin 
10154887Schin static Push_t*
10164887Schin localize(Push_t* psp, char* s, char* e, int term, int n, char* catalog, int version, Sfio_t* ip)
10174887Schin {
10184887Schin 	char*		t;
10194887Schin 	char*		u;
10204887Schin 	Push_t*		tsp;
10214887Schin 	int		c;
10224887Schin 
10234887Schin 	t = skip(s, term, 0, 0, n, 0, 0, version);
10244887Schin 	if (e && t > e)
10254887Schin 		t = e;
10264887Schin 	while (s < t)
10274887Schin 	{
10284887Schin 		switch (c = *s++)
10294887Schin 		{
10304887Schin 		case ':':
10314887Schin 		case '?':
10324887Schin 			if (term && *s == c)
10334887Schin 				s++;
10344887Schin 			break;
10354887Schin 		case ']':
10364887Schin 			if (*s == c)
10374887Schin 				s++;
10384887Schin 			break;
10394887Schin 		}
10404887Schin 		sfputc(ip, c);
10414887Schin 	}
10424887Schin 	if (!(s = sfstruse(ip)) || (u = T(error_info.id, catalog, s)) == s)
10434887Schin 		return 0;
10444887Schin 	n = strlen(u);
10454887Schin 	if (tsp = newof(0, Push_t, 1, n + 1))
10464887Schin 	{
10474887Schin 		tsp->nb = (char*)(tsp + 1);
10484887Schin 		tsp->ne = tsp->nb + n;
10494887Schin 		strcpy(tsp->nb, u);
10504887Schin 		tsp->ob = t;
10514887Schin 		tsp->oe = e;
10524887Schin 		tsp->ch = 1;
10534887Schin 	}
10544887Schin 	tsp->next = psp;
10554887Schin 	return tsp;
10564887Schin }
10574887Schin 
10584887Schin /*
10594887Schin  * output label s from [ ...label...[?...] ] to sp
10604887Schin  * 1 returned if the label was translated
10614887Schin  */
10624887Schin 
10634887Schin static int
10648462SApril.Chin@Sun.COM label(register Sfio_t* sp, int sep, register char* s, int about, int z, int level, int style, int f, Sfio_t* ip, int version, char* catalog)
10654887Schin {
10664887Schin 	register int	c;
10674887Schin 	register char*	t;
10684887Schin 	register char*	e;
10694887Schin 	int		ostyle;
10704887Schin 	int		a;
10714887Schin 	int		i;
10724887Schin 	char*		p;
10734887Schin 	char*		w;
10744887Schin 	char*		y;
10754887Schin 	int		va;
10764887Schin 	Push_t*		tsp;
10774887Schin 
10784887Schin 	int		r = 0;
10794887Schin 	int		n = 1;
10804887Schin 	Push_t*		psp = 0;
10814887Schin 
10824887Schin 	if ((ostyle = style) > (STYLE_nroff - (sep <= 0)) && f != FONT_LITERAL)
10834887Schin 		style = 0;
10844887Schin 	if (z < 0)
10854887Schin 		e = s + strlen(s);
10864887Schin 	else
10874887Schin 		e = s + z;
10884887Schin 	if (sep > 0)
10894887Schin 	{
10904887Schin 		if (sep == ' ' && style == STYLE_nroff)
10914887Schin 			sfputc(sp, '\\');
10924887Schin 		sfputc(sp, sep);
10934887Schin 	}
10944887Schin 	sep = !sep || z < 0;
10954887Schin 	va = 0;
10964887Schin 	y = 0;
10978462SApril.Chin@Sun.COM 	if (about)
10988462SApril.Chin@Sun.COM 		sfputc(sp, '(');
10994887Schin 	if (version < 1)
11004887Schin 	{
11014887Schin 		a = 0;
11024887Schin 		for (;;)
11034887Schin 		{
11044887Schin 			if (s >= e)
11054887Schin 				return r;
11064887Schin 			switch (c = *s++)
11074887Schin 			{
11084887Schin 			case '[':
11094887Schin 				a++;
11104887Schin 				break;
11114887Schin 			case ']':
11124887Schin 				if (--a < 0)
11134887Schin 					return r;
11144887Schin 				break;
11154887Schin 			}
11164887Schin 			sfputc(sp, c);
11174887Schin 		}
11184887Schin 	}
11194887Schin 	else if (level && (*(p = skip(s, 0, 0, 0, 1, level, 1, version)) == ':' || *p == '#'))
11204887Schin 	{
11214887Schin 		va = 0;
11224887Schin 		if (*++p == '?' || *p == *(p - 1))
11234887Schin 		{
11244887Schin 			p++;
11254887Schin 			va |= OPT_optional;
11264887Schin 		}
11274887Schin 		if (*(p = next(p, version)) == '[')
11284887Schin 			y = p + 1;
11294887Schin 	}
11304887Schin 	if (X(catalog) && (!level || *s == '\a' || *(s - 1) != '+') &&
11314887Schin 	    (tsp = localize(psp, s, e, (sep || level) ? '?' : 0, sep || level, catalog, version, ip)))
11324887Schin 	{
11334887Schin 		psp= tsp;
11344887Schin 		s = psp->nb;
11354887Schin 		e = psp->ne;
11364887Schin 		r = psp->ch > 0;
11374887Schin 	}
11384887Schin 	switch (*s)
11394887Schin 	{
11404887Schin 	case '\a':
11414887Schin 		if (f == FONT_ITALIC)
11424887Schin 			s++;
11434887Schin 		f = 0;
11444887Schin 		break;
11454887Schin 	case '\b':
11464887Schin 		if (f == FONT_BOLD)
11474887Schin 			s++;
11484887Schin 		f = 0;
11494887Schin 		break;
11504887Schin 	case '\v':
11514887Schin 		if (f == FONT_LITERAL)
11524887Schin 			s++;
11534887Schin 		f = 0;
11544887Schin 		break;
11554887Schin 	default:
11564887Schin 		if (f)
11574887Schin 			sfputr(sp, font(f, style, 1), -1);
11584887Schin 		break;
11594887Schin 	}
11604887Schin 	for (;;)
11614887Schin 	{
11624887Schin 		if (s >= e)
11634887Schin 		{
11644887Schin 			if (!(tsp = psp))
11654887Schin 				goto restore;
11664887Schin 			s = psp->ob;
11674887Schin 			e = psp->oe;
11684887Schin 			psp = psp->next;
11694887Schin 			free(tsp);
11704887Schin 			continue;
11714887Schin 		}
11724887Schin 		switch (c = *s++)
11734887Schin 		{
11744887Schin 		case '(':
11754887Schin 			if (n)
11764887Schin 			{
11774887Schin 				n = 0;
11784887Schin 				if (f)
11794887Schin 				{
11804887Schin 					sfputr(sp, font(f, style, 0), -1);
11814887Schin 					f = 0;
11824887Schin 				}
11834887Schin 			}
11844887Schin 			break;
11854887Schin 		case '?':
11864887Schin 		case ':':
11874887Schin 		case ']':
11884887Schin 			if (psp && psp->ch)
11894887Schin 				break;
11904887Schin 			if (y)
11914887Schin 			{
11924887Schin 				if (va & OPT_optional)
11934887Schin 					sfputc(sp, '[');
11944887Schin 				sfputc(sp, '=');
11958462SApril.Chin@Sun.COM 				label(sp, 0, y, 0, -1, 0, style, FONT_ITALIC, ip, version, catalog);
11964887Schin 				if (va & OPT_optional)
11974887Schin 					sfputc(sp, ']');
11984887Schin 				y = 0;
11994887Schin 			}
12004887Schin 			switch (c)
12014887Schin 			{
12024887Schin 			case '?':
12034887Schin 				if (*s == '?')
12044887Schin 					s++;
12054887Schin 				else if (*s == ']' && *(s + 1) != ']')
12064887Schin 					continue;
12074887Schin 				else if (sep)
12084887Schin 					goto restore;
12094887Schin 				else if (X(catalog) && (tsp = localize(psp, s, e, 0, 1, catalog, version, ip)))
12104887Schin 				{
12114887Schin 					psp = tsp;
12124887Schin 					s = psp->nb;
12134887Schin 					e = psp->ne;
12144887Schin 				}
12154887Schin 				break;
12164887Schin 			case ']':
12174887Schin 				if (sep && *s++ != ']')
12184887Schin 					goto restore;
12194887Schin 				break;
12204887Schin 			case ':':
12214887Schin 				if (sep && *s++ != ':')
12224887Schin 					goto restore;
12234887Schin 				break;
12244887Schin 			}
12254887Schin 			break;
12264887Schin 		case '\a':
12274887Schin 			a = FONT_ITALIC;
12284887Schin 		setfont:
12294887Schin 			if (f & ~a)
12304887Schin 			{
12314887Schin 				sfputr(sp, font(f, style, 0), -1);
12324887Schin 				f = 0;
12334887Schin 			}
12344887Schin 			if (!f && style == STYLE_html)
12354887Schin 			{
12364887Schin 				for (t = s; t < e && !isspace(*t) && !iscntrl(*t); t++);
12374887Schin 				if (*t == c && *++t == '(')
12384887Schin 				{
12394887Schin 					w = t;
12404887Schin 					while (++t < e && isdigit(*t));
12414887Schin 					if (t < e && *t == ')' && t > w + 1)
12424887Schin 					{
12434887Schin 						sfprintf(sp, "<NOBR><A href=\"../man%-.*s/%-.*s.html\">%s%-.*s%s</A>%-.*s</NOBR>"
12444887Schin 							, t - w - 1, w + 1
12454887Schin 							, w - s - 1, s
12464887Schin 							, font(a, style, 1)
12474887Schin 							, w - s - 1, s
12484887Schin 							, font(a, style, 0)
12494887Schin 							, t - w + 1, w
12504887Schin 							);
12514887Schin 						s = t + 1;
12524887Schin 						continue;
12534887Schin 					}
12544887Schin 				}
12554887Schin 			}
12564887Schin 			sfputr(sp, font(a, style, !!(f ^= a)), -1);
12574887Schin 			continue;
12584887Schin 		case '\b':
12594887Schin 			a = FONT_BOLD;
12604887Schin 			goto setfont;
12614887Schin 		case '\f':
12624887Schin 			psp = info(psp, s, e, ip);
12634887Schin 			if (psp->nb)
12644887Schin 			{
12654887Schin 				s = psp->nb;
12664887Schin 				e = psp->ne;
12674887Schin 			}
12684887Schin 			else
12694887Schin 			{
12704887Schin 				s = psp->ob;
12714887Schin 				psp = psp->next;
12724887Schin 			}
12734887Schin 			continue;
12744887Schin 		case '\n':
12754887Schin 			sfputc(sp, c);
12764887Schin 			for (i = 0; i < level; i++)
12774887Schin 				sfputc(sp, '\t');
12784887Schin 			continue;
12794887Schin 		case '\v':
12804887Schin 			a = FONT_LITERAL;
12814887Schin 			goto setfont;
12824887Schin 		case '<':
12834887Schin 			if (style == STYLE_html)
12844887Schin 			{
12854887Schin 				sfputr(sp, "&lt;", -1);
12864887Schin 				c = 0;
12874887Schin 				for (t = s; t < e; t++)
12884887Schin 					if (!isalnum(*t) && *t != '_' && *t != '.' && *t != '-')
12894887Schin 					{
12904887Schin 						if (*t == '@')
12914887Schin 						{
12924887Schin 							if (c)
12934887Schin 								break;
12944887Schin 							c = 1;
12954887Schin 						}
12964887Schin 						else if (*t == '>')
12974887Schin 						{
12984887Schin 							if (c)
12994887Schin 							{
13004887Schin 								sfprintf(sp, "<A href=\"mailto:%-.*s>%-.*s</A>&gt;", t - s, s, t - s, s);
13014887Schin 								s = t + 1;
13024887Schin 							}
13034887Schin 							break;
13044887Schin 						}
13054887Schin 						else
13064887Schin 							break;
13074887Schin 					}
13084887Schin 				continue;
13094887Schin 			}
13104887Schin 			break;
13114887Schin 		case '>':
13124887Schin 			if (style == STYLE_html)
13134887Schin 			{
13144887Schin 				sfputr(sp, "&gt;", -1);
13154887Schin 				continue;
13164887Schin 			}
13174887Schin 			break;
13184887Schin 		case '&':
13194887Schin 			if (style == STYLE_html)
13204887Schin 			{
13214887Schin 				sfputr(sp, "&amp;", -1);
13224887Schin 				continue;
13234887Schin 			}
13244887Schin 			break;
13254887Schin 		case '-':
13264887Schin 			if (ostyle == STYLE_nroff)
13274887Schin 				sfputc(sp, '\\');
13284887Schin 			break;
13294887Schin 		case '.':
13304887Schin 			if (ostyle == STYLE_nroff)
13314887Schin 			{
13324887Schin 				sfputc(sp, '\\');
13334887Schin 				sfputc(sp, '&');
13344887Schin 			}
13354887Schin 			break;
13364887Schin 		case '\\':
13374887Schin 			if (ostyle == STYLE_nroff)
13384887Schin 			{
13394887Schin 				c = 'e';
13404887Schin 				sfputc(sp, '\\');
13414887Schin 			}
13424887Schin 			break;
13434887Schin 		case ' ':
13444887Schin 			if (ostyle == STYLE_nroff)
13454887Schin 				sfputc(sp, '\\');
13464887Schin 			break;
13474887Schin 		}
13484887Schin 		sfputc(sp, c);
13494887Schin 	}
13504887Schin  restore:
13514887Schin 	if (f)
13524887Schin 		sfputr(sp, font(f, style, 0), -1);
13538462SApril.Chin@Sun.COM 	if (about)
13548462SApril.Chin@Sun.COM 		sfputc(sp, ')');
13554887Schin 	if (psp)
13564887Schin 		pop(psp);
13574887Schin 	return r;
13584887Schin }
13594887Schin 
13604887Schin /*
13614887Schin  * output args description to sp from p of length n
13624887Schin  */
13634887Schin 
13644887Schin static void
13654887Schin args(register Sfio_t* sp, register char* p, register int n, int flags, int style, Sfio_t* ip, int version, char* catalog)
13664887Schin {
13674887Schin 	register int	i;
13684887Schin 	register char*	t;
13694887Schin 	register char*	o;
13704887Schin 	register char*	a = 0;
13714887Schin 	char*		b;
13724887Schin 	int		sep;
13734887Schin 
13744887Schin 	if (flags & OPT_functions)
13754887Schin 		sep = '\t';
13764887Schin 	else
13774887Schin 	{
13784887Schin 		sep = ' ';
13794887Schin 		o = T(NiL, ID, "options");
13804887Schin 		b = style == STYLE_nroff ? "\\ " : " ";
13814887Schin 		for (;;)
13824887Schin 		{
13834887Schin 			t = (char*)memchr(p, '\n', n);
13844887Schin 			if (style >= STYLE_man)
13854887Schin 			{
13864887Schin 				if (!(a = error_info.id))
13874887Schin 					a = "...";
13884887Schin 				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);
13894887Schin 			}
13904887Schin 			else if (a)
13914887Schin 				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);
13924887Schin 			else
13934887Schin 			{
13944887Schin 				if (!(a = error_info.id))
13954887Schin 					a = "...";
13964887Schin 				if (!sfstrtell(sp))
13974887Schin 					sfprintf(sp, "[%s%s%s]", b, o, b);
13984887Schin 			}
13994887Schin 			if (!t)
14004887Schin 				break;
14014887Schin 			i = ++t - p;
14024887Schin 			if (i)
14034887Schin 			{
14044887Schin 				sfputr(sp, b, -1);
14054887Schin 				if (X(catalog))
14064887Schin 				{
14074887Schin 					sfwrite(ip, p, i);
14084887Schin 					if (b = sfstruse(ip))
14094887Schin 						sfputr(sp, T(error_info.id, catalog, b), -1);
14104887Schin 					else
14114887Schin 						sfwrite(sp, p, i);
14124887Schin 				}
14134887Schin 				else
14144887Schin 					sfwrite(sp, p, i);
14154887Schin 			}
14164887Schin 			if (style == STYLE_html)
14174887Schin 				sfputr(sp, "<BR>", '\n');
14184887Schin 			else if (style == STYLE_nroff)
14194887Schin 				sfputr(sp, ".br", '\n');
14204887Schin 			else if (style == STYLE_api)
14214887Schin 				sfputr(sp, ".BR", '\n');
14224887Schin 			p = t;
14234887Schin 			n -= i;
14244887Schin 			while (n > 0 && (*p == ' ' || *p == '\t'))
14254887Schin 			{
14264887Schin 				p++;
14274887Schin 				n--;
14284887Schin 			}
14294887Schin 		}
14304887Schin 	}
14314887Schin 	if (n)
14328462SApril.Chin@Sun.COM 		label(sp, sep, p, 0, n, 0, style, 0, ip, version, catalog);
14334887Schin }
14344887Schin 
14354887Schin /*
14364887Schin  * output [+-...label...?...] label s to sp
14374887Schin  * according to {...} level and style
14384887Schin  * return 0:header 1:paragraph
14394887Schin  */
14404887Schin 
14414887Schin static int
14428462SApril.Chin@Sun.COM item(Sfio_t* sp, char* s, int about, int level, int style, Sfio_t* ip, int version, char* catalog)
14434887Schin {
14444887Schin 	register char*	t;
14454887Schin 	int		n;
14464887Schin 	int		par;
14474887Schin 
14484887Schin 	sfputc(sp, '\n');
14494887Schin 	if (*s == '\n')
14504887Schin 	{
14514887Schin 		par = 0;
14524887Schin 		if (style >= STYLE_nroff)
14534887Schin 			sfprintf(sp, ".DS\n");
14544887Schin 		else
14554887Schin 		{
14564887Schin 			if (style == STYLE_html)
14574887Schin 				sfprintf(sp, "<PRE>\n");
14584887Schin 			else
14594887Schin 				sfputc(sp, '\n');
14604887Schin 			for (n = 0; n < level; n++)
14614887Schin 				sfputc(sp, '\t');
14624887Schin 		}
14638462SApril.Chin@Sun.COM 		label(sp, 0, s + 1, about, -1, level, style, FONT_LITERAL, ip, version, catalog);
14644887Schin 		sfputc(sp, '\n');
14654887Schin 		if (style >= STYLE_nroff)
14664887Schin 			sfprintf(sp, ".DE");
14674887Schin 		else if (style == STYLE_html)
14684887Schin 			sfprintf(sp, "</PRE>");
14694887Schin 	}
14704887Schin 	else if (*s != ']' && (*s != '?' || *(s + 1) == '?'))
14714887Schin 	{
14724887Schin 		par = 0;
14734887Schin 		if (level)
14744887Schin 		{
14754887Schin 			if (style >= STYLE_nroff)
14768462SApril.Chin@Sun.COM 				sfprintf(sp, ".H%d ", (level - (level > 2)) / 2);
14774887Schin 			else
14784887Schin 				for (n = 0; n < level; n++)
14794887Schin 					sfputc(sp, '\t');
14804887Schin 		}
14814887Schin 		if (style == STYLE_html)
14824887Schin 		{
14834887Schin 			if (!level)
14844887Schin 				sfputr(sp, "<H4>", -1);
14854887Schin 			sfputr(sp, "<A name=\"", -1);
14864887Schin 			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] == '?')
14874887Schin 				for (t = s + 8; *t && *t != ']'; t++)
14884887Schin 					if (t[0] == 'p' && (!strncmp(t, "proprietary", 11) || !strncmp(t, "private", 7)) || t[0] == 'n' && !strncmp(t, "noncommercial", 13))
14894887Schin 					{
14904887Schin 						opt_info.state->flags |= OPT_proprietary;
14914887Schin 						break;
14924887Schin 					}
14938462SApril.Chin@Sun.COM 			label(sp, 0, s, about, -1, level, 0, 0, ip, version, catalog);
14944887Schin 			sfputr(sp, "\">", -1);
14958462SApril.Chin@Sun.COM 			label(sp, 0, s, about, -1, level, style, level ? FONT_BOLD : 0, ip, version, catalog);
14964887Schin 			sfputr(sp, "</A>", -1);
14974887Schin 			if (!level)
14984887Schin 				sfputr(sp, "</H4>", -1);
14994887Schin 		}
15004887Schin 		else
15014887Schin 		{
15024887Schin 			if (!level)
15034887Schin 			{
15044887Schin 				if (style >= STYLE_nroff)
15054887Schin 					sfprintf(sp, ".SH ");
15064887Schin 				else if (style == STYLE_man)
15074887Schin 					sfputc(sp, '\n');
15084887Schin 				else if (style != STYLE_options && style != STYLE_match || *s == '-' || *s == '+')
15094887Schin 					sfputc(sp, '\t');
15104887Schin 			}
15118462SApril.Chin@Sun.COM 			label(sp, 0, s, about, -1, level, style, FONT_BOLD, ip, version, catalog);
15124887Schin 		}
15134887Schin 	}
15144887Schin 	else
15154887Schin 	{
15164887Schin 		par = 1;
15174887Schin 		if (style >= STYLE_nroff)
15188462SApril.Chin@Sun.COM 			sfputr(sp, level ? ".SP" : ".PP", -1);
15194887Schin 	}
15204887Schin 	if (style >= STYLE_nroff || !level)
15214887Schin 		sfputc(sp, '\n');
15224887Schin 	if (par && style < STYLE_nroff)
15234887Schin 		for (n = 0; n < level; n++)
15244887Schin 			sfputc(sp, '\t');
15254887Schin 	return par;
15264887Schin }
15274887Schin 
15284887Schin /*
15294887Schin  * output text to sp from p according to style
15304887Schin  */
15314887Schin 
15324887Schin static char*
15334887Schin textout(Sfio_t* sp, register char* p, int style, int level, int bump, Sfio_t* ip, int version, char* catalog)
15344887Schin {
15354887Schin #if 0
15364887Schin #define textout(a,b,c,d,e,f,g,h)	(sfprintf(a,"(%d)",__LINE__),textout(a,b,c,d,e,f,g,h))
15374887Schin #endif
15384887Schin 	register char*	t;
15394887Schin 	register int	c;
15404887Schin 	register int	n;
15414887Schin 	char*		e;
15424887Schin 	int		a;
15434887Schin 	int		f;
15444887Schin 	int		par;
15458462SApril.Chin@Sun.COM 	int		about;
15464887Schin 	Push_t*		tsp;
15474887Schin 
15484887Schin 	int		ident = 0;
15494887Schin 	int		lev = level;
15504887Schin 	Push_t*		psp = 0;
15514887Schin 
15524887Schin  again:
15538462SApril.Chin@Sun.COM 	about = 0;
15544887Schin 	if ((c = *p) == GO)
15554887Schin 	{
15564887Schin 		for (;;)
15574887Schin 		{
15584887Schin 			while (*(p = next(p + 1, version)) == '\n');
15594887Schin 			if (*p == GO)
15604887Schin 			{
15614887Schin 				if (level > 1)
15624887Schin 					level++;
15634887Schin 				level++;
15644887Schin 			}
15654887Schin 			else if (*p != OG)
15664887Schin 			{
15678462SApril.Chin@Sun.COM 				if (level <= 1 || *p != '[' || *(p + 1) != '-' || style == STYLE_man && *(p + 2) == '?' || isalpha(*(p + 2)))
15684887Schin 					break;
15694887Schin 				p = skip(p, 0, 0, 0, 1, level, 0, version);
15704887Schin 			}
15714887Schin 			else if ((level -= 2) <= lev)
15724887Schin 				return p + 1;
15734887Schin 		}
15744887Schin 		if (*p == '\f')
15754887Schin 		{
15764887Schin 			psp = info(psp, p + 1, NiL, ip);
15774887Schin 			if (psp->nb)
15784887Schin 				p = psp->nb;
15794887Schin 			else
15804887Schin 			{
15814887Schin 				p = psp->ob;
15824887Schin 				psp = psp->next;
15834887Schin 			}
15844887Schin 		}
15854887Schin 		if (*p != '[')
15864887Schin 			return p;
15874887Schin 		c = *++p;
15884887Schin 		if (level > 1)
15894887Schin 			level++;
15904887Schin 		level++;
15914887Schin 	}
15924887Schin 	if (c == '-' && level > 1)
15938462SApril.Chin@Sun.COM 	{
15948462SApril.Chin@Sun.COM 		if (style == STYLE_man)
15958462SApril.Chin@Sun.COM 		{
15968462SApril.Chin@Sun.COM 			about = 1;
15978462SApril.Chin@Sun.COM 			if (*(p + 1) == '-')
15988462SApril.Chin@Sun.COM 				p++;
15998462SApril.Chin@Sun.COM 		}
16008462SApril.Chin@Sun.COM 		else
16018462SApril.Chin@Sun.COM 			for (;;)
16028462SApril.Chin@Sun.COM 			{
16038462SApril.Chin@Sun.COM 				p = skip(p, 0, 0, 0, 1, level, 0, version);
16048462SApril.Chin@Sun.COM 				while (*(p = next(p + 1, version)) == '\n');
16058462SApril.Chin@Sun.COM 				if (*p == '[')
16068462SApril.Chin@Sun.COM 				{
16078462SApril.Chin@Sun.COM 					if ((c = *++p) != '-')
16088462SApril.Chin@Sun.COM 						break;
16098462SApril.Chin@Sun.COM 				}
16108462SApril.Chin@Sun.COM 				else if (*p == GO)
16118462SApril.Chin@Sun.COM 					goto again;
16128462SApril.Chin@Sun.COM 				else if (*p == OG)
16138462SApril.Chin@Sun.COM 					return p + 1;
16148462SApril.Chin@Sun.COM 			}
16158462SApril.Chin@Sun.COM 	}
16164887Schin 	if (c == '+' || c == '-' && (bump = 3) || c != ' ' && level > 1)
16174887Schin 	{
16184887Schin 		p = skip(t = p + 1, '?', 0, 0, 1, level, 0, version);
16198462SApril.Chin@Sun.COM 		if (c == '-' && (*t == '?' || isdigit(*t) || *p == '?' && *(p + 1) == '\n'))
16204887Schin 		{
16214887Schin 			if ((c = *p) != '?')
16224887Schin 				return skip(p, 0, 0, 0, 1, level, 1, version);
16238462SApril.Chin@Sun.COM 			e = C("version");
16248462SApril.Chin@Sun.COM 			par = item(sp, e, about, level, style, ip, version, ID);
16254887Schin 			for (;;)
16264887Schin 			{
16274887Schin 				while (isspace(*(p + 1)))
16284887Schin 					p++;
16294887Schin 				e = p;
16304887Schin 				if (e[1] == '@' && e[2] == '(' && e[3] == '#' && e[4] == ')')
16314887Schin 					p = e + 4;
16324887Schin 				else if (e[1] == '$' && e[2] == 'I' && e[3] == 'd' && e[4] == ':' && e[5] == ' ')
16334887Schin 				{
16344887Schin 					p = e + 5;
16354887Schin 					ident = 1;
16364887Schin 				}
16374887Schin 				else
16384887Schin 					break;
16394887Schin 			}
16404887Schin 		}
16414887Schin 		else
16424887Schin 		{
16434887Schin 			if (isdigit(c) && isdigit(*t))
16444887Schin 			{
16454887Schin 				while (isdigit(*t))
16464887Schin 					t++;
16474887Schin 				if (*t == ':')
16484887Schin 					t++;
16494887Schin 			}
16504887Schin 			else if (isalnum(c) && *t-- == ':')
16514887Schin 			{
16524887Schin 				if (X(catalog) || *t == *(t + 2))
16534887Schin 					t += 2;
16544887Schin 				else
16554887Schin 				{
16564887Schin 					sfprintf(ip, "%s", t);
16574887Schin 					if (e = sfstruse(ip))
16584887Schin 						*((t = e) + 1) = '|';
16594887Schin 				}
16604887Schin 			}
16618462SApril.Chin@Sun.COM 			par = item(sp, t, about, level, style, ip, version, catalog);
16624887Schin 			c = *p;
16634887Schin 		}
16648462SApril.Chin@Sun.COM 		if (!about && level)
16654887Schin 			par = 0;
16664887Schin 	}
16674887Schin 	else
16684887Schin 	{
16694887Schin 		if (style >= STYLE_nroff)
16704887Schin 			sfputc(sp, '\n');
16714887Schin 		else if (c == '?')
16724887Schin 			for (n = 0; n < level; n++)
16734887Schin 				sfputc(sp, '\t');
16744887Schin 		par = 0;
16754887Schin 	}
16764887Schin 	if (c == ':')
16774887Schin 		c = *(p = skip(p, '?', 0, 0, 1, 0, 0, version));
16784887Schin 	if ((c == ']' || c == '?' && *(p + 1) == ']' && *(p + 2) != ']' && p++) && (c = *(p = next(p + 1, version))) == GO)
16794887Schin 		p = textout(sp, p, style, level + bump + par + 1, 0, ip, version, catalog);
16804887Schin 	else if (c == '?' || c == ' ')
16814887Schin 	{
16824887Schin 		p++;
16834887Schin 		if (c == ' ')
16844887Schin 			sfputc(sp, c);
16854887Schin 		else
16864887Schin 		{
16874887Schin 			if (X(catalog) && (tsp = localize(psp, p, NiL, 0, 1, catalog, version, ip)))
16884887Schin 			{
16894887Schin 				psp = tsp;
16904887Schin 				p = psp->nb;
16914887Schin 			}
16924887Schin 			if (style < STYLE_nroff)
16934887Schin 				for (n = 0; n < bump + 1; n++)
16944887Schin 					sfputc(sp, '\t');
16954887Schin 		}
16964887Schin 		f = 0;
16974887Schin 		for (;;)
16984887Schin 		{
16994887Schin 			switch (c = *p++)
17004887Schin 			{
17014887Schin 			case 0:
17024887Schin 				if (!(tsp = psp))
17034887Schin 				{
17044887Schin 					if (f)
17054887Schin 						sfputr(sp, font(f, style, 0), -1);
17064887Schin 					return p - 1;
17074887Schin 				}
17084887Schin 				p = psp->ob;
17094887Schin 				psp = psp->next;
17104887Schin 				free(tsp);
17114887Schin 				continue;
17124887Schin 			case ']':
17134887Schin 				if (psp && psp->ch)
17144887Schin 					break;
17154887Schin 				if (*p != ']')
17164887Schin 				{
17174887Schin 					if (f)
17184887Schin 					{
17194887Schin 						sfputr(sp, font(f, style, 0), -1);
17204887Schin 						f = 0;
17214887Schin 					}
17224887Schin 					for (;;)
17234887Schin 					{
17244887Schin 						if ((*p == '#' || *p == ':') && level > lev)
17254887Schin 						{
17264887Schin 							char*	o;
17274887Schin 							char*	v;
17284887Schin 							int	j;
17294887Schin 							int	m;
17304887Schin 							int	ol;
17314887Schin 							int	vl;
17324887Schin 
17334887Schin 							a = 0;
17344887Schin 							o = 0;
17354887Schin 							v = 0;
17364887Schin 							if (*++p == '?' || *p == *(p - 1))
17374887Schin 							{
17384887Schin 								p++;
17394887Schin 								a |= OPT_optional;
17404887Schin 							}
17414887Schin 							if (*(p = next(p, version)) == '[')
17424887Schin 							{
17434887Schin 								p = skip(p + 1, ':', '?', 0, 1, 0, 0, version);
17444887Schin 								while (*p == ':')
17454887Schin 								{
17464887Schin 									p = skip(t = p + 1, ':', '?', 0, 1, 0, 0, version);
17474887Schin 									m = p - t;
17484887Schin 									if (*t == '!')
17494887Schin 									{
17504887Schin 										o = t + 1;
17514887Schin 										ol = m - 1;
17524887Schin 									}
17534887Schin 									else if (*t == '=')
17544887Schin 									{
17554887Schin 										v = t + 1;
17564887Schin 										vl = m - 1;
17574887Schin 									}
17584887Schin 									else
17594887Schin 										for (j = 0; j < elementsof(attrs); j++)
17604887Schin 											if (strneq(t, attrs[j].name, m))
17614887Schin 											{
17624887Schin 												a |= attrs[j].flag;
17634887Schin 												break;
17644887Schin 											}
17654887Schin 								}
17664887Schin 							}
17674887Schin 							if (a & OPT_optional)
17684887Schin 							{
17694887Schin 								if (o)
17704887Schin 								{
17714887Schin 									sfprintf(sp, " %s ", T(NiL, ID, "If the option value is omitted then"));
17724887Schin 									sfputr(sp, font(FONT_BOLD, style, 1), -1);
17734887Schin 									t = o + ol;
17744887Schin 									while (o < t)
17754887Schin 									{
17764887Schin 										if (((c = *o++) == ':' || c == '?') && *o == c)
17774887Schin 											o++;
17784887Schin 										sfputc(sp, c);
17794887Schin 									}
17804887Schin 									sfputr(sp, font(FONT_BOLD, style, 0), -1);
17814887Schin 									sfprintf(sp, " %s.", T(NiL, ID, "is assumed"));
17824887Schin 								}
17834887Schin 								else
17844887Schin 									sfprintf(sp, " %s", T(NiL, ID, "The option value may be omitted."));
17854887Schin 							}
17864887Schin 							if (v)
17874887Schin 							{
17884887Schin 								sfprintf(sp, " %s ", T(NiL, ID, "The default value is"));
17894887Schin 								sfputr(sp, font(FONT_BOLD, style, 1), -1);
17904887Schin 								t = v + vl;
17914887Schin 								while (v < t)
17924887Schin 								{
17934887Schin 									if (((c = *v++) == ':' || c == '?') && *v == c)
17944887Schin 										v++;
17954887Schin 									sfputc(sp, c);
17964887Schin 								}
17974887Schin 								sfputr(sp, font(FONT_BOLD, style, 0), -1);
17984887Schin 								sfputc(sp, '.');
17994887Schin 							}
18004887Schin 							p = skip(p, 0, 0, 0, 1, 0, 1, version);
18014887Schin 						}
18024887Schin 						if (*(p = next(p, version)) == GO)
18034887Schin 							p = textout(sp, p, style, level + bump + !level, 0, ip, version, catalog);
18044887Schin 						else if (*p == '[' && level > lev)
18054887Schin 						{
18064887Schin 							p++;
18074887Schin 							goto again;
18084887Schin 						}
18094887Schin 						else if (*p == '\f')
18104887Schin 						{
18114887Schin 							p++;
18124887Schin 							if (style != STYLE_keys)
18134887Schin 							{
18144887Schin 								psp = info(psp, p, NiL, ip);
18154887Schin 								if (psp->nb)
18164887Schin 									p = psp->nb;
18174887Schin 								else
18184887Schin 								{
18194887Schin 									p = psp->ob;
18204887Schin 									psp = psp->next;
18214887Schin 								}
18224887Schin 							}
18234887Schin 						}
18244887Schin 						else if (!*p)
18254887Schin 						{
18264887Schin 							if (!(tsp = psp))
18274887Schin 								break;
18284887Schin 							p = psp->ob;
18294887Schin 							psp = psp->next;
18304887Schin 							free(tsp);
18314887Schin 						}
18324887Schin 						else if (*p != OG)
18334887Schin 							break;
18344887Schin 						else
18354887Schin 						{
18364887Schin 							p++;
18374887Schin 							if ((level -= 2) <= lev)
18384887Schin 								break;
18394887Schin 						}
18404887Schin 					}
18414887Schin 					return p;
18424887Schin 				}
18434887Schin 				p++;
18444887Schin 				break;
18454887Schin 			case '\a':
18464887Schin 				a = FONT_ITALIC;
18474887Schin 			setfont:
18484887Schin 				if (f & ~a)
18494887Schin 				{
18504887Schin 					sfputr(sp, font(f, style, 0), -1);
18514887Schin 					f = 0;
18524887Schin 				}
18534887Schin 				if (!f && style == STYLE_html)
18544887Schin 				{
18554887Schin 					for (t = p; *t && !isspace(*t) && !iscntrl(*t); t++);
18564887Schin 					if (*t == c && *++t == '(')
18574887Schin 					{
18584887Schin 						e = t;
18594887Schin 						while (isdigit(*++t));
18604887Schin 						if (*t == ')' && t > e + 1)
18614887Schin 						{
18624887Schin 							sfprintf(sp, "<NOBR><A href=\"../man%-.*s/%-.*s.html\">%s%-.*s%s</A>%-.*s</NOBR>"
18634887Schin 								, t - e - 1, e + 1
18644887Schin 								, e - p - 1, p
18654887Schin 								, font(a, style, 1)
18664887Schin 								, e - p - 1, p
18674887Schin 								, font(a, style, 0)
18684887Schin 								, t - e + 1, e
18694887Schin 								);
18704887Schin 							p = t + 1;
18714887Schin 							continue;
18724887Schin 						}
18734887Schin 					}
18744887Schin 				}
18754887Schin 				sfputr(sp, font(a, style, !!(f ^= a)), -1);
18764887Schin 				continue;
18774887Schin 			case '\b':
18784887Schin 				a = FONT_BOLD;
18794887Schin 				goto setfont;
18804887Schin 			case '\f':
18814887Schin 				if (style != STYLE_keys)
18824887Schin 				{
18834887Schin 					psp = info(psp, p, NiL, ip);
18844887Schin 					if (psp->nb)
18854887Schin 						p = psp->nb;
18864887Schin 					else
18874887Schin 					{
18884887Schin 						p = psp->ob;
18894887Schin 						psp = psp->next;
18904887Schin 					}
18914887Schin 				}
18924887Schin 				continue;
18934887Schin 			case '\v':
18944887Schin 				a = FONT_LITERAL;
18954887Schin 				goto setfont;
18964887Schin 			case ' ':
18974887Schin 				if (ident && *p == '$')
18984887Schin 				{
18994887Schin 					while (*++p)
19004887Schin 						if (*p == ']')
19014887Schin 						{
19024887Schin 							if (*(p + 1) != ']')
19034887Schin 								break;
19044887Schin 							p++;
19054887Schin 						}
19064887Schin 					continue;
19074887Schin 				}
19084887Schin 			case '\n':
19094887Schin 			case '\r':
19104887Schin 			case '\t':
19114887Schin 				while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
19124887Schin 					p++;
19134887Schin 				if (*p == ']' && *(p + 1) != ']' && (!psp || !psp->ch))
19144887Schin 					continue;
19154887Schin 				c = ' ';
19164887Schin 				break;
19174887Schin 			case '<':
19184887Schin 				if (style == STYLE_html)
19194887Schin 				{
19204887Schin 					sfputr(sp, "&lt;", -1);
19214887Schin 					c = 0;
19224887Schin 					for (t = p; *t; t++)
19234887Schin 						if (!isalnum(*t) && *t != '_' && *t != '.' && *t != '-')
19244887Schin 						{
19254887Schin 							if (*t == '@')
19264887Schin 							{
19274887Schin 								if (c)
19284887Schin 									break;
19294887Schin 								c = 1;
19304887Schin 							}
19314887Schin 							else if (*t == '>')
19324887Schin 							{
19334887Schin 								if (c)
19344887Schin 								{
19354887Schin 									sfprintf(sp, "<A href=\"mailto:%-.*s\">%-.*s</A>&gt;", t - p, p, t - p, p);
19364887Schin 									p = t + 1;
19374887Schin 								}
19384887Schin 								break;
19394887Schin 							}
19404887Schin 							else
19414887Schin 								break;
19424887Schin 						}
19434887Schin 					continue;
19444887Schin 				}
19454887Schin 				break;
19464887Schin 			case '>':
19474887Schin 				if (style == STYLE_html)
19484887Schin 				{
19494887Schin 					sfputr(sp, "&gt;", -1);
19504887Schin 					continue;
19514887Schin 				}
19524887Schin 				break;
19534887Schin 			case '&':
19544887Schin 				if (style == STYLE_html)
19554887Schin 				{
19564887Schin 					sfputr(sp, "&amp;", -1);
19574887Schin 					continue;
19584887Schin 				}
19594887Schin 				break;
19604887Schin 			case '-':
19614887Schin 				if (style == STYLE_nroff)
19624887Schin 					sfputc(sp, '\\');
19634887Schin 				break;
19644887Schin 			case '.':
19654887Schin 				if (style == STYLE_nroff)
19664887Schin 				{
19674887Schin 					sfputc(sp, '\\');
19684887Schin 					sfputc(sp, '&');
19694887Schin 				}
19704887Schin 				break;
19714887Schin 			case '\\':
19724887Schin 				if (style == STYLE_nroff)
19734887Schin 				{
19744887Schin 					sfputc(sp, c);
19754887Schin 					c = 'e';
19764887Schin 				}
19774887Schin 				break;
19784887Schin 			}
19794887Schin 			sfputc(sp, c);
19804887Schin 		}
19814887Schin 	}
19824887Schin 	else if (c == '[' && level > lev)
19834887Schin 	{
19844887Schin 		p++;
19854887Schin 		goto again;
19864887Schin 	}
19874887Schin 	return p;
19884887Schin }
19894887Schin 
19904887Schin /*
19914887Schin  * generate optget() help [...] list from lp
19924887Schin  */
19934887Schin 
19944887Schin static void
19954887Schin list(Sfio_t* sp, register const List_t* lp)
19964887Schin {
19974887Schin 	sfprintf(sp, "[%c", lp->type);
19984887Schin 	if (lp->name)
19994887Schin 	{
20004887Schin 		sfprintf(sp, "%s", lp->name);
20014887Schin 		if (lp->text)
20024887Schin 			sfprintf(sp, "?%s", lp->text);
20034887Schin 	}
20044887Schin 	sfputc(sp, ']');
20054887Schin }
20064887Schin 
20074887Schin /*
20084887Schin  * return pointer to help message sans `Usage: command'
20094887Schin  * if oopts is 0 then opt_info.state->pass is used
20104887Schin  * what:
20114887Schin  *	0	?short by default, ?long if any long options used
20124887Schin  *	*	otherwise see help_text[] (--???)
20134887Schin  * external formatter:
20144887Schin  *	\a...\a	italic
20154887Schin  *	\b...\b	bold
20164887Schin  *	\f...\f	discipline infof callback on ...
20174887Schin  *	\v...\v	literal
20184887Schin  * internal formatter:
20194887Schin  *	\t	indent
20204887Schin  *	\n	newline
20214887Schin  * margin flush pops to previous indent
20224887Schin  */
20234887Schin 
20244887Schin char*
20254887Schin opthelp(const char* oopts, const char* what)
20264887Schin {
20274887Schin 	register Sfio_t*	sp;
20284887Schin 	register Sfio_t*	mp;
20294887Schin 	register int		c;
20304887Schin 	register char*		p;
20314887Schin 	register Indent_t*	ip;
20324887Schin 	char*			t;
20334887Schin 	char*			x;
20344887Schin 	char*			w;
20354887Schin 	char*			u;
20364887Schin 	char*			y;
20374887Schin 	char*			s;
20384887Schin 	char*			d;
20394887Schin 	char*			v;
20404887Schin 	char*			ov;
20414887Schin 	char*			name;
20424887Schin 	char*			pp;
20434887Schin 	char*			rb;
20444887Schin 	char*			re;
20454887Schin 	int			f;
20464887Schin 	int			i;
20474887Schin 	int			j;
20484887Schin 	int			m;
20494887Schin 	int			n;
20504887Schin 	int			a;
20514887Schin 	int			sl;
20524887Schin 	int			vl;
20534887Schin 	int			ol;
20544887Schin 	int			wl;
20554887Schin 	int			xl;
20564887Schin 	int			rm;
20574887Schin 	int			ts;
20584887Schin 	int			co;
20594887Schin 	int			z;
20604887Schin 	int			style;
20614887Schin 	int			head;
20628462SApril.Chin@Sun.COM 	int			margin;
20634887Schin 	int			mode;
20644887Schin 	int			mutex;
20654887Schin 	int			prefix;
20664887Schin 	int			version;
20674887Schin 	long			tp;
20684887Schin 	char*			catalog;
20694887Schin 	Optpass_t*		o;
20704887Schin 	Optpass_t*		q;
20714887Schin 	Optpass_t*		e;
20724887Schin 	Optpass_t		one;
20734887Schin 	Help_t*			hp;
20744887Schin 	short			ptstk[elementsof(indent) + 2];
20754887Schin 	short*			pt;
20764887Schin 	Sfio_t*			vp;
20774887Schin 	Push_t*			tsp;
20784887Schin 
20794887Schin 	char*			opts = (char*)oopts;
20804887Schin 	int			flags = 0;
20814887Schin 	int			matched = 0;
20824887Schin 	int			paragraph = 0;
20834887Schin 	int			section = 1;
20844887Schin 	Push_t*			psp = 0;
20854887Schin 	Sfio_t*			sp_help = 0;
20864887Schin 	Sfio_t*			sp_text = 0;
20874887Schin 	Sfio_t*			sp_plus = 0;
20884887Schin 	Sfio_t*			sp_head = 0;
20894887Schin 	Sfio_t*			sp_body = 0;
20904887Schin 	Sfio_t*			sp_info = 0;
20914887Schin 	Sfio_t*			sp_misc = 0;
20924887Schin 
20934887Schin 	if (!(mp = opt_info.state->mp) && !(mp = opt_info.state->mp = sfstropen()))
20944887Schin 		goto nospace;
20954887Schin 	if (!what)
20964887Schin 		style = opt_info.state->style;
20974887Schin 	else if (!*what)
20984887Schin 		style = STYLE_options;
20994887Schin 	else if (*what != '?')
21004887Schin 		style = STYLE_match;
21014887Schin 	else if (!*(what + 1))
21024887Schin 		style = STYLE_man;
21034887Schin 	else if ((hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), (char*)what + 1)) && hp->style >= 0)
21044887Schin 	{
21054887Schin 		style = hp->style;
21064887Schin 		if (*hp->name != '?')
21074887Schin 			what = hp->name;
21084887Schin 	}
21094887Schin 	else
21104887Schin 	{
21114887Schin 		if ((style = opt_info.state->force) < STYLE_man)
21124887Schin 			style = STYLE_man;
21134887Schin 		if (!(sp_help = sfstropen()))
21144887Schin 			goto nospace;
21154887Schin 		for (i = 0; i < elementsof(help_head); i++)
21164887Schin 			list(sp_help, &help_head[i]);
21174887Schin 		for (i = 0; i < elementsof(styles); i++)
21184887Schin 			sfprintf(sp_help, "[:%s?%s]", styles[i].match, styles[i].text);
21194887Schin 		for (i = 0; i < elementsof(help_tail); i++)
21204887Schin 			list(sp_help, &help_tail[i]);
21214887Schin 		if (!(opts = sfstruse(sp_help)))
21224887Schin 			goto nospace;
21234887Schin 	}
21244887Schin 	message((-20, "AHA#%d style=%d", __LINE__, style));
21254887Schin  again:
21264887Schin 	if (opts)
21274887Schin 	{
21284887Schin 		for (i = 0; i < opt_info.state->npass; i++)
21294887Schin 			if (opt_info.state->pass[i].oopts == opts)
21304887Schin 			{
21314887Schin 				o = &opt_info.state->pass[i];
21324887Schin 				break;
21334887Schin 			}
21344887Schin 		if (i >= opt_info.state->npass)
21354887Schin 		{
21364887Schin 			o = &one;
21374887Schin 			if (init((char*)opts, o))
21384887Schin 				goto nospace;
21394887Schin 		}
21404887Schin 		e = o + 1;
21414887Schin 	}
21424887Schin 	else if (opt_info.state->npass > 0)
21434887Schin 	{
21444887Schin 		o = opt_info.state->pass;
21454887Schin 		e = o + opt_info.state->npass;
21464887Schin 	}
21474887Schin 	else if (opt_info.state->npass < 0)
21484887Schin 	{
21494887Schin 		o = &opt_info.state->cache->pass;
21504887Schin 		e = o + 1;
21514887Schin 	}
21524887Schin 	else
21534887Schin 		return T(NiL, ID, "[* call optget() before opthelp() *]");
2154*10898Sroland.mainz@nrubsig.org 	if (style <= STYLE_usage)
21554887Schin 	{
21564887Schin 		if (!(sp_text = sfstropen()) || !(sp_info = sfstropen()))
21574887Schin 			goto nospace;
21584887Schin 		if (style >= STYLE_match && style < STYLE_keys && !(sp_body = sfstropen()))
21594887Schin 			goto nospace;
21604887Schin 	}
21614887Schin 	switch (style)
21624887Schin 	{
21634887Schin 	case STYLE_api:
21644887Schin 	case STYLE_html:
21654887Schin 	case STYLE_nroff:
21664887Schin 		opt_info.state->emphasis = 0;
21674887Schin 		break;
21684887Schin 	case STYLE_usage:
21694887Schin 	case STYLE_keys:
21704887Schin 		for (q = o; q < e; q++)
21714887Schin 			if (!(q->flags & OPT_ignore) && !streq(q->catalog, o->catalog))
21724887Schin 				o = q;
21734887Schin 		/*FALLTHROUGH*/
21744887Schin 	case STYLE_posix:
21754887Schin 		sfputc(mp, '\f');
21764887Schin 		break;
21774887Schin 	default:
21784887Schin 		if (!opt_info.state->emphasis)
21794887Schin 		{
21804887Schin 			if (x = getenv("ERROR_OPTIONS"))
21814887Schin 			{
21824887Schin 				if (strmatch(x, "*noemphasi*"))
21834887Schin 					break;
21844887Schin 				if (strmatch(x, "*emphasi*"))
21854887Schin 				{
21864887Schin 					opt_info.state->emphasis = 1;
21874887Schin 					break;
21884887Schin 				}
21894887Schin 			}
21904887Schin 			if ((x = getenv("TERM")) && strmatch(x, "(ansi|vt100|xterm)*") && isatty(sffileno(sfstderr)))
21914887Schin 				opt_info.state->emphasis = 1;
21924887Schin 		}
21934887Schin 		break;
21944887Schin 	}
21954887Schin 	x = "";
21964887Schin 	xl = 0;
21974887Schin 	for (q = o; q < e; q++)
21984887Schin 	{
21994887Schin 		if (q->flags & OPT_ignore)
22004887Schin 			continue;
22014887Schin 		if (section < q->section)
22024887Schin 			section = q->section;
22034887Schin 		section = q->section;
22044887Schin 		flags |= q->flags;
22054887Schin 		p = q->opts;
22064887Schin 		prefix = q->prefix;
22074887Schin 		version = q->version;
22084887Schin 		catalog = q->catalog;
22094887Schin 		switch (style)
22104887Schin 		{
22114887Schin 		case STYLE_usage:
22124887Schin 			if (xl)
22134887Schin 				sfputc(mp, '\n');
22144887Schin 			else
22154887Schin 				xl = 1;
2216*10898Sroland.mainz@nrubsig.org 			psp = 0;
2217*10898Sroland.mainz@nrubsig.org 			for (;;)
22184887Schin 			{
2219*10898Sroland.mainz@nrubsig.org 				switch (c = *p++)
22204887Schin 				{
2221*10898Sroland.mainz@nrubsig.org 				case 0:
2222*10898Sroland.mainz@nrubsig.org 					if (!(tsp = psp))
2223*10898Sroland.mainz@nrubsig.org 						goto style_usage;
2224*10898Sroland.mainz@nrubsig.org 					p = psp->ob;
2225*10898Sroland.mainz@nrubsig.org 					psp = psp->next;
2226*10898Sroland.mainz@nrubsig.org 					free(tsp);
2227*10898Sroland.mainz@nrubsig.org 					continue;
22284887Schin 				case '\a':
22294887Schin 					c = 'a';
22304887Schin 					break;
22314887Schin 				case '\b':
22324887Schin 					c = 'b';
22334887Schin 					break;
22344887Schin 				case '\f':
2235*10898Sroland.mainz@nrubsig.org 					psp = info(psp, p, NiL, sp_info);
2236*10898Sroland.mainz@nrubsig.org 					if (psp->nb)
2237*10898Sroland.mainz@nrubsig.org 						p = psp->nb;
2238*10898Sroland.mainz@nrubsig.org 					else
2239*10898Sroland.mainz@nrubsig.org 					{
2240*10898Sroland.mainz@nrubsig.org 						p = psp->ob;
2241*10898Sroland.mainz@nrubsig.org 						psp = psp->next;
2242*10898Sroland.mainz@nrubsig.org 					}
2243*10898Sroland.mainz@nrubsig.org 					continue;
22444887Schin 				case '\n':
22454887Schin 					c = 'n';
22464887Schin 					break;
22474887Schin 				case '\r':
22484887Schin 					c = 'r';
22494887Schin 					break;
22504887Schin 				case '\t':
22514887Schin 					c = 't';
22524887Schin 					break;
22534887Schin 				case '\v':
22544887Schin 					c = 'v';
22554887Schin 					break;
22564887Schin 				case '"':
22574887Schin 					c = '"';
22584887Schin 					break;
22594887Schin 				case '\'':
22604887Schin 					c = '\'';
22614887Schin 					break;
22624887Schin 				case '\\':
22634887Schin 					c = '\\';
22644887Schin 					break;
22654887Schin 				default:
22664887Schin 					sfputc(mp, c);
22674887Schin 					continue;
22684887Schin 				}
22694887Schin 				sfputc(mp, '\\');
22704887Schin 				sfputc(mp, c);
22714887Schin 			}
2272*10898Sroland.mainz@nrubsig.org 		style_usage:
22734887Schin 			continue;
22744887Schin 		case STYLE_keys:
22754887Schin 			a = 0;
22764887Schin 			psp = 0;
22774887Schin 			vl = 0;
22784887Schin 			for (;;)
22794887Schin 			{
22804887Schin 				if (!(c = *p++))
22814887Schin 				{
22824887Schin 					if (!(tsp = psp))
22834887Schin 						break;
22844887Schin 					p = psp->ob;
22854887Schin 					psp = psp->next;
22864887Schin 					free(tsp);
22874887Schin 					continue;
22884887Schin 				}
22894887Schin 				if (c == '\f')
22904887Schin 				{
22914887Schin 					psp = info(psp, p, NiL, sp_info);
22924887Schin 					if (psp->nb)
22934887Schin 						p = psp->nb;
22944887Schin 					else
22954887Schin 					{
22964887Schin 						p = psp->ob;
22974887Schin 						psp = psp->next;
22984887Schin 					}
22994887Schin 					continue;
23004887Schin 				}
23014887Schin 				f = z = 1;
23024887Schin 				t = 0;
23034887Schin 				if (a == 0 && (c == ' ' || c == '\n' && *p == '\n'))
23044887Schin 				{
23054887Schin 					if (c == ' ' && *p == ']')
23064887Schin 					{
23074887Schin 						p++;
23084887Schin 						continue;
23094887Schin 					}
23104887Schin 					if (*p == '\n')
23114887Schin 						p++;
23124887Schin 					a = c;
23134887Schin 				}
23144887Schin 				else if (c == '\n')
23154887Schin 				{
23164887Schin 					if (a == ' ')
23174887Schin 						a = -1;
23184887Schin 					else if (a == '\n' || *p == '\n')
23194887Schin 					{
23204887Schin 						a = -1;
23214887Schin 						p++;
23224887Schin 					}
23234887Schin 					continue;
23244887Schin 				}
23254887Schin 				else if ((c == ':' || c == '#') && (*p == '[' || *p == '?' && *(p + 1) == '[' && p++))
23264887Schin 					p++;
23274887Schin 				else if (c != '[')
23284887Schin 				{
23298462SApril.Chin@Sun.COM 					if (c == GO)
23304887Schin 						vl++;
23318462SApril.Chin@Sun.COM 					else if (c == OG)
23324887Schin 						vl--;
23334887Schin 					continue;
23344887Schin 				}
23354887Schin 				else if (*p == ' ')
23364887Schin 				{
23374887Schin 					p++;
23384887Schin 					continue;
23394887Schin 				}
23404887Schin 				else if (*p == '-')
23414887Schin 				{
23424887Schin 					z = 0;
23434887Schin 					if (*++p == '-')
23444887Schin 					{
23454887Schin 						p = skip(p, 0, 0, 0, 1, 0, 1, version);
23464887Schin 						continue;
23474887Schin 					}
23484887Schin 				}
23494887Schin 				else if (*p == '+')
23504887Schin 				{
23514887Schin 					p++;
23524887Schin 					if (vl > 0 && *p != '\a')
23534887Schin 					{
23544887Schin 						f = 0;
23554887Schin 						p = skip(p, '?', 0, 0, 1, 0, 0, version);
23564887Schin 						if (*p == '?')
23574887Schin 							p++;
23584887Schin 					}
23594887Schin 				}
23604887Schin 				else
23614887Schin 				{
23624887Schin 					if (*(p + 1) == '\f' && (vp = opt_info.state->vp))
23634887Schin 						p = expand(p + 2, NiL, &t, vp);
23644887Schin 					p = skip(p, ':', '?', 0, 1, 0, 0, version);
23654887Schin 					if (*p == ':')
23664887Schin 						p++;
23674887Schin 				}
23684887Schin 				if (f && *p == '?' && *(p + 1) != '?')
23694887Schin 				{
23704887Schin 					f = 0;
23714887Schin 					if (z)
23724887Schin 						p++;
23734887Schin 					else
23744887Schin 						p = skip(p, 0, 0, 0, 1, 0, 0, version);
23754887Schin 				}
23764887Schin 				if (*p == ']' && *(p + 1) != ']')
23774887Schin 				{
23784887Schin 					p++;
23794887Schin 					continue;
23804887Schin 				}
23814887Schin 				if (!*p)
23824887Schin 				{
23834887Schin 					if (!t)
23844887Schin 						break;
23854887Schin 					p = t;
23864887Schin 					t = 0;
23874887Schin 				}
23884887Schin 				m = sfstrtell(mp);
23894887Schin 				sfputc(mp, '"');
23904887Schin 				xl = 1;
23914887Schin 				/*UNDENT...*/
23924887Schin 
23934887Schin 	for (;;)
23944887Schin 	{
23954887Schin 		if (!(c = *p++))
23964887Schin 		{
23974887Schin 			if (t)
23984887Schin 			{
23994887Schin 				p = t;
24004887Schin 				t = 0;
24014887Schin 			}
24024887Schin 			if (!(tsp = psp))
24034887Schin 			{
24044887Schin 				p--;
24054887Schin 				break;
24064887Schin 			}
24074887Schin 			p = psp->ob;
24084887Schin 			psp = psp->next;
24094887Schin 			free(tsp);
24104887Schin 			continue;
24114887Schin 		}
24124887Schin 		if (a > 0)
24134887Schin 		{
24144887Schin 			if (c == '\n')
24154887Schin 			{
24164887Schin 				if (a == ' ')
24174887Schin 				{
24184887Schin 					a = -1;
24194887Schin 					break;
24204887Schin 				}
24214887Schin 				if (a == '\n' || *p == '\n')
24224887Schin 				{
24234887Schin 					a = -1;
24244887Schin 					p++;
24254887Schin 					break;
24264887Schin 				}
24274887Schin 			}
24284887Schin 		}
24294887Schin 		else if (c == ']')
24304887Schin 		{
24314887Schin 			if (*p != ']')
24324887Schin 			{
24334887Schin 				sfputc(mp, 0);
24344887Schin 				y = sfstrbase(mp) + m + 1;
24354887Schin 				if (D(y) || !strmatch(y, KEEP) || strmatch(y, OMIT))
24364887Schin 				{
24374887Schin 					sfstrseek(mp, m, SEEK_SET);
24384887Schin 					xl = 0;
24394887Schin 				}
24404887Schin 				else
24414887Schin 					sfstrseek(mp, -1, SEEK_CUR);
24424887Schin 				break;
24434887Schin 			}
24444887Schin 			sfputc(mp, *p++);
24454887Schin 			continue;
24464887Schin 		}
24474887Schin 		switch (c)
24484887Schin 		{
24494887Schin 		case '?':
24504887Schin 			if (f)
24514887Schin 			{
24524887Schin 				if (*p == '?')
24534887Schin 				{
24544887Schin 					p++;
24554887Schin 					sfputc(mp, c);
24564887Schin 				}
24574887Schin 				else
24584887Schin 				{
24594887Schin 					f = 0;
24604887Schin 					sfputc(mp, 0);
24614887Schin 					y = sfstrbase(mp) + m + 1;
24624887Schin 					if (D(y) || !strmatch(y, KEEP) || strmatch(y, OMIT))
24634887Schin 					{
24644887Schin 						sfstrseek(mp, m, SEEK_SET);
24654887Schin 						xl = 0;
24664887Schin 					}
24674887Schin 					else
24684887Schin 						sfstrseek(mp, -1, SEEK_CUR);
24694887Schin 					if (z && (*p != ']' || *(p + 1) == ']'))
24704887Schin 					{
24714887Schin 						if (xl)
24724887Schin 						{
24734887Schin 							sfputc(mp, '"');
24744887Schin 							sfputc(mp, '\n');
24754887Schin 						}
24764887Schin 						m = sfstrtell(mp);
24774887Schin 						sfputc(mp, '"');
24784887Schin 						xl = 1;
24794887Schin 					}
24804887Schin 					else
24814887Schin 					{
24824887Schin 						p = skip(p, 0, 0, 0, 1, 0, 0, version);
24834887Schin 						if (*p == '?')
24844887Schin 							p++;
24854887Schin 					}
24864887Schin 				}
24874887Schin 			}
24884887Schin 			else
24894887Schin 				sfputc(mp, c);
24904887Schin 			continue;
24914887Schin 		case ':':
24924887Schin 			if (f && *p == ':')
24934887Schin 				p++;
24944887Schin 			sfputc(mp, c);
24954887Schin 			continue;
24964887Schin 		case '\a':
24974887Schin 			c = 'a';
24984887Schin 			break;
24994887Schin 		case '\b':
25004887Schin 			c = 'b';
25014887Schin 			break;
25024887Schin 		case '\f':
25034887Schin 			c = 'f';
25044887Schin 			break;
25054887Schin 		case '\n':
25064887Schin 			c = 'n';
25074887Schin 			break;
25084887Schin 		case '\r':
25094887Schin 			c = 'r';
25104887Schin 			break;
25114887Schin 		case '\t':
25124887Schin 			c = 't';
25134887Schin 			break;
25144887Schin 		case '\v':
25154887Schin 			c = 'v';
25164887Schin 			break;
25174887Schin 		case '"':
25184887Schin 			c = '"';
25194887Schin 			break;
25204887Schin 		case '\\':
25214887Schin 			c = '\\';
25224887Schin 			break;
25234887Schin 		case CC_esc:
25244887Schin 			c = 'E';
25254887Schin 			break;
25264887Schin 		default:
25274887Schin 			sfputc(mp, c);
25284887Schin 			continue;
25294887Schin 		}
25304887Schin 		sfputc(mp, '\\');
25314887Schin 		sfputc(mp, c);
25324887Schin 	}
25334887Schin 
25344887Schin 				/*...INDENT*/
25354887Schin 				if (xl)
25364887Schin 				{
25374887Schin 					sfputc(mp, '"');
25384887Schin 					sfputc(mp, '\n');
25394887Schin 				}
25404887Schin 			}
25414887Schin 			continue;
25424887Schin 		}
25434887Schin 		z = 0;
25444887Schin 		head = 0;
25454887Schin 		mode = 0;
25464887Schin 		mutex = 0;
25474887Schin 		if (style > STYLE_short && style < STYLE_nroff && version < 1)
25484887Schin 		{
25494887Schin 			style = STYLE_short;
25504887Schin 			if (sp_body)
25514887Schin 			{
25524887Schin 				sfclose(sp_body);
25534887Schin 				sp_body = 0;
25544887Schin 			}
25554887Schin 		}
25564887Schin 		else if (style == STYLE_short && prefix < 2)
25574887Schin 			style = STYLE_long;
25584887Schin 		if (*p == ':')
25594887Schin 			p++;
25604887Schin 		if (*p == '+')
25614887Schin 		{
25624887Schin 			p++;
25634887Schin 			if (!(sp = sp_plus) && !(sp = sp_plus = sfstropen()))
25644887Schin 				goto nospace;
25654887Schin 		}
25664887Schin 		else if (style >= STYLE_match)
25674887Schin 			sp = sp_body;
25684887Schin 		else
25694887Schin 			sp = sp_text;
25704887Schin 		psp = 0;
25714887Schin 		for (;;)
25724887Schin 		{
25734887Schin 			if (!(*(p = next(p, version))))
25744887Schin 			{
25754887Schin 				if (!(tsp = psp))
25764887Schin 					break;
25774887Schin 				p = psp->ob;
25784887Schin 				psp = psp->next;
25794887Schin 				free(tsp);
25804887Schin 				continue;
25814887Schin 			}
25824887Schin 			if (*p == '\f')
25834887Schin 			{
25844887Schin 				psp = info(psp, p + 1, NiL, sp_info);
25854887Schin 				if (psp->nb)
25864887Schin 					p = psp->nb;
25874887Schin 				else
25884887Schin 				{
25894887Schin 					p = psp->ob;
25904887Schin 					psp = psp->next;
25914887Schin 				}
25924887Schin 				continue;
25934887Schin 			}
25944887Schin 			if (*p == '\n' || *p == ' ')
25954887Schin 			{
25964887Schin 				if (*(x = p = next(p + 1, version)))
25974887Schin 					while (*++p)
25984887Schin 						if (*p == '\n')
25994887Schin 						{
26004887Schin 							while (*++p == ' ' || *p == '\t' || *p == '\r');
26014887Schin 							if (*p == '\n')
26024887Schin 								break;
26034887Schin 						}
26044887Schin 				xl = p - x;
26054887Schin 				if (!*p)
26064887Schin 					break;
26074887Schin 				continue;
26084887Schin 			}
26098462SApril.Chin@Sun.COM 			if (*p == OG)
26104887Schin 			{
26114887Schin 				p++;
26124887Schin 				continue;
26134887Schin 			}
26144887Schin 			message((-20, "opthelp: opt %s", show(p)));
26154887Schin 			if (z < 0)
26164887Schin 				z = 0;
26174887Schin 			a = 0;
26184887Schin 			f = 0;
26194887Schin 			w = 0;
26204887Schin 			d = 0;
26214887Schin 			s = 0;
26228462SApril.Chin@Sun.COM 			rb = re = 0;
26234887Schin 			sl = 0;
26248462SApril.Chin@Sun.COM 			vl = 0;
26254887Schin 			if (*p == '[')
26264887Schin 			{
26274887Schin 				if ((c = *(p = next(p + 1, version))) == '-')
26284887Schin 				{
26294887Schin 					if (style >= STYLE_man)
26304887Schin 					{
26314887Schin 						if (*(p + 1) != '-')
26324887Schin 						{
26334887Schin 							if (!sp_misc && !(sp_misc = sfstropen()))
26344887Schin 								goto nospace;
26354887Schin 							else
26364887Schin 								p = textout(sp_misc, p, style, 1, 3, sp_info, version, catalog);
26374887Schin 							continue;
26384887Schin 						}
26394887Schin 					}
26404887Schin 					else if (style == STYLE_match && *what == '-')
26414887Schin 					{
26428462SApril.Chin@Sun.COM 						if (*(p + 1) == '?' || isdigit(*(p + 1)))
26434887Schin 							s = C("version");
26444887Schin 						else
26454887Schin 							s = p + 1;
26464887Schin 						w = (char*)what;
26474887Schin 						if (*s != '-' || *(w + 1) == '-')
26484887Schin 						{
26494887Schin 							if (*s == '-')
26504887Schin 								s++;
26514887Schin 							if (*(w + 1) == '-')
26524887Schin 								w++;
26534887Schin 							if (match(w + 1, s, version, catalog))
26544887Schin 							{
26554887Schin 								if (*(p + 1) == '-')
26564887Schin 									p++;
26574887Schin 								p = textout(sp, p, style, 1, 3, sp_info, version, catalog);
26584887Schin 								matched = -1;
26594887Schin 								continue;
26604887Schin 							}
26614887Schin 						}
26624887Schin 					}
26634887Schin 					if (!z)
26644887Schin 						z = -1;
26654887Schin 				}
26664887Schin 				else if (c == '+')
26674887Schin 				{
26684887Schin 					if (style >= STYLE_man)
26694887Schin 					{
26704887Schin 						p = textout(sp_body, p, style, 0, 0, sp_info, version, catalog);
26714887Schin 						if (!sp_head)
26724887Schin 						{
26734887Schin 							sp_head = sp_body;
26744887Schin 							if (!(sp_body = sfstropen()))
26754887Schin 								goto nospace;
26764887Schin 						}
26774887Schin 						continue;
26784887Schin 					}
26794887Schin 					else if (style == STYLE_match && *what == '+')
26804887Schin 					{
26814887Schin 						if (paragraph)
26824887Schin 						{
26834887Schin 							if (p[1] == '?')
26844887Schin 							{
26854887Schin 								p = textout(sp, p, style, 1, 3, sp_info, version, catalog);
26864887Schin 								continue;
26874887Schin 							}
26884887Schin 							paragraph = 0;
26894887Schin 						}
26904887Schin 						if (match((char*)what + 1, p + 1, version, catalog))
26914887Schin 						{
26924887Schin 							p = textout(sp, p, style, 1, 3, sp_info, version, catalog);
26934887Schin 							matched = -1;
26944887Schin 							paragraph = 1;
26954887Schin 							continue;
26964887Schin 						}
26974887Schin 					}
26984887Schin 					if (!z)
26994887Schin 						z = -1;
27004887Schin 				}
27014887Schin 				else if (c == '[' || version < 1)
27024887Schin 				{
27034887Schin 					mutex++;
27044887Schin 					continue;
27054887Schin 				}
27064887Schin 				else
27074887Schin 				{
27084887Schin 					if (c == '!')
27094887Schin 					{
27104887Schin 						a |= OPT_invert;
27114887Schin 						p++;
27124887Schin 					}
27134887Schin 					rb = p;
27144887Schin 					if (*p != ':')
27154887Schin 					{
27164887Schin 						s = p;
27174887Schin 						if (*(p + 1) == '|')
27184887Schin 						{
27194887Schin 							while (*++p && *p != '=' && *p != '!' && *p != ':' && *p != '?');
27204887Schin 							if ((p - s) > 1)
27214887Schin 								sl = p - s;
27224887Schin 							if (*p == '!')
27234887Schin 								a |= OPT_invert;
27244887Schin 						}
27254887Schin 						if (*(p + 1) == '\f')
27264887Schin 							p++;
27274887Schin 						else
27284887Schin 							p = skip(p, ':', '?', 0, 1, 0, 0, version);
27294887Schin 						if (sl || (p - s) == 1 || *(s + 1) == '=' || *(s + 1) == '!' && (a |= OPT_invert) || *(s + 1) == '|')
27304887Schin 							f = *s;
27314887Schin 					}
27324887Schin 					re = p;
27334887Schin 					if (style <= STYLE_short)
27344887Schin 					{
27354887Schin 						if (!z && !f)
27364887Schin 							z = -1;
27374887Schin 					}
27384887Schin 					else
27394887Schin 					{
27404887Schin 						if (*p == '\f' && (vp = opt_info.state->vp))
27414887Schin 							p = expand(p + 1, NiL, &t, vp);
27424887Schin 						else
27434887Schin 							t = 0;
27444887Schin 						if (*p == ':')
27454887Schin 						{
27464887Schin 							p = skip(w = p + 1, ':', '?', 0, 1, 0, 0, version);
27474887Schin 							if (!(wl = p - w))
27484887Schin 								w = 0;
27494887Schin 						}
27504887Schin 						else
27514887Schin 							wl = 0;
27524887Schin 						if (*p == ':' || *p == '?')
27534887Schin 						{
27544887Schin 							d = p;
27554887Schin 							p = skip(p, 0, 0, 0, 1, 0, 0, version);
27564887Schin 						}
27574887Schin 						else
27584887Schin 							d = 0;
27594887Schin 						if (style == STYLE_match)
27604887Schin 						{
27614887Schin 							if (wl && !match((char*)what, w, version, catalog))
27624887Schin 								wl = 0;
27634887Schin 							if ((!wl || *w == ':' || *w == '?') && (what[1] || sl && !memchr(s, what[0], sl) || !sl && what[0] != f))
27644887Schin 							{
27654887Schin 								w = 0;
27664887Schin 								if (!z)
27674887Schin 									z = -1;
27684887Schin 							}
27694887Schin 							else
27704887Schin 								matched = 1;
27714887Schin 						}
27724887Schin 						if (t)
27734887Schin 						{
27744887Schin 							p = t;
27754887Schin 							if (*p == ':' || *p == '?')
27764887Schin 							{
27774887Schin 								d = p;
27784887Schin 								p = skip(p, 0, 0, 0, 1, 0, 0, version);
27794887Schin 							}
27804887Schin 						}
27814887Schin 					}
27824887Schin 				}
27834887Schin 				p = skip(p, 0, 0, 0, 1, 0, 1, version);
27844887Schin 				if (*p == GO)
27854887Schin 					p = skip(p + 1, 0, 0, 0, 0, 1, 1, version);
27864887Schin 			}
27874887Schin 			else if (*p == ']')
27884887Schin 			{
27894887Schin 				if (mutex)
27904887Schin 				{
27914887Schin 					if (style >= STYLE_nroff)
27924887Schin 						sfputr(sp_body, "\n.OP - - anyof", '\n');
27934887Schin 					if (!(mutex & 1))
27944887Schin 					{
27954887Schin 						mutex--;
27964887Schin 						if (style <= STYLE_long)
27974887Schin 						{
27984887Schin 							sfputc(sp_body, ' ');
27994887Schin 							sfputc(sp_body, ']');
28004887Schin 						}
28014887Schin 					}
28024887Schin 					mutex--;
28034887Schin 				}
28044887Schin 				p++;
28054887Schin 				continue;
28064887Schin 			}
28074887Schin 			else if (*p == '?')
28084887Schin 			{
28094887Schin 				if (style < STYLE_match)
28104887Schin 					z = 1;
28114887Schin 				mode |= OPT_hidden;
28124887Schin 				p++;
28134887Schin 				continue;
28144887Schin 			}
28154887Schin 			else if (*p == '\\' && style==STYLE_posix)
28164887Schin 			{
28174887Schin 				if (*++p)
28184887Schin 					p++;
28194887Schin 				continue;
28204887Schin 			}
28214887Schin 			else
28224887Schin 			{
28234887Schin 				f = *p++;
28244887Schin 				s = 0;
28254887Schin 				if (style == STYLE_match && !z)
28264887Schin 					z = -1;
28274887Schin 			}
28284887Schin 			if (!z)
28294887Schin 			{
28304887Schin 				if (style == STYLE_long || prefix < 2 || (q->flags & OPT_long))
28314887Schin 					f = 0;
28324887Schin 				else if (style <= STYLE_short)
28334887Schin 					w = 0;
28344887Schin 				if (!f && !w)
28354887Schin 					z = -1;
28364887Schin 			}
28378462SApril.Chin@Sun.COM 			ov = 0;
28388462SApril.Chin@Sun.COM 			u = v = y = 0;
28394887Schin 			if (*p == ':' && (a |= OPT_string) || *p == '#' && (a |= OPT_number))
28404887Schin 			{
28414887Schin 				message((-21, "opthelp: arg %s", show(p)));
28424887Schin 				if (*++p == '?' || *p == *(p - 1))
28434887Schin 				{
28444887Schin 					p++;
28454887Schin 					a |= OPT_optional;
28464887Schin 				}
28474887Schin 				if (*(p = next(p, version)) == '[')
28484887Schin 				{
28494887Schin 					if (!z)
28504887Schin 					{
28514887Schin 						p = skip(y = p + 1, ':', '?', 0, 1, 0, 0, version);
28524887Schin 						while (*p == ':')
28534887Schin 						{
28544887Schin 							p = skip(t = p + 1, ':', '?', 0, 1, 0, 0, version);
28554887Schin 							m = p - t;
28564887Schin 							if (*t == '!')
28574887Schin 							{
28584887Schin 								ov = t + 1;
28594887Schin 								ol = m - 1;
28604887Schin 							}
28614887Schin 							else if (*t == '=')
28624887Schin 							{
28634887Schin 								v = t + 1;
28644887Schin 								vl = m - 1;
28654887Schin 							}
28664887Schin 							else
28674887Schin 								for (j = 0; j < elementsof(attrs); j++)
28684887Schin 									if (strneq(t, attrs[j].name, m))
28694887Schin 									{
28704887Schin 										a |= attrs[j].flag;
28714887Schin 										break;
28724887Schin 									}
28734887Schin 						}
28744887Schin 						if (*p == '?')
28754887Schin 							u = p;
28764887Schin 						p = skip(p, 0, 0, 0, 1, 0, 1, version);
28774887Schin 					}
28784887Schin 					else
28794887Schin 						p = skip(p + 1, 0, 0, 0, 1, 0, 1, version);
28804887Schin 				}
28814887Schin 				else
28824887Schin 					y = (a & OPT_number) ? T(NiL, ID, "#") : T(NiL, ID, "arg");
28834887Schin 			}
28844887Schin 			else
28854887Schin 				a |= OPT_flag;
28864887Schin 			if (!z)
28874887Schin 			{
28884887Schin 				if (style <= STYLE_short && !y && !mutex || style == STYLE_posix)
28894887Schin 				{
28904887Schin 					if (style != STYLE_posix && !sfstrtell(sp))
28914887Schin 					{
28924887Schin 						sfputc(sp, '[');
28934887Schin 						if (sp == sp_plus)
28944887Schin 							sfputc(sp, '+');
28954887Schin 						sfputc(sp, '-');
28964887Schin 					}
28974887Schin 					if (!sl)
28984887Schin 						sfputc(sp, f);
28994887Schin 					else
29004887Schin 						for (c = 0; c < sl; c++)
29014887Schin 							if (s[c] != '|')
29024887Schin 								sfputc(sp, s[c]);
29034887Schin 					if (style == STYLE_posix && y)
29044887Schin 						sfputc(sp, ':');
29054887Schin 				}
29064887Schin 				else
29074887Schin 				{
29084887Schin 					if (style >= STYLE_match)
29094887Schin 					{
29104887Schin 						sfputc(sp_body, '\n');
29114887Schin 						if (!head)
29124887Schin 						{
29134887Schin 							head = 1;
29148462SApril.Chin@Sun.COM 							item(sp_body, (flags & OPT_functions) ? C("FUNCTIONS") : C("OPTIONS"), 0, 0, style, sp_info, version, ID);
29154887Schin 						}
29164887Schin 						if (style >= STYLE_nroff)
29174887Schin 						{
29184887Schin 							if (mutex & 1)
29194887Schin 							{
29204887Schin 								mutex++;
29214887Schin 								sfputr(sp_body, "\n.OP - - oneof", '\n');
29224887Schin 							}
29234887Schin 						}
29244887Schin 						else
29254887Schin 							sfputc(sp_body, '\t');
29264887Schin 					}
29274887Schin 					else
29284887Schin 					{
29294887Schin 						if (sp_body)
29304887Schin 							sfputc(sp_body, ' ');
29314887Schin 						else if (!(sp_body = sfstropen()))
29324887Schin 							goto nospace;
29334887Schin 						if (mutex)
29344887Schin 						{
29354887Schin 							if (mutex & 1)
29364887Schin 							{
29374887Schin 								mutex++;
29384887Schin 								sfputc(sp_body, '[');
29394887Schin 							}
29404887Schin 							else
29414887Schin 								sfputc(sp_body, '|');
29424887Schin 							sfputc(sp_body, ' ');
29434887Schin 						}
29444887Schin 						else
29454887Schin 							sfputc(sp_body, '[');
29464887Schin 					}
29474887Schin 					if (style >= STYLE_nroff)
29484887Schin 					{
29494887Schin 						if (flags & OPT_functions)
29504887Schin 						{
29514887Schin 							sfputr(sp_body, ".FN", ' ');
29524887Schin 							if (re > rb)
29534887Schin 								sfwrite(sp_body, rb, re - rb);
29544887Schin 							else
29554887Schin 								sfputr(sp, "void", -1);
29564887Schin 							if (w)
29578462SApril.Chin@Sun.COM 								label(sp_body, ' ', w, 0, -1, 0, style, FONT_BOLD, sp_info, version, catalog);
29584887Schin 						}
29594887Schin 						else
29604887Schin 						{
29614887Schin 							sfputr(sp_body, ".OP", ' ');
29624887Schin 							if (sl)
29634887Schin 								sfwrite(sp_body, s, sl);
29644887Schin 							else
29654887Schin 								sfputc(sp_body, f ? f : '-');
29664887Schin 							sfputc(sp_body, ' ');
29674887Schin 							if (w)
29684887Schin 							{
29698462SApril.Chin@Sun.COM 								if (label(sp_body, 0, w, 0, -1, 0, style, 0, sp_info, version, catalog))
29704887Schin 								{
29714887Schin 									sfputc(sp_body, '|');
29728462SApril.Chin@Sun.COM 									label(sp_body, 0, w, 0, -1, 0, style, 0, sp_info, version, native);
29734887Schin 								}
29744887Schin 							}
29754887Schin 							else
29764887Schin 								sfputc(sp_body, '-');
29774887Schin 							sfputc(sp_body, ' ');
29784887Schin 							m = a & OPT_TYPE;
29794887Schin 							for (j = 0; j < elementsof(attrs); j++)
29804887Schin 								if (m & attrs[j].flag)
29814887Schin 								{
29824887Schin 									sfputr(sp_body, attrs[j].name, -1);
29834887Schin 									break;
29844887Schin 								}
29854887Schin 							if (m = (a & ~m) | mode)
29864887Schin 								for (j = 0; j < elementsof(attrs); j++)
29874887Schin 									if (m & attrs[j].flag)
29884887Schin 									{
29894887Schin 										sfputc(sp_body, ':');
29904887Schin 										sfputr(sp_body, attrs[j].name, -1);
29914887Schin 									}
29924887Schin 							sfputc(sp_body, ' ');
29934887Schin 							if (y)
29948462SApril.Chin@Sun.COM 								label(sp_body, 0, y, 0, -1, 0, style, 0, sp_info, version, catalog);
29954887Schin 							else
29964887Schin 								sfputc(sp_body, '-');
29974887Schin 							if (v)
29984887Schin 								sfprintf(sp_body, " %-.*s", vl, v);
29994887Schin 						}
30004887Schin 					}
30014887Schin 					else
30024887Schin 					{
30034887Schin 						if (f)
30044887Schin 						{
30054887Schin 							if (sp_body == sp_plus)
30064887Schin 								sfputc(sp_body, '+');
30074887Schin 							sfputc(sp_body, '-');
30084887Schin 							sfputr(sp_body, font(FONT_BOLD, style, 1), -1);
30094887Schin 							if (!sl)
30104887Schin 							{
30114887Schin 								sfputc(sp_body, f);
30124887Schin 								if (f == '-' && y)
30134887Schin 								{
30144887Schin 									y = 0;
30154887Schin 									sfputr(sp_body, C("long-option[=value]"), -1);
30164887Schin 								}
30174887Schin 							}
30184887Schin 							else
30194887Schin 								sfwrite(sp_body, s, sl);
30204887Schin 							sfputr(sp_body, font(FONT_BOLD, style, 0), -1);
30214887Schin 							if (w)
30224887Schin 							{
30234887Schin 								sfputc(sp_body, ',');
30244887Schin 								sfputc(sp_body, ' ');
30254887Schin 							}
30264887Schin 						}
30274887Schin 						else if ((flags & OPT_functions) && re > rb)
30284887Schin 						{
30294887Schin 							sfwrite(sp_body, rb, re - rb);
30304887Schin 							sfputc(sp_body, ' ');
30314887Schin 						}
30324887Schin 						if (w)
30334887Schin 						{
30344887Schin 							if (prefix > 0)
30354887Schin 							{
30364887Schin 								sfputc(sp_body, '-');
30374887Schin 								if (prefix > 1)
30384887Schin 									sfputc(sp_body, '-');
30394887Schin 							}
30408462SApril.Chin@Sun.COM 							if (label(sp_body, 0, w, 0, -1, 0, style, FONT_BOLD, sp_info, version, catalog))
30414887Schin 							{
30424887Schin 								sfputc(sp_body, '|');
30438462SApril.Chin@Sun.COM 								label(sp_body, 0, w, 0, -1, 0, style, FONT_BOLD, sp_info, version, native);
30444887Schin 							}
30454887Schin 						}
30464887Schin 						if (y)
30474887Schin 						{
30484887Schin 							if (a & OPT_optional)
30494887Schin 								sfputc(sp_body, '[');
30504887Schin 							else if (!w)
30514887Schin 								sfputc(sp_body, ' ');
30524887Schin 							if (w)
30534887Schin 								sfputc(sp_body, prefix == 1 ? ' ' : '=');
30548462SApril.Chin@Sun.COM 							label(sp_body, 0, y, 0, -1, 0, style, FONT_ITALIC, sp_info, version, catalog);
30554887Schin 							if (a & OPT_optional)
30564887Schin 								sfputc(sp_body, ']');
30574887Schin 						}
30584887Schin 					}
30594887Schin 					if (style >= STYLE_match)
30604887Schin 					{
30614887Schin 						if (d)
30624887Schin 							textout(sp_body, d, style, 0, 3, sp_info, version, catalog);
30634887Schin 						if (u)
30644887Schin 							textout(sp_body, u, style, 0, 3, sp_info, version, catalog);
30654887Schin 						if ((a & OPT_invert) && w && (d || u))
30664887Schin 						{
30674887Schin 							u = skip(w, ':', '?', 0, 1, 0, 0, version);
30684887Schin 							if (f)
30694887Schin 								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);
30704887Schin 							else
30714887Schin 								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"));
30724887Schin 							if (!(t = sfstruse(sp_info)))
30734887Schin 								goto nospace;
30744887Schin 							textout(sp_body, t, style, 0, 0, sp_info, version, NiL);
30754887Schin 						}
30764887Schin 						if (*p == GO)
30774887Schin 						{
30784887Schin 							p = u ? skip(p + 1, 0, 0, 0, 0, 1, 1, version) : textout(sp_body, p, style, 4, 0, sp_info, version, catalog);
30794887Schin 							y = "+?";
30804887Schin 						}
30814887Schin 						else
30824887Schin 							y = " ";
30834887Schin 						if (a & OPT_optional)
30844887Schin 						{
30854887Schin 							if (ov)
30864887Schin 							{
30874887Schin 								sfprintf(sp_info, "%s%s \b", y, T(NiL, ID, "If the option value is omitted then"));
30884887Schin 								t = ov + ol;
30894887Schin 								while (ov < t)
30904887Schin 								{
30914887Schin 									if (((c = *ov++) == ':' || c == '?') && *ov == c)
30924887Schin 										ov++;
30934887Schin 									sfputc(sp_info, c);
30944887Schin 								}
30954887Schin 								sfprintf(sp_info, "\b %s.", T(NiL, ID, "is assumed"));
30964887Schin 							}
30974887Schin 							else
30984887Schin 								sfprintf(sp_info, "%s%s", y, T(NiL, ID, "The option value may be omitted."));
30994887Schin 							if (!(t = sfstruse(sp_info)))
31004887Schin 								goto nospace;
31014887Schin 							textout(sp_body, t, style, 4, 0, sp_info, version, NiL);
31024887Schin 							y = " ";
31034887Schin 						}
31044887Schin 						if (v)
31054887Schin 						{
31064887Schin 							sfprintf(sp_info, "%s%s \b", y, T(NiL, ID, "The default value is"));
31074887Schin 							t = v + vl;
31084887Schin 							while (v < t)
31094887Schin 							{
31104887Schin 								if (((c = *v++) == ':' || c == '?') && *v == c)
31114887Schin 									v++;
31124887Schin 								sfputc(sp_info, c);
31134887Schin 							}
31144887Schin 							sfputc(sp_info, '\b');
31154887Schin 							sfputc(sp_info, '.');
31164887Schin 							if (!(t = sfstruse(sp_info)))
31174887Schin 								goto nospace;
31184887Schin 							textout(sp_body, t, style, 4, 0, sp_info, version, NiL);
31194887Schin 						}
31204887Schin 					}
31214887Schin 					else if (!mutex)
31224887Schin 						sfputc(sp_body, ']');
31234887Schin 				}
31244887Schin 				if (*p == GO)
31254887Schin 				{
31264887Schin 					if (style >= STYLE_match)
31274887Schin 						p = textout(sp_body, p, style, 4, 0, sp_info, version, catalog);
31284887Schin 					else
31294887Schin 						p = skip(p + 1, 0, 0, 0, 0, 1, 1, version);
31304887Schin 				}
31314887Schin 			}
31324887Schin 			else if (*p == GO)
31334887Schin 				p = skip(p + 1, 0, 0, 0, 0, 1, 1, version);
31344887Schin 		}
31354887Schin 		psp = pop(psp);
31364887Schin 		if (sp_misc)
31374887Schin 		{
31384887Schin 			if (!(p = sfstruse(sp_misc)))
31394887Schin 				goto nospace;
31404887Schin 			for (t = p; *t == '\t' || *t == '\n'; t++);
31414887Schin 			if (*t)
31424887Schin 			{
31438462SApril.Chin@Sun.COM 				item(sp_body, C("IMPLEMENTATION"), 0, 0, style, sp_info, version, ID);
31444887Schin 				sfputr(sp_body, p, -1);
31454887Schin 			}
31464887Schin 		}
31474887Schin 	}
31484887Schin 	version = o->version;
31494887Schin 	catalog = o->catalog;
31504887Schin 	if (style >= STYLE_keys)
31514887Schin 	{
31524887Schin 		if (sp_info)
31534887Schin 			sfclose(sp_info);
31544887Schin 		if (style == STYLE_keys && sfstrtell(mp) > 1)
31554887Schin 			sfstrseek(mp, -1, SEEK_CUR);
31564887Schin 		if (!(p = sfstruse(mp)))
31574887Schin 			goto nospace;
31584887Schin 		return opt_info.msg = p;
31594887Schin 	}
31604887Schin 	sp = sp_text;
31614887Schin 	if (sfstrtell(sp) && style != STYLE_posix)
31624887Schin 		sfputc(sp, ']');
31634887Schin 	if (style == STYLE_nroff)
31644887Schin 	{
31654887Schin 		sfprintf(sp, "\
31664887Schin .\\\" format with nroff|troff|groff -man\n\
31674887Schin .fp 5 CW\n\
31688462SApril.Chin@Sun.COM .nr mH 5\n\
31698462SApril.Chin@Sun.COM .de H0\n\
31708462SApril.Chin@Sun.COM .nr mH 0\n\
31718462SApril.Chin@Sun.COM .in 5n\n\
31728462SApril.Chin@Sun.COM \\fB\\\\$1\\fP\n\
31738462SApril.Chin@Sun.COM .in 7n\n\
31744887Schin ..\n\
31754887Schin .de H1\n\
31768462SApril.Chin@Sun.COM .nr mH 1\n\
31778462SApril.Chin@Sun.COM .in 7n\n\
31784887Schin \\fB\\\\$1\\fP\n\
31798462SApril.Chin@Sun.COM .in 9n\n\
31804887Schin ..\n\
31814887Schin .de H2\n\
31828462SApril.Chin@Sun.COM .nr mH 2\n\
31838462SApril.Chin@Sun.COM .in 11n\n\
31844887Schin \\fB\\\\$1\\fP\n\
31858462SApril.Chin@Sun.COM .in 13n\n\
31864887Schin ..\n\
31874887Schin .de H3\n\
31888462SApril.Chin@Sun.COM .nr mH 3\n\
31898462SApril.Chin@Sun.COM .in 15n\n\
31904887Schin \\fB\\\\$1\\fP\n\
31918462SApril.Chin@Sun.COM .in 17n\n\
31924887Schin ..\n\
31934887Schin .de H4\n\
31948462SApril.Chin@Sun.COM .nr mH 4\n\
31958462SApril.Chin@Sun.COM .in 19n\n\
31964887Schin \\fB\\\\$1\\fP\n\
31978462SApril.Chin@Sun.COM .in 21n\n\
31984887Schin ..\n\
31994887Schin .de OP\n\
32008462SApril.Chin@Sun.COM .nr mH 0\n\
32014887Schin .ie !'\\\\$1'-' \\{\n\
32024887Schin .ds mO \\\\fB\\\\-\\\\$1\\\\fP\n\
32034887Schin .ds mS ,\\\\0\n\
32044887Schin .\\}\n\
32054887Schin .el \\{\n\
32064887Schin .ds mO \\\\&\n\
32074887Schin .ds mS \\\\&\n\
32084887Schin .\\}\n\
32094887Schin .ie '\\\\$2'-' \\{\n\
32104887Schin .if !'\\\\$4'-' .as mO \\\\0\\\\fI\\\\$4\\\\fP\n\
32114887Schin .\\}\n\
32124887Schin .el \\{\n\
32134887Schin .as mO \\\\*(mS\\\\fB%s\\\\$2\\\\fP\n\
32144887Schin .if !'\\\\$4'-' .as mO =\\\\fI\\\\$4\\\\fP\n\
32154887Schin .\\}\n\
32168462SApril.Chin@Sun.COM .in 5n\n\
32174887Schin \\\\*(mO\n\
32188462SApril.Chin@Sun.COM .in 9n\n\
32198462SApril.Chin@Sun.COM ..\n\
32208462SApril.Chin@Sun.COM .de SP\n\
32218462SApril.Chin@Sun.COM .if \\\\n(mH==2 .in 9n\n\
32228462SApril.Chin@Sun.COM .if \\\\n(mH==3 .in 13n\n\
32238462SApril.Chin@Sun.COM .if \\\\n(mH==4 .in 17n\n\
32244887Schin ..\n\
32254887Schin .de FN\n\
32268462SApril.Chin@Sun.COM .nr mH 0\n\
32278462SApril.Chin@Sun.COM .in 5n\n\
32284887Schin \\\\$1 \\\\$2\n\
32298462SApril.Chin@Sun.COM .in 9n\n\
32308462SApril.Chin@Sun.COM ..\n\
32318462SApril.Chin@Sun.COM .de DS\n\
32328462SApril.Chin@Sun.COM .in +3n\n\
32338462SApril.Chin@Sun.COM .ft 5\n\
32348462SApril.Chin@Sun.COM .nf\n\
32358462SApril.Chin@Sun.COM ..\n\
32368462SApril.Chin@Sun.COM .de DE\n\
32378462SApril.Chin@Sun.COM .fi\n\
32388462SApril.Chin@Sun.COM .ft R\n\
32398462SApril.Chin@Sun.COM .in -3n\n\
32404887Schin ..\n\
32414887Schin .TH %s %d\n\
32424887Schin "
32434887Schin , o->prefix == 2 ? "\\\\-\\\\-" : o->prefix == 1 ? "\\\\-" : ""
32444887Schin , error_info.id
32454887Schin , section
32464887Schin );
32474887Schin 	}
32484887Schin 	if (style == STYLE_match)
32494887Schin 	{
32504887Schin 		if (!matched)
32514887Schin 		{
32524887Schin 			if (hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), (char*)what))
32534887Schin 			{
32544887Schin 				if (!sp_help && !(sp_help = sfstropen()))
32554887Schin 					goto nospace;
32564887Schin 				sfprintf(sp_help, "[-][:%s?%s]", hp->match, hp->text);
32574887Schin 				if (!(opts = sfstruse(sp_help)))
32584887Schin 					goto nospace;
32594887Schin 				goto again;
32604887Schin 			}
32614887Schin 			s = (char*)unknown;
32624887Schin 			goto nope;
32634887Schin 		}
32644887Schin 		else if (matched < 0)
32654887Schin 			x = 0;
32664887Schin 	}
32674887Schin 	if (sp_plus)
32684887Schin 	{
32694887Schin 		if (sfstrtell(sp_plus))
32704887Schin 		{
32714887Schin 			if (sfstrtell(sp))
32724887Schin 				sfputc(sp, ' ');
32734887Schin 			if (!(t = sfstruse(sp_plus)))
32744887Schin 				goto nospace;
32754887Schin 			sfputr(sp, t, ']');
32764887Schin 		}
32774887Schin 		sfclose(sp_plus);
32784887Schin 	}
32794887Schin 	if (style >= STYLE_man)
32804887Schin 	{
32814887Schin 		if (sp_head)
32824887Schin 		{
32834887Schin 			if (!(t = sfstruse(sp_head)))
32844887Schin 				goto nospace;
32854887Schin 			for (; *t == '\n'; t++);
32864887Schin 			sfputr(sp, t, '\n');
32874887Schin 			sfclose(sp_head);
32884887Schin 			sp_head = 0;
32894887Schin 		}
32908462SApril.Chin@Sun.COM 		item(sp, C("SYNOPSIS"), 0, 0, style, sp_info, version, ID);
32914887Schin 	}
32924887Schin 	if (x)
32934887Schin 	{
32944887Schin 		for (t = x + xl; t > x && (*(t - 1) == '\n' || *(t - 1) == '\r'); t--);
32954887Schin 		xl = t - x;
32964887Schin 		if (style >= STYLE_match)
32974887Schin 		{
32984887Schin 			args(sp, x, xl, flags, style, sp_info, version, catalog);
32994887Schin 			x = 0;
33004887Schin 		}
33014887Schin 	}
33024887Schin 	if (sp_body)
33034887Schin 	{
33044887Schin 		if (sfstrtell(sp_body))
33054887Schin 		{
33064887Schin 			if (style < STYLE_match && sfstrtell(sp))
33074887Schin 				sfputc(sp, ' ');
33084887Schin 			if (!(t = sfstruse(sp_body)))
33094887Schin 				goto nospace;
33104887Schin 			sfputr(sp, t, -1);
33114887Schin 		}
33124887Schin 		sfclose(sp_body);
33134887Schin 		sp_body = 0;
33144887Schin 	}
33154887Schin 	if (x && style != STYLE_posix)
33164887Schin 		args(sp, x, xl, flags, style, sp_info, version, catalog);
33174887Schin 	if (sp_info)
33184887Schin 	{
33194887Schin 		sfclose(sp_info);
33204887Schin 		sp_info = 0;
33214887Schin 	}
33224887Schin 	if (sp_misc)
33234887Schin 	{
33244887Schin 		sfclose(sp_misc);
33254887Schin 		sp_misc = 0;
33264887Schin 	}
33274887Schin 	if (!(p = sfstruse(sp)))
33284887Schin 		goto nospace;
33294887Schin 	name = error_info.id ? error_info.id : "command";
33304887Schin 	m = strlen(name) + 1;
33318462SApril.Chin@Sun.COM #if 0
33324887Schin 	if (!opt_info.state->width)
33338462SApril.Chin@Sun.COM #endif
33344887Schin 	{
33354887Schin 		astwinsize(1, NiL, &opt_info.state->width);
33364887Schin 		if (opt_info.state->width < 20)
33374887Schin 			opt_info.state->width = OPT_WIDTH;
33384887Schin 	}
33398462SApril.Chin@Sun.COM 	margin = style == STYLE_api ? (8 * 1024) : (opt_info.state->width - 1);
33404887Schin 	if (!(opt_info.state->flags & OPT_preformat))
33414887Schin 	{
33424887Schin 		if (style >= STYLE_man || matched < 0)
33434887Schin 		{
33444887Schin 			sfputc(mp, '\f');
33454887Schin 			ts = 0;
33464887Schin 		}
33474887Schin 		else
33484887Schin 			ts = OPT_USAGE + m;
33494887Schin 		if (style == STYLE_html)
33504887Schin 		{
33514887Schin 			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);
33524887Schin 			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);
33534887Schin 			sfprintf(mp, "<DL compact>\n<DT>");
33544887Schin 			co = 2;
33554887Schin 			*(pt = ptstk) = 0;
33564887Schin 		}
33574887Schin 		else
33584887Schin 			co = 0;
33598462SApril.Chin@Sun.COM 		if ((rm = margin - ts) < OPT_MARGIN)
33604887Schin 			rm = OPT_MARGIN;
33614887Schin 		ip = indent;
33624887Schin 		ip->stop = (ip+1)->stop = style >= STYLE_html ? 0 : 2;
33634887Schin 		tp = 0;
33644887Schin 		n = 0;
33654887Schin 		head = 1;
33664887Schin 		while (*p == '\n')
33674887Schin 			p++;
33684887Schin 		while (c = *p++)
33694887Schin 		{
33704887Schin 			if (c == '\n')
33714887Schin 			{
33724887Schin 				ip = indent;
33734887Schin 				n = 0;
33744887Schin 				tp = 0;
33754887Schin 				sfputc(mp, '\n');
33764887Schin 				co = 0;
33778462SApril.Chin@Sun.COM 				rm = margin;
33784887Schin 				ts = ip->stop;
33794887Schin 				if (*p == '\n')
33804887Schin 				{
33814887Schin 					while (*++p == '\n');
33824887Schin 					if ((style == STYLE_man || style == STYLE_html) && (!head || *p != ' ' && *p != '\t'))
33834887Schin 					{
33844887Schin 						if (style == STYLE_man)
33854887Schin 							p--;
33864887Schin 						else
33874887Schin 							sfprintf(mp, "<P>\n");
33884887Schin 					}
33894887Schin 				}
33904887Schin 				head = *p != ' ' && *p != '\t';
33914887Schin 				if (style == STYLE_html && (*p != '<' || !strneq(p, "<BR>", 4) && !strneq(p, "<P>", 3)))
33924887Schin 				{
33934887Schin 					y = p;
33944887Schin 					while (*p == '\t')
33954887Schin 						p++;
33964887Schin 					if (*p == '\n')
33974887Schin 						continue;
33984887Schin 					j = p - y;
33994887Schin 					if (j > *pt)
34004887Schin 					{
34014887Schin 						if (pt > ptstk)
34024887Schin 							sfprintf(mp, "<DL compact>\n");
34034887Schin 						*++pt = j;
34044887Schin 						sfprintf(mp, "<DL compact>\n");
34054887Schin 					}
34064887Schin 					else while (j < *pt)
34074887Schin 					{
34084887Schin 						if (--pt > ptstk)
34094887Schin 							sfprintf(mp, "</DL>\n");
34104887Schin 						sfprintf(mp, "</DL>\n");
34114887Schin 					}
34124887Schin 					co += sfprintf(mp, "<DT>");
34134887Schin 				}
34144887Schin 			}
34154887Schin 			else if (c == '\t')
34164887Schin 			{
34174887Schin 				if (style == STYLE_html)
34184887Schin 				{
34194887Schin 					while (*p == '\t')
34204887Schin 						p++;
34214887Schin 					if (*p != '\n')
34224887Schin 						co += sfprintf(mp, "<DD>");
34234887Schin 				}
34244887Schin 				else
34254887Schin 				{
34264887Schin 					if ((ip+1)->stop)
34274887Schin 					{
34284887Schin 						do
34294887Schin 						{
34304887Schin 							ip++;
34314887Schin 							if (*p != '\t')
34324887Schin 								break;
34334887Schin 							p++;
34344887Schin 						} while ((ip+1)->stop);
34354887Schin 						if (*p == '\n')
34364887Schin 							continue;
34374887Schin 						ts = ip->stop;
34384887Schin 						if (co >= ts)
34394887Schin 						{
34404887Schin 							sfputc(mp, '\n');
34414887Schin 							co = 0;
34428462SApril.Chin@Sun.COM 							rm = margin;
34434887Schin 							ts = ip->stop;
34444887Schin 						}
34454887Schin 					}
34464887Schin 					while (co < ts)
34474887Schin 					{
34484887Schin 						sfputc(mp, ' ');
34494887Schin 						co++;
34504887Schin 					}
34514887Schin 				}
34524887Schin 			}
34534887Schin 			else
34544887Schin 			{
34554887Schin 				if (c == ' ' && !n)
34564887Schin 				{
34574887Schin 					if (co >= rm)
34584887Schin 						tp = 0;
34594887Schin 					else
34604887Schin 					{
34614887Schin 						tp = sfstrtell(mp);
34624887Schin 						pp = p;
34634887Schin 					}
34644887Schin 					if (style == STYLE_nroff && !co)
34654887Schin 						continue;
34664887Schin 				}
34674887Schin 				else if (style == STYLE_html)
34684887Schin 				{
34694887Schin 					if (c == '<')
34704887Schin 					{
34714887Schin 						if (strneq(p, "NOBR>", 5))
34724887Schin 							n++;
34734887Schin 						else if (n && strneq(p, "/NOBR>", 6) && !--n)
34744887Schin 						{
34754887Schin 							for (y = p += 6; (c = *p) && c != ' ' && c != '\t' && c != '\n' && c != '<'; p++)
34764887Schin 								if (c == '[')
34774887Schin 									sfputr(mp, "&#0091;", -1);
34784887Schin 								else if (c == ']')
34794887Schin 									sfputr(mp, "&#0093;", -1);
34804887Schin 								else
34814887Schin 									sfputc(mp, c);
34824887Schin 							sfwrite(mp, "</NOBR", 6);
34834887Schin 							c = '>';
34844887Schin 							tp = 0;
34854887Schin 							co += p - y + 6;
34864887Schin 						}
34874887Schin 					}
34884887Schin 					else if (c == '>' && !n)
34894887Schin 					{
34904887Schin 						for (y = --p; (c = *p) && c != ' ' && c != '\t' && c != '\n' && c != '<'; p++)
34914887Schin 							if (c == '[')
34924887Schin 								sfputr(mp, "&#0091;", -1);
34934887Schin 							else if (c == ']')
34944887Schin 								sfputr(mp, "&#0093;", -1);
34954887Schin 							else
34964887Schin 								sfputc(mp, c);
34974887Schin 						c = *sfstrseek(mp, -1, SEEK_CUR);
34984887Schin 						if (p > y + 1)
34994887Schin 						{
35004887Schin 							tp = 0;
35014887Schin 							co += p - y - 1;
35024887Schin 						}
35034887Schin 						if (co >= rm)
35044887Schin 							tp = 0;
35054887Schin 						else
35064887Schin 						{
35074887Schin 							tp = sfstrtell(mp);
35084887Schin 							pp = p;
35094887Schin 						}
35104887Schin 					}
35114887Schin 					else if (c == '[')
35124887Schin 					{
35134887Schin 						sfputr(mp, "&#0091", -1);
35144887Schin 						c = ';';
35154887Schin 					}
35164887Schin 					else if (c == ']')
35174887Schin 					{
35184887Schin 						sfputr(mp, "&#0093", -1);
35194887Schin 						c = ';';
35204887Schin 					}
35214887Schin 					else if (c == 'h')
35224887Schin 					{
35234887Schin 						y = p;
35244887Schin 						if (*y++ == 't' && *y++ == 't' && *y++ == 'p' && (*y == ':' || *y++ == 's' && *y == ':') && *y++ == ':' && *y++ == '/' && *y++ == '/')
35254887Schin 						{
35264887Schin 							while (isalnum(*y) || *y == '_' || *y == '/' || *y == '-' || *y == '.')
35274887Schin 								y++;
35284887Schin 							if (*y == '?')
35294887Schin 								while (isalnum(*y) || *y == '_' || *y == '/' || *y == '-' || *y == '.' || *y == '?' || *y == '=' || *y == '%' || *y == '&' || *y == ';' || *y == '#')
35304887Schin 									y++;
35314887Schin 							if (*(y - 1) == '.')
35324887Schin 								y--;
35334887Schin 							p--;
35344887Schin 							sfprintf(mp, "<A href=\"%-.*s\">%-.*s</A", y - p, p, y - p, p);
35354887Schin 							p = y;
35364887Schin 							c = '>';
35374887Schin 						}
35384887Schin 					}
35394887Schin 					else if (c == 'C')
35404887Schin 					{
35414887Schin 						y = p;
35424887Schin 						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++ == ')')
35434887Schin 						{
35444887Schin 							sfputr(mp, "Copyright &copy", -1);
35454887Schin 							p = y;
35464887Schin 							c = ';';
35474887Schin 						}
35484887Schin 					}
35494887Schin 				}
35504887Schin 				else if (c == ']')
35514887Schin 				{
35524887Schin 					if (n)
35534887Schin 						n--;
35544887Schin 				}
35554887Schin 				else if (c == '[')
35564887Schin 					n++;
35574887Schin 				if (c == CC_esc)
35584887Schin 				{
35594887Schin 					sfputc(mp, c);
35604887Schin 					do
35614887Schin 					{
35624887Schin 						if (!(c = *p++))
35634887Schin 						{
35644887Schin 							p--;
35654887Schin 							break;
35664887Schin 						}
35674887Schin 						sfputc(mp, c);
35684887Schin 					} while (c < 'a' || c > 'z');
35694887Schin 				}
35704887Schin 				else if (co++ >= rm && !n)
35714887Schin 				{
35724887Schin 					if (tp)
35734887Schin 					{
35744887Schin 						if (*sfstrseek(mp, tp, SEEK_SET) != ' ')
35754887Schin 							sfstrseek(mp, 1, SEEK_CUR);
35764887Schin 						tp = 0;
35774887Schin 						p = pp;
35784887Schin 						n = 0;
35794887Schin 					}
35804887Schin 					else if (c != ' ' && c != '\n')
35814887Schin 						sfputc(mp, c);
35824887Schin 					if (*p == ' ')
35834887Schin 						p++;
35844887Schin 					if (*p != '\n')
35854887Schin 					{
35864887Schin 						sfputc(mp, '\n');
35874887Schin 						for (co = 0; co < ts; co++)
35884887Schin 							sfputc(mp, ' ');
35898462SApril.Chin@Sun.COM 						rm = margin;
35904887Schin 					}
35914887Schin 				}
35924887Schin 				else
35934887Schin 					sfputc(mp, c);
35944887Schin 			}
35954887Schin 		}
35964887Schin 		for (d = sfstrbase(mp), t = sfstrseek(mp, 0, SEEK_CUR); t > d && ((c = *(t - 1)) == '\n' || c == '\r' || c == ' ' || c == '\t'); t--);
35974887Schin 		sfstrseek(mp, t - d, SEEK_SET);
35984887Schin 		if (style == STYLE_html)
35994887Schin 		{
36004887Schin 			while (pt > ptstk)
36014887Schin 			{
36024887Schin 				if (--pt > ptstk)
36034887Schin 					sfprintf(mp, "\n</DL>");
36044887Schin 				sfprintf(mp, "\n</DL>");
36054887Schin 			}
36064887Schin 			sfprintf(mp, "</DL>\n</BODY>\n</HTML>");
36074887Schin 		}
36084887Schin 	}
36094887Schin 	else
36104887Schin 		sfputr(mp, p, 0);
36114887Schin 	if (!(p = sfstruse(mp)))
36124887Schin 		goto nospace;
36134887Schin 	if (sp)
36144887Schin 		sfclose(sp);
36154887Schin 	return opt_info.msg = p;
36164887Schin  nospace:
36174887Schin 	s = T(NiL, ID, "[* out of space *]");
36184887Schin  nope:
36194887Schin 	if (psp)
36204887Schin 		pop(psp);
36214887Schin 	if (sp_help)
36224887Schin 		sfclose(sp_help);
36234887Schin 	if (sp_text)
36244887Schin 		sfclose(sp_text);
36254887Schin 	if (sp_plus)
36264887Schin 		sfclose(sp_plus);
36274887Schin 	if (sp_info)
36284887Schin 		sfclose(sp_info);
36294887Schin 	if (sp_head)
36304887Schin 		sfclose(sp_head);
36314887Schin 	if (sp_body)
36324887Schin 		sfclose(sp_body);
36334887Schin 	if (sp_misc)
36344887Schin 		sfclose(sp_misc);
36354887Schin 	return s;
36364887Schin }
36374887Schin 
36384887Schin /*
36394887Schin  * compatibility wrapper to opthelp()
36404887Schin  */
36414887Schin 
36424887Schin char*
36434887Schin optusage(const char* opts)
36444887Schin {
36454887Schin 	return opthelp(opts, NiL);
36464887Schin }
36474887Schin 
36484887Schin /*
36494887Schin  * convert number using strtonll() *except* that
36504887Schin  * 0*[[:digit:]].* is treated as [[:digit:]].*
36514887Schin  * i.e., it looks octal but isn't, to meet
36524887Schin  * posix Utility Argument Syntax -- use
36534887Schin  * 0x.* or <base>#* for alternate bases
36544887Schin  */
36554887Schin 
36564887Schin static intmax_t
36574887Schin optnumber(const char* s, char** t, int* e)
36584887Schin {
36594887Schin 	intmax_t	n;
36604887Schin 	int		oerrno;
36614887Schin 
36624887Schin 	while (*s == '0' && isdigit(*(s + 1)))
36634887Schin 		s++;
36644887Schin 	oerrno = errno;
36654887Schin 	errno = 0;
36664887Schin 	n = strtonll(s, t, NiL, 0);
36674887Schin 	if (e)
36684887Schin 		*e = errno;
36694887Schin 	errno = oerrno;
36704887Schin 	return n;
36714887Schin }
36724887Schin 
36734887Schin /*
36744887Schin  * point opt_info.arg to an error/info message for opt_info.name
36754887Schin  * p points to opts location for opt_info.name
36764887Schin  * optget() return value is returned
36774887Schin  */
36784887Schin 
36794887Schin static int
36804887Schin opterror(register char* p, int version, char* catalog, int err)
36814887Schin {
36824887Schin 	register Sfio_t*	mp;
36834887Schin 	register Sfio_t*	tp;
36844887Schin 	register char*		s;
36854887Schin 	register int		c;
36864887Schin 
36874887Schin 	if (opt_info.num != LONG_MIN)
3688*10898Sroland.mainz@nrubsig.org 		opt_info.num = (long)(opt_info.number = 0);
36894887Schin 	if (!p || !(mp = opt_info.state->mp) && !(mp = opt_info.state->mp = sfstropen()))
36904887Schin 		goto nospace;
36914887Schin 	s = *p == '-' ? p : opt_info.name;
36924887Schin 	if (*p == '!')
36934887Schin 	{
36944887Schin 		while (*s == '-')
36954887Schin 			sfputc(mp, *s++);
36964887Schin 		sfputc(mp, 'n');
36974887Schin 		sfputc(mp, 'o');
36984887Schin 	}
36994887Schin 	sfputr(mp, s, ':');
37004887Schin 	sfputc(mp, ' ');
37014887Schin 	if (*p == '#' || *p == ':')
37024887Schin 	{
37034887Schin 		if (*p == '#')
37044887Schin 		{
37054887Schin 			s = T(NiL, ID, "numeric");
37064887Schin 			sfputr(mp, s, ' ');
37074887Schin 		}
37084887Schin 		if (*(p = next(p + 1, version)) == '[')
37094887Schin 		{
37104887Schin 			p = skip(s = p + 1, ':', '?', 0, 1, 0, 0, version);
37114887Schin 			tp = X(catalog) ? opt_info.state->xp : mp;
37124887Schin 			while (s < p)
37134887Schin 			{
37144887Schin 				if ((c = *s++) == '?' || c == ']')
37154887Schin 					s++;
37164887Schin 				sfputc(tp, c);
37174887Schin 			}
37184887Schin 			if (!X(catalog))
37194887Schin 				sfputc(mp, ' ');
37204887Schin 			else if (p = sfstruse(tp))
37214887Schin 				sfputr(mp, T(error_info.id, catalog, p), ' ');
37224887Schin 			else
37234887Schin 				goto nospace;
37244887Schin 		}
37254887Schin 		p = opt_info.name[2] ? C("value expected") : C("argument expected");
37264887Schin 	}
37274887Schin 	else if (*p == '*' || *p == '&')
37284887Schin 	{
37294887Schin 		sfputr(mp, opt_info.arg, ':');
37304887Schin 		sfputc(mp, ' ');
37314887Schin 		p = *p == '&' ? C("ambiguous option argument value") : C("unknown option argument value");
37324887Schin 	}
37334887Schin 	else if (*p == '=' || *p == '!')
37344887Schin 		p = C("value not expected");
37354887Schin 	else if (*p == '?')
37364887Schin 		p = *(p + 1) == '?' ? C("optget: option not supported") : C("ambiguous option");
37374887Schin 	else if (*p == '+')
37384887Schin 		p = C("section not found");
37394887Schin 	else
37404887Schin 	{
37414887Schin 		if (opt_info.option[0] != '?' && opt_info.option[0] != '-' || opt_info.option[1] != '?' && opt_info.option[1] != '-')
37424887Schin 			opt_info.option[0] = 0;
37434887Schin 		p = C("unknown option");
37444887Schin 	}
37454887Schin 	p = T(NiL, ID, p);
37464887Schin 	sfputr(mp, p, -1);
37474887Schin 	if (err)
37484887Schin 		sfputr(mp, " -- out of range", -1);
37494887Schin 	if (opt_info.arg = sfstruse(mp))
37504887Schin 		return ':';
37514887Schin  nospace:
37524887Schin 	opt_info.arg = T(NiL, ID, "[* out of space *]");
37534887Schin 	return ':';
37544887Schin }
37554887Schin 
37564887Schin /*
37574887Schin  * argv:	command line argv where argv[0] is command name
37584887Schin  *
37594887Schin  * opts:	option control string
37604887Schin  *
37614887Schin  *	'[' [flag][=][index][:<long-name>[|<alias-name>...]['?'description]] ']'
37624887Schin  *			long option name, index, description; -index returned
37634887Schin  *	':'		option takes string arg
37644887Schin  *	'#'		option takes numeric arg (concat option may follow)
37654887Schin  *	'?'		(option) following options not in usage
37664887Schin  *			(following # or :) optional arg
37674887Schin  *	'[' '[' ... ] ... '[' ... ']' ']'
37684887Schin  *			mutually exclusive option grouping
37694887Schin  *	'[' name [:attr]* [?description] ']'
37704887Schin  *			(following # or :) optional option arg description
37714887Schin  *	'\n'[' '|'\t']*	ignored for legibility
37724887Schin  *	' ' ...		optional argument(s) description (to end of string)
37734887Schin  *			or after blank line
37744887Schin  *	']]'		literal ']' within '[' ... ']'
37754887Schin  *
37764887Schin  * return:
37774887Schin  *	0		no more options
37784887Schin  *	'?'		usage: opt_info.arg points to message sans
37794887Schin  *			`Usage: command '
37804887Schin  *	':'		error: opt_info.arg points to message sans `command: '
37814887Schin  *
3782*10898Sroland.mainz@nrubsig.org  * ':'  '#'  ' '  '['  ']'
37834887Schin  *			invalid option chars
37844887Schin  *
37854887Schin  * -- terminates option list and returns 0
37864887Schin  *
37874887Schin  * + as first opts char makes + equivalent to -
37884887Schin  *
37894887Schin  * if any # option is specified then numeric options (e.g., -123)
37904887Schin  * are associated with the leftmost # option in opts
37914887Schin  *
37924887Schin  * usage info in placed opt_info.arg when '?' returned
37934887Schin  * see help_text[] (--???) for more info
37944887Schin  */
37954887Schin 
37964887Schin int
37974887Schin optget(register char** argv, const char* oopts)
37984887Schin {
37994887Schin 	register int	c;
38004887Schin 	register char*	s;
38014887Schin 	char*		a;
38024887Schin 	char*		b;
38034887Schin 	char*		e;
38044887Schin 	char*		f;
38054887Schin 	char*		g;
38064887Schin 	char*		v;
38074887Schin 	char*		w;
38084887Schin 	char*		p;
38094887Schin 	char*		q;
38104887Schin 	char*		t;
38114887Schin 	char*		y;
38124887Schin 	char*		numopt;
38134887Schin 	char*		opts;
38144887Schin 	char*		catalog;
38154887Schin 	int		n;
38164887Schin 	int		m;
38174887Schin 	int		k;
38184887Schin 	int		j;
38194887Schin 	int		x;
38204887Schin 	int		err;
38214887Schin 	int		no;
38224887Schin 	int		nov;
38234887Schin 	int		num;
38244887Schin 	int		numchr;
38254887Schin 	int		prefix;
38264887Schin 	int		version;
38274887Schin 	Help_t*		hp;
38284887Schin 	Push_t*		psp;
38294887Schin 	Push_t*		tsp;
38304887Schin 	Sfio_t*		vp;
38314887Schin 	Sfio_t*		xp;
38324887Schin 	Optcache_t*	cache;
38334887Schin 	Optcache_t*	pcache;
38344887Schin 	Optpass_t*	pass;
38354887Schin 
38368462SApril.Chin@Sun.COM #if !_PACKAGE_astsa && !_YOU_FIGURED_OUT_HOW_TO_GET_ALL_DLLS_TO_DO_THIS_
38374887Schin 	/*
38384887Schin 	 * these are not initialized by all dlls!
38394887Schin 	 */
38404887Schin 
38414887Schin 	extern Error_info_t	_error_info_;
38424887Schin 	extern Opt_t		_opt_info_;
38434887Schin 
38444887Schin 	if (!_error_infop_)
38454887Schin 		_error_infop_ = &_error_info_;
38464887Schin 	if (!_opt_infop_)
38474887Schin 		_opt_infop_ = &_opt_info_;
38484887Schin 	if (!opt_info.state)
38494887Schin 		opt_info.state = &state;
38504887Schin #endif
38514887Schin 	if (!oopts)
38524887Schin 		return 0;
38534887Schin 	opt_info.state->pindex = opt_info.index;
38544887Schin 	opt_info.state->poffset = opt_info.offset;
38554887Schin 	if (!opt_info.index)
38564887Schin 	{
38574887Schin 		opt_info.index = 1;
38584887Schin 		opt_info.offset = 0;
38594887Schin 		if (opt_info.state->npass)
38604887Schin 		{
38614887Schin 			opt_info.state->npass = 0;
38624887Schin 			opt_info.state->join = 0;
38634887Schin 		}
38644887Schin 	}
38654887Schin 	if (!argv)
38664887Schin 		cache = 0;
38674887Schin 	else
38684887Schin 		for (pcache = 0, cache = opt_info.state->cache; cache; pcache = cache, cache = cache->next)
38694887Schin 			if (cache->pass.oopts == (char*)oopts)
38704887Schin 				break;
38714887Schin 	if (cache)
38724887Schin 	{
38734887Schin 		if (pcache)
38744887Schin 		{
38754887Schin 			pcache->next = cache->next;
38764887Schin 			cache->next = opt_info.state->cache;
38774887Schin 			opt_info.state->cache = cache;
38784887Schin 		}
38794887Schin 		pass = &cache->pass;
38804887Schin 		opt_info.state->npass = -1;
38814887Schin 	}
38824887Schin 	else
38834887Schin 	{
38844887Schin 		if (!argv)
38854887Schin 			n = opt_info.state->npass ? opt_info.state->npass : 1;
38864887Schin 		else if ((n = opt_info.state->join - 1) < 0)
38874887Schin 			n = 0;
38884887Schin 		if (n >= opt_info.state->npass || opt_info.state->pass[n].oopts != (char*)oopts)
38894887Schin 		{
38904887Schin 			for (m = 0; m < opt_info.state->npass && opt_info.state->pass[m].oopts != (char*)oopts; m++);
38914887Schin 			if (m < opt_info.state->npass)
38924887Schin 				n = m;
38934887Schin 			else
38944887Schin 			{
38954887Schin 				if (n >= elementsof(opt_info.state->pass))
38964887Schin 					n = elementsof(opt_info.state->pass) - 1;
38974887Schin 				init((char*)oopts, &opt_info.state->pass[n]);
38984887Schin 				if (opt_info.state->npass <= n)
38994887Schin 					opt_info.state->npass = n + 1;
39004887Schin 			}
39014887Schin 		}
39024887Schin 		if (!argv)
39034887Schin 			return 0;
39044887Schin 		pass = &opt_info.state->pass[n];
39054887Schin 	}
39064887Schin 	opts = pass->opts;
39074887Schin 	prefix = pass->prefix;
39084887Schin 	version = pass->version;
39094887Schin 	if (!(xp = opt_info.state->xp) || (catalog = pass->catalog) && !X(catalog))
39104887Schin 		catalog = 0;
39114887Schin 	else /* if (!error_info.catalog) */
39124887Schin 		error_info.catalog = catalog;
39134887Schin  again:
39144887Schin 	psp = 0;
39154887Schin 
39164887Schin 	/*
39174887Schin 	 * check if any options remain and determine if the
39184887Schin 	 * next option is short or long
39194887Schin 	 */
39204887Schin 
39214887Schin 	opt_info.assignment = 0;
39224887Schin 	num = 1;
39234887Schin 	w = v = 0;
39244887Schin 	x = 0;
39254887Schin 	for (;;)
39264887Schin 	{
39274887Schin 		if (!opt_info.offset)
39284887Schin 		{
39294887Schin 			/*
39304887Schin 			 * finished with the previous arg
39314887Schin 			 */
39324887Schin 
39334887Schin 			if (opt_info.index == 1 && opt_info.argv != opt_info.state->strv)
39344887Schin 			{
39354887Schin 				opt_info.argv = 0;
39364887Schin 				opt_info.state->argv[0] = 0;
39374887Schin 				if (argv[0] && (opt_info.state->argv[0] = save(argv[0])))
39384887Schin 					opt_info.argv = opt_info.state->argv;
39394887Schin 				opt_info.state->style = STYLE_short;
39404887Schin 			}
39414887Schin 			if (!(s = argv[opt_info.index]))
39424887Schin 				return 0;
39434887Schin 			if (!prefix)
39444887Schin 			{
39454887Schin 				/*
39464887Schin 				 * long with no prefix (dd style)
39474887Schin 				 */
39484887Schin 
39494887Schin 				n = 2;
39504887Schin 				if ((c = *s) != '-' && c != '+')
39514887Schin 					c = '-';
39524887Schin 				else if (*++s == c)
39534887Schin 				{
39544887Schin 					if (!*++s)
39554887Schin 					{
39564887Schin 						opt_info.index++;
39574887Schin 						return 0;
39584887Schin 					}
39598462SApril.Chin@Sun.COM 					else if (*s == c)
39608462SApril.Chin@Sun.COM 						return 0;
39614887Schin 				}
39624887Schin 				else if (*s == '?')
39634887Schin 					n = 1;
39644887Schin 			}
39658462SApril.Chin@Sun.COM 			else if ((c = *s++) != '-' && (c != '+' || !(pass->flags & OPT_plus) && (!(pass->flags & OPT_numeric) || !isdigit(*s))))
39664887Schin 			{
39674887Schin 				if (!(pass->flags & OPT_old) || !isalpha(c))
39684887Schin 					return 0;
39694887Schin 				s--;
39704887Schin 				n = 1;
39714887Schin 				opt_info.offset--;
39724887Schin 			}
39734887Schin 			else if (*s == c)
39744887Schin 			{
39754887Schin 				if (!*++s)
39764887Schin 				{
39774887Schin 					/*
39784887Schin 					 * -- or ++ end of options
39794887Schin 					 */
39804887Schin 
39814887Schin 					opt_info.index++;
39824887Schin 					return 0;
39834887Schin 				}
39848462SApril.Chin@Sun.COM 				else if (*s == c)
39858462SApril.Chin@Sun.COM 				{
39868462SApril.Chin@Sun.COM 					/*
39878462SApril.Chin@Sun.COM 					 * ---* or +++* are operands
39888462SApril.Chin@Sun.COM 					 */
39898462SApril.Chin@Sun.COM 
39908462SApril.Chin@Sun.COM 					return 0;
39918462SApril.Chin@Sun.COM 				}
39924887Schin 				if (version || *s == '?' || !(pass->flags & OPT_minus))
39934887Schin 				{
39944887Schin 					/*
39954887Schin 					 * long with double prefix
39964887Schin 					 */
39974887Schin 
39984887Schin 					n = 2;
39994887Schin 				}
40004887Schin 				else
40014887Schin 				{
40024887Schin 					/*
40034887Schin 					 * short option char '-'
40044887Schin 					 */
40054887Schin 
40064887Schin 					s--;
40074887Schin 					n = 1;
40084887Schin 				}
40094887Schin 			}
40104887Schin 			else if (prefix == 1 && *s != '?')
40114887Schin 			{
40124887Schin 				/*
40134887Schin 				 * long with single prefix (find style)
40144887Schin 				 */
40154887Schin 
40164887Schin 				n = 2;
40174887Schin 			}
40184887Schin 			else
40194887Schin 			{
40204887Schin 				/*
40214887Schin 				 * short (always with single prefix)
40224887Schin 				 */
40234887Schin 
40244887Schin 				n = 1;
40254887Schin 			}
40264887Schin 
40274887Schin 			/*
40284887Schin 			 * just a prefix is an option (e.g., `-' == stdin)
40294887Schin 			 */
40304887Schin 
40314887Schin 			if (!*s)
40324887Schin 				return 0;
40334887Schin 			if (c == '+')
40344887Schin 				opt_info.arg = 0;
4035*10898Sroland.mainz@nrubsig.org 			message((-2, "c='%c' n=%d", c, n));
40364887Schin 			if (n == 2)
40374887Schin 			{
40384887Schin 				x = 0;
40394887Schin 				opt_info.state->style = STYLE_long;
40404887Schin 				opt_info.option[0] = opt_info.name[0] = opt_info.name[1] = c;
40414887Schin 				w = &opt_info.name[prefix];
40424887Schin 				if ((*s == 'n' || *s == 'N') && (*(s + 1) == 'o' || *(s + 1) == 'O') && *(s + 2) && *(s + 2) != '=')
40434887Schin 					no = *(s + 2) == '-' ? 3 : 2;
40444887Schin 				else
40454887Schin 					no = 0;
40464887Schin 				for (c = *s; *s; s++)
40474887Schin 				{
40484887Schin 					if (*s == '=')
40494887Schin 					{
40504887Schin 						if (*(s + 1) == '=')
40514887Schin 							s++;
40524887Schin 						if (!isalnum(*(s - 1)) && *(w - 1) == (opt_info.assignment = *(s - 1)))
40534887Schin 							w--;
40544887Schin 						v = ++s;
40554887Schin 						break;
40564887Schin 					}
40574887Schin 					if (w < &opt_info.name[elementsof(opt_info.name) - 1] && *s != ':' && *s != '|' && *s != '[' && *s != ']')
40584887Schin 						*w++ = *s;
40594887Schin 				}
40604887Schin 				*w = 0;
40614887Schin 				w = &opt_info.name[prefix];
40624887Schin 				c = *w;
40634887Schin 				opt_info.offset = 0;
40644887Schin 				opt_info.index++;
40654887Schin 				break;
40664887Schin 			}
40674887Schin 			opt_info.offset++;
40684887Schin 		}
40694887Schin 		if (!argv[opt_info.index])
40704887Schin 			return 0;
40714887Schin 		if (c = argv[opt_info.index][opt_info.offset++])
40724887Schin 		{
40734887Schin 			if ((k = argv[opt_info.index][0]) != '-' && k != '+')
40744887Schin 				k = '-';
40754887Schin 			opt_info.option[0] = opt_info.name[0] = k;
40764887Schin 			opt_info.option[1] = opt_info.name[1] = c;
40774887Schin 			opt_info.option[2] = opt_info.name[2] = 0;
40784887Schin 			break;
40794887Schin 		}
40804887Schin 		opt_info.offset = 0;
40814887Schin 		opt_info.index++;
40824887Schin 	}
40834887Schin 
40844887Schin 	/*
40854887Schin 	 * at this point:
40864887Schin 	 *
40874887Schin 	 *	c	the first character of the option
40884887Schin 	 *	w	long option name if != 0, otherwise short
40894887Schin 	 *	v	long option value (via =) if w != 0
40904887Schin 	 */
40914887Schin 
40924887Schin 	if (c == '?')
40934887Schin 	{
40944887Schin 		/*
40954887Schin 		 * ? always triggers internal help
40964887Schin 		 */
40974887Schin 
40984887Schin 		if (w && !v && (*(w + 1) || !(v = argv[opt_info.index]) || !++opt_info.index))
40994887Schin 			v = w + 1;
41004887Schin 		opt_info.option[1] = c;
41014887Schin 		opt_info.option[2] = 0;
41024887Schin 		if (!w)
41034887Schin 		{
41044887Schin 			opt_info.name[1] = c;
41054887Schin 			opt_info.name[2] = 0;
41064887Schin 		}
41074887Schin 		goto help;
41084887Schin 	}
41094887Schin 	numopt = 0;
41104887Schin 	f = 0;
41114887Schin 	s = opts;
41124887Schin 
41134887Schin 	/*
41144887Schin 	 * no option can start with these characters
41154887Schin 	 */
41164887Schin 
41174887Schin 	if (c == ':' || c == '#' || c == ' ' || c == '[' || c == ']')
41184887Schin 	{
41194887Schin 		if (c != *s)
41204887Schin 			s = "";
41214887Schin 	}
41224887Schin 	else
41234887Schin 	{
41244887Schin 		a = 0;
41254887Schin 		if (!w && (pass->flags & OPT_cache))
41264887Schin 		{
41274887Schin 			if (cache)
41284887Schin 			{
41294887Schin 				if (k = cache->flags[map[c]])
41304887Schin 				{
41314887Schin 					opt_info.arg = 0;
41324887Schin 
41334887Schin 					/*
41344887Schin 					 * this is a ksh getopts workaround
41354887Schin 					 */
41364887Schin 
41374887Schin 					if (opt_info.num != LONG_MIN)
4138*10898Sroland.mainz@nrubsig.org 						opt_info.num = (long)(opt_info.number = !(k & OPT_cache_invert));
41394887Schin 					if (!(k & (OPT_cache_string|OPT_cache_numeric)))
41404887Schin 						return c;
41414887Schin 					if (*(opt_info.arg = &argv[opt_info.index++][opt_info.offset]))
41424887Schin 					{
41434887Schin 						if (!(k & OPT_cache_numeric))
41444887Schin 						{
41454887Schin 							opt_info.offset = 0;
41464887Schin 							return c;
41474887Schin 						}
41484887Schin 						opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
41494887Schin 						if (err || e == opt_info.arg)
41504887Schin 						{
41514887Schin 							if (!err && (k & OPT_cache_optional))
41524887Schin 							{
41534887Schin 								opt_info.arg = 0;
41544887Schin 								opt_info.index--;
41554887Schin 								return c;
41564887Schin 							}
41574887Schin 						}
41584887Schin 						else if (*e)
41594887Schin 						{
41604887Schin 							opt_info.offset += e - opt_info.arg;
41614887Schin 							opt_info.index--;
41624887Schin 							return c;
41634887Schin 						}
41644887Schin 						else
41654887Schin 						{
41664887Schin 							opt_info.offset = 0;
41674887Schin 							return c;
41684887Schin 						}
41694887Schin 					}
41704887Schin 					else if (opt_info.arg = argv[opt_info.index])
41714887Schin 					{
41724887Schin 						opt_info.index++;
41734887Schin 						if ((k & OPT_cache_optional) && (*opt_info.arg == '-' || (pass->flags & OPT_plus) && *opt_info.arg == '+') && *(opt_info.arg + 1))
41744887Schin 						{
41754887Schin 							opt_info.arg = 0;
41764887Schin 							opt_info.index--;
41774887Schin 							opt_info.offset = 0;
41784887Schin 							return c;
41794887Schin 						}
41804887Schin 						if (k & OPT_cache_string)
41814887Schin 						{
41824887Schin 							opt_info.offset = 0;
41834887Schin 							return c;
41844887Schin 						}
41854887Schin 						opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
41864887Schin 						if (!err)
41874887Schin 						{
41884887Schin 							if (!*e)
41894887Schin 							{
41904887Schin 								opt_info.offset = 0;
41914887Schin 								return c;
41924887Schin 							}
41934887Schin 							if (k & OPT_cache_optional)
41944887Schin 							{
41954887Schin 								opt_info.arg = 0;
41964887Schin 								opt_info.index--;
41974887Schin 								opt_info.offset = 0;
41984887Schin 								return c;
41994887Schin 							}
42004887Schin 						}
42014887Schin 					}
42024887Schin 					else if (k & OPT_cache_optional)
42034887Schin 					{
42044887Schin 						opt_info.offset = 0;
42054887Schin 						return c;
42064887Schin 					}
42074887Schin 					opt_info.index--;
42084887Schin 				}
42094887Schin 				cache = 0;
42104887Schin 			}
42114887Schin 			else if (cache = newof(0, Optcache_t, 1, 0))
42124887Schin 			{
42134887Schin 				cache->caching = c;
42144887Schin 				c = 0;
42154887Schin 				cache->pass = *pass;
42164887Schin 				cache->next = opt_info.state->cache;
42174887Schin 				opt_info.state->cache = cache;
42184887Schin 			}
42194887Schin 		}
42204887Schin 		else
42214887Schin 			cache = 0;
42224887Schin 		for (;;)
42234887Schin 		{
42244887Schin 			if (!(*(s = next(s, version))) || *s == '\n' || *s == ' ')
42254887Schin 			{
42264887Schin 				if (!(tsp = psp))
42274887Schin 				{
42284887Schin 					if (cache)
42294887Schin 					{
42304887Schin 						/*
42314887Schin 						 * the first loop pass
42324887Schin 						 * initialized the cache
42334887Schin 						 * so one more pass to
42344887Schin 						 * check the cache or
42354887Schin 						 * bail for a full scan
42364887Schin 						 */
42374887Schin 
42384887Schin 						cache->flags[0] = 0;
42394887Schin 						c = cache->caching;
42404887Schin 						cache->caching = 0;
42414887Schin 						cache = 0;
42424887Schin 						s = opts;
42434887Schin 						continue;
42444887Schin 					}
42454887Schin 					if (!x && catalog)
42464887Schin 					{
42474887Schin 						/*
42484887Schin 						 * the first loop pass
42494887Schin 						 * translated long
42504887Schin 						 * options and there
42514887Schin 						 * were no matches so
42524887Schin 						 * one more pass for C
42534887Schin 						 * locale
42544887Schin 						 */
42554887Schin 
42564887Schin 						catalog = 0;
42574887Schin 						s = opts;
42584887Schin 						continue;
42594887Schin 					}
42604887Schin 					s = "";
42614887Schin 					break;
42624887Schin 				}
42634887Schin 				s = psp->ob;
42644887Schin 				psp = psp->next;
42654887Schin 				free(tsp);
42664887Schin 				continue;
42674887Schin 			}
42684887Schin 			if (*s == '\f')
42694887Schin 			{
42704887Schin 				psp = info(psp, s + 1, NiL, opt_info.state->xp);
42714887Schin 				if (psp->nb)
42724887Schin 					s = psp->nb;
42734887Schin 				else
42744887Schin 				{
42754887Schin 					s = psp->ob;
42764887Schin 					psp = psp->next;
42774887Schin 				}
42784887Schin 				continue;
42794887Schin 			}
4280*10898Sroland.mainz@nrubsig.org 			message((-20, "optget: opt %s  c %c  w %s  num %ld", show(s), c, w, num));
42814887Schin 			if (*s == c && !w)
42824887Schin 				break;
42834887Schin 			else if (*s == '[')
42844887Schin 			{
42854887Schin 				f = s = next(s + 1, version);
42864887Schin 				k = *f;
42874887Schin 				if (k == '+' || k == '-')
42884887Schin 					/* ignore */;
42894887Schin 				else if (k == '[' || version < 1)
42904887Schin 					continue;
42914887Schin 				else if (w && !cache)
42924887Schin 				{
42934887Schin 					nov = no;
42944887Schin 					if (*(s + 1) == '\f' && (vp = opt_info.state->vp))
42954887Schin 					{
42964887Schin 						sfputc(vp, k);
42974887Schin 						s = expand(s + 2, NiL, &t, vp);
42984887Schin 						if (*s)
42994887Schin 							*(f = s - 1) = k;
43004887Schin 						else
43014887Schin 						{
43024887Schin 							f = sfstrbase(vp);
43034887Schin 							if (s = strrchr(f, ':'))
43044887Schin 								f = s - 1;
43054887Schin 							else
43064887Schin 								s = f + 1;
43074887Schin 						}
43084887Schin 					}
43094887Schin 					else
43104887Schin 						t = 0;
43114887Schin 					if (*s != ':')
43124887Schin 						s = skip(s, ':', '?', 0, 1, 0, 0, version);
43134887Schin 					if (*s == ':')
43144887Schin 					{
43154887Schin 						if (catalog)
43164887Schin 						{
43174887Schin 							p = skip(s + 1, '?', 0, 0, 1, 0, 0, version);
43184887Schin 							e = sfprints("%-.*s", p - (s + 1), s + 1);
43194887Schin 							g = T(error_info.id, catalog, e);
43204887Schin 							if (g == e)
43214887Schin 								p = 0;
43224887Schin 							else
43234887Schin 							{
43244887Schin 								sfprintf(xp, ":%s|%s?", g, e);
43254887Schin 								if (!(s = sfstruse(xp)))
43264887Schin 									goto nospace;
43274887Schin 							}
43284887Schin 						}
43294887Schin 						else
43304887Schin 							p = 0;
43314887Schin 						y = w;
43324887Schin 						for (;;)
43334887Schin 						{
43344887Schin 							n = m = 0;
43354887Schin 							e = s + 1;
43364887Schin 							while (*++s)
43374887Schin 							{
43384887Schin 								if (*s == '*' || *s == '\a')
43394887Schin 								{
43404887Schin 									if (*s == '\a')
43414887Schin 										do
43424887Schin 										{
43434887Schin 											if (!*++s)
43444887Schin 											{
43454887Schin 												s--;
43464887Schin 												break;
43474887Schin 											}
43484887Schin 										} while (*s != '\a');
43494887Schin 									j = *(s + 1);
43504887Schin 									if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
43514887Schin 									{
43524887Schin 										while (*w)
43534887Schin 											w++;
43544887Schin 										m = 0;
43554887Schin 										break;
43564887Schin 									}
43574887Schin 									m = 1;
43584887Schin 								}
43594887Schin 								else if (*s == *w || sep(*s) && sep(*w))
43604887Schin 									w++;
43614887Schin 								else if (*w == 0)
43624887Schin 									break;
43634887Schin 								else if (!sep(*s))
43644887Schin 								{
43654887Schin 									if (sep(*w))
43664887Schin 									{
43674887Schin 										if (*++w == *s)
43684887Schin 										{
43694887Schin 											w++;
43704887Schin 											continue;
43714887Schin 										}
43724887Schin 									}
43734887Schin 									else if (w == y || sep(*(w - 1)) || isupper(*(w - 1)) && islower(*w))
43744887Schin 										break;
43754887Schin 									for (q = s; *q && !sep(*q) && *q != '|' && *q != '?' && *q != ']'; q++);
43764887Schin 									if (!sep(*q))
43774887Schin 										break;
43784887Schin 									for (s = q; w > y && *w != *(s + 1); w--);
43794887Schin 								}
43804887Schin 								else if (*w != *(s + 1))
43814887Schin 									break;
43824887Schin 							}
43834887Schin 							if (!*w)
43844887Schin 							{
43854887Schin 								nov = 0;
43864887Schin 								break;
43874887Schin 							}
43884887Schin 							if (n = no)
43894887Schin 							{
43904887Schin 								m = 0;
43914887Schin 								s = e - 1;
43924887Schin 								w = y + n;
43934887Schin 								while (*++s)
43944887Schin 								{
43954887Schin 									if (*s == '*' || *s == '\a')
43964887Schin 									{
43974887Schin 										if (*s == '\a')
43984887Schin 											do
43994887Schin 											{
44004887Schin 												if (!*++s)
44014887Schin 												{
44024887Schin 													s--;
44034887Schin 													break;
44044887Schin 												}
44054887Schin 											} while (*s != '\a');
44064887Schin 										j = *(s + 1);
44074887Schin 										if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
44084887Schin 										{
44094887Schin 											while (*w)
44104887Schin 												w++;
44114887Schin 											m = 0;
44124887Schin 											break;
44134887Schin 										}
44144887Schin 										m = 1;
44154887Schin 									}
44164887Schin 									else if (*s == *w || sep(*s) && sep(*w))
44174887Schin 										w++;
44184887Schin 									else if (*w == 0)
44194887Schin 										break;
44204887Schin 									else if (!sep(*s))
44214887Schin 									{
44224887Schin 										if (sep(*w))
44234887Schin 										{
44244887Schin 											if (*++w == *s)
44254887Schin 											{
44264887Schin 												w++;
44274887Schin 												continue;
44284887Schin 											}
44294887Schin 										}
44304887Schin 										else if (w == y || sep(*(w - 1)) || isupper(*(w - 1)) && islower(*w))
44314887Schin 											break;
44324887Schin 										for (q = s; *q && !sep(*q) && *q != '|' && *q != '?' && *q != ']'; q++);
44334887Schin 										if (!sep(*q))
44344887Schin 											break;
44354887Schin 										for (s = q; w > y && *w != *(s + 1); w--);
44364887Schin 									}
44374887Schin 									else if (*w != *(s + 1))
44384887Schin 										break;
44394887Schin 								}
44404887Schin 								if (!*w)
44414887Schin 									break;
44424887Schin 							}
44434887Schin 							if (*(s = skip(s, ':', '|', '?', 1, 0, 0, version)) != '|')
44444887Schin 								break;
44454887Schin 							w = y;
44464887Schin 						}
44474887Schin 						if (p)
44484887Schin 							s = p;
44494887Schin 						if (!*w)
44504887Schin 						{
44514887Schin 							if (n)
44524887Schin 								num = 0;
44534887Schin 							if (!(n = (m || *s == ':' || *s == '|' || *s == '?' || *s == ']' || *s == 0)) && x)
44544887Schin 							{
44554887Schin 								psp = pop(psp);
44564887Schin 								return opterror("?", version, catalog, 0);
44574887Schin 							}
44584887Schin 							for (x = k; *(f + 1) == '|' && (j = *(f + 2)) && j != '!' && j != '=' && j != ':' && j != '?' && j != ']'; f += 2);
44594887Schin 							if (*f == ':')
44604887Schin 							{
44614887Schin 								x = -1;
44624887Schin 								opt_info.option[1] = '-';
44634887Schin 								opt_info.option[2] = 0;
44644887Schin 							}
44654887Schin 							else if (*(f + 1) == ':' || *(f + 1) == '!' && *(f + 2) == ':')
44664887Schin 							{
44674887Schin 								opt_info.option[1] = x;
44684887Schin 								opt_info.option[2] = 0;
44694887Schin 							}
44704887Schin 							else
44714887Schin 							{
44724887Schin 								a = f;
44734887Schin 								if (*a == '=')
44744887Schin 									a++;
44754887Schin 								else
44764887Schin 								{
44774887Schin 									if (*(a + 1) == '!')
44784887Schin 										a++;
44794887Schin 									if (*(a + 1) == '=')
44804887Schin 										a += 2;
44814887Schin 								}
44824887Schin 								x = -strtol(a, &b, 0);
44834887Schin 								if ((b - a) > sizeof(opt_info.option) - 2)
44844887Schin 									b = a + sizeof(opt_info.option) - 2;
44854887Schin 								memcpy(&opt_info.option[1], a, b - a);
44864887Schin 								opt_info.option[b - a + 1] = 0;
44874887Schin 							}
44884887Schin 							b = e;
44894887Schin 							if (t)
44904887Schin 							{
44914887Schin 								s = t;
44924887Schin 								t = 0;
44934887Schin 							}
44944887Schin 							a = s = skip(s, 0, 0, 0, 1, 0, 0, version);
44954887Schin 							if (n)
44964887Schin 							{
44974887Schin 								w = y;
44984887Schin 								break;
44994887Schin 							}
45004887Schin 						}
45014887Schin 						w = y;
45024887Schin 					}
45034887Schin 					else if (k == c && prefix == 1)
45044887Schin 					{
45054887Schin 						w = 0;
45064887Schin 						opt_info.name[1] = c;
45074887Schin 						opt_info.name[2] = 0;
45084887Schin 						opt_info.offset = 2;
45094887Schin 						opt_info.index--;
45104887Schin 						break;
45114887Schin 					}
45124887Schin 					if (t)
45134887Schin 					{
45144887Schin 						s = t;
45154887Schin 						if (a)
45164887Schin 							a = t;
45174887Schin 					}
45184887Schin 				}
45194887Schin 				s = skip(s, 0, 0, 0, 1, 0, 1, version);
45204887Schin 				if (*s == GO)
45214887Schin 					s = skip(s + 1, 0, 0, 0, 0, 1, 1, version);
45224887Schin 				if (cache)
45234887Schin 				{
45244887Schin 					m = OPT_cache_flag;
45254887Schin 					v = s;
45264887Schin 					if (*v == '#')
45274887Schin 					{
45284887Schin 						v++;
45294887Schin 						m |= OPT_cache_numeric;
45304887Schin 					}
45314887Schin 					else if (*v == ':')
45324887Schin 					{
45334887Schin 						v++;
45344887Schin 						m |= OPT_cache_string;
45354887Schin 					}
45364887Schin 					if (*v == '?')
45374887Schin 					{
45384887Schin 						v++;
45394887Schin 						m |= OPT_cache_optional;
45404887Schin 					}
45414887Schin 					else if (*v == *(v - 1))
45424887Schin 						v++;
45434887Schin 					if (*(v = next(v, version)) == '[')
45444887Schin 						v = skip(v + 1, 0, 0, 0, 1, 0, 1, version);
45454887Schin 					if (*v != GO)
45464887Schin 					{
45474887Schin 						v = f;
45484887Schin 						for (;;)
45494887Schin 						{
45504887Schin 							if (isdigit(*f) && isdigit(*(f + 1)))
45514887Schin 								while (isdigit(*(f + 1)))
45524887Schin 									f++;
45534887Schin 							else if (*(f + 1) == '=')
45544887Schin 								break;
45554887Schin 							else
45564887Schin 								cache->flags[map[*f]] = m;
45574887Schin 							j = 0;
45584887Schin 							while (*(f + 1) == '|')
45594887Schin 							{
45604887Schin 								f += 2;
45614887Schin 								if (!(j = *f) || j == '!' || j == '=' || j == ':' || j == '?' || j == ']')
45624887Schin 									break;
45634887Schin 								cache->flags[map[j]] = m;
45644887Schin 							}
45654887Schin 							if (j != '!' || (m & OPT_cache_invert))
45664887Schin 								break;
45674887Schin 							f = v;
45684887Schin 							m |= OPT_cache_invert;
45694887Schin 						}
45704887Schin 					}
45714887Schin 				}
45724887Schin 				else
45734887Schin 				{
45744887Schin 					m = 0;
45754887Schin 					if (!w)
45764887Schin 					{
45774887Schin 						if (isdigit(*f) && isdigit(*(f + 1)))
45784887Schin 							k = -1;
45794887Schin 						if (c == k)
45804887Schin 							m = 1;
45814887Schin 						while (*(f + 1) == '|')
45824887Schin 						{
45834887Schin 							f += 2;
45844887Schin 							if (!(j = *f))
45854887Schin 							{
45864887Schin 								m = 0;
45874887Schin 								break;
45884887Schin 							}
45894887Schin 							else if (j == c)
45904887Schin 								m = 1;
45914887Schin 							else if (j == '!' || j == '=' || j == ':' || j == '?' || j == ']')
45924887Schin 								break;
45934887Schin 						}
45944887Schin 					}
45954887Schin 					if (m)
45964887Schin 					{
45974887Schin 						s--;
45984887Schin 						if (*++f == '!')
45994887Schin 						{
46004887Schin 							f++;
46014887Schin 							num = 0;
46024887Schin 						}
46034887Schin 						if (*f == '=')
46044887Schin 						{
46054887Schin 							c = -strtol(++f, &b, 0);
46064887Schin 							if ((b - f) > sizeof(opt_info.option) - 2)
46074887Schin 								b = f + sizeof(opt_info.option) - 2;
46084887Schin 							memcpy(&opt_info.option[1], f, b - f);
46094887Schin 							opt_info.option[b - f + 1] = 0;
46104887Schin 						}
46114887Schin 						else
46124887Schin 							c = k;
46134887Schin 						break;
46144887Schin 					}
46154887Schin 				}
46164887Schin 				if (*s == '#')
46174887Schin 				{
46184887Schin 					if (!numopt && s > opts)
46194887Schin 					{
46204887Schin 						numopt = s - 1;
46214887Schin 						numchr = k;
46224887Schin 						if (*f == ':')
46234887Schin 							numchr = -1;
46244887Schin 						else if (*(f + 1) != ':' && *(f + 1) != '!' && *(f + 1) != ']')
46254887Schin 						{
46264887Schin 							a = f;
46274887Schin 							if (*a == '=')
46284887Schin 								a++;
46294887Schin 							else
46304887Schin 							{
46314887Schin 								if (*(a + 1) == '!')
46324887Schin 									a++;
46334887Schin 								if (*(a + 1) == '=')
46344887Schin 									a += 2;
46354887Schin 							}
46364887Schin 							numchr = -strtol(a, NiL, 0);
46374887Schin 						}
46384887Schin 					}
46394887Schin 				}
46404887Schin 				else if (*s != ':')
46414887Schin 					continue;
46424887Schin 			}
46434887Schin 			else if (*s == ']')
46444887Schin 			{
46454887Schin 				s++;
46464887Schin 				continue;
46474887Schin 			}
46484887Schin 			else if (*s == '#')
46494887Schin 			{
46504887Schin 				if (!numopt && s > opts)
46514887Schin 					numchr = *(numopt = s - 1);
46524887Schin 			}
46534887Schin 			else if (*s != ':')
46544887Schin 			{
46554887Schin 				if (cache)
46564887Schin 				{
46574887Schin 					m = OPT_cache_flag;
46584887Schin 					if (*(s + 1) == '#')
46594887Schin 					{
46604887Schin 						m |= OPT_cache_numeric;
46614887Schin 						if (*(s + 2) == '?')
46624887Schin 							m |= OPT_cache_optional;
46634887Schin 					}
46644887Schin 					else if (*(s + 1) == ':')
46654887Schin 					{
46664887Schin 						m |= OPT_cache_string;
46674887Schin 						if (*(s + 2) == '?')
46684887Schin 							m |= OPT_cache_optional;
46694887Schin 					}
46704887Schin 					cache->flags[map[*s]] = m;
46714887Schin 				}
46724887Schin 				s++;
46734887Schin 				continue;
46744887Schin 			}
46754887Schin 			message((-21, "optget: opt %s", show(s)));
46764887Schin 			if (*++s == '?' || *s == *(s - 1))
46774887Schin 				s++;
46784887Schin 			if (*(s = next(s, version)) == '[')
46794887Schin 			{
46804887Schin 				s = skip(s + 1, 0, 0, 0, 1, 0, 1, version);
46814887Schin 				if (*s == GO)
46824887Schin 					s = skip(s + 1, 0, 0, 0, 0, 1, 1, version);
46834887Schin 			}
4684*10898Sroland.mainz@nrubsig.org 			message((-21, "optget: opt %s", show(s)));
46854887Schin 		}
46864887Schin 		if (w && x)
46874887Schin 		{
46884887Schin 			s = skip(b, '|', '?', 0, 1, 0, 0, version);
46894887Schin 			if (v && (a == 0 || *a == 0 || *(a + 1) != ':' && *(a + 1) != '#') && (*v == '0' || *v == '1') && !*(v + 1))
46904887Schin 			{
46914887Schin 				if (*v == '0')
46924887Schin 					num = !num;
46934887Schin 				v = 0;
46944887Schin 			}
46954887Schin 			if ((s - b) >= elementsof(opt_info.name))
46964887Schin 				s = b + elementsof(opt_info.name) - 1;
46974887Schin 			for (;;)
46984887Schin 			{
46994887Schin 				if (b >= s)
47004887Schin 				{
47014887Schin 					*w = 0;
47024887Schin 					break;
47034887Schin 				}
47044887Schin 				if (*b == '*')
47054887Schin 					break;
47064887Schin 				*w++ = *b++;
47074887Schin 			}
47084887Schin 			if (!num && v)
47094887Schin 				return opterror(no ? "!" : "=", version, catalog, 0);
47104887Schin 			w = &opt_info.name[prefix];
47114887Schin 			c = x;
47124887Schin 			s = a;
47134887Schin 		}
47144887Schin 	}
47154887Schin 	if (!*s)
47164887Schin 	{
47174887Schin 		if (w)
47184887Schin 		{
47194887Schin 			if (hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), w))
47204887Schin 			{
47214887Schin 				if (!v)
47224887Schin 					v = (char*)hp->name;
47234887Schin 				goto help;
47244887Schin 			}
47254887Schin 			if (!v)
47264887Schin 			{
47274887Schin 				v = opt_info.name;
47284887Schin 				goto help;
47294887Schin 			}
47304887Schin 		}
47318462SApril.Chin@Sun.COM 		if (w || !isdigit(c) || !numopt || !(pass->flags & OPT_numeric))
47324887Schin 		{
47334887Schin 			pop(psp);
47344887Schin 			return opterror("", version, catalog, 0);
47354887Schin 		}
47364887Schin 		s = numopt;
47374887Schin 		c = opt_info.option[1] = numchr;
47384887Schin 		opt_info.offset--;
47394887Schin 	}
47404887Schin 	opt_info.arg = 0;
47414887Schin 
47424887Schin 	/*
47434887Schin 	 * this is a ksh getopts workaround
47444887Schin 	 */
47454887Schin 
47464887Schin 	if (opt_info.num != LONG_MIN)
4747*10898Sroland.mainz@nrubsig.org 		opt_info.num = (long)(opt_info.number = num);
47484887Schin 	if ((n = *++s == '#') || *s == ':' || w && !nov && v && (optnumber(v, &e, NiL), n = !*e))
47494887Schin 	{
47504887Schin 		if (w)
47514887Schin 		{
47524887Schin 			if (nov)
47534887Schin 			{
47544887Schin 				if (v)
47554887Schin 				{
47564887Schin 					pop(psp);
47574887Schin 					return opterror("!", version, catalog, 0);
47584887Schin 				}
4759*10898Sroland.mainz@nrubsig.org 				opt_info.num = (long)(opt_info.number = 0);
47604887Schin 			}
47614887Schin 			else
47624887Schin 			{
47634887Schin 				if (!v && *(s + 1) != '?' && (v = argv[opt_info.index]))
47644887Schin 				{
47654887Schin 					opt_info.index++;
47664887Schin 					opt_info.offset = 0;
47674887Schin 				}
47684887Schin 				if (!(opt_info.arg = v) || (*v == '0' || *v == '1') && !*(v + 1))
47694887Schin 				{
47704887Schin 					if (*(s + 1) != '?')
47714887Schin 					{
47724887Schin 						if (!opt_info.arg)
47734887Schin 						{
47744887Schin 							pop(psp);
47754887Schin 							return opterror(s, version, catalog, 0);
47764887Schin 						}
47774887Schin 					}
47784887Schin 					else if (*(t = next(s + 2, version)) == '[')
47794887Schin 						while (*(t = skip(t, ':', 0, 0, 1, 0, 0, version)) == ':')
47804887Schin 							if (*++t == '!')
47814887Schin 							{
47824887Schin 								if (!v || *v == '1')
47834887Schin 								{
47844887Schin 									e = skip(t, ':', '?', ']', 1, 0, 0, version);
47854887Schin 									opt_info.arg = sfprints("%-.*s", e - t - 1, t + 1);
47864887Schin 								}
47874887Schin 								else
47884887Schin 								{
47894887Schin 									opt_info.arg = 0;
4790*10898Sroland.mainz@nrubsig.org 									opt_info.num = (long)(opt_info.number = 0);
47914887Schin 								}
47924887Schin 								break;
47934887Schin 							}
47944887Schin 				}
47954887Schin 				if (opt_info.arg && n)
47964887Schin 				{
47974887Schin 					opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
47984887Schin 					if (err || e == opt_info.arg)
47994887Schin 					{
48004887Schin 						pop(psp);
48014887Schin 						return opterror(s, version, catalog, err);
48024887Schin 					}
48034887Schin 				}
48044887Schin 			}
48054887Schin 			goto optarg;
48064887Schin 		}
48074887Schin 		else if (*(opt_info.arg = &argv[opt_info.index++][opt_info.offset]))
48084887Schin 		{
48094887Schin 			if (*s == '#')
48104887Schin 			{
48114887Schin 				opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
48124887Schin 				if (err || e == opt_info.arg)
48134887Schin 				{
48144887Schin 					if (!err && *(s + 1) == '?')
48154887Schin 					{
48164887Schin 						opt_info.arg = 0;
48174887Schin 						opt_info.index--;
48184887Schin 					}
48194887Schin 					else
48204887Schin 					{
48214887Schin 						opt_info.offset = 0;
48224887Schin 						c = opterror(s, version, catalog, err);
48234887Schin 					}
48244887Schin 					pop(psp);
48254887Schin 					return c;
48264887Schin 				}
48274887Schin 				else if (*e)
48284887Schin 				{
48294887Schin 					opt_info.offset += e - opt_info.arg;
48304887Schin 					opt_info.index--;
48314887Schin 					pop(psp);
48324887Schin 					return c;
48334887Schin 				}
48344887Schin 			}
48354887Schin 		}
48364887Schin 		else if (opt_info.arg = argv[opt_info.index])
48374887Schin 		{
48384887Schin 			opt_info.index++;
48394887Schin 			if (*(s + 1) == '?' && (*opt_info.arg == '-' || (pass->flags & OPT_plus) && *opt_info.arg == '+') && *(opt_info.arg + 1))
48404887Schin 			{
48414887Schin 				opt_info.index--;
48424887Schin 				opt_info.arg = 0;
48434887Schin 			}
48444887Schin 			else if (*s == '#')
48454887Schin 			{
48464887Schin 				opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
48474887Schin 				if (err || *e)
48484887Schin 				{
48494887Schin 					if (!err && *(s + 1) == '?')
48504887Schin 					{
48514887Schin 						opt_info.arg = 0;
48524887Schin 						opt_info.index--;
48534887Schin 					}
48544887Schin 					else
48554887Schin 					{
48564887Schin 						pop(psp);
48574887Schin 						opt_info.offset = 0;
48584887Schin 						return opterror(s, version, catalog, err);
48594887Schin 					}
48604887Schin 				}
48614887Schin 			}
48624887Schin 		}
48634887Schin 		else if (*(s + 1) != '?')
48644887Schin 		{
48654887Schin 			opt_info.index--;
48664887Schin 			pop(psp);
48674887Schin 			return opterror(s, version, catalog, 0);
48684887Schin 		}
48694887Schin 		opt_info.offset = 0;
48704887Schin 	optarg:
48714887Schin 		if (*s == ':' && *(s = skip(s, 0, 0, 0, 1, 0, 1, version)) == GO && *(s = next(s + 1, version)) == '[' && isalnum(*(s + 1)))
48724887Schin 		{
48734887Schin 			x = 0;
48744887Schin 			if (opt_info.arg)
48754887Schin 			{
48764887Schin 				do
48774887Schin 				{
48784887Schin 					w = y = opt_info.arg;
48794887Schin 					f = s = next(s + 1, version);
48804887Schin 					k = *f;
48814887Schin 					if (k == *w && isalpha(k) && !*(w + 1))
48824887Schin 					{
48834887Schin 						x = k;
48844887Schin 						break;
48854887Schin 					}
48864887Schin 					if (*s == '+' || *s == '-')
48874887Schin 						continue;
48884887Schin 					else if (*s == '[' || version < 1)
48894887Schin 						continue;
48904887Schin 					else
48914887Schin 					{
48924887Schin 						if (*s != ':')
48934887Schin 							s = skip(s, ':', '?', 0, 1, 0, 0, version);
48944887Schin 						if (*s == ':')
48954887Schin 						{
48964887Schin 							if (catalog)
48974887Schin 							{
48984887Schin 								p = skip(s + 1, '?', 0, 0, 1, 0, 0, version);
48994887Schin 								e = sfprints("%-.*s", p - (s + 1), s + 1);
49004887Schin 								b = T(error_info.id, catalog, e);
49014887Schin 								if (b == e)
49024887Schin 									p = 0;
49034887Schin 								else
49044887Schin 								{
49054887Schin 									sfprintf(xp, ":%s|%s?", b, e);
49064887Schin 									if (!(s = sfstruse(xp)))
49074887Schin 										goto nospace;
49084887Schin 								}
49094887Schin 							}
49104887Schin 							else
49114887Schin 								p = 0;
49124887Schin 							for (;;)
49134887Schin 							{
49144887Schin 								n = m = 0;
49154887Schin 								e = s + 1;
49164887Schin 								while (*++s)
49174887Schin 								{
49184887Schin 									if (*s == '*' || *s == '\a')
49194887Schin 									{
49204887Schin 										if (*s == '\a')
49214887Schin 											do
49224887Schin 											{
49234887Schin 												if (!*++s)
49244887Schin 												{
49254887Schin 													s--;
49264887Schin 													break;
49274887Schin 												}
49284887Schin 											} while (*s != '\a');
49294887Schin 										j = *(s + 1);
49304887Schin 										if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
49314887Schin 										{
49324887Schin 											while (*w)
49334887Schin 												w++;
49344887Schin 											m = 0;
49354887Schin 											break;
49364887Schin 										}
49374887Schin 										m = 1;
49384887Schin 									}
49394887Schin 									else if (*s == *w || sep(*s) && sep(*w))
49404887Schin 										w++;
49414887Schin 									else if (*w == 0)
49424887Schin 										break;
49434887Schin 									else if (!sep(*s))
49444887Schin 									{
49454887Schin 										if (sep(*w))
49464887Schin 										{
49474887Schin 											if (*++w == *s)
49484887Schin 											{
49494887Schin 												w++;
49504887Schin 												continue;
49514887Schin 											}
49524887Schin 										}
49534887Schin 										else if (w == y || sep(*(w - 1)) || isupper(*(w - 1)) && islower(*w))
49544887Schin 											break;
49554887Schin 										for (q = s; *q && !sep(*q) && *q != '|' && *q != '?' && *q != ']'; q++);
49564887Schin 										if (!sep(*q))
49574887Schin 											break;
49584887Schin 										for (s = q; w > y && *w != *(s + 1); w--);
49594887Schin 									}
49604887Schin 									else if (*w != *(s + 1))
49614887Schin 										break;
49624887Schin 								}
49634887Schin 								if (!*w)
49644887Schin 								{
49654887Schin 									nov = 0;
49664887Schin 									break;
49674887Schin 								}
49684887Schin 								if (*(s = skip(s, ':', '|', '?', 1, 0, 0, version)) != '|')
49694887Schin 									break;
49704887Schin 								w = y;
49714887Schin 							}
49724887Schin 							if (p)
49734887Schin 								s = p;
49744887Schin 							if (!*w)
49754887Schin 							{
49764887Schin 								if (n)
49774887Schin 									num = 0;
49784887Schin 								if (!(n = (m || *s == ':' || *s == '|' || *s == '?' || *s == ']')) && x)
49794887Schin 								{
49804887Schin 									pop(psp);
49814887Schin 									return opterror("&", version, catalog, 0);
49824887Schin 								}
49834887Schin 								for (x = k; *(f + 1) == '|' && (j = *(f + 2)) && j != '!' && j != '=' && j != ':' && j != '?' && j != ']'; f += 2);
49844887Schin 								if (*f == ':')
49854887Schin 									x = -1;
49864887Schin 								else if (*(f + 1) == ':' || *(f + 1) == '!' && *(f + 2) == ':')
49874887Schin 									/* ok */;
49884887Schin 								else
49894887Schin 								{
49904887Schin 									a = f;
49914887Schin 									if (*a == '=')
49924887Schin 										a++;
49934887Schin 									else
49944887Schin 									{
49954887Schin 										if (*(a + 1) == '!')
49964887Schin 											a++;
49974887Schin 										if (*(a + 1) == '=')
49984887Schin 											a += 2;
49994887Schin 									}
50004887Schin 									x = -strtol(a, &b, 0);
50014887Schin 								}
50024887Schin 								b = e;
50034887Schin 								a = s = skip(s, 0, 0, 0, 1, 0, 0, version);
50044887Schin 								if (n)
50054887Schin 									break;
50064887Schin 							}
50074887Schin 						}
50084887Schin 					}
50094887Schin 				} while (*(s = skip(s, 0, 0, 0, 1, 0, 1, version)) == '[');
5010*10898Sroland.mainz@nrubsig.org 				if (!(opt_info.num = (long)(opt_info.number = x)))
50114887Schin 				{
50124887Schin 					pop(psp);
50134887Schin 					return opterror("*", version, catalog, 0);
50144887Schin 				}
50154887Schin 			}
50164887Schin 		}
50174887Schin 	}
50184887Schin 	else if (w && v)
50194887Schin 	{
50204887Schin 		pop(psp);
50214887Schin 		return opterror("=", version, catalog, 0);
50224887Schin 	}
50234887Schin 	else
50244887Schin 	{
5025*10898Sroland.mainz@nrubsig.org 		opt_info.num = (long)(opt_info.number = num);
50264887Schin 		if (!w && !argv[opt_info.index][opt_info.offset])
50274887Schin 		{
50284887Schin 			opt_info.offset = 0;
50294887Schin 			opt_info.index++;
50304887Schin 		}
50314887Schin 	}
50324887Schin 	pop(psp);
50334887Schin 	return c;
50344887Schin  help:
50354887Schin 	if (v && *v == '?' && *(v + 1) == '?' && *(v + 2))
50364887Schin 	{
50374887Schin 		s = v + 2;
50384887Schin 		if ((s[0] == 'n' || s[0] == 'N') && (s[1] == 'o' || s[1] == 'O'))
50394887Schin 		{
50404887Schin 			s += 2;
50414887Schin 			n = -1;
50424887Schin 		}
50434887Schin 		else
50444887Schin 			n = 1;
50454887Schin 		if (hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), s))
50464887Schin 		{
50474887Schin 			if (hp->style < STYLE_man || !(s = argv[opt_info.index]) || s[0] != '-' || s[1] != '-' || !s[2])
50484887Schin 			{
50494887Schin 				opt_info.arg = sfprints("\fversion=%d", version);
50504887Schin 				pop(psp);
50514887Schin 				return '?';
50524887Schin 			}
50534887Schin 			opt_info.state->force = hp->style;
50544887Schin 		}
50554887Schin 		else if (match(s, "ESC", -1, NiL) || match(s, "EMPHASIS", -1, NiL))
50564887Schin 			opt_info.state->emphasis = n;
50574887Schin 		else if (match(s, "PREFORMAT", -1, NiL))
50584887Schin 			opt_info.state->flags |= OPT_preformat;
50594887Schin 		else if (match(s, "TEST", -1, NiL))
50604887Schin 		{
50614887Schin 			opt_info.state->width = OPT_WIDTH;
50624887Schin 			opt_info.state->emphasis = 1;
50634887Schin 		}
50644887Schin 		else
50654887Schin 		{
50664887Schin 			pop(psp);
50674887Schin 			return opterror(v, version, catalog, 0);
50684887Schin 		}
50694887Schin 		psp = pop(psp);
50704887Schin 		if (argv == opt_info.state->strv)
50714887Schin 			return '#';
50724887Schin 		goto again;
50734887Schin 	}
50744887Schin 	if ((opt_info.arg = opthelp(NiL, v)) == (char*)unknown)
50754887Schin 	{
50764887Schin 		pop(psp);
50774887Schin 		return opterror(v, version, catalog, 0);
50784887Schin 	}
50794887Schin 	pop(psp);
50804887Schin 	return '?';
50814887Schin  nospace:
50824887Schin 	pop(psp);
50834887Schin 	return opterror(NiL, 0, NiL, 0);
50844887Schin }
50854887Schin 
50864887Schin /*
50874887Schin  * parse long options with 0,1,2 leading '-' or '+' from string and pass to optget()
50884887Schin  * syntax is the unquoted
50894887Schin  *
50904887Schin  *	<length> [-|+|--|++]<name>[[-+:|&=]=<value>\n (or \0 for the last)
50914887Schin  *
50924887Schin  * or the quoted
50934887Schin  *
50944887Schin  *	[-|+|--|++][no]name[[-+:|&=]=['"{(]value[)}"']][, ]...
50954887Schin  *
50964887Schin  * with \x escapes passed to chresc()
50974887Schin  *
50984887Schin  * return '#' for `label:', with opt_info.name==label
50994887Schin  * str[opt_info.offset]	next arg
51004887Schin  *
51014887Schin  *	optstr(s, 0)
51024887Schin  *		return '-' if arg, 0 otherwise
51034887Schin  *	optstr(0, opts)
51044887Schin  *		use previous parsed str
51054887Schin  */
51064887Schin 
51074887Schin int
51084887Schin optstr(const char* str, const char* opts)
51094887Schin {
51104887Schin 	register char*		s = (char*)str;
51114887Schin 	register Sfio_t*	mp;
51124887Schin 	register int		c;
51134887Schin 	register int		ql;
51144887Schin 	register int		qr;
51154887Schin 	register int		qc;
51164887Schin 	int			v;
51174887Schin 	char*			e;
51184887Schin 
51194887Schin  again:
51204887Schin 	if (s)
51214887Schin 	{
51224887Schin 		if (!(mp = opt_info.state->strp) && !(mp = opt_info.state->strp = sfstropen()))
51234887Schin 			return 0;
51244887Schin 		if (opt_info.state->str != s)
51254887Schin 			opt_info.state->str = s;
51264887Schin 		else if (opt_info.index == 1)
51274887Schin 			s += opt_info.offset;
51284887Schin 		while (*s == ',' || *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')
51294887Schin 			s++;
51304887Schin 		if (!*s)
51314887Schin 		{
51324887Schin 			opt_info.state->str = 0;
51334887Schin 			return 0;
51344887Schin 		}
51354887Schin 		if (*s == '-' || *s == '+')
51364887Schin 		{
51374887Schin 			c = *s++;
51384887Schin 			sfputc(mp, c);
51394887Schin 			if (*s == c)
51404887Schin 			{
51414887Schin 				sfputc(mp, c);
51424887Schin 				s++;
51434887Schin 			}
51444887Schin 		}
51454887Schin 		else
51464887Schin 		{
51474887Schin 			sfputc(mp, '-');
51484887Schin 			sfputc(mp, '-');
51494887Schin 		}
51504887Schin 		if (isdigit(*s) && (v = (int)strtol(s, &e, 10)) > 1 && isspace(*e) && --v <= strlen(s) && (s[v] == 0 || s[v] == '\n'))
51514887Schin 		{
51524887Schin 			s += v;
51534887Schin 			while (isspace(*++e));
51544887Schin 			sfwrite(mp, e, s - e);
51554887Schin 		}
51564887Schin 		else
51574887Schin 		{
51584887Schin 			while (*s && *s != ',' && *s != ' ' && *s != '\t' && *s != '\n' && *s != '\r' && *s != '=' && *s != ':')
51594887Schin 				sfputc(mp, *s++);
51604887Schin 			if ((c = *s) == ':' && *(s + 1) != '=')
51614887Schin 			{
51624887Schin 				opt_info.index = 1;
51634887Schin 				opt_info.offset = ++s - (char*)str;
51644887Schin 				if (!(s = sfstruse(mp)))
51654887Schin 					goto nospace;
51664887Schin 				s += 2;
51674887Schin 				e = opt_info.name;
51684887Schin 				while (e < &opt_info.name[sizeof(opt_info.name)-1] && (*e++ = *s++));
51694887Schin 				opt_info.arg = 0;
5170*10898Sroland.mainz@nrubsig.org 				opt_info.num = (long)(opt_info.number = 0);
51714887Schin 				opt_info.option[0] = ':';
51724887Schin 				opt_info.option[1] = 0;
51734887Schin 				return '#';
51744887Schin 			}
51754887Schin 			if (c == ':' || c == '=')
51764887Schin 			{
51774887Schin 				sfputc(mp, c);
51784887Schin 				ql = qr = 0;
51794887Schin 				while (c = *++s)
51804887Schin 				{
51814887Schin 					if (c == '\\')
51824887Schin 					{
51834887Schin 						sfputc(mp, chresc(s, &e));
51844887Schin 						s = e - 1;
51854887Schin 					}
51864887Schin 					else if (c == qr)
51874887Schin 					{
51884887Schin 						if (qr != ql)
51894887Schin 							sfputc(mp, c);
51904887Schin 						if (--qc <= 0)
51914887Schin 							qr = ql = 0;
51924887Schin 					}
51934887Schin 					else if (c == ql)
51944887Schin 					{
51954887Schin 						sfputc(mp, c);
51964887Schin 						qc++;
51974887Schin 					}
51984887Schin 					else if (qr)
51994887Schin 						sfputc(mp, c);
52004887Schin 					else if (c == ',' || c == ' ' || c == '\t' || c == '\n' || c == '\r')
52014887Schin 						break;
52024887Schin 					else if (c == '"' || c == '\'')
52034887Schin 					{
52044887Schin 						ql = qr = c;
52054887Schin 						qc = 1;
52064887Schin 					}
52074887Schin 					else
52084887Schin 					{
52094887Schin 						sfputc(mp, c);
52104887Schin 						if (c == GO)
52114887Schin 						{
52124887Schin 							ql = c;
52134887Schin 							qr = OG;
52144887Schin 							qc = 1;
52154887Schin 						}
52164887Schin 						else if (c == '(')
52174887Schin 						{
52184887Schin 							ql = c;
52194887Schin 							qr = ')';
52204887Schin 							qc = 1;
52214887Schin 						}
52224887Schin 					}
52234887Schin 				}
52244887Schin 			}
52254887Schin 		}
52264887Schin 		opt_info.argv = opt_info.state->strv;
52274887Schin 		opt_info.state->strv[0] = T(NiL, ID, "option");
52284887Schin 		if (!(opt_info.state->strv[1] = sfstruse(mp)))
52294887Schin 			goto nospace;
52304887Schin 		opt_info.state->strv[2] = 0;
52314887Schin 		opt_info.offset = s - (char*)str;
52324887Schin 	}
52334887Schin 	if (opts)
52344887Schin 	{
52354887Schin 		if (!opt_info.state->strv[1])
52364887Schin 		{
52374887Schin 			opt_info.state->str = 0;
52384887Schin 			return 0;
52394887Schin 		}
52404887Schin 		opt_info.index = 1;
52414887Schin 		v = opt_info.offset;
52424887Schin 		opt_info.offset = 0;
52434887Schin 		c = optget(opt_info.state->strv, opts);
52444887Schin 		opt_info.index = 1;
52454887Schin 		opt_info.offset = v;
52464887Schin 		if (c == '#')
52474887Schin 		{
52484887Schin 			s = opt_info.state->str;
52494887Schin 			goto again;
52504887Schin 		}
52514887Schin 		if ((c == '?' || c == ':') && (opt_info.arg[0] == '-' && opt_info.arg[1] == '-'))
52524887Schin 			opt_info.arg += 2;
52534887Schin 		s = opt_info.name;
52544887Schin 		if (*s++ == '-' && *s++ == '-' && *s)
52554887Schin 		{
52564887Schin 			e = opt_info.name;
52574887Schin 			while (*e++ = *s++);
52584887Schin 		}
52594887Schin 	}
52604887Schin 	else
52614887Schin 		c = '-';
52624887Schin 	return c;
52634887Schin  nospace:
52644887Schin 	return opterror(NiL, 0, NiL, 0);
52654887Schin }
5266