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