// vconsole.cpp // Author: Josh Holtrop // Date: 08/02/04 // Modified: 05/11/05 extern "C" { #include "hos_defines.h" #include "mm/vmm.h" #include "lang/lang.h" #include "display/display.h" #include "functions.h" } #include "devices.h" #include "char/vconsole.h" VConsole *vconsoles[VCONSOLE_MAX]; // pointer to virtual console structs char ansi2vgaAttr[8] = {0, 4, 2, 6, 1, 5, 3, 7}; void vconsole_setup(int width, int height) { for (int i = 0; i < VCONSOLE_MAX; i++) vconsoles[i] = new VConsole(width, height); } int vconsole_activate(u32_t id) { if (id >= VCONSOLE_MAX) return -1; vconsoles[id]->activate(); return 0; } int vconsole_deactivate(u32_t id) { if (id >= VCONSOLE_MAX) return -1; vconsoles[id]->deactivate(); return 0; } VConsoleDriver::~VConsoleDriver() { for (int i = 0; i < VCONSOLE_MAX; i++) if (vconsoles[i]) delete vconsoles[i]; } int VConsoleDriver::char_write(minor_t minor, int c) { if (minor < 0 || minor >= VCONSOLE_MAX) return -1; if (!vconsoles[minor]) return -2; return vconsoles[minor]->char_write(c); } VConsole::VConsole(int width, int height) { myBuffer = new u16_t[width * height]; myBuffer2 = NULL; myWidth = width; myHeight = height; myAttribute = myForeground = 0x07; memsetw(myBuffer, 0x0720, width * height); myCursorPosition = 0; myCursorStackPosition = myEscapeLevel = myEscapePosition = myBackground = myBold = myReverse = myBlink = myConcealed = myActive = 0; } VConsole::~VConsole() { delete[] myBuffer; } void VConsole::activate() { if (myActive) // don't activate if already active return; myActive = 1; myBuffer2 = myBuffer; myBuffer = (u16_t *)CONSOLE_MEMORY; memcpyd(myBuffer, myBuffer2, (myWidth * myHeight) >> 1); writeCursorPosition(myCursorPosition); } void VConsole::deactivate() { if (!myActive) // don't deactivate non-active console return; myActive = 0; myBuffer = myBuffer2; myBuffer2 = NULL; memcpyd(myBuffer, (u16_t *)CONSOLE_MEMORY, (myWidth * myHeight) >> 1); } int VConsole::char_write(int c) { int cursorY = myCursorPosition / myWidth; int cursorX = myCursorPosition % myWidth; switch (myEscapeLevel) { case 2: if (c >= '0' && c <= '9') // c is part of an escape value { myEscapeValue[myEscapePosition] *= 10; myEscapeValue[myEscapePosition] += c - '0'; return 0; } else if (c == ';') { if (myEscapePosition < 7) myEscapePosition++; return 0; } switch (c) { case 'A': // move cursor up n rows update_cursor_coord(cursorY - myEscapeValue[0], cursorX); break; case 'B': // move cursor down n rows update_cursor_coord(cursorY + myEscapeValue[0], cursorX); break; case 'C': // move cursor left n columns update_cursor_coord(cursorY, cursorX - myEscapeValue[0]); break; case 'D': // move cursor right n columns update_cursor_coord(cursorY, cursorX + myEscapeValue[0]); break; case 'H': case 'f': // move cursor to position (x,y) upper left is (1,1) update_cursor_coord(myEscapeValue[1] - 1, myEscapeValue[0] - 1); break; case 'J': // clear screen, home cursor memsetw(myBuffer, 0x0720, myWidth * myHeight); update_cursor_coord(0, 0); break; case 'K': // erase line from cursor position (including char. under cursor) to end of line memsetw(myBuffer + myCursorPosition, 0x0720, myWidth - cursorX); break; case 's': // push cursor position on an internal stack if (myCursorStackPosition < 16) myCursorStack[myCursorStackPosition++] = myCursorPosition; break; case 'u': // pop cursor position from stack if (myCursorStackPosition > 0) update_cursor(myCursorStack[--myCursorStackPosition]); break; case 'm': // set text attributes for (int evalEscapePosition = 0; evalEscapePosition <= myEscapePosition; evalEscapePosition++) { switch (myEscapeValue[evalEscapePosition]) { case 0: myForeground = 0x07; myBackground = myConcealed = myReverse = myBlink = myBold = 0; update_attribute(); break; case 1: myBold = 1; update_attribute(); break; case 5: myBlink = 1; update_attribute(); break; case 7: myReverse = 1; update_attribute(); break; case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: myForeground = ansi2vgaAttr[myEscapeValue[evalEscapePosition] - 30]; update_attribute(); break; case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: myBackground = ansi2vgaAttr[myEscapeValue[evalEscapePosition] - 40]; update_attribute(); break; } } myEscapePosition = 0; break; } memsetd(myEscapeValue, 0, 8); myEscapePosition = 0; myEscapeLevel = 0; return 0; case 1: if (c == '[') myEscapeLevel = 2; break; myEscapeLevel = 0; return 0; // invalid escape sequence default: if (c == '\e') { myEscapeLevel = 1; return 0; } put_char(c); } return 0; } void VConsole::put_char(int c) { if (!myConcealed) { switch (c) { case '\t': if (myCursorPosition % 8) update_cursor(myCursorPosition + (8 - (myCursorPosition % 8))); else update_cursor(myCursorPosition + 8); break; case '\n': if (myCursorPosition % myWidth) update_cursor(myCursorPosition + (myWidth - (myCursorPosition % myWidth))); else update_cursor(myCursorPosition + myWidth); break; default: myBuffer[myCursorPosition] = c | (myAttribute << 8); update_cursor(myCursorPosition + 1); } } } void VConsole::update_cursor_coord(int y, int x) { if (y < 0) y = 0; else if (y >= myHeight) y = myHeight - 1; if (x < 0) x = 0; else if (x >= myWidth) x = myWidth - 1; update_cursor(myWidth * y + x); } void VConsole::update_cursor(u16_t position) { myCursorPosition = position; if (position >= (myWidth * myHeight)) // time to scroll console { int i; for (i = 0; i < myCursorStackPosition; i++) { myCursorStack[i] -= myWidth; if (myCursorStack[i] < 0) myCursorStack[i] = 0; } myCursorPosition -= myWidth; memcpyw(myBuffer, myBuffer + myWidth, myWidth * (myHeight - 1)); memsetw(myBuffer + (myWidth * (myHeight - 1)), 0x0720, myWidth); } if (myActive) writeCursorPosition(position); } void VConsole::update_attribute() { if (myReverse) myAttribute = myBlink << 7 | myForeground << 4 | myBold << 3 | myBackground; else myAttribute = myBlink << 7 | myBackground << 4 | myBold << 3 | myForeground; }