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