blob: 7f450b594f37f71a9856f8b633c4880612895992 [file] [log] [blame]
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -07001/*
2 * Copyright (c) 2008 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <app/console.h>
24#include <debug.h>
25#include <string.h>
26#include <ctype.h>
27#include <stdlib.h>
Travis Geiselbrechteb946052008-09-07 22:32:49 -070028#include <stdio.h>
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -070029
30static cmd_block *command_list = NULL;
31
32/* a linear array of statically defined command blocks,
33 defined in the linker script.
34 */
35extern cmd_block __commands_start;
36extern cmd_block __commands_end;
37
38static int cmd_help(int argc, const cmd_args *argv);
39static int cmd_test(int argc, const cmd_args *argv);
40
41STATIC_COMMAND_START
42 { "help", "this list", &cmd_help },
43 { "test", "test the command processor", &cmd_test },
44STATIC_COMMAND_END(help);
45
46int console_init(void)
47{
48 printf("console_init: entry\n");
49
50 /* add all the statically defined commands to the list */
51 cmd_block *block;
52 for (block = &__commands_start; block != &__commands_end; block++) {
53 console_register_commands(block);
54 }
55
56 return 0;
57}
58
59static const cmd *match_command(const char *command)
60{
61 cmd_block *block;
62 size_t i;
63
64 for (block = command_list; block != NULL; block = block->next) {
65 const cmd *curr_cmd = block->list;
66 for (i = 0; i < block->count; i++) {
67 if (strcmp(command, curr_cmd[i].cmd_str) == 0) {
68 return &curr_cmd[i];
69 }
70 }
71 }
72
73 return NULL;
74}
75
76static int read_line(char *buffer, int len)
77{
78 int pos = 0;
79 int escape_level = 0;
80
81 for (;;) {
82 char c;
83
84 /* loop until we get a char */
Travis Geiselbrechteb946052008-09-07 22:32:49 -070085 if (getc(&c) < 0)
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -070086 continue;
87
88// printf("c = 0x%hhx\n", c);
89
90 if (escape_level == 0) {
91 switch (c) {
92 case '\r':
93 case '\n':
Travis Geiselbrechteb946052008-09-07 22:32:49 -070094 putc(c);
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -070095 goto done;
96
97 case 0x7f: // backspace or delete
98 case 0x8:
99 if (pos > 0) {
100 pos--;
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700101 puts("\x1b[1D"); // move to the left one
102 putc(' ');
103 puts("\x1b[1D"); // move to the left one
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700104 }
105 break;
106
107 case 0x1b: // escape
108 escape_level++;
109 break;
110
111 default:
112 buffer[pos++] = c;
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700113 putc(c);
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700114 }
115 } else if (escape_level == 1) {
116 // inside an escape, look for '['
117 if (c == '[') {
118 escape_level++;
119 } else {
120 // we didn't get it, abort
121 escape_level = 0;
122 }
123 } else { // escape_level > 1
124 switch (c) {
125 case 67: // right arrow
126 buffer[pos++] = ' ';
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700127 putc(' ');
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700128 break;
129 case 68: // left arrow
130 if (pos > 0) {
131 pos--;
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700132 puts("\x1b[1D"); // move to the left one
133 putc(' ');
134 puts("\x1b[1D"); // move to the left one
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700135 }
136 break;
137 case 65: // up arrow
138 case 66: // down arrow
139 // XXX do history here
140 break;
141 default:
142 break;
143 }
144 escape_level = 0;
145 }
146
147 /* end of line. */
148 if (pos == (len - 1)) {
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700149 puts("\nerror: line too long\n");
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700150 pos = 0;
151 goto done;
152 }
153 }
154
155done:
156// printf("returning pos %d\n", pos);
157
158 buffer[pos] = 0;
159 return pos;
160}
161
162static int tokenize_command(char *buffer, cmd_args *args, int arg_count)
163{
164 int pos;
165 int arg;
166 bool finished;
167 enum {
168 INITIAL = 0,
169 IN_SPACE,
170 IN_TOKEN
171 } state;
172
173 pos = 0;
174 arg = 0;
175 state = INITIAL;
176 finished = false;
177
178 for (;;) {
179 char c = buffer[pos];
180
181 if (c == '\0')
182 finished = true;
183
184// printf("c 0x%hhx state %d arg %d pos %d\n", c, state, arg, pos);
185
186 switch (state) {
187 case INITIAL:
188 if (isspace(c)) {
189 state = IN_SPACE;
190 } else {
191 state = IN_TOKEN;
192 args[arg].str = &buffer[pos];
193 }
194 break;
195 case IN_TOKEN:
196 if (finished) {
197 arg++;
198 goto done;
199 }
200 if (isspace(c)) {
201 arg++;
202 buffer[pos] = 0;
203 /* are we out of tokens? */
204 if (arg == arg_count)
205 goto done;
206 state = IN_SPACE;
207 }
208 pos++;
209 break;
210 case IN_SPACE:
211 if (finished)
212 goto done;
213 if (!isspace(c)) {
214 state = IN_TOKEN;
215 args[arg].str = &buffer[pos];
216 }
217 pos++;
218 break;
219 }
220 }
221
222done:
223 return arg;
224}
225
226static void convert_args(int argc, cmd_args *argv)
227{
228 int i;
229
230 for (i = 0; i < argc; i++) {
231 argv[i].u = atoui(argv[i].str);
232 argv[i].i = atoi(argv[i].str);
233 }
234}
235
236static void console_loop(void)
237{
238 cmd_args args[16];
239 char buffer[256];
240
241 printf("entering main console loop\n");
242
243 for (;;) {
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700244 puts("] ");
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700245
246 int len = read_line(buffer, sizeof(buffer));
247 if (len == 0)
248 continue;
249
250// printf("line = '%s'\n", buffer);
251
252 /* tokenize the line */
253 int argc = tokenize_command(buffer, args, 16);
254 if (argc < 0) {
255 printf("syntax error\n");
256 continue;
257 } else if (argc == 0) {
258 continue;
259 }
260
261// printf("after tokenize: argc %d\n", argc);
262// for (int i = 0; i < argc; i++)
263// printf("%d: '%s'\n", i, args[i].str);
264
265 /* convert the args */
266 convert_args(argc, args);
267
268 /* try to match the command */
269 const cmd *command = match_command(args[0].str);
270 if (!command) {
271 printf("command not found\n");
272 continue;
273 }
274
275 int result = command->cmd_callback(argc, args);
276
277 // XXX do something with the result
278 }
279}
280
281
282void console_start(void)
283{
284
285 console_loop();
286}
287
288int console_run_command(const char *string)
289{
290 const cmd *command;
291
292 ASSERT(string != NULL);
293
294 command = match_command(string);
295 if (!command)
296 return -1;
297
298 int result = command->cmd_callback(0, NULL);
299
300 return result;
301}
302
303void console_register_commands(cmd_block *block)
304{
305 ASSERT(block);
306 ASSERT(block->next == NULL);
307
308 block->next = command_list;
309 command_list = block;
310}
311
312static int cmd_help(int argc, const cmd_args *argv)
313{
314
315 printf("command list:\n");
316
317 cmd_block *block;
318 size_t i;
319
320 for (block = command_list; block != NULL; block = block->next) {
321 const cmd *curr_cmd = block->list;
322 for (i = 0; i < block->count; i++) {
323 printf("\t%-16s: %s\n", curr_cmd[i].cmd_str, curr_cmd[i].help_str ? curr_cmd[i].help_str : "");
324 }
325 }
326
327 return 0;
328}
329
330static int cmd_test(int argc, const cmd_args *argv)
331{
332 int i;
333
334 printf("argc %d, argv %p\n", argc, argv);
335 for (i = 0; i < argc; i++)
336 printf("\t%d: str '%s', i %d, u %#x\n", i, argv[i].str, argv[i].i, argv[i].u);
337
338 return 0;
339}
340