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