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