Annotation of src/usr.bin/mandoc/mdoc_argv.c, Revision 1.38
1.38 ! schwarze 1: /* $Id: mdoc_argv.c,v 1.37 2011/04/24 16:22:02 schwarze Exp $ */
1.1 kristaps 2: /*
1.36 schwarze 3: * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.2 schwarze 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.2 schwarze 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 16: */
17: #include <sys/types.h>
18:
19: #include <assert.h>
20: #include <ctype.h>
21: #include <stdlib.h>
22: #include <stdio.h>
23: #include <string.h>
24:
1.37 schwarze 25: #include "mdoc.h"
1.29 schwarze 26: #include "mandoc.h"
1.1 kristaps 27: #include "libmdoc.h"
1.19 schwarze 28: #include "libmandoc.h"
1.1 kristaps 29:
1.36 schwarze 30: #define MULTI_STEP 5 /* pre-allocate argument values */
1.38 ! schwarze 31: #define DELIMSZ 6 /* max possible size of a delimiter */
! 32:
! 33: enum argsflag {
! 34: ARGSFL_NONE = 0,
! 35: ARGSFL_DELIM, /* handle delimiters of [[::delim::][ ]+]+ */
! 36: ARGSFL_TABSEP /* handle tab/`Ta' separated phrases */
! 37: };
! 38:
! 39: enum argvflag {
! 40: ARGV_NONE, /* no args to flag (e.g., -split) */
! 41: ARGV_SINGLE, /* one arg to flag (e.g., -file xxx) */
! 42: ARGV_MULTI, /* multiple args (e.g., -column xxx yyy) */
! 43: ARGV_OPT_SINGLE /* optional arg (e.g., -offset [xxx]) */
! 44: };
1.1 kristaps 45:
1.33 schwarze 46: static enum mdocargt argv_a2arg(enum mdoct, const char *);
1.24 schwarze 47: static enum margserr args(struct mdoc *, int, int *,
1.38 ! schwarze 48: char *, enum argsflag, char **);
! 49: static int args_checkpunct(const char *, int);
1.1 kristaps 50: static int argv(struct mdoc *, int,
51: struct mdoc_argv *, int *, char *);
52: static int argv_single(struct mdoc *, int,
53: struct mdoc_argv *, int *, char *);
54: static int argv_opt_single(struct mdoc *, int,
55: struct mdoc_argv *, int *, char *);
56: static int argv_multi(struct mdoc *, int,
57: struct mdoc_argv *, int *, char *);
1.37 schwarze 58: static void argn_free(struct mdoc_arg *, int);
1.1 kristaps 59:
1.36 schwarze 60: static const enum argvflag argvflags[MDOC_ARG_MAX] = {
1.1 kristaps 61: ARGV_NONE, /* MDOC_Split */
62: ARGV_NONE, /* MDOC_Nosplit */
63: ARGV_NONE, /* MDOC_Ragged */
64: ARGV_NONE, /* MDOC_Unfilled */
65: ARGV_NONE, /* MDOC_Literal */
1.17 schwarze 66: ARGV_SINGLE, /* MDOC_File */
1.15 schwarze 67: ARGV_OPT_SINGLE, /* MDOC_Offset */
1.1 kristaps 68: ARGV_NONE, /* MDOC_Bullet */
69: ARGV_NONE, /* MDOC_Dash */
70: ARGV_NONE, /* MDOC_Hyphen */
71: ARGV_NONE, /* MDOC_Item */
72: ARGV_NONE, /* MDOC_Enum */
73: ARGV_NONE, /* MDOC_Tag */
74: ARGV_NONE, /* MDOC_Diag */
75: ARGV_NONE, /* MDOC_Hang */
76: ARGV_NONE, /* MDOC_Ohang */
77: ARGV_NONE, /* MDOC_Inset */
78: ARGV_MULTI, /* MDOC_Column */
79: ARGV_SINGLE, /* MDOC_Width */
80: ARGV_NONE, /* MDOC_Compact */
1.14 schwarze 81: ARGV_NONE, /* MDOC_Std */
1.1 kristaps 82: ARGV_NONE, /* MDOC_Filled */
83: ARGV_NONE, /* MDOC_Words */
84: ARGV_NONE, /* MDOC_Emphasis */
85: ARGV_NONE, /* MDOC_Symbolic */
86: ARGV_NONE /* MDOC_Symbolic */
87: };
88:
1.38 ! schwarze 89: static const enum argsflag argflags[MDOC_MAX] = {
! 90: ARGSFL_NONE, /* Ap */
! 91: ARGSFL_NONE, /* Dd */
! 92: ARGSFL_NONE, /* Dt */
! 93: ARGSFL_NONE, /* Os */
! 94: ARGSFL_NONE, /* Sh */
! 95: ARGSFL_NONE, /* Ss */
! 96: ARGSFL_NONE, /* Pp */
! 97: ARGSFL_DELIM, /* D1 */
! 98: ARGSFL_DELIM, /* Dl */
! 99: ARGSFL_NONE, /* Bd */
! 100: ARGSFL_NONE, /* Ed */
! 101: ARGSFL_NONE, /* Bl */
! 102: ARGSFL_NONE, /* El */
! 103: ARGSFL_NONE, /* It */
! 104: ARGSFL_DELIM, /* Ad */
! 105: ARGSFL_DELIM, /* An */
! 106: ARGSFL_DELIM, /* Ar */
! 107: ARGSFL_NONE, /* Cd */
! 108: ARGSFL_DELIM, /* Cm */
! 109: ARGSFL_DELIM, /* Dv */
! 110: ARGSFL_DELIM, /* Er */
! 111: ARGSFL_DELIM, /* Ev */
! 112: ARGSFL_NONE, /* Ex */
! 113: ARGSFL_DELIM, /* Fa */
! 114: ARGSFL_NONE, /* Fd */
! 115: ARGSFL_DELIM, /* Fl */
! 116: ARGSFL_DELIM, /* Fn */
! 117: ARGSFL_DELIM, /* Ft */
! 118: ARGSFL_DELIM, /* Ic */
! 119: ARGSFL_NONE, /* In */
! 120: ARGSFL_DELIM, /* Li */
! 121: ARGSFL_NONE, /* Nd */
! 122: ARGSFL_DELIM, /* Nm */
! 123: ARGSFL_DELIM, /* Op */
! 124: ARGSFL_NONE, /* Ot */
! 125: ARGSFL_DELIM, /* Pa */
! 126: ARGSFL_NONE, /* Rv */
! 127: ARGSFL_DELIM, /* St */
! 128: ARGSFL_DELIM, /* Va */
! 129: ARGSFL_DELIM, /* Vt */
! 130: ARGSFL_DELIM, /* Xr */
! 131: ARGSFL_NONE, /* %A */
! 132: ARGSFL_NONE, /* %B */
! 133: ARGSFL_NONE, /* %D */
! 134: ARGSFL_NONE, /* %I */
! 135: ARGSFL_NONE, /* %J */
! 136: ARGSFL_NONE, /* %N */
! 137: ARGSFL_NONE, /* %O */
! 138: ARGSFL_NONE, /* %P */
! 139: ARGSFL_NONE, /* %R */
! 140: ARGSFL_NONE, /* %T */
! 141: ARGSFL_NONE, /* %V */
! 142: ARGSFL_DELIM, /* Ac */
! 143: ARGSFL_NONE, /* Ao */
! 144: ARGSFL_DELIM, /* Aq */
! 145: ARGSFL_DELIM, /* At */
! 146: ARGSFL_DELIM, /* Bc */
! 147: ARGSFL_NONE, /* Bf */
! 148: ARGSFL_NONE, /* Bo */
! 149: ARGSFL_DELIM, /* Bq */
! 150: ARGSFL_DELIM, /* Bsx */
! 151: ARGSFL_DELIM, /* Bx */
! 152: ARGSFL_NONE, /* Db */
! 153: ARGSFL_DELIM, /* Dc */
! 154: ARGSFL_NONE, /* Do */
! 155: ARGSFL_DELIM, /* Dq */
! 156: ARGSFL_DELIM, /* Ec */
! 157: ARGSFL_NONE, /* Ef */
! 158: ARGSFL_DELIM, /* Em */
! 159: ARGSFL_NONE, /* Eo */
! 160: ARGSFL_DELIM, /* Fx */
! 161: ARGSFL_DELIM, /* Ms */
! 162: ARGSFL_DELIM, /* No */
! 163: ARGSFL_DELIM, /* Ns */
! 164: ARGSFL_DELIM, /* Nx */
! 165: ARGSFL_DELIM, /* Ox */
! 166: ARGSFL_DELIM, /* Pc */
! 167: ARGSFL_DELIM, /* Pf */
! 168: ARGSFL_NONE, /* Po */
! 169: ARGSFL_DELIM, /* Pq */
! 170: ARGSFL_DELIM, /* Qc */
! 171: ARGSFL_DELIM, /* Ql */
! 172: ARGSFL_NONE, /* Qo */
! 173: ARGSFL_DELIM, /* Qq */
! 174: ARGSFL_NONE, /* Re */
! 175: ARGSFL_NONE, /* Rs */
! 176: ARGSFL_DELIM, /* Sc */
! 177: ARGSFL_NONE, /* So */
! 178: ARGSFL_DELIM, /* Sq */
! 179: ARGSFL_NONE, /* Sm */
! 180: ARGSFL_DELIM, /* Sx */
! 181: ARGSFL_DELIM, /* Sy */
! 182: ARGSFL_DELIM, /* Tn */
! 183: ARGSFL_DELIM, /* Ux */
! 184: ARGSFL_DELIM, /* Xc */
! 185: ARGSFL_NONE, /* Xo */
! 186: ARGSFL_NONE, /* Fo */
! 187: ARGSFL_NONE, /* Fc */
! 188: ARGSFL_NONE, /* Oo */
! 189: ARGSFL_DELIM, /* Oc */
! 190: ARGSFL_NONE, /* Bk */
! 191: ARGSFL_NONE, /* Ek */
! 192: ARGSFL_NONE, /* Bt */
! 193: ARGSFL_NONE, /* Hf */
! 194: ARGSFL_NONE, /* Fr */
! 195: ARGSFL_NONE, /* Ud */
! 196: ARGSFL_NONE, /* Lb */
! 197: ARGSFL_NONE, /* Lp */
! 198: ARGSFL_DELIM, /* Lk */
! 199: ARGSFL_DELIM, /* Mt */
! 200: ARGSFL_DELIM, /* Brq */
! 201: ARGSFL_NONE, /* Bro */
! 202: ARGSFL_DELIM, /* Brc */
! 203: ARGSFL_NONE, /* %C */
! 204: ARGSFL_NONE, /* Es */
! 205: ARGSFL_NONE, /* En */
! 206: ARGSFL_NONE, /* Dx */
! 207: ARGSFL_NONE, /* %Q */
! 208: ARGSFL_NONE, /* br */
! 209: ARGSFL_NONE, /* sp */
! 210: ARGSFL_NONE, /* %U */
! 211: ARGSFL_NONE, /* Ta */
1.1 kristaps 212: };
213:
1.37 schwarze 214: static const enum mdocargt args_Ex[] = {
215: MDOC_Std,
216: MDOC_ARG_MAX
217: };
218:
219: static const enum mdocargt args_An[] = {
220: MDOC_Split,
221: MDOC_Nosplit,
222: MDOC_ARG_MAX
223: };
224:
225: static const enum mdocargt args_Bd[] = {
226: MDOC_Ragged,
227: MDOC_Unfilled,
228: MDOC_Filled,
229: MDOC_Literal,
230: MDOC_File,
231: MDOC_Offset,
232: MDOC_Compact,
233: MDOC_Centred,
234: MDOC_ARG_MAX
235: };
236:
237: static const enum mdocargt args_Bf[] = {
238: MDOC_Emphasis,
239: MDOC_Literal,
240: MDOC_Symbolic,
241: MDOC_ARG_MAX
242: };
243:
244: static const enum mdocargt args_Bk[] = {
245: MDOC_Words,
246: MDOC_ARG_MAX
247: };
248:
249: static const enum mdocargt args_Bl[] = {
250: MDOC_Bullet,
251: MDOC_Dash,
252: MDOC_Hyphen,
253: MDOC_Item,
254: MDOC_Enum,
255: MDOC_Tag,
256: MDOC_Diag,
257: MDOC_Hang,
258: MDOC_Ohang,
259: MDOC_Inset,
260: MDOC_Column,
261: MDOC_Width,
262: MDOC_Offset,
263: MDOC_Compact,
264: MDOC_Nested,
265: MDOC_ARG_MAX
266: };
267:
1.1 kristaps 268: /*
269: * Parse an argument from line text. This comes in the form of -key
270: * [value0...], which may either have a single mandatory value, at least
271: * one mandatory value, an optional single value, or no value.
272: */
1.24 schwarze 273: enum margverr
1.22 schwarze 274: mdoc_argv(struct mdoc *m, int line, enum mdoct tok,
1.1 kristaps 275: struct mdoc_arg **v, int *pos, char *buf)
276: {
277: char *p, sv;
278: struct mdoc_argv tmp;
279: struct mdoc_arg *arg;
280:
1.30 schwarze 281: if ('\0' == buf[*pos])
1.1 kristaps 282: return(ARGV_EOLN);
283:
284: assert(' ' != buf[*pos]);
285:
286: /* Parse through to the first unescaped space. */
287:
288: p = &buf[++(*pos)];
289:
290: assert(*pos > 0);
291:
292: /* LINTED */
293: while (buf[*pos]) {
294: if (' ' == buf[*pos])
295: if ('\\' != buf[*pos - 1])
296: break;
297: (*pos)++;
298: }
299:
300: /* XXX - save zeroed byte, if not an argument. */
301:
1.30 schwarze 302: sv = '\0';
1.1 kristaps 303: if (buf[*pos]) {
304: sv = buf[*pos];
1.30 schwarze 305: buf[(*pos)++] = '\0';
1.1 kristaps 306: }
307:
1.36 schwarze 308: memset(&tmp, 0, sizeof(struct mdoc_argv));
1.1 kristaps 309: tmp.line = line;
310: tmp.pos = *pos;
311:
312: /* See if our token accepts the argument. */
313:
314: if (MDOC_ARG_MAX == (tmp.arg = argv_a2arg(tok, p))) {
315: /* XXX - restore saved zeroed byte. */
316: if (sv)
317: buf[*pos - 1] = sv;
318: return(ARGV_WORD);
319: }
320:
321: while (buf[*pos] && ' ' == buf[*pos])
322: (*pos)++;
323:
1.6 schwarze 324: if ( ! argv(m, line, &tmp, pos, buf))
1.1 kristaps 325: return(ARGV_ERROR);
326:
1.19 schwarze 327: if (NULL == (arg = *v))
328: arg = *v = mandoc_calloc(1, sizeof(struct mdoc_arg));
1.1 kristaps 329:
330: arg->argc++;
1.19 schwarze 331: arg->argv = mandoc_realloc
332: (arg->argv, arg->argc * sizeof(struct mdoc_argv));
1.1 kristaps 333:
1.36 schwarze 334: memcpy(&arg->argv[(int)arg->argc - 1],
1.1 kristaps 335: &tmp, sizeof(struct mdoc_argv));
336:
337: return(ARGV_ARG);
338: }
339:
340: void
341: mdoc_argv_free(struct mdoc_arg *p)
342: {
1.23 schwarze 343: int i;
1.1 kristaps 344:
345: if (NULL == p)
346: return;
347:
348: if (p->refcnt) {
349: --(p->refcnt);
350: if (p->refcnt)
351: return;
352: }
353: assert(p->argc);
354:
1.24 schwarze 355: for (i = (int)p->argc - 1; i >= 0; i--)
1.37 schwarze 356: argn_free(p, i);
1.23 schwarze 357:
358: free(p->argv);
359: free(p);
360: }
361:
1.37 schwarze 362: static void
363: argn_free(struct mdoc_arg *p, int iarg)
1.23 schwarze 364: {
1.33 schwarze 365: struct mdoc_argv *arg;
1.23 schwarze 366: int j;
1.1 kristaps 367:
1.33 schwarze 368: arg = &p->argv[iarg];
369:
1.23 schwarze 370: if (arg->sz && arg->value) {
1.24 schwarze 371: for (j = (int)arg->sz - 1; j >= 0; j--)
1.23 schwarze 372: free(arg->value[j]);
373: free(arg->value);
1.1 kristaps 374: }
375:
1.23 schwarze 376: for (--p->argc; iarg < (int)p->argc; iarg++)
377: p->argv[iarg] = p->argv[iarg+1];
1.1 kristaps 378: }
379:
1.24 schwarze 380: enum margserr
1.38 ! schwarze 381: mdoc_zargs(struct mdoc *m, int line, int *pos, char *buf, char **v)
1.12 schwarze 382: {
383:
1.38 ! schwarze 384: return(args(m, line, pos, buf, ARGSFL_NONE, v));
1.12 schwarze 385: }
386:
1.24 schwarze 387: enum margserr
1.22 schwarze 388: mdoc_args(struct mdoc *m, int line, int *pos,
389: char *buf, enum mdoct tok, char **v)
1.1 kristaps 390: {
1.38 ! schwarze 391: enum argsflag fl;
1.1 kristaps 392: struct mdoc_node *n;
393:
1.36 schwarze 394: fl = argflags[tok];
1.1 kristaps 395:
1.12 schwarze 396: if (MDOC_It != tok)
397: return(args(m, line, pos, buf, fl, v));
398:
1.30 schwarze 399: /*
400: * We know that we're in an `It', so it's reasonable to expect
401: * us to be sitting in a `Bl'. Someday this may not be the case
402: * (if we allow random `It's sitting out there), so provide a
403: * safe fall-back into the default behaviour.
1.1 kristaps 404: */
405:
1.12 schwarze 406: for (n = m->last; n; n = n->parent)
1.30 schwarze 407: if (MDOC_Bl == n->tok)
1.38 ! schwarze 408: if (LIST_column == n->norm->Bl.type) {
! 409: fl = ARGSFL_TABSEP;
! 410: break;
! 411: }
1.1 kristaps 412:
1.8 schwarze 413: return(args(m, line, pos, buf, fl, v));
1.1 kristaps 414: }
415:
1.24 schwarze 416: static enum margserr
1.12 schwarze 417: args(struct mdoc *m, int line, int *pos,
1.38 ! schwarze 418: char *buf, enum argsflag fl, char **v)
1.1 kristaps 419: {
1.30 schwarze 420: char *p, *pp;
421: enum margserr rc;
1.1 kristaps 422:
1.12 schwarze 423: assert(' ' != buf[*pos]);
1.1 kristaps 424:
1.28 schwarze 425: if ('\0' == buf[*pos]) {
426: if (MDOC_PPHRASE & m->flags)
427: return(ARGS_EOLN);
428: /*
429: * If we're not in a partial phrase and the flag for
430: * being a phrase literal is still set, the punctuation
431: * is unterminated.
432: */
433: if (MDOC_PHRASELIT & m->flags)
1.36 schwarze 434: mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
1.28 schwarze 435:
436: m->flags &= ~MDOC_PHRASELIT;
1.1 kristaps 437: return(ARGS_EOLN);
1.28 schwarze 438: }
1.1 kristaps 439:
1.36 schwarze 440: *v = &buf[*pos];
1.1 kristaps 441:
1.38 ! schwarze 442: if (ARGSFL_DELIM == fl)
! 443: if (args_checkpunct(buf, *pos))
1.36 schwarze 444: return(ARGS_PUNCT);
1.1 kristaps 445:
1.12 schwarze 446: /*
447: * First handle TABSEP items, restricted to `Bl -column'. This
448: * ignores conventional token parsing and instead uses tabs or
449: * `Ta' macros to separate phrases. Phrases are parsed again
450: * for arguments at a later phase.
451: */
452:
1.38 ! schwarze 453: if (ARGSFL_TABSEP == fl) {
1.12 schwarze 454: /* Scan ahead to tab (can't be escaped). */
455: p = strchr(*v, '\t');
1.28 schwarze 456: pp = NULL;
1.12 schwarze 457:
458: /* Scan ahead to unescaped `Ta'. */
1.28 schwarze 459: if ( ! (MDOC_PHRASELIT & m->flags))
460: for (pp = *v; ; pp++) {
461: if (NULL == (pp = strstr(pp, "Ta")))
462: break;
463: if (pp > *v && ' ' != *(pp - 1))
464: continue;
1.30 schwarze 465: if (' ' == *(pp + 2) || '\0' == *(pp + 2))
1.28 schwarze 466: break;
467: }
1.1 kristaps 468:
1.24 schwarze 469: /* By default, assume a phrase. */
470: rc = ARGS_PHRASE;
471:
1.1 kristaps 472: /*
1.12 schwarze 473: * Adjust new-buffer position to be beyond delimiter
474: * mark (e.g., Ta -> end + 2).
1.1 kristaps 475: */
1.12 schwarze 476: if (p && pp) {
477: *pos += pp < p ? 2 : 1;
1.24 schwarze 478: rc = pp < p ? ARGS_PHRASE : ARGS_PPHRASE;
1.12 schwarze 479: p = pp < p ? pp : p;
480: } else if (p && ! pp) {
1.24 schwarze 481: rc = ARGS_PPHRASE;
1.12 schwarze 482: *pos += 1;
483: } else if (pp && ! p) {
484: p = pp;
485: *pos += 2;
1.25 schwarze 486: } else {
487: rc = ARGS_PEND;
1.12 schwarze 488: p = strchr(*v, 0);
1.25 schwarze 489: }
1.1 kristaps 490:
1.12 schwarze 491: /* Whitespace check for eoln case... */
1.38 ! schwarze 492: if ('\0' == *p && ' ' == *(p - 1))
1.36 schwarze 493: mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
1.12 schwarze 494:
495: *pos += (int)(p - *v);
496:
497: /* Strip delimiter's preceding whitespace. */
498: pp = p - 1;
499: while (pp > *v && ' ' == *pp) {
500: if (pp > *v && '\\' == *(pp - 1))
501: break;
502: pp--;
503: }
504: *(pp + 1) = 0;
1.1 kristaps 505:
1.12 schwarze 506: /* Strip delimiter's proceeding whitespace. */
507: for (pp = &buf[*pos]; ' ' == *pp; pp++, (*pos)++)
508: /* Skip ahead. */ ;
1.1 kristaps 509:
1.24 schwarze 510: return(rc);
1.12 schwarze 511: }
1.1 kristaps 512:
1.12 schwarze 513: /*
514: * Process a quoted literal. A quote begins with a double-quote
515: * and ends with a double-quote NOT preceded by a double-quote.
516: * Whitespace is NOT involved in literal termination.
517: */
1.1 kristaps 518:
1.28 schwarze 519: if (MDOC_PHRASELIT & m->flags || '\"' == buf[*pos]) {
520: if ( ! (MDOC_PHRASELIT & m->flags))
521: *v = &buf[++(*pos)];
522:
523: if (MDOC_PPHRASE & m->flags)
524: m->flags |= MDOC_PHRASELIT;
1.1 kristaps 525:
1.12 schwarze 526: for ( ; buf[*pos]; (*pos)++) {
527: if ('\"' != buf[*pos])
528: continue;
529: if ('\"' != buf[*pos + 1])
530: break;
531: (*pos)++;
532: }
1.1 kristaps 533:
1.28 schwarze 534: if ('\0' == buf[*pos]) {
1.38 ! schwarze 535: if (MDOC_PPHRASE & m->flags)
1.13 schwarze 536: return(ARGS_QWORD);
1.36 schwarze 537: mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
1.12 schwarze 538: return(ARGS_QWORD);
539: }
1.1 kristaps 540:
1.28 schwarze 541: m->flags &= ~MDOC_PHRASELIT;
542: buf[(*pos)++] = '\0';
1.1 kristaps 543:
1.28 schwarze 544: if ('\0' == buf[*pos])
1.12 schwarze 545: return(ARGS_QWORD);
1.1 kristaps 546:
1.12 schwarze 547: while (' ' == buf[*pos])
548: (*pos)++;
1.1 kristaps 549:
1.38 ! schwarze 550: if ('\0' == buf[*pos])
1.36 schwarze 551: mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
1.1 kristaps 552:
1.12 schwarze 553: return(ARGS_QWORD);
1.1 kristaps 554: }
555:
1.38 ! schwarze 556: p = &buf[*pos];
! 557: *v = mandoc_getarg(m->parse, &p, line, pos);
1.1 kristaps 558:
1.12 schwarze 559: return(ARGS_WORD);
1.1 kristaps 560: }
561:
1.36 schwarze 562: /*
563: * Check if the string consists only of space-separated closing
564: * delimiters. This is a bit of a dance: the first must be a close
565: * delimiter, but it may be followed by middle delimiters. Arbitrary
566: * whitespace may separate these tokens.
567: */
568: static int
1.38 ! schwarze 569: args_checkpunct(const char *buf, int i)
1.36 schwarze 570: {
1.38 ! schwarze 571: int j;
! 572: char dbuf[DELIMSZ];
1.36 schwarze 573: enum mdelim d;
574:
575: /* First token must be a close-delimiter. */
576:
1.38 ! schwarze 577: for (j = 0; buf[i] && ' ' != buf[i] && j < DELIMSZ; j++, i++)
! 578: dbuf[j] = buf[i];
1.1 kristaps 579:
1.36 schwarze 580: if (DELIMSZ == j)
581: return(0);
582:
1.38 ! schwarze 583: dbuf[j] = '\0';
! 584: if (DELIM_CLOSE != mdoc_isdelim(dbuf))
1.36 schwarze 585: return(0);
586:
1.38 ! schwarze 587: while (' ' == buf[i])
1.36 schwarze 588: i++;
589:
590: /* Remaining must NOT be open/none. */
591:
1.38 ! schwarze 592: while (buf[i]) {
1.36 schwarze 593: j = 0;
1.38 ! schwarze 594: while (buf[i] && ' ' != buf[i] && j < DELIMSZ)
! 595: dbuf[j++] = buf[i++];
1.36 schwarze 596:
597: if (DELIMSZ == j)
598: return(0);
599:
1.38 ! schwarze 600: dbuf[j] = '\0';
! 601: d = mdoc_isdelim(dbuf);
1.36 schwarze 602: if (DELIM_NONE == d || DELIM_OPEN == d)
603: return(0);
604:
1.38 ! schwarze 605: while (' ' == buf[i])
1.36 schwarze 606: i++;
607: }
608:
1.38 ! schwarze 609: return('\0' == buf[i]);
1.36 schwarze 610: }
611:
612: /*
613: * Match up an argument string (e.g., `-foo bar' having "foo") with the
1.37 schwarze 614: * correct identifier. It must apply to the given macro. If none was
1.36 schwarze 615: * found (including bad matches), return MDOC_ARG_MAX.
616: */
1.33 schwarze 617: static enum mdocargt
1.22 schwarze 618: argv_a2arg(enum mdoct tok, const char *p)
1.1 kristaps 619: {
1.38 ! schwarze 620: const enum mdocargt *argsp;
1.1 kristaps 621:
1.38 ! schwarze 622: argsp = NULL;
1.1 kristaps 623:
624: switch (tok) {
625: case (MDOC_An):
1.38 ! schwarze 626: argsp = args_An;
1.1 kristaps 627: break;
628: case (MDOC_Bd):
1.38 ! schwarze 629: argsp = args_Bd;
1.1 kristaps 630: break;
631: case (MDOC_Bf):
1.38 ! schwarze 632: argsp = args_Bf;
1.1 kristaps 633: break;
634: case (MDOC_Bk):
1.38 ! schwarze 635: argsp = args_Bk;
1.1 kristaps 636: break;
637: case (MDOC_Bl):
1.38 ! schwarze 638: argsp = args_Bl;
1.1 kristaps 639: break;
640: case (MDOC_Rv):
641: /* FALLTHROUGH */
642: case (MDOC_Ex):
1.38 ! schwarze 643: argsp = args_Ex;
1.1 kristaps 644: break;
645: default:
1.37 schwarze 646: return(MDOC_ARG_MAX);
1.1 kristaps 647: }
648:
1.38 ! schwarze 649: assert(argsp);
1.37 schwarze 650:
1.38 ! schwarze 651: for ( ; MDOC_ARG_MAX != *argsp ; argsp++)
! 652: if (0 == strcmp(p, mdoc_argnames[*argsp]))
! 653: return(*argsp);
1.36 schwarze 654:
1.1 kristaps 655: return(MDOC_ARG_MAX);
656: }
657:
658: static int
1.6 schwarze 659: argv_multi(struct mdoc *m, int line,
1.1 kristaps 660: struct mdoc_argv *v, int *pos, char *buf)
661: {
1.24 schwarze 662: enum margserr ac;
1.1 kristaps 663: char *p;
664:
665: for (v->sz = 0; ; v->sz++) {
666: if ('-' == buf[*pos])
667: break;
1.38 ! schwarze 668: ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
1.24 schwarze 669: if (ARGS_ERROR == ac)
1.1 kristaps 670: return(0);
1.24 schwarze 671: else if (ARGS_EOLN == ac)
1.1 kristaps 672: break;
673:
1.19 schwarze 674: if (0 == v->sz % MULTI_STEP)
675: v->value = mandoc_realloc(v->value,
1.1 kristaps 676: (v->sz + MULTI_STEP) * sizeof(char *));
1.19 schwarze 677:
678: v->value[(int)v->sz] = mandoc_strdup(p);
1.1 kristaps 679: }
680:
1.4 schwarze 681: return(1);
1.1 kristaps 682: }
683:
684: static int
1.6 schwarze 685: argv_opt_single(struct mdoc *m, int line,
1.1 kristaps 686: struct mdoc_argv *v, int *pos, char *buf)
687: {
1.24 schwarze 688: enum margserr ac;
1.1 kristaps 689: char *p;
690:
691: if ('-' == buf[*pos])
692: return(1);
693:
1.38 ! schwarze 694: ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
1.24 schwarze 695: if (ARGS_ERROR == ac)
1.1 kristaps 696: return(0);
1.24 schwarze 697: if (ARGS_EOLN == ac)
1.1 kristaps 698: return(1);
699:
700: v->sz = 1;
1.19 schwarze 701: v->value = mandoc_malloc(sizeof(char *));
702: v->value[0] = mandoc_strdup(p);
1.1 kristaps 703:
704: return(1);
705: }
706:
707: /*
708: * Parse a single, mandatory value from the stream.
709: */
710: static int
1.6 schwarze 711: argv_single(struct mdoc *m, int line,
1.1 kristaps 712: struct mdoc_argv *v, int *pos, char *buf)
713: {
1.24 schwarze 714: int ppos;
715: enum margserr ac;
1.1 kristaps 716: char *p;
717:
718: ppos = *pos;
719:
1.38 ! schwarze 720: ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
1.29 schwarze 721: if (ARGS_EOLN == ac) {
722: mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTARGVCOUNT);
723: return(0);
724: } else if (ARGS_ERROR == ac)
1.1 kristaps 725: return(0);
726:
727: v->sz = 1;
1.19 schwarze 728: v->value = mandoc_malloc(sizeof(char *));
729: v->value[0] = mandoc_strdup(p);
1.1 kristaps 730:
731: return(1);
732: }
733:
734: /*
735: * Determine rules for parsing arguments. Arguments can either accept
736: * no parameters, an optional single parameter, one parameter, or
737: * multiple parameters.
738: */
739: static int
740: argv(struct mdoc *mdoc, int line,
741: struct mdoc_argv *v, int *pos, char *buf)
742: {
743:
744: v->sz = 0;
745: v->value = NULL;
746:
1.36 schwarze 747: switch (argvflags[v->arg]) {
1.1 kristaps 748: case (ARGV_SINGLE):
749: return(argv_single(mdoc, line, v, pos, buf));
750: case (ARGV_MULTI):
751: return(argv_multi(mdoc, line, v, pos, buf));
752: case (ARGV_OPT_SINGLE):
753: return(argv_opt_single(mdoc, line, v, pos, buf));
1.36 schwarze 754: case (ARGV_NONE):
755: break;
1.1 kristaps 756: default:
1.36 schwarze 757: abort();
758: /* NOTREACHED */
1.1 kristaps 759: }
760:
761: return(1);
762: }