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