aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--dumbsh.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/dumbsh.c b/dumbsh.c
new file mode 100644
index 0000000..1d4ca4f
--- /dev/null
+++ b/dumbsh.c
@@ -0,0 +1,220 @@
1/* dumbsh.c - A really dumb shell, to demonstrate handlekeys usage.
2 *
3 * Copyright 2014 David Seikel <won_fang@yahoo.com.au>
4 *
5 * Not a real shell, so doesn't follow any standards,
6 * coz it wont implement them anyway.
7
8USE_DUMBSH(NEWTOY(dumbsh, "", TOYFLAG_USR|TOYFLAG_BIN))
9
10config DUMBSH
11 bool "dumbsh"
12 default n
13 help
14 usage: dumbsh
15
16 A really dumb shell.
17*/
18
19#include "toys.h"
20#include "lib/handlekeys.h"
21
22typedef void (*eventHandler) (void);
23
24struct keyCommand
25{
26 char *key;
27 eventHandler handler;
28};
29
30GLOBALS(
31 unsigned h, w;
32 int x, y;
33)
34
35#define TT this.dumbsh
36
37static void moveCursor()
38{
39 if (0 > TT.y) TT.y = 0;
40 if (0 > TT.x) TT.x = 0;
41 if (strlen(toybuf) <= TT.x) TT.x = strlen(toybuf);
42 if (TT.w < TT.y) TT.y = TT.w;
43 if (TT.h < TT.x) TT.x = TT.h;
44 printf("\x1B[%d;0H%s\x1B[%d;%dH", TT.y + 1, toybuf, TT.y + 1, TT.x + 1);
45 fflush(stdout);
46}
47
48static void handleCSI(long extra, char *command, int *params, int count)
49{
50 // Parameters are cursor line and column. Note this may be sent at other times, not just during terminal resize.
51 if (strcmp("R", command) == 0)
52 {
53 int r = params[0], c = params[1];
54
55 // The defaults are 1, which get ignored by the heuristic below.
56 // Check it's not an F3 key variation, coz some of them use the same CSI function code.
57 // This is a heuristic, we are checking against an unusable terminal size.
58 if ((2 == count) && (8 < r) && (8 < c))
59 {
60 TT.h = r;
61 TT.w = c;
62 moveCursor();
63 }
64 }
65}
66
67static void deleteChar()
68{
69 int j;
70
71 for (j = TT.x; toybuf[j]; j++)
72 toybuf[j] = toybuf[j + 1];
73 moveCursor();
74}
75
76static void backSpaceChar()
77{
78 if (TT.x)
79 {
80 TT.x--;
81 deleteChar();
82 }
83}
84
85static void doCommand()
86{
87 // This is where we would actually deal with what ever command the user had typed in.
88 // For now we just move on.
89 toybuf[0] = 0;
90 TT.x = 0;
91 TT.y++;
92 moveCursor();
93}
94
95static void downLine()
96{
97 // Do command history stuff here.
98}
99
100static void endOfLine()
101{
102 TT.x = strlen(toybuf) - 1;
103 moveCursor();
104}
105
106static void leftChar()
107{
108 TT.x--;
109 moveCursor();
110}
111
112static void quit()
113{
114 handle_keys_quit();
115}
116
117static void rightChar()
118{
119 TT.x++;
120 moveCursor();
121}
122
123static void startOfLine()
124{
125 TT.x = 0;
126 moveCursor();
127}
128
129static void upLine()
130{
131 // Do command history stuff here.
132}
133
134// The key to command mappings.
135static struct keyCommand simpleEmacsKeys[] =
136{
137 {"Del", backSpaceChar},
138 {"^D", deleteChar},
139 {"Return", doCommand},
140 {"Down", downLine},
141 {"^N", downLine},
142 {"End", endOfLine},
143 {"^E", endOfLine},
144 {"Left", leftChar},
145 {"^B", leftChar},
146 {"^X^C", quit},
147 {"^C", quit},
148 {"Right", rightChar},
149 {"^F", rightChar},
150 {"Home", startOfLine},
151 {"^A", startOfLine},
152 {"Up", upLine},
153 {"^P", upLine},
154 {NULL, NULL}
155};
156
157static int handleKeySequence(long extra, char *sequence)
158{
159 int j;
160
161 // Search for a key sequence bound to a command.
162 for (j = 0; simpleEmacsKeys[j].key; j++)
163 {
164 if (strcmp(simpleEmacsKeys[j].key, sequence) == 0)
165 {
166 if (simpleEmacsKeys[j].handler) simpleEmacsKeys[j].handler();
167 return 1;
168 }
169 }
170
171 if ((0 == sequence[1]) && isprint(sequence[0])) // See if it's an ordinary key.
172 {
173 if (TT.x < sizeof(toybuf))
174 {
175 int j;
176
177 for (j = strlen(toybuf); j >= TT.x; j--)
178 toybuf[j + 1] = toybuf[j];
179 toybuf[TT.x] = sequence[0];
180 TT.x++;
181 moveCursor();
182 }
183 return 1;
184 }
185
186 return 0;
187}
188
189void dumbsh_main(void)
190{
191 struct termios termio, oldtermio;
192
193 // Grab the old terminal settings and save it.
194 tcgetattr(0, &oldtermio);
195 tcflush(0, TCIFLUSH);
196 termio = oldtermio;
197
198 // Mould the terminal to our will.
199 termio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC | IXON | IXOFF | IXANY);
200 termio.c_oflag &= ~OPOST;
201 termio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | TOSTOP | ICANON | ISIG | IEXTEN);
202 termio.c_cflag &= ~(CSIZE | PARENB);
203 termio.c_cflag |= CS8;
204 termio.c_cc[VTIME]=0; // deciseconds.
205 termio.c_cc[VMIN]=1;
206 tcsetattr(0, TCSANOW, &termio);
207
208 TT.w = 80;
209 TT.h = 24;
210 terminal_size(&TT.w, &TT.h);
211
212 // Run the main loop.
213 handle_keys(0, handleKeySequence, handleCSI);
214
215 // Restore the old terminal settings.
216 tcsetattr(0, TCSANOW, &oldtermio);
217
218 puts("");
219 fflush(stdout);
220}