xref: /freebsd/usr.bin/systat/keyboard.c (revision ef36b3f75658d201edb495068db5e1be49593de5)
1 /*-
2  * Copyright (c) 1980, 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 
32 __FBSDID("$FreeBSD$");
33 
34 #ifdef lint
35 static const char sccsid[] = "@(#)keyboard.c	8.1 (Berkeley) 6/6/93";
36 #endif
37 
38 #include <sys/select.h>
39 #include <sys/time.h>
40 
41 #include <errno.h>
42 #include <ctype.h>
43 #include <stdlib.h>
44 #include <termios.h>
45 #include <unistd.h>
46 
47 #include "systat.h"
48 #include "extern.h"
49 
50 static char line[80];
51 static int keyboard_dispatch(int ch);
52 
53 int
54 keyboard(void)
55 {
56 	int ch, n;
57 	struct timeval last, intvl, now, tm;
58 	fd_set rfds;
59 
60 	/* Set initial timings */
61 	gettimeofday(&last, NULL);
62 	intvl.tv_sec = delay / 1000000;
63 	intvl.tv_usec = delay % 1000000;
64 	for (;;) {
65 		col = 0;
66 		move(CMDLINE, 0);
67 		for (;;) {
68 			/* Determine interval to sleep */
69 			(void)gettimeofday(&now, NULL);
70 			tm.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
71 			tm.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
72 			while (tm.tv_usec < 0) {
73 				tm.tv_usec += 1000000;
74 				tm.tv_sec--;
75 			}
76 			while (tm.tv_usec >= 1000000) {
77 				tm.tv_usec -= 1000000;
78 				tm.tv_sec++;
79 			}
80 			if (tm.tv_sec < 0) {
81 				/* We have to update screen immediately */
82 				display();
83 				gettimeofday(&last, NULL);
84 				continue;
85 			}
86 
87 			/* Prepare select  */
88 			FD_ZERO(&rfds);
89 			FD_SET(STDIN_FILENO, &rfds);
90 			n = select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tm);
91 
92 			if (n > 0) {
93 				/* Read event on stdin */
94 				ch = getch();
95 
96 				if (keyboard_dispatch(ch) == 0) {
97 					refresh();
98 					continue;
99 				}
100 
101 				line[col] = '\0';
102 				command(line + 1);
103 				/* Refresh delay */
104 				intvl.tv_sec = delay / 1000000;
105 				intvl.tv_usec = delay % 1000000;
106 				refresh();
107 				break;
108 			}
109 
110 			if (n < 0 && errno != EINTR)
111 				exit(1);
112 
113 			/* Timeout or signal. Call display another time */
114 			display();
115 			gettimeofday(&last, NULL);
116 		}
117 	}
118 }
119 
120 static int
121 keyboard_dispatch(int ch)
122 {
123 
124 	if (ch == ERR) {
125 		if (errno == EINTR)
126 			return 0;
127 		exit(1);
128 	}
129 	if (ch >= 'A' && ch <= 'Z')
130 		ch += 'a' - 'A';
131 	if (col == 0) {
132 		if (ch == CTRL('l')) {
133 			wrefresh(curscr);
134 			return 0;
135 		}
136 		if (ch == CTRL('g')) {
137 			status();
138 			return 0;
139 		}
140 		if (ch != ':')
141 			return 0;
142 		move(CMDLINE, 0);
143 		clrtoeol();
144 	}
145 	if (ch == erasechar() && col > 0) {
146 		if (col == 1 && line[0] == ':')
147 			return 0;
148 		col--;
149 		goto doerase;
150 	}
151 	if (ch == CTRL('w') && col > 0) {
152 		while (--col >= 0 && isspace(line[col]))
153 			;
154 		col++;
155 		while (--col >= 0 && !isspace(line[col]))
156 			if (col == 0 && line[0] == ':')
157 				return 1;
158 		col++;
159 		goto doerase;
160 	}
161 	if (ch == killchar() && col > 0) {
162 		col = 0;
163 		if (line[0] == ':')
164 			col++;
165 doerase:
166 		move(CMDLINE, col);
167 		clrtoeol();
168 		return 0;
169 	}
170 	if (isprint(ch) || ch == ' ') {
171 		line[col] = ch;
172 		mvaddch(CMDLINE, col, ch);
173 		col++;
174 	}
175 
176 	if (col == 0 || (ch != '\r' && ch != '\n'))
177 		return 0;
178 
179 	return 1;
180 }
181