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