Annotation of src/lib/libterminfo/term.c, Revision 1.19.2.1
1.19.2.1! pgoyette 1: /* $NetBSD: term.c,v 1.20 2016/11/24 17:09:55 christos Exp $ */
1.1 roy 2:
3: /*
1.12 roy 4: * Copyright (c) 2009, 2010, 2011 The NetBSD Foundation, Inc.
1.1 roy 5: *
6: * This code is derived from software contributed to The NetBSD Foundation
7: * by Roy Marples.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28: */
29:
30: #include <sys/cdefs.h>
1.19.2.1! pgoyette 31: __RCSID("$NetBSD: term.c,v 1.20 2016/11/24 17:09:55 christos Exp $");
1.1 roy 32:
33: #include <sys/stat.h>
34:
35: #include <assert.h>
1.15 joerg 36: #include <cdbr.h>
1.1 roy 37: #include <ctype.h>
38: #include <errno.h>
39: #include <fcntl.h>
40: #include <limits.h>
41: #include <stdio.h>
42: #include <stdlib.h>
43: #include <string.h>
44: #include <term_private.h>
45: #include <term.h>
46:
1.8 roy 47: #define _PATH_TERMINFO "/usr/share/misc/terminfo"
1.1 roy 48:
49: static char database[PATH_MAX];
50: static char pathbuf[PATH_MAX];
51: const char *_ti_database;
52:
1.9 roy 53: /* Include a generated list of pre-compiled terminfo descriptions. */
54: #include "compiled_terms.c"
1.5 roy 55:
1.1 roy 56: static int
1.18 christos 57: allocset(void *pp, int init, size_t nelem, size_t elemsize)
58: {
59: void **p = pp;
60: if (*p) {
61: memset(*p, init, nelem * elemsize);
62: return 0;
63: }
64:
65: if ((*p = calloc(nelem, elemsize)) == NULL)
66: return -1;
67:
68: if (init != 0)
69: memset(*p, init, nelem * elemsize);
70: return 0;
71: }
72:
73: static int
1.5 roy 74: _ti_readterm(TERMINAL *term, const char *cap, size_t caplen, int flags)
1.1 roy 75: {
1.3 roy 76: uint8_t ver;
1.1 roy 77: uint16_t ind, num;
78: size_t len;
79: TERMUSERDEF *ud;
80:
1.19.2.1! pgoyette 81: if (caplen == 0)
! 82: goto out;
1.3 roy 83: ver = *cap++;
1.19.2.1! pgoyette 84: caplen--;
1.15 joerg 85: /* Only read version 1 structures */
1.19.2.1! pgoyette 86: if (ver != 1)
! 87: goto out;
1.1 roy 88:
1.18 christos 89:
90: if (allocset(&term->flags, 0, TIFLAGMAX + 1, sizeof(*term->flags)) == -1)
1.13 roy 91: return -1;
1.18 christos 92:
93: if (allocset(&term->nums, -1, TINUMMAX + 1, sizeof(*term->nums)) == -1)
1.13 roy 94: return -1;
1.18 christos 95:
96: if (allocset(&term->strs, 0, TISTRMAX + 1, sizeof(*term->strs)) == -1)
1.13 roy 97: return -1;
1.18 christos 98:
99: if (term->_arealen != caplen) {
100: term->_arealen = caplen;
101: term->_area = realloc(term->_area, term->_arealen);
102: if (term->_area == NULL)
103: return -1;
104: }
1.19 christos 105: memcpy(term->_area, cap, term->_arealen);
1.1 roy 106:
107: cap = term->_area;
108: len = le16dec(cap);
109: cap += sizeof(uint16_t);
110: term->name = cap;
111: cap += len;
1.15 joerg 112: len = le16dec(cap);
113: cap += sizeof(uint16_t);
114: if (len == 0)
1.3 roy 115: term->_alias = NULL;
116: else {
1.15 joerg 117: term->_alias = cap;
118: cap += len;
1.3 roy 119: }
1.1 roy 120: len = le16dec(cap);
121: cap += sizeof(uint16_t);
1.6 roy 122: if (len == 0)
123: term->desc = NULL;
124: else {
125: term->desc = cap;
126: cap += len;
127: }
1.1 roy 128:
129: num = le16dec(cap);
130: cap += sizeof(uint16_t);
131: if (num != 0) {
132: num = le16dec(cap);
133: cap += sizeof(uint16_t);
134: for (; num != 0; num--) {
135: ind = le16dec(cap);
136: cap += sizeof(uint16_t);
137: term->flags[ind] = *cap++;
138: if (flags == 0 && !VALID_BOOLEAN(term->flags[ind]))
139: term->flags[ind] = 0;
140: }
141: }
1.17 roy 142:
1.1 roy 143: num = le16dec(cap);
144: cap += sizeof(uint16_t);
145: if (num != 0) {
146: num = le16dec(cap);
147: cap += sizeof(uint16_t);
148: for (; num != 0; num--) {
149: ind = le16dec(cap);
150: cap += sizeof(uint16_t);
151: term->nums[ind] = le16dec(cap);
152: if (flags == 0 && !VALID_NUMERIC(term->nums[ind]))
153: term->nums[ind] = ABSENT_NUMERIC;
154: cap += sizeof(uint16_t);
155: }
156: }
1.17 roy 157:
1.1 roy 158: num = le16dec(cap);
159: cap += sizeof(uint16_t);
160: if (num != 0) {
161: num = le16dec(cap);
162: cap += sizeof(uint16_t);
163: for (; num != 0; num--) {
164: ind = le16dec(cap);
165: cap += sizeof(uint16_t);
166: len = le16dec(cap);
167: cap += sizeof(uint16_t);
168: if (len > 0)
169: term->strs[ind] = cap;
170: else if (flags == 0)
171: term->strs[ind] = ABSENT_STRING;
172: else
173: term->strs[ind] = CANCELLED_STRING;
174: cap += len;
175: }
176: }
1.17 roy 177:
1.1 roy 178: num = le16dec(cap);
179: cap += sizeof(uint16_t);
180: if (num != 0) {
1.18 christos 181: num = le16dec(cap);
1.1 roy 182: cap += sizeof(uint16_t);
1.18 christos 183: if (num != term->_nuserdefs) {
184: free(term->_userdefs);
185: term->_userdefs = NULL;
186: term->_nuserdefs = num;
187: }
188: if (allocset(&term->_userdefs, 0, term->_nuserdefs,
189: sizeof(*term->_userdefs)) == -1)
190: return -1;
1.1 roy 191: for (num = 0; num < term->_nuserdefs; num++) {
192: ud = &term->_userdefs[num];
193: len = le16dec(cap);
194: cap += sizeof(uint16_t);
195: ud->id = cap;
196: cap += len;
197: ud->type = *cap++;
198: switch (ud->type) {
199: case 'f':
200: ud->flag = *cap++;
201: if (flags == 0 &&
202: !VALID_BOOLEAN(ud->flag))
203: ud->flag = 0;
204: ud->num = ABSENT_NUMERIC;
205: ud->str = ABSENT_STRING;
206: break;
207: case 'n':
208: ud->flag = ABSENT_BOOLEAN;
209: ud->num = le16dec(cap);
210: if (flags == 0 &&
211: !VALID_NUMERIC(ud->num))
212: ud->num = ABSENT_NUMERIC;
213: ud->str = ABSENT_STRING;
214: cap += sizeof(uint16_t);
215: break;
216: case 's':
217: ud->flag = ABSENT_BOOLEAN;
218: ud->num = ABSENT_NUMERIC;
219: len = le16dec(cap);
220: cap += sizeof(uint16_t);
221: if (len > 0)
222: ud->str = cap;
223: else if (flags == 0)
224: ud->str = ABSENT_STRING;
225: else
226: ud->str = CANCELLED_STRING;
227: cap += len;
228: break;
229: default:
1.19.2.1! pgoyette 230: goto out;
1.1 roy 231: }
232: }
1.18 christos 233: } else {
234: term->_nuserdefs = 0;
235: if (term->_userdefs) {
236: free(term->_userdefs);
237: term->_userdefs = NULL;
238: }
1.1 roy 239: }
1.18 christos 240:
1.1 roy 241: return 1;
1.19.2.1! pgoyette 242: out:
! 243: errno = EINVAL;
! 244: return -1;
1.1 roy 245: }
246:
247: static int
248: _ti_dbgetterm(TERMINAL *term, const char *path, const char *name, int flags)
249: {
1.15 joerg 250: struct cdbr *db;
251: const void *data;
252: char *db_name;
253: const uint8_t *data8;
254: size_t len, klen;
1.1 roy 255: int r;
256:
1.15 joerg 257: if (asprintf(&db_name, "%s.cdb", path) < 0)
258: return -1;
259:
260: db = cdbr_open(db_name, CDBR_DEFAULT);
261: free(db_name);
1.1 roy 262: if (db == NULL)
263: return -1;
1.15 joerg 264:
265: klen = strlen(name) + 1;
266: if (cdbr_find(db, name, klen, &data, &len) == -1)
267: goto fail;
268: data8 = data;
269: if (len == 0)
270: goto fail;
271: /* Check for alias first, fall through to processing normal entries. */
272: if (data8[0] == 2) {
1.16 joerg 273: if (klen + 7 > len || le16dec(data8 + 5) != klen)
1.15 joerg 274: goto fail;
275: if (memcmp(data8 + 7, name, klen))
276: goto fail;
277: if (cdbr_get(db, le32dec(data8 + 1), &data, &len))
278: goto fail;
279: data8 = data;
280: if (data8[0] != 1)
281: goto fail;
1.17 roy 282: } else if (data8[0] != 1)
1.15 joerg 283: goto fail;
284: else if (klen + 3 >= len || le16dec(data8 + 1) != klen)
285: goto fail;
286: else if (memcmp(data8 + 3, name, klen))
287: goto fail;
288:
1.1 roy 289: strlcpy(database, path, sizeof(database));
290: _ti_database = database;
291:
1.15 joerg 292: r = _ti_readterm(term, data, len, flags);
293: cdbr_close(db);
1.1 roy 294: return r;
1.15 joerg 295:
296: fail:
297: cdbr_close(db);
298: return 0;
1.1 roy 299: }
300:
301: static int
302: _ti_dbgettermp(TERMINAL *term, const char *path, const char *name, int flags)
303: {
304: const char *p;
305: size_t l;
306: int r, e;
307:
308: e = -1;
309: r = 0;
310: do {
311: for (p = path; *path != '\0' && *path != ':'; path++)
312: continue;
313: l = path - p;
314: if (l != 0 && l + 1 < sizeof(pathbuf)) {
315: memcpy(pathbuf, p, l);
316: pathbuf[l] = '\0';
317: r = _ti_dbgetterm(term, pathbuf, name, flags);
318: if (r == 1)
319: return 1;
320: if (r == 0)
321: e = 0;
322: }
323: } while (*path++ == ':');
324: return e;
325: }
326:
1.8 roy 327: static int
1.11 roy 328: ticcmp(const TIC *tic, const char *name)
329: {
330: char *alias, *s;
331: size_t len, l;
332:
333: if (strcmp(tic->name, name) == 0)
334: return 0;
335: if (tic->alias == NULL)
336: return -1;
337:
338: len = strlen(name);
339: alias = tic->alias;
340: while (*alias != '\0') {
341: s = strchr(alias, '|');
342: if (s == NULL)
343: l = strlen(alias);
344: else
345: l = s - alias;
1.14 joerg 346: if (len == l && memcmp(alias, name, l) == 0)
1.11 roy 347: return 0;
348: if (s == NULL)
349: break;
350: alias = s + 1;
351: }
352: return 1;
353: }
354:
355: static int
1.8 roy 356: _ti_findterm(TERMINAL *term, const char *name, int flags)
1.1 roy 357: {
358: int r;
1.10 roy 359: char *c, *e, h[PATH_MAX];
360: TIC *tic;
361: uint8_t *f;
362: ssize_t len;
1.1 roy 363:
364: _DIAGASSERT(term != NULL);
365: _DIAGASSERT(name != NULL);
366:
1.4 roy 367: database[0] = '\0';
1.1 roy 368: _ti_database = NULL;
1.10 roy 369: r = 0;
1.5 roy 370:
1.11 roy 371: if ((e = getenv("TERMINFO")) != NULL && *e != '\0')
1.8 roy 372: if (e[0] == '/')
373: return _ti_dbgetterm(term, e, name, flags);
1.11 roy 374:
375: c = NULL;
376: if (e == NULL && (c = getenv("TERMCAP")) != NULL) {
377: if (*c != '\0' && *c != '/') {
378: c = strdup(c);
379: if (c != NULL) {
380: e = captoinfo(c);
381: free(c);
382: }
383: }
384: }
385:
386: if (e != NULL) {
387: if (c == NULL)
388: e = strdup(e); /* So we don't destroy env */
1.18 christos 389: if (e == NULL)
1.11 roy 390: tic = NULL;
1.18 christos 391: else {
1.11 roy 392: tic = _ti_compile(e, TIC_WARNING |
393: TIC_ALIAS | TIC_DESCRIPTION | TIC_EXTRA);
394: free(e);
1.18 christos 395: }
1.11 roy 396: if (tic != NULL && ticcmp(tic, name) == 0) {
1.10 roy 397: len = _ti_flatten(&f, tic);
398: if (len != -1) {
1.12 roy 399: r = _ti_readterm(term, (char *)f, (size_t)len,
400: flags);
1.10 roy 401: free(f);
402: }
403: }
404: _ti_freetic(tic);
405: if (r == 1) {
1.11 roy 406: if (c == NULL)
407: _ti_database = "$TERMINFO";
408: else
409: _ti_database = "$TERMCAP";
1.10 roy 410: return r;
411: }
1.8 roy 412: }
1.1 roy 413:
1.8 roy 414: if ((e = getenv("TERMINFO_DIRS")) != NULL)
415: return _ti_dbgettermp(term, e, name, flags);
416:
417: if ((e = getenv("HOME")) != NULL) {
1.1 roy 418: snprintf(h, sizeof(h), "%s/.terminfo", e);
419: r = _ti_dbgetterm(term, h, name, flags);
420: }
1.8 roy 421: if (r != 1)
422: r = _ti_dbgettermp(term, _PATH_TERMINFO, name, flags);
1.4 roy 423:
1.8 roy 424: return r;
425:
426: }
427:
428: int
429: _ti_getterm(TERMINAL *term, const char *name, int flags)
430: {
431: int r;
432: size_t i;
433: const struct compiled_term *t;
434:
435: r = _ti_findterm(term, name, flags);
1.4 roy 436: if (r == 1)
1.10 roy 437: return r;
1.4 roy 438:
1.7 roy 439: for (i = 0; i < __arraycount(compiled_terms); i++) {
440: t = &compiled_terms[i];
441: if (strcmp(name, t->name) == 0) {
442: r = _ti_readterm(term, t->cap, t->caplen, flags);
1.5 roy 443: break;
444: }
1.7 roy 445: }
1.5 roy 446:
1.4 roy 447: return r;
1.1 roy 448: }
CVSweb <webmaster@jp.NetBSD.org>