1 /****************************************************************************
2 * Copyright (c) 1998 Free Software Foundation, Inc. *
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: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
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. *
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 *
27 ****************************************************************************/
29 /****************************************************************************
30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
31 * and: Eric S. Raymond <esr@snark.thyrsus.com> *
32 ****************************************************************************/
37 * read_entry.c -- Routine for reading in a compiled terminfo file
41 #include <curses.priv.h>
51 MODULE_ID("$Id: read_entry.c,v 1.35 1998/02/11 12:13:59 tom Exp $")
59 * _nc_read_file_entry(filename, ptr)
61 * Read the compiled terminfo entry in the given file into the
62 * structure pointed to by ptr, allocating space for the string
67 #define BYTE(p,n) (unsigned char)((p)[n])
69 #define IS_NEG1(p) ((BYTE(p,0) == 0377) && (BYTE(p,1) == 0377))
70 #define IS_NEG2(p) ((BYTE(p,0) == 0376) && (BYTE(p,1) == 0377))
71 #define LOW_MSB(p) (BYTE(p,0) + 256*BYTE(p,1))
73 static bool have_tic_directory = FALSE;
76 * Record the "official" location of the terminfo directory, according to
77 * the place where we're writing to, or the normal default, if not.
79 const char *_nc_tic_dir(const char *path)
81 static const char *result = TERMINFO;
85 have_tic_directory = TRUE;
86 } else if (!have_tic_directory) {
88 if ((envp = getenv("TERMINFO")) != 0)
89 return _nc_tic_dir(envp);
94 int _nc_read_file_entry(const char *const filename, TERMTYPE *ptr)
95 /* return 1 if read, 0 if not found or garbled */
97 int name_size, bool_count, num_count, str_count, str_size;
99 char buf[MAX_ENTRY_SIZE];
101 if ((fd = open(filename, O_RDONLY|O_BINARY)) < 0)
104 T(("read terminfo %s", filename));
106 /* grab the header */
107 (void) read(fd, buf, 12);
108 if (LOW_MSB(buf) != MAGIC)
113 name_size = LOW_MSB(buf + 2);
114 bool_count = LOW_MSB(buf + 4);
115 num_count = LOW_MSB(buf + 6);
116 str_count = LOW_MSB(buf + 8);
117 str_size = LOW_MSB(buf + 10);
121 /* try to allocate space for the string table */
122 ptr->str_table = malloc((unsigned)str_size);
123 if (ptr->str_table == 0)
131 read(fd, buf, min(MAX_NAME_SIZE, (unsigned)name_size));
132 buf[MAX_NAME_SIZE] = '\0';
133 ptr->term_names = calloc(strlen(buf) + 1, sizeof(char));
134 (void) strcpy(ptr->term_names, buf);
135 if (name_size > MAX_NAME_SIZE)
136 lseek(fd, (off_t) (name_size - MAX_NAME_SIZE), 1);
138 /* grab the booleans */
139 read(fd, ptr->Booleans, min(BOOLCOUNT, (unsigned)bool_count));
140 if (bool_count > BOOLCOUNT)
141 lseek(fd, (off_t) (bool_count - BOOLCOUNT), 1);
143 for (i=bool_count; i < BOOLCOUNT; i++)
144 ptr->Booleans[i] = 0;
147 * If booleans end on an odd byte, skip it. The machine they
148 * originally wrote terminfo on must have been a 16-bit
149 * word-oriented machine that would trap out if you tried a
150 * word access off a 2-byte boundary.
152 if ((name_size + bool_count) % 2 != 0)
155 /* grab the numbers */
156 (void) read(fd, buf, min(NUMCOUNT*2, (unsigned)num_count*2));
157 for (i = 0; i < min(num_count, NUMCOUNT); i++)
159 if (IS_NEG1(buf + 2*i))
160 ptr->Numbers[i] = ABSENT_NUMERIC;
161 else if (IS_NEG2(buf + 2*i))
162 ptr->Numbers[i] = CANCELLED_NUMERIC;
164 ptr->Numbers[i] = LOW_MSB(buf + 2*i);
166 if (num_count > NUMCOUNT)
167 lseek(fd, (off_t) (2 * (num_count - NUMCOUNT)), 1);
169 for (i=num_count; i < NUMCOUNT; i++)
170 ptr->Numbers[i] = ABSENT_NUMERIC;
174 if (str_count*2 >= MAX_ENTRY_SIZE)
179 /* grab the string offsets */
180 numread = read(fd, buf, (unsigned)(str_count*2));
181 if (numread < str_count*2)
186 for (i = 0; i < numread/2; i++)
190 if (IS_NEG1(buf + 2*i))
191 ptr->Strings[i] = ABSENT_STRING;
192 else if (IS_NEG2(buf + 2*i))
193 ptr->Strings[i] = CANCELLED_STRING;
195 ptr->Strings[i] = (LOW_MSB(buf+2*i) + ptr->str_table);
199 if (str_count > STRCOUNT)
200 lseek(fd, (off_t) (2 * (str_count - STRCOUNT)), 1);
202 for (i = str_count; i < STRCOUNT; i++)
203 ptr->Strings[i] = ABSENT_STRING;
207 /* finally, grab the string table itself */
208 numread = read(fd, ptr->str_table, (unsigned)str_size);
209 if (numread != str_size)
221 * Build a terminfo pathname and try to read the data. Returns 1 on success,
224 static int _nc_read_tic_entry(char *const filename,
225 const char *const dir, const char *ttn, TERMTYPE *const tp)
227 /* maximum safe length of terminfo root directory name */
228 #define MAX_TPATH (PATH_MAX - MAX_ALIAS - 6)
230 if (strlen(dir) > MAX_TPATH)
232 (void) sprintf(filename, "%s/%s", dir, ttn);
233 return _nc_read_file_entry(filename, tp);
237 * _nc_read_entry(char *tn, char *filename, TERMTYPE *tp)
239 * Find and read the compiled entry for a given terminal type,
240 * if it exists. We take pains here to make sure no combination
241 * of environment variables and terminal type name can be used to
242 * overrun the file buffer.
245 int _nc_read_entry(const char *const tn, char *const filename, TERMTYPE *const tp)
248 char ttn[MAX_ALIAS + 3];
250 /* truncate the terminal name to prevent dangerous buffer airline */
251 (void) sprintf(ttn, "%c/%.*s", *tn, MAX_ALIAS, tn);
253 /* This is System V behavior, in conjunction with our requirements for
254 * writing terminfo entries.
256 if (have_tic_directory
257 && _nc_read_tic_entry(filename, _nc_tic_dir(0), ttn, tp) == 1)
260 if ((envp = getenv("TERMINFO")) != 0
261 && _nc_read_tic_entry(filename, _nc_tic_dir(envp), ttn, tp) == 1)
264 /* this is an ncurses extension */
265 if ((envp = getenv("HOME")) != 0)
267 char *home = malloc(strlen(envp) + strlen(PRIVATE_INFO) + 2);
269 (void) sprintf(home, PRIVATE_INFO, envp);
270 if (_nc_read_tic_entry(filename, home, ttn, tp) == 1) {
277 /* this is an ncurses extension */
278 if ((envp = getenv("TERMINFO_DIRS")) != 0)
280 /* strtok modifies its argument, so we must copy */
281 char *list = strcpy(malloc(strlen(envp)+1), envp);
282 const char *cp = strtok(list, ":");
288 if (_nc_read_tic_entry(filename, cp, ttn, tp) == 1) {
293 ((cp = strtok((char *)0, ":")) != 0);
299 /* try the system directory */
300 return(_nc_read_tic_entry(filename, TERMINFO, ttn, tp));