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