diff --git a/tools/emul/README.md b/tools/emul/README.md index f27efa4..cb664bf 100644 --- a/tools/emul/README.md +++ b/tools/emul/README.md @@ -25,6 +25,16 @@ We don't try to emulate real hardware to ease the development of device drivers because so far, I don't see the advantage of emulation versus running code on the real thing. +By default, the shell initialized itself with a CFS device containing the +contents of `cfsin/` at launch (it's packed on the fly). You can specify an +alternate CFS device file (it has to be packaed already) through the `-f` flag. + +By default, the shell runs interactively, but you can also pipe contents through +stdin instead. The contents will be interpreted exactly as if you had typed it +yourself and the result will be spit in stdout (it includes your typed in +contents because the Collapse OS console echoes back every character that is +sent to it.). This feature is useful for automated tests in `tools/tests/shell`. + ## zasm `zasm/zasm` is `apps/zasm` wrapped in an emulator. It is quite central to the diff --git a/tools/emul/shell/shell.c b/tools/emul/shell/shell.c index 2560414..4dc4717 100644 --- a/tools/emul/shell/shell.c +++ b/tools/emul/shell/shell.c @@ -1,5 +1,6 @@ #include #include +#include #include #include "../emul.h" #include "shell-bin.h" @@ -135,12 +136,36 @@ static void iowr_fsaddr(uint8_t val) } } -int main() +int main(int argc, char *argv[]) { + FILE *fp = NULL; + while (1) { + int c = getopt(argc, argv, "f:"); + if (c < 0) { + break; + } + switch (c) { + case 'f': + fp = fopen(optarg, "r"); + if (fp == NULL) { + fprintf(stderr, "Can't open %s\n", optarg); + return 1; + } + break; + default: + fprintf(stderr, "Usage: shell [-f fsdev]\n"); + return 1; + } + } // Setup fs blockdev - FILE *fp = popen("../cfspack/cfspack cfsin", "r"); + if (fp == NULL) { + fp = popen("../cfspack/cfspack cfsin", "r"); + if (fp == NULL) { + fprintf(stderr, "Can't initialize filesystem. Leaving blank.\n"); + } + } if (fp != NULL) { - printf("Initializing filesystem\n"); + fprintf(stderr, "Initializing filesystem\n"); int i = 0; int c = fgetc(fp); while (c != EOF) { @@ -150,19 +175,20 @@ int main() } fsdev_size = i; pclose(fp); - } else { - printf("Can't initialize filesystem. Leaving blank.\n"); } - // Turn echo off: the shell takes care of its own echoing. + bool tty = isatty(fileno(stdin)); struct termios termInfo; - if (tcgetattr(0, &termInfo) == -1) { - printf("Can't setup terminal.\n"); - return 1; + if (tty) { + // Turn echo off: the shell takes care of its own echoing. + if (tcgetattr(0, &termInfo) == -1) { + printf("Can't setup terminal.\n"); + return 1; + } + termInfo.c_lflag &= ~ECHO; + termInfo.c_lflag &= ~ICANON; + tcsetattr(0, TCSAFLUSH, &termInfo); } - termInfo.c_lflag &= ~ECHO; - termInfo.c_lflag &= ~ICANON; - tcsetattr(0, TCSAFLUSH, &termInfo); Machine *m = emul_init(); @@ -182,10 +208,12 @@ int main() while (running && emul_step()); - printf("Done!\n"); - termInfo.c_lflag |= ECHO; - termInfo.c_lflag |= ICANON; - tcsetattr(0, TCSAFLUSH, &termInfo); - emul_printdebug(); + if (tty) { + printf("Done!\n"); + termInfo.c_lflag |= ECHO; + termInfo.c_lflag |= ICANON; + tcsetattr(0, TCSAFLUSH, &termInfo); + emul_printdebug(); + } return 0; } diff --git a/tools/tests/Makefile b/tools/tests/Makefile index 70b8373..e44faa9 100644 --- a/tools/tests/Makefile +++ b/tools/tests/Makefile @@ -2,6 +2,7 @@ EMULDIR = ../emul .PHONY: run run: - $(MAKE) -C $(EMULDIR) zasm/zasm runbin/runbin + $(MAKE) -C $(EMULDIR) zasm/zasm runbin/runbin shell/shell cd unit && ./runtests.sh cd zasm && ./runtests.sh + cd shell && ./runtests.sh diff --git a/tools/tests/shell/.gitignore b/tools/tests/shell/.gitignore new file mode 100644 index 0000000..c58b0ca --- /dev/null +++ b/tools/tests/shell/.gitignore @@ -0,0 +1 @@ +/test.cfs diff --git a/tools/tests/shell/cfsin/bar b/tools/tests/shell/cfsin/bar new file mode 100644 index 0000000..839d375 --- /dev/null +++ b/tools/tests/shell/cfsin/bar @@ -0,0 +1 @@ +Hello Bar! diff --git a/tools/tests/shell/cfsin/foo b/tools/tests/shell/cfsin/foo new file mode 100644 index 0000000..953a6f4 --- /dev/null +++ b/tools/tests/shell/cfsin/foo @@ -0,0 +1 @@ +Hello Foo! diff --git a/tools/tests/shell/fls.expected b/tools/tests/shell/fls.expected new file mode 100644 index 0000000..ce602af --- /dev/null +++ b/tools/tests/shell/fls.expected @@ -0,0 +1,5 @@ +Collapse OS +> fls +bar +foo +> diff --git a/tools/tests/shell/fls.replay b/tools/tests/shell/fls.replay new file mode 100644 index 0000000..b9cf197 --- /dev/null +++ b/tools/tests/shell/fls.replay @@ -0,0 +1 @@ +fls diff --git a/tools/tests/shell/print.expected b/tools/tests/shell/print.expected new file mode 100644 index 0000000..4fe6e58 --- /dev/null +++ b/tools/tests/shell/print.expected @@ -0,0 +1,4 @@ +Collapse OS +> print 42 +42 +> diff --git a/tools/tests/shell/print.replay b/tools/tests/shell/print.replay new file mode 100644 index 0000000..2e97662 --- /dev/null +++ b/tools/tests/shell/print.replay @@ -0,0 +1 @@ +print 42 diff --git a/tools/tests/shell/runtests.sh b/tools/tests/shell/runtests.sh new file mode 100755 index 0000000..c583734 --- /dev/null +++ b/tools/tests/shell/runtests.sh @@ -0,0 +1,30 @@ +#!/bin/sh -e + +EMULDIR=../../emul +SHELL=../../emul/shell/shell + +replay() { + fn=$1 + replayfn=${fn%.*}.expected + ACTUAL=$("${SHELL}" -f test.cfs < "${fn}" 2> /dev/null) + EXPECTED=$(cat ${replayfn}) + if [ "$ACTUAL" = "$EXPECTED" ]; then + echo ok + else + echo different. Whole output: + echo "${ACTUAL}" + exit 1 + fi +} + +../../cfspack/cfspack cfsin > test.cfs + +if [ ! -z $1 ]; then + replay $1 + exit 0 +fi + +for fn in *.replay; do + echo "Replaying ${fn}" + replay "${fn}" +done