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