compile.c revision 1.2
1/* $NetBSD: compile.c,v 1.2 2010/02/25 23:44:02 roy Exp $ */ 2 3/* 4 * Copyright (c) 2009, 2010 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#if HAVE_NBTOOL_CONFIG_H 31#include "nbtool_config.h" 32#endif 33 34#include <sys/cdefs.h> 35__RCSID("$NetBSD: compile.c,v 1.2 2010/02/25 23:44:02 roy Exp $"); 36 37#include <assert.h> 38#include <ctype.h> 39#include <err.h> 40#include <errno.h> 41#include <limits.h> 42#include <stdarg.h> 43#include <stdlib.h> 44#include <stdint.h> 45#include <stdio.h> 46#include <string.h> 47#include <term_private.h> 48#include <term.h> 49 50static void __attribute__((__format__(__printf__, 2, 3))) 51dowarn(int flags, const char *fmt, ...) 52{ 53 va_list va; 54 55 errno = EINVAL; 56 if (flags & TIC_WARNING) { 57 va_start(va, fmt); 58 vwarnx(fmt, va); 59 va_end(va); 60 } 61} 62 63char * 64_ti_grow_tbuf(TBUF *tbuf, size_t len) 65{ 66 char *buf; 67 size_t l; 68 69 _DIAGASSERT(tbuf != NULL); 70 71 l = tbuf->bufpos + len; 72 if (l > tbuf->buflen) { 73 if (tbuf->bufpos == 0) 74 buf = malloc(l); 75 else 76 buf = realloc(tbuf->buf, l); 77 if (buf == NULL) 78 return NULL; 79 tbuf->buf = buf; 80 tbuf->buflen = l; 81 } 82 return tbuf->buf; 83} 84 85char * 86_ti_find_cap(TBUF *tbuf, char type, short ind) 87{ 88 size_t n; 89 short num; 90 char *cap; 91 92 _DIAGASSERT(tbuf != NULL); 93 94 cap = tbuf->buf; 95 for (n = tbuf->entries; n > 0; n--) { 96 num = le16dec(cap); 97 cap += sizeof(uint16_t); 98 if (num == ind) 99 return cap; 100 switch (type) { 101 case 'f': 102 cap++; 103 break; 104 case 'n': 105 cap += sizeof(uint16_t); 106 break; 107 case 's': 108 num = le16dec(cap); 109 cap += sizeof(uint16_t); 110 cap += num; 111 break; 112 } 113 } 114 115 errno = ESRCH; 116 return NULL; 117} 118 119char * 120_ti_find_extra(TBUF *tbuf, const char *code) 121{ 122 size_t n; 123 short num; 124 char *cap; 125 126 _DIAGASSERT(tbuf != NULL); 127 _DIAGASSERT(code != NULL); 128 129 cap = tbuf->buf; 130 for (n = tbuf->entries; n > 0; n--) { 131 num = le16dec(cap); 132 cap += sizeof(uint16_t); 133 if (strcmp(cap, code) == 0) 134 return cap + num; 135 cap += num; 136 switch (*cap++) { 137 case 'f': 138 cap++; 139 break; 140 case 'n': 141 cap += sizeof(uint16_t); 142 break; 143 case 's': 144 num = le16dec(cap); 145 cap += sizeof(uint16_t); 146 cap += num; 147 break; 148 } 149 } 150 151 errno = ESRCH; 152 return NULL; 153} 154 155size_t 156_ti_store_extra(TIC *tic, int wrn, char *id, char type, char flag, short num, 157 char *str, size_t strl, int flags) 158{ 159 size_t l; 160 161 _DIAGASSERT(tic != NULL); 162 163 if (strcmp(id, "use") != 0) { 164 if (_ti_find_extra(&tic->extras, id) != NULL) 165 return 0; 166 if (!(flags & TIC_EXTRA)) { 167 if (wrn != 0) 168 dowarn(flags, "%s: %s: unknown capability", 169 tic->name, id); 170 return 0; 171 } 172 } 173 174 l = strlen(id) + 1; 175 if (l > UINT16_T_MAX) { 176 dowarn(flags, "%s: %s: cap name is too long", tic->name, id); 177 return 0; 178 } 179 180 if (!_ti_grow_tbuf(&tic->extras, 181 l + strl + (sizeof(uint16_t) * 2) + 1)) 182 return 0; 183 le16enc(tic->extras.buf + tic->extras.bufpos, l); 184 tic->extras.bufpos += sizeof(uint16_t); 185 memcpy(tic->extras.buf + tic->extras.bufpos, id, l); 186 tic->extras.bufpos += l; 187 tic->extras.buf[tic->extras.bufpos++] = type; 188 switch (type) { 189 case 'f': 190 tic->extras.buf[tic->extras.bufpos++] = flag; 191 break; 192 case 'n': 193 le16enc(tic->extras.buf + tic->extras.bufpos, num); 194 tic->extras.bufpos += sizeof(uint16_t); 195 break; 196 case 's': 197 le16enc(tic->extras.buf + tic->extras.bufpos, strl); 198 tic->extras.bufpos += sizeof(uint16_t); 199 memcpy(tic->extras.buf + tic->extras.bufpos, str, strl); 200 tic->extras.bufpos += strl; 201 break; 202 } 203 tic->extras.entries++; 204 return 1; 205} 206 207ssize_t 208_ti_flatten(uint8_t **buf, const TIC *tic) 209{ 210 size_t buflen, len, alen, dlen; 211 uint8_t *cap; 212 213 _DIAGASSERT(buf != NULL); 214 _DIAGASSERT(tic != NULL); 215 216 len = strlen(tic->name) + 1; 217 if (tic->alias == NULL) 218 alen = 0; 219 else 220 alen = strlen(tic->alias) + 1; 221 if (tic->desc == NULL) 222 dlen = 0; 223 else 224 dlen = strlen(tic->desc) + 1; 225 buflen = sizeof(char) + 226 sizeof(uint16_t) + len + 227 sizeof(uint16_t) + alen + 228 sizeof(uint16_t) + dlen + 229 (sizeof(uint16_t) * 2) + tic->flags.bufpos + 230 (sizeof(uint16_t) * 2) + tic->nums.bufpos + 231 (sizeof(uint16_t) * 2) + tic->strs.bufpos + 232 (sizeof(uint16_t) * 2) + tic->extras.bufpos; 233 *buf = malloc(buflen); 234 if (*buf == NULL) 235 return -1; 236 237 cap = *buf; 238 if (alen == 0 && dlen == 0 && tic->flags.bufpos == 0 && 239 tic->nums.bufpos == 0 && tic->strs.bufpos == 0 && 240 tic->extras.bufpos == 0) 241 *cap++ = 0; /* alias */ 242 else 243 *cap++ = 2; /* version */ 244 le16enc(cap, len); 245 cap += sizeof(uint16_t); 246 memcpy(cap, tic->name, len); 247 cap += len; 248 249 le16enc(cap, alen); 250 cap += sizeof(uint16_t); 251 if (tic->alias != NULL) { 252 memcpy(cap, tic->alias, alen); 253 cap += alen; 254 } 255 le16enc(cap, dlen); 256 cap += sizeof(uint16_t); 257 if (tic->desc != NULL) { 258 memcpy(cap, tic->desc, dlen); 259 cap += dlen; 260 } 261 262 if (tic->flags.entries == 0) { 263 le16enc(cap, 0); 264 cap += sizeof(uint16_t); 265 } else { 266 le16enc(cap, (tic->flags.bufpos + sizeof(uint16_t))); 267 cap += sizeof(uint16_t); 268 le16enc(cap, tic->flags.entries); 269 cap += sizeof(uint16_t); 270 memcpy(cap, tic->flags.buf, tic->flags.bufpos); 271 cap += tic->flags.bufpos; 272 } 273 274 if (tic->nums.entries == 0) { 275 le16enc(cap, 0); 276 cap += sizeof(uint16_t); 277 } else { 278 le16enc(cap, (tic->nums.bufpos + sizeof(uint16_t))); 279 cap += sizeof(uint16_t); 280 le16enc(cap, tic->nums.entries); 281 cap += sizeof(uint16_t); 282 memcpy(cap, tic->nums.buf, tic->nums.bufpos); 283 cap += tic->nums.bufpos; 284 } 285 286 if (tic->strs.entries == 0) { 287 le16enc(cap, 0); 288 cap += sizeof(uint16_t); 289 } else { 290 le16enc(cap, (tic->strs.bufpos + sizeof(uint16_t))); 291 cap += sizeof(uint16_t); 292 le16enc(cap, tic->strs.entries); 293 cap += sizeof(uint16_t); 294 memcpy(cap, tic->strs.buf, tic->strs.bufpos); 295 cap += tic->strs.bufpos; 296 } 297 298 if (tic->extras.entries == 0) { 299 le16enc(cap, 0); 300 cap += sizeof(uint16_t); 301 } else { 302 le16enc(cap, (tic->extras.bufpos + sizeof(uint16_t))); 303 cap += sizeof(uint16_t); 304 le16enc(cap, tic->extras.entries); 305 cap += sizeof(uint16_t); 306 memcpy(cap, tic->extras.buf, tic->extras.bufpos); 307 cap += tic->extras.bufpos; 308 } 309 310 return cap - *buf; 311} 312 313static int 314encode_string(const char *term, const char *cap, TBUF *tbuf, const char *str, 315 int flags) 316{ 317 int slash, i, num; 318 char ch, *p, *s, last; 319 320 if (_ti_grow_tbuf(tbuf, strlen(str) + 1) == NULL) 321 return -1; 322 p = s = tbuf->buf + tbuf->bufpos; 323 slash = 0; 324 last = '\0'; 325 /* Convert escape codes */ 326 while ((ch = *str++) != '\0') { 327 if (slash == 0 && ch == '\\') { 328 slash = 1; 329 continue; 330 } 331 if (slash == 0) { 332 if (last != '%' && ch == '^') { 333 ch = *str++; 334 if (((unsigned char)ch) >= 128) 335 dowarn(flags, 336 "%s: %s: illegal ^ character", 337 term, cap); 338 if (ch == '\0') 339 break; 340 if (ch == '?') 341 ch = '\177'; 342 else if ((ch &= 037) == 0) 343 ch = 128; 344 } 345 *p++ = ch; 346 last = ch; 347 continue; 348 } 349 slash = 0; 350 if (ch >= '0' && ch <= '7') { 351 num = ch - '0'; 352 for (i = 0; i < 2; i++) { 353 if (*str < '0' || *str > '7') { 354 if (isdigit((unsigned char)*str)) 355 dowarn(flags, 356 "%s: %s: non octal" 357 " digit", term, cap); 358 else 359 break; 360 } 361 num = num * 8 + *str++ - '0'; 362 } 363 if (num == 0) 364 num = 0200; 365 *p++ = (char)num; 366 continue; 367 } 368 switch (ch) { 369 case 'a': 370 *p++ = '\a'; 371 break; 372 case 'b': 373 *p++ = '\b'; 374 break; 375 case 'e': /* FALLTHROUGH */ 376 case 'E': 377 *p++ = '\033'; 378 break; 379 case 'f': 380 *p++ = '\014'; 381 break; 382 case 'l': /* FALLTHROUGH */ 383 case 'n': 384 *p++ = '\n'; 385 break; 386 case 'r': 387 *p++ = '\r'; 388 break; 389 case 's': 390 *p++ = ' '; 391 break; 392 case 't': 393 *p++ = '\t'; 394 break; 395 default: 396 397 /* We should warn here */ 398 case '^': 399 case ',': 400 case ':': 401 case '|': 402 *p++ = ch; 403 break; 404 } 405 last = ch; 406 } 407 *p++ = '\0'; 408 tbuf->bufpos += p - s; 409 return 0; 410} 411 412static char * 413get_token(char **cap) 414{ 415 char *token; 416 int esc; 417 418 while (isspace((unsigned char)**cap)) 419 (*cap)++; 420 if (**cap == '\0') 421 return NULL; 422 423 /* We can't use stresep(3) as ^ we need two escape chars */ 424 esc = 0; 425 for (token = *cap; 426 **cap != '\0' && (esc == 1 || **cap != ','); 427 (*cap)++) 428 { 429 if (esc == 0) { 430 if (**cap == '\\' || **cap == '^') 431 esc = 1; 432 } else 433 esc = 0; 434 } 435 436 if (**cap != '\0') 437 *(*cap)++ = '\0'; 438 439 return token; 440} 441 442TIC * 443_ti_compile(char *cap, int flags) 444{ 445 char *token, *p, *e, *name, *desc, *alias; 446 signed char flag; 447 long num; 448 ssize_t ind; 449 size_t len; 450 TBUF buf; 451 TIC *tic; 452 453 _DIAGASSERT(cap != NULL); 454 455 name = get_token(&cap); 456 if (name == NULL) { 457 dowarn(flags, "no seperator found: %s", cap); 458 return NULL; 459 } 460 desc = strrchr(name, '|'); 461 if (desc != NULL) 462 *desc++ = '\0'; 463 alias = strchr(name, '|'); 464 if (alias != NULL) 465 *alias++ = '\0'; 466 467 tic = calloc(sizeof(*tic), 1); 468 if (tic == NULL) 469 return NULL; 470 471 buf.buf = NULL; 472 buf.buflen = 0; 473 474 tic->name = strdup(name); 475 if (tic->name == NULL) 476 goto error; 477 if (alias != NULL && flags & TIC_ALIAS) { 478 tic->alias = strdup(alias); 479 if (tic->alias == NULL) 480 goto error; 481 } 482 if (desc != NULL && flags & TIC_DESCRIPTION) { 483 tic->desc = strdup(desc); 484 if (tic->desc == NULL) 485 goto error; 486 } 487 488 for (token = get_token(&cap); 489 token != NULL && *token != '\0'; 490 token = get_token(&cap)) 491 { 492 /* Skip commented caps */ 493 if (!(flags & TIC_COMMENT) && token[0] == '.') 494 continue; 495 496 /* Obsolete entries */ 497 if (token[0] == 'O' && token[1] == 'T') { 498 if (!(flags & TIC_EXTRA)) 499 continue; 500 token += 2; 501 } 502 503 /* str cap */ 504 p = strchr(token, '='); 505 if (p != NULL) { 506 *p++ = '\0'; 507 /* Don't use the string if we already have it */ 508 ind = _ti_strindex(token); 509 if (ind != -1 && 510 _ti_find_cap(&tic->strs, 's', ind) != NULL) 511 continue; 512 513 /* Encode the string to our scratch buffer */ 514 buf.bufpos = 0; 515 if (encode_string(tic->name, token, 516 &buf, p, flags) == -1) 517 goto error; 518 if (buf.bufpos > UINT16_T_MAX) { 519 dowarn(flags, "%s: %s: string is too long", 520 tic->name, token); 521 continue; 522 } 523 if (!VALID_STRING(buf.buf)) { 524 dowarn(flags, "%s: %s: invalid string", 525 tic->name, token); 526 continue; 527 } 528 529 if (ind == -1) 530 _ti_store_extra(tic, 1, token, 's', -1, -2, 531 buf.buf, buf.bufpos, flags); 532 else { 533 if (!_ti_grow_tbuf(&tic->strs, 534 (sizeof(uint16_t) * 2) + buf.bufpos)) 535 goto error; 536 le16enc(tic->strs.buf + tic->strs.bufpos, ind); 537 tic->strs.bufpos += sizeof(uint16_t); 538 le16enc(tic->strs.buf + tic->strs.bufpos, 539 buf.bufpos); 540 tic->strs.bufpos += sizeof(uint16_t); 541 memcpy(tic->strs.buf + tic->strs.bufpos, 542 buf.buf, buf.bufpos); 543 tic->strs.bufpos += buf.bufpos; 544 tic->strs.entries++; 545 } 546 continue; 547 } 548 549 /* num cap */ 550 p = strchr(token, '#'); 551 if (p != NULL) { 552 *p++ = '\0'; 553 /* Don't use the number if we already have it */ 554 ind = _ti_numindex(token); 555 if (ind != -1 && 556 _ti_find_cap(&tic->nums, 'n', ind) != NULL) 557 continue; 558 559 num = strtol(p, &e, 0); 560 if (*e != '\0') { 561 dowarn(flags, "%s: %s: not a number", 562 tic->name, token); 563 continue; 564 } 565 if (!VALID_NUMERIC(num)) { 566 dowarn(flags, "%s: %s: number out of range", 567 tic->name, token); 568 continue; 569 } 570 if (ind == -1) 571 _ti_store_extra(tic, 1, token, 'n', -1, 572 num, NULL, 0, flags); 573 else { 574 if (_ti_grow_tbuf(&tic->nums, 575 sizeof(uint16_t) * 2) == NULL) 576 goto error; 577 le16enc(tic->nums.buf + tic->nums.bufpos, ind); 578 tic->nums.bufpos += sizeof(uint16_t); 579 le16enc(tic->nums.buf + tic->nums.bufpos, num); 580 tic->nums.bufpos += sizeof(uint16_t); 581 tic->nums.entries++; 582 } 583 continue; 584 } 585 586 flag = 1; 587 len = strlen(token) - 1; 588 if (token[len] == '@') { 589 flag = CANCELLED_BOOLEAN; 590 token[len] = '\0'; 591 } 592 ind = _ti_flagindex(token); 593 if (ind == -1 && flag == CANCELLED_BOOLEAN) { 594 if ((ind = _ti_numindex(token)) != -1) { 595 if (_ti_find_cap(&tic->nums, 'n', ind) != NULL) 596 continue; 597 if (_ti_grow_tbuf(&tic->nums, 598 sizeof(uint16_t) * 2) == NULL) 599 goto error; 600 le16enc(tic->nums.buf + tic->nums.bufpos, ind); 601 tic->nums.bufpos += sizeof(uint16_t); 602 le16enc(tic->nums.buf + tic->nums.bufpos, 603 CANCELLED_NUMERIC); 604 tic->nums.bufpos += sizeof(uint16_t); 605 tic->nums.entries++; 606 continue; 607 } else if ((ind = _ti_strindex(token)) != -1) { 608 if (_ti_find_cap(&tic->strs, 's', ind) != NULL) 609 continue; 610 if (_ti_grow_tbuf(&tic->strs, 611 (sizeof(uint16_t) * 2) + 1) == NULL) 612 goto error; 613 le16enc(tic->strs.buf + tic->strs.bufpos, ind); 614 tic->strs.bufpos += sizeof(uint16_t); 615 le16enc(tic->strs.buf + tic->strs.bufpos, 0); 616 tic->strs.bufpos += sizeof(uint16_t); 617 tic->strs.entries++; 618 continue; 619 } 620 } 621 if (ind == -1) 622 _ti_store_extra(tic, 1, token, 'f', flag, 0, NULL, 0, 623 flags); 624 else if (_ti_find_cap(&tic->flags, 'f', ind) == NULL) { 625 if (_ti_grow_tbuf(&tic->flags, sizeof(uint16_t) + 1) 626 == NULL) 627 goto error; 628 le16enc(tic->flags.buf + tic->flags.bufpos, ind); 629 tic->flags.bufpos += sizeof(uint16_t); 630 tic->flags.buf[tic->flags.bufpos++] = flag; 631 tic->flags.entries++; 632 } 633 } 634 635 free(buf.buf); 636 return tic; 637 638error: 639 free(buf.buf); 640 _ti_freetic(tic); 641 return NULL; 642} 643 644void 645_ti_freetic(TIC *tic) 646{ 647 648 if (tic != NULL) { 649 free(tic->name); 650 free(tic->alias); 651 free(tic->desc); 652 free(tic->flags.buf); 653 free(tic->nums.buf); 654 free(tic->strs.buf); 655 free(tic); 656 } 657} 658