1 /* $NetBSD: screen.c,v 1.6 2003/08/07 09:28:01 agc Exp $ */
4 * Copyright (c) 1988 Mark Nudelman
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/cdefs.h>
36 static char sccsid
[] = "@(#)screen.c 8.2 (Berkeley) 4/20/94";
38 __RCSID("$NetBSD: screen.c,v 1.6 2003/08/07 09:28:01 agc Exp $");
43 * Routines which deal with the characteristics of the terminal.
44 * Uses termcap to be as terminal-independent as possible.
46 * {{ Someday this should be rewritten to use curses. }}
65 #include <sys/ioctl.h>
75 #include <sys/ioctl.h>
78 * For the Unix PC (ATT 7300 & 3B1):
79 * Since WIOCGETD is defined in sys/window.h, we can't use that to decide
80 * whether to include sys/window.h. Use SIGPHONE from sys/signal.h instead.
82 #include <sys/signal.h>
84 #include <sys/window.h>
89 * Strings passed to tputs() to do various terminal functions.
92 *sc_pad
, /* Pad string */
93 *sc_home
, /* Cursor home */
94 *sc_addline
, /* Add line, scroll down following lines */
95 *sc_lower_left
, /* Cursor to last line, first column */
96 *sc_move
, /* General cursor positioning */
97 *sc_clear
, /* Clear screen */
98 *sc_eol_clear
, /* Clear to end of line */
99 *sc_s_in
, /* Enter standout (highlighted) mode */
100 *sc_s_out
, /* Exit standout mode */
101 *sc_u_in
, /* Enter underline mode */
102 *sc_u_out
, /* Exit underline mode */
103 *sc_b_in
, /* Enter bold mode */
104 *sc_b_out
, /* Exit bold mode */
105 *sc_backspace
, /* Backspace cursor */
106 *sc_init
, /* Startup terminal initialization */
107 *sc_deinit
; /* Exit terminal de-intialization */
109 int auto_wrap
; /* Terminal does \r\n when write past margin */
110 int ignaw
; /* Terminal ignores \n immediately after wrap */
111 /* The user's erase and line-kill chars */
112 int retain_below
; /* Terminal retains text below the screen */
113 int erase_char
, kill_char
, werase_char
;
114 int sc_width
, sc_height
= -1; /* Height & width of screen */
115 int sc_window
= -1; /* window size for forward and backward */
116 int bo_width
, be_width
; /* Printing width of boldface sequences */
117 int ul_width
, ue_width
; /* Printing width of underline sequences */
118 int so_width
, se_width
; /* Printing width of standout sequences */
121 * These two variables are sometimes defined in,
122 * and needed by, the termcap library.
123 * It may be necessary on some systems to declare them extern here.
125 /*extern*/ short ospeed
; /* Terminal output baud rate */
126 /*extern*/ char PC
; /* Pad character */
129 * Change terminal to "raw mode", or restore to "normal" mode.
131 * 1. An outstanding read will complete on receipt of a single keystroke.
132 * 2. Input is not echoed.
133 * 3. On output, \n is mapped to \r\n.
134 * 4. \t is NOT expanded into spaces.
135 * 5. Signal-causing characters such as ctrl-C (interrupt),
136 * etc. are NOT disabled.
137 * It doesn't matter whether an input \n is mapped to \r, or vice versa.
143 #if TERMIO || TERMIOS
147 static struct termio save_term
;
150 static struct termios save_term
;
156 * Get terminal modes.
159 (void)ioctl(2, TCGETA
, &s
);
165 * Save modes and set certain variables dependent on modes.
169 ospeed
= s
.c_cflag
& CBAUD
;
171 ospeed
= cfgetospeed(&s
);
173 erase_char
= s
.c_cc
[VERASE
];
174 kill_char
= s
.c_cc
[VKILL
];
175 werase_char
= s
.c_cc
[VWERASE
];
178 * Set the modes to the way we want them.
180 s
.c_lflag
&= ~(ICANON
|ECHO
|ECHOE
|ECHOK
|ECHONL
);
181 s
.c_oflag
|= (OPOST
|ONLCR
|TAB3
);
183 s
.c_oflag
&= ~(OCRNL
|ONOCR
|ONLRET
);
190 * Restore saved modes.
195 (void)ioctl(2, TCSETAW
, &s
);
197 tcsetattr(2, TCSADRAIN
, &s
);
202 static struct sgttyb save_term
;
207 * Get terminal modes.
209 (void)ioctl(2, TIOCGETP
, &s
);
210 (void)ioctl(2, TIOCGLTC
, &l
);
213 * Save modes and set certain variables dependent on modes.
216 ospeed
= s
.sg_ospeed
;
217 erase_char
= s
.sg_erase
;
218 kill_char
= s
.sg_kill
;
219 werase_char
= l
.t_werasc
;
222 * Set the modes to the way we want them.
224 s
.sg_flags
|= CBREAK
;
225 s
.sg_flags
&= ~(ECHO
|XTABS
);
229 * Restore saved modes.
233 (void)ioctl(2, TIOCSETN
, &s
);
238 * Get terminal capabilities via termcap.
254 static char sbuf
[1024];
257 * Find out what kind of terminal this is.
259 if ((term
= getenv("TERM")) == NULL
)
261 if (tgetent(termbuf
, term
) <= 0)
262 (void)strlcpy(termbuf
, "dumb:co#80:hc:", sizeof(termbuf
));
265 * Get size of the screen.
268 if (ioctl(2, TIOCGWINSZ
, &w
) == 0 && w
.ws_row
> 0)
269 sc_height
= w
.ws_row
;
272 if (ioctl(2, WIOCGETD
, &w
) == 0 && w
.uw_height
> 0)
273 sc_height
= w
.uw_height
/w
.uw_vs
;
277 sc_height
= tgetnum("li");
278 hard
= (sc_height
< 0 || tgetflag("hc"));
280 /* Oh no, this is a hardcopy terminal. */
285 if (ioctl(2, TIOCGWINSZ
, &w
) == 0 && w
.ws_col
> 0)
289 if (ioctl(2, WIOCGETD
, &w
) == 0 && w
.uw_width
> 0)
290 sc_width
= w
.uw_width
/w
.uw_hs
;
294 sc_width
= tgetnum("co");
298 auto_wrap
= tgetflag("am");
299 ignaw
= tgetflag("xn");
300 retain_below
= tgetflag("db");
303 * Assumes termcap variable "sg" is the printing width of
304 * the standout sequence, the end standout sequence,
305 * the underline sequence, the end underline sequence,
306 * the boldface sequence, and the end boldface sequence.
308 if ((so_width
= tgetnum("sg")) < 0)
310 be_width
= bo_width
= ue_width
= ul_width
= se_width
= so_width
;
313 * Get various string-valued capabilities.
317 sc_pad
= tgetstr("pc", &sp
);
321 sc_init
= tgetstr("ti", &sp
);
325 sc_deinit
= tgetstr("te", &sp
);
326 if (sc_deinit
== NULL
)
329 sc_eol_clear
= tgetstr("ce", &sp
);
330 if (hard
|| sc_eol_clear
== NULL
|| *sc_eol_clear
== '\0')
335 sc_clear
= tgetstr("cl", &sp
);
336 if (hard
|| sc_clear
== NULL
|| *sc_clear
== '\0')
341 sc_move
= tgetstr("cm", &sp
);
342 if (hard
|| sc_move
== NULL
|| *sc_move
== '\0')
345 * This is not an error here, because we don't
346 * always need sc_move.
347 * We need it only if we don't have home or lower-left.
352 sc_s_in
= tgetstr("so", &sp
);
353 if (hard
|| sc_s_in
== NULL
)
356 sc_s_out
= tgetstr("se", &sp
);
357 if (hard
|| sc_s_out
== NULL
)
360 sc_u_in
= tgetstr("us", &sp
);
361 if (hard
|| sc_u_in
== NULL
)
364 sc_u_out
= tgetstr("ue", &sp
);
365 if (hard
|| sc_u_out
== NULL
)
368 sc_b_in
= tgetstr("md", &sp
);
369 if (hard
|| sc_b_in
== NULL
)
375 sc_b_out
= tgetstr("me", &sp
);
376 if (hard
|| sc_b_out
== NULL
)
380 sc_home
= tgetstr("ho", &sp
);
381 if (hard
|| sc_home
== NULL
|| *sc_home
== '\0')
383 if (*sc_move
== '\0')
386 * This last resort for sc_home is supposed to
387 * be an up-arrow suggesting moving to the
388 * top of the "virtual screen". (The one in
389 * your imagination as you try to use this on
390 * a hard copy terminal.)
397 * but we can use "move(0,0)".
399 (void)strlcpy(sp
, tgoto(sc_move
, 0, 0),
400 sizeof(sbuf
) - (sp
- sbuf
));
402 sp
+= strlen(sp
) + 1;
406 sc_lower_left
= tgetstr("ll", &sp
);
407 if (hard
|| sc_lower_left
== NULL
|| *sc_lower_left
== '\0')
409 if (*sc_move
== '\0')
411 sc_lower_left
= "\r";
415 * No "lower-left" string,
416 * but we can use "move(0,last-line)".
418 (void)strlcpy(sp
, tgoto(sc_move
, 0, sc_height
-1),
419 sizeof(sbuf
) - (sp
- sbuf
));
421 sp
+= strlen(sp
) + 1;
426 * To add a line at top of screen and scroll the display down,
427 * we use "al" (add line) or "sr" (scroll reverse).
429 if ((sc_addline
= tgetstr("al", &sp
)) == NULL
||
431 sc_addline
= tgetstr("sr", &sp
);
433 if (hard
|| sc_addline
== NULL
|| *sc_addline
== '\0')
436 /* Force repaint on any backward movement */
444 sc_backspace
= tgetstr("bc", &sp
);
445 if (sc_backspace
== NULL
|| *sc_backspace
== '\0')
452 * Below are the functions which perform all the
453 * terminal-specific screen manipulation.
457 * Initialize terminal
462 tputs(sc_init
, sc_height
, putchr
);
466 * Deinitialize terminal
471 tputs(sc_deinit
, sc_height
, putchr
);
475 * Home cursor (move to upper left corner of screen).
480 tputs(sc_home
, 1, putchr
);
484 * Add a blank line (called with cursor at home).
485 * Should scroll the display down.
490 tputs(sc_addline
, sc_height
, putchr
);
493 int short_file
; /* if file less than a screen */
502 tputs(sc_lower_left
, 1, putchr
);
506 * Ring the terminal bell.
520 tputs(sc_clear
, sc_height
, putchr
);
524 * Clear from the cursor to the end of the cursor's line.
525 * {{ This must not move the cursor. }}
530 tputs(sc_eol_clear
, 1, putchr
);
534 * Begin "standout" (bold, underline, or whatever).
539 tputs(sc_s_in
, 1, putchr
);
548 tputs(sc_s_out
, 1, putchr
);
552 * Begin "underline" (hopefully real underlining,
553 * otherwise whatever the terminal provides).
558 tputs(sc_u_in
, 1, putchr
);
567 tputs(sc_u_out
, 1, putchr
);
576 tputs(sc_b_in
, 1, putchr
);
585 tputs(sc_b_out
, 1, putchr
);
589 * Erase the character to the left of the cursor
590 * and move the cursor left.
596 * Try to erase the previous character by overstriking with a space.
598 tputs(sc_backspace
, 1, putchr
);
600 tputs(sc_backspace
, 1, putchr
);
604 * Output a plain backspace, without erasing the previous char.
609 tputs(sc_backspace
, 1, putchr
);