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