]> git.cameronkatri.com Git - mandoc.git/blob - argv.c
Initial block-display support.
[mandoc.git] / argv.c
1 /* $Id: argv.c,v 1.26 2009/01/22 14:56:21 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008 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
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19 #include <assert.h>
20 #include <ctype.h>
21 #include <err.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "private.h"
27
28 /*
29 * Parse arguments and parameters of macros. Arguments follow the
30 * syntax of `-arg [val [valN...]]', while parameters are free-form text
31 * following arguments (if any). This file must correctly handle the
32 * strange punctuation rules dictated by groff.
33 */
34
35 #define ARGS_QUOTED (1 << 0)
36 #define ARGS_DELIM (1 << 1)
37 #define ARGS_TABSEP (1 << 2)
38
39 static int lookup(int, const char *);
40 static int args(struct mdoc *, int, int *,
41 char *, int, char **);
42 static int argv(struct mdoc *, int,
43 struct mdoc_arg *, int *, char *);
44 static int argv_single(struct mdoc *, int,
45 struct mdoc_arg *, int *, char *);
46 static int argv_multi(struct mdoc *, int,
47 struct mdoc_arg *, int *, char *);
48 static int postargv(struct mdoc *, int,
49 const struct mdoc_arg *, int);
50 static int pwarn(struct mdoc *, int, int, int);
51 static int perr(struct mdoc *, int, int, int);
52
53 /* Warning messages. */
54
55 #define WQUOTPARM (0)
56 #define WARGVPARM (1)
57 #define WCOLEMPTY (2)
58 #define WTAILWS (3)
59
60 /* Error messages. */
61
62 #define EQUOTTERM (0)
63 #define EOFFSET (1)
64 #define EARGVAL (2)
65 #define EARGMANY (3)
66
67 static int mdoc_argflags[MDOC_MAX] = {
68 0, /* \" */
69 0, /* Dd */
70 0, /* Dt */
71 0, /* Os */
72 0, /* Sh */
73 0, /* Ss */
74 ARGS_DELIM, /* Pp */
75 ARGS_DELIM, /* D1 */
76 ARGS_DELIM, /* Dl */
77 0, /* Bd */
78 0, /* Ed */
79 0, /* Bl */
80 0, /* El */
81 ARGS_DELIM, /* It */
82 ARGS_DELIM, /* Ad */
83 ARGS_DELIM, /* An */
84 ARGS_DELIM, /* Ar */
85 ARGS_QUOTED, /* Cd */
86 ARGS_DELIM, /* Cm */
87 ARGS_DELIM, /* Dv */
88 ARGS_DELIM, /* Er */
89 ARGS_DELIM, /* Ev */
90 0, /* Ex */
91 ARGS_DELIM | ARGS_QUOTED, /* Fa */
92 0, /* Fd */
93 ARGS_DELIM, /* Fl */
94 ARGS_DELIM | ARGS_QUOTED, /* Fn */
95 ARGS_DELIM | ARGS_QUOTED, /* Ft */
96 ARGS_DELIM, /* Ic */
97 0, /* In */
98 ARGS_DELIM, /* Li */
99 0, /* Nd */
100 ARGS_DELIM, /* Nm */
101 ARGS_DELIM, /* Op */
102 0, /* Ot */
103 ARGS_DELIM, /* Pa */
104 0, /* Rv */
105 ARGS_DELIM, /* St */
106 ARGS_DELIM, /* Va */
107 ARGS_DELIM, /* Vt */
108 ARGS_DELIM, /* Xr */
109 ARGS_QUOTED, /* %A */
110 ARGS_QUOTED, /* %B */
111 ARGS_QUOTED, /* %D */
112 ARGS_QUOTED, /* %I */
113 ARGS_QUOTED, /* %J */
114 ARGS_QUOTED, /* %N */
115 ARGS_QUOTED, /* %O */
116 ARGS_QUOTED, /* %P */
117 ARGS_QUOTED, /* %R */
118 ARGS_QUOTED, /* %T */
119 ARGS_QUOTED, /* %V */
120 ARGS_DELIM, /* Ac */
121 0, /* Ao */
122 ARGS_DELIM, /* Aq */
123 ARGS_DELIM, /* At */
124 ARGS_DELIM, /* Bc */
125 0, /* Bf */
126 0, /* Bo */
127 ARGS_DELIM, /* Bq */
128 ARGS_DELIM, /* Bsx */
129 ARGS_DELIM, /* Bx */
130 0, /* Db */
131 ARGS_DELIM, /* Dc */
132 0, /* Do */
133 ARGS_DELIM, /* Dq */
134 ARGS_DELIM, /* Ec */
135 0, /* Ef */
136 ARGS_DELIM, /* Em */
137 0, /* Eo */
138 ARGS_DELIM, /* Fx */
139 ARGS_DELIM, /* Ms */
140 ARGS_DELIM, /* No */
141 ARGS_DELIM, /* Ns */
142 ARGS_DELIM, /* Nx */
143 ARGS_DELIM, /* Ox */
144 ARGS_DELIM, /* Pc */
145 ARGS_DELIM, /* Pf */
146 0, /* Po */
147 ARGS_DELIM, /* Pq */
148 ARGS_DELIM, /* Qc */
149 ARGS_DELIM, /* Ql */
150 0, /* Qo */
151 ARGS_DELIM, /* Qq */
152 0, /* Re */
153 0, /* Rs */
154 ARGS_DELIM, /* Sc */
155 0, /* So */
156 ARGS_DELIM, /* Sq */
157 0, /* Sm */
158 ARGS_DELIM, /* Sx */
159 ARGS_DELIM, /* Sy */
160 ARGS_DELIM, /* Tn */
161 ARGS_DELIM, /* Ux */
162 ARGS_DELIM, /* Xc */
163 0, /* Xo */
164 0, /* Fo */
165 0, /* Fc */
166 0, /* Oo */
167 ARGS_DELIM, /* Oc */
168 0, /* Bk */
169 0, /* Ek */
170 0, /* Bt */
171 0, /* Hf */
172 0, /* Fr */
173 0, /* Ud */
174 };
175
176
177 static int
178 perr(struct mdoc *mdoc, int line, int pos, int code)
179 {
180 int c;
181
182 switch (code) {
183 case (EQUOTTERM):
184 c = mdoc_perr(mdoc, line, pos,
185 "unterminated quoted parameter");
186 break;
187 case (EOFFSET):
188 c = mdoc_perr(mdoc, line, pos,
189 "invalid value for offset argument");
190 break;
191 case (EARGVAL):
192 c = mdoc_perr(mdoc, line, pos,
193 "argument requires a value");
194 break;
195 case (EARGMANY):
196 c = mdoc_perr(mdoc, line, pos,
197 "too many values for argument");
198 break;
199 default:
200 abort();
201 /* NOTREACHED */
202 }
203 return(c);
204 }
205
206
207 static int
208 pwarn(struct mdoc *mdoc, int line, int pos, int code)
209 {
210 int c;
211
212 switch (code) {
213 case (WQUOTPARM):
214 c = mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
215 "unexpected quoted parameter");
216 break;
217 case (WARGVPARM):
218 c = mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
219 "argument-like parameter");
220 break;
221 case (WCOLEMPTY):
222 c = mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
223 "last list column is empty");
224 break;
225 case (WTAILWS):
226 c = mdoc_pwarn(mdoc, line, pos, WARN_COMPAT,
227 "trailing whitespace");
228 break;
229 default:
230 abort();
231 /* NOTREACHED */
232 }
233 return(c);
234 }
235
236
237 int
238 mdoc_args(struct mdoc *mdoc, int line,
239 int *pos, char *buf, int tok, char **v)
240 {
241 int fl, c, i;
242 struct mdoc_node *n;
243
244 fl = (0 == tok) ? 0 : mdoc_argflags[tok];
245
246 /*
247 * First see if we should use TABSEP (Bl -column). This
248 * invalidates the use of ARGS_DELIM.
249 */
250
251 if (MDOC_It == tok) {
252 for (n = mdoc->last; n; n = n->parent)
253 if (MDOC_BLOCK == n->type)
254 if (MDOC_Bl == n->tok)
255 break;
256 assert(n);
257 c = (int)n->data.block.argc;
258 assert(c > 0);
259
260 /* LINTED */
261 for (i = 0; i < c; i++) {
262 if (MDOC_Column != n->data.block.argv[i].arg)
263 continue;
264 fl |= ARGS_TABSEP;
265 fl &= ~ARGS_DELIM;
266 break;
267 }
268 }
269
270 return(args(mdoc, line, pos, buf, fl, v));
271 }
272
273
274 static int
275 args(struct mdoc *mdoc, int line,
276 int *pos, char *buf, int fl, char **v)
277 {
278 int i, c;
279 char *p, *pp;
280
281 assert(*pos > 0);
282
283 if (0 == buf[*pos])
284 return(ARGS_EOLN);
285
286 if ('\"' == buf[*pos] && ! (fl & ARGS_QUOTED))
287 if ( ! pwarn(mdoc, line, *pos, WQUOTPARM))
288 return(ARGS_ERROR);
289
290 if ('-' == buf[*pos])
291 if ( ! pwarn(mdoc, line, *pos, WARGVPARM))
292 return(ARGS_ERROR);
293
294 /*
295 * If the first character is a delimiter and we're to look for
296 * delimited strings, then pass down the buffer seeing if it
297 * follows the pattern of [[::delim::][ ]+]+.
298 */
299
300 if ((fl & ARGS_DELIM) && mdoc_iscdelim(buf[*pos])) {
301 for (i = *pos; (c = buf[i]); ) {
302 if ( ! mdoc_iscdelim(c))
303 break;
304 i++;
305 if (0 == buf[i] || ! isspace(c))
306 break;
307 i++;
308 while (buf[i] && isspace(c))
309 i++;
310 }
311 if (0 == buf[i]) {
312 *v = &buf[*pos];
313 return(ARGS_PUNCT);
314 }
315 }
316
317 /* First parse non-quoted strings. */
318
319 if ('\"' != buf[*pos] || ! (ARGS_QUOTED & fl)) {
320 *v = &buf[*pos];
321
322 /*
323 * Thar be dragons here! If we're tab-separated, search
324 * ahead for either a tab or the `Ta' macro. If a tab
325 * is detected, it mustn't be escaped; if a `Ta' is
326 * detected, it must be space-buffered before and after.
327 * If either of these hold true, then prune out the
328 * extra spaces and call it an argument.
329 */
330
331 if (ARGS_TABSEP & fl) {
332 /* Scan ahead to unescaped tab. */
333
334 for (p = *v; ; p++) {
335 if (NULL == (p = strchr(p, '\t')))
336 break;
337 if (p == *v)
338 break;
339 if ('\\' != *(p - 1))
340 break;
341 }
342
343 /* Scan ahead to unescaped `Ta'. */
344
345 for (pp = *v; ; pp++) {
346 if (NULL == (pp = strstr(pp, "Ta")))
347 break;
348 if (pp > *v && ' ' != *(pp - 1))
349 continue;
350 if (' ' == *(pp + 2) || 0 == *(pp + 2))
351 break;
352 }
353
354 /* Choose delimiter tab/Ta. */
355
356 if (p && pp)
357 p = (p < pp ? p : pp);
358 else if ( ! p && pp)
359 p = pp;
360
361 /* Strip delimiter's preceding whitespace. */
362
363 if (p && p > *v) {
364 pp = p - 1;
365 while (pp > *v && ' ' == *pp)
366 pp--;
367 if (pp == *v && ' ' == *pp)
368 *pp = 0;
369 else if (' ' == *pp)
370 *(pp + 1) = 0;
371 }
372
373 /* ...in- and proceding whitespace. */
374
375 if (p && ('\t' != *p)) {
376 *p++ = 0;
377 *p++ = 0;
378 } else if (p)
379 *p++ = 0;
380
381 if (p) {
382 while (' ' == *p)
383 p++;
384 if (0 != *p)
385 *(p - 1) = 0;
386 *pos += p - *v;
387 }
388
389 if (p && 0 == *p)
390 if ( ! pwarn(mdoc, line, *pos, WCOLEMPTY))
391 return(0);
392 if (p && 0 == *p && p > *v && ' ' == *(p - 1))
393 if ( ! pwarn(mdoc, line, *pos, WTAILWS))
394 return(0);
395
396 if (p)
397 return(ARGS_WORD);
398
399 /* Configure the eoln case, too. */
400
401 p = strchr(*v, 0);
402 assert(p);
403
404 if (p > *v && ' ' == *(p - 1))
405 if ( ! pwarn(mdoc, line, *pos, WTAILWS))
406 return(0);
407 *pos += p - *v;
408
409 return(ARGS_WORD);
410 }
411
412 /* Do non-tabsep look-ahead here. */
413
414 if ( ! (ARGS_TABSEP & fl))
415 while ((c = buf[*pos])) {
416 if (isspace(c))
417 if ('\\' != buf[*pos - 1])
418 break;
419 (*pos)++;
420 }
421
422 if (0 == buf[*pos])
423 return(ARGS_WORD);
424
425 buf[(*pos)++] = 0;
426
427 if (0 == buf[*pos])
428 return(ARGS_WORD);
429
430 if ( ! (ARGS_TABSEP & fl))
431 while (buf[*pos] && isspace((int)buf[*pos]))
432 (*pos)++;
433
434 if (buf[*pos])
435 return(ARGS_WORD);
436
437 if ( ! pwarn(mdoc, line, *pos, WTAILWS))
438 return(ARGS_ERROR);
439
440 return(ARGS_WORD);
441 }
442
443 /*
444 * If we're a quoted string (and quoted strings are allowed),
445 * then parse ahead to the next quote. If none's found, it's an
446 * error. After, parse to the next word.
447 */
448
449 *v = &buf[++(*pos)];
450
451 while (buf[*pos] && '\"' != buf[*pos])
452 (*pos)++;
453
454 if (0 == buf[*pos]) {
455 (void)perr(mdoc, line, *pos, EQUOTTERM);
456 return(ARGS_ERROR);
457 }
458
459 buf[(*pos)++] = 0;
460 if (0 == buf[*pos])
461 return(ARGS_QWORD);
462
463 while (buf[*pos] && isspace((int)buf[*pos]))
464 (*pos)++;
465
466 if (buf[*pos])
467 return(ARGS_QWORD);
468
469 if ( ! pwarn(mdoc, line, *pos, WTAILWS))
470 return(ARGS_ERROR);
471
472 return(ARGS_QWORD);
473 }
474
475
476 static int
477 lookup(int tok, const char *argv)
478 {
479
480 switch (tok) {
481 case (MDOC_An):
482 if (xstrcmp(argv, "split"))
483 return(MDOC_Split);
484 else if (xstrcmp(argv, "nosplit"))
485 return(MDOC_Nosplit);
486 break;
487
488 case (MDOC_Bd):
489 if (xstrcmp(argv, "ragged"))
490 return(MDOC_Ragged);
491 else if (xstrcmp(argv, "unfilled"))
492 return(MDOC_Unfilled);
493 else if (xstrcmp(argv, "filled"))
494 return(MDOC_Filled);
495 else if (xstrcmp(argv, "literal"))
496 return(MDOC_Literal);
497 else if (xstrcmp(argv, "file"))
498 return(MDOC_File);
499 else if (xstrcmp(argv, "offset"))
500 return(MDOC_Offset);
501 break;
502
503 case (MDOC_Bf):
504 if (xstrcmp(argv, "emphasis"))
505 return(MDOC_Emphasis);
506 else if (xstrcmp(argv, "literal"))
507 return(MDOC_Literal);
508 else if (xstrcmp(argv, "symbolic"))
509 return(MDOC_Symbolic);
510 break;
511
512 case (MDOC_Bk):
513 if (xstrcmp(argv, "words"))
514 return(MDOC_Words);
515 break;
516
517 case (MDOC_Bl):
518 if (xstrcmp(argv, "bullet"))
519 return(MDOC_Bullet);
520 else if (xstrcmp(argv, "dash"))
521 return(MDOC_Dash);
522 else if (xstrcmp(argv, "hyphen"))
523 return(MDOC_Hyphen);
524 else if (xstrcmp(argv, "item"))
525 return(MDOC_Item);
526 else if (xstrcmp(argv, "enum"))
527 return(MDOC_Enum);
528 else if (xstrcmp(argv, "tag"))
529 return(MDOC_Tag);
530 else if (xstrcmp(argv, "diag"))
531 return(MDOC_Diag);
532 else if (xstrcmp(argv, "hang"))
533 return(MDOC_Hang);
534 else if (xstrcmp(argv, "ohang"))
535 return(MDOC_Ohang);
536 else if (xstrcmp(argv, "inset"))
537 return(MDOC_Inset);
538 else if (xstrcmp(argv, "column"))
539 return(MDOC_Column);
540 else if (xstrcmp(argv, "width"))
541 return(MDOC_Width);
542 else if (xstrcmp(argv, "offset"))
543 return(MDOC_Offset);
544 else if (xstrcmp(argv, "compact"))
545 return(MDOC_Compact);
546 break;
547
548 case (MDOC_Rv):
549 /* FALLTHROUGH */
550 case (MDOC_Ex):
551 if (xstrcmp(argv, "std"))
552 return(MDOC_Std);
553 break;
554
555 case (MDOC_St):
556 if (xstrcmp(argv, "p1003.1-88"))
557 return(MDOC_p1003_1_88);
558 else if (xstrcmp(argv, "p1003.1-90"))
559 return(MDOC_p1003_1_90);
560 else if (xstrcmp(argv, "p1003.1-96"))
561 return(MDOC_p1003_1_96);
562 else if (xstrcmp(argv, "p1003.1-2001"))
563 return(MDOC_p1003_1_2001);
564 else if (xstrcmp(argv, "p1003.1-2004"))
565 return(MDOC_p1003_1_2004);
566 else if (xstrcmp(argv, "p1003.1"))
567 return(MDOC_p1003_1);
568 else if (xstrcmp(argv, "p1003.1b"))
569 return(MDOC_p1003_1b);
570 else if (xstrcmp(argv, "p1003.1b-93"))
571 return(MDOC_p1003_1b_93);
572 else if (xstrcmp(argv, "p1003.1c-95"))
573 return(MDOC_p1003_1c_95);
574 else if (xstrcmp(argv, "p1003.1g-2000"))
575 return(MDOC_p1003_1g_2000);
576 else if (xstrcmp(argv, "p1003.2-92"))
577 return(MDOC_p1003_2_92);
578 else if (xstrcmp(argv, "p1003.2-95"))
579 return(MDOC_p1387_2_95);
580 else if (xstrcmp(argv, "p1003.2"))
581 return(MDOC_p1003_2);
582 else if (xstrcmp(argv, "p1387.2-95"))
583 return(MDOC_p1387_2);
584 else if (xstrcmp(argv, "isoC-90"))
585 return(MDOC_isoC_90);
586 else if (xstrcmp(argv, "isoC-amd1"))
587 return(MDOC_isoC_amd1);
588 else if (xstrcmp(argv, "isoC-tcor1"))
589 return(MDOC_isoC_tcor1);
590 else if (xstrcmp(argv, "isoC-tcor2"))
591 return(MDOC_isoC_tcor2);
592 else if (xstrcmp(argv, "isoC-99"))
593 return(MDOC_isoC_99);
594 else if (xstrcmp(argv, "ansiC"))
595 return(MDOC_ansiC);
596 else if (xstrcmp(argv, "ansiC-89"))
597 return(MDOC_ansiC_89);
598 else if (xstrcmp(argv, "ansiC-99"))
599 return(MDOC_ansiC_99);
600 else if (xstrcmp(argv, "ieee754"))
601 return(MDOC_ieee754);
602 else if (xstrcmp(argv, "iso8802-3"))
603 return(MDOC_iso8802_3);
604 else if (xstrcmp(argv, "xpg3"))
605 return(MDOC_xpg3);
606 else if (xstrcmp(argv, "xpg4"))
607 return(MDOC_xpg4);
608 else if (xstrcmp(argv, "xpg4.2"))
609 return(MDOC_xpg4_2);
610 else if (xstrcmp(argv, "xpg4.3"))
611 return(MDOC_xpg4_3);
612 else if (xstrcmp(argv, "xbd5"))
613 return(MDOC_xbd5);
614 else if (xstrcmp(argv, "xcu5"))
615 return(MDOC_xcu5);
616 else if (xstrcmp(argv, "xsh5"))
617 return(MDOC_xsh5);
618 else if (xstrcmp(argv, "xns5"))
619 return(MDOC_xns5);
620 else if (xstrcmp(argv, "xns5.2d2.0"))
621 return(MDOC_xns5_2d2_0);
622 else if (xstrcmp(argv, "xcurses4.2"))
623 return(MDOC_xcurses4_2);
624 else if (xstrcmp(argv, "susv2"))
625 return(MDOC_susv2);
626 else if (xstrcmp(argv, "susv3"))
627 return(MDOC_susv3);
628 else if (xstrcmp(argv, "svid4"))
629 return(MDOC_svid4);
630 break;
631
632 default:
633 break;
634 }
635
636 return(MDOC_ARG_MAX);
637 }
638
639
640 static int
641 postargv(struct mdoc *mdoc, int line, const struct mdoc_arg *v, int pos)
642 {
643
644 switch (v->arg) {
645 case (MDOC_Offset):
646 assert(v->value);
647 assert(v->value[0]);
648 if (xstrcmp(v->value[0], "left"))
649 break;
650 if (xstrcmp(v->value[0], "right"))
651 break;
652 if (xstrcmp(v->value[0], "center"))
653 break;
654 if (xstrcmp(v->value[0], "indent"))
655 break;
656 if (xstrcmp(v->value[0], "indent-two"))
657 break;
658 return(perr(mdoc, line, pos, EOFFSET));
659 default:
660 break;
661 }
662
663 return(1);
664 }
665
666
667 static int
668 argv_multi(struct mdoc *mdoc, int line,
669 struct mdoc_arg *v, int *pos, char *buf)
670 {
671 int c, ppos;
672 char *p;
673
674 v->sz = 0;
675 v->value = xcalloc(MDOC_LINEARG_MAX, sizeof(char *));
676
677 ppos = *pos;
678
679 for (v->sz = 0; v->sz < MDOC_LINEARG_MAX; v->sz++) {
680 if ('-' == buf[*pos])
681 break;
682 c = args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
683 if (ARGS_ERROR == c) {
684 free(v->value);
685 return(0);
686 } else if (ARGS_EOLN == c)
687 break;
688 v->value[v->sz] = p;
689 }
690
691 if (0 < v->sz && v->sz < MDOC_LINEARG_MAX)
692 return(1);
693
694 free(v->value);
695 if (0 == v->sz)
696 return(perr(mdoc, line, ppos, EARGVAL));
697
698 return(perr(mdoc, line, ppos, EARGMANY));
699 }
700
701
702 static int
703 argv_single(struct mdoc *mdoc, int line,
704 struct mdoc_arg *v, int *pos, char *buf)
705 {
706 int c, ppos;
707 char *p;
708
709 ppos = *pos;
710
711 c = args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
712 if (ARGS_ERROR == c)
713 return(0);
714 if (ARGS_EOLN == c)
715 return(perr(mdoc, line, ppos, EARGVAL));
716
717 v->sz = 1;
718 v->value = xcalloc(1, sizeof(char *));
719 v->value[0] = p;
720 return(1);
721 }
722
723
724 static int
725 argv(struct mdoc *mdoc, int line,
726 struct mdoc_arg *v, int *pos, char *buf)
727 {
728
729 v->sz = 0;
730 v->value = NULL;
731
732 switch (v->arg) {
733 case(MDOC_Std):
734 /* FALLTHROUGH */
735 case(MDOC_Width):
736 /* FALLTHROUGH */
737 case(MDOC_Offset):
738 return(argv_single(mdoc, line, v, pos, buf));
739 case(MDOC_Column):
740 return(argv_multi(mdoc, line, v, pos, buf));
741 default:
742 break;
743 }
744
745 return(1);
746 }
747
748
749 int
750 mdoc_argv(struct mdoc *mdoc, int line, int tok,
751 struct mdoc_arg *v, int *pos, char *buf)
752 {
753 int i, ppos;
754 char *p;
755
756 (void)memset(v, 0, sizeof(struct mdoc_arg));
757
758 if (0 == buf[*pos])
759 return(ARGV_EOLN);
760
761 assert( ! isspace((int)buf[*pos]));
762
763 if ('-' != buf[*pos])
764 return(ARGV_WORD);
765
766 i = *pos;
767 p = &buf[++(*pos)];
768
769 v->line = line;
770 v->pos = *pos;
771
772 assert(*pos > 0);
773
774 /* LINTED */
775 while (buf[*pos]) {
776 if (isspace((int)buf[*pos]))
777 if ('\\' != buf[*pos - 1])
778 break;
779 (*pos)++;
780 }
781
782 if (buf[*pos])
783 buf[(*pos)++] = 0;
784
785 if (MDOC_ARG_MAX == (v->arg = lookup(tok, p))) {
786 if ( ! pwarn(mdoc, line, i, WARGVPARM))
787 return(ARGV_ERROR);
788 return(ARGV_WORD);
789 }
790
791 while (buf[*pos] && isspace((int)buf[*pos]))
792 (*pos)++;
793
794 /* FIXME: whitespace if no value. */
795
796 ppos = *pos;
797 if ( ! argv(mdoc, line, v, pos, buf))
798 return(ARGV_ERROR);
799 if ( ! postargv(mdoc, line, v, ppos))
800 return(ARGV_ERROR);
801
802 return(ARGV_ARG);
803 }
804
805
806 void
807 mdoc_argv_free(int sz, struct mdoc_arg *arg)
808 {
809 int i;
810
811 for (i = 0; i < sz; i++) {
812 if (0 == arg[i].sz) {
813 assert(NULL == arg[i].value);
814 continue;
815 }
816 assert(arg[i].value);
817 free(arg[i].value);
818 }
819 }
820