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