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))
+++ /dev/null
-# 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
+++ /dev/null
-/*
- * Acess GUI Terminal
- * - By John Hodge (thePowersGang)
- *
- * display.c
- * - Abstract display manipulation methods
- */
-#include "include/display.h"
-#include <acess/sys.h> // _SysDebug
-#include <stdlib.h> // exit
-#include <string.h>
-#include <unicode.h>
-#include <stdio.h>
-#include <axwin3/axwin.h>
-#include <axwin3/richtext.h>
-#include <stdbool.h>
-#include <assert.h>
-
-#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();
-}
-
+++ /dev/null
-/*
- * Acess GUI Terminal
- * - By John Hodge (thePowersGang)
- *
- * display.h
- * - RichText terminal translation
- */
-#ifndef _DISPLAY_H_
-#define _DISPLAY_H_
-
-#include <stdint.h>
-#include <stddef.h> // size_t
-#include <stdbool.h>
-
-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
-
+++ /dev/null
-/*
- * 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
-
+++ /dev/null
-/*
- * Acess GUI Terminal
- * - By John Hodge (thePowersGang)
- *
- * main.c
- * - Core
- */
-#include <axwin3/axwin.h>
-#include <axwin3/menu.h>
-#include <axwin3/richtext.h>
-#include <axwin3/keysyms.h>
-#include <stdio.h>
-#include <acess/sys.h>
-#include "include/display.h"
-#include "include/vt100.h"
-#include <string.h>
-#include <unicode.h>
-#include <errno.h>
-#include <acess/devices/pty.h>
-
-// === 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);
-}
-
+++ /dev/null
-/*
- * Acess GUI Terminal
- * - By John Hodge (thePowersGang)
- *
- * vt100.c
- * - VT100/xterm Emulation
- */
-#include <string.h>
-#include <limits.h>
-#include "include/vt100.h"
-#include "include/display.h"
-#include <ctype.h> // isalpha
-#include <acess/sys.h> // _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;
-}
--- /dev/null
+# 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
--- /dev/null
+/*
+ * Acess GUI Terminal
+ * - By John Hodge (thePowersGang)
+ *
+ * display.c
+ * - Abstract display manipulation methods
+ */
+#include "include/display.h"
+#include <acess/sys.h> // _SysDebug
+#include <stdlib.h> // exit
+#include <string.h>
+#include <unicode.h>
+#include <stdio.h>
+#include <axwin3/axwin.h>
+#include <axwin3/richtext.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#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();
+}
+
--- /dev/null
+/*
+ * Acess GUI Terminal
+ * - By John Hodge (thePowersGang)
+ *
+ * display.h
+ * - RichText terminal translation
+ */
+#ifndef _DISPLAY_H_
+#define _DISPLAY_H_
+
+#include <stdint.h>
+#include <stddef.h> // size_t
+#include <stdbool.h>
+
+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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * Acess GUI Terminal
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Core
+ */
+#include <axwin3/axwin.h>
+#include <axwin3/menu.h>
+#include <axwin3/richtext.h>
+#include <axwin3/keysyms.h>
+#include <stdio.h>
+#include <acess/sys.h>
+#include "include/display.h"
+#include "include/vt100.h"
+#include <string.h>
+#include <unicode.h>
+#include <errno.h>
+#include <acess/devices/pty.h>
+
+// === 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);
+}
+
--- /dev/null
+/*
+ * Acess GUI Terminal
+ * - By John Hodge (thePowersGang)
+ *
+ * vt100.c
+ * - VT100/xterm Emulation
+ */
+#include <string.h>
+#include <limits.h>
+#include "include/vt100.h"
+#include "include/display.h"
+#include <ctype.h> // isalpha
+#include <acess/sys.h> // _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;
+}