[PATCH 10/20] app: printf: use HelenOS verison with wide char support

Jean-Christophe PLAGNIOL-VILLARD plagnioj at jcrosoft.com
Wed Mar 6 04:29:39 EST 2013


Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
---
 apps/include/stdio.h               |   21 +-
 apps/include/stdlib.h              |    3 +
 apps/include/{stdlib.h => wchar.h} |   24 +-
 apps/libc/Kconfig                  |   10 +
 apps/libc/Makefile                 |    1 +
 apps/libc/helenos/Makefile         |    4 +
 apps/libc/helenos/align.h          |   63 ++
 apps/libc/helenos/assert.h         |    2 +
 apps/libc/helenos/ctype.c          |   52 ++
 apps/libc/helenos/printf_core.c    |  905 +++++++++++++++++++
 apps/libc/helenos/printf_core.h    |   59 ++
 apps/libc/helenos/stdio.c          |  153 ++++
 apps/libc/helenos/str.c            | 1755 ++++++++++++++++++++++++++++++++++++
 apps/libc/helenos/str.h            |  135 +++
 apps/libc/helenos/vsnprintf.c      |  187 ++++
 15 files changed, 3353 insertions(+), 21 deletions(-)
 copy apps/include/{stdlib.h => wchar.h} (70%)
 create mode 100644 apps/libc/helenos/Makefile
 create mode 100644 apps/libc/helenos/align.h
 create mode 100644 apps/libc/helenos/assert.h
 create mode 100644 apps/libc/helenos/ctype.c
 create mode 100644 apps/libc/helenos/printf_core.c
 create mode 100644 apps/libc/helenos/printf_core.h
 create mode 100644 apps/libc/helenos/stdio.c
 create mode 100644 apps/libc/helenos/str.c
 create mode 100644 apps/libc/helenos/str.h
 create mode 100644 apps/libc/helenos/vsnprintf.c

diff --git a/apps/include/stdio.h b/apps/include/stdio.h
index 32a7d25..9c9720e 100644
--- a/apps/include/stdio.h
+++ b/apps/include/stdio.h
@@ -49,6 +49,16 @@ size_t fread(void *buf, size_t size, size_t nb, FILE *f);
 size_t fwrite(const void *buf, size_t size, size_t nb, FILE *f);
 int fseek(FILE *stream, long offset, int whence);
 
+int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2)));
+int vprintf(const char *fmt, va_list args);
+int sprintf(char *buf, const char *fmt, ...) __attribute__ ((format(__printf__, 2, 3)));
+int snprintf(char *buf, size_t size, const char *fmt, ...) __attribute__ ((format(__printf__, 3, 4)));
+int vsprintf(char *buf, const char *fmt, va_list args);
+char *asprintf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2)));
+char *vasprintf(const char *fmt, va_list ap);
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
 /* barebox API */
 void eputc(char c);
 int eputs(const char *str);
@@ -56,15 +66,4 @@ int tstc(void);
 int flush(int fd);
 char* itoa(int i);
 
-static int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2)));
-static inline int printf(const char *fmt, ...)
-{
-	return 0;
-}
-
-static inline int vprintf(const char *fmt, va_list args)
-{
-	return 0;
-}
-
 #endif /* __STDIO_H__ */
diff --git a/apps/include/stdlib.h b/apps/include/stdlib.h
index 7ae78ad..e08775f 100644
--- a/apps/include/stdlib.h
+++ b/apps/include/stdlib.h
@@ -26,4 +26,7 @@ int atoi(const char *s);
 long atol(const char *s);
 long long atoll(const char *s);
 
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
+
 #endif /* __STDLIB_H__ */
diff --git a/apps/include/stdlib.h b/apps/include/wchar.h
similarity index 70%
copy from apps/include/stdlib.h
copy to apps/include/wchar.h
index 7ae78ad..8610569 100644
--- a/apps/include/stdlib.h
+++ b/apps/include/wchar.h
@@ -14,16 +14,20 @@
  * this file might be covered by the GNU General Public License.
  */
 
-#ifndef __STDLIB_H__
-#define __STDLIB_H__
+#ifndef __WCHAR_H__
+#define __WCHAR_H__
 
-#define EXIT_FAILURE 1
-#define EXIT_SUCCESS 0
+#include <stdio.h>
 
-char *getenv(const char *name);
-void exit(int num);
-int atoi(const char *s);
-long atol(const char *s);
-long long atoll(const char *s);
+typedef unsigned long wchar_t;
+typedef long wint_t;
 
-#endif /* __STDLIB_H__ */
+
+#define wprintf printf
+#define fwprintf fprintf
+#define swprintf sprintf
+#define vwprintf vprintf
+#define vfwprintf vfwprintf
+#define vswprintf vswprintf
+
+#endif /* __WCHAR_H__ */
diff --git a/apps/libc/Kconfig b/apps/libc/Kconfig
index b9478b5..25b35ee 100644
--- a/apps/libc/Kconfig
+++ b/apps/libc/Kconfig
@@ -22,4 +22,14 @@ config APP_PRINTF_STACK_SIZE
 	hex "printf stack size"
 	default 0x1000
 
+choice
+	prompt "printf implementation"
+
+config APPS_PRINTF_HELENOS
+	bool "helen os"
+	help
+	  support wide char
+
+endchoice
+
 endmenu
diff --git a/apps/libc/Makefile b/apps/libc/Makefile
index 844ea9b..c84f00e 100644
--- a/apps/libc/Makefile
+++ b/apps/libc/Makefile
@@ -15,6 +15,7 @@ app-y += unistd.o
 app-$(CONFIG_APPS_MALLOC_DUMMY) += dummy_malloc.o
 app-$(CONFIG_APPS_MALLOC_TLSF) += tlsf_malloc.o tlsf.o
 app-y += string.o
+obj-$(CONFIG_APPS_PRINTF_HELENOS) += helenos/
 obj-y += sys/
 app-y += time.o
 
diff --git a/apps/libc/helenos/Makefile b/apps/libc/helenos/Makefile
new file mode 100644
index 0000000..1c34aff
--- /dev/null
+++ b/apps/libc/helenos/Makefile
@@ -0,0 +1,4 @@
+app-y += printf_core.o
+app-y += vsnprintf.o
+app-y += str.o
+app-y += stdio.o
diff --git a/apps/libc/helenos/align.h b/apps/libc/helenos/align.h
new file mode 100644
index 0000000..8ca4270
--- /dev/null
+++ b/apps/libc/helenos/align.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005 Jakub Jermar
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_ALIGN_H_
+#define LIBC_ALIGN_H_
+
+/** Align to the nearest lower address which is a power of two.
+ *
+ * @param s		Address or size to be aligned.
+ * @param a		Size of alignment, must be power of 2.
+ */
+#define ALIGN_DOWN(s, a)	((s) & ~((a) - 1))
+
+
+/** Align to the nearest higher address which is a power of two.
+ *
+ * @param s		Address or size to be aligned.
+ * @param a		Size of alignment, must be power of 2.
+ */
+#define ALIGN_UP(s, a)		((long)((s) + ((a) - 1)) & ~((long) (a) - 1))
+
+/** Round up to the nearest higher boundary.
+ *
+ * @param n		Number to be aligned.
+ * @param b		Boundary, arbitrary unsigned number.
+ */
+#define ROUND_UP(n, b)		(((n) / (b) + ((n) % (b) != 0)) * (b))
+
+#endif
+
+/** @}
+ */
diff --git a/apps/libc/helenos/assert.h b/apps/libc/helenos/assert.h
new file mode 100644
index 0000000..16fedb4
--- /dev/null
+++ b/apps/libc/helenos/assert.h
@@ -0,0 +1,2 @@
+
+#define assert(x)
diff --git a/apps/libc/helenos/ctype.c b/apps/libc/helenos/ctype.c
new file mode 100644
index 0000000..6d20da5
--- /dev/null
+++ b/apps/libc/helenos/ctype.c
@@ -0,0 +1,52 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ *  linux/lib/ctype.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#include <linux/ctype.h>
+
+unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C,			/* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,		/* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C,			/* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C,			/* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,			/* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P,			/* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D,			/* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P,			/* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,	/* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U,			/* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U,			/* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P,			/* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,	/* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L,			/* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L,			/* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C,			/* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
diff --git a/apps/libc/helenos/printf_core.c b/apps/libc/helenos/printf_core.c
new file mode 100644
index 0000000..ccfaaa9
--- /dev/null
+++ b/apps/libc/helenos/printf_core.c
@@ -0,0 +1,905 @@
+/*
+ * Copyright (c) 2001-2004 Jakub Jermar
+ * Copyright (c) 2006 Josef Cejka
+ * Copyright (c) 2009 Martin Decky
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "printf_core.h"
+#include "str.h"
+
+/** show prefixes 0x or 0 */
+#define __PRINTF_FLAG_PREFIX       0x00000001
+
+/** show the decimal point even if no fractional digits present */
+#define __PRINTF_FLAG_DECIMALPT    0x00000001
+
+/** signed / unsigned number */
+#define __PRINTF_FLAG_SIGNED       0x00000002
+
+/** print leading zeroes */
+#define __PRINTF_FLAG_ZEROPADDED   0x00000004
+
+/** align to left */
+#define __PRINTF_FLAG_LEFTALIGNED  0x00000010
+
+/** always show + sign */
+#define __PRINTF_FLAG_SHOWPLUS     0x00000020
+
+/** print space instead of plus */
+#define __PRINTF_FLAG_SPACESIGN    0x00000040
+
+/** show big characters */
+#define __PRINTF_FLAG_BIGCHARS     0x00000080
+
+/** number has - sign */
+#define __PRINTF_FLAG_NEGATIVE     0x00000100
+
+/** don't print trailing zeros in the fractional part */
+#define __PRINTF_FLAG_NOFRACZEROS  0x00000200
+
+
+/**
+ * Buffer big enough for 64-bit number printed in base 2, sign, prefix and 0
+ * to terminate string... (last one is only for better testing end of buffer by
+ * zero-filling subroutine)
+ */
+#define PRINT_NUMBER_BUFFER_SIZE  (64 + 5)
+
+/** Enumeration of possible arguments types.
+ */
+typedef enum {
+	PrintfQualifierByte = 0,
+	PrintfQualifierShort,
+	PrintfQualifierInt,
+	PrintfQualifierLong,
+	PrintfQualifierLongLong,
+	PrintfQualifierPointer,
+	PrintfQualifierSize
+} qualifier_t;
+
+static const char *nullstr = "(NULL)";
+static const char digits_small[] = "0123456789abcdef";
+static const char digits_big[] = "0123456789ABCDEF";
+static const char invalch = U_SPECIAL;
+
+/** Print one or more characters without adding newline.
+ *
+ * @param buf  Buffer holding characters with size of
+ *             at least size bytes. NULL is not allowed!
+ * @param size Size of the buffer in bytes.
+ * @param ps   Output method and its data.
+ *
+ * @return Number of characters printed.
+ *
+ */
+static int printf_putnchars(const char *buf, size_t size,
+    printf_spec_t *ps)
+{
+	return ps->str_write((void *) buf, size, ps->data);
+}
+
+/** Print one or more wide characters without adding newline.
+ *
+ * @param buf  Buffer holding wide characters with size of
+ *             at least size bytes. NULL is not allowed!
+ * @param size Size of the buffer in bytes.
+ * @param ps   Output method and its data.
+ *
+ * @return Number of wide characters printed.
+ *
+ */
+static int printf_wputnchars(const wchar_t *buf, size_t size,
+    printf_spec_t *ps)
+{
+	return ps->wstr_write((void *) buf, size, ps->data);
+}
+
+/** Print string without adding a newline.
+ *
+ * @param str String to print.
+ * @param ps  Write function specification and support data.
+ *
+ * @return Number of characters printed.
+ *
+ */
+static int printf_putstr(const char *str, printf_spec_t *ps)
+{
+	if (str == NULL)
+		return printf_putnchars(nullstr, str_size(nullstr), ps);
+	
+	return ps->str_write((void *) str, str_size(str), ps->data);
+}
+
+/** Print one ASCII character.
+ *
+ * @param c  ASCII character to be printed.
+ * @param ps Output method.
+ *
+ * @return Number of characters printed.
+ *
+ */
+static int printf_putchar(const char ch, printf_spec_t *ps)
+{
+	if (!ascii_check(ch))
+		return ps->str_write((void *) &invalch, 1, ps->data);
+	
+	return ps->str_write(&ch, 1, ps->data);
+}
+
+/** Print one wide character.
+ *
+ * @param c  Wide character to be printed.
+ * @param ps Output method.
+ *
+ * @return Number of characters printed.
+ *
+ */
+static int printf_putwchar(const wchar_t ch, printf_spec_t *ps)
+{
+	if (!chr_check(ch))
+		return ps->str_write((void *) &invalch, 1, ps->data);
+	
+	return ps->wstr_write(&ch, sizeof(wchar_t), ps->data);
+}
+
+/** Print one formatted ASCII character.
+ *
+ * @param ch    Character to print.
+ * @param width Width modifier.
+ * @param flags Flags that change the way the character is printed.
+ *
+ * @return Number of characters printed, negative value on failure.
+ *
+ */
+static int print_char(const char ch, int width, uint32_t flags, printf_spec_t *ps)
+{
+	size_t counter = 0;
+	if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
+		while (--width > 0) {
+			/*
+			 * One space is consumed by the character itself, hence
+			 * the predecrement.
+			 */
+			if (printf_putchar(' ', ps) > 0)
+				counter++;
+		}
+	}
+	
+	if (printf_putchar(ch, ps) > 0)
+		counter++;
+	
+	while (--width > 0) {
+		/*
+		 * One space is consumed by the character itself, hence
+		 * the predecrement.
+		 */
+		if (printf_putchar(' ', ps) > 0)
+			counter++;
+	}
+	
+	return (int) (counter);
+}
+
+/** Print one formatted wide character.
+ *
+ * @param ch    Character to print.
+ * @param width Width modifier.
+ * @param flags Flags that change the way the character is printed.
+ *
+ * @return Number of characters printed, negative value on failure.
+ *
+ */
+static int print_wchar(const wchar_t ch, int width, uint32_t flags, printf_spec_t *ps)
+{
+	size_t counter = 0;
+	if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
+		while (--width > 0) {
+			/*
+			 * One space is consumed by the character itself, hence
+			 * the predecrement.
+			 */
+			if (printf_putchar(' ', ps) > 0)
+				counter++;
+		}
+	}
+	
+	if (printf_putwchar(ch, ps) > 0)
+		counter++;
+	
+	while (--width > 0) {
+		/*
+		 * One space is consumed by the character itself, hence
+		 * the predecrement.
+		 */
+		if (printf_putchar(' ', ps) > 0)
+			counter++;
+	}
+	
+	return (int) (counter);
+}
+
+/** Print string.
+ *
+ * @param str       String to be printed.
+ * @param width     Width modifier.
+ * @param precision Precision modifier.
+ * @param flags     Flags that modify the way the string is printed.
+ *
+ * @return Number of characters printed, negative value on failure.
+ */
+static int print_str(char *str, int width, unsigned int precision,
+    uint32_t flags, printf_spec_t *ps)
+{
+	size_t strw;
+	size_t counter = 0;
+	size_t size;
+	int retval;
+
+	if (str == NULL)
+		return printf_putstr(nullstr, ps);
+	
+	strw = str_length(str);
+
+	/* Precision unspecified - print everything. */
+	if ((precision == 0) || (precision > strw))
+		precision = strw;
+	
+	/* Left padding */
+	width -= precision;
+	if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
+		while (width-- > 0) {
+			if (printf_putchar(' ', ps) == 1)
+				counter++;
+		}
+	}
+	
+	/* Part of @a str fitting into the alloted space. */
+	size = str_lsize(str, precision);
+	if ((retval = printf_putnchars(str, size, ps)) < 0)
+		return -counter;
+
+	counter += retval;
+
+	/* Right padding */
+	while (width-- > 0) {
+		if (printf_putchar(' ', ps) == 1)
+			counter++;
+	}
+
+	return ((int) counter);
+
+}
+
+/** Print wide string.
+ *
+ * @param str       Wide string to be printed.
+ * @param width     Width modifier.
+ * @param precision Precision modifier.
+ * @param flags     Flags that modify the way the string is printed.
+ *
+ * @return Number of wide characters printed, negative value on failure.
+ */
+static int print_wstr(wchar_t *str, int width, unsigned int precision,
+    uint32_t flags, printf_spec_t *ps)
+{
+	size_t counter = 0;
+	size_t strw;
+	int retval;
+	size_t size;
+
+	if (str == NULL)
+		return printf_putstr(nullstr, ps);
+	
+	strw = wstr_length(str);
+
+	/* Precision not specified - print everything. */
+	if ((precision == 0) || (precision > strw))
+		precision = strw;
+	
+	/* Left padding */
+	width -= precision;
+	if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
+		while (width-- > 0) {
+			if (printf_putchar(' ', ps) == 1)
+				counter++;
+		}
+	}
+	
+	/* Part of @a wstr fitting into the alloted space. */
+	size = wstr_lsize(str, precision);
+	if ((retval = printf_wputnchars(str, size, ps)) < 0)
+		return -counter;
+	
+	counter += retval;
+	
+	/* Right padding */
+	while (width-- > 0) {
+		if (printf_putchar(' ', ps) == 1)
+			counter++;
+	}
+
+	return ((int) counter);
+}
+
+/** Print a number in a given base.
+ *
+ * Print significant digits of a number in given base.
+ *
+ * @param num       Number to print.
+ * @param width     Width modifier.
+ * @param precision Precision modifier.
+ * @param base      Base to print the number in (must be between 2 and 16).
+ * @param flags     Flags that modify the way the number is printed.
+ *
+ * @return Number of characters printed.
+ *
+ */
+static int print_number(uint64_t num, int width, int precision, int base,
+			uint64_t flags, printf_spec_t *ps)
+{
+	const char *digits;
+	char d[PRINT_NUMBER_BUFFER_SIZE];
+	char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
+	int size = 0;		/* Size of number with all prefixes and signs. */
+	int number_size;	/* Size of plain number. */
+	char sgn;
+	int retval;
+	int counter = 0;
+
+	if (flags & __PRINTF_FLAG_BIGCHARS)
+		digits = digits_big;
+	else
+		digits = digits_small;
+	
+	/* Put zero at end of string */
+	*ptr-- = 0;
+	
+	if (num == 0) {
+		*ptr-- = '0';
+		size++;
+	} else {
+		do {
+			*ptr-- = digits[num % base];
+			size++;
+		} while (num /= base);
+	}
+	
+	/* Size of plain number */
+	number_size = size;
+	
+	/*
+	 * Collect the sum of all prefixes/signs/etc. to calculate padding and
+	 * leading zeroes.
+	 */
+	if (flags & __PRINTF_FLAG_PREFIX) {
+		switch (base) {
+		case 2:
+			/* Binary formating is not standard, but usefull */
+			size += 2;
+			break;
+		case 8:
+			size++;
+			break;
+		case 16:
+			size += 2;
+			break;
+		}
+	}
+	
+	sgn = 0;
+	if (flags & __PRINTF_FLAG_SIGNED) {
+		if (flags & __PRINTF_FLAG_NEGATIVE) {
+			sgn = '-';
+			size++;
+		} else if (flags & __PRINTF_FLAG_SHOWPLUS) {
+			sgn = '+';
+			size++;
+		} else if (flags & __PRINTF_FLAG_SPACESIGN) {
+			sgn = ' ';
+			size++;
+		}
+	}
+	
+	if (flags & __PRINTF_FLAG_LEFTALIGNED)
+		flags &= ~__PRINTF_FLAG_ZEROPADDED;
+	
+	/*
+	 * If the number is left-aligned or precision is specified then
+	 * padding with zeros is ignored.
+	 */
+	if (flags & __PRINTF_FLAG_ZEROPADDED) {
+		if ((precision == 0) && (width > size))
+			precision = width - size + number_size;
+	}
+	
+	/* Print leading spaces */
+	if (number_size > precision) {
+		/* Print the whole number, not only a part */
+		precision = number_size;
+	}
+	
+	width -= precision + size - number_size;
+	
+	if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
+		while (width-- > 0) {
+			if (printf_putchar(' ', ps) == 1)
+				counter++;
+		}
+	}
+	
+	/* Print sign */
+	if (sgn) {
+		if (printf_putchar(sgn, ps) == 1)
+			counter++;
+	}
+	
+	/* Print prefix */
+	if (flags & __PRINTF_FLAG_PREFIX) {
+		switch (base) {
+		case 2:
+			/* Binary formating is not standard, but usefull */
+			if (printf_putchar('0', ps) == 1)
+				counter++;
+			if (flags & __PRINTF_FLAG_BIGCHARS) {
+				if (printf_putchar('B', ps) == 1)
+					counter++;
+			} else {
+				if (printf_putchar('b', ps) == 1)
+					counter++;
+			}
+			break;
+		case 8:
+			if (printf_putchar('o', ps) == 1)
+				counter++;
+			break;
+		case 16:
+			if (printf_putchar('0', ps) == 1)
+				counter++;
+			if (flags & __PRINTF_FLAG_BIGCHARS) {
+				if (printf_putchar('X', ps) == 1)
+					counter++;
+			} else {
+				if (printf_putchar('x', ps) == 1)
+					counter++;
+			}
+			break;
+		}
+	}
+	
+	/* Print leading zeroes */
+	precision -= number_size;
+	while (precision-- > 0) {
+		if (printf_putchar('0', ps) == 1)
+			counter++;
+	}
+	
+	/* Print the number itself */
+	if ((retval = printf_putstr(++ptr, ps)) > 0)
+		counter += retval;
+	
+	/* Print trailing spaces */
+	
+	while (width-- > 0) {
+		if (printf_putchar(' ', ps) == 1)
+			counter++;
+	}
+	
+	return ((int) counter);
+}
+
+/** Print formatted string.
+ *
+ * Print string formatted according to the fmt parameter and variadic arguments.
+ * Each formatting directive must have the following form:
+ *
+ *  \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
+ *
+ * FLAGS:@n
+ *  - "#" Force to print prefix. For \%o conversion, the prefix is 0, for
+ *        \%x and \%X prefixes are 0x and 0X and for conversion \%b the
+ *        prefix is 0b.
+ *
+ *  - "-" Align to left.
+ *
+ *  - "+" Print positive sign just as negative.
+ *
+ *  - " " If the printed number is positive and "+" flag is not set,
+ *        print space in place of sign.
+ *
+ *  - "0" Print 0 as padding instead of spaces. Zeroes are placed between
+ *        sign and the rest of the number. This flag is ignored if "-"
+ *        flag is specified.
+ *
+ * WIDTH:@n
+ *  - Specify the minimal width of a printed argument. If it is bigger,
+ *    width is ignored. If width is specified with a "*" character instead of
+ *    number, width is taken from parameter list. And integer parameter is
+ *    expected before parameter for processed conversion specification. If
+ *    this value is negative its absolute value is taken and the "-" flag is
+ *    set.
+ *
+ * PRECISION:@n
+ *  - Value precision. For numbers it specifies minimum valid numbers.
+ *    Smaller numbers are printed with leading zeroes. Bigger numbers are not
+ *    affected. Strings with more than precision characters are cut off. Just
+ *    as with width, an "*" can be used used instead of a number. An integer
+ *    value is then expected in parameters. When both width and precision are
+ *    specified using "*", the first parameter is used for width and the
+ *    second one for precision.
+ *
+ * TYPE:@n
+ *  - "hh" Signed or unsigned char. at n
+ *  - "h"  Signed or unsigned short. at n
+ *  - ""   Signed or unsigned int (default value). at n
+ *  - "l"  Signed or unsigned long int. at n
+ *         If conversion is "c", the character is wint_t (wide character). at n
+ *         If conversion is "s", the string is wchar_t * (wide string). at n
+ *  - "ll" Signed or unsigned long long int. at n
+ *  - "z"  Signed or unsigned ssize_t or site_t. at n
+ *
+ * CONVERSION:@n
+ *  - % Print percentile character itself.
+ *
+ *  - c Print single character. The character is expected to be plain
+ *      ASCII (e.g. only values 0 .. 127 are valid). at n
+ *      If type is "l", then the character is expected to be wide character
+ *      (e.g. values 0 .. 0x10ffff are valid).
+ *
+ *  - s Print zero terminated string. If a NULL value is passed as
+ *      value, "(NULL)" is printed instead. at n
+ *      If type is "l", then the string is expected to be wide string.
+ *
+ *  - P, p Print value of a pointer. Void * value is expected and it is
+ *         printed in hexadecimal notation with prefix (as with
+ *         \%#0.8X / \%#0.8x for 32-bit or \%#0.16lX / \%#0.16lx for 64-bit
+ *         long pointers).
+ *
+ *  - b Print value as unsigned binary number. Prefix is not printed by
+ *      default. (Nonstandard extension.)
+ *
+ *  - o Print value as unsigned octal number. Prefix is not printed by
+ *      default.
+ *
+ *  - d, i Print signed decimal number. There is no difference between d
+ *         and i conversion.
+ *
+ *  - u Print unsigned decimal number.
+ *
+ *  - X, x Print hexadecimal number with upper- or lower-case. Prefix is
+ *         not printed by default.
+ *
+ * All other characters from fmt except the formatting directives are printed
+ * verbatim.
+ *
+ * @param fmt Format NULL-terminated string.
+ *
+ * @return Number of characters printed, negative value on failure.
+ *
+ */
+int printf_core(const char *fmt, printf_spec_t *ps, va_list ap)
+{
+	size_t i;        /* Index of the currently processed character from fmt */
+	size_t nxt = 0;  /* Index of the next character from fmt */
+	size_t j = 0;    /* Index to the first not printed nonformating character */
+	
+	size_t counter = 0;   /* Number of characters printed */
+	int retval;           /* Return values from nested functions */
+	
+	while (true) {
+		wchar_t uc;
+
+		i = nxt;
+		uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
+		
+		if (uc == 0)
+			break;
+		
+		/* Control character */
+		if (uc == '%') {
+			uint32_t flags = 0;
+			bool end = false;
+			int width = 0;
+			int precision = -1;
+			qualifier_t qualifier;
+			unsigned int base = 10;
+			size_t size;
+			uint64_t number;
+
+			/* Print common characters if any processed */
+			if (i > j) {
+				if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
+					/* Error */
+					counter = -counter;
+					goto out;
+				}
+				counter += retval;
+			}
+			
+			j = i;
+			
+			/* Parse modifiers */
+			do {
+				i = nxt;
+				uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
+				switch (uc) {
+				case '#':
+					flags |= __PRINTF_FLAG_PREFIX;
+					flags |= __PRINTF_FLAG_DECIMALPT;
+					break;
+				case '-':
+					flags |= __PRINTF_FLAG_LEFTALIGNED;
+					break;
+				case '+':
+					flags |= __PRINTF_FLAG_SHOWPLUS;
+					break;
+				case ' ':
+					flags |= __PRINTF_FLAG_SPACESIGN;
+					break;
+				case '0':
+					flags |= __PRINTF_FLAG_ZEROPADDED;
+					break;
+				default:
+					end = true;
+				};
+			} while (!end);
+			
+			/* Width & '*' operator */
+			if (isdigit(uc)) {
+				while (true) {
+					width *= 10;
+					width += uc - '0';
+					
+					i = nxt;
+					uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
+					if (uc == 0)
+						break;
+					if (!isdigit(uc))
+						break;
+				}
+			} else if (uc == '*') {
+				/* Get width value from argument list */
+				i = nxt;
+				uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
+				width = (int) va_arg(ap, int);
+				if (width < 0) {
+					/* Negative width sets '-' flag */
+					width *= -1;
+					flags |= __PRINTF_FLAG_LEFTALIGNED;
+				}
+			}
+			
+			/* Precision and '*' operator */
+			if (uc == '.') {
+				i = nxt;
+				uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
+				if (isdigit(uc)) {
+					precision = 0;
+					while (true) {
+						precision *= 10;
+						precision += uc - '0';
+						
+						i = nxt;
+						uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
+						if (uc == 0)
+							break;
+						if (!isdigit(uc))
+							break;
+					}
+				} else if (uc == '*') {
+					/* Get precision value from the argument list */
+					i = nxt;
+					uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
+					precision = (int) va_arg(ap, int);
+					if (precision < 0) {
+						/* Ignore negative precision - use default instead */
+						precision = -1;
+					}
+				}
+			}
+			
+			switch (uc) {
+			/** @todo Unimplemented qualifiers:
+			 *        t ptrdiff_t - ISO C 99
+			 */
+			case 'h':
+				/* Char or short */
+				qualifier = PrintfQualifierShort;
+				i = nxt;
+				uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
+				if (uc == 'h') {
+					i = nxt;
+					uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
+					qualifier = PrintfQualifierByte;
+				}
+				break;
+			case 'l':
+				/* Long or long long */
+				qualifier = PrintfQualifierLong;
+				i = nxt;
+				uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
+				if (uc == 'l') {
+					i = nxt;
+					uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
+					qualifier = PrintfQualifierLongLong;
+				}
+				break;
+			case 'z':
+				qualifier = PrintfQualifierSize;
+				i = nxt;
+				uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
+				break;
+			default:
+				/* Default type */
+				qualifier = PrintfQualifierInt;
+			}
+			
+			switch (uc) {
+			/*
+			 * String and character conversions.
+			 */
+			case 's':
+				precision = max(0,  precision);
+				
+				if (qualifier == PrintfQualifierLong)
+					retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps);
+				else
+					retval = print_str(va_arg(ap, char *), width, precision, flags, ps);
+				
+				if (retval < 0) {
+					counter = -counter;
+					goto out;
+				}
+				
+				counter += retval;
+				j = nxt;
+				goto next_char;
+			case 'c':
+				if (qualifier == PrintfQualifierLong)
+					retval = print_wchar(va_arg(ap, wint_t), width, flags, ps);
+				else
+					retval = print_char(va_arg(ap, unsigned int), width, flags, ps);
+				
+				if (retval < 0) {
+					counter = -counter;
+					goto out;
+				};
+				
+				counter += retval;
+				j = nxt;
+				goto next_char;
+				
+			/*
+			 * Integer values
+			 */
+			case 'P':
+				/* Pointer */
+				flags |= __PRINTF_FLAG_BIGCHARS;
+			case 'p':
+				flags |= __PRINTF_FLAG_PREFIX;
+				flags |= __PRINTF_FLAG_ZEROPADDED;
+				base = 16;
+				qualifier = PrintfQualifierPointer;
+				break;
+			case 'b':
+				base = 2;
+				break;
+			case 'o':
+				base = 8;
+				break;
+			case 'd':
+			case 'i':
+				flags |= __PRINTF_FLAG_SIGNED;
+			case 'u':
+				break;
+			case 'X':
+				flags |= __PRINTF_FLAG_BIGCHARS;
+			case 'x':
+				base = 16;
+				break;
+			
+			/* Percentile itself */
+			case '%':
+				j = i;
+				goto next_char;
+			
+			/*
+			 * Bad formatting.
+			 */
+			default:
+				/*
+				 * Unknown format. Now, j is the index of '%'
+				 * so we will print whole bad format sequence.
+				 */
+				goto next_char;
+			}
+			
+			/* Print integers */
+			switch (qualifier) {
+			case PrintfQualifierByte:
+				size = sizeof(unsigned char);
+				number = (uint64_t) va_arg(ap, unsigned int);
+				break;
+			case PrintfQualifierShort:
+				size = sizeof(unsigned short);
+				number = (uint64_t) va_arg(ap, unsigned int);
+				break;
+			case PrintfQualifierInt:
+				size = sizeof(unsigned int);
+				number = (uint64_t) va_arg(ap, unsigned int);
+				break;
+			case PrintfQualifierLong:
+				size = sizeof(unsigned long);
+				number = (uint64_t) va_arg(ap, unsigned long);
+				break;
+			case PrintfQualifierLongLong:
+				size = sizeof(unsigned long long);
+				number = (uint64_t) va_arg(ap, unsigned long long);
+				break;
+			case PrintfQualifierPointer:
+				size = sizeof(void *);
+				precision = size << 1;
+				number = (uint64_t) (unsigned long)va_arg(ap, void *);
+				break;
+			case PrintfQualifierSize:
+				size = sizeof(size_t);
+				number = (uint64_t) va_arg(ap, size_t);
+				break;
+			default:
+				/* Unknown qualifier */
+				counter = -counter;
+				goto out;
+			}
+			
+			if ((retval = print_number(number, width, precision,
+			    base, flags, ps)) < 0) {
+				counter = -counter;
+				goto out;
+			}
+			
+			counter += retval;
+			j = nxt;
+		}
+next_char:
+		;
+	}
+	
+	if (i > j) {
+		if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
+			/* Error */
+			counter = -counter;
+			goto out;
+		}
+		counter += retval;
+	}
+	
+out:
+	return ((int) counter);
+}
diff --git a/apps/libc/helenos/printf_core.h b/apps/libc/helenos/printf_core.h
new file mode 100644
index 0000000..71c725a
--- /dev/null
+++ b/apps/libc/helenos/printf_core.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2006 Josef Cejka
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_PRINTF_CORE_H_
+#define LIBC_PRINTF_CORE_H_
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+/** Structure for specifying output methods for different printf clones. */
+typedef struct {
+	/* String output function, returns number of printed characters or EOF */
+	int (*str_write)(const char *, size_t, void *);
+	
+	/* Wide string output function, returns number of printed characters or EOF */
+	int (*wstr_write)(const wchar_t *, size_t, void *);
+	
+	/* User data - output stream specification, state, locks, etc. */
+	void *data;
+} printf_spec_t;
+
+extern int printf_core(const char *, printf_spec_t *, va_list);
+
+#endif
+
+/** @}
+ */
diff --git a/apps/libc/helenos/stdio.c b/apps/libc/helenos/stdio.c
new file mode 100644
index 0000000..e4bf3c6
--- /dev/null
+++ b/apps/libc/helenos/stdio.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * Copyright (c) 2011 Petr Koupy
+ * 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 libposix
+ * @{
+ */
+/** @file Standard buffered input/output.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <malloc.h>
+
+#include "printf_core.h"
+#include "str.h"
+
+
+/**
+ * Write ordinary string to the opened file.
+ *
+ * @param str String to be written.
+ * @param size Size of the string (in bytes)..
+ * @param fd File descriptor of the opened file.
+ * @return The number of written characters.
+ */
+static int _dprintf_str_write(const char *str, size_t size, void *fd)
+{
+	ssize_t wr = write(*(int *) fd, str, size);
+	return str_nlength(str, wr);
+}
+
+/**
+ * Write wide string to the opened file.
+ * 
+ * @param str String to be written.
+ * @param size Size of the string (in bytes).
+ * @param fd File descriptor of the opened file.
+ * @return The number of written characters.
+ */
+static int _dprintf_wstr_write(const wchar_t *str, size_t size, void *fd)
+{
+	size_t offset = 0;
+	size_t chars = 0;
+	size_t sz;
+	char buf[4];
+	
+	while (offset < size) {
+		sz = 0;
+		if (chr_encode(str[chars], buf, &sz, sizeof(buf)) != 0) {
+			break;
+		}
+		
+		if (write(*(int *) fd, buf, sz) != (ssize_t) sz) {
+			break;
+		}
+		
+		chars++;
+		offset += sizeof(wchar_t);
+	}
+	
+	return chars;
+}
+
+/**
+ * Print formatted output to the opened file.
+ * 
+ * @param fildes File descriptor of the opened file.
+ * @param format Format description.
+ * @param ap Print arguments.
+ * @return Either the number of printed characters or negative value on error.
+ */
+int vdprintf(int fildes, const char * format, va_list ap)
+{
+	printf_spec_t spec = {
+		.str_write = _dprintf_str_write,
+		.wstr_write = _dprintf_wstr_write,
+		.data = &fildes
+	};
+	
+	return printf_core(format, &spec, ap);
+}
+
+/**
+ * Print formatted output to the string.
+ * 
+ * @param s Output string.
+ * @param format Format description.
+ * @return Either the number of printed characters (excluding null byte) or
+ *     negative value on error.
+ */
+int sprintf(char *s, const char * format, ...)
+{
+	va_list list;
+	int result;
+
+	va_start(list, format);
+	result = vsprintf(s, format, list);
+	va_end(list);
+	return result;
+}
+
+/**
+ * Print formatted output to the string.
+ * 
+ * @param s Output string.
+ * @param format Format description.
+ * @param ap Print arguments.
+ * @return Either the number of printed characters (excluding null byte) or
+ *     negative value on error.
+ */
+int vsprintf(char *s, const char * format, va_list ap)
+{
+	return vsnprintf(s, STR_NO_LIMIT, format, ap);
+}
+
+int snprintf(char *str, size_t size, const char *fmt, ...)
+{
+	int ret;
+	va_list args;
+
+	va_start(args, fmt);
+	ret = vsnprintf(str, size, fmt, args);
+	va_end(args);
+
+	return ret;
+}
diff --git a/apps/libc/helenos/str.c b/apps/libc/helenos/str.c
new file mode 100644
index 0000000..cb350e9
--- /dev/null
+++ b/apps/libc/helenos/str.c
@@ -0,0 +1,1755 @@
+/*
+ * Copyright (c) 2005 Martin Decky
+ * Copyright (c) 2008 Jiri Svoboda
+ * Copyright (c) 2011 Martin Sucha
+ * Copyright (c) 2011 Oleg Romanenko
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <errno.h>
+#include <limits.h>
+#include <wchar.h>
+#include "align.h"
+#include "assert.h"
+#include "str.h"
+
+/** Check the condition if wchar_t is signed */
+#ifdef WCHAR_IS_UNSIGNED
+	#define WCHAR_SIGNED_CHECK(cond)  (true)
+#else
+	#define WCHAR_SIGNED_CHECK(cond)  (cond)
+#endif
+
+/** Byte mask consisting of lowest @n bits (out of 8) */
+#define LO_MASK_8(n)  ((uint8_t) ((1 << (n)) - 1))
+
+/** Byte mask consisting of lowest @n bits (out of 32) */
+#define LO_MASK_32(n)  ((uint32_t) ((1 << (n)) - 1))
+
+/** Byte mask consisting of highest @n bits (out of 8) */
+#define HI_MASK_8(n)  (~LO_MASK_8(8 - (n)))
+
+/** Number of data bits in a UTF-8 continuation byte */
+#define CONT_BITS  6
+
+/** Decode a single character from a string.
+ *
+ * Decode a single character from a string of size @a size. Decoding starts
+ * at @a offset and this offset is moved to the beginning of the next
+ * character. In case of decoding error, offset generally advances at least
+ * by one. However, offset is never moved beyond size.
+ *
+ * @param str    String (not necessarily NULL-terminated).
+ * @param offset Byte offset in string where to start decoding.
+ * @param size   Size of the string (in bytes).
+ *
+ * @return Value of decoded character, U_SPECIAL on decoding error or
+ *         NULL if attempt to decode beyond @a size.
+ *
+ */
+wchar_t str_decode(const char *str, size_t *offset, size_t size)
+{
+	uint8_t b0;
+	unsigned int b0_bits;  /* Data bits in first byte */
+	unsigned int cbytes;   /* Number of continuation bytes */
+	wchar_t ch;
+
+	if (*offset + 1 > size)
+		return 0;
+	
+	/* First byte read from string */
+	b0 = (uint8_t) str[(*offset)++];
+	
+	/* Determine code length */
+	
+	if ((b0 & 0x80) == 0) {
+		/* 0xxxxxxx (Plain ASCII) */
+		b0_bits = 7;
+		cbytes = 0;
+	} else if ((b0 & 0xe0) == 0xc0) {
+		/* 110xxxxx 10xxxxxx */
+		b0_bits = 5;
+		cbytes = 1;
+	} else if ((b0 & 0xf0) == 0xe0) {
+		/* 1110xxxx 10xxxxxx 10xxxxxx */
+		b0_bits = 4;
+		cbytes = 2;
+	} else if ((b0 & 0xf8) == 0xf0) {
+		/* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+		b0_bits = 3;
+		cbytes = 3;
+	} else {
+		/* 10xxxxxx -- unexpected continuation byte */
+		return U_SPECIAL;
+	}
+	
+	if (*offset + cbytes > size)
+		return U_SPECIAL;
+	
+	ch = b0 & LO_MASK_8(b0_bits);
+	
+	/* Decode continuation bytes */
+	while (cbytes > 0) {
+		uint8_t b = (uint8_t) str[(*offset)++];
+		
+		/* Must be 10xxxxxx */
+		if ((b & 0xc0) != 0x80)
+			return U_SPECIAL;
+		
+		/* Shift data bits to ch */
+		ch = (ch << CONT_BITS) | (wchar_t) (b & LO_MASK_8(CONT_BITS));
+		cbytes--;
+	}
+	
+	return ch;
+}
+
+/** Decode a single character from a string to the left.
+ *
+ * Decode a single character from a string of size @a size. Decoding starts
+ * at @a offset and this offset is moved to the beginning of the previous
+ * character. In case of decoding error, offset generally decreases at least
+ * by one. However, offset is never moved before 0.
+ *
+ * @param str    String (not necessarily NULL-terminated).
+ * @param offset Byte offset in string where to start decoding.
+ * @param size   Size of the string (in bytes).
+ *
+ * @return Value of decoded character, U_SPECIAL on decoding error or
+ *         NULL if attempt to decode beyond @a start of str.
+ *
+ */
+wchar_t str_decode_reverse(const char *str, size_t *offset, size_t size)
+{
+	size_t processed = 0;
+
+	if (*offset == 0)
+		return 0;
+	
+	/* Continue while continuation bytes found */
+	while (*offset > 0 && processed < 4) {
+		uint8_t b = (uint8_t) str[--(*offset)];
+		
+		if (processed == 0 && (b & 0x80) == 0) {
+			/* 0xxxxxxx (Plain ASCII) */
+			return b & 0x7f;
+		}
+		else if ((b & 0xe0) == 0xc0 || (b & 0xf0) == 0xe0 ||
+		    (b & 0xf8) == 0xf0) {
+			/* Start byte */
+			size_t start_offset = *offset;
+			return str_decode(str, &start_offset, size);
+		}
+		else if ((b & 0xc0) != 0x80) {
+			/* Not a continuation byte */
+			return U_SPECIAL;
+		}
+		processed++;
+	}
+	/* Too many continuation bytes */
+	return U_SPECIAL;
+}
+
+/** Encode a single character to string representation.
+ *
+ * Encode a single character to string representation (i.e. UTF-8) and store
+ * it into a buffer at @a offset. Encoding starts at @a offset and this offset
+ * is moved to the position where the next character can be written to.
+ *
+ * @param ch     Input character.
+ * @param str    Output buffer.
+ * @param offset Byte offset where to start writing.
+ * @param size   Size of the output buffer (in bytes).
+ *
+ * @return 0 if the character was encoded successfully, EOVERFLOW if there
+ *         was not enough space in the output buffer or EINVAL if the character
+ *         code was invalid.
+ */
+int chr_encode(const wchar_t ch, char *str, size_t *offset, size_t size)
+{
+	unsigned int i;
+	uint32_t cc = (uint32_t) ch;
+	unsigned int b0_bits;  /* Data bits in first byte */
+	unsigned int cbytes;   /* Number of continuation bytes */
+
+	if (*offset >= size)
+		return EOVERFLOW;
+	
+	if (!chr_check(ch))
+		return EINVAL;
+	
+	/* Unsigned version of ch (bit operations should only be done
+	   on unsigned types). */
+	
+	/* Determine how many continuation bytes are needed */
+	
+	if ((cc & ~LO_MASK_32(7)) == 0) {
+		b0_bits = 7;
+		cbytes = 0;
+	} else if ((cc & ~LO_MASK_32(11)) == 0) {
+		b0_bits = 5;
+		cbytes = 1;
+	} else if ((cc & ~LO_MASK_32(16)) == 0) {
+		b0_bits = 4;
+		cbytes = 2;
+	} else if ((cc & ~LO_MASK_32(21)) == 0) {
+		b0_bits = 3;
+		cbytes = 3;
+	} else {
+		/* Codes longer than 21 bits are not supported */
+		return EINVAL;
+	}
+	
+	/* Check for available space in buffer */
+	if (*offset + cbytes >= size)
+		return EOVERFLOW;
+	
+	/* Encode continuation bytes */
+	for (i = cbytes; i > 0; i--) {
+		str[*offset + i] = 0x80 | (cc & LO_MASK_32(CONT_BITS));
+		cc = cc >> CONT_BITS;
+	}
+	
+	/* Encode first byte */
+	str[*offset] = (cc & LO_MASK_32(b0_bits)) | HI_MASK_8(8 - b0_bits - 1);
+	
+	/* Advance offset */
+	*offset += cbytes + 1;
+	
+	return 0;
+}
+
+/** Get size of string.
+ *
+ * Get the number of bytes which are used by the string @a str (excluding the
+ * NULL-terminator).
+ *
+ * @param str String to consider.
+ *
+ * @return Number of bytes used by the string
+ *
+ */
+size_t str_size(const char *str)
+{
+	size_t size = 0;
+	
+	while (*str++ != 0)
+		size++;
+	
+	return size;
+}
+
+/** Get size of wide string.
+ *
+ * Get the number of bytes which are used by the wide string @a str (excluding the
+ * NULL-terminator).
+ *
+ * @param str Wide string to consider.
+ *
+ * @return Number of bytes used by the wide string
+ *
+ */
+size_t wstr_size(const wchar_t *str)
+{
+	return (wstr_length(str) * sizeof(wchar_t));
+}
+
+/** Get size of string with length limit.
+ *
+ * Get the number of bytes which are used by up to @a max_len first
+ * characters in the string @a str. If @a max_len is greater than
+ * the length of @a str, the entire string is measured (excluding the
+ * NULL-terminator).
+ *
+ * @param str     String to consider.
+ * @param max_len Maximum number of characters to measure.
+ *
+ * @return Number of bytes used by the characters.
+ *
+ */
+size_t str_lsize(const char *str, size_t max_len)
+{
+	size_t len = 0;
+	size_t offset = 0;
+	
+	while (len < max_len) {
+		if (str_decode(str, &offset, STR_NO_LIMIT) == 0)
+			break;
+		
+		len++;
+	}
+	
+	return offset;
+}
+
+/** Get size of string with size limit.
+ *
+ * Get the number of bytes which are used by the string @a str
+ * (excluding the NULL-terminator), but no more than @max_size bytes.
+ *
+ * @param str      String to consider.
+ * @param max_size Maximum number of bytes to measure.
+ *
+ * @return Number of bytes used by the string
+ *
+ */
+size_t str_nsize(const char *str, size_t max_size)
+{
+	size_t size = 0;
+	
+	while ((*str++ != 0) && (size < max_size))
+		size++;
+	
+	return size;
+}
+
+/** Get size of wide string with size limit.
+ *
+ * Get the number of bytes which are used by the wide string @a str
+ * (excluding the NULL-terminator), but no more than @max_size bytes.
+ *
+ * @param str      Wide string to consider.
+ * @param max_size Maximum number of bytes to measure.
+ *
+ * @return Number of bytes used by the wide string
+ *
+ */
+size_t wstr_nsize(const wchar_t *str, size_t max_size)
+{
+	return (wstr_nlength(str, max_size) * sizeof(wchar_t));
+}
+
+/** Get size of wide string with length limit.
+ *
+ * Get the number of bytes which are used by up to @a max_len first
+ * wide characters in the wide string @a str. If @a max_len is greater than
+ * the length of @a str, the entire wide string is measured (excluding the
+ * NULL-terminator).
+ *
+ * @param str     Wide string to consider.
+ * @param max_len Maximum number of wide characters to measure.
+ *
+ * @return Number of bytes used by the wide characters.
+ *
+ */
+size_t wstr_lsize(const wchar_t *str, size_t max_len)
+{
+	return (wstr_nlength(str, max_len * sizeof(wchar_t)) * sizeof(wchar_t));
+}
+
+/** Get number of characters in a string.
+ *
+ * @param str NULL-terminated string.
+ *
+ * @return Number of characters in string.
+ *
+ */
+size_t str_length(const char *str)
+{
+	size_t len = 0;
+	size_t offset = 0;
+	
+	while (str_decode(str, &offset, STR_NO_LIMIT) != 0)
+		len++;
+	
+	return len;
+}
+
+/** Get number of characters in a wide string.
+ *
+ * @param str NULL-terminated wide string.
+ *
+ * @return Number of characters in @a str.
+ *
+ */
+size_t wstr_length(const wchar_t *wstr)
+{
+	size_t len = 0;
+	
+	while (*wstr++ != 0)
+		len++;
+	
+	return len;
+}
+
+/** Get number of characters in a string with size limit.
+ *
+ * @param str  NULL-terminated string.
+ * @param size Maximum number of bytes to consider.
+ *
+ * @return Number of characters in string.
+ *
+ */
+size_t str_nlength(const char *str, size_t size)
+{
+	size_t len = 0;
+	size_t offset = 0;
+	
+	while (str_decode(str, &offset, size) != 0)
+		len++;
+	
+	return len;
+}
+
+/** Get number of characters in a string with size limit.
+ *
+ * @param str  NULL-terminated string.
+ * @param size Maximum number of bytes to consider.
+ *
+ * @return Number of characters in string.
+ *
+ */
+size_t wstr_nlength(const wchar_t *str, size_t size)
+{
+	size_t len = 0;
+	size_t limit = ALIGN_DOWN(size, sizeof(wchar_t));
+	size_t offset = 0;
+	
+	while ((offset < limit) && (*str++ != 0)) {
+		len++;
+		offset += sizeof(wchar_t);
+	}
+	
+	return len;
+}
+
+/** Get character display width on a character cell display.
+ *
+ * @param ch	Character
+ * @return	Width of character in cells.
+ */
+size_t chr_width(wchar_t ch)
+{
+	return 1;
+}
+
+/** Get string display width on a character cell display.
+ *
+ * @param str	String
+ * @return	Width of string in cells.
+ */
+size_t str_width(const char *str)
+{
+	size_t width = 0;
+	size_t offset = 0;
+	wchar_t ch;
+	
+	while ((ch = str_decode(str, &offset, STR_NO_LIMIT)) != 0)
+		width += chr_width(ch);
+	
+	return width;
+}
+
+/** Check whether character is plain ASCII.
+ *
+ * @return True if character is plain ASCII.
+ *
+ */
+bool ascii_check(wchar_t ch)
+{
+	if (WCHAR_SIGNED_CHECK(ch >= 0) && (ch <= 127))
+		return true;
+	
+	return false;
+}
+
+/** Check whether character is valid
+ *
+ * @return True if character is a valid Unicode code point.
+ *
+ */
+bool chr_check(wchar_t ch)
+{
+	if (WCHAR_SIGNED_CHECK(ch >= 0) && (ch <= 1114111))
+		return true;
+	
+	return false;
+}
+
+/** Compare two NULL terminated strings.
+ *
+ * Do a char-by-char comparison of two NULL-terminated strings.
+ * The strings are considered equal iff their length is equal
+ * and both strings consist of the same sequence of characters.
+ *
+ * A string S1 is less than another string S2 if it has a character with
+ * lower value at the first character position where the strings differ.
+ * If the strings differ in length, the shorter one is treated as if
+ * padded by characters with a value of zero.
+ *
+ * @param s1 First string to compare.
+ * @param s2 Second string to compare.
+ *
+ * @return 0 if the strings are equal, -1 if the first is less than the second,
+ *         1 if the second is less than the first.
+ *
+ */
+int str_cmp(const char *s1, const char *s2)
+{
+	wchar_t c1 = 0;
+	wchar_t c2 = 0;
+	
+	size_t off1 = 0;
+	size_t off2 = 0;
+
+	while (true) {
+		c1 = str_decode(s1, &off1, STR_NO_LIMIT);
+		c2 = str_decode(s2, &off2, STR_NO_LIMIT);
+
+		if (c1 < c2)
+			return -1;
+		
+		if (c1 > c2)
+			return 1;
+
+		if (c1 == 0 || c2 == 0)
+			break;		
+	}
+
+	return 0;
+}
+
+/** Compare two NULL terminated strings with length limit.
+ *
+ * Do a char-by-char comparison of two NULL-terminated strings.
+ * The strings are considered equal iff
+ * min(str_length(s1), max_len) == min(str_length(s2), max_len)
+ * and both strings consist of the same sequence of characters,
+ * up to max_len characters.
+ *
+ * A string S1 is less than another string S2 if it has a character with
+ * lower value at the first character position where the strings differ.
+ * If the strings differ in length, the shorter one is treated as if
+ * padded by characters with a value of zero. Only the first max_len
+ * characters are considered.
+ *
+ * @param s1      First string to compare.
+ * @param s2      Second string to compare.
+ * @param max_len Maximum number of characters to consider.
+ *
+ * @return 0 if the strings are equal, -1 if the first is less than the second,
+ *         1 if the second is less than the first.
+ *
+ */
+int str_lcmp(const char *s1, const char *s2, size_t max_len)
+{
+	wchar_t c1 = 0;
+	wchar_t c2 = 0;
+	
+	size_t off1 = 0;
+	size_t off2 = 0;
+	
+	size_t len = 0;
+
+	while (true) {
+		if (len >= max_len)
+			break;
+
+		c1 = str_decode(s1, &off1, STR_NO_LIMIT);
+		c2 = str_decode(s2, &off2, STR_NO_LIMIT);
+
+		if (c1 < c2)
+			return -1;
+
+		if (c1 > c2)
+			return 1;
+
+		if (c1 == 0 || c2 == 0)
+			break;
+
+		++len;	
+	}
+
+	return 0;
+
+}
+
+/** Test whether p is a prefix of s.
+ *
+ * Do a char-by-char comparison of two NULL-terminated strings
+ * and determine if p is a prefix of s.
+ *
+ * @param s The string in which to look
+ * @param p The string to check if it is a prefix of s
+ *
+ * @return true iff p is prefix of s else false
+ *
+ */
+bool str_test_prefix(const char *s, const char *p)
+{
+	wchar_t c1 = 0;
+	wchar_t c2 = 0;
+	
+	size_t off1 = 0;
+	size_t off2 = 0;
+
+	while (true) {
+		c1 = str_decode(s, &off1, STR_NO_LIMIT);
+		c2 = str_decode(p, &off2, STR_NO_LIMIT);
+		
+		if (c2 == 0)
+			return true;
+
+		if (c1 != c2)
+			return false;
+		
+		if (c1 == 0)
+			break;
+	}
+
+	return false;
+}
+
+/** Copy string.
+ *
+ * Copy source string @a src to destination buffer @a dest.
+ * No more than @a size bytes are written. If the size of the output buffer
+ * is at least one byte, the output string will always be well-formed, i.e.
+ * null-terminated and containing only complete characters.
+ *
+ * @param dest  Destination buffer.
+ * @param count Size of the destination buffer (must be > 0).
+ * @param src   Source string.
+ *
+ */
+void str_cpy(char *dest, size_t size, const char *src)
+{
+	/* There must be space for a null terminator in the buffer. */
+	size_t src_off = 0;
+	size_t dest_off = 0;
+	wchar_t ch;
+
+	assert(size > 0);
+
+	while ((ch = str_decode(src, &src_off, STR_NO_LIMIT)) != 0) {
+		if (chr_encode(ch, dest, &dest_off, size - 1) != 0)
+			break;
+	}
+	
+	dest[dest_off] = '\0';
+}
+
+/** Copy size-limited substring.
+ *
+ * Copy prefix of string @a src of max. size @a size to destination buffer
+ * @a dest. No more than @a size bytes are written. The output string will
+ * always be well-formed, i.e. null-terminated and containing only complete
+ * characters.
+ *
+ * No more than @a n bytes are read from the input string, so it does not
+ * have to be null-terminated.
+ *
+ * @param dest  Destination buffer.
+ * @param count Size of the destination buffer (must be > 0).
+ * @param src   Source string.
+ * @param n     Maximum number of bytes to read from @a src.
+ *
+ */
+void str_ncpy(char *dest, size_t size, const char *src, size_t n)
+{
+	/* There must be space for a null terminator in the buffer. */
+	size_t src_off = 0;
+	size_t dest_off = 0;
+	wchar_t ch;
+
+	assert(size > 0);
+
+	while ((ch = str_decode(src, &src_off, n)) != 0) {
+		if (chr_encode(ch, dest, &dest_off, size - 1) != 0)
+			break;
+	}
+	
+	dest[dest_off] = '\0';
+}
+
+/** Append one string to another.
+ *
+ * Append source string @a src to string in destination buffer @a dest.
+ * Size of the destination buffer is @a dest. If the size of the output buffer
+ * is at least one byte, the output string will always be well-formed, i.e.
+ * null-terminated and containing only complete characters.
+ *
+ * @param dest   Destination buffer.
+ * @param count Size of the destination buffer.
+ * @param src   Source string.
+ */
+void str_append(char *dest, size_t size, const char *src)
+{
+	size_t dstr_size;
+
+	dstr_size = str_size(dest);
+	if (dstr_size >= size)
+		return;
+	
+	str_cpy(dest + dstr_size, size - dstr_size, src);
+}
+
+/** Convert space-padded ASCII to string.
+ *
+ * Common legacy text encoding in hardware is 7-bit ASCII fitted into
+ * a fixed-width byte buffer (bit 7 always zero), right-padded with spaces
+ * (ASCII 0x20). Convert space-padded ascii to string representation.
+ *
+ * If the text does not fit into the destination buffer, the function converts
+ * as many characters as possible and returns EOVERFLOW.
+ *
+ * If the text contains non-ASCII bytes (with bit 7 set), the whole string is
+ * converted anyway and invalid characters are replaced with question marks
+ * (U_SPECIAL) and the function returns EIO.
+ *
+ * Regardless of return value upon return @a dest will always be well-formed.
+ *
+ * @param dest		Destination buffer
+ * @param size		Size of destination buffer
+ * @param src		Space-padded ASCII.
+ * @param n		Size of the source buffer in bytes.
+ *
+ * @return		0 on success, EOVERFLOW if the text does not fit
+ *			destination buffer, EIO if the text contains
+ *			non-ASCII bytes.
+ */
+int spascii_to_str(char *dest, size_t size, const uint8_t *src, size_t n)
+{
+	size_t sidx;
+	size_t didx;
+	size_t dlast;
+	uint8_t byte;
+	int rc;
+	int result;
+
+	/* There must be space for a null terminator in the buffer. */
+	assert(size > 0);
+	result = 0;
+
+	didx = 0;
+	dlast = 0;
+	for (sidx = 0; sidx < n; ++sidx) {
+		byte = src[sidx];
+		if (!ascii_check(byte)) {
+			byte = U_SPECIAL;
+			result = EIO;
+		}
+
+		rc = chr_encode(byte, dest, &didx, size - 1);
+		if (rc != 0) {
+			assert(rc == EOVERFLOW);
+			dest[didx] = '\0';
+			return rc;
+		}
+
+		/* Remember dest index after last non-empty character */
+		if (byte != 0x20)
+			dlast = didx;
+	}
+
+	/* Terminate string after last non-empty character */
+	dest[dlast] = '\0';
+	return result;
+}
+
+/** 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;
+	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, dest, &dest_off, size - 1) != 0)
+			break;
+	}
+
+	dest[dest_off] = '\0';
+}
+
+/** Convert UTF16 string to string.
+ *
+ * Convert utf16 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. Surrogate pairs also supported.
+ *
+ * @param dest	Destination buffer.
+ * @param size	Size of the destination buffer.
+ * @param src	Source utf16 string.
+ *
+ * @return 0, if success, negative otherwise.
+ */
+int utf16_to_str(char *dest, size_t size, const uint16_t *src)
+{
+	size_t idx = 0, dest_off = 0;
+	wchar_t ch;
+	int rc = 0;
+
+	/* There must be space for a null terminator in the buffer. */
+	assert(size > 0);
+
+	while (src[idx]) {
+		if ((src[idx] & 0xfc00) == 0xd800) {
+			if (src[idx + 1] && (src[idx + 1] & 0xfc00) == 0xdc00) {
+				ch = 0x10000;
+				ch += (src[idx] & 0x03FF) << 10;
+				ch += (src[idx + 1] & 0x03FF);
+				idx += 2;
+			}
+			else
+				break;
+		} else {
+			ch = src[idx];
+			idx++;
+		}
+		rc = chr_encode(ch, dest, &dest_off, size - 1);
+		if (rc != 0)
+			break;
+	}
+	dest[dest_off] = '\0';
+	return rc;
+}
+
+int str_to_utf16(uint16_t *dest, size_t size, const char *src)
+{
+	int rc = 0;
+	size_t offset = 0;
+	size_t idx = 0;
+	wchar_t c;
+
+	assert(size > 0);
+	
+	while ((c = str_decode(src, &offset, STR_NO_LIMIT)) != 0) {
+		if (c > 0x10000) {
+			if (idx + 2 >= size - 1) {
+				rc = EOVERFLOW;
+				break;
+			}
+			c = (c - 0x10000);
+			dest[idx] = 0xD800 | (c >> 10);
+			dest[idx + 1] = 0xDC00 | (c & 0x3FF);
+			idx++;
+		} else {
+			 dest[idx] = c;
+		}
+
+		idx++;
+		if (idx >= size - 1) {
+			rc = EOVERFLOW;
+			break;
+		}
+	}
+
+	dest[idx] = '\0';
+	return rc;
+}
+
+
+/** 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)) != 0)
+			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) != 0)
+			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 dlen. @a dlen must be non-zero
+ * and the wide string written will always be null-terminated.
+ *
+ * @param dest	Destination buffer.
+ * @param dlen	Length of destination buffer (number of wchars).
+ * @param src	Source string.
+ */
+void str_to_wstr(wchar_t *dest, size_t dlen, const char *src)
+{
+	size_t offset;
+	size_t di;
+	wchar_t c;
+
+	assert(dlen > 0);
+
+	offset = 0;
+	di = 0;
+
+	do {
+		if (di >= dlen - 1)
+			break;
+
+		c = str_decode(src, &offset, STR_NO_LIMIT);
+		dest[di++] = c;
+	} while (c != '\0');
+
+	dest[dlen - 1] = '\0';
+}
+
+/** Convert string to wide string.
+ *
+ * Convert string @a src to wide string. A new wide NULL-terminated
+ * string will be allocated on the heap.
+ *
+ * @param src	Source string.
+ */
+wchar_t *str_to_awstr(const char *str)
+{
+	size_t len = str_length(str);
+	
+	wchar_t *wstr = calloc(len+1, sizeof(wchar_t));
+	if (wstr == NULL)
+		return NULL;
+	
+	str_to_wstr(wstr, len + 1, str);
+	return wstr;
+}
+
+/** Find first occurence of character in string.
+ *
+ * @param str String to search.
+ * @param ch  Character to look for.
+ *
+ * @return Pointer to character in @a str or NULL if not found.
+ */
+char *str_chr(const char *str, wchar_t ch)
+{
+	wchar_t acc;
+	size_t off = 0;
+	size_t last = 0;
+	
+	while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
+		if (acc == ch)
+			return (char *) (str + last);
+		last = off;
+	}
+	
+	return NULL;
+}
+
+/** Removes specified trailing characters from a string.
+ *
+ * @param str String to remove from.
+ * @param ch  Character to remove.
+ */
+void str_rtrim(char *str, wchar_t ch)
+{
+	size_t off = 0;
+	size_t pos = 0;
+	wchar_t c;
+	bool update_last_chunk = true;
+	char *last_chunk = NULL;
+
+	while ((c = str_decode(str, &off, STR_NO_LIMIT))) {
+		if (c != ch) {
+			update_last_chunk = true;
+			last_chunk = NULL;
+		} else if (update_last_chunk) {
+			update_last_chunk = false;
+			last_chunk = (str + pos);
+		}
+		pos = off;
+	}
+
+	if (last_chunk)
+		*last_chunk = '\0';
+}
+
+/** Removes specified leading characters from a string.
+ *
+ * @param str String to remove from.
+ * @param ch  Character to remove.
+ */
+void str_ltrim(char *str, wchar_t ch)
+{
+	wchar_t acc;
+	size_t off = 0;
+	size_t pos = 0;
+	size_t str_sz = str_size(str);
+
+	while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
+		if (acc != ch)
+			break;
+		else
+			pos = off;
+	}
+
+	if (pos > 0) {
+		memmove(str, &str[pos], str_sz - pos);
+		pos = str_sz - pos;
+		str[str_sz - pos] = '\0';
+	}
+}
+
+/** Find last occurence of character in string.
+ *
+ * @param str String to search.
+ * @param ch  Character to look for.
+ *
+ * @return Pointer to character in @a str or NULL if not found.
+ */
+char *str_rchr(const char *str, wchar_t ch)
+{
+	wchar_t acc;
+	size_t off = 0;
+	size_t last = 0;
+	const char *res = NULL;
+	
+	while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
+		if (acc == ch)
+			res = (str + last);
+		last = off;
+	}
+	
+	return (char *) res;
+}
+
+/** Insert a wide character into a wide string.
+ *
+ * Insert a wide character into a wide string at position
+ * @a pos. The characters after the position are shifted.
+ *
+ * @param str     String to insert to.
+ * @param ch      Character to insert to.
+ * @param pos     Character index where to insert.
+ @ @param max_pos Characters in the buffer.
+ *
+ * @return True if the insertion was sucessful, false if the position
+ *         is out of bounds.
+ *
+ */
+bool wstr_linsert(wchar_t *str, wchar_t ch, size_t pos, size_t max_pos)
+{
+	size_t len = wstr_length(str);
+	size_t i;
+	
+	if ((pos > len) || (pos + 1 > max_pos))
+		return false;
+	
+	for (i = len; i + 1 > pos; i--)
+		str[i + 1] = str[i];
+	
+	str[pos] = ch;
+	
+	return true;
+}
+
+/** Remove a wide character from a wide string.
+ *
+ * Remove a wide character from a wide string at position
+ * @a pos. The characters after the position are shifted.
+ *
+ * @param str String to remove from.
+ * @param pos Character index to remove.
+ *
+ * @return True if the removal was sucessful, false if the position
+ *         is out of bounds.
+ *
+ */
+bool wstr_remove(wchar_t *str, size_t pos)
+{
+	size_t len = wstr_length(str);
+	size_t i;
+	
+	if (pos >= len)
+		return false;
+	
+	for (i = pos + 1; i <= len; i++)
+		str[i - 1] = str[i];
+	
+	return true;
+}
+
+int stricmp(const char *a, const char *b)
+{
+	int c = 0;
+	
+	while (a[c] && b[c] && (!(tolower(a[c]) - tolower(b[c]))))
+		c++;
+	
+	return (tolower(a[c]) - tolower(b[c]));
+}
+
+/** Convert string to a number. 
+ * Core of strtol and strtoul functions.
+ *
+ * @param nptr		Pointer to string.
+ * @param endptr	If not NULL, function stores here pointer to the first
+ * 			invalid character.
+ * @param base		Zero or number between 2 and 36 inclusive.
+ * @param sgn		It's set to 1 if minus found.
+ * @return		Result of conversion.
+ */
+static unsigned long
+_strtoul(const char *nptr, char **endptr, int base, char *sgn)
+{
+	unsigned char c;
+	unsigned long result = 0;
+	unsigned long a, b;
+	const char *str = nptr;
+	const char *tmpptr;
+	
+	while (isspace(*str))
+		str++;
+	
+	if (*str == '-') {
+		*sgn = 1;
+		++str;
+	} else if (*str == '+')
+		++str;
+	
+	if (base) {
+		if ((base == 1) || (base > 36)) {
+			/* FIXME: set errno to EINVAL */
+			return 0;
+		}
+		if ((base == 16) && (*str == '0') && ((str[1] == 'x') ||
+		    (str[1] == 'X'))) {
+			str += 2;
+		}
+	} else {
+		base = 10;
+		
+		if (*str == '0') {
+			base = 8;
+			if ((str[1] == 'X') || (str[1] == 'x'))  {
+				base = 16;
+				str += 2;
+			}
+		} 
+	}
+	
+	tmpptr = str;
+
+	while (*str) {
+		c = *str;
+		c = (c >= 'a' ? c - 'a' + 10 : (c >= 'A' ? c - 'A' + 10 :
+		    (c <= '9' ? c - '0' : 0xff)));
+		if (c >= base) {
+			break;
+		}
+		
+		a = (result & 0xff) * base + c;
+		b = (result >> 8) * base + (a >> 8);
+		
+		if (b > (ULONG_MAX >> 8)) {
+			/* overflow */
+			/* FIXME: errno = ERANGE*/
+			return ULONG_MAX;
+		}
+	
+		result = (b << 8) + (a & 0xff);
+		++str;
+	}
+	
+	if (str == tmpptr) {
+		/*
+		 * No number was found => first invalid character is the first
+		 * character of the string.
+		 */
+		/* FIXME: set errno to EINVAL */
+		str = nptr;
+		result = 0;
+	}
+	
+	if (endptr)
+		*endptr = (char *) str;
+
+	if (nptr == str) { 
+		/*FIXME: errno = EINVAL*/
+		return 0;
+	}
+
+	return result;
+}
+
+/** Convert initial part of string to long int according to given base.
+ * The number may begin with an arbitrary number of whitespaces followed by
+ * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
+ * inserted and the number will be taken as hexadecimal one. If the base is 0
+ * and the number begin with a zero, number will be taken as octal one (as with
+ * base 8). Otherwise the base 0 is taken as decimal.
+ *
+ * @param nptr		Pointer to string.
+ * @param endptr	If not NULL, function stores here pointer to the first
+ * 			invalid character.
+ * @param base		Zero or number between 2 and 36 inclusive.
+ * @return		Result of conversion.
+ */
+long int strtol(const char *nptr, char **endptr, int base)
+{
+	char sgn = 0;
+	unsigned long number = 0;
+	
+	number = _strtoul(nptr, endptr, base, &sgn);
+
+	if (number > LONG_MAX) {
+		if ((sgn) && (number == (unsigned long) (LONG_MAX) + 1)) {
+			/* FIXME: set 0 to errno */
+			return number;		
+		}
+		/* FIXME: set ERANGE to errno */
+		return (sgn ? LONG_MIN : LONG_MAX);	
+	}
+	
+	return (sgn ? -number : number);
+}
+
+/** Convert initial part of string to unsigned long according to given base.
+ * The number may begin with an arbitrary number of whitespaces followed by
+ * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
+ * inserted and the number will be taken as hexadecimal one. If the base is 0
+ * and the number begin with a zero, number will be taken as octal one (as with
+ * base 8). Otherwise the base 0 is taken as decimal.
+ *
+ * @param nptr		Pointer to string.
+ * @param endptr	If not NULL, function stores here pointer to the first
+ * 			invalid character
+ * @param base		Zero or number between 2 and 36 inclusive.
+ * @return		Result of conversion.
+ */
+unsigned long strtoul(const char *nptr, char **endptr, int base)
+{
+	char sgn = 0;
+	unsigned long number = 0;
+	
+	number = _strtoul(nptr, endptr, base, &sgn);
+
+	return (sgn ? -number : number);
+}
+
+char *strtok(char *s, const char *delim)
+{
+	static char *next;
+
+	return strtok_r(s, delim, &next);
+}
+
+char *strtok_r(char *s, const char *delim, char **next)
+{
+	char *start, *end;
+
+	if (s == NULL)
+		s = *next;
+
+	/* Skip over leading delimiters. */
+	while (*s && (str_chr(delim, *s) != NULL)) ++s;
+	start = s;
+
+	/* Skip over token characters. */
+	while (*s && (str_chr(delim, *s) == NULL)) ++s;
+	end = s;
+	*next = (*s ? s + 1 : s);
+
+	if (start == end) {
+		return NULL;	/* No more tokens. */
+	}
+
+	/* Overwrite delimiter with NULL terminator. */
+	*end = '\0';
+	return start;
+}
+
+/** Convert string to uint64_t (internal variant).
+ *
+ * @param nptr   Pointer to string.
+ * @param endptr Pointer to the first invalid character is stored here.
+ * @param base   Zero or number between 2 and 36 inclusive.
+ * @param neg    Indication of unary minus is stored here.
+ * @apram result Result of the conversion.
+ *
+ * @return 0 if conversion was successful.
+ *
+ */
+static int str_uint(const char *nptr, char **endptr, unsigned int base,
+    bool *neg, uint64_t *result)
+{
+	const char *str = nptr;
+	const char *startstr;
+
+	assert(endptr != NULL);
+	assert(neg != NULL);
+	assert(result != NULL);
+	
+	*neg = false;
+	
+	/* Ignore leading whitespace */
+	while (isspace(*str))
+		str++;
+	
+	if (*str == '-') {
+		*neg = true;
+		str++;
+	} else if (*str == '+')
+		str++;
+	
+	if (base == 0) {
+		/* Decode base if not specified */
+		base = 10;
+		
+		if (*str == '0') {
+			base = 8;
+			str++;
+			
+			switch (*str) {
+			case 'b':
+			case 'B':
+				base = 2;
+				str++;
+				break;
+			case 'o':
+			case 'O':
+				base = 8;
+				str++;
+				break;
+			case 'd':
+			case 'D':
+			case 't':
+			case 'T':
+				base = 10;
+				str++;
+				break;
+			case 'x':
+			case 'X':
+				base = 16;
+				str++;
+				break;
+			default:
+				str--;
+			}
+		}
+	} else {
+		/* Check base range */
+		if ((base < 2) || (base > 36)) {
+			*endptr = (char *) str;
+			return EINVAL;
+		}
+	}
+	
+	*result = 0;
+	startstr = str;
+	
+	while (*str != 0) {
+		unsigned int digit;
+		uint64_t prev;
+		
+		if ((*str >= 'a') && (*str <= 'z'))
+			digit = *str - 'a' + 10;
+		else if ((*str >= 'A') && (*str <= 'Z'))
+			digit = *str - 'A' + 10;
+		else if ((*str >= '0') && (*str <= '9'))
+			digit = *str - '0';
+		else
+			break;
+		
+		if (digit >= base)
+			break;
+		
+		prev = *result;
+		*result = (*result) * base + digit;
+		
+		if (*result < prev) {
+			/* Overflow */
+			*endptr = (char *) str;
+			return EOVERFLOW;
+		}
+		
+		str++;
+	}
+	
+	if (str == startstr) {
+		/*
+		 * No digits were decoded => first invalid character is
+		 * the first character of the string.
+		 */
+		str = nptr;
+	}
+	
+	*endptr = (char *) str;
+	
+	if (str == nptr)
+		return EINVAL;
+	
+	return 0;
+}
+
+/** Convert string to uint8_t.
+ *
+ * @param nptr   Pointer to string.
+ * @param endptr If not NULL, pointer to the first invalid character
+ *               is stored here.
+ * @param base   Zero or number between 2 and 36 inclusive.
+ * @param strict Do not allow any trailing characters.
+ * @param result Result of the conversion.
+ *
+ * @return 0 if conversion was successful.
+ *
+ */
+int str_uint8_t(const char *nptr, char **endptr, unsigned int base,
+    bool strict, uint8_t *result)
+{
+	bool neg;
+	char *lendptr;
+	uint64_t res;
+	int ret;
+	uint8_t _res;
+
+	assert(result != NULL);
+
+	ret = str_uint(nptr, &lendptr, base, &neg, &res);
+	
+	if (endptr != NULL)
+		*endptr = (char *) lendptr;
+	
+	if (ret != 0)
+		return ret;
+	
+	/* Do not allow negative values */
+	if (neg)
+		return EINVAL;
+	
+	/* Check whether we are at the end of
+	   the string in strict mode */
+	if ((strict) && (*lendptr != 0))
+		return EINVAL;
+	
+	/* Check for overflow */
+	_res = (uint8_t) res;
+	if (_res != res)
+		return EOVERFLOW;
+	
+	*result = _res;
+	
+	return 0;
+}
+
+/** Convert string to uint16_t.
+ *
+ * @param nptr   Pointer to string.
+ * @param endptr If not NULL, pointer to the first invalid character
+ *               is stored here.
+ * @param base   Zero or number between 2 and 36 inclusive.
+ * @param strict Do not allow any trailing characters.
+ * @param result Result of the conversion.
+ *
+ * @return 0 if conversion was successful.
+ *
+ */
+int str_uint16_t(const char *nptr, char **endptr, unsigned int base,
+    bool strict, uint16_t *result)
+{
+	bool neg;
+	char *lendptr;
+	uint64_t res;
+	int ret;
+	uint16_t _res;
+
+	assert(result != NULL);
+
+	ret = str_uint(nptr, &lendptr, base, &neg, &res);
+	
+	if (endptr != NULL)
+		*endptr = (char *) lendptr;
+	
+	if (ret != 0)
+		return ret;
+	
+	/* Do not allow negative values */
+	if (neg)
+		return EINVAL;
+	
+	/* Check whether we are at the end of
+	   the string in strict mode */
+	if ((strict) && (*lendptr != 0))
+		return EINVAL;
+	
+	/* Check for overflow */
+	_res = (uint16_t) res;
+	if (_res != res)
+		return EOVERFLOW;
+	
+	*result = _res;
+	
+	return 0;
+}
+
+/** Convert string to uint32_t.
+ *
+ * @param nptr   Pointer to string.
+ * @param endptr If not NULL, pointer to the first invalid character
+ *               is stored here.
+ * @param base   Zero or number between 2 and 36 inclusive.
+ * @param strict Do not allow any trailing characters.
+ * @param result Result of the conversion.
+ *
+ * @return 0 if conversion was successful.
+ *
+ */
+int str_uint32_t(const char *nptr, char **endptr, unsigned int base,
+    bool strict, uint32_t *result)
+{
+	bool neg;
+	char *lendptr;
+	uint64_t res;
+	int ret;
+	uint32_t _res;
+
+	assert(result != NULL);
+
+	ret = str_uint(nptr, &lendptr, base, &neg, &res);
+	
+	if (endptr != NULL)
+		*endptr = (char *) lendptr;
+	
+	if (ret != 0)
+		return ret;
+	
+	/* Do not allow negative values */
+	if (neg)
+		return EINVAL;
+	
+	/* Check whether we are at the end of
+	   the string in strict mode */
+	if ((strict) && (*lendptr != 0))
+		return EINVAL;
+	
+	/* Check for overflow */
+	_res = (uint32_t) res;
+	if (_res != res)
+		return EOVERFLOW;
+	
+	*result = _res;
+	
+	return 0;
+}
+
+/** Convert string to uint64_t.
+ *
+ * @param nptr   Pointer to string.
+ * @param endptr If not NULL, pointer to the first invalid character
+ *               is stored here.
+ * @param base   Zero or number between 2 and 36 inclusive.
+ * @param strict Do not allow any trailing characters.
+ * @param result Result of the conversion.
+ *
+ * @return 0 if conversion was successful.
+ *
+ */
+int str_uint64_t(const char *nptr, char **endptr, unsigned int base,
+    bool strict, uint64_t *result)
+{
+	bool neg;
+	char *lendptr;
+	int ret;
+
+	assert(result != NULL);
+	
+	ret = str_uint(nptr, &lendptr, base, &neg, result);
+	
+	if (endptr != NULL)
+		*endptr = (char *) lendptr;
+	
+	if (ret != 0)
+		return ret;
+	
+	/* Do not allow negative values */
+	if (neg)
+		return EINVAL;
+	
+	/* Check whether we are at the end of
+	   the string in strict mode */
+	if ((strict) && (*lendptr != 0))
+		return EINVAL;
+	
+	return 0;
+}
+
+/** Convert string to size_t.
+ *
+ * @param nptr   Pointer to string.
+ * @param endptr If not NULL, pointer to the first invalid character
+ *               is stored here.
+ * @param base   Zero or number between 2 and 36 inclusive.
+ * @param strict Do not allow any trailing characters.
+ * @param result Result of the conversion.
+ *
+ * @return 0 if conversion was successful.
+ *
+ */
+int str_size_t(const char *nptr, char **endptr, unsigned int base,
+    bool strict, size_t *result)
+{
+	bool neg;
+	char *lendptr;
+	uint64_t res;
+	int ret;
+	size_t _res;
+
+	assert(result != NULL);
+	
+	ret = str_uint(nptr, &lendptr, base, &neg, &res);
+	
+	if (endptr != NULL)
+		*endptr = (char *) lendptr;
+	
+	if (ret != 0)
+		return ret;
+	
+	/* Do not allow negative values */
+	if (neg)
+		return EINVAL;
+	
+	/* Check whether we are at the end of
+	   the string in strict mode */
+	if ((strict) && (*lendptr != 0))
+		return EINVAL;
+	
+	/* Check for overflow */
+	_res = (size_t) res;
+	if (_res != res)
+		return EOVERFLOW;
+	
+	*result = _res;
+	
+	return 0;
+}
+
+void order_suffix(const uint64_t val, uint64_t *rv, char *suffix)
+{
+	if (val > UINT64_C(10000000000000000000)) {
+		*rv = val / UINT64_C(1000000000000000000);
+		*suffix = 'Z';
+	} else if (val > UINT64_C(1000000000000000000)) {
+		*rv = val / UINT64_C(1000000000000000);
+		*suffix = 'E';
+	} else if (val > UINT64_C(1000000000000000)) {
+		*rv = val / UINT64_C(1000000000000);
+		*suffix = 'T';
+	} else if (val > UINT64_C(1000000000000)) {
+		*rv = val / UINT64_C(1000000000);
+		*suffix = 'G';
+	} else if (val > UINT64_C(1000000000)) {
+		*rv = val / UINT64_C(1000000);
+		*suffix = 'M';
+	} else if (val > UINT64_C(1000000)) {
+		*rv = val / UINT64_C(1000);
+		*suffix = 'k';
+	} else {
+		*rv = val;
+		*suffix = ' ';
+	}
+}
+
+void bin_order_suffix(const uint64_t val, uint64_t *rv, const char **suffix,
+    bool fixed)
+{
+	if (val > UINT64_C(1152921504606846976)) {
+		*rv = val / UINT64_C(1125899906842624);
+		*suffix = "EiB";
+	} else if (val > UINT64_C(1125899906842624)) {
+		*rv = val / UINT64_C(1099511627776);
+		*suffix = "TiB";
+	} else if (val > UINT64_C(1099511627776)) {
+		*rv = val / UINT64_C(1073741824);
+		*suffix = "GiB";
+	} else if (val > UINT64_C(1073741824)) {
+		*rv = val / UINT64_C(1048576);
+		*suffix = "MiB";
+	} else if (val > UINT64_C(1048576)) {
+		*rv = val / UINT64_C(1024);
+		*suffix = "KiB";
+	} else {
+		*rv = val;
+		if (fixed)
+			*suffix = "B  ";
+		else
+			*suffix = "B";
+	}
+}
+
+/** @}
+ */
diff --git a/apps/libc/helenos/str.h b/apps/libc/helenos/str.h
new file mode 100644
index 0000000..f114543
--- /dev/null
+++ b/apps/libc/helenos/str.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2005 Martin Decky
+ * Copyright (c) 2011 Oleg Romanenko
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_STR_H_
+#define LIBC_STR_H_
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <wchar.h>
+
+#define U_SPECIAL  '?'
+
+/** No size limit constant */
+#define STR_NO_LIMIT  ((size_t) -1)
+
+/** Maximum size of a string containing @c length characters */
+#define STR_BOUNDS(length)  ((length) << 2)
+
+/**
+ * Maximum size of a buffer needed to a string converted from space-padded
+ * ASCII of size @a spa_size using spascii_to_str().
+ */
+#define SPASCII_STR_BUFSIZE(spa_size) ((spa_size) + 1)
+
+extern wchar_t str_decode(const char *str, size_t *offset, size_t sz);
+extern wchar_t str_decode_reverse(const char *str, size_t *offset, size_t sz);
+extern int chr_encode(const wchar_t ch, char *str, size_t *offset, size_t sz);
+
+extern size_t str_size(const char *str);
+extern size_t wstr_size(const wchar_t *str);
+
+extern size_t str_nsize(const char *str, size_t max_size);
+extern size_t wstr_nsize(const wchar_t *str, size_t max_size);
+
+extern size_t str_lsize(const char *str, size_t max_len);
+extern size_t wstr_lsize(const wchar_t *str, size_t max_len);
+
+extern size_t str_length(const char *str);
+extern size_t wstr_length(const wchar_t *wstr);
+
+extern size_t str_nlength(const char *str, size_t size);
+extern size_t wstr_nlength(const wchar_t *str, size_t size);
+
+extern size_t chr_width(wchar_t ch);
+extern size_t str_width(const char *str);
+
+extern bool ascii_check(wchar_t ch);
+extern bool chr_check(wchar_t ch);
+
+extern int str_cmp(const char *s1, const char *s2);
+extern int str_lcmp(const char *s1, const char *s2, size_t max_len);
+
+extern bool str_test_prefix(const char *s, const char *p);
+
+extern void str_cpy(char *dest, size_t size, const char *src);
+extern void str_ncpy(char *dest, size_t size, const char *src, size_t n);
+extern void str_append(char *dest, size_t size, const char *src);
+
+extern int spascii_to_str(char *dest, size_t size, const uint8_t *src, size_t n);
+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);
+extern wchar_t *str_to_awstr(const char *src);
+extern int utf16_to_str(char *dest, size_t size, const uint16_t *src);
+extern int str_to_utf16(uint16_t *dest, size_t size, const char *src);
+
+extern char *str_chr(const char *str, wchar_t ch);
+extern char *str_rchr(const char *str, wchar_t ch);
+
+extern void str_rtrim(char *str, wchar_t ch);
+extern void str_ltrim(char *str, wchar_t ch);
+
+extern bool wstr_linsert(wchar_t *str, wchar_t ch, size_t pos, size_t max_pos);
+extern bool wstr_remove(wchar_t *str, size_t pos);
+
+extern char *str_dup(const char *);
+extern char *str_ndup(const char *, size_t max_size);
+
+extern int str_uint8_t(const char *, char **, unsigned int, bool, uint8_t *);
+extern int str_uint16_t(const char *, char **, unsigned int, bool, uint16_t *);
+extern int str_uint32_t(const char *, char **, unsigned int, bool, uint32_t *);
+extern int str_uint64_t(const char *, char **, unsigned int, bool, uint64_t *);
+extern int str_size_t(const char *, char **, unsigned int, bool, size_t *);
+
+extern void order_suffix(const uint64_t, uint64_t *, char *);
+extern void bin_order_suffix(const uint64_t, uint64_t *, const char **, bool);
+
+/*
+ * TODO: Get rid of this.
+ */
+
+extern int stricmp(const char *, const char *);
+
+extern long int strtol(const char *, char **, int);
+extern unsigned long strtoul(const char *, char **, int);
+
+extern char * strtok_r(char *, const char *, char **);
+extern char * strtok(char *, const char *);
+
+#endif
+
+/** @}
+ */
diff --git a/apps/libc/helenos/vsnprintf.c b/apps/libc/helenos/vsnprintf.c
new file mode 100644
index 0000000..7b54719
--- /dev/null
+++ b/apps/libc/helenos/vsnprintf.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2006 Josef Cejka
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include "str.h"
+#include "printf_core.h"
+#include <errno.h>
+
+typedef struct {
+	size_t size;    /* Total size of the buffer (in bytes) */
+	size_t len;     /* Number of already used bytes */
+	char *dst;      /* Destination */
+} vsnprintf_data_t;
+
+/** Write string to given buffer.
+ *
+ * Write at most data->size plain characters including trailing zero.
+ * According to C99, snprintf() has to return number of characters that
+ * would have been written if enough space had been available. Hence
+ * the return value is not the number of actually printed characters
+ * but size of the input string.
+ *
+ * @param str  Source string to print.
+ * @param size Number of plain characters in str.
+ * @param data Structure describing destination string, counter
+ *             of used space and total string size.
+ *
+ * @return Number of characters to print (not characters actually
+ *         printed).
+ *
+ */
+static int vsnprintf_str_write(const char *str, size_t size, vsnprintf_data_t *data)
+{
+	size_t left = data->size - data->len;
+	
+	if (left == 0)
+		return ((int) size);
+	
+	if (left == 1) {
+		/* We have only one free byte left in buffer
+		 * -> store trailing zero
+		 */
+		data->dst[data->size - 1] = 0;
+		data->len = data->size;
+		return ((int) size);
+	}
+	
+	if (left <= size) {
+		/* We do not have enough space for the whole string
+		 * with the trailing zero => print only a part
+		 * of string
+		 */
+		size_t index = 0;
+		
+		while (index < size) {
+			wchar_t uc = str_decode(str, &index, size);
+			
+			if (chr_encode(uc, data->dst, &data->len, data->size - 1) != 0)
+				break;
+		}
+		
+		/* Put trailing zero at end, but not count it
+		 * into data->len so it could be rewritten next time
+		 */
+		data->dst[data->len] = 0;
+		
+		return ((int) size);
+	}
+	
+	/* Buffer is big enough to print the whole string */
+	memcpy((void *)(data->dst + data->len), (void *) str, size);
+	data->len += size;
+	
+	/* Put trailing zero at end, but not count it
+	 * into data->len so it could be rewritten next time
+	 */
+	data->dst[data->len] = 0;
+	
+	return ((int) size);
+}
+
+/** Write wide string to given buffer.
+ *
+ * Write at most data->size plain characters including trailing zero.
+ * According to C99, snprintf() has to return number of characters that
+ * would have been written if enough space had been available. Hence
+ * the return value is not the number of actually printed characters
+ * but size of the input string.
+ *
+ * @param str  Source wide string to print.
+ * @param size Number of bytes in str.
+ * @param data Structure describing destination string, counter
+ *             of used space and total string size.
+ *
+ * @return Number of wide characters to print (not characters actually
+ *         printed).
+ *
+ */
+static int vsnprintf_wstr_write(const wchar_t *str, size_t size, vsnprintf_data_t *data)
+{
+	size_t index = 0;
+	
+	while (index < (size / sizeof(wchar_t))) {
+		size_t left = data->size - data->len;
+		
+		if (left == 0)
+			return ((int) size);
+		
+		if (left == 1) {
+			/* We have only one free byte left in buffer
+			 * -> store trailing zero
+			 */
+			data->dst[data->size - 1] = 0;
+			data->len = data->size;
+			return ((int) size);
+		}
+		
+		if (chr_encode(str[index], data->dst, &data->len, data->size - 1) != 0)
+			break;
+		
+		index++;
+	}
+	
+	/* Put trailing zero at end, but not count it
+	 * into data->len so it could be rewritten next time
+	 */
+	data->dst[data->len] = 0;
+	
+	return ((int) size);
+}
+
+int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
+{
+	vsnprintf_data_t data = {
+		size,
+		0,
+		str
+	};
+	printf_spec_t ps = {
+		(int(*) (const char *, size_t, void *)) vsnprintf_str_write,
+		(int(*) (const wchar_t *, size_t, void *)) vsnprintf_wstr_write,
+		&data
+	};
+	
+	/* Print 0 at end of string - fix the case that nothing will be printed */
+	if (size > 0)
+		str[0] = 0;
+	
+	/* vsnprintf_write ensures that str will be terminated by zero. */
+	return printf_core(fmt, &ps, ap);
+}
+
+/** @}
+ */
-- 
1.7.10.4




More information about the barebox mailing list