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) ((str) != NULL ? (void)tputs(str, 1, putstdout) : (void)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 if ((go
= tgoto(tc_cursor_motion
, 0, screen_length
- 1)) != NULL
)
208 (void) strcpy(lower_left
, go
);
210 lower_left
[0] = '\0';
214 screen_readtermcap(int interactive
)
223 /* set defaults in case we aren't smart */
224 screen_width
= MAX_COLS
;
227 if (interactive
== No
)
229 /* pretend we have a dumb terminal */
234 /* assume we have a smart terminal until proven otherwise */
235 smart_terminal
= Yes
;
237 /* get the terminal name */
238 term_name
= getenv("TERM");
240 /* if there is no TERM, assume it's a dumb terminal */
241 /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */
242 if (term_name
== NULL
)
248 /* now get the termcap entry */
249 if ((status
= tgetent(termcap_buf
, term_name
)) != 1)
253 fprintf(stderr
, "%s: can't open termcap file\n", myname
);
257 fprintf(stderr
, "%s: no termcap entry for a `%s' terminal\n",
261 /* pretend it's dumb and proceed */
266 /* "hardcopy" immediately indicates a very stupid terminal */
273 /* set up common terminal capabilities */
274 if ((screen_length
= tgetnum("li")) <= 0)
279 /* screen_width is a little different */
280 if ((screen_width
= tgetnum("co")) == -1)
289 /* terminals that overstrike need special attention */
290 tc_overstrike
= tgetflag("os");
292 /* initialize the pointer into the termcap string buffer */
293 bufptr
= string_buffer
;
295 /* get "ce", clear to end */
298 tc_clear_line
= tgetstr("ce", &bufptr
);
301 /* get necessary capabilities */
302 if ((tc_clear_screen
= tgetstr("cl", &bufptr
)) == NULL
||
303 (tc_cursor_motion
= tgetstr("cm", &bufptr
)) == NULL
)
309 /* get some more sophisticated stuff -- these are optional */
310 tc_clear_to_end
= tgetstr("cd", &bufptr
);
311 terminal_init
= tgetstr("ti", &bufptr
);
312 terminal_end
= tgetstr("te", &bufptr
);
313 tc_start_standout
= tgetstr("so", &bufptr
);
314 tc_end_standout
= tgetstr("se", &bufptr
);
317 PC
= (PCptr
= tgetstr("pc", &bufptr
)) ? *PCptr
: 0;
319 /* set convenience strings */
320 if ((go
= tgoto(tc_cursor_motion
, 0, 0)) != NULL
)
321 (void) strcpy(home
, go
);
324 /* (lower_left is set in screen_getsize) */
326 /* get the actual screen size with an ioctl, if needed */
327 /* This may change screen_width and screen_length, and it always
331 /* If screen_length is 0 from both termcap and ioctl then we are dumb */
332 if (screen_length
== 0)
338 /* if stdout is not a terminal, pretend we are a dumb terminal */
340 if (ioctl(STDOUT
, TIOCGETP
, &old_settings
) == -1)
346 if (ioctl(STDOUT
, TCGETA
, &old_settings
) == -1)
352 if (tcgetattr(STDOUT
, &old_settings
) == -1)
358 return smart_terminal
;
365 /* get the old settings for safe keeping */
367 if (ioctl(STDOUT
, TIOCGETP
, &old_settings
) != -1)
369 /* copy the settings so we can modify them */
370 new_settings
= old_settings
;
372 /* turn on CBREAK and turn off character echo and tab expansion */
373 new_settings
.sg_flags
|= CBREAK
;
374 new_settings
.sg_flags
&= ~(ECHO
|XTABS
);
375 (void) ioctl(STDOUT
, TIOCSETP
, &new_settings
);
377 /* remember the erase and kill characters */
378 ch_erase
= old_settings
.sg_erase
;
379 ch_kill
= old_settings
.sg_kill
;
380 ch_werase
= old_settings
.sg_werase
;
383 /* get the local mode word */
384 (void) ioctl(STDOUT
, TIOCLGET
, &old_lword
);
387 new_lword
= old_lword
| LTOSTOP
;
388 (void) ioctl(STDOUT
, TIOCLSET
, &new_lword
);
390 /* remember that it really is a terminal */
393 /* send the termcap initialization string */
394 putcap(terminal_init
);
398 if (ioctl(STDOUT
, TCGETA
, &old_settings
) != -1)
400 /* copy the settings so we can modify them */
401 new_settings
= old_settings
;
403 /* turn off ICANON, character echo and tab expansion */
404 new_settings
.c_lflag
&= ~(ICANON
|ECHO
);
405 new_settings
.c_oflag
&= ~(TAB3
);
406 new_settings
.c_cc
[VMIN
] = 1;
407 new_settings
.c_cc
[VTIME
] = 0;
408 (void) ioctl(STDOUT
, TCSETA
, &new_settings
);
410 /* remember the erase and kill characters */
411 ch_erase
= old_settings
.c_cc
[VERASE
];
412 ch_kill
= old_settings
.c_cc
[VKILL
];
413 ch_werase
= old_settings
.c_cc
[VWERASE
];
415 /* remember that it really is a terminal */
418 /* send the termcap initialization string */
419 putcap(terminal_init
);
423 if (tcgetattr(STDOUT
, &old_settings
) != -1)
425 /* copy the settings so we can modify them */
426 new_settings
= old_settings
;
428 /* turn off ICANON, character echo and tab expansion */
429 new_settings
.c_lflag
&= ~(ICANON
|ECHO
);
430 new_settings
.c_oflag
&= ~(TAB3
);
431 new_settings
.c_cc
[VMIN
] = 1;
432 new_settings
.c_cc
[VTIME
] = 0;
433 (void) tcsetattr(STDOUT
, TCSADRAIN
, &new_settings
);
435 /* remember the erase and kill characters */
436 ch_erase
= old_settings
.c_cc
[VERASE
];
437 ch_kill
= old_settings
.c_cc
[VKILL
];
438 ch_werase
= old_settings
.c_cc
[VWERASE
];
440 /* remember that it really is a terminal */
443 /* send the termcap initialization string */
444 putcap(terminal_init
);
450 /* not a terminal at all---consider it dumb */
459 /* move to the lower left, clear the line and send "te" */
463 putcap(tc_clear_line
);
465 putcap(terminal_end
);
468 /* if we have settings to reset, then do so */
472 (void) ioctl(STDOUT
, TIOCSETP
, &old_settings
);
474 (void) ioctl(STDOUT
, TIOCLSET
, &old_lword
);
478 (void) ioctl(STDOUT
, TCSETA
, &old_settings
);
481 (void) tcsetattr(STDOUT
, TCSADRAIN
, &old_settings
);
490 /* install our settings if it is a terminal */
494 (void) ioctl(STDOUT
, TIOCSETP
, &new_settings
);
496 (void) ioctl(STDOUT
, TIOCLSET
, &new_lword
);
500 (void) ioctl(STDOUT
, TCSETA
, &new_settings
);
503 (void) tcsetattr(STDOUT
, TCSADRAIN
, &new_settings
);
507 /* send init string */
510 putcap(terminal_init
);
515 screen_move(int x
, int y
)
518 char *go
= tgoto(tc_cursor_motion
, x
, y
);
520 tputs(go
, 1, putstdout
);
524 screen_standout(const char *msg
)
529 putcap(tc_start_standout
);
531 putcap(tc_end_standout
);
545 putcap(tc_clear_screen
);
557 putcap(tc_clear_to_end
);
565 screen_cleareol(int len
)
570 if (smart_terminal
&& !tc_overstrike
&& len
> 0)
574 putcap(tc_clear_line
);