From: John Hodge Date: Sun, 8 Sep 2013 11:59:17 +0000 (+0800) Subject: Usermode/GUI Terminal - Renamed folder X-Git-Tag: rel0.15~246 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=3a6a04204acae8bc2ccfce7d0be1f1ba75744bb5;p=tpg%2Facess2.git Usermode/GUI Terminal - Renamed folder --- diff --git a/Makefile b/Makefile index 3940b3e2..f450dd76 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ EXTLIBS := USRAPPS := init login CLIShell cat ls mount automounter USRAPPS += bomb lspci USRAPPS += ip dhcpclient ping telnet irc wget telnetd -USRAPPS += axwin3 gui_ate gui_shell +USRAPPS += axwin3 gui_ate gui_terminal define targetclasses AI_$1 := $$(addprefix allinstall-,$$($1)) diff --git a/Usermode/Applications/gui_shell_src/Makefile b/Usermode/Applications/gui_shell_src/Makefile deleted file mode 100644 index a38f1355..00000000 --- a/Usermode/Applications/gui_shell_src/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Project: [GUI] Terminal - --include ../Makefile.cfg - -LDFLAGS += -laxwin3 -lunicode - -OBJ = main.o vt100.o display.o -BIN = terminal -DIR := Apps/AxWin/3.0 - --include ../Makefile.tpl diff --git a/Usermode/Applications/gui_shell_src/display.c b/Usermode/Applications/gui_shell_src/display.c deleted file mode 100644 index 00496088..00000000 --- a/Usermode/Applications/gui_shell_src/display.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Acess GUI Terminal - * - By John Hodge (thePowersGang) - * - * display.c - * - Abstract display manipulation methods - */ -#include "include/display.h" -#include // _SysDebug -#include // exit -#include -#include -#include -#include -#include -#include -#include - -#define UNIMPLIMENTED() do{_SysDebug("UNIMPLIMENTED %s", __func__); exit(-1);}while(0) - -// === EXTERN == -extern tHWND gMainWindow; - -typedef struct sLine tLine; - -struct sLine { - char *Data; - // TODO: Cache offsets to avoid scan-forward - size_t Len; - size_t Size; - bool IsDirty; -}; - -struct sTerminal { - int ViewCols; - int ViewRows; - - int CursorRow; - int CursorCol; - - size_t CursorByte; - - bool bUsingAltBuf; - - size_t ViewOffset; - size_t TotalLines; - struct sLine *PriBuf; - - struct sLine *AltBuf; -}; - -// === GLOBALS === -tTerminal gMainBuffer; - int giCurrentLine; - int giCurrentLinePos; // byte offset, not column - int giCurrentCol; - int giFirstDispLine; // First displayed line - int giFirstLine; // Ring buffer start -char **gasDisplayLines; - int *gaiDisplayLineSizes; -char *gabDisplayLinesDirty; - -// === CODE === -tTerminal *Display_Init(int Cols, int Lines, int ExtraScrollbackLines) -{ - tTerminal *term = &gMainBuffer; - term->ViewCols = Cols; - term->ViewRows = Lines; - term->TotalLines = Lines + ExtraScrollbackLines; - term->PriBuf = calloc( sizeof(tLine), (Lines + ExtraScrollbackLines) ); - - AxWin3_RichText_SetLineCount(gMainWindow, Lines+ExtraScrollbackLines); - AxWin3_RichText_SetCursorType(gMainWindow, 1); // TODO: enum - return term; -} - -// Return the byte length of a single on-screen character -size_t _GetCharLength(size_t AvailLength, const char *Text, uint32_t *BaseCodepoint) -{ - if( !AvailLength ) - return 0; - - size_t charlen = ReadUTF8(Text, BaseCodepoint); - - while(charlen < AvailLength) - { - uint32_t cp; - size_t size = ReadUTF8(Text+charlen, &cp); - if( Unicode_IsPrinting(cp) ) - break; - charlen += size; - } - - return charlen; -} - -tLine *Display_int_GetCurLine(tTerminal *Term) -{ - int lineidx = Term->CursorRow + (Term->bUsingAltBuf ? 0 : Term->ViewOffset); - return (Term->bUsingAltBuf ? Term->AltBuf : Term->PriBuf) + lineidx; -} - -size_t Display_int_PushCharacter(tTerminal *Term, size_t AvailLength, const char *Text) -{ - tLine *lineptr = Display_int_GetCurLine(Term); - uint32_t cp; - size_t charlen = _GetCharLength(AvailLength, Text, &cp); - bool bOverwrite = Unicode_IsPrinting(cp); - - _SysDebug("Line %b:%i += %i '%.*s'", Term->bUsingAltBuf, Term->CursorRow, charlen, charlen, Text); - - // Figure out how much we need to shift the stream - int shift; - if( bOverwrite ) { - size_t nextlen = _GetCharLength( - lineptr->Len-Term->CursorByte, - lineptr->Data+Term->CursorByte, - NULL); - _SysDebug("Char at +%i is %i long (%.*s)", Term->CursorByte, nextlen, - nextlen, lineptr->Data+Term->CursorByte); - shift = charlen - nextlen; - } - else { - shift = charlen; - } - _SysDebug("shift = %i", shift); - - // Ensure we have space enough - if( !lineptr->Data || shift > 0 ) { - const size_t size_step = 64; - assert(shift > 0); - lineptr->Size = (lineptr->Len+shift+1 + size_step-1) & ~(size_step-1); - void *tmp = realloc(lineptr->Data, lineptr->Size); - if( !tmp ) perror("Display_int_PushCharacter - realloc"); - lineptr->Data = tmp; - } - - // Insert into stream - char *base = lineptr->Data + Term->CursorByte; - if( Term->CursorByte == lineptr->Len ) { - // No shifting needed - } - else if( shift >= 0 ) { - size_t bytes = lineptr->Len - (Term->CursorByte+shift); - _SysDebug("memmove(base+%i, base, %i)", shift, bytes); - memmove(base+shift, base, bytes); - } - else { - shift = -shift; - size_t bytes = lineptr->Len - (Term->CursorByte+shift); - _SysDebug("memmove(base, base+%i, %i)", shift, bytes); - memmove(base, base+shift, bytes); - } - memcpy(base, Text, charlen); - lineptr->IsDirty = true; - lineptr->Len += shift; - lineptr->Data[lineptr->Len] = 0; // NULL Terminate - - Term->CursorByte += charlen; - - // HACKY: Prevents the CursorCol++ in Display_AddText from having an effect - if( !bOverwrite ) - Term->CursorCol --; - - return charlen; -} - -void Display_AddText(tTerminal *Term, size_t Length, const char *UTF8Text) -{ - _SysDebug("%i '%.*s'", Length, Length, UTF8Text); - while( Length > 0 ) - { - size_t used = Display_int_PushCharacter(Term, Length, UTF8Text); - - Length -= used; - UTF8Text += used; - - Term->CursorCol ++; - if( Term->CursorCol == Term->ViewCols ) { - Display_Newline(Term, 1); - } - } -} - -void Display_Newline(tTerminal *Term, bool bCarriageReturn) -{ -// Display_Flush(); - - // Going down! - Term->CursorRow ++; - if( Term->CursorRow == Term->TotalLines ) { - // TODO: Scrolling - } - - if( bCarriageReturn ) { - Term->CursorByte = 0; - Term->CursorCol = 0; - return ; - } - - tLine *line = Display_int_GetCurLine(Term); - - Term->CursorByte = 0; - int old_col = Term->CursorCol; - Term->CursorCol = 0; - - size_t ofs = 0; - while( Term->CursorCol < old_col && ofs < line->Len ) { - ofs += _GetCharLength(line->Len-ofs, line->Data+ofs, NULL); - Term->CursorCol ++; - } - Term->CursorByte = ofs; - - while( Term->CursorCol < old_col ) - Display_AddText(Term, 1, " "); -} - -void Display_SetCursor(tTerminal *Term, int Row, int Col) -{ - UNIMPLIMENTED(); -} - -void Display_MoveCursor(tTerminal *Term, int RelRow, int RelCol) -{ - if( RelRow != 0 ) - { - UNIMPLIMENTED(); - } - - if( RelCol != 0 ) - { - int req_col = Term->CursorCol + RelCol; - if( req_col < 0 ) req_col = 0; - if( req_col > Term->ViewCols ) req_col = Term->ViewCols; - - tLine *line = Display_int_GetCurLine(Term); - size_t ofs = 0; - for( int i = 0; i < req_col; i ++ ) - { - size_t clen = _GetCharLength(line->Len-ofs, line->Data+ofs, NULL); - if( clen == 0 ) { - req_col = i; - break; - } - ofs += clen; - } - - Term->CursorCol = req_col; - Term->CursorByte = ofs; - } -} - -void Display_ClearLine(tTerminal *Term, int Dir) // 0: All, 1: Forward, -1: Reverse -{ - if( Dir == 0 ) - { - tLine *line = Display_int_GetCurLine(Term); - // Completely clear line - if( line->Data ) - free(line->Data); - line->Data = NULL; - line->IsDirty = true; - } - else if( Dir == 1 ) - { - // Forward clear (truncate) - } - else if( Dir == -1 ) - { - // Reverse clear (replace with spaces) - } - else - { - // BUGCHECK - } -} - -void Display_ClearLines(tTerminal *Term, int Dir) // 0: All, 1: Forward, -1: Reverse -{ - if( Dir == 0 ) - { - // Push giDisplayLines worth of empty lines - // Move cursor back up by giDisplayLines - } - else if( Dir == 1 ) - { - // Push (giDisplayLines - (giCurrentLine-giFirstDispLine)) and reverse - } - else if( Dir == -1 ) - { - // Reverse clear (replace with spaces) - } - else - { - // BUGCHECK - } -} - -void Display_SetForeground(tTerminal *Term, uint32_t RGB) -{ - char buf[7+1]; - sprintf(buf, "\1%06x", RGB&0xFFFFFF); - Display_AddText(Term, 7, buf); -} - -void Display_SetBackground(tTerminal *Term, uint32_t RGB) -{ - char buf[7+1]; - sprintf(buf, "\2%06x", RGB&0xFFFFFF); - Display_AddText(Term, 7, buf); -} - -void Display_Flush(tTerminal *Term) -{ - for( int i = 0; i < Term->ViewRows; i ++ ) - { - int line = (Term->ViewOffset + i) % Term->TotalLines; - tLine *lineptr = &Term->PriBuf[line]; - if( !lineptr->IsDirty ) - continue; - _SysDebug("Line %i+%i '%.*s'", Term->ViewOffset, i, lineptr->Len, lineptr->Data); - AxWin3_RichText_SendLine(gMainWindow, Term->ViewOffset + i, lineptr->Data ); - lineptr->IsDirty = 0; - } - AxWin3_RichText_SetCursorPos(gMainWindow, Term->CursorRow, Term->CursorCol); -} - -void Display_ShowAltBuffer(tTerminal *Term, bool AltBufEnabled) -{ - UNIMPLIMENTED(); -} - diff --git a/Usermode/Applications/gui_shell_src/include/display.h b/Usermode/Applications/gui_shell_src/include/display.h deleted file mode 100644 index 26601fe1..00000000 --- a/Usermode/Applications/gui_shell_src/include/display.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Acess GUI Terminal - * - By John Hodge (thePowersGang) - * - * display.h - * - RichText terminal translation - */ -#ifndef _DISPLAY_H_ -#define _DISPLAY_H_ - -#include -#include // size_t -#include - -typedef struct sTerminal tTerminal; - -extern tTerminal *Display_Init(int Cols, int Lines, int ExtraScrollbackLines); - -extern void Display_AddText(tTerminal *Term, size_t Length, const char *UTF8Text); -extern void Display_Newline(tTerminal *Term, bool bCarriageReturn); -extern void Display_SetCursor(tTerminal *Term, int Row, int Col); -extern void Display_MoveCursor(tTerminal *Term, int RelRow, int RelCol); -extern void Display_ClearLine(tTerminal *Term, int Dir); // 0: All, 1: Forward, -1: Reverse -extern void Display_ClearLines(tTerminal *Term, int Dir); // 0: All, 1: Forward, -1: Reverse -extern void Display_SetForeground(tTerminal *Term, uint32_t RGB); -extern void Display_SetBackground(tTerminal *Term, uint32_t RGB); -/** - * \brief Ensure that recent updates are flushed to the server - * \note Called at the end of an "input" buffer - */ -extern void Display_Flush(tTerminal *Term); - -/** - * \brief Switch the display to the alternate buffer (no scrollback) - */ -extern void Display_ShowAltBuffer(tTerminal *Term, bool AltBufEnabled); - -#endif - diff --git a/Usermode/Applications/gui_shell_src/include/vt100.h b/Usermode/Applications/gui_shell_src/include/vt100.h deleted file mode 100644 index 162991b0..00000000 --- a/Usermode/Applications/gui_shell_src/include/vt100.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Acess GUI Terminal - * - By John Hodge (thePowersGang) - * - * vt100.h - * - VT100/xterm emulation - */ -#ifndef _VT100_H_ -#define _VT100_H_ - -#include "display.h" - -/** - * Returns either a positive or negative byte count. - * Positive means that many bytes were used as part of the escape sequence - * and should not be sent to the display. - * Negative means that there were that many bytes before the next escape - * sequence (and hence those should be displayed). - */ -extern int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf); - - -#endif - diff --git a/Usermode/Applications/gui_shell_src/main.c b/Usermode/Applications/gui_shell_src/main.c deleted file mode 100644 index 822f28b8..00000000 --- a/Usermode/Applications/gui_shell_src/main.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Acess GUI Terminal - * - By John Hodge (thePowersGang) - * - * main.c - * - Core - */ -#include -#include -#include -#include -#include -#include -#include "include/display.h" -#include "include/vt100.h" -#include -#include -#include -#include - -// === PROTOTYPES === - int main(int argc, char *argv[], const char **envp); - int Term_KeyHandler(tHWND Window, int bPress, uint32_t KeySym, uint32_t Translated); - int Term_MouseHandler(tHWND Window, int bPress, int Button, int Row, int Col); -void Term_HandleOutput(tTerminal *Term, int Len, const char *Buf); - -// === GLOBALS === -tHWND gMainWindow; -tHWND gMenuWindow; - int giPTYHandle; - -// === CODE === -int main(int argc, char *argv[], const char **envp) -{ - AxWin3_Connect(NULL); - - // --- Build up window - gMainWindow = AxWin3_RichText_CreateWindow(NULL, AXWIN3_RICHTEXT_READONLY); - AxWin3_SetWindowTitle(gMainWindow, "Terminal"); // TODO: Update title with other info - - gMenuWindow = AxWin3_Menu_Create(gMainWindow); - AxWin3_Menu_AddItem(gMenuWindow, "Copy\tWin+C", NULL, NULL, 0, NULL); - AxWin3_Menu_AddItem(gMenuWindow, "Paste\tWin+V", NULL, NULL, 0, NULL); - // TODO: Populate menu - - - // TODO: Tabs? - - AxWin3_RichText_SetKeyHandler (gMainWindow, Term_KeyHandler); - AxWin3_RichText_SetMouseHandler (gMainWindow, Term_MouseHandler); - AxWin3_RichText_SetDefaultColour(gMainWindow, 0xFFFFFF); - AxWin3_RichText_SetBackground (gMainWindow, 0x000000); - AxWin3_RichText_SetFont (gMainWindow, "#monospace", 10); - AxWin3_RichText_SetCursorPos (gMainWindow, 0, 0); - AxWin3_RichText_SetCursorType (gMainWindow, AXWIN3_RICHTEXT_CURSOR_INV); - AxWin3_RichText_SetCursorBlink (gMainWindow, 1); - - tTerminal *term = Display_Init(80, 25, 100); - AxWin3_ResizeWindow(gMainWindow, 80*8, 25*16); - AxWin3_MoveWindow(gMainWindow, 20, 50); - AxWin3_ShowWindow(gMainWindow, 1); - AxWin3_FocusWindow(gMainWindow); - - // Create PTY - giPTYHandle = _SysOpen("/Devices/pts/ptmx", OPENFLAG_READ|OPENFLAG_WRITE); - if( giPTYHandle < 0 ) { - perror("Unable to create/open PTY"); - _SysDebug("Unable to create/open PTY: %s", strerror(errno)); - return -1; - } - // - Initialise - { - _SysIOCtl(giPTYHandle, PTY_IOCTL_SETID, "gui0"); - struct ptymode mode = {.InputMode = PTYIMODE_CANON|PTYIMODE_ECHO, .OutputMode=0}; - struct ptydims dims = {.W = 80, .H = 25}; - _SysIOCtl(giPTYHandle, PTY_IOCTL_SETMODE, &mode); - _SysIOCtl(giPTYHandle, PTY_IOCTL_SETDIMS, &dims); - } - - // Spawn shell - { - int fd = _SysOpen("/Devices/pts/gui0", OPENFLAG_READ|OPENFLAG_WRITE); - int fds[] = {fd, fd, fd}; - const char *argv[] = {"CLIShell", NULL}; - int pid = _SysSpawn("/Acess/Bin/CLIShell", argv, envp, 3, fds, NULL); - if( pid < 0 ) - _SysDebug("ERROR: Shell spawn failed: %s", strerror(errno)); - _SysIOCtl(fd, PTY_IOCTL_SETPGRP, &pid); - _SysClose(fd); - } - - // Main loop - for( ;; ) - { - fd_set fds; - - FD_ZERO(&fds); - FD_SET(giPTYHandle, &fds); - AxWin3_MessageSelect(giPTYHandle + 1, &fds); - - if( FD_ISSET(giPTYHandle, &fds) ) - { - _SysDebug("Activity on child stdout"); - // Read and update screen - char buf[128]; - int len = _SysRead(giPTYHandle, buf, sizeof(buf)); - if( len <= 0 ) break; - - Term_HandleOutput(term, len, buf); - } - } - - return 0; -} - -int Term_KeyHandler(tHWND Window, int bPress, uint32_t KeySym, uint32_t Translated) -{ - static int ctrl_state = 0; - - // Handle modifiers - #define _bitset(var,bit,set) do{if(set)var|=1<<(bit);else var&=~(1<<(bit));}while(0) - switch(KeySym) - { - case KEYSYM_LEFTCTRL: - _bitset(ctrl_state, 0, bPress!=0); - return 0; - case KEYSYM_RIGHTCTRL: - _bitset(ctrl_state, 1, bPress!=0); - return 0; - } - #undef _bitset - - // Handle shortcuts - // - Ctrl-A -- Ctrl-Z - if( ctrl_state && KeySym >= KEYSYM_a && KeySym <= KEYSYM_z ) - { - Translated = KeySym - KEYSYM_a + 1; - _SysDebug("Ctrl-%c: KS %x => Trans %x", 'A'+(KeySym-KEYSYM_a), KeySym, Translated); - } - - // == 2 :: FIRE - if( bPress == 2 ) - { - if( Translated ) - { - char buf[6]; - int len; - - // Encode and send - len = WriteUTF8(buf, Translated); - - _SysDebug("Keystroke %x:%x translated to '%.*s'", KeySym, Translated, len, buf); - _SysWrite(giPTYHandle, buf, len); - - return 0; - } - - // No translation, look for escape sequences to send - const char *str = NULL; - switch(KeySym) - { - case KEYSYM_LEFTARROW: - str = "\x1b[D"; - break; - case KEYSYM_RIGHTARROW: - str = "\x1b[C"; - break; - case KEYSYM_UPARROW: - str = "\x1b[A"; - break; - case KEYSYM_DOWNARROW: - str = "\x1b[B"; - break; - } - if( str ) - { - _SysWrite(giPTYHandle, str, strlen(str)); - } - } - return 0; -} - -int Term_MouseHandler(tHWND Window, int bPress, int Button, int Row, int Col) -{ - return 0; -} - -void Term_HandleOutput(tTerminal *Term, int Len, const char *Buf) -{ - // TODO: Handle graphical / accelerated modes - - int ofs = 0; - int esc_len = 0; - - while( ofs < Len ) - { - esc_len = Term_HandleVT100(Term, Len - ofs, Buf + ofs); - if( esc_len < 0 ) { - Display_AddText(Term, -esc_len, Buf + ofs); - esc_len = -esc_len; - } - ofs += esc_len; - //_SysDebug("Len = %i, ofs = %i", Len, ofs); - } - - Display_Flush(Term); -} - diff --git a/Usermode/Applications/gui_shell_src/vt100.c b/Usermode/Applications/gui_shell_src/vt100.c deleted file mode 100644 index cad41194..00000000 --- a/Usermode/Applications/gui_shell_src/vt100.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Acess GUI Terminal - * - By John Hodge (thePowersGang) - * - * vt100.c - * - VT100/xterm Emulation - */ -#include -#include -#include "include/vt100.h" -#include "include/display.h" -#include // isalpha -#include // _SysDebug - -const uint32_t caVT100Colours[] = { - // Black, Red, Green, Yellow, Blue, Purple, Cyan, Gray - // Same again, but bright - 0x000000, 0x770000, 0x007700, 0x777700, 0x000077, 0x770077, 0x007777, 0xAAAAAAA, - 0xCCCCCC, 0xFF0000, 0x00FF00, 0xFFFF00, 0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFFF -}; - - int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buf); - -static inline int min(int a, int b) -{ - return a < b ? a : b; -} - -int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf) -{ - #define MAX_VT100_ESCAPE_LEN 16 - static char inc_buf[MAX_VT100_ESCAPE_LEN]; - static int inc_len = 0; - - if( inc_len > 0 || *Buf == '\x1b' ) - { - // Handle VT100 (like) escape sequence - int new_bytes = min(MAX_VT100_ESCAPE_LEN - inc_len, Len); - int ret = 0, old_inc_len = inc_len; - memcpy(inc_buf + inc_len, Buf, new_bytes); - - inc_len += new_bytes; - - if( inc_len <= 1 ) - return 1; // Skip 1 character (the '\x1b') - - switch(inc_buf[1]) - { - case '[': // Multibyte, funtime starts - ret = Term_HandleVT100_Long(Term, inc_len-2, inc_buf+2); - if( ret > 0 ) { - ret += 2; - } - break; - default: - ret = 2; - break; - } - - if( ret != 0 ) { - inc_len = 0; - ret -= old_inc_len; // counter cached bytes - } - return ret; - } - - switch( *Buf ) - { - case '\b': - Display_MoveCursor(Term, -1, 0); - Display_AddText(Term, 1, " "); - Display_MoveCursor(Term, -1, 0); - // TODO: Need to handle \t and ^A-Z - return 1; - case '\t': - // TODO: tab (get current cursor pos, space until multiple of 8) - return 1; - case '\n': - Display_Newline(Term, 1); - return 1; - case '\r': - Display_MoveCursor(Term, INT_MIN, 0); - return 1; - } - - int ret = 0; - while( ret < Len ) - { - switch(*Buf) - { - case '\x1b': - case '\b': - case '\t': - case '\n': - case '\r': - // Force an exit right now - Len = ret; - break; - default: - ret ++; - Buf ++; - break; - } - } - return -ret; -} - -int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) -{ - char c; - int argc = 0, j = 0; - int args[6] = {0,0,0,0,0,0}; - int bQuestionMark = 0; - - // Get Arguments - if(j == Len) return 0; - c = Buffer[j++]; - if(c == '?') { - bQuestionMark = 1; - if(j == Len) return 0; - c = Buffer[j++]; - } - if( '0' <= c && c <= '9' ) - { - do { - if(c == ';') { - if(j == Len) return 0; - c = Buffer[j++]; - } - while('0' <= c && c <= '9') { - args[argc] *= 10; - args[argc] += c-'0'; - if(j == Len) return 0; - c = Buffer[j++]; - } - argc ++; - } while(c == ';'); - } - - // Get Command - if( !isalpha(c) ) { - // Bother. - _SysDebug("Unexpected char 0x%x in VT100 escape code", c); - return 1; - } - - if( bQuestionMark ) - { - int set = 0; - // Special commands - switch( c ) - { - case 'h': // set - set = 1; - case 'l': // unset - switch(args[0]) - { - case 25: // Hide cursor - _SysDebug("TODO: \\e[?25%c Show/Hide cursor", c); - break; - case 1047: // Alternate buffer - Display_ShowAltBuffer(Term, set); - break; - default: - _SysDebug("TODO: \\e[?%i%c Unknow DEC private mode", args[0], c); - break; - } - break; - default: - _SysDebug("Unknown VT100 extended escape char 0x%x", c); - break; - } - } - else - { - // Standard commands - switch( c ) - { - case 'H': - if( argc != 2 ) { - } - else { - Display_SetCursor(Term, args[0], args[1]); - } - break; - case 'J': - if( argc == 0 ) - Display_ClearLine(Term, 0); - else if( args[0] == 2 ) - Display_ClearLines(Term, 0); // Entire screen! - else - _SysDebug("TODO: VT100 %i J", args[0]); - break; - case 'T': // Scroll down n=1 - _SysDebug("TODO: \\x1B[nT - Scroll down"); - break; - case 'm': - if( argc == 0 ) - { - // Reset - } - else - { - int i; - for( i = 0; i < argc; i ++ ) - { - if( args[i] < 8 ) - { - // TODO: Flags? - } - else if( 30 <= args[i] && args[i] <= 37 ) - { - // TODO: Bold/bright - Display_SetForeground( Term, caVT100Colours[ args[i]-30 ] ); - } - else if( 40 <= args[i] && args[i] <= 47 ) - { - // TODO: Bold/bright - Display_SetBackground( Term, caVT100Colours[ args[i]-30 ] ); - } - } - } - break; - // Set scrolling region - case 'r': - _SysDebug("TODO: \\x1B[%i;%ir - Set Scroll Region", - args[0], args[1]); - break; - default: - _SysDebug("Unknown VT100 long escape char 0x%x '%c'", c, c); - break; - } - } - return j; -} diff --git a/Usermode/Applications/gui_terminal_src/Makefile b/Usermode/Applications/gui_terminal_src/Makefile new file mode 100644 index 00000000..a38f1355 --- /dev/null +++ b/Usermode/Applications/gui_terminal_src/Makefile @@ -0,0 +1,11 @@ +# Project: [GUI] Terminal + +-include ../Makefile.cfg + +LDFLAGS += -laxwin3 -lunicode + +OBJ = main.o vt100.o display.o +BIN = terminal +DIR := Apps/AxWin/3.0 + +-include ../Makefile.tpl diff --git a/Usermode/Applications/gui_terminal_src/display.c b/Usermode/Applications/gui_terminal_src/display.c new file mode 100644 index 00000000..00496088 --- /dev/null +++ b/Usermode/Applications/gui_terminal_src/display.c @@ -0,0 +1,332 @@ +/* + * Acess GUI Terminal + * - By John Hodge (thePowersGang) + * + * display.c + * - Abstract display manipulation methods + */ +#include "include/display.h" +#include // _SysDebug +#include // exit +#include +#include +#include +#include +#include +#include +#include + +#define UNIMPLIMENTED() do{_SysDebug("UNIMPLIMENTED %s", __func__); exit(-1);}while(0) + +// === EXTERN == +extern tHWND gMainWindow; + +typedef struct sLine tLine; + +struct sLine { + char *Data; + // TODO: Cache offsets to avoid scan-forward + size_t Len; + size_t Size; + bool IsDirty; +}; + +struct sTerminal { + int ViewCols; + int ViewRows; + + int CursorRow; + int CursorCol; + + size_t CursorByte; + + bool bUsingAltBuf; + + size_t ViewOffset; + size_t TotalLines; + struct sLine *PriBuf; + + struct sLine *AltBuf; +}; + +// === GLOBALS === +tTerminal gMainBuffer; + int giCurrentLine; + int giCurrentLinePos; // byte offset, not column + int giCurrentCol; + int giFirstDispLine; // First displayed line + int giFirstLine; // Ring buffer start +char **gasDisplayLines; + int *gaiDisplayLineSizes; +char *gabDisplayLinesDirty; + +// === CODE === +tTerminal *Display_Init(int Cols, int Lines, int ExtraScrollbackLines) +{ + tTerminal *term = &gMainBuffer; + term->ViewCols = Cols; + term->ViewRows = Lines; + term->TotalLines = Lines + ExtraScrollbackLines; + term->PriBuf = calloc( sizeof(tLine), (Lines + ExtraScrollbackLines) ); + + AxWin3_RichText_SetLineCount(gMainWindow, Lines+ExtraScrollbackLines); + AxWin3_RichText_SetCursorType(gMainWindow, 1); // TODO: enum + return term; +} + +// Return the byte length of a single on-screen character +size_t _GetCharLength(size_t AvailLength, const char *Text, uint32_t *BaseCodepoint) +{ + if( !AvailLength ) + return 0; + + size_t charlen = ReadUTF8(Text, BaseCodepoint); + + while(charlen < AvailLength) + { + uint32_t cp; + size_t size = ReadUTF8(Text+charlen, &cp); + if( Unicode_IsPrinting(cp) ) + break; + charlen += size; + } + + return charlen; +} + +tLine *Display_int_GetCurLine(tTerminal *Term) +{ + int lineidx = Term->CursorRow + (Term->bUsingAltBuf ? 0 : Term->ViewOffset); + return (Term->bUsingAltBuf ? Term->AltBuf : Term->PriBuf) + lineidx; +} + +size_t Display_int_PushCharacter(tTerminal *Term, size_t AvailLength, const char *Text) +{ + tLine *lineptr = Display_int_GetCurLine(Term); + uint32_t cp; + size_t charlen = _GetCharLength(AvailLength, Text, &cp); + bool bOverwrite = Unicode_IsPrinting(cp); + + _SysDebug("Line %b:%i += %i '%.*s'", Term->bUsingAltBuf, Term->CursorRow, charlen, charlen, Text); + + // Figure out how much we need to shift the stream + int shift; + if( bOverwrite ) { + size_t nextlen = _GetCharLength( + lineptr->Len-Term->CursorByte, + lineptr->Data+Term->CursorByte, + NULL); + _SysDebug("Char at +%i is %i long (%.*s)", Term->CursorByte, nextlen, + nextlen, lineptr->Data+Term->CursorByte); + shift = charlen - nextlen; + } + else { + shift = charlen; + } + _SysDebug("shift = %i", shift); + + // Ensure we have space enough + if( !lineptr->Data || shift > 0 ) { + const size_t size_step = 64; + assert(shift > 0); + lineptr->Size = (lineptr->Len+shift+1 + size_step-1) & ~(size_step-1); + void *tmp = realloc(lineptr->Data, lineptr->Size); + if( !tmp ) perror("Display_int_PushCharacter - realloc"); + lineptr->Data = tmp; + } + + // Insert into stream + char *base = lineptr->Data + Term->CursorByte; + if( Term->CursorByte == lineptr->Len ) { + // No shifting needed + } + else if( shift >= 0 ) { + size_t bytes = lineptr->Len - (Term->CursorByte+shift); + _SysDebug("memmove(base+%i, base, %i)", shift, bytes); + memmove(base+shift, base, bytes); + } + else { + shift = -shift; + size_t bytes = lineptr->Len - (Term->CursorByte+shift); + _SysDebug("memmove(base, base+%i, %i)", shift, bytes); + memmove(base, base+shift, bytes); + } + memcpy(base, Text, charlen); + lineptr->IsDirty = true; + lineptr->Len += shift; + lineptr->Data[lineptr->Len] = 0; // NULL Terminate + + Term->CursorByte += charlen; + + // HACKY: Prevents the CursorCol++ in Display_AddText from having an effect + if( !bOverwrite ) + Term->CursorCol --; + + return charlen; +} + +void Display_AddText(tTerminal *Term, size_t Length, const char *UTF8Text) +{ + _SysDebug("%i '%.*s'", Length, Length, UTF8Text); + while( Length > 0 ) + { + size_t used = Display_int_PushCharacter(Term, Length, UTF8Text); + + Length -= used; + UTF8Text += used; + + Term->CursorCol ++; + if( Term->CursorCol == Term->ViewCols ) { + Display_Newline(Term, 1); + } + } +} + +void Display_Newline(tTerminal *Term, bool bCarriageReturn) +{ +// Display_Flush(); + + // Going down! + Term->CursorRow ++; + if( Term->CursorRow == Term->TotalLines ) { + // TODO: Scrolling + } + + if( bCarriageReturn ) { + Term->CursorByte = 0; + Term->CursorCol = 0; + return ; + } + + tLine *line = Display_int_GetCurLine(Term); + + Term->CursorByte = 0; + int old_col = Term->CursorCol; + Term->CursorCol = 0; + + size_t ofs = 0; + while( Term->CursorCol < old_col && ofs < line->Len ) { + ofs += _GetCharLength(line->Len-ofs, line->Data+ofs, NULL); + Term->CursorCol ++; + } + Term->CursorByte = ofs; + + while( Term->CursorCol < old_col ) + Display_AddText(Term, 1, " "); +} + +void Display_SetCursor(tTerminal *Term, int Row, int Col) +{ + UNIMPLIMENTED(); +} + +void Display_MoveCursor(tTerminal *Term, int RelRow, int RelCol) +{ + if( RelRow != 0 ) + { + UNIMPLIMENTED(); + } + + if( RelCol != 0 ) + { + int req_col = Term->CursorCol + RelCol; + if( req_col < 0 ) req_col = 0; + if( req_col > Term->ViewCols ) req_col = Term->ViewCols; + + tLine *line = Display_int_GetCurLine(Term); + size_t ofs = 0; + for( int i = 0; i < req_col; i ++ ) + { + size_t clen = _GetCharLength(line->Len-ofs, line->Data+ofs, NULL); + if( clen == 0 ) { + req_col = i; + break; + } + ofs += clen; + } + + Term->CursorCol = req_col; + Term->CursorByte = ofs; + } +} + +void Display_ClearLine(tTerminal *Term, int Dir) // 0: All, 1: Forward, -1: Reverse +{ + if( Dir == 0 ) + { + tLine *line = Display_int_GetCurLine(Term); + // Completely clear line + if( line->Data ) + free(line->Data); + line->Data = NULL; + line->IsDirty = true; + } + else if( Dir == 1 ) + { + // Forward clear (truncate) + } + else if( Dir == -1 ) + { + // Reverse clear (replace with spaces) + } + else + { + // BUGCHECK + } +} + +void Display_ClearLines(tTerminal *Term, int Dir) // 0: All, 1: Forward, -1: Reverse +{ + if( Dir == 0 ) + { + // Push giDisplayLines worth of empty lines + // Move cursor back up by giDisplayLines + } + else if( Dir == 1 ) + { + // Push (giDisplayLines - (giCurrentLine-giFirstDispLine)) and reverse + } + else if( Dir == -1 ) + { + // Reverse clear (replace with spaces) + } + else + { + // BUGCHECK + } +} + +void Display_SetForeground(tTerminal *Term, uint32_t RGB) +{ + char buf[7+1]; + sprintf(buf, "\1%06x", RGB&0xFFFFFF); + Display_AddText(Term, 7, buf); +} + +void Display_SetBackground(tTerminal *Term, uint32_t RGB) +{ + char buf[7+1]; + sprintf(buf, "\2%06x", RGB&0xFFFFFF); + Display_AddText(Term, 7, buf); +} + +void Display_Flush(tTerminal *Term) +{ + for( int i = 0; i < Term->ViewRows; i ++ ) + { + int line = (Term->ViewOffset + i) % Term->TotalLines; + tLine *lineptr = &Term->PriBuf[line]; + if( !lineptr->IsDirty ) + continue; + _SysDebug("Line %i+%i '%.*s'", Term->ViewOffset, i, lineptr->Len, lineptr->Data); + AxWin3_RichText_SendLine(gMainWindow, Term->ViewOffset + i, lineptr->Data ); + lineptr->IsDirty = 0; + } + AxWin3_RichText_SetCursorPos(gMainWindow, Term->CursorRow, Term->CursorCol); +} + +void Display_ShowAltBuffer(tTerminal *Term, bool AltBufEnabled) +{ + UNIMPLIMENTED(); +} + diff --git a/Usermode/Applications/gui_terminal_src/include/display.h b/Usermode/Applications/gui_terminal_src/include/display.h new file mode 100644 index 00000000..26601fe1 --- /dev/null +++ b/Usermode/Applications/gui_terminal_src/include/display.h @@ -0,0 +1,39 @@ +/* + * Acess GUI Terminal + * - By John Hodge (thePowersGang) + * + * display.h + * - RichText terminal translation + */ +#ifndef _DISPLAY_H_ +#define _DISPLAY_H_ + +#include +#include // size_t +#include + +typedef struct sTerminal tTerminal; + +extern tTerminal *Display_Init(int Cols, int Lines, int ExtraScrollbackLines); + +extern void Display_AddText(tTerminal *Term, size_t Length, const char *UTF8Text); +extern void Display_Newline(tTerminal *Term, bool bCarriageReturn); +extern void Display_SetCursor(tTerminal *Term, int Row, int Col); +extern void Display_MoveCursor(tTerminal *Term, int RelRow, int RelCol); +extern void Display_ClearLine(tTerminal *Term, int Dir); // 0: All, 1: Forward, -1: Reverse +extern void Display_ClearLines(tTerminal *Term, int Dir); // 0: All, 1: Forward, -1: Reverse +extern void Display_SetForeground(tTerminal *Term, uint32_t RGB); +extern void Display_SetBackground(tTerminal *Term, uint32_t RGB); +/** + * \brief Ensure that recent updates are flushed to the server + * \note Called at the end of an "input" buffer + */ +extern void Display_Flush(tTerminal *Term); + +/** + * \brief Switch the display to the alternate buffer (no scrollback) + */ +extern void Display_ShowAltBuffer(tTerminal *Term, bool AltBufEnabled); + +#endif + diff --git a/Usermode/Applications/gui_terminal_src/include/vt100.h b/Usermode/Applications/gui_terminal_src/include/vt100.h new file mode 100644 index 00000000..162991b0 --- /dev/null +++ b/Usermode/Applications/gui_terminal_src/include/vt100.h @@ -0,0 +1,24 @@ +/* + * Acess GUI Terminal + * - By John Hodge (thePowersGang) + * + * vt100.h + * - VT100/xterm emulation + */ +#ifndef _VT100_H_ +#define _VT100_H_ + +#include "display.h" + +/** + * Returns either a positive or negative byte count. + * Positive means that many bytes were used as part of the escape sequence + * and should not be sent to the display. + * Negative means that there were that many bytes before the next escape + * sequence (and hence those should be displayed). + */ +extern int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf); + + +#endif + diff --git a/Usermode/Applications/gui_terminal_src/main.c b/Usermode/Applications/gui_terminal_src/main.c new file mode 100644 index 00000000..822f28b8 --- /dev/null +++ b/Usermode/Applications/gui_terminal_src/main.c @@ -0,0 +1,208 @@ +/* + * Acess GUI Terminal + * - By John Hodge (thePowersGang) + * + * main.c + * - Core + */ +#include +#include +#include +#include +#include +#include +#include "include/display.h" +#include "include/vt100.h" +#include +#include +#include +#include + +// === PROTOTYPES === + int main(int argc, char *argv[], const char **envp); + int Term_KeyHandler(tHWND Window, int bPress, uint32_t KeySym, uint32_t Translated); + int Term_MouseHandler(tHWND Window, int bPress, int Button, int Row, int Col); +void Term_HandleOutput(tTerminal *Term, int Len, const char *Buf); + +// === GLOBALS === +tHWND gMainWindow; +tHWND gMenuWindow; + int giPTYHandle; + +// === CODE === +int main(int argc, char *argv[], const char **envp) +{ + AxWin3_Connect(NULL); + + // --- Build up window + gMainWindow = AxWin3_RichText_CreateWindow(NULL, AXWIN3_RICHTEXT_READONLY); + AxWin3_SetWindowTitle(gMainWindow, "Terminal"); // TODO: Update title with other info + + gMenuWindow = AxWin3_Menu_Create(gMainWindow); + AxWin3_Menu_AddItem(gMenuWindow, "Copy\tWin+C", NULL, NULL, 0, NULL); + AxWin3_Menu_AddItem(gMenuWindow, "Paste\tWin+V", NULL, NULL, 0, NULL); + // TODO: Populate menu + + + // TODO: Tabs? + + AxWin3_RichText_SetKeyHandler (gMainWindow, Term_KeyHandler); + AxWin3_RichText_SetMouseHandler (gMainWindow, Term_MouseHandler); + AxWin3_RichText_SetDefaultColour(gMainWindow, 0xFFFFFF); + AxWin3_RichText_SetBackground (gMainWindow, 0x000000); + AxWin3_RichText_SetFont (gMainWindow, "#monospace", 10); + AxWin3_RichText_SetCursorPos (gMainWindow, 0, 0); + AxWin3_RichText_SetCursorType (gMainWindow, AXWIN3_RICHTEXT_CURSOR_INV); + AxWin3_RichText_SetCursorBlink (gMainWindow, 1); + + tTerminal *term = Display_Init(80, 25, 100); + AxWin3_ResizeWindow(gMainWindow, 80*8, 25*16); + AxWin3_MoveWindow(gMainWindow, 20, 50); + AxWin3_ShowWindow(gMainWindow, 1); + AxWin3_FocusWindow(gMainWindow); + + // Create PTY + giPTYHandle = _SysOpen("/Devices/pts/ptmx", OPENFLAG_READ|OPENFLAG_WRITE); + if( giPTYHandle < 0 ) { + perror("Unable to create/open PTY"); + _SysDebug("Unable to create/open PTY: %s", strerror(errno)); + return -1; + } + // - Initialise + { + _SysIOCtl(giPTYHandle, PTY_IOCTL_SETID, "gui0"); + struct ptymode mode = {.InputMode = PTYIMODE_CANON|PTYIMODE_ECHO, .OutputMode=0}; + struct ptydims dims = {.W = 80, .H = 25}; + _SysIOCtl(giPTYHandle, PTY_IOCTL_SETMODE, &mode); + _SysIOCtl(giPTYHandle, PTY_IOCTL_SETDIMS, &dims); + } + + // Spawn shell + { + int fd = _SysOpen("/Devices/pts/gui0", OPENFLAG_READ|OPENFLAG_WRITE); + int fds[] = {fd, fd, fd}; + const char *argv[] = {"CLIShell", NULL}; + int pid = _SysSpawn("/Acess/Bin/CLIShell", argv, envp, 3, fds, NULL); + if( pid < 0 ) + _SysDebug("ERROR: Shell spawn failed: %s", strerror(errno)); + _SysIOCtl(fd, PTY_IOCTL_SETPGRP, &pid); + _SysClose(fd); + } + + // Main loop + for( ;; ) + { + fd_set fds; + + FD_ZERO(&fds); + FD_SET(giPTYHandle, &fds); + AxWin3_MessageSelect(giPTYHandle + 1, &fds); + + if( FD_ISSET(giPTYHandle, &fds) ) + { + _SysDebug("Activity on child stdout"); + // Read and update screen + char buf[128]; + int len = _SysRead(giPTYHandle, buf, sizeof(buf)); + if( len <= 0 ) break; + + Term_HandleOutput(term, len, buf); + } + } + + return 0; +} + +int Term_KeyHandler(tHWND Window, int bPress, uint32_t KeySym, uint32_t Translated) +{ + static int ctrl_state = 0; + + // Handle modifiers + #define _bitset(var,bit,set) do{if(set)var|=1<<(bit);else var&=~(1<<(bit));}while(0) + switch(KeySym) + { + case KEYSYM_LEFTCTRL: + _bitset(ctrl_state, 0, bPress!=0); + return 0; + case KEYSYM_RIGHTCTRL: + _bitset(ctrl_state, 1, bPress!=0); + return 0; + } + #undef _bitset + + // Handle shortcuts + // - Ctrl-A -- Ctrl-Z + if( ctrl_state && KeySym >= KEYSYM_a && KeySym <= KEYSYM_z ) + { + Translated = KeySym - KEYSYM_a + 1; + _SysDebug("Ctrl-%c: KS %x => Trans %x", 'A'+(KeySym-KEYSYM_a), KeySym, Translated); + } + + // == 2 :: FIRE + if( bPress == 2 ) + { + if( Translated ) + { + char buf[6]; + int len; + + // Encode and send + len = WriteUTF8(buf, Translated); + + _SysDebug("Keystroke %x:%x translated to '%.*s'", KeySym, Translated, len, buf); + _SysWrite(giPTYHandle, buf, len); + + return 0; + } + + // No translation, look for escape sequences to send + const char *str = NULL; + switch(KeySym) + { + case KEYSYM_LEFTARROW: + str = "\x1b[D"; + break; + case KEYSYM_RIGHTARROW: + str = "\x1b[C"; + break; + case KEYSYM_UPARROW: + str = "\x1b[A"; + break; + case KEYSYM_DOWNARROW: + str = "\x1b[B"; + break; + } + if( str ) + { + _SysWrite(giPTYHandle, str, strlen(str)); + } + } + return 0; +} + +int Term_MouseHandler(tHWND Window, int bPress, int Button, int Row, int Col) +{ + return 0; +} + +void Term_HandleOutput(tTerminal *Term, int Len, const char *Buf) +{ + // TODO: Handle graphical / accelerated modes + + int ofs = 0; + int esc_len = 0; + + while( ofs < Len ) + { + esc_len = Term_HandleVT100(Term, Len - ofs, Buf + ofs); + if( esc_len < 0 ) { + Display_AddText(Term, -esc_len, Buf + ofs); + esc_len = -esc_len; + } + ofs += esc_len; + //_SysDebug("Len = %i, ofs = %i", Len, ofs); + } + + Display_Flush(Term); +} + diff --git a/Usermode/Applications/gui_terminal_src/vt100.c b/Usermode/Applications/gui_terminal_src/vt100.c new file mode 100644 index 00000000..cad41194 --- /dev/null +++ b/Usermode/Applications/gui_terminal_src/vt100.c @@ -0,0 +1,235 @@ +/* + * Acess GUI Terminal + * - By John Hodge (thePowersGang) + * + * vt100.c + * - VT100/xterm Emulation + */ +#include +#include +#include "include/vt100.h" +#include "include/display.h" +#include // isalpha +#include // _SysDebug + +const uint32_t caVT100Colours[] = { + // Black, Red, Green, Yellow, Blue, Purple, Cyan, Gray + // Same again, but bright + 0x000000, 0x770000, 0x007700, 0x777700, 0x000077, 0x770077, 0x007777, 0xAAAAAAA, + 0xCCCCCC, 0xFF0000, 0x00FF00, 0xFFFF00, 0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFFF +}; + + int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buf); + +static inline int min(int a, int b) +{ + return a < b ? a : b; +} + +int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf) +{ + #define MAX_VT100_ESCAPE_LEN 16 + static char inc_buf[MAX_VT100_ESCAPE_LEN]; + static int inc_len = 0; + + if( inc_len > 0 || *Buf == '\x1b' ) + { + // Handle VT100 (like) escape sequence + int new_bytes = min(MAX_VT100_ESCAPE_LEN - inc_len, Len); + int ret = 0, old_inc_len = inc_len; + memcpy(inc_buf + inc_len, Buf, new_bytes); + + inc_len += new_bytes; + + if( inc_len <= 1 ) + return 1; // Skip 1 character (the '\x1b') + + switch(inc_buf[1]) + { + case '[': // Multibyte, funtime starts + ret = Term_HandleVT100_Long(Term, inc_len-2, inc_buf+2); + if( ret > 0 ) { + ret += 2; + } + break; + default: + ret = 2; + break; + } + + if( ret != 0 ) { + inc_len = 0; + ret -= old_inc_len; // counter cached bytes + } + return ret; + } + + switch( *Buf ) + { + case '\b': + Display_MoveCursor(Term, -1, 0); + Display_AddText(Term, 1, " "); + Display_MoveCursor(Term, -1, 0); + // TODO: Need to handle \t and ^A-Z + return 1; + case '\t': + // TODO: tab (get current cursor pos, space until multiple of 8) + return 1; + case '\n': + Display_Newline(Term, 1); + return 1; + case '\r': + Display_MoveCursor(Term, INT_MIN, 0); + return 1; + } + + int ret = 0; + while( ret < Len ) + { + switch(*Buf) + { + case '\x1b': + case '\b': + case '\t': + case '\n': + case '\r': + // Force an exit right now + Len = ret; + break; + default: + ret ++; + Buf ++; + break; + } + } + return -ret; +} + +int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) +{ + char c; + int argc = 0, j = 0; + int args[6] = {0,0,0,0,0,0}; + int bQuestionMark = 0; + + // Get Arguments + if(j == Len) return 0; + c = Buffer[j++]; + if(c == '?') { + bQuestionMark = 1; + if(j == Len) return 0; + c = Buffer[j++]; + } + if( '0' <= c && c <= '9' ) + { + do { + if(c == ';') { + if(j == Len) return 0; + c = Buffer[j++]; + } + while('0' <= c && c <= '9') { + args[argc] *= 10; + args[argc] += c-'0'; + if(j == Len) return 0; + c = Buffer[j++]; + } + argc ++; + } while(c == ';'); + } + + // Get Command + if( !isalpha(c) ) { + // Bother. + _SysDebug("Unexpected char 0x%x in VT100 escape code", c); + return 1; + } + + if( bQuestionMark ) + { + int set = 0; + // Special commands + switch( c ) + { + case 'h': // set + set = 1; + case 'l': // unset + switch(args[0]) + { + case 25: // Hide cursor + _SysDebug("TODO: \\e[?25%c Show/Hide cursor", c); + break; + case 1047: // Alternate buffer + Display_ShowAltBuffer(Term, set); + break; + default: + _SysDebug("TODO: \\e[?%i%c Unknow DEC private mode", args[0], c); + break; + } + break; + default: + _SysDebug("Unknown VT100 extended escape char 0x%x", c); + break; + } + } + else + { + // Standard commands + switch( c ) + { + case 'H': + if( argc != 2 ) { + } + else { + Display_SetCursor(Term, args[0], args[1]); + } + break; + case 'J': + if( argc == 0 ) + Display_ClearLine(Term, 0); + else if( args[0] == 2 ) + Display_ClearLines(Term, 0); // Entire screen! + else + _SysDebug("TODO: VT100 %i J", args[0]); + break; + case 'T': // Scroll down n=1 + _SysDebug("TODO: \\x1B[nT - Scroll down"); + break; + case 'm': + if( argc == 0 ) + { + // Reset + } + else + { + int i; + for( i = 0; i < argc; i ++ ) + { + if( args[i] < 8 ) + { + // TODO: Flags? + } + else if( 30 <= args[i] && args[i] <= 37 ) + { + // TODO: Bold/bright + Display_SetForeground( Term, caVT100Colours[ args[i]-30 ] ); + } + else if( 40 <= args[i] && args[i] <= 47 ) + { + // TODO: Bold/bright + Display_SetBackground( Term, caVT100Colours[ args[i]-30 ] ); + } + } + } + break; + // Set scrolling region + case 'r': + _SysDebug("TODO: \\x1B[%i;%ir - Set Scroll Region", + args[0], args[1]); + break; + default: + _SysDebug("Unknown VT100 long escape char 0x%x '%c'", c, c); + break; + } + } + return j; +}