1 /*
2 * Top users/processes display for Unix
3 * Version 3
4 *
5 * This program may be freely redistributed,
6 * but this entire comment MUST remain intact.
7 *
8 * Copyright (c) 1984, 1989, William LeFebvre, Rice University
9 * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
10 *
11 * $FreeBSD$
12 */
13
14 /* This file contains the routines that interface to termcap and stty/gtty.
15 *
16 * Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty.
17 *
18 * I put in code to turn on the TOSTOP bit while top was running, but I
19 * didn't really like the results. If you desire it, turn on the
20 * preprocessor variable "TOStop". --wnl
21 */
22
23 #include "os.h"
24 #include "top.h"
25
26 #include <sys/ioctl.h>
27 #ifdef CBREAK
28 # include <sgtty.h>
29 # define SGTTY
30 #else
31 # ifdef TCGETA
32 # define TERMIO
33 # include <termio.h>
34 # else
35 # define TERMIOS
36 # include <termios.h>
37 # endif
38 #endif
39 #if defined(TERMIO) || defined(TERMIOS)
40 # ifndef TAB3
41 # ifdef OXTABS
42 # define TAB3 OXTABS
43 # else
44 # define TAB3 0
45 # endif
46 # endif
47 #endif
48 #include "screen.h"
49 #include "boolean.h"
50
51 extern char *myname;
52
53 int putstdout();
54
55 int overstrike;
56 int screen_length;
57 int screen_width;
58 char ch_erase;
59 char ch_kill;
60 char smart_terminal;
61 char PC;
62 char *tgetstr();
63 char *tgoto();
64 char termcap_buf[1024];
65 char string_buffer[1024];
66 char home[15];
67 char lower_left[15];
68 char *clear_line;
69 char *clear_screen;
70 char *clear_to_end;
71 char *cursor_motion;
72 char *start_standout;
73 char *end_standout;
74 char *terminal_init;
75 char *terminal_end;
76
77 #ifdef SGTTY
78 static struct sgttyb old_settings;
79 static struct sgttyb new_settings;
80 #endif
81 #ifdef TERMIO
82 static struct termio old_settings;
83 static struct termio new_settings;
84 #endif
85 #ifdef TERMIOS
86 static struct termios old_settings;
87 static struct termios new_settings;
88 #endif
89 static char is_a_terminal = No;
90 #ifdef TOStop
91 static int old_lword;
92 static int new_lword;
93 #endif
94
95 #define STDIN 0
96 #define STDOUT 1
97 #define STDERR 2
98
99 void
init_termcap(interactive)100 init_termcap(interactive)
101
102 int interactive;
103
104 {
105 char *bufptr;
106 char *PCptr;
107 char *term_name;
108 char *getenv();
109 int status;
110
111 /* set defaults in case we aren't smart */
112 screen_width = MAX_COLS;
113 screen_length = 0;
114
115 if (!interactive)
116 {
117 /* pretend we have a dumb terminal */
118 smart_terminal = No;
119 return;
120 }
121
122 /* assume we have a smart terminal until proven otherwise */
123 smart_terminal = Yes;
124
125 /* get the terminal name */
126 term_name = getenv("TERM");
127
128 /* if there is no TERM, assume it's a dumb terminal */
129 /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */
130 if (term_name == NULL)
131 {
132 smart_terminal = No;
133 return;
134 }
135
136 /* now get the termcap entry */
137 if ((status = tgetent(termcap_buf, term_name)) != 1)
138 {
139 if (status == -1)
140 {
141 fprintf(stderr, "%s: can't open termcap file\n", myname);
142 }
143 else
144 {
145 fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n",
146 myname, term_name);
147 }
148
149 /* pretend it's dumb and proceed */
150 smart_terminal = No;
151 return;
152 }
153
154 /* "hardcopy" immediately indicates a very stupid terminal */
155 if (tgetflag("hc"))
156 {
157 smart_terminal = No;
158 return;
159 }
160
161 /* set up common terminal capabilities */
162 if ((screen_length = tgetnum("li")) <= 0)
163 {
164 screen_length = smart_terminal = 0;
165 return;
166 }
167
168 /* screen_width is a little different */
169 if ((screen_width = tgetnum("co")) == -1)
170 {
171 screen_width = 79;
172 }
173 else
174 {
175 screen_width -= 1;
176 }
177
178 /* terminals that overstrike need special attention */
179 overstrike = tgetflag("os");
180
181 /* initialize the pointer into the termcap string buffer */
182 bufptr = string_buffer;
183
184 /* get "ce", clear to end */
185 if (!overstrike)
186 {
187 clear_line = tgetstr("ce", &bufptr);
188 }
189
190 /* get necessary capabilities */
191 if ((clear_screen = tgetstr("cl", &bufptr)) == NULL ||
192 (cursor_motion = tgetstr("cm", &bufptr)) == NULL)
193 {
194 smart_terminal = No;
195 return;
196 }
197
198 /* get some more sophisticated stuff -- these are optional */
199 clear_to_end = tgetstr("cd", &bufptr);
200 terminal_init = tgetstr("ti", &bufptr);
201 terminal_end = tgetstr("te", &bufptr);
202 start_standout = tgetstr("so", &bufptr);
203 end_standout = tgetstr("se", &bufptr);
204
205 /* pad character */
206 PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0;
207
208 /* set convenience strings */
209 (void) strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1);
210 home[sizeof(home) - 1] = '\0';
211 /* (lower_left is set in get_screensize) */
212
213 /* get the actual screen size with an ioctl, if needed */
214 /* This may change screen_width and screen_length, and it always
215 sets lower_left. */
216 get_screensize();
217
218 /* if stdout is not a terminal, pretend we are a dumb terminal */
219 #ifdef SGTTY
220 if (ioctl(STDOUT, TIOCGETP, &old_settings) == -1)
221 {
222 smart_terminal = No;
223 }
224 #endif
225 #ifdef TERMIO
226 if (ioctl(STDOUT, TCGETA, &old_settings) == -1)
227 {
228 smart_terminal = No;
229 }
230 #endif
231 #ifdef TERMIOS
232 if (tcgetattr(STDOUT, &old_settings) == -1)
233 {
234 smart_terminal = No;
235 }
236 #endif
237 }
238
init_screen()239 init_screen()
240
241 {
242 /* get the old settings for safe keeping */
243 #ifdef SGTTY
244 if (ioctl(STDOUT, TIOCGETP, &old_settings) != -1)
245 {
246 /* copy the settings so we can modify them */
247 new_settings = old_settings;
248
249 /* turn on CBREAK and turn off character echo and tab expansion */
250 new_settings.sg_flags |= CBREAK;
251 new_settings.sg_flags &= ~(ECHO|XTABS);
252 (void) ioctl(STDOUT, TIOCSETP, &new_settings);
253
254 /* remember the erase and kill characters */
255 ch_erase = old_settings.sg_erase;
256 ch_kill = old_settings.sg_kill;
257
258 #ifdef TOStop
259 /* get the local mode word */
260 (void) ioctl(STDOUT, TIOCLGET, &old_lword);
261
262 /* modify it */
263 new_lword = old_lword | LTOSTOP;
264 (void) ioctl(STDOUT, TIOCLSET, &new_lword);
265 #endif
266 /* remember that it really is a terminal */
267 is_a_terminal = Yes;
268
269 /* send the termcap initialization string */
270 putcap(terminal_init);
271 }
272 #endif
273 #ifdef TERMIO
274 if (ioctl(STDOUT, TCGETA, &old_settings) != -1)
275 {
276 /* copy the settings so we can modify them */
277 new_settings = old_settings;
278
279 /* turn off ICANON, character echo and tab expansion */
280 new_settings.c_lflag &= ~(ICANON|ECHO);
281 new_settings.c_oflag &= ~(TAB3);
282 new_settings.c_cc[VMIN] = 1;
283 new_settings.c_cc[VTIME] = 0;
284 (void) ioctl(STDOUT, TCSETA, &new_settings);
285
286 /* remember the erase and kill characters */
287 ch_erase = old_settings.c_cc[VERASE];
288 ch_kill = old_settings.c_cc[VKILL];
289
290 /* remember that it really is a terminal */
291 is_a_terminal = Yes;
292
293 /* send the termcap initialization string */
294 putcap(terminal_init);
295 }
296 #endif
297 #ifdef TERMIOS
298 if (tcgetattr(STDOUT, &old_settings) != -1)
299 {
300 /* copy the settings so we can modify them */
301 new_settings = old_settings;
302
303 /* turn off ICANON, character echo and tab expansion */
304 new_settings.c_lflag &= ~(ICANON|ECHO);
305 new_settings.c_oflag &= ~(TAB3);
306 new_settings.c_cc[VMIN] = 1;
307 new_settings.c_cc[VTIME] = 0;
308 (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings);
309
310 /* remember the erase and kill characters */
311 ch_erase = old_settings.c_cc[VERASE];
312 ch_kill = old_settings.c_cc[VKILL];
313
314 /* remember that it really is a terminal */
315 is_a_terminal = Yes;
316
317 /* send the termcap initialization string */
318 putcap(terminal_init);
319 }
320 #endif
321
322 if (!is_a_terminal)
323 {
324 /* not a terminal at all---consider it dumb */
325 smart_terminal = No;
326 }
327 }
328
end_screen()329 end_screen()
330
331 {
332 /* move to the lower left, clear the line and send "te" */
333 if (smart_terminal)
334 {
335 putcap(lower_left);
336 putcap(clear_line);
337 fflush(stdout);
338 putcap(terminal_end);
339 }
340
341 /* if we have settings to reset, then do so */
342 if (is_a_terminal)
343 {
344 #ifdef SGTTY
345 (void) ioctl(STDOUT, TIOCSETP, &old_settings);
346 #ifdef TOStop
347 (void) ioctl(STDOUT, TIOCLSET, &old_lword);
348 #endif
349 #endif
350 #ifdef TERMIO
351 (void) ioctl(STDOUT, TCSETA, &old_settings);
352 #endif
353 #ifdef TERMIOS
354 (void) tcsetattr(STDOUT, TCSADRAIN, &old_settings);
355 #endif
356 }
357 }
358
reinit_screen()359 reinit_screen()
360
361 {
362 /* install our settings if it is a terminal */
363 if (is_a_terminal)
364 {
365 #ifdef SGTTY
366 (void) ioctl(STDOUT, TIOCSETP, &new_settings);
367 #ifdef TOStop
368 (void) ioctl(STDOUT, TIOCLSET, &new_lword);
369 #endif
370 #endif
371 #ifdef TERMIO
372 (void) ioctl(STDOUT, TCSETA, &new_settings);
373 #endif
374 #ifdef TERMIOS
375 (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings);
376 #endif
377 }
378
379 /* send init string */
380 if (smart_terminal)
381 {
382 putcap(terminal_init);
383 }
384 }
385
get_screensize()386 get_screensize()
387
388 {
389
390 #ifdef TIOCGWINSZ
391
392 struct winsize ws;
393
394 if (ioctl (1, TIOCGWINSZ, &ws) != -1)
395 {
396 if (ws.ws_row != 0)
397 {
398 screen_length = ws.ws_row;
399 }
400 if (ws.ws_col != 0)
401 {
402 screen_width = ws.ws_col - 1;
403 }
404 }
405
406 #else
407 #ifdef TIOCGSIZE
408
409 struct ttysize ts;
410
411 if (ioctl (1, TIOCGSIZE, &ts) != -1)
412 {
413 if (ts.ts_lines != 0)
414 {
415 screen_length = ts.ts_lines;
416 }
417 if (ts.ts_cols != 0)
418 {
419 screen_width = ts.ts_cols - 1;
420 }
421 }
422
423 #endif /* TIOCGSIZE */
424 #endif /* TIOCGWINSZ */
425
426 (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1),
427 sizeof(lower_left) - 1);
428 lower_left[sizeof(lower_left) - 1] = '\0';
429 }
430
standout(msg)431 standout(msg)
432
433 char *msg;
434
435 {
436 if (smart_terminal)
437 {
438 putcap(start_standout);
439 fputs(msg, stdout);
440 putcap(end_standout);
441 }
442 else
443 {
444 fputs(msg, stdout);
445 }
446 }
447
clear()448 clear()
449
450 {
451 if (smart_terminal)
452 {
453 putcap(clear_screen);
454 }
455 }
456
clear_eol(len)457 clear_eol(len)
458
459 int len;
460
461 {
462 if (smart_terminal && !overstrike && len > 0)
463 {
464 if (clear_line)
465 {
466 putcap(clear_line);
467 return(0);
468 }
469 else
470 {
471 while (len-- > 0)
472 {
473 putchar(' ');
474 }
475 return(1);
476 }
477 }
478 return(-1);
479 }
480
go_home()481 go_home()
482
483 {
484 if (smart_terminal)
485 {
486 putcap(home);
487 }
488 }
489
490 /* This has to be defined as a subroutine for tputs (instead of a macro) */
491
putstdout(ch)492 putstdout(ch)
493
494 char ch;
495
496 {
497 putchar(ch);
498 }
499
500