summaryrefslogtreecommitdiff
path: root/src/main/c
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-08-10 11:11:18 -0700
committerCliff Click <cliffc@acm.org>2026-11-08 14:10:02 -0800
commit44505aa5b75b1046f13f2bc2a52fe0b16d975838 (patch)
treecc558485c807ac3842cd73943cf5e294c4a307de /src/main/c
parent2560096fb4636263798ae56c88687973c72cdf6e (diff)
downloadSimple-linear-chapter30.tar.gz
Simple-linear-chapter30.zip
Chapter 30: Text Formatting and Diagnosticslinear-chapter30
Co-authored-by: Hsiang-Ying Fu <66062782+fuhsnn@users.noreply.github.com> Co-authored-by: fuhsnn <66062782+fuhsnn@users.noreply.github.com> Co-authored-by: Symious <14933944+symious@users.noreply.github.com> Co-authored-by: Jun Kawasaki <jun784@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/main/c')
-rw-r--r--src/main/c/simple_crt.c124
1 files changed, 86 insertions, 38 deletions
diff --git a/src/main/c/simple_crt.c b/src/main/c/simple_crt.c
index 8656a3cc..438ae5f9 100644
--- a/src/main/c/simple_crt.c
+++ b/src/main/c/simple_crt.c
@@ -1,58 +1,106 @@
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
// errno may be thread-local or a macro calling a platform accessor.
int32_t simple_errno(void) { return errno; }
+int32_t simple_set_errno(int32_t error) { errno = error; return -1; }
+// Export platform errno constants; the buffering and retry loops are Simple.
+// C identifiers avoid the macros; linker names match the Simple bindings.
+int32_t simple_EINTR __asm__("EINTR") = EINTR;
+int32_t simple_EIO __asm__("EIO") = EIO;
+int32_t simple_EINVAL __asm__("EINVAL") = EINVAL;
+int32_t simple_EOVERFLOW __asm__("EOVERFLOW") = EOVERFLOW;
-// Native process arguments converted to ordinary Simple array layouts.
-// The outer array is mutable; every contained byte array is published as
-// immutable and non-null to Simple code.
+// Read one stdin byte, without terminal line editing or echo. POSIX terminals
+// include Cygwin consoles; redirected files/pipes need no mode change.
+// Return 0..255, or -1 with errno set to EOF or an OS error. Control characters,
+// including Ctrl-C, are returned as bytes so the mode is restored first.
+int32_t simple_getch(void) {
+ struct termios saved, mode;
+ int terminal = tcgetattr(STDIN_FILENO, &saved) == 0;
+ if (!terminal && errno != ENOTTY)
+ return -1;
+ if (terminal) {
+ mode = saved;
+ mode.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG | IEXTEN);
+ mode.c_iflag &= ~IXON;
+ mode.c_cc[VMIN] = 1;
+ mode.c_cc[VTIME] = 0;
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &mode) != 0)
+ return -1;
+ }
+ unsigned char byte;
+ ssize_t count = read(STDIN_FILENO, &byte, 1);
+ int read_errno = errno;
+ if (terminal) {
+ int restored;
+ do {
+ restored = tcsetattr(STDIN_FILENO, TCSANOW, &saved);
+ } while (restored != 0 && errno == EINTR);
+ if (restored != 0)
+ return -1;
+ }
+ if (count < 0) {
+ errno = read_errno;
+ return -1;
+ }
+ if (count == 0) {
+ errno = EOF;
+ return -1;
+ }
+ return byte;
+}
+
+// Simple byte-array layout, used only by the floating-point formatter.
typedef struct SimpleBytes {
uint32_t len;
unsigned char bytes[];
} SimpleBytes;
-typedef struct SimpleArgs {
- uint32_t len;
- uint32_t pad;
- SimpleBytes *args[];
-} SimpleArgs;
+// Binary floating-point conversion is the only native formatting primitive.
+// Buffering, integer conversion, string precision and padding live in sys.text.
+SimpleBytes *simple_text_float(double value, int64_t spec,
+ int64_t width, int64_t precision) {
+ char kind = spec & 255;
+ if (!kind) { kind = 'g'; precision = 17; }
+ if (!strchr("fFeEgGaA", kind) || (spec & ~8191LL) ||
+ width < 0 || width > INT32_MAX || precision < -1 || precision > INT32_MAX)
+ abort();
+ char fmt[64], *p = fmt;
+ *p++ = '%';
+ const char *flags = "-+ #0";
+ for (int i=0; i<5; i++) if (spec & (256LL<<i)) *p++ = flags[i];
+ if (width) p += sprintf(p, "%d", (int)width);
+ if (precision >= 0) p += sprintf(p, ".%d", (int)precision);
+ *p++ = kind;
+ *p = 0;
+ int len = snprintf(NULL, 0, fmt, value);
+ if (len < 0) abort();
+ SimpleBytes *str = malloc(sizeof(*str) + (size_t)len + 1);
+ if (!str) abort();
+ str->len = (uint32_t)len;
+ snprintf((char *)str->bytes, (size_t)len + 1, fmt, value);
+ return str;
+}
+// Simple does not yet dereference raw native pointers. Keep just the argv
+// element access here; allocation and array construction live in sys/rt/simple_args.smp.
+const char *simple_argv(char **argv, int64_t index) {
+ return argv[index];
+}
__attribute__((CALL_CONV))
-extern int64_t simple_main(SimpleArgs *args);
-
-static SimpleArgs *simple_args(int argc, char **argv) {
- if (argc < 0 || (uint64_t)argc > UINT32_MAX)
- return NULL;
-
- SimpleArgs *args = calloc(1, sizeof(*args) + (size_t)argc * sizeof(args->args[0]));
- if (args == NULL)
- return NULL;
- args->len = (uint32_t)argc;
-
- for (int i = 0; i < argc; i++) {
- size_t len = strlen(argv[i]);
- if (len > UINT32_MAX) {
- free(args);
- return NULL;
- }
- SimpleBytes *str = malloc(sizeof(*str) + len);
- if (str == NULL) {
- for (int j = 0; j < i; j++) free(args->args[j]);
- free(args);
- return NULL;
- }
- str->len = (uint32_t)len;
- memcpy(str->bytes, argv[i], len);
- args->args[i] = str;
- }
- return args;
-}
+extern void *simple_args(int64_t argc, char **argv);
+__attribute__((CALL_CONV))
+extern int64_t simple_main(void *args);
int main(int argc, char **argv) {
- SimpleArgs *args = simple_args(argc, argv);
+ // simple_args fills every slot before publishing this as u8[~][].
+ void *args = simple_args(argc, argv);
if (args == NULL)
return 1;
// The language-level hidden receiver is not part of the emitted ABI for