[tinfo] factor out do_terminfo_lookups()

pull/2549/head
nick black 2 years ago committed by nick black
parent 2584435efc
commit 5806aa6864

@ -1478,6 +1478,76 @@ xtversion_cb(inputctx* ictx){
return 2;
}
// precondition: s starts with two hex digits, the first of which is not
// greater than 7.
static inline char
toxdigit(const char* s){
char c = isalpha(*s) ? tolower(*s) - 'a' + 10 : *s - '0';
c *= 16;
++s;
c += isalpha(*s) ? tolower(*s) - 'a' + 10 : *s - '0';
return c;
}
// on success, the subsequent character is returned, and |key| and |val| have
// heap-allocated, decoded, nul-terminated copies of the appropriate input.
static const char*
gettcap(const char* s, char** key, char** val){
const char* equals = s;
while(*equals != '='){
if(!isxdigit(*equals)){ // rejects a NUL byte
logerror("bad key in %s", s);
return NULL;
}
++equals;
}
if(equals - s == 0 || (equals - s) % 2){
logerror("bad key in %s", s);
return NULL;
}
if((*key = malloc((equals - s) / 2 + 1)) == NULL){
return NULL;
}
char* keytarg = *key;
do{
*keytarg = toxdigit(s);
s += 2;
++keytarg;
}while(*s != '=');
*keytarg = '\0';
++equals; // now one past the equal sign
const char *end = equals;
while(*end != ';' && *end){
if(!isxdigit(*end)){
logerror("bad value in %s", s);
goto valerr;
}
++end;
}
if(end - equals == 0 || (end - equals) % 2){
logerror("bad value in %s", s);
goto valerr;
}
if((*val = malloc((end - equals) / 2 + 1)) == NULL){
goto valerr;
}
char* valtarg = *val;
++s;
do{
*valtarg = toxdigit(s);
s += 2;
++valtarg;
}while(s != end);
*valtarg = '\0';
loginfo("key: %s val: %s", *key, *val);
return end;
valerr:
free(*key);
*key = NULL;
return end;
}
// XTGETTCAP responses are delimited by semicolons
static int
tcap_cb(inputctx* ictx){
@ -1490,47 +1560,41 @@ tcap_cb(inputctx* ictx){
free(str);
return 2;
}
char* s = str;
while(*s){
// FIXME clean this crap up, grotesque
if(strncasecmp(s, "544e=", 5) == 0){
size_t len = 5;
while(s[len] && s[len] != ';'){
++len;
}
const char* tn = s + 5;
len -= 5;
const char* s = str;
char* key;
char* val;
// answers are delimited with semicolons, hex-encoded, key=value
while(*s && (s = gettcap(s, &val, &key)) ){
if(strcmp(val, "TN") == 0){
if(ictx->initdata->qterm == TERMINAL_UNKNOWN){
if(len == 10){
if(strncasecmp(tn, "787465726d", 10) == 0){
ictx->initdata->qterm = TERMINAL_XTERM; // "xterm"
}
}else if(len == 12){
if(strncasecmp(tn, "6D6C7465726D", 12) == 0){
ictx->initdata->qterm = TERMINAL_MLTERM;
}
}else if(len == 22){
if(strncasecmp(tn, "787465726d2d6b69747479", 22) == 0){
ictx->initdata->qterm = TERMINAL_KITTY; // "xterm-kitty"
}
}else if(len == 28){
if(strncasecmp(tn, "787465726d2d323536636f6c6f72", 28) == 0){
ictx->initdata->qterm = TERMINAL_XTERM; // "xterm-256color"
}
if(strcasecmp(key, "xterm") == 0){
ictx->initdata->qterm = TERMINAL_XTERM; // "xterm"
}else if(strcasecmp(key, "mlterm") == 0){
ictx->initdata->qterm = TERMINAL_MLTERM;
}else if(strcasecmp(key, "xterm-kitty") == 0){
ictx->initdata->qterm = TERMINAL_KITTY; // "xterm-kitty"
}else if(strcasecmp(key, "xterm-256color") == 0){
ictx->initdata->qterm = TERMINAL_XTERM; // "xterm-256color"
}else{
logdebug("unknown terminal name %s", tn);
logdebug("unknown terminal name %s", key);
}
}
}else if(strncasecmp(s, "524742=", 7) == 0){
}else if(strcmp(val, "RGB") == 0){
loginfo("got rgb (%s)", s);
ictx->initdata->rgb = true;
}else if(strcmp(val, "hpa") == 0){
loginfo("got hpa (%s)", key);
ictx->initdata->hpa = key;
key = NULL;
}else{
logdebug("unknown capability=val %s", str);
logwarn("unknown capability: %s", str);
}
if((s = strchr(s, ';')) == NULL){
break;
}
++s;
free(val);
free(key);
}
if(*s){
free(str);
return -1;
}
free(str);
return 2;

@ -82,6 +82,7 @@ struct initial_responses {
ncpalette palette; // palette entries
int maxpaletteread; // maximum palette index read
bool pixelmice; // have we pixel-based mice events?
char* hpa; // control sequence for hpa via XTGETTCAP
};
// Blocking call. Waits until the input thread has processed all responses to

@ -8,6 +8,9 @@ extern "C" {
// logging
extern ncloglevel_e loglevel;
static inline void nclog(const char* fmt, ...)
__attribute__ ((format (printf, 1, 2)));
static inline void
nclog(const char* fmt, ...){
va_list va;

@ -455,8 +455,15 @@ init_terminfo_esc(tinfo* ti, const char* name, escape_e idx,
// XTVERSION. Replies with DCS > | ... ST
#define XTVERSION "\x1b[>0q"
// XTGETTCAP['TN', 'RGB'] (Terminal Name, RGB)
#define XTGETTCAP "\x1bP+q544e;524742\x1b\\"
// ideally we'd abandon terminfo entirely (terminfo is great; TERM sucks), and
// get all properties through terminal queries. we don't yet, but grab a few
// of importance that we know to oftentimes be incorrect:
// * TN (544e): terminal name; a poor man's XTVERSION
// * RGB (524742): 24-bit color is supported via setaf/setab
// * hpa (687061): broken in Kitty FreeBSD terminfo (#2541)
// XTGETTCAP['TN', 'RGB', 'hpa']
// (Terminal Name, RGB, Horizontal Position Absolute)
#define XTGETTCAP "\x1bP+q544e;524742;687061\x1b\\"
// Secondary Device Attributes, necessary to get Alacritty's version. Since
// this doesn't uniquely identify a terminal, we ask it last, so that if any
@ -1052,6 +1059,60 @@ unix_early_matches(const char* term){
#endif
#endif
static int
do_terminfo_lookups(tinfo *ti, size_t* tablelen, size_t* tableused){
// don't list any here for which we also send XTGETTCAP sequences
const struct strtdesc {
escape_e esc;
const char* tinfo;
} strtdescs[] = {
{ ESCAPE_CUP, "cup", },
{ ESCAPE_HPA, "hpa", },
{ ESCAPE_VPA, "vpa", },
// Not all terminals support setting the fore/background independently
{ ESCAPE_SETAF, "setaf", },
{ ESCAPE_SETAB, "setab", },
{ ESCAPE_OP, "op", },
{ ESCAPE_CNORM, "cnorm", },
{ ESCAPE_CIVIS, "civis", },
{ ESCAPE_SGR0, "sgr0", },
{ ESCAPE_SITM, "sitm", },
{ ESCAPE_RITM, "ritm", },
{ ESCAPE_BOLD, "bold", },
{ ESCAPE_CUD, "cud", },
{ ESCAPE_CUU, "cuu", },
{ ESCAPE_CUF, "cuf", },
{ ESCAPE_CUB, "cub", },
{ ESCAPE_U7, "u7", },
{ ESCAPE_SMKX, "smkx", },
{ ESCAPE_SMXX, "smxx", },
{ ESCAPE_EL, "el", },
{ ESCAPE_RMXX, "rmxx", },
{ ESCAPE_SMUL, "smul", },
{ ESCAPE_RMUL, "rmul", },
{ ESCAPE_SC, "sc", },
{ ESCAPE_RC, "rc", },
{ ESCAPE_IND, "ind", },
{ ESCAPE_INDN, "indn", },
{ ESCAPE_CLEAR, "clear", },
{ ESCAPE_OC, "oc", },
{ ESCAPE_RMKX, "rmkx", },
{ ESCAPE_INITC, "initc", },
{ ESCAPE_MAX, NULL, },
};
for(typeof(*strtdescs)* strtdesc = strtdescs ; strtdesc->esc < ESCAPE_MAX ; ++strtdesc){
if(init_terminfo_esc(ti, strtdesc->tinfo, strtdesc->esc, tablelen, tableused)){
return -1;
}
}
// verify that the terminal provides cursor addressing (absolute movement)
if(ti->escindices[ESCAPE_CUP] == 0){
logpanic("required terminfo capability 'cup' not defined");
return -1;
}
return 0;
}
// if |termtype| is not NULL, it is used to look up the terminfo database entry
// via setupterm(). the value of the TERM environment variable is otherwise
// (implicitly) used. some details are not exposed via terminfo, and we must
@ -1167,52 +1228,7 @@ int interrogate_terminfo(tinfo* ti, FILE* out, unsigned utf8,
}
ti->caps.rgb = query_rgb(); // independent of colors
}
const struct strtdesc {
escape_e esc;
const char* tinfo;
} strtdescs[] = {
{ ESCAPE_CUP, "cup", },
{ ESCAPE_HPA, "hpa", },
{ ESCAPE_VPA, "vpa", },
// Not all terminals support setting the fore/background independently
{ ESCAPE_SETAF, "setaf", },
{ ESCAPE_SETAB, "setab", },
{ ESCAPE_OP, "op", },
{ ESCAPE_CNORM, "cnorm", },
{ ESCAPE_CIVIS, "civis", },
{ ESCAPE_SGR0, "sgr0", },
{ ESCAPE_SITM, "sitm", },
{ ESCAPE_RITM, "ritm", },
{ ESCAPE_BOLD, "bold", },
{ ESCAPE_CUD, "cud", },
{ ESCAPE_CUU, "cuu", },
{ ESCAPE_CUF, "cuf", },
{ ESCAPE_CUB, "cub", },
{ ESCAPE_U7, "u7", },
{ ESCAPE_SMKX, "smkx", },
{ ESCAPE_SMXX, "smxx", },
{ ESCAPE_EL, "el", },
{ ESCAPE_RMXX, "rmxx", },
{ ESCAPE_SMUL, "smul", },
{ ESCAPE_RMUL, "rmul", },
{ ESCAPE_SC, "sc", },
{ ESCAPE_RC, "rc", },
{ ESCAPE_IND, "ind", },
{ ESCAPE_INDN, "indn", },
{ ESCAPE_CLEAR, "clear", },
{ ESCAPE_OC, "oc", },
{ ESCAPE_RMKX, "rmkx", },
{ ESCAPE_INITC, "initc", },
{ ESCAPE_MAX, NULL, },
};
for(typeof(*strtdescs)* strtdesc = strtdescs ; strtdesc->esc < ESCAPE_MAX ; ++strtdesc){
if(init_terminfo_esc(ti, strtdesc->tinfo, strtdesc->esc, &tablelen, &tableused)){
goto err;
}
}
// verify that the terminal provides cursor addressing (absolute movement)
if(ti->escindices[ESCAPE_CUP] == 0){
logpanic("required terminfo capability 'cup' not defined");
if(do_terminfo_lookups(ti, &tablelen, &tableused)){
goto err;
}
if(ti->ttyfd >= 0){

Loading…
Cancel
Save