Index: kernel/generic/src/console/kconsole.c
===================================================================
--- kernel/generic/src/console/kconsole.c	(revision 06b785f8cd841eaeec20587b753477850c12723b)
+++ kernel/generic/src/console/kconsole.c	(revision 9be1d58c0982bff8d79f4b3723dbfa968d1053a6)
@@ -32,8 +32,9 @@
 
 /**
- * @file	kconsole.c
- * @brief	Kernel console.
+ * @file  kconsole.c
+ * @brief Kernel console.
  *
  * This file contains kernel thread managing the kernel console.
+ *
  */
 
@@ -57,4 +58,5 @@
 #include <errno.h>
 #include <putchar.h>
+#include <string.h>
 
 /** Simple kernel console.
@@ -65,5 +67,5 @@
  * register their own commands.
  */
- 
+
 /** Locking.
  *
@@ -80,12 +82,10 @@
  * lower address must be locked first.
  */
- 
-SPINLOCK_INITIALIZE(cmd_lock);	/**< Lock protecting command list. */
-LIST_INITIALIZE(cmd_head);	/**< Command list. */
-
-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] = {};
+
+SPINLOCK_INITIALIZE(cmd_lock);  /**< Lock protecting command list. */
+LIST_INITIALIZE(cmd_head);      /**< Command list. */
+
+static wchar_t history[KCONSOLE_HISTORY][MAX_CMDLINE] = {};
+static count_t history_pos = 0;
 
 /** Initialize kconsole data structures
@@ -98,8 +98,8 @@
 {
 	unsigned int i;
-
+	
 	cmd_init();
 	for (i = 0; i < KCONSOLE_HISTORY; i++)
-		history[i][0] = '\0';
+		history[i][0] = 0;
 }
 
@@ -108,7 +108,8 @@
  * @param cmd Structure describing the command.
  *
- * @return 0 on failure, 1 on success.
- */
-int cmd_register(cmd_info_t *cmd)
+ * @return False on failure, true on success.
+ *
+ */
+bool cmd_register(cmd_info_t *cmd)
 {
 	link_t *cur;
@@ -120,14 +121,12 @@
 	 */
 	for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
-		cmd_info_t *hlp;
-		
-		hlp = list_get_instance(cur, cmd_info_t, link);
-
+		cmd_info_t *hlp = list_get_instance(cur, cmd_info_t, link);
+		
 		if (hlp == cmd) {
 			/* The command is already there. */
 			spinlock_unlock(&cmd_lock);
-			return 0;
-		}
-
+			return false;
+		}
+		
 		/* Avoid deadlock. */
 		if (hlp < cmd) {
@@ -138,11 +137,11 @@
 			spinlock_lock(&hlp->lock);
 		}
-		if ((strncmp(hlp->name, cmd->name, max(str_size(cmd->name),
-		    str_size(hlp->name))) == 0)) {
+		
+		if (str_cmp(hlp->name, cmd->name) == 0) {
 			/* The command is already there. */
 			spinlock_unlock(&hlp->lock);
 			spinlock_unlock(&cmd->lock);
 			spinlock_unlock(&cmd_lock);
-			return 0;
+			return false;
 		}
 		
@@ -157,9 +156,9 @@
 	
 	spinlock_unlock(&cmd_lock);
-	return 1;
+	return true;
 }
 
 /** Print count times a character */
-static void rdln_print_c(wchar_t ch, count_t count)
+static void print_cc(wchar_t ch, count_t count)
 {
 	count_t i;
@@ -168,243 +167,246 @@
 }
 
-/** Insert character to string */
-static void insert_char(char *str, char ch, int pos)
-{
-	int i;
-	
-	for (i = str_size(str); i > pos; i--)
-		str[i] = str[i - 1];
-	str[pos] = ch;
-}
-
 /** Try to find a command beginning with prefix */
-static const char *cmdtab_search_one(const char *name,link_t **startpos)
-{
-	size_t namelen = str_size(name);
-	const char *curname;
-
+static const char *cmdtab_search_one(const char *name, link_t **startpos)
+{
+	count_t namelen = str_length(name);
+	
 	spinlock_lock(&cmd_lock);
-
-	if (!*startpos)
+	
+	if (*startpos == NULL)
 		*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 (str_size(curname) < namelen)
+		cmd_info_t *hlp = list_get_instance(*startpos, cmd_info_t, link);
+		
+		const char *curname = hlp->name;
+		if (str_length(curname) < namelen)
 			continue;
-		if (strncmp(curname, name, namelen) == 0) {
-			spinlock_unlock(&cmd_lock);	
-			return curname+namelen;
-		}
-	}
-	spinlock_unlock(&cmd_lock);	
+		
+		if (str_lcmp(curname, name, namelen) == 0) {
+			spinlock_unlock(&cmd_lock);
+			return (curname + str_lsize(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)
-{
-	static char output[/*MAX_SYMBOL_NAME*/128 + 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, str_size(foundtxt) + 1);
-		else {
-			for (i = 0; output[i] && foundtxt[i] &&
-			    output[i] == foundtxt[i]; i++)
-				;
-			output[i] = '\0';
-		}
+/** Command completion of the commands
+ *
+ * @param name String to match, changed to hint on exit
+ * @param size Input buffer size
+ *
+ * @return Number of found matches
+ *
+ */
+static int cmdtab_compl(char *input, size_t size)
+{
+	const char *name = input;
+	
+	count_t found = 0;
+	link_t *pos = NULL;
+	const char *hint;
+	char output[MAX_CMDLINE];
+	
+	output[0] = 0;
+	
+	while ((hint = cmdtab_search_one(name, &pos))) {
+		if ((found == 0) || (str_length(output) > str_length(hint)))
+			str_ncpy(output, hint, MAX_CMDLINE);
+		
+		pos = pos->next;
 		found++;
 	}
-	if (!found)
-		return 0;
-
-	if (found > 1 && !str_size(output)) {
+	
+	if ((found > 1) && (str_length(output) != 0)) {
 		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, 128/*MAX_SYMBOL_NAME*/);
+		pos = NULL;
+		while ((hint = 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);
+			pos = pos->next;
+		}
+	}
+	
+	if (found > 0)
+		str_ncpy(input, output, size);
+	
 	return found;
 }
 
-static char *clever_readline(const char *prompt, indev_t *input)
-{
-	static int histposition = 0;
-
-	static char tmp[MAX_CMDLINE + 1];
-	int curlen = 0, position = 0;
-	char *current = history[histposition];
-	int i;
-	char mod; /* Command Modifier */
-	char c;
-
+static wchar_t *clever_readline(const char *prompt, indev_t *indev)
+{
 	printf("%s> ", prompt);
-	while (1) {
-		c = _getc(input);
-		if (c == '\n') {
-			putchar(c);
+	
+	count_t position = 0;
+	wchar_t *current = history[history_pos];
+	current[0] = 0;
+	
+	while (true) {
+		wchar_t ch = _getc(indev);
+		
+		if (ch == '\n') {
+			/* Enter */
+			putchar(ch);
 			break;
 		}
-		if (c == '\b') { /* Backspace */
+		
+		if (ch == '\b') {
+			/* Backspace */
 			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') { /* Tabulator */
-			int found;
-
+			
+			if (wstr_remove(current, position - 1)) {
+				putchar('\b');
+				printf("%ls", current + position);
+				position--;
+				print_cc('\b', wstr_length(current) - position);
+				continue;
+			}
+		}
+		
+		if (ch == '\t') {
+			/* Tab completion */
+			
 			/* Move to the end of the word */
-			for (; position < curlen && current[position] != ' ';
+			for (; (current[position] != 0) && (!isspace(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 (position == 0)
+				continue;
+			
+			/* Find the beginning of the word
+			   and copy it to tmp */
+			count_t beg;
+			for (beg = position - 1; (beg > 0) && (!isspace(current[beg]));
+			    beg--);
+			
+			if (isspace(current[beg]))
+				beg++;
+			
+			char tmp[STR_BOUNDS(MAX_CMDLINE)];
+			wstr_nstr(tmp, current + beg, position - beg + 1);
+			
+			int found;
+			if (beg == 0) {
+				/* Command completion */
+				found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE));
+			} else {
+				/* Symbol completion */
+				found = symtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE));
 			}
-
-			if (found == 0) 
+			
+			if (found == 0)
 				continue;
-			for (i = 0; tmp[i] && curlen < MAX_CMDLINE;
-			    i++, curlen++)
-				insert_char(current, tmp[i], i + position);
-
-			if (str_size(tmp) || found == 1) { /* If we have a hint */
-				for (i = position; i < curlen; i++) 
-					putchar(current[i]);
-				position += str_size(tmp);
-				/* Add space to end */
-				if (found == 1 && position == curlen &&
-				    curlen < MAX_CMDLINE) {
-					current[position] = ' ';
-					curlen++;
-					position++;
-					putchar(' ');
+			
+			size_t off = 0;
+			count_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 ((str_length(tmp) > 0) || (found == 1)) {
+				/* We have a hint */
+				printf("%ls", current + position);
+				print_cc('\b', wstr_length(current) - position);
+				position += str_length(tmp);
+				
+				if ((found == 1) && (position == wstr_length(current))) {
+					if (wstr_linsert(current, ' ', position, MAX_CMDLINE)) {
+						printf("%ls", current + position);
+						position++;
+					}
 				}
-			} else { /* No hint, table was printed */
+			} else {
+				/* No unique hint, list was printed */
 				printf("%s> ", prompt);
-				for (i = 0; i < curlen; i++)
-					putchar(current[i]);
-				position += str_size(tmp);
+				printf("%ls", current);
+				position += str_length(tmp);
 			}
-			rdln_print_c('\b', curlen - position);
+			
+			print_cc('\b', wstr_length(current) - position);
 			continue;
 		}
-		if (c == 0x1b) { /* Special command */
-			mod = _getc(input);
-			c = _getc(input);
-
-			if (mod != 0x5b && mod != 0x4f)
+		
+		if (ch == 0x1b) {
+			/* Special command */
+			wchar_t mod = _getc(indev);
+			wchar_t ch = _getc(indev);
+			
+			if ((mod != 0x5b) && (mod != 0x4f))
 				continue;
-
-			if (c == 0x33 && _getc(input) == 0x7e) {
+			
+			if ((ch == 0x33) && (_getc(indev) == 0x7e)) {
 				/* Delete */
-				if (position == curlen)
+				if (position == wstr_length(current))
 					continue;
-				for (i = position + 1; i < curlen; i++) {
-					putchar(current[i]);
-					current[i - 1] = current[i];
+				
+				if (wstr_remove(current, position)) {
+					putchar('\b');
+					printf("%ls", current + position);
+					position--;
+					print_cc('\b', wstr_length(current) - position);
 				}
-				putchar(' ');
-				rdln_print_c('\b', curlen - position);
-				curlen--;
-			} else if (c == 0x48) { /* Home */
-				rdln_print_c('\b', position);
+			} else if (ch == 0x48) {
+				/* Home */
+				print_cc('\b', position);
 				position = 0;
-			} else if (c == 0x46) {  /* End */
-				for (i = position; i < curlen; i++)
-					putchar(current[i]);
-				position = curlen;
-			} else if (c == 0x44) { /* Left */
+			} else if (ch == 0x46) {
+				/* End */
+				printf("%ls", current + position);
+				position = wstr_length(current);
+			} else if (ch == 0x44) {
+				/* Left */
 				if (position > 0) {
 					putchar('\b');
 					position--;
 				}
-				continue;
-			} else if (c == 0x43) { /* Right */
-				if (position < curlen) {
+			} else if (ch == 0x43) {
+				/* Right */
+				if (position < wstr_length(current)) {
 					putchar(current[position]);
 					position++;
 				}
-				continue;
-			} else if (c == 0x41 || c == 0x42) { 
-                                /* Up, down */
-				rdln_print_c('\b', position);
-				rdln_print_c(' ', curlen);
-				rdln_print_c('\b', curlen);
-				if (c == 0x41) /* Up */
-					histposition--;
-				else
-					histposition++;
-				if (histposition < 0) {
-					histposition = KCONSOLE_HISTORY - 1;
+			} else if ((ch == 0x41) || (ch == 0x42)) {
+				/* Up, down */
+				print_cc('\b', position);
+				print_cc(' ', wstr_length(current));
+				print_cc('\b', wstr_length(current));
+				
+				if (ch == 0x41) {
+					/* Up */
+					if (history_pos == 0)
+						history_pos = KCONSOLE_HISTORY - 1;
+					else
+						history_pos--;
 				} else {
-					histposition =
-					    histposition % KCONSOLE_HISTORY;
+					/* Down */
+					history_pos++;
+					history_pos = history_pos % KCONSOLE_HISTORY;
 				}
-				current = history[histposition];
-				printf("%s", current);
-				curlen = str_size(current);
-				position = curlen;
-				continue;
+				current = history[history_pos];
+				printf("%ls", current);
+				position = wstr_length(current);
 			}
 			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);
-	} 
-	if (curlen) {
-		histposition++;
-		histposition = histposition % KCONSOLE_HISTORY;
-	}
-	current[curlen] = '\0';
+		
+		if (wstr_linsert(current, ch, position, MAX_CMDLINE)) {
+			printf("%ls", current + position);
+			position++;
+			print_cc('\b', wstr_length(current) - position);
+		}
+	}
+	
+	if (wstr_length(current) > 0) {
+		history_pos++;
+		history_pos = history_pos % KCONSOLE_HISTORY;
+	}
+	
 	return current;
 }
@@ -415,64 +417,8 @@
 }
 
-/** Kernel console prompt.
- *
- * @param prompt Kernel console prompt (e.g kconsole/panic).
- * @param msg    Message to display in the beginning.
- * @param kcon   Wait for keypress to show the prompt
- *               and never exit.
- *
- */
-void kconsole(char *prompt, char *msg, bool kcon)
-{
-	cmd_info_t *cmd_info;
-	count_t len;
-	char *cmdline;
-	
-	if (!stdin) {
-		LOG("No stdin for kernel console");
-		return;
-	}
-	
-	if (msg)
-		printf("%s", msg);
-	
-	if (kcon)
-		_getc(stdin);
-	else
-		printf("Type \"exit\" to leave the console.\n");
-	
-	while (true) {
-		cmdline = clever_readline((char *) prompt, stdin);
-		len = str_size(cmdline);
-		if (!len)
-			continue;
-		
-		if ((!kcon) && (len == 4) && (strncmp(cmdline, "exit", 4) == 0))
-			break;
-		
-		cmd_info = parse_cmdline(cmdline, len);
-		if (!cmd_info)
-			continue;
-		
-		(void) cmd_info->func(cmd_info->argv);
-	}
-}
-
-/** Kernel console managing thread.
- *
- */
-void kconsole_thread(void *data)
-{
-	kconsole("kconsole", "Kernel console ready (press any key to activate)\n", true);
-}
-
-static int parse_int_arg(char *text, size_t len, unative_t *result)
-{
-	uintptr_t symaddr;
+static bool parse_int_arg(const char *text, size_t len, unative_t *result)
+{
 	bool isaddr = false;
 	bool isptr = false;
-	int rc;
-
-	static char symname[MAX_SYMBOL_NAME];
 	
 	/* If we get a name, try to find it in symbol table */
@@ -486,65 +432,111 @@
 		len--;
 	}
-	if (text[0] < '0' || text[0] > '9') {
-		strncpy(symname, text, min(len + 1, MAX_SYMBOL_NAME));
-		rc = symtab_addr_lookup(symname, &symaddr);
+	
+	if ((text[0] < '0') || (text[0] > '9')) {
+		char symname[MAX_SYMBOL_NAME];
+		str_ncpy(symname, text, min(len + 1, MAX_SYMBOL_NAME));
+		
+		uintptr_t symaddr;
+		int rc = symtab_addr_lookup(symname, &symaddr);
 		switch (rc) {
 		case ENOENT:
 			printf("Symbol %s not found.\n", symname);
-			return -1;
+			return false;
 		case EOVERFLOW:
 			printf("Duplicate symbol %s.\n", symname);
 			symtab_print_search(symname);
-			return -1;
-		default:
+			return false;
+		case ENOTSUP:
 			printf("No symbol information available.\n");
-			return -1;
-		}
-
+			return false;
+		}
+		
 		if (isaddr)
-			*result = (unative_t)symaddr;
+			*result = (unative_t) symaddr;
 		else if (isptr)
-			*result = **((unative_t **)symaddr);
+			*result = **((unative_t **) symaddr);
 		else
-			*result = *((unative_t *)symaddr);
-	} else { /* It's a number - convert it */
+			*result = *((unative_t *) symaddr);
+	} else {
+		/* It's a number - convert it */
 		*result = atoi(text);
 		if (isptr)
-			*result = *((unative_t *)*result);
-	}
-
-	return 0;
+			*result = *((unative_t *) *result);
+	}
+	
+	return true;
+}
+
+/** Parse argument.
+ *
+ * Find start and end positions of command line argument.
+ *
+ * @param cmdline Command line as read from the input device.
+ * @param size    Size (in bytes) of the string.
+ * @param start   On entry, 'start' contains pointer to the offset
+ *                of the first unprocessed character of cmdline.
+ *                On successful exit, it marks beginning of the next argument.
+ * @param end     Undefined on entry. On exit, 'end' is the offset of the first
+ *                character behind the next argument.
+ *
+ * @return False on failure, true on success.
+ *
+ */
+static bool parse_argument(const char *cmdline, size_t size, size_t *start, size_t *end)
+{
+	ASSERT(start != NULL);
+	ASSERT(end != NULL);
+	
+	bool found_start = false;
+	size_t offset = *start;
+	size_t prev = *start;
+	wchar_t ch;
+	
+	while ((ch = str_decode(cmdline, &offset, size)) != 0) {
+		if (!found_start) {
+			if (!isspace(ch)) {
+				*start = prev;
+				found_start = true;
+			}
+		} else {
+			if (isspace(ch))
+				break;
+		}
+		
+		prev = offset;
+	}
+	*end = offset;
+	
+	return found_start;
 }
 
 /** Parse command line.
  *
- * @param cmdline Command line as read from input device.
- * @param len Command line length.
+ * @param cmdline Command line as read from input device. 
+ * @param size    Size (in bytes) of the string.
  *
  * @return Structure describing the command.
- */
-cmd_info_t *parse_cmdline(char *cmdline, size_t len)
-{
-	index_t start = 0, end = 0;
+ *
+ */
+static cmd_info_t *parse_cmdline(const char *cmdline, size_t size)
+{
+	size_t start = 0;
+	size_t end = 0;
+	if (!parse_argument(cmdline, size, &start, &end)) {
+		/* Command line did not contain alphanumeric word. */
+		return NULL;
+	}
+	spinlock_lock(&cmd_lock);
+	
 	cmd_info_t *cmd = NULL;
 	link_t *cur;
-	count_t i;
-	int error = 0;
-	
-	if (!parse_argument(cmdline, len, &start, &end)) {
-		/* Command line did not contain alphanumeric word. */
-		return NULL;
-	}
-
-	spinlock_lock(&cmd_lock);
 	
 	for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
-		cmd_info_t *hlp;
-		
-		hlp = list_get_instance(cur, cmd_info_t, link);
+		cmd_info_t *hlp = list_get_instance(cur, cmd_info_t, link);
 		spinlock_lock(&hlp->lock);
 		
-		if (strncmp(hlp->name, &cmdline[start], max(str_size(hlp->name),
-		    end - start + 1)) == 0) {
+		if (str_lcmp(hlp->name, cmdline + start,
+		    max(str_length(hlp->name),
+		    str_nlength(cmdline + start, (count_t) (end - start) - 1))) == 0) {
 			cmd = hlp;
 			break;
@@ -554,5 +546,5 @@
 	}
 	
-	spinlock_unlock(&cmd_lock);	
+	spinlock_unlock(&cmd_lock);
 	
 	if (!cmd) {
@@ -561,5 +553,5 @@
 		return NULL;
 	}
-
+	
 	/* cmd == hlp is locked */
 	
@@ -570,9 +562,10 @@
 	 * structure.
 	 */
-
+	
+	bool error = false;
+	count_t i;
 	for (i = 0; i < cmd->argc; i++) {
-		char *buf;
-		start = end + 1;
-		if (!parse_argument(cmdline, len, &start, &end)) {
+		start = end;
+		if (!parse_argument(cmdline, size, &start, &end)) {
 			printf("Too few arguments.\n");
 			spinlock_unlock(&cmd->lock);
@@ -580,40 +573,40 @@
 		}
 		
-		error = 0;
+		char *buf;
 		switch (cmd->argv[i].type) {
 		case ARG_TYPE_STRING:
 			buf = (char *) cmd->argv[i].buffer;
-			strncpy(buf, (const char *) &cmdline[start],
-			    min((end - start) + 2, cmd->argv[i].len));
-			buf[min((end - start) + 1, cmd->argv[i].len - 1)] =
-			    '\0';
+			str_ncpy(buf, cmdline + start,
+			    min((end - start) + 1, cmd->argv[i].len));
 			break;
-		case ARG_TYPE_INT: 
-			if (parse_int_arg(cmdline + start, end - start + 1, 
+		case ARG_TYPE_INT:
+			if (!parse_int_arg(cmdline + start, end - start,
 			    &cmd->argv[i].intval))
-				error = 1;
+				error = true;
 			break;
 		case ARG_TYPE_VAR:
-			if (start != end && cmdline[start] == '"' &&
-			    cmdline[end] == '"') {
-				buf = (char *) cmd->argv[i].buffer;
-				strncpy(buf, (const char *) &cmdline[start + 1],
-				    min((end-start), cmd->argv[i].len));
-				buf[min((end - start), cmd->argv[i].len - 1)] =
-				    '\0';
-				cmd->argv[i].intval = (unative_t) buf;
-				cmd->argv[i].vartype = ARG_TYPE_STRING;
-			} else if (!parse_int_arg(cmdline + start,
-			    end - start + 1, &cmd->argv[i].intval)) {
+			if ((start < end - 1) && (cmdline[start] == '"')) {
+				if (cmdline[end - 1] == '"') {
+					buf = (char *) cmd->argv[i].buffer;
+					str_ncpy(buf, cmdline + start + 1,
+					    min((end - start) - 1, cmd->argv[i].len));
+					cmd->argv[i].intval = (unative_t) buf;
+					cmd->argv[i].vartype = ARG_TYPE_STRING;
+				} else {
+					printf("Wrong synxtax.\n");
+					error = true;
+				}
+			} else if (parse_int_arg(cmdline + start,
+			    end - start, &cmd->argv[i].intval)) {
 				cmd->argv[i].vartype = ARG_TYPE_INT;
 			} else {
 				printf("Unrecognized variable argument.\n");
-				error = 1;
+				error = true;
 			}
 			break;
 		case ARG_TYPE_INVALID:
 		default:
-			printf("invalid argument type\n");
-			error = 1;
+			printf("Invalid argument type\n");
+			error = true;
 			break;
 		}
@@ -625,6 +618,6 @@
 	}
 	
-	start = end + 1;
-	if (parse_argument(cmdline, len, &start, &end)) {
+	start = end;
+	if (parse_argument(cmdline, size, &start, &end)) {
 		printf("Too many arguments.\n");
 		spinlock_unlock(&cmd->lock);
@@ -636,40 +629,53 @@
 }
 
-/** Parse argument.
- *
- * Find start and end positions of command line argument.
- *
- * @param cmdline Command line as read from the input device.
- * @param len Number of characters in cmdline.
- * @param start On entry, 'start' contains pointer to the index 
- *        of first unprocessed character of cmdline.
- *        On successful exit, it marks beginning of the next argument.
- * @param end Undefined on entry. On exit, 'end' points to the last character
- *        of the next argument.
- *
- * @return false on failure, true on success.
- */
-bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end)
-{
-	index_t i;
-	bool found_start = false;
-	
-	ASSERT(start != NULL);
-	ASSERT(end != NULL);
-	
-	for (i = *start; i < len; i++) {
-		if (!found_start) {
-			if (isspace(cmdline[i]))
-				(*start)++;
-			else
-				found_start = true;
-		} else {
-			if (isspace(cmdline[i]))
-				break;
-		}
-	}
-	*end = i - 1;
-
-	return found_start;
+/** Kernel console prompt.
+ *
+ * @param prompt Kernel console prompt (e.g kconsole/panic).
+ * @param msg    Message to display in the beginning.
+ * @param kcon   Wait for keypress to show the prompt
+ *               and never exit.
+ *
+ */
+void kconsole(char *prompt, char *msg, bool kcon)
+{
+	if (!stdin) {
+		LOG("No stdin for kernel console");
+		return;
+	}
+	
+	if (msg)
+		printf("%s", msg);
+	
+	if (kcon)
+		_getc(stdin);
+	else
+		printf("Type \"exit\" to leave the console.\n");
+	
+	while (true) {
+		wchar_t *tmp = clever_readline((char *) prompt, stdin);
+		count_t len = wstr_length(tmp);
+		if (!len)
+			continue;
+		
+		char cmdline[STR_BOUNDS(MAX_CMDLINE)];
+		wstr_nstr(cmdline, tmp, STR_BOUNDS(MAX_CMDLINE));
+		
+		if ((!kcon) && (len == 4) && (str_lcmp(cmdline, "exit", 4) == 0))
+			break;
+		
+		cmd_info_t *cmd_info = parse_cmdline(cmdline, STR_BOUNDS(MAX_CMDLINE));
+		if (!cmd_info)
+			continue;
+		
+		(void) cmd_info->func(cmd_info->argv);
+	}
+}
+
+/** Kernel console managing thread.
+ *
+ */
+void kconsole_thread(void *data)
+{
+	kconsole("kconsole", "Kernel console ready (press any key to activate)\n", true);
 }
 
