1 |
|
|
/* $OpenBSD: read_termcap.c,v 1.22 2010/01/12 23:22:06 nicm Exp $ */ |
2 |
|
|
|
3 |
|
|
/**************************************************************************** |
4 |
|
|
* Copyright (c) 1998-2005,2006 Free Software Foundation, Inc. * |
5 |
|
|
* * |
6 |
|
|
* Permission is hereby granted, free of charge, to any person obtaining a * |
7 |
|
|
* copy of this software and associated documentation files (the * |
8 |
|
|
* "Software"), to deal in the Software without restriction, including * |
9 |
|
|
* without limitation the rights to use, copy, modify, merge, publish, * |
10 |
|
|
* distribute, distribute with modifications, sublicense, and/or sell * |
11 |
|
|
* copies of the Software, and to permit persons to whom the Software is * |
12 |
|
|
* furnished to do so, subject to the following conditions: * |
13 |
|
|
* * |
14 |
|
|
* The above copyright notice and this permission notice shall be included * |
15 |
|
|
* in all copies or substantial portions of the Software. * |
16 |
|
|
* * |
17 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * |
18 |
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * |
19 |
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * |
20 |
|
|
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * |
21 |
|
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * |
22 |
|
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * |
23 |
|
|
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. * |
24 |
|
|
* * |
25 |
|
|
* Except as contained in this notice, the name(s) of the above copyright * |
26 |
|
|
* holders shall not be used in advertising or otherwise to promote the * |
27 |
|
|
* sale, use or other dealings in this Software without prior written * |
28 |
|
|
* authorization. * |
29 |
|
|
****************************************************************************/ |
30 |
|
|
|
31 |
|
|
/**************************************************************************** |
32 |
|
|
* Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * |
33 |
|
|
* and: Eric S. Raymond <esr@snark.thyrsus.com> * |
34 |
|
|
* and: Thomas E. Dickey 1996-on * |
35 |
|
|
****************************************************************************/ |
36 |
|
|
|
37 |
|
|
/* |
38 |
|
|
* Termcap compatibility support |
39 |
|
|
* |
40 |
|
|
* If your OS integrator didn't install a terminfo database, you can call |
41 |
|
|
* _nc_read_termcap_entry() to support reading and translating capabilities |
42 |
|
|
* from the system termcap file. This is a kludge; it will bulk up and slow |
43 |
|
|
* down every program that uses ncurses, and translated termcap entries cannot |
44 |
|
|
* use full terminfo capabilities. Don't use it unless you absolutely have to; |
45 |
|
|
* instead, get your system people to run tic(1) from root on the terminfo |
46 |
|
|
* master included with ncurses to translate it into a terminfo database. |
47 |
|
|
* |
48 |
|
|
* If USE_GETCAP is enabled, we use what is effectively a copy of the 4.4BSD |
49 |
|
|
* getcap code to fetch entries. There are disadvantages to this; mainly that |
50 |
|
|
* getcap(3) does its own resolution, meaning that entries read in in this way |
51 |
|
|
* can't reference the terminfo tree. The only thing it buys is faster startup |
52 |
|
|
* time, getcap(3) is much faster than our tic parser. |
53 |
|
|
*/ |
54 |
|
|
|
55 |
|
|
#include <curses.priv.h> |
56 |
|
|
|
57 |
|
|
#include <ctype.h> |
58 |
|
|
#include <sys/types.h> |
59 |
|
|
#include <sys/stat.h> |
60 |
|
|
#include <tic.h> |
61 |
|
|
#include <term_entry.h> |
62 |
|
|
|
63 |
|
|
MODULE_ID("$Id: read_termcap.c,v 1.22 2010/01/12 23:22:06 nicm Exp $") |
64 |
|
|
|
65 |
|
|
#if !PURE_TERMINFO |
66 |
|
|
|
67 |
|
|
#define TC_SUCCESS 0 |
68 |
|
|
#define TC_NOT_FOUND -1 |
69 |
|
|
#define TC_SYS_ERR -2 |
70 |
|
|
#define TC_REF_LOOP -3 |
71 |
|
|
#define TC_UNRESOLVED -4 /* this is not returned by BSD cgetent */ |
72 |
|
|
|
73 |
|
|
static NCURSES_CONST char * |
74 |
|
|
get_termpath(void) |
75 |
|
|
{ |
76 |
|
|
NCURSES_CONST char *result; |
77 |
|
|
|
78 |
|
|
if (!use_terminfo_vars() || (result = getenv("TERMPATH")) == 0) |
79 |
|
|
result = TERMPATH; |
80 |
|
|
T(("TERMPATH is %s", result)); |
81 |
|
|
return result; |
82 |
|
|
} |
83 |
|
|
|
84 |
|
|
#if USE_GETCAP |
85 |
|
|
|
86 |
|
|
#if HAVE_BSD_CGETENT |
87 |
|
|
#define _nc_cgetcap cgetcap |
88 |
|
|
#define _nc_cgetent(buf, oline, db_array, name) cgetent(buf, db_array, name) |
89 |
|
|
#define _nc_cgetmatch cgetmatch |
90 |
|
|
#define _nc_cgetset cgetset |
91 |
|
|
#else |
92 |
|
|
static int _nc_cgetmatch(char *, const char *); |
93 |
|
|
static int _nc_getent(char **, unsigned *, int *, int, char **, int, const char |
94 |
|
|
*, int, char *); |
95 |
|
|
static int _nc_nfcmp(const char *, char *); |
96 |
|
|
|
97 |
|
|
/*- |
98 |
|
|
* Copyright (c) 1992, 1993 |
99 |
|
|
* The Regents of the University of California. All rights reserved. |
100 |
|
|
* |
101 |
|
|
* This code is derived from software contributed to Berkeley by |
102 |
|
|
* Casey Leedom of Lawrence Livermore National Laboratory. |
103 |
|
|
* |
104 |
|
|
* Redistribution and use in source and binary forms, with or without |
105 |
|
|
* modification, are permitted provided that the following conditions |
106 |
|
|
* are met: |
107 |
|
|
* 1. Redistributions of source code must retain the above copyright |
108 |
|
|
* notice, this list of conditions and the following disclaimer. |
109 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
110 |
|
|
* notice, this list of conditions and the following disclaimer in the |
111 |
|
|
* documentation and/or other materials provided with the distribution. |
112 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
113 |
|
|
* may be used to endorse or promote products derived from this software |
114 |
|
|
* without specific prior written permission. |
115 |
|
|
* |
116 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
117 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
118 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
119 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
120 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
121 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
122 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
123 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
124 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
125 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
126 |
|
|
* SUCH DAMAGE. |
127 |
|
|
*/ |
128 |
|
|
|
129 |
|
|
#define BFRAG 1024 |
130 |
|
|
#define BSIZE 1024 |
131 |
|
|
#define MAX_RECURSION 32 /* maximum getent recursion */ |
132 |
|
|
|
133 |
|
|
static size_t topreclen; /* toprec length */ |
134 |
|
|
static char *toprec; /* Additional record specified by cgetset() */ |
135 |
|
|
static int gottoprec; /* Flag indicating retrieval of toprecord */ |
136 |
|
|
|
137 |
|
|
/* |
138 |
|
|
* Cgetset() allows the addition of a user specified buffer to be added to the |
139 |
|
|
* database array, in effect "pushing" the buffer on top of the virtual |
140 |
|
|
* database. 0 is returned on success, -1 on failure. |
141 |
|
|
*/ |
142 |
|
|
static int |
143 |
|
|
_nc_cgetset(const char *ent) |
144 |
|
|
{ |
145 |
|
|
if (ent == 0) { |
146 |
|
|
FreeIfNeeded(toprec); |
147 |
|
|
toprec = 0; |
148 |
|
|
topreclen = 0; |
149 |
|
|
return (0); |
150 |
|
|
} |
151 |
|
|
topreclen = strlen(ent); |
152 |
|
|
if ((toprec = typeMalloc(char, topreclen + 1)) == 0) { |
153 |
|
|
errno = ENOMEM; |
154 |
|
|
return (-1); |
155 |
|
|
} |
156 |
|
|
gottoprec = 0; |
157 |
|
|
(void) strlcpy(toprec, ent, topreclen + 1); |
158 |
|
|
return (0); |
159 |
|
|
} |
160 |
|
|
|
161 |
|
|
/* |
162 |
|
|
* Cgetcap searches the capability record buf for the capability cap with type |
163 |
|
|
* `type'. A pointer to the value of cap is returned on success, 0 if the |
164 |
|
|
* requested capability couldn't be found. |
165 |
|
|
* |
166 |
|
|
* Specifying a type of ':' means that nothing should follow cap (:cap:). In |
167 |
|
|
* this case a pointer to the terminating ':' or NUL will be returned if cap is |
168 |
|
|
* found. |
169 |
|
|
* |
170 |
|
|
* If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) |
171 |
|
|
* return 0. |
172 |
|
|
*/ |
173 |
|
|
static char * |
174 |
|
|
_nc_cgetcap(char *buf, const char *cap, int type) |
175 |
|
|
{ |
176 |
|
|
register const char *cp; |
177 |
|
|
register char *bp; |
178 |
|
|
|
179 |
|
|
bp = buf; |
180 |
|
|
for (;;) { |
181 |
|
|
/* |
182 |
|
|
* Skip past the current capability field - it's either the |
183 |
|
|
* name field if this is the first time through the loop, or |
184 |
|
|
* the remainder of a field whose name failed to match cap. |
185 |
|
|
*/ |
186 |
|
|
for (;;) { |
187 |
|
|
if (*bp == '\0') |
188 |
|
|
return (0); |
189 |
|
|
else if (*bp++ == ':') |
190 |
|
|
break; |
191 |
|
|
} |
192 |
|
|
|
193 |
|
|
/* |
194 |
|
|
* Try to match (cap, type) in buf. |
195 |
|
|
*/ |
196 |
|
|
for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++) |
197 |
|
|
continue; |
198 |
|
|
if (*cp != '\0') |
199 |
|
|
continue; |
200 |
|
|
if (*bp == '@') |
201 |
|
|
return (0); |
202 |
|
|
if (type == ':') { |
203 |
|
|
if (*bp != '\0' && *bp != ':') |
204 |
|
|
continue; |
205 |
|
|
return (bp); |
206 |
|
|
} |
207 |
|
|
if (*bp != type) |
208 |
|
|
continue; |
209 |
|
|
bp++; |
210 |
|
|
return (*bp == '@' ? 0 : bp); |
211 |
|
|
} |
212 |
|
|
/* NOTREACHED */ |
213 |
|
|
} |
214 |
|
|
|
215 |
|
|
/* |
216 |
|
|
* Cgetent extracts the capability record name from the NULL terminated file |
217 |
|
|
* array db_array and returns a pointer to a malloc'd copy of it in buf. Buf |
218 |
|
|
* must be retained through all subsequent calls to cgetcap, cgetnum, cgetflag, |
219 |
|
|
* and cgetstr, but may then be freed. |
220 |
|
|
* |
221 |
|
|
* Returns: |
222 |
|
|
* |
223 |
|
|
* positive # on success (i.e., the index in db_array) |
224 |
|
|
* TC_NOT_FOUND if the requested record couldn't be found |
225 |
|
|
* TC_SYS_ERR if a system error was encountered (e.g.,couldn't open a file) |
226 |
|
|
* TC_REF_LOOP if a potential reference loop is detected |
227 |
|
|
* TC_UNRESOLVED if we had too many recurrences to resolve |
228 |
|
|
*/ |
229 |
|
|
static int |
230 |
|
|
_nc_cgetent(char **buf, int *oline, char **db_array, const char *name) |
231 |
|
|
{ |
232 |
|
|
unsigned dummy; |
233 |
|
|
|
234 |
|
|
return (_nc_getent(buf, &dummy, oline, 0, db_array, -1, name, 0, 0)); |
235 |
|
|
} |
236 |
|
|
|
237 |
|
|
/* |
238 |
|
|
* Getent implements the functions of cgetent. If fd is non-negative, |
239 |
|
|
* *db_array has already been opened and fd is the open file descriptor. We |
240 |
|
|
* do this to save time and avoid using up file descriptors for tc= |
241 |
|
|
* recursions. |
242 |
|
|
* |
243 |
|
|
* Getent returns the same success/failure codes as cgetent. On success, a |
244 |
|
|
* pointer to a malloc'd capability record with all tc= capabilities fully |
245 |
|
|
* expanded and its length (not including trailing ASCII NUL) are left in |
246 |
|
|
* *cap and *len. |
247 |
|
|
* |
248 |
|
|
* Basic algorithm: |
249 |
|
|
* + Allocate memory incrementally as needed in chunks of size BFRAG |
250 |
|
|
* for capability buffer. |
251 |
|
|
* + Recurse for each tc=name and interpolate result. Stop when all |
252 |
|
|
* names interpolated, a name can't be found, or depth exceeds |
253 |
|
|
* MAX_RECURSION. |
254 |
|
|
*/ |
255 |
|
|
#define DOALLOC(size) typeRealloc(char, size, record) |
256 |
|
|
static int |
257 |
|
|
_nc_getent( |
258 |
|
|
char **cap, /* termcap-content */ |
259 |
|
|
unsigned *len, /* length, needed for recursion */ |
260 |
|
|
int *beginning, /* line-number at match */ |
261 |
|
|
int in_array, /* index in 'db_array[] */ |
262 |
|
|
char **db_array, /* list of files to search */ |
263 |
|
|
int fd, |
264 |
|
|
const char *name, |
265 |
|
|
int depth, |
266 |
|
|
char *nfield) |
267 |
|
|
{ |
268 |
|
|
register char *r_end, *rp; |
269 |
|
|
int myfd = FALSE; |
270 |
|
|
char *record = 0; |
271 |
|
|
int tc_not_resolved; |
272 |
|
|
int current; |
273 |
|
|
int lineno; |
274 |
|
|
|
275 |
|
|
/* |
276 |
|
|
* Return with ``loop detected'' error if we've recurred more than |
277 |
|
|
* MAX_RECURSION times. |
278 |
|
|
*/ |
279 |
|
|
if (depth > MAX_RECURSION) |
280 |
|
|
return (TC_REF_LOOP); |
281 |
|
|
|
282 |
|
|
/* |
283 |
|
|
* Check if we have a top record from cgetset(). |
284 |
|
|
*/ |
285 |
|
|
if (depth == 0 && toprec != 0 && _nc_cgetmatch(toprec, name) == 0) { |
286 |
|
|
if ((record = DOALLOC(topreclen + BFRAG)) == 0) { |
287 |
|
|
errno = ENOMEM; |
288 |
|
|
return (TC_SYS_ERR); |
289 |
|
|
} |
290 |
|
|
(void) strlcpy(record, toprec, topreclen + BFRAG); |
291 |
|
|
rp = record + topreclen + 1; |
292 |
|
|
r_end = rp + BFRAG; |
293 |
|
|
current = in_array; |
294 |
|
|
} else { |
295 |
|
|
int foundit; |
296 |
|
|
|
297 |
|
|
/* |
298 |
|
|
* Allocate first chunk of memory. |
299 |
|
|
*/ |
300 |
|
|
if ((record = DOALLOC(BFRAG)) == 0) { |
301 |
|
|
errno = ENOMEM; |
302 |
|
|
return (TC_SYS_ERR); |
303 |
|
|
} |
304 |
|
|
rp = r_end = record + BFRAG; |
305 |
|
|
foundit = FALSE; |
306 |
|
|
|
307 |
|
|
/* |
308 |
|
|
* Loop through database array until finding the record. |
309 |
|
|
*/ |
310 |
|
|
for (current = in_array; db_array[current] != 0; current++) { |
311 |
|
|
int eof = FALSE; |
312 |
|
|
|
313 |
|
|
/* |
314 |
|
|
* Open database if not already open. |
315 |
|
|
*/ |
316 |
|
|
if (fd >= 0) { |
317 |
|
|
(void) lseek(fd, (off_t) 0, SEEK_SET); |
318 |
|
|
} else if ((_nc_access(db_array[current], R_OK) < 0) |
319 |
|
|
|| (fd = open(db_array[current], O_RDONLY, 0)) < 0) { |
320 |
|
|
/* No error on unfound file. */ |
321 |
|
|
if (errno == ENOENT) |
322 |
|
|
continue; |
323 |
|
|
free(record); |
324 |
|
|
return (TC_SYS_ERR); |
325 |
|
|
} else { |
326 |
|
|
myfd = TRUE; |
327 |
|
|
} |
328 |
|
|
lineno = 0; |
329 |
|
|
|
330 |
|
|
/* |
331 |
|
|
* Find the requested capability record ... |
332 |
|
|
*/ |
333 |
|
|
{ |
334 |
|
|
char buf[2048]; |
335 |
|
|
register char *b_end = buf; |
336 |
|
|
register char *bp = buf; |
337 |
|
|
register int c; |
338 |
|
|
|
339 |
|
|
/* |
340 |
|
|
* Loop invariants: |
341 |
|
|
* There is always room for one more character in record. |
342 |
|
|
* R_end always points just past end of record. |
343 |
|
|
* Rp always points just past last character in record. |
344 |
|
|
* B_end always points just past last character in buf. |
345 |
|
|
* Bp always points at next character in buf. |
346 |
|
|
*/ |
347 |
|
|
|
348 |
|
|
for (;;) { |
349 |
|
|
int first = lineno + 1; |
350 |
|
|
|
351 |
|
|
/* |
352 |
|
|
* Read in a line implementing (\, newline) |
353 |
|
|
* line continuation. |
354 |
|
|
*/ |
355 |
|
|
rp = record; |
356 |
|
|
for (;;) { |
357 |
|
|
if (bp >= b_end) { |
358 |
|
|
int n; |
359 |
|
|
|
360 |
|
|
n = read(fd, buf, sizeof(buf)); |
361 |
|
|
if (n <= 0) { |
362 |
|
|
if (myfd) |
363 |
|
|
(void) close(fd); |
364 |
|
|
if (n < 0) { |
365 |
|
|
free(record); |
366 |
|
|
return (TC_SYS_ERR); |
367 |
|
|
} |
368 |
|
|
fd = -1; |
369 |
|
|
eof = TRUE; |
370 |
|
|
break; |
371 |
|
|
} |
372 |
|
|
b_end = buf + n; |
373 |
|
|
bp = buf; |
374 |
|
|
} |
375 |
|
|
|
376 |
|
|
c = *bp++; |
377 |
|
|
if (c == '\n') { |
378 |
|
|
lineno++; |
379 |
|
|
if (rp == record || *(rp - 1) != '\\') |
380 |
|
|
break; |
381 |
|
|
} |
382 |
|
|
*rp++ = c; |
383 |
|
|
|
384 |
|
|
/* |
385 |
|
|
* Enforce loop invariant: if no room |
386 |
|
|
* left in record buffer, try to get |
387 |
|
|
* some more. |
388 |
|
|
*/ |
389 |
|
|
if (rp >= r_end) { |
390 |
|
|
unsigned pos; |
391 |
|
|
size_t newsize; |
392 |
|
|
|
393 |
|
|
pos = rp - record; |
394 |
|
|
newsize = r_end - record + BFRAG; |
395 |
|
|
record = DOALLOC(newsize); |
396 |
|
|
if (record == 0) { |
397 |
|
|
if (myfd) |
398 |
|
|
(void) close(fd); |
399 |
|
|
errno = ENOMEM; |
400 |
|
|
return (TC_SYS_ERR); |
401 |
|
|
} |
402 |
|
|
r_end = record + newsize; |
403 |
|
|
rp = record + pos; |
404 |
|
|
} |
405 |
|
|
} |
406 |
|
|
/* loop invariant lets us do this */ |
407 |
|
|
*rp++ = '\0'; |
408 |
|
|
|
409 |
|
|
/* |
410 |
|
|
* If encountered eof check next file. |
411 |
|
|
*/ |
412 |
|
|
if (eof) |
413 |
|
|
break; |
414 |
|
|
|
415 |
|
|
/* |
416 |
|
|
* Toss blank lines and comments. |
417 |
|
|
*/ |
418 |
|
|
if (*record == '\0' || *record == '#') |
419 |
|
|
continue; |
420 |
|
|
|
421 |
|
|
/* |
422 |
|
|
* See if this is the record we want ... |
423 |
|
|
*/ |
424 |
|
|
if (_nc_cgetmatch(record, name) == 0 |
425 |
|
|
&& (nfield == 0 |
426 |
|
|
|| !_nc_nfcmp(nfield, record))) { |
427 |
|
|
foundit = TRUE; |
428 |
|
|
*beginning = first; |
429 |
|
|
break; /* found it! */ |
430 |
|
|
} |
431 |
|
|
} |
432 |
|
|
} |
433 |
|
|
if (foundit) |
434 |
|
|
break; |
435 |
|
|
} |
436 |
|
|
|
437 |
|
|
if (!foundit) |
438 |
|
|
return (TC_NOT_FOUND); |
439 |
|
|
} |
440 |
|
|
|
441 |
|
|
/* |
442 |
|
|
* Got the capability record, but now we have to expand all tc=name |
443 |
|
|
* references in it ... |
444 |
|
|
*/ |
445 |
|
|
{ |
446 |
|
|
register char *newicap, *s; |
447 |
|
|
register int newilen; |
448 |
|
|
unsigned ilen; |
449 |
|
|
int diff, iret, tclen, oline; |
450 |
|
|
char *icap, *scan, *tc, *tcstart, *tcend; |
451 |
|
|
|
452 |
|
|
/* |
453 |
|
|
* Loop invariants: |
454 |
|
|
* There is room for one more character in record. |
455 |
|
|
* R_end points just past end of record. |
456 |
|
|
* Rp points just past last character in record. |
457 |
|
|
* Scan points at remainder of record that needs to be |
458 |
|
|
* scanned for tc=name constructs. |
459 |
|
|
*/ |
460 |
|
|
scan = record; |
461 |
|
|
tc_not_resolved = FALSE; |
462 |
|
|
for (;;) { |
463 |
|
|
if ((tc = _nc_cgetcap(scan, "tc", '=')) == 0) |
464 |
|
|
break; |
465 |
|
|
|
466 |
|
|
/* |
467 |
|
|
* Find end of tc=name and stomp on the trailing `:' |
468 |
|
|
* (if present) so we can use it to call ourselves. |
469 |
|
|
*/ |
470 |
|
|
s = tc; |
471 |
|
|
while (*s != '\0') { |
472 |
|
|
if (*s++ == ':') { |
473 |
|
|
*(s - 1) = '\0'; |
474 |
|
|
break; |
475 |
|
|
} |
476 |
|
|
} |
477 |
|
|
tcstart = tc - 3; |
478 |
|
|
tclen = s - tcstart; |
479 |
|
|
tcend = s; |
480 |
|
|
|
481 |
|
|
iret = _nc_getent(&icap, &ilen, &oline, current, db_array, fd, |
482 |
|
|
tc, depth + 1, 0); |
483 |
|
|
newicap = icap; /* Put into a register. */ |
484 |
|
|
newilen = ilen; |
485 |
|
|
if (iret != TC_SUCCESS) { |
486 |
|
|
/* an error */ |
487 |
|
|
if (iret < TC_NOT_FOUND) { |
488 |
|
|
if (myfd) |
489 |
|
|
(void) close(fd); |
490 |
|
|
free(record); |
491 |
|
|
return (iret); |
492 |
|
|
} |
493 |
|
|
if (iret == TC_UNRESOLVED) |
494 |
|
|
tc_not_resolved = TRUE; |
495 |
|
|
/* couldn't resolve tc */ |
496 |
|
|
if (iret == TC_NOT_FOUND) { |
497 |
|
|
*(s - 1) = ':'; |
498 |
|
|
scan = s - 1; |
499 |
|
|
tc_not_resolved = TRUE; |
500 |
|
|
continue; |
501 |
|
|
} |
502 |
|
|
} |
503 |
|
|
|
504 |
|
|
/* not interested in name field of tc'ed record */ |
505 |
|
|
s = newicap; |
506 |
|
|
while (*s != '\0' && *s++ != ':') ; |
507 |
|
|
newilen -= s - newicap; |
508 |
|
|
newicap = s; |
509 |
|
|
|
510 |
|
|
/* make sure interpolated record is `:'-terminated */ |
511 |
|
|
s += newilen; |
512 |
|
|
if (*(s - 1) != ':') { |
513 |
|
|
*s = ':'; /* overwrite NUL with : */ |
514 |
|
|
newilen++; |
515 |
|
|
} |
516 |
|
|
|
517 |
|
|
/* |
518 |
|
|
* Make sure there's enough room to insert the |
519 |
|
|
* new record. |
520 |
|
|
*/ |
521 |
|
|
diff = newilen - tclen; |
522 |
|
|
if (diff >= r_end - rp) { |
523 |
|
|
unsigned pos, tcpos, tcposend; |
524 |
|
|
size_t newsize; |
525 |
|
|
|
526 |
|
|
pos = rp - record; |
527 |
|
|
newsize = r_end - record + diff + BFRAG; |
528 |
|
|
tcpos = tcstart - record; |
529 |
|
|
tcposend = tcend - record; |
530 |
|
|
record = DOALLOC(newsize); |
531 |
|
|
if (record == 0) { |
532 |
|
|
if (myfd) |
533 |
|
|
(void) close(fd); |
534 |
|
|
free(icap); |
535 |
|
|
errno = ENOMEM; |
536 |
|
|
return (TC_SYS_ERR); |
537 |
|
|
} |
538 |
|
|
r_end = record + newsize; |
539 |
|
|
rp = record + pos; |
540 |
|
|
tcstart = record + tcpos; |
541 |
|
|
tcend = record + tcposend; |
542 |
|
|
} |
543 |
|
|
|
544 |
|
|
/* |
545 |
|
|
* Insert tc'ed record into our record. |
546 |
|
|
*/ |
547 |
|
|
s = tcstart + newilen; |
548 |
|
|
memmove(s, tcend, (size_t) (rp - tcend)); |
549 |
|
|
memmove(tcstart, newicap, (size_t) newilen); |
550 |
|
|
rp += diff; |
551 |
|
|
free(icap); |
552 |
|
|
|
553 |
|
|
/* |
554 |
|
|
* Start scan on `:' so next cgetcap works properly |
555 |
|
|
* (cgetcap always skips first field). |
556 |
|
|
*/ |
557 |
|
|
scan = s - 1; |
558 |
|
|
} |
559 |
|
|
} |
560 |
|
|
|
561 |
|
|
/* |
562 |
|
|
* Close file (if we opened it), give back any extra memory, and |
563 |
|
|
* return capability, length and success. |
564 |
|
|
*/ |
565 |
|
|
if (myfd) |
566 |
|
|
(void) close(fd); |
567 |
|
|
*len = rp - record - 1; /* don't count NUL */ |
568 |
|
|
if (r_end > rp) { |
569 |
|
|
if ((record = DOALLOC((size_t) (rp - record))) == 0) { |
570 |
|
|
errno = ENOMEM; |
571 |
|
|
return (TC_SYS_ERR); |
572 |
|
|
} |
573 |
|
|
} |
574 |
|
|
|
575 |
|
|
*cap = record; |
576 |
|
|
if (tc_not_resolved) |
577 |
|
|
return (TC_UNRESOLVED); |
578 |
|
|
return (current); |
579 |
|
|
} |
580 |
|
|
|
581 |
|
|
/* |
582 |
|
|
* Cgetmatch will return 0 if name is one of the names of the capability |
583 |
|
|
* record buf, -1 if not. |
584 |
|
|
*/ |
585 |
|
|
static int |
586 |
|
|
_nc_cgetmatch(char *buf, const char *name) |
587 |
|
|
{ |
588 |
|
|
register const char *np; |
589 |
|
|
register char *bp; |
590 |
|
|
|
591 |
|
|
/* |
592 |
|
|
* Start search at beginning of record. |
593 |
|
|
*/ |
594 |
|
|
bp = buf; |
595 |
|
|
for (;;) { |
596 |
|
|
/* |
597 |
|
|
* Try to match a record name. |
598 |
|
|
*/ |
599 |
|
|
np = name; |
600 |
|
|
for (;;) { |
601 |
|
|
if (*np == '\0') { |
602 |
|
|
if (*bp == '|' || *bp == ':' || *bp == '\0') |
603 |
|
|
return (0); |
604 |
|
|
else |
605 |
|
|
break; |
606 |
|
|
} else if (*bp++ != *np++) { |
607 |
|
|
break; |
608 |
|
|
} |
609 |
|
|
} |
610 |
|
|
|
611 |
|
|
/* |
612 |
|
|
* Match failed, skip to next name in record. |
613 |
|
|
*/ |
614 |
|
|
bp--; /* a '|' or ':' may have stopped the match */ |
615 |
|
|
for (;;) { |
616 |
|
|
if (*bp == '\0' || *bp == ':') |
617 |
|
|
return (-1); /* match failed totally */ |
618 |
|
|
else if (*bp++ == '|') |
619 |
|
|
break; /* found next name */ |
620 |
|
|
} |
621 |
|
|
} |
622 |
|
|
} |
623 |
|
|
|
624 |
|
|
/* |
625 |
|
|
* Compare name field of record. |
626 |
|
|
*/ |
627 |
|
|
static int |
628 |
|
|
_nc_nfcmp(const char *nf, char *rec) |
629 |
|
|
{ |
630 |
|
|
char *cp, tmp; |
631 |
|
|
int ret; |
632 |
|
|
|
633 |
|
|
for (cp = rec; *cp != ':'; cp++) ; |
634 |
|
|
|
635 |
|
|
tmp = *(cp + 1); |
636 |
|
|
*(cp + 1) = '\0'; |
637 |
|
|
ret = strcmp(nf, rec); |
638 |
|
|
*(cp + 1) = tmp; |
639 |
|
|
|
640 |
|
|
return (ret); |
641 |
|
|
} |
642 |
|
|
#endif /* HAVE_BSD_CGETENT */ |
643 |
|
|
|
644 |
|
|
/* |
645 |
|
|
* Since ncurses provides its own 'tgetent()', we cannot use the native one. |
646 |
|
|
* So we reproduce the logic to get down to cgetent() -- or our cut-down |
647 |
|
|
* version of that -- to circumvent the problem of configuring against the |
648 |
|
|
* termcap library. |
649 |
|
|
*/ |
650 |
|
|
#define USE_BSD_TGETENT 1 |
651 |
|
|
|
652 |
|
|
#if USE_BSD_TGETENT |
653 |
|
|
/* |
654 |
|
|
* Copyright (c) 1980, 1993 |
655 |
|
|
* The Regents of the University of California. All rights reserved. |
656 |
|
|
* |
657 |
|
|
* Redistribution and use in source and binary forms, with or without |
658 |
|
|
* modification, are permitted provided that the following conditions |
659 |
|
|
* are met: |
660 |
|
|
* 1. Redistributions of source code must retain the above copyright |
661 |
|
|
* notice, this list of conditions and the following disclaimer. |
662 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
663 |
|
|
* notice, this list of conditions and the following disclaimer in the |
664 |
|
|
* documentation and/or other materials provided with the distribution. |
665 |
|
|
* 3. All advertising materials mentioning features or use of this software |
666 |
|
|
* must display the following acknowledgment: |
667 |
|
|
* This product includes software developed by the University of |
668 |
|
|
* California, Berkeley and its contributors. |
669 |
|
|
* 4. Neither the name of the University nor the names of its contributors |
670 |
|
|
* may be used to endorse or promote products derived from this software |
671 |
|
|
* without specific prior written permission. |
672 |
|
|
* |
673 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
674 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
675 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
676 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
677 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
678 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
679 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
680 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
681 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
682 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
683 |
|
|
* SUCH DAMAGE. |
684 |
|
|
*/ |
685 |
|
|
|
686 |
|
|
#define PBUFSIZ 512 /* max length of filename path */ |
687 |
|
|
#define PVECSIZ 32 /* max number of names in path */ |
688 |
|
|
#define TBUFSIZ (2048*2) |
689 |
|
|
|
690 |
|
|
static char *tbuf; |
691 |
|
|
|
692 |
|
|
/* |
693 |
|
|
* On entry, srcp points to a non ':' character which is the beginning of the |
694 |
|
|
* token, if any. We'll try to return a string that doesn't end with a ':'. |
695 |
|
|
*/ |
696 |
|
|
static char * |
697 |
|
|
get_tc_token(char **srcp, int *endp) |
698 |
|
|
{ |
699 |
|
|
int ch; |
700 |
|
|
bool found = FALSE; |
701 |
|
|
char *s, *base; |
702 |
|
|
char *tok = 0; |
703 |
|
|
|
704 |
|
|
*endp = TRUE; |
705 |
|
|
for (s = base = *srcp; *s != '\0';) { |
706 |
|
|
ch = *s++; |
707 |
|
|
if (ch == '\\') { |
708 |
|
|
if (*s == '\0') { |
709 |
|
|
break; |
710 |
|
|
} else if (*s++ == '\n') { |
711 |
|
|
while (isspace(UChar(*s))) |
712 |
|
|
s++; |
713 |
|
|
} else { |
714 |
|
|
found = TRUE; |
715 |
|
|
} |
716 |
|
|
} else if (ch == ':') { |
717 |
|
|
if (found) { |
718 |
|
|
tok = base; |
719 |
|
|
s[-1] = '\0'; |
720 |
|
|
*srcp = s; |
721 |
|
|
*endp = FALSE; |
722 |
|
|
break; |
723 |
|
|
} |
724 |
|
|
base = s; |
725 |
|
|
} else if (isgraph(UChar(ch))) { |
726 |
|
|
found = TRUE; |
727 |
|
|
} |
728 |
|
|
} |
729 |
|
|
|
730 |
|
|
/* malformed entry may end without a ':' */ |
731 |
|
|
if (tok == 0 && found) { |
732 |
|
|
tok = base; |
733 |
|
|
} |
734 |
|
|
|
735 |
|
|
return tok; |
736 |
|
|
} |
737 |
|
|
|
738 |
|
|
static char * |
739 |
|
|
copy_tc_token(char *dst, const char *src, size_t len) |
740 |
|
|
{ |
741 |
|
|
int ch; |
742 |
|
|
|
743 |
|
|
while ((ch = *src++) != '\0') { |
744 |
|
|
if (ch == '\\' && *src == '\n') { |
745 |
|
|
while (isspace(UChar(*src))) |
746 |
|
|
src++; |
747 |
|
|
continue; |
748 |
|
|
} |
749 |
|
|
if (--len == 0) { |
750 |
|
|
dst = 0; |
751 |
|
|
break; |
752 |
|
|
} |
753 |
|
|
*dst++ = ch; |
754 |
|
|
} |
755 |
|
|
return dst; |
756 |
|
|
} |
757 |
|
|
|
758 |
|
|
/* |
759 |
|
|
* Get an entry for terminal name in buffer bp from the termcap file. |
760 |
|
|
*/ |
761 |
|
|
static int |
762 |
|
|
_nc_tgetent(char *bp, char **sourcename, int *lineno, const char *name) |
763 |
|
|
{ |
764 |
|
|
static char *the_source; |
765 |
|
|
register char *p; |
766 |
|
|
register char *cp; |
767 |
|
|
char *dummy = NULL; |
768 |
|
|
char **fname; |
769 |
|
|
char *home; |
770 |
|
|
int i; |
771 |
|
|
char pathbuf[PBUFSIZ]; /* holds raw path of filenames */ |
772 |
|
|
char *pathvec[PVECSIZ]; /* to point to names in pathbuf */ |
773 |
|
|
char **pvec; /* holds usable tail of path vector */ |
774 |
|
|
NCURSES_CONST char *termpath; |
775 |
|
|
string_desc desc; |
776 |
|
|
|
777 |
|
|
fname = pathvec; |
778 |
|
|
pvec = pathvec; |
779 |
|
|
tbuf = bp; |
780 |
|
|
p = pathbuf; |
781 |
|
|
cp = use_terminfo_vars()? getenv("TERMCAP") : NULL; |
782 |
|
|
|
783 |
|
|
/* |
784 |
|
|
* TERMCAP can have one of two things in it. It can be the name of a file |
785 |
|
|
* to use instead of /etc/termcap. In this case it better start with a |
786 |
|
|
* "/". Or it can be an entry to use so we don't have to read the file. |
787 |
|
|
* In this case it has to already have the newlines crunched out. If |
788 |
|
|
* TERMCAP does not hold a file name then a path of names is searched |
789 |
|
|
* instead. The path is found in the TERMPATH variable, or becomes |
790 |
|
|
* "$HOME/.termcap /etc/termcap" if no TERMPATH exists. |
791 |
|
|
*/ |
792 |
|
|
_nc_str_init(&desc, pathbuf, sizeof(pathbuf)); |
793 |
|
|
if (cp == NULL) { |
794 |
|
|
_nc_safe_strcpy(&desc, get_termpath()); |
795 |
|
|
} else if (!_nc_is_abs_path(cp)) { /* TERMCAP holds an entry */ |
796 |
|
|
if ((termpath = get_termpath()) != 0) { |
797 |
|
|
_nc_safe_strcat(&desc, termpath); |
798 |
|
|
} else { |
799 |
|
|
char temp[PBUFSIZ]; |
800 |
|
|
temp[0] = 0; |
801 |
|
|
if ((home = getenv("HOME")) != 0 && *home != '\0' |
802 |
|
|
&& strchr(home, ' ') == 0 |
803 |
|
|
&& strlen(home) < sizeof(temp) - 10) { /* setup path */ |
804 |
|
|
snprintf(temp, sizeof(temp), "%s/", home); /* $HOME first */ |
805 |
|
|
} |
806 |
|
|
/* if no $HOME look in current directory */ |
807 |
|
|
strlcat(temp, ".termcap", sizeof temp); |
808 |
|
|
_nc_safe_strcat(&desc, temp); |
809 |
|
|
_nc_safe_strcat(&desc, " "); |
810 |
|
|
_nc_safe_strcat(&desc, get_termpath()); |
811 |
|
|
} |
812 |
|
|
} else { /* user-defined name in TERMCAP */ |
813 |
|
|
_nc_safe_strcat(&desc, cp); /* still can be tokenized */ |
814 |
|
|
} |
815 |
|
|
|
816 |
|
|
*fname++ = pathbuf; /* tokenize path into vector of names */ |
817 |
|
|
while (*++p) { |
818 |
|
|
if (*p == ' ' || *p == NCURSES_PATHSEP) { |
819 |
|
|
*p = '\0'; |
820 |
|
|
while (*++p) |
821 |
|
|
if (*p != ' ' && *p != NCURSES_PATHSEP) |
822 |
|
|
break; |
823 |
|
|
if (*p == '\0') |
824 |
|
|
break; |
825 |
|
|
*fname++ = p; |
826 |
|
|
if (fname >= pathvec + PVECSIZ) { |
827 |
|
|
fname--; |
828 |
|
|
break; |
829 |
|
|
} |
830 |
|
|
} |
831 |
|
|
} |
832 |
|
|
*fname = 0; /* mark end of vector */ |
833 |
|
|
if (_nc_is_abs_path(cp)) { |
834 |
|
|
if (_nc_cgetset(cp) < 0) { |
835 |
|
|
return (TC_SYS_ERR); |
836 |
|
|
} |
837 |
|
|
} |
838 |
|
|
|
839 |
|
|
i = _nc_cgetent(&dummy, lineno, pathvec, name); |
840 |
|
|
|
841 |
|
|
/* ncurses' termcap-parsing routines cannot handle multiple adjacent |
842 |
|
|
* empty fields, and mistakenly use the last valid cap entry instead of |
843 |
|
|
* the first (breaks tc= includes) |
844 |
|
|
*/ |
845 |
|
|
if (i >= 0) { |
846 |
|
|
char *pd, *ps, *tok; |
847 |
|
|
int endflag = FALSE; |
848 |
|
|
char *list[1023]; |
849 |
|
|
size_t n, count = 0; |
850 |
|
|
|
851 |
|
|
pd = bp; |
852 |
|
|
ps = dummy; |
853 |
|
|
while (!endflag && (tok = get_tc_token(&ps, &endflag)) != 0) { |
854 |
|
|
bool ignore = FALSE; |
855 |
|
|
|
856 |
|
|
for (n = 1; n < count; n++) { |
857 |
|
|
char *s = list[n]; |
858 |
|
|
if (s[0] == tok[0] |
859 |
|
|
&& s[1] == tok[1]) { |
860 |
|
|
ignore = TRUE; |
861 |
|
|
break; |
862 |
|
|
} |
863 |
|
|
} |
864 |
|
|
if (ignore != TRUE) { |
865 |
|
|
list[count++] = tok; |
866 |
|
|
pd = copy_tc_token(pd, tok, TBUFSIZ - (2 + pd - bp)); |
867 |
|
|
if (pd == 0) { |
868 |
|
|
i = -1; |
869 |
|
|
break; |
870 |
|
|
} |
871 |
|
|
*pd++ = ':'; |
872 |
|
|
*pd = '\0'; |
873 |
|
|
} |
874 |
|
|
} |
875 |
|
|
} |
876 |
|
|
|
877 |
|
|
FreeIfNeeded(dummy); |
878 |
|
|
FreeIfNeeded(the_source); |
879 |
|
|
the_source = 0; |
880 |
|
|
|
881 |
|
|
/* This is not related to the BSD cgetent(), but to fake up a suitable |
882 |
|
|
* filename for ncurses' error reporting. (If we are not using BSD |
883 |
|
|
* cgetent, then it is the actual filename). |
884 |
|
|
*/ |
885 |
|
|
if (i >= 0) { |
886 |
|
|
#if HAVE_BSD_CGETENT |
887 |
|
|
char temp[PATH_MAX]; |
888 |
|
|
|
889 |
|
|
_nc_str_init(&desc, temp, sizeof(temp)); |
890 |
|
|
_nc_safe_strcpy(&desc, pathvec[i]); |
891 |
|
|
_nc_safe_strcat(&desc, ".db"); |
892 |
|
|
if (_nc_access(temp, R_OK) == 0) { |
893 |
|
|
_nc_safe_strcpy(&desc, pathvec[i]); |
894 |
|
|
} |
895 |
|
|
if ((the_source = strdup(temp)) != 0) |
896 |
|
|
*sourcename = the_source; |
897 |
|
|
#else |
898 |
|
|
if ((the_source = strdup(pathvec[i])) != 0) |
899 |
|
|
*sourcename = the_source; |
900 |
|
|
#endif |
901 |
|
|
} |
902 |
|
|
|
903 |
|
|
return (i); |
904 |
|
|
} |
905 |
|
|
#endif /* USE_BSD_TGETENT */ |
906 |
|
|
#endif /* USE_GETCAP */ |
907 |
|
|
|
908 |
|
|
#define MAXPATHS 32 |
909 |
|
|
|
910 |
|
|
/* |
911 |
|
|
* Add a filename to the list in 'termpaths[]', checking that we really have |
912 |
|
|
* a right to open the file. |
913 |
|
|
*/ |
914 |
|
|
#if !USE_GETCAP |
915 |
|
|
static int |
916 |
|
|
add_tc(char *termpaths[], char *path, int count) |
917 |
|
|
{ |
918 |
|
|
char *save = strchr(path, NCURSES_PATHSEP); |
919 |
|
|
if (save != 0) |
920 |
|
|
*save = '\0'; |
921 |
|
|
if (count < MAXPATHS |
922 |
|
|
&& _nc_access(path, R_OK) == 0) { |
923 |
|
|
termpaths[count++] = path; |
924 |
|
|
T(("Adding termpath %s", path)); |
925 |
|
|
} |
926 |
|
|
termpaths[count] = 0; |
927 |
|
|
if (save != 0) |
928 |
|
|
*save = NCURSES_PATHSEP; |
929 |
|
|
return count; |
930 |
|
|
} |
931 |
|
|
#define ADD_TC(path, count) filecount = add_tc(termpaths, path, count) |
932 |
|
|
#endif /* !USE_GETCAP */ |
933 |
|
|
|
934 |
|
|
NCURSES_EXPORT(int) |
935 |
|
|
_nc_read_termcap_entry(const char *const tn, TERMTYPE *const tp) |
936 |
|
|
{ |
937 |
|
|
int found = TGETENT_NO; |
938 |
|
|
ENTRY *ep; |
939 |
|
|
#if USE_GETCAP_CACHE |
940 |
|
|
char cwd_buf[PATH_MAX]; |
941 |
|
|
#endif |
942 |
|
|
#if USE_GETCAP |
943 |
|
|
char *p, tc[TBUFSIZ]; |
944 |
|
|
int status; |
945 |
|
|
static char *source; |
946 |
|
|
static int lineno; |
947 |
|
|
|
948 |
|
|
T(("read termcap entry for %s", tn)); |
949 |
|
|
|
950 |
|
|
if (strlen(tn) == 0 |
951 |
|
|
|| strcmp(tn, ".") == 0 |
952 |
|
|
|| strcmp(tn, "..") == 0 |
953 |
|
|
|| _nc_pathlast(tn) != 0) { |
954 |
|
|
T(("illegal or missing entry name '%s'", tn)); |
955 |
|
|
return TGETENT_NO; |
956 |
|
|
} |
957 |
|
|
|
958 |
|
|
if (use_terminfo_vars() && (p = getenv("TERMCAP")) != 0 |
959 |
|
|
&& !_nc_is_abs_path(p) && _nc_name_match(p, tn, "|:")) { |
960 |
|
|
/* TERMCAP holds a termcap entry */ |
961 |
|
|
strncpy(tc, p, sizeof(tc) - 1); |
962 |
|
|
tc[sizeof(tc) - 1] = '\0'; |
963 |
|
|
_nc_set_source("TERMCAP"); |
964 |
|
|
} else { |
965 |
|
|
/* we're using getcap(3) */ |
966 |
|
|
if ((status = _nc_tgetent(tc, &source, &lineno, tn)) < 0) |
967 |
|
|
return (status == TC_NOT_FOUND ? TGETENT_NO : TGETENT_ERR); |
968 |
|
|
|
969 |
|
|
_nc_curr_line = lineno; |
970 |
|
|
_nc_set_source(source); |
971 |
|
|
} |
972 |
|
|
_nc_read_entry_source((FILE *) 0, tc, FALSE, FALSE, NULLHOOK); |
973 |
|
|
#else |
974 |
|
|
/* |
975 |
|
|
* Here is what the 4.4BSD termcap(3) page prescribes: |
976 |
|
|
* |
977 |
|
|
* It will look in the environment for a TERMCAP variable. If found, and |
978 |
|
|
* the value does not begin with a slash, and the terminal type name is the |
979 |
|
|
* same as the environment string TERM, the TERMCAP string is used instead |
980 |
|
|
* of reading a termcap file. If it does begin with a slash, the string is |
981 |
|
|
* used as a path name of the termcap file to search. If TERMCAP does not |
982 |
|
|
* begin with a slash and name is different from TERM, tgetent() searches |
983 |
|
|
* the files $HOME/.termcap and /usr/share/misc/termcap, in that order, |
984 |
|
|
* unless the environment variable TERMPATH exists, in which case it |
985 |
|
|
* specifies a list of file pathnames (separated by spaces or colons) to be |
986 |
|
|
* searched instead. |
987 |
|
|
* |
988 |
|
|
* It goes on to state: |
989 |
|
|
* |
990 |
|
|
* Whenever multiple files are searched and a tc field occurs in the |
991 |
|
|
* requested entry, the entry it names must be found in the same file or |
992 |
|
|
* one of the succeeding files. |
993 |
|
|
* |
994 |
|
|
* However, this restriction is relaxed in ncurses; tc references to |
995 |
|
|
* previous files are permitted. |
996 |
|
|
* |
997 |
|
|
* This routine returns 1 if an entry is found, 0 if not found, and -1 if |
998 |
|
|
* the database is not accessible. |
999 |
|
|
*/ |
1000 |
|
|
FILE *fp; |
1001 |
|
|
char *tc, *termpaths[MAXPATHS]; |
1002 |
|
|
int filecount = 0; |
1003 |
|
|
int j, k; |
1004 |
|
|
bool use_buffer = FALSE; |
1005 |
|
|
bool normal = TRUE; |
1006 |
|
|
char tc_buf[1024]; |
1007 |
|
|
char pathbuf[PATH_MAX]; |
1008 |
|
|
char *copied = 0; |
1009 |
|
|
char *cp; |
1010 |
|
|
struct stat test_stat[MAXPATHS]; |
1011 |
|
|
|
1012 |
|
|
termpaths[filecount] = 0; |
1013 |
|
|
if (use_terminfo_vars() && (tc = getenv("TERMCAP")) != 0) { |
1014 |
|
|
if (_nc_is_abs_path(tc)) { /* interpret as a filename */ |
1015 |
|
|
ADD_TC(tc, 0); |
1016 |
|
|
normal = FALSE; |
1017 |
|
|
} else if (_nc_name_match(tc, tn, "|:")) { /* treat as a capability file */ |
1018 |
|
|
use_buffer = TRUE; |
1019 |
|
|
(void) snprintf(tc_buf, sizeof(tc_buf), "%.*s\n", (int) sizeof(tc_buf) - 2, tc); |
1020 |
|
|
normal = FALSE; |
1021 |
|
|
} |
1022 |
|
|
} |
1023 |
|
|
|
1024 |
|
|
if (normal) { /* normal case */ |
1025 |
|
|
char envhome[PATH_MAX], *h; |
1026 |
|
|
|
1027 |
|
|
copied = strdup(get_termpath()); |
1028 |
|
|
for (cp = copied; *cp; cp++) { |
1029 |
|
|
if (*cp == NCURSES_PATHSEP) |
1030 |
|
|
*cp = '\0'; |
1031 |
|
|
else if (cp == copied || cp[-1] == '\0') { |
1032 |
|
|
ADD_TC(cp, filecount); |
1033 |
|
|
} |
1034 |
|
|
} |
1035 |
|
|
|
1036 |
|
|
#define PRIVATE_CAP "%s/.termcap" |
1037 |
|
|
|
1038 |
|
|
if (use_terminfo_vars() && (h = getenv("HOME")) != NULL && *h != '\0' |
1039 |
|
|
&& (strlen(h) + sizeof(PRIVATE_CAP)) < PATH_MAX) { |
1040 |
|
|
/* user's .termcap, if any, should override it */ |
1041 |
|
|
(void) strlcpy(envhome, h, sizeof(envhome); |
1042 |
|
|
(void) snprintf(pathbuf, sizeof(pathbuf), PRIVATE_CAP, envhome); |
1043 |
|
|
ADD_TC(pathbuf, filecount); |
1044 |
|
|
} |
1045 |
|
|
} |
1046 |
|
|
|
1047 |
|
|
/* |
1048 |
|
|
* Probably /etc/termcap is a symlink to /usr/share/misc/termcap. |
1049 |
|
|
* Avoid reading the same file twice. |
1050 |
|
|
*/ |
1051 |
|
|
#if HAVE_LINK |
1052 |
|
|
for (j = 0; j < filecount; j++) { |
1053 |
|
|
bool omit = FALSE; |
1054 |
|
|
if (stat(termpaths[j], &test_stat[j]) != 0 |
1055 |
|
|
|| (test_stat[j].st_mode & S_IFMT) != S_IFREG) { |
1056 |
|
|
omit = TRUE; |
1057 |
|
|
} else { |
1058 |
|
|
for (k = 0; k < j; k++) { |
1059 |
|
|
if (test_stat[k].st_dev == test_stat[j].st_dev |
1060 |
|
|
&& test_stat[k].st_ino == test_stat[j].st_ino) { |
1061 |
|
|
omit = TRUE; |
1062 |
|
|
break; |
1063 |
|
|
} |
1064 |
|
|
} |
1065 |
|
|
} |
1066 |
|
|
if (omit) { |
1067 |
|
|
T(("Path %s is a duplicate", termpaths[j])); |
1068 |
|
|
for (k = j + 1; k < filecount; k++) { |
1069 |
|
|
termpaths[k - 1] = termpaths[k]; |
1070 |
|
|
test_stat[k - 1] = test_stat[k]; |
1071 |
|
|
} |
1072 |
|
|
--filecount; |
1073 |
|
|
--j; |
1074 |
|
|
} |
1075 |
|
|
} |
1076 |
|
|
#endif |
1077 |
|
|
|
1078 |
|
|
/* parse the sources */ |
1079 |
|
|
if (use_buffer) { |
1080 |
|
|
_nc_set_source("TERMCAP"); |
1081 |
|
|
|
1082 |
|
|
/* |
1083 |
|
|
* We don't suppress warning messages here. The presumption is |
1084 |
|
|
* that since it's just a single entry, they won't be a pain. |
1085 |
|
|
*/ |
1086 |
|
|
_nc_read_entry_source((FILE *) 0, tc_buf, FALSE, FALSE, NULLHOOK); |
1087 |
|
|
} else { |
1088 |
|
|
int i; |
1089 |
|
|
|
1090 |
|
|
for (i = 0; i < filecount; i++) { |
1091 |
|
|
|
1092 |
|
|
T(("Looking for %s in %s", tn, termpaths[i])); |
1093 |
|
|
if (_nc_access(termpaths[i], R_OK) == 0 |
1094 |
|
|
&& (fp = fopen(termpaths[i], "r")) != (FILE *) 0) { |
1095 |
|
|
_nc_set_source(termpaths[i]); |
1096 |
|
|
|
1097 |
|
|
/* |
1098 |
|
|
* Suppress warning messages. Otherwise you get 400 lines of |
1099 |
|
|
* crap from archaic termcap files as ncurses complains about |
1100 |
|
|
* all the obsolete capabilities. |
1101 |
|
|
*/ |
1102 |
|
|
_nc_read_entry_source(fp, (char *) 0, FALSE, TRUE, NULLHOOK); |
1103 |
|
|
|
1104 |
|
|
(void) fclose(fp); |
1105 |
|
|
} |
1106 |
|
|
} |
1107 |
|
|
} |
1108 |
|
|
if (copied != 0) |
1109 |
|
|
free(copied); |
1110 |
|
|
#endif /* USE_GETCAP */ |
1111 |
|
|
|
1112 |
|
|
if (_nc_head == 0) |
1113 |
|
|
return (TGETENT_ERR); |
1114 |
|
|
|
1115 |
|
|
/* resolve all use references */ |
1116 |
|
|
_nc_resolve_uses2(TRUE, FALSE); |
1117 |
|
|
|
1118 |
|
|
/* find a terminal matching tn, if we can */ |
1119 |
|
|
#if USE_GETCAP_CACHE |
1120 |
|
|
if (getcwd(cwd_buf, sizeof(cwd_buf)) != 0) { |
1121 |
|
|
_nc_set_writedir((char *) 0); /* note: this does a chdir */ |
1122 |
|
|
#endif |
1123 |
|
|
for_entry_list(ep) { |
1124 |
|
|
if (_nc_name_match(ep->tterm.term_names, tn, "|:")) { |
1125 |
|
|
/* |
1126 |
|
|
* Make a local copy of the terminal capabilities, delinked |
1127 |
|
|
* from the list. |
1128 |
|
|
*/ |
1129 |
|
|
*tp = ep->tterm; |
1130 |
|
|
_nc_delink_entry(_nc_head, &(ep->tterm)); |
1131 |
|
|
free(ep); |
1132 |
|
|
|
1133 |
|
|
/* |
1134 |
|
|
* OK, now try to write the type to user's terminfo directory. |
1135 |
|
|
* Next time he loads this, it will come through terminfo. |
1136 |
|
|
* |
1137 |
|
|
* Advantage: Second and subsequent fetches of this entry will |
1138 |
|
|
* be very fast. |
1139 |
|
|
* |
1140 |
|
|
* Disadvantage: After the first time a termcap type is loaded |
1141 |
|
|
* by its user, editing it in the /etc/termcap file, or in |
1142 |
|
|
* TERMCAP, or in a local ~/.termcap, will be ineffective |
1143 |
|
|
* unless the terminfo entry is explicitly removed. |
1144 |
|
|
*/ |
1145 |
|
|
#if USE_GETCAP_CACHE |
1146 |
|
|
(void) _nc_write_entry(tp); |
1147 |
|
|
#endif |
1148 |
|
|
found = TGETENT_YES; |
1149 |
|
|
break; |
1150 |
|
|
} |
1151 |
|
|
} |
1152 |
|
|
#if USE_GETCAP_CACHE |
1153 |
|
|
chdir(cwd_buf); |
1154 |
|
|
} |
1155 |
|
|
#endif |
1156 |
|
|
|
1157 |
|
|
return (found); |
1158 |
|
|
} |
1159 |
|
|
#else |
1160 |
|
|
extern |
1161 |
|
|
NCURSES_EXPORT(void) |
1162 |
|
|
_nc_read_termcap(void); |
1163 |
|
|
NCURSES_EXPORT(void) |
1164 |
|
|
_nc_read_termcap(void) |
1165 |
|
|
{ |
1166 |
|
|
} |
1167 |
|
|
#endif /* PURE_TERMINFO */ |