Index: uspace/app/bdsh/input.c
===================================================================
--- uspace/app/bdsh/input.c	(revision 8d04f7097b62134326c7132337e2989e9f5643a1)
+++ uspace/app/bdsh/input.c	(revision 84b14e230361e29caa5996ca93c28c1323646630)
@@ -125,5 +125,6 @@
 	int i;
 
-	console_goto(fphone(stdout), ti->col0 + start, ti->row0);
+	console_goto(fphone(stdout), (ti->col0 + start) % ti->con_cols,
+	    ti->row0 + (ti->col0 + start) / ti->con_cols);
 	printf("%ls", ti->buffer + start);
 	for (i = 0; i < pad; ++i)
@@ -134,18 +135,24 @@
 static char *tinput_get_str(tinput_t *ti)
 {
-	char *str;
-
-	str = malloc(STR_BOUNDS(ti->nc) + 1);
-	if (str == NULL)
-		return NULL;
-
-	wstr_nstr(str, ti->buffer, STR_BOUNDS(ti->nc) + 1);
-
-	return str;
+	return wstr_to_astr(ti->buffer);
 }
 
 static void tinput_position_caret(tinput_t *ti)
 {
-	console_goto(fphone(stdout), ti->col0 + ti->pos, ti->row0);
+	console_goto(fphone(stdout), (ti->col0 + ti->pos) % ti->con_cols,
+	    ti->row0 + (ti->col0 + ti->pos) / ti->con_cols);
+}
+
+/** Update row0 in case the screen could have scrolled. */
+static void tinput_update_origin(tinput_t *ti)
+{
+	int width, rows;
+
+	width = ti->col0 + ti->nc;
+	rows = (width / ti->con_cols) + 1;
+ 
+	/* Update row0 if the screen scrolled. */
+	if (ti->row0 + rows > ti->con_rows)
+		ti->row0 = ti->con_rows - rows;	
 }
 
@@ -153,10 +160,16 @@
 {
 	int i;
+	int new_width, new_height;
 
 	if (ti->nc == INPUT_MAX)
 		return;
 
-	if (ti->col0 + ti->nc >= ti->con_cols - 1)
-		return;
+	new_width = ti->col0 + ti->nc + 1;
+	if (new_width % ti->con_cols == 0) {
+		/* Advancing to new line. */
+		new_height = (new_width / ti->con_cols) + 1;
+		if (new_height >= ti->con_rows)
+			return; /* Disallow text longer than 1 page for now. */
+	}
 
 	for (i = ti->nc; i > ti->pos; --i)
@@ -169,4 +182,5 @@
 
 	tinput_display_tail(ti, ti->pos - 1, 0);
+	tinput_update_origin(ti);
 	tinput_position_caret(ti);
 }
@@ -247,4 +261,17 @@
 }
 
+static void tinput_seek_vertical(tinput_t *ti, seek_dir_t dir)
+{
+	if (dir == seek_forward) {
+		if (ti->pos + ti->con_cols <= ti->nc)
+			ti->pos = ti->pos + ti->con_cols;
+	} else {
+		if (ti->pos - ti->con_cols >= 0)
+			ti->pos = ti->pos - ti->con_cols;
+	}
+
+	tinput_position_caret(ti);
+}
+
 static void tinput_seek_max(tinput_t *ti, seek_dir_t dir)
 {
@@ -306,4 +333,5 @@
 	tinput_set_str(ti, ti->history[ti->hpos]);
 	tinput_display_tail(ti, 0, pad);
+	tinput_update_origin(ti);
 	tinput_position_caret(ti);
 }
@@ -330,4 +358,5 @@
 	ti->pos = 0;
 	ti->nc = 0;
+	ti->buffer[0] = '\0';
 
 	while (true) {
@@ -348,4 +377,10 @@
 				tinput_seek_word(ti, seek_forward);
 				break;
+			case KC_UP:
+				tinput_seek_vertical(ti, seek_backward);
+				break;
+			case KC_DOWN:
+				tinput_seek_vertical(ti, seek_forward);
+				break;
 			}
 		}
@@ -389,4 +424,6 @@
 
 done:
+	ti->pos = ti->nc;
+	tinput_position_caret(ti);
 	putchar('\n');
 
Index: uspace/app/edit/edit.c
===================================================================
--- uspace/app/edit/edit.c	(revision 8d04f7097b62134326c7132337e2989e9f5643a1)
+++ uspace/app/edit/edit.c	(revision 84b14e230361e29caa5996ca93c28c1323646630)
@@ -102,4 +102,7 @@
 #define ED_INFTY 65536
 
+/** Maximum filename length that can be entered. */
+#define INFNAME_MAX_LEN 128
+
 static void key_handle_unmod(console_event_t const *ev);
 static void key_handle_ctrl(console_event_t const *ev);
@@ -331,6 +334,4 @@
 }
 
-#define INPUT_MAX_LEN 64
-
 /** Ask for a file name. */
 static char *filename_prompt(char const *prompt, char const *init_value)
@@ -338,5 +339,6 @@
 	console_event_t ev;
 	char *str;
-	wchar_t buffer[INPUT_MAX_LEN + 1];
+	wchar_t buffer[INFNAME_MAX_LEN + 1];
+	int max_len;
 	int nc;
 	bool done;
@@ -349,5 +351,6 @@
 	console_set_color(con, COLOR_WHITE, COLOR_BLACK, 0);
 
-	str_to_wstr(buffer, INPUT_MAX_LEN + 1, init_value);
+	max_len = min(INFNAME_MAX_LEN, scr_columns - 4 - str_length(prompt));
+	str_to_wstr(buffer, max_len + 1, init_value);
 	nc = wstr_length(buffer);
 	done = false;
@@ -376,5 +379,5 @@
 					break;
 				default:
-					if (ev.c >= 32 && nc < INPUT_MAX_LEN) {
+					if (ev.c >= 32 && nc < max_len) {
 						putchar(ev.c);
 						fflush(stdout);
@@ -388,10 +391,5 @@
 
 	buffer[nc] = '\0';
-
-	str = malloc(STR_BOUNDS(wstr_length(buffer)) + 1);
-	if (str == NULL)
-		return NULL;
-
-	wstr_nstr(str, buffer, STR_BOUNDS(wstr_length(buffer)) + 1);
+	str = wstr_to_astr(buffer);
 
 	console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
Index: uspace/lib/libc/generic/string.c
===================================================================
--- uspace/lib/libc/generic/string.c	(revision 8d04f7097b62134326c7132337e2989e9f5643a1)
+++ uspace/lib/libc/generic/string.c	(revision 84b14e230361e29caa5996ca93c28c1323646630)
@@ -471,5 +471,5 @@
  * null-terminated and containing only complete characters.
  *
- * @param dst   Destination buffer.
+ * @param dest   Destination buffer.
  * @param count Size of the destination buffer (must be > 0).
  * @param src   Source string.
@@ -505,5 +505,5 @@
  * have to be null-terminated.
  *
- * @param dst   Destination buffer.
+ * @param dest   Destination buffer.
  * @param count Size of the destination buffer (must be > 0).
  * @param src   Source string.
@@ -537,5 +537,5 @@
  * null-terminated and containing only complete characters.
  *
- * @param dst   Destination buffer.
+ * @param dest   Destination buffer.
  * @param count Size of the destination buffer.
  * @param src   Source string.
@@ -549,43 +549,88 @@
 }
 
-/** Copy NULL-terminated wide string to string
- *
- * Copy source wide string @a src to destination buffer @a dst.
- * No more than @a size bytes are written. NULL-terminator is always
- * written after the last succesfully copied character (i.e. if the
- * destination buffer is has at least 1 byte, it will be always
- * NULL-terminated).
- *
- * @param src   Source wide string.
- * @param dst   Destination buffer.
- * @param count Size of the destination buffer.
- *
- */
-void wstr_nstr(char *dst, const wchar_t *src, size_t size)
-{
-	/* No space for the NULL-terminator in the buffer */
-	if (size == 0)
-		return;
-	
+/** Convert wide string to string.
+ *
+ * Convert wide string @a src to string. The output is written to the buffer
+ * specified by @a dest and @a size. @a size must be non-zero and the string
+ * written will always be well-formed.
+ *
+ * @param dest	Destination buffer.
+ * @param size	Size of the destination buffer.
+ * @param src	Source wide string.
+ */
+void wstr_to_str(char *dest, size_t size, const wchar_t *src)
+{
 	wchar_t ch;
-	size_t src_idx = 0;
-	size_t dst_off = 0;
-	
+	size_t src_idx;
+	size_t dest_off;
+
+	/* There must be space for a null terminator in the buffer. */
+	assert(size > 0);
+	
+	src_idx = 0;
+	dest_off = 0;
+
 	while ((ch = src[src_idx++]) != 0) {
-		if (chr_encode(ch, dst, &dst_off, size) != EOK)
+		if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
 			break;
 	}
-	
-	if (dst_off >= size)
-		dst[size - 1] = 0;
-	else
-		dst[dst_off] = 0;
-}
+
+	dest[dest_off] = '\0';
+}
+
+/** Convert wide string to new string.
+ *
+ * Convert wide string @a src to string. Space for the new string is allocated
+ * on the heap.
+ *
+ * @param src	Source wide string.
+ * @return	New string.
+ */
+char *wstr_to_astr(const wchar_t *src)
+{
+	char dbuf[STR_BOUNDS(1)];
+	char *str;
+	wchar_t ch;
+
+	size_t src_idx;
+	size_t dest_off;
+	size_t dest_size;
+
+	/* Compute size of encoded string. */
+
+	src_idx = 0;
+	dest_size = 0;
+
+	while ((ch = src[src_idx++]) != 0) {
+		dest_off = 0;
+		if (chr_encode(ch, dbuf, &dest_off, STR_BOUNDS(1)) != EOK)
+			break;
+		dest_size += dest_off;
+	}
+
+	str = malloc(dest_size + 1);
+	if (str == NULL)
+		return NULL;
+
+	/* Encode string. */
+
+	src_idx = 0;
+	dest_off = 0;
+
+	while ((ch = src[src_idx++]) != 0) {
+		if (chr_encode(ch, str, &dest_off, dest_size) != EOK)
+			break;
+	}
+
+	str[dest_size] = '\0';
+	return str;
+}
+
 
 /** Convert string to wide string.
  *
  * Convert string @a src to wide string. The output is written to the
- * buffer specified by @a dest and @a size, which must have non-zero
- * size. The output will always be null-terminated.
+ * buffer specified by @a dest and @a dlen. @a dlen must be non-zero
+ * and the wide string written will always be null-terminated.
  *
  * @param dest	Destination buffer.
Index: uspace/lib/libc/include/string.h
===================================================================
--- uspace/lib/libc/include/string.h	(revision 8d04f7097b62134326c7132337e2989e9f5643a1)
+++ uspace/lib/libc/include/string.h	(revision 84b14e230361e29caa5996ca93c28c1323646630)
@@ -73,5 +73,6 @@
 extern void str_append(char *dest, size_t size, const char *src);
 
-extern void wstr_nstr(char *dst, const wchar_t *src, size_t size);
+extern void wstr_to_str(char *dest, size_t size, const wchar_t *src);
+extern char *wstr_to_astr(const wchar_t *src);
 extern void str_to_wstr(wchar_t *dest, size_t dlen, const char *src);
 
