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