tools/llvm: Do not build with symbols
[minix3.git] / lib / libterminfo / term.c
blob840d03c87cd453730cbede6cd4a79ff662dde9a4
1 /* $NetBSD: term.c,v 1.17 2013/06/07 13:16:18 roy Exp $ */
3 /*
4 * Copyright (c) 2009, 2010, 2011 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Roy Marples.
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.
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.
30 #include <sys/cdefs.h>
31 __RCSID("$NetBSD: term.c,v 1.17 2013/06/07 13:16:18 roy Exp $");
33 #include <sys/stat.h>
35 #include <assert.h>
36 #include <cdbr.h>
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>
47 #if !defined(__minix)
48 #define _PATH_TERMINFO "/usr/share/misc/terminfo"
49 #else
50 #define _PATH_TERMINFO "/usr/share/terminfo/terminfo"
51 #endif /* !defined(__minix) */
53 static char database[PATH_MAX];
54 static char pathbuf[PATH_MAX];
55 const char *_ti_database;
57 /* Include a generated list of pre-compiled terminfo descriptions. */
58 #include "compiled_terms.c"
60 static int
61 _ti_readterm(TERMINAL *term, const char *cap, size_t caplen, int flags)
63 uint8_t ver;
64 uint16_t ind, num;
65 size_t len;
66 TERMUSERDEF *ud;
68 ver = *cap++;
69 /* Only read version 1 structures */
70 if (ver != 1) {
71 errno = EINVAL;
72 return -1;
75 term->flags = calloc(TIFLAGMAX + 1, sizeof(char));
76 if (term->flags == NULL)
77 return -1;
78 term->nums = malloc((TINUMMAX + 1) * sizeof(short));
79 if (term->nums == NULL)
80 return -1;
81 memset(term->nums, (short)-1, (TINUMMAX + 1) * sizeof(short));
82 term->strs = calloc(TISTRMAX + 1, sizeof(char *));
83 if (term->strs == NULL)
84 return -1;
85 term->_arealen = caplen;
86 term->_area = malloc(term->_arealen);
87 if (term->_area == NULL)
88 return -1;
89 memcpy(term->_area, cap, term->_arealen);
91 cap = term->_area;
92 len = le16dec(cap);
93 cap += sizeof(uint16_t);
94 term->name = cap;
95 cap += len;
96 len = le16dec(cap);
97 cap += sizeof(uint16_t);
98 if (len == 0)
99 term->_alias = NULL;
100 else {
101 term->_alias = cap;
102 cap += len;
104 len = le16dec(cap);
105 cap += sizeof(uint16_t);
106 if (len == 0)
107 term->desc = NULL;
108 else {
109 term->desc = cap;
110 cap += len;
113 num = le16dec(cap);
114 cap += sizeof(uint16_t);
115 if (num != 0) {
116 num = le16dec(cap);
117 cap += sizeof(uint16_t);
118 for (; num != 0; num--) {
119 ind = le16dec(cap);
120 cap += sizeof(uint16_t);
121 term->flags[ind] = *cap++;
122 if (flags == 0 && !VALID_BOOLEAN(term->flags[ind]))
123 term->flags[ind] = 0;
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->nums[ind] = le16dec(cap);
136 if (flags == 0 && !VALID_NUMERIC(term->nums[ind]))
137 term->nums[ind] = ABSENT_NUMERIC;
138 cap += sizeof(uint16_t);
142 num = le16dec(cap);
143 cap += sizeof(uint16_t);
144 if (num != 0) {
145 num = le16dec(cap);
146 cap += sizeof(uint16_t);
147 for (; num != 0; num--) {
148 ind = le16dec(cap);
149 cap += sizeof(uint16_t);
150 len = le16dec(cap);
151 cap += sizeof(uint16_t);
152 if (len > 0)
153 term->strs[ind] = cap;
154 else if (flags == 0)
155 term->strs[ind] = ABSENT_STRING;
156 else
157 term->strs[ind] = CANCELLED_STRING;
158 cap += len;
162 num = le16dec(cap);
163 cap += sizeof(uint16_t);
164 if (num != 0) {
165 term->_nuserdefs = le16dec(cap);
166 term->_userdefs = malloc(sizeof(*term->_userdefs) * num);
167 cap += sizeof(uint16_t);
168 for (num = 0; num < term->_nuserdefs; num++) {
169 ud = &term->_userdefs[num];
170 len = le16dec(cap);
171 cap += sizeof(uint16_t);
172 ud->id = cap;
173 cap += len;
174 ud->type = *cap++;
175 switch (ud->type) {
176 case 'f':
177 ud->flag = *cap++;
178 if (flags == 0 &&
179 !VALID_BOOLEAN(ud->flag))
180 ud->flag = 0;
181 ud->num = ABSENT_NUMERIC;
182 ud->str = ABSENT_STRING;
183 break;
184 case 'n':
185 ud->flag = ABSENT_BOOLEAN;
186 ud->num = le16dec(cap);
187 if (flags == 0 &&
188 !VALID_NUMERIC(ud->num))
189 ud->num = ABSENT_NUMERIC;
190 ud->str = ABSENT_STRING;
191 cap += sizeof(uint16_t);
192 break;
193 case 's':
194 ud->flag = ABSENT_BOOLEAN;
195 ud->num = ABSENT_NUMERIC;
196 len = le16dec(cap);
197 cap += sizeof(uint16_t);
198 if (len > 0)
199 ud->str = cap;
200 else if (flags == 0)
201 ud->str = ABSENT_STRING;
202 else
203 ud->str = CANCELLED_STRING;
204 cap += len;
205 break;
206 default:
207 errno = EINVAL;
208 return -1;
212 return 1;
215 static int
216 _ti_dbgetterm(TERMINAL *term, const char *path, const char *name, int flags)
218 struct cdbr *db;
219 const void *data;
220 char *db_name;
221 const uint8_t *data8;
222 size_t len, klen;
223 int r;
225 if (asprintf(&db_name, "%s.cdb", path) < 0)
226 return -1;
228 db = cdbr_open(db_name, CDBR_DEFAULT);
229 free(db_name);
230 if (db == NULL)
231 return -1;
233 klen = strlen(name) + 1;
234 if (cdbr_find(db, name, klen, &data, &len) == -1)
235 goto fail;
236 data8 = data;
237 if (len == 0)
238 goto fail;
239 /* Check for alias first, fall through to processing normal entries. */
240 if (data8[0] == 2) {
241 if (klen + 7 > len || le16dec(data8 + 5) != klen)
242 goto fail;
243 if (memcmp(data8 + 7, name, klen))
244 goto fail;
245 if (cdbr_get(db, le32dec(data8 + 1), &data, &len))
246 goto fail;
247 data8 = data;
248 if (data8[0] != 1)
249 goto fail;
250 } else if (data8[0] != 1)
251 goto fail;
252 else if (klen + 3 >= len || le16dec(data8 + 1) != klen)
253 goto fail;
254 else if (memcmp(data8 + 3, name, klen))
255 goto fail;
257 strlcpy(database, path, sizeof(database));
258 _ti_database = database;
260 r = _ti_readterm(term, data, len, flags);
261 cdbr_close(db);
262 return r;
264 fail:
265 cdbr_close(db);
266 return 0;
269 static int
270 _ti_dbgettermp(TERMINAL *term, const char *path, const char *name, int flags)
272 const char *p;
273 size_t l;
274 int r, e;
276 e = -1;
277 r = 0;
278 do {
279 for (p = path; *path != '\0' && *path != ':'; path++)
280 continue;
281 l = path - p;
282 if (l != 0 && l + 1 < sizeof(pathbuf)) {
283 memcpy(pathbuf, p, l);
284 pathbuf[l] = '\0';
285 r = _ti_dbgetterm(term, pathbuf, name, flags);
286 if (r == 1)
287 return 1;
288 if (r == 0)
289 e = 0;
291 } while (*path++ == ':');
292 return e;
295 static int
296 ticcmp(const TIC *tic, const char *name)
298 char *alias, *s;
299 size_t len, l;
301 if (strcmp(tic->name, name) == 0)
302 return 0;
303 if (tic->alias == NULL)
304 return -1;
306 len = strlen(name);
307 alias = tic->alias;
308 while (*alias != '\0') {
309 s = strchr(alias, '|');
310 if (s == NULL)
311 l = strlen(alias);
312 else
313 l = s - alias;
314 if (len == l && memcmp(alias, name, l) == 0)
315 return 0;
316 if (s == NULL)
317 break;
318 alias = s + 1;
320 return 1;
323 static int
324 _ti_findterm(TERMINAL *term, const char *name, int flags)
326 int r;
327 char *c, *e, h[PATH_MAX];
328 TIC *tic;
329 uint8_t *f;
330 ssize_t len;
332 _DIAGASSERT(term != NULL);
333 _DIAGASSERT(name != NULL);
335 database[0] = '\0';
336 _ti_database = NULL;
337 r = 0;
339 if ((e = getenv("TERMINFO")) != NULL && *e != '\0')
340 if (e[0] == '/')
341 return _ti_dbgetterm(term, e, name, flags);
343 c = NULL;
344 if (e == NULL && (c = getenv("TERMCAP")) != NULL) {
345 if (*c != '\0' && *c != '/') {
346 c = strdup(c);
347 if (c != NULL) {
348 e = captoinfo(c);
349 free(c);
354 if (e != NULL) {
355 if (c == NULL)
356 e = strdup(e); /* So we don't destroy env */
357 if (e == NULL)
358 tic = NULL;
359 else
360 tic = _ti_compile(e, TIC_WARNING |
361 TIC_ALIAS | TIC_DESCRIPTION | TIC_EXTRA);
362 if (c == NULL && e != NULL)
363 free(e);
364 if (tic != NULL && ticcmp(tic, name) == 0) {
365 len = _ti_flatten(&f, tic);
366 if (len != -1) {
367 r = _ti_readterm(term, (char *)f, (size_t)len,
368 flags);
369 free(f);
372 _ti_freetic(tic);
373 if (r == 1) {
374 if (c == NULL)
375 _ti_database = "$TERMINFO";
376 else
377 _ti_database = "$TERMCAP";
378 return r;
382 if ((e = getenv("TERMINFO_DIRS")) != NULL)
383 return _ti_dbgettermp(term, e, name, flags);
385 if ((e = getenv("HOME")) != NULL) {
386 snprintf(h, sizeof(h), "%s/.terminfo", e);
387 r = _ti_dbgetterm(term, h, name, flags);
389 if (r != 1)
390 r = _ti_dbgettermp(term, _PATH_TERMINFO, name, flags);
392 return r;
397 _ti_getterm(TERMINAL *term, const char *name, int flags)
399 int r;
400 size_t i;
401 const struct compiled_term *t;
403 r = _ti_findterm(term, name, flags);
404 if (r == 1)
405 return r;
407 for (i = 0; i < __arraycount(compiled_terms); i++) {
408 t = &compiled_terms[i];
409 if (strcmp(name, t->name) == 0) {
410 r = _ti_readterm(term, t->cap, t->caplen, flags);
411 break;
415 return r;