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