From fceb15b1d325a7bb0bcab8993a1057cb991172e8 Mon Sep 17 00:00:00 2001 From: Michal Idziorek Date: Fri, 22 May 2015 03:28:49 +0200 Subject: support for fg and bg color escape sequences --- terminal/terminal.c | 552 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 552 insertions(+) create mode 100644 terminal/terminal.c (limited to 'terminal/terminal.c') diff --git a/terminal/terminal.c b/terminal/terminal.c new file mode 100644 index 0000000..4d3a1a0 --- /dev/null +++ b/terminal/terminal.c @@ -0,0 +1,552 @@ +// +// http://en.wikipedia.org/wiki/VT52 +// http://vt100.net/docs/vt520-rm/ +// man 4 console_codes +// + +#include "terminal.h" +#include "kernel/kmalloc.h" +#include "driver/screen.h" + +#define SET_LFNL true +#define SET_BUFF true +#define SET_ECHO true + + +typedef enum { + + ecma48_reset, + ecma48_bold, + ecma48_halfbright, + ecma48_underscore, + ecma48_blink, + ecma48_reverse_video, + ecma48_reset_mapping, + ecma48_null_mapping_1, + ecma48_null_mapping_2, + ecma48_normalbright_1, + ecma48_normalbright_2, + ecma48_nounderline, + ecma48_blinkoff, + ecma48_reverse_video_off, + + ecma48_fg_black =30, + ecma48_fg_red, + ecma48_fg_green, + ecma48_fg_brown, + ecma48_fg_blue, + ecma48_fg_magenta, + ecma48_fg_cyan, + ecma48_fg_white, + ecma48_undersore_on, // set def color + ecma48_undersore_off, // set def color + + ecma48_bg_black, + ecma48_bg_red, + ecma48_bg_green, + ecma48_bg_brown, + ecma48_bg_blue, + ecma48_bg_magenta, + ecma48_bg_cyan, + ecma48_bg_white, + + ecma48_bg_default =49, + +}terminal_settings; + + +// deprecated +#define VT52_WIDTH 75 +#define VT52_HEIGHT 24 + +#define VT52_ESC_1 0x1b //ESC + +#define VT52_UP 'A' +#define VT52_DOWN 'B' +#define VT52_RIGHT 'C' +#define VT52_LEFT 'D' +#define VT52_GRAPH_ON 'F' +#define VT52_GRAPH_OFF 'G' +#define VT52_HOME 'H' +#define VT52_REV_FEED 'I' +#define VT52_ERASE_SCR 'J' +#define VT52_ERASE_LINE 'K' +#define VT52_KEYPAD_ON '=' +#define VT52_KEYPAD_OFF '>' + +#define VT52_EXIT '<' + +#define VT52_ENTER_AUTOPRINT '^' +#define VT52_EXIT_AUTOPRINT '_' + +#define VT52_PRINT_LINE 'W' +#define VT52_ENTER_PRINT 'W' +#define VT52_EXIT_PRINT 'X' +#define VT52_PRINT ']' +#define VT52_JUMP 'Y' // followed by LINE COL (subtr -32 from val) +#define VT52_IDENTIFY 'Z' +#define VT52_IDENTIFY_TO_HOST "/Z" +// + +#define NPAR_START 1000 + +static uint32_t index(terminal_tty *tty, uint32_t x, uint32_t y) +{ + return tty->width*y+x; +} + +static void set_char(terminal_tty *tty, uint32_t x, uint32_t y, uint8_t c, uint8_t fg, uint8_t bg) +{ + tty->data[index(tty,x,y)]=c; + tty->data[index(tty,x,y)]|=fg<<8; + tty->data[index(tty,x,y)]|=bg<<16; + tty->screen->put_char(c,fg,bg,x,y); +} + +static void process_graphic_npar(terminal_tty *tty, terminal_settings s) +{ + switch(s) + { + case ecma48_fg_black: + tty->fg=SCR_BLACK; + break; + + case ecma48_fg_red: + tty->fg=SCR_RED; + break; + + case ecma48_fg_green: + tty->fg=SCR_GREEN; + break; + + case ecma48_fg_brown: + tty->fg=SCR_BROWN; + break; + + case ecma48_fg_blue: + tty->fg=SCR_BLUE; + break; + + case ecma48_fg_magenta: + tty->fg=SCR_MAGENTA; + break; + + case ecma48_fg_cyan: + tty->fg=SCR_CYAN; + break; + + case ecma48_fg_white: + tty->fg=SCR_WHITE; + break; + + + + case ecma48_bg_black: + tty->bg=SCR_BLACK; + break; + + case ecma48_bg_red: + tty->bg=SCR_RED; + break; + + case ecma48_bg_green: + tty->bg=SCR_GREEN; + break; + + case ecma48_bg_brown: + tty->bg=SCR_BROWN; + break; + + case ecma48_bg_blue: + tty->bg=SCR_BLUE; + break; + + case ecma48_bg_magenta: + tty->bg=SCR_MAGENTA; + break; + + case ecma48_bg_cyan: + tty->bg=SCR_CYAN; + break; + + case ecma48_bg_white: + tty->bg=SCR_WHITE; + break; + + + + + + + + case ecma48_bg_default: + tty->fg=SCR_BLACK; + break; + + } +} + + +static void process_graphic_npars(terminal_tty *tty) +{ + + char buf[4]; + int b=0; + + tty->escaping=0; + + for(int i=0;inpar+1;i++) + { + char c=tty->command[NPAR_START+i]; + buf[b++]=c; + + if(i==tty->npar||c==';') + { + if(b==2)process_graphic_npar(tty,buf[0]-'0'); + if(b==3)process_graphic_npar(tty,(buf[0]-'0')*10+(buf[1]-'0')); + b=0; + } + //terminal_put(tty,tty->command[NPAR_START+i]); + } + + tty->npar=0; + + + + +} + +static void reset(terminal_tty *tty) +{ + tty->bg=SCR_BLACK; + tty->fg=SCR_WHITE; + + for(int x=0;xwidth;x++) + for(int y=0;yheight;y++) + { + set_char(tty,x,y,' ',tty->fg,tty->bg); + } + + tty->x=0; + tty->y=0; + tty->command_l=0; +} + +terminal_tty terminal_init(term_out *screen,term_in *input) +{ + terminal_tty tty; + + tty.data=kballoc(2); + + tty.command=kballoc(1); + tty.command_l=0; + + tty.escaping=0; + + tty.screen=screen; + tty.input=input; + + tty.x=0; + tty.y=0; + + tty.width=VT52_WIDTH; + tty.height=VT52_HEIGHT; + + reset(&tty); + + return tty; +} + + + +void terminal_kb(terminal_tty *tty, uint8_t c) +{ + + terminal_put(tty,c); + tty->command[tty->command_l]=c; + (tty->command_l)++; + + if(c==0x08) + { + tty->command_l-=2; + if(tty->command_l<0)tty->command_l=0; + } + else if(c=='\n') + { + // write command to ringbuff + for(int i=0;icommand_l;i++) + tty->input->put_char(tty->command[i]); + + tty->command_l=0; + } + +} + +// send one ASCII character to the terminal +bool terminal_put(terminal_tty *tty, uint8_t c) +{ + + // CONTROL CHARACTERS + if(c==0x07){return;} // BEL + if(c==0x7F){return;} // nothing + + if(c==0x09){return;} // TAB TODO! + if(c==0x0E){return;} // G1 set + if(c==0x0F){return;} // G0 set + + if(c==0x18||c==0x1A){tty->escaping=0;return;} // cancel escaping + if(c==0x1B){tty->escaping=1;return;} // ESC + if(c==0x9B){tty->escaping=2;tty->npar=0;return;} // CSI = ESC [ + + if(c==0x08) //BACKSPACE + { + if(tty->x>0&&tty->command_l>0) + { + set_char(tty,tty->x-1,tty->y,' ',tty->fg,tty->bg); + tty->x--; + } + } + + else if(c==0x0D) // CR + { + tty->x=0; + return; + } + + else if(c==0x0A||c==0x0B||c==0x0C) // \n NEXTLINE + { + for(uint32_t x=tty->x;xwidth;x++) + { + set_char(tty,x,tty->y,' ',tty->fg,tty->bg); + } + tty->y++; + if(SET_LFNL)tty->x=0; + } + else // + { + // ESC- but not CSI-sequences + if(tty->escaping==1) + { + if(c=='c'){reset(tty);} // RESET + if(c=='D'){tty->y++;} // LINEFEED + if(c=='E'){tty->y++;tty->x=0;} //NEWLINE + if(c=='H'){} // SET TABSTOP: TODO + if(c=='M'){ // REVERSE LINEFEED + + if(tty->y==0) + { + for(int32_t y=tty->height-1;y>=0;y--) + { + for(uint32_t x=0;xwidth;x++) + { + uint32_t c=' '|tty->fg<<8|tty->bg<<16; + if(y!=0) c=tty->data[index(tty,x,y-1)]; + tty->data[index(tty,x,y)] = c; + + tty->screen->put_char(c&0xff,(c>>8)&0xff,c>>16,x,y); //TODO: get from buffer + } + } + } + else + tty->y--; + + } + + if(c=='Z'){// IDENTIFY: claim we are vt102 + + tty->input->put_char(0x1B); //ESC + tty->input->put_char('['); + tty->input->put_char('?'); + tty->input->put_char('6'); + tty->input->put_char('c'); + + return;} + + if(c=='7'){}// SAVE STATE + if(c=='8'){}// RESTORE STATE + if(c=='['){tty->escaping=2;tty->npar=0;return;} // CONTROL SEQ INTRODUCER + + + // TODO + // %, %@, %G, %8, #8, (, (B, (O, (U, (K + // ), >, =, ] (???) + // + // + + tty->escaping=0; // DONE + } + // CSI SEQEUENCES (AFTER ESC [..) + else if(tty->escaping==2) + { + //ECMA-48: TODO + //ECMA-48 GRAPHIC RENDITION: TODO + if(c!='m') + { + tty->command[NPAR_START+(tty->npar++)]=c; + } + else + { + process_graphic_npars(tty); + } + + //ECMA-48 MODE SWITCHES: TODO + //ECMA-48 STATUS REPORT: TODO + + //DEC PRIVATE MODE: TODO + //LINUX CONSOLE PRIVATE CSI: TODO + + } + else //PROBABLY (AND HOPEFULLY) JUST A NORMAL CHAR + { + set_char(tty,tty->x,tty->y,c,tty->fg,tty->bg); + tty->x++; + } + + } + + + + + + //autobreak + if(tty->x>=tty->width) + { + tty->x=0; + tty->y++; + } + + //autoscroll + if(tty->y>=tty->height) + { + tty->y--; + for(uint32_t y=0;yheight;y++) + { + for(uint32_t x=0;xwidth;x++) + { + uint32_t c=tty->data[index(tty,x,y+1)]; + if(y==tty->height-1)c=' '|tty->fg<<8|tty->bg<<16; + tty->data[index(tty,x,y)] = c; + tty->screen->put_char(c&0xff,(c>>8)&0xff,c>>16,x,y); //TODO: get from buffer + } + } + } + + //cusor pos + tty->screen->update_cursor(tty->x,tty->y); + return true; +} + +//deprecated +/* +bool vt52_put(terminal_tty *tty, uint8_t c) +{ + if(c==VT52_ESC_1){tty->escaping=1;return;} + if(c=='['){if(tty->escaping==1)escaping=2;return;} + + if(escaping==3){tty->x=c-32; escaping++;return;} //TODO: check for overflow? + if(escaping==4){tty->y=c-32; escaping=0;return;} + + // does this really need to be escaped with ESC [ not JUST ESC?? TODO; check? + if(escaping==2) // two last characters are escape seq: ^[ + { + if(c==VT52_JUMP)escaping++; + + else + { + switch('c') + { + case VT52_UP: + if(tty->y>0)tty->y--; + break; + + case VT52_DOWN: + if(tty->y+1height)tty->y++; + break; + + case VT52_LEFT: + if(tty->x+1width)tty->x++; + break; + + case VT52_RIGHT: + if(tty->x>0)tty->x--; + break; + + case VT52_HOME: + tty->x=tty->y=0; + break; + + case VT52_REV_FEED: + + break; + + case VT52_ERASE_SCR: + for(uint32_t y=tty->y+1;yheight;y++) + { + for(uint32_t x=0;xwidth;x++) + { + uint32_t c=tty->data[index(tty,x,y+1)]; + tty->data[index(tty,x,y)] = c; + tty->screen->put_char(c,0xf,x,y); + } + } + case VT52_ERASE_LINE: + + for(uint32_t x=tty->x;xwidth;x++) + { + uint32_t c=tty->data[index(tty,x,tty->y)]; + tty->data[index(tty,x,tty->y)] = c; + tty->screen->put_char(c,0xf,x,tty->y); + } + + break; + + } + + escaping=0; + } + + return; + + } + + if(c!='\n') + { + tty->data[index(tty,tty->x,tty->y)]=c; + tty->screen->put_char(c,0xf,tty->x,tty->y); + } + else + { + tty->y++; + tty->x=-1; + + } + + tty->x++; + + if(tty->x>=tty->width) + { + tty->x=0; + tty->y++; + + } + + //autoscroll + if(tty->y>=tty->height) + { + tty->y--; + for(uint32_t y=0;yheight;y++) + { + for(uint32_t x=0;xwidth;x++) + { + uint32_t c=tty->data[index(tty,x,y+1)]; + if(y==tty->height-1)c=' '; + tty->data[index(tty,x,y)] = c; + tty->screen->put_char(c,0xf,x,y); + } + } + } + + tty->screen->update_cursor(tty->x,tty->y); + return true; +} +*/ -- cgit v1.2.3