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