1 /****************************************************************************
2 * Copyright (c) 1998-2003,2004 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 * and: Thomas E. Dickey *
33 ****************************************************************************/
36 * read_entry.c -- Routine for reading in a compiled terminfo file
40 #include <curses.priv.h>
43 #include <term_entry.h>
45 MODULE_ID("$Id: read_entry.c,v 1.79 2004/01/11 01:57:05 tom Exp $")
48 #define tell(fd) lseek(fd, 0, SEEK_CUR) /* lseek() is POSIX, but not tell() */
53 * _nc_read_file_entry(filename, ptr)
55 * Read the compiled terminfo entry in the given file into the
56 * structure pointed to by ptr, allocating space for the string
61 #define BYTE(p,n) (unsigned char)((p)[n])
63 #define IS_NEG1(p) ((BYTE(p,0) == 0377) && (BYTE(p,1) == 0377))
64 #define IS_NEG2(p) ((BYTE(p,0) == 0376) && (BYTE(p,1) == 0377))
65 #define LOW_MSB(p) (BYTE(p,0) + 256*BYTE(p,1))
67 static bool have_tic_directory
= FALSE
;
68 static bool keep_tic_directory
= FALSE
;
71 * Record the "official" location of the terminfo directory, according to
72 * the place where we're writing to, or the normal default, if not.
74 NCURSES_EXPORT(const char *)
75 _nc_tic_dir(const char *path
)
77 static const char *result
= TERMINFO
;
79 if (!keep_tic_directory
) {
82 have_tic_directory
= TRUE
;
83 } else if (!have_tic_directory
&& use_terminfo_vars()) {
85 if ((envp
= getenv("TERMINFO")) != 0)
86 return _nc_tic_dir(envp
);
93 * Special fix to prevent the terminfo directory from being moved after tic
94 * has chdir'd to it. If we let it be changed, then if $TERMINFO has a
95 * relative path, we'll lose track of the actual directory.
98 _nc_keep_tic_dir(const char *path
)
101 keep_tic_directory
= TRUE
;
105 convert_shorts(char *buf
, short *Numbers
, int count
)
108 for (i
= 0; i
< count
; i
++) {
109 if (IS_NEG1(buf
+ 2 * i
))
110 Numbers
[i
] = ABSENT_NUMERIC
;
111 else if (IS_NEG2(buf
+ 2 * i
))
112 Numbers
[i
] = CANCELLED_NUMERIC
;
114 Numbers
[i
] = LOW_MSB(buf
+ 2 * i
);
115 TR(TRACE_DATABASE
, ("get Numbers[%d]=%d", i
, Numbers
[i
]));
120 convert_strings(char *buf
, char **Strings
, int count
, int size
, char *table
)
125 for (i
= 0; i
< count
; i
++) {
126 if (IS_NEG1(buf
+ 2 * i
)) {
127 Strings
[i
] = ABSENT_STRING
;
128 } else if (IS_NEG2(buf
+ 2 * i
)) {
129 Strings
[i
] = CANCELLED_STRING
;
130 } else if (LOW_MSB(buf
+ 2 * i
) > size
) {
131 Strings
[i
] = ABSENT_STRING
;
133 Strings
[i
] = (LOW_MSB(buf
+ 2 * i
) + table
);
134 TR(TRACE_DATABASE
, ("Strings[%d] = %s", i
, _nc_visbuf(Strings
[i
])));
137 /* make sure all strings are NUL terminated */
138 if (VALID_STRING(Strings
[i
])) {
139 for (p
= Strings
[i
]; p
<= table
+ size
; p
++)
142 /* if there is no NUL, ignore the string */
143 if (p
> table
+ size
)
144 Strings
[i
] = ABSENT_STRING
;
149 #define read_shorts(fd, buf, count) (read(fd, buf, (count)*2) == (count)*2)
151 #define even_boundary(value) \
152 if ((value) % 2 != 0) read(fd, buf, 1)
155 read_termtype(int fd
, TERMTYPE
* ptr
)
156 /* return 1 if read, 0 if not found or garbled */
158 int name_size
, bool_count
, num_count
, str_count
, str_size
;
160 char buf
[MAX_ENTRY_SIZE
+ 1];
163 TR(TRACE_DATABASE
, ("READ termtype header @%ld", (long) tell(fd
)));
165 memset(ptr
, 0, sizeof(*ptr
));
167 /* grab the header */
168 if (!read_shorts(fd
, buf
, 6)
169 || LOW_MSB(buf
) != MAGIC
) {
173 name_size
= LOW_MSB(buf
+ 2);
174 bool_count
= LOW_MSB(buf
+ 4);
175 num_count
= LOW_MSB(buf
+ 6);
176 str_count
= LOW_MSB(buf
+ 8);
177 str_size
= LOW_MSB(buf
+ 10);
180 ("TERMTYPE name_size=%d, bool=%d/%d, num=%d/%d str=%d/%d(%d)",
181 name_size
, bool_count
, BOOLCOUNT
, num_count
, NUMCOUNT
,
182 str_count
, STRCOUNT
, str_size
));
192 /* try to allocate space for the string table */
193 if (str_count
* 2 >= (int) sizeof(buf
)
194 || (ptr
->str_table
= typeMalloc(char, (unsigned) str_size
)) == 0) {
201 /* grab the name (a null-terminated string) */
202 want
= min(MAX_NAME_SIZE
, (unsigned) name_size
);
203 if ((have
= read(fd
, buf
, want
)) != want
) {
204 memset(buf
+ have
, 0, want
- have
);
207 ptr
->term_names
= typeCalloc(char, strlen(buf
) + 1);
208 if (ptr
->term_names
== NULL
) {
211 (void) strcpy(ptr
->term_names
, buf
);
212 if (have
> MAX_NAME_SIZE
)
213 lseek(fd
, (off_t
) (have
- MAX_NAME_SIZE
), 1);
215 /* grab the booleans */
216 if ((ptr
->Booleans
= typeCalloc(char, max(BOOLCOUNT
, bool_count
))) == 0
217 || read(fd
, ptr
->Booleans
, (unsigned) bool_count
) < bool_count
) {
222 * If booleans end on an odd byte, skip it. The machine they
223 * originally wrote terminfo on must have been a 16-bit
224 * word-oriented machine that would trap out if you tried a
225 * word access off a 2-byte boundary.
227 even_boundary(name_size
+ bool_count
);
229 /* grab the numbers */
230 if ((ptr
->Numbers
= typeCalloc(short, max(NUMCOUNT
, num_count
))) == 0
231 || !read_shorts(fd
, buf
, num_count
)) {
234 convert_shorts(buf
, ptr
->Numbers
, num_count
);
236 if ((ptr
->Strings
= typeCalloc(char *, max(STRCOUNT
, str_count
))) == 0)
240 /* grab the string offsets */
241 if (!read_shorts(fd
, buf
, str_count
)) {
244 /* finally, grab the string table itself */
245 if (read(fd
, ptr
->str_table
, (unsigned) str_size
) != str_size
)
247 convert_strings(buf
, ptr
->Strings
, str_count
, str_size
, ptr
->str_table
);
251 ptr
->num_Booleans
= BOOLCOUNT
;
252 ptr
->num_Numbers
= NUMCOUNT
;
253 ptr
->num_Strings
= STRCOUNT
;
256 * Read extended entries, if any, after the normal end of terminfo data.
258 even_boundary(str_size
);
259 TR(TRACE_DATABASE
, ("READ extended_header @%ld", (long) tell(fd
)));
260 if (_nc_user_definable
&& read_shorts(fd
, buf
, 5)) {
261 int ext_bool_count
= LOW_MSB(buf
+ 0);
262 int ext_num_count
= LOW_MSB(buf
+ 2);
263 int ext_str_count
= LOW_MSB(buf
+ 4);
264 int ext_str_size
= LOW_MSB(buf
+ 6);
265 int ext_str_limit
= LOW_MSB(buf
+ 8);
266 int need
= (ext_bool_count
+ ext_num_count
+ ext_str_count
);
269 if (need
>= (int) sizeof(buf
)
270 || ext_str_size
>= (int) sizeof(buf
)
271 || ext_str_limit
>= (int) sizeof(buf
)
272 || ext_bool_count
< 0
276 || ext_str_limit
< 0)
279 ptr
->num_Booleans
= BOOLCOUNT
+ ext_bool_count
;
280 ptr
->num_Numbers
= NUMCOUNT
+ ext_num_count
;
281 ptr
->num_Strings
= STRCOUNT
+ ext_str_count
;
283 ptr
->Booleans
= typeRealloc(char, ptr
->num_Booleans
, ptr
->Booleans
);
284 ptr
->Numbers
= typeRealloc(short, ptr
->num_Numbers
, ptr
->Numbers
);
285 ptr
->Strings
= typeRealloc(char *, ptr
->num_Strings
, ptr
->Strings
);
287 TR(TRACE_DATABASE
, ("extended header is %d/%d/%d(%d:%d)",
288 ext_bool_count
, ext_num_count
, ext_str_count
,
289 ext_str_size
, ext_str_limit
));
291 TR(TRACE_DATABASE
, ("READ %d extended-booleans @%ld",
292 ext_bool_count
, (long) tell(fd
)));
293 if ((ptr
->ext_Booleans
= ext_bool_count
) != 0) {
294 if (read(fd
, ptr
->Booleans
+ BOOLCOUNT
, (unsigned)
295 ext_bool_count
) != ext_bool_count
)
298 even_boundary(ext_bool_count
);
300 TR(TRACE_DATABASE
, ("READ %d extended-numbers @%ld",
301 ext_num_count
, (long) tell(fd
)));
302 if ((ptr
->ext_Numbers
= ext_num_count
) != 0) {
303 if (!read_shorts(fd
, buf
, ext_num_count
))
305 TR(TRACE_DATABASE
, ("Before converting extended-numbers"));
306 convert_shorts(buf
, ptr
->Numbers
+ NUMCOUNT
, ext_num_count
);
309 TR(TRACE_DATABASE
, ("READ extended-offsets @%ld", (long) tell(fd
)));
310 if ((ext_str_count
|| need
)
311 && !read_shorts(fd
, buf
, ext_str_count
+ need
))
314 TR(TRACE_DATABASE
, ("READ %d bytes of extended-strings @%ld",
315 ext_str_limit
, (long) tell(fd
)));
318 if ((ptr
->ext_str_table
= typeMalloc(char, ext_str_limit
)) == 0)
320 if (read(fd
, ptr
->ext_str_table
, ext_str_limit
) != ext_str_limit
)
322 TR(TRACE_DATABASE
, ("first extended-string is %s", _nc_visbuf(ptr
->ext_str_table
)));
325 if ((ptr
->ext_Strings
= ext_str_count
) != 0) {
327 ("Before computing extended-string capabilities str_count=%d, ext_str_count=%d",
328 str_count
, ext_str_count
));
329 convert_strings(buf
, ptr
->Strings
+ str_count
, ext_str_count
,
330 ext_str_limit
, ptr
->ext_str_table
);
331 for (i
= ext_str_count
- 1; i
>= 0; i
--) {
332 TR(TRACE_DATABASE
, ("MOVE from [%d:%d] %s",
334 _nc_visbuf(ptr
->Strings
[i
+ str_count
])));
335 ptr
->Strings
[i
+ STRCOUNT
] = ptr
->Strings
[i
+ str_count
];
336 if (VALID_STRING(ptr
->Strings
[i
+ STRCOUNT
]))
337 base
+= (strlen(ptr
->Strings
[i
+ STRCOUNT
]) + 1);
338 TR(TRACE_DATABASE
, ("... to [%d] %s",
340 _nc_visbuf(ptr
->Strings
[i
+ STRCOUNT
])));
345 if ((ptr
->ext_Names
= typeCalloc(char *, need
)) == 0)
348 ("ext_NAMES starting @%d in extended_strings, first = %s",
349 base
, _nc_visbuf(ptr
->ext_str_table
+ base
)));
350 convert_strings(buf
+ (2 * ext_str_count
), ptr
->ext_Names
, need
,
351 ext_str_limit
, ptr
->ext_str_table
+ base
);
354 T(("...done reading terminfo bool %d(%d) num %d(%d) str %d(%d)",
355 ptr
->num_Booleans
, ptr
->ext_Booleans
,
356 ptr
->num_Numbers
, ptr
->ext_Numbers
,
357 ptr
->num_Strings
, ptr
->ext_Strings
));
359 TR(TRACE_DATABASE
, ("extend: num_Booleans:%d", ptr
->num_Booleans
));
361 #endif /* NCURSES_XNAMES */
363 T(("...done reading terminfo bool %d num %d str %d",
364 bool_count
, num_count
, str_count
));
366 TR(TRACE_DATABASE
, ("normal: num_Booleans:%d", ptr
->num_Booleans
));
370 for (i
= bool_count
; i
< BOOLCOUNT
; i
++)
371 ptr
->Booleans
[i
] = FALSE
;
372 for (i
= num_count
; i
< NUMCOUNT
; i
++)
373 ptr
->Numbers
[i
] = ABSENT_NUMERIC
;
374 for (i
= str_count
; i
< STRCOUNT
; i
++)
375 ptr
->Strings
[i
] = ABSENT_STRING
;
381 _nc_read_file_entry(const char *const filename
, TERMTYPE
* ptr
)
382 /* return 1 if read, 0 if not found or garbled */
386 if (_nc_access(filename
, R_OK
) < 0
387 || (fd
= open(filename
, O_RDONLY
| O_BINARY
)) < 0) {
388 T(("cannot open terminfo %s (errno=%d)", filename
, errno
));
391 T(("read terminfo %s", filename
));
392 if ((code
= read_termtype(fd
, ptr
)) == 0)
393 _nc_free_termtype(ptr
);
401 * Build a terminfo pathname and try to read the data. Returns 1 on success,
405 _nc_read_tic_entry(char *const filename
,
406 const char *const dir
, const char *ttn
, TERMTYPE
* const tp
)
408 int need
= 2 + strlen(dir
) + strlen(ttn
);
412 (void) sprintf(filename
, "%s/%s", dir
, ttn
);
413 return _nc_read_file_entry(filename
, tp
);
417 * Process the list of :-separated directories, looking for the terminal type.
418 * We don't use strtok because it does not show us empty tokens.
421 _nc_read_terminfo_dirs(const char *dirs
, char *const filename
, const char *const
422 ttn
, TERMTYPE
* const tp
)
428 /* we'll modify the argument, so we must copy */
429 if ((b
= a
= list
= strdup(dirs
)) == NULL
)
434 if (c
== 0 || c
== NCURSES_PATHSEP
) {
438 if (_nc_read_tic_entry(filename
, b
, ttn
, tp
) == 1) {
454 * _nc_read_entry(char *tn, char *filename, TERMTYPE *tp)
456 * Find and read the compiled entry for a given terminal type,
457 * if it exists. We take pains here to make sure no combination
458 * of environment variables and terminal type name can be used to
459 * overrun the file buffer.
463 _nc_read_entry(const char *const tn
, char *const filename
, TERMTYPE
* const tp
)
469 || strcmp(tn
, ".") == 0
470 || strcmp(tn
, "..") == 0
471 || _nc_pathlast(tn
) != 0) {
472 T(("illegal or missing entry name '%s'", tn
));
476 /* truncate the terminal name to prevent buffer overflow */
477 (void) sprintf(ttn
, "%c/%.*s", *tn
, (int) sizeof(ttn
) - 3, tn
);
479 /* This is System V behavior, in conjunction with our requirements for
480 * writing terminfo entries.
482 if (have_tic_directory
483 && _nc_read_tic_entry(filename
, _nc_tic_dir(0), ttn
, tp
) == 1)
486 if (use_terminfo_vars()) {
487 if ((envp
= getenv("TERMINFO")) != 0
488 && _nc_read_tic_entry(filename
, _nc_tic_dir(envp
), ttn
, tp
) == 1)
491 /* this is an ncurses extension */
492 if ((envp
= _nc_home_terminfo()) != 0) {
493 if (_nc_read_tic_entry(filename
, envp
, ttn
, tp
) == 1) {
498 /* this is an ncurses extension */
499 if ((envp
= getenv("TERMINFO_DIRS")) != 0)
500 return _nc_read_terminfo_dirs(envp
, filename
, ttn
, tp
);
503 /* Try the system directory. Note that the TERMINFO_DIRS value, if
504 * defined by the configure script, begins with a ":", which will be
505 * interpreted as TERMINFO.
508 return _nc_read_terminfo_dirs(TERMINFO_DIRS
, filename
, ttn
, tp
);
510 return _nc_read_tic_entry(filename
, TERMINFO
, ttn
, tp
);