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