1/**************************************************************************** 2 * Copyright (c) 1998-2007,2008 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 * * 34 * some of the code in here was contributed by: * 35 * Magnus Bengtsson, d6mbeng@dtek.chalmers.se (Nov'93) * 36 * (but it has changed a lot) * 37 ****************************************************************************/ 38 39#define __INTERNAL_CAPS_VISIBLE 40#include <curses.priv.h> 41 42#include <termcap.h> 43#include <tic.h> 44#include <ctype.h> 45 46#include <term_entry.h> 47 48MODULE_ID("$Id: lib_termcap.c,v 1.63 2008/08/16 19:22:55 tom Exp $") 49 50NCURSES_EXPORT_VAR(char *) UP = 0; 51NCURSES_EXPORT_VAR(char *) BC = 0; 52 53#define MyCache _nc_globals.tgetent_cache 54#define CacheInx _nc_globals.tgetent_index 55#define CacheSeq _nc_globals.tgetent_sequence 56 57#define FIX_SGR0 MyCache[CacheInx].fix_sgr0 58#define LAST_TRM MyCache[CacheInx].last_term 59#define LAST_BUF MyCache[CacheInx].last_bufp 60#define LAST_USE MyCache[CacheInx].last_used 61#define LAST_SEQ MyCache[CacheInx].sequence 62 63/*************************************************************************** 64 * 65 * tgetent(bufp, term) 66 * 67 * In termcap, this function reads in the entry for terminal `term' into the 68 * buffer pointed to by bufp. It must be called before any of the functions 69 * below are called. 70 * In this terminfo emulation, tgetent() simply calls setupterm() (which 71 * does a bit more than tgetent() in termcap does), and returns its return 72 * value (1 if successful, 0 if no terminal with the given name could be 73 * found, or -1 if no terminal descriptions have been installed on the 74 * system). The bufp argument is ignored. 75 * 76 ***************************************************************************/ 77 78NCURSES_EXPORT(int) 79tgetent(char *bufp, const char *name) 80{ 81 int errcode; 82 int n; 83 bool found_cache = FALSE; 84 85 START_TRACE(); 86 T((T_CALLED("tgetent()"))); 87 88 _nc_setupterm((NCURSES_CONST char *) name, STDOUT_FILENO, &errcode, TRUE); 89 90 /* 91 * In general we cannot tell if the fixed sgr0 is still used by the 92 * caller, but if tgetent() is called with the same buffer, that is 93 * good enough, since the previous data would be invalidated by the 94 * current call. 95 * 96 * bufp may be a null pointer, e.g., GNU termcap. That allocates data, 97 * which is good until the next tgetent() call. The conventional termcap 98 * is inconvenient because of the fixed buffer size, but because it uses 99 * caller-supplied buffers, can have multiple terminal descriptions in 100 * use at a given time. 101 */ 102 for (n = 0; n < TGETENT_MAX; ++n) { 103 bool same_result = (MyCache[n].last_used && MyCache[n].last_bufp == bufp); 104 if (same_result) { 105 CacheInx = n; 106 if (FIX_SGR0 != 0) { 107 FreeAndNull(FIX_SGR0); 108 } 109 /* 110 * Also free the terminfo data that we loaded (much bigger leak). 111 */ 112 if (LAST_TRM != 0 && LAST_TRM != cur_term) { 113 TERMINAL *trm = LAST_TRM; 114 del_curterm(LAST_TRM); 115 for (CacheInx = 0; CacheInx < TGETENT_MAX; ++CacheInx) 116 if (LAST_TRM == trm) 117 LAST_TRM = 0; 118 CacheInx = n; 119 } 120 found_cache = TRUE; 121 break; 122 } 123 } 124 if (!found_cache) { 125 int best = 0; 126 127 for (CacheInx = 0; CacheInx < TGETENT_MAX; ++CacheInx) { 128 if (LAST_SEQ < MyCache[best].sequence) { 129 best = CacheInx; 130 } 131 } 132 CacheInx = best; 133 } 134 LAST_TRM = cur_term; 135 LAST_SEQ = ++CacheSeq; 136 137 PC = 0; 138 UP = 0; 139 BC = 0; 140 FIX_SGR0 = 0; /* don't free it - application may still use */ 141 142 if (errcode == 1) { 143 144 if (cursor_left) 145 if ((backspaces_with_bs = (char) !strcmp(cursor_left, "\b")) == 0) 146 backspace_if_not_bs = cursor_left; 147 148 /* we're required to export these */ 149 if (pad_char != NULL) 150 PC = pad_char[0]; 151 if (cursor_up != NULL) 152 UP = cursor_up; 153 if (backspace_if_not_bs != NULL) 154 BC = backspace_if_not_bs; 155 156 if ((FIX_SGR0 = _nc_trim_sgr0(&(cur_term->type))) != 0) { 157 if (!strcmp(FIX_SGR0, exit_attribute_mode)) { 158 if (FIX_SGR0 != exit_attribute_mode) { 159 free(FIX_SGR0); 160 } 161 FIX_SGR0 = 0; 162 } 163 } 164 LAST_BUF = bufp; 165 LAST_USE = TRUE; 166 167 SetNoPadding(SP); 168 (void) baudrate(); /* sets ospeed as a side-effect */ 169 170/* LINT_PREPRO 171#if 0*/ 172#include <capdefaults.c> 173/* LINT_PREPRO 174#endif*/ 175 176 } 177 returnCode(errcode); 178} 179 180/*************************************************************************** 181 * 182 * tgetflag(str) 183 * 184 * Look up boolean termcap capability str and return its value (TRUE=1 if 185 * present, FALSE=0 if not). 186 * 187 ***************************************************************************/ 188 189NCURSES_EXPORT(int) 190tgetflag(NCURSES_CONST char *id) 191{ 192 unsigned i; 193 194 T((T_CALLED("tgetflag(%s)"), id)); 195 if (cur_term != 0) { 196 TERMTYPE *tp = &(cur_term->type); 197 for_each_boolean(i, tp) { 198 const char *capname = ExtBoolname(tp, i, boolcodes); 199 if (!strncmp(id, capname, 2)) { 200 /* setupterm forces invalid booleans to false */ 201 returnCode(tp->Booleans[i]); 202 } 203 } 204 } 205 returnCode(0); /* Solaris does this */ 206} 207 208/*************************************************************************** 209 * 210 * tgetnum(str) 211 * 212 * Look up numeric termcap capability str and return its value, or -1 if 213 * not given. 214 * 215 ***************************************************************************/ 216 217NCURSES_EXPORT(int) 218tgetnum(NCURSES_CONST char *id) 219{ 220 unsigned i; 221 222 T((T_CALLED("tgetnum(%s)"), id)); 223 if (cur_term != 0) { 224 TERMTYPE *tp = &(cur_term->type); 225 for_each_number(i, tp) { 226 const char *capname = ExtNumname(tp, i, numcodes); 227 if (!strncmp(id, capname, 2)) { 228 if (!VALID_NUMERIC(tp->Numbers[i])) 229 returnCode(ABSENT_NUMERIC); 230 returnCode(tp->Numbers[i]); 231 } 232 } 233 } 234 returnCode(ABSENT_NUMERIC); 235} 236 237/*************************************************************************** 238 * 239 * tgetstr(str, area) 240 * 241 * Look up string termcap capability str and return a pointer to its value, 242 * or NULL if not given. 243 * 244 ***************************************************************************/ 245 246NCURSES_EXPORT(char *) 247tgetstr(NCURSES_CONST char *id, char **area) 248{ 249 unsigned i; 250 char *result = NULL; 251 252 T((T_CALLED("tgetstr(%s,%p)"), id, area)); 253 if (cur_term != 0) { 254 TERMTYPE *tp = &(cur_term->type); 255 for_each_string(i, tp) { 256 const char *capname = ExtStrname(tp, i, strcodes); 257 if (!strncmp(id, capname, 2)) { 258 result = tp->Strings[i]; 259 TR(TRACE_DATABASE, ("found match : %s", _nc_visbuf(result))); 260 /* setupterm forces canceled strings to null */ 261 if (VALID_STRING(result)) { 262 if (result == exit_attribute_mode 263 && FIX_SGR0 != 0) { 264 result = FIX_SGR0; 265 TR(TRACE_DATABASE, ("altered to : %s", _nc_visbuf(result))); 266 } 267 if (area != 0 268 && *area != 0) { 269 (void) strcpy(*area, result); 270 result = *area; 271 *area += strlen(*area) + 1; 272 } 273 } 274 break; 275 } 276 } 277 } 278 returnPtr(result); 279} 280 281#if NO_LEAKS 282NCURSES_EXPORT(void) 283_nc_tgetent_leaks(void) 284{ 285 for (CacheInx = 0; CacheInx < TGETENT_MAX; ++CacheInx) { 286 FreeIfNeeded(FIX_SGR0); 287 if (LAST_TRM != 0) 288 del_curterm(LAST_TRM); 289 } 290} 291#endif 292