Skip to content

Commit 4fc7b2d

Browse files
committed
[atari] Buffer line on minimal getchar
The Atari OS expects that IOCB screen editor inputs are line-atomic; it corrupts the cursor if writes happen in the meantime. It's generally expected in C that one can interleave getchar and putchar, and that putchars only take effect after a line is entered. Accordingly, this change line-buffers the minimal getchar for Atari targets. Fixes #378
1 parent 80d3c4b commit 4fc7b2d

File tree

1 file changed

+33
-6
lines changed

1 file changed

+33
-6
lines changed

mos-platform/atari8-common/getchar.c

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <atari.h>
2+
#include <stdbool.h>
23
#include <stdio.h>
34

45
__attribute__((always_inline, weak)) int __to_ascii(void *ctx,
@@ -18,12 +19,38 @@ __attribute__((always_inline, weak)) int __to_ascii(void *ctx,
1819
}
1920
}
2021

21-
int __getchar() {
22-
OS.iocb[0].command = IOCB_GETCHR;
23-
OS.iocb[0].buflen = 0;
22+
// The Atari OS screen editor expects that screen editor reads are atomic with
23+
// line granularity. Corruption results if characters are output while a read is
24+
// in progress. Since this is unusual on other C targets (it's usually fine to
25+
// interleave getchar and putchar), getchar is line buffered, even in the
26+
// minimal stdio here.
27+
28+
// Provide space for a full logical line (3 screen lines and a newline).
29+
static char buf[40 * 3 + 1];
30+
// Index of next character to be read.
31+
static char buf_idx;
32+
// Length of the filled region of the buffer.
33+
static char buf_len;
34+
35+
// Fill the input buffer and return true on error.
36+
static bool fill_buf(void) {
37+
buf_idx = 0;
38+
buf_len = 0;
39+
OS.iocb[0].command = IOCB_GETREC;
40+
OS.iocb[0].buffer = buf;
41+
OS.iocb[0].buflen = sizeof(buf) - 1;
2442
const unsigned char channel = 0;
25-
unsigned char c;
2643
unsigned char status;
27-
asm volatile("jsr $e456\n" : "=a"(c), "=y"(status) : "x"(channel) : "p");
28-
return status < 0x80 ? c : EOF;
44+
asm volatile("jsr $e456\n" : "=y"(status) : "x"(channel) : "p");
45+
if (status >= 0x80)
46+
return EOF;
47+
buf_len = OS.iocb[0].buflen;
48+
return status >= 0x80;
49+
}
50+
51+
int __getchar() {
52+
if (buf_idx == buf_len)
53+
if (fill_buf())
54+
return EOF;
55+
return buf[buf_idx++];
2956
}

0 commit comments

Comments
 (0)