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