Index: arch/ia32/include/i8042.h
===================================================================
--- arch/ia32/include/i8042.h	(revision 54aff986b661048892fa3f1d7a529a7604f2f556)
+++ arch/ia32/include/i8042.h	(revision 0c8e69204d1c8675761780e4b928c137593c09fc)
@@ -38,4 +38,9 @@
 #define SC_RSHIFT	0x36
 #define SC_CAPSLOCK	0x3a
+#define SC_SPEC_ESCAPE  0xe0
+#define SC_LEFTARR      0x4b
+#define SC_RIGHTARR     0x4d
+#define SC_UPARR        0x48
+#define SC_DOWNARR      0x50
 
 extern void i8042_init(void);
Index: arch/ia32/src/drivers/i8042.c
===================================================================
--- arch/ia32/src/drivers/i8042.c	(revision 54aff986b661048892fa3f1d7a529a7604f2f556)
+++ arch/ia32/src/drivers/i8042.c	(revision 0c8e69204d1c8675761780e4b928c137593c09fc)
@@ -304,12 +304,34 @@
 	spinlock_lock(&keylock);
 	switch (sc) {
-	    case SC_LSHIFT:
-	    case SC_RSHIFT:
+	case SC_LSHIFT:
+	case SC_RSHIFT:
 	    	keyflags |= PRESSED_SHIFT;
 		break;
-	    case SC_CAPSLOCK:
+	case SC_CAPSLOCK:
 		keyflags |= PRESSED_CAPSLOCK;
 		break;
-	    default:
+	case SC_SPEC_ESCAPE:
+		break;
+	case SC_LEFTARR:
+		chardev_push_character(&kbrd, 0x1b);
+		chardev_push_character(&kbrd, 0x5b);
+		chardev_push_character(&kbrd, 0x44);
+		break;
+	case SC_RIGHTARR:
+		chardev_push_character(&kbrd, 0x1b);
+		chardev_push_character(&kbrd, 0x5b);
+		chardev_push_character(&kbrd, 0x43);
+		break;
+	case SC_UPARR:
+		chardev_push_character(&kbrd, 0x1b);
+		chardev_push_character(&kbrd, 0x5b);
+		chardev_push_character(&kbrd, 0x41);
+		break;
+	case SC_DOWNARR:
+		chardev_push_character(&kbrd, 0x1b);
+		chardev_push_character(&kbrd, 0x5b);
+		chardev_push_character(&kbrd, 0x42);
+		break;
+	default:
 	    	letter = is_lower(ascii);
 		capslock = (keyflags & PRESSED_CAPSLOCK) || (lockflags & LOCKED_CAPSLOCK);
Index: generic/include/console/console.h
===================================================================
--- generic/include/console/console.h	(revision 54aff986b661048892fa3f1d7a529a7604f2f556)
+++ generic/include/console/console.h	(revision 0c8e69204d1c8675761780e4b928c137593c09fc)
@@ -37,4 +37,5 @@
 
 extern __u8 getc(chardev_t *chardev);
+__u8 _getc(chardev_t *chardev);
 extern count_t gets(chardev_t *chardev, char *buf, size_t buflen);
 extern void putchar(char c);
Index: generic/include/console/kconsole.h
===================================================================
--- generic/include/console/kconsole.h	(revision 54aff986b661048892fa3f1d7a529a7604f2f556)
+++ generic/include/console/kconsole.h	(revision 0c8e69204d1c8675761780e4b928c137593c09fc)
@@ -35,4 +35,5 @@
 
 #define MAX_CMDLINE     256
+#define KCONSOLE_HISTORY 10
 
 enum cmd_arg_type {
Index: generic/include/symtab.h
===================================================================
--- generic/include/symtab.h	(revision 54aff986b661048892fa3f1d7a529a7604f2f556)
+++ generic/include/symtab.h	(revision 0c8e69204d1c8675761780e4b928c137593c09fc)
@@ -42,4 +42,5 @@
 extern __address get_symbol_addr(const char *name);
 extern void symtab_print_search(const char *name);
+extern int symtab_compl(char *name);
 
 /* Symtable linked together by build process */
Index: generic/src/console/console.c
===================================================================
--- generic/src/console/console.c	(revision 54aff986b661048892fa3f1d7a529a7604f2f556)
+++ generic/src/console/console.c	(revision 0c8e69204d1c8675761780e4b928c137593c09fc)
@@ -40,5 +40,5 @@
 chardev_t *stdout = NULL;
 
-/** Get character from character device.
+/** Get character from character device. Do not echo character.
  *
  * @param chardev Character device.
@@ -46,5 +46,5 @@
  * @return Character read.
  */
-static __u8 _getc(chardev_t *chardev)
+__u8 _getc(chardev_t *chardev)
 {
 	__u8 ch;
Index: generic/src/console/kconsole.c
===================================================================
--- generic/src/console/kconsole.c	(revision 54aff986b661048892fa3f1d7a529a7604f2f556)
+++ generic/src/console/kconsole.c	(revision 0c8e69204d1c8675761780e4b928c137593c09fc)
@@ -70,12 +70,17 @@
 static cmd_info_t *parse_cmdline(char *cmdline, size_t len);
 static bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end);
+static char history[KCONSOLE_HISTORY][MAX_CMDLINE] = {};
 
 /** Initialize kconsole data structures. */
 void kconsole_init(void)
 {
+	int i;
+
 	spinlock_initialize(&cmd_lock, "kconsole_cmd");
 	list_initialize(&cmd_head);
 
 	cmd_init();
+	for (i=0; i<KCONSOLE_HISTORY; i++)
+		history[i][0] = '\0';
 }
 
@@ -138,4 +143,224 @@
 }
 
+static void rdln_print_c(char ch, int count)
+{
+	int i;
+	for (i=0;i<count;i++)
+		putchar(ch);
+}
+
+static void insert_char(char *str, char ch, int pos)
+{
+	int i;
+	
+	for (i=strlen(str);i > pos; i--)
+		str[i] = str[i-1];
+	str[pos] = ch;
+}
+
+static const char * cmdtab_search_one(const char *name,link_t **startpos)
+{
+	int namelen = strlen(name);
+	const char *curname;
+	char *foundsym = NULL;
+	int foundpos = 0;
+
+	spinlock_lock(&cmd_lock);
+
+	if (!*startpos)
+		*startpos = cmd_head.next;
+
+	for (;*startpos != &cmd_head;*startpos = (*startpos)->next) {
+		cmd_info_t *hlp;
+		hlp = list_get_instance(*startpos, cmd_info_t, link);
+
+		curname = hlp->name;
+		if (strlen(curname) < namelen)
+			continue;
+		if (strncmp(curname, name, namelen) == 0) {
+			spinlock_unlock(&cmd_lock);	
+			return curname+namelen;
+		}
+	}
+	spinlock_unlock(&cmd_lock);	
+	return NULL;
+}
+
+
+/** Command completion of the commands 
+ *
+ * @param name - string to match, changed to hint on exit
+ * @return number of found matches
+ */
+static int cmdtab_compl(char *name)
+{
+	char output[MAX_SYMBOL_NAME+1];
+	link_t *startpos = NULL;
+	const char *foundtxt;
+	int found = 0;
+	int i;
+
+	output[0] = '\0';
+	while ((foundtxt = cmdtab_search_one(name, &startpos))) {
+		startpos = startpos->next;
+		if (!found)
+			strncpy(output, foundtxt, strlen(foundtxt)+1);
+		else {
+			for (i=0; output[i] && foundtxt[i] && output[i]==foundtxt[i]; i++)
+				;
+			output[i] = '\0';
+		}
+		found++;
+	}
+	if (!found)
+		return 0;
+
+	if (found > 1) {
+		printf("\n");
+		startpos = NULL;
+		while ((foundtxt = cmdtab_search_one(name, &startpos))) {
+			cmd_info_t *hlp;
+			hlp = list_get_instance(startpos, cmd_info_t, link);
+			printf("%s - %s\n", hlp->name, hlp->description);
+			startpos = startpos->next;
+		}
+	}
+	strncpy(name, output, MAX_SYMBOL_NAME);
+	return found;
+	
+}
+
+static char * clever_readline(const char *prompt, chardev_t *input)
+{
+	static int histposition = 0;
+
+	char tmp[MAX_CMDLINE+1];
+	int curlen = 0, position = 0;
+	char *current = history[histposition];
+	int i;
+	char c;
+
+	printf("%s> ", prompt);
+	while (1) {
+		c = _getc(input);
+		if (c == '\n') {
+			putchar(c);
+			break;
+		} if (c == '\b') {
+			if (position == 0)
+				continue;
+			for (i=position; i<curlen;i++)
+				current[i-1] = current[i];
+			curlen--;
+			position--;
+			putchar('\b');
+			for (i=position;i<curlen;i++)
+				putchar(current[i]);
+			putchar(' ');
+			rdln_print_c('\b',curlen-position+1);
+			continue;
+		}
+		if (c == '\t') {
+			int found;
+
+			/* Move to the end of the word */
+			for (;position<curlen && current[position]!=' ';position++)
+				putchar(current[position]);
+			/* Copy to tmp last word */
+			for (i=position-1;i >= 0 && current[i]!=' ' ;i--)
+				;
+			/* If word begins with * or &, skip it */
+			if (tmp[0] == '*' || tmp[0] == '&')
+				for (i=1;tmp[i];i++)
+					tmp[i-1] = tmp[i];
+			i++; /* I is at the start of the word */
+			strncpy(tmp, current+i, position-i+1);
+
+			if (i==0) { /* Command completion */
+				found = cmdtab_compl(tmp);
+			} else { /* Symtab completion */
+				found = symtab_compl(tmp);
+			}
+
+			if (found == 0) 
+				continue;
+			for (i=0;tmp[i] && curlen < MAX_CMDLINE;i++,curlen++)
+				insert_char(current, tmp[i], i+position);
+			if (found == 1) { /* One match */
+				for (i=position;i<curlen;i++)
+					putchar(current[i]);
+				position += strlen(tmp);
+				/* Add space to end */
+				if (position == curlen && curlen < MAX_CMDLINE) {
+					current[position] = ' ';
+					curlen++;
+					position++;
+					putchar(' ');
+				}
+			} else {
+				printf("%s> ", prompt);
+				for (i=0; i<curlen;i++)
+					putchar(current[i]);
+				position += strlen(tmp);
+			}
+			rdln_print_c('\b', curlen-position);
+			continue;
+		}
+		if (c == 0x1b) {
+			c = _getc(input);
+			if (c!= 0x5b)
+				continue;
+			c = _getc(input);
+			if (c == 0x44) { /* Left */
+				if (position > 0) {
+					putchar('\b');
+					position--;
+				}
+				continue;
+			}
+			if (c == 0x43) { /* Right */
+				if (position < curlen) {
+					putchar(current[position]);
+					position++;
+				}
+				continue;
+			}
+			if (c == 0x41 || c == 0x42) { /* Up,down */
+				rdln_print_c('\b',position);
+				rdln_print_c(' ',curlen);
+				rdln_print_c('\b',curlen);
+				if (c == 0x41)
+					histposition--;
+				else
+					histposition++;
+				if (histposition < 0)
+					histposition = KCONSOLE_HISTORY -1 ;
+				else
+					histposition =  histposition % KCONSOLE_HISTORY;
+				current = history[histposition];
+				printf("%s", current);
+				curlen = strlen(current);
+				position = curlen;
+				continue;
+			}
+			continue;
+		}
+		if (curlen >= MAX_CMDLINE)
+			continue;
+
+		insert_char(current, c, position);
+
+		curlen++;
+		for (i=position;i<curlen;i++)
+			putchar(current[i]);
+		position++;
+		rdln_print_c('\b',curlen-position);
+	} 
+	histposition++;
+	histposition = histposition % KCONSOLE_HISTORY;
+	current[curlen] = '\0';
+	return current;
+}
+
 /** Kernel console managing thread.
  *
@@ -144,7 +369,7 @@
 void kconsole(void *arg)
 {
-	char cmdline[MAX_CMDLINE+1];
 	cmd_info_t *cmd_info;
 	count_t len;
+	char *cmdline;
 
 	if (!stdin) {
@@ -154,8 +379,8 @@
 	
 	while (true) {
-		printf("%s> ", __FUNCTION__);
-		if (!(len = gets(stdin, cmdline, sizeof(cmdline))))
-			continue;
-		cmdline[len] = '\0';
+		cmdline = clever_readline(__FUNCTION__, stdin);
+		len = strlen(cmdline);
+		if (!len)
+			continue;
 		cmd_info = parse_cmdline(cmdline, len);
 		if (!cmd_info)
Index: generic/src/debug/symtab.c
===================================================================
--- generic/src/debug/symtab.c	(revision 54aff986b661048892fa3f1d7a529a7604f2f556)
+++ generic/src/debug/symtab.c	(revision 0c8e69204d1c8675761780e4b928c137593c09fc)
@@ -56,8 +56,47 @@
 }
 
+/** Find symbols that match the parameter forward and print them 
+ *
+ * @param name - search string
+ * @param startpos - starting position, changes to found position
+ * @return Pointer to the part of string that should be completed or NULL
+ */
+static char * symtab_search_one(const char *name, int *startpos)
+{
+	int namelen = strlen(name);
+	char *curname;
+	int i,j;
+	char *foundsym = NULL;
+	int foundpos = 0;
+	int colonoffset = -1;
+
+	for (i=0;name[i];i++)
+		if (name[i] == ':') {
+			colonoffset = i;
+			break;
+		}
+
+	for (i=*startpos;symbol_table[i].address_le;++i) {
+		/* Find a ':' in name */
+		curname = symbol_table[i].symbol_name;
+		for (j=0; curname[j] && curname[j] != ':'; j++)
+			;
+		if (!curname[j])
+			continue;
+		j -= colonoffset;
+		curname += j;
+		if (strlen(curname) < namelen)
+			continue;
+		if (strncmp(curname, name, namelen) == 0) {
+			*startpos = i;
+			return curname+namelen;
+		}
+	}
+	return NULL;
+}
+
 /** Return address that corresponds to the entry
  *
- * Search symbol table, and if the address ENDS with
- * the parameter, return value
+ * Search symbol table, and if there is one match, return it
  *
  * @param name Name of the symbol
@@ -66,46 +105,82 @@
 __address get_symbol_addr(const char *name)
 {
-	count_t i;
 	count_t found = 0;
-	count_t found_pos;
+	__address addr = NULL;
+	char *hint;
+	int i;
 
-	count_t nmlen = strlen(name);
-	count_t slen;
-
-	for (i=0;symbol_table[i].address_le;++i) {
-		slen = strlen(symbol_table[i].symbol_name);
-		if (slen < nmlen)
-			continue;
-		if (strncmp(name, symbol_table[i].symbol_name + (slen-nmlen),
-			    nmlen) == 0) {
+	i = 0;
+	while ((hint=symtab_search_one(name, &i))) {
+		if (!strlen(hint)) {
+			addr =  __u64_le2host(symbol_table[i].address_le);
 			found++;
-			found_pos = i;
 		}
+		i++;
 	}
-	if (found == 0)
-		return NULL;
-	if (found == 1)
-		return __u64_le2host(symbol_table[found_pos].address_le);
-	return ((__address) -1);
+	if (found > 1)
+		return ((__address) -1);
+	return addr;
 }
 
+/** Find symbols that match parameter and prints them */
 void symtab_print_search(const char *name)
 {
 	int i;
-	count_t nmlen = strlen(name);
-	count_t slen;
 	__address addr;
 	char *realname;
 
-	for (i=0;symbol_table[i].address_le;++i) {
-		slen = strlen(symbol_table[i].symbol_name);
-		if (slen < nmlen)
-			continue;
-		if (strncmp(name, symbol_table[i].symbol_name + (slen-nmlen),
-			    nmlen) == 0) {
-			addr =  __u64_le2host(symbol_table[i].address_le);
-			realname = symbol_table[i].symbol_name;
-			printf("0x%p: %s\n", addr, realname);
+
+	i = 0;
+	while (symtab_search_one(name, &i)) {
+		addr =  __u64_le2host(symbol_table[i].address_le);
+		realname = symbol_table[i].symbol_name;
+		printf("0x%p: %s\n", addr, realname);
+		i++;
+	}
+}
+
+/** Symtab completion
+ *
+ * @param name - Search string, completes to symbol name
+ * @returns - 0 - nothing found, 1 - success, >1 print duplicates 
+ */
+int symtab_compl(char *name)
+{
+	char output[MAX_SYMBOL_NAME+1];
+	int startpos = 0;
+	char *foundtxt;
+	int found = 0;
+	int i;
+
+	/* Do not print everything */
+	if (!strlen(name))
+		return 0;
+
+	output[0] = '\0';
+
+	while ((foundtxt = symtab_search_one(name, &startpos))) {
+		startpos++;
+		if (!found)
+			strncpy(output, foundtxt, strlen(foundtxt)+1);
+		else {
+			for (i=0; output[i] && foundtxt[i] && output[i]==foundtxt[i]; i++)
+				;
+			output[i] = '\0';
+		}
+		found++;
+	}
+	if (!found)
+		return 0;
+
+	if (found > 1) {
+		printf("\n");
+		startpos = 0;
+		while ((foundtxt = symtab_search_one(name, &startpos))) {
+			printf("%s\n", symbol_table[startpos].symbol_name);
+			startpos++;
 		}
 	}
+	strncpy(name, output, MAX_SYMBOL_NAME);
+	return found;
+	
 }
Index: generic/src/lib/func.c
===================================================================
--- generic/src/lib/func.c	(revision 54aff986b661048892fa3f1d7a529a7604f2f556)
+++ generic/src/lib/func.c	(revision 0c8e69204d1c8675761780e4b928c137593c09fc)
@@ -80,5 +80,5 @@
  * @param len Maximal length for comparison.
  *
- * @return 0 if the strings are equal, 1 otherwise.
+ * @return 0 if the strings are equal, -1 if first is smaller, 1 if second smaller.
  *
  */
@@ -88,9 +88,14 @@
 	
 	i = 0;
-	while ((i < len) && (src[i] == dst[i])) {
-		if ((i == len - 1) || (src[i] == '\0'))
-			return 0;
-		i++;
+	for (;*src && *dst && i < len;src++,dst++,i++) {
+		if (*src < *dst)
+			return -1;
+		if (*src > *dst)
+			return 1;
 	}
+	if (i == len || *src == *dst)
+		return 0;
+	if (*src < *dst)
+		return -1;
 	return 1;
 }
