Merge branch 'vendor/OPENSSL'
[dragonfly.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: 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 $
13  */
14
15 /*  This file contains the routines that interface to termcap and stty/gtty.
16  *
17  *  Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty.
18  *
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
22  */
23
24 #include "os.h"
25 #include "top.h"
26
27 #include <sys/ioctl.h>
28 #include <curses.h>
29 #include <term.h>
30 #include <termios.h>
31 #include "screen.h"
32 #include "boolean.h"
33
34 extern char *myname;
35
36 int  overstrike;
37 int  screen_length;
38 int  screen_width;
39 char ch_erase;
40 char ch_kill;
41 char smart_terminal;
42 char PC;
43 char termcap_buf[1024];
44 char string_buffer[1024];
45 char home[15];
46 char lower_left[15];
47 char *clear_line;
48 char *clear_the_screen;
49 char *clear_to_end;
50 char *cursor_motion;
51 char *start_standout;
52 char *end_standout;
53 char *terminal_init;
54 char *terminal_end;
55
56 static struct termios old_settings;
57 static struct termios new_settings;
58 static char is_a_terminal = No;
59
60 #define STDIN   0
61 #define STDOUT  1
62 #define STDERR  2
63
64 void
65 init_termcap(int interactive)
66 {
67     char *bufptr;
68     char *PCptr;
69     char *term_name;
70     int status;
71
72     /* set defaults in case we aren't smart */
73     screen_width = MAX_COLS;
74     screen_length = 0;
75
76     if (!interactive)
77     {
78         /* pretend we have a dumb terminal */
79         smart_terminal = No;
80         return;
81     }
82
83     /* assume we have a smart terminal until proven otherwise */
84     smart_terminal = Yes;
85
86     /* get the terminal name */
87     term_name = getenv("TERM");
88
89     /* if there is no TERM, assume it's a dumb terminal */
90     /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */
91     if (term_name == NULL)
92     {
93         smart_terminal = No;
94         return;
95     }
96
97     /* now get the termcap entry */
98     if ((status = tgetent(termcap_buf, term_name)) != 1)
99     {
100         if (status == -1)
101         {
102             fprintf(stderr, "%s: can't open termcap file\n", myname);
103         }
104         else
105         {
106             fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n",
107                     myname, term_name);
108         }
109
110         /* pretend it's dumb and proceed */
111         smart_terminal = No;
112         return;
113     }
114
115     /* "hardcopy" immediately indicates a very stupid terminal */
116     if (tgetflag("hc"))
117     {
118         smart_terminal = No;
119         return;
120     }
121
122     /* set up common terminal capabilities */
123     if ((screen_length = tgetnum("li")) <= 0)
124     {
125         screen_length = smart_terminal = 0;
126         return;
127     }
128
129     /* screen_width is a little different */
130     if ((screen_width = tgetnum("co")) == -1)
131     {
132         screen_width = 79;
133     }
134     else
135     {
136         screen_width -= 1;
137     }
138
139     /* terminals that overstrike need special attention */
140     overstrike = tgetflag("os");
141
142     /* initialize the pointer into the termcap string buffer */
143     bufptr = string_buffer;
144
145     /* get "ce", clear to end */
146     if (!overstrike)
147     {
148         clear_line = tgetstr("ce", &bufptr);
149     }
150
151     /* get necessary capabilities */
152     if ((clear_the_screen  = tgetstr("cl", &bufptr)) == NULL ||
153         (cursor_motion = tgetstr("cm", &bufptr)) == NULL)
154     {
155         smart_terminal = No;
156         return;
157     }
158
159     /* get some more sophisticated stuff -- these are optional */
160     clear_to_end   = tgetstr("cd", &bufptr);
161     terminal_init  = tgetstr("ti", &bufptr);
162     terminal_end   = tgetstr("te", &bufptr);
163     start_standout = tgetstr("so", &bufptr);
164     end_standout   = tgetstr("se", &bufptr);
165
166     /* pad character */
167     PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0;
168
169     /* set convenience strings */
170     (void) strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1);
171     home[sizeof(home) - 1] = '\0';
172     /* (lower_left is set in get_screensize) */
173
174     /* get the actual screen size with an ioctl, if needed */
175     /* This may change screen_width and screen_length, and it always
176        sets lower_left. */
177     get_screensize();
178
179     /* if stdout is not a terminal, pretend we are a dumb terminal */
180     if (tcgetattr(STDOUT, &old_settings) == -1)
181     {
182         smart_terminal = No;
183     }
184 }
185
186 void
187 init_screen(void)
188 {
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 &= ~(OXTABS);
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
258 #ifdef TIOCGWINSZ
259
260     struct winsize ws;
261
262     if (ioctl (1, TIOCGWINSZ, &ws) != -1)
263     {
264         if (ws.ws_row != 0)
265         {
266             screen_length = ws.ws_row;
267         }
268         if (ws.ws_col != 0)
269         {
270             screen_width = ws.ws_col - 1;
271         }
272     }
273
274 #else
275 #ifdef TIOCGSIZE
276
277     struct ttysize ts;
278
279     if (ioctl (1, TIOCGSIZE, &ts) != -1)
280     {
281         if (ts.ts_lines != 0)
282         {
283             screen_length = ts.ts_lines;
284         }
285         if (ts.ts_cols != 0)
286         {
287             screen_width = ts.ts_cols - 1;
288         }
289     }
290
291 #endif /* TIOCGSIZE */
292 #endif /* TIOCGWINSZ */
293
294     (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1),
295         sizeof(lower_left) - 1);
296     lower_left[sizeof(lower_left) - 1] = '\0';
297 }
298
299 void
300 dostandout(const char *msg)
301 {
302     if (smart_terminal)
303     {
304         putcap(start_standout);
305         fputs(msg, stdout);
306         putcap(end_standout);
307     }
308     else
309     {
310         fputs(msg, stdout);
311     }
312 }
313
314 void
315 clear_myscreen(void)
316 {
317     if (smart_terminal)
318     {
319        putcap(clear_screen);
320     }
321 }
322
323 int
324 clear_eol(int len)
325 {
326     if (smart_terminal && !overstrike && len > 0)
327     {
328         if (clear_line)
329         {
330             putcap(clear_line);
331             return(0);
332         }
333         else
334         {
335             while (len-- > 0)
336             {
337                 putchar(' ');
338             }
339             return(1);
340         }
341     }
342     return(-1);
343 }
344
345 void
346 go_home(void)
347 {
348     if (smart_terminal)
349     {
350         putcap(home);
351     }
352 }
353
354 /* This has to be defined as a subroutine for tputs (instead of a macro) */
355
356 int
357 putstdout(int ch)
358 {
359     return(putchar(ch));
360 }
361