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