TIC * _ti_compile(char *cap, int flags) { char *token, *p, *e, *name, *desc, *alias; signed char flag; long cnum; short num; ssize_t ind; size_t len; TBUF buf; TIC *tic; _DIAGASSERT(cap != NULL); name = _ti_get_token(&cap, ','); if (name == NULL) { dowarn(flags, "no seperator found: %s", cap); return NULL; } desc = strrchr(name, '|'); if (desc != NULL) *desc++ = '\0'; alias = strchr(name, '|'); if (alias != NULL) *alias++ = '\0'; tic = calloc(sizeof(*tic), 1); if (tic == NULL) return NULL; buf.buf = NULL; buf.buflen = 0; tic->name = strdup(name); if (tic->name == NULL) goto error; if (alias != NULL && flags & TIC_ALIAS) { tic->alias = strdup(alias); if (tic->alias == NULL) goto error; } if (desc != NULL && flags & TIC_DESCRIPTION) { tic->desc = strdup(desc); if (tic->desc == NULL) goto error; } for (token = _ti_get_token(&cap, ','); token != NULL && *token != '\0'; token = _ti_get_token(&cap, ',')) { /* Skip commented caps */ if (!(flags & TIC_COMMENT) && token[0] == '.') continue; /* Obsolete entries */ if (token[0] == 'O' && token[1] == 'T') { if (!(flags & TIC_EXTRA)) continue; token += 2; } /* str cap */ p = strchr(token, '='); if (p != NULL) { *p++ = '\0'; /* Don't use the string if we already have it */ ind = _ti_strindex(token); if (ind != -1 && _ti_find_cap(&tic->strs, 's', ind) != NULL) continue; /* Encode the string to our scratch buffer */ buf.bufpos = 0; if (encode_string(tic->name, token, &buf, p, flags) == -1) goto error; if (buf.bufpos > UINT16_T_MAX) { dowarn(flags, "%s: %s: string is too long", tic->name, token); continue; } if (!VALID_STRING(buf.buf)) { dowarn(flags, "%s: %s: invalid string", tic->name, token); continue; } if (ind == -1) _ti_store_extra(tic, 1, token, 's', -1, -2, buf.buf, buf.bufpos, flags); else { if (!_ti_grow_tbuf(&tic->strs, (sizeof(uint16_t) * 2) + buf.bufpos)) goto error; le16enc(tic->strs.buf + tic->strs.bufpos, ind); tic->strs.bufpos += sizeof(uint16_t); le16enc(tic->strs.buf + tic->strs.bufpos, buf.bufpos); tic->strs.bufpos += sizeof(uint16_t); memcpy(tic->strs.buf + tic->strs.bufpos, buf.buf, buf.bufpos); tic->strs.bufpos += buf.bufpos; tic->strs.entries++; } continue; } /* num cap */ p = strchr(token, '#'); if (p != NULL) { *p++ = '\0'; /* Don't use the number if we already have it */ ind = _ti_numindex(token); if (ind != -1 && _ti_find_cap(&tic->nums, 'n', ind) != NULL) continue; cnum = strtol(p, &e, 0); if (*e != '\0') { dowarn(flags, "%s: %s: not a number", tic->name, token); continue; } if (!VALID_NUMERIC(cnum)) { dowarn(flags, "%s: %s: number out of range", tic->name, token); continue; } num = (short)cnum; if (ind == -1) _ti_store_extra(tic, 1, token, 'n', -1, num, NULL, 0, flags); else { if (_ti_grow_tbuf(&tic->nums, sizeof(uint16_t) * 2) == NULL) goto error; le16enc(tic->nums.buf + tic->nums.bufpos, ind); tic->nums.bufpos += sizeof(uint16_t); le16enc(tic->nums.buf + tic->nums.bufpos, num); tic->nums.bufpos += sizeof(uint16_t); tic->nums.entries++; } continue; } flag = 1; len = strlen(token) - 1; if (token[len] == '@') { flag = CANCELLED_BOOLEAN; token[len] = '\0'; } ind = _ti_flagindex(token); if (ind == -1 && flag == CANCELLED_BOOLEAN) { if ((ind = _ti_numindex(token)) != -1) { if (_ti_find_cap(&tic->nums, 'n', ind) != NULL) continue; if (_ti_grow_tbuf(&tic->nums, sizeof(uint16_t) * 2) == NULL) goto error; le16enc(tic->nums.buf + tic->nums.bufpos, ind); tic->nums.bufpos += sizeof(uint16_t); le16enc(tic->nums.buf + tic->nums.bufpos, (uint16_t)CANCELLED_NUMERIC); tic->nums.bufpos += sizeof(uint16_t); tic->nums.entries++; continue; } else if ((ind = _ti_strindex(token)) != -1) { if (_ti_find_cap(&tic->strs, 's', ind) != NULL) continue; if (_ti_grow_tbuf(&tic->strs, (sizeof(uint16_t) * 2) + 1) == NULL) goto error; le16enc(tic->strs.buf + tic->strs.bufpos, ind); tic->strs.bufpos += sizeof(uint16_t); le16enc(tic->strs.buf + tic->strs.bufpos, 0); tic->strs.bufpos += sizeof(uint16_t); tic->strs.entries++; continue; } } if (ind == -1) _ti_store_extra(tic, 1, token, 'f', flag, 0, NULL, 0, flags); else if (_ti_find_cap(&tic->flags, 'f', ind) == NULL) { if (_ti_grow_tbuf(&tic->flags, sizeof(uint16_t) + 1) == NULL) goto error; le16enc(tic->flags.buf + tic->flags.bufpos, ind); tic->flags.bufpos += sizeof(uint16_t); tic->flags.buf[tic->flags.bufpos++] = flag; tic->flags.entries++; } } free(buf.buf); return tic; error: free(buf.buf); _ti_freetic(tic); return NULL; }
static int _ti_findterm(TERMINAL *term, const char *name, int flags) { int r; char *c, *e, h[PATH_MAX]; TIC *tic; uint8_t *f; ssize_t len; _DIAGASSERT(term != NULL); _DIAGASSERT(name != NULL); database[0] = '\0'; _ti_database = NULL; r = 0; if ((e = getenv("TERMINFO")) != NULL && *e != '\0') if (e[0] == '/') return _ti_dbgetterm(term, e, name, flags); c = NULL; #ifdef USE_TERMCAP if (e == NULL && (c = getenv("TERMCAP")) != NULL) { if (*c != '\0' && *c != '/') { c = strdup(c); if (c != NULL) { e = captoinfo(c); free(c); } } } #endif if (e != NULL) { if (c == NULL) e = strdup(e); /* So we don't destroy env */ if (e == NULL) tic = NULL; else { tic = _ti_compile(e, TIC_WARNING | TIC_ALIAS | TIC_DESCRIPTION | TIC_EXTRA); free(e); } if (tic != NULL && ticcmp(tic, name) == 0) { len = _ti_flatten(&f, tic); if (len != -1) { r = _ti_readterm(term, (char *)f, (size_t)len, flags); free(f); } } _ti_freetic(tic); if (r == 1) { if (c == NULL) _ti_database = "$TERMINFO"; else _ti_database = "$TERMCAP"; return r; } } if ((e = getenv("TERMINFO_DIRS")) != NULL) return _ti_dbgettermp(term, e, name, flags); if ((e = getenv("HOME")) != NULL) { snprintf(h, sizeof(h), "%s/.terminfo", e); r = _ti_dbgetterm(term, h, name, flags); } if (r != 1) r = _ti_dbgettermp(term, _PATH_TERMINFO, name, flags); return r; }