]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/top/screen.c
top(1): ansify, style(9). and nits
[FreeBSD/FreeBSD.git] / usr.bin / 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 "top.h"
24
25 #include <sys/ioctl.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #define TERMIOS
29 #include <termios.h>
30 #include <curses.h>
31 #include <termcap.h>
32 #include "screen.h"
33 #include "boolean.h"
34
35 int  overstrike;
36 int  screen_length;
37 int  screen_width;
38 char ch_erase;
39 char ch_kill;
40 char smart_terminal;
41 char PC;
42 static char termcap_buf[1024];
43 static char string_buffer[1024];
44 static char home[15];
45 static char lower_left[15];
46 char *clear_line;
47 static char *clear_screen;
48 char *clear_to_end;
49 char *cursor_motion;
50 static char *start_standout;
51 static char *end_standout;
52 static char *terminal_init;
53 static char *terminal_end;
54
55 static struct termios old_settings;
56 static struct termios new_settings;
57 static char is_a_terminal = No;
58
59 #define STDIN   0
60 #define STDOUT  1
61 #define STDERR  2
62
63 void
64 init_termcap(int interactive)
65 {
66     char *bufptr;
67     char *PCptr;
68     char *term_name;
69     int status;
70
71     /* set defaults in case we aren't smart */
72     screen_width = MAX_COLS;
73     screen_length = 0;
74
75     if (!interactive)
76     {
77         /* pretend we have a dumb terminal */
78         smart_terminal = No;
79         return;
80     }
81
82     /* assume we have a smart terminal until proven otherwise */
83     smart_terminal = Yes;
84
85     /* get the terminal name */
86     term_name = getenv("TERM");
87
88     /* if there is no TERM, assume it's a dumb terminal */
89     /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */
90     if (term_name == NULL)
91     {
92         smart_terminal = No;
93         return;
94     }
95
96     /* now get the termcap entry */
97     if ((status = tgetent(termcap_buf, term_name)) != 1)
98     {
99         if (status == -1)
100         {
101             fprintf(stderr, "%s: can't open termcap file\n", myname);
102         }
103         else
104         {
105             fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n",
106                     myname, term_name);
107         }
108
109         /* pretend it's dumb and proceed */
110         smart_terminal = No;
111         return;
112     }
113
114     /* "hardcopy" immediately indicates a very stupid terminal */
115     if (tgetflag("hc"))
116     {
117         smart_terminal = No;
118         return;
119     }
120
121     /* set up common terminal capabilities */
122     if ((screen_length = tgetnum("li")) <= 0)
123     {
124         screen_length = smart_terminal = 0;
125         return;
126     }
127
128     /* screen_width is a little different */
129     if ((screen_width = tgetnum("co")) == -1)
130     {
131         screen_width = 79;
132     }
133     else
134     {
135         screen_width -= 1;
136     }
137
138     /* terminals that overstrike need special attention */
139     overstrike = tgetflag("os");
140
141     /* initialize the pointer into the termcap string buffer */
142     bufptr = string_buffer;
143
144     /* get "ce", clear to end */
145     if (!overstrike)
146     {
147         clear_line = tgetstr("ce", &bufptr);
148     }
149
150     /* get necessary capabilities */
151     if ((clear_screen  = tgetstr("cl", &bufptr)) == NULL ||
152         (cursor_motion = tgetstr("cm", &bufptr)) == NULL)
153     {
154         smart_terminal = No;
155         return;
156     }
157
158     /* get some more sophisticated stuff -- these are optional */
159     clear_to_end   = tgetstr("cd", &bufptr);
160     terminal_init  = tgetstr("ti", &bufptr);
161     terminal_end   = tgetstr("te", &bufptr);
162     start_standout = tgetstr("so", &bufptr);
163     end_standout   = tgetstr("se", &bufptr);
164
165     /* pad character */
166     PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0;
167
168     /* set convenience strings */
169     (void) strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1);
170     home[sizeof(home) - 1] = '\0';
171     /* (lower_left is set in get_screensize) */
172
173     /* get the actual screen size with an ioctl, if needed */
174     /* This may change screen_width and screen_length, and it always
175        sets lower_left. */
176     get_screensize();
177
178     /* if stdout is not a terminal, pretend we are a dumb terminal */
179     if (tcgetattr(STDOUT, &old_settings) == -1)
180     {
181         smart_terminal = No;
182     }
183 }
184
185 void
186 init_screen(void)
187 {
188     /* get the old settings for safe keeping */
189     if (tcgetattr(STDOUT, &old_settings) != -1)
190     {
191         /* copy the settings so we can modify them */
192         new_settings = old_settings;
193
194         /* turn off ICANON, character echo and tab expansion */
195         new_settings.c_lflag &= ~(ICANON|ECHO);
196         new_settings.c_oflag &= ~(TAB3);
197         new_settings.c_cc[VMIN] = 1;
198         new_settings.c_cc[VTIME] = 0;
199         (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings);
200
201         /* remember the erase and kill characters */
202         ch_erase = old_settings.c_cc[VERASE];
203         ch_kill  = old_settings.c_cc[VKILL];
204
205         /* remember that it really is a terminal */
206         is_a_terminal = Yes;
207
208         /* send the termcap initialization string */
209         putcap(terminal_init);
210     }
211
212     if (!is_a_terminal)
213     {
214         /* not a terminal at all---consider it dumb */
215         smart_terminal = No;
216     }
217 }
218
219 void
220 end_screen(void)
221 {
222     /* move to the lower left, clear the line and send "te" */
223     if (smart_terminal)
224     {
225         putcap(lower_left);
226         putcap(clear_line);
227         fflush(stdout);
228         putcap(terminal_end);
229     }
230
231     /* if we have settings to reset, then do so */
232     if (is_a_terminal)
233     {
234         (void) tcsetattr(STDOUT, TCSADRAIN, &old_settings);
235     }
236 }
237
238 void
239 reinit_screen(void)
240 {
241     /* install our settings if it is a terminal */
242     if (is_a_terminal)
243     {
244         (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings);
245     }
246
247     /* send init string */
248     if (smart_terminal)
249     {
250         putcap(terminal_init);
251     }
252 }
253
254 void
255 get_screensize(void)
256 {
257     struct winsize ws;
258
259     if (ioctl (1, TIOCGWINSZ, &ws) != -1)
260     {
261         if (ws.ws_row != 0)
262         {
263             screen_length = ws.ws_row;
264         }
265         if (ws.ws_col != 0)
266         {
267             screen_width = ws.ws_col - 1;
268         }
269     }
270
271
272     (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1),
273         sizeof(lower_left) - 1);
274     lower_left[sizeof(lower_left) - 1] = '\0';
275 }
276
277 void
278 top_standout(char *msg)
279 {
280     if (smart_terminal)
281     {
282         putcap(start_standout);
283         fputs(msg, stdout);
284         putcap(end_standout);
285     }
286     else
287     {
288         fputs(msg, stdout);
289     }
290 }
291
292 void
293 top_clear(void)
294 {
295     if (smart_terminal)
296     {
297         putcap(clear_screen);
298     }
299 }
300
301 int
302 clear_eol(int len)
303 {
304     if (smart_terminal && !overstrike && len > 0)
305     {
306         if (clear_line)
307         {
308             putcap(clear_line);
309             return(0);
310         }
311         else
312         {
313             while (len-- > 0)
314             {
315                 putchar(' ');
316             }
317             return(1);
318         }
319     }
320     return(-1);
321 }
322
323 void
324 go_home(void)
325 {
326     if (smart_terminal)
327     {
328         putcap(home);
329     }
330 }
331
332 /* This has to be defined as a subroutine for tputs (instead of a macro) */
333
334 int
335 putstdout(int ch)
336 {
337     return putchar(ch);
338 }