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