2 * Top users/processes display for Unix
5 * This program may be freely redistributed,
6 * but this entire comment MUST remain intact.
8 * Copyright (c) 1984, 1989, William LeFebvre, Rice University
9 * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
11 * $FreeBSD: src/contrib/top/screen.c,v 1.2.6.1 2000/09/20 02:27:57 jkh Exp $
12 * $DragonFly: src/contrib/top/screen.c,v 1.2 2003/06/17 04:24:07 dillon Exp $
15 /* This file contains the routines that interface to termcap and stty/gtty.
17 * Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty.
19 * I put in code to turn on the TOSTOP bit while top was running, but I
20 * didn't really like the results. If you desire it, turn on the
21 * preprocessor variable "TOStop". --wnl
27 #include <sys/ioctl.h>
40 #if defined(TERMIO) || defined(TERMIOS)
65 char termcap_buf
[1024];
66 char string_buffer
[1024];
79 static struct sgttyb old_settings
;
80 static struct sgttyb new_settings
;
83 static struct termio old_settings
;
84 static struct termio new_settings
;
87 static struct termios old_settings
;
88 static struct termios new_settings
;
90 static char is_a_terminal
= No
;
100 init_termcap(interactive
)
111 /* set defaults in case we aren't smart */
112 screen_width
= MAX_COLS
;
117 /* pretend we have a dumb terminal */
122 /* assume we have a smart terminal until proven otherwise */
123 smart_terminal
= Yes
;
125 /* get the terminal name */
126 term_name
= getenv("TERM");
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
)
136 /* now get the termcap entry */
137 if ((status
= tgetent(termcap_buf
, term_name
)) != 1)
141 fprintf(stderr
, "%s: can't open termcap file\n", myname
);
145 fprintf(stderr
, "%s: no termcap entry for a `%s' terminal\n",
149 /* pretend it's dumb and proceed */
154 /* "hardcopy" immediately indicates a very stupid terminal */
161 /* set up common terminal capabilities */
162 if ((screen_length
= tgetnum("li")) <= 0)
164 screen_length
= smart_terminal
= 0;
168 /* screen_width is a little different */
169 if ((screen_width
= tgetnum("co")) == -1)
178 /* terminals that overstrike need special attention */
179 overstrike
= tgetflag("os");
181 /* initialize the pointer into the termcap string buffer */
182 bufptr
= string_buffer
;
184 /* get "ce", clear to end */
187 clear_line
= tgetstr("ce", &bufptr
);
190 /* get necessary capabilities */
191 if ((clear_screen
= tgetstr("cl", &bufptr
)) == NULL
||
192 (cursor_motion
= tgetstr("cm", &bufptr
)) == NULL
)
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
);
206 PC
= (PCptr
= tgetstr("pc", &bufptr
)) ? *PCptr
: 0;
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) */
213 /* get the actual screen size with an ioctl, if needed */
214 /* This may change screen_width and screen_length, and it always
218 /* if stdout is not a terminal, pretend we are a dumb terminal */
220 if (ioctl(STDOUT
, TIOCGETP
, &old_settings
) == -1)
226 if (ioctl(STDOUT
, TCGETA
, &old_settings
) == -1)
232 if (tcgetattr(STDOUT
, &old_settings
) == -1)
242 /* get the old settings for safe keeping */
244 if (ioctl(STDOUT
, TIOCGETP
, &old_settings
) != -1)
246 /* copy the settings so we can modify them */
247 new_settings
= old_settings
;
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
);
254 /* remember the erase and kill characters */
255 ch_erase
= old_settings
.sg_erase
;
256 ch_kill
= old_settings
.sg_kill
;
259 /* get the local mode word */
260 (void) ioctl(STDOUT
, TIOCLGET
, &old_lword
);
263 new_lword
= old_lword
| LTOSTOP
;
264 (void) ioctl(STDOUT
, TIOCLSET
, &new_lword
);
266 /* remember that it really is a terminal */
269 /* send the termcap initialization string */
270 putcap(terminal_init
);
274 if (ioctl(STDOUT
, TCGETA
, &old_settings
) != -1)
276 /* copy the settings so we can modify them */
277 new_settings
= old_settings
;
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
);
286 /* remember the erase and kill characters */
287 ch_erase
= old_settings
.c_cc
[VERASE
];
288 ch_kill
= old_settings
.c_cc
[VKILL
];
290 /* remember that it really is a terminal */
293 /* send the termcap initialization string */
294 putcap(terminal_init
);
298 if (tcgetattr(STDOUT
, &old_settings
) != -1)
300 /* copy the settings so we can modify them */
301 new_settings
= old_settings
;
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
);
310 /* remember the erase and kill characters */
311 ch_erase
= old_settings
.c_cc
[VERASE
];
312 ch_kill
= old_settings
.c_cc
[VKILL
];
314 /* remember that it really is a terminal */
317 /* send the termcap initialization string */
318 putcap(terminal_init
);
324 /* not a terminal at all---consider it dumb */
332 /* move to the lower left, clear the line and send "te" */
338 putcap(terminal_end
);
341 /* if we have settings to reset, then do so */
345 (void) ioctl(STDOUT
, TIOCSETP
, &old_settings
);
347 (void) ioctl(STDOUT
, TIOCLSET
, &old_lword
);
351 (void) ioctl(STDOUT
, TCSETA
, &old_settings
);
354 (void) tcsetattr(STDOUT
, TCSADRAIN
, &old_settings
);
362 /* install our settings if it is a terminal */
366 (void) ioctl(STDOUT
, TIOCSETP
, &new_settings
);
368 (void) ioctl(STDOUT
, TIOCLSET
, &new_lword
);
372 (void) ioctl(STDOUT
, TCSETA
, &new_settings
);
375 (void) tcsetattr(STDOUT
, TCSADRAIN
, &new_settings
);
379 /* send init string */
382 putcap(terminal_init
);
394 if (ioctl (1, TIOCGWINSZ
, &ws
) != -1)
398 screen_length
= ws
.ws_row
;
402 screen_width
= ws
.ws_col
- 1;
411 if (ioctl (1, TIOCGSIZE
, &ts
) != -1)
413 if (ts
.ts_lines
!= 0)
415 screen_length
= ts
.ts_lines
;
419 screen_width
= ts
.ts_cols
- 1;
423 #endif /* TIOCGSIZE */
424 #endif /* TIOCGWINSZ */
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';
438 putcap(start_standout
);
440 putcap(end_standout
);
453 putcap(clear_screen
);
462 if (smart_terminal
&& !overstrike
&& len
> 0)
490 /* This has to be defined as a subroutine for tputs (instead of a macro) */