mdoc.c revision 1.1.1.8
1/*	$Vendor-Id: mdoc.c,v 1.145 2010/05/31 21:32:57 kristaps Exp $ */
2/*
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
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 above
7 * copyright notice and this permission notice appear in all copies.
8 *
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.
16 */
17#ifdef HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <sys/types.h>
22
23#include <assert.h>
24#include <ctype.h>
25#include <stdarg.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <time.h>
30
31#include "mandoc.h"
32#include "libmdoc.h"
33#include "libmandoc.h"
34
35const	char *const __mdoc_macronames[MDOC_MAX] = {
36	"Ap",		"Dd",		"Dt",		"Os",
37	"Sh",		"Ss",		"Pp",		"D1",
38	"Dl",		"Bd",		"Ed",		"Bl",
39	"El",		"It",		"Ad",		"An",
40	"Ar",		"Cd",		"Cm",		"Dv",
41	"Er",		"Ev",		"Ex",		"Fa",
42	"Fd",		"Fl",		"Fn",		"Ft",
43	"Ic",		"In",		"Li",		"Nd",
44	"Nm",		"Op",		"Ot",		"Pa",
45	"Rv",		"St",		"Va",		"Vt",
46	/* LINTED */
47	"Xr",		"%A",		"%B",		"%D",
48	/* LINTED */
49	"%I",		"%J",		"%N",		"%O",
50	/* LINTED */
51	"%P",		"%R",		"%T",		"%V",
52	"Ac",		"Ao",		"Aq",		"At",
53	"Bc",		"Bf",		"Bo",		"Bq",
54	"Bsx",		"Bx",		"Db",		"Dc",
55	"Do",		"Dq",		"Ec",		"Ef",
56	"Em",		"Eo",		"Fx",		"Ms",
57	"No",		"Ns",		"Nx",		"Ox",
58	"Pc",		"Pf",		"Po",		"Pq",
59	"Qc",		"Ql",		"Qo",		"Qq",
60	"Re",		"Rs",		"Sc",		"So",
61	"Sq",		"Sm",		"Sx",		"Sy",
62	"Tn",		"Ux",		"Xc",		"Xo",
63	"Fo",		"Fc",		"Oo",		"Oc",
64	"Bk",		"Ek",		"Bt",		"Hf",
65	"Fr",		"Ud",		"Lb",		"Lp",
66	"Lk",		"Mt",		"Brq",		"Bro",
67	/* LINTED */
68	"Brc",		"%C",		"Es",		"En",
69	/* LINTED */
70	"Dx",		"%Q",		"br",		"sp",
71	/* LINTED */
72	"%U",		"Ta"
73	};
74
75const	char *const __mdoc_argnames[MDOC_ARG_MAX] = {
76	"split",		"nosplit",		"ragged",
77	"unfilled",		"literal",		"file",
78	"offset",		"bullet",		"dash",
79	"hyphen",		"item",			"enum",
80	"tag",			"diag",			"hang",
81	"ohang",		"inset",		"column",
82	"width",		"compact",		"std",
83	"filled",		"words",		"emphasis",
84	"symbolic",		"nested",		"centered"
85	};
86
87const	char * const *mdoc_macronames = __mdoc_macronames;
88const	char * const *mdoc_argnames = __mdoc_argnames;
89
90static	void		  mdoc_node_free(struct mdoc_node *);
91static	void		  mdoc_node_unlink(struct mdoc *,
92				struct mdoc_node *);
93static	void		  mdoc_free1(struct mdoc *);
94static	void		  mdoc_alloc1(struct mdoc *);
95static	struct mdoc_node *node_alloc(struct mdoc *, int, int,
96				enum mdoct, enum mdoc_type);
97static	int		  node_append(struct mdoc *,
98				struct mdoc_node *);
99static	int		  mdoc_ptext(struct mdoc *, int, char *, int);
100static	int		  mdoc_pmacro(struct mdoc *, int, char *, int);
101static	int		  macrowarn(struct mdoc *, int,
102				const char *, int);
103
104
105const struct mdoc_node *
106mdoc_node(const struct mdoc *m)
107{
108
109	return(MDOC_HALT & m->flags ? NULL : m->first);
110}
111
112
113const struct mdoc_meta *
114mdoc_meta(const struct mdoc *m)
115{
116
117	return(MDOC_HALT & m->flags ? NULL : &m->meta);
118}
119
120
121/*
122 * Frees volatile resources (parse tree, meta-data, fields).
123 */
124static void
125mdoc_free1(struct mdoc *mdoc)
126{
127
128	if (mdoc->first)
129		mdoc_node_delete(mdoc, mdoc->first);
130	if (mdoc->meta.title)
131		free(mdoc->meta.title);
132	if (mdoc->meta.os)
133		free(mdoc->meta.os);
134	if (mdoc->meta.name)
135		free(mdoc->meta.name);
136	if (mdoc->meta.arch)
137		free(mdoc->meta.arch);
138	if (mdoc->meta.vol)
139		free(mdoc->meta.vol);
140	if (mdoc->meta.msec)
141		free(mdoc->meta.msec);
142}
143
144
145/*
146 * Allocate all volatile resources (parse tree, meta-data, fields).
147 */
148static void
149mdoc_alloc1(struct mdoc *mdoc)
150{
151
152	memset(&mdoc->meta, 0, sizeof(struct mdoc_meta));
153	mdoc->flags = 0;
154	mdoc->lastnamed = mdoc->lastsec = SEC_NONE;
155	mdoc->last = mandoc_calloc(1, sizeof(struct mdoc_node));
156	mdoc->first = mdoc->last;
157	mdoc->last->type = MDOC_ROOT;
158	mdoc->next = MDOC_NEXT_CHILD;
159}
160
161
162/*
163 * Free up volatile resources (see mdoc_free1()) then re-initialises the
164 * data with mdoc_alloc1().  After invocation, parse data has been reset
165 * and the parser is ready for re-invocation on a new tree; however,
166 * cross-parse non-volatile data is kept intact.
167 */
168void
169mdoc_reset(struct mdoc *mdoc)
170{
171
172	mdoc_free1(mdoc);
173	mdoc_alloc1(mdoc);
174}
175
176
177/*
178 * Completely free up all volatile and non-volatile parse resources.
179 * After invocation, the pointer is no longer usable.
180 */
181void
182mdoc_free(struct mdoc *mdoc)
183{
184
185	mdoc_free1(mdoc);
186	free(mdoc);
187}
188
189
190/*
191 * Allocate volatile and non-volatile parse resources.
192 */
193struct mdoc *
194mdoc_alloc(void *data, int pflags, mandocmsg msg)
195{
196	struct mdoc	*p;
197
198	p = mandoc_calloc(1, sizeof(struct mdoc));
199
200	p->msg = msg;
201	p->data = data;
202	p->pflags = pflags;
203
204	mdoc_hash_init();
205	mdoc_alloc1(p);
206	return(p);
207}
208
209
210/*
211 * Climb back up the parse tree, validating open scopes.  Mostly calls
212 * through to macro_end() in macro.c.
213 */
214int
215mdoc_endparse(struct mdoc *m)
216{
217
218	if (MDOC_HALT & m->flags)
219		return(0);
220	else if (mdoc_macroend(m))
221		return(1);
222	m->flags |= MDOC_HALT;
223	return(0);
224}
225
226
227/*
228 * Main parse routine.  Parses a single line -- really just hands off to
229 * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()).
230 */
231int
232mdoc_parseln(struct mdoc *m, int ln, char *buf, int offs)
233{
234
235	if (MDOC_HALT & m->flags)
236		return(0);
237
238	m->flags |= MDOC_NEWLINE;
239	return(('.' == buf[offs] || '\'' == buf[offs]) ?
240			mdoc_pmacro(m, ln, buf, offs) :
241			mdoc_ptext(m, ln, buf, offs));
242}
243
244
245int
246mdoc_vmsg(struct mdoc *mdoc, enum mandocerr t,
247		int ln, int pos, const char *fmt, ...)
248{
249	char		 buf[256];
250	va_list		 ap;
251
252	va_start(ap, fmt);
253	vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
254	va_end(ap);
255
256	return((*mdoc->msg)(t, mdoc->data, ln, pos, buf));
257}
258
259
260int
261mdoc_macro(struct mdoc *m, enum mdoct tok,
262		int ln, int pp, int *pos, char *buf)
263{
264	assert(tok < MDOC_MAX);
265
266	/* If we're in the body, deny prologue calls. */
267
268	if (MDOC_PROLOGUE & mdoc_macros[tok].flags &&
269			MDOC_PBODY & m->flags)
270		return(mdoc_pmsg(m, ln, pp, MANDOCERR_BADBODY));
271
272	/* If we're in the prologue, deny "body" macros.  */
273
274	if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
275			! (MDOC_PBODY & m->flags)) {
276		if ( ! mdoc_pmsg(m, ln, pp, MANDOCERR_BADPROLOG))
277			return(0);
278		if (NULL == m->meta.title)
279			m->meta.title = mandoc_strdup("UNKNOWN");
280		if (NULL == m->meta.vol)
281			m->meta.vol = mandoc_strdup("LOCAL");
282		if (NULL == m->meta.os)
283			m->meta.os = mandoc_strdup("LOCAL");
284		if (0 == m->meta.date)
285			m->meta.date = time(NULL);
286		m->flags |= MDOC_PBODY;
287	}
288
289	return((*mdoc_macros[tok].fp)(m, tok, ln, pp, pos, buf));
290}
291
292
293static int
294node_append(struct mdoc *mdoc, struct mdoc_node *p)
295{
296
297	assert(mdoc->last);
298	assert(mdoc->first);
299	assert(MDOC_ROOT != p->type);
300
301	switch (mdoc->next) {
302	case (MDOC_NEXT_SIBLING):
303		mdoc->last->next = p;
304		p->prev = mdoc->last;
305		p->parent = mdoc->last->parent;
306		break;
307	case (MDOC_NEXT_CHILD):
308		mdoc->last->child = p;
309		p->parent = mdoc->last;
310		break;
311	default:
312		abort();
313		/* NOTREACHED */
314	}
315
316	p->parent->nchild++;
317
318	if ( ! mdoc_valid_pre(mdoc, p))
319		return(0);
320	if ( ! mdoc_action_pre(mdoc, p))
321		return(0);
322
323	switch (p->type) {
324	case (MDOC_HEAD):
325		assert(MDOC_BLOCK == p->parent->type);
326		p->parent->head = p;
327		break;
328	case (MDOC_TAIL):
329		assert(MDOC_BLOCK == p->parent->type);
330		p->parent->tail = p;
331		break;
332	case (MDOC_BODY):
333		assert(MDOC_BLOCK == p->parent->type);
334		p->parent->body = p;
335		break;
336	default:
337		break;
338	}
339
340	mdoc->last = p;
341
342	switch (p->type) {
343	case (MDOC_TEXT):
344		if ( ! mdoc_valid_post(mdoc))
345			return(0);
346		if ( ! mdoc_action_post(mdoc))
347			return(0);
348		break;
349	default:
350		break;
351	}
352
353	return(1);
354}
355
356
357static struct mdoc_node *
358node_alloc(struct mdoc *m, int line, int pos,
359		enum mdoct tok, enum mdoc_type type)
360{
361	struct mdoc_node *p;
362
363	p = mandoc_calloc(1, sizeof(struct mdoc_node));
364	p->sec = m->lastsec;
365	p->line = line;
366	p->pos = pos;
367	p->tok = tok;
368	p->type = type;
369	if (MDOC_NEWLINE & m->flags)
370		p->flags |= MDOC_LINE;
371	m->flags &= ~MDOC_NEWLINE;
372	return(p);
373}
374
375
376int
377mdoc_tail_alloc(struct mdoc *m, int line, int pos, enum mdoct tok)
378{
379	struct mdoc_node *p;
380
381	p = node_alloc(m, line, pos, tok, MDOC_TAIL);
382	if ( ! node_append(m, p))
383		return(0);
384	m->next = MDOC_NEXT_CHILD;
385	return(1);
386}
387
388
389int
390mdoc_head_alloc(struct mdoc *m, int line, int pos, enum mdoct tok)
391{
392	struct mdoc_node *p;
393
394	assert(m->first);
395	assert(m->last);
396
397	p = node_alloc(m, line, pos, tok, MDOC_HEAD);
398	if ( ! node_append(m, p))
399		return(0);
400	m->next = MDOC_NEXT_CHILD;
401	return(1);
402}
403
404
405int
406mdoc_body_alloc(struct mdoc *m, int line, int pos, enum mdoct tok)
407{
408	struct mdoc_node *p;
409
410	p = node_alloc(m, line, pos, tok, MDOC_BODY);
411	if ( ! node_append(m, p))
412		return(0);
413	m->next = MDOC_NEXT_CHILD;
414	return(1);
415}
416
417
418int
419mdoc_block_alloc(struct mdoc *m, int line, int pos,
420		enum mdoct tok, struct mdoc_arg *args)
421{
422	struct mdoc_node *p;
423
424	p = node_alloc(m, line, pos, tok, MDOC_BLOCK);
425	p->args = args;
426	if (p->args)
427		(args->refcnt)++;
428	if ( ! node_append(m, p))
429		return(0);
430	m->next = MDOC_NEXT_CHILD;
431	return(1);
432}
433
434
435int
436mdoc_elem_alloc(struct mdoc *m, int line, int pos,
437		enum mdoct tok, struct mdoc_arg *args)
438{
439	struct mdoc_node *p;
440
441	p = node_alloc(m, line, pos, tok, MDOC_ELEM);
442	p->args = args;
443	if (p->args)
444		(args->refcnt)++;
445	if ( ! node_append(m, p))
446		return(0);
447	m->next = MDOC_NEXT_CHILD;
448	return(1);
449}
450
451
452int
453mdoc_word_alloc(struct mdoc *m, int line, int pos, const char *p)
454{
455	struct mdoc_node *n;
456	size_t		  sv, len;
457
458	len = strlen(p);
459
460	n = node_alloc(m, line, pos, MDOC_MAX, MDOC_TEXT);
461	n->string = mandoc_malloc(len + 1);
462	sv = strlcpy(n->string, p, len + 1);
463
464	/* Prohibit truncation. */
465	assert(sv < len + 1);
466
467	if ( ! node_append(m, n))
468		return(0);
469
470	m->next = MDOC_NEXT_SIBLING;
471	return(1);
472}
473
474
475void
476mdoc_node_free(struct mdoc_node *p)
477{
478
479	if (p->string)
480		free(p->string);
481	if (p->args)
482		mdoc_argv_free(p->args);
483	free(p);
484}
485
486
487static void
488mdoc_node_unlink(struct mdoc *m, struct mdoc_node *n)
489{
490
491	/* Adjust siblings. */
492
493	if (n->prev)
494		n->prev->next = n->next;
495	if (n->next)
496		n->next->prev = n->prev;
497
498	/* Adjust parent. */
499
500	if (n->parent) {
501		n->parent->nchild--;
502		if (n->parent->child == n)
503			n->parent->child = n->prev ? n->prev : n->next;
504	}
505
506	/* Adjust parse point, if applicable. */
507
508	if (m && m->last == n) {
509		if (n->prev) {
510			m->last = n->prev;
511			m->next = MDOC_NEXT_SIBLING;
512		} else {
513			m->last = n->parent;
514			m->next = MDOC_NEXT_CHILD;
515		}
516	}
517
518	if (m && m->first == n)
519		m->first = NULL;
520}
521
522
523void
524mdoc_node_delete(struct mdoc *m, struct mdoc_node *p)
525{
526
527	while (p->child) {
528		assert(p->nchild);
529		mdoc_node_delete(m, p->child);
530	}
531	assert(0 == p->nchild);
532
533	mdoc_node_unlink(m, p);
534	mdoc_node_free(p);
535}
536
537
538/*
539 * Parse free-form text, that is, a line that does not begin with the
540 * control character.
541 */
542static int
543mdoc_ptext(struct mdoc *m, int line, char *buf, int offs)
544{
545	char		 *c, *ws, *end;
546	struct mdoc_node *n;
547
548	/* Ignore bogus comments. */
549
550	if ('\\' == buf[offs] &&
551			'.' == buf[offs + 1] &&
552			'"' == buf[offs + 2])
553		return(mdoc_pmsg(m, line, offs, MANDOCERR_BADCOMMENT));
554
555	/* No text before an initial macro. */
556
557	if (SEC_NONE == m->lastnamed)
558		return(mdoc_pmsg(m, line, offs, MANDOCERR_NOTEXT));
559
560	assert(m->last);
561	n = m->last;
562
563	/*
564	 * Divert directly to list processing if we're encountering a
565	 * columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry
566	 * (a MDOC_BODY means it's already open, in which case we should
567	 * process within its context in the normal way).
568	 */
569
570	if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
571			LIST_column == n->data.list) {
572		/* `Bl' is open without any children. */
573		m->flags |= MDOC_FREECOL;
574		return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf));
575	}
576
577	if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
578			NULL != n->parent &&
579			MDOC_Bl == n->parent->tok &&
580			LIST_column == n->parent->data.list) {
581		/* `Bl' has block-level `It' children. */
582		m->flags |= MDOC_FREECOL;
583		return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf));
584	}
585
586	/*
587	 * Search for the beginning of unescaped trailing whitespace (ws)
588	 * and for the first character not to be output (end).
589	 */
590
591	/* FIXME: replace with strcspn(). */
592	ws = NULL;
593	for (c = end = buf + offs; *c; c++) {
594		switch (*c) {
595		case '-':
596			if (mandoc_hyph(buf + offs, c))
597				*c = ASCII_HYPH;
598			ws = NULL;
599			break;
600		case ' ':
601			if (NULL == ws)
602				ws = c;
603			continue;
604		case '\t':
605			/*
606			 * Always warn about trailing tabs,
607			 * even outside literal context,
608			 * where they should be put on the next line.
609			 */
610			if (NULL == ws)
611				ws = c;
612			/*
613			 * Strip trailing tabs in literal context only;
614			 * outside, they affect the next line.
615			 */
616			if (MDOC_LITERAL & m->flags)
617				continue;
618			break;
619		case '\\':
620			/* Skip the escaped character, too, if any. */
621			if (c[1])
622				c++;
623			/* FALLTHROUGH */
624		default:
625			ws = NULL;
626			break;
627		}
628		end = c + 1;
629	}
630	*end = '\0';
631
632	if (ws)
633		if ( ! mdoc_pmsg(m, line, (int)(ws-buf), MANDOCERR_EOLNSPACE))
634			return(0);
635
636	if ('\0' == buf[offs] && ! (MDOC_LITERAL & m->flags)) {
637		if ( ! mdoc_pmsg(m, line, (int)(c-buf), MANDOCERR_NOBLANKLN))
638			return(0);
639
640		/*
641		 * Insert a `Pp' in the case of a blank line.  Technically,
642		 * blank lines aren't allowed, but enough manuals assume this
643		 * behaviour that we want to work around it.
644		 */
645		if ( ! mdoc_elem_alloc(m, line, offs, MDOC_Pp, NULL))
646			return(0);
647
648		m->next = MDOC_NEXT_SIBLING;
649		return(1);
650	}
651
652	if ( ! mdoc_word_alloc(m, line, offs, buf+offs))
653		return(0);
654
655	if (MDOC_LITERAL & m->flags)
656		return(1);
657
658	/*
659	 * End-of-sentence check.  If the last character is an unescaped
660	 * EOS character, then flag the node as being the end of a
661	 * sentence.  The front-end will know how to interpret this.
662	 */
663
664	assert(buf < end);
665
666	if (mandoc_eos(buf+offs, (size_t)(end-buf-offs)))
667		m->last->flags |= MDOC_EOS;
668
669	return(1);
670}
671
672
673static int
674macrowarn(struct mdoc *m, int ln, const char *buf, int offs)
675{
676	int		 rc;
677
678	rc = mdoc_vmsg(m, MANDOCERR_MACRO, ln, offs,
679			"unknown macro: %s%s",
680			buf, strlen(buf) > 3 ? "..." : "");
681
682	/* FIXME: logic should be in driver. */
683	/* FIXME: broken, will error out and not omit a message. */
684	return(MDOC_IGN_MACRO & m->pflags ? rc : 0);
685}
686
687
688/*
689 * Parse a macro line, that is, a line beginning with the control
690 * character.
691 */
692int
693mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs)
694{
695	enum mdoct	  tok;
696	int		  i, j, sv;
697	char		  mac[5];
698	struct mdoc_node *n;
699
700	/* Empty lines are ignored. */
701
702	offs++;
703
704	if ('\0' == buf[offs])
705		return(1);
706
707	i = offs;
708
709	/* Accept whitespace after the initial control char. */
710
711	if (' ' == buf[i]) {
712		i++;
713		while (buf[i] && ' ' == buf[i])
714			i++;
715		if ('\0' == buf[i])
716			return(1);
717	}
718
719	sv = i;
720
721	/* Copy the first word into a nil-terminated buffer. */
722
723	for (j = 0; j < 4; j++, i++) {
724		if ('\0' == (mac[j] = buf[i]))
725			break;
726		else if (' ' == buf[i])
727			break;
728
729		/* Check for invalid characters. */
730
731		if (isgraph((u_char)buf[i]))
732			continue;
733		if ( ! mdoc_pmsg(m, ln, i, MANDOCERR_BADCHAR))
734			return(0);
735		i--;
736	}
737
738	mac[j] = '\0';
739
740	if (j == 4 || j < 2) {
741		if ( ! macrowarn(m, ln, mac, sv))
742			goto err;
743		return(1);
744	}
745
746	if (MDOC_MAX == (tok = mdoc_hash_find(mac))) {
747		if ( ! macrowarn(m, ln, mac, sv))
748			goto err;
749		return(1);
750	}
751
752	/* The macro is sane.  Jump to the next word. */
753
754	while (buf[i] && ' ' == buf[i])
755		i++;
756
757	/*
758	 * Trailing whitespace.  Note that tabs are allowed to be passed
759	 * into the parser as "text", so we only warn about spaces here.
760	 */
761
762	if ('\0' == buf[i] && ' ' == buf[i - 1])
763		if ( ! mdoc_pmsg(m, ln, i - 1, MANDOCERR_EOLNSPACE))
764			goto err;
765
766	/*
767	 * If an initial macro or a list invocation, divert directly
768	 * into macro processing.
769	 */
770
771	if (NULL == m->last || MDOC_It == tok || MDOC_El == tok) {
772		if ( ! mdoc_macro(m, tok, ln, sv, &i, buf))
773			goto err;
774		return(1);
775	}
776
777	n = m->last;
778	assert(m->last);
779
780	/*
781	 * If the first macro of a `Bl -column', open an `It' block
782	 * context around the parsed macro.
783	 */
784
785	if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
786			LIST_column == n->data.list) {
787		m->flags |= MDOC_FREECOL;
788		if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf))
789			goto err;
790		return(1);
791	}
792
793	/*
794	 * If we're following a block-level `It' within a `Bl -column'
795	 * context (perhaps opened in the above block or in ptext()),
796	 * then open an `It' block context around the parsed macro.
797	 */
798
799	if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
800			NULL != n->parent &&
801			MDOC_Bl == n->parent->tok &&
802			LIST_column == n->parent->data.list) {
803		m->flags |= MDOC_FREECOL;
804		if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf))
805			goto err;
806		return(1);
807	}
808
809	/* Normal processing of a macro. */
810
811	if ( ! mdoc_macro(m, tok, ln, sv, &i, buf))
812		goto err;
813
814	return(1);
815
816err:	/* Error out. */
817
818	m->flags |= MDOC_HALT;
819	return(0);
820}
821
822
823