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