Annotation of src/usr.bin/mandoc/mdoc_macro.c, Revision 1.43
1.43 ! schwarze 1: /* $Id: mdoc_macro.c,v 1.42 2010/05/15 15:37:53 schwarze Exp $ */
1.1 kristaps 2: /*
1.2 schwarze 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.2 schwarze 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.2 schwarze 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 16: */
17: #include <assert.h>
18: #include <ctype.h>
19: #include <stdlib.h>
20: #include <stdio.h>
21: #include <string.h>
1.26 schwarze 22: #include <time.h>
1.1 kristaps 23:
24: #include "libmdoc.h"
1.39 schwarze 25: #include "libmandoc.h"
1.1 kristaps 26:
1.35 schwarze 27: enum rew {
28: REWIND_REWIND,
29: REWIND_NOHALT,
30: REWIND_HALT
31: };
1.1 kristaps 32:
1.36 schwarze 33: static int blk_full(MACRO_PROT_ARGS);
34: static int blk_exp_close(MACRO_PROT_ARGS);
35: static int blk_part_exp(MACRO_PROT_ARGS);
36: static int blk_part_imp(MACRO_PROT_ARGS);
37: static int ctx_synopsis(MACRO_PROT_ARGS);
38: static int in_line_eoln(MACRO_PROT_ARGS);
39: static int in_line_argn(MACRO_PROT_ARGS);
40: static int in_line(MACRO_PROT_ARGS);
41: static int obsolete(MACRO_PROT_ARGS);
42:
43: static int append_delims(struct mdoc *,
44: int, int *, char *);
45: static enum mdoct lookup(enum mdoct, const char *);
46: static enum mdoct lookup_raw(const char *);
1.37 schwarze 47: static int phrase(struct mdoc *, int, int,
1.41 schwarze 48: char *, enum margserr);
1.36 schwarze 49: static enum mdoct rew_alt(enum mdoct);
50: static int rew_dobreak(enum mdoct,
51: const struct mdoc_node *);
52: static enum rew rew_dohalt(enum mdoct, enum mdoc_type,
53: const struct mdoc_node *);
54: static int rew_elem(struct mdoc *, enum mdoct);
55: static int rew_last(struct mdoc *,
56: const struct mdoc_node *);
57: static int rew_sub(enum mdoc_type, struct mdoc *,
58: enum mdoct, int, int);
59: static int swarn(struct mdoc *, enum mdoc_type, int,
60: int, const struct mdoc_node *);
1.1 kristaps 61:
62: const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
1.4 schwarze 63: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */
1.1 kristaps 64: { in_line_eoln, MDOC_PROLOGUE }, /* Dd */
65: { in_line_eoln, MDOC_PROLOGUE }, /* Dt */
66: { in_line_eoln, MDOC_PROLOGUE }, /* Os */
67: { blk_full, 0 }, /* Sh */
68: { blk_full, 0 }, /* Ss */
1.16 schwarze 69: { in_line_eoln, 0 }, /* Pp */
1.1 kristaps 70: { blk_part_imp, MDOC_PARSED }, /* D1 */
71: { blk_part_imp, MDOC_PARSED }, /* Dl */
72: { blk_full, MDOC_EXPLICIT }, /* Bd */
73: { blk_exp_close, MDOC_EXPLICIT }, /* Ed */
74: { blk_full, MDOC_EXPLICIT }, /* Bl */
75: { blk_exp_close, MDOC_EXPLICIT }, /* El */
76: { blk_full, MDOC_PARSED }, /* It */
77: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
1.3 schwarze 78: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* An */
1.1 kristaps 79: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
1.15 schwarze 80: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cd */
1.1 kristaps 81: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
82: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
83: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
84: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
85: { in_line_eoln, 0 }, /* Ex */
86: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
87: { in_line_eoln, 0 }, /* Fd */
88: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
89: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
1.3 schwarze 90: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */
1.1 kristaps 91: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
1.11 schwarze 92: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */
1.1 kristaps 93: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */
1.12 schwarze 94: { blk_full, 0 }, /* Nd */
1.1 kristaps 95: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
96: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
97: { obsolete, 0 }, /* Ot */
98: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
99: { in_line_eoln, 0 }, /* Rv */
100: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */
101: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
1.28 schwarze 102: { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
103: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
1.1 kristaps 104: { in_line_eoln, 0 }, /* %A */
105: { in_line_eoln, 0 }, /* %B */
106: { in_line_eoln, 0 }, /* %D */
107: { in_line_eoln, 0 }, /* %I */
108: { in_line_eoln, 0 }, /* %J */
109: { in_line_eoln, 0 }, /* %N */
110: { in_line_eoln, 0 }, /* %O */
111: { in_line_eoln, 0 }, /* %P */
112: { in_line_eoln, 0 }, /* %R */
113: { in_line_eoln, 0 }, /* %T */
114: { in_line_eoln, 0 }, /* %V */
115: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */
116: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */
117: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */
118: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */
119: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */
120: { blk_full, MDOC_EXPLICIT }, /* Bf */
121: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */
122: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */
123: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */
124: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */
125: { in_line_eoln, 0 }, /* Db */
126: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */
127: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */
128: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */
129: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */
130: { blk_exp_close, MDOC_EXPLICIT }, /* Ef */
131: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Em */
132: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
133: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */
1.3 schwarze 134: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */
1.1 kristaps 135: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* No */
136: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ns */
137: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */
138: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */
139: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */
1.35 schwarze 140: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */
1.1 kristaps 141: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */
142: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */
143: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */
144: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */
145: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */
146: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */
147: { blk_exp_close, MDOC_EXPLICIT }, /* Re */
148: { blk_full, MDOC_EXPLICIT }, /* Rs */
149: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */
150: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */
151: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */
152: { in_line_eoln, 0 }, /* Sm */
153: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */
154: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */
155: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
156: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ux */
157: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
158: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
159: { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */
160: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */
161: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */
162: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */
163: { blk_full, MDOC_EXPLICIT }, /* Bk */
164: { blk_exp_close, MDOC_EXPLICIT }, /* Ek */
165: { in_line_eoln, 0 }, /* Bt */
166: { in_line_eoln, 0 }, /* Hf */
167: { obsolete, 0 }, /* Fr */
168: { in_line_eoln, 0 }, /* Ud */
169: { in_line_eoln, 0 }, /* Lb */
1.16 schwarze 170: { in_line_eoln, 0 }, /* Lp */
1.3 schwarze 171: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */
172: { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */
1.1 kristaps 173: { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Brq */
174: { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */
175: { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */
176: { in_line_eoln, 0 }, /* %C */
177: { obsolete, 0 }, /* Es */
178: { obsolete, 0 }, /* En */
179: { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */
180: { in_line_eoln, 0 }, /* %Q */
1.13 schwarze 181: { in_line_eoln, 0 }, /* br */
182: { in_line_eoln, 0 }, /* sp */
1.25 schwarze 183: { in_line_eoln, 0 }, /* %U */
1.1 kristaps 184: };
185:
186: const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
187:
188:
189: static int
190: swarn(struct mdoc *mdoc, enum mdoc_type type,
191: int line, int pos, const struct mdoc_node *p)
192: {
193: const char *n, *t, *tt;
194:
195: n = t = "<root>";
196: tt = "block";
197:
198: switch (type) {
199: case (MDOC_BODY):
200: tt = "multi-line";
201: break;
202: case (MDOC_HEAD):
203: tt = "line";
204: break;
205: default:
206: break;
207: }
208:
209: switch (p->type) {
210: case (MDOC_BLOCK):
211: n = mdoc_macronames[p->tok];
212: t = "block";
213: break;
214: case (MDOC_BODY):
215: n = mdoc_macronames[p->tok];
216: t = "multi-line";
217: break;
218: case (MDOC_HEAD):
219: n = mdoc_macronames[p->tok];
220: t = "line";
221: break;
222: default:
223: break;
224: }
225:
226: if ( ! (MDOC_IGN_SCOPE & mdoc->pflags))
1.6 schwarze 227: return(mdoc_verr(mdoc, line, pos,
1.1 kristaps 228: "%s scope breaks %s scope of %s",
229: tt, t, n));
1.5 schwarze 230: return(mdoc_vwarn(mdoc, line, pos,
1.1 kristaps 231: "%s scope breaks %s scope of %s",
232: tt, t, n));
233: }
234:
235:
236: /*
237: * This is called at the end of parsing. It must traverse up the tree,
238: * closing out open [implicit] scopes. Obviously, open explicit scopes
239: * are errors.
240: */
241: int
1.22 schwarze 242: mdoc_macroend(struct mdoc *m)
1.1 kristaps 243: {
244: struct mdoc_node *n;
245:
246: /* Scan for open explicit scopes. */
247:
1.22 schwarze 248: n = MDOC_VALID & m->last->flags ? m->last->parent : m->last;
1.1 kristaps 249:
250: for ( ; n; n = n->parent) {
251: if (MDOC_BLOCK != n->type)
252: continue;
253: if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags))
254: continue;
1.22 schwarze 255: return(mdoc_nerr(m, n, EOPEN));
1.1 kristaps 256: }
257:
1.22 schwarze 258: /* Rewind to the first. */
259:
260: return(rew_last(m, m->first));
1.1 kristaps 261: }
262:
1.22 schwarze 263:
264: /*
265: * Look up a macro from within a subsequent context.
266: */
1.36 schwarze 267: static enum mdoct
268: lookup(enum mdoct from, const char *p)
1.21 schwarze 269: {
1.24 schwarze 270: /* FIXME: make -diag lists be un-PARSED. */
1.21 schwarze 271:
272: if ( ! (MDOC_PARSED & mdoc_macros[from].flags))
273: return(MDOC_MAX);
1.24 schwarze 274: return(lookup_raw(p));
1.21 schwarze 275: }
276:
277:
1.22 schwarze 278: /*
279: * Lookup a macro following the initial line macro.
280: */
1.36 schwarze 281: static enum mdoct
1.24 schwarze 282: lookup_raw(const char *p)
1.1 kristaps 283: {
1.36 schwarze 284: enum mdoct res;
1.1 kristaps 285:
1.24 schwarze 286: if (MDOC_MAX == (res = mdoc_hash_find(p)))
1.21 schwarze 287: return(MDOC_MAX);
288: if (MDOC_CALLABLE & mdoc_macros[res].flags)
1.1 kristaps 289: return(res);
290: return(MDOC_MAX);
291: }
292:
293:
294: static int
1.22 schwarze 295: rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
1.1 kristaps 296: {
297:
298: assert(to);
299: mdoc->next = MDOC_NEXT_SIBLING;
300:
301: /* LINTED */
302: while (mdoc->last != to) {
303: if ( ! mdoc_valid_post(mdoc))
304: return(0);
305: if ( ! mdoc_action_post(mdoc))
306: return(0);
307: mdoc->last = mdoc->last->parent;
308: assert(mdoc->last);
309: }
310:
311: if ( ! mdoc_valid_post(mdoc))
312: return(0);
313: return(mdoc_action_post(mdoc));
314: }
315:
316:
1.22 schwarze 317: /*
318: * Return the opening macro of a closing one, e.g., `Ec' has `Eo' as its
319: * matching pair.
320: */
1.34 schwarze 321: static enum mdoct
322: rew_alt(enum mdoct tok)
1.1 kristaps 323: {
324: switch (tok) {
325: case (MDOC_Ac):
326: return(MDOC_Ao);
327: case (MDOC_Bc):
328: return(MDOC_Bo);
329: case (MDOC_Brc):
330: return(MDOC_Bro);
331: case (MDOC_Dc):
332: return(MDOC_Do);
333: case (MDOC_Ec):
334: return(MDOC_Eo);
335: case (MDOC_Ed):
336: return(MDOC_Bd);
337: case (MDOC_Ef):
338: return(MDOC_Bf);
339: case (MDOC_Ek):
340: return(MDOC_Bk);
341: case (MDOC_El):
342: return(MDOC_Bl);
343: case (MDOC_Fc):
344: return(MDOC_Fo);
345: case (MDOC_Oc):
346: return(MDOC_Oo);
347: case (MDOC_Pc):
348: return(MDOC_Po);
349: case (MDOC_Qc):
350: return(MDOC_Qo);
351: case (MDOC_Re):
352: return(MDOC_Rs);
353: case (MDOC_Sc):
354: return(MDOC_So);
355: case (MDOC_Xc):
356: return(MDOC_Xo);
357: default:
358: break;
359: }
360: abort();
361: /* NOTREACHED */
362: }
363:
364:
365: /*
366: * Rewind rules. This indicates whether to stop rewinding
367: * (REWIND_HALT) without touching our current scope, stop rewinding and
368: * close our current scope (REWIND_REWIND), or continue (REWIND_NOHALT).
369: * The scope-closing and so on occurs in the various rew_* routines.
370: */
1.35 schwarze 371: static enum rew
1.34 schwarze 372: rew_dohalt(enum mdoct tok, enum mdoc_type type,
373: const struct mdoc_node *p)
1.1 kristaps 374: {
375:
376: if (MDOC_ROOT == p->type)
377: return(REWIND_HALT);
378: if (MDOC_VALID & p->flags)
379: return(REWIND_NOHALT);
380:
381: switch (tok) {
382: case (MDOC_Aq):
383: /* FALLTHROUGH */
384: case (MDOC_Bq):
385: /* FALLTHROUGH */
386: case (MDOC_Brq):
387: /* FALLTHROUGH */
388: case (MDOC_D1):
389: /* FALLTHROUGH */
390: case (MDOC_Dl):
391: /* FALLTHROUGH */
392: case (MDOC_Dq):
393: /* FALLTHROUGH */
394: case (MDOC_Op):
395: /* FALLTHROUGH */
396: case (MDOC_Pq):
397: /* FALLTHROUGH */
398: case (MDOC_Ql):
399: /* FALLTHROUGH */
400: case (MDOC_Qq):
401: /* FALLTHROUGH */
402: case (MDOC_Sq):
1.28 schwarze 403: /* FALLTHROUGH */
404: case (MDOC_Vt):
1.1 kristaps 405: assert(MDOC_TAIL != type);
406: if (type == p->type && tok == p->tok)
407: return(REWIND_REWIND);
408: break;
409: case (MDOC_It):
410: assert(MDOC_TAIL != type);
411: if (type == p->type && tok == p->tok)
412: return(REWIND_REWIND);
413: if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
414: return(REWIND_HALT);
415: break;
416: case (MDOC_Sh):
417: if (type == p->type && tok == p->tok)
418: return(REWIND_REWIND);
419: break;
1.12 schwarze 420: case (MDOC_Nd):
421: /* FALLTHROUGH */
1.1 kristaps 422: case (MDOC_Ss):
423: assert(MDOC_TAIL != type);
424: if (type == p->type && tok == p->tok)
425: return(REWIND_REWIND);
426: if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
427: return(REWIND_HALT);
428: break;
429: case (MDOC_Ao):
430: /* FALLTHROUGH */
431: case (MDOC_Bd):
432: /* FALLTHROUGH */
433: case (MDOC_Bf):
434: /* FALLTHROUGH */
435: case (MDOC_Bk):
436: /* FALLTHROUGH */
437: case (MDOC_Bl):
438: /* FALLTHROUGH */
439: case (MDOC_Bo):
440: /* FALLTHROUGH */
441: case (MDOC_Bro):
442: /* FALLTHROUGH */
443: case (MDOC_Do):
444: /* FALLTHROUGH */
445: case (MDOC_Eo):
446: /* FALLTHROUGH */
447: case (MDOC_Fo):
448: /* FALLTHROUGH */
449: case (MDOC_Oo):
450: /* FALLTHROUGH */
451: case (MDOC_Po):
452: /* FALLTHROUGH */
453: case (MDOC_Qo):
454: /* FALLTHROUGH */
455: case (MDOC_Rs):
456: /* FALLTHROUGH */
457: case (MDOC_So):
458: /* FALLTHROUGH */
459: case (MDOC_Xo):
460: if (type == p->type && tok == p->tok)
461: return(REWIND_REWIND);
462: break;
463: /* Multi-line explicit scope close. */
464: case (MDOC_Ac):
465: /* FALLTHROUGH */
466: case (MDOC_Bc):
467: /* FALLTHROUGH */
468: case (MDOC_Brc):
469: /* FALLTHROUGH */
470: case (MDOC_Dc):
471: /* FALLTHROUGH */
472: case (MDOC_Ec):
473: /* FALLTHROUGH */
474: case (MDOC_Ed):
475: /* FALLTHROUGH */
476: case (MDOC_Ek):
477: /* FALLTHROUGH */
478: case (MDOC_El):
479: /* FALLTHROUGH */
480: case (MDOC_Fc):
481: /* FALLTHROUGH */
482: case (MDOC_Ef):
483: /* FALLTHROUGH */
484: case (MDOC_Oc):
485: /* FALLTHROUGH */
486: case (MDOC_Pc):
487: /* FALLTHROUGH */
488: case (MDOC_Qc):
489: /* FALLTHROUGH */
490: case (MDOC_Re):
491: /* FALLTHROUGH */
492: case (MDOC_Sc):
493: /* FALLTHROUGH */
494: case (MDOC_Xc):
495: if (type == p->type && rew_alt(tok) == p->tok)
496: return(REWIND_REWIND);
497: break;
498: default:
499: abort();
500: /* NOTREACHED */
501: }
502:
503: return(REWIND_NOHALT);
504: }
505:
506:
507: /*
508: * See if we can break an encountered scope (the rew_dohalt has returned
509: * REWIND_NOHALT).
510: */
511: static int
1.34 schwarze 512: rew_dobreak(enum mdoct tok, const struct mdoc_node *p)
1.1 kristaps 513: {
514:
515: assert(MDOC_ROOT != p->type);
516: if (MDOC_ELEM == p->type)
517: return(1);
518: if (MDOC_TEXT == p->type)
519: return(1);
520: if (MDOC_VALID & p->flags)
521: return(1);
522:
523: switch (tok) {
524: case (MDOC_It):
525: return(MDOC_It == p->tok);
1.12 schwarze 526: case (MDOC_Nd):
527: return(MDOC_Nd == p->tok);
1.1 kristaps 528: case (MDOC_Ss):
529: return(MDOC_Ss == p->tok);
530: case (MDOC_Sh):
1.12 schwarze 531: if (MDOC_Nd == p->tok)
532: return(1);
1.1 kristaps 533: if (MDOC_Ss == p->tok)
534: return(1);
535: return(MDOC_Sh == p->tok);
536: case (MDOC_El):
537: if (MDOC_It == p->tok)
538: return(1);
539: break;
540: case (MDOC_Oc):
541: if (MDOC_Op == p->tok)
542: return(1);
543: break;
544: default:
545: break;
546: }
547:
548: if (MDOC_EXPLICIT & mdoc_macros[tok].flags)
549: return(p->tok == rew_alt(tok));
550: else if (MDOC_BLOCK == p->type)
551: return(1);
552:
553: return(tok == p->tok);
554: }
555:
556:
557: static int
1.34 schwarze 558: rew_elem(struct mdoc *mdoc, enum mdoct tok)
1.1 kristaps 559: {
560: struct mdoc_node *n;
561:
562: n = mdoc->last;
563: if (MDOC_ELEM != n->type)
564: n = n->parent;
565: assert(MDOC_ELEM == n->type);
566: assert(tok == n->tok);
567:
568: return(rew_last(mdoc, n));
569: }
570:
571:
572: static int
1.22 schwarze 573: rew_sub(enum mdoc_type t, struct mdoc *m,
1.34 schwarze 574: enum mdoct tok, int line, int ppos)
1.1 kristaps 575: {
576: struct mdoc_node *n;
1.35 schwarze 577: enum rew c;
1.1 kristaps 578:
579: /* LINTED */
1.22 schwarze 580: for (n = m->last; n; n = n->parent) {
581: c = rew_dohalt(tok, t, n);
582: if (REWIND_HALT == c) {
583: if (MDOC_BLOCK != t)
584: return(1);
585: if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags))
586: return(1);
587: return(mdoc_perr(m, line, ppos, ENOCTX));
588: }
1.1 kristaps 589: if (REWIND_REWIND == c)
590: break;
591: else if (rew_dobreak(tok, n))
592: continue;
1.22 schwarze 593: if ( ! swarn(m, t, line, ppos, n))
1.1 kristaps 594: return(0);
595: }
596:
597: assert(n);
1.29 schwarze 598: if ( ! rew_last(m, n))
599: return(0);
600:
601: /*
1.34 schwarze 602: * The current block extends an enclosing block beyond a line
603: * break. Now that the current block ends, close the enclosing
604: * block, too.
1.29 schwarze 605: */
1.34 schwarze 606: if (NULL != (n = n->pending)) {
1.29 schwarze 607: assert(MDOC_HEAD == n->type);
608: if ( ! rew_last(m, n))
609: return(0);
610: if ( ! mdoc_body_alloc(m, n->line, n->pos, n->tok))
611: return(0);
612: }
613: return(1);
1.1 kristaps 614: }
615:
616:
617: static int
1.42 schwarze 618: append_delims(struct mdoc *m, int line, int *pos, char *buf)
1.1 kristaps 619: {
1.42 schwarze 620: int la;
1.36 schwarze 621: enum margserr ac;
1.1 kristaps 622: char *p;
623:
1.42 schwarze 624: if ('\0' == buf[*pos])
1.1 kristaps 625: return(1);
626:
627: for (;;) {
1.42 schwarze 628: la = *pos;
629: ac = mdoc_zargs(m, line, pos, buf, ARGS_NOWARN, &p);
1.1 kristaps 630:
1.36 schwarze 631: if (ARGS_ERROR == ac)
1.1 kristaps 632: return(0);
1.36 schwarze 633: else if (ARGS_EOLN == ac)
1.1 kristaps 634: break;
1.42 schwarze 635:
1.40 schwarze 636: assert(DELIM_NONE != mdoc_isdelim(p));
1.42 schwarze 637: if ( ! mdoc_word_alloc(m, line, la, p))
1.1 kristaps 638: return(0);
1.43 ! schwarze 639:
1.42 schwarze 640: /*
641: * If we encounter end-of-sentence symbols, then trigger
642: * the double-space.
643: *
644: * XXX: it's easy to allow this to propogate outward to
645: * the last symbol, such that `. )' will cause the
646: * correct double-spacing. However, (1) groff isn't
647: * smart enough to do this and (2) it would require
648: * knowing which symbols break this behaviour, for
649: * example, `. ;' shouldn't propogate the double-space.
650: */
651: if (mandoc_eos(p, strlen(p)))
652: m->last->flags |= MDOC_EOS;
1.1 kristaps 653: }
654:
655: return(1);
656: }
657:
658:
659: /*
660: * Close out block partial/full explicit.
661: */
662: static int
663: blk_exp_close(MACRO_PROT_ARGS)
664: {
1.37 schwarze 665: int j, lastarg, maxargs, flushed, nl;
1.36 schwarze 666: enum margserr ac;
667: enum mdoct ntok;
1.1 kristaps 668: char *p;
669:
1.37 schwarze 670: nl = MDOC_NEWLINE & m->flags;
671:
1.1 kristaps 672: switch (tok) {
673: case (MDOC_Ec):
674: maxargs = 1;
675: break;
676: default:
677: maxargs = 0;
678: break;
679: }
680:
681: if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
1.14 schwarze 682: if (buf[*pos])
1.22 schwarze 683: if ( ! mdoc_pwarn(m, line, ppos, ENOLINE))
1.1 kristaps 684: return(0);
1.14 schwarze 685:
1.22 schwarze 686: if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
1.14 schwarze 687: return(0);
1.22 schwarze 688: return(rew_sub(MDOC_BLOCK, m, tok, line, ppos));
1.1 kristaps 689: }
690:
1.22 schwarze 691: if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
1.1 kristaps 692: return(0);
693:
1.22 schwarze 694: if (maxargs > 0)
695: if ( ! mdoc_tail_alloc(m, line, ppos, rew_alt(tok)))
1.1 kristaps 696: return(0);
697:
1.20 schwarze 698: for (flushed = j = 0; ; j++) {
1.1 kristaps 699: lastarg = *pos;
700:
701: if (j == maxargs && ! flushed) {
1.22 schwarze 702: if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
1.1 kristaps 703: return(0);
704: flushed = 1;
705: }
706:
1.36 schwarze 707: ac = mdoc_args(m, line, pos, buf, tok, &p);
1.1 kristaps 708:
1.36 schwarze 709: if (ARGS_ERROR == ac)
1.1 kristaps 710: return(0);
1.36 schwarze 711: if (ARGS_PUNCT == ac)
1.1 kristaps 712: break;
1.36 schwarze 713: if (ARGS_EOLN == ac)
1.1 kristaps 714: break;
715:
1.36 schwarze 716: ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
717:
718: if (MDOC_MAX == ntok) {
719: if ( ! mdoc_word_alloc(m, line, lastarg, p))
1.1 kristaps 720: return(0);
1.36 schwarze 721: continue;
722: }
1.1 kristaps 723:
1.36 schwarze 724: if ( ! flushed) {
725: if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
726: return(0);
727: flushed = 1;
728: }
729: if ( ! mdoc_macro(m, ntok, line, lastarg, pos, buf))
1.1 kristaps 730: return(0);
1.36 schwarze 731: break;
1.1 kristaps 732: }
733:
1.22 schwarze 734: if ( ! flushed && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
1.1 kristaps 735: return(0);
736:
1.37 schwarze 737: if ( ! nl)
1.1 kristaps 738: return(1);
1.22 schwarze 739: return(append_delims(m, line, pos, buf));
1.1 kristaps 740: }
741:
742:
743: static int
744: in_line(MACRO_PROT_ARGS)
745: {
1.40 schwarze 746: int la, lastpunct, cnt, nc, nl;
1.36 schwarze 747: enum margverr av;
748: enum mdoct ntok;
749: enum margserr ac;
1.40 schwarze 750: enum mdelim d;
1.36 schwarze 751: struct mdoc_arg *arg;
752: char *p;
1.1 kristaps 753:
1.37 schwarze 754: nl = MDOC_NEWLINE & m->flags;
755:
1.1 kristaps 756: /*
757: * Whether we allow ignored elements (those without content,
758: * usually because of reserved words) to squeak by.
759: */
1.32 schwarze 760:
1.1 kristaps 761: switch (tok) {
1.19 schwarze 762: case (MDOC_An):
763: /* FALLTHROUGH */
764: case (MDOC_Ar):
1.1 kristaps 765: /* FALLTHROUGH */
766: case (MDOC_Fl):
767: /* FALLTHROUGH */
1.3 schwarze 768: case (MDOC_Lk):
1.18 schwarze 769: /* FALLTHROUGH */
1.19 schwarze 770: case (MDOC_Nm):
771: /* FALLTHROUGH */
1.18 schwarze 772: case (MDOC_Pa):
1.1 kristaps 773: nc = 1;
774: break;
775: default:
776: nc = 0;
777: break;
778: }
779:
1.20 schwarze 780: for (arg = NULL;; ) {
1.1 kristaps 781: la = *pos;
1.36 schwarze 782: av = mdoc_argv(m, line, tok, &arg, pos, buf);
1.1 kristaps 783:
1.36 schwarze 784: if (ARGV_WORD == av) {
1.1 kristaps 785: *pos = la;
786: break;
787: }
1.36 schwarze 788: if (ARGV_EOLN == av)
1.1 kristaps 789: break;
1.36 schwarze 790: if (ARGV_ARG == av)
1.1 kristaps 791: continue;
792:
793: mdoc_argv_free(arg);
794: return(0);
795: }
796:
797: for (cnt = 0, lastpunct = 1;; ) {
798: la = *pos;
1.36 schwarze 799: ac = mdoc_args(m, line, pos, buf, tok, &p);
1.1 kristaps 800:
1.36 schwarze 801: if (ARGS_ERROR == ac)
1.1 kristaps 802: return(0);
1.36 schwarze 803: if (ARGS_EOLN == ac)
1.1 kristaps 804: break;
1.36 schwarze 805: if (ARGS_PUNCT == ac)
1.1 kristaps 806: break;
807:
1.36 schwarze 808: ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1.1 kristaps 809:
810: /*
811: * In this case, we've located a submacro and must
812: * execute it. Close out scope, if open. If no
813: * elements have been generated, either create one (nc)
814: * or raise a warning.
815: */
816:
1.36 schwarze 817: if (MDOC_MAX != ntok) {
1.22 schwarze 818: if (0 == lastpunct && ! rew_elem(m, tok))
1.1 kristaps 819: return(0);
820: if (nc && 0 == cnt) {
1.22 schwarze 821: if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
1.1 kristaps 822: return(0);
1.22 schwarze 823: if ( ! rew_last(m, m->last))
1.3 schwarze 824: return(0);
1.1 kristaps 825: } else if ( ! nc && 0 == cnt) {
826: mdoc_argv_free(arg);
1.22 schwarze 827: if ( ! mdoc_pwarn(m, line, ppos, EIGNE))
1.1 kristaps 828: return(0);
829: }
1.36 schwarze 830: if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1.1 kristaps 831: return(0);
1.37 schwarze 832: if ( ! nl)
1.1 kristaps 833: return(1);
1.22 schwarze 834: return(append_delims(m, line, pos, buf));
1.21 schwarze 835: }
1.1 kristaps 836:
837: /*
838: * Non-quote-enclosed punctuation. Set up our scope, if
839: * a word; rewind the scope, if a delimiter; then append
840: * the word.
841: */
842:
1.40 schwarze 843: d = ARGS_QWORD == ac ? DELIM_NONE : mdoc_isdelim(p);
1.1 kristaps 844:
1.40 schwarze 845: if (ARGS_QWORD != ac && DELIM_NONE != d) {
1.22 schwarze 846: if (0 == lastpunct && ! rew_elem(m, tok))
1.1 kristaps 847: return(0);
848: lastpunct = 1;
849: } else if (lastpunct) {
1.22 schwarze 850: if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
1.1 kristaps 851: return(0);
852: lastpunct = 0;
853: }
854:
1.40 schwarze 855: if (DELIM_NONE == d)
1.1 kristaps 856: cnt++;
1.22 schwarze 857: if ( ! mdoc_word_alloc(m, line, la, p))
1.1 kristaps 858: return(0);
1.27 schwarze 859:
860: /*
861: * `Fl' macros have their scope re-opened with each new
862: * word so that the `-' can be added to each one without
863: * having to parse out spaces.
864: */
865: if (0 == lastpunct && MDOC_Fl == tok) {
866: if ( ! rew_elem(m, tok))
867: return(0);
868: lastpunct = 1;
869: }
1.1 kristaps 870: }
871:
1.22 schwarze 872: if (0 == lastpunct && ! rew_elem(m, tok))
1.1 kristaps 873: return(0);
874:
875: /*
876: * If no elements have been collected and we're allowed to have
877: * empties (nc), open a scope and close it out. Otherwise,
878: * raise a warning.
879: */
1.32 schwarze 880:
1.1 kristaps 881: if (nc && 0 == cnt) {
1.22 schwarze 882: if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
1.1 kristaps 883: return(0);
1.22 schwarze 884: if ( ! rew_last(m, m->last))
1.3 schwarze 885: return(0);
886: } else if ( ! nc && 0 == cnt) {
1.1 kristaps 887: mdoc_argv_free(arg);
1.22 schwarze 888: if ( ! mdoc_pwarn(m, line, ppos, EIGNE))
1.1 kristaps 889: return(0);
890: }
891:
1.37 schwarze 892: if ( ! nl)
1.1 kristaps 893: return(1);
1.22 schwarze 894: return(append_delims(m, line, pos, buf));
1.1 kristaps 895: }
896:
897:
898: static int
899: blk_full(MACRO_PROT_ARGS)
900: {
1.43 ! schwarze 901: int la, nl;
1.1 kristaps 902: struct mdoc_arg *arg;
1.32 schwarze 903: struct mdoc_node *head; /* save of head macro */
1.34 schwarze 904: struct mdoc_node *body; /* save of body macro */
1.32 schwarze 905: struct mdoc_node *n;
1.36 schwarze 906: enum mdoct ntok;
1.37 schwarze 907: enum margserr ac, lac;
1.36 schwarze 908: enum margverr av;
1.1 kristaps 909: char *p;
910:
1.43 ! schwarze 911: nl = MDOC_NEWLINE & m->flags;
! 912:
1.32 schwarze 913: /* Close out prior implicit scope. */
1.12 schwarze 914:
1.1 kristaps 915: if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
1.22 schwarze 916: if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
1.1 kristaps 917: return(0);
1.22 schwarze 918: if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
1.1 kristaps 919: return(0);
920: }
921:
1.32 schwarze 922: /*
923: * This routine accomodates implicitly- and explicitly-scoped
924: * macro openings. Implicit ones first close out prior scope
925: * (seen above). Delay opening the head until necessary to
926: * allow leading punctuation to print. Special consideration
927: * for `It -column', which has phrase-part syntax instead of
928: * regular child nodes.
929: */
930:
1.1 kristaps 931: for (arg = NULL;; ) {
1.32 schwarze 932: la = *pos;
1.36 schwarze 933: av = mdoc_argv(m, line, tok, &arg, pos, buf);
1.1 kristaps 934:
1.36 schwarze 935: if (ARGV_WORD == av) {
1.32 schwarze 936: *pos = la;
1.1 kristaps 937: break;
938: }
939:
1.36 schwarze 940: if (ARGV_EOLN == av)
1.1 kristaps 941: break;
1.36 schwarze 942: if (ARGV_ARG == av)
1.1 kristaps 943: continue;
944:
945: mdoc_argv_free(arg);
946: return(0);
947: }
948:
1.22 schwarze 949: if ( ! mdoc_block_alloc(m, line, ppos, tok, arg))
1.1 kristaps 950: return(0);
951:
1.34 schwarze 952: head = body = NULL;
1.1 kristaps 953:
1.32 schwarze 954: /*
955: * The `Nd' macro has all arguments in its body: it's a hybrid
956: * of block partial-explicit and full-implicit. Stupid.
957: */
1.12 schwarze 958:
1.32 schwarze 959: if (MDOC_Nd == tok) {
960: if ( ! mdoc_head_alloc(m, line, ppos, tok))
961: return(0);
962: head = m->last;
1.22 schwarze 963: if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1.12 schwarze 964: return(0);
1.22 schwarze 965: if ( ! mdoc_body_alloc(m, line, ppos, tok))
1.12 schwarze 966: return(0);
1.34 schwarze 967: body = m->last;
1.12 schwarze 968: }
969:
1.37 schwarze 970: ac = ARGS_ERROR;
971:
1.41 schwarze 972: for ( ; ; ) {
1.32 schwarze 973: la = *pos;
1.37 schwarze 974: lac = ac;
1.36 schwarze 975: ac = mdoc_args(m, line, pos, buf, tok, &p);
1.1 kristaps 976:
1.36 schwarze 977: if (ARGS_ERROR == ac)
1.1 kristaps 978: return(0);
1.36 schwarze 979: if (ARGS_EOLN == ac)
1.1 kristaps 980: break;
1.32 schwarze 981:
1.41 schwarze 982: if (ARGS_PEND == ac) {
983: if (ARGS_PPHRASE == lac)
984: ac = ARGS_PPHRASE;
985: else
986: ac = ARGS_PHRASE;
987: }
988:
1.32 schwarze 989: /* Don't emit leading punct. for phrases. */
990:
1.37 schwarze 991: if (NULL == head &&
992: ARGS_PHRASE != ac &&
1.36 schwarze 993: ARGS_PPHRASE != ac &&
994: ARGS_QWORD != ac &&
1.40 schwarze 995: DELIM_OPEN == mdoc_isdelim(p)) {
1.32 schwarze 996: if ( ! mdoc_word_alloc(m, line, la, p))
997: return(0);
998: continue;
999: }
1000:
1001: /* Always re-open head for phrases. */
1002:
1.37 schwarze 1003: if (NULL == head ||
1004: ARGS_PHRASE == ac ||
1.36 schwarze 1005: ARGS_PPHRASE == ac) {
1.32 schwarze 1006: if ( ! mdoc_head_alloc(m, line, ppos, tok))
1.1 kristaps 1007: return(0);
1.29 schwarze 1008: head = m->last;
1.32 schwarze 1009: }
1010:
1.41 schwarze 1011: if (ARGS_PHRASE == ac || ARGS_PPHRASE == ac) {
1012: if (ARGS_PPHRASE == ac)
1013: m->flags |= MDOC_PPHRASE;
1014: if ( ! phrase(m, line, la, buf, ac))
1.1 kristaps 1015: return(0);
1.41 schwarze 1016: m->flags &= ~MDOC_PPHRASE;
1.22 schwarze 1017: if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1.1 kristaps 1018: return(0);
1019: continue;
1020: }
1021:
1.36 schwarze 1022: ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1023:
1024: if (MDOC_MAX == ntok) {
1025: if ( ! mdoc_word_alloc(m, line, la, p))
1.1 kristaps 1026: return(0);
1.36 schwarze 1027: continue;
1.32 schwarze 1028: }
1.36 schwarze 1029:
1030: if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1.32 schwarze 1031: return(0);
1.36 schwarze 1032: break;
1.32 schwarze 1033: }
1.1 kristaps 1034:
1.32 schwarze 1035: if (NULL == head) {
1036: if ( ! mdoc_head_alloc(m, line, ppos, tok))
1.1 kristaps 1037: return(0);
1.32 schwarze 1038: head = m->last;
1.1 kristaps 1039: }
1040:
1.43 ! schwarze 1041: if (nl && ! append_delims(m, line, pos, buf))
1.1 kristaps 1042: return(0);
1.12 schwarze 1043:
1.34 schwarze 1044: /* If we've already opened our body, exit now. */
1.32 schwarze 1045:
1.34 schwarze 1046: if (NULL != body)
1.12 schwarze 1047: return(1);
1.29 schwarze 1048:
1049: /*
1.34 schwarze 1050: * If there is an open (i.e., unvalidated) sub-block requiring
1051: * explicit close-out, postpone switching the current block from
1052: * head to body until the rew_sub() call closing out that
1053: * sub-block.
1.29 schwarze 1054: */
1055: for (n = m->last; n && n != head; n = n->parent) {
1.34 schwarze 1056: if (MDOC_BLOCK == n->type &&
1057: MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
1058: ! (MDOC_VALID & n->flags)) {
1059: assert( ! (MDOC_ACTED & n->flags));
1.29 schwarze 1060: n->pending = head;
1061: return(1);
1062: }
1063: }
1.32 schwarze 1064: /* Close out scopes to remain in a consistent state. */
1.12 schwarze 1065:
1.22 schwarze 1066: if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1.1 kristaps 1067: return(0);
1.22 schwarze 1068: if ( ! mdoc_body_alloc(m, line, ppos, tok))
1.1 kristaps 1069: return(0);
1070:
1071: return(1);
1072: }
1073:
1074:
1075: static int
1076: blk_part_imp(MACRO_PROT_ARGS)
1077: {
1.43 ! schwarze 1078: int la, nl;
1.36 schwarze 1079: enum mdoct ntok;
1080: enum margserr ac;
1.1 kristaps 1081: char *p;
1.32 schwarze 1082: struct mdoc_node *blk; /* saved block context */
1083: struct mdoc_node *body; /* saved body context */
1084: struct mdoc_node *n;
1.1 kristaps 1085:
1.43 ! schwarze 1086: nl = MDOC_NEWLINE & m->flags;
! 1087:
1.32 schwarze 1088: /*
1089: * A macro that spans to the end of the line. This is generally
1090: * (but not necessarily) called as the first macro. The block
1091: * has a head as the immediate child, which is always empty,
1092: * followed by zero or more opening punctuation nodes, then the
1093: * body (which may be empty, depending on the macro), then zero
1094: * or more closing punctuation nodes.
1095: */
1.22 schwarze 1096:
1097: if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
1098: return(0);
1.32 schwarze 1099:
1.22 schwarze 1100: blk = m->last;
1.32 schwarze 1101:
1.22 schwarze 1102: if ( ! mdoc_head_alloc(m, line, ppos, tok))
1.1 kristaps 1103: return(0);
1.22 schwarze 1104: if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1.1 kristaps 1105: return(0);
1106:
1.32 schwarze 1107: /*
1108: * Open the body scope "on-demand", that is, after we've
1109: * processed all our the leading delimiters (open parenthesis,
1110: * etc.).
1111: */
1.1 kristaps 1112:
1.32 schwarze 1113: for (body = NULL; ; ) {
1.22 schwarze 1114: la = *pos;
1.36 schwarze 1115: ac = mdoc_args(m, line, pos, buf, tok, &p);
1.32 schwarze 1116:
1.36 schwarze 1117: if (ARGS_ERROR == ac)
1.1 kristaps 1118: return(0);
1.36 schwarze 1119: if (ARGS_EOLN == ac)
1.32 schwarze 1120: break;
1.36 schwarze 1121: if (ARGS_PUNCT == ac)
1.1 kristaps 1122: break;
1123:
1.36 schwarze 1124: if (NULL == body && ARGS_QWORD != ac &&
1.40 schwarze 1125: DELIM_OPEN == mdoc_isdelim(p)) {
1.22 schwarze 1126: if ( ! mdoc_word_alloc(m, line, la, p))
1.1 kristaps 1127: return(0);
1128: continue;
1129: }
1130:
1.32 schwarze 1131: if (NULL == body) {
1132: if ( ! mdoc_body_alloc(m, line, ppos, tok))
1133: return(0);
1134: body = m->last;
1135: }
1136:
1.36 schwarze 1137: ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1138:
1139: if (MDOC_MAX == ntok) {
1140: if ( ! mdoc_word_alloc(m, line, la, p))
1.32 schwarze 1141: return(0);
1.36 schwarze 1142: continue;
1143: }
1.32 schwarze 1144:
1.36 schwarze 1145: if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1.32 schwarze 1146: return(0);
1.36 schwarze 1147: break;
1.32 schwarze 1148: }
1149:
1150: /* Clean-ups to leave in a consistent state. */
1151:
1152: if (NULL == body) {
1153: if ( ! mdoc_body_alloc(m, line, ppos, tok))
1.1 kristaps 1154: return(0);
1.32 schwarze 1155: body = m->last;
1.39 schwarze 1156: }
1157:
1158: for (n = body->child; n && n->next; n = n->next)
1159: /* Do nothing. */ ;
1160:
1161: /*
1162: * End of sentence spacing: if the last node is a text node and
1163: * has a trailing period, then mark it as being end-of-sentence.
1164: */
1165:
1166: if (n && MDOC_TEXT == n->type && n->string)
1167: if (mandoc_eos(n->string, strlen(n->string)))
1168: n->flags |= MDOC_EOS;
1169:
1170: /* Up-propogate the end-of-space flag. */
1171:
1172: if (n && (MDOC_EOS & n->flags)) {
1173: body->flags |= MDOC_EOS;
1174: body->parent->flags |= MDOC_EOS;
1.1 kristaps 1175: }
1176:
1.22 schwarze 1177: /*
1178: * If we can't rewind to our body, then our scope has already
1179: * been closed by another macro (like `Oc' closing `Op'). This
1180: * is ugly behaviour nodding its head to OpenBSD's overwhelming
1.34 schwarze 1181: * crufty use of `Op' breakage.
1.1 kristaps 1182: */
1.22 schwarze 1183: for (n = m->last; n; n = n->parent)
1.1 kristaps 1184: if (body == n)
1185: break;
1.32 schwarze 1186:
1.22 schwarze 1187: if (NULL == n && ! mdoc_nwarn(m, body, EIMPBRK))
1188: return(0);
1.32 schwarze 1189:
1.22 schwarze 1190: if (n && ! rew_last(m, body))
1191: return(0);
1.1 kristaps 1192:
1.22 schwarze 1193: /* Standard appending of delimiters. */
1.1 kristaps 1194:
1.43 ! schwarze 1195: if (nl && ! append_delims(m, line, pos, buf))
1.1 kristaps 1196: return(0);
1197:
1.22 schwarze 1198: /* Rewind scope, if applicable. */
1.1 kristaps 1199:
1.22 schwarze 1200: if (n && ! rew_last(m, blk))
1.1 kristaps 1201: return(0);
1202:
1203: return(1);
1204: }
1205:
1206:
1207: static int
1208: blk_part_exp(MACRO_PROT_ARGS)
1209: {
1.37 schwarze 1210: int la, nl;
1.36 schwarze 1211: enum margserr ac;
1.32 schwarze 1212: struct mdoc_node *head; /* keep track of head */
1213: struct mdoc_node *body; /* keep track of body */
1.1 kristaps 1214: char *p;
1.36 schwarze 1215: enum mdoct ntok;
1.1 kristaps 1216:
1.37 schwarze 1217: nl = MDOC_NEWLINE & m->flags;
1218:
1.32 schwarze 1219: /*
1220: * The opening of an explicit macro having zero or more leading
1221: * punctuation nodes; a head with optional single element (the
1222: * case of `Eo'); and a body that may be empty.
1223: */
1.22 schwarze 1224:
1225: if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
1.1 kristaps 1226: return(0);
1.22 schwarze 1227:
1.32 schwarze 1228: for (head = body = NULL; ; ) {
1.22 schwarze 1229: la = *pos;
1.36 schwarze 1230: ac = mdoc_args(m, line, pos, buf, tok, &p);
1.1 kristaps 1231:
1.36 schwarze 1232: if (ARGS_ERROR == ac)
1.1 kristaps 1233: return(0);
1.36 schwarze 1234: if (ARGS_PUNCT == ac)
1.1 kristaps 1235: break;
1.36 schwarze 1236: if (ARGS_EOLN == ac)
1.1 kristaps 1237: break;
1238:
1.32 schwarze 1239: /* Flush out leading punctuation. */
1240:
1.36 schwarze 1241: if (NULL == head && ARGS_QWORD != ac &&
1.40 schwarze 1242: DELIM_OPEN == mdoc_isdelim(p)) {
1.32 schwarze 1243: assert(NULL == body);
1244: if ( ! mdoc_word_alloc(m, line, la, p))
1245: return(0);
1246: continue;
1247: }
1248:
1249: if (NULL == head) {
1250: assert(NULL == body);
1251: if ( ! mdoc_head_alloc(m, line, ppos, tok))
1.1 kristaps 1252: return(0);
1.32 schwarze 1253: head = m->last;
1.1 kristaps 1254: }
1255:
1.32 schwarze 1256: /*
1257: * `Eo' gobbles any data into the head, but most other
1258: * macros just immediately close out and begin the body.
1259: */
1260:
1261: if (NULL == body) {
1262: assert(head);
1263: /* No check whether it's a macro! */
1264: if (MDOC_Eo == tok)
1265: if ( ! mdoc_word_alloc(m, line, la, p))
1266: return(0);
1267:
1.22 schwarze 1268: if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1.1 kristaps 1269: return(0);
1.22 schwarze 1270: if ( ! mdoc_body_alloc(m, line, ppos, tok))
1.1 kristaps 1271: return(0);
1.32 schwarze 1272: body = m->last;
1273:
1274: if (MDOC_Eo == tok)
1275: continue;
1276: }
1277:
1278: assert(NULL != head && NULL != body);
1279:
1.36 schwarze 1280: ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1281:
1282: if (MDOC_MAX == ntok) {
1283: if ( ! mdoc_word_alloc(m, line, la, p))
1.32 schwarze 1284: return(0);
1.36 schwarze 1285: continue;
1.1 kristaps 1286: }
1.32 schwarze 1287:
1.36 schwarze 1288: if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1.1 kristaps 1289: return(0);
1.36 schwarze 1290: break;
1.1 kristaps 1291: }
1292:
1.32 schwarze 1293: /* Clean-up to leave in a consistent state. */
1294:
1295: if (NULL == head) {
1296: if ( ! mdoc_head_alloc(m, line, ppos, tok))
1297: return(0);
1298: head = m->last;
1299: }
1.22 schwarze 1300:
1.32 schwarze 1301: if (NULL == body) {
1.22 schwarze 1302: if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1.1 kristaps 1303: return(0);
1.22 schwarze 1304: if ( ! mdoc_body_alloc(m, line, ppos, tok))
1.1 kristaps 1305: return(0);
1.32 schwarze 1306: body = m->last;
1.1 kristaps 1307: }
1308:
1.22 schwarze 1309: /* Standard appending of delimiters. */
1310:
1.37 schwarze 1311: if ( ! nl)
1.1 kristaps 1312: return(1);
1.22 schwarze 1313: return(append_delims(m, line, pos, buf));
1.1 kristaps 1314: }
1315:
1316:
1.37 schwarze 1317: /* ARGSUSED */
1.1 kristaps 1318: static int
1319: in_line_argn(MACRO_PROT_ARGS)
1320: {
1.37 schwarze 1321: int la, flushed, j, maxargs, nl;
1.36 schwarze 1322: enum margserr ac;
1323: enum margverr av;
1324: struct mdoc_arg *arg;
1325: char *p;
1326: enum mdoct ntok;
1.1 kristaps 1327:
1.37 schwarze 1328: nl = MDOC_NEWLINE & m->flags;
1329:
1.32 schwarze 1330: /*
1331: * A line macro that has a fixed number of arguments (maxargs).
1332: * Only open the scope once the first non-leading-punctuation is
1333: * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then
1334: * keep it open until the maximum number of arguments are
1335: * exhausted.
1336: */
1.1 kristaps 1337:
1338: switch (tok) {
1339: case (MDOC_Ap):
1340: /* FALLTHROUGH */
1341: case (MDOC_No):
1342: /* FALLTHROUGH */
1343: case (MDOC_Ns):
1344: /* FALLTHROUGH */
1345: case (MDOC_Ux):
1346: maxargs = 0;
1347: break;
1.28 schwarze 1348: case (MDOC_Xr):
1349: maxargs = 2;
1350: break;
1.1 kristaps 1351: default:
1352: maxargs = 1;
1353: break;
1354: }
1355:
1.32 schwarze 1356: for (arg = NULL; ; ) {
1.22 schwarze 1357: la = *pos;
1.36 schwarze 1358: av = mdoc_argv(m, line, tok, &arg, pos, buf);
1.1 kristaps 1359:
1.36 schwarze 1360: if (ARGV_WORD == av) {
1.22 schwarze 1361: *pos = la;
1.1 kristaps 1362: break;
1363: }
1364:
1.36 schwarze 1365: if (ARGV_EOLN == av)
1.1 kristaps 1366: break;
1.36 schwarze 1367: if (ARGV_ARG == av)
1.1 kristaps 1368: continue;
1369:
1370: mdoc_argv_free(arg);
1371: return(0);
1372: }
1373:
1.32 schwarze 1374: for (flushed = j = 0; ; ) {
1.22 schwarze 1375: la = *pos;
1.36 schwarze 1376: ac = mdoc_args(m, line, pos, buf, tok, &p);
1.1 kristaps 1377:
1.36 schwarze 1378: if (ARGS_ERROR == ac)
1.1 kristaps 1379: return(0);
1.36 schwarze 1380: if (ARGS_PUNCT == ac)
1.1 kristaps 1381: break;
1.36 schwarze 1382: if (ARGS_EOLN == ac)
1.1 kristaps 1383: break;
1384:
1.32 schwarze 1385: if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
1.36 schwarze 1386: ARGS_QWORD != ac &&
1.40 schwarze 1387: 0 == j && DELIM_OPEN == mdoc_isdelim(p)) {
1.32 schwarze 1388: if ( ! mdoc_word_alloc(m, line, la, p))
1389: return(0);
1390: continue;
1.40 schwarze 1391: } else if (0 == j)
1.32 schwarze 1392: if ( ! mdoc_elem_alloc(m, line, la, tok, arg))
1393: return(0);
1394:
1395: if (j == maxargs && ! flushed) {
1396: if ( ! rew_elem(m, tok))
1397: return(0);
1398: flushed = 1;
1399: }
1400:
1.36 schwarze 1401: ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1402:
1403: if (MDOC_MAX != ntok) {
1.22 schwarze 1404: if ( ! flushed && ! rew_elem(m, tok))
1.1 kristaps 1405: return(0);
1406: flushed = 1;
1.36 schwarze 1407: if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1.1 kristaps 1408: return(0);
1.32 schwarze 1409: j++;
1.1 kristaps 1410: break;
1411: }
1412:
1413: if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
1.36 schwarze 1414: ARGS_QWORD != ac &&
1.40 schwarze 1415: ! flushed &&
1416: DELIM_NONE != mdoc_isdelim(p)) {
1.22 schwarze 1417: if ( ! rew_elem(m, tok))
1.1 kristaps 1418: return(0);
1419: flushed = 1;
1420: }
1.28 schwarze 1421:
1422: /*
1423: * XXX: this is a hack to work around groff's ugliness
1424: * as regards `Xr' and extraneous arguments. It should
1425: * ideally be deprecated behaviour, but because this is
1426: * code is no here, it's unlikely to be removed.
1427: */
1428: if (MDOC_Xr == tok && j == maxargs) {
1.32 schwarze 1429: if ( ! mdoc_elem_alloc(m, line, la, MDOC_Ns, NULL))
1.28 schwarze 1430: return(0);
1431: if ( ! rew_elem(m, MDOC_Ns))
1432: return(0);
1433: }
1434:
1.22 schwarze 1435: if ( ! mdoc_word_alloc(m, line, la, p))
1.1 kristaps 1436: return(0);
1.32 schwarze 1437: j++;
1.1 kristaps 1438: }
1439:
1.32 schwarze 1440: if (0 == j && ! mdoc_elem_alloc(m, line, la, tok, arg))
1441: return(0);
1442:
1443: /* Close out in a consistent state. */
1.22 schwarze 1444:
1445: if ( ! flushed && ! rew_elem(m, tok))
1.1 kristaps 1446: return(0);
1.37 schwarze 1447: if ( ! nl)
1.1 kristaps 1448: return(1);
1.22 schwarze 1449: return(append_delims(m, line, pos, buf));
1.1 kristaps 1450: }
1451:
1452:
1453: static int
1454: in_line_eoln(MACRO_PROT_ARGS)
1455: {
1.36 schwarze 1456: int la;
1457: enum margserr ac;
1458: enum margverr av;
1459: struct mdoc_arg *arg;
1460: char *p;
1461: enum mdoct ntok;
1.1 kristaps 1462:
1463: assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));
1464:
1.22 schwarze 1465: /* Parse macro arguments. */
1.1 kristaps 1466:
1.22 schwarze 1467: for (arg = NULL; ; ) {
1.1 kristaps 1468: la = *pos;
1.36 schwarze 1469: av = mdoc_argv(m, line, tok, &arg, pos, buf);
1.1 kristaps 1470:
1.36 schwarze 1471: if (ARGV_WORD == av) {
1.1 kristaps 1472: *pos = la;
1473: break;
1474: }
1.36 schwarze 1475: if (ARGV_EOLN == av)
1.1 kristaps 1476: break;
1.36 schwarze 1477: if (ARGV_ARG == av)
1.1 kristaps 1478: continue;
1479:
1480: mdoc_argv_free(arg);
1481: return(0);
1482: }
1483:
1.22 schwarze 1484: /* Open element scope. */
1485:
1486: if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
1.1 kristaps 1487: return(0);
1488:
1.22 schwarze 1489: /* Parse argument terms. */
1.1 kristaps 1490:
1491: for (;;) {
1492: la = *pos;
1.36 schwarze 1493: ac = mdoc_args(m, line, pos, buf, tok, &p);
1.1 kristaps 1494:
1.36 schwarze 1495: if (ARGS_ERROR == ac)
1.1 kristaps 1496: return(0);
1.36 schwarze 1497: if (ARGS_EOLN == ac)
1.1 kristaps 1498: break;
1499:
1.36 schwarze 1500: ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1.1 kristaps 1501:
1.36 schwarze 1502: if (MDOC_MAX == ntok) {
1503: if ( ! mdoc_word_alloc(m, line, la, p))
1.1 kristaps 1504: return(0);
1.36 schwarze 1505: continue;
1506: }
1.1 kristaps 1507:
1.36 schwarze 1508: if ( ! rew_elem(m, tok))
1.1 kristaps 1509: return(0);
1.36 schwarze 1510: return(mdoc_macro(m, ntok, line, la, pos, buf));
1.1 kristaps 1511: }
1512:
1.22 schwarze 1513: /* Close out (no delimiters). */
1514:
1515: return(rew_elem(m, tok));
1.28 schwarze 1516: }
1517:
1518:
1519: /* ARGSUSED */
1520: static int
1521: ctx_synopsis(MACRO_PROT_ARGS)
1522: {
1.37 schwarze 1523: int nl;
1524:
1525: nl = MDOC_NEWLINE & m->flags;
1.28 schwarze 1526:
1527: /* If we're not in the SYNOPSIS, go straight to in-line. */
1528: if (SEC_SYNOPSIS != m->lastsec)
1529: return(in_line(m, tok, line, ppos, pos, buf));
1530:
1531: /* If we're a nested call, same place. */
1.37 schwarze 1532: if ( ! nl)
1.28 schwarze 1533: return(in_line(m, tok, line, ppos, pos, buf));
1534:
1535: /*
1536: * XXX: this will open a block scope; however, if later we end
1537: * up formatting the block scope, then child nodes will inherit
1538: * the formatting. Be careful.
1539: */
1540:
1541: return(blk_part_imp(m, tok, line, ppos, pos, buf));
1.1 kristaps 1542: }
1543:
1544:
1545: /* ARGSUSED */
1546: static int
1547: obsolete(MACRO_PROT_ARGS)
1548: {
1549:
1.22 schwarze 1550: return(mdoc_pwarn(m, line, ppos, EOBS));
1.1 kristaps 1551: }
1552:
1553:
1.17 schwarze 1554: /*
1555: * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs.
1556: * They're unusual because they're basically free-form text until a
1557: * macro is encountered.
1558: */
1.1 kristaps 1559: static int
1.41 schwarze 1560: phrase(struct mdoc *m, int line, int ppos, char *buf, enum margserr ac)
1.1 kristaps 1561: {
1.36 schwarze 1562: int la, pos;
1.37 schwarze 1563: enum margserr aac;
1.36 schwarze 1564: enum mdoct ntok;
1565: char *p;
1.1 kristaps 1566:
1.41 schwarze 1567: assert(ARGS_PHRASE == ac || ARGS_PPHRASE == ac);
1.37 schwarze 1568:
1.17 schwarze 1569: for (pos = ppos; ; ) {
1570: la = pos;
1.1 kristaps 1571:
1.37 schwarze 1572: aac = mdoc_zargs(m, line, &pos, buf, 0, &p);
1.1 kristaps 1573:
1.37 schwarze 1574: if (ARGS_ERROR == aac)
1.17 schwarze 1575: return(0);
1.37 schwarze 1576: if (ARGS_EOLN == aac)
1.17 schwarze 1577: break;
1.1 kristaps 1578:
1.41 schwarze 1579: ntok = ARGS_QWORD == aac ? MDOC_MAX : lookup_raw(p);
1.1 kristaps 1580:
1.36 schwarze 1581: if (MDOC_MAX == ntok) {
1582: if ( ! mdoc_word_alloc(m, line, la, p))
1.1 kristaps 1583: return(0);
1.36 schwarze 1584: continue;
1585: }
1.1 kristaps 1586:
1.36 schwarze 1587: if ( ! mdoc_macro(m, ntok, line, la, &pos, buf))
1.1 kristaps 1588: return(0);
1.36 schwarze 1589: return(append_delims(m, line, &pos, buf));
1.1 kristaps 1590: }
1591:
1592: return(1);
1593: }
1.17 schwarze 1594:
1595: