From fc6bc1a3d8e885b69ad333c72e41a143fe2d5b1a Mon Sep 17 00:00:00 2001 From: nick black Date: Sun, 13 Jun 2021 12:17:35 -0400 Subject: [PATCH] build up pump_control_read() state machine, terminate on DA response #1469 --- src/lib/input.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/src/lib/input.c b/src/lib/input.c index 5d7fca170..7cf22bda4 100644 --- a/src/lib/input.c +++ b/src/lib/input.c @@ -610,6 +610,86 @@ void ncinputlayer_stop(ncinputlayer* nilayer){ input_free_esctrie(&nilayer->inputescapes); } +typedef struct init_state { + tinfo* tcache; + enum { + STATE_NULL, + STATE_ESC, + STATE_CSI, + STATE_DCS, + STATE_DA, + } state; +} init_state; + +// FIXME ought implement the full Williams automaton +// 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, "char: %c %d %02x\n", c, c, c); + if(c == NCKEY_ESC){ + if(inits->state != STATE_NULL){ + fprintf(stderr, "Unexpected escape in state %d\n", inits->state); + } + inits->state = STATE_ESC; + return 0; + } + switch(inits->state){ + case STATE_NULL: + // not an escape -- throw into user queue + break; + case STATE_ESC: + if(c == '['){ + inits->state = STATE_CSI; + }else if(c == 'P'){ + inits->state = STATE_DCS; + } + break; + case STATE_CSI: + if(c == '?'){ + inits->state = STATE_DA; + } + break; + case STATE_DA: + if(c == 'c'){ + inits->state = STATE_NULL; + return 1; + } + break; + default: + fprintf(stderr, "Reached invalid init state %d\n", inits->state); + return -1; + } + return 0; +} + +// complete the terminal detection process +static int +control_read(tinfo* tcache, int ttyfd){ + init_state inits = { + .tcache = tcache, + .state = STATE_NULL, + }; + unsigned char* buf; + ssize_t s; + + if((buf = malloc(BUFSIZ)) == NULL){ + return -1; + } + while((s = read(ttyfd, buf, sizeof(buf))) != -1){ + for(ssize_t idx = 0; idx < s ; ++idx){ + if(pump_control_read(&inits, buf[idx]) == 1){ // success! + free(buf); + return 0; + } + } + } + fprintf(stderr, "failed on %d (%s)\n", ttyfd, strerror(errno)); + free(buf); + return -1; +} + // FIXME complete terminal detection + int ncinputlayer_init(tinfo* tcache, FILE* infp){ ncinputlayer* nilayer = &tcache->input; setbuffer(infp, NULL, 0); @@ -623,8 +703,6 @@ int ncinputlayer_init(tinfo* tcache, FILE* infp){ nilayer->inputbuf_valid_starts = 0; nilayer->inputbuf_write_at = 0; nilayer->input_events = 0; - if(nilayer->ttyfd >= 0){ - // FIXME complete terminal detection - } + control_read(tcache, nilayer->ttyfd >= 0 ? nilayer->ttyfd : nilayer->infd); return 0; }