From 749e5aaf4047fe9b4431a4b336e4f2c82473b603 Mon Sep 17 00:00:00 2001 From: d_m Date: Fri, 10 Nov 2023 12:04:46 -0500 Subject: [PATCH] Some updates --- README.md | 7 + process.patch | 349 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 356 insertions(+) create mode 100644 process.patch diff --git a/README.md b/README.md index 0d9b9d9..7dabca0 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,10 @@ or alternately: gcc term.c -c term ./term term.rom ``` + +## files + +* `term.py` - bootstrapping program for running `term.rom` via python +* `term.c` - bootstrapping program from running `term.rom` via c +* `process.patch` - experimental patch adding *nix subprocess management to the console device +* `determ.terminfo` - wip terminfo definition for determ diff --git a/process.patch b/process.patch new file mode 100644 index 0000000..cc5164e --- /dev/null +++ b/process.patch @@ -0,0 +1,349 @@ +diff --git a/build.sh b/build.sh +index ae2e905..740bf6f 100755 +--- a/build.sh ++++ b/build.sh +@@ -60,6 +60,8 @@ then + clang-format -i src/devices/controller.c + clang-format -i src/devices/datetime.h + clang-format -i src/devices/datetime.c ++ clang-format -i src/devices/console.h ++ clang-format -i src/devices/console.c + clang-format -i src/uxnasm.c + clang-format -i src/uxnemu.c + clang-format -i src/uxncli.c +@@ -83,7 +85,7 @@ Darwin) # macOS + UXNEMU_LDFLAGS="$(brew --prefix)/lib/libSDL2.a $(sdl2-config --cflags --static-libs | sed -e 's/-lSDL2 //')" + ;; + Linux|*) +- UXNEMU_LDFLAGS="-L/usr/local/lib $(sdl2-config --cflags --libs)" ++ UXNEMU_LDFLAGS="-L/usr/local/lib $(sdl2-config --cflags --libs) -lutil" + ;; + esac + +@@ -99,7 +101,7 @@ fi + + echo "Building.." + ${CC} ${CFLAGS} src/uxnasm.c -o bin/uxnasm +-${CC} ${CFLAGS} ${CORE} src/devices/system.c src/devices/file.c src/devices/datetime.c src/devices/mouse.c src/devices/controller.c src/devices/screen.c src/devices/audio.c src/uxnemu.c ${UXNEMU_LDFLAGS} ${FILE_LDFLAGS} -o bin/uxnemu ++${CC} ${CFLAGS} ${CORE} src/devices/system.c src/devices/file.c src/devices/datetime.c src/devices/mouse.c src/devices/controller.c src/devices/screen.c src/devices/audio.c src/devices/console.c src/uxnemu.c ${UXNEMU_LDFLAGS} ${FILE_LDFLAGS} -o bin/uxnemu + ${CC} ${CFLAGS} ${CORE} src/devices/system.c src/devices/file.c src/devices/datetime.c src/uxncli.c ${FILE_LDFLAGS} -o bin/uxncli + + if [ $install = 1 ] +diff --git a/src/devices/console.c b/src/devices/console.c +new file mode 100644 +index 0000000..eda58ea +--- /dev/null ++++ b/src/devices/console.c +@@ -0,0 +1,212 @@ ++/* ++Copyright (c) 2023 d_m ++ ++Permission to use, copy, modify, and distribute this software for any ++purpose with or without fee is hereby granted, provided that the above ++copyright notice and this permission notice appear in all copies. ++ ++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++WITH REGARD TO THIS SOFTWARE. ++*/ ++ ++#undef _POSIX_C_SOURCE ++#define _POSIX_C_SOURCE 200112L ++ ++#include "../uxn.h" ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* process */ ++static char *fork_args[32]; ++static pid_t child_pid; ++static int child_mode; ++static int pty_fd; ++static int to_child_fd[2]; ++static int from_child_fd[2]; ++static int saved_in; ++static int saved_out; ++ ++static void ++parse_args(Uint8 *d, Uxn *u) ++{ ++ int addr = (d[0x3] << 8) | d[0x4]; ++ char *pos = (char *)&u->ram[addr]; ++ int i = 0; ++ do { ++ fork_args[i++] = pos; ++ while (*pos != 0) pos++; ++ pos++; ++ } while (*pos != '\0'); ++ fork_args[i] = NULL; ++} ++ ++/* call after we're sure the process has exited */ ++static void ++clean_after_child() ++{ ++ child_pid = 0; ++ if (child_mode >= 0x80) { ++ close(pty_fd); ++ dup2(saved_in, 0); ++ dup2(saved_out, 1); ++ } else { ++ if (child_mode & 0x01) { ++ close(to_child_fd[1]); ++ dup2(saved_out, 1); ++ } ++ if (child_mode & 0x06) { ++ close(from_child_fd[0]); ++ dup2(saved_in, 0); ++ } ++ } ++ child_mode = 0; ++ saved_in = -1; ++ saved_out = -1; ++} ++ ++static void ++kill_child(Uint8 *d) ++{ ++ if (child_pid) { ++ kill(child_pid, 9); ++ int wstatus; ++ if (waitpid(child_pid, &wstatus, 0)) { ++ d[0x6] = 1; ++ d[0x7] = WEXITSTATUS(wstatus); ++ clean_after_child(); ++ } ++ } ++} ++ ++static void ++start_fork_pty(Uint8 *d, Uxn *u) ++{ ++ int fd = -1; ++ pid_t pid = forkpty(&fd, NULL, NULL, NULL); ++ if (pid < 0) { /* failure */ ++ d[0x6] = 0xff; ++ fprintf(stderr, "fork failure"); ++ } else if (pid == 0) { /* child */ ++ setenv("TERM", "ansi", 1); ++ execvp(fork_args[0], fork_args); ++ d[0x6] = 0xff; ++ fprintf(stderr, "exec failure"); ++ } else { /*parent*/ ++ child_pid = pid; ++ pty_fd = fd; ++ struct winsize ws = {24, 80, 8, 12}; ++ ioctl(fd, TIOCSWINSZ, &ws); ++ saved_in = dup(0); ++ saved_out = dup(1); ++ dup2(fd, 0); ++ dup2(fd, 1); ++ } ++} ++ ++static void ++start_fork_pipe(Uint8 *d, Uxn *u) ++{ ++ if (child_mode & 0x01) { ++ /* parent writes to child's stdin */ ++ if (pipe(to_child_fd) == -1) { ++ d[0x6] = 0xff; ++ fprintf(stderr, "pipe error: to child"); ++ return; ++ } ++ } ++ ++ if (child_mode & 0x06) { ++ /* parent reads from child's stdout and/or stderr */ ++ if (pipe(from_child_fd) == -1) { ++ d[0x6] = 0xff; ++ fprintf(stderr, "pipe error: to child"); ++ return; ++ } ++ } ++ ++ pid_t pid = fork(); ++ if (pid < 0) { /* failure */ ++ d[0x6] = 0xff; ++ fprintf(stderr, "fork failure"); ++ } else if (pid == 0) { /* child */ ++ if (child_mode & 0x01) { ++ dup2(to_child_fd[0], 0); ++ close(to_child_fd[1]); ++ } ++ if (child_mode & 0x06) { ++ if (child_mode & 0x02) dup2(from_child_fd[1], 1); ++ if (child_mode & 0x04) dup2(from_child_fd[1], 2); ++ close(from_child_fd[0]); ++ } ++ execvp(fork_args[0], fork_args); ++ d[0x6] = 0xff; ++ fprintf(stderr, "exec failure"); ++ } else { /*parent*/ ++ child_pid = pid; ++ if (child_mode & 0x01) { ++ saved_out = dup(1); ++ dup2(to_child_fd[1], 1); ++ close(to_child_fd[0]); ++ } ++ if (child_mode & 0x06) { ++ saved_in = dup(0); ++ dup2(from_child_fd[0], 0); ++ close(from_child_fd[1]); ++ } ++ } ++} ++ ++static void ++start_fork(Uint8 *d, Uxn *u) ++{ ++ kill_child(d); ++ child_mode = d[0x5]; ++ parse_args(d, u); ++ if (child_mode >= 0x80) { ++ start_fork_pty(d, u); ++ } else { ++ start_fork_pipe(d, u); ++ } ++} ++ ++Uint8 ++console_dei(Uint8 *d, Uint8 port) ++{ ++ switch(port) { ++ case 0x6: ++ case 0x7: ++ if (child_pid) { ++ int wstatus; ++ if (waitpid(child_pid, &wstatus, WNOHANG)) { ++ d[0x6] = 1; ++ d[0x7] = WEXITSTATUS(wstatus); ++ clean_after_child(); ++ } ++ } ++ } ++ return d[port]; ++} ++ ++void ++console_deo(Uint8 *d, Uint8 port, Uxn *u) ++{ ++ FILE *fd = NULL; ++ switch(port) { ++ case 0x5: start_fork(d, u); break; ++ case 0x6: kill_child(d); break; ++ case 0x8: fd = stdout; break; ++ case 0x9: fd = stderr; break; ++ } ++ ++ if(fd) { ++ fputc(d[port], fd); ++ fflush(fd); ++ } ++} +diff --git a/src/devices/console.h b/src/devices/console.h +new file mode 100644 +index 0000000..3eb8e19 +--- /dev/null ++++ b/src/devices/console.h +@@ -0,0 +1,13 @@ ++/* ++Copyright (c) 2023 d_m ++ ++Permission to use, copy, modify, and distribute this software for any ++purpose with or without fee is hereby granted, provided that the above ++copyright notice and this permission notice appear in all copies. ++ ++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++WITH REGARD TO THIS SOFTWARE. ++*/ ++ ++Uint8 console_dei(Uint8 *d, Uint8 port); ++void console_deo(Uint8 *d, Uint8 port, Uxn *u); +diff --git a/src/uxnemu.c b/src/uxnemu.c +index 39c4300..7291d76 100644 +--- a/src/uxnemu.c ++++ b/src/uxnemu.c +@@ -16,12 +16,15 @@ + #include "devices/controller.h" + #include "devices/mouse.h" + #include "devices/datetime.h" ++#include "devices/console.h" + #ifdef _WIN32 + #include + #endif + #pragma GCC diagnostic pop + #pragma clang diagnostic pop + ++#include ++ + /* + Copyright (c) 2021-2023 Devine Lu Linvega, Andrew Alderwick + +@@ -70,17 +73,6 @@ console_input(Uxn *u, char c) + return uxn_eval(u, GETVEC(d)); + } + +-static void +-console_deo(Uint8 *d, Uint8 port) +-{ +- FILE *fd = port == 0x8 ? stdout : port == 0x9 ? stderr +- : 0; +- if(fd) { +- fputc(d[port], fd); +- fflush(fd); +- } +-} +- + static Uint8 + audio_dei(int instance, Uint8 *d, Uint8 port) + { +@@ -109,6 +101,7 @@ emu_dei(Uxn *u, Uint8 addr) + { + Uint8 p = addr & 0x0f, d = addr & 0xf0; + switch(d) { ++ case 0x10: return console_dei(&u->dev[d], p); + case 0x20: return screen_dei(&u->dev[d], p); + case 0x30: return audio_dei(0, &u->dev[d], p); + case 0x40: return audio_dei(1, &u->dev[d], p); +@@ -133,7 +126,7 @@ emu_deo(Uxn *u, Uint8 addr, Uint8 v) + if(p > 0x7 && p < 0xe) + screen_palette(&uxn_screen, &u->dev[0x8]); + break; +- case 0x10: console_deo(&u->dev[d], p); break; ++ case 0x10: console_deo(&u->dev[d], p, u); break; + case 0x20: screen_deo(u->ram, &u->dev[d], p); break; + case 0x30: audio_deo(0, &u->dev[d], p, u); break; + case 0x40: audio_deo(1, &u->dev[d], p, u); break; +@@ -171,9 +164,23 @@ static int + stdin_handler(void *p) + { + SDL_Event event; ++ fd_set rds; ++ struct timeval tv; ++ int retval; ++ int ok = 1; + event.type = stdin_event; +- while(read(0, &event.cbutton.button, 1) > 0 && SDL_PushEvent(&event) >= 0) +- ; ++ while(ok) { ++ FD_ZERO(&rds); ++ FD_SET(0, &rds); /* read from stdin */ ++ tv.tv_sec = 0; ++ tv.tv_usec = 100000; /* wait 100ms */ ++ retval = select(1, &rds, NULL, NULL, &tv); ++ if (retval > 0) { ++ ok = read(0, &event.cbutton.button, 1) > 0 && SDL_PushEvent(&event) >= 0; ++ } else if (retval < 0) { ++ ok = 0; ++ } ++ } + return 0; + (void)p; + }