Annotation of mandoc/mdoc_macro.c, Revision 1.6
1.6 ! kristaps 1: /* $Id: mdoc_macro.c,v 1.5 2009/03/31 13:50:19 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;
874: } else if ( ! nc && 0 == cnt)
875: if ( ! pwarn(mdoc, line, ppos, WIGNE))
1.3 kristaps 876: return(0);
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.4 kristaps 926: mdoc->next = MDOC_NEXT_SIBLING;
927: } else if ( ! nc && 0 == cnt)
928: if ( ! pwarn(mdoc, line, ppos, WIGNE))
1.3 kristaps 929: return(0);
1.4 kristaps 930:
1.1 kristaps 931: if (ppos > 1)
932: return(1);
933: return(append_delims(mdoc, line, pos, buf));
934: }
935:
936:
937: /*
938: * Block full-explicit and full-implicit.
939: */
940: static int
941: blk_full(MACRO_PROT_ARGS)
942: {
943: int c, lastarg, reopen;
944: struct mdoc_arg *arg;
945: char *p;
946:
947: if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
948: if ( ! rew_subblock(MDOC_BODY, mdoc,
949: tok, line, ppos))
950: return(0);
951: if ( ! rew_impblock(mdoc, tok, line, ppos))
952: return(0);
953: }
954:
955: for (arg = NULL;; ) {
956: lastarg = *pos;
957: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
958:
959: if (ARGV_WORD == c) {
960: *pos = lastarg;
961: break;
962: }
963:
964: if (ARGV_EOLN == c)
965: break;
966: if (ARGV_ARG == c)
967: continue;
968:
969: mdoc_argv_free(arg);
970: return(0);
971: }
972:
973: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, arg))
974: return(0);
975: mdoc->next = MDOC_NEXT_CHILD;
976:
977: if (0 == buf[*pos]) {
978: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
979: return(0);
980: if ( ! rew_subblock(MDOC_HEAD, mdoc,
981: tok, line, ppos))
982: return(0);
983: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
984: return(0);
985: mdoc->next = MDOC_NEXT_CHILD;
986: return(1);
987: }
988:
989: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
990: return(0);
991: mdoc->next = MDOC_NEXT_CHILD;
992:
993: for (reopen = 0;; ) {
994: lastarg = *pos;
995: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
996:
997: if (ARGS_ERROR == c)
998: return(0);
999: if (ARGS_EOLN == c)
1000: break;
1001: if (ARGS_PHRASE == c) {
1002: if (reopen && ! mdoc_head_alloc
1003: (mdoc, line, ppos, tok))
1004: return(0);
1005: mdoc->next = MDOC_NEXT_CHILD;
1006: /*
1007: * Phrases are self-contained macro phrases used
1008: * in the columnar output of a macro. They need
1009: * special handling.
1010: */
1011: if ( ! phrase(mdoc, line, lastarg, buf))
1012: return(0);
1013: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1014: tok, line, ppos))
1015: return(0);
1016:
1017: reopen = 1;
1018: continue;
1019: }
1020:
1021: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1022: return(0);
1023:
1024: if (MDOC_MAX == c) {
1025: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1026: return(0);
1027: mdoc->next = MDOC_NEXT_SIBLING;
1028: continue;
1029: }
1030:
1031: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1032: return(0);
1033: break;
1034: }
1035:
1036: if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
1037: return(0);
1038: if ( ! rew_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1039: return(0);
1040:
1041: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1042: return(0);
1043: mdoc->next = MDOC_NEXT_CHILD;
1044:
1045: return(1);
1046: }
1047:
1048:
1049: /*
1050: * Block partial-imnplicit scope.
1051: */
1052: static int
1053: blk_part_imp(MACRO_PROT_ARGS)
1054: {
1055: int lastarg, c;
1056: char *p;
1057: struct mdoc_node *blk, *body, *n;
1058:
1059: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
1060: return(0);
1061: mdoc->next = MDOC_NEXT_CHILD;
1062: blk = mdoc->last;
1063:
1064: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1065: return(0);
1066: mdoc->next = MDOC_NEXT_SIBLING;
1067:
1068: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1069: return(0);
1070: mdoc->next = MDOC_NEXT_CHILD;
1071: body = mdoc->last;
1072:
1073: /* XXX - no known argument macros. */
1074:
1075: for (lastarg = ppos;; ) {
1076: lastarg = *pos;
1077: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1078: assert(ARGS_PHRASE != c);
1079:
1080: if (ARGS_ERROR == c)
1081: return(0);
1082: if (ARGS_PUNCT == c)
1083: break;
1084: if (ARGS_EOLN == c)
1085: break;
1086:
1087: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1088: return(0);
1089: else if (MDOC_MAX == c) {
1090: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1091: return(0);
1092: mdoc->next = MDOC_NEXT_SIBLING;
1093: continue;
1094: }
1095:
1096: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1097: return(0);
1098: break;
1099: }
1100:
1101: /*
1102: * Since we know what our context is, we can rewind directly to
1103: * it. This allows us to accomodate for our scope being
1104: * violated by another token.
1105: */
1106:
1107: for (n = mdoc->last; n; n = n->parent)
1108: if (body == n)
1109: break;
1110:
1111: if (NULL == n && ! pwarn(mdoc, body->line, body->pos, WIMPBRK))
1112: return(0);
1113:
1114: if (n && ! rew_last(mdoc, body))
1115: return(0);
1116:
1117: if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
1118: return(0);
1119:
1120: if (n && ! rew_last(mdoc, blk))
1121: return(0);
1122:
1123: return(1);
1124: }
1125:
1126:
1127: /*
1128: * Block partial-explicit macros.
1129: */
1130: static int
1131: blk_part_exp(MACRO_PROT_ARGS)
1132: {
1133: int lastarg, flushed, j, c, maxargs;
1134: char *p;
1135:
1136: lastarg = ppos;
1137: flushed = 0;
1138:
1139: /*
1140: * Number of arguments (head arguments). Only `Eo' has these,
1141: */
1142:
1143: switch (tok) {
1144: case (MDOC_Eo):
1145: maxargs = 1;
1146: break;
1147: default:
1148: maxargs = 0;
1149: break;
1150: }
1151:
1152: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
1153: return(0);
1154: mdoc->next = MDOC_NEXT_CHILD;
1155:
1156: if (0 == maxargs) {
1157: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1158: return(0);
1159: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1160: tok, line, ppos))
1161: return(0);
1162: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1163: return(0);
1164: flushed = 1;
1165: } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1166: return(0);
1167:
1168: mdoc->next = MDOC_NEXT_CHILD;
1169:
1170: for (j = 0; ; j++) {
1171: lastarg = *pos;
1172: if (j == maxargs && ! flushed) {
1173: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1174: tok, line, ppos))
1175: return(0);
1176: flushed = 1;
1177: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1178: return(0);
1179: mdoc->next = MDOC_NEXT_CHILD;
1180: }
1181:
1182: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1183: assert(ARGS_PHRASE != c);
1184:
1185: if (ARGS_ERROR == c)
1186: return(0);
1187: if (ARGS_PUNCT == c)
1188: break;
1189: if (ARGS_EOLN == c)
1190: break;
1191:
1192: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1193: return(0);
1194: else if (MDOC_MAX != c) {
1195: if ( ! flushed) {
1196: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1197: tok, line, ppos))
1198: return(0);
1199: flushed = 1;
1200: if ( ! mdoc_body_alloc(mdoc, line,
1201: ppos, tok))
1202: return(0);
1203: mdoc->next = MDOC_NEXT_CHILD;
1204: }
1205: if ( ! mdoc_macro(mdoc, c, line, lastarg,
1206: pos, buf))
1207: return(0);
1208: break;
1209: }
1210:
1211: if ( ! flushed && mdoc_isdelim(p)) {
1212: if ( ! rew_subblock(MDOC_HEAD, mdoc,
1213: tok, line, ppos))
1214: return(0);
1215: flushed = 1;
1216: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1217: return(0);
1218: mdoc->next = MDOC_NEXT_CHILD;
1219: }
1220:
1221: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1222: return(0);
1223: mdoc->next = MDOC_NEXT_SIBLING;
1224: }
1225:
1226: if ( ! flushed) {
1227: if ( ! rew_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1228: return(0);
1229: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1230: return(0);
1231: mdoc->next = MDOC_NEXT_CHILD;
1232: }
1233:
1234: if (ppos > 1)
1235: return(1);
1236: return(append_delims(mdoc, line, pos, buf));
1237: }
1238:
1239:
1240: /*
1241: * In-line macros where reserved words signal closure of the macro.
1242: * Macros also have a fixed number of arguments.
1243: */
1244: static int
1245: in_line_argn(MACRO_PROT_ARGS)
1246: {
1247: int lastarg, flushed, j, c, maxargs;
1248: struct mdoc_arg *arg;
1249: char *p;
1250:
1251:
1252: /*
1253: * Fixed maximum arguments per macro. Some of these have none
1254: * and close as soon as the invocation is parsed.
1255: */
1256:
1257: switch (tok) {
1258: case (MDOC_Ap):
1259: /* FALLTHROUGH */
1260: case (MDOC_No):
1261: /* FALLTHROUGH */
1262: case (MDOC_Ns):
1263: /* FALLTHROUGH */
1264: case (MDOC_Ux):
1265: maxargs = 0;
1266: break;
1267: default:
1268: maxargs = 1;
1269: break;
1270: }
1271:
1272: for (lastarg = ppos, arg = NULL;; ) {
1273: lastarg = *pos;
1274: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1275:
1276: if (ARGV_WORD == c) {
1277: *pos = lastarg;
1278: break;
1279: }
1280:
1281: if (ARGV_EOLN == c)
1282: break;
1283: if (ARGV_ARG == c)
1284: continue;
1285:
1286: mdoc_argv_free(arg);
1287: return(0);
1288: }
1289:
1290: if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1291: return(0);
1292: mdoc->next = MDOC_NEXT_CHILD;
1293:
1294: for (flushed = j = 0; ; j++) {
1295: lastarg = *pos;
1296:
1297: if (j == maxargs && ! flushed) {
1298: if ( ! rew_elem(mdoc, tok))
1299: return(0);
1300: flushed = 1;
1301: }
1302:
1303: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1304:
1305: if (ARGS_ERROR == c)
1306: return(0);
1307: if (ARGS_PUNCT == c)
1308: break;
1309: if (ARGS_EOLN == c)
1310: break;
1311:
1312: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1313: return(0);
1314: else if (MDOC_MAX != c) {
1315: if ( ! flushed && ! rew_elem(mdoc, tok))
1316: return(0);
1317: flushed = 1;
1318: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1319: return(0);
1320: break;
1321: }
1322:
1323: if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
1324: ! flushed && mdoc_isdelim(p)) {
1325: if ( ! rew_elem(mdoc, tok))
1326: return(0);
1327: flushed = 1;
1328: }
1329:
1330: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1331: return(0);
1332: mdoc->next = MDOC_NEXT_SIBLING;
1333: }
1334:
1335: if ( ! flushed && ! rew_elem(mdoc, tok))
1336: return(0);
1337:
1338: if (ppos > 1)
1339: return(1);
1340: return(append_delims(mdoc, line, pos, buf));
1341: }
1342:
1343:
1344: /*
1345: * In-line macro that spans an entire line. May be callable, but has no
1346: * subsequent parsed arguments.
1347: */
1348: static int
1349: in_line_eoln(MACRO_PROT_ARGS)
1350: {
1351: int c, w, la;
1352: struct mdoc_arg *arg;
1353: char *p;
1354:
1355: assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));
1356:
1357: arg = NULL;
1358:
1359: for (;;) {
1360: la = *pos;
1361: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1362:
1363: if (ARGV_WORD == c) {
1364: *pos = la;
1365: break;
1366: }
1367: if (ARGV_EOLN == c)
1368: break;
1369: if (ARGV_ARG == c)
1370: continue;
1371:
1372: mdoc_argv_free(arg);
1373: return(0);
1374: }
1375:
1376: if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1377: return(0);
1378:
1379: mdoc->next = MDOC_NEXT_CHILD;
1380:
1381: for (;;) {
1382: la = *pos;
1383: w = mdoc_args(mdoc, line, pos, buf, tok, &p);
1384:
1385: if (ARGS_ERROR == w)
1386: return(0);
1387: if (ARGS_EOLN == w)
1388: break;
1389:
1390: c = ARGS_QWORD == w ? MDOC_MAX :
1391: lookup(mdoc, line, la, tok, p);
1392:
1393: if (MDOC_MAX != c && -1 != c) {
1394: if ( ! rew_elem(mdoc, tok))
1395: return(0);
1396: return(mdoc_macro(mdoc, c, line, la, pos, buf));
1397: } else if (-1 == c)
1398: return(0);
1399:
1400: if ( ! mdoc_word_alloc(mdoc, line, la, p))
1401: return(0);
1402: mdoc->next = MDOC_NEXT_SIBLING;
1403: }
1404:
1405: return(rew_elem(mdoc, tok));
1406: }
1407:
1408:
1409: /* ARGSUSED */
1410: static int
1411: obsolete(MACRO_PROT_ARGS)
1412: {
1413:
1414: return(pwarn(mdoc, line, ppos, WOBS));
1415: }
1416:
1417:
1418: static int
1419: phrase(struct mdoc *mdoc, int line, int ppos, char *buf)
1420: {
1421: int i, la, c, quoted;
1422:
1423: /*
1424: * Parse over words in a phrase. We have to handle this
1425: * specially because we assume no calling context -- in normal
1426: * circumstances, we switch argument parsing based on whether
1427: * the parent macro accepts quotes, tabs, etc. Here, anything
1428: * goes.
1429: */
1430:
1431: for (i = ppos; buf[i]; ) {
1432: assert(' ' != buf[i]);
1433: la = i;
1434: quoted = 0;
1435:
1436: /*
1437: * Read to next token. If quoted (check not escaped),
1438: * scan ahead to next unescaped quote. If not quoted or
1439: * escape-quoted, then scan ahead to next space.
1440: */
1441:
1442: if ((i && '\"' == buf[i] && '\\' != buf[i - 1]) ||
1443: (0 == i && '\"' == buf[i])) {
1444: for (la = ++i; buf[i]; i++)
1445: if ('\"' != buf[i])
1446: continue;
1447: else if ('\\' != buf[i - 1])
1448: break;
1449: if (0 == buf[i])
1450: return(perr(mdoc, line, la, EQUOT));
1451: quoted = 1;
1452: } else
1453: for ( ; buf[i]; i++)
1454: if (i && ' ' == buf[i]) {
1455: if ('\\' != buf[i - 1])
1456: break;
1457: } else if (' ' == buf[i])
1458: break;
1459:
1460: /* If not end-of-line, terminate argument. */
1461:
1462: if (buf[i])
1463: buf[i++] = 0;
1464:
1465: /* Read to next argument. */
1466:
1467: for ( ; buf[i] && ' ' == buf[i]; i++)
1468: /* Spin. */ ;
1469:
1470: /*
1471: * If we're a non-quoted string, try to look up the
1472: * value as a macro and execute it, if found.
1473: */
1474:
1475: c = quoted ? MDOC_MAX :
1.6 ! kristaps 1476: mdoc_hash_find(mdoc->htab, &buf[la]);
1.1 kristaps 1477:
1478: if (MDOC_MAX != c) {
1479: if ( ! mdoc_macro(mdoc, c, line, la, &i, buf))
1480: return(0);
1481: return(append_delims(mdoc, line, &i, buf));
1482: }
1483:
1484: /* A regular word or quoted string. */
1485:
1486: if ( ! mdoc_word_alloc(mdoc, line, la, &buf[la]))
1487: return(0);
1488: mdoc->next = MDOC_NEXT_SIBLING;
1489: }
1490:
1491: return(1);
1492: }
CVSweb