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