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