move app/console to lib/console
diff --git a/lib/console/console.c b/lib/console/console.c
new file mode 100644
index 0000000..5782530
--- /dev/null
+++ b/lib/console/console.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <lib/console.h>
+
+static cmd_block *command_list = NULL;
+
+/* a linear array of statically defined command blocks,
+ defined in the linker script.
+ */
+extern cmd_block __commands_start;
+extern cmd_block __commands_end;
+
+static int cmd_help(int argc, const cmd_args *argv);
+static int cmd_test(int argc, const cmd_args *argv);
+
+STATIC_COMMAND_START
+ { "help", "this list", &cmd_help },
+ { "test", "test the command processor", &cmd_test },
+STATIC_COMMAND_END(help);
+
+int console_init(void)
+{
+ printf("console_init: entry\n");
+
+ /* add all the statically defined commands to the list */
+ cmd_block *block;
+ for (block = &__commands_start; block != &__commands_end; block++) {
+ console_register_commands(block);
+ }
+
+ return 0;
+}
+
+static const cmd *match_command(const char *command)
+{
+ cmd_block *block;
+ size_t i;
+
+ for (block = command_list; block != NULL; block = block->next) {
+ const cmd *curr_cmd = block->list;
+ for (i = 0; i < block->count; i++) {
+ if (strcmp(command, curr_cmd[i].cmd_str) == 0) {
+ return &curr_cmd[i];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int read_line(char *buffer, int len)
+{
+ int pos = 0;
+ int escape_level = 0;
+
+ for (;;) {
+ char c;
+
+ /* loop until we get a char */
+ if (getc(&c) < 0)
+ continue;
+
+// printf("c = 0x%hhx\n", c);
+
+ if (escape_level == 0) {
+ switch (c) {
+ case '\r':
+ case '\n':
+ putc(c);
+ goto done;
+
+ case 0x7f: // backspace or delete
+ case 0x8:
+ if (pos > 0) {
+ pos--;
+ puts("\x1b[1D"); // move to the left one
+ putc(' ');
+ puts("\x1b[1D"); // move to the left one
+ }
+ break;
+
+ case 0x1b: // escape
+ escape_level++;
+ break;
+
+ default:
+ buffer[pos++] = c;
+ putc(c);
+ }
+ } else if (escape_level == 1) {
+ // inside an escape, look for '['
+ if (c == '[') {
+ escape_level++;
+ } else {
+ // we didn't get it, abort
+ escape_level = 0;
+ }
+ } else { // escape_level > 1
+ switch (c) {
+ case 67: // right arrow
+ buffer[pos++] = ' ';
+ putc(' ');
+ break;
+ case 68: // left arrow
+ if (pos > 0) {
+ pos--;
+ puts("\x1b[1D"); // move to the left one
+ putc(' ');
+ puts("\x1b[1D"); // move to the left one
+ }
+ break;
+ case 65: // up arrow
+ case 66: // down arrow
+ // XXX do history here
+ break;
+ default:
+ break;
+ }
+ escape_level = 0;
+ }
+
+ /* end of line. */
+ if (pos == (len - 1)) {
+ puts("\nerror: line too long\n");
+ pos = 0;
+ goto done;
+ }
+ }
+
+done:
+// printf("returning pos %d\n", pos);
+
+ buffer[pos] = 0;
+ return pos;
+}
+
+static int tokenize_command(char *buffer, cmd_args *args, int arg_count)
+{
+ int pos;
+ int arg;
+ bool finished;
+ enum {
+ INITIAL = 0,
+ IN_SPACE,
+ IN_TOKEN
+ } state;
+
+ pos = 0;
+ arg = 0;
+ state = INITIAL;
+ finished = false;
+
+ for (;;) {
+ char c = buffer[pos];
+
+ if (c == '\0')
+ finished = true;
+
+// printf("c 0x%hhx state %d arg %d pos %d\n", c, state, arg, pos);
+
+ switch (state) {
+ case INITIAL:
+ if (isspace(c)) {
+ state = IN_SPACE;
+ } else {
+ state = IN_TOKEN;
+ args[arg].str = &buffer[pos];
+ }
+ break;
+ case IN_TOKEN:
+ if (finished) {
+ arg++;
+ goto done;
+ }
+ if (isspace(c)) {
+ arg++;
+ buffer[pos] = 0;
+ /* are we out of tokens? */
+ if (arg == arg_count)
+ goto done;
+ state = IN_SPACE;
+ }
+ pos++;
+ break;
+ case IN_SPACE:
+ if (finished)
+ goto done;
+ if (!isspace(c)) {
+ state = IN_TOKEN;
+ args[arg].str = &buffer[pos];
+ }
+ pos++;
+ break;
+ }
+ }
+
+done:
+ return arg;
+}
+
+static void convert_args(int argc, cmd_args *argv)
+{
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ argv[i].u = atoui(argv[i].str);
+ argv[i].i = atoi(argv[i].str);
+ }
+}
+
+static void console_loop(void)
+{
+ cmd_args args[16];
+ char buffer[256];
+
+ printf("entering main console loop\n");
+
+ for (;;) {
+ puts("] ");
+
+ int len = read_line(buffer, sizeof(buffer));
+ if (len == 0)
+ continue;
+
+// printf("line = '%s'\n", buffer);
+
+ /* tokenize the line */
+ int argc = tokenize_command(buffer, args, 16);
+ if (argc < 0) {
+ printf("syntax error\n");
+ continue;
+ } else if (argc == 0) {
+ continue;
+ }
+
+// printf("after tokenize: argc %d\n", argc);
+// for (int i = 0; i < argc; i++)
+// printf("%d: '%s'\n", i, args[i].str);
+
+ /* convert the args */
+ convert_args(argc, args);
+
+ /* try to match the command */
+ const cmd *command = match_command(args[0].str);
+ if (!command) {
+ printf("command not found\n");
+ continue;
+ }
+
+ int result = command->cmd_callback(argc, args);
+
+ // XXX do something with the result
+ }
+}
+
+
+void console_start(void)
+{
+
+ console_loop();
+}
+
+int console_run_command(const char *string)
+{
+ const cmd *command;
+
+ ASSERT(string != NULL);
+
+ command = match_command(string);
+ if (!command)
+ return -1;
+
+ int result = command->cmd_callback(0, NULL);
+
+ return result;
+}
+
+void console_register_commands(cmd_block *block)
+{
+ ASSERT(block);
+ ASSERT(block->next == NULL);
+
+ block->next = command_list;
+ command_list = block;
+}
+
+static int cmd_help(int argc, const cmd_args *argv)
+{
+
+ printf("command list:\n");
+
+ cmd_block *block;
+ size_t i;
+
+ for (block = command_list; block != NULL; block = block->next) {
+ const cmd *curr_cmd = block->list;
+ for (i = 0; i < block->count; i++) {
+ printf("\t%-16s: %s\n", curr_cmd[i].cmd_str, curr_cmd[i].help_str ? curr_cmd[i].help_str : "");
+ }
+ }
+
+ return 0;
+}
+
+static int cmd_test(int argc, const cmd_args *argv)
+{
+ int i;
+
+ printf("argc %d, argv %p\n", argc, argv);
+ for (i = 0; i < argc; i++)
+ printf("\t%d: str '%s', i %d, u %#x\n", i, argv[i].str, argv[i].i, argv[i].u);
+
+ return 0;
+}
+