Annotation of src/usr.bin/top/screen.c, Revision 1.16
1.16 ! otto 1: /* $OpenBSD: screen.c,v 1.15 2007/03/30 19:21:19 otto 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.
1.14 deraadt 33: *
1.10 deraadt 34: * Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty.
1.14 deraadt 35: *
1.10 deraadt 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>
1.13 millert 43: #include <err.h>
1.2 downsj 44: #include <stdio.h>
45: #include <stdlib.h>
1.3 millert 46: #include <string.h>
1.2 downsj 47: #include <term.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;
1.1 downsj 60:
1.12 deraadt 61: static struct termios old_settings, new_settings;
1.1 downsj 62:
1.12 deraadt 63: static char is_a_terminal = No;
1.1 downsj 64:
1.9 pvalchev 65: void
66: init_termcap(int interactive)
1.1 downsj 67: {
1.10 deraadt 68: char *bufptr, *PCptr, *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: /* pretend we have a dumb terminal */
77: smart_terminal = No;
78: return;
79: }
80: /* assume we have a smart terminal until proven otherwise */
81: smart_terminal = Yes;
82:
83: /* get the terminal name */
84: term_name = getenv("TERM");
85:
86: /* if there is no TERM, assume it's a dumb terminal */
87: /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */
88: if (term_name == NULL) {
89: smart_terminal = No;
90: return;
91: }
92:
93: /* now get the termcap entry */
94: if ((status = tgetent(NULL, term_name)) != 1) {
95: if (status == -1)
1.12 deraadt 96: warnx("can't open termcap file");
1.10 deraadt 97: else
1.12 deraadt 98: warnx("no termcap entry for a `%s' terminal", term_name);
1.10 deraadt 99:
100: /* pretend it's dumb and proceed */
101: smart_terminal = No;
102: return;
1.1 downsj 103: }
1.10 deraadt 104:
105: /* "hardcopy" immediately indicates a very stupid terminal */
106: if (tgetflag("hc")) {
107: smart_terminal = No;
108: return;
109: }
110: /* set up common terminal capabilities */
111: if ((screen_length = tgetnum("li")) <= Header_lines) {
112: screen_length = smart_terminal = 0;
113: return;
114: }
115:
116: /* screen_width is a little different */
117: if ((screen_width = tgetnum("co")) == -1)
118: screen_width = 79;
1.1 downsj 119: else
1.10 deraadt 120: screen_width -= 1;
121:
122: /* terminals that overstrike need special attention */
123: overstrike = tgetflag("os");
124:
125: /* initialize the pointer into the termcap string buffer */
126: bufptr = string_buffer;
127:
128: /* get "ce", clear to end */
129: if (!overstrike) {
130: clear_line = tgetstr("ce", &bufptr);
131: }
132: /* get necessary capabilities */
133: if ((clear_scr = tgetstr("cl", &bufptr)) == NULL ||
134: (cursor_motion = tgetstr("cm", &bufptr)) == NULL) {
135: smart_terminal = No;
136: return;
137: }
138: /* get some more sophisticated stuff -- these are optional */
139: clear_to_end = tgetstr("cd", &bufptr);
140: terminal_init = tgetstr("ti", &bufptr);
141: terminal_end = tgetstr("te", &bufptr);
142: start_standout = tgetstr("so", &bufptr);
143: end_standout = tgetstr("se", &bufptr);
144:
145: /* pad character */
146: PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0;
147:
148: /* set convenience strings */
149: (void) strlcpy(home, tgoto(cursor_motion, 0, 0), sizeof(home));
150: /* (lower_left is set in get_screensize) */
151:
152: /* get the actual screen size with an ioctl, if needed */
153: /*
154: * This may change screen_width and screen_length, and it always sets
155: * lower_left.
156: */
157: get_screensize();
158:
159: /* if stdout is not a terminal, pretend we are a dumb terminal */
160: if (tcgetattr(STDOUT_FILENO, &old_settings) == -1)
161: smart_terminal = No;
1.1 downsj 162: }
163:
1.9 pvalchev 164: void
165: init_screen(void)
1.1 downsj 166: {
1.10 deraadt 167: /* get the old settings for safe keeping */
168: if (tcgetattr(STDOUT_FILENO, &old_settings) != -1) {
169: /* copy the settings so we can modify them */
170: new_settings = old_settings;
171:
172: /* turn off ICANON, character echo and tab expansion */
173: new_settings.c_lflag &= ~(ICANON | ECHO);
174: new_settings.c_oflag &= ~(OXTABS);
175: new_settings.c_cc[VMIN] = 1;
176: new_settings.c_cc[VTIME] = 0;
177: (void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings);
178:
179: /* remember the erase and kill characters */
180: ch_erase = old_settings.c_cc[VERASE];
181: ch_kill = old_settings.c_cc[VKILL];
182:
183: /* remember that it really is a terminal */
184: is_a_terminal = Yes;
185:
186: /* send the termcap initialization string */
187: putcap(terminal_init);
188: }
189: if (!is_a_terminal) {
190: /* not a terminal at all---consider it dumb */
191: smart_terminal = No;
192: }
1.1 downsj 193: }
194:
1.9 pvalchev 195: void
196: end_screen(void)
1.1 downsj 197: {
1.10 deraadt 198: /* move to the lower left, clear the line and send "te" */
199: if (smart_terminal) {
200: putcap(lower_left);
201: putcap(clear_line);
202: fflush(stdout);
203: putcap(terminal_end);
204: }
205:
206: /* if we have settings to reset, then do so */
207: if (is_a_terminal)
208: (void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &old_settings);
1.1 downsj 209: }
210:
1.9 pvalchev 211: void
212: reinit_screen(void)
1.1 downsj 213: {
1.10 deraadt 214: /* install our settings if it is a terminal */
215: if (is_a_terminal)
216: (void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings);
217:
218: /* send init string */
219: if (smart_terminal)
220: putcap(terminal_init);
1.1 downsj 221: }
222:
1.9 pvalchev 223: void
224: get_screensize(void)
1.1 downsj 225: {
1.10 deraadt 226: struct winsize ws;
1.1 downsj 227:
1.10 deraadt 228: if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) {
229: if (ws.ws_row != 0)
230: screen_length = ws.ws_row;
231: if (ws.ws_col != 0)
232: screen_width = ws.ws_col - 1;
233: }
234: (void) strlcpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1),
235: sizeof(lower_left));
1.1 downsj 236: }
237:
1.9 pvalchev 238: void
239: standout(char *msg)
1.1 downsj 240: {
1.10 deraadt 241: if (smart_terminal) {
242: putcap(start_standout);
243: if (fputs(msg, stdout) == EOF)
244: exit(1);
245: putcap(end_standout);
246: } else {
247: if (fputs(msg, stdout) == EOF)
248: exit(1);
249: }
1.1 downsj 250: }
251:
1.14 deraadt 252: void
253: clear(void)
1.1 downsj 254: {
1.10 deraadt 255: if (smart_terminal)
256: putcap(clear_scr);
1.1 downsj 257: }
258:
1.9 pvalchev 259: int
260: clear_eol(int len)
1.1 downsj 261: {
1.10 deraadt 262: if (smart_terminal && !overstrike && len > 0) {
263: if (clear_line) {
264: putcap(clear_line);
265: return (0);
266: } else {
267: while (len-- > 0) {
268: if (putchar(' ') == EOF)
269: exit(1);
270: }
271: return (1);
272: }
1.1 downsj 273: }
1.10 deraadt 274: return (-1);
1.1 downsj 275: }
276:
1.9 pvalchev 277: void
278: go_home(void)
1.1 downsj 279: {
1.10 deraadt 280: if (smart_terminal)
281: putcap(home);
1.1 downsj 282: }
283:
284: /* This has to be defined as a subroutine for tputs (instead of a macro) */
1.9 pvalchev 285: int
286: putstdout(int ch)
1.1 downsj 287: {
1.10 deraadt 288: int ret;
1.7 deraadt 289:
1.10 deraadt 290: ret = putchar(ch);
291: if (ret == EOF)
292: exit(1);
293: return (ret);
1.1 downsj 294: }