=== modified file 'kernel/generic/include/debug.h'
--- kernel/generic/include/debug.h	2012-04-02 15:52:07 +0000
+++ kernel/generic/include/debug.h	2012-07-04 17:43:22 +0000
@@ -36,7 +36,7 @@
 #define KERN_DEBUG_H_
 
 #include <panic.h>
-#include <symtab.h>
+#include <symtab_lookup.h>
 
 #define CALLER  ((uintptr_t) __builtin_return_address(0))
 

=== modified file 'kernel/generic/include/symtab.h'
--- kernel/generic/include/symtab.h	2012-04-02 15:52:07 +0000
+++ kernel/generic/include/symtab.h	2012-07-04 17:44:44 +0000
@@ -35,29 +35,13 @@
 #ifndef KERN_SYMTAB_H_
 #define KERN_SYMTAB_H_
 
-#include <typedefs.h>
-
-#define MAX_SYMBOL_NAME  64
-
-struct symtab_entry {
-	uint64_t address_le;
-	char symbol_name[MAX_SYMBOL_NAME];
-};
-
-extern int symtab_name_lookup(uintptr_t, const char **, uintptr_t *);
-extern const char *symtab_fmt_name_lookup(uintptr_t);
-extern int symtab_addr_lookup(const char *, uintptr_t *);
+#define MAX_TAB_HINTS 37
+
+#include <symtab_lookup.h>
+#include <console/chardev.h>
+
 extern void symtab_print_search(const char *);
-extern int symtab_compl(char *, size_t);
-
-#ifdef CONFIG_SYMTAB
-
-/** Symtable linked together by build process
- *
- */
-extern struct symtab_entry symbol_table[];
-
-#endif /* CONFIG_SYMTAB */
+extern int symtab_compl(char *, size_t, indev_t *);
 
 #endif
 

=== added file 'kernel/generic/include/symtab_lookup.h'
--- kernel/generic/include/symtab_lookup.h	1970-01-01 00:00:00 +0000
+++ kernel/generic/include/symtab_lookup.h	2012-07-04 17:43:06 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005 Ondrej Palkovsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup generic
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_SYMTAB_LOOKUP_H_
+#define KERN_SYMTAB_LOOKUP_H_
+
+#include <typedefs.h>
+
+#define MAX_SYMBOL_NAME  64
+
+struct symtab_entry {
+	uint64_t address_le;
+	char symbol_name[MAX_SYMBOL_NAME];
+};
+
+extern int symtab_name_lookup(uintptr_t, const char **, uintptr_t *);
+extern const char *symtab_fmt_name_lookup(uintptr_t);
+extern int symtab_addr_lookup(const char *, uintptr_t *);
+
+#ifdef CONFIG_SYMTAB
+
+/** Symtable linked together by build process
+ *
+ */
+extern struct symtab_entry symbol_table[];
+
+#endif /* CONFIG_SYMTAB */
+
+#endif
+
+/** @}
+ */

=== modified file 'kernel/generic/src/console/kconsole.c'
--- kernel/generic/src/console/kconsole.c	2012-04-02 15:52:07 +0000
+++ kernel/generic/src/console/kconsole.c	2012-07-04 18:15:47 +0000
@@ -200,14 +200,23 @@
  * @return Number of found matches
  *
  */
-NO_TRACE static int cmdtab_compl(char *input, size_t size)
+NO_TRACE static int cmdtab_compl(char *input, size_t size, indev_t * indev)
 {
 	const char *name = input;
 	
 	size_t found = 0;
+	/* Maximum Match Length : Length of longest matching common substring in
+	   case more than one match is found */
+	size_t max_match_len = size;
+	size_t max_match_len_tmp = size;
+	size_t input_len = str_length(input);
 	link_t *pos = NULL;
 	const char *hint;
 	char *output = malloc(MAX_CMDLINE, 0);
+	char display = 'y';
+	size_t hints_to_show = MAX_TAB_HINTS - 1;
+	size_t total_hints_shown = 0;
+	char continue_showing_hints = 'y';
 	
 	output[0] = 0;
 	
@@ -219,14 +228,58 @@
 		found++;
 	}
 	
+	/* If possible completions are more than MAX_TAB_HINTS, ask user whether to display them or not. */
+	if (found > MAX_TAB_HINTS) {
+		printf("\nDisplay all %d possibilities? (y or n)", found);
+		do {
+			display = indev_pop_character(indev);
+		} while (display != 'y' && display != 'n' && display != 'Y' && display != 'N');
+	}
+	
 	if ((found > 1) && (str_length(output) != 0)) {
 		printf("\n");
 		pos = NULL;
 		while (cmdtab_search_one(name, &pos)) {
 			cmd_info_t *hlp = list_get_instance(pos, cmd_info_t, link);
-			printf("%s (%s)\n", hlp->name, hlp->description);
+
+			if (display == 'y' || display == 'Y') { /* We are still showing hints */
+				printf("%s (%s)\n", hlp->name, hlp->description);
+				--hints_to_show;
+				++total_hints_shown;
+
+				if (hints_to_show == 0 && total_hints_shown != found) { /* Time to ask user to continue */
+					printf("--More--");
+					do {
+						continue_showing_hints = indev_pop_character(indev);
+						if (continue_showing_hints == 'y' || continue_showing_hints == 'Y'
+								|| continue_showing_hints == ' ') {
+							hints_to_show = MAX_TAB_HINTS - 1; /* Display a full page again */
+							break;
+						}
+
+						if (continue_showing_hints == 'n' || continue_showing_hints == 'N'
+								|| continue_showing_hints == 'q' || continue_showing_hints == 'Q') {
+							display = 'n'; /* Stop displaying hints */
+							break;
+						}
+
+						if (continue_showing_hints == '\n') {
+							hints_to_show = 1; /* Show one more hint */
+							break;
+						}
+					} while (1);
+
+					printf("\r         \r"); /* Delete the --More-- option */
+				}
+			}
+
 			pos = pos->next;
+			for(max_match_len_tmp = 0; output[max_match_len_tmp] == hlp->name[input_len + max_match_len_tmp]
+					&& max_match_len_tmp < max_match_len; ++max_match_len_tmp);
+			max_match_len = max_match_len_tmp;
 		}
+		/* keep only the characters common in all completions */
+		output[max_match_len] = 0;
 	}
 	
 	if (found > 0)
@@ -293,33 +346,36 @@
 			int found;
 			if (beg == 0) {
 				/* Command completion */
-				found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE));
+				found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev);
 			} else {
 				/* Symbol completion */
-				found = symtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE));
+				found = symtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev);
 			}
 			
 			if (found == 0)
 				continue;
+
+			/* We have hints, may be many. In case of more than one hint,
+			   tmp will contain the common prefix. */
+			size_t off = 0;
+			size_t i = 0;
+			while ((ch = str_decode(tmp, &off, STR_NO_LIMIT)) != 0) {
+				if (!wstr_linsert(current, ch, position + i, MAX_CMDLINE))
+					break;
+				i++;
+			}
 			
 			if (found > 1) {
 				/* No unique hint, list was printed */
 				printf("%s> ", prompt);
 				printf("%ls", current);
+				position += str_length(tmp);
 				print_cc('\b', wstr_length(current) - position);
 				continue;
 			}
 			
 			/* We have a hint */
 			
-			size_t off = 0;
-			size_t i = 0;
-			while ((ch = str_decode(tmp, &off, STR_NO_LIMIT)) != 0) {
-				if (!wstr_linsert(current, ch, position + i, MAX_CMDLINE))
-					break;
-				i++;
-			}
-			
 			printf("%ls", current + position);
 			position += str_length(tmp);
 			print_cc('\b', wstr_length(current) - position);
@@ -539,7 +595,7 @@
 
 /** Parse command line.
  *
- * @param cmdline Command line as read from input device. 
+ * @param cmdline Command line as read from input device.
  * @param size    Size (in bytes) of the string.
  *
  * @return Structure describing the command.

=== modified file 'kernel/generic/src/debug/symtab.c'
--- kernel/generic/src/debug/symtab.c	2012-04-02 15:52:07 +0000
+++ kernel/generic/src/debug/symtab.c	2012-07-04 18:17:39 +0000
@@ -208,7 +208,7 @@
  * @return 0 - nothing found, 1 - success, >1 print duplicates
  *
  */
-int symtab_compl(char *input, size_t size)
+int symtab_compl(char *input, size_t size, indev_t * indev)
 {
 #ifdef CONFIG_SYMTAB
 	const char *name = input;
@@ -225,8 +225,24 @@
 	size_t pos = 0;
 	const char *hint;
 	char output[MAX_SYMBOL_NAME];
+	/* Maximum Match Length : Length of longest matching common substring in
+	   case more than one match is found */
+	size_t max_match_len = size;
+	size_t max_match_len_tmp = size;
+	size_t input_len = str_length(input);
+	char *sym_name;
+	char display = 'y';
+	size_t hints_to_show = MAX_TAB_HINTS - 1;
+	size_t total_hints_shown = 0;
+	char continue_showing_hints = 'y';
 	
 	output[0] = 0;
+
+	while ((hint = symtab_search_one(name, &pos))) {
+		++pos;
+	}
+
+	pos = 0;
 	
 	while ((hint = symtab_search_one(name, &pos))) {
 		if ((found == 0) || (str_length(output) > str_length(hint)))
@@ -236,13 +252,58 @@
 		found++;
 	}
 	
+	/* If possible completions are more than MAX_TAB_HINTS, ask user whether to display them or not. */
+	if (found > MAX_TAB_HINTS) {
+		printf("\nDisplay all %d possibilities? (y or n)", found);
+		do {
+			display = indev_pop_character(indev);
+		} while (display != 'y' && display != 'n' && display != 'Y' && display != 'N');
+	}
+	
 	if ((found > 1) && (str_length(output) != 0)) {
 		printf("\n");
 		pos = 0;
 		while (symtab_search_one(name, &pos)) {
-			printf("%s\n", symbol_table[pos].symbol_name);
+			sym_name = symbol_table[pos].symbol_name;
 			pos++;
+
+			if (display == 'y' || display == 'Y') { /* We are still showing hints */
+				printf("%s\n", sym_name);
+				--hints_to_show;
+				++total_hints_shown;
+
+				if (hints_to_show == 0 && total_hints_shown != found) { /* Time to ask user to continue */
+					printf("--More--");
+					do {
+						continue_showing_hints = indev_pop_character(indev);
+						if (continue_showing_hints == 'y' || continue_showing_hints == 'Y'
+								|| continue_showing_hints == ' ') {
+							hints_to_show = MAX_TAB_HINTS - 1; /* Display a full page again */
+							break;
+						}
+
+						if (continue_showing_hints == 'n' || continue_showing_hints == 'N'
+								|| continue_showing_hints == 'q' || continue_showing_hints == 'Q') {
+							display = 'n'; /* Stop displaying hints */
+							break;
+						}
+
+						if (continue_showing_hints == '\n') {
+							hints_to_show = 1; /* Show one more hint */
+							break;
+						}
+					} while (1);
+
+					printf("\r         \r"); /* Delete the --More-- option */
+				}
+			}
+
+			for(max_match_len_tmp = 0; output[max_match_len_tmp] == sym_name[input_len + max_match_len_tmp]
+					&& max_match_len_tmp < max_match_len; ++max_match_len_tmp);
+			max_match_len = max_match_len_tmp;
 		}
+		/* keep only the characters common in all completions */
+		output[max_match_len] = 0;
 	}
 	
 	if (found > 0)

