1 /* $NetBSD: term.c,v 1.17 2013/06/07 13:16:18 roy Exp $ */ 2 3 /* 4 * Copyright (c) 2009, 2010, 2011 The NetBSD Foundation, Inc. 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> 31 __RCSID("$NetBSD: term.c,v 1.17 2013/06/07 13:16:18 roy Exp $"); 32 33 #include <sys/stat.h> 34 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> 46 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) */ 52 53 static char database[PATH_MAX]; 54 static char pathbuf[PATH_MAX]; 55 const char *_ti_database; 56 57 /* Include a generated list of pre-compiled terminfo descriptions. */ 58 #include "compiled_terms.c" 59 60 static int 61 _ti_readterm(TERMINAL *term, const char *cap, size_t caplen, int flags) 62 { 63 uint8_t ver; 64 uint16_t ind, num; 65 size_t len; 66 TERMUSERDEF *ud; 67 68 ver = *cap++; 69 /* Only read version 1 structures */ 70 if (ver != 1) { 71 errno = EINVAL; 72 return -1; 73 } 74 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); 90 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; 103 } 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; 111 } 112 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; 124 } 125 } 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->nums[ind] = le16dec(cap); 136 if (flags == 0 && !VALID_NUMERIC(term->nums[ind])) 137 term->nums[ind] = ABSENT_NUMERIC; 138 cap += sizeof(uint16_t); 139 } 140 } 141 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; 159 } 160 } 161 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; 209 } 210 } 211 } 212 return 1; 213 } 214 215 static int 216 _ti_dbgetterm(TERMINAL *term, const char *path, const char *name, int flags) 217 { 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; 224 225 if (asprintf(&db_name, "%s.cdb", path) < 0) 226 return -1; 227 228 db = cdbr_open(db_name, CDBR_DEFAULT); 229 free(db_name); 230 if (db == NULL) 231 return -1; 232 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; 256 257 strlcpy(database, path, sizeof(database)); 258 _ti_database = database; 259 260 r = _ti_readterm(term, data, len, flags); 261 cdbr_close(db); 262 return r; 263 264 fail: 265 cdbr_close(db); 266 return 0; 267 } 268 269 static int 270 _ti_dbgettermp(TERMINAL *term, const char *path, const char *name, int flags) 271 { 272 const char *p; 273 size_t l; 274 int r, e; 275 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; 290 } 291 } while (*path++ == ':'); 292 return e; 293 } 294 295 static int 296 ticcmp(const TIC *tic, const char *name) 297 { 298 char *alias, *s; 299 size_t len, l; 300 301 if (strcmp(tic->name, name) == 0) 302 return 0; 303 if (tic->alias == NULL) 304 return -1; 305 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; 319 } 320 return 1; 321 } 322 323 static int 324 _ti_findterm(TERMINAL *term, const char *name, int flags) 325 { 326 int r; 327 char *c, *e, h[PATH_MAX]; 328 TIC *tic; 329 uint8_t *f; 330 ssize_t len; 331 332 _DIAGASSERT(term != NULL); 333 _DIAGASSERT(name != NULL); 334 335 database[0] = '\0'; 336 _ti_database = NULL; 337 r = 0; 338 339 if ((e = getenv("TERMINFO")) != NULL && *e != '\0') 340 if (e[0] == '/') 341 return _ti_dbgetterm(term, e, name, flags); 342 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); 350 } 351 } 352 } 353 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); 370 } 371 } 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; 379 } 380 } 381 382 if ((e = getenv("TERMINFO_DIRS")) != NULL) 383 return _ti_dbgettermp(term, e, name, flags); 384 385 if ((e = getenv("HOME")) != NULL) { 386 snprintf(h, sizeof(h), "%s/.terminfo", e); 387 r = _ti_dbgetterm(term, h, name, flags); 388 } 389 if (r != 1) 390 r = _ti_dbgettermp(term, _PATH_TERMINFO, name, flags); 391 392 return r; 393 394 } 395 396 int 397 _ti_getterm(TERMINAL *term, const char *name, int flags) 398 { 399 int r; 400 size_t i; 401 const struct compiled_term *t; 402 403 r = _ti_findterm(term, name, flags); 404 if (r == 1) 405 return r; 406 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; 412 } 413 } 414 415 return r; 416 } 417