GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mg/ttyio.c Lines: 0 73 0.0 %
Date: 2017-11-13 Branches: 0 44 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: ttyio.c,v 1.37 2015/03/23 12:31:19 bcallah Exp $	*/
2
3
/* This file is in the public domain. */
4
5
/*
6
 * POSIX terminal I/O.
7
 *
8
 * The functions in this file negotiate with the operating system for
9
 * keyboard characters, and write characters to the display in a barely
10
 * buffered fashion.
11
 */
12
13
#include <sys/ioctl.h>
14
#include <sys/queue.h>
15
#include <sys/time.h>
16
#include <sys/types.h>
17
#include <errno.h>
18
#include <fcntl.h>
19
#include <poll.h>
20
#include <signal.h>
21
#include <stdio.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <term.h>
25
#include <termios.h>
26
#include <unistd.h>
27
28
#include "def.h"
29
30
#define NOBUF	512			/* Output buffer size. */
31
32
int	ttstarted;
33
char	obuf[NOBUF];			/* Output buffer. */
34
size_t	nobuf;				/* Buffer count. */
35
struct	termios	oldtty;			/* POSIX tty settings. */
36
struct	termios	newtty;
37
int	nrow;				/* Terminal size, rows. */
38
int	ncol;				/* Terminal size, columns. */
39
40
/*
41
 * This function gets called once, to set up the terminal.
42
 * On systems w/o TCSASOFT we turn off off flow control,
43
 * which isn't really the right thing to do.
44
 */
45
void
46
ttopen(void)
47
{
48
	if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO))
49
		panic("standard input and output must be a terminal");
50
51
	if (ttraw() == FALSE)
52
		panic("aborting due to terminal initialize failure");
53
}
54
55
/*
56
 * This function sets the terminal to RAW mode, as defined for the current
57
 * shell.  This is called both by ttopen() above and by spawncli() to
58
 * get the current terminal settings and then change them to what
59
 * mg expects.	Thus, tty changes done while spawncli() is in effect
60
 * will be reflected in mg.
61
 */
62
int
63
ttraw(void)
64
{
65
	if (tcgetattr(0, &oldtty) < 0) {
66
		dobeep();
67
		ewprintf("ttopen can't get terminal attributes");
68
		return (FALSE);
69
	}
70
	(void)memcpy(&newtty, &oldtty, sizeof(newtty));
71
	/* Set terminal to 'raw' mode and ignore a 'break' */
72
	newtty.c_cc[VMIN] = 1;
73
	newtty.c_cc[VTIME] = 0;
74
	newtty.c_iflag |= IGNBRK;
75
	newtty.c_iflag &= ~(BRKINT | PARMRK | INLCR | IGNCR | ICRNL | IXON);
76
	newtty.c_oflag &= ~OPOST;
77
	newtty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
78
79
	if (tcsetattr(0, TCSASOFT | TCSADRAIN, &newtty) < 0) {
80
		dobeep();
81
		ewprintf("ttopen can't tcsetattr");
82
		return (FALSE);
83
	}
84
	ttstarted = 1;
85
86
	return (TRUE);
87
}
88
89
/*
90
 * This function gets called just before we go back home to the shell.
91
 * Put all of the terminal parameters back.
92
 * Under UN*X this just calls ttcooked(), but the ttclose() hook is in
93
 * because vttidy() in display.c expects it for portability reasons.
94
 */
95
void
96
ttclose(void)
97
{
98
	if (ttstarted) {
99
		if (ttcooked() == FALSE)
100
			panic("");	/* ttcooked() already printf'd */
101
		ttstarted = 0;
102
	}
103
}
104
105
/*
106
 * This function restores all terminal settings to their default values,
107
 * in anticipation of exiting or suspending the editor.
108
 */
109
int
110
ttcooked(void)
111
{
112
	ttflush();
113
	if (tcsetattr(0, TCSASOFT | TCSADRAIN, &oldtty) < 0) {
114
		dobeep();
115
		ewprintf("ttclose can't tcsetattr");
116
		return (FALSE);
117
	}
118
	return (TRUE);
119
}
120
121
/*
122
 * Write character to the display.  Characters are buffered up,
123
 * to make things a little bit more efficient.
124
 */
125
int
126
ttputc(int c)
127
{
128
	if (nobuf >= NOBUF)
129
		ttflush();
130
	obuf[nobuf++] = c;
131
	return (c);
132
}
133
134
/*
135
 * Flush output.
136
 */
137
void
138
ttflush(void)
139
{
140
	ssize_t	 written;
141
	char	*buf = obuf;
142
143
	if (nobuf == 0)
144
		return;
145
146
	while ((written = write(fileno(stdout), buf, nobuf)) != nobuf) {
147
		if (written == -1) {
148
			if (errno == EINTR)
149
				continue;
150
			panic("ttflush write failed");
151
		}
152
		buf += written;
153
		nobuf -= written;
154
	}
155
	nobuf = 0;
156
}
157
158
/*
159
 * Read character from terminal. All 8 bits are returned, so that you
160
 * can use a multi-national terminal.
161
 */
162
int
163
ttgetc(void)
164
{
165
	char	c;
166
	ssize_t	ret;
167
168
	do {
169
		ret = read(STDIN_FILENO, &c, 1);
170
		if (ret == -1 && errno == EINTR) {
171
			if (winch_flag) {
172
				redraw(0, 0);
173
				winch_flag = 0;
174
			}
175
		} else if (ret == -1 && errno == EIO)
176
			panic("lost stdin");
177
		else if (ret == 1)
178
			break;
179
	} while (1);
180
	return ((int) c) & 0xFF;
181
}
182
183
/*
184
 * Returns TRUE if there are characters waiting to be read.
185
 */
186
int
187
charswaiting(void)
188
{
189
	int	x;
190
191
	return ((ioctl(0, FIONREAD, &x) < 0) ? 0 : x);
192
}
193
194
/*
195
 * panic - just exit, as quickly as we can.
196
 */
197
void
198
panic(char *s)
199
{
200
	static int panicking = 0;
201
202
	if (panicking)
203
		return;
204
	else
205
		panicking = 1;
206
	ttclose();
207
	(void) fputs("panic: ", stderr);
208
	(void) fputs(s, stderr);
209
	(void) fputc('\n', stderr);
210
	exit(1);
211
}
212
213
/*
214
 * This function returns FALSE if any characters have showed up on the
215
 * tty before 'msec' milliseconds.
216
 */
217
int
218
ttwait(int msec)
219
{
220
	struct pollfd	pfd[1];
221
222
	pfd[0].fd = 0;
223
	pfd[0].events = POLLIN;
224
225
	if ((poll(pfd, 1, msec)) == 0)
226
		return (TRUE);
227
	return (FALSE);
228
}