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