Import mdocml-1.11.3
[dragonfly.git] / contrib / mdocml / mdoc_argv.c
CommitLineData
a4c7eb57 1/* $Id: mdoc_argv.c,v 1.77 2011/05/12 23:44:01 kristaps Exp $ */
80387638
SW
2/*
3 * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
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 above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17#ifdef HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <sys/types.h>
22
23#include <assert.h>
24#include <ctype.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28
60e1e752 29#include "mdoc.h"
80387638
SW
30#include "mandoc.h"
31#include "libmdoc.h"
32#include "libmandoc.h"
33
60e1e752 34#define MULTI_STEP 5 /* pre-allocate argument values */
a4c7eb57
SW
35#define DELIMSZ 6 /* max possible size of a delimiter */
36
37enum argsflag {
38 ARGSFL_NONE = 0,
39 ARGSFL_DELIM, /* handle delimiters of [[::delim::][ ]+]+ */
40 ARGSFL_TABSEP /* handle tab/`Ta' separated phrases */
41};
42
43enum argvflag {
44 ARGV_NONE, /* no args to flag (e.g., -split) */
45 ARGV_SINGLE, /* one arg to flag (e.g., -file xxx) */
46 ARGV_MULTI, /* multiple args (e.g., -column xxx yyy) */
47 ARGV_OPT_SINGLE /* optional arg (e.g., -offset [xxx]) */
48};
80387638
SW
49
50static enum mdocargt argv_a2arg(enum mdoct, const char *);
51static enum margserr args(struct mdoc *, int, int *,
a4c7eb57
SW
52 char *, enum argsflag, char **);
53static int args_checkpunct(const char *, int);
80387638
SW
54static int argv(struct mdoc *, int,
55 struct mdoc_argv *, int *, char *);
56static int argv_single(struct mdoc *, int,
57 struct mdoc_argv *, int *, char *);
58static int argv_opt_single(struct mdoc *, int,
59 struct mdoc_argv *, int *, char *);
60static int argv_multi(struct mdoc *, int,
61 struct mdoc_argv *, int *, char *);
60e1e752 62static void argn_free(struct mdoc_arg *, int);
80387638 63
60e1e752 64static const enum argvflag argvflags[MDOC_ARG_MAX] = {
80387638
SW
65 ARGV_NONE, /* MDOC_Split */
66 ARGV_NONE, /* MDOC_Nosplit */
67 ARGV_NONE, /* MDOC_Ragged */
68 ARGV_NONE, /* MDOC_Unfilled */
69 ARGV_NONE, /* MDOC_Literal */
70 ARGV_SINGLE, /* MDOC_File */
71 ARGV_OPT_SINGLE, /* MDOC_Offset */
72 ARGV_NONE, /* MDOC_Bullet */
73 ARGV_NONE, /* MDOC_Dash */
74 ARGV_NONE, /* MDOC_Hyphen */
75 ARGV_NONE, /* MDOC_Item */
76 ARGV_NONE, /* MDOC_Enum */
77 ARGV_NONE, /* MDOC_Tag */
78 ARGV_NONE, /* MDOC_Diag */
79 ARGV_NONE, /* MDOC_Hang */
80 ARGV_NONE, /* MDOC_Ohang */
81 ARGV_NONE, /* MDOC_Inset */
82 ARGV_MULTI, /* MDOC_Column */
83 ARGV_SINGLE, /* MDOC_Width */
84 ARGV_NONE, /* MDOC_Compact */
85 ARGV_NONE, /* MDOC_Std */
86 ARGV_NONE, /* MDOC_Filled */
87 ARGV_NONE, /* MDOC_Words */
88 ARGV_NONE, /* MDOC_Emphasis */
89 ARGV_NONE, /* MDOC_Symbolic */
90 ARGV_NONE /* MDOC_Symbolic */
91};
92
a4c7eb57
SW
93static const enum argsflag argflags[MDOC_MAX] = {
94 ARGSFL_NONE, /* Ap */
95 ARGSFL_NONE, /* Dd */
96 ARGSFL_NONE, /* Dt */
97 ARGSFL_NONE, /* Os */
98 ARGSFL_NONE, /* Sh */
99 ARGSFL_NONE, /* Ss */
100 ARGSFL_NONE, /* Pp */
101 ARGSFL_DELIM, /* D1 */
102 ARGSFL_DELIM, /* Dl */
103 ARGSFL_NONE, /* Bd */
104 ARGSFL_NONE, /* Ed */
105 ARGSFL_NONE, /* Bl */
106 ARGSFL_NONE, /* El */
107 ARGSFL_NONE, /* It */
108 ARGSFL_DELIM, /* Ad */
109 ARGSFL_DELIM, /* An */
110 ARGSFL_DELIM, /* Ar */
111 ARGSFL_NONE, /* Cd */
112 ARGSFL_DELIM, /* Cm */
113 ARGSFL_DELIM, /* Dv */
114 ARGSFL_DELIM, /* Er */
115 ARGSFL_DELIM, /* Ev */
116 ARGSFL_NONE, /* Ex */
117 ARGSFL_DELIM, /* Fa */
118 ARGSFL_NONE, /* Fd */
119 ARGSFL_DELIM, /* Fl */
120 ARGSFL_DELIM, /* Fn */
121 ARGSFL_DELIM, /* Ft */
122 ARGSFL_DELIM, /* Ic */
123 ARGSFL_NONE, /* In */
124 ARGSFL_DELIM, /* Li */
125 ARGSFL_NONE, /* Nd */
126 ARGSFL_DELIM, /* Nm */
127 ARGSFL_DELIM, /* Op */
128 ARGSFL_NONE, /* Ot */
129 ARGSFL_DELIM, /* Pa */
130 ARGSFL_NONE, /* Rv */
131 ARGSFL_DELIM, /* St */
132 ARGSFL_DELIM, /* Va */
133 ARGSFL_DELIM, /* Vt */
134 ARGSFL_DELIM, /* Xr */
135 ARGSFL_NONE, /* %A */
136 ARGSFL_NONE, /* %B */
137 ARGSFL_NONE, /* %D */
138 ARGSFL_NONE, /* %I */
139 ARGSFL_NONE, /* %J */
140 ARGSFL_NONE, /* %N */
141 ARGSFL_NONE, /* %O */
142 ARGSFL_NONE, /* %P */
143 ARGSFL_NONE, /* %R */
144 ARGSFL_NONE, /* %T */
145 ARGSFL_NONE, /* %V */
146 ARGSFL_DELIM, /* Ac */
147 ARGSFL_NONE, /* Ao */
148 ARGSFL_DELIM, /* Aq */
149 ARGSFL_DELIM, /* At */
150 ARGSFL_DELIM, /* Bc */
151 ARGSFL_NONE, /* Bf */
152 ARGSFL_NONE, /* Bo */
153 ARGSFL_DELIM, /* Bq */
154 ARGSFL_DELIM, /* Bsx */
155 ARGSFL_DELIM, /* Bx */
156 ARGSFL_NONE, /* Db */
157 ARGSFL_DELIM, /* Dc */
158 ARGSFL_NONE, /* Do */
159 ARGSFL_DELIM, /* Dq */
160 ARGSFL_DELIM, /* Ec */
161 ARGSFL_NONE, /* Ef */
162 ARGSFL_DELIM, /* Em */
163 ARGSFL_NONE, /* Eo */
164 ARGSFL_DELIM, /* Fx */
165 ARGSFL_DELIM, /* Ms */
166 ARGSFL_DELIM, /* No */
167 ARGSFL_DELIM, /* Ns */
168 ARGSFL_DELIM, /* Nx */
169 ARGSFL_DELIM, /* Ox */
170 ARGSFL_DELIM, /* Pc */
171 ARGSFL_DELIM, /* Pf */
172 ARGSFL_NONE, /* Po */
173 ARGSFL_DELIM, /* Pq */
174 ARGSFL_DELIM, /* Qc */
175 ARGSFL_DELIM, /* Ql */
176 ARGSFL_NONE, /* Qo */
177 ARGSFL_DELIM, /* Qq */
178 ARGSFL_NONE, /* Re */
179 ARGSFL_NONE, /* Rs */
180 ARGSFL_DELIM, /* Sc */
181 ARGSFL_NONE, /* So */
182 ARGSFL_DELIM, /* Sq */
183 ARGSFL_NONE, /* Sm */
184 ARGSFL_DELIM, /* Sx */
185 ARGSFL_DELIM, /* Sy */
186 ARGSFL_DELIM, /* Tn */
187 ARGSFL_DELIM, /* Ux */
188 ARGSFL_DELIM, /* Xc */
189 ARGSFL_NONE, /* Xo */
190 ARGSFL_NONE, /* Fo */
191 ARGSFL_NONE, /* Fc */
192 ARGSFL_NONE, /* Oo */
193 ARGSFL_DELIM, /* Oc */
194 ARGSFL_NONE, /* Bk */
195 ARGSFL_NONE, /* Ek */
196 ARGSFL_NONE, /* Bt */
197 ARGSFL_NONE, /* Hf */
198 ARGSFL_NONE, /* Fr */
199 ARGSFL_NONE, /* Ud */
200 ARGSFL_NONE, /* Lb */
201 ARGSFL_NONE, /* Lp */
202 ARGSFL_DELIM, /* Lk */
203 ARGSFL_DELIM, /* Mt */
204 ARGSFL_DELIM, /* Brq */
205 ARGSFL_NONE, /* Bro */
206 ARGSFL_DELIM, /* Brc */
207 ARGSFL_NONE, /* %C */
208 ARGSFL_NONE, /* Es */
209 ARGSFL_NONE, /* En */
210 ARGSFL_NONE, /* Dx */
211 ARGSFL_NONE, /* %Q */
212 ARGSFL_NONE, /* br */
213 ARGSFL_NONE, /* sp */
214 ARGSFL_NONE, /* %U */
215 ARGSFL_NONE, /* Ta */
80387638
SW
216};
217
60e1e752
SW
218static const enum mdocargt args_Ex[] = {
219 MDOC_Std,
220 MDOC_ARG_MAX
221};
222
223static const enum mdocargt args_An[] = {
224 MDOC_Split,
225 MDOC_Nosplit,
226 MDOC_ARG_MAX
227};
228
229static const enum mdocargt args_Bd[] = {
230 MDOC_Ragged,
231 MDOC_Unfilled,
232 MDOC_Filled,
233 MDOC_Literal,
234 MDOC_File,
235 MDOC_Offset,
236 MDOC_Compact,
237 MDOC_Centred,
238 MDOC_ARG_MAX
239};
240
241static const enum mdocargt args_Bf[] = {
242 MDOC_Emphasis,
243 MDOC_Literal,
244 MDOC_Symbolic,
245 MDOC_ARG_MAX
246};
247
248static const enum mdocargt args_Bk[] = {
249 MDOC_Words,
250 MDOC_ARG_MAX
251};
252
253static const enum mdocargt args_Bl[] = {
254 MDOC_Bullet,
255 MDOC_Dash,
256 MDOC_Hyphen,
257 MDOC_Item,
258 MDOC_Enum,
259 MDOC_Tag,
260 MDOC_Diag,
261 MDOC_Hang,
262 MDOC_Ohang,
263 MDOC_Inset,
264 MDOC_Column,
265 MDOC_Width,
266 MDOC_Offset,
267 MDOC_Compact,
268 MDOC_Nested,
269 MDOC_ARG_MAX
270};
80387638
SW
271
272/*
273 * Parse an argument from line text. This comes in the form of -key
274 * [value0...], which may either have a single mandatory value, at least
275 * one mandatory value, an optional single value, or no value.
276 */
277enum margverr
278mdoc_argv(struct mdoc *m, int line, enum mdoct tok,
279 struct mdoc_arg **v, int *pos, char *buf)
280{
281 char *p, sv;
282 struct mdoc_argv tmp;
283 struct mdoc_arg *arg;
284
285 if ('\0' == buf[*pos])
286 return(ARGV_EOLN);
287
288 assert(' ' != buf[*pos]);
289
290 /* Parse through to the first unescaped space. */
291
292 p = &buf[++(*pos)];
293
294 assert(*pos > 0);
295
296 /* LINTED */
297 while (buf[*pos]) {
298 if (' ' == buf[*pos])
299 if ('\\' != buf[*pos - 1])
300 break;
301 (*pos)++;
302 }
303
304 /* XXX - save zeroed byte, if not an argument. */
305
306 sv = '\0';
307 if (buf[*pos]) {
308 sv = buf[*pos];
309 buf[(*pos)++] = '\0';
310 }
311
60e1e752 312 memset(&tmp, 0, sizeof(struct mdoc_argv));
80387638
SW
313 tmp.line = line;
314 tmp.pos = *pos;
315
316 /* See if our token accepts the argument. */
317
318 if (MDOC_ARG_MAX == (tmp.arg = argv_a2arg(tok, p))) {
319 /* XXX - restore saved zeroed byte. */
320 if (sv)
321 buf[*pos - 1] = sv;
322 return(ARGV_WORD);
323 }
324
325 while (buf[*pos] && ' ' == buf[*pos])
326 (*pos)++;
327
328 if ( ! argv(m, line, &tmp, pos, buf))
329 return(ARGV_ERROR);
330
331 if (NULL == (arg = *v))
332 arg = *v = mandoc_calloc(1, sizeof(struct mdoc_arg));
333
334 arg->argc++;
335 arg->argv = mandoc_realloc
336 (arg->argv, arg->argc * sizeof(struct mdoc_argv));
337
60e1e752 338 memcpy(&arg->argv[(int)arg->argc - 1],
80387638
SW
339 &tmp, sizeof(struct mdoc_argv));
340
341 return(ARGV_ARG);
342}
343
80387638
SW
344void
345mdoc_argv_free(struct mdoc_arg *p)
346{
347 int i;
348
349 if (NULL == p)
350 return;
351
352 if (p->refcnt) {
353 --(p->refcnt);
354 if (p->refcnt)
355 return;
356 }
357 assert(p->argc);
358
359 for (i = (int)p->argc - 1; i >= 0; i--)
60e1e752 360 argn_free(p, i);
80387638
SW
361
362 free(p->argv);
363 free(p);
364}
365
60e1e752
SW
366static void
367argn_free(struct mdoc_arg *p, int iarg)
80387638
SW
368{
369 struct mdoc_argv *arg;
370 int j;
371
372 arg = &p->argv[iarg];
373
374 if (arg->sz && arg->value) {
375 for (j = (int)arg->sz - 1; j >= 0; j--)
376 free(arg->value[j]);
377 free(arg->value);
378 }
379
380 for (--p->argc; iarg < (int)p->argc; iarg++)
381 p->argv[iarg] = p->argv[iarg+1];
382}
383
80387638 384enum margserr
a4c7eb57 385mdoc_zargs(struct mdoc *m, int line, int *pos, char *buf, char **v)
80387638
SW
386{
387
a4c7eb57 388 return(args(m, line, pos, buf, ARGSFL_NONE, v));
80387638
SW
389}
390
80387638
SW
391enum margserr
392mdoc_args(struct mdoc *m, int line, int *pos,
393 char *buf, enum mdoct tok, char **v)
394{
a4c7eb57 395 enum argsflag fl;
80387638
SW
396 struct mdoc_node *n;
397
60e1e752 398 fl = argflags[tok];
80387638
SW
399
400 if (MDOC_It != tok)
401 return(args(m, line, pos, buf, fl, v));
402
403 /*
404 * We know that we're in an `It', so it's reasonable to expect
405 * us to be sitting in a `Bl'. Someday this may not be the case
406 * (if we allow random `It's sitting out there), so provide a
407 * safe fall-back into the default behaviour.
408 */
409
410 for (n = m->last; n; n = n->parent)
411 if (MDOC_Bl == n->tok)
a4c7eb57
SW
412 if (LIST_column == n->norm->Bl.type) {
413 fl = ARGSFL_TABSEP;
414 break;
415 }
80387638
SW
416
417 return(args(m, line, pos, buf, fl, v));
418}
419
80387638
SW
420static enum margserr
421args(struct mdoc *m, int line, int *pos,
a4c7eb57 422 char *buf, enum argsflag fl, char **v)
80387638 423{
80387638
SW
424 char *p, *pp;
425 enum margserr rc;
80387638 426
80387638
SW
427 assert(' ' != buf[*pos]);
428
429 if ('\0' == buf[*pos]) {
430 if (MDOC_PPHRASE & m->flags)
431 return(ARGS_EOLN);
432 /*
433 * If we're not in a partial phrase and the flag for
434 * being a phrase literal is still set, the punctuation
435 * is unterminated.
436 */
437 if (MDOC_PHRASELIT & m->flags)
60e1e752 438 mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
80387638
SW
439
440 m->flags &= ~MDOC_PHRASELIT;
441 return(ARGS_EOLN);
442 }
443
80387638
SW
444 *v = &buf[*pos];
445
a4c7eb57
SW
446 if (ARGSFL_DELIM == fl)
447 if (args_checkpunct(buf, *pos))
448 return(ARGS_PUNCT);
60e1e752 449
80387638
SW
450 /*
451 * First handle TABSEP items, restricted to `Bl -column'. This
452 * ignores conventional token parsing and instead uses tabs or
453 * `Ta' macros to separate phrases. Phrases are parsed again
454 * for arguments at a later phase.
455 */
456
a4c7eb57 457 if (ARGSFL_TABSEP == fl) {
80387638
SW
458 /* Scan ahead to tab (can't be escaped). */
459 p = strchr(*v, '\t');
460 pp = NULL;
461
462 /* Scan ahead to unescaped `Ta'. */
463 if ( ! (MDOC_PHRASELIT & m->flags))
464 for (pp = *v; ; pp++) {
465 if (NULL == (pp = strstr(pp, "Ta")))
466 break;
467 if (pp > *v && ' ' != *(pp - 1))
468 continue;
469 if (' ' == *(pp + 2) || '\0' == *(pp + 2))
470 break;
471 }
472
473 /* By default, assume a phrase. */
474 rc = ARGS_PHRASE;
475
476 /*
477 * Adjust new-buffer position to be beyond delimiter
478 * mark (e.g., Ta -> end + 2).
479 */
480 if (p && pp) {
481 *pos += pp < p ? 2 : 1;
482 rc = pp < p ? ARGS_PHRASE : ARGS_PPHRASE;
483 p = pp < p ? pp : p;
484 } else if (p && ! pp) {
485 rc = ARGS_PPHRASE;
486 *pos += 1;
487 } else if (pp && ! p) {
488 p = pp;
489 *pos += 2;
490 } else {
491 rc = ARGS_PEND;
492 p = strchr(*v, 0);
493 }
494
495 /* Whitespace check for eoln case... */
a4c7eb57 496 if ('\0' == *p && ' ' == *(p - 1))
60e1e752 497 mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
80387638
SW
498
499 *pos += (int)(p - *v);
500
501 /* Strip delimiter's preceding whitespace. */
502 pp = p - 1;
503 while (pp > *v && ' ' == *pp) {
504 if (pp > *v && '\\' == *(pp - 1))
505 break;
506 pp--;
507 }
508 *(pp + 1) = 0;
509
510 /* Strip delimiter's proceeding whitespace. */
511 for (pp = &buf[*pos]; ' ' == *pp; pp++, (*pos)++)
512 /* Skip ahead. */ ;
513
514 return(rc);
515 }
516
517 /*
518 * Process a quoted literal. A quote begins with a double-quote
519 * and ends with a double-quote NOT preceded by a double-quote.
520 * Whitespace is NOT involved in literal termination.
521 */
522
523 if (MDOC_PHRASELIT & m->flags || '\"' == buf[*pos]) {
524 if ( ! (MDOC_PHRASELIT & m->flags))
525 *v = &buf[++(*pos)];
526
527 if (MDOC_PPHRASE & m->flags)
528 m->flags |= MDOC_PHRASELIT;
529
530 for ( ; buf[*pos]; (*pos)++) {
531 if ('\"' != buf[*pos])
532 continue;
533 if ('\"' != buf[*pos + 1])
534 break;
535 (*pos)++;
536 }
537
538 if ('\0' == buf[*pos]) {
a4c7eb57 539 if (MDOC_PPHRASE & m->flags)
80387638 540 return(ARGS_QWORD);
60e1e752 541 mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
80387638
SW
542 return(ARGS_QWORD);
543 }
544
545 m->flags &= ~MDOC_PHRASELIT;
546 buf[(*pos)++] = '\0';
547
548 if ('\0' == buf[*pos])
549 return(ARGS_QWORD);
550
551 while (' ' == buf[*pos])
552 (*pos)++;
553
a4c7eb57 554 if ('\0' == buf[*pos])
60e1e752 555 mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
80387638
SW
556
557 return(ARGS_QWORD);
558 }
559
a4c7eb57
SW
560 p = &buf[*pos];
561 *v = mandoc_getarg(m->parse, &p, line, pos);
80387638
SW
562
563 return(ARGS_WORD);
564}
565
60e1e752
SW
566/*
567 * Check if the string consists only of space-separated closing
568 * delimiters. This is a bit of a dance: the first must be a close
569 * delimiter, but it may be followed by middle delimiters. Arbitrary
570 * whitespace may separate these tokens.
571 */
572static int
a4c7eb57 573args_checkpunct(const char *buf, int i)
60e1e752
SW
574{
575 int j;
576 char dbuf[DELIMSZ];
577 enum mdelim d;
578
579 /* First token must be a close-delimiter. */
580
581 for (j = 0; buf[i] && ' ' != buf[i] && j < DELIMSZ; j++, i++)
582 dbuf[j] = buf[i];
583
584 if (DELIMSZ == j)
585 return(0);
586
587 dbuf[j] = '\0';
588 if (DELIM_CLOSE != mdoc_isdelim(dbuf))
589 return(0);
590
591 while (' ' == buf[i])
592 i++;
593
594 /* Remaining must NOT be open/none. */
595
596 while (buf[i]) {
597 j = 0;
598 while (buf[i] && ' ' != buf[i] && j < DELIMSZ)
599 dbuf[j++] = buf[i++];
600
601 if (DELIMSZ == j)
602 return(0);
603
604 dbuf[j] = '\0';
605 d = mdoc_isdelim(dbuf);
606 if (DELIM_NONE == d || DELIM_OPEN == d)
607 return(0);
608
609 while (' ' == buf[i])
610 i++;
611 }
612
60e1e752
SW
613 return('\0' == buf[i]);
614}
80387638 615
60e1e752
SW
616/*
617 * Match up an argument string (e.g., `-foo bar' having "foo") with the
618 * correrct identifier. It must apply to the given macro. If none was
619 * found (including bad matches), return MDOC_ARG_MAX.
620 */
80387638
SW
621static enum mdocargt
622argv_a2arg(enum mdoct tok, const char *p)
623{
a4c7eb57 624 const enum mdocargt *argsp;
80387638 625
a4c7eb57 626 argsp = NULL;
80387638
SW
627
628 switch (tok) {
629 case (MDOC_An):
a4c7eb57 630 argsp = args_An;
80387638 631 break;
80387638 632 case (MDOC_Bd):
a4c7eb57 633 argsp = args_Bd;
80387638 634 break;
80387638 635 case (MDOC_Bf):
a4c7eb57 636 argsp = args_Bf;
80387638 637 break;
80387638 638 case (MDOC_Bk):
a4c7eb57 639 argsp = args_Bk;
80387638 640 break;
80387638 641 case (MDOC_Bl):
a4c7eb57 642 argsp = args_Bl;
80387638 643 break;
80387638
SW
644 case (MDOC_Rv):
645 /* FALLTHROUGH */
646 case (MDOC_Ex):
a4c7eb57 647 argsp = args_Ex;
80387638
SW
648 break;
649 default:
60e1e752 650 return(MDOC_ARG_MAX);
80387638
SW
651 }
652
a4c7eb57 653 assert(argsp);
60e1e752 654
a4c7eb57
SW
655 for ( ; MDOC_ARG_MAX != *argsp ; argsp++)
656 if (0 == strcmp(p, mdoc_argnames[*argsp]))
657 return(*argsp);
60e1e752 658
80387638
SW
659 return(MDOC_ARG_MAX);
660}
661
80387638
SW
662static int
663argv_multi(struct mdoc *m, int line,
664 struct mdoc_argv *v, int *pos, char *buf)
665{
666 enum margserr ac;
667 char *p;
668
669 for (v->sz = 0; ; v->sz++) {
670 if ('-' == buf[*pos])
671 break;
a4c7eb57 672 ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
80387638
SW
673 if (ARGS_ERROR == ac)
674 return(0);
675 else if (ARGS_EOLN == ac)
676 break;
677
678 if (0 == v->sz % MULTI_STEP)
679 v->value = mandoc_realloc(v->value,
680 (v->sz + MULTI_STEP) * sizeof(char *));
681
682 v->value[(int)v->sz] = mandoc_strdup(p);
683 }
684
685 return(1);
686}
687
80387638
SW
688static int
689argv_opt_single(struct mdoc *m, int line,
690 struct mdoc_argv *v, int *pos, char *buf)
691{
692 enum margserr ac;
693 char *p;
694
695 if ('-' == buf[*pos])
696 return(1);
697
a4c7eb57 698 ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
80387638
SW
699 if (ARGS_ERROR == ac)
700 return(0);
701 if (ARGS_EOLN == ac)
702 return(1);
703
704 v->sz = 1;
705 v->value = mandoc_malloc(sizeof(char *));
706 v->value[0] = mandoc_strdup(p);
707
708 return(1);
709}
710
80387638
SW
711/*
712 * Parse a single, mandatory value from the stream.
713 */
714static int
715argv_single(struct mdoc *m, int line,
716 struct mdoc_argv *v, int *pos, char *buf)
717{
718 int ppos;
719 enum margserr ac;
720 char *p;
721
722 ppos = *pos;
723
a4c7eb57 724 ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
80387638
SW
725 if (ARGS_EOLN == ac) {
726 mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTARGVCOUNT);
727 return(0);
728 } else if (ARGS_ERROR == ac)
729 return(0);
730
731 v->sz = 1;
732 v->value = mandoc_malloc(sizeof(char *));
733 v->value[0] = mandoc_strdup(p);
734
735 return(1);
736}
737
80387638
SW
738/*
739 * Determine rules for parsing arguments. Arguments can either accept
740 * no parameters, an optional single parameter, one parameter, or
741 * multiple parameters.
742 */
743static int
744argv(struct mdoc *mdoc, int line,
745 struct mdoc_argv *v, int *pos, char *buf)
746{
747
748 v->sz = 0;
749 v->value = NULL;
750
60e1e752 751 switch (argvflags[v->arg]) {
80387638
SW
752 case (ARGV_SINGLE):
753 return(argv_single(mdoc, line, v, pos, buf));
754 case (ARGV_MULTI):
755 return(argv_multi(mdoc, line, v, pos, buf));
756 case (ARGV_OPT_SINGLE):
757 return(argv_opt_single(mdoc, line, v, pos, buf));
60e1e752 758 case (ARGV_NONE):
80387638 759 break;
60e1e752
SW
760 default:
761 abort();
762 /* NOTREACHED */
80387638
SW
763 }
764
765 return(1);
766}