libutil: add O_NOCTTY back to old pty open code
[minix.git] / lib / libterminfo / term.c
bloba76a4cfd73d739aca73666a5263e79a5ec1cdc92
1 /* $NetBSD: term.c,v 1.11 2010/02/26 00:09:00 roy Exp $ */
3 /*
4 * Copyright (c) 2009, 2010 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.11 2010/02/26 00:09:00 roy Exp $");
33 #include <sys/stat.h>
35 #include <assert.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <limits.h>
40 #include <ndbm.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <term_private.h>
45 #include <term.h>
47 #ifndef __minix
48 #define _PATH_TERMINFO "/usr/share/misc/terminfo"
49 #else
50 #define _PATH_TERMINFO "/usr/share/terminfo/terminfo"
51 #endif
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 and 2 structures */
70 if (ver != 1 && ver != 2) {
71 errno = EINVAL;
72 return -1;
75 term->flags = calloc(TIFLAGMAX + 1, sizeof(char));
76 if (term->flags == NULL)
77 goto err;
78 term->nums = malloc((TINUMMAX + 1) * sizeof(short));
79 if (term->nums == NULL)
80 goto err;
81 memset(term->nums, (short)-1, (TINUMMAX + 1) * sizeof(short));
82 term->strs = calloc(TISTRMAX + 1, sizeof(char *));
83 if (term->strs == NULL)
84 goto err;
85 term->_arealen = caplen;
86 term->_area = malloc(term->_arealen);
87 if (term->_area == NULL)
88 goto err;
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 if (ver == 1)
97 term->_alias = NULL;
98 else {
99 len = le16dec(cap);
100 cap += sizeof(uint16_t);
101 if (len == 0)
102 term->_alias = NULL;
103 else {
104 term->_alias = cap;
105 cap += len;
108 len = le16dec(cap);
109 cap += sizeof(uint16_t);
110 if (len == 0)
111 term->desc = NULL;
112 else {
113 term->desc = cap;
114 cap += len;
117 num = le16dec(cap);
118 cap += sizeof(uint16_t);
119 if (num != 0) {
120 num = le16dec(cap);
121 cap += sizeof(uint16_t);
122 for (; num != 0; num--) {
123 ind = le16dec(cap);
124 cap += sizeof(uint16_t);
125 term->flags[ind] = *cap++;
126 if (flags == 0 && !VALID_BOOLEAN(term->flags[ind]))
127 term->flags[ind] = 0;
131 num = le16dec(cap);
132 cap += sizeof(uint16_t);
133 if (num != 0) {
134 num = le16dec(cap);
135 cap += sizeof(uint16_t);
136 for (; num != 0; num--) {
137 ind = le16dec(cap);
138 cap += sizeof(uint16_t);
139 term->nums[ind] = le16dec(cap);
140 if (flags == 0 && !VALID_NUMERIC(term->nums[ind]))
141 term->nums[ind] = ABSENT_NUMERIC;
142 cap += sizeof(uint16_t);
146 num = le16dec(cap);
147 cap += sizeof(uint16_t);
148 if (num != 0) {
149 num = le16dec(cap);
150 cap += sizeof(uint16_t);
151 for (; num != 0; num--) {
152 ind = le16dec(cap);
153 cap += sizeof(uint16_t);
154 len = le16dec(cap);
155 cap += sizeof(uint16_t);
156 if (len > 0)
157 term->strs[ind] = cap;
158 else if (flags == 0)
159 term->strs[ind] = ABSENT_STRING;
160 else
161 term->strs[ind] = CANCELLED_STRING;
162 cap += len;
166 num = le16dec(cap);
167 cap += sizeof(uint16_t);
168 if (num != 0) {
169 term->_nuserdefs = le16dec(cap);
170 term->_userdefs = malloc(sizeof(*term->_userdefs) * num);
171 cap += sizeof(uint16_t);
172 for (num = 0; num < term->_nuserdefs; num++) {
173 ud = &term->_userdefs[num];
174 len = le16dec(cap);
175 cap += sizeof(uint16_t);
176 ud->id = cap;
177 cap += len;
178 ud->type = *cap++;
179 switch (ud->type) {
180 case 'f':
181 ud->flag = *cap++;
182 if (flags == 0 &&
183 !VALID_BOOLEAN(ud->flag))
184 ud->flag = 0;
185 ud->num = ABSENT_NUMERIC;
186 ud->str = ABSENT_STRING;
187 break;
188 case 'n':
189 ud->flag = ABSENT_BOOLEAN;
190 ud->num = le16dec(cap);
191 if (flags == 0 &&
192 !VALID_NUMERIC(ud->num))
193 ud->num = ABSENT_NUMERIC;
194 ud->str = ABSENT_STRING;
195 cap += sizeof(uint16_t);
196 break;
197 case 's':
198 ud->flag = ABSENT_BOOLEAN;
199 ud->num = ABSENT_NUMERIC;
200 len = le16dec(cap);
201 cap += sizeof(uint16_t);
202 if (len > 0)
203 ud->str = cap;
204 else if (flags == 0)
205 ud->str = ABSENT_STRING;
206 else
207 ud->str = CANCELLED_STRING;
208 cap += len;
209 break;
210 default:
211 errno = EINVAL;
212 goto err;
216 return 1;
218 err:
219 _ti_freeterm(term);
220 return -1;
223 static int
224 _ti_dbgetterm(TERMINAL *term, const char *path, const char *name, int flags)
226 DBM *db;
227 datum dt;
228 char *p;
229 int r;
231 db = dbm_open(path, O_RDONLY, 0644);
232 if (db == NULL)
233 return -1;
234 strlcpy(database, path, sizeof(database));
235 _ti_database = database;
236 dt.dptr = (void *)__UNCONST(name);
237 dt.dsize = strlen(name);
238 dt = dbm_fetch(db, dt);
239 if (dt.dptr == NULL) {
240 dbm_close(db);
241 return 0;
244 for (;;) {
245 p = (char *)dt.dptr;
246 if (*p++ != 0) /* not alias */
247 break;
248 dt.dsize = le16dec(p) - 1;
249 p += sizeof(uint16_t);
250 dt.dptr = p;
251 dt = dbm_fetch(db, dt);
252 if (dt.dptr == NULL) {
253 dbm_close(db);
254 return 0;
258 r = _ti_readterm(term, (char *)dt.dptr, dt.dsize, flags);
259 dbm_close(db);
260 return r;
263 static int
264 _ti_dbgettermp(TERMINAL *term, const char *path, const char *name, int flags)
266 const char *p;
267 size_t l;
268 int r, e;
270 e = -1;
271 r = 0;
272 do {
273 for (p = path; *path != '\0' && *path != ':'; path++)
274 continue;
275 l = path - p;
276 if (l != 0 && l + 1 < sizeof(pathbuf)) {
277 memcpy(pathbuf, p, l);
278 pathbuf[l] = '\0';
279 r = _ti_dbgetterm(term, pathbuf, name, flags);
280 if (r == 1)
281 return 1;
282 if (r == 0)
283 e = 0;
285 } while (*path++ == ':');
286 return e;
289 static int
290 ticcmp(const TIC *tic, const char *name)
292 char *alias, *s;
293 size_t len, l;
295 if (strcmp(tic->name, name) == 0)
296 return 0;
297 if (tic->alias == NULL)
298 return -1;
300 len = strlen(name);
301 alias = tic->alias;
302 while (*alias != '\0') {
303 s = strchr(alias, '|');
304 if (s == NULL)
305 l = strlen(alias);
306 else
307 l = s - alias;
308 if (len == l && strncmp(alias, name, l) == 0)
309 return 0;
310 if (s == NULL)
311 break;
312 alias = s + 1;
314 return 1;
317 static int
318 _ti_findterm(TERMINAL *term, const char *name, int flags)
320 int r;
321 char *c, *e, h[PATH_MAX];
322 TIC *tic;
323 uint8_t *f;
324 ssize_t len;
326 _DIAGASSERT(term != NULL);
327 _DIAGASSERT(name != NULL);
329 database[0] = '\0';
330 _ti_database = NULL;
331 r = 0;
333 if ((e = getenv("TERMINFO")) != NULL && *e != '\0')
334 if (e[0] == '/')
335 return _ti_dbgetterm(term, e, name, flags);
337 c = NULL;
338 if (e == NULL && (c = getenv("TERMCAP")) != NULL) {
339 if (*c != '\0' && *c != '/') {
340 c = strdup(c);
341 if (c != NULL) {
342 e = captoinfo(c);
343 free(c);
348 if (e != NULL) {
349 if (c == NULL)
350 e = strdup(e); /* So we don't destroy env */
351 if (e == NULL)
352 tic = NULL;
353 else
354 tic = _ti_compile(e, TIC_WARNING |
355 TIC_ALIAS | TIC_DESCRIPTION | TIC_EXTRA);
356 if (c == NULL && e != NULL)
357 free(e);
358 if (tic != NULL && ticcmp(tic, name) == 0) {
359 len = _ti_flatten(&f, tic);
360 if (len != -1) {
361 r = _ti_readterm(term, (char *)f, len, flags);
362 free(f);
365 _ti_freetic(tic);
366 if (r == 1) {
367 if (c == NULL)
368 _ti_database = "$TERMINFO";
369 else
370 _ti_database = "$TERMCAP";
371 return r;
375 if ((e = getenv("TERMINFO_DIRS")) != NULL)
376 return _ti_dbgettermp(term, e, name, flags);
378 if ((e = getenv("HOME")) != NULL) {
379 snprintf(h, sizeof(h), "%s/.terminfo", e);
380 r = _ti_dbgetterm(term, h, name, flags);
382 if (r != 1)
383 r = _ti_dbgettermp(term, _PATH_TERMINFO, name, flags);
385 return r;
390 _ti_getterm(TERMINAL *term, const char *name, int flags)
392 int r;
393 size_t i;
394 const struct compiled_term *t;
396 r = _ti_findterm(term, name, flags);
397 if (r == 1)
398 return r;
400 for (i = 0; i < __arraycount(compiled_terms); i++) {
401 t = &compiled_terms[i];
402 if (strcmp(name, t->name) == 0) {
403 r = _ti_readterm(term, t->cap, t->caplen, flags);
404 break;
408 return r;
411 void
412 _ti_freeterm(TERMINAL *term)
415 if (term != NULL) {
416 free(term->_area);
417 free(term->strs);
418 free(term->nums);
419 free(term->flags);
420 free(term->_userdefs);