1 /**************************************************************************** 2 * Copyright (c) 1998-2009,2010 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.73 2010/12/25 19:27:12 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 * 68 * tgetent(bufp, term) 69 * 70 * In termcap, this function reads in the entry for terminal `term' into the 71 * buffer pointed to by bufp. It must be called before any of the functions 72 * below are called. 73 * In this terminfo emulation, tgetent() simply calls setupterm() (which 74 * does a bit more than tgetent() in termcap does), and returns its return 75 * value (1 if successful, 0 if no terminal with the given name could be 76 * found, or -1 if no terminal descriptions have been installed on the 77 * system). The bufp argument is ignored. 78 * 79 ***************************************************************************/ 80 81 NCURSES_EXPORT(int) 82 NCURSES_SP_NAME(tgetent) (NCURSES_SP_DCLx char *bufp, const char *name) 83 { 84 int rc = ERR; 85 int n; 86 bool found_cache = FALSE; 87 #ifdef USE_TERM_DRIVER 88 TERMINAL *termp = 0; 89 #endif 90 91 START_TRACE(); 92 T((T_CALLED("tgetent()"))); 93 94 TINFO_SETUP_TERM(&termp, (NCURSES_CONST char *) name, 95 STDOUT_FILENO, &rc, TRUE); 96 97 #ifdef USE_TERM_DRIVER 98 if (termp == 0 || 99 !((TERMINAL_CONTROL_BLOCK *) termp)->drv->isTerminfo) 100 return (rc); 101 #endif 102 103 /* 104 * In general we cannot tell if the fixed sgr0 is still used by the 105 * caller, but if tgetent() is called with the same buffer, that is 106 * good enough, since the previous data would be invalidated by the 107 * current call. 108 * 109 * bufp may be a null pointer, e.g., GNU termcap. That allocates data, 110 * which is good until the next tgetent() call. The conventional termcap 111 * is inconvenient because of the fixed buffer size, but because it uses 112 * caller-supplied buffers, can have multiple terminal descriptions in 113 * use at a given time. 114 */ 115 for (n = 0; n < TGETENT_MAX; ++n) { 116 bool same_result = (MyCache[n].last_used && MyCache[n].last_bufp == bufp); 117 if (same_result) { 118 CacheInx = n; 119 if (FIX_SGR0 != 0) { 120 FreeAndNull(FIX_SGR0); 121 } 122 /* 123 * Also free the terminfo data that we loaded (much bigger leak). 124 */ 125 if (LAST_TRM != 0 && LAST_TRM != TerminalOf(SP_PARM)) { 126 TERMINAL *trm = LAST_TRM; 127 NCURSES_SP_NAME(del_curterm) (NCURSES_SP_ARGx LAST_TRM); 128 for (CacheInx = 0; CacheInx < TGETENT_MAX; ++CacheInx) 129 if (LAST_TRM == trm) 130 LAST_TRM = 0; 131 CacheInx = n; 132 } 133 found_cache = TRUE; 134 break; 135 } 136 } 137 if (!found_cache) { 138 int best = 0; 139 140 for (CacheInx = 0; CacheInx < TGETENT_MAX; ++CacheInx) { 141 if (LAST_SEQ < MyCache[best].sequence) { 142 best = CacheInx; 143 } 144 } 145 CacheInx = best; 146 } 147 LAST_TRM = TerminalOf(SP_PARM); 148 LAST_SEQ = ++CacheSeq; 149 150 PC = 0; 151 UP = 0; 152 BC = 0; 153 FIX_SGR0 = 0; /* don't free it - application may still use */ 154 155 if (rc == 1) { 156 157 if (cursor_left) 158 if ((backspaces_with_bs = (char) !strcmp(cursor_left, "\b")) == 0) 159 backspace_if_not_bs = cursor_left; 160 161 /* we're required to export these */ 162 if (pad_char != NULL) 163 PC = pad_char[0]; 164 if (cursor_up != NULL) 165 UP = cursor_up; 166 if (backspace_if_not_bs != NULL) 167 BC = backspace_if_not_bs; 168 169 if ((FIX_SGR0 = _nc_trim_sgr0(&(TerminalOf(SP_PARM)->type))) != 0) { 170 if (!strcmp(FIX_SGR0, exit_attribute_mode)) { 171 if (FIX_SGR0 != exit_attribute_mode) { 172 free(FIX_SGR0); 173 } 174 FIX_SGR0 = 0; 175 } 176 } 177 LAST_BUF = bufp; 178 LAST_USE = TRUE; 179 180 SetNoPadding(SP_PARM); 181 (void) NCURSES_SP_NAME(baudrate) (NCURSES_SP_ARG); /* sets ospeed as a side-effect */ 182 183 /* LINT_PREPRO 184 #if 0*/ 185 #include <capdefaults.c> 186 /* LINT_PREPRO 187 #endif*/ 188 189 } 190 returnCode(rc); 191 } 192 193 #if NCURSES_SP_FUNCS 194 NCURSES_EXPORT(int) 195 tgetent(char *bufp, const char *name) 196 { 197 return NCURSES_SP_NAME(tgetent) (CURRENT_SCREEN, bufp, name); 198 } 199 #endif 200 201 #if 0 202 static bool 203 same_tcname(const char *a, const char *b) 204 { 205 fprintf(stderr, "compare(%s,%s)\n", a, b); 206 return !strncmp(a, b, 2); 207 } 208 #else 209 #define same_tcname(a,b) !strncmp(a,b,2) 210 #endif 211 212 /*************************************************************************** 213 * 214 * tgetflag(str) 215 * 216 * Look up boolean termcap capability str and return its value (TRUE=1 if 217 * present, FALSE=0 if not). 218 * 219 ***************************************************************************/ 220 221 NCURSES_EXPORT(int) 222 NCURSES_SP_NAME(tgetflag) (NCURSES_SP_DCLx NCURSES_CONST char *id) 223 { 224 int result = 0; /* Solaris returns zero for missing flag */ 225 int i, j; 226 227 T((T_CALLED("tgetflag(%p, %s)"), (void *) SP_PARM, id)); 228 if (HasTInfoTerminal(SP_PARM)) { 229 TERMTYPE *tp = &(TerminalOf(SP_PARM)->type); 230 struct name_table_entry const *entry_ptr; 231 232 entry_ptr = _nc_find_type_entry(id, BOOLEAN, TRUE); 233 if (entry_ptr != 0) { 234 j = entry_ptr->nte_index; 235 } 236 #if NCURSES_XNAMES 237 else { 238 j = -1; 239 for_each_ext_boolean(i, tp) { 240 const char *capname = ExtBoolname(tp, i, boolcodes); 241 if (same_tcname(id, capname)) { 242 j = i; 243 break; 244 } 245 } 246 } 247 #endif 248 if (j >= 0) { 249 /* note: setupterm forces invalid booleans to false */ 250 result = tp->Booleans[j]; 251 } 252 } 253 returnCode(result); 254 } 255 256 #if NCURSES_SP_FUNCS 257 NCURSES_EXPORT(int) 258 tgetflag(NCURSES_CONST char *id) 259 { 260 return NCURSES_SP_NAME(tgetflag) (CURRENT_SCREEN, id); 261 } 262 #endif 263 264 /*************************************************************************** 265 * 266 * tgetnum(str) 267 * 268 * Look up numeric termcap capability str and return its value, or -1 if 269 * not given. 270 * 271 ***************************************************************************/ 272 273 NCURSES_EXPORT(int) 274 NCURSES_SP_NAME(tgetnum) (NCURSES_SP_DCLx NCURSES_CONST char *id) 275 { 276 int result = ABSENT_NUMERIC; 277 int i, j; 278 279 T((T_CALLED("tgetnum(%p, %s)"), (void *) SP_PARM, id)); 280 if (HasTInfoTerminal(SP_PARM)) { 281 TERMTYPE *tp = &(TerminalOf(SP_PARM)->type); 282 struct name_table_entry const *entry_ptr; 283 284 entry_ptr = _nc_find_type_entry(id, NUMBER, TRUE); 285 if (entry_ptr != 0) { 286 j = entry_ptr->nte_index; 287 } 288 #if NCURSES_XNAMES 289 else { 290 j = -1; 291 for_each_ext_number(i, tp) { 292 const char *capname = ExtNumname(tp, i, numcodes); 293 if (same_tcname(id, capname)) { 294 j = i; 295 break; 296 } 297 } 298 } 299 #endif 300 if (j >= 0) { 301 if (VALID_NUMERIC(tp->Numbers[j])) 302 result = tp->Numbers[j]; 303 } 304 } 305 returnCode(result); 306 } 307 308 #if NCURSES_SP_FUNCS 309 NCURSES_EXPORT(int) 310 tgetnum(NCURSES_CONST char *id) 311 { 312 return NCURSES_SP_NAME(tgetnum) (CURRENT_SCREEN, id); 313 } 314 #endif 315 316 /*************************************************************************** 317 * 318 * tgetstr(str, area) 319 * 320 * Look up string termcap capability str and return a pointer to its value, 321 * or NULL if not given. 322 * 323 ***************************************************************************/ 324 325 NCURSES_EXPORT(char *) 326 NCURSES_SP_NAME(tgetstr) (NCURSES_SP_DCLx NCURSES_CONST char *id, char **area) 327 { 328 char *result = NULL; 329 int i, j; 330 331 T((T_CALLED("tgetstr(%s,%p)"), id, (void *) area)); 332 if (HasTInfoTerminal(SP_PARM)) { 333 TERMTYPE *tp = &(TerminalOf(SP_PARM)->type); 334 struct name_table_entry const *entry_ptr; 335 336 entry_ptr = _nc_find_type_entry(id, STRING, TRUE); 337 if (entry_ptr != 0) { 338 j = entry_ptr->nte_index; 339 } 340 #if NCURSES_XNAMES 341 else { 342 j = -1; 343 for_each_ext_string(i, tp) { 344 const char *capname = ExtStrname(tp, i, strcodes); 345 if (same_tcname(id, capname)) { 346 j = i; 347 break; 348 } 349 } 350 } 351 #endif 352 if (j >= 0) { 353 result = tp->Strings[j]; 354 TR(TRACE_DATABASE, ("found match : %s", _nc_visbuf(result))); 355 /* setupterm forces canceled strings to null */ 356 if (VALID_STRING(result)) { 357 if (result == exit_attribute_mode 358 && FIX_SGR0 != 0) { 359 result = FIX_SGR0; 360 TR(TRACE_DATABASE, ("altered to : %s", _nc_visbuf(result))); 361 } 362 if (area != 0 363 && *area != 0) { 364 (void) strcpy(*area, result); 365 result = *area; 366 *area += strlen(*area) + 1; 367 } 368 } 369 } 370 } 371 returnPtr(result); 372 } 373 374 #if NCURSES_SP_FUNCS 375 NCURSES_EXPORT(char *) 376 tgetstr(NCURSES_CONST char *id, char **area) 377 { 378 return NCURSES_SP_NAME(tgetstr) (CURRENT_SCREEN, id, area); 379 } 380 #endif 381 382 #if NO_LEAKS 383 NCURSES_EXPORT(void) 384 _nc_tgetent_leaks(void) 385 { 386 for (CacheInx = 0; CacheInx < TGETENT_MAX; ++CacheInx) { 387 FreeIfNeeded(FIX_SGR0); 388 if (LAST_TRM != 0) 389 del_curterm(LAST_TRM); 390 } 391 } 392 #endif 393