Annotation of mandoc/mdoc_macro.c, Revision 1.12
1.12 ! kristaps 1: /* $Id: mdoc_macro.c,v 1.11 2009/06/11 20:02:37 kristaps Exp $ */
1.1 kristaps 2: /*
1.9 kristaps 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.8 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.8 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: */
17: #include <assert.h>
18: #include <ctype.h>
19: #include <stdlib.h>
20: #include <stdio.h>
21: #include <string.h>
22:
23: #include "libmdoc.h"
24:
25: /* FIXME: .Fl, .Ar, .Cd handling of `|'. */
26:
27: enum mwarn {
1.4 kristaps 28: WIGNE,
1.1 kristaps 29: WIMPBRK,
30: WMACPARM,
31: WOBS
32: };
33:
34: enum merr {
35: EOPEN,
36: EQUOT,
37: ENOCTX,
38: ENOPARMS
39: };
40:
41: #define REWIND_REWIND (1 << 0)
42: #define REWIND_NOHALT (1 << 1)
43: #define REWIND_HALT (1 << 2)
44:
45: static int obsolete(MACRO_PROT_ARGS);
46: static int blk_part_exp(MACRO_PROT_ARGS);
47: static int in_line_eoln(MACRO_PROT_ARGS);
48: static int in_line_argn(MACRO_PROT_ARGS);
49: static int in_line(MACRO_PROT_ARGS);
50: static int blk_full(MACRO_PROT_ARGS);
51: static int blk_exp_close(MACRO_PROT_ARGS);
52: static int blk_part_imp(MACRO_PROT_ARGS);
53:
54: static int phrase(struct mdoc *, int, int, char *);
55: static int rew_dohalt(int, enum mdoc_type,
56: const struct mdoc_node *);
57: static int rew_alt(int);
58: static int rew_dobreak(int, const struct mdoc_node *);
59: static int rew_elem(struct mdoc *, int);
60: static int rew_impblock(struct mdoc *, int, int, int);
61: static int rew_expblock(struct mdoc *, int, int, int);
62: static int rew_subblock(enum mdoc_type,
63: struct mdoc *, int, int, int);
64: static int rew_last(struct mdoc *, struct mdoc_node *);
65: static int append_delims(struct mdoc *, int, int *, char *);
66: static int lookup(struct mdoc *, int, int, int, const char *);
67: static int pwarn(struct mdoc *, int, int, enum mwarn);
68: static int perr(struct mdoc *, int, int, enum merr);
69: static int swarn(struct mdoc *, enum mdoc_type, int, int,
70: const struct mdoc_node *);
71:
72: #define nerr(m, n, t) perr((m), (n)->line, (n)->pos, (t))
73:
74: /* Central table of library: who gets parsed how. */
75:
76: const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
77: { NULL, 0 }, /* \" */
78: { in_line_eoln, MDOC_PROLOGUE }, /* Dd */
79: { in_line_eoln, MDOC_PROLOGUE }, /* Dt */
80: { in_line_eoln, MDOC_PROLOGUE }, /* Os */
81: { blk_full, 0 }, /* Sh */
82: { blk_full, 0 }, /* Ss */
83: { in_line, 0 }, /* Pp */
84: { blk_part_imp, MDOC_PARSED }, /* D1 */
85: { blk_part_imp, MDOC_PARSED }, /* Dl */
86: { blk_full, MDOC_EXPLICIT }, /* Bd */
87: { blk_exp_close, MDOC_EXPLICIT }, /* Ed */
88: { blk_full, MDOC_EXPLICIT }, /* Bl */
89: { blk_exp_close, MDOC_EXPLICIT }, /* El */
90: { blk_full, MDOC_PARSED }, /* It */
91: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
1.10 kristaps 92: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* An */
1.1 kristaps 93: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
94: { in_line_eoln, MDOC_CALLABLE }, /* Cd */
95: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
96: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
97: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
98: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
99: { in_line_eoln, 0 }, /* Ex */
100: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
101: { in_line_eoln, 0 }, /* Fd */
102: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
103: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
1.11 kristaps 104: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */
1.1 kristaps 105: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
1.11 kristaps 106: { in_line_eoln, 0 }, /* In */ /* FIXME: historic usage! */
1.1 kristaps 107: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */
108: { in_line_eoln, 0 }, /* Nd */
109: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
110: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
111: { obsolete, 0 }, /* Ot */
112: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
113: { in_line_eoln, 0 }, /* Rv */
114: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */
115: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
116: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
117: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
118: { in_line_eoln, 0 }, /* %A */
119: { in_line_eoln, 0 }, /* %B */
120: { in_line_eoln, 0 }, /* %D */
121: { in_line_eoln, 0 }, /* %I */
122: { in_line_eoln, 0 }, /* %J */
123: { in_line_eoln, 0 }, /* %N */
124: { in_line_eoln, 0 }, /* %O */
125: { in_line_eoln, 0 }, /* %P */
126: { in_line_eoln, 0 }, /* %R */
127: { in_line_eoln, 0 }, /* %T */
128: { in_line_eoln, 0 }, /* %V */
129: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */
130: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */
131: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */
132: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */
133: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */
134: { blk_full, MDOC_EXPLICIT }, /* Bf */
135: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */
136: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */
137: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */
138: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */
139: { in_line_eoln, 0 }, /* Db */
140: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */
141: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */
142: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */
143: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */
144: { blk_exp_close, MDOC_EXPLICIT }, /* Ef */
145: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Em */
146: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
147: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */
1.11 kristaps 148: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */
1.1 kristaps 149: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* No */
150: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ns */
151: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */
152: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */
153: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */
154: { in_line_argn, MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */
155: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */
156: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */
157: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */
158: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */
159: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */
160: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */
161: { blk_exp_close, MDOC_EXPLICIT }, /* Re */
162: { blk_full, MDOC_EXPLICIT }, /* Rs */
163: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */
164: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */
165: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */
166: { in_line_eoln, 0 }, /* Sm */
167: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */
168: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */
169: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
170: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ux */
171: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
172: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
173: { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */
174: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */
175: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */
176: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */
177: { blk_full, MDOC_EXPLICIT }, /* Bk */
178: { blk_exp_close, MDOC_EXPLICIT }, /* Ek */
179: { in_line_eoln, 0 }, /* Bt */
180: { in_line_eoln, 0 }, /* Hf */
181: { obsolete, 0 }, /* Fr */
182: { in_line_eoln, 0 }, /* Ud */
183: { in_line_eoln, 0 }, /* Lb */
184: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */
185: { in_line, 0 }, /* Lp */
1.12 ! kristaps 186: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */
! 187: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */
1.1 kristaps 188: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Brq */
189: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */
190: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */
191: { in_line_eoln, 0 }, /* %C */
192: { obsolete, 0 }, /* Es */
193: { obsolete, 0 }, /* En */
194: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */
195: { in_line_eoln, 0 }, /* %Q */
196: };
197:
198: const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
199:
200:
201: static int
202: perr(struct mdoc *mdoc, int line, int pos, enum merr type)
203: {
204: char *p;
205:
206: p = NULL;
207: switch (type) {
208: case (EOPEN):
209: p = "explicit scope still open on exit";
210: break;
211: case (EQUOT):
212: p = "unterminated quotation";
213: break;
214: case (ENOCTX):
215: p = "closure has no prior context";
216: break;
217: case (ENOPARMS):
218: p = "unexpect line arguments";
219: break;
220: }
221: assert(p);
222: return(mdoc_perr(mdoc, line, pos, p));
223: }
224:
225:
226: static int
227: pwarn(struct mdoc *mdoc, int line, int pos, enum mwarn type)
228: {
229: char *p;
230:
231: p = NULL;
232: switch (type) {
1.4 kristaps 233: case (WIGNE):
234: p = "ignoring empty element";
235: break;
1.1 kristaps 236: case (WIMPBRK):
237: p = "crufty end-of-line scope violation";
238: break;
239: case (WMACPARM):
240: p = "macro-like parameter";
241: break;
242: case (WOBS):
243: p = "macro marked obsolete";
244: break;
245: }
246: assert(p);
247: return(mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX, p));
248: }
249:
250:
251: static int
252: swarn(struct mdoc *mdoc, enum mdoc_type type,
253: int line, int pos, const struct mdoc_node *p)
254: {
255: const char *n, *t, *tt;
256:
257: n = t = "<root>";
258: tt = "block";
259:
260: switch (type) {
261: case (MDOC_BODY):
262: tt = "multi-line";
263: break;
264: case (MDOC_HEAD):
265: tt = "line";
266: break;
267: default:
268: break;
269: }
270:
271: switch (p->type) {
272: case (MDOC_BLOCK):
273: n = mdoc_macronames[p->tok];
274: t = "block";
275: break;
276: case (MDOC_BODY):
277: n = mdoc_macronames[p->tok];
278: t = "multi-line";
279: break;
280: case (MDOC_HEAD):
281: n = mdoc_macronames[p->tok];
282: t = "line";
283: break;
284: default:
285: break;
286: }
287:
288: if ( ! (MDOC_IGN_SCOPE & mdoc->pflags))
289: return(mdoc_perr(mdoc, line, pos,
290: "%s scope breaks %s scope of %s",
291: tt, t, n));
292: return(mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
293: "%s scope breaks %s scope of %s",
294: tt, t, n));
295: }
296:
297:
298: /*
299: * This is called at the end of parsing. It must traverse up the tree,
300: * closing out open [implicit] scopes. Obviously, open explicit scopes
301: * are errors.
302: */
303: int
1.2 kristaps 304: mdoc_macroend(struct mdoc *mdoc)
1.1 kristaps 305: {
306: struct mdoc_node *n;
307:
308: /* Scan for open explicit scopes. */
309:
310: n = MDOC_VALID & mdoc->last->flags ?
311: mdoc->last->parent : mdoc->last;
312:
313: for ( ; n; n = n->parent) {
314: if (MDOC_BLOCK != n->type)
315: continue;
316: if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags))
317: continue;
318: return(nerr(mdoc, n, EOPEN));
319: }
320:
321: return(rew_last(mdoc, mdoc->first));
322: }
323:
324: static int
325: lookup(struct mdoc *mdoc, int line, int pos, int from, const char *p)
326: {
327: int res;
328:
1.6 kristaps 329: res = mdoc_hash_find(mdoc->htab, p);
1.1 kristaps 330: if (MDOC_PARSED & mdoc_macros[from].flags)
331: return(res);
332: if (MDOC_MAX == res)
333: return(res);
334: if ( ! pwarn(mdoc, line, pos, WMACPARM))
335: return(-1);
336: return(MDOC_MAX);
337: }
338:
339:
340: static int
341: rew_last(struct mdoc *mdoc, struct mdoc_node *to)
342: {
343:
344: assert(to);
345: mdoc->next = MDOC_NEXT_SIBLING;
346:
347: /* LINTED */
348: while (mdoc->last != to) {
349: if ( ! mdoc_valid_post(mdoc))
350: return(0);
351: if ( ! mdoc_action_post(mdoc))
352: return(0);
353: mdoc->last = mdoc->last->parent;
354: assert(mdoc->last);
355: }
356:
357: if ( ! mdoc_valid_post(mdoc))
358: return(0);
359: return(mdoc_action_post(mdoc));
360: }
361:
362:
363: static int
364: rew_alt(int tok)
365: {
366: switch (tok) {
367: case (MDOC_Ac):
368: return(MDOC_Ao);
369: case (MDOC_Bc):
370: return(MDOC_Bo);
371: case (MDOC_Brc):
372: return(MDOC_Bro);
373: case (MDOC_Dc):
374: return(MDOC_Do);
375: case (MDOC_Ec):
376: return(MDOC_Eo);
377: case (MDOC_Ed):
378: return(MDOC_Bd);
379: case (MDOC_Ef):
380: return(MDOC_Bf);
381: case (MDOC_Ek):
382: return(MDOC_Bk);
383: case (MDOC_El):
384: return(MDOC_Bl);
385: case (MDOC_Fc):
386: return(MDOC_Fo);
387: case (MDOC_Oc):
388: return(MDOC_Oo);
389: case (MDOC_Pc):
390: return(MDOC_Po);
391: case (MDOC_Qc):
392: return(MDOC_Qo);
393: case (MDOC_Re):
394: return(MDOC_Rs);
395: case (MDOC_Sc):
396: return(MDOC_So);
397: case (MDOC_Xc):
398: return(MDOC_Xo);
399: default:
400: break;
401: }
402: abort();
403: /* NOTREACHED */
404: }
405:
406:
407: /*
408: * Rewind rules. This indicates whether to stop rewinding
409: * (REWIND_HALT) without touching our current scope, stop rewinding and
410: * close our current scope (REWIND_REWIND), or continue (REWIND_NOHALT).
411: * The scope-closing and so on occurs in the various rew_* routines.
412: */
413: static int
414: rew_dohalt(int tok, enum mdoc_type type, const struct mdoc_node *p)
415: {
416:
417: if (MDOC_ROOT == p->type)
418: return(REWIND_HALT);
419: if (MDOC_VALID & p->flags)
420: return(REWIND_NOHALT);
421:
422: switch (tok) {
423: case (MDOC_Aq):
424: /* FALLTHROUGH */
425: case (MDOC_Bq):
426: /* FALLTHROUGH */
427: case (MDOC_Brq):
428: /* FALLTHROUGH */
429: case (MDOC_D1):
430: /* FALLTHROUGH */
431: case (MDOC_Dl):
432: /* FALLTHROUGH */
433: case (MDOC_Dq):
434: /* FALLTHROUGH */
435: case (MDOC_Op):
436: /* FALLTHROUGH */
437: case (MDOC_Pq):
438: /* FALLTHROUGH */
439: case (MDOC_Ql):
440: /* FALLTHROUGH */
441: case (MDOC_Qq):
442: /* FALLTHROUGH */
443: case (MDOC_Sq):
444: assert(MDOC_HEAD != type);
445: assert(MDOC_TAIL != type);
446: if (type == p->type && tok == p->tok)
447: return(REWIND_REWIND);
448: break;
449: case (MDOC_It):
450: assert(MDOC_TAIL != type);
451: if (type == p->type && tok == p->tok)
452: return(REWIND_REWIND);
453: if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
454: return(REWIND_HALT);
455: break;
456: case (MDOC_Sh):
457: if (type == p->type && tok == p->tok)
458: return(REWIND_REWIND);
459: break;
460: case (MDOC_Ss):
461: assert(MDOC_TAIL != type);
462: if (type == p->type && tok == p->tok)
463: return(REWIND_REWIND);
464: if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
465: return(REWIND_HALT);
466: break;
467: case (MDOC_Ao):
468: /* FALLTHROUGH */
469: case (MDOC_Bd):
470: /* FALLTHROUGH */
471: case (MDOC_Bf):
472: /* FALLTHROUGH */
473: case (MDOC_Bk):
474: /* FALLTHROUGH */
475: case (MDOC_Bl):
476: /* FALLTHROUGH */
477: case (MDOC_Bo):
478: /* FALLTHROUGH */
479: case (MDOC_Bro):
480: /* FALLTHROUGH */
481: case (MDOC_Do):
482: /* FALLTHROUGH */
483: case (MDOC_Eo):
484: /* FALLTHROUGH */
485: case (MDOC_Fo):
486: /* FALLTHROUGH */
487: case (MDOC_Oo):
488: /* FALLTHROUGH */
489: case (MDOC_Po):
490: /* FALLTHROUGH */
491: case (MDOC_Qo):
492: /* FALLTHROUGH */
493: case (MDOC_Rs):
494: /* FALLTHROUGH */
495: case (MDOC_So):
496: /* FALLTHROUGH */
497: case (MDOC_Xo):
498: if (type == p->type && tok == p->tok)
499: return(REWIND_REWIND);
500: break;
501:
502: /* Multi-line explicit scope close. */
503: case (MDOC_Ac):
504: /* FALLTHROUGH */
505: case (MDOC_Bc):
506: /* FALLTHROUGH */
507: case (MDOC_Brc):
508: /* FALLTHROUGH */
509: case (MDOC_Dc):
510: /* FALLTHROUGH */
511: case (MDOC_Ec):
512: /* FALLTHROUGH */
513: case (MDOC_Ed):
514: /* FALLTHROUGH */
515: case (MDOC_Ek):
516: /* FALLTHROUGH */
517: case (MDOC_El):
518: /* FALLTHROUGH */
519: case (MDOC_Fc):
520: /* FALLTHROUGH */
521: case (MDOC_Ef):
522: /* FALLTHROUGH */
523: case (MDOC_Oc):
524: /* FALLTHROUGH */
525: case (MDOC_Pc):
526: /* FALLTHROUGH */
527: case (MDOC_Qc):
528: /* FALLTHROUGH */
529: case (MDOC_Re):
530: /* FALLTHROUGH */
531: case (MDOC_Sc):
532: /* FALLTHROUGH */
533: case (MDOC_Xc):
534: if (type == p->type && rew_alt(tok) == p->tok)
535: return(REWIND_REWIND);
536: break;
537: default:
538: abort();
539: /* NOTREACHED */
540: }
541:
542: return(REWIND_NOHALT);
543: }
544:
545:
546: /*
547: * See if we can break an encountered scope (the rew_dohalt has returned
548: * REWIND_NOHALT).
549: */
550: static int
551: rew_dobreak(int tok, const struct mdoc_node *p)
552: {
553:
554: assert(MDOC_ROOT != p->type);
555: if (MDOC_ELEM == p->type)
556: return(1);
557: if (MDOC_TEXT == p->type)
558: return(1);
559: if (MDOC_VALID & p->flags)
560: return(1);
561:
562: switch (tok) {
563: case (MDOC_It):
564: return(MDOC_It == p->tok);
565: case (MDOC_Ss):
566: return(MDOC_Ss == p->tok);
567: case (MDOC_Sh):
568: if (MDOC_Ss == p->tok)
569: return(1);
570: return(MDOC_Sh == p->tok);
571: case (MDOC_El):
572: if (MDOC_It == p->tok)
573: return(1);
574: break;
575: case (MDOC_Oc):
576: /* XXX - experimental! */
577: if (MDOC_Op == p->tok)
578: return(1);
579: break;
580: default:
581: break;
582: }
583:
584: if (MDOC_EXPLICIT & mdoc_macros[tok].flags)
585: return(p->tok == rew_alt(tok));
586: else if (MDOC_BLOCK == p->type)
587: return(1);
588:
589: return(tok == p->tok);
590: }
591:
592:
593: static int
594: rew_elem(struct mdoc *mdoc, int tok)
595: {
596: struct mdoc_node *n;
597:
598: n = mdoc->last;
599: if (MDOC_ELEM != n->type)
600: n = n->parent;
601: assert(MDOC_ELEM == n->type);
602: assert(tok == n->tok);
603:
604: return(rew_last(mdoc, n));
605: }
606:
607:
608: static int
609: rew_subblock(enum mdoc_type type, struct mdoc *mdoc,
610: int tok, int line, int ppos)
611: {
612: struct mdoc_node *n;
613: int c;
614:
615: /* LINTED */
616: for (n = mdoc->last; n; n = n->parent) {
617: c = rew_dohalt(tok, type, n);
618: if (REWIND_HALT == c)
619: return(1);
620: if (REWIND_REWIND == c)
621: break;
622: else if (rew_dobreak(tok, n))
623: continue;
624: if ( ! swarn(mdoc, type, line, ppos, n))
625: return(0);
626: }
627:
628: assert(n);
629: return(rew_last(mdoc, n));
630: }
631:
632:
633: static int
634: rew_expblock(struct mdoc *mdoc, int tok, int line, int ppos)
635: {
636: struct mdoc_node *n;
637: int c;
638:
639: /* LINTED */
640: for (n = mdoc->last; n; n = n->parent) {
641: c = rew_dohalt(tok, MDOC_BLOCK, n);
642: if (REWIND_HALT == c)
643: return(perr(mdoc, line, ppos, ENOCTX));
644: if (REWIND_REWIND == c)
645: break;
646: else if (rew_dobreak(tok, n))
647: continue;
648: if ( ! swarn(mdoc, MDOC_BLOCK, line, ppos, n))
649: return(0);
650: }
651:
652: assert(n);
653: return(rew_last(mdoc, n));
654: }
655:
656:
657: static int
658: rew_impblock(struct mdoc *mdoc, int tok, int line, int ppos)
659: {
660: struct mdoc_node *n;
661: int c;
662:
663: /* LINTED */
664: for (n = mdoc->last; n; n = n->parent) {
665: c = rew_dohalt(tok, MDOC_BLOCK, n);
666: if (REWIND_HALT == c)
667: return(1);
668: else if (REWIND_REWIND == c)
669: break;
670: else if (rew_dobreak(tok, n))
671: continue;
672: if ( ! swarn(mdoc, MDOC_BLOCK, line, ppos, n))
673: return(0);
674: }
675:
676: assert(n);
677: return(rew_last(mdoc, n));
678: }
679:
680:
681: static int
682: append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
683: {
684: int c, lastarg;
685: char *p;
686:
687: if (0 == buf[*pos])
688: return(1);
689:
690: for (;;) {
691: lastarg = *pos;
692: c = mdoc_args(mdoc, line, pos, buf, 0, &p);
693: assert(ARGS_PHRASE != c);
694:
695: if (ARGS_ERROR == c)
696: return(0);
697: else if (ARGS_EOLN == c)
698: break;
699: assert(mdoc_isdelim(p));
700: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
701: return(0);
702: mdoc->next = MDOC_NEXT_SIBLING;
703: }
704:
705: return(1);
706: }
707:
708:
709: /*
710: * Close out block partial/full explicit.
711: */
712: static int
713: blk_exp_close(MACRO_PROT_ARGS)
714: {
715: int j, c, lastarg, maxargs, flushed;
716: char *p;
717:
718: switch (tok) {
719: case (MDOC_Ec):
720: maxargs = 1;
721: break;
722: default:
723: maxargs = 0;
724: break;
725: }
726:
727: if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
728: if (0 == buf[*pos]) {
729: if ( ! rew_subblock(MDOC_BODY, mdoc,
730: tok, line, ppos))
731: return(0);
732: return(rew_expblock(mdoc, tok, line, ppos));
733: }
734: return(perr(mdoc, line, ppos, ENOPARMS));
735: }
736:
737: if ( ! rew_subblock(MDOC_BODY, mdoc, tok, line, ppos))
738: return(0);
739:
740: if (maxargs > 0) {
741: if ( ! mdoc_tail_alloc(mdoc, line,
742: ppos, rew_alt(tok)))
743: return(0);
744: mdoc->next = MDOC_NEXT_CHILD;
745: }
746:
747: for (lastarg = ppos, flushed = j = 0; ; j++) {
748: lastarg = *pos;
749:
750: if (j == maxargs && ! flushed) {
751: if ( ! rew_expblock(mdoc, tok, line, ppos))
752: return(0);
753: flushed = 1;
754: }
755:
756: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
757:
758: if (ARGS_ERROR == c)
759: return(0);
760: if (ARGS_PUNCT == c)
761: break;
762: if (ARGS_EOLN == c)
763: break;
764:
765: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
766: return(0);
767: else if (MDOC_MAX != c) {
768: if ( ! flushed) {
769: if ( ! rew_expblock(mdoc, tok,
770: line, ppos))
771: return(0);
772: flushed = 1;
773: }
774: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
775: return(0);
776: break;
777: }
778:
779: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
780: return(0);
781: mdoc->next = MDOC_NEXT_SIBLING;
782: }
783:
784: if ( ! flushed && ! rew_expblock(mdoc, tok, line, ppos))
785: return(0);
786:
787: if (ppos > 1)
788: return(1);
789: return(append_delims(mdoc, line, pos, buf));
790: }
791:
792:
793: /*
794: * In-line macros where reserved words cause scope close-reopen.
795: */
796: static int
797: in_line(MACRO_PROT_ARGS)
798: {
1.4 kristaps 799: int la, lastpunct, c, w, cnt, d, nc;
1.1 kristaps 800: struct mdoc_arg *arg;
801: char *p;
802:
1.4 kristaps 803: /*
804: * Whether we allow ignored elements (those without content,
805: * usually because of reserved words) to squeak by.
806: */
807: switch (tok) {
808: case (MDOC_Lp):
809: /* FALLTHROUGH */
810: case (MDOC_Pp):
811: /* FALLTHROUGH */
812: case (MDOC_Nm):
813: /* FALLTHROUGH */
814: case (MDOC_Fl):
815: /* FALLTHROUGH */
1.12 ! kristaps 816: case (MDOC_Lk):
! 817: /* FALLTHROUGH */
1.4 kristaps 818: case (MDOC_Ar):
819: nc = 1;
820: break;
821: default:
822: nc = 0;
823: break;
824: }
825:
1.1 kristaps 826: for (la = ppos, arg = NULL;; ) {
827: la = *pos;
828: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
829:
830: if (ARGV_WORD == c) {
831: *pos = la;
832: break;
833: }
834: if (ARGV_EOLN == c)
835: break;
836: if (ARGV_ARG == c)
837: continue;
838:
839: mdoc_argv_free(arg);
840: return(0);
841: }
842:
1.4 kristaps 843: for (cnt = 0, lastpunct = 1;; ) {
1.1 kristaps 844: la = *pos;
845: w = mdoc_args(mdoc, line, pos, buf, tok, &p);
846:
847: if (ARGS_ERROR == w)
848: return(0);
849: if (ARGS_EOLN == w)
850: break;
851: if (ARGS_PUNCT == w)
852: break;
853:
854: /* Quoted words shouldn't be looked-up. */
855:
856: c = ARGS_QWORD == w ? MDOC_MAX :
857: lookup(mdoc, line, la, tok, p);
858:
1.4 kristaps 859: /*
860: * In this case, we've located a submacro and must
861: * execute it. Close out scope, if open. If no
862: * elements have been generated, either create one (nc)
863: * or raise a warning.
864: */
1.1 kristaps 865:
866: if (MDOC_MAX != c && -1 != c) {
867: if (0 == lastpunct && ! rew_elem(mdoc, tok))
868: return(0);
1.4 kristaps 869: if (nc && 0 == cnt) {
1.3 kristaps 870: if ( ! mdoc_elem_alloc(mdoc, line, ppos,
871: tok, arg))
872: return(0);
1.12 ! kristaps 873: if ( ! rew_last(mdoc, mdoc->last))
! 874: return(0);
1.7 kristaps 875: } else if ( ! nc && 0 == cnt) {
876: mdoc_argv_free(arg);
1.4 kristaps 877: if ( ! pwarn(mdoc, line, ppos, WIGNE))
1.3 kristaps 878: return(0);
1.7 kristaps 879: }
1.1 kristaps 880: c = mdoc_macro(mdoc, c, line, la, pos, buf);
881: if (0 == c)
882: return(0);
883: if (ppos > 1)
884: return(1);
885: return(append_delims(mdoc, line, pos, buf));
886: } else if (-1 == c)
887: return(0);
888:
1.4 kristaps 889: /*
890: * Non-quote-enclosed punctuation. Set up our scope, if
891: * a word; rewind the scope, if a delimiter; then append
892: * the word.
893: */
1.1 kristaps 894:
1.3 kristaps 895: d = mdoc_isdelim(p);
896:
897: if (ARGS_QWORD != w && d) {
1.1 kristaps 898: if (0 == lastpunct && ! rew_elem(mdoc, tok))
899: return(0);
900: lastpunct = 1;
901: } else if (lastpunct) {
902: c = mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
903: if (0 == c)
904: return(0);
905: mdoc->next = MDOC_NEXT_CHILD;
906: lastpunct = 0;
907: }
908:
1.3 kristaps 909: if ( ! d)
910: cnt++;
1.1 kristaps 911: if ( ! mdoc_word_alloc(mdoc, line, la, p))
912: return(0);
913: mdoc->next = MDOC_NEXT_SIBLING;
914: }
915:
916: if (0 == lastpunct && ! rew_elem(mdoc, tok))
917: return(0);
1.4 kristaps 918:
919: /*
920: * If no elements have been collected and we're allowed to have
921: * empties (nc), open a scope and close it out. Otherwise,
922: * raise a warning.
923: *
924: */
925: if (nc && 0 == cnt) {
1.3 kristaps 926: c = mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
927: if (0 == c)
928: return(0);
1.12 ! kristaps 929: if ( ! rew_last(mdoc, mdoc->last))
! 930: return(0);
1.7 kristaps 931: } else if ( ! nc && 0 == cnt) {
932: mdoc_argv_free(arg);
1.4 kristaps 933: if ( ! pwarn(mdoc, line, ppos, WIGNE))
1.3 kristaps 934: return(0);
1.7 kristaps 935: }
1.4 kristaps 936:
1.1 kristaps 937: if (ppos > 1)
938: return(1);
939: return(append_delims(mdoc, line, pos, buf));
940: }
941:
942:
943: /*
944: * Block full-explicit and full-implicit.
945: */
946: static int
947: blk_full(MACRO_PROT_ARGS)
948: {
949: int c, lastarg, reopen;
950: struct mdoc_arg *arg;
951: char *p;
952:
953: if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
954: if ( ! rew_subblock(MDOC_BODY, mdoc,
955: tok, line, ppos))
956: return(0);
957: if ( ! rew_impblock(mdoc, tok, line, ppos))
958: return(0);
959: }
960:
961: for (arg = NULL;; ) {
962: lastarg = *pos;
963: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
964:
965: if (ARGV_WORD == c) {
966: *pos = lastarg;
967: break;
968: }
969:
970: if (ARGV_EOLN == c)
971: break;
972: if (ARGV_ARG == c)
973: continue;
974:
975: mdoc_argv_free(arg);
976: return(0);
977: }
978:
979: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, arg))
980: return(0);
981: mdoc->next = MDOC_NEXT_CHILD;
982:
983: if (0 == buf[*pos]) {
984: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
985: return(0);
986: if ( ! rew_subblock(MDOC_HEAD, mdoc,
987: tok, line, ppos))
988: return(0);
989: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
990: return(0);
991: mdoc->next = MDOC_NEXT_CHILD;
992: return(1);
993: }
994:
995: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
996: return(0);
997: mdoc->next = MDOC_NEXT_CHILD;
998:
999: for (reopen = 0;; ) {
1000: lastarg = *pos;
1001: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1002:
1003: if (ARGS_ERROR == c)
1004: return(0);
1005: if (ARGS_EOLN == c)
1006: break;
1007: if (ARGS_PHRASE == c) {
1008: if (reopen && ! mdoc_head_alloc
1009: (mdoc, line, ppos, tok))
1010: return(0);
1011: mdoc->next = MDOC_NEXT_CHILD;
1012: /*
1013: * Phrases are self-contained macro phrases used
1014: * in the columnar output of a macro. They need
1015: * special handling.
1016: */
1017: if ( ! phrase(mdoc, line, lastarg, buf))
1018: return(0);
1019: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1020: tok, line, ppos))
1021: return(0);
1022:
1023: reopen = 1;
1024: continue;
1025: }
1026:
1027: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1028: return(0);
1029:
1030: if (MDOC_MAX == c) {
1031: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1032: return(0);
1033: mdoc->next = MDOC_NEXT_SIBLING;
1034: continue;
1035: }
1036:
1037: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1038: return(0);
1039: break;
1040: }
1041:
1042: if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
1043: return(0);
1044: if ( ! rew_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1045: return(0);
1046:
1047: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1048: return(0);
1049: mdoc->next = MDOC_NEXT_CHILD;
1050:
1051: return(1);
1052: }
1053:
1054:
1055: /*
1056: * Block partial-imnplicit scope.
1057: */
1058: static int
1059: blk_part_imp(MACRO_PROT_ARGS)
1060: {
1061: int lastarg, c;
1062: char *p;
1063: struct mdoc_node *blk, *body, *n;
1064:
1065: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
1066: return(0);
1067: mdoc->next = MDOC_NEXT_CHILD;
1068: blk = mdoc->last;
1069:
1070: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1071: return(0);
1072: mdoc->next = MDOC_NEXT_SIBLING;
1073:
1074: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1075: return(0);
1076: mdoc->next = MDOC_NEXT_CHILD;
1077: body = mdoc->last;
1078:
1079: /* XXX - no known argument macros. */
1080:
1081: for (lastarg = ppos;; ) {
1082: lastarg = *pos;
1083: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1084: assert(ARGS_PHRASE != c);
1085:
1086: if (ARGS_ERROR == c)
1087: return(0);
1088: if (ARGS_PUNCT == c)
1089: break;
1090: if (ARGS_EOLN == c)
1091: break;
1092:
1093: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1094: return(0);
1095: else if (MDOC_MAX == c) {
1096: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1097: return(0);
1098: mdoc->next = MDOC_NEXT_SIBLING;
1099: continue;
1100: }
1101:
1102: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1103: return(0);
1104: break;
1105: }
1106:
1107: /*
1108: * Since we know what our context is, we can rewind directly to
1109: * it. This allows us to accomodate for our scope being
1110: * violated by another token.
1111: */
1112:
1113: for (n = mdoc->last; n; n = n->parent)
1114: if (body == n)
1115: break;
1116:
1117: if (NULL == n && ! pwarn(mdoc, body->line, body->pos, WIMPBRK))
1118: return(0);
1119:
1120: if (n && ! rew_last(mdoc, body))
1121: return(0);
1122:
1123: if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
1124: return(0);
1125:
1126: if (n && ! rew_last(mdoc, blk))
1127: return(0);
1128:
1129: return(1);
1130: }
1131:
1132:
1133: /*
1134: * Block partial-explicit macros.
1135: */
1136: static int
1137: blk_part_exp(MACRO_PROT_ARGS)
1138: {
1139: int lastarg, flushed, j, c, maxargs;
1140: char *p;
1141:
1142: lastarg = ppos;
1143: flushed = 0;
1144:
1145: /*
1146: * Number of arguments (head arguments). Only `Eo' has these,
1147: */
1148:
1149: switch (tok) {
1150: case (MDOC_Eo):
1151: maxargs = 1;
1152: break;
1153: default:
1154: maxargs = 0;
1155: break;
1156: }
1157:
1158: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
1159: return(0);
1160: mdoc->next = MDOC_NEXT_CHILD;
1161:
1162: if (0 == maxargs) {
1163: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1164: return(0);
1165: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1166: tok, line, ppos))
1167: return(0);
1168: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1169: return(0);
1170: flushed = 1;
1171: } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1172: return(0);
1173:
1174: mdoc->next = MDOC_NEXT_CHILD;
1175:
1176: for (j = 0; ; j++) {
1177: lastarg = *pos;
1178: if (j == maxargs && ! flushed) {
1179: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1180: tok, line, ppos))
1181: return(0);
1182: flushed = 1;
1183: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1184: return(0);
1185: mdoc->next = MDOC_NEXT_CHILD;
1186: }
1187:
1188: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1189: assert(ARGS_PHRASE != c);
1190:
1191: if (ARGS_ERROR == c)
1192: return(0);
1193: if (ARGS_PUNCT == c)
1194: break;
1195: if (ARGS_EOLN == c)
1196: break;
1197:
1198: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1199: return(0);
1200: else if (MDOC_MAX != c) {
1201: if ( ! flushed) {
1202: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1203: tok, line, ppos))
1204: return(0);
1205: flushed = 1;
1206: if ( ! mdoc_body_alloc(mdoc, line,
1207: ppos, tok))
1208: return(0);
1209: mdoc->next = MDOC_NEXT_CHILD;
1210: }
1211: if ( ! mdoc_macro(mdoc, c, line, lastarg,
1212: pos, buf))
1213: return(0);
1214: break;
1215: }
1216:
1217: if ( ! flushed && mdoc_isdelim(p)) {
1218: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1219: tok, line, ppos))
1220: return(0);
1221: flushed = 1;
1222: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1223: return(0);
1224: mdoc->next = MDOC_NEXT_CHILD;
1225: }
1226:
1227: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1228: return(0);
1229: mdoc->next = MDOC_NEXT_SIBLING;
1230: }
1231:
1232: if ( ! flushed) {
1233: if ( ! rew_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1234: return(0);
1235: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1236: return(0);
1237: mdoc->next = MDOC_NEXT_CHILD;
1238: }
1239:
1240: if (ppos > 1)
1241: return(1);
1242: return(append_delims(mdoc, line, pos, buf));
1243: }
1244:
1245:
1246: /*
1247: * In-line macros where reserved words signal closure of the macro.
1248: * Macros also have a fixed number of arguments.
1249: */
1250: static int
1251: in_line_argn(MACRO_PROT_ARGS)
1252: {
1253: int lastarg, flushed, j, c, maxargs;
1254: struct mdoc_arg *arg;
1255: char *p;
1256:
1257:
1258: /*
1259: * Fixed maximum arguments per macro. Some of these have none
1260: * and close as soon as the invocation is parsed.
1261: */
1262:
1263: switch (tok) {
1264: case (MDOC_Ap):
1265: /* FALLTHROUGH */
1266: case (MDOC_No):
1267: /* FALLTHROUGH */
1268: case (MDOC_Ns):
1269: /* FALLTHROUGH */
1270: case (MDOC_Ux):
1271: maxargs = 0;
1272: break;
1273: default:
1274: maxargs = 1;
1275: break;
1276: }
1277:
1278: for (lastarg = ppos, arg = NULL;; ) {
1279: lastarg = *pos;
1280: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1281:
1282: if (ARGV_WORD == c) {
1283: *pos = lastarg;
1284: break;
1285: }
1286:
1287: if (ARGV_EOLN == c)
1288: break;
1289: if (ARGV_ARG == c)
1290: continue;
1291:
1292: mdoc_argv_free(arg);
1293: return(0);
1294: }
1295:
1296: if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1297: return(0);
1298: mdoc->next = MDOC_NEXT_CHILD;
1299:
1300: for (flushed = j = 0; ; j++) {
1301: lastarg = *pos;
1302:
1303: if (j == maxargs && ! flushed) {
1304: if ( ! rew_elem(mdoc, tok))
1305: return(0);
1306: flushed = 1;
1307: }
1308:
1309: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1310:
1311: if (ARGS_ERROR == c)
1312: return(0);
1313: if (ARGS_PUNCT == c)
1314: break;
1315: if (ARGS_EOLN == c)
1316: break;
1317:
1318: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1319: return(0);
1320: else if (MDOC_MAX != c) {
1321: if ( ! flushed && ! rew_elem(mdoc, tok))
1322: return(0);
1323: flushed = 1;
1324: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1325: return(0);
1326: break;
1327: }
1328:
1329: if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
1330: ! flushed && mdoc_isdelim(p)) {
1331: if ( ! rew_elem(mdoc, tok))
1332: return(0);
1333: flushed = 1;
1334: }
1335:
1336: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1337: return(0);
1338: mdoc->next = MDOC_NEXT_SIBLING;
1339: }
1340:
1341: if ( ! flushed && ! rew_elem(mdoc, tok))
1342: return(0);
1343:
1344: if (ppos > 1)
1345: return(1);
1346: return(append_delims(mdoc, line, pos, buf));
1347: }
1348:
1349:
1350: /*
1351: * In-line macro that spans an entire line. May be callable, but has no
1352: * subsequent parsed arguments.
1353: */
1354: static int
1355: in_line_eoln(MACRO_PROT_ARGS)
1356: {
1357: int c, w, la;
1358: struct mdoc_arg *arg;
1359: char *p;
1360:
1361: assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));
1362:
1363: arg = NULL;
1364:
1365: for (;;) {
1366: la = *pos;
1367: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1368:
1369: if (ARGV_WORD == c) {
1370: *pos = la;
1371: break;
1372: }
1373: if (ARGV_EOLN == c)
1374: break;
1375: if (ARGV_ARG == c)
1376: continue;
1377:
1378: mdoc_argv_free(arg);
1379: return(0);
1380: }
1381:
1382: if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1383: return(0);
1384:
1385: mdoc->next = MDOC_NEXT_CHILD;
1386:
1387: for (;;) {
1388: la = *pos;
1389: w = mdoc_args(mdoc, line, pos, buf, tok, &p);
1390:
1391: if (ARGS_ERROR == w)
1392: return(0);
1393: if (ARGS_EOLN == w)
1394: break;
1395:
1396: c = ARGS_QWORD == w ? MDOC_MAX :
1397: lookup(mdoc, line, la, tok, p);
1398:
1399: if (MDOC_MAX != c && -1 != c) {
1400: if ( ! rew_elem(mdoc, tok))
1401: return(0);
1402: return(mdoc_macro(mdoc, c, line, la, pos, buf));
1403: } else if (-1 == c)
1404: return(0);
1405:
1406: if ( ! mdoc_word_alloc(mdoc, line, la, p))
1407: return(0);
1408: mdoc->next = MDOC_NEXT_SIBLING;
1409: }
1410:
1411: return(rew_elem(mdoc, tok));
1412: }
1413:
1414:
1415: /* ARGSUSED */
1416: static int
1417: obsolete(MACRO_PROT_ARGS)
1418: {
1419:
1420: return(pwarn(mdoc, line, ppos, WOBS));
1421: }
1422:
1423:
1424: static int
1425: phrase(struct mdoc *mdoc, int line, int ppos, char *buf)
1426: {
1427: int i, la, c, quoted;
1428:
1429: /*
1430: * Parse over words in a phrase. We have to handle this
1431: * specially because we assume no calling context -- in normal
1432: * circumstances, we switch argument parsing based on whether
1433: * the parent macro accepts quotes, tabs, etc. Here, anything
1434: * goes.
1435: */
1436:
1437: for (i = ppos; buf[i]; ) {
1438: assert(' ' != buf[i]);
1439: la = i;
1440: quoted = 0;
1441:
1442: /*
1443: * Read to next token. If quoted (check not escaped),
1444: * scan ahead to next unescaped quote. If not quoted or
1445: * escape-quoted, then scan ahead to next space.
1446: */
1447:
1448: if ((i && '\"' == buf[i] && '\\' != buf[i - 1]) ||
1449: (0 == i && '\"' == buf[i])) {
1450: for (la = ++i; buf[i]; i++)
1451: if ('\"' != buf[i])
1452: continue;
1453: else if ('\\' != buf[i - 1])
1454: break;
1455: if (0 == buf[i])
1456: return(perr(mdoc, line, la, EQUOT));
1457: quoted = 1;
1458: } else
1459: for ( ; buf[i]; i++)
1460: if (i && ' ' == buf[i]) {
1461: if ('\\' != buf[i - 1])
1462: break;
1463: } else if (' ' == buf[i])
1464: break;
1465:
1466: /* If not end-of-line, terminate argument. */
1467:
1468: if (buf[i])
1469: buf[i++] = 0;
1470:
1471: /* Read to next argument. */
1472:
1473: for ( ; buf[i] && ' ' == buf[i]; i++)
1474: /* Spin. */ ;
1475:
1476: /*
1477: * If we're a non-quoted string, try to look up the
1478: * value as a macro and execute it, if found.
1479: */
1480:
1481: c = quoted ? MDOC_MAX :
1.6 kristaps 1482: mdoc_hash_find(mdoc->htab, &buf[la]);
1.1 kristaps 1483:
1484: if (MDOC_MAX != c) {
1485: if ( ! mdoc_macro(mdoc, c, line, la, &i, buf))
1486: return(0);
1487: return(append_delims(mdoc, line, &i, buf));
1488: }
1489:
1490: /* A regular word or quoted string. */
1491:
1492: if ( ! mdoc_word_alloc(mdoc, line, la, &buf[la]))
1493: return(0);
1494: mdoc->next = MDOC_NEXT_SIBLING;
1495: }
1496:
1497: return(1);
1498: }
CVSweb