xref: /illumos-gate/usr/src/cmd/mandoc/man.c (revision 371584c2)
1 /*	$Id: man.c,v 1.166 2015/10/22 21:54:23 schwarze Exp $ */
2 /*
3  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
5  * Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 #include "config.h"
20 
21 #include <sys/types.h>
22 
23 #include <assert.h>
24 #include <ctype.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 
30 #include "mandoc_aux.h"
31 #include "mandoc.h"
32 #include "roff.h"
33 #include "man.h"
34 #include "libmandoc.h"
35 #include "roff_int.h"
36 #include "libman.h"
37 
38 const	char *const __man_macronames[MAN_MAX] = {
39 	"br",		"TH",		"SH",		"SS",
40 	"TP",		"LP",		"PP",		"P",
41 	"IP",		"HP",		"SM",		"SB",
42 	"BI",		"IB",		"BR",		"RB",
43 	"R",		"B",		"I",		"IR",
44 	"RI",		"sp",		"nf",
45 	"fi",		"RE",		"RS",		"DT",
46 	"UC",		"PD",		"AT",		"in",
47 	"ft",		"OP",		"EX",		"EE",
48 	"UR",		"UE",		"ll"
49 	};
50 
51 const	char * const *man_macronames = __man_macronames;
52 
53 static	void		 man_descope(struct roff_man *, int, int);
54 static	int		 man_ptext(struct roff_man *, int, char *, int);
55 static	int		 man_pmacro(struct roff_man *, int, char *, int);
56 
57 
58 int
59 man_parseln(struct roff_man *man, int ln, char *buf, int offs)
60 {
61 
62 	if (man->last->type != ROFFT_EQN || ln > man->last->line)
63 		man->flags |= MAN_NEWLINE;
64 
65 	return roff_getcontrol(man->roff, buf, &offs) ?
66 	    man_pmacro(man, ln, buf, offs) :
67 	    man_ptext(man, ln, buf, offs);
68 }
69 
70 static void
71 man_descope(struct roff_man *man, int line, int offs)
72 {
73 	/*
74 	 * Co-ordinate what happens with having a next-line scope open:
75 	 * first close out the element scope (if applicable), then close
76 	 * out the block scope (also if applicable).
77 	 */
78 
79 	if (man->flags & MAN_ELINE) {
80 		man->flags &= ~MAN_ELINE;
81 		man_unscope(man, man->last->parent);
82 	}
83 	if ( ! (man->flags & MAN_BLINE))
84 		return;
85 	man->flags &= ~MAN_BLINE;
86 	man_unscope(man, man->last->parent);
87 	roff_body_alloc(man, line, offs, man->last->tok);
88 }
89 
90 static int
91 man_ptext(struct roff_man *man, int line, char *buf, int offs)
92 {
93 	int		 i;
94 
95 	/* Literal free-form text whitespace is preserved. */
96 
97 	if (man->flags & MAN_LITERAL) {
98 		roff_word_alloc(man, line, offs, buf + offs);
99 		man_descope(man, line, offs);
100 		return 1;
101 	}
102 
103 	for (i = offs; buf[i] == ' '; i++)
104 		/* Skip leading whitespace. */ ;
105 
106 	/*
107 	 * Blank lines are ignored right after headings
108 	 * but add a single vertical space elsewhere.
109 	 */
110 
111 	if (buf[i] == '\0') {
112 		/* Allocate a blank entry. */
113 		if (man->last->tok != MAN_SH &&
114 		    man->last->tok != MAN_SS) {
115 			roff_elem_alloc(man, line, offs, MAN_sp);
116 			man->next = ROFF_NEXT_SIBLING;
117 		}
118 		return 1;
119 	}
120 
121 	/*
122 	 * Warn if the last un-escaped character is whitespace. Then
123 	 * strip away the remaining spaces (tabs stay!).
124 	 */
125 
126 	i = (int)strlen(buf);
127 	assert(i);
128 
129 	if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
130 		if (i > 1 && '\\' != buf[i - 2])
131 			mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
132 			    line, i - 1, NULL);
133 
134 		for (--i; i && ' ' == buf[i]; i--)
135 			/* Spin back to non-space. */ ;
136 
137 		/* Jump ahead of escaped whitespace. */
138 		i += '\\' == buf[i] ? 2 : 1;
139 
140 		buf[i] = '\0';
141 	}
142 	roff_word_alloc(man, line, offs, buf + offs);
143 
144 	/*
145 	 * End-of-sentence check.  If the last character is an unescaped
146 	 * EOS character, then flag the node as being the end of a
147 	 * sentence.  The front-end will know how to interpret this.
148 	 */
149 
150 	assert(i);
151 	if (mandoc_eos(buf, (size_t)i))
152 		man->last->flags |= MAN_EOS;
153 
154 	man_descope(man, line, offs);
155 	return 1;
156 }
157 
158 static int
159 man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
160 {
161 	struct roff_node *n;
162 	const char	*cp;
163 	int		 tok;
164 	int		 i, ppos;
165 	int		 bline;
166 	char		 mac[5];
167 
168 	ppos = offs;
169 
170 	/*
171 	 * Copy the first word into a nil-terminated buffer.
172 	 * Stop when a space, tab, escape, or eoln is encountered.
173 	 */
174 
175 	i = 0;
176 	while (i < 4 && strchr(" \t\\", buf[offs]) == NULL)
177 		mac[i++] = buf[offs++];
178 
179 	mac[i] = '\0';
180 
181 	tok = (i > 0 && i < 4) ? man_hash_find(mac) : TOKEN_NONE;
182 
183 	if (tok == TOKEN_NONE) {
184 		mandoc_msg(MANDOCERR_MACRO, man->parse,
185 		    ln, ppos, buf + ppos - 1);
186 		return 1;
187 	}
188 
189 	/* Skip a leading escape sequence or tab. */
190 
191 	switch (buf[offs]) {
192 	case '\\':
193 		cp = buf + offs + 1;
194 		mandoc_escape(&cp, NULL, NULL);
195 		offs = cp - buf;
196 		break;
197 	case '\t':
198 		offs++;
199 		break;
200 	default:
201 		break;
202 	}
203 
204 	/* Jump to the next non-whitespace word. */
205 
206 	while (buf[offs] && buf[offs] == ' ')
207 		offs++;
208 
209 	/*
210 	 * Trailing whitespace.  Note that tabs are allowed to be passed
211 	 * into the parser as "text", so we only warn about spaces here.
212 	 */
213 
214 	if (buf[offs] == '\0' && buf[offs - 1] == ' ')
215 		mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
216 		    ln, offs - 1, NULL);
217 
218 	/*
219 	 * Some macros break next-line scopes; otherwise, remember
220 	 * whether we are in next-line scope for a block head.
221 	 */
222 
223 	man_breakscope(man, tok);
224 	bline = man->flags & MAN_BLINE;
225 
226 	/* Call to handler... */
227 
228 	assert(man_macros[tok].fp);
229 	(*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);
230 
231 	/* In quick mode (for mandocdb), abort after the NAME section. */
232 
233 	if (man->quick && tok == MAN_SH) {
234 		n = man->last;
235 		if (n->type == ROFFT_BODY &&
236 		    strcmp(n->prev->child->string, "NAME"))
237 			return 2;
238 	}
239 
240 	/*
241 	 * If we are in a next-line scope for a block head,
242 	 * close it out now and switch to the body,
243 	 * unless the next-line scope is allowed to continue.
244 	 */
245 
246 	if ( ! bline || man->flags & MAN_ELINE ||
247 	    man_macros[tok].flags & MAN_NSCOPED)
248 		return 1;
249 
250 	assert(man->flags & MAN_BLINE);
251 	man->flags &= ~MAN_BLINE;
252 
253 	man_unscope(man, man->last->parent);
254 	roff_body_alloc(man, ln, ppos, man->last->tok);
255 	return 1;
256 }
257 
258 void
259 man_breakscope(struct roff_man *man, int tok)
260 {
261 	struct roff_node *n;
262 
263 	/*
264 	 * An element next line scope is open,
265 	 * and the new macro is not allowed inside elements.
266 	 * Delete the element that is being broken.
267 	 */
268 
269 	if (man->flags & MAN_ELINE && (tok == TOKEN_NONE ||
270 	    ! (man_macros[tok].flags & MAN_NSCOPED))) {
271 		n = man->last;
272 		assert(n->type != ROFFT_TEXT);
273 		if (man_macros[n->tok].flags & MAN_NSCOPED)
274 			n = n->parent;
275 
276 		mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
277 		    n->line, n->pos, "%s breaks %s",
278 		    tok == TOKEN_NONE ? "TS" : man_macronames[tok],
279 		    man_macronames[n->tok]);
280 
281 		roff_node_delete(man, n);
282 		man->flags &= ~MAN_ELINE;
283 	}
284 
285 	/*
286 	 * Weird special case:
287 	 * Switching fill mode closes section headers.
288 	 */
289 
290 	if (man->flags & MAN_BLINE &&
291 	    (tok == MAN_nf || tok == MAN_fi) &&
292 	    (man->last->tok == MAN_SH || man->last->tok == MAN_SS)) {
293 		n = man->last;
294 		man_unscope(man, n);
295 		roff_body_alloc(man, n->line, n->pos, n->tok);
296 		man->flags &= ~MAN_BLINE;
297 	}
298 
299 	/*
300 	 * A block header next line scope is open,
301 	 * and the new macro is not allowed inside block headers.
302 	 * Delete the block that is being broken.
303 	 */
304 
305 	if (man->flags & MAN_BLINE && (tok == TOKEN_NONE ||
306 	    man_macros[tok].flags & MAN_BSCOPE)) {
307 		n = man->last;
308 		if (n->type == ROFFT_TEXT)
309 			n = n->parent;
310 		if ( ! (man_macros[n->tok].flags & MAN_BSCOPE))
311 			n = n->parent;
312 
313 		assert(n->type == ROFFT_HEAD);
314 		n = n->parent;
315 		assert(n->type == ROFFT_BLOCK);
316 		assert(man_macros[n->tok].flags & MAN_SCOPED);
317 
318 		mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
319 		    n->line, n->pos, "%s breaks %s",
320 		    tok == TOKEN_NONE ? "TS" : man_macronames[tok],
321 		    man_macronames[n->tok]);
322 
323 		roff_node_delete(man, n);
324 		man->flags &= ~MAN_BLINE;
325 	}
326 }
327 
328 const struct mparse *
329 man_mparse(const struct roff_man *man)
330 {
331 
332 	assert(man && man->parse);
333 	return man->parse;
334 }
335 
336 void
337 man_state(struct roff_man *man, struct roff_node *n)
338 {
339 
340 	switch(n->tok) {
341 	case MAN_nf:
342 	case MAN_EX:
343 		if (man->flags & MAN_LITERAL && ! (n->flags & MAN_VALID))
344 			mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
345 			    n->line, n->pos, "nf");
346 		man->flags |= MAN_LITERAL;
347 		break;
348 	case MAN_fi:
349 	case MAN_EE:
350 		if ( ! (man->flags & MAN_LITERAL) &&
351 		     ! (n->flags & MAN_VALID))
352 			mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
353 			    n->line, n->pos, "fi");
354 		man->flags &= ~MAN_LITERAL;
355 		break;
356 	default:
357 		break;
358 	}
359 	man->last->flags |= MAN_VALID;
360 }
361 
362 void
363 man_validate(struct roff_man *man)
364 {
365 
366 	man->last = man->first;
367 	man_node_validate(man);
368 	man->flags &= ~MAN_LITERAL;
369 }
370