lib_termcap.c revision 302408
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: stable/11/contrib/ncurses/ncurses/tinfo/lib_termcap.c 262685 2014-03-02 08:58:21Z 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.80 2013/06/08 16:48:47 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 * 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
96NCURSES_EXPORT(int)
97NCURSES_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
219NCURSES_EXPORT(int)
220tgetent(char *bufp, const char *name)
221{
222    return NCURSES_SP_NAME(tgetent) (CURRENT_SCREEN, bufp, name);
223}
224#endif
225
226#if 0
227static bool
228same_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
248NCURSES_EXPORT(int)
249NCURSES_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
284NCURSES_EXPORT(int)
285tgetflag(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
300NCURSES_EXPORT(int)
301NCURSES_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
336NCURSES_EXPORT(int)
337tgetnum(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
352NCURSES_EXPORT(char *)
353NCURSES_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
402NCURSES_EXPORT(char *)
403tgetstr(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
410NCURSES_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