GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mandoc/man.c Lines: 143 157 91.1 %
Date: 2017-11-13 Branches: 111 150 74.0 %

Line Branch Exec Source
1
/*	$OpenBSD: man.c,v 1.124 2017/06/28 12:52:27 schwarze Exp $ */
2
/*
3
 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4
 * Copyright (c) 2013, 2014, 2015, 2017 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 <sys/types.h>
20
21
#include <assert.h>
22
#include <ctype.h>
23
#include <stdarg.h>
24
#include <stdlib.h>
25
#include <stdio.h>
26
#include <string.h>
27
28
#include "mandoc_aux.h"
29
#include "mandoc.h"
30
#include "roff.h"
31
#include "man.h"
32
#include "libmandoc.h"
33
#include "roff_int.h"
34
#include "libman.h"
35
36
static	void		 man_descope(struct roff_man *, int, int);
37
static	int		 man_ptext(struct roff_man *, int, char *, int);
38
static	int		 man_pmacro(struct roff_man *, int, char *, int);
39
40
41
int
42
man_parseln(struct roff_man *man, int ln, char *buf, int offs)
43
{
44
45

369507
	if (man->last->type != ROFFT_EQN || ln > man->last->line)
46
369507
		man->flags |= MAN_NEWLINE;
47
48
1108521
	return roff_getcontrol(man->roff, buf, &offs) ?
49
118864
	    man_pmacro(man, ln, buf, offs) :
50
250643
	    man_ptext(man, ln, buf, offs);
51
}
52
53
static void
54
man_descope(struct roff_man *man, int line, int offs)
55
{
56
	/*
57
	 * Co-ordinate what happens with having a next-line scope open:
58
	 * first close out the element scope (if applicable), then close
59
	 * out the block scope (also if applicable).
60
	 */
61
62
500306
	if (man->flags & MAN_ELINE) {
63
39
		man->flags &= ~MAN_ELINE;
64
39
		man_unscope(man, man->last->parent);
65
39
	}
66
250153
	if ( ! (man->flags & MAN_BLINE))
67
		return;
68
1334
	man->flags &= ~MAN_BLINE;
69
1334
	man_unscope(man, man->last->parent);
70
1334
	roff_body_alloc(man, line, offs, man->last->tok);
71
251487
}
72
73
static int
74
man_ptext(struct roff_man *man, int line, char *buf, int offs)
75
{
76
	int		 i;
77
	const char 	*cp, *sp;
78
	char		*ep;
79
80
	/* Literal free-form text whitespace is preserved. */
81
82
501286
	if (man->flags & MAN_LITERAL) {
83
64354
		roff_word_alloc(man, line, offs, buf + offs);
84
64354
		man_descope(man, line, offs);
85
64354
		return 1;
86
	}
87
88
377878
	for (i = offs; buf[i] == ' '; i++)
89
		/* Skip leading whitespace. */ ;
90
91
	/*
92
	 * Blank lines are ignored in next line scope
93
	 * and right after headings and cancel preceding \c,
94
	 * but add a single vertical space elsewhere.
95
	 */
96
97
186289
	if (buf[i] == '\0') {
98
490
		if (man->flags & (MAN_ELINE | MAN_BLINE)) {
99
24
			mandoc_msg(MANDOCERR_BLK_BLANK, man->parse,
100
			    line, 0, NULL);
101
24
			return 1;
102
		}
103

788
		if (man->last->tok == MAN_SH || man->last->tok == MAN_SS)
104
290
			return 1;
105
176
		switch (man->last->type) {
106
		case ROFFT_TEXT:
107
107
			sp = man->last->string;
108
107
			cp = ep = strchr(sp, '\0') - 2;
109

217
			if (cp < sp || cp[0] != '\\' || cp[1] != 'c')
110
				break;
111

9
			while (cp > sp && cp[-1] == '\\')
112
				cp--;
113
3
			if ((ep - cp) % 2)
114
				break;
115
3
			*ep = '\0';
116
3
			return 1;
117
		default:
118
			break;
119
		}
120
173
		roff_elem_alloc(man, line, offs, ROFF_sp);
121
173
		man->next = ROFF_NEXT_SIBLING;
122
173
		return 1;
123
	}
124
125
	/*
126
	 * Warn if the last un-escaped character is whitespace. Then
127
	 * strip away the remaining spaces (tabs stay!).
128
	 */
129
130
185799
	i = (int)strlen(buf);
131
185799
	assert(i);
132
133

369965
	if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
134

3266
		if (i > 1 && '\\' != buf[i - 2])
135
1633
			mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
136
			    line, i - 1, NULL);
137
138

10287
		for (--i; i && ' ' == buf[i]; i--)
139
			/* Spin back to non-space. */ ;
140
141
		/* Jump ahead of escaped whitespace. */
142
1633
		i += '\\' == buf[i] ? 2 : 1;
143
144
1633
		buf[i] = '\0';
145
1633
	}
146
185799
	roff_word_alloc(man, line, offs, buf + offs);
147
148
	/*
149
	 * End-of-sentence check.  If the last character is an unescaped
150
	 * EOS character, then flag the node as being the end of a
151
	 * sentence.  The front-end will know how to interpret this.
152
	 */
153
154
185799
	assert(i);
155
185799
	if (mandoc_eos(buf, (size_t)i))
156
51585
		man->last->flags |= NODE_EOS;
157
158
185799
	man_descope(man, line, offs);
159
185799
	return 1;
160
250643
}
161
162
static int
163
man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
164
{
165
	struct roff_node *n;
166
118864
	const char	*cp;
167
	size_t		 sz;
168
	enum roff_tok	 tok;
169
	int		 ppos;
170
	int		 bline;
171
172
	/* Determine the line macro. */
173
174
118864
	ppos = offs;
175
	tok = TOKEN_NONE;
176

1062459
	for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++)
177
235289
		offs++;
178
118864
	if (sz > 0 && sz < 4)
179
118864
		tok = roffhash_find(man->manmac, buf + ppos, sz);
180
118864
	if (tok == TOKEN_NONE) {
181
		mandoc_msg(MANDOCERR_MACRO, man->parse,
182
		    ln, ppos, buf + ppos - 1);
183
		return 1;
184
	}
185
186
	/* Skip a leading escape sequence or tab. */
187
188
118870
	switch (buf[offs]) {
189
	case '\\':
190
6
		cp = buf + offs + 1;
191
6
		mandoc_escape(&cp, NULL, NULL);
192
6
		offs = cp - buf;
193
6
		break;
194
	case '\t':
195
		offs++;
196
		break;
197
	default:
198
		break;
199
	}
200
201
	/* Jump to the next non-whitespace word. */
202
203
363682
	while (buf[offs] == ' ')
204
62977
		offs++;
205
206
	/*
207
	 * Trailing whitespace.  Note that tabs are allowed to be passed
208
	 * into the parser as "text", so we only warn about spaces here.
209
	 */
210
211

174780
	if (buf[offs] == '\0' && buf[offs - 1] == ' ')
212
8
		mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
213
		    ln, offs - 1, NULL);
214
215
	/*
216
	 * Some macros break next-line scopes; otherwise, remember
217
	 * whether we are in next-line scope for a block head.
218
	 */
219
220
118864
	man_breakscope(man, tok);
221
118864
	bline = man->flags & MAN_BLINE;
222
223
	/*
224
	 * If the line in next-line scope ends with \c, keep the
225
	 * next-line scope open for the subsequent input line.
226
	 * That is not at all portable, only groff >= 1.22.4
227
	 * does it, but *if* this weird idiom occurs in a manual
228
	 * page, that's very likely what the author intended.
229
	 */
230
231
118864
	if (bline) {
232
1193
		cp = strchr(buf + offs, '\0') - 2;
233

2404
		if (cp >= buf && cp[0] == '\\' && cp[1] == 'c')
234
15
			bline = 0;
235
	}
236
237
	/* Call to handler... */
238
239
118864
	assert(man_macros[tok].fp);
240
118864
	(*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);
241
242
	/* In quick mode (for mandocdb), abort after the NAME section. */
243
244
118864
	if (man->quick && tok == MAN_SH) {
245
		n = man->last;
246
		if (n->type == ROFFT_BODY &&
247
		    strcmp(n->prev->child->string, "NAME"))
248
			return 2;
249
	}
250
251
	/*
252
	 * If we are in a next-line scope for a block head,
253
	 * close it out now and switch to the body,
254
	 * unless the next-line scope is allowed to continue.
255
	 */
256
257

121206
	if ( ! bline || man->flags & MAN_ELINE ||
258
1164
	    man_macros[tok].flags & MAN_NSCOPED)
259
117715
		return 1;
260
261
1149
	assert(man->flags & MAN_BLINE);
262
1149
	man->flags &= ~MAN_BLINE;
263
264
1149
	man_unscope(man, man->last->parent);
265
1149
	roff_body_alloc(man, ln, ppos, man->last->tok);
266
1149
	return 1;
267
118864
}
268
269
void
270
man_breakscope(struct roff_man *man, int tok)
271
{
272
	struct roff_node *n;
273
274
	/*
275
	 * An element next line scope is open,
276
	 * and the new macro is not allowed inside elements.
277
	 * Delete the element that is being broken.
278
	 */
279
280

247032
	if (man->flags & MAN_ELINE && (tok < MAN_TH ||
281
11
	    ! (man_macros[tok].flags & MAN_NSCOPED))) {
282
14
		n = man->last;
283
14
		if (n->type == ROFFT_TEXT)
284
			n = n->parent;
285

28
		if (n->tok < MAN_TH ||
286
14
		    man_macros[n->tok].flags & MAN_NSCOPED)
287
			n = n->parent;
288
289
28
		mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
290
14
		    n->line, n->pos, "%s breaks %s",
291
14
		    roff_name[tok], roff_name[n->tok]);
292
293
14
		roff_node_delete(man, n);
294
14
		man->flags &= ~MAN_ELINE;
295
14
	}
296
297
	/*
298
	 * Weird special case:
299
	 * Switching fill mode closes section headers.
300
	 */
301
302

123517
	if (man->flags & MAN_BLINE &&
303
1379
	    (tok == MAN_nf || tok == MAN_fi) &&
304
42
	    (man->last->tok == MAN_SH || man->last->tok == MAN_SS)) {
305
24
		n = man->last;
306
24
		man_unscope(man, n);
307
24
		roff_body_alloc(man, n->line, n->pos, n->tok);
308
24
		man->flags &= ~MAN_BLINE;
309
24
	}
310
311
	/*
312
	 * A block header next line scope is open,
313
	 * and the new macro is not allowed inside block headers.
314
	 * Delete the block that is being broken.
315
	 */
316
317

126194
	if (man->flags & MAN_BLINE && (tok < MAN_TH ||
318
1337
	    man_macros[tok].flags & MAN_BSCOPE)) {
319
162
		n = man->last;
320
162
		if (n->type == ROFFT_TEXT)
321
18
			n = n->parent;
322

324
		if (n->tok < MAN_TH ||
323
162
		    (man_macros[n->tok].flags & MAN_BSCOPE) == 0)
324
5
			n = n->parent;
325
326
162
		assert(n->type == ROFFT_HEAD);
327
162
		n = n->parent;
328
162
		assert(n->type == ROFFT_BLOCK);
329
162
		assert(man_macros[n->tok].flags & MAN_SCOPED);
330
331
324
		mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
332
162
		    n->line, n->pos, "%s breaks %s",
333
162
		    roff_name[tok], roff_name[n->tok]);
334
335
162
		roff_node_delete(man, n);
336
162
		man->flags &= ~MAN_BLINE;
337
162
	}
338
123502
}
339
340
const struct mparse *
341
man_mparse(const struct roff_man *man)
342
{
343
344
	assert(man && man->parse);
345
	return man->parse;
346
}
347
348
void
349
man_state(struct roff_man *man, struct roff_node *n)
350
{
351
352

681176
	switch(n->tok) {
353
	case MAN_nf:
354
	case MAN_EX:
355

22423
		if (man->flags & MAN_LITERAL && ! (n->flags & NODE_VALID))
356
32
			mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
357
16
			    n->line, n->pos, "nf");
358
22390
		man->flags |= MAN_LITERAL;
359
22390
		break;
360
	case MAN_fi:
361
	case MAN_EE:
362

22384
		if ( ! (man->flags & MAN_LITERAL) &&
363
48
		     ! (n->flags & NODE_VALID))
364
60
			mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
365
30
			    n->line, n->pos, "fi");
366
22336
		man->flags &= ~MAN_LITERAL;
367
22336
		break;
368
	default:
369
		break;
370
	}
371
318225
	man->last->flags |= NODE_VALID;
372
318225
}
373
374
void
375
man_validate(struct roff_man *man)
376
{
377
378
4522
	man->last = man->first;
379
2261
	man_node_validate(man);
380
2261
	man->flags &= ~MAN_LITERAL;
381
2261
}