|
|
1.1 ! root 1: /* ! 2: * Hatari - console.c ! 3: * ! 4: * Copyright (C) 2012 by Eero Tamminen ! 5: * ! 6: * This file is distributed under the GNU General Public License, version 2 ! 7: * or at your option any later version. Read the file gpl.txt for details. ! 8: * ! 9: * console.c - catching of emulated console output with minimal VT52 emulation. ! 10: */ ! 11: const char Console_fileid[] = "Hatari console.c : " __DATE__ " " __TIME__; ! 12: ! 13: #include <stdio.h> ! 14: #include <string.h> ! 15: #include <SDL.h> ! 16: ! 17: #include "main.h" ! 18: #include "m68000.h" ! 19: #include "stMemory.h" ! 20: #include "hatari-glue.h" ! 21: #include "console.h" ! 22: #include "options.h" ! 23: ! 24: /** ! 25: * Maps Atari characters to their closest ASCII equivalents. ! 26: */ ! 27: static void map_character(Uint8 value) ! 28: { ! 29: static const Uint8 map_0_31[32] = { ! 30: '.', '.', '.', '.', '.', '.', '.', '.', /* 0x00 */ ! 31: /* white space */ ! 32: '\b','\t','\n','.','.','\r', '.', '.', /* 0x08 */ ! 33: /* LED numbers */ ! 34: '0', '1', '2', '3', '4', '5', '6', '7', /* 0x10 */ ! 35: '8', '9', '.', '.', '.', '.', '.', '.' /* 0x18 */ ! 36: }; ! 37: static const Uint8 map_128_255[128] = { ! 38: /* accented characters */ ! 39: 'C', 'U', 'e', 'a', 'a', 'a', 'a', 'c', /* 0x80 */ ! 40: 'e', 'e', 'e', 'i', 'i', 'i', 'A', 'A', /* 0x88 */ ! 41: 'E', 'a', 'A', 'o', 'o', 'o', 'u', 'u', /* 0x90 */ ! 42: 'y', 'o', 'u', 'c', '.', 'Y', 'B', 'f', /* 0x98 */ ! 43: 'a', 'i', 'o', 'u', 'n', 'N', 'a', 'o', /* 0xA0 */ ! 44: '?', '.', '.', '.', '.', 'i', '<', '>', /* 0xA8 */ ! 45: 'a', 'o', 'O', 'o', 'o', 'O', 'A', 'A', /* 0xB0 */ ! 46: 'O', '"','\'', '.', '.', 'C', 'R', '.', /* 0xB8 */ ! 47: 'j', 'J', '.', '.', '.', '.', '.', '.', /* 0xC0 */ ! 48: '.', '.', '.', '.', '.', '.', '.', '.', /* 0xC8 */ ! 49: '.', '.', '.', '.', '.', '.', '.', '.', /* 0xD0 */ ! 50: '.', '.', '.', '.', '.', '.', '^', '.', /* 0xD8 */ ! 51: '.', '.', '.', '.', '.', '.', '.', '.', /* 0xE0 */ ! 52: '.', '.', '.', '.', '.', '.', '.', '.', /* 0xE8 */ ! 53: '.', '.', '.', '.', '.', '.', '.', '.', /* 0xF0 */ ! 54: '.', '.', '.', '.', '.', '.', '.', '.' /* 0xF8 */ ! 55: }; ! 56: /* map normal characters to host console */ ! 57: if (value < 32) { ! 58: fputc(map_0_31[value], stderr); ! 59: } else if (value > 127) { ! 60: fputc(map_128_255[value-128], stderr); ! 61: } else { ! 62: fputc(value, stderr); ! 63: } ! 64: } ! 65: ! 66: ! 67: /** ! 68: * Convert given console character output to ASCII. ! 69: * Accepts one character at the time, parses VT52 escape codes ! 70: * and outputs them on console. ! 71: * ! 72: * On host, TOS cursor forwards movement is done with spaces, ! 73: * backwards movement is delayed until next non-white character ! 74: * at which point output switches to next line. Other VT52 ! 75: * escape sequences than cursor movement are ignored. ! 76: */ ! 77: static void vt52_emu(Uint8 value) ! 78: { ! 79: /* state machine to handle/ignore VT52 escape sequence */ ! 80: static int escape_index; ! 81: static int escape_target; ! 82: static int hpos_host, hpos_tos; ! 83: static bool need_nl; ! 84: static enum { ! 85: ESCAPE_NONE, ESCAPE_POSITION ! 86: } escape_type; ! 87: ! 88: if (escape_target) { ! 89: if (++escape_index == 1) { ! 90: /* VT52 escape sequences */ ! 91: switch(value) { ! 92: case 'E': /* clear screen+home -> newline */ ! 93: fputs("\n", stderr); ! 94: hpos_host = 0; ! 95: break; ! 96: /* sequences with arguments */ ! 97: case 'b': /* foreground color */ ! 98: case 'c': /* background color */ ! 99: escape_target = 2; ! 100: return; ! 101: case 'Y': /* cursor position */ ! 102: escape_type = ESCAPE_POSITION; ! 103: escape_target = 3; ! 104: return; ! 105: } ! 106: } else if (escape_index < escape_target) { ! 107: return; ! 108: } ! 109: if (escape_type == ESCAPE_POSITION) { ! 110: /* last item gives horizontal position */ ! 111: hpos_tos = value - ' '; ! 112: if (hpos_tos > 79) { ! 113: hpos_tos = 79; ! 114: } else if (hpos_tos < 0) { ! 115: hpos_tos = 0; ! 116: } ! 117: if (hpos_tos > hpos_host) { ! 118: fprintf(stderr, "%*s", hpos_tos - hpos_host, ""); ! 119: hpos_host = hpos_tos; ! 120: } else if (hpos_tos < hpos_host) { ! 121: need_nl = true; ! 122: } ! 123: } ! 124: /* escape sequence end */ ! 125: escape_target = 0; ! 126: return; ! 127: } ! 128: if (value == 27) { ! 129: /* escape sequence start */ ! 130: escape_type = ESCAPE_NONE; ! 131: escape_target = 1; ! 132: escape_index = 0; ! 133: return; ! 134: } ! 135: ! 136: /* do newline & indent for backwards movement only when necessary */ ! 137: if (need_nl) { ! 138: /* TOS cursor horizontal movement until host output */ ! 139: switch (value) { ! 140: case ' ': ! 141: hpos_tos++; ! 142: return; ! 143: case '\b': ! 144: hpos_tos--; ! 145: return; ! 146: case '\t': ! 147: hpos_tos = (hpos_tos + 8) & 0xfff0; ! 148: return; ! 149: case '\r': ! 150: case '\n': ! 151: hpos_tos = 0; ! 152: break; ! 153: } ! 154: fputs("\n", stderr); ! 155: if (hpos_tos > 0 && hpos_tos < 80) { ! 156: fprintf(stderr, "%*s", hpos_tos, ""); ! 157: hpos_host = hpos_tos; ! 158: } else { ! 159: hpos_host = 0; ! 160: } ! 161: need_nl = false; ! 162: } ! 163: ! 164: /* host cursor horizontal movement */ ! 165: switch (value) { ! 166: case '\b': ! 167: hpos_host--; ! 168: break; ! 169: case '\t': ! 170: hpos_host = (hpos_host + 8) & 0xfff0; ! 171: break; ! 172: case '\r': ! 173: case '\n': ! 174: hpos_host = 0; ! 175: break; ! 176: default: ! 177: hpos_host++; ! 178: break; ! 179: } ! 180: map_character(value); ! 181: } ! 182: ! 183: ! 184: /** ! 185: * Catch requested xconout vector calls and show their output on console ! 186: */ ! 187: void Console_Check(void) ! 188: { ! 189: Uint32 pc, xconout, stack, stackbeg, stackend; ! 190: int increment; ! 191: Uint16 chr; ! 192: ! 193: /* xconout vector for requested device? */ ! 194: xconout = STMemory_ReadLong(0x57e + ConOutDevice * SIZE_LONG); ! 195: pc = M68000_GetPC(); ! 196: if (pc != xconout) { ! 197: return; ! 198: } ! 199: ! 200: /* assumptions about xconout function: ! 201: * - c declaration: leftmost item on top of stackframe ! 202: * - args: WORD device, WORD character to output ! 203: * - can find the correct stackframe arguments by skipping ! 204: * wrong looking stack content from intermediate functions ! 205: * (bsr/jsr return addresses are > 0xff, local stack args ! 206: * could be an issue but hopefully don't match device number ! 207: * in any of the TOSes nor in MiNT or its conout devices) ! 208: */ ! 209: stackbeg = stack = Regs[REG_A7]; ! 210: stackend = stack + 16; ! 211: increment = SIZE_LONG; ! 212: while (STMemory_ReadWord(stack) != ConOutDevice) { ! 213: stack += increment; ! 214: if (stack > stackend) { ! 215: if (increment == SIZE_LONG) { ! 216: /* skipping return addresses not enough, ! 217: * try skipping potential local args too ! 218: */ ! 219: fprintf(stderr, "WARNING: xconout stack args not found by skipping return addresses, trying short skipping.\n"); ! 220: increment = SIZE_WORD; ! 221: stack = stackbeg; ! 222: continue; ! 223: } ! 224: /* failed */ ! 225: fprintf(stderr, "WARNING: xconout args not found from stack.\n"); ! 226: return; ! 227: } ! 228: } ! 229: chr = STMemory_ReadWord(stack + SIZE_WORD); ! 230: if (chr & 0xff00) { ! 231: /* allow 0xff high byte (sign extension?) */ ! 232: if ((chr & 0xff00) != 0xff00) { ! 233: fprintf(stderr, "WARNING: xconout character has unknown high byte bits: 0x%x '%c'.\n", chr, chr&0xff); ! 234: /* higher bits, assume not correct arg */ ! 235: return; ! 236: } ! 237: chr &= 0xff; ! 238: } ! 239: switch(ConOutDevice) { ! 240: case 2: /* EmuTOS/TOS/MiNT/etc console, VT-52 terminal */ ! 241: vt52_emu(chr); ! 242: break; ! 243: case 0: /* Printer/Parallel port */ ! 244: case 1: /* Aux device, the RS-232 port */ ! 245: case 3: /* MIDI port */ ! 246: case 4: /* Keyboard port */ ! 247: case 5: /* Raw screen device (no escape sequence / control char processing) */ ! 248: case 6: /* ST compatible RS-232 port (Modem 1) */ ! 249: case 7: /* SCC channel B (Modem 2) */ ! 250: map_character(chr); ! 251: break; ! 252: } ! 253: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.