fix numerous bugs, add tty controls, etc
This commit is contained in:
parent
05cf2c6ef3
commit
8ddc1b7676
|
@ -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')
|
||||
- 0x02 - (getpid) unused
|
||||
- 0x03 - (kill) unused
|
||||
- 0x04 - (raw-tty) unused
|
||||
- 0x04 - (restore-tty) unused
|
||||
- 0x10 - (getenv) name string (e.g. "TERM")
|
||||
- 0x11 - (setenv) assignment string (e.g. "TERM=vt100")
|
||||
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
|
||||
- 0x02 - getpid: responds with child process pid (if any)
|
||||
- 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
|
||||
- 0x11 - setenv: reads an assignment (e.g. TERM=vt100), updates env
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux
|
||||
|
@ -32,27 +33,28 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|||
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_reads(mode) (mode & CONSOLE_CHILD_READS)
|
||||
#define child_writes(mode) (mode & CONSOLE_CHILD_WRITES)
|
||||
#define child_writes_out(mode) (mode & CONSOLE_MODE_OUT)
|
||||
#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
|
||||
handle_sigchld(int sig)
|
||||
{
|
||||
|
@ -61,13 +63,16 @@ handle_sigchld(int sig)
|
|||
while((pid = waitpid(-1, &wstatus, WNOHANG)) > 0) {
|
||||
UxnSubprocess *child = find_child_by_pid(pid);
|
||||
if (child != NULL) {
|
||||
/* set running to negative when exiting for clean up */
|
||||
child->running = WEXITSTATUS(wstatus) - 256;
|
||||
/* close relevant file descriptors */
|
||||
if(child_ptys(child->mode))
|
||||
close(child->pty);
|
||||
else {
|
||||
if(child_reads(child->mode)) close(child->fd_in);
|
||||
if(child_writes(child->mode)) close(child->fd_out);
|
||||
}
|
||||
/* reset fields to starting values */
|
||||
child->pid = child->mode = 0;
|
||||
child->fd_out = child->fd_in = child->pty = -1;
|
||||
return;
|
||||
|
@ -79,7 +84,7 @@ static void
|
|||
start_fork_pty(UxnSubprocess *child, int mode)
|
||||
{
|
||||
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);
|
||||
if(pid < 0) { /* failure */
|
||||
fprintf(stderr, "parent fork failure\n");
|
||||
|
@ -95,6 +100,7 @@ start_fork_pty(UxnSubprocess *child, int mode)
|
|||
child->fd_in = fd;
|
||||
child->fd_out = fd;
|
||||
} while (child->pid != pid);
|
||||
/* loop to avoid possible race with clean up */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,6 +126,7 @@ start_fork_pipe(UxnSubprocess *child, int mode)
|
|||
pid_t pid = fork();
|
||||
if(pid < 0) { /* failure */
|
||||
fprintf(stderr, "fork failure\n");
|
||||
return;
|
||||
} else if(pid == 0) { /* child */
|
||||
if(child_reads(mode)) {
|
||||
dup2(to_child_fd[0], 0);
|
||||
|
@ -142,6 +149,9 @@ start_fork_pipe(UxnSubprocess *child, int mode)
|
|||
child->fd_in = child_reads(mode) ? to_child_fd[1] : -1;
|
||||
child->fd_out = child_writes(mode) ? from_child_fd[0] : -1;
|
||||
} while (child->pid != pid);
|
||||
/* loop to avoid possible race with clean up */
|
||||
|
||||
/* close the unused end of pipes we opened */
|
||||
if(child_reads(mode)) close(to_child_fd[0]);
|
||||
if(child_writes(mode)) close(from_child_fd[1]);
|
||||
}
|
||||
|
@ -173,7 +183,7 @@ host_execute(Uxn *u, Uint8 *d)
|
|||
UxnSubprocess *child = &children[opts & 0x3];
|
||||
|
||||
fork_args[2] = cmd;
|
||||
if(child->pid)
|
||||
if(child->pid > 0)
|
||||
kill(child->pid, 9);
|
||||
|
||||
if(opts >= 0x80)
|
||||
|
@ -202,13 +212,42 @@ static void
|
|||
host_kill(Uxn *u, Uint8 *d)
|
||||
{
|
||||
int n = d[0xe] & 0x3;
|
||||
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
|
||||
host_getenv(Uxn *u, Uint8 *d)
|
||||
{
|
||||
int addr = PEEK2(d + 0x3);
|
||||
int addr = PEEK2(d + 0xc);
|
||||
char *name = (char *)&u->ram[addr];
|
||||
host_response(u, getenv(name));
|
||||
}
|
||||
|
@ -216,23 +255,29 @@ host_getenv(Uxn *u, Uint8 *d)
|
|||
static void
|
||||
host_setenv(Uxn *u, Uint8 *d)
|
||||
{
|
||||
int addr = PEEK2(d + 0x3);
|
||||
int addr = PEEK2(d + 0xc);
|
||||
char *name = (char *)&u->ram[addr];
|
||||
int i = 0;
|
||||
while (name[i] != '=') i++;
|
||||
while(name[i] != '=') i++;
|
||||
if(name[i] == '=') {
|
||||
name[i] = '\0';
|
||||
char *value = &name[i+1];
|
||||
setenv(name, value, 1);
|
||||
} else {
|
||||
fprintf(stderr, "mal-formed setenv\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
host_put(Uxn *u, Uint8 *d)
|
||||
{
|
||||
switch(d[0xf]) {
|
||||
case 0x0: /* nop */ break;
|
||||
case 0x1: host_execute(u, d); break;
|
||||
case 0x2: host_getpid(u, d); break;
|
||||
case 0x3: host_kill(u, d); break;
|
||||
case 0x00: /* nop */ break;
|
||||
case 0x01: host_execute(u, d); break;
|
||||
case 0x02: host_getpid(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 0x11: host_setenv(u, d); break;
|
||||
}
|
||||
|
@ -266,7 +311,7 @@ UxnSubprocess
|
|||
void
|
||||
console_monitor(Uxn *u)
|
||||
{
|
||||
fflush(stdout);
|
||||
/*fflush(stdout);*/ /* TODO: needed? stderr? children? */
|
||||
for(int n = 0; n < CONSOLE_MAX_CHILDREN; n++) {
|
||||
UxnSubprocess *child = &children[n];
|
||||
if(child->running < 0) {
|
||||
|
@ -277,7 +322,6 @@ console_monitor(Uxn *u)
|
|||
}
|
||||
}
|
||||
|
||||
// TODO ignore port
|
||||
int
|
||||
console_input(Uxn *u, char c, int type)
|
||||
{
|
||||
|
|
|
@ -47,8 +47,11 @@ void console_deo(Uxn *u, Uint8 *d, Uint8 port);
|
|||
#define CONSOLE_MODE_OUT 0x20
|
||||
#define CONSOLE_MODE_INP 0x10
|
||||
|
||||
#define CONSOLE_CHILD_READS 0x90 /* CONSOLE_MODE_PTY | CONSOLE_MODE_INP */
|
||||
#define CONSOLE_CHILD_WRITES 0xe0 /* CONSOLE_MODE_PTY | CONSOLE_MODE_OUT | CONSOLE_MODE_ERR */
|
||||
/* CONSOLE_MODE_PTY | CONSOLE_MODE_INP */
|
||||
#define CONSOLE_CHILD_READS 0x90
|
||||
|
||||
/* CONSOLE_MODE_PTY | CONSOLE_MODE_OUT | CONSOLE_MODE_ERR */
|
||||
#define CONSOLE_CHILD_WRITES 0xe0
|
||||
|
||||
#define CONSOLE_MAX_CHILDREN 4
|
||||
|
||||
|
|
11
src/uxn11.c
11
src/uxn11.c
|
@ -268,17 +268,14 @@ emu_run(Uxn *u, char *rom)
|
|||
timerfd_settime(fds[1].fd, 0, &screen_tspec, NULL);
|
||||
fds[2].fd = STDIN_FILENO;
|
||||
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 */
|
||||
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].events = POLLIN;
|
||||
}
|
||||
if(poll(fds, 7, 1000) <= 0)
|
||||
if(poll(fds, 3 + CONSOLE_MAX_CHILDREN, 1000) <= 0)
|
||||
continue;
|
||||
while(XPending(display))
|
||||
emu_event(u);
|
||||
|
@ -297,7 +294,7 @@ emu_run(Uxn *u, char *rom)
|
|||
handle_input(u, fds[2], coninp, CONSOLE_STDIN, CONSOLE_STDIN_END);
|
||||
|
||||
/* 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], coninp, CONSOLE_CHILD_DATA | i, CONSOLE_CHILD_END | i);
|
||||
|
||||
/* check to see if any children exited */
|
||||
|
|
|
@ -171,16 +171,12 @@
|
|||
#01 .Console/host-put DEO JMP2r
|
||||
|
||||
( restore the terminal to "normal" settings )
|
||||
@restore-terminal
|
||||
;stty-sane !run-cmd
|
||||
@restore-terminal ( -> )
|
||||
#05 .Console/host-put DEO JMP2r
|
||||
|
||||
( put the terminal in raw mode )
|
||||
@init-terminal ( -> )
|
||||
;stty-raw !run-cmd
|
||||
|
||||
( command strings to use )
|
||||
@stty-sane "stty 20 "sane 00
|
||||
@stty-raw "stty 20 "raw 20 "-echo 00
|
||||
#04 .Console/host-put DEO JMP2r
|
||||
|
||||
( import uxn regex library )
|
||||
~regex.tal
|
||||
|
@ -487,11 +483,7 @@
|
|||
( )
|
||||
( this definition is needed so the address can be used by JCN2. )
|
||||
@quit-now
|
||||
;finish-quit .Console/vector DEO2
|
||||
restore-terminal BRK
|
||||
|
||||
@finish-quit
|
||||
.Console/type DEI #81 NEQ ?{ #80 .System/halt DEO } BRK
|
||||
restore-terminal #010f DEO BRK
|
||||
|
||||
( label that calls BRK )
|
||||
( )
|
||||
|
|
|
@ -409,7 +409,6 @@
|
|||
|
||||
( send ESC [ $c )
|
||||
@arrow ( c^ -> )
|
||||
( .Console/w STH )
|
||||
.Console/proc-put STH
|
||||
#1b STHkr DEO LIT "[ STHkr DEO STHr DEO
|
||||
JMP2r
|
||||
|
@ -417,12 +416,10 @@
|
|||
@paste-from-buf ( size* -> )
|
||||
;paste-buf SWP2 OVR2 ADD2 SWP2 ( limit* start* )
|
||||
&loop ( limit* pos* )
|
||||
( LDAk .Console/w DEO INC2 ( limit* pos+1* ) )
|
||||
LDAk .Console/proc-put DEO INC2 ( limit* pos+1* )
|
||||
GTH2k ?&loop POP2 POP2 JMP2r
|
||||
|
||||
@bracket-paste ( c^ -> )
|
||||
( .Console/w STH )
|
||||
.Console/proc-put STH
|
||||
#1b STHkr DEO
|
||||
LIT "[ STHkr DEO
|
||||
|
@ -638,7 +635,6 @@
|
|||
.Controller/key DEI
|
||||
DUP #08 NEQ ?&done
|
||||
POP #7f ( send DEL instead of BS )
|
||||
( &done .Console/w DEO BRK )
|
||||
&done .Console/proc-put DEO BRK
|
||||
|
||||
@ctrl ( -> is-down? ) .Controller/button DEI #01 AND JMP2r
|
||||
|
@ -646,10 +642,8 @@
|
|||
|
||||
( alt-XYZ emits ESC and then emits XYZ )
|
||||
@on-alt-key ( -> BRK )
|
||||
( #1b .Console/w DEO )
|
||||
#1b .Console/proc-put DEO
|
||||
ctrl ?on-ctrl-key
|
||||
( .Controller/key DEI .Console/w DEO BRK )
|
||||
.Controller/key DEI .Console/proc-put DEO BRK
|
||||
|
||||
( control seqs: )
|
||||
|
@ -685,7 +679,6 @@
|
|||
&rs #1e !&done
|
||||
&us #1f !&done
|
||||
&c1 LIT "@ SUB
|
||||
( &done .Console/w DEO BRK )
|
||||
&done .Console/proc-put DEO BRK
|
||||
|
||||
@on-read-priv ( -> BRK )
|
||||
|
@ -911,15 +904,11 @@
|
|||
|
||||
@dsr ( n* -> )
|
||||
#0006 NEQ2 ?&done
|
||||
( #1b .Console/w DEO )
|
||||
#1b .Console/proc-put DEO
|
||||
( LIT "[ .Console/w DEO )
|
||||
LIT "[ .Console/proc-put DEO
|
||||
.cur-y LDZ2 INC2 emit-dec2
|
||||
( LIT "; .Console/w DEO )
|
||||
LIT "; .Console/proc-put DEO
|
||||
.cur-x LDZ2 INC2 emit-dec2
|
||||
( LIT "R .Console/w DEO )
|
||||
LIT "R .Console/proc-put DEO
|
||||
&done BRK
|
||||
|
||||
|
@ -1300,14 +1289,21 @@
|
|||
|
||||
( emit a signed short as a decimal )
|
||||
@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 )
|
||||
|
||||
( emit an unsigned short as a decimal )
|
||||
@emit-dec2 ( n* -> )
|
||||
LITr ff00 &read #000a DIV2k STH2k MUL2 SUB2 STH2r INCr ORAk ?&read
|
||||
POP2 &write NIP #30 ADD #18 DEO OVRr ADDr STHkr ?&write
|
||||
POP2r JMP2r
|
||||
LIT2r ff00 ( n* [ff^ 0^] )
|
||||
&read ( ... x* )
|
||||
#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
|
||||
@scratch $40 &pos $2
|
||||
|
|
Loading…
Reference in New Issue