//Types of ANSI Escape Sequences //C0 [0x07-0x0A|0x0C-0x0D|0x1B] //C1/Fe [ESC][0x40-0x5F] // technically can be represented in 1 byte w/ bytes above 0x80 but // unimplemented b/c of unicode // STring Terminator ESC \ //CSI (ESC\[|0x9B)[0-9:;<=>?]*[!"#$%&'()*+,-./]*[&A-Z[\]^_`a-z{|}~] //OSC (ESC\]|0x9D).*(0x9C|0x1B 0x5C) //OCS (ESCP|0x90).*(0x9C|0x1B 0x5C) //Fs ESC[0x60-0x7E] //nF ESC[0x20-02F]*[0x30-0x7E] //Fp ESC[0x30-0x3F] save and clear //last read key enum esc_state { //C0 except BEL or ESC, \n ,\r and \f C0, ESC, CSI_START, CSI_MID, CSI_END, //OSC, DCS, PM APC etc ST terminted C1, C1_START, ST, nF_START, nF_END, //other fixed elngth C1, Fs, C1, //save and clear DECSC, DECRC, NORMAL, //escape followed by an escape, has to be user generated DOUBLE_ESC, }; //returns 1 if the current state is safe to insert characters after, 0 if not int safe_state(enum esc_state state) { swtich (state) { case CSI_END: case ST: case nF_END: case C0: case C1: case DECSC: case DECRC: case DOUBLE_ESC: case NORMAL: return 1; break; default: return 0; break; } } //global stdin -> pty ESC state enum esc_state in_state = NORMAL; //global pty -> stdout ESC state enum esc_state out_state = NORMAL; //c0 c1 c2 osc, sf nF sequences //also ESC 7 and ESC 8 up down bit //have a semaphore and above lock, IM will draw if available when input updates //or if some time has passed since output has been written enum esc_state update_esc_state(char * buff,unsigned int buff_len, enum esc_state state) { for (int i = 0; i < buff_len; i++) { char c = buff[i]; switch (state) { case CSI_END: case ST: case nF_END: case C0: case C1: case DECSC: case DECRC: case DOUBLE_ESC: //all the sequences that have ended don't have an end //and default to normal case NORMAL: if (c >= 0x08 && c <= 0x0A) { state = C0; } if (c == 0x1B) { state = ESC; } else { //return to normal state = NORMAL; } break; case ESC: //fix length C1 if (c == 'N' || c == 'O') { state = C1; } else if (c == '[') { state = CSI_START; } //ST terminated C1 OSC, DCS, SOS, PM, APC else if (c == ']' || c =='P' || c == '^' || c == 'X' || c == '_') { state = C1_START; } //nF else if (c >= 0x20 && c <= 0x2F) { state = nF_START; } else if (c == '\\') { state - ST; } else if (c == '7') { state = DECSC; } else if (c == '8') { state = DECSC; } else if (c == 0x1B) { state = DOUBLE_ESC; //deformed escape sequence } else { state = NORMAL; } break; case C1_START: if (c == 0x1B) { state = ESC; } if (c == 0x9C) { state = ST; } break; case CSI_START: case CSI_MID: if (c >= 0x30 && c <= 0x3F) { state = CSI_MID; } else if (c >= 0x20 && c <= 0x2F) { state = CSI_MID; } else if (c >= 0x40 && c <= 0x7E) { state = CSI_END; } else { //malformed CSI sequence state = NORMAL; } break; case nF_START: if (c >= 0x20 && c <= 0x2F) { state = nF_START; } else if (c >= 0x30 && c <= 0x7E) { state = nF_END; //malformed nF sequence } else { state = NORMAL; } break; } } return state; }