Annotation of hatari/src/debug/console.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.