#include #include #include "joey.h" #ifdef JOEY_IIGS segment "ansiterm"; #endif #include "ansiterm.h" typedef struct { int x; int y; } Vector2T; static int _columns = 40; static int _rows = 25; static int _xoff = 0; static int _yoff = 0; static bool _escFound = false; static bool _inEscape = false; static bool _bold = false; static bool _blink = false; static bool _reverse = false; static int _foreground = 7; static int _background = 0; static int _fColor = 7; static int _bColor = 0; static int _number = 0; static int _parameters[5]; static int _parameterCount = 0; static Vector2T _cursorSave; static Vector2T _cursor; static jlStaT *_ansiFont = NULL; static int *_screenBuffer = NULL; void termDebug(const char *what, ...); bool termParseANSI(char c); void termRenderCharacterAtCursor(char c); void termRepaint(void); void termResetSequence(void); void termScrollUp(void); void termUpdateColors(void); void termClearScreen(void) { memset(_screenBuffer, 0, (size_t)(2 * _columns * _rows)); } __attribute__((__format__ (__printf__, 1, 0))) void termDebug(const char *what, ...) { char msg[1024]; va_list va; va_start(va, what); vsprintf(msg, what, va); va_end(va); printf("%s\n", msg); } void termGetCursor(int *x, int *y) { *x = _cursor.x; *y = _cursor.y; } void termMoveCursor(int x, int y) { if (x < 1) { _cursor.x = 1; termDebug("Attempt to position cursor too far left: %d", x); } else { if (x > _columns) { _cursor.x = _columns; termDebug("Attempt to position cursor too far right: %d", x); } else { _cursor.x = x; } } if (y < 1) { _cursor.y = 1; termDebug("Attempt to position cursor too far up: %d", y); } else { if (y > _rows) { _cursor.y = _rows; termDebug("Attempt to position cursor too far down: %d", y); } else { _cursor.y = y; } } } bool termParseANSI(char c) { int x; int y; int oldX; int cx; int p; bool updateDisplay = false; Vector2T cursor = _cursor; // Find leading ESC character. if ((c == (char)27) && !_escFound && !_inEscape) { _escFound = true; return updateDisplay; } // Find [ character. if ((c == '[') && _escFound && !_inEscape) { _inEscape = true; return updateDisplay; } // We don't do non-'ESC[' sequences. if (_escFound && !_inEscape) { termDebug("Unexpected Character: %d", (int)c); termResetSequence(); } if (_inEscape) { switch (c) { // All we know is that a Xenomorph may be involved. case '[': case (char)27: termDebug("BUG! Escape found inside sequence."); break; // End of a parameter. case ';': _parameters[_parameterCount++] = _number; _number = 0; break; // Cursor up. case 'A': y = _number; termDebug("Moving cursor up %d", y); termMoveCursor(cursor.x, cursor.y - y); termResetSequence(); break; // Cursor down. case 'B': y = _number; termDebug("Moving cursor down %d", y); termMoveCursor(cursor.x, cursor.y + y); termResetSequence(); break; // Cursor forward. case 'C': x = _number; termDebug("Moving cursor right %d", x); termMoveCursor(cursor.x + x, cursor.y); termResetSequence(); break; // Cursor backward. case 'D': x = _number; termDebug("Moving cursor left %d", x); termMoveCursor(cursor.x - x, cursor.y); termResetSequence(); break; // Cursor line down. case 'E': y = _number; termDebug("Moving cursor down line %d", y); termMoveCursor(1, cursor.y + y); //***TODO*** This should allow scrolling termResetSequence(); break; // Cursor line up. case 'F': y = _number; termDebug("Moving cursor up line %d", y); termMoveCursor(1, cursor.y - y); termResetSequence(); break; // Cursor horizontal absolute. case 'G': x = _number; termDebug("Moving cursor horizontally to %d", x); termMoveCursor(x, cursor.y); termResetSequence(); break; // Move cursor. case 'H': case 'f': switch (_parameterCount) { case 0: // Absolute position, Y. Kinda. Moves X to 1. y = _number; termDebug("Moving cursor to 1x%d", y); termMoveCursor(1, y); break; case 1: // Absolute position. x = _number; y = _parameters[0]; termDebug("Moving cursor to %dx%d", x, y); termMoveCursor(x, y); break; default: termDebug("Unknown Cursor Move"); break; } termResetSequence(); break; // Clear display. case 'J': if ((_parameterCount == 0) && (_number == 2)) { termDebug("Clear display"); termClearScreen(); updateDisplay = true; termMoveCursor(1, 1); } else { termDebug("Unimplemented Screen Clear"); } termResetSequence(); break; // Clear from cursor to end of line. case 'K': x = _number; if (x == 0) { termDebug("Clear to end of line"); oldX = cursor.x; for (cx=cursor.x; cx<=_columns; cx++) { termMoveCursor(cx, cursor.y); termRenderCharacterAtCursor(' '); } termMoveCursor(oldX, cursor.y); } else { termDebug("Unimplemented Line Clear"); } termResetSequence(); break; // Insert lines. case 'L': //***TODO*** termDebug("Unimplemented Insert Line"); termResetSequence(); break; // Delete lines. case 'M': //***TODO*** termDebug("Unimplemented Delete Line"); termResetSequence(); break; // Delete characters. case 'P': //***TODO*** termDebug("Unimplemented Delete Character"); termResetSequence(); break; // Scroll Up. case 'S': //***TODO*** termDebug("Unimplemented Scroll Up"); termResetSequence(); break; // Scroll Down. case 'T': //***TODO*** termDebug("Unimplemented Scroll Down"); termResetSequence(); break; // Clear Screen with Normal Attribute. case 'U': x = _bColor; _bColor = 0; termUpdateColors(); termClearScreen(); updateDisplay = true; _bColor = x; termUpdateColors(); termMoveCursor(1, 1); termResetSequence(); break; // Back-TAB. case 'Z': //***TODO*** termDebug("Unimplemented Back TAB"); termResetSequence(); break; // Set attributes. case 'm': _parameters[_parameterCount++] = _number; for (p=0; p<_parameterCount; p++) { termDebug("Set attribute %d", _parameters[p]); x = _parameters[p]; switch (x) { case 0: _bold = false; _blink = false; _reverse = false; _fColor = 7; _bColor = 0; termUpdateColors(); break; case 1: _bold = true; termUpdateColors(); break; case 5: case 6: _blink = true; break; case 7: if (!_reverse) { x = _fColor; _fColor = _bColor; _bColor = x; termUpdateColors(); } _reverse = true; break; case 21: case 22: _bold = false; termUpdateColors(); break; case 25: _blink = false; break; case 27: if (_reverse) { x = _fColor; _fColor = _bColor; _bColor = x; termUpdateColors(); } _reverse = false; break; default: if ((x > 29) && (x < 38)) { _fColor = x - 30; termUpdateColors(); } else { if ((x > 39) && (x < 48)) { _bColor = x - 40; termUpdateColors(); } else { termDebug("Unknown attribute: %d", (int)c); } } break; } } termResetSequence(); break; // Define scroll region. case 'r': //***TODO*** termDebug("Unimplemented Scroll Region"); termResetSequence(); break; // Cursor save. case 's': termDebug("Saving cursor"); _cursorSave = cursor; termResetSequence(); break; // Cursor restore. case 'u': termDebug("Restoring cursor"); termMoveCursor(_cursorSave.x, _cursorSave.y); termResetSequence(); break; // Something else. default: // Number? if ((c >= '0') && (c <= '9')) { _number = _number * 10 + (c - '0'); } else { termDebug("Unknown sequence: %d", (int)c); termResetSequence(); } break; } } else { switch (c) { case (char)7: // Beep! termDebug("Unimplemented beep"); break; case (char)8: case (char)127: //***TODO*** Backspace termDebug("Unimplemented backspace"); break; case (char)9: //***TODO*** TAB termDebug("Unimplemented tab"); break; case (char)10: cursor.y++; if (cursor.y > _rows) { cursor.y--; termScrollUp(); updateDisplay = true; } termMoveCursor(cursor.x, cursor.y); break; case (char)12: x = _bColor; _bColor = 0; termUpdateColors(); termClearScreen(); updateDisplay = true; _bColor = x; termUpdateColors(); termMoveCursor(1, 1); break; case (char)13: termMoveCursor(1, cursor.y); break; default: updateDisplay = true; termRenderCharacterAtCursor(c); if (_blink) { //***TODO*** Not handled } cursor.x++; if (cursor.x > _columns) { cursor.x = 1; cursor.y++; if (cursor.y > _rows) { cursor.y--; termScrollUp(); } } termMoveCursor(cursor.x, cursor.y); break; } } return updateDisplay; } void termPrint(char *string) { int x; int l = (int)strlen(string); for (x=0; x