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