GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/less/less/../output.c Lines: 55 107 51.4 %
Date: 2017-11-13 Branches: 21 56 37.5 %

Line Branch Exec Source
1
/*
2
 * Copyright (C) 1984-2012  Mark Nudelman
3
 * Modified for use with illumos by Garrett D'Amore.
4
 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
5
 *
6
 * You may distribute under the terms of either the GNU General Public
7
 * License or the Less License, as specified in the README file.
8
 *
9
 * For more information, see the README file.
10
 */
11
12
/*
13
 * High level routines dealing with the output to the screen.
14
 */
15
16
#include "less.h"
17
18
int errmsgs;	/* Count of messages displayed by error() */
19
20
extern volatile sig_atomic_t sigs;
21
extern int sc_width;
22
extern int so_s_width, so_e_width;
23
extern int screen_trashed;
24
extern int any_display;
25
extern int is_tty;
26
extern int oldbot;
27
28
static int need_clr;
29
30
/*
31
 * Display the line which is in the line buffer.
32
 */
33
void
34
put_line(void)
35
{
36
	int c;
37
	int i;
38
1928
	int a;
39
40
964
	if (ABORT_SIGS()) {
41
		/*
42
		 * Don't output if a signal is pending.
43
		 */
44
		screen_trashed = 1;
45
		return;
46
	}
47
48
62964
	for (i = 0; (c = gline(i, &a)) != '\0'; i++) {
49
30518
		at_switch(a);
50
30518
		if (c == '\b')
51
13
			putbs();
52
		else
53
30505
			(void) putchr(c);
54
	}
55
56
964
	at_exit();
57
1928
}
58
59
static char obuf[OUTBUF_SIZE];
60
static char *ob = obuf;
61
62
/*
63
 * Flush buffered output.
64
 *
65
 * If we haven't displayed any file data yet,
66
 * output messages on error output (file descriptor 2),
67
 * otherwise output on standard output (file descriptor 1).
68
 *
69
 * This has the desirable effect of producing all
70
 * error messages on error output if standard output
71
 * is directed to a file.  It also does the same if
72
 * we never produce any real output; for example, if
73
 * the input file(s) cannot be opened.  If we do
74
 * eventually produce output, code in edit() makes
75
 * sure these messages can be seen before they are
76
 * overwritten or scrolled away.
77
 */
78
void
79
flush(int ignore_errors)
80
{
81
	int n;
82
	int fd;
83
	ssize_t nwritten;
84
85
576
	n = (intptr_t)ob - (intptr_t)obuf;
86
288
	if (n == 0)
87
59
		return;
88
89
229
	fd = (any_display) ? STDOUT_FILENO : STDERR_FILENO;
90
229
	nwritten = write(fd, obuf, n);
91
229
	if (nwritten != n) {
92
		if (nwritten == -1 && !ignore_errors)
93
			quit(QUIT_ERROR);
94
		screen_trashed = 1;
95
	}
96
229
	ob = obuf;
97
517
}
98
99
/*
100
 * Output a character.
101
 */
102
int
103
putchr(int c)
104
{
105
70580
	if (need_clr) {
106
		need_clr = 0;
107
		clear_bot();
108
	}
109
	/*
110
	 * Some versions of flush() write to *ob, so we must flush
111
	 * when we are still one char from the end of obuf.
112
	 */
113
35290
	if (ob >= &obuf[sizeof (obuf)-1])
114
17
		flush(0);
115
35290
	*ob++ = (char)c;
116
35290
	return (c);
117
}
118
119
/*
120
 * Output a string.
121
 */
122
void
123
putstr(const char *s)
124
{
125
2250
	while (*s != '\0')
126
666
		(void) putchr(*s++);
127
306
}
128
129
130
/*
131
 * Convert an integral type to a string.
132
 */
133
#define	TYPE_TO_A_FUNC(funcname, type)		\
134
void						\
135
funcname(type num, char *buf, size_t len)	\
136
{						\
137
	int neg = (num < 0);			\
138
	char tbuf[23];	\
139
	char *s = tbuf + sizeof (tbuf);		\
140
	if (neg)				\
141
		num = -num;			\
142
	*--s = '\0';				\
143
	do {					\
144
		*--s = (num % 10) + '0';	\
145
	} while ((num /= 10) != 0);		\
146
	if (neg)				\
147
		 *--s = '-';			\
148
	(void) strlcpy(buf, s, len);		\
149
}
150
151
TYPE_TO_A_FUNC(postoa, off_t)
152
TYPE_TO_A_FUNC(inttoa, int)
153
154
/*
155
 * Output an integer in a given radix.
156
 */
157
static int
158
iprint_int(int num)
159
{
160
	char buf[11];
161
162
	inttoa(num, buf, sizeof (buf));
163
	putstr(buf);
164
	return (strlen(buf));
165
}
166
167
/*
168
 * Output a line number in a given radix.
169
 */
170
static int
171
iprint_linenum(off_t num)
172
{
173
	char buf[21];
174
175
	postoa(num, buf, sizeof(buf));
176
	putstr(buf);
177
	return (strlen(buf));
178
}
179
180
/*
181
 * This function implements printf-like functionality
182
 * using a more portable argument list mechanism than printf's.
183
 */
184
static int
185
less_printf(const char *fmt, PARG *parg)
186
{
187
	char *s;
188
	int col;
189
190
	col = 0;
191
137
	while (*fmt != '\0') {
192
64
		if (*fmt != '%') {
193
64
			(void) putchr(*fmt++);
194
64
			col++;
195
64
		} else {
196
			++fmt;
197
			switch (*fmt++) {
198
			case 's':
199
				s = parg->p_string;
200
				parg++;
201
				while (*s != '\0') {
202
					(void) putchr(*s++);
203
					col++;
204
				}
205
				break;
206
			case 'd':
207
				col += iprint_int(parg->p_int);
208
				parg++;
209
				break;
210
			case 'n':
211
				col += iprint_linenum(parg->p_linenum);
212
				parg++;
213
				break;
214
			}
215
		}
216
	}
217
3
	return (col);
218
}
219
220
/*
221
 * Get a RETURN.
222
 * If some other non-trivial char is pressed, unget it, so it will
223
 * become the next command.
224
 */
225
void
226
get_return(void)
227
{
228
	int c;
229
230
6
	c = getchr();
231
3
	if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
232
3
		ungetcc(c);
233
3
}
234
235
/*
236
 * Output a message in the lower left corner of the screen
237
 * and wait for carriage return.
238
 */
239
void
240
error(const char *fmt, PARG *parg)
241
{
242
	int col = 0;
243
	static char return_to_continue[] = "  (press RETURN)";
244
245
6
	errmsgs++;
246
247
3
	if (any_display && is_tty) {
248
3
		if (!oldbot)
249
3
			squish_check();
250
3
		at_exit();
251
3
		clear_bot();
252
3
		at_enter(AT_STANDOUT);
253
3
		col += so_s_width;
254
3
	}
255
256
3
	col += less_printf(fmt, parg);
257
258
3
	if (!(any_display && is_tty)) {
259
		(void) putchr('\n');
260
		return;
261
	}
262
263
3
	putstr(return_to_continue);
264
3
	at_exit();
265
3
	col += sizeof (return_to_continue) + so_e_width;
266
267
3
	get_return();
268
3
	lower_left();
269
3
	clear_eol();
270
271
3
	if (col >= sc_width)
272
		/*
273
		 * Printing the message has probably scrolled the screen.
274
		 * {{ Unless the terminal doesn't have auto margins,
275
		 *    in which case we just hammered on the right margin. }}
276
		 */
277
		screen_trashed = 1;
278
279
3
	flush(0);
280
6
}
281
282
static char intr_to_abort[] = "... (interrupt to abort)";
283
284
/*
285
 * Output a message in the lower left corner of the screen
286
 * and don't wait for carriage return.
287
 * Usually used to warn that we are beginning a potentially
288
 * time-consuming operation.
289
 */
290
void
291
ierror(const char *fmt, PARG *parg)
292
{
293
	at_exit();
294
	clear_bot();
295
	at_enter(AT_STANDOUT);
296
	(void) less_printf(fmt, parg);
297
	putstr(intr_to_abort);
298
	at_exit();
299
	flush(0);
300
	need_clr = 1;
301
}
302
303
/*
304
 * Output a message in the lower left corner of the screen
305
 * and return a single-character response.
306
 */
307
int
308
query(const char *fmt, PARG *parg)
309
{
310
	int c;
311
	int col = 0;
312
313
	if (any_display && is_tty)
314
		clear_bot();
315
316
	(void) less_printf(fmt, parg);
317
	c = getchr();
318
319
	if (!(any_display && is_tty)) {
320
		(void) putchr('\n');
321
		return (c);
322
	}
323
324
	lower_left();
325
	if (col >= sc_width)
326
		screen_trashed = 1;
327
	flush(0);
328
329
	return (c);
330
}