xref: /netbsd-src/lib/libcurses/setterm.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /*	$NetBSD: setterm.c,v 1.26 2000/06/12 21:04:08 jdc Exp $	*/
2 
3 /*
4  * Copyright (c) 1981, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)setterm.c	8.8 (Berkeley) 10/25/94";
40 #else
41 __RCSID("$NetBSD: setterm.c,v 1.26 2000/06/12 21:04:08 jdc Exp $");
42 #endif
43 #endif /* not lint */
44 
45 #include <sys/ioctl.h>		/* TIOCGWINSZ on old systems. */
46 
47 #include <stdlib.h>
48 #include <string.h>
49 #include <termios.h>
50 #include <unistd.h>
51 
52 #include "curses.h"
53 #include "curses_private.h"
54 
55 static int zap(struct tinfo *tinfo);
56 
57 struct tinfo *_cursesi_genbuf;
58 
59 static char	*sflags[] = {
60 		/*	 am   ut   bs   cc   da   eo   hc   hl  */
61 			&AM, &UT, &BS, &CC, &DA, &EO, &HC, &HL,
62 		/*	 in   mi   ms   nc   ns   os   ul   xb  */
63 			&IN, &MI, &MS, &NC, &NS, &OS, &UL, &XB,
64 		/*	 xn   xt   xs   xx  */
65 			&XN, &XT, &XS, &XX
66 		};
67 
68 static int	*svals[] = {
69 		/*	 pa   Co */
70 			&PA, &cO, &nc
71 		};
72 static char	*_PC,
73 		**sstrs[] = {
74 		/*	 AC   AE   AL   AS   bc   bl   bt   cd   ce  */
75 			&AC, &AE, &AL, &AS, &BC, &BL, &BT, &CD, &CE,
76 		/*	 cl   cm   cr   cs   dc   DL   dm   do   eA  */
77 			&CL, &CM, &CR, &CS, &DC, &DL, &DM, &DO, &Ea,
78 		/*	 ed   ei   k0   k1   k2   k3   k4   k5   k6  */
79 			&ED, &EI, &K0, &K1, &K2, &K3, &K4, &K5, &K6,
80 		/*	 k7   k8   k9   ho   ic   im   ip   kd   ke  */
81 			&K7, &K8, &K9, &HO, &IC, &IM, &IP, &KD, &KE,
82 		/*	 kh   kl   kr   ks   ku   ll   ma   mb   md  */
83 			&KH, &KL, &KR, &KS, &KU, &LL, &MA, &MB, &MD,
84 		/*	 me   mh   mk   mm   mo   mp   mr   nd   nl  */
85 			&ME, &MH, &MK, &MM, &MO, &MP, &MR, &ND, &NL,
86 		/*	 oc   op    pc   rc   sc   se   SF   so   sp */
87 			&OC, &OP, &_PC, &RC, &SC, &SE, &SF, &SO, &SP,
88 		/*	 SR   ta   te   ti   uc   ue   up   us   vb  */
89 			&SR, &TA, &TE, &TI, &UC, &UE, &UP, &US, &VB,
90 		/*	 vi   vs   ve   AB   AF   al   dl   Ic   Ip  */
91 			&VI, &VS, &VE, &ab, &af, &al, &dl, &iC, &iP,
92 		/*	 Sb   Sf   sf   sr   AL        DL        UP  */
93 			&sB, &sF, &sf, &sr, &AL_PARM, &DL_PARM, &UP_PARM,
94 		/*	   DO        LE          RI                  */
95 			&DOWN_PARM, &LEFT_PARM, &RIGHT_PARM,
96 		};
97 
98 static char	*aoftspace;		/* Address of _tspace for relocation */
99 static char	*tspace;		/* Space for capability strings */
100 static size_t   tspace_size;            /* size of tspace */
101 
102 char	*ttytype;
103 attr_t	 __mask_OP, __mask_ME, __mask_UE, __mask_SE;
104 
105 int
106 setterm(char *type)
107 {
108 	static char __ttytype[128], cm_buff[1024], tc[1024], *tcptr;
109 	int unknown;
110 	size_t limit;
111 	struct winsize win;
112 	char *p;
113 
114 #ifdef DEBUG
115 	__CTRACE("setterm: (\"%s\")\nLINES = %d, COLS = %d\n",
116 	    type, LINES, COLS);
117 #endif
118 	if (type[0] == '\0')
119 		type = "xx";
120 	unknown = 0;
121 	if (t_getent(&_cursesi_genbuf, type) != 1) {
122 		unknown++;
123 	}
124 #ifdef DEBUG
125 	__CTRACE("setterm: tty = %s\n", type);
126 #endif
127 
128 	/* Try TIOCGWINSZ, and, if it fails, the termcap entry. */
129 	if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) != -1 &&
130 	    win.ws_row != 0 && win.ws_col != 0) {
131 		LINES = win.ws_row;
132 		COLS = win.ws_col;
133 	}  else {
134 		if (unknown) {
135 			LINES = -1;
136 			COLS = -1;
137 		} else {
138 			LINES = t_getnum(_cursesi_genbuf, "li");
139 			COLS = t_getnum(_cursesi_genbuf, "co");
140 		}
141 
142 	}
143 
144 	/* POSIX 1003.2 requires that the environment override. */
145 	if ((p = getenv("LINES")) != NULL)
146 		LINES = (int) strtol(p, NULL, 10);
147 	if ((p = getenv("COLUMNS")) != NULL)
148 		COLS = (int) strtol(p, NULL, 10);
149 
150 	/*
151 	 * Want cols > 4, otherwise things will fail.
152 	 */
153 	if (COLS <= 4)
154 		return (ERR);
155 
156 #ifdef DEBUG
157 	__CTRACE("setterm: LINES = %d, COLS = %d\n", LINES, COLS);
158 #endif
159 	if (!unknown) {
160 		if (zap(_cursesi_genbuf) == ERR) /* Get terminal description.*/
161 			return ERR;
162 	}
163 
164 	/* If we can't tab, we can't backtab, either. */
165 	if (!GT)
166 		BT = NULL;
167 
168 	/*
169 	 * Test for cursor motion capability.
170 	 *
171 	 */
172 	if (t_goto(NULL, CM, 0, 0, cm_buff, 1023) < 0) {
173 		CA = 0;
174 		CM = 0;
175 	} else
176 		CA = 1;
177 
178 	PC = _PC ? _PC[0] : 0;
179 	aoftspace = tspace;
180 	if (unknown) {
181 		strcpy(ttytype, "dumb");
182 	} else {
183 		tcptr = tc;
184 		limit = 1023;
185 		if (t_getterm(_cursesi_genbuf, &tcptr, &limit) < 0)
186 			return ERR;
187 		ttytype = __longname(tc, __ttytype);
188 	}
189 
190 	/* If no scrolling commands, no quick change. */
191 	__noqch =
192   	    (CS == NULL || HO == NULL ||
193 	    (SF == NULL && sf == NULL) || (SR == NULL && sr == NULL)) &&
194 	    ((AL == NULL && al == NULL) || (DL == NULL && dl == NULL));
195 
196 	/* Precalculate conflict info for color/attribute end commands. */
197 	__mask_OP = __ATTRIBUTES & ~__COLOR;
198 	if (OP != NULL) {
199 		if (SE != NULL && !strcmp(OP, SE))
200 			__mask_OP &= ~__STANDOUT;
201 		if (UE != NULL && !strcmp(OP, UE))
202 			__mask_OP &= ~__UNDERSCORE;
203 		if (ME != NULL && !strcmp(OP, ME))
204 			__mask_OP &= ~__TERMATTR;
205 	}
206 	__mask_ME = __ATTRIBUTES & ~__TERMATTR;
207 	if (ME != NULL) {
208 		if (SE != NULL && !strcmp(ME, SE))
209 			__mask_ME &= ~__STANDOUT;
210 		if (UE != NULL && !strcmp(ME, UE))
211 			__mask_ME &= ~__UNDERSCORE;
212 		if (OP != NULL && !strcmp(ME, OP))
213 			__mask_ME &= ~__COLOR;
214 	}
215 	__mask_UE = __ATTRIBUTES & ~__UNDERSCORE;
216 	if (UE != NULL) {
217 		if (SE != NULL && !strcmp(UE, SE))
218 			__mask_UE &= ~__STANDOUT;
219 		if (ME != NULL && !strcmp(UE, ME))
220 			__mask_UE &= ~__TERMATTR;
221 		if (OP != NULL && !strcmp(UE, OP))
222 			__mask_UE &= ~__COLOR;
223 	}
224 	__mask_SE = __ATTRIBUTES & ~__STANDOUT;
225 	if (SE != NULL) {
226 		if (UE != NULL && !strcmp(SE, UE))
227 			__mask_SE &= ~__UNDERSCORE;
228 		if (ME != NULL && !strcmp(SE, ME))
229 			__mask_SE &= ~__TERMATTR;
230 		if (OP != NULL && !strcmp(SE, OP))
231 			__mask_SE &= ~__COLOR;
232 	}
233 
234 	return (unknown ? ERR : OK);
235 }
236 
237 /*
238  * zap --
239  *	Gets all the terminal flags from the termcap database.
240  */
241 static int
242 zap(struct tinfo *tinfo)
243 {
244 	const char *nampstr, *namp;
245         char ***sp;
246 	int  **vp;
247 	char **fp;
248 	char tmp[3];
249 	size_t i;
250 #ifdef DEBUG
251 	char	*cp;
252 #endif
253 	tmp[2] = '\0';
254 
255 	namp = "amutbsccdaeohchlinmimsncnsosulxbxnxtxsxx";
256 	fp = sflags;
257 	do {
258 		*tmp = *namp;
259 		*(tmp + 1) = *(namp + 1);
260 		*(*fp++) = t_getflag(tinfo, tmp);
261 #ifdef DEBUG
262 		__CTRACE("%2.2s = %s\n", namp, *fp[-1] ? "TRUE" : "FALSE");
263 #endif
264 		namp += 2;
265 
266 	} while (*namp);
267 	namp = "paCoNC";
268 	vp = svals;
269 	do {
270 		*tmp = *namp;
271 		*(tmp + 1) = *(namp + 1);
272 		*(*vp++) = t_getnum(tinfo, tmp);
273 #ifdef DEBUG
274 		__CTRACE("%2.2s = %d\n", namp, *vp[-1]);
275 #endif
276 		namp += 2;
277 
278 	} while (*namp);
279 
280 	  /* calculate the size of tspace.... */
281 	nampstr = "acaeALasbcblbtcdceclcmcrcsdcDLdmdoeAedeik0k1k2k3k4k5k6k7k8k9hoicimipkdkekhklkrkskullmambmdmemhmkmmmompmrndnlocoppcprscseSFsospSRtatetiucueupusvbvivsveABAFaldlIcIpSbSfsfsrALDLUPDOLERI";
282 	namp = nampstr;
283 	tspace_size = 0;
284 	do {
285 		*tmp = *namp;
286 		*(tmp + 1) = *(namp + 1);
287 		t_getstr(tinfo, tmp, NULL, &i);
288 		tspace_size += i + 1;
289 		namp += 2;
290 	} while (*namp);
291 
292 	if ((tspace = (char *) malloc(tspace_size)) == NULL)
293 		return ERR;
294 #ifdef DEBUG
295 	__CTRACE("Allocated %d (0x%x) size buffer for tspace\n", tspace_size,
296 		 tspace_size);
297 #endif
298 	aoftspace = tspace;
299 
300 	namp = nampstr;
301 	sp = sstrs;
302 	do {
303 		*tmp = *namp;
304 		*(tmp + 1) = *(namp + 1);
305 		*(*sp++) = t_getstr(tinfo, tmp, &aoftspace, NULL);
306 #ifdef DEBUG
307 		__CTRACE("%2.2s = %s", namp, *sp[-1] == NULL ? "NULL\n" : "\"");
308 		if (*sp[-1] != NULL) {
309 			for (cp = *sp[-1]; *cp; cp++)
310 				__CTRACE("%s", unctrl(*cp));
311 			__CTRACE("\"\n");
312 		}
313 #endif
314 		namp += 2;
315 	} while (*namp);
316 	if (XS)
317 		SO = SE = NULL;
318 	else {
319 		if (t_getnum(tinfo, "sg") > 0)
320 			SO = NULL;
321 		if (t_getnum(tinfo, "ug") > 0)
322 			US = NULL;
323 		if (!SO && US) {
324 			SO = US;
325 			SE = UE;
326 		}
327 	}
328 
329 	return OK;
330 }
331 
332 /*
333  * getcap --
334  *	Return a capability from termcap.
335  */
336 char	*
337 getcap(char *name)
338 {
339 	size_t ent_size, offset;
340 	char *new_tspace;
341 
342 	  /* verify cap exists and grab size of it at the same time */
343 	t_getstr(_cursesi_genbuf, name, NULL, &ent_size);
344 
345 	  /* grow tspace to hold the new cap */
346 	if ((new_tspace = realloc(tspace, ent_size + tspace_size)) == NULL)
347 		return NULL;
348 
349 	  /* point aoftspace to the same place in the newly allocated buffer */
350 	offset = aoftspace - tspace;
351 	tspace = new_tspace + offset;
352 
353 	return (t_getstr(_cursesi_genbuf, name, &aoftspace, NULL));
354 }
355