]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/top/screen.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / top / screen.c
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 init_termcap(interactive)
100
101 int interactive;
102
103 {
104     char *bufptr;
105     char *PCptr;
106     char *term_name;
107     char *getenv();
108     int status;
109
110     /* set defaults in case we aren't smart */
111     screen_width = MAX_COLS;
112     screen_length = 0;
113
114     if (!interactive)
115     {
116         /* pretend we have a dumb terminal */
117         smart_terminal = No;
118         return;
119     }
120
121     /* assume we have a smart terminal until proven otherwise */
122     smart_terminal = Yes;
123
124     /* get the terminal name */
125     term_name = getenv("TERM");
126
127     /* if there is no TERM, assume it's a dumb terminal */
128     /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */
129     if (term_name == NULL)
130     {
131         smart_terminal = No;
132         return;
133     }
134
135     /* now get the termcap entry */
136     if ((status = tgetent(termcap_buf, term_name)) != 1)
137     {
138         if (status == -1)
139         {
140             fprintf(stderr, "%s: can't open termcap file\n", myname);
141         }
142         else
143         {
144             fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n",
145                     myname, term_name);
146         }
147
148         /* pretend it's dumb and proceed */
149         smart_terminal = No;
150         return;
151     }
152
153     /* "hardcopy" immediately indicates a very stupid terminal */
154     if (tgetflag("hc"))
155     {
156         smart_terminal = No;
157         return;
158     }
159
160     /* set up common terminal capabilities */
161     if ((screen_length = tgetnum("li")) <= 0)
162     {
163         screen_length = smart_terminal = 0;
164         return;
165     }
166
167     /* screen_width is a little different */
168     if ((screen_width = tgetnum("co")) == -1)
169     {
170         screen_width = 79;
171     }
172     else
173     {
174         screen_width -= 1;
175     }
176
177     /* terminals that overstrike need special attention */
178     overstrike = tgetflag("os");
179
180     /* initialize the pointer into the termcap string buffer */
181     bufptr = string_buffer;
182
183     /* get "ce", clear to end */
184     if (!overstrike)
185     {
186         clear_line = tgetstr("ce", &bufptr);
187     }
188
189     /* get necessary capabilities */
190     if ((clear_screen  = tgetstr("cl", &bufptr)) == NULL ||
191         (cursor_motion = tgetstr("cm", &bufptr)) == NULL)
192     {
193         smart_terminal = No;
194         return;
195     }
196
197     /* get some more sophisticated stuff -- these are optional */
198     clear_to_end   = tgetstr("cd", &bufptr);
199     terminal_init  = tgetstr("ti", &bufptr);
200     terminal_end   = tgetstr("te", &bufptr);
201     start_standout = tgetstr("so", &bufptr);
202     end_standout   = tgetstr("se", &bufptr);
203
204     /* pad character */
205     PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0;
206
207     /* set convenience strings */
208     (void) strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1);
209     home[sizeof(home) - 1] = '\0';
210     /* (lower_left is set in get_screensize) */
211
212     /* get the actual screen size with an ioctl, if needed */
213     /* This may change screen_width and screen_length, and it always
214        sets lower_left. */
215     get_screensize();
216
217     /* if stdout is not a terminal, pretend we are a dumb terminal */
218 #ifdef SGTTY
219     if (ioctl(STDOUT, TIOCGETP, &old_settings) == -1)
220     {
221         smart_terminal = No;
222     }
223 #endif
224 #ifdef TERMIO
225     if (ioctl(STDOUT, TCGETA, &old_settings) == -1)
226     {
227         smart_terminal = No;
228     }
229 #endif
230 #ifdef TERMIOS
231     if (tcgetattr(STDOUT, &old_settings) == -1)
232     {
233         smart_terminal = No;
234     }
235 #endif
236 }
237
238 init_screen()
239
240 {
241     /* get the old settings for safe keeping */
242 #ifdef SGTTY
243     if (ioctl(STDOUT, TIOCGETP, &old_settings) != -1)
244     {
245         /* copy the settings so we can modify them */
246         new_settings = old_settings;
247
248         /* turn on CBREAK and turn off character echo and tab expansion */
249         new_settings.sg_flags |= CBREAK;
250         new_settings.sg_flags &= ~(ECHO|XTABS);
251         (void) ioctl(STDOUT, TIOCSETP, &new_settings);
252
253         /* remember the erase and kill characters */
254         ch_erase = old_settings.sg_erase;
255         ch_kill  = old_settings.sg_kill;
256
257 #ifdef TOStop
258         /* get the local mode word */
259         (void) ioctl(STDOUT, TIOCLGET, &old_lword);
260
261         /* modify it */
262         new_lword = old_lword | LTOSTOP;
263         (void) ioctl(STDOUT, TIOCLSET, &new_lword);
264 #endif
265         /* remember that it really is a terminal */
266         is_a_terminal = Yes;
267
268         /* send the termcap initialization string */
269         putcap(terminal_init);
270     }
271 #endif
272 #ifdef TERMIO
273     if (ioctl(STDOUT, TCGETA, &old_settings) != -1)
274     {
275         /* copy the settings so we can modify them */
276         new_settings = old_settings;
277
278         /* turn off ICANON, character echo and tab expansion */
279         new_settings.c_lflag &= ~(ICANON|ECHO);
280         new_settings.c_oflag &= ~(TAB3);
281         new_settings.c_cc[VMIN] = 1;
282         new_settings.c_cc[VTIME] = 0;
283         (void) ioctl(STDOUT, TCSETA, &new_settings);
284
285         /* remember the erase and kill characters */
286         ch_erase = old_settings.c_cc[VERASE];
287         ch_kill  = old_settings.c_cc[VKILL];
288
289         /* remember that it really is a terminal */
290         is_a_terminal = Yes;
291
292         /* send the termcap initialization string */
293         putcap(terminal_init);
294     }
295 #endif
296 #ifdef TERMIOS
297     if (tcgetattr(STDOUT, &old_settings) != -1)
298     {
299         /* copy the settings so we can modify them */
300         new_settings = old_settings;
301
302         /* turn off ICANON, character echo and tab expansion */
303         new_settings.c_lflag &= ~(ICANON|ECHO);
304         new_settings.c_oflag &= ~(TAB3);
305         new_settings.c_cc[VMIN] = 1;
306         new_settings.c_cc[VTIME] = 0;
307         (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings);
308
309         /* remember the erase and kill characters */
310         ch_erase = old_settings.c_cc[VERASE];
311         ch_kill  = old_settings.c_cc[VKILL];
312
313         /* remember that it really is a terminal */
314         is_a_terminal = Yes;
315
316         /* send the termcap initialization string */
317         putcap(terminal_init);
318     }
319 #endif
320
321     if (!is_a_terminal)
322     {
323         /* not a terminal at all---consider it dumb */
324         smart_terminal = No;
325     }
326 }
327
328 end_screen()
329
330 {
331     /* move to the lower left, clear the line and send "te" */
332     if (smart_terminal)
333     {
334         putcap(lower_left);
335         putcap(clear_line);
336         fflush(stdout);
337         putcap(terminal_end);
338     }
339
340     /* if we have settings to reset, then do so */
341     if (is_a_terminal)
342     {
343 #ifdef SGTTY
344         (void) ioctl(STDOUT, TIOCSETP, &old_settings);
345 #ifdef TOStop
346         (void) ioctl(STDOUT, TIOCLSET, &old_lword);
347 #endif
348 #endif
349 #ifdef TERMIO
350         (void) ioctl(STDOUT, TCSETA, &old_settings);
351 #endif
352 #ifdef TERMIOS
353         (void) tcsetattr(STDOUT, TCSADRAIN, &old_settings);
354 #endif
355     }
356 }
357
358 reinit_screen()
359
360 {
361     /* install our settings if it is a terminal */
362     if (is_a_terminal)
363     {
364 #ifdef SGTTY
365         (void) ioctl(STDOUT, TIOCSETP, &new_settings);
366 #ifdef TOStop
367         (void) ioctl(STDOUT, TIOCLSET, &new_lword);
368 #endif
369 #endif
370 #ifdef TERMIO
371         (void) ioctl(STDOUT, TCSETA, &new_settings);
372 #endif
373 #ifdef TERMIOS
374         (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings);
375 #endif
376     }
377
378     /* send init string */
379     if (smart_terminal)
380     {
381         putcap(terminal_init);
382     }
383 }
384
385 get_screensize()
386
387 {
388
389 #ifdef TIOCGWINSZ
390
391     struct winsize ws;
392
393     if (ioctl (1, TIOCGWINSZ, &ws) != -1)
394     {
395         if (ws.ws_row != 0)
396         {
397             screen_length = ws.ws_row;
398         }
399         if (ws.ws_col != 0)
400         {
401             screen_width = ws.ws_col - 1;
402         }
403     }
404
405 #else
406 #ifdef TIOCGSIZE
407
408     struct ttysize ts;
409
410     if (ioctl (1, TIOCGSIZE, &ts) != -1)
411     {
412         if (ts.ts_lines != 0)
413         {
414             screen_length = ts.ts_lines;
415         }
416         if (ts.ts_cols != 0)
417         {
418             screen_width = ts.ts_cols - 1;
419         }
420     }
421
422 #endif /* TIOCGSIZE */
423 #endif /* TIOCGWINSZ */
424
425     (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1),
426         sizeof(lower_left) - 1);
427     lower_left[sizeof(lower_left) - 1] = '\0';
428 }
429
430 standout(msg)
431
432 char *msg;
433
434 {
435     if (smart_terminal)
436     {
437         putcap(start_standout);
438         fputs(msg, stdout);
439         putcap(end_standout);
440     }
441     else
442     {
443         fputs(msg, stdout);
444     }
445 }
446
447 clear()
448
449 {
450     if (smart_terminal)
451     {
452         putcap(clear_screen);
453     }
454 }
455
456 clear_eol(len)
457
458 int len;
459
460 {
461     if (smart_terminal && !overstrike && len > 0)
462     {
463         if (clear_line)
464         {
465             putcap(clear_line);
466             return(0);
467         }
468         else
469         {
470             while (len-- > 0)
471             {
472                 putchar(' ');
473             }
474             return(1);
475         }
476     }
477     return(-1);
478 }
479
480 go_home()
481
482 {
483     if (smart_terminal)
484     {
485         putcap(home);
486     }
487 }
488
489 /* This has to be defined as a subroutine for tputs (instead of a macro) */
490
491 putstdout(ch)
492
493 char ch;
494
495 {
496     putchar(ch);
497 }
498