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