diff options
author | David Walter Seikel | 2014-01-30 21:37:56 +1000 |
---|---|---|
committer | David Walter Seikel | 2014-01-30 21:37:56 +1000 |
commit | 7161efbd008f139884df16b82c07f3c2b7f5b50d (patch) | |
tree | d168b4d5f1dc2a3b935891ce26347df5fde1386c | |
parent | Added dumbsh, a really really dumb shell, for demonstration. (diff) | |
download | boxes-7161efbd008f139884df16b82c07f3c2b7f5b50d.zip boxes-7161efbd008f139884df16b82c07f3c2b7f5b50d.tar.gz boxes-7161efbd008f139884df16b82c07f3c2b7f5b50d.tar.bz2 boxes-7161efbd008f139884df16b82c07f3c2b7f5b50d.tar.xz |
Fix up dumbsh so it all works.
-rw-r--r-- | dumbsh.c | 104 |
1 files changed, 65 insertions, 39 deletions
@@ -30,47 +30,51 @@ struct keyCommand | |||
30 | GLOBALS( | 30 | GLOBALS( |
31 | unsigned h, w; | 31 | unsigned h, w; |
32 | int x, y; | 32 | int x, y; |
33 | struct double_list *current; | ||
33 | ) | 34 | ) |
34 | 35 | ||
35 | #define TT this.dumbsh | 36 | #define TT this.dumbsh |
36 | 37 | ||
37 | static void moveCursor() | 38 | static void updateLine() |
38 | { | 39 | { |
39 | if (0 > TT.y) TT.y = 0; | 40 | if (0 > TT.y) TT.y = 0; |
40 | if (0 > TT.x) TT.x = 0; | 41 | if (0 > TT.x) TT.x = 0; |
41 | if (strlen(toybuf) <= TT.x) TT.x = strlen(toybuf); | 42 | if (strlen(toybuf) <= TT.x) TT.x = strlen(toybuf); |
42 | if (TT.w < TT.y) TT.y = TT.w; | 43 | if (TT.h < TT.y) TT.y = TT.h; |
43 | if (TT.h < TT.x) TT.x = TT.h; | 44 | if (TT.w < TT.x) TT.x = TT.w; |
44 | printf("\x1B[%d;0H%s\x1B[%d;%dH", TT.y + 1, toybuf, TT.y + 1, TT.x + 1); | 45 | printf("\x1B[%d;0H%-*s\x1B[%d;%dH", TT.y + 1, TT.w, toybuf, TT.y + 1, TT.x + 1); |
45 | fflush(stdout); | 46 | fflush(stdout); |
46 | } | 47 | } |
47 | 48 | ||
49 | // Callback for incoming CSI commands from the terminal. | ||
48 | static void handleCSI(long extra, char *command, int *params, int count) | 50 | static void handleCSI(long extra, char *command, int *params, int count) |
49 | { | 51 | { |
50 | // Parameters are cursor line and column. Note this may be sent at other times, not just during terminal resize. | 52 | // Is it a cursor location report? |
51 | if (strcmp("R", command) == 0) | 53 | if (strcmp("R", command) == 0) |
52 | { | 54 | { |
55 | // Parameters are cursor line and column. Note this may be sent at other times, not just during terminal resize. | ||
56 | // The defaults are 1, which get ignored by the heuristic below. | ||
53 | int r = params[0], c = params[1]; | 57 | int r = params[0], c = params[1]; |
54 | 58 | ||
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. | 59 | // 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. | 60 | // This is a heuristic, we are checking against an unusable terminal size. |
58 | if ((2 == count) && (8 < r) && (8 < c)) | 61 | if ((2 == count) && (8 < r) && (8 < c)) |
59 | { | 62 | { |
60 | TT.h = r; | 63 | TT.h = r; |
61 | TT.w = c; | 64 | TT.w = c; |
62 | moveCursor(); | 65 | updateLine(); |
63 | } | 66 | } |
64 | } | 67 | } |
65 | } | 68 | } |
66 | 69 | ||
70 | // The various commands. | ||
67 | static void deleteChar() | 71 | static void deleteChar() |
68 | { | 72 | { |
69 | int j; | 73 | int j; |
70 | 74 | ||
71 | for (j = TT.x; toybuf[j]; j++) | 75 | for (j = TT.x; toybuf[j]; j++) |
72 | toybuf[j] = toybuf[j + 1]; | 76 | toybuf[j] = toybuf[j + 1]; |
73 | moveCursor(); | 77 | updateLine(); |
74 | } | 78 | } |
75 | 79 | ||
76 | static void backSpaceChar() | 80 | static void backSpaceChar() |
@@ -82,31 +86,42 @@ static void backSpaceChar() | |||
82 | } | 86 | } |
83 | } | 87 | } |
84 | 88 | ||
89 | // This is where we would actually deal with what ever command the user had typed in. | ||
90 | // For now we just move on. | ||
85 | static void doCommand() | 91 | static void doCommand() |
86 | { | 92 | { |
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; | 93 | toybuf[0] = 0; |
90 | TT.x = 0; | 94 | TT.x = 0; |
91 | TT.y++; | 95 | TT.y++; |
92 | moveCursor(); | 96 | updateLine(); |
93 | } | ||
94 | |||
95 | static void downLine() | ||
96 | { | ||
97 | // Do command history stuff here. | ||
98 | } | 97 | } |
99 | 98 | ||
100 | static void endOfLine() | 99 | static void endOfLine() |
101 | { | 100 | { |
102 | TT.x = strlen(toybuf) - 1; | 101 | TT.x = strlen(toybuf) - 1; |
103 | moveCursor(); | 102 | updateLine(); |
104 | } | 103 | } |
105 | 104 | ||
106 | static void leftChar() | 105 | static void leftChar() |
107 | { | 106 | { |
108 | TT.x--; | 107 | TT.x--; |
109 | moveCursor(); | 108 | updateLine(); |
109 | } | ||
110 | |||
111 | static void nextHistory() | ||
112 | { | ||
113 | TT.current = TT.current->next; | ||
114 | strcpy(toybuf, TT.current->data); | ||
115 | TT.x = strlen(toybuf); | ||
116 | updateLine(); | ||
117 | } | ||
118 | |||
119 | static void prevHistory() | ||
120 | { | ||
121 | TT.current = TT.current->prev; | ||
122 | strcpy(toybuf, TT.current->data); | ||
123 | TT.x = strlen(toybuf); | ||
124 | updateLine(); | ||
110 | } | 125 | } |
111 | 126 | ||
112 | static void quit() | 127 | static void quit() |
@@ -117,28 +132,26 @@ static void quit() | |||
117 | static void rightChar() | 132 | static void rightChar() |
118 | { | 133 | { |
119 | TT.x++; | 134 | TT.x++; |
120 | moveCursor(); | 135 | updateLine(); |
121 | } | 136 | } |
122 | 137 | ||
123 | static void startOfLine() | 138 | static void startOfLine() |
124 | { | 139 | { |
125 | TT.x = 0; | 140 | TT.x = 0; |
126 | moveCursor(); | 141 | updateLine(); |
127 | } | ||
128 | |||
129 | static void upLine() | ||
130 | { | ||
131 | // Do command history stuff here. | ||
132 | } | 142 | } |
133 | 143 | ||
134 | // The key to command mappings. | 144 | // The key to command mappings. |
135 | static struct keyCommand simpleEmacsKeys[] = | 145 | static struct keyCommand simpleEmacsKeys[] = |
136 | { | 146 | { |
137 | {"Del", backSpaceChar}, | 147 | {"BS", backSpaceChar}, |
148 | {"Del", deleteChar}, | ||
138 | {"^D", deleteChar}, | 149 | {"^D", deleteChar}, |
139 | {"Return", doCommand}, | 150 | {"Return", doCommand}, |
140 | {"Down", downLine}, | 151 | {"^J", doCommand}, |
141 | {"^N", downLine}, | 152 | {"^M", doCommand}, |
153 | {"Down", nextHistory}, | ||
154 | {"^N", nextHistory}, | ||
142 | {"End", endOfLine}, | 155 | {"End", endOfLine}, |
143 | {"^E", endOfLine}, | 156 | {"^E", endOfLine}, |
144 | {"Left", leftChar}, | 157 | {"Left", leftChar}, |
@@ -149,8 +162,8 @@ static struct keyCommand simpleEmacsKeys[] = | |||
149 | {"^F", rightChar}, | 162 | {"^F", rightChar}, |
150 | {"Home", startOfLine}, | 163 | {"Home", startOfLine}, |
151 | {"^A", startOfLine}, | 164 | {"^A", startOfLine}, |
152 | {"Up", upLine}, | 165 | {"Up", prevHistory}, |
153 | {"^P", upLine}, | 166 | {"^P", prevHistory}, |
154 | {NULL, NULL} | 167 | {NULL, NULL} |
155 | }; | 168 | }; |
156 | 169 | ||
@@ -168,17 +181,19 @@ static int handleKeySequence(long extra, char *sequence) | |||
168 | } | 181 | } |
169 | } | 182 | } |
170 | 183 | ||
171 | if ((0 == sequence[1]) && isprint(sequence[0])) // See if it's an ordinary key. | 184 | // See if it's ordinary keys. |
185 | if (isprint(sequence[0])) | ||
172 | { | 186 | { |
173 | if (TT.x < sizeof(toybuf)) | 187 | if (TT.x < sizeof(toybuf)) |
174 | { | 188 | { |
175 | int j; | 189 | int j, l = strlen(sequence); |
176 | 190 | ||
177 | for (j = strlen(toybuf); j >= TT.x; j--) | 191 | for (j = strlen(toybuf); j >= TT.x; j--) |
178 | toybuf[j + 1] = toybuf[j]; | 192 | toybuf[j + l] = toybuf[j]; |
179 | toybuf[TT.x] = sequence[0]; | 193 | for (j = 0; j < l; j++) |
180 | TT.x++; | 194 | toybuf[TT.x + j] = sequence[j]; |
181 | moveCursor(); | 195 | TT.x += l; |
196 | updateLine(); | ||
182 | } | 197 | } |
183 | return 1; | 198 | return 1; |
184 | } | 199 | } |
@@ -189,6 +204,18 @@ static int handleKeySequence(long extra, char *sequence) | |||
189 | void dumbsh_main(void) | 204 | void dumbsh_main(void) |
190 | { | 205 | { |
191 | struct termios termio, oldtermio; | 206 | struct termios termio, oldtermio; |
207 | char *temp = getenv("HOME"); | ||
208 | int fd; | ||
209 | |||
210 | // Load bash history. | ||
211 | temp = xmsprintf("%s/%s", temp ? temp : "", ".bash_history"); | ||
212 | if (-1 != (fd = open(temp, O_RDONLY))) | ||
213 | { | ||
214 | while ((temp = get_line(fd))) TT.current = dlist_add(&TT.current, temp); | ||
215 | close(fd); | ||
216 | } | ||
217 | if (!TT.current) | ||
218 | TT.current = dlist_add(&TT.current, ""); | ||
192 | 219 | ||
193 | // Grab the old terminal settings and save it. | 220 | // Grab the old terminal settings and save it. |
194 | tcgetattr(0, &oldtermio); | 221 | tcgetattr(0, &oldtermio); |
@@ -205,16 +232,15 @@ void dumbsh_main(void) | |||
205 | termio.c_cc[VMIN]=1; | 232 | termio.c_cc[VMIN]=1; |
206 | tcsetattr(0, TCSANOW, &termio); | 233 | tcsetattr(0, TCSANOW, &termio); |
207 | 234 | ||
235 | // Let the mouldy old terminal mold us. | ||
208 | TT.w = 80; | 236 | TT.w = 80; |
209 | TT.h = 24; | 237 | TT.h = 24; |
210 | terminal_size(&TT.w, &TT.h); | 238 | terminal_size(&TT.w, &TT.h); |
211 | 239 | ||
212 | // Run the main loop. | 240 | updateLine(); |
213 | handle_keys(0, handleKeySequence, handleCSI); | 241 | handle_keys(0, handleKeySequence, handleCSI); |
214 | 242 | ||
215 | // Restore the old terminal settings. | ||
216 | tcsetattr(0, TCSANOW, &oldtermio); | 243 | tcsetattr(0, TCSANOW, &oldtermio); |
217 | |||
218 | puts(""); | 244 | puts(""); |
219 | fflush(stdout); | 245 | fflush(stdout); |
220 | } | 246 | } |