fd302086be7cf05d0f5df87df2bd4f02b2627161
[dragonfly.git] / usr.bin / mandoc / mdoc_argv.c
1 /*      $Id: mdoc_argv.c,v 1.18 2009/10/27 21:40:07 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         0, /* %U */
207 };
208
209
210 /*
211  * Parse an argument from line text.  This comes in the form of -key
212  * [value0...], which may either have a single mandatory value, at least
213  * one mandatory value, an optional single value, or no value.
214  */
215 int
216 mdoc_argv(struct mdoc *m, int line, int tok,
217                 struct mdoc_arg **v, int *pos, char *buf)
218 {
219         char             *p, sv;
220         struct mdoc_argv tmp;
221         struct mdoc_arg  *arg;
222
223         if (0 == buf[*pos])
224                 return(ARGV_EOLN);
225
226         assert(' ' != buf[*pos]);
227
228         /* Parse through to the first unescaped space. */
229
230         p = &buf[++(*pos)];
231
232         assert(*pos > 0);
233
234         /* LINTED */
235         while (buf[*pos]) {
236                 if (' ' == buf[*pos])
237                         if ('\\' != buf[*pos - 1])
238                                 break;
239                 (*pos)++;
240         }
241
242         /* XXX - save zeroed byte, if not an argument. */
243
244         sv = 0;
245         if (buf[*pos]) {
246                 sv = buf[*pos];
247                 buf[(*pos)++] = 0;
248         }
249
250         (void)memset(&tmp, 0, sizeof(struct mdoc_argv));
251         tmp.line = line;
252         tmp.pos = *pos;
253
254         /* See if our token accepts the argument. */
255
256         if (MDOC_ARG_MAX == (tmp.arg = argv_a2arg(tok, p))) {
257                 /* XXX - restore saved zeroed byte. */
258                 if (sv)
259                         buf[*pos - 1] = sv;
260                 return(ARGV_WORD);
261         }
262
263         while (buf[*pos] && ' ' == buf[*pos])
264                 (*pos)++;
265
266         if ( ! argv(m, line, &tmp, pos, buf))
267                 return(ARGV_ERROR);
268
269         if (NULL == (arg = *v)) {
270                 *v = calloc(1, sizeof(struct mdoc_arg));
271                 if (NULL == *v) {
272                         (void)mdoc_nerr(m, m->last, EMALLOC);
273                         return(ARGV_ERROR);
274                 }
275                 arg = *v;
276         }
277
278         arg->argc++;
279         arg->argv = realloc(arg->argv, arg->argc *
280                         sizeof(struct mdoc_argv));
281
282         if (NULL == arg->argv) {
283                 (void)mdoc_nerr(m, m->last, EMALLOC);
284                 return(ARGV_ERROR);
285         }
286
287         (void)memcpy(&arg->argv[(int)arg->argc - 1],
288                         &tmp, sizeof(struct mdoc_argv));
289
290         return(ARGV_ARG);
291 }
292
293
294 void
295 mdoc_argv_free(struct mdoc_arg *p)
296 {
297         int              i, j;
298
299         if (NULL == p)
300                 return;
301
302         if (p->refcnt) {
303                 --(p->refcnt);
304                 if (p->refcnt)
305                         return;
306         }
307         assert(p->argc);
308
309         /* LINTED */
310         for (i = 0; i < (int)p->argc; i++) {
311                 if (0 == p->argv[i].sz)
312                         continue;
313                 if (NULL == p->argv[i].value)
314                         continue;
315
316                 /* LINTED */
317                 for (j = 0; j < (int)p->argv[i].sz; j++)
318                         if (p->argv[i].value[j])
319                                 free(p->argv[i].value[j]);
320
321                 free(p->argv[i].value);
322         }
323
324         free(p->argv);
325         free(p);
326 }
327
328
329 int
330 mdoc_zargs(struct mdoc *m, int line, int *pos,
331                 char *buf, int flags, char **v)
332 {
333
334         return(args(m, line, pos, buf, flags, v));
335 }
336
337
338 int
339 mdoc_args(struct mdoc *m, int line,
340                 int *pos, char *buf, int tok, char **v)
341 {
342         int               fl, c, i;
343         struct mdoc_node *n;
344
345         fl = (0 == tok) ? 0 : mdoc_argflags[tok];
346
347         if (MDOC_It != tok)
348                 return(args(m, line, pos, buf, fl, v));
349
350         /*
351          * The `It' macro is a special case, as it acquires parameters from its
352          * parent `Bl' context, specifically, we're concerned with -column.
353          */
354
355         for (n = m->last; n; n = n->parent)
356                 if (MDOC_BLOCK == n->type && MDOC_Bl == n->tok)
357                         break;
358
359         assert(n);
360         c = (int)(n->args ? n->args->argc : 0);
361         assert(c > 0);
362
363         /* LINTED */
364         for (i = 0; i < c; i++) {
365                 if (MDOC_Column != n->args->argv[i].arg)
366                         continue;
367                 fl |= ARGS_TABSEP;
368                 fl &= ~ARGS_DELIM;
369                 break;
370         }
371
372         return(args(m, line, pos, buf, fl, v));
373 }
374
375
376 static int
377 args(struct mdoc *m, int line, int *pos,
378                 char *buf, int fl, char **v)
379 {
380         int               i;
381         char             *p, *pp;
382
383         /*
384          * Parse out the terms (like `val' in `.Xx -arg val' or simply
385          * `.Xx val'), which can have all sorts of properties:
386          *
387          *   ARGS_DELIM: use special handling if encountering trailing
388          *   delimiters in the form of [[::delim::][ ]+]+.
389          *
390          *   ARGS_NOWARN: don't post warnings.  This is only used when
391          *   re-parsing delimiters, as the warnings have already been
392          *   posted.
393          *
394          *   ARGS_TABSEP: use special handling for tab/`Ta' separated
395          *   phrases like in `Bl -column'.
396          */
397
398         assert(*pos);
399         assert(' ' != buf[*pos]);
400
401         if (0 == buf[*pos])
402                 return(ARGS_EOLN);
403
404         /*
405          * If the first character is a delimiter and we're to look for
406          * delimited strings, then pass down the buffer seeing if it
407          * follows the pattern of [[::delim::][ ]+]+.
408          */
409
410         if ((fl & ARGS_DELIM) && mdoc_iscdelim(buf[*pos])) {
411                 for (i = *pos; buf[i]; ) {
412                         if ( ! mdoc_iscdelim(buf[i]))
413                                 break;
414                         i++;
415                         if (0 == buf[i] || ' ' != buf[i])
416                                 break;
417                         i++;
418                         while (buf[i] && ' ' == buf[i])
419                                 i++;
420                 }
421
422                 if (0 == buf[i]) {
423                         *v = &buf[*pos];
424                         if (' ' != buf[i - 1])
425                                 return(ARGS_PUNCT);
426                         if (ARGS_NOWARN & fl)
427                                 return(ARGS_PUNCT);
428                         if ( ! mdoc_pwarn(m, line, *pos, ETAILWS))
429                                 return(ARGS_ERROR);
430                         return(ARGS_PUNCT);
431                 }
432         }
433
434         *v = &buf[*pos];
435
436         /*
437          * First handle TABSEP items, restricted to `Bl -column'.  This
438          * ignores conventional token parsing and instead uses tabs or
439          * `Ta' macros to separate phrases.  Phrases are parsed again
440          * for arguments at a later phase.
441          */
442
443         if (ARGS_TABSEP & fl) {
444                 /* Scan ahead to tab (can't be escaped). */
445                 p = strchr(*v, '\t');
446
447                 /* Scan ahead to unescaped `Ta'. */
448                 for (pp = *v; ; pp++) {
449                         if (NULL == (pp = strstr(pp, "Ta")))
450                                 break;
451                         if (pp > *v && ' ' != *(pp - 1))
452                                 continue;
453                         if (' ' == *(pp + 2) || 0 == *(pp + 2))
454                                 break;
455                 }
456
457                 /*
458                  * Adjust new-buffer position to be beyond delimiter
459                  * mark (e.g., Ta -> end + 2).
460                  */
461                 if (p && pp) {
462                         *pos += pp < p ? 2 : 1;
463                         p = pp < p ? pp : p;
464                 } else if (p && ! pp) {
465                         *pos += 1;
466                 } else if (pp && ! p) {
467                         p = pp;
468                         *pos += 2;
469                 } else
470                         p = strchr(*v, 0);
471
472                 /* Whitespace check for eoln case... */
473                 if (0 == *p && ' ' == *(p - 1) && ! (ARGS_NOWARN & fl))
474                         if ( ! mdoc_pwarn(m, line, *pos, ETAILWS))
475                                 return(ARGS_ERROR);
476
477                 *pos += (int)(p - *v);
478
479                 /* Strip delimiter's preceding whitespace. */
480                 pp = p - 1;
481                 while (pp > *v && ' ' == *pp) {
482                         if (pp > *v && '\\' == *(pp - 1))
483                                 break;
484                         pp--;
485                 }
486                 *(pp + 1) = 0;
487
488                 /* Strip delimiter's proceeding whitespace. */
489                 for (pp = &buf[*pos]; ' ' == *pp; pp++, (*pos)++)
490                         /* Skip ahead. */ ;
491
492                 return(ARGS_PHRASE);
493         }
494
495         /*
496          * Process a quoted literal.  A quote begins with a double-quote
497          * and ends with a double-quote NOT preceded by a double-quote.
498          * Whitespace is NOT involved in literal termination.
499          */
500
501         if ('\"' == buf[*pos]) {
502                 *v = &buf[++(*pos)];
503
504                 for ( ; buf[*pos]; (*pos)++) {
505                         if ('\"' != buf[*pos])
506                                 continue;
507                         if ('\"' != buf[*pos + 1])
508                                 break;
509                         (*pos)++;
510                 }
511
512                 if (0 == buf[*pos]) {
513                         if (ARGS_NOWARN & fl)
514                                 return(ARGS_QWORD);
515                         if ( ! mdoc_pwarn(m, line, *pos, EQUOTTERM))
516                                 return(ARGS_ERROR);
517                         return(ARGS_QWORD);
518                 }
519
520                 buf[(*pos)++] = 0;
521
522                 if (0 == buf[*pos])
523                         return(ARGS_QWORD);
524
525                 while (' ' == buf[*pos])
526                         (*pos)++;
527
528                 if (0 == buf[*pos] && ! (ARGS_NOWARN & fl))
529                         if ( ! mdoc_pwarn(m, line, *pos, ETAILWS))
530                                 return(ARGS_ERROR);
531
532                 return(ARGS_QWORD);
533         }
534
535         /*
536          * A non-quoted term progresses until either the end of line or
537          * a non-escaped whitespace.
538          */
539
540         for ( ; buf[*pos]; (*pos)++)
541                 if (' ' == buf[*pos] && '\\' != buf[*pos - 1])
542                         break;
543
544         if (0 == buf[*pos])
545                 return(ARGS_WORD);
546
547         buf[(*pos)++] = 0;
548
549         while (' ' == buf[*pos])
550                 (*pos)++;
551
552         if (0 == buf[*pos] && ! (ARGS_NOWARN & fl))
553                 if ( ! mdoc_pwarn(m, line, *pos, ETAILWS))
554                         return(ARGS_ERROR);
555
556         return(ARGS_WORD);
557 }
558
559
560 static int
561 argv_a2arg(int tok, const char *p)
562 {
563
564         /*
565          * Parse an argument identifier from its text.  XXX - this
566          * should really be table-driven to clarify the code.
567          *
568          * If you add an argument to the list, make sure that you
569          * register it here with its one or more macros!
570          */
571
572         switch (tok) {
573         case (MDOC_An):
574                 if (0 == strcmp(p, "split"))
575                         return(MDOC_Split);
576                 else if (0 == strcmp(p, "nosplit"))
577                         return(MDOC_Nosplit);
578                 break;
579
580         case (MDOC_Bd):
581                 if (0 == strcmp(p, "ragged"))
582                         return(MDOC_Ragged);
583                 else if (0 == strcmp(p, "unfilled"))
584                         return(MDOC_Unfilled);
585                 else if (0 == strcmp(p, "filled"))
586                         return(MDOC_Filled);
587                 else if (0 == strcmp(p, "literal"))
588                         return(MDOC_Literal);
589                 else if (0 == strcmp(p, "file"))
590                         return(MDOC_File);
591                 else if (0 == strcmp(p, "offset"))
592                         return(MDOC_Offset);
593                 else if (0 == strcmp(p, "compact"))
594                         return(MDOC_Compact);
595                 else if (0 == strcmp(p, "centered"))
596                         return(MDOC_Centred);
597                 break;
598
599         case (MDOC_Bf):
600                 if (0 == strcmp(p, "emphasis"))
601                         return(MDOC_Emphasis);
602                 else if (0 == strcmp(p, "literal"))
603                         return(MDOC_Literal);
604                 else if (0 == strcmp(p, "symbolic"))
605                         return(MDOC_Symbolic);
606                 break;
607
608         case (MDOC_Bk):
609                 if (0 == strcmp(p, "words"))
610                         return(MDOC_Words);
611                 break;
612
613         case (MDOC_Bl):
614                 if (0 == strcmp(p, "bullet"))
615                         return(MDOC_Bullet);
616                 else if (0 == strcmp(p, "dash"))
617                         return(MDOC_Dash);
618                 else if (0 == strcmp(p, "hyphen"))
619                         return(MDOC_Hyphen);
620                 else if (0 == strcmp(p, "item"))
621                         return(MDOC_Item);
622                 else if (0 == strcmp(p, "enum"))
623                         return(MDOC_Enum);
624                 else if (0 == strcmp(p, "tag"))
625                         return(MDOC_Tag);
626                 else if (0 == strcmp(p, "diag"))
627                         return(MDOC_Diag);
628                 else if (0 == strcmp(p, "hang"))
629                         return(MDOC_Hang);
630                 else if (0 == strcmp(p, "ohang"))
631                         return(MDOC_Ohang);
632                 else if (0 == strcmp(p, "inset"))
633                         return(MDOC_Inset);
634                 else if (0 == strcmp(p, "column"))
635                         return(MDOC_Column);
636                 else if (0 == strcmp(p, "width"))
637                         return(MDOC_Width);
638                 else if (0 == strcmp(p, "offset"))
639                         return(MDOC_Offset);
640                 else if (0 == strcmp(p, "compact"))
641                         return(MDOC_Compact);
642                 else if (0 == strcmp(p, "nested"))
643                         return(MDOC_Nested);
644                 break;
645
646         case (MDOC_Rv):
647                 /* FALLTHROUGH */
648         case (MDOC_Ex):
649                 if (0 == strcmp(p, "std"))
650                         return(MDOC_Std);
651                 break;
652         default:
653                 break;
654         }
655
656         return(MDOC_ARG_MAX);
657 }
658
659
660 static int
661 argv_multi(struct mdoc *m, int line,
662                 struct mdoc_argv *v, int *pos, char *buf)
663 {
664         int              c;
665         char            *p;
666
667         for (v->sz = 0; ; v->sz++) {
668                 if ('-' == buf[*pos])
669                         break;
670                 c = args(m, line, pos, buf, 0, &p);
671                 if (ARGS_ERROR == c)
672                         return(0);
673                 else if (ARGS_EOLN == c)
674                         break;
675
676                 if (0 == v->sz % MULTI_STEP) {
677                         v->value = realloc(v->value,
678                                 (v->sz + MULTI_STEP) * sizeof(char *));
679                         if (NULL == v->value) {
680                                 (void)mdoc_nerr(m, m->last, EMALLOC);
681                                 return(ARGV_ERROR);
682                         }
683                 }
684                 if (NULL == (v->value[(int)v->sz] = strdup(p)))
685                         return(mdoc_nerr(m, m->last, EMALLOC));
686         }
687
688         return(1);
689 }
690
691
692 static int
693 argv_opt_single(struct mdoc *m, int line,
694                 struct mdoc_argv *v, int *pos, char *buf)
695 {
696         int              c;
697         char            *p;
698
699         if ('-' == buf[*pos])
700                 return(1);
701
702         c = args(m, line, pos, buf, 0, &p);
703         if (ARGS_ERROR == c)
704                 return(0);
705         if (ARGS_EOLN == c)
706                 return(1);
707
708         v->sz = 1;
709         if (NULL == (v->value = calloc(1, sizeof(char *))))
710                 return(mdoc_nerr(m, m->last, EMALLOC));
711         if (NULL == (v->value[0] = strdup(p)))
712                 return(mdoc_nerr(m, m->last, EMALLOC));
713
714         return(1);
715 }
716
717
718 /*
719  * Parse a single, mandatory value from the stream.
720  */
721 static int
722 argv_single(struct mdoc *m, int line,
723                 struct mdoc_argv *v, int *pos, char *buf)
724 {
725         int              c, ppos;
726         char            *p;
727
728         ppos = *pos;
729
730         c = args(m, line, pos, buf, 0, &p);
731         if (ARGS_ERROR == c)
732                 return(0);
733         if (ARGS_EOLN == c)
734                 return(mdoc_perr(m, line, ppos, EARGVAL));
735
736         v->sz = 1;
737         if (NULL == (v->value = calloc(1, sizeof(char *))))
738                 return(mdoc_nerr(m, m->last, EMALLOC));
739         if (NULL == (v->value[0] = strdup(p)))
740                 return(mdoc_nerr(m, m->last, EMALLOC));
741
742         return(1);
743 }
744
745
746 /*
747  * Determine rules for parsing arguments.  Arguments can either accept
748  * no parameters, an optional single parameter, one parameter, or
749  * multiple parameters.
750  */
751 static int
752 argv(struct mdoc *mdoc, int line,
753                 struct mdoc_argv *v, int *pos, char *buf)
754 {
755
756         v->sz = 0;
757         v->value = NULL;
758
759         switch (mdoc_argvflags[v->arg]) {
760         case (ARGV_SINGLE):
761                 return(argv_single(mdoc, line, v, pos, buf));
762         case (ARGV_MULTI):
763                 return(argv_multi(mdoc, line, v, pos, buf));
764         case (ARGV_OPT_SINGLE):
765                 return(argv_opt_single(mdoc, line, v, pos, buf));
766         default:
767                 /* ARGV_NONE */
768                 break;
769         }
770
771         return(1);
772 }