Annotation of src/lib/libterminfo/term.c, Revision 1.21.2.2
1.21.2.2! pgoyette 1: /* $NetBSD: term.c,v 1.28 2017/05/16 12:03:41 roy 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.21.2.2! pgoyette 31: __RCSID("$NetBSD: term.c,v 1.28 2017/05/16 12:03:41 roy 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:
1.21.2.2! pgoyette 49: static char __ti_database[PATH_MAX];
1.1 roy 50: const char *_ti_database;
51:
1.9 roy 52: /* Include a generated list of pre-compiled terminfo descriptions. */
53: #include "compiled_terms.c"
1.5 roy 54:
1.1 roy 55: static int
1.18 christos 56: allocset(void *pp, int init, size_t nelem, size_t elemsize)
57: {
58: void **p = pp;
59: if (*p) {
60: memset(*p, init, nelem * elemsize);
61: return 0;
62: }
63:
64: if ((*p = calloc(nelem, elemsize)) == NULL)
65: return -1;
66:
67: if (init != 0)
68: memset(*p, init, nelem * elemsize);
69: return 0;
70: }
71:
72: static int
1.5 roy 73: _ti_readterm(TERMINAL *term, const char *cap, size_t caplen, int flags)
1.1 roy 74: {
1.21.2.1 pgoyette 75: char ver;
1.1 roy 76: uint16_t ind, num;
77: size_t len;
78: TERMUSERDEF *ud;
79:
1.20 christos 80: if (caplen == 0)
81: goto out;
1.3 roy 82: ver = *cap++;
1.20 christos 83: caplen--;
1.15 joerg 84: /* Only read version 1 structures */
1.20 christos 85: if (ver != 1)
86: goto out;
1.1 roy 87:
1.21 roy 88: if (allocset(&term->flags, 0, TIFLAGMAX+1, sizeof(*term->flags)) == -1)
1.13 roy 89: return -1;
1.18 christos 90:
1.21 roy 91: if (allocset(&term->nums, -1, TINUMMAX+1, sizeof(*term->nums)) == -1)
1.13 roy 92: return -1;
1.18 christos 93:
1.21 roy 94: if (allocset(&term->strs, 0, TISTRMAX+1, sizeof(*term->strs)) == -1)
1.13 roy 95: return -1;
1.18 christos 96:
97: if (term->_arealen != caplen) {
98: term->_arealen = caplen;
99: term->_area = realloc(term->_area, term->_arealen);
100: if (term->_area == NULL)
101: return -1;
102: }
1.19 christos 103: memcpy(term->_area, cap, term->_arealen);
1.1 roy 104:
105: cap = term->_area;
106: len = le16dec(cap);
107: cap += sizeof(uint16_t);
108: term->name = cap;
109: cap += len;
1.15 joerg 110: len = le16dec(cap);
111: cap += sizeof(uint16_t);
112: if (len == 0)
1.3 roy 113: term->_alias = NULL;
114: else {
1.15 joerg 115: term->_alias = cap;
116: cap += len;
1.3 roy 117: }
1.1 roy 118: len = le16dec(cap);
119: cap += sizeof(uint16_t);
1.6 roy 120: if (len == 0)
121: term->desc = NULL;
122: else {
123: term->desc = cap;
124: cap += len;
125: }
1.1 roy 126:
127: num = le16dec(cap);
128: cap += sizeof(uint16_t);
129: if (num != 0) {
130: num = le16dec(cap);
131: cap += sizeof(uint16_t);
132: for (; num != 0; num--) {
133: ind = le16dec(cap);
134: cap += sizeof(uint16_t);
135: term->flags[ind] = *cap++;
136: if (flags == 0 && !VALID_BOOLEAN(term->flags[ind]))
137: term->flags[ind] = 0;
138: }
139: }
1.17 roy 140:
1.1 roy 141: num = le16dec(cap);
142: cap += sizeof(uint16_t);
143: if (num != 0) {
144: num = le16dec(cap);
145: cap += sizeof(uint16_t);
146: for (; num != 0; num--) {
147: ind = le16dec(cap);
148: cap += sizeof(uint16_t);
1.21.2.1 pgoyette 149: term->nums[ind] = (short)le16dec(cap);
1.1 roy 150: if (flags == 0 && !VALID_NUMERIC(term->nums[ind]))
151: term->nums[ind] = ABSENT_NUMERIC;
152: cap += sizeof(uint16_t);
153: }
154: }
1.17 roy 155:
1.1 roy 156: num = le16dec(cap);
157: cap += sizeof(uint16_t);
158: if (num != 0) {
159: num = le16dec(cap);
160: cap += sizeof(uint16_t);
161: for (; num != 0; num--) {
162: ind = le16dec(cap);
163: cap += sizeof(uint16_t);
164: len = le16dec(cap);
165: cap += sizeof(uint16_t);
166: if (len > 0)
167: term->strs[ind] = cap;
168: else if (flags == 0)
169: term->strs[ind] = ABSENT_STRING;
170: else
171: term->strs[ind] = CANCELLED_STRING;
172: cap += len;
173: }
174: }
1.17 roy 175:
1.1 roy 176: num = le16dec(cap);
177: cap += sizeof(uint16_t);
178: if (num != 0) {
1.18 christos 179: num = le16dec(cap);
1.1 roy 180: cap += sizeof(uint16_t);
1.18 christos 181: if (num != term->_nuserdefs) {
182: free(term->_userdefs);
183: term->_userdefs = NULL;
184: term->_nuserdefs = num;
185: }
186: if (allocset(&term->_userdefs, 0, term->_nuserdefs,
187: sizeof(*term->_userdefs)) == -1)
188: return -1;
1.1 roy 189: for (num = 0; num < term->_nuserdefs; num++) {
190: ud = &term->_userdefs[num];
191: len = le16dec(cap);
192: cap += sizeof(uint16_t);
193: ud->id = cap;
194: cap += len;
195: ud->type = *cap++;
196: switch (ud->type) {
197: case 'f':
198: ud->flag = *cap++;
199: if (flags == 0 &&
200: !VALID_BOOLEAN(ud->flag))
201: ud->flag = 0;
202: ud->num = ABSENT_NUMERIC;
203: ud->str = ABSENT_STRING;
204: break;
205: case 'n':
206: ud->flag = ABSENT_BOOLEAN;
1.21.2.1 pgoyette 207: ud->num = (short)le16dec(cap);
1.1 roy 208: if (flags == 0 &&
209: !VALID_NUMERIC(ud->num))
210: ud->num = ABSENT_NUMERIC;
211: ud->str = ABSENT_STRING;
212: cap += sizeof(uint16_t);
213: break;
214: case 's':
215: ud->flag = ABSENT_BOOLEAN;
216: ud->num = ABSENT_NUMERIC;
217: len = le16dec(cap);
218: cap += sizeof(uint16_t);
219: if (len > 0)
220: ud->str = cap;
221: else if (flags == 0)
222: ud->str = ABSENT_STRING;
223: else
224: ud->str = CANCELLED_STRING;
225: cap += len;
226: break;
227: default:
1.20 christos 228: goto out;
1.1 roy 229: }
230: }
1.18 christos 231: } else {
232: term->_nuserdefs = 0;
233: if (term->_userdefs) {
234: free(term->_userdefs);
235: term->_userdefs = NULL;
236: }
1.1 roy 237: }
1.18 christos 238:
1.1 roy 239: return 1;
1.20 christos 240: out:
241: errno = EINVAL;
242: return -1;
1.1 roy 243: }
244:
245: static int
1.21.2.2! pgoyette 246: _ti_checkname(const char *name, const char *termname, const char *termalias)
! 247: {
! 248: const char *alias, *s;
! 249: size_t len, l;
! 250:
! 251: /* Check terminal name matches. */
! 252: if (strcmp(termname, name) == 0)
! 253: return 1;
! 254:
! 255: /* Check terminal aliases match. */
! 256: if (termalias == NULL)
! 257: return 0;
! 258:
! 259: len = strlen(name);
! 260: alias = termalias;
! 261: while (*alias != '\0') {
! 262: s = strchr(alias, '|');
! 263: if (s == NULL)
! 264: l = strlen(alias);
! 265: else
! 266: l = (size_t)(s - alias);
! 267: if (len == l && memcmp(alias, name, l) == 0)
! 268: return 1;
! 269: if (s == NULL)
! 270: break;
! 271: alias = s + 1;
! 272: }
! 273:
! 274: /* No match. */
! 275: return 0;
! 276: }
! 277:
! 278: static int
1.1 roy 279: _ti_dbgetterm(TERMINAL *term, const char *path, const char *name, int flags)
280: {
1.15 joerg 281: struct cdbr *db;
282: const void *data;
283: const uint8_t *data8;
284: size_t len, klen;
1.1 roy 285: int r;
286:
1.21.2.2! pgoyette 287: if (snprintf(__ti_database, sizeof(__ti_database), "%s.cdb", path) < 0)
1.15 joerg 288: return -1;
1.21.2.2! pgoyette 289: db = cdbr_open(__ti_database, CDBR_DEFAULT);
1.1 roy 290: if (db == NULL)
291: return -1;
1.15 joerg 292:
1.21.2.2! pgoyette 293: r = 0;
1.15 joerg 294: klen = strlen(name) + 1;
295: if (cdbr_find(db, name, klen, &data, &len) == -1)
1.21.2.2! pgoyette 296: goto out;
1.15 joerg 297: data8 = data;
298: if (len == 0)
1.21.2.2! pgoyette 299: goto out;
! 300:
! 301: /* If the entry is an alias, load the indexed terminfo description. */
1.15 joerg 302: if (data8[0] == 2) {
303: if (cdbr_get(db, le32dec(data8 + 1), &data, &len))
1.21.2.2! pgoyette 304: goto out;
1.15 joerg 305: data8 = data;
1.21.2.2! pgoyette 306: }
1.1 roy 307:
1.15 joerg 308: r = _ti_readterm(term, data, len, flags);
1.21.2.2! pgoyette 309: /* Ensure that this is the right terminfo description. */
! 310: if (r == 1)
! 311: r = _ti_checkname(name, term->name, term->_alias);
! 312: /* Remember the database we read. */
! 313: if (r == 1)
! 314: _ti_database = __ti_database;
1.15 joerg 315:
1.21.2.2! pgoyette 316: out:
1.15 joerg 317: cdbr_close(db);
1.21.2.2! pgoyette 318: return r;
1.1 roy 319: }
320:
321: static int
322: _ti_dbgettermp(TERMINAL *term, const char *path, const char *name, int flags)
323: {
324: const char *p;
1.21.2.2! pgoyette 325: char pathbuf[PATH_MAX];
1.1 roy 326: size_t l;
327: int r, e;
328:
329: e = -1;
330: r = 0;
331: do {
332: for (p = path; *path != '\0' && *path != ':'; path++)
333: continue;
1.21.2.1 pgoyette 334: l = (size_t)(path - p);
1.1 roy 335: if (l != 0 && l + 1 < sizeof(pathbuf)) {
336: memcpy(pathbuf, p, l);
337: pathbuf[l] = '\0';
338: r = _ti_dbgetterm(term, pathbuf, name, flags);
339: if (r == 1)
340: return 1;
341: if (r == 0)
342: e = 0;
343: }
344: } while (*path++ == ':');
345: return e;
346: }
347:
1.8 roy 348: static int
349: _ti_findterm(TERMINAL *term, const char *name, int flags)
1.1 roy 350: {
351: int r;
1.21.2.2! pgoyette 352: char *c, *e;
1.1 roy 353:
354: _DIAGASSERT(term != NULL);
355: _DIAGASSERT(name != NULL);
356:
357: _ti_database = NULL;
1.10 roy 358: r = 0;
1.5 roy 359:
1.21 roy 360: if ((e = getenv("TERMINFO")) != NULL && *e != '\0') {
1.8 roy 361: if (e[0] == '/')
362: return _ti_dbgetterm(term, e, name, flags);
1.21 roy 363: }
1.11 roy 364:
365: c = NULL;
366: if (e == NULL && (c = getenv("TERMCAP")) != NULL) {
367: if (*c != '\0' && *c != '/') {
368: c = strdup(c);
369: if (c != NULL) {
370: e = captoinfo(c);
371: free(c);
372: }
373: }
374: }
375:
376: if (e != NULL) {
1.21.2.2! pgoyette 377: TIC *tic;
! 378:
1.11 roy 379: if (c == NULL)
380: e = strdup(e); /* So we don't destroy env */
1.18 christos 381: if (e == NULL)
1.11 roy 382: tic = NULL;
1.18 christos 383: else {
1.11 roy 384: tic = _ti_compile(e, TIC_WARNING |
385: TIC_ALIAS | TIC_DESCRIPTION | TIC_EXTRA);
386: free(e);
1.18 christos 387: }
1.21.2.2! pgoyette 388: if (tic != NULL &&
! 389: _ti_checkname(name, tic->name, tic->alias) == 1)
! 390: {
! 391: uint8_t *f;
! 392: ssize_t len;
! 393:
1.10 roy 394: len = _ti_flatten(&f, tic);
395: if (len != -1) {
1.12 roy 396: r = _ti_readterm(term, (char *)f, (size_t)len,
397: flags);
1.10 roy 398: free(f);
399: }
400: }
401: _ti_freetic(tic);
402: if (r == 1) {
1.11 roy 403: if (c == NULL)
404: _ti_database = "$TERMINFO";
405: else
406: _ti_database = "$TERMCAP";
1.10 roy 407: return r;
408: }
1.8 roy 409: }
1.1 roy 410:
1.8 roy 411: if ((e = getenv("TERMINFO_DIRS")) != NULL)
412: return _ti_dbgettermp(term, e, name, flags);
413:
414: if ((e = getenv("HOME")) != NULL) {
1.21.2.2! pgoyette 415: char homepath[PATH_MAX];
! 416:
! 417: if (snprintf(homepath, sizeof(homepath), "%s/.terminfo", e) > 0)
! 418: r = _ti_dbgetterm(term, homepath, name, flags);
1.1 roy 419: }
1.8 roy 420: if (r != 1)
421: r = _ti_dbgettermp(term, _PATH_TERMINFO, name, flags);
1.4 roy 422:
1.8 roy 423: return r;
424: }
425:
426: int
427: _ti_getterm(TERMINAL *term, const char *name, int flags)
428: {
429: int r;
430: size_t i;
431: const struct compiled_term *t;
432:
433: r = _ti_findterm(term, name, flags);
1.4 roy 434: if (r == 1)
1.10 roy 435: return r;
1.4 roy 436:
1.7 roy 437: for (i = 0; i < __arraycount(compiled_terms); i++) {
438: t = &compiled_terms[i];
439: if (strcmp(name, t->name) == 0) {
440: r = _ti_readterm(term, t->cap, t->caplen, flags);
1.5 roy 441: break;
442: }
1.7 roy 443: }
1.5 roy 444:
1.4 roy 445: return r;
1.1 roy 446: }
CVSweb <webmaster@jp.NetBSD.org>