1 1.26 roy /* $NetBSD: compile.c,v 1.26 2020/06/21 15:05:23 roy Exp $ */ 2 1.1 roy 3 1.1 roy /* 4 1.14 roy * Copyright (c) 2009, 2010, 2011, 2020 The NetBSD Foundation, Inc. 5 1.1 roy * 6 1.1 roy * This code is derived from software contributed to The NetBSD Foundation 7 1.1 roy * by Roy Marples. 8 1.1 roy * 9 1.1 roy * Redistribution and use in source and binary forms, with or without 10 1.1 roy * modification, are permitted provided that the following conditions 11 1.1 roy * are met: 12 1.1 roy * 1. Redistributions of source code must retain the above copyright 13 1.1 roy * notice, this list of conditions and the following disclaimer. 14 1.1 roy * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 roy * notice, this list of conditions and the following disclaimer in the 16 1.1 roy * documentation and/or other materials provided with the distribution. 17 1.1 roy * 18 1.1 roy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 roy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 roy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 roy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 roy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 1.1 roy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 roy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 roy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 roy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 1.1 roy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 roy */ 29 1.1 roy 30 1.1 roy #if HAVE_NBTOOL_CONFIG_H 31 1.1 roy #include "nbtool_config.h" 32 1.1 roy #endif 33 1.1 roy 34 1.1 roy #include <sys/cdefs.h> 35 1.26 roy __RCSID("$NetBSD: compile.c,v 1.26 2020/06/21 15:05:23 roy Exp $"); 36 1.3 dholland 37 1.3 dholland #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H 38 1.3 dholland #include <sys/endian.h> 39 1.3 dholland #endif 40 1.1 roy 41 1.1 roy #include <assert.h> 42 1.1 roy #include <ctype.h> 43 1.1 roy #include <err.h> 44 1.1 roy #include <errno.h> 45 1.1 roy #include <limits.h> 46 1.1 roy #include <stdarg.h> 47 1.1 roy #include <stdlib.h> 48 1.1 roy #include <stdint.h> 49 1.1 roy #include <stdio.h> 50 1.1 roy #include <string.h> 51 1.1 roy #include <term_private.h> 52 1.1 roy #include <term.h> 53 1.1 roy 54 1.6 joerg static void __printflike(2, 3) 55 1.1 roy dowarn(int flags, const char *fmt, ...) 56 1.1 roy { 57 1.1 roy va_list va; 58 1.1 roy 59 1.1 roy errno = EINVAL; 60 1.1 roy if (flags & TIC_WARNING) { 61 1.1 roy va_start(va, fmt); 62 1.1 roy vwarnx(fmt, va); 63 1.1 roy va_end(va); 64 1.1 roy } 65 1.1 roy } 66 1.1 roy 67 1.25 roy #ifdef TERMINFO_COMPAT 68 1.22 roy int 69 1.22 roy _ti_promote(TIC *tic) 70 1.22 roy { 71 1.23 roy char *obuf, type, flag, *buf, *delim, *name, *nbuf; 72 1.22 roy const char *cap, *code, *str; 73 1.22 roy size_t n, entries, strl; 74 1.22 roy uint16_t ind; 75 1.22 roy int num, ortype, error = 0; 76 1.22 roy 77 1.22 roy ortype = tic->rtype; 78 1.22 roy tic->rtype = TERMINFO_RTYPE; 79 1.22 roy obuf = tic->name; 80 1.22 roy tic->name = _ti_getname(tic->rtype, tic->name); 81 1.22 roy if (tic->name == NULL) { 82 1.22 roy warn("_ti_getname"); 83 1.22 roy tic->name = obuf; 84 1.22 roy return -1; 85 1.22 roy } 86 1.22 roy free(obuf); 87 1.22 roy 88 1.23 roy n = 0; 89 1.23 roy obuf = buf = tic->alias; 90 1.23 roy tic->alias = NULL; 91 1.23 roy while (buf != NULL) { 92 1.23 roy delim = strchr(buf, '|'); 93 1.23 roy if (delim != NULL) 94 1.23 roy *delim++ = '\0'; 95 1.23 roy name = _ti_getname(tic->rtype, buf); 96 1.23 roy strl = strlen(name) + 1; 97 1.23 roy nbuf = realloc(tic->alias, n + strl); 98 1.23 roy if (nbuf == NULL) { 99 1.23 roy free(name); 100 1.23 roy return -1; 101 1.23 roy } 102 1.23 roy tic->alias = nbuf; 103 1.23 roy memcpy(tic->alias + n, name, strl); 104 1.23 roy n += strl; 105 1.23 roy free(name); 106 1.23 roy buf = delim; 107 1.23 roy } 108 1.23 roy free(obuf); 109 1.23 roy 110 1.22 roy obuf = tic->nums.buf; 111 1.22 roy cap = obuf; 112 1.22 roy entries = tic->nums.entries; 113 1.22 roy tic->nums.buf = NULL; 114 1.22 roy tic->nums.entries = tic->nums.buflen = tic->nums.bufpos = 0; 115 1.22 roy for (n = entries; n > 0; n--) { 116 1.22 roy ind = _ti_decode_16(&cap); 117 1.22 roy num = _ti_decode_num(&cap, ortype); 118 1.22 roy if (VALID_NUMERIC(num) && 119 1.22 roy !_ti_encode_buf_id_num(&tic->nums, ind, num, 120 1.22 roy _ti_numsize(tic))) 121 1.22 roy { 122 1.22 roy warn("promote num"); 123 1.22 roy error = -1; 124 1.22 roy break; 125 1.22 roy } 126 1.22 roy } 127 1.22 roy free(obuf); 128 1.22 roy 129 1.22 roy obuf = tic->extras.buf; 130 1.22 roy cap = obuf; 131 1.22 roy entries = tic->extras.entries; 132 1.22 roy tic->extras.buf = NULL; 133 1.22 roy tic->extras.entries = tic->extras.buflen = tic->extras.bufpos = 0; 134 1.22 roy for (n = entries; n > 0; n--) { 135 1.22 roy num = _ti_decode_16(&cap); 136 1.24 roy flag = 0; /* satisfy gcc, won't be used for non flag types */ 137 1.24 roy str = NULL; /* satisfy gcc, won't be used as strl is 0 */ 138 1.22 roy strl = 0; 139 1.22 roy code = cap; 140 1.22 roy cap += num; 141 1.22 roy type = *cap++; 142 1.22 roy switch (type) { 143 1.22 roy case 'f': 144 1.22 roy flag = *cap++; 145 1.22 roy break; 146 1.22 roy case 'n': 147 1.22 roy num = _ti_decode_num(&cap, ortype); 148 1.22 roy break; 149 1.22 roy case 's': 150 1.22 roy strl = _ti_decode_16(&cap); 151 1.22 roy str = cap; 152 1.22 roy cap += strl; 153 1.22 roy break; 154 1.22 roy default: 155 1.22 roy errno = EINVAL; 156 1.22 roy break; 157 1.22 roy } 158 1.22 roy if (!_ti_store_extra(tic, 0, code, type, flag, num, 159 1.22 roy str, strl, TIC_EXTRA)) 160 1.22 roy { 161 1.22 roy error = -1; 162 1.22 roy break; 163 1.22 roy } 164 1.22 roy } 165 1.22 roy free(obuf); 166 1.22 roy 167 1.22 roy return error; 168 1.22 roy } 169 1.25 roy #endif 170 1.22 roy 171 1.1 roy char * 172 1.1 roy _ti_grow_tbuf(TBUF *tbuf, size_t len) 173 1.1 roy { 174 1.1 roy char *buf; 175 1.1 roy size_t l; 176 1.1 roy 177 1.1 roy _DIAGASSERT(tbuf != NULL); 178 1.1 roy 179 1.1 roy l = tbuf->bufpos + len; 180 1.1 roy if (l > tbuf->buflen) { 181 1.7 joerg if (tbuf->buflen == 0) 182 1.1 roy buf = malloc(l); 183 1.1 roy else 184 1.1 roy buf = realloc(tbuf->buf, l); 185 1.1 roy if (buf == NULL) 186 1.1 roy return NULL; 187 1.1 roy tbuf->buf = buf; 188 1.1 roy tbuf->buflen = l; 189 1.1 roy } 190 1.1 roy return tbuf->buf; 191 1.1 roy } 192 1.1 roy 193 1.16 christos const char * 194 1.15 christos _ti_find_cap(TIC *tic, TBUF *tbuf, char type, short ind) 195 1.1 roy { 196 1.1 roy size_t n; 197 1.12 roy uint16_t num; 198 1.16 christos const char *cap; 199 1.1 roy 200 1.1 roy _DIAGASSERT(tbuf != NULL); 201 1.1 roy 202 1.1 roy cap = tbuf->buf; 203 1.1 roy for (n = tbuf->entries; n > 0; n--) { 204 1.16 christos num = _ti_decode_16(&cap); 205 1.12 roy if ((short)num == ind) 206 1.1 roy return cap; 207 1.1 roy switch (type) { 208 1.1 roy case 'f': 209 1.1 roy cap++; 210 1.1 roy break; 211 1.1 roy case 'n': 212 1.15 christos cap += _ti_numsize(tic); 213 1.1 roy break; 214 1.1 roy case 's': 215 1.16 christos num = _ti_decode_16(&cap); 216 1.1 roy cap += num; 217 1.1 roy break; 218 1.1 roy } 219 1.1 roy } 220 1.9 roy 221 1.1 roy errno = ESRCH; 222 1.1 roy return NULL; 223 1.1 roy } 224 1.1 roy 225 1.16 christos const char * 226 1.15 christos _ti_find_extra(TIC *tic, TBUF *tbuf, const char *code) 227 1.1 roy { 228 1.1 roy size_t n; 229 1.12 roy uint16_t num; 230 1.16 christos const char *cap; 231 1.1 roy 232 1.1 roy _DIAGASSERT(tbuf != NULL); 233 1.1 roy _DIAGASSERT(code != NULL); 234 1.1 roy 235 1.1 roy cap = tbuf->buf; 236 1.1 roy for (n = tbuf->entries; n > 0; n--) { 237 1.16 christos num = _ti_decode_16(&cap); 238 1.1 roy if (strcmp(cap, code) == 0) 239 1.1 roy return cap + num; 240 1.1 roy cap += num; 241 1.1 roy switch (*cap++) { 242 1.1 roy case 'f': 243 1.1 roy cap++; 244 1.1 roy break; 245 1.1 roy case 'n': 246 1.15 christos cap += _ti_numsize(tic); 247 1.1 roy break; 248 1.1 roy case 's': 249 1.16 christos num = _ti_decode_16(&cap); 250 1.1 roy cap += num; 251 1.1 roy break; 252 1.1 roy } 253 1.1 roy } 254 1.9 roy 255 1.1 roy errno = ESRCH; 256 1.1 roy return NULL; 257 1.1 roy } 258 1.1 roy 259 1.15 christos char * 260 1.15 christos _ti_getname(int rtype, const char *orig) 261 1.15 christos { 262 1.25 roy #ifdef TERMINFO_COMPAT 263 1.21 roy const char *delim; 264 1.15 christos char *name; 265 1.21 roy const char *verstr; 266 1.21 roy size_t diff, vlen; 267 1.15 christos 268 1.21 roy switch (rtype) { 269 1.21 roy case TERMINFO_RTYPE: 270 1.21 roy verstr = TERMINFO_VDELIMSTR "v3"; 271 1.21 roy break; 272 1.21 roy case TERMINFO_RTYPE_O1: 273 1.21 roy verstr = ""; 274 1.21 roy break; 275 1.21 roy default: 276 1.21 roy errno = EINVAL; 277 1.21 roy return NULL; 278 1.15 christos } 279 1.21 roy 280 1.21 roy delim = orig; 281 1.21 roy while (*delim != '\0' && *delim != TERMINFO_VDELIM) 282 1.21 roy delim++; 283 1.21 roy diff = delim - orig; 284 1.21 roy vlen = strlen(verstr); 285 1.21 roy name = malloc(diff + vlen + 1); 286 1.21 roy if (name == NULL) 287 1.21 roy return NULL; 288 1.21 roy 289 1.21 roy memcpy(name, orig, diff); 290 1.21 roy memcpy(name + diff, verstr, vlen + 1); 291 1.15 christos return name; 292 1.25 roy #else 293 1.25 roy return strdup(orig); 294 1.25 roy #endif 295 1.15 christos } 296 1.15 christos 297 1.1 roy size_t 298 1.15 christos _ti_store_extra(TIC *tic, int wrn, const char *id, char type, char flag, 299 1.15 christos int num, const char *str, size_t strl, int flags) 300 1.1 roy { 301 1.22 roy size_t l, capl; 302 1.1 roy 303 1.1 roy _DIAGASSERT(tic != NULL); 304 1.1 roy 305 1.1 roy if (strcmp(id, "use") != 0) { 306 1.15 christos if (_ti_find_extra(tic, &tic->extras, id) != NULL) 307 1.1 roy return 0; 308 1.1 roy if (!(flags & TIC_EXTRA)) { 309 1.1 roy if (wrn != 0) 310 1.1 roy dowarn(flags, "%s: %s: unknown capability", 311 1.1 roy tic->name, id); 312 1.1 roy return 0; 313 1.1 roy } 314 1.1 roy } 315 1.9 roy 316 1.1 roy l = strlen(id) + 1; 317 1.22 roy if (l > UINT16_MAX) { 318 1.1 roy dowarn(flags, "%s: %s: cap name is too long", tic->name, id); 319 1.1 roy return 0; 320 1.1 roy } 321 1.9 roy 322 1.22 roy capl = sizeof(uint16_t) + l + 1; 323 1.22 roy switch (type) { 324 1.22 roy case 'f': 325 1.22 roy capl++; 326 1.22 roy break; 327 1.22 roy case 'n': 328 1.22 roy capl += _ti_numsize(tic); 329 1.22 roy break; 330 1.22 roy case 's': 331 1.22 roy capl += sizeof(uint16_t) + strl; 332 1.22 roy break; 333 1.22 roy } 334 1.22 roy 335 1.22 roy if (!_ti_grow_tbuf(&tic->extras, capl)) 336 1.1 roy return 0; 337 1.16 christos _ti_encode_buf_count_str(&tic->extras, id, l); 338 1.1 roy tic->extras.buf[tic->extras.bufpos++] = type; 339 1.1 roy switch (type) { 340 1.1 roy case 'f': 341 1.1 roy tic->extras.buf[tic->extras.bufpos++] = flag; 342 1.1 roy break; 343 1.1 roy case 'n': 344 1.16 christos _ti_encode_buf_num(&tic->extras, num, tic->rtype); 345 1.1 roy break; 346 1.1 roy case 's': 347 1.16 christos _ti_encode_buf_count_str(&tic->extras, str, strl); 348 1.1 roy break; 349 1.1 roy } 350 1.1 roy tic->extras.entries++; 351 1.1 roy return 1; 352 1.1 roy } 353 1.1 roy 354 1.16 christos static void 355 1.16 christos _ti_encode_buf(char **cap, const TBUF *buf) 356 1.16 christos { 357 1.16 christos if (buf->entries == 0) { 358 1.16 christos _ti_encode_16(cap, 0); 359 1.16 christos } else { 360 1.16 christos _ti_encode_16(cap, buf->bufpos + sizeof(uint16_t)); 361 1.16 christos _ti_encode_16(cap, buf->entries); 362 1.16 christos _ti_encode_str(cap, buf->buf, buf->bufpos); 363 1.16 christos } 364 1.16 christos } 365 1.16 christos 366 1.1 roy ssize_t 367 1.1 roy _ti_flatten(uint8_t **buf, const TIC *tic) 368 1.1 roy { 369 1.1 roy size_t buflen, len, alen, dlen; 370 1.16 christos char *cap; 371 1.1 roy 372 1.1 roy _DIAGASSERT(buf != NULL); 373 1.1 roy _DIAGASSERT(tic != NULL); 374 1.1 roy 375 1.1 roy len = strlen(tic->name) + 1; 376 1.1 roy if (tic->alias == NULL) 377 1.1 roy alen = 0; 378 1.1 roy else 379 1.1 roy alen = strlen(tic->alias) + 1; 380 1.1 roy if (tic->desc == NULL) 381 1.1 roy dlen = 0; 382 1.1 roy else 383 1.1 roy dlen = strlen(tic->desc) + 1; 384 1.16 christos 385 1.1 roy buflen = sizeof(char) + 386 1.1 roy sizeof(uint16_t) + len + 387 1.1 roy sizeof(uint16_t) + alen + 388 1.1 roy sizeof(uint16_t) + dlen + 389 1.1 roy (sizeof(uint16_t) * 2) + tic->flags.bufpos + 390 1.1 roy (sizeof(uint16_t) * 2) + tic->nums.bufpos + 391 1.1 roy (sizeof(uint16_t) * 2) + tic->strs.bufpos + 392 1.1 roy (sizeof(uint16_t) * 2) + tic->extras.bufpos; 393 1.16 christos 394 1.1 roy *buf = malloc(buflen); 395 1.1 roy if (*buf == NULL) 396 1.1 roy return -1; 397 1.9 roy 398 1.16 christos cap = (char *)*buf; 399 1.15 christos *cap++ = tic->rtype; 400 1.9 roy 401 1.16 christos _ti_encode_count_str(&cap, tic->name, len); 402 1.16 christos _ti_encode_count_str(&cap, tic->alias, alen); 403 1.16 christos _ti_encode_count_str(&cap, tic->desc, dlen); 404 1.9 roy 405 1.16 christos _ti_encode_buf(&cap, &tic->flags); 406 1.9 roy 407 1.16 christos _ti_encode_buf(&cap, &tic->nums); 408 1.16 christos _ti_encode_buf(&cap, &tic->strs); 409 1.16 christos _ti_encode_buf(&cap, &tic->extras); 410 1.1 roy 411 1.16 christos return (uint8_t *)cap - *buf; 412 1.1 roy } 413 1.1 roy 414 1.1 roy static int 415 1.1 roy encode_string(const char *term, const char *cap, TBUF *tbuf, const char *str, 416 1.1 roy int flags) 417 1.1 roy { 418 1.1 roy int slash, i, num; 419 1.1 roy char ch, *p, *s, last; 420 1.9 roy 421 1.1 roy if (_ti_grow_tbuf(tbuf, strlen(str) + 1) == NULL) 422 1.1 roy return -1; 423 1.1 roy p = s = tbuf->buf + tbuf->bufpos; 424 1.1 roy slash = 0; 425 1.1 roy last = '\0'; 426 1.1 roy /* Convert escape codes */ 427 1.1 roy while ((ch = *str++) != '\0') { 428 1.10 roy if (ch == '\n') { 429 1.10 roy /* Following a newline, strip leading whitespace from 430 1.10 roy * capability strings. */ 431 1.10 roy while (isspace((unsigned char)*str)) 432 1.10 roy str++; 433 1.10 roy continue; 434 1.10 roy } 435 1.1 roy if (slash == 0 && ch == '\\') { 436 1.1 roy slash = 1; 437 1.1 roy continue; 438 1.1 roy } 439 1.1 roy if (slash == 0) { 440 1.1 roy if (last != '%' && ch == '^') { 441 1.1 roy ch = *str++; 442 1.1 roy if (((unsigned char)ch) >= 128) 443 1.1 roy dowarn(flags, 444 1.1 roy "%s: %s: illegal ^ character", 445 1.1 roy term, cap); 446 1.1 roy if (ch == '\0') 447 1.1 roy break; 448 1.1 roy if (ch == '?') 449 1.1 roy ch = '\177'; 450 1.1 roy else if ((ch &= 037) == 0) 451 1.5 roy ch = (char)128; 452 1.11 roy } else if (!isprint((unsigned char)ch)) 453 1.11 roy dowarn(flags, 454 1.11 roy "%s: %s: unprintable character", 455 1.11 roy term, cap); 456 1.1 roy *p++ = ch; 457 1.1 roy last = ch; 458 1.1 roy continue; 459 1.1 roy } 460 1.1 roy slash = 0; 461 1.1 roy if (ch >= '0' && ch <= '7') { 462 1.1 roy num = ch - '0'; 463 1.1 roy for (i = 0; i < 2; i++) { 464 1.1 roy if (*str < '0' || *str > '7') { 465 1.1 roy if (isdigit((unsigned char)*str)) 466 1.1 roy dowarn(flags, 467 1.1 roy "%s: %s: non octal" 468 1.1 roy " digit", term, cap); 469 1.1 roy else 470 1.1 roy break; 471 1.1 roy } 472 1.1 roy num = num * 8 + *str++ - '0'; 473 1.1 roy } 474 1.1 roy if (num == 0) 475 1.1 roy num = 0200; 476 1.1 roy *p++ = (char)num; 477 1.1 roy continue; 478 1.1 roy } 479 1.1 roy switch (ch) { 480 1.1 roy case 'a': 481 1.1 roy *p++ = '\a'; 482 1.1 roy break; 483 1.1 roy case 'b': 484 1.1 roy *p++ = '\b'; 485 1.1 roy break; 486 1.1 roy case 'e': /* FALLTHROUGH */ 487 1.1 roy case 'E': 488 1.1 roy *p++ = '\033'; 489 1.1 roy break; 490 1.1 roy case 'f': 491 1.1 roy *p++ = '\014'; 492 1.1 roy break; 493 1.1 roy case 'l': /* FALLTHROUGH */ 494 1.1 roy case 'n': 495 1.1 roy *p++ = '\n'; 496 1.1 roy break; 497 1.1 roy case 'r': 498 1.1 roy *p++ = '\r'; 499 1.1 roy break; 500 1.1 roy case 's': 501 1.1 roy *p++ = ' '; 502 1.1 roy break; 503 1.1 roy case 't': 504 1.1 roy *p++ = '\t'; 505 1.1 roy break; 506 1.1 roy default: 507 1.1 roy /* We should warn here */ 508 1.1 roy case '^': 509 1.1 roy case ',': 510 1.1 roy case ':': 511 1.1 roy case '|': 512 1.1 roy *p++ = ch; 513 1.1 roy break; 514 1.1 roy } 515 1.1 roy last = ch; 516 1.1 roy } 517 1.1 roy *p++ = '\0'; 518 1.12 roy tbuf->bufpos += (size_t)(p - s); 519 1.1 roy return 0; 520 1.1 roy } 521 1.1 roy 522 1.4 roy char * 523 1.4 roy _ti_get_token(char **cap, char sep) 524 1.1 roy { 525 1.4 roy char esc, *token; 526 1.1 roy 527 1.1 roy while (isspace((unsigned char)**cap)) 528 1.1 roy (*cap)++; 529 1.1 roy if (**cap == '\0') 530 1.1 roy return NULL; 531 1.1 roy 532 1.1 roy /* We can't use stresep(3) as ^ we need two escape chars */ 533 1.4 roy esc = '\0'; 534 1.1 roy for (token = *cap; 535 1.4 roy **cap != '\0' && (esc != '\0' || **cap != sep); 536 1.1 roy (*cap)++) 537 1.1 roy { 538 1.4 roy if (esc == '\0') { 539 1.1 roy if (**cap == '\\' || **cap == '^') 540 1.4 roy esc = **cap; 541 1.4 roy } else { 542 1.4 roy /* termcap /E/ is valid */ 543 1.4 roy if (sep == ':' && esc == '\\' && **cap == 'E') 544 1.4 roy esc = 'x'; 545 1.4 roy else 546 1.4 roy esc = '\0'; 547 1.4 roy } 548 1.1 roy } 549 1.1 roy 550 1.1 roy if (**cap != '\0') 551 1.1 roy *(*cap)++ = '\0'; 552 1.1 roy 553 1.1 roy return token; 554 1.1 roy } 555 1.1 roy 556 1.16 christos int 557 1.16 christos _ti_encode_buf_id_num(TBUF *tbuf, int ind, int num, size_t len) 558 1.16 christos { 559 1.16 christos if (!_ti_grow_tbuf(tbuf, sizeof(uint16_t) + len)) 560 1.16 christos return 0; 561 1.16 christos _ti_encode_buf_16(tbuf, ind); 562 1.16 christos if (len == sizeof(uint32_t)) 563 1.26 roy _ti_encode_buf_32(tbuf, (uint32_t)num); 564 1.16 christos else 565 1.26 roy _ti_encode_buf_16(tbuf, (uint16_t)num); 566 1.16 christos tbuf->entries++; 567 1.16 christos return 1; 568 1.16 christos } 569 1.16 christos 570 1.16 christos int 571 1.16 christos _ti_encode_buf_id_count_str(TBUF *tbuf, int ind, const void *buf, size_t len) 572 1.16 christos { 573 1.16 christos if (!_ti_grow_tbuf(tbuf, 2 * sizeof(uint16_t) + len)) 574 1.16 christos return 0; 575 1.16 christos _ti_encode_buf_16(tbuf, ind); 576 1.16 christos _ti_encode_buf_count_str(tbuf, buf, len); 577 1.16 christos tbuf->entries++; 578 1.16 christos return 1; 579 1.16 christos } 580 1.16 christos 581 1.16 christos int 582 1.16 christos _ti_encode_buf_id_flags(TBUF *tbuf, int ind, int flag) 583 1.16 christos { 584 1.16 christos if (!_ti_grow_tbuf(tbuf, sizeof(uint16_t) + 1)) 585 1.16 christos return 0; 586 1.16 christos _ti_encode_buf_16(tbuf, ind); 587 1.16 christos tbuf->buf[tbuf->bufpos++] = flag; 588 1.16 christos tbuf->entries++; 589 1.16 christos return 1; 590 1.16 christos } 591 1.16 christos 592 1.1 roy TIC * 593 1.1 roy _ti_compile(char *cap, int flags) 594 1.1 roy { 595 1.1 roy char *token, *p, *e, *name, *desc, *alias; 596 1.1 roy signed char flag; 597 1.5 roy long cnum; 598 1.14 roy short ind; 599 1.14 roy int num; 600 1.1 roy size_t len; 601 1.1 roy TBUF buf; 602 1.1 roy TIC *tic; 603 1.1 roy 604 1.9 roy _DIAGASSERT(cap != NULL); 605 1.1 roy 606 1.4 roy name = _ti_get_token(&cap, ','); 607 1.1 roy if (name == NULL) { 608 1.15 christos dowarn(flags, "no separator found: %s", cap); 609 1.1 roy return NULL; 610 1.1 roy } 611 1.1 roy desc = strrchr(name, '|'); 612 1.1 roy if (desc != NULL) 613 1.1 roy *desc++ = '\0'; 614 1.1 roy alias = strchr(name, '|'); 615 1.1 roy if (alias != NULL) 616 1.1 roy *alias++ = '\0'; 617 1.1 roy 618 1.14 roy if (strlen(name) > UINT16_MAX - 1) { 619 1.14 roy dowarn(flags, "%s: name too long", name); 620 1.14 roy return NULL; 621 1.14 roy } 622 1.14 roy if (desc != NULL && strlen(desc) > UINT16_MAX - 1) { 623 1.14 roy dowarn(flags, "%s: description too long: %s", name, desc); 624 1.14 roy return NULL; 625 1.14 roy } 626 1.14 roy if (alias != NULL && strlen(alias) > UINT16_MAX - 1) { 627 1.14 roy dowarn(flags, "%s: alias too long: %s", name, alias); 628 1.14 roy return NULL; 629 1.14 roy } 630 1.14 roy 631 1.1 roy tic = calloc(sizeof(*tic), 1); 632 1.1 roy if (tic == NULL) 633 1.1 roy return NULL; 634 1.1 roy 635 1.25 roy #ifdef TERMINFO_COMPAT 636 1.22 roy tic->rtype = TERMINFO_RTYPE_O1; /* will promote if needed */ 637 1.25 roy #else 638 1.25 roy tic->rtype = TERMINFO_RTYPE; 639 1.25 roy #endif 640 1.1 roy buf.buf = NULL; 641 1.1 roy buf.buflen = 0; 642 1.1 roy 643 1.15 christos tic->name = _ti_getname(tic->rtype, name); 644 1.1 roy if (tic->name == NULL) 645 1.1 roy goto error; 646 1.1 roy if (alias != NULL && flags & TIC_ALIAS) { 647 1.15 christos tic->alias = _ti_getname(tic->rtype, alias); 648 1.1 roy if (tic->alias == NULL) 649 1.1 roy goto error; 650 1.1 roy } 651 1.1 roy if (desc != NULL && flags & TIC_DESCRIPTION) { 652 1.1 roy tic->desc = strdup(desc); 653 1.1 roy if (tic->desc == NULL) 654 1.1 roy goto error; 655 1.1 roy } 656 1.1 roy 657 1.4 roy for (token = _ti_get_token(&cap, ','); 658 1.1 roy token != NULL && *token != '\0'; 659 1.4 roy token = _ti_get_token(&cap, ',')) 660 1.1 roy { 661 1.1 roy /* Skip commented caps */ 662 1.1 roy if (!(flags & TIC_COMMENT) && token[0] == '.') 663 1.1 roy continue; 664 1.1 roy 665 1.1 roy /* Obsolete entries */ 666 1.1 roy if (token[0] == 'O' && token[1] == 'T') { 667 1.1 roy if (!(flags & TIC_EXTRA)) 668 1.1 roy continue; 669 1.1 roy token += 2; 670 1.1 roy } 671 1.1 roy 672 1.1 roy /* str cap */ 673 1.1 roy p = strchr(token, '='); 674 1.1 roy if (p != NULL) { 675 1.1 roy *p++ = '\0'; 676 1.1 roy /* Don't use the string if we already have it */ 677 1.12 roy ind = (short)_ti_strindex(token); 678 1.1 roy if (ind != -1 && 679 1.15 christos _ti_find_cap(tic, &tic->strs, 's', ind) != NULL) 680 1.1 roy continue; 681 1.1 roy 682 1.1 roy /* Encode the string to our scratch buffer */ 683 1.1 roy buf.bufpos = 0; 684 1.1 roy if (encode_string(tic->name, token, 685 1.1 roy &buf, p, flags) == -1) 686 1.1 roy goto error; 687 1.14 roy if (buf.bufpos > UINT16_MAX - 1) { 688 1.1 roy dowarn(flags, "%s: %s: string is too long", 689 1.1 roy tic->name, token); 690 1.1 roy continue; 691 1.1 roy } 692 1.1 roy if (!VALID_STRING(buf.buf)) { 693 1.1 roy dowarn(flags, "%s: %s: invalid string", 694 1.1 roy tic->name, token); 695 1.1 roy continue; 696 1.1 roy } 697 1.1 roy 698 1.16 christos if (ind == -1) { 699 1.16 christos if (!_ti_store_extra(tic, 1, token, 's', -1, -2, 700 1.16 christos buf.buf, buf.bufpos, flags)) 701 1.16 christos goto error; 702 1.16 christos } else { 703 1.16 christos if (!_ti_encode_buf_id_count_str(&tic->strs, 704 1.16 christos ind, buf.buf, buf.bufpos)) 705 1.1 roy goto error; 706 1.1 roy } 707 1.1 roy continue; 708 1.1 roy } 709 1.1 roy 710 1.1 roy /* num cap */ 711 1.1 roy p = strchr(token, '#'); 712 1.1 roy if (p != NULL) { 713 1.1 roy *p++ = '\0'; 714 1.1 roy /* Don't use the number if we already have it */ 715 1.12 roy ind = (short)_ti_numindex(token); 716 1.1 roy if (ind != -1 && 717 1.15 christos _ti_find_cap(tic, &tic->nums, 'n', ind) != NULL) 718 1.1 roy continue; 719 1.1 roy 720 1.5 roy cnum = strtol(p, &e, 0); 721 1.1 roy if (*e != '\0') { 722 1.1 roy dowarn(flags, "%s: %s: not a number", 723 1.1 roy tic->name, token); 724 1.1 roy continue; 725 1.1 roy } 726 1.14 roy if (!VALID_NUMERIC(cnum) || cnum > INT32_MAX) { 727 1.14 roy dowarn(flags, "%s: %s: number %ld out of range", 728 1.14 roy tic->name, token, cnum); 729 1.1 roy continue; 730 1.1 roy } 731 1.22 roy if (cnum > INT16_MAX) { 732 1.22 roy if (flags & TIC_COMPAT_V1) 733 1.22 roy cnum = INT16_MAX; 734 1.22 roy else if (tic->rtype == TERMINFO_RTYPE_O1) 735 1.22 roy if (_ti_promote(tic) == -1) 736 1.22 roy goto error; 737 1.22 roy } 738 1.13 roy 739 1.14 roy num = (int)cnum; 740 1.16 christos if (ind == -1) { 741 1.16 christos if (!_ti_store_extra(tic, 1, token, 'n', -1, 742 1.16 christos num, NULL, 0, flags)) 743 1.1 roy goto error; 744 1.16 christos } else { 745 1.16 christos if (!_ti_encode_buf_id_num(&tic->nums, 746 1.16 christos ind, num, _ti_numsize(tic))) 747 1.16 christos goto error; 748 1.1 roy } 749 1.1 roy continue; 750 1.1 roy } 751 1.1 roy 752 1.1 roy flag = 1; 753 1.1 roy len = strlen(token) - 1; 754 1.1 roy if (token[len] == '@') { 755 1.1 roy flag = CANCELLED_BOOLEAN; 756 1.1 roy token[len] = '\0'; 757 1.1 roy } 758 1.12 roy ind = (short)_ti_flagindex(token); 759 1.1 roy if (ind == -1 && flag == CANCELLED_BOOLEAN) { 760 1.12 roy if ((ind = (short)_ti_numindex(token)) != -1) { 761 1.15 christos if (_ti_find_cap(tic, &tic->nums, 'n', ind) 762 1.15 christos != NULL) 763 1.1 roy continue; 764 1.16 christos if (!_ti_encode_buf_id_num(&tic->nums, ind, 765 1.16 christos CANCELLED_NUMERIC, _ti_numsize(tic))) 766 1.1 roy goto error; 767 1.1 roy continue; 768 1.12 roy } else if ((ind = (short)_ti_strindex(token)) != -1) { 769 1.15 christos if (_ti_find_cap(tic, &tic->strs, 's', ind) 770 1.15 christos != NULL) 771 1.1 roy continue; 772 1.16 christos if (!_ti_encode_buf_id_num( 773 1.16 christos &tic->strs, ind, 0, sizeof(uint16_t))) 774 1.1 roy goto error; 775 1.1 roy continue; 776 1.1 roy } 777 1.1 roy } 778 1.16 christos if (ind == -1) { 779 1.16 christos if (!_ti_store_extra(tic, 1, token, 'f', flag, 0, NULL, 780 1.16 christos 0, flags)) 781 1.16 christos goto error; 782 1.16 christos } else if (_ti_find_cap(tic, &tic->flags, 'f', ind) == NULL) { 783 1.20 christos if (!_ti_encode_buf_id_flags(&tic->flags, ind, flag)) 784 1.1 roy goto error; 785 1.1 roy } 786 1.1 roy } 787 1.1 roy 788 1.1 roy free(buf.buf); 789 1.1 roy return tic; 790 1.1 roy 791 1.1 roy error: 792 1.1 roy free(buf.buf); 793 1.1 roy _ti_freetic(tic); 794 1.1 roy return NULL; 795 1.1 roy } 796 1.1 roy 797 1.1 roy void 798 1.1 roy _ti_freetic(TIC *tic) 799 1.1 roy { 800 1.1 roy 801 1.1 roy if (tic != NULL) { 802 1.1 roy free(tic->name); 803 1.1 roy free(tic->alias); 804 1.1 roy free(tic->desc); 805 1.7 joerg free(tic->extras.buf); 806 1.1 roy free(tic->flags.buf); 807 1.1 roy free(tic->nums.buf); 808 1.1 roy free(tic->strs.buf); 809 1.1 roy free(tic); 810 1.1 roy } 811 1.1 roy } 812