From cbbc71bf7754af613cd7b4b695baeef5b51e1e07 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Thu, 30 Jan 2014 19:12:04 +1000 Subject: Added dumbsh, a really really dumb shell, for demonstration. Yes, I know, it's still broken. --- dumbsh.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 dumbsh.c diff --git a/dumbsh.c b/dumbsh.c new file mode 100644 index 0000000..1d4ca4f --- /dev/null +++ b/dumbsh.c @@ -0,0 +1,220 @@ +/* dumbsh.c - A really dumb shell, to demonstrate handlekeys usage. + * + * Copyright 2014 David Seikel + * + * Not a real shell, so doesn't follow any standards, + * coz it wont implement them anyway. + +USE_DUMBSH(NEWTOY(dumbsh, "", TOYFLAG_USR|TOYFLAG_BIN)) + +config DUMBSH + bool "dumbsh" + default n + help + usage: dumbsh + + A really dumb shell. +*/ + +#include "toys.h" +#include "lib/handlekeys.h" + +typedef void (*eventHandler) (void); + +struct keyCommand +{ + char *key; + eventHandler handler; +}; + +GLOBALS( + unsigned h, w; + int x, y; +) + +#define TT this.dumbsh + +static void moveCursor() +{ + if (0 > TT.y) TT.y = 0; + if (0 > TT.x) TT.x = 0; + if (strlen(toybuf) <= TT.x) TT.x = strlen(toybuf); + if (TT.w < TT.y) TT.y = TT.w; + if (TT.h < TT.x) TT.x = TT.h; + printf("\x1B[%d;0H%s\x1B[%d;%dH", TT.y + 1, toybuf, TT.y + 1, TT.x + 1); + fflush(stdout); +} + +static void handleCSI(long extra, char *command, int *params, int count) +{ + // Parameters are cursor line and column. Note this may be sent at other times, not just during terminal resize. + if (strcmp("R", command) == 0) + { + int r = params[0], c = params[1]; + + // The defaults are 1, which get ignored by the heuristic below. + // Check it's not an F3 key variation, coz some of them use the same CSI function code. + // This is a heuristic, we are checking against an unusable terminal size. + if ((2 == count) && (8 < r) && (8 < c)) + { + TT.h = r; + TT.w = c; + moveCursor(); + } + } +} + +static void deleteChar() +{ + int j; + + for (j = TT.x; toybuf[j]; j++) + toybuf[j] = toybuf[j + 1]; + moveCursor(); +} + +static void backSpaceChar() +{ + if (TT.x) + { + TT.x--; + deleteChar(); + } +} + +static void doCommand() +{ + // This is where we would actually deal with what ever command the user had typed in. + // For now we just move on. + toybuf[0] = 0; + TT.x = 0; + TT.y++; + moveCursor(); +} + +static void downLine() +{ + // Do command history stuff here. +} + +static void endOfLine() +{ + TT.x = strlen(toybuf) - 1; + moveCursor(); +} + +static void leftChar() +{ + TT.x--; + moveCursor(); +} + +static void quit() +{ + handle_keys_quit(); +} + +static void rightChar() +{ + TT.x++; + moveCursor(); +} + +static void startOfLine() +{ + TT.x = 0; + moveCursor(); +} + +static void upLine() +{ + // Do command history stuff here. +} + +// The key to command mappings. +static struct keyCommand simpleEmacsKeys[] = +{ + {"Del", backSpaceChar}, + {"^D", deleteChar}, + {"Return", doCommand}, + {"Down", downLine}, + {"^N", downLine}, + {"End", endOfLine}, + {"^E", endOfLine}, + {"Left", leftChar}, + {"^B", leftChar}, + {"^X^C", quit}, + {"^C", quit}, + {"Right", rightChar}, + {"^F", rightChar}, + {"Home", startOfLine}, + {"^A", startOfLine}, + {"Up", upLine}, + {"^P", upLine}, + {NULL, NULL} +}; + +static int handleKeySequence(long extra, char *sequence) +{ + int j; + + // Search for a key sequence bound to a command. + for (j = 0; simpleEmacsKeys[j].key; j++) + { + if (strcmp(simpleEmacsKeys[j].key, sequence) == 0) + { + if (simpleEmacsKeys[j].handler) simpleEmacsKeys[j].handler(); + return 1; + } + } + + if ((0 == sequence[1]) && isprint(sequence[0])) // See if it's an ordinary key. + { + if (TT.x < sizeof(toybuf)) + { + int j; + + for (j = strlen(toybuf); j >= TT.x; j--) + toybuf[j + 1] = toybuf[j]; + toybuf[TT.x] = sequence[0]; + TT.x++; + moveCursor(); + } + return 1; + } + + return 0; +} + +void dumbsh_main(void) +{ + struct termios termio, oldtermio; + + // Grab the old terminal settings and save it. + tcgetattr(0, &oldtermio); + tcflush(0, TCIFLUSH); + termio = oldtermio; + + // Mould the terminal to our will. + termio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC | IXON | IXOFF | IXANY); + termio.c_oflag &= ~OPOST; + termio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | TOSTOP | ICANON | ISIG | IEXTEN); + termio.c_cflag &= ~(CSIZE | PARENB); + termio.c_cflag |= CS8; + termio.c_cc[VTIME]=0; // deciseconds. + termio.c_cc[VMIN]=1; + tcsetattr(0, TCSANOW, &termio); + + TT.w = 80; + TT.h = 24; + terminal_size(&TT.w, &TT.h); + + // Run the main loop. + handle_keys(0, handleKeySequence, handleCSI); + + // Restore the old terminal settings. + tcsetattr(0, TCSANOW, &oldtermio); + + puts(""); + fflush(stdout); +} -- cgit v1.1