1 /**************************************************************************** 2 * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. * 3 * * 4 * Permission is hereby granted, free of charge, to any person obtaining a * 5 * copy of this software and associated documentation files (the * 6 * "Software"), to deal in the Software without restriction, including * 7 * without limitation the rights to use, copy, modify, merge, publish, * 8 * distribute, distribute with modifications, sublicense, and/or sell * 9 * copies of the Software, and to permit persons to whom the Software is * 10 * furnished to do so, subject to the following conditions: * 11 * * 12 * The above copyright notice and this permission notice shall be included * 13 * in all copies or substantial portions of the Software. * 14 * * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 22 * * 23 * Except as contained in this notice, the name(s) of the above copyright * 24 * holders shall not be used in advertising or otherwise to promote the * 25 * sale, use or other dealings in this Software without prior written * 26 * authorization. * 27 ****************************************************************************/ 28 29 /**************************************************************************** 30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 31 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32 * and: Thomas E. Dickey 1996-on * 33 * and: Juergen Pfeifer * 34 * * 35 * some of the code in here was contributed by: * 36 * Magnus Bengtsson, d6mbeng@dtek.chalmers.se (Nov'93) * 37 * (but it has changed a lot) * 38 ****************************************************************************/ 39 40 #define __INTERNAL_CAPS_VISIBLE 41 #include <curses.priv.h> 42 43 #include <termcap.h> 44 #include <tic.h> 45 #include <ctype.h> 46 47 #ifndef CUR 48 #define CUR SP_TERMTYPE 49 #endif 50 51 MODULE_ID("$Id: lib_termcap.c,v 1.80 2013/06/08 16:48:47 tom Exp $") 52 53 NCURSES_EXPORT_VAR(char *) UP = 0; 54 NCURSES_EXPORT_VAR(char *) BC = 0; 55 56 #define MyCache _nc_globals.tgetent_cache 57 #define CacheInx _nc_globals.tgetent_index 58 #define CacheSeq _nc_globals.tgetent_sequence 59 60 #define FIX_SGR0 MyCache[CacheInx].fix_sgr0 61 #define LAST_TRM MyCache[CacheInx].last_term 62 #define LAST_BUF MyCache[CacheInx].last_bufp 63 #define LAST_USE MyCache[CacheInx].last_used 64 #define LAST_SEQ MyCache[CacheInx].sequence 65 66 /* 67 * Termcap names are matched only using the first two bytes. 68 * Ignore any extended names longer than two bytes, to avoid problems 69 * with legacy code which passes in parameters whose use is long forgotten. 70 */ 71 #define ValidCap(cap) (((cap)[0] != '\0') && ((cap)[1] != '\0')) 72 #define SameCap(a,b) (((a)[0] == (b)[0]) && ((a)[1] == (b)[1])) 73 #define ValidExt(ext) (ValidCap(ext) && (ext)[2] == '\0') 74 75 /*************************************************************************** 76 * 77 * tgetent(bufp, term) 78 * 79 * In termcap, this function reads in the entry for terminal `term' into the 80 * buffer pointed to by bufp. It must be called before any of the functions 81 * below are called. 82 * In this terminfo emulation, tgetent() simply calls setupterm() (which 83 * does a bit more than tgetent() in termcap does), and returns its return 84 * value (1 if successful, 0 if no terminal with the given name could be 85 * found, or -1 if no terminal descriptions have been installed on the 86 * system). The bufp argument is ignored. 87 * 88 ***************************************************************************/ 89 90 NCURSES_EXPORT(int) 91 NCURSES_SP_NAME(tgetent) (NCURSES_SP_DCLx char *bufp, const char *name) 92 { 93 int rc = ERR; 94 int n; 95 bool found_cache = FALSE; 96 #ifdef USE_TERM_DRIVER 97 TERMINAL *termp = 0; 98 #endif 99 100 START_TRACE(); 101 T((T_CALLED("tgetent()"))); 102 103 TINFO_SETUP_TERM(&termp, (NCURSES_CONST char *) name, 104 STDOUT_FILENO, &rc, TRUE); 105 106 #ifdef USE_TERM_DRIVER 107 if (termp == 0 || 108 !((TERMINAL_CONTROL_BLOCK *) termp)->drv->isTerminfo) 109 returnCode(rc); 110 #endif 111 112 /* 113 * In general we cannot tell if the fixed sgr0 is still used by the 114 * caller, but if tgetent() is called with the same buffer, that is 115 * good enough, since the previous data would be invalidated by the 116 * current call. 117 * 118 * bufp may be a null pointer, e.g., GNU termcap. That allocates data, 119 * which is good until the next tgetent() call. The conventional termcap 120 * is inconvenient because of the fixed buffer size, but because it uses 121 * caller-supplied buffers, can have multiple terminal descriptions in 122 * use at a given time. 123 */ 124 for (n = 0; n < TGETENT_MAX; ++n) { 125 bool same_result = (MyCache[n].last_used && MyCache[n].last_bufp == bufp); 126 if (same_result) { 127 CacheInx = n; 128 if (FIX_SGR0 != 0) { 129 FreeAndNull(FIX_SGR0); 130 } 131 /* 132 * Also free the terminfo data that we loaded (much bigger leak). 133 */ 134 if (LAST_TRM != 0 && LAST_TRM != TerminalOf(SP_PARM)) { 135 TERMINAL *trm = LAST_TRM; 136 NCURSES_SP_NAME(del_curterm) (NCURSES_SP_ARGx LAST_TRM); 137 for (CacheInx = 0; CacheInx < TGETENT_MAX; ++CacheInx) 138 if (LAST_TRM == trm) 139 LAST_TRM = 0; 140 CacheInx = n; 141 } 142 found_cache = TRUE; 143 break; 144 } 145 } 146 if (!found_cache) { 147 int best = 0; 148 149 for (CacheInx = 0; CacheInx < TGETENT_MAX; ++CacheInx) { 150 if (LAST_SEQ < MyCache[best].sequence) { 151 best = CacheInx; 152 } 153 } 154 CacheInx = best; 155 } 156 LAST_TRM = TerminalOf(SP_PARM); 157 LAST_SEQ = ++CacheSeq; 158 159 PC = 0; 160 UP = 0; 161 BC = 0; 162 FIX_SGR0 = 0; /* don't free it - application may still use */ 163 164 if (rc == 1) { 165 166 if (cursor_left) 167 if ((backspaces_with_bs = (char) !strcmp(cursor_left, "\b")) == 0) 168 backspace_if_not_bs = cursor_left; 169 170 /* we're required to export these */ 171 if (pad_char != NULL) 172 PC = pad_char[0]; 173 if (cursor_up != NULL) 174 UP = cursor_up; 175 if (backspace_if_not_bs != NULL) 176 BC = backspace_if_not_bs; 177 178 if ((FIX_SGR0 = _nc_trim_sgr0(&(TerminalOf(SP_PARM)->type))) != 0) { 179 if (!strcmp(FIX_SGR0, exit_attribute_mode)) { 180 if (FIX_SGR0 != exit_attribute_mode) { 181 free(FIX_SGR0); 182 } 183 FIX_SGR0 = 0; 184 } 185 } 186 LAST_BUF = bufp; 187 LAST_USE = TRUE; 188 189 SetNoPadding(SP_PARM); 190 (void) NCURSES_SP_NAME(baudrate) (NCURSES_SP_ARG); /* sets ospeed as a side-effect */ 191 192 /* LINT_PREPRO 193 #if 0*/ 194 #include <capdefaults.c> 195 /* LINT_PREPRO 196 #endif*/ 197 198 } 199 returnCode(rc); 200 } 201 202 #if NCURSES_SP_FUNCS 203 NCURSES_EXPORT(int) 204 tgetent(char *bufp, const char *name) 205 { 206 return NCURSES_SP_NAME(tgetent) (CURRENT_SCREEN, bufp, name); 207 } 208 #endif 209 210 #if 0 211 static bool 212 same_tcname(const char *a, const char *b) 213 { 214 bool code = SameCap(a, b); 215 fprintf(stderr, "compare(%s,%s) %s\n", a, b, code ? "same" : "diff"); 216 return code; 217 } 218 219 #else 220 #define same_tcname(a,b) SameCap(a,b) 221 #endif 222 223 /*************************************************************************** 224 * 225 * tgetflag(str) 226 * 227 * Look up boolean termcap capability str and return its value (TRUE=1 if 228 * present, FALSE=0 if not). 229 * 230 ***************************************************************************/ 231 232 NCURSES_EXPORT(int) 233 NCURSES_SP_NAME(tgetflag) (NCURSES_SP_DCLx NCURSES_CONST char *id) 234 { 235 int result = 0; /* Solaris returns zero for missing flag */ 236 int j = -1; 237 238 T((T_CALLED("tgetflag(%p, %s)"), (void *) SP_PARM, id)); 239 if (HasTInfoTerminal(SP_PARM) && ValidCap(id)) { 240 TERMTYPE *tp = &(TerminalOf(SP_PARM)->type); 241 struct name_table_entry const *entry_ptr; 242 243 entry_ptr = _nc_find_type_entry(id, BOOLEAN, TRUE); 244 if (entry_ptr != 0) { 245 j = entry_ptr->nte_index; 246 } 247 #if NCURSES_XNAMES 248 else { 249 int i; 250 for_each_ext_boolean(i, tp) { 251 const char *capname = ExtBoolname(tp, i, boolcodes); 252 if (same_tcname(id, capname) && ValidExt(capname)) { 253 j = i; 254 break; 255 } 256 } 257 } 258 #endif 259 if (j >= 0) { 260 /* note: setupterm forces invalid booleans to false */ 261 result = tp->Booleans[j]; 262 } 263 } 264 returnCode(result); 265 } 266 267 #if NCURSES_SP_FUNCS 268 NCURSES_EXPORT(int) 269 tgetflag(NCURSES_CONST char *id) 270 { 271 return NCURSES_SP_NAME(tgetflag) (CURRENT_SCREEN, id); 272 } 273 #endif 274 275 /*************************************************************************** 276 * 277 * tgetnum(str) 278 * 279 * Look up numeric termcap capability str and return its value, or -1 if 280 * not given. 281 * 282 ***************************************************************************/ 283 284 NCURSES_EXPORT(int) 285 NCURSES_SP_NAME(tgetnum) (NCURSES_SP_DCLx NCURSES_CONST char *id) 286 { 287 int result = ABSENT_NUMERIC; 288 int j = -1; 289 290 T((T_CALLED("tgetnum(%p, %s)"), (void *) SP_PARM, id)); 291 if (HasTInfoTerminal(SP_PARM) && ValidCap(id)) { 292 TERMTYPE *tp = &(TerminalOf(SP_PARM)->type); 293 struct name_table_entry const *entry_ptr; 294 295 entry_ptr = _nc_find_type_entry(id, NUMBER, TRUE); 296 if (entry_ptr != 0) { 297 j = entry_ptr->nte_index; 298 } 299 #if NCURSES_XNAMES 300 else { 301 int i; 302 for_each_ext_number(i, tp) { 303 const char *capname = ExtNumname(tp, i, numcodes); 304 if (same_tcname(id, capname) && ValidExt(capname)) { 305 j = i; 306 break; 307 } 308 } 309 } 310 #endif 311 if (j >= 0) { 312 if (VALID_NUMERIC(tp->Numbers[j])) 313 result = tp->Numbers[j]; 314 } 315 } 316 returnCode(result); 317 } 318 319 #if NCURSES_SP_FUNCS 320 NCURSES_EXPORT(int) 321 tgetnum(NCURSES_CONST char *id) 322 { 323 return NCURSES_SP_NAME(tgetnum) (CURRENT_SCREEN, id); 324 } 325 #endif 326 327 /*************************************************************************** 328 * 329 * tgetstr(str, area) 330 * 331 * Look up string termcap capability str and return a pointer to its value, 332 * or NULL if not given. 333 * 334 ***************************************************************************/ 335 336 NCURSES_EXPORT(char *) 337 NCURSES_SP_NAME(tgetstr) (NCURSES_SP_DCLx NCURSES_CONST char *id, char **area) 338 { 339 char *result = NULL; 340 int j = -1; 341 342 T((T_CALLED("tgetstr(%s,%p)"), id, (void *) area)); 343 if (HasTInfoTerminal(SP_PARM) && ValidCap(id)) { 344 TERMTYPE *tp = &(TerminalOf(SP_PARM)->type); 345 struct name_table_entry const *entry_ptr; 346 347 entry_ptr = _nc_find_type_entry(id, STRING, TRUE); 348 if (entry_ptr != 0) { 349 j = entry_ptr->nte_index; 350 } 351 #if NCURSES_XNAMES 352 else { 353 int i; 354 for_each_ext_string(i, tp) { 355 const char *capname = ExtStrname(tp, i, strcodes); 356 if (same_tcname(id, capname) && ValidExt(capname)) { 357 j = i; 358 break; 359 } 360 } 361 } 362 #endif 363 if (j >= 0) { 364 result = tp->Strings[j]; 365 TR(TRACE_DATABASE, ("found match %d: %s", j, _nc_visbuf(result))); 366 /* setupterm forces canceled strings to null */ 367 if (VALID_STRING(result)) { 368 if (result == exit_attribute_mode 369 && FIX_SGR0 != 0) { 370 result = FIX_SGR0; 371 TR(TRACE_DATABASE, ("altered to : %s", _nc_visbuf(result))); 372 } 373 if (area != 0 374 && *area != 0) { 375 _nc_STRCPY(*area, result, 1024); 376 result = *area; 377 *area += strlen(*area) + 1; 378 } 379 } 380 } 381 } 382 returnPtr(result); 383 } 384 385 #if NCURSES_SP_FUNCS 386 NCURSES_EXPORT(char *) 387 tgetstr(NCURSES_CONST char *id, char **area) 388 { 389 return NCURSES_SP_NAME(tgetstr) (CURRENT_SCREEN, id, area); 390 } 391 #endif 392 393 #if NO_LEAKS 394 NCURSES_EXPORT(void) 395 _nc_tgetent_leaks(void) 396 { 397 for (CacheInx = 0; CacheInx < TGETENT_MAX; ++CacheInx) { 398 FreeIfNeeded(FIX_SGR0); 399 if (LAST_TRM != 0) 400 del_curterm(LAST_TRM); 401 } 402 } 403 #endif 404