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

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: #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) {
1.1.1.2   root       58:                fputc(map_0_31[value], stdout);
1.1       root       59:        } else if (value > 127) {
1.1.1.2   root       60:                fputc(map_128_255[value-128], stdout);
1.1       root       61:        } else {
1.1.1.2   root       62:                fputc(value, stdout);
1.1       root       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 */
1.1.1.2   root       93:                                fputs("\n", stdout);
1.1       root       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) {
1.1.1.2   root      118:                                fprintf(stdout, "%*s", hpos_tos - hpos_host, "");
1.1       root      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:                }
1.1.1.2   root      154:                fputs("\n", stdout);
1.1       root      155:                if (hpos_tos > 0 && hpos_tos < 80) {
1.1.1.2   root      156:                        fprintf(stdout, "%*s", hpos_tos, "");
1.1       root      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:        }
1.1.1.3 ! root      253:        fflush(stdout);
1.1       root      254: }

unix.superglobalmegacorp.com

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