2 * Copyright (c) 1984 through 2008, William LeFebvre
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
16 * * Neither the name of William LeFebvre nor the names of other
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Top users/processes display for Unix
38 /* This file contains the routines that interface to termcap and stty/gtty.
40 * Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty.
42 * I put in code to turn on the TOSTOP bit while top was running, but I
43 * didn't really like the results. If you desire it, turn on the
44 * preprocessor variable "TOStop". --wnl
50 #if HAVE_CURSES_H && HAVE_TERM_H
64 int tputs(const char *, int, int (*)(int));
67 char *tgoto(const char *, int, int);
69 #if !HAVE_DECL_TGETENT
70 int tgetent(const char *, char *);
72 #if !HAVE_DECL_TGETFLAG
73 int tgetflag(const char *);
75 #if !HAVE_DECL_TGETNUM
76 int tgetnum(const char *);
78 #if !HAVE_DECL_TGETSTR
79 char *tgetstr(const char *, char **);
82 #include <sys/ioctl.h>
95 #if defined(USE_TERMIO) || defined(USE_TERMIOS)
108 #define putcap(str) (void)((str) != NULL ? tputs(str, 1, putstdout) : 0)
121 static int tc_overstrike;
122 static char termcap_buf[1024];
123 static char string_buffer[1024];
124 static char home[15];
125 static char lower_left[15];
126 static char *tc_clear_line;
127 static char *tc_clear_screen;
128 static char *tc_clear_to_end;
129 static char *tc_cursor_motion;
130 static char *tc_start_standout;
131 static char *tc_end_standout;
132 static char *terminal_init;
133 static char *terminal_end;
136 static struct sgttyb old_settings;
137 static struct sgttyb new_settings;
140 static struct termio old_settings;
141 static struct termio new_settings;
144 static struct termios old_settings;
145 static struct termios new_settings;
147 static char is_a_terminal = No;
149 static int old_lword;
150 static int new_lword;
157 /* This has to be defined as a subroutine for tputs (instead of a macro) */
160 putstdout(TPUTS_PUTC_ARGTYPE ch)
163 return putchar((int)ch);
175 if (ioctl (1, TIOCGWINSZ, &ws) != -1)
179 screen_length = ws.ws_row;
183 screen_width = ws.ws_col - 1;
192 if (ioctl (1, TIOCGSIZE, &ts) != -1)
194 if (ts.ts_lines != 0)
196 screen_length = ts.ts_lines;
200 screen_width = ts.ts_cols - 1;
204 #endif /* TIOCGSIZE */
205 #endif /* TIOCGWINSZ */
207 (void) strcpy(lower_left, tgoto(tc_cursor_motion, 0, screen_length - 1));
211 screen_readtermcap(int interactive)
220 /* set defaults in case we aren't smart */
221 screen_width = MAX_COLS;
224 if (interactive == No)
226 /* pretend we have a dumb terminal */
231 /* assume we have a smart terminal until proven otherwise */
232 smart_terminal = Yes;
234 /* get the terminal name */
235 term_name = getenv("TERM");
237 /* if there is no TERM, assume it's a dumb terminal */
238 /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */
239 if (term_name == NULL)
245 /* now get the termcap entry */
246 if ((status = tgetent(termcap_buf, term_name)) != 1)
250 fprintf(stderr, "%s: can't open termcap file\n", myname);
254 fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n",
258 /* pretend it's dumb and proceed */
263 /* "hardcopy" immediately indicates a very stupid terminal */
270 /* set up common terminal capabilities */
271 if ((screen_length = tgetnum("li")) <= 0)
273 screen_length = smart_terminal = 0;
277 /* screen_width is a little different */
278 if ((screen_width = tgetnum("co")) == -1)
287 /* terminals that overstrike need special attention */
288 tc_overstrike = tgetflag("os");
290 /* initialize the pointer into the termcap string buffer */
291 bufptr = string_buffer;
293 /* get "ce", clear to end */
296 tc_clear_line = tgetstr("ce", &bufptr);
299 /* get necessary capabilities */
300 if ((tc_clear_screen = tgetstr("cl", &bufptr)) == NULL ||
301 (tc_cursor_motion = tgetstr("cm", &bufptr)) == NULL)
307 /* get some more sophisticated stuff -- these are optional */
308 tc_clear_to_end = tgetstr("cd", &bufptr);
309 terminal_init = tgetstr("ti", &bufptr);
310 terminal_end = tgetstr("te", &bufptr);
311 tc_start_standout = tgetstr("so", &bufptr);
312 tc_end_standout = tgetstr("se", &bufptr);
315 PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0;
317 /* set convenience strings */
318 (void) strcpy(home, tgoto(tc_cursor_motion, 0, 0));
319 /* (lower_left is set in screen_getsize) */
321 /* get the actual screen size with an ioctl, if needed */
322 /* This may change screen_width and screen_length, and it always
326 /* if stdout is not a terminal, pretend we are a dumb terminal */
328 if (ioctl(STDOUT, TIOCGETP, &old_settings) == -1)
334 if (ioctl(STDOUT, TCGETA, &old_settings) == -1)
340 if (tcgetattr(STDOUT, &old_settings) == -1)
346 return smart_terminal;
353 /* get the old settings for safe keeping */
355 if (ioctl(STDOUT, TIOCGETP, &old_settings) != -1)
357 /* copy the settings so we can modify them */
358 new_settings = old_settings;
360 /* turn on CBREAK and turn off character echo and tab expansion */
361 new_settings.sg_flags |= CBREAK;
362 new_settings.sg_flags &= ~(ECHO|XTABS);
363 (void) ioctl(STDOUT, TIOCSETP, &new_settings);
365 /* remember the erase and kill characters */
366 ch_erase = old_settings.sg_erase;
367 ch_kill = old_settings.sg_kill;
368 ch_werase = old_settings.sg_werase;
371 /* get the local mode word */
372 (void) ioctl(STDOUT, TIOCLGET, &old_lword);
375 new_lword = old_lword | LTOSTOP;
376 (void) ioctl(STDOUT, TIOCLSET, &new_lword);
378 /* remember that it really is a terminal */
381 /* send the termcap initialization string */
382 putcap(terminal_init);
386 if (ioctl(STDOUT, TCGETA, &old_settings) != -1)
388 /* copy the settings so we can modify them */
389 new_settings = old_settings;
391 /* turn off ICANON, character echo and tab expansion */
392 new_settings.c_lflag &= ~(ICANON|ECHO);
393 new_settings.c_oflag &= ~(TAB3);
394 new_settings.c_cc[VMIN] = 1;
395 new_settings.c_cc[VTIME] = 0;
396 (void) ioctl(STDOUT, TCSETA, &new_settings);
398 /* remember the erase and kill characters */
399 ch_erase = old_settings.c_cc[VERASE];
400 ch_kill = old_settings.c_cc[VKILL];
401 ch_werase = old_settings.c_cc[VWERASE];
403 /* remember that it really is a terminal */
406 /* send the termcap initialization string */
407 putcap(terminal_init);
411 if (tcgetattr(STDOUT, &old_settings) != -1)
413 /* copy the settings so we can modify them */
414 new_settings = old_settings;
416 /* turn off ICANON, character echo and tab expansion */
417 new_settings.c_lflag &= ~(ICANON|ECHO);
418 new_settings.c_oflag &= ~(TAB3);
419 new_settings.c_cc[VMIN] = 1;
420 new_settings.c_cc[VTIME] = 0;
421 (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings);
423 /* remember the erase and kill characters */
424 ch_erase = old_settings.c_cc[VERASE];
425 ch_kill = old_settings.c_cc[VKILL];
426 ch_werase = old_settings.c_cc[VWERASE];
428 /* remember that it really is a terminal */
431 /* send the termcap initialization string */
432 putcap(terminal_init);
438 /* not a terminal at all---consider it dumb */
447 /* move to the lower left, clear the line and send "te" */
451 putcap(tc_clear_line);
453 putcap(terminal_end);
456 /* if we have settings to reset, then do so */
460 (void) ioctl(STDOUT, TIOCSETP, &old_settings);
462 (void) ioctl(STDOUT, TIOCLSET, &old_lword);
466 (void) ioctl(STDOUT, TCSETA, &old_settings);
469 (void) tcsetattr(STDOUT, TCSADRAIN, &old_settings);
478 /* install our settings if it is a terminal */
482 (void) ioctl(STDOUT, TIOCSETP, &new_settings);
484 (void) ioctl(STDOUT, TIOCLSET, &new_lword);
488 (void) ioctl(STDOUT, TCSETA, &new_settings);
491 (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings);
495 /* send init string */
498 putcap(terminal_init);
503 screen_move(int x, int y)
506 tputs(tgoto(tc_cursor_motion, x, y), 1, putstdout);
510 screen_standout(char *msg)
515 putcap(tc_start_standout);
517 putcap(tc_end_standout);
531 putcap(tc_clear_screen);
543 putcap(tc_clear_to_end);
551 screen_cleareol(int len)
556 if (smart_terminal && !tc_overstrike && len > 0)
560 putcap(tc_clear_line);