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