diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | escape.h | 133 | ||||
-rw-r--r-- | ptyim.c | 35 |
3 files changed, 158 insertions, 12 deletions
@@ -1,4 +1,4 @@ -ptyim: ptyim.c im.h boshiamy.h +ptyim: ptyim.c im.h escape.h boshiamy.h gcc ptyim.c -o ptyim install: ptyim cp ptyim /usr/bin/ptyim diff --git a/escape.h b/escape.h new file mode 100644 index 0000000..8b5f0dd --- /dev/null +++ b/escape.h @@ -0,0 +1,133 @@ +//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, +}; +//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: + //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; + //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; +} @@ -12,12 +12,15 @@ #include <signal.h> #include <sys/prctl.h> #include "im.h" +#include "escape.h" #define WRITE_BUFFER_LEN 128 //determines if the master process is running int running = 1; //hook for when the pty child process dies void childhook(int a) { running = 0; + //this way it exists even if the loop is waiting for 1 last read char + _exit(0); } //pty master and slave fd int pty_slave = -1; @@ -170,17 +173,27 @@ int main (int argc, char * argv[], char * envp[]) { while (running) { int rchars_read = read(STDIN_FILENO, read_buffer, 1); if (rchars_read > 0) { - //feeds the input char into the im state machine - char input_buffer[IM_TABLE_ENTRY_LEN+1] = {0}; - int im_chars = update_im_state(read_buffer[0], - input_buffer); - //just in case it wasn't null terminated right - input_buffer[im_chars] = 0; - if (im_chars >0) { - //writes the input into pty_master if - //there was an output from the state - //machine - write(pty_master,input_buffer,im_chars); + //feeds input char into the escape state + //machine + in_state = update_esc_state(read_buffer, 1, in_state); + fprintf(stderr, "%c: %d\n", read_buffer[0],in_state); + //skips if the char was anything but + //normal + if (in_state == NORMAL) { + //feeds the input char into the im state machine + char input_buffer[IM_TABLE_ENTRY_LEN+1] = {0}; + int im_chars = update_im_state(read_buffer[0], + input_buffer); + //just in case it wasn't null terminated right + input_buffer[im_chars] = 0; + if (im_chars >0) { + //writes the input into pty_master if + //there was an output from the state + //machine + write(pty_master,input_buffer,im_chars); + } + } else { + write(pty_master,read_buffer,1); } //any input update will lead to a disp_im update disp_im(STDIN_FILENO, trows, tcols); |