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