150276Speter/****************************************************************************
2184989Srafan * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
3050276Speter *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
3150276Speter *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32166124Srafan *     and: Thomas E. Dickey                        1996-on                 *
3350276Speter ****************************************************************************/
3450276Speter
3550276Speter/*
3650276Speter *	read_entry.c -- Routine for reading in a compiled terminfo file
3750276Speter */
3850276Speter
3950276Speter#include <curses.priv.h>
40166124Srafan#include <hashed_db.h>
4150276Speter
4250276Speter#include <tic.h>
4350276Speter#include <term_entry.h>
4450276Speter
45184989SrafanMODULE_ID("$Id: read_entry.c,v 1.102 2008/08/03 19:33:04 tom Exp $")
4650276Speter
47166124Srafan#define TYPE_CALLOC(type,elts) typeCalloc(type, (unsigned)(elts))
4850276Speter
49166124Srafan#if USE_DATABASE
5062449Speterstatic void
5162449Speterconvert_shorts(char *buf, short *Numbers, int count)
5250276Speter{
5350276Speter    int i;
5462449Speter    for (i = 0; i < count; i++) {
5562449Speter	if (IS_NEG1(buf + 2 * i))
5650276Speter	    Numbers[i] = ABSENT_NUMERIC;
5762449Speter	else if (IS_NEG2(buf + 2 * i))
5850276Speter	    Numbers[i] = CANCELLED_NUMERIC;
5950276Speter	else
6062449Speter	    Numbers[i] = LOW_MSB(buf + 2 * i);
6162449Speter	TR(TRACE_DATABASE, ("get Numbers[%d]=%d", i, Numbers[i]));
6250276Speter    }
6350276Speter}
6450276Speter
6562449Speterstatic void
6662449Speterconvert_strings(char *buf, char **Strings, int count, int size, char *table)
6750276Speter{
6850276Speter    int i;
6950276Speter    char *p;
7050276Speter
7150276Speter    for (i = 0; i < count; i++) {
7262449Speter	if (IS_NEG1(buf + 2 * i)) {
7350276Speter	    Strings[i] = ABSENT_STRING;
7462449Speter	} else if (IS_NEG2(buf + 2 * i)) {
7550276Speter	    Strings[i] = CANCELLED_STRING;
76184989Srafan	} else if ((int) LOW_MSB(buf + 2 * i) > size) {
7750276Speter	    Strings[i] = ABSENT_STRING;
7850276Speter	} else {
7962449Speter	    Strings[i] = (LOW_MSB(buf + 2 * i) + table);
8062449Speter	    TR(TRACE_DATABASE, ("Strings[%d] = %s", i, _nc_visbuf(Strings[i])));
8150276Speter	}
8250276Speter
8350276Speter	/* make sure all strings are NUL terminated */
8450276Speter	if (VALID_STRING(Strings[i])) {
8550276Speter	    for (p = Strings[i]; p <= table + size; p++)
8650276Speter		if (*p == '\0')
8750276Speter		    break;
8850276Speter	    /* if there is no NUL, ignore the string */
8950276Speter	    if (p > table + size)
9050276Speter		Strings[i] = ABSENT_STRING;
9150276Speter	}
9250276Speter    }
9350276Speter}
9450276Speter
95166124Srafanstatic int
96166124Srafanfake_read(char *src, int *offset, int limit, char *dst, unsigned want)
97166124Srafan{
98166124Srafan    int have = (limit - *offset);
9950276Speter
100166124Srafan    if (have > 0) {
101166124Srafan	if ((int) want > have)
102166124Srafan	    want = have;
103166124Srafan	memcpy(dst, src + *offset, want);
104166124Srafan	*offset += want;
105166124Srafan    } else {
106166124Srafan	want = 0;
107166124Srafan    }
108166124Srafan    return (int) want;
109166124Srafan}
110166124Srafan
111166124Srafan#define Read(buf, count) fake_read(buffer, &offset, limit, buf, count)
112166124Srafan
113166124Srafan#define read_shorts(buf, count) \
114166124Srafan	(Read(buf, (unsigned) (count)*2) == (int) (count)*2)
115166124Srafan
11650276Speter#define even_boundary(value) \
117166124Srafan    if ((value) % 2 != 0) Read(buf, 1)
11850276Speter
119166124SrafanNCURSES_EXPORT(int)
120166124Srafan_nc_read_termtype(TERMTYPE *ptr, char *buffer, int limit)
12150276Speter/* return 1 if read, 0 if not found or garbled */
12250276Speter{
123166124Srafan    int offset = 0;
12462449Speter    int name_size, bool_count, num_count, str_count, str_size;
12562449Speter    int i;
126166124Srafan    char buf[MAX_ENTRY_SIZE + 1];
127166124Srafan    char *string_table;
128166124Srafan    unsigned want, have;
12950276Speter
130166124Srafan    TR(TRACE_DATABASE, ("READ termtype header @%d", offset));
13150276Speter
13262449Speter    memset(ptr, 0, sizeof(*ptr));
13362449Speter
13450276Speter    /* grab the header */
135166124Srafan    if (!read_shorts(buf, 6)
136166124Srafan	|| !IS_TIC_MAGIC(buf)) {
137166124Srafan	return (TGETENT_NO);
13850276Speter    }
13950276Speter
14062449Speter    name_size = LOW_MSB(buf + 2);
14150276Speter    bool_count = LOW_MSB(buf + 4);
14262449Speter    num_count = LOW_MSB(buf + 6);
14362449Speter    str_count = LOW_MSB(buf + 8);
14462449Speter    str_size = LOW_MSB(buf + 10);
14550276Speter
14662449Speter    TR(TRACE_DATABASE,
14766963Speter       ("TERMTYPE name_size=%d, bool=%d/%d, num=%d/%d str=%d/%d(%d)",
14866963Speter	name_size, bool_count, BOOLCOUNT, num_count, NUMCOUNT,
14966963Speter	str_count, STRCOUNT, str_size));
15062449Speter    if (name_size < 0
15162449Speter	|| bool_count < 0
15262449Speter	|| num_count < 0
15362449Speter	|| str_count < 0
15462449Speter	|| str_size < 0) {
155166124Srafan	return (TGETENT_NO);
15650276Speter    }
15750276Speter
158166124Srafan    want = str_size + name_size + 1;
15950276Speter    if (str_size) {
16050276Speter	/* try to allocate space for the string table */
16162449Speter	if (str_count * 2 >= (int) sizeof(buf)
162166124Srafan	    || (string_table = typeMalloc(char, want)) == 0) {
163166124Srafan	    return (TGETENT_NO);
16450276Speter	}
16550276Speter    } else {
16650276Speter	str_count = 0;
167166124Srafan	if ((string_table = typeMalloc(char, want)) == 0) {
168166124Srafan	    return (TGETENT_NO);
169166124Srafan	}
17050276Speter    }
17150276Speter
172166124Srafan    /* grab the name (a null-terminated string) */
173166124Srafan    want = min(MAX_NAME_SIZE, (unsigned) name_size);
174166124Srafan    ptr->str_table = string_table;
175166124Srafan    ptr->term_names = string_table;
176166124Srafan    if ((have = Read(ptr->term_names, want)) != want) {
177166124Srafan	memset(ptr->term_names + have, 0, want - have);
17850276Speter    }
179166124Srafan    ptr->term_names[want] = '\0';
180166124Srafan    string_table += (want + 1);
18150276Speter
182166124Srafan    if (have > MAX_NAME_SIZE)
183166124Srafan	offset = (have - MAX_NAME_SIZE);
184166124Srafan
18550276Speter    /* grab the booleans */
186166124Srafan    if ((ptr->Booleans = TYPE_CALLOC(NCURSES_SBOOL,
187166124Srafan				     max(BOOLCOUNT, bool_count))) == 0
188166124Srafan	|| Read(ptr->Booleans, (unsigned) bool_count) < bool_count) {
189166124Srafan	return (TGETENT_NO);
19050276Speter    }
19150276Speter
19250276Speter    /*
19350276Speter     * If booleans end on an odd byte, skip it.  The machine they
19450276Speter     * originally wrote terminfo on must have been a 16-bit
19550276Speter     * word-oriented machine that would trap out if you tried a
19650276Speter     * word access off a 2-byte boundary.
19750276Speter     */
19850276Speter    even_boundary(name_size + bool_count);
19950276Speter
20050276Speter    /* grab the numbers */
201166124Srafan    if ((ptr->Numbers = TYPE_CALLOC(short, max(NUMCOUNT, num_count))) == 0
202166124Srafan	|| !read_shorts(buf, num_count)) {
203166124Srafan	return (TGETENT_NO);
20450276Speter    }
20550276Speter    convert_shorts(buf, ptr->Numbers, num_count);
20650276Speter
207166124Srafan    if ((ptr->Strings = TYPE_CALLOC(char *, max(STRCOUNT, str_count))) == 0)
208166124Srafan	  return (TGETENT_NO);
20950276Speter
21062449Speter    if (str_count) {
21150276Speter	/* grab the string offsets */
212166124Srafan	if (!read_shorts(buf, str_count)) {
213166124Srafan	    return (TGETENT_NO);
21450276Speter	}
21550276Speter	/* finally, grab the string table itself */
216166124Srafan	if (Read(string_table, (unsigned) str_size) != str_size)
217166124Srafan	    return (TGETENT_NO);
218166124Srafan	convert_strings(buf, ptr->Strings, str_count, str_size, string_table);
21950276Speter    }
22050276Speter#if NCURSES_XNAMES
22150276Speter
22250276Speter    ptr->num_Booleans = BOOLCOUNT;
22362449Speter    ptr->num_Numbers = NUMCOUNT;
22462449Speter    ptr->num_Strings = STRCOUNT;
22550276Speter
22650276Speter    /*
22750276Speter     * Read extended entries, if any, after the normal end of terminfo data.
22850276Speter     */
22950276Speter    even_boundary(str_size);
230166124Srafan    TR(TRACE_DATABASE, ("READ extended_header @%d", offset));
231166124Srafan    if (_nc_user_definable && read_shorts(buf, 5)) {
23250276Speter	int ext_bool_count = LOW_MSB(buf + 0);
23362449Speter	int ext_num_count = LOW_MSB(buf + 2);
23462449Speter	int ext_str_count = LOW_MSB(buf + 4);
23562449Speter	int ext_str_size = LOW_MSB(buf + 6);
23662449Speter	int ext_str_limit = LOW_MSB(buf + 8);
237166124Srafan	unsigned need = (ext_bool_count + ext_num_count + ext_str_count);
23850276Speter	int base = 0;
23950276Speter
240166124Srafan	if (need >= sizeof(buf)
24162449Speter	    || ext_str_size >= (int) sizeof(buf)
24262449Speter	    || ext_str_limit >= (int) sizeof(buf)
24362449Speter	    || ext_bool_count < 0
24462449Speter	    || ext_num_count < 0
24562449Speter	    || ext_str_count < 0
24662449Speter	    || ext_str_size < 0
24762449Speter	    || ext_str_limit < 0)
248166124Srafan	    return (TGETENT_NO);
24950276Speter
25050276Speter	ptr->num_Booleans = BOOLCOUNT + ext_bool_count;
25162449Speter	ptr->num_Numbers = NUMCOUNT + ext_num_count;
25262449Speter	ptr->num_Strings = STRCOUNT + ext_str_count;
25350276Speter
254166124Srafan	ptr->Booleans = typeRealloc(NCURSES_SBOOL, ptr->num_Booleans, ptr->Booleans);
25550276Speter	ptr->Numbers = typeRealloc(short, ptr->num_Numbers, ptr->Numbers);
25662449Speter	ptr->Strings = typeRealloc(char *, ptr->num_Strings, ptr->Strings);
25750276Speter
25862449Speter	TR(TRACE_DATABASE, ("extended header is %d/%d/%d(%d:%d)",
25966963Speter			    ext_bool_count, ext_num_count, ext_str_count,
26066963Speter			    ext_str_size, ext_str_limit));
26150276Speter
26262449Speter	TR(TRACE_DATABASE, ("READ %d extended-booleans @%d",
263166124Srafan			    ext_bool_count, offset));
26450276Speter	if ((ptr->ext_Booleans = ext_bool_count) != 0) {
265166124Srafan	    if (Read(ptr->Booleans + BOOLCOUNT, (unsigned)
26666963Speter		     ext_bool_count) != ext_bool_count)
267166124Srafan		return (TGETENT_NO);
26850276Speter	}
26950276Speter	even_boundary(ext_bool_count);
27050276Speter
27162449Speter	TR(TRACE_DATABASE, ("READ %d extended-numbers @%d",
272166124Srafan			    ext_num_count, offset));
27350276Speter	if ((ptr->ext_Numbers = ext_num_count) != 0) {
274166124Srafan	    if (!read_shorts(buf, ext_num_count))
275166124Srafan		return (TGETENT_NO);
27662449Speter	    TR(TRACE_DATABASE, ("Before converting extended-numbers"));
27750276Speter	    convert_shorts(buf, ptr->Numbers + NUMCOUNT, ext_num_count);
27850276Speter	}
27950276Speter
280166124Srafan	TR(TRACE_DATABASE, ("READ extended-offsets @%d", offset));
28150276Speter	if ((ext_str_count || need)
282166124Srafan	    && !read_shorts(buf, ext_str_count + need))
283166124Srafan	    return (TGETENT_NO);
28450276Speter
28562449Speter	TR(TRACE_DATABASE, ("READ %d bytes of extended-strings @%d",
286166124Srafan			    ext_str_limit, offset));
28762449Speter
28850276Speter	if (ext_str_limit) {
28950276Speter	    if ((ptr->ext_str_table = typeMalloc(char, ext_str_limit)) == 0)
290166124Srafan		  return (TGETENT_NO);
291166124Srafan	    if (Read(ptr->ext_str_table, (unsigned) ext_str_limit) != ext_str_limit)
292166124Srafan		return (TGETENT_NO);
29362449Speter	    TR(TRACE_DATABASE, ("first extended-string is %s", _nc_visbuf(ptr->ext_str_table)));
29450276Speter	}
29550276Speter
29650276Speter	if ((ptr->ext_Strings = ext_str_count) != 0) {
29762449Speter	    TR(TRACE_DATABASE,
29866963Speter	       ("Before computing extended-string capabilities str_count=%d, ext_str_count=%d",
29966963Speter		str_count, ext_str_count));
30062449Speter	    convert_strings(buf, ptr->Strings + str_count, ext_str_count,
30166963Speter			    ext_str_limit, ptr->ext_str_table);
30262449Speter	    for (i = ext_str_count - 1; i >= 0; i--) {
30362449Speter		TR(TRACE_DATABASE, ("MOVE from [%d:%d] %s",
30466963Speter				    i, i + str_count,
30566963Speter				    _nc_visbuf(ptr->Strings[i + str_count])));
30662449Speter		ptr->Strings[i + STRCOUNT] = ptr->Strings[i + str_count];
30762449Speter		if (VALID_STRING(ptr->Strings[i + STRCOUNT]))
30862449Speter		    base += (strlen(ptr->Strings[i + STRCOUNT]) + 1);
30962449Speter		TR(TRACE_DATABASE, ("... to    [%d] %s",
31066963Speter				    i + STRCOUNT,
31166963Speter				    _nc_visbuf(ptr->Strings[i + STRCOUNT])));
31250276Speter	    }
31350276Speter	}
31450276Speter
31550276Speter	if (need) {
316184989Srafan	    if (ext_str_count >= (MAX_ENTRY_SIZE * 2))
317184989Srafan		  return (TGETENT_NO);
318166124Srafan	    if ((ptr->ext_Names = TYPE_CALLOC(char *, need)) == 0)
319166124Srafan		  return (TGETENT_NO);
32062449Speter	    TR(TRACE_DATABASE,
32166963Speter	       ("ext_NAMES starting @%d in extended_strings, first = %s",
32266963Speter		base, _nc_visbuf(ptr->ext_str_table + base)));
323166124Srafan	    convert_strings(buf + (2 * ext_str_count),
324166124Srafan			    ptr->ext_Names,
325166124Srafan			    (int) need,
32666963Speter			    ext_str_limit, ptr->ext_str_table + base);
32750276Speter	}
32850276Speter
32950276Speter	T(("...done reading terminfo bool %d(%d) num %d(%d) str %d(%d)",
33066963Speter	   ptr->num_Booleans, ptr->ext_Booleans,
33166963Speter	   ptr->num_Numbers, ptr->ext_Numbers,
33266963Speter	   ptr->num_Strings, ptr->ext_Strings));
33350276Speter
33462449Speter	TR(TRACE_DATABASE, ("extend: num_Booleans:%d", ptr->num_Booleans));
33550276Speter    } else
33650276Speter#endif /* NCURSES_XNAMES */
33750276Speter    {
33850276Speter	T(("...done reading terminfo bool %d num %d str %d",
33966963Speter	   bool_count, num_count, str_count));
34062449Speter#if NCURSES_XNAMES
34162449Speter	TR(TRACE_DATABASE, ("normal: num_Booleans:%d", ptr->num_Booleans));
34262449Speter#endif
34350276Speter    }
34450276Speter
34550276Speter    for (i = bool_count; i < BOOLCOUNT; i++)
34650276Speter	ptr->Booleans[i] = FALSE;
34750276Speter    for (i = num_count; i < NUMCOUNT; i++)
34850276Speter	ptr->Numbers[i] = ABSENT_NUMERIC;
34950276Speter    for (i = str_count; i < STRCOUNT; i++)
35050276Speter	ptr->Strings[i] = ABSENT_STRING;
35150276Speter
352166124Srafan    return (TGETENT_YES);
35350276Speter}
35450276Speter
355166124Srafan/*
356166124Srafan *	int
357166124Srafan *	_nc_read_file_entry(filename, ptr)
358166124Srafan *
359166124Srafan *	Read the compiled terminfo entry in the given file into the
360166124Srafan *	structure pointed to by ptr, allocating space for the string
361166124Srafan *	table.
362166124Srafan */
36376726SpeterNCURSES_EXPORT(int)
364166124Srafan_nc_read_file_entry(const char *const filename, TERMTYPE *ptr)
36550276Speter/* return 1 if read, 0 if not found or garbled */
36650276Speter{
36750276Speter    int code, fd = -1;
368166124Srafan    int limit;
369166124Srafan    char buffer[MAX_ENTRY_SIZE + 1];
37050276Speter
37150276Speter    if (_nc_access(filename, R_OK) < 0
37262449Speter	|| (fd = open(filename, O_RDONLY | O_BINARY)) < 0) {
37350276Speter	T(("cannot open terminfo %s (errno=%d)", filename, errno));
374166124Srafan	code = TGETENT_NO;
375166124Srafan    } else {
376166124Srafan	if ((limit = read(fd, buffer, sizeof(buffer))) > 0) {
377166124Srafan
378166124Srafan	    T(("read terminfo %s", filename));
379166124Srafan	    if ((code = _nc_read_termtype(ptr, buffer, limit)) == TGETENT_NO) {
380166124Srafan		_nc_free_termtype(ptr);
381166124Srafan	    }
382166124Srafan	} else {
383166124Srafan	    code = TGETENT_NO;
384166124Srafan	}
385166124Srafan	close(fd);
38650276Speter    }
38750276Speter
38850276Speter    return (code);
38950276Speter}
39050276Speter
39150276Speter/*
392166124Srafan * Build a terminfo pathname and try to read the data.  Returns TGETENT_YES on
393166124Srafan * success, TGETENT_NO on failure.
39450276Speter */
39562449Speterstatic int
396166124Srafan_nc_read_tic_entry(char *filename,
397166124Srafan		   unsigned limit,
398166124Srafan		   const char *const path,
399166124Srafan		   const char *name,
400166124Srafan		   TERMTYPE *const tp)
40150276Speter{
402166124Srafan    int result = TGETENT_NO;
40350276Speter
404166124Srafan    /*
405166124Srafan     * If we are looking in a directory, assume the entry is a file under that,
406166124Srafan     * according to the normal rules.
407166124Srafan     *
408166124Srafan     * FIXME - add caseless-filename fixup.
409166124Srafan     */
410166124Srafan    if (_nc_is_dir_path(path)) {
411166124Srafan	unsigned need = 4 + strlen(path) + strlen(name);
41250276Speter
413166124Srafan	if (need <= limit) {
414174993Srafan	    (void) sprintf(filename, "%s/" LEAF_FMT "/%s", path, *name, name);
415166124Srafan	    result = _nc_read_file_entry(filename, tp);
416166124Srafan	}
417166124Srafan    }
418166124Srafan#if USE_HASHED_DB
419166124Srafan    else {
420166124Srafan	static const char suffix[] = DBM_SUFFIX;
421166124Srafan	DB *capdbp;
422166124Srafan	unsigned lens = sizeof(suffix) - 1;
423166124Srafan	unsigned size = strlen(path);
424166124Srafan	unsigned need = lens + size;
42550276Speter
426166124Srafan	if (need <= limit) {
427166124Srafan	    if (size >= lens
428166124Srafan		&& !strcmp(path + size - lens, suffix))
429166124Srafan		(void) strcpy(filename, path);
430166124Srafan	    else
431166124Srafan		(void) sprintf(filename, "%s%s", path, suffix);
43250276Speter
433166124Srafan	    /*
434166124Srafan	     * It would be nice to optimize the dbopen/close activity, as
435166124Srafan	     * done in the cgetent implementation for tc= clauses.  However,
436166124Srafan	     * since we support multiple database locations, we cannot do
437166124Srafan	     * that.
438166124Srafan	     */
439166124Srafan	    if ((capdbp = _nc_db_open(filename, FALSE)) != 0) {
440166124Srafan		DBT key, data;
441166124Srafan		int reccnt = 0;
442166124Srafan		char *save = strdup(name);
443166124Srafan
444166124Srafan		memset(&key, 0, sizeof(key));
445166124Srafan		key.data = save;
446166124Srafan		key.size = strlen(save);
447166124Srafan
448166124Srafan		/*
449166124Srafan		 * This lookup could return termcap data, which we do not want.
450166124Srafan		 * We are looking for compiled (binary) terminfo data.
451166124Srafan		 *
452166124Srafan		 * cgetent uses a two-level lookup.  On the first it uses the
453166124Srafan		 * given name to return a record containing only the aliases
454166124Srafan		 * for an entry.  On the second (using that list of aliases as
455166124Srafan		 * a key), it returns the content of the terminal description.
456166124Srafan		 * We expect second lookup to return data beginning with the
457166124Srafan		 * same set of aliases.
458166124Srafan		 *
459166124Srafan		 * For compiled terminfo, the list of aliases in the second
460166124Srafan		 * case will be null-terminated.  A termcap entry will not be,
461166124Srafan		 * and will run on into the description.  So we can easily
462166124Srafan		 * distinguish between the two (source/binary) by checking the
463166124Srafan		 * lengths.
464166124Srafan		 */
465166124Srafan		while (_nc_db_get(capdbp, &key, &data) == 0) {
466166124Srafan		    int used = data.size - 1;
467166124Srafan		    char *have = (char *) data.data;
468166124Srafan
469166124Srafan		    if (*have++ == 0) {
470166124Srafan			if (data.size > key.size
471166124Srafan			    && IS_TIC_MAGIC(have)) {
472166124Srafan			    result = _nc_read_termtype(tp, have, used);
473166124Srafan			    if (result == TGETENT_NO) {
474166124Srafan				_nc_free_termtype(tp);
475166124Srafan			    }
476166124Srafan			}
477166124Srafan			break;
478166124Srafan		    }
479166124Srafan
480166124Srafan		    /*
481166124Srafan		     * Just in case we have a corrupt database, do not waste
482166124Srafan		     * time with it.
483166124Srafan		     */
484166124Srafan		    if (++reccnt >= 3)
485166124Srafan			break;
486166124Srafan
487166124Srafan		    /*
488166124Srafan		     * Prepare for the second level.
489166124Srafan		     */
490166124Srafan		    key.data = have;
491166124Srafan		    key.size = used;
492166124Srafan		}
493166124Srafan
494166124Srafan		_nc_db_close(capdbp);
495166124Srafan		free(save);
49662449Speter	    }
49750276Speter	}
49862449Speter    }
499166124Srafan#endif
500166124Srafan    return result;
50150276Speter}
502166124Srafan#endif /* USE_DATABASE */
50350276Speter
50450276Speter/*
505166124Srafan *	_nc_read_entry(char *name, char *filename, TERMTYPE *tp)
50650276Speter *
50750276Speter *	Find and read the compiled entry for a given terminal type,
50850276Speter *	if it exists.  We take pains here to make sure no combination
50950276Speter *	of environment variables and terminal type name can be used to
51050276Speter *	overrun the file buffer.
51150276Speter */
51250276Speter
51376726SpeterNCURSES_EXPORT(int)
514166124Srafan_nc_read_entry(const char *const name, char *const filename, TERMTYPE *const tp)
51550276Speter{
516166124Srafan    int code = TGETENT_NO;
51750276Speter
518166124Srafan    if (strlen(name) == 0
519166124Srafan	|| strcmp(name, ".") == 0
520166124Srafan	|| strcmp(name, "..") == 0
521166124Srafan	|| _nc_pathlast(name) != 0
522166124Srafan	|| strchr(name, NCURSES_PATHSEP) != 0) {
523166124Srafan	T(("illegal or missing entry name '%s'", name));
524166124Srafan    } else {
525166124Srafan#if USE_DATABASE
526166124Srafan	DBDIRS state = dbdTIC;
527166124Srafan	int offset = 0;
528166124Srafan	const char *path;
52950276Speter
530166124Srafan	while ((path = _nc_next_db(&state, &offset)) != 0) {
531166124Srafan	    code = _nc_read_tic_entry(filename, PATH_MAX, path, name, tp);
532166124Srafan	    if (code == TGETENT_YES) {
533166124Srafan		_nc_last_db();
534166124Srafan		break;
53566963Speter	    }
53650276Speter	}
537166124Srafan#endif
538166124Srafan#if USE_TERMCAP
539166124Srafan	if (code != TGETENT_YES) {
540166124Srafan	    code = _nc_read_termcap_entry(name, tp);
541166124Srafan	    sprintf(filename, "%.*s", PATH_MAX - 1, _nc_get_source());
542166124Srafan	}
543166124Srafan#endif
54462449Speter    }
545166124Srafan    return code;
54650276Speter}
547