Compare commits
2 Commits
214d504311
...
8ddc1b7676
Author | SHA1 | Date |
---|---|---|
~d6 | 8ddc1b7676 | |
~d6 | 05cf2c6ef3 |
|
@ -63,6 +63,8 @@ for a host-put (0x1f). the meaning values by host-put value:
|
||||||
- 0x01 - (execute) command string (e.g. 'gcc -o "demo" demo.c')
|
- 0x01 - (execute) command string (e.g. 'gcc -o "demo" demo.c')
|
||||||
- 0x02 - (getpid) unused
|
- 0x02 - (getpid) unused
|
||||||
- 0x03 - (kill) unused
|
- 0x03 - (kill) unused
|
||||||
|
- 0x04 - (raw-tty) unused
|
||||||
|
- 0x04 - (restore-tty) unused
|
||||||
- 0x10 - (getenv) name string (e.g. "TERM")
|
- 0x10 - (getenv) name string (e.g. "TERM")
|
||||||
- 0x11 - (setenv) assignment string (e.g. "TERM=vt100")
|
- 0x11 - (setenv) assignment string (e.g. "TERM=vt100")
|
||||||
strings must be null-terminated. commands are parsed by /bin/sh -c.
|
strings must be null-terminated. commands are parsed by /bin/sh -c.
|
||||||
|
@ -86,6 +88,8 @@ the host-put port (0x1f) specifies which host action to take:
|
||||||
- 0x01 - execute: reads command string, starts a subprocess
|
- 0x01 - execute: reads command string, starts a subprocess
|
||||||
- 0x02 - getpid: responds with child process pid (if any)
|
- 0x02 - getpid: responds with child process pid (if any)
|
||||||
- 0x03 - kill: shuts down child process
|
- 0x03 - kill: shuts down child process
|
||||||
|
- 0x04 - put stdin tty into raw mode
|
||||||
|
- 0x05 - restore stdin tty to canonical mode
|
||||||
- 0x10 - getenv: looks up a name (e.g. TERM) in env, responds with value
|
- 0x10 - getenv: looks up a name (e.g. TERM) in env, responds with value
|
||||||
- 0x11 - setenv: reads an assignment (e.g. TERM=vt100), updates env
|
- 0x11 - setenv: reads an assignment (e.g. TERM=vt100), updates env
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifdef __linux
|
#ifdef __linux
|
||||||
|
@ -32,27 +33,28 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
WITH REGARD TO THIS SOFTWARE.
|
WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
UxnSubprocess children[CONSOLE_MAX_CHILDREN];
|
|
||||||
static char *fork_args[4] = {"/bin/sh", "-c", "", NULL};
|
|
||||||
static int to_child_fd[2], from_child_fd[2];
|
|
||||||
static char buf[16];
|
|
||||||
|
|
||||||
static UxnSubprocess*
|
|
||||||
find_child_by_pid(pid_t pid)
|
|
||||||
{
|
|
||||||
for(int n = 0; n < CONSOLE_MAX_CHILDREN; n++) {
|
|
||||||
if(children[n].pid == pid)
|
|
||||||
return &children[n];
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define child_ptys(mode) (mode & CONSOLE_MODE_PTY)
|
#define child_ptys(mode) (mode & CONSOLE_MODE_PTY)
|
||||||
#define child_reads(mode) (mode & CONSOLE_CHILD_READS)
|
#define child_reads(mode) (mode & CONSOLE_CHILD_READS)
|
||||||
#define child_writes(mode) (mode & CONSOLE_CHILD_WRITES)
|
#define child_writes(mode) (mode & CONSOLE_CHILD_WRITES)
|
||||||
#define child_writes_out(mode) (mode & CONSOLE_MODE_OUT)
|
#define child_writes_out(mode) (mode & CONSOLE_MODE_OUT)
|
||||||
#define child_writes_err(mode) (mode & CONSOLE_MODE_ERR)
|
#define child_writes_err(mode) (mode & CONSOLE_MODE_ERR)
|
||||||
|
|
||||||
|
UxnSubprocess children[CONSOLE_MAX_CHILDREN];
|
||||||
|
static char *fork_args[4] = {"/bin/sh", "-c", "", NULL};
|
||||||
|
static int to_child_fd[2], from_child_fd[2];
|
||||||
|
static char buf[16];
|
||||||
|
static int raw_tty = 0;
|
||||||
|
struct termios old_termios;
|
||||||
|
|
||||||
|
static UxnSubprocess*
|
||||||
|
find_child_by_pid(pid_t pid)
|
||||||
|
{
|
||||||
|
for(int n = 0; n < CONSOLE_MAX_CHILDREN; n++)
|
||||||
|
if(children[n].pid == pid)
|
||||||
|
return &children[n];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_sigchld(int sig)
|
handle_sigchld(int sig)
|
||||||
{
|
{
|
||||||
|
@ -61,29 +63,28 @@ handle_sigchld(int sig)
|
||||||
while((pid = waitpid(-1, &wstatus, WNOHANG)) > 0) {
|
while((pid = waitpid(-1, &wstatus, WNOHANG)) > 0) {
|
||||||
UxnSubprocess *child = find_child_by_pid(pid);
|
UxnSubprocess *child = find_child_by_pid(pid);
|
||||||
if (child != NULL) {
|
if (child != NULL) {
|
||||||
|
/* set running to negative when exiting for clean up */
|
||||||
child->running = WEXITSTATUS(wstatus) - 256;
|
child->running = WEXITSTATUS(wstatus) - 256;
|
||||||
if(CONSOLE_DEBUG)
|
/* close relevant file descriptors */
|
||||||
fprintf(stderr, "handle_sigchld: %d -> child %d (%d) -> %d\n", sig, child->id, pid, child->running);
|
|
||||||
if(child_ptys(child->mode))
|
if(child_ptys(child->mode))
|
||||||
close(child->pty);
|
close(child->pty);
|
||||||
else {
|
else {
|
||||||
if(child_reads(child->mode)) close(child->fd_in);
|
if(child_reads(child->mode)) close(child->fd_in);
|
||||||
if(child_writes(child->mode)) close(child->fd_out);
|
if(child_writes(child->mode)) close(child->fd_out);
|
||||||
}
|
}
|
||||||
|
/* reset fields to starting values */
|
||||||
child->pid = child->mode = 0;
|
child->pid = child->mode = 0;
|
||||||
child->fd_out = child->fd_in = child->pty = -1;
|
child->fd_out = child->fd_in = child->pty = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(CONSOLE_DEBUG)
|
|
||||||
fprintf(stderr, "handle_sigchld: no child found", sig);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
start_fork_pty(UxnSubprocess *child, int mode)
|
start_fork_pty(UxnSubprocess *child, int mode)
|
||||||
{
|
{
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
struct winsize ws = {23, 80, 8, 12}; // rows, cols, xps, ypx
|
struct winsize ws = {23, 80, 8, 12};
|
||||||
pid_t pid = forkpty(&fd, NULL, NULL, &ws);
|
pid_t pid = forkpty(&fd, NULL, NULL, &ws);
|
||||||
if(pid < 0) { /* failure */
|
if(pid < 0) { /* failure */
|
||||||
fprintf(stderr, "parent fork failure\n");
|
fprintf(stderr, "parent fork failure\n");
|
||||||
|
@ -99,13 +100,13 @@ start_fork_pty(UxnSubprocess *child, int mode)
|
||||||
child->fd_in = fd;
|
child->fd_in = fd;
|
||||||
child->fd_out = fd;
|
child->fd_out = fd;
|
||||||
} while (child->pid != pid);
|
} while (child->pid != pid);
|
||||||
|
/* loop to avoid possible race with clean up */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
start_fork_pipe(UxnSubprocess *child, int mode)
|
start_fork_pipe(UxnSubprocess *child, int mode)
|
||||||
{
|
{
|
||||||
//printf("start_fork_pipe(..., %d)\n", mode);
|
|
||||||
if(child_reads(mode)) {
|
if(child_reads(mode)) {
|
||||||
/* parent writes to child's stdin */
|
/* parent writes to child's stdin */
|
||||||
if(pipe(to_child_fd) == -1) {
|
if(pipe(to_child_fd) == -1) {
|
||||||
|
@ -125,6 +126,7 @@ start_fork_pipe(UxnSubprocess *child, int mode)
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if(pid < 0) { /* failure */
|
if(pid < 0) { /* failure */
|
||||||
fprintf(stderr, "fork failure\n");
|
fprintf(stderr, "fork failure\n");
|
||||||
|
return;
|
||||||
} else if(pid == 0) { /* child */
|
} else if(pid == 0) { /* child */
|
||||||
if(child_reads(mode)) {
|
if(child_reads(mode)) {
|
||||||
dup2(to_child_fd[0], 0);
|
dup2(to_child_fd[0], 0);
|
||||||
|
@ -147,19 +149,12 @@ start_fork_pipe(UxnSubprocess *child, int mode)
|
||||||
child->fd_in = child_reads(mode) ? to_child_fd[1] : -1;
|
child->fd_in = child_reads(mode) ? to_child_fd[1] : -1;
|
||||||
child->fd_out = child_writes(mode) ? from_child_fd[0] : -1;
|
child->fd_out = child_writes(mode) ? from_child_fd[0] : -1;
|
||||||
} while (child->pid != pid);
|
} while (child->pid != pid);
|
||||||
//printf("child %d: pid=%d mode=%d running=%d in=%d out=%d\n", child->id, child->pid, child->mode, child->running, child->fd_in, child->fd_out);
|
/* loop to avoid possible race with clean up */
|
||||||
if(CONSOLE_DEBUG)
|
|
||||||
fprintf(stderr, "child has pid %d\n", child->pid);
|
/* close the unused end of pipes we opened */
|
||||||
if(child_reads(mode)) close(to_child_fd[0]);
|
if(child_reads(mode)) close(to_child_fd[0]);
|
||||||
if(child_writes(mode)) close(from_child_fd[1]);
|
if(child_writes(mode)) close(from_child_fd[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* /\* TODO *\/ */
|
|
||||||
/* for(int n = 0; n < CONSOLE_MAX_CHILDREN; n++) { */
|
|
||||||
/* UxnSubprocess *child = &children[n]; */
|
|
||||||
/* printf("child: %d/%d (%d, %d)\n", n, child->id, child->fd_out, child->pid); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -174,8 +169,6 @@ proc_put(Uxn *u, Uint8 *d)
|
||||||
{
|
{
|
||||||
Uint8 c = d[0xa];
|
Uint8 c = d[0xa];
|
||||||
int n = d[0xe] & 0x3;
|
int n = d[0xe] & 0x3;
|
||||||
if (CONSOLE_DEBUG)
|
|
||||||
fprintf(stderr, " fd %d: write %02x\n", children[n].fd_in, c);
|
|
||||||
write(children[n].fd_in, &c, 1);
|
write(children[n].fd_in, &c, 1);
|
||||||
fdatasync(children[n].fd_in);
|
fdatasync(children[n].fd_in);
|
||||||
}
|
}
|
||||||
|
@ -190,13 +183,8 @@ host_execute(Uxn *u, Uint8 *d)
|
||||||
UxnSubprocess *child = &children[opts & 0x3];
|
UxnSubprocess *child = &children[opts & 0x3];
|
||||||
|
|
||||||
fork_args[2] = cmd;
|
fork_args[2] = cmd;
|
||||||
if(CONSOLE_DEBUG)
|
if(child->pid > 0)
|
||||||
fprintf(stderr, "running execute: %s (#%02x)\n", cmd, opts);
|
|
||||||
if(child->pid) {
|
|
||||||
if(CONSOLE_DEBUG)
|
|
||||||
fprintf(stderr, " killing previous child: %d\n", child->pid);
|
|
||||||
kill(child->pid, 9);
|
kill(child->pid, 9);
|
||||||
}
|
|
||||||
|
|
||||||
if(opts >= 0x80)
|
if(opts >= 0x80)
|
||||||
start_fork_pty(child, mode);
|
start_fork_pty(child, mode);
|
||||||
|
@ -208,8 +196,8 @@ static void
|
||||||
host_response(Uxn *u, char *s)
|
host_response(Uxn *u, char *s)
|
||||||
{
|
{
|
||||||
for(int i = 0;; i++)
|
for(int i = 0;; i++)
|
||||||
console_input(u, 0x5, s[i], CONSOLE_HOST);
|
console_input(u, s[i], CONSOLE_HOST);
|
||||||
console_input(u, 0x5, '\0', CONSOLE_HOST_END);
|
console_input(u, '\0', CONSOLE_HOST_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -224,13 +212,42 @@ static void
|
||||||
host_kill(Uxn *u, Uint8 *d)
|
host_kill(Uxn *u, Uint8 *d)
|
||||||
{
|
{
|
||||||
int n = d[0xe] & 0x3;
|
int n = d[0xe] & 0x3;
|
||||||
kill(children[n].pid, 15);
|
if(children[n].pid > 0)
|
||||||
|
kill(children[n].pid, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
host_raw_tty()
|
||||||
|
{
|
||||||
|
if(!raw_tty) {
|
||||||
|
tcgetattr(STDIN_FILENO, &old_termios);
|
||||||
|
struct termios term = old_termios;
|
||||||
|
/* corresponds to `stty raw -echo` */
|
||||||
|
term.c_cflag |= (CS8);
|
||||||
|
term.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP);
|
||||||
|
term.c_iflag &= ~(INLCR | IGNCR | ICRNL | IXON | IXOFF | IUCLC | IXANY | IMAXBEL);
|
||||||
|
term.c_lflag &= ~(ICANON | ISIG | ECHO);
|
||||||
|
term.c_oflag &= ~(OPOST);
|
||||||
|
term.c_cc[VMIN] = 0;
|
||||||
|
term.c_cc[VTIME] = 1;
|
||||||
|
tcsetattr(0, TCSAFLUSH, &term);
|
||||||
|
raw_tty = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
host_restore_tty()
|
||||||
|
{
|
||||||
|
if(raw_tty) {
|
||||||
|
tcsetattr(0, TCSAFLUSH, &old_termios);
|
||||||
|
raw_tty = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
host_getenv(Uxn *u, Uint8 *d)
|
host_getenv(Uxn *u, Uint8 *d)
|
||||||
{
|
{
|
||||||
int addr = PEEK2(d + 0x3);
|
int addr = PEEK2(d + 0xc);
|
||||||
char *name = (char *)&u->ram[addr];
|
char *name = (char *)&u->ram[addr];
|
||||||
host_response(u, getenv(name));
|
host_response(u, getenv(name));
|
||||||
}
|
}
|
||||||
|
@ -238,23 +255,29 @@ host_getenv(Uxn *u, Uint8 *d)
|
||||||
static void
|
static void
|
||||||
host_setenv(Uxn *u, Uint8 *d)
|
host_setenv(Uxn *u, Uint8 *d)
|
||||||
{
|
{
|
||||||
int addr = PEEK2(d + 0x3);
|
int addr = PEEK2(d + 0xc);
|
||||||
char *name = (char *)&u->ram[addr];
|
char *name = (char *)&u->ram[addr];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (name[i] != '=') i++;
|
while(name[i] != '=') i++;
|
||||||
name[i] = '\0';
|
if(name[i] == '=') {
|
||||||
char *value = &name[i+1];
|
name[i] = '\0';
|
||||||
setenv(name, value, 1);
|
char *value = &name[i+1];
|
||||||
|
setenv(name, value, 1);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "mal-formed setenv\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
host_put(Uxn *u, Uint8 *d)
|
host_put(Uxn *u, Uint8 *d)
|
||||||
{
|
{
|
||||||
switch(d[0xf]) {
|
switch(d[0xf]) {
|
||||||
case 0x0: /* nop */ break;
|
case 0x00: /* nop */ break;
|
||||||
case 0x1: host_execute(u, d); break;
|
case 0x01: host_execute(u, d); break;
|
||||||
case 0x2: host_getpid(u, d); break;
|
case 0x02: host_getpid(u, d); break;
|
||||||
case 0x3: host_kill(u, d); break;
|
case 0x03: host_kill(u, d); break;
|
||||||
|
case 0x04: host_raw_tty(); break;
|
||||||
|
case 0x05: host_restore_tty(); break;
|
||||||
case 0x10: host_getenv(u, d); break;
|
case 0x10: host_getenv(u, d); break;
|
||||||
case 0x11: host_setenv(u, d); break;
|
case 0x11: host_setenv(u, d); break;
|
||||||
}
|
}
|
||||||
|
@ -288,23 +311,19 @@ UxnSubprocess
|
||||||
void
|
void
|
||||||
console_monitor(Uxn *u)
|
console_monitor(Uxn *u)
|
||||||
{
|
{
|
||||||
fflush(stdout);
|
/*fflush(stdout);*/ /* TODO: needed? stderr? children? */
|
||||||
for(int n = 0; n < CONSOLE_MAX_CHILDREN; n++) {
|
for(int n = 0; n < CONSOLE_MAX_CHILDREN; n++) {
|
||||||
UxnSubprocess *child = &children[n];
|
UxnSubprocess *child = &children[n];
|
||||||
/* printf("child: %d/%d (%d, %d)\n", n, child->id, child->fd_out, child->pid); */
|
|
||||||
if(child->running < 0) {
|
if(child->running < 0) {
|
||||||
/* printf("child ready for clean up: %d\n", n); */
|
|
||||||
/* fflush(stdout); */
|
|
||||||
Uint8 status = child->running + 256;
|
Uint8 status = child->running + 256;
|
||||||
child->running = 0;
|
child->running = 0;
|
||||||
console_input(u, 0x4, status, CONSOLE_CHILD_EXIT | n);
|
console_input(u, status, CONSOLE_CHILD_EXIT | n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO ignore port
|
|
||||||
int
|
int
|
||||||
console_input(Uxn *u, int port, char c, int type)
|
console_input(Uxn *u, char c, int type)
|
||||||
{
|
{
|
||||||
Uint8 *d = &u->dev[0x10];
|
Uint8 *d = &u->dev[0x10];
|
||||||
d[0x2] = c;
|
d[0x2] = c;
|
||||||
|
@ -317,8 +336,8 @@ console_listen(Uxn *u, int i, int argc, char **argv)
|
||||||
{
|
{
|
||||||
for(; i < argc; i++) {
|
for(; i < argc; i++) {
|
||||||
char *p = argv[i];
|
char *p = argv[i];
|
||||||
while(*p) console_input(u, 0x2, *p++, CONSOLE_ARG);
|
while(*p) console_input(u, *p++, CONSOLE_ARG);
|
||||||
console_input(u, 0x2, '\n', i == argc - 1 ? CONSOLE_ARG_END : CONSOLE_ARG_SPACER);
|
console_input(u, '\n', i == argc - 1 ? CONSOLE_ARG_END : CONSOLE_ARG_SPACER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,6 @@ WITH REGARD TO THIS SOFTWARE.
|
||||||
|
|
||||||
#define CONSOLE_VERSION 1
|
#define CONSOLE_VERSION 1
|
||||||
|
|
||||||
#define CONSOLE_DEBUG 0
|
|
||||||
|
|
||||||
#define CONSOLE_NONE 0x00
|
#define CONSOLE_NONE 0x00
|
||||||
#define CONSOLE_STDIN 0x01
|
#define CONSOLE_STDIN 0x01
|
||||||
#define CONSOLE_ARG 0x02
|
#define CONSOLE_ARG 0x02
|
||||||
|
@ -27,19 +25,19 @@ WITH REGARD TO THIS SOFTWARE.
|
||||||
#define CONSOLE_CHILD_EXIT 0x80 /* exits from child-n: 0x80 | n */
|
#define CONSOLE_CHILD_EXIT 0x80 /* exits from child-n: 0x80 | n */
|
||||||
|
|
||||||
typedef struct UxnSubprocess {
|
typedef struct UxnSubprocess {
|
||||||
int id; /* identifier: 0-3 */
|
int id; /* identifier: 0-3 */
|
||||||
pid_t pid; /* when running, pid > 0 */
|
pid_t pid; /* when running, pid > 0 */
|
||||||
int mode; /* bit flags: CONSOLE_MODE_ */
|
int mode; /* bit flags: CONSOLE_MODE_ */
|
||||||
int running; /* 0=stopped, >0 running, <0 exiting */
|
int running; /* 0=stopped, >0 running, <0 exiting */
|
||||||
int fd_in; /* fd to send to child; -1 is unset */
|
int fd_in; /* fd to send to child; -1 is unset */
|
||||||
int fd_out; /* fd to read from child; -1 is unset */
|
int fd_out; /* fd to read from child; -1 is unset */
|
||||||
int pty; /* pty for child; -1 is unset */
|
int pty; /* pty for child; -1 is unset */
|
||||||
} UxnSubprocess;
|
} UxnSubprocess;
|
||||||
|
|
||||||
void init_console(void);
|
void init_console(void);
|
||||||
UxnSubprocess *get_child(int n);
|
UxnSubprocess *get_child(int n);
|
||||||
void console_monitor(Uxn *u);
|
void console_monitor(Uxn *u);
|
||||||
int console_input(Uxn *u, int port, char c, int type);
|
int console_input(Uxn *u, char c, int type);
|
||||||
void console_listen(Uxn *u, int i, int argc, char **argv);
|
void console_listen(Uxn *u, int i, int argc, char **argv);
|
||||||
Uint8 console_dei(Uxn *u, Uint8 addr);
|
Uint8 console_dei(Uxn *u, Uint8 addr);
|
||||||
void console_deo(Uxn *u, Uint8 *d, Uint8 port);
|
void console_deo(Uxn *u, Uint8 *d, Uint8 port);
|
||||||
|
@ -49,8 +47,11 @@ void console_deo(Uxn *u, Uint8 *d, Uint8 port);
|
||||||
#define CONSOLE_MODE_OUT 0x20
|
#define CONSOLE_MODE_OUT 0x20
|
||||||
#define CONSOLE_MODE_INP 0x10
|
#define CONSOLE_MODE_INP 0x10
|
||||||
|
|
||||||
#define CONSOLE_CHILD_READS 0x90 /* CONSOLE_MODE_PTY | CONSOLE_MODE_INP */
|
/* CONSOLE_MODE_PTY | CONSOLE_MODE_INP */
|
||||||
#define CONSOLE_CHILD_WRITES 0xe0 /* CONSOLE_MODE_PTY | CONSOLE_MODE_OUT | CONSOLE_MODE_ERR */
|
#define CONSOLE_CHILD_READS 0x90
|
||||||
|
|
||||||
|
/* CONSOLE_MODE_PTY | CONSOLE_MODE_OUT | CONSOLE_MODE_ERR */
|
||||||
|
#define CONSOLE_CHILD_WRITES 0xe0
|
||||||
|
|
||||||
#define CONSOLE_MAX_CHILDREN 4
|
#define CONSOLE_MAX_CHILDREN 4
|
||||||
|
|
||||||
|
|
21
src/uxn11.c
21
src/uxn11.c
|
@ -152,16 +152,16 @@ toggle_scale(Uxn *u)
|
||||||
|
|
||||||
/* returns true if the fd ended (has been closed), false otherwise */
|
/* returns true if the fd ended (has been closed), false otherwise */
|
||||||
static int
|
static int
|
||||||
handle_input(Uxn *u, struct pollfd pollfd, int port, char *coninp, int argdata, int argend)
|
handle_input(Uxn *u, struct pollfd pollfd, char *coninp, int argdata, int argend)
|
||||||
{
|
{
|
||||||
if((pollfd.revents & POLLIN) != 0) {
|
if((pollfd.revents & POLLIN) != 0) {
|
||||||
int n = read(pollfd.fd, coninp, CONINBUFSIZE - 1);
|
int n = read(pollfd.fd, coninp, CONINBUFSIZE - 1);
|
||||||
coninp[n] = 0;
|
coninp[n] = 0;
|
||||||
if(n == 0)
|
if(n == 0)
|
||||||
console_input(u, port, 0, argend);
|
console_input(u, 0, argend);
|
||||||
else
|
else
|
||||||
for(int i = 0; i < n; i++)
|
for(int i = 0; i < n; i++)
|
||||||
console_input(u, port, coninp[i], argdata);
|
console_input(u, coninp[i], argdata);
|
||||||
return n == 0;
|
return n == 0;
|
||||||
} else
|
} else
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -268,17 +268,14 @@ emu_run(Uxn *u, char *rom)
|
||||||
timerfd_settime(fds[1].fd, 0, &screen_tspec, NULL);
|
timerfd_settime(fds[1].fd, 0, &screen_tspec, NULL);
|
||||||
fds[2].fd = STDIN_FILENO;
|
fds[2].fd = STDIN_FILENO;
|
||||||
fds[0].events = fds[1].events = fds[2].events = POLLIN;
|
fds[0].events = fds[1].events = fds[2].events = POLLIN;
|
||||||
for(i = 0; i < 4; i++) {
|
|
||||||
fds[i + 3].fd = get_child(i)->fd_out;
|
|
||||||
fds[i + 3].events = POLLIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* main loop */
|
/* main loop */
|
||||||
while(!u->dev[0x0f]) {
|
while(!u->dev[0x0f]) {
|
||||||
for(i = 0; i < 4; i++) {
|
for(i = 0; i < CONSOLE_MAX_CHILDREN; i++) {
|
||||||
fds[i + 3].fd = get_child(i)->fd_out;
|
fds[i + 3].fd = get_child(i)->fd_out;
|
||||||
|
fds[i + 3].events = POLLIN;
|
||||||
}
|
}
|
||||||
if(poll(fds, 7, 1000) <= 0)
|
if(poll(fds, 3 + CONSOLE_MAX_CHILDREN, 1000) <= 0)
|
||||||
continue;
|
continue;
|
||||||
while(XPending(display))
|
while(XPending(display))
|
||||||
emu_event(u);
|
emu_event(u);
|
||||||
|
@ -294,11 +291,11 @@ emu_run(Uxn *u, char *rom)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read input from stdin */
|
/* read input from stdin */
|
||||||
handle_input(u, fds[2], 0x2, coninp, CONSOLE_STDIN, CONSOLE_STDIN_END);
|
handle_input(u, fds[2], coninp, CONSOLE_STDIN, CONSOLE_STDIN_END);
|
||||||
|
|
||||||
/* read input from child processes */
|
/* read input from child processes */
|
||||||
for(i = 0; i < 4; i++)
|
for(i = 0; i < CONSOLE_MAX_CHILDREN; i++)
|
||||||
handle_input(u, fds[i + 3], 0x4, coninp, CONSOLE_CHILD_DATA | i, CONSOLE_CHILD_END | i);
|
handle_input(u, fds[i + 3], coninp, CONSOLE_CHILD_DATA | i, CONSOLE_CHILD_END | i);
|
||||||
|
|
||||||
/* check to see if any children exited */
|
/* check to see if any children exited */
|
||||||
console_monitor(u);
|
console_monitor(u);
|
||||||
|
|
16
src/uxncli.c
16
src/uxncli.c
|
@ -50,17 +50,11 @@ handle_input(Uxn *u, int fd, int port, int argdata, int argend)
|
||||||
{
|
{
|
||||||
char buf[32];
|
char buf[32];
|
||||||
int n = read(fd, &buf, 32);
|
int n = read(fd, &buf, 32);
|
||||||
if(n == 0) {
|
if(n == 0)
|
||||||
if(CONSOLE_DEBUG)
|
console_input(u, 0x00, argend);
|
||||||
fprintf(stderr, " fd %d: closed\n", fd);
|
else
|
||||||
console_input(u, port, 0x00, argend);
|
for(int i = 0; i < n; i++)
|
||||||
} else {
|
console_input(u, buf[i], argdata);
|
||||||
for(int i = 0; i < n; i++) {
|
|
||||||
if(CONSOLE_DEBUG)
|
|
||||||
fprintf(stderr, " fd %d: read %02x\n", fd, buf[i]);
|
|
||||||
console_input(u, port, buf[i], argdata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -171,16 +171,12 @@
|
||||||
#01 .Console/host-put DEO JMP2r
|
#01 .Console/host-put DEO JMP2r
|
||||||
|
|
||||||
( restore the terminal to "normal" settings )
|
( restore the terminal to "normal" settings )
|
||||||
@restore-terminal
|
@restore-terminal ( -> )
|
||||||
;stty-sane !run-cmd
|
#05 .Console/host-put DEO JMP2r
|
||||||
|
|
||||||
( put the terminal in raw mode )
|
( put the terminal in raw mode )
|
||||||
@init-terminal ( -> )
|
@init-terminal ( -> )
|
||||||
;stty-raw !run-cmd
|
#04 .Console/host-put DEO JMP2r
|
||||||
|
|
||||||
( command strings to use )
|
|
||||||
@stty-sane "stty 20 "sane 00
|
|
||||||
@stty-raw "stty 20 "raw 20 "-echo 00
|
|
||||||
|
|
||||||
( import uxn regex library )
|
( import uxn regex library )
|
||||||
~regex.tal
|
~regex.tal
|
||||||
|
@ -487,11 +483,7 @@
|
||||||
( )
|
( )
|
||||||
( this definition is needed so the address can be used by JCN2. )
|
( this definition is needed so the address can be used by JCN2. )
|
||||||
@quit-now
|
@quit-now
|
||||||
;finish-quit .Console/vector DEO2
|
restore-terminal #010f DEO BRK
|
||||||
restore-terminal BRK
|
|
||||||
|
|
||||||
@finish-quit
|
|
||||||
.Console/type DEI #81 NEQ ?{ #80 .System/halt DEO } BRK
|
|
||||||
|
|
||||||
( label that calls BRK )
|
( label that calls BRK )
|
||||||
( )
|
( )
|
||||||
|
|
|
@ -409,7 +409,6 @@
|
||||||
|
|
||||||
( send ESC [ $c )
|
( send ESC [ $c )
|
||||||
@arrow ( c^ -> )
|
@arrow ( c^ -> )
|
||||||
( .Console/w STH )
|
|
||||||
.Console/proc-put STH
|
.Console/proc-put STH
|
||||||
#1b STHkr DEO LIT "[ STHkr DEO STHr DEO
|
#1b STHkr DEO LIT "[ STHkr DEO STHr DEO
|
||||||
JMP2r
|
JMP2r
|
||||||
|
@ -417,12 +416,10 @@
|
||||||
@paste-from-buf ( size* -> )
|
@paste-from-buf ( size* -> )
|
||||||
;paste-buf SWP2 OVR2 ADD2 SWP2 ( limit* start* )
|
;paste-buf SWP2 OVR2 ADD2 SWP2 ( limit* start* )
|
||||||
&loop ( limit* pos* )
|
&loop ( limit* pos* )
|
||||||
( LDAk .Console/w DEO INC2 ( limit* pos+1* ) )
|
|
||||||
LDAk .Console/proc-put DEO INC2 ( limit* pos+1* )
|
LDAk .Console/proc-put DEO INC2 ( limit* pos+1* )
|
||||||
GTH2k ?&loop POP2 POP2 JMP2r
|
GTH2k ?&loop POP2 POP2 JMP2r
|
||||||
|
|
||||||
@bracket-paste ( c^ -> )
|
@bracket-paste ( c^ -> )
|
||||||
( .Console/w STH )
|
|
||||||
.Console/proc-put STH
|
.Console/proc-put STH
|
||||||
#1b STHkr DEO
|
#1b STHkr DEO
|
||||||
LIT "[ STHkr DEO
|
LIT "[ STHkr DEO
|
||||||
|
@ -638,7 +635,6 @@
|
||||||
.Controller/key DEI
|
.Controller/key DEI
|
||||||
DUP #08 NEQ ?&done
|
DUP #08 NEQ ?&done
|
||||||
POP #7f ( send DEL instead of BS )
|
POP #7f ( send DEL instead of BS )
|
||||||
( &done .Console/w DEO BRK )
|
|
||||||
&done .Console/proc-put DEO BRK
|
&done .Console/proc-put DEO BRK
|
||||||
|
|
||||||
@ctrl ( -> is-down? ) .Controller/button DEI #01 AND JMP2r
|
@ctrl ( -> is-down? ) .Controller/button DEI #01 AND JMP2r
|
||||||
|
@ -646,10 +642,8 @@
|
||||||
|
|
||||||
( alt-XYZ emits ESC and then emits XYZ )
|
( alt-XYZ emits ESC and then emits XYZ )
|
||||||
@on-alt-key ( -> BRK )
|
@on-alt-key ( -> BRK )
|
||||||
( #1b .Console/w DEO )
|
|
||||||
#1b .Console/proc-put DEO
|
#1b .Console/proc-put DEO
|
||||||
ctrl ?on-ctrl-key
|
ctrl ?on-ctrl-key
|
||||||
( .Controller/key DEI .Console/w DEO BRK )
|
|
||||||
.Controller/key DEI .Console/proc-put DEO BRK
|
.Controller/key DEI .Console/proc-put DEO BRK
|
||||||
|
|
||||||
( control seqs: )
|
( control seqs: )
|
||||||
|
@ -685,7 +679,6 @@
|
||||||
&rs #1e !&done
|
&rs #1e !&done
|
||||||
&us #1f !&done
|
&us #1f !&done
|
||||||
&c1 LIT "@ SUB
|
&c1 LIT "@ SUB
|
||||||
( &done .Console/w DEO BRK )
|
|
||||||
&done .Console/proc-put DEO BRK
|
&done .Console/proc-put DEO BRK
|
||||||
|
|
||||||
@on-read-priv ( -> BRK )
|
@on-read-priv ( -> BRK )
|
||||||
|
@ -911,15 +904,11 @@
|
||||||
|
|
||||||
@dsr ( n* -> )
|
@dsr ( n* -> )
|
||||||
#0006 NEQ2 ?&done
|
#0006 NEQ2 ?&done
|
||||||
( #1b .Console/w DEO )
|
|
||||||
#1b .Console/proc-put DEO
|
#1b .Console/proc-put DEO
|
||||||
( LIT "[ .Console/w DEO )
|
|
||||||
LIT "[ .Console/proc-put DEO
|
LIT "[ .Console/proc-put DEO
|
||||||
.cur-y LDZ2 INC2 emit-dec2
|
.cur-y LDZ2 INC2 emit-dec2
|
||||||
( LIT "; .Console/w DEO )
|
|
||||||
LIT "; .Console/proc-put DEO
|
LIT "; .Console/proc-put DEO
|
||||||
.cur-x LDZ2 INC2 emit-dec2
|
.cur-x LDZ2 INC2 emit-dec2
|
||||||
( LIT "R .Console/w DEO )
|
|
||||||
LIT "R .Console/proc-put DEO
|
LIT "R .Console/proc-put DEO
|
||||||
&done BRK
|
&done BRK
|
||||||
|
|
||||||
|
@ -1300,14 +1289,21 @@
|
||||||
|
|
||||||
( emit a signed short as a decimal )
|
( emit a signed short as a decimal )
|
||||||
@emit-sdec2 ( n* -> )
|
@emit-sdec2 ( n* -> )
|
||||||
DUP2k #1f SFT2 EQUk ?&s LIT2 "- 18 DEO
|
DUP2k #1f SFT2 EQUk ?&s LIT "- .Console/proc-put DEO
|
||||||
&s MUL2 SUB2 ( fall-through to emit-dec2 )
|
&s MUL2 SUB2 ( fall-through to emit-dec2 )
|
||||||
|
|
||||||
( emit an unsigned short as a decimal )
|
( emit an unsigned short as a decimal )
|
||||||
@emit-dec2 ( n* -> )
|
@emit-dec2 ( n* -> )
|
||||||
LITr ff00 &read #000a DIV2k STH2k MUL2 SUB2 STH2r INCr ORAk ?&read
|
LIT2r ff00 ( n* [ff^ 0^] )
|
||||||
POP2 &write NIP #30 ADD #18 DEO OVRr ADDr STHkr ?&write
|
&read ( ... x* )
|
||||||
POP2r JMP2r
|
#000a DIV2k STH2k ( x* 10* x/10* [ff^ i^ x/10*] )
|
||||||
|
MUL2 SUB2 STH2r ( x%10* x/10* [ff^ i^] )
|
||||||
|
INCr ORAk ?&read ( x%10* x/10* [ff^ i+1^] )
|
||||||
|
POP2 ( x0* ... xn* [ff^ i+1^] )
|
||||||
|
&write
|
||||||
|
NIP #30 ADD .Console/proc-put DEO ( x0* ... xn-1* [ff^ j^] )
|
||||||
|
OVRr ADDr STHkr ?&write ( x* ... xn-1* [ff^ j-1^] )
|
||||||
|
POP2r JMP2r ( )
|
||||||
|
|
||||||
@debug-log "debug_term.log 00
|
@debug-log "debug_term.log 00
|
||||||
@scratch $40 &pos $2
|
@scratch $40 &pos $2
|
||||||
|
|
Loading…
Reference in New Issue