14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1985-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.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	*/
534887Schin #define OPT_minus	0x021		/* '-' is an option flag	*/
544887Schin #define OPT_number	0x040		/* arg is strtonll() number	*/
554887Schin #define OPT_oneof	0x080		/* arg may be set once		*/
564887Schin #define OPT_optional	0x100		/* arg is optional		*/
574887Schin #define OPT_string	0x200		/* arg is string		*/
584887Schin 
594887Schin #define OPT_preformat	0001		/* output preformat string	*/
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;
683*8462SApril.Chin@Sun.COM 	Dtdisc_t*	d;
6844887Schin 
6854887Schin 	static Dt_t*	dict;
6864887Schin 
6874887Schin 	if (!dict)
6884887Schin 	{
689*8462SApril.Chin@Sun.COM 		if (!(d = newof(0, Dtdisc_t, 1, 0)))
690*8462SApril.Chin@Sun.COM 			return (char*)s;
691*8462SApril.Chin@Sun.COM 		d->key = offsetof(Save_t, text);
692*8462SApril.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 			{
760*8462SApril.Chin@Sun.COM 				if (!isdigit(*s))
7614887Schin 					p->version = 1;
7624887Schin 				else
763*8462SApril.Chin@Sun.COM 					while (isdigit(*s))
7644887Schin 						p->version = p->version * 10 + (*s++ - '0');
7654887Schin 				while (*s && *s != '?' && *s != ']')
7664887Schin 				{
7674887Schin 					c = *s++;
768*8462SApril.Chin@Sun.COM 					if (!isdigit(*s))
7694887Schin 						n = 1;
7704887Schin 					else
7714887Schin 					{
7724887Schin 						n = 0;
773*8462SApril.Chin@Sun.COM 						while (isdigit(*s))
7744887Schin 							n = n * 10 + (*s++ - '0');
7754887Schin 					}
7764887Schin 					switch (c)
7774887Schin 					{
778*8462SApril.Chin@Sun.COM 					case '+':
779*8462SApril.Chin@Sun.COM 						p->flags |= OPT_plus;
780*8462SApril.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;
790*8462SApril.Chin@Sun.COM 					case 'n':
791*8462SApril.Chin@Sun.COM 						p->flags |= OPT_numeric;
792*8462SApril.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 	}
850*8462SApril.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;
9054887Schin 	return 0;
9064887Schin }
9074887Schin 
9084887Schin /*
9094887Schin  * return the bold set/unset sequence for style
9104887Schin  */
9114887Schin 
9124887Schin static const char*
9134887Schin font(int f, int style, int set)
9144887Schin {
9154887Schin 	switch (style)
9164887Schin 	{
9174887Schin 	case STYLE_html:
9184887Schin 		return fonts[f].html[set];
9194887Schin 	case STYLE_nroff:
9204887Schin 		return fonts[f].nroff[set];
9214887Schin 	case STYLE_short:
9224887Schin 	case STYLE_long:
9234887Schin 	case STYLE_posix:
9244887Schin 	case STYLE_api:
9254887Schin 		break;
9264887Schin 	default:
9274887Schin 		if (opt_info.state->emphasis > 0)
9284887Schin 			return fonts[f].term[set];
9294887Schin 		break;
9304887Schin 	}
9314887Schin 	return "";
9324887Schin }
9334887Schin 
9344887Schin /*
9354887Schin  * expand \f...\f info
9364887Schin  * *p set to next char after second \f
9374887Schin  * expanded value returned
9384887Schin  */
9394887Schin 
9404887Schin static char*
9414887Schin expand(register char* s, register char* e, char** p, Sfio_t* ip)
9424887Schin {
9434887Schin 	register int	c;
9444887Schin 	register char*	b = s;
9454887Schin 	int		n;
9464887Schin 
9474887Schin 	message((-23, "AHA#%d expand(%s)", __LINE__, show(s)));
9484887Schin 	n = sfstrtell(ip);
9494887Schin 	c = 1;
9504887Schin 	while ((!e || s < e) && (c = *s++) && c != '\f');
9514887Schin 	sfwrite(ip, b, s - b - 1);
9524887Schin 	sfputc(ip, 0);
9534887Schin 	b = sfstrbase(ip) + n;
9544887Schin 	message((-23, "AHA#%d expand(%s)", __LINE__, b));
9554887Schin 	n = sfstrtell(ip);
9564887Schin 	if (!c)
9574887Schin 		s--;
9584887Schin 	if (*b == '?')
9594887Schin 	{
9604887Schin 		if (!*++b || streq(b, "NAME"))
9614887Schin 		{
9624887Schin 			if (!(b = error_info.id))
9634887Schin 				b = "command";
9644887Schin 			sfstrseek(ip, 0, SEEK_SET);
9654887Schin 			sfputr(ip, b, -1);
9664887Schin 			n = 0;
9674887Schin 		}
9684887Schin 		else
9694887Schin 			n = 1;
9704887Schin 	}
9714887Schin 	else if (!opt_info.disc || !opt_info.disc->infof || (*opt_info.disc->infof)(&opt_info, ip, b, opt_info.disc) < 0)
9724887Schin 		n = 0;
9734887Schin 	*p = s;
9744887Schin 	if (s = sfstruse(ip))
9754887Schin 		s += n;
9764887Schin 	else
9774887Schin 		s = "error";
9784887Schin 	return s;
9794887Schin }
9804887Schin 
9814887Schin /*
9824887Schin  * push \f...\f info
9834887Schin  */
9844887Schin 
9854887Schin static Push_t*
9864887Schin info(Push_t* psp, char* s, char* e, Sfio_t* ip)
9874887Schin {
9884887Schin 	register char*	b;
9894887Schin 	int		n;
9904887Schin 	Push_t*		tsp;
9914887Schin 
9924887Schin 	static Push_t	push;
9934887Schin 
9944887Schin 	b = expand(s, e, &s, ip);
9954887Schin 	n = strlen(b);
9964887Schin 	if (tsp = newof(0, Push_t, 1, n + 1))
9974887Schin 	{
9984887Schin 		tsp->nb = (char*)(tsp + 1);
9994887Schin 		tsp->ne = tsp->nb + n;
10004887Schin 		strcpy(tsp->nb, b);
10014887Schin 	}
10024887Schin 	else
10034887Schin 		tsp = &push;
10044887Schin 	tsp->next = psp;
10054887Schin 	tsp->ob = s;
10064887Schin 	tsp->oe = e;
10074887Schin 	return tsp;
10084887Schin }
10094887Schin 
10104887Schin /*
10114887Schin  * push translation
10124887Schin  */
10134887Schin 
10144887Schin static Push_t*
10154887Schin localize(Push_t* psp, char* s, char* e, int term, int n, char* catalog, int version, Sfio_t* ip)
10164887Schin {
10174887Schin 	char*		t;
10184887Schin 	char*		u;
10194887Schin 	Push_t*		tsp;
10204887Schin 	int		c;
10214887Schin 
10224887Schin 	t = skip(s, term, 0, 0, n, 0, 0, version);
10234887Schin 	if (e && t > e)
10244887Schin 		t = e;
10254887Schin 	while (s < t)
10264887Schin 	{
10274887Schin 		switch (c = *s++)
10284887Schin 		{
10294887Schin 		case ':':
10304887Schin 		case '?':
10314887Schin 			if (term && *s == c)
10324887Schin 				s++;
10334887Schin 			break;
10344887Schin 		case ']':
10354887Schin 			if (*s == c)
10364887Schin 				s++;
10374887Schin 			break;
10384887Schin 		}
10394887Schin 		sfputc(ip, c);
10404887Schin 	}
10414887Schin 	if (!(s = sfstruse(ip)) || (u = T(error_info.id, catalog, s)) == s)
10424887Schin 		return 0;
10434887Schin 	n = strlen(u);
10444887Schin 	if (tsp = newof(0, Push_t, 1, n + 1))
10454887Schin 	{
10464887Schin 		tsp->nb = (char*)(tsp + 1);
10474887Schin 		tsp->ne = tsp->nb + n;
10484887Schin 		strcpy(tsp->nb, u);
10494887Schin 		tsp->ob = t;
10504887Schin 		tsp->oe = e;
10514887Schin 		tsp->ch = 1;
10524887Schin 	}
10534887Schin 	tsp->next = psp;
10544887Schin 	return tsp;
10554887Schin }
10564887Schin 
10574887Schin /*
10584887Schin  * output label s from [ ...label...[?...] ] to sp
10594887Schin  * 1 returned if the label was translated
10604887Schin  */
10614887Schin 
10624887Schin static int
1063*8462SApril.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)
10644887Schin {
10654887Schin 	register int	c;
10664887Schin 	register char*	t;
10674887Schin 	register char*	e;
10684887Schin 	int		ostyle;
10694887Schin 	int		a;
10704887Schin 	int		i;
10714887Schin 	char*		p;
10724887Schin 	char*		w;
10734887Schin 	char*		y;
10744887Schin 	int		va;
10754887Schin 	Push_t*		tsp;
10764887Schin 
10774887Schin 	int		r = 0;
10784887Schin 	int		n = 1;
10794887Schin 	Push_t*		psp = 0;
10804887Schin 
10814887Schin 	if ((ostyle = style) > (STYLE_nroff - (sep <= 0)) && f != FONT_LITERAL)
10824887Schin 		style = 0;
10834887Schin 	if (z < 0)
10844887Schin 		e = s + strlen(s);
10854887Schin 	else
10864887Schin 		e = s + z;
10874887Schin 	if (sep > 0)
10884887Schin 	{
10894887Schin 		if (sep == ' ' && style == STYLE_nroff)
10904887Schin 			sfputc(sp, '\\');
10914887Schin 		sfputc(sp, sep);
10924887Schin 	}
10934887Schin 	sep = !sep || z < 0;
10944887Schin 	va = 0;
10954887Schin 	y = 0;
1096*8462SApril.Chin@Sun.COM 	if (about)
1097*8462SApril.Chin@Sun.COM 		sfputc(sp, '(');
10984887Schin 	if (version < 1)
10994887Schin 	{
11004887Schin 		a = 0;
11014887Schin 		for (;;)
11024887Schin 		{
11034887Schin 			if (s >= e)
11044887Schin 				return r;
11054887Schin 			switch (c = *s++)
11064887Schin 			{
11074887Schin 			case '[':
11084887Schin 				a++;
11094887Schin 				break;
11104887Schin 			case ']':
11114887Schin 				if (--a < 0)
11124887Schin 					return r;
11134887Schin 				break;
11144887Schin 			}
11154887Schin 			sfputc(sp, c);
11164887Schin 		}
11174887Schin 	}
11184887Schin 	else if (level && (*(p = skip(s, 0, 0, 0, 1, level, 1, version)) == ':' || *p == '#'))
11194887Schin 	{
11204887Schin 		va = 0;
11214887Schin 		if (*++p == '?' || *p == *(p - 1))
11224887Schin 		{
11234887Schin 			p++;
11244887Schin 			va |= OPT_optional;
11254887Schin 		}
11264887Schin 		if (*(p = next(p, version)) == '[')
11274887Schin 			y = p + 1;
11284887Schin 	}
11294887Schin 	if (X(catalog) && (!level || *s == '\a' || *(s - 1) != '+') &&
11304887Schin 	    (tsp = localize(psp, s, e, (sep || level) ? '?' : 0, sep || level, catalog, version, ip)))
11314887Schin 	{
11324887Schin 		psp= tsp;
11334887Schin 		s = psp->nb;
11344887Schin 		e = psp->ne;
11354887Schin 		r = psp->ch > 0;
11364887Schin 	}
11374887Schin 	switch (*s)
11384887Schin 	{
11394887Schin 	case '\a':
11404887Schin 		if (f == FONT_ITALIC)
11414887Schin 			s++;
11424887Schin 		f = 0;
11434887Schin 		break;
11444887Schin 	case '\b':
11454887Schin 		if (f == FONT_BOLD)
11464887Schin 			s++;
11474887Schin 		f = 0;
11484887Schin 		break;
11494887Schin 	case '\v':
11504887Schin 		if (f == FONT_LITERAL)
11514887Schin 			s++;
11524887Schin 		f = 0;
11534887Schin 		break;
11544887Schin 	default:
11554887Schin 		if (f)
11564887Schin 			sfputr(sp, font(f, style, 1), -1);
11574887Schin 		break;
11584887Schin 	}
11594887Schin 	for (;;)
11604887Schin 	{
11614887Schin 		if (s >= e)
11624887Schin 		{
11634887Schin 			if (!(tsp = psp))
11644887Schin 				goto restore;
11654887Schin 			s = psp->ob;
11664887Schin 			e = psp->oe;
11674887Schin 			psp = psp->next;
11684887Schin 			free(tsp);
11694887Schin 			continue;
11704887Schin 		}
11714887Schin 		switch (c = *s++)
11724887Schin 		{
11734887Schin 		case '(':
11744887Schin 			if (n)
11754887Schin 			{
11764887Schin 				n = 0;
11774887Schin 				if (f)
11784887Schin 				{
11794887Schin 					sfputr(sp, font(f, style, 0), -1);
11804887Schin 					f = 0;
11814887Schin 				}
11824887Schin 			}
11834887Schin 			break;
11844887Schin 		case '?':
11854887Schin 		case ':':
11864887Schin 		case ']':
11874887Schin 			if (psp && psp->ch)
11884887Schin 				break;
11894887Schin 			if (y)
11904887Schin 			{
11914887Schin 				if (va & OPT_optional)
11924887Schin 					sfputc(sp, '[');
11934887Schin 				sfputc(sp, '=');
1194*8462SApril.Chin@Sun.COM 				label(sp, 0, y, 0, -1, 0, style, FONT_ITALIC, ip, version, catalog);
11954887Schin 				if (va & OPT_optional)
11964887Schin 					sfputc(sp, ']');
11974887Schin 				y = 0;
11984887Schin 			}
11994887Schin 			switch (c)
12004887Schin 			{
12014887Schin 			case '?':
12024887Schin 				if (*s == '?')
12034887Schin 					s++;
12044887Schin 				else if (*s == ']' && *(s + 1) != ']')
12054887Schin 					continue;
12064887Schin 				else if (sep)
12074887Schin 					goto restore;
12084887Schin 				else if (X(catalog) && (tsp = localize(psp, s, e, 0, 1, catalog, version, ip)))
12094887Schin 				{
12104887Schin 					psp = tsp;
12114887Schin 					s = psp->nb;
12124887Schin 					e = psp->ne;
12134887Schin 				}
12144887Schin 				break;
12154887Schin 			case ']':
12164887Schin 				if (sep && *s++ != ']')
12174887Schin 					goto restore;
12184887Schin 				break;
12194887Schin 			case ':':
12204887Schin 				if (sep && *s++ != ':')
12214887Schin 					goto restore;
12224887Schin 				break;
12234887Schin 			}
12244887Schin 			break;
12254887Schin 		case '\a':
12264887Schin 			a = FONT_ITALIC;
12274887Schin 		setfont:
12284887Schin 			if (f & ~a)
12294887Schin 			{
12304887Schin 				sfputr(sp, font(f, style, 0), -1);
12314887Schin 				f = 0;
12324887Schin 			}
12334887Schin 			if (!f && style == STYLE_html)
12344887Schin 			{
12354887Schin 				for (t = s; t < e && !isspace(*t) && !iscntrl(*t); t++);
12364887Schin 				if (*t == c && *++t == '(')
12374887Schin 				{
12384887Schin 					w = t;
12394887Schin 					while (++t < e && isdigit(*t));
12404887Schin 					if (t < e && *t == ')' && t > w + 1)
12414887Schin 					{
12424887Schin 						sfprintf(sp, "<NOBR><A href=\"../man%-.*s/%-.*s.html\">%s%-.*s%s</A>%-.*s</NOBR>"
12434887Schin 							, t - w - 1, w + 1
12444887Schin 							, w - s - 1, s
12454887Schin 							, font(a, style, 1)
12464887Schin 							, w - s - 1, s
12474887Schin 							, font(a, style, 0)
12484887Schin 							, t - w + 1, w
12494887Schin 							);
12504887Schin 						s = t + 1;
12514887Schin 						continue;
12524887Schin 					}
12534887Schin 				}
12544887Schin 			}
12554887Schin 			sfputr(sp, font(a, style, !!(f ^= a)), -1);
12564887Schin 			continue;
12574887Schin 		case '\b':
12584887Schin 			a = FONT_BOLD;
12594887Schin 			goto setfont;
12604887Schin 		case '\f':
12614887Schin 			psp = info(psp, s, e, ip);
12624887Schin 			if (psp->nb)
12634887Schin 			{
12644887Schin 				s = psp->nb;
12654887Schin 				e = psp->ne;
12664887Schin 			}
12674887Schin 			else
12684887Schin 			{
12694887Schin 				s = psp->ob;
12704887Schin 				psp = psp->next;
12714887Schin 			}
12724887Schin 			continue;
12734887Schin 		case '\n':
12744887Schin 			sfputc(sp, c);
12754887Schin 			for (i = 0; i < level; i++)
12764887Schin 				sfputc(sp, '\t');
12774887Schin 			continue;
12784887Schin 		case '\v':
12794887Schin 			a = FONT_LITERAL;
12804887Schin 			goto setfont;
12814887Schin 		case '<':
12824887Schin 			if (style == STYLE_html)
12834887Schin 			{
12844887Schin 				sfputr(sp, "&lt;", -1);
12854887Schin 				c = 0;
12864887Schin 				for (t = s; t < e; t++)
12874887Schin 					if (!isalnum(*t) && *t != '_' && *t != '.' && *t != '-')
12884887Schin 					{
12894887Schin 						if (*t == '@')
12904887Schin 						{
12914887Schin 							if (c)
12924887Schin 								break;
12934887Schin 							c = 1;
12944887Schin 						}
12954887Schin 						else if (*t == '>')
12964887Schin 						{
12974887Schin 							if (c)
12984887Schin 							{
12994887Schin 								sfprintf(sp, "<A href=\"mailto:%-.*s>%-.*s</A>&gt;", t - s, s, t - s, s);
13004887Schin 								s = t + 1;
13014887Schin 							}
13024887Schin 							break;
13034887Schin 						}
13044887Schin 						else
13054887Schin 							break;
13064887Schin 					}
13074887Schin 				continue;
13084887Schin 			}
13094887Schin 			break;
13104887Schin 		case '>':
13114887Schin 			if (style == STYLE_html)
13124887Schin 			{
13134887Schin 				sfputr(sp, "&gt;", -1);
13144887Schin 				continue;
13154887Schin 			}
13164887Schin 			break;
13174887Schin 		case '&':
13184887Schin 			if (style == STYLE_html)
13194887Schin 			{
13204887Schin 				sfputr(sp, "&amp;", -1);
13214887Schin 				continue;
13224887Schin 			}
13234887Schin 			break;
13244887Schin 		case '-':
13254887Schin 			if (ostyle == STYLE_nroff)
13264887Schin 				sfputc(sp, '\\');
13274887Schin 			break;
13284887Schin 		case '.':
13294887Schin 			if (ostyle == STYLE_nroff)
13304887Schin 			{
13314887Schin 				sfputc(sp, '\\');
13324887Schin 				sfputc(sp, '&');
13334887Schin 			}
13344887Schin 			break;
13354887Schin 		case '\\':
13364887Schin 			if (ostyle == STYLE_nroff)
13374887Schin 			{
13384887Schin 				c = 'e';
13394887Schin 				sfputc(sp, '\\');
13404887Schin 			}
13414887Schin 			break;
13424887Schin 		case ' ':
13434887Schin 			if (ostyle == STYLE_nroff)
13444887Schin 				sfputc(sp, '\\');
13454887Schin 			break;
13464887Schin 		}
13474887Schin 		sfputc(sp, c);
13484887Schin 	}
13494887Schin  restore:
13504887Schin 	if (f)
13514887Schin 		sfputr(sp, font(f, style, 0), -1);
1352*8462SApril.Chin@Sun.COM 	if (about)
1353*8462SApril.Chin@Sun.COM 		sfputc(sp, ')');
13544887Schin 	if (psp)
13554887Schin 		pop(psp);
13564887Schin 	return r;
13574887Schin }
13584887Schin 
13594887Schin /*
13604887Schin  * output args description to sp from p of length n
13614887Schin  */
13624887Schin 
13634887Schin static void
13644887Schin args(register Sfio_t* sp, register char* p, register int n, int flags, int style, Sfio_t* ip, int version, char* catalog)
13654887Schin {
13664887Schin 	register int	i;
13674887Schin 	register char*	t;
13684887Schin 	register char*	o;
13694887Schin 	register char*	a = 0;
13704887Schin 	char*		b;
13714887Schin 	int		sep;
13724887Schin 
13734887Schin 	if (flags & OPT_functions)
13744887Schin 		sep = '\t';
13754887Schin 	else
13764887Schin 	{
13774887Schin 		sep = ' ';
13784887Schin 		o = T(NiL, ID, "options");
13794887Schin 		b = style == STYLE_nroff ? "\\ " : " ";
13804887Schin 		for (;;)
13814887Schin 		{
13824887Schin 			t = (char*)memchr(p, '\n', n);
13834887Schin 			if (style >= STYLE_man)
13844887Schin 			{
13854887Schin 				if (!(a = error_info.id))
13864887Schin 					a = "...";
13874887Schin 				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);
13884887Schin 			}
13894887Schin 			else if (a)
13904887Schin 				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);
13914887Schin 			else
13924887Schin 			{
13934887Schin 				if (!(a = error_info.id))
13944887Schin 					a = "...";
13954887Schin 				if (!sfstrtell(sp))
13964887Schin 					sfprintf(sp, "[%s%s%s]", b, o, b);
13974887Schin 			}
13984887Schin 			if (!t)
13994887Schin 				break;
14004887Schin 			i = ++t - p;
14014887Schin 			if (i)
14024887Schin 			{
14034887Schin 				sfputr(sp, b, -1);
14044887Schin 				if (X(catalog))
14054887Schin 				{
14064887Schin 					sfwrite(ip, p, i);
14074887Schin 					if (b = sfstruse(ip))
14084887Schin 						sfputr(sp, T(error_info.id, catalog, b), -1);
14094887Schin 					else
14104887Schin 						sfwrite(sp, p, i);
14114887Schin 				}
14124887Schin 				else
14134887Schin 					sfwrite(sp, p, i);
14144887Schin 			}
14154887Schin 			if (style == STYLE_html)
14164887Schin 				sfputr(sp, "<BR>", '\n');
14174887Schin 			else if (style == STYLE_nroff)
14184887Schin 				sfputr(sp, ".br", '\n');
14194887Schin 			else if (style == STYLE_api)
14204887Schin 				sfputr(sp, ".BR", '\n');
14214887Schin 			p = t;
14224887Schin 			n -= i;
14234887Schin 			while (n > 0 && (*p == ' ' || *p == '\t'))
14244887Schin 			{
14254887Schin 				p++;
14264887Schin 				n--;
14274887Schin 			}
14284887Schin 		}
14294887Schin 	}
14304887Schin 	if (n)
1431*8462SApril.Chin@Sun.COM 		label(sp, sep, p, 0, n, 0, style, 0, ip, version, catalog);
14324887Schin }
14334887Schin 
14344887Schin /*
14354887Schin  * output [+-...label...?...] label s to sp
14364887Schin  * according to {...} level and style
14374887Schin  * return 0:header 1:paragraph
14384887Schin  */
14394887Schin 
14404887Schin static int
1441*8462SApril.Chin@Sun.COM item(Sfio_t* sp, char* s, int about, int level, int style, Sfio_t* ip, int version, char* catalog)
14424887Schin {
14434887Schin 	register char*	t;
14444887Schin 	int		n;
14454887Schin 	int		par;
14464887Schin 
14474887Schin 	sfputc(sp, '\n');
14484887Schin 	if (*s == '\n')
14494887Schin 	{
14504887Schin 		par = 0;
14514887Schin 		if (style >= STYLE_nroff)
14524887Schin 			sfprintf(sp, ".DS\n");
14534887Schin 		else
14544887Schin 		{
14554887Schin 			if (style == STYLE_html)
14564887Schin 				sfprintf(sp, "<PRE>\n");
14574887Schin 			else
14584887Schin 				sfputc(sp, '\n');
14594887Schin 			for (n = 0; n < level; n++)
14604887Schin 				sfputc(sp, '\t');
14614887Schin 		}
1462*8462SApril.Chin@Sun.COM 		label(sp, 0, s + 1, about, -1, level, style, FONT_LITERAL, ip, version, catalog);
14634887Schin 		sfputc(sp, '\n');
14644887Schin 		if (style >= STYLE_nroff)
14654887Schin 			sfprintf(sp, ".DE");
14664887Schin 		else if (style == STYLE_html)
14674887Schin 			sfprintf(sp, "</PRE>");
14684887Schin 	}
14694887Schin 	else if (*s != ']' && (*s != '?' || *(s + 1) == '?'))
14704887Schin 	{
14714887Schin 		par = 0;
14724887Schin 		if (level)
14734887Schin 		{
14744887Schin 			if (style >= STYLE_nroff)
1475*8462SApril.Chin@Sun.COM 				sfprintf(sp, ".H%d ", (level - (level > 2)) / 2);
14764887Schin 			else
14774887Schin 				for (n = 0; n < level; n++)
14784887Schin 					sfputc(sp, '\t');
14794887Schin 		}
14804887Schin 		if (style == STYLE_html)
14814887Schin 		{
14824887Schin 			if (!level)
14834887Schin 				sfputr(sp, "<H4>", -1);
14844887Schin 			sfputr(sp, "<A name=\"", -1);
14854887Schin 			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] == '?')
14864887Schin 				for (t = s + 8; *t && *t != ']'; t++)
14874887Schin 					if (t[0] == 'p' && (!strncmp(t, "proprietary", 11) || !strncmp(t, "private", 7)) || t[0] == 'n' && !strncmp(t, "noncommercial", 13))
14884887Schin 					{
14894887Schin 						opt_info.state->flags |= OPT_proprietary;
14904887Schin 						break;
14914887Schin 					}
1492*8462SApril.Chin@Sun.COM 			label(sp, 0, s, about, -1, level, 0, 0, ip, version, catalog);
14934887Schin 			sfputr(sp, "\">", -1);
1494*8462SApril.Chin@Sun.COM 			label(sp, 0, s, about, -1, level, style, level ? FONT_BOLD : 0, ip, version, catalog);
14954887Schin 			sfputr(sp, "</A>", -1);
14964887Schin 			if (!level)
14974887Schin 				sfputr(sp, "</H4>", -1);
14984887Schin 		}
14994887Schin 		else
15004887Schin 		{
15014887Schin 			if (!level)
15024887Schin 			{
15034887Schin 				if (style >= STYLE_nroff)
15044887Schin 					sfprintf(sp, ".SH ");
15054887Schin 				else if (style == STYLE_man)
15064887Schin 					sfputc(sp, '\n');
15074887Schin 				else if (style != STYLE_options && style != STYLE_match || *s == '-' || *s == '+')
15084887Schin 					sfputc(sp, '\t');
15094887Schin 			}
1510*8462SApril.Chin@Sun.COM 			label(sp, 0, s, about, -1, level, style, FONT_BOLD, ip, version, catalog);
15114887Schin 		}
15124887Schin 	}
15134887Schin 	else
15144887Schin 	{
15154887Schin 		par = 1;
15164887Schin 		if (style >= STYLE_nroff)
1517*8462SApril.Chin@Sun.COM 			sfputr(sp, level ? ".SP" : ".PP", -1);
15184887Schin 	}
15194887Schin 	if (style >= STYLE_nroff || !level)
15204887Schin 		sfputc(sp, '\n');
15214887Schin 	if (par && style < STYLE_nroff)
15224887Schin 		for (n = 0; n < level; n++)
15234887Schin 			sfputc(sp, '\t');
15244887Schin 	return par;
15254887Schin }
15264887Schin 
15274887Schin /*
15284887Schin  * output text to sp from p according to style
15294887Schin  */
15304887Schin 
15314887Schin static char*
15324887Schin textout(Sfio_t* sp, register char* p, int style, int level, int bump, Sfio_t* ip, int version, char* catalog)
15334887Schin {
15344887Schin #if 0
15354887Schin #define textout(a,b,c,d,e,f,g,h)	(sfprintf(a,"(%d)",__LINE__),textout(a,b,c,d,e,f,g,h))
15364887Schin #endif
15374887Schin 	register char*	t;
15384887Schin 	register int	c;
15394887Schin 	register int	n;
15404887Schin 	char*		e;
15414887Schin 	int		a;
15424887Schin 	int		f;
15434887Schin 	int		par;
1544*8462SApril.Chin@Sun.COM 	int		about;
15454887Schin 	Push_t*		tsp;
15464887Schin 
15474887Schin 	int		ident = 0;
15484887Schin 	int		lev = level;
15494887Schin 	Push_t*		psp = 0;
15504887Schin 
15514887Schin  again:
1552*8462SApril.Chin@Sun.COM 	about = 0;
15534887Schin 	if ((c = *p) == GO)
15544887Schin 	{
15554887Schin 		for (;;)
15564887Schin 		{
15574887Schin 			while (*(p = next(p + 1, version)) == '\n');
15584887Schin 			if (*p == GO)
15594887Schin 			{
15604887Schin 				if (level > 1)
15614887Schin 					level++;
15624887Schin 				level++;
15634887Schin 			}
15644887Schin 			else if (*p != OG)
15654887Schin 			{
1566*8462SApril.Chin@Sun.COM 				if (level <= 1 || *p != '[' || *(p + 1) != '-' || style == STYLE_man && *(p + 2) == '?' || isalpha(*(p + 2)))
15674887Schin 					break;
15684887Schin 				p = skip(p, 0, 0, 0, 1, level, 0, version);
15694887Schin 			}
15704887Schin 			else if ((level -= 2) <= lev)
15714887Schin 				return p + 1;
15724887Schin 		}
15734887Schin 		if (*p == '\f')
15744887Schin 		{
15754887Schin 			psp = info(psp, p + 1, NiL, ip);
15764887Schin 			if (psp->nb)
15774887Schin 				p = psp->nb;
15784887Schin 			else
15794887Schin 			{
15804887Schin 				p = psp->ob;
15814887Schin 				psp = psp->next;
15824887Schin 			}
15834887Schin 		}
15844887Schin 		if (*p != '[')
15854887Schin 			return p;
15864887Schin 		c = *++p;
15874887Schin 		if (level > 1)
15884887Schin 			level++;
15894887Schin 		level++;
15904887Schin 	}
15914887Schin 	if (c == '-' && level > 1)
1592*8462SApril.Chin@Sun.COM 	{
1593*8462SApril.Chin@Sun.COM 		if (style == STYLE_man)
1594*8462SApril.Chin@Sun.COM 		{
1595*8462SApril.Chin@Sun.COM 			about = 1;
1596*8462SApril.Chin@Sun.COM 			if (*(p + 1) == '-')
1597*8462SApril.Chin@Sun.COM 				p++;
1598*8462SApril.Chin@Sun.COM 		}
1599*8462SApril.Chin@Sun.COM 		else
1600*8462SApril.Chin@Sun.COM 			for (;;)
1601*8462SApril.Chin@Sun.COM 			{
1602*8462SApril.Chin@Sun.COM 				p = skip(p, 0, 0, 0, 1, level, 0, version);
1603*8462SApril.Chin@Sun.COM 				while (*(p = next(p + 1, version)) == '\n');
1604*8462SApril.Chin@Sun.COM 				if (*p == '[')
1605*8462SApril.Chin@Sun.COM 				{
1606*8462SApril.Chin@Sun.COM 					if ((c = *++p) != '-')
1607*8462SApril.Chin@Sun.COM 						break;
1608*8462SApril.Chin@Sun.COM 				}
1609*8462SApril.Chin@Sun.COM 				else if (*p == GO)
1610*8462SApril.Chin@Sun.COM 					goto again;
1611*8462SApril.Chin@Sun.COM 				else if (*p == OG)
1612*8462SApril.Chin@Sun.COM 					return p + 1;
1613*8462SApril.Chin@Sun.COM 			}
1614*8462SApril.Chin@Sun.COM 	}
16154887Schin 	if (c == '+' || c == '-' && (bump = 3) || c != ' ' && level > 1)
16164887Schin 	{
16174887Schin 		p = skip(t = p + 1, '?', 0, 0, 1, level, 0, version);
1618*8462SApril.Chin@Sun.COM 		if (c == '-' && (*t == '?' || isdigit(*t) || *p == '?' && *(p + 1) == '\n'))
16194887Schin 		{
16204887Schin 			if ((c = *p) != '?')
16214887Schin 				return skip(p, 0, 0, 0, 1, level, 1, version);
1622*8462SApril.Chin@Sun.COM 			e = C("version");
1623*8462SApril.Chin@Sun.COM 			par = item(sp, e, about, level, style, ip, version, ID);
16244887Schin 			for (;;)
16254887Schin 			{
16264887Schin 				while (isspace(*(p + 1)))
16274887Schin 					p++;
16284887Schin 				e = p;
16294887Schin 				if (e[1] == '@' && e[2] == '(' && e[3] == '#' && e[4] == ')')
16304887Schin 					p = e + 4;
16314887Schin 				else if (e[1] == '$' && e[2] == 'I' && e[3] == 'd' && e[4] == ':' && e[5] == ' ')
16324887Schin 				{
16334887Schin 					p = e + 5;
16344887Schin 					ident = 1;
16354887Schin 				}
16364887Schin 				else
16374887Schin 					break;
16384887Schin 			}
16394887Schin 		}
16404887Schin 		else
16414887Schin 		{
16424887Schin 			if (isdigit(c) && isdigit(*t))
16434887Schin 			{
16444887Schin 				while (isdigit(*t))
16454887Schin 					t++;
16464887Schin 				if (*t == ':')
16474887Schin 					t++;
16484887Schin 			}
16494887Schin 			else if (isalnum(c) && *t-- == ':')
16504887Schin 			{
16514887Schin 				if (X(catalog) || *t == *(t + 2))
16524887Schin 					t += 2;
16534887Schin 				else
16544887Schin 				{
16554887Schin 					sfprintf(ip, "%s", t);
16564887Schin 					if (e = sfstruse(ip))
16574887Schin 						*((t = e) + 1) = '|';
16584887Schin 				}
16594887Schin 			}
1660*8462SApril.Chin@Sun.COM 			par = item(sp, t, about, level, style, ip, version, catalog);
16614887Schin 			c = *p;
16624887Schin 		}
1663*8462SApril.Chin@Sun.COM 		if (!about && level)
16644887Schin 			par = 0;
16654887Schin 	}
16664887Schin 	else
16674887Schin 	{
16684887Schin 		if (style >= STYLE_nroff)
16694887Schin 			sfputc(sp, '\n');
16704887Schin 		else if (c == '?')
16714887Schin 			for (n = 0; n < level; n++)
16724887Schin 				sfputc(sp, '\t');
16734887Schin 		par = 0;
16744887Schin 	}
16754887Schin 	if (c == ':')
16764887Schin 		c = *(p = skip(p, '?', 0, 0, 1, 0, 0, version));
16774887Schin 	if ((c == ']' || c == '?' && *(p + 1) == ']' && *(p + 2) != ']' && p++) && (c = *(p = next(p + 1, version))) == GO)
16784887Schin 		p = textout(sp, p, style, level + bump + par + 1, 0, ip, version, catalog);
16794887Schin 	else if (c == '?' || c == ' ')
16804887Schin 	{
16814887Schin 		p++;
16824887Schin 		if (c == ' ')
16834887Schin 			sfputc(sp, c);
16844887Schin 		else
16854887Schin 		{
16864887Schin 			if (X(catalog) && (tsp = localize(psp, p, NiL, 0, 1, catalog, version, ip)))
16874887Schin 			{
16884887Schin 				psp = tsp;
16894887Schin 				p = psp->nb;
16904887Schin 			}
16914887Schin 			if (style < STYLE_nroff)
16924887Schin 				for (n = 0; n < bump + 1; n++)
16934887Schin 					sfputc(sp, '\t');
16944887Schin 		}
16954887Schin 		f = 0;
16964887Schin 		for (;;)
16974887Schin 		{
16984887Schin 			switch (c = *p++)
16994887Schin 			{
17004887Schin 			case 0:
17014887Schin 				if (!(tsp = psp))
17024887Schin 				{
17034887Schin 					if (f)
17044887Schin 						sfputr(sp, font(f, style, 0), -1);
17054887Schin 					return p - 1;
17064887Schin 				}
17074887Schin 				p = psp->ob;
17084887Schin 				psp = psp->next;
17094887Schin 				free(tsp);
17104887Schin 				continue;
17114887Schin 			case ']':
17124887Schin 				if (psp && psp->ch)
17134887Schin 					break;
17144887Schin 				if (*p != ']')
17154887Schin 				{
17164887Schin 					if (f)
17174887Schin 					{
17184887Schin 						sfputr(sp, font(f, style, 0), -1);
17194887Schin 						f = 0;
17204887Schin 					}
17214887Schin 					for (;;)
17224887Schin 					{
17234887Schin 						if ((*p == '#' || *p == ':') && level > lev)
17244887Schin 						{
17254887Schin 							char*	o;
17264887Schin 							char*	v;
17274887Schin 							int	j;
17284887Schin 							int	m;
17294887Schin 							int	ol;
17304887Schin 							int	vl;
17314887Schin 
17324887Schin 							a = 0;
17334887Schin 							o = 0;
17344887Schin 							v = 0;
17354887Schin 							if (*++p == '?' || *p == *(p - 1))
17364887Schin 							{
17374887Schin 								p++;
17384887Schin 								a |= OPT_optional;
17394887Schin 							}
17404887Schin 							if (*(p = next(p, version)) == '[')
17414887Schin 							{
17424887Schin 								p = skip(p + 1, ':', '?', 0, 1, 0, 0, version);
17434887Schin 								while (*p == ':')
17444887Schin 								{
17454887Schin 									p = skip(t = p + 1, ':', '?', 0, 1, 0, 0, version);
17464887Schin 									m = p - t;
17474887Schin 									if (*t == '!')
17484887Schin 									{
17494887Schin 										o = t + 1;
17504887Schin 										ol = m - 1;
17514887Schin 									}
17524887Schin 									else if (*t == '=')
17534887Schin 									{
17544887Schin 										v = t + 1;
17554887Schin 										vl = m - 1;
17564887Schin 									}
17574887Schin 									else
17584887Schin 										for (j = 0; j < elementsof(attrs); j++)
17594887Schin 											if (strneq(t, attrs[j].name, m))
17604887Schin 											{
17614887Schin 												a |= attrs[j].flag;
17624887Schin 												break;
17634887Schin 											}
17644887Schin 								}
17654887Schin 							}
17664887Schin 							if (a & OPT_optional)
17674887Schin 							{
17684887Schin 								if (o)
17694887Schin 								{
17704887Schin 									sfprintf(sp, " %s ", T(NiL, ID, "If the option value is omitted then"));
17714887Schin 									sfputr(sp, font(FONT_BOLD, style, 1), -1);
17724887Schin 									t = o + ol;
17734887Schin 									while (o < t)
17744887Schin 									{
17754887Schin 										if (((c = *o++) == ':' || c == '?') && *o == c)
17764887Schin 											o++;
17774887Schin 										sfputc(sp, c);
17784887Schin 									}
17794887Schin 									sfputr(sp, font(FONT_BOLD, style, 0), -1);
17804887Schin 									sfprintf(sp, " %s.", T(NiL, ID, "is assumed"));
17814887Schin 								}
17824887Schin 								else
17834887Schin 									sfprintf(sp, " %s", T(NiL, ID, "The option value may be omitted."));
17844887Schin 							}
17854887Schin 							if (v)
17864887Schin 							{
17874887Schin 								sfprintf(sp, " %s ", T(NiL, ID, "The default value is"));
17884887Schin 								sfputr(sp, font(FONT_BOLD, style, 1), -1);
17894887Schin 								t = v + vl;
17904887Schin 								while (v < t)
17914887Schin 								{
17924887Schin 									if (((c = *v++) == ':' || c == '?') && *v == c)
17934887Schin 										v++;
17944887Schin 									sfputc(sp, c);
17954887Schin 								}
17964887Schin 								sfputr(sp, font(FONT_BOLD, style, 0), -1);
17974887Schin 								sfputc(sp, '.');
17984887Schin 							}
17994887Schin 							p = skip(p, 0, 0, 0, 1, 0, 1, version);
18004887Schin 						}
18014887Schin 						if (*(p = next(p, version)) == GO)
18024887Schin 							p = textout(sp, p, style, level + bump + !level, 0, ip, version, catalog);
18034887Schin 						else if (*p == '[' && level > lev)
18044887Schin 						{
18054887Schin 							p++;
18064887Schin 							goto again;
18074887Schin 						}
18084887Schin 						else if (*p == '\f')
18094887Schin 						{
18104887Schin 							p++;
18114887Schin 							if (style != STYLE_keys)
18124887Schin 							{
18134887Schin 								psp = info(psp, p, NiL, ip);
18144887Schin 								if (psp->nb)
18154887Schin 									p = psp->nb;
18164887Schin 								else
18174887Schin 								{
18184887Schin 									p = psp->ob;
18194887Schin 									psp = psp->next;
18204887Schin 								}
18214887Schin 							}
18224887Schin 						}
18234887Schin 						else if (!*p)
18244887Schin 						{
18254887Schin 							if (!(tsp = psp))
18264887Schin 								break;
18274887Schin 							p = psp->ob;
18284887Schin 							psp = psp->next;
18294887Schin 							free(tsp);
18304887Schin 						}
18314887Schin 						else if (*p != OG)
18324887Schin 							break;
18334887Schin 						else
18344887Schin 						{
18354887Schin 							p++;
18364887Schin 							if ((level -= 2) <= lev)
18374887Schin 								break;
18384887Schin 						}
18394887Schin 					}
18404887Schin 					return p;
18414887Schin 				}
18424887Schin 				p++;
18434887Schin 				break;
18444887Schin 			case '\a':
18454887Schin 				a = FONT_ITALIC;
18464887Schin 			setfont:
18474887Schin 				if (f & ~a)
18484887Schin 				{
18494887Schin 					sfputr(sp, font(f, style, 0), -1);
18504887Schin 					f = 0;
18514887Schin 				}
18524887Schin 				if (!f && style == STYLE_html)
18534887Schin 				{
18544887Schin 					for (t = p; *t && !isspace(*t) && !iscntrl(*t); t++);
18554887Schin 					if (*t == c && *++t == '(')
18564887Schin 					{
18574887Schin 						e = t;
18584887Schin 						while (isdigit(*++t));
18594887Schin 						if (*t == ')' && t > e + 1)
18604887Schin 						{
18614887Schin 							sfprintf(sp, "<NOBR><A href=\"../man%-.*s/%-.*s.html\">%s%-.*s%s</A>%-.*s</NOBR>"
18624887Schin 								, t - e - 1, e + 1
18634887Schin 								, e - p - 1, p
18644887Schin 								, font(a, style, 1)
18654887Schin 								, e - p - 1, p
18664887Schin 								, font(a, style, 0)
18674887Schin 								, t - e + 1, e
18684887Schin 								);
18694887Schin 							p = t + 1;
18704887Schin 							continue;
18714887Schin 						}
18724887Schin 					}
18734887Schin 				}
18744887Schin 				sfputr(sp, font(a, style, !!(f ^= a)), -1);
18754887Schin 				continue;
18764887Schin 			case '\b':
18774887Schin 				a = FONT_BOLD;
18784887Schin 				goto setfont;
18794887Schin 			case '\f':
18804887Schin 				if (style != STYLE_keys)
18814887Schin 				{
18824887Schin 					psp = info(psp, p, NiL, ip);
18834887Schin 					if (psp->nb)
18844887Schin 						p = psp->nb;
18854887Schin 					else
18864887Schin 					{
18874887Schin 						p = psp->ob;
18884887Schin 						psp = psp->next;
18894887Schin 					}
18904887Schin 				}
18914887Schin 				continue;
18924887Schin 			case '\v':
18934887Schin 				a = FONT_LITERAL;
18944887Schin 				goto setfont;
18954887Schin 			case ' ':
18964887Schin 				if (ident && *p == '$')
18974887Schin 				{
18984887Schin 					while (*++p)
18994887Schin 						if (*p == ']')
19004887Schin 						{
19014887Schin 							if (*(p + 1) != ']')
19024887Schin 								break;
19034887Schin 							p++;
19044887Schin 						}
19054887Schin 					continue;
19064887Schin 				}
19074887Schin 			case '\n':
19084887Schin 			case '\r':
19094887Schin 			case '\t':
19104887Schin 				while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
19114887Schin 					p++;
19124887Schin 				if (*p == ']' && *(p + 1) != ']' && (!psp || !psp->ch))
19134887Schin 					continue;
19144887Schin 				c = ' ';
19154887Schin 				break;
19164887Schin 			case '<':
19174887Schin 				if (style == STYLE_html)
19184887Schin 				{
19194887Schin 					sfputr(sp, "&lt;", -1);
19204887Schin 					c = 0;
19214887Schin 					for (t = p; *t; t++)
19224887Schin 						if (!isalnum(*t) && *t != '_' && *t != '.' && *t != '-')
19234887Schin 						{
19244887Schin 							if (*t == '@')
19254887Schin 							{
19264887Schin 								if (c)
19274887Schin 									break;
19284887Schin 								c = 1;
19294887Schin 							}
19304887Schin 							else if (*t == '>')
19314887Schin 							{
19324887Schin 								if (c)
19334887Schin 								{
19344887Schin 									sfprintf(sp, "<A href=\"mailto:%-.*s\">%-.*s</A>&gt;", t - p, p, t - p, p);
19354887Schin 									p = t + 1;
19364887Schin 								}
19374887Schin 								break;
19384887Schin 							}
19394887Schin 							else
19404887Schin 								break;
19414887Schin 						}
19424887Schin 					continue;
19434887Schin 				}
19444887Schin 				break;
19454887Schin 			case '>':
19464887Schin 				if (style == STYLE_html)
19474887Schin 				{
19484887Schin 					sfputr(sp, "&gt;", -1);
19494887Schin 					continue;
19504887Schin 				}
19514887Schin 				break;
19524887Schin 			case '&':
19534887Schin 				if (style == STYLE_html)
19544887Schin 				{
19554887Schin 					sfputr(sp, "&amp;", -1);
19564887Schin 					continue;
19574887Schin 				}
19584887Schin 				break;
19594887Schin 			case '-':
19604887Schin 				if (style == STYLE_nroff)
19614887Schin 					sfputc(sp, '\\');
19624887Schin 				break;
19634887Schin 			case '.':
19644887Schin 				if (style == STYLE_nroff)
19654887Schin 				{
19664887Schin 					sfputc(sp, '\\');
19674887Schin 					sfputc(sp, '&');
19684887Schin 				}
19694887Schin 				break;
19704887Schin 			case '\\':
19714887Schin 				if (style == STYLE_nroff)
19724887Schin 				{
19734887Schin 					sfputc(sp, c);
19744887Schin 					c = 'e';
19754887Schin 				}
19764887Schin 				break;
19774887Schin 			}
19784887Schin 			sfputc(sp, c);
19794887Schin 		}
19804887Schin 	}
19814887Schin 	else if (c == '[' && level > lev)
19824887Schin 	{
19834887Schin 		p++;
19844887Schin 		goto again;
19854887Schin 	}
19864887Schin 	return p;
19874887Schin }
19884887Schin 
19894887Schin /*
19904887Schin  * generate optget() help [...] list from lp
19914887Schin  */
19924887Schin 
19934887Schin static void
19944887Schin list(Sfio_t* sp, register const List_t* lp)
19954887Schin {
19964887Schin 	sfprintf(sp, "[%c", lp->type);
19974887Schin 	if (lp->name)
19984887Schin 	{
19994887Schin 		sfprintf(sp, "%s", lp->name);
20004887Schin 		if (lp->text)
20014887Schin 			sfprintf(sp, "?%s", lp->text);
20024887Schin 	}
20034887Schin 	sfputc(sp, ']');
20044887Schin }
20054887Schin 
20064887Schin /*
20074887Schin  * return pointer to help message sans `Usage: command'
20084887Schin  * if oopts is 0 then opt_info.state->pass is used
20094887Schin  * what:
20104887Schin  *	0	?short by default, ?long if any long options used
20114887Schin  *	*	otherwise see help_text[] (--???)
20124887Schin  * external formatter:
20134887Schin  *	\a...\a	italic
20144887Schin  *	\b...\b	bold
20154887Schin  *	\f...\f	discipline infof callback on ...
20164887Schin  *	\v...\v	literal
20174887Schin  * internal formatter:
20184887Schin  *	\t	indent
20194887Schin  *	\n	newline
20204887Schin  * margin flush pops to previous indent
20214887Schin  */
20224887Schin 
20234887Schin char*
20244887Schin opthelp(const char* oopts, const char* what)
20254887Schin {
20264887Schin 	register Sfio_t*	sp;
20274887Schin 	register Sfio_t*	mp;
20284887Schin 	register int		c;
20294887Schin 	register char*		p;
20304887Schin 	register Indent_t*	ip;
20314887Schin 	char*			t;
20324887Schin 	char*			x;
20334887Schin 	char*			w;
20344887Schin 	char*			u;
20354887Schin 	char*			y;
20364887Schin 	char*			s;
20374887Schin 	char*			d;
20384887Schin 	char*			v;
20394887Schin 	char*			ov;
20404887Schin 	char*			name;
20414887Schin 	char*			pp;
20424887Schin 	char*			rb;
20434887Schin 	char*			re;
20444887Schin 	int			f;
20454887Schin 	int			i;
20464887Schin 	int			j;
20474887Schin 	int			m;
20484887Schin 	int			n;
20494887Schin 	int			a;
20504887Schin 	int			sl;
20514887Schin 	int			vl;
20524887Schin 	int			ol;
20534887Schin 	int			wl;
20544887Schin 	int			xl;
20554887Schin 	int			rm;
20564887Schin 	int			ts;
20574887Schin 	int			co;
20584887Schin 	int			z;
20594887Schin 	int			style;
20604887Schin 	int			head;
2061*8462SApril.Chin@Sun.COM 	int			margin;
20624887Schin 	int			mode;
20634887Schin 	int			mutex;
20644887Schin 	int			prefix;
20654887Schin 	int			version;
20664887Schin 	long			tp;
20674887Schin 	char*			catalog;
20684887Schin 	Optpass_t*		o;
20694887Schin 	Optpass_t*		q;
20704887Schin 	Optpass_t*		e;
20714887Schin 	Optpass_t		one;
20724887Schin 	Help_t*			hp;
20734887Schin 	short			ptstk[elementsof(indent) + 2];
20744887Schin 	short*			pt;
20754887Schin 	Sfio_t*			vp;
20764887Schin 	Push_t*			tsp;
20774887Schin 
20784887Schin 	char*			opts = (char*)oopts;
20794887Schin 	int			flags = 0;
20804887Schin 	int			matched = 0;
20814887Schin 	int			paragraph = 0;
20824887Schin 	int			section = 1;
20834887Schin 	Push_t*			psp = 0;
20844887Schin 	Sfio_t*			sp_help = 0;
20854887Schin 	Sfio_t*			sp_text = 0;
20864887Schin 	Sfio_t*			sp_plus = 0;
20874887Schin 	Sfio_t*			sp_head = 0;
20884887Schin 	Sfio_t*			sp_body = 0;
20894887Schin 	Sfio_t*			sp_info = 0;
20904887Schin 	Sfio_t*			sp_misc = 0;
20914887Schin 
20924887Schin 	if (!(mp = opt_info.state->mp) && !(mp = opt_info.state->mp = sfstropen()))
20934887Schin 		goto nospace;
20944887Schin 	if (!what)
20954887Schin 		style = opt_info.state->style;
20964887Schin 	else if (!*what)
20974887Schin 		style = STYLE_options;
20984887Schin 	else if (*what != '?')
20994887Schin 		style = STYLE_match;
21004887Schin 	else if (!*(what + 1))
21014887Schin 		style = STYLE_man;
21024887Schin 	else if ((hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), (char*)what + 1)) && hp->style >= 0)
21034887Schin 	{
21044887Schin 		style = hp->style;
21054887Schin 		if (*hp->name != '?')
21064887Schin 			what = hp->name;
21074887Schin 	}
21084887Schin 	else
21094887Schin 	{
21104887Schin 		if ((style = opt_info.state->force) < STYLE_man)
21114887Schin 			style = STYLE_man;
21124887Schin 		if (!(sp_help = sfstropen()))
21134887Schin 			goto nospace;
21144887Schin 		for (i = 0; i < elementsof(help_head); i++)
21154887Schin 			list(sp_help, &help_head[i]);
21164887Schin 		for (i = 0; i < elementsof(styles); i++)
21174887Schin 			sfprintf(sp_help, "[:%s?%s]", styles[i].match, styles[i].text);
21184887Schin 		for (i = 0; i < elementsof(help_tail); i++)
21194887Schin 			list(sp_help, &help_tail[i]);
21204887Schin 		if (!(opts = sfstruse(sp_help)))
21214887Schin 			goto nospace;
21224887Schin 	}
21234887Schin 	message((-20, "AHA#%d style=%d", __LINE__, style));
21244887Schin  again:
21254887Schin 	if (opts)
21264887Schin 	{
21274887Schin 		for (i = 0; i < opt_info.state->npass; i++)
21284887Schin 			if (opt_info.state->pass[i].oopts == opts)
21294887Schin 			{
21304887Schin 				o = &opt_info.state->pass[i];
21314887Schin 				break;
21324887Schin 			}
21334887Schin 		if (i >= opt_info.state->npass)
21344887Schin 		{
21354887Schin 			o = &one;
21364887Schin 			if (init((char*)opts, o))
21374887Schin 				goto nospace;
21384887Schin 		}
21394887Schin 		e = o + 1;
21404887Schin 	}
21414887Schin 	else if (opt_info.state->npass > 0)
21424887Schin 	{
21434887Schin 		o = opt_info.state->pass;
21444887Schin 		e = o + opt_info.state->npass;
21454887Schin 	}
21464887Schin 	else if (opt_info.state->npass < 0)
21474887Schin 	{
21484887Schin 		o = &opt_info.state->cache->pass;
21494887Schin 		e = o + 1;
21504887Schin 	}
21514887Schin 	else
21524887Schin 		return T(NiL, ID, "[* call optget() before opthelp() *]");
21534887Schin 	if (style < STYLE_usage)
21544887Schin 	{
21554887Schin 		if (!(sp_text = sfstropen()) || !(sp_info = sfstropen()))
21564887Schin 			goto nospace;
21574887Schin 		if (style >= STYLE_match && style < STYLE_keys && !(sp_body = sfstropen()))
21584887Schin 			goto nospace;
21594887Schin 	}
21604887Schin 	switch (style)
21614887Schin 	{
21624887Schin 	case STYLE_api:
21634887Schin 	case STYLE_html:
21644887Schin 	case STYLE_nroff:
21654887Schin 		opt_info.state->emphasis = 0;
21664887Schin 		break;
21674887Schin 	case STYLE_usage:
21684887Schin 	case STYLE_keys:
21694887Schin 		for (q = o; q < e; q++)
21704887Schin 			if (!(q->flags & OPT_ignore) && !streq(q->catalog, o->catalog))
21714887Schin 				o = q;
21724887Schin 		/*FALLTHROUGH*/
21734887Schin 	case STYLE_posix:
21744887Schin 		sfputc(mp, '\f');
21754887Schin 		break;
21764887Schin 	default:
21774887Schin 		if (!opt_info.state->emphasis)
21784887Schin 		{
21794887Schin 			if (x = getenv("ERROR_OPTIONS"))
21804887Schin 			{
21814887Schin 				if (strmatch(x, "*noemphasi*"))
21824887Schin 					break;
21834887Schin 				if (strmatch(x, "*emphasi*"))
21844887Schin 				{
21854887Schin 					opt_info.state->emphasis = 1;
21864887Schin 					break;
21874887Schin 				}
21884887Schin 			}
21894887Schin 			if ((x = getenv("TERM")) && strmatch(x, "(ansi|vt100|xterm)*") && isatty(sffileno(sfstderr)))
21904887Schin 				opt_info.state->emphasis = 1;
21914887Schin 		}
21924887Schin 		break;
21934887Schin 	}
21944887Schin 	x = "";
21954887Schin 	xl = 0;
21964887Schin 	for (q = o; q < e; q++)
21974887Schin 	{
21984887Schin 		if (q->flags & OPT_ignore)
21994887Schin 			continue;
22004887Schin 		if (section < q->section)
22014887Schin 			section = q->section;
22024887Schin 		section = q->section;
22034887Schin 		flags |= q->flags;
22044887Schin 		p = q->opts;
22054887Schin 		prefix = q->prefix;
22064887Schin 		version = q->version;
22074887Schin 		catalog = q->catalog;
22084887Schin 		switch (style)
22094887Schin 		{
22104887Schin 		case STYLE_usage:
22114887Schin 			if (xl)
22124887Schin 				sfputc(mp, '\n');
22134887Schin 			else
22144887Schin 				xl = 1;
22154887Schin 			while (c = *p++)
22164887Schin 			{
22174887Schin 				switch (c)
22184887Schin 				{
22194887Schin 				case '\a':
22204887Schin 					c = 'a';
22214887Schin 					break;
22224887Schin 				case '\b':
22234887Schin 					c = 'b';
22244887Schin 					break;
22254887Schin 				case '\f':
22264887Schin 					c = 'f';
22274887Schin 					break;
22284887Schin 				case '\n':
22294887Schin 					c = 'n';
22304887Schin 					break;
22314887Schin 				case '\r':
22324887Schin 					c = 'r';
22334887Schin 					break;
22344887Schin 				case '\t':
22354887Schin 					c = 't';
22364887Schin 					break;
22374887Schin 				case '\v':
22384887Schin 					c = 'v';
22394887Schin 					break;
22404887Schin 				case '"':
22414887Schin 					c = '"';
22424887Schin 					break;
22434887Schin 				case '\'':
22444887Schin 					c = '\'';
22454887Schin 					break;
22464887Schin 				case '\\':
22474887Schin 					c = '\\';
22484887Schin 					break;
22494887Schin 				default:
22504887Schin 					sfputc(mp, c);
22514887Schin 					continue;
22524887Schin 				}
22534887Schin 				sfputc(mp, '\\');
22544887Schin 				sfputc(mp, c);
22554887Schin 			}
22564887Schin 			continue;
22574887Schin 		case STYLE_keys:
22584887Schin 			a = 0;
22594887Schin 			psp = 0;
22604887Schin 			vl = 0;
22614887Schin 			for (;;)
22624887Schin 			{
22634887Schin 				if (!(c = *p++))
22644887Schin 				{
22654887Schin 					if (!(tsp = psp))
22664887Schin 						break;
22674887Schin 					p = psp->ob;
22684887Schin 					psp = psp->next;
22694887Schin 					free(tsp);
22704887Schin 					continue;
22714887Schin 				}
22724887Schin 				if (c == '\f')
22734887Schin 				{
22744887Schin 					psp = info(psp, p, NiL, sp_info);
22754887Schin 					if (psp->nb)
22764887Schin 						p = psp->nb;
22774887Schin 					else
22784887Schin 					{
22794887Schin 						p = psp->ob;
22804887Schin 						psp = psp->next;
22814887Schin 					}
22824887Schin 					continue;
22834887Schin 				}
22844887Schin 				f = z = 1;
22854887Schin 				t = 0;
22864887Schin 				if (a == 0 && (c == ' ' || c == '\n' && *p == '\n'))
22874887Schin 				{
22884887Schin 					if (c == ' ' && *p == ']')
22894887Schin 					{
22904887Schin 						p++;
22914887Schin 						continue;
22924887Schin 					}
22934887Schin 					if (*p == '\n')
22944887Schin 						p++;
22954887Schin 					a = c;
22964887Schin 				}
22974887Schin 				else if (c == '\n')
22984887Schin 				{
22994887Schin 					if (a == ' ')
23004887Schin 						a = -1;
23014887Schin 					else if (a == '\n' || *p == '\n')
23024887Schin 					{
23034887Schin 						a = -1;
23044887Schin 						p++;
23054887Schin 					}
23064887Schin 					continue;
23074887Schin 				}
23084887Schin 				else if ((c == ':' || c == '#') && (*p == '[' || *p == '?' && *(p + 1) == '[' && p++))
23094887Schin 					p++;
23104887Schin 				else if (c != '[')
23114887Schin 				{
2312*8462SApril.Chin@Sun.COM 					if (c == GO)
23134887Schin 						vl++;
2314*8462SApril.Chin@Sun.COM 					else if (c == OG)
23154887Schin 						vl--;
23164887Schin 					continue;
23174887Schin 				}
23184887Schin 				else if (*p == ' ')
23194887Schin 				{
23204887Schin 					p++;
23214887Schin 					continue;
23224887Schin 				}
23234887Schin 				else if (*p == '-')
23244887Schin 				{
23254887Schin 					z = 0;
23264887Schin 					if (*++p == '-')
23274887Schin 					{
23284887Schin 						p = skip(p, 0, 0, 0, 1, 0, 1, version);
23294887Schin 						continue;
23304887Schin 					}
23314887Schin 				}
23324887Schin 				else if (*p == '+')
23334887Schin 				{
23344887Schin 					p++;
23354887Schin 					if (vl > 0 && *p != '\a')
23364887Schin 					{
23374887Schin 						f = 0;
23384887Schin 						p = skip(p, '?', 0, 0, 1, 0, 0, version);
23394887Schin 						if (*p == '?')
23404887Schin 							p++;
23414887Schin 					}
23424887Schin 				}
23434887Schin 				else
23444887Schin 				{
23454887Schin 					if (*(p + 1) == '\f' && (vp = opt_info.state->vp))
23464887Schin 						p = expand(p + 2, NiL, &t, vp);
23474887Schin 					p = skip(p, ':', '?', 0, 1, 0, 0, version);
23484887Schin 					if (*p == ':')
23494887Schin 						p++;
23504887Schin 				}
23514887Schin 				if (f && *p == '?' && *(p + 1) != '?')
23524887Schin 				{
23534887Schin 					f = 0;
23544887Schin 					if (z)
23554887Schin 						p++;
23564887Schin 					else
23574887Schin 						p = skip(p, 0, 0, 0, 1, 0, 0, version);
23584887Schin 				}
23594887Schin 				if (*p == ']' && *(p + 1) != ']')
23604887Schin 				{
23614887Schin 					p++;
23624887Schin 					continue;
23634887Schin 				}
23644887Schin 				if (!*p)
23654887Schin 				{
23664887Schin 					if (!t)
23674887Schin 						break;
23684887Schin 					p = t;
23694887Schin 					t = 0;
23704887Schin 				}
23714887Schin 				m = sfstrtell(mp);
23724887Schin 				sfputc(mp, '"');
23734887Schin 				xl = 1;
23744887Schin 				/*UNDENT...*/
23754887Schin 
23764887Schin 	for (;;)
23774887Schin 	{
23784887Schin 		if (!(c = *p++))
23794887Schin 		{
23804887Schin 			if (t)
23814887Schin 			{
23824887Schin 				p = t;
23834887Schin 				t = 0;
23844887Schin 			}
23854887Schin 			if (!(tsp = psp))
23864887Schin 			{
23874887Schin 				p--;
23884887Schin 				break;
23894887Schin 			}
23904887Schin 			p = psp->ob;
23914887Schin 			psp = psp->next;
23924887Schin 			free(tsp);
23934887Schin 			continue;
23944887Schin 		}
23954887Schin 		if (a > 0)
23964887Schin 		{
23974887Schin 			if (c == '\n')
23984887Schin 			{
23994887Schin 				if (a == ' ')
24004887Schin 				{
24014887Schin 					a = -1;
24024887Schin 					break;
24034887Schin 				}
24044887Schin 				if (a == '\n' || *p == '\n')
24054887Schin 				{
24064887Schin 					a = -1;
24074887Schin 					p++;
24084887Schin 					break;
24094887Schin 				}
24104887Schin 			}
24114887Schin 		}
24124887Schin 		else if (c == ']')
24134887Schin 		{
24144887Schin 			if (*p != ']')
24154887Schin 			{
24164887Schin 				sfputc(mp, 0);
24174887Schin 				y = sfstrbase(mp) + m + 1;
24184887Schin 				if (D(y) || !strmatch(y, KEEP) || strmatch(y, OMIT))
24194887Schin 				{
24204887Schin 					sfstrseek(mp, m, SEEK_SET);
24214887Schin 					xl = 0;
24224887Schin 				}
24234887Schin 				else
24244887Schin 					sfstrseek(mp, -1, SEEK_CUR);
24254887Schin 				break;
24264887Schin 			}
24274887Schin 			sfputc(mp, *p++);
24284887Schin 			continue;
24294887Schin 		}
24304887Schin 		switch (c)
24314887Schin 		{
24324887Schin 		case '?':
24334887Schin 			if (f)
24344887Schin 			{
24354887Schin 				if (*p == '?')
24364887Schin 				{
24374887Schin 					p++;
24384887Schin 					sfputc(mp, c);
24394887Schin 				}
24404887Schin 				else
24414887Schin 				{
24424887Schin 					f = 0;
24434887Schin 					sfputc(mp, 0);
24444887Schin 					y = sfstrbase(mp) + m + 1;
24454887Schin 					if (D(y) || !strmatch(y, KEEP) || strmatch(y, OMIT))
24464887Schin 					{
24474887Schin 						sfstrseek(mp, m, SEEK_SET);
24484887Schin 						xl = 0;
24494887Schin 					}
24504887Schin 					else
24514887Schin 						sfstrseek(mp, -1, SEEK_CUR);
24524887Schin 					if (z && (*p != ']' || *(p + 1) == ']'))
24534887Schin 					{
24544887Schin 						if (xl)
24554887Schin 						{
24564887Schin 							sfputc(mp, '"');
24574887Schin 							sfputc(mp, '\n');
24584887Schin 						}
24594887Schin 						m = sfstrtell(mp);
24604887Schin 						sfputc(mp, '"');
24614887Schin 						xl = 1;
24624887Schin 					}
24634887Schin 					else
24644887Schin 					{
24654887Schin 						p = skip(p, 0, 0, 0, 1, 0, 0, version);
24664887Schin 						if (*p == '?')
24674887Schin 							p++;
24684887Schin 					}
24694887Schin 				}
24704887Schin 			}
24714887Schin 			else
24724887Schin 				sfputc(mp, c);
24734887Schin 			continue;
24744887Schin 		case ':':
24754887Schin 			if (f && *p == ':')
24764887Schin 				p++;
24774887Schin 			sfputc(mp, c);
24784887Schin 			continue;
24794887Schin 		case '\a':
24804887Schin 			c = 'a';
24814887Schin 			break;
24824887Schin 		case '\b':
24834887Schin 			c = 'b';
24844887Schin 			break;
24854887Schin 		case '\f':
24864887Schin 			c = 'f';
24874887Schin 			break;
24884887Schin 		case '\n':
24894887Schin 			c = 'n';
24904887Schin 			break;
24914887Schin 		case '\r':
24924887Schin 			c = 'r';
24934887Schin 			break;
24944887Schin 		case '\t':
24954887Schin 			c = 't';
24964887Schin 			break;
24974887Schin 		case '\v':
24984887Schin 			c = 'v';
24994887Schin 			break;
25004887Schin 		case '"':
25014887Schin 			c = '"';
25024887Schin 			break;
25034887Schin 		case '\\':
25044887Schin 			c = '\\';
25054887Schin 			break;
25064887Schin 		case CC_esc:
25074887Schin 			c = 'E';
25084887Schin 			break;
25094887Schin 		default:
25104887Schin 			sfputc(mp, c);
25114887Schin 			continue;
25124887Schin 		}
25134887Schin 		sfputc(mp, '\\');
25144887Schin 		sfputc(mp, c);
25154887Schin 	}
25164887Schin 
25174887Schin 				/*...INDENT*/
25184887Schin 				if (xl)
25194887Schin 				{
25204887Schin 					sfputc(mp, '"');
25214887Schin 					sfputc(mp, '\n');
25224887Schin 				}
25234887Schin 			}
25244887Schin 			continue;
25254887Schin 		}
25264887Schin 		z = 0;
25274887Schin 		head = 0;
25284887Schin 		mode = 0;
25294887Schin 		mutex = 0;
25304887Schin 		if (style > STYLE_short && style < STYLE_nroff && version < 1)
25314887Schin 		{
25324887Schin 			style = STYLE_short;
25334887Schin 			if (sp_body)
25344887Schin 			{
25354887Schin 				sfclose(sp_body);
25364887Schin 				sp_body = 0;
25374887Schin 			}
25384887Schin 		}
25394887Schin 		else if (style == STYLE_short && prefix < 2)
25404887Schin 			style = STYLE_long;
25414887Schin 		if (*p == ':')
25424887Schin 			p++;
25434887Schin 		if (*p == '+')
25444887Schin 		{
25454887Schin 			p++;
25464887Schin 			if (!(sp = sp_plus) && !(sp = sp_plus = sfstropen()))
25474887Schin 				goto nospace;
25484887Schin 		}
25494887Schin 		else if (style >= STYLE_match)
25504887Schin 			sp = sp_body;
25514887Schin 		else
25524887Schin 			sp = sp_text;
25534887Schin 		psp = 0;
25544887Schin 		for (;;)
25554887Schin 		{
25564887Schin 			if (!(*(p = next(p, version))))
25574887Schin 			{
25584887Schin 				if (!(tsp = psp))
25594887Schin 					break;
25604887Schin 				p = psp->ob;
25614887Schin 				psp = psp->next;
25624887Schin 				free(tsp);
25634887Schin 				continue;
25644887Schin 			}
25654887Schin 			if (*p == '\f')
25664887Schin 			{
25674887Schin 				psp = info(psp, p + 1, NiL, sp_info);
25684887Schin 				if (psp->nb)
25694887Schin 					p = psp->nb;
25704887Schin 				else
25714887Schin 				{
25724887Schin 					p = psp->ob;
25734887Schin 					psp = psp->next;
25744887Schin 				}
25754887Schin 				continue;
25764887Schin 			}
25774887Schin 			if (*p == '\n' || *p == ' ')
25784887Schin 			{
25794887Schin 				if (*(x = p = next(p + 1, version)))
25804887Schin 					while (*++p)
25814887Schin 						if (*p == '\n')
25824887Schin 						{
25834887Schin 							while (*++p == ' ' || *p == '\t' || *p == '\r');
25844887Schin 							if (*p == '\n')
25854887Schin 								break;
25864887Schin 						}
25874887Schin 				xl = p - x;
25884887Schin 				if (!*p)
25894887Schin 					break;
25904887Schin 				continue;
25914887Schin 			}
2592*8462SApril.Chin@Sun.COM 			if (*p == OG)
25934887Schin 			{
25944887Schin 				p++;
25954887Schin 				continue;
25964887Schin 			}
25974887Schin 			message((-20, "opthelp: opt %s", show(p)));
25984887Schin 			if (z < 0)
25994887Schin 				z = 0;
26004887Schin 			a = 0;
26014887Schin 			f = 0;
26024887Schin 			w = 0;
26034887Schin 			d = 0;
26044887Schin 			s = 0;
2605*8462SApril.Chin@Sun.COM 			rb = re = 0;
26064887Schin 			sl = 0;
2607*8462SApril.Chin@Sun.COM 			vl = 0;
26084887Schin 			if (*p == '[')
26094887Schin 			{
26104887Schin 				if ((c = *(p = next(p + 1, version))) == '-')
26114887Schin 				{
26124887Schin 					if (style >= STYLE_man)
26134887Schin 					{
26144887Schin 						if (*(p + 1) != '-')
26154887Schin 						{
26164887Schin 							if (!sp_misc && !(sp_misc = sfstropen()))
26174887Schin 								goto nospace;
26184887Schin 							else
26194887Schin 								p = textout(sp_misc, p, style, 1, 3, sp_info, version, catalog);
26204887Schin 							continue;
26214887Schin 						}
26224887Schin 					}
26234887Schin 					else if (style == STYLE_match && *what == '-')
26244887Schin 					{
2625*8462SApril.Chin@Sun.COM 						if (*(p + 1) == '?' || isdigit(*(p + 1)))
26264887Schin 							s = C("version");
26274887Schin 						else
26284887Schin 							s = p + 1;
26294887Schin 						w = (char*)what;
26304887Schin 						if (*s != '-' || *(w + 1) == '-')
26314887Schin 						{
26324887Schin 							if (*s == '-')
26334887Schin 								s++;
26344887Schin 							if (*(w + 1) == '-')
26354887Schin 								w++;
26364887Schin 							if (match(w + 1, s, version, catalog))
26374887Schin 							{
26384887Schin 								if (*(p + 1) == '-')
26394887Schin 									p++;
26404887Schin 								p = textout(sp, p, style, 1, 3, sp_info, version, catalog);
26414887Schin 								matched = -1;
26424887Schin 								continue;
26434887Schin 							}
26444887Schin 						}
26454887Schin 					}
26464887Schin 					if (!z)
26474887Schin 						z = -1;
26484887Schin 				}
26494887Schin 				else if (c == '+')
26504887Schin 				{
26514887Schin 					if (style >= STYLE_man)
26524887Schin 					{
26534887Schin 						p = textout(sp_body, p, style, 0, 0, sp_info, version, catalog);
26544887Schin 						if (!sp_head)
26554887Schin 						{
26564887Schin 							sp_head = sp_body;
26574887Schin 							if (!(sp_body = sfstropen()))
26584887Schin 								goto nospace;
26594887Schin 						}
26604887Schin 						continue;
26614887Schin 					}
26624887Schin 					else if (style == STYLE_match && *what == '+')
26634887Schin 					{
26644887Schin 						if (paragraph)
26654887Schin 						{
26664887Schin 							if (p[1] == '?')
26674887Schin 							{
26684887Schin 								p = textout(sp, p, style, 1, 3, sp_info, version, catalog);
26694887Schin 								continue;
26704887Schin 							}
26714887Schin 							paragraph = 0;
26724887Schin 						}
26734887Schin 						if (match((char*)what + 1, p + 1, version, catalog))
26744887Schin 						{
26754887Schin 							p = textout(sp, p, style, 1, 3, sp_info, version, catalog);
26764887Schin 							matched = -1;
26774887Schin 							paragraph = 1;
26784887Schin 							continue;
26794887Schin 						}
26804887Schin 					}
26814887Schin 					if (!z)
26824887Schin 						z = -1;
26834887Schin 				}
26844887Schin 				else if (c == '[' || version < 1)
26854887Schin 				{
26864887Schin 					mutex++;
26874887Schin 					continue;
26884887Schin 				}
26894887Schin 				else
26904887Schin 				{
26914887Schin 					if (c == '!')
26924887Schin 					{
26934887Schin 						a |= OPT_invert;
26944887Schin 						p++;
26954887Schin 					}
26964887Schin 					rb = p;
26974887Schin 					if (*p != ':')
26984887Schin 					{
26994887Schin 						s = p;
27004887Schin 						if (*(p + 1) == '|')
27014887Schin 						{
27024887Schin 							while (*++p && *p != '=' && *p != '!' && *p != ':' && *p != '?');
27034887Schin 							if ((p - s) > 1)
27044887Schin 								sl = p - s;
27054887Schin 							if (*p == '!')
27064887Schin 								a |= OPT_invert;
27074887Schin 						}
27084887Schin 						if (*(p + 1) == '\f')
27094887Schin 							p++;
27104887Schin 						else
27114887Schin 							p = skip(p, ':', '?', 0, 1, 0, 0, version);
27124887Schin 						if (sl || (p - s) == 1 || *(s + 1) == '=' || *(s + 1) == '!' && (a |= OPT_invert) || *(s + 1) == '|')
27134887Schin 							f = *s;
27144887Schin 					}
27154887Schin 					re = p;
27164887Schin 					if (style <= STYLE_short)
27174887Schin 					{
27184887Schin 						if (!z && !f)
27194887Schin 							z = -1;
27204887Schin 					}
27214887Schin 					else
27224887Schin 					{
27234887Schin 						if (*p == '\f' && (vp = opt_info.state->vp))
27244887Schin 							p = expand(p + 1, NiL, &t, vp);
27254887Schin 						else
27264887Schin 							t = 0;
27274887Schin 						if (*p == ':')
27284887Schin 						{
27294887Schin 							p = skip(w = p + 1, ':', '?', 0, 1, 0, 0, version);
27304887Schin 							if (!(wl = p - w))
27314887Schin 								w = 0;
27324887Schin 						}
27334887Schin 						else
27344887Schin 							wl = 0;
27354887Schin 						if (*p == ':' || *p == '?')
27364887Schin 						{
27374887Schin 							d = p;
27384887Schin 							p = skip(p, 0, 0, 0, 1, 0, 0, version);
27394887Schin 						}
27404887Schin 						else
27414887Schin 							d = 0;
27424887Schin 						if (style == STYLE_match)
27434887Schin 						{
27444887Schin 							if (wl && !match((char*)what, w, version, catalog))
27454887Schin 								wl = 0;
27464887Schin 							if ((!wl || *w == ':' || *w == '?') && (what[1] || sl && !memchr(s, what[0], sl) || !sl && what[0] != f))
27474887Schin 							{
27484887Schin 								w = 0;
27494887Schin 								if (!z)
27504887Schin 									z = -1;
27514887Schin 							}
27524887Schin 							else
27534887Schin 								matched = 1;
27544887Schin 						}
27554887Schin 						if (t)
27564887Schin 						{
27574887Schin 							p = t;
27584887Schin 							if (*p == ':' || *p == '?')
27594887Schin 							{
27604887Schin 								d = p;
27614887Schin 								p = skip(p, 0, 0, 0, 1, 0, 0, version);
27624887Schin 							}
27634887Schin 						}
27644887Schin 					}
27654887Schin 				}
27664887Schin 				p = skip(p, 0, 0, 0, 1, 0, 1, version);
27674887Schin 				if (*p == GO)
27684887Schin 					p = skip(p + 1, 0, 0, 0, 0, 1, 1, version);
27694887Schin 			}
27704887Schin 			else if (*p == ']')
27714887Schin 			{
27724887Schin 				if (mutex)
27734887Schin 				{
27744887Schin 					if (style >= STYLE_nroff)
27754887Schin 						sfputr(sp_body, "\n.OP - - anyof", '\n');
27764887Schin 					if (!(mutex & 1))
27774887Schin 					{
27784887Schin 						mutex--;
27794887Schin 						if (style <= STYLE_long)
27804887Schin 						{
27814887Schin 							sfputc(sp_body, ' ');
27824887Schin 							sfputc(sp_body, ']');
27834887Schin 						}
27844887Schin 					}
27854887Schin 					mutex--;
27864887Schin 				}
27874887Schin 				p++;
27884887Schin 				continue;
27894887Schin 			}
27904887Schin 			else if (*p == '?')
27914887Schin 			{
27924887Schin 				if (style < STYLE_match)
27934887Schin 					z = 1;
27944887Schin 				mode |= OPT_hidden;
27954887Schin 				p++;
27964887Schin 				continue;
27974887Schin 			}
27984887Schin 			else if (*p == '\\' && style==STYLE_posix)
27994887Schin 			{
28004887Schin 				if (*++p)
28014887Schin 					p++;
28024887Schin 				continue;
28034887Schin 			}
28044887Schin 			else
28054887Schin 			{
28064887Schin 				f = *p++;
28074887Schin 				s = 0;
28084887Schin 				if (style == STYLE_match && !z)
28094887Schin 					z = -1;
28104887Schin 			}
28114887Schin 			if (!z)
28124887Schin 			{
28134887Schin 				if (style == STYLE_long || prefix < 2 || (q->flags & OPT_long))
28144887Schin 					f = 0;
28154887Schin 				else if (style <= STYLE_short)
28164887Schin 					w = 0;
28174887Schin 				if (!f && !w)
28184887Schin 					z = -1;
28194887Schin 			}
2820*8462SApril.Chin@Sun.COM 			ov = 0;
2821*8462SApril.Chin@Sun.COM 			u = v = y = 0;
28224887Schin 			if (*p == ':' && (a |= OPT_string) || *p == '#' && (a |= OPT_number))
28234887Schin 			{
28244887Schin 				message((-21, "opthelp: arg %s", show(p)));
28254887Schin 				if (*++p == '?' || *p == *(p - 1))
28264887Schin 				{
28274887Schin 					p++;
28284887Schin 					a |= OPT_optional;
28294887Schin 				}
28304887Schin 				if (*(p = next(p, version)) == '[')
28314887Schin 				{
28324887Schin 					if (!z)
28334887Schin 					{
28344887Schin 						p = skip(y = p + 1, ':', '?', 0, 1, 0, 0, version);
28354887Schin 						while (*p == ':')
28364887Schin 						{
28374887Schin 							p = skip(t = p + 1, ':', '?', 0, 1, 0, 0, version);
28384887Schin 							m = p - t;
28394887Schin 							if (*t == '!')
28404887Schin 							{
28414887Schin 								ov = t + 1;
28424887Schin 								ol = m - 1;
28434887Schin 							}
28444887Schin 							else if (*t == '=')
28454887Schin 							{
28464887Schin 								v = t + 1;
28474887Schin 								vl = m - 1;
28484887Schin 							}
28494887Schin 							else
28504887Schin 								for (j = 0; j < elementsof(attrs); j++)
28514887Schin 									if (strneq(t, attrs[j].name, m))
28524887Schin 									{
28534887Schin 										a |= attrs[j].flag;
28544887Schin 										break;
28554887Schin 									}
28564887Schin 						}
28574887Schin 						if (*p == '?')
28584887Schin 							u = p;
28594887Schin 						p = skip(p, 0, 0, 0, 1, 0, 1, version);
28604887Schin 					}
28614887Schin 					else
28624887Schin 						p = skip(p + 1, 0, 0, 0, 1, 0, 1, version);
28634887Schin 				}
28644887Schin 				else
28654887Schin 					y = (a & OPT_number) ? T(NiL, ID, "#") : T(NiL, ID, "arg");
28664887Schin 			}
28674887Schin 			else
28684887Schin 				a |= OPT_flag;
28694887Schin 			if (!z)
28704887Schin 			{
28714887Schin 				if (style <= STYLE_short && !y && !mutex || style == STYLE_posix)
28724887Schin 				{
28734887Schin 					if (style != STYLE_posix && !sfstrtell(sp))
28744887Schin 					{
28754887Schin 						sfputc(sp, '[');
28764887Schin 						if (sp == sp_plus)
28774887Schin 							sfputc(sp, '+');
28784887Schin 						sfputc(sp, '-');
28794887Schin 					}
28804887Schin 					if (!sl)
28814887Schin 						sfputc(sp, f);
28824887Schin 					else
28834887Schin 						for (c = 0; c < sl; c++)
28844887Schin 							if (s[c] != '|')
28854887Schin 								sfputc(sp, s[c]);
28864887Schin 					if (style == STYLE_posix && y)
28874887Schin 						sfputc(sp, ':');
28884887Schin 				}
28894887Schin 				else
28904887Schin 				{
28914887Schin 					if (style >= STYLE_match)
28924887Schin 					{
28934887Schin 						sfputc(sp_body, '\n');
28944887Schin 						if (!head)
28954887Schin 						{
28964887Schin 							head = 1;
2897*8462SApril.Chin@Sun.COM 							item(sp_body, (flags & OPT_functions) ? C("FUNCTIONS") : C("OPTIONS"), 0, 0, style, sp_info, version, ID);
28984887Schin 						}
28994887Schin 						if (style >= STYLE_nroff)
29004887Schin 						{
29014887Schin 							if (mutex & 1)
29024887Schin 							{
29034887Schin 								mutex++;
29044887Schin 								sfputr(sp_body, "\n.OP - - oneof", '\n');
29054887Schin 							}
29064887Schin 						}
29074887Schin 						else
29084887Schin 							sfputc(sp_body, '\t');
29094887Schin 					}
29104887Schin 					else
29114887Schin 					{
29124887Schin 						if (sp_body)
29134887Schin 							sfputc(sp_body, ' ');
29144887Schin 						else if (!(sp_body = sfstropen()))
29154887Schin 							goto nospace;
29164887Schin 						if (mutex)
29174887Schin 						{
29184887Schin 							if (mutex & 1)
29194887Schin 							{
29204887Schin 								mutex++;
29214887Schin 								sfputc(sp_body, '[');
29224887Schin 							}
29234887Schin 							else
29244887Schin 								sfputc(sp_body, '|');
29254887Schin 							sfputc(sp_body, ' ');
29264887Schin 						}
29274887Schin 						else
29284887Schin 							sfputc(sp_body, '[');
29294887Schin 					}
29304887Schin 					if (style >= STYLE_nroff)
29314887Schin 					{
29324887Schin 						if (flags & OPT_functions)
29334887Schin 						{
29344887Schin 							sfputr(sp_body, ".FN", ' ');
29354887Schin 							if (re > rb)
29364887Schin 								sfwrite(sp_body, rb, re - rb);
29374887Schin 							else
29384887Schin 								sfputr(sp, "void", -1);
29394887Schin 							if (w)
2940*8462SApril.Chin@Sun.COM 								label(sp_body, ' ', w, 0, -1, 0, style, FONT_BOLD, sp_info, version, catalog);
29414887Schin 						}
29424887Schin 						else
29434887Schin 						{
29444887Schin 							sfputr(sp_body, ".OP", ' ');
29454887Schin 							if (sl)
29464887Schin 								sfwrite(sp_body, s, sl);
29474887Schin 							else
29484887Schin 								sfputc(sp_body, f ? f : '-');
29494887Schin 							sfputc(sp_body, ' ');
29504887Schin 							if (w)
29514887Schin 							{
2952*8462SApril.Chin@Sun.COM 								if (label(sp_body, 0, w, 0, -1, 0, style, 0, sp_info, version, catalog))
29534887Schin 								{
29544887Schin 									sfputc(sp_body, '|');
2955*8462SApril.Chin@Sun.COM 									label(sp_body, 0, w, 0, -1, 0, style, 0, sp_info, version, native);
29564887Schin 								}
29574887Schin 							}
29584887Schin 							else
29594887Schin 								sfputc(sp_body, '-');
29604887Schin 							sfputc(sp_body, ' ');
29614887Schin 							m = a & OPT_TYPE;
29624887Schin 							for (j = 0; j < elementsof(attrs); j++)
29634887Schin 								if (m & attrs[j].flag)
29644887Schin 								{
29654887Schin 									sfputr(sp_body, attrs[j].name, -1);
29664887Schin 									break;
29674887Schin 								}
29684887Schin 							if (m = (a & ~m) | mode)
29694887Schin 								for (j = 0; j < elementsof(attrs); j++)
29704887Schin 									if (m & attrs[j].flag)
29714887Schin 									{
29724887Schin 										sfputc(sp_body, ':');
29734887Schin 										sfputr(sp_body, attrs[j].name, -1);
29744887Schin 									}
29754887Schin 							sfputc(sp_body, ' ');
29764887Schin 							if (y)
2977*8462SApril.Chin@Sun.COM 								label(sp_body, 0, y, 0, -1, 0, style, 0, sp_info, version, catalog);
29784887Schin 							else
29794887Schin 								sfputc(sp_body, '-');
29804887Schin 							if (v)
29814887Schin 								sfprintf(sp_body, " %-.*s", vl, v);
29824887Schin 						}
29834887Schin 					}
29844887Schin 					else
29854887Schin 					{
29864887Schin 						if (f)
29874887Schin 						{
29884887Schin 							if (sp_body == sp_plus)
29894887Schin 								sfputc(sp_body, '+');
29904887Schin 							sfputc(sp_body, '-');
29914887Schin 							sfputr(sp_body, font(FONT_BOLD, style, 1), -1);
29924887Schin 							if (!sl)
29934887Schin 							{
29944887Schin 								sfputc(sp_body, f);
29954887Schin 								if (f == '-' && y)
29964887Schin 								{
29974887Schin 									y = 0;
29984887Schin 									sfputr(sp_body, C("long-option[=value]"), -1);
29994887Schin 								}
30004887Schin 							}
30014887Schin 							else
30024887Schin 								sfwrite(sp_body, s, sl);
30034887Schin 							sfputr(sp_body, font(FONT_BOLD, style, 0), -1);
30044887Schin 							if (w)
30054887Schin 							{
30064887Schin 								sfputc(sp_body, ',');
30074887Schin 								sfputc(sp_body, ' ');
30084887Schin 							}
30094887Schin 						}
30104887Schin 						else if ((flags & OPT_functions) && re > rb)
30114887Schin 						{
30124887Schin 							sfwrite(sp_body, rb, re - rb);
30134887Schin 							sfputc(sp_body, ' ');
30144887Schin 						}
30154887Schin 						if (w)
30164887Schin 						{
30174887Schin 							if (prefix > 0)
30184887Schin 							{
30194887Schin 								sfputc(sp_body, '-');
30204887Schin 								if (prefix > 1)
30214887Schin 									sfputc(sp_body, '-');
30224887Schin 							}
3023*8462SApril.Chin@Sun.COM 							if (label(sp_body, 0, w, 0, -1, 0, style, FONT_BOLD, sp_info, version, catalog))
30244887Schin 							{
30254887Schin 								sfputc(sp_body, '|');
3026*8462SApril.Chin@Sun.COM 								label(sp_body, 0, w, 0, -1, 0, style, FONT_BOLD, sp_info, version, native);
30274887Schin 							}
30284887Schin 						}
30294887Schin 						if (y)
30304887Schin 						{
30314887Schin 							if (a & OPT_optional)
30324887Schin 								sfputc(sp_body, '[');
30334887Schin 							else if (!w)
30344887Schin 								sfputc(sp_body, ' ');
30354887Schin 							if (w)
30364887Schin 								sfputc(sp_body, prefix == 1 ? ' ' : '=');
3037*8462SApril.Chin@Sun.COM 							label(sp_body, 0, y, 0, -1, 0, style, FONT_ITALIC, sp_info, version, catalog);
30384887Schin 							if (a & OPT_optional)
30394887Schin 								sfputc(sp_body, ']');
30404887Schin 						}
30414887Schin 					}
30424887Schin 					if (style >= STYLE_match)
30434887Schin 					{
30444887Schin 						if (d)
30454887Schin 							textout(sp_body, d, style, 0, 3, sp_info, version, catalog);
30464887Schin 						if (u)
30474887Schin 							textout(sp_body, u, style, 0, 3, sp_info, version, catalog);
30484887Schin 						if ((a & OPT_invert) && w && (d || u))
30494887Schin 						{
30504887Schin 							u = skip(w, ':', '?', 0, 1, 0, 0, version);
30514887Schin 							if (f)
30524887Schin 								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);
30534887Schin 							else
30544887Schin 								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"));
30554887Schin 							if (!(t = sfstruse(sp_info)))
30564887Schin 								goto nospace;
30574887Schin 							textout(sp_body, t, style, 0, 0, sp_info, version, NiL);
30584887Schin 						}
30594887Schin 						if (*p == GO)
30604887Schin 						{
30614887Schin 							p = u ? skip(p + 1, 0, 0, 0, 0, 1, 1, version) : textout(sp_body, p, style, 4, 0, sp_info, version, catalog);
30624887Schin 							y = "+?";
30634887Schin 						}
30644887Schin 						else
30654887Schin 							y = " ";
30664887Schin 						if (a & OPT_optional)
30674887Schin 						{
30684887Schin 							if (ov)
30694887Schin 							{
30704887Schin 								sfprintf(sp_info, "%s%s \b", y, T(NiL, ID, "If the option value is omitted then"));
30714887Schin 								t = ov + ol;
30724887Schin 								while (ov < t)
30734887Schin 								{
30744887Schin 									if (((c = *ov++) == ':' || c == '?') && *ov == c)
30754887Schin 										ov++;
30764887Schin 									sfputc(sp_info, c);
30774887Schin 								}
30784887Schin 								sfprintf(sp_info, "\b %s.", T(NiL, ID, "is assumed"));
30794887Schin 							}
30804887Schin 							else
30814887Schin 								sfprintf(sp_info, "%s%s", y, T(NiL, ID, "The option value may be omitted."));
30824887Schin 							if (!(t = sfstruse(sp_info)))
30834887Schin 								goto nospace;
30844887Schin 							textout(sp_body, t, style, 4, 0, sp_info, version, NiL);
30854887Schin 							y = " ";
30864887Schin 						}
30874887Schin 						if (v)
30884887Schin 						{
30894887Schin 							sfprintf(sp_info, "%s%s \b", y, T(NiL, ID, "The default value is"));
30904887Schin 							t = v + vl;
30914887Schin 							while (v < t)
30924887Schin 							{
30934887Schin 								if (((c = *v++) == ':' || c == '?') && *v == c)
30944887Schin 									v++;
30954887Schin 								sfputc(sp_info, c);
30964887Schin 							}
30974887Schin 							sfputc(sp_info, '\b');
30984887Schin 							sfputc(sp_info, '.');
30994887Schin 							if (!(t = sfstruse(sp_info)))
31004887Schin 								goto nospace;
31014887Schin 							textout(sp_body, t, style, 4, 0, sp_info, version, NiL);
31024887Schin 						}
31034887Schin 					}
31044887Schin 					else if (!mutex)
31054887Schin 						sfputc(sp_body, ']');
31064887Schin 				}
31074887Schin 				if (*p == GO)
31084887Schin 				{
31094887Schin 					if (style >= STYLE_match)
31104887Schin 						p = textout(sp_body, p, style, 4, 0, sp_info, version, catalog);
31114887Schin 					else
31124887Schin 						p = skip(p + 1, 0, 0, 0, 0, 1, 1, version);
31134887Schin 				}
31144887Schin 			}
31154887Schin 			else if (*p == GO)
31164887Schin 				p = skip(p + 1, 0, 0, 0, 0, 1, 1, version);
31174887Schin 		}
31184887Schin 		psp = pop(psp);
31194887Schin 		if (sp_misc)
31204887Schin 		{
31214887Schin 			if (!(p = sfstruse(sp_misc)))
31224887Schin 				goto nospace;
31234887Schin 			for (t = p; *t == '\t' || *t == '\n'; t++);
31244887Schin 			if (*t)
31254887Schin 			{
3126*8462SApril.Chin@Sun.COM 				item(sp_body, C("IMPLEMENTATION"), 0, 0, style, sp_info, version, ID);
31274887Schin 				sfputr(sp_body, p, -1);
31284887Schin 			}
31294887Schin 		}
31304887Schin 	}
31314887Schin 	version = o->version;
31324887Schin 	catalog = o->catalog;
31334887Schin 	if (style >= STYLE_keys)
31344887Schin 	{
31354887Schin 		if (sp_info)
31364887Schin 			sfclose(sp_info);
31374887Schin 		if (style == STYLE_keys && sfstrtell(mp) > 1)
31384887Schin 			sfstrseek(mp, -1, SEEK_CUR);
31394887Schin 		if (!(p = sfstruse(mp)))
31404887Schin 			goto nospace;
31414887Schin 		return opt_info.msg = p;
31424887Schin 	}
31434887Schin 	sp = sp_text;
31444887Schin 	if (sfstrtell(sp) && style != STYLE_posix)
31454887Schin 		sfputc(sp, ']');
31464887Schin 	if (style == STYLE_nroff)
31474887Schin 	{
31484887Schin 		sfprintf(sp, "\
31494887Schin .\\\" format with nroff|troff|groff -man\n\
31504887Schin .fp 5 CW\n\
3151*8462SApril.Chin@Sun.COM .nr mH 5\n\
3152*8462SApril.Chin@Sun.COM .de H0\n\
3153*8462SApril.Chin@Sun.COM .nr mH 0\n\
3154*8462SApril.Chin@Sun.COM .in 5n\n\
3155*8462SApril.Chin@Sun.COM \\fB\\\\$1\\fP\n\
3156*8462SApril.Chin@Sun.COM .in 7n\n\
31574887Schin ..\n\
31584887Schin .de H1\n\
3159*8462SApril.Chin@Sun.COM .nr mH 1\n\
3160*8462SApril.Chin@Sun.COM .in 7n\n\
31614887Schin \\fB\\\\$1\\fP\n\
3162*8462SApril.Chin@Sun.COM .in 9n\n\
31634887Schin ..\n\
31644887Schin .de H2\n\
3165*8462SApril.Chin@Sun.COM .nr mH 2\n\
3166*8462SApril.Chin@Sun.COM .in 11n\n\
31674887Schin \\fB\\\\$1\\fP\n\
3168*8462SApril.Chin@Sun.COM .in 13n\n\
31694887Schin ..\n\
31704887Schin .de H3\n\
3171*8462SApril.Chin@Sun.COM .nr mH 3\n\
3172*8462SApril.Chin@Sun.COM .in 15n\n\
31734887Schin \\fB\\\\$1\\fP\n\
3174*8462SApril.Chin@Sun.COM .in 17n\n\
31754887Schin ..\n\
31764887Schin .de H4\n\
3177*8462SApril.Chin@Sun.COM .nr mH 4\n\
3178*8462SApril.Chin@Sun.COM .in 19n\n\
31794887Schin \\fB\\\\$1\\fP\n\
3180*8462SApril.Chin@Sun.COM .in 21n\n\
31814887Schin ..\n\
31824887Schin .de OP\n\
3183*8462SApril.Chin@Sun.COM .nr mH 0\n\
31844887Schin .ie !'\\\\$1'-' \\{\n\
31854887Schin .ds mO \\\\fB\\\\-\\\\$1\\\\fP\n\
31864887Schin .ds mS ,\\\\0\n\
31874887Schin .\\}\n\
31884887Schin .el \\{\n\
31894887Schin .ds mO \\\\&\n\
31904887Schin .ds mS \\\\&\n\
31914887Schin .\\}\n\
31924887Schin .ie '\\\\$2'-' \\{\n\
31934887Schin .if !'\\\\$4'-' .as mO \\\\0\\\\fI\\\\$4\\\\fP\n\
31944887Schin .\\}\n\
31954887Schin .el \\{\n\
31964887Schin .as mO \\\\*(mS\\\\fB%s\\\\$2\\\\fP\n\
31974887Schin .if !'\\\\$4'-' .as mO =\\\\fI\\\\$4\\\\fP\n\
31984887Schin .\\}\n\
3199*8462SApril.Chin@Sun.COM .in 5n\n\
32004887Schin \\\\*(mO\n\
3201*8462SApril.Chin@Sun.COM .in 9n\n\
3202*8462SApril.Chin@Sun.COM ..\n\
3203*8462SApril.Chin@Sun.COM .de SP\n\
3204*8462SApril.Chin@Sun.COM .if \\\\n(mH==2 .in 9n\n\
3205*8462SApril.Chin@Sun.COM .if \\\\n(mH==3 .in 13n\n\
3206*8462SApril.Chin@Sun.COM .if \\\\n(mH==4 .in 17n\n\
32074887Schin ..\n\
32084887Schin .de FN\n\
3209*8462SApril.Chin@Sun.COM .nr mH 0\n\
3210*8462SApril.Chin@Sun.COM .in 5n\n\
32114887Schin \\\\$1 \\\\$2\n\
3212*8462SApril.Chin@Sun.COM .in 9n\n\
3213*8462SApril.Chin@Sun.COM ..\n\
3214*8462SApril.Chin@Sun.COM .de DS\n\
3215*8462SApril.Chin@Sun.COM .in +3n\n\
3216*8462SApril.Chin@Sun.COM .ft 5\n\
3217*8462SApril.Chin@Sun.COM .nf\n\
3218*8462SApril.Chin@Sun.COM ..\n\
3219*8462SApril.Chin@Sun.COM .de DE\n\
3220*8462SApril.Chin@Sun.COM .fi\n\
3221*8462SApril.Chin@Sun.COM .ft R\n\
3222*8462SApril.Chin@Sun.COM .in -3n\n\
32234887Schin ..\n\
32244887Schin .TH %s %d\n\
32254887Schin "
32264887Schin , o->prefix == 2 ? "\\\\-\\\\-" : o->prefix == 1 ? "\\\\-" : ""
32274887Schin , error_info.id
32284887Schin , section
32294887Schin );
32304887Schin 	}
32314887Schin 	if (style == STYLE_match)
32324887Schin 	{
32334887Schin 		if (!matched)
32344887Schin 		{
32354887Schin 			if (hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), (char*)what))
32364887Schin 			{
32374887Schin 				if (!sp_help && !(sp_help = sfstropen()))
32384887Schin 					goto nospace;
32394887Schin 				sfprintf(sp_help, "[-][:%s?%s]", hp->match, hp->text);
32404887Schin 				if (!(opts = sfstruse(sp_help)))
32414887Schin 					goto nospace;
32424887Schin 				goto again;
32434887Schin 			}
32444887Schin 			s = (char*)unknown;
32454887Schin 			goto nope;
32464887Schin 		}
32474887Schin 		else if (matched < 0)
32484887Schin 			x = 0;
32494887Schin 	}
32504887Schin 	if (sp_plus)
32514887Schin 	{
32524887Schin 		if (sfstrtell(sp_plus))
32534887Schin 		{
32544887Schin 			if (sfstrtell(sp))
32554887Schin 				sfputc(sp, ' ');
32564887Schin 			if (!(t = sfstruse(sp_plus)))
32574887Schin 				goto nospace;
32584887Schin 			sfputr(sp, t, ']');
32594887Schin 		}
32604887Schin 		sfclose(sp_plus);
32614887Schin 	}
32624887Schin 	if (style >= STYLE_man)
32634887Schin 	{
32644887Schin 		if (sp_head)
32654887Schin 		{
32664887Schin 			if (!(t = sfstruse(sp_head)))
32674887Schin 				goto nospace;
32684887Schin 			for (; *t == '\n'; t++);
32694887Schin 			sfputr(sp, t, '\n');
32704887Schin 			sfclose(sp_head);
32714887Schin 			sp_head = 0;
32724887Schin 		}
3273*8462SApril.Chin@Sun.COM 		item(sp, C("SYNOPSIS"), 0, 0, style, sp_info, version, ID);
32744887Schin 	}
32754887Schin 	if (x)
32764887Schin 	{
32774887Schin 		for (t = x + xl; t > x && (*(t - 1) == '\n' || *(t - 1) == '\r'); t--);
32784887Schin 		xl = t - x;
32794887Schin 		if (style >= STYLE_match)
32804887Schin 		{
32814887Schin 			args(sp, x, xl, flags, style, sp_info, version, catalog);
32824887Schin 			x = 0;
32834887Schin 		}
32844887Schin 	}
32854887Schin 	if (sp_body)
32864887Schin 	{
32874887Schin 		if (sfstrtell(sp_body))
32884887Schin 		{
32894887Schin 			if (style < STYLE_match && sfstrtell(sp))
32904887Schin 				sfputc(sp, ' ');
32914887Schin 			if (!(t = sfstruse(sp_body)))
32924887Schin 				goto nospace;
32934887Schin 			sfputr(sp, t, -1);
32944887Schin 		}
32954887Schin 		sfclose(sp_body);
32964887Schin 		sp_body = 0;
32974887Schin 	}
32984887Schin 	if (x && style != STYLE_posix)
32994887Schin 		args(sp, x, xl, flags, style, sp_info, version, catalog);
33004887Schin 	if (sp_info)
33014887Schin 	{
33024887Schin 		sfclose(sp_info);
33034887Schin 		sp_info = 0;
33044887Schin 	}
33054887Schin 	if (sp_misc)
33064887Schin 	{
33074887Schin 		sfclose(sp_misc);
33084887Schin 		sp_misc = 0;
33094887Schin 	}
33104887Schin 	if (!(p = sfstruse(sp)))
33114887Schin 		goto nospace;
33124887Schin 	name = error_info.id ? error_info.id : "command";
33134887Schin 	m = strlen(name) + 1;
3314*8462SApril.Chin@Sun.COM #if 0
33154887Schin 	if (!opt_info.state->width)
3316*8462SApril.Chin@Sun.COM #endif
33174887Schin 	{
33184887Schin 		astwinsize(1, NiL, &opt_info.state->width);
33194887Schin 		if (opt_info.state->width < 20)
33204887Schin 			opt_info.state->width = OPT_WIDTH;
33214887Schin 	}
3322*8462SApril.Chin@Sun.COM 	margin = style == STYLE_api ? (8 * 1024) : (opt_info.state->width - 1);
33234887Schin 	if (!(opt_info.state->flags & OPT_preformat))
33244887Schin 	{
33254887Schin 		if (style >= STYLE_man || matched < 0)
33264887Schin 		{
33274887Schin 			sfputc(mp, '\f');
33284887Schin 			ts = 0;
33294887Schin 		}
33304887Schin 		else
33314887Schin 			ts = OPT_USAGE + m;
33324887Schin 		if (style == STYLE_html)
33334887Schin 		{
33344887Schin 			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);
33354887Schin 			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);
33364887Schin 			sfprintf(mp, "<DL compact>\n<DT>");
33374887Schin 			co = 2;
33384887Schin 			*(pt = ptstk) = 0;
33394887Schin 		}
33404887Schin 		else
33414887Schin 			co = 0;
3342*8462SApril.Chin@Sun.COM 		if ((rm = margin - ts) < OPT_MARGIN)
33434887Schin 			rm = OPT_MARGIN;
33444887Schin 		ip = indent;
33454887Schin 		ip->stop = (ip+1)->stop = style >= STYLE_html ? 0 : 2;
33464887Schin 		tp = 0;
33474887Schin 		n = 0;
33484887Schin 		head = 1;
33494887Schin 		while (*p == '\n')
33504887Schin 			p++;
33514887Schin 		while (c = *p++)
33524887Schin 		{
33534887Schin 			if (c == '\n')
33544887Schin 			{
33554887Schin 				ip = indent;
33564887Schin 				n = 0;
33574887Schin 				tp = 0;
33584887Schin 				sfputc(mp, '\n');
33594887Schin 				co = 0;
3360*8462SApril.Chin@Sun.COM 				rm = margin;
33614887Schin 				ts = ip->stop;
33624887Schin 				if (*p == '\n')
33634887Schin 				{
33644887Schin 					while (*++p == '\n');
33654887Schin 					if ((style == STYLE_man || style == STYLE_html) && (!head || *p != ' ' && *p != '\t'))
33664887Schin 					{
33674887Schin 						if (style == STYLE_man)
33684887Schin 							p--;
33694887Schin 						else
33704887Schin 							sfprintf(mp, "<P>\n");
33714887Schin 					}
33724887Schin 				}
33734887Schin 				head = *p != ' ' && *p != '\t';
33744887Schin 				if (style == STYLE_html && (*p != '<' || !strneq(p, "<BR>", 4) && !strneq(p, "<P>", 3)))
33754887Schin 				{
33764887Schin 					y = p;
33774887Schin 					while (*p == '\t')
33784887Schin 						p++;
33794887Schin 					if (*p == '\n')
33804887Schin 						continue;
33814887Schin 					j = p - y;
33824887Schin 					if (j > *pt)
33834887Schin 					{
33844887Schin 						if (pt > ptstk)
33854887Schin 							sfprintf(mp, "<DL compact>\n");
33864887Schin 						*++pt = j;
33874887Schin 						sfprintf(mp, "<DL compact>\n");
33884887Schin 					}
33894887Schin 					else while (j < *pt)
33904887Schin 					{
33914887Schin 						if (--pt > ptstk)
33924887Schin 							sfprintf(mp, "</DL>\n");
33934887Schin 						sfprintf(mp, "</DL>\n");
33944887Schin 					}
33954887Schin 					co += sfprintf(mp, "<DT>");
33964887Schin 				}
33974887Schin 			}
33984887Schin 			else if (c == '\t')
33994887Schin 			{
34004887Schin 				if (style == STYLE_html)
34014887Schin 				{
34024887Schin 					while (*p == '\t')
34034887Schin 						p++;
34044887Schin 					if (*p != '\n')
34054887Schin 						co += sfprintf(mp, "<DD>");
34064887Schin 				}
34074887Schin 				else
34084887Schin 				{
34094887Schin 					if ((ip+1)->stop)
34104887Schin 					{
34114887Schin 						do
34124887Schin 						{
34134887Schin 							ip++;
34144887Schin 							if (*p != '\t')
34154887Schin 								break;
34164887Schin 							p++;
34174887Schin 						} while ((ip+1)->stop);
34184887Schin 						if (*p == '\n')
34194887Schin 							continue;
34204887Schin 						ts = ip->stop;
34214887Schin 						if (co >= ts)
34224887Schin 						{
34234887Schin 							sfputc(mp, '\n');
34244887Schin 							co = 0;
3425*8462SApril.Chin@Sun.COM 							rm = margin;
34264887Schin 							ts = ip->stop;
34274887Schin 						}
34284887Schin 					}
34294887Schin 					while (co < ts)
34304887Schin 					{
34314887Schin 						sfputc(mp, ' ');
34324887Schin 						co++;
34334887Schin 					}
34344887Schin 				}
34354887Schin 			}
34364887Schin 			else
34374887Schin 			{
34384887Schin 				if (c == ' ' && !n)
34394887Schin 				{
34404887Schin 					if (co >= rm)
34414887Schin 						tp = 0;
34424887Schin 					else
34434887Schin 					{
34444887Schin 						tp = sfstrtell(mp);
34454887Schin 						pp = p;
34464887Schin 					}
34474887Schin 					if (style == STYLE_nroff && !co)
34484887Schin 						continue;
34494887Schin 				}
34504887Schin 				else if (style == STYLE_html)
34514887Schin 				{
34524887Schin 					if (c == '<')
34534887Schin 					{
34544887Schin 						if (strneq(p, "NOBR>", 5))
34554887Schin 							n++;
34564887Schin 						else if (n && strneq(p, "/NOBR>", 6) && !--n)
34574887Schin 						{
34584887Schin 							for (y = p += 6; (c = *p) && c != ' ' && c != '\t' && c != '\n' && c != '<'; p++)
34594887Schin 								if (c == '[')
34604887Schin 									sfputr(mp, "&#0091;", -1);
34614887Schin 								else if (c == ']')
34624887Schin 									sfputr(mp, "&#0093;", -1);
34634887Schin 								else
34644887Schin 									sfputc(mp, c);
34654887Schin 							sfwrite(mp, "</NOBR", 6);
34664887Schin 							c = '>';
34674887Schin 							tp = 0;
34684887Schin 							co += p - y + 6;
34694887Schin 						}
34704887Schin 					}
34714887Schin 					else if (c == '>' && !n)
34724887Schin 					{
34734887Schin 						for (y = --p; (c = *p) && c != ' ' && c != '\t' && c != '\n' && c != '<'; p++)
34744887Schin 							if (c == '[')
34754887Schin 								sfputr(mp, "&#0091;", -1);
34764887Schin 							else if (c == ']')
34774887Schin 								sfputr(mp, "&#0093;", -1);
34784887Schin 							else
34794887Schin 								sfputc(mp, c);
34804887Schin 						c = *sfstrseek(mp, -1, SEEK_CUR);
34814887Schin 						if (p > y + 1)
34824887Schin 						{
34834887Schin 							tp = 0;
34844887Schin 							co += p - y - 1;
34854887Schin 						}
34864887Schin 						if (co >= rm)
34874887Schin 							tp = 0;
34884887Schin 						else
34894887Schin 						{
34904887Schin 							tp = sfstrtell(mp);
34914887Schin 							pp = p;
34924887Schin 						}
34934887Schin 					}
34944887Schin 					else if (c == '[')
34954887Schin 					{
34964887Schin 						sfputr(mp, "&#0091", -1);
34974887Schin 						c = ';';
34984887Schin 					}
34994887Schin 					else if (c == ']')
35004887Schin 					{
35014887Schin 						sfputr(mp, "&#0093", -1);
35024887Schin 						c = ';';
35034887Schin 					}
35044887Schin 					else if (c == 'h')
35054887Schin 					{
35064887Schin 						y = p;
35074887Schin 						if (*y++ == 't' && *y++ == 't' && *y++ == 'p' && (*y == ':' || *y++ == 's' && *y == ':') && *y++ == ':' && *y++ == '/' && *y++ == '/')
35084887Schin 						{
35094887Schin 							while (isalnum(*y) || *y == '_' || *y == '/' || *y == '-' || *y == '.')
35104887Schin 								y++;
35114887Schin 							if (*y == '?')
35124887Schin 								while (isalnum(*y) || *y == '_' || *y == '/' || *y == '-' || *y == '.' || *y == '?' || *y == '=' || *y == '%' || *y == '&' || *y == ';' || *y == '#')
35134887Schin 									y++;
35144887Schin 							if (*(y - 1) == '.')
35154887Schin 								y--;
35164887Schin 							p--;
35174887Schin 							sfprintf(mp, "<A href=\"%-.*s\">%-.*s</A", y - p, p, y - p, p);
35184887Schin 							p = y;
35194887Schin 							c = '>';
35204887Schin 						}
35214887Schin 					}
35224887Schin 					else if (c == 'C')
35234887Schin 					{
35244887Schin 						y = p;
35254887Schin 						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++ == ')')
35264887Schin 						{
35274887Schin 							sfputr(mp, "Copyright &copy", -1);
35284887Schin 							p = y;
35294887Schin 							c = ';';
35304887Schin 						}
35314887Schin 					}
35324887Schin 				}
35334887Schin 				else if (c == ']')
35344887Schin 				{
35354887Schin 					if (n)
35364887Schin 						n--;
35374887Schin 				}
35384887Schin 				else if (c == '[')
35394887Schin 					n++;
35404887Schin 				if (c == CC_esc)
35414887Schin 				{
35424887Schin 					sfputc(mp, c);
35434887Schin 					do
35444887Schin 					{
35454887Schin 						if (!(c = *p++))
35464887Schin 						{
35474887Schin 							p--;
35484887Schin 							break;
35494887Schin 						}
35504887Schin 						sfputc(mp, c);
35514887Schin 					} while (c < 'a' || c > 'z');
35524887Schin 				}
35534887Schin 				else if (co++ >= rm && !n)
35544887Schin 				{
35554887Schin 					if (tp)
35564887Schin 					{
35574887Schin 						if (*sfstrseek(mp, tp, SEEK_SET) != ' ')
35584887Schin 							sfstrseek(mp, 1, SEEK_CUR);
35594887Schin 						tp = 0;
35604887Schin 						p = pp;
35614887Schin 						n = 0;
35624887Schin 					}
35634887Schin 					else if (c != ' ' && c != '\n')
35644887Schin 						sfputc(mp, c);
35654887Schin 					if (*p == ' ')
35664887Schin 						p++;
35674887Schin 					if (*p != '\n')
35684887Schin 					{
35694887Schin 						sfputc(mp, '\n');
35704887Schin 						for (co = 0; co < ts; co++)
35714887Schin 							sfputc(mp, ' ');
3572*8462SApril.Chin@Sun.COM 						rm = margin;
35734887Schin 					}
35744887Schin 				}
35754887Schin 				else
35764887Schin 					sfputc(mp, c);
35774887Schin 			}
35784887Schin 		}
35794887Schin 		for (d = sfstrbase(mp), t = sfstrseek(mp, 0, SEEK_CUR); t > d && ((c = *(t - 1)) == '\n' || c == '\r' || c == ' ' || c == '\t'); t--);
35804887Schin 		sfstrseek(mp, t - d, SEEK_SET);
35814887Schin 		if (style == STYLE_html)
35824887Schin 		{
35834887Schin 			while (pt > ptstk)
35844887Schin 			{
35854887Schin 				if (--pt > ptstk)
35864887Schin 					sfprintf(mp, "\n</DL>");
35874887Schin 				sfprintf(mp, "\n</DL>");
35884887Schin 			}
35894887Schin 			sfprintf(mp, "</DL>\n</BODY>\n</HTML>");
35904887Schin 		}
35914887Schin 	}
35924887Schin 	else
35934887Schin 		sfputr(mp, p, 0);
35944887Schin 	if (!(p = sfstruse(mp)))
35954887Schin 		goto nospace;
35964887Schin 	if (sp)
35974887Schin 		sfclose(sp);
35984887Schin 	return opt_info.msg = p;
35994887Schin  nospace:
36004887Schin 	s = T(NiL, ID, "[* out of space *]");
36014887Schin  nope:
36024887Schin 	if (psp)
36034887Schin 		pop(psp);
36044887Schin 	if (sp_help)
36054887Schin 		sfclose(sp_help);
36064887Schin 	if (sp_text)
36074887Schin 		sfclose(sp_text);
36084887Schin 	if (sp_plus)
36094887Schin 		sfclose(sp_plus);
36104887Schin 	if (sp_info)
36114887Schin 		sfclose(sp_info);
36124887Schin 	if (sp_head)
36134887Schin 		sfclose(sp_head);
36144887Schin 	if (sp_body)
36154887Schin 		sfclose(sp_body);
36164887Schin 	if (sp_misc)
36174887Schin 		sfclose(sp_misc);
36184887Schin 	return s;
36194887Schin }
36204887Schin 
36214887Schin /*
36224887Schin  * compatibility wrapper to opthelp()
36234887Schin  */
36244887Schin 
36254887Schin char*
36264887Schin optusage(const char* opts)
36274887Schin {
36284887Schin 	return opthelp(opts, NiL);
36294887Schin }
36304887Schin 
36314887Schin /*
36324887Schin  * convert number using strtonll() *except* that
36334887Schin  * 0*[[:digit:]].* is treated as [[:digit:]].*
36344887Schin  * i.e., it looks octal but isn't, to meet
36354887Schin  * posix Utility Argument Syntax -- use
36364887Schin  * 0x.* or <base>#* for alternate bases
36374887Schin  */
36384887Schin 
36394887Schin static intmax_t
36404887Schin optnumber(const char* s, char** t, int* e)
36414887Schin {
36424887Schin 	intmax_t	n;
36434887Schin 	int		oerrno;
36444887Schin 
36454887Schin 	while (*s == '0' && isdigit(*(s + 1)))
36464887Schin 		s++;
36474887Schin 	oerrno = errno;
36484887Schin 	errno = 0;
36494887Schin 	n = strtonll(s, t, NiL, 0);
36504887Schin 	if (e)
36514887Schin 		*e = errno;
36524887Schin 	errno = oerrno;
36534887Schin 	return n;
36544887Schin }
36554887Schin 
36564887Schin /*
36574887Schin  * point opt_info.arg to an error/info message for opt_info.name
36584887Schin  * p points to opts location for opt_info.name
36594887Schin  * optget() return value is returned
36604887Schin  */
36614887Schin 
36624887Schin static int
36634887Schin opterror(register char* p, int version, char* catalog, int err)
36644887Schin {
36654887Schin 	register Sfio_t*	mp;
36664887Schin 	register Sfio_t*	tp;
36674887Schin 	register char*		s;
36684887Schin 	register int		c;
36694887Schin 
36704887Schin 	if (opt_info.num != LONG_MIN)
36714887Schin 		opt_info.num = opt_info.number = 0;
36724887Schin 	if (!p || !(mp = opt_info.state->mp) && !(mp = opt_info.state->mp = sfstropen()))
36734887Schin 		goto nospace;
36744887Schin 	s = *p == '-' ? p : opt_info.name;
36754887Schin 	if (*p == '!')
36764887Schin 	{
36774887Schin 		while (*s == '-')
36784887Schin 			sfputc(mp, *s++);
36794887Schin 		sfputc(mp, 'n');
36804887Schin 		sfputc(mp, 'o');
36814887Schin 	}
36824887Schin 	sfputr(mp, s, ':');
36834887Schin 	sfputc(mp, ' ');
36844887Schin 	if (*p == '#' || *p == ':')
36854887Schin 	{
36864887Schin 		if (*p == '#')
36874887Schin 		{
36884887Schin 			s = T(NiL, ID, "numeric");
36894887Schin 			sfputr(mp, s, ' ');
36904887Schin 		}
36914887Schin 		if (*(p = next(p + 1, version)) == '[')
36924887Schin 		{
36934887Schin 			p = skip(s = p + 1, ':', '?', 0, 1, 0, 0, version);
36944887Schin 			tp = X(catalog) ? opt_info.state->xp : mp;
36954887Schin 			while (s < p)
36964887Schin 			{
36974887Schin 				if ((c = *s++) == '?' || c == ']')
36984887Schin 					s++;
36994887Schin 				sfputc(tp, c);
37004887Schin 			}
37014887Schin 			if (!X(catalog))
37024887Schin 				sfputc(mp, ' ');
37034887Schin 			else if (p = sfstruse(tp))
37044887Schin 				sfputr(mp, T(error_info.id, catalog, p), ' ');
37054887Schin 			else
37064887Schin 				goto nospace;
37074887Schin 		}
37084887Schin 		p = opt_info.name[2] ? C("value expected") : C("argument expected");
37094887Schin 	}
37104887Schin 	else if (*p == '*' || *p == '&')
37114887Schin 	{
37124887Schin 		sfputr(mp, opt_info.arg, ':');
37134887Schin 		sfputc(mp, ' ');
37144887Schin 		p = *p == '&' ? C("ambiguous option argument value") : C("unknown option argument value");
37154887Schin 	}
37164887Schin 	else if (*p == '=' || *p == '!')
37174887Schin 		p = C("value not expected");
37184887Schin 	else if (*p == '?')
37194887Schin 		p = *(p + 1) == '?' ? C("optget: option not supported") : C("ambiguous option");
37204887Schin 	else if (*p == '+')
37214887Schin 		p = C("section not found");
37224887Schin 	else
37234887Schin 	{
37244887Schin 		if (opt_info.option[0] != '?' && opt_info.option[0] != '-' || opt_info.option[1] != '?' && opt_info.option[1] != '-')
37254887Schin 			opt_info.option[0] = 0;
37264887Schin 		p = C("unknown option");
37274887Schin 	}
37284887Schin 	p = T(NiL, ID, p);
37294887Schin 	sfputr(mp, p, -1);
37304887Schin 	if (err)
37314887Schin 		sfputr(mp, " -- out of range", -1);
37324887Schin 	if (opt_info.arg = sfstruse(mp))
37334887Schin 		return ':';
37344887Schin  nospace:
37354887Schin 	opt_info.arg = T(NiL, ID, "[* out of space *]");
37364887Schin 	return ':';
37374887Schin }
37384887Schin 
37394887Schin /*
37404887Schin  * argv:	command line argv where argv[0] is command name
37414887Schin  *
37424887Schin  * opts:	option control string
37434887Schin  *
37444887Schin  *	'[' [flag][=][index][:<long-name>[|<alias-name>...]['?'description]] ']'
37454887Schin  *			long option name, index, description; -index returned
37464887Schin  *	':'		option takes string arg
37474887Schin  *	'#'		option takes numeric arg (concat option may follow)
37484887Schin  *	'?'		(option) following options not in usage
37494887Schin  *			(following # or :) optional arg
37504887Schin  *	'[' '[' ... ] ... '[' ... ']' ']'
37514887Schin  *			mutually exclusive option grouping
37524887Schin  *	'[' name [:attr]* [?description] ']'
37534887Schin  *			(following # or :) optional option arg description
37544887Schin  *	'\n'[' '|'\t']*	ignored for legibility
37554887Schin  *	' ' ...		optional argument(s) description (to end of string)
37564887Schin  *			or after blank line
37574887Schin  *	']]'		literal ']' within '[' ... ']'
37584887Schin  *
37594887Schin  * return:
37604887Schin  *	0		no more options
37614887Schin  *	'?'		usage: opt_info.arg points to message sans
37624887Schin  *			`Usage: command '
37634887Schin  *	':'		error: opt_info.arg points to message sans `command: '
37644887Schin  *
37654887Schin  * '-' '+' '?' ':' '#' '[' ']' ' '
37664887Schin  *			invalid option chars
37674887Schin  *
37684887Schin  * -- terminates option list and returns 0
37694887Schin  *
37704887Schin  * + as first opts char makes + equivalent to -
37714887Schin  *
37724887Schin  * if any # option is specified then numeric options (e.g., -123)
37734887Schin  * are associated with the leftmost # option in opts
37744887Schin  *
37754887Schin  * usage info in placed opt_info.arg when '?' returned
37764887Schin  * see help_text[] (--???) for more info
37774887Schin  */
37784887Schin 
37794887Schin int
37804887Schin optget(register char** argv, const char* oopts)
37814887Schin {
37824887Schin 	register int	c;
37834887Schin 	register char*	s;
37844887Schin 	char*		a;
37854887Schin 	char*		b;
37864887Schin 	char*		e;
37874887Schin 	char*		f;
37884887Schin 	char*		g;
37894887Schin 	char*		v;
37904887Schin 	char*		w;
37914887Schin 	char*		p;
37924887Schin 	char*		q;
37934887Schin 	char*		t;
37944887Schin 	char*		y;
37954887Schin 	char*		numopt;
37964887Schin 	char*		opts;
37974887Schin 	char*		catalog;
37984887Schin 	int		n;
37994887Schin 	int		m;
38004887Schin 	int		k;
38014887Schin 	int		j;
38024887Schin 	int		x;
38034887Schin 	int		err;
38044887Schin 	int		no;
38054887Schin 	int		nov;
38064887Schin 	int		num;
38074887Schin 	int		numchr;
38084887Schin 	int		prefix;
38094887Schin 	int		version;
38104887Schin 	Help_t*		hp;
38114887Schin 	Push_t*		psp;
38124887Schin 	Push_t*		tsp;
38134887Schin 	Sfio_t*		vp;
38144887Schin 	Sfio_t*		xp;
38154887Schin 	Optcache_t*	cache;
38164887Schin 	Optcache_t*	pcache;
38174887Schin 	Optpass_t*	pass;
38184887Schin 
3819*8462SApril.Chin@Sun.COM #if !_PACKAGE_astsa && !_YOU_FIGURED_OUT_HOW_TO_GET_ALL_DLLS_TO_DO_THIS_
38204887Schin 	/*
38214887Schin 	 * these are not initialized by all dlls!
38224887Schin 	 */
38234887Schin 
38244887Schin 	extern Error_info_t	_error_info_;
38254887Schin 	extern Opt_t		_opt_info_;
38264887Schin 
38274887Schin 	if (!_error_infop_)
38284887Schin 		_error_infop_ = &_error_info_;
38294887Schin 	if (!_opt_infop_)
38304887Schin 		_opt_infop_ = &_opt_info_;
38314887Schin 	if (!opt_info.state)
38324887Schin 		opt_info.state = &state;
38334887Schin #endif
38344887Schin 	if (!oopts)
38354887Schin 		return 0;
38364887Schin 	opt_info.state->pindex = opt_info.index;
38374887Schin 	opt_info.state->poffset = opt_info.offset;
38384887Schin 	if (!opt_info.index)
38394887Schin 	{
38404887Schin 		opt_info.index = 1;
38414887Schin 		opt_info.offset = 0;
38424887Schin 		if (opt_info.state->npass)
38434887Schin 		{
38444887Schin 			opt_info.state->npass = 0;
38454887Schin 			opt_info.state->join = 0;
38464887Schin 		}
38474887Schin 	}
38484887Schin 	if (!argv)
38494887Schin 		cache = 0;
38504887Schin 	else
38514887Schin 		for (pcache = 0, cache = opt_info.state->cache; cache; pcache = cache, cache = cache->next)
38524887Schin 			if (cache->pass.oopts == (char*)oopts)
38534887Schin 				break;
38544887Schin 	if (cache)
38554887Schin 	{
38564887Schin 		if (pcache)
38574887Schin 		{
38584887Schin 			pcache->next = cache->next;
38594887Schin 			cache->next = opt_info.state->cache;
38604887Schin 			opt_info.state->cache = cache;
38614887Schin 		}
38624887Schin 		pass = &cache->pass;
38634887Schin 		opt_info.state->npass = -1;
38644887Schin 	}
38654887Schin 	else
38664887Schin 	{
38674887Schin 		if (!argv)
38684887Schin 			n = opt_info.state->npass ? opt_info.state->npass : 1;
38694887Schin 		else if ((n = opt_info.state->join - 1) < 0)
38704887Schin 			n = 0;
38714887Schin 		if (n >= opt_info.state->npass || opt_info.state->pass[n].oopts != (char*)oopts)
38724887Schin 		{
38734887Schin 			for (m = 0; m < opt_info.state->npass && opt_info.state->pass[m].oopts != (char*)oopts; m++);
38744887Schin 			if (m < opt_info.state->npass)
38754887Schin 				n = m;
38764887Schin 			else
38774887Schin 			{
38784887Schin 				if (n >= elementsof(opt_info.state->pass))
38794887Schin 					n = elementsof(opt_info.state->pass) - 1;
38804887Schin 				init((char*)oopts, &opt_info.state->pass[n]);
38814887Schin 				if (opt_info.state->npass <= n)
38824887Schin 					opt_info.state->npass = n + 1;
38834887Schin 			}
38844887Schin 		}
38854887Schin 		if (!argv)
38864887Schin 			return 0;
38874887Schin 		pass = &opt_info.state->pass[n];
38884887Schin 	}
38894887Schin 	opts = pass->opts;
38904887Schin 	prefix = pass->prefix;
38914887Schin 	version = pass->version;
38924887Schin 	if (!(xp = opt_info.state->xp) || (catalog = pass->catalog) && !X(catalog))
38934887Schin 		catalog = 0;
38944887Schin 	else /* if (!error_info.catalog) */
38954887Schin 		error_info.catalog = catalog;
38964887Schin  again:
38974887Schin 	psp = 0;
38984887Schin 
38994887Schin 	/*
39004887Schin 	 * check if any options remain and determine if the
39014887Schin 	 * next option is short or long
39024887Schin 	 */
39034887Schin 
39044887Schin 	opt_info.assignment = 0;
39054887Schin 	num = 1;
39064887Schin 	w = v = 0;
39074887Schin 	x = 0;
39084887Schin 	for (;;)
39094887Schin 	{
39104887Schin 		if (!opt_info.offset)
39114887Schin 		{
39124887Schin 			/*
39134887Schin 			 * finished with the previous arg
39144887Schin 			 */
39154887Schin 
39164887Schin 			if (opt_info.index == 1 && opt_info.argv != opt_info.state->strv)
39174887Schin 			{
39184887Schin 				opt_info.argv = 0;
39194887Schin 				opt_info.state->argv[0] = 0;
39204887Schin 				if (argv[0] && (opt_info.state->argv[0] = save(argv[0])))
39214887Schin 					opt_info.argv = opt_info.state->argv;
39224887Schin 				opt_info.state->style = STYLE_short;
39234887Schin 			}
39244887Schin 			if (!(s = argv[opt_info.index]))
39254887Schin 				return 0;
39264887Schin 			if (!prefix)
39274887Schin 			{
39284887Schin 				/*
39294887Schin 				 * long with no prefix (dd style)
39304887Schin 				 */
39314887Schin 
39324887Schin 				n = 2;
39334887Schin 				if ((c = *s) != '-' && c != '+')
39344887Schin 					c = '-';
39354887Schin 				else if (*++s == c)
39364887Schin 				{
39374887Schin 					if (!*++s)
39384887Schin 					{
39394887Schin 						opt_info.index++;
39404887Schin 						return 0;
39414887Schin 					}
3942*8462SApril.Chin@Sun.COM 					else if (*s == c)
3943*8462SApril.Chin@Sun.COM 						return 0;
39444887Schin 				}
39454887Schin 				else if (*s == '?')
39464887Schin 					n = 1;
39474887Schin 			}
3948*8462SApril.Chin@Sun.COM 			else if ((c = *s++) != '-' && (c != '+' || !(pass->flags & OPT_plus) && (!(pass->flags & OPT_numeric) || !isdigit(*s))))
39494887Schin 			{
39504887Schin 				if (!(pass->flags & OPT_old) || !isalpha(c))
39514887Schin 					return 0;
39524887Schin 				s--;
39534887Schin 				n = 1;
39544887Schin 				opt_info.offset--;
39554887Schin 			}
39564887Schin 			else if (*s == c)
39574887Schin 			{
39584887Schin 				if (!*++s)
39594887Schin 				{
39604887Schin 					/*
39614887Schin 					 * -- or ++ end of options
39624887Schin 					 */
39634887Schin 
39644887Schin 					opt_info.index++;
39654887Schin 					return 0;
39664887Schin 				}
3967*8462SApril.Chin@Sun.COM 				else if (*s == c)
3968*8462SApril.Chin@Sun.COM 				{
3969*8462SApril.Chin@Sun.COM 					/*
3970*8462SApril.Chin@Sun.COM 					 * ---* or +++* are operands
3971*8462SApril.Chin@Sun.COM 					 */
3972*8462SApril.Chin@Sun.COM 
3973*8462SApril.Chin@Sun.COM 					return 0;
3974*8462SApril.Chin@Sun.COM 				}
39754887Schin 				if (version || *s == '?' || !(pass->flags & OPT_minus))
39764887Schin 				{
39774887Schin 					/*
39784887Schin 					 * long with double prefix
39794887Schin 					 */
39804887Schin 
39814887Schin 					n = 2;
39824887Schin 				}
39834887Schin 				else
39844887Schin 				{
39854887Schin 					/*
39864887Schin 					 * short option char '-'
39874887Schin 					 */
39884887Schin 
39894887Schin 					s--;
39904887Schin 					n = 1;
39914887Schin 				}
39924887Schin 			}
39934887Schin 			else if (prefix == 1 && *s != '?')
39944887Schin 			{
39954887Schin 				/*
39964887Schin 				 * long with single prefix (find style)
39974887Schin 				 */
39984887Schin 
39994887Schin 				n = 2;
40004887Schin 			}
40014887Schin 			else
40024887Schin 			{
40034887Schin 				/*
40044887Schin 				 * short (always with single prefix)
40054887Schin 				 */
40064887Schin 
40074887Schin 				n = 1;
40084887Schin 			}
40094887Schin 
40104887Schin 			/*
40114887Schin 			 * just a prefix is an option (e.g., `-' == stdin)
40124887Schin 			 */
40134887Schin 
40144887Schin 			if (!*s)
40154887Schin 				return 0;
40164887Schin 			if (c == '+')
40174887Schin 				opt_info.arg = 0;
40184887Schin 			if (n == 2)
40194887Schin 			{
40204887Schin 				x = 0;
40214887Schin 				opt_info.state->style = STYLE_long;
40224887Schin 				opt_info.option[0] = opt_info.name[0] = opt_info.name[1] = c;
40234887Schin 				w = &opt_info.name[prefix];
40244887Schin 				if ((*s == 'n' || *s == 'N') && (*(s + 1) == 'o' || *(s + 1) == 'O') && *(s + 2) && *(s + 2) != '=')
40254887Schin 					no = *(s + 2) == '-' ? 3 : 2;
40264887Schin 				else
40274887Schin 					no = 0;
40284887Schin 				for (c = *s; *s; s++)
40294887Schin 				{
40304887Schin 					if (*s == '=')
40314887Schin 					{
40324887Schin 						if (*(s + 1) == '=')
40334887Schin 							s++;
40344887Schin 						if (!isalnum(*(s - 1)) && *(w - 1) == (opt_info.assignment = *(s - 1)))
40354887Schin 							w--;
40364887Schin 						v = ++s;
40374887Schin 						break;
40384887Schin 					}
40394887Schin 					if (w < &opt_info.name[elementsof(opt_info.name) - 1] && *s != ':' && *s != '|' && *s != '[' && *s != ']')
40404887Schin 						*w++ = *s;
40414887Schin 				}
40424887Schin 				*w = 0;
40434887Schin 				w = &opt_info.name[prefix];
40444887Schin 				c = *w;
40454887Schin 				opt_info.offset = 0;
40464887Schin 				opt_info.index++;
40474887Schin 				break;
40484887Schin 			}
40494887Schin 			opt_info.offset++;
40504887Schin 		}
40514887Schin 		if (!argv[opt_info.index])
40524887Schin 			return 0;
40534887Schin 		if (c = argv[opt_info.index][opt_info.offset++])
40544887Schin 		{
40554887Schin 			if ((k = argv[opt_info.index][0]) != '-' && k != '+')
40564887Schin 				k = '-';
40574887Schin 			opt_info.option[0] = opt_info.name[0] = k;
40584887Schin 			opt_info.option[1] = opt_info.name[1] = c;
40594887Schin 			opt_info.option[2] = opt_info.name[2] = 0;
40604887Schin 			break;
40614887Schin 		}
40624887Schin 		opt_info.offset = 0;
40634887Schin 		opt_info.index++;
40644887Schin 	}
40654887Schin 
40664887Schin 	/*
40674887Schin 	 * at this point:
40684887Schin 	 *
40694887Schin 	 *	c	the first character of the option
40704887Schin 	 *	w	long option name if != 0, otherwise short
40714887Schin 	 *	v	long option value (via =) if w != 0
40724887Schin 	 */
40734887Schin 
40744887Schin 	if (c == '?')
40754887Schin 	{
40764887Schin 		/*
40774887Schin 		 * ? always triggers internal help
40784887Schin 		 */
40794887Schin 
40804887Schin 		if (w && !v && (*(w + 1) || !(v = argv[opt_info.index]) || !++opt_info.index))
40814887Schin 			v = w + 1;
40824887Schin 		opt_info.option[1] = c;
40834887Schin 		opt_info.option[2] = 0;
40844887Schin 		if (!w)
40854887Schin 		{
40864887Schin 			opt_info.name[1] = c;
40874887Schin 			opt_info.name[2] = 0;
40884887Schin 		}
40894887Schin 		goto help;
40904887Schin 	}
40914887Schin 	numopt = 0;
40924887Schin 	f = 0;
40934887Schin 	s = opts;
40944887Schin 
40954887Schin 	/*
40964887Schin 	 * no option can start with these characters
40974887Schin 	 */
40984887Schin 
40994887Schin 	if (c == ':' || c == '#' || c == ' ' || c == '[' || c == ']')
41004887Schin 	{
41014887Schin 		if (c != *s)
41024887Schin 			s = "";
41034887Schin 	}
41044887Schin 	else
41054887Schin 	{
41064887Schin 		a = 0;
41074887Schin 		if (!w && (pass->flags & OPT_cache))
41084887Schin 		{
41094887Schin 			if (cache)
41104887Schin 			{
41114887Schin 				if (k = cache->flags[map[c]])
41124887Schin 				{
41134887Schin 					opt_info.arg = 0;
41144887Schin 
41154887Schin 					/*
41164887Schin 					 * this is a ksh getopts workaround
41174887Schin 					 */
41184887Schin 
41194887Schin 					if (opt_info.num != LONG_MIN)
41204887Schin 						opt_info.num = opt_info.number = !(k & OPT_cache_invert);
41214887Schin 					if (!(k & (OPT_cache_string|OPT_cache_numeric)))
41224887Schin 						return c;
41234887Schin 					if (*(opt_info.arg = &argv[opt_info.index++][opt_info.offset]))
41244887Schin 					{
41254887Schin 						if (!(k & OPT_cache_numeric))
41264887Schin 						{
41274887Schin 							opt_info.offset = 0;
41284887Schin 							return c;
41294887Schin 						}
41304887Schin 						opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
41314887Schin 						if (err || e == opt_info.arg)
41324887Schin 						{
41334887Schin 							if (!err && (k & OPT_cache_optional))
41344887Schin 							{
41354887Schin 								opt_info.arg = 0;
41364887Schin 								opt_info.index--;
41374887Schin 								return c;
41384887Schin 							}
41394887Schin 						}
41404887Schin 						else if (*e)
41414887Schin 						{
41424887Schin 							opt_info.offset += e - opt_info.arg;
41434887Schin 							opt_info.index--;
41444887Schin 							return c;
41454887Schin 						}
41464887Schin 						else
41474887Schin 						{
41484887Schin 							opt_info.offset = 0;
41494887Schin 							return c;
41504887Schin 						}
41514887Schin 					}
41524887Schin 					else if (opt_info.arg = argv[opt_info.index])
41534887Schin 					{
41544887Schin 						opt_info.index++;
41554887Schin 						if ((k & OPT_cache_optional) && (*opt_info.arg == '-' || (pass->flags & OPT_plus) && *opt_info.arg == '+') && *(opt_info.arg + 1))
41564887Schin 						{
41574887Schin 							opt_info.arg = 0;
41584887Schin 							opt_info.index--;
41594887Schin 							opt_info.offset = 0;
41604887Schin 							return c;
41614887Schin 						}
41624887Schin 						if (k & OPT_cache_string)
41634887Schin 						{
41644887Schin 							opt_info.offset = 0;
41654887Schin 							return c;
41664887Schin 						}
41674887Schin 						opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
41684887Schin 						if (!err)
41694887Schin 						{
41704887Schin 							if (!*e)
41714887Schin 							{
41724887Schin 								opt_info.offset = 0;
41734887Schin 								return c;
41744887Schin 							}
41754887Schin 							if (k & OPT_cache_optional)
41764887Schin 							{
41774887Schin 								opt_info.arg = 0;
41784887Schin 								opt_info.index--;
41794887Schin 								opt_info.offset = 0;
41804887Schin 								return c;
41814887Schin 							}
41824887Schin 						}
41834887Schin 					}
41844887Schin 					else if (k & OPT_cache_optional)
41854887Schin 					{
41864887Schin 						opt_info.offset = 0;
41874887Schin 						return c;
41884887Schin 					}
41894887Schin 					opt_info.index--;
41904887Schin 				}
41914887Schin 				cache = 0;
41924887Schin 			}
41934887Schin 			else if (cache = newof(0, Optcache_t, 1, 0))
41944887Schin 			{
41954887Schin 				cache->caching = c;
41964887Schin 				c = 0;
41974887Schin 				cache->pass = *pass;
41984887Schin 				cache->next = opt_info.state->cache;
41994887Schin 				opt_info.state->cache = cache;
42004887Schin 			}
42014887Schin 		}
42024887Schin 		else
42034887Schin 			cache = 0;
42044887Schin 		for (;;)
42054887Schin 		{
42064887Schin 			if (!(*(s = next(s, version))) || *s == '\n' || *s == ' ')
42074887Schin 			{
42084887Schin 				if (!(tsp = psp))
42094887Schin 				{
42104887Schin 					if (cache)
42114887Schin 					{
42124887Schin 						/*
42134887Schin 						 * the first loop pass
42144887Schin 						 * initialized the cache
42154887Schin 						 * so one more pass to
42164887Schin 						 * check the cache or
42174887Schin 						 * bail for a full scan
42184887Schin 						 */
42194887Schin 
42204887Schin 						cache->flags[0] = 0;
42214887Schin 						c = cache->caching;
42224887Schin 						cache->caching = 0;
42234887Schin 						cache = 0;
42244887Schin 						s = opts;
42254887Schin 						continue;
42264887Schin 					}
42274887Schin 					if (!x && catalog)
42284887Schin 					{
42294887Schin 						/*
42304887Schin 						 * the first loop pass
42314887Schin 						 * translated long
42324887Schin 						 * options and there
42334887Schin 						 * were no matches so
42344887Schin 						 * one more pass for C
42354887Schin 						 * locale
42364887Schin 						 */
42374887Schin 
42384887Schin 						catalog = 0;
42394887Schin 						s = opts;
42404887Schin 						continue;
42414887Schin 					}
42424887Schin 					s = "";
42434887Schin 					break;
42444887Schin 				}
42454887Schin 				s = psp->ob;
42464887Schin 				psp = psp->next;
42474887Schin 				free(tsp);
42484887Schin 				continue;
42494887Schin 			}
42504887Schin 			if (*s == '\f')
42514887Schin 			{
42524887Schin 				psp = info(psp, s + 1, NiL, opt_info.state->xp);
42534887Schin 				if (psp->nb)
42544887Schin 					s = psp->nb;
42554887Schin 				else
42564887Schin 				{
42574887Schin 					s = psp->ob;
42584887Schin 					psp = psp->next;
42594887Schin 				}
42604887Schin 				continue;
42614887Schin 			}
42624887Schin 			message((-20, "optget: opt %s w %s num %ld", show(s), w, num));
42634887Schin 			if (*s == c && !w)
42644887Schin 				break;
42654887Schin 			else if (*s == '[')
42664887Schin 			{
42674887Schin 				f = s = next(s + 1, version);
42684887Schin 				k = *f;
42694887Schin 				if (k == '+' || k == '-')
42704887Schin 					/* ignore */;
42714887Schin 				else if (k == '[' || version < 1)
42724887Schin 					continue;
42734887Schin 				else if (w && !cache)
42744887Schin 				{
42754887Schin 					nov = no;
42764887Schin 					if (*(s + 1) == '\f' && (vp = opt_info.state->vp))
42774887Schin 					{
42784887Schin 						sfputc(vp, k);
42794887Schin 						s = expand(s + 2, NiL, &t, vp);
42804887Schin 						if (*s)
42814887Schin 							*(f = s - 1) = k;
42824887Schin 						else
42834887Schin 						{
42844887Schin 							f = sfstrbase(vp);
42854887Schin 							if (s = strrchr(f, ':'))
42864887Schin 								f = s - 1;
42874887Schin 							else
42884887Schin 								s = f + 1;
42894887Schin 						}
42904887Schin 					}
42914887Schin 					else
42924887Schin 						t = 0;
42934887Schin 					if (*s != ':')
42944887Schin 						s = skip(s, ':', '?', 0, 1, 0, 0, version);
42954887Schin 					if (*s == ':')
42964887Schin 					{
42974887Schin 						if (catalog)
42984887Schin 						{
42994887Schin 							p = skip(s + 1, '?', 0, 0, 1, 0, 0, version);
43004887Schin 							e = sfprints("%-.*s", p - (s + 1), s + 1);
43014887Schin 							g = T(error_info.id, catalog, e);
43024887Schin 							if (g == e)
43034887Schin 								p = 0;
43044887Schin 							else
43054887Schin 							{
43064887Schin 								sfprintf(xp, ":%s|%s?", g, e);
43074887Schin 								if (!(s = sfstruse(xp)))
43084887Schin 									goto nospace;
43094887Schin 							}
43104887Schin 						}
43114887Schin 						else
43124887Schin 							p = 0;
43134887Schin 						y = w;
43144887Schin 						for (;;)
43154887Schin 						{
43164887Schin 							n = m = 0;
43174887Schin 							e = s + 1;
43184887Schin 							while (*++s)
43194887Schin 							{
43204887Schin 								if (*s == '*' || *s == '\a')
43214887Schin 								{
43224887Schin 									if (*s == '\a')
43234887Schin 										do
43244887Schin 										{
43254887Schin 											if (!*++s)
43264887Schin 											{
43274887Schin 												s--;
43284887Schin 												break;
43294887Schin 											}
43304887Schin 										} while (*s != '\a');
43314887Schin 									j = *(s + 1);
43324887Schin 									if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
43334887Schin 									{
43344887Schin 										while (*w)
43354887Schin 											w++;
43364887Schin 										m = 0;
43374887Schin 										break;
43384887Schin 									}
43394887Schin 									m = 1;
43404887Schin 								}
43414887Schin 								else if (*s == *w || sep(*s) && sep(*w))
43424887Schin 									w++;
43434887Schin 								else if (*w == 0)
43444887Schin 									break;
43454887Schin 								else if (!sep(*s))
43464887Schin 								{
43474887Schin 									if (sep(*w))
43484887Schin 									{
43494887Schin 										if (*++w == *s)
43504887Schin 										{
43514887Schin 											w++;
43524887Schin 											continue;
43534887Schin 										}
43544887Schin 									}
43554887Schin 									else if (w == y || sep(*(w - 1)) || isupper(*(w - 1)) && islower(*w))
43564887Schin 										break;
43574887Schin 									for (q = s; *q && !sep(*q) && *q != '|' && *q != '?' && *q != ']'; q++);
43584887Schin 									if (!sep(*q))
43594887Schin 										break;
43604887Schin 									for (s = q; w > y && *w != *(s + 1); w--);
43614887Schin 								}
43624887Schin 								else if (*w != *(s + 1))
43634887Schin 									break;
43644887Schin 							}
43654887Schin 							if (!*w)
43664887Schin 							{
43674887Schin 								nov = 0;
43684887Schin 								break;
43694887Schin 							}
43704887Schin 							if (n = no)
43714887Schin 							{
43724887Schin 								m = 0;
43734887Schin 								s = e - 1;
43744887Schin 								w = y + n;
43754887Schin 								while (*++s)
43764887Schin 								{
43774887Schin 									if (*s == '*' || *s == '\a')
43784887Schin 									{
43794887Schin 										if (*s == '\a')
43804887Schin 											do
43814887Schin 											{
43824887Schin 												if (!*++s)
43834887Schin 												{
43844887Schin 													s--;
43854887Schin 													break;
43864887Schin 												}
43874887Schin 											} while (*s != '\a');
43884887Schin 										j = *(s + 1);
43894887Schin 										if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
43904887Schin 										{
43914887Schin 											while (*w)
43924887Schin 												w++;
43934887Schin 											m = 0;
43944887Schin 											break;
43954887Schin 										}
43964887Schin 										m = 1;
43974887Schin 									}
43984887Schin 									else if (*s == *w || sep(*s) && sep(*w))
43994887Schin 										w++;
44004887Schin 									else if (*w == 0)
44014887Schin 										break;
44024887Schin 									else if (!sep(*s))
44034887Schin 									{
44044887Schin 										if (sep(*w))
44054887Schin 										{
44064887Schin 											if (*++w == *s)
44074887Schin 											{
44084887Schin 												w++;
44094887Schin 												continue;
44104887Schin 											}
44114887Schin 										}
44124887Schin 										else if (w == y || sep(*(w - 1)) || isupper(*(w - 1)) && islower(*w))
44134887Schin 											break;
44144887Schin 										for (q = s; *q && !sep(*q) && *q != '|' && *q != '?' && *q != ']'; q++);
44154887Schin 										if (!sep(*q))
44164887Schin 											break;
44174887Schin 										for (s = q; w > y && *w != *(s + 1); w--);
44184887Schin 									}
44194887Schin 									else if (*w != *(s + 1))
44204887Schin 										break;
44214887Schin 								}
44224887Schin 								if (!*w)
44234887Schin 									break;
44244887Schin 							}
44254887Schin 							if (*(s = skip(s, ':', '|', '?', 1, 0, 0, version)) != '|')
44264887Schin 								break;
44274887Schin 							w = y;
44284887Schin 						}
44294887Schin 						if (p)
44304887Schin 							s = p;
44314887Schin 						if (!*w)
44324887Schin 						{
44334887Schin 							if (n)
44344887Schin 								num = 0;
44354887Schin 							if (!(n = (m || *s == ':' || *s == '|' || *s == '?' || *s == ']' || *s == 0)) && x)
44364887Schin 							{
44374887Schin 								psp = pop(psp);
44384887Schin 								return opterror("?", version, catalog, 0);
44394887Schin 							}
44404887Schin 							for (x = k; *(f + 1) == '|' && (j = *(f + 2)) && j != '!' && j != '=' && j != ':' && j != '?' && j != ']'; f += 2);
44414887Schin 							if (*f == ':')
44424887Schin 							{
44434887Schin 								x = -1;
44444887Schin 								opt_info.option[1] = '-';
44454887Schin 								opt_info.option[2] = 0;
44464887Schin 							}
44474887Schin 							else if (*(f + 1) == ':' || *(f + 1) == '!' && *(f + 2) == ':')
44484887Schin 							{
44494887Schin 								opt_info.option[1] = x;
44504887Schin 								opt_info.option[2] = 0;
44514887Schin 							}
44524887Schin 							else
44534887Schin 							{
44544887Schin 								a = f;
44554887Schin 								if (*a == '=')
44564887Schin 									a++;
44574887Schin 								else
44584887Schin 								{
44594887Schin 									if (*(a + 1) == '!')
44604887Schin 										a++;
44614887Schin 									if (*(a + 1) == '=')
44624887Schin 										a += 2;
44634887Schin 								}
44644887Schin 								x = -strtol(a, &b, 0);
44654887Schin 								if ((b - a) > sizeof(opt_info.option) - 2)
44664887Schin 									b = a + sizeof(opt_info.option) - 2;
44674887Schin 								memcpy(&opt_info.option[1], a, b - a);
44684887Schin 								opt_info.option[b - a + 1] = 0;
44694887Schin 							}
44704887Schin 							b = e;
44714887Schin 							if (t)
44724887Schin 							{
44734887Schin 								s = t;
44744887Schin 								t = 0;
44754887Schin 							}
44764887Schin 							a = s = skip(s, 0, 0, 0, 1, 0, 0, version);
44774887Schin 							if (n)
44784887Schin 							{
44794887Schin 								w = y;
44804887Schin 								break;
44814887Schin 							}
44824887Schin 						}
44834887Schin 						w = y;
44844887Schin 					}
44854887Schin 					else if (k == c && prefix == 1)
44864887Schin 					{
44874887Schin 						w = 0;
44884887Schin 						opt_info.name[1] = c;
44894887Schin 						opt_info.name[2] = 0;
44904887Schin 						opt_info.offset = 2;
44914887Schin 						opt_info.index--;
44924887Schin 						break;
44934887Schin 					}
44944887Schin 					if (t)
44954887Schin 					{
44964887Schin 						s = t;
44974887Schin 						if (a)
44984887Schin 							a = t;
44994887Schin 					}
45004887Schin 				}
45014887Schin 				s = skip(s, 0, 0, 0, 1, 0, 1, version);
45024887Schin 				if (*s == GO)
45034887Schin 					s = skip(s + 1, 0, 0, 0, 0, 1, 1, version);
45044887Schin 				if (cache)
45054887Schin 				{
45064887Schin 					m = OPT_cache_flag;
45074887Schin 					v = s;
45084887Schin 					if (*v == '#')
45094887Schin 					{
45104887Schin 						v++;
45114887Schin 						m |= OPT_cache_numeric;
45124887Schin 					}
45134887Schin 					else if (*v == ':')
45144887Schin 					{
45154887Schin 						v++;
45164887Schin 						m |= OPT_cache_string;
45174887Schin 					}
45184887Schin 					if (*v == '?')
45194887Schin 					{
45204887Schin 						v++;
45214887Schin 						m |= OPT_cache_optional;
45224887Schin 					}
45234887Schin 					else if (*v == *(v - 1))
45244887Schin 						v++;
45254887Schin 					if (*(v = next(v, version)) == '[')
45264887Schin 						v = skip(v + 1, 0, 0, 0, 1, 0, 1, version);
45274887Schin 					if (*v != GO)
45284887Schin 					{
45294887Schin 						v = f;
45304887Schin 						for (;;)
45314887Schin 						{
45324887Schin 							if (isdigit(*f) && isdigit(*(f + 1)))
45334887Schin 								while (isdigit(*(f + 1)))
45344887Schin 									f++;
45354887Schin 							else if (*(f + 1) == '=')
45364887Schin 								break;
45374887Schin 							else
45384887Schin 								cache->flags[map[*f]] = m;
45394887Schin 							j = 0;
45404887Schin 							while (*(f + 1) == '|')
45414887Schin 							{
45424887Schin 								f += 2;
45434887Schin 								if (!(j = *f) || j == '!' || j == '=' || j == ':' || j == '?' || j == ']')
45444887Schin 									break;
45454887Schin 								cache->flags[map[j]] = m;
45464887Schin 							}
45474887Schin 							if (j != '!' || (m & OPT_cache_invert))
45484887Schin 								break;
45494887Schin 							f = v;
45504887Schin 							m |= OPT_cache_invert;
45514887Schin 						}
45524887Schin 					}
45534887Schin 				}
45544887Schin 				else
45554887Schin 				{
45564887Schin 					m = 0;
45574887Schin 					if (!w)
45584887Schin 					{
45594887Schin 						if (isdigit(*f) && isdigit(*(f + 1)))
45604887Schin 							k = -1;
45614887Schin 						if (c == k)
45624887Schin 							m = 1;
45634887Schin 						while (*(f + 1) == '|')
45644887Schin 						{
45654887Schin 							f += 2;
45664887Schin 							if (!(j = *f))
45674887Schin 							{
45684887Schin 								m = 0;
45694887Schin 								break;
45704887Schin 							}
45714887Schin 							else if (j == c)
45724887Schin 								m = 1;
45734887Schin 							else if (j == '!' || j == '=' || j == ':' || j == '?' || j == ']')
45744887Schin 								break;
45754887Schin 						}
45764887Schin 					}
45774887Schin 					if (m)
45784887Schin 					{
45794887Schin 						s--;
45804887Schin 						if (*++f == '!')
45814887Schin 						{
45824887Schin 							f++;
45834887Schin 							num = 0;
45844887Schin 						}
45854887Schin 						if (*f == '=')
45864887Schin 						{
45874887Schin 							c = -strtol(++f, &b, 0);
45884887Schin 							if ((b - f) > sizeof(opt_info.option) - 2)
45894887Schin 								b = f + sizeof(opt_info.option) - 2;
45904887Schin 							memcpy(&opt_info.option[1], f, b - f);
45914887Schin 							opt_info.option[b - f + 1] = 0;
45924887Schin 						}
45934887Schin 						else
45944887Schin 							c = k;
45954887Schin 						break;
45964887Schin 					}
45974887Schin 				}
45984887Schin 				if (*s == '#')
45994887Schin 				{
46004887Schin 					if (!numopt && s > opts)
46014887Schin 					{
46024887Schin 						numopt = s - 1;
46034887Schin 						numchr = k;
46044887Schin 						if (*f == ':')
46054887Schin 							numchr = -1;
46064887Schin 						else if (*(f + 1) != ':' && *(f + 1) != '!' && *(f + 1) != ']')
46074887Schin 						{
46084887Schin 							a = f;
46094887Schin 							if (*a == '=')
46104887Schin 								a++;
46114887Schin 							else
46124887Schin 							{
46134887Schin 								if (*(a + 1) == '!')
46144887Schin 									a++;
46154887Schin 								if (*(a + 1) == '=')
46164887Schin 									a += 2;
46174887Schin 							}
46184887Schin 							numchr = -strtol(a, NiL, 0);
46194887Schin 						}
46204887Schin 					}
46214887Schin 				}
46224887Schin 				else if (*s != ':')
46234887Schin 					continue;
46244887Schin 			}
46254887Schin 			else if (*s == ']')
46264887Schin 			{
46274887Schin 				s++;
46284887Schin 				continue;
46294887Schin 			}
46304887Schin 			else if (*s == '#')
46314887Schin 			{
46324887Schin 				if (!numopt && s > opts)
46334887Schin 					numchr = *(numopt = s - 1);
46344887Schin 			}
46354887Schin 			else if (*s != ':')
46364887Schin 			{
46374887Schin 				if (cache)
46384887Schin 				{
46394887Schin 					m = OPT_cache_flag;
46404887Schin 					if (*(s + 1) == '#')
46414887Schin 					{
46424887Schin 						m |= OPT_cache_numeric;
46434887Schin 						if (*(s + 2) == '?')
46444887Schin 							m |= OPT_cache_optional;
46454887Schin 					}
46464887Schin 					else if (*(s + 1) == ':')
46474887Schin 					{
46484887Schin 						m |= OPT_cache_string;
46494887Schin 						if (*(s + 2) == '?')
46504887Schin 							m |= OPT_cache_optional;
46514887Schin 					}
46524887Schin 					cache->flags[map[*s]] = m;
46534887Schin 				}
46544887Schin 				s++;
46554887Schin 				continue;
46564887Schin 			}
46574887Schin 			message((-21, "optget: opt %s", show(s)));
46584887Schin 			if (*++s == '?' || *s == *(s - 1))
46594887Schin 				s++;
46604887Schin 			if (*(s = next(s, version)) == '[')
46614887Schin 			{
46624887Schin 				s = skip(s + 1, 0, 0, 0, 1, 0, 1, version);
46634887Schin 				if (*s == GO)
46644887Schin 					s = skip(s + 1, 0, 0, 0, 0, 1, 1, version);
46654887Schin 			}
46664887Schin 		}
46674887Schin 		if (w && x)
46684887Schin 		{
46694887Schin 			s = skip(b, '|', '?', 0, 1, 0, 0, version);
46704887Schin 			if (v && (a == 0 || *a == 0 || *(a + 1) != ':' && *(a + 1) != '#') && (*v == '0' || *v == '1') && !*(v + 1))
46714887Schin 			{
46724887Schin 				if (*v == '0')
46734887Schin 					num = !num;
46744887Schin 				v = 0;
46754887Schin 			}
46764887Schin 			if ((s - b) >= elementsof(opt_info.name))
46774887Schin 				s = b + elementsof(opt_info.name) - 1;
46784887Schin 			for (;;)
46794887Schin 			{
46804887Schin 				if (b >= s)
46814887Schin 				{
46824887Schin 					*w = 0;
46834887Schin 					break;
46844887Schin 				}
46854887Schin 				if (*b == '*')
46864887Schin 					break;
46874887Schin 				*w++ = *b++;
46884887Schin 			}
46894887Schin 			if (!num && v)
46904887Schin 				return opterror(no ? "!" : "=", version, catalog, 0);
46914887Schin 			w = &opt_info.name[prefix];
46924887Schin 			c = x;
46934887Schin 			s = a;
46944887Schin 		}
46954887Schin 	}
46964887Schin 	if (!*s)
46974887Schin 	{
46984887Schin 		if (w)
46994887Schin 		{
47004887Schin 			if (hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), w))
47014887Schin 			{
47024887Schin 				if (!v)
47034887Schin 					v = (char*)hp->name;
47044887Schin 				goto help;
47054887Schin 			}
47064887Schin 			if (!v)
47074887Schin 			{
47084887Schin 				v = opt_info.name;
47094887Schin 				goto help;
47104887Schin 			}
47114887Schin 		}
4712*8462SApril.Chin@Sun.COM 		if (w || !isdigit(c) || !numopt || !(pass->flags & OPT_numeric))
47134887Schin 		{
47144887Schin 			pop(psp);
47154887Schin 			return opterror("", version, catalog, 0);
47164887Schin 		}
47174887Schin 		s = numopt;
47184887Schin 		c = opt_info.option[1] = numchr;
47194887Schin 		opt_info.offset--;
47204887Schin 	}
47214887Schin 	opt_info.arg = 0;
47224887Schin 
47234887Schin 	/*
47244887Schin 	 * this is a ksh getopts workaround
47254887Schin 	 */
47264887Schin 
47274887Schin 	if (opt_info.num != LONG_MIN)
47284887Schin 		opt_info.num = opt_info.number = num;
47294887Schin 	if ((n = *++s == '#') || *s == ':' || w && !nov && v && (optnumber(v, &e, NiL), n = !*e))
47304887Schin 	{
47314887Schin 		if (w)
47324887Schin 		{
47334887Schin 			if (nov)
47344887Schin 			{
47354887Schin 				if (v)
47364887Schin 				{
47374887Schin 					pop(psp);
47384887Schin 					return opterror("!", version, catalog, 0);
47394887Schin 				}
47404887Schin 				opt_info.num = opt_info.number = 0;
47414887Schin 			}
47424887Schin 			else
47434887Schin 			{
47444887Schin 				if (!v && *(s + 1) != '?' && (v = argv[opt_info.index]))
47454887Schin 				{
47464887Schin 					opt_info.index++;
47474887Schin 					opt_info.offset = 0;
47484887Schin 				}
47494887Schin 				if (!(opt_info.arg = v) || (*v == '0' || *v == '1') && !*(v + 1))
47504887Schin 				{
47514887Schin 					if (*(s + 1) != '?')
47524887Schin 					{
47534887Schin 						if (!opt_info.arg)
47544887Schin 						{
47554887Schin 							pop(psp);
47564887Schin 							return opterror(s, version, catalog, 0);
47574887Schin 						}
47584887Schin 					}
47594887Schin 					else if (*(t = next(s + 2, version)) == '[')
47604887Schin 						while (*(t = skip(t, ':', 0, 0, 1, 0, 0, version)) == ':')
47614887Schin 							if (*++t == '!')
47624887Schin 							{
47634887Schin 								if (!v || *v == '1')
47644887Schin 								{
47654887Schin 									e = skip(t, ':', '?', ']', 1, 0, 0, version);
47664887Schin 									opt_info.arg = sfprints("%-.*s", e - t - 1, t + 1);
47674887Schin 								}
47684887Schin 								else
47694887Schin 								{
47704887Schin 									opt_info.arg = 0;
47714887Schin 									opt_info.num = opt_info.number = 0;
47724887Schin 								}
47734887Schin 								break;
47744887Schin 							}
47754887Schin 				}
47764887Schin 				if (opt_info.arg && n)
47774887Schin 				{
47784887Schin 					opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
47794887Schin 					if (err || e == opt_info.arg)
47804887Schin 					{
47814887Schin 						pop(psp);
47824887Schin 						return opterror(s, version, catalog, err);
47834887Schin 					}
47844887Schin 				}
47854887Schin 			}
47864887Schin 			goto optarg;
47874887Schin 		}
47884887Schin 		else if (*(opt_info.arg = &argv[opt_info.index++][opt_info.offset]))
47894887Schin 		{
47904887Schin 			if (*s == '#')
47914887Schin 			{
47924887Schin 				opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
47934887Schin 				if (err || e == opt_info.arg)
47944887Schin 				{
47954887Schin 					if (!err && *(s + 1) == '?')
47964887Schin 					{
47974887Schin 						opt_info.arg = 0;
47984887Schin 						opt_info.index--;
47994887Schin 					}
48004887Schin 					else
48014887Schin 					{
48024887Schin 						opt_info.offset = 0;
48034887Schin 						c = opterror(s, version, catalog, err);
48044887Schin 					}
48054887Schin 					pop(psp);
48064887Schin 					return c;
48074887Schin 				}
48084887Schin 				else if (*e)
48094887Schin 				{
48104887Schin 					opt_info.offset += e - opt_info.arg;
48114887Schin 					opt_info.index--;
48124887Schin 					pop(psp);
48134887Schin 					return c;
48144887Schin 				}
48154887Schin 			}
48164887Schin 		}
48174887Schin 		else if (opt_info.arg = argv[opt_info.index])
48184887Schin 		{
48194887Schin 			opt_info.index++;
48204887Schin 			if (*(s + 1) == '?' && (*opt_info.arg == '-' || (pass->flags & OPT_plus) && *opt_info.arg == '+') && *(opt_info.arg + 1))
48214887Schin 			{
48224887Schin 				opt_info.index--;
48234887Schin 				opt_info.arg = 0;
48244887Schin 			}
48254887Schin 			else if (*s == '#')
48264887Schin 			{
48274887Schin 				opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
48284887Schin 				if (err || *e)
48294887Schin 				{
48304887Schin 					if (!err && *(s + 1) == '?')
48314887Schin 					{
48324887Schin 						opt_info.arg = 0;
48334887Schin 						opt_info.index--;
48344887Schin 					}
48354887Schin 					else
48364887Schin 					{
48374887Schin 						pop(psp);
48384887Schin 						opt_info.offset = 0;
48394887Schin 						return opterror(s, version, catalog, err);
48404887Schin 					}
48414887Schin 				}
48424887Schin 			}
48434887Schin 		}
48444887Schin 		else if (*(s + 1) != '?')
48454887Schin 		{
48464887Schin 			opt_info.index--;
48474887Schin 			pop(psp);
48484887Schin 			return opterror(s, version, catalog, 0);
48494887Schin 		}
48504887Schin 		opt_info.offset = 0;
48514887Schin 	optarg:
48524887Schin 		if (*s == ':' && *(s = skip(s, 0, 0, 0, 1, 0, 1, version)) == GO && *(s = next(s + 1, version)) == '[' && isalnum(*(s + 1)))
48534887Schin 		{
48544887Schin 			x = 0;
48554887Schin 			if (opt_info.arg)
48564887Schin 			{
48574887Schin 				do
48584887Schin 				{
48594887Schin 					w = y = opt_info.arg;
48604887Schin 					f = s = next(s + 1, version);
48614887Schin 					k = *f;
48624887Schin 					if (k == *w && isalpha(k) && !*(w + 1))
48634887Schin 					{
48644887Schin 						x = k;
48654887Schin 						break;
48664887Schin 					}
48674887Schin 					if (*s == '+' || *s == '-')
48684887Schin 						continue;
48694887Schin 					else if (*s == '[' || version < 1)
48704887Schin 						continue;
48714887Schin 					else
48724887Schin 					{
48734887Schin 						if (*s != ':')
48744887Schin 							s = skip(s, ':', '?', 0, 1, 0, 0, version);
48754887Schin 						if (*s == ':')
48764887Schin 						{
48774887Schin 							if (catalog)
48784887Schin 							{
48794887Schin 								p = skip(s + 1, '?', 0, 0, 1, 0, 0, version);
48804887Schin 								e = sfprints("%-.*s", p - (s + 1), s + 1);
48814887Schin 								b = T(error_info.id, catalog, e);
48824887Schin 								if (b == e)
48834887Schin 									p = 0;
48844887Schin 								else
48854887Schin 								{
48864887Schin 									sfprintf(xp, ":%s|%s?", b, e);
48874887Schin 									if (!(s = sfstruse(xp)))
48884887Schin 										goto nospace;
48894887Schin 								}
48904887Schin 							}
48914887Schin 							else
48924887Schin 								p = 0;
48934887Schin 							for (;;)
48944887Schin 							{
48954887Schin 								n = m = 0;
48964887Schin 								e = s + 1;
48974887Schin 								while (*++s)
48984887Schin 								{
48994887Schin 									if (*s == '*' || *s == '\a')
49004887Schin 									{
49014887Schin 										if (*s == '\a')
49024887Schin 											do
49034887Schin 											{
49044887Schin 												if (!*++s)
49054887Schin 												{
49064887Schin 													s--;
49074887Schin 													break;
49084887Schin 												}
49094887Schin 											} while (*s != '\a');
49104887Schin 										j = *(s + 1);
49114887Schin 										if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
49124887Schin 										{
49134887Schin 											while (*w)
49144887Schin 												w++;
49154887Schin 											m = 0;
49164887Schin 											break;
49174887Schin 										}
49184887Schin 										m = 1;
49194887Schin 									}
49204887Schin 									else if (*s == *w || sep(*s) && sep(*w))
49214887Schin 										w++;
49224887Schin 									else if (*w == 0)
49234887Schin 										break;
49244887Schin 									else if (!sep(*s))
49254887Schin 									{
49264887Schin 										if (sep(*w))
49274887Schin 										{
49284887Schin 											if (*++w == *s)
49294887Schin 											{
49304887Schin 												w++;
49314887Schin 												continue;
49324887Schin 											}
49334887Schin 										}
49344887Schin 										else if (w == y || sep(*(w - 1)) || isupper(*(w - 1)) && islower(*w))
49354887Schin 											break;
49364887Schin 										for (q = s; *q && !sep(*q) && *q != '|' && *q != '?' && *q != ']'; q++);
49374887Schin 										if (!sep(*q))
49384887Schin 											break;
49394887Schin 										for (s = q; w > y && *w != *(s + 1); w--);
49404887Schin 									}
49414887Schin 									else if (*w != *(s + 1))
49424887Schin 										break;
49434887Schin 								}
49444887Schin 								if (!*w)
49454887Schin 								{
49464887Schin 									nov = 0;
49474887Schin 									break;
49484887Schin 								}
49494887Schin 								if (*(s = skip(s, ':', '|', '?', 1, 0, 0, version)) != '|')
49504887Schin 									break;
49514887Schin 								w = y;
49524887Schin 							}
49534887Schin 							if (p)
49544887Schin 								s = p;
49554887Schin 							if (!*w)
49564887Schin 							{
49574887Schin 								if (n)
49584887Schin 									num = 0;
49594887Schin 								if (!(n = (m || *s == ':' || *s == '|' || *s == '?' || *s == ']')) && x)
49604887Schin 								{
49614887Schin 									pop(psp);
49624887Schin 									return opterror("&", version, catalog, 0);
49634887Schin 								}
49644887Schin 								for (x = k; *(f + 1) == '|' && (j = *(f + 2)) && j != '!' && j != '=' && j != ':' && j != '?' && j != ']'; f += 2);
49654887Schin 								if (*f == ':')
49664887Schin 									x = -1;
49674887Schin 								else if (*(f + 1) == ':' || *(f + 1) == '!' && *(f + 2) == ':')
49684887Schin 									/* ok */;
49694887Schin 								else
49704887Schin 								{
49714887Schin 									a = f;
49724887Schin 									if (*a == '=')
49734887Schin 										a++;
49744887Schin 									else
49754887Schin 									{
49764887Schin 										if (*(a + 1) == '!')
49774887Schin 											a++;
49784887Schin 										if (*(a + 1) == '=')
49794887Schin 											a += 2;
49804887Schin 									}
49814887Schin 									x = -strtol(a, &b, 0);
49824887Schin 								}
49834887Schin 								b = e;
49844887Schin 								a = s = skip(s, 0, 0, 0, 1, 0, 0, version);
49854887Schin 								if (n)
49864887Schin 									break;
49874887Schin 							}
49884887Schin 						}
49894887Schin 					}
49904887Schin 				} while (*(s = skip(s, 0, 0, 0, 1, 0, 1, version)) == '[');
49914887Schin 				if (!(opt_info.num = opt_info.number = x))
49924887Schin 				{
49934887Schin 					pop(psp);
49944887Schin 					return opterror("*", version, catalog, 0);
49954887Schin 				}
49964887Schin 			}
49974887Schin 		}
49984887Schin 	}
49994887Schin 	else if (w && v)
50004887Schin 	{
50014887Schin 		pop(psp);
50024887Schin 		return opterror("=", version, catalog, 0);
50034887Schin 	}
50044887Schin 	else
50054887Schin 	{
50064887Schin 		opt_info.num = opt_info.number = num;
50074887Schin 		if (!w && !argv[opt_info.index][opt_info.offset])
50084887Schin 		{
50094887Schin 			opt_info.offset = 0;
50104887Schin 			opt_info.index++;
50114887Schin 		}
50124887Schin 	}
50134887Schin 	pop(psp);
50144887Schin 	return c;
50154887Schin  help:
50164887Schin 	if (v && *v == '?' && *(v + 1) == '?' && *(v + 2))
50174887Schin 	{
50184887Schin 		s = v + 2;
50194887Schin 		if ((s[0] == 'n' || s[0] == 'N') && (s[1] == 'o' || s[1] == 'O'))
50204887Schin 		{
50214887Schin 			s += 2;
50224887Schin 			n = -1;
50234887Schin 		}
50244887Schin 		else
50254887Schin 			n = 1;
50264887Schin 		if (hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), s))
50274887Schin 		{
50284887Schin 			if (hp->style < STYLE_man || !(s = argv[opt_info.index]) || s[0] != '-' || s[1] != '-' || !s[2])
50294887Schin 			{
50304887Schin 				opt_info.arg = sfprints("\fversion=%d", version);
50314887Schin 				pop(psp);
50324887Schin 				return '?';
50334887Schin 			}
50344887Schin 			opt_info.state->force = hp->style;
50354887Schin 		}
50364887Schin 		else if (match(s, "ESC", -1, NiL) || match(s, "EMPHASIS", -1, NiL))
50374887Schin 			opt_info.state->emphasis = n;
50384887Schin 		else if (match(s, "PREFORMAT", -1, NiL))
50394887Schin 			opt_info.state->flags |= OPT_preformat;
50404887Schin 		else if (match(s, "TEST", -1, NiL))
50414887Schin 		{
50424887Schin 			opt_info.state->width = OPT_WIDTH;
50434887Schin 			opt_info.state->emphasis = 1;
50444887Schin 		}
50454887Schin 		else
50464887Schin 		{
50474887Schin 			pop(psp);
50484887Schin 			return opterror(v, version, catalog, 0);
50494887Schin 		}
50504887Schin 		psp = pop(psp);
50514887Schin 		if (argv == opt_info.state->strv)
50524887Schin 			return '#';
50534887Schin 		goto again;
50544887Schin 	}
50554887Schin 	if ((opt_info.arg = opthelp(NiL, v)) == (char*)unknown)
50564887Schin 	{
50574887Schin 		pop(psp);
50584887Schin 		return opterror(v, version, catalog, 0);
50594887Schin 	}
50604887Schin 	pop(psp);
50614887Schin 	return '?';
50624887Schin  nospace:
50634887Schin 	pop(psp);
50644887Schin 	return opterror(NiL, 0, NiL, 0);
50654887Schin }
50664887Schin 
50674887Schin /*
50684887Schin  * parse long options with 0,1,2 leading '-' or '+' from string and pass to optget()
50694887Schin  * syntax is the unquoted
50704887Schin  *
50714887Schin  *	<length> [-|+|--|++]<name>[[-+:|&=]=<value>\n (or \0 for the last)
50724887Schin  *
50734887Schin  * or the quoted
50744887Schin  *
50754887Schin  *	[-|+|--|++][no]name[[-+:|&=]=['"{(]value[)}"']][, ]...
50764887Schin  *
50774887Schin  * with \x escapes passed to chresc()
50784887Schin  *
50794887Schin  * return '#' for `label:', with opt_info.name==label
50804887Schin  * str[opt_info.offset]	next arg
50814887Schin  *
50824887Schin  *	optstr(s, 0)
50834887Schin  *		return '-' if arg, 0 otherwise
50844887Schin  *	optstr(0, opts)
50854887Schin  *		use previous parsed str
50864887Schin  */
50874887Schin 
50884887Schin int
50894887Schin optstr(const char* str, const char* opts)
50904887Schin {
50914887Schin 	register char*		s = (char*)str;
50924887Schin 	register Sfio_t*	mp;
50934887Schin 	register int		c;
50944887Schin 	register int		ql;
50954887Schin 	register int		qr;
50964887Schin 	register int		qc;
50974887Schin 	int			v;
50984887Schin 	char*			e;
50994887Schin 
51004887Schin  again:
51014887Schin 	if (s)
51024887Schin 	{
51034887Schin 		if (!(mp = opt_info.state->strp) && !(mp = opt_info.state->strp = sfstropen()))
51044887Schin 			return 0;
51054887Schin 		if (opt_info.state->str != s)
51064887Schin 			opt_info.state->str = s;
51074887Schin 		else if (opt_info.index == 1)
51084887Schin 			s += opt_info.offset;
51094887Schin 		while (*s == ',' || *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')
51104887Schin 			s++;
51114887Schin 		if (!*s)
51124887Schin 		{
51134887Schin 			opt_info.state->str = 0;
51144887Schin 			return 0;
51154887Schin 		}
51164887Schin 		if (*s == '-' || *s == '+')
51174887Schin 		{
51184887Schin 			c = *s++;
51194887Schin 			sfputc(mp, c);
51204887Schin 			if (*s == c)
51214887Schin 			{
51224887Schin 				sfputc(mp, c);
51234887Schin 				s++;
51244887Schin 			}
51254887Schin 		}
51264887Schin 		else
51274887Schin 		{
51284887Schin 			sfputc(mp, '-');
51294887Schin 			sfputc(mp, '-');
51304887Schin 		}
51314887Schin 		if (isdigit(*s) && (v = (int)strtol(s, &e, 10)) > 1 && isspace(*e) && --v <= strlen(s) && (s[v] == 0 || s[v] == '\n'))
51324887Schin 		{
51334887Schin 			s += v;
51344887Schin 			while (isspace(*++e));
51354887Schin 			sfwrite(mp, e, s - e);
51364887Schin 		}
51374887Schin 		else
51384887Schin 		{
51394887Schin 			while (*s && *s != ',' && *s != ' ' && *s != '\t' && *s != '\n' && *s != '\r' && *s != '=' && *s != ':')
51404887Schin 				sfputc(mp, *s++);
51414887Schin 			if ((c = *s) == ':' && *(s + 1) != '=')
51424887Schin 			{
51434887Schin 				opt_info.index = 1;
51444887Schin 				opt_info.offset = ++s - (char*)str;
51454887Schin 				if (!(s = sfstruse(mp)))
51464887Schin 					goto nospace;
51474887Schin 				s += 2;
51484887Schin 				e = opt_info.name;
51494887Schin 				while (e < &opt_info.name[sizeof(opt_info.name)-1] && (*e++ = *s++));
51504887Schin 				opt_info.arg = 0;
51514887Schin 				opt_info.num = opt_info.number = 0;
51524887Schin 				opt_info.option[0] = ':';
51534887Schin 				opt_info.option[1] = 0;
51544887Schin 				return '#';
51554887Schin 			}
51564887Schin 			if (c == ':' || c == '=')
51574887Schin 			{
51584887Schin 				sfputc(mp, c);
51594887Schin 				ql = qr = 0;
51604887Schin 				while (c = *++s)
51614887Schin 				{
51624887Schin 					if (c == '\\')
51634887Schin 					{
51644887Schin 						sfputc(mp, chresc(s, &e));
51654887Schin 						s = e - 1;
51664887Schin 					}
51674887Schin 					else if (c == qr)
51684887Schin 					{
51694887Schin 						if (qr != ql)
51704887Schin 							sfputc(mp, c);
51714887Schin 						if (--qc <= 0)
51724887Schin 							qr = ql = 0;
51734887Schin 					}
51744887Schin 					else if (c == ql)
51754887Schin 					{
51764887Schin 						sfputc(mp, c);
51774887Schin 						qc++;
51784887Schin 					}
51794887Schin 					else if (qr)
51804887Schin 						sfputc(mp, c);
51814887Schin 					else if (c == ',' || c == ' ' || c == '\t' || c == '\n' || c == '\r')
51824887Schin 						break;
51834887Schin 					else if (c == '"' || c == '\'')
51844887Schin 					{
51854887Schin 						ql = qr = c;
51864887Schin 						qc = 1;
51874887Schin 					}
51884887Schin 					else
51894887Schin 					{
51904887Schin 						sfputc(mp, c);
51914887Schin 						if (c == GO)
51924887Schin 						{
51934887Schin 							ql = c;
51944887Schin 							qr = OG;
51954887Schin 							qc = 1;
51964887Schin 						}
51974887Schin 						else if (c == '(')
51984887Schin 						{
51994887Schin 							ql = c;
52004887Schin 							qr = ')';
52014887Schin 							qc = 1;
52024887Schin 						}
52034887Schin 					}
52044887Schin 				}
52054887Schin 			}
52064887Schin 		}
52074887Schin 		opt_info.argv = opt_info.state->strv;
52084887Schin 		opt_info.state->strv[0] = T(NiL, ID, "option");
52094887Schin 		if (!(opt_info.state->strv[1] = sfstruse(mp)))
52104887Schin 			goto nospace;
52114887Schin 		opt_info.state->strv[2] = 0;
52124887Schin 		opt_info.offset = s - (char*)str;
52134887Schin 	}
52144887Schin 	if (opts)
52154887Schin 	{
52164887Schin 		if (!opt_info.state->strv[1])
52174887Schin 		{
52184887Schin 			opt_info.state->str = 0;
52194887Schin 			return 0;
52204887Schin 		}
52214887Schin 		opt_info.index = 1;
52224887Schin 		v = opt_info.offset;
52234887Schin 		opt_info.offset = 0;
52244887Schin 		c = optget(opt_info.state->strv, opts);
52254887Schin 		opt_info.index = 1;
52264887Schin 		opt_info.offset = v;
52274887Schin 		if (c == '#')
52284887Schin 		{
52294887Schin 			s = opt_info.state->str;
52304887Schin 			goto again;
52314887Schin 		}
52324887Schin 		if ((c == '?' || c == ':') && (opt_info.arg[0] == '-' && opt_info.arg[1] == '-'))
52334887Schin 			opt_info.arg += 2;
52344887Schin 		s = opt_info.name;
52354887Schin 		if (*s++ == '-' && *s++ == '-' && *s)
52364887Schin 		{
52374887Schin 			e = opt_info.name;
52384887Schin 			while (*e++ = *s++);
52394887Schin 		}
52404887Schin 	}
52414887Schin 	else
52424887Schin 		c = '-';
52434887Schin 	return c;
52444887Schin  nospace:
52454887Schin 	return opterror(NiL, 0, NiL, 0);
52464887Schin }
5247