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