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