Annotation of mandoc/argv.c, Revision 1.41
1.41 ! kristaps 1: /* $Id: argv.c,v 1.40 2009/03/08 12:40:27 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)) {
1.40 kristaps 276: *v = xcalloc(1, sizeof(struct mdoc_arg));
1.39 kristaps 277: arg = *v;
1.40 kristaps 278: }
1.39 kristaps 279:
280: arg->argc++;
281: arg->argv = xrealloc(arg->argv, arg->argc *
1.40 kristaps 282: sizeof(struct mdoc_argv));
1.39 kristaps 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:
1.41 ! kristaps 296: if (NULL == p)
! 297: return;
! 298:
1.40 kristaps 299: if (p->refcnt) {
300: --(p->refcnt);
301: if (p->refcnt)
302: return;
303: }
304:
305: assert(p->argc);
1.39 kristaps 306:
307: /* LINTED */
308: for (i = 0; i < (int)p->argc; i++) {
309: if (0 == p->argv[i].sz)
310: continue;
311: /* LINTED */
312: for (j = 0; j < (int)p->argv[i].sz; j++)
313: free(p->argv[i].value[j]);
1.40 kristaps 314:
1.39 kristaps 315: free(p->argv[i].value);
316: }
317:
1.40 kristaps 318: free(p->argv);
1.39 kristaps 319: free(p);
320: }
321:
322:
323:
1.24 kristaps 324: static int
1.39 kristaps 325: perr(struct mdoc *mdoc, int line, int pos, enum merr code)
1.25 kristaps 326: {
1.39 kristaps 327: char *p;
328:
329: p = NULL;
1.25 kristaps 330:
331: switch (code) {
332: case (EQUOTTERM):
1.39 kristaps 333: p = "unterminated quoted parameter";
1.25 kristaps 334: break;
335: case (EARGVAL):
1.39 kristaps 336: p = "argument requires a value";
1.25 kristaps 337: break;
338: }
1.39 kristaps 339:
340: assert(p);
341: return(mdoc_perr(mdoc, line, pos, p));
1.25 kristaps 342: }
343:
344:
345: static int
1.39 kristaps 346: pwarn(struct mdoc *mdoc, int line, int pos, enum mwarn code)
1.24 kristaps 347: {
1.39 kristaps 348: char *p;
1.24 kristaps 349: int c;
350:
1.39 kristaps 351: p = NULL;
352: c = WARN_SYNTAX;
353:
1.24 kristaps 354: switch (code) {
355: case (WQUOTPARM):
1.39 kristaps 356: p = "unexpected quoted parameter";
1.24 kristaps 357: break;
358: case (WARGVPARM):
1.39 kristaps 359: p = "argument-like parameter";
1.24 kristaps 360: break;
1.25 kristaps 361: case (WCOLEMPTY):
1.39 kristaps 362: p = "last list column is empty";
363: c = WARN_COMPAT;
1.25 kristaps 364: break;
365: case (WTAILWS):
1.39 kristaps 366: p = "trailing whitespace";
367: c = WARN_COMPAT;
1.25 kristaps 368: break;
1.24 kristaps 369: }
1.39 kristaps 370:
371: assert(p);
372: return(mdoc_pwarn(mdoc, line, pos, c, p));
1.24 kristaps 373: }
374:
375:
1.2 kristaps 376: int
1.22 kristaps 377: mdoc_args(struct mdoc *mdoc, int line,
378: int *pos, char *buf, int tok, char **v)
1.1 kristaps 379: {
1.26 kristaps 380: int fl, c, i;
1.22 kristaps 381: struct mdoc_node *n;
382:
1.24 kristaps 383: fl = (0 == tok) ? 0 : mdoc_argflags[tok];
384:
385: /*
1.36 kristaps 386: * Override per-macro argument flags with context-specific ones.
387: * As of now, this is only valid for `It' depending on its list
388: * context.
1.24 kristaps 389: */
390:
1.36 kristaps 391: switch (tok) {
392: case (MDOC_It):
1.24 kristaps 393: for (n = mdoc->last; n; n = n->parent)
1.36 kristaps 394: if (MDOC_BLOCK == n->type && MDOC_Bl == n->tok)
395: break;
396:
1.24 kristaps 397: assert(n);
1.39 kristaps 398: c = (int)(n->args ? n->args->argc : 0);
1.24 kristaps 399: assert(c > 0);
1.26 kristaps 400:
1.36 kristaps 401: /*
402: * Using `Bl -column' adds ARGS_TABSEP to the arguments
403: * and invalidates ARGS_DELIM. Using `Bl -diag' allows
404: * for quoted arguments.
405: */
406:
1.26 kristaps 407: /* LINTED */
1.24 kristaps 408: for (i = 0; i < c; i++) {
1.39 kristaps 409: switch (n->args->argv[i].arg) {
1.35 kristaps 410: case (MDOC_Column):
411: fl |= ARGS_TABSEP;
412: fl &= ~ARGS_DELIM;
413: i = c;
414: break;
415: case (MDOC_Diag):
416: fl |= ARGS_QUOTED;
417: i = c;
418: break;
419: default:
420: break;
421: }
1.24 kristaps 422: }
1.39 kristaps 423: break;
1.36 kristaps 424: default:
425: break;
1.24 kristaps 426: }
427:
1.36 kristaps 428: /* Continue parsing the arguments themselves... */
429:
1.26 kristaps 430: return(args(mdoc, line, pos, buf, fl, v));
431: }
432:
433:
434: static int
435: args(struct mdoc *mdoc, int line,
436: int *pos, char *buf, int fl, char **v)
437: {
1.31 kristaps 438: int i;
1.26 kristaps 439: char *p, *pp;
440:
441: assert(*pos > 0);
442:
443: if (0 == buf[*pos])
444: return(ARGS_EOLN);
445:
446: if ('\"' == buf[*pos] && ! (fl & ARGS_QUOTED))
447: if ( ! pwarn(mdoc, line, *pos, WQUOTPARM))
448: return(ARGS_ERROR);
449:
1.38 kristaps 450: if ( ! (fl & ARGS_ARGVLIKE) && '-' == buf[*pos])
1.26 kristaps 451: if ( ! pwarn(mdoc, line, *pos, WARGVPARM))
452: return(ARGS_ERROR);
453:
1.24 kristaps 454: /*
455: * If the first character is a delimiter and we're to look for
456: * delimited strings, then pass down the buffer seeing if it
457: * follows the pattern of [[::delim::][ ]+]+.
458: */
459:
1.2 kristaps 460: if ((fl & ARGS_DELIM) && mdoc_iscdelim(buf[*pos])) {
1.31 kristaps 461: for (i = *pos; buf[i]; ) {
462: if ( ! mdoc_iscdelim(buf[i]))
1.2 kristaps 463: break;
464: i++;
1.34 kristaps 465: /* There must be at least one space... */
1.37 kristaps 466: if (0 == buf[i] || ! isspace((u_char)buf[i]))
1.34 kristaps 467: break;
468: i++;
1.37 kristaps 469: while (buf[i] && isspace((u_char)buf[i]))
1.2 kristaps 470: i++;
471: }
472: if (0 == buf[i]) {
473: *v = &buf[*pos];
474: return(ARGS_PUNCT);
475: }
476: }
477:
1.24 kristaps 478: /* First parse non-quoted strings. */
1.1 kristaps 479:
1.17 kristaps 480: if ('\"' != buf[*pos] || ! (ARGS_QUOTED & fl)) {
1.1 kristaps 481: *v = &buf[*pos];
482:
1.24 kristaps 483: /*
484: * Thar be dragons here! If we're tab-separated, search
485: * ahead for either a tab or the `Ta' macro. If a tab
486: * is detected, it mustn't be escaped; if a `Ta' is
487: * detected, it must be space-buffered before and after.
488: * If either of these hold true, then prune out the
489: * extra spaces and call it an argument.
490: */
491:
492: if (ARGS_TABSEP & fl) {
493: /* Scan ahead to unescaped tab. */
1.12 kristaps 494:
1.24 kristaps 495: for (p = *v; ; p++) {
496: if (NULL == (p = strchr(p, '\t')))
497: break;
498: if (p == *v)
499: break;
500: if ('\\' != *(p - 1))
1.12 kristaps 501: break;
502: }
1.24 kristaps 503:
504: /* Scan ahead to unescaped `Ta'. */
505:
506: for (pp = *v; ; pp++) {
507: if (NULL == (pp = strstr(pp, "Ta")))
508: break;
509: if (pp > *v && ' ' != *(pp - 1))
510: continue;
511: if (' ' == *(pp + 2) || 0 == *(pp + 2))
512: break;
513: }
514:
515: /* Choose delimiter tab/Ta. */
516:
517: if (p && pp)
518: p = (p < pp ? p : pp);
519: else if ( ! p && pp)
520: p = pp;
521:
522: /* Strip delimiter's preceding whitespace. */
523:
524: if (p && p > *v) {
525: pp = p - 1;
526: while (pp > *v && ' ' == *pp)
527: pp--;
528: if (pp == *v && ' ' == *pp)
529: *pp = 0;
530: else if (' ' == *pp)
531: *(pp + 1) = 0;
532: }
533:
534: /* ...in- and proceding whitespace. */
535:
536: if (p && ('\t' != *p)) {
537: *p++ = 0;
538: *p++ = 0;
539: } else if (p)
540: *p++ = 0;
541:
542: if (p) {
543: while (' ' == *p)
544: p++;
545: if (0 != *p)
546: *(p - 1) = 0;
1.33 kristaps 547: *pos += (int)(p - *v);
1.24 kristaps 548: }
549:
1.25 kristaps 550: if (p && 0 == *p)
551: if ( ! pwarn(mdoc, line, *pos, WCOLEMPTY))
552: return(0);
553: if (p && 0 == *p && p > *v && ' ' == *(p - 1))
554: if ( ! pwarn(mdoc, line, *pos, WTAILWS))
555: return(0);
556:
1.26 kristaps 557: if (p)
558: return(ARGS_WORD);
559:
1.24 kristaps 560: /* Configure the eoln case, too. */
561:
1.26 kristaps 562: p = strchr(*v, 0);
563: assert(p);
564:
565: if (p > *v && ' ' == *(p - 1))
566: if ( ! pwarn(mdoc, line, *pos, WTAILWS))
567: return(0);
1.33 kristaps 568: *pos += (int)(p - *v);
1.24 kristaps 569:
570: return(ARGS_WORD);
571: }
572:
573: /* Do non-tabsep look-ahead here. */
574:
575: if ( ! (ARGS_TABSEP & fl))
1.31 kristaps 576: while (buf[*pos]) {
1.37 kristaps 577: if (isspace((u_char)buf[*pos]))
1.17 kristaps 578: if ('\\' != buf[*pos - 1])
579: break;
1.12 kristaps 580: (*pos)++;
1.17 kristaps 581: }
1.1 kristaps 582:
583: if (0 == buf[*pos])
1.2 kristaps 584: return(ARGS_WORD);
1.1 kristaps 585:
586: buf[(*pos)++] = 0;
1.12 kristaps 587:
1.1 kristaps 588: if (0 == buf[*pos])
1.2 kristaps 589: return(ARGS_WORD);
1.1 kristaps 590:
1.12 kristaps 591: if ( ! (ARGS_TABSEP & fl))
1.37 kristaps 592: while (buf[*pos] && isspace((u_char)buf[*pos]))
1.12 kristaps 593: (*pos)++;
1.1 kristaps 594:
595: if (buf[*pos])
1.2 kristaps 596: return(ARGS_WORD);
1.1 kristaps 597:
1.25 kristaps 598: if ( ! pwarn(mdoc, line, *pos, WTAILWS))
1.2 kristaps 599: return(ARGS_ERROR);
1.1 kristaps 600:
1.2 kristaps 601: return(ARGS_WORD);
602: }
603:
604: /*
605: * If we're a quoted string (and quoted strings are allowed),
606: * then parse ahead to the next quote. If none's found, it's an
1.4 kristaps 607: * error. After, parse to the next word.
1.2 kristaps 608: */
1.1 kristaps 609:
610: *v = &buf[++(*pos)];
611:
612: while (buf[*pos] && '\"' != buf[*pos])
613: (*pos)++;
614:
615: if (0 == buf[*pos]) {
1.25 kristaps 616: (void)perr(mdoc, line, *pos, EQUOTTERM);
1.2 kristaps 617: return(ARGS_ERROR);
1.1 kristaps 618: }
619:
620: buf[(*pos)++] = 0;
621: if (0 == buf[*pos])
1.19 kristaps 622: return(ARGS_QWORD);
1.1 kristaps 623:
1.37 kristaps 624: while (buf[*pos] && isspace((u_char)buf[*pos]))
1.1 kristaps 625: (*pos)++;
626:
627: if (buf[*pos])
1.19 kristaps 628: return(ARGS_QWORD);
1.1 kristaps 629:
1.25 kristaps 630: if ( ! pwarn(mdoc, line, *pos, WTAILWS))
1.2 kristaps 631: return(ARGS_ERROR);
632:
1.19 kristaps 633: return(ARGS_QWORD);
1.1 kristaps 634: }
635:
636:
1.2 kristaps 637: static int
1.30 kristaps 638: argv_a2arg(int tok, const char *argv)
1.1 kristaps 639: {
640:
1.36 kristaps 641: /*
642: * Parse an argument identifier from its text. XXX - this
643: * should really be table-driven to clarify the code.
644: *
645: * If you add an argument to the list, make sure that you
646: * register it here with its one or more macros!
647: */
648:
1.1 kristaps 649: switch (tok) {
1.6 kristaps 650: case (MDOC_An):
651: if (xstrcmp(argv, "split"))
652: return(MDOC_Split);
653: else if (xstrcmp(argv, "nosplit"))
654: return(MDOC_Nosplit);
655: break;
656:
1.2 kristaps 657: case (MDOC_Bd):
1.1 kristaps 658: if (xstrcmp(argv, "ragged"))
659: return(MDOC_Ragged);
660: else if (xstrcmp(argv, "unfilled"))
661: return(MDOC_Unfilled);
1.13 kristaps 662: else if (xstrcmp(argv, "filled"))
663: return(MDOC_Filled);
1.1 kristaps 664: else if (xstrcmp(argv, "literal"))
665: return(MDOC_Literal);
666: else if (xstrcmp(argv, "file"))
667: return(MDOC_File);
668: else if (xstrcmp(argv, "offset"))
669: return(MDOC_Offset);
1.2 kristaps 670: break;
671:
1.8 kristaps 672: case (MDOC_Bf):
673: if (xstrcmp(argv, "emphasis"))
674: return(MDOC_Emphasis);
675: else if (xstrcmp(argv, "literal"))
676: return(MDOC_Literal);
677: else if (xstrcmp(argv, "symbolic"))
678: return(MDOC_Symbolic);
679: break;
680:
1.7 kristaps 681: case (MDOC_Bk):
682: if (xstrcmp(argv, "words"))
683: return(MDOC_Words);
684: break;
685:
1.2 kristaps 686: case (MDOC_Bl):
687: if (xstrcmp(argv, "bullet"))
1.1 kristaps 688: return(MDOC_Bullet);
689: else if (xstrcmp(argv, "dash"))
690: return(MDOC_Dash);
691: else if (xstrcmp(argv, "hyphen"))
692: return(MDOC_Hyphen);
693: else if (xstrcmp(argv, "item"))
694: return(MDOC_Item);
695: else if (xstrcmp(argv, "enum"))
696: return(MDOC_Enum);
697: else if (xstrcmp(argv, "tag"))
698: return(MDOC_Tag);
699: else if (xstrcmp(argv, "diag"))
700: return(MDOC_Diag);
701: else if (xstrcmp(argv, "hang"))
702: return(MDOC_Hang);
703: else if (xstrcmp(argv, "ohang"))
704: return(MDOC_Ohang);
705: else if (xstrcmp(argv, "inset"))
706: return(MDOC_Inset);
707: else if (xstrcmp(argv, "column"))
708: return(MDOC_Column);
709: else if (xstrcmp(argv, "width"))
710: return(MDOC_Width);
1.2 kristaps 711: else if (xstrcmp(argv, "offset"))
712: return(MDOC_Offset);
1.1 kristaps 713: else if (xstrcmp(argv, "compact"))
714: return(MDOC_Compact);
1.2 kristaps 715: break;
1.3 kristaps 716:
717: case (MDOC_Rv):
718: /* FALLTHROUGH */
719: case (MDOC_Ex):
720: if (xstrcmp(argv, "std"))
721: return(MDOC_Std);
722: break;
1.1 kristaps 723: default:
1.8 kristaps 724: break;
1.1 kristaps 725: }
726:
727: return(MDOC_ARG_MAX);
728: }
729:
730:
1.2 kristaps 731: static int
1.26 kristaps 732: argv_multi(struct mdoc *mdoc, int line,
1.39 kristaps 733: struct mdoc_argv *v, int *pos, char *buf)
1.12 kristaps 734: {
735: int c, ppos;
736: char *p;
737:
738: ppos = *pos;
739:
1.39 kristaps 740: for (v->sz = 0; ; v->sz++) {
1.12 kristaps 741: if ('-' == buf[*pos])
742: break;
1.26 kristaps 743: c = args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
1.39 kristaps 744: if (ARGS_ERROR == c)
1.12 kristaps 745: return(0);
1.39 kristaps 746: else if (ARGS_EOLN == c)
1.12 kristaps 747: break;
1.39 kristaps 748:
749: if (0 == v->sz % 5)
750: v->value = xrealloc(v->value,
751: (v->sz + 5) * sizeof(char *));
752:
1.40 kristaps 753: v->value[(int)v->sz] = xstrdup(p);
1.12 kristaps 754: }
755:
1.39 kristaps 756: if (v->sz)
1.12 kristaps 757: return(1);
758:
1.39 kristaps 759: return(perr(mdoc, line, ppos, EARGVAL));
1.12 kristaps 760: }
761:
762:
763: static int
1.36 kristaps 764: argv_opt_single(struct mdoc *mdoc, int line,
1.39 kristaps 765: struct mdoc_argv *v, int *pos, char *buf)
1.36 kristaps 766: {
1.39 kristaps 767: int c;
1.36 kristaps 768: char *p;
769:
770: if ('-' == buf[*pos])
771: return(1);
772:
773: c = args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
774: if (ARGS_ERROR == c)
775: return(0);
776: if (ARGS_EOLN == c)
777: return(1);
778:
779: v->sz = 1;
780: v->value = xcalloc(1, sizeof(char *));
1.40 kristaps 781: v->value[0] = xstrdup(p);
1.36 kristaps 782: return(1);
783: }
784:
785:
786: /*
787: * Parse a single, mandatory value from the stream.
788: */
789: static int
1.26 kristaps 790: argv_single(struct mdoc *mdoc, int line,
1.39 kristaps 791: struct mdoc_argv *v, int *pos, char *buf)
1.1 kristaps 792: {
1.12 kristaps 793: int c, ppos;
1.1 kristaps 794: char *p;
795:
796: ppos = *pos;
797:
1.26 kristaps 798: c = args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
1.12 kristaps 799: if (ARGS_ERROR == c)
800: return(0);
801: if (ARGS_EOLN == c)
1.36 kristaps 802: return(perr(mdoc, line, ppos, EARGVAL));
1.12 kristaps 803:
804: v->sz = 1;
805: v->value = xcalloc(1, sizeof(char *));
1.40 kristaps 806: v->value[0] = xstrdup(p);
1.12 kristaps 807: return(1);
808: }
809:
810:
1.36 kristaps 811: /*
812: * Determine rules for parsing arguments. Arguments can either accept
813: * no parameters, an optional single parameter, one parameter, or
814: * multiple parameters.
815: */
1.12 kristaps 816: static int
1.37 kristaps 817: argv(struct mdoc *mdoc, int tok, int line,
1.39 kristaps 818: struct mdoc_argv *v, int *pos, char *buf)
1.12 kristaps 819: {
1.37 kristaps 820: int fl;
1.12 kristaps 821:
822: v->sz = 0;
823: v->value = NULL;
1.37 kristaps 824: fl = mdoc_argvflags[v->arg];
1.12 kristaps 825:
1.37 kristaps 826: /*
827: * Override the default per-argument value.
828: */
829:
830: switch (tok) {
831: case (MDOC_Ex):
832: fl = ARGV_OPT_SINGLE;
833: break;
834: default:
835: break;
836: }
837:
838: switch (fl) {
1.36 kristaps 839: case (ARGV_SINGLE):
1.26 kristaps 840: return(argv_single(mdoc, line, v, pos, buf));
1.36 kristaps 841: case (ARGV_MULTI):
1.26 kristaps 842: return(argv_multi(mdoc, line, v, pos, buf));
1.36 kristaps 843: case (ARGV_OPT_SINGLE):
844: return(argv_opt_single(mdoc, line, v, pos, buf));
1.1 kristaps 845: default:
1.36 kristaps 846: /* ARGV_NONE */
1.6 kristaps 847: break;
1.1 kristaps 848: }
849:
850: return(1);
851: }
CVSweb