diff --git a/sortix/Makefile b/sortix/Makefile
index a324485f..22dfb61e 100644
--- a/sortix/Makefile
+++ b/sortix/Makefile
@@ -110,8 +110,10 @@ uart.o \
terminal.o \
linebuffer.o \
logterminal.o \
-vgaterminal.o \
+textterminal.o \
serialterminal.o \
+textbuffer.o \
+vgatextbuffer.o \
descriptors.o \
device.o \
refcount.o \
diff --git a/sortix/include/sortix/kernel/textbuffer.h b/sortix/include/sortix/kernel/textbuffer.h
new file mode 100644
index 00000000..884cc909
--- /dev/null
+++ b/sortix/include/sortix/kernel/textbuffer.h
@@ -0,0 +1,99 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ textbuffer.h
+ Provides a indexable text buffer for used by text mode terminals.
+
+*******************************************************************************/
+
+#ifndef SORTIX_TEXTBUFFER_H
+#define SORTIX_TEXTBUFFER_H
+
+#include
+#include
+
+namespace Sortix {
+
+struct TextPos
+{
+ TextPos() { }
+ TextPos(size_t x, size_t y) : x(x), y(y) { }
+ size_t x;
+ size_t y;
+};
+
+struct TextChar
+{
+ TextChar() { }
+ TextChar(char c, uint8_t vgacolor) : c(c), vgacolor(vgacolor) { }
+ char c;
+ uint8_t vgacolor; // Format of
+};
+
+class TextBuffer
+{
+public:
+ virtual ~TextBuffer() { }
+ virtual size_t Width() const = 0;
+ virtual size_t Height() const = 0;
+ virtual TextChar GetChar(TextPos pos) const = 0;
+ virtual void SetChar(TextPos pos, TextChar c) = 0;
+ virtual uint16_t GetCharAttr(TextPos pos) const = 0;
+ virtual void SetCharAttr(TextPos pos, uint16_t attr) = 0;
+ virtual void Scroll(ssize_t off, TextChar fillwith) = 0;
+ virtual void Move(TextPos to, TextPos from, size_t numchars) = 0;
+ virtual void Fill(TextPos from, TextPos to, TextChar fillwith,
+ uint16_t fillattr) = 0;
+ virtual bool GetCursorEnabled() const = 0;
+ virtual void SetCursorEnabled(bool enablecursor) = 0;
+ virtual TextPos GetCursorPos() const = 0;
+ virtual void SetCursorPos(TextPos cursorpos) = 0;
+
+};
+
+// The purpose of this handle class is such that the terminal driver can have
+// its backing storage replaced at runtime, for instance if the user changes
+// the screen resolution or the graphics driver. The backing text buffer can
+// only be changed when there are no references (but our own) to the text buffer
+// so don't forget to release it when you are done.
+class TextBufferHandle : public Refcounted
+{
+public:
+ TextBufferHandle(TextBuffer* textbuf = NULL, bool deletebuf = true,
+ TextBuffer* def = NULL, bool deletedef = true);
+ ~TextBufferHandle();
+ TextBuffer* Acquire();
+ void Release(TextBuffer* textbuf);
+ void Replace(TextBuffer* newtextbuf, bool deletebuf = true);
+
+private:
+ kthread_mutex_t mutex;
+ kthread_cond_t unusedcond;
+ TextBuffer* textbuf;
+ TextBuffer* def;
+ size_t numused;
+ bool deletedef;
+ bool deletebuf;
+
+
+};
+
+} // namespace Sortix
+
+#endif
diff --git a/sortix/kernel.cpp b/sortix/kernel.cpp
index 9d7b33e0..835cb669 100644
--- a/sortix/kernel.cpp
+++ b/sortix/kernel.cpp
@@ -24,6 +24,9 @@
*******************************************************************************/
#include
+#include
+#include
+#include
#include
#include
#include
@@ -42,9 +45,10 @@
#include "pci.h"
#include "com.h"
#include "uart.h"
+#include "vgatextbuffer.h"
#include "terminal.h"
#include "serialterminal.h"
-#include "vgaterminal.h"
+#include "textterminal.h"
#include "elf.h"
#include "initrd.h"
#include "vga.h"
@@ -90,6 +94,11 @@ void DoWelcome()
Log::Print(" BOOTING OPERATING SYSTEM... ");
}
+static size_t PrintToTextTerminal(void* user, const char* str, size_t len)
+{
+ return ((TextTerminal*) user)->Print(str, len);
+}
+
extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
{
// Initialize system calls.
@@ -98,13 +107,19 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
// Detect and initialize any serial COM ports in the system.
COM::EarlyInit();
- // Initialize the default terminal.
- VGATerminal::Init();
- Maxsi::Format::Callback logcallback = VGATerminal::Print;
- void* logpointer = NULL;
+ // Setup a text buffer handle for use by the text terminal.
+ uint16_t* const VGAFB = (uint16_t*) 0xB8000;
+ const size_t VGA_WIDTH = 80;
+ const size_t VGA_HEIGHT = 25;
+ static uint16_t vga_attr_buffer[VGA_WIDTH*VGA_HEIGHT];
+ VGATextBuffer textbuf(VGAFB, vga_attr_buffer, VGA_WIDTH, VGA_HEIGHT);
+ TextBufferHandle textbufhandle(NULL, false, &textbuf, false);
- // Initialize the kernel log.
- Log::Init(logcallback, logpointer);
+ // Setup a text terminal instance.
+ TextTerminal textterm(&textbufhandle);
+
+ // Register the text terminal as the kernel log and initialize it.
+ Log::Init(PrintToTextTerminal, &textterm);
// Display the boot welcome screen.
DoWelcome();
diff --git a/sortix/serialterminal.cpp b/sortix/serialterminal.cpp
index d7471444..9047f986 100644
--- a/sortix/serialterminal.cpp
+++ b/sortix/serialterminal.cpp
@@ -29,7 +29,6 @@
#include "keyboard.h"
#include "uart.h"
#include "serialterminal.h"
-#include "vgaterminal.h"
#include "scheduler.h"
using namespace Maxsi;
@@ -144,7 +143,10 @@ namespace Sortix
size_t Print(void* /*user*/, const char* string, size_t stringlen)
{
+ #warning Echoing to the VGA terminal is broken
+#if 0
if ( ECHO_TO_VGA ) { VGATerminal::Print(NULL, string, stringlen); }
+#endif
if ( cursordisabled )
{
const char* msg = "\e[h";
diff --git a/sortix/textbuffer.cpp b/sortix/textbuffer.cpp
new file mode 100644
index 00000000..8dfff4db
--- /dev/null
+++ b/sortix/textbuffer.cpp
@@ -0,0 +1,83 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ textbuffer.cpp
+ Provides a indexable text buffer for used by text mode terminals.
+
+*******************************************************************************/
+
+#include
+#include
+#include
+#include
+
+namespace Sortix {
+
+TextBufferHandle::TextBufferHandle(TextBuffer* textbuf, bool deletebuf,
+ TextBuffer* def, bool deletedef)
+{
+ this->textbuf = textbuf;
+ this->deletebuf = deletebuf;
+ this->def = def;
+ this->deletedef = deletedef;
+ this->numused = 0;
+ this->mutex = KTHREAD_MUTEX_INITIALIZER;
+ this->unusedcond = KTHREAD_COND_INITIALIZER;
+}
+
+TextBufferHandle::~TextBufferHandle()
+{
+ if ( deletebuf )
+ delete textbuf;
+ if ( deletedef )
+ delete def;
+}
+
+TextBuffer* TextBufferHandle::Acquire()
+{
+ ScopedLock lock(&mutex);
+ numused++;
+ if ( textbuf )
+ return textbuf;
+ if ( !def )
+ numused--;
+ return def;
+}
+
+void TextBufferHandle::Release(TextBuffer* textbuf)
+{
+ ASSERT(textbuf);
+ ScopedLock lock(&mutex);
+ ASSERT(numused);
+ if ( !--numused )
+ kthread_cond_signal(&unusedcond);
+}
+
+void TextBufferHandle::Replace(TextBuffer* newtextbuf, bool deletebuf)
+{
+ ScopedLock lock(&mutex);
+ while ( numused )
+ kthread_cond_wait(&unusedcond, &mutex);
+ if ( deletebuf )
+ delete textbuf;
+ this->textbuf = newtextbuf;
+ this->deletebuf = deletebuf;
+}
+
+} // namespace Sortix
diff --git a/sortix/textterminal.cpp b/sortix/textterminal.cpp
new file mode 100644
index 00000000..00a70140
--- /dev/null
+++ b/sortix/textterminal.cpp
@@ -0,0 +1,417 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ textterminal.cpp
+ Translates a character stream to a 2 dimensional array of character.
+
+*******************************************************************************/
+
+#include
+#include
+#include
+#include
+#include "textterminal.h"
+
+namespace Sortix {
+
+const uint16_t DEFAULT_COLOR = COLOR8_LIGHT_GREY << 0U | COLOR8_BLACK << 4U;
+const uint16_t ATTR_CHAR = 1U << 0U;
+
+TextTerminal::TextTerminal(TextBufferHandle* textbufhandle)
+{
+ this->textbufhandle = textbufhandle; textbufhandle->Refer();
+ Reset();
+}
+
+void TextTerminal::Reset()
+{
+ vgacolor = DEFAULT_COLOR;
+ column = line = 0;
+ ansisavedposx = ansisavedposy = 0;
+ ansimode = NONE;
+ TextBuffer* textbuf = textbufhandle->Acquire();
+ TextPos fillfrom(0, 0);
+ TextPos fillto(textbuf->Width()-1, textbuf->Height()-1);
+ TextChar fillwith(' ', vgacolor);
+ textbuf->Fill(fillfrom, fillto, fillwith, 0);
+ textbuf->SetCursorEnabled(true);
+ UpdateCursor(textbuf);
+ textbufhandle->Release(textbuf);
+}
+
+size_t TextTerminal::Print(const char* string, size_t stringlen)
+{
+ TextBuffer* textbuf = textbufhandle->Acquire();
+ for ( size_t i = 0; i < stringlen; i++ )
+ PutChar(textbuf, string[i]);
+ UpdateCursor(textbuf);
+ textbufhandle->Release(textbuf);
+ return stringlen;
+}
+
+void TextTerminal::PutChar(TextBuffer* textbuf, char c)
+{
+ if ( ansimode )
+ PutAnsiEscaped(textbuf, c);
+ else switch ( c )
+ {
+ case '\n': Newline(textbuf); break;
+ case '\r': column = 0; break;
+ case '\b': Backspace(textbuf); break;
+ case '\t': Tab(textbuf); break;
+ case '\e': AnsiReset(); break;
+ default:
+ {
+ if ( textbuf->Width() <= column )
+ Newline(textbuf);
+ TextPos pos(column++, line);
+ TextChar tc(c, vgacolor);
+ textbuf->SetChar(pos, tc);
+ textbuf->SetCharAttr(pos, ATTR_CHAR);
+ } break;
+ }
+}
+
+void TextTerminal::UpdateCursor(TextBuffer* textbuf)
+{
+ textbuf->SetCursorPos(TextPos(column, line));
+}
+
+void TextTerminal::Newline(TextBuffer* textbuf)
+{
+ textbuf->SetCharAttr(TextPos(column, line), ATTR_CHAR);
+ column = 0;
+ if ( line < textbuf->Height()-1 )
+ line++;
+ else
+ textbuf->Scroll(1, TextChar(' ', vgacolor)),
+ line = textbuf->Height()-1;
+}
+
+static TextPos DecrementTextPos(TextBuffer* textbuf, TextPos pos)
+{
+ if ( !pos.x && !pos.y )
+ return pos;
+ if ( !pos.x )
+ return TextPos(textbuf->Width(), pos.y-1);
+ return TextPos(pos.x-1, pos.y);
+}
+
+void TextTerminal::Backspace(TextBuffer* textbuf)
+{
+ TextPos pos(column, line);
+ while ( pos.x || pos.y )
+ {
+ pos = DecrementTextPos(textbuf, pos);
+ uint16_t attr = textbuf->GetCharAttr(pos);
+ textbuf->SetChar(pos, TextChar(' ', vgacolor));
+ textbuf->SetCharAttr(pos, attr & ~ATTR_CHAR);
+ if ( attr & ATTR_CHAR )
+ break;
+ }
+ column = pos.x;
+ line = pos.y;
+}
+
+void TextTerminal::Tab(TextBuffer* textbuf)
+{
+ if ( column == textbuf->Width() )
+ Newline(textbuf);
+ // TODO: This does not work correctly if the text buffer width is not a
+ // multiple of four and the column is near the edge.
+ unsigned until = 4 - (column % 4);
+ textbuf->SetCharAttr(TextPos(column, line), ATTR_CHAR);
+ while ( (until--) != 0 )
+ textbuf->SetChar(TextPos(column++, line), TextChar(' ', vgacolor));
+}
+
+// TODO: This implementation of the 'Ansi Escape Codes' is incomplete and hacky.
+void TextTerminal::AnsiReset()
+{
+ ansiusedparams = 0;
+ currentparamindex = 0;
+ ansiparams[0] = 0;
+ paramundefined = true;
+ ignoresequence = false;
+ ansimode = CSI;
+}
+
+void TextTerminal::PutAnsiEscaped(TextBuffer* textbuf, char c)
+{
+ // Check the proper prefixes are used.
+ if ( ansimode == CSI )
+ {
+ if ( c != '[' ) { ansimode = NONE; return; }
+ ansimode = COMMAND;
+ return;
+ }
+
+ // Read part of a parameter.
+ if ( '0' <= c && c <= '9' )
+ {
+ if ( paramundefined )
+ ansiusedparams++;
+ paramundefined = false;
+ unsigned val = c - '0';
+ ansiparams[currentparamindex] *= 10;
+ ansiparams[currentparamindex] += val;
+ }
+
+ // Parameter delimiter.
+ else if ( c == ';' )
+ {
+ if ( currentparamindex == ANSI_NUM_PARAMS - 1 )
+ {
+ ansimode = NONE;
+ return;
+ }
+ paramundefined = true;
+ ansiparams[++currentparamindex] = 0;
+ }
+
+ // Left for future standardization, so discard this sequence.
+ else if ( c == ':' )
+ {
+ ignoresequence = true;
+ }
+
+ // Run a command.
+ else if ( 64 <= c && c <= 126 )
+ {
+ if ( !ignoresequence )
+ RunAnsiCommand(textbuf, c);
+ }
+
+ // Something I don't understand, and ignore intentionally.
+ else if ( c == '?' )
+ {
+ }
+
+ // TODO: There are some rare things that should be supported here.
+
+ // Ignore unknown input.
+ else
+ {
+ ansimode = NONE;
+ }
+}
+
+void TextTerminal::RunAnsiCommand(TextBuffer* textbuf, char c)
+{
+ const unsigned width = (unsigned) textbuf->Width();
+ const unsigned height = (unsigned) textbuf->Height();
+
+ switch ( c )
+ {
+ case 'A': // Cursor up
+ {
+ unsigned dist = 0 < ansiusedparams ? ansiparams[0] : 1;
+ if ( line < dist )
+ line = 0;
+ else
+ line -= dist;
+ } break;
+ case 'B': // Cursor down
+ {
+ unsigned dist = 0 < ansiusedparams ? ansiparams[0] : 1;
+ if ( height <= line + dist )
+ line = height-1;
+ else
+ line += dist;
+ } break;
+ case 'C': // Cursor forward
+ {
+ unsigned dist = 0 < ansiusedparams ? ansiparams[0] : 1;
+ if ( width <= column + dist )
+ column = width-1;
+ else
+ column += dist;
+ } break;
+ case 'D': // Cursor backward
+ {
+ unsigned dist = 0 < ansiusedparams ? ansiparams[0] : 1;
+ if ( column < dist )
+ column = 0;
+ else
+ column -= dist;
+ } break;
+ case 'E': // Move to beginning of line N lines down.
+ {
+ column = 0;
+ unsigned dist = 0 < ansiusedparams ? ansiparams[0] : 1;
+ if ( height <= line + dist )
+ line = height-1;
+ else
+ line += dist;
+ } break;
+ case 'F': // Move to beginning of line N lines up.
+ {
+ column = 0;
+ unsigned dist = 0 < ansiusedparams ? ansiparams[0] : 1;
+ if ( line < dist )
+ line = 0;
+ else
+ line -= dist;
+ } break;
+ case 'G': // Move the cursor to column N.
+ {
+ unsigned pos = 0 < ansiusedparams ? ansiparams[0]-1 : 0;
+ if ( width <= pos )
+ pos = width-1;
+ column = pos;
+ } break;
+ case 'H': // Move the cursor to line Y, column X.
+ case 'f':
+ {
+ unsigned posy = 0 < ansiusedparams ? ansiparams[0]-1 : 0;
+ unsigned posx = 1 < ansiusedparams ? ansiparams[1]-1 : 0;
+ if ( width <= posx )
+ posx = width-1;
+ if ( height <= posy )
+ posy = height-1;
+ column = posx;
+ line = posy;
+ } break;
+ case 'J': // Erase parts of the screen.
+ {
+ unsigned mode = 0 < ansiusedparams ? ansiparams[0] : 0;
+ TextPos from(0, 0);
+ TextPos to(0, 0);
+
+ if ( mode == 0 ) // From cursor to end.
+ from = TextPos{column, line},
+ to = TextPos{width-1, height-1};
+
+ if ( mode == 1 ) // From start to cursor.
+ from = TextPos{0, 0},
+ to = TextPos{column, line};
+
+ if ( mode == 2 ) // Everything.
+ from = TextPos{0, 0},
+ to = TextPos{width-1, height-1};
+
+ textbuf->Fill(from, to, TextChar(' ', vgacolor), 0);
+ } break;
+ case 'K': // Erase parts of the current line.
+ {
+ unsigned mode = 0 < ansiusedparams ? ansiparams[0] : 0;
+ TextPos from(0, 0);
+ TextPos to(0, 0);
+
+ if ( mode == 0 ) // From cursor to end.
+ from = TextPos{column, line},
+ to = TextPos{width-1, line};
+
+ if ( mode == 1 ) // From start to cursor.
+ from = TextPos{0, line},
+ to = TextPos{column, line};
+
+ if ( mode == 2 ) // Everything.
+ from = TextPos{0, line},
+ to = TextPos{width-1, line};
+
+ textbuf->Fill(from, to, TextChar(' ', vgacolor), 0);
+ } break;
+ case 'S': // Scroll a line up and place a new line at the buttom.
+ {
+ textbuf->Scroll(1, TextChar(' ', vgacolor));
+ line = height-1;
+ } break;
+ case 'T': // Scroll a line up and place a new line at the top.
+ {
+ textbuf->Scroll(-1, TextChar(' ', vgacolor));
+ line = 0;
+ } break;
+ case 'm': // Change how the text is rendered.
+ {
+ if ( ansiusedparams == 0 )
+ {
+ ansiparams[0] = 0;
+ ansiusedparams++;
+ }
+
+ // Convert from the ANSI color scheme to the VGA color scheme.
+ const unsigned conversion[8] =
+ {
+ COLOR8_BLACK, COLOR8_RED, COLOR8_GREEN, COLOR8_BROWN,
+ COLOR8_BLUE, COLOR8_MAGENTA, COLOR8_CYAN, COLOR8_LIGHT_GREY,
+ };
+
+ for ( size_t i = 0; i < ansiusedparams; i++ )
+ {
+ unsigned cmd = ansiparams[i];
+ // Turn all attributes off.
+ if ( cmd == 0 )
+ {
+ vgacolor = DEFAULT_COLOR;
+ }
+ // Set text color.
+ else if ( 30 <= cmd && cmd <= 37 )
+ {
+ unsigned val = cmd - 30;
+ vgacolor &= 0xF0;
+ vgacolor |= conversion[val] << 0;
+ }
+ // Set background color.
+ else if ( 40 <= cmd && cmd <= 47 )
+ {
+ unsigned val = cmd - 40;
+ vgacolor &= 0x0F;
+ vgacolor |= conversion[val] << 4;
+ }
+ // TODO: There are many other things we don't support.
+ }
+ } break;
+ case 'n': // Request special information from terminal.
+ {
+ // TODO: Handle this code.
+ } break;
+ case 's': // Save cursor position.
+ {
+ ansisavedposx = column;
+ ansisavedposx = line;
+ } break;
+ case 'u': // Restore cursor position.
+ {
+ column = ansisavedposx;
+ line = ansisavedposx;
+ if ( width <= column )
+ column = width-1;
+ if ( height <= line )
+ line = height-1;
+ } break;
+ case 'l': // Hide cursor.
+ {
+ // TODO: This is somehow related to the special char '?'.
+ if ( 0 < ansiusedparams && ansiparams[0] == 25 )
+ textbuf->SetCursorEnabled(false);
+ } break;
+ case 'h': // Show cursor.
+ {
+ // TODO: This is somehow related to the special char '?'.
+ if ( 0 < ansiusedparams && ansiparams[0] == 25 )
+ textbuf->SetCursorEnabled(true);
+ } break;
+ // TODO: Handle other cases.
+ }
+
+ ansimode = NONE;
+}
+
+} // namespace Sortix
diff --git a/sortix/textterminal.h b/sortix/textterminal.h
new file mode 100644
index 00000000..ad23125e
--- /dev/null
+++ b/sortix/textterminal.h
@@ -0,0 +1,69 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ textterminal.cpp
+ An indexable text buffer with the VGA text mode framebuffer as backend.
+
+*******************************************************************************/
+
+#ifndef SORTIX_TEXTTERMINAL_H
+#define SORTIX_TEXTTERMINAL_H
+
+namespace Sortix {
+
+class TextBufferHandle;
+
+class TextTerminal //: public Printable ?
+{
+public:
+ TextTerminal(TextBufferHandle* textbufhandle);
+ ~TextTerminal();
+ size_t Print(const char* string, size_t stringlen);
+
+private:
+ void PutChar(TextBuffer* textbuf, char c);
+ void UpdateCursor(TextBuffer* textbuf);
+ void Newline(TextBuffer* textbuf);
+ void Backspace(TextBuffer* textbuf);
+ void Tab(TextBuffer* textbuf);
+ void PutAnsiEscaped(TextBuffer* textbuf, char c);
+ void RunAnsiCommand(TextBuffer* textbuf, char c);
+ void AnsiReset();
+ void Reset();
+
+private:
+ TextBufferHandle* textbufhandle;
+ uint8_t vgacolor;
+ unsigned column;
+ unsigned line;
+ unsigned ansisavedposx;
+ unsigned ansisavedposy;
+ enum { NONE = 0, CSI, COMMAND, } ansimode;
+ static const size_t ANSI_NUM_PARAMS = 16;
+ unsigned ansiusedparams;
+ unsigned ansiparams[ANSI_NUM_PARAMS];
+ unsigned currentparamindex;
+ bool paramundefined;
+ bool ignoresequence;
+
+};
+
+} // namespace Sortix
+
+#endif
diff --git a/sortix/vgaterminal.cpp b/sortix/vgaterminal.cpp
deleted file mode 100644
index 4aa04cfa..00000000
--- a/sortix/vgaterminal.cpp
+++ /dev/null
@@ -1,547 +0,0 @@
-/*******************************************************************************
-
- Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
-
- This file is part of Sortix.
-
- Sortix is free software: you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option) any later
- version.
-
- Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- Sortix. If not, see .
-
- vgaterminal.cpp
- A terminal based on a text mode buffer.
-
-*******************************************************************************/
-
-#include
-#include
-#include
-#include
-#include "vga.h"
-#include "vgaterminal.h"
-
-using namespace Maxsi;
-
-namespace Sortix {
-namespace VGATerminal {
-
-const unsigned width = 80;
-const unsigned height = 25;
-const uint16_t DEFAULT_COLOR = (COLOR8_LIGHT_GREY << 8) | (COLOR8_BLACK << 12);
-uint16_t* const vga = (uint16_t* const) 0xB8000;
-uint16_t vgaattr[width * height];
-const uint16_t VGAATTR_CHAR = (1U<<0U);
-unsigned line;
-unsigned column;
-uint16_t currentcolor;
-unsigned ansisavedposx;
-unsigned ansisavedposy;
-bool showcursor;
-
-enum
-{
- NONE,
- CSI,
- COMMAND,
-} ansimode;
-
-void UpdateCursor()
-{
- if ( showcursor )
- VGA::SetCursor(column, line);
- else
- VGA::SetCursor(width, height-1);
-}
-
-// Clear the screen, put the cursor at the top left corner, set default
-// text color, and reset ANSI escape sequence state.
-void Reset()
-{
- ansimode = NONE;
-
- line = 0;
- column = 0;
- ansisavedposx = 0;
- ansisavedposy = 0;
-
- currentcolor = DEFAULT_COLOR;
-
- for ( nat y = 0; y < height; y++ )
- {
- for ( nat x = 0; x < width; x++ )
- {
- unsigned index = y * width + x;
- vga[index] = ' ' | DEFAULT_COLOR;
- vgaattr[index] = 0;
- }
- }
-
- // Reset the VGA cursor.
- showcursor = true;
- UpdateCursor();
-}
-
-// Initialize the terminal driver.
-void Init()
-{
- Reset();
-}
-
-// Move every line one row up and leaves an empty line at the bottom.
-void ScrollUp()
-{
- for ( nat y = 1; y < height; y++ )
- {
- size_t linesize = width * sizeof(uint16_t);
- size_t fromoff = (y-0) * width;
- size_t destoff = (y-1) * width;
- Memory::Copy(vga + destoff, vga + fromoff, linesize);
- Memory::Copy(vgaattr + destoff, vgaattr + fromoff, linesize);
- }
-
- for ( nat x = 0; x < width; x++ )
- {
- unsigned index = (height-1) * width + x;
- vga[index] = ' ' | currentcolor;
- vgaattr[index] = 0;
- }
-}
-
-// Move every line one row down and leaves an empty line at the top.
-void ScrollDown()
-{
- for ( nat y = 1; y < height; y++ )
- {
- size_t linesize = width * sizeof(uint16_t);
- size_t fromoff = (y-1) * width;
- size_t destoff = (y-0) * width;
- Memory::Copy(vga + destoff, vga + fromoff, linesize);
- Memory::Copy(vgaattr + destoff, vgaattr + fromoff, linesize);
- }
-
- for ( nat x = 0; x < width; x++ )
- {
- unsigned index = x;
- vga[index] = ' ' | currentcolor;
- vgaattr[index] = 0;
- }
-}
-
-// Move to the next line. If at bottom, scroll one line up.
-void Newline()
-{
- vgaattr[line * width + column] |= VGAATTR_CHAR;
- if ( line < height - 1 )
- line++;
- else
- ScrollUp();
- column = 0;
- UpdateCursor();
-}
-
-void ANSIReset();
-void ParseANSIEscape(char c);
-
-// Print text to the vga framebuffer, simulating how a terminal would
-// display the text.
-size_t Print(void* /*user*/, const char* string, size_t stringlen)
-{
- // Iterate over each character.
- size_t left = stringlen;
- while ( (left--) > 0 )
- {
- char c = *(string++);
-
- // If we are parsing an escape sequence, parse another char.
- if ( ansimode != NONE ) { ParseANSIEscape(c); continue; }
-
- switch ( c )
- {
- // Move cursor to the next line and scroll up (if needed).
- case '\n':
- {
- Newline();
- break;
- }
- // Move cursor to start of line.
- case '\r':
- {
- column = 0;
- break;
- }
- // Delete the previous character.
- case '\b':
- {
- unsigned pos = line * width + column;
- while ( pos )
- {
- unsigned nextpos = pos-1;
- vga[nextpos] = ' ' | currentcolor;
- pos = nextpos;
- uint16_t attr = vgaattr[pos];
- vgaattr[pos] = 0;
- if ( attr & VGAATTR_CHAR ) { break; }
- }
- column = pos % width;
- line = pos / width;
- break;
- }
- // Expand a tab to a few spaces.
- case '\t':
- {
- if ( column == width ) { Newline(); }
- nat until = 4 - (column % 4);
-
- vgaattr[line * width + (column)] |= VGAATTR_CHAR;
- while ( (until--) != 0 )
- {
- vga[line * width + (column++)] = ' ' | currentcolor;
- }
- break;
- }
- // Initialize an ANSI escape sequence, allowing much more
- // powerful control of the terminal than ASCII does.
- case '\e':
- {
- ANSIReset();
- break;
- }
- // Print this character at the cursor and increment the cursor.
- default:
- {
- if ( column == width ) { Newline(); }
- unsigned index = line * width + (column++);
- vga[index] = c | currentcolor;
- vgaattr[index] |= VGAATTR_CHAR;
- break;
- }
- }
- }
-
- // Update the VGA hardware cursor.
- UpdateCursor();
-
- return stringlen;
-}
-
-const size_t ANSI_NUM_PARAMS = 16;
-nat ansiusedparams;
-nat ansiparams[ANSI_NUM_PARAMS];
-nat currentparamindex;
-bool paramundefined;
-bool ignoresequence;
-
-// TODO: The ANSI escape code is only partially implemented!
-
-// Begin an ANSI esacpe sequence.
-void ANSIReset()
-{
- if ( ansimode == NONE )
- {
- ansiusedparams = 0;
- currentparamindex = 0;
- ansiparams[0] = 0;
- paramundefined = true;
- ignoresequence = false;
- ansimode = CSI;
- }
-}
-
-// Reads parameters and changes font properties accordingly.
-void AnsiSetFont()
-{
- // Convert from the ANSI color scheme to the VGA color scheme.
- const unsigned conversion[8] =
- {
- COLOR8_BLACK, COLOR8_RED, COLOR8_GREEN, COLOR8_BROWN,
- COLOR8_BLUE, COLOR8_MAGENTA, COLOR8_CYAN, COLOR8_LIGHT_GREY,
- };
-
- for ( size_t i = 0; i < ansiusedparams; i++ )
- {
- nat cmd = ansiparams[i];
- // Turn all attributes off.
- if ( cmd == 0 )
- {
- currentcolor = DEFAULT_COLOR;
- }
- // Set text color.
- else if ( 30 <= cmd && cmd <= 37 )
- {
- nat val = cmd - 30;
- currentcolor &= (0xF0FF);
- currentcolor |= (conversion[val] << 8);
- }
- // Set background color.
- else if ( 40 <= cmd && cmd <= 47 )
- {
- nat val = cmd - 40;
- currentcolor &= (0x0FFF);
- currentcolor |= (conversion[val] << 12);
- }
- // TODO: There are many other things we don't support.
- }
-}
-
-// Executes an ASNI escape command based on given parameters.
-void RunANSICommand(char c)
-{
- switch ( c )
- {
- // Cursor up
- case 'A':
- {
- nat dist = ( 0 < ansiusedparams ) ? ansiparams[0] : 1;
- if ( line < dist ) { line = 0; } else { line -= dist; }
- break;
- }
- // Cursor down
- case 'B':
- {
- nat dist = ( 0 < ansiusedparams ) ? ansiparams[0] : 1;
- if ( height <= line + dist ) { line = height-1; } else { line += dist; }
- break;
- }
- // Cursor forward
- case 'C':
- {
- nat dist = ( 0 < ansiusedparams ) ? ansiparams[0] : 1;
- if ( width <= column + dist ) { column = width-1; } else { column += dist; }
- break;
- }
- // Cursor backward
- case 'D':
- {
- nat dist = ( 0 < ansiusedparams ) ? ansiparams[0] : 1;
- if ( column < dist ) { column = 0; } else { column -= dist; }
- break;
- }
- // Move to beginning of line N lines down.
- case 'E':
- {
- column = 0;
- nat dist = ( 0 < ansiusedparams ) ? ansiparams[0] : 1;
- if ( height <= line + dist ) { line = height-1; } else { line += dist; }
- break;
- }
- // Move to beginning of line N lines up.
- case 'F':
- {
- column = 0;
- nat dist = ( 0 < ansiusedparams ) ? ansiparams[0] : 1;
- if ( line < dist ) { line = 0; } else { line -= dist; }
- break;
- }
- // Move the cursor to column N.
- case 'G':
- {
- nat pos = ( 0 < ansiusedparams ) ? ansiparams[0]-1 : 0;
- if ( width <= pos ) { pos = width-1; }
- column = pos;
- break;
- }
- // Move the cursor to line Y, column X.
- case 'H':
- case 'f':
- {
- nat posy = ( 0 < ansiusedparams ) ? ansiparams[0]-1 : 0;
- nat posx = ( 1 < ansiusedparams ) ? ansiparams[1]-1 : 0;
- if ( width <= posx ) { posx = width-1; }
- if ( height <= posy ) { posy = height-1; }
- column = posx;
- line = posy;
- break;
- }
- // Erase parts of the screen.
- case 'J':
- {
- nat mode = ( 0 < ansiusedparams ) ? ansiparams[0] : 0;
-
- nat from = 0;
- nat to = 0;
-
- // From cursor to end.
- if ( mode == 0 ) { from = line*width + column; to = height*width - 1; }
-
- // From start to cursor.
- if ( mode == 1 ) { from = 0; to = line*width + column; }
-
- // Everything.
- if ( mode == 2 ) { from = 0; to = height*width - 1; }
-
- for ( nat i = from; i <= to; i++ )
- {
- vga[i] = ' ' | currentcolor;
- vgaattr[i] = 0;
- }
-
- break;
- }
- // Erase parts of the current line.
- case 'K':
- {
- nat mode = ( 0 < ansiusedparams ) ? ansiparams[0] : 0;
-
- nat from = 0;
- nat to = 0;
-
- // From cursor to end.
- if ( mode == 0 ) { from = column; to = width - 1; }
-
- // From start to cursor.
- if ( mode == 1 ) { from = 0; to = column; }
-
- // Everything.
- if ( mode == 2 ) { from = 0; to = width - 1; }
-
- for ( nat i = from; i <= to; i++ )
- {
- unsigned index = line * width + i;
- vga[index] = ' ' | currentcolor;
- vgaattr[index] = 0;
- }
-
- break;
- }
- // Scroll a line up and place a new line at the buttom.
- case 'S':
- {
- ScrollUp(); line = height-1;
- break;
- }
- // Scroll a line up and place a new line at the top.
- case 'T':
- {
- ScrollDown(); line = 0;
- break;
- }
- // Change how the text is rendered.
- case 'm':
- {
- if ( ansiusedparams == 0 )
- {
- ansiparams[0] = 0;
- ansiusedparams++;
- }
- AnsiSetFont();
- break;
- }
- // Request special information from terminal.
- case 'n':
- {
- // TODO: Handle this code.
- break;
- }
- // Save cursor position.
- case 's':
- {
- ansisavedposx = column;
- ansisavedposx = line;
- break;
- }
- // Restore cursor position.
- case 'u':
- {
- column = ansisavedposx;
- line = ansisavedposx;
- if ( width <= column ) { column = width-1; }
- if ( height <= line ) { line = height-1; }
- break;
- }
- // Hide cursor.
- case 'l':
- {
- // TODO: This is somehow related to the special char '?'.
- if ( 0 < ansiusedparams && ansiparams[0] == 25 )
- {
- showcursor = false;
- UpdateCursor();
- }
- break;
- }
- // Show cursor.
- case 'h':
- {
- // TODO: This is somehow related to the special char '?'.
- if ( 0 < ansiusedparams && ansiparams[0] == 25 )
- {
- showcursor = true;
- UpdateCursor();
- }
- break;
- }
- // TODO: Handle other cases.
- }
-
- ansimode = NONE;
-}
-
-// Parse another char of an ASNI escape code.
-void ParseANSIEscape(char c)
-{
- // Check the proper prefixes are used.
- if ( ansimode == CSI )
- {
- if ( c != '[' ) { ansimode = NONE; return; }
- ansimode = COMMAND;
- }
-
- // Parse parameters and the command.
- else if ( ansimode == COMMAND )
- {
- // Read part of a parameter.
- if ( '0' <= c && c <= '9' )
- {
- if ( paramundefined ) { ansiusedparams++; }
- paramundefined = false;
- nat val = c - '0';
- ansiparams[currentparamindex] *= 10;
- ansiparams[currentparamindex] += val;
- }
-
- // Parameter delimiter.
- else if ( c == ';' )
- {
- if ( currentparamindex == ANSI_NUM_PARAMS - 1 ) { ansimode = NONE; return; }
- paramundefined = true;
- ansiparams[++currentparamindex] = 0;
- }
-
- // Left for future standardization, so discard this sequence.
- else if ( c == ':' )
- {
- ignoresequence = true;
- }
-
- // Run a command.
- else if ( 64 <= c && c <= 126 )
- {
- if ( !ignoresequence ) { RunANSICommand(c); }
- }
-
- // Something I don't understand, and ignore intentionally.
- else if ( c == '?' )
- {
- }
-
- // TODO: There are some rare things that should be supported here.
-
- // Ignore unknown input.
- else
- {
- ansimode = NONE;
- }
- }
-}
-
-} // namespace VGATerminal
-} // namespace Sortix
diff --git a/sortix/vgaterminal.h b/sortix/vgaterminal.h
deleted file mode 100644
index e011c4b8..00000000
--- a/sortix/vgaterminal.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
-
- Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
-
- This file is part of Sortix.
-
- Sortix is free software: you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option) any later
- version.
-
- Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- Sortix. If not, see .
-
- vgaterminal.cpp
- A terminal based on a text mode buffer.
-
-*******************************************************************************/
-
-#ifndef SORTIX_VGATERMINAL_H
-#define SORTIX_VGATERMINAL_H
-
-namespace Sortix {
-namespace VGATerminal {
-
-void Init();
-void Reset();
-size_t Print(void* user, const char* string, size_t stringlen);
-
-} // namespace VGATerminal
-} // namespace Sortix
-
-#endif
-
diff --git a/sortix/vgatextbuffer.cpp b/sortix/vgatextbuffer.cpp
new file mode 100644
index 00000000..c949e35c
--- /dev/null
+++ b/sortix/vgatextbuffer.cpp
@@ -0,0 +1,193 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ vgatextbuffer.cpp
+ An indexable text buffer with the VGA text mode framebuffer as backend.
+
+*******************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include "vga.h"
+#include "vgatextbuffer.h"
+
+namespace Sortix {
+
+VGATextBuffer::VGATextBuffer(uint16_t* vga, uint16_t* attr,
+ size_t width, size_t height)
+{
+ this->vga = vga;
+ this->attr = attr;
+ this->width = width;
+ this->height = height;
+ cursorpos = {0, 0};
+ cursorenabled = true;
+ UpdateCursor();
+}
+
+VGATextBuffer::~VGATextBuffer()
+{
+}
+
+static TextChar EntryToTextChar(uint16_t entry)
+{
+ char c = entry & 0x00FF;
+ uint8_t vgacolor = entry >> 8U;
+ return TextChar{c, vgacolor};
+}
+
+static uint16_t CharToTextEntry(TextChar c)
+{
+ return (uint16_t) c.c | (uint16_t) c.vgacolor << 8U;
+}
+
+
+bool VGATextBuffer::UsablePosition(TextPos pos) const
+{
+ return pos.x < width && pos.y < height;
+}
+
+TextPos VGATextBuffer::CropPosition(TextPos pos) const
+{
+ if ( width <= pos.x )
+ pos.x = width - 1;
+ if ( height <= pos.y )
+ pos.y = height -1;
+ return pos;
+}
+
+size_t VGATextBuffer::OffsetOfPos(TextPos pos) const
+{
+ return pos.y * width + pos.x;
+}
+
+size_t VGATextBuffer::Width() const
+{
+ return width;
+}
+
+size_t VGATextBuffer::Height() const
+{
+ return height;
+}
+
+TextChar VGATextBuffer::GetChar(TextPos pos) const
+{
+ if ( UsablePosition(pos) )
+ return EntryToTextChar(vga[OffsetOfPos(pos)]);
+ return {0, 0};
+}
+
+void VGATextBuffer::SetChar(TextPos pos, TextChar c)
+{
+ if ( UsablePosition(pos) )
+ vga[OffsetOfPos(pos)] = CharToTextEntry(c);
+}
+
+uint16_t VGATextBuffer::GetCharAttr(TextPos pos) const
+{
+ if ( UsablePosition(pos) )
+ return attr[OffsetOfPos(pos)];
+ return 0;
+}
+
+void VGATextBuffer::SetCharAttr(TextPos pos, uint16_t attrval)
+{
+ if ( UsablePosition(pos) )
+ attr[OffsetOfPos(pos)] = attrval;
+}
+
+void VGATextBuffer::Scroll(ssize_t off, TextChar fillwith)
+{
+ if ( !off )
+ return;
+ bool neg = 0 < off;
+ size_t absoff = off < 0 ? -off : off;
+ if ( height < absoff )
+ absoff = height;
+ TextPos scrollfrom = neg ? TextPos{0, absoff} : TextPos{0, 0};
+ TextPos scrollto = neg ? TextPos{0, 0} : TextPos{0, absoff};
+ TextPos fillfrom = neg ? TextPos{0, height-absoff} : TextPos{0, 0};
+ TextPos fillto = neg ? TextPos{width-1, height-1} : TextPos{width-1, absoff-1};
+ size_t scrollchars = width * (height-absoff);
+ Move(scrollto, scrollfrom, scrollchars);
+ Fill(fillfrom, fillto, fillwith, 0);
+}
+
+void VGATextBuffer::Move(TextPos to, TextPos from, size_t numchars)
+{
+ size_t dest = OffsetOfPos(CropPosition(to));
+ size_t src = OffsetOfPos(CropPosition(from));
+ if ( dest < src )
+ for ( size_t i = 0; i < numchars; i++ )
+ vga[dest + i] = vga[src + i],
+ attr[dest + i] = attr[src + i];
+ else if ( src < dest )
+ for ( size_t i = 0; i < numchars; i++ )
+ vga[dest + numchars-1 - i] = vga[src + numchars-1 - i],
+ attr[dest + numchars-1 - i] = attr[src + numchars-1 - i];
+}
+
+void VGATextBuffer::Fill(TextPos from, TextPos to, TextChar fillwith,
+ uint16_t fillattr)
+{
+ from = CropPosition(from);
+ to = CropPosition(to);
+ size_t start = OffsetOfPos(from);
+ size_t end = OffsetOfPos(to);
+ size_t entry = CharToTextEntry(fillwith);
+ for ( size_t i = start; i <= end; i++ )
+ vga[i] = entry,
+ attr[i] = fillattr;
+}
+
+bool VGATextBuffer::GetCursorEnabled() const
+{
+ return cursorenabled;
+}
+
+void VGATextBuffer::SetCursorEnabled(bool enablecursor)
+{
+ cursorenabled = enablecursor;
+ UpdateCursor();
+}
+
+TextPos VGATextBuffer::GetCursorPos() const
+{
+ return cursorpos;
+}
+
+void VGATextBuffer::SetCursorPos(TextPos cursorpos)
+{
+ this->cursorpos = cursorpos;
+ UpdateCursor();
+}
+
+void VGATextBuffer::UpdateCursor()
+{
+ if ( cursorenabled )
+ VGA::SetCursor(cursorpos.x, cursorpos.y);
+ else
+ VGA::SetCursor(width, height-1);
+}
+
+} // namespace Sortix
diff --git a/sortix/vgatextbuffer.h b/sortix/vgatextbuffer.h
new file mode 100644
index 00000000..99d31ffc
--- /dev/null
+++ b/sortix/vgatextbuffer.h
@@ -0,0 +1,70 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ vgatextbuffer.h
+ An indexable text buffer with the VGA text mode framebuffer as backend.
+
+*******************************************************************************/
+
+#ifndef SORTIX_VGATEXTBUFFER_H
+#define SORTIX_VGATEXTBUFFER_H
+
+#include
+
+namespace Sortix {
+
+class VGATextBuffer : public TextBuffer
+{
+public:
+ VGATextBuffer(uint16_t* vga, uint16_t* attr, size_t width, size_t height);
+ virtual ~VGATextBuffer();
+ virtual size_t Width() const;
+ virtual size_t Height() const;
+ virtual TextChar GetChar(TextPos pos) const;
+ virtual void SetChar(TextPos pos, TextChar c);
+ virtual uint16_t GetCharAttr(TextPos pos) const ;
+ virtual void SetCharAttr(TextPos pos, uint16_t attrval);
+ virtual void Scroll(ssize_t off, TextChar fillwith);
+ virtual void Move(TextPos to, TextPos from, size_t numchars);
+ virtual void Fill(TextPos from, TextPos to, TextChar fillwith,
+ uint16_t fillattr);
+ virtual bool GetCursorEnabled() const;
+ virtual void SetCursorEnabled(bool enablecursor);
+ virtual TextPos GetCursorPos() const;
+ virtual void SetCursorPos(TextPos cursorpos);
+
+private:
+ bool UsablePosition(TextPos pos) const;
+ TextPos CropPosition(TextPos pos) const;
+ size_t OffsetOfPos(TextPos pos) const;
+ void UpdateCursor();
+
+private:
+ uint16_t* vga;
+ uint16_t* attr;
+ size_t width;
+ size_t height;
+ TextPos cursorpos;
+ bool cursorenabled;
+
+};
+
+} // namespace Sortix
+
+#endif