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