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