xref: /netbsd-src/lib/libcurses/setterm.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
1 /*	$NetBSD: setterm.c,v 1.28 2000/12/22 17:07:13 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.28 2000/12/22 17:07:13 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        bs        cc        da        eo  */
61 			&__tc_am, &__tc_bs, &__tc_cc, &__tc_da, &__tc_eo,
62 		/*	      hc        hl        in        mi        ms  */
63 			&__tc_hc, &__tc_hl, &__tc_in, &__tc_mi, &__tc_ms,
64 		/*	      nc        ns        os        ul        ut  */
65 			&__tc_nc, &__tc_ns, &__tc_os, &__tc_ul, &__tc_ut,
66 		/*	      xb        xn        xt        xs        xx  */
67 			&__tc_xb, &__tc_xn, &__tc_xt, &__tc_xs, &__tc_xx
68 		};
69 
70 static int	*svals[] = {
71 		/*	      pa        Co        NC  */
72 			&__tc_pa, &__tc_Co, &__tc_NC
73 		};
74 static char	*_PC,
75 		**sstrs[] = {
76 		/*	      AB        ac        ae        AF        AL  */
77 			&__tc_AB, &__tc_ac, &__tc_ae, &__tc_AF, &__tc_AL,
78 		/*	      al        as        bc        bl        bt  */
79 			&__tc_al, &__tc_as, &__tc_bc, &__tc_bl, &__tc_bt,
80 		/*	      cd        ce        cl        cm        cr  */
81 			&__tc_cd, &__tc_ce, &__tc_cl, &__tc_cm, &__tc_cr,
82 		/*	      cs        dc        DL        dl        dm  */
83 			&__tc_cs, &__tc_dc, &__tc_DL, &__tc_dl, &__tc_dm,
84 		/*	      DO        do        eA        ed        ei  */
85 			&__tc_DO, &__tc_do, &__tc_eA, &__tc_ed, &__tc_ei,
86 		/*	      ho        Ic        ic        im        Ip  */
87 			&__tc_ho, &__tc_Ic, &__tc_ic, &__tc_im, &__tc_Ip,
88 		/*	      ip        k0        k1        k2        k3  */
89 			&__tc_ip, &__tc_k0, &__tc_k1, &__tc_k2, &__tc_k3,
90 		/*	      k4        k5        k6        k7        k8  */
91 			&__tc_k4, &__tc_k5, &__tc_k6, &__tc_k7, &__tc_k8,
92 		/*	      k9        kd        ke        kh        kl  */
93 			&__tc_k9, &__tc_kd, &__tc_ke, &__tc_kh, &__tc_kl,
94 		/*	      kr        ks        ku        LE        ll  */
95 			&__tc_kr, &__tc_ks, &__tc_ku, &__tc_LE, &__tc_ll,
96 		/*	      ma        mb        md        me        mh  */
97 			&__tc_ma, &__tc_mb, &__tc_md, &__tc_me, &__tc_mh,
98 		/*	      mk        mm        mo        mp        mr  */
99 			&__tc_mk, &__tc_mm, &__tc_mo, &__tc_mp, &__tc_mr,
100 		/*	      nd        nl        oc        op    pc      */
101 			&__tc_nd, &__tc_nl, &__tc_oc, &__tc_op, &_PC,
102 		/*	      rc        RI        sc        Sb        se  */
103 			&__tc_rc, &__tc_RI, &__tc_Sb, &__tc_sc, &__tc_se,
104 		/*	      SF        Sf        sf        so        sp  */
105 			&__tc_SF, &__tc_Sf, &__tc_sf, &__tc_so, &__tc_sp,
106 		/*	      SR        sr        ta        te        ti  */
107 			&__tc_SR, &__tc_sr, &__tc_ta, &__tc_te, &__tc_ti,
108 		/*	      uc        ue        UP        up        us  */
109 			&__tc_uc, &__tc_ue, &__tc_UP, &__tc_up, &__tc_us,
110 		/*	      vb        ve        vi        vs            */
111 			&__tc_vb, &__tc_ve, &__tc_vi, &__tc_vs
112 		};
113 
114 static char	*aoftspace;		/* Address of _tspace for relocation */
115 static char	*tspace;		/* Space for capability strings */
116 static size_t   tspace_size;            /* size of tspace */
117 
118 char	*ttytype;
119 attr_t	 __mask_op, __mask_me, __mask_ue, __mask_se;
120 
121 int
122 setterm(char *type)
123 {
124 	static char __ttytype[128], cm_buff[1024], tc[1024], *tcptr;
125 	int unknown;
126 	size_t limit;
127 	struct winsize win;
128 	char *p;
129 
130 #ifdef DEBUG
131 	__CTRACE("setterm: (\"%s\")\nLINES = %d, COLS = %d\n",
132 	    type, LINES, COLS);
133 #endif
134 	if (type[0] == '\0')
135 		type = "xx";
136 	unknown = 0;
137 	if (t_getent(&_cursesi_genbuf, type) != 1) {
138 		unknown++;
139 	}
140 #ifdef DEBUG
141 	__CTRACE("setterm: tty = %s\n", type);
142 #endif
143 
144 	/* Try TIOCGWINSZ, and, if it fails, the termcap entry. */
145 	if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) != -1 &&
146 	    win.ws_row != 0 && win.ws_col != 0) {
147 		LINES = win.ws_row;
148 		COLS = win.ws_col;
149 	}  else {
150 		if (unknown) {
151 			LINES = -1;
152 			COLS = -1;
153 		} else {
154 			LINES = t_getnum(_cursesi_genbuf, "li");
155 			COLS = t_getnum(_cursesi_genbuf, "co");
156 		}
157 
158 	}
159 
160 	/* POSIX 1003.2 requires that the environment override. */
161 	if ((p = getenv("LINES")) != NULL)
162 		LINES = (int) strtol(p, NULL, 10);
163 	if ((p = getenv("COLUMNS")) != NULL)
164 		COLS = (int) strtol(p, NULL, 10);
165 
166 	/*
167 	 * Want cols > 4, otherwise things will fail.
168 	 */
169 	if (COLS <= 4)
170 		return (ERR);
171 
172 #ifdef DEBUG
173 	__CTRACE("setterm: LINES = %d, COLS = %d\n", LINES, COLS);
174 #endif
175 	if (!unknown) {
176 		if (zap(_cursesi_genbuf) == ERR) /* Get terminal description.*/
177 			return ERR;
178 	}
179 
180 	/* If we can't tab, we can't backtab, either. */
181 	if (!__GT)
182 		__tc_bt = NULL;
183 
184 	/*
185 	 * Test for cursor motion capability.
186 	 *
187 	 */
188 	if (t_goto(NULL, __tc_cm, 0, 0, cm_buff, 1023) < 0) {
189 		__CA = 0;
190 		__tc_cm = 0;
191 	} else
192 		__CA = 1;
193 
194 	PC = _PC ? _PC[0] : 0;
195 	aoftspace = tspace;
196 	if (unknown) {
197 		strcpy(ttytype, "dumb");
198 	} else {
199 		tcptr = tc;
200 		limit = 1023;
201 		if (t_getterm(_cursesi_genbuf, &tcptr, &limit) < 0)
202 			return ERR;
203 		ttytype = __longname(tc, __ttytype);
204 	}
205 
206 	/* If no scrolling commands, no quick change. */
207 	__noqch =
208   	    (__tc_cs == NULL || __tc_ho == NULL ||
209 	    (__tc_SF == NULL && __tc_sf == NULL) || (__tc_SR == NULL && __tc_sr == NULL)) &&
210 	    ((__tc_AL == NULL && __tc_al == NULL) || (__tc_DL == NULL && __tc_dl == NULL));
211 
212 	/* Precalculate conflict info for color/attribute end commands. */
213 	__mask_op = __ATTRIBUTES & ~__COLOR;
214 	if (__tc_op != NULL) {
215 		if (__tc_se != NULL && !strcmp(__tc_op, __tc_se))
216 			__mask_op &= ~__STANDOUT;
217 		if (__tc_ue != NULL && !strcmp(__tc_op, __tc_ue))
218 			__mask_op &= ~__UNDERSCORE;
219 		if (__tc_me != NULL && !strcmp(__tc_op, __tc_me))
220 			__mask_op &= ~__TERMATTR;
221 	}
222 	__mask_me = __ATTRIBUTES & ~__TERMATTR;
223 	if (__tc_me != NULL) {
224 		if (__tc_se != NULL && !strcmp(__tc_me, __tc_se))
225 			__mask_me &= ~__STANDOUT;
226 		if (__tc_ue != NULL && !strcmp(__tc_me, __tc_ue))
227 			__mask_me &= ~__UNDERSCORE;
228 		if (__tc_op != NULL && !strcmp(__tc_me, __tc_op))
229 			__mask_me &= ~__COLOR;
230 	}
231 	__mask_ue = __ATTRIBUTES & ~__UNDERSCORE;
232 	if (__tc_ue != NULL) {
233 		if (__tc_se != NULL && !strcmp(__tc_ue, __tc_se))
234 			__mask_ue &= ~__STANDOUT;
235 		if (__tc_me != NULL && !strcmp(__tc_ue, __tc_me))
236 			__mask_ue &= ~__TERMATTR;
237 		if (__tc_op != NULL && !strcmp(__tc_ue, __tc_op))
238 			__mask_ue &= ~__COLOR;
239 	}
240 	__mask_se = __ATTRIBUTES & ~__STANDOUT;
241 	if (__tc_se != NULL) {
242 		if (__tc_ue != NULL && !strcmp(__tc_se, __tc_ue))
243 			__mask_se &= ~__UNDERSCORE;
244 		if (__tc_me != NULL && !strcmp(__tc_se, __tc_me))
245 			__mask_se &= ~__TERMATTR;
246 		if (__tc_op != NULL && !strcmp(__tc_se, __tc_op))
247 			__mask_se &= ~__COLOR;
248 	}
249 
250 	return (unknown ? ERR : OK);
251 }
252 
253 /*
254  * zap --
255  *	Gets all the terminal flags from the termcap database.
256  */
257 static int
258 zap(struct tinfo *tinfo)
259 {
260 	const char *nampstr, *namp;
261         char ***sp;
262 	int  **vp;
263 	char **fp;
264 	char tmp[3];
265 	size_t i;
266 #ifdef DEBUG
267 	char	*cp;
268 #endif
269 	tmp[2] = '\0';
270 
271 	namp = "ambsccdaeohchlinmimsncnsosulutxbxnxtxsxx";
272 	fp = sflags;
273 	do {
274 		*tmp = *namp;
275 		*(tmp + 1) = *(namp + 1);
276 		*(*fp++) = t_getflag(tinfo, tmp);
277 #ifdef DEBUG
278 		__CTRACE("%2.2s = %s\n", namp, *fp[-1] ? "TRUE" : "FALSE");
279 #endif
280 		namp += 2;
281 
282 	} while (*namp);
283 	namp = "paCoNC";
284 	vp = svals;
285 	do {
286 		*tmp = *namp;
287 		*(tmp + 1) = *(namp + 1);
288 		*(*vp++) = t_getnum(tinfo, tmp);
289 #ifdef DEBUG
290 		__CTRACE("%2.2s = %d\n", namp, *vp[-1]);
291 #endif
292 		namp += 2;
293 
294 	} while (*namp);
295 
296 	  /* calculate the size of tspace.... */
297 	nampstr = "ABacaeAFALalasbcblbtcdceclcmcrcsdcDLdldmDOdoeAedeihoIcicimIpipk0k1k2k3k4k5k6k7k8k9kdkekhklkrkskuLEllmambmdmemhmkmmmompmrndnlocoppcrcRISbscseSFSfsfsospSRsrtatetiucueUPupusvbvevivs";
298 	namp = nampstr;
299 	tspace_size = 0;
300 	do {
301 		*tmp = *namp;
302 		*(tmp + 1) = *(namp + 1);
303 		t_getstr(tinfo, tmp, NULL, &i);
304 		tspace_size += i + 1;
305 		namp += 2;
306 	} while (*namp);
307 
308 	if ((tspace = (char *) malloc(tspace_size)) == NULL)
309 		return ERR;
310 #ifdef DEBUG
311 	__CTRACE("Allocated %d (0x%x) size buffer for tspace\n", tspace_size,
312 		 tspace_size);
313 #endif
314 	aoftspace = tspace;
315 
316 	namp = nampstr;
317 	sp = sstrs;
318 	do {
319 		*tmp = *namp;
320 		*(tmp + 1) = *(namp + 1);
321 		*(*sp++) = t_getstr(tinfo, tmp, &aoftspace, NULL);
322 #ifdef DEBUG
323 		__CTRACE("%2.2s = %s", namp, *sp[-1] == NULL ? "NULL\n" : "\"");
324 		if (*sp[-1] != NULL) {
325 			for (cp = *sp[-1]; *cp; cp++)
326 				__CTRACE("%s", unctrl(*cp));
327 			__CTRACE("\"\n");
328 		}
329 #endif
330 		namp += 2;
331 	} while (*namp);
332 	if (__tc_xs)
333 		__tc_so = __tc_se = NULL;
334 	else {
335 		if (t_getnum(tinfo, "sg") > 0)
336 			__tc_so = NULL;
337 		if (t_getnum(tinfo, "ug") > 0)
338 			__tc_us = NULL;
339 		if (!__tc_so && __tc_us) {
340 			__tc_so = __tc_us;
341 			__tc_se = __tc_ue;
342 		}
343 	}
344 
345 	return OK;
346 }
347 
348 /*
349  * getcap --
350  *	Return a capability from termcap.
351  */
352 char	*
353 getcap(char *name)
354 {
355 	size_t ent_size, offset;
356 	char *new_tspace;
357 
358 	  /* verify cap exists and grab size of it at the same time */
359 	t_getstr(_cursesi_genbuf, name, NULL, &ent_size);
360 
361 	  /* grow tspace to hold the new cap */
362 	if ((new_tspace = realloc(tspace, ent_size + tspace_size)) == NULL)
363 		return NULL;
364 
365 	  /* point aoftspace to the same place in the newly allocated buffer */
366 	offset = aoftspace - tspace;
367 	tspace = new_tspace + offset;
368 
369 	return (t_getstr(_cursesi_genbuf, name, &aoftspace, NULL));
370 }
371