diff --git a/src/lib/input.c b/src/lib/input.c index 579db8bae..b6c224a5d 100644 --- a/src/lib/input.c +++ b/src/lib/input.c @@ -624,8 +624,12 @@ typedef struct init_state { STATE_XTGETTCAP1, // XTGETTCAP, got '0/1' (DCS 0/1 + r Pt ST) STATE_XTGETTCAP2, // XTGETTCAP, got '+' (DCS 0/1 + r Pt ST) STATE_XTGETTCAP3, // XTGETTCAP, got 'r' (DCS 0/1 + r Pt ST) + STATE_XTGETTCAP_TERMNAME1, // got property 544E, 'TN' (terminal name) first hex nibble + STATE_XTGETTCAP_TERMNAME2, // got property 544E, 'TN' (terminal name) second hex nibble STATE_DCS_DRAIN, // throw away input until we hit escape - STATE_TDA, // tertiary DA + STATE_TDA1, // tertiary DA, got '!' + STATE_TDA2, // tertiary DA, got '|', first hex nibble + STATE_TDA3, // tertiary DA, second hex nibble STATE_SDA, // secondary DA (CSI > Pp ; Pv ; Pc c) STATE_DA, // primary DA (CSI ? ... c) OR XTSMGRAPHICS STATE_DA_1, // got '1', XTSMGRAPHICS color registers or primary DA @@ -642,6 +646,8 @@ typedef struct init_state { STATE_XTSMGRAPHICS_DRAIN, // drain out XTSMGRAPHICS to 'S' } state; int numeric; // currently-lexed numeric + char runstring[80]; // running string + size_t stridx; // position to write in string bool xtgettcap_good; // high when we've received DCS 1 } init_state; @@ -659,13 +665,54 @@ ruts_numeric(int* numeric, unsigned char c){ return 0; } +static int +ruts_hex(int* numeric, unsigned char c){ + if(!isxdigit(c)){ + return -1; + } + int digit; + if(isdigit(c)){ + digit = c - '0'; + }else if(islower(c)){ + digit = c - 'a' + 10; + }else if(isupper(c)){ + digit = c - 'A' + 10; + }else{ + return -1; // should be impossible to reach + } + if(INT_MAX / 10 - digit < *numeric){ // would overflow + return -1; + } + *numeric *= 16; + *numeric += digit; + return 0; +} + +// add a decoded hex byte to the string +static int +ruts_string(init_state* inits){ + if(inits->stridx == sizeof(inits->runstring)){ + return -1; // overflow, too long + } + if(inits->numeric > 255){ + return -1; + } + unsigned char c = inits->numeric; + if(!isprint(c)){ + return -1; + } + inits->runstring[inits->stridx] = c; + inits->runstring[++inits->stridx] = '\0'; + return 0; +} + // FIXME ought implement the full Williams automaton // FIXME doesn't handle 8-bit controls (would need convert UTF-8) // returns 1 after handling the Device Attributes response, 0 if more input // ought be fed to the machine, and -1 on an invalid state transition. static int pump_control_read(init_state* inits, unsigned char c){ -//fprintf(stderr, "state: %2d char: %1c %3d %02x\n", inits->state, isprint(c) ? c : ' ', c, c); +fprintf(stderr, "state: %2d char: %1c %3d %02x\n", inits->state, isprint(c) ? c : ' ', c, c); if(c == NCKEY_ESC){ /*if(inits->state != STATE_NULL && inits->state != STATE_DCS && inits->state != STATE_DCS_DRAIN && inits->state != STATE_XTVERSION2 && inits->state != STATE_XTGETTCAP3 && inits->state != STATE_DA_DRAIN){ fprintf(stderr, "Unexpected escape in state %d\n", inits->state); @@ -684,8 +731,7 @@ pump_control_read(init_state* inits, unsigned char c){ }else if(c == 'P'){ inits->state = STATE_DCS; }else if(c == '\\'){ -//fprintf(stderr, "string terminator -- parse previous response FIXME\n"); - // FIXME only now do we parse e.g. XTGETTCAP response +fprintf(stderr, "string terminator after [%s]\n", inits->runstring); inits->state = STATE_NULL; } break; @@ -700,7 +746,7 @@ pump_control_read(init_state* inits, unsigned char c){ break; case STATE_DCS: // terminated by ST if(c == '\\'){ - fprintf(stderr, "terminated DCS\n"); +//fprintf(stderr, "terminated DCS\n"); inits->state = STATE_NULL; }else if(c == '1'){ inits->state = STATE_XTGETTCAP1; @@ -710,6 +756,8 @@ pump_control_read(init_state* inits, unsigned char c){ inits->xtgettcap_good = false; }else if(c == '>'){ inits->state = STATE_XTVERSION1; + }else if(c == '!'){ + inits->state = STATE_TDA1; }else{ inits->state = STATE_DCS_DRAIN; } @@ -720,12 +768,17 @@ pump_control_read(init_state* inits, unsigned char c){ case STATE_XTVERSION1: if(c == '|'){ inits->state = STATE_XTVERSION2; + inits->stridx = 0; + inits->runstring[0] = '\0'; }else{ // FIXME error? } break; case STATE_XTVERSION2: - // FIXME roll up string + inits->numeric = c; + if(ruts_string(inits)){ + return -1; + } break; case STATE_XTGETTCAP1: if(c == '+'){ @@ -742,10 +795,59 @@ pump_control_read(init_state* inits, unsigned char c){ } break; case STATE_XTGETTCAP3: - // FIXME feed to terminfo buffer + if(c == '='){ + if(inits->numeric == 0x544e){ + inits->state = STATE_XTGETTCAP_TERMNAME1; + inits->stridx = 0; + inits->numeric = 0; + inits->runstring[0] = '\0'; + }else{ + inits->state = STATE_DCS_DRAIN; + } + }else if(ruts_hex(&inits->numeric, c)){ + return -1; + } break; - case STATE_TDA: - // FIXME + case STATE_XTGETTCAP_TERMNAME1: + if(ruts_hex(&inits->numeric, c)){ + return -1; + } + inits->state = STATE_XTGETTCAP_TERMNAME2; + break; + case STATE_XTGETTCAP_TERMNAME2: + if(ruts_hex(&inits->numeric, c)){ + return -1; + } + inits->state = STATE_XTGETTCAP_TERMNAME1; + if(ruts_string(inits)){ + return -1; + } + inits->numeric = 0; + break; + case STATE_TDA1: + if(c == '|'){ + inits->state = STATE_TDA2; + inits->stridx = 0; + inits->runstring[0] = '\0'; + }else{ + // FIXME + } + break; + case STATE_TDA2: + if(ruts_hex(&inits->numeric, c)){ + return -1; + } + inits->state = STATE_TDA3; + break; + case STATE_TDA3: + if(ruts_hex(&inits->numeric, c)){ + return -1; + } + inits->state = STATE_TDA2; + if(ruts_string(inits)){ + inits->state = STATE_DCS_DRAIN; + } + inits->numeric = 0; break; case STATE_SDA: if(c == 'c'){ diff --git a/src/lib/termdesc.h b/src/lib/termdesc.h index 38e3c45ab..8d5e04f50 100644 --- a/src/lib/termdesc.h +++ b/src/lib/termdesc.h @@ -170,11 +170,11 @@ term_supported_styles(const tinfo* ti){ enum queried_terminal { TERMINAL_UNKNOWN, // no useful information from queries; use termname TERMINAL_LINUX, // ioctl()s - TERMINAL_XTERM, - TERMINAL_VTE, - TERMINAL_ALACRITTY, - TERMINAL_KITTY, // XTGETTCAP['TN'] + TERMINAL_XTERM, // XTVERSION == 'XTerm(ver)' + TERMINAL_VTE, // TDA: "~VTE" + TERMINAL_KITTY, // XTGETTCAP['TN'] == 'xterm-kitty' TERMINAL_FOOT, // TDA: "\EP!|464f4f54\E\\" + TERMINAL_MLTERM, // XTGETTCAP['TN'] == 'mlterm' TERMINAL_WEZTERM, };