xref: /onnv-gate/usr/src/lib/libast/common/misc/optget.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin  * Glenn Fowler
254887Schin  * AT&T Research
264887Schin  *
274887Schin  * command line option parser and usage formatter
284887Schin  * its a monster but its all in one place
294887Schin  * widen your window while you're at it
304887Schin  */
314887Schin 
324887Schin #include <optlib.h>
334887Schin #include <debug.h>
344887Schin #include <ccode.h>
354887Schin #include <ctype.h>
364887Schin #include <errno.h>
374887Schin 
384887Schin #define KEEP		"*[A-Za-z][A-Za-z]*"
394887Schin #define OMIT		"*@(\\[[-+]*\\?*\\]|\\@\\(#\\)|Copyright \\(c\\)|\\$\\I\\d\\: )*"
404887Schin 
414887Schin #define GO		'{'		/* group nest open		*/
424887Schin #define OG		'}'		/* group nest close		*/
434887Schin 
444887Schin #define OPT_WIDTH	80		/* default help text width	*/
454887Schin #define OPT_MARGIN	10		/* default help text margin	*/
464887Schin #define OPT_USAGE	7		/* usage continuation indent	*/
474887Schin 
484887Schin #define OPT_flag	0x001		/* flag ( 0 or 1 )		*/
494887Schin #define OPT_hidden	0x002		/* remaining are hidden		*/
504887Schin #define OPT_ignorecase	0x004		/* arg match ignores case	*/
514887Schin #define OPT_invert	0x008		/* flag inverts long sense	*/
524887Schin #define OPT_listof	0x010		/* arg is ' ' or ',' list	*/
5310898Sroland.mainz@nrubsig.org #define OPT_number	0x020		/* arg is strtonll() number	*/
5410898Sroland.mainz@nrubsig.org #define OPT_oneof	0x040		/* arg may be set once		*/
5510898Sroland.mainz@nrubsig.org #define OPT_optional	0x080		/* arg is optional		*/
5610898Sroland.mainz@nrubsig.org #define OPT_string	0x100		/* arg is string		*/
574887Schin 
584887Schin #define OPT_preformat	0001		/* output preformat string	*/
5910898Sroland.mainz@nrubsig.org #define OPT_proprietary	0002		/* proprietary docs		*/
604887Schin 
614887Schin #define OPT_TYPE	(OPT_flag|OPT_number|OPT_string)
624887Schin 
634887Schin #define STYLE_posix	0		/* posix getopt usage		*/
644887Schin #define STYLE_short	1		/* [default] short usage	*/
654887Schin #define STYLE_long	2		/* long usage			*/
664887Schin #define STYLE_match	3		/* long description of matches	*/
674887Schin #define STYLE_options	4		/* short and long descriptions	*/
684887Schin #define STYLE_man	5		/* pretty details		*/
694887Schin #define STYLE_html	6		/* html details			*/
704887Schin #define STYLE_nroff	7		/* nroff details		*/
714887Schin #define STYLE_api	8		/* program details		*/
724887Schin #define STYLE_keys	9		/* translation key strings	*/
734887Schin #define STYLE_usage	10		/* escaped usage string		*/
744887Schin 
754887Schin #define FONT_BOLD	1
764887Schin #define FONT_ITALIC	2
774887Schin #define FONT_LITERAL	4
784887Schin 
794887Schin #define sep(c)		((c)=='-'||(c)=='_')
804887Schin 
814887Schin typedef struct Attr_s
824887Schin {
834887Schin 	const char*	name;
844887Schin 	int		flag;
854887Schin } Attr_t;
864887Schin 
874887Schin typedef struct Help_s
884887Schin {
894887Schin 	const char*	match;		/* builtin help match name	*/
904887Schin 	const char*	name;		/* builtin help name		*/
914887Schin 	int		style;		/* STYLE_*			*/
924887Schin 	const char*	text;		/* --? text			*/
934887Schin 	unsigned int	size;		/* strlen text			*/
944887Schin } Help_t;
954887Schin 
964887Schin typedef struct Font_s
974887Schin {
984887Schin 	const char*	html[2];
994887Schin 	const char*	nroff[2];
1004887Schin 	const char*	term[2];
1014887Schin } Font_t;
1024887Schin 
1034887Schin typedef struct List_s
1044887Schin {
1054887Schin 	int		type;		/* { - + : }			*/
1064887Schin 	const char*	name;		/* list name			*/
1074887Schin 	const char*	text;		/* help text			*/
1084887Schin } List_t;
1094887Schin 
1104887Schin typedef struct Msg_s
1114887Schin {
1124887Schin 	const char*	text;		/* default message text		*/
1134887Schin 	Dtlink_t	link;		/* cdt link			*/
1144887Schin } Msg_t;
1154887Schin 
1164887Schin typedef struct Save_s
1174887Schin {
1184887Schin 	Dtlink_t	link;		/* cdt link			*/
1194887Schin 	char		text[1];	/* saved text text		*/
1204887Schin } Save_t;
1214887Schin 
1224887Schin typedef struct Push_s
1234887Schin {
1244887Schin 	struct Push_s*	next;		/* next string			*/
1254887Schin 	char*		ob;		/* next char in old string	*/
1264887Schin 	char*		oe;		/* end of old string		*/
1274887Schin 	char*		nb;		/* next char in new string	*/
1284887Schin 	char*		ne;		/* end of new string		*/
1294887Schin 	int		ch;		/* localize() translation	*/
1304887Schin } Push_t;
1314887Schin 
1324887Schin typedef struct Indent_s
1334887Schin {
1344887Schin 	int		stop;		/* tab column position		*/
1354887Schin } Indent_t;
1364887Schin 
1374887Schin static Indent_t		indent[] =
1384887Schin {
1394887Schin 	0,2,	4,10,	12,18,	20,26,	28,34,	36,42,	44,50,	0,0
1404887Schin };
1414887Schin 
1424887Schin static const char	term_off[] =	{CC_esc,'[','0','m',0};
1434887Schin static const char	term_B_on[] =	{CC_esc,'[','1','m',0};
1444887Schin static const char	term_I_on[] =	{CC_esc,'[','1',';','4','m',0};
1454887Schin 
1464887Schin static const Font_t	fonts[] =
1474887Schin {
1484887Schin 	"",	"",	"",	"",	"",			"",
1494887Schin 	"</B>",	"<B>", "\\fP",	"\\fB",	&term_off[0],	&term_B_on[0],
1504887Schin 	"</I>",	"<I>", "\\fP",	"\\fI",	&term_off[0],	&term_I_on[0],
1514887Schin 	"",	"",	"",	"",	"",			"",
1524887Schin 	"</TT>","<TT>","\\fP",	"\\f5",	"",			"",
1534887Schin };
1544887Schin 
1554887Schin static char		native[] = "";
1564887Schin 
1574887Schin #if !_PACKAGE_astsa
1584887Schin 
1594887Schin #define ID		ast.id
1604887Schin 
1614887Schin #define C(s)		ERROR_catalog(s)
1624887Schin #define D(s)		(opt_info.state->msgdict && dtmatch(opt_info.state->msgdict, (s)))
1634887Schin #define T(i,c,m)	(X(c)?translate(i,c,C(m)):(m))
1644887Schin #define X(c)		(ERROR_translating()&&(c)!=native)
1654887Schin #define Z(x)		C(x),sizeof(x)-1
1664887Schin 
1674887Schin /*
1684887Schin  * translate with C_LC_MESSAGES_libast[] check
1694887Schin  */
1704887Schin 
1714887Schin static char*
translate(const char * cmd,const char * cat,const char * msg)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*
show(register char * s)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;
386*12068SRoger.Faulkner@Oracle.COM 		case '\n':
387*12068SRoger.Faulkner@Oracle.COM 			*t++ = '\\';
388*12068SRoger.Faulkner@Oracle.COM 			c = 'n';
389*12068SRoger.Faulkner@Oracle.COM 			break;
390*12068SRoger.Faulkner@Oracle.COM 		case '\t':
391*12068SRoger.Faulkner@Oracle.COM 			*t++ = '\\';
392*12068SRoger.Faulkner@Oracle.COM 			c = 't';
393*12068SRoger.Faulkner@Oracle.COM 			break;
3944887Schin 		case '\v':
3954887Schin 			*t++ = '\\';
3964887Schin 			c = 'v';
3974887Schin 			break;
3984887Schin 		}
3994887Schin 		*t++ = c;
4004887Schin 	}
4014887Schin  done:
4024887Schin 	*t = 0;
4034887Schin 	return buf;
4044887Schin }
4054887Schin 
4064887Schin #endif
4074887Schin 
4084887Schin /*
4094887Schin  * pop the push stack
4104887Schin  */
4114887Schin 
4124887Schin static Push_t*
pop(register Push_t * psp)4134887Schin pop(register Push_t* psp)
4144887Schin {
4154887Schin 	register Push_t*	tsp;
4164887Schin 
4174887Schin 	while (tsp = psp)
4184887Schin 	{
4194887Schin 		psp = psp->next;
4204887Schin 		free(tsp);
4214887Schin 	}
4224887Schin 	return 0;
4234887Schin }
4244887Schin 
4254887Schin /*
4264887Schin  * skip over line space to the next token
4274887Schin  */
4284887Schin 
4294887Schin static char*
next(register char * s,int version)4304887Schin next(register char* s, int version)
4314887Schin {
4324887Schin 	register char*	b;
4334887Schin 
4344887Schin 	while (*s == '\t' || *s == '\r' || version >= 1 && *s == ' ')
4354887Schin 		s++;
4364887Schin 	if (*s == '\n')
4374887Schin 	{
4384887Schin 		b = s;
4394887Schin 		while (*++s == ' ' || *s == '\t' || *s == '\r');
4404887Schin 		if (*s == '\n')
4414887Schin 			return b;
4424887Schin 	}
4434887Schin 	return s;
4444887Schin }
4454887Schin 
4464887Schin /*
4474887Schin  * skip to t1 or t2 or t3, whichever first, in s
4484887Schin  *	n==0	outside [...]
4494887Schin  *	n==1	inside [...] before ?
4504887Schin  *	n==2	inside [...] after ?
4514887Schin  *	b==0	outside {...}
4524887Schin  *	b==1	inside {...}
4534887Schin  * past skips past the terminator to the next token
4544887Schin  * otherwise a pointer to the terminator is returned
4554887Schin  *
4564887Schin  * ]] for ] inside [...]
4574887Schin  * ?? for ? inside [...] before ?
4584887Schin  * :: for : inside [...] before ?
4594887Schin  */
4604887Schin 
4614887Schin static char*
skip(register char * s,register int t1,register int t2,register int t3,register int n,register int b,int past,int version)4624887Schin skip(register char* s, register int t1, register int t2, register int t3, register int n, register int b, int past, int version)
4634887Schin {
4644887Schin 	register int	c;
4654887Schin 	register int	on = n;
4664887Schin 	register int	ob = b;
4674887Schin 
4684887Schin 	if (version < 1)
4694887Schin 	{
4704887Schin 		n = n >= 1;
4714887Schin 		for (;;)
4724887Schin 		{
4734887Schin 			switch (*s++)
4744887Schin 			{
4754887Schin 			case 0:
4764887Schin 				break;
4774887Schin 			case '[':
4784887Schin 				n++;
4794887Schin 				continue;
4804887Schin 			case ']':
4814887Schin 				if (--n <= 0)
4824887Schin 					break;
4834887Schin 				continue;
4844887Schin 			default:
4854887Schin 				continue;
4864887Schin 			}
4874887Schin 			break;
4884887Schin 		}
4894887Schin 	}
4904887Schin 	else while (c = *s++)
4914887Schin 	{
4924887Schin 		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)));
4934887Schin 		if (c == '[')
4944887Schin 		{
4954887Schin 			if (!n)
4964887Schin 				n = 1;
4974887Schin 		}
4984887Schin 		else if (c == ']')
4994887Schin 		{
5004887Schin 			if (n)
5014887Schin 			{
5024887Schin 				if (*s == ']')
5034887Schin 					s++;
5044887Schin 				else if (on == 1)
5054887Schin 					break;
5064887Schin 				else
5074887Schin 					n = 0;
5084887Schin 			}
5094887Schin 		}
5104887Schin 		else if (c == GO)
5114887Schin 		{
5124887Schin 			if (n == 0)
5134887Schin 				b++;
5144887Schin 		}
5154887Schin 		else if (c == OG)
5164887Schin 		{
5174887Schin 			if (n == 0 && b-- == ob)
5184887Schin 				break;
5194887Schin 		}
5204887Schin 		else if (c == '?')
5214887Schin 		{
5224887Schin 			if (n == 1)
5234887Schin 			{
5244887Schin 				if (*s == '?')
5254887Schin 					s++;
5264887Schin 				else
5274887Schin 				{
5284887Schin 					if (n == on && (c == t1 || c == t2 || c == t3))
5294887Schin 						break;
5304887Schin 					n = 2;
5314887Schin 				}
5324887Schin 			}
5334887Schin 		}
5344887Schin 		else if (n == on && (c == t1 || c == t2 || c == t3))
5354887Schin 		{
5364887Schin 			if (n == 1 && c == ':' && *s == c)
5374887Schin 				s++;
5384887Schin 			else
5394887Schin 				break;
5404887Schin 		}
5414887Schin 	}
5424887Schin 	return past && *(s - 1) ? next(s, version) : s - 1;
5434887Schin }
5444887Schin 
5454887Schin /*
5464887Schin  * match s with t
5474887Schin  * t translated if possible
5484887Schin  * imbedded { - _ ' } ignored
5494887Schin  * * separates required prefix from optional suffix
5504887Schin  * otherwise prefix match
5514887Schin  */
5524887Schin 
5534887Schin static int
match(char * s,char * t,int version,const char * id,const char * catalog)554*12068SRoger.Faulkner@Oracle.COM match(char* s, char* t, int version, const char* id, const char* catalog)
5554887Schin {
5564887Schin 	register char*	w;
5574887Schin 	register char*	x;
5584887Schin 	char*		xw;
5594887Schin 	char*		ww;
5604887Schin 	int		n;
5614887Schin 	int		v;
5624887Schin 	int		j;
5634887Schin 
5644887Schin 	for (n = 0; n < 2; n++)
5654887Schin 	{
5664887Schin 		if (n)
5674887Schin 			x = t;
5684887Schin 		else
5694887Schin 		{
5704887Schin 			if (catalog)
5714887Schin 			{
5724887Schin 				w = skip(t, ':', '?', 0, 1, 0, 0, version);
5734887Schin 				w = sfprints("%-.*s", w - t, t);
574*12068SRoger.Faulkner@Oracle.COM 				x = T(id, catalog, w);
5754887Schin 				if (x == w)
5764887Schin 					continue;
5774887Schin 			}
5784887Schin 			x = T(NiL, ID, t);
5794887Schin 			if (x == t)
5804887Schin 				continue;
5814887Schin 		}
5824887Schin 		do
5834887Schin 		{
5844887Schin 			v = 0;
5854887Schin 			xw = x;
5864887Schin 			w = ww = s;
5874887Schin 			while (*x && *w)
5884887Schin 			{
5894887Schin 				if (isupper(*x))
5904887Schin 					xw = x;
5914887Schin 				if (isupper(*w))
5924887Schin 					ww = w;
5934887Schin 				if (*x == '*' && !v++ || *x == '\a')
5944887Schin 				{
5954887Schin 					if (*x == '\a')
5964887Schin 						do
5974887Schin 						{
5984887Schin 							if (!*++x)
5994887Schin 							{
6004887Schin 								x--;
6014887Schin 								break;
6024887Schin 							}
6034887Schin 						} while (*x != '\a');
6044887Schin 					j = *(x + 1);
6054887Schin 					if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
6064887Schin 						while (*w)
6074887Schin 							w++;
6084887Schin 				}
6094887Schin 				else if (sep(*x))
6104887Schin 					xw = ++x;
6114887Schin 				else if (sep(*w) && w != s)
6124887Schin 					ww = ++w;
6134887Schin 				else if (*x == *w)
6144887Schin 				{
6154887Schin 					x++;
6164887Schin 					w++;
6174887Schin 				}
6184887Schin 				else if (w == ww && x == xw)
6194887Schin 					break;
6204887Schin 				else
6214887Schin 				{
6224887Schin 					if (x != xw)
6234887Schin 					{
6244887Schin 						while (*x && !sep(*x) && !isupper(*x))
6254887Schin 							x++;
6264887Schin 						if (!*x)
6274887Schin 							break;
6284887Schin 						if (sep(*x))
6294887Schin 							x++;
6304887Schin 						xw = x;
6314887Schin 					}
6324887Schin 					while (w > ww && *w != *x)
6334887Schin 						w--;
6344887Schin 				}
6354887Schin 			}
6364887Schin 			if (!*w)
6374887Schin 			{
6384887Schin 				if (!v)
6394887Schin 				{
6404887Schin 					for (;;)
6414887Schin 					{
6424887Schin 						switch (*x++)
6434887Schin 						{
6444887Schin 						case 0:
6454887Schin 						case ':':
6464887Schin 						case '|':
6474887Schin 						case '?':
6484887Schin 						case ']':
6494887Schin 							return 1;
6504887Schin 						case '*':
6514887Schin 							break;
6524887Schin 						default:
6534887Schin 							continue;
6544887Schin 						}
6554887Schin 						break;
6564887Schin 					}
6574887Schin 					break;
6584887Schin 				}
6594887Schin 				return 1;
6604887Schin 			}
6614887Schin 		} while (*(x = skip(x, '|', 0, 0, 1, 0, 0, version)) == '|' && x++);
6624887Schin 	}
6634887Schin 	return 0;
6644887Schin }
6654887Schin 
6664887Schin /*
6674887Schin  * prefix search for s in tab with num elements of size
6684887Schin  * with optional translation
6694887Schin  */
6704887Schin 
6714887Schin static void*
search(const void * tab,size_t num,size_t siz,char * s)6724887Schin search(const void* tab, size_t num, size_t siz, char* s)
6734887Schin {
6744887Schin 	register char*	p;
6754887Schin 	register char*	e;
6764887Schin 
6774887Schin 	for (e = (p = (char*)tab) + num * siz; p < e; p += siz)
678*12068SRoger.Faulkner@Oracle.COM 		if (match(s, *((char**)p), -1, NiL, NiL))
6794887Schin 			return (void*)p;
6804887Schin 	return 0;
6814887Schin }
6824887Schin 
6834887Schin /*
6844887Schin  * save s and return the saved pointer
6854887Schin  */
6864887Schin 
6874887Schin static char*
save(const char * s)6884887Schin save(const char* s)
6894887Schin {
6904887Schin 	Save_t*		p;
6918462SApril.Chin@Sun.COM 	Dtdisc_t*	d;
6924887Schin 
6934887Schin 	static Dt_t*	dict;
6944887Schin 
6954887Schin 	if (!dict)
6964887Schin 	{
6978462SApril.Chin@Sun.COM 		if (!(d = newof(0, Dtdisc_t, 1, 0)))
6988462SApril.Chin@Sun.COM 			return (char*)s;
6998462SApril.Chin@Sun.COM 		d->key = offsetof(Save_t, text);
7008462SApril.Chin@Sun.COM 		if (!(dict = dtopen(d, Dthash)))
7014887Schin 			return (char*)s;
7024887Schin 	}
7034887Schin 	if (!(p = (Save_t*)dtmatch(dict, s)))
7044887Schin 	{
7054887Schin 		if (!(p = newof(0, Save_t, 1, strlen(s))))
7064887Schin 			return (char*)s;
7074887Schin 		strcpy(p->text, s);
7084887Schin 		dtinsert(dict, p);
7094887Schin 	}
7104887Schin 	return p->text;
7114887Schin }
7124887Schin 
7134887Schin /*
7144887Schin  * initialize the attributes for pass p from opt string s
7154887Schin  */
7164887Schin 
7174887Schin static int
init(register char * s,Optpass_t * p)7184887Schin init(register char* s, Optpass_t* p)
7194887Schin {
7204887Schin 	register char*	t;
721*12068SRoger.Faulkner@Oracle.COM 	register char*	u;
7224887Schin 	register int	c;
7234887Schin 	register int	a;
7244887Schin 	register int	n;
7254887Schin 
7264887Schin 	if (!opt_info.state->msgdict)
7274887Schin 	{
7284887Schin #if !_PACKAGE_astsa
7294887Schin 		if (!ast.locale.serial)
7304887Schin 			setlocale(LC_ALL, "");
7314887Schin #endif
7324887Schin 		opt_info.state->vp = sfstropen();
7334887Schin 		opt_info.state->xp = sfstropen();
7344887Schin 		opt_info.state->msgdisc.key = offsetof(Msg_t, text);
7354887Schin 		opt_info.state->msgdisc.size = -1;
7364887Schin 		opt_info.state->msgdisc.link = offsetof(Msg_t, link);
7374887Schin 		if (opt_info.state->msgdict = dtopen(&opt_info.state->msgdisc, Dthash))
7384887Schin 			for (n = 0; n < elementsof(C_LC_MESSAGES_libast); n++)
7394887Schin 				dtinsert(opt_info.state->msgdict, C_LC_MESSAGES_libast + n);
7404887Schin 		if (!map[OPT_FLAGS[0]])
7414887Schin 			for (n = 0, t = OPT_FLAGS; *t; t++)
7424887Schin 				map[*t] = ++n;
7434887Schin 	}
7444887Schin #if _BLD_DEBUG
7454887Schin 	error(-1, "optget debug");
7464887Schin #endif
7474887Schin 	p->oopts = s;
7484887Schin 	p->version = 0;
7494887Schin 	p->prefix = 2;
7504887Schin 	p->section = 1;
7514887Schin 	p->flags = 0;
752*12068SRoger.Faulkner@Oracle.COM 	p->id = error_info.id;
7534887Schin 	p->catalog = 0;
7544887Schin 	s = next(s, 0);
7554887Schin 	if (*s == ':')
7564887Schin 		s++;
7574887Schin 	if (*s == '+')
7584887Schin 		s++;
7594887Schin 	s = next(s, 0);
7604887Schin 	if (*s++ == '[')
7614887Schin 	{
7624887Schin 		if (*s == '+')
7634887Schin 			p->version = 1;
7644887Schin 		else if (*s++ == '-')
7654887Schin 		{
7664887Schin 			if (*s == '?' || *s == ']')
7674887Schin 				p->version = 1;
7684887Schin 			else
7694887Schin 			{
7708462SApril.Chin@Sun.COM 				if (!isdigit(*s))
7714887Schin 					p->version = 1;
7724887Schin 				else
7738462SApril.Chin@Sun.COM 					while (isdigit(*s))
7744887Schin 						p->version = p->version * 10 + (*s++ - '0');
7754887Schin 				while (*s && *s != '?' && *s != ']')
7764887Schin 				{
7774887Schin 					c = *s++;
7788462SApril.Chin@Sun.COM 					if (!isdigit(*s))
7794887Schin 						n = 1;
7804887Schin 					else
7814887Schin 					{
7824887Schin 						n = 0;
7838462SApril.Chin@Sun.COM 						while (isdigit(*s))
7844887Schin 							n = n * 10 + (*s++ - '0');
7854887Schin 					}
7864887Schin 					switch (c)
7874887Schin 					{
7888462SApril.Chin@Sun.COM 					case '+':
7898462SApril.Chin@Sun.COM 						p->flags |= OPT_plus;
7908462SApril.Chin@Sun.COM 						break;
7914887Schin 					case 'c':
7924887Schin 						p->flags |= OPT_cache;
7934887Schin 						break;
7944887Schin 					case 'i':
7954887Schin 						p->flags |= OPT_ignore;
7964887Schin 						break;
7974887Schin 					case 'l':
7984887Schin 						p->flags |= OPT_long;
7994887Schin 						break;
8008462SApril.Chin@Sun.COM 					case 'n':
8018462SApril.Chin@Sun.COM 						p->flags |= OPT_numeric;
8028462SApril.Chin@Sun.COM 						break;
8034887Schin 					case 'o':
8044887Schin 						p->flags |= OPT_old;
8054887Schin 						break;
8064887Schin 					case 'p':
8074887Schin 						p->prefix = n;
8084887Schin 						break;
8094887Schin 					case 's':
8104887Schin 						p->section = n;
8114887Schin 						if (n > 1 && n < 6)
8124887Schin 						{
8134887Schin 							p->flags |= OPT_functions;
8144887Schin 							p->prefix = 0;
8154887Schin 						}
8164887Schin 						break;
8174887Schin 					}
8184887Schin 				}
8194887Schin 			}
8204887Schin 		}
8214887Schin 		while (*s)
822*12068SRoger.Faulkner@Oracle.COM 			if (*s++ == ']')
8234887Schin 			{
824*12068SRoger.Faulkner@Oracle.COM 				while (isspace(*s))
825*12068SRoger.Faulkner@Oracle.COM 					s++;
826*12068SRoger.Faulkner@Oracle.COM 				if (*s++ == '[')
8274887Schin 				{
828*12068SRoger.Faulkner@Oracle.COM 					if (*s++ != '-')
8294887Schin 					{
830*12068SRoger.Faulkner@Oracle.COM 						if (strneq(s - 1, "+NAME?", 6))
831*12068SRoger.Faulkner@Oracle.COM 						{
832*12068SRoger.Faulkner@Oracle.COM 							for (s += 5; *s == '\a' || *s == '\b' || *s == '\v' || *s == ' '; s++);
833*12068SRoger.Faulkner@Oracle.COM 							if (*s != '\f')
834*12068SRoger.Faulkner@Oracle.COM 							{
835*12068SRoger.Faulkner@Oracle.COM 								for (t = s; *t && *t != ' ' && *t != ']'; t++);
836*12068SRoger.Faulkner@Oracle.COM 								if (t > s)
837*12068SRoger.Faulkner@Oracle.COM 								{
838*12068SRoger.Faulkner@Oracle.COM 									u = t;
839*12068SRoger.Faulkner@Oracle.COM 									if (*(t - 1) == '\a' || *(t - 1) == '\b' || *(t - 1) == '\v')
840*12068SRoger.Faulkner@Oracle.COM 										t--;
841*12068SRoger.Faulkner@Oracle.COM 									if (t > s)
842*12068SRoger.Faulkner@Oracle.COM 									{
843*12068SRoger.Faulkner@Oracle.COM 										while (*u == ' ' || *u == '\\')
844*12068SRoger.Faulkner@Oracle.COM 											u++;
845*12068SRoger.Faulkner@Oracle.COM 										if (*u == '-' || *u == ']')
846*12068SRoger.Faulkner@Oracle.COM 											p->id = save(sfprints("%-.*s", t - s, s));
847*12068SRoger.Faulkner@Oracle.COM 									}
848*12068SRoger.Faulkner@Oracle.COM 								}
849*12068SRoger.Faulkner@Oracle.COM 							}
850*12068SRoger.Faulkner@Oracle.COM 						}
851*12068SRoger.Faulkner@Oracle.COM 						break;
8524887Schin 					}
853*12068SRoger.Faulkner@Oracle.COM 					if (*s == '-')
854*12068SRoger.Faulkner@Oracle.COM 						s++;
855*12068SRoger.Faulkner@Oracle.COM 					if (strneq(s, "catalog?", 8))
856*12068SRoger.Faulkner@Oracle.COM 						p->catalog = s += 8;
8574887Schin 				}
8584887Schin 			}
8594887Schin 	}
860*12068SRoger.Faulkner@Oracle.COM 	if (!error_info.id)
861*12068SRoger.Faulkner@Oracle.COM 	{
862*12068SRoger.Faulkner@Oracle.COM 		if (!(error_info.id = p->id))
863*12068SRoger.Faulkner@Oracle.COM 			p->id = "command";
864*12068SRoger.Faulkner@Oracle.COM 	}
865*12068SRoger.Faulkner@Oracle.COM 	else if (p->id == error_info.id)
866*12068SRoger.Faulkner@Oracle.COM 		p->id = save(p->id);
867*12068SRoger.Faulkner@Oracle.COM 	if (s = p->catalog)
868*12068SRoger.Faulkner@Oracle.COM 		p->catalog = ((t = strchr(s, ']')) && (!p->id || (t - s) != strlen(p->id) || !strneq(s, p->id, t - s))) ? save(sfprints("%-.*s", t - s, s)) : (char*)0;
8694887Schin 	if (!p->catalog)
8704887Schin 	{
871*12068SRoger.Faulkner@Oracle.COM 		if (opt_info.disc && opt_info.disc->catalog && (!p->id || !streq(opt_info.disc->catalog, p->id)))
8724887Schin 			p->catalog = opt_info.disc->catalog;
8734887Schin 		else
8744887Schin 			p->catalog = ID;
8754887Schin 	}
8764887Schin 	s = p->oopts;
8774887Schin 	if (*s == ':')
8784887Schin 		s++;
8794887Schin 	if (*s == '+')
8804887Schin 	{
8814887Schin 		s++;
8824887Schin 		p->flags |= OPT_plus;
8834887Schin 	}
8848462SApril.Chin@Sun.COM 	s = next(s, 0);
8854887Schin 	if (*s != '[')
8864887Schin 		for (t = s, a = 0; *t; t++)
8874887Schin 			if (!a && *t == '-')
8884887Schin 			{
8894887Schin 				p->flags |= OPT_minus;
8904887Schin 				break;
8914887Schin 			}
8924887Schin 			else if (*t == '[')
8934887Schin 				a++;
8944887Schin 			else if (*t == ']')
8954887Schin 				a--;
8964887Schin 	if (!p->version && (t = strchr(s, '(')) && strchr(t, ')') && (opt_info.state->cp || (opt_info.state->cp = sfstropen())))
8974887Schin 	{
8984887Schin 		/*
8994887Schin 		 * solaris long option compatibility
9004887Schin 		 */
9014887Schin 
9024887Schin 		p->version = 1;
9034887Schin 		for (t = p->oopts; t < s; t++)
9044887Schin 			sfputc(opt_info.state->cp, *t);
9054887Schin 		n = t - p->oopts;
9064887Schin 		sfputc(opt_info.state->cp, '[');
9074887Schin 		sfputc(opt_info.state->cp, '-');
9084887Schin 		sfputc(opt_info.state->cp, ']');
909*12068SRoger.Faulkner@Oracle.COM 		c = *s++;
910*12068SRoger.Faulkner@Oracle.COM 		while (c)
9114887Schin 		{
9124887Schin 			sfputc(opt_info.state->cp, '[');
9134887Schin 			sfputc(opt_info.state->cp, c);
9144887Schin 			if (a = (c = *s++) == ':')
9154887Schin 				c = *s++;
9164887Schin 			if (c == '(')
9174887Schin 			{
9184887Schin 				sfputc(opt_info.state->cp, ':');
9194887Schin 				for (;;)
9204887Schin 				{
9214887Schin 					while ((c = *s++) && c != ')')
9224887Schin 						sfputc(opt_info.state->cp, c);
923*12068SRoger.Faulkner@Oracle.COM 					if (!c || (c = *s++) != '(')
9244887Schin 						break;
9254887Schin 					sfputc(opt_info.state->cp, '|');
9264887Schin 				}
9274887Schin 			}
9284887Schin 			sfputc(opt_info.state->cp, ']');
9294887Schin 			if (a)
9304887Schin 				sfputr(opt_info.state->cp, ":[string]", -1);
9314887Schin 		}
9324887Schin 		if (!(p->oopts = s = sfstruse(opt_info.state->cp)))
9334887Schin 			return -1;
9344887Schin 		s += n;
9354887Schin 	}
9364887Schin 	p->opts = s;
937*12068SRoger.Faulkner@Oracle.COM 	message((-1, "version=%d prefix=%d section=%d flags=%04x id=%s catalog=%s", p->version, p->prefix, p->section, p->flags, p->id, p->catalog));
9384887Schin 	return 0;
9394887Schin }
9404887Schin 
9414887Schin /*
9424887Schin  * return the bold set/unset sequence for style
9434887Schin  */
9444887Schin 
9454887Schin static const char*
font(int f,int style,int set)9464887Schin font(int f, int style, int set)
9474887Schin {
9484887Schin 	switch (style)
9494887Schin 	{
9504887Schin 	case STYLE_html:
9514887Schin 		return fonts[f].html[set];
9524887Schin 	case STYLE_nroff:
9534887Schin 		return fonts[f].nroff[set];
9544887Schin 	case STYLE_short:
9554887Schin 	case STYLE_long:
9564887Schin 	case STYLE_posix:
9574887Schin 	case STYLE_api:
9584887Schin 		break;
9594887Schin 	default:
9604887Schin 		if (opt_info.state->emphasis > 0)
9614887Schin 			return fonts[f].term[set];
9624887Schin 		break;
9634887Schin 	}
9644887Schin 	return "";
9654887Schin }
9664887Schin 
9674887Schin /*
9684887Schin  * expand \f...\f info
9694887Schin  * *p set to next char after second \f
9704887Schin  * expanded value returned
9714887Schin  */
9724887Schin 
9734887Schin static char*
expand(register char * s,register char * e,char ** p,Sfio_t * ip,char * id)974*12068SRoger.Faulkner@Oracle.COM expand(register char* s, register char* e, char** p, Sfio_t* ip, char* id)
9754887Schin {
9764887Schin 	register int	c;
9774887Schin 	register char*	b = s;
9784887Schin 	int		n;
9794887Schin 
9804887Schin 	n = sfstrtell(ip);
9814887Schin 	c = 1;
9824887Schin 	while ((!e || s < e) && (c = *s++) && c != '\f');
9834887Schin 	sfwrite(ip, b, s - b - 1);
9844887Schin 	sfputc(ip, 0);
9854887Schin 	b = sfstrbase(ip) + n;
9864887Schin 	n = sfstrtell(ip);
9874887Schin 	if (!c)
9884887Schin 		s--;
9894887Schin 	if (*b == '?')
9904887Schin 	{
9914887Schin 		if (!*++b || streq(b, "NAME"))
9924887Schin 		{
993*12068SRoger.Faulkner@Oracle.COM 			if (!(b = id))
9944887Schin 				b = "command";
9954887Schin 			sfstrseek(ip, 0, SEEK_SET);
9964887Schin 			sfputr(ip, b, -1);
9974887Schin 			n = 0;
9984887Schin 		}
9994887Schin 		else
10004887Schin 			n = 1;
10014887Schin 	}
10024887Schin 	else if (!opt_info.disc || !opt_info.disc->infof || (*opt_info.disc->infof)(&opt_info, ip, b, opt_info.disc) < 0)
10034887Schin 		n = 0;
10044887Schin 	*p = s;
10054887Schin 	if (s = sfstruse(ip))
10064887Schin 		s += n;
10074887Schin 	else
10084887Schin 		s = "error";
10094887Schin 	return s;
10104887Schin }
10114887Schin 
10124887Schin /*
10134887Schin  * push \f...\f info
10144887Schin  */
10154887Schin 
10164887Schin static Push_t*
info(Push_t * psp,char * s,char * e,Sfio_t * ip,char * id)1017*12068SRoger.Faulkner@Oracle.COM info(Push_t* psp, char* s, char* e, Sfio_t* ip, char* id)
10184887Schin {
10194887Schin 	register char*	b;
10204887Schin 	int		n;
10214887Schin 	Push_t*		tsp;
10224887Schin 
10234887Schin 	static Push_t	push;
10244887Schin 
1025*12068SRoger.Faulkner@Oracle.COM 	b = expand(s, e, &s, ip, id);
10264887Schin 	n = strlen(b);
10274887Schin 	if (tsp = newof(0, Push_t, 1, n + 1))
10284887Schin 	{
10294887Schin 		tsp->nb = (char*)(tsp + 1);
10304887Schin 		tsp->ne = tsp->nb + n;
10314887Schin 		strcpy(tsp->nb, b);
10324887Schin 	}
10334887Schin 	else
10344887Schin 		tsp = &push;
10354887Schin 	tsp->next = psp;
10364887Schin 	tsp->ob = s;
10374887Schin 	tsp->oe = e;
10384887Schin 	return tsp;
10394887Schin }
10404887Schin 
10414887Schin /*
10424887Schin  * push translation
10434887Schin  */
10444887Schin 
10454887Schin static Push_t*
localize(Push_t * psp,char * s,char * e,int term,int n,Sfio_t * ip,int version,char * id,char * catalog)1046*12068SRoger.Faulkner@Oracle.COM localize(Push_t* psp, char* s, char* e, int term, int n, Sfio_t* ip, int version, char* id, char* catalog)
10474887Schin {
10484887Schin 	char*		t;
10494887Schin 	char*		u;
10504887Schin 	Push_t*		tsp;
10514887Schin 	int		c;
10524887Schin 
10534887Schin 	t = skip(s, term, 0, 0, n, 0, 0, version);
10544887Schin 	if (e && t > e)
10554887Schin 		t = e;
10564887Schin 	while (s < t)
10574887Schin 	{
10584887Schin 		switch (c = *s++)
10594887Schin 		{
10604887Schin 		case ':':
10614887Schin 		case '?':
10624887Schin 			if (term && *s == c)
10634887Schin 				s++;
10644887Schin 			break;
10654887Schin 		case ']':
10664887Schin 			if (*s == c)
10674887Schin 				s++;
10684887Schin 			break;
10694887Schin 		}
10704887Schin 		sfputc(ip, c);
10714887Schin 	}
1072*12068SRoger.Faulkner@Oracle.COM 	if (!(s = sfstruse(ip)) || (u = T(id, catalog, s)) == s)
10734887Schin 		return 0;
10744887Schin 	n = strlen(u);
10754887Schin 	if (tsp = newof(0, Push_t, 1, n + 1))
10764887Schin 	{
10774887Schin 		tsp->nb = (char*)(tsp + 1);
10784887Schin 		tsp->ne = tsp->nb + n;
10794887Schin 		strcpy(tsp->nb, u);
10804887Schin 		tsp->ob = t;
10814887Schin 		tsp->oe = e;
10824887Schin 		tsp->ch = 1;
10834887Schin 	}
10844887Schin 	tsp->next = psp;
10854887Schin 	return tsp;
10864887Schin }
10874887Schin 
10884887Schin /*
10894887Schin  * output label s from [ ...label...[?...] ] to sp
10904887Schin  * 1 returned if the label was translated
10914887Schin  */
10924887Schin 
10934887Schin static int
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 * id,char * catalog)1094*12068SRoger.Faulkner@Oracle.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* id, char* catalog)
10954887Schin {
10964887Schin 	register int	c;
10974887Schin 	register char*	t;
10984887Schin 	register char*	e;
10994887Schin 	int		ostyle;
11004887Schin 	int		a;
11014887Schin 	int		i;
11024887Schin 	char*		p;
11034887Schin 	char*		w;
11044887Schin 	char*		y;
11054887Schin 	int		va;
11064887Schin 	Push_t*		tsp;
11074887Schin 
11084887Schin 	int		r = 0;
11094887Schin 	int		n = 1;
11104887Schin 	Push_t*		psp = 0;
11114887Schin 
11124887Schin 	if ((ostyle = style) > (STYLE_nroff - (sep <= 0)) && f != FONT_LITERAL)
11134887Schin 		style = 0;
11144887Schin 	if (z < 0)
11154887Schin 		e = s + strlen(s);
11164887Schin 	else
11174887Schin 		e = s + z;
11184887Schin 	if (sep > 0)
11194887Schin 	{
11204887Schin 		if (sep == ' ' && style == STYLE_nroff)
11214887Schin 			sfputc(sp, '\\');
11224887Schin 		sfputc(sp, sep);
11234887Schin 	}
11244887Schin 	sep = !sep || z < 0;
11254887Schin 	va = 0;
11264887Schin 	y = 0;
11278462SApril.Chin@Sun.COM 	if (about)
11288462SApril.Chin@Sun.COM 		sfputc(sp, '(');
11294887Schin 	if (version < 1)
11304887Schin 	{
11314887Schin 		a = 0;
11324887Schin 		for (;;)
11334887Schin 		{
11344887Schin 			if (s >= e)
11354887Schin 				return r;
11364887Schin 			switch (c = *s++)
11374887Schin 			{
11384887Schin 			case '[':
11394887Schin 				a++;
11404887Schin 				break;
11414887Schin 			case ']':
11424887Schin 				if (--a < 0)
11434887Schin 					return r;
11444887Schin 				break;
11454887Schin 			}
11464887Schin 			sfputc(sp, c);
11474887Schin 		}
11484887Schin 	}
11494887Schin 	else if (level && (*(p = skip(s, 0, 0, 0, 1, level, 1, version)) == ':' || *p == '#'))
11504887Schin 	{
11514887Schin 		va = 0;
11524887Schin 		if (*++p == '?' || *p == *(p - 1))
11534887Schin 		{
11544887Schin 			p++;
11554887Schin 			va |= OPT_optional;
11564887Schin 		}
11574887Schin 		if (*(p = next(p, version)) == '[')
11584887Schin 			y = p + 1;
11594887Schin 	}
11604887Schin 	if (X(catalog) && (!level || *s == '\a' || *(s - 1) != '+') &&
1161*12068SRoger.Faulkner@Oracle.COM 	    (tsp = localize(psp, s, e, (sep || level) ? '?' : 0, sep || level, ip, version, id, catalog)))
11624887Schin 	{
11634887Schin 		psp= tsp;
11644887Schin 		s = psp->nb;
11654887Schin 		e = psp->ne;
11664887Schin 		r = psp->ch > 0;
11674887Schin 	}
11684887Schin 	switch (*s)
11694887Schin 	{
11704887Schin 	case '\a':
11714887Schin 		if (f == FONT_ITALIC)
11724887Schin 			s++;
11734887Schin 		f = 0;
11744887Schin 		break;
11754887Schin 	case '\b':
11764887Schin 		if (f == FONT_BOLD)
11774887Schin 			s++;
11784887Schin 		f = 0;
11794887Schin 		break;
11804887Schin 	case '\v':
11814887Schin 		if (f == FONT_LITERAL)
11824887Schin 			s++;
11834887Schin 		f = 0;
11844887Schin 		break;
11854887Schin 	default:
11864887Schin 		if (f)
11874887Schin 			sfputr(sp, font(f, style, 1), -1);
11884887Schin 		break;
11894887Schin 	}
11904887Schin 	for (;;)
11914887Schin 	{
11924887Schin 		if (s >= e)
11934887Schin 		{
11944887Schin 			if (!(tsp = psp))
11954887Schin 				goto restore;
11964887Schin 			s = psp->ob;
11974887Schin 			e = psp->oe;
11984887Schin 			psp = psp->next;
11994887Schin 			free(tsp);
12004887Schin 			continue;
12014887Schin 		}
12024887Schin 		switch (c = *s++)
12034887Schin 		{
12044887Schin 		case '(':
12054887Schin 			if (n)
12064887Schin 			{
12074887Schin 				n = 0;
12084887Schin 				if (f)
12094887Schin 				{
12104887Schin 					sfputr(sp, font(f, style, 0), -1);
12114887Schin 					f = 0;
12124887Schin 				}
12134887Schin 			}
12144887Schin 			break;
12154887Schin 		case '?':
12164887Schin 		case ':':
12174887Schin 		case ']':
12184887Schin 			if (psp && psp->ch)
12194887Schin 				break;
12204887Schin 			if (y)
12214887Schin 			{
12224887Schin 				if (va & OPT_optional)
12234887Schin 					sfputc(sp, '[');
12244887Schin 				sfputc(sp, '=');
1225*12068SRoger.Faulkner@Oracle.COM 				label(sp, 0, y, 0, -1, 0, style, FONT_ITALIC, ip, version, id, catalog);
12264887Schin 				if (va & OPT_optional)
12274887Schin 					sfputc(sp, ']');
12284887Schin 				y = 0;
12294887Schin 			}
12304887Schin 			switch (c)
12314887Schin 			{
12324887Schin 			case '?':
12334887Schin 				if (*s == '?')
12344887Schin 					s++;
12354887Schin 				else if (*s == ']' && *(s + 1) != ']')
12364887Schin 					continue;
12374887Schin 				else if (sep)
12384887Schin 					goto restore;
1239*12068SRoger.Faulkner@Oracle.COM 				else if (X(catalog) && (tsp = localize(psp, s, e, 0, 1, ip, version, id, catalog)))
12404887Schin 				{
12414887Schin 					psp = tsp;
12424887Schin 					s = psp->nb;
12434887Schin 					e = psp->ne;
12444887Schin 				}
12454887Schin 				break;
12464887Schin 			case ']':
12474887Schin 				if (sep && *s++ != ']')
12484887Schin 					goto restore;
12494887Schin 				break;
12504887Schin 			case ':':
12514887Schin 				if (sep && *s++ != ':')
12524887Schin 					goto restore;
12534887Schin 				break;
12544887Schin 			}
12554887Schin 			break;
12564887Schin 		case '\a':
12574887Schin 			a = FONT_ITALIC;
12584887Schin 		setfont:
12594887Schin 			if (f & ~a)
12604887Schin 			{
12614887Schin 				sfputr(sp, font(f, style, 0), -1);
12624887Schin 				f = 0;
12634887Schin 			}
12644887Schin 			if (!f && style == STYLE_html)
12654887Schin 			{
12664887Schin 				for (t = s; t < e && !isspace(*t) && !iscntrl(*t); t++);
12674887Schin 				if (*t == c && *++t == '(')
12684887Schin 				{
12694887Schin 					w = t;
12704887Schin 					while (++t < e && isdigit(*t));
12714887Schin 					if (t < e && *t == ')' && t > w + 1)
12724887Schin 					{
12734887Schin 						sfprintf(sp, "<NOBR><A href=\"../man%-.*s/%-.*s.html\">%s%-.*s%s</A>%-.*s</NOBR>"
12744887Schin 							, t - w - 1, w + 1
12754887Schin 							, w - s - 1, s
12764887Schin 							, font(a, style, 1)
12774887Schin 							, w - s - 1, s
12784887Schin 							, font(a, style, 0)
12794887Schin 							, t - w + 1, w
12804887Schin 							);
12814887Schin 						s = t + 1;
12824887Schin 						continue;
12834887Schin 					}
12844887Schin 				}
12854887Schin 			}
12864887Schin 			sfputr(sp, font(a, style, !!(f ^= a)), -1);
12874887Schin 			continue;
12884887Schin 		case '\b':
12894887Schin 			a = FONT_BOLD;
12904887Schin 			goto setfont;
12914887Schin 		case '\f':
1292*12068SRoger.Faulkner@Oracle.COM 			psp = info(psp, s, e, ip, id);
12934887Schin 			if (psp->nb)
12944887Schin 			{
12954887Schin 				s = psp->nb;
12964887Schin 				e = psp->ne;
12974887Schin 			}
12984887Schin 			else
12994887Schin 			{
13004887Schin 				s = psp->ob;
13014887Schin 				psp = psp->next;
13024887Schin 			}
13034887Schin 			continue;
13044887Schin 		case '\n':
13054887Schin 			sfputc(sp, c);
13064887Schin 			for (i = 0; i < level; i++)
13074887Schin 				sfputc(sp, '\t');
13084887Schin 			continue;
13094887Schin 		case '\v':
13104887Schin 			a = FONT_LITERAL;
13114887Schin 			goto setfont;
13124887Schin 		case '<':
13134887Schin 			if (style == STYLE_html)
13144887Schin 			{
13154887Schin 				sfputr(sp, "&lt;", -1);
13164887Schin 				c = 0;
13174887Schin 				for (t = s; t < e; t++)
13184887Schin 					if (!isalnum(*t) && *t != '_' && *t != '.' && *t != '-')
13194887Schin 					{
13204887Schin 						if (*t == '@')
13214887Schin 						{
13224887Schin 							if (c)
13234887Schin 								break;
13244887Schin 							c = 1;
13254887Schin 						}
13264887Schin 						else if (*t == '>')
13274887Schin 						{
13284887Schin 							if (c)
13294887Schin 							{
13304887Schin 								sfprintf(sp, "<A href=\"mailto:%-.*s>%-.*s</A>&gt;", t - s, s, t - s, s);
13314887Schin 								s = t + 1;
13324887Schin 							}
13334887Schin 							break;
13344887Schin 						}
13354887Schin 						else
13364887Schin 							break;
13374887Schin 					}
13384887Schin 				continue;
13394887Schin 			}
13404887Schin 			break;
13414887Schin 		case '>':
13424887Schin 			if (style == STYLE_html)
13434887Schin 			{
13444887Schin 				sfputr(sp, "&gt;", -1);
13454887Schin 				continue;
13464887Schin 			}
13474887Schin 			break;
13484887Schin 		case '&':
13494887Schin 			if (style == STYLE_html)
13504887Schin 			{
13514887Schin 				sfputr(sp, "&amp;", -1);
13524887Schin 				continue;
13534887Schin 			}
13544887Schin 			break;
13554887Schin 		case '-':
13564887Schin 			if (ostyle == STYLE_nroff)
13574887Schin 				sfputc(sp, '\\');
13584887Schin 			break;
13594887Schin 		case '.':
13604887Schin 			if (ostyle == STYLE_nroff)
13614887Schin 			{
13624887Schin 				sfputc(sp, '\\');
13634887Schin 				sfputc(sp, '&');
13644887Schin 			}
13654887Schin 			break;
13664887Schin 		case '\\':
13674887Schin 			if (ostyle == STYLE_nroff)
13684887Schin 			{
13694887Schin 				c = 'e';
13704887Schin 				sfputc(sp, '\\');
13714887Schin 			}
13724887Schin 			break;
13734887Schin 		case ' ':
13744887Schin 			if (ostyle == STYLE_nroff)
13754887Schin 				sfputc(sp, '\\');
13764887Schin 			break;
13774887Schin 		}
13784887Schin 		sfputc(sp, c);
13794887Schin 	}
13804887Schin  restore:
13814887Schin 	if (f)
13824887Schin 		sfputr(sp, font(f, style, 0), -1);
13838462SApril.Chin@Sun.COM 	if (about)
13848462SApril.Chin@Sun.COM 		sfputc(sp, ')');
13854887Schin 	if (psp)
13864887Schin 		pop(psp);
13874887Schin 	return r;
13884887Schin }
13894887Schin 
13904887Schin /*
13914887Schin  * output args description to sp from p of length n
13924887Schin  */
13934887Schin 
13944887Schin static void
args(register Sfio_t * sp,register char * p,register int n,int flags,int style,Sfio_t * ip,int version,char * id,char * catalog)1395*12068SRoger.Faulkner@Oracle.COM args(register Sfio_t* sp, register char* p, register int n, int flags, int style, Sfio_t* ip, int version, char* id, char* catalog)
13964887Schin {
13974887Schin 	register int	i;
13984887Schin 	register char*	t;
13994887Schin 	register char*	o;
14004887Schin 	register char*	a = 0;
14014887Schin 	char*		b;
14024887Schin 	int		sep;
14034887Schin 
14044887Schin 	if (flags & OPT_functions)
14054887Schin 		sep = '\t';
14064887Schin 	else
14074887Schin 	{
14084887Schin 		sep = ' ';
14094887Schin 		o = T(NiL, ID, "options");
14104887Schin 		b = style == STYLE_nroff ? "\\ " : " ";
14114887Schin 		for (;;)
14124887Schin 		{
14134887Schin 			t = (char*)memchr(p, '\n', n);
14144887Schin 			if (style >= STYLE_man)
14154887Schin 			{
1416*12068SRoger.Faulkner@Oracle.COM 				if (!(a = id))
14174887Schin 					a = "...";
14184887Schin 				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);
14194887Schin 			}
14204887Schin 			else if (a)
14214887Schin 				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);
14224887Schin 			else
14234887Schin 			{
1424*12068SRoger.Faulkner@Oracle.COM 				if (!(a = error_info.id) && !(a = id))
14254887Schin 					a = "...";
14264887Schin 				if (!sfstrtell(sp))
14274887Schin 					sfprintf(sp, "[%s%s%s]", b, o, b);
14284887Schin 			}
14294887Schin 			if (!t)
14304887Schin 				break;
14314887Schin 			i = ++t - p;
14324887Schin 			if (i)
14334887Schin 			{
14344887Schin 				sfputr(sp, b, -1);
14354887Schin 				if (X(catalog))
14364887Schin 				{
14374887Schin 					sfwrite(ip, p, i);
14384887Schin 					if (b = sfstruse(ip))
1439*12068SRoger.Faulkner@Oracle.COM 						sfputr(sp, T(id, catalog, b), -1);
14404887Schin 					else
14414887Schin 						sfwrite(sp, p, i);
14424887Schin 				}
14434887Schin 				else
14444887Schin 					sfwrite(sp, p, i);
14454887Schin 			}
14464887Schin 			if (style == STYLE_html)
14474887Schin 				sfputr(sp, "<BR>", '\n');
14484887Schin 			else if (style == STYLE_nroff)
14494887Schin 				sfputr(sp, ".br", '\n');
14504887Schin 			else if (style == STYLE_api)
14514887Schin 				sfputr(sp, ".BR", '\n');
14524887Schin 			p = t;
14534887Schin 			n -= i;
14544887Schin 			while (n > 0 && (*p == ' ' || *p == '\t'))
14554887Schin 			{
14564887Schin 				p++;
14574887Schin 				n--;
14584887Schin 			}
14594887Schin 		}
14604887Schin 	}
14614887Schin 	if (n)
1462*12068SRoger.Faulkner@Oracle.COM 		label(sp, sep, p, 0, n, 0, style, 0, ip, version, id, catalog);
14634887Schin }
14644887Schin 
14654887Schin /*
14664887Schin  * output [+-...label...?...] label s to sp
14674887Schin  * according to {...} level and style
14684887Schin  * return 0:header 1:paragraph
14694887Schin  */
14704887Schin 
14714887Schin static int
item(Sfio_t * sp,char * s,int about,int level,int style,Sfio_t * ip,int version,char * id,char * catalog)1472*12068SRoger.Faulkner@Oracle.COM item(Sfio_t* sp, char* s, int about, int level, int style, Sfio_t* ip, int version, char* id, char* catalog)
14734887Schin {
14744887Schin 	register char*	t;
14754887Schin 	int		n;
14764887Schin 	int		par;
14774887Schin 
14784887Schin 	sfputc(sp, '\n');
14794887Schin 	if (*s == '\n')
14804887Schin 	{
14814887Schin 		par = 0;
14824887Schin 		if (style >= STYLE_nroff)
14834887Schin 			sfprintf(sp, ".DS\n");
14844887Schin 		else
14854887Schin 		{
14864887Schin 			if (style == STYLE_html)
14874887Schin 				sfprintf(sp, "<PRE>\n");
14884887Schin 			else
14894887Schin 				sfputc(sp, '\n');
14904887Schin 			for (n = 0; n < level; n++)
14914887Schin 				sfputc(sp, '\t');
14924887Schin 		}
1493*12068SRoger.Faulkner@Oracle.COM 		label(sp, 0, s + 1, about, -1, level, style, FONT_LITERAL, ip, version, id, catalog);
14944887Schin 		sfputc(sp, '\n');
14954887Schin 		if (style >= STYLE_nroff)
14964887Schin 			sfprintf(sp, ".DE");
14974887Schin 		else if (style == STYLE_html)
14984887Schin 			sfprintf(sp, "</PRE>");
14994887Schin 	}
15004887Schin 	else if (*s != ']' && (*s != '?' || *(s + 1) == '?'))
15014887Schin 	{
15024887Schin 		par = 0;
15034887Schin 		if (level)
15044887Schin 		{
15054887Schin 			if (style >= STYLE_nroff)
15068462SApril.Chin@Sun.COM 				sfprintf(sp, ".H%d ", (level - (level > 2)) / 2);
15074887Schin 			else
15084887Schin 				for (n = 0; n < level; n++)
15094887Schin 					sfputc(sp, '\t');
15104887Schin 		}
15114887Schin 		if (style == STYLE_html)
15124887Schin 		{
15134887Schin 			if (!level)
15144887Schin 				sfputr(sp, "<H4>", -1);
15154887Schin 			sfputr(sp, "<A name=\"", -1);
15164887Schin 			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] == '?')
15174887Schin 				for (t = s + 8; *t && *t != ']'; t++)
15184887Schin 					if (t[0] == 'p' && (!strncmp(t, "proprietary", 11) || !strncmp(t, "private", 7)) || t[0] == 'n' && !strncmp(t, "noncommercial", 13))
15194887Schin 					{
15204887Schin 						opt_info.state->flags |= OPT_proprietary;
15214887Schin 						break;
15224887Schin 					}
1523*12068SRoger.Faulkner@Oracle.COM 			label(sp, 0, s, about, -1, level, 0, 0, ip, version, id, catalog);
15244887Schin 			sfputr(sp, "\">", -1);
1525*12068SRoger.Faulkner@Oracle.COM 			label(sp, 0, s, about, -1, level, style, level ? FONT_BOLD : 0, ip, version, id, catalog);
15264887Schin 			sfputr(sp, "</A>", -1);
15274887Schin 			if (!level)
15284887Schin 				sfputr(sp, "</H4>", -1);
15294887Schin 		}
15304887Schin 		else
15314887Schin 		{
15324887Schin 			if (!level)
15334887Schin 			{
15344887Schin 				if (style >= STYLE_nroff)
15354887Schin 					sfprintf(sp, ".SH ");
15364887Schin 				else if (style == STYLE_man)
15374887Schin 					sfputc(sp, '\n');
15384887Schin 				else if (style != STYLE_options && style != STYLE_match || *s == '-' || *s == '+')
15394887Schin 					sfputc(sp, '\t');
15404887Schin 			}
1541*12068SRoger.Faulkner@Oracle.COM 			label(sp, 0, s, about, -1, level, style, FONT_BOLD, ip, version, id, catalog);
15424887Schin 		}
15434887Schin 	}
15444887Schin 	else
15454887Schin 	{
15464887Schin 		par = 1;
15474887Schin 		if (style >= STYLE_nroff)
15488462SApril.Chin@Sun.COM 			sfputr(sp, level ? ".SP" : ".PP", -1);
15494887Schin 	}
15504887Schin 	if (style >= STYLE_nroff || !level)
15514887Schin 		sfputc(sp, '\n');
15524887Schin 	if (par && style < STYLE_nroff)
15534887Schin 		for (n = 0; n < level; n++)
15544887Schin 			sfputc(sp, '\t');
15554887Schin 	return par;
15564887Schin }
15574887Schin 
15584887Schin /*
15594887Schin  * output text to sp from p according to style
15604887Schin  */
15614887Schin 
1562*12068SRoger.Faulkner@Oracle.COM #if _BLD_DEBUG
1563*12068SRoger.Faulkner@Oracle.COM 
1564*12068SRoger.Faulkner@Oracle.COM static char*	textout(Sfio_t*, char*, int, int, int, Sfio_t*, int, char*, char*);
1565*12068SRoger.Faulkner@Oracle.COM 
15664887Schin static char*
trace_textout(Sfio_t * sp,register char * p,int style,int level,int bump,Sfio_t * ip,int version,char * id,char * catalog,int line)1567*12068SRoger.Faulkner@Oracle.COM trace_textout(Sfio_t* sp, register char* p, int style, int level, int bump, Sfio_t* ip, int version, char* id, char* catalog, int line)
15684887Schin {
1569*12068SRoger.Faulkner@Oracle.COM 	static int	depth = 0;
1570*12068SRoger.Faulkner@Oracle.COM 
1571*12068SRoger.Faulkner@Oracle.COM 	message((-21, "opthelp: txt#%d +++ %2d \"%s\" style=%d level=%d bump=%d", line, ++depth, show(p), style, level, bump));
1572*12068SRoger.Faulkner@Oracle.COM 	p = textout(sp, p, style, level, bump, ip, version, id, catalog);
1573*12068SRoger.Faulkner@Oracle.COM 	message((-21, "opthelp: txt#%d --- %2d \"%s\"", line, depth--, show(p)));
1574*12068SRoger.Faulkner@Oracle.COM 	return p;
1575*12068SRoger.Faulkner@Oracle.COM }
1576*12068SRoger.Faulkner@Oracle.COM 
1577*12068SRoger.Faulkner@Oracle.COM #endif
1578*12068SRoger.Faulkner@Oracle.COM 
1579*12068SRoger.Faulkner@Oracle.COM static char*
textout(Sfio_t * sp,register char * p,int style,int level,int bump,Sfio_t * ip,int version,char * id,char * catalog)1580*12068SRoger.Faulkner@Oracle.COM textout(Sfio_t* sp, register char* p, int style, int level, int bump, Sfio_t* ip, int version, char* id, char* catalog)
1581*12068SRoger.Faulkner@Oracle.COM {
1582*12068SRoger.Faulkner@Oracle.COM #if _BLD_DEBUG
1583*12068SRoger.Faulkner@Oracle.COM #define textout(sp,p,style,level,bump,ip,version,id,catalog)	trace_textout(sp,p,style,level,bump,ip,version,id,catalog,__LINE__)
15844887Schin #endif
15854887Schin 	register char*	t;
15864887Schin 	register int	c;
15874887Schin 	register int	n;
15884887Schin 	char*		e;
15894887Schin 	int		a;
15904887Schin 	int		f;
15914887Schin 	int		par;
15928462SApril.Chin@Sun.COM 	int		about;
15934887Schin 	Push_t*		tsp;
15944887Schin 
15954887Schin 	int		ident = 0;
15964887Schin 	int		lev = level;
15974887Schin 	Push_t*		psp = 0;
15984887Schin 
15994887Schin  again:
16008462SApril.Chin@Sun.COM 	about = 0;
16014887Schin 	if ((c = *p) == GO)
16024887Schin 	{
16034887Schin 		for (;;)
16044887Schin 		{
16054887Schin 			while (*(p = next(p + 1, version)) == '\n');
16064887Schin 			if (*p == GO)
16074887Schin 			{
16084887Schin 				if (level > 1)
16094887Schin 					level++;
16104887Schin 				level++;
16114887Schin 			}
16124887Schin 			else if (*p != OG)
16134887Schin 			{
16148462SApril.Chin@Sun.COM 				if (level <= 1 || *p != '[' || *(p + 1) != '-' || style == STYLE_man && *(p + 2) == '?' || isalpha(*(p + 2)))
16154887Schin 					break;
16164887Schin 				p = skip(p, 0, 0, 0, 1, level, 0, version);
16174887Schin 			}
16184887Schin 			else if ((level -= 2) <= lev)
16194887Schin 				return p + 1;
16204887Schin 		}
16214887Schin 		if (*p == '\f')
16224887Schin 		{
1623*12068SRoger.Faulkner@Oracle.COM 			psp = info(psp, p + 1, NiL, ip, id);
16244887Schin 			if (psp->nb)
16254887Schin 				p = psp->nb;
16264887Schin 			else
16274887Schin 			{
16284887Schin 				p = psp->ob;
16294887Schin 				psp = psp->next;
16304887Schin 			}
16314887Schin 		}
16324887Schin 		if (*p != '[')
16334887Schin 			return p;
16344887Schin 		c = *++p;
16354887Schin 		if (level > 1)
16364887Schin 			level++;
16374887Schin 		level++;
16384887Schin 	}
16394887Schin 	if (c == '-' && level > 1)
16408462SApril.Chin@Sun.COM 	{
16418462SApril.Chin@Sun.COM 		if (style == STYLE_man)
16428462SApril.Chin@Sun.COM 		{
16438462SApril.Chin@Sun.COM 			about = 1;
16448462SApril.Chin@Sun.COM 			if (*(p + 1) == '-')
16458462SApril.Chin@Sun.COM 				p++;
16468462SApril.Chin@Sun.COM 		}
16478462SApril.Chin@Sun.COM 		else
16488462SApril.Chin@Sun.COM 			for (;;)
16498462SApril.Chin@Sun.COM 			{
16508462SApril.Chin@Sun.COM 				p = skip(p, 0, 0, 0, 1, level, 0, version);
16518462SApril.Chin@Sun.COM 				while (*(p = next(p + 1, version)) == '\n');
16528462SApril.Chin@Sun.COM 				if (*p == '[')
16538462SApril.Chin@Sun.COM 				{
16548462SApril.Chin@Sun.COM 					if ((c = *++p) != '-')
16558462SApril.Chin@Sun.COM 						break;
16568462SApril.Chin@Sun.COM 				}
16578462SApril.Chin@Sun.COM 				else if (*p == GO)
16588462SApril.Chin@Sun.COM 					goto again;
16598462SApril.Chin@Sun.COM 				else if (*p == OG)
16608462SApril.Chin@Sun.COM 					return p + 1;
16618462SApril.Chin@Sun.COM 			}
16628462SApril.Chin@Sun.COM 	}
16634887Schin 	if (c == '+' || c == '-' && (bump = 3) || c != ' ' && level > 1)
16644887Schin 	{
16654887Schin 		p = skip(t = p + 1, '?', 0, 0, 1, level, 0, version);
16668462SApril.Chin@Sun.COM 		if (c == '-' && (*t == '?' || isdigit(*t) || *p == '?' && *(p + 1) == '\n'))
16674887Schin 		{
16684887Schin 			if ((c = *p) != '?')
16694887Schin 				return skip(p, 0, 0, 0, 1, level, 1, version);
16708462SApril.Chin@Sun.COM 			e = C("version");
1671*12068SRoger.Faulkner@Oracle.COM 			par = item(sp, e, about, level, style, ip, version, id, ID);
16724887Schin 			for (;;)
16734887Schin 			{
16744887Schin 				while (isspace(*(p + 1)))
16754887Schin 					p++;
16764887Schin 				e = p;
16774887Schin 				if (e[1] == '@' && e[2] == '(' && e[3] == '#' && e[4] == ')')
16784887Schin 					p = e + 4;
16794887Schin 				else if (e[1] == '$' && e[2] == 'I' && e[3] == 'd' && e[4] == ':' && e[5] == ' ')
16804887Schin 				{
16814887Schin 					p = e + 5;
16824887Schin 					ident = 1;
16834887Schin 				}
16844887Schin 				else
16854887Schin 					break;
16864887Schin 			}
16874887Schin 		}
16884887Schin 		else
16894887Schin 		{
16904887Schin 			if (isdigit(c) && isdigit(*t))
16914887Schin 			{
16924887Schin 				while (isdigit(*t))
16934887Schin 					t++;
16944887Schin 				if (*t == ':')
16954887Schin 					t++;
16964887Schin 			}
16974887Schin 			else if (isalnum(c) && *t-- == ':')
16984887Schin 			{
16994887Schin 				if (X(catalog) || *t == *(t + 2))
17004887Schin 					t += 2;
17014887Schin 				else
17024887Schin 				{
17034887Schin 					sfprintf(ip, "%s", t);
17044887Schin 					if (e = sfstruse(ip))
17054887Schin 						*((t = e) + 1) = '|';
17064887Schin 				}
17074887Schin 			}
1708*12068SRoger.Faulkner@Oracle.COM 			par = item(sp, t, about, level, style, ip, version, id, catalog);
17094887Schin 			c = *p;
17104887Schin 		}
17118462SApril.Chin@Sun.COM 		if (!about && level)
17124887Schin 			par = 0;
17134887Schin 	}
17144887Schin 	else
17154887Schin 	{
17164887Schin 		if (style >= STYLE_nroff)
17174887Schin 			sfputc(sp, '\n');
17184887Schin 		else if (c == '?')
17194887Schin 			for (n = 0; n < level; n++)
17204887Schin 				sfputc(sp, '\t');
17214887Schin 		par = 0;
17224887Schin 	}
17234887Schin 	if (c == ':')
17244887Schin 		c = *(p = skip(p, '?', 0, 0, 1, 0, 0, version));
17254887Schin 	if ((c == ']' || c == '?' && *(p + 1) == ']' && *(p + 2) != ']' && p++) && (c = *(p = next(p + 1, version))) == GO)
1726*12068SRoger.Faulkner@Oracle.COM 	{
1727*12068SRoger.Faulkner@Oracle.COM 		p = textout(sp, p, style, level + bump + par + 1, 0, ip, version, id, catalog);
1728*12068SRoger.Faulkner@Oracle.COM 		if (level > lev && *p && *(p = next(p, version)) == '[')
1729*12068SRoger.Faulkner@Oracle.COM 		{
1730*12068SRoger.Faulkner@Oracle.COM 			p++;
1731*12068SRoger.Faulkner@Oracle.COM 			message((-21, "textout#%d p=%s", __LINE__, show(p)));
1732*12068SRoger.Faulkner@Oracle.COM 			goto again;
1733*12068SRoger.Faulkner@Oracle.COM 		}
1734*12068SRoger.Faulkner@Oracle.COM 	}
17354887Schin 	else if (c == '?' || c == ' ')
17364887Schin 	{
17374887Schin 		p++;
17384887Schin 		if (c == ' ')
17394887Schin 			sfputc(sp, c);
17404887Schin 		else
17414887Schin 		{
1742*12068SRoger.Faulkner@Oracle.COM 			if (X(catalog) && (tsp = localize(psp, p, NiL, 0, 1, ip, version, id, catalog)))
17434887Schin 			{
17444887Schin 				psp = tsp;
17454887Schin 				p = psp->nb;
17464887Schin 			}
17474887Schin 			if (style < STYLE_nroff)
17484887Schin 				for (n = 0; n < bump + 1; n++)
17494887Schin 					sfputc(sp, '\t');
17504887Schin 		}
17514887Schin 		f = 0;
17524887Schin 		for (;;)
17534887Schin 		{
17544887Schin 			switch (c = *p++)
17554887Schin 			{
17564887Schin 			case 0:
17574887Schin 				if (!(tsp = psp))
17584887Schin 				{
17594887Schin 					if (f)
17604887Schin 						sfputr(sp, font(f, style, 0), -1);
17614887Schin 					return p - 1;
17624887Schin 				}
17634887Schin 				p = psp->ob;
17644887Schin 				psp = psp->next;
17654887Schin 				free(tsp);
17664887Schin 				continue;
17674887Schin 			case ']':
17684887Schin 				if (psp && psp->ch)
17694887Schin 					break;
17704887Schin 				if (*p != ']')
17714887Schin 				{
17724887Schin 					if (f)
17734887Schin 					{
17744887Schin 						sfputr(sp, font(f, style, 0), -1);
17754887Schin 						f = 0;
17764887Schin 					}
17774887Schin 					for (;;)
17784887Schin 					{
17794887Schin 						if ((*p == '#' || *p == ':') && level > lev)
17804887Schin 						{
17814887Schin 							char*	o;
17824887Schin 							char*	v;
17834887Schin 							int	j;
17844887Schin 							int	m;
17854887Schin 							int	ol;
17864887Schin 							int	vl;
17874887Schin 
17884887Schin 							a = 0;
17894887Schin 							o = 0;
17904887Schin 							v = 0;
17914887Schin 							if (*++p == '?' || *p == *(p - 1))
17924887Schin 							{
17934887Schin 								p++;
17944887Schin 								a |= OPT_optional;
17954887Schin 							}
17964887Schin 							if (*(p = next(p, version)) == '[')
17974887Schin 							{
17984887Schin 								p = skip(p + 1, ':', '?', 0, 1, 0, 0, version);
17994887Schin 								while (*p == ':')
18004887Schin 								{
18014887Schin 									p = skip(t = p + 1, ':', '?', 0, 1, 0, 0, version);
18024887Schin 									m = p - t;
18034887Schin 									if (*t == '!')
18044887Schin 									{
18054887Schin 										o = t + 1;
18064887Schin 										ol = m - 1;
18074887Schin 									}
18084887Schin 									else if (*t == '=')
18094887Schin 									{
18104887Schin 										v = t + 1;
18114887Schin 										vl = m - 1;
18124887Schin 									}
18134887Schin 									else
18144887Schin 										for (j = 0; j < elementsof(attrs); j++)
18154887Schin 											if (strneq(t, attrs[j].name, m))
18164887Schin 											{
18174887Schin 												a |= attrs[j].flag;
18184887Schin 												break;
18194887Schin 											}
18204887Schin 								}
18214887Schin 							}
18224887Schin 							if (a & OPT_optional)
18234887Schin 							{
18244887Schin 								if (o)
18254887Schin 								{
18264887Schin 									sfprintf(sp, " %s ", T(NiL, ID, "If the option value is omitted then"));
18274887Schin 									sfputr(sp, font(FONT_BOLD, style, 1), -1);
18284887Schin 									t = o + ol;
18294887Schin 									while (o < t)
18304887Schin 									{
18314887Schin 										if (((c = *o++) == ':' || c == '?') && *o == c)
18324887Schin 											o++;
18334887Schin 										sfputc(sp, c);
18344887Schin 									}
18354887Schin 									sfputr(sp, font(FONT_BOLD, style, 0), -1);
18364887Schin 									sfprintf(sp, " %s.", T(NiL, ID, "is assumed"));
18374887Schin 								}
18384887Schin 								else
18394887Schin 									sfprintf(sp, " %s", T(NiL, ID, "The option value may be omitted."));
18404887Schin 							}
18414887Schin 							if (v)
18424887Schin 							{
18434887Schin 								sfprintf(sp, " %s ", T(NiL, ID, "The default value is"));
18444887Schin 								sfputr(sp, font(FONT_BOLD, style, 1), -1);
18454887Schin 								t = v + vl;
18464887Schin 								while (v < t)
18474887Schin 								{
18484887Schin 									if (((c = *v++) == ':' || c == '?') && *v == c)
18494887Schin 										v++;
18504887Schin 									sfputc(sp, c);
18514887Schin 								}
18524887Schin 								sfputr(sp, font(FONT_BOLD, style, 0), -1);
18534887Schin 								sfputc(sp, '.');
18544887Schin 							}
18554887Schin 							p = skip(p, 0, 0, 0, 1, 0, 1, version);
18564887Schin 						}
18574887Schin 						if (*(p = next(p, version)) == GO)
1858*12068SRoger.Faulkner@Oracle.COM 						{
1859*12068SRoger.Faulkner@Oracle.COM 							p = textout(sp, p, style, level + bump + !level, 0, ip, version, id, catalog);
1860*12068SRoger.Faulkner@Oracle.COM 							if (*p && *(p = next(p, version)) == '[' && !isalnum(*(p + 1)))
1861*12068SRoger.Faulkner@Oracle.COM 							{
1862*12068SRoger.Faulkner@Oracle.COM 								p++;
1863*12068SRoger.Faulkner@Oracle.COM 								message((-21, "textout#%d p=%s", __LINE__, show(p)));
1864*12068SRoger.Faulkner@Oracle.COM 								goto again;
1865*12068SRoger.Faulkner@Oracle.COM 							}
1866*12068SRoger.Faulkner@Oracle.COM 						}
18674887Schin 						else if (*p == '[' && level > lev)
18684887Schin 						{
18694887Schin 							p++;
18704887Schin 							goto again;
18714887Schin 						}
18724887Schin 						else if (*p == '\f')
18734887Schin 						{
18744887Schin 							p++;
18754887Schin 							if (style != STYLE_keys)
18764887Schin 							{
1877*12068SRoger.Faulkner@Oracle.COM 								psp = info(psp, p, NiL, ip, id);
18784887Schin 								if (psp->nb)
18794887Schin 									p = psp->nb;
18804887Schin 								else
18814887Schin 								{
18824887Schin 									p = psp->ob;
18834887Schin 									psp = psp->next;
18844887Schin 								}
18854887Schin 							}
18864887Schin 						}
18874887Schin 						else if (!*p)
18884887Schin 						{
18894887Schin 							if (!(tsp = psp))
18904887Schin 								break;
18914887Schin 							p = psp->ob;
18924887Schin 							psp = psp->next;
18934887Schin 							free(tsp);
18944887Schin 						}
18954887Schin 						else if (*p != OG)
18964887Schin 							break;
18974887Schin 						else
18984887Schin 						{
18994887Schin 							p++;
19004887Schin 							if ((level -= 2) <= lev)
19014887Schin 								break;
19024887Schin 						}
19034887Schin 					}
19044887Schin 					return p;
19054887Schin 				}
19064887Schin 				p++;
19074887Schin 				break;
19084887Schin 			case '\a':
19094887Schin 				a = FONT_ITALIC;
19104887Schin 			setfont:
19114887Schin 				if (f & ~a)
19124887Schin 				{
19134887Schin 					sfputr(sp, font(f, style, 0), -1);
19144887Schin 					f = 0;
19154887Schin 				}
19164887Schin 				if (!f && style == STYLE_html)
19174887Schin 				{
19184887Schin 					for (t = p; *t && !isspace(*t) && !iscntrl(*t); t++);
19194887Schin 					if (*t == c && *++t == '(')
19204887Schin 					{
19214887Schin 						e = t;
19224887Schin 						while (isdigit(*++t));
19234887Schin 						if (*t == ')' && t > e + 1)
19244887Schin 						{
19254887Schin 							sfprintf(sp, "<NOBR><A href=\"../man%-.*s/%-.*s.html\">%s%-.*s%s</A>%-.*s</NOBR>"
19264887Schin 								, t - e - 1, e + 1
19274887Schin 								, e - p - 1, p
19284887Schin 								, font(a, style, 1)
19294887Schin 								, e - p - 1, p
19304887Schin 								, font(a, style, 0)
19314887Schin 								, t - e + 1, e
19324887Schin 								);
19334887Schin 							p = t + 1;
19344887Schin 							continue;
19354887Schin 						}
19364887Schin 					}
19374887Schin 				}
19384887Schin 				sfputr(sp, font(a, style, !!(f ^= a)), -1);
19394887Schin 				continue;
19404887Schin 			case '\b':
19414887Schin 				a = FONT_BOLD;
19424887Schin 				goto setfont;
19434887Schin 			case '\f':
19444887Schin 				if (style != STYLE_keys)
19454887Schin 				{
1946*12068SRoger.Faulkner@Oracle.COM 					psp = info(psp, p, NiL, ip, id);
19474887Schin 					if (psp->nb)
19484887Schin 						p = psp->nb;
19494887Schin 					else
19504887Schin 					{
19514887Schin 						p = psp->ob;
19524887Schin 						psp = psp->next;
19534887Schin 					}
19544887Schin 				}
19554887Schin 				continue;
19564887Schin 			case '\v':
19574887Schin 				a = FONT_LITERAL;
19584887Schin 				goto setfont;
19594887Schin 			case ' ':
19604887Schin 				if (ident && *p == '$')
19614887Schin 				{
19624887Schin 					while (*++p)
19634887Schin 						if (*p == ']')
19644887Schin 						{
19654887Schin 							if (*(p + 1) != ']')
19664887Schin 								break;
19674887Schin 							p++;
19684887Schin 						}
19694887Schin 					continue;
19704887Schin 				}
19714887Schin 			case '\n':
19724887Schin 			case '\r':
19734887Schin 			case '\t':
19744887Schin 				while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
19754887Schin 					p++;
19764887Schin 				if (*p == ']' && *(p + 1) != ']' && (!psp || !psp->ch))
19774887Schin 					continue;
19784887Schin 				c = ' ';
19794887Schin 				break;
19804887Schin 			case '<':
19814887Schin 				if (style == STYLE_html)
19824887Schin 				{
19834887Schin 					sfputr(sp, "&lt;", -1);
19844887Schin 					c = 0;
19854887Schin 					for (t = p; *t; t++)
19864887Schin 						if (!isalnum(*t) && *t != '_' && *t != '.' && *t != '-')
19874887Schin 						{
19884887Schin 							if (*t == '@')
19894887Schin 							{
19904887Schin 								if (c)
19914887Schin 									break;
19924887Schin 								c = 1;
19934887Schin 							}
19944887Schin 							else if (*t == '>')
19954887Schin 							{
19964887Schin 								if (c)
19974887Schin 								{
19984887Schin 									sfprintf(sp, "<A href=\"mailto:%-.*s\">%-.*s</A>&gt;", t - p, p, t - p, p);
19994887Schin 									p = t + 1;
20004887Schin 								}
20014887Schin 								break;
20024887Schin 							}
20034887Schin 							else
20044887Schin 								break;
20054887Schin 						}
20064887Schin 					continue;
20074887Schin 				}
20084887Schin 				break;
20094887Schin 			case '>':
20104887Schin 				if (style == STYLE_html)
20114887Schin 				{
20124887Schin 					sfputr(sp, "&gt;", -1);
20134887Schin 					continue;
20144887Schin 				}
20154887Schin 				break;
20164887Schin 			case '&':
20174887Schin 				if (style == STYLE_html)
20184887Schin 				{
20194887Schin 					sfputr(sp, "&amp;", -1);
20204887Schin 					continue;
20214887Schin 				}
20224887Schin 				break;
20234887Schin 			case '-':
20244887Schin 				if (style == STYLE_nroff)
20254887Schin 					sfputc(sp, '\\');
20264887Schin 				break;
20274887Schin 			case '.':
20284887Schin 				if (style == STYLE_nroff)
20294887Schin 				{
20304887Schin 					sfputc(sp, '\\');
20314887Schin 					sfputc(sp, '&');
20324887Schin 				}
20334887Schin 				break;
20344887Schin 			case '\\':
20354887Schin 				if (style == STYLE_nroff)
20364887Schin 				{
20374887Schin 					sfputc(sp, c);
20384887Schin 					c = 'e';
20394887Schin 				}
20404887Schin 				break;
20414887Schin 			}
20424887Schin 			sfputc(sp, c);
20434887Schin 		}
20444887Schin 	}
20454887Schin 	else if (c == '[' && level > lev)
20464887Schin 	{
20474887Schin 		p++;
20484887Schin 		goto again;
20494887Schin 	}
20504887Schin 	return p;
20514887Schin }
20524887Schin 
20534887Schin /*
20544887Schin  * generate optget() help [...] list from lp
20554887Schin  */
20564887Schin 
20574887Schin static void
list(Sfio_t * sp,register const List_t * lp)20584887Schin list(Sfio_t* sp, register const List_t* lp)
20594887Schin {
20604887Schin 	sfprintf(sp, "[%c", lp->type);
20614887Schin 	if (lp->name)
20624887Schin 	{
20634887Schin 		sfprintf(sp, "%s", lp->name);
20644887Schin 		if (lp->text)
20654887Schin 			sfprintf(sp, "?%s", lp->text);
20664887Schin 	}
20674887Schin 	sfputc(sp, ']');
20684887Schin }
20694887Schin 
20704887Schin /*
20714887Schin  * return pointer to help message sans `Usage: command'
20724887Schin  * if oopts is 0 then opt_info.state->pass is used
20734887Schin  * what:
20744887Schin  *	0	?short by default, ?long if any long options used
20754887Schin  *	*	otherwise see help_text[] (--???)
20764887Schin  * external formatter:
20774887Schin  *	\a...\a	italic
20784887Schin  *	\b...\b	bold
20794887Schin  *	\f...\f	discipline infof callback on ...
20804887Schin  *	\v...\v	literal
20814887Schin  * internal formatter:
20824887Schin  *	\t	indent
20834887Schin  *	\n	newline
20844887Schin  * margin flush pops to previous indent
20854887Schin  */
20864887Schin 
20874887Schin char*
opthelp(const char * oopts,const char * what)20884887Schin opthelp(const char* oopts, const char* what)
20894887Schin {
20904887Schin 	register Sfio_t*	sp;
20914887Schin 	register Sfio_t*	mp;
20924887Schin 	register int		c;
20934887Schin 	register char*		p;
20944887Schin 	register Indent_t*	ip;
20954887Schin 	char*			t;
20964887Schin 	char*			x;
20974887Schin 	char*			w;
20984887Schin 	char*			u;
20994887Schin 	char*			y;
21004887Schin 	char*			s;
21014887Schin 	char*			d;
21024887Schin 	char*			v;
21034887Schin 	char*			ov;
21044887Schin 	char*			pp;
21054887Schin 	char*			rb;
21064887Schin 	char*			re;
21074887Schin 	int			f;
21084887Schin 	int			i;
21094887Schin 	int			j;
21104887Schin 	int			m;
21114887Schin 	int			n;
21124887Schin 	int			a;
21134887Schin 	int			sl;
21144887Schin 	int			vl;
21154887Schin 	int			ol;
21164887Schin 	int			wl;
21174887Schin 	int			xl;
21184887Schin 	int			rm;
21194887Schin 	int			ts;
21204887Schin 	int			co;
21214887Schin 	int			z;
21224887Schin 	int			style;
21234887Schin 	int			head;
21248462SApril.Chin@Sun.COM 	int			margin;
21254887Schin 	int			mode;
21264887Schin 	int			mutex;
21274887Schin 	int			prefix;
21284887Schin 	int			version;
21294887Schin 	long			tp;
2130*12068SRoger.Faulkner@Oracle.COM 	char*			id;
21314887Schin 	char*			catalog;
21324887Schin 	Optpass_t*		o;
21334887Schin 	Optpass_t*		q;
21344887Schin 	Optpass_t*		e;
21354887Schin 	Optpass_t		one;
21364887Schin 	Help_t*			hp;
21374887Schin 	short			ptstk[elementsof(indent) + 2];
21384887Schin 	short*			pt;
21394887Schin 	Sfio_t*			vp;
21404887Schin 	Push_t*			tsp;
21414887Schin 
21424887Schin 	char*			opts = (char*)oopts;
21434887Schin 	int			flags = 0;
21444887Schin 	int			matched = 0;
21454887Schin 	int			paragraph = 0;
21464887Schin 	int			section = 1;
21474887Schin 	Push_t*			psp = 0;
21484887Schin 	Sfio_t*			sp_help = 0;
21494887Schin 	Sfio_t*			sp_text = 0;
21504887Schin 	Sfio_t*			sp_plus = 0;
21514887Schin 	Sfio_t*			sp_head = 0;
21524887Schin 	Sfio_t*			sp_body = 0;
21534887Schin 	Sfio_t*			sp_info = 0;
21544887Schin 	Sfio_t*			sp_misc = 0;
21554887Schin 
21564887Schin 	if (!(mp = opt_info.state->mp) && !(mp = opt_info.state->mp = sfstropen()))
21574887Schin 		goto nospace;
21584887Schin 	if (!what)
21594887Schin 		style = opt_info.state->style;
21604887Schin 	else if (!*what)
21614887Schin 		style = STYLE_options;
21624887Schin 	else if (*what != '?')
21634887Schin 		style = STYLE_match;
21644887Schin 	else if (!*(what + 1))
21654887Schin 		style = STYLE_man;
21664887Schin 	else if ((hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), (char*)what + 1)) && hp->style >= 0)
21674887Schin 	{
21684887Schin 		style = hp->style;
21694887Schin 		if (*hp->name != '?')
21704887Schin 			what = hp->name;
21714887Schin 	}
21724887Schin 	else
21734887Schin 	{
21744887Schin 		if ((style = opt_info.state->force) < STYLE_man)
21754887Schin 			style = STYLE_man;
21764887Schin 		if (!(sp_help = sfstropen()))
21774887Schin 			goto nospace;
21784887Schin 		for (i = 0; i < elementsof(help_head); i++)
21794887Schin 			list(sp_help, &help_head[i]);
21804887Schin 		for (i = 0; i < elementsof(styles); i++)
21814887Schin 			sfprintf(sp_help, "[:%s?%s]", styles[i].match, styles[i].text);
21824887Schin 		for (i = 0; i < elementsof(help_tail); i++)
21834887Schin 			list(sp_help, &help_tail[i]);
21844887Schin 		if (!(opts = sfstruse(sp_help)))
21854887Schin 			goto nospace;
21864887Schin 	}
21874887Schin  again:
21884887Schin 	if (opts)
21894887Schin 	{
21904887Schin 		for (i = 0; i < opt_info.state->npass; i++)
21914887Schin 			if (opt_info.state->pass[i].oopts == opts)
21924887Schin 			{
21934887Schin 				o = &opt_info.state->pass[i];
21944887Schin 				break;
21954887Schin 			}
21964887Schin 		if (i >= opt_info.state->npass)
21974887Schin 		{
21984887Schin 			o = &one;
21994887Schin 			if (init((char*)opts, o))
22004887Schin 				goto nospace;
22014887Schin 		}
22024887Schin 		e = o + 1;
22034887Schin 	}
22044887Schin 	else if (opt_info.state->npass > 0)
22054887Schin 	{
22064887Schin 		o = opt_info.state->pass;
22074887Schin 		e = o + opt_info.state->npass;
22084887Schin 	}
22094887Schin 	else if (opt_info.state->npass < 0)
22104887Schin 	{
22114887Schin 		o = &opt_info.state->cache->pass;
22124887Schin 		e = o + 1;
22134887Schin 	}
22144887Schin 	else
22154887Schin 		return T(NiL, ID, "[* call optget() before opthelp() *]");
221610898Sroland.mainz@nrubsig.org 	if (style <= STYLE_usage)
22174887Schin 	{
22184887Schin 		if (!(sp_text = sfstropen()) || !(sp_info = sfstropen()))
22194887Schin 			goto nospace;
22204887Schin 		if (style >= STYLE_match && style < STYLE_keys && !(sp_body = sfstropen()))
22214887Schin 			goto nospace;
22224887Schin 	}
22234887Schin 	switch (style)
22244887Schin 	{
22254887Schin 	case STYLE_api:
22264887Schin 	case STYLE_html:
22274887Schin 	case STYLE_nroff:
22284887Schin 		opt_info.state->emphasis = 0;
22294887Schin 		break;
22304887Schin 	case STYLE_usage:
22314887Schin 	case STYLE_keys:
22324887Schin 		for (q = o; q < e; q++)
22334887Schin 			if (!(q->flags & OPT_ignore) && !streq(q->catalog, o->catalog))
22344887Schin 				o = q;
22354887Schin 		/*FALLTHROUGH*/
22364887Schin 	case STYLE_posix:
22374887Schin 		sfputc(mp, '\f');
22384887Schin 		break;
22394887Schin 	default:
22404887Schin 		if (!opt_info.state->emphasis)
22414887Schin 		{
22424887Schin 			if (x = getenv("ERROR_OPTIONS"))
22434887Schin 			{
22444887Schin 				if (strmatch(x, "*noemphasi*"))
22454887Schin 					break;
22464887Schin 				if (strmatch(x, "*emphasi*"))
22474887Schin 				{
22484887Schin 					opt_info.state->emphasis = 1;
22494887Schin 					break;
22504887Schin 				}
22514887Schin 			}
22524887Schin 			if ((x = getenv("TERM")) && strmatch(x, "(ansi|vt100|xterm)*") && isatty(sffileno(sfstderr)))
22534887Schin 				opt_info.state->emphasis = 1;
22544887Schin 		}
22554887Schin 		break;
22564887Schin 	}
22574887Schin 	x = "";
22584887Schin 	xl = 0;
22594887Schin 	for (q = o; q < e; q++)
22604887Schin 	{
22614887Schin 		if (q->flags & OPT_ignore)
22624887Schin 			continue;
22634887Schin 		if (section < q->section)
22644887Schin 			section = q->section;
22654887Schin 		section = q->section;
22664887Schin 		flags |= q->flags;
22674887Schin 		p = q->opts;
22684887Schin 		prefix = q->prefix;
22694887Schin 		version = q->version;
2270*12068SRoger.Faulkner@Oracle.COM 		id = q->id;
22714887Schin 		catalog = q->catalog;
22724887Schin 		switch (style)
22734887Schin 		{
22744887Schin 		case STYLE_usage:
22754887Schin 			if (xl)
22764887Schin 				sfputc(mp, '\n');
22774887Schin 			else
22784887Schin 				xl = 1;
227910898Sroland.mainz@nrubsig.org 			psp = 0;
228010898Sroland.mainz@nrubsig.org 			for (;;)
22814887Schin 			{
228210898Sroland.mainz@nrubsig.org 				switch (c = *p++)
22834887Schin 				{
228410898Sroland.mainz@nrubsig.org 				case 0:
228510898Sroland.mainz@nrubsig.org 					if (!(tsp = psp))
228610898Sroland.mainz@nrubsig.org 						goto style_usage;
228710898Sroland.mainz@nrubsig.org 					p = psp->ob;
228810898Sroland.mainz@nrubsig.org 					psp = psp->next;
228910898Sroland.mainz@nrubsig.org 					free(tsp);
229010898Sroland.mainz@nrubsig.org 					continue;
22914887Schin 				case '\a':
22924887Schin 					c = 'a';
22934887Schin 					break;
22944887Schin 				case '\b':
22954887Schin 					c = 'b';
22964887Schin 					break;
22974887Schin 				case '\f':
2298*12068SRoger.Faulkner@Oracle.COM 					psp = info(psp, p, NiL, sp_info, id);
229910898Sroland.mainz@nrubsig.org 					if (psp->nb)
230010898Sroland.mainz@nrubsig.org 						p = psp->nb;
230110898Sroland.mainz@nrubsig.org 					else
230210898Sroland.mainz@nrubsig.org 					{
230310898Sroland.mainz@nrubsig.org 						p = psp->ob;
230410898Sroland.mainz@nrubsig.org 						psp = psp->next;
230510898Sroland.mainz@nrubsig.org 					}
230610898Sroland.mainz@nrubsig.org 					continue;
23074887Schin 				case '\n':
23084887Schin 					c = 'n';
23094887Schin 					break;
23104887Schin 				case '\r':
23114887Schin 					c = 'r';
23124887Schin 					break;
23134887Schin 				case '\t':
23144887Schin 					c = 't';
23154887Schin 					break;
23164887Schin 				case '\v':
23174887Schin 					c = 'v';
23184887Schin 					break;
23194887Schin 				case '"':
23204887Schin 					c = '"';
23214887Schin 					break;
23224887Schin 				case '\'':
23234887Schin 					c = '\'';
23244887Schin 					break;
23254887Schin 				case '\\':
23264887Schin 					c = '\\';
23274887Schin 					break;
23284887Schin 				default:
23294887Schin 					sfputc(mp, c);
23304887Schin 					continue;
23314887Schin 				}
23324887Schin 				sfputc(mp, '\\');
23334887Schin 				sfputc(mp, c);
23344887Schin 			}
233510898Sroland.mainz@nrubsig.org 		style_usage:
23364887Schin 			continue;
23374887Schin 		case STYLE_keys:
23384887Schin 			a = 0;
23394887Schin 			psp = 0;
23404887Schin 			vl = 0;
23414887Schin 			for (;;)
23424887Schin 			{
23434887Schin 				if (!(c = *p++))
23444887Schin 				{
23454887Schin 					if (!(tsp = psp))
23464887Schin 						break;
23474887Schin 					p = psp->ob;
23484887Schin 					psp = psp->next;
23494887Schin 					free(tsp);
23504887Schin 					continue;
23514887Schin 				}
23524887Schin 				if (c == '\f')
23534887Schin 				{
2354*12068SRoger.Faulkner@Oracle.COM 					psp = info(psp, p, NiL, sp_info, id);
23554887Schin 					if (psp->nb)
23564887Schin 						p = psp->nb;
23574887Schin 					else
23584887Schin 					{
23594887Schin 						p = psp->ob;
23604887Schin 						psp = psp->next;
23614887Schin 					}
23624887Schin 					continue;
23634887Schin 				}
23644887Schin 				f = z = 1;
23654887Schin 				t = 0;
23664887Schin 				if (a == 0 && (c == ' ' || c == '\n' && *p == '\n'))
23674887Schin 				{
23684887Schin 					if (c == ' ' && *p == ']')
23694887Schin 					{
23704887Schin 						p++;
23714887Schin 						continue;
23724887Schin 					}
23734887Schin 					if (*p == '\n')
23744887Schin 						p++;
23754887Schin 					a = c;
23764887Schin 				}
23774887Schin 				else if (c == '\n')
23784887Schin 				{
23794887Schin 					if (a == ' ')
23804887Schin 						a = -1;
23814887Schin 					else if (a == '\n' || *p == '\n')
23824887Schin 					{
23834887Schin 						a = -1;
23844887Schin 						p++;
23854887Schin 					}
23864887Schin 					continue;
23874887Schin 				}
23884887Schin 				else if ((c == ':' || c == '#') && (*p == '[' || *p == '?' && *(p + 1) == '[' && p++))
23894887Schin 					p++;
23904887Schin 				else if (c != '[')
23914887Schin 				{
23928462SApril.Chin@Sun.COM 					if (c == GO)
23934887Schin 						vl++;
23948462SApril.Chin@Sun.COM 					else if (c == OG)
23954887Schin 						vl--;
23964887Schin 					continue;
23974887Schin 				}
23984887Schin 				else if (*p == ' ')
23994887Schin 				{
24004887Schin 					p++;
24014887Schin 					continue;
24024887Schin 				}
24034887Schin 				else if (*p == '-')
24044887Schin 				{
24054887Schin 					z = 0;
24064887Schin 					if (*++p == '-')
24074887Schin 					{
24084887Schin 						p = skip(p, 0, 0, 0, 1, 0, 1, version);
24094887Schin 						continue;
24104887Schin 					}
24114887Schin 				}
24124887Schin 				else if (*p == '+')
24134887Schin 				{
24144887Schin 					p++;
24154887Schin 					if (vl > 0 && *p != '\a')
24164887Schin 					{
24174887Schin 						f = 0;
24184887Schin 						p = skip(p, '?', 0, 0, 1, 0, 0, version);
24194887Schin 						if (*p == '?')
24204887Schin 							p++;
24214887Schin 					}
24224887Schin 				}
24234887Schin 				else
24244887Schin 				{
24254887Schin 					if (*(p + 1) == '\f' && (vp = opt_info.state->vp))
2426*12068SRoger.Faulkner@Oracle.COM 						p = expand(p + 2, NiL, &t, vp, id);
24274887Schin 					p = skip(p, ':', '?', 0, 1, 0, 0, version);
24284887Schin 					if (*p == ':')
24294887Schin 						p++;
24304887Schin 				}
24314887Schin 				if (f && *p == '?' && *(p + 1) != '?')
24324887Schin 				{
24334887Schin 					f = 0;
24344887Schin 					if (z)
24354887Schin 						p++;
24364887Schin 					else
24374887Schin 						p = skip(p, 0, 0, 0, 1, 0, 0, version);
24384887Schin 				}
24394887Schin 				if (*p == ']' && *(p + 1) != ']')
24404887Schin 				{
24414887Schin 					p++;
24424887Schin 					continue;
24434887Schin 				}
24444887Schin 				if (!*p)
24454887Schin 				{
24464887Schin 					if (!t)
24474887Schin 						break;
24484887Schin 					p = t;
24494887Schin 					t = 0;
24504887Schin 				}
24514887Schin 				m = sfstrtell(mp);
24524887Schin 				sfputc(mp, '"');
24534887Schin 				xl = 1;
24544887Schin 				/*UNDENT...*/
24554887Schin 
24564887Schin 	for (;;)
24574887Schin 	{
24584887Schin 		if (!(c = *p++))
24594887Schin 		{
24604887Schin 			if (t)
24614887Schin 			{
24624887Schin 				p = t;
24634887Schin 				t = 0;
24644887Schin 			}
24654887Schin 			if (!(tsp = psp))
24664887Schin 			{
24674887Schin 				p--;
24684887Schin 				break;
24694887Schin 			}
24704887Schin 			p = psp->ob;
24714887Schin 			psp = psp->next;
24724887Schin 			free(tsp);
24734887Schin 			continue;
24744887Schin 		}
24754887Schin 		if (a > 0)
24764887Schin 		{
24774887Schin 			if (c == '\n')
24784887Schin 			{
24794887Schin 				if (a == ' ')
24804887Schin 				{
24814887Schin 					a = -1;
24824887Schin 					break;
24834887Schin 				}
24844887Schin 				if (a == '\n' || *p == '\n')
24854887Schin 				{
24864887Schin 					a = -1;
24874887Schin 					p++;
24884887Schin 					break;
24894887Schin 				}
24904887Schin 			}
24914887Schin 		}
24924887Schin 		else if (c == ']')
24934887Schin 		{
24944887Schin 			if (*p != ']')
24954887Schin 			{
24964887Schin 				sfputc(mp, 0);
24974887Schin 				y = sfstrbase(mp) + m + 1;
24984887Schin 				if (D(y) || !strmatch(y, KEEP) || strmatch(y, OMIT))
24994887Schin 				{
25004887Schin 					sfstrseek(mp, m, SEEK_SET);
25014887Schin 					xl = 0;
25024887Schin 				}
25034887Schin 				else
25044887Schin 					sfstrseek(mp, -1, SEEK_CUR);
25054887Schin 				break;
25064887Schin 			}
25074887Schin 			sfputc(mp, *p++);
25084887Schin 			continue;
25094887Schin 		}
25104887Schin 		switch (c)
25114887Schin 		{
25124887Schin 		case '?':
25134887Schin 			if (f)
25144887Schin 			{
25154887Schin 				if (*p == '?')
25164887Schin 				{
25174887Schin 					p++;
25184887Schin 					sfputc(mp, c);
25194887Schin 				}
25204887Schin 				else
25214887Schin 				{
25224887Schin 					f = 0;
25234887Schin 					sfputc(mp, 0);
25244887Schin 					y = sfstrbase(mp) + m + 1;
25254887Schin 					if (D(y) || !strmatch(y, KEEP) || strmatch(y, OMIT))
25264887Schin 					{
25274887Schin 						sfstrseek(mp, m, SEEK_SET);
25284887Schin 						xl = 0;
25294887Schin 					}
25304887Schin 					else
25314887Schin 						sfstrseek(mp, -1, SEEK_CUR);
25324887Schin 					if (z && (*p != ']' || *(p + 1) == ']'))
25334887Schin 					{
25344887Schin 						if (xl)
25354887Schin 						{
25364887Schin 							sfputc(mp, '"');
25374887Schin 							sfputc(mp, '\n');
25384887Schin 						}
25394887Schin 						m = sfstrtell(mp);
25404887Schin 						sfputc(mp, '"');
25414887Schin 						xl = 1;
25424887Schin 					}
25434887Schin 					else
25444887Schin 					{
25454887Schin 						p = skip(p, 0, 0, 0, 1, 0, 0, version);
25464887Schin 						if (*p == '?')
25474887Schin 							p++;
25484887Schin 					}
25494887Schin 				}
25504887Schin 			}
25514887Schin 			else
25524887Schin 				sfputc(mp, c);
25534887Schin 			continue;
25544887Schin 		case ':':
25554887Schin 			if (f && *p == ':')
25564887Schin 				p++;
25574887Schin 			sfputc(mp, c);
25584887Schin 			continue;
25594887Schin 		case '\a':
25604887Schin 			c = 'a';
25614887Schin 			break;
25624887Schin 		case '\b':
25634887Schin 			c = 'b';
25644887Schin 			break;
25654887Schin 		case '\f':
25664887Schin 			c = 'f';
25674887Schin 			break;
25684887Schin 		case '\n':
25694887Schin 			c = 'n';
25704887Schin 			break;
25714887Schin 		case '\r':
25724887Schin 			c = 'r';
25734887Schin 			break;
25744887Schin 		case '\t':
25754887Schin 			c = 't';
25764887Schin 			break;
25774887Schin 		case '\v':
25784887Schin 			c = 'v';
25794887Schin 			break;
25804887Schin 		case '"':
25814887Schin 			c = '"';
25824887Schin 			break;
25834887Schin 		case '\\':
25844887Schin 			c = '\\';
25854887Schin 			break;
25864887Schin 		case CC_esc:
25874887Schin 			c = 'E';
25884887Schin 			break;
25894887Schin 		default:
25904887Schin 			sfputc(mp, c);
25914887Schin 			continue;
25924887Schin 		}
25934887Schin 		sfputc(mp, '\\');
25944887Schin 		sfputc(mp, c);
25954887Schin 	}
25964887Schin 
25974887Schin 				/*...INDENT*/
25984887Schin 				if (xl)
25994887Schin 				{
26004887Schin 					sfputc(mp, '"');
26014887Schin 					sfputc(mp, '\n');
26024887Schin 				}
26034887Schin 			}
26044887Schin 			continue;
26054887Schin 		}
26064887Schin 		z = 0;
26074887Schin 		head = 0;
26084887Schin 		mode = 0;
26094887Schin 		mutex = 0;
26104887Schin 		if (style > STYLE_short && style < STYLE_nroff && version < 1)
26114887Schin 		{
26124887Schin 			style = STYLE_short;
26134887Schin 			if (sp_body)
26144887Schin 			{
26154887Schin 				sfclose(sp_body);
26164887Schin 				sp_body = 0;
26174887Schin 			}
26184887Schin 		}
26194887Schin 		else if (style == STYLE_short && prefix < 2)
26204887Schin 			style = STYLE_long;
26214887Schin 		if (*p == ':')
26224887Schin 			p++;
26234887Schin 		if (*p == '+')
26244887Schin 		{
26254887Schin 			p++;
26264887Schin 			if (!(sp = sp_plus) && !(sp = sp_plus = sfstropen()))
26274887Schin 				goto nospace;
26284887Schin 		}
26294887Schin 		else if (style >= STYLE_match)
26304887Schin 			sp = sp_body;
26314887Schin 		else
26324887Schin 			sp = sp_text;
26334887Schin 		psp = 0;
26344887Schin 		for (;;)
26354887Schin 		{
26364887Schin 			if (!(*(p = next(p, version))))
26374887Schin 			{
26384887Schin 				if (!(tsp = psp))
26394887Schin 					break;
26404887Schin 				p = psp->ob;
26414887Schin 				psp = psp->next;
26424887Schin 				free(tsp);
26434887Schin 				continue;
26444887Schin 			}
26454887Schin 			if (*p == '\f')
26464887Schin 			{
2647*12068SRoger.Faulkner@Oracle.COM 				psp = info(psp, p + 1, NiL, sp_info, id);
26484887Schin 				if (psp->nb)
26494887Schin 					p = psp->nb;
26504887Schin 				else
26514887Schin 				{
26524887Schin 					p = psp->ob;
26534887Schin 					psp = psp->next;
26544887Schin 				}
26554887Schin 				continue;
26564887Schin 			}
26574887Schin 			if (*p == '\n' || *p == ' ')
26584887Schin 			{
26594887Schin 				if (*(x = p = next(p + 1, version)))
26604887Schin 					while (*++p)
26614887Schin 						if (*p == '\n')
26624887Schin 						{
26634887Schin 							while (*++p == ' ' || *p == '\t' || *p == '\r');
26644887Schin 							if (*p == '\n')
26654887Schin 								break;
26664887Schin 						}
26674887Schin 				xl = p - x;
26684887Schin 				if (!*p)
26694887Schin 					break;
26704887Schin 				continue;
26714887Schin 			}
26728462SApril.Chin@Sun.COM 			if (*p == OG)
26734887Schin 			{
26744887Schin 				p++;
26754887Schin 				continue;
26764887Schin 			}
26774887Schin 			message((-20, "opthelp: opt %s", show(p)));
26784887Schin 			if (z < 0)
26794887Schin 				z = 0;
26804887Schin 			a = 0;
26814887Schin 			f = 0;
26824887Schin 			w = 0;
26834887Schin 			d = 0;
26844887Schin 			s = 0;
26858462SApril.Chin@Sun.COM 			rb = re = 0;
26864887Schin 			sl = 0;
26878462SApril.Chin@Sun.COM 			vl = 0;
26884887Schin 			if (*p == '[')
26894887Schin 			{
26904887Schin 				if ((c = *(p = next(p + 1, version))) == '-')
26914887Schin 				{
26924887Schin 					if (style >= STYLE_man)
26934887Schin 					{
26944887Schin 						if (*(p + 1) != '-')
26954887Schin 						{
26964887Schin 							if (!sp_misc && !(sp_misc = sfstropen()))
26974887Schin 								goto nospace;
26984887Schin 							else
2699*12068SRoger.Faulkner@Oracle.COM 								p = textout(sp_misc, p, style, 1, 3, sp_info, version, id, catalog);
27004887Schin 							continue;
27014887Schin 						}
27024887Schin 					}
27034887Schin 					else if (style == STYLE_match && *what == '-')
27044887Schin 					{
27058462SApril.Chin@Sun.COM 						if (*(p + 1) == '?' || isdigit(*(p + 1)))
27064887Schin 							s = C("version");
27074887Schin 						else
27084887Schin 							s = p + 1;
27094887Schin 						w = (char*)what;
27104887Schin 						if (*s != '-' || *(w + 1) == '-')
27114887Schin 						{
27124887Schin 							if (*s == '-')
27134887Schin 								s++;
27144887Schin 							if (*(w + 1) == '-')
27154887Schin 								w++;
2716*12068SRoger.Faulkner@Oracle.COM 							if (match(w + 1, s, version, id, catalog))
27174887Schin 							{
27184887Schin 								if (*(p + 1) == '-')
27194887Schin 									p++;
2720*12068SRoger.Faulkner@Oracle.COM 								p = textout(sp, p, style, 1, 3, sp_info, version, id, catalog);
27214887Schin 								matched = -1;
27224887Schin 								continue;
27234887Schin 							}
27244887Schin 						}
27254887Schin 					}
27264887Schin 					if (!z)
27274887Schin 						z = -1;
27284887Schin 				}
27294887Schin 				else if (c == '+')
27304887Schin 				{
27314887Schin 					if (style >= STYLE_man)
27324887Schin 					{
2733*12068SRoger.Faulkner@Oracle.COM 						p = textout(sp_body, p, style, 0, 0, sp_info, version, id, catalog);
27344887Schin 						if (!sp_head)
27354887Schin 						{
27364887Schin 							sp_head = sp_body;
27374887Schin 							if (!(sp_body = sfstropen()))
27384887Schin 								goto nospace;
27394887Schin 						}
27404887Schin 						continue;
27414887Schin 					}
27424887Schin 					else if (style == STYLE_match && *what == '+')
27434887Schin 					{
27444887Schin 						if (paragraph)
27454887Schin 						{
27464887Schin 							if (p[1] == '?')
27474887Schin 							{
2748*12068SRoger.Faulkner@Oracle.COM 								p = textout(sp, p, style, 1, 3, sp_info, version, id, catalog);
27494887Schin 								continue;
27504887Schin 							}
27514887Schin 							paragraph = 0;
27524887Schin 						}
2753*12068SRoger.Faulkner@Oracle.COM 						if (match((char*)what + 1, p + 1, version, id, catalog))
27544887Schin 						{
2755*12068SRoger.Faulkner@Oracle.COM 							p = textout(sp, p, style, 1, 3, sp_info, version, id, catalog);
27564887Schin 							matched = -1;
27574887Schin 							paragraph = 1;
27584887Schin 							continue;
27594887Schin 						}
27604887Schin 					}
27614887Schin 					if (!z)
27624887Schin 						z = -1;
27634887Schin 				}
27644887Schin 				else if (c == '[' || version < 1)
27654887Schin 				{
27664887Schin 					mutex++;
27674887Schin 					continue;
27684887Schin 				}
27694887Schin 				else
27704887Schin 				{
27714887Schin 					if (c == '!')
27724887Schin 					{
27734887Schin 						a |= OPT_invert;
27744887Schin 						p++;
27754887Schin 					}
27764887Schin 					rb = p;
27774887Schin 					if (*p != ':')
27784887Schin 					{
27794887Schin 						s = p;
27804887Schin 						if (*(p + 1) == '|')
27814887Schin 						{
27824887Schin 							while (*++p && *p != '=' && *p != '!' && *p != ':' && *p != '?');
27834887Schin 							if ((p - s) > 1)
27844887Schin 								sl = p - s;
27854887Schin 							if (*p == '!')
27864887Schin 								a |= OPT_invert;
27874887Schin 						}
27884887Schin 						if (*(p + 1) == '\f')
27894887Schin 							p++;
27904887Schin 						else
27914887Schin 							p = skip(p, ':', '?', 0, 1, 0, 0, version);
27924887Schin 						if (sl || (p - s) == 1 || *(s + 1) == '=' || *(s + 1) == '!' && (a |= OPT_invert) || *(s + 1) == '|')
27934887Schin 							f = *s;
27944887Schin 					}
27954887Schin 					re = p;
27964887Schin 					if (style <= STYLE_short)
27974887Schin 					{
27984887Schin 						if (!z && !f)
27994887Schin 							z = -1;
28004887Schin 					}
28014887Schin 					else
28024887Schin 					{
28034887Schin 						if (*p == '\f' && (vp = opt_info.state->vp))
2804*12068SRoger.Faulkner@Oracle.COM 							p = expand(p + 1, NiL, &t, vp, id);
28054887Schin 						else
28064887Schin 							t = 0;
28074887Schin 						if (*p == ':')
28084887Schin 						{
28094887Schin 							p = skip(w = p + 1, ':', '?', 0, 1, 0, 0, version);
28104887Schin 							if (!(wl = p - w))
28114887Schin 								w = 0;
28124887Schin 						}
28134887Schin 						else
28144887Schin 							wl = 0;
28154887Schin 						if (*p == ':' || *p == '?')
28164887Schin 						{
28174887Schin 							d = p;
28184887Schin 							p = skip(p, 0, 0, 0, 1, 0, 0, version);
28194887Schin 						}
28204887Schin 						else
28214887Schin 							d = 0;
28224887Schin 						if (style == STYLE_match)
28234887Schin 						{
2824*12068SRoger.Faulkner@Oracle.COM 							if (wl && !match((char*)what, w, version, id, catalog))
28254887Schin 								wl = 0;
28264887Schin 							if ((!wl || *w == ':' || *w == '?') && (what[1] || sl && !memchr(s, what[0], sl) || !sl && what[0] != f))
28274887Schin 							{
28284887Schin 								w = 0;
28294887Schin 								if (!z)
28304887Schin 									z = -1;
28314887Schin 							}
28324887Schin 							else
28334887Schin 								matched = 1;
28344887Schin 						}
28354887Schin 						if (t)
28364887Schin 						{
28374887Schin 							p = t;
28384887Schin 							if (*p == ':' || *p == '?')
28394887Schin 							{
28404887Schin 								d = p;
28414887Schin 								p = skip(p, 0, 0, 0, 1, 0, 0, version);
28424887Schin 							}
28434887Schin 						}
28444887Schin 					}
28454887Schin 				}
28464887Schin 				p = skip(p, 0, 0, 0, 1, 0, 1, version);
28474887Schin 				if (*p == GO)
28484887Schin 					p = skip(p + 1, 0, 0, 0, 0, 1, 1, version);
28494887Schin 			}
28504887Schin 			else if (*p == ']')
28514887Schin 			{
28524887Schin 				if (mutex)
28534887Schin 				{
28544887Schin 					if (style >= STYLE_nroff)
28554887Schin 						sfputr(sp_body, "\n.OP - - anyof", '\n');
28564887Schin 					if (!(mutex & 1))
28574887Schin 					{
28584887Schin 						mutex--;
28594887Schin 						if (style <= STYLE_long)
28604887Schin 						{
28614887Schin 							sfputc(sp_body, ' ');
28624887Schin 							sfputc(sp_body, ']');
28634887Schin 						}
28644887Schin 					}
28654887Schin 					mutex--;
28664887Schin 				}
28674887Schin 				p++;
28684887Schin 				continue;
28694887Schin 			}
28704887Schin 			else if (*p == '?')
28714887Schin 			{
28724887Schin 				if (style < STYLE_match)
28734887Schin 					z = 1;
28744887Schin 				mode |= OPT_hidden;
28754887Schin 				p++;
28764887Schin 				continue;
28774887Schin 			}
28784887Schin 			else if (*p == '\\' && style==STYLE_posix)
28794887Schin 			{
28804887Schin 				if (*++p)
28814887Schin 					p++;
28824887Schin 				continue;
28834887Schin 			}
28844887Schin 			else
28854887Schin 			{
28864887Schin 				f = *p++;
28874887Schin 				s = 0;
28884887Schin 				if (style == STYLE_match && !z)
28894887Schin 					z = -1;
28904887Schin 			}
28914887Schin 			if (!z)
28924887Schin 			{
28934887Schin 				if (style == STYLE_long || prefix < 2 || (q->flags & OPT_long))
28944887Schin 					f = 0;
28954887Schin 				else if (style <= STYLE_short)
28964887Schin 					w = 0;
28974887Schin 				if (!f && !w)
28984887Schin 					z = -1;
28994887Schin 			}
29008462SApril.Chin@Sun.COM 			ov = 0;
29018462SApril.Chin@Sun.COM 			u = v = y = 0;
29024887Schin 			if (*p == ':' && (a |= OPT_string) || *p == '#' && (a |= OPT_number))
29034887Schin 			{
29044887Schin 				message((-21, "opthelp: arg %s", show(p)));
29054887Schin 				if (*++p == '?' || *p == *(p - 1))
29064887Schin 				{
29074887Schin 					p++;
29084887Schin 					a |= OPT_optional;
29094887Schin 				}
29104887Schin 				if (*(p = next(p, version)) == '[')
29114887Schin 				{
29124887Schin 					if (!z)
29134887Schin 					{
29144887Schin 						p = skip(y = p + 1, ':', '?', 0, 1, 0, 0, version);
29154887Schin 						while (*p == ':')
29164887Schin 						{
29174887Schin 							p = skip(t = p + 1, ':', '?', 0, 1, 0, 0, version);
29184887Schin 							m = p - t;
29194887Schin 							if (*t == '!')
29204887Schin 							{
29214887Schin 								ov = t + 1;
29224887Schin 								ol = m - 1;
29234887Schin 							}
29244887Schin 							else if (*t == '=')
29254887Schin 							{
29264887Schin 								v = t + 1;
29274887Schin 								vl = m - 1;
29284887Schin 							}
29294887Schin 							else
29304887Schin 								for (j = 0; j < elementsof(attrs); j++)
29314887Schin 									if (strneq(t, attrs[j].name, m))
29324887Schin 									{
29334887Schin 										a |= attrs[j].flag;
29344887Schin 										break;
29354887Schin 									}
29364887Schin 						}
29374887Schin 						if (*p == '?')
29384887Schin 							u = p;
29394887Schin 						p = skip(p, 0, 0, 0, 1, 0, 1, version);
29404887Schin 					}
29414887Schin 					else
29424887Schin 						p = skip(p + 1, 0, 0, 0, 1, 0, 1, version);
29434887Schin 				}
29444887Schin 				else
29454887Schin 					y = (a & OPT_number) ? T(NiL, ID, "#") : T(NiL, ID, "arg");
29464887Schin 			}
29474887Schin 			else
29484887Schin 				a |= OPT_flag;
29494887Schin 			if (!z)
29504887Schin 			{
29514887Schin 				if (style <= STYLE_short && !y && !mutex || style == STYLE_posix)
29524887Schin 				{
29534887Schin 					if (style != STYLE_posix && !sfstrtell(sp))
29544887Schin 					{
29554887Schin 						sfputc(sp, '[');
29564887Schin 						if (sp == sp_plus)
29574887Schin 							sfputc(sp, '+');
29584887Schin 						sfputc(sp, '-');
29594887Schin 					}
29604887Schin 					if (!sl)
29614887Schin 						sfputc(sp, f);
29624887Schin 					else
29634887Schin 						for (c = 0; c < sl; c++)
29644887Schin 							if (s[c] != '|')
29654887Schin 								sfputc(sp, s[c]);
29664887Schin 					if (style == STYLE_posix && y)
29674887Schin 						sfputc(sp, ':');
29684887Schin 				}
29694887Schin 				else
29704887Schin 				{
29714887Schin 					if (style >= STYLE_match)
29724887Schin 					{
29734887Schin 						sfputc(sp_body, '\n');
29744887Schin 						if (!head)
29754887Schin 						{
29764887Schin 							head = 1;
2977*12068SRoger.Faulkner@Oracle.COM 							item(sp_body, (flags & OPT_functions) ? C("FUNCTIONS") : C("OPTIONS"), 0, 0, style, sp_info, version, id, ID);
29784887Schin 						}
29794887Schin 						if (style >= STYLE_nroff)
29804887Schin 						{
29814887Schin 							if (mutex & 1)
29824887Schin 							{
29834887Schin 								mutex++;
29844887Schin 								sfputr(sp_body, "\n.OP - - oneof", '\n');
29854887Schin 							}
29864887Schin 						}
29874887Schin 						else
29884887Schin 							sfputc(sp_body, '\t');
29894887Schin 					}
29904887Schin 					else
29914887Schin 					{
29924887Schin 						if (sp_body)
29934887Schin 							sfputc(sp_body, ' ');
29944887Schin 						else if (!(sp_body = sfstropen()))
29954887Schin 							goto nospace;
29964887Schin 						if (mutex)
29974887Schin 						{
29984887Schin 							if (mutex & 1)
29994887Schin 							{
30004887Schin 								mutex++;
30014887Schin 								sfputc(sp_body, '[');
30024887Schin 							}
30034887Schin 							else
30044887Schin 								sfputc(sp_body, '|');
30054887Schin 							sfputc(sp_body, ' ');
30064887Schin 						}
30074887Schin 						else
30084887Schin 							sfputc(sp_body, '[');
30094887Schin 					}
30104887Schin 					if (style >= STYLE_nroff)
30114887Schin 					{
30124887Schin 						if (flags & OPT_functions)
30134887Schin 						{
30144887Schin 							sfputr(sp_body, ".FN", ' ');
30154887Schin 							if (re > rb)
30164887Schin 								sfwrite(sp_body, rb, re - rb);
30174887Schin 							else
30184887Schin 								sfputr(sp, "void", -1);
30194887Schin 							if (w)
3020*12068SRoger.Faulkner@Oracle.COM 								label(sp_body, ' ', w, 0, -1, 0, style, FONT_BOLD, sp_info, version, id, catalog);
30214887Schin 						}
30224887Schin 						else
30234887Schin 						{
30244887Schin 							sfputr(sp_body, ".OP", ' ');
30254887Schin 							if (sl)
30264887Schin 								sfwrite(sp_body, s, sl);
30274887Schin 							else
30284887Schin 								sfputc(sp_body, f ? f : '-');
30294887Schin 							sfputc(sp_body, ' ');
30304887Schin 							if (w)
30314887Schin 							{
3032*12068SRoger.Faulkner@Oracle.COM 								if (label(sp_body, 0, w, 0, -1, 0, style, 0, sp_info, version, id, catalog))
30334887Schin 								{
30344887Schin 									sfputc(sp_body, '|');
3035*12068SRoger.Faulkner@Oracle.COM 									label(sp_body, 0, w, 0, -1, 0, style, 0, sp_info, version, id, native);
30364887Schin 								}
30374887Schin 							}
30384887Schin 							else
30394887Schin 								sfputc(sp_body, '-');
30404887Schin 							sfputc(sp_body, ' ');
30414887Schin 							m = a & OPT_TYPE;
30424887Schin 							for (j = 0; j < elementsof(attrs); j++)
30434887Schin 								if (m & attrs[j].flag)
30444887Schin 								{
30454887Schin 									sfputr(sp_body, attrs[j].name, -1);
30464887Schin 									break;
30474887Schin 								}
30484887Schin 							if (m = (a & ~m) | mode)
30494887Schin 								for (j = 0; j < elementsof(attrs); j++)
30504887Schin 									if (m & attrs[j].flag)
30514887Schin 									{
30524887Schin 										sfputc(sp_body, ':');
30534887Schin 										sfputr(sp_body, attrs[j].name, -1);
30544887Schin 									}
30554887Schin 							sfputc(sp_body, ' ');
30564887Schin 							if (y)
3057*12068SRoger.Faulkner@Oracle.COM 								label(sp_body, 0, y, 0, -1, 0, style, 0, sp_info, version, id, catalog);
30584887Schin 							else
30594887Schin 								sfputc(sp_body, '-');
30604887Schin 							if (v)
30614887Schin 								sfprintf(sp_body, " %-.*s", vl, v);
30624887Schin 						}
30634887Schin 					}
30644887Schin 					else
30654887Schin 					{
30664887Schin 						if (f)
30674887Schin 						{
30684887Schin 							if (sp_body == sp_plus)
30694887Schin 								sfputc(sp_body, '+');
30704887Schin 							sfputc(sp_body, '-');
30714887Schin 							sfputr(sp_body, font(FONT_BOLD, style, 1), -1);
30724887Schin 							if (!sl)
30734887Schin 							{
30744887Schin 								sfputc(sp_body, f);
30754887Schin 								if (f == '-' && y)
30764887Schin 								{
30774887Schin 									y = 0;
30784887Schin 									sfputr(sp_body, C("long-option[=value]"), -1);
30794887Schin 								}
30804887Schin 							}
30814887Schin 							else
30824887Schin 								sfwrite(sp_body, s, sl);
30834887Schin 							sfputr(sp_body, font(FONT_BOLD, style, 0), -1);
30844887Schin 							if (w)
30854887Schin 							{
30864887Schin 								sfputc(sp_body, ',');
30874887Schin 								sfputc(sp_body, ' ');
30884887Schin 							}
30894887Schin 						}
30904887Schin 						else if ((flags & OPT_functions) && re > rb)
30914887Schin 						{
30924887Schin 							sfwrite(sp_body, rb, re - rb);
30934887Schin 							sfputc(sp_body, ' ');
30944887Schin 						}
30954887Schin 						if (w)
30964887Schin 						{
30974887Schin 							if (prefix > 0)
30984887Schin 							{
30994887Schin 								sfputc(sp_body, '-');
31004887Schin 								if (prefix > 1)
31014887Schin 									sfputc(sp_body, '-');
31024887Schin 							}
3103*12068SRoger.Faulkner@Oracle.COM 							if (label(sp_body, 0, w, 0, -1, 0, style, FONT_BOLD, sp_info, version, id, catalog))
31044887Schin 							{
31054887Schin 								sfputc(sp_body, '|');
3106*12068SRoger.Faulkner@Oracle.COM 								label(sp_body, 0, w, 0, -1, 0, style, FONT_BOLD, sp_info, version, id, native);
31074887Schin 							}
31084887Schin 						}
31094887Schin 						if (y)
31104887Schin 						{
31114887Schin 							if (a & OPT_optional)
31124887Schin 								sfputc(sp_body, '[');
31134887Schin 							else if (!w)
31144887Schin 								sfputc(sp_body, ' ');
31154887Schin 							if (w)
31164887Schin 								sfputc(sp_body, prefix == 1 ? ' ' : '=');
3117*12068SRoger.Faulkner@Oracle.COM 							label(sp_body, 0, y, 0, -1, 0, style, FONT_ITALIC, sp_info, version, id, catalog);
31184887Schin 							if (a & OPT_optional)
31194887Schin 								sfputc(sp_body, ']');
31204887Schin 						}
31214887Schin 					}
31224887Schin 					if (style >= STYLE_match)
31234887Schin 					{
31244887Schin 						if (d)
3125*12068SRoger.Faulkner@Oracle.COM 							textout(sp_body, d, style, 0, 3, sp_info, version, id, catalog);
31264887Schin 						if (u)
3127*12068SRoger.Faulkner@Oracle.COM 							textout(sp_body, u, style, 0, 3, sp_info, version, id, catalog);
31284887Schin 						if ((a & OPT_invert) && w && (d || u))
31294887Schin 						{
31304887Schin 							u = skip(w, ':', '?', 0, 1, 0, 0, version);
31314887Schin 							if (f)
31324887Schin 								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);
31334887Schin 							else
31344887Schin 								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"));
31354887Schin 							if (!(t = sfstruse(sp_info)))
31364887Schin 								goto nospace;
3137*12068SRoger.Faulkner@Oracle.COM 							textout(sp_body, t, style, 0, 0, sp_info, version, NiL, NiL);
31384887Schin 						}
31394887Schin 						if (*p == GO)
31404887Schin 						{
3141*12068SRoger.Faulkner@Oracle.COM 							p = u ? skip(p + 1, 0, 0, 0, 0, 1, 1, version) : textout(sp_body, p, style, 4, 0, sp_info, version, id, catalog);
31424887Schin 							y = "+?";
31434887Schin 						}
31444887Schin 						else
31454887Schin 							y = " ";
31464887Schin 						if (a & OPT_optional)
31474887Schin 						{
31484887Schin 							if (ov)
31494887Schin 							{
31504887Schin 								sfprintf(sp_info, "%s%s \b", y, T(NiL, ID, "If the option value is omitted then"));
31514887Schin 								t = ov + ol;
31524887Schin 								while (ov < t)
31534887Schin 								{
31544887Schin 									if (((c = *ov++) == ':' || c == '?') && *ov == c)
31554887Schin 										ov++;
31564887Schin 									sfputc(sp_info, c);
31574887Schin 								}
31584887Schin 								sfprintf(sp_info, "\b %s.", T(NiL, ID, "is assumed"));
31594887Schin 							}
31604887Schin 							else
31614887Schin 								sfprintf(sp_info, "%s%s", y, T(NiL, ID, "The option value may be omitted."));
31624887Schin 							if (!(t = sfstruse(sp_info)))
31634887Schin 								goto nospace;
3164*12068SRoger.Faulkner@Oracle.COM 							textout(sp_body, t, style, 4, 0, sp_info, version, NiL, NiL);
31654887Schin 							y = " ";
31664887Schin 						}
31674887Schin 						if (v)
31684887Schin 						{
31694887Schin 							sfprintf(sp_info, "%s%s \b", y, T(NiL, ID, "The default value is"));
31704887Schin 							t = v + vl;
31714887Schin 							while (v < t)
31724887Schin 							{
31734887Schin 								if (((c = *v++) == ':' || c == '?') && *v == c)
31744887Schin 									v++;
31754887Schin 								sfputc(sp_info, c);
31764887Schin 							}
31774887Schin 							sfputc(sp_info, '\b');
31784887Schin 							sfputc(sp_info, '.');
31794887Schin 							if (!(t = sfstruse(sp_info)))
31804887Schin 								goto nospace;
3181*12068SRoger.Faulkner@Oracle.COM 							textout(sp_body, t, style, 4, 0, sp_info, version, NiL, NiL);
31824887Schin 						}
31834887Schin 					}
31844887Schin 					else if (!mutex)
31854887Schin 						sfputc(sp_body, ']');
31864887Schin 				}
31874887Schin 				if (*p == GO)
31884887Schin 				{
31894887Schin 					if (style >= STYLE_match)
3190*12068SRoger.Faulkner@Oracle.COM 						p = textout(sp_body, p, style, 4, 0, sp_info, version, id, catalog);
31914887Schin 					else
31924887Schin 						p = skip(p + 1, 0, 0, 0, 0, 1, 1, version);
31934887Schin 				}
31944887Schin 			}
31954887Schin 			else if (*p == GO)
31964887Schin 				p = skip(p + 1, 0, 0, 0, 0, 1, 1, version);
31974887Schin 		}
31984887Schin 		psp = pop(psp);
31994887Schin 		if (sp_misc)
32004887Schin 		{
32014887Schin 			if (!(p = sfstruse(sp_misc)))
32024887Schin 				goto nospace;
32034887Schin 			for (t = p; *t == '\t' || *t == '\n'; t++);
32044887Schin 			if (*t)
32054887Schin 			{
3206*12068SRoger.Faulkner@Oracle.COM 				item(sp_body, C("IMPLEMENTATION"), 0, 0, style, sp_info, version, id, ID);
32074887Schin 				sfputr(sp_body, p, -1);
32084887Schin 			}
32094887Schin 		}
32104887Schin 	}
32114887Schin 	version = o->version;
3212*12068SRoger.Faulkner@Oracle.COM 	id = o->id;
32134887Schin 	catalog = o->catalog;
32144887Schin 	if (style >= STYLE_keys)
32154887Schin 	{
32164887Schin 		if (sp_info)
32174887Schin 			sfclose(sp_info);
32184887Schin 		if (style == STYLE_keys && sfstrtell(mp) > 1)
32194887Schin 			sfstrseek(mp, -1, SEEK_CUR);
32204887Schin 		if (!(p = sfstruse(mp)))
32214887Schin 			goto nospace;
32224887Schin 		return opt_info.msg = p;
32234887Schin 	}
32244887Schin 	sp = sp_text;
32254887Schin 	if (sfstrtell(sp) && style != STYLE_posix)
32264887Schin 		sfputc(sp, ']');
32274887Schin 	if (style == STYLE_nroff)
32284887Schin 	{
3229*12068SRoger.Faulkner@Oracle.COM 		char	ud[64];
3230*12068SRoger.Faulkner@Oracle.COM 
3231*12068SRoger.Faulkner@Oracle.COM 		s = o->id;
3232*12068SRoger.Faulkner@Oracle.COM 		t = ud;
3233*12068SRoger.Faulkner@Oracle.COM 		while (t < &ud[sizeof(ud)-2] && (c = *s++))
3234*12068SRoger.Faulkner@Oracle.COM 		{
3235*12068SRoger.Faulkner@Oracle.COM 			if (islower(c))
3236*12068SRoger.Faulkner@Oracle.COM 				c = toupper(c);
3237*12068SRoger.Faulkner@Oracle.COM 			*t++ = c;
3238*12068SRoger.Faulkner@Oracle.COM 		}
3239*12068SRoger.Faulkner@Oracle.COM 		*t = 0;
32404887Schin 		sfprintf(sp, "\
32414887Schin .\\\" format with nroff|troff|groff -man\n\
32424887Schin .fp 5 CW\n\
32438462SApril.Chin@Sun.COM .nr mH 5\n\
32448462SApril.Chin@Sun.COM .de H0\n\
32458462SApril.Chin@Sun.COM .nr mH 0\n\
32468462SApril.Chin@Sun.COM .in 5n\n\
32478462SApril.Chin@Sun.COM \\fB\\\\$1\\fP\n\
32488462SApril.Chin@Sun.COM .in 7n\n\
32494887Schin ..\n\
32504887Schin .de H1\n\
32518462SApril.Chin@Sun.COM .nr mH 1\n\
32528462SApril.Chin@Sun.COM .in 7n\n\
32534887Schin \\fB\\\\$1\\fP\n\
32548462SApril.Chin@Sun.COM .in 9n\n\
32554887Schin ..\n\
32564887Schin .de H2\n\
32578462SApril.Chin@Sun.COM .nr mH 2\n\
32588462SApril.Chin@Sun.COM .in 11n\n\
32594887Schin \\fB\\\\$1\\fP\n\
32608462SApril.Chin@Sun.COM .in 13n\n\
32614887Schin ..\n\
32624887Schin .de H3\n\
32638462SApril.Chin@Sun.COM .nr mH 3\n\
32648462SApril.Chin@Sun.COM .in 15n\n\
32654887Schin \\fB\\\\$1\\fP\n\
32668462SApril.Chin@Sun.COM .in 17n\n\
32674887Schin ..\n\
32684887Schin .de H4\n\
32698462SApril.Chin@Sun.COM .nr mH 4\n\
32708462SApril.Chin@Sun.COM .in 19n\n\
32714887Schin \\fB\\\\$1\\fP\n\
32728462SApril.Chin@Sun.COM .in 21n\n\
32734887Schin ..\n\
32744887Schin .de OP\n\
32758462SApril.Chin@Sun.COM .nr mH 0\n\
32764887Schin .ie !'\\\\$1'-' \\{\n\
32774887Schin .ds mO \\\\fB\\\\-\\\\$1\\\\fP\n\
32784887Schin .ds mS ,\\\\0\n\
32794887Schin .\\}\n\
32804887Schin .el \\{\n\
32814887Schin .ds mO \\\\&\n\
32824887Schin .ds mS \\\\&\n\
32834887Schin .\\}\n\
32844887Schin .ie '\\\\$2'-' \\{\n\
32854887Schin .if !'\\\\$4'-' .as mO \\\\0\\\\fI\\\\$4\\\\fP\n\
32864887Schin .\\}\n\
32874887Schin .el \\{\n\
32884887Schin .as mO \\\\*(mS\\\\fB%s\\\\$2\\\\fP\n\
32894887Schin .if !'\\\\$4'-' .as mO =\\\\fI\\\\$4\\\\fP\n\
32904887Schin .\\}\n\
32918462SApril.Chin@Sun.COM .in 5n\n\
32924887Schin \\\\*(mO\n\
32938462SApril.Chin@Sun.COM .in 9n\n\
32948462SApril.Chin@Sun.COM ..\n\
32958462SApril.Chin@Sun.COM .de SP\n\
32968462SApril.Chin@Sun.COM .if \\\\n(mH==2 .in 9n\n\
32978462SApril.Chin@Sun.COM .if \\\\n(mH==3 .in 13n\n\
32988462SApril.Chin@Sun.COM .if \\\\n(mH==4 .in 17n\n\
32994887Schin ..\n\
33004887Schin .de FN\n\
33018462SApril.Chin@Sun.COM .nr mH 0\n\
33028462SApril.Chin@Sun.COM .in 5n\n\
33034887Schin \\\\$1 \\\\$2\n\
33048462SApril.Chin@Sun.COM .in 9n\n\
33058462SApril.Chin@Sun.COM ..\n\
33068462SApril.Chin@Sun.COM .de DS\n\
33078462SApril.Chin@Sun.COM .in +3n\n\
33088462SApril.Chin@Sun.COM .ft 5\n\
33098462SApril.Chin@Sun.COM .nf\n\
33108462SApril.Chin@Sun.COM ..\n\
33118462SApril.Chin@Sun.COM .de DE\n\
33128462SApril.Chin@Sun.COM .fi\n\
33138462SApril.Chin@Sun.COM .ft R\n\
33148462SApril.Chin@Sun.COM .in -3n\n\
33154887Schin ..\n\
33164887Schin .TH %s %d\n\
33174887Schin "
33184887Schin , o->prefix == 2 ? "\\\\-\\\\-" : o->prefix == 1 ? "\\\\-" : ""
3319*12068SRoger.Faulkner@Oracle.COM , ud
33204887Schin , section
33214887Schin );
33224887Schin 	}
33234887Schin 	if (style == STYLE_match)
33244887Schin 	{
33254887Schin 		if (!matched)
33264887Schin 		{
33274887Schin 			if (hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), (char*)what))
33284887Schin 			{
33294887Schin 				if (!sp_help && !(sp_help = sfstropen()))
33304887Schin 					goto nospace;
33314887Schin 				sfprintf(sp_help, "[-][:%s?%s]", hp->match, hp->text);
33324887Schin 				if (!(opts = sfstruse(sp_help)))
33334887Schin 					goto nospace;
33344887Schin 				goto again;
33354887Schin 			}
33364887Schin 			s = (char*)unknown;
33374887Schin 			goto nope;
33384887Schin 		}
33394887Schin 		else if (matched < 0)
33404887Schin 			x = 0;
33414887Schin 	}
33424887Schin 	if (sp_plus)
33434887Schin 	{
33444887Schin 		if (sfstrtell(sp_plus))
33454887Schin 		{
33464887Schin 			if (sfstrtell(sp))
33474887Schin 				sfputc(sp, ' ');
33484887Schin 			if (!(t = sfstruse(sp_plus)))
33494887Schin 				goto nospace;
33504887Schin 			sfputr(sp, t, ']');
33514887Schin 		}
33524887Schin 		sfclose(sp_plus);
33534887Schin 	}
33544887Schin 	if (style >= STYLE_man)
33554887Schin 	{
33564887Schin 		if (sp_head)
33574887Schin 		{
33584887Schin 			if (!(t = sfstruse(sp_head)))
33594887Schin 				goto nospace;
33604887Schin 			for (; *t == '\n'; t++);
33614887Schin 			sfputr(sp, t, '\n');
33624887Schin 			sfclose(sp_head);
33634887Schin 			sp_head = 0;
33644887Schin 		}
3365*12068SRoger.Faulkner@Oracle.COM 		item(sp, C("SYNOPSIS"), 0, 0, style, sp_info, version, id, ID);
33664887Schin 	}
33674887Schin 	if (x)
33684887Schin 	{
33694887Schin 		for (t = x + xl; t > x && (*(t - 1) == '\n' || *(t - 1) == '\r'); t--);
33704887Schin 		xl = t - x;
33714887Schin 		if (style >= STYLE_match)
33724887Schin 		{
3373*12068SRoger.Faulkner@Oracle.COM 			args(sp, x, xl, flags, style, sp_info, version, id, catalog);
33744887Schin 			x = 0;
33754887Schin 		}
33764887Schin 	}
33774887Schin 	if (sp_body)
33784887Schin 	{
33794887Schin 		if (sfstrtell(sp_body))
33804887Schin 		{
33814887Schin 			if (style < STYLE_match && sfstrtell(sp))
33824887Schin 				sfputc(sp, ' ');
33834887Schin 			if (!(t = sfstruse(sp_body)))
33844887Schin 				goto nospace;
33854887Schin 			sfputr(sp, t, -1);
33864887Schin 		}
33874887Schin 		sfclose(sp_body);
33884887Schin 		sp_body = 0;
33894887Schin 	}
33904887Schin 	if (x && style != STYLE_posix)
3391*12068SRoger.Faulkner@Oracle.COM 		args(sp, x, xl, flags, style, sp_info, version, id, catalog);
33924887Schin 	if (sp_info)
33934887Schin 	{
33944887Schin 		sfclose(sp_info);
33954887Schin 		sp_info = 0;
33964887Schin 	}
33974887Schin 	if (sp_misc)
33984887Schin 	{
33994887Schin 		sfclose(sp_misc);
34004887Schin 		sp_misc = 0;
34014887Schin 	}
34024887Schin 	if (!(p = sfstruse(sp)))
34034887Schin 		goto nospace;
3404*12068SRoger.Faulkner@Oracle.COM 	astwinsize(1, NiL, &opt_info.state->width);
3405*12068SRoger.Faulkner@Oracle.COM 	if (opt_info.state->width < 20)
3406*12068SRoger.Faulkner@Oracle.COM 		opt_info.state->width = OPT_WIDTH;
3407*12068SRoger.Faulkner@Oracle.COM 	m = strlen((style <= STYLE_long && error_info.id && !strchr(error_info.id, '/')) ? error_info.id : id) + 1;
34088462SApril.Chin@Sun.COM 	margin = style == STYLE_api ? (8 * 1024) : (opt_info.state->width - 1);
34094887Schin 	if (!(opt_info.state->flags & OPT_preformat))
34104887Schin 	{
34114887Schin 		if (style >= STYLE_man || matched < 0)
34124887Schin 		{
34134887Schin 			sfputc(mp, '\f');
34144887Schin 			ts = 0;
34154887Schin 		}
34164887Schin 		else
34174887Schin 			ts = OPT_USAGE + m;
34184887Schin 		if (style == STYLE_html)
34194887Schin 		{
3420*12068SRoger.Faulkner@Oracle.COM 			char	ud[64];
3421*12068SRoger.Faulkner@Oracle.COM 
3422*12068SRoger.Faulkner@Oracle.COM 			s = id;
3423*12068SRoger.Faulkner@Oracle.COM 			t = ud;
3424*12068SRoger.Faulkner@Oracle.COM 			while (t < &ud[sizeof(ud)-2] && (c = *s++))
3425*12068SRoger.Faulkner@Oracle.COM 			{
3426*12068SRoger.Faulkner@Oracle.COM 				if (islower(c))
3427*12068SRoger.Faulkner@Oracle.COM 					c = toupper(c);
3428*12068SRoger.Faulkner@Oracle.COM 				*t++ = c;
3429*12068SRoger.Faulkner@Oracle.COM 			}
3430*12068SRoger.Faulkner@Oracle.COM 			*t = 0;
3431*12068SRoger.Faulkner@Oracle.COM 			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" : "", id);
3432*12068SRoger.Faulkner@Oracle.COM 			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", ud, section, T(NiL, ID, heading[section % 10]), ud, section);
34334887Schin 			sfprintf(mp, "<DL compact>\n<DT>");
34344887Schin 			co = 2;
34354887Schin 			*(pt = ptstk) = 0;
34364887Schin 		}
34374887Schin 		else
34384887Schin 			co = 0;
34398462SApril.Chin@Sun.COM 		if ((rm = margin - ts) < OPT_MARGIN)
34404887Schin 			rm = OPT_MARGIN;
34414887Schin 		ip = indent;
34424887Schin 		ip->stop = (ip+1)->stop = style >= STYLE_html ? 0 : 2;
34434887Schin 		tp = 0;
34444887Schin 		n = 0;
34454887Schin 		head = 1;
34464887Schin 		while (*p == '\n')
34474887Schin 			p++;
34484887Schin 		while (c = *p++)
34494887Schin 		{
34504887Schin 			if (c == '\n')
34514887Schin 			{
34524887Schin 				ip = indent;
34534887Schin 				n = 0;
34544887Schin 				tp = 0;
34554887Schin 				sfputc(mp, '\n');
34564887Schin 				co = 0;
34578462SApril.Chin@Sun.COM 				rm = margin;
34584887Schin 				ts = ip->stop;
34594887Schin 				if (*p == '\n')
34604887Schin 				{
34614887Schin 					while (*++p == '\n');
34624887Schin 					if ((style == STYLE_man || style == STYLE_html) && (!head || *p != ' ' && *p != '\t'))
34634887Schin 					{
34644887Schin 						if (style == STYLE_man)
34654887Schin 							p--;
34664887Schin 						else
34674887Schin 							sfprintf(mp, "<P>\n");
34684887Schin 					}
34694887Schin 				}
34704887Schin 				head = *p != ' ' && *p != '\t';
34714887Schin 				if (style == STYLE_html && (*p != '<' || !strneq(p, "<BR>", 4) && !strneq(p, "<P>", 3)))
34724887Schin 				{
34734887Schin 					y = p;
34744887Schin 					while (*p == '\t')
34754887Schin 						p++;
34764887Schin 					if (*p == '\n')
34774887Schin 						continue;
34784887Schin 					j = p - y;
34794887Schin 					if (j > *pt)
34804887Schin 					{
34814887Schin 						if (pt > ptstk)
34824887Schin 							sfprintf(mp, "<DL compact>\n");
34834887Schin 						*++pt = j;
34844887Schin 						sfprintf(mp, "<DL compact>\n");
34854887Schin 					}
34864887Schin 					else while (j < *pt)
34874887Schin 					{
34884887Schin 						if (--pt > ptstk)
34894887Schin 							sfprintf(mp, "</DL>\n");
34904887Schin 						sfprintf(mp, "</DL>\n");
34914887Schin 					}
34924887Schin 					co += sfprintf(mp, "<DT>");
34934887Schin 				}
34944887Schin 			}
34954887Schin 			else if (c == '\t')
34964887Schin 			{
34974887Schin 				if (style == STYLE_html)
34984887Schin 				{
34994887Schin 					while (*p == '\t')
35004887Schin 						p++;
35014887Schin 					if (*p != '\n')
35024887Schin 						co += sfprintf(mp, "<DD>");
35034887Schin 				}
35044887Schin 				else
35054887Schin 				{
35064887Schin 					if ((ip+1)->stop)
35074887Schin 					{
35084887Schin 						do
35094887Schin 						{
35104887Schin 							ip++;
35114887Schin 							if (*p != '\t')
35124887Schin 								break;
35134887Schin 							p++;
35144887Schin 						} while ((ip+1)->stop);
35154887Schin 						if (*p == '\n')
35164887Schin 							continue;
35174887Schin 						ts = ip->stop;
35184887Schin 						if (co >= ts)
35194887Schin 						{
35204887Schin 							sfputc(mp, '\n');
35214887Schin 							co = 0;
35228462SApril.Chin@Sun.COM 							rm = margin;
35234887Schin 							ts = ip->stop;
35244887Schin 						}
35254887Schin 					}
35264887Schin 					while (co < ts)
35274887Schin 					{
35284887Schin 						sfputc(mp, ' ');
35294887Schin 						co++;
35304887Schin 					}
35314887Schin 				}
35324887Schin 			}
35334887Schin 			else
35344887Schin 			{
35354887Schin 				if (c == ' ' && !n)
35364887Schin 				{
35374887Schin 					if (co >= rm)
35384887Schin 						tp = 0;
35394887Schin 					else
35404887Schin 					{
35414887Schin 						tp = sfstrtell(mp);
35424887Schin 						pp = p;
35434887Schin 					}
35444887Schin 					if (style == STYLE_nroff && !co)
35454887Schin 						continue;
35464887Schin 				}
35474887Schin 				else if (style == STYLE_html)
35484887Schin 				{
35494887Schin 					if (c == '<')
35504887Schin 					{
35514887Schin 						if (strneq(p, "NOBR>", 5))
35524887Schin 							n++;
35534887Schin 						else if (n && strneq(p, "/NOBR>", 6) && !--n)
35544887Schin 						{
35554887Schin 							for (y = p += 6; (c = *p) && c != ' ' && c != '\t' && c != '\n' && c != '<'; p++)
35564887Schin 								if (c == '[')
35574887Schin 									sfputr(mp, "&#0091;", -1);
35584887Schin 								else if (c == ']')
35594887Schin 									sfputr(mp, "&#0093;", -1);
35604887Schin 								else
35614887Schin 									sfputc(mp, c);
35624887Schin 							sfwrite(mp, "</NOBR", 6);
35634887Schin 							c = '>';
35644887Schin 							tp = 0;
35654887Schin 							co += p - y + 6;
35664887Schin 						}
35674887Schin 					}
35684887Schin 					else if (c == '>' && !n)
35694887Schin 					{
35704887Schin 						for (y = --p; (c = *p) && c != ' ' && c != '\t' && c != '\n' && c != '<'; p++)
35714887Schin 							if (c == '[')
35724887Schin 								sfputr(mp, "&#0091;", -1);
35734887Schin 							else if (c == ']')
35744887Schin 								sfputr(mp, "&#0093;", -1);
35754887Schin 							else
35764887Schin 								sfputc(mp, c);
35774887Schin 						c = *sfstrseek(mp, -1, SEEK_CUR);
35784887Schin 						if (p > y + 1)
35794887Schin 						{
35804887Schin 							tp = 0;
35814887Schin 							co += p - y - 1;
35824887Schin 						}
35834887Schin 						if (co >= rm)
35844887Schin 							tp = 0;
35854887Schin 						else
35864887Schin 						{
35874887Schin 							tp = sfstrtell(mp);
35884887Schin 							pp = p;
35894887Schin 						}
35904887Schin 					}
35914887Schin 					else if (c == '[')
35924887Schin 					{
35934887Schin 						sfputr(mp, "&#0091", -1);
35944887Schin 						c = ';';
35954887Schin 					}
35964887Schin 					else if (c == ']')
35974887Schin 					{
35984887Schin 						sfputr(mp, "&#0093", -1);
35994887Schin 						c = ';';
36004887Schin 					}
36014887Schin 					else if (c == 'h')
36024887Schin 					{
36034887Schin 						y = p;
36044887Schin 						if (*y++ == 't' && *y++ == 't' && *y++ == 'p' && (*y == ':' || *y++ == 's' && *y == ':') && *y++ == ':' && *y++ == '/' && *y++ == '/')
36054887Schin 						{
36064887Schin 							while (isalnum(*y) || *y == '_' || *y == '/' || *y == '-' || *y == '.')
36074887Schin 								y++;
36084887Schin 							if (*y == '?')
36094887Schin 								while (isalnum(*y) || *y == '_' || *y == '/' || *y == '-' || *y == '.' || *y == '?' || *y == '=' || *y == '%' || *y == '&' || *y == ';' || *y == '#')
36104887Schin 									y++;
36114887Schin 							if (*(y - 1) == '.')
36124887Schin 								y--;
36134887Schin 							p--;
36144887Schin 							sfprintf(mp, "<A href=\"%-.*s\">%-.*s</A", y - p, p, y - p, p);
36154887Schin 							p = y;
36164887Schin 							c = '>';
36174887Schin 						}
36184887Schin 					}
36194887Schin 					else if (c == 'C')
36204887Schin 					{
36214887Schin 						y = p;
36224887Schin 						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++ == ')')
36234887Schin 						{
36244887Schin 							sfputr(mp, "Copyright &copy", -1);
36254887Schin 							p = y;
36264887Schin 							c = ';';
36274887Schin 						}
36284887Schin 					}
36294887Schin 				}
36304887Schin 				else if (c == ']')
36314887Schin 				{
36324887Schin 					if (n)
36334887Schin 						n--;
36344887Schin 				}
36354887Schin 				else if (c == '[')
36364887Schin 					n++;
36374887Schin 				if (c == CC_esc)
36384887Schin 				{
36394887Schin 					sfputc(mp, c);
36404887Schin 					do
36414887Schin 					{
36424887Schin 						if (!(c = *p++))
36434887Schin 						{
36444887Schin 							p--;
36454887Schin 							break;
36464887Schin 						}
36474887Schin 						sfputc(mp, c);
36484887Schin 					} while (c < 'a' || c > 'z');
36494887Schin 				}
36504887Schin 				else if (co++ >= rm && !n)
36514887Schin 				{
36524887Schin 					if (tp)
36534887Schin 					{
36544887Schin 						if (*sfstrseek(mp, tp, SEEK_SET) != ' ')
36554887Schin 							sfstrseek(mp, 1, SEEK_CUR);
36564887Schin 						tp = 0;
36574887Schin 						p = pp;
36584887Schin 						n = 0;
36594887Schin 					}
36604887Schin 					else if (c != ' ' && c != '\n')
36614887Schin 						sfputc(mp, c);
36624887Schin 					if (*p == ' ')
36634887Schin 						p++;
36644887Schin 					if (*p != '\n')
36654887Schin 					{
36664887Schin 						sfputc(mp, '\n');
36674887Schin 						for (co = 0; co < ts; co++)
36684887Schin 							sfputc(mp, ' ');
36698462SApril.Chin@Sun.COM 						rm = margin;
36704887Schin 					}
36714887Schin 				}
36724887Schin 				else
36734887Schin 					sfputc(mp, c);
36744887Schin 			}
36754887Schin 		}
36764887Schin 		for (d = sfstrbase(mp), t = sfstrseek(mp, 0, SEEK_CUR); t > d && ((c = *(t - 1)) == '\n' || c == '\r' || c == ' ' || c == '\t'); t--);
36774887Schin 		sfstrseek(mp, t - d, SEEK_SET);
36784887Schin 		if (style == STYLE_html)
36794887Schin 		{
36804887Schin 			while (pt > ptstk)
36814887Schin 			{
36824887Schin 				if (--pt > ptstk)
36834887Schin 					sfprintf(mp, "\n</DL>");
36844887Schin 				sfprintf(mp, "\n</DL>");
36854887Schin 			}
36864887Schin 			sfprintf(mp, "</DL>\n</BODY>\n</HTML>");
36874887Schin 		}
36884887Schin 	}
36894887Schin 	else
36904887Schin 		sfputr(mp, p, 0);
36914887Schin 	if (!(p = sfstruse(mp)))
36924887Schin 		goto nospace;
36934887Schin 	if (sp)
36944887Schin 		sfclose(sp);
36954887Schin 	return opt_info.msg = p;
36964887Schin  nospace:
36974887Schin 	s = T(NiL, ID, "[* out of space *]");
36984887Schin  nope:
36994887Schin 	if (psp)
37004887Schin 		pop(psp);
37014887Schin 	if (sp_help)
37024887Schin 		sfclose(sp_help);
37034887Schin 	if (sp_text)
37044887Schin 		sfclose(sp_text);
37054887Schin 	if (sp_plus)
37064887Schin 		sfclose(sp_plus);
37074887Schin 	if (sp_info)
37084887Schin 		sfclose(sp_info);
37094887Schin 	if (sp_head)
37104887Schin 		sfclose(sp_head);
37114887Schin 	if (sp_body)
37124887Schin 		sfclose(sp_body);
37134887Schin 	if (sp_misc)
37144887Schin 		sfclose(sp_misc);
37154887Schin 	return s;
37164887Schin }
37174887Schin 
37184887Schin /*
37194887Schin  * compatibility wrapper to opthelp()
37204887Schin  */
37214887Schin 
37224887Schin char*
optusage(const char * opts)37234887Schin optusage(const char* opts)
37244887Schin {
37254887Schin 	return opthelp(opts, NiL);
37264887Schin }
37274887Schin 
37284887Schin /*
37294887Schin  * convert number using strtonll() *except* that
37304887Schin  * 0*[[:digit:]].* is treated as [[:digit:]].*
37314887Schin  * i.e., it looks octal but isn't, to meet
37324887Schin  * posix Utility Argument Syntax -- use
37334887Schin  * 0x.* or <base>#* for alternate bases
37344887Schin  */
37354887Schin 
37364887Schin static intmax_t
optnumber(const char * s,char ** t,int * e)37374887Schin optnumber(const char* s, char** t, int* e)
37384887Schin {
37394887Schin 	intmax_t	n;
37404887Schin 	int		oerrno;
37414887Schin 
37424887Schin 	while (*s == '0' && isdigit(*(s + 1)))
37434887Schin 		s++;
37444887Schin 	oerrno = errno;
37454887Schin 	errno = 0;
37464887Schin 	n = strtonll(s, t, NiL, 0);
37474887Schin 	if (e)
37484887Schin 		*e = errno;
37494887Schin 	errno = oerrno;
37504887Schin 	return n;
37514887Schin }
37524887Schin 
37534887Schin /*
37544887Schin  * point opt_info.arg to an error/info message for opt_info.name
37554887Schin  * p points to opts location for opt_info.name
37564887Schin  * optget() return value is returned
37574887Schin  */
37584887Schin 
37594887Schin static int
opterror(register char * p,int err,int version,char * id,char * catalog)3760*12068SRoger.Faulkner@Oracle.COM opterror(register char* p, int err, int version, char* id, char* catalog)
37614887Schin {
37624887Schin 	register Sfio_t*	mp;
37634887Schin 	register Sfio_t*	tp;
37644887Schin 	register char*		s;
37654887Schin 	register int		c;
37664887Schin 
37674887Schin 	if (opt_info.num != LONG_MIN)
376810898Sroland.mainz@nrubsig.org 		opt_info.num = (long)(opt_info.number = 0);
37694887Schin 	if (!p || !(mp = opt_info.state->mp) && !(mp = opt_info.state->mp = sfstropen()))
37704887Schin 		goto nospace;
37714887Schin 	s = *p == '-' ? p : opt_info.name;
37724887Schin 	if (*p == '!')
37734887Schin 	{
37744887Schin 		while (*s == '-')
37754887Schin 			sfputc(mp, *s++);
37764887Schin 		sfputc(mp, 'n');
37774887Schin 		sfputc(mp, 'o');
37784887Schin 	}
37794887Schin 	sfputr(mp, s, ':');
37804887Schin 	sfputc(mp, ' ');
37814887Schin 	if (*p == '#' || *p == ':')
37824887Schin 	{
37834887Schin 		if (*p == '#')
37844887Schin 		{
37854887Schin 			s = T(NiL, ID, "numeric");
37864887Schin 			sfputr(mp, s, ' ');
37874887Schin 		}
37884887Schin 		if (*(p = next(p + 1, version)) == '[')
37894887Schin 		{
37904887Schin 			p = skip(s = p + 1, ':', '?', 0, 1, 0, 0, version);
37914887Schin 			tp = X(catalog) ? opt_info.state->xp : mp;
37924887Schin 			while (s < p)
37934887Schin 			{
37944887Schin 				if ((c = *s++) == '?' || c == ']')
37954887Schin 					s++;
37964887Schin 				sfputc(tp, c);
37974887Schin 			}
37984887Schin 			if (!X(catalog))
37994887Schin 				sfputc(mp, ' ');
38004887Schin 			else if (p = sfstruse(tp))
3801*12068SRoger.Faulkner@Oracle.COM 				sfputr(mp, T(id, catalog, p), ' ');
38024887Schin 			else
38034887Schin 				goto nospace;
38044887Schin 		}
38054887Schin 		p = opt_info.name[2] ? C("value expected") : C("argument expected");
38064887Schin 	}
38074887Schin 	else if (*p == '*' || *p == '&')
38084887Schin 	{
38094887Schin 		sfputr(mp, opt_info.arg, ':');
38104887Schin 		sfputc(mp, ' ');
38114887Schin 		p = *p == '&' ? C("ambiguous option argument value") : C("unknown option argument value");
38124887Schin 	}
38134887Schin 	else if (*p == '=' || *p == '!')
38144887Schin 		p = C("value not expected");
38154887Schin 	else if (*p == '?')
38164887Schin 		p = *(p + 1) == '?' ? C("optget: option not supported") : C("ambiguous option");
38174887Schin 	else if (*p == '+')
38184887Schin 		p = C("section not found");
38194887Schin 	else
38204887Schin 	{
38214887Schin 		if (opt_info.option[0] != '?' && opt_info.option[0] != '-' || opt_info.option[1] != '?' && opt_info.option[1] != '-')
38224887Schin 			opt_info.option[0] = 0;
38234887Schin 		p = C("unknown option");
38244887Schin 	}
38254887Schin 	p = T(NiL, ID, p);
38264887Schin 	sfputr(mp, p, -1);
38274887Schin 	if (err)
38284887Schin 		sfputr(mp, " -- out of range", -1);
38294887Schin 	if (opt_info.arg = sfstruse(mp))
38304887Schin 		return ':';
38314887Schin  nospace:
38324887Schin 	opt_info.arg = T(NiL, ID, "[* out of space *]");
38334887Schin 	return ':';
38344887Schin }
38354887Schin 
38364887Schin /*
38374887Schin  * argv:	command line argv where argv[0] is command name
38384887Schin  *
38394887Schin  * opts:	option control string
38404887Schin  *
38414887Schin  *	'[' [flag][=][index][:<long-name>[|<alias-name>...]['?'description]] ']'
38424887Schin  *			long option name, index, description; -index returned
38434887Schin  *	':'		option takes string arg
38444887Schin  *	'#'		option takes numeric arg (concat option may follow)
38454887Schin  *	'?'		(option) following options not in usage
38464887Schin  *			(following # or :) optional arg
38474887Schin  *	'[' '[' ... ] ... '[' ... ']' ']'
38484887Schin  *			mutually exclusive option grouping
38494887Schin  *	'[' name [:attr]* [?description] ']'
38504887Schin  *			(following # or :) optional option arg description
38514887Schin  *	'\n'[' '|'\t']*	ignored for legibility
38524887Schin  *	' ' ...		optional argument(s) description (to end of string)
38534887Schin  *			or after blank line
38544887Schin  *	']]'		literal ']' within '[' ... ']'
38554887Schin  *
38564887Schin  * return:
38574887Schin  *	0		no more options
38584887Schin  *	'?'		usage: opt_info.arg points to message sans
38594887Schin  *			`Usage: command '
38604887Schin  *	':'		error: opt_info.arg points to message sans `command: '
38614887Schin  *
386210898Sroland.mainz@nrubsig.org  * ':'  '#'  ' '  '['  ']'
38634887Schin  *			invalid option chars
38644887Schin  *
38654887Schin  * -- terminates option list and returns 0
38664887Schin  *
38674887Schin  * + as first opts char makes + equivalent to -
38684887Schin  *
38694887Schin  * if any # option is specified then numeric options (e.g., -123)
38704887Schin  * are associated with the leftmost # option in opts
38714887Schin  *
38724887Schin  * usage info in placed opt_info.arg when '?' returned
38734887Schin  * see help_text[] (--???) for more info
38744887Schin  */
38754887Schin 
38764887Schin int
optget(register char ** argv,const char * oopts)38774887Schin optget(register char** argv, const char* oopts)
38784887Schin {
38794887Schin 	register int	c;
38804887Schin 	register char*	s;
38814887Schin 	char*		a;
38824887Schin 	char*		b;
38834887Schin 	char*		e;
38844887Schin 	char*		f;
38854887Schin 	char*		g;
38864887Schin 	char*		v;
38874887Schin 	char*		w;
38884887Schin 	char*		p;
38894887Schin 	char*		q;
38904887Schin 	char*		t;
38914887Schin 	char*		y;
38924887Schin 	char*		numopt;
38934887Schin 	char*		opts;
3894*12068SRoger.Faulkner@Oracle.COM 	char*		id;
38954887Schin 	char*		catalog;
38964887Schin 	int		n;
38974887Schin 	int		m;
38984887Schin 	int		k;
38994887Schin 	int		j;
39004887Schin 	int		x;
39014887Schin 	int		err;
39024887Schin 	int		no;
39034887Schin 	int		nov;
39044887Schin 	int		num;
39054887Schin 	int		numchr;
39064887Schin 	int		prefix;
39074887Schin 	int		version;
39084887Schin 	Help_t*		hp;
39094887Schin 	Push_t*		psp;
39104887Schin 	Push_t*		tsp;
39114887Schin 	Sfio_t*		vp;
39124887Schin 	Sfio_t*		xp;
39134887Schin 	Optcache_t*	cache;
39144887Schin 	Optcache_t*	pcache;
39154887Schin 	Optpass_t*	pass;
39164887Schin 
39178462SApril.Chin@Sun.COM #if !_PACKAGE_astsa && !_YOU_FIGURED_OUT_HOW_TO_GET_ALL_DLLS_TO_DO_THIS_
39184887Schin 	/*
39194887Schin 	 * these are not initialized by all dlls!
39204887Schin 	 */
39214887Schin 
39224887Schin 	extern Error_info_t	_error_info_;
39234887Schin 	extern Opt_t		_opt_info_;
39244887Schin 
39254887Schin 	if (!_error_infop_)
39264887Schin 		_error_infop_ = &_error_info_;
39274887Schin 	if (!_opt_infop_)
39284887Schin 		_opt_infop_ = &_opt_info_;
39294887Schin 	if (!opt_info.state)
39304887Schin 		opt_info.state = &state;
39314887Schin #endif
39324887Schin 	if (!oopts)
39334887Schin 		return 0;
39344887Schin 	opt_info.state->pindex = opt_info.index;
39354887Schin 	opt_info.state->poffset = opt_info.offset;
39364887Schin 	if (!opt_info.index)
39374887Schin 	{
39384887Schin 		opt_info.index = 1;
39394887Schin 		opt_info.offset = 0;
39404887Schin 		if (opt_info.state->npass)
39414887Schin 		{
39424887Schin 			opt_info.state->npass = 0;
39434887Schin 			opt_info.state->join = 0;
39444887Schin 		}
39454887Schin 	}
39464887Schin 	if (!argv)
39474887Schin 		cache = 0;
39484887Schin 	else
39494887Schin 		for (pcache = 0, cache = opt_info.state->cache; cache; pcache = cache, cache = cache->next)
39504887Schin 			if (cache->pass.oopts == (char*)oopts)
39514887Schin 				break;
39524887Schin 	if (cache)
39534887Schin 	{
39544887Schin 		if (pcache)
39554887Schin 		{
39564887Schin 			pcache->next = cache->next;
39574887Schin 			cache->next = opt_info.state->cache;
39584887Schin 			opt_info.state->cache = cache;
39594887Schin 		}
39604887Schin 		pass = &cache->pass;
39614887Schin 		opt_info.state->npass = -1;
39624887Schin 	}
39634887Schin 	else
39644887Schin 	{
39654887Schin 		if (!argv)
39664887Schin 			n = opt_info.state->npass ? opt_info.state->npass : 1;
39674887Schin 		else if ((n = opt_info.state->join - 1) < 0)
39684887Schin 			n = 0;
39694887Schin 		if (n >= opt_info.state->npass || opt_info.state->pass[n].oopts != (char*)oopts)
39704887Schin 		{
39714887Schin 			for (m = 0; m < opt_info.state->npass && opt_info.state->pass[m].oopts != (char*)oopts; m++);
39724887Schin 			if (m < opt_info.state->npass)
39734887Schin 				n = m;
39744887Schin 			else
39754887Schin 			{
39764887Schin 				if (n >= elementsof(opt_info.state->pass))
39774887Schin 					n = elementsof(opt_info.state->pass) - 1;
39784887Schin 				init((char*)oopts, &opt_info.state->pass[n]);
39794887Schin 				if (opt_info.state->npass <= n)
39804887Schin 					opt_info.state->npass = n + 1;
39814887Schin 			}
39824887Schin 		}
39834887Schin 		if (!argv)
39844887Schin 			return 0;
39854887Schin 		pass = &opt_info.state->pass[n];
39864887Schin 	}
39874887Schin 	opts = pass->opts;
39884887Schin 	prefix = pass->prefix;
39894887Schin 	version = pass->version;
3990*12068SRoger.Faulkner@Oracle.COM 	id = pass->id;
39914887Schin 	if (!(xp = opt_info.state->xp) || (catalog = pass->catalog) && !X(catalog))
39924887Schin 		catalog = 0;
39934887Schin 	else /* if (!error_info.catalog) */
39944887Schin 		error_info.catalog = catalog;
39954887Schin  again:
39964887Schin 	psp = 0;
39974887Schin 
39984887Schin 	/*
39994887Schin 	 * check if any options remain and determine if the
40004887Schin 	 * next option is short or long
40014887Schin 	 */
40024887Schin 
40034887Schin 	opt_info.assignment = 0;
40044887Schin 	num = 1;
40054887Schin 	w = v = 0;
40064887Schin 	x = 0;
40074887Schin 	for (;;)
40084887Schin 	{
40094887Schin 		if (!opt_info.offset)
40104887Schin 		{
40114887Schin 			/*
40124887Schin 			 * finished with the previous arg
40134887Schin 			 */
40144887Schin 
40154887Schin 			if (opt_info.index == 1 && opt_info.argv != opt_info.state->strv)
40164887Schin 			{
40174887Schin 				opt_info.argv = 0;
40184887Schin 				opt_info.state->argv[0] = 0;
40194887Schin 				if (argv[0] && (opt_info.state->argv[0] = save(argv[0])))
40204887Schin 					opt_info.argv = opt_info.state->argv;
40214887Schin 				opt_info.state->style = STYLE_short;
40224887Schin 			}
40234887Schin 			if (!(s = argv[opt_info.index]))
40244887Schin 				return 0;
40254887Schin 			if (!prefix)
40264887Schin 			{
40274887Schin 				/*
40284887Schin 				 * long with no prefix (dd style)
40294887Schin 				 */
40304887Schin 
40314887Schin 				n = 2;
40324887Schin 				if ((c = *s) != '-' && c != '+')
40334887Schin 					c = '-';
40344887Schin 				else if (*++s == c)
40354887Schin 				{
40364887Schin 					if (!*++s)
40374887Schin 					{
40384887Schin 						opt_info.index++;
40394887Schin 						return 0;
40404887Schin 					}
40418462SApril.Chin@Sun.COM 					else if (*s == c)
40428462SApril.Chin@Sun.COM 						return 0;
40434887Schin 				}
40444887Schin 				else if (*s == '?')
40454887Schin 					n = 1;
40464887Schin 			}
40478462SApril.Chin@Sun.COM 			else if ((c = *s++) != '-' && (c != '+' || !(pass->flags & OPT_plus) && (!(pass->flags & OPT_numeric) || !isdigit(*s))))
40484887Schin 			{
40494887Schin 				if (!(pass->flags & OPT_old) || !isalpha(c))
40504887Schin 					return 0;
40514887Schin 				s--;
40524887Schin 				n = 1;
40534887Schin 				opt_info.offset--;
40544887Schin 			}
40554887Schin 			else if (*s == c)
40564887Schin 			{
40574887Schin 				if (!*++s)
40584887Schin 				{
40594887Schin 					/*
40604887Schin 					 * -- or ++ end of options
40614887Schin 					 */
40624887Schin 
40634887Schin 					opt_info.index++;
40644887Schin 					return 0;
40654887Schin 				}
40668462SApril.Chin@Sun.COM 				else if (*s == c)
40678462SApril.Chin@Sun.COM 				{
40688462SApril.Chin@Sun.COM 					/*
40698462SApril.Chin@Sun.COM 					 * ---* or +++* are operands
40708462SApril.Chin@Sun.COM 					 */
40718462SApril.Chin@Sun.COM 
40728462SApril.Chin@Sun.COM 					return 0;
40738462SApril.Chin@Sun.COM 				}
40744887Schin 				if (version || *s == '?' || !(pass->flags & OPT_minus))
40754887Schin 				{
40764887Schin 					/*
40774887Schin 					 * long with double prefix
40784887Schin 					 */
40794887Schin 
40804887Schin 					n = 2;
40814887Schin 				}
40824887Schin 				else
40834887Schin 				{
40844887Schin 					/*
40854887Schin 					 * short option char '-'
40864887Schin 					 */
40874887Schin 
40884887Schin 					s--;
40894887Schin 					n = 1;
40904887Schin 				}
40914887Schin 			}
40924887Schin 			else if (prefix == 1 && *s != '?')
40934887Schin 			{
40944887Schin 				/*
40954887Schin 				 * long with single prefix (find style)
40964887Schin 				 */
40974887Schin 
40984887Schin 				n = 2;
40994887Schin 			}
41004887Schin 			else
41014887Schin 			{
41024887Schin 				/*
41034887Schin 				 * short (always with single prefix)
41044887Schin 				 */
41054887Schin 
41064887Schin 				n = 1;
41074887Schin 			}
41084887Schin 
41094887Schin 			/*
41104887Schin 			 * just a prefix is an option (e.g., `-' == stdin)
41114887Schin 			 */
41124887Schin 
41134887Schin 			if (!*s)
41144887Schin 				return 0;
41154887Schin 			if (c == '+')
41164887Schin 				opt_info.arg = 0;
411710898Sroland.mainz@nrubsig.org 			message((-2, "c='%c' n=%d", c, n));
41184887Schin 			if (n == 2)
41194887Schin 			{
41204887Schin 				x = 0;
41214887Schin 				opt_info.state->style = STYLE_long;
41224887Schin 				opt_info.option[0] = opt_info.name[0] = opt_info.name[1] = c;
41234887Schin 				w = &opt_info.name[prefix];
41244887Schin 				if ((*s == 'n' || *s == 'N') && (*(s + 1) == 'o' || *(s + 1) == 'O') && *(s + 2) && *(s + 2) != '=')
41254887Schin 					no = *(s + 2) == '-' ? 3 : 2;
41264887Schin 				else
41274887Schin 					no = 0;
41284887Schin 				for (c = *s; *s; s++)
41294887Schin 				{
41304887Schin 					if (*s == '=')
41314887Schin 					{
41324887Schin 						if (*(s + 1) == '=')
41334887Schin 							s++;
41344887Schin 						if (!isalnum(*(s - 1)) && *(w - 1) == (opt_info.assignment = *(s - 1)))
41354887Schin 							w--;
41364887Schin 						v = ++s;
41374887Schin 						break;
41384887Schin 					}
41394887Schin 					if (w < &opt_info.name[elementsof(opt_info.name) - 1] && *s != ':' && *s != '|' && *s != '[' && *s != ']')
41404887Schin 						*w++ = *s;
41414887Schin 				}
41424887Schin 				*w = 0;
41434887Schin 				w = &opt_info.name[prefix];
41444887Schin 				c = *w;
41454887Schin 				opt_info.offset = 0;
41464887Schin 				opt_info.index++;
41474887Schin 				break;
41484887Schin 			}
41494887Schin 			opt_info.offset++;
41504887Schin 		}
41514887Schin 		if (!argv[opt_info.index])
41524887Schin 			return 0;
41534887Schin 		if (c = argv[opt_info.index][opt_info.offset++])
41544887Schin 		{
41554887Schin 			if ((k = argv[opt_info.index][0]) != '-' && k != '+')
41564887Schin 				k = '-';
41574887Schin 			opt_info.option[0] = opt_info.name[0] = k;
41584887Schin 			opt_info.option[1] = opt_info.name[1] = c;
41594887Schin 			opt_info.option[2] = opt_info.name[2] = 0;
41604887Schin 			break;
41614887Schin 		}
41624887Schin 		opt_info.offset = 0;
41634887Schin 		opt_info.index++;
41644887Schin 	}
41654887Schin 
41664887Schin 	/*
41674887Schin 	 * at this point:
41684887Schin 	 *
41694887Schin 	 *	c	the first character of the option
41704887Schin 	 *	w	long option name if != 0, otherwise short
41714887Schin 	 *	v	long option value (via =) if w != 0
41724887Schin 	 */
41734887Schin 
41744887Schin 	if (c == '?')
41754887Schin 	{
41764887Schin 		/*
41774887Schin 		 * ? always triggers internal help
41784887Schin 		 */
41794887Schin 
41804887Schin 		if (w && !v && (*(w + 1) || !(v = argv[opt_info.index]) || !++opt_info.index))
41814887Schin 			v = w + 1;
41824887Schin 		opt_info.option[1] = c;
41834887Schin 		opt_info.option[2] = 0;
41844887Schin 		if (!w)
41854887Schin 		{
41864887Schin 			opt_info.name[1] = c;
41874887Schin 			opt_info.name[2] = 0;
41884887Schin 		}
41894887Schin 		goto help;
41904887Schin 	}
41914887Schin 	numopt = 0;
41924887Schin 	f = 0;
41934887Schin 	s = opts;
41944887Schin 
41954887Schin 	/*
41964887Schin 	 * no option can start with these characters
41974887Schin 	 */
41984887Schin 
41994887Schin 	if (c == ':' || c == '#' || c == ' ' || c == '[' || c == ']')
42004887Schin 	{
42014887Schin 		if (c != *s)
42024887Schin 			s = "";
42034887Schin 	}
42044887Schin 	else
42054887Schin 	{
42064887Schin 		a = 0;
42074887Schin 		if (!w && (pass->flags & OPT_cache))
42084887Schin 		{
42094887Schin 			if (cache)
42104887Schin 			{
42114887Schin 				if (k = cache->flags[map[c]])
42124887Schin 				{
42134887Schin 					opt_info.arg = 0;
42144887Schin 
42154887Schin 					/*
42164887Schin 					 * this is a ksh getopts workaround
42174887Schin 					 */
42184887Schin 
42194887Schin 					if (opt_info.num != LONG_MIN)
422010898Sroland.mainz@nrubsig.org 						opt_info.num = (long)(opt_info.number = !(k & OPT_cache_invert));
42214887Schin 					if (!(k & (OPT_cache_string|OPT_cache_numeric)))
42224887Schin 						return c;
42234887Schin 					if (*(opt_info.arg = &argv[opt_info.index++][opt_info.offset]))
42244887Schin 					{
42254887Schin 						if (!(k & OPT_cache_numeric))
42264887Schin 						{
42274887Schin 							opt_info.offset = 0;
42284887Schin 							return c;
42294887Schin 						}
42304887Schin 						opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
42314887Schin 						if (err || e == opt_info.arg)
42324887Schin 						{
42334887Schin 							if (!err && (k & OPT_cache_optional))
42344887Schin 							{
42354887Schin 								opt_info.arg = 0;
42364887Schin 								opt_info.index--;
42374887Schin 								return c;
42384887Schin 							}
42394887Schin 						}
42404887Schin 						else if (*e)
42414887Schin 						{
42424887Schin 							opt_info.offset += e - opt_info.arg;
42434887Schin 							opt_info.index--;
42444887Schin 							return c;
42454887Schin 						}
42464887Schin 						else
42474887Schin 						{
42484887Schin 							opt_info.offset = 0;
42494887Schin 							return c;
42504887Schin 						}
42514887Schin 					}
42524887Schin 					else if (opt_info.arg = argv[opt_info.index])
42534887Schin 					{
42544887Schin 						opt_info.index++;
42554887Schin 						if ((k & OPT_cache_optional) && (*opt_info.arg == '-' || (pass->flags & OPT_plus) && *opt_info.arg == '+') && *(opt_info.arg + 1))
42564887Schin 						{
42574887Schin 							opt_info.arg = 0;
42584887Schin 							opt_info.index--;
42594887Schin 							opt_info.offset = 0;
42604887Schin 							return c;
42614887Schin 						}
42624887Schin 						if (k & OPT_cache_string)
42634887Schin 						{
42644887Schin 							opt_info.offset = 0;
42654887Schin 							return c;
42664887Schin 						}
42674887Schin 						opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
42684887Schin 						if (!err)
42694887Schin 						{
42704887Schin 							if (!*e)
42714887Schin 							{
42724887Schin 								opt_info.offset = 0;
42734887Schin 								return c;
42744887Schin 							}
42754887Schin 							if (k & OPT_cache_optional)
42764887Schin 							{
42774887Schin 								opt_info.arg = 0;
42784887Schin 								opt_info.index--;
42794887Schin 								opt_info.offset = 0;
42804887Schin 								return c;
42814887Schin 							}
42824887Schin 						}
42834887Schin 					}
42844887Schin 					else if (k & OPT_cache_optional)
42854887Schin 					{
42864887Schin 						opt_info.offset = 0;
42874887Schin 						return c;
42884887Schin 					}
42894887Schin 					opt_info.index--;
42904887Schin 				}
42914887Schin 				cache = 0;
42924887Schin 			}
42934887Schin 			else if (cache = newof(0, Optcache_t, 1, 0))
42944887Schin 			{
42954887Schin 				cache->caching = c;
42964887Schin 				c = 0;
42974887Schin 				cache->pass = *pass;
42984887Schin 				cache->next = opt_info.state->cache;
42994887Schin 				opt_info.state->cache = cache;
43004887Schin 			}
43014887Schin 		}
43024887Schin 		else
43034887Schin 			cache = 0;
43044887Schin 		for (;;)
43054887Schin 		{
43064887Schin 			if (!(*(s = next(s, version))) || *s == '\n' || *s == ' ')
43074887Schin 			{
43084887Schin 				if (!(tsp = psp))
43094887Schin 				{
43104887Schin 					if (cache)
43114887Schin 					{
43124887Schin 						/*
43134887Schin 						 * the first loop pass
43144887Schin 						 * initialized the cache
43154887Schin 						 * so one more pass to
43164887Schin 						 * check the cache or
43174887Schin 						 * bail for a full scan
43184887Schin 						 */
43194887Schin 
43204887Schin 						cache->flags[0] = 0;
43214887Schin 						c = cache->caching;
43224887Schin 						cache->caching = 0;
43234887Schin 						cache = 0;
43244887Schin 						s = opts;
43254887Schin 						continue;
43264887Schin 					}
43274887Schin 					if (!x && catalog)
43284887Schin 					{
43294887Schin 						/*
43304887Schin 						 * the first loop pass
43314887Schin 						 * translated long
43324887Schin 						 * options and there
43334887Schin 						 * were no matches so
43344887Schin 						 * one more pass for C
43354887Schin 						 * locale
43364887Schin 						 */
43374887Schin 
43384887Schin 						catalog = 0;
43394887Schin 						s = opts;
43404887Schin 						continue;
43414887Schin 					}
43424887Schin 					s = "";
43434887Schin 					break;
43444887Schin 				}
43454887Schin 				s = psp->ob;
43464887Schin 				psp = psp->next;
43474887Schin 				free(tsp);
43484887Schin 				continue;
43494887Schin 			}
43504887Schin 			if (*s == '\f')
43514887Schin 			{
4352*12068SRoger.Faulkner@Oracle.COM 				psp = info(psp, s + 1, NiL, opt_info.state->xp, id);
43534887Schin 				if (psp->nb)
43544887Schin 					s = psp->nb;
43554887Schin 				else
43564887Schin 				{
43574887Schin 					s = psp->ob;
43584887Schin 					psp = psp->next;
43594887Schin 				}
43604887Schin 				continue;
43614887Schin 			}
436210898Sroland.mainz@nrubsig.org 			message((-20, "optget: opt %s  c %c  w %s  num %ld", show(s), c, w, num));
43634887Schin 			if (*s == c && !w)
43644887Schin 				break;
43654887Schin 			else if (*s == '[')
43664887Schin 			{
43674887Schin 				f = s = next(s + 1, version);
43684887Schin 				k = *f;
43694887Schin 				if (k == '+' || k == '-')
43704887Schin 					/* ignore */;
43714887Schin 				else if (k == '[' || version < 1)
43724887Schin 					continue;
43734887Schin 				else if (w && !cache)
43744887Schin 				{
43754887Schin 					nov = no;
43764887Schin 					if (*(s + 1) == '\f' && (vp = opt_info.state->vp))
43774887Schin 					{
43784887Schin 						sfputc(vp, k);
4379*12068SRoger.Faulkner@Oracle.COM 						s = expand(s + 2, NiL, &t, vp, id);
43804887Schin 						if (*s)
43814887Schin 							*(f = s - 1) = k;
43824887Schin 						else
43834887Schin 						{
43844887Schin 							f = sfstrbase(vp);
43854887Schin 							if (s = strrchr(f, ':'))
43864887Schin 								f = s - 1;
43874887Schin 							else
43884887Schin 								s = f + 1;
43894887Schin 						}
43904887Schin 					}
43914887Schin 					else
43924887Schin 						t = 0;
43934887Schin 					if (*s != ':')
43944887Schin 						s = skip(s, ':', '?', 0, 1, 0, 0, version);
43954887Schin 					if (*s == ':')
43964887Schin 					{
43974887Schin 						if (catalog)
43984887Schin 						{
43994887Schin 							p = skip(s + 1, '?', 0, 0, 1, 0, 0, version);
44004887Schin 							e = sfprints("%-.*s", p - (s + 1), s + 1);
4401*12068SRoger.Faulkner@Oracle.COM 							g = T(id, catalog, e);
44024887Schin 							if (g == e)
44034887Schin 								p = 0;
44044887Schin 							else
44054887Schin 							{
44064887Schin 								sfprintf(xp, ":%s|%s?", g, e);
44074887Schin 								if (!(s = sfstruse(xp)))
44084887Schin 									goto nospace;
44094887Schin 							}
44104887Schin 						}
44114887Schin 						else
44124887Schin 							p = 0;
44134887Schin 						y = w;
44144887Schin 						for (;;)
44154887Schin 						{
44164887Schin 							n = m = 0;
44174887Schin 							e = s + 1;
44184887Schin 							while (*++s)
44194887Schin 							{
44204887Schin 								if (*s == '*' || *s == '\a')
44214887Schin 								{
44224887Schin 									if (*s == '\a')
44234887Schin 										do
44244887Schin 										{
44254887Schin 											if (!*++s)
44264887Schin 											{
44274887Schin 												s--;
44284887Schin 												break;
44294887Schin 											}
44304887Schin 										} while (*s != '\a');
44314887Schin 									j = *(s + 1);
44324887Schin 									if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
44334887Schin 									{
44344887Schin 										while (*w)
44354887Schin 											w++;
44364887Schin 										m = 0;
44374887Schin 										break;
44384887Schin 									}
44394887Schin 									m = 1;
44404887Schin 								}
44414887Schin 								else if (*s == *w || sep(*s) && sep(*w))
44424887Schin 									w++;
44434887Schin 								else if (*w == 0)
44444887Schin 									break;
44454887Schin 								else if (!sep(*s))
44464887Schin 								{
44474887Schin 									if (sep(*w))
44484887Schin 									{
44494887Schin 										if (*++w == *s)
44504887Schin 										{
44514887Schin 											w++;
44524887Schin 											continue;
44534887Schin 										}
44544887Schin 									}
44554887Schin 									else if (w == y || sep(*(w - 1)) || isupper(*(w - 1)) && islower(*w))
44564887Schin 										break;
44574887Schin 									for (q = s; *q && !sep(*q) && *q != '|' && *q != '?' && *q != ']'; q++);
44584887Schin 									if (!sep(*q))
44594887Schin 										break;
44604887Schin 									for (s = q; w > y && *w != *(s + 1); w--);
44614887Schin 								}
44624887Schin 								else if (*w != *(s + 1))
44634887Schin 									break;
44644887Schin 							}
44654887Schin 							if (!*w)
44664887Schin 							{
44674887Schin 								nov = 0;
44684887Schin 								break;
44694887Schin 							}
44704887Schin 							if (n = no)
44714887Schin 							{
44724887Schin 								m = 0;
44734887Schin 								s = e - 1;
44744887Schin 								w = y + n;
44754887Schin 								while (*++s)
44764887Schin 								{
44774887Schin 									if (*s == '*' || *s == '\a')
44784887Schin 									{
44794887Schin 										if (*s == '\a')
44804887Schin 											do
44814887Schin 											{
44824887Schin 												if (!*++s)
44834887Schin 												{
44844887Schin 													s--;
44854887Schin 													break;
44864887Schin 												}
44874887Schin 											} while (*s != '\a');
44884887Schin 										j = *(s + 1);
44894887Schin 										if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
44904887Schin 										{
44914887Schin 											while (*w)
44924887Schin 												w++;
44934887Schin 											m = 0;
44944887Schin 											break;
44954887Schin 										}
44964887Schin 										m = 1;
44974887Schin 									}
44984887Schin 									else if (*s == *w || sep(*s) && sep(*w))
44994887Schin 										w++;
45004887Schin 									else if (*w == 0)
45014887Schin 										break;
45024887Schin 									else if (!sep(*s))
45034887Schin 									{
45044887Schin 										if (sep(*w))
45054887Schin 										{
45064887Schin 											if (*++w == *s)
45074887Schin 											{
45084887Schin 												w++;
45094887Schin 												continue;
45104887Schin 											}
45114887Schin 										}
45124887Schin 										else if (w == y || sep(*(w - 1)) || isupper(*(w - 1)) && islower(*w))
45134887Schin 											break;
45144887Schin 										for (q = s; *q && !sep(*q) && *q != '|' && *q != '?' && *q != ']'; q++);
45154887Schin 										if (!sep(*q))
45164887Schin 											break;
45174887Schin 										for (s = q; w > y && *w != *(s + 1); w--);
45184887Schin 									}
45194887Schin 									else if (*w != *(s + 1))
45204887Schin 										break;
45214887Schin 								}
45224887Schin 								if (!*w)
45234887Schin 									break;
45244887Schin 							}
45254887Schin 							if (*(s = skip(s, ':', '|', '?', 1, 0, 0, version)) != '|')
45264887Schin 								break;
45274887Schin 							w = y;
45284887Schin 						}
45294887Schin 						if (p)
45304887Schin 							s = p;
45314887Schin 						if (!*w)
45324887Schin 						{
45334887Schin 							if (n)
45344887Schin 								num = 0;
45354887Schin 							if (!(n = (m || *s == ':' || *s == '|' || *s == '?' || *s == ']' || *s == 0)) && x)
45364887Schin 							{
45374887Schin 								psp = pop(psp);
4538*12068SRoger.Faulkner@Oracle.COM 								return opterror("?", 0, version, id, catalog);
45394887Schin 							}
45404887Schin 							for (x = k; *(f + 1) == '|' && (j = *(f + 2)) && j != '!' && j != '=' && j != ':' && j != '?' && j != ']'; f += 2);
45414887Schin 							if (*f == ':')
45424887Schin 							{
45434887Schin 								x = -1;
45444887Schin 								opt_info.option[1] = '-';
45454887Schin 								opt_info.option[2] = 0;
45464887Schin 							}
45474887Schin 							else if (*(f + 1) == ':' || *(f + 1) == '!' && *(f + 2) == ':')
45484887Schin 							{
45494887Schin 								opt_info.option[1] = x;
45504887Schin 								opt_info.option[2] = 0;
45514887Schin 							}
45524887Schin 							else
45534887Schin 							{
45544887Schin 								a = f;
45554887Schin 								if (*a == '=')
45564887Schin 									a++;
45574887Schin 								else
45584887Schin 								{
45594887Schin 									if (*(a + 1) == '!')
45604887Schin 										a++;
45614887Schin 									if (*(a + 1) == '=')
45624887Schin 										a += 2;
45634887Schin 								}
45644887Schin 								x = -strtol(a, &b, 0);
45654887Schin 								if ((b - a) > sizeof(opt_info.option) - 2)
45664887Schin 									b = a + sizeof(opt_info.option) - 2;
45674887Schin 								memcpy(&opt_info.option[1], a, b - a);
45684887Schin 								opt_info.option[b - a + 1] = 0;
45694887Schin 							}
45704887Schin 							b = e;
45714887Schin 							if (t)
45724887Schin 							{
45734887Schin 								s = t;
45744887Schin 								t = 0;
45754887Schin 							}
45764887Schin 							a = s = skip(s, 0, 0, 0, 1, 0, 0, version);
45774887Schin 							if (n)
45784887Schin 							{
45794887Schin 								w = y;
45804887Schin 								break;
45814887Schin 							}
45824887Schin 						}
45834887Schin 						w = y;
45844887Schin 					}
45854887Schin 					else if (k == c && prefix == 1)
45864887Schin 					{
45874887Schin 						w = 0;
45884887Schin 						opt_info.name[1] = c;
45894887Schin 						opt_info.name[2] = 0;
45904887Schin 						opt_info.offset = 2;
45914887Schin 						opt_info.index--;
45924887Schin 						break;
45934887Schin 					}
45944887Schin 					if (t)
45954887Schin 					{
45964887Schin 						s = t;
45974887Schin 						if (a)
45984887Schin 							a = t;
45994887Schin 					}
46004887Schin 				}
46014887Schin 				s = skip(s, 0, 0, 0, 1, 0, 1, version);
46024887Schin 				if (*s == GO)
46034887Schin 					s = skip(s + 1, 0, 0, 0, 0, 1, 1, version);
46044887Schin 				if (cache)
46054887Schin 				{
46064887Schin 					m = OPT_cache_flag;
46074887Schin 					v = s;
46084887Schin 					if (*v == '#')
46094887Schin 					{
46104887Schin 						v++;
46114887Schin 						m |= OPT_cache_numeric;
46124887Schin 					}
46134887Schin 					else if (*v == ':')
46144887Schin 					{
46154887Schin 						v++;
46164887Schin 						m |= OPT_cache_string;
46174887Schin 					}
46184887Schin 					if (*v == '?')
46194887Schin 					{
46204887Schin 						v++;
46214887Schin 						m |= OPT_cache_optional;
46224887Schin 					}
46234887Schin 					else if (*v == *(v - 1))
46244887Schin 						v++;
46254887Schin 					if (*(v = next(v, version)) == '[')
46264887Schin 						v = skip(v + 1, 0, 0, 0, 1, 0, 1, version);
46274887Schin 					if (*v != GO)
46284887Schin 					{
46294887Schin 						v = f;
46304887Schin 						for (;;)
46314887Schin 						{
46324887Schin 							if (isdigit(*f) && isdigit(*(f + 1)))
46334887Schin 								while (isdigit(*(f + 1)))
46344887Schin 									f++;
46354887Schin 							else if (*(f + 1) == '=')
46364887Schin 								break;
46374887Schin 							else
46384887Schin 								cache->flags[map[*f]] = m;
46394887Schin 							j = 0;
46404887Schin 							while (*(f + 1) == '|')
46414887Schin 							{
46424887Schin 								f += 2;
46434887Schin 								if (!(j = *f) || j == '!' || j == '=' || j == ':' || j == '?' || j == ']')
46444887Schin 									break;
46454887Schin 								cache->flags[map[j]] = m;
46464887Schin 							}
46474887Schin 							if (j != '!' || (m & OPT_cache_invert))
46484887Schin 								break;
46494887Schin 							f = v;
46504887Schin 							m |= OPT_cache_invert;
46514887Schin 						}
46524887Schin 					}
46534887Schin 				}
46544887Schin 				else
46554887Schin 				{
46564887Schin 					m = 0;
46574887Schin 					if (!w)
46584887Schin 					{
46594887Schin 						if (isdigit(*f) && isdigit(*(f + 1)))
46604887Schin 							k = -1;
46614887Schin 						if (c == k)
46624887Schin 							m = 1;
46634887Schin 						while (*(f + 1) == '|')
46644887Schin 						{
46654887Schin 							f += 2;
46664887Schin 							if (!(j = *f))
46674887Schin 							{
46684887Schin 								m = 0;
46694887Schin 								break;
46704887Schin 							}
46714887Schin 							else if (j == c)
46724887Schin 								m = 1;
46734887Schin 							else if (j == '!' || j == '=' || j == ':' || j == '?' || j == ']')
46744887Schin 								break;
46754887Schin 						}
46764887Schin 					}
46774887Schin 					if (m)
46784887Schin 					{
46794887Schin 						s--;
46804887Schin 						if (*++f == '!')
46814887Schin 						{
46824887Schin 							f++;
46834887Schin 							num = 0;
46844887Schin 						}
46854887Schin 						if (*f == '=')
46864887Schin 						{
46874887Schin 							c = -strtol(++f, &b, 0);
46884887Schin 							if ((b - f) > sizeof(opt_info.option) - 2)
46894887Schin 								b = f + sizeof(opt_info.option) - 2;
46904887Schin 							memcpy(&opt_info.option[1], f, b - f);
46914887Schin 							opt_info.option[b - f + 1] = 0;
46924887Schin 						}
46934887Schin 						else
46944887Schin 							c = k;
46954887Schin 						break;
46964887Schin 					}
46974887Schin 				}
46984887Schin 				if (*s == '#')
46994887Schin 				{
47004887Schin 					if (!numopt && s > opts)
47014887Schin 					{
47024887Schin 						numopt = s - 1;
47034887Schin 						numchr = k;
47044887Schin 						if (*f == ':')
47054887Schin 							numchr = -1;
47064887Schin 						else if (*(f + 1) != ':' && *(f + 1) != '!' && *(f + 1) != ']')
47074887Schin 						{
47084887Schin 							a = f;
47094887Schin 							if (*a == '=')
47104887Schin 								a++;
47114887Schin 							else
47124887Schin 							{
47134887Schin 								if (*(a + 1) == '!')
47144887Schin 									a++;
47154887Schin 								if (*(a + 1) == '=')
47164887Schin 									a += 2;
47174887Schin 							}
47184887Schin 							numchr = -strtol(a, NiL, 0);
47194887Schin 						}
47204887Schin 					}
47214887Schin 				}
47224887Schin 				else if (*s != ':')
47234887Schin 					continue;
47244887Schin 			}
47254887Schin 			else if (*s == ']')
47264887Schin 			{
47274887Schin 				s++;
47284887Schin 				continue;
47294887Schin 			}
47304887Schin 			else if (*s == '#')
47314887Schin 			{
47324887Schin 				if (!numopt && s > opts)
47334887Schin 					numchr = *(numopt = s - 1);
47344887Schin 			}
47354887Schin 			else if (*s != ':')
47364887Schin 			{
47374887Schin 				if (cache)
47384887Schin 				{
47394887Schin 					m = OPT_cache_flag;
47404887Schin 					if (*(s + 1) == '#')
47414887Schin 					{
47424887Schin 						m |= OPT_cache_numeric;
47434887Schin 						if (*(s + 2) == '?')
47444887Schin 							m |= OPT_cache_optional;
47454887Schin 					}
47464887Schin 					else if (*(s + 1) == ':')
47474887Schin 					{
47484887Schin 						m |= OPT_cache_string;
47494887Schin 						if (*(s + 2) == '?')
47504887Schin 							m |= OPT_cache_optional;
47514887Schin 					}
47524887Schin 					cache->flags[map[*s]] = m;
47534887Schin 				}
47544887Schin 				s++;
47554887Schin 				continue;
47564887Schin 			}
47574887Schin 			message((-21, "optget: opt %s", show(s)));
47584887Schin 			if (*++s == '?' || *s == *(s - 1))
47594887Schin 				s++;
47604887Schin 			if (*(s = next(s, version)) == '[')
47614887Schin 			{
47624887Schin 				s = skip(s + 1, 0, 0, 0, 1, 0, 1, version);
47634887Schin 				if (*s == GO)
47644887Schin 					s = skip(s + 1, 0, 0, 0, 0, 1, 1, version);
47654887Schin 			}
476610898Sroland.mainz@nrubsig.org 			message((-21, "optget: opt %s", show(s)));
47674887Schin 		}
47684887Schin 		if (w && x)
47694887Schin 		{
47704887Schin 			s = skip(b, '|', '?', 0, 1, 0, 0, version);
47714887Schin 			if (v && (a == 0 || *a == 0 || *(a + 1) != ':' && *(a + 1) != '#') && (*v == '0' || *v == '1') && !*(v + 1))
47724887Schin 			{
47734887Schin 				if (*v == '0')
47744887Schin 					num = !num;
47754887Schin 				v = 0;
47764887Schin 			}
47774887Schin 			if ((s - b) >= elementsof(opt_info.name))
47784887Schin 				s = b + elementsof(opt_info.name) - 1;
47794887Schin 			for (;;)
47804887Schin 			{
47814887Schin 				if (b >= s)
47824887Schin 				{
47834887Schin 					*w = 0;
47844887Schin 					break;
47854887Schin 				}
47864887Schin 				if (*b == '*')
47874887Schin 					break;
47884887Schin 				*w++ = *b++;
47894887Schin 			}
47904887Schin 			if (!num && v)
4791*12068SRoger.Faulkner@Oracle.COM 				return opterror(no ? "!" : "=", 0, version, id, catalog);
47924887Schin 			w = &opt_info.name[prefix];
47934887Schin 			c = x;
47944887Schin 			s = a;
47954887Schin 		}
47964887Schin 	}
47974887Schin 	if (!*s)
47984887Schin 	{
47994887Schin 		if (w)
48004887Schin 		{
48014887Schin 			if (hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), w))
48024887Schin 			{
48034887Schin 				if (!v)
48044887Schin 					v = (char*)hp->name;
48054887Schin 				goto help;
48064887Schin 			}
48074887Schin 			if (!v)
48084887Schin 			{
48094887Schin 				v = opt_info.name;
48104887Schin 				goto help;
48114887Schin 			}
48124887Schin 		}
48138462SApril.Chin@Sun.COM 		if (w || !isdigit(c) || !numopt || !(pass->flags & OPT_numeric))
48144887Schin 		{
48154887Schin 			pop(psp);
4816*12068SRoger.Faulkner@Oracle.COM 			return opterror("", 0, version, id, catalog);
48174887Schin 		}
48184887Schin 		s = numopt;
48194887Schin 		c = opt_info.option[1] = numchr;
48204887Schin 		opt_info.offset--;
48214887Schin 	}
48224887Schin 	opt_info.arg = 0;
48234887Schin 
48244887Schin 	/*
48254887Schin 	 * this is a ksh getopts workaround
48264887Schin 	 */
48274887Schin 
48284887Schin 	if (opt_info.num != LONG_MIN)
482910898Sroland.mainz@nrubsig.org 		opt_info.num = (long)(opt_info.number = num);
48304887Schin 	if ((n = *++s == '#') || *s == ':' || w && !nov && v && (optnumber(v, &e, NiL), n = !*e))
48314887Schin 	{
48324887Schin 		if (w)
48334887Schin 		{
48344887Schin 			if (nov)
48354887Schin 			{
48364887Schin 				if (v)
48374887Schin 				{
48384887Schin 					pop(psp);
4839*12068SRoger.Faulkner@Oracle.COM 					return opterror("!", 0, version, id, catalog);
48404887Schin 				}
484110898Sroland.mainz@nrubsig.org 				opt_info.num = (long)(opt_info.number = 0);
48424887Schin 			}
48434887Schin 			else
48444887Schin 			{
48454887Schin 				if (!v && *(s + 1) != '?' && (v = argv[opt_info.index]))
48464887Schin 				{
48474887Schin 					opt_info.index++;
48484887Schin 					opt_info.offset = 0;
48494887Schin 				}
48504887Schin 				if (!(opt_info.arg = v) || (*v == '0' || *v == '1') && !*(v + 1))
48514887Schin 				{
48524887Schin 					if (*(s + 1) != '?')
48534887Schin 					{
48544887Schin 						if (!opt_info.arg)
48554887Schin 						{
48564887Schin 							pop(psp);
4857*12068SRoger.Faulkner@Oracle.COM 							return opterror(s, 0, version, id, catalog);
48584887Schin 						}
48594887Schin 					}
48604887Schin 					else if (*(t = next(s + 2, version)) == '[')
48614887Schin 						while (*(t = skip(t, ':', 0, 0, 1, 0, 0, version)) == ':')
48624887Schin 							if (*++t == '!')
48634887Schin 							{
48644887Schin 								if (!v || *v == '1')
48654887Schin 								{
48664887Schin 									e = skip(t, ':', '?', ']', 1, 0, 0, version);
48674887Schin 									opt_info.arg = sfprints("%-.*s", e - t - 1, t + 1);
48684887Schin 								}
48694887Schin 								else
48704887Schin 								{
48714887Schin 									opt_info.arg = 0;
487210898Sroland.mainz@nrubsig.org 									opt_info.num = (long)(opt_info.number = 0);
48734887Schin 								}
48744887Schin 								break;
48754887Schin 							}
48764887Schin 				}
48774887Schin 				if (opt_info.arg && n)
48784887Schin 				{
48794887Schin 					opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
48804887Schin 					if (err || e == opt_info.arg)
48814887Schin 					{
48824887Schin 						pop(psp);
4883*12068SRoger.Faulkner@Oracle.COM 						return opterror(s, err, version, id, catalog);
48844887Schin 					}
48854887Schin 				}
48864887Schin 			}
48874887Schin 			goto optarg;
48884887Schin 		}
48894887Schin 		else if (*(opt_info.arg = &argv[opt_info.index++][opt_info.offset]))
48904887Schin 		{
48914887Schin 			if (*s == '#')
48924887Schin 			{
48934887Schin 				opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
48944887Schin 				if (err || e == opt_info.arg)
48954887Schin 				{
48964887Schin 					if (!err && *(s + 1) == '?')
48974887Schin 					{
48984887Schin 						opt_info.arg = 0;
48994887Schin 						opt_info.index--;
49004887Schin 					}
49014887Schin 					else
49024887Schin 					{
49034887Schin 						opt_info.offset = 0;
4904*12068SRoger.Faulkner@Oracle.COM 						c = opterror(s, err, version, id, catalog);
49054887Schin 					}
49064887Schin 					pop(psp);
49074887Schin 					return c;
49084887Schin 				}
49094887Schin 				else if (*e)
49104887Schin 				{
49114887Schin 					opt_info.offset += e - opt_info.arg;
49124887Schin 					opt_info.index--;
49134887Schin 					pop(psp);
49144887Schin 					return c;
49154887Schin 				}
49164887Schin 			}
49174887Schin 		}
49184887Schin 		else if (opt_info.arg = argv[opt_info.index])
49194887Schin 		{
49204887Schin 			opt_info.index++;
49214887Schin 			if (*(s + 1) == '?' && (*opt_info.arg == '-' || (pass->flags & OPT_plus) && *opt_info.arg == '+') && *(opt_info.arg + 1))
49224887Schin 			{
49234887Schin 				opt_info.index--;
49244887Schin 				opt_info.arg = 0;
49254887Schin 			}
49264887Schin 			else if (*s == '#')
49274887Schin 			{
49284887Schin 				opt_info.num = (long)(opt_info.number = optnumber(opt_info.arg, &e, &err));
49294887Schin 				if (err || *e)
49304887Schin 				{
49314887Schin 					if (!err && *(s + 1) == '?')
49324887Schin 					{
49334887Schin 						opt_info.arg = 0;
49344887Schin 						opt_info.index--;
49354887Schin 					}
49364887Schin 					else
49374887Schin 					{
49384887Schin 						pop(psp);
49394887Schin 						opt_info.offset = 0;
4940*12068SRoger.Faulkner@Oracle.COM 						return opterror(s, err, version, id, catalog);
49414887Schin 					}
49424887Schin 				}
49434887Schin 			}
49444887Schin 		}
49454887Schin 		else if (*(s + 1) != '?')
49464887Schin 		{
49474887Schin 			opt_info.index--;
49484887Schin 			pop(psp);
4949*12068SRoger.Faulkner@Oracle.COM 			return opterror(s, 0, version, id, catalog);
49504887Schin 		}
49514887Schin 		opt_info.offset = 0;
49524887Schin 	optarg:
49534887Schin 		if (*s == ':' && *(s = skip(s, 0, 0, 0, 1, 0, 1, version)) == GO && *(s = next(s + 1, version)) == '[' && isalnum(*(s + 1)))
49544887Schin 		{
49554887Schin 			x = 0;
49564887Schin 			if (opt_info.arg)
49574887Schin 			{
49584887Schin 				do
49594887Schin 				{
49604887Schin 					w = y = opt_info.arg;
49614887Schin 					f = s = next(s + 1, version);
49624887Schin 					k = *f;
49634887Schin 					if (k == *w && isalpha(k) && !*(w + 1))
49644887Schin 					{
49654887Schin 						x = k;
49664887Schin 						break;
49674887Schin 					}
49684887Schin 					if (*s == '+' || *s == '-')
49694887Schin 						continue;
49704887Schin 					else if (*s == '[' || version < 1)
49714887Schin 						continue;
49724887Schin 					else
49734887Schin 					{
49744887Schin 						if (*s != ':')
49754887Schin 							s = skip(s, ':', '?', 0, 1, 0, 0, version);
49764887Schin 						if (*s == ':')
49774887Schin 						{
49784887Schin 							if (catalog)
49794887Schin 							{
49804887Schin 								p = skip(s + 1, '?', 0, 0, 1, 0, 0, version);
49814887Schin 								e = sfprints("%-.*s", p - (s + 1), s + 1);
4982*12068SRoger.Faulkner@Oracle.COM 								b = T(id, catalog, e);
49834887Schin 								if (b == e)
49844887Schin 									p = 0;
49854887Schin 								else
49864887Schin 								{
49874887Schin 									sfprintf(xp, ":%s|%s?", b, e);
49884887Schin 									if (!(s = sfstruse(xp)))
49894887Schin 										goto nospace;
49904887Schin 								}
49914887Schin 							}
49924887Schin 							else
49934887Schin 								p = 0;
49944887Schin 							for (;;)
49954887Schin 							{
49964887Schin 								n = m = 0;
49974887Schin 								e = s + 1;
49984887Schin 								while (*++s)
49994887Schin 								{
50004887Schin 									if (*s == '*' || *s == '\a')
50014887Schin 									{
50024887Schin 										if (*s == '\a')
50034887Schin 											do
50044887Schin 											{
50054887Schin 												if (!*++s)
50064887Schin 												{
50074887Schin 													s--;
50084887Schin 													break;
50094887Schin 												}
50104887Schin 											} while (*s != '\a');
50114887Schin 										j = *(s + 1);
50124887Schin 										if (j == ':' || j == '|' || j == '?' || j == ']' || j == 0)
50134887Schin 										{
50144887Schin 											while (*w)
50154887Schin 												w++;
50164887Schin 											m = 0;
50174887Schin 											break;
50184887Schin 										}
50194887Schin 										m = 1;
50204887Schin 									}
50214887Schin 									else if (*s == *w || sep(*s) && sep(*w))
50224887Schin 										w++;
50234887Schin 									else if (*w == 0)
50244887Schin 										break;
50254887Schin 									else if (!sep(*s))
50264887Schin 									{
50274887Schin 										if (sep(*w))
50284887Schin 										{
50294887Schin 											if (*++w == *s)
50304887Schin 											{
50314887Schin 												w++;
50324887Schin 												continue;
50334887Schin 											}
50344887Schin 										}
50354887Schin 										else if (w == y || sep(*(w - 1)) || isupper(*(w - 1)) && islower(*w))
50364887Schin 											break;
50374887Schin 										for (q = s; *q && !sep(*q) && *q != '|' && *q != '?' && *q != ']'; q++);
50384887Schin 										if (!sep(*q))
50394887Schin 											break;
50404887Schin 										for (s = q; w > y && *w != *(s + 1); w--);
50414887Schin 									}
50424887Schin 									else if (*w != *(s + 1))
50434887Schin 										break;
50444887Schin 								}
50454887Schin 								if (!*w)
50464887Schin 								{
50474887Schin 									nov = 0;
50484887Schin 									break;
50494887Schin 								}
50504887Schin 								if (*(s = skip(s, ':', '|', '?', 1, 0, 0, version)) != '|')
50514887Schin 									break;
50524887Schin 								w = y;
50534887Schin 							}
50544887Schin 							if (p)
50554887Schin 								s = p;
50564887Schin 							if (!*w)
50574887Schin 							{
50584887Schin 								if (n)
50594887Schin 									num = 0;
50604887Schin 								if (!(n = (m || *s == ':' || *s == '|' || *s == '?' || *s == ']')) && x)
50614887Schin 								{
50624887Schin 									pop(psp);
5063*12068SRoger.Faulkner@Oracle.COM 									return opterror("&", 0, version, id, catalog);
50644887Schin 								}
50654887Schin 								for (x = k; *(f + 1) == '|' && (j = *(f + 2)) && j != '!' && j != '=' && j != ':' && j != '?' && j != ']'; f += 2);
50664887Schin 								if (*f == ':')
50674887Schin 									x = -1;
50684887Schin 								else if (*(f + 1) == ':' || *(f + 1) == '!' && *(f + 2) == ':')
50694887Schin 									/* ok */;
50704887Schin 								else
50714887Schin 								{
50724887Schin 									a = f;
50734887Schin 									if (*a == '=')
50744887Schin 										a++;
50754887Schin 									else
50764887Schin 									{
50774887Schin 										if (*(a + 1) == '!')
50784887Schin 											a++;
50794887Schin 										if (*(a + 1) == '=')
50804887Schin 											a += 2;
50814887Schin 									}
50824887Schin 									x = -strtol(a, &b, 0);
50834887Schin 								}
50844887Schin 								b = e;
50854887Schin 								a = s = skip(s, 0, 0, 0, 1, 0, 0, version);
50864887Schin 								if (n)
50874887Schin 									break;
50884887Schin 							}
50894887Schin 						}
50904887Schin 					}
50914887Schin 				} while (*(s = skip(s, 0, 0, 0, 1, 0, 1, version)) == '[');
509210898Sroland.mainz@nrubsig.org 				if (!(opt_info.num = (long)(opt_info.number = x)))
50934887Schin 				{
50944887Schin 					pop(psp);
5095*12068SRoger.Faulkner@Oracle.COM 					return opterror("*", 0, version, id, catalog);
50964887Schin 				}
50974887Schin 			}
50984887Schin 		}
50994887Schin 	}
51004887Schin 	else if (w && v)
51014887Schin 	{
51024887Schin 		pop(psp);
5103*12068SRoger.Faulkner@Oracle.COM 		return opterror("=", 0, version, id, catalog);
51044887Schin 	}
51054887Schin 	else
51064887Schin 	{
510710898Sroland.mainz@nrubsig.org 		opt_info.num = (long)(opt_info.number = num);
51084887Schin 		if (!w && !argv[opt_info.index][opt_info.offset])
51094887Schin 		{
51104887Schin 			opt_info.offset = 0;
51114887Schin 			opt_info.index++;
51124887Schin 		}
51134887Schin 	}
51144887Schin 	pop(psp);
51154887Schin 	return c;
51164887Schin  help:
51174887Schin 	if (v && *v == '?' && *(v + 1) == '?' && *(v + 2))
51184887Schin 	{
51194887Schin 		s = v + 2;
51204887Schin 		if ((s[0] == 'n' || s[0] == 'N') && (s[1] == 'o' || s[1] == 'O'))
51214887Schin 		{
51224887Schin 			s += 2;
51234887Schin 			n = -1;
51244887Schin 		}
51254887Schin 		else
51264887Schin 			n = 1;
51274887Schin 		if (hp = (Help_t*)search(styles, elementsof(styles), sizeof(styles[0]), s))
51284887Schin 		{
51294887Schin 			if (hp->style < STYLE_man || !(s = argv[opt_info.index]) || s[0] != '-' || s[1] != '-' || !s[2])
51304887Schin 			{
51314887Schin 				opt_info.arg = sfprints("\fversion=%d", version);
51324887Schin 				pop(psp);
51334887Schin 				return '?';
51344887Schin 			}
51354887Schin 			opt_info.state->force = hp->style;
51364887Schin 		}
5137*12068SRoger.Faulkner@Oracle.COM 		else if (match(s, "ESC", -1, ID, NiL) || match(s, "EMPHASIS", -1, ID, NiL))
51384887Schin 			opt_info.state->emphasis = n;
5139*12068SRoger.Faulkner@Oracle.COM 		else if (match(s, "PREFORMAT", -1, ID, NiL))
51404887Schin 			opt_info.state->flags |= OPT_preformat;
5141*12068SRoger.Faulkner@Oracle.COM 		else if (match(s, "TEST", -1, ID, NiL))
51424887Schin 		{
51434887Schin 			opt_info.state->width = OPT_WIDTH;
51444887Schin 			opt_info.state->emphasis = 1;
51454887Schin 		}
51464887Schin 		else
51474887Schin 		{
51484887Schin 			pop(psp);
5149*12068SRoger.Faulkner@Oracle.COM 			return opterror(v, 0, version, id, catalog);
51504887Schin 		}
51514887Schin 		psp = pop(psp);
51524887Schin 		if (argv == opt_info.state->strv)
51534887Schin 			return '#';
51544887Schin 		goto again;
51554887Schin 	}
51564887Schin 	if ((opt_info.arg = opthelp(NiL, v)) == (char*)unknown)
51574887Schin 	{
51584887Schin 		pop(psp);
5159*12068SRoger.Faulkner@Oracle.COM 		return opterror(v, 0, version, id, catalog);
51604887Schin 	}
51614887Schin 	pop(psp);
51624887Schin 	return '?';
51634887Schin  nospace:
51644887Schin 	pop(psp);
5165*12068SRoger.Faulkner@Oracle.COM 	return opterror(NiL, 0, 0, NiL, NiL);
51664887Schin }
51674887Schin 
51684887Schin /*
51694887Schin  * parse long options with 0,1,2 leading '-' or '+' from string and pass to optget()
51704887Schin  * syntax is the unquoted
51714887Schin  *
51724887Schin  *	<length> [-|+|--|++]<name>[[-+:|&=]=<value>\n (or \0 for the last)
51734887Schin  *
51744887Schin  * or the quoted
51754887Schin  *
51764887Schin  *	[-|+|--|++][no]name[[-+:|&=]=['"{(]value[)}"']][, ]...
51774887Schin  *
51784887Schin  * with \x escapes passed to chresc()
51794887Schin  *
51804887Schin  * return '#' for `label:', with opt_info.name==label
51814887Schin  * str[opt_info.offset]	next arg
51824887Schin  *
51834887Schin  *	optstr(s, 0)
51844887Schin  *		return '-' if arg, 0 otherwise
51854887Schin  *	optstr(0, opts)
51864887Schin  *		use previous parsed str
51874887Schin  */
51884887Schin 
51894887Schin int
optstr(const char * str,const char * opts)51904887Schin optstr(const char* str, const char* opts)
51914887Schin {
51924887Schin 	register char*		s = (char*)str;
51934887Schin 	register Sfio_t*	mp;
51944887Schin 	register int		c;
51954887Schin 	register int		ql;
51964887Schin 	register int		qr;
51974887Schin 	register int		qc;
51984887Schin 	int			v;
51994887Schin 	char*			e;
52004887Schin 
52014887Schin  again:
52024887Schin 	if (s)
52034887Schin 	{
52044887Schin 		if (!(mp = opt_info.state->strp) && !(mp = opt_info.state->strp = sfstropen()))
52054887Schin 			return 0;
52064887Schin 		if (opt_info.state->str != s)
52074887Schin 			opt_info.state->str = s;
52084887Schin 		else if (opt_info.index == 1)
52094887Schin 			s += opt_info.offset;
52104887Schin 		while (*s == ',' || *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')
52114887Schin 			s++;
52124887Schin 		if (!*s)
52134887Schin 		{
52144887Schin 			opt_info.state->str = 0;
52154887Schin 			return 0;
52164887Schin 		}
52174887Schin 		if (*s == '-' || *s == '+')
52184887Schin 		{
52194887Schin 			c = *s++;
52204887Schin 			sfputc(mp, c);
52214887Schin 			if (*s == c)
52224887Schin 			{
52234887Schin 				sfputc(mp, c);
52244887Schin 				s++;
52254887Schin 			}
52264887Schin 		}
52274887Schin 		else
52284887Schin 		{
52294887Schin 			sfputc(mp, '-');
52304887Schin 			sfputc(mp, '-');
52314887Schin 		}
52324887Schin 		if (isdigit(*s) && (v = (int)strtol(s, &e, 10)) > 1 && isspace(*e) && --v <= strlen(s) && (s[v] == 0 || s[v] == '\n'))
52334887Schin 		{
52344887Schin 			s += v;
52354887Schin 			while (isspace(*++e));
52364887Schin 			sfwrite(mp, e, s - e);
52374887Schin 		}
52384887Schin 		else
52394887Schin 		{
52404887Schin 			while (*s && *s != ',' && *s != ' ' && *s != '\t' && *s != '\n' && *s != '\r' && *s != '=' && *s != ':')
52414887Schin 				sfputc(mp, *s++);
52424887Schin 			if ((c = *s) == ':' && *(s + 1) != '=')
52434887Schin 			{
52444887Schin 				opt_info.index = 1;
52454887Schin 				opt_info.offset = ++s - (char*)str;
52464887Schin 				if (!(s = sfstruse(mp)))
52474887Schin 					goto nospace;
52484887Schin 				s += 2;
52494887Schin 				e = opt_info.name;
52504887Schin 				while (e < &opt_info.name[sizeof(opt_info.name)-1] && (*e++ = *s++));
52514887Schin 				opt_info.arg = 0;
525210898Sroland.mainz@nrubsig.org 				opt_info.num = (long)(opt_info.number = 0);
52534887Schin 				opt_info.option[0] = ':';
52544887Schin 				opt_info.option[1] = 0;
52554887Schin 				return '#';
52564887Schin 			}
52574887Schin 			if (c == ':' || c == '=')
52584887Schin 			{
52594887Schin 				sfputc(mp, c);
52604887Schin 				ql = qr = 0;
52614887Schin 				while (c = *++s)
52624887Schin 				{
52634887Schin 					if (c == '\\')
52644887Schin 					{
52654887Schin 						sfputc(mp, chresc(s, &e));
52664887Schin 						s = e - 1;
52674887Schin 					}
52684887Schin 					else if (c == qr)
52694887Schin 					{
52704887Schin 						if (qr != ql)
52714887Schin 							sfputc(mp, c);
52724887Schin 						if (--qc <= 0)
52734887Schin 							qr = ql = 0;
52744887Schin 					}
52754887Schin 					else if (c == ql)
52764887Schin 					{
52774887Schin 						sfputc(mp, c);
52784887Schin 						qc++;
52794887Schin 					}
52804887Schin 					else if (qr)
52814887Schin 						sfputc(mp, c);
52824887Schin 					else if (c == ',' || c == ' ' || c == '\t' || c == '\n' || c == '\r')
52834887Schin 						break;
52844887Schin 					else if (c == '"' || c == '\'')
52854887Schin 					{
52864887Schin 						ql = qr = c;
52874887Schin 						qc = 1;
52884887Schin 					}
52894887Schin 					else
52904887Schin 					{
52914887Schin 						sfputc(mp, c);
52924887Schin 						if (c == GO)
52934887Schin 						{
52944887Schin 							ql = c;
52954887Schin 							qr = OG;
52964887Schin 							qc = 1;
52974887Schin 						}
52984887Schin 						else if (c == '(')
52994887Schin 						{
53004887Schin 							ql = c;
53014887Schin 							qr = ')';
53024887Schin 							qc = 1;
53034887Schin 						}
53044887Schin 					}
53054887Schin 				}
53064887Schin 			}
53074887Schin 		}
53084887Schin 		opt_info.argv = opt_info.state->strv;
53094887Schin 		opt_info.state->strv[0] = T(NiL, ID, "option");
53104887Schin 		if (!(opt_info.state->strv[1] = sfstruse(mp)))
53114887Schin 			goto nospace;
53124887Schin 		opt_info.state->strv[2] = 0;
53134887Schin 		opt_info.offset = s - (char*)str;
53144887Schin 	}
53154887Schin 	if (opts)
53164887Schin 	{
53174887Schin 		if (!opt_info.state->strv[1])
53184887Schin 		{
53194887Schin 			opt_info.state->str = 0;
53204887Schin 			return 0;
53214887Schin 		}
53224887Schin 		opt_info.index = 1;
53234887Schin 		v = opt_info.offset;
53244887Schin 		opt_info.offset = 0;
53254887Schin 		c = optget(opt_info.state->strv, opts);
53264887Schin 		opt_info.index = 1;
53274887Schin 		opt_info.offset = v;
53284887Schin 		if (c == '#')
53294887Schin 		{
53304887Schin 			s = opt_info.state->str;
53314887Schin 			goto again;
53324887Schin 		}
53334887Schin 		if ((c == '?' || c == ':') && (opt_info.arg[0] == '-' && opt_info.arg[1] == '-'))
53344887Schin 			opt_info.arg += 2;
53354887Schin 		s = opt_info.name;
53364887Schin 		if (*s++ == '-' && *s++ == '-' && *s)
53374887Schin 		{
53384887Schin 			e = opt_info.name;
53394887Schin 			while (*e++ = *s++);
53404887Schin 		}
53414887Schin 	}
53424887Schin 	else
53434887Schin 		c = '-';
53444887Schin 	return c;
53454887Schin  nospace:
5346*12068SRoger.Faulkner@Oracle.COM 	return opterror(NiL, 0, 0, NiL, NiL);
53474887Schin }
5348