Merge branch 'vendor/GCC44'
[dragonfly.git] / contrib / mdocml / mdoc_argv.c
1 /*      $Id: mdoc_argv.c,v 1.77 2011/05/12 23:44:01 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 #define DELIMSZ          6 /* max possible size of a delimiter */
36
37 enum    argsflag {
38         ARGSFL_NONE = 0,
39         ARGSFL_DELIM, /* handle delimiters of [[::delim::][ ]+]+ */
40         ARGSFL_TABSEP /* handle tab/`Ta' separated phrases */
41 };
42
43 enum    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 };
49
50 static  enum mdocargt    argv_a2arg(enum mdoct, const char *);
51 static  enum margserr    args(struct mdoc *, int, int *, 
52                                 char *, enum argsflag, char **);
53 static  int              args_checkpunct(const char *, int);
54 static  int              argv(struct mdoc *, int, 
55                                 struct mdoc_argv *, int *, char *);
56 static  int              argv_single(struct mdoc *, int, 
57                                 struct mdoc_argv *, int *, char *);
58 static  int              argv_opt_single(struct mdoc *, int, 
59                                 struct mdoc_argv *, int *, char *);
60 static  int              argv_multi(struct mdoc *, int, 
61                                 struct mdoc_argv *, int *, char *);
62 static  void             argn_free(struct mdoc_arg *, int);
63
64 static  const enum argvflag argvflags[MDOC_ARG_MAX] = {
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
93 static  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 */
216 };
217
218 static  const enum mdocargt args_Ex[] = {
219         MDOC_Std,
220         MDOC_ARG_MAX
221 };
222
223 static  const enum mdocargt args_An[] = {
224         MDOC_Split,
225         MDOC_Nosplit,
226         MDOC_ARG_MAX
227 };
228
229 static  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
241 static  const enum mdocargt args_Bf[] = {
242         MDOC_Emphasis,
243         MDOC_Literal,
244         MDOC_Symbolic,
245         MDOC_ARG_MAX
246 };
247
248 static  const enum mdocargt args_Bk[] = {
249         MDOC_Words,
250         MDOC_ARG_MAX
251 };
252
253 static  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 };
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  */
277 enum margverr
278 mdoc_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
312         memset(&tmp, 0, sizeof(struct mdoc_argv));
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
338         memcpy(&arg->argv[(int)arg->argc - 1], 
339                         &tmp, sizeof(struct mdoc_argv));
340
341         return(ARGV_ARG);
342 }
343
344 void
345 mdoc_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--)
360                 argn_free(p, i);
361
362         free(p->argv);
363         free(p);
364 }
365
366 static void
367 argn_free(struct mdoc_arg *p, int iarg)
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
384 enum margserr
385 mdoc_zargs(struct mdoc *m, int line, int *pos, char *buf, char **v)
386 {
387
388         return(args(m, line, pos, buf, ARGSFL_NONE, v));
389 }
390
391 enum margserr
392 mdoc_args(struct mdoc *m, int line, int *pos, 
393                 char *buf, enum mdoct tok, char **v)
394 {
395         enum argsflag     fl;
396         struct mdoc_node *n;
397
398         fl = argflags[tok];
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)
412                         if (LIST_column == n->norm->Bl.type) {
413                                 fl = ARGSFL_TABSEP;
414                                 break;
415                         }
416
417         return(args(m, line, pos, buf, fl, v));
418 }
419
420 static enum margserr
421 args(struct mdoc *m, int line, int *pos, 
422                 char *buf, enum argsflag fl, char **v)
423 {
424         char            *p, *pp;
425         enum margserr    rc;
426
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)
438                         mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
439
440                 m->flags &= ~MDOC_PHRASELIT;
441                 return(ARGS_EOLN);
442         }
443
444         *v = &buf[*pos];
445
446         if (ARGSFL_DELIM == fl)
447                 if (args_checkpunct(buf, *pos))
448                         return(ARGS_PUNCT);
449
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
457         if (ARGSFL_TABSEP == fl) {
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... */
496                 if ('\0' == *p && ' ' == *(p - 1))
497                         mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
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]) {
539                         if (MDOC_PPHRASE & m->flags)
540                                 return(ARGS_QWORD);
541                         mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
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
554                 if ('\0' == buf[*pos])
555                         mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
556
557                 return(ARGS_QWORD);
558         }
559
560         p = &buf[*pos];
561         *v = mandoc_getarg(m->parse, &p, line, pos);
562
563         return(ARGS_WORD);
564 }
565
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  */
572 static int
573 args_checkpunct(const char *buf, int i)
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
613         return('\0' == buf[i]);
614 }
615
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  */
621 static enum mdocargt
622 argv_a2arg(enum mdoct tok, const char *p)
623 {
624         const enum mdocargt *argsp;
625
626         argsp = NULL;
627
628         switch (tok) {
629         case (MDOC_An):
630                 argsp = args_An;
631                 break;
632         case (MDOC_Bd):
633                 argsp = args_Bd;
634                 break;
635         case (MDOC_Bf):
636                 argsp = args_Bf;
637                 break;
638         case (MDOC_Bk):
639                 argsp = args_Bk;
640                 break;
641         case (MDOC_Bl):
642                 argsp = args_Bl;
643                 break;
644         case (MDOC_Rv):
645                 /* FALLTHROUGH */
646         case (MDOC_Ex):
647                 argsp = args_Ex;
648                 break;
649         default:
650                 return(MDOC_ARG_MAX);
651         }
652
653         assert(argsp);
654
655         for ( ; MDOC_ARG_MAX != *argsp ; argsp++)
656                 if (0 == strcmp(p, mdoc_argnames[*argsp]))
657                         return(*argsp);
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, ARGSFL_NONE, &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, ARGSFL_NONE, &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, ARGSFL_NONE, &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 }