]> git.cameronkatri.com Git - mandoc.git/blob - argv.c
Added argv regression tests.
[mandoc.git] / argv.c
1 /* $Id: argv.c,v 1.36 2009/03/05 12:08:53 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19 #include <assert.h>
20 #include <ctype.h>
21 #include <err.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "private.h"
27
28 /*
29 * Routines to parse arguments of macros. Arguments follow the syntax
30 * of `-arg [val [valN...]]'. Arguments come in all types: quoted
31 * arguments, multiple arguments per value, no-value arguments, etc.
32 */
33
34 #define ARGS_QUOTED (1 << 0)
35 #define ARGS_DELIM (1 << 1)
36 #define ARGS_TABSEP (1 << 2)
37
38 #define ARGV_NONE (1 << 0)
39 #define ARGV_SINGLE (1 << 1)
40 #define ARGV_MULTI (1 << 2)
41 #define ARGV_OPT_SINGLE (1 << 3)
42
43 static int argv_a2arg(int, const char *);
44 static int args(struct mdoc *, int, int *,
45 char *, int, char **);
46 static int argv(struct mdoc *, int,
47 struct mdoc_arg *, int *, char *);
48 static int argv_single(struct mdoc *, int,
49 struct mdoc_arg *, int *, char *);
50 static int argv_opt_single(struct mdoc *, int,
51 struct mdoc_arg *, int *, char *);
52 static int argv_multi(struct mdoc *, int,
53 struct mdoc_arg *, int *, char *);
54 static int pwarn(struct mdoc *, int, int, int);
55 static int perr(struct mdoc *, int, int, int);
56
57 /* Warning messages. */
58
59 #define WQUOTPARM (0)
60 #define WARGVPARM (1)
61 #define WCOLEMPTY (2)
62 #define WTAILWS (3)
63
64 /* Error messages. */
65
66 #define EQUOTTERM (0)
67 #define EARGVAL (1)
68 #define EARGMANY (2)
69
70 /* Per-argument flags. */
71
72 static int mdoc_argvflags[MDOC_ARG_MAX] = {
73 ARGV_NONE, /* MDOC_Split */
74 ARGV_NONE, /* MDOC_Nosplit */
75 ARGV_NONE, /* MDOC_Ragged */
76 ARGV_NONE, /* MDOC_Unfilled */
77 ARGV_NONE, /* MDOC_Literal */
78 ARGV_NONE, /* MDOC_File */
79 ARGV_SINGLE, /* MDOC_Offset */
80 ARGV_NONE, /* MDOC_Bullet */
81 ARGV_NONE, /* MDOC_Dash */
82 ARGV_NONE, /* MDOC_Hyphen */
83 ARGV_NONE, /* MDOC_Item */
84 ARGV_NONE, /* MDOC_Enum */
85 ARGV_NONE, /* MDOC_Tag */
86 ARGV_NONE, /* MDOC_Diag */
87 ARGV_NONE, /* MDOC_Hang */
88 ARGV_NONE, /* MDOC_Ohang */
89 ARGV_NONE, /* MDOC_Inset */
90 ARGV_MULTI, /* MDOC_Column */
91 ARGV_SINGLE, /* MDOC_Width */
92 ARGV_NONE, /* MDOC_Compact */
93 ARGV_OPT_SINGLE, /* MDOC_Std */
94 ARGV_NONE, /* MDOC_p1003_1_88 */
95 ARGV_NONE, /* MDOC_p1003_1_90 */
96 ARGV_NONE, /* MDOC_p1003_1_96 */
97 ARGV_NONE, /* MDOC_p1003_1_2001 */
98 ARGV_NONE, /* MDOC_p1003_1_2004 */
99 ARGV_NONE, /* MDOC_p1003_1 */
100 ARGV_NONE, /* MDOC_p1003_1b */
101 ARGV_NONE, /* MDOC_p1003_1b_93 */
102 ARGV_NONE, /* MDOC_p1003_1c_95 */
103 ARGV_NONE, /* MDOC_p1003_1g_2000 */
104 ARGV_NONE, /* MDOC_p1003_2_92 */
105 ARGV_NONE, /* MDOC_p1387_2_95 */
106 ARGV_NONE, /* MDOC_p1003_2 */
107 ARGV_NONE, /* MDOC_p1387_2 */
108 ARGV_NONE, /* MDOC_isoC_90 */
109 ARGV_NONE, /* MDOC_isoC_amd1 */
110 ARGV_NONE, /* MDOC_isoC_tcor1 */
111 ARGV_NONE, /* MDOC_isoC_tcor2 */
112 ARGV_NONE, /* MDOC_isoC_99 */
113 ARGV_NONE, /* MDOC_ansiC */
114 ARGV_NONE, /* MDOC_ansiC_89 */
115 ARGV_NONE, /* MDOC_ansiC_99 */
116 ARGV_NONE, /* MDOC_ieee754 */
117 ARGV_NONE, /* MDOC_iso8802_3 */
118 ARGV_NONE, /* MDOC_xpg3 */
119 ARGV_NONE, /* MDOC_xpg4 */
120 ARGV_NONE, /* MDOC_xpg4_2 */
121 ARGV_NONE, /* MDOC_xpg4_3 */
122 ARGV_NONE, /* MDOC_xbd5 */
123 ARGV_NONE, /* MDOC_xcu5 */
124 ARGV_NONE, /* MDOC_xsh5 */
125 ARGV_NONE, /* MDOC_xns5 */
126 ARGV_NONE, /* MDOC_xns5_2d2_0 */
127 ARGV_NONE, /* MDOC_xcurses4_2 */
128 ARGV_NONE, /* MDOC_susv2 */
129 ARGV_NONE, /* MDOC_susv3 */
130 ARGV_NONE, /* MDOC_svid4 */
131 ARGV_NONE, /* MDOC_Filled */
132 ARGV_NONE, /* MDOC_Words */
133 ARGV_NONE, /* MDOC_Emphasis */
134 ARGV_NONE /* MDOC_Symbolic */
135 };
136
137 static int mdoc_argflags[MDOC_MAX] = {
138 0, /* \" */
139 0, /* Dd */
140 0, /* Dt */
141 0, /* Os */
142 0, /* Sh */
143 0, /* Ss */
144 ARGS_DELIM, /* Pp */
145 ARGS_DELIM, /* D1 */
146 ARGS_DELIM, /* Dl */
147 0, /* Bd */
148 0, /* Ed */
149 0, /* Bl */
150 0, /* El */
151 0, /* It */
152 ARGS_DELIM, /* Ad */
153 ARGS_DELIM, /* An */
154 ARGS_DELIM, /* Ar */
155 ARGS_QUOTED, /* Cd */
156 ARGS_DELIM, /* Cm */
157 ARGS_DELIM, /* Dv */
158 ARGS_DELIM, /* Er */
159 ARGS_DELIM, /* Ev */
160 0, /* Ex */
161 ARGS_DELIM | ARGS_QUOTED, /* Fa */
162 0, /* Fd */
163 ARGS_DELIM, /* Fl */
164 ARGS_DELIM | ARGS_QUOTED, /* Fn */
165 ARGS_DELIM | ARGS_QUOTED, /* Ft */
166 ARGS_DELIM, /* Ic */
167 0, /* In */
168 ARGS_DELIM, /* Li */
169 0, /* Nd */
170 ARGS_DELIM, /* Nm */
171 ARGS_DELIM, /* Op */
172 0, /* Ot */
173 ARGS_DELIM, /* Pa */
174 0, /* Rv */
175 ARGS_DELIM, /* St */
176 ARGS_DELIM, /* Va */
177 ARGS_DELIM, /* Vt */
178 ARGS_DELIM, /* Xr */
179 ARGS_QUOTED, /* %A */
180 ARGS_QUOTED, /* %B */
181 ARGS_QUOTED, /* %D */
182 ARGS_QUOTED, /* %I */
183 ARGS_QUOTED, /* %J */
184 ARGS_QUOTED, /* %N */
185 ARGS_QUOTED, /* %O */
186 ARGS_QUOTED, /* %P */
187 ARGS_QUOTED, /* %R */
188 ARGS_QUOTED, /* %T */
189 ARGS_QUOTED, /* %V */
190 ARGS_DELIM, /* Ac */
191 0, /* Ao */
192 ARGS_DELIM, /* Aq */
193 ARGS_DELIM, /* At */
194 ARGS_DELIM, /* Bc */
195 0, /* Bf */
196 0, /* Bo */
197 ARGS_DELIM, /* Bq */
198 ARGS_DELIM, /* Bsx */
199 ARGS_DELIM, /* Bx */
200 0, /* Db */
201 ARGS_DELIM, /* Dc */
202 0, /* Do */
203 ARGS_DELIM, /* Dq */
204 ARGS_DELIM, /* Ec */
205 0, /* Ef */
206 ARGS_DELIM, /* Em */
207 0, /* Eo */
208 ARGS_DELIM, /* Fx */
209 ARGS_DELIM, /* Ms */
210 ARGS_DELIM, /* No */
211 ARGS_DELIM, /* Ns */
212 ARGS_DELIM, /* Nx */
213 ARGS_DELIM, /* Ox */
214 ARGS_DELIM, /* Pc */
215 ARGS_DELIM, /* Pf */
216 0, /* Po */
217 ARGS_DELIM, /* Pq */
218 ARGS_DELIM, /* Qc */
219 ARGS_DELIM, /* Ql */
220 0, /* Qo */
221 ARGS_DELIM, /* Qq */
222 0, /* Re */
223 0, /* Rs */
224 ARGS_DELIM, /* Sc */
225 0, /* So */
226 ARGS_DELIM, /* Sq */
227 0, /* Sm */
228 ARGS_DELIM, /* Sx */
229 ARGS_DELIM, /* Sy */
230 ARGS_DELIM, /* Tn */
231 ARGS_DELIM, /* Ux */
232 ARGS_DELIM, /* Xc */
233 0, /* Xo */
234 0, /* Fo */
235 0, /* Fc */
236 0, /* Oo */
237 ARGS_DELIM, /* Oc */
238 0, /* Bk */
239 0, /* Ek */
240 0, /* Bt */
241 0, /* Hf */
242 0, /* Fr */
243 0, /* Ud */
244 };
245
246
247 static int
248 perr(struct mdoc *mdoc, int line, int pos, int code)
249 {
250 int c;
251
252 switch (code) {
253 case (EQUOTTERM):
254 c = mdoc_perr(mdoc, line, pos,
255 "unterminated quoted parameter");
256 break;
257 case (EARGVAL):
258 c = mdoc_perr(mdoc, line, pos,
259 "argument requires a value");
260 break;
261 case (EARGMANY):
262 c = mdoc_perr(mdoc, line, pos,
263 "too many values for argument");
264 break;
265 default:
266 abort();
267 /* NOTREACHED */
268 }
269 return(c);
270 }
271
272
273 static int
274 pwarn(struct mdoc *mdoc, int line, int pos, int code)
275 {
276 int c;
277
278 switch (code) {
279 case (WQUOTPARM):
280 c = mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
281 "unexpected quoted parameter");
282 break;
283 case (WARGVPARM):
284 c = mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
285 "argument-like parameter");
286 break;
287 case (WCOLEMPTY):
288 c = mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
289 "last list column is empty");
290 break;
291 case (WTAILWS):
292 c = mdoc_pwarn(mdoc, line, pos, WARN_COMPAT,
293 "trailing whitespace");
294 break;
295 default:
296 abort();
297 /* NOTREACHED */
298 }
299 return(c);
300 }
301
302
303 int
304 mdoc_args(struct mdoc *mdoc, int line,
305 int *pos, char *buf, int tok, char **v)
306 {
307 int fl, c, i;
308 struct mdoc_node *n;
309
310 fl = (0 == tok) ? 0 : mdoc_argflags[tok];
311
312 /*
313 * Override per-macro argument flags with context-specific ones.
314 * As of now, this is only valid for `It' depending on its list
315 * context.
316 */
317
318 switch (tok) {
319 case (MDOC_It):
320 for (n = mdoc->last; n; n = n->parent)
321 if (MDOC_BLOCK == n->type && MDOC_Bl == n->tok)
322 break;
323
324 assert(n);
325 c = (int)n->data.block.argc;
326 assert(c > 0);
327
328 /*
329 * Using `Bl -column' adds ARGS_TABSEP to the arguments
330 * and invalidates ARGS_DELIM. Using `Bl -diag' allows
331 * for quoted arguments.
332 */
333
334 /* LINTED */
335 for (i = 0; i < c; i++) {
336 switch (n->data.block.argv[i].arg) {
337 case (MDOC_Column):
338 fl |= ARGS_TABSEP;
339 fl &= ~ARGS_DELIM;
340 i = c;
341 break;
342 case (MDOC_Diag):
343 fl |= ARGS_QUOTED;
344 i = c;
345 break;
346 default:
347 break;
348 }
349 }
350 default:
351 break;
352 }
353
354 /* Continue parsing the arguments themselves... */
355
356 return(args(mdoc, line, pos, buf, fl, v));
357 }
358
359
360 static int
361 args(struct mdoc *mdoc, int line,
362 int *pos, char *buf, int fl, char **v)
363 {
364 int i;
365 char *p, *pp;
366
367 assert(*pos > 0);
368
369 if (0 == buf[*pos])
370 return(ARGS_EOLN);
371
372 if ('\"' == buf[*pos] && ! (fl & ARGS_QUOTED))
373 if ( ! pwarn(mdoc, line, *pos, WQUOTPARM))
374 return(ARGS_ERROR);
375
376 if ('-' == buf[*pos])
377 if ( ! pwarn(mdoc, line, *pos, WARGVPARM))
378 return(ARGS_ERROR);
379
380 /*
381 * If the first character is a delimiter and we're to look for
382 * delimited strings, then pass down the buffer seeing if it
383 * follows the pattern of [[::delim::][ ]+]+.
384 */
385
386 if ((fl & ARGS_DELIM) && mdoc_iscdelim(buf[*pos])) {
387 for (i = *pos; buf[i]; ) {
388 if ( ! mdoc_iscdelim(buf[i]))
389 break;
390 i++;
391 /* There must be at least one space... */
392 if (0 == buf[i] || ! isspace((int)buf[i]))
393 break;
394 i++;
395 while (buf[i] && isspace((int)buf[i]))
396 i++;
397 }
398 if (0 == buf[i]) {
399 *v = &buf[*pos];
400 return(ARGS_PUNCT);
401 }
402 }
403
404 /* First parse non-quoted strings. */
405
406 if ('\"' != buf[*pos] || ! (ARGS_QUOTED & fl)) {
407 *v = &buf[*pos];
408
409 /*
410 * Thar be dragons here! If we're tab-separated, search
411 * ahead for either a tab or the `Ta' macro. If a tab
412 * is detected, it mustn't be escaped; if a `Ta' is
413 * detected, it must be space-buffered before and after.
414 * If either of these hold true, then prune out the
415 * extra spaces and call it an argument.
416 */
417
418 if (ARGS_TABSEP & fl) {
419 /* Scan ahead to unescaped tab. */
420
421 for (p = *v; ; p++) {
422 if (NULL == (p = strchr(p, '\t')))
423 break;
424 if (p == *v)
425 break;
426 if ('\\' != *(p - 1))
427 break;
428 }
429
430 /* Scan ahead to unescaped `Ta'. */
431
432 for (pp = *v; ; pp++) {
433 if (NULL == (pp = strstr(pp, "Ta")))
434 break;
435 if (pp > *v && ' ' != *(pp - 1))
436 continue;
437 if (' ' == *(pp + 2) || 0 == *(pp + 2))
438 break;
439 }
440
441 /* Choose delimiter tab/Ta. */
442
443 if (p && pp)
444 p = (p < pp ? p : pp);
445 else if ( ! p && pp)
446 p = pp;
447
448 /* Strip delimiter's preceding whitespace. */
449
450 if (p && p > *v) {
451 pp = p - 1;
452 while (pp > *v && ' ' == *pp)
453 pp--;
454 if (pp == *v && ' ' == *pp)
455 *pp = 0;
456 else if (' ' == *pp)
457 *(pp + 1) = 0;
458 }
459
460 /* ...in- and proceding whitespace. */
461
462 if (p && ('\t' != *p)) {
463 *p++ = 0;
464 *p++ = 0;
465 } else if (p)
466 *p++ = 0;
467
468 if (p) {
469 while (' ' == *p)
470 p++;
471 if (0 != *p)
472 *(p - 1) = 0;
473 *pos += (int)(p - *v);
474 }
475
476 if (p && 0 == *p)
477 if ( ! pwarn(mdoc, line, *pos, WCOLEMPTY))
478 return(0);
479 if (p && 0 == *p && p > *v && ' ' == *(p - 1))
480 if ( ! pwarn(mdoc, line, *pos, WTAILWS))
481 return(0);
482
483 if (p)
484 return(ARGS_WORD);
485
486 /* Configure the eoln case, too. */
487
488 p = strchr(*v, 0);
489 assert(p);
490
491 if (p > *v && ' ' == *(p - 1))
492 if ( ! pwarn(mdoc, line, *pos, WTAILWS))
493 return(0);
494 *pos += (int)(p - *v);
495
496 return(ARGS_WORD);
497 }
498
499 /* Do non-tabsep look-ahead here. */
500
501 if ( ! (ARGS_TABSEP & fl))
502 while (buf[*pos]) {
503 if (isspace((int)buf[*pos]))
504 if ('\\' != buf[*pos - 1])
505 break;
506 (*pos)++;
507 }
508
509 if (0 == buf[*pos])
510 return(ARGS_WORD);
511
512 buf[(*pos)++] = 0;
513
514 if (0 == buf[*pos])
515 return(ARGS_WORD);
516
517 if ( ! (ARGS_TABSEP & fl))
518 while (buf[*pos] && isspace((int)buf[*pos]))
519 (*pos)++;
520
521 if (buf[*pos])
522 return(ARGS_WORD);
523
524 if ( ! pwarn(mdoc, line, *pos, WTAILWS))
525 return(ARGS_ERROR);
526
527 return(ARGS_WORD);
528 }
529
530 /*
531 * If we're a quoted string (and quoted strings are allowed),
532 * then parse ahead to the next quote. If none's found, it's an
533 * error. After, parse to the next word.
534 */
535
536 *v = &buf[++(*pos)];
537
538 while (buf[*pos] && '\"' != buf[*pos])
539 (*pos)++;
540
541 if (0 == buf[*pos]) {
542 (void)perr(mdoc, line, *pos, EQUOTTERM);
543 return(ARGS_ERROR);
544 }
545
546 buf[(*pos)++] = 0;
547 if (0 == buf[*pos])
548 return(ARGS_QWORD);
549
550 while (buf[*pos] && isspace((int)buf[*pos]))
551 (*pos)++;
552
553 if (buf[*pos])
554 return(ARGS_QWORD);
555
556 if ( ! pwarn(mdoc, line, *pos, WTAILWS))
557 return(ARGS_ERROR);
558
559 return(ARGS_QWORD);
560 }
561
562
563 static int
564 argv_a2arg(int tok, const char *argv)
565 {
566
567 /*
568 * Parse an argument identifier from its text. XXX - this
569 * should really be table-driven to clarify the code.
570 *
571 * If you add an argument to the list, make sure that you
572 * register it here with its one or more macros!
573 */
574
575 switch (tok) {
576 case (MDOC_An):
577 if (xstrcmp(argv, "split"))
578 return(MDOC_Split);
579 else if (xstrcmp(argv, "nosplit"))
580 return(MDOC_Nosplit);
581 break;
582
583 case (MDOC_Bd):
584 if (xstrcmp(argv, "ragged"))
585 return(MDOC_Ragged);
586 else if (xstrcmp(argv, "unfilled"))
587 return(MDOC_Unfilled);
588 else if (xstrcmp(argv, "filled"))
589 return(MDOC_Filled);
590 else if (xstrcmp(argv, "literal"))
591 return(MDOC_Literal);
592 else if (xstrcmp(argv, "file"))
593 return(MDOC_File);
594 else if (xstrcmp(argv, "offset"))
595 return(MDOC_Offset);
596 break;
597
598 case (MDOC_Bf):
599 if (xstrcmp(argv, "emphasis"))
600 return(MDOC_Emphasis);
601 else if (xstrcmp(argv, "literal"))
602 return(MDOC_Literal);
603 else if (xstrcmp(argv, "symbolic"))
604 return(MDOC_Symbolic);
605 break;
606
607 case (MDOC_Bk):
608 if (xstrcmp(argv, "words"))
609 return(MDOC_Words);
610 break;
611
612 case (MDOC_Bl):
613 if (xstrcmp(argv, "bullet"))
614 return(MDOC_Bullet);
615 else if (xstrcmp(argv, "dash"))
616 return(MDOC_Dash);
617 else if (xstrcmp(argv, "hyphen"))
618 return(MDOC_Hyphen);
619 else if (xstrcmp(argv, "item"))
620 return(MDOC_Item);
621 else if (xstrcmp(argv, "enum"))
622 return(MDOC_Enum);
623 else if (xstrcmp(argv, "tag"))
624 return(MDOC_Tag);
625 else if (xstrcmp(argv, "diag"))
626 return(MDOC_Diag);
627 else if (xstrcmp(argv, "hang"))
628 return(MDOC_Hang);
629 else if (xstrcmp(argv, "ohang"))
630 return(MDOC_Ohang);
631 else if (xstrcmp(argv, "inset"))
632 return(MDOC_Inset);
633 else if (xstrcmp(argv, "column"))
634 return(MDOC_Column);
635 else if (xstrcmp(argv, "width"))
636 return(MDOC_Width);
637 else if (xstrcmp(argv, "offset"))
638 return(MDOC_Offset);
639 else if (xstrcmp(argv, "compact"))
640 return(MDOC_Compact);
641 break;
642
643 case (MDOC_Rv):
644 /* FALLTHROUGH */
645 case (MDOC_Ex):
646 if (xstrcmp(argv, "std"))
647 return(MDOC_Std);
648 break;
649
650 case (MDOC_St):
651 if (xstrcmp(argv, "p1003.1-88"))
652 return(MDOC_p1003_1_88);
653 else if (xstrcmp(argv, "p1003.1-90"))
654 return(MDOC_p1003_1_90);
655 else if (xstrcmp(argv, "p1003.1-96"))
656 return(MDOC_p1003_1_96);
657 else if (xstrcmp(argv, "p1003.1-2001"))
658 return(MDOC_p1003_1_2001);
659 else if (xstrcmp(argv, "p1003.1-2004"))
660 return(MDOC_p1003_1_2004);
661 else if (xstrcmp(argv, "p1003.1"))
662 return(MDOC_p1003_1);
663 else if (xstrcmp(argv, "p1003.1b"))
664 return(MDOC_p1003_1b);
665 else if (xstrcmp(argv, "p1003.1b-93"))
666 return(MDOC_p1003_1b_93);
667 else if (xstrcmp(argv, "p1003.1c-95"))
668 return(MDOC_p1003_1c_95);
669 else if (xstrcmp(argv, "p1003.1g-2000"))
670 return(MDOC_p1003_1g_2000);
671 else if (xstrcmp(argv, "p1003.2-92"))
672 return(MDOC_p1003_2_92);
673 else if (xstrcmp(argv, "p1003.2-95"))
674 return(MDOC_p1387_2_95);
675 else if (xstrcmp(argv, "p1003.2"))
676 return(MDOC_p1003_2);
677 else if (xstrcmp(argv, "p1387.2-95"))
678 return(MDOC_p1387_2);
679 else if (xstrcmp(argv, "isoC-90"))
680 return(MDOC_isoC_90);
681 else if (xstrcmp(argv, "isoC-amd1"))
682 return(MDOC_isoC_amd1);
683 else if (xstrcmp(argv, "isoC-tcor1"))
684 return(MDOC_isoC_tcor1);
685 else if (xstrcmp(argv, "isoC-tcor2"))
686 return(MDOC_isoC_tcor2);
687 else if (xstrcmp(argv, "isoC-99"))
688 return(MDOC_isoC_99);
689 else if (xstrcmp(argv, "ansiC"))
690 return(MDOC_ansiC);
691 else if (xstrcmp(argv, "ansiC-89"))
692 return(MDOC_ansiC_89);
693 else if (xstrcmp(argv, "ansiC-99"))
694 return(MDOC_ansiC_99);
695 else if (xstrcmp(argv, "ieee754"))
696 return(MDOC_ieee754);
697 else if (xstrcmp(argv, "iso8802-3"))
698 return(MDOC_iso8802_3);
699 else if (xstrcmp(argv, "xpg3"))
700 return(MDOC_xpg3);
701 else if (xstrcmp(argv, "xpg4"))
702 return(MDOC_xpg4);
703 else if (xstrcmp(argv, "xpg4.2"))
704 return(MDOC_xpg4_2);
705 else if (xstrcmp(argv, "xpg4.3"))
706 return(MDOC_xpg4_3);
707 else if (xstrcmp(argv, "xbd5"))
708 return(MDOC_xbd5);
709 else if (xstrcmp(argv, "xcu5"))
710 return(MDOC_xcu5);
711 else if (xstrcmp(argv, "xsh5"))
712 return(MDOC_xsh5);
713 else if (xstrcmp(argv, "xns5"))
714 return(MDOC_xns5);
715 else if (xstrcmp(argv, "xns5.2d2.0"))
716 return(MDOC_xns5_2d2_0);
717 else if (xstrcmp(argv, "xcurses4.2"))
718 return(MDOC_xcurses4_2);
719 else if (xstrcmp(argv, "susv2"))
720 return(MDOC_susv2);
721 else if (xstrcmp(argv, "susv3"))
722 return(MDOC_susv3);
723 else if (xstrcmp(argv, "svid4"))
724 return(MDOC_svid4);
725 break;
726
727 default:
728 break;
729 }
730
731 return(MDOC_ARG_MAX);
732 }
733
734
735 static int
736 argv_multi(struct mdoc *mdoc, int line,
737 struct mdoc_arg *v, int *pos, char *buf)
738 {
739 int c, ppos;
740 char *p;
741
742 v->sz = 0;
743 v->value = xcalloc(MDOC_LINEARG_MAX, sizeof(char *));
744
745 ppos = *pos;
746
747 for (v->sz = 0; v->sz < MDOC_LINEARG_MAX; v->sz++) {
748 if ('-' == buf[*pos])
749 break;
750 c = args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
751 if (ARGS_ERROR == c) {
752 free(v->value);
753 return(0);
754 } else if (ARGS_EOLN == c)
755 break;
756 v->value[(int)v->sz] = p;
757 }
758
759 if (0 < v->sz && v->sz < MDOC_LINEARG_MAX)
760 return(1);
761
762 free(v->value);
763 if (0 == v->sz)
764 return(perr(mdoc, line, ppos, EARGVAL));
765
766 return(perr(mdoc, line, ppos, EARGMANY));
767 }
768
769
770 static int
771 argv_opt_single(struct mdoc *mdoc, int line,
772 struct mdoc_arg *v, int *pos, char *buf)
773 {
774 int c, ppos;
775 char *p;
776
777 ppos = *pos;
778
779 if ('-' == buf[*pos])
780 return(1);
781
782 c = args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
783 if (ARGS_ERROR == c)
784 return(0);
785 if (ARGS_EOLN == c)
786 return(1);
787
788 v->sz = 1;
789 v->value = xcalloc(1, sizeof(char *));
790 v->value[0] = p;
791 return(1);
792 }
793
794
795 /*
796 * Parse a single, mandatory value from the stream.
797 */
798 static int
799 argv_single(struct mdoc *mdoc, int line,
800 struct mdoc_arg *v, int *pos, char *buf)
801 {
802 int c, ppos;
803 char *p;
804
805 ppos = *pos;
806
807 c = args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
808 if (ARGS_ERROR == c)
809 return(0);
810 if (ARGS_EOLN == c)
811 return(perr(mdoc, line, ppos, EARGVAL));
812
813 v->sz = 1;
814 v->value = xcalloc(1, sizeof(char *));
815 v->value[0] = p;
816 return(1);
817 }
818
819
820 /*
821 * Determine rules for parsing arguments. Arguments can either accept
822 * no parameters, an optional single parameter, one parameter, or
823 * multiple parameters.
824 */
825 static int
826 argv(struct mdoc *mdoc, int line,
827 struct mdoc_arg *v, int *pos, char *buf)
828 {
829
830 v->sz = 0;
831 v->value = NULL;
832
833 switch (mdoc_argvflags[v->arg]) {
834 case (ARGV_SINGLE):
835 return(argv_single(mdoc, line, v, pos, buf));
836 case (ARGV_MULTI):
837 return(argv_multi(mdoc, line, v, pos, buf));
838 case (ARGV_OPT_SINGLE):
839 return(argv_opt_single(mdoc, line, v, pos, buf));
840 default:
841 /* ARGV_NONE */
842 break;
843 }
844
845 return(1);
846 }
847
848
849 /*
850 * Parse an argument from line text. This comes in the form of -key
851 * [value0...], which may either have a single mandatory value, at least
852 * one mandatory value, an optional single value, or no value.
853 */
854 int
855 mdoc_argv(struct mdoc *mdoc, int line, int tok,
856 struct mdoc_arg *v, int *pos, char *buf)
857 {
858 int i;
859 char *p;
860
861 (void)memset(v, 0, sizeof(struct mdoc_arg));
862
863 if (0 == buf[*pos])
864 return(ARGV_EOLN);
865
866 assert( ! isspace((int)buf[*pos]));
867
868 if ('-' != buf[*pos])
869 return(ARGV_WORD);
870
871 i = *pos;
872 p = &buf[++(*pos)];
873
874 v->line = line;
875 v->pos = *pos;
876
877 assert(*pos > 0);
878
879 /* LINTED */
880 while (buf[*pos]) {
881 if (isspace((int)buf[*pos]))
882 if ('\\' != buf[*pos - 1])
883 break;
884 (*pos)++;
885 }
886
887 if (buf[*pos])
888 buf[(*pos)++] = 0;
889
890 /*
891 * We now parse out the per-macro arguments. XXX - this can be
892 * made much cleaner using per-argument tables. See argv_a2arg
893 * for details.
894 */
895
896 if (MDOC_ARG_MAX == (v->arg = argv_a2arg(tok, p))) {
897 if ( ! pwarn(mdoc, line, i, WARGVPARM))
898 return(ARGV_ERROR);
899 return(ARGV_WORD);
900 }
901
902 while (buf[*pos] && isspace((int)buf[*pos]))
903 (*pos)++;
904
905 /* FIXME: whitespace if no value. */
906
907 if ( ! argv(mdoc, line, v, pos, buf))
908 return(ARGV_ERROR);
909
910 return(ARGV_ARG);
911 }
912
913
914 void
915 mdoc_argv_free(int sz, struct mdoc_arg *arg)
916 {
917 int i;
918
919 for (i = 0; i < sz; i++) {
920 if (0 == arg[i].sz) {
921 assert(NULL == arg[i].value);
922 continue;
923 }
924 assert(arg[i].value);
925 free(arg[i].value);
926 }
927 }
928