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