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