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