1*84d9c625SLionel Sambuc /* $NetBSD: setterm.c,v 1.52 2013/10/16 19:59:29 roy Exp $ */
2b7061124SArun Thomas
351ffecc1SBen Gras /*
451ffecc1SBen Gras * Copyright (c) 1981, 1993, 1994
551ffecc1SBen Gras * The Regents of the University of California. All rights reserved.
651ffecc1SBen Gras *
751ffecc1SBen Gras * Redistribution and use in source and binary forms, with or without
851ffecc1SBen Gras * modification, are permitted provided that the following conditions
951ffecc1SBen Gras * are met:
1051ffecc1SBen Gras * 1. Redistributions of source code must retain the above copyright
1151ffecc1SBen Gras * notice, this list of conditions and the following disclaimer.
1251ffecc1SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
1351ffecc1SBen Gras * notice, this list of conditions and the following disclaimer in the
1451ffecc1SBen Gras * documentation and/or other materials provided with the distribution.
1551ffecc1SBen Gras * 3. Neither the name of the University nor the names of its contributors
1651ffecc1SBen Gras * may be used to endorse or promote products derived from this software
1751ffecc1SBen Gras * without specific prior written permission.
1851ffecc1SBen Gras *
1951ffecc1SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2051ffecc1SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2151ffecc1SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2251ffecc1SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2351ffecc1SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2451ffecc1SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2551ffecc1SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2651ffecc1SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2751ffecc1SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2851ffecc1SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2951ffecc1SBen Gras * SUCH DAMAGE.
3051ffecc1SBen Gras */
31b7061124SArun Thomas
3251ffecc1SBen Gras #include <sys/cdefs.h>
3351ffecc1SBen Gras #ifndef lint
3451ffecc1SBen Gras #if 0
3551ffecc1SBen Gras static char sccsid[] = "@(#)setterm.c 8.8 (Berkeley) 10/25/94";
3651ffecc1SBen Gras #else
37*84d9c625SLionel Sambuc __RCSID("$NetBSD: setterm.c,v 1.52 2013/10/16 19:59:29 roy Exp $");
3851ffecc1SBen Gras #endif
3951ffecc1SBen Gras #endif /* not lint */
4051ffecc1SBen Gras
4151ffecc1SBen Gras #include <sys/ioctl.h> /* TIOCGWINSZ on old systems. */
4251ffecc1SBen Gras
4351ffecc1SBen Gras #include <stdlib.h>
4451ffecc1SBen Gras #include <string.h>
4551ffecc1SBen Gras #include <termios.h>
4651ffecc1SBen Gras #include <unistd.h>
4751ffecc1SBen Gras
4851ffecc1SBen Gras #include "curses.h"
4951ffecc1SBen Gras #include "curses_private.h"
5051ffecc1SBen Gras
5151ffecc1SBen Gras static int does_esc_m(const char *cap);
52*84d9c625SLionel Sambuc static int does_ctrl_o(const char *exit_cap, const char *acs_cap);
5351ffecc1SBen Gras
5451ffecc1SBen Gras attr_t __mask_op, __mask_me, __mask_ue, __mask_se;
5551ffecc1SBen Gras
5651ffecc1SBen Gras int
setterm(char * type)5751ffecc1SBen Gras setterm(char *type)
58b7061124SArun Thomas {
5951ffecc1SBen Gras return _cursesi_setterm(type, _cursesi_screen);
60b7061124SArun Thomas }
61b7061124SArun Thomas
6251ffecc1SBen Gras int
_cursesi_setterm(char * type,SCREEN * screen)6351ffecc1SBen Gras _cursesi_setterm(char *type, SCREEN *screen)
64b7061124SArun Thomas {
6551ffecc1SBen Gras int unknown, r;
6651ffecc1SBen Gras struct winsize win;
6751ffecc1SBen Gras char *p;
6851ffecc1SBen Gras
6951ffecc1SBen Gras if (type[0] == '\0')
7051ffecc1SBen Gras type = "xx";
7151ffecc1SBen Gras unknown = 0;
7251ffecc1SBen Gras (void)ti_setupterm(&screen->term, type, fileno(screen->outfd), &r);
7351ffecc1SBen Gras if (screen->term == NULL) {
7451ffecc1SBen Gras unknown++;
7551ffecc1SBen Gras (void)ti_setupterm(&screen->term, "dumb",
7651ffecc1SBen Gras fileno(screen->outfd), &r);
7751ffecc1SBen Gras /* No dumb term? We can't continue */
7851ffecc1SBen Gras if (screen->term == NULL)
7951ffecc1SBen Gras return ERR;
8051ffecc1SBen Gras }
8151ffecc1SBen Gras #ifdef DEBUG
8251ffecc1SBen Gras __CTRACE(__CTRACE_INIT, "setterm: tty = %s\n", type);
8351ffecc1SBen Gras #endif
8451ffecc1SBen Gras
850c3ae37fSLionel Sambuc /* Try TIOCGWINSZ, and, if it fails, the terminfo entry. */
8651ffecc1SBen Gras if (ioctl(fileno(screen->outfd), TIOCGWINSZ, &win) != -1 &&
8751ffecc1SBen Gras win.ws_row != 0 && win.ws_col != 0) {
8851ffecc1SBen Gras screen->LINES = win.ws_row;
8951ffecc1SBen Gras screen->COLS = win.ws_col;
9051ffecc1SBen Gras } else {
9151ffecc1SBen Gras if (unknown) {
9251ffecc1SBen Gras screen->LINES = -1;
9351ffecc1SBen Gras screen->COLS = -1;
9451ffecc1SBen Gras } else {
9551ffecc1SBen Gras screen->LINES = t_lines(screen->term);
9651ffecc1SBen Gras screen->COLS = t_columns(screen->term);
97b7061124SArun Thomas }
9851ffecc1SBen Gras }
99b7061124SArun Thomas
10051ffecc1SBen Gras /* POSIX 1003.2 requires that the environment override. */
10151ffecc1SBen Gras if ((p = getenv("LINES")) != NULL)
10251ffecc1SBen Gras screen->LINES = (int) strtol(p, NULL, 0);
10351ffecc1SBen Gras if ((p = getenv("COLUMNS")) != NULL)
10451ffecc1SBen Gras screen->COLS = (int) strtol(p, NULL, 0);
10551ffecc1SBen Gras if ((p = getenv("ESCDELAY")) != NULL)
10651ffecc1SBen Gras ESCDELAY = (int) strtol(p, NULL, 0);
107*84d9c625SLionel Sambuc if ((p = getenv("TABSIZE")) != NULL)
108*84d9c625SLionel Sambuc screen->TABSIZE = (int) strtol(p, NULL, 0);
109*84d9c625SLionel Sambuc else if (t_init_tabs(screen->term) >= 0)
110*84d9c625SLionel Sambuc screen->TABSIZE = (int) t_init_tabs(screen->term);
111*84d9c625SLionel Sambuc else
112*84d9c625SLionel Sambuc screen->TABSIZE = 8;
11351ffecc1SBen Gras /*
11451ffecc1SBen Gras * Want cols > 4, otherwise things will fail.
11551ffecc1SBen Gras */
11651ffecc1SBen Gras if (screen->COLS <= 4)
11751ffecc1SBen Gras return (ERR);
118b7061124SArun Thomas
11951ffecc1SBen Gras LINES = screen->LINES;
12051ffecc1SBen Gras COLS = screen->COLS;
121*84d9c625SLionel Sambuc TABSIZE = screen->TABSIZE;
12251ffecc1SBen Gras
12351ffecc1SBen Gras #ifdef DEBUG
124*84d9c625SLionel Sambuc __CTRACE(__CTRACE_INIT,
125*84d9c625SLionel Sambuc "setterm: LINES = %d, COLS = %d\n, TABSIZE = %d\n",
126*84d9c625SLionel Sambuc LINES, COLS, TABSIZE);
12751ffecc1SBen Gras #endif
12851ffecc1SBen Gras
12951ffecc1SBen Gras /*
13051ffecc1SBen Gras * set the pad char, only take the first char of the pc capability
13151ffecc1SBen Gras * as this is all we can use.
13251ffecc1SBen Gras */
13351ffecc1SBen Gras screen->padchar = t_pad_char(screen->term) ?
13451ffecc1SBen Gras t_pad_char(screen->term)[0] : 0;
13551ffecc1SBen Gras
13651ffecc1SBen Gras /* If no scrolling commands, no quick change. */
13751ffecc1SBen Gras screen->noqch =
13851ffecc1SBen Gras (t_change_scroll_region(screen->term) == NULL ||
13951ffecc1SBen Gras t_cursor_home(screen->term) == NULL ||
14051ffecc1SBen Gras (t_parm_index(screen->term) == NULL &&
14151ffecc1SBen Gras t_scroll_forward(screen->term) == NULL) ||
14251ffecc1SBen Gras (t_parm_rindex(screen->term) == NULL &&
14351ffecc1SBen Gras t_scroll_reverse(screen->term) == NULL)) &&
14451ffecc1SBen Gras ((t_parm_insert_line(screen->term) == NULL &&
14551ffecc1SBen Gras t_insert_line(screen->term) == NULL) ||
14651ffecc1SBen Gras (t_parm_delete_line(screen->term) == NULL &&
14751ffecc1SBen Gras t_delete_line(screen->term) == NULL));
14851ffecc1SBen Gras
14951ffecc1SBen Gras /*
15051ffecc1SBen Gras * Precalculate conflict info for color/attribute end commands.
15151ffecc1SBen Gras */
15251ffecc1SBen Gras #ifndef HAVE_WCHAR
15351ffecc1SBen Gras screen->mask_op = __ATTRIBUTES & ~__COLOR;
15451ffecc1SBen Gras #else
15551ffecc1SBen Gras screen->mask_op = WA_ATTRIBUTES & ~__COLOR;
15651ffecc1SBen Gras #endif /* HAVE_WCHAR */
15751ffecc1SBen Gras if (t_orig_pair(screen->term) != NULL) {
15851ffecc1SBen Gras if (does_esc_m(t_orig_pair(screen->term)))
15951ffecc1SBen Gras screen->mask_op &=
16051ffecc1SBen Gras ~(__STANDOUT | __UNDERSCORE | __TERMATTR);
16151ffecc1SBen Gras else {
16251ffecc1SBen Gras if (t_exit_standout_mode(screen->term) != NULL &&
16351ffecc1SBen Gras !strcmp(t_orig_pair(screen->term),
16451ffecc1SBen Gras t_exit_standout_mode(screen->term)))
16551ffecc1SBen Gras screen->mask_op &= ~__STANDOUT;
16651ffecc1SBen Gras if (t_exit_underline_mode(screen->term) != NULL &&
16751ffecc1SBen Gras !strcmp(t_orig_pair(screen->term),
16851ffecc1SBen Gras t_exit_underline_mode(screen->term)))
16951ffecc1SBen Gras screen->mask_op &= ~__UNDERSCORE;
17051ffecc1SBen Gras if (t_exit_attribute_mode(screen->term) != NULL &&
17151ffecc1SBen Gras !strcmp(t_orig_pair(screen->term),
17251ffecc1SBen Gras t_exit_attribute_mode(screen->term)))
17351ffecc1SBen Gras screen->mask_op &= ~__TERMATTR;
17451ffecc1SBen Gras }
17551ffecc1SBen Gras }
17651ffecc1SBen Gras /*
17751ffecc1SBen Gras * Assume that "me" turns off all attributes apart from ACS.
17851ffecc1SBen Gras * It might turn off ACS, so check for that.
17951ffecc1SBen Gras */
18051ffecc1SBen Gras if (t_exit_attribute_mode(screen->term) != NULL &&
181*84d9c625SLionel Sambuc t_exit_alt_charset_mode(screen->term) != NULL &&
182*84d9c625SLionel Sambuc does_ctrl_o(t_exit_attribute_mode(screen->term),
183*84d9c625SLionel Sambuc t_exit_alt_charset_mode(screen->term)))
18451ffecc1SBen Gras screen->mask_me = 0;
18551ffecc1SBen Gras else
18651ffecc1SBen Gras screen->mask_me = __ALTCHARSET;
18751ffecc1SBen Gras
18851ffecc1SBen Gras /* Check what turning off the attributes also turns off */
18951ffecc1SBen Gras #ifndef HAVE_WCHAR
19051ffecc1SBen Gras screen->mask_ue = __ATTRIBUTES & ~__UNDERSCORE;
19151ffecc1SBen Gras #else
19251ffecc1SBen Gras screen->mask_ue = WA_ATTRIBUTES & ~__UNDERSCORE;
19351ffecc1SBen Gras #endif /* HAVE_WCHAR */
19451ffecc1SBen Gras if (t_exit_underline_mode(screen->term) != NULL) {
19551ffecc1SBen Gras if (does_esc_m(t_exit_underline_mode(screen->term)))
19651ffecc1SBen Gras screen->mask_ue &=
19751ffecc1SBen Gras ~(__STANDOUT | __TERMATTR | __COLOR);
19851ffecc1SBen Gras else {
19951ffecc1SBen Gras if (t_exit_standout_mode(screen->term) != NULL &&
20051ffecc1SBen Gras !strcmp(t_exit_underline_mode(screen->term),
20151ffecc1SBen Gras t_exit_standout_mode(screen->term)))
20251ffecc1SBen Gras screen->mask_ue &= ~__STANDOUT;
20351ffecc1SBen Gras if (t_exit_attribute_mode(screen->term) != NULL &&
20451ffecc1SBen Gras !strcmp(t_exit_underline_mode(screen->term),
20551ffecc1SBen Gras t_exit_attribute_mode(screen->term)))
20651ffecc1SBen Gras screen->mask_ue &= ~__TERMATTR;
20751ffecc1SBen Gras if (t_orig_pair(screen->term) != NULL &&
20851ffecc1SBen Gras !strcmp(t_exit_underline_mode(screen->term),
20951ffecc1SBen Gras t_orig_pair(screen->term)))
21051ffecc1SBen Gras screen->mask_ue &= ~__COLOR;
21151ffecc1SBen Gras }
21251ffecc1SBen Gras }
21351ffecc1SBen Gras #ifndef HAVE_WCHAR
21451ffecc1SBen Gras screen->mask_se = __ATTRIBUTES & ~__STANDOUT;
21551ffecc1SBen Gras #else
21651ffecc1SBen Gras screen->mask_se = WA_ATTRIBUTES & ~__STANDOUT;
21751ffecc1SBen Gras #endif /* HAVE_WCHAR */
21851ffecc1SBen Gras if (t_exit_standout_mode(screen->term) != NULL) {
21951ffecc1SBen Gras if (does_esc_m(t_exit_standout_mode(screen->term)))
22051ffecc1SBen Gras screen->mask_se &=
22151ffecc1SBen Gras ~(__UNDERSCORE | __TERMATTR | __COLOR);
22251ffecc1SBen Gras else {
22351ffecc1SBen Gras if (t_exit_underline_mode(screen->term) != NULL &&
22451ffecc1SBen Gras !strcmp(t_exit_standout_mode(screen->term),
22551ffecc1SBen Gras t_exit_underline_mode(screen->term)))
22651ffecc1SBen Gras screen->mask_se &= ~__UNDERSCORE;
22751ffecc1SBen Gras if (t_exit_attribute_mode(screen->term) != NULL &&
22851ffecc1SBen Gras !strcmp(t_exit_standout_mode(screen->term),
22951ffecc1SBen Gras t_exit_attribute_mode(screen->term)))
23051ffecc1SBen Gras screen->mask_se &= ~__TERMATTR;
23151ffecc1SBen Gras if (t_orig_pair(screen->term) != NULL &&
23251ffecc1SBen Gras !strcmp(t_exit_standout_mode(screen->term),
23351ffecc1SBen Gras t_orig_pair(screen->term)))
23451ffecc1SBen Gras screen->mask_se &= ~__COLOR;
23551ffecc1SBen Gras }
23651ffecc1SBen Gras }
23751ffecc1SBen Gras
23851ffecc1SBen Gras return (unknown ? ERR : OK);
23951ffecc1SBen Gras }
24051ffecc1SBen Gras
24151ffecc1SBen Gras /*
24251ffecc1SBen Gras * _cursesi_resetterm --
24351ffecc1SBen Gras * Copy the terminal instance data for the given screen to the global
24451ffecc1SBen Gras * variables.
24551ffecc1SBen Gras */
24651ffecc1SBen Gras void
_cursesi_resetterm(SCREEN * screen)24751ffecc1SBen Gras _cursesi_resetterm(SCREEN *screen)
248b7061124SArun Thomas {
24951ffecc1SBen Gras
25051ffecc1SBen Gras LINES = screen->LINES;
25151ffecc1SBen Gras COLS = screen->COLS;
252*84d9c625SLionel Sambuc TABSIZE = screen->TABSIZE;
25351ffecc1SBen Gras __GT = screen->GT;
25451ffecc1SBen Gras
25551ffecc1SBen Gras __noqch = screen->noqch;
25651ffecc1SBen Gras __mask_op = screen->mask_op;
25751ffecc1SBen Gras __mask_me = screen->mask_me;
25851ffecc1SBen Gras __mask_ue = screen->mask_ue;
25951ffecc1SBen Gras __mask_se = screen->mask_se;
26051ffecc1SBen Gras
26151ffecc1SBen Gras set_curterm(screen->term);
26251ffecc1SBen Gras }
26351ffecc1SBen Gras
26451ffecc1SBen Gras /*
26551ffecc1SBen Gras * does_esc_m --
26651ffecc1SBen Gras * A hack for xterm-like terminals where "\E[m" or "\E[0m" will turn off
26751ffecc1SBen Gras * other attributes, so we check for this in the capability passed to us.
26851ffecc1SBen Gras * Note that we can't just do simple string comparison, as the capability
26951ffecc1SBen Gras * may contain multiple, ';' separated sequence parts.
27051ffecc1SBen Gras */
27151ffecc1SBen Gras static int
does_esc_m(const char * cap)27251ffecc1SBen Gras does_esc_m(const char *cap)
27351ffecc1SBen Gras {
27451ffecc1SBen Gras #define WAITING 0
27551ffecc1SBen Gras #define PARSING 1
27651ffecc1SBen Gras #define NUMBER 2
27751ffecc1SBen Gras #define FOUND 4
27851ffecc1SBen Gras const char *capptr;
27951ffecc1SBen Gras int seq;
28051ffecc1SBen Gras
28151ffecc1SBen Gras #ifdef DEBUG
28251ffecc1SBen Gras __CTRACE(__CTRACE_INIT, "does_esc_m: Checking %s\n", cap);
28351ffecc1SBen Gras #endif
28451ffecc1SBen Gras /* Is it just "\E[m" or "\E[0m"? */
28551ffecc1SBen Gras if (!strcmp(cap, "\x1b[m") || !strcmp(cap, "\x1b[0m"))
28651ffecc1SBen Gras return 1;
28751ffecc1SBen Gras
28851ffecc1SBen Gras /* Does it contain a "\E[...m" sequence? */
28951ffecc1SBen Gras if (strlen(cap) < 4)
29051ffecc1SBen Gras return 0;
29151ffecc1SBen Gras capptr = cap;
29251ffecc1SBen Gras seq = WAITING;
29351ffecc1SBen Gras while (*capptr != 0) {
29451ffecc1SBen Gras switch (seq) {
29551ffecc1SBen Gras /* Start of sequence */
29651ffecc1SBen Gras case WAITING:
29751ffecc1SBen Gras if (!strncmp(capptr, "\x1b[", 2)) {
29851ffecc1SBen Gras capptr+=2;
29951ffecc1SBen Gras if (*capptr == 'm')
30051ffecc1SBen Gras return 1;
30151ffecc1SBen Gras else {
30251ffecc1SBen Gras seq=PARSING;
30351ffecc1SBen Gras continue;
30451ffecc1SBen Gras }
30551ffecc1SBen Gras }
30651ffecc1SBen Gras break;
30751ffecc1SBen Gras /* Looking for '0' */
30851ffecc1SBen Gras case PARSING:
30951ffecc1SBen Gras if (*capptr == '0')
31051ffecc1SBen Gras seq=FOUND;
31151ffecc1SBen Gras else if (*capptr > '0' && *capptr <= '9')
31251ffecc1SBen Gras seq=NUMBER;
31351ffecc1SBen Gras else if (*capptr != ';')
31451ffecc1SBen Gras seq=WAITING;
31551ffecc1SBen Gras break;
31651ffecc1SBen Gras /* Some other number */
31751ffecc1SBen Gras case NUMBER:
31851ffecc1SBen Gras if (*capptr == ';')
31951ffecc1SBen Gras seq=PARSING;
32051ffecc1SBen Gras else if (!(*capptr >= '0' && *capptr <= '9'))
32151ffecc1SBen Gras seq=WAITING;
32251ffecc1SBen Gras break;
32351ffecc1SBen Gras /* Found a '0' */
32451ffecc1SBen Gras case FOUND:
32551ffecc1SBen Gras if (*capptr == 'm')
32651ffecc1SBen Gras return 1;
32751ffecc1SBen Gras else if (!((*capptr >= '0' && *capptr <= '9') ||
32851ffecc1SBen Gras *capptr == ';'))
32951ffecc1SBen Gras seq=WAITING;
33051ffecc1SBen Gras break;
33151ffecc1SBen Gras default:
33251ffecc1SBen Gras break;
33351ffecc1SBen Gras }
33451ffecc1SBen Gras capptr++;
33551ffecc1SBen Gras }
33651ffecc1SBen Gras return 0;
33751ffecc1SBen Gras }
33851ffecc1SBen Gras
33951ffecc1SBen Gras /*
34051ffecc1SBen Gras * does_ctrl_o --
34151ffecc1SBen Gras * A hack for vt100/xterm-like terminals where the "me" capability also
342*84d9c625SLionel Sambuc * unsets acs.
34351ffecc1SBen Gras */
34451ffecc1SBen Gras static int
does_ctrl_o(const char * exit_cap,const char * acs_cap)345*84d9c625SLionel Sambuc does_ctrl_o(const char *exit_cap, const char *acs_cap)
34651ffecc1SBen Gras {
347*84d9c625SLionel Sambuc const char *eptr = exit_cap, *aptr = acs_cap;
348*84d9c625SLionel Sambuc int l;
34951ffecc1SBen Gras
35051ffecc1SBen Gras #ifdef DEBUG
351*84d9c625SLionel Sambuc __CTRACE(__CTRACE_INIT, "does_ctrl_o: Testing %s for %s\n", eptr, aptr);
35251ffecc1SBen Gras #endif
353*84d9c625SLionel Sambuc l = strlen(acs_cap);
354*84d9c625SLionel Sambuc while (*eptr != 0) {
355*84d9c625SLionel Sambuc if (!strncmp(eptr, aptr, l))
35651ffecc1SBen Gras return 1;
357*84d9c625SLionel Sambuc eptr++;
35851ffecc1SBen Gras }
35951ffecc1SBen Gras return 0;
36051ffecc1SBen Gras }
361