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;
+}
+