2 /***************************************************************************
4 ****************************************************************************
5 * ncurses is copyright (C) 1992-1995 *
7 * zmbenhal@netcom.com *
9 * esr@snark.thyrsus.com *
11 * Permission is hereby granted to reproduce and distribute ncurses *
12 * by any means and for any fee, whether alone or as part of a *
13 * larger distribution, in source or in binary form, PROVIDED *
14 * this notice is included with any such distribution, and is not *
15 * removed from any of its header files. Mention of ncurses in any *
16 * applications linked with it is highly appreciated. *
18 * ncurses comes AS IS with no warranty, implied or expressed. *
20 ***************************************************************************/
25 * read_entry.c -- Routine for reading in a compiled terminfo file
29 #include <curses.priv.h>
39 MODULE_ID("$Id: read_entry.c,v 1.31 1997/05/10 17:31:08 tom Exp $")
45 * _nc_read_file_entry(filename, ptr)
47 * Read the compiled terminfo entry in the given file into the
48 * structure pointed to by ptr, allocating space for the string
53 #define BYTE(p,n) (unsigned char)((p)[n])
55 #define IS_NEG1(p) ((BYTE(p,0) == 0377) && (BYTE(p,1) == 0377))
56 #define IS_NEG2(p) ((BYTE(p,0) == 0376) && (BYTE(p,1) == 0377))
57 #define LOW_MSB(p) (BYTE(p,0) + 256*BYTE(p,1))
59 static bool have_tic_directory = FALSE;
62 * Record the "official" location of the terminfo directory, according to
63 * the place where we're writing to, or the normal default, if not.
65 const char *_nc_tic_dir(const char *path)
67 static const char *result = TERMINFO;
71 have_tic_directory = TRUE;
72 } else if (!have_tic_directory) {
74 if ((envp = getenv("TERMINFO")) != 0)
75 return _nc_tic_dir(envp);
80 int _nc_read_file_entry(const char *const filename, TERMTYPE *ptr)
81 /* return 1 if read, 0 if not found or garbled */
83 int name_size, bool_count, num_count, str_count, str_size;
85 char buf[MAX_ENTRY_SIZE];
87 if ((fd = open(filename, O_RDONLY)) < 0)
90 T(("read terminfo %s", filename));
93 (void) read(fd, buf, 12);
94 if (LOW_MSB(buf) != MAGIC)
99 name_size = LOW_MSB(buf + 2);
100 bool_count = LOW_MSB(buf + 4);
101 num_count = LOW_MSB(buf + 6);
102 str_count = LOW_MSB(buf + 8);
103 str_size = LOW_MSB(buf + 10);
107 /* try to allocate space for the string table */
108 ptr->str_table = malloc((unsigned)str_size);
109 if (ptr->str_table == 0)
117 read(fd, buf, min(MAX_NAME_SIZE, (unsigned)name_size));
118 buf[MAX_NAME_SIZE] = '\0';
119 ptr->term_names = calloc(strlen(buf) + 1, sizeof(char));
120 (void) strcpy(ptr->term_names, buf);
121 if (name_size > MAX_NAME_SIZE)
122 lseek(fd, (off_t) (name_size - MAX_NAME_SIZE), 1);
124 /* grab the booleans */
125 read(fd, ptr->Booleans, min(BOOLCOUNT, (unsigned)bool_count));
126 if (bool_count > BOOLCOUNT)
127 lseek(fd, (off_t) (bool_count - BOOLCOUNT), 1);
129 for (i=bool_count; i < BOOLCOUNT; i++)
130 ptr->Booleans[i] = 0;
133 * If booleans end on an odd byte, skip it. The machine they
134 * originally wrote terminfo on must have been a 16-bit
135 * word-oriented machine that would trap out if you tried a
136 * word access off a 2-byte boundary.
138 if ((name_size + bool_count) % 2 != 0)
141 /* grab the numbers */
142 (void) read(fd, buf, min(NUMCOUNT*2, (unsigned)num_count*2));
143 for (i = 0; i < min(num_count, NUMCOUNT); i++)
145 if (IS_NEG1(buf + 2*i))
146 ptr->Numbers[i] = ABSENT_NUMERIC;
147 else if (IS_NEG2(buf + 2*i))
148 ptr->Numbers[i] = CANCELLED_NUMERIC;
150 ptr->Numbers[i] = LOW_MSB(buf + 2*i);
152 if (num_count > NUMCOUNT)
153 lseek(fd, (off_t) (2 * (num_count - NUMCOUNT)), 1);
155 for (i=num_count; i < NUMCOUNT; i++)
156 ptr->Numbers[i] = ABSENT_NUMERIC;
160 /* grab the string offsets */
161 numread = read(fd, buf, (unsigned)(str_count*2));
162 if (numread < str_count*2)
167 for (i = 0; i < numread/2; i++)
169 if (IS_NEG1(buf + 2*i))
170 ptr->Strings[i] = ABSENT_STRING;
171 else if (IS_NEG2(buf + 2*i))
172 ptr->Strings[i] = CANCELLED_STRING;
174 ptr->Strings[i] = (LOW_MSB(buf+2*i) + ptr->str_table);
178 if (str_count > STRCOUNT)
179 lseek(fd, (off_t) (2 * (str_count - STRCOUNT)), 1);
181 for (i = str_count; i < STRCOUNT; i++)
182 ptr->Strings[i] = ABSENT_STRING;
186 /* finally, grab the string table itself */
187 numread = read(fd, ptr->str_table, (unsigned)str_size);
188 if (numread != str_size)
200 * Build a terminfo pathname and try to read the data. Returns 1 on success,
203 static int _nc_read_tic_entry(char *const filename,
204 const char *const dir, const char *ttn, TERMTYPE *const tp)
206 /* maximum safe length of terminfo root directory name */
207 #define MAX_TPATH (PATH_MAX - MAX_ALIAS - 6)
209 if (strlen(dir) > MAX_TPATH)
211 (void) sprintf(filename, "%s/%s", dir, ttn);
212 return _nc_read_file_entry(filename, tp);
216 * _nc_read_entry(char *tn, char *filename, TERMTYPE *tp)
218 * Find and read the compiled entry for a given terminal type,
219 * if it exists. We take pains here to make sure no combination
220 * of environment variables and terminal type name can be used to
221 * overrun the file buffer.
224 int _nc_read_entry(const char *const tn, char *const filename, TERMTYPE *const tp)
227 char ttn[MAX_ALIAS + 3];
229 /* truncate the terminal name to prevent dangerous buffer airline */
230 (void) sprintf(ttn, "%c/%.*s", *tn, MAX_ALIAS, tn);
232 /* This is System V behavior, in conjunction with our requirements for
233 * writing terminfo entries.
235 if (have_tic_directory
236 && _nc_read_tic_entry(filename, _nc_tic_dir(0), ttn, tp) == 1)
239 if ((envp = getenv("TERMINFO")) != 0
240 && _nc_read_tic_entry(filename, _nc_tic_dir(envp), ttn, tp) == 1)
243 /* this is an ncurses extension */
244 if ((envp = getenv("HOME")) != 0)
246 char *home = malloc(strlen(envp) + strlen(PRIVATE_INFO) + 2);
248 (void) sprintf(home, PRIVATE_INFO, envp);
249 if (_nc_read_tic_entry(filename, home, ttn, tp) == 1) {
256 /* this is an ncurses extension */
257 if ((envp = getenv("TERMINFO_DIRS")) != 0)
259 /* strtok modifies its argument, so we must copy */
260 char *list = strcpy(malloc(strlen(envp)+1), envp);
261 const char *cp = strtok(list, ":");
267 if (_nc_read_tic_entry(filename, cp, ttn, tp) == 1) {
272 ((cp = strtok((char *)0, ":")) != 0);
278 /* try the system directory */
279 return(_nc_read_tic_entry(filename, TERMINFO, ttn, tp));
283 * _nc_first_name(char *names)
285 * Extract the primary name from a compiled entry.
288 char *_nc_first_name(const char *const sp)
289 /* get the first name from the given name list */
291 static char buf[MAX_NAME_SIZE];
294 (void) strcpy(buf, sp);
296 cp = strchr(buf, '|');
304 * bool _nc_name_match(namelist, name, delim)
306 * Is the given name matched in namelist?
309 int _nc_name_match(const char *const namelst, const char *const name, const char *const delim)
310 /* microtune this, it occurs in several critical loops */
312 char namecopy[MAX_ENTRY_SIZE]; /* this may get called on a TERMCAP value */
317 (void) strcpy(namecopy, namelst);
318 if ((cp = strtok(namecopy, delim)) != 0) {
320 /* avoid strcmp() function-call cost if possible */
321 if (cp[0] == name[0] && strcmp(cp, name) == 0)
324 ((cp = strtok((char *)0, delim)) != 0);