Annotation of mandoc/mdoc_macro.c, Revision 1.9
1.9 ! kristaps 1: /* $Id: mdoc_macro.c,v 1.8 2009/04/12 19:45:26 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 */
92: { in_line, MDOC_PARSED }, /* An */
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 */
104: { in_line, MDOC_PARSED }, /* Ft */
105: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
106: { in_line_eoln, 0 }, /* In */
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 */
148: { in_line, MDOC_PARSED }, /* Ms */
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 */
186: { in_line, MDOC_PARSED }, /* Lk */
187: { in_line, MDOC_PARSED }, /* Mt */
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 */
816: case (MDOC_Ar):
817: nc = 1;
818: break;
819: default:
820: nc = 0;
821: break;
822: }
823:
1.1 kristaps 824: for (la = ppos, arg = NULL;; ) {
825: la = *pos;
826: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
827:
828: if (ARGV_WORD == c) {
829: *pos = la;
830: break;
831: }
832: if (ARGV_EOLN == c)
833: break;
834: if (ARGV_ARG == c)
835: continue;
836:
837: mdoc_argv_free(arg);
838: return(0);
839: }
840:
1.4 kristaps 841: for (cnt = 0, lastpunct = 1;; ) {
1.1 kristaps 842: la = *pos;
843: w = mdoc_args(mdoc, line, pos, buf, tok, &p);
844:
845: if (ARGS_ERROR == w)
846: return(0);
847: if (ARGS_EOLN == w)
848: break;
849: if (ARGS_PUNCT == w)
850: break;
851:
852: /* Quoted words shouldn't be looked-up. */
853:
854: c = ARGS_QWORD == w ? MDOC_MAX :
855: lookup(mdoc, line, la, tok, p);
856:
1.4 kristaps 857: /*
858: * In this case, we've located a submacro and must
859: * execute it. Close out scope, if open. If no
860: * elements have been generated, either create one (nc)
861: * or raise a warning.
862: */
1.1 kristaps 863:
864: if (MDOC_MAX != c && -1 != c) {
865: if (0 == lastpunct && ! rew_elem(mdoc, tok))
866: return(0);
1.4 kristaps 867: if (nc && 0 == cnt) {
1.3 kristaps 868: if ( ! mdoc_elem_alloc(mdoc, line, ppos,
869: tok, arg))
870: return(0);
1.4 kristaps 871: mdoc->next = MDOC_NEXT_SIBLING;
1.7 kristaps 872: } else if ( ! nc && 0 == cnt) {
873: mdoc_argv_free(arg);
1.4 kristaps 874: if ( ! pwarn(mdoc, line, ppos, WIGNE))
1.3 kristaps 875: return(0);
1.7 kristaps 876: }
1.1 kristaps 877: c = mdoc_macro(mdoc, c, line, la, pos, buf);
878: if (0 == c)
879: return(0);
880: if (ppos > 1)
881: return(1);
882: return(append_delims(mdoc, line, pos, buf));
883: } else if (-1 == c)
884: return(0);
885:
1.4 kristaps 886: /*
887: * Non-quote-enclosed punctuation. Set up our scope, if
888: * a word; rewind the scope, if a delimiter; then append
889: * the word.
890: */
1.1 kristaps 891:
1.3 kristaps 892: d = mdoc_isdelim(p);
893:
894: if (ARGS_QWORD != w && d) {
1.1 kristaps 895: if (0 == lastpunct && ! rew_elem(mdoc, tok))
896: return(0);
897: lastpunct = 1;
898: } else if (lastpunct) {
899: c = mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
900: if (0 == c)
901: return(0);
902: mdoc->next = MDOC_NEXT_CHILD;
903: lastpunct = 0;
904: }
905:
1.3 kristaps 906: if ( ! d)
907: cnt++;
1.1 kristaps 908: if ( ! mdoc_word_alloc(mdoc, line, la, p))
909: return(0);
910: mdoc->next = MDOC_NEXT_SIBLING;
911: }
912:
913: if (0 == lastpunct && ! rew_elem(mdoc, tok))
914: return(0);
1.4 kristaps 915:
916: /*
917: * If no elements have been collected and we're allowed to have
918: * empties (nc), open a scope and close it out. Otherwise,
919: * raise a warning.
920: *
921: */
922: if (nc && 0 == cnt) {
1.3 kristaps 923: c = mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
924: if (0 == c)
925: return(0);
1.4 kristaps 926: mdoc->next = MDOC_NEXT_SIBLING;
1.7 kristaps 927: } else if ( ! nc && 0 == cnt) {
928: mdoc_argv_free(arg);
1.4 kristaps 929: if ( ! pwarn(mdoc, line, ppos, WIGNE))
1.3 kristaps 930: return(0);
1.7 kristaps 931: }
1.4 kristaps 932:
1.1 kristaps 933: if (ppos > 1)
934: return(1);
935: return(append_delims(mdoc, line, pos, buf));
936: }
937:
938:
939: /*
940: * Block full-explicit and full-implicit.
941: */
942: static int
943: blk_full(MACRO_PROT_ARGS)
944: {
945: int c, lastarg, reopen;
946: struct mdoc_arg *arg;
947: char *p;
948:
949: if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
950: if ( ! rew_subblock(MDOC_BODY, mdoc,
951: tok, line, ppos))
952: return(0);
953: if ( ! rew_impblock(mdoc, tok, line, ppos))
954: return(0);
955: }
956:
957: for (arg = NULL;; ) {
958: lastarg = *pos;
959: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
960:
961: if (ARGV_WORD == c) {
962: *pos = lastarg;
963: break;
964: }
965:
966: if (ARGV_EOLN == c)
967: break;
968: if (ARGV_ARG == c)
969: continue;
970:
971: mdoc_argv_free(arg);
972: return(0);
973: }
974:
975: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, arg))
976: return(0);
977: mdoc->next = MDOC_NEXT_CHILD;
978:
979: if (0 == buf[*pos]) {
980: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
981: return(0);
982: if ( ! rew_subblock(MDOC_HEAD, mdoc,
983: tok, line, ppos))
984: return(0);
985: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
986: return(0);
987: mdoc->next = MDOC_NEXT_CHILD;
988: return(1);
989: }
990:
991: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
992: return(0);
993: mdoc->next = MDOC_NEXT_CHILD;
994:
995: for (reopen = 0;; ) {
996: lastarg = *pos;
997: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
998:
999: if (ARGS_ERROR == c)
1000: return(0);
1001: if (ARGS_EOLN == c)
1002: break;
1003: if (ARGS_PHRASE == c) {
1004: if (reopen && ! mdoc_head_alloc
1005: (mdoc, line, ppos, tok))
1006: return(0);
1007: mdoc->next = MDOC_NEXT_CHILD;
1008: /*
1009: * Phrases are self-contained macro phrases used
1010: * in the columnar output of a macro. They need
1011: * special handling.
1012: */
1013: if ( ! phrase(mdoc, line, lastarg, buf))
1014: return(0);
1015: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1016: tok, line, ppos))
1017: return(0);
1018:
1019: reopen = 1;
1020: continue;
1021: }
1022:
1023: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1024: return(0);
1025:
1026: if (MDOC_MAX == c) {
1027: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1028: return(0);
1029: mdoc->next = MDOC_NEXT_SIBLING;
1030: continue;
1031: }
1032:
1033: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1034: return(0);
1035: break;
1036: }
1037:
1038: if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
1039: return(0);
1040: if ( ! rew_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1041: return(0);
1042:
1043: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1044: return(0);
1045: mdoc->next = MDOC_NEXT_CHILD;
1046:
1047: return(1);
1048: }
1049:
1050:
1051: /*
1052: * Block partial-imnplicit scope.
1053: */
1054: static int
1055: blk_part_imp(MACRO_PROT_ARGS)
1056: {
1057: int lastarg, c;
1058: char *p;
1059: struct mdoc_node *blk, *body, *n;
1060:
1061: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
1062: return(0);
1063: mdoc->next = MDOC_NEXT_CHILD;
1064: blk = mdoc->last;
1065:
1066: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1067: return(0);
1068: mdoc->next = MDOC_NEXT_SIBLING;
1069:
1070: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1071: return(0);
1072: mdoc->next = MDOC_NEXT_CHILD;
1073: body = mdoc->last;
1074:
1075: /* XXX - no known argument macros. */
1076:
1077: for (lastarg = ppos;; ) {
1078: lastarg = *pos;
1079: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1080: assert(ARGS_PHRASE != c);
1081:
1082: if (ARGS_ERROR == c)
1083: return(0);
1084: if (ARGS_PUNCT == c)
1085: break;
1086: if (ARGS_EOLN == c)
1087: break;
1088:
1089: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1090: return(0);
1091: else if (MDOC_MAX == c) {
1092: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1093: return(0);
1094: mdoc->next = MDOC_NEXT_SIBLING;
1095: continue;
1096: }
1097:
1098: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1099: return(0);
1100: break;
1101: }
1102:
1103: /*
1104: * Since we know what our context is, we can rewind directly to
1105: * it. This allows us to accomodate for our scope being
1106: * violated by another token.
1107: */
1108:
1109: for (n = mdoc->last; n; n = n->parent)
1110: if (body == n)
1111: break;
1112:
1113: if (NULL == n && ! pwarn(mdoc, body->line, body->pos, WIMPBRK))
1114: return(0);
1115:
1116: if (n && ! rew_last(mdoc, body))
1117: return(0);
1118:
1119: if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
1120: return(0);
1121:
1122: if (n && ! rew_last(mdoc, blk))
1123: return(0);
1124:
1125: return(1);
1126: }
1127:
1128:
1129: /*
1130: * Block partial-explicit macros.
1131: */
1132: static int
1133: blk_part_exp(MACRO_PROT_ARGS)
1134: {
1135: int lastarg, flushed, j, c, maxargs;
1136: char *p;
1137:
1138: lastarg = ppos;
1139: flushed = 0;
1140:
1141: /*
1142: * Number of arguments (head arguments). Only `Eo' has these,
1143: */
1144:
1145: switch (tok) {
1146: case (MDOC_Eo):
1147: maxargs = 1;
1148: break;
1149: default:
1150: maxargs = 0;
1151: break;
1152: }
1153:
1154: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
1155: return(0);
1156: mdoc->next = MDOC_NEXT_CHILD;
1157:
1158: if (0 == maxargs) {
1159: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1160: return(0);
1161: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1162: tok, line, ppos))
1163: return(0);
1164: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1165: return(0);
1166: flushed = 1;
1167: } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1168: return(0);
1169:
1170: mdoc->next = MDOC_NEXT_CHILD;
1171:
1172: for (j = 0; ; j++) {
1173: lastarg = *pos;
1174: if (j == maxargs && ! flushed) {
1175: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1176: tok, line, ppos))
1177: return(0);
1178: flushed = 1;
1179: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1180: return(0);
1181: mdoc->next = MDOC_NEXT_CHILD;
1182: }
1183:
1184: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1185: assert(ARGS_PHRASE != c);
1186:
1187: if (ARGS_ERROR == c)
1188: return(0);
1189: if (ARGS_PUNCT == c)
1190: break;
1191: if (ARGS_EOLN == c)
1192: break;
1193:
1194: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1195: return(0);
1196: else if (MDOC_MAX != c) {
1197: if ( ! flushed) {
1198: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1199: tok, line, ppos))
1200: return(0);
1201: flushed = 1;
1202: if ( ! mdoc_body_alloc(mdoc, line,
1203: ppos, tok))
1204: return(0);
1205: mdoc->next = MDOC_NEXT_CHILD;
1206: }
1207: if ( ! mdoc_macro(mdoc, c, line, lastarg,
1208: pos, buf))
1209: return(0);
1210: break;
1211: }
1212:
1213: if ( ! flushed && mdoc_isdelim(p)) {
1214: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1215: tok, line, ppos))
1216: return(0);
1217: flushed = 1;
1218: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1219: return(0);
1220: mdoc->next = MDOC_NEXT_CHILD;
1221: }
1222:
1223: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1224: return(0);
1225: mdoc->next = MDOC_NEXT_SIBLING;
1226: }
1227:
1228: if ( ! flushed) {
1229: if ( ! rew_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1230: return(0);
1231: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1232: return(0);
1233: mdoc->next = MDOC_NEXT_CHILD;
1234: }
1235:
1236: if (ppos > 1)
1237: return(1);
1238: return(append_delims(mdoc, line, pos, buf));
1239: }
1240:
1241:
1242: /*
1243: * In-line macros where reserved words signal closure of the macro.
1244: * Macros also have a fixed number of arguments.
1245: */
1246: static int
1247: in_line_argn(MACRO_PROT_ARGS)
1248: {
1249: int lastarg, flushed, j, c, maxargs;
1250: struct mdoc_arg *arg;
1251: char *p;
1252:
1253:
1254: /*
1255: * Fixed maximum arguments per macro. Some of these have none
1256: * and close as soon as the invocation is parsed.
1257: */
1258:
1259: switch (tok) {
1260: case (MDOC_Ap):
1261: /* FALLTHROUGH */
1262: case (MDOC_No):
1263: /* FALLTHROUGH */
1264: case (MDOC_Ns):
1265: /* FALLTHROUGH */
1266: case (MDOC_Ux):
1267: maxargs = 0;
1268: break;
1269: default:
1270: maxargs = 1;
1271: break;
1272: }
1273:
1274: for (lastarg = ppos, arg = NULL;; ) {
1275: lastarg = *pos;
1276: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1277:
1278: if (ARGV_WORD == c) {
1279: *pos = lastarg;
1280: break;
1281: }
1282:
1283: if (ARGV_EOLN == c)
1284: break;
1285: if (ARGV_ARG == c)
1286: continue;
1287:
1288: mdoc_argv_free(arg);
1289: return(0);
1290: }
1291:
1292: if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1293: return(0);
1294: mdoc->next = MDOC_NEXT_CHILD;
1295:
1296: for (flushed = j = 0; ; j++) {
1297: lastarg = *pos;
1298:
1299: if (j == maxargs && ! flushed) {
1300: if ( ! rew_elem(mdoc, tok))
1301: return(0);
1302: flushed = 1;
1303: }
1304:
1305: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1306:
1307: if (ARGS_ERROR == c)
1308: return(0);
1309: if (ARGS_PUNCT == c)
1310: break;
1311: if (ARGS_EOLN == c)
1312: break;
1313:
1314: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1315: return(0);
1316: else if (MDOC_MAX != c) {
1317: if ( ! flushed && ! rew_elem(mdoc, tok))
1318: return(0);
1319: flushed = 1;
1320: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1321: return(0);
1322: break;
1323: }
1324:
1325: if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
1326: ! flushed && mdoc_isdelim(p)) {
1327: if ( ! rew_elem(mdoc, tok))
1328: return(0);
1329: flushed = 1;
1330: }
1331:
1332: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1333: return(0);
1334: mdoc->next = MDOC_NEXT_SIBLING;
1335: }
1336:
1337: if ( ! flushed && ! rew_elem(mdoc, tok))
1338: return(0);
1339:
1340: if (ppos > 1)
1341: return(1);
1342: return(append_delims(mdoc, line, pos, buf));
1343: }
1344:
1345:
1346: /*
1347: * In-line macro that spans an entire line. May be callable, but has no
1348: * subsequent parsed arguments.
1349: */
1350: static int
1351: in_line_eoln(MACRO_PROT_ARGS)
1352: {
1353: int c, w, la;
1354: struct mdoc_arg *arg;
1355: char *p;
1356:
1357: assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));
1358:
1359: arg = NULL;
1360:
1361: for (;;) {
1362: la = *pos;
1363: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1364:
1365: if (ARGV_WORD == c) {
1366: *pos = la;
1367: break;
1368: }
1369: if (ARGV_EOLN == c)
1370: break;
1371: if (ARGV_ARG == c)
1372: continue;
1373:
1374: mdoc_argv_free(arg);
1375: return(0);
1376: }
1377:
1378: if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1379: return(0);
1380:
1381: mdoc->next = MDOC_NEXT_CHILD;
1382:
1383: for (;;) {
1384: la = *pos;
1385: w = mdoc_args(mdoc, line, pos, buf, tok, &p);
1386:
1387: if (ARGS_ERROR == w)
1388: return(0);
1389: if (ARGS_EOLN == w)
1390: break;
1391:
1392: c = ARGS_QWORD == w ? MDOC_MAX :
1393: lookup(mdoc, line, la, tok, p);
1394:
1395: if (MDOC_MAX != c && -1 != c) {
1396: if ( ! rew_elem(mdoc, tok))
1397: return(0);
1398: return(mdoc_macro(mdoc, c, line, la, pos, buf));
1399: } else if (-1 == c)
1400: return(0);
1401:
1402: if ( ! mdoc_word_alloc(mdoc, line, la, p))
1403: return(0);
1404: mdoc->next = MDOC_NEXT_SIBLING;
1405: }
1406:
1407: return(rew_elem(mdoc, tok));
1408: }
1409:
1410:
1411: /* ARGSUSED */
1412: static int
1413: obsolete(MACRO_PROT_ARGS)
1414: {
1415:
1416: return(pwarn(mdoc, line, ppos, WOBS));
1417: }
1418:
1419:
1420: static int
1421: phrase(struct mdoc *mdoc, int line, int ppos, char *buf)
1422: {
1423: int i, la, c, quoted;
1424:
1425: /*
1426: * Parse over words in a phrase. We have to handle this
1427: * specially because we assume no calling context -- in normal
1428: * circumstances, we switch argument parsing based on whether
1429: * the parent macro accepts quotes, tabs, etc. Here, anything
1430: * goes.
1431: */
1432:
1433: for (i = ppos; buf[i]; ) {
1434: assert(' ' != buf[i]);
1435: la = i;
1436: quoted = 0;
1437:
1438: /*
1439: * Read to next token. If quoted (check not escaped),
1440: * scan ahead to next unescaped quote. If not quoted or
1441: * escape-quoted, then scan ahead to next space.
1442: */
1443:
1444: if ((i && '\"' == buf[i] && '\\' != buf[i - 1]) ||
1445: (0 == i && '\"' == buf[i])) {
1446: for (la = ++i; buf[i]; i++)
1447: if ('\"' != buf[i])
1448: continue;
1449: else if ('\\' != buf[i - 1])
1450: break;
1451: if (0 == buf[i])
1452: return(perr(mdoc, line, la, EQUOT));
1453: quoted = 1;
1454: } else
1455: for ( ; buf[i]; i++)
1456: if (i && ' ' == buf[i]) {
1457: if ('\\' != buf[i - 1])
1458: break;
1459: } else if (' ' == buf[i])
1460: break;
1461:
1462: /* If not end-of-line, terminate argument. */
1463:
1464: if (buf[i])
1465: buf[i++] = 0;
1466:
1467: /* Read to next argument. */
1468:
1469: for ( ; buf[i] && ' ' == buf[i]; i++)
1470: /* Spin. */ ;
1471:
1472: /*
1473: * If we're a non-quoted string, try to look up the
1474: * value as a macro and execute it, if found.
1475: */
1476:
1477: c = quoted ? MDOC_MAX :
1.6 kristaps 1478: mdoc_hash_find(mdoc->htab, &buf[la]);
1.1 kristaps 1479:
1480: if (MDOC_MAX != c) {
1481: if ( ! mdoc_macro(mdoc, c, line, la, &i, buf))
1482: return(0);
1483: return(append_delims(mdoc, line, &i, buf));
1484: }
1485:
1486: /* A regular word or quoted string. */
1487:
1488: if ( ! mdoc_word_alloc(mdoc, line, la, &buf[la]))
1489: return(0);
1490: mdoc->next = MDOC_NEXT_SIBLING;
1491: }
1492:
1493: return(1);
1494: }
CVSweb