summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2018-10-27 23:42:20 +0200
committerAndreas Kling <awesomekling@gmail.com>2018-10-27 23:42:20 +0200
commit8289a5c93cabc3cfb4cf6e5e551d8ad6fca58a9f (patch)
tree35b40937c6128a9462bd5c142d3f4a3c453fa6ca
parentcc7e3519a67c8080c44a104ab1b5d4d61b6b35c5 (diff)
downloadserenity-8289a5c93cabc3cfb4cf6e5e551d8ad6fca58a9f.zip
Implement 'H' and 'J' escape sequences.
-rw-r--r--AK/Vector.h3
-rw-r--r--Kernel/Console.cpp154
-rw-r--r--Kernel/Console.h17
-rw-r--r--Kernel/VGA.cpp6
-rw-r--r--Kernel/VGA.h2
5 files changed, 168 insertions, 14 deletions
diff --git a/AK/Vector.h b/AK/Vector.h
index 7c258eb659..330d33cd0d 100644
--- a/AK/Vector.h
+++ b/AK/Vector.h
@@ -87,6 +87,9 @@ public:
size_t size() const { return m_impl ? m_impl->size() : 0; }
size_t capacity() const { return m_impl ? m_impl->capacity() : 0; }
+ T* data() { return m_impl ? &at(0) : nullptr; }
+ const T* data() const { return m_impl ? &at(0) : nullptr; }
+
const T& at(size_t i) const { return m_impl->at(i); }
T& at(size_t i) { return m_impl->at(i); }
diff --git a/Kernel/Console.cpp b/Kernel/Console.cpp
index 08ecedd0d8..5a95d8d982 100644
--- a/Kernel/Console.cpp
+++ b/Kernel/Console.cpp
@@ -1,6 +1,8 @@
#include "Console.h"
#include "VGA.h"
#include "IO.h"
+#include "kprintf.h"
+#include <AK/String.h>
// Bytes output to 0xE9 end up on the Bochs console. It's very handy.
#define CONSOLE_OUT_TO_E9
@@ -34,21 +36,153 @@ ssize_t Console::read(byte* buffer, size_t bufferSize)
return 0;
}
+inline bool isParameter(byte ch)
+{
+ return ch >= 0x30 && ch <= 0x3f;
+}
+
+inline bool isIntermediate(byte ch)
+{
+ return ch >= 0x20 && ch <= 0x2f;
+}
+
+inline bool isFinal(byte ch)
+{
+ return ch >= 0x40 && ch <= 0x7e;
+}
+
+unsigned parseUInt(const String& str, bool& ok)
+{
+ unsigned value = 0;
+ for (size_t i = 0; i < str.length(); ++i) {
+ if (str[i] < '0' || str[i] > '9') {
+ ok = false;
+ return 0;
+ }
+ value = value * 10;
+ value += str[i] - '0';
+ }
+ ok = true;
+ return value;
+}
+
+void Console::escape$H(const Vector<unsigned>& params)
+{
+ unsigned row = 1;
+ unsigned col = 1;
+
+ if (params.size() >= 1)
+ row = params[0];
+ if (params.size() >= 2)
+ col = params[1];
+ m_cursorRow = row - 1;
+ m_cursorColumn = col - 1;
+ vga_set_cursor(row - 1, col - 1);
+}
+
+void Console::escape$J(const Vector<unsigned>& params)
+{
+ int mode = 0;
+ if (params.size() >= 1)
+ mode = params[0];
+ switch (mode) {
+ case 0:
+ // FIXME: Clear from cursor to end of screen.
+ notImplemented();
+ break;
+ case 1:
+ // FIXME: Clear from cursor to beginning of screen.
+ notImplemented();
+ break;
+ case 2:
+ vga_clear();
+ break;
+ case 3:
+ // FIXME: <esc>[3J should also clear the scrollback buffer.
+ vga_clear();
+ break;
+ }
+}
+
+void Console::executeEscapeSequence(byte final)
+{
+ auto paramparts = String((const char*)m_parameters.data(), m_parameters.size()).split(';');
+ Vector<unsigned> params;
+ for (auto& parampart : paramparts) {
+ bool ok;
+ unsigned value = parseUInt(parampart, ok);
+ if (!ok) {
+ // FIXME: Should we do something else?
+ return;
+ }
+ params.append(value);
+ }
+ switch (final) {
+ case 'H': escape$H(params); break;
+ case 'J': escape$J(params); break;
+ default: break;
+ }
+
+ m_parameters.clear();
+ m_intermediates.clear();
+}
+
void Console::putChar(char ch)
{
#ifdef CONSOLE_OUT_TO_E9
+ //if (ch != 27)
IO::out8(0xe9, ch);
#endif
- switch (ch) {
- case '\0':
- return;
- case '\n':
- m_cursorColumn = 0;
+ auto scrollup = [&] {
if (m_cursorRow == (m_rows - 1)) {
vga_scroll_up();
} else {
++m_cursorRow;
}
+ m_cursorColumn = 0;
+ };
+
+ switch (m_escState) {
+ case ExpectBracket:
+ if (ch == '[')
+ m_escState = ExpectParameter;
+ else
+ m_escState = Normal;
+ return;
+ case ExpectParameter:
+ if (isParameter(ch)) {
+ m_parameters.append(ch);
+ return;
+ }
+ m_escState = ExpectIntermediate;
+ // fall through
+ case ExpectIntermediate:
+ if (isIntermediate(ch)) {
+ m_intermediates.append(ch);
+ return;
+ }
+ m_escState = ExpectFinal;
+ // fall through
+ case ExpectFinal:
+ if (isFinal(ch)) {
+ m_escState = Normal;
+ executeEscapeSequence(ch);
+ return;
+ }
+ m_escState = Normal;
+ return;
+ case Normal:
+ break;
+ }
+
+ switch (ch) {
+ case '\0':
+ return;
+ case '\033':
+ m_escState = ExpectBracket;
+ return;
+ case '\n':
+ scrollup();
vga_set_cursor(m_cursorRow, m_cursorColumn);
return;
}
@@ -56,14 +190,8 @@ void Console::putChar(char ch)
vga_putch_at(m_cursorRow, m_cursorColumn, ch);
++m_cursorColumn;
- if (m_cursorColumn >= m_columns) {
- if (m_cursorRow == (m_rows - 1)) {
- vga_scroll_up();
- } else {
- ++m_cursorRow;
- }
- m_cursorColumn = 0;
- }
+ if (m_cursorColumn >= m_columns)
+ scrollup();
vga_set_cursor(m_cursorRow, m_cursorColumn);
}
diff --git a/Kernel/Console.h b/Kernel/Console.h
index 196f9cb6ad..7b7d69c743 100644
--- a/Kernel/Console.h
+++ b/Kernel/Console.h
@@ -1,6 +1,7 @@
#pragma once
#include <AK/Compiler.h>
+#include <AK/Vector.h>
#include <VirtualFileSystem/CharacterDevice.h>
class Console final : public CharacterDevice {
@@ -17,6 +18,9 @@ public:
void putChar(char);
private:
+ void escape$H(const Vector<unsigned>&);
+ void escape$J(const Vector<unsigned>&);
+
const byte m_rows { 25 };
const byte m_columns { 80 };
byte m_cursorRow { 0 };
@@ -24,6 +28,19 @@ private:
byte m_currentAttribute { 0x07 };
+ void executeEscapeSequence(byte final);
+
+ enum EscapeState {
+ Normal,
+ ExpectBracket,
+ ExpectParameter,
+ ExpectIntermediate,
+ ExpectFinal,
+ };
+ EscapeState m_escState { Normal };
+ Vector<byte> m_parameters;
+ Vector<byte> m_intermediates;
+
const byte* s_vgaMemory { (const byte*)0xb8000 };
};
diff --git a/Kernel/VGA.cpp b/Kernel/VGA.cpp
index 59e3c73267..b2571ecdd8 100644
--- a/Kernel/VGA.cpp
+++ b/Kernel/VGA.cpp
@@ -15,6 +15,12 @@ void vga_scroll_up()
memset(vga_mem + (160 * 24), 0, 160);
}
+void vga_clear()
+{
+ InterruptDisabler disabler;
+ memset(vga_mem, 0, 160 * 25);
+}
+
void vga_putch_at(byte row, byte column, byte ch)
{
word cur = (row * 160) + (column * 2);
diff --git a/Kernel/VGA.h b/Kernel/VGA.h
index b13f84b32f..a1e505f53c 100644
--- a/Kernel/VGA.h
+++ b/Kernel/VGA.h
@@ -10,4 +10,4 @@ void vga_set_cursor(BYTE row, BYTE column);
WORD vga_get_cursor();
void vga_putch_at(byte row, byte column, byte ch);
void vga_scroll_up();
-
+void vga_clear();