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