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

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

unix.superglobalmegacorp.com

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