Annotation of src/usr.bin/top/screen.c, Revision 1.12
1.12 ! deraadt 1: /* $OpenBSD: screen.c,v 1.11 2003/06/13 21:52:25 deraadt Exp $ */
1.1 downsj 2:
3: /*
4: * Top users/processes display for Unix
5: * Version 3
6: *
1.8 deraadt 7: * Copyright (c) 1984, 1989, William LeFebvre, Rice University
8: * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
1.1 downsj 9: *
1.8 deraadt 10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22: * IN NO EVENT SHALL THE AUTHOR OR HIS EMPLOYER BE LIABLE FOR ANY DIRECT, INDIRECT,
23: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1 downsj 29: */
30:
1.10 deraadt 31: /*
32: * This file contains the routines that interface to termcap and stty/gtty.
33: *
34: * Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty.
35: *
36: * I put in code to turn on the TOSTOP bit while top was running, but I didn't
37: * really like the results. If you desire it, turn on the preprocessor
38: * variable "TOStop". --wnl
1.1 downsj 39: */
40:
1.2 downsj 41: #include <sys/types.h>
42: #include <sys/ioctl.h>
43: #include <stdio.h>
44: #include <stdlib.h>
1.3 millert 45: #include <string.h>
1.2 downsj 46: #include <term.h>
47: #include <termios.h>
48: #include <unistd.h>
49:
1.1 downsj 50: #include "top.h"
51: #include "screen.h"
52: #include "boolean.h"
53:
1.12 ! deraadt 54: int overstrike, screen_length, screen_width;
! 55: char ch_erase, ch_kill, smart_terminal, PC;
! 56: char string_buffer[1024], home[15], lower_left[15];
! 57: char *clear_line, *clear_scr, *clear_to_end;
! 58: char *cursor_motion, *start_standout, *end_standout;
! 59: char *terminal_init, *terminal_end;
! 60: short ospeed;
1.1 downsj 61:
1.12 ! deraadt 62: static struct termios old_settings, new_settings;
1.1 downsj 63:
1.12 ! deraadt 64: static char is_a_terminal = No;
1.1 downsj 65:
1.9 pvalchev 66: void
67: init_termcap(int interactive)
1.1 downsj 68: {
1.10 deraadt 69: char *bufptr, *PCptr, *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: /* pretend we have a dumb terminal */
78: smart_terminal = No;
79: return;
80: }
81: /* assume we have a smart terminal until proven otherwise */
82: smart_terminal = Yes;
83:
84: /* get the terminal name */
85: term_name = getenv("TERM");
86:
87: /* if there is no TERM, assume it's a dumb terminal */
88: /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */
89: if (term_name == NULL) {
90: smart_terminal = No;
91: return;
92: }
93:
94: /* now get the termcap entry */
95: if ((status = tgetent(NULL, term_name)) != 1) {
96: if (status == -1)
1.12 ! deraadt 97: warnx("can't open termcap file");
1.10 deraadt 98: else
1.12 ! deraadt 99: warnx("no termcap entry for a `%s' terminal", term_name);
1.10 deraadt 100:
101: /* pretend it's dumb and proceed */
102: smart_terminal = No;
103: return;
1.1 downsj 104: }
1.10 deraadt 105:
106: /* "hardcopy" immediately indicates a very stupid terminal */
107: if (tgetflag("hc")) {
108: smart_terminal = No;
109: return;
110: }
111: /* set up common terminal capabilities */
112: if ((screen_length = tgetnum("li")) <= Header_lines) {
113: screen_length = smart_terminal = 0;
114: return;
115: }
116:
117: /* screen_width is a little different */
118: if ((screen_width = tgetnum("co")) == -1)
119: screen_width = 79;
1.1 downsj 120: else
1.10 deraadt 121: screen_width -= 1;
122:
123: /* terminals that overstrike need special attention */
124: overstrike = tgetflag("os");
125:
126: /* initialize the pointer into the termcap string buffer */
127: bufptr = string_buffer;
128:
129: /* get "ce", clear to end */
130: if (!overstrike) {
131: clear_line = tgetstr("ce", &bufptr);
132: }
133: /* get necessary capabilities */
134: if ((clear_scr = tgetstr("cl", &bufptr)) == NULL ||
135: (cursor_motion = tgetstr("cm", &bufptr)) == NULL) {
136: smart_terminal = No;
137: return;
138: }
139: /* get some more sophisticated stuff -- these are optional */
140: clear_to_end = tgetstr("cd", &bufptr);
141: terminal_init = tgetstr("ti", &bufptr);
142: terminal_end = tgetstr("te", &bufptr);
143: start_standout = tgetstr("so", &bufptr);
144: end_standout = tgetstr("se", &bufptr);
145:
146: /* pad character */
147: PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0;
148:
149: /* set convenience strings */
150: (void) strlcpy(home, tgoto(cursor_motion, 0, 0), sizeof(home));
151: /* (lower_left is set in get_screensize) */
152:
153: /* get the actual screen size with an ioctl, if needed */
154: /*
155: * This may change screen_width and screen_length, and it always sets
156: * lower_left.
157: */
158: get_screensize();
159:
160: /* if stdout is not a terminal, pretend we are a dumb terminal */
161: if (tcgetattr(STDOUT_FILENO, &old_settings) == -1)
162: smart_terminal = No;
1.1 downsj 163: }
164:
1.9 pvalchev 165: void
166: init_screen(void)
1.1 downsj 167: {
1.10 deraadt 168: /* get the old settings for safe keeping */
169: if (tcgetattr(STDOUT_FILENO, &old_settings) != -1) {
170: /* copy the settings so we can modify them */
171: new_settings = old_settings;
172:
173: /* turn off ICANON, character echo and tab expansion */
174: new_settings.c_lflag &= ~(ICANON | ECHO);
175: new_settings.c_oflag &= ~(OXTABS);
176: new_settings.c_cc[VMIN] = 1;
177: new_settings.c_cc[VTIME] = 0;
178: (void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings);
179:
180: /* remember the erase and kill characters */
181: ch_erase = old_settings.c_cc[VERASE];
182: ch_kill = old_settings.c_cc[VKILL];
183:
184: /* remember that it really is a terminal */
185: is_a_terminal = Yes;
186:
187: /* send the termcap initialization string */
188: putcap(terminal_init);
189: }
190: if (!is_a_terminal) {
191: /* not a terminal at all---consider it dumb */
192: smart_terminal = No;
193: }
1.1 downsj 194: }
195:
1.9 pvalchev 196: void
197: end_screen(void)
1.1 downsj 198: {
1.10 deraadt 199: /* move to the lower left, clear the line and send "te" */
200: if (smart_terminal) {
201: putcap(lower_left);
202: putcap(clear_line);
203: fflush(stdout);
204: putcap(terminal_end);
205: }
206:
207: /* if we have settings to reset, then do so */
208: if (is_a_terminal)
209: (void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &old_settings);
1.1 downsj 210: }
211:
1.9 pvalchev 212: void
213: reinit_screen(void)
1.1 downsj 214: {
1.10 deraadt 215: /* install our settings if it is a terminal */
216: if (is_a_terminal)
217: (void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings);
218:
219: /* send init string */
220: if (smart_terminal)
221: putcap(terminal_init);
1.1 downsj 222: }
223:
1.9 pvalchev 224: void
225: get_screensize(void)
1.1 downsj 226: {
1.10 deraadt 227: struct winsize ws;
1.1 downsj 228:
1.10 deraadt 229: if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) {
230: if (ws.ws_row != 0)
231: screen_length = ws.ws_row;
232: if (ws.ws_col != 0)
233: screen_width = ws.ws_col - 1;
234: }
235: (void) strlcpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1),
236: sizeof(lower_left));
1.1 downsj 237: }
238:
1.9 pvalchev 239: void
240: standout(char *msg)
1.1 downsj 241: {
1.10 deraadt 242: if (smart_terminal) {
243: putcap(start_standout);
244: if (fputs(msg, stdout) == EOF)
245: exit(1);
246: putcap(end_standout);
247: } else {
248: if (fputs(msg, stdout) == EOF)
249: exit(1);
250: }
1.1 downsj 251: }
252:
1.10 deraadt 253: void
254: clear()
1.1 downsj 255: {
1.10 deraadt 256: if (smart_terminal)
257: putcap(clear_scr);
1.1 downsj 258: }
259:
1.9 pvalchev 260: int
261: clear_eol(int len)
1.1 downsj 262: {
1.10 deraadt 263: if (smart_terminal && !overstrike && len > 0) {
264: if (clear_line) {
265: putcap(clear_line);
266: return (0);
267: } else {
268: while (len-- > 0) {
269: if (putchar(' ') == EOF)
270: exit(1);
271: }
272: return (1);
273: }
1.1 downsj 274: }
1.10 deraadt 275: return (-1);
1.1 downsj 276: }
277:
1.9 pvalchev 278: void
279: go_home(void)
1.1 downsj 280: {
1.10 deraadt 281: if (smart_terminal)
282: putcap(home);
1.1 downsj 283: }
284:
285: /* This has to be defined as a subroutine for tputs (instead of a macro) */
1.9 pvalchev 286: int
287: putstdout(int ch)
1.1 downsj 288: {
1.10 deraadt 289: int ret;
1.7 deraadt 290:
1.10 deraadt 291: ret = putchar(ch);
292: if (ret == EOF)
293: exit(1);
294: return (ret);
1.1 downsj 295: }