Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ HelenOS.config	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -462,4 +462,7 @@
 ! [(CONFIG_HID_IN=generic|CONFIG_HID_IN=serial)&PLATFORM=ia64&MACHINE=i460GX] CONFIG_NS16550 (y/n)
 
+% Support for ARM926 on-chip UART
+! [(CONFIG_HID_OUT=generic|CONFIG_HID_OUT=serial)&PLATFORM=arm32&MACHINE=integratorcp] CONFIG_ARM926_UART (y/n)
+
 % Support for Samsung S3C24XX on-chip UART
 ! [(CONFIG_HID_OUT=generic|CONFIG_HID_OUT=serial)&PLATFORM=arm32&MACHINE=gta02] CONFIG_S3C24XX_UART (y/n)
@@ -487,5 +490,5 @@
 
 % Serial line input module
-! [CONFIG_DSRLNIN=y|(PLATFORM=arm32&MACHINE=gta02)|(PLATFORM=ia64&MACHINE=i460GX&CONFIG_NS16550=y)|(PLATFORM=ia64&MACHINE=ski)|(PLATFORM=sparc64&PROCESSOR=sun4v)] CONFIG_SRLN (y)
+! [CONFIG_DSRLNIN=y|(PLATFORM=arm32&MACHINE=gta02)|(PLATFORM=arm32&MACHINE=integratorcp&CONFIG_ARM926_UART=y)|(PLATFORM=ia64&MACHINE=i460GX&CONFIG_NS16550=y)|(PLATFORM=ia64&MACHINE=ski)|(PLATFORM=sparc64&PROCESSOR=sun4v)] CONFIG_SRLN (y)
 
 % EGA support
@@ -584,7 +587,4 @@
 # USB settings
 
-% USB verbose messages
-! CONFIG_USB_VERBOSE (n/y)
-
 % Start virtual USB host controller
 ! CONFIG_RUN_VIRTUAL_USB_HC (n/y)
Index: Makefile
===================================================================
--- Makefile	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -45,5 +45,5 @@
 CONFIG_HEADER = config.h
 
-.PHONY: all precheck cscope autotool config_auto config_default config distclean clean check releasefile release
+.PHONY: all precheck cscope cscope_parts autotool config_auto config_default config distclean clean check releasefile release
 
 all: $(COMMON_MAKEFILE) $(COMMON_HEADER) $(CONFIG_MAKEFILE) $(CONFIG_HEADER)
@@ -58,4 +58,10 @@
 cscope:
 	find abi kernel boot uspace -regex '^.*\.[chsS]$$' | xargs $(CSCOPE) -b -k -u -f$(CSCOPE).out
+
+cscope_parts:
+	find abi -regex '^.*\.[chsS]$$' | xargs $(CSCOPE) -b -k -u -f$(CSCOPE)_abi.out
+	find kernel -regex '^.*\.[chsS]$$' | xargs $(CSCOPE) -b -k -u -f$(CSCOPE)_kernel.out
+	find boot -regex '^.*\.[chsS]$$' | xargs $(CSCOPE) -b -k -u -f$(CSCOPE)_boot.out
+	find uspace -regex '^.*\.[chsS]$$' | xargs $(CSCOPE) -b -k -u -f$(CSCOPE)_uspace.out
 
 # Pre-integration build check
Index: abi/include/ipc/ipc.h
===================================================================
--- abi/include/ipc/ipc.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ abi/include/ipc/ipc.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -57,9 +57,6 @@
 #define IPC_CALL_FORWARDED  (1 << 2)
 
-/** Identify connect_me_to answer */
-#define IPC_CALL_CONN_ME_TO  (1 << 3)
-
 /** Interrupt notification */
-#define IPC_CALL_NOTIF  (1 << 4)
+#define IPC_CALL_NOTIF  (1 << 3)
 
 
Index: abi/include/mm/as.h
===================================================================
--- abi/include/mm/as.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ abi/include/mm/as.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -37,8 +37,9 @@
 
 /** Address space area flags. */
-#define AS_AREA_READ       1
-#define AS_AREA_WRITE      2
-#define AS_AREA_EXEC       4
-#define AS_AREA_CACHEABLE  8
+#define AS_AREA_READ       0x01
+#define AS_AREA_WRITE      0x02
+#define AS_AREA_EXEC       0x04
+#define AS_AREA_CACHEABLE  0x08
+#define AS_AREA_GUARD      0x10
 
 /** Address space area info exported to uspace. */
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ boot/Makefile.common	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -74,5 +74,6 @@
 	$(USPACE_PATH)/srv/locsrv/locsrv \
 	$(USPACE_PATH)/srv/bd/rd/rd \
-	$(USPACE_PATH)/srv/vfs/vfs
+	$(USPACE_PATH)/srv/vfs/vfs \
+	$(USPACE_PATH)/srv/logger/logger
 
 ifeq ($(RDFMT),tmpfs)
@@ -107,4 +108,5 @@
 	$(USPACE_PATH)/srv/fs/cdfs/cdfs \
 	$(USPACE_PATH)/srv/fs/exfat/exfat \
+	$(USPACE_PATH)/srv/fs/udf/udf \
 	$(USPACE_PATH)/srv/fs/ext2fs/ext2fs \
 	$(USPACE_PATH)/srv/fs/ext4fs/ext4fs \
@@ -157,4 +159,5 @@
 
 RD_APPS_NON_ESSENTIAL = \
+	$(USPACE_PATH)/app/bithenge/bithenge \
 	$(USPACE_PATH)/app/blkdump/blkdump \
 	$(USPACE_PATH)/app/bnchmark/bnchmark \
@@ -169,8 +172,8 @@
 	$(USPACE_PATH)/app/killall/killall \
 	$(USPACE_PATH)/app/loc/loc \
+	$(USPACE_PATH)/app/logset/logset \
 	$(USPACE_PATH)/app/mkfat/mkfat \
 	$(USPACE_PATH)/app/mkexfat/mkexfat \
 	$(USPACE_PATH)/app/mkmfs/mkmfs \
-	$(USPACE_PATH)/app/lsusb/lsusb \
 	$(USPACE_PATH)/app/sbi/sbi \
 	$(USPACE_PATH)/app/sportdmp/sportdmp \
@@ -195,4 +198,5 @@
 	$(USPACE_PATH)/app/mkbd/mkbd \
 	$(USPACE_PATH)/app/websrv/websrv \
+	$(USPACE_PATH)/app/date/date \
 	$(USPACE_PATH)/app/vdemo/vdemo
 
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ boot/arch/amd64/Makefile.inc	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -42,4 +42,5 @@
 	char/ps2mouse \
 	char/xtkbd \
+	time/cmos-rtc \
 	bus/usb/ehci\
 	bus/usb/ohci \
Index: boot/arch/arm32/include/main.h
===================================================================
--- boot/arch/arm32/include/main.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ boot/arch/arm32/include/main.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -52,8 +52,8 @@
 
 /** GXemul testarm serial console output register */
-#define TESTARM_SCONS_ADDR 	0x10000000
+#define TESTARM_SCONS_ADDR	0x10000000
 
 /** IntegratorCP serial console output register */
-#define ICP_SCONS_ADDR 		0x16000000
+#define ICP_SCONS_ADDR		0x16000000
 
 extern void bootstrap(void);
Index: boot/arch/ppc32/_link.ld.in
===================================================================
--- boot/arch/ppc32/_link.ld.in	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ boot/arch/ppc32/_link.ld.in	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -2,5 +2,5 @@
 
 SECTIONS {
-	. = 0x01000000;
+	. = 0x02000000;
 	.text : {
 		*(BOOTSTRAP);
Index: boot/arch/ppc32/include/arch.h
===================================================================
--- boot/arch/ppc32/include/arch.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ boot/arch/ppc32/include/arch.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -35,5 +35,5 @@
 #define BOOT_OFFSET  0x8000
 
-#define LOADER_ADDRESS  0x01000000
+#define LOADER_ADDRESS  0x02000000
 
 #ifndef __ASM__
Index: boot/arch/ppc32/src/main.c
===================================================================
--- boot/arch/ppc32/src/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ boot/arch/ppc32/src/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -103,4 +103,10 @@
 	}
 	
+	if (top >= (size_t) loader_address_pa) {
+		printf("Inflated components overlap loader area.\n");
+		printf("The boot image is too large. Halting.\n");
+		halt();
+	}
+	
 	void *balloc_base;
 	void *balloc_base_pa;
Index: boot/generic/include/printf.h
===================================================================
--- boot/generic/include/printf.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ boot/generic/include/printf.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -35,15 +35,5 @@
 #include <typedefs.h>
 #include <stdarg.h>
-
-#ifndef NVERIFY_PRINTF
-
-#define PRINTF_ATTRIBUTE(start, end) \
-	__attribute__((format(gnu_printf, start, end)))
-
-#else /* NVERIFY_PRINTF */
-
-#define PRINTF_ATTRIBUTE(start, end)
-
-#endif /* NVERIFY_PRINTF */
+#include <printf_verify.h>
 
 #define EOF  (-1)
Index: boot/generic/include/printf_verify.h
===================================================================
--- boot/generic/include/printf_verify.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ boot/generic/include/printf_verify.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/** @file
+ */
+
+#ifndef BOOT_PRINTF_VERIFY_H_
+#define BOOT_PRINTF_VERIFY_H_
+
+#ifndef NVERIFY_PRINTF
+
+#define PRINTF_ATTRIBUTE(start, end) \
+	__attribute__((format(gnu_printf, start, end)))
+
+#else /* NVERIFY_PRINTF */
+
+#define PRINTF_ATTRIBUTE(start, end)
+
+#endif /* NVERIFY_PRINTF */
+
+#endif
+
+/** @}
+ */
Index: contrib/bazaar/bzreml/__init__.py
===================================================================
--- contrib/bazaar/bzreml/__init__.py	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ contrib/bazaar/bzreml/__init__.py	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -52,5 +52,5 @@
 
 from bzrlib import errors
-from bzrlib import revision
+from bzrlib import revision as _mod_revision
 from bzrlib import __version__ as bzrlib_version
 
Index: contrib/bazaar/mbprotect/__init__.py
===================================================================
--- contrib/bazaar/mbprotect/__init__.py	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ contrib/bazaar/mbprotect/__init__.py	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -44,4 +44,5 @@
 import bzrlib.branch
 from bzrlib.errors import TipChangeRejected
+from bzrlib import revision as _mod_revision
 
 def iter_reverse_revision_history(repository, revision_id):
Index: contrib/conf/sparc64-qe
===================================================================
--- contrib/conf/sparc64-qe	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ contrib/conf/sparc64-qe	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+qemu-system-sparc64 $@ -M sun4u -boot d -cdrom image.iso
Index: defaults/amd64/Makefile.config
===================================================================
--- defaults/amd64/Makefile.config	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ defaults/amd64/Makefile.config	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -57,5 +57,5 @@
 
 # Default framebuffer mode
-CONFIG_BFB_MODE = 800x600
+CONFIG_BFB_MODE = 1024x768
 
 # Default framebuffer depth
Index: defaults/ia32/Makefile.config
===================================================================
--- defaults/ia32/Makefile.config	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ defaults/ia32/Makefile.config	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -63,5 +63,5 @@
 
 # Default framebuffer mode
-CONFIG_BFB_MODE = 800x600
+CONFIG_BFB_MODE = 1024x768
 
 # Default framebuffer depth
Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -262,4 +262,15 @@
 	generic/src/ipc/ipc.c \
 	generic/src/ipc/sysipc.c \
+	generic/src/ipc/sysipc_ops.c \
+	generic/src/ipc/ops/clnestab.c \
+	generic/src/ipc/ops/conctmeto.c \
+	generic/src/ipc/ops/concttome.c \
+	generic/src/ipc/ops/connclone.c \
+	generic/src/ipc/ops/dataread.c \
+	generic/src/ipc/ops/datawrite.c \
+	generic/src/ipc/ops/debug.c \
+	generic/src/ipc/ops/sharein.c \
+	generic/src/ipc/ops/shareout.c \
+	generic/src/ipc/ops/stchngath.c \
 	generic/src/ipc/ipcrsc.c \
 	generic/src/ipc/irq.c \
Index: kernel/arch/arm32/Makefile.inc
===================================================================
--- kernel/arch/arm32/Makefile.inc	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/arch/arm32/Makefile.inc	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -33,5 +33,5 @@
 ATSIGN = %
 
-GCC_CFLAGS += -march=armv4
+GCC_CFLAGS += -march=armv4 -fno-omit-frame-pointer -mapcs-frame
 
 BITS = 32
Index: kernel/arch/arm32/include/istate.h
===================================================================
--- kernel/arch/arm32/include/istate.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/arch/arm32/include/istate.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -49,4 +49,5 @@
 /** Struct representing CPU state saved when an exception occurs. */
 typedef struct istate {
+	uint32_t dummy;
 	uint32_t spsr;
 	uint32_t sp;
Index: kernel/arch/arm32/src/exc_handler.S
===================================================================
--- kernel/arch/arm32/src/exc_handler.S	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/arch/arm32/src/exc_handler.S	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -130,7 +130,9 @@
 	stmfd r13!, {r2}
 2:
+	sub sp, sp, #4
 .endm
 
 .macro LOAD_REGS_FROM_STACK
+	add sp, sp, #4
 	ldmfd r13!, {r0}
 	msr spsr, r0
Index: kernel/arch/arm32/src/exception.c
===================================================================
--- kernel/arch/arm32/src/exception.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/arch/arm32/src/exception.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -123,5 +123,5 @@
 	
 	asm volatile (
-		"mrc p15, 0, %[control_reg], c1, c1"
+		"mrc p15, 0, %[control_reg], c1, c0"
 		: [control_reg] "=r" (control_reg)
 	);
@@ -131,5 +131,5 @@
 	
 	asm volatile (
-		"mcr p15, 0, %[control_reg], c1, c1"
+		"mcr p15, 0, %[control_reg], c1, c0"
 		:: [control_reg] "r" (control_reg)
 	);
Index: kernel/arch/arm32/src/mach/integratorcp/integratorcp.c
===================================================================
--- kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -38,5 +38,7 @@
 #include <console/chardev.h>
 #include <genarch/drivers/pl050/pl050.h>
+#include <genarch/drivers/arm926_uart/arm926_uart.h>
 #include <genarch/kbrd/kbrd.h>
+#include <genarch/srln/srln.h>
 #include <console/console.h>
 #include <sysinfo/sysinfo.h>
@@ -53,7 +55,15 @@
 #include <print.h>
 
+
 #define SDRAM_SIZE	(sdram[((*(uint32_t *)(ICP_CMCR+ICP_SDRAMCR_OFFSET) & ICP_SDRAM_MASK) >> 2)])
-static icp_hw_map_t icp_hw_map;
-static irq_t icp_timer_irq;
+
+static struct {
+	icp_hw_map_t hw_map;
+	irq_t timer_irq;
+	arm926_uart_t uart;
+} icp;
+
+
+
 struct arm_machine_ops icp_machine_ops = {
 	icp_init,
@@ -70,5 +80,4 @@
 
 static bool hw_map_init_called = false;
-static bool vga_init = false;
 uint32_t sdram[8] = {
 	16777216,	/* 16mb */
@@ -89,12 +98,12 @@
 void icp_vga_init(void)
 {
-	*(uint32_t*)((char *)(icp_hw_map.cmcr)+0x14) = 0xA05F0000;
-	*(uint32_t*)((char *)(icp_hw_map.cmcr)+0x1C) = 0x12C11000;
-	*(uint32_t*)icp_hw_map.vga = 0x3F1F3F9C;
-	*(uint32_t*)((char *)(icp_hw_map.vga) + 0x4) = 0x080B61DF;
-	*(uint32_t*)((char *)(icp_hw_map.vga) + 0x8) = 0x067F3800;
-	*(uint32_t*)((char *)(icp_hw_map.vga) + 0x10) = ICP_FB;
-	*(uint32_t *)((char *)(icp_hw_map.vga) + 0x1C) = 0x182B;
-	*(uint32_t*)((char *)(icp_hw_map.cmcr)+0xC) = 0x33805000;
+	*(uint32_t*)((char *)(icp.hw_map.cmcr)+0x14) = 0xA05F0000;
+	*(uint32_t*)((char *)(icp.hw_map.cmcr)+0x1C) = 0x12C11000;
+	*(uint32_t*)icp.hw_map.vga = 0x3F1F3F9C;
+	*(uint32_t*)((char *)(icp.hw_map.vga) + 0x4) = 0x080B61DF;
+	*(uint32_t*)((char *)(icp.hw_map.vga) + 0x8) = 0x067F3800;
+	*(uint32_t*)((char *)(icp.hw_map.vga) + 0x10) = ICP_FB;
+	*(uint32_t *)((char *)(icp.hw_map.vga) + 0x1C) = 0x182B;
+	*(uint32_t*)((char *)(icp.hw_map.cmcr)+0xC) = 0x33805000;
 	
 }
@@ -103,5 +112,5 @@
 static inline uint32_t icp_irqc_get_sources(void)
 {
-	return *((uint32_t *) icp_hw_map.irqc);
+	return *((uint32_t *) icp.hw_map.irqc);
 }
 
@@ -113,5 +122,5 @@
 static inline void icp_irqc_mask(uint32_t irq)
 {
-	*((uint32_t *) icp_hw_map.irqc_mask) = (1 << irq);
+	*((uint32_t *) icp.hw_map.irqc_mask) = (1 << irq);
 }
 
@@ -123,33 +132,33 @@
 static inline void icp_irqc_unmask(uint32_t irq)
 {
-	*((uint32_t *) icp_hw_map.irqc_unmask) |= (1 << irq);
-}
-
-/** Initializes icp_hw_map. */
+	*((uint32_t *) icp.hw_map.irqc_unmask) |= (1 << irq);
+}
+
+/** Initializes icp.hw_map. */
 void icp_init(void)
 {
-	icp_hw_map.uart = km_map(ICP_UART, PAGE_SIZE,
-	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
-	icp_hw_map.kbd_ctrl = km_map(ICP_KBD, PAGE_SIZE, PAGE_NOT_CACHEABLE);
-	icp_hw_map.kbd_stat = icp_hw_map.kbd_ctrl + ICP_KBD_STAT;
-	icp_hw_map.kbd_data = icp_hw_map.kbd_ctrl + ICP_KBD_DATA;
-	icp_hw_map.kbd_intstat = icp_hw_map.kbd_ctrl + ICP_KBD_INTR_STAT;
-	icp_hw_map.rtc = km_map(ICP_RTC, PAGE_SIZE,
-	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
-	icp_hw_map.rtc1_load = icp_hw_map.rtc + ICP_RTC1_LOAD_OFFSET;
-	icp_hw_map.rtc1_read = icp_hw_map.rtc + ICP_RTC1_READ_OFFSET;
-	icp_hw_map.rtc1_ctl = icp_hw_map.rtc + ICP_RTC1_CTL_OFFSET;
-	icp_hw_map.rtc1_intrclr = icp_hw_map.rtc + ICP_RTC1_INTRCLR_OFFSET;
-	icp_hw_map.rtc1_bgload = icp_hw_map.rtc + ICP_RTC1_BGLOAD_OFFSET;
-	icp_hw_map.rtc1_intrstat = icp_hw_map.rtc + ICP_RTC1_INTRSTAT_OFFSET;
-
-	icp_hw_map.irqc = km_map(ICP_IRQC, PAGE_SIZE,
-	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
-	icp_hw_map.irqc_mask = icp_hw_map.irqc + ICP_IRQC_MASK_OFFSET;
-	icp_hw_map.irqc_unmask = icp_hw_map.irqc + ICP_IRQC_UNMASK_OFFSET;
-	icp_hw_map.cmcr = km_map(ICP_CMCR, PAGE_SIZE,
-	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
-	icp_hw_map.sdramcr = icp_hw_map.cmcr + ICP_SDRAMCR_OFFSET;
-	icp_hw_map.vga = km_map(ICP_VGA, PAGE_SIZE,
+	icp.hw_map.uart = km_map(ICP_UART, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+	icp.hw_map.kbd_ctrl = km_map(ICP_KBD, PAGE_SIZE, PAGE_NOT_CACHEABLE);
+	icp.hw_map.kbd_stat = icp.hw_map.kbd_ctrl + ICP_KBD_STAT;
+	icp.hw_map.kbd_data = icp.hw_map.kbd_ctrl + ICP_KBD_DATA;
+	icp.hw_map.kbd_intstat = icp.hw_map.kbd_ctrl + ICP_KBD_INTR_STAT;
+	icp.hw_map.rtc = km_map(ICP_RTC, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+	icp.hw_map.rtc1_load = icp.hw_map.rtc + ICP_RTC1_LOAD_OFFSET;
+	icp.hw_map.rtc1_read = icp.hw_map.rtc + ICP_RTC1_READ_OFFSET;
+	icp.hw_map.rtc1_ctl = icp.hw_map.rtc + ICP_RTC1_CTL_OFFSET;
+	icp.hw_map.rtc1_intrclr = icp.hw_map.rtc + ICP_RTC1_INTRCLR_OFFSET;
+	icp.hw_map.rtc1_bgload = icp.hw_map.rtc + ICP_RTC1_BGLOAD_OFFSET;
+	icp.hw_map.rtc1_intrstat = icp.hw_map.rtc + ICP_RTC1_INTRSTAT_OFFSET;
+
+	icp.hw_map.irqc = km_map(ICP_IRQC, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+	icp.hw_map.irqc_mask = icp.hw_map.irqc + ICP_IRQC_MASK_OFFSET;
+	icp.hw_map.irqc_unmask = icp.hw_map.irqc + ICP_IRQC_UNMASK_OFFSET;
+	icp.hw_map.cmcr = km_map(ICP_CMCR, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+	icp.hw_map.sdramcr = icp.hw_map.cmcr + ICP_SDRAMCR_OFFSET;
+	icp.hw_map.vga = km_map(ICP_VGA, PAGE_SIZE,
 	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 
@@ -164,7 +173,7 @@
 {
 	icp_irqc_mask(ICP_TIMER_IRQ);
-	*((uint32_t*) icp_hw_map.rtc1_load) = frequency;
-	*((uint32_t*) icp_hw_map.rtc1_bgload) = frequency;
-	*((uint32_t*) icp_hw_map.rtc1_ctl) = ICP_RTC_CTL_VALUE;
+	*((uint32_t*) icp.hw_map.rtc1_load) = frequency;
+	*((uint32_t*) icp.hw_map.rtc1_bgload) = frequency;
+	*((uint32_t*) icp.hw_map.rtc1_ctl) = ICP_RTC_CTL_VALUE;
 	icp_irqc_unmask(ICP_TIMER_IRQ);
 }
@@ -172,6 +181,6 @@
 static irq_ownership_t icp_timer_claim(irq_t *irq)
 {
-	if (icp_hw_map.rtc1_intrstat) {
-		*((uint32_t*) icp_hw_map.rtc1_intrclr) = 1;
+	if (icp.hw_map.rtc1_intrstat) {
+		*((uint32_t*) icp.hw_map.rtc1_intrclr) = 1;
 		return IRQ_ACCEPT;
 	} else
@@ -200,11 +209,11 @@
 static void icp_timer_irq_init(void)
 {
-	irq_initialize(&icp_timer_irq);
-	icp_timer_irq.devno = device_assign_devno();
-	icp_timer_irq.inr = ICP_TIMER_IRQ;
-	icp_timer_irq.claim = icp_timer_claim;
-	icp_timer_irq.handler = icp_timer_irq_handler;
-
-	irq_register(&icp_timer_irq);
+	irq_initialize(&icp.timer_irq);
+	icp.timer_irq.devno = device_assign_devno();
+	icp.timer_irq.inr = ICP_TIMER_IRQ;
+	icp.timer_irq.claim = icp_timer_claim;
+	icp.timer_irq.handler = icp_timer_irq_handler;
+
+	irq_register(&icp.timer_irq);
 }
 
@@ -231,5 +240,5 @@
 
 	if (hw_map_init_called) {
-		*size = (sdram[((*(uint32_t *)icp_hw_map.sdramcr &
+		*size = (sdram[((*(uint32_t *)icp.hw_map.sdramcr &
 		    ICP_SDRAM_MASK) >> 2)]);
 	} else {
@@ -286,4 +295,5 @@
 {
 #ifdef CONFIG_FB
+	static bool vga_init = false;
 	if (!vga_init) {
 		icp_vga_init();
@@ -304,4 +314,9 @@
 		stdout_wire(fbdev);
 #endif
+#ifdef CONFIG_ARM926_UART
+	if (arm926_uart_init(&icp.uart, ARM926_UART0_IRQ,
+	    ARM926_UART0_BASE_ADDRESS, sizeof(arm926_uart_regs_t)))
+		stdout_wire(&icp.uart.outdev);
+#endif
 }
 
@@ -310,7 +325,7 @@
 
 	pl050_t *pl050 = malloc(sizeof(pl050_t), FRAME_ATOMIC);
-	pl050->status = (ioport8_t *)icp_hw_map.kbd_stat;
-	pl050->data = (ioport8_t *)icp_hw_map.kbd_data;
-	pl050->ctrl = (ioport8_t *)icp_hw_map.kbd_ctrl;
+	pl050->status = (ioport8_t *)icp.hw_map.kbd_stat;
+	pl050->data = (ioport8_t *)icp.hw_map.kbd_data;
+	pl050->ctrl = (ioport8_t *)icp.hw_map.kbd_ctrl;
 		
 	pl050_instance_t *pl050_instance = pl050_init(pl050, ICP_KBD_IRQ);
@@ -335,4 +350,13 @@
 	    ICP_KBD);
 
+#ifdef CONFIG_ARM926_UART
+        srln_instance_t *srln_instance = srln_init();
+        if (srln_instance) {
+                indev_t *sink = stdin_wire();
+                indev_t *srln = srln_wire(srln_instance, sink);
+                arm926_uart_input_wire(&icp.uart, srln);
+		icp_irqc_unmask(ARM926_UART0_IRQ);
+        }
+#endif
 }
 
Index: kernel/arch/arm32/src/mm/page_fault.c
===================================================================
--- kernel/arch/arm32/src/mm/page_fault.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/arch/arm32/src/mm/page_fault.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -77,49 +77,4 @@
 }
 
-/** Decides whether the instruction is load/store or not.
- *
- * @param instr Instruction
- *
- * @return true when instruction is load/store, false otherwise
- *
- */
-static inline bool is_load_store_instruction(instruction_t instr)
-{
-	/* load store immediate offset */
-	if (instr.type == 0x2)
-		return true;
-	
-	/* load store register offset */
-	if ((instr.type == 0x3) && (instr.bit4 == 0))
-		return true;
-	
-	/* load store multiple */
-	if (instr.type == 0x4)
-		return true;
-	
-	/* oprocessor load/store */
-	if (instr.type == 0x6)
-		return true;
-	
-	return false;
-}
-
-/** Decides whether the instruction is swap or not.
- *
- * @param instr Instruction
- *
- * @return true when instruction is swap, false otherwise
- */
-static inline bool is_swap_instruction(instruction_t instr)
-{
-	/* swap, swapb instruction */
-	if ((instr.type == 0x0) &&
-	    ((instr.opcode == 0x8) || (instr.opcode == 0xa)) &&
-	    (instr.access == 0x0) && (instr.bits567 == 0x4) && (instr.bit4 == 1))
-		return true;
-	
-	return false;
-}
-
 /** Decides whether read or write into memory is requested.
  *
@@ -128,5 +83,5 @@
  *
  * @return Type of access into memory, PF_ACCESS_EXEC if no memory access is
- * 	   requested.
+ *	   requested.
  */
 static pf_access_t get_memory_access_type(uint32_t instr_addr,
@@ -146,23 +101,38 @@
 	}
 
-	/* load store instructions */
-	if (is_load_store_instruction(instr)) {
-		if (instr.access == 1) {
-			return PF_ACCESS_READ;
-		} else {
-			return PF_ACCESS_WRITE;
+	/* See ARM Architecture reference manual ARMv7-A and ARMV7-R edition
+	 * A5.3 (PDF p. 206) */
+	static const struct {
+		uint32_t mask;
+		uint32_t value;
+		pf_access_t access;
+	} ls_inst[] = {
+		/* Store word/byte */
+		{ 0x0e100000, 0x04000000, PF_ACCESS_WRITE }, /*STR(B) imm*/
+		{ 0x0e100010, 0x06000000, PF_ACCESS_WRITE }, /*STR(B) reg*/
+		/* Load word/byte */
+		{ 0x0e100000, 0x04100000, PF_ACCESS_READ }, /*LDR(B) imm*/
+		{ 0x0e100010, 0x06100000, PF_ACCESS_READ }, /*LDR(B) reg*/
+		/* Store half-word/dual  A5.2.8 */
+		{ 0x0e1000b0, 0x000000b0, PF_ACCESS_WRITE }, /*STRH imm reg*/
+		/* Load half-word/dual A5.2.8 */
+		{ 0x0e0000f0, 0x000000d0, PF_ACCESS_READ }, /*LDRH imm reg*/
+		{ 0x0e1000b0, 0x001000b0, PF_ACCESS_READ }, /*LDRH imm reg*/
+		/* Block data transfer, Store */
+		{ 0x0e100000, 0x08000000, PF_ACCESS_WRITE }, /* STM variants */
+		{ 0x0e100000, 0x08100000, PF_ACCESS_READ },  /* LDM variants */
+		/* Swap */
+		{ 0x0fb00000, 0x01000000, PF_ACCESS_WRITE },
+	};
+	const uint32_t inst = *(uint32_t*)instr_addr;
+	for (unsigned i = 0; i < sizeof(ls_inst) / sizeof(ls_inst[0]); ++i) {
+		if ((inst & ls_inst[i].mask) == ls_inst[i].value) {
+			return ls_inst[i].access;
 		}
-	}
-
-	/* swap, swpb instruction */
-	if (is_swap_instruction(instr)) {
-		return PF_ACCESS_WRITE;
 	}
 
 	panic("page_fault - instruction doesn't access memory "
 	    "(instr_code: %#0" PRIx32 ", badvaddr:%p).",
-	    instr_union.pc, (void *) badvaddr);
-
-	return PF_ACCESS_EXEC;
+	    inst, (void *) badvaddr);
 }
 
Index: kernel/genarch/Makefile.inc
===================================================================
--- kernel/genarch/Makefile.inc	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/genarch/Makefile.inc	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -91,4 +91,9 @@
 endif
 
+ifeq ($(CONFIG_ARM926_UART),y)
+	GENARCH_SOURCES += \
+		genarch/src/drivers/arm926_uart/arm926_uart.c
+endif
+
 ifeq ($(CONFIG_S3C24XX_IRQC),y)
 	GENARCH_SOURCES += \
Index: kernel/genarch/include/drivers/arm926_uart/arm926_uart.h
===================================================================
--- kernel/genarch/include/drivers/arm926_uart/arm926_uart.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/genarch/include/drivers/arm926_uart/arm926_uart.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2012 Jan Vesely
+ * 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 genarch
+ * @{
+ */
+/**
+ * @file
+ * @brief ARM926 on-chip UART (PrimeCell UART, PL011) driver.
+ */
+
+#ifndef KERN_ARM926_UART_H_
+#define KERN_ARM926_UART_H_
+
+#include <ddi/irq.h>
+#include <console/chardev.h>
+#include <typedefs.h>
+
+
+/** ARM926 User Guide ch. 4.8.5 (p. 106 in the pdf) */
+#define ARM926_UART0_BASE_ADDRESS   0x16000000
+#define ARM926_UART1_BASE_ADDRESS   0x16000000
+
+/** ARM926 User Guide ch. A.1 (p. 124 in the pdf) */
+#define ARM926_UART0_IRQ   1
+#define ARM926_UART1_IRQ   2
+
+/** PrimeCell UART TRM ch. 3.3 (p. 49 in the pdf) */
+typedef struct {
+	/** UART data register */
+	ioport32_t data;
+#define ARM926_UART_DATA_DATA_MASK   0xff
+#define ARM926_UART_DATA_FE_FLAG   (1 <<  7)
+#define ARM926_UART_DATA_PE_FLAG   (1 <<  9)
+#define ARM926_UART_DATA_BE_FLAG   (1 << 10)
+#define ARM926_UART_DATA_OE_FLAG   (1 << 11)
+
+	union {
+		/* Same values that are in upper bits of data register*/
+		const ioport32_t status;
+#define ARM926_UART_STATUS_FE_FLAG   (1 << 0)
+#define ARM926_UART_STATUS_PE_FLAG   (1 << 1)
+#define ARM926_UART_STATUS_BE_FLAG   (1 << 2)
+#define ARM926_UART_STATUS_OE_FLAG   (1 << 3)
+		/* Writing anything clears all errors */
+		ioport32_t error_clear;
+	};
+	uint32_t padd0_[4];
+
+	const ioport32_t flag;
+#define ARM926_UART_FLAG_CTS_FLAG    (1 << 0)
+#define ARM926_UART_FLAG_DSR_FLAG    (1 << 1)
+#define ARM926_UART_FLAG_DCD_FLAG    (1 << 2)
+#define ARM926_UART_FLAG_BUSY_FLAG   (1 << 3)
+#define ARM926_UART_FLAG_RXFE_FLAG   (1 << 4)
+#define ARM926_UART_FLAG_TXFF_FLAG   (1 << 5)
+#define ARM926_UART_FLAG_RXFF_FLAG   (1 << 6)
+#define ARM926_UART_FLAG_TXFE_FLAG   (1 << 7)
+#define ARM926_UART_FLAG_RI_FLAG     (1 << 8)
+	uint32_t padd1_;
+
+	ioport32_t irda_low_power;
+#define ARM926_UART_IRDA_LOW_POWER_MASK   0xff
+
+	ioport32_t int_baud_divisor;
+#define ARM926_UART_INT_BAUD_DIVISOR_MASK   0xffff
+
+	ioport32_t fract_baud_divisor;
+#define ARM926_UART_FRACT_BAUD_DIVISOR_MASK   0x1f
+
+	ioport32_t line_control_high;
+#define ARM926_UART_CONTROLHI_BRK_FLAG    (1 << 0)
+#define ARM926_UART_CONTROLHI_PEN_FLAG    (1 << 1)
+#define ARM926_UART_CONTROLHI_EPS_FLAG    (1 << 2)
+#define ARM926_UART_CONTROLHI_STP2_FLAG   (1 << 3)
+#define ARM926_UART_CONTROLHI_FEN_FLAG    (1 << 4)
+#define ARM926_UART_CONTROLHI_WLEN_MASK   0x3
+#define ARM926_UART_CONTROLHI_WLEN_SHIFT    5
+#define ARM926_UART_CONTROLHI_SPS_FLAG    (1 << 5)
+
+	ioport32_t control;
+#define ARM926_UART_CONTROL_UARTEN_FLAG   (1 << 0)
+#define ARM926_UART_CONTROL_SIREN_FLAG    (1 << 1)
+#define ARM926_UART_CONTROL_SIRLP_FLAG    (1 << 2)
+#define ARM926_UART_CONTROL_LBE_FLAG      (1 << 7)
+#define ARM926_UART_CONTROL_TXE_FLAG      (1 << 8)
+#define ARM926_UART_CONTROL_RXE_FLAG      (1 << 9)
+#define ARM926_UART_CONTROL_DTR_FLAG     (1 << 10)
+#define ARM926_UART_CONTROL_RTS_FLAG     (1 << 11)
+#define ARM926_UART_CONTROL_OUT1_FLAG    (1 << 12)
+#define ARM926_UART_CONTROL_OUT2_FLAG    (1 << 13)
+#define ARM926_UART_CONTROL_RTSE_FLAG    (1 << 14)
+#define ARM926_UART_CONTROL_CTSE_FLAG    (1 << 15)
+
+	ioport32_t interrupt_fifo;
+#define ARM926_UART_INTERRUPTFIFO_TX_MASK   0x7
+#define ARM926_UART_INTERRUPTFIFO_TX_SHIFT    0
+#define ARM926_UART_INTERRUPTFIFO_RX_MASK   0x7
+#define ARM926_UART_INTERRUPTFIFO_RX_SHIFT    3
+
+	/** Interrupt mask register */
+	ioport32_t interrupt_mask;
+	/** Pending interrupts before applying the mask */
+	const ioport32_t raw_interrupt_status;
+	/** Pending interrupts after applying the mask */
+	const ioport32_t masked_interrupt_status;
+	/** Write 1s to clear pending interrupts */
+	ioport32_t interrupt_clear;
+#define ARM926_UART_INTERRUPT_RIM_FLAG    (1 << 0)
+#define ARM926_UART_INTERRUPT_CTSM_FLAG   (1 << 1)
+#define ARM926_UART_INTERRUPT_DCDM_FLAG   (1 << 2)
+#define ARM926_UART_INTERRUPT_DSRM_FLAG   (1 << 3)
+#define ARM926_UART_INTERRUPT_RX_FLAG     (1 << 4)
+#define ARM926_UART_INTERRUPT_TX_FLAG     (1 << 5)
+#define ARM926_UART_INTERRUPT_RT_FLAG     (1 << 6)
+#define ARM926_UART_INTERRUPT_FE_FLAG     (1 << 7)
+#define ARM926_UART_INTERRUPT_PE_FLAG     (1 << 8)
+#define ARM926_UART_INTERRUPT_BE_FLAG     (1 << 9)
+#define ARM926_UART_INTERRUPT_OE_FLAG    (1 << 10)
+#define ARM926_UART_INTERRUPT_ALL           0x3ff
+
+	ioport32_t dma_control;
+#define ARM926_UART_DMACONTROL_RXDMAEN_FLAG    (1 << 0)
+#define ARM926_UART_DMACONTROL_TXDMAEN_FLAG    (1 << 1)
+#define ARM926_UART_DMACONTROL_DMAONERR_FLAG   (1 << 2)
+
+	// TODO There is some reserved space here followed by
+	// peripheral identification registers.
+} arm926_uart_regs_t;
+
+typedef struct {
+	arm926_uart_regs_t *regs;
+	indev_t *indev;
+	outdev_t outdev;
+	irq_t irq;
+} arm926_uart_t;
+
+bool arm926_uart_init(arm926_uart_t *, inr_t, uintptr_t, size_t);
+void arm926_uart_input_wire(arm926_uart_t *, indev_t *);
+
+#endif
+/**
+ * @}
+ */
Index: kernel/genarch/include/multiboot/multiboot.h
===================================================================
--- kernel/genarch/include/multiboot/multiboot.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/genarch/include/multiboot/multiboot.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -99,4 +99,5 @@
 
 extern void multiboot_extract_command(char *, size_t, const char *);
+extern void multiboot_extract_argument(char *, size_t, const char *);
 extern void multiboot_info_parse(uint32_t, const multiboot_info_t *);
 
Index: kernel/genarch/src/drivers/arm926_uart/arm926_uart.c
===================================================================
--- kernel/genarch/src/drivers/arm926_uart/arm926_uart.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/genarch/src/drivers/arm926_uart/arm926_uart.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2012 Jan Vesely
+ * 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 genarch
+ * @{
+ */
+/**
+ * @file
+ * @brief ARM926 on-chip UART (PrimeCell UART, PL011) driver.
+ */
+
+#include <genarch/drivers/arm926_uart/arm926_uart.h>
+#include <console/chardev.h>
+#include <console/console.h>
+#include <ddi/device.h>
+#include <arch/asm.h>
+#include <mm/slab.h>
+#include <mm/page.h>
+#include <mm/km.h>
+#include <sysinfo/sysinfo.h>
+#include <str.h>
+
+static void arm926_uart_sendb(arm926_uart_t *uart, uint8_t byte)
+{
+	/* Wait for space becoming available in Tx FIFO. */
+	// TODO make pio_read accept consts pointers and remove the cast
+	while ((pio_read_32((ioport32_t*)&uart->regs->flag) & ARM926_UART_FLAG_TXFF_FLAG) != 0)
+		;
+
+	pio_write_32(&uart->regs->data, byte);
+}
+
+static void arm926_uart_putchar(outdev_t *dev, wchar_t ch)
+{
+	arm926_uart_t *uart = dev->data;
+
+	if (!ascii_check(ch)) {
+		arm926_uart_sendb(uart, U_SPECIAL);
+	} else {
+		if (ch == '\n')
+			arm926_uart_sendb(uart, (uint8_t) '\r');
+		arm926_uart_sendb(uart, (uint8_t) ch);
+	}
+}
+
+static outdev_operations_t arm926_uart_ops = {
+	.write = arm926_uart_putchar,
+	.redraw = NULL,
+};
+
+static irq_ownership_t arm926_uart_claim(irq_t *irq)
+{
+	return IRQ_ACCEPT;
+}
+
+static void arm926_uart_irq_handler(irq_t *irq)
+{
+	arm926_uart_t *uart = irq->instance;
+
+	// TODO make pio_read accept const pointers and remove the cast
+	while ((pio_read_32((ioport32_t*)&uart->regs->flag) & ARM926_UART_FLAG_RXFE_FLAG) == 0) {
+		/* We ignore all error flags here */
+		const uint8_t data = pio_read_32(&uart->regs->data);
+		if (uart->indev)
+			indev_push_character(uart->indev, data);
+	}
+	/* Ack interrupts */
+	pio_write_32(&uart->regs->interrupt_clear, ARM926_UART_INTERRUPT_ALL);
+}
+
+bool arm926_uart_init(
+    arm926_uart_t *uart, inr_t interrupt, uintptr_t addr, size_t size)
+{
+	ASSERT(uart);
+	uart->regs = (void*)km_map(addr, size, PAGE_NOT_CACHEABLE);
+
+	ASSERT(uart->regs);
+
+	/* Enable hw flow control */
+	uart->regs->control = 0 |
+	    ARM926_UART_CONTROL_UARTEN_FLAG |
+	    ARM926_UART_CONTROL_RTSE_FLAG |
+	    ARM926_UART_CONTROL_CTSE_FLAG;
+
+	/* Mask all interrupts */
+	uart->regs->interrupt_mask = 0;
+
+	outdev_initialize("arm926_uart_dev", &uart->outdev, &arm926_uart_ops);
+	uart->outdev.data = uart;
+
+	/* Initialize IRQ */
+	irq_initialize(&uart->irq);
+        uart->irq.devno = device_assign_devno();
+        uart->irq.inr = interrupt;
+        uart->irq.claim = arm926_uart_claim;
+        uart->irq.handler = arm926_uart_irq_handler;
+        uart->irq.instance = uart;
+
+	return true;
+}
+
+void arm926_uart_input_wire(arm926_uart_t *uart, indev_t *indev)
+{
+	ASSERT(uart);
+	ASSERT(indev);
+
+	uart->indev = indev;
+	irq_register(&uart->irq);
+	/* Enable receive interrupt */
+	uart->regs->interrupt_mask |= ARM926_UART_INTERRUPT_RX_FLAG;
+}
+
+/** @}
+ */
+
Index: kernel/genarch/src/multiboot/multiboot.c
===================================================================
--- kernel/genarch/src/multiboot/multiboot.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/genarch/src/multiboot/multiboot.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -71,4 +71,33 @@
 }
 
+/** Extract arguments from the multiboot module command line.
+ *
+ * @param buf      Destination buffer (will be always NULL-terminated).
+ * @param size     Size of destination buffer (in bytes).
+ * @param cmd_line Input string (the command line).
+ *
+ */
+void multiboot_extract_argument(char *buf, size_t size, const char *cmd_line)
+{
+	/* Start after first space. */
+	const char *start = str_chr(cmd_line, ' ');
+	if (start == NULL) {
+		str_cpy(buf, size, "");
+		return;
+	}
+
+	const char *end = cmd_line + str_size(cmd_line);
+
+	/* Skip the space(s). */
+	while (start != end) {
+		if (start[0] == ' ')
+			start++;
+		else
+			break;
+	}
+
+	str_ncpy(buf, size, start, (size_t) (end - start));
+}
+
 static void multiboot_modules(uint32_t count, multiboot_module_t *mods)
 {
@@ -84,6 +113,10 @@
 			multiboot_extract_command(init.tasks[init.cnt].name,
 			    CONFIG_TASK_NAME_BUFLEN, MULTIBOOT_PTR(mods[i].string));
-		} else
+			multiboot_extract_argument(init.tasks[init.cnt].arguments,
+			    CONFIG_TASK_ARGUMENTS_BUFLEN, MULTIBOOT_PTR(mods[i].string));
+		} else {
 			init.tasks[init.cnt].name[0] = 0;
+			init.tasks[init.cnt].arguments[0] = 0;
+		}
 		
 		init.cnt++;
Index: kernel/genarch/src/multiboot/multiboot2.c
===================================================================
--- kernel/genarch/src/multiboot/multiboot2.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/genarch/src/multiboot/multiboot2.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -49,4 +49,6 @@
 		multiboot_extract_command(init.tasks[init.cnt].name,
 		    CONFIG_TASK_NAME_BUFLEN, module->string);
+		multiboot_extract_argument(init.tasks[init.cnt].arguments,
+		    CONFIG_TASK_ARGUMENTS_BUFLEN, module->string);
 		
 		init.cnt++;
Index: kernel/generic/include/config.h
===================================================================
--- kernel/generic/include/config.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/include/config.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -47,4 +47,11 @@
 #define CONFIG_INIT_TASKS        32
 #define CONFIG_TASK_NAME_BUFLEN  32
+#define CONFIG_TASK_ARGUMENTS_BUFLEN 64
+
+/**
+ * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
+ * requests.
+ */
+#define DATA_XFER_LIMIT  (64 * 1024)
 
 #ifndef __ASM__
@@ -56,4 +63,5 @@
 	size_t size;
 	char name[CONFIG_TASK_NAME_BUFLEN];
+	char arguments[CONFIG_TASK_ARGUMENTS_BUFLEN];
 } init_task_t;
 
Index: kernel/generic/include/interrupt.h
===================================================================
--- kernel/generic/include/interrupt.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/include/interrupt.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -59,5 +59,6 @@
 extern exc_table_t exc_table[];
 
-extern void fault_from_uspace(istate_t *, const char *, ...);
+extern void fault_from_uspace(istate_t *, const char *, ...)
+    PRINTF_ATTRIBUTE(2, 3);
 extern void fault_if_from_uspace(istate_t *, const char *, ...)
     PRINTF_ATTRIBUTE(2, 3);
Index: kernel/generic/include/ipc/ipc.h
===================================================================
--- kernel/generic/include/ipc/ipc.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/include/ipc/ipc.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -65,4 +65,5 @@
 	mutex_t lock;
 	link_t link;
+	struct task *caller;
 	struct answerbox *callee;
 	ipc_phone_state_t state;
@@ -72,4 +73,7 @@
 typedef struct answerbox {
 	IRQ_SPINLOCK_DECLARE(lock);
+
+	/** Answerbox is active until it enters cleanup. */
+	bool active;
 	
 	struct task *task;
@@ -106,10 +110,43 @@
 
 typedef struct {
-	link_t link;
+	/**
+	 * Task link.
+	 * Valid only when the call is not forgotten.
+	 * Protected by the task's active_calls_lock.
+	 */
+	link_t ta_link;
+
+	atomic_t refcnt;
+
+	/** Answerbox link. */
+	link_t ab_link;
 	
 	unsigned int flags;
+
+	/** Protects the forget member. */
+	SPINLOCK_DECLARE(forget_lock);
+
+	/**
+	 * True if the caller 'forgot' this call and donated it to the callee.
+	 * Forgotten calls are discarded upon answering (the answer is not
+	 * delivered) and answered calls cannot be forgotten. Forgotten calls
+	 * also do not figure on the task's active call list.
+	 *
+	 * We keep this separate from the flags so that it is not necessary
+	 * to take a lock when accessing them.
+	 */
+	bool forget;
+
+	/** True if the call is in the active list. */
+	bool active;
 	
-	/** Identification of the caller. */
+	/**
+	 * Identification of the caller.
+	 * Valid only when the call is not forgotten.
+	 */
 	struct task *sender;
+	
+	/** Phone which was used to send the call. */
+	phone_t *caller_phone;
 	
 	/** Private data to internal IPC. */
@@ -118,14 +155,10 @@
 	/** Data passed from/to userspace. */
 	ipc_data_t data;
-	
+
+	/** Method as it was sent in the request. */
+	sysarg_t request_method;
+
 	/** Buffer for IPC_M_DATA_WRITE and IPC_M_DATA_READ. */
 	uint8_t *buffer;
-	
-	/*
-	 * The forward operation can masquerade the caller phone. For those
-	 * cases, we must keep it aside so that the answer is processed
-	 * correctly.
-	 */
-	phone_t *caller_phone;
 } call_t;
 
@@ -136,4 +169,6 @@
 extern call_t *ipc_call_alloc(unsigned int);
 extern void ipc_call_free(call_t *);
+extern void ipc_call_hold(call_t *);
+extern void ipc_call_release(call_t *);
 
 extern int ipc_call(phone_t *, call_t *);
@@ -141,7 +176,8 @@
 extern int ipc_forward(call_t *, phone_t *, answerbox_t *, unsigned int);
 extern void ipc_answer(answerbox_t *, call_t *);
+extern void _ipc_answer_free_call(call_t *, bool);
 
-extern void ipc_phone_init(phone_t *);
-extern void ipc_phone_connect(phone_t *, answerbox_t *);
+extern void ipc_phone_init(phone_t *, struct task *);
+extern bool ipc_phone_connect(phone_t *, answerbox_t *);
 extern int ipc_phone_hangup(phone_t *);
 
@@ -151,5 +187,5 @@
 extern void ipc_backsend_err(phone_t *, call_t *, sysarg_t);
 extern void ipc_answerbox_slam_phones(answerbox_t *, bool);
-extern void ipc_cleanup_call_list(list_t *);
+extern void ipc_cleanup_call_list(answerbox_t *, list_t *);
 
 extern void ipc_print_task(task_id_t);
Index: kernel/generic/include/ipc/ipcrsc.h
===================================================================
--- kernel/generic/include/ipc/ipcrsc.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/include/ipc/ipcrsc.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -40,6 +40,7 @@
 
 extern call_t *get_call(sysarg_t);
+extern int phone_get(sysarg_t, phone_t **);
 extern int phone_alloc(task_t *);
-extern void phone_connect(int, answerbox_t *);
+extern bool phone_connect(int, answerbox_t *);
 extern void phone_dealloc(int);
 
Index: kernel/generic/include/ipc/sysipc_ops.h
===================================================================
--- kernel/generic/include/ipc/sysipc_ops.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/include/ipc/sysipc_ops.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2012 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_SYSIPC_OPS_H_
+#define KERN_SYSIPC_OPS_H_
+
+#include <ipc/ipc.h>
+
+#define SYSIPC_OP(op, call, ...) \
+	({ \
+		int rc = EOK; \
+		\
+		sysipc_ops_t *ops; \
+		ops = sysipc_ops_get((call)->request_method); \
+		if (ops->op) \
+			rc = ops->op((call), ##__VA_ARGS__); \
+		rc; \
+	})
+
+/**
+ * This header declares the per-method IPC callbacks. Using these callbacks,
+ * each IPC method (but system methods in particular), can define actions that
+ * will be called at specific moments in the call life-cycle.
+ *
+ * Normally, the kernel will attempt to invoke the following callbacks in the
+ * following order on each call:
+ *
+ * request_preprocess()
+ * request_process()
+ * answer_preprocess()
+ * answer_process()
+ *
+ * This callback invocation sequence is a natural order of processing. Note,
+ * however, that due to various special circumstances, callbacks may be called
+ * also in a different than natural order of processing. This means that some
+ * callbacks may be skipped and some others may be called instead.
+ *
+ * The additional callbacks that may be called are as follows:
+ *
+ * request_forget()
+ * answer_cleanup()
+ *
+ * There are several notable scenarios in which some callbacks of the natural
+ * order of processing will be skipped.
+ *
+ * The request_process(), answer_preprocess() and answer_process() callbacks
+ * will be skipped if the call cannot be delivered to the callee. This may
+ * happen when e.g. the request_preprocess() callback fails or the connection
+ * to the callee is not functional. The next callback that will be invoked on
+ * the call is request_forget().
+ *
+ * The comments for each callback type describe the specifics of each callback
+ * such as the context in which it is invoked and various constraints.
+ */
+
+typedef struct {
+	/**
+	 * This callback is called from request_preprocess().
+	 * 
+	 * Context:		caller
+	 * Caller alive:	guaranteed
+	 * Races with:		N/A
+	 * Invoked on:		all calls
+	 */
+	int (* request_preprocess)(call_t *, phone_t *);
+
+	/**
+	 * This callback is called when the IPC cleanup code wins the race to
+	 * forget the call.
+	 *
+	 * Context:		caller
+	 * Caller alive:	guaranteed
+	 * Races with:		request_process(), answer_cleanup(),
+	 *			_ipc_answer_free_call()
+	 * Invoked on:		all forgotten calls
+	 */	
+	int (* request_forget)(call_t *);
+
+	/**
+	 * This callback is called from process_request().
+	 *
+	 * Context:		callee
+	 * Caller alive:	no guarantee
+	 * Races with:		request_forget()
+	 * Invoked on:		all calls delivered to the callee
+	 */	
+	int (* request_process)(call_t *, answerbox_t *);
+
+	/**
+	 * This callback is called when answer_preprocess() loses the race to
+	 * answer the call.
+	 *
+	 * Context:		callee
+	 * Caller alive:	no guarantee
+	 * Races with:		request_forget()
+	 * Invoked on:		all forgotten calls
+	 */
+	int (* answer_cleanup)(call_t *, ipc_data_t *);
+
+	/**
+	 * This callback is called when answer_preprocess() wins the race to
+	 * answer the call.
+	 *
+	 * Context:		callee
+	 * Caller alive:	guaranteed
+	 * Races with:		N/A
+	 * Invoked on:		all answered calls
+	 */
+	int (* answer_preprocess)(call_t *, ipc_data_t *);
+
+	/**
+	 * This callback is called from process_answer().
+	 *
+	 * Context:		caller
+	 * Caller alive:	guaranteed
+	 * Races with:		N/A
+	 * Invoked on:		all answered calls
+	 */
+	int (* answer_process)(call_t *);
+} sysipc_ops_t;
+
+extern sysipc_ops_t *sysipc_ops_get(sysarg_t);
+
+extern int null_request_preprocess(call_t *, phone_t *);
+extern int null_request_forget(call_t *);
+extern int null_request_process(call_t *, answerbox_t *);
+extern int null_answer_cleanup(call_t *, ipc_data_t *);
+extern int null_answer_preprocess(call_t *, ipc_data_t *);
+extern int null_answer_process(call_t *);
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/ipc/sysipc_priv.h
===================================================================
--- kernel/generic/include/ipc/sysipc_priv.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/include/ipc/sysipc_priv.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_SYSIPC_PRIV_H_
+#define KERN_SYSIPC_PRIV_H_
+
+#include <ipc/ipc.h>
+
+extern int answer_preprocess(call_t *, ipc_data_t *);
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/lib/elf_load.h
===================================================================
--- kernel/generic/include/lib/elf_load.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/include/lib/elf_load.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -42,16 +42,15 @@
  * ELF error return codes
  */
-#define EE_OK			0	/* No error */
-#define EE_INVALID		1	/* Invalid ELF image */
-#define	EE_MEMORY		2	/* Cannot allocate address space */
-#define EE_INCOMPATIBLE		3	/* ELF image is not compatible with current architecture */
-#define EE_UNSUPPORTED		4	/* Non-supported ELF (e.g. dynamic ELFs) */
-#define EE_LOADER		5	/* The image is actually a program loader. */
-#define EE_IRRECOVERABLE	6
+#define EE_OK             0  /* No error */
+#define EE_INVALID        1  /* Invalid ELF image */
+#define EE_MEMORY         2  /* Cannot allocate address space */
+#define EE_INCOMPATIBLE   3  /* ELF image is not compatible with current architecture */
+#define EE_UNSUPPORTED    4  /* Non-supported ELF (e.g. dynamic ELFs) */
+#define EE_LOADER         5  /* The image is actually a program loader. */
+#define EE_IRRECOVERABLE  6  /* Irrecoverable error. */
 
 /**
  * This flags is passed when running the loader, otherwise elf_load()
  * would return with a EE_LOADER error code.
- *
  */
 #define ELD_F_NONE    0
Index: kernel/generic/include/macros.h
===================================================================
--- kernel/generic/include/macros.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/include/macros.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -52,8 +52,19 @@
     uint64_t sz2)
 {
-	uint64_t e1 = s1 + sz1;
-	uint64_t e2 = s2 + sz2;
-	
-	return ((s1 < e2) && (s2 < e1));
+	uint64_t e1 = s1 + sz1 - 1;
+	uint64_t e2 = s2 + sz2 - 1;
+
+	/* both sizes are non-zero */
+	if (sz1 && sz2)
+		return ((s1 <= e2) && (s2 <= e1));
+
+	/* one size is non-zero */
+	if (sz2)
+		return ((s1 >= s2) && (s1 <= e2));
+	if (sz1)
+		return ((s2 >= s1) && (s2 <= e1));
+
+	/* both are zero */
+	return (s1 == s2);
 }
 
@@ -119,4 +130,12 @@
 	    | ((((uint64_t) (up)) & UINT32_C(0xffffffff)) << 32))
 
+/* Test for sum overflow. */
+#define overflows(a, b) \
+	((a) + (b) < (a))
+
+/* Test for sum overflow into positive numbers. */
+#define overflows_into_positive(a, b)	\
+	(overflows((a), (b)) && ((a) + (b) > 0))
+
 /** Pseudorandom generator
  *
Index: kernel/generic/include/print.h
===================================================================
--- kernel/generic/include/print.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/include/print.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -38,15 +38,5 @@
 #include <typedefs.h>
 #include <stdarg.h>
-
-#ifndef NVERIFY_PRINTF
-
-#define PRINTF_ATTRIBUTE(start, end) \
-	__attribute__((format(gnu_printf, start, end)))
-
-#else /* NVERIFY_PRINTF */
-
-#define PRINTF_ATTRIBUTE(start, end)
-
-#endif /* NVERIFY_PRINTF */
+#include <printf/verify.h>
 
 #define EOF  (-1)
Index: kernel/generic/include/printf/verify.h
===================================================================
--- kernel/generic/include/printf/verify.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/include/printf/verify.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/** @addtogroup generic
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_PRINTF_VERIFY_H_
+#define KERN_PRINTF_VERIFY_H_
+
+#ifndef NVERIFY_PRINTF
+
+#define PRINTF_ATTRIBUTE(start, end) \
+	__attribute__((format(gnu_printf, start, end)))
+
+#else /* NVERIFY_PRINTF */
+
+#define PRINTF_ATTRIBUTE(start, end)
+
+#endif /* NVERIFY_PRINTF */
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/proc/task.h
===================================================================
--- kernel/generic/include/proc/task.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/include/proc/task.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -95,8 +95,24 @@
 	
 	/* IPC stuff */
-	answerbox_t answerbox;  /**< Communication endpoint */
+
+	/** Receiving communication endpoint */
+	answerbox_t answerbox;
+
+	/** Sending communication endpoints */
 	phone_t phones[IPC_MAX_PHONES];
-	stats_ipc_t ipc_info;   /**< IPC statistics */
+
+	/** Spinlock protecting the active_calls list. */
+	SPINLOCK_DECLARE(active_calls_lock);
+
+	/**
+	 * List of all calls sent by this task that have not yet been
+	 * answered.
+	 */
+	list_t active_calls;
+
 	event_t events[EVENT_TASK_END - EVENT_END];
+
+	/** IPC statistics */
+	stats_ipc_t ipc_info;
 	
 #ifdef CONFIG_UDEBUG
Index: kernel/generic/src/ipc/event.c
===================================================================
--- kernel/generic/src/ipc/event.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/src/ipc/event.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -163,9 +163,13 @@
 				call->data.task_id = TASK ? TASK->taskid : 0;
 				
-				irq_spinlock_lock(&event->answerbox->irq_lock, true);
-				list_append(&call->link, &event->answerbox->irq_notifs);
-				irq_spinlock_unlock(&event->answerbox->irq_lock, true);
-				
-				waitq_wakeup(&event->answerbox->wq, WAKEUP_FIRST);
+				irq_spinlock_lock(&event->answerbox->irq_lock,
+				    true);
+				list_append(&call->ab_link,
+				    &event->answerbox->irq_notifs);
+				irq_spinlock_unlock(&event->answerbox->irq_lock,
+				    true);
+				
+				waitq_wakeup(&event->answerbox->wq,
+				    WAKEUP_FIRST);
 				
 				if (mask)
Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/src/ipc/ipc.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -45,4 +45,6 @@
 #include <ipc/kbox.h>
 #include <ipc/event.h>
+#include <ipc/sysipc_ops.h>
+#include <ipc/sysipc_priv.h>
 #include <errno.h>
 #include <mm/slab.h>
@@ -71,6 +73,23 @@
 {
 	memsetb(call, sizeof(*call), 0);
-	call->sender = TASK;
+	spinlock_initialize(&call->forget_lock, "forget_lock");
+	call->active = false;
+	call->forget = false;
+	call->sender = NULL;
 	call->buffer = NULL;
+}
+
+void ipc_call_hold(call_t *call)
+{
+	atomic_inc(&call->refcnt);
+}
+
+void ipc_call_release(call_t *call)
+{
+	if (atomic_predec(&call->refcnt) == 0) {
+		if (call->buffer)
+			free(call->buffer);
+		slab_free(ipc_call_slab, call);
+	}
 }
 
@@ -83,5 +102,5 @@
  *
  * @return If flags permit it, return NULL, or initialized kernel
- *         call structure.
+ *         call structure with one reference.
  *
  */
@@ -89,6 +108,8 @@
 {
 	call_t *call = slab_alloc(ipc_call_slab, flags);
-	if (call)
+	if (call) {
 		_ipc_call_init(call);
+		ipc_call_hold(call);
+	}
 	
 	return call;
@@ -102,8 +123,5 @@
 void ipc_call_free(call_t *call)
 {
-	/* Check to see if we have data in the IPC_M_DATA_SEND buffer. */
-	if (call->buffer)
-		free(call->buffer);
-	slab_free(ipc_call_slab, call);
+	ipc_call_release(call);
 }
 
@@ -132,18 +150,24 @@
  * @param phone Initialized phone structure.
  * @param box   Initialized answerbox structure.
- *
- */
-void ipc_phone_connect(phone_t *phone, answerbox_t *box)
-{
+ * @return      True if the phone was connected, false otherwise.
+ */
+bool ipc_phone_connect(phone_t *phone, answerbox_t *box)
+{
+	bool active;
+
 	mutex_lock(&phone->lock);
-	
-	phone->state = IPC_PHONE_CONNECTED;
-	phone->callee = box;
-	
 	irq_spinlock_lock(&box->lock, true);
-	list_append(&phone->link, &box->connected_phones);
+
+	active = box->active;
+	if (active) {
+		phone->state = IPC_PHONE_CONNECTED;
+		phone->callee = box;
+		list_append(&phone->link, &box->connected_phones);
+	}
+
 	irq_spinlock_unlock(&box->lock, true);
-	
 	mutex_unlock(&phone->lock);
+
+	return active;
 }
 
@@ -151,9 +175,11 @@
  *
  * @param phone Phone structure to be initialized.
- *
- */
-void ipc_phone_init(phone_t *phone)
+ * @param caller Owning task.
+ *
+ */
+void ipc_phone_init(phone_t *phone, task_t *caller)
 {
 	mutex_initialize(&phone->lock, MUTEX_PASSIVE);
+	phone->caller = caller;
 	phone->callee = NULL;
 	phone->state = IPC_PHONE_FREE;
@@ -167,23 +193,36 @@
  *
  */
-static void _ipc_answer_free_call(call_t *call, bool selflocked)
-{
-	answerbox_t *callerbox = &call->sender->answerbox;
-	bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox));
-	
+void _ipc_answer_free_call(call_t *call, bool selflocked)
+{
 	/* Count sent answer */
 	irq_spinlock_lock(&TASK->lock, true);
 	TASK->ipc_info.answer_sent++;
 	irq_spinlock_unlock(&TASK->lock, true);
+
+	spinlock_lock(&call->forget_lock);
+	if (call->forget) {
+		/* This is a forgotten call and call->sender is not valid. */
+		spinlock_unlock(&call->forget_lock);
+		ipc_call_free(call);
+		return;
+	} else {
+		/*
+		 * If the call is still active, i.e. it was answered
+		 * in a non-standard way, remove the call from the
+		 * sender's active call list.
+		 */
+		if (call->active) {
+			spinlock_lock(&call->sender->active_calls_lock);
+			list_remove(&call->ta_link);
+			spinlock_unlock(&call->sender->active_calls_lock);
+		}
+	}
+	spinlock_unlock(&call->forget_lock);
+
+	answerbox_t *callerbox = &call->sender->answerbox;
+	bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox));
 	
 	call->flags |= IPC_CALL_ANSWERED;
 	
-	if (call->flags & IPC_CALL_FORWARDED) {
-		if (call->caller_phone) {
-			/* Demasquerade the caller phone. */
-			call->data.phone = call->caller_phone;
-		}
-	}
-
 	call->data.task_id = TASK->taskid;
 	
@@ -191,5 +230,5 @@
 		irq_spinlock_lock(&callerbox->lock, true);
 	
-	list_append(&call->link, &callerbox->answers);
+	list_append(&call->ab_link, &callerbox->answers);
 	
 	if (do_lock)
@@ -209,9 +248,26 @@
 	/* Remove from active box */
 	irq_spinlock_lock(&box->lock, true);
-	list_remove(&call->link);
+	list_remove(&call->ab_link);
 	irq_spinlock_unlock(&box->lock, true);
 	
 	/* Send back answer */
 	_ipc_answer_free_call(call, false);
+}
+
+static void _ipc_call_actions_internal(phone_t *phone, call_t *call)
+{
+	task_t *caller = phone->caller;
+
+	atomic_inc(&phone->active_calls);
+	call->caller_phone = phone;
+	call->sender = caller;
+
+	call->active = true;
+	spinlock_lock(&caller->active_calls_lock);
+	list_append(&call->ta_link, &caller->active_calls);
+	spinlock_unlock(&caller->active_calls_lock);
+
+	call->data.phone = phone;
+	call->data.task_id = caller->taskid;
 }
 
@@ -228,6 +284,5 @@
 void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
 {
-	call->data.phone = phone;
-	atomic_inc(&phone->active_calls);
+	_ipc_call_actions_internal(phone, call);
 	IPC_SET_RETVAL(call->data, err);
 	_ipc_answer_free_call(call, false);
@@ -243,17 +298,16 @@
 static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
 {
+	task_t *caller = phone->caller;
+
 	/* Count sent ipc call */
-	irq_spinlock_lock(&TASK->lock, true);
-	TASK->ipc_info.call_sent++;
-	irq_spinlock_unlock(&TASK->lock, true);
-	
-	if (!(call->flags & IPC_CALL_FORWARDED)) {
-		atomic_inc(&phone->active_calls);
-		call->data.phone = phone;
-		call->data.task_id = TASK->taskid;
-	}
+	irq_spinlock_lock(&caller->lock, true);
+	caller->ipc_info.call_sent++;
+	irq_spinlock_unlock(&caller->lock, true);
+	
+	if (!(call->flags & IPC_CALL_FORWARDED))
+		_ipc_call_actions_internal(phone, call);
 	
 	irq_spinlock_lock(&box->lock, true);
-	list_append(&call->link, &box->calls);
+	list_append(&call->ab_link, &box->calls);
 	irq_spinlock_unlock(&box->lock, true);
 	
@@ -275,8 +329,5 @@
 	if (phone->state != IPC_PHONE_CONNECTED) {
 		mutex_unlock(&phone->lock);
-		if (call->flags & IPC_CALL_FORWARDED) {
-			IPC_SET_RETVAL(call->data, EFORWARD);
-			_ipc_answer_free_call(call, false);
-		} else {
+		if (!(call->flags & IPC_CALL_FORWARDED)) {
 			if (phone->state == IPC_PHONE_HUNGUP)
 				ipc_backsend_err(phone, call, EHANGUP);
@@ -325,4 +376,5 @@
 		call_t *call = ipc_call_alloc(0);
 		IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
+		call->request_method = IPC_M_PHONE_HUNGUP;
 		call->flags |= IPC_CALL_DISCARD_ANSWER;
 		_ipc_call(phone, box, call);
@@ -356,10 +408,8 @@
 	TASK->ipc_info.forwarded++;
 	irq_spinlock_pass(&TASK->lock, &oldbox->lock);
-	list_remove(&call->link);
+	list_remove(&call->ab_link);
 	irq_spinlock_unlock(&oldbox->lock, true);
 	
 	if (mode & IPC_FF_ROUTE_FROM_ME) {
-		if (!call->caller_phone)
-			call->caller_phone = call->data.phone;
 		call->data.phone = newphone;
 		call->data.task_id = TASK->taskid;
@@ -406,6 +456,6 @@
 		
 		request = list_get_instance(list_first(&box->irq_notifs),
-		    call_t, link);
-		list_remove(&request->link);
+		    call_t, ab_link);
+		list_remove(&request->ab_link);
 		
 		irq_spinlock_unlock(&box->irq_lock, false);
@@ -416,7 +466,7 @@
 		/* Handle asynchronous answers */
 		request = list_get_instance(list_first(&box->answers),
-		    call_t, link);
-		list_remove(&request->link);
-		atomic_dec(&request->data.phone->active_calls);
+		    call_t, ab_link);
+		list_remove(&request->ab_link);
+		atomic_dec(&request->caller_phone->active_calls);
 	} else if (!list_empty(&box->calls)) {
 		/* Count received call */
@@ -425,9 +475,9 @@
 		/* Handle requests */
 		request = list_get_instance(list_first(&box->calls),
-		    call_t, link);
-		list_remove(&request->link);
+		    call_t, ab_link);
+		list_remove(&request->ab_link);
 		
 		/* Append request to dispatch queue */
-		list_append(&request->link, &box->dispatched_calls);
+		list_append(&request->ab_link, &box->dispatched_calls);
 	} else {
 		/* This can happen regularly after ipc_cleanup */
@@ -449,19 +499,29 @@
 /** Answer all calls from list with EHANGUP answer.
  *
+ * @param box Answerbox with the list.
  * @param lst Head of the list to be cleaned up.
- *
- */
-void ipc_cleanup_call_list(list_t *lst)
-{
+ */
+void ipc_cleanup_call_list(answerbox_t *box, list_t *lst)
+{
+	irq_spinlock_lock(&box->lock, true);
 	while (!list_empty(lst)) {
-		call_t *call = list_get_instance(list_first(lst), call_t, link);
-		if (call->buffer)
-			free(call->buffer);
-		
-		list_remove(&call->link);
-		
+		call_t *call = list_get_instance(list_first(lst), call_t,
+		    ab_link);
+		
+		list_remove(&call->ab_link);
+
+		irq_spinlock_unlock(&box->lock, true);
+
+		if (lst == &box->calls)
+			SYSIPC_OP(request_process, call, box);
+
+		ipc_data_t old = call->data;
 		IPC_SET_RETVAL(call->data, EHANGUP);
+		answer_preprocess(call, &old);
 		_ipc_answer_free_call(call, true);
-	}
+
+		irq_spinlock_lock(&box->lock, true);
+	}
+	irq_spinlock_unlock(&box->lock, true);
 }
 
@@ -501,5 +561,7 @@
 			mutex_unlock(&phone->lock);
 			irq_spinlock_unlock(&box->lock, true);
-			
+
+			// FIXME: phone can become deallocated at any time now
+
 			/*
 			 * Send one message to the answerbox for each
@@ -509,4 +571,5 @@
 			 */
 			IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
+			call->request_method = IPC_M_PHONE_HUNGUP;
 			call->flags |= IPC_CALL_DISCARD_ANSWER;
 			_ipc_call(phone, box, call);
@@ -529,4 +592,127 @@
 }
 
+static void ipc_forget_all_active_calls(void)
+{
+	call_t *call;
+
+restart:
+	spinlock_lock(&TASK->active_calls_lock);
+	if (list_empty(&TASK->active_calls)) {
+		/*
+		 * We are done, there are no more active calls.
+		 * Nota bene: there may still be answers waiting for pick up.
+		 */
+		spinlock_unlock(&TASK->active_calls_lock);	
+		return;	
+	}
+	
+	call = list_get_instance(list_first(&TASK->active_calls), call_t,
+	    ta_link);
+
+	if (!spinlock_trylock(&call->forget_lock)) {
+		/*
+		 * Avoid deadlock and let async_answer() or
+		 *  _ipc_answer_free_call() win the race to dequeue the first
+		 * call on the list.
+		 */
+		spinlock_unlock(&TASK->active_calls_lock);	
+		goto restart;
+	}
+
+	/*
+	 * Forget the call and donate it to the task which holds up the answer.
+	 */
+
+	call->forget = true;
+	call->sender = NULL;
+	list_remove(&call->ta_link);
+
+	/*
+	 * The call may be freed by _ipc_answer_free_call() before we are done
+	 * with it; to avoid working with a destroyed call_t structure, we
+	 * must hold a reference to it.
+	 */
+	ipc_call_hold(call);
+
+	spinlock_unlock(&call->forget_lock);
+	spinlock_unlock(&TASK->active_calls_lock);
+
+	atomic_dec(&call->caller_phone->active_calls);
+
+	SYSIPC_OP(request_forget, call);
+
+	ipc_call_release(call);
+
+	goto restart;
+}
+
+/** Wait for all answers to asynchronous calls to arrive. */
+static void ipc_wait_for_all_answered_calls(void)
+{
+	call_t *call;
+	size_t i;
+
+restart:
+	/*
+	 * Go through all phones, until they are all free.
+	 * Locking is needed as there may be connection handshakes in progress.
+	 */
+	for (i = 0; i < IPC_MAX_PHONES; i++) {
+		phone_t *phone = &TASK->phones[i];
+
+		mutex_lock(&phone->lock);	
+		if ((phone->state == IPC_PHONE_HUNGUP) &&
+		    (atomic_get(&phone->active_calls) == 0)) {
+			phone->state = IPC_PHONE_FREE;
+			phone->callee = NULL;
+		}
+
+		/*
+		 * We might have had some IPC_PHONE_CONNECTING phones at the
+		 * beginning of ipc_cleanup(). Depending on whether these were
+		 * forgotten or answered, they will eventually enter the
+		 * IPC_PHONE_FREE or IPC_PHONE_CONNECTED states, respectively.
+		 * In the latter case, the other side may slam the open phones
+		 * at any time, in which case we will get an IPC_PHONE_SLAMMED
+		 * phone.
+		 */
+		if ((phone->state == IPC_PHONE_CONNECTED) ||
+		    (phone->state == IPC_PHONE_SLAMMED)) {
+			mutex_unlock(&phone->lock);
+			ipc_phone_hangup(phone);
+			/*
+			 * Now there may be one extra active call, which needs
+			 * to be forgotten.
+			 */
+			ipc_forget_all_active_calls();
+			goto restart;
+		}
+
+		/*
+		 * If the hangup succeeded, it has sent a HANGUP message, the
+		 * IPC is now in HUNGUP state, we wait for the reply to come
+		 */
+		if (phone->state != IPC_PHONE_FREE) {
+			mutex_unlock(&phone->lock);
+			break;
+		}
+
+		mutex_unlock(&phone->lock);
+	}
+		
+	/* Got into cleanup */
+	if (i == IPC_MAX_PHONES)
+		return;
+		
+	call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
+	    SYNCH_FLAGS_NONE);
+	ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
+
+	SYSIPC_OP(answer_process, call);
+
+	ipc_call_free(call);
+	goto restart;
+}
+
 /** Clean up all IPC communication of the current task.
  *
@@ -537,7 +723,16 @@
 void ipc_cleanup(void)
 {
+	/*
+	 * Mark the answerbox as inactive.
+	 *
+	 * The main purpose for doing this is to prevent any pending callback
+	 * connections from getting established beyond this point.
+	 */
+	irq_spinlock_lock(&TASK->answerbox.lock, true);
+	TASK->answerbox.active = false;
+	irq_spinlock_unlock(&TASK->answerbox.lock, true);
+
 	/* Disconnect all our phones ('ipc_phone_hangup') */
-	size_t i;
-	for (i = 0; i < IPC_MAX_PHONES; i++)
+	for (size_t i = 0; i < IPC_MAX_PHONES; i++)
 		ipc_phone_hangup(&TASK->phones[i]);
 	
@@ -557,51 +752,10 @@
 	
 	/* Answer all messages in 'calls' and 'dispatched_calls' queues */
-	irq_spinlock_lock(&TASK->answerbox.lock, true);
-	ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
-	ipc_cleanup_call_list(&TASK->answerbox.calls);
-	irq_spinlock_unlock(&TASK->answerbox.lock, true);
-	
-	/* Wait for all answers to asynchronous calls to arrive */
-	while (true) {
-		/*
-		 * Go through all phones, until they are all FREE
-		 * Locking is not needed, no one else should modify
-		 * it when we are in cleanup
-		 */
-		for (i = 0; i < IPC_MAX_PHONES; i++) {
-			if (TASK->phones[i].state == IPC_PHONE_HUNGUP &&
-			    atomic_get(&TASK->phones[i].active_calls) == 0) {
-				TASK->phones[i].state = IPC_PHONE_FREE;
-				TASK->phones[i].callee = NULL;
-			}
-			
-			/*
-			 * Just for sure, we might have had some
-			 * IPC_PHONE_CONNECTING phones
-			 */
-			if (TASK->phones[i].state == IPC_PHONE_CONNECTED)
-				ipc_phone_hangup(&TASK->phones[i]);
-			
-			/*
-			 * If the hangup succeeded, it has sent a HANGUP
-			 * message, the IPC is now in HUNGUP state, we
-			 * wait for the reply to come
-			 */
-			
-			if (TASK->phones[i].state != IPC_PHONE_FREE)
-				break;
-		}
-		
-		/* Got into cleanup */
-		if (i == IPC_MAX_PHONES)
-			break;
-		
-		call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
-		    SYNCH_FLAGS_NONE);
-		ASSERT((call->flags & IPC_CALL_ANSWERED) ||
-		    (call->flags & IPC_CALL_NOTIF));
-		
-		ipc_call_free(call);
-	}
+	ipc_cleanup_call_list(&TASK->answerbox, &TASK->answerbox.calls);
+	ipc_cleanup_call_list(&TASK->answerbox,
+	    &TASK->answerbox.dispatched_calls);
+
+	ipc_forget_all_active_calls();
+	ipc_wait_for_all_answered_calls();
 }
 
@@ -615,4 +769,38 @@
 	ipc_answerbox_slab = slab_cache_create("answerbox_t",
 	    sizeof(answerbox_t), 0, NULL, NULL, 0);
+}
+
+
+static void ipc_print_call_list(list_t *list)
+{
+	list_foreach(*list, cur) {
+		call_t *call = list_get_instance(cur, call_t, ab_link);
+		
+#ifdef __32_BITS__
+		printf("%10p ", call);
+#endif
+		
+#ifdef __64_BITS__
+		printf("%18p ", call);
+#endif
+		
+		spinlock_lock(&call->forget_lock);
+
+		printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
+		    " %-6" PRIun " %-6" PRIun " %-7x",
+		    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
+		    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
+		    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
+		    call->flags);
+
+		if (call->forget) {
+			printf(" ? (call forgotten)\n");
+		} else {
+			printf(" %" PRIu64 " (%s)\n",
+			    call->sender->taskid, call->sender->name);
+		}
+
+		spinlock_unlock(&call->forget_lock);
+	}
 }
 
@@ -688,62 +876,9 @@
 	
 	printf(" --- incomming calls ---\n");
-	list_foreach(task->answerbox.calls, cur) {
-		call_t *call = list_get_instance(cur, call_t, link);
-		
-#ifdef __32_BITS__
-		printf("%10p ", call);
-#endif
-		
-#ifdef __64_BITS__
-		printf("%18p ", call);
-#endif
-		
-		printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
-		    " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
-		    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
-		    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
-		    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
-		    call->flags, call->sender->taskid, call->sender->name);
-	}
-	
+	ipc_print_call_list(&task->answerbox.calls);
 	printf(" --- dispatched calls ---\n");
-	list_foreach(task->answerbox.dispatched_calls, cur) {
-		call_t *call = list_get_instance(cur, call_t, link);
-		
-#ifdef __32_BITS__
-		printf("%10p ", call);
-#endif
-		
-#ifdef __64_BITS__
-		printf("%18p ", call);
-#endif
-		
-		printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
-		    " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
-		    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
-		    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
-		    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
-		    call->flags, call->sender->taskid, call->sender->name);
-	}
-	
+	ipc_print_call_list(&task->answerbox.dispatched_calls);
 	printf(" --- incoming answers ---\n");
-	list_foreach(task->answerbox.answers, cur) {
-		call_t *call = list_get_instance(cur, call_t, link);
-		
-#ifdef __32_BITS__
-		printf("%10p ", call);
-#endif
-		
-#ifdef __64_BITS__
-		printf("%18p ", call);
-#endif
-		
-		printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
-		    " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
-		    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
-		    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
-		    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
-		    call->flags, call->sender->taskid, call->sender->name);
-	}
+	ipc_print_call_list(&task->answerbox.answers);
 	
 	irq_spinlock_unlock(&task->answerbox.lock, false);
Index: kernel/generic/src/ipc/ipcrsc.c
===================================================================
--- kernel/generic/src/ipc/ipcrsc.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/src/ipc/ipcrsc.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -132,4 +132,5 @@
 #include <ipc/ipcrsc.h>
 #include <debug.h>
+#include <abi/errno.h>
 
 /** Find call_t * in call table according to callid.
@@ -151,5 +152,5 @@
 	
 	list_foreach(TASK->answerbox.dispatched_calls, lst) {
-		call_t *call = list_get_instance(lst, call_t, link);
+		call_t *call = list_get_instance(lst, call_t, ab_link);
 		if ((sysarg_t) call == callid) {
 			result = call;
@@ -162,4 +163,21 @@
 }
 
+/** Get phone from the current task by ID.
+ *
+ * @param phoneid Phone ID.
+ * @param phone   Place to store pointer to phone.
+ *
+ * @return EOK on success, EINVAL if ID is invalid.
+ *
+ */
+int phone_get(sysarg_t phoneid, phone_t **phone)
+{
+	if (phoneid >= IPC_MAX_PHONES)
+		return EINVAL;
+	
+	*phone = &TASK->phones[phoneid];
+	return EOK;
+}
+
 /** Allocate new phone slot in the specified task.
  *
@@ -176,10 +194,12 @@
 	size_t i;
 	for (i = 0; i < IPC_MAX_PHONES; i++) {
-		if ((task->phones[i].state == IPC_PHONE_HUNGUP) &&
-		    (atomic_get(&task->phones[i].active_calls) == 0))
-			task->phones[i].state = IPC_PHONE_FREE;
+		phone_t *phone = &task->phones[i];
+
+		if ((phone->state == IPC_PHONE_HUNGUP) &&
+		    (atomic_get(&phone->active_calls) == 0))
+			phone->state = IPC_PHONE_FREE;
 		
-		if (task->phones[i].state == IPC_PHONE_FREE) {
-			task->phones[i].state = IPC_PHONE_CONNECTING;
+		if (phone->state == IPC_PHONE_FREE) {
+			phone->state = IPC_PHONE_CONNECTING;
 			break;
 		}
@@ -223,4 +243,5 @@
  * @param phoneid Phone handle to be connected.
  * @param box     Answerbox to which to connect the phone handle.
+ * @return        True if the phone was connected, false otherwise.
  *
  * The procedure _enforces_ that the user first marks the phone
@@ -229,10 +250,10 @@
  *
  */
-void phone_connect(int phoneid, answerbox_t *box)
+bool phone_connect(int phoneid, answerbox_t *box)
 {
 	phone_t *phone = &TASK->phones[phoneid];
 	
 	ASSERT(phone->state == IPC_PHONE_CONNECTING);
-	ipc_phone_connect(phone, box);
+	return ipc_phone_connect(phone, box);
 }
 
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/src/ipc/irq.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -510,5 +510,5 @@
 {
 	irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false);
-	list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs);
+	list_append(&call->ab_link, &irq->notif_cfg.answerbox->irq_notifs);
 	irq_spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock, false);
 	
Index: kernel/generic/src/ipc/kbox.c
===================================================================
--- kernel/generic/src/ipc/kbox.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/src/ipc/kbox.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -49,4 +49,12 @@
 {
 	/*
+	 * Not really needed, just to be consistent with the meaning of
+	 * answerbox_t.active.
+	 */
+	irq_spinlock_lock(&TASK->kb.box.lock, true);
+	TASK->kb.box.active = false;
+	irq_spinlock_unlock(&TASK->kb.box.lock, true);
+
+	/*
 	 * Only hold kb.cleanup_lock while setting kb.finished -
 	 * this is enough.
@@ -89,8 +97,6 @@
 	
 	/* Answer all messages in 'calls' and 'dispatched_calls' queues. */
-	irq_spinlock_lock(&TASK->kb.box.lock, true);
-	ipc_cleanup_call_list(&TASK->kb.box.dispatched_calls);
-	ipc_cleanup_call_list(&TASK->kb.box.calls);
-	irq_spinlock_unlock(&TASK->kb.box.lock, true);
+	ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.calls);
+	ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.dispatched_calls);
 }
 
@@ -163,5 +169,5 @@
 	while (!done) {
 		call_t *call = ipc_wait_for_call(&TASK->kb.box, SYNCH_NO_TIMEOUT,
-			SYNCH_FLAGS_NONE);
+		    SYNCH_FLAGS_NONE);
 		
 		if (call == NULL)
@@ -237,5 +243,5 @@
 	
 	/* Connect the newly allocated phone to the kbox */
-	ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
+	(void) ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
 	
 	if (task->kb.thread != NULL) {
Index: kernel/generic/src/ipc/ops/clnestab.c
===================================================================
--- kernel/generic/src/ipc/ops/clnestab.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/src/ipc/ops/clnestab.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2012 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <synch/mutex.h>
+#include <abi/errno.h>
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	IPC_SET_ARG5(call->data, (sysarg_t) phone);
+
+	return EOK;	
+}
+
+static int answer_cleanup(call_t *answer, ipc_data_t *olddata)
+{
+	phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
+
+	mutex_lock(&phone->lock);
+	if (phone->state == IPC_PHONE_CONNECTED) {
+		irq_spinlock_lock(&phone->callee->lock, true);
+		list_remove(&phone->link);
+		phone->state = IPC_PHONE_SLAMMED;
+		irq_spinlock_unlock(&phone->callee->lock, true);
+	}
+	mutex_unlock(&phone->lock);
+
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+
+	if (IPC_GET_RETVAL(answer->data) != EOK) {
+		/*
+		 * The other party on the cloned phone rejected our request
+		 * for connection on the protocol level.  We need to break the
+		 * connection without sending IPC_M_HUNGUP back.
+		 */
+		answer_cleanup(answer, olddata);
+	}
+	
+	return EOK;
+}
+
+sysipc_ops_t ipc_m_clone_establish_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/conctmeto.c
===================================================================
--- kernel/generic/src/ipc/ops/conctmeto.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/src/ipc/ops/conctmeto.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2012 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <ipc/ipcrsc.h>
+#include <abi/errno.h>
+#include <arch.h>
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	int newphid = phone_alloc(TASK);
+
+	if (newphid < 0)
+		return ELIMIT;
+		
+	/* Set arg5 for server */
+	IPC_SET_ARG5(call->data, (sysarg_t) &TASK->phones[newphid]);
+	call->priv = newphid;
+
+	return EOK;
+}
+
+static int request_forget(call_t *call)
+{
+	phone_dealloc(call->priv);
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
+
+	/* If the user accepted call, connect */
+	if (IPC_GET_RETVAL(answer->data) == EOK)
+		(void) ipc_phone_connect(phone, &TASK->answerbox);
+
+	return EOK;
+}
+
+static int answer_process(call_t *answer)
+{
+	if (IPC_GET_RETVAL(answer->data))
+		phone_dealloc(answer->priv);
+	else
+		IPC_SET_ARG5(answer->data, answer->priv);
+	
+	return EOK;
+}
+
+sysipc_ops_t ipc_m_connect_me_to_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/concttome.c
===================================================================
--- kernel/generic/src/ipc/ops/concttome.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/src/ipc/ops/concttome.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2012 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <ipc/ipcrsc.h>
+#include <abi/errno.h>
+#include <arch.h>
+
+static int request_process(call_t *call, answerbox_t *box)
+{
+	int phoneid = phone_alloc(TASK);
+
+	IPC_SET_ARG5(call->data, phoneid);
+	
+	return EOK;
+}
+
+static int answer_cleanup(call_t *answer, ipc_data_t *olddata)
+{
+	int phoneid = (int) IPC_GET_ARG5(*olddata);
+
+	if (phoneid >= 0)
+		phone_dealloc(phoneid);
+
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	int phoneid = (int) IPC_GET_ARG5(*olddata);
+
+	if (IPC_GET_RETVAL(answer->data) != EOK) {
+		/* The connection was not accepted */
+		answer_cleanup(answer, olddata);
+	} else if (phoneid >= 0) {
+		/* The connection was accepted */
+		if (phone_connect(phoneid, &answer->sender->answerbox)) {
+			/* Set 'phone hash' as arg5 of response */
+			IPC_SET_ARG5(answer->data,
+			    (sysarg_t) &TASK->phones[phoneid]);
+		} else {
+			/* The answerbox is shutting down. */
+			IPC_SET_RETVAL(answer->data, ENOENT);
+			answer_cleanup(answer, olddata);
+		}
+	} else {
+		IPC_SET_RETVAL(answer->data, ELIMIT);
+	}
+
+	return EOK;
+}
+
+
+sysipc_ops_t ipc_m_connect_to_me_ops = {
+	.request_preprocess = null_request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = request_process,
+	.answer_cleanup = answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/connclone.c
===================================================================
--- kernel/generic/src/ipc/ops/connclone.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/src/ipc/ops/connclone.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2012 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <ipc/ipcrsc.h>
+#include <synch/mutex.h>
+#include <abi/errno.h>
+#include <arch.h>
+
+static void phones_lock(phone_t *p1, phone_t *p2)
+{
+	if (p1 < p2) {
+		mutex_lock(&p1->lock);
+		mutex_lock(&p2->lock);
+	} else if (p1 > p2) {
+		mutex_lock(&p2->lock);
+		mutex_lock(&p1->lock);
+	} else
+		mutex_lock(&p1->lock);
+}
+
+static void phones_unlock(phone_t *p1, phone_t *p2)
+{
+	mutex_unlock(&p1->lock);
+	if (p1 != p2)
+		mutex_unlock(&p2->lock);
+}
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	phone_t *cloned_phone;
+
+	if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK)
+		return ENOENT;
+		
+	phones_lock(cloned_phone, phone);
+		
+	if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
+	    phone->state != IPC_PHONE_CONNECTED) {
+		phones_unlock(cloned_phone, phone);
+		return EINVAL;
+	}
+		
+	/*
+	 * We can be pretty sure now that both tasks exist and we are
+	 * connected to them. As we continue to hold the phone locks,
+	 * we are effectively preventing them from finishing their
+	 * potential cleanup.
+	 *
+	 */
+	int newphid = phone_alloc(phone->callee->task);
+	if (newphid < 0) {
+		phones_unlock(cloned_phone, phone);
+		return ELIMIT;
+	}
+		
+	(void) ipc_phone_connect(&phone->callee->task->phones[newphid],
+	    cloned_phone->callee);
+	phones_unlock(cloned_phone, phone);
+		
+	/* Set the new phone for the callee. */
+	IPC_SET_ARG1(call->data, newphid);
+
+	return EOK;
+}
+
+static int answer_cleanup(call_t *answer, ipc_data_t *olddata)
+{
+	int phoneid = (int) IPC_GET_ARG1(*olddata);
+	phone_t *phone = &TASK->phones[phoneid];
+
+	/*
+	 * In this case, the connection was established at the request
+	 * time and therefore we need to slam the phone.  We don't
+	 * merely hangup as that would result in sending IPC_M_HUNGUP
+	 * to the third party on the other side of the cloned phone.
+	 */
+	mutex_lock(&phone->lock);
+	if (phone->state == IPC_PHONE_CONNECTED) {
+		irq_spinlock_lock(&phone->callee->lock, true);
+		list_remove(&phone->link);
+		phone->state = IPC_PHONE_SLAMMED;
+		irq_spinlock_unlock(&phone->callee->lock, true);
+	}
+	mutex_unlock(&phone->lock);
+
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	if (IPC_GET_RETVAL(answer->data) != EOK) {
+		/*
+		 * The recipient of the cloned phone rejected the offer.
+		 */
+		answer_cleanup(answer, olddata);
+	}
+
+	return EOK;
+}
+
+sysipc_ops_t ipc_m_connection_clone_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/dataread.c
===================================================================
--- kernel/generic/src/ipc/ops/dataread.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/src/ipc/ops/dataread.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2012 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <mm/slab.h>
+#include <abi/errno.h>
+#include <syscall/copy.h>
+#include <config.h>
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	size_t size = IPC_GET_ARG2(call->data);
+
+	if (size > DATA_XFER_LIMIT) {
+		int flags = IPC_GET_ARG3(call->data);
+
+		if (flags & IPC_XF_RESTRICT)
+			IPC_SET_ARG2(call->data, DATA_XFER_LIMIT);
+		else
+			return ELIMIT;
+	}
+
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	ASSERT(!answer->buffer);
+
+	if (!IPC_GET_RETVAL(answer->data)) {
+		/* The recipient agreed to send data. */
+		uintptr_t src = IPC_GET_ARG1(answer->data);
+		uintptr_t dst = IPC_GET_ARG1(*olddata);
+		size_t max_size = IPC_GET_ARG2(*olddata);
+		size_t size = IPC_GET_ARG2(answer->data);
+
+		if (size && size <= max_size) {
+			/*
+			 * Copy the destination VA so that this piece of
+			 * information is not lost.
+			 */
+			IPC_SET_ARG1(answer->data, dst);
+				
+			answer->buffer = malloc(size, 0);
+			int rc = copy_from_uspace(answer->buffer,
+			    (void *) src, size);
+			if (rc) {
+				IPC_SET_RETVAL(answer->data, rc);
+				/*
+				 * answer->buffer will be cleaned up in
+				 * ipc_call_free().
+				 */
+			}
+		} else if (!size) {
+			IPC_SET_RETVAL(answer->data, EOK);
+		} else {
+			IPC_SET_RETVAL(answer->data, ELIMIT);
+		}
+	}
+
+	return EOK;
+}
+
+static int answer_process(call_t *answer)
+{
+	if (answer->buffer) {
+		uintptr_t dst = IPC_GET_ARG1(answer->data);
+		size_t size = IPC_GET_ARG2(answer->data);
+		int rc;
+
+		rc = copy_to_uspace((void *) dst, answer->buffer, size);
+		if (rc)
+			IPC_SET_RETVAL(answer->data, rc);
+	}
+
+	return EOK;
+}
+
+sysipc_ops_t ipc_m_data_read_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/datawrite.c
===================================================================
--- kernel/generic/src/ipc/ops/datawrite.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/src/ipc/ops/datawrite.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2012 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <mm/slab.h>
+#include <abi/errno.h>
+#include <syscall/copy.h>
+#include <config.h>
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	uintptr_t src = IPC_GET_ARG1(call->data);
+	size_t size = IPC_GET_ARG2(call->data);
+
+	if (size > DATA_XFER_LIMIT) {
+		int flags = IPC_GET_ARG3(call->data);
+
+		if (flags & IPC_XF_RESTRICT) {
+			size = DATA_XFER_LIMIT;
+			IPC_SET_ARG2(call->data, size);
+		} else
+			return ELIMIT;
+	}
+
+	call->buffer = (uint8_t *) malloc(size, 0);
+	int rc = copy_from_uspace(call->buffer, (void *) src, size);
+	if (rc != 0) {
+		/*
+		 * call->buffer will be cleaned up in ipc_call_free() at the
+		 * latest.
+		 */
+		return rc;
+	}
+		
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	ASSERT(answer->buffer);
+
+	if (!IPC_GET_RETVAL(answer->data)) {
+		/* The recipient agreed to receive data. */
+		uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data);
+		size_t size = (size_t)IPC_GET_ARG2(answer->data);
+		size_t max_size = (size_t)IPC_GET_ARG2(*olddata);
+			
+		if (size <= max_size) {
+			int rc = copy_to_uspace((void *) dst,
+			    answer->buffer, size);
+			if (rc)
+				IPC_SET_RETVAL(answer->data, rc);
+		} else {
+			IPC_SET_RETVAL(answer->data, ELIMIT);
+		}
+	}
+
+	return EOK;
+}
+
+
+sysipc_ops_t ipc_m_data_write_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/debug.c
===================================================================
--- kernel/generic/src/ipc/ops/debug.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/src/ipc/ops/debug.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2008 Jiri Svoboda 
+ * 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <udebug/udebug_ipc.h>
+#include <syscall/copy.h>
+#include <abi/errno.h>
+
+static int request_process(call_t *call, answerbox_t *box)
+{
+	return -1;
+}
+
+static int answer_process(call_t *answer)
+{
+	if (answer->buffer) {
+		uintptr_t dst = IPC_GET_ARG1(answer->data);
+		size_t size = IPC_GET_ARG2(answer->data);
+		int rc;
+
+		rc = copy_to_uspace((void *) dst, answer->buffer, size);
+		if (rc)
+			IPC_SET_RETVAL(answer->data, rc);
+	}
+
+	return EOK;
+}
+
+sysipc_ops_t ipc_m_debug_ops = {
+#ifdef CONFIG_UDEBUG
+	.request_preprocess = udebug_request_preprocess,
+#else
+	.request_preprocess = null_request_preprocess,
+#endif
+	.request_forget = null_request_forget,
+	.request_process = request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = null_answer_preprocess,
+	.answer_process = answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/sharein.c
===================================================================
--- kernel/generic/src/ipc/ops/sharein.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/src/ipc/ops/sharein.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2012 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <mm/as.h>
+#include <synch/spinlock.h>
+#include <proc/task.h>
+#include <abi/errno.h>
+#include <arch.h>
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	if (!IPC_GET_RETVAL(answer->data)) {
+		irq_spinlock_lock(&answer->sender->lock, true);
+		as_t *as = answer->sender->as;
+		irq_spinlock_unlock(&answer->sender->lock, true);
+			
+		uintptr_t dst_base = (uintptr_t) -1;
+		int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
+		    IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data),
+		    &dst_base, IPC_GET_ARG3(answer->data));
+		IPC_SET_ARG4(answer->data, dst_base);
+		IPC_SET_RETVAL(answer->data, rc);
+	}
+	
+	return EOK;
+}
+
+sysipc_ops_t ipc_m_share_in_ops = {
+	.request_preprocess = null_request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/shareout.c
===================================================================
--- kernel/generic/src/ipc/ops/shareout.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/src/ipc/ops/shareout.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <mm/as.h>
+#include <synch/spinlock.h>
+#include <proc/task.h>
+#include <syscall/copy.h>
+#include <abi/errno.h>
+#include <arch.h>
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	size_t size = as_area_get_size(IPC_GET_ARG1(call->data));
+
+	if (!size)
+		return EPERM;
+	IPC_SET_ARG2(call->data, size);
+
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	int rc = EOK;
+
+	if (!IPC_GET_RETVAL(answer->data)) {
+		/* Accepted, handle as_area receipt */
+
+		irq_spinlock_lock(&answer->sender->lock, true);
+		as_t *as = answer->sender->as;
+		irq_spinlock_unlock(&answer->sender->lock, true);
+
+		uintptr_t dst_base = (uintptr_t) -1;
+		rc = as_area_share(as, IPC_GET_ARG1(*olddata),
+		    IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata),
+		    &dst_base, IPC_GET_ARG1(answer->data));
+			
+		if (rc == EOK) {
+			rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data),
+			    &dst_base, sizeof(dst_base));
+		}
+			
+		IPC_SET_RETVAL(answer->data, rc);
+	}
+
+	return rc;
+}
+
+sysipc_ops_t ipc_m_share_out_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/stchngath.c
===================================================================
--- kernel/generic/src/ipc/ops/stchngath.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/src/ipc/ops/stchngath.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2012 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <ipc/ipcrsc.h>
+#include <synch/mutex.h>
+#include <proc/task.h>
+#include <abi/errno.h>
+#include <macros.h>
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	phone_t *sender_phone;
+	task_t *other_task_s;
+
+	if (phone_get(IPC_GET_ARG5(call->data), &sender_phone) != EOK)
+		return ENOENT;
+
+	mutex_lock(&sender_phone->lock);
+	if (sender_phone->state != IPC_PHONE_CONNECTED) {
+		mutex_unlock(&sender_phone->lock);
+		return EINVAL;
+	}
+
+	other_task_s = sender_phone->callee->task;
+
+	mutex_unlock(&sender_phone->lock);
+
+	/* Remember the third party task hash. */
+	IPC_SET_ARG5(call->data, (sysarg_t) other_task_s);
+
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	int rc = EOK;
+
+	if (!IPC_GET_RETVAL(answer->data)) {
+		/* The recipient authorized the change of state. */
+		phone_t *recipient_phone;
+		task_t *other_task_s;
+		task_t *other_task_r;
+
+		rc = phone_get(IPC_GET_ARG1(answer->data),
+		    &recipient_phone);
+		if (rc != EOK) {
+			IPC_SET_RETVAL(answer->data, ENOENT);
+			return ENOENT;
+		}
+
+		mutex_lock(&recipient_phone->lock);
+		if (recipient_phone->state != IPC_PHONE_CONNECTED) {
+			mutex_unlock(&recipient_phone->lock);
+			IPC_SET_RETVAL(answer->data, EINVAL);
+			return EINVAL;
+		}
+
+		other_task_r = recipient_phone->callee->task;
+		other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
+
+		/*
+		 * See if both the sender and the recipient meant the
+		 * same third party task.
+		 */
+		if (other_task_r != other_task_s) {
+			IPC_SET_RETVAL(answer->data, EINVAL);
+			rc = EINVAL;
+		} else {
+			rc = event_task_notify_5(other_task_r,
+			    EVENT_TASK_STATE_CHANGE, false,
+			    IPC_GET_ARG1(*olddata),
+			    IPC_GET_ARG2(*olddata),
+			    IPC_GET_ARG3(*olddata),
+			    LOWER32(olddata->task_id),
+			    UPPER32(olddata->task_id));
+			IPC_SET_RETVAL(answer->data, rc);
+		}
+
+		mutex_unlock(&recipient_phone->lock);
+	}
+
+	return rc;
+}
+
+sysipc_ops_t ipc_m_state_change_authorize_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/src/ipc/sysipc.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -34,12 +34,11 @@
 
 #include <arch.h>
-#include <proc/task.h>
-#include <proc/thread.h>
 #include <errno.h>
 #include <memstr.h>
-#include <debug.h>
 #include <ipc/ipc.h>
 #include <abi/ipc/methods.h>
 #include <ipc/sysipc.h>
+#include <ipc/sysipc_ops.h>
+#include <ipc/sysipc_priv.h>
 #include <ipc/irq.h>
 #include <ipc/ipcrsc.h>
@@ -47,37 +46,12 @@
 #include <ipc/kbox.h>
 #include <synch/waitq.h>
-#include <udebug/udebug_ipc.h>
 #include <arch/interrupt.h>
 #include <syscall/copy.h>
 #include <security/cap.h>
 #include <console/console.h>
-#include <mm/as.h>
 #include <print.h>
 #include <macros.h>
 
-/**
- * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
- * requests.
- */
-#define DATA_XFER_LIMIT  (64 * 1024)
-
 #define STRUCT_TO_USPACE(dst, src)  copy_to_uspace((dst), (src), sizeof(*(src)))
-
-/** Get phone from the current task by ID.
- *
- * @param phoneid Phone ID.
- * @param phone   Place to store pointer to phone.
- *
- * @return EOK on success, EINVAL if ID is invalid.
- *
- */
-static int phone_get(sysarg_t phoneid, phone_t **phone)
-{
-	if (phoneid >= IPC_MAX_PHONES)
-		return EINVAL;
-	
-	*phone = &TASK->phones[phoneid];
-	return EOK;
-}
 
 /** Decide if the interface and method is a system method.
@@ -181,235 +155,59 @@
  * @param olddata Saved data of the request.
  *
- * @return Return 0 on success or an error code.
- *
- */
-static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
-{
+ * @return Return EOK on success or a negative error code.
+ *
+ */
+int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	int rc = EOK;
+
+	spinlock_lock(&answer->forget_lock);
+	if (answer->forget) {
+		/*
+		 * This is a forgotten call and answer->sender is not valid.
+		 */
+		spinlock_unlock(&answer->forget_lock);
+
+		SYSIPC_OP(answer_cleanup, answer, olddata);
+		return rc;
+	} else {
+		ASSERT(answer->active);
+
+		/*
+		 * Mark the call as inactive to prevent _ipc_answer_free_call()
+		 * from attempting to remove the call from the active list
+		 * itself.
+		 */
+		answer->active = false;
+
+		/*
+		 * Remove the call from the sender's active call list.
+		 * We enforce this locking order so that any potential
+		 * concurrently executing forget operation is forced to
+		 * release its active_calls_lock and lose the race to
+		 * forget this soon to be answered call. 
+		 */
+		spinlock_lock(&answer->sender->active_calls_lock);
+		list_remove(&answer->ta_link);
+		spinlock_unlock(&answer->sender->active_calls_lock);
+	}
+	spinlock_unlock(&answer->forget_lock);
+
 	if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
-		/* In case of forward, hangup the forwared phone,
-		 * not the originator
-		 */
-		mutex_lock(&answer->data.phone->lock);
-		irq_spinlock_lock(&TASK->answerbox.lock, true);
-		if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
-			list_remove(&answer->data.phone->link);
-			answer->data.phone->state = IPC_PHONE_SLAMMED;
+		phone_t *phone = answer->caller_phone;
+		mutex_lock(&phone->lock);
+		if (phone->state == IPC_PHONE_CONNECTED) {
+			irq_spinlock_lock(&phone->callee->lock, true);
+			list_remove(&phone->link);
+			phone->state = IPC_PHONE_SLAMMED;
+			irq_spinlock_unlock(&phone->callee->lock, true);
 		}
-		irq_spinlock_unlock(&TASK->answerbox.lock, true);
-		mutex_unlock(&answer->data.phone->lock);
+		mutex_unlock(&phone->lock);
 	}
 	
 	if (!olddata)
-		return 0;
-	
-	if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECTION_CLONE) {
-		int phoneid = IPC_GET_ARG1(*olddata);
-		phone_t *phone = &TASK->phones[phoneid];
-		
-		if (IPC_GET_RETVAL(answer->data) != EOK) {
-			/*
-			 * The recipient of the cloned phone rejected the offer.
-			 * In this case, the connection was established at the
-			 * request time and therefore we need to slam the phone.
-			 * We don't merely hangup as that would result in
-			 * sending IPC_M_HUNGUP to the third party on the
-			 * other side of the cloned phone.
-			 */
-			mutex_lock(&phone->lock);
-			if (phone->state == IPC_PHONE_CONNECTED) {
-				irq_spinlock_lock(&phone->callee->lock, true);
-				list_remove(&phone->link);
-				phone->state = IPC_PHONE_SLAMMED;
-				irq_spinlock_unlock(&phone->callee->lock, true);
-			}
-			mutex_unlock(&phone->lock);
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CLONE_ESTABLISH) {
-		phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
-		
-		if (IPC_GET_RETVAL(answer->data) != EOK) {
-			/*
-			 * The other party on the cloned phoned rejected our
-			 * request for connection on the protocol level.
-			 * We need to break the connection without sending
-			 * IPC_M_HUNGUP back.
-			 */
-			mutex_lock(&phone->lock);
-			if (phone->state == IPC_PHONE_CONNECTED) {
-				irq_spinlock_lock(&phone->callee->lock, true);
-				list_remove(&phone->link);
-				phone->state = IPC_PHONE_SLAMMED;
-				irq_spinlock_unlock(&phone->callee->lock, true);
-			}
-			mutex_unlock(&phone->lock);
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
-		int phoneid = IPC_GET_ARG5(*olddata);
-		
-		if (IPC_GET_RETVAL(answer->data) != EOK) {
-			/* The connection was not accepted */
-			phone_dealloc(phoneid);
-		} else {
-			/* The connection was accepted */
-			phone_connect(phoneid, &answer->sender->answerbox);
-			/* Set 'phone hash' as arg5 of response */
-			IPC_SET_ARG5(answer->data,
-			    (sysarg_t) &TASK->phones[phoneid]);
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
-		/* If the users accepted call, connect */
-		if (IPC_GET_RETVAL(answer->data) == EOK) {
-			ipc_phone_connect((phone_t *) IPC_GET_ARG5(*olddata),
-			    &TASK->answerbox);
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_OUT) {
-		if (!IPC_GET_RETVAL(answer->data)) {
-			/* Accepted, handle as_area receipt */
-			
-			irq_spinlock_lock(&answer->sender->lock, true);
-			as_t *as = answer->sender->as;
-			irq_spinlock_unlock(&answer->sender->lock, true);
-			
-			uintptr_t dst_base = (uintptr_t) -1;
-			int rc = as_area_share(as, IPC_GET_ARG1(*olddata),
-			    IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata),
-			    &dst_base, IPC_GET_ARG1(answer->data));
-			
-			if (rc == EOK)
-				rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data),
-				    &dst_base, sizeof(dst_base));
-			
-			IPC_SET_RETVAL(answer->data, rc);
-			return rc;
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_IN) {
-		if (!IPC_GET_RETVAL(answer->data)) {
-			irq_spinlock_lock(&answer->sender->lock, true);
-			as_t *as = answer->sender->as;
-			irq_spinlock_unlock(&answer->sender->lock, true);
-			
-			uintptr_t dst_base = (uintptr_t) -1;
-			int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
-			    IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data),
-			    &dst_base, IPC_GET_ARG3(answer->data));
-			IPC_SET_ARG4(answer->data, dst_base);
-			IPC_SET_RETVAL(answer->data, rc);
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_READ) {
-		ASSERT(!answer->buffer);
-		if (!IPC_GET_RETVAL(answer->data)) {
-			/* The recipient agreed to send data. */
-			uintptr_t src = IPC_GET_ARG1(answer->data);
-			uintptr_t dst = IPC_GET_ARG1(*olddata);
-			size_t max_size = IPC_GET_ARG2(*olddata);
-			size_t size = IPC_GET_ARG2(answer->data);
-			if (size && size <= max_size) {
-				/*
-				 * Copy the destination VA so that this piece of
-				 * information is not lost.
-				 */
-				IPC_SET_ARG1(answer->data, dst);
-				
-				answer->buffer = malloc(size, 0);
-				int rc = copy_from_uspace(answer->buffer,
-				    (void *) src, size);
-				if (rc) {
-					IPC_SET_RETVAL(answer->data, rc);
-					free(answer->buffer);
-					answer->buffer = NULL;
-				}
-			} else if (!size) {
-				IPC_SET_RETVAL(answer->data, EOK);
-			} else {
-				IPC_SET_RETVAL(answer->data, ELIMIT);
-			}
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_WRITE) {
-		ASSERT(answer->buffer);
-		if (!IPC_GET_RETVAL(answer->data)) {
-			/* The recipient agreed to receive data. */
-			uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data);
-			size_t size = (size_t)IPC_GET_ARG2(answer->data);
-			size_t max_size = (size_t)IPC_GET_ARG2(*olddata);
-			
-			if (size <= max_size) {
-				int rc = copy_to_uspace((void *) dst,
-				    answer->buffer, size);
-				if (rc)
-					IPC_SET_RETVAL(answer->data, rc);
-			} else {
-				IPC_SET_RETVAL(answer->data, ELIMIT);
-			}
-		}
-		free(answer->buffer);
-		answer->buffer = NULL;
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_STATE_CHANGE_AUTHORIZE) {
-		if (!IPC_GET_RETVAL(answer->data)) {
-			/* The recipient authorized the change of state. */
-			phone_t *recipient_phone;
-			task_t *other_task_s;
-			task_t *other_task_r;
-			int rc;
-
-			rc = phone_get(IPC_GET_ARG1(answer->data),
-			    &recipient_phone);
-			if (rc != EOK) {
-				IPC_SET_RETVAL(answer->data, ENOENT);
-				return ENOENT;
-			}
-
-			mutex_lock(&recipient_phone->lock);
-			if (recipient_phone->state != IPC_PHONE_CONNECTED) {
-				mutex_unlock(&recipient_phone->lock);
-				IPC_SET_RETVAL(answer->data, EINVAL);
-				return EINVAL;
-			}
-
-			other_task_r = recipient_phone->callee->task;
-			other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
-
-			/*
-			 * See if both the sender and the recipient meant the
-			 * same third party task.
-			 */
-			if (other_task_r != other_task_s) {
-				IPC_SET_RETVAL(answer->data, EINVAL);
-				rc = EINVAL;
-			} else {
-				rc = event_task_notify_5(other_task_r,
-				    EVENT_TASK_STATE_CHANGE, false,
-				    IPC_GET_ARG1(*olddata),
-				    IPC_GET_ARG2(*olddata),
-				    IPC_GET_ARG3(*olddata),
-				    LOWER32(olddata->task_id),
-				    UPPER32(olddata->task_id));
-				IPC_SET_RETVAL(answer->data, rc);
-			}
-
-			mutex_unlock(&recipient_phone->lock);
-			return rc;
-		}
-	}
-	
-	return 0;
-}
-
-static void phones_lock(phone_t *p1, phone_t *p2)
-{
-	if (p1 < p2) {
-		mutex_lock(&p1->lock);
-		mutex_lock(&p2->lock);
-	} else if (p1 > p2) {
-		mutex_lock(&p2->lock);
-		mutex_lock(&p1->lock);
-	} else
-		mutex_lock(&p1->lock);
-}
-
-static void phones_unlock(phone_t *p1, phone_t *p2)
-{
-	mutex_unlock(&p1->lock);
-	if (p1 != p2)
-		mutex_unlock(&p2->lock);
+		return rc;
+
+	return SYSIPC_OP(answer_preprocess, answer, olddata);
 }
 
@@ -424,124 +222,6 @@
 static int request_preprocess(call_t *call, phone_t *phone)
 {
-	switch (IPC_GET_IMETHOD(call->data)) {
-	case IPC_M_CONNECTION_CLONE: {
-		phone_t *cloned_phone;
-		if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK)
-			return ENOENT;
-		
-		phones_lock(cloned_phone, phone);
-		
-		if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
-		    phone->state != IPC_PHONE_CONNECTED) {
-			phones_unlock(cloned_phone, phone);
-			return EINVAL;
-		}
-		
-		/*
-		 * We can be pretty sure now that both tasks exist and we are
-		 * connected to them. As we continue to hold the phone locks,
-		 * we are effectively preventing them from finishing their
-		 * potential cleanup.
-		 *
-		 */
-		int newphid = phone_alloc(phone->callee->task);
-		if (newphid < 0) {
-			phones_unlock(cloned_phone, phone);
-			return ELIMIT;
-		}
-		
-		ipc_phone_connect(&phone->callee->task->phones[newphid],
-		    cloned_phone->callee);
-		phones_unlock(cloned_phone, phone);
-		
-		/* Set the new phone for the callee. */
-		IPC_SET_ARG1(call->data, newphid);
-		break;
-	}
-	case IPC_M_CLONE_ESTABLISH:
-		IPC_SET_ARG5(call->data, (sysarg_t) phone);
-		break;
-	case IPC_M_CONNECT_ME_TO: {
-		int newphid = phone_alloc(TASK);
-		if (newphid < 0)
-			return ELIMIT;
-		
-		/* Set arg5 for server */
-		IPC_SET_ARG5(call->data, (sysarg_t) &TASK->phones[newphid]);
-		call->flags |= IPC_CALL_CONN_ME_TO;
-		call->priv = newphid;
-		break;
-	}
-	case IPC_M_SHARE_OUT: {
-		size_t size = as_area_get_size(IPC_GET_ARG1(call->data));
-		if (!size)
-			return EPERM;
-		
-		IPC_SET_ARG2(call->data, size);
-		break;
-	}
-	case IPC_M_DATA_READ: {
-		size_t size = IPC_GET_ARG2(call->data);
-		if (size > DATA_XFER_LIMIT) {
-			int flags = IPC_GET_ARG3(call->data);
-			if (flags & IPC_XF_RESTRICT)
-				IPC_SET_ARG2(call->data, DATA_XFER_LIMIT);
-			else
-				return ELIMIT;
-		}
-		break;
-	}
-	case IPC_M_DATA_WRITE: {
-		uintptr_t src = IPC_GET_ARG1(call->data);
-		size_t size = IPC_GET_ARG2(call->data);
-		
-		if (size > DATA_XFER_LIMIT) {
-			int flags = IPC_GET_ARG3(call->data);
-			if (flags & IPC_XF_RESTRICT) {
-				size = DATA_XFER_LIMIT;
-				IPC_SET_ARG2(call->data, size);
-			} else
-				return ELIMIT;
-		}
-		
-		call->buffer = (uint8_t *) malloc(size, 0);
-		int rc = copy_from_uspace(call->buffer, (void *) src, size);
-		if (rc != 0) {
-			free(call->buffer);
-			return rc;
-		}
-		
-		break;
-	}
-	case IPC_M_STATE_CHANGE_AUTHORIZE: {
-		phone_t *sender_phone;
-		task_t *other_task_s;
-
-		if (phone_get(IPC_GET_ARG5(call->data), &sender_phone) != EOK)
-			return ENOENT;
-
-		mutex_lock(&sender_phone->lock);
-		if (sender_phone->state != IPC_PHONE_CONNECTED) {
-			mutex_unlock(&sender_phone->lock);
-			return EINVAL;
-		}
-
-		other_task_s = sender_phone->callee->task;
-
-		mutex_unlock(&sender_phone->lock);
-
-		/* Remember the third party task hash. */
-		IPC_SET_ARG5(call->data, (sysarg_t) other_task_s);
-		break;
-	}
-#ifdef CONFIG_UDEBUG
-	case IPC_M_DEBUG:
-		return udebug_request_preprocess(call, phone);
-#endif
-	default:
-		break;
-	}
-	
-	return 0;
+	call->request_method = IPC_GET_IMETHOD(call->data);
+	return SYSIPC_OP(request_preprocess, call, phone);
 }
 
@@ -561,26 +241,7 @@
 		IPC_SET_RETVAL(call->data, EFORWARD);
 	
-	if (call->flags & IPC_CALL_CONN_ME_TO) {
-		if (IPC_GET_RETVAL(call->data))
-			phone_dealloc(call->priv);
-		else
-			IPC_SET_ARG5(call->data, call->priv);
-	}
-	
-	if (call->buffer) {
-		/*
-		 * This must be an affirmative answer to IPC_M_DATA_READ
-		 * or IPC_M_DEBUG/UDEBUG_M_MEM_READ...
-		 *
-		 */
-		uintptr_t dst = IPC_GET_ARG1(call->data);
-		size_t size = IPC_GET_ARG2(call->data);
-		int rc = copy_to_uspace((void *) dst, call->buffer, size);
-		if (rc)
-			IPC_SET_RETVAL(call->data, rc);
-		free(call->buffer);
-		call->buffer = NULL;
-	}
-}
+	SYSIPC_OP(answer_process, call);
+}
+
 
 /** Do basic kernel processing of received call request.
@@ -595,23 +256,5 @@
 static int process_request(answerbox_t *box, call_t *call)
 {
-	if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME) {
-		int phoneid = phone_alloc(TASK);
-		if (phoneid < 0) {  /* Failed to allocate phone */
-			IPC_SET_RETVAL(call->data, ELIMIT);
-			ipc_answer(box, call);
-			return -1;
-		}
-		
-		IPC_SET_ARG5(call->data, phoneid);
-	}
-	
-	switch (IPC_GET_IMETHOD(call->data)) {
-	case IPC_M_DEBUG:
-		return -1;
-	default:
-		break;
-	}
-	
-	return 0;
+	return SYSIPC_OP(request_process, call, box);
 }
 
@@ -745,21 +388,27 @@
 {
 	call_t *call = get_call(callid);
+	phone_t *phone;
+	bool need_old = answer_need_old(call);
+	bool after_forward = false;
+	ipc_data_t old;
+	int rc;
+
 	if (!call)
 		return ENOENT;
-	
+
+	if (need_old)
+		old = call->data;
+	
+	if (phone_get(phoneid, &phone) != EOK) {
+		rc = ENOENT;
+		goto error;
+	}
+	
+	if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
+		rc = EPERM;
+		goto error;
+	}
+
 	call->flags |= IPC_CALL_FORWARDED;
-	
-	phone_t *phone;
-	if (phone_get(phoneid, &phone) != EOK) {
-		IPC_SET_RETVAL(call->data, EFORWARD);
-		ipc_answer(&TASK->answerbox, call);
-		return ENOENT;
-	}
-	
-	if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
-		IPC_SET_RETVAL(call->data, EFORWARD);
-		ipc_answer(&TASK->answerbox, call);
-		return EPERM;
-	}
 	
 	/*
@@ -797,5 +446,21 @@
 	}
 	
-	return ipc_forward(call, phone, &TASK->answerbox, mode);
+	rc = ipc_forward(call, phone, &TASK->answerbox, mode);
+	if (rc != EOK) {
+		after_forward = true;
+		goto error;
+	}
+
+	return EOK;
+
+error:
+	IPC_SET_RETVAL(call->data, EFORWARD);
+	(void) answer_preprocess(call, need_old ? &old : NULL);
+	if (after_forward)
+		_ipc_answer_free_call(call, false);
+	else
+		ipc_answer(&TASK->answerbox, call);
+
+	return rc;
 }
 
Index: kernel/generic/src/ipc/sysipc_ops.c
===================================================================
--- kernel/generic/src/ipc/sysipc_ops.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/src/ipc/sysipc_ops.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2012 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <abi/ipc/methods.h>
+#include <abi/errno.h>
+
+/* Forward declarations. */
+sysipc_ops_t ipc_m_connection_clone_ops;
+sysipc_ops_t ipc_m_clone_establish_ops;
+sysipc_ops_t ipc_m_connect_to_me_ops;
+sysipc_ops_t ipc_m_connect_me_to_ops;
+sysipc_ops_t ipc_m_share_out_ops;
+sysipc_ops_t ipc_m_share_in_ops;
+sysipc_ops_t ipc_m_data_write_ops;
+sysipc_ops_t ipc_m_data_read_ops;
+sysipc_ops_t ipc_m_state_change_authorize_ops;
+sysipc_ops_t ipc_m_debug_ops;
+
+static sysipc_ops_t *sysipc_ops[] = {
+	[IPC_M_CONNECTION_CLONE] = &ipc_m_connection_clone_ops,
+	[IPC_M_CLONE_ESTABLISH] = &ipc_m_clone_establish_ops,
+	[IPC_M_CONNECT_TO_ME] = &ipc_m_connect_to_me_ops,
+	[IPC_M_CONNECT_ME_TO] = &ipc_m_connect_me_to_ops,
+	[IPC_M_SHARE_OUT] = &ipc_m_share_out_ops,
+	[IPC_M_SHARE_IN] = &ipc_m_share_in_ops,
+	[IPC_M_DATA_WRITE] = &ipc_m_data_write_ops,
+	[IPC_M_DATA_READ] = &ipc_m_data_read_ops,
+	[IPC_M_STATE_CHANGE_AUTHORIZE] = &ipc_m_state_change_authorize_ops,
+	[IPC_M_DEBUG] = &ipc_m_debug_ops
+};
+
+static sysipc_ops_t null_ops = {
+	.request_preprocess = null_request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = null_answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+int null_request_preprocess(call_t *call, phone_t *phone)
+{
+	return EOK;
+}
+
+int null_request_forget(call_t *call)
+{
+	return EOK;
+}
+
+int null_request_process(call_t *call, answerbox_t *box)
+{
+	return EOK;
+}
+
+int null_answer_cleanup(call_t *call, ipc_data_t *data)
+{
+	return EOK;
+}
+
+int null_answer_preprocess(call_t *call, ipc_data_t *data)
+{
+	return EOK;
+}
+
+int null_answer_process(call_t *call)
+{
+	return EOK;
+}
+
+sysipc_ops_t *sysipc_ops_get(sysarg_t imethod)
+{
+	if (imethod < sizeof(sysipc_ops) / (sizeof(sysipc_ops_t *)))
+		return sysipc_ops[imethod] ? sysipc_ops[imethod] : &null_ops;
+
+	return &null_ops;
+}
+
+/** @}
+ */
Index: kernel/generic/src/main/kinit.c
===================================================================
--- kernel/generic/src/main/kinit.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/src/main/kinit.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -69,4 +69,5 @@
 #include <str.h>
 #include <sysinfo/stats.h>
+#include <sysinfo/sysinfo.h>
 #include <align.h>
 
@@ -189,4 +190,26 @@
 	program_t programs[CONFIG_INIT_TASKS];
 	
+	// FIXME: do not propagate arguments through sysinfo
+	// but pass them directly to the tasks
+	for (i = 0; i < init.cnt; i++) {
+		const char *arguments = init.tasks[i].arguments;
+		if (str_length(arguments) == 0)
+			continue;
+		if (str_length(init.tasks[i].name) == 0)
+			continue;
+		size_t arguments_size = str_size(arguments);
+
+		void *arguments_copy = malloc(arguments_size, 0);
+		if (arguments_copy == NULL)
+			continue;
+		memcpy(arguments_copy, arguments, arguments_size);
+
+		char item_name[CONFIG_TASK_NAME_BUFLEN + 15];
+		snprintf(item_name, CONFIG_TASK_NAME_BUFLEN + 15,
+		    "init_args.%s", init.tasks[i].name);
+
+		sysinfo_set_item_data(item_name, NULL, arguments_copy, arguments_size);
+	}
+
 	for (i = 0; i < init.cnt; i++) {
 		if (init.tasks[i].paddr % FRAME_SIZE) {
Index: kernel/generic/src/mm/as.c
===================================================================
--- kernel/generic/src/mm/as.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/src/mm/as.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -285,8 +285,9 @@
 /** Check area conflicts with other areas.
  *
- * @param as    Address space.
- * @param addr  Starting virtual address of the area being tested.
- * @param count Number of pages in the area being tested.
- * @param avoid Do not touch this area.
+ * @param as      Address space.
+ * @param addr    Starting virtual address of the area being tested.
+ * @param count   Number of pages in the area being tested.
+ * @param guarded True if the area being tested is protected by guard pages.
+ * @param avoid   Do not touch this area.
  *
  * @return True if there is no conflict, false otherwise.
@@ -294,8 +295,15 @@
  */
 NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr,
-    size_t count, as_area_t *avoid)
+    size_t count, bool guarded, as_area_t *avoid)
 {
 	ASSERT((addr % PAGE_SIZE) == 0);
 	ASSERT(mutex_locked(&as->lock));
+
+	/*
+	 * If the addition of the supposed area address and size overflows,
+	 * report conflict.
+	 */
+	if (overflows_into_positive(addr, P2SZ(count)))
+		return false;
 	
 	/*
@@ -304,5 +312,5 @@
 	if (overlaps(addr, P2SZ(count), (uintptr_t) NULL, PAGE_SIZE))
 		return false;
-	
+
 	/*
 	 * The leaf node is found in O(log n), where n is proportional to
@@ -328,6 +336,51 @@
 		if (area != avoid) {
 			mutex_lock(&area->lock);
-			
+
+			/*
+			 * If at least one of the two areas are protected
+			 * by the AS_AREA_GUARD flag then we must be sure
+			 * that they are separated by at least one unmapped
+			 * page.
+			 */
+			int const gp = (guarded || 
+			    (area->flags & AS_AREA_GUARD)) ? 1 : 0;
+			
+			/*
+			 * The area comes from the left neighbour node, which
+			 * means that there already are some areas in the leaf
+			 * node, which in turn means that adding gp is safe and
+			 * will not cause an integer overflow.
+			 */
 			if (overlaps(addr, P2SZ(count), area->base,
+			    P2SZ(area->pages + gp))) {
+				mutex_unlock(&area->lock);
+				return false;
+			}
+			
+			mutex_unlock(&area->lock);
+		}
+	}
+	
+	node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);
+	if (node) {
+		area = (as_area_t *) node->value[0];
+		
+		if (area != avoid) {
+			int gp;
+
+			mutex_lock(&area->lock);
+
+			gp = (guarded || (area->flags & AS_AREA_GUARD)) ? 1 : 0;
+			if (gp && overflows(addr, P2SZ(count))) {
+				/*
+				 * Guard page not needed if the supposed area
+				 * is adjacent to the end of the address space.
+				 * We already know that the following test is
+				 * going to fail...
+				 */
+				gp--;
+			}
+			
+			if (overlaps(addr, P2SZ(count + gp), area->base,
 			    P2SZ(area->pages))) {
 				mutex_unlock(&area->lock);
@@ -339,25 +392,10 @@
 	}
 	
-	node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);
-	if (node) {
-		area = (as_area_t *) node->value[0];
-		
-		if (area != avoid) {
-			mutex_lock(&area->lock);
-			
-			if (overlaps(addr, P2SZ(count), area->base,
-			    P2SZ(area->pages))) {
-				mutex_unlock(&area->lock);
-				return false;
-			}
-			
-			mutex_unlock(&area->lock);
-		}
-	}
-	
 	/* Second, check the leaf node. */
 	btree_key_t i;
 	for (i = 0; i < leaf->keys; i++) {
 		area = (as_area_t *) leaf->value[i];
+		int agp;
+		int gp;
 		
 		if (area == avoid)
@@ -365,7 +403,18 @@
 		
 		mutex_lock(&area->lock);
-		
-		if (overlaps(addr, P2SZ(count), area->base,
-		    P2SZ(area->pages))) {
+
+		gp = (guarded || (area->flags & AS_AREA_GUARD)) ? 1 : 0;
+		agp = gp;
+
+		/*
+		 * Sanitize the two possible unsigned integer overflows.
+		 */
+		if (gp && overflows(addr, P2SZ(count)))
+			gp--;
+		if (agp && overflows(area->base, P2SZ(area->pages)))
+			agp--;
+
+		if (overlaps(addr, P2SZ(count + gp), area->base,
+		    P2SZ(area->pages + agp))) {
 			mutex_unlock(&area->lock);
 			return false;
@@ -392,7 +441,8 @@
  * this function.
  *
- * @param as    Address space.
- * @param bound Lowest address bound.
- * @param size  Requested size of the allocation.
+ * @param as      Address space.
+ * @param bound   Lowest address bound.
+ * @param size    Requested size of the allocation.
+ * @param guarded True if the allocation must be protected by guard pages.
  *
  * @return Address of the beginning of unmapped address space area.
@@ -401,5 +451,5 @@
  */
 NO_TRACE static uintptr_t as_get_unmapped_area(as_t *as, uintptr_t bound,
-    size_t size)
+    size_t size, bool guarded)
 {
 	ASSERT(mutex_locked(&as->lock));
@@ -423,7 +473,15 @@
 	/* First check the bound address itself */
 	uintptr_t addr = ALIGN_UP(bound, PAGE_SIZE);
-	if ((addr >= bound) &&
-	    (check_area_conflicts(as, addr, pages, NULL)))
-		return addr;
+	if (addr >= bound) {
+		if (guarded) {
+			/* Leave an unmapped page between the lower
+			 * bound and the area's start address.
+			 */
+			addr += P2SZ(1);
+		}
+
+		if (check_area_conflicts(as, addr, pages, guarded, NULL))
+			return addr;
+	}
 	
 	/* Eventually check the addresses behind each area */
@@ -439,7 +497,15 @@
 			addr =
 			    ALIGN_UP(area->base + P2SZ(area->pages), PAGE_SIZE);
+
+			if (guarded || area->flags & AS_AREA_GUARD) {
+				/* We must leave an unmapped page
+				 * between the two areas.
+				 */
+				addr += P2SZ(1);
+			}
+
 			bool avail =
 			    ((addr >= bound) && (addr >= area->base) &&
-			    (check_area_conflicts(as, addr, pages, area)));
+			    (check_area_conflicts(as, addr, pages, guarded, area)));
 			
 			mutex_unlock(&area->lock);
@@ -481,5 +547,5 @@
 	if (size == 0)
 		return NULL;
-	
+
 	size_t pages = SIZE2FRAMES(size);
 	
@@ -487,9 +553,11 @@
 	if ((flags & AS_AREA_EXEC) && (flags & AS_AREA_WRITE))
 		return NULL;
+
+	bool const guarded = flags & AS_AREA_GUARD;
 	
 	mutex_lock(&as->lock);
 	
 	if (*base == (uintptr_t) -1) {
-		*base = as_get_unmapped_area(as, bound, size);
+		*base = as_get_unmapped_area(as, bound, size, guarded);
 		if (*base == (uintptr_t) -1) {
 			mutex_unlock(&as->lock);
@@ -497,6 +565,9 @@
 		}
 	}
-	
-	if (!check_area_conflicts(as, *base, pages, NULL)) {
+
+	if (overflows_into_positive(*base, size))
+		return NULL;
+
+	if (!check_area_conflicts(as, *base, pages, guarded, NULL)) {
 		mutex_unlock(&as->lock);
 		return NULL;
@@ -776,7 +847,14 @@
 		/*
 		 * Growing the area.
+		 */
+
+		if (overflows_into_positive(address, P2SZ(pages)))
+			return EINVAL;
+
+		/*
 		 * Check for overlaps with other address space areas.
 		 */
-		if (!check_area_conflicts(as, address, pages, area)) {
+		bool const guarded = area->flags & AS_AREA_GUARD;
+		if (!check_area_conflicts(as, address, pages, guarded, area)) {
 			mutex_unlock(&area->lock);
 			mutex_unlock(&as->lock);
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ kernel/generic/src/proc/task.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -161,5 +161,8 @@
 	size_t i;
 	for (i = 0; i < IPC_MAX_PHONES; i++)
-		ipc_phone_init(&task->phones[i]);
+		ipc_phone_init(&task->phones[i], task);
+
+	spinlock_initialize(&task->active_calls_lock, "active_calls_lock");
+	list_initialize(&task->active_calls);
 	
 #ifdef CONFIG_UDEBUG
@@ -203,4 +206,6 @@
 	event_task_init(task);
 	
+	task->answerbox.active = true;
+
 #ifdef CONFIG_UDEBUG
 	/* Init debugging stuff */
@@ -208,4 +213,5 @@
 	
 	/* Init kbox stuff */
+	task->kb.box.active = true;
 	task->kb.finished = false;
 #endif
@@ -213,5 +219,5 @@
 	if ((ipc_phone_0) &&
 	    (container_check(ipc_phone_0->task->container, task->container)))
-		ipc_phone_connect(&task->phones[0], ipc_phone_0);
+		(void) ipc_phone_connect(&task->phones[0], ipc_phone_0);
 	
 	btree_create(&task->futexes);
Index: tools/toolchain.sh
===================================================================
--- tools/toolchain.sh	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ tools/toolchain.sh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -43,6 +43,6 @@
 MPFR_MAIN=<<EOF
 #if MPFR_VERSION < MPFR_VERSION_NUM(2, 4, 2)
-choke me
-	#endif
+	choke me
+#endif
 EOF
 
@@ -55,6 +55,6 @@
 BINUTILS_VERSION="2.22"
 BINUTILS_RELEASE=""
-GCC_VERSION="4.7.1"
-GDB_VERSION="7.4"
+GCC_VERSION="4.7.2"
+GDB_VERSION="7.5"
 
 BASEDIR="`pwd`"
@@ -192,4 +192,5 @@
 	echo " - SED, AWK, Flex, Bison, gzip, bzip2, Bourne Shell"
 	echo " - gettext, zlib, Texinfo, libelf, libgomp"
+	echo " - terminfo"
 	echo " - GNU Multiple Precision Library (GMP)"
 	echo " - GNU Make"
@@ -274,6 +275,6 @@
 	
 	download_fetch "${BINUTILS_SOURCE}" "${BINUTILS}" "ee0f10756c84979622b992a4a61ea3f5"
-	download_fetch "${GCC_SOURCE}" "${GCC}" "933e6f15f51c031060af64a9e14149ff"
-	download_fetch "${GDB_SOURCE}" "${GDB}" "95a9a8305fed4d30a30a6dc28ff9d060"
+	download_fetch "${GCC_SOURCE}" "${GCC}" "cc308a0891e778cfda7a151ab8a6e762"
+	download_fetch "${GDB_SOURCE}" "${GDB}" "24a6779a9fe0260667710de1b082ef61"
 }
 
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -35,4 +35,5 @@
 DIRS = \
 	app/bdsh \
+	app/bithenge \
 	app/blkdump \
 	app/bnchmark \
@@ -47,4 +48,5 @@
 	app/klog \
 	app/loc \
+	app/logset \
 	app/mkfat \
 	app/mkexfat \
@@ -71,4 +73,5 @@
 	app/sysinfo \
 	app/mkbd \
+	app/date \
 	app/websrv \
 	app/vdemo \
@@ -77,4 +80,5 @@
 	srv/clipboard \
 	srv/locsrv \
+	srv/logger \
 	srv/devman \
 	srv/loader \
@@ -95,4 +99,5 @@
 	srv/bd/part/mbr_part \
 	srv/fs/exfat \
+	srv/fs/udf \
 	srv/fs/fat \
 	srv/fs/cdfs \
@@ -132,5 +137,5 @@
 	drv/nic/ne2k \
 	drv/nic/e1k \
-	drv/nic/rtl8139
+	drv/nic/rtl8139 \
 
 ifeq ($(CONFIG_PCC),y)
@@ -161,4 +166,5 @@
 		drv/bus/isa \
 		drv/char/ns8250 \
+		drv/time/cmos-rtc \
 		srv/hw/irc/apic \
 		srv/hw/irc/i8259
@@ -171,4 +177,5 @@
 		drv/bus/isa \
 		drv/char/ns8250 \
+		drv/time/cmos-rtc \
 		srv/hw/irc/apic \
 		srv/hw/irc/i8259
@@ -213,4 +220,5 @@
 	lib/usbhid \
 	lib/usbvirt \
+	lib/bithenge \
 	lib/posix
 
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/Makefile.common	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -134,4 +134,6 @@
 LIBSCSI_PREFIX = $(LIB_PREFIX)/scsi
 
+LIBBITHENGE_PREFIX = $(LIB_PREFIX)/bithenge
+
 ifeq ($(STATIC_NEEDED),y)
 	STATIC_BUILD = y
@@ -225,5 +227,5 @@
 
 ifeq ($(POSIX_COMPAT),y)
-	CFLAGS = -I$(LIBPOSIX_PREFIX)
+	CFLAGS = -I$(LIBPOSIX_PREFIX)/include/posix  -I$(LIBPOSIX_PREFIX)/include/
 	LIBS += $(LIBPOSIX_PREFIX)/libposix.a
 endif
Index: uspace/app/bdsh/Makefile
===================================================================
--- uspace/app/bdsh/Makefile	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/bdsh/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -53,4 +53,5 @@
 	cmds/modules/unmount/unmount.c \
 	cmds/modules/kcon/kcon.c \
+	cmds/modules/cmp/cmp.c \
 	cmds/builtins/batch/batch.c \
 	cmds/builtins/exit/exit.c \
Index: uspace/app/bdsh/cmds/modules/cmp/cmp.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cmp/cmp.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/bdsh/cmds/modules/cmp/cmp.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <mem.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <vfs/vfs.h>
+
+#include "cmds.h"
+#include "cmp.h"
+#include "config.h"
+#include "entry.h"
+#include "errors.h"
+#include "util.h"
+
+static const char *cmdname = "cmp";
+#define CMP_VERSION "0.0.1"
+#define CMP_BUFLEN 1024
+
+static struct option const long_options[] = {
+	{ "help", no_argument, 0, 'h' },
+	{ "version", no_argument, 0, 'v' },
+	{ 0, 0, 0, 0 }
+};
+
+/* Dispays help for cat in various levels */
+void help_cmd_cmp(unsigned int level)
+{
+	if (level == HELP_SHORT) {
+		printf("`%s' compares the contents of two files\n", cmdname);
+	} else {
+		help_cmd_cmp(HELP_SHORT);
+		printf(
+		"Usage:  %s [options] <file1> <file2>\n"
+		"Options:\n"
+		"  -h, --help       A short option summary\n"
+		"  -v, --version    Print version information and exit\n"
+		"No output is printed; the return code is 1 if the files differ.\n",
+		cmdname);
+	}
+
+	return;
+}
+
+static int cmp_files(const char *fn0, const char *fn1)
+{
+	int rc = 0;
+	const char *fn[2] = {fn0, fn1};
+	int fd[2] = {-1, -1};
+	char buffer[2][CMP_BUFLEN];
+	ssize_t offset[2];
+
+	for (int i = 0; i < 2; i++) {
+		fd[i] = open(fn[i], O_RDONLY);
+		if (fd[i] < 0) {
+			rc = errno;
+			printf("Unable to open %s\n", fn[i]);
+			goto end;
+		}
+	}
+
+	do {
+		for (int i = 0; i < 2; i++) {
+			offset[i] = 0;
+			ssize_t size;
+			do {
+				size = read(fd[i], buffer[i] + offset[i],
+				    CMP_BUFLEN - offset[i]);
+				if (size < 0) {
+					rc = errno;
+					printf("Error reading from %s\n",
+					    fn[i]);
+					goto end;
+				}
+				offset[i] += size;
+			} while (size && offset[i] < CMP_BUFLEN);
+		}
+
+		if (offset[0] != offset[1] ||
+		    bcmp(buffer[0], buffer[1], offset[0])) {
+			rc = 1;
+			goto end;
+		}
+	} while (offset[0] == CMP_BUFLEN);
+
+end:
+	if (fd[0] >= 0)
+		close(fd[0]);
+	if (fd[1] >= 0)
+		close(fd[1]);
+	return rc;
+}
+
+/* Main entry point for cmd, accepts an array of arguments */
+int cmd_cmp(char **argv)
+{
+	int rc;
+	unsigned int argc;
+	int c, opt_ind;
+	
+	argc = cli_count_args(argv);
+
+	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
+		c = getopt_long(argc, argv, "hv", long_options, &opt_ind);
+		switch (c) {
+		case 'h':
+			help_cmd_cmp(HELP_LONG);
+			return CMD_SUCCESS;
+		case 'v':
+			printf("%s\n", CMP_VERSION);
+			return CMD_SUCCESS;
+		}
+	}
+
+	if (argc - optind != 2) {
+		printf("%s - incorrect number of arguments. Try `%s --help'\n",
+			cmdname, cmdname);
+		return CMD_FAILURE;
+	}
+
+	rc = cmp_files(argv[optind], argv[optind + 1]);
+	if (rc)
+		return CMD_FAILURE;
+	else
+		return CMD_SUCCESS;
+}
Index: uspace/app/bdsh/cmds/modules/cmp/cmp.h
===================================================================
--- uspace/app/bdsh/cmds/modules/cmp/cmp.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/bdsh/cmds/modules/cmp/cmp.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,7 @@
+#ifndef CMP_H
+#define CMP_H
+
+/* Prototypes for the cmp command, excluding entry points */
+
+#endif /* CMP_H */
+
Index: uspace/app/bdsh/cmds/modules/cmp/cmp_def.h
===================================================================
--- uspace/app/bdsh/cmds/modules/cmp/cmp_def.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/bdsh/cmds/modules/cmp/cmp_def.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,7 @@
+{
+	"cmp",
+	"Compare the contents of two files",
+	&cmd_cmp,
+	&help_cmd_cmp,
+},
+
Index: uspace/app/bdsh/cmds/modules/cmp/entry.h
===================================================================
--- uspace/app/bdsh/cmds/modules/cmp/entry.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/bdsh/cmds/modules/cmp/entry.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,9 @@
+#ifndef CMP_ENTRY_H
+#define CMP_ENTRY_H
+
+/* Entry points for the cat command */
+extern int cmd_cmp(char **);
+extern void help_cmd_cmp(unsigned int);
+
+#endif /* CAT_ENTRY_H */
+
Index: uspace/app/bdsh/cmds/modules/modules.h
===================================================================
--- uspace/app/bdsh/cmds/modules/modules.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/bdsh/cmds/modules/modules.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -63,4 +63,5 @@
 #include "printf/entry.h"
 #include "echo/entry.h"
+#include "cmp/entry.h"
 
 /* Each .def function fills the module_t struct with the individual name, entry
@@ -86,4 +87,5 @@
 #include "printf/printf_def.h"
 #include "echo/echo_def.h"
+#include "cmp/cmp_def.h"
 
 	{NULL, NULL, NULL, NULL}
Index: uspace/app/bdsh/config.h
===================================================================
--- uspace/app/bdsh/config.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/bdsh/config.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -55,6 +55,3 @@
 #define PACKAGE_STRING "The brain dead shell"
 #define PACKAGE_TARNAME "bdsh"
-#define PACKAGE_VERSION "0.0.1"
-
-
-
+#define PACKAGE_VERSION "0.1.0"
Index: uspace/app/bdsh/errors.h
===================================================================
--- uspace/app/bdsh/errors.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/bdsh/errors.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -30,4 +30,6 @@
 #define ERRORS_H
 
+#include <io/verify.h>
+
 /* Various error levels */
 #define CL_EFATAL  -1
@@ -46,5 +48,6 @@
 extern volatile int cli_errno;
 
-extern void cli_error(int, const char *, ...);
+extern void cli_error(int, const char *, ...)
+    PRINTF_ATTRIBUTE(2, 3);
 
 #endif
Index: uspace/app/bithenge/Makefile
===================================================================
--- uspace/app/bithenge/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/bithenge/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2012 Sean Bartell
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBBITHENGE_PREFIX)/libbithenge.a $(LIBBLOCK_PREFIX)/libblock.a
+EXTRA_CFLAGS = -I$(LIBBITHENGE_PREFIX)/include -D__HELENOS__
+BINARY = bithenge
+
+SOURCES = \
+	test.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/bithenge/Makefile.linux
===================================================================
--- uspace/app/bithenge/Makefile.linux	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/bithenge/Makefile.linux	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2012 Sean Bartell
+# 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.
+#
+
+CFLAGS += -fexec-charset=UTF-8 -finput-charset=UTF-8 -std=gnu99 -pipe
+CFLAGS += -Wall -Wextra -Werror -Wno-clobbered -Wno-unused-parameter -Wmissing-prototypes -Werror-implicit-function-declaration -Wwrite-strings
+CFLAGS += -ftrapv
+CFLAGS += -g
+
+LIBBITHENGE_PREFIX = ../../lib/bithenge
+CFLAGS += -I$(LIBBITHENGE_PREFIX)/include
+LIBS += $(LIBBITHENGE_PREFIX)/libbithenge.a
+
+BINARY = bithenge
+
+SOURCES = \
+	test.c
+
+ifdef COVERAGE
+	CFLAGS += -fprofile-arcs -ftest-coverage
+endif
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+$(BINARY): $(OBJECTS)
+	$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
+
+clean:
+	find . -name '*.o' -follow -exec rm \{\} \;
+	rm -f $(BINARY)
Index: uspace/app/bithenge/test.c
===================================================================
--- uspace/app/bithenge/test.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/bithenge/test.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Simple program to test Bithenge.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <bithenge/blob.h>
+#include <bithenge/source.h>
+#include <bithenge/print.h>
+#include <bithenge/script.h>
+#include <bithenge/transform.h>
+#include <bithenge/tree.h>
+#include <bithenge/os.h>
+
+#ifdef __HELENOS__
+#include <str_error.h>
+#else
+#include <string.h>
+#define str_error strerror
+#endif
+
+int main(int argc, char *argv[])
+{
+	int rc;
+	if (argc < 3) {
+		fprintf(stderr, "Usage: %s <script> <source>\n", argv[0]);
+		return 1;
+	} else {
+		bithenge_scope_t *scope = NULL;
+		bithenge_transform_t *transform = NULL;
+		bithenge_node_t *node = NULL, *node2 = NULL;
+
+		rc = bithenge_scope_new(&scope, NULL);
+		if (rc != EOK) {
+			printf("Error creating scope: %s\n", str_error(rc));
+			scope = NULL;
+			goto error;
+		}
+
+		rc = bithenge_parse_script(argv[1], &transform);
+		if (rc != EOK) {
+			printf("Error parsing script: %s\n", str_error(rc));
+			transform = NULL;
+			goto error;
+		}
+
+		rc = bithenge_node_from_source(&node, argv[2]);
+		if (rc != EOK) {
+			printf("Error creating node from source: %s\n", str_error(rc));
+			node = NULL;
+			goto error;
+		}
+
+		rc = bithenge_transform_apply(transform, scope, node, &node2);
+		if (rc != EOK) {
+			const char *message = bithenge_scope_get_error(scope);
+			printf("Error applying transform: %s\n",
+			    message ? message : str_error(rc));
+			node2 = NULL;
+			goto error;
+		}
+
+		bithenge_node_dec_ref(node);
+		node = NULL;
+		bithenge_transform_dec_ref(transform);
+		transform = NULL;
+
+		rc = bithenge_print_node(BITHENGE_PRINT_PYTHON, node2);
+		if (rc != EOK) {
+			const char *message = bithenge_scope_get_error(scope);
+			printf("Error printing node: %s\n",
+			    message ? message : str_error(rc));
+			goto error;
+		}
+		bithenge_node_dec_ref(node2);
+		node2 = NULL;
+		bithenge_scope_dec_ref(scope);
+		scope = NULL;
+		printf("\n");
+
+		return 0;
+
+error:
+		bithenge_node_dec_ref(node);
+		bithenge_node_dec_ref(node2);
+		bithenge_transform_dec_ref(transform);
+		bithenge_scope_dec_ref(scope);
+		return 1;
+	}
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/date/Makefile
===================================================================
--- uspace/app/date/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/date/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2012 Maurizio Lombardi
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = date
+
+SOURCES = \
+	date.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/date/date.c
===================================================================
--- uspace/app/date/date.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/date/date.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 <stdio.h>
+#include <device/clock_dev.h>
+#include <errno.h>
+#include <loc.h>
+#include <time.h>
+#include <malloc.h>
+#include <getopt.h>
+#include <ctype.h>
+
+#define NAME   "date"
+
+static int read_date_from_arg(char *wdate, struct tm *t);
+static int read_time_from_arg(char *wdate, struct tm *t);
+static int tm_sanity_check(struct tm *t);
+static bool is_leap_year(int year);
+
+static void usage(void);
+
+static int days_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+int
+main(int argc, char **argv)
+{
+	int rc, c;
+	category_id_t cat_id;
+	size_t        svc_cnt;
+	service_id_t  *svc_ids = NULL;
+	service_id_t  svc_id;
+	char          *svc_name = NULL;
+	bool          read_only = true;
+	char          *wdate = NULL;
+	char          *wtime = NULL;
+	struct tm     t;
+	int           n_args = argc;
+
+	while ((c = getopt(argc, argv, "hd:t:")) != -1) {
+		switch (c) {
+		case 'h':
+			usage();
+			return 0;
+		case 'd':
+			if (wdate) {
+				usage();
+				return 1;
+			}
+			wdate = (char *)optarg;
+			read_only = false;
+			n_args -= 2;
+			break;
+		case 't':
+			if (wtime) {
+				usage();
+				return 1;
+			}
+			wtime = (char *)optarg;
+			read_only = false;
+			n_args -= 2;
+			break;
+		case '?':
+			usage();
+			return 1;
+		}
+	}
+
+	if (n_args != 1) {
+		printf(NAME ": Unrecognized parameter\n");
+		usage();
+		return 1;
+	}
+
+	/* Get the id of the clock category */
+	rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		printf(NAME ": Cannot get clock category id\n");
+		goto exit;
+	}
+
+	/* Get the list of available services in the clock category */
+	rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
+	if (rc != EOK) {
+		printf(NAME ": Cannot get the list of services in the clock "
+		    "category\n");
+		goto exit;
+	}
+
+	/* Check if there are available services in the clock category */
+	if (svc_cnt == 0) {
+		printf(NAME ": No available service found in "
+		    "the clock category\n");
+		goto exit;
+	}
+
+	/* Get the name of the clock service */
+	rc = loc_service_get_name(svc_ids[0], &svc_name);
+	if (rc != EOK) {
+		printf(NAME ": Cannot get the name of the service\n");
+		goto exit;
+	}
+
+	/* Get the service id for the device */
+	rc = loc_service_get_id(svc_name, &svc_id, 0);
+	if (rc != EOK) {
+		printf(NAME ": Cannot get the service id for device %s",
+		    svc_name);
+		goto exit;
+	}
+
+	/* Connect to the device */
+	async_sess_t *sess = loc_service_connect(EXCHANGE_SERIALIZE,
+	    svc_id, 0);
+	if (!sess) {
+		printf(NAME ": Cannot connect to the device\n");
+		goto exit;
+	}
+
+	/* Read the current date/time */
+	rc = clock_dev_time_get(sess, &t);
+	if (rc != EOK) {
+		printf(NAME ": Cannot read the current time\n");
+		goto exit;
+	}
+
+	if (read_only) {
+		/* Print the current time and exit */
+		printf("%02d/%02d/%d ", t.tm_mday,
+		    t.tm_mon + 1, 1900 + t.tm_year);
+		printf("%02d:%02d:%02d\n", t.tm_hour, t.tm_min, t.tm_sec);
+	} else {
+		if (wdate) {
+			rc = read_date_from_arg(wdate, &t);
+			if (rc != EOK) {
+				printf(NAME ": error, date format not "
+				    "recognized\n");
+				usage();
+				goto exit;
+			}
+		}
+		if (wtime) {
+			rc = read_time_from_arg(wtime, &t);
+			if (rc != EOK) {
+				printf(NAME ": error, time format not "
+				    "recognized\n");
+				usage();
+				goto exit;
+			}
+		}
+
+		rc = tm_sanity_check(&t);
+		if (rc != EOK) {
+			printf(NAME ": error, invalid date/time\n");
+			goto exit;
+		}
+
+		rc = clock_dev_time_set(sess, &t);
+		if (rc != EOK) {
+			printf(NAME ": error, Unable to set date/time\n");
+			goto exit;
+		}
+	}
+
+exit:
+	free(svc_name);
+	free(svc_ids);
+	return rc;
+}
+
+/** Read the day, month and year from a string
+ *  with the following format: DD/MM/YYYY
+ */
+static int
+read_date_from_arg(char *wdate, struct tm *t)
+{
+	int rc;
+	uint32_t tmp;
+
+	if (str_size(wdate) != 10) /* str_size("DD/MM/YYYY") == 10 */
+		return EINVAL;
+
+	if (wdate[2] != '/' ||
+	    wdate[5] != '/') {
+		return EINVAL;
+	}
+
+	rc = str_uint32_t(&wdate[0], NULL, 10, false, &tmp);
+	if (rc != EOK)
+		return rc;
+
+	t->tm_mday = tmp;
+
+	rc = str_uint32_t(&wdate[3], NULL, 10, false, &tmp);
+	if (rc != EOK)
+		return rc;
+
+	t->tm_mon = tmp - 1;
+
+	rc = str_uint32_t(&wdate[6], NULL, 10, false, &tmp);
+	t->tm_year = tmp - 1900;
+
+	return rc;
+}
+
+/** Read the hours, minutes and seconds from a string
+ *  with the following format: HH:MM:SS or HH:MM
+ */
+static int
+read_time_from_arg(char *wtime, struct tm *t)
+{
+	int rc;
+	size_t len = str_size(wtime);
+	bool sec_present = len == 8;
+	uint32_t tmp;
+
+	/* str_size("HH:MM") == 5 */
+	/* str_size("HH:MM:SS") == 8 */
+	if (len != 8 && len != 5)
+		return EINVAL;
+
+	if (sec_present && wtime[5] != ':')
+		return EINVAL;
+
+	if (wtime[2] != ':')
+		return EINVAL;
+
+	rc = str_uint32_t(&wtime[0], NULL, 10, false, &tmp);
+	if (rc != EOK)
+		return rc;
+
+	t->tm_hour = tmp;
+
+	rc = str_uint32_t(&wtime[3], NULL, 10, false, &tmp);
+	if (rc != EOK)
+		return rc;
+
+	t->tm_min = tmp;
+
+	if (sec_present) {
+		rc = str_uint32_t(&wtime[6], NULL, 10, false, &tmp);
+		t->tm_sec = tmp;
+	} else
+		t->tm_sec = 0;
+
+	return rc;
+}
+
+/** Check if the tm structure contains valid values
+ *
+ * @param t     The tm structure to check
+ *
+ * @return      EOK on success or EINVAL
+ */
+static int
+tm_sanity_check(struct tm *t)
+{
+	int ndays;
+
+	if (t->tm_sec < 0 || t->tm_sec > 59)
+		return EINVAL;
+	else if (t->tm_min < 0 || t->tm_min > 59)
+		return EINVAL;
+	else if (t->tm_hour < 0 || t->tm_hour > 23)
+		return EINVAL;
+	else if (t->tm_mday < 1 || t->tm_mday > 31)
+		return EINVAL;
+	else if (t->tm_mon < 0 || t->tm_mon > 11)
+		return EINVAL;
+	else if (t->tm_year < 0 || t->tm_year > 199)
+		return EINVAL;
+
+	if (t->tm_mon == 1/* FEB */ && is_leap_year(t->tm_year))
+		ndays = 29;
+	else
+		ndays = days_month[t->tm_mon];
+
+	if (t->tm_mday > ndays)
+		return EINVAL;
+
+	return EOK;
+}
+
+/** Check if a year is a leap year
+ *
+ * @param year   The year to check
+ *
+ * @return       true if it is a leap year, false otherwise
+ */
+static bool
+is_leap_year(int year)
+{
+	bool r = false;
+
+	if (year % 4 == 0) {
+		if (year % 100 == 0)
+			r = year % 400 == 0;
+		else
+			r = true;
+	}
+
+	return r;
+}
+
+static void
+usage(void)
+{
+	printf("Usage: date [-d DD/MM/YYYY] [-t HH:MM[:SS]]\n");
+	printf("       -d   Change the current date\n");
+	printf("       -t   Change the current time\n");
+	printf("       -h   Display this information\n");
+}
+
Index: uspace/app/devctl/devctl.c
===================================================================
--- uspace/app/devctl/devctl.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/devctl/devctl.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -151,5 +151,6 @@
 	rc = devman_fun_offline(funh);
 	if (rc != EOK) {
-		printf(NAME ": Failed to offline function '%s'.\n", path);
+		printf(NAME ": Failed to offline function '%s' (%s)\n", path,
+		    str_error(rc));
 		return rc;
 	}
Index: uspace/app/edit/edit.c
===================================================================
--- uspace/app/edit/edit.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/edit/edit.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -111,5 +111,4 @@
 #define BUF_SIZE 64
 #define TAB_WIDTH 8
-#define ED_INFTY 65536
 
 /** Maximum filename length that can be entered. */
@@ -507,4 +506,5 @@
 static void key_handle_movement(unsigned int key, bool select)
 {
+	spt_t pt;
 	switch (key) {
 	case KC_LEFT:
@@ -521,8 +521,12 @@
 		break;
 	case KC_HOME:
-		caret_move_relative(0, -ED_INFTY, dir_after, select);
+		tag_get_pt(&pane.caret_pos, &pt);
+		pt_get_sol(&pt, &pt);
+		caret_move(pt, select, true);
 		break;
 	case KC_END:
-		caret_move_relative(0, +ED_INFTY, dir_before, select);
+		tag_get_pt(&pane.caret_pos, &pt);
+		pt_get_eol(&pt, &pt);
+		caret_move(pt, select, true);
 		break;
 	case KC_PAGE_UP:
Index: uspace/app/logset/Makefile
===================================================================
--- uspace/app/logset/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/logset/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2012 Vojtech Horky
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = logset
+
+SOURCES = \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/logset/main.c
===================================================================
--- uspace/app/logset/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/logset/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 logset
+ * @{
+ */
+/** @file Change logger behavior.
+ */
+#include <stdio.h>
+#include <async.h>
+#include <errno.h>
+#include <str_error.h>
+#include <io/logctl.h>
+
+static log_level_t parse_log_level_or_die(const char *log_level)
+{
+	log_level_t result;
+	int rc = log_level_from_str(log_level, &result);
+	if (rc != EOK) {
+		fprintf(stderr, "Unrecognised log level '%s': %s.\n",
+		    log_level, str_error(rc));
+		exit(2);
+	}
+	return result;
+}
+
+static void usage(const char *progname)
+{
+	fprintf(stderr, "Usage:\n");
+	fprintf(stderr, "  %s <default-logging-level>\n", progname);
+	fprintf(stderr, "  %s <log-name> <logging-level>\n", progname);
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc == 2) {
+		log_level_t new_default_level = parse_log_level_or_die(argv[1]);
+		int rc = logctl_set_default_level(new_default_level);
+
+		if (rc != EOK) {
+			fprintf(stderr, "Failed to change default logging level: %s.\n",
+			    str_error(rc));
+			return 2;
+		}
+	} else if (argc == 3) {
+		log_level_t new_level = parse_log_level_or_die(argv[2]);
+		const char *logname = argv[1];
+		int rc = logctl_set_log_level(logname, new_level);
+
+		if (rc != EOK) {
+			fprintf(stderr, "Failed to change logging level: %s.\n",
+			    str_error(rc));
+			return 2;
+		}
+	} else {
+		usage(argv[0]);
+		return 1;
+	}
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/msim/arch_helenos/input.c
===================================================================
--- uspace/app/msim/arch_helenos/input.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/msim/arch_helenos/input.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -32,4 +32,7 @@
 /** @file HelenOS specific functions for MSIM simulator.
  */
+
+/* Because of asprintf. */
+#define _GNU_SOURCE
 #include "../../io/input.h"
 #include "../../io/output.h"
@@ -38,4 +41,5 @@
 #include <tinput.h>
 #include <errno.h>
+#include <stdlib.h>
 
 static tinput_t *input_prompt;
Index: uspace/app/msim/arch_helenos/misc.c
===================================================================
--- uspace/app/msim/arch_helenos/misc.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/msim/arch_helenos/misc.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -44,4 +44,5 @@
 #include <ctype.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 /* Define when the dprinter device shall try to filter
Index: uspace/app/tester/Makefile
===================================================================
--- uspace/app/tester/Makefile	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/tester/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -29,6 +29,6 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBEXT2_PREFIX)/libext2.a $(LIBBLOCK_PREFIX)/libblock.a
-EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBEXT2_PREFIX)
+LIBS = $(LIBEXT2_PREFIX)/libext2.a $(LIBBLOCK_PREFIX)/libblock.a $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBEXT2_PREFIX) -I$(LIBSOFTFLOAT_PREFIX)
 BINARY = tester
 
@@ -42,10 +42,15 @@
 	print/print4.c \
 	print/print5.c \
+	print/print6.c \
 	console/console1.c \
 	stdio/stdio1.c \
 	stdio/stdio2.c \
+	stdio/logger1.c \
+	stdio/logger2.c \
 	fault/fault1.c \
 	fault/fault2.c \
 	fault/fault3.c \
+	float/float1.c \
+	float/softfloat1.c \
 	vfs/vfs1.c \
 	ipc/ping_pong.c \
@@ -59,5 +64,5 @@
 	hw/misc/virtchar1.c \
 	hw/serial/serial1.c \
-	libext2/libext2_1.c
+	ext2/ext2_1.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/tester/ext2/ext2_1.c
===================================================================
--- uspace/app/tester/ext2/ext2_1.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/tester/ext2/ext2_1.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 <stdio.h>
+#include <unistd.h>
+#include "../tester.h"
+#include "../util.h"
+#include <libext2.h>
+#include <malloc.h>
+
+static ext2_superblock_t *fake_superblock1()
+{
+	uint8_t *buf;
+	int i;
+	
+	buf = malloc(EXT2_SUPERBLOCK_SIZE);
+	if (buf == NULL) {
+		return NULL;
+	}
+	
+	for (i = 0; i < EXT2_SUPERBLOCK_SIZE; i++) {
+		buf[i] = i % 256;
+	}
+	
+	return (ext2_superblock_t *) buf;
+}
+
+const char *test_ext2_1(void)
+{
+	ext2_superblock_t *fake1;
+	
+	TPRINTF("Testing ext2 superblock getters...\n");
+	TPRINTF("Simple test for correct position and byte order\n");
+	
+	fake1 = fake_superblock1();
+	if (fake1 == NULL) {
+		return "Failed allocating memory for test superblock 1";
+	}
+	
+	ASSERT_EQ_32(0x03020100, ext2_superblock_get_total_inode_count(fake1),
+	    "Failed getting total inode count");
+	ASSERT_EQ_32(0x07060504, ext2_superblock_get_total_block_count(fake1),
+	    "Failed getting total block count");
+	ASSERT_EQ_32(0x0B0A0908, ext2_superblock_get_reserved_block_count(fake1),
+	    "Failed getting reserved block count");
+	ASSERT_EQ_32(0x0F0E0D0C, ext2_superblock_get_free_block_count(fake1),
+	    "Failed getting free block count");
+	ASSERT_EQ_32(0x13121110, ext2_superblock_get_free_inode_count(fake1),
+	    "Failed getting free inode count");
+	ASSERT_EQ_32(0x17161514, ext2_superblock_get_first_block(fake1),
+	    "Failed getting first block number");
+	ASSERT_EQ_32(0x1B1A1918, ext2_superblock_get_block_size_log2(fake1),
+	    "Failed getting log block size");
+	ASSERT_EQ_32(0x1F1E1D1C, ext2_superblock_get_fragment_size_log2(fake1),
+	    "Failed getting log fragment size");
+	ASSERT_EQ_32(0x23222120, ext2_superblock_get_blocks_per_group(fake1),
+	    "Failed getting blocks per group");
+	ASSERT_EQ_32(0x27262524, ext2_superblock_get_fragments_per_group(fake1),
+	    "Failed getting fragments per group");
+	ASSERT_EQ_32(0x2B2A2928, ext2_superblock_get_inodes_per_group(fake1),
+	    "Failed getting inodes per group");
+	ASSERT_EQ_16(0x3938, ext2_superblock_get_magic(fake1),
+	    "Failed getting magic number");
+	ASSERT_EQ_16(0x3B3A, ext2_superblock_get_state(fake1),
+	    "Failed getting state");
+	ASSERT_EQ_16(0x3F3E, ext2_superblock_get_rev_minor(fake1),
+	    "Failed getting minor revision number");
+	ASSERT_EQ_32(0x4B4A4948, ext2_superblock_get_os(fake1),
+	    "Failed getting OS");
+	ASSERT_EQ_32(0x4F4E4D4C, ext2_superblock_get_rev_major(fake1),
+	    "Failed getting major revision number");
+	ASSERT_EQ_32(0x57565554, ext2_superblock_get_first_inode(fake1),
+	    "Failed getting first inode number");
+	ASSERT_EQ_16(0x5958, ext2_superblock_get_inode_size(fake1),
+	    "Failed getting size");
+	ASSERT_EQ_8(0x68, fake1->uuid[0], "UUID position is incorrect");
+	ASSERT_EQ_8(0x78, fake1->volume_name[0],
+	    "Volume name position is incorrect");
+	
+	return NULL;
+}
Index: uspace/app/tester/ext2/ext2_1.def
===================================================================
--- uspace/app/tester/ext2/ext2_1.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/tester/ext2/ext2_1.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,6 @@
+{
+	"ext2_1",
+	"Superblock getters test",
+	&test_ext2_1,
+	true
+},
Index: uspace/app/tester/float/float1.c
===================================================================
--- uspace/app/tester/float/float1.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/tester/float/float1.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2005 Jakub Vana
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <atomic.h>
+#include <thread.h>
+#include <inttypes.h>
+#include "../tester.h"
+
+#define THREADS   150
+#define ATTEMPTS  100
+
+#define E_10E8     UINT32_C(271828182)
+#define PRECISION  100000000
+
+static atomic_t threads_finished;
+static atomic_t threads_fault;
+
+static void e(void *data)
+{
+	for (unsigned int i = 0; i < ATTEMPTS; i++) {
+		double le = -1;
+		double e = 0;
+		double f = 1;
+		
+		for (double d = 1; e != le; d *= f, f += 1) {
+			le = e;
+			e = e + 1 / d;
+		}
+		
+		if ((uint32_t) (e * PRECISION) != E_10E8) {
+			atomic_inc(&threads_fault);
+			break;
+		}
+	}
+	
+	atomic_inc(&threads_finished);
+}
+
+const char *test_float1(void)
+{
+	atomic_count_t total = 0;
+	
+	atomic_set(&threads_finished, 0);
+	atomic_set(&threads_fault, 0);
+	
+	TPRINTF("Creating threads");
+	for (unsigned int i = 0; i < THREADS; i++) {
+		if (thread_create(e, NULL, "e", NULL) < 0) {
+			TPRINTF("\nCould not create thread %u\n", i);
+			break;
+		}
+		
+		TPRINTF(".");
+		total++;
+	}
+	
+	TPRINTF("\n");
+	
+	while (atomic_get(&threads_finished) < total) {
+		TPRINTF("Threads left: %" PRIua "\n",
+		    total - atomic_get(&threads_finished));
+		sleep(1);
+	}
+	
+	if (atomic_get(&threads_fault) == 0)
+		return NULL;
+	
+	return "Test failed";
+}
Index: uspace/app/tester/float/float1.def
===================================================================
--- uspace/app/tester/float/float1.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/tester/float/float1.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,6 @@
+{
+	"float1",
+	"Floating point computation",
+	&test_float1,
+	true
+},
Index: uspace/app/tester/float/softfloat1.c
===================================================================
--- uspace/app/tester/float/softfloat1.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/tester/float/softfloat1.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2012 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 <stdio.h>
+#include <stdlib.h>
+#include <sftypes.h>
+#include <add.h>
+#include <sub.h>
+#include <mul.h>
+#include <div.h>
+#include <comparison.h>
+#include <bool.h>
+#include "../tester.h"
+
+#define OPERANDS  6 
+#define PRECISION  10000
+
+#define PRIdCMPTYPE  PRId32
+
+typedef int32_t cmptype_t;
+typedef void (* float_op_t)(float, float, float *, float_t *);
+typedef void (* double_op_t)(double, double, double *, double_t *);
+typedef void (* double_cmp_op_t)(double, double, cmptype_t *, cmptype_t *);
+typedef void (* template_t)(void *, unsigned, unsigned, cmptype_t *,
+    cmptype_t *);
+
+static float fop_a[OPERANDS] =
+	{3.5, -2.1, 100.0, 50.0, -1024.0, 0.0};
+
+static float fop_b[OPERANDS] =
+	{-2.1, 100.0, 50.0, -1024.0, 3.5, 0.0};
+
+static double dop_a[OPERANDS] =
+	{3.5, -2.1, 100.0, 50.0, -1024.0, 0.0};
+
+static double dop_b[OPERANDS] =
+	{-2.1, 100.0, 50.0, -1024.0, 3.5, 0.0};
+
+static cmptype_t cmpabs(cmptype_t a)
+{
+	if (a >= 0)
+		return a;
+	
+	return -a;
+}
+
+static int dcmp(double a, double b)
+{
+	if (a < b)
+		return -1;
+	else if (a > b)
+		return 1;
+
+	return 0;
+}
+
+static void
+float_template(void *f, unsigned i, unsigned j, cmptype_t *pic,
+    cmptype_t *pisc)
+{
+	float c;
+	float_t sc;
+
+	float_op_t op = (float_op_t) f;
+	
+	op(fop_a[i], fop_b[j], &c, &sc);
+
+	*pic = (cmptype_t) (c * PRECISION);
+	*pisc = (cmptype_t) (sc.val * PRECISION);
+}
+
+static void
+double_template(void *f, unsigned i, unsigned j, cmptype_t *pic,
+    cmptype_t *pisc)
+{
+	double c;
+	double_t sc;
+
+	double_op_t op = (double_op_t) f;
+	
+	op(dop_a[i], dop_b[j], &c, &sc);
+
+	*pic = (cmptype_t) (c * PRECISION);
+	*pisc = (cmptype_t) (sc.val * PRECISION);
+}
+
+static void
+double_compare_template(void *f, unsigned i, unsigned j, cmptype_t *pis,
+    cmptype_t *piss)
+{
+	double_cmp_op_t op = (double_cmp_op_t) f;
+	
+	op(dop_a[i], dop_b[j], pis, piss);
+}
+
+static bool test_template(template_t template, void *f)
+{
+	bool correct = true;
+	
+	for (unsigned int i = 0; i < OPERANDS; i++) {
+		for (unsigned int j = 0; j < OPERANDS; j++) {			
+			cmptype_t ic;
+			cmptype_t isc;
+
+			template(f, i, j, &ic, &isc);	
+			cmptype_t diff = cmpabs(ic - isc);
+			
+			if (diff != 0) {
+				TPRINTF("i=%u, j=%u diff=%" PRIdCMPTYPE "\n",
+				    i, j, diff);
+				correct = false;
+			}
+		}
+	}
+	
+	return correct;
+}
+
+static void float_add_operator(float a, float b, float *pc, float_t *psc)
+{
+	*pc = a + b;
+	
+	float_t sa;
+	float_t sb;
+	
+	sa.val = a;
+	sb.val = b;
+	if (sa.data.parts.sign == sb.data.parts.sign)
+		psc->data = add_float(sa.data, sb.data);
+	else if (sa.data.parts.sign) {
+		sa.data.parts.sign = 0;
+		psc->data = sub_float(sb.data, sa.data);
+	} else {
+		sb.data.parts.sign = 0;
+		psc->data = sub_float(sa.data, sb.data);
+	}
+}
+
+static void float_mul_operator(float a, float b, float *pc, float_t *psc)
+{
+	*pc = a * b;
+	
+	float_t sa;
+	float_t sb;
+	
+	sa.val = a;
+	sb.val = b;
+	psc->data = mul_float(sa.data, sb.data);
+}
+
+static void float_div_operator(float a, float b, float *pc, float_t *psc)
+{
+	if ((cmptype_t) b == 0) {
+		*pc = 0.0;
+		psc->val = 0.0;
+		return;
+	}
+
+	*pc = a / b;
+	
+	float_t sa;
+	float_t sb;
+	
+	sa.val = a;
+	sb.val = b;
+	psc->data = div_float(sa.data, sb.data);
+}
+
+static void double_add_operator(double a, double b, double *pc, double_t *psc)
+{
+	*pc = a + b;
+	
+	double_t sa;
+	double_t sb;
+	
+	sa.val = a;
+	sb.val = b;
+	if (sa.data.parts.sign == sb.data.parts.sign)
+		psc->data = add_double(sa.data, sb.data);
+	else if (sa.data.parts.sign) {
+		sa.data.parts.sign = 0;
+		psc->data = sub_double(sb.data, sa.data);
+	} else {
+		sb.data.parts.sign = 0;
+		psc->data = sub_double(sa.data, sb.data);
+	}
+}
+
+static void double_mul_operator(double a, double b, double *pc, double_t *psc)
+{
+	*pc = a * b;
+	
+	double_t sa;
+	double_t sb;
+	
+	sa.val = a;
+	sb.val = b;
+	psc->data = mul_double(sa.data, sb.data);
+}
+
+static void double_div_operator(double a, double b, double *pc, double_t *psc)
+{
+	if ((cmptype_t) b == 0) {
+		*pc = 0.0;
+		psc->val = 0.0;
+		return;
+	}
+
+	*pc = a / b;
+	
+	double_t sa;
+	double_t sb;
+	
+	sa.val = a;
+	sb.val = b;
+	psc->data = div_double(sa.data, sb.data);
+}
+
+static void
+double_cmp_operator(double a, double b, cmptype_t *pis, cmptype_t *piss)
+{
+	*pis = dcmp(a, b);
+
+	double_t sa;
+	double_t sb;
+
+	sa.val = a;
+	sb.val = b;
+
+	if (is_double_lt(sa.data, sb.data))
+		*piss = -1;
+	else if (is_double_gt(sa.data, sb.data))
+		*piss = 1;
+	else if (is_double_eq(sa.data, sb.data))
+		*piss = 0;
+	else
+		*piss = 42;
+}
+
+const char *test_softfloat1(void)
+{
+	const char *err = NULL;
+
+	if (!test_template(float_template, float_add_operator)) {
+		err = "Float addition failed";
+		TPRINTF("%s\n", err);
+	}
+	if (!test_template(float_template, float_mul_operator)) {
+		err = "Float multiplication failed";
+		TPRINTF("%s\n", err);
+	}
+	if (!test_template(float_template, float_div_operator)) {
+		err = "Float division failed";
+		TPRINTF("%s\n", err);
+	}
+	if (!test_template(double_template, double_add_operator)) {
+		err = "Double addition failed";
+		TPRINTF("%s\n", err);
+	}
+	if (!test_template(double_template, double_mul_operator)) {
+		err = "Double multiplication failed";
+		TPRINTF("%s\n", err);
+	}
+	if (!test_template(double_template, double_div_operator)) {
+		err = "Double division failed";
+		TPRINTF("%s\n", err);
+	}
+	if (!test_template(double_compare_template, double_cmp_operator)) {
+		err = "Double comparison failed";
+		TPRINTF("%s\n", err);
+	}
+	
+	return err;
+}
+
Index: uspace/app/tester/float/softfloat1.def
===================================================================
--- uspace/app/tester/float/softfloat1.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/tester/float/softfloat1.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,6 @@
+{
+	"softfloat1",
+	"Software floating point computation",
+	&test_softfloat1,
+	true
+},
Index: pace/app/tester/libext2/libext2_1.c
===================================================================
--- uspace/app/tester/libext2/libext2_1.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,106 +1,0 @@
-/*
- * Copyright (c) 2011 Martin Sucha
- * 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 <stdio.h>
-#include <unistd.h>
-#include "../tester.h"
-#include "../util.h"
-#include <libext2.h>
-#include <malloc.h>
-
-static ext2_superblock_t *fake_superblock1()
-{
-	uint8_t *buf;
-	int i;
-	
-	buf = malloc(EXT2_SUPERBLOCK_SIZE);
-	if (buf == NULL) {
-		return NULL;
-	}
-	
-	for (i = 0; i < EXT2_SUPERBLOCK_SIZE; i++) {
-		buf[i] = i % 256;
-	}
-	
-	return (ext2_superblock_t *) buf;
-}
-
-const char *test_libext2_1(void)
-{
-	ext2_superblock_t *fake1;
-	
-	TPRINTF("Testing libext2 superblock getters...\n");
-	TPRINTF("Simple test for correct position and byte order\n");
-	
-	fake1 = fake_superblock1();
-	if (fake1 == NULL) {
-		return "Failed allocating memory for test superblock 1";
-	}
-	
-	ASSERT_EQ_32(0x03020100, ext2_superblock_get_total_inode_count(fake1),
-	    "Failed getting total inode count");
-	ASSERT_EQ_32(0x07060504, ext2_superblock_get_total_block_count(fake1),
-	    "Failed getting total block count");
-	ASSERT_EQ_32(0x0B0A0908, ext2_superblock_get_reserved_block_count(fake1),
-	    "Failed getting reserved block count");
-	ASSERT_EQ_32(0x0F0E0D0C, ext2_superblock_get_free_block_count(fake1),
-	    "Failed getting free block count");
-	ASSERT_EQ_32(0x13121110, ext2_superblock_get_free_inode_count(fake1),
-	    "Failed getting free inode count");
-	ASSERT_EQ_32(0x17161514, ext2_superblock_get_first_block(fake1),
-	    "Failed getting first block number");
-	ASSERT_EQ_32(0x1B1A1918, ext2_superblock_get_block_size_log2(fake1),
-	    "Failed getting log block size");
-	ASSERT_EQ_32(0x1F1E1D1C, ext2_superblock_get_fragment_size_log2(fake1),
-	    "Failed getting log fragment size");
-	ASSERT_EQ_32(0x23222120, ext2_superblock_get_blocks_per_group(fake1),
-	    "Failed getting blocks per group");
-	ASSERT_EQ_32(0x27262524, ext2_superblock_get_fragments_per_group(fake1),
-	    "Failed getting fragments per group");
-	ASSERT_EQ_32(0x2B2A2928, ext2_superblock_get_inodes_per_group(fake1),
-	    "Failed getting inodes per group");
-	ASSERT_EQ_16(0x3938, ext2_superblock_get_magic(fake1),
-	    "Failed getting magic number");
-	ASSERT_EQ_16(0x3B3A, ext2_superblock_get_state(fake1),
-	    "Failed getting state");
-	ASSERT_EQ_16(0x3F3E, ext2_superblock_get_rev_minor(fake1),
-	    "Failed getting minor revision number");
-	ASSERT_EQ_32(0x4B4A4948, ext2_superblock_get_os(fake1),
-	    "Failed getting OS");
-	ASSERT_EQ_32(0x4F4E4D4C, ext2_superblock_get_rev_major(fake1),
-	    "Failed getting major revision number");
-	ASSERT_EQ_32(0x57565554, ext2_superblock_get_first_inode(fake1),
-	    "Failed getting first inode number");
-	ASSERT_EQ_16(0x5958, ext2_superblock_get_inode_size(fake1),
-	    "Failed getting size");
-	ASSERT_EQ_8(0x68, fake1->uuid[0], "UUID position is incorrect");
-	ASSERT_EQ_8(0x78, fake1->volume_name[0],
-	    "Volume name position is incorrect");
-	
-	return NULL;
-}
Index: pace/app/tester/libext2/libext2_1.def
===================================================================
--- uspace/app/tester/libext2/libext2_1.def	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,6 +1,0 @@
-{
-	"libext2_1",
-	"Superblock getters test",
-	&test_libext2_1,
-	true
-},
Index: uspace/app/tester/print/print5.def
===================================================================
--- uspace/app/tester/print/print5.def	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/tester/print/print5.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -1,6 +1,6 @@
 {
-	"print1",
-	"String printf test",
-	&test_print1,
+	"print5",
+	"Char printf test",
+	&test_print5,
 	true
 },
Index: uspace/app/tester/print/print6.c
===================================================================
--- uspace/app/tester/print/print6.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/tester/print/print6.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * 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 <stdio.h>
+#include <unistd.h>
+#include "../tester.h"
+
+#include <str.h>
+
+const char *test_print6(void)
+{
+	struct {
+		double val;
+		const char *fmt;
+		const char *exp_str;
+		const char *warn_str;
+	} pat[] = {
+		/* 
+		 * Generic 
+		 */
+		{ 2.0,         "%g",       "2", 0 },
+		{ 0,           "%g",       "0", 0 },
+		{ 0.1,         "%g",     "0.1", 0 },
+		{ 9e59,        "%g",   "9e+59", 0 },
+		{ -9e-59,      "%g",  "-9e-59", 0 },
+		{ 1e307,       "%g",  "1e+307", 0 },   
+		{ 0.09999999999999999, "%g",  "9.999999999999999e-02", 0 },   
+		{ 0.099999999999999999, "%g",  "0.1", 0 },   
+
+		/*
+		 * gcc and msvc convert "3.4567e-317" to different binary
+		 * doubles.
+		 */
+		{ 3.4567e-317, "%g",  "3.4567e-317", "3.456998e-317" },   
+		{ 3.4567e-318, "%g",  "3.4567e-318", 0 },   
+		{ 123456789012345.0, "%g",  "123456789012345", 0 },   
+		{ -123456789012345.0, "%g",  "-123456789012345", 0 },   
+
+		/* Special */
+		{ 1e300 * 1e300, "%g",  "inf", 0 },   
+		{ -1.0 /(1e300 * 1e300), "%g",  "-0", 0 },   
+
+		{ 1234567.8901, "%g",  "1234567.8901", 0 },   
+		{ 1234567.80012, "%g",  "1234567.80012", 0 },   
+		{ 112e-32, "%g",  "1.12e-30", 0 },   
+		{ 10.0e45, "%g",  "1e+46", 0 },   
+
+		/* rounding w/ trailing zero removal */
+		{ 0.01, "%10.6g",      "      0.01", 0 },   
+		{ 9.495, "%10.2g",     "       9.5", 0 },   
+		{ 9.495e30, "%10.2g",  "   9.5e+30", 0 },   
+		{ 9.495e30, "%10g",  " 9.495e+30", 0 },   
+		{ 9.495e30, "%10.6g",  " 9.495e+30", 0 },   
+
+		/*
+		 * Scientific 
+		 */
+		{ 1e05, "%e",  "1.000000e+05", 0 },   
+
+		/* full padding */
+
+		/* __PRINTF_FLAG_SHOWPLUS | __PRINTF_FLAG_ZEROPADDED */
+		{ 1e-1, "%+010.3e",  "+1.000e-01", 0 },
+		{ 1e-1, "%+10.3e",  "+1.000e-01", 0 },   
+		/* __PRINTF_FLAG_SHOWPLUS | __PRINTF_FLAG_LEFTALIGNED */
+		{ 1e-1, "%+-10.3e",  "+1.000e-01", 0 },
+
+		/* padding */
+
+		/* __PRINTF_FLAG_SHOWPLUS | __PRINTF_FLAG_ZEROPADDED */
+		{ 1e-1, "%+010.2e",  "+01.00e-01", 0 },
+		{ 1e-1, "%+10.2e",  " +1.00e-01", 0 },   
+		/* __PRINTF_FLAG_SHOWPLUS | __PRINTF_FLAG_LEFTALIGNED */
+		{ 1e-1, "%+-10.2e",  "+1.00e-01 ", 0 },
+		/* __PRINTF_FLAG_SPACESIGN | __PRINTF_FLAG_ZEROPADDED */
+		{ 1e-1, "% 010.2e",  " 01.00e-01", 0 },
+		/* __PRINTF_FLAG_ZEROPADDED */
+		{ 1e-1, "%010.2e",  "001.00e-01", 0 },
+		/* __PRINTF_FLAG_SPACESIGN */
+		{ 1e-1, "% 10.2e",  "  1.00e-01", 0 },
+		{ 1e-1, "%10.2e",  "  1.00e-01", 0 },   
+
+		/* padding fractionals */
+
+		/* __PRINTF_FLAG_SHOWPLUS | __PRINTF_FLAG_ZEROPADDED */
+		{ 1.08e29, "%+010.3e",  "+1.080e+29", 0 },
+		{ 1.08e29, "%+10.3e",  "+1.080e+29", 0 },  
+		/* __PRINTF_FLAG_SHOWPLUS | __PRINTF_FLAG_ZEROPADDED */
+		{ 1.08e29, "%+011.2e",  "+001.08e+29", 0 },
+		{ 1.085e29, "%11.2e", "   1.09e+29", 0 },   
+
+		/* rounding */
+
+		{ 1.345e2, "%+10.2e",  " +1.35e+02", 0 }, 
+		{ 9.995e2, "%+10.2e",  " +1.00e+03", 0 }, 
+		{ -9.99499999e2, "%10.2e",  " -9.99e+02", 0 },   
+		{ -9.99499999e2, "%10.0e",  "    -1e+03", 0 },   
+		/* __PRINTF_FLAG_DECIMALPT */
+		{ -9.99499999e2, "%#10.0e",  "   -1.e+03", 0 },
+		/* __PRINTF_FLAG_DECIMALPT */
+		{ -1.2345006789e+231, "%#10.10e",   "-1.2345006789e+231", 0 },
+		/* __PRINTF_FLAG_DECIMALPT */
+		{ -1.23450067995e+231, "%#10.10e",  "-1.2345006800e+231", 0 },
+			
+		/* special */
+
+		{ 1e300 * 1e300, "%10.5e",  "       inf", 0 },   
+		{ -1.0 /(1e300 * 1e300), "%10.2e",  " -0.00e+00", 0 },   
+		/* __PRINTF_FLAG_BIGCHARS */
+		{ 1e300 * 1e300, "%10.5E",  "       INF", 0 },
+		/* __PRINTF_FLAG_BIGCHARS */
+		{ -1.0 /(1e300 * 1e300), "%10.2E",  " -0.00E+00", 0 },
+
+		/*
+		 * Fixed
+		 */
+		 
+		/* padding */
+
+		/* __PRINTF_FLAG_SPACESIGN | __PRINTF_FLAG_ZEROPADDED */
+		{ 1e-1, "% 010.3f",  " 00000.100", 0 },
+		/*
+		 * __PRINTF_FLAG_SPACESIGN | __PRINTF_FLAG_ZEROPADDED |
+		 * __PRINTF_FLAG_LEFTALIGNED
+		 */
+		{ 1e-1, "% 0-10.3f",  " 0.100    ", 0 },
+		/* __PRINTF_FLAG_SPACESIGN | __PRINTF_FLAG_ZEROPADDED */
+		{ 1e-1, "% 010.3f",  " 00000.100", 0 },
+		{ 1e-1, "%10.3f",  "     0.100", 0 },   
+
+		/* rounding */
+
+		{ -0.0, "%10.0f",     "        -0", 0 },   
+		{ -0.099, "%+10.3f",   "    -0.099", 0 }, 
+		{ -0.0995, "%+10.3f",  "    -0.100", 0 }, 
+		{ -0.0994, "%+10.3f",  "    -0.099", 0 }, 
+		{ -99.995, "%+10.0f",  "      -100", 0 }, 
+		{ 3.5, "%+10.30f",  "+3.500000000000000000000000000000", 0 }, 
+		{ 3.5, "%+10.0f",      "        +4", 0 }, 
+		{ 0.1, "%+10.6f",      " +0.100000", 0 }, 
+
+		/*
+		 * The compiler will go for closer 0.10..055 instead of
+		 * 0.09..917
+		 */
+		{ 0.1, "%+10.20f",  "+0.10000000000000000550", 0 },  
+		/* Next closest to 0.1 */
+		{ 0.0999999999999999917, "%+10.20f", "+0.09999999999999999170",
+		    0 }, 
+		{ 0.0999999999999999917, "%+10f",    " +0.100000", 0 },
+		{ 0.0999999999999998945, "%10.20f",  "0.09999999999999989450",
+		    0 },   
+	};
+
+	int patterns_len = (int)(sizeof(pat) / sizeof(pat[0]));
+	int failed = 0;
+	const int buf_size = 256;
+	char buf[256 + 1] = { 0 };
+	
+	TPRINTF("Test printing of floating point numbers via "
+	    "printf(\"%%f\"):\n");
+	
+	for (int i = 0; i < patterns_len; ++i) {
+		
+		snprintf(buf, buf_size, pat[i].fmt, pat[i].val);
+		
+		if (!str_cmp(buf, pat[i].exp_str)) {
+			TPRINTF("ok:  %s |%s| == |%s|\n",
+			    pat[i].fmt, buf, pat[i].exp_str);
+		} else {
+			if (pat[i].warn_str && !str_cmp(buf, pat[i].warn_str)) {
+				TPRINTF("warn: %s |%s| != |%s|\n",
+				    pat[i].fmt, buf, pat[i].exp_str);
+			} else {
+				++failed;
+				TPRINTF("ERR: %s |%s| != |%s|\n",
+				    pat[i].fmt, buf, pat[i].exp_str);
+			}
+		}
+	}
+	
+	if (failed) {
+		return "Unexpectedly misprinted floating point numbers.";
+	} else {
+		return 0;
+	}
+}
+
Index: uspace/app/tester/print/print6.def
===================================================================
--- uspace/app/tester/print/print6.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/tester/print/print6.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,6 @@
+{
+	"print6",
+	"Floating point printf test",
+	&test_print6,
+	true
+},
Index: uspace/app/tester/stdio/logger1.c
===================================================================
--- uspace/app/tester/stdio/logger1.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/tester/stdio/logger1.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <io/log.h>
+#include "../tester.h"
+
+const char *test_logger1(void)
+{
+	for (log_level_t level = 0; level < LVL_LIMIT; level++) {
+		log_msg(LOG_DEFAULT, level, "Testing logger, level %d.", (int) level);
+	}
+
+	return NULL;
+}
Index: uspace/app/tester/stdio/logger1.def
===================================================================
--- uspace/app/tester/stdio/logger1.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/tester/stdio/logger1.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,6 @@
+{
+	"logger1",
+	"Logger printing test",
+	&test_logger1,
+	true
+},
Index: uspace/app/tester/stdio/logger2.c
===================================================================
--- uspace/app/tester/stdio/logger2.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/tester/stdio/logger2.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <io/log.h>
+#include <async.h>
+#include "../tester.h"
+
+const char *test_logger2(void)
+{
+	log_t log_alpha = log_create("alpha", LOG_DEFAULT);
+	log_t log_bravo = log_create("bravo", log_alpha);
+
+	TPRINTF("Alpha is %" PRIlogctx ".\n", log_alpha);
+	TPRINTF("Bravo is %" PRIlogctx ".\n", log_bravo);
+
+	while (true) {
+		/*
+		 * Intentionally skipping FATAL to allow muting
+		 * the output completely by setting visible level to FATAL.
+		 */
+		for (log_level_t level = LVL_ERROR; level < LVL_LIMIT; level++) {
+			log_msg(LOG_DEFAULT, level, "Printing level %d (%s).",
+			    (int) level, log_level_str(level));
+			log_msg(log_alpha, level,
+			    "Printing level %d (%s) into alpha log.",
+			    (int) level, log_level_str(level));
+			log_msg(log_bravo, level,
+			    "Printing level %d (%s) into bravo sub-log.",
+			    (int) level, log_level_str(level));
+			async_usleep(1000 * 100);
+		}
+	}
+
+	return NULL;
+}
Index: uspace/app/tester/stdio/logger2.def
===================================================================
--- uspace/app/tester/stdio/logger2.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/app/tester/stdio/logger2.def	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,6 @@
+{
+	"logger2",
+	"Logger endless test",
+	&test_logger2,
+	false
+},
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/tester/tester.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -39,4 +39,5 @@
 #include <stdio.h>
 #include <str.h>
+#include <io/log.h>
 #include "tester.h"
 
@@ -52,10 +53,15 @@
 #include "print/print4.def"
 #include "print/print5.def"
+#include "print/print6.def"
 #include "console/console1.def"
 #include "stdio/stdio1.def"
 #include "stdio/stdio2.def"
+#include "stdio/logger1.def"
+#include "stdio/logger2.def"
 #include "fault/fault1.def"
 #include "fault/fault2.def"
 #include "fault/fault3.def"
+#include "float/float1.def"
+#include "float/softfloat1.def"
 #include "vfs/vfs1.def"
 #include "ipc/ping_pong.def"
@@ -68,5 +74,5 @@
 #include "hw/serial/serial1.def"
 #include "hw/misc/virtchar1.def"
-#include "libext2/libext2_1.def"
+#include "ext2/ext2_1.def"
 	{NULL, NULL, NULL, false}
 };
@@ -138,4 +144,6 @@
 	}
 	
+	log_init("tester");
+
 	test_quiet = false;
 	test_argc = argc - 2;
Index: uspace/app/tester/tester.h
===================================================================
--- uspace/app/tester/tester.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/tester/tester.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -85,10 +85,15 @@
 extern const char *test_print4(void);
 extern const char *test_print5(void);
+extern const char *test_print6(void);
 extern const char *test_console1(void);
 extern const char *test_stdio1(void);
 extern const char *test_stdio2(void);
+extern const char *test_logger1(void);
+extern const char *test_logger2(void);
 extern const char *test_fault1(void);
 extern const char *test_fault2(void);
 extern const char *test_fault3(void);
+extern const char *test_float1(void);
+extern const char *test_softfloat1(void);
 extern const char *test_vfs1(void);
 extern const char *test_ping_pong(void);
@@ -101,5 +106,5 @@
 extern const char *test_serial1(void);
 extern const char *test_virtchar1(void);
-extern const char *test_libext2_1(void);
+extern const char *test_ext2_1(void);
 extern const char *test_devman1(void);
 extern const char *test_devman2(void);
Index: uspace/app/top/screen.h
===================================================================
--- uspace/app/top/screen.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/top/screen.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -36,4 +36,5 @@
 
 #include <io/console.h>
+#include <io/verify.h>
 #include "top.h"
 
@@ -43,5 +44,6 @@
 extern void screen_done(void);
 extern void print_data(data_t *);
-extern void show_warning(const char *, ...);
+extern void show_warning(const char *, ...)
+    PRINTF_ATTRIBUTE(1, 2);
 
 extern int tgetchar(unsigned int);
Index: uspace/app/trace/ipcp.c
===================================================================
--- uspace/app/trace/ipcp.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/trace/ipcp.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -98,6 +98,6 @@
 	.key_hash = pending_call_key_hash,
 	.key_equal = pending_call_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
Index: uspace/app/trace/proto.c
===================================================================
--- uspace/app/trace/proto.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/trace/proto.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -79,6 +79,6 @@
 	.key_hash = srv_proto_key_hash,
 	.key_equal = srv_proto_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -105,6 +105,6 @@
 	.key_hash = method_oper_key_hash,
 	.key_equal = method_oper_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
Index: uspace/app/vuhid/main.c
===================================================================
--- uspace/app/vuhid/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/app/vuhid/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -155,5 +155,5 @@
 	int rc;
 
-	usb_log_enable(USB_LOG_LEVEL_DEBUG2, "vusbhid");
+	log_init("vuhid");
 
 	fibril_mutex_initialize(&vuhid_data.iface_count_mutex);
Index: uspace/dist/src/bithenge/basic.bh
===================================================================
--- uspace/dist/src/bithenge/basic.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/basic.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,11 @@
+transform main = struct {
+	.u8 <- uint8;
+	.u16le <- uint16le;
+	.u16be <- uint16be;
+	.u32le <- uint32le;
+	.u32be <- uint32be;
+	.u64le <- uint64le;
+	.u64be <- uint64be;
+	.empty_blob <- known_length(0);
+	.ascii <- ascii <- known_length(8);
+};
Index: uspace/dist/src/bithenge/basic.dat
===================================================================
--- uspace/dist/src/bithenge/basic.dat	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/basic.dat	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,2 @@
+ªðð!CeeC!þÜºvT22TvºÜþ0~
+\"'	
Index: uspace/dist/src/bithenge/basic.out
===================================================================
--- uspace/dist/src/bithenge/basic.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/basic.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,11 @@
+{
+    "u8": 170,
+    "u16le": 4080,
+    "u16be": 4080,
+    "u32le": 2271560481,
+    "u32be": 2271560481,
+    "u64le": 1167088121787636990,
+    "u64be": 1167088121787636990,
+    "empty_blob": b"",
+    "ascii": "0~\u000a\\\"'\u0009\u001b"
+}
Index: uspace/dist/src/bithenge/bits.bh
===================================================================
--- uspace/dist/src/bithenge/bits.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/bits.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,25 @@
+transform main = struct {
+	.bits_le <- repeat(8) { bit } <- bits_le <- known_length(1);
+	.bits_be <- repeat(8) { bit } <- bits_be <- known_length(1);
+	<- struct {
+		.le0 <- uint_le(0);
+		.le1 <- uint_le(1);
+		.le2 <- uint_le(2);
+		.le3 <- uint_le(3);
+		.le4 <- uint_le(4);
+		.le5 <- uint_le(5);
+		.le6 <- uint_le(6);
+		.le7 <- uint_le(7);
+		.le8 <- uint_le(8);
+
+		.be8 <- uint_be(8);
+		.be7 <- uint_be(7);
+		.be6 <- uint_be(6);
+		.be5 <- uint_be(5);
+		.be4 <- uint_be(4);
+		.be3 <- uint_be(3);
+		.be2 <- uint_be(2);
+		.be1 <- uint_be(1);
+		.be0 <- uint_be(0);
+	} <- bits_be <- known_length(9);
+};
Index: uspace/dist/src/bithenge/bits.dat
===================================================================
--- uspace/dist/src/bithenge/bits.dat	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/bits.dat	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,1 @@
+ee¤BB%
Index: uspace/dist/src/bithenge/bits.out
===================================================================
--- uspace/dist/src/bithenge/bits.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/bits.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,40 @@
+{
+    "bits_le": {
+        0: True,
+        1: False,
+        2: True,
+        3: False,
+        4: False,
+        5: True,
+        6: True,
+        7: False
+    },
+    "bits_be": {
+        0: False,
+        1: True,
+        2: True,
+        3: False,
+        4: False,
+        5: True,
+        6: False,
+        7: True
+    },
+    "le0": 0,
+    "le1": 1,
+    "le2": 2,
+    "le3": 4,
+    "le4": 8,
+    "le5": 16,
+    "le6": 32,
+    "le7": 64,
+    "le8": 128,
+    "be8": 128,
+    "be7": 64,
+    "be6": 32,
+    "be5": 16,
+    "be4": 8,
+    "be3": 4,
+    "be2": 2,
+    "be1": 1,
+    "be0": 0
+}
Index: uspace/dist/src/bithenge/cond.bh
===================================================================
--- uspace/dist/src/bithenge/cond.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/cond.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,36 @@
+transform pascal_string = struct {
+	<- struct { # An inner struct for testing purposes
+		.len <- uint8;
+	};
+	.string <- ascii <- known_length(.len);
+};
+
+transform u32(little_endian) =
+	if (little_endian) {
+		uint32le
+	} else {
+		uint32be
+	};
+
+transform item(little_endian, len) = struct {
+	.type <- (3 * in + 1) <- u32(little_endian);
+	.name <- pascal_string;
+	switch (.type) {
+		10: {
+			.val <- u32(little_endian);
+		};
+		11: {
+			.text <- ascii <- known_length(len);
+		};
+		else: {
+			.unknown <- known_length(len);
+		};
+	}
+};
+
+transform main() = struct {
+	.first_len <- (3);
+	.second_len <- (6 - 2);
+	.first_item <- item(true, .first_len);
+	.second_item <- item(false, .second_len);
+};
Index: uspace/dist/src/bithenge/cond.out
===================================================================
--- uspace/dist/src/bithenge/cond.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/cond.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,20 @@
+{
+    "first_len": 3,
+    "second_len": 4,
+    "first_item": {
+        "type": 52,
+        "name": {
+            "len": 6,
+            "string": "Item 1"
+        },
+        "unknown": b"\xcf\x80\x78"
+    },
+    "second_item": {
+        "type": 10,
+        "name": {
+            "len": 6,
+            "string": "Item 2"
+        },
+        "val": 12345
+    }
+}
Index: uspace/dist/src/bithenge/expression.bh
===================================================================
--- uspace/dist/src/bithenge/expression.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/expression.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,54 @@
+transform compare_ints(a, b) = struct {
+	.l <- (a < b);
+	.g <- (a > b);
+	.ge <- (a >= b);
+	.le <- (a <= b);
+	.eq <- (a == b);
+	.ne <- (a != b);
+};
+
+transform arithmetic(a, b) = struct {
+	.sum <- (a + b);
+	.difference <- (a - b);
+	.product <- (a * b);
+	if (b > 0) {
+		.quotient <- (a // b);
+		.remainder <- (a % b);
+	}
+};
+
+transform concat_bits(a, b) = uint_le(24) <- (in.concat_bits) <- struct {
+	.bits0 <- bits_le <- (a);
+	.bits1 <- bits_be <- (b);
+	.concat_bits <- (.bits0 ++ (.bits1 ++ .bits0));
+};
+
+transform equality(bytes0, bytes1, str0, str1) = struct {
+	.neqs <- ((0 != 1) != (2 != 3));
+	.bytes0_eq_bytes1 <- (bytes0 == bytes1);
+	.bytes0_ne_bytes0 <- (bytes0 != bytes0);
+	.str0_ne_str1 <- (str0 != str1);
+	.str1_eq_str1 <- (str1 == str1);
+	.bytes1_eq_1 <- (bytes1 == 1);
+};
+
+transform subblob(bytes0) = struct {
+	.subblob <- (bytes0[0:][0,1][0:1]);
+};
+
+transform main = struct {
+	.bytes0 <- known_length(1);
+	.bytes1 <- known_length(1);
+	.str0 <- ascii <- (.bytes0);
+	.str1 <- ascii <- (.bytes1);
+	.compare_ints_0_1 <- compare_ints(0, 1);
+	.compare_ints_0_0 <- compare_ints(0, 0);
+	.compare_ints_1_0 <- compare_ints(1, 0);
+	.arithmetic_0_1 <- arithmetic(0, 1);
+	.arithmetic_17_n3 <- arithmetic(17, 0 - 3);
+	.arithmetic_n17_3 <- arithmetic(0 - 17, 3);
+	.concat_bytes <- (.bytes0 ++ (.bytes1 ++ .bytes0));
+	.concat_bits <- concat_bits(.bytes0, .bytes1);
+	.equality <- equality(.bytes0, .bytes1, .str0, .str1);
+	.subblob <- subblob(.bytes0);
+};
Index: uspace/dist/src/bithenge/expression.dat
===================================================================
--- uspace/dist/src/bithenge/expression.dat	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/expression.dat	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,1 @@
+17
Index: uspace/dist/src/bithenge/expression.out
===================================================================
--- uspace/dist/src/bithenge/expression.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/expression.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,62 @@
+{
+    "bytes0": b"\x31",
+    "bytes1": b"\x37",
+    "str0": "1",
+    "str1": "7",
+    "compare_ints_0_1": {
+        "l": True,
+        "g": False,
+        "ge": False,
+        "le": True,
+        "eq": False,
+        "ne": True
+    },
+    "compare_ints_0_0": {
+        "l": False,
+        "g": False,
+        "ge": True,
+        "le": True,
+        "eq": True,
+        "ne": False
+    },
+    "compare_ints_1_0": {
+        "l": False,
+        "g": True,
+        "ge": True,
+        "le": False,
+        "eq": False,
+        "ne": True
+    },
+    "arithmetic_0_1": {
+        "sum": 1,
+        "difference": -1,
+        "product": 0,
+        "quotient": 0,
+        "remainder": 0
+    },
+    "arithmetic_17_n3": {
+        "sum": 14,
+        "difference": 20,
+        "product": -51
+    },
+    "arithmetic_n17_3": {
+        "sum": -14,
+        "difference": -20,
+        "product": -51,
+        "quotient": -6,
+        "remainder": 1
+    },
+    "concat_bytes": b"\x31\x37\x31",
+    "concat_bits": 3271729,
+    "equality": {
+        "neqs": False,
+        "bytes0_eq_bytes1": False,
+        "bytes0_ne_bytes0": False,
+        "str0_ne_str1": True,
+        "str1_eq_str1": True,
+        "bytes1_eq_1": False
+    },
+    "subblob": {
+        "subblob": b"\x31"
+    }
+}
Index: uspace/dist/src/bithenge/fat.bh
===================================================================
--- uspace/dist/src/bithenge/fat.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/fat.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,168 @@
+# Copyright (c) 2012 Sean Bartell
+# 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.
+
+# FAT filesystem script.
+# Largely based on https://en.wikipedia.org/wiki/File_Allocation_Table
+# Currently only FAT12 and FAT16 are supported.
+
+transform u8 = uint8;
+transform u16 = uint16le;
+transform u32 = uint32le;
+
+transform fat_attributes = struct {
+	.read_only <- bit;
+	.hidden <- bit;
+	.system <- bit;
+	.volume_label <- bit;
+	.subdirectory <- bit;
+	.archive <- bit;
+	.device <- bit;
+	.reserved <- bit;
+} <- bits_le <- known_length(1);
+
+transform file_data(data, bits, fat, cluster_size, start) = (in.data) <- struct {
+	.cluster <- (data[(start-2)*cluster_size, cluster_size]);
+	.last_cluster_number <- switch (bits) {
+		12: (488);       # 0x00000ff8
+		16: (65528);     # 0x0000fff8
+		32: (268435448); # 0x0ffffff8
+	};
+	.next <- (fat[start]);
+	if (.next == 0 || .next >= .last_cluster_number) {
+		.data <- (.cluster);
+	} else {
+		.rest <- file_data(data, bits, fat, cluster_size, .next) <- known_length(0);
+		.data <- (.cluster ++ .rest);
+	}
+};
+
+transform fat_dir_entry(data, bits, fat, cluster_size, self_start, parent) = struct {
+	.filename <- known_length(8);
+	.extension <- known_length(3);
+	.attrs <- fat_attributes;
+	.flags <- u8;
+	.ctime_fine <- u8;
+	.ctime <- u16;
+	.cdate <- u16;
+	.adate <- u16;
+	.permissions <- u16;
+	.mtime <- u16;
+	.mdate <- u16;
+	.start <- u16;
+	.size <- u32;
+	.size_shown <- if (.size > 32) { (32) } else { (.size) };
+
+	if (.start != 0 && .start != self_start && .start != parent && .filename[0] != 229) {
+		.data
+		    <- if (.attrs.subdirectory) {
+		        repeat { fat_dir_entry(data, bits, fat, cluster_size, .start, self_start) }
+		    } else {
+		        (in[0,.size_shown])
+		    }
+		    <- if (.size != 0) { (in[0,.size]) } else { (in) }
+		    <- file_data(data, bits, fat, cluster_size, .start);
+	}
+};
+
+transform fat_table(bits, num_clusters) = switch (bits) {
+	12: partial {repeat(num_clusters) { uint_le(12) }} <- bits_le;
+	16: partial {repeat(num_clusters) { u16 }};
+	32: partial {repeat(num_clusters) { u32 }};
+};
+
+transform fat_super(disk) = struct {
+	.jump_instruction <- known_length(3);
+	.oem_name <- ascii <- known_length(8);
+
+	# DOS 2.0 BPB
+	.bytes_per_sector <- u16; # must be power of two, at least 32
+	.sectors_per_cluster <- u8; # must be power of two
+	.num_reserved_sectors <- u16;
+	.num_fats <- u8; # at least 1
+	.num_root_entries <- u16; # 0 for FAT32
+	.num_sectors_16 <- u16;
+	.media_descriptor <- u8;
+	.sectors_per_fat <- u16; # 0 for FAT32
+
+	# DOS 3.0/3.2/3.31 BPB
+	.sectors_per_track <- u16;
+	.num_heads <- u16;
+
+	# DOS 3.31 BPB
+	.bpb331 <- struct {
+		.ignore <- nonzero_boolean <- (.num_sectors_16);
+		.num_hidden_sectors <- u32;
+		.num_sectors_32 <- u32;
+	};
+
+	.drive_number <- u8;
+	.chkdsk_flags <- u8;
+	.extended_boot_signature <- u8;
+	if (.extended_boot_signature == 41) {
+		.volume_id <- u32;
+		.volume_label <- ascii <- known_length(11);
+		.type <- ascii <- known_length(8);
+	}
+
+	.boot_signature <- (disk[510,2]); # b"\x55\xaa"; TODO: what if .bytes_per_sector < 512?
+};
+
+transform fat_filesystem_tree(disk) = struct {
+	.super <- partial{fat_super(disk)} <- (disk);
+
+	.num_sectors <- if (.super.bpb331.ignore) {
+		(.super.num_sectors_16)
+	} else {
+		(.super.bpb331.num_sectors_32)
+	};
+
+	.cluster_size <- (.super.sectors_per_cluster * .super.bytes_per_sector);
+	.first_root_sector <- (.super.num_reserved_sectors + .super.num_fats * .super.sectors_per_fat);
+	.first_data_sector <- (.first_root_sector +
+	    (.super.num_root_entries * 32 + .super.bytes_per_sector - 1) //
+	    .super.bytes_per_sector);
+	.num_clusters <- (2 + (.num_sectors - .first_data_sector) // .super.sectors_per_cluster);
+	.bits <- if (.num_clusters < 4085) { (12) }
+	    else { if (.num_clusters < 65525) { (16) } else { (32) } };
+
+	.fats <- partial(.super.num_reserved_sectors * .super.bytes_per_sector) {
+		repeat(.super.num_fats) {
+			fat_table(.bits, .num_clusters) <-
+				known_length(.super.sectors_per_fat * .super.bytes_per_sector)
+		}
+	} <- (disk);
+
+	.root <- partial(.first_root_sector * .super.bytes_per_sector) {
+		repeat(.super.num_root_entries) {
+			fat_dir_entry(disk[.first_data_sector * .super.bytes_per_sector:],
+			    .bits, .fats[0], .cluster_size, 0, 0)
+		}
+	} <- (disk);
+};
+
+transform fat_filesystem = partial {fat_filesystem_tree(in)};
+
+transform main = fat_filesystem;
Index: uspace/dist/src/bithenge/fat.out
===================================================================
--- uspace/dist/src/bithenge/fat.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/fat.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,908 @@
+{
+    "super": {
+        "jump_instruction": b"\xeb\x3c\x90",
+        "oem_name": "mkdosfs",
+        "bytes_per_sector": 512,
+        "sectors_per_cluster": 1,
+        "num_reserved_sectors": 1,
+        "num_fats": 1,
+        "num_root_entries": 16,
+        "num_sectors_16": 66,
+        "media_descriptor": 248,
+        "sectors_per_fat": 1,
+        "sectors_per_track": 32,
+        "num_heads": 64,
+        "bpb331": {
+            "ignore": True,
+            "num_hidden_sectors": 0,
+            "num_sectors_32": 0
+        },
+        "drive_number": 0,
+        "chkdsk_flags": 0,
+        "extended_boot_signature": 41,
+        "volume_id": 1045880152,
+        "volume_label": "Test       ",
+        "type": "FAT12   ",
+        "boot_signature": b"\x55\xaa"
+    },
+    "num_sectors": 66,
+    "cluster_size": 512,
+    "first_root_sector": 2,
+    "first_data_sector": 3,
+    "num_clusters": 65,
+    "bits": 12,
+    "fats": {
+        0: {
+            0: 4088,
+            1: 4095,
+            2: 0,
+            3: 4095,
+            4: 0,
+            5: 0,
+            6: 0,
+            7: 0,
+            8: 0,
+            9: 0,
+            10: 0,
+            11: 0,
+            12: 0,
+            13: 0,
+            14: 0,
+            15: 0,
+            16: 0,
+            17: 0,
+            18: 0,
+            19: 0,
+            20: 0,
+            21: 0,
+            22: 0,
+            23: 0,
+            24: 0,
+            25: 0,
+            26: 0,
+            27: 0,
+            28: 0,
+            29: 0,
+            30: 0,
+            31: 0,
+            32: 0,
+            33: 0,
+            34: 0,
+            35: 0,
+            36: 0,
+            37: 38,
+            38: 4095,
+            39: 0,
+            40: 0,
+            41: 0,
+            42: 0,
+            43: 0,
+            44: 0,
+            45: 0,
+            46: 0,
+            47: 0,
+            48: 0,
+            49: 0,
+            50: 0,
+            51: 0,
+            52: 0,
+            53: 0,
+            54: 0,
+            55: 0,
+            56: 0,
+            57: 0,
+            58: 0,
+            59: 0,
+            60: 0,
+            61: 0,
+            62: 0,
+            63: 0,
+            64: 0
+        }
+    },
+    "root": {
+        0: {
+            "filename": b"\x54\x65\x73\x74\x20\x20\x20\x20",
+            "extension": b"\x20\x20\x20",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": True,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 35030,
+            "cdate": 16658,
+            "adate": 16658,
+            "permissions": 0,
+            "mtime": 35030,
+            "mdate": 16658,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        1: {
+            "filename": b"\x41\x73\x00\x75\x00\x62\x00\x64",
+            "extension": b"\x00\x69\x00",
+            "attrs": {
+                "read_only": True,
+                "hidden": True,
+                "system": True,
+                "volume_label": True,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 173,
+            "ctime": 114,
+            "cdate": 0,
+            "adate": 65535,
+            "permissions": 65535,
+            "mtime": 65535,
+            "mdate": 65535,
+            "start": 0,
+            "size": 4294967295,
+            "size_shown": 32
+        },
+        2: {
+            "filename": b"\x53\x55\x42\x44\x49\x52\x20\x20",
+            "extension": b"\x20\x20\x20",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": True,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 100,
+            "ctime": 43267,
+            "cdate": 16658,
+            "adate": 16658,
+            "permissions": 0,
+            "mtime": 43290,
+            "mdate": 16658,
+            "start": 3,
+            "size": 0,
+            "size_shown": 0,
+            "data": {
+                0: {
+                    "filename": b"\x2e\x20\x20\x20\x20\x20\x20\x20",
+                    "extension": b"\x20\x20\x20",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": True,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 100,
+                    "ctime": 43236,
+                    "cdate": 16658,
+                    "adate": 16658,
+                    "permissions": 0,
+                    "mtime": 43236,
+                    "mdate": 16658,
+                    "start": 3,
+                    "size": 0,
+                    "size_shown": 0
+                },
+                1: {
+                    "filename": b"\x2e\x2e\x20\x20\x20\x20\x20\x20",
+                    "extension": b"\x20\x20\x20",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": True,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 100,
+                    "ctime": 43236,
+                    "cdate": 16658,
+                    "adate": 16658,
+                    "permissions": 0,
+                    "mtime": 43236,
+                    "mdate": 16658,
+                    "start": 0,
+                    "size": 0,
+                    "size_shown": 0
+                },
+                2: {
+                    "filename": b"\xe5\x2e\x00\x66\x00\x69\x00\x6c",
+                    "extension": b"\x00\x65\x00",
+                    "attrs": {
+                        "read_only": True,
+                        "hidden": True,
+                        "system": True,
+                        "volume_label": True,
+                        "subdirectory": False,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 103,
+                    "ctime": 46,
+                    "cdate": 116,
+                    "adate": 120,
+                    "permissions": 116,
+                    "mtime": 46,
+                    "mdate": 115,
+                    "start": 0,
+                    "size": 7340151,
+                    "size_shown": 32
+                },
+                3: {
+                    "filename": b"\xe5\x49\x4c\x45\x54\x58\x7e\x31",
+                    "extension": b"\x53\x57\x50",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": False,
+                        "archive": True,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 0,
+                    "ctime": 43287,
+                    "cdate": 16658,
+                    "adate": 16658,
+                    "permissions": 0,
+                    "mtime": 43287,
+                    "mdate": 16658,
+                    "start": 13,
+                    "size": 12288,
+                    "size_shown": 32
+                },
+                4: {
+                    "filename": b"\x41\x66\x00\x69\x00\x6c\x00\x65",
+                    "extension": b"\x00\x2e\x00",
+                    "attrs": {
+                        "read_only": True,
+                        "hidden": True,
+                        "system": True,
+                        "volume_label": True,
+                        "subdirectory": False,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 25,
+                    "ctime": 116,
+                    "cdate": 120,
+                    "adate": 116,
+                    "permissions": 0,
+                    "mtime": 65535,
+                    "mdate": 65535,
+                    "start": 0,
+                    "size": 4294967295,
+                    "size_shown": 32
+                },
+                5: {
+                    "filename": b"\x46\x49\x4c\x45\x20\x20\x20\x20",
+                    "extension": b"\x54\x58\x54",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": False,
+                        "archive": True,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 0,
+                    "ctime": 43290,
+                    "cdate": 16658,
+                    "adate": 16658,
+                    "permissions": 0,
+                    "mtime": 43290,
+                    "mdate": 16658,
+                    "start": 37,
+                    "size": 951,
+                    "size_shown": 32,
+                    "data": b"\x22\x4a\x61\x62\x62\x65\x72\x77\x6f\x63\x6b\x79\x22\x0a\x0a\x27\x54\x77\x61\x73\x20\x62\x72\x69\x6c\x6c\x69\x67\x2c\x20\x61\x6e"
+                },
+                6: {
+                    "filename": b"\xe5\x2e\x00\x66\x00\x69\x00\x6c",
+                    "extension": b"\x00\x65\x00",
+                    "attrs": {
+                        "read_only": True,
+                        "hidden": True,
+                        "system": True,
+                        "volume_label": True,
+                        "subdirectory": False,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 111,
+                    "ctime": 46,
+                    "cdate": 116,
+                    "adate": 120,
+                    "permissions": 116,
+                    "mtime": 46,
+                    "mdate": 115,
+                    "start": 0,
+                    "size": 7864439,
+                    "size_shown": 32
+                },
+                7: {
+                    "filename": b"\xe5\x49\x4c\x45\x54\x58\x7e\x31",
+                    "extension": b"\x53\x57\x58",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": False,
+                        "archive": True,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 100,
+                    "ctime": 43267,
+                    "cdate": 16658,
+                    "adate": 16658,
+                    "permissions": 0,
+                    "mtime": 43267,
+                    "mdate": 16658,
+                    "start": 0,
+                    "size": 0,
+                    "size_shown": 0
+                },
+                8: {
+                    "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+                    "extension": b"\x00\x00\x00",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": False,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 0,
+                    "ctime": 0,
+                    "cdate": 0,
+                    "adate": 0,
+                    "permissions": 0,
+                    "mtime": 0,
+                    "mdate": 0,
+                    "start": 0,
+                    "size": 0,
+                    "size_shown": 0
+                },
+                9: {
+                    "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+                    "extension": b"\x00\x00\x00",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": False,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 0,
+                    "ctime": 0,
+                    "cdate": 0,
+                    "adate": 0,
+                    "permissions": 0,
+                    "mtime": 0,
+                    "mdate": 0,
+                    "start": 0,
+                    "size": 0,
+                    "size_shown": 0
+                },
+                10: {
+                    "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+                    "extension": b"\x00\x00\x00",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": False,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 0,
+                    "ctime": 0,
+                    "cdate": 0,
+                    "adate": 0,
+                    "permissions": 0,
+                    "mtime": 0,
+                    "mdate": 0,
+                    "start": 0,
+                    "size": 0,
+                    "size_shown": 0
+                },
+                11: {
+                    "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+                    "extension": b"\x00\x00\x00",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": False,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 0,
+                    "ctime": 0,
+                    "cdate": 0,
+                    "adate": 0,
+                    "permissions": 0,
+                    "mtime": 0,
+                    "mdate": 0,
+                    "start": 0,
+                    "size": 0,
+                    "size_shown": 0
+                },
+                12: {
+                    "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+                    "extension": b"\x00\x00\x00",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": False,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 0,
+                    "ctime": 0,
+                    "cdate": 0,
+                    "adate": 0,
+                    "permissions": 0,
+                    "mtime": 0,
+                    "mdate": 0,
+                    "start": 0,
+                    "size": 0,
+                    "size_shown": 0
+                },
+                13: {
+                    "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+                    "extension": b"\x00\x00\x00",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": False,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 0,
+                    "ctime": 0,
+                    "cdate": 0,
+                    "adate": 0,
+                    "permissions": 0,
+                    "mtime": 0,
+                    "mdate": 0,
+                    "start": 0,
+                    "size": 0,
+                    "size_shown": 0
+                },
+                14: {
+                    "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+                    "extension": b"\x00\x00\x00",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": False,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 0,
+                    "ctime": 0,
+                    "cdate": 0,
+                    "adate": 0,
+                    "permissions": 0,
+                    "mtime": 0,
+                    "mdate": 0,
+                    "start": 0,
+                    "size": 0,
+                    "size_shown": 0
+                },
+                15: {
+                    "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+                    "extension": b"\x00\x00\x00",
+                    "attrs": {
+                        "read_only": False,
+                        "hidden": False,
+                        "system": False,
+                        "volume_label": False,
+                        "subdirectory": False,
+                        "archive": False,
+                        "device": False,
+                        "reserved": False
+                    },
+                    "flags": 0,
+                    "ctime_fine": 0,
+                    "ctime": 0,
+                    "cdate": 0,
+                    "adate": 0,
+                    "permissions": 0,
+                    "mtime": 0,
+                    "mdate": 0,
+                    "start": 0,
+                    "size": 0,
+                    "size_shown": 0
+                }
+            }
+        },
+        3: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        4: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        5: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        6: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        7: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        8: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        9: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        10: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        11: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        12: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        13: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        14: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        },
+        15: {
+            "filename": b"\x00\x00\x00\x00\x00\x00\x00\x00",
+            "extension": b"\x00\x00\x00",
+            "attrs": {
+                "read_only": False,
+                "hidden": False,
+                "system": False,
+                "volume_label": False,
+                "subdirectory": False,
+                "archive": False,
+                "device": False,
+                "reserved": False
+            },
+            "flags": 0,
+            "ctime_fine": 0,
+            "ctime": 0,
+            "cdate": 0,
+            "adate": 0,
+            "permissions": 0,
+            "mtime": 0,
+            "mdate": 0,
+            "start": 0,
+            "size": 0,
+            "size_shown": 0
+        }
+    }
+}
Index: uspace/dist/src/bithenge/gif/gif.bh
===================================================================
--- uspace/dist/src/bithenge/gif/gif.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/gif/gif.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,148 @@
+#
+# Copyright (c) 2012 Vojtech Horky
+# 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.
+#
+
+#
+# Graphics Interchange Format (image/gif)
+#
+
+
+transform chars(len) = ascii <- known_length(len);
+transform word = uint16le;
+
+
+
+transform gif_signature = chars(3);
+
+transform gif_version = chars(3);
+
+transform gif_color_map_entry = struct {
+	.red <- uint8;
+	.green <- uint8;
+	.blue <- uint8;
+};
+
+transform gif_color_map(length) = repeat(length) {
+	gif_color_map_entry
+};
+
+transform gif_color_map_from_bits_per_pixel(bits_per_pixel) = struct {
+	# We need to emulate missing << operator
+	switch (bits_per_pixel) {
+		1: { <- gif_color_map(2); };
+		2: { <- gif_color_map(4); };
+		3: { <- gif_color_map(8); };
+		4: { <- gif_color_map(16); };
+		5: { <- gif_color_map(32); };
+		6: { <- gif_color_map(64); };
+		7: { <- gif_color_map(128); };
+		8: { <- gif_color_map(256); };
+	}
+};
+
+
+# Process GIF data block:
+#  - first byte denotes block size (.length)
+#  - followed by .length bytes of the actual data (not processed here)
+#  - followed by next block or terminator (zero)
+transform generic_data_block = do {
+	struct {
+		.length <- uint8;
+		.has_next <- nonzero_boolean <- (.length);
+		if (.has_next) {
+			.data <- known_length(.length);
+		}
+	}
+} while (.has_next);
+
+
+transform gif_image_block = struct {
+	.left <- word;
+	.top <- word;
+	.width <- word;
+	.height <- word;
+	
+	<- struct {
+		.use_local_color_map <- bit;
+		.interlacing <- bit;
+		.reserved_bits <- uint_be(3);
+		.bits_per_pixel <- (in + 1) <- uint_be(3);
+	} <- bits_be <- known_length(1);
+	
+	if (.use_local_color_map) {
+		.local_color_map <- gif_color_map_from_bits_per_pixel(.bits_per_pixel);
+	}
+	
+	.lzw_initial_size <- uint8;
+	.lzw_data <- generic_data_block;	
+};
+
+# TODO: interpret known extensions
+transform gif_extension = struct {
+	.function <- uint8;
+	.data <- generic_data_block;
+};
+
+# Switch over known blocks (image, extensions, end)
+transform gif_block = struct {
+	.kind <- uint8;
+	switch (.kind) {
+		33: { # exclamation mark -> extension block
+			.extension <- gif_extension;
+		};
+		44: { # comma -> image
+			.image <- gif_image_block;
+		};
+		59: { # semicolon -> terminator
+			.after_terminator <- repeat { uint8 };
+		};
+		else: {
+			.unknown <- repeat { uint8 };
+		};
+	}
+}; 
+
+transform main = struct {
+	.signature <- gif_signature;
+	.version <- gif_version;
+	.width <- word;
+	.height <- word;
+	<- struct {
+		.global_color_map_exists <- bit;
+		.color_resolution <- uint_be(3);
+		.reserved_bit <- uint_be(1);
+		.bits_per_pixel <- (in + 1) <- uint_be(3);
+	} <- bits_be <- known_length(1);
+	.background_color_index <- uint8;
+	.reserved <- uint8;
+	if (.global_color_map_exists) {
+		.global_color_map <- gif_color_map_from_bits_per_pixel(.bits_per_pixel);
+	}
+	.blocks <- repeat {
+		gif_block
+	}; 
+};
Index: uspace/dist/src/bithenge/gif/readme
===================================================================
--- uspace/dist/src/bithenge/gif/readme	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/gif/readme	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,9 @@
+
+File `loader.gif' was retrieved from
+   http://www.ajaxload.info/
+using default settings.
+
+File `blue_1x1.gif' was generated with ImageMagick using command
+   convert -size 1x1 xc:blue gif87:blue_1x1.gif
+
+File `helenos.gif' is a converted uspace/srv/hid/console/gfx/helenos.tga.
Index: uspace/dist/src/bithenge/repeat.bh
===================================================================
--- uspace/dist/src/bithenge/repeat.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/repeat.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,27 @@
+transform with_count = struct {
+	.none <- repeat(0) { uint8 };
+	.one <- repeat(1) { uint8 };
+	.count <- uint8;
+	if (true) { # test whether .count is still accessible
+		.many <- repeat(.count) { uint8 };
+	}
+};
+
+transform without_count = struct {
+	.until_error <- repeat { uint8 <- zero_terminated };
+	.until_end <- repeat { uint8 };
+};
+
+transform do_while = do {
+	struct {
+		.valid <- nonzero_boolean <- uint8;
+		.val <- uint8;
+	}
+} while (.valid);
+
+transform main = struct {
+	.with_count <- with_count;
+	.without_count <- without_count <- known_length(9);
+	.do_while <- do_while;
+	.do_while_item <- (.do_while[1]);
+};
Index: uspace/dist/src/bithenge/repeat.out
===================================================================
--- uspace/dist/src/bithenge/repeat.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/repeat.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,48 @@
+{
+    "with_count": {
+        "none": {},
+        "one": {
+            0: 127
+        },
+        "count": 7,
+        "many": {
+            0: 2,
+            1: 3,
+            2: 5,
+            3: 7,
+            4: 11,
+            5: 13,
+            6: 17
+        }
+    },
+    "without_count": {
+        "until_error": {
+            0: 2,
+            1: 4,
+            2: 8
+        },
+        "until_end": {
+            0: 16,
+            1: 32,
+            2: 64
+        }
+    },
+    "do_while": {
+        0: {
+            "valid": True,
+            "val": 1
+        },
+        1: {
+            "valid": True,
+            "val": 4
+        },
+        2: {
+            "valid": False,
+            "val": 9
+        }
+    },
+    "do_while_item": {
+        "valid": True,
+        "val": 4
+    }
+}
Index: uspace/dist/src/bithenge/test.bdsh
===================================================================
--- uspace/dist/src/bithenge/test.bdsh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/test.bdsh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,25 @@
+bithenge basic.bh basic.dat | to /tmp/bithenge-test.out
+cmp basic.out /tmp/bithenge-test.out
+
+bithenge bits.bh bits.dat | to /tmp/bithenge-test.out
+cmp bits.out /tmp/bithenge-test.out
+
+bithenge cond.bh cond.dat | to /tmp/bithenge-test.out
+cmp cond.out /tmp/bithenge-test.out
+
+bithenge expression.bh expression.dat | to /tmp/bithenge-test.out
+cmp expression.out /tmp/bithenge-test.out
+
+bithenge fat.bh fat.dat | to /tmp/bithenge-test.out
+cmp fat.out /tmp/bithenge-test.out
+
+bithenge repeat.bh repeat.dat | to /tmp/bithenge-test.out
+cmp repeat.out /tmp/bithenge-test.out
+
+bithenge trip.bh trip.dat | to /tmp/bithenge-test.out
+cmp trip.out /tmp/bithenge-test.out
+
+bithenge usbdesc.bh usbdesc.kbd.dat | to /tmp/bithenge-test.out
+cmp usbdesc.kbd.out /tmp/bithenge-test.out
+
+echo Success
Index: uspace/dist/src/bithenge/test.sh
===================================================================
--- uspace/dist/src/bithenge/test.sh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/test.sh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,33 @@
+#!/bin/bash
+shopt -s nullglob
+set -e
+
+BITHENGE=../../../app/bithenge/bithenge
+
+if type valgrind >/dev/null 2>&1
+then
+	BITHENGE="valgrind -q --show-reachable=yes --error-exitcode=64 ${BITHENGE}"
+else
+	echo "Valgrind not found."
+fi
+
+test_file() {
+	echo "Testing $1 on $2..."
+	${BITHENGE} $1 $2 2>&1|diff $3 -
+}
+
+for BH in *.bh
+do
+	for DAT in $(basename ${BH} .bh).dat $(basename ${BH} .bh).*.dat
+	do
+		OUT=$(basename ${DAT} .dat).out
+		[ -e ${DAT} ] || continue
+		[ -e ${OUT} ] || continue
+		test_file ${BH} ${DAT} ${OUT}
+	done
+done
+
+test_file trip.bh file:trip.dat trip.out
+test_file repeat.bh hex:7f07020305070b0D11020004000800102040010101040009 repeat.out
+
+echo "Done!"
Index: uspace/dist/src/bithenge/trip.bh
===================================================================
--- uspace/dist/src/bithenge/trip.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/trip.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,15 @@
+transform point = struct {
+	.lat <- uint32le;
+	.lon <- uint32le;
+};
+
+transform named_point = struct {
+	.name <- ascii <- zero_terminated;
+	<- point;
+};
+
+transform main = struct {
+	.from <- named_point;
+	.to <- named_point;
+	.distance <- uint32le; # in kilometers
+};
Index: uspace/dist/src/bithenge/trip.out
===================================================================
--- uspace/dist/src/bithenge/trip.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/trip.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,13 @@
+{
+    "from": {
+        "name": "Raleigh",
+        "lat": 36,
+        "lon": 79
+    },
+    "to": {
+        "name": "Denver",
+        "lat": 40,
+        "lon": 105
+    },
+    "distance": 2353
+}
Index: uspace/dist/src/bithenge/usbdesc.bh
===================================================================
--- uspace/dist/src/bithenge/usbdesc.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/usbdesc.bh	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,68 @@
+##
+##
+## USB DESCRIPTORS
+##
+##
+
+# Originally by Vojtech Horky.
+
+# Block prefixed with a byte length
+transform block = (in.data) <- struct {
+	.bLength <- uint8;
+	.data <- known_length(.bLength - 1);
+};
+
+# USB configuration descriptor
+# This is not the full configuration descriptor (i.e. with interface
+# and endpoint descriptors included) but only the header. 
+transform usb_configuration_descriptor_bare = struct {
+	.wTotalLength <- uint16le;
+	.bNumInterfaces <- uint8;
+	.bConfigurationValue <- uint8;
+	.iConfiguration <- uint8;
+	.bmAttributes <- uint8;
+	.MaxPower <- uint8;
+};
+
+# USB interface descriptor
+transform usb_interface_descriptor = struct {
+	.bInterfaceNumber <- uint8;
+	.bAlternateSetting <- uint8;
+	.bNumEndpoints <- uint8;
+	.bInterfaceClass <- uint8;
+	.bInterfaceSubClass <- uint8;
+	.bInterfaceProtocol <- uint8;
+	.iInterface <- uint8;
+};
+
+# USB endpoint descriptor
+transform usb_endpoint_descriptor = struct {
+	.bEndpointAddress  <- uint8;
+	.bmAttributes <- uint8;
+	.wMaxPacketSize <- uint16le;
+	.bInterval <- uint8;
+};
+
+# USB HID descriptor
+transform usb_hid_descriptor = struct {
+	.bcdHID <- uint16le;
+	.bCountryCode <- uint8;
+	.bNumDescriptors <- uint8;
+	<- repeat(.bNumDescriptors) { struct {
+		.bDescriptorType <- uint8;
+		.wDescriptorLength <- uint16le;
+	} };
+};
+
+# USB descriptor
+transform usb_descriptor = struct {
+	.bDescriptorType <- uint8;
+	<- switch (.bDescriptorType) {
+		 2: usb_configuration_descriptor_bare;
+		 4: usb_interface_descriptor;
+		 5: usb_endpoint_descriptor;
+		33: usb_hid_descriptor;
+	};
+} <- block;
+
+transform main = repeat { usb_descriptor };
Index: uspace/dist/src/bithenge/usbdesc.kbd.out
===================================================================
--- uspace/dist/src/bithenge/usbdesc.kbd.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/dist/src/bithenge/usbdesc.kbd.out	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,38 @@
+{
+    0: {
+        "bDescriptorType": 2,
+        "wTotalLength": 34,
+        "bNumInterfaces": 1,
+        "bConfigurationValue": 1,
+        "iConfiguration": 8,
+        "bmAttributes": 160,
+        "MaxPower": 50
+    },
+    1: {
+        "bDescriptorType": 4,
+        "bInterfaceNumber": 0,
+        "bAlternateSetting": 0,
+        "bNumEndpoints": 1,
+        "bInterfaceClass": 9,
+        "bInterfaceSubClass": 1,
+        "bInterfaceProtocol": 1,
+        "iInterface": 0
+    },
+    2: {
+        "bDescriptorType": 33,
+        "bcdHID": 273,
+        "bCountryCode": 0,
+        "bNumDescriptors": 1,
+        0: {
+            "bDescriptorType": 34,
+            "wDescriptorLength": 63
+        }
+    },
+    3: {
+        "bDescriptorType": 5,
+        "bEndpointAddress": 129,
+        "bmAttributes": 3,
+        "wMaxPacketSize": 8,
+        "bInterval": 10
+    }
+}
Index: uspace/dist/src/c/demos/top/screen.h
===================================================================
--- uspace/dist/src/c/demos/top/screen.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/dist/src/c/demos/top/screen.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -36,4 +36,5 @@
 
 #include <io/console.h>
+#include <io/verify.h>
 #include "top.h"
 
@@ -43,5 +44,6 @@
 extern void screen_done(void);
 extern void print_data(data_t *);
-extern void print_warning(const char *, ...);
+extern void print_warning(const char *, ...)
+    PRINTF_ATTRIBUTE(1, 2);
 
 extern int tgetchar(unsigned int);
Index: uspace/drv/block/ahci/ahci.c
===================================================================
--- uspace/drv/block/ahci/ahci.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/block/ahci/ahci.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -1340,5 +1340,5 @@
 {
 	printf("%s: HelenOS AHCI device driver\n", NAME);
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	fibril_mutex_initialize(&sata_devices_count_lock);
 	return ddf_driver_main(&ahci_driver);
Index: uspace/drv/bus/isa/i8237.c
===================================================================
--- uspace/drv/bus/isa/i8237.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/isa/i8237.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -351,5 +351,6 @@
 	
 	/* 16 bit transfers are a bit special */
-	ddf_msg(LVL_DEBUG, "Unspoiled address: %p and size: %zu.", pa, size);
+	ddf_msg(LVL_DEBUG, "Unspoiled address %#" PRIx32 " (size %" PRIu16 ")",
+	    pa, size);
 	if (channel > 4) {
 		/* Size must be aligned to 16 bits */
@@ -367,6 +368,6 @@
 	const dma_channel_t dma_channel = controller_8237.channels[channel];
 	
-	ddf_msg(LVL_DEBUG, "Setting channel %u, to address %p(%zu), mode %hhx.",
-	    channel, pa, size, mode);
+	ddf_msg(LVL_DEBUG, "Setting channel %u to address %#" PRIx32 " "
+	    "(size %" PRIu16 "), mode %hhx.", channel, pa, size, mode);
 	
 	/* Mask DMA request */
Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/isa/isa.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -712,5 +712,5 @@
 static void isa_init()
 {
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	isa_fun_ops.interfaces[HW_RES_DEV_IFACE] = &isa_fun_hw_res_ops;
 }
Index: uspace/drv/bus/isa/isa.dev
===================================================================
--- uspace/drv/bus/isa/isa.dev	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/isa/isa.dev	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -27,2 +27,6 @@
 	dma 1
 	dma 5
+
+cmos-rtc:
+	match 100 isa/cmos-rtc
+	io_range 70 2
Index: uspace/drv/bus/pci/pciintel/pci.c
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/pci/pciintel/pci.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -729,5 +729,5 @@
 static void pciintel_init(void)
 {
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	pci_fun_ops.interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops;
 	pci_fun_ops.interfaces[PCI_DEV_IFACE] = &pci_dev_ops;
Index: uspace/drv/bus/usb/ehci/main.c
===================================================================
--- uspace/drv/bus/usb/ehci/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/usb/ehci/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -132,5 +132,5 @@
 int main(int argc, char *argv[])
 {
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 	return ddf_driver_main(&ehci_driver);
 }
Index: uspace/drv/bus/usb/ohci/main.c
===================================================================
--- uspace/drv/bus/usb/ohci/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/usb/ohci/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -83,5 +83,5 @@
 int main(int argc, char *argv[])
 {
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 	return ddf_driver_main(&ohci_driver);
 }
Index: uspace/drv/bus/usb/uhci/main.c
===================================================================
--- uspace/drv/bus/usb/uhci/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/usb/uhci/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -87,5 +87,5 @@
 {
 	printf(NAME ": HelenOS UHCI driver.\n");
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	return ddf_driver_main(&uhci_driver);
Index: uspace/drv/bus/usb/uhcirh/main.c
===================================================================
--- uspace/drv/bus/usb/uhcirh/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/usb/uhcirh/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -73,5 +73,5 @@
 {
 	printf(NAME ": HelenOS UHCI root hub driver.\n");
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 	return ddf_driver_main(&uhci_rh_driver);
 }
Index: uspace/drv/bus/usb/usbflbk/main.c
===================================================================
--- uspace/drv/bus/usb/usbflbk/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/usb/usbflbk/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -110,5 +110,5 @@
 int main(int argc, char *argv[])
 {
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	return usb_driver_main(&usbfallback_driver);
Index: uspace/drv/bus/usb/usbhid/main.c
===================================================================
--- uspace/drv/bus/usb/usbhid/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/usb/usbhid/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -172,5 +172,5 @@
 	printf(NAME ": HelenOS USB HID driver.\n");
 
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	return usb_driver_main(&usb_hid_driver);
Index: uspace/drv/bus/usb/usbhub/main.c
===================================================================
--- uspace/drv/bus/usb/usbhub/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/usb/usbhub/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -79,5 +79,5 @@
 {
 	printf(NAME ": HelenOS USB hub driver.\n");
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	return usb_driver_main(&usb_hub_driver);
Index: uspace/drv/bus/usb/usbmast/main.c
===================================================================
--- uspace/drv/bus/usb/usbmast/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/usb/usbmast/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -383,5 +383,5 @@
 int main(int argc, char *argv[])
 {
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	return usb_driver_main(&usbmast_driver);
Index: uspace/drv/bus/usb/usbmid/main.c
===================================================================
--- uspace/drv/bus/usb/usbmid/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/usb/usbmid/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -180,5 +180,5 @@
 	printf(NAME ": USB multi interface device driver.\n");
 
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	return usb_driver_main(&mid_driver);
Index: uspace/drv/bus/usb/vhc/Makefile
===================================================================
--- uspace/drv/bus/usb/vhc/Makefile	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/usb/vhc/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -32,6 +32,6 @@
 	$(LIBUSBDEV_PREFIX)/libusbdev.a \
 	$(LIBUSBHOST_PREFIX)/libusbhost.a \
+	$(LIBUSBVIRT_PREFIX)/libusbvirt.a \
 	$(LIBUSB_PREFIX)/libusb.a \
-	$(LIBUSBVIRT_PREFIX)/libusbvirt.a \
 	$(LIBDRV_PREFIX)/libdrv.a
 
Index: uspace/drv/bus/usb/vhc/main.c
===================================================================
--- uspace/drv/bus/usb/vhc/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/bus/usb/vhc/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -138,5 +138,5 @@
 int main(int argc, char * argv[])
 {	
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	printf(NAME ": virtual USB host controller driver.\n");
Index: uspace/drv/char/i8042/i8042.c
===================================================================
--- uspace/drv/char/i8042/i8042.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/char/i8042/i8042.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -302,5 +302,5 @@
 	const bool enabled = hw_res_enable_interrupt(parent_sess);
 	if (!enabled) {
-		log_msg(LVL_ERROR, "Failed to enable interrupts: %s.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to enable interrupts: %s.",
 		    ddf_dev_get_name(ddf_dev));
 		rc = EIO;
Index: uspace/drv/char/i8042/main.c
===================================================================
--- uspace/drv/char/i8042/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/char/i8042/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -151,5 +151,5 @@
 {
 	printf("%s: HelenOS PS/2 driver.\n", NAME);
-	ddf_log_init(NAME, LVL_NOTE);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&i8042_driver);
 }
Index: uspace/drv/char/ns8250/ns8250.c
===================================================================
--- uspace/drv/char/ns8250/ns8250.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/char/ns8250/ns8250.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -1084,5 +1084,5 @@
 static void ns8250_init(void)
 {
-	ddf_log_init(NAME, LVL_WARN);
+	ddf_log_init(NAME);
 	
 	ns8250_dev_ops.open = &ns8250_open;
Index: uspace/drv/char/ps2mouse/main.c
===================================================================
--- uspace/drv/char/ps2mouse/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/char/ps2mouse/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -69,5 +69,5 @@
 {
 	printf(NAME ": HelenOS ps/2 mouse driver.\n");
-	ddf_log_init(NAME, LVL_NOTE);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&mouse_driver);
 }
Index: uspace/drv/char/ps2mouse/ps2mouse.c
===================================================================
--- uspace/drv/char/ps2mouse/ps2mouse.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/char/ps2mouse/ps2mouse.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -75,5 +75,5 @@
 	const ssize_t size = chardev_read(sess, &data, 1); \
 	if (size != 1) { \
-		ddf_msg(LVL_ERROR, "Failed reading byte: %d)", size);\
+		ddf_msg(LVL_ERROR, "Failed reading byte: %zd)", size);\
 		return size < 0 ? size : EIO; \
 	} \
Index: uspace/drv/char/xtkbd/main.c
===================================================================
--- uspace/drv/char/xtkbd/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/char/xtkbd/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -69,5 +69,5 @@
 {
 	printf(NAME ": HelenOS XT keyboard driver.\n");
-	ddf_log_init(NAME, LVL_NOTE);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&kbd_driver);
 }
Index: uspace/drv/infrastructure/root/root.c
===================================================================
--- uspace/drv/infrastructure/root/root.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/infrastructure/root/root.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -237,5 +237,5 @@
 	printf(NAME ": HelenOS root device driver\n");
 
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&root_driver);
 }
Index: uspace/drv/infrastructure/rootmac/rootmac.c
===================================================================
--- uspace/drv/infrastructure/rootmac/rootmac.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/infrastructure/rootmac/rootmac.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -179,5 +179,5 @@
 {
 	printf("%s: HelenOS Mac platform driver\n", NAME);
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	rootmac_fun_ops.interfaces[HW_RES_DEV_IFACE] = &fun_hw_res_ops;
 	return ddf_driver_main(&rootmac_driver);
Index: uspace/drv/infrastructure/rootpc/rootpc.c
===================================================================
--- uspace/drv/infrastructure/rootpc/rootpc.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/infrastructure/rootpc/rootpc.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -195,5 +195,5 @@
 static void root_pc_init(void)
 {
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	rootpc_fun_ops.interfaces[HW_RES_DEV_IFACE] = &fun_hw_res_ops;
 }
Index: uspace/drv/infrastructure/rootvirt/rootvirt.c
===================================================================
--- uspace/drv/infrastructure/rootvirt/rootvirt.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/infrastructure/rootvirt/rootvirt.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -240,5 +240,5 @@
 	printf(NAME ": HelenOS virtual devices root driver\n");
 
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&rootvirt_driver);
 }
Index: uspace/drv/nic/e1k/e1k.c
===================================================================
--- uspace/drv/nic/e1k/e1k.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/nic/e1k/e1k.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -2381,5 +2381,5 @@
 	    &e1000_nic_iface);
 	
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	ddf_msg(LVL_NOTE, "HelenOS E1000 driver started");
 	return ddf_driver_main(&e1000_driver);
Index: uspace/drv/nic/rtl8139/driver.c
===================================================================
--- uspace/drv/nic/rtl8139/driver.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/nic/rtl8139/driver.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -620,6 +620,6 @@
 		/* Check if the header is valid, otherwise we are lost in the buffer */
 		if (size == 0 || size > RTL8139_FRAME_MAX_LENGTH) {
-			ddf_msg(LVL_ERROR, "Receiver error -> receiver reset (size: %4"PRIu16", "
-			    "header 0x%4"PRIx16". Offset: %zu)", size, frame_header, 
+			ddf_msg(LVL_ERROR, "Receiver error -> receiver reset (size: %4" PRIu16 ", "
+			    "header 0x%4" PRIx16 ". Offset: %d)", size, frame_header,
 			    rx_offset);
 			goto rx_err;
@@ -1162,5 +1162,5 @@
 
 	/* Allocate buffer for receiver */
-	ddf_msg(LVL_DEBUG, "Allocating receiver buffer of the size %zu bytes",
+	ddf_msg(LVL_DEBUG, "Allocating receiver buffer of the size %d bytes",
 	    RxBUF_TOT_LENGTH);
 
@@ -1249,5 +1249,5 @@
 	/* Gain control over port's registers. */
 	if (pio_enable(rtl8139->io_addr, RTL8139_IO_SIZE, &rtl8139->io_port)) {
-		ddf_msg(LVL_ERROR, "Cannot gain the port %lx for device %s.", rtl8139->io_addr,
+		ddf_msg(LVL_ERROR, "Cannot gain the port %p for device %s.", rtl8139->io_addr,
 		    ddf_dev_get_name(dev));
 		return EADDRNOTAVAIL;
@@ -1296,5 +1296,5 @@
 
 	assert(dev);
-	ddf_msg(LVL_NOTE, "RTL8139_dev_add %s (handle = %d)",
+	ddf_msg(LVL_NOTE, "RTL8139_dev_add %s (handle = %zu)",
 	    ddf_dev_get_name(dev), ddf_dev_get_handle(dev));
 
@@ -1328,5 +1328,5 @@
 	rc = nic_connect_to_services(nic_data);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed to connect to services", rc);
+		ddf_msg(LVL_ERROR, "Failed to connect to services (%d)", rc);
 		goto err_irq;
 	}
@@ -2139,7 +2139,8 @@
 		pio_write_32(rtl8139->io_port + TCTR, 0);
 
-		ddf_msg(LVL_DEBUG, "Periodic mode. Interrupt mask %"PRIx16", poll.full_skips %"
-		    PRIu32", last timer %"PRIu32".", rtl8139->int_mask, 
-		    rtl8139->poll_timer.full_skips, rtl8139->poll_timer.last_val);
+		ddf_msg(LVL_DEBUG, "Periodic mode. Interrupt mask %" PRIx16 ", "
+		    "poll.full_skips %zu, last timer %" PRIu32,
+		    rtl8139->int_mask, rtl8139->poll_timer.full_skips,
+		    rtl8139->poll_timer.last_val);
 		break;
 	default:
@@ -2186,5 +2187,5 @@
 		&rtl8139_driver_ops, &rtl8139_dev_ops, &rtl8139_nic_iface);
 
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	ddf_msg(LVL_NOTE, "HelenOS RTL8139 driver started");
 	return ddf_driver_main(&rtl8139_driver);
Index: uspace/drv/test/test1/test1.c
===================================================================
--- uspace/drv/test/test1/test1.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/test/test1/test1.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -306,5 +306,5 @@
 {
 	printf(NAME ": HelenOS test1 virtual device driver\n");
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&test1_driver);
 }
Index: uspace/drv/test/test2/test2.c
===================================================================
--- uspace/drv/test/test2/test2.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/test/test2/test2.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -308,5 +308,5 @@
 {
 	printf(NAME ": HelenOS test2 virtual device driver\n");
-	ddf_log_init(NAME, LVL_NOTE);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&test2_driver);
 }
Index: uspace/drv/test/test3/test3.c
===================================================================
--- uspace/drv/test/test3/test3.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/drv/test/test3/test3.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -193,5 +193,5 @@
 {
 	printf(NAME ": HelenOS test3 virtual device driver\n");
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&test3_driver);
 }
Index: uspace/drv/time/cmos-rtc/Makefile
===================================================================
--- uspace/drv/time/cmos-rtc/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/drv/time/cmos-rtc/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2012 Maurizio Lombardi
+# 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.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = cmos-rtc
+
+SOURCES = \
+	cmos-rtc.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/time/cmos-rtc/cmos-regs.h
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-regs.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/drv/time/cmos-rtc/cmos-regs.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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.
+ */
+
+#ifndef _CMOS_RTC_H_
+#define _CMOS_RTC_H_
+
+#define RTC_SEC           0x00
+#define RTC_MIN           0x02
+#define RTC_HOUR          0x04
+#define RTC_DAY           0x07
+#define RTC_MON           0x08
+#define RTC_YEAR          0x09
+
+#define RTC_STATUS_B      0x0B
+#define RTC_B_24H         0x02 /* 24h mode */
+#define RTC_B_BCD         0x04 /* BCD mode */
+#define RTC_B_INH         0x80 /* Inhibit updates */
+
+#define RTC_STATUS_D      0x0D
+#define RTC_D_BATTERY_OK  0x80 /* Battery status */
+
+#define RTC_STATUS_A      0x0A
+#define RTC_A_UPDATE      0x80 /* Update in progress */
+#define RTC_A_CLK_STOP    0x70 /* Stop the clock */
+
+#endif
+
Index: uspace/drv/time/cmos-rtc/cmos-rtc.c
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,775 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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.
+ */
+
+/**
+ * @defgroup CMOS RTC driver.
+ * @brief HelenOS RTC driver.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <errno.h>
+#include <ddi.h>
+#include <as.h>
+#include <sysinfo.h>
+#include <libarch/ddi.h>
+#include <libarch/barrier.h>
+#include <stdio.h>
+#include <ddf/driver.h>
+#include <ddf/log.h>
+#include <ops/clock_dev.h>
+#include <ops/battery_dev.h>
+#include <fibril_synch.h>
+#include <device/hw_res.h>
+#include <macros.h>
+#include <time.h>
+
+#include "cmos-regs.h"
+
+#define NAME "cmos-rtc"
+
+#define REG_COUNT 2
+
+#define REG_SEL_PORT(port)  (port)
+#define REG_RW_PORT(port)   ((port) + 1)
+
+typedef struct rtc {
+	/** DDF device node */
+	ddf_dev_t *dev;
+	/** DDF function node */
+	ddf_fun_t *fun;
+	/** The fibril mutex for synchronizing the access to the device */
+	fibril_mutex_t mutex;
+	/** The base I/O address of the device registers */
+	ioport8_t *io_addr;
+	/** The I/O port used to access the CMOS registers */
+	ioport8_t *port;
+	/** true if device is removed */
+	bool removed;
+	/** number of connected clients */
+	int clients_connected;
+	/** time at which the system booted */
+	time_t boottime;
+} rtc_t;
+
+static rtc_t *dev_rtc(ddf_dev_t *dev);
+static rtc_t *fun_rtc(ddf_fun_t *fun);
+static int
+rtc_battery_status_get(ddf_fun_t *fun, battery_status_t *status);
+static int  rtc_time_get(ddf_fun_t *fun, struct tm *t);
+static int  rtc_time_set(ddf_fun_t *fun, struct tm *t);
+static int  rtc_dev_add(ddf_dev_t *dev);
+static int  rtc_dev_initialize(rtc_t *rtc);
+static bool rtc_pio_enable(rtc_t *rtc);
+static void rtc_dev_cleanup(rtc_t *rtc);
+static int  rtc_open(ddf_fun_t *fun);
+static void rtc_close(ddf_fun_t *fun);
+static bool rtc_update_in_progress(rtc_t *rtc);
+static int  rtc_register_read(rtc_t *rtc, int reg);
+static unsigned bcd2bin(unsigned bcd);
+static unsigned bin2bcd(unsigned binary);
+static int rtc_dev_remove(ddf_dev_t *dev);
+static void rtc_register_write(rtc_t *rtc, int reg, int data);
+static time_t uptime_get(void);
+static bool is_battery_ok(rtc_t *rtc);
+static int  rtc_fun_online(ddf_fun_t *fun);
+static int  rtc_fun_offline(ddf_fun_t *fun);
+
+static ddf_dev_ops_t rtc_dev_ops;
+
+/** The RTC device driver's standard operations */
+static driver_ops_t rtc_ops = {
+	.dev_add = rtc_dev_add,
+	.dev_remove = rtc_dev_remove,
+	.fun_online = rtc_fun_online,
+	.fun_offline = rtc_fun_offline,
+};
+
+/** The RTC device driver structure */
+static driver_t rtc_driver = {
+	.name = NAME,
+	.driver_ops = &rtc_ops,
+};
+
+/** Clock interface */
+static clock_dev_ops_t rtc_clock_dev_ops = {
+	.time_get = rtc_time_get,
+	.time_set = rtc_time_set,
+};
+
+/** Battery powered device interface */
+static battery_dev_ops_t rtc_battery_dev_ops = {
+	.battery_status_get = rtc_battery_status_get,
+	.battery_charge_level_get = NULL,
+};
+
+/** Obtain soft state structure from device node */
+static rtc_t *
+dev_rtc(ddf_dev_t *dev)
+{
+	return ddf_dev_data_get(dev);
+}
+
+/** Obtain soft state structure from function node */
+static rtc_t *
+fun_rtc(ddf_fun_t *fun)
+{
+	return dev_rtc(ddf_fun_get_dev(fun));
+}
+
+/** Initialize the RTC driver */
+static void
+rtc_init(void)
+{
+	ddf_log_init(NAME);
+
+	rtc_dev_ops.open = rtc_open;
+	rtc_dev_ops.close = rtc_close;
+
+	rtc_dev_ops.interfaces[CLOCK_DEV_IFACE] = &rtc_clock_dev_ops;
+	rtc_dev_ops.interfaces[BATTERY_DEV_IFACE] = &rtc_battery_dev_ops;
+	rtc_dev_ops.default_handler = NULL;
+}
+
+/** Clean up the RTC soft state
+ *
+ * @param rtc  The RTC device
+ */
+static void
+rtc_dev_cleanup(rtc_t *rtc)
+{
+}
+
+/** Enable the I/O ports of the device
+ *
+ * @param rtc  The real time clock device
+ *
+ * @return  true in case of success, false otherwise
+ */
+static bool
+rtc_pio_enable(rtc_t *rtc)
+{
+	if (pio_enable((void *) rtc->io_addr, REG_COUNT,
+	    (void **) &rtc->port)) {
+
+		ddf_msg(LVL_ERROR, "Cannot map the port %lx"
+		    " for device %s", (long unsigned int)rtc->io_addr,
+		    ddf_dev_get_name(rtc->dev));
+		return false;
+	}
+
+	return true;
+}
+
+/** Initialize the RTC device
+ *
+ * @param rtc  Pointer to the RTC device
+ *
+ * @return  EOK on success or a negative error code
+ */ 
+static int
+rtc_dev_initialize(rtc_t *rtc)
+{
+	int rc;
+	size_t i;
+	hw_resource_t *res;
+	bool ioport = false;
+	async_sess_t *parent_sess;
+
+	ddf_msg(LVL_DEBUG, "rtc_dev_initialize %s", ddf_dev_get_name(rtc->dev));
+
+	rtc->boottime = 0;
+	rtc->clients_connected = 0;
+
+	hw_resource_list_t hw_resources;
+	memset(&hw_resources, 0, sizeof(hw_resource_list_t));
+
+	/* Connect to the parent's driver */
+
+	parent_sess = ddf_dev_parent_sess_create(rtc->dev, EXCHANGE_SERIALIZE);
+	if (!parent_sess) {
+		ddf_msg(LVL_ERROR, "Failed to connect to parent driver\
+		    of device %s.", ddf_dev_get_name(rtc->dev));
+		rc = ENOENT;
+		goto error;
+	}
+
+	/* Get the HW resources */
+	rc = hw_res_get_resource_list(parent_sess, &hw_resources);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to get HW resources\
+		    for device %s", ddf_dev_get_name(rtc->dev));
+		goto error;
+	}
+
+	for (i = 0; i < hw_resources.count; ++i) {
+		res = &hw_resources.resources[i];
+
+		if (res->res.io_range.size < REG_COUNT) {
+			ddf_msg(LVL_ERROR, "I/O range assigned to \
+			    device %s is too small",
+			    ddf_dev_get_name(rtc->dev));
+			rc = ELIMIT;
+			continue;
+		}
+
+		rtc->io_addr = (ioport8_t *) (long) res->res.io_range.address;
+		ioport = true;
+		ddf_msg(LVL_NOTE, "Device %s was assigned I/O address "
+		    "0x%lx", ddf_dev_get_name(rtc->dev),
+		    (unsigned long int) rtc->io_addr);
+		rc = EOK;
+		break;
+	}
+
+	if (rc != EOK)
+		goto error;
+
+	if (!ioport) {
+		/* No I/O address assigned to this device */
+		ddf_msg(LVL_ERROR, "Missing HW resource for device %s",
+		    ddf_dev_get_name(rtc->dev));
+		rc = ENOENT;
+		goto error;
+	}
+
+	hw_res_clean_resource_list(&hw_resources);
+
+	return EOK;
+
+error:
+	rtc_dev_cleanup(rtc);
+	hw_res_clean_resource_list(&hw_resources);
+
+	return rc;
+}
+
+/** Read a register from the CMOS memory
+ *
+ * @param rtc    The rtc device
+ * @param reg    The index of the register to read
+ *
+ * @return       The value of the register
+ */
+static int
+rtc_register_read(rtc_t *rtc, int reg)
+{
+	pio_write_8(REG_SEL_PORT(rtc->port), reg);
+	return pio_read_8(REG_RW_PORT(rtc->port));
+}
+
+/** Write a register to the CMOS memory
+ *
+ * @param rtc    The rtc device
+ * @param reg    The index of the register to write
+ * @param data   The data to write
+ */
+static void
+rtc_register_write(rtc_t *rtc, int reg, int data)
+{
+	pio_write_8(REG_SEL_PORT(rtc->port), reg);
+	pio_write_8(REG_RW_PORT(rtc->port), data);
+}
+
+/** Check if an update is in progress
+ *
+ * @param rtc  The rtc device
+ *
+ * @return  true if an update is in progress, false otherwise
+ */
+static bool
+rtc_update_in_progress(rtc_t *rtc)
+{
+	return rtc_register_read(rtc, RTC_STATUS_A) & RTC_A_UPDATE;
+}
+
+/** Read the current time from the CMOS
+ *
+ * @param fun  The RTC function
+ * @param t    Pointer to the time variable
+ *
+ * @return  EOK on success or a negative error code
+ */
+static int
+rtc_time_get(ddf_fun_t *fun, struct tm *t)
+{
+	bool bcd_mode;
+	bool pm_mode = false;
+	rtc_t *rtc = fun_rtc(fun);
+
+	fibril_mutex_lock(&rtc->mutex);
+
+	if (rtc->boottime != 0) {
+		/* There is no need to read the current time from the
+		 * device because it has already been cached.
+		 */
+
+		time_t cur_time = rtc->boottime + uptime_get();
+
+		fibril_mutex_unlock(&rtc->mutex);
+
+		return time_local2tm(cur_time, t);
+	}
+
+	/* Check if the RTC battery is OK */
+	if (!is_battery_ok(rtc)) {
+		fibril_mutex_unlock(&rtc->mutex);
+		return EIO;
+	}
+
+	/* now read the registers */
+	do {
+		/* Suspend until the update process has finished */
+		while (rtc_update_in_progress(rtc));
+
+		t->tm_sec  = rtc_register_read(rtc, RTC_SEC);
+		t->tm_min  = rtc_register_read(rtc, RTC_MIN);
+		t->tm_hour = rtc_register_read(rtc, RTC_HOUR);
+		t->tm_mday = rtc_register_read(rtc, RTC_DAY);
+		t->tm_mon  = rtc_register_read(rtc, RTC_MON);
+		t->tm_year = rtc_register_read(rtc, RTC_YEAR);
+
+		/* Now check if it is stable */
+	} while(t->tm_sec  != rtc_register_read(rtc, RTC_SEC) ||
+	    t->tm_min  != rtc_register_read(rtc, RTC_MIN) ||
+	    t->tm_mday != rtc_register_read(rtc, RTC_DAY) ||
+	    t->tm_mon  != rtc_register_read(rtc, RTC_MON) ||
+	    t->tm_year != rtc_register_read(rtc, RTC_YEAR));
+
+	/* Check if the RTC is working in 12h mode */
+	bool _12h_mode = !(rtc_register_read(rtc, RTC_STATUS_B) &
+	    RTC_B_24H);
+
+	if (_12h_mode) {
+		/* The RTC is working in 12h mode, check if it is AM or PM */
+		if (t->tm_hour & 0x80) {
+			/* PM flag is active, it must be cleared */
+			t->tm_hour &= ~0x80;
+			pm_mode = true;
+		}
+	}
+
+	/* Check if the RTC is working in BCD mode */
+	bcd_mode = !(rtc_register_read(rtc, RTC_STATUS_B) & RTC_B_BCD);
+
+	if (bcd_mode) {
+		t->tm_sec  = bcd2bin(t->tm_sec);
+		t->tm_min  = bcd2bin(t->tm_min);
+		t->tm_hour = bcd2bin(t->tm_hour);
+		t->tm_mday = bcd2bin(t->tm_mday);
+		t->tm_mon  = bcd2bin(t->tm_mon);
+		t->tm_year = bcd2bin(t->tm_year);
+	}
+
+	if (_12h_mode) {
+		/* Convert to 24h mode */
+		if (pm_mode) {
+			if (t->tm_hour < 12)
+				t->tm_hour += 12;
+		} else if (t->tm_hour == 12)
+			t->tm_hour = 0;
+	}
+
+	/* Count the months starting from 0, not from 1 */
+	t->tm_mon--;
+
+	if (t->tm_year < 100) {
+		/* tm_year is the number of years since 1900 but the
+		 * RTC epoch is 2000.
+		 */
+		t->tm_year += 100;
+	}
+
+	/* Try to normalize the content of the tm structure */
+	time_t r = mktime(t);
+	int result;
+
+	if (r < 0)
+		result = EINVAL;
+	else {
+		rtc->boottime = r - uptime_get();
+		result = EOK;
+	}
+
+	fibril_mutex_unlock(&rtc->mutex);
+
+	return result;
+}
+
+/** Set the time in the RTC
+ *
+ * @param fun  The RTC function
+ * @param t    The time value to set
+ *
+ * @return  EOK or a negative error code
+ */
+static int
+rtc_time_set(ddf_fun_t *fun, struct tm *t)
+{
+	bool bcd_mode;
+	time_t norm_time;
+	time_t uptime;
+	int  reg_b;
+	int  reg_a;
+	int  epoch;
+	rtc_t *rtc = fun_rtc(fun);
+
+	/* Try to normalize the content of the tm structure */
+	if ((norm_time = mktime(t)) < 0)
+		return EINVAL;
+
+	uptime = uptime_get();
+	if (norm_time <= uptime) {
+		/* This is not acceptable */
+		return EINVAL;
+	}
+
+	fibril_mutex_lock(&rtc->mutex);
+
+	if (!is_battery_ok(rtc)) {
+		fibril_mutex_unlock(&rtc->mutex);
+		return EIO;
+	}
+
+	/* boottime must be recomputed */
+	rtc->boottime = 0;
+
+	/* Detect the RTC epoch */
+	if (rtc_register_read(rtc, RTC_YEAR) < 100)
+		epoch = 2000;
+	else
+		epoch = 1900;
+
+	if (epoch == 2000 && t->tm_year < 100) {
+		/* Can't set a year before the epoch */
+		fibril_mutex_unlock(&rtc->mutex);
+		return EINVAL;
+	}
+
+	t->tm_mon++; /* counts from 1, not from 0 */
+
+	reg_b = rtc_register_read(rtc, RTC_STATUS_B);
+
+	if (!(reg_b & RTC_B_24H)) {
+		/* Force 24h mode of operation */
+		reg_b |= RTC_B_24H;
+		rtc_register_write(rtc, RTC_STATUS_B, reg_b);
+	}
+
+	if (epoch == 2000) {
+		/* The RTC epoch is year 2000  but the tm_year
+		 * field counts years since 1900.
+		 */
+		t->tm_year -= 100;
+	}
+
+	/* Check if the rtc is working in bcd mode */
+	bcd_mode = !(reg_b & RTC_B_BCD);
+	if (bcd_mode) {
+		/* Convert the tm struct fields in BCD mode */
+		t->tm_sec  = bin2bcd(t->tm_sec);
+		t->tm_min  = bin2bcd(t->tm_min);
+		t->tm_hour = bin2bcd(t->tm_hour);
+		t->tm_mday = bin2bcd(t->tm_mday);
+		t->tm_mon  = bin2bcd(t->tm_mon);
+		t->tm_year = bin2bcd(t->tm_year);
+	}
+
+	/* Inhibit updates */
+	rtc_register_write(rtc, RTC_STATUS_B, reg_b | RTC_B_INH);
+
+	/* Write current time to RTC */
+	rtc_register_write(rtc, RTC_SEC, t->tm_sec);
+	rtc_register_write(rtc, RTC_MIN, t->tm_min);
+	rtc_register_write(rtc, RTC_HOUR, t->tm_hour);
+	rtc_register_write(rtc, RTC_DAY, t->tm_mday);
+	rtc_register_write(rtc, RTC_MON, t->tm_mon);
+	rtc_register_write(rtc, RTC_YEAR, t->tm_year);
+
+	/* Stop the clock */
+	reg_a = rtc_register_read(rtc, RTC_STATUS_A);
+	rtc_register_write(rtc, RTC_STATUS_A, RTC_A_CLK_STOP | reg_a);
+	
+	/* Enable updates */
+	rtc_register_write(rtc, RTC_STATUS_B, reg_b);
+	rtc_register_write(rtc, RTC_STATUS_A, reg_a);
+
+	fibril_mutex_unlock(&rtc->mutex);
+
+	return EOK;
+}
+
+/** Get the status of the real time clock battery
+ *
+ * @param fun    The RTC function
+ * @param status The status of the battery
+ *
+ * @return       EOK on success or a negative error code
+ */
+static int
+rtc_battery_status_get(ddf_fun_t *fun, battery_status_t *status)
+{
+	rtc_t *rtc = fun_rtc(fun);
+
+	fibril_mutex_lock(&rtc->mutex);
+	const bool batt_ok = is_battery_ok(rtc);
+	fibril_mutex_unlock(&rtc->mutex);
+
+	*status = batt_ok ? BATTERY_OK : BATTERY_LOW;
+
+	return EOK;
+}
+
+/** Check if the battery is working properly or not.
+ *  The caller already holds the rtc->mutex lock.
+ *
+ *  @param rtc   The RTC instance.
+ *
+ *  @return      true if the battery is ok, false otherwise.
+ */
+static bool
+is_battery_ok(rtc_t *rtc)
+{
+	return rtc_register_read(rtc, RTC_STATUS_D) & RTC_D_BATTERY_OK;
+}
+
+/** The dev_add callback of the rtc driver
+ *
+ * @param dev  The RTC device
+ *
+ * @return  EOK on success or a negative error code
+ */
+static int
+rtc_dev_add(ddf_dev_t *dev)
+{
+	rtc_t *rtc;
+	ddf_fun_t *fun = NULL;
+	int rc;
+	bool need_cleanup = false;
+
+	ddf_msg(LVL_DEBUG, "rtc_dev_add %s (handle = %d)",
+	    ddf_dev_get_name(dev), (int) ddf_dev_get_handle(dev));
+
+	rtc = ddf_dev_data_alloc(dev, sizeof(rtc_t));
+	if (!rtc)
+		return ENOMEM;
+
+	rtc->dev = dev;
+	fibril_mutex_initialize(&rtc->mutex);
+
+	rc = rtc_dev_initialize(rtc);
+	if (rc != EOK)
+		goto error;
+
+	need_cleanup = true;
+
+	if (!rtc_pio_enable(rtc)) {
+		rc = EADDRNOTAVAIL;
+		goto error;
+	}
+
+	fun = ddf_fun_create(dev, fun_exposed, "a");
+	if (!fun) {
+		ddf_msg(LVL_ERROR, "Failed creating function");
+		rc = ENOENT;
+		goto error;
+	}
+
+	ddf_fun_set_ops(fun, &rtc_dev_ops);
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding function");
+		goto error;
+	}
+
+	rtc->fun = fun;
+
+	ddf_fun_add_to_category(fun, "clock");
+
+	ddf_msg(LVL_NOTE, "Device %s successfully initialized",
+	    ddf_dev_get_name(dev));
+
+	return rc;
+
+error:
+	if (fun)
+		ddf_fun_destroy(fun);
+	if (need_cleanup)
+		rtc_dev_cleanup(rtc);
+	return rc;
+}
+
+/** The dev_remove callback for the rtc driver
+ *
+ * @param dev   The RTC device
+ *
+ * @return      EOK on success or a negative error code
+ */
+static int
+rtc_dev_remove(ddf_dev_t *dev)
+{
+	rtc_t *rtc = dev_rtc(dev);
+	int rc;
+
+	fibril_mutex_lock(&rtc->mutex);
+	if (rtc->clients_connected > 0) {
+		fibril_mutex_unlock(&rtc->mutex);
+		return EBUSY;
+	}
+
+	rtc->removed = true;
+	fibril_mutex_unlock(&rtc->mutex);
+
+	rc = rtc_fun_offline(rtc->fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to offline function");
+		return rc;
+	}
+
+	rc = ddf_fun_unbind(rtc->fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to unbind function");
+		return rc;
+	}
+
+	ddf_fun_destroy(rtc->fun);
+	rtc_dev_cleanup(rtc);
+
+	return rc;
+}
+
+/** Open the device
+ *
+ * @param fun   The function node
+ *
+ * @return  EOK on success or a negative error code
+ */
+static int
+rtc_open(ddf_fun_t *fun)
+{
+	int rc;
+	rtc_t *rtc = fun_rtc(fun);
+
+	fibril_mutex_lock(&rtc->mutex);
+
+	if (rtc->removed)
+		rc = ENXIO;
+	else {
+		rc = EOK;
+		rtc->clients_connected++;
+	}
+
+	fibril_mutex_unlock(&rtc->mutex);
+	return rc;
+}
+
+/** Close the device
+ *
+ * @param fun  The function node
+ */
+static void
+rtc_close(ddf_fun_t *fun)
+{
+	rtc_t *rtc = fun_rtc(fun);
+
+	fibril_mutex_lock(&rtc->mutex);
+
+	rtc->clients_connected--;
+	assert(rtc->clients_connected >= 0);
+
+	fibril_mutex_unlock(&rtc->mutex);
+}
+
+/** Convert from BCD mode to binary mode
+ *
+ * @param bcd   The number in BCD format to convert
+ *
+ * @return      The converted value
+ */
+static unsigned 
+bcd2bin(unsigned bcd)
+{
+	return ((bcd & 0xF0) >> 1) + ((bcd & 0xF0) >> 3) + (bcd & 0xf);
+}
+
+/** Convert from binary mode to BCD mode
+ *
+ * @param bcd   The number in binary mode to convert
+ *
+ * @return      The converted value
+ */
+static unsigned
+bin2bcd(unsigned binary)
+{
+	return ((binary / 10) << 4) + (binary % 10);
+}
+
+static time_t
+uptime_get(void)
+{
+	struct timeval tv;
+
+	getuptime(&tv);
+
+	return tv.tv_sec;
+}
+
+static int
+rtc_fun_online(ddf_fun_t *fun)
+{
+	int rc;
+
+	ddf_msg(LVL_DEBUG, "rtc_fun_online()");
+
+	rc = ddf_fun_online(fun);
+	if (rc == EOK)
+		ddf_fun_add_to_category(fun, "clock");
+
+	return rc;
+}
+
+static int
+rtc_fun_offline(ddf_fun_t *fun)
+{
+	ddf_msg(LVL_DEBUG, "rtc_fun_offline()");
+	return ddf_fun_offline(fun);
+}
+
+int
+main(int argc, char **argv)
+{
+	printf(NAME ": HelenOS RTC driver\n");
+	rtc_init();
+	return ddf_driver_main(&rtc_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/time/cmos-rtc/cmos-rtc.ma
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-rtc.ma	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/drv/time/cmos-rtc/cmos-rtc.ma	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,1 @@
+100 isa/cmos-rtc
Index: uspace/lib/bithenge/Makefile
===================================================================
--- uspace/lib/bithenge/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2012 Sean Bartell
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libbithenge
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -D__HELENOS__ -Iinclude
+
+SOURCES = \
+	src/helenos/block.c \
+	src/blob.c \
+	src/compound.c \
+	src/expression.c \
+	src/file.c \
+	src/print.c \
+	src/script.c \
+	src/sequence.c \
+	src/source.c \
+	src/transform.c \
+	src/tree.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/bithenge/Makefile.linux
===================================================================
--- uspace/lib/bithenge/Makefile.linux	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/Makefile.linux	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,65 @@
+#
+# Copyright (c) 2012 Sean Bartell
+# 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.
+#
+
+CFLAGS += -fexec-charset=UTF-8 -finput-charset=UTF-8 -std=gnu99 -pipe
+CFLAGS += -Wall -Wextra -Werror -Wno-clobbered -Wno-unused-parameter -Wmissing-prototypes -Werror-implicit-function-declaration -Wwrite-strings
+CFLAGS += -ftrapv
+CFLAGS += -g
+CFLAGS += -Iinclude
+
+LIBRARY = libbithenge.a
+
+SOURCES = \
+	src/blob.c \
+	src/compound.c \
+	src/expression.c \
+	src/file.c \
+	src/print.c \
+	src/script.c \
+	src/sequence.c \
+	src/source.c \
+	src/transform.c \
+	src/tree.c
+
+ifdef COVERAGE
+	CFLAGS += -fprofile-arcs -ftest-coverage
+endif
+
+ifdef FAILURE
+	CFLAGS += -DBITHENGE_FAILURE_ENABLE=1
+	SOURCES += src/failure.c
+endif
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+$(LIBRARY): $(OBJECTS)
+	$(AR) rcs $@ $^
+
+clean:
+	find . -name '*.o' -follow -exec rm \{\} \;
+	rm -f $(LIBRARY)
Index: uspace/lib/bithenge/include/bithenge/blob.h
===================================================================
--- uspace/lib/bithenge/include/bithenge/blob.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/include/bithenge/blob.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Raw binary blobs.
+ */
+
+#ifndef BITHENGE_BLOB_H_
+#define BITHENGE_BLOB_H_
+
+#include <sys/types.h>
+#include <errno.h>
+#include "tree.h"
+
+/** A blob of raw binary data.
+ * @implements bithenge_node_t */
+typedef struct {
+	/** @privatesection */
+	struct bithenge_node_t base;
+} bithenge_blob_t;
+
+/** Operations providing random access to binary data.
+ * @todo Should these be thread-safe? */
+typedef struct bithenge_random_access_blob_ops_t {
+	/** @copydoc bithenge_blob_t::bithenge_blob_size */
+	int (*size)(bithenge_blob_t *self, aoff64_t *size);
+	/** @copydoc bithenge_blob_t::bithenge_blob_read */
+	int (*read)(bithenge_blob_t *self, aoff64_t offset, char *buffer,
+	    aoff64_t *size);
+	/** @copydoc bithenge_blob_t::bithenge_blob_read_bits */
+	int (*read_bits)(bithenge_blob_t *self, aoff64_t offset, char *buffer,
+	    aoff64_t *size, bool little_endian);
+	/** Destroy the blob.
+	 * @param blob The blob. */
+	void (*destroy)(bithenge_blob_t *self);
+} bithenge_random_access_blob_ops_t;
+
+/** A blob built from an object that supports only sequential reading.
+ * @implements bithenge_blob_t */
+typedef struct {
+	/** @privatesection */
+	/** The base random-access blob. */
+	bithenge_blob_t base;
+	/** Operations providing sequential access. */
+	const struct bithenge_sequential_blob_ops_t *ops;
+	/** Buffer containing all data read. */
+	char *buffer;
+	/** Size of buffer. */
+	aoff64_t buffer_size;
+	/** Amount of data actually in buffer. */
+	aoff64_t data_size;
+} bithenge_sequential_blob_t;
+
+/** Operations providing sequential access to binary data.
+ * @memberof bithenge_sequential_blob_t */
+typedef struct bithenge_sequential_blob_ops_t {
+
+	/** Get the total size of the blob. If the total size cannot be
+	 * determined easily, this field may be null or return an error,
+	 * forcing the entire blob to be read to determine its size.
+	 *
+	 * @memberof bithenge_blob_t
+	 * @param self The blob.
+	 * @param[out] size Total size of the blob.
+	 * @return EOK on success or an error code from errno.h.
+	 */
+	int (*size)(bithenge_sequential_blob_t *self, aoff64_t *size);
+
+	/** Read the next part of the blob. If the requested data extends
+	 * beyond the end of the blob, the data up until the end of the blob
+	 * will be read.
+	 *
+	 * @param self The blob.
+	 * @param[out] buffer Buffer to read into. If an error occurs, the contents are
+	 * undefined.
+	 * @param[in,out] size Number of bytes to read; may be 0. If not enough
+	 * data is left in the blob, the actual number of bytes read should be
+	 * stored here. If an error occurs, the contents are undefined.
+	 * @return EOK on success or an error code from errno.h.
+	 */
+	int (*read)(bithenge_sequential_blob_t *self, char *buffer,
+	    aoff64_t *size);
+
+	/** Destroy the blob.
+	 * @param self The blob. */
+	void (*destroy)(bithenge_sequential_blob_t *self);
+} bithenge_sequential_blob_ops_t;
+
+/** Get the total size of the blob.
+ *
+ * @memberof bithenge_blob_t
+ * @param self The blob.
+ * @param[out] size Total size of the blob.
+ * @return EOK on success or an error code from errno.h.
+ */
+static inline int bithenge_blob_size(bithenge_blob_t *self, aoff64_t *size)
+{
+	assert(self);
+	assert(self->base.blob_ops);
+	return self->base.blob_ops->size(self, size);
+}
+
+/** Read part of the blob. If the requested data extends beyond the end of the
+ * blob, the data up until the end of the blob will be read. If the offset is
+ * beyond the end of the blob, even if the size is zero, an error will be
+ * returned.
+ *
+ * @memberof bithenge_blob_t
+ * @param self The blob.
+ * @param offset Byte offset within the blob.
+ * @param[out] buffer Buffer to read into. If an error occurs, the contents are
+ * undefined.
+ * @param[in,out] size Number of bytes to read; may be 0. If the requested
+ * range extends beyond the end of the blob, the actual number of bytes read
+ * should be stored here. If an error occurs, the contents are undefined.
+ * @return EOK on success or an error code from errno.h.
+ */
+static inline int bithenge_blob_read(bithenge_blob_t *self, aoff64_t offset,
+    char *buffer, aoff64_t *size)
+{
+	assert(self);
+	assert(self->base.blob_ops);
+	if (!self->base.blob_ops->read)
+		return EINVAL;
+	return self->base.blob_ops->read(self, offset, buffer, size);
+}
+
+/** Read part of the bit blob. If the requested data extends beyond the end of
+ * the blob, the data up until the end of the blob will be read. If the offset
+ * is beyond the end of the blob, even if the size is zero, an error will be
+ * returned.
+ *
+ * @memberof bithenge_blob_t
+ * @param self The blob.
+ * @param offset Byte offset within the blob.
+ * @param[out] buffer Buffer to read into. If an error occurs, the contents are
+ * undefined.
+ * @param[in,out] size Number of bytes to read; may be 0. If the requested
+ * range extends beyond the end of the blob, the actual number of bytes read
+ * should be stored here. If an error occurs, the contents are undefined.
+ * @param little_endian If true, bytes will be filled starting at the least
+ * significant bit; otherwise, they will be filled starting at the most
+ * significant bit.
+ * @return EOK on success or an error code from errno.h.
+ */
+static inline int bithenge_blob_read_bits(bithenge_blob_t *self,
+    aoff64_t offset, char *buffer, aoff64_t *size, bool little_endian)
+{
+	assert(self);
+	assert(self->base.blob_ops);
+	if (!self->base.blob_ops->read_bits)
+		return EINVAL;
+	return self->base.blob_ops->read_bits(self, offset, buffer, size,
+	    little_endian);
+}
+
+/** Check whether the blob is empty.
+ *
+ * @memberof bithenge_blob_t
+ * @param self The blob.
+ * @param[out] out Holds whether the blob is empty.
+ * @return EOK on success or an error code from errno.h. */
+static inline int bithenge_blob_empty(bithenge_blob_t *self, bool *out)
+{
+	assert(self);
+	assert(self->base.blob_ops);
+	aoff64_t size;
+	int rc = bithenge_blob_size(self, &size);
+	*out = size == 0;
+	return rc;
+}
+
+/** Cast a blob node to a generic node.
+ * @memberof bithenge_blob_t
+ * @param blob The blob to cast.
+ * @return The blob node as a generic node. */
+static inline bithenge_node_t *bithenge_blob_as_node(bithenge_blob_t *blob)
+{
+	return &blob->base;
+}
+
+/** Cast a generic node to a blob node.
+ * @memberof bithenge_blob_t
+ * @param node The node to cast, which must be a blob node.
+ * @return The generic node as a blob node. */
+static inline bithenge_blob_t *bithenge_node_as_blob(bithenge_node_t *node)
+{
+	assert(node->type == BITHENGE_NODE_BLOB);
+	return (bithenge_blob_t *)node;
+}
+
+/** Increment a blob's reference count.
+ * @param blob The blob to reference. */
+static inline void bithenge_blob_inc_ref(bithenge_blob_t *blob)
+{
+	bithenge_node_inc_ref(bithenge_blob_as_node(blob));
+}
+
+/** Decrement a blob's reference count.
+ * @param blob The blob to dereference, or NULL. */
+static inline void bithenge_blob_dec_ref(bithenge_blob_t *blob)
+{
+	if (blob)
+		bithenge_node_dec_ref(bithenge_blob_as_node(blob));
+}
+
+/** @memberof bithenge_blob_t */
+int bithenge_init_random_access_blob(bithenge_blob_t *,
+    const bithenge_random_access_blob_ops_t *);
+/** @memberof bithenge_sequential_blob_t */
+int bithenge_init_sequential_blob(bithenge_sequential_blob_t *,
+    const bithenge_sequential_blob_ops_t *);
+/** @memberof bithenge_blob_t */
+int bithenge_new_blob_from_data(bithenge_node_t **, const void *, size_t);
+/** @memberof bithenge_blob_t */
+int bithenge_new_blob_from_buffer(bithenge_node_t **, const void *, size_t,
+    bool);
+int bithenge_new_offset_blob(bithenge_node_t **, bithenge_blob_t *, aoff64_t);
+int bithenge_new_subblob(bithenge_node_t **, bithenge_blob_t *, aoff64_t,
+    aoff64_t);
+/** @memberof bithenge_blob_t */
+int bithenge_blob_equal(bool *, bithenge_blob_t *, bithenge_blob_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/bithenge/include/bithenge/compound.h
===================================================================
--- uspace/lib/bithenge/include/bithenge/compound.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/include/bithenge/compound.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Compound transforms.
+ */
+
+#ifndef BITHENGE_COMPOUND_H_
+#define BITHENGE_COMPOUND_H_
+
+#include "expression.h"
+#include "transform.h"
+
+int bithenge_new_composed_transform(bithenge_transform_t **,
+    bithenge_transform_t **, size_t);
+int bithenge_if_transform(bithenge_transform_t **, bithenge_expression_t *,
+    bithenge_transform_t *, bithenge_transform_t *);
+int bithenge_partial_transform(bithenge_transform_t **,
+    bithenge_transform_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/bithenge/include/bithenge/expression.h
===================================================================
--- uspace/lib/bithenge/include/bithenge/expression.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/include/bithenge/expression.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Expressions.
+ */
+
+#ifndef BITHENGE_EXPRESSION_H_
+#define BITHENGE_EXPRESSION_H_
+
+#include "blob.h"
+#include "transform.h"
+#include "tree.h"
+
+/** An expression that calculates a value given a scope. */
+typedef struct {
+	/** @privatesection */
+	const struct bithenge_expression_ops *ops;
+	unsigned int refs;
+} bithenge_expression_t;
+
+/** Operations provided by an expression. */
+typedef struct bithenge_expression_ops {
+	/** @copydoc bithenge_expression_t::bithenge_expression_evaluate */
+	int (*evaluate)(bithenge_expression_t *self, bithenge_scope_t *scope,
+	    bithenge_node_t **out);
+	/** Destroy the expression.
+	 * @param self The expression. */
+	void (*destroy)(bithenge_expression_t *self);
+} bithenge_expression_ops_t;
+
+/** Increment an expression's reference count.
+ * @param self The expression to reference. */
+static inline void bithenge_expression_inc_ref(bithenge_expression_t *self)
+{
+	assert(self);
+	self->refs++;
+}
+
+/** Decrement an expression's reference count and free it if appropriate.
+ * @param self The expression to dereference, or NULL. */
+static inline void bithenge_expression_dec_ref(bithenge_expression_t *self)
+{
+	if (!self)
+		return;
+	assert(self->ops);
+	assert(self->refs > 0);
+	if (--self->refs == 0)
+		self->ops->destroy(self);
+}
+
+/** Evaluate an expression. Takes ownership of nothing.
+ * @memberof bithenge_expression_t
+ * @param self The expression.
+ * @param scope The scope.
+ * @param[out] out Where the output tree will be stored.
+ * @return EOK on success or an error code from errno.h. */
+static inline int bithenge_expression_evaluate(bithenge_expression_t *self,
+    bithenge_scope_t *scope, bithenge_node_t **out)
+{
+	assert(self);
+	assert(self->ops);
+	return self->ops->evaluate(self, scope, out);
+}
+
+/** The binary operators supported by @a bithenge_binary_expression(). */
+typedef enum {
+	BITHENGE_EXPRESSION_INVALID_BINARY_OP,
+
+	BITHENGE_EXPRESSION_ADD,
+	BITHENGE_EXPRESSION_SUBTRACT,
+	BITHENGE_EXPRESSION_MULTIPLY,
+	BITHENGE_EXPRESSION_INTEGER_DIVIDE,
+	BITHENGE_EXPRESSION_MODULO,
+
+	BITHENGE_EXPRESSION_LESS_THAN,
+	BITHENGE_EXPRESSION_GREATER_THAN,
+	BITHENGE_EXPRESSION_LESS_THAN_OR_EQUAL,
+	BITHENGE_EXPRESSION_GREATER_THAN_OR_EQUAL,
+	BITHENGE_EXPRESSION_EQUALS,
+	BITHENGE_EXPRESSION_NOT_EQUALS,
+
+	BITHENGE_EXPRESSION_AND,
+	BITHENGE_EXPRESSION_OR,
+
+	BITHENGE_EXPRESSION_MEMBER,
+	BITHENGE_EXPRESSION_CONCAT,
+} bithenge_binary_op_t;
+
+int bithenge_init_expression(bithenge_expression_t *,
+    const bithenge_expression_ops_t *);
+int bithenge_binary_expression(bithenge_expression_t **, bithenge_binary_op_t,
+    bithenge_expression_t *, bithenge_expression_t *);
+int bithenge_in_node_expression(bithenge_expression_t **);
+int bithenge_current_node_expression(bithenge_expression_t **);
+int bithenge_param_expression(bithenge_expression_t **, int);
+int bithenge_const_expression(bithenge_expression_t **, bithenge_node_t *);
+int bithenge_scope_member_expression(bithenge_expression_t **,
+    bithenge_node_t *);
+int bithenge_subblob_expression(bithenge_expression_t **,
+    bithenge_expression_t *, bithenge_expression_t *, bithenge_expression_t *,
+    bool);
+int bithenge_param_wrapper(bithenge_transform_t **, bithenge_transform_t *,
+    bithenge_expression_t **);
+int bithenge_expression_transform(bithenge_transform_t **,
+    bithenge_expression_t *);
+int bithenge_inputless_transform(bithenge_transform_t **,
+    bithenge_expression_t *);
+
+int bithenge_concat_blob(bithenge_node_t **, bithenge_blob_t *,
+    bithenge_blob_t *);
+int bithenge_concat_blob_lazy(bithenge_node_t **, bithenge_blob_t *,
+    bithenge_expression_t *, bithenge_scope_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/bithenge/include/bithenge/file.h
===================================================================
--- uspace/lib/bithenge/include/bithenge/file.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/include/bithenge/file.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Access files as blobs.
+ */
+
+#ifndef BITHENGE_FILE_H_
+#define BITHENGE_FILE_H_
+
+#include <stdio.h>
+#include "blob.h"
+
+int bithenge_new_file_blob(bithenge_node_t **, const char *);
+int bithenge_new_file_blob_from_fd(bithenge_node_t **, int);
+int bithenge_new_file_blob_from_file(bithenge_node_t **, FILE *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/bithenge/include/bithenge/os.h
===================================================================
--- uspace/lib/bithenge/include/bithenge/os.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/include/bithenge/os.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * Copyright (c) 2012 Vojtech Horky
+ * 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.
+ */
+
+#ifndef BITHENGE_OS_H_
+#define BITHENGE_OS_H_
+
+
+#ifdef __HELENOS__
+typedef int64_t bithenge_int_t;
+#define BITHENGE_PRId PRId64
+
+#else
+/* Assuming GNU/Linux system. */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#define BITHENGE_PRId PRIdMAX
+typedef intmax_t bithenge_int_t;
+typedef uint64_t aoff64_t;
+#define EOK 0
+
+#endif
+
+#endif
Index: uspace/lib/bithenge/include/bithenge/print.h
===================================================================
--- uspace/lib/bithenge/include/bithenge/print.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/include/bithenge/print.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Write a tree as JSON or other text formats.
+ */
+
+#ifndef BITHENGE_PRINT_H_
+#define BITHENGE_PRINT_H_
+
+#include "tree.h"
+
+/** Specifies the format to be used when printing. */
+typedef enum {
+	/** Print a Python value. Note that internal nodes will be represented
+	 * as unordered dictionaries. */
+	BITHENGE_PRINT_PYTHON,
+	/** Print JSON. Due to the limitations of JSON, type information may be
+	 * lost. */
+	BITHENGE_PRINT_JSON,
+} bithenge_print_type_t;
+
+int bithenge_print_node(bithenge_print_type_t, bithenge_node_t *);
+int bithenge_print_node_to_string(char **, size_t *, bithenge_print_type_t,
+    bithenge_node_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/bithenge/include/bithenge/script.h
===================================================================
--- uspace/lib/bithenge/include/bithenge/script.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/include/bithenge/script.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Script parsing.
+ */
+
+#ifndef BITHENGE_SCRIPT_H_
+#define BITHENGE_SCRIPT_H_
+
+#include "transform.h"
+
+int bithenge_parse_script(const char *, bithenge_transform_t **);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/bithenge/include/bithenge/sequence.h
===================================================================
--- uspace/lib/bithenge/include/bithenge/sequence.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/include/bithenge/sequence.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Sequence transforms.
+ */
+
+#ifndef BITHENGE_SEQUENCE_H_
+#define BITHENGE_SEQUENCE_H_
+
+#include "transform.h"
+
+int bithenge_new_struct(bithenge_transform_t **,
+    bithenge_named_transform_t *);
+int bithenge_repeat_transform(bithenge_transform_t **, bithenge_transform_t *,
+    bithenge_expression_t *);
+int bithenge_do_while_transform(bithenge_transform_t **,
+    bithenge_transform_t *, bithenge_expression_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/bithenge/include/bithenge/source.h
===================================================================
--- uspace/lib/bithenge/include/bithenge/source.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/include/bithenge/source.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Provide various external sources of data.
+ */
+
+#ifndef BITHENGE_SOURCE_H_
+#define BITHENGE_SOURCE_H_
+
+#include "tree.h"
+
+int bithenge_node_from_source(bithenge_node_t **, const char *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/bithenge/include/bithenge/transform.h
===================================================================
--- uspace/lib/bithenge/include/bithenge/transform.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/include/bithenge/transform.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Transforms.
+ */
+
+#ifndef BITHENGE_TRANSFORM_H_
+#define BITHENGE_TRANSFORM_H_
+
+#include "blob.h"
+#include "tree.h"
+
+/** A transform that creates a new tree from an old tree. */
+typedef struct {
+	/** @privatesection */
+	const struct bithenge_transform_ops *ops;
+	unsigned int refs;
+	int num_params;
+} bithenge_transform_t;
+
+/** Context and parameters used when applying transforms. */
+typedef struct bithenge_scope {
+	/** @privatesection */
+	unsigned int refs;
+	struct bithenge_scope *outer;
+	char *error;
+	bool barrier;
+	int num_params;
+	bithenge_node_t **params;
+	bithenge_node_t *current_node;
+	bithenge_node_t *in_node;
+} bithenge_scope_t;
+
+/** Increment a scope's reference count.
+ * @memberof bithenge_scope_t
+ * @param self The scope to reference. */
+static inline void bithenge_scope_inc_ref(bithenge_scope_t *self)
+{
+	assert(self);
+	self->refs++;
+}
+
+/** Operations that may be provided by a transform. All transforms must provide
+ * apply and/or prefix_apply. To be used in struct transforms and repeat
+ * transforms, transforms must provide prefix_length and/or prefix_apply. */
+typedef struct bithenge_transform_ops {
+	/** @copydoc bithenge_transform_t::bithenge_transform_apply */
+	int (*apply)(bithenge_transform_t *self, bithenge_scope_t *scope,
+	    bithenge_node_t *in, bithenge_node_t **out);
+	/** @copydoc bithenge_transform_t::bithenge_transform_prefix_length */
+	int (*prefix_length)(bithenge_transform_t *self,
+	    bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out);
+	/** @copydoc bithenge_transform_t::bithenge_transform_prefix_apply */
+	int (*prefix_apply)(bithenge_transform_t *self,
+	    bithenge_scope_t *scope, bithenge_blob_t *blob,
+	    bithenge_node_t **out_node, aoff64_t *out_size);
+	/** Destroy the transform.
+	 * @param self The transform. */
+	void (*destroy)(bithenge_transform_t *self);
+} bithenge_transform_ops_t;
+
+/** Get the number of parameters required by a transform. This number is used
+ * by the parser and param-wrapper. Takes ownership of nothing.
+ * @param self The transform.
+ * @return The number of parameters required. */
+static inline int bithenge_transform_num_params(bithenge_transform_t *self)
+{
+	assert(self);
+	return self->num_params;
+}
+
+/** Increment a transform's reference count.
+ * @param self The transform to reference. */
+static inline void bithenge_transform_inc_ref(bithenge_transform_t *self)
+{
+	assert(self);
+	self->refs++;
+}
+
+/** Decrement a transform's reference count and free it if appropriate.
+ * @param self The transform to dereference, or NULL. */
+static inline void bithenge_transform_dec_ref(bithenge_transform_t *self)
+{
+	if (!self)
+		return;
+	assert(self->ops);
+	assert(self->refs > 0);
+	if (--self->refs == 0)
+		self->ops->destroy(self);
+}
+
+/** A transform with a name. */
+typedef struct {
+	/** The transform's name. */
+	const char *name;
+	/** The transform. */
+	bithenge_transform_t *transform;
+} bithenge_named_transform_t;
+
+/** Transform that decodes an 8-bit unsigned integer */
+extern bithenge_transform_t bithenge_uint8_transform;
+/** Transform that decodes a 16-bit little-endian unsigned integer */
+extern bithenge_transform_t bithenge_uint16le_transform;
+/** Transform that decodes a 16-bit big-endian unsigned integer */
+extern bithenge_transform_t bithenge_uint16be_transform;
+/** Transform that decodes a 32-bit little-endian unsigned integer */
+extern bithenge_transform_t bithenge_uint32le_transform;
+/** Transform that decodes a 32-bit big-endian unsigned integer */
+extern bithenge_transform_t bithenge_uint32be_transform;
+/** Transform that decodes a 64-bit little-endian unsigned integer */
+extern bithenge_transform_t bithenge_uint64le_transform;
+/** Transform that decodes a 64-bit big-endian unsigned integer */
+extern bithenge_transform_t bithenge_uint64be_transform;
+
+/** @cond */
+extern bithenge_transform_t bithenge_ascii_transform;
+extern bithenge_transform_t bithenge_bit_transform;
+extern bithenge_transform_t bithenge_bits_be_transform;
+extern bithenge_transform_t bithenge_bits_le_transform;
+extern bithenge_transform_t bithenge_invalid_transform;
+extern bithenge_transform_t bithenge_known_length_transform;
+extern bithenge_transform_t bithenge_nonzero_boolean_transform;
+extern bithenge_transform_t bithenge_uint_le_transform;
+extern bithenge_transform_t bithenge_uint_be_transform;
+extern bithenge_transform_t bithenge_zero_terminated_transform;
+extern bithenge_named_transform_t *bithenge_primitive_transforms;
+/** @endcond */
+
+/** @memberof bithenge_transform_t */
+int bithenge_init_transform(bithenge_transform_t *,
+    const bithenge_transform_ops_t *, int);
+/** @memberof bithenge_transform_t */
+int bithenge_transform_apply(bithenge_transform_t *, bithenge_scope_t *,
+    bithenge_node_t *, bithenge_node_t **);
+/** @memberof bithenge_transform_t */
+int bithenge_transform_prefix_length(bithenge_transform_t *,
+    bithenge_scope_t *, bithenge_blob_t *, aoff64_t *);
+/** @memberof bithenge_transform_t */
+int bithenge_transform_prefix_apply(bithenge_transform_t *, bithenge_scope_t *,
+    bithenge_blob_t *, bithenge_node_t **, aoff64_t *);
+int bithenge_new_barrier_transform(bithenge_transform_t **, int);
+int bithenge_barrier_transform_set_subtransform(bithenge_transform_t *,
+    bithenge_transform_t *);
+
+/** @memberof bithenge_scope_t */
+int bithenge_scope_new(bithenge_scope_t **, bithenge_scope_t *);
+/** @memberof bithenge_scope_t */
+void bithenge_scope_dec_ref(bithenge_scope_t *);
+/** @memberof bithenge_scope_t */
+bithenge_scope_t *bithenge_scope_outer(bithenge_scope_t *);
+/** @memberof bithenge_scope_t */
+const char *bithenge_scope_get_error(bithenge_scope_t *);
+/** @memberof bithenge_scope_t */
+int bithenge_scope_error(bithenge_scope_t *, const char *, ...);
+/** @memberof bithenge_scope_t */
+bithenge_node_t *bithenge_scope_get_current_node(bithenge_scope_t *);
+/** @memberof bithenge_scope_t */
+void bithenge_scope_set_current_node(bithenge_scope_t *, bithenge_node_t *);
+/** @memberof bithenge_scope_t */
+bithenge_node_t *bithenge_scope_in_node(bithenge_scope_t *);
+/** @memberof bithenge_scope_t */
+void bithenge_scope_set_in_node(bithenge_scope_t *, bithenge_node_t *);
+/** @memberof bithenge_scope_t */
+void bithenge_scope_set_barrier(bithenge_scope_t *);
+/** @memberof bithenge_scope_t */
+bool bithenge_scope_is_barrier(bithenge_scope_t *);
+/** @memberof bithenge_scope_t */
+int bithenge_scope_alloc_params(bithenge_scope_t *, int);
+/** @memberof bithenge_scope_t */
+int bithenge_scope_set_param(bithenge_scope_t *, int, bithenge_node_t *);
+/** @memberof bithenge_scope_t */
+int bithenge_scope_get_param(bithenge_scope_t *, int, bithenge_node_t **);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/bithenge/include/bithenge/tree.h
===================================================================
--- uspace/lib/bithenge/include/bithenge/tree.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/include/bithenge/tree.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Trees and nodes.
+ */
+
+#ifndef BITHENGE_TREE_H_
+#define BITHENGE_TREE_H_
+
+#include <assert.h>
+#include <sys/types.h>
+#include "os.h"
+
+/** Indicates the type of a tree node. */
+typedef enum {
+	/** An internal node with labelled edges to other nodes. */
+	BITHENGE_NODE_INTERNAL = 1,
+	/** A leaf node holding a boolean value. */
+	BITHENGE_NODE_BOOLEAN,
+	/** A leaf node holding an integer. */
+	BITHENGE_NODE_INTEGER,
+	/** A leaf node holding a string. */
+	BITHENGE_NODE_STRING,
+	/** A leaf node holding a binary blob. */
+	BITHENGE_NODE_BLOB,
+} bithenge_node_type_t;
+
+/** A tree node. It can have any of the types in @a bithenge_node_type_t. */
+typedef struct bithenge_node_t {
+	/** @privatesection */
+	bithenge_node_type_t type;
+	unsigned int refs;
+	union {
+		/** @privatesection */
+		const struct bithenge_internal_node_ops_t *internal_ops;
+		bool boolean_value;
+		bithenge_int_t integer_value;
+		struct {
+			/** @privatesection */
+			const char *ptr;
+			bool needs_free;
+		} string_value;
+		const struct bithenge_random_access_blob_ops_t *blob_ops;
+	};
+} bithenge_node_t;
+
+/** A callback function used to iterate over a node's children. It takes
+ * ownership of a reference to both the key and the value.
+ * @memberof bithenge_node_t
+ * @param key The key.
+ * @param value The value.
+ * @param data Data provided to @a bithenge_node_t::bithenge_node_for_each.
+ * @return EOK on success or an error code from errno.h. */
+typedef int (*bithenge_for_each_func_t)(bithenge_node_t *key, bithenge_node_t *value, void *data);
+
+/** Operations providing access to an internal node. */
+typedef struct bithenge_internal_node_ops_t {
+	/** @copydoc bithenge_node_t::bithenge_node_for_each */
+	int (*for_each)(bithenge_node_t *self, bithenge_for_each_func_t func, void *data);
+	/** @copydoc bithenge_node_t::bithenge_node_get */
+	int (*get)(bithenge_node_t *self, bithenge_node_t *key,
+	    bithenge_node_t **out);
+	/** Destroys the internal node.
+	 * @param self The node to destroy. */
+	void (*destroy)(bithenge_node_t *self);
+} bithenge_internal_node_ops_t;
+
+/** Find the type of a node.
+ * @memberof bithenge_node_t
+ * @param node The node.
+ * @return The type of the node. */
+static inline bithenge_node_type_t bithenge_node_type(const bithenge_node_t *node)
+{
+	return node->type;
+}
+
+/** Increment a node's reference count.
+ * @memberof bithenge_node_t
+ * @param node The node to reference. */
+static inline void bithenge_node_inc_ref(bithenge_node_t *node)
+{
+	assert(node);
+	node->refs++;
+}
+
+/** @memberof bithenge_node_t */
+void bithenge_node_dec_ref(bithenge_node_t *node);
+
+/** Iterate over a node's children.
+ * @memberof bithenge_node_t
+ * @param self The internal node to iterate over.
+ * @param func The callback function.
+ * @param data Data to provide to the callback function.
+ * @return EOK on success or an error code from errno.h. */
+static inline int bithenge_node_for_each(bithenge_node_t *self,
+    bithenge_for_each_func_t func, void *data)
+{
+	assert(self->type == BITHENGE_NODE_INTERNAL);
+	return self->internal_ops->for_each(self, func, data);
+}
+
+/** @memberof bithenge_node_t */
+int bithenge_node_get(bithenge_node_t *, bithenge_node_t *,
+    bithenge_node_t **);
+
+/** Get the value of a boolean node.
+ * @memberof bithenge_node_t
+ * @param self The boolean node.
+ * @return The node's value. */
+static inline bool bithenge_boolean_node_value(bithenge_node_t *self)
+{
+	assert(self->type == BITHENGE_NODE_BOOLEAN);
+	return self->boolean_value;
+}
+
+/** Get the value of an integer node.
+ * @memberof bithenge_node_t
+ * @param self The integer node.
+ * @return The node's value. */
+static inline bithenge_int_t bithenge_integer_node_value(bithenge_node_t *self)
+{
+	assert(self->type == BITHENGE_NODE_INTEGER);
+	return self->integer_value;
+}
+
+/** Get the value of an string node.
+ * @memberof bithenge_node_t
+ * @param self The string node.
+ * @return The node's value. */
+static inline const char *bithenge_string_node_value(bithenge_node_t *self)
+{
+	assert(self->type == BITHENGE_NODE_STRING);
+	return self->string_value.ptr;
+}
+
+/** @memberof bithenge_node_t */
+int bithenge_init_internal_node(bithenge_node_t *,
+    const bithenge_internal_node_ops_t *);
+/** @memberof bithenge_node_t */
+int bithenge_new_empty_internal_node(bithenge_node_t **);
+/** @memberof bithenge_node_t */
+int bithenge_new_simple_internal_node(bithenge_node_t **, bithenge_node_t **,
+    bithenge_int_t, bool needs_free);
+/** @memberof bithenge_node_t */
+int bithenge_new_boolean_node(bithenge_node_t **, bool);
+/** @memberof bithenge_node_t */
+int bithenge_new_integer_node(bithenge_node_t **, bithenge_int_t);
+/** @memberof bithenge_node_t */
+int bithenge_new_string_node(bithenge_node_t **, const char *, bool);
+/** @memberof bithenge_node_t */
+int bithenge_node_equal(bool *, bithenge_node_t *, bithenge_node_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/bithenge/src/blob.c
===================================================================
--- uspace/lib/bithenge/src/blob.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/blob.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Raw binary blobs.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "common.h"
+#include <bithenge/blob.h>
+#include <bithenge/tree.h>
+
+/** Initialize a random access blob.
+ * @memberof bithenge_blob_t
+ * @param[out] blob The blob to initialize.
+ * @param[in] ops Operations providing random access support. This pointer must
+ * be valid until the blob is destroyed.
+ * @return EOK on success or an error code from errno.h.
+ */
+int bithenge_init_random_access_blob(bithenge_blob_t *blob,
+    const bithenge_random_access_blob_ops_t *ops)
+{
+	assert(blob);
+	assert(ops);
+	assert(ops->destroy);
+	assert(ops->read || ops->read_bits);
+	assert(ops->size);
+
+	if (bithenge_should_fail())
+		return ENOMEM;
+
+	blob->base.type = BITHENGE_NODE_BLOB;
+	blob->base.refs = 1;
+	blob->base.blob_ops = ops;
+	return EOK;
+}
+
+static int sequential_buffer(bithenge_sequential_blob_t *blob, aoff64_t end)
+{
+	bool need_realloc = false;
+	while (end > blob->buffer_size) {
+		blob->buffer_size = max(4096, 2 * blob->buffer_size);
+		need_realloc = true;
+	}
+	if (need_realloc) {
+		char *buffer = realloc(blob->buffer, blob->buffer_size);
+		if (!buffer)
+			return ENOMEM;
+		blob->buffer = buffer;
+	}
+	aoff64_t size = end - blob->data_size;
+	int rc = blob->ops->read(blob, blob->buffer + blob->data_size, &size);
+	if (rc != EOK)
+		return rc;
+	blob->data_size += size;
+	return EOK;
+}
+
+static inline bithenge_sequential_blob_t *blob_as_sequential(
+    bithenge_blob_t *base)
+{
+	return (bithenge_sequential_blob_t *)base;
+}
+
+static inline bithenge_blob_t *sequential_as_blob(
+    bithenge_sequential_blob_t *blob)
+{
+	return &blob->base;
+}
+
+static int sequential_size(bithenge_blob_t *base, aoff64_t *size)
+{
+	bithenge_sequential_blob_t *blob = blob_as_sequential(base);
+	int rc;
+	if (blob->ops->size) {
+		rc = blob->ops->size(blob, size);
+		if (rc == EOK)
+			return EOK;
+	}
+	rc = sequential_buffer(blob, blob->buffer_size);
+	if (rc != EOK)
+		return rc;
+	while (blob->data_size == blob->buffer_size) {
+		rc = sequential_buffer(blob, 2 * blob->buffer_size);
+		if (rc != EOK)
+			return rc;
+	}
+	*size = blob->data_size;
+	return EOK;
+}
+
+static int sequential_read(bithenge_blob_t *base, aoff64_t offset,
+    char *buffer, aoff64_t *size)
+{
+	bithenge_sequential_blob_t *blob = blob_as_sequential(base);
+	aoff64_t end = offset + *size;
+	if (end > blob->data_size) {
+		int rc = sequential_buffer(blob, end);
+		if (rc != EOK)
+			return rc;
+	}
+	if (offset > blob->data_size)
+		return EINVAL;
+	*size = min(*size, blob->data_size - end);
+	memcpy(buffer, blob->buffer + offset, *size);
+	return EOK;
+}
+
+static void sequential_destroy(bithenge_blob_t *base)
+{
+	bithenge_sequential_blob_t *blob = blob_as_sequential(base);
+	free(blob->buffer);
+	blob->ops->destroy(blob);
+}
+
+static const bithenge_random_access_blob_ops_t sequential_ops = {
+	.size = sequential_size,
+	.read = sequential_read,
+	.destroy = sequential_destroy,
+};
+
+/** Initialize a sequential blob.
+ * @memberof bithenge_sequential_blob_t
+ * @param[out] blob The blob to initialize.
+ * @param[in] ops Operations providing sequential access support. This pointer
+ * must be valid until the blob is destroyed.
+ * @return EOK on success or an error code from errno.h.
+ */
+int bithenge_init_sequential_blob(bithenge_sequential_blob_t *blob,
+    const bithenge_sequential_blob_ops_t *ops)
+{
+	assert(blob);
+	assert(ops);
+	assert(ops->destroy);
+	assert(ops->read);
+	// ops->size is optional
+
+	int rc = bithenge_init_random_access_blob(sequential_as_blob(blob),
+	    &sequential_ops);
+	if (rc != EOK)
+		return rc;
+	blob->ops = ops;
+	blob->buffer = NULL; // realloc(NULL, ...) works like malloc
+	blob->buffer_size = 0;
+	blob->data_size = 0;
+	return EOK;
+}
+
+typedef struct {
+	bithenge_blob_t base;
+	const char *buffer;
+	size_t size;
+	bool needs_free;
+} memory_blob_t;
+
+static inline memory_blob_t *blob_as_memory(bithenge_blob_t *base)
+{
+	return (memory_blob_t *)base;
+}
+
+static inline bithenge_blob_t *memory_as_blob(memory_blob_t *blob)
+{
+	return &blob->base;
+}
+
+static int memory_size(bithenge_blob_t *base, aoff64_t *size)
+{
+	memory_blob_t *blob = blob_as_memory(base);
+	if (bithenge_should_fail())
+		return EIO;
+	*size = blob->size;
+	return EOK;
+}
+
+static int memory_read(bithenge_blob_t *base, aoff64_t offset, char *buffer,
+    aoff64_t *size)
+{
+	memory_blob_t *blob = blob_as_memory(base);
+	if (offset > blob->size)
+		return ELIMIT;
+	*size = min(*size, blob->size - offset);
+	memcpy(buffer, blob->buffer + offset, *size);
+	return EOK;
+}
+
+static void memory_destroy(bithenge_blob_t *base)
+{
+	memory_blob_t *blob = blob_as_memory(base);
+	if (blob->needs_free)
+		free((void *)blob->buffer);
+	free(blob);
+}
+
+static const bithenge_random_access_blob_ops_t memory_ops = {
+	.size = memory_size,
+	.read = memory_read,
+	.destroy = memory_destroy,
+};
+
+/** Create a blob node from a buffer. The buffer must exist as long as the blob
+ * does. The blob must be freed with @a bithenge_node_t::bithenge_node_destroy
+ * after it is used.
+ * @memberof bithenge_blob_t
+ * @param[out] out Stores the created blob node.
+ * @param[in] buffer The buffer, which must not be changed until the blob is
+ * destroyed.
+ * @param len The length of the data.
+ * @param needs_free If true, the buffer will be freed with free() if this
+ * function fails or the blob is destroyed.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_blob_from_buffer(bithenge_node_t **out, const void *buffer,
+    size_t len, bool needs_free)
+{
+	int rc;
+	assert(buffer || !len);
+
+	memory_blob_t *blob = malloc(sizeof(*blob));
+	if (!blob) {
+		rc = ENOMEM;
+		goto error;
+	}
+	rc = bithenge_init_random_access_blob(memory_as_blob(blob),
+	    &memory_ops);
+	if (rc != EOK)
+		goto error;
+	blob->buffer = buffer;
+	blob->size = len;
+	blob->needs_free = needs_free;
+	*out = bithenge_blob_as_node(memory_as_blob(blob));
+	return EOK;
+	
+error:
+	if (needs_free)
+		free((void *)buffer);
+	free(blob);
+	return rc;
+}
+
+/** Create a blob node from data. Unlike with @a
+ * bithenge_blob_t::bithenge_new_blob_from_buffer, the data is copied into a
+ * new buffer and the original data can be changed after this call. The blob
+ * must be freed with @a bithenge_node_t::bithenge_node_destroy after it is
+ * used.
+ * @memberof bithenge_blob_t
+ * @param[out] out Stores the created blob node.
+ * @param[in] data The data.
+ * @param len The length of the data.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_blob_from_data(bithenge_node_t **out, const void *data,
+    size_t len)
+{
+	char *buffer = malloc(len);
+	if (!buffer)
+		return ENOMEM;
+	memcpy(buffer, data, len);
+
+	return bithenge_new_blob_from_buffer(out, buffer, len, true);
+}
+
+
+
+typedef struct {
+	bithenge_blob_t base;
+	bithenge_blob_t *source;
+	aoff64_t offset;
+	aoff64_t size;
+	bool size_matters;
+} subblob_t;
+
+static inline subblob_t *blob_as_subblob(bithenge_blob_t *base)
+{
+	return (subblob_t *)base;
+}
+
+static inline bithenge_blob_t *subblob_as_blob(subblob_t *blob)
+{
+	return &blob->base;
+}
+
+static int subblob_size(bithenge_blob_t *base, aoff64_t *size)
+{
+	subblob_t *blob = blob_as_subblob(base);
+	if (blob->size_matters) {
+		*size = blob->size;
+		return EOK;
+	} else {
+		int rc = bithenge_blob_size(blob->source, size);
+		*size -= blob->offset;
+		return rc;
+	}
+}
+
+static int subblob_read(bithenge_blob_t *base, aoff64_t offset,
+    char *buffer, aoff64_t *size)
+{
+	subblob_t *blob = blob_as_subblob(base);
+	if (blob->size_matters) {
+		if (offset > blob->size)
+			return EINVAL;
+		*size = min(*size, blob->size - offset);
+	}
+	offset += blob->offset;
+	return bithenge_blob_read(blob->source, offset, buffer, size);
+}
+
+static int subblob_read_bits(bithenge_blob_t *base, aoff64_t offset,
+    char *buffer, aoff64_t *size, bool little_endian)
+{
+	subblob_t *blob = blob_as_subblob(base);
+	if (blob->size_matters) {
+		if (offset > blob->size)
+			return EINVAL;
+		*size = min(*size, blob->size - offset);
+	}
+	offset += blob->offset;
+	return bithenge_blob_read_bits(blob->source, offset, buffer, size,
+	    little_endian);
+}
+
+static void subblob_destroy(bithenge_blob_t *base)
+{
+	subblob_t *blob = blob_as_subblob(base);
+	bithenge_blob_dec_ref(blob->source);
+	free(blob);
+}
+
+static const bithenge_random_access_blob_ops_t subblob_ops = {
+	.size = subblob_size,
+	.read = subblob_read,
+	.read_bits = subblob_read_bits,
+	.destroy = subblob_destroy,
+};
+
+static bool is_subblob(bithenge_blob_t *blob)
+{
+	return blob->base.blob_ops == &subblob_ops;
+}
+
+static int new_subblob(bithenge_node_t **out, bithenge_blob_t *source,
+    aoff64_t offset, aoff64_t size, bool size_matters)
+{
+	assert(out);
+	assert(source);
+	int rc;
+	subblob_t *blob = 0;
+
+	if (is_subblob(source)) {
+		/* We can do some optimizations this way */
+		if (!size_matters)
+			size = 0;
+		subblob_t *source_subblob = blob_as_subblob(source);
+		if (source_subblob->size_matters &&
+		    offset + size > source_subblob->size) {
+			rc = EINVAL;
+			goto error;
+		}
+
+		if (source->base.refs == 1) {
+			source_subblob->offset += offset;
+			source_subblob->size -= offset;
+			if (size_matters) {
+				source_subblob->size_matters = true;
+				source_subblob->size = size;
+			}
+			*out = bithenge_blob_as_node(source);
+			return EOK;
+		}
+
+		if (!size_matters && source_subblob->size_matters) {
+			size_matters = true;
+			size = source_subblob->size - offset;
+		}
+		offset += source_subblob->offset;
+		source = source_subblob->source;
+		bithenge_blob_inc_ref(source);
+		bithenge_blob_dec_ref(subblob_as_blob(source_subblob));
+	}
+
+	blob = malloc(sizeof(*blob));
+	if (!blob) {
+		rc = ENOMEM;
+		goto error;
+	}
+	rc = bithenge_init_random_access_blob(subblob_as_blob(blob),
+	    &subblob_ops);
+	if (rc != EOK)
+		goto error;
+	blob->source = source;
+	blob->offset = offset;
+	blob->size = size;
+	blob->size_matters = size_matters;
+	*out = bithenge_blob_as_node(subblob_as_blob(blob));
+	return EOK;
+
+error:
+	bithenge_blob_dec_ref(source);
+	free(blob);
+	return rc;
+}
+
+/** Create a blob from data offset within another blob. This function takes
+ * ownership of a reference to @a blob.
+ * @param[out] out Stores the created blob node. On error, this is unchanged.
+ * @param[in] source The input blob.
+ * @param offset The offset within the input blob at which the new blob will start.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_offset_blob(bithenge_node_t **out, bithenge_blob_t *source,
+    aoff64_t offset)
+{
+	return new_subblob(out, source, offset, 0, false);
+}
+
+/** Create a blob from part of another blob. This function takes ownership of a
+ * reference to @a blob.
+ * @param[out] out Stores the created blob node. On error, this is unchanged.
+ * @param[in] source The input blob.
+ * @param offset The offset within the input blob at which the new blob will start.
+ * @param size The size of the new blob.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_subblob(bithenge_node_t **out, bithenge_blob_t *source,
+    aoff64_t offset, aoff64_t size)
+{
+	return new_subblob(out, source, offset, size, true);
+}
+
+/** Check whether the contents of two blobs are equal.
+ * @memberof bithenge_blob_t
+ * @param[out] out Holds whether the blobs are equal.
+ * @param a, b Blobs to compare.
+ * @return EOK on success, or an error code from errno.h.
+ */
+int bithenge_blob_equal(bool *out, bithenge_blob_t *a, bithenge_blob_t *b)
+{
+	assert(a);
+	assert(a->base.blob_ops);
+	assert(b);
+	assert(b->base.blob_ops);
+	int rc;
+	char buffer_a[4096], buffer_b[4096];
+	aoff64_t offset = 0, size_a = sizeof(buffer_a), size_b = sizeof(buffer_b);
+	do {
+		rc = bithenge_blob_read(a, offset, buffer_a, &size_a);
+		if (rc != EOK)
+			return rc;
+		rc = bithenge_blob_read(b, offset, buffer_b, &size_b);
+		if (rc != EOK)
+			return rc;
+		if (size_a != size_b || bcmp(buffer_a, buffer_b, size_a)) {
+			*out = false;
+			return EOK;
+		}
+		offset += size_a;
+	} while (size_a == sizeof(buffer_a));
+	*out = true;
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/lib/bithenge/src/common.h
===================================================================
--- uspace/lib/bithenge/src/common.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/common.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * Copyright (c) 2012 Vojtech Horky
+ * 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.
+ */
+
+#ifndef BITHENGE_COMMON_H_
+#define BITHENGE_COMMON_H_
+
+#ifdef __HELENOS__
+#include "helenos/common.h"
+#else
+#include "linux/common.h"
+#endif
+
+#ifdef BITHENGE_FAILURE_ENABLE
+#include "failure.h"
+#else
+static inline int bithenge_should_fail(void)
+{
+	return 0;
+}
+#endif
+
+#endif
Index: uspace/lib/bithenge/src/compound.c
===================================================================
--- uspace/lib/bithenge/src/compound.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/compound.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Compound transforms.
+ */
+
+#include <stdlib.h>
+#include <bithenge/compound.h>
+#include <bithenge/expression.h>
+#include <bithenge/transform.h>
+#include <bithenge/tree.h>
+#include "common.h"
+
+
+
+/***************** compose_transform                         *****************/
+
+typedef struct {
+	bithenge_transform_t base;
+	bithenge_transform_t **xforms;
+	size_t num;
+} compose_transform_t;
+
+static bithenge_transform_t *compose_as_transform(compose_transform_t *xform)
+{
+	return &xform->base;
+}
+
+static compose_transform_t *transform_as_compose(bithenge_transform_t *xform)
+{
+	return (compose_transform_t *)xform;
+}
+
+static int compose_apply(bithenge_transform_t *base, bithenge_scope_t *scope,
+    bithenge_node_t *in, bithenge_node_t **out)
+{
+	int rc;
+	compose_transform_t *self = transform_as_compose(base);
+	bithenge_node_inc_ref(in);
+
+	/* i ranges from (self->num - 1) to 0 inside the loop. */
+	for (size_t i = self->num; i--; ) {
+		bithenge_node_t *tmp;
+		rc = bithenge_transform_apply(self->xforms[i], scope, in,
+		    &tmp);
+		bithenge_node_dec_ref(in);
+		if (rc != EOK)
+			return rc;
+		in = tmp;
+	}
+
+	*out = in;
+	return rc;
+}
+
+static int compose_prefix_length(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
+{
+	compose_transform_t *self = transform_as_compose(base);
+	return bithenge_transform_prefix_length(self->xforms[self->num - 1],
+	    scope, blob, out);
+}
+
+static void compose_destroy(bithenge_transform_t *base)
+{
+	compose_transform_t *self = transform_as_compose(base);
+	for (size_t i = 0; i < self->num; i++)
+		bithenge_transform_dec_ref(self->xforms[i]);
+	free(self->xforms);
+	free(self);
+}
+
+static const bithenge_transform_ops_t compose_transform_ops = {
+	.apply = compose_apply,
+	.prefix_length = compose_prefix_length,
+	.destroy = compose_destroy,
+};
+
+/** Create a composition of multiple transforms. When the result is applied to a
+ * node, each transform is applied in turn, with the last transform applied
+ * first. @a xforms may contain any number of transforms or no transforms at
+ * all. This function takes ownership of @a xforms and the references therein.
+ * @param[out] out Holds the result.
+ * @param[in] xforms The transforms to apply.
+ * @param num The number of transforms.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_composed_transform(bithenge_transform_t **out,
+    bithenge_transform_t **xforms, size_t num)
+{
+	if (num == 0) {
+		/* TODO: optimize */
+	} else if (num == 1) {
+		*out = xforms[0];
+		free(xforms);
+		return EOK;
+	}
+
+	int rc;
+	compose_transform_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+	rc = bithenge_init_transform(compose_as_transform(self),
+	    &compose_transform_ops, 0);
+	if (rc != EOK)
+		goto error;
+	self->xforms = xforms;
+	self->num = num;
+	*out = compose_as_transform(self);
+	return EOK;
+error:
+	for (size_t i = 0; i < num; i++)
+		bithenge_transform_dec_ref(xforms[i]);
+	free(xforms);
+	free(self);
+	return rc;
+}
+
+
+
+/***************** if_transform                              *****************/
+
+typedef struct {
+	bithenge_transform_t base;
+	bithenge_expression_t *expr;
+	bithenge_transform_t *true_xform, *false_xform;
+} if_transform_t;
+
+static inline bithenge_transform_t *if_as_transform(if_transform_t *self)
+{
+	return &self->base;
+}
+
+static inline if_transform_t *transform_as_if(bithenge_transform_t *base)
+{
+	return (if_transform_t *)base;
+}
+
+static int if_transform_choose(if_transform_t *self, bithenge_scope_t *scope,
+    bool *out)
+{
+	bithenge_node_t *cond_node;
+	int rc = bithenge_expression_evaluate(self->expr, scope, &cond_node);
+	if (rc != EOK)
+		return rc;
+	if (bithenge_node_type(cond_node) != BITHENGE_NODE_BOOLEAN) {
+		bithenge_node_dec_ref(cond_node);
+		return EINVAL;
+	}
+	*out = bithenge_boolean_node_value(cond_node);
+	bithenge_node_dec_ref(cond_node);
+	return EOK;
+}
+
+static int if_transform_apply(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
+{
+	if_transform_t *self = transform_as_if(base);
+	bool cond;
+	int rc = if_transform_choose(self, scope, &cond);
+	if (rc != EOK)
+		return rc;
+	return bithenge_transform_apply(
+	    cond ? self->true_xform : self->false_xform, scope, in, out);
+}
+
+static int if_transform_prefix_length(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
+{
+	if_transform_t *self = transform_as_if(base);
+	bool cond;
+	int rc = if_transform_choose(self, scope, &cond);
+	if (rc != EOK)
+		return rc;
+	return bithenge_transform_prefix_length(
+	    cond ? self->true_xform : self->false_xform, scope, in, out);
+}
+
+static void if_transform_destroy(bithenge_transform_t *base)
+{
+	if_transform_t *self = transform_as_if(base);
+	bithenge_expression_dec_ref(self->expr);
+	bithenge_transform_dec_ref(self->true_xform);
+	bithenge_transform_dec_ref(self->false_xform);
+	free(self);
+}
+
+static const bithenge_transform_ops_t if_transform_ops = {
+	.apply = if_transform_apply,
+	.prefix_length = if_transform_prefix_length,
+	.destroy = if_transform_destroy,
+};
+
+/** Create a transform that applies either of two transforms depending on a
+ * boolean expression. Takes references to @a expr, @a true_xform, and
+ * @a false_xform.
+ * @param[out] out Holds the new transform.
+ * @param expr The boolean expression to evaluate.
+ * @param true_xform The transform to apply if the expression is true.
+ * @param false_xform The transform to apply if the expression is false.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_if_transform(bithenge_transform_t **out,
+    bithenge_expression_t *expr, bithenge_transform_t *true_xform,
+    bithenge_transform_t *false_xform)
+{
+	int rc;
+	if_transform_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_transform(if_as_transform(self), &if_transform_ops,
+	    0);
+	if (rc != EOK)
+		goto error;
+
+	self->expr = expr;
+	self->true_xform = true_xform;
+	self->false_xform = false_xform;
+	*out = if_as_transform(self);
+	return EOK;
+
+error:
+	free(self);
+	bithenge_expression_dec_ref(expr);
+	bithenge_transform_dec_ref(true_xform);
+	bithenge_transform_dec_ref(false_xform);
+	return rc;
+}
+
+
+
+/***************** partial_transform                         *****************/
+
+typedef struct {
+	bithenge_transform_t base;
+	bithenge_transform_t *xform;
+} partial_transform_t;
+
+static inline bithenge_transform_t *partial_as_transform(
+    partial_transform_t *self)
+{
+	return &self->base;
+}
+
+static inline partial_transform_t *transform_as_partial(
+    bithenge_transform_t *base)
+{
+	return (partial_transform_t *)base;
+}
+
+static int partial_transform_apply(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
+{
+	partial_transform_t *self = transform_as_partial(base);
+	if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
+		return EINVAL;
+	return bithenge_transform_prefix_apply(self->xform, scope,
+	    bithenge_node_as_blob(in), out, NULL);
+}
+
+static void partial_transform_destroy(bithenge_transform_t *base)
+{
+	partial_transform_t *self = transform_as_partial(base);
+	bithenge_transform_dec_ref(self->xform);
+	free(self);
+}
+
+static const bithenge_transform_ops_t partial_transform_ops = {
+	.apply = partial_transform_apply,
+	.destroy = partial_transform_destroy,
+};
+
+/** Create a transform that doesn't require its subtransform to use the whole
+ * input. Takes a reference to @a xform.
+ * @param[out] out Holds the new transform.
+ * @param xform The subtransform to apply.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_partial_transform(bithenge_transform_t **out,
+    bithenge_transform_t *xform)
+{
+	int rc;
+	partial_transform_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_transform(partial_as_transform(self),
+	    &partial_transform_ops, 0);
+	if (rc != EOK)
+		goto error;
+
+	self->xform = xform;
+	*out = partial_as_transform(self);
+	return EOK;
+
+error:
+	free(self);
+	bithenge_transform_dec_ref(xform);
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/bithenge/src/expression.c
===================================================================
--- uspace/lib/bithenge/src/expression.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/expression.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,1200 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Expressions.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "common.h"
+#include <bithenge/blob.h>
+#include <bithenge/expression.h>
+#include <bithenge/transform.h>
+#include <bithenge/tree.h>
+
+/** Initialize a new expression.
+ * @param[out] self Expression to initialize.
+ * @param[in] ops Operations provided by the expression.
+ * @return EOK or an error code from errno.h. */
+int bithenge_init_expression(bithenge_expression_t *self,
+    const bithenge_expression_ops_t *ops)
+{
+	assert(ops);
+	assert(ops->evaluate);
+	assert(ops->destroy);
+	if (bithenge_should_fail())
+		return ENOMEM;
+	self->ops = ops;
+	self->refs = 1;
+	return EOK;
+}
+
+static void expression_indestructible(bithenge_expression_t *self)
+{
+	assert(false);
+}
+
+
+
+/***************** binary_expression                         *****************/
+
+typedef struct {
+	bithenge_expression_t base;
+	bithenge_binary_op_t op;
+	bithenge_expression_t *a, *b;
+} binary_expression_t;
+
+static inline binary_expression_t *expression_as_binary(
+    bithenge_expression_t *base)
+{
+	return (binary_expression_t *)base;
+}
+
+static inline bithenge_expression_t *binary_as_expression(
+    binary_expression_t *self)
+{
+	return &self->base;
+}
+
+static int binary_expression_evaluate(bithenge_expression_t *base,
+    bithenge_scope_t *scope, bithenge_node_t **out)
+{
+	int rc;
+	binary_expression_t *self = expression_as_binary(base);
+	bithenge_node_t *a, *b;
+	rc = bithenge_expression_evaluate(self->a, scope, &a);
+	if (rc != EOK)
+		return rc;
+	if (self->op != BITHENGE_EXPRESSION_CONCAT) {
+		rc = bithenge_expression_evaluate(self->b, scope, &b);
+		if (rc != EOK) {
+			bithenge_node_dec_ref(a);
+			return rc;
+		}
+	}
+
+	/* Check types and get values. */
+	/* Assigning 0 only to make the compiler happy. */
+	bithenge_int_t a_int = 0, b_int = 0;
+	bool a_bool = false, b_bool = false, out_bool = false;
+	switch (self->op) {
+	case BITHENGE_EXPRESSION_ADD: /* fallthrough */
+	case BITHENGE_EXPRESSION_SUBTRACT: /* fallthrough */
+	case BITHENGE_EXPRESSION_MULTIPLY: /* fallthrough */
+	case BITHENGE_EXPRESSION_INTEGER_DIVIDE: /* fallthrough */
+	case BITHENGE_EXPRESSION_MODULO: /* fallthrough */
+	case BITHENGE_EXPRESSION_LESS_THAN: /* fallthrough */
+	case BITHENGE_EXPRESSION_LESS_THAN_OR_EQUAL: /* fallthrough */
+	case BITHENGE_EXPRESSION_GREATER_THAN: /* fallthrough */
+	case BITHENGE_EXPRESSION_GREATER_THAN_OR_EQUAL:
+		rc = EINVAL;
+		if (bithenge_node_type(a) != BITHENGE_NODE_INTEGER)
+			goto error;
+		if (bithenge_node_type(b) != BITHENGE_NODE_INTEGER)
+			goto error;
+		a_int = bithenge_integer_node_value(a);
+		b_int = bithenge_integer_node_value(b);
+		break;
+	case BITHENGE_EXPRESSION_AND: /* fallthrough */
+	case BITHENGE_EXPRESSION_OR:
+		rc = EINVAL;
+		if (bithenge_node_type(a) != BITHENGE_NODE_BOOLEAN)
+			goto error;
+		if (bithenge_node_type(b) != BITHENGE_NODE_BOOLEAN)
+			goto error;
+		a_bool = bithenge_boolean_node_value(a);
+		b_bool = bithenge_boolean_node_value(b);
+		break;
+	case BITHENGE_EXPRESSION_CONCAT:
+		if (bithenge_node_type(a) != BITHENGE_NODE_BLOB)
+			goto error;
+		break;
+	default:
+		break;
+	}
+
+	switch (self->op) {
+	case BITHENGE_EXPRESSION_ADD:
+		rc = bithenge_new_integer_node(out, a_int + b_int);
+		break;
+	case BITHENGE_EXPRESSION_SUBTRACT:
+		rc = bithenge_new_integer_node(out, a_int - b_int);
+		break;
+	case BITHENGE_EXPRESSION_MULTIPLY:
+		rc = bithenge_new_integer_node(out, a_int * b_int);
+		break;
+	case BITHENGE_EXPRESSION_INTEGER_DIVIDE:
+		/* Integer division can behave in three major ways when the
+		  operands are signed: truncated, floored, or Euclidean. When
+		 * b > 0, we give the same result as floored and Euclidean;
+		 * otherwise, we currently raise an error. See
+		 * https://en.wikipedia.org/wiki/Modulo_operation and its
+		 * references. */
+		if (b_int <= 0) {
+			rc = EINVAL;
+			break;
+		}
+		rc = bithenge_new_integer_node(out,
+		    (a_int / b_int) + (a_int % b_int < 0 ? -1 : 0));
+		break;
+	case BITHENGE_EXPRESSION_MODULO:
+		/* This is consistent with division; see above. */
+		if (b_int <= 0) {
+			rc = EINVAL;
+			break;
+		}
+		rc = bithenge_new_integer_node(out,
+		    (a_int % b_int) + (a_int % b_int < 0 ? b_int : 0));
+		break;
+	case BITHENGE_EXPRESSION_LESS_THAN:
+		rc = bithenge_new_boolean_node(out, a_int < b_int);
+		break;
+	case BITHENGE_EXPRESSION_LESS_THAN_OR_EQUAL:
+		rc = bithenge_new_boolean_node(out, a_int <= b_int);
+		break;
+	case BITHENGE_EXPRESSION_GREATER_THAN:
+		rc = bithenge_new_boolean_node(out, a_int > b_int);
+		break;
+	case BITHENGE_EXPRESSION_GREATER_THAN_OR_EQUAL:
+		rc = bithenge_new_boolean_node(out, a_int >= b_int);
+		break;
+	case BITHENGE_EXPRESSION_EQUALS:
+		rc = bithenge_node_equal(&out_bool, a, b);
+		if (rc != EOK)
+			break;
+		rc = bithenge_new_boolean_node(out, out_bool);
+		break;
+	case BITHENGE_EXPRESSION_NOT_EQUALS:
+		rc = bithenge_node_equal(&out_bool, a, b);
+		if (rc != EOK)
+			break;
+		rc = bithenge_new_boolean_node(out, !out_bool);
+		break;
+	case BITHENGE_EXPRESSION_AND:
+		rc = bithenge_new_boolean_node(out, a_bool && b_bool);
+		break;
+	case BITHENGE_EXPRESSION_OR:
+		rc = bithenge_new_boolean_node(out, a_bool || b_bool);
+		break;
+	case BITHENGE_EXPRESSION_MEMBER:
+		rc = bithenge_node_get(a, b, out);
+		b = NULL;
+		break;
+	case BITHENGE_EXPRESSION_CONCAT:
+		bithenge_expression_inc_ref(self->b);
+		bithenge_scope_inc_ref(scope);
+		rc = bithenge_concat_blob_lazy(out, bithenge_node_as_blob(a),
+		    self->b, scope);
+		a = NULL;
+		b = NULL;
+		break;
+	case BITHENGE_EXPRESSION_INVALID_BINARY_OP:
+		assert(false);
+		break;
+	}
+
+error:
+	bithenge_node_dec_ref(a);
+	bithenge_node_dec_ref(b);
+	return rc;
+}
+
+static void binary_expression_destroy(bithenge_expression_t *base)
+{
+	binary_expression_t *self = expression_as_binary(base);
+	bithenge_expression_dec_ref(self->a);
+	bithenge_expression_dec_ref(self->b);
+	free(self);
+}
+
+static const bithenge_expression_ops_t binary_expression_ops = {
+	.evaluate = binary_expression_evaluate,
+	.destroy = binary_expression_destroy,
+};
+
+/** Create a binary expression. Takes ownership of @a a and @a b.
+ * @param[out] out Holds the new expression.
+ * @param op The operator to apply.
+ * @param a The first operand.
+ * @param b The second operand.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_binary_expression(bithenge_expression_t **out,
+    bithenge_binary_op_t op, bithenge_expression_t *a,
+    bithenge_expression_t *b)
+{
+	int rc;
+	binary_expression_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_expression(binary_as_expression(self),
+	    &binary_expression_ops);
+	if (rc != EOK)
+		goto error;
+
+	self->op = op;
+	self->a = a;
+	self->b = b;
+	*out = binary_as_expression(self);
+	return EOK;
+
+error:
+	bithenge_expression_dec_ref(a);
+	bithenge_expression_dec_ref(b);
+	free(self);
+	return rc;
+}
+
+
+
+/***************** in_node_expression                        *****************/
+
+static int in_node_evaluate(bithenge_expression_t *self,
+    bithenge_scope_t *scope, bithenge_node_t **out)
+{
+	for (; scope; scope = bithenge_scope_outer(scope)) {
+		*out = bithenge_scope_in_node(scope);
+		if (*out)
+			return EOK;
+	}
+	return EINVAL;
+}
+
+static const bithenge_expression_ops_t in_node_ops = {
+	.evaluate = in_node_evaluate,
+	.destroy = expression_indestructible,
+};
+
+static bithenge_expression_t in_node_expression = {
+	&in_node_ops, 1
+};
+
+/** Create an expression that gets the current input node.
+ * @param[out] out Holds the new expression.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_in_node_expression(bithenge_expression_t **out)
+{
+	if (bithenge_should_fail())
+		return ENOMEM;
+	bithenge_expression_inc_ref(&in_node_expression);
+	*out = &in_node_expression;
+	return EOK;
+}
+
+
+
+/***************** current_node_expression                   *****************/
+
+static int current_node_evaluate(bithenge_expression_t *self,
+    bithenge_scope_t *scope, bithenge_node_t **out)
+{
+	*out = bithenge_scope_get_current_node(scope);
+	if (!*out)
+		return EINVAL;
+	return EOK;
+}
+
+static const bithenge_expression_ops_t current_node_ops = {
+	.evaluate = current_node_evaluate,
+	.destroy = expression_indestructible,
+};
+
+static bithenge_expression_t current_node_expression = {
+	&current_node_ops, 1
+};
+
+/** Create an expression that gets the current node being created.
+ * @param[out] out Holds the new expression.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_current_node_expression(bithenge_expression_t **out)
+{
+	bithenge_expression_inc_ref(&current_node_expression);
+	*out = &current_node_expression;
+	return EOK;
+}
+
+
+
+/***************** param_expression                          *****************/
+
+typedef struct {
+	bithenge_expression_t base;
+	int index;
+} param_expression_t;
+
+static inline param_expression_t *expression_as_param(
+    bithenge_expression_t *base)
+{
+	return (param_expression_t *)base;
+}
+
+static inline bithenge_expression_t *param_as_expression(
+    param_expression_t *self)
+{
+	return &self->base;
+}
+
+static int param_expression_evaluate(bithenge_expression_t *base,
+    bithenge_scope_t *scope, bithenge_node_t **out)
+{
+	param_expression_t *self = expression_as_param(base);
+	return bithenge_scope_get_param(scope, self->index, out);
+}
+
+static void param_expression_destroy(bithenge_expression_t *base)
+{
+	param_expression_t *self = expression_as_param(base);
+	free(self);
+}
+
+static const bithenge_expression_ops_t param_expression_ops = {
+	.evaluate = param_expression_evaluate,
+	.destroy = param_expression_destroy,
+};
+
+/** Create an expression that returns a parameter.
+ * @param[out] out Holds the created expression.
+ * @param index The index of the parameter to get.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_param_expression(bithenge_expression_t **out, int index)
+{
+	int rc;
+	param_expression_t *self = malloc(sizeof(*self));
+	if (!self)
+		return ENOMEM;
+
+	rc = bithenge_init_expression(param_as_expression(self),
+	    &param_expression_ops);
+	if (rc != EOK) {
+		free(self);
+		return rc;
+	}
+
+	self->index = index;
+	*out = param_as_expression(self);
+	return EOK;
+}
+
+
+
+/***************** const_expression                          *****************/
+
+typedef struct {
+	bithenge_expression_t base;
+	bithenge_node_t *node;
+} const_expression_t;
+
+static inline const_expression_t *expression_as_const(
+    bithenge_expression_t *base)
+{
+	return (const_expression_t *)base;
+}
+
+static inline bithenge_expression_t *const_as_expression(
+    const_expression_t *self)
+{
+	return &self->base;
+}
+
+static int const_expression_evaluate(bithenge_expression_t *base,
+    bithenge_scope_t *scope, bithenge_node_t **out)
+{
+	const_expression_t *self = expression_as_const(base);
+	bithenge_node_inc_ref(self->node);
+	*out = self->node;
+	return EOK;
+}
+
+static void const_expression_destroy(bithenge_expression_t *base)
+{
+	const_expression_t *self = expression_as_const(base);
+	bithenge_node_dec_ref(self->node);
+	free(self);
+}
+
+static const bithenge_expression_ops_t const_expression_ops = {
+	.evaluate = const_expression_evaluate,
+	.destroy = const_expression_destroy,
+};
+
+/** Create an expression that returns a constant. Takes a reference to @a node.
+ * @param[out] out Holds the created expression.
+ * @param node The constant.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_const_expression(bithenge_expression_t **out,
+    bithenge_node_t *node)
+{
+	int rc;
+	const_expression_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_expression(const_as_expression(self),
+	    &const_expression_ops);
+	if (rc != EOK)
+		goto error;
+
+	self->node = node;
+	*out = const_as_expression(self);
+	return EOK;
+
+error:
+	free(self);
+	bithenge_node_dec_ref(node);
+	return rc;
+}
+
+
+
+/***************** scope_member_expression                   *****************/
+
+typedef struct {
+	bithenge_expression_t base;
+	bithenge_node_t *key;
+} scope_member_expression_t;
+
+static scope_member_expression_t *expression_as_scope_member(
+    bithenge_expression_t *base)
+{
+	return (scope_member_expression_t *)base;
+}
+
+static bithenge_expression_t *scope_member_as_expression(
+    scope_member_expression_t *expr)
+{
+	return &expr->base;
+}
+
+static int scope_member_expression_evaluate(bithenge_expression_t *base, 
+    bithenge_scope_t *scope, bithenge_node_t **out)
+{
+	scope_member_expression_t *self = expression_as_scope_member(base);
+	for (; scope && !bithenge_scope_is_barrier(scope);
+	    scope = bithenge_scope_outer(scope)) {
+		bithenge_node_t *cur = bithenge_scope_get_current_node(scope);
+		if (!cur)
+			continue;
+		bithenge_node_inc_ref(self->key);
+		int rc = bithenge_node_get(cur, self->key, out);
+		bithenge_node_dec_ref(cur);
+		if (rc != ENOENT) /* EOK or error */
+			return rc;
+	}
+	return bithenge_scope_error(scope, "No scope member %t", self->key);
+}
+
+static void scope_member_expression_destroy(bithenge_expression_t *base)
+{
+	scope_member_expression_t *self = expression_as_scope_member(base);
+	bithenge_node_dec_ref(self->key);
+	free(self);
+}
+
+static const bithenge_expression_ops_t scope_member_expression_ops = {
+	.evaluate = scope_member_expression_evaluate,
+	.destroy = scope_member_expression_destroy,
+};
+
+/** Create an expression that gets a member from one of the current nodes being
+ * created. It searches from the current scope outwards, stopping at barrier
+ * scopes.
+ * @param[out] out Holds the new expression.
+ * @param key The key to search for in nodes being created.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_scope_member_expression(bithenge_expression_t **out,
+    bithenge_node_t *key)
+{
+	int rc;
+	scope_member_expression_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_expression(scope_member_as_expression(self),
+	    &scope_member_expression_ops);
+	if (rc != EOK)
+		goto error;
+
+	self->key = key;
+	*out = scope_member_as_expression(self);
+	return EOK;
+
+error:
+	bithenge_node_dec_ref(key);
+	free(self);
+	return rc;
+}
+
+
+
+/***************** subblob_expression                        *****************/
+
+typedef struct {
+	bithenge_expression_t base;
+	bithenge_expression_t *blob, *start, *limit;
+	bool absolute_limit;
+} subblob_expression_t;
+
+static subblob_expression_t *expression_as_subblob(bithenge_expression_t *base)
+{
+	return (subblob_expression_t *)base;
+}
+
+static bithenge_expression_t *subblob_as_expression(subblob_expression_t *expr)
+{
+	return &expr->base;
+}
+
+static int subblob_expression_evaluate(bithenge_expression_t *base, 
+    bithenge_scope_t *scope, bithenge_node_t **out)
+{
+	subblob_expression_t *self = expression_as_subblob(base);
+	bithenge_node_t *start_node;
+	int rc = bithenge_expression_evaluate(self->start, scope, &start_node);
+	if (rc != EOK)
+		return rc;
+	if (bithenge_node_type(start_node) != BITHENGE_NODE_INTEGER) {
+		bithenge_node_dec_ref(start_node);
+		return EINVAL;
+	}
+	bithenge_int_t start = bithenge_integer_node_value(start_node);
+	bithenge_node_dec_ref(start_node);
+
+	bithenge_int_t limit = -1;
+	if (self->limit) {
+		bithenge_node_t *limit_node;
+		rc = bithenge_expression_evaluate(self->limit, scope,
+		    &limit_node);
+		if (rc != EOK)
+			return rc;
+		if (bithenge_node_type(limit_node) != BITHENGE_NODE_INTEGER) {
+			bithenge_node_dec_ref(limit_node);
+			return EINVAL;
+		}
+		limit = bithenge_integer_node_value(limit_node);
+		bithenge_node_dec_ref(limit_node);
+		if (self->absolute_limit)
+			limit -= start;
+	}
+
+	if (start < 0 || (self->limit && limit < 0))
+		return EINVAL;
+
+	bithenge_node_t *blob;
+	rc = bithenge_expression_evaluate(self->blob, scope, &blob);
+	if (rc != EOK)
+		return rc;
+	if (bithenge_node_type(blob) != BITHENGE_NODE_BLOB) {
+		bithenge_node_dec_ref(blob);
+		return EINVAL;
+	}
+
+	if (self->limit)
+		return bithenge_new_subblob(out, bithenge_node_as_blob(blob),
+		    start, limit);
+	else
+		return bithenge_new_offset_blob(out,
+		    bithenge_node_as_blob(blob), start);
+}
+
+static void subblob_expression_destroy(bithenge_expression_t *base)
+{
+	subblob_expression_t *self = expression_as_subblob(base);
+	bithenge_expression_dec_ref(self->blob);
+	bithenge_expression_dec_ref(self->start);
+	bithenge_expression_dec_ref(self->limit);
+	free(self);
+}
+
+static const bithenge_expression_ops_t subblob_expression_ops = {
+	.evaluate = subblob_expression_evaluate,
+	.destroy = subblob_expression_destroy,
+};
+
+/** Create an expression that gets a subblob. Takes references to @a blob,
+ * @a start, and @a limit.
+ * @param[out] out Holds the new expression.
+ * @param blob Calculates the blob.
+ * @param start Calculates the start offset within the blob.
+ * @param limit Calculates the limit. Can be NULL, in which case an offset blob
+ * is returned.
+ * @param absolute_limit If true, the limit is an absolute offset; otherwise,
+ * it is relative to the start.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_subblob_expression(bithenge_expression_t **out,
+    bithenge_expression_t *blob, bithenge_expression_t *start,
+    bithenge_expression_t *limit, bool absolute_limit)
+{
+	int rc;
+	subblob_expression_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_expression(subblob_as_expression(self),
+	    &subblob_expression_ops);
+	if (rc != EOK)
+		goto error;
+
+	self->blob = blob;
+	self->start = start;
+	self->limit = limit;
+	self->absolute_limit = absolute_limit;
+	*out = subblob_as_expression(self);
+	return EOK;
+
+error:
+	bithenge_expression_dec_ref(blob);
+	bithenge_expression_dec_ref(start);
+	bithenge_expression_dec_ref(limit);
+	free(self);
+	return rc;
+}
+
+/***************** param_wrapper                             *****************/
+
+typedef struct {
+	bithenge_transform_t base;
+	bithenge_transform_t *transform;
+	bithenge_expression_t **params;
+} param_wrapper_t;
+
+static inline bithenge_transform_t *param_wrapper_as_transform(
+    param_wrapper_t *self)
+{
+	return &self->base;
+}
+
+static inline param_wrapper_t *transform_as_param_wrapper(
+    bithenge_transform_t *base)
+{
+	return (param_wrapper_t *)base;
+}
+
+static int param_wrapper_fill_scope(param_wrapper_t *self, bithenge_scope_t
+    *inner, bithenge_scope_t *outer)
+{
+	int rc;
+	int num_params = bithenge_transform_num_params(self->transform);
+	rc = bithenge_scope_alloc_params(inner, num_params);
+	if (rc != EOK)
+		return rc;
+	for (int i = 0; i < num_params; i++) {
+		bithenge_node_t *node;
+		rc = bithenge_expression_evaluate(self->params[i], outer,
+		    &node);
+		if (rc != EOK)
+			return rc;
+		rc = bithenge_scope_set_param(inner, i, node);
+		if (rc != EOK)
+			return rc;
+	}
+	return EOK;
+}
+
+static int param_wrapper_apply(bithenge_transform_t *base,
+    bithenge_scope_t *outer, bithenge_node_t *in, bithenge_node_t **out)
+{
+	param_wrapper_t *self = transform_as_param_wrapper(base);
+	bithenge_scope_t *inner;
+	int rc = bithenge_scope_new(&inner, outer);
+	if (rc != EOK)
+		return rc;
+	rc = param_wrapper_fill_scope(self, inner, outer);
+	if (rc != EOK)
+		goto error;
+
+	rc = bithenge_transform_apply(self->transform, inner, in, out);
+	in = NULL;
+
+error:
+	bithenge_scope_dec_ref(inner);
+	return rc;
+}
+
+static int param_wrapper_prefix_length(bithenge_transform_t *base,
+    bithenge_scope_t *outer, bithenge_blob_t *in, aoff64_t *out)
+{
+	param_wrapper_t *self = transform_as_param_wrapper(base);
+	bithenge_scope_t *inner;
+	int rc = bithenge_scope_new(&inner, outer);
+	if (rc != EOK)
+		return rc;
+	rc = param_wrapper_fill_scope(self, inner, outer);
+	if (rc != EOK)
+		goto error;
+
+	rc = bithenge_transform_prefix_length(self->transform, inner, in, out);
+	in = NULL;
+
+error:
+	bithenge_scope_dec_ref(inner);
+	return rc;
+}
+
+static int param_wrapper_prefix_apply(bithenge_transform_t *base,
+    bithenge_scope_t *outer, bithenge_blob_t *in, bithenge_node_t **out_node,
+    aoff64_t *out_length)
+{
+	param_wrapper_t *self = transform_as_param_wrapper(base);
+	bithenge_scope_t *inner;
+	int rc = bithenge_scope_new(&inner, outer);
+	if (rc != EOK)
+		return rc;
+	rc = param_wrapper_fill_scope(self, inner, outer);
+	if (rc != EOK)
+		goto error;
+
+	rc = bithenge_transform_prefix_apply(self->transform, inner, in,
+	    out_node, out_length);
+
+error:
+	bithenge_scope_dec_ref(inner);
+	return rc;
+}
+
+static void param_wrapper_destroy(bithenge_transform_t *base)
+{
+	param_wrapper_t *self = transform_as_param_wrapper(base);
+	int num_params = bithenge_transform_num_params(self->transform);
+	bithenge_transform_dec_ref(self->transform);
+	for (int i = 0; i < num_params; i++)
+		bithenge_expression_dec_ref(self->params[i]);
+	free(self->params);
+	free(self);
+}
+
+static const bithenge_transform_ops_t param_wrapper_ops = {
+	.apply = param_wrapper_apply,
+	.prefix_length = param_wrapper_prefix_length,
+	.prefix_apply = param_wrapper_prefix_apply,
+	.destroy = param_wrapper_destroy,
+};
+
+/** Create a transform that calculates parameters for another transform. Takes
+ * ownership of @a transform, @a params, and each element of @a params. The
+ * number of parameters must be correct.
+ * @param[out] out Holds the new transform.
+ * @param transform The transform for which parameters are calculated.
+ * @param params The expressions used to calculate the parameters.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_param_wrapper(bithenge_transform_t **out,
+    bithenge_transform_t *transform, bithenge_expression_t **params)
+{
+	int rc;
+	int num_params = bithenge_transform_num_params(transform);
+	param_wrapper_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_transform(param_wrapper_as_transform(self),
+	    &param_wrapper_ops, 0);
+	if (rc != EOK)
+		goto error;
+
+	self->transform = transform;
+	self->params = params;
+	*out = param_wrapper_as_transform(self);
+	return EOK;
+
+error:
+	free(self);
+	for (int i = 0; i < num_params; i++)
+		bithenge_expression_dec_ref(params[i]);
+	free(params);
+	bithenge_transform_dec_ref(transform);
+	return rc;
+}
+
+
+
+/***************** expression_transform           *****************/
+
+/* Also used by inputless_transform. */
+typedef struct {
+	bithenge_transform_t base;
+	bithenge_expression_t *expr;
+} expression_transform_t;
+
+static inline bithenge_transform_t *expression_as_transform(
+    expression_transform_t *self)
+{
+	return &self->base;
+}
+
+static inline expression_transform_t *transform_as_expression(
+    bithenge_transform_t *base)
+{
+	return (expression_transform_t *)base;
+}
+
+static int expression_transform_apply(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
+{
+	expression_transform_t *self = transform_as_expression(base);
+	bithenge_scope_t *inner;
+	int rc = bithenge_scope_new(&inner, scope);
+	if (rc != EOK)
+		return rc;
+	bithenge_scope_set_in_node(inner, in);
+	rc = bithenge_expression_evaluate(self->expr, inner, out);
+	bithenge_scope_dec_ref(inner);
+	return rc;
+}
+
+/* Also used by inputless_transform. */
+static void expression_transform_destroy(bithenge_transform_t *base)
+{
+	expression_transform_t *self = transform_as_expression(base);
+	bithenge_expression_dec_ref(self->expr);
+	free(self);
+}
+
+static const bithenge_transform_ops_t expression_transform_ops = {
+	.apply = expression_transform_apply,
+	.destroy = expression_transform_destroy,
+};
+
+/** Create a transform that evaluates an expression on the input node. Takes a
+ * reference to the expression.
+ * @param[out] out Holds the new transform.
+ * @param expr The expression to evaluate.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_expression_transform(bithenge_transform_t ** out,
+    bithenge_expression_t *expr)
+{
+	int rc;
+	expression_transform_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_transform(expression_as_transform(self),
+	    &expression_transform_ops, 0);
+	if (rc != EOK)
+		goto error;
+
+	self->expr = expr;
+	*out = expression_as_transform(self);
+	return EOK;
+
+error:
+	free(self);
+	bithenge_expression_dec_ref(expr);
+	return rc;
+}
+
+
+
+/***************** inputless_transform            *****************/
+
+static int inputless_transform_prefix_length(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
+{
+	*out = 0;
+	return EOK;
+}
+
+static int inputless_transform_prefix_apply(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_blob_t *in, bithenge_node_t **out_node,
+    aoff64_t *out_size)
+{
+	expression_transform_t *self = transform_as_expression(base);
+	if (out_size)
+		*out_size = 0;
+	return bithenge_expression_evaluate(self->expr, scope, out_node);
+}
+
+static const bithenge_transform_ops_t inputless_transform_ops = {
+	.prefix_length = inputless_transform_prefix_length,
+	.prefix_apply = inputless_transform_prefix_apply,
+	.destroy = expression_transform_destroy,
+};
+
+/** Create a transform that takes an empty blob and produces the result of an
+ * expression. Takes a reference to the expression.
+ * @param[out] out Holds the new transform.
+ * @param expr The expression to evaluate.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_inputless_transform(bithenge_transform_t ** out,
+    bithenge_expression_t *expr)
+{
+	int rc;
+	expression_transform_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_transform(expression_as_transform(self),
+	    &inputless_transform_ops, 0);
+	if (rc != EOK)
+		goto error;
+
+	self->expr = expr;
+	*out = expression_as_transform(self);
+	return EOK;
+
+error:
+	free(self);
+	bithenge_expression_dec_ref(expr);
+	return rc;
+}
+
+
+
+/***************** concat_blob                    *****************/
+
+typedef struct {
+	bithenge_blob_t base;
+	bithenge_blob_t *a, *b;
+	aoff64_t a_size;
+	bithenge_expression_t *b_expr;
+	bithenge_scope_t *scope;
+} concat_blob_t;
+
+static inline concat_blob_t *blob_as_concat(bithenge_blob_t *base)
+{
+	return (concat_blob_t *)base;
+}
+
+static inline bithenge_blob_t *concat_as_blob(concat_blob_t *blob)
+{
+	return &blob->base;
+}
+
+static int concat_blob_evaluate_b(concat_blob_t *self)
+{
+	if (self->b)
+		return EOK;
+	bithenge_node_t *b_node;
+	int rc = bithenge_expression_evaluate(self->b_expr, self->scope,
+	    &b_node);
+	if (rc != EOK)
+		return rc;
+	if (bithenge_node_type(b_node) != BITHENGE_NODE_BLOB) {
+		bithenge_node_dec_ref(b_node);
+		return bithenge_scope_error(self->scope,
+		    "Concatenation arguments must be blobs");
+	}
+	self->b = bithenge_node_as_blob(b_node);
+	bithenge_expression_dec_ref(self->b_expr);
+	bithenge_scope_dec_ref(self->scope);
+	self->b_expr = NULL;
+	self->scope = NULL;
+	return EOK;
+}
+
+static int concat_blob_size(bithenge_blob_t *base, aoff64_t *size)
+{
+	concat_blob_t *self = blob_as_concat(base);
+	int rc = concat_blob_evaluate_b(self);
+	if (rc != EOK)
+		return rc;
+	rc = bithenge_blob_size(self->b, size);
+	*size += self->a_size;
+	return rc;
+}
+
+static int concat_blob_read(bithenge_blob_t *base, aoff64_t offset,
+    char *buffer, aoff64_t *size)
+{
+	int rc;
+	concat_blob_t *self = blob_as_concat(base);
+
+	aoff64_t a_size = 0, b_size = 0;
+	if (offset < self->a_size) {
+		a_size = *size;
+		rc = bithenge_blob_read(self->a, offset, buffer, &a_size);
+		if (rc != EOK)
+			return rc;
+	}
+	if (offset + *size > self->a_size) {
+		rc = concat_blob_evaluate_b(self);
+		if (rc != EOK)
+			return rc;
+		b_size = *size - a_size;
+		rc = bithenge_blob_read(self->b,
+		    offset + a_size - self->a_size, buffer + a_size, &b_size);
+		if (rc != EOK)
+			return rc;
+	}
+	assert(a_size + b_size <= *size);
+	*size = a_size + b_size;
+	return EOK;
+}
+
+static int concat_blob_read_bits(bithenge_blob_t *base, aoff64_t offset,
+    char *buffer, aoff64_t *size, bool little_endian)
+{
+	int rc;
+	concat_blob_t *self = blob_as_concat(base);
+
+	aoff64_t a_size = 0, b_size = 0;
+	if (offset < self->a_size) {
+		a_size = *size;
+		rc = bithenge_blob_read_bits(self->a, offset, buffer, &a_size,
+		    little_endian);
+		if (rc != EOK)
+			return rc;
+	}
+	if (offset + *size > self->a_size) {
+		rc = concat_blob_evaluate_b(self);
+		if (rc != EOK)
+			return rc;
+		b_size = *size - a_size;
+		assert(a_size % 8 == 0); /* TODO: don't require this */
+		rc = bithenge_blob_read_bits(self->b,
+		    offset + a_size - self->a_size, buffer + a_size / 8,
+		    &b_size, little_endian);
+		if (rc != EOK)
+			return rc;
+	}
+	assert(a_size + b_size <= *size);
+	*size = a_size + b_size;
+	return EOK;
+}
+
+static void concat_blob_destroy(bithenge_blob_t *base)
+{
+	concat_blob_t *self = blob_as_concat(base);
+	bithenge_blob_dec_ref(self->a);
+	bithenge_blob_dec_ref(self->b);
+	bithenge_expression_dec_ref(self->b_expr);
+	bithenge_scope_dec_ref(self->scope);
+	free(self);
+}
+
+static const bithenge_random_access_blob_ops_t concat_blob_ops = {
+	.size = concat_blob_size,
+	.read = concat_blob_read,
+	.read_bits = concat_blob_read_bits,
+	.destroy = concat_blob_destroy,
+};
+
+/** Create a concatenated blob. Takes references to @a a and @a b.
+ * @param[out] out Holds the new blob.
+ * @param a The first blob.
+ * @param b The second blob.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_concat_blob(bithenge_node_t **out, bithenge_blob_t *a,
+    bithenge_blob_t *b)
+{
+	assert(out);
+	assert(a);
+	assert(b);
+	int rc;
+	concat_blob_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_blob_size(a, &self->a_size);
+	if (rc != EOK)
+		goto error;
+
+	rc = bithenge_init_random_access_blob(concat_as_blob(self),
+	    &concat_blob_ops);
+	if (rc != EOK)
+		goto error;
+	self->a = a;
+	self->b = b;
+	self->b_expr = NULL;
+	self->scope = NULL;
+	*out = bithenge_blob_as_node(concat_as_blob(self));
+	return EOK;
+
+error:
+	bithenge_blob_dec_ref(a);
+	bithenge_blob_dec_ref(b);
+	free(self);
+	return rc;
+}
+
+/** Create a lazy concatenated blob. Takes references to @a a, @a b_expr, and
+ * @a scope.
+ * @param[out] out Holds the new blob.
+ * @param a The first blob.
+ * @param b_expr An expression to calculate the second blob.
+ * @param scope The scope in which @a b_expr should be evaluated.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_concat_blob_lazy(bithenge_node_t **out, bithenge_blob_t *a,
+    bithenge_expression_t *b_expr, bithenge_scope_t *scope)
+{
+	assert(out);
+	assert(a);
+	assert(b_expr);
+	assert(scope);
+	int rc;
+	concat_blob_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_blob_size(a, &self->a_size);
+	if (rc != EOK)
+		goto error;
+
+	rc = bithenge_init_random_access_blob(concat_as_blob(self),
+	    &concat_blob_ops);
+	if (rc != EOK)
+		goto error;
+	self->a = a;
+	self->b = NULL;
+	self->b_expr = b_expr;
+	self->scope = scope;
+	*out = bithenge_blob_as_node(concat_as_blob(self));
+	return EOK;
+
+error:
+	bithenge_blob_dec_ref(a);
+	bithenge_expression_dec_ref(b_expr);
+	bithenge_scope_dec_ref(scope);
+	free(self);
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/bithenge/src/failure.c
===================================================================
--- uspace/lib/bithenge/src/failure.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/failure.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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.
+ */
+
+/** @cond internal */
+/** @addtogroup bithenge
+ * @{
+ */
+/**
+ * @file
+ * Fake system call errors for testing.
+ */
+
+#include <errno.h>
+#include <execinfo.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#define BITHENGE_FAILURE_DECLS_ONLY 1
+#include "failure.h"
+#include "common.h"
+
+/* This file raises fake errors from system calls, to test that Bithenge
+ * handles the errors correctly. It has two primary modes of operation,
+ * depending on an environment variable:
+ *
+ * BITHENGE_FAILURE_INDEX not set: when a system call is made, a child process
+ * returns a fake error from that call. If the child process handles the error
+ * correctly (exit code is 1), the main process continues without errors. If
+ * the child process has a problem, the main process raises the fake error
+ * again and shows all stdout and stderr output. For speed, errors are only
+ * raised when part of the backtrace has not been seen before.
+ *
+ * BITHENGE_FAILURE_INDEX set: the program runs normally until system call
+ * number BITHENGE_FAILURE_INDEX is made; a fake error is returned from this
+ * call. */
+
+static int g_initialized = 0;
+static int g_failure_index = -1;
+static int g_failure_index_selected = -1;
+
+typedef struct backtrace_item {
+	struct backtrace_item *next;
+	void *backtrace_item;
+} backtrace_item_t;
+
+static backtrace_item_t *g_backtrace_items = NULL;
+
+static void atexit_handler(void)
+{
+	while (g_backtrace_items) {
+		backtrace_item_t *first = g_backtrace_items;
+		g_backtrace_items = first->next;
+		free(first);
+	}
+}
+
+static inline void initialize(void)
+{
+	g_initialized = 1;
+	int rc = atexit(atexit_handler);
+	if (rc)
+		exit(127);
+
+	char *sel_str = getenv("BITHENGE_FAILURE_INDEX");
+	if (sel_str)
+		g_failure_index_selected = strtol(sel_str, NULL, 10);
+}
+
+/* Record a hit for a backtrace address and return whether this is the first
+ * hit. */
+static inline int backtrace_item_hit(void *addr)
+{
+	backtrace_item_t **bip;
+	for (bip = &g_backtrace_items; *bip; bip = &(*bip)->next) {
+		backtrace_item_t *bi = *bip;
+		if (bi->backtrace_item == addr) {
+			/* Keep frequently accessed items near the front. */
+			*bip = bi->next;
+			bi->next = g_backtrace_items;
+			g_backtrace_items = bi;
+			return 0;
+		}
+	}
+
+	/* No item found; create one. */
+	backtrace_item_t *i = malloc(sizeof(*i));
+	if (!i)
+		exit(127);
+	i->next = g_backtrace_items;
+	i->backtrace_item = addr;
+	g_backtrace_items = i;
+	return 1;
+}
+
+int bithenge_should_fail(void)
+{
+	g_failure_index++;
+
+	if (!g_initialized)
+		initialize();
+
+	if (g_failure_index_selected != -1) {
+		if (g_failure_index == g_failure_index_selected)
+			return 1; /* breakpoint here */
+		return 0;
+	}
+
+	/* If all backtrace items have been seen already, there's no need to
+	 * try raising an error. */
+	void *trace[256];
+	int size = backtrace(trace, 256);
+	int raise_error = 0;
+	for (int i = 0; i < size; i++) {
+		if (backtrace_item_hit(trace[i]))
+			raise_error = 1;
+	}
+	if (!raise_error)
+		return 0;
+
+	if (!fork()) {
+		/* Child silently fails. */
+		int null = open("/dev/null", O_WRONLY);
+		if (null == -1)
+			exit(127);
+		dup2(null, STDOUT_FILENO);
+		dup2(null, STDERR_FILENO);
+		close(null);
+		return 1;
+	}
+
+	/* Parent checks whether child failed correctly. */
+	int status;
+	wait(&status);
+	if (WIFEXITED(status) && WEXITSTATUS(status) == 1)
+		return 0;
+
+	/* The child had an error! We couldn't easily debug it because it was
+	 * in a separate process with redirected stdout and stderr. Do it again
+	 * without redirecting or forking. */
+	fprintf(stderr, "** Fake error raised here (BITHENGE_FAILURE_INDEX=%d)\n",
+	    g_failure_index);
+	return 1;
+}
+
+void *bithenge_failure_malloc(size_t size)
+{
+	if (bithenge_should_fail())
+		return NULL;
+	return malloc(size);
+}
+
+void *bithenge_failure_realloc(void *ptr, size_t size)
+{
+	if (bithenge_should_fail())
+		return NULL;
+	return realloc(ptr, size);
+}
+
+ssize_t bithenge_failure_read(int fd, void *buf, size_t count)
+{
+	if (bithenge_should_fail()) {
+		errno = EIO;
+		return -1;
+	}
+	return read(fd, buf, count);
+}
+
+off_t bithenge_failure_lseek(int fd, off_t offset, int whither)
+{
+	if (bithenge_should_fail()) {
+		errno = EINVAL;
+		return (off_t) -1;
+	}
+	return lseek(fd, offset, whither);
+}
+
+int bithenge_failure_ferror(FILE *stream)
+{
+	if (bithenge_should_fail())
+		return 1;
+	return ferror(stream);
+}
+
+char *bithenge_failure_str_ndup(const char *s, size_t max_len)
+{
+	if (bithenge_should_fail())
+		return NULL;
+	return str_ndup(s, max_len);
+}
+
+int bithenge_failure_open(const char *pathname, int flags)
+{
+	if (bithenge_should_fail()) {
+		errno = EACCES;
+		return -1;
+	}
+	return open(pathname, flags);
+}
+
+int bithenge_failure_fstat(int fd, struct stat *buf)
+{
+	if (bithenge_should_fail()) {
+		errno = EIO;
+		return -1;
+	}
+	return fstat(fd, buf);
+}
+
+/** @}
+ */
+/** @endcond */
Index: uspace/lib/bithenge/src/failure.h
===================================================================
--- uspace/lib/bithenge/src/failure.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/failure.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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.
+ */
+
+/** @cond internal */
+/** @addtogroup bithenge
+ * @{
+ */
+/**
+ * @file
+ * Fake system call errors for testing.
+ */
+
+#ifndef BITHENGE_FAILURE_H_
+#define BITHENGE_FAILURE_H_
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+int bithenge_should_fail(void);
+void *bithenge_failure_malloc(size_t);
+void *bithenge_failure_realloc(void *, size_t);
+ssize_t bithenge_failure_read(int, void *, size_t);
+off_t bithenge_failure_lseek(int, off_t, int);
+int bithenge_failure_ferror(FILE *);
+char *bithenge_failure_str_ndup(const char *, size_t);
+int bithenge_failure_open(const char *, int);
+int bithenge_failure_fstat(int, struct stat *);
+
+#ifndef BITHENGE_FAILURE_DECLS_ONLY
+#define malloc bithenge_failure_malloc
+#define realloc bithenge_failure_realloc
+#define read bithenge_failure_read
+#define lseek bithenge_failure_lseek
+#define ferror bithenge_failure_ferror
+#define str_ndup bithenge_failure_str_ndup
+#define open bithenge_failure_open
+#define fstat bithenge_failure_fstat
+#endif
+
+#endif
+
+/** @}
+ */
+
+/** @endcond */
+
Index: uspace/lib/bithenge/src/file.c
===================================================================
--- uspace/lib/bithenge/src/file.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/file.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Access files as blobs.
+ * @todo Provide more information about the file.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "common.h"
+#include <bithenge/blob.h>
+#include <bithenge/file.h>
+
+typedef struct {
+	bithenge_blob_t base;
+	int fd;
+	aoff64_t size; // needed by file_read()
+	bool needs_close;
+} file_blob_t;
+
+static inline file_blob_t *blob_as_file(bithenge_blob_t *base)
+{
+	return (file_blob_t *)base;
+}
+
+static inline bithenge_blob_t *file_as_blob(file_blob_t *blob)
+{
+	return &blob->base;
+}
+
+static int file_size(bithenge_blob_t *base, aoff64_t *size)
+{
+	file_blob_t *blob = blob_as_file(base);
+	*size = blob->size;
+	return EOK;
+}
+
+static int file_read(bithenge_blob_t *base, aoff64_t offset, char *buffer,
+    aoff64_t *size)
+{
+	file_blob_t *blob = blob_as_file(base);
+	if (offset > blob->size)
+		return ELIMIT;
+	if (lseek(blob->fd, offset, SEEK_SET) < 0)
+		return errno == EINVAL ? EIO : errno;
+
+	ssize_t amount_read;
+	aoff64_t remaining_size = *size;
+	*size = 0;
+	do {
+		amount_read = read(blob->fd, buffer, remaining_size);
+		if (amount_read < 0)
+			return errno;
+		buffer += amount_read;
+		*size += amount_read;
+		remaining_size -= amount_read;
+	} while (remaining_size && amount_read);
+	return EOK;
+}
+
+static void file_destroy(bithenge_blob_t *base)
+{
+	file_blob_t *blob = blob_as_file(base);
+	close(blob->fd);
+	free(blob);
+}
+
+static const bithenge_random_access_blob_ops_t file_ops = {
+	.size = file_size,
+	.read = file_read,
+	.destroy = file_destroy,
+};
+
+static int new_file_blob(bithenge_node_t **out, int fd, bool needs_close)
+{
+	assert(out);
+
+	struct stat stat;
+	int rc = fstat(fd, &stat);
+	if (rc != EOK) {
+		if (needs_close)
+			close(fd);
+		return rc;
+	}
+
+	// Create blob
+	file_blob_t *blob = malloc(sizeof(*blob));
+	if (!blob) {
+		if (needs_close)
+			close(fd);
+		return ENOMEM;
+	}
+	rc = bithenge_init_random_access_blob(file_as_blob(blob), &file_ops);
+	if (rc != EOK) {
+		free(blob);
+		if (needs_close)
+			close(fd);
+		return rc;
+	}
+	blob->fd = fd;
+#ifdef __HELENOS__
+	blob->size = stat.size;
+#else
+	blob->size = stat.st_size;
+#endif
+	blob->needs_close = needs_close;
+	*out = bithenge_blob_as_node(file_as_blob(blob));
+
+	return EOK;
+}
+
+/** Create a blob for a file. The blob must be freed with @a
+ * bithenge_node_t::bithenge_node_destroy after it is used.
+ * @param[out] out Stores the created blob.
+ * @param filename The name of the file.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_file_blob(bithenge_node_t **out, const char *filename)
+{
+	assert(filename);
+
+	int fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		return fd;
+
+	return new_file_blob(out, fd, true);
+}
+
+/** Create a blob for a file descriptor. The blob must be freed with @a
+ * bithenge_node_t::bithenge_node_destroy after it is used.
+ * @param[out] out Stores the created blob.
+ * @param fd The file descriptor.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_file_blob_from_fd(bithenge_node_t **out, int fd)
+{
+	return new_file_blob(out, fd, false);
+}
+
+/** Create a blob for a file pointer. The blob must be freed with @a
+ * bithenge_node_t::bithenge_node_destroy after it is used.
+ * @param[out] out Stores the created blob.
+ * @param file The file pointer.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_file_blob_from_file(bithenge_node_t **out, FILE *file)
+{
+	int fd = fileno(file);
+	if (fd < 0)
+		return errno;
+	return new_file_blob(out, fd, false);
+}
+
+/** @}
+ */
Index: uspace/lib/bithenge/src/helenos/block.c
===================================================================
--- uspace/lib/bithenge/src/helenos/block.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/helenos/block.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Access block devices as blobs.
+ * @todo Provide more information about the block device (block size).
+ */
+
+#include <assert.h>
+#include <block.h>
+#include <errno.h>
+#include <loc.h>
+#include <macros.h>
+#include <stdlib.h>
+#include <bithenge/blob.h>
+#include "block.h"
+
+typedef struct {
+	bithenge_blob_t base;
+	service_id_t service_id;
+	aoff64_t size;
+} block_blob_t;
+
+static inline block_blob_t *blob_as_block(bithenge_blob_t *base)
+{
+	return (block_blob_t *)base;
+}
+
+static inline bithenge_blob_t *block_as_blob(block_blob_t *blob)
+{
+	return &blob->base;
+}
+
+static int block_size(bithenge_blob_t *base, aoff64_t *size)
+{
+	block_blob_t *self = blob_as_block(base);
+	*size = self->size;
+	return EOK;
+}
+
+static int block_read(bithenge_blob_t *base, aoff64_t offset, char *buffer,
+    aoff64_t *size)
+{
+	block_blob_t *self = blob_as_block(base);
+	if (offset > self->size)
+		return ELIMIT;
+	*size = min(*size, self->size - offset);
+	return block_read_bytes_direct(self->service_id, offset, *size, buffer);
+}
+
+static void block_destroy(bithenge_blob_t *base)
+{
+	block_blob_t *self = blob_as_block(base);
+	block_fini(self->service_id);
+	free(self);
+}
+
+static const bithenge_random_access_blob_ops_t block_ops = {
+	.size = block_size,
+	.read = block_read,
+	.destroy = block_destroy,
+};
+
+/** Create a blob for a block device. The blob must be freed with
+ * @a bithenge_node_t::bithenge_node_destroy after it is used.
+ * @param[out] out Stores the created blob.
+ * @param service_id The service ID of the block device.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_block_blob(bithenge_node_t **out, service_id_t service_id)
+{
+	assert(out);
+
+	// Initialize libblock
+	int rc;
+	rc = block_init(EXCHANGE_SERIALIZE, service_id, 2048);
+	if (rc != EOK)
+		return rc;
+
+	// Calculate total device size
+	size_t bsize;
+	aoff64_t nblocks;
+	aoff64_t size;
+	rc = block_get_bsize(service_id, &bsize);
+	if (rc != EOK) {
+		block_fini(service_id);
+		return rc;
+	}
+	rc = block_get_nblocks(service_id, &nblocks);
+	if (rc != EOK) {
+		block_fini(service_id);
+		return rc;
+	}
+	size = bsize * nblocks;
+
+	// Create blob
+	block_blob_t *blob = malloc(sizeof(*blob));
+	if (!blob) {
+		block_fini(service_id);
+		return ENOMEM;
+	}
+	rc = bithenge_init_random_access_blob(block_as_blob(blob),
+	    &block_ops);
+	if (rc != EOK) {
+		free(blob);
+		block_fini(service_id);
+		return rc;
+	}
+	blob->service_id = service_id;
+	blob->size = size;
+	*out = bithenge_blob_as_node(block_as_blob(blob));
+
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/lib/bithenge/src/helenos/block.h
===================================================================
--- uspace/lib/bithenge/src/helenos/block.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/helenos/block.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Access block devices as blobs.
+ */
+
+#ifndef BITHENGE_BLOCK_H_
+#define BITHENGE_BLOCK_H_
+
+#include <loc.h>
+#include <bithenge/tree.h>
+
+int bithenge_new_block_blob(bithenge_node_t **, service_id_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/bithenge/src/helenos/common.h
===================================================================
--- uspace/lib/bithenge/src/helenos/common.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/helenos/common.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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.
+ */
+
+#ifndef BITHENGE_HELENOS_COMMON_H_
+#define BITHENGE_HELENOS_COMMON_H_
+
+#include <bithenge/os.h>
+#include <bool.h>
+#include <byteorder.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <macros.h>
+#include <mem.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str.h>
+#include <str_error.h>
+
+#define BITHENGE_PRId PRId64
+
+typedef struct {
+	const char *string;
+	size_t offset;
+	wchar_t ch;
+} string_iterator_t;
+
+static inline string_iterator_t string_iterator(const char *string)
+{
+	string_iterator_t i;
+	i.string = string;
+	i.offset = 0;
+	i.ch = str_decode(i.string, &i.offset, STR_NO_LIMIT);
+	return i;
+}
+
+static inline bool string_iterator_done(const string_iterator_t *i)
+{
+	return i->ch == L'\0';
+}
+
+static inline int string_iterator_next(string_iterator_t *i, wchar_t *out)
+{
+	*out = i->ch;
+	if (*out == U_SPECIAL)
+		return EINVAL;
+	i->ch = str_decode(i->string, &i->offset, STR_NO_LIMIT);
+	return EOK;
+}
+
+static inline void *memchr(const void *s, int c, size_t n)
+{
+	for (size_t i = 0; i < n; i++)
+		if (((char *)s)[i] == c)
+			return (void *)(s + i);
+	return NULL;
+}
+
+static inline int bithenge_parse_int(const char *start, bithenge_int_t *result)
+{
+	const char *real_start = *start == '-' ? start + 1 : start;
+	uint64_t val;
+	int rc = str_uint64_t(real_start, NULL, 10, false, &val);
+	*result = val;
+	if (*start == '-')
+		*result = -*result;
+	return rc;
+}
+
+#endif
Index: uspace/lib/bithenge/src/linux/common.h
===================================================================
--- uspace/lib/bithenge/src/linux/common.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/linux/common.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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.
+ */
+
+#ifndef BITHENGE_LINUX_COMMON_H_
+#define BITHENGE_LINUX_COMMON_H_
+
+#include <endian.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <memory.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#define max(aleph, bet) ((aleph) > (bet) ? (aleph) : (bet))
+#define min(aleph, bet) ((aleph) < (bet) ? (aleph) : (bet))
+
+#define EOK 0
+#define ELIMIT EINVAL
+
+typedef intmax_t bithenge_int_t;
+#define BITHENGE_PRId PRIdMAX
+typedef uint64_t aoff64_t;
+typedef const char *string_iterator_t;
+
+static inline string_iterator_t string_iterator(const char *string)
+{
+	return string;
+}
+
+static inline int string_iterator_next(string_iterator_t *i, wchar_t *out)
+{
+	wint_t rc = btowc(*(*i)++); // TODO
+	*out = (wchar_t) rc;
+	return rc == WEOF ? EILSEQ : EOK;
+}
+
+static inline bool string_iterator_done(const string_iterator_t *i)
+{
+	return !**i;
+}
+
+static inline size_t str_length(const char *string)
+{
+	return strlen(string);
+}
+
+static inline const char *str_chr(const char *string, wchar_t ch)
+{
+	return strchr(string, wctob(ch)); // TODO
+}
+
+static inline int str_cmp(const char *s1, const char *s2)
+{
+	return strcmp(s1, s2);
+}
+
+static inline int str_lcmp(const char *s1, const char *s2, size_t max_len)
+{
+	return strncmp(s1, s2, max_len);
+}
+
+static inline char *str_dup(const char *s)
+{
+	return strdup(s);
+}
+
+static inline char *str_ndup(const char *s, size_t max_len)
+{
+	return strndup(s, max_len);
+}
+
+static inline const char *str_error(int e)
+{
+	return strerror(e);
+}
+
+static inline uint16_t uint16_t_le2host(uint16_t val)
+{
+	return le16toh(val);
+}
+
+static inline uint16_t uint16_t_be2host(uint16_t val)
+{
+	return be16toh(val);
+}
+
+static inline uint32_t uint32_t_le2host(uint32_t val)
+{
+	return le32toh(val);
+}
+
+static inline uint32_t uint32_t_be2host(uint32_t val)
+{
+	return be32toh(val);
+}
+
+static inline uint64_t uint64_t_le2host(uint64_t val)
+{
+	return le64toh(val);
+}
+
+static inline uint64_t uint64_t_be2host(uint64_t val)
+{
+	return be64toh(val);
+}
+
+static inline int bithenge_parse_int(const char *start, bithenge_int_t *result)
+{
+	errno = 0;
+	*result = strtoll(start, NULL, 10);
+	return errno;
+}
+
+#endif
Index: uspace/lib/bithenge/src/print.c
===================================================================
--- uspace/lib/bithenge/src/print.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/print.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Write a tree as JSON or other text formats.
+ * @todo Allow more control over the printing style, and handle printing in
+ * limited space.
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <bithenge/blob.h>
+#include <bithenge/print.h>
+#include <bithenge/tree.h>
+#include "common.h"
+
+typedef struct {
+	bithenge_print_type_t type;
+	bool first;
+	int depth;
+	char *buffer;
+	size_t buffer_size;
+} state_t;
+
+static void state_printf(state_t *state, const char *format, ...)
+{
+	va_list ap;
+	va_start(ap, format);
+	if (state->buffer) {
+		int rc = vsnprintf(state->buffer, state->buffer_size, format,
+		    ap);
+		if (rc > 0 && (size_t)rc >= state->buffer_size)
+			rc = state->buffer_size - 1;
+		if (rc > 0) {
+			state->buffer += rc;
+			state->buffer_size -= rc;
+		}
+	} else {
+		vprintf(format, ap);
+	}
+	va_end(ap);
+}
+
+static int print_node(state_t *, bithenge_node_t *);
+
+static void newline(state_t *state)
+{
+	state_printf(state, "\n");
+	for (int i = 0; i < state->depth; i++) {
+		state_printf(state, "    ");
+	}
+}
+
+static void increase_depth(state_t *state)
+{
+	state->depth++;
+}
+
+static void decrease_depth(state_t *state)
+{
+	state->depth--;
+}
+
+static int print_internal_func(bithenge_node_t *key, bithenge_node_t *value, void *data)
+{
+	state_t *state = (state_t *)data;
+	int rc = EOK;
+	if (!state->first)
+		state_printf(state, ",");
+	newline(state);
+	state->first = false;
+	bool add_quotes = state->type == BITHENGE_PRINT_JSON
+	    && bithenge_node_type(key) != BITHENGE_NODE_STRING;
+	if (add_quotes)
+		state_printf(state, "\"");
+	rc = print_node(state, key);
+	if (rc != EOK)
+		goto end;
+	if (add_quotes)
+		state_printf(state, "\"");
+	state_printf(state, ": ");
+	rc = print_node(state, value);
+	if (rc != EOK)
+		goto end;
+end:
+	bithenge_node_dec_ref(key);
+	bithenge_node_dec_ref(value);
+	return rc;
+}
+
+static int print_internal(state_t *state, bithenge_node_t *node)
+{
+	int rc;
+	state_printf(state, "{");
+	increase_depth(state);
+	state->first = true;
+	rc = bithenge_node_for_each(node, print_internal_func, state);
+	if (rc != EOK)
+		return rc;
+	decrease_depth(state);
+	if (!state->first)
+		newline(state);
+	state->first = false;
+	state_printf(state, "}");
+	return EOK;
+}
+
+static int print_boolean(state_t *state, bithenge_node_t *node)
+{
+	bool value = bithenge_boolean_node_value(node);
+	switch (state->type) {
+	case BITHENGE_PRINT_PYTHON:
+		state_printf(state, value ? "True" : "False");
+		break;
+	case BITHENGE_PRINT_JSON:
+		state_printf(state, value ? "true" : "false");
+		break;
+	}
+	return EOK;
+}
+
+static int print_integer(state_t *state, bithenge_node_t *node)
+{
+	bithenge_int_t value = bithenge_integer_node_value(node);
+	state_printf(state, "%" BITHENGE_PRId, value);
+	return EOK;
+}
+
+static int print_string(state_t *state, bithenge_node_t *node)
+{
+	const char *value = bithenge_string_node_value(node);
+	state_printf(state, "\"");
+	for (string_iterator_t i = string_iterator(value); !string_iterator_done(&i); ) {
+		wchar_t ch;
+		int rc = string_iterator_next(&i, &ch);
+		if (rc != EOK)
+			return rc;
+		if (ch == '"' || ch == '\\') {
+			state_printf(state, "\\%lc", (wint_t) ch);
+		} else if (ch <= 0x1f) {
+			state_printf(state, "\\u%04x", (unsigned int) ch);
+		} else {
+			state_printf(state, "%lc", (wint_t) ch);
+		}
+	}
+	state_printf(state, "\"");
+	return EOK;
+}
+
+static int print_blob(state_t *state, bithenge_node_t *node)
+{
+	bithenge_blob_t *blob = bithenge_node_as_blob(node);
+	aoff64_t pos = 0;
+	uint8_t buffer[1024];
+	aoff64_t size = sizeof(buffer);
+	int rc;
+	state_printf(state,
+	    state->type == BITHENGE_PRINT_PYTHON ? "b\"" : "\"");
+	do {
+		rc = bithenge_blob_read(blob, pos, (char *)buffer, &size);
+		if (rc != EOK)
+			return rc;
+		for (aoff64_t i = 0; i < size; i++)
+			state_printf(state, "\\x%02x",
+			    (unsigned int)buffer[i]);
+		pos += size;
+	} while (size == sizeof(buffer));
+	state_printf(state, "\"");
+	return EOK;
+}
+
+static int print_node(state_t *state, bithenge_node_t *tree)
+{
+	switch (bithenge_node_type(tree)) {
+	case BITHENGE_NODE_INTERNAL:
+		return print_internal(state, tree);
+	case BITHENGE_NODE_BOOLEAN:
+		return print_boolean(state, tree);
+	case BITHENGE_NODE_INTEGER:
+		return print_integer(state, tree);
+	case BITHENGE_NODE_STRING:
+		return print_string(state, tree);
+	case BITHENGE_NODE_BLOB:
+		return print_blob(state, tree);
+	}
+	return ENOTSUP;
+}
+
+/** Print a tree as text to stdout.
+ * @param type The format to use.
+ * @param tree The root node of the tree to print.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_print_node(bithenge_print_type_t type, bithenge_node_t *tree)
+{
+	state_t state = {type, true, 0, NULL, 0};
+	return print_node(&state, tree);
+}
+
+/** Print a tree as text into a buffer.
+ * @param[in,out] str Holds a pointer to the buffer; changed to point to the
+ * null character.
+ * @param[in,out] size Holds the size of the buffer; changed to hold the
+ * remaining size.
+ * @param type The format to use.
+ * @param tree The root node of the tree to print.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_print_node_to_string(char **str, size_t *size,
+    bithenge_print_type_t type, bithenge_node_t *tree)
+{
+	state_t state = {type, true, 0, *str, *size};
+	int rc = print_node(&state, tree);
+	*str = state.buffer;
+	*size = state.buffer_size;
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/bithenge/src/script.c
===================================================================
--- uspace/lib/bithenge/src/script.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/script.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,1340 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Script parsing.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <bithenge/compound.h>
+#include <bithenge/expression.h>
+#include <bithenge/script.h>
+#include <bithenge/sequence.h>
+#include <bithenge/transform.h>
+#include <bithenge/tree.h>
+#include "common.h"
+
+/** @cond internal */
+#define BUFFER_SIZE 4096
+/** @endcond */
+
+/** Tokens with more characters than this may be read incorrectly. */
+static const int MAX_TOKEN_SIZE = 256;
+
+/** @cond internal
+ * Single-character symbols are represented by the character itself. Every
+ * other token uses one of these values: */
+typedef enum {
+	TOKEN_ERROR = -128,
+
+	TOKEN_AND,
+	TOKEN_CONCAT,
+	TOKEN_EQUALS,
+	TOKEN_EOF,
+	TOKEN_GREATER_THAN_OR_EQUAL,
+	TOKEN_IDENTIFIER,
+	TOKEN_INTEGER,
+	TOKEN_INTEGER_DIVIDE,
+	TOKEN_LEFT_ARROW,
+	TOKEN_LESS_THAN_OR_EQUAL,
+	TOKEN_NOT_EQUAL,
+	TOKEN_OR,
+
+	/* Keywords */
+	TOKEN_DO,
+	TOKEN_ELSE,
+	TOKEN_FALSE,
+	TOKEN_IF,
+	TOKEN_IN,
+	TOKEN_PARTIAL,
+	TOKEN_REPEAT,
+	TOKEN_STRUCT,
+	TOKEN_SWITCH,
+	TOKEN_TRANSFORM,
+	TOKEN_TRUE,
+	TOKEN_WHILE,
+} token_type_t;
+/** @endcond */
+
+/** Singly-linked list of named transforms. */
+typedef struct transform_list {
+	char *name;
+	bithenge_transform_t *transform;
+	struct transform_list *next;
+} transform_list_t;
+
+/** State kept by the parser. */
+typedef struct {
+	/** Rather than constantly checking return values, the parser uses this
+	 * to indicate whether an error has occurred. */
+	int error;
+
+	/** The list of named transforms. */
+	transform_list_t *transform_list;
+
+	/** The name of the script file. */
+	const char *filename;
+	/** The script file being read from. */
+	FILE *file;
+	/** The buffer that holds script code. There is always a '\0' after the
+	 * current position to prevent reading too far. */
+	char buffer[BUFFER_SIZE];
+	/** The start position within the buffer of the next unread token. */
+	size_t buffer_pos;
+	/** The start position within the buffer of the current token. */
+	size_t old_buffer_pos;
+	/** The line number of the current token. */
+	int lineno;
+	/** Added to a buffer position to find the column number. */
+	int line_offset;
+
+	/** The type of the current token. */
+	token_type_t token;
+	union {
+		/** The value of a TOKEN_IDENTIFIER token. Unless changed to
+		 * NULL, it will be freed when the next token is read. */
+		char *token_string;
+		/** The value of a TOKEN_INTEGER token. */
+		bithenge_int_t token_int;
+	};
+
+	/** The names of the current transform's parameters. */
+	char **parameter_names;
+	/** The number of parameters. */
+	int num_params;
+	/** @a parse_expression sets this when TOKEN_IN is used. */
+	bool in_node_used;
+} state_t;
+
+/** Free the previous token's data. This must be called before changing
+ * state->token. */
+static void done_with_token(state_t *state)
+{
+	if (state->token == TOKEN_IDENTIFIER)
+		free(state->token_string);
+	state->token = TOKEN_ERROR;
+}
+
+/** Note that an error has occurred if error is not EOK. */
+static void error_errno(state_t *state, int error)
+{
+	// Don't overwrite a previous error.
+	if (state->error == EOK && error != EOK) {
+		done_with_token(state);
+		state->token = TOKEN_ERROR;
+		state->error = error;
+	}
+}
+
+/** Note that a syntax error has occurred and print an error message. */
+static void syntax_error(state_t *state, const char *message)
+{
+	// Printing multiple errors is confusing.
+	if (state->error == EOK) {
+		size_t start_char = state->old_buffer_pos + state->line_offset;
+		size_t end_char = state->buffer_pos + state->line_offset;
+		size_t size = end_char - start_char;
+		fprintf(stderr, "%s:%d:", state->filename, state->lineno);
+		if (size <= 1)
+			fprintf(stderr, "%zd: ", start_char);
+		else
+			fprintf(stderr, "%zd-%zd: ", start_char, end_char - 1);
+		fprintf(stderr, "%s: \"%.*s\"\n", message, (int)size,
+		    state->buffer + state->old_buffer_pos);
+		error_errno(state, EINVAL);
+	}
+}
+
+/** Ensure the buffer contains enough characters to read a token. */
+static void fill_buffer(state_t *state)
+{
+	if (state->buffer_pos + MAX_TOKEN_SIZE < BUFFER_SIZE)
+		return;
+
+	size_t empty_size = state->buffer_pos;
+	size_t used_size = BUFFER_SIZE - 1 - state->buffer_pos;
+	memmove(state->buffer, state->buffer + state->buffer_pos, used_size);
+	state->line_offset += state->buffer_pos;
+	state->buffer_pos = 0;
+
+	size_t read_size = fread(state->buffer + used_size, 1, empty_size,
+	    state->file);
+	if (ferror(state->file))
+		error_errno(state, EIO);
+	state->buffer[used_size + read_size] = '\0';
+}
+
+/** Read the next token. */
+static void next_token(state_t *state)
+{
+	fill_buffer(state);
+	done_with_token(state);
+	state->old_buffer_pos = state->buffer_pos;
+	char ch = state->buffer[state->buffer_pos];
+	if (ch == '\0') {
+		state->token = TOKEN_EOF;
+	} else if (ch == '#') {
+		while (state->buffer[state->buffer_pos] != '\n'
+		    && state->buffer[state->buffer_pos] != '\0') {
+			state->buffer_pos++;
+			fill_buffer(state);
+		}
+		next_token(state);
+		return;
+	} else if (isspace(ch)) {
+		// Will eventually reach the '\0' at the end
+		while (isspace(state->buffer[state->buffer_pos])) {
+			if (state->buffer[state->buffer_pos] == '\n') {
+				state->lineno++;
+				state->line_offset = -state->buffer_pos;
+			}
+			state->buffer_pos++;
+		}
+		next_token(state);
+		return;
+	} else if (isalpha(ch)) {
+		while (isalnum(state->buffer[state->buffer_pos])
+		    || state->buffer[state->buffer_pos] == '_')
+			state->buffer_pos++;
+		char *value = str_ndup(state->buffer + state->old_buffer_pos,
+		    state->buffer_pos - state->old_buffer_pos);
+		if (!value) {
+			error_errno(state, ENOMEM);
+		} else if (!str_cmp(value, "do")) {
+			state->token = TOKEN_DO;
+			free(value);
+		} else if (!str_cmp(value, "else")) {
+			state->token = TOKEN_ELSE;
+			free(value);
+		} else if (!str_cmp(value, "false")) {
+			state->token = TOKEN_FALSE;
+			free(value);
+		} else if (!str_cmp(value, "if")) {
+			state->token = TOKEN_IF;
+			free(value);
+		} else if (!str_cmp(value, "in")) {
+			state->token = TOKEN_IN;
+			free(value);
+		} else if (!str_cmp(value, "partial")) {
+			state->token = TOKEN_PARTIAL;
+			free(value);
+		} else if (!str_cmp(value, "repeat")) {
+			state->token = TOKEN_REPEAT;
+			free(value);
+		} else if (!str_cmp(value, "struct")) {
+			state->token = TOKEN_STRUCT;
+			free(value);
+		} else if (!str_cmp(value, "switch")) {
+			state->token = TOKEN_SWITCH;
+			free(value);
+		} else if (!str_cmp(value, "transform")) {
+			state->token = TOKEN_TRANSFORM;
+			free(value);
+		} else if (!str_cmp(value, "true")) {
+			state->token = TOKEN_TRUE;
+			free(value);
+		} else if (!str_cmp(value, "while")) {
+			state->token = TOKEN_WHILE;
+			free(value);
+		} else {
+			state->token = TOKEN_IDENTIFIER;
+			state->token_string = value;
+		}
+	} else if (isdigit(ch)) {
+		while (isdigit(state->buffer[state->buffer_pos]))
+			state->buffer_pos++;
+		state->token = TOKEN_INTEGER;
+		int rc = bithenge_parse_int(state->buffer +
+		    state->old_buffer_pos, &state->token_int);
+		error_errno(state, rc);
+	} else if (ch == '<') {
+		state->token = ch;
+		state->buffer_pos++;
+		if (state->buffer[state->buffer_pos] == '-') {
+			state->buffer_pos++;
+			state->token = TOKEN_LEFT_ARROW;
+		} else if (state->buffer[state->buffer_pos] == '=') {
+			state->buffer_pos++;
+			state->token = TOKEN_LESS_THAN_OR_EQUAL;
+		}
+	} else if (ch == '>') {
+		state->token = ch;
+		state->buffer_pos++;
+		if (state->buffer[state->buffer_pos] == '=') {
+			state->buffer_pos++;
+			state->token = TOKEN_GREATER_THAN_OR_EQUAL;
+		}
+	} else if (ch == '=') {
+		state->token = ch;
+		state->buffer_pos++;
+		if (state->buffer[state->buffer_pos] == '=') {
+			state->token = TOKEN_EQUALS;
+			state->buffer_pos++;
+		}
+	} else if (ch == '/') {
+		state->token = ch;
+		state->buffer_pos++;
+		if (state->buffer[state->buffer_pos] == '/') {
+			state->token = TOKEN_INTEGER_DIVIDE;
+			state->buffer_pos++;
+		}
+	} else if (ch == '!') {
+		state->token = ch;
+		state->buffer_pos++;
+		if (state->buffer[state->buffer_pos] == '=') {
+			state->token = TOKEN_NOT_EQUAL;
+			state->buffer_pos++;
+		}
+	} else if (ch == '&') {
+		state->token = ch;
+		state->buffer_pos++;
+		if (state->buffer[state->buffer_pos] == '&') {
+			state->token = TOKEN_AND;
+			state->buffer_pos++;
+		}
+	} else if (ch == '|') {
+		state->token = ch;
+		state->buffer_pos++;
+		if (state->buffer[state->buffer_pos] == '|') {
+			state->token = TOKEN_OR;
+			state->buffer_pos++;
+		}
+	} else if (ch == '+') {
+		state->token = ch;
+		state->buffer_pos++;
+		if (state->buffer[state->buffer_pos] == '+') {
+			state->token = TOKEN_CONCAT;
+			state->buffer_pos++;
+		}
+	} else {
+		state->token = ch;
+		state->buffer_pos++;
+	}
+}
+
+/** Allocate memory and handle failure by setting the error in the state. The
+ * caller must check the state for errors before using the return value of this
+ * function. */
+static void *state_malloc(state_t *state, size_t size)
+{
+	if (state->error != EOK)
+		return NULL;
+	void *result = malloc(size);
+	if (result == NULL)
+		error_errno(state, ENOMEM);
+	return result;
+}
+
+/** Reallocate memory and handle failure by setting the error in the state. If
+ * an error occurs, the existing pointer will be returned. */
+static void *state_realloc(state_t *state, void *ptr, size_t size)
+{
+	if (state->error != EOK)
+		return ptr;
+	void *result = realloc(ptr, size);
+	if (result == NULL) {
+		error_errno(state, ENOMEM);
+		return ptr;
+	}
+	return result;
+}
+
+/** Expect and consume a certain token. If the next token is of the wrong type,
+ * an error is caused. */
+static void expect(state_t *state, token_type_t type)
+{
+	if (state->token != type) {
+		syntax_error(state, "unexpected");
+		return;
+	}
+	next_token(state);
+}
+
+/** Expect and consume an identifier token. If the next token is not an
+ * identifier, an error is caused and this function returns null. */
+static char *expect_identifier(state_t *state)
+{
+	if (state->token != TOKEN_IDENTIFIER) {
+		syntax_error(state, "unexpected (identifier expected)");
+		return NULL;
+	}
+	char *val = state->token_string;
+	state->token_string = NULL;
+	next_token(state);
+	return val;
+}
+
+/** Find a transform by name. A reference will be added to the transform.
+ * @return The found transform, or NULL if none was found. */
+static bithenge_transform_t *get_named_transform(state_t *state,
+    const char *name)
+{
+	for (transform_list_t *e = state->transform_list; e; e = e->next) {
+		if (!str_cmp(e->name, name)) {
+			bithenge_transform_inc_ref(e->transform);
+			return e->transform;
+		}
+	}
+	for (int i = 0; bithenge_primitive_transforms[i].name; i++) {
+		if (!str_cmp(bithenge_primitive_transforms[i].name, name)) {
+			bithenge_transform_t *xform =
+			    bithenge_primitive_transforms[i].transform;
+			bithenge_transform_inc_ref(xform);
+			return xform;
+		}
+	}
+	return NULL;
+}
+
+/** Add a named transform. This function takes ownership of the name and a
+ * reference to the transform. If an error has occurred, either may be null. */
+static void add_named_transform(state_t *state, bithenge_transform_t *xform, char *name)
+{
+	transform_list_t *entry = state_malloc(state, sizeof(*entry));
+	if (state->error != EOK) {
+		free(name);
+		bithenge_transform_dec_ref(xform);
+		free(entry);
+		return;
+	}
+	entry->name = name;
+	entry->transform = xform;
+	entry->next = state->transform_list;
+	state->transform_list = entry;
+}
+
+static bithenge_transform_t *parse_transform(state_t *state);
+static bithenge_transform_t *parse_struct(state_t *state);
+static bithenge_expression_t *parse_expression(state_t *state);
+
+
+
+/***************** Expressions                               *****************/
+
+/** @cond internal */
+typedef enum {
+	PRECEDENCE_NONE,
+	PRECEDENCE_AND,
+	PRECEDENCE_EQUALS,
+	PRECEDENCE_COMPARE,
+	PRECEDENCE_ADD,
+	PRECEDENCE_MULTIPLY,
+} precedence_t;
+/** @endcond */
+
+static bithenge_binary_op_t token_as_binary_operator(token_type_t token)
+{
+	switch ((int)token) {
+	case '+':
+		return BITHENGE_EXPRESSION_ADD;
+	case '-':
+		return BITHENGE_EXPRESSION_SUBTRACT;
+	case '*':
+		return BITHENGE_EXPRESSION_MULTIPLY;
+	case TOKEN_INTEGER_DIVIDE:
+		return BITHENGE_EXPRESSION_INTEGER_DIVIDE;
+	case '%':
+		return BITHENGE_EXPRESSION_MODULO;
+	case '<':
+		return BITHENGE_EXPRESSION_LESS_THAN;
+	case TOKEN_LESS_THAN_OR_EQUAL:
+		return BITHENGE_EXPRESSION_LESS_THAN_OR_EQUAL;
+	case '>':
+		return BITHENGE_EXPRESSION_GREATER_THAN;
+	case TOKEN_GREATER_THAN_OR_EQUAL:
+		return BITHENGE_EXPRESSION_GREATER_THAN_OR_EQUAL;
+	case TOKEN_EQUALS:
+		return BITHENGE_EXPRESSION_EQUALS;
+	case TOKEN_NOT_EQUAL:
+		return BITHENGE_EXPRESSION_NOT_EQUALS;
+	case TOKEN_AND:
+		return BITHENGE_EXPRESSION_AND;
+	case TOKEN_OR:
+		return BITHENGE_EXPRESSION_OR;
+	case TOKEN_CONCAT:
+		return BITHENGE_EXPRESSION_CONCAT;
+	default:
+		return BITHENGE_EXPRESSION_INVALID_BINARY_OP;
+	}
+}
+
+static precedence_t binary_operator_precedence(bithenge_binary_op_t op)
+{
+	switch (op) {
+	case BITHENGE_EXPRESSION_ADD: /* fallthrough */
+	case BITHENGE_EXPRESSION_SUBTRACT: /* fallthrough */
+	case BITHENGE_EXPRESSION_CONCAT:
+		return PRECEDENCE_ADD;
+	case BITHENGE_EXPRESSION_MULTIPLY: /* fallthrough */
+	case BITHENGE_EXPRESSION_INTEGER_DIVIDE: /* fallthrough */
+	case BITHENGE_EXPRESSION_MODULO:
+		return PRECEDENCE_MULTIPLY;
+	case BITHENGE_EXPRESSION_LESS_THAN: /* fallthrough */
+	case BITHENGE_EXPRESSION_LESS_THAN_OR_EQUAL: /* fallthrough */
+	case BITHENGE_EXPRESSION_GREATER_THAN: /* fallthrough */
+	case BITHENGE_EXPRESSION_GREATER_THAN_OR_EQUAL:
+		return PRECEDENCE_COMPARE;
+	case BITHENGE_EXPRESSION_EQUALS: /* fallthrough */
+	case BITHENGE_EXPRESSION_NOT_EQUALS:
+		return PRECEDENCE_EQUALS;
+	case BITHENGE_EXPRESSION_AND: /* fallthrough */
+	case BITHENGE_EXPRESSION_OR:
+		return PRECEDENCE_AND;
+	default:
+		assert(false);
+		return PRECEDENCE_NONE;
+	}
+}
+
+static bithenge_expression_t *parse_term(state_t *state)
+{
+	int rc;
+	if (state->token == TOKEN_TRUE || state->token == TOKEN_FALSE) {
+		bool val = state->token == TOKEN_TRUE;
+		next_token(state);
+		bithenge_node_t *node;
+		rc = bithenge_new_boolean_node(&node, val);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+
+		bithenge_expression_t *expr;
+		rc = bithenge_const_expression(&expr, node);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+
+		return expr;
+	} else if (state->token == TOKEN_IN) {
+		next_token(state);
+		state->in_node_used = true;
+		bithenge_expression_t *expr;
+		rc = bithenge_in_node_expression(&expr);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+		return expr;
+	} else if (state->token == TOKEN_INTEGER) {
+		bithenge_int_t val = state->token_int;
+		next_token(state);
+		bithenge_node_t *node;
+		rc = bithenge_new_integer_node(&node, val);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+
+		bithenge_expression_t *expr;
+		rc = bithenge_const_expression(&expr, node);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+
+		return expr;
+	} else if (state->token == TOKEN_IDENTIFIER) {
+		int i;
+		for (i = 0; i < state->num_params; i++)
+			if (!str_cmp(state->parameter_names[i],
+			    state->token_string))
+				break;
+
+		if (i == state->num_params) {
+			syntax_error(state, "unknown identifier");
+			return NULL;
+		}
+
+		next_token(state);
+
+		bithenge_expression_t *expr;
+		rc = bithenge_param_expression(&expr, i);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+		return expr;
+	} else if (state->token == '.') {
+		next_token(state);
+
+		const char *id = expect_identifier(state);
+		bithenge_node_t *key = NULL;
+		bithenge_expression_t *expr = NULL;
+
+		if (state->error == EOK) {
+			rc = bithenge_new_string_node(&key, id, true);
+			id = NULL;
+			error_errno(state, rc);
+		}
+
+		if (state->error == EOK) {
+			rc = bithenge_scope_member_expression(&expr, key);
+			key = NULL;
+			if (rc != EOK)
+				expr = NULL;
+			error_errno(state, rc);
+		}
+
+		if (state->error != EOK) {
+			free((char *)id);
+			bithenge_node_dec_ref(key);
+			bithenge_expression_dec_ref(expr);
+			return NULL;
+		}
+
+		return expr;
+	} else if (state->token == '(') {
+		next_token(state);
+		bithenge_expression_t *expr = parse_expression(state);
+		expect(state, ')');
+		return expr;
+	} else {
+		syntax_error(state, "expression expected");
+		return NULL;
+	}
+}
+
+static bithenge_expression_t *parse_postfix_expression(state_t *state)
+{
+	int rc;
+	bithenge_expression_t *expr = parse_term(state);
+	while (state->error == EOK) {
+		if (state->token == '.') {
+			next_token(state);
+
+			const char *id = expect_identifier(state);
+
+			if (state->error != EOK) {
+				free((char *)id);
+				bithenge_expression_dec_ref(expr);
+				return NULL;
+			}
+
+			bithenge_node_t *key = NULL;
+			rc = bithenge_new_string_node(&key, id, true);
+			if (rc != EOK) {
+				error_errno(state, rc);
+				bithenge_expression_dec_ref(expr);
+				return NULL;
+			}
+
+			bithenge_expression_t *key_expr;
+			rc = bithenge_const_expression(&key_expr, key);
+			if (rc != EOK) {
+				error_errno(state, rc);
+				bithenge_expression_dec_ref(expr);
+				return NULL;
+			}
+
+			rc = bithenge_binary_expression(&expr,
+			    BITHENGE_EXPRESSION_MEMBER, expr, key_expr);
+			if (rc != EOK) {
+				error_errno(state, rc);
+				return NULL;
+			}
+		} else if (state->token == '[') {
+			next_token(state);
+			bithenge_expression_t *start = parse_expression(state);
+			bool absolute_limit = false;
+			if (state->token == ',' || state->token == ':') {
+				absolute_limit = state->token == ':';
+				next_token(state);
+				bithenge_expression_t *limit = NULL;
+				if (!(state->token == ']' && absolute_limit))
+					limit = parse_expression(state);
+				expect(state, ']');
+
+				if (state->error != EOK) {
+					bithenge_expression_dec_ref(expr);
+					bithenge_expression_dec_ref(start);
+					bithenge_expression_dec_ref(limit);
+					return NULL;
+				}
+				rc = bithenge_subblob_expression(&expr, expr, start,
+				    limit, absolute_limit);
+				if (rc != EOK) {
+					error_errno(state, rc);
+					return NULL;
+				}
+			} else if (state->token == ']') {
+				next_token(state);
+
+				if (state->error != EOK) {
+					bithenge_expression_dec_ref(expr);
+					bithenge_expression_dec_ref(start);
+					return NULL;
+				}
+				rc = bithenge_binary_expression(&expr,
+				    BITHENGE_EXPRESSION_MEMBER, expr, start);
+				if (rc != EOK) {
+					error_errno(state, rc);
+					return NULL;
+				}
+			} else {
+				syntax_error(state, "expected ',', ':', or ']'");
+				bithenge_expression_dec_ref(expr);
+				bithenge_expression_dec_ref(start);
+				return NULL;
+			}
+		} else {
+			break;
+		}
+	}
+	return expr;
+}
+
+static bithenge_expression_t *parse_expression_precedence(state_t *state,
+    precedence_t prev_precedence)
+{
+	bithenge_expression_t *expr = parse_postfix_expression(state);
+	while (state->error == EOK) {
+		bithenge_binary_op_t op =
+		    token_as_binary_operator(state->token);
+		if (op == BITHENGE_EXPRESSION_INVALID_BINARY_OP)
+			break;
+		precedence_t precedence = binary_operator_precedence(op);
+		if (precedence <= prev_precedence)
+			break;
+		next_token(state);
+
+		bithenge_expression_t *expr2 =
+		    parse_expression_precedence(state, precedence);
+		if (state->error != EOK) {
+			bithenge_expression_dec_ref(expr2);
+			break;
+		}
+		int rc = bithenge_binary_expression(&expr, op, expr, expr2);
+		if (rc != EOK) {
+			expr = NULL;
+			error_errno(state, rc);
+		}
+	}
+	if (state->error != EOK) {
+		bithenge_expression_dec_ref(expr);
+		expr = NULL;
+	}
+	return expr;
+}
+
+static bithenge_expression_t *parse_expression(state_t *state)
+{
+	return parse_expression_precedence(state, PRECEDENCE_NONE);
+}
+
+
+
+/* state->token must be TOKEN_IDENTIFIER when this is called. */
+static bithenge_transform_t *parse_invocation(state_t *state)
+{
+	bithenge_transform_t *result = get_named_transform(state,
+	    state->token_string);
+	if (!result)
+		syntax_error(state, "transform not found");
+	next_token(state);
+
+	bithenge_expression_t **params = NULL;
+	int num_params = 0;
+	if (state->token == '(') {
+		next_token(state);
+		while (state->error == EOK && state->token != ')') {
+			if (num_params)
+				expect(state, ',');
+			params = state_realloc(state, params,
+			    (num_params + 1)*sizeof(*params));
+			if (state->error != EOK)
+				break;
+			params[num_params] = parse_expression(state);
+			num_params++;
+		}
+		expect(state, ')');
+	}
+
+	/* TODO: show correct error position */
+	if (state->error == EOK
+	    && bithenge_transform_num_params(result) != num_params)
+		syntax_error(state, "incorrect number of parameters before");
+
+	if (state->error != EOK) {
+		while (num_params--)
+			bithenge_expression_dec_ref(params[num_params]);
+		free(params);
+		bithenge_transform_dec_ref(result);
+		return NULL;
+	}
+
+	if (num_params) {
+		int rc = bithenge_param_wrapper(&result, result, params);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			result = NULL;
+		}
+	}
+
+	return result;
+}
+
+/** Create a transform that just produces an empty node.
+ * @param state The parser state.
+ * @return The new transform, or NULL on error. */
+static bithenge_transform_t *make_empty_transform(state_t *state)
+{
+	bithenge_node_t *node;
+	int rc = bithenge_new_empty_internal_node(&node);
+	if (rc != EOK) {
+		error_errno(state, rc);
+		return NULL;
+	}
+
+	bithenge_expression_t *expr;
+	rc = bithenge_const_expression(&expr, node);
+	if (rc != EOK) {
+		error_errno(state, rc);
+		return NULL;
+	}
+
+	bithenge_transform_t *xform;
+	rc = bithenge_inputless_transform(&xform, expr);
+	if (rc != EOK) {
+		error_errno(state, rc);
+		return NULL;
+	}
+
+	return xform;
+}
+
+static bithenge_transform_t *parse_if(state_t *state, bool in_struct)
+{
+	expect(state, TOKEN_IF);
+	expect(state, '(');
+	bithenge_expression_t *expr = parse_expression(state);
+	expect(state, ')');
+	expect(state, '{');
+	bithenge_transform_t *true_xform =
+	    in_struct ? parse_struct(state) : parse_transform(state);
+	expect(state, '}');
+
+	bithenge_transform_t *false_xform = NULL;
+	if (state->token == TOKEN_ELSE) {
+		next_token(state);
+		expect(state, '{');
+		false_xform =
+		    in_struct ? parse_struct(state) : parse_transform(state);
+		expect(state, '}');
+	} else {
+		if (in_struct)
+			false_xform = make_empty_transform(state);
+		else
+			syntax_error(state, "else expected");
+	}
+
+	if (state->error != EOK) {
+		bithenge_expression_dec_ref(expr);
+		bithenge_transform_dec_ref(true_xform);
+		bithenge_transform_dec_ref(false_xform);
+		return NULL;
+	}
+
+	bithenge_transform_t *if_xform;
+	int rc = bithenge_if_transform(&if_xform, expr, true_xform,
+	    false_xform);
+	if (rc != EOK) {
+		error_errno(state, rc);
+		return NULL;
+	}
+	return if_xform;
+}
+
+static bithenge_transform_t *parse_switch(state_t *state, bool in_struct)
+{
+	expect(state, TOKEN_SWITCH);
+	expect(state, '(');
+	bithenge_expression_t *ref_expr = parse_expression(state);
+	expect(state, ')');
+	expect(state, '{');
+	int num = 0;
+	bithenge_expression_t **exprs = NULL;
+	bithenge_transform_t **xforms = NULL;
+	while (state->error == EOK && state->token != '}') {
+		bithenge_expression_t *expr;
+		if (state->token == TOKEN_ELSE) {
+			next_token(state);
+			bithenge_node_t *node;
+			int rc = bithenge_new_boolean_node(&node, true);
+			if (rc != EOK) {
+				error_errno(state, rc);
+				break;
+			}
+			rc = bithenge_const_expression(&expr, node);
+			if (rc != EOK) {
+				error_errno(state, rc);
+				break;
+			}
+		} else {
+			expr = parse_expression(state);
+			if (state->error == EOK) {
+				bithenge_expression_inc_ref(ref_expr);
+				int rc = bithenge_binary_expression(&expr,
+				    BITHENGE_EXPRESSION_EQUALS, ref_expr,
+				    expr);
+				if (rc != EOK) {
+					error_errno(state, rc);
+					break;
+				}
+			}
+		}
+
+		expect(state, ':');
+		bithenge_transform_t *xform;
+		if (in_struct) {
+			expect(state, '{');
+			xform = parse_struct(state);
+			expect(state, '}');
+		} else
+			xform = parse_transform(state);
+		expect(state, ';');
+
+		exprs = state_realloc(state, exprs,
+		    sizeof(*exprs) * (num + 1));
+		xforms = state_realloc(state, xforms,
+		    sizeof(*xforms) * (num + 1));
+		if (state->error != EOK) {
+			bithenge_expression_dec_ref(expr);
+			bithenge_transform_dec_ref(xform);
+			break;
+		}
+
+		exprs[num] = expr;
+		xforms[num] = xform;
+		num++;
+	}
+	bithenge_expression_dec_ref(ref_expr);
+
+	bithenge_transform_t *switch_xform = &bithenge_invalid_transform;
+	bithenge_transform_inc_ref(switch_xform);
+	while (state->error == EOK && num >= 1) {
+		num--;
+		int rc = bithenge_if_transform(&switch_xform, exprs[num],
+		    xforms[num], switch_xform);
+		if (rc != EOK) {
+			switch_xform = NULL;
+			error_errno(state, rc);
+		}
+	}
+
+	while (num >= 1) {
+		num--;
+		bithenge_expression_dec_ref(exprs[num]);
+		bithenge_transform_dec_ref(xforms[num]);
+	}
+	free(exprs);
+	free(xforms);
+
+	expect(state, '}');
+	return switch_xform;
+}
+
+static bithenge_transform_t *parse_repeat(state_t *state)
+{
+	expect(state, TOKEN_REPEAT);
+	bithenge_expression_t *expr = NULL;
+	if (state->token == '(') {
+		next_token(state);
+		expr = parse_expression(state);
+		expect(state, ')');
+	}
+	expect(state, '{');
+	bithenge_transform_t *xform = parse_transform(state);
+	expect(state, '}');
+
+	if (state->error != EOK) {
+		bithenge_expression_dec_ref(expr);
+		bithenge_transform_dec_ref(xform);
+		return NULL;
+	}
+
+	bithenge_transform_t *repeat_xform;
+	int rc = bithenge_repeat_transform(&repeat_xform, xform, expr);
+	if (rc != EOK) {
+		error_errno(state, rc);
+		return NULL;
+	}
+	return repeat_xform;
+}
+
+static bithenge_transform_t *parse_do_while(state_t *state)
+{
+	expect(state, TOKEN_DO);
+	expect(state, '{');
+	bithenge_transform_t *xform = parse_transform(state);
+	expect(state, '}');
+	expect(state, TOKEN_WHILE);
+	expect(state, '(');
+	bithenge_expression_t *expr = parse_expression(state);
+	expect(state, ')');
+
+	if (state->error != EOK) {
+		bithenge_expression_dec_ref(expr);
+		bithenge_transform_dec_ref(xform);
+		return NULL;
+	}
+
+	bithenge_transform_t *do_while_xform;
+	int rc = bithenge_do_while_transform(&do_while_xform, xform, expr);
+	if (rc != EOK) {
+		error_errno(state, rc);
+		return NULL;
+	}
+	return do_while_xform;
+}
+
+static bithenge_transform_t *parse_partial(state_t *state)
+{
+	expect(state, TOKEN_PARTIAL);
+	bithenge_transform_t *offset_xform = NULL;
+	if (state->token == '(') {
+		next_token(state);
+		bithenge_expression_t *offset = parse_expression(state);
+		expect(state, ')');
+
+		bithenge_expression_t *in_expr;
+		int rc = bithenge_in_node_expression(&in_expr);
+		if (rc != EOK)
+			error_errno(state, rc);
+		if (state->error != EOK) {
+			bithenge_expression_dec_ref(offset);
+			return NULL;
+		}
+
+		rc = bithenge_subblob_expression(&offset, in_expr, offset,
+		    NULL, true);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+
+		rc = bithenge_expression_transform(&offset_xform, offset);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+	}
+	expect(state, '{');
+	bithenge_transform_t *xform = parse_transform(state);
+	expect(state, '}');
+	if (state->error != EOK) {
+		bithenge_transform_dec_ref(offset_xform);
+		bithenge_transform_dec_ref(xform);
+		return NULL;
+	}
+
+	int rc = bithenge_partial_transform(&xform, xform);
+	if (rc != EOK) {
+		error_errno(state, rc);
+		bithenge_transform_dec_ref(offset_xform);
+		return NULL;
+	}
+
+	if (offset_xform) {
+		bithenge_transform_t **xforms = malloc(2 * sizeof(*xforms));
+		if (!xforms) {
+			error_errno(state, ENOMEM);
+			bithenge_transform_dec_ref(xform);
+			bithenge_transform_dec_ref(offset_xform);
+			return NULL;
+		}
+		xforms[0] = xform;
+		xforms[1] = offset_xform;
+		rc = bithenge_new_composed_transform(&xform, xforms, 2);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+	}
+
+	return xform;
+}
+
+/* The TOKEN_STRUCT and '{' must already have been skipped. */
+static bithenge_transform_t *parse_struct(state_t *state)
+{
+	size_t num = 0;
+	bithenge_named_transform_t *subxforms;
+	/* We keep an extra space for the {NULL, NULL} terminator. */
+	subxforms = state_malloc(state, sizeof(*subxforms));
+	while (state->error == EOK && state->token != '}') {
+		if (state->token == TOKEN_IF) {
+			subxforms[num].transform = parse_if(state, true);
+			subxforms[num].name = NULL;
+		} else if (state->token == TOKEN_SWITCH) {
+			subxforms[num].transform = parse_switch(state, true);
+			subxforms[num].name = NULL;
+		} else {
+			if (state->token == '.') {
+				next_token(state);
+				subxforms[num].name = expect_identifier(state);
+			} else {
+				subxforms[num].name = NULL;
+			}
+			expect(state, TOKEN_LEFT_ARROW);
+			subxforms[num].transform = parse_transform(state);
+			expect(state, ';');
+		}
+		num++;
+		subxforms = state_realloc(state, subxforms,
+		    (num + 1)*sizeof(*subxforms));
+	}
+
+	if (state->error != EOK) {
+		while (num--) {
+			free((void *)subxforms[num].name);
+			bithenge_transform_dec_ref(subxforms[num].transform);
+		}
+		free(subxforms);
+		return NULL;
+	}
+
+	subxforms[num].name = NULL;
+	subxforms[num].transform = NULL;
+	bithenge_transform_t *result;
+	int rc = bithenge_new_struct(&result, subxforms);
+	if (rc != EOK) {
+		error_errno(state, rc);
+		return NULL;
+	}
+	return result;
+}
+
+/** Parse a transform without composition.
+ * @return The parsed transform, or NULL if an error occurred. */
+static bithenge_transform_t *parse_transform_no_compose(state_t *state)
+{
+	if (state->token == '(') {
+		next_token(state);
+		state->in_node_used = false;
+		bithenge_expression_t *expr = parse_expression(state);
+		expect(state, ')');
+		if (state->error != EOK) {
+			bithenge_expression_dec_ref(expr);
+			return NULL;
+		}
+
+		bithenge_transform_t *xform;
+		int rc;
+		if (state->in_node_used)
+			rc = bithenge_expression_transform(&xform, expr);
+		else
+			rc = bithenge_inputless_transform(&xform, expr);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+		return xform;
+	} else if (state->token == TOKEN_DO) {
+		return parse_do_while(state);
+	} else if (state->token == TOKEN_IDENTIFIER) {
+		return parse_invocation(state);
+	} else if (state->token == TOKEN_IF) {
+		return parse_if(state, false);
+	} else if (state->token == TOKEN_PARTIAL) {
+		return parse_partial(state);
+	} else if (state->token == TOKEN_REPEAT) {
+		return parse_repeat(state);
+	} else if (state->token == TOKEN_STRUCT) {
+		next_token(state);
+		expect(state, '{');
+		bithenge_transform_t *xform = parse_struct(state);
+		expect(state, '}');
+		return xform;
+	} else if (state->token == TOKEN_SWITCH) {
+		return parse_switch(state, false);
+	} else {
+		syntax_error(state, "unexpected (transform expected)");
+		return NULL;
+	}
+}
+
+/** Parse a transform.
+ * @return The parsed transform, or NULL if an error occurred. */
+static bithenge_transform_t *parse_transform(state_t *state)
+{
+	bithenge_transform_t *result = parse_transform_no_compose(state);
+	bithenge_transform_t **xforms = NULL;
+	size_t num = 1;
+	while (state->token == TOKEN_LEFT_ARROW) {
+		expect(state, TOKEN_LEFT_ARROW);
+		xforms = state_realloc(state, xforms,
+		    (num + 1) * sizeof(*xforms));
+		if (state->error != EOK)
+			break;
+		xforms[num++] = parse_transform_no_compose(state);
+	}
+	if (state->error != EOK) {
+		while (xforms && num > 1)
+			bithenge_transform_dec_ref(xforms[--num]);
+		free(xforms);
+		bithenge_transform_dec_ref(result);
+		return NULL;
+	}
+	if (xforms) {
+		xforms[0] = result;
+		int rc = bithenge_new_composed_transform(&result, xforms, num);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+	}
+	return result;
+}
+
+/** Parse a definition. */
+static void parse_definition(state_t *state)
+{
+	expect(state, TOKEN_TRANSFORM);
+	char *name = expect_identifier(state);
+
+	if (state->token == '(') {
+		next_token(state);
+		while (state->error == EOK && state->token != ')') {
+			if (state->num_params)
+				expect(state, ',');
+			state->parameter_names = state_realloc(state,
+			    state->parameter_names,
+			    (state->num_params + 1)*sizeof(*state->parameter_names));
+			if (state->error != EOK)
+				break;
+			state->parameter_names[state->num_params++] =
+			    expect_identifier(state);
+		}
+		expect(state, ')');
+	}
+
+	bithenge_transform_t *barrier = NULL;
+	if (state->error == EOK) {
+		int rc = bithenge_new_barrier_transform(&barrier,
+		    state->num_params);
+		if (rc != EOK) {
+			barrier = NULL;
+			error_errno(state, rc);
+		}
+	}
+
+	add_named_transform(state, barrier, name);
+
+	expect(state, '=');
+	bithenge_transform_t *xform = parse_transform(state);
+	expect(state, ';');
+
+	if (state->error == EOK) {
+		int rc = bithenge_barrier_transform_set_subtransform(barrier,
+		    xform);
+		xform = NULL;
+		if (rc != EOK)
+			error_errno(state, rc);
+	}
+
+	if (state->error != EOK)
+		bithenge_transform_dec_ref(xform);
+
+	for (int i = 0; i < state->num_params; i++)
+		free(state->parameter_names[i]);
+	free(state->parameter_names);
+	state->parameter_names = NULL;
+	state->num_params = 0;
+}
+
+/** Initialize the state. */
+static void state_init(state_t *state, const char *filename)
+{
+	state->error = EOK;
+	state->transform_list = NULL;
+	state->parameter_names = NULL;
+	state->num_params = 0;
+	state->token = TOKEN_ERROR;
+	state->old_buffer_pos = state->buffer_pos = BUFFER_SIZE - 1;
+	state->lineno = 1;
+	state->line_offset = (int)-state->buffer_pos + 1;
+	state->filename = filename;
+	state->file = fopen(filename, "r");
+	if (!state->file) {
+		error_errno(state, errno);
+	} else {
+		next_token(state);
+	}
+}
+
+/** Destroy the state. */
+static void state_destroy(state_t *state)
+{
+	done_with_token(state);
+	state->token = TOKEN_ERROR;
+	if (state->file)
+		fclose(state->file);
+	transform_list_t *entry = state->transform_list;
+	while (entry) {
+		transform_list_t *next = entry->next;
+		free(entry->name);
+		bithenge_transform_dec_ref(entry->transform);
+		free(entry);
+		entry = next;
+	}
+	for (int i = 0; i < state->num_params; i++)
+		free(state->parameter_names[i]);
+	free(state->parameter_names);
+}
+
+/** Parse a script file.
+ * @param filename The name of the script file.
+ * @param[out] out Stores the "main" transform.
+ * @return EOK on success, EINVAL on syntax error, or an error code from
+ * errno.h. */
+int bithenge_parse_script(const char *filename, bithenge_transform_t **out)
+{
+	state_t state;
+	state_init(&state, filename);
+	while (state.error == EOK && state.token != TOKEN_EOF)
+		parse_definition(&state);
+	*out = get_named_transform(&state, "main");
+	int rc = state.error;
+	state_destroy(&state);
+	if (rc == EOK && !*out) {
+		fprintf(stderr, "no \"main\" transform\n");
+		rc = EINVAL;
+	}
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/bithenge/src/sequence.c
===================================================================
--- uspace/lib/bithenge/src/sequence.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/sequence.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,1146 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Sequence transforms.
+ */
+
+#include <stdlib.h>
+#include <bithenge/blob.h>
+#include <bithenge/expression.h>
+#include <bithenge/sequence.h>
+#include <bithenge/tree.h>
+#include "common.h"
+
+
+
+/***************** seq_node                                  *****************/
+
+typedef struct {
+	bithenge_node_t base;
+	const struct seq_node_ops *ops;
+	bithenge_blob_t *blob;
+	bithenge_scope_t *scope;
+	aoff64_t *ends;
+	size_t num_ends;
+	bool end_on_empty;
+	bithenge_int_t num_xforms;
+} seq_node_t;
+
+typedef struct seq_node_ops {
+	int (*get_transform)(seq_node_t *self, bithenge_transform_t **out,
+	    bithenge_int_t index);
+} seq_node_ops_t;
+
+static bithenge_node_t *seq_as_node(seq_node_t *node)
+{
+	return &node->base;
+}
+
+static seq_node_t *node_as_seq(bithenge_node_t *node)
+{
+	return (seq_node_t *)node;
+}
+
+static int seq_node_field_offset(seq_node_t *self, aoff64_t *out, size_t index)
+{
+	if (index == 0) {
+		*out = 0;
+		return EOK;
+	}
+	index--;
+	aoff64_t prev_offset =
+	    self->num_ends ? self->ends[self->num_ends - 1] : 0;
+	for (; self->num_ends <= index; self->num_ends++) {
+		bithenge_transform_t *subxform;
+		int rc = self->ops->get_transform(self, &subxform,
+		    self->num_ends);
+		if (rc != EOK)
+			return rc;
+
+		bithenge_node_t *subblob_node;
+		bithenge_blob_inc_ref(self->blob);
+		rc = bithenge_new_offset_blob(&subblob_node, self->blob,
+		    prev_offset);
+		if (rc != EOK) {
+			bithenge_transform_dec_ref(subxform);
+			return rc;
+		}
+
+		if (self->end_on_empty) {
+			bool empty;
+			rc = bithenge_blob_empty(
+			    bithenge_node_as_blob(subblob_node), &empty);
+			if (rc == EOK && empty) {
+				self->num_xforms = self->num_ends;
+				rc = ENOENT;
+			}
+			if (rc != EOK) {
+				bithenge_transform_dec_ref(subxform);
+				bithenge_node_dec_ref(subblob_node);
+				return rc;
+			}
+		}
+
+		bithenge_blob_t *subblob = bithenge_node_as_blob(subblob_node);
+		aoff64_t field_size;
+		rc = bithenge_transform_prefix_length(subxform, self->scope,
+		    subblob, &field_size);
+		bithenge_node_dec_ref(subblob_node);
+		bithenge_transform_dec_ref(subxform);
+		if (rc != EOK)
+			return rc;
+
+		if (self->num_xforms == -1) {
+			aoff64_t *new_ends = realloc(self->ends,
+			    (self->num_ends + 1)*sizeof(*new_ends));
+			if (!new_ends)
+				return ENOMEM;
+			self->ends = new_ends;
+		}
+
+		prev_offset = self->ends[self->num_ends] =
+		    prev_offset + field_size;
+	}
+	*out = self->ends[index];
+	return EOK;
+}
+
+static int seq_node_subtransform(seq_node_t *self, bithenge_node_t **out,
+    size_t index)
+{
+	aoff64_t start_pos;
+	int rc = seq_node_field_offset(self, &start_pos, index);
+	if (rc != EOK)
+		return rc;
+
+	bithenge_transform_t *subxform;
+	rc = self->ops->get_transform(self, &subxform, index);
+	if (rc != EOK)
+		return rc;
+
+	if (index == self->num_ends) {
+		/* We can apply the subtransform and cache its prefix length at
+		 * the same time. */
+		bithenge_node_t *blob_node;
+		bithenge_blob_inc_ref(self->blob);
+		rc = bithenge_new_offset_blob(&blob_node, self->blob,
+		    start_pos);
+		if (rc != EOK) {
+			bithenge_transform_dec_ref(subxform);
+			return rc;
+		}
+
+		if (self->end_on_empty) {
+			bool empty;
+			rc = bithenge_blob_empty(
+			    bithenge_node_as_blob(blob_node), &empty);
+			if (rc == EOK && empty) {
+				self->num_xforms = self->num_ends;
+				rc = ENOENT;
+			}
+			if (rc != EOK) {
+				bithenge_transform_dec_ref(subxform);
+				bithenge_node_dec_ref(blob_node);
+				return rc;
+			}
+		}
+
+		aoff64_t size;
+		rc = bithenge_transform_prefix_apply(subxform, self->scope,
+		    bithenge_node_as_blob(blob_node), out, &size);
+		bithenge_node_dec_ref(blob_node);
+		bithenge_transform_dec_ref(subxform);
+		if (rc != EOK)
+			return rc;
+
+		if (self->num_xforms == -1) {
+			aoff64_t *new_ends = realloc(self->ends,
+			    (self->num_ends + 1)*sizeof(*new_ends));
+			if (!new_ends)
+				return ENOMEM;
+			self->ends = new_ends;
+		}
+		self->ends[self->num_ends++] = start_pos + size;
+	} else {
+		aoff64_t end_pos;
+		int rc = seq_node_field_offset(self, &end_pos, index + 1);
+		if (rc != EOK) {
+			bithenge_transform_dec_ref(subxform);
+			return rc;
+		}
+
+		bithenge_node_t *blob_node;
+		bithenge_blob_inc_ref(self->blob);
+		rc = bithenge_new_subblob(&blob_node, self->blob, start_pos,
+		    end_pos - start_pos);
+		if (rc != EOK) {
+			bithenge_transform_dec_ref(subxform);
+			return rc;
+		}
+
+		rc = bithenge_transform_apply(subxform, self->scope, blob_node,
+		    out);
+		bithenge_node_dec_ref(blob_node);
+		bithenge_transform_dec_ref(subxform);
+		if (rc != EOK)
+			return rc;
+	}
+
+	return EOK;
+}
+
+static int seq_node_complete(seq_node_t *self, bool *out)
+{
+	aoff64_t blob_size, end_pos;
+	int rc = bithenge_blob_size(self->blob, &blob_size);
+	if (rc != EOK)
+		return rc;
+	rc = seq_node_field_offset(self, &end_pos, self->num_xforms);
+	if (rc != EOK)
+		return rc;
+	*out = blob_size == end_pos;
+	return EOK;
+}
+
+static void seq_node_destroy(seq_node_t *self)
+{
+	bithenge_scope_dec_ref(self->scope);
+	bithenge_blob_dec_ref(self->blob);
+	free(self->ends);
+}
+
+static void seq_node_set_num_xforms(seq_node_t *self,
+    bithenge_int_t num_xforms)
+{
+	self->num_xforms = num_xforms;
+}
+
+static bithenge_scope_t *seq_node_scope(seq_node_t *self)
+{
+	return self->scope;
+}
+
+static int seq_node_init(seq_node_t *self, const seq_node_ops_t *ops,
+    bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_int_t num_xforms,
+    bool end_on_empty)
+{
+	self->ops = ops;
+	if (num_xforms != -1) {
+		self->ends = malloc(sizeof(*self->ends) * num_xforms);
+		if (!self->ends)
+			return ENOMEM;
+	} else
+		self->ends = NULL;
+	bithenge_blob_inc_ref(blob);
+	self->blob = blob;
+	self->num_xforms = num_xforms;
+	self->num_ends = 0;
+	self->end_on_empty = end_on_empty;
+	self->scope = scope;
+	if (self->scope)
+		bithenge_scope_inc_ref(self->scope);
+	return EOK;
+}
+
+
+
+/***************** bithenge_new_struct                       *****************/
+
+typedef struct {
+	bithenge_transform_t base;
+	bithenge_named_transform_t *subtransforms;
+	size_t num_subtransforms;
+} struct_transform_t;
+
+static bithenge_transform_t *struct_as_transform(struct_transform_t *xform)
+{
+	return &xform->base;
+}
+
+static struct_transform_t *transform_as_struct(bithenge_transform_t *xform)
+{
+	return (struct_transform_t *)xform;
+}
+
+typedef struct {
+	seq_node_t base;
+	struct_transform_t *transform;
+	bool prefix;
+} struct_node_t;
+
+static seq_node_t *struct_as_seq(struct_node_t *node)
+{
+	return &node->base;
+}
+
+static struct_node_t *seq_as_struct(seq_node_t *base)
+{
+	return (struct_node_t *)base;
+}
+
+static bithenge_node_t *struct_as_node(struct_node_t *node)
+{
+	return seq_as_node(struct_as_seq(node));
+}
+
+static struct_node_t *node_as_struct(bithenge_node_t *node)
+{
+	return seq_as_struct(node_as_seq(node));
+}
+
+static int struct_node_for_each(bithenge_node_t *base,
+    bithenge_for_each_func_t func, void *data)
+{
+	int rc = EOK;
+	struct_node_t *self = node_as_struct(base);
+	bithenge_named_transform_t *subxforms =
+	    self->transform->subtransforms;
+
+	for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
+		bithenge_node_t *subxform_result;
+		rc = seq_node_subtransform(struct_as_seq(self),
+		    &subxform_result, i);
+		if (rc != EOK)
+			return rc;
+
+		if (subxforms[i].name) {
+			bithenge_node_t *name_node;
+			rc = bithenge_new_string_node(&name_node,
+			    subxforms[i].name, false);
+			if (rc == EOK) {
+				rc = func(name_node, subxform_result, data);
+				subxform_result = NULL;
+			}
+		} else {
+			if (bithenge_node_type(subxform_result) !=
+			    BITHENGE_NODE_INTERNAL) {
+				rc = EINVAL;
+			} else {
+				rc = bithenge_node_for_each(subxform_result,
+				    func, data);
+			}
+		}
+		bithenge_node_dec_ref(subxform_result);
+		if (rc != EOK)
+			return rc;
+	}
+
+	if (!self->prefix) {
+		bool complete;
+		rc = seq_node_complete(struct_as_seq(self), &complete);
+		if (rc != EOK)
+			return rc;
+		if (!complete)
+			return EINVAL;
+	}
+
+	return rc;
+}
+
+static int struct_node_get(bithenge_node_t *base, bithenge_node_t *key,
+    bithenge_node_t **out)
+{
+	struct_node_t *self = node_as_struct(base);
+
+	int rc = ENOENT;
+	if (bithenge_node_type(key) != BITHENGE_NODE_STRING)
+		goto end;
+	const char *name = bithenge_string_node_value(key);
+
+	const bithenge_named_transform_t *subxforms =
+	    self->transform->subtransforms;
+	for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
+		if (subxforms[i].name && !str_cmp(name, subxforms[i].name)) {
+			rc = seq_node_subtransform(struct_as_seq(self), out, i);
+			goto end;
+		}
+	}
+
+	for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
+		if (subxforms[i].name)
+			continue;
+		bithenge_node_t *subxform_result;
+		rc = seq_node_subtransform(struct_as_seq(self),
+		    &subxform_result, i);
+		if (rc != EOK)
+			goto end;
+		if (bithenge_node_type(subxform_result) !=
+		    BITHENGE_NODE_INTERNAL) {
+			bithenge_node_dec_ref(subxform_result);
+			rc = EINVAL;
+			goto end;
+		}
+		bithenge_node_inc_ref(key);
+		rc = bithenge_node_get(subxform_result, key, out);
+		bithenge_node_dec_ref(subxform_result);
+		if (rc != ENOENT)
+			goto end;
+	}
+
+	rc = ENOENT;
+end:
+	bithenge_node_dec_ref(key);
+	return rc;
+}
+
+static void struct_node_destroy(bithenge_node_t *base)
+{
+	struct_node_t *node = node_as_struct(base);
+
+	/* Treat the scope carefully because of the circular reference. In
+	 * struct_transform_make_node, things are set up so node owns a
+	 * reference to the scope, but scope doesn't own a reference to node,
+	 * so node's reference count is too low. */
+	bithenge_scope_t *scope = seq_node_scope(struct_as_seq(node));
+	if (scope->refs == 1) {
+		/* Mostly normal destroy, but we didn't inc_ref(node) for the
+		 * scope in struct_transform_make_node, so make sure it doesn't
+		 * try to dec_ref. */
+		scope->current_node = NULL;
+		seq_node_destroy(struct_as_seq(node));
+	} else if (scope->refs > 1) {
+		/* The scope is still needed, but node isn't otherwise needed.
+		 * Switch things around so scope owns a reference to node, but
+		 * not vice versa, and scope's reference count is too low. */
+		bithenge_node_inc_ref(base);
+		bithenge_scope_dec_ref(scope);
+		return;
+	} else {
+		/* This happens after the previous case, when scope is no
+		 * longer used and is being destroyed. Since scope is already
+		 * being destroyed, set it to NULL here so we don't try to
+		 * destroy it twice. */
+		struct_as_seq(node)->scope = NULL;
+		seq_node_destroy(struct_as_seq(node));
+	}
+
+	bithenge_transform_dec_ref(struct_as_transform(node->transform));
+	free(node);
+}
+
+static const bithenge_internal_node_ops_t struct_node_ops = {
+	.for_each = struct_node_for_each,
+	.get = struct_node_get,
+	.destroy = struct_node_destroy,
+};
+
+static int struct_node_get_transform(seq_node_t *base,
+    bithenge_transform_t **out, bithenge_int_t index)
+{
+	struct_node_t *self = seq_as_struct(base);
+	*out = self->transform->subtransforms[index].transform;
+	bithenge_transform_inc_ref(*out);
+	return EOK;
+}
+
+static const seq_node_ops_t struct_node_seq_ops = {
+	.get_transform = struct_node_get_transform,
+};
+
+static int struct_transform_make_node(struct_transform_t *self,
+    bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
+    bool prefix)
+{
+	struct_node_t *node = malloc(sizeof(*node));
+	if (!node)
+		return ENOMEM;
+
+	int rc = bithenge_init_internal_node(struct_as_node(node),
+	    &struct_node_ops);
+	if (rc != EOK) {
+		free(node);
+		return rc;
+	}
+	bithenge_scope_t *inner;
+	rc = bithenge_scope_new(&inner, scope);
+	if (rc != EOK) {
+		free(node);
+		return rc;
+	}
+
+	rc = seq_node_init(struct_as_seq(node), &struct_node_seq_ops, inner,
+	    blob, self->num_subtransforms, false);
+	if (rc != EOK) {
+		bithenge_scope_dec_ref(inner);
+		free(node);
+		return rc;
+	}
+
+	bithenge_transform_inc_ref(struct_as_transform(self));
+	node->transform = self;
+	node->prefix = prefix;
+
+	/* We should inc_ref(node) here, but that would make a cycle. Instead,
+	 * we leave it 1 too low, so that when the only remaining use of node
+	 * is the scope, node will be destroyed. Also see the comment in
+	 * struct_node_destroy. */
+	bithenge_scope_set_current_node(inner, struct_as_node(node));
+	bithenge_scope_dec_ref(inner);
+
+	*out = struct_as_node(node);
+
+	return EOK;
+}
+
+static int struct_transform_apply(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
+{
+	struct_transform_t *self = transform_as_struct(base);
+	if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
+		return EINVAL;
+	return struct_transform_make_node(self, out, scope,
+	    bithenge_node_as_blob(in), false);
+}
+
+static int struct_transform_prefix_length(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
+{
+	struct_transform_t *self = transform_as_struct(base);
+	bithenge_node_t *struct_node;
+	int rc = struct_transform_make_node(self, &struct_node, scope, blob,
+	    true);
+	if (rc != EOK)
+		return rc;
+
+	rc = seq_node_field_offset(node_as_seq(struct_node), out,
+	    self->num_subtransforms);
+	bithenge_node_dec_ref(struct_node);
+	return rc;
+}
+
+static int struct_transform_prefix_apply(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
+    aoff64_t *out_size)
+{
+	struct_transform_t *self = transform_as_struct(base);
+	int rc = struct_transform_make_node(self, out_node, scope, blob,
+	    true);
+	if (rc != EOK)
+		return rc;
+
+	if (out_size) {
+		rc = seq_node_field_offset(node_as_seq(*out_node), out_size,
+		    self->num_subtransforms);
+		if (rc != EOK) {
+			bithenge_node_dec_ref(*out_node);
+			return rc;
+		}
+	}
+
+	return EOK;
+}
+
+static void free_subtransforms(bithenge_named_transform_t *subtransforms)
+{
+	for (size_t i = 0; subtransforms[i].transform; i++) {
+		free((void *)subtransforms[i].name);
+		bithenge_transform_dec_ref(subtransforms[i].transform);
+	}
+	free(subtransforms);
+}
+
+static void struct_transform_destroy(bithenge_transform_t *base)
+{
+	struct_transform_t *self = transform_as_struct(base);
+	free_subtransforms(self->subtransforms);
+	free(self);
+}
+
+static bithenge_transform_ops_t struct_transform_ops = {
+	.apply = struct_transform_apply,
+	.prefix_length = struct_transform_prefix_length,
+	.prefix_apply = struct_transform_prefix_apply,
+	.destroy = struct_transform_destroy,
+};
+
+/** Create a struct transform. The transform will apply its subtransforms
+ * sequentially to a blob to create an internal node. Each result is either
+ * given a key from @a subtransforms or, if the name is NULL, the result's keys
+ * and values are merged into the struct transform's result. This function
+ * takes ownership of @a subtransforms and the names and references therein.
+ * @param[out] out Stores the created transform.
+ * @param subtransforms The subtransforms and field names.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_struct(bithenge_transform_t **out,
+    bithenge_named_transform_t *subtransforms)
+{
+	int rc;
+	struct_transform_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+	rc = bithenge_init_transform(struct_as_transform(self),
+	    &struct_transform_ops, 0);
+	if (rc != EOK)
+		goto error;
+	self->subtransforms = subtransforms;
+	self->num_subtransforms = 0;
+	for (self->num_subtransforms = 0;
+	    subtransforms[self->num_subtransforms].transform;
+	    self->num_subtransforms++);
+	*out = struct_as_transform(self);
+	return EOK;
+error:
+	free_subtransforms(subtransforms);
+	free(self);
+	return rc;
+}
+
+
+
+/***************** bithenge_repeat_transform                 *****************/
+
+/* TODO: ignore errors */
+
+typedef struct {
+	bithenge_transform_t base;
+	bithenge_expression_t *expr;
+	bithenge_transform_t *xform;
+} repeat_transform_t;
+
+static inline bithenge_transform_t *repeat_as_transform(
+    repeat_transform_t *self)
+{
+	return &self->base;
+}
+
+static inline repeat_transform_t *transform_as_repeat(
+    bithenge_transform_t *base)
+{
+	return (repeat_transform_t *)base;
+}
+
+typedef struct {
+	seq_node_t base;
+	bool prefix;
+	bithenge_int_t count;
+	bithenge_transform_t *xform;
+} repeat_node_t;
+
+static seq_node_t *repeat_as_seq(repeat_node_t *self)
+{
+	return &self->base;
+}
+
+static repeat_node_t *seq_as_repeat(seq_node_t *base)
+{
+	return (repeat_node_t *)base;
+}
+
+static bithenge_node_t *repeat_as_node(repeat_node_t *self)
+{
+	return seq_as_node(repeat_as_seq(self));
+}
+
+static repeat_node_t *node_as_repeat(bithenge_node_t *base)
+{
+	return seq_as_repeat(node_as_seq(base));
+}
+
+static int repeat_node_for_each(bithenge_node_t *base,
+    bithenge_for_each_func_t func, void *data)
+{
+	int rc = EOK;
+	repeat_node_t *self = node_as_repeat(base);
+
+	for (bithenge_int_t i = 0; self->count == -1 || i < self->count; i++) {
+		bithenge_node_t *subxform_result;
+		rc = seq_node_subtransform(repeat_as_seq(self),
+		    &subxform_result, i);
+		if ((rc == EINVAL || rc == ENOENT) && self->count == -1) {
+			self->count = i;
+			seq_node_set_num_xforms(repeat_as_seq(self),
+			    self->count);
+			rc = EOK;
+			break;
+		}
+		if (rc != EOK)
+			return rc;
+
+		bithenge_node_t *key_node;
+		rc = bithenge_new_integer_node(&key_node, i);
+		if (rc != EOK) {
+			bithenge_node_dec_ref(subxform_result);
+			return rc;
+		}
+		rc = func(key_node, subxform_result, data);
+		if (rc != EOK)
+			return rc;
+	}
+
+	if (!self->prefix) {
+		bool complete;
+		rc = seq_node_complete(repeat_as_seq(self), &complete);
+		if (rc != EOK)
+			return rc;
+		if (!complete)
+			return EINVAL;
+	}
+
+	return rc;
+}
+
+static int repeat_node_get(bithenge_node_t *base, bithenge_node_t *key,
+    bithenge_node_t **out)
+{
+	repeat_node_t *self = node_as_repeat(base);
+
+	if (bithenge_node_type(key) != BITHENGE_NODE_INTEGER) {
+		bithenge_node_dec_ref(key);
+		return ENOENT;
+	}
+
+	bithenge_int_t index = bithenge_integer_node_value(key);
+	bithenge_node_dec_ref(key);
+	if (index < 0 || (self->count != -1 && index >= self->count))
+		return ENOENT;
+	return seq_node_subtransform(repeat_as_seq(self), out, index);
+}
+
+static void repeat_node_destroy(bithenge_node_t *base)
+{
+	repeat_node_t *self = node_as_repeat(base);
+	seq_node_destroy(repeat_as_seq(self));
+	bithenge_transform_dec_ref(self->xform);
+	free(self);
+}
+
+static const bithenge_internal_node_ops_t repeat_node_ops = {
+	.for_each = repeat_node_for_each,
+	.get = repeat_node_get,
+	.destroy = repeat_node_destroy,
+};
+
+static int repeat_node_get_transform(seq_node_t *base,
+    bithenge_transform_t **out, bithenge_int_t index)
+{
+	repeat_node_t *self = seq_as_repeat(base);
+	*out = self->xform;
+	bithenge_transform_inc_ref(*out);
+	return EOK;
+}
+
+static const seq_node_ops_t repeat_node_seq_ops = {
+	.get_transform = repeat_node_get_transform,
+};
+
+static int repeat_transform_make_node(repeat_transform_t *self,
+    bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
+    bool prefix)
+{
+	bithenge_int_t count = -1;
+	if (self->expr != NULL) {
+		bithenge_node_t *count_node;
+		int rc = bithenge_expression_evaluate(self->expr, scope,
+		    &count_node);
+		if (rc != EOK)
+			return rc;
+		if (bithenge_node_type(count_node) != BITHENGE_NODE_INTEGER) {
+			bithenge_node_dec_ref(count_node);
+			return EINVAL;
+		}
+		count = bithenge_integer_node_value(count_node);
+		bithenge_node_dec_ref(count_node);
+		if (count < 0)
+			return EINVAL;
+	}
+
+	repeat_node_t *node = malloc(sizeof(*node));
+	if (!node)
+		return ENOMEM;
+
+	int rc = bithenge_init_internal_node(repeat_as_node(node),
+	    &repeat_node_ops);
+	if (rc != EOK) {
+		free(node);
+		return rc;
+	}
+
+	rc = seq_node_init(repeat_as_seq(node), &repeat_node_seq_ops, scope,
+	    blob, count, count == -1);
+	if (rc != EOK) {
+		free(node);
+		return rc;
+	}
+
+	bithenge_transform_inc_ref(self->xform);
+	node->xform = self->xform;
+	node->count = count;
+	node->prefix = prefix;
+	*out = repeat_as_node(node);
+	return EOK;
+}
+
+static int repeat_transform_apply(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
+{
+	repeat_transform_t *self = transform_as_repeat(base);
+	if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
+		return EINVAL;
+	return repeat_transform_make_node(self, out, scope,
+	    bithenge_node_as_blob(in), false);
+}
+
+static int repeat_transform_prefix_apply(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
+    aoff64_t *out_size)
+{
+	repeat_transform_t *self = transform_as_repeat(base);
+	int rc = repeat_transform_make_node(self, out_node, scope, blob, true);
+	if (rc != EOK)
+		return rc;
+
+	if (out_size) {
+		bithenge_int_t count = node_as_repeat(*out_node)->count;
+		if (count != -1) {
+			rc = seq_node_field_offset(node_as_seq(*out_node),
+			    out_size, count);
+			if (rc != EOK) {
+				bithenge_node_dec_ref(*out_node);
+				return rc;
+			}
+		} else {
+			*out_size = 0;
+			for (count = 1; ; count++) {
+				aoff64_t size;
+				rc = seq_node_field_offset(
+				    node_as_seq(*out_node), &size, count);
+				if (rc == EINVAL || rc == ENOENT)
+					break;
+				if (rc != EOK) {
+					bithenge_node_dec_ref(*out_node);
+					return rc;
+				}
+				*out_size = size;
+			}
+		}
+	}
+	return EOK;
+}
+
+static void repeat_transform_destroy(bithenge_transform_t *base)
+{
+	repeat_transform_t *self = transform_as_repeat(base);
+	bithenge_transform_dec_ref(self->xform);
+	bithenge_expression_dec_ref(self->expr);
+	free(self);
+}
+
+static const bithenge_transform_ops_t repeat_transform_ops = {
+	.apply = repeat_transform_apply,
+	.prefix_apply = repeat_transform_prefix_apply,
+	.destroy = repeat_transform_destroy,
+};
+
+/** Create a transform that applies its subtransform repeatedly. Takes a
+ * reference to @a xform and @a expr.
+ * @param[out] out Holds the new transform.
+ * @param xform The subtransform to apply repeatedly.
+ * @param expr Used to calculate the number of times @a xform will be applied.
+ * May be NULL, in which case @a xform will be applied indefinitely.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_repeat_transform(bithenge_transform_t **out,
+    bithenge_transform_t *xform, bithenge_expression_t *expr)
+{
+	int rc;
+	repeat_transform_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_transform(repeat_as_transform(self),
+	    &repeat_transform_ops, 0);
+	if (rc != EOK)
+		goto error;
+
+	self->expr = expr;
+	self->xform = xform;
+	*out = repeat_as_transform(self);
+	return EOK;
+
+error:
+	free(self);
+	bithenge_expression_dec_ref(expr);
+	bithenge_transform_dec_ref(xform);
+	return rc;
+}
+
+
+
+/***************** bithenge_do_while_transform               *****************/
+
+typedef struct {
+	bithenge_transform_t base;
+	bithenge_expression_t *expr;
+	bithenge_transform_t *xform;
+} do_while_transform_t;
+
+static inline bithenge_transform_t *do_while_as_transform(
+    do_while_transform_t *self)
+{
+	return &self->base;
+}
+
+static inline do_while_transform_t *transform_as_do_while(
+    bithenge_transform_t *base)
+{
+	return (do_while_transform_t *)base;
+}
+
+typedef struct {
+	seq_node_t base;
+	bithenge_expression_t *expr;
+	bithenge_transform_t *xform;
+	bithenge_int_t count;
+} do_while_node_t;
+
+static seq_node_t *do_while_as_seq(do_while_node_t *self)
+{
+	return &self->base;
+}
+
+static do_while_node_t *seq_as_do_while(seq_node_t *base)
+{
+	return (do_while_node_t *)base;
+}
+
+static bithenge_node_t *do_while_as_node(do_while_node_t *self)
+{
+	return seq_as_node(do_while_as_seq(self));
+}
+
+static do_while_node_t *node_as_do_while(bithenge_node_t *base)
+{
+	return seq_as_do_while(node_as_seq(base));
+}
+
+static int do_while_node_for_each(bithenge_node_t *base,
+    bithenge_for_each_func_t func, void *data)
+{
+	int rc = EOK;
+	do_while_node_t *self = node_as_do_while(base);
+
+	for (bithenge_int_t i = 0; ; i++) {
+		bithenge_node_t *subxform_result;
+		rc = seq_node_subtransform(do_while_as_seq(self),
+		    &subxform_result, i);
+		if (rc != EOK)
+			return rc;
+
+		bithenge_node_t *key_node;
+		rc = bithenge_new_integer_node(&key_node, i);
+		if (rc != EOK) {
+			bithenge_node_dec_ref(subxform_result);
+			return rc;
+		}
+		bithenge_node_inc_ref(subxform_result);
+		rc = func(key_node, subxform_result, data);
+		if (rc != EOK) {
+			bithenge_node_dec_ref(subxform_result);
+			return rc;
+		}
+
+		bithenge_scope_t *scope;
+		rc = bithenge_scope_new(&scope,
+		    seq_node_scope(do_while_as_seq(self)));
+		if (rc != EOK) {
+			bithenge_node_dec_ref(subxform_result);
+			return rc;
+		}
+		bithenge_scope_set_current_node(scope, subxform_result);
+		bithenge_node_t *expr_result;
+		rc = bithenge_expression_evaluate(self->expr, scope,
+		    &expr_result);
+		bithenge_scope_dec_ref(scope);
+		if (rc != EOK)
+			return rc;
+		if (bithenge_node_type(expr_result) != BITHENGE_NODE_BOOLEAN) {
+			bithenge_node_dec_ref(expr_result);
+			return EINVAL;
+		}
+		bool cond = bithenge_boolean_node_value(expr_result);
+		bithenge_node_dec_ref(expr_result);
+		if (!cond) {
+			self->count = i + 1;
+			seq_node_set_num_xforms(do_while_as_seq(self),
+			    self->count);
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static void do_while_node_destroy(bithenge_node_t *base)
+{
+	do_while_node_t *self = node_as_do_while(base);
+	seq_node_destroy(do_while_as_seq(self));
+	bithenge_expression_dec_ref(self->expr);
+	bithenge_transform_dec_ref(self->xform);
+	free(self);
+}
+
+static const bithenge_internal_node_ops_t do_while_node_ops = {
+	.for_each = do_while_node_for_each,
+	.destroy = do_while_node_destroy,
+};
+
+static int do_while_node_get_transform(seq_node_t *base,
+    bithenge_transform_t **out, bithenge_int_t index)
+{
+	do_while_node_t *self = seq_as_do_while(base);
+	*out = self->xform;
+	bithenge_transform_inc_ref(*out);
+	return EOK;
+}
+
+static const seq_node_ops_t do_while_node_seq_ops = {
+	.get_transform = do_while_node_get_transform,
+};
+
+static int do_while_transform_make_node(do_while_transform_t *self,
+    bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob)
+{
+	do_while_node_t *node = malloc(sizeof(*node));
+	if (!node)
+		return ENOMEM;
+
+	int rc = bithenge_init_internal_node(do_while_as_node(node),
+	    &do_while_node_ops);
+	if (rc != EOK) {
+		free(node);
+		return rc;
+	}
+
+	rc = seq_node_init(do_while_as_seq(node), &do_while_node_seq_ops,
+	    scope, blob, -1, false);
+	if (rc != EOK) {
+		free(node);
+		return rc;
+	}
+
+	bithenge_transform_inc_ref(self->xform);
+	node->xform = self->xform;
+	bithenge_expression_inc_ref(self->expr);
+	node->expr = self->expr;
+	node->count = -1;
+	*out = do_while_as_node(node);
+	return EOK;
+}
+
+static int for_each_noop(bithenge_node_t *key, bithenge_node_t *value,
+    void *data)
+{
+	bithenge_node_dec_ref(key);
+	bithenge_node_dec_ref(value);
+	return EOK;
+}
+
+static int do_while_transform_prefix_apply(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
+    aoff64_t *out_size)
+{
+	do_while_transform_t *self = transform_as_do_while(base);
+	int rc = do_while_transform_make_node(self, out_node, scope, blob);
+	if (rc != EOK)
+		return rc;
+
+	if (out_size) {
+		rc = bithenge_node_for_each(*out_node, for_each_noop, NULL);
+		if (rc != EOK) {
+			bithenge_node_dec_ref(*out_node);
+			return rc;
+		}
+
+		rc = seq_node_field_offset(node_as_seq(*out_node), out_size,
+		    node_as_do_while(*out_node)->count);
+		if (rc != EOK) {
+			bithenge_node_dec_ref(*out_node);
+			return rc;
+		}
+	}
+
+	return EOK;
+}
+
+static void do_while_transform_destroy(bithenge_transform_t *base)
+{
+	do_while_transform_t *self = transform_as_do_while(base);
+	bithenge_transform_dec_ref(self->xform);
+	bithenge_expression_dec_ref(self->expr);
+	free(self);
+}
+
+static const bithenge_transform_ops_t do_while_transform_ops = {
+	.prefix_apply = do_while_transform_prefix_apply,
+	.destroy = do_while_transform_destroy,
+};
+
+/** Create a transform that applies its subtransform while an expression on the
+ * result returns true. Takes a reference to @a xform and @a expr.
+ * @param[out] out Holds the new transform.
+ * @param xform The subtransform to apply repeatedly.
+ * @param expr Applied in the result of each application of @a xform to
+ * determine whether there will be more.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_do_while_transform(bithenge_transform_t **out,
+    bithenge_transform_t *xform, bithenge_expression_t *expr)
+{
+	int rc;
+	do_while_transform_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_transform(do_while_as_transform(self),
+	    &do_while_transform_ops, 0);
+	if (rc != EOK)
+		goto error;
+
+	self->expr = expr;
+	self->xform = xform;
+	*out = do_while_as_transform(self);
+	return EOK;
+
+error:
+	free(self);
+	bithenge_expression_dec_ref(expr);
+	bithenge_transform_dec_ref(xform);
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/bithenge/src/source.c
===================================================================
--- uspace/lib/bithenge/src/source.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/source.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Provide various external sources of data.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <bithenge/blob.h>
+#include <bithenge/file.h>
+#include <bithenge/source.h>
+#include "common.h"
+
+#ifdef __HELENOS__
+#include <loc.h>
+#include "helenos/block.h"
+#endif
+
+static inline int hex_digit(char digit)
+{
+	if ('0' <= digit && digit <= '9')
+		return digit - '0' + 0x0;
+	if ('a' <= digit && digit <= 'f')
+		return digit - 'a' + 0xa;
+	if ('A' <= digit && digit <= 'F')
+		return digit - 'A' + 0xA;
+	return -1;
+}
+
+static int blob_from_hex(bithenge_node_t **out, const char *hex)
+{
+	size_t size = str_length(hex);
+	if (size % 2)
+		return EINVAL;
+	size /= 2;
+	char *buffer = malloc(size);
+	if (!buffer)
+		return ENOMEM;
+	for (size_t i = 0; i < size; i++) {
+		int upper = hex_digit(hex[2 * i + 0]);
+		int lower = hex_digit(hex[2 * i + 1]);
+		if (upper == -1 || lower == -1) {
+			free(buffer);
+			return EINVAL;
+		}
+		buffer[i] = upper << 4 | lower;
+	}
+	return bithenge_new_blob_from_buffer(out, buffer, size, true);
+}
+
+/** Create a node from a source described with a string. For instance,
+ * "hex:55aa" will result in a blob node. If there is no colon in the string,
+ * it is assumed to be a filename.
+ * @param[out] out Stores the created node.
+ * @param source Specifies the node to be created.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_node_from_source(bithenge_node_t **out, const char *source)
+{
+	if (str_chr(source, ':')) {
+		if (!str_lcmp(source, "file:", 5)) {
+			// Example: file:/textdemo
+			return bithenge_new_file_blob(out, source + 5);
+#ifdef __HELENOS__
+		} else if (!str_lcmp(source, "block:", 6)) {
+			// Example: block:bd/initrd
+			service_id_t service_id;
+			int rc = loc_service_get_id(source + 6, &service_id, 0);
+			if (rc != EOK)
+				return rc;
+			return bithenge_new_block_blob(out, service_id);
+#endif
+		} else if (!str_lcmp(source, "hex:", 4)) {
+			// Example: hex:04000000
+			return blob_from_hex(out, source + 4);
+		} else {
+			return EINVAL;
+		}
+	}
+	return bithenge_new_file_blob(out, source);
+}
+
+/** @}
+ */
Index: uspace/lib/bithenge/src/transform.c
===================================================================
--- uspace/lib/bithenge/src/transform.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/transform.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,1078 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Transforms.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <bithenge/blob.h>
+#include <bithenge/print.h>
+#include <bithenge/transform.h>
+#include "common.h"
+
+
+
+/***************** transform                                 *****************/
+
+/** Initialize a new transform.
+ * @param[out] self Transform to initialize.
+ * @param[in] ops Operations provided by the transform.
+ * @param num_params The number of parameters required. If this is nonzero, the
+ * transform will get its own context with parameters, probably provided by a
+ * param_wrapper. If this is zero, the existing outer context will be used with
+ * whatever parameters it has, so they can be passed to any param_wrappers
+ * within.
+ * @return EOK or an error code from errno.h. */
+int bithenge_init_transform(bithenge_transform_t *self,
+    const bithenge_transform_ops_t *ops, int num_params)
+{
+	assert(ops);
+	assert(ops->apply || ops->prefix_apply);
+	assert(ops->destroy);
+	if (bithenge_should_fail())
+		return ENOMEM;
+	self->ops = ops;
+	self->refs = 1;
+	self->num_params = num_params;
+	return EOK;
+}
+
+static void transform_indestructible(bithenge_transform_t *self)
+{
+	assert(false);
+}
+
+/** Apply a transform. Takes ownership of nothing.
+ * @memberof bithenge_transform_t
+ * @param self The transform.
+ * @param scope The scope.
+ * @param in The input tree.
+ * @param[out] out Where the output tree will be stored.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_transform_apply(bithenge_transform_t *self,
+    bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
+{
+	assert(self);
+	assert(self->ops);
+	if (self->ops->apply)
+		return self->ops->apply(self, scope, in, out);
+
+	if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
+		return EINVAL;
+	aoff64_t self_size, whole_size;
+	int rc = bithenge_transform_prefix_apply(self, scope,
+	    bithenge_node_as_blob(in), out, &self_size);
+	if (rc != EOK)
+		return rc;
+	rc = bithenge_blob_size(bithenge_node_as_blob(in), &whole_size);
+	if (rc == EOK && whole_size != self_size)
+		rc = EINVAL;
+	if (rc != EOK) {
+		bithenge_node_dec_ref(*out);
+		return rc;
+	}
+	return EOK;
+}
+
+/** Find the length of the prefix of a blob this transform can use as input. In
+ * other words, figure out how many bytes this transform will use up.  This
+ * method is optional and can return an error, but it must succeed for struct
+ * subtransforms. Takes ownership of nothing.
+ * @memberof bithenge_transform_t
+ * @param self The transform.
+ * @param scope The scope.
+ * @param blob The blob.
+ * @param[out] out Where the prefix length will be stored.
+ * @return EOK on success, ENOTSUP if not supported, or another error code from
+ * errno.h. */
+int bithenge_transform_prefix_length(bithenge_transform_t *self,
+    bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
+{
+	assert(self);
+	assert(self->ops);
+	if (self->ops->prefix_length)
+		return self->ops->prefix_length(self, scope, blob, out);
+	if (!self->ops->prefix_apply)
+		return ENOTSUP;
+
+	bithenge_node_t *node;
+	int rc = bithenge_transform_prefix_apply(self, scope, blob, &node,
+	    out);
+	if (rc != EOK)
+		return rc;
+	bithenge_node_dec_ref(node);
+	return EOK;
+}
+
+/** Apply this transform to a prefix of a blob. In other words, feed as much of
+ * the blob into this transform as possible. Takes ownership of nothing.
+ * @memberof bithenge_transform_t
+ * @param self The transform.
+ * @param scope The scope.
+ * @param blob The blob.
+ * @param[out] out_node Holds the result of applying this transform to the
+ * prefix.
+ * @param[out] out_size Holds the size of the prefix. Can be null, in which
+ * case the size is not determined.
+ * @return EOK on success, ENOTSUP if not supported, or another error code from
+ * errno.h. */
+int bithenge_transform_prefix_apply(bithenge_transform_t *self,
+    bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
+    aoff64_t *out_size)
+{
+	assert(self);
+	assert(self->ops);
+	if (self->ops->prefix_apply)
+		return self->ops->prefix_apply(self, scope, blob, out_node,
+		    out_size);
+	if (!self->ops->prefix_length)
+		return ENOTSUP;
+
+	aoff64_t size;
+	int rc = bithenge_transform_prefix_length(self, scope, blob, &size);
+	if (rc != EOK)
+		return rc;
+	bithenge_node_t *prefix_blob;
+	bithenge_blob_inc_ref(blob);
+	rc = bithenge_new_subblob(&prefix_blob, blob, 0, size);
+	if (rc != EOK)
+		return rc;
+	rc = bithenge_transform_apply(self, scope, prefix_blob, out_node);
+	bithenge_node_dec_ref(prefix_blob);
+	if (out_size)
+		*out_size = size;
+	return rc;
+}
+
+
+
+/***************** scope                                     *****************/
+
+/** Create a transform scope. It must be dereferenced with @a
+ * bithenge_scope_dec_ref after it is used. Takes ownership of nothing.
+ * @memberof bithenge_scope_t
+ * @param[out] out Holds the new scope.
+ * @param outer The outer scope, or NULL.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_scope_new(bithenge_scope_t **out, bithenge_scope_t *outer)
+{
+	bithenge_scope_t *self = malloc(sizeof(*self));
+	if (!self)
+		return ENOMEM;
+	self->refs = 1;
+	if (outer)
+		bithenge_scope_inc_ref(outer);
+	self->outer = outer;
+	self->error = NULL;
+	self->barrier = false;
+	self->num_params = 0;
+	self->params = NULL;
+	self->current_node = NULL;
+	self->in_node = NULL;
+	*out = self;
+	return EOK;
+}
+
+/** Dereference a transform scope.
+ * @memberof bithenge_scope_t
+ * @param self The scope to dereference, or NULL. */
+void bithenge_scope_dec_ref(bithenge_scope_t *self)
+{
+	if (!self)
+		return;
+	if (--self->refs)
+		return;
+	bithenge_node_dec_ref(self->current_node);
+	for (int i = 0; i < self->num_params; i++)
+		bithenge_node_dec_ref(self->params[i]);
+	bithenge_scope_dec_ref(self->outer);
+	free(self->params);
+	free(self->error);
+	free(self);
+}
+
+/** Get the outer scope of a scope, which may be NULL.
+ * @memberof bithenge_scope_t
+ * @param self The scope to examine.
+ * @return The outer scope, which may be NULL. */
+bithenge_scope_t *bithenge_scope_outer(bithenge_scope_t *self)
+{
+	return self->outer;
+}
+
+/** Get the error message stored in the scope, which may be NULL. The error
+ * message only exists as long as the scope does.
+ * @memberof bithenge_scope_t
+ * @param scope The scope to get the error message from.
+ * @return The error message, or NULL. */
+const char *bithenge_scope_get_error(bithenge_scope_t *scope)
+{
+	return scope->error;
+}
+
+/** Set the error message for the scope. The error message is stored in the
+ * outermost scope, but if any scope already has an error message this error
+ * message is ignored.
+ * @memberof bithenge_scope_t
+ * @param scope The scope.
+ * @param format The format string.
+ * @return EINVAL normally, or another error code from errno.h. */
+int bithenge_scope_error(bithenge_scope_t *scope, const char *format, ...)
+{
+	if (scope->error)
+		return EINVAL;
+	while (scope->outer) {
+		scope = scope->outer;
+		if (scope->error)
+			return EINVAL;
+	}
+	size_t space_left = 256;
+	scope->error = malloc(space_left);
+	if (!scope->error)
+		return ENOMEM;
+	char *out = scope->error;
+	va_list ap;
+	va_start(ap, format);
+
+	while (*format) {
+		if (format[0] == '%' && format[1] == 't') {
+			format += 2;
+			int rc = bithenge_print_node_to_string(&out,
+			    &space_left, BITHENGE_PRINT_PYTHON,
+			    va_arg(ap, bithenge_node_t *));
+			if (rc != EOK) {
+				va_end(ap);
+				return rc;
+			}
+		} else {
+			const char *end = str_chr(format, '%');
+			if (!end)
+				end = format + str_length(format);
+			size_t size = min((size_t)(end - format),
+			    space_left - 1);
+			memcpy(out, format, size);
+			format = end;
+			out += size;
+			space_left -= size;
+		}
+	}
+	*out = '\0';
+
+	va_end(ap);
+	return EINVAL;
+}
+
+/** Get the current node being created, which may be NULL.
+ * @memberof bithenge_scope_t
+ * @param scope The scope to get the current node from.
+ * @return The node being created, or NULL. */
+bithenge_node_t *bithenge_scope_get_current_node(bithenge_scope_t *scope)
+{
+	if (scope->current_node)
+		bithenge_node_inc_ref(scope->current_node);
+	return scope->current_node;
+}
+
+/** Set the current node being created. Takes a reference to @a node.
+ * @memberof bithenge_scope_t
+ * @param scope The scope to set the current node in.
+ * @param node The current node being created, or NULL. */
+void bithenge_scope_set_current_node(bithenge_scope_t *scope,
+    bithenge_node_t *node)
+{
+	bithenge_node_dec_ref(scope->current_node);
+	scope->current_node = node;
+}
+
+/** Get the current input node, which may be NULL.
+ * @memberof bithenge_scope_t
+ * @param scope The scope to get the current input node from.
+ * @return The input node, or NULL. */
+bithenge_node_t *bithenge_scope_in_node(bithenge_scope_t *scope)
+{
+	if (scope->in_node)
+		bithenge_node_inc_ref(scope->in_node);
+	return scope->in_node;
+}
+
+/** Set the current input node. Takes a reference to @a node.
+ * @memberof bithenge_scope_t
+ * @param scope The scope to set the input node in.
+ * @param node The input node, or NULL. */
+void bithenge_scope_set_in_node(bithenge_scope_t *scope, bithenge_node_t *node)
+{
+	bithenge_node_dec_ref(scope->in_node);
+	scope->in_node = node;
+}
+
+/** Set a scope as a barrier.
+ * @memberof bithenge_scope_t
+ * @param self The scope to change. */
+void bithenge_scope_set_barrier(bithenge_scope_t *self)
+{
+	self->barrier = true;
+}
+
+/** Check whether a scope is a barrier, meaning that variable lookup stops at
+ * it.
+ * @memberof bithenge_scope_t
+ * @param self The scope to check.
+ * @return Whether the scope is a barrier. */
+bool bithenge_scope_is_barrier(bithenge_scope_t *self)
+{
+	return self->barrier;
+}
+
+/** Allocate parameters. The parameters must then be set with @a
+ * bithenge_scope_set_param. This must not be called on a scope that already
+ * has parameters.
+ * @memberof bithenge_scope_t
+ * @param scope The scope in which to allocate parameters.
+ * @param num_params The number of parameters to allocate.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_scope_alloc_params(bithenge_scope_t *scope, int num_params)
+{
+	scope->params = malloc(sizeof(*scope->params) * num_params);
+	if (!scope->params)
+		return ENOMEM;
+	scope->num_params = num_params;
+	for (int i = 0; i < num_params; i++)
+		scope->params[i] = NULL;
+	return EOK;
+}
+
+/** Set a parameter. Takes a reference to @a node. Note that range checking is
+ * not done in release builds.
+ * @memberof bithenge_scope_t
+ * @param scope The scope in which to allocate parameters.
+ * @param i The index of the parameter to set.
+ * @param node The value to store in the parameter.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_scope_set_param( bithenge_scope_t *scope, int i,
+    bithenge_node_t *node)
+{
+	assert(scope);
+	assert(i >= 0 && i < scope->num_params);
+	if (bithenge_should_fail()) {
+		bithenge_node_dec_ref(node);
+		return ENOMEM;
+	}
+	scope->params[i] = node;
+	return EOK;
+}
+
+/** Get a parameter. Note that range checking is not done in release builds.
+ * @memberof bithenge_scope_t
+ * @param scope The scope to get the parameter from.
+ * @param i The index of the parameter to set.
+ * @param[out] out Stores a new reference to the parameter.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_scope_get_param(bithenge_scope_t *scope, int i,
+    bithenge_node_t **out)
+{
+	assert(scope);
+	if (scope->num_params) {
+		assert(i >= 0 && i < scope->num_params);
+		*out = scope->params[i];
+		bithenge_node_inc_ref(*out);
+		return EOK;
+	} else {
+		return bithenge_scope_get_param(scope->outer, i, out);
+	}
+}
+
+
+
+/***************** barrier_transform                         *****************/
+
+typedef struct {
+	bithenge_transform_t base;
+	bithenge_transform_t *transform;
+} barrier_transform_t;
+
+static inline barrier_transform_t *transform_as_barrier(
+    bithenge_transform_t *base)
+{
+	return (barrier_transform_t *)base;
+}
+
+static inline bithenge_transform_t *barrier_as_transform(
+    barrier_transform_t *self)
+{
+	return &self->base;
+}
+
+static int barrier_transform_apply(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
+{
+	barrier_transform_t *self = transform_as_barrier(base);
+	bithenge_scope_t *inner_scope;
+	int rc = bithenge_scope_new(&inner_scope, scope);
+	if (rc != EOK)
+		return rc;
+	bithenge_scope_set_barrier(inner_scope);
+	bithenge_scope_set_in_node(inner_scope, in);
+	rc = bithenge_transform_apply(self->transform, inner_scope, in, out);
+	bithenge_scope_dec_ref(inner_scope);
+	return rc;
+}
+
+static int barrier_transform_prefix_length(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
+{
+	barrier_transform_t *self = transform_as_barrier(base);
+	bithenge_scope_t *inner_scope;
+	int rc = bithenge_scope_new(&inner_scope, scope);
+	if (rc != EOK)
+		return rc;
+	bithenge_scope_set_barrier(inner_scope);
+	bithenge_scope_set_in_node(inner_scope, bithenge_blob_as_node(in));
+	rc = bithenge_transform_prefix_length(self->transform, inner_scope, in,
+	    out);
+	bithenge_scope_dec_ref(inner_scope);
+	return rc;
+}
+
+static int barrier_transform_prefix_apply(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_blob_t *in, bithenge_node_t **out_node,
+    aoff64_t *out_length)
+{
+	barrier_transform_t *self = transform_as_barrier(base);
+	bithenge_scope_t *inner_scope;
+	int rc = bithenge_scope_new(&inner_scope, scope);
+	if (rc != EOK)
+		return rc;
+	bithenge_scope_set_barrier(inner_scope);
+	bithenge_scope_set_in_node(inner_scope, bithenge_blob_as_node(in));
+	rc = bithenge_transform_prefix_apply(self->transform, inner_scope, in,
+	    out_node, out_length);
+	bithenge_scope_dec_ref(inner_scope);
+	return rc;
+}
+
+static void barrier_transform_destroy(bithenge_transform_t *base)
+{
+	barrier_transform_t *self = transform_as_barrier(base);
+	bithenge_transform_dec_ref(self->transform);
+	free(self);
+}
+
+static const bithenge_transform_ops_t barrier_transform_ops = {
+	.apply = barrier_transform_apply,
+	.prefix_length = barrier_transform_prefix_length,
+	.prefix_apply = barrier_transform_prefix_apply,
+	.destroy = barrier_transform_destroy,
+};
+
+/** Set the subtransform of a barrier transform. This must be done before the
+ * barrier transform is used. Takes a reference to @a transform.
+ * @param base The barrier transform.
+ * @param transform The subtransform to use for all operations.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_barrier_transform_set_subtransform(bithenge_transform_t *base,
+    bithenge_transform_t *transform)
+{
+	assert(transform);
+	assert(bithenge_transform_num_params(transform) == 0);
+
+	if (bithenge_should_fail()) {
+		bithenge_transform_dec_ref(transform);
+		return ENOMEM;
+	}
+
+	barrier_transform_t *self = transform_as_barrier(base);
+	assert(!self->transform);
+	self->transform = transform;
+	return EOK;
+}
+
+/** Create a wrapper transform that creates a new scope. This ensures nothing
+ * from the outer scope is passed in, other than parameters. The wrapper may
+ * have a different value for num_params. The subtransform must be set with @a
+ * bithenge_barrier_transform_set_subtransform before the result is used.
+ * @param[out] out Holds the created transform.
+ * @param num_params The number of parameters to require, which may be 0.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_barrier_transform(bithenge_transform_t **out, int num_params)
+{
+	int rc;
+	barrier_transform_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+	rc = bithenge_init_transform(barrier_as_transform(self),
+	    &barrier_transform_ops, num_params);
+	if (rc != EOK)
+		goto error;
+	self->transform = NULL;
+	*out = barrier_as_transform(self);
+	return EOK;
+error:
+	free(self);
+	return rc;
+}
+
+
+
+/***************** ascii                                     *****************/
+
+static int ascii_apply(bithenge_transform_t *self, bithenge_scope_t *scope,
+    bithenge_node_t *in, bithenge_node_t **out)
+{
+	int rc;
+	if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
+		return EINVAL;
+	bithenge_blob_t *blob = bithenge_node_as_blob(in);
+	aoff64_t size;
+	rc = bithenge_blob_size(blob, &size);
+	if (rc != EOK)
+		return rc;
+
+	char *buffer = malloc(size + 1);
+	if (!buffer)
+		return ENOMEM;
+	aoff64_t size_read = size;
+	rc = bithenge_blob_read(blob, 0, buffer, &size_read);
+	if (rc != EOK) {
+		free(buffer);
+		return rc;
+	}
+	if (size_read != size) {
+		free(buffer);
+		return EINVAL;
+	}
+	buffer[size] = '\0';
+
+	/* TODO: what if the OS encoding is incompatible with ASCII? */
+	return bithenge_new_string_node(out, buffer, true);
+}
+
+static const bithenge_transform_ops_t ascii_ops = {
+	.apply = ascii_apply,
+	.destroy = transform_indestructible,
+};
+
+/** The ASCII text transform. */
+bithenge_transform_t bithenge_ascii_transform = {
+	&ascii_ops, 1, 0
+};
+
+
+
+/***************** bit                                       *****************/
+
+static int bit_prefix_apply(bithenge_transform_t *self,
+    bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
+    aoff64_t *out_size)
+{
+	char buffer;
+	aoff64_t size = 1;
+	int rc = bithenge_blob_read_bits(blob, 0, &buffer, &size, true);
+	if (rc != EOK)
+		return rc;
+	if (size != 1)
+		return EINVAL;
+	if (out_size)
+		*out_size = size;
+	return bithenge_new_boolean_node(out_node, (buffer & 1) != 0);
+}
+
+static const bithenge_transform_ops_t bit_ops = {
+	.prefix_apply = bit_prefix_apply,
+	.destroy = transform_indestructible,
+};
+
+/** A transform that decodes a bit as a boolean. */
+bithenge_transform_t bithenge_bit_transform = {
+	&bit_ops, 1, 0
+};
+
+
+
+/***************** bits_be, bits_le                          *****************/
+
+typedef struct {
+	bithenge_blob_t base;
+	bithenge_blob_t *bytes;
+	bool little_endian;
+} bits_xe_blob_t;
+
+static bits_xe_blob_t *blob_as_bits_xe(bithenge_blob_t *base)
+{
+	return (bits_xe_blob_t *)base;
+}
+
+static bithenge_blob_t *bits_xe_as_blob(bits_xe_blob_t *self)
+{
+	return &self->base;
+}
+
+static int bits_xe_size(bithenge_blob_t *base, aoff64_t *out)
+{
+	bits_xe_blob_t *self = blob_as_bits_xe(base);
+	int rc = bithenge_blob_size(self->bytes, out);
+	*out *= 8;
+	return rc;
+}
+
+static uint8_t reverse_byte(uint8_t val)
+{
+	val = ((val & 0x0f) << 4) ^ ((val & 0xf0) >> 4);
+	val = ((val & 0x33) << 2) ^ ((val & 0xcc) >> 2);
+	val = ((val & 0x55) << 1) ^ ((val & 0xaa) >> 1);
+	return val;
+}
+
+static int bits_xe_read_bits(bithenge_blob_t *base, aoff64_t offset,
+    char *buffer, aoff64_t *size, bool little_endian)
+{
+	bits_xe_blob_t *self = blob_as_bits_xe(base);
+	aoff64_t bytes_offset = offset / 8;
+	aoff64_t bit_offset = offset % 8;
+	aoff64_t output_num_bytes = (*size + 7) / 8;
+	aoff64_t bytes_size = (*size + bit_offset + 7) / 8;
+	bool separate_buffer = bit_offset != 0;
+	uint8_t *bytes_buffer;
+	if (separate_buffer) {
+		/* Allocate an extra byte, to make sure byte1 can be read. */
+		bytes_buffer = malloc(bytes_size + 1);
+		if (!bytes_buffer)
+			return ENOMEM;
+	} else
+		bytes_buffer = (uint8_t *)buffer;
+
+	int rc = bithenge_blob_read(self->bytes, bytes_offset,
+	    (char *)bytes_buffer, &bytes_size);
+	if (rc != EOK)
+		goto end;
+	*size = min(*size, bytes_size * 8 - bit_offset);
+
+	if (little_endian != self->little_endian)
+		for (aoff64_t i = 0; i < bytes_size; i++)
+			bytes_buffer[i] = reverse_byte(bytes_buffer[i]);
+
+	if (bit_offset || separate_buffer) {
+		for (aoff64_t i = 0; i < output_num_bytes; i++) {
+			uint8_t byte0 = bytes_buffer[i];
+			uint8_t	byte1 = bytes_buffer[i + 1];
+			buffer[i] = little_endian ?
+			    (byte0 >> bit_offset) ^ (byte1 << (8 - bit_offset)) :
+			    (byte0 << bit_offset) ^ (byte1 >> (8 - bit_offset));
+		}
+	}
+
+end:
+	if (separate_buffer)
+		free(bytes_buffer);
+	return rc;
+}
+
+static void bits_xe_destroy(bithenge_blob_t *base)
+{
+	bits_xe_blob_t *self = blob_as_bits_xe(base);
+	bithenge_blob_dec_ref(self->bytes);
+	free(self);
+}
+
+static const bithenge_random_access_blob_ops_t bits_xe_blob_ops = {
+	.size = bits_xe_size,
+	.read_bits = bits_xe_read_bits,
+	.destroy = bits_xe_destroy,
+};
+
+static int bits_xe_apply(bithenge_transform_t *self, bithenge_scope_t *scope,
+    bithenge_node_t *in, bithenge_node_t **out)
+{
+	if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
+		return EINVAL;
+	bits_xe_blob_t *blob = malloc(sizeof(*blob));
+	if (!blob)
+		return ENOMEM;
+	int rc = bithenge_init_random_access_blob(bits_xe_as_blob(blob),
+	    &bits_xe_blob_ops);
+	if (rc != EOK) {
+		free(blob);
+		return rc;
+	}
+	bithenge_node_inc_ref(in);
+	blob->bytes = bithenge_node_as_blob(in);
+	blob->little_endian = (self == &bithenge_bits_le_transform);
+	*out = bithenge_blob_as_node(bits_xe_as_blob(blob));
+	return EOK;
+}
+
+static const bithenge_transform_ops_t bits_xe_ops = {
+	.apply = bits_xe_apply,
+	.destroy = transform_indestructible,
+};
+
+/** A transform that converts a byte blob to a bit blob, most-significant bit
+ * first. */
+bithenge_transform_t bithenge_bits_be_transform = {
+	&bits_xe_ops, 1, 0
+};
+
+/** A transform that converts a byte blob to a bit blob, least-significant bit
+ * first. */
+bithenge_transform_t bithenge_bits_le_transform = {
+	&bits_xe_ops, 1, 0
+};
+
+
+
+/***************** invalid                                   *****************/
+
+static int invalid_apply(bithenge_transform_t *self, bithenge_scope_t *scope,
+    bithenge_node_t *in, bithenge_node_t **out)
+{
+	return EINVAL;
+}
+
+static const bithenge_transform_ops_t invalid_ops = {
+	.apply = invalid_apply,
+	.destroy = transform_indestructible,
+};
+
+/** A transform that always raises an error. */
+bithenge_transform_t bithenge_invalid_transform = {
+	&invalid_ops, 1, 0
+};
+
+
+
+/***************** known_length                              *****************/
+
+static int known_length_apply(bithenge_transform_t *self,
+    bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
+{
+	bithenge_node_t *length_node;
+	int rc = bithenge_scope_get_param(scope, 0, &length_node);
+	if (rc != EOK)
+		return rc;
+	if (bithenge_node_type(length_node) != BITHENGE_NODE_INTEGER) {
+		bithenge_node_dec_ref(length_node);
+		return EINVAL;
+	}
+	bithenge_int_t length = bithenge_integer_node_value(length_node);
+	bithenge_node_dec_ref(length_node);
+
+	if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
+		return EINVAL;
+	aoff64_t size;
+	rc = bithenge_blob_size(bithenge_node_as_blob(in), &size);
+	if (rc != EOK)
+		return rc;
+	if (length != (bithenge_int_t)size)
+		return EINVAL;
+
+	bithenge_node_inc_ref(in);
+	*out = in;
+	return EOK;
+}
+
+static int known_length_prefix_length(bithenge_transform_t *self,
+    bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
+{
+	bithenge_node_t *length_node;
+	int rc = bithenge_scope_get_param(scope, 0, &length_node);
+	if (rc != EOK)
+		return rc;
+	if (bithenge_node_type(length_node) != BITHENGE_NODE_INTEGER) {
+		bithenge_node_dec_ref(length_node);
+		return EINVAL;
+	}
+	bithenge_int_t length = bithenge_integer_node_value(length_node);
+	bithenge_node_dec_ref(length_node);
+
+	*out = (aoff64_t)length;
+	return EOK;
+}
+
+static const bithenge_transform_ops_t known_length_ops = {
+	.apply = known_length_apply,
+	.prefix_length = known_length_prefix_length,
+	.destroy = transform_indestructible,
+};
+
+/** Pass through a blob, but require its length to equal the first argument. */
+bithenge_transform_t bithenge_known_length_transform = {
+	&known_length_ops, 1, 1
+};
+
+static int nonzero_boolean_apply(bithenge_transform_t *self,
+    bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
+{
+	if (bithenge_node_type(in) != BITHENGE_NODE_INTEGER)
+		return EINVAL;
+	bool value = bithenge_integer_node_value(in) != 0;
+	return bithenge_new_boolean_node(out, value);
+}
+
+static const bithenge_transform_ops_t nonzero_boolean_ops = {
+	.apply = nonzero_boolean_apply,
+	.destroy = transform_indestructible,
+};
+
+/** A transform that converts integers to booleans, true if nonzero. */
+bithenge_transform_t bithenge_nonzero_boolean_transform = {
+	&nonzero_boolean_ops, 1, 0
+};
+
+static int prefix_length_1(bithenge_transform_t *self, bithenge_scope_t *scope,
+    bithenge_blob_t *blob, aoff64_t *out)
+{
+	*out = 1;
+	return EOK;
+}
+
+static int prefix_length_2(bithenge_transform_t *self, bithenge_scope_t *scope,
+    bithenge_blob_t *blob, aoff64_t *out)
+{
+	*out = 2;
+	return EOK;
+}
+
+static int prefix_length_4(bithenge_transform_t *self, bithenge_scope_t *scope,
+    bithenge_blob_t *blob, aoff64_t *out)
+{
+	*out = 4;
+	return EOK;
+}
+
+static int prefix_length_8(bithenge_transform_t *self, bithenge_scope_t *scope,
+    bithenge_blob_t *blob, aoff64_t *out)
+{
+	*out = 8;
+	return EOK;
+}
+
+/** @cond internal */
+#define MAKE_UINT_TRANSFORM(NAME, TYPE, ENDIAN, PREFIX_LENGTH_FUNC)            \
+	static int NAME##_apply(bithenge_transform_t *self,                    \
+	    bithenge_scope_t *scope, bithenge_node_t *in,                      \
+	    bithenge_node_t **out)                                             \
+	{                                                                      \
+		int rc;                                                        \
+		if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)              \
+			return EINVAL;                                         \
+		bithenge_blob_t *blob = bithenge_node_as_blob(in);             \
+		                                                               \
+		/* Read too many bytes; success means the blob is too long. */ \
+		TYPE val[2];                                                   \
+		aoff64_t size = sizeof(val[0]) + 1;                            \
+		rc = bithenge_blob_read(blob, 0, (char *)val, &size);          \
+		if (rc != EOK)                                                 \
+			return rc;                                             \
+		if (size != sizeof(val[0]))                                    \
+			return EINVAL;                                         \
+		                                                               \
+		return bithenge_new_integer_node(out, ENDIAN(val[0]));         \
+	}                                                                      \
+	                                                                       \
+	static const bithenge_transform_ops_t NAME##_ops = {                   \
+		.apply = NAME##_apply,                                         \
+		.prefix_length = PREFIX_LENGTH_FUNC,                           \
+		.destroy = transform_indestructible,                           \
+	};                                                                     \
+	                                                                       \
+	bithenge_transform_t bithenge_##NAME##_transform = {                   \
+		&NAME##_ops, 1, 0                                              \
+	}
+
+MAKE_UINT_TRANSFORM(uint8   , uint8_t ,                 , prefix_length_1);
+MAKE_UINT_TRANSFORM(uint16le, uint16_t, uint16_t_le2host, prefix_length_2);
+MAKE_UINT_TRANSFORM(uint16be, uint16_t, uint16_t_be2host, prefix_length_2);
+MAKE_UINT_TRANSFORM(uint32le, uint32_t, uint32_t_le2host, prefix_length_4);
+MAKE_UINT_TRANSFORM(uint32be, uint32_t, uint32_t_be2host, prefix_length_4);
+MAKE_UINT_TRANSFORM(uint64le, uint64_t, uint64_t_le2host, prefix_length_8);
+MAKE_UINT_TRANSFORM(uint64be, uint64_t, uint64_t_be2host, prefix_length_8);
+/** @endcond */
+
+
+
+/***************** uint_be, uint_le                          *****************/
+
+static int uint_xe_prefix_apply(bithenge_transform_t *self,
+    bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
+    aoff64_t *out_size)
+{
+	bool little_endian = (self == &bithenge_uint_le_transform);
+	bithenge_node_t *num_bits_node;
+	int rc = bithenge_scope_get_param(scope, 0, &num_bits_node);
+	if (rc != EOK)
+		return rc;
+	if (bithenge_node_type(num_bits_node) != BITHENGE_NODE_INTEGER) {
+		bithenge_node_dec_ref(num_bits_node);
+		return EINVAL;
+	}
+	bithenge_int_t num_bits = bithenge_integer_node_value(num_bits_node);
+	bithenge_node_dec_ref(num_bits_node);
+	if (num_bits < 0)
+		return EINVAL;
+	if ((size_t)num_bits > sizeof(bithenge_int_t) * 8 - 1)
+		return EINVAL;
+
+	aoff64_t size = num_bits;
+	uint8_t buffer[sizeof(bithenge_int_t)];
+	rc = bithenge_blob_read_bits(blob, 0, (char *)buffer, &size,
+	    little_endian);
+	if (rc != EOK)
+		return rc;
+	if (size != (aoff64_t)num_bits)
+		return EINVAL;
+	if (out_size)
+		*out_size = size;
+
+	bithenge_int_t result = 0;
+	bithenge_int_t num_easy_bytes = num_bits / 8;
+	if (little_endian) {
+		for (bithenge_int_t i = 0; i < num_easy_bytes; i++)
+			result += buffer[i] << 8 * i;
+		if (num_bits % 8)
+			result += (buffer[num_easy_bytes] &
+			    ((1 << num_bits % 8) - 1)) << 8 * num_easy_bytes;
+	} else {
+		for (bithenge_int_t i = 0; i < num_easy_bytes; i++)
+			result += buffer[i] << (num_bits - 8 * (i + 1));
+		if (num_bits % 8)
+			result += buffer[num_easy_bytes] >> (8 - num_bits % 8);
+	}
+
+	return bithenge_new_integer_node(out_node, result);
+}
+
+static const bithenge_transform_ops_t uint_xe_ops = {
+	.prefix_apply = uint_xe_prefix_apply,
+	.destroy = transform_indestructible,
+};
+
+/** A transform that reads an unsigned integer from an arbitrary number of
+ * bits, most-significant bit first. */
+bithenge_transform_t bithenge_uint_be_transform = {
+	&uint_xe_ops, 1, 1
+};
+
+/** A transform that reads an unsigned integer from an arbitrary number of
+ * bits, least-significant bit first. */
+bithenge_transform_t bithenge_uint_le_transform = {
+	&uint_xe_ops, 1, 1
+};
+
+
+
+/***************** zero_terminated                           *****************/
+
+static int zero_terminated_apply(bithenge_transform_t *self,
+    bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
+{
+	int rc;
+	if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
+		return EINVAL;
+	bithenge_blob_t *blob = bithenge_node_as_blob(in);
+	aoff64_t size;
+	rc = bithenge_blob_size(blob, &size);
+	if (rc != EOK)
+		return rc;
+	if (size < 1)
+		return EINVAL;
+	char ch;
+	aoff64_t size_read = 1;
+	rc = bithenge_blob_read(blob, size - 1, &ch, &size_read);
+	if (rc != EOK)
+		return rc;
+	if (size_read != 1 || ch != '\0')
+		return EINVAL;
+	bithenge_blob_inc_ref(blob);
+	return bithenge_new_subblob(out, blob, 0, size - 1);
+}
+
+static int zero_terminated_prefix_length(bithenge_transform_t *self,
+    bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
+{
+	int rc;
+	char buffer[4096];
+	aoff64_t offset = 0, size_read = sizeof(buffer);
+	do {
+		rc = bithenge_blob_read(blob, offset, buffer, &size_read);
+		if (rc != EOK)
+			return rc;
+		char *found = memchr(buffer, '\0', size_read);
+		if (found) {
+			*out = found - buffer + offset + 1;
+			return EOK;
+		}
+		offset += size_read;
+	} while (size_read == sizeof(buffer));
+	return EINVAL;
+}
+
+static const bithenge_transform_ops_t zero_terminated_ops = {
+	.apply = zero_terminated_apply,
+	.prefix_length = zero_terminated_prefix_length,
+	.destroy = transform_indestructible,
+};
+
+/** The zero-terminated data transform. */
+bithenge_transform_t bithenge_zero_terminated_transform = {
+	&zero_terminated_ops, 1, 0
+};
+
+static bithenge_named_transform_t primitive_transforms[] = {
+	{"ascii", &bithenge_ascii_transform},
+	{"bit", &bithenge_bit_transform},
+	{"bits_be", &bithenge_bits_be_transform},
+	{"bits_le", &bithenge_bits_le_transform},
+	{"known_length", &bithenge_known_length_transform},
+	{"nonzero_boolean", &bithenge_nonzero_boolean_transform},
+	{"uint8", &bithenge_uint8_transform},
+	{"uint16be", &bithenge_uint16be_transform},
+	{"uint16le", &bithenge_uint16le_transform},
+	{"uint32be", &bithenge_uint32be_transform},
+	{"uint32le", &bithenge_uint32le_transform},
+	{"uint64be", &bithenge_uint64be_transform},
+	{"uint64le", &bithenge_uint64le_transform},
+	{"uint_be", &bithenge_uint_be_transform},
+	{"uint_le", &bithenge_uint_le_transform},
+	{"zero_terminated", &bithenge_zero_terminated_transform},
+	{NULL, NULL}
+};
+
+/** An array of named built-in transforms. */
+bithenge_named_transform_t *bithenge_primitive_transforms = primitive_transforms;
+
+/** @}
+ */
Index: uspace/lib/bithenge/src/tree.c
===================================================================
--- uspace/lib/bithenge/src/tree.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/bithenge/src/tree.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Trees and nodes.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <bithenge/blob.h>
+#include <bithenge/tree.h>
+#include "common.h"
+
+static void blob_destroy(bithenge_node_t *base)
+{
+	bithenge_blob_t *self = bithenge_node_as_blob(base);
+	assert(self->base.blob_ops);
+	self->base.blob_ops->destroy(self);
+}
+
+static void node_destroy(bithenge_node_t *self)
+{
+	switch (bithenge_node_type(self)) {
+	case BITHENGE_NODE_BLOB:
+		blob_destroy(self);
+		return;
+	case BITHENGE_NODE_STRING:
+		if (self->string_value.needs_free)
+			free((void *)self->string_value.ptr);
+		break;
+	case BITHENGE_NODE_INTERNAL:
+		self->internal_ops->destroy(self);
+		return;
+	case BITHENGE_NODE_BOOLEAN:
+		return; /* The boolean nodes are allocated statically below. */
+	case BITHENGE_NODE_INTEGER: /* pass-through */
+		break;
+	}
+	free(self);
+}
+
+/** Decrement a node's reference count and free it if appropriate.
+ * @memberof bithenge_node_t
+ * @param node The node to dereference, or NULL. */
+void bithenge_node_dec_ref(bithenge_node_t *node)
+{
+	if (!node)
+		return;
+	assert (node->refs > 0);
+	if (--node->refs == 0)
+		node_destroy(node);
+}
+
+typedef struct {
+	bithenge_node_t *key;
+	bithenge_node_t **out;
+} get_for_each_data_t;
+
+static int get_for_each_func(bithenge_node_t *key, bithenge_node_t *value,
+    void *raw_data)
+{
+	get_for_each_data_t *data = (get_for_each_data_t *)raw_data;
+	bool equal;
+	int rc = bithenge_node_equal(&equal, key, data->key);
+	bithenge_node_dec_ref(key);
+	if (rc != EOK)
+		return rc;
+	if (equal) {
+		*data->out = value;
+		return EEXIST;
+	}
+	bithenge_node_dec_ref(value);
+	return EOK;
+}
+
+/** Get a child of a node. Takes ownership of the key. If the node does not
+ * provide this function, for_each will be used as an alternative, which may be
+ * very slow. Also works for blob nodes to find the byte value at a given
+ * index.
+ * @memberof bithenge_node_t
+ * @param self The internal/blob node to find a child of.
+ * @param key The key to search for.
+ * @param[out] out Holds the found node.
+ * @return EOK on success, ENOENT if not found, or another error code from
+ * errno.h. */
+int bithenge_node_get(bithenge_node_t *self, bithenge_node_t *key,
+    bithenge_node_t **out)
+{
+	if (self->type == BITHENGE_NODE_BLOB) {
+		if (bithenge_node_type(key) != BITHENGE_NODE_INTEGER) {
+			bithenge_node_dec_ref(key);
+			return ENOENT;
+		}
+		bithenge_int_t offset = bithenge_integer_node_value(key);
+		bithenge_node_dec_ref(key);
+		uint8_t byte;
+		aoff64_t size = 1;
+		int rc = bithenge_blob_read(bithenge_node_as_blob(self),
+		    offset, (char *)&byte, &size);
+		if (rc != EOK)
+			return rc;
+		if (size != 1)
+			return ENOENT;
+
+		return bithenge_new_integer_node(out, byte);
+	}
+
+	assert(self->type == BITHENGE_NODE_INTERNAL);
+	if (self->internal_ops->get)
+		return self->internal_ops->get(self, key, out);
+	*out = NULL;
+	get_for_each_data_t data = {key, out};
+	int rc = bithenge_node_for_each(self, get_for_each_func, &data);
+	bithenge_node_dec_ref(key);
+	if (rc == EEXIST && *out)
+		return EOK;
+	if (rc == EOK)
+		rc = ENOENT;
+	bithenge_node_dec_ref(*out);
+	return rc;
+}
+
+/** Initialize an internal node.
+ * @memberof bithenge_node_t
+ * @param[out] self The node.
+ * @param[in] ops The operations provided.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_init_internal_node(bithenge_node_t *self,
+    const bithenge_internal_node_ops_t *ops)
+{
+	self->type = BITHENGE_NODE_INTERNAL;
+	self->refs = 1;
+	self->internal_ops = ops;
+	return EOK;
+}
+
+static void internal_node_indestructible(bithenge_node_t *self)
+{
+	assert(false);
+}
+
+static int empty_internal_node_for_each(bithenge_node_t *base,
+    bithenge_for_each_func_t func, void *data)
+{
+	return EOK;
+}
+
+static int empty_internal_node_get(bithenge_node_t *self, bithenge_node_t *key,
+    bithenge_node_t **out)
+{
+	return ENOENT;
+}
+
+static const bithenge_internal_node_ops_t empty_internal_node_ops = {
+	.for_each = empty_internal_node_for_each,
+	.get = empty_internal_node_get,
+	.destroy = internal_node_indestructible,
+};
+
+static bithenge_node_t empty_internal_node = {
+	BITHENGE_NODE_INTERNAL,
+	1,
+	{ .internal_ops = &empty_internal_node_ops },
+};
+
+/** Create an empty internal node.
+ * @param[out] out Holds the created node.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_empty_internal_node(bithenge_node_t **out)
+{
+	if (bithenge_should_fail())
+		return ENOMEM;
+	bithenge_node_inc_ref(&empty_internal_node);
+	*out = &empty_internal_node;
+	return EOK;
+}
+
+typedef struct
+{
+	bithenge_node_t base;
+	bithenge_node_t **nodes;
+	bithenge_int_t len;
+	bool needs_free;
+} simple_internal_node_t;
+
+static simple_internal_node_t *node_as_simple(bithenge_node_t *node)
+{
+	return (simple_internal_node_t *)node;
+}
+
+static bithenge_node_t *simple_as_node(simple_internal_node_t *node)
+{
+	return &node->base;
+}
+
+static int simple_internal_node_for_each(bithenge_node_t *base,
+    bithenge_for_each_func_t func, void *data)
+{
+	int rc;
+	simple_internal_node_t *self = node_as_simple(base);
+	for (bithenge_int_t i = 0; i < self->len; i++) {
+		bithenge_node_inc_ref(self->nodes[2*i+0]);
+		bithenge_node_inc_ref(self->nodes[2*i+1]);
+		rc = func(self->nodes[2*i+0], self->nodes[2*i+1], data);
+		if (rc != EOK)
+			return rc;
+	}
+	return EOK;
+}
+
+static void simple_internal_node_destroy(bithenge_node_t *base)
+{
+	simple_internal_node_t *self = node_as_simple(base);
+	for (bithenge_int_t i = 0; i < 2 * self->len; i++)
+		bithenge_node_dec_ref(self->nodes[i]);
+	if (self->needs_free)
+		free(self->nodes);
+	free(self);
+}
+
+static bithenge_internal_node_ops_t simple_internal_node_ops = {
+	.for_each = simple_internal_node_for_each,
+	.destroy = simple_internal_node_destroy,
+};
+
+/** Create an internal node from a set of keys and values. This function takes
+ * ownership of a reference to the key and value nodes, and optionally the
+ * array @a nodes.
+ * @memberof bithenge_node_t
+ * @param[out] out Stores the created internal node.
+ * @param nodes The array of key-value pairs. Keys are stored at even indices
+ * and values are stored at odd indices.
+ * @param len The number of key-value pairs in the node array.
+ * @param needs_free If true, when the internal node is destroyed it will free
+ * the nodes array rather than just dereferencing each node inside it.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_simple_internal_node(bithenge_node_t **out,
+    bithenge_node_t **nodes, bithenge_int_t len, bool needs_free)
+{
+	int rc;
+	assert(out);
+	simple_internal_node_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+	rc = bithenge_init_internal_node(simple_as_node(self),
+	    &simple_internal_node_ops);
+	if (rc != EOK)
+		goto error;
+	self->nodes = nodes;
+	self->len = len;
+	self->needs_free = needs_free;
+	*out = simple_as_node(self);
+	return EOK;
+error:
+	for (bithenge_int_t i = 0; i < 2 * len; i++)
+		bithenge_node_dec_ref(nodes[i]);
+	if (needs_free)
+		free(nodes);
+	free(self);
+	return rc;
+}
+
+static bithenge_node_t false_node = { BITHENGE_NODE_BOOLEAN, 1, .boolean_value = false };
+static bithenge_node_t true_node = { BITHENGE_NODE_BOOLEAN, 1, .boolean_value = true };
+
+/** Create a boolean node.
+ * @memberof bithenge_node_t
+ * @param[out] out Stores the created boolean node.
+ * @param value The value for the node to hold.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_boolean_node(bithenge_node_t **out, bool value)
+{
+	assert(out);
+	if (bithenge_should_fail())
+		return ENOMEM;
+	*out = value ? &true_node : &false_node;
+	(*out)->refs++;
+	return EOK;
+}
+
+/** Create an integer node.
+ * @memberof bithenge_node_t
+ * @param[out] out Stores the created integer node.
+ * @param value The value for the node to hold.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_integer_node(bithenge_node_t **out, bithenge_int_t value)
+{
+	assert(out);
+	bithenge_node_t *self = malloc(sizeof(*self));
+	if (!self)
+		return ENOMEM;
+	self->type = BITHENGE_NODE_INTEGER;
+	self->refs = 1;
+	self->integer_value = value;
+	*out = self;
+	return EOK;
+}
+
+/** Create a string node.
+ * @memberof bithenge_node_t
+ * @param[out] out Stores the created string node. On error, this is unchanged.
+ * @param value The value for the node to hold.
+ * @param needs_free Whether the string should be freed when the node is
+ * destroyed.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_string_node(bithenge_node_t **out, const char *value, bool needs_free)
+{
+	assert(out);
+	bithenge_node_t *self = malloc(sizeof(*self));
+	if (!self) {
+		if (needs_free)
+			free((void *)value);
+		return ENOMEM;
+	}
+	self->type = BITHENGE_NODE_STRING;
+	self->refs = 1;
+	self->string_value.ptr = value;
+	self->string_value.needs_free = needs_free;
+	*out = self;
+	return EOK;
+}
+
+/** Check whether the contents of two nodes are equal. Does not yet work for
+ * internal nodes. Takes ownership of nothing.
+ * @memberof bithenge_node_t
+ * @param[out] out Holds whether the nodes are equal.
+ * @param a, b Nodes to compare.
+ * @return EOK on success or an error code from errno.h.
+ * @todo Add support for internal nodes. */
+int bithenge_node_equal(bool *out, bithenge_node_t *a, bithenge_node_t *b)
+{
+	if (a->type != b->type) {
+		*out = false;
+		return EOK;
+	}
+	switch (a->type) {
+	case BITHENGE_NODE_INTERNAL:
+		*out = false;
+		return EOK;
+	case BITHENGE_NODE_BOOLEAN:
+		*out = a->boolean_value == b->boolean_value;
+		return EOK;
+	case BITHENGE_NODE_INTEGER:
+		*out = a->integer_value == b->integer_value;
+		return EOK;
+	case BITHENGE_NODE_STRING:
+		*out = !str_cmp(a->string_value.ptr, b->string_value.ptr);
+		return EOK;
+	case BITHENGE_NODE_BLOB:
+		return bithenge_blob_equal(out, bithenge_node_as_blob(a),
+		    bithenge_node_as_blob(b));
+	}
+	return EINVAL;
+}
+
+/** @}
+ */
Index: uspace/lib/block/block.c
===================================================================
--- uspace/lib/block/block.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/block/block.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -255,6 +255,6 @@
 	.key_hash = cache_key_hash,
 	.key_equal = cache_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -71,8 +71,11 @@
 	generic/device/hw_res_parsed.c \
 	generic/device/char_dev.c \
+	generic/device/clock_dev.c \
+	generic/device/battery_dev.c \
 	generic/device/graph_dev.c \
 	generic/device/nic.c \
 	generic/device/pci.c \
 	generic/device/ahci.c \
+	generic/dlfcn.c \
 	generic/elf/elf_load.c \
 	generic/event.c \
@@ -101,4 +104,5 @@
 	generic/io/printf.c \
 	generic/io/log.c \
+	generic/io/logctl.c \
 	generic/io/klog.c \
 	generic/io/snprintf.c \
@@ -106,4 +110,5 @@
 	generic/io/vsnprintf.c \
 	generic/io/printf_core.c \
+	generic/io/con_srv.c \
 	generic/io/console.c \
 	generic/io/visualizer.c \
@@ -111,4 +116,7 @@
 	generic/iplink.c \
 	generic/iplink_srv.c \
+	generic/ieee_double.c \
+	generic/power_of_ten.c \
+	generic/double_to_str.c \
 	generic/malloc.c \
 	generic/sysinfo.c \
@@ -140,5 +148,4 @@
 ifeq ($(CONFIG_RTLD),y)
 	GENERIC_SOURCES += \
-		generic/dlfcn.c \
 		generic/rtld/rtld.c \
 		generic/rtld/dynamic.c \
Index: uspace/lib/c/arch/abs32le/_link.ld.in
===================================================================
--- uspace/lib/c/arch/abs32le/_link.ld.in	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/abs32le/_link.ld.in	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.text : {
@@ -30,4 +23,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/abs32le/include/types.h
===================================================================
--- uspace/lib/c/arch/abs32le/include/types.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/abs32le/include/types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -47,4 +47,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/amd64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/amd64/_link.ld.in	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/amd64/_link.ld.in	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -16,14 +16,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -35,4 +28,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/amd64/include/types.h
===================================================================
--- uspace/lib/c/arch/amd64/include/types.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/amd64/include/types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -47,4 +47,5 @@
 
 typedef uint64_t sysarg_t;
+typedef int64_t native_t;
 
 typedef int64_t ssize_t;
Index: uspace/lib/c/arch/arm32/Makefile.common
===================================================================
--- uspace/lib/c/arch/arm32/Makefile.common	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/arm32/Makefile.common	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -28,5 +28,6 @@
 #
 
-GCC_CFLAGS += -ffixed-r9 -mtp=soft -fno-omit-frame-pointer -march=armv4
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
+GCC_CFLAGS += -ffixed-r9 -mtp=soft -fno-omit-frame-pointer -march=armv4 -mapcs-frame
 
 ENDIANESS = LE
Index: uspace/lib/c/arch/arm32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/arm32/_link.ld.in	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/arm32/_link.ld.in	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 8);
 	
 	.init : {
@@ -34,4 +27,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/arm32/include/types.h
===================================================================
--- uspace/lib/c/arch/arm32/include/types.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/arm32/include/types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -48,4 +48,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/ia32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia32/_link.ld.in	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/ia32/_link.ld.in	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -24,13 +24,4 @@
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-#if defined(LOADER) || defined(DLEXE)
-	.interp : {
-		*(.interp);
-	} :interp :text
-#endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -71,4 +62,11 @@
 	} :text
 #endif
+	
+#if defined(LOADER) || defined(DLEXE)
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
+	
 	. = . + 0x1000;
 	
Index: uspace/lib/c/arch/ia32/include/types.h
===================================================================
--- uspace/lib/c/arch/ia32/include/types.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/ia32/include/types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -47,4 +47,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/ia64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia64/_link.ld.in	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/ia64/_link.ld.in	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -15,13 +15,9 @@
 #ifdef LOADER
 	. = 0x800000000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
 	
-	/* Make sure the code is aligned reasonably */
+	/* Workaround proper alignment of the .init section */
 	. = ALIGN(., 16);
 	
@@ -34,4 +30,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/ia64/include/types.h
===================================================================
--- uspace/lib/c/arch/ia64/include/types.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/ia64/include/types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -57,4 +57,5 @@
 
 typedef uint64_t sysarg_t;
+typedef int64_t native_t;
 
 typedef int64_t ssize_t;
Index: uspace/lib/c/arch/mips32/Makefile.common
===================================================================
--- uspace/lib/c/arch/mips32/Makefile.common	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/mips32/Makefile.common	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -28,4 +28,5 @@
 
 GCC_CFLAGS += -msoft-float -mips3 -mabi=32
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
 
 ENDIANESS = LE
Index: uspace/lib/c/arch/mips32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips32/_link.ld.in	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/mips32/_link.ld.in	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70004000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -34,4 +27,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/mips32/include/types.h
===================================================================
--- uspace/lib/c/arch/mips32/include/types.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/mips32/include/types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -48,4 +48,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/mips32eb/Makefile.common
===================================================================
--- uspace/lib/c/arch/mips32eb/Makefile.common	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/mips32eb/Makefile.common	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -28,4 +28,5 @@
 
 GCC_CFLAGS += -msoft-float -mips3 -mabi=32
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
 
 ENDIANESS = BE
Index: uspace/lib/c/arch/mips64/Makefile.common
===================================================================
--- uspace/lib/c/arch/mips64/Makefile.common	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/mips64/Makefile.common	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -28,4 +28,5 @@
 
 GCC_CFLAGS += -msoft-float -mips3 -mabi=64
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
 AFLAGS = -64
 
Index: uspace/lib/c/arch/mips64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips64/_link.ld.in	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/mips64/_link.ld.in	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -16,14 +16,7 @@
 #ifdef LOADER
 	. = 0x70004000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -35,4 +28,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/mips64/include/types.h
===================================================================
--- uspace/lib/c/arch/mips64/include/types.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/mips64/include/types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -48,4 +48,5 @@
 
 typedef uint64_t sysarg_t;
+typedef int64_t native_t;
 
 typedef int64_t ssize_t;
Index: uspace/lib/c/arch/ppc32/Makefile.common
===================================================================
--- uspace/lib/c/arch/ppc32/Makefile.common	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/ppc32/Makefile.common	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -28,4 +28,5 @@
 
 GCC_CFLAGS += -mcpu=powerpc -msoft-float -m32
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
 AFLAGS = -a32
 
Index: uspace/lib/c/arch/ppc32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ppc32/_link.ld.in	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/ppc32/_link.ld.in	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -16,14 +16,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 4);
 	
 	.init : {
@@ -35,4 +28,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/ppc32/include/types.h
===================================================================
--- uspace/lib/c/arch/ppc32/include/types.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/ppc32/include/types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -47,4 +47,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/sparc64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/sparc64/_link.ld.in	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/sparc64/_link.ld.in	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70004000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -34,4 +27,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/sparc64/include/types.h
===================================================================
--- uspace/lib/c/arch/sparc64/include/types.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/arch/sparc64/include/types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -47,4 +47,5 @@
 
 typedef uint64_t sysarg_t;
+typedef int64_t native_t;
 
 typedef int64_t ssize_t;
Index: uspace/lib/c/generic/adt/hash_table.c
===================================================================
--- uspace/lib/c/generic/adt/hash_table.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/generic/adt/hash_table.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -62,10 +62,10 @@
 
 
-static size_t round_up_size(size_t size);
-static bool alloc_table(size_t bucket_cnt, list_t **pbuckets);
-static void clear_items(hash_table_t *h);
-static void resize(hash_table_t *h, size_t new_bucket_cnt);
-static void grow_if_needed(hash_table_t *h);
-static void shrink_if_needed(hash_table_t *h);
+static size_t round_up_size(size_t);
+static bool alloc_table(size_t, list_t **);
+static void clear_items(hash_table_t *);
+static void resize(hash_table_t *, size_t);
+static void grow_if_needed(hash_table_t *);
+static void shrink_if_needed(hash_table_t *);
 
 /* Dummy do nothing callback to invoke in place of remove_callback == NULL. */
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/generic/async.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -416,6 +416,6 @@
 	.key_hash = client_key_hash,
 	.key_equal = client_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -452,6 +452,6 @@
 	.key_hash = conn_key_hash,
 	.key_equal = conn_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -628,5 +628,5 @@
 	
 	if (usecs) {
-		gettimeofday(&conn->wdata.to_event.expires, NULL);
+		getuptime(&conn->wdata.to_event.expires);
 		tv_add(&conn->wdata.to_event.expires, usecs);
 	} else
@@ -947,5 +947,5 @@
 {
 	struct timeval tv;
-	gettimeofday(&tv, NULL);
+	getuptime(&tv);
 	
 	futex_down(&async_futex);
@@ -1004,5 +1004,5 @@
 			
 			struct timeval tv;
-			gettimeofday(&tv, NULL);
+			getuptime(&tv);
 			
 			if (tv_gteq(&tv, &waiter->to_event.expires)) {
@@ -1309,5 +1309,5 @@
 		timeout = 0;
 
-	gettimeofday(&msg->wdata.to_event.expires, NULL);
+	getuptime(&msg->wdata.to_event.expires);
 	tv_add(&msg->wdata.to_event.expires, timeout);
 	
@@ -1391,5 +1391,5 @@
 	msg->wdata.fid = fibril_get_id();
 	
-	gettimeofday(&msg->wdata.to_event.expires, NULL);
+	getuptime(&msg->wdata.to_event.expires);
 	tv_add(&msg->wdata.to_event.expires, timeout);
 	
Index: uspace/lib/c/generic/device/battery_dev.c
===================================================================
--- uspace/lib/c/generic/device/battery_dev.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/generic/device/battery_dev.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 <ipc/dev_iface.h>
+#include <device/battery_dev.h>
+#include <errno.h>
+#include <async.h>
+#include <time.h>
+
+/** Read the current battery status from the device
+ *
+ * @param sess     Session of the device
+ * @param status   Current status of the battery
+ *
+ * @return         EOK on success or a negative error code
+ */
+int
+battery_status_get(async_sess_t *sess, battery_status_t *batt_status)
+{
+	sysarg_t status;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	int const rc = async_req_1_1(exch, DEV_IFACE_ID(BATTERY_DEV_IFACE),
+	    BATTERY_STATUS_GET, &status);
+
+	async_exchange_end(exch);
+
+	if (rc == EOK)
+		*batt_status = (battery_status_t) status;
+
+	return rc;
+}
+
+/** Read the current battery charge level from the device
+ *
+ * @param sess     Session of the device
+ * @param level    Battery charge level (0 - 100)
+ *
+ * @return         EOK on success or a negative error code
+ */
+int
+battery_charge_level_get(async_sess_t *sess, int *level)
+{
+	sysarg_t charge_level;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	int const rc = async_req_1_1(exch, DEV_IFACE_ID(BATTERY_DEV_IFACE),
+	    BATTERY_CHARGE_LEVEL_GET, &charge_level);
+
+	async_exchange_end(exch);
+
+	if (rc == EOK)
+		*level = (int) charge_level;
+
+	return rc;
+}
+
+/** @}
+ */
+
Index: uspace/lib/c/generic/device/clock_dev.c
===================================================================
--- uspace/lib/c/generic/device/clock_dev.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/generic/device/clock_dev.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 <ipc/dev_iface.h>
+#include <device/clock_dev.h>
+#include <errno.h>
+#include <async.h>
+#include <time.h>
+
+/** Read the current time from the device
+ *
+ * @param sess     Session of the device
+ * @param t        The current time that will be read from the device
+ *
+ * @return         EOK on success or a negative error code
+ */
+int
+clock_dev_time_get(async_sess_t *sess, struct tm *t)
+{
+	aid_t req;
+	int ret;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	req = async_send_1(exch, DEV_IFACE_ID(CLOCK_DEV_IFACE),
+	    CLOCK_DEV_TIME_GET, NULL);
+	ret = async_data_read_start(exch, t, sizeof(*t));
+
+	async_exchange_end(exch);
+
+	sysarg_t rc;
+	if (ret != EOK) {
+		async_forget(req);
+		return ret;
+	}
+
+	async_wait_for(req, &rc);
+	return (int)rc;
+}
+
+/** Set the current time
+ *
+ * @param sess   Session of the device
+ * @param t      The current time that will be written to the device
+ *
+ * @return       EOK on success or a negative error code
+ */
+int
+clock_dev_time_set(async_sess_t *sess, struct tm *t)
+{
+	aid_t req;
+	int ret;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	req = async_send_1(exch, DEV_IFACE_ID(CLOCK_DEV_IFACE),
+	    CLOCK_DEV_TIME_SET, NULL);
+	ret = async_data_write_start(exch, t, sizeof(*t));
+
+	async_exchange_end(exch);
+
+	sysarg_t rc;
+	if (ret != EOK) {
+		async_forget(req);
+		return ret;
+	}
+
+	async_wait_for(req, &rc);
+	return (int)rc;
+}
+
+/** @}
+ */
+
Index: uspace/lib/c/generic/dlfcn.c
===================================================================
--- uspace/lib/c/generic/dlfcn.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/generic/dlfcn.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -38,4 +38,6 @@
 #include <stdlib.h>
 #include <dlfcn.h>
+
+#ifdef CONFIG_RTLD
 
 #include <rtld/module.h>
@@ -87,4 +89,18 @@
 }
 
+#else /* CONFIG_RTLD not defined */
+
+void *dlopen(const char *path, int flag)
+{
+	return NULL;
+}
+
+void *dlsym(void *mod, const char *sym_name)
+{
+	return NULL;
+}
+
+#endif
+
 /** @}
  */
Index: uspace/lib/c/generic/double_to_str.c
===================================================================
--- uspace/lib/c/generic/double_to_str.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/generic/double_to_str.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,785 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * 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 <double_to_str.h>
+
+#include "private/power_of_ten.h"
+#include <ieee_double.h>
+
+#include <stdint.h>
+#include <assert.h>
+#include <bool.h>
+
+/*
+ * Floating point numbers are converted from their binary representation
+ * into a decimal string using the algorithm described in:
+ *   Printing floating-point numbers quickly and accurately with integers
+ *   Loitsch, 2010
+ */
+
+/** The computation assumes a significand of 64 bits. */
+static const int significand_width = 64;
+
+/* Scale exponents to interval [alpha, gamma] to simplify conversion. */
+static const int alpha = -59;
+static const int gamma = -32;
+
+
+/** Returns true if the most-significant bit of num.significand is set. */
+static bool is_normalized(fp_num_t num)
+{
+	assert(8*sizeof(num.significand) == significand_width);
+
+	/* Normalized == most significant bit of the significand is set. */
+	return (num.significand & (1ULL << (significand_width - 1))) != 0;
+}
+
+/** Returns a normalized num with the MSbit set. */
+static fp_num_t normalize(fp_num_t num)
+{
+	const uint64_t top10bits = 0xffc0000000000000ULL;
+
+	/* num usually comes from ieee_double with top 10 bits zero. */
+	while (0 == (num.significand & top10bits)) {
+		num.significand <<= 10;
+		num.exponent -= 10;
+	}
+
+	while (!is_normalized(num)) {
+		num.significand <<= 1;
+		--num.exponent;
+	}
+
+	return num;
+}
+
+
+/** Returns x * y with an error of less than 0.5 ulp. */
+static fp_num_t multiply(fp_num_t x, fp_num_t y)
+{
+	assert(/* is_normalized(x) && */ is_normalized(y));
+	
+	const uint32_t low_bits = -1;
+
+	uint64_t a, b, c, d;
+	a = x.significand >> 32;
+	b = x.significand & low_bits;
+	c = y.significand >> 32;
+	d = y.significand & low_bits;
+
+	uint64_t bd, ad, bc, ac;
+	bd = b * d;
+	ad = a * d;
+	
+	bc = b * c;
+	ac = a * c;
+
+	/* Denote 32 bit parts of x a y as: x == a b, y == c d. Then:
+	 *        a  b    
+	 *  *     c  d
+	 *  ----------
+	 *       ad bd .. multiplication of 32bit parts results in 64bit parts
+	 *  + ac bc
+	 *  ----------
+	 *       [b|d] .. Depicts 64 bit intermediate results and how
+	 *     [a|d]      the 32 bit parts of these results overlap and
+	 *     [b|c]      contribute to the final result.
+	 *  +[a|c]
+	 *  ----------
+	 *   [ret]
+	 *  [tmp]
+	 */
+	uint64_t tmp = (bd >> 32) + (ad & low_bits) + (bc & low_bits);
+
+	/* Round upwards. */
+	tmp += 1U << 31;
+
+	fp_num_t ret;
+	ret.significand = ac + (bc >> 32) + (ad >> 32) + (tmp >> 32);
+	ret.exponent = x.exponent + y.exponent + significand_width;
+	
+	return ret;			
+}
+
+
+/** Returns a - b. Both must have the same exponent. */
+static fp_num_t subtract(fp_num_t a, fp_num_t b)
+{
+	assert(a.exponent == b.exponent);
+	assert(a.significand >= b.significand);
+
+	fp_num_t result;
+	
+	result.significand = a.significand - b.significand;
+	result.exponent = a.exponent;
+
+	return result;
+}
+
+
+/** Returns the interval [low, high] of numbers that convert to binary val. */
+static void get_normalized_bounds(ieee_double_t val, fp_num_t *high, 
+	fp_num_t *low, fp_num_t *val_dist)
+{
+	/* 
+	 * Only works if val comes directly from extract_ieee_double without
+	 * being manipulated in any way (eg it must not be normalized). 
+	 */
+	assert(!is_normalized(val.pos_val));
+
+	high->significand = (val.pos_val.significand << 1) + 1;
+	high->exponent = val.pos_val.exponent - 1;
+
+	/* val_dist = high - val */
+	val_dist->significand = 1;
+	val_dist->exponent = val.pos_val.exponent - 1;
+
+	/* Distance from both lower and upper bound is the same. */
+	if (!val.is_accuracy_step) {
+		low->significand = (val.pos_val.significand << 1) - 1;
+		low->exponent = val.pos_val.exponent - 1;
+	} else {
+		low->significand = (val.pos_val.significand << 2) - 1;
+		low->exponent = val.pos_val.exponent - 2;
+	}
+
+	*high = normalize(*high);
+
+	/* 
+	 * Lower bound may not be normalized if subtracting 1 unit
+	 * reset the most-significant bit to 0. 
+	 */
+	low->significand = low->significand << (low->exponent - high->exponent);
+	low->exponent = high->exponent;
+
+	val_dist->significand = 
+		val_dist->significand << (val_dist->exponent - high->exponent);
+	val_dist->exponent = high->exponent;
+}
+
+/** Determines the interval of numbers that have the binary representation 
+ *  of val.
+ * 
+ * Numbers in the range [scaled_upper_bound - bounds_delta, scaled_upper_bound]
+ * have the same double binary representation as val. 
+ *
+ * Bounds are scaled by 10^scale so that alpha <= exponent <= gamma.
+ * Moreover, scaled_upper_bound is normalized.
+ *
+ * val_dist is the scaled distance from val to the upper bound, ie
+ * val_dist == (upper_bound - val) * 10^scale
+ */
+static void calc_scaled_bounds(ieee_double_t val, fp_num_t *scaled_upper_bound, 
+	fp_num_t *bounds_delta, fp_num_t *val_dist, int *scale)
+{
+	fp_num_t upper_bound, lower_bound;
+
+	get_normalized_bounds(val, &upper_bound, &lower_bound, val_dist);
+
+	assert(upper_bound.exponent == lower_bound.exponent);
+	assert(is_normalized(upper_bound));
+	assert(normalize(val.pos_val).exponent == upper_bound.exponent);
+
+	/* 
+	 * Find such a cached normalized power of 10 that if multiplied
+	 * by upper_bound the binary exponent of upper_bound almost vanishes, 
+	 * ie:
+	 *   upper_scaled := upper_bound * 10^scale
+	 *   alpha <= upper_scaled.exponent <= gamma
+	 *   alpha <= upper_bound.exponent + pow_10.exponent + 64 <= gamma
+	 */
+	fp_num_t scaling_power_of_10;
+	int lower_bin_exp = alpha - upper_bound.exponent - significand_width;
+
+	get_power_of_ten(lower_bin_exp, &scaling_power_of_10, scale);
+
+	int scale_exp = scaling_power_of_10.exponent;
+	assert(alpha <= upper_bound.exponent + scale_exp + significand_width);
+	assert(upper_bound.exponent + scale_exp + significand_width <= gamma);
+
+	fp_num_t upper_scaled = multiply(upper_bound, scaling_power_of_10);
+	fp_num_t lower_scaled = multiply(lower_bound, scaling_power_of_10);
+	*val_dist = multiply(*val_dist, scaling_power_of_10);
+
+	assert(alpha <= upper_scaled.exponent && upper_scaled.exponent <= gamma);
+
+	/* 
+	 * Any value between lower and upper bound would be represented
+	 * in binary as the double val originated from. The bounds were
+	 * however scaled by an imprecise power of 10 (error less than 
+	 * 1 ulp) so the scaled bounds have an error of less than 1 ulp. 
+	 * Conservatively round the lower bound up and the upper bound 
+	 * down by 1 ulp just to be on the safe side. It avoids pronouncing
+	 * produced decimal digits as correct if such a decimal number
+	 * is close to the bounds to within 1 ulp. 
+	 */
+	upper_scaled.significand -= 1;
+	lower_scaled.significand += 1;
+
+	*bounds_delta = subtract(upper_scaled, lower_scaled);
+	*scaled_upper_bound = upper_scaled;
+}
+
+
+/** Rounds the last digit of buf so that it is closest to the converted number.*/
+static void round_last_digit(uint64_t rest, uint64_t w_dist, uint64_t delta,
+	uint64_t digit_val_diff, char *buf, int len)
+{
+	/*
+	 *  | <------- delta -------> |
+	 *  |    | <---- w_dist ----> |
+	 *  |    |       | <- rest -> |
+	 *  |    |       |            |
+	 *  |    |       ` buffer     |
+	 *  |    ` w                  ` upper
+	 *  ` lower
+	 *
+	 * delta = upper - lower .. conservative/safe interval
+	 * w_dist = upper - w    
+	 * upper = "number represented by digits in buf" + rest
+	 * 
+	 * Changing buf[len - 1] changes the value represented by buf 
+	 * by digit_val_diff * scaling, where scaling is shared by
+	 * all parameters. 
+	 *
+	 */
+
+	/* Current number in buf is greater than the double being converted */
+	bool cur_greater_w = rest < w_dist;
+	/* Rounding down by one would keep buf in between bounds (in safe rng). */
+	bool next_in_val_rng = cur_greater_w && (rest + digit_val_diff < delta);
+	/* Rounding down by one would bring buf closer to the processed number. */
+	bool next_closer = next_in_val_rng 
+		&& (rest + digit_val_diff < w_dist || rest - w_dist < w_dist - rest);
+
+	/* Of the shortest strings pick the one that is closest to the actual 
+	   floating point number. */
+	while (next_closer) {
+		assert('0' < buf[len - 1]);
+		assert(0 < digit_val_diff);
+
+		--buf[len - 1];
+		rest += digit_val_diff;
+
+		cur_greater_w = rest < w_dist;
+		next_in_val_rng = cur_greater_w && (rest + digit_val_diff < delta);
+		next_closer = next_in_val_rng 
+			&& (rest + digit_val_diff < w_dist || rest - w_dist < w_dist - rest);
+	}
+}
+
+
+/** Generates the shortest accurate decimal string representation.
+ *
+ * Outputs (mostly) the shortest accurate string representation 
+ * for the number scaled_upper - val_dist. Numbers in the interval
+ * [scaled_upper - delta, scaled_upper] have the same binary
+ * floating point representation and will therefore share the
+ * shortest string representation (up to the rounding of the last
+ * digit to bring the shortest string also the closest to the
+ * actual number). 
+ *
+ * @param scaled_upper Scaled upper bound of numbers that have the
+ *              same binary representation as the converted number.
+ *              Scaled by 10^-scale so that alpha <= exponent <= gamma.
+ * @param delta scaled_upper - delta is the lower bound of numbers
+ *              that share the same binary representation in double.
+ * @param val_dist scaled_upper - val_dist is the number whose
+ *              decimal string we're generating.
+ * @param scale Decimal scaling of the value to convert (ie scaled_upper).
+ * @param buf   Buffer to store the string representation. Must be large 
+ *              enough to store all digits and a null terminator. At most
+ *              MAX_DOUBLE_STR_LEN digits will be written (not counting
+ *              the null terminator).
+ * @param buf_size Size of buf in bytes. 
+ * @param dec_exponent Will be set to the decimal exponent of the number 
+ *              string in buf.
+ *
+ * @return Number of digits; negative on failure (eg buffer too small).
+ */
+static int gen_dec_digits(fp_num_t scaled_upper, fp_num_t delta, 
+	fp_num_t val_dist, int scale, char *buf, size_t buf_size, int *dec_exponent)
+{
+	/* 
+	 * The integral part of scaled_upper is 5 to 32 bits long while 
+	 * the remaining fractional part is 59 to 32 bits long because:
+	 * -59 == alpha <= scaled_upper.e <= gamma == -32
+	 *
+	 *  | <------- delta -------> |
+	 *  |    | <--- val_dist ---> |
+	 *  |    |    |<- remainder ->|
+	 *  |    |    |               |
+	 *  |    |    ` buffer        |
+	 *  |    ` val                ` upper
+	 *  ` lower
+	 *
+	 */ 
+	assert(scaled_upper.significand != 0);
+	assert(alpha <= scaled_upper.exponent && scaled_upper.exponent <= gamma);
+	assert(scaled_upper.exponent == delta.exponent);
+	assert(scaled_upper.exponent == val_dist.exponent);
+	assert(val_dist.significand <= delta.significand);
+
+	/* We'll produce at least one digit and a null terminator. */
+	if (buf_size < 2) {
+		return -1;
+	}
+
+	/* one is number 1 encoded with the same exponent as scaled_upper */
+	fp_num_t one;
+	one.significand = ((uint64_t) 1) << (-scaled_upper.exponent);
+	one.exponent = scaled_upper.exponent;
+
+	/*
+	 * Extract the integral part of scaled_upper. 
+	 *  upper / one == upper >> -one.e 
+	 */
+	uint32_t int_part = (uint32_t)(scaled_upper.significand >> (-one.exponent));
+	
+	/* 
+	 * Fractional part of scaled_upper.
+	 *  upper % one == upper & (one.f - 1) 
+	 */
+	uint64_t frac_part = scaled_upper.significand & (one.significand - 1);
+
+	/*
+	 * The integral part of upper has at least 5 bits (64 + alpha) and 
+	 * at most 32 bits (64 + gamma). The integral part has at most 10 
+	 * decimal digits, so kappa <= 10. 
+	 */
+	int kappa = 10;
+	uint32_t div = 1000000000;
+	size_t len = 0;
+
+	/* Produce decimal digits for the integral part of upper. */
+	while (kappa > 0) {
+		int digit = int_part / div;
+		int_part %= div;
+
+		--kappa;
+
+		/* Skip leading zeros. */
+		if (digit != 0 || len != 0) {
+			/* Current length + new digit + null terminator <= buf_size */
+			if (len + 2 <= buf_size) {
+				buf[len] = '0' + digit;
+				++len;
+			} else {
+				return -1;
+			}
+		}
+
+		/* 
+		 * Difference between the so far produced decimal number and upper
+		 * is calculated as: remaining_int_part * one + frac_part 
+		 */
+		uint64_t remainder = (((uint64_t)int_part) << -one.exponent) + frac_part;
+
+		/* The produced decimal number would convert back to upper. */
+		if (remainder <= delta.significand) {
+			assert(0 < len && len < buf_size);
+			*dec_exponent = kappa - scale;
+			buf[len] = '\0';
+
+			/* Of the shortest representations choose the numerically closest. */
+			round_last_digit(remainder, val_dist.significand, delta.significand,
+				(uint64_t)div << (-one.exponent), buf, len);
+			return len;
+		}
+
+		div /= 10;
+	}
+
+	/* Generate decimal digits for the fractional part of upper. */
+	do {
+		/*
+		 * Does not overflow because at least 5 upper bits were
+		 * taken by the integral part and are now unused in frac_part. 
+		 */
+		frac_part *= 10;
+		delta.significand *= 10;
+		val_dist.significand *= 10;
+
+		/* frac_part / one */
+		int digit = (int)(frac_part >> (-one.exponent));
+		
+		/* frac_part %= one */
+		frac_part &= one.significand - 1;
+
+		--kappa;
+
+		/* Skip leading zeros. */
+		if (digit == 0 && len == 0) {
+			continue;
+		}
+
+		/* Current length + new digit + null terminator <= buf_size */
+		if (len + 2 <= buf_size) {
+			buf[len] = '0' + digit;
+			++len;
+		} else {
+			return -1;
+		}
+	} while (frac_part > delta.significand);
+
+	assert(0 < len && len < buf_size);
+
+	*dec_exponent = kappa - scale;
+	buf[len] = '\0';
+
+	/* Of the shortest representations choose the numerically closest one. */
+	round_last_digit(frac_part, val_dist.significand, delta.significand, 
+		one.significand, buf, len);
+
+	return len;
+}
+
+/** Produce a string for 0.0 */
+static int zero_to_str(char *buf, size_t buf_size, int *dec_exponent)
+{
+	if (2 <= buf_size) {
+		buf[0] = '0';
+		buf[1] = '\0';
+		*dec_exponent = 0;
+		return 1;
+	} else {
+		return -1;
+	}
+}
+
+
+/** Converts a non-special double into its shortest accurate string 
+ *  representation.
+ *
+ * Produces an accurate string representation, ie the string will 
+ * convert back to the same binary double (eg via strtod). In the
+ * vast majority of cases (99%) the string will be the shortest such
+ * string that is also the closest to the value of any shortest
+ * string representations. Therefore, no trailing zeros are ever
+ * produced.
+ *
+ * Conceptually, the value is: buf * 10^dec_exponent
+ *
+ * Never outputs trailing zeros.
+ *
+ * @param ieee_val Binary double description to convert. Must be the product
+ *                 of extract_ieee_double and it must not be a special number.
+ * @param buf      Buffer to store the string representation. Must be large 
+ *                 enough to store all digits and a null terminator. At most
+ *                 MAX_DOUBLE_STR_LEN digits will be written (not counting
+ *                 the null terminator).
+ * @param buf_size Size of buf in bytes.
+ * @param dec_exponent Will be set to the decimal exponent of the number 
+ *                 string in buf.
+ *
+ * @return The number of printed digits. A negative value indicates
+ *         an error: buf too small (or ieee_val.is_special).
+ */
+int double_to_short_str(ieee_double_t ieee_val, char *buf, size_t buf_size, 
+	int *dec_exponent)
+{
+	/* The whole computation assumes 64bit significand. */
+	assert(sizeof(ieee_val.pos_val.significand) == sizeof(uint64_t));
+
+	if (ieee_val.is_special) {
+		return -1;
+	}
+
+	/* Zero cannot be normalized. Handle it here. */
+	if (0 == ieee_val.pos_val.significand) {
+		return zero_to_str(buf, buf_size, dec_exponent);
+	}
+
+	fp_num_t scaled_upper_bound;
+	fp_num_t delta;
+	fp_num_t val_dist;
+	int scale;
+
+	calc_scaled_bounds(ieee_val, &scaled_upper_bound, 
+		&delta, &val_dist, &scale);
+
+	int len = gen_dec_digits(scaled_upper_bound, delta, val_dist, scale, 
+		buf, buf_size, dec_exponent);
+
+	assert(len <= MAX_DOUBLE_STR_LEN);
+	return len;
+}
+
+/** Generates a fixed number of decimal digits of w_scaled.
+ *
+ * double == w_scaled * 10^-scale, where alpha <= w_scaled.e <= gamma
+ *
+ * @param w_scaled Scaled number by 10^-scale so that
+ *              alpha <= exponent <= gamma
+ * @param scale Decimal scaling of the value to convert (ie w_scaled).
+ * @param signif_d_cnt Maximum number of significant digits to output. 
+ *              Negative if as many as possible are requested.
+ * @param frac_d_cnt   Maximum number of fractional digits to output.
+ *              Negative if as many as possible are requested.
+ *              Eg. if 2 then 1.234 -> "1.23"; if 2 then 3e-9 -> "0".
+ * @param buf   Buffer to store the string representation. Must be large 
+ *              enough to store all digits and a null terminator. At most
+ *              MAX_DOUBLE_STR_LEN digits will be written (not counting
+ *              the null terminator).
+ * @param buf_size Size of buf in bytes. 
+ *
+ * @return Number of digits; negative on failure (eg buffer too small).
+ */
+static int gen_fixed_dec_digits(fp_num_t w_scaled, int scale, int signif_d_cnt, 
+	int frac_d_cnt, char *buf, size_t buf_size, int *dec_exponent)
+{
+	/* We'll produce at least one digit and a null terminator. */
+	if (0 == signif_d_cnt || buf_size < 2) {
+		return -1;
+	}
+
+	/* 
+	 * The integral part of w_scaled is 5 to 32 bits long while the 
+	 * remaining fractional part is 59 to 32 bits long because:
+	 * -59 == alpha <= w_scaled.e <= gamma == -32
+	 * 
+	 * Therefore:
+	 *  | 5..32 bits | 32..59 bits | == w_scaled == w * 10^scale
+	 *  |  int_part  |  frac_part  |
+	 *  |0 0  ..  0 1|0 0   ..  0 0| == one == 1.0
+	 *  |      0     |0 0   ..  0 1| == w_err == 1 * 2^w_scaled.e  
+	*/
+	assert(alpha <= w_scaled.exponent && w_scaled.exponent <= gamma);
+	assert(0 != w_scaled.significand);
+
+	/* 
+	 * Scaling the number being converted by 10^scale introduced
+	 * an error of less that 1 ulp. The actual value of w_scaled
+	 * could lie anywhere between w_scaled.signif +/- w_err. 
+	 * Scale the error locally as we scale the fractional part
+	 * of w_scaled.
+	 */
+	uint64_t w_err = 1;
+
+	/* one is number 1.0 encoded with the same exponent as w_scaled */
+	fp_num_t one;
+	one.significand = ((uint64_t) 1) << (-w_scaled.exponent);
+	one.exponent = w_scaled.exponent;
+
+	/* Extract the integral part of w_scaled. 
+	   w_scaled / one == w_scaled >> -one.e */
+	uint32_t int_part = (uint32_t)(w_scaled.significand >> (-one.exponent));
+
+	/* Fractional part of w_scaled.
+	   w_scaled % one == w_scaled & (one.f - 1) */
+	uint64_t frac_part = w_scaled.significand & (one.significand - 1);
+
+	size_t len = 0;
+	/* 
+	 * The integral part of w_scaled has at least 5 bits (64 + alpha = 5) 
+	 * and at most 32 bits (64 + gamma = 32). The integral part has 
+	 * at most 10 decimal digits, so kappa <= 10. 
+	 */
+	int kappa = 10;
+	uint32_t div = 1000000000;
+
+	int rem_signif_d_cnt = signif_d_cnt;
+	int rem_frac_d_cnt = 
+		(frac_d_cnt >= 0) ? (kappa - scale + frac_d_cnt) : INT_MAX;
+
+	/* Produce decimal digits for the integral part of w_scaled. */
+	while (kappa > 0 && rem_signif_d_cnt != 0 && rem_frac_d_cnt > 0) {
+		int digit = int_part / div;
+		int_part %= div;
+
+		div /= 10;
+		--kappa;
+		--rem_frac_d_cnt;
+
+		/* Skip leading zeros. */
+		if (digit == 0 && len == 0) {
+			continue;
+		}
+
+		/* Current length + new digit + null terminator <= buf_size */
+		if (len + 2 <= buf_size) {
+			buf[len] = '0' + digit;
+			++len;
+			--rem_signif_d_cnt;
+		} else {
+			return -1;
+		}
+	}
+
+	/* Generate decimal digits for the fractional part of w_scaled. */
+	while (w_err <= frac_part && rem_signif_d_cnt != 0 && rem_frac_d_cnt > 0) {
+		/*
+		 * Does not overflow because at least 5 upper bits were
+		 * taken by the integral part and are now unused in frac_part. 
+		 */
+		frac_part *= 10;
+		w_err *= 10;
+
+		/* frac_part / one */
+		int digit = (int)(frac_part >> (-one.exponent));
+		
+		/* frac_part %= one */
+		frac_part &= one.significand - 1;
+
+		--kappa;
+		--rem_frac_d_cnt;
+
+		/* Skip leading zeros. */
+		if (digit == 0 && len == 0) {
+			continue;
+		}
+
+		/* Current length + new digit + null terminator <= buf_size */
+		if (len + 2 <= buf_size) {
+			buf[len] = '0' + digit;
+			++len;
+			--rem_signif_d_cnt;
+		} else {
+			return -1;
+		}
+	};
+
+	assert(/* 0 <= len && */ len < buf_size);
+
+	if (0 < len) {
+		*dec_exponent = kappa - scale;
+		assert(frac_d_cnt < 0 || -frac_d_cnt <= *dec_exponent);
+	} else {
+		/* 
+		 * The number of fractional digits was too limiting to produce 
+		 * any digits. 
+		 */
+		assert(rem_frac_d_cnt <= 0 || w_scaled.significand == 0);
+		*dec_exponent = 0;
+		buf[0] = '0';
+		len = 1;
+	}
+
+	if (len < buf_size) {
+		buf[len] = '\0';
+		assert(signif_d_cnt < 0 || (int)len <= signif_d_cnt);
+		return len;
+	} else {
+		return -1;
+	}
+}
+
+
+/** Converts a non-special double into its string representation.
+ *
+ * Conceptually, the truncated double value is: buf * 10^dec_exponent
+ *
+ * Conversion errors are tracked, so all produced digits except the
+ * last one are accurate. Garbage digits are never produced.
+ * If the requested number of digits cannot be produced accurately 
+ * due to conversion errors less digits are produced than requested 
+ * and the last digit has an error of +/- 1 (so if '7' is the last
+ * converted digit it might have been converted to any of '6'..'8'
+ * had the conversion been completely precise). 
+ *
+ * If no error occurs at least one digit is output. 
+ *
+ * The conversion stops once the requested number of significant or 
+ * fractional digits is reached or the conversion error is too large 
+ * to generate any more digits (whichever happens first).
+ *
+ * Any digits following the first (most-significant) digit (this digit
+ * included) are counted as significant digits; eg:
+ *   1.4,    4 signif -> "1400" * 10^-3, ie 1.400
+ *   1000.3, 1 signif -> "1" * 10^3      ie 1000
+ *   0.003,  2 signif -> "30" * 10^-4    ie 0.003
+ *   9.5     1 signif -> "9" * 10^0,     ie 9
+ *
+ * Any digits following the decimal point are counted as fractional digits.
+ * This includes the zeros that would appear between the decimal point
+ * and the first non-zero fractional digit. If fewer fractional digits
+ * are requested than would allow to place the most-significant digit
+ * a "0" is output. Eg:
+ *   1.4,   3 frac -> "1400" * 10^-3,   ie 1.400
+ *   12.34  4 frac -> "123400" * 10^-4, ie 12.3400
+ *   3e-99  4 frac -> "0" * 10^0,       ie 0
+ *   0.009  2 frac -> "0" * 10^-2,      ie 0
+ *
+ * @param ieee_val Binary double description to convert. Must be the product
+ *                 of extract_ieee_double and it must not be a special number.
+ * @param signif_d_cnt Maximum number of significant digits to produce.
+ *                 The output is not rounded. 
+ *                 Set to a negative value to generate as many digits
+ *                 as accurately possible.
+ * @param frac_d_cnt Maximum number of fractional digits to produce including
+ *                 any zeros immediately trailing the decimal point. 
+ *                 The output is not rounded. 
+ *                 Set to a negative value to generate as many digits
+ *                 as accurately possible.
+ * @param buf      Buffer to store the string representation. Must be large 
+ *                 enough to store all digits and a null terminator. At most
+ *                 MAX_DOUBLE_STR_LEN digits will be written (not counting
+ *                 the null terminator).
+ * @param buf_size Size of buf in bytes.
+ * @param dec_exponent Set to the decimal exponent of the number string 
+ *                 in buf.
+ *
+ * @return The number of output digits. A negative value indicates
+ *         an error: buf too small (or ieee_val.is_special, or 
+ *         signif_d_cnt == 0).
+ */
+int double_to_fixed_str(ieee_double_t ieee_val, int signif_d_cnt,
+	int frac_d_cnt, char *buf, size_t buf_size, int *dec_exponent)
+{
+	/* The whole computation assumes 64bit significand. */
+	assert(sizeof(ieee_val.pos_val.significand) == sizeof(uint64_t));
+
+	if (ieee_val.is_special) {
+		return -1;
+	}
+
+	/* Zero cannot be normalized. Handle it here. */
+	if (0 == ieee_val.pos_val.significand) {
+		return zero_to_str(buf, buf_size, dec_exponent);
+	}
+
+	/* Normalize and scale. */
+	fp_num_t w = normalize(ieee_val.pos_val);
+
+	int lower_bin_exp = alpha - w.exponent - significand_width;
+
+	int scale;
+	fp_num_t scaling_power_of_10;
+
+	get_power_of_ten(lower_bin_exp, &scaling_power_of_10, &scale);
+
+	fp_num_t w_scaled = multiply(w, scaling_power_of_10);
+
+	/* Produce decimal digits from the scaled number. */
+	int len = gen_fixed_dec_digits(w_scaled, scale, signif_d_cnt, frac_d_cnt, 
+		buf, buf_size, dec_exponent);
+
+	assert(len <= MAX_DOUBLE_STR_LEN);
+	return len;
+}
+
Index: uspace/lib/c/generic/fibril_synch.c
===================================================================
--- uspace/lib/c/generic/fibril_synch.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/generic/fibril_synch.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -379,5 +379,5 @@
 	futex_down(&async_futex);
 	if (timeout) {
-		gettimeofday(&wdata.to_event.expires, NULL);
+		getuptime(&wdata.to_event.expires);
 		tv_add(&wdata.to_event.expires, timeout);
 		async_insert_timeout(&wdata);
Index: uspace/lib/c/generic/ieee_double.c
===================================================================
--- uspace/lib/c/generic/ieee_double.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/generic/ieee_double.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * 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 <ieee_double.h>
+
+#include <assert.h>
+
+/** Returns an easily processible description of the double val.
+ */
+ieee_double_t extract_ieee_double(double val)
+{
+	const uint64_t significand_mask = 0xfffffffffffffULL;
+	const uint64_t exponent_mask = 0x7ff0000000000000ULL;
+	const int exponent_shift = 64 - 11 - 1;
+	const uint64_t sign_mask = 0x8000000000000000ULL;
+	
+	const int special_exponent = 0x7ff;
+	const int denormal_exponent = 0;
+	const uint64_t hidden_bit = (1ULL << 52);
+	const int exponent_bias = 1075;
+
+	assert(sizeof(val) == sizeof(uint64_t));
+
+	union {
+		uint64_t num;
+		double val;
+	} bits;
+
+	bits.val = val;
+
+	/* 
+	 * Extract the binary ieee representation of the double. 
+	 * Relies on integers having the same endianness as doubles.
+	 */
+	uint64_t num = bits.num;	
+
+	ieee_double_t ret;
+
+	/* Determine the sign. */
+	ret.is_negative = ((num & sign_mask) != 0);
+
+	/* Extract the exponent. */
+	int raw_exponent = (num & exponent_mask) >> exponent_shift;
+
+	/* The extracted raw significand may not contain the hidden bit */
+	uint64_t raw_significand = num & significand_mask;
+
+	ret.is_special = (raw_exponent == special_exponent);
+
+	/* NaN or infinity */
+	if (ret.is_special) {
+		ret.is_infinity = (raw_significand == 0);
+		ret.is_nan = (raw_significand != 0);
+
+		/* These are not valid for special numbers but init them anyway. */
+		ret.is_denormal = true;
+		ret.is_accuracy_step = false;
+		ret.pos_val.significand = 0;
+		ret.pos_val.exponent = 0;
+	} else {
+		ret.is_infinity = false;
+		ret.is_nan = false;
+
+		ret.is_denormal = (raw_exponent == denormal_exponent);
+
+		/* Denormal or zero. */
+		if (ret.is_denormal) {
+			ret.pos_val.significand = raw_significand;
+			ret.pos_val.exponent = 1 - exponent_bias;
+			ret.is_accuracy_step = false;
+		} else {
+			ret.pos_val.significand = raw_significand + hidden_bit;
+			ret.pos_val.exponent = raw_exponent - exponent_bias;
+
+			/* The predecessor is closer to val than the successor 
+			 * if val is a normal value of the form 2^k (hence
+			 * raw_significand == 0) with the only exception being 
+			 * the smallest normal (raw_exponent == 1). The smallest 
+			 * normal's predecessor is the largest denormal and denormals 
+			 * do not get an extra bit of precision because their exponent 
+			 * stays the same (ie it does not decrease from k to k-1).
+			 */
+			ret.is_accuracy_step = (raw_significand == 0) && (raw_exponent != 1);
+		}
+	}
+
+	return ret;
+}
+
Index: uspace/lib/c/generic/io/con_srv.c
===================================================================
--- uspace/lib/c/generic/io/con_srv.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/generic/io/con_srv.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * 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
+ * @brief Console protocol server stub
+ */
+#include <errno.h>
+#include <ipc/console.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <io/con_srv.h>
+
+static void con_read_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	void *buf;
+	size_t size;
+	int rc;
+	ipc_callid_t rcallid;
+
+	if (!async_data_read_receive(&rcallid, &size)) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	buf = malloc(size);
+	if (buf == NULL) {
+		async_answer_0(rcallid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	if (srv->srvs->ops->read == NULL) {
+		async_answer_0(rcallid, ENOTSUP);
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->read(srv, buf, size);
+	if (rc < 0) {
+		async_answer_0(rcallid, rc);
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	async_data_read_finalize(rcallid, buf, size);
+	free(buf);
+
+	if (rc >= 0)
+		async_answer_1(callid, EOK, rc);
+	else
+		async_answer_0(callid, rc);
+}
+
+static void con_write_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	void *data;
+	size_t size;
+	int rc;
+
+	rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	if (srv->srvs->ops->write == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->write(srv, data, size);
+	free(data);
+
+	if (rc >= 0)
+		async_answer_1(callid, EOK, rc);
+	else
+		async_answer_0(callid, rc);
+}
+
+static void con_sync_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	if (srv->srvs->ops->sync == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->sync(srv);
+	async_answer_0(callid, EOK);
+}
+
+static void con_clear_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	if (srv->srvs->ops->clear == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->clear(srv);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_pos_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	sysarg_t col;
+	sysarg_t row;
+
+	col = IPC_GET_ARG1(*call);
+	row = IPC_GET_ARG2(*call);
+
+	if (srv->srvs->ops->set_pos == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_pos(srv, col, row);
+	async_answer_0(callid, EOK);
+}
+
+static void con_get_pos_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	sysarg_t col;
+	sysarg_t row;
+
+	if (srv->srvs->ops->get_pos == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_pos(srv, &col, &row);
+	async_answer_2(callid, rc, col, row);
+}
+
+static void con_get_size_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	sysarg_t cols;
+	sysarg_t rows;
+
+	if (srv->srvs->ops->get_size == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_size(srv, &cols, &rows);
+	async_answer_2(callid, rc, cols, rows);
+}
+
+static void con_get_color_cap_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	console_caps_t ccap;
+
+	if (srv->srvs->ops->get_color_cap == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_color_cap(srv, &ccap);
+	async_answer_1(callid, rc, (sysarg_t)ccap);
+}
+
+static void con_set_style_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	console_style_t style;
+
+	style = IPC_GET_ARG1(*call);
+
+	if (srv->srvs->ops->set_style == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_style(srv, style);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_color_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	console_color_t bgcolor;
+	console_color_t fgcolor;
+	console_color_attr_t flags;
+
+	bgcolor = IPC_GET_ARG1(*call);
+	fgcolor = IPC_GET_ARG2(*call);
+	flags = IPC_GET_ARG3(*call);
+
+	if (srv->srvs->ops->set_color == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_color(srv, bgcolor, fgcolor, flags);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_rgb_color_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	pixel_t bgcolor;
+	pixel_t fgcolor;
+
+	bgcolor = IPC_GET_ARG1(*call);
+	fgcolor = IPC_GET_ARG2(*call);
+
+	if (srv->srvs->ops->set_rgb_color == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_rgb_color(srv, bgcolor, fgcolor);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_cursor_visibility_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	bool show;
+
+	show = IPC_GET_ARG1(*call);
+
+	if (srv->srvs->ops->set_cursor_visibility == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_cursor_visibility(srv, show);
+	async_answer_0(callid, EOK);
+}
+
+static void con_get_event_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	kbd_event_t event;
+
+	if (srv->srvs->ops->get_event == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_event(srv, &event);
+	async_answer_4(callid, rc, event.type, event.key, event.mods, event.c);
+}
+
+static con_srv_t *con_srv_create(con_srvs_t *srvs)
+{
+	con_srv_t *srv;
+
+	srv = calloc(1, sizeof(*srv));
+	if (srv == NULL)
+		return NULL;
+
+	srv->srvs = srvs;
+	return srv;
+}
+
+void con_srvs_init(con_srvs_t *srvs)
+{
+	srvs->ops = NULL;
+	srvs->sarg = NULL;
+	srvs->abort_timeout = 0;
+	srvs->aborted = false;
+}
+
+int con_conn(ipc_callid_t iid, ipc_call_t *icall, con_srvs_t *srvs)
+{
+	con_srv_t *srv;
+	int rc;
+
+	/* Accept the connection */
+	async_answer_0(iid, EOK);
+
+	srv = con_srv_create(srvs);
+	if (srv == NULL)
+		return ENOMEM;
+
+/*	async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (sess == NULL)
+		return ENOMEM;
+
+	srv->client_sess = sess;
+*/
+	srv->client_sess = NULL;
+
+	rc = srvs->ops->open(srvs, srv);
+	if (rc != EOK)
+		return rc;
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = 0;
+
+		while (callid == 0) {
+			/* XXX Need to be able to abort immediately */
+			callid = async_get_call_timeout(&call,
+			    srvs->abort_timeout);
+
+			if (srv->srvs->aborted) {
+				if (callid != 0)
+					async_answer_0(callid, EINTR);
+				break;
+			}
+		}
+
+		if (callid == 0)
+			break;
+
+		sysarg_t method = IPC_GET_IMETHOD(call);
+
+		if (!method) {
+			/* The other side has hung up */
+			async_answer_0(callid, EOK);
+			break;
+		}
+
+		switch (method) {
+		case VFS_OUT_READ:
+			con_read_srv(srv, callid, &call);
+			break;
+		case VFS_OUT_WRITE:
+			con_write_srv(srv, callid, &call);
+			break;
+		case VFS_OUT_SYNC:
+			con_sync_srv(srv, callid, &call);
+			break;
+		case CONSOLE_CLEAR:
+			con_clear_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_POS:
+			con_set_pos_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_POS:
+			con_get_pos_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_SIZE:
+			con_get_size_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_COLOR_CAP:
+			con_get_color_cap_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_STYLE:
+			con_set_style_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_COLOR:
+			con_set_color_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_RGB_COLOR:
+			con_set_rgb_color_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_CURSOR_VISIBILITY:
+			con_set_cursor_visibility_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_EVENT:
+			con_get_event_srv(srv, callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+		}
+	}
+
+	rc = srvs->ops->close(srv);
+	free(srv);
+
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/io/console.c
===================================================================
--- uspace/lib/c/generic/io/console.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/generic/io/console.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -38,5 +38,4 @@
 #include <async.h>
 #include <errno.h>
-#include <stdio.h>
 #include <malloc.h>
 #include <vfs/vfs_sess.h>
@@ -126,5 +125,5 @@
 {
 	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
-	async_req_1_0(exch, CONSOLE_CURSOR_VISIBILITY, (show != false));
+	async_req_1_0(exch, CONSOLE_SET_CURSOR_VISIBILITY, (show != false));
 	async_exchange_end(exch);
 }
@@ -151,5 +150,5 @@
 {
 	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
-	async_req_2_0(exch, CONSOLE_GOTO, col, row);
+	async_req_2_0(exch, CONSOLE_SET_POS, col, row);
 	async_exchange_end(exch);
 }
Index: uspace/lib/c/generic/io/input.c
===================================================================
--- uspace/lib/c/generic/io/input.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/generic/io/input.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -143,6 +143,6 @@
 	x = IPC_GET_ARG1(*call);
 	y = IPC_GET_ARG2(*call);
-	max_x = IPC_GET_ARG2(*call);
-	max_y = IPC_GET_ARG3(*call);
+	max_x = IPC_GET_ARG3(*call);
+	max_y = IPC_GET_ARG4(*call);
 
 	rc = input->ev_ops->abs_move(input, x, y, max_x, max_y);
Index: uspace/lib/c/generic/io/log.c
===================================================================
--- uspace/lib/c/generic/io/log.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/generic/io/log.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -38,58 +38,190 @@
 #include <stdlib.h>
 #include <stdio.h>
-
+#include <async.h>
 #include <io/log.h>
-
-/** Serialization mutex for logging functions. */
-static FIBRIL_MUTEX_INITIALIZE(log_serializer);
-
-/** Current log level. */
-static log_level_t log_level;
-
-static FILE *log_stream;
-
+#include <ipc/logger.h>
+#include <ns.h>
+
+/** Id of the first log we create at logger. */
+static sysarg_t default_log_id;
+
+/** Log messages are printed under this name. */
 static const char *log_prog_name;
 
-/** Prefixes for individual logging levels. */
+/** Names of individual log levels. */
 static const char *log_level_names[] = {
-	[LVL_FATAL] = "Fatal error",
-	[LVL_ERROR] = "Error",
-	[LVL_WARN] = "Warning",
-	[LVL_NOTE] = "Note",
-	[LVL_DEBUG] = "Debug",
-	[LVL_DEBUG2] = "Debug2"
+	"fatal",
+	"error",
+	"warn",
+	"note",
+	"debug",
+	"debug2",
+	NULL
 };
 
+/** IPC session with the logger service. */
+static async_sess_t *logger_session;
+
+/** Maximum length of a single log message (in bytes). */
+#define MESSAGE_BUFFER_SIZE 4096
+
+/** Send formatted message to the logger service.
+ *
+ * @param session Initialized IPC session with the logger.
+ * @param log Log to use.
+ * @param level Verbosity level of the message.
+ * @param message The actual message.
+ * @return Error code of the conversion or EOK on success.
+ */
+static int logger_message(async_sess_t *session, log_t log, log_level_t level, char *message)
+{
+	async_exch_t *exchange = async_exchange_begin(session);
+	if (exchange == NULL) {
+		return ENOMEM;
+	}
+	if (log == LOG_DEFAULT)
+		log = default_log_id;
+
+	// FIXME: remove when all USB drivers use libc logging explicitly
+	str_rtrim(message, '\n');
+
+	aid_t reg_msg = async_send_2(exchange, LOGGER_WRITER_MESSAGE,
+	    log, level, NULL);
+	int rc = async_data_write_start(exchange, message, str_size(message));
+	sysarg_t reg_msg_rc;
+	async_wait_for(reg_msg, &reg_msg_rc);
+
+	async_exchange_end(exchange);
+
+	/*
+	 * Getting ENAK means no-one wants our message. That is not an
+	 * error at all.
+	 */
+	if (rc == ENAK)
+		rc = EOK;
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	return reg_msg_rc;
+}
+
+/** Get name of the log level.
+ *
+ * @param level The log level.
+ * @return String name or "unknown".
+ */
+const char *log_level_str(log_level_t level)
+{
+	if (level >= LVL_LIMIT)
+		return "unknown";
+	else
+		return log_level_names[level];
+}
+
+/** Convert log level name to the enum.
+ *
+ * @param[in] name Log level name or log level number.
+ * @param[out] level_out Where to store the result (set to NULL to ignore).
+ * @return Error code of the conversion or EOK on success.
+ */
+int log_level_from_str(const char *name, log_level_t *level_out)
+{
+	log_level_t level = LVL_FATAL;
+
+	while (log_level_names[level] != NULL) {
+		if (str_cmp(name, log_level_names[level]) == 0) {
+			if (level_out != NULL)
+				*level_out = level;
+			return EOK;
+		}
+		level++;
+	}
+
+	/* Maybe user specified number directly. */
+	char *end_ptr;
+	int level_int = strtol(name, &end_ptr, 0);
+	if ((end_ptr == name) || (str_length(end_ptr) != 0))
+		return EINVAL;
+	if (level_int < 0)
+		return ERANGE;
+	if (level_int >= (int) LVL_LIMIT)
+		return ERANGE;
+
+	if (level_out != NULL)
+		*level_out = (log_level_t) level_int;
+
+	return EOK;
+}
+
 /** Initialize the logging system.
  *
- * @param prog_name	Program name, will be printed as part of message
- * @param level		Minimum message level to print
- */
-int log_init(const char *prog_name, log_level_t level)
-{
-	assert(level < LVL_LIMIT);
-	log_level = level;
-
-	log_stream = stdout;
+ * @param prog_name Program name, will be printed as part of message
+ */
+int log_init(const char *prog_name)
+{
 	log_prog_name = str_dup(prog_name);
 	if (log_prog_name == NULL)
 		return ENOMEM;
 
+	logger_session = service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_LOGGER, LOGGER_INTERFACE_WRITER, 0);
+	if (logger_session == NULL) {
+		return ENOMEM;
+	}
+
+	default_log_id = log_create(prog_name, LOG_NO_PARENT);
+
 	return EOK;
 }
 
+/** Create a new (sub-) log.
+ *
+ * This function always returns a valid log_t. In case of errors,
+ * @c parent is returned and errors are silently ignored.
+ *
+ * @param name Log name under which message will be reported (appended to parents name).
+ * @param parent Parent log.
+ * @return Opaque identifier of the newly created log.
+ */
+log_t log_create(const char *name, log_t parent)
+{
+	async_exch_t *exchange = async_exchange_begin(logger_session);
+	if (exchange == NULL)
+		return parent;
+
+	if (parent == LOG_DEFAULT)
+		parent = default_log_id;
+
+	ipc_call_t answer;
+	aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_LOG,
+	    parent, &answer);
+	int rc = async_data_write_start(exchange, name, str_size(name));
+	sysarg_t reg_msg_rc;
+	async_wait_for(reg_msg, &reg_msg_rc);
+
+	async_exchange_end(exchange);
+
+	if ((rc != EOK) || (reg_msg_rc != EOK))
+		return parent;
+
+	return IPC_GET_ARG1(answer);
+}
+
 /** Write an entry to the log.
  *
- * @param level		Message verbosity level. Message is only printed
- *			if verbosity is less than or equal to current
- *			reporting level.
- * @param fmt		Format string (no traling newline).
- */
-void log_msg(log_level_t level, const char *fmt, ...)
+ * The message is printed only if the verbosity level is less than or
+ * equal to currently set reporting level of the log.
+ *
+ * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means).
+ * @param level Severity level of the message.
+ * @param fmt Format string in printf-like format (without trailing newline).
+ */
+void log_msg(log_t ctx, log_level_t level, const char *fmt, ...)
 {
 	va_list args;
 
 	va_start(args, fmt);
-	log_msgv(level, fmt, args);
+	log_msgv(ctx, level, fmt, args);
 	va_end(args);
 }
@@ -97,25 +229,20 @@
 /** Write an entry to the log (va_list variant).
  *
- * @param level		Message verbosity level. Message is only printed
- *			if verbosity is less than or equal to current
- *			reporting level.
- * @param fmt		Format string (no trailing newline)
- */
-void log_msgv(log_level_t level, const char *fmt, va_list args)
+ * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means).
+ * @param level Severity level of the message.
+ * @param fmt Format string in printf-like format (without trailing newline).
+ * @param args Arguments.
+ */
+void log_msgv(log_t ctx, log_level_t level, const char *fmt, va_list args)
 {
 	assert(level < LVL_LIMIT);
 
-	/* Higher number means higher verbosity. */
-	if (level <= log_level) {
-		fibril_mutex_lock(&log_serializer);
-
-		fprintf(log_stream, "%s: %s: ", log_prog_name,
-		    log_level_names[level]);
-		vfprintf(log_stream, fmt, args);
-		fputc('\n', log_stream);
-		fflush(log_stream);
-
-		fibril_mutex_unlock(&log_serializer);
-	}
+	char *message_buffer = malloc(MESSAGE_BUFFER_SIZE);
+	if (message_buffer == NULL)
+		return;
+
+	vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
+	logger_message(logger_session, ctx, level, message_buffer);
+	free(message_buffer);
 }
 
Index: uspace/lib/c/generic/io/logctl.c
===================================================================
--- uspace/lib/c/generic/io/logctl.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/generic/io/logctl.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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
+ * @{
+ */
+
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <io/logctl.h>
+#include <ipc/logger.h>
+#include <sysinfo.h>
+#include <ns.h>
+#include <str.h>
+
+/** IPC session with the logger service. */
+static async_sess_t *logger_session = NULL;
+
+static int start_logger_exchange(async_exch_t **exchange_out)
+{
+	assert(exchange_out != NULL);
+
+	if (logger_session == NULL) {
+		logger_session = service_connect_blocking(EXCHANGE_SERIALIZE,
+		    SERVICE_LOGGER, LOGGER_INTERFACE_CONTROL, 0);
+		if (logger_session == NULL)
+			return ENOMEM;
+	}
+
+	assert(logger_session != NULL);
+
+	async_exch_t *exchange = async_exchange_begin(logger_session);
+	if (exchange == NULL)
+		return ENOMEM;
+
+	*exchange_out = exchange;
+
+	return EOK;
+}
+
+/** Set default reported log level (global setting).
+ *
+ * This setting affects all logger clients whose reporting level was
+ * not yet changed.
+ *
+ * If logging level of client A is changed with logctl_set_log_level()
+ * to some level, this call will have no effect at that client's reporting
+ * level. Even if the actual value of the reporting level of client A is
+ * the same as current (previous) default log level.
+ *
+ * @param new_level New reported logging level.
+ * @return Error code of the conversion or EOK on success.
+ */
+int logctl_set_default_level(log_level_t new_level)
+{
+	async_exch_t *exchange = NULL;
+	int rc = start_logger_exchange(&exchange);
+	if (rc != EOK)
+		return rc;
+
+	rc = (int) async_req_1_0(exchange,
+	    LOGGER_CONTROL_SET_DEFAULT_LEVEL, new_level);
+
+	async_exchange_end(exchange);
+
+	return rc;
+}
+
+/** Set reported log level of a single log.
+ *
+ * @see logctl_set_default_level
+ *
+ * @param logname Log name.
+ * @param new_level New reported logging level.
+ * @return Error code of the conversion or EOK on success.
+ */
+int logctl_set_log_level(const char *logname, log_level_t new_level)
+{
+	async_exch_t *exchange = NULL;
+	int rc = start_logger_exchange(&exchange);
+	if (rc != EOK)
+		return rc;
+
+	aid_t reg_msg = async_send_1(exchange, LOGGER_CONTROL_SET_LOG_LEVEL,
+	    new_level, NULL);
+	rc = async_data_write_start(exchange, logname, str_size(logname));
+	sysarg_t reg_msg_rc;
+	async_wait_for(reg_msg, &reg_msg_rc);
+
+	async_exchange_end(exchange);
+
+	if (rc != EOK)
+		return rc;
+
+	return (int) reg_msg_rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/io/output.c
===================================================================
--- uspace/lib/c/generic/io/output.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/generic/io/output.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -37,4 +37,5 @@
 #include <as.h>
 #include <ipc/output.h>
+#include <io/concaps.h>
 #include <io/output.h>
 
Index: uspace/lib/c/generic/io/printf_core.c
===================================================================
--- uspace/lib/c/generic/io/printf_core.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/generic/io/printf_core.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -42,8 +42,16 @@
 #include <ctype.h>
 #include <str.h>
+#include <double_to_str.h>
+#include <ieee_double.h>
+#include <assert.h>
+#include <macros.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
@@ -66,4 +74,8 @@
 /** number has - sign */
 #define __PRINTF_FLAG_NEGATIVE     0x00000100
+
+/** don't print trailing zeros in the fractional part */
+#define __PRINTF_FLAG_NOFRACZEROS  0x00000200
+
 
 /**
@@ -110,4 +122,47 @@
 static const char invalch = U_SPECIAL;
 
+
+
+/** Unformatted double number string representation. */
+typedef struct {
+	/** Buffer with len digits, no sign or leading zeros. */
+	char *str;
+	/** Number of digits in str. */
+	int len;
+	/** Decimal exponent, ie number = str * 10^dec_exp */
+	int dec_exp;
+	/** True if negative. */
+	bool neg;
+} double_str_t;
+
+
+
+/** Returns the sign character or 0 if no sign should be printed. */
+static int get_sign_char(bool negative, uint32_t flags)
+{
+	if (negative) {
+		return '-';
+	} else if (flags & __PRINTF_FLAG_SHOWPLUS) {
+		return '+';
+	} else if (flags & __PRINTF_FLAG_SPACESIGN) {
+		return ' ';
+	} else {
+		return 0;
+	}
+}
+
+/** Prints count times character ch. */
+static int print_padding(char ch, int count, printf_spec_t *ps)
+{
+	for (int i = 0; i < count; ++i) {
+		if (ps->str_write(&ch, 1, ps->data) < 0) {
+			return -1;
+		}
+	}
+
+	return count;
+}
+
+
 /** Print one or more characters without adding newline.
  *
@@ -281,6 +336,7 @@
 		return printf_putstr(nullstr, ps);
 	
-	/* Print leading spaces. */
 	size_t strw = str_length(str);
+
+	/* Precision unspecified - print everything. */
 	if ((precision == 0) || (precision > strw))
 		precision = strw;
@@ -329,6 +385,7 @@
 		return printf_putstr(nullstr, ps);
 	
-	/* Print leading spaces. */
 	size_t strw = wstr_length(str);
+
+	/* Precision not specified - print everything. */
 	if ((precision == 0) || (precision > strw))
 		precision = strw;
@@ -377,4 +434,9 @@
     uint32_t flags, printf_spec_t *ps)
 {
+	/* Precision not specified. */
+	if (precision < 0) {
+		precision = 0;
+	}
+	
 	const char *digits;
 	if (flags & __PRINTF_FLAG_BIGCHARS)
@@ -525,4 +587,656 @@
 	
 	return ((int) counter);
+}
+
+/** Prints a special double (ie NaN, infinity) padded to width characters. */
+static int print_special(ieee_double_t val, int width, uint32_t flags, 
+	printf_spec_t *ps)
+{
+	assert(val.is_special);
+
+	char sign = get_sign_char(val.is_negative, flags);
+
+	const int str_len = 3;
+	const char *str;
+	
+	if (flags & __PRINTF_FLAG_BIGCHARS) {
+		str = val.is_infinity ? "INF" : "NAN";
+	} else {
+		str = val.is_infinity ? "inf" : "nan";
+	}
+
+	int padding_len = max(0, width - ((sign ? 1 : 0) + str_len));
+
+	int counter = 0;
+	int ret;
+
+	/* Leading padding. */
+	if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
+		if ((ret = print_padding(' ', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	if (sign) {
+		if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
+			return -1;
+		
+		counter += ret;
+	}
+
+	if ((ret = ps->str_write(str, str_len, ps->data)) < 0)
+		return -1;
+	
+	counter += ret;
+
+
+	/* Trailing padding. */
+	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
+		if ((ret = print_padding(' ', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	return counter;
+}
+
+/** Trims trailing zeros but leaves a single "0" intact. */
+static void fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp)
+{
+	/* Cut the zero off by adjusting the exponent. */
+	while (2 <= *len && '0' == buf[*len - 1]) {
+		--*len;
+		++*dec_exp;
+	}
+}
+
+/** Textually round up the last digit thereby eliminating it. */
+static void fp_round_up(char *buf, int *len, int *dec_exp)
+{
+	assert(1 <= *len);
+
+	char *last_digit = &buf[*len - 1];
+
+	int carry = ('5' <= *last_digit);
+
+	/* Cut the digit off by adjusting the exponent. */
+	--*len;
+	++*dec_exp;
+	--last_digit;
+
+	if (carry) {
+		/* Skip all the digits to cut off/round to zero. */
+		while (buf <= last_digit && '9' == *last_digit) {
+			--last_digit;
+		}
+
+		/* last_digit points to the last digit to round but not '9' */
+		if (buf <= last_digit) {
+			*last_digit += 1;
+			int new_len = last_digit - buf + 1;
+			*dec_exp += *len - new_len;
+			*len = new_len;
+		} else {
+			/* All len digits rounded to 0. */
+			buf[0] = '1';
+			*dec_exp += *len;
+			*len = 1;
+		}
+	} else {
+		/* The only digit was rounded to 0. */
+		if (last_digit < buf) {
+			buf[0] = '0';
+			*dec_exp = 0;
+			*len = 1;
+		}
+	}
+}
+
+
+/** Format and print the double string repressentation according 
+ *  to the %f specifier. 
+ */
+static int print_double_str_fixed(double_str_t *val_str, int precision, int width, 
+	uint32_t flags, printf_spec_t *ps)
+{
+	int len = val_str->len;
+	char *buf = val_str->str;
+	int dec_exp = val_str->dec_exp;
+
+	assert(0 < len);
+	assert(0 <= precision);
+	assert(0 <= dec_exp || -dec_exp <= precision);
+
+	/* Number of integral digits to print (at least leading zero). */
+	int int_len = max(1, len + dec_exp);
+
+	char sign = get_sign_char(val_str->neg, flags);
+
+	/* Fractional portion lengths. */
+	int last_frac_signif_pos = max(0, -dec_exp);
+	int leading_frac_zeros = max(0, last_frac_signif_pos - len);
+	int signif_frac_figs = min(last_frac_signif_pos, len);
+	int trailing_frac_zeros = precision - last_frac_signif_pos;
+	char *buf_frac = buf + len - signif_frac_figs;
+
+	if (flags & __PRINTF_FLAG_NOFRACZEROS) {
+		trailing_frac_zeros = 0;
+	}
+
+	int frac_len = leading_frac_zeros + signif_frac_figs + trailing_frac_zeros;
+
+	bool has_decimal_pt = (0 < frac_len) || (flags & __PRINTF_FLAG_DECIMALPT);
+
+	/* Number of non-padding chars to print. */
+	int num_len = (sign ? 1 : 0) + int_len + (has_decimal_pt ? 1 : 0) + frac_len;
+
+	int padding_len = max(0, width - num_len);
+	int ret = 0;
+	int counter = 0;
+
+	/* Leading padding and sign. */
+
+	if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
+		if ((ret = print_padding(' ', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	if (sign) {
+		if ((ret = ps->str_write(&sign, 1, ps->data)) < 0) 
+			return -1;
+		
+		counter += ret;
+	}
+
+	if (flags & __PRINTF_FLAG_ZEROPADDED) {
+		if ((ret = print_padding('0', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	/* Print the intergral part of the buffer. */
+
+	int buf_int_len = min(len, len + dec_exp);
+
+	if (0 < buf_int_len) {
+		if ((ret = ps->str_write(buf, buf_int_len, ps->data)) < 0) 
+			return -1;
+
+		counter += ret;
+
+		/* Print trailing zeros of the integral part of the number. */
+		if ((ret = print_padding('0', int_len - buf_int_len, ps)) < 0) 
+			return -1;
+	} else {
+		/* Single leading integer 0. */
+		char ch = '0';
+		if ((ret = ps->str_write(&ch, 1, ps->data)) < 0) 
+			return -1;
+	}
+
+	counter += ret;
+	
+	/* Print the decimal point and the fractional part. */
+	if (has_decimal_pt) {
+		char ch = '.';
+
+		if ((ret = ps->str_write(&ch, 1, ps->data)) < 0) 
+			return -1;
+		
+		counter += ret;
+
+		/* Print leading zeros of the fractional part of the number. */
+		if ((ret = print_padding('0', leading_frac_zeros, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+
+		/* Print significant digits of the fractional part of the number. */
+		if (0 < signif_frac_figs) {
+			if ((ret = ps->str_write(buf_frac, signif_frac_figs, ps->data)) < 0) 
+				return -1;
+
+			counter += ret;
+		}
+
+		/* Print trailing zeros of the fractional part of the number. */
+		if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	/* Trailing padding. */
+	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
+		if ((ret = print_padding(' ', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	return counter;
+}
+
+
+/** Convert, format and print a double according to the %f specifier. 
+ *
+ * @param g     Double to print.
+ * @param precision Number of fractional digits to print. If 0 no
+ *              decimal point will be printed unless the flag
+ *              __PRINTF_FLAG_DECIMALPT is specified.
+ * @param width Minimum number of characters to display. Pads 
+ *              with '0' or ' ' depending on the set flags;
+ * @param flags Printf flags.
+ * @param ps    Printing functions.
+ *
+ * @return The number of characters printed; negative on failure.
+ */
+static int print_double_fixed(double g, int precision, int width, uint32_t flags, 
+	printf_spec_t *ps)
+{
+	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
+		flags &= ~__PRINTF_FLAG_ZEROPADDED;
+	}
+
+	if (flags & __PRINTF_FLAG_DECIMALPT) {
+		flags &= ~__PRINTF_FLAG_NOFRACZEROS;
+	}
+
+	ieee_double_t val = extract_ieee_double(g);
+
+	if (val.is_special) {
+		return print_special(val, width, flags, ps);
+	} 
+
+	char buf[MAX_DOUBLE_STR_BUF_SIZE];
+	const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
+	double_str_t val_str;
+
+	val_str.str = buf;
+	val_str.neg = val.is_negative;
+
+	if (0 <= precision) {
+		/* 
+		 * Request one more digit so we can round the result. The last
+		 * digit it returns may have an error of at most +/- 1. 
+		 */
+		val_str.len = double_to_fixed_str(val, -1, precision + 1, buf, buf_size, 
+			&val_str.dec_exp);
+
+		/* 
+		 * Round using the last digit to produce precision fractional digits. 
+		 * If less than precision+1 fractional digits were output the last 
+		 * digit is definitely inaccurate so also round to get rid of it. 
+		 */
+		fp_round_up(buf, &val_str.len, &val_str.dec_exp);
+
+		/* Rounding could have introduced trailing zeros. */
+		if (flags & __PRINTF_FLAG_NOFRACZEROS) {
+			fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
+		}
+	} else {
+		/* Let the implementation figure out the proper precision. */
+		val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp);
+		
+		/* Precision needed for the last significant digit. */
+		precision = max(0, -val_str.dec_exp);
+	}
+
+	return print_double_str_fixed(&val_str, precision, width, flags, ps);
+}
+
+/** Prints the decimal exponent part of a %e specifier formatted number. */
+static int print_exponent(int exp_val, uint32_t flags, printf_spec_t *ps)
+{
+	int counter = 0;
+	int ret;
+
+	char exp_ch = (flags & __PRINTF_FLAG_BIGCHARS) ? 'E' : 'e';
+
+	if ((ret = ps->str_write(&exp_ch, 1, ps->data)) < 0) 
+		return -1;
+	
+	counter += ret;
+
+	char exp_sign = (exp_val < 0) ? '-' : '+';
+
+	if ((ret = ps->str_write(&exp_sign, 1, ps->data)) < 0)
+		return -1;
+
+	counter += ret;
+
+	/* Print the exponent. */
+	exp_val = abs(exp_val);
+	
+	char exp_str[4] = { 0 };
+
+	exp_str[0] = '0' + exp_val / 100;
+	exp_str[1] = '0' + (exp_val % 100) / 10 ;
+	exp_str[2] = '0' + (exp_val % 10);
+	
+	int exp_len = (exp_str[0] == '0') ? 2 : 3;
+	const char *exp_str_start = &exp_str[3] - exp_len;
+
+	if ((ret = ps->str_write(exp_str_start, exp_len, ps->data)) < 0) 
+		return -1;
+
+	counter += ret;
+
+	return counter;
+}
+
+
+/** Format and print the double string repressentation according 
+ *  to the %e specifier. 
+ */
+static int print_double_str_scient(double_str_t *val_str, int precision, 
+	int width, uint32_t flags, printf_spec_t *ps)
+{
+	int len = val_str->len;
+	int dec_exp = val_str->dec_exp;
+	char *buf  = val_str->str;
+
+	assert(0 < len);
+
+	char sign = get_sign_char(val_str->neg, flags);
+	bool has_decimal_pt = (0 < precision) || (flags & __PRINTF_FLAG_DECIMALPT);
+	int dec_pt_len = has_decimal_pt ? 1 : 0;
+
+	/* Fractional part lengths. */
+	int signif_frac_figs = len - 1;
+	int trailing_frac_zeros = precision - signif_frac_figs;
+
+	if (flags & __PRINTF_FLAG_NOFRACZEROS) {
+		trailing_frac_zeros = 0;
+	}
+
+	int frac_len = signif_frac_figs + trailing_frac_zeros;
+
+	int exp_val = dec_exp + len - 1;
+	/* Account for exponent sign and 'e'; minimum 2 digits. */
+	int exp_len = 2 + (abs(exp_val) >= 100 ? 3 : 2);
+
+	/* Number of non-padding chars to print. */
+	int num_len = (sign ? 1 : 0) + 1 + dec_pt_len + frac_len + exp_len;
+
+	int padding_len = max(0, width - num_len);
+	int ret = 0;
+	int counter = 0;
+
+	if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
+		if ((ret = print_padding(' ', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	if (sign) {
+		if ((ret = ps->str_write(&sign, 1, ps->data)) < 0) 
+			return -1;
+		
+		counter += ret;
+	}
+
+	if (flags & __PRINTF_FLAG_ZEROPADDED) {
+		if ((ret = print_padding('0', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	/* Single leading integer. */
+	if ((ret = ps->str_write(buf, 1, ps->data)) < 0) 
+		return -1;
+
+	counter += ret;
+
+	/* Print the decimal point and the fractional part. */
+	if (has_decimal_pt) {
+		char ch = '.';
+
+		if ((ret = ps->str_write(&ch, 1, ps->data)) < 0) 
+			return -1;
+		
+		counter += ret;
+
+		/* Print significant digits of the fractional part of the number. */
+		if (0 < signif_frac_figs) {
+			if ((ret = ps->str_write(buf + 1, signif_frac_figs, ps->data)) < 0) 
+				return -1;
+
+			counter += ret;
+		}
+
+		/* Print trailing zeros of the fractional part of the number. */
+		if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	/* Print the exponent. */
+	if ((ret = print_exponent(exp_val, flags, ps)) < 0) 
+		return -1;
+
+	counter += ret;
+
+	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
+		if ((ret = print_padding(' ', padding_len, ps)) < 0) 
+			return -1;
+
+		counter += ret;
+	}
+
+	return counter;
+}
+
+
+/** Convert, format and print a double according to the %e specifier. 
+ *
+ * Note that if g is large, the output may be huge (3e100 prints 
+ * with at least 100 digits).
+ *
+ * %e style: [-]d.dddde+dd
+ *  left-justified:  [-]d.dddde+dd[space_pad]
+ *  right-justified: [space_pad][-][zero_pad]d.dddde+dd
+ *
+ * @param g     Double to print.
+ * @param precision Number of fractional digits to print, ie
+ *              precision + 1 significant digits to display. If 0 no
+ *              decimal point will be printed unless the flag
+ *              __PRINTF_FLAG_DECIMALPT is specified. If negative
+ *              the shortest accurate number will be printed.
+ * @param width Minimum number of characters to display. Pads 
+ *              with '0' or ' ' depending on the set flags;
+ * @param flags Printf flags.
+ * @param ps    Printing functions.
+ *
+ * @return The number of characters printed; negative on failure.
+ */
+static int print_double_scientific(double g, int precision, int width, 
+	uint32_t flags, printf_spec_t *ps)
+{
+	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
+		flags &= ~__PRINTF_FLAG_ZEROPADDED;
+	}
+
+	ieee_double_t val = extract_ieee_double(g);
+
+	if (val.is_special) {
+		return print_special(val, width, flags, ps);
+	} 
+
+	char buf[MAX_DOUBLE_STR_BUF_SIZE];
+	const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
+	double_str_t val_str;
+
+	val_str.str = buf;
+	val_str.neg = val.is_negative;
+
+	if (0 <= precision) {
+		/* 
+		 * Request one more digit (in addition to the leading integer) 
+		 * so we can round the result. The last digit it returns may 
+		 * have an error of at most +/- 1. 
+		 */
+		val_str.len = double_to_fixed_str(val, precision + 2, -1, buf, buf_size, 
+			&val_str.dec_exp);
+
+		/* 
+		 * Round the extra digit to produce precision+1 significant digits. 
+		 * If less than precision+2 significant digits were returned the last 
+		 * digit is definitely inaccurate so also round to get rid of it. 
+		 */
+		fp_round_up(buf, &val_str.len, &val_str.dec_exp);
+
+		/* Rounding could have introduced trailing zeros. */
+		if (flags & __PRINTF_FLAG_NOFRACZEROS) {
+			fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
+		}
+	} else {
+		/* Let the implementation figure out the proper precision. */
+		val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp);
+		
+		/* Use all produced digits. */
+		precision = val_str.len - 1;
+	}
+
+	return print_double_str_scient(&val_str, precision, width, flags, ps);
+}
+
+
+/** Convert, format and print a double according to the %g specifier. 
+ *
+ * %g style chooses between %f and %e. 
+ *
+ * @param g     Double to print.
+ * @param precision Number of significant digits to display; excluding
+ *              any leading zeros from this count. If negative
+ *              the shortest accurate number will be printed.
+ * @param width Minimum number of characters to display. Pads 
+ *              with '0' or ' ' depending on the set flags;
+ * @param flags Printf flags.
+ * @param ps    Printing functions.
+ *
+ * @return The number of characters printed; negative on failure.
+ */
+static int print_double_generic(double g, int precision, int width, 
+	uint32_t flags, printf_spec_t *ps)
+{
+	ieee_double_t val = extract_ieee_double(g);
+
+	if (val.is_special) {
+		return print_special(val, width, flags, ps);
+	} 
+
+	char buf[MAX_DOUBLE_STR_BUF_SIZE];
+	const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
+	int dec_exp;
+	int len;
+
+	/* Honor the user requested number of significant digits. */
+	if (0 <= precision) {
+		/* 
+		 * Do a quick and dirty conversion of a single digit to determine 
+		 * the decimal exponent.
+		 */
+		len = double_to_fixed_str(val, 1, -1, buf, buf_size, &dec_exp);
+		assert(0 < len);
+
+		precision = max(1, precision);
+
+		if (-4 <= dec_exp && dec_exp < precision) {
+			precision = precision - (dec_exp + 1);
+			return print_double_fixed(g, precision, width, 
+				flags | __PRINTF_FLAG_NOFRACZEROS, ps);
+		} else {
+			--precision;
+			return print_double_scientific(g, precision, width, 
+				flags | __PRINTF_FLAG_NOFRACZEROS, ps);
+		}
+	} else {
+		/* Convert to get the decimal exponent and digit count.*/
+		len = double_to_short_str(val, buf, buf_size, &dec_exp);
+		assert(0 < len);
+
+		if (flags & __PRINTF_FLAG_LEFTALIGNED) {
+			flags &= ~__PRINTF_FLAG_ZEROPADDED;
+		}
+
+		double_str_t val_str;
+		val_str.str = buf;
+		val_str.len = len;
+		val_str.neg = val.is_negative;
+		val_str.dec_exp = dec_exp;
+
+		int first_digit_pos = len + dec_exp;
+		int last_digit_pos = dec_exp;
+
+		/* The whole number (15 digits max) fits between dec places 15 .. -6 */
+		if (len <= 15 && -6 <= last_digit_pos && first_digit_pos <= 15) {
+			/* Precision needed for the last significant digit. */
+			precision = max(0, -val_str.dec_exp);
+			return print_double_str_fixed(&val_str, precision, width, flags, ps);
+		} else {
+			/* Use all produced digits. */
+			precision = val_str.len - 1;
+			return print_double_str_scient(&val_str, precision, width, flags, ps);
+		}
+	}
+}
+
+
+/** Convert, format and print a double according to the specifier. 
+ *
+ * Depending on the specifier it prints the double using the styles
+ * %g, %f or %e by means of print_double_generic(), print_double_fixed(),
+ * print_double_scientific().
+ *
+ * @param g     Double to print.
+ * @param spec  Specifier of the style to print in; one of: 'g','G','f','F',
+ *              'e','E'.
+ * @param precision Number of fractional digits to display. If negative
+ *              the shortest accurate number will be printed for style %g;
+ *              negative precision defaults to 6 for styles %f, %e.
+ * @param width Minimum number of characters to display. Pads 
+ *              with '0' or ' ' depending on the set flags;
+ * @param flags Printf flags.
+ * @param ps    Printing functions.
+ *
+ * @return The number of characters printed; negative on failure.
+ */
+static int print_double(double g, char spec, int precision, int width, 
+	uint32_t flags, printf_spec_t *ps)
+{
+	switch (spec) {
+	case 'F':
+		flags |= __PRINTF_FLAG_BIGCHARS;
+		/* Fall through.*/
+	case 'f':
+		precision = (precision < 0) ? 6 : precision;
+		return print_double_fixed(g, precision, width, flags, ps);
+
+	case 'E':
+		flags |= __PRINTF_FLAG_BIGCHARS;
+		/* Fall through.*/
+	case 'e':
+		precision = (precision < 0) ? 6 : precision;
+		return print_double_scientific(g, precision, width, flags, ps);
+
+	case 'G':
+		flags |= __PRINTF_FLAG_BIGCHARS;
+		/* Fall through.*/
+	case 'g':
+		return print_double_generic(g, precision, width, flags, ps);
+
+	default:
+		assert(false);
+		return -1;
+	}
 }
 
@@ -656,4 +1370,5 @@
 				case '#':
 					flags |= __PRINTF_FLAG_PREFIX;
+					flags |= __PRINTF_FLAG_DECIMALPT;
 					break;
 				case '-':
@@ -701,9 +1416,10 @@
 			
 			/* Precision and '*' operator */
-			int precision = 0;
+			int precision = -1;
 			if (uc == '.') {
 				i = nxt;
 				uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
 				if (isdigit(uc)) {
+					precision = 0;
 					while (true) {
 						precision *= 10;
@@ -723,6 +1439,6 @@
 					precision = (int) va_arg(ap, int);
 					if (precision < 0) {
-						/* Ignore negative precision */
-						precision = 0;
+						/* Ignore negative precision - use default instead */
+						precision = -1;
 					}
 				}
@@ -774,4 +1490,6 @@
 			 */
 			case 's':
+				precision = max(0,  precision);
+				
 				if (qualifier == PrintfQualifierLong)
 					retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps);
@@ -797,4 +1515,25 @@
 					goto out;
 				};
+				
+				counter += retval;
+				j = nxt;
+				goto next_char;
+				
+			/*
+			 * Floating point values
+			 */
+			case 'G':
+			case 'g':
+			case 'F':
+			case 'f':
+			case 'E':
+			case 'e':
+				retval = print_double(va_arg(ap, double), uc, precision, 
+					width, flags, ps);
+				
+				if (retval < 0) {
+					counter = -counter;
+					goto out;
+				}
 				
 				counter += retval;
Index: uspace/lib/c/generic/power_of_ten.c
===================================================================
--- uspace/lib/c/generic/power_of_ten.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/generic/power_of_ten.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * 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 "private/power_of_ten.h"
+
+#include <ieee_double.h>
+#include <assert.h>
+
+/** Precomputed normalized rounded-up powers of 10^k.
+ *
+ * The powers were computed using arbitrary precision arithmetic
+ * and rounded up to the top 64 significant bits. Therefore:
+ *   10^dec_exp == significand * 2^bin_exp  +/- 0.5 ulp error
+ *
+ * The smallest interval of binary exponents computed by hand
+ * is [-1083, 987]. Add 200 (exponent change > 3 * 64 bits) 
+ * to both bounds just to be on the safe side; ie [-1283, 1187].
+ */
+static struct {
+	uint64_t significand;
+	int16_t bin_exp;
+	int16_t dec_exp;
+} fp_powers_of_10[] = {
+	{ 0xb8e1cbc28bef0b69ULL, -1286, -368 },
+	{ 0x89bf722840327f82ULL, -1259, -360 },
+	{ 0xcd42a11346f34f7dULL, -1233, -352 },
+	{ 0x98ee4a22ecf3188cULL, -1206, -344 },
+	{ 0xe3e27a444d8d98b8ULL, -1180, -336 },
+	{ 0xa9c98d8ccb009506ULL, -1153, -328 },
+	{ 0xfd00b897478238d1ULL, -1127, -320 },
+	{ 0xbc807527ed3e12bdULL, -1100, -312 },
+	{ 0x8c71dcd9ba0b4926ULL, -1073, -304 },
+	{ 0xd1476e2c07286faaULL, -1047, -296 },
+	{ 0x9becce62836ac577ULL, -1020, -288 },
+	{ 0xe858ad248f5c22caULL, -994, -280 },
+	{ 0xad1c8eab5ee43b67ULL, -967, -272 },
+	{ 0x80fa687f881c7f8eULL, -940, -264 },
+	{ 0xc0314325637a193aULL, -914, -256 },
+	{ 0x8f31cc0937ae58d3ULL, -887, -248 },
+	{ 0xd5605fcdcf32e1d7ULL, -861, -240 },
+	{ 0x9efa548d26e5a6e2ULL, -834, -232 },
+	{ 0xece53cec4a314ebeULL, -808, -224 },
+	{ 0xb080392cc4349dedULL, -781, -216 },
+	{ 0x8380dea93da4bc60ULL, -754, -208 },
+	{ 0xc3f490aa77bd60fdULL, -728, -200 },
+	{ 0x91ff83775423cc06ULL, -701, -192 },
+	{ 0xd98ddaee19068c76ULL, -675, -184 },
+	{ 0xa21727db38cb0030ULL, -648, -176 },
+	{ 0xf18899b1bc3f8ca2ULL, -622, -168 },
+	{ 0xb3f4e093db73a093ULL, -595, -160 },
+	{ 0x8613fd0145877586ULL, -568, -152 },
+	{ 0xc7caba6e7c5382c9ULL, -542, -144 },
+	{ 0x94db483840b717f0ULL, -515, -136 },
+	{ 0xddd0467c64bce4a1ULL, -489, -128 },
+	{ 0xa54394fe1eedb8ffULL, -462, -120 },
+	{ 0xf64335bcf065d37dULL, -436, -112 },
+	{ 0xb77ada0617e3bbcbULL, -409, -104 },
+	{ 0x88b402f7fd75539bULL, -382, -96 },
+	{ 0xcbb41ef979346bcaULL, -356, -88 },
+	{ 0x97c560ba6b0919a6ULL, -329, -80 },
+	{ 0xe2280b6c20dd5232ULL, -303, -72 },
+	{ 0xa87fea27a539e9a5ULL, -276, -64 },
+	{ 0xfb158592be068d2fULL, -250, -56 },
+	{ 0xbb127c53b17ec159ULL, -223, -48 },
+	{ 0x8b61313bbabce2c6ULL, -196, -40 },
+	{ 0xcfb11ead453994baULL, -170, -32 },
+	{ 0x9abe14cd44753b53ULL, -143, -24 },
+	{ 0xe69594bec44de15bULL, -117, -16 },
+	{ 0xabcc77118461cefdULL, -90, -8 },
+	{ 0x8000000000000000ULL, -63, 0 },
+	{ 0xbebc200000000000ULL, -37, 8 },
+	{ 0x8e1bc9bf04000000ULL, -10, 16 },
+	{ 0xd3c21bcecceda100ULL, 16, 24 },
+	{ 0x9dc5ada82b70b59eULL, 43, 32 },
+	{ 0xeb194f8e1ae525fdULL, 69, 40 },
+	{ 0xaf298d050e4395d7ULL, 96, 48 },
+	{ 0x82818f1281ed44a0ULL, 123, 56 },
+	{ 0xc2781f49ffcfa6d5ULL, 149, 64 },
+	{ 0x90e40fbeea1d3a4bULL, 176, 72 },
+	{ 0xd7e77a8f87daf7fcULL, 202, 80 },
+	{ 0xa0dc75f1778e39d6ULL, 229, 88 },
+	{ 0xefb3ab16c59b14a3ULL, 255, 96 },
+	{ 0xb2977ee300c50fe7ULL, 282, 104 },
+	{ 0x850fadc09923329eULL, 309, 112 },
+	{ 0xc646d63501a1511eULL, 335, 120 },
+	{ 0x93ba47c980e98ce0ULL, 362, 128 },
+	{ 0xdc21a1171d42645dULL, 388, 136 },
+	{ 0xa402b9c5a8d3a6e7ULL, 415, 144 },
+	{ 0xf46518c2ef5b8cd1ULL, 441, 152 },
+	{ 0xb616a12b7fe617aaULL, 468, 160 },
+	{ 0x87aa9aff79042287ULL, 495, 168 },
+	{ 0xca28a291859bbf93ULL, 521, 176 },
+	{ 0x969eb7c47859e744ULL, 548, 184 },
+	{ 0xe070f78d3927556bULL, 574, 192 },
+	{ 0xa738c6bebb12d16dULL, 601, 200 },
+	{ 0xf92e0c3537826146ULL, 627, 208 },
+	{ 0xb9a74a0637ce2ee1ULL, 654, 216 },
+	{ 0x8a5296ffe33cc930ULL, 681, 224 },
+	{ 0xce1de40642e3f4b9ULL, 707, 232 },
+	{ 0x9991a6f3d6bf1766ULL, 734, 240 },
+	{ 0xe4d5e82392a40515ULL, 760, 248 },
+	{ 0xaa7eebfb9df9de8eULL, 787, 256 },
+	{ 0xfe0efb53d30dd4d8ULL, 813, 264 },
+	{ 0xbd49d14aa79dbc82ULL, 840, 272 },
+	{ 0x8d07e33455637eb3ULL, 867, 280 },
+	{ 0xd226fc195c6a2f8cULL, 893, 288 },
+	{ 0x9c935e00d4b9d8d2ULL, 920, 296 },
+	{ 0xe950df20247c83fdULL, 946, 304 },
+	{ 0xadd57a27d29339f6ULL, 973, 312 },
+	{ 0x81842f29f2cce376ULL, 1000, 320 },
+	{ 0xc0fe908895cf3b44ULL, 1026, 328 },
+	{ 0x8fcac257558ee4e6ULL, 1053, 336 },
+	{ 0xd6444e39c3db9b0aULL, 1079, 344 },
+	{ 0x9fa42700db900ad2ULL, 1106, 352 },
+	{ 0xede24ae798ec8284ULL, 1132, 360 },
+	{ 0xb13cc3832ef0c9acULL, 1159, 368 },
+	{ 0x840d57e2899d945fULL, 1186, 376 }
+};
+
+
+/** 
+ * Returns the smallest precomputed power of 10 such that 
+ *  binary_exp <= power_of_10.bin_exp
+ * where
+ *  10^decimal_exp = power_of_10.significand * 2^bin_exp 
+ * with an error of 0.5 ulp in the significand.
+ */
+void get_power_of_ten(int binary_exp, fp_num_t *power_of_10, int *decimal_exp)
+{
+	const int powers_count = sizeof(fp_powers_of_10) / sizeof(fp_powers_of_10[0]);
+	const int min_bin_exp = fp_powers_of_10[0].bin_exp;
+	const int max_bin_exp = fp_powers_of_10[powers_count - 1].bin_exp;
+	const int max_bin_exp_diff = 27;
+
+	assert(min_bin_exp <= binary_exp && binary_exp <= max_bin_exp);
+
+	/* 
+	 * Binary exponent difference between adjacent powers of 10 
+	 * is lg(10^8) = 26.575. The starting search index seed_idx
+	 * undershoots the actual position by less than 1.6%, ie it
+	 * skips 26.575/27 = 98.4% of all the smaller powers. This
+	 * translates to at most three extra tests. 
+	 */
+	int seed_idx = (binary_exp - min_bin_exp) / max_bin_exp_diff;
+
+	assert(fp_powers_of_10[seed_idx].bin_exp < binary_exp);
+
+	for (int i = seed_idx; i < powers_count; ++i) {
+		/* Found the smallest power of 10 with bin_exp >= binary_exp. */
+		if (binary_exp <= fp_powers_of_10[i].bin_exp) {
+			assert(fp_powers_of_10[i].bin_exp <= binary_exp + max_bin_exp_diff);
+
+			power_of_10->significand = fp_powers_of_10[i].significand;
+			power_of_10->exponent = fp_powers_of_10[i].bin_exp;
+			*decimal_exp = fp_powers_of_10[i].dec_exp;
+			return;
+		}
+	}
+
+	assert(false);
+}
+
Index: uspace/lib/c/generic/private/power_of_ten.h
===================================================================
--- uspace/lib/c/generic/private/power_of_ten.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/generic/private/power_of_ten.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * 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.
+ */
+
+#ifndef POWER_OF_TEN_H_
+#define POWER_OF_TEN_H_
+
+/* Fwd decl. */
+struct fp_num_t_tag;
+
+extern void get_power_of_ten(int, struct fp_num_t_tag *, int *);
+
+#endif
Index: uspace/lib/c/generic/time.c
===================================================================
--- uspace/lib/c/generic/time.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/generic/time.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -1,4 +1,6 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
  * All rights reserved.
  *
@@ -43,5 +45,14 @@
 #include <ddi.h>
 #include <libc.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
 #include <unistd.h>
+#include <loc.h>
+#include <device/clock_dev.h>
+#include <malloc.h>
+
+#define ASCTIME_BUF_LEN 26
 
 /** Pointer to kernel shared variables with time */
@@ -52,4 +63,337 @@
 } *ktime = NULL;
 
+/* Helper functions ***********************************************************/
+
+#define HOURS_PER_DAY (24)
+#define MINS_PER_HOUR (60)
+#define SECS_PER_MIN (60)
+#define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY)
+#define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR)
+#define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY)
+
+/**
+ * Checks whether the year is a leap year.
+ *
+ * @param year Year since 1900 (e.g. for 1970, the value is 70).
+ * @return true if year is a leap year, false otherwise
+ */
+static bool _is_leap_year(time_t year)
+{
+	year += 1900;
+
+	if (year % 400 == 0)
+		return true;
+	if (year % 100 == 0)
+		return false;
+	if (year % 4 == 0)
+		return true;
+	return false;
+}
+
+/**
+ * Returns how many days there are in the given month of the given year.
+ * Note that year is only taken into account if month is February.
+ *
+ * @param year Year since 1900 (can be negative).
+ * @param mon Month of the year. 0 for January, 11 for December.
+ * @return Number of days in the specified month.
+ */
+static int _days_in_month(time_t year, time_t mon)
+{
+	assert(mon >= 0 && mon <= 11);
+
+	static int month_days[] =
+		{ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+	if (mon == 1) {
+		year += 1900;
+		/* february */
+		return _is_leap_year(year) ? 29 : 28;
+	} else {
+		return month_days[mon];
+	}
+}
+
+/**
+ * For specified year, month and day of month, returns which day of that year
+ * it is.
+ *
+ * For example, given date 2011-01-03, the corresponding expression is:
+ *     _day_of_year(111, 0, 3) == 2
+ *
+ * @param year Year (year 1900 = 0, can be negative).
+ * @param mon Month (January = 0).
+ * @param mday Day of month (First day is 1).
+ * @return Day of year (First day is 0).
+ */
+static int _day_of_year(time_t year, time_t mon, time_t mday)
+{
+	static int mdays[] =
+	    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+	static int leap_mdays[] =
+	    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
+
+	return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1;
+}
+
+/**
+ * Integer division that rounds to negative infinity.
+ * Used by some functions in this file.
+ *
+ * @param op1 Dividend.
+ * @param op2 Divisor.
+ * @return Rounded quotient.
+ */
+static time_t _floor_div(time_t op1, time_t op2)
+{
+	if (op1 >= 0 || op1 % op2 == 0) {
+		return op1 / op2;
+	} else {
+		return op1 / op2 - 1;
+	}
+}
+
+/**
+ * Modulo that rounds to negative infinity.
+ * Used by some functions in this file.
+ *
+ * @param op1 Dividend.
+ * @param op2 Divisor.
+ * @return Remainder.
+ */
+static time_t _floor_mod(time_t op1, time_t op2)
+{
+	int div = _floor_div(op1, op2);
+
+	/* (a / b) * b + a % b == a */
+	/* thus, a % b == a - (a / b) * b */
+
+	int result = op1 - div * op2;
+	
+	/* Some paranoid checking to ensure I didn't make a mistake here. */
+	assert(result >= 0);
+	assert(result < op2);
+	assert(div * op2 + result == op1);
+	
+	return result;
+}
+
+/**
+ * Number of days since the Epoch.
+ * Epoch is 1970-01-01, which is also equal to day 0.
+ *
+ * @param year Year (year 1900 = 0, may be negative).
+ * @param mon Month (January = 0).
+ * @param mday Day of month (first day = 1).
+ * @return Number of days since the Epoch.
+ */
+static time_t _days_since_epoch(time_t year, time_t mon, time_t mday)
+{
+	return (year - 70) * 365 + _floor_div(year - 69, 4) -
+	    _floor_div(year - 1, 100) + _floor_div(year + 299, 400) +
+	    _day_of_year(year, mon, mday);
+}
+
+/**
+ * Seconds since the Epoch. see also _days_since_epoch().
+ * 
+ * @param tm Normalized broken-down time.
+ * @return Number of seconds since the epoch, not counting leap seconds.
+ */
+static time_t _secs_since_epoch(const struct tm *tm)
+{
+	return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *
+	    SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR +
+	    tm->tm_min * SECS_PER_MIN + tm->tm_sec;
+}
+
+/**
+ * Which day of week the specified date is.
+ * 
+ * @param year Year (year 1900 = 0).
+ * @param mon Month (January = 0).
+ * @param mday Day of month (first = 1).
+ * @return Day of week (Sunday = 0).
+ */
+static int _day_of_week(time_t year, time_t mon, time_t mday)
+{
+	/* 1970-01-01 is Thursday */
+	return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7);
+}
+
+/**
+ * Normalizes the broken-down time and optionally adds specified amount of
+ * seconds.
+ * 
+ * @param tm Broken-down time to normalize.
+ * @param sec_add Seconds to add.
+ * @return 0 on success, -1 on overflow
+ */
+static int _normalize_time(struct tm *tm, time_t sec_add)
+{
+	// TODO: DST correction
+
+	/* Set initial values. */
+	time_t sec = tm->tm_sec + sec_add;
+	time_t min = tm->tm_min;
+	time_t hour = tm->tm_hour;
+	time_t day = tm->tm_mday - 1;
+	time_t mon = tm->tm_mon;
+	time_t year = tm->tm_year;
+
+	/* Adjust time. */
+	min += _floor_div(sec, SECS_PER_MIN);
+	sec = _floor_mod(sec, SECS_PER_MIN);
+	hour += _floor_div(min, MINS_PER_HOUR);
+	min = _floor_mod(min, MINS_PER_HOUR);
+	day += _floor_div(hour, HOURS_PER_DAY);
+	hour = _floor_mod(hour, HOURS_PER_DAY);
+
+	/* Adjust month. */
+	year += _floor_div(mon, 12);
+	mon = _floor_mod(mon, 12);
+
+	/* Now the difficult part - days of month. */
+	
+	/* First, deal with whole cycles of 400 years = 146097 days. */
+	year += _floor_div(day, 146097) * 400;
+	day = _floor_mod(day, 146097);
+	
+	/* Then, go in one year steps. */
+	if (mon <= 1) {
+		/* January and February. */
+		while (day > 365) {
+			day -= _is_leap_year(year) ? 366 : 365;
+			year++;
+		}
+	} else {
+		/* Rest of the year. */
+		while (day > 365) {
+			day -= _is_leap_year(year + 1) ? 366 : 365;
+			year++;
+		}
+	}
+	
+	/* Finally, finish it off month per month. */
+	while (day >= _days_in_month(year, mon)) {
+		day -= _days_in_month(year, mon);
+		mon++;
+		if (mon >= 12) {
+			mon -= 12;
+			year++;
+		}
+	}
+	
+	/* Calculate the remaining two fields. */
+	tm->tm_yday = _day_of_year(year, mon, day + 1);
+	tm->tm_wday = _day_of_week(year, mon, day + 1);
+	
+	/* And put the values back to the struct. */
+	tm->tm_sec = (int) sec;
+	tm->tm_min = (int) min;
+	tm->tm_hour = (int) hour;
+	tm->tm_mday = (int) day + 1;
+	tm->tm_mon = (int) mon;
+	
+	/* Casts to work around libc brain-damage. */
+	if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) {
+		tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX);
+		return -1;
+	}
+	
+	tm->tm_year = (int) year;
+	return 0;
+}
+
+/**
+ * Which day the week-based year starts on, relative to the first calendar day.
+ * E.g. if the year starts on December 31st, the return value is -1.
+ *
+ * @param Year since 1900.
+ * @return Offset of week-based year relative to calendar year.
+ */
+static int _wbyear_offset(int year)
+{
+	int start_wday = _day_of_week(year, 0, 1);
+	return _floor_mod(4 - start_wday, 7) - 3;
+}
+
+/**
+ * Returns week-based year of the specified time.
+ *
+ * @param tm Normalized broken-down time.
+ * @return Week-based year.
+ */
+static int _wbyear(const struct tm *tm)
+{
+	int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
+	if (day < 0) {
+		/* Last week of previous year. */
+		return tm->tm_year - 1;
+	}
+	if (day > 364 + _is_leap_year(tm->tm_year)) {
+		/* First week of next year. */
+		return tm->tm_year + 1;
+	}
+	/* All the other days are in the calendar year. */
+	return tm->tm_year;
+}
+
+/**
+ * Week number of the year, assuming weeks start on sunday.
+ * The first Sunday of January is the first day of week 1;
+ * days in the new year before this are in week 0.
+ *
+ * @param tm Normalized broken-down time.
+ * @return The week number (0 - 53).
+ */
+static int _sun_week_number(const struct tm *tm)
+{
+	int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7;
+	return (tm->tm_yday - first_day + 7) / 7;
+}
+
+/**
+ * Week number of the year, assuming weeks start on monday.
+ * If the week containing January 1st has four or more days in the new year,
+ * then it is considered week 1. Otherwise, it is the last week of the previous
+ * year, and the next week is week 1. Both January 4th and the first Thursday
+ * of January are always in week 1.
+ *
+ * @param tm Normalized broken-down time.
+ * @return The week number (1 - 53).
+ */
+static int _iso_week_number(const struct tm *tm)
+{
+	int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
+	if (day < 0) {
+		/* Last week of previous year. */
+		return 53;
+	}
+	if (day > 364 + _is_leap_year(tm->tm_year)) {
+		/* First week of next year. */
+		return 1;
+	}
+	/* All the other days give correct answer. */
+	return (day / 7 + 1);
+}
+
+/**
+ * Week number of the year, assuming weeks start on monday.
+ * The first Monday of January is the first day of week 1;
+ * days in the new year before this are in week 0. 
+ *
+ * @param tm Normalized broken-down time.
+ * @return The week number (0 - 53).
+ */
+static int _mon_week_number(const struct tm *tm)
+{
+	int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7;
+	return (tm->tm_yday - first_day + 7) / 7;
+}
+
+/******************************************************************************/
+
+
 /** Add microseconds to given timeval.
  *
@@ -139,4 +483,67 @@
  */
 int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+	int rc;
+	struct tm t;
+	category_id_t cat_id;
+	size_t svc_cnt;
+	service_id_t *svc_ids = NULL;
+	service_id_t svc_id;
+	char *svc_name = NULL;
+
+	static async_sess_t *clock_conn = NULL;
+
+	if (tz) {
+		tz->tz_minuteswest = 0;
+		tz->tz_dsttime = DST_NONE;
+	}
+
+	if (clock_conn == NULL) {
+		rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
+		if (rc != EOK)
+			goto ret_uptime;
+
+		rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
+		if (rc != EOK)
+			goto ret_uptime;
+
+		if (svc_cnt == 0)
+			goto ret_uptime;
+
+		rc = loc_service_get_name(svc_ids[0], &svc_name);
+		if (rc != EOK)
+			goto ret_uptime;
+
+		rc = loc_service_get_id(svc_name, &svc_id, 0);
+		if (rc != EOK)
+			goto ret_uptime;
+
+		clock_conn = loc_service_connect(EXCHANGE_SERIALIZE,
+		    svc_id, IPC_FLAG_BLOCKING);
+		if (!clock_conn)
+			goto ret_uptime;
+	}
+
+	rc = clock_dev_time_get(clock_conn, &t);
+	if (rc != EOK)
+		goto ret_uptime;
+
+	tv->tv_usec = 0;
+	tv->tv_sec = mktime(&t);
+
+	free(svc_name);
+	free(svc_ids);
+
+	return EOK;
+
+ret_uptime:
+
+	free(svc_name);
+	free(svc_ids);
+
+	return getuptime(tv);
+}
+
+int getuptime(struct timeval *tv)
 {
 	if (ktime == NULL) {
@@ -160,9 +567,4 @@
 	}
 	
-	if (tz) {
-		tz->tz_minuteswest = 0;
-		tz->tz_dsttime = DST_NONE;
-	}
-	
 	sysarg_t s2 = ktime->seconds2;
 	
@@ -178,5 +580,5 @@
 	} else
 		tv->tv_sec = s1;
-	
+
 	return 0;
 }
@@ -229,4 +631,355 @@
 }
 
+/**
+ * This function first normalizes the provided broken-down time
+ * (moves all values to their proper bounds) and then tries to
+ * calculate the appropriate time_t representation.
+ *
+ * @param tm Broken-down time.
+ * @return time_t representation of the time, undefined value on overflow.
+ */
+time_t mktime(struct tm *tm)
+{
+	// TODO: take DST flag into account
+	// TODO: detect overflow
+
+	_normalize_time(tm, 0);
+	return _secs_since_epoch(tm);
+}
+
+/**
+ * Convert time and date to a string, based on a specified format and
+ * current locale.
+ * 
+ * @param s Buffer to write string to.
+ * @param maxsize Size of the buffer.
+ * @param format Format of the output.
+ * @param tm Broken-down time to format.
+ * @return Number of bytes written.
+ */
+size_t strftime(char *restrict s, size_t maxsize,
+    const char *restrict format, const struct tm *restrict tm)
+{
+	assert(s != NULL);
+	assert(format != NULL);
+	assert(tm != NULL);
+
+	// TODO: use locale
+	static const char *wday_abbr[] = {
+		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+	};
+	static const char *wday[] = {
+		"Sunday", "Monday", "Tuesday", "Wednesday",
+		"Thursday", "Friday", "Saturday"
+	};
+	static const char *mon_abbr[] = {
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+	};
+	static const char *mon[] = {
+		"January", "February", "March", "April", "May", "June", "July",
+		"August", "September", "October", "November", "December"
+	};
+	
+	if (maxsize < 1) {
+		return 0;
+	}
+	
+	char *ptr = s;
+	size_t consumed;
+	size_t remaining = maxsize;
+	
+	#define append(...) { \
+		/* FIXME: this requires POSIX-correct snprintf */ \
+		/*        otherwise it won't work with non-ascii chars */ \
+		consumed = snprintf(ptr, remaining, __VA_ARGS__); \
+		if (consumed >= remaining) { \
+			return 0; \
+		} \
+		ptr += consumed; \
+		remaining -= consumed; \
+	}
+	
+	#define recurse(fmt) { \
+		consumed = strftime(ptr, remaining, fmt, tm); \
+		if (consumed == 0) { \
+			return 0; \
+		} \
+		ptr += consumed; \
+		remaining -= consumed; \
+	}
+	
+	#define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \
+	    (((hour) == 0) ? 12 : (hour)))
+	
+	while (*format != '\0') {
+		if (*format != '%') {
+			append("%c", *format);
+			format++;
+			continue;
+		}
+		
+		format++;
+		if (*format == '0' || *format == '+') {
+			// TODO: padding
+			format++;
+		}
+		while (isdigit(*format)) {
+			// TODO: padding
+			format++;
+		}
+		if (*format == 'O' || *format == 'E') {
+			// TODO: locale's alternative format
+			format++;
+		}
+		
+		switch (*format) {
+		case 'a':
+			append("%s", wday_abbr[tm->tm_wday]); break;
+		case 'A':
+			append("%s", wday[tm->tm_wday]); break;
+		case 'b':
+			append("%s", mon_abbr[tm->tm_mon]); break;
+		case 'B':
+			append("%s", mon[tm->tm_mon]); break;
+		case 'c':
+			// TODO: locale-specific datetime format
+			recurse("%Y-%m-%d %H:%M:%S"); break;
+		case 'C':
+			append("%02d", (1900 + tm->tm_year) / 100); break;
+		case 'd':
+			append("%02d", tm->tm_mday); break;
+		case 'D':
+			recurse("%m/%d/%y"); break;
+		case 'e':
+			append("%2d", tm->tm_mday); break;
+		case 'F':
+			recurse("%+4Y-%m-%d"); break;
+		case 'g':
+			append("%02d", _wbyear(tm) % 100); break;
+		case 'G':
+			append("%d", _wbyear(tm)); break;
+		case 'h':
+			recurse("%b"); break;
+		case 'H':
+			append("%02d", tm->tm_hour); break;
+		case 'I':
+			append("%02d", TO_12H(tm->tm_hour)); break;
+		case 'j':
+			append("%03d", tm->tm_yday); break;
+		case 'k':
+			append("%2d", tm->tm_hour); break;
+		case 'l':
+			append("%2d", TO_12H(tm->tm_hour)); break;
+		case 'm':
+			append("%02d", tm->tm_mon); break;
+		case 'M':
+			append("%02d", tm->tm_min); break;
+		case 'n':
+			append("\n"); break;
+		case 'p':
+			append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break;
+		case 'P':
+			append("%s", tm->tm_hour < 12 ? "am" : "PM"); break;
+		case 'r':
+			recurse("%I:%M:%S %p"); break;
+		case 'R':
+			recurse("%H:%M"); break;
+		case 's':
+			append("%ld", _secs_since_epoch(tm)); break;
+		case 'S':
+			append("%02d", tm->tm_sec); break;
+		case 't':
+			append("\t"); break;
+		case 'T':
+			recurse("%H:%M:%S"); break;
+		case 'u':
+			append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
+			break;
+		case 'U':
+			append("%02d", _sun_week_number(tm)); break;
+		case 'V':
+			append("%02d", _iso_week_number(tm)); break;
+		case 'w':
+			append("%d", tm->tm_wday); break;
+		case 'W':
+			append("%02d", _mon_week_number(tm)); break;
+		case 'x':
+			// TODO: locale-specific date format
+			recurse("%Y-%m-%d"); break;
+		case 'X':
+			// TODO: locale-specific time format
+			recurse("%H:%M:%S"); break;
+		case 'y':
+			append("%02d", tm->tm_year % 100); break;
+		case 'Y':
+			append("%d", 1900 + tm->tm_year); break;
+		case 'z':
+			// TODO: timezone
+			break;
+		case 'Z':
+			// TODO: timezone
+			break;
+		case '%':
+			append("%%");
+			break;
+		default:
+			/* Invalid specifier, print verbatim. */
+			while (*format != '%') {
+				format--;
+			}
+			append("%%");
+			break;
+		}
+		format++;
+	}
+	
+	#undef append
+	#undef recurse
+	
+	return maxsize - remaining;
+}
+
+
+/** Converts a time value to a broken-down UTC time
+ *
+ * @param time    Time to convert
+ * @param result  Structure to store the result to
+ *
+ * @return        EOK or a negative error code
+ */
+int time_utc2tm(const time_t time, struct tm *restrict result)
+{
+	assert(result != NULL);
+
+	/* Set result to epoch. */
+	result->tm_sec = 0;
+	result->tm_min = 0;
+	result->tm_hour = 0;
+	result->tm_mday = 1;
+	result->tm_mon = 0;
+	result->tm_year = 70; /* 1970 */
+
+	if (_normalize_time(result, time) == -1)
+		return EOVERFLOW;
+
+	return EOK;
+}
+
+/** Converts a time value to a null terminated string of the form
+ *  "Wed Jun 30 21:49:08 1993\n" expressed in UTC.
+ *
+ * @param time   Time to convert.
+ * @param buf    Buffer to store the string to, must be at least
+ *               ASCTIME_BUF_LEN bytes long.
+ *
+ * @return       EOK or a negative error code.
+ */
+int time_utc2str(const time_t time, char *restrict buf)
+{
+	struct tm t;
+	int r;
+
+	if ((r = time_utc2tm(time, &t)) != EOK)
+		return r;
+
+	time_tm2str(&t, buf);
+	return EOK;
+}
+
+
+/**
+ * Converts broken-down time to a string in format
+ * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
+ *
+ * @param timeptr Broken-down time structure.
+ * @param buf     Buffer to store string to, must be at least ASCTIME_BUF_LEN
+ *                bytes long.
+ */
+void time_tm2str(const struct tm *restrict timeptr, char *restrict buf)
+{
+	assert(timeptr != NULL);
+	assert(buf != NULL);
+
+	static const char *wday[] = {
+		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+	};
+	static const char *mon[] = {
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+	};
+
+	snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n",
+	    wday[timeptr->tm_wday],
+	    mon[timeptr->tm_mon],
+	    timeptr->tm_mday, timeptr->tm_hour,
+	    timeptr->tm_min, timeptr->tm_sec,
+	    1900 + timeptr->tm_year);
+}
+
+/**
+ * Converts a time value to a broken-down local time, expressed relative
+ * to the user's specified timezone.
+ *
+ * @param timer     Time to convert.
+ * @param result    Structure to store the result to.
+ *
+ * @return          EOK on success or a negative error code.
+ */
+int time_local2tm(const time_t time, struct tm *restrict result)
+{
+	// TODO: deal with timezone
+	// currently assumes system and all times are in GMT
+
+	/* Set result to epoch. */
+	result->tm_sec = 0;
+	result->tm_min = 0;
+	result->tm_hour = 0;
+	result->tm_mday = 1;
+	result->tm_mon = 0;
+	result->tm_year = 70; /* 1970 */
+
+	if (_normalize_time(result, time) == -1)
+		return EOVERFLOW;
+
+	return EOK;
+}
+
+/**
+ * Converts the calendar time to a null terminated string
+ * of the form "Wed Jun 30 21:49:08 1993\n" expressed relative to the
+ * user's specified timezone.
+ * 
+ * @param timer  Time to convert.
+ * @param buf    Buffer to store the string to. Must be at least
+ *               ASCTIME_BUF_LEN bytes long.
+ *
+ * @return       EOK on success or a negative error code.
+ */
+int time_local2str(const time_t time, char *buf)
+{
+	struct tm loctime;
+	int r;
+
+	if ((r = time_local2tm(time, &loctime)) != EOK)
+		return r;
+
+	time_tm2str(&loctime, buf);
+
+	return EOK;
+}
+
+/**
+ * Calculate the difference between two times, in seconds.
+ * 
+ * @param time1 First time.
+ * @param time0 Second time.
+ * @return Time in seconds.
+ */
+double difftime(time_t time1, time_t time0)
+{
+	return (double) (time1 - time0);
+}
+
 /** @}
  */
Index: uspace/lib/c/generic/tls.c
===================================================================
--- uspace/lib/c/generic/tls.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/generic/tls.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -42,4 +42,5 @@
 #include <str.h>
 #include <align.h>
+#include <unistd.h>
 
 /** Create TLS (Thread Local Storage) data structures.
@@ -57,4 +58,6 @@
 	
 	tcb = __alloc_tls(&data, tls_size);
+	if (!tcb)
+		return NULL;
 	
 	/*
@@ -89,5 +92,8 @@
 
 	result = malloc(sizeof(tcb_t) + size);
+	if (!result)
+		return NULL;
 	*data = ((void *)result) + sizeof(tcb_t);
+
 	return result;
 }
@@ -118,5 +124,6 @@
 	size = ALIGN_UP(size, &_tls_alignment);
 	*data = memalign((uintptr_t) &_tls_alignment, sizeof(tcb_t) + size);
-
+	if (!*data)
+		return NULL;
 	tcb = (tcb_t *) (*data + size);
 	tcb->self = tcb;
Index: uspace/lib/c/include/device/battery_dev.h
===================================================================
--- uspace/lib/c/include/device/battery_dev.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/include/device/battery_dev.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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_DEVICE_BATTERY_DEV_H_
+#define LIBC_DEVICE_BATTERY_DEV_H_
+
+#include <async.h>
+
+typedef enum {
+	BATTERY_OK,
+	BATTERY_LOW,
+	BATTERY_NOT_PRESENT,
+} battery_status_t;
+
+typedef enum {
+	BATTERY_STATUS_GET = 0,
+	BATTERY_CHARGE_LEVEL_GET,
+} battery_dev_method_t;
+
+extern int battery_status_get(async_sess_t *, battery_status_t *);
+extern int battery_charge_level_get(async_sess_t *, int *);
+
+#endif
+
Index: uspace/lib/c/include/device/clock_dev.h
===================================================================
--- uspace/lib/c/include/device/clock_dev.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/include/device/clock_dev.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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_DEVICE_CLOCK_DEV_H_
+#define LIBC_DEVICE_CLOCK_DEV_H_
+
+#include <async.h>
+#include <time.h>
+
+typedef enum {
+	CLOCK_DEV_TIME_GET = 0,
+	CLOCK_DEV_TIME_SET,
+} clock_dev_method_t;
+
+extern int clock_dev_time_get(async_sess_t *, struct tm *);
+extern int clock_dev_time_set(async_sess_t *, struct tm *);
+
+#endif
+
Index: uspace/lib/c/include/double_to_str.h
===================================================================
--- uspace/lib/c/include/double_to_str.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/include/double_to_str.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * 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.
+ */
+
+#ifndef DOUBLE_TO_STR_H_
+#define DOUBLE_TO_STR_H_
+
+#include <unistd.h>
+
+/** Maximum number of digits double_to_*_str conversion functions produce. 
+ *
+ * Both double_to_short_str and double_to_fixed_str generate digits out
+ * of a 64bit unsigned int number representation. The max number of 
+ * of digits is therefore 20. Add 1 to help users who forget to reserve
+ * space for a null terminator.
+ */
+#define MAX_DOUBLE_STR_LEN (20 + 1)
+
+/** Maximum buffer size needed to store the output of double_to_*_str 
+ *  functions. 
+ */
+#define MAX_DOUBLE_STR_BUF_SIZE  21
+
+/* Fwd decl.*/
+struct ieee_double_t_tag;
+
+extern int double_to_short_str(struct ieee_double_t_tag, char *, size_t, int *);
+extern int double_to_fixed_str(struct ieee_double_t_tag, int, int, char *,
+    size_t, int *);
+
+#endif 
Index: uspace/lib/c/include/ieee_double.h
===================================================================
--- uspace/lib/c/include/ieee_double.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/include/ieee_double.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012 Adam Hraska
+ * 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.
+ */
+
+#ifndef IEEE_DOUBLE_H_
+#define IEEE_DOUBLE_H_
+
+#include <stdint.h>
+#include <bool.h>
+
+/** Represents a non-negative floating point number: significand * 2^exponent */
+typedef struct fp_num_t_tag {
+	/** Significand (aka mantissa). */
+	uint64_t significand;
+	/** Binary exponent. */
+	int exponent;
+} fp_num_t;
+
+/** Double number description according to IEEE 754. */
+typedef struct ieee_double_t_tag {
+	/** The number is a NaN or infinity. */
+	bool is_special;
+	/** Not a number. */
+	bool is_nan;
+	bool is_negative;
+	/** The number denoted infinity. */
+	bool is_infinity;
+	/** The number could not be represented as a normalized double. */
+	bool is_denormal;
+	/**
+	 * The predecessor double is closer than the successor. This happens 
+	 * if a normal number is of the form 2^k and it is not the smallest
+	 * normal number. 
+	 */
+	bool is_accuracy_step;
+	/** 
+	 * If !is_special the double's value is:
+	 *   pos_val.significand * 2^pos_val.exponent
+	 */
+	fp_num_t pos_val;
+} ieee_double_t;
+
+extern ieee_double_t extract_ieee_double(double);
+
+#endif
Index: uspace/lib/c/include/io/con_srv.h
===================================================================
--- uspace/lib/c/include/io/con_srv.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/include/io/con_srv.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * 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_CON_SRV_H_
+#define LIBC_CON_SRV_H_
+
+#include <adt/list.h>
+#include <async.h>
+#include <fibril_synch.h>
+#include <io/color.h>
+#include <io/concaps.h>
+#include <io/kbd_event.h>
+#include <io/pixel.h>
+#include <io/style.h>
+#include <bool.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+typedef struct con_ops con_ops_t;
+
+/** Service setup (per sevice) */
+typedef struct {
+	con_ops_t *ops;
+	void *sarg;
+	/** Period to check for abort */
+	suseconds_t abort_timeout;
+	bool aborted;
+} con_srvs_t;
+
+/** Server structure (per client session) */
+typedef struct {
+	con_srvs_t *srvs;
+	async_sess_t *client_sess;
+	void *carg;
+} con_srv_t;
+
+typedef struct con_ops {
+	int (*open)(con_srvs_t *, con_srv_t *);
+	int (*close)(con_srv_t *);
+	int (*read)(con_srv_t *, void *, size_t);
+	int (*write)(con_srv_t *, void *, size_t);
+	void (*sync)(con_srv_t *);
+	void (*clear)(con_srv_t *);
+	void (*set_pos)(con_srv_t *, sysarg_t col, sysarg_t row);
+	int (*get_pos)(con_srv_t *, sysarg_t *, sysarg_t *);
+	int (*get_size)(con_srv_t *, sysarg_t *, sysarg_t *);
+	int (*get_color_cap)(con_srv_t *, console_caps_t *);
+	void (*set_style)(con_srv_t *, console_style_t);
+	void (*set_color)(con_srv_t *, console_color_t, console_color_t,
+	    console_color_attr_t);
+	void (*set_rgb_color)(con_srv_t *, pixel_t, pixel_t);
+	void (*set_cursor_visibility)(con_srv_t *, bool);
+	int (*get_event)(con_srv_t *, kbd_event_t *);
+} con_ops_t;
+
+extern void con_srvs_init(con_srvs_t *);
+
+extern int con_conn(ipc_callid_t, ipc_call_t *, con_srvs_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/concaps.h
===================================================================
--- uspace/lib/c/include/io/concaps.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/include/io/concaps.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * 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 libcipc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_IO_CONCAPS_H_
+#define LIBC_IO_CONCAPS_H_
+
+typedef enum {
+	CONSOLE_CAP_NONE = 0,
+	CONSOLE_CAP_STYLE = 1,
+	CONSOLE_CAP_INDEXED = 2,
+	CONSOLE_CAP_RGB = 4
+} console_caps_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/console.h
===================================================================
--- uspace/lib/c/include/io/console.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/include/io/console.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -37,4 +37,5 @@
 
 #include <sys/time.h>
+#include <io/concaps.h>
 #include <io/kbd_event.h>
 #include <io/keycode.h>
@@ -42,11 +43,4 @@
 #include <bool.h>
 #include <stdio.h>
-
-typedef enum {
-	CONSOLE_CAP_NONE = 0,
-	CONSOLE_CAP_STYLE = 1,
-	CONSOLE_CAP_INDEXED = 2,
-	CONSOLE_CAP_RGB = 4
-} console_caps_t;
 
 /** Console control structure. */
Index: uspace/lib/c/include/io/klog.h
===================================================================
--- uspace/lib/c/include/io/klog.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/include/io/klog.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -38,8 +38,10 @@
 #include <sys/types.h>
 #include <stdarg.h>
+#include <io/verify.h>
 
 extern size_t klog_write(const void *, size_t);
 extern void klog_update(void);
-extern int klog_printf(const char *, ...);
+extern int klog_printf(const char *, ...)
+    PRINTF_ATTRIBUTE(1, 2);
 extern int klog_vprintf(const char *, va_list);
 
Index: uspace/lib/c/include/io/log.h
===================================================================
--- uspace/lib/c/include/io/log.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/include/io/log.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -36,20 +36,46 @@
 
 #include <stdarg.h>
+#include <inttypes.h>
+#include <io/verify.h>
 
+/** Log message level. */
 typedef enum {
+	/** Fatal error, program is not able to recover at all. */
 	LVL_FATAL,
+	/** Serious error but the program can recover from it. */
 	LVL_ERROR,
+	/** Easily recoverable problem. */
 	LVL_WARN,
+	/** Information message that ought to be printed by default. */
 	LVL_NOTE,
+	/** Debugging purpose message. */
 	LVL_DEBUG,
+	/** More detailed debugging message. */
 	LVL_DEBUG2,
-
+	
 	/** For checking range of values */
 	LVL_LIMIT
 } log_level_t;
 
-extern int log_init(const char *, log_level_t);
-extern void log_msg(log_level_t, const char *, ...);
-extern void log_msgv(log_level_t, const char *, va_list);
+/** Log itself (logging target). */
+typedef sysarg_t log_t;
+/** Formatting directive for printing log_t. */
+#define PRIlogctx PRIxn
+
+/** Default log (target). */
+#define LOG_DEFAULT ((log_t) -1)
+
+/** Use when creating new top-level log. */
+#define LOG_NO_PARENT ((log_t) 0)
+
+extern const char *log_level_str(log_level_t);
+extern int log_level_from_str(const char *, log_level_t *);
+
+extern int log_init(const char *);
+extern log_t log_create(const char *, log_t);
+
+extern void log_msg(log_t, log_level_t, const char *, ...)
+    PRINTF_ATTRIBUTE(3, 4);
+extern void log_msgv(log_t, log_level_t, const char *, va_list);
 
 #endif
Index: uspace/lib/c/include/io/logctl.h
===================================================================
--- uspace/lib/c/include/io/logctl.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/include/io/logctl.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011-2012 Vojtech Horky
+ * 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
+ * @{
+ */
+
+#ifndef LIBC_IO_LOGCTL_H_
+#define LIBC_IO_LOGCTL_H_
+
+#include <io/log.h>
+
+extern int logctl_set_default_level(log_level_t);
+extern int logctl_set_log_level(const char *, log_level_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/verify.h
===================================================================
--- uspace/lib/c/include/io/verify.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/include/io/verify.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_IO_VERIFY_H_
+#define LIBC_IO_VERIFY_H_
+
+#ifndef NVERIFY_PRINTF
+
+#define PRINTF_ATTRIBUTE(start, end) \
+	__attribute__((format(gnu_printf, start, end)))
+
+#else /* NVERIFY_PRINTF */
+
+#define PRINTF_ATTRIBUTE(start, end)
+
+#endif /* NVERIFY_PRINTF */
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/console.h
===================================================================
--- uspace/lib/c/include/ipc/console.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/include/ipc/console.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -43,10 +43,10 @@
 	CONSOLE_GET_EVENT,
 	CONSOLE_GET_POS,
-	CONSOLE_GOTO,
+	CONSOLE_SET_POS,
 	CONSOLE_CLEAR,
 	CONSOLE_SET_STYLE,
 	CONSOLE_SET_COLOR,
 	CONSOLE_SET_RGB_COLOR,
-	CONSOLE_CURSOR_VISIBILITY
+	CONSOLE_SET_CURSOR_VISIBILITY
 } console_request_t;
 
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -54,4 +54,8 @@
 	/** Interface provided by USB HID devices. */
 	USBHID_DEV_IFACE,
+	/** Interface provided by Real Time Clock devices */
+	CLOCK_DEV_IFACE,
+	/** Interface provided by battery powered devices */
+	BATTERY_DEV_IFACE,
 	/** Interface provided by AHCI devices. */
 	AHCI_DEV_IFACE,
Index: uspace/lib/c/include/ipc/logger.h
===================================================================
--- uspace/lib/c/include/ipc/logger.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/c/include/ipc/logger.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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
+ * @{
+ */
+
+#ifndef LIBC_IPC_LOGGER_H_
+#define LIBC_IPC_LOGGER_H_
+
+#include <ipc/common.h>
+
+typedef enum {
+	/** Set (global) default displayed logging level.
+	 *
+	 * Arguments: new log level.
+	 * Returns: error code
+	 */
+	LOGGER_CONTROL_SET_DEFAULT_LEVEL = IPC_FIRST_USER_METHOD,
+	/** Set displayed level for given log.
+	 *
+	 * Arguments: new log level.
+	 * Returns: error code
+	 * Followed by: string with full log name.
+	 */
+	LOGGER_CONTROL_SET_LOG_LEVEL
+} logger_control_request_t;
+
+typedef enum {
+	/** Create new log.
+	 *
+	 * Arguments: parent log id (0 for top-level log).
+	 * Returns: error code, log id
+	 * Followed by: string with log name.
+	 */
+	LOGGER_WRITER_CREATE_LOG = IPC_FIRST_USER_METHOD,
+	/** Write a message to a given log.
+	 *
+	 * Arguments: log id, message severity level (log_level_t)
+	 * Returns: error code
+	 * Followed by: string with the message.
+	 */
+	LOGGER_WRITER_MESSAGE
+} logger_writer_request_t;
+
+typedef enum {
+	/** Interface for controlling logger behavior. */
+	LOGGER_INTERFACE_CONTROL,
+	/** Interface for servers writing to the log. */
+	LOGGER_INTERFACE_WRITER
+} logger_interface_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/services.h
===================================================================
--- uspace/lib/c/include/ipc/services.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/include/ipc/services.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -45,4 +45,5 @@
 	SERVICE_VFS        = FOURCC('v', 'f', 's', ' '),
 	SERVICE_LOC        = FOURCC('l', 'o', 'c', ' '),
+	SERVICE_LOGGER     = FOURCC('l', 'o', 'g', 'g'),
 	SERVICE_DEVMAN     = FOURCC('d', 'e', 'v', 'n'),
 	SERVICE_IRC        = FOURCC('i', 'r', 'c', ' '),
Index: uspace/lib/c/include/macros.h
===================================================================
--- uspace/lib/c/include/macros.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/include/macros.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -38,4 +38,6 @@
 #define min(a, b)  ((a) < (b) ? (a) : (b))
 #define max(a, b)  ((a) > (b) ? (a) : (b))
+#define abs(a)     ((a) >= 0 ? (a) : (-a))
+
 
 #define KiB2SIZE(kb)  ((kb) << 10)
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/include/stdio.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -39,15 +39,5 @@
 #include <stdarg.h>
 #include <str.h>
-
-#ifndef NVERIFY_PRINTF
-
-#define PRINTF_ATTRIBUTE(start, end) \
-	__attribute__((format(gnu_printf, start, end)))
-
-#else /* NVERIFY_PRINTF */
-
-#define PRINTF_ATTRIBUTE(start, end)
-
-#endif /* NVERIFY_PRINTF */
+#include <io/verify.h>
 
 #define EOF  (-1)
Index: uspace/lib/c/include/sys/time.h
===================================================================
--- uspace/lib/c/include/sys/time.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/c/include/sys/time.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -1,4 +1,6 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
  * All rights reserved.
  *
@@ -39,4 +41,5 @@
 
 #define DST_NONE 0
+#define ASCTIME_BUF_LEN 26
 
 typedef long time_t;
@@ -45,4 +48,16 @@
 typedef uint32_t useconds_t;
 typedef uint32_t mseconds_t;
+
+struct tm {
+	int tm_sec;         /* Seconds [0,60]. */
+	int tm_min;         /* Minutes [0,59]. */
+	int tm_hour;        /* Hour [0,23]. */
+	int tm_mday;        /* Day of month [1,31]. */
+	int tm_mon;         /* Month of year [0,11]. */
+	int tm_year;        /* Years since 1900. */
+	int tm_wday;        /* Day of week [0,6] (Sunday = 0). */
+	int tm_yday;        /* Day of year [0,365]. */
+	int tm_isdst;       /* Daylight Savings flag. */
+};
 
 struct timeval {
@@ -61,6 +76,17 @@
 extern int tv_gteq(struct timeval *tv1, struct timeval *tv2);
 extern int gettimeofday(struct timeval *tv, struct timezone *tz);
+extern int getuptime(struct timeval *tv);
 
 extern void udelay(useconds_t);
+
+extern time_t mktime(struct tm *tm);
+extern int time_utc2tm(const time_t time, struct tm *result);
+extern int time_utc2str(const time_t time, char *buf);
+extern void time_tm2str(const struct tm *timeptr, char *buf);
+extern int time_local2tm(const time_t time, struct tm *result);
+extern int time_local2str(const time_t time, char *buf);
+extern double difftime(time_t time1, time_t time0);
+extern size_t strftime(char *restrict s, size_t maxsize,
+    const char *restrict format, const struct tm *restrict tm);
 
 #endif
Index: uspace/lib/clui/tinput.c
===================================================================
--- uspace/lib/clui/tinput.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/clui/tinput.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -104,5 +104,7 @@
 static void tinput_display_tail(tinput_t *ti, size_t start, size_t pad)
 {
-	wchar_t dbuf[INPUT_MAX_SIZE + 1];
+	wchar_t *dbuf = malloc((INPUT_MAX_SIZE + 1) * sizeof(wchar_t));
+	if (!dbuf)
+		return;	
 	
 	size_t sa;
@@ -146,4 +148,6 @@
 	
 	console_flush(ti->console);
+
+	free(dbuf);
 }
 
Index: uspace/lib/draw/surface.c
===================================================================
--- uspace/lib/draw/surface.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/draw/surface.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -44,14 +44,14 @@
 	surface_flags_t flags;
 
-	sysarg_t dirty_x_lo;
-	sysarg_t dirty_x_hi;
-	sysarg_t dirty_y_lo;
-	sysarg_t dirty_y_hi;
+	surface_coord_t dirty_x_lo;
+	surface_coord_t dirty_x_hi;
+	surface_coord_t dirty_y_lo;
+	surface_coord_t dirty_y_hi;
 
 	pixelmap_t pixmap;
 };
 
-surface_t *surface_create(
-    sysarg_t width, sysarg_t height, pixel_t *pixbuf, surface_flags_t flags)
+surface_t *surface_create(surface_coord_t width, surface_coord_t height,
+    pixel_t *pixbuf, surface_flags_t flags)
 {
 	surface_t *surface = (surface_t *) malloc(sizeof(surface_t));
@@ -118,5 +118,5 @@
 }
 
-void surface_get_resolution(surface_t *surface, sysarg_t *width, sysarg_t *height)
+void surface_get_resolution(surface_t *surface, surface_coord_t *width, surface_coord_t *height)
 {
 	assert(width);
@@ -127,6 +127,6 @@
 }
 
-void surface_get_damaged_region(surface_t *surface, sysarg_t *x, sysarg_t *y,
-    sysarg_t *width, sysarg_t *height)
+void surface_get_damaged_region(surface_t *surface, surface_coord_t *x, surface_coord_t *y,
+    surface_coord_t *width, surface_coord_t *height)
 {
 	assert(x);
@@ -151,5 +151,5 @@
 }
 
-void surface_put_pixel(surface_t *surface, sysarg_t x, sysarg_t y, pixel_t pixel)
+void surface_put_pixel(surface_t *surface, surface_coord_t x, surface_coord_t y, pixel_t pixel)
 {
 	surface->dirty_x_lo = surface->dirty_x_lo > x ? x : surface->dirty_x_lo;
@@ -163,5 +163,5 @@
 }
 
-pixel_t surface_get_pixel(surface_t *surface, sysarg_t x, sysarg_t y)
+pixel_t surface_get_pixel(surface_t *surface, surface_coord_t x, surface_coord_t y)
 {
 	if (x < surface->pixmap.width && y < surface->pixmap.height) {
Index: uspace/lib/draw/surface.h
===================================================================
--- uspace/lib/draw/surface.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/draw/surface.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -45,4 +45,6 @@
 typedef struct surface surface_t;
 
+typedef sysarg_t surface_coord_t;
+
 typedef enum {
 	SURFACE_FLAG_NONE = 0,
@@ -50,5 +52,5 @@
 } surface_flags_t;
 
-extern surface_t *surface_create(sysarg_t, sysarg_t, pixel_t *, surface_flags_t);
+extern surface_t *surface_create(surface_coord_t, surface_coord_t, pixel_t *, surface_flags_t);
 extern void surface_destroy(surface_t *);
 
@@ -56,11 +58,11 @@
 extern pixel_t *surface_direct_access(surface_t *);
 extern pixelmap_t *surface_pixmap_access(surface_t *);
-extern void surface_get_resolution(surface_t *, sysarg_t *, sysarg_t *);
-extern void surface_get_damaged_region(surface_t *, sysarg_t *, sysarg_t *,
-    sysarg_t *, sysarg_t *);
+extern void surface_get_resolution(surface_t *, surface_coord_t *, surface_coord_t *);
+extern void surface_get_damaged_region(surface_t *, surface_coord_t *, surface_coord_t *,
+    surface_coord_t *, surface_coord_t *);
 extern void surface_reset_damaged_region(surface_t *);
 
-extern void surface_put_pixel(surface_t *, sysarg_t, sysarg_t, pixel_t);
-extern pixel_t surface_get_pixel(surface_t *, sysarg_t, sysarg_t);
+extern void surface_put_pixel(surface_t *, surface_coord_t, surface_coord_t, pixel_t);
+extern pixel_t surface_get_pixel(surface_t *, surface_coord_t, surface_coord_t);
 
 #endif
Index: uspace/lib/drv/Makefile
===================================================================
--- uspace/lib/drv/Makefile	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/drv/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -46,4 +46,6 @@
 	generic/remote_usbhc.c \
 	generic/remote_usbhid.c \
+	generic/remote_clock_dev.c \
+	generic/remote_battery_dev.c \
 	generic/remote_ahci.c
 
Index: uspace/lib/drv/generic/dev_iface.c
===================================================================
--- uspace/lib/drv/generic/dev_iface.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/drv/generic/dev_iface.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -41,4 +41,6 @@
 #include "remote_hw_res.h"
 #include "remote_char_dev.h"
+#include "remote_clock_dev.h"
+#include "remote_battery_dev.h"
 #include "remote_graph_dev.h"
 #include "remote_nic.h"
@@ -59,4 +61,6 @@
 		&remote_usbhc_iface,
 		&remote_usbhid_iface,
+		&remote_clock_dev_iface,
+		&remote_battery_dev_iface,
 		&remote_ahci_iface
 	}
Index: uspace/lib/drv/generic/log.c
===================================================================
--- uspace/lib/drv/generic/log.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/drv/generic/log.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -38,10 +38,9 @@
  *
  * @param drv_name Driver name, will be printed as part of message
- * @param level    Minimum message level to print
  *
  */
-int ddf_log_init(const char *drv_name, log_level_t level)
+int ddf_log_init(const char *drv_name)
 {
-	return log_init(drv_name, level);
+	return log_init(drv_name);
 }
 
@@ -59,5 +58,5 @@
 	
 	va_start(args, fmt);
-	log_msgv(level, fmt, args);
+	log_msgv(LOG_DEFAULT, level, fmt, args);
 	va_end(args);
 }
Index: uspace/lib/drv/generic/remote_battery_dev.c
===================================================================
--- uspace/lib/drv/generic/remote_battery_dev.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/drv/generic/remote_battery_dev.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <ops/battery_dev.h>
+#include <device/battery_dev.h>
+#include <ddf/driver.h>
+
+static void remote_battery_status_get(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+static void remote_battery_charge_level_get(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+
+/** Remote battery interface operations */
+static remote_iface_func_ptr_t remote_battery_dev_iface_ops[] = {
+	&remote_battery_status_get,
+	&remote_battery_charge_level_get,
+};
+
+/** Remote battery interface structure
+ *
+ * Interface for processing request from remote clients
+ * addressed by the battery interface.
+ *
+ */
+remote_iface_t remote_battery_dev_iface = {
+	.method_count = sizeof(remote_battery_dev_iface_ops) /
+	    sizeof(remote_iface_func_ptr_t),
+	.methods = remote_battery_dev_iface_ops,
+};
+
+/** Process the status_get() request from the remote client
+ *
+ * @param fun    The function from which the battery status is read
+ * @param ops    The local ops structure
+ */
+static void
+remote_battery_status_get(ddf_fun_t *fun, void *ops, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	const battery_dev_ops_t *bops = (battery_dev_ops_t *) ops;
+
+	if (bops->battery_status_get == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	battery_status_t batt_status;
+	const int rc = bops->battery_status_get(fun, &batt_status);
+
+	if (rc != EOK)
+		async_answer_0(callid, rc);
+	else
+		async_answer_1(callid, rc, batt_status);
+}
+
+/** Process the battery_charge_level_get() request from the remote client
+ *
+ * @param fun    The function from which the battery charge level is read
+ * @param ops    The local ops structure
+ *
+ */
+static void
+remote_battery_charge_level_get(ddf_fun_t *fun, void *ops, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	const battery_dev_ops_t *bops = (battery_dev_ops_t *) ops;
+
+	if (bops->battery_charge_level_get == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	int battery_level;
+	const int rc = bops->battery_charge_level_get(fun, &battery_level);
+
+	if (rc != EOK)
+		async_answer_0(callid, rc);
+	else
+		async_answer_1(callid, rc, battery_level);
+}
+
Index: uspace/lib/drv/generic/remote_clock_dev.c
===================================================================
--- uspace/lib/drv/generic/remote_clock_dev.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/drv/generic/remote_clock_dev.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <time.h>
+
+#include <ops/clock_dev.h>
+#include <ddf/driver.h>
+
+static void remote_clock_time_get(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+static void remote_clock_time_set(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+
+/** Remote clock interface operations */
+static remote_iface_func_ptr_t remote_clock_dev_iface_ops[] = {
+	&remote_clock_time_get,
+	&remote_clock_time_set,
+};
+
+/** Remote clock interface structure
+ *
+ * Interface for processing requests from remote clients
+ * addressed by the clock interface.
+ */
+remote_iface_t remote_clock_dev_iface = {
+	.method_count = sizeof(remote_clock_dev_iface_ops) /
+	    sizeof(remote_iface_func_ptr_t),
+	.methods = remote_clock_dev_iface_ops,
+};
+
+/** Process the time_get() request from the remote client
+ *
+ * @param fun   The function from which the time is read
+ * @param ops   The local ops structure
+ */
+static void
+remote_clock_time_get(ddf_fun_t *fun, void *ops, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	clock_dev_ops_t *clock_dev_ops = (clock_dev_ops_t *) ops;
+	ipc_callid_t cid;
+	struct tm t;
+	int rc;
+	size_t len;
+
+	if (!async_data_read_receive(&cid, &len)) {
+		/* TODO: Handle protocol error */
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	if (!clock_dev_ops->time_get) {
+		/* The driver does not provide the time_get() functionality */
+		async_answer_0(cid, ENOTSUP);
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = (*clock_dev_ops->time_get)(fun, &t);
+
+	if (rc != EOK) {
+		/* Some error occurred */
+		async_answer_0(cid, rc);
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	/* The operation was successful */
+	async_data_read_finalize(cid, &t, sizeof(struct tm));
+	async_answer_0(callid, rc);
+}
+
+/** Process the time_set() request from the remote client
+ *
+ * @param fun   The function to which the data are written
+ * @param ops   The local ops structure
+ */
+static void remote_clock_time_set(ddf_fun_t *fun, void *ops,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	clock_dev_ops_t *clock_dev_ops = (clock_dev_ops_t *) ops;
+	int          rc;
+	struct tm    t;
+	ipc_callid_t cid;
+	size_t       len;
+
+	if (!async_data_write_receive(&cid, &len)) {
+		/* TODO: Handle protocol error */
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	if (!clock_dev_ops->time_set) {
+		/* The driver does not support the time_set() functionality */
+		async_answer_0(cid, ENOTSUP);
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	async_data_write_finalize(cid, &t, sizeof(struct tm));
+
+	rc = (*clock_dev_ops->time_set)(fun, &t);
+
+	async_answer_0(callid, rc);
+}
+
+/**
+ * @}
+ */
+
Index: uspace/lib/drv/include/ddf/log.h
===================================================================
--- uspace/lib/drv/include/ddf/log.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/drv/include/ddf/log.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -35,7 +35,9 @@
 
 #include <io/log.h>
+#include <io/verify.h>
 
-extern int ddf_log_init(const char *, log_level_t);
-extern void ddf_msg(log_level_t, const char *, ...);
+extern int ddf_log_init(const char *);
+extern void ddf_msg(log_level_t, const char *, ...)
+    PRINTF_ATTRIBUTE(2, 3);
 
 extern void ddf_dump_buffer(char *, size_t, const void *, size_t, size_t,
Index: uspace/lib/drv/include/ops/battery_dev.h
===================================================================
--- uspace/lib/drv/include/ops/battery_dev.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/drv/include/ops/battery_dev.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_OPS_BATTERY_DEV_H_
+#define LIBDRV_OPS_BATTERY_DEV_H_
+
+#include "../ddf/driver.h"
+#include "device/battery_dev.h"
+
+typedef struct {
+	int (*battery_status_get)(ddf_fun_t *, battery_status_t *);
+	int (*battery_charge_level_get)(ddf_fun_t *, int *);
+} battery_dev_ops_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/ops/clock_dev.h
===================================================================
--- uspace/lib/drv/include/ops/clock_dev.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/drv/include/ops/clock_dev.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_OPS_CLOCK_DEV_H_
+#define LIBDRV_OPS_CLOCK_DEV_H_
+
+#include <time.h>
+#include "../ddf/driver.h"
+
+typedef struct {
+	int (*time_get)(ddf_fun_t *, struct tm *);
+	int (*time_set)(ddf_fun_t *, struct tm *);
+} clock_dev_ops_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/remote_battery_dev.h
===================================================================
--- uspace/lib/drv/include/remote_battery_dev.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/drv/include/remote_battery_dev.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_BATTERY_DEV_H_
+#define LIBDRV_REMOTE_BATTERY_DEV_H_
+
+extern remote_iface_t remote_battery_dev_iface;
+
+#endif
+
+/**
+ * @}
+ */
+
Index: uspace/lib/drv/include/remote_clock_dev.h
===================================================================
--- uspace/lib/drv/include/remote_clock_dev.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/drv/include/remote_clock_dev.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_CLOCK_DEV_H_
+#define LIBDRV_REMOTE_CLOCK_DEV_H_
+
+extern remote_iface_t remote_clock_dev_iface;
+
+#endif
+
+/**
+ * @}
+ */
+
Index: uspace/lib/ext4/libext4_crc.c
===================================================================
--- uspace/lib/ext4/libext4_crc.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/ext4/libext4_crc.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -33,78 +33,12 @@
 /**
  * @file  libext4_crc.c
- * @brief CRC checksumming implementation from Linux.
  */
 
-#include <byteorder.h>
 #include "libext4.h"
 
-/** CRC table for the CRC-16.
- *
- * The poly is 0x8005 (x^16 + x^15 + x^2 + 1).
- *
- */
-uint16_t const crc16_table[256] = {
-	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
-	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
-	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
-	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
-	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
-	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
-	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
-	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
-	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
-	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
-	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
-	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
-	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
-	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
-	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
-	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
-	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
-	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
-	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
-	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
-	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
-	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
-	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
-	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
-	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
-	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
-	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
-	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
-	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
-	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
-	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
-	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
-};
-
-/** Modify CRC value.
- *
- * @param crc   Current CRC value
- * @param data  New byte of data to be "added" to CRC
- *
- * @return Updated CRC value
- *
- */
-static inline uint16_t crc16_byte(uint16_t crc, const uint8_t data)
-{
-	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
-}
-
-/** Compute the CRC-16 for the data buffer.
- *
- * @param crc    Previous CRC value
- * @param buffer Data pointer
- * @param len    Number of bytes in the buffer
- *
- * @return Updated CRC value
- *
- */
 uint16_t crc16(uint16_t crc, const uint8_t *buffer, size_t len)
 {
-	while (len--)
-		crc = crc16_byte(crc, *buffer++);
-	
-	return crc;
+	// TODO
+	return 0;
 }
 
Index: uspace/lib/ext4/libext4_filesystem.c
===================================================================
--- uspace/lib/ext4/libext4_filesystem.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/ext4/libext4_filesystem.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -471,6 +471,4 @@
 
 /** Compute checksum of block group descriptor.
- *
- * It uses crc functions from Linux kernel implementation.
  *
  * @param sb   Superblock
@@ -1284,4 +1282,9 @@
 	block_t *block;
 	while (level > 0) {
+		
+		/* Sparse check */
+		if (current_block == 0)
+			return EOK;
+		
 		int rc = block_get(&block, fs->device, current_block, 0);
 		if (rc != EOK)
Index: uspace/lib/ext4/libext4_hash.c
===================================================================
--- uspace/lib/ext4/libext4_hash.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/ext4/libext4_hash.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -35,285 +35,12 @@
  */
 
+#include "libext4.h"
 #include <errno.h>
-#include <mem.h>
-#include "libext4.h"
 
-#define TEA_DELTA  0x9E3779B9
-
-/* F, G and H are basic MD4 functions: selection, majority, parity */
-#define F(x, y, z)  ((z) ^ ((x) & ((y) ^ (z))))
-#define G(x, y, z)  (((x) & (y)) + (((x) ^ (y)) & (z)))
-#define H(x, y, z)  ((x) ^ (y) ^ (z))
-
-/*
- * The generic round function.  The application is so specific that
- * we don't bother protecting all the arguments with parens, as is generally
- * good macro practice, in favor of extra legibility.
- * Rotation is separate from addition to prevent recomputation
- */
-#define ROUND(f, a, b, c, d, x, s) \
-	(a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s)))
-
-#define K1  0
-#define K2  013240474631UL
-#define K3  015666365641UL
-
-static void tea_transform(uint32_t buf[4], uint32_t const in[])
-{
-	uint32_t sum = 0;
-	uint32_t b0 = buf[0];
-	uint32_t b1 = buf[1];
-	uint32_t a = in[0];
-	uint32_t b = in[1];
-	uint32_t c = in[2];
-	uint32_t d = in[3];
-	
-	int n = 16;
-	
-	do {
-		sum += TEA_DELTA;
-		b0 += ((b1 << 4) + a) ^ (b1 + sum) ^ ((b1 >> 5) + b);
-		b1 += ((b0 << 4) + c) ^ (b0 + sum) ^ ((b0 >> 5) + d);
-	} while (--n);
-	
-	buf[0] += b0;
-	buf[1] += b1;
-}
-
-
-static void half_md4_transform(uint32_t buf[4], const uint32_t in[8])
-{
-	uint32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3];
-	
-	/* Round 1 */
-	ROUND(F, a, b, c, d, in[0] + K1,  3);
-	ROUND(F, d, a, b, c, in[1] + K1,  7);
-	ROUND(F, c, d, a, b, in[2] + K1, 11);
-	ROUND(F, b, c, d, a, in[3] + K1, 19);
-	ROUND(F, a, b, c, d, in[4] + K1,  3);
-	ROUND(F, d, a, b, c, in[5] + K1,  7);
-	ROUND(F, c, d, a, b, in[6] + K1, 11);
-	ROUND(F, b, c, d, a, in[7] + K1, 19);
-	
-	/* Round 2 */
-	ROUND(G, a, b, c, d, in[1] + K2,  3);
-	ROUND(G, d, a, b, c, in[3] + K2,  5);
-	ROUND(G, c, d, a, b, in[5] + K2,  9);
-	ROUND(G, b, c, d, a, in[7] + K2, 13);
-	ROUND(G, a, b, c, d, in[0] + K2,  3);
-	ROUND(G, d, a, b, c, in[2] + K2,  5);
-	ROUND(G, c, d, a, b, in[4] + K2,  9);
-	ROUND(G, b, c, d, a, in[6] + K2, 13);
-	
-	/* Round 3 */
-	ROUND(H, a, b, c, d, in[3] + K3,  3);
-	ROUND(H, d, a, b, c, in[7] + K3,  9);
-	ROUND(H, c, d, a, b, in[2] + K3, 11);
-	ROUND(H, b, c, d, a, in[6] + K3, 15);
-	ROUND(H, a, b, c, d, in[1] + K3,  3);
-	ROUND(H, d, a, b, c, in[5] + K3,  9);
-	ROUND(H, c, d, a, b, in[0] + K3, 11);
-	ROUND(H, b, c, d, a, in[4] + K3, 15);
-	
-	buf[0] += a;
-	buf[1] += b;
-	buf[2] += c;
-	buf[3] += d;
-}
-
-static uint32_t hash_unsigned(const char *name, int len)
-{
-	uint32_t hash;
-	uint32_t hash0 = 0x12a3fe2d;
-	uint32_t hash1 = 0x37abe8f9;
-	const unsigned char *ucp = (const unsigned char *) name;
-	
-	while (len--) {
-		hash = hash1 + (hash0 ^ (((int) *ucp++) * 7152373));
-		
-		if (hash & 0x80000000)
-			hash -= 0x7fffffff;
-		
-		hash1 = hash0;
-		hash0 = hash;
-	}
-	
-	return hash0 << 1;
-}
-
-static uint32_t hash_signed(const char *name, int len)
-{
-	uint32_t hash;
-	uint32_t hash0 = 0x12a3fe2d;
-	uint32_t hash1 = 0x37abe8f9;
-	const signed char *scp = (const signed char *) name;
-	
-	while (len--) {
-		hash = hash1 + (hash0 ^ (((int) *scp++) * 7152373));
-		
-		if (hash & 0x80000000)
-			hash -= 0x7fffffff;
-		
-		hash1 = hash0;
-		hash0 = hash;
-	}
-	
-	return hash0 << 1;
-}
-
-static void str2hashbuf_signed(const char *msg, int len, uint32_t *buf, int num)
-{
-	uint32_t pad, val;
-	int i;
-	const signed char *scp = (const signed char *) msg;
-	
-	pad = (uint32_t) len | ((uint32_t) len << 8);
-	pad |= pad << 16;
-	
-	val = pad;
-	if (len > num * 4)
-		len = num * 4;
-	
-	for (i = 0; i < len; i++) {
-		if ((i % 4) == 0)
-			val = pad;
-		
-		val = ((int) scp[i]) + (val << 8);
-		if ((i % 4) == 3) {
-			*buf++ = val;
-			val = pad;
-			num--;
-		}
-	}
-	
-	if (--num >= 0)
-		*buf++ = val;
-	
-	while (--num >= 0)
-		*buf++ = pad;
-}
-
-static void str2hashbuf_unsigned(const char *msg, int len, uint32_t *buf,
-    int num)
-{
-	uint32_t pad, val;
-	int i;
-	const unsigned char *ucp = (const unsigned char *) msg;
-	
-	pad = (uint32_t) len | ((uint32_t) len << 8);
-	pad |= pad << 16;
-	
-	val = pad;
-	if (len > num * 4)
-		len = num * 4;
-	
-	for (i = 0; i < len; i++) {
-		if ((i % 4) == 0)
-			val = pad;
-		
-		val = ((int) ucp[i]) + (val << 8);
-		if ((i % 4) == 3) {
-			*buf++ = val;
-			val = pad;
-			num--;
-		}
-	}
-	
-	if (--num >= 0)
-		*buf++ = val;
-	
-	while (--num >= 0)
-		*buf++ = pad;
-}
-
-/** Compute hash value of the string.
- *
- * @param hinfo Hash info structure with information about
- *              the algorithm, hash seed and with the place
- *              for the output hash value
- * @param len  Length of the name
- * @param name Name to be hashed
- *
- * @return Error code
- *
- */
 int ext4_hash_string(ext4_hash_info_t *hinfo, int len, const char *name)
 {
-	uint32_t hash = 0;
-	uint32_t minor_hash = 0;
-	const char *p;
-	int i;
-	uint32_t in[8], buf[4];
-	void (*str2hashbuf)(const char *, int, uint32_t *, int) =
-	    str2hashbuf_signed;
-	
-	/* Initialize the default seed for the hash checksum functions */
-	buf[0] = 0x67452301;
-	buf[1] = 0xefcdab89;
-	buf[2] = 0x98badcfe;
-	buf[3] = 0x10325476;
-	
-	/* Check if the seed is all zero's */
-	if (hinfo->seed) {
-		for (i = 0; i < 4; i++) {
-			if (hinfo->seed[i] != 0)
-				break;
-			
-		}
-		
-		if (i < 4)
-			memcpy(buf, hinfo->seed, sizeof(buf));
-	}
-	
-	switch (hinfo->hash_version) {
-	case EXT4_HASH_VERSION_LEGACY_UNSIGNED:
-		hash = hash_unsigned(name, len);
-		break;
-	case EXT4_HASH_VERSION_LEGACY:
-		hash = hash_signed(name, len);
-		break;
-	case EXT4_HASH_VERSION_HALF_MD4_UNSIGNED:
-		str2hashbuf = str2hashbuf_unsigned;
-	case EXT4_HASH_VERSION_HALF_MD4:
-		p = name;
-		
-		while (len > 0) {
-			(*str2hashbuf)(p, len, in, 8);
-			half_md4_transform(buf, in);
-			len -= 32;
-			p += 32;
-		}
-		
-		minor_hash = buf[2];
-		hash = buf[1];
-		break;
-	case EXT4_HASH_VERSION_TEA_UNSIGNED:
-		str2hashbuf = str2hashbuf_unsigned;
-	case EXT4_HASH_VERSION_TEA:
-		p = name;
-		
-		while (len > 0) {
-			(*str2hashbuf)(p, len, in, 4);
-			tea_transform(buf, in);
-			len -= 16;
-			p += 16;
-		}
-		
-		hash = buf[0];
-		minor_hash = buf[1];
-		break;
-	default:
-		hinfo->hash = 0;
-		return EINVAL;
-	}
-	
-	hash = hash & ~1;
-	if (hash == (EXT4_DIRECTORY_HTREE_EOF << 1))
-		hash = (EXT4_DIRECTORY_HTREE_EOF - 1) << 1;
-	
-	hinfo->hash = hash;
-	hinfo->minor_hash = minor_hash;
-	
-	return EOK;
+	// TODO
+	hinfo->hash = 0;
+	return ENOTSUP;
 }
 
Index: uspace/lib/fs/libfs.c
===================================================================
--- uspace/lib/fs/libfs.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/fs/libfs.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -631,12 +631,7 @@
 						async_answer_0(rid, rc);
 					} else {
-						aoff64_t size = ops->size_get(fn);
-						async_answer_5(rid, fs_handle,
-						    service_id,
-						    ops->index_get(fn),
-						    LOWER32(size),
-						    UPPER32(size),
-						    ops->lnkcnt_get(fn));
-						(void) ops->node_put(fn);
+						(void) ops->node_put(cur);
+						cur = fn;
+						goto out_with_answer;
 					}
 				} else
@@ -715,12 +710,7 @@
 					async_answer_0(rid, rc);
 				} else {
-					aoff64_t size = ops->size_get(fn);
-					async_answer_5(rid, fs_handle,
-					    service_id,
-					    ops->index_get(fn),
-					    LOWER32(size),
-					    UPPER32(size),
-					    ops->lnkcnt_get(fn));
-					(void) ops->node_put(fn);
+					(void) ops->node_put(cur);
+					cur = fn;
+					goto out_with_answer;
 				}
 			} else
Index: uspace/lib/gui/terminal.c
===================================================================
--- uspace/lib/gui/terminal.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/gui/terminal.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -39,6 +39,7 @@
 #include <surface.h>
 #include <gfx/font-8x16.h>
+#include <io/con_srv.h>
+#include <io/concaps.h>
 #include <io/console.h>
-#include <ipc/console.h>
 #include <task.h>
 #include <adt/list.h>
@@ -60,4 +61,44 @@
 
 static LIST_INITIALIZE(terms);
+
+static int term_open(con_srvs_t *, con_srv_t *);
+static int term_close(con_srv_t *);
+static int term_read(con_srv_t *, void *, size_t);
+static int term_write(con_srv_t *, void *, size_t);
+static void term_sync(con_srv_t *);
+static void term_clear(con_srv_t *);
+static void term_set_pos(con_srv_t *, sysarg_t col, sysarg_t row);
+static int term_get_pos(con_srv_t *, sysarg_t *, sysarg_t *);
+static int term_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
+static int term_get_color_cap(con_srv_t *, console_caps_t *);
+static void term_set_style(con_srv_t *, console_style_t);
+static void term_set_color(con_srv_t *, console_color_t, console_color_t,
+    console_color_attr_t);
+static void term_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
+static void term_set_cursor_visibility(con_srv_t *, bool);
+static int term_get_event(con_srv_t *, kbd_event_t *);
+
+static con_ops_t con_ops = {
+	.open = term_open,
+	.close = term_close,
+	.read = term_read,
+	.write = term_write,
+	.sync = term_sync,
+	.clear = term_clear,
+	.set_pos = term_set_pos,
+	.get_pos = term_get_pos,
+	.get_size = term_get_size,
+	.get_color_cap = term_get_color_cap,
+	.set_style = term_set_style,
+	.set_color = term_set_color,
+	.set_rgb_color = term_set_rgb_color,
+	.set_cursor_visibility = term_set_cursor_visibility,
+	.get_event = term_get_event
+};
+
+static terminal_t *srv_to_terminal(con_srv_t *srv)
+{
+	return srv->srvs->sarg;
+}
 
 static void getterm(const char *svc, const char *app)
@@ -341,39 +382,18 @@
 }
 
-static void term_set_cursor(terminal_t *term, sysarg_t col, sysarg_t row)
-{
-	fibril_mutex_lock(&term->mtx);
-	chargrid_set_cursor(term->frontbuf, col, row);
-	fibril_mutex_unlock(&term->mtx);
-	
-	term_update(term);
-}
-
-static void term_set_cursor_visibility(terminal_t *term, bool visible)
-{
-	fibril_mutex_lock(&term->mtx);
-	chargrid_set_cursor_visibility(term->frontbuf, visible);
-	fibril_mutex_unlock(&term->mtx);
-	
-	term_update(term);
-}
-
-static void term_read(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
-{
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_read_receive(&callid, &size)) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	char *buf = (char *) malloc(size);
-	if (buf == NULL) {
-		async_answer_0(callid, ENOMEM);
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
+static int term_open(con_srvs_t *srvs, con_srv_t *srv)
+{
+	return EOK;
+}
+
+static int term_close(con_srv_t *srv)
+{
+	return EOK;
+}
+
+static int term_read(con_srv_t *srv, void *buf, size_t size)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	uint8_t *bbuf = buf;
 	size_t pos = 0;
 	
@@ -386,5 +406,5 @@
 		/* Copy to the buffer remaining characters. */
 		while ((pos < size) && (term->char_remains_len > 0)) {
-			buf[pos] = term->char_remains[0];
+			bbuf[pos] = term->char_remains[0];
 			pos++;
 			
@@ -416,7 +436,5 @@
 	}
 	
-	(void) async_data_read_finalize(callid, buf, size);
-	async_answer_1(iid, EOK, size);
-	free(buf);
+	return size;
 }
 
@@ -449,25 +467,26 @@
 }
 
-static void term_write(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
-{
-	void *buf;
-	size_t size;
-	int rc = async_data_write_accept(&buf, false, 0, 0, 0, &size);
-	
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
+static int term_write(con_srv_t *srv, void *data, size_t size)
+{
+	terminal_t *term = srv_to_terminal(srv);
 	
 	size_t off = 0;
 	while (off < size)
-		term_write_char(term, str_decode(buf, &off, size));
-	
-	async_answer_1(iid, EOK, size);
-	free(buf);
-}
-
-static void term_clear(terminal_t *term)
-{
+		term_write_char(term, str_decode(data, &off, size));
+	
+	return size;
+}
+
+static void term_sync(con_srv_t *srv)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	term_update(term);
+}
+
+static void term_clear(con_srv_t *srv)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
 	fibril_mutex_lock(&term->mtx);
 	chargrid_clear(term->frontbuf);
@@ -477,18 +496,50 @@
 }
 
-static void term_get_cursor(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
-{
-	sysarg_t col;
-	sysarg_t row;
-	
-	fibril_mutex_lock(&term->mtx);
-	chargrid_get_cursor(term->frontbuf, &col, &row);
-	fibril_mutex_unlock(&term->mtx);
-	
-	async_answer_2(iid, EOK, col, row);
-}
-
-static void term_set_style(terminal_t *term, console_style_t style)
-{
+static void term_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	fibril_mutex_lock(&term->mtx);
+	chargrid_set_cursor(term->frontbuf, col, row);
+	fibril_mutex_unlock(&term->mtx);
+	
+	term_update(term);
+}
+
+static int term_get_pos(con_srv_t *srv, sysarg_t *col, sysarg_t *row)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	fibril_mutex_lock(&term->mtx);
+	chargrid_get_cursor(term->frontbuf, col, row);
+	fibril_mutex_unlock(&term->mtx);
+	
+	return EOK;
+}
+
+static int term_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	fibril_mutex_lock(&term->mtx);
+	*cols = term->cols;
+	*rows = term->rows;
+	fibril_mutex_unlock(&term->mtx);
+	
+	return EOK;
+}
+
+static int term_get_color_cap(con_srv_t *srv, console_caps_t *caps)
+{
+	(void) srv;
+	*caps = TERM_CAPS;
+	
+	return EOK;
+}
+
+static void term_set_style(con_srv_t *srv, console_style_t style)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
 	fibril_mutex_lock(&term->mtx);
 	chargrid_set_style(term->frontbuf, style);
@@ -496,7 +547,9 @@
 }
 
-static void term_set_color(terminal_t *term, console_color_t bgcolor,
+static void term_set_color(con_srv_t *srv, console_color_t bgcolor,
     console_color_t fgcolor, console_color_attr_t attr)
 {
+	terminal_t *term = srv_to_terminal(srv);
+	
 	fibril_mutex_lock(&term->mtx);
 	chargrid_set_color(term->frontbuf, bgcolor, fgcolor, attr);
@@ -504,7 +557,9 @@
 }
 
-static void term_set_rgb_color(terminal_t *term, pixel_t bgcolor,
+static void term_set_rgb_color(con_srv_t *srv, pixel_t bgcolor,
     pixel_t fgcolor)
 {
+	terminal_t *term = srv_to_terminal(srv);
+	
 	fibril_mutex_lock(&term->mtx);
 	chargrid_set_rgb_color(term->frontbuf, bgcolor, fgcolor);
@@ -512,11 +567,24 @@
 }
 
-static void term_get_event(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
-{
+static void term_set_cursor_visibility(con_srv_t *srv, bool visible)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	fibril_mutex_lock(&term->mtx);
+	chargrid_set_cursor_visibility(term->frontbuf, visible);
+	fibril_mutex_unlock(&term->mtx);
+	
+	term_update(term);
+}
+
+static int term_get_event(con_srv_t *srv, kbd_event_t *event)
+{
+	terminal_t *term = srv_to_terminal(srv);
 	link_t *link = prodcons_consume(&term->input_pc);
-	kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
-	
-	async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
-	free(event);
+	kbd_event_t *kevent = list_get_instance(link, kbd_event_t, link);
+	
+	*event = *kevent;
+	free(kevent);
+	return EOK;
 }
 
@@ -612,68 +680,7 @@
 	
 	if (atomic_postinc(&term->refcnt) == 0)
-		term_set_cursor_visibility(term, true);
-	
-	/* Accept the connection */
-	async_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			return;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case VFS_OUT_READ:
-			term_read(term, callid, &call);
-			break;
-		case VFS_OUT_WRITE:
-			term_write(term, callid, &call);
-			break;
-		case VFS_OUT_SYNC:
-			term_update(term);
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CLEAR:
-			term_clear(term);
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GOTO:
-			term_set_cursor(term, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GET_POS:
-			term_get_cursor(term, callid, &call);
-			break;
-		case CONSOLE_GET_SIZE:
-			async_answer_2(callid, EOK, term->cols, term->rows);
-			break;
-		case CONSOLE_GET_COLOR_CAP:
-			async_answer_1(callid, EOK, TERM_CAPS);
-			break;
-		case CONSOLE_SET_STYLE:
-			term_set_style(term, IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_SET_COLOR:
-			term_set_color(term, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
-			    IPC_GET_ARG3(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_SET_RGB_COLOR:
-			term_set_rgb_color(term, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CURSOR_VISIBILITY:
-			term_set_cursor_visibility(term, IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GET_EVENT:
-			term_get_event(term, callid, &call);
-			break;
-		default:
-			async_answer_0(callid, EINVAL);
-		}
-	}
+		chargrid_set_cursor_visibility(term->frontbuf, true);
+	
+	con_conn(iid, icall, &term->srvs);
 }
 
@@ -727,4 +734,8 @@
 	
 	async_set_client_connection(term_connection);
+	con_srvs_init(&term->srvs);
+	term->srvs.ops = &con_ops;
+	term->srvs.sarg = term;
+	
 	int rc = loc_server_register(NAME);
 	if (rc != EOK) {
Index: uspace/lib/gui/terminal.h
===================================================================
--- uspace/lib/gui/terminal.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/gui/terminal.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -41,4 +41,5 @@
 #include <font.h>
 #include <io/chargrid.h>
+#include <io/con_srv.h>
 #include <adt/list.h>
 #include <adt/prodcons.h>
@@ -66,4 +67,5 @@
 	
 	service_id_t dsid;
+	con_srvs_t srvs;
 } terminal_t;
 
Index: uspace/lib/nic/src/nic_addr_db.c
===================================================================
--- uspace/lib/nic/src/nic_addr_db.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/nic/src/nic_addr_db.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -107,5 +107,5 @@
 	.key_hash = nic_addr_key_hash,
 	.key_equal = nic_addr_key_equal,
-	.equal = 0,
+	.equal = NULL,
 	.remove_callback = nic_addr_removed
 };
Index: uspace/lib/posix/Makefile
===================================================================
--- uspace/lib/posix/Makefile	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/posix/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -33,5 +33,7 @@
 LSONAME = libposix.so0
 
-INCLUDE_LIBC = ./libc
+EXTRA_CFLAGS = -Iinclude/
+
+INCLUDE_LIBC = ./include/libc
 
 PRE_DEPEND = $(INCLUDE_LIBC)
@@ -39,27 +41,27 @@
 
 SOURCES = \
-	ctype.c \
-	errno.c \
-	fcntl.c \
-	fnmatch.c \
-	getopt.c \
-	locale.c \
-	math.c \
-	pwd.c \
-	signal.c \
-	stdio.c \
-	stdio/scanf.c \
-	stdlib.c \
-	stdlib/strtol.c \
-	stdlib/strtold.c \
-	string.c \
-	strings.c \
-	sys/stat.c \
-	sys/wait.c \
-	time.c \
-	unistd.c
+	source/ctype.c \
+	source/errno.c \
+	source/fcntl.c \
+	source/fnmatch.c \
+	source/getopt.c \
+	source/locale.c \
+	source/math.c \
+	source/pwd.c \
+	source/signal.c \
+	source/stdio.c \
+	source/stdio/scanf.c \
+	source/stdlib.c \
+	source/stdlib/strtol.c \
+	source/stdlib/strtold.c \
+	source/string.c \
+	source/strings.c \
+	source/sys/stat.c \
+	source/sys/wait.c \
+	source/time.c \
+	source/unistd.c
 
 include $(USPACE_PREFIX)/Makefile.common
 
 $(INCLUDE_LIBC): ../c/include
-	ln -s -f -n $^ $@
+	ln -s -f -n ../$^ $@
Index: pace/lib/posix/assert.h
===================================================================
--- uspace/lib/posix/assert.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,48 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Program assertion.
- */
-
-/* NO include guard on purpose. */
-
-#include "libc/assert.h"
-
-#undef assert
-
-#ifndef NDEBUG
-	#define assert(expr) ((expr) ? (void) 0 : assert_abort(#expr, __FILE__, __LINE__))
-#else
-	#define assert(expr) ((void) 0)
-#endif
-
-/** @}
- */
Index: pace/lib/posix/ctype.c
===================================================================
--- uspace/lib/posix/ctype.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,131 +1,0 @@
-/*
- * 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 Character classification.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "ctype.h"
-
-/**
- * Checks whether character is a hexadecimal digit.
- *
- * @param c Character to inspect.
- * @return Non-zero if character match the definition, zero otherwise.
- */
-int posix_isxdigit(int c)
-{
-	return isdigit(c) ||
-	    (c >= 'a' && c <= 'f') ||
-	    (c >= 'A' && c <= 'F');
-}
-
-/**
- * Checks whether character is a word separator.
- *
- * @param c Character to inspect.
- * @return Non-zero if character match the definition, zero otherwise.
- */
-int posix_isblank(int c)
-{
-	return c == ' ' || c == '\t';
-}
-
-/**
- * Checks whether character is a control character.
- *
- * @param c Character to inspect.
- * @return Non-zero if character match the definition, zero otherwise.
- */
-int posix_iscntrl(int c)
-{
-	return c < 0x20 || c == 0x7E;
-}
-
-/**
- * Checks whether character is any printing character except space.
- *
- * @param c Character to inspect.
- * @return Non-zero if character match the definition, zero otherwise.
- */
-int posix_isgraph(int c)
-{
-	return posix_isprint(c) && c != ' ';
-}
-
-/**
- * Checks whether character is a printing character.
- *
- * @param c Character to inspect.
- * @return Non-zero if character match the definition, zero otherwise.
- */
-int posix_isprint(int c)
-{
-	return posix_isascii(c) && !posix_iscntrl(c);
-}
-
-/**
- * Checks whether character is a punctuation.
- *
- * @param c Character to inspect.
- * @return Non-zero if character match the definition, zero otherwise.
- */
-int posix_ispunct(int c)
-{
-	return !isspace(c) && !isalnum(c) && posix_isprint(c);
-}
-
-/**
- * Checks whether character is ASCII. (obsolete)
- *
- * @param c Character to inspect.
- * @return Non-zero if character match the definition, zero otherwise.
- */
-int posix_isascii(int c)
-{
-	return c >= 0 && c < 128;
-}
-
-/**
- * Converts argument to a 7-bit ASCII character. (obsolete)
- *
- * @param c Character to convert.
- * @return Coverted character.
- */
-int posix_toascii(int c)
-{
-	return c & 0x7F;
-}
-
-/** @}
- */
Index: pace/lib/posix/ctype.h
===================================================================
--- uspace/lib/posix/ctype.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,73 +1,0 @@
-/*
- * 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 Character classification.
- */
-
-#ifndef POSIX_CTYPE_H_
-#define POSIX_CTYPE_H_
-
-#include "libc/ctype.h"
-
-/* Classification of Characters */
-extern int posix_isxdigit(int c);
-extern int posix_isblank(int c);
-extern int posix_iscntrl(int c);
-extern int posix_isgraph(int c);
-extern int posix_isprint(int c);
-extern int posix_ispunct(int c);
-
-/* Obsolete Functions and Macros */
-extern int posix_isascii(int c);
-extern int posix_toascii(int c);
-#undef _tolower
-#define _tolower(c) ((c) - 'A' + 'a')
-#undef _toupper
-#define _toupper(c) ((c) - 'a' + 'A')
-
-
-#ifndef LIBPOSIX_INTERNAL
-	#define isxdigit posix_isxdigit
-	#define isblank posix_isblank
-	#define iscntrl posix_iscntrl
-	#define isgraph posix_isgraph
-	#define isprint posix_isprint
-	#define ispunct posix_ispunct
-	
-	#define isascii posix_isascii
-	#define toascii posix_toascii
-#endif
-
-#endif /* POSIX_CTYPE_H_ */
-
-/** @}
- */
Index: pace/lib/posix/errno.c
===================================================================
--- uspace/lib/posix/errno.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,52 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 System error numbers.
- */
-
-#include "errno.h"
-
-#include "stdlib.h"
-#include "libc/fibril.h"
-
-static fibril_local int _posix_errno;
-
-int *__posix_errno(void)
-{
-	if (*__errno() != 0) {
-		_posix_errno = abs(*__errno());
-		*__errno() = 0;
-	}
-	return &_posix_errno;
-}
-
-/** @}
- */
Index: pace/lib/posix/errno.h
===================================================================
--- uspace/lib/posix/errno.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,328 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 System error numbers.
- */
-
-#ifndef POSIX_ERRNO_H_
-#define POSIX_ERRNO_H_
-
-#include "libc/errno.h"
-
-/* IMPORTANT:
- * Since libc uses negative errorcodes, some sort of conversion is necessary to
- * keep POSIX programs and libraries from breaking. This file maps POSIX error
- * codes to absolute values of corresponding libc codes where available, and
- * assigns new code where there is no prior definition in libc.
- *
- * A new errno variable is defined. When accessed, the function first looks at
- * libc errno and iff it is != 0, sets the POSIX errno to absolute value of
- * libc errno. Given that no library function sets errno to 0 and that all
- * POSIX libraries will be used solely by POSIX programs (thus, there only needs
- * to be one way correspondence between errno and posix_errno), this approach
- * should work as expected in most cases and does not require any wrappers for
- * libc routines that would just change errno values.
- *
- * There is no conditioning by LIBPOSIX_INTERNAL for redefinitions of macros.
- * If there is a need to check errno for a value not defined by POSIX, it's
- * necessary to compare errno against abs(ECODE), because there is no
- * redefinition for such error codes.
- *
- * XXX: maybe all HOS error codes should be redefined
- *
- * NOTE: This redefinition is slightly POSIX incompatible, since the
- *  specification requires the macro values to be usable in preprocessing
- *  directives. I don't think that's very important, though.
- */
-
-#undef errno
-#define errno (*__posix_errno())
-
-#include "unistd.h"
-
-extern int *__posix_errno(void);
-
-#define __TOP_ERRNO (-NO_DATA)
-
-enum {
-	POSIX_E2BIG = __TOP_ERRNO + 1,
-	POSIX_EACCES = __TOP_ERRNO + 2,
-	POSIX_EADDRINUSE = -EADDRINUSE,
-	POSIX_EADDRNOTAVAIL = -EADDRNOTAVAIL,
-	POSIX_EAFNOSUPPORT = -EAFNOSUPPORT,
-	POSIX_EAGAIN = -EAGAIN,
-	POSIX_EALREADY = __TOP_ERRNO + 3,
-	POSIX_EBADF = -EBADF,
-	POSIX_EBADMSG = __TOP_ERRNO + 4,
-	POSIX_EBUSY = -EBUSY,
-	POSIX_ECANCELED = __TOP_ERRNO + 5,
-	POSIX_ECHILD = __TOP_ERRNO + 6,
-	POSIX_ECONNABORTED = __TOP_ERRNO + 7,
-	POSIX_ECONNREFUSED = __TOP_ERRNO + 8,
-	POSIX_ECONNRESET = __TOP_ERRNO + 9,
-	POSIX_EDEADLK = __TOP_ERRNO + 10,
-	POSIX_EDESTADDRREQ = -EDESTADDRREQ,
-	POSIX_EDOM = __TOP_ERRNO + 11,
-	POSIX_EDQUOT = __TOP_ERRNO + 12,
-	POSIX_EEXIST = -EEXIST,
-	POSIX_EFAULT = __TOP_ERRNO + 13,
-	POSIX_EFBIG = __TOP_ERRNO + 14,
-	POSIX_EHOSTUNREACH = __TOP_ERRNO + 15,
-	POSIX_EIDRM = __TOP_ERRNO + 16,
-	POSIX_EILSEQ = __TOP_ERRNO + 17,
-	POSIX_EINPROGRESS = -EINPROGRESS,
-	POSIX_EINTR = -EINTR,
-	POSIX_EINVAL = -EINVAL,
-	POSIX_EIO = -EIO,
-	POSIX_EISCONN = __TOP_ERRNO + 18,
-	POSIX_EISDIR = -EISDIR,
-	POSIX_ELOOP = __TOP_ERRNO + 19,
-	POSIX_EMFILE = -EMFILE,
-	POSIX_EMLINK = -EMLINK,
-	POSIX_EMSGSIZE = __TOP_ERRNO + 20,
-	POSIX_EMULTIHOP = __TOP_ERRNO + 21,
-	POSIX_ENAMETOOLONG = -ENAMETOOLONG,
-	POSIX_ENETDOWN = __TOP_ERRNO + 22,
-	POSIX_ENETRESET = __TOP_ERRNO + 23,
-	POSIX_ENETUNREACH = __TOP_ERRNO + 24,
-	POSIX_ENFILE = __TOP_ERRNO + 25,
-	POSIX_ENOBUFS = __TOP_ERRNO + 26,
-	POSIX_ENODATA = -NO_DATA,
-	POSIX_ENODEV = __TOP_ERRNO + 27,
-	POSIX_ENOENT = -ENOENT,
-	POSIX_ENOEXEC = __TOP_ERRNO + 28,
-	POSIX_ENOLCK = __TOP_ERRNO + 29,
-	POSIX_ENOLINK = __TOP_ERRNO + 30,
-	POSIX_ENOMEM = -ENOMEM,
-	POSIX_ENOMSG = __TOP_ERRNO + 31,
-	POSIX_ENOPROTOOPT = __TOP_ERRNO + 32,
-	POSIX_ENOSPC = -ENOSPC,
-	POSIX_ENOSR = __TOP_ERRNO + 33,
-	POSIX_ENOSTR = __TOP_ERRNO + 34,
-	POSIX_ENOSYS = __TOP_ERRNO + 35,
-	POSIX_ENOTCONN = -ENOTCONN,
-	POSIX_ENOTDIR = -ENOTDIR,
-	POSIX_ENOTEMPTY = -ENOTEMPTY,
-	POSIX_ENOTRECOVERABLE = __TOP_ERRNO + 36,
-	POSIX_ENOTSOCK = -ENOTSOCK,
-	POSIX_ENOTSUP = -ENOTSUP,
-	POSIX_ENOTTY = __TOP_ERRNO + 37,
-	POSIX_ENXIO = __TOP_ERRNO + 38,
-	POSIX_EOPNOTSUPP = __TOP_ERRNO + 39,
-	POSIX_EOVERFLOW = -EOVERFLOW,
-	POSIX_EOWNERDEAD = __TOP_ERRNO + 40,
-	POSIX_EPERM = -EPERM,
-	POSIX_EPIPE = __TOP_ERRNO + 41,
-	POSIX_EPROTO = __TOP_ERRNO + 42,
-	POSIX_EPROTONOSUPPORT = -EPROTONOSUPPORT,
-	POSIX_EPROTOTYPE = __TOP_ERRNO + 43,
-	POSIX_ERANGE = -ERANGE,
-	POSIX_EROFS = __TOP_ERRNO + 44,
-	POSIX_ESPIPE = __TOP_ERRNO + 45,
-	POSIX_ESRCH = __TOP_ERRNO + 46,
-	POSIX_ESTALE = __TOP_ERRNO + 47,
-	POSIX_ETIME = __TOP_ERRNO + 48,
-	POSIX_ETIMEDOUT = __TOP_ERRNO + 49,
-	POSIX_ETXTBSY = __TOP_ERRNO + 50,
-	POSIX_EWOULDBLOCK = __TOP_ERRNO + 51,
-	POSIX_EXDEV = -EXDEV,
-};
-
-#undef __TOP_ERRNO
-
-#undef E2BIG
-#undef EACCES
-#undef EADDRINUSE
-#undef EADDRNOTAVAIL
-#undef EAFNOSUPPORT
-#undef EAGAIN
-#undef EALREADY
-#undef EBADF
-#undef EBADMSG
-#undef EBUSY
-#undef ECANCELED
-#undef ECHILD
-#undef ECONNABORTED
-#undef ECONNREFUSED
-#undef ECONNRESET
-#undef EDEADLK
-#undef EDESTADDRREQ
-#undef EDOM
-#undef EDQUOT
-#undef EEXIST
-#undef EFAULT
-#undef EFBIG
-#undef EHOSTUNREACH
-#undef EIDRM
-#undef EILSEQ
-#undef EINPROGRESS
-#undef EINTR
-#undef EINVAL
-#undef EIO
-#undef EISCONN
-#undef EISDIR
-#undef ELOOP
-#undef EMFILE
-#undef EMLINK
-#undef EMSGSIZE
-#undef EMULTIHOP
-#undef ENAMETOOLONG
-#undef ENETDOWN
-#undef ENETRESET
-#undef ENETUNREACH
-#undef ENFILE
-#undef ENOBUFS
-#undef ENODATA
-#undef ENODEV
-#undef ENOENT
-#undef ENOEXEC
-#undef ENOLCK
-#undef ENOLINK
-#undef ENOMEM
-#undef ENOMSG
-#undef ENOPROTOOPT
-#undef ENOSPC
-#undef ENOSR
-#undef ENOSTR
-#undef ENOSYS
-#undef ENOTCONN
-#undef ENOTDIR
-#undef ENOTEMPTY
-#undef ENOTRECOVERABLE
-#undef ENOTSOCK
-#undef ENOTSUP
-#undef ENOTTY
-#undef ENXIO
-#undef EOPNOTSUPP
-#undef EOVERFLOW
-#undef EOWNERDEAD
-#undef EPERM
-#undef EPIPE
-#undef EPROTO
-#undef EPROTONOSUPPORT
-#undef EPROTOTYPE
-#undef ERANGE
-#undef EROFS
-#undef ESPIPE
-#undef ESRCH
-#undef ESTALE
-#undef ETIME
-#undef ETIMEDOUT
-#undef ETXTBSY
-#undef EWOULDBLOCK
-#undef EXDEV
-
-#define E2BIG POSIX_E2BIG
-#define EACCES POSIX_EACCES
-#define EADDRINUSE POSIX_EADDRINUSE
-#define EADDRNOTAVAIL POSIX_EADDRNOTAVAIL
-#define EAFNOSUPPORT POSIX_EAFNOSUPPORT
-#define EAGAIN POSIX_EAGAIN
-#define EALREADY POSIX_EALREADY
-#define EBADF POSIX_EBADF
-#define EBADMSG POSIX_EBADMSG
-#define EBUSY POSIX_EBUSY
-#define ECANCELED POSIX_ECANCELED
-#define ECHILD POSIX_ECHILD
-#define ECONNABORTED POSIX_ECONNABORTED
-#define ECONNREFUSED POSIX_ECONNREFUSED
-#define ECONNRESET POSIX_ECONNRESET
-#define EDEADLK POSIX_EDEADLK
-#define EDESTADDRREQ POSIX_EDESTADDRREQ
-#define EDOM POSIX_EDOM
-#define EDQUOT POSIX_EDQUOT
-#define EEXIST POSIX_EEXIST
-#define EFAULT POSIX_EFAULT
-#define EFBIG POSIX_EFBIG
-#define EHOSTUNREACH POSIX_EHOSTUNREACH
-#define EIDRM POSIX_EIDRM
-#define EILSEQ POSIX_EILSEQ
-#define EINPROGRESS POSIX_EINPROGRESS
-#define EINTR POSIX_EINTR
-#define EINVAL POSIX_EINVAL
-#define EIO POSIX_EIO
-#define EISCONN POSIX_EISCONN
-#define EISDIR POSIX_EISDIR
-#define ELOOP POSIX_ELOOP
-#define EMFILE POSIX_EMFILE
-#define EMLINK POSIX_EMLINK
-#define EMSGSIZE POSIX_EMSGSIZE
-#define EMULTIHOP POSIX_EMULTIHOP
-#define ENAMETOOLONG POSIX_ENAMETOOLONG
-#define ENETDOWN POSIX_ENETDOWN
-#define ENETRESET POSIX_ENETRESET
-#define ENETUNREACH POSIX_ENETUNREACH
-#define ENFILE POSIX_ENFILE
-#define ENOBUFS POSIX_ENOBUFS
-#define ENODATA POSIX_ENODATA
-#define ENODEV POSIX_ENODEV
-#define ENOENT POSIX_ENOENT
-#define ENOEXEC POSIX_ENOEXEC
-#define ENOLCK POSIX_ENOLCK
-#define ENOLINK POSIX_ENOLINK
-#define ENOMEM POSIX_ENOMEM
-#define ENOMSG POSIX_ENOMSG
-#define ENOPROTOOPT POSIX_ENOPROTOOPT
-#define ENOSPC POSIX_ENOSPC
-#define ENOSR POSIX_ENOSR
-#define ENOSTR POSIX_ENOSTR
-#define ENOSYS POSIX_ENOSYS
-#define ENOTCONN POSIX_ENOTCONN
-#define ENOTDIR POSIX_ENOTDIR
-#define ENOTEMPTY POSIX_ENOTEMPTY
-#define ENOTRECOVERABLE POSIX_ENOTRECOVERABLE
-#define ENOTSOCK POSIX_ENOTSOCK
-#define ENOTSUP POSIX_ENOTSUP
-#define ENOTTY POSIX_ENOTTY
-#define ENXIO POSIX_ENXIO
-#define EOPNOTSUPP POSIX_EOPNOTSUPP
-#define EOVERFLOW POSIX_EOVERFLOW
-#define EOWNERDEAD POSIX_EOWNERDEAD
-#define EPERM POSIX_EPERM
-#define EPIPE POSIX_EPIPE
-#define EPROTO POSIX_EPROTO
-#define EPROTONOSUPPORT POSIX_EPROTONOSUPPORT
-#define EPROTOTYPE POSIX_EPROTOTYPE
-#define ERANGE POSIX_ERANGE
-#define EROFS POSIX_EROFS
-#define ESPIPE POSIX_ESPIPE
-#define ESRCH POSIX_ESRCH
-#define ESTALE POSIX_ESTALE
-#define ETIME POSIX_ETIME
-#define ETIMEDOUT POSIX_ETIMEDOUT
-#define ETXTBSY POSIX_ETXTBSY
-#define EWOULDBLOCK POSIX_EWOULDBLOCK
-#define EXDEV POSIX_EXDEV
-
-#endif /* POSIX_ERRNO_H_ */
-
-/** @}
- */
Index: pace/lib/posix/fcntl.c
===================================================================
--- uspace/lib/posix/fcntl.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,98 +1,0 @@
-/*
- * 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 File control.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "internal/common.h"
-#include "fcntl.h"
-
-#include "libc/unistd.h"
-#include "libc/vfs/vfs.h"
-#include "errno.h"
-
-/**
- * Performs set of operations on the opened files.
- *
- * @param fd File descriptor of the opened file.
- * @param cmd Operation to carry out.
- * @return Non-negative on success. Might have special meaning corresponding
- *     to the requested operation.
- */
-int posix_fcntl(int fd, int cmd, ...)
-{
-	int flags;
-
-	switch (cmd) {
-	case F_DUPFD:
-	case F_DUPFD_CLOEXEC:
-		/* VFS currently does not provide the functionality to duplicate
-		 * opened file descriptor. */
-		// FIXME: implement this once dup() is available
-		errno = ENOTSUP;
-		return -1;
-	case F_GETFD:
-		/* FD_CLOEXEC is not supported. There are no other flags. */
-		return 0;
-	case F_SETFD:
-		/* FD_CLOEXEC is not supported. Ignore arguments and report success. */
-		return 0;
-	case F_GETFL:
-		/* File status flags (i.e. O_APPEND) are currently private to the
-		 * VFS server so it cannot be easily retrieved. */
-		flags = 0;
-		/* File access flags are currently not supported for file descriptors.
-		 * Provide full access. */
-		flags |= O_RDWR;
-		return flags;
-	case F_SETFL:
-		/* File access flags are currently not supported for file descriptors.
-		 * Ignore arguments and report success. */
-		return 0;
-	case F_GETOWN:
-	case F_SETOWN:
-	case F_GETLK:
-	case F_SETLK:
-	case F_SETLKW:
-		/* Signals (SIGURG) and file locks are not supported. */
-		errno = ENOTSUP;
-		return -1;
-	default:
-		/* Unknown command */
-		errno = EINVAL;
-		return -1;
-	}
-}
-
-/** @}
- */
Index: pace/lib/posix/fcntl.h
===================================================================
--- uspace/lib/posix/fcntl.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,94 +1,0 @@
-/*
- * 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 File control.
- */
-
-#ifndef POSIX_FCNTL_H_
-#define POSIX_FCNTL_H_
-
-#include "sys/types.h"
-#include "libc/fcntl.h"
-#include "errno.h"
-
-/* Mask for file access modes. */
-#undef O_ACCMODE
-#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
-
-/* fcntl commands */
-#undef F_DUPFD
-#undef F_DUPFD_CLOEXEC
-#undef F_GETFD
-#undef F_SETFD
-#undef F_GETFL
-#undef F_SETFL
-#undef F_GETOWN
-#undef F_SETOWN
-#undef F_GETLK
-#undef F_SETLK
-#undef F_SETLKW
-#define F_DUPFD            0 /* Duplicate file descriptor. */
-#define F_DUPFD_CLOEXEC    1 /* Same as F_DUPFD but with FD_CLOEXEC flag set. */
-#define F_GETFD            2 /* Get file descriptor flags. */
-#define F_SETFD            3 /* Set file descriptor flags. */
-#define F_GETFL            4 /* Get file status and access flags. */
-#define F_SETFL            5 /* Set file status flags. */
-#define F_GETOWN           6 /* Get socket owner. */
-#define F_SETOWN           7 /* Set socket owner. */
-#define F_GETLK            8 /* Get locking information. */
-#define F_SETLK            9 /* Set locking information. */
-#define F_SETLKW          10 /* Set locking information; wait if blocked. */
-
-/* File descriptor flags used with F_GETFD and F_SETFD. */
-#undef FD_CLOEXEC
-#define FD_CLOEXEC         1 /* Close on exec. */
-
-#undef open
-#define open(path, ...) \
-	({ \
-		int rc = open(path, ##__VA_ARGS__); \
-		if (rc < 0) { \
-			errno = -rc; \
-			rc = -1; \
-		} \
-		rc; \
-	})
-
-extern int posix_fcntl(int fd, int cmd, ...);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define fcntl posix_fcntl
-#endif
-
-#endif /* POSIX_FCNTL_H_ */
-
-/** @}
- */
Index: pace/lib/posix/float.h
===================================================================
--- uspace/lib/posix/float.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,43 +1,0 @@
-/*
- * 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 Floating type support.
- */
-
-#ifndef POSIX_FLOAT_H_
-#define POSIX_FLOAT_H_
-
-/* Empty. Just to satisfy preprocessor. */
-
-#endif /* POSIX_FLOAT_H_ */
-
-/** @}
- */
Index: pace/lib/posix/fnmatch.c
===================================================================
--- uspace/lib/posix/fnmatch.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,716 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Filename-matching.
- */
-
-/* This file contains an implementation of the fnmatch() pattern matching
- * function. There is more code than necessary to account for the possibility
- * of adding POSIX-like locale support to the system in the future. Functions
- * that are only necessary for locale support currently simply use single
- * characters for "collation elements". 
- * When (or if) locales are properly implemented, extending this implementation
- * will be fairly straightforward.
- */
-
-#include "stdbool.h"
-#include "ctype.h"
-#include "string.h"
-#include "stdlib.h"
-#include "assert.h"
-
-#define LIBPOSIX_INTERNAL
-
-#include "internal/common.h"
-#include "fnmatch.h"
-
-/* Returned by _match... functions. */
-#define INVALID_PATTERN -1
-
-/* Type for collating element, simple identity with characters now,
- * but may be extended for better locale support.
- */
-typedef int coll_elm_t;
-
-/** Return value indicating that the element in question
- * is not valid in the current locale. (That is, if locales are supported.)
- */
-#define COLL_ELM_INVALID -1
-
-/**
- * Get collating element matching a string.
- *
- * @param str String representation of the element.
- * @return Matching collating element or COLL_ELM_INVALID.
- */
-static coll_elm_t _coll_elm_get(const char* str)
-{
-	if (str[0] == '\0' || str[1] != '\0') {
-		return COLL_ELM_INVALID;
-	}
-	return str[0];
-}
-
-/**
- * Get collating element matching a single character.
- *
- * @param c Character representation of the element.
- * @return Matching collating element.
- */
-static coll_elm_t _coll_elm_char(int c)
-{
-	return c;
-}
-
-/**
- * Match collating element with a beginning of a string.
- *
- * @param elm Collating element to match.
- * @param str String which beginning should match the element.
- * @return 0 if the element doesn't match, or the number of characters matched.
- */
-static int _coll_elm_match(coll_elm_t elm, const char *str)
-{
-	return elm == *str;
-}
-
-/**
- * Checks whether a string begins with a collating element in the given range.
- * Ordering depends on the locale (if locales are supported).
- *
- * @param first First element of the range.
- * @param second Last element of the range.
- * @param str String to match.
- * @return 0 if there is no match, or the number of characters matched.
- */
-static int _coll_elm_between(coll_elm_t first, coll_elm_t second,
-    const char *str)
-{
-	return *str >= first && *str <= second;
-}
-
-/**
- * Read a string delimited by [? and ?].
- *
- * @param pattern Pointer to the string to read from. Its position is moved
- *    to the first character after the closing ].
- * @param seq The character on the inside of brackets.
- * @param buf Read buffer.
- * @param buf_sz Read buffer's size. If the buffer is not large enough for
- *    the entire string, the string is cut with no error indication.
- * @param flags Flags modifying the behavior.
- * @return True on success, false if the pattern is invalid.
- */
-static bool _get_delimited(
-    const char **pattern, int seq,
-    char *buf, size_t buf_sz, int flags)
-{
-	const bool noescape = (flags & FNM_NOESCAPE) != 0;
-	const bool pathname = (flags & FNM_PATHNAME) != 0;
-
-	const char *p = *pattern;
-	assert(p[0] == '[' && p[1] == seq /* Caller should ensure this. */);
-	p += 2;
-
-	while (true) {
-		if (*p == seq && *(p + 1) == ']') {
-			/* String properly ended, return. */
-			*pattern = p + 2;
-			*buf = '\0';
-			return true;
-		}
-		if (!noescape && *p == '\\') {
-			p++;
-		}
-		if (*p == '\0') {
-			/* String not ended properly, invalid pattern. */
-			return false;
-		}
-		if (pathname && *p == '/') {
-			/* Slash in a pathname pattern is invalid. */
-			return false;
-		}
-		if (buf_sz > 1) {
-			/* Only add to the buffer if there is space. */
-			*buf = *p;
-			buf++;
-			buf_sz--;
-		}
-		p++;
-	}
-}
-
-/************** CHARACTER CLASSES ****************/
-
-#define MAX_CLASS_OR_COLL_LEN 6
-
-struct _char_class {
-	const char *name;
-	int (*func) (int);
-};
-
-/* List of supported character classes. */
-static const struct _char_class _char_classes[] = {
-	{ "alnum", isalnum },
-	{ "alpha", isalpha },
-	{ "blank", isblank },
-	{ "cntrl", iscntrl },
-	{ "digit", isdigit },
-	{ "graph", isgraph },
-	{ "lower", islower },
-	{ "print", isprint },
-	{ "punct", ispunct },
-	{ "space", isspace },
-	{ "upper", isupper },
-	{ "xdigit", isxdigit }
-};
-
-/**
- * Compare function for binary search in the _char_classes array.
- * 
- * @param key Key of the searched element.
- * @param elem Element of _char_classes array.
- * @return Ordering indicator (-1 less than, 0 equal, 1 greater than).
- */
-static int _class_compare(const void *key, const void *elem)
-{
-	const struct _char_class *class = elem;
-	return strcmp((const char *) key, class->name);
-}
-
-/**
- * Returns whether the given character belongs to the specified character class.
- * 
- * @param cname Name of the character class.
- * @param c Character.
- * @return True if the character belongs to the class, false otherwise.
- */
-static bool _is_in_class (const char *cname, int c)
-{
-	/* Search for class in the array of supported character classes. */
-	const struct _char_class *class = bsearch(cname, _char_classes,
-	    sizeof(_char_classes) / sizeof(struct _char_class),
-	    sizeof(struct _char_class), _class_compare);
-
-	if (class == NULL) {
-		/* No such class supported - treat as an empty class. */
-		return false;
-	} else {
-		/* Class matched. */
-		return class->func(c);
-	}
-}
-
-/**
- * Tries to parse an initial part of the pattern as a character class pattern,
- * and if successful, matches the beginning of the given string against the class.
- * 
- * @param pattern Pointer to the pattern to match. Must begin with a class
- *    specifier and is repositioned to the first character after the specifier
- *    if successful.
- * @param str String to match.
- * @param flags Flags modifying the behavior (see fnmatch()).
- * @return INVALID_PATTERN if the pattern doesn't start with a valid class
- *    specifier, 0 if the beginning of the matched string doesn't belong
- *    to the class, or positive number of characters matched.
- */
-static int _match_char_class(const char **pattern, const char *str, int flags)
-{
-	char class[MAX_CLASS_OR_COLL_LEN + 1];
-
-	if (!_get_delimited(pattern, ':', class, sizeof(class), flags)) {
-		return INVALID_PATTERN;
-	}
-
-	return _is_in_class(class, *str);
-}
-
-/************** END CHARACTER CLASSES ****************/
-
-/**
- * Reads the next collating element in the pattern, taking into account
- * locale (if supported) and flags (see fnmatch()).
- * 
- * @param pattern Pattern.
- * @param flags Flags given to fnmatch().
- * @return Collating element on success,
- *     or COLL_ELM_INVALID if the pattern is invalid.
- */
-static coll_elm_t _next_coll_elm(const char **pattern, int flags)
-{
-	assert(pattern != NULL);
-	assert(*pattern != NULL);
-	assert(**pattern != '\0');
-
-	const char *p = *pattern;
-	const bool noescape = (flags & FNM_NOESCAPE) != 0;
-	const bool pathname = (flags & FNM_PATHNAME) != 0;
-
-	if (*p == '[') {
-		if (*(p + 1) == '.') {
-			char buf[MAX_CLASS_OR_COLL_LEN + 1];
-			if (!_get_delimited(pattern, '.', buf, sizeof(buf), flags)) {
-				return COLL_ELM_INVALID;
-			}
-			return _coll_elm_get(buf);
-		}
-
-		if (*(p + 1) == '=') {
-			char buf[MAX_CLASS_OR_COLL_LEN + 1];
-			if (!_get_delimited(pattern, '=', buf, sizeof(buf), flags)) {
-				return COLL_ELM_INVALID;
-			}
-			return _coll_elm_get(buf);
-		}
-	}
-
-	if (!noescape && *p == '\\') {
-		p++;
-		if (*p == '\0') {
-			*pattern = p;
-			return COLL_ELM_INVALID;
-		}
-	}
-	if (pathname && *p == '/') {
-		return COLL_ELM_INVALID;
-	}
-	
-	*pattern = p + 1;
-	return _coll_elm_char(*p);
-}
-
-/**
- * Matches the beginning of the given string against a bracket expression
- * the pattern begins with.
- * 
- * @param pattern Pointer to the beginning of a bracket expression in a pattern.
- *     On success, the pointer is moved to the first character after the
- *     bracket expression.
- * @param str Unmatched part of the string.
- * @param flags Flags given to fnmatch().
- * @return INVALID_PATTERN if the pattern is invalid, 0 if there is no match
- *     or the number of matched characters on success.
- */
-static int _match_bracket_expr(const char **pattern, const char *str, int flags)
-{
-	const bool pathname = (flags & FNM_PATHNAME) != 0;
-	const bool special_period = (flags & FNM_PERIOD) != 0;
-	const char *p = *pattern;
-	bool negative = false;
-	int matched = 0;
-
-	#define _matched(match) { \
-		int _match = match; \
-		if (_match < 0) { \
-			/* Invalid pattern */ \
-			return _match; \
-		} else if (matched == 0 && _match > 0) { \
-			/* First match */ \
-			matched = _match; \
-		} \
-	}
-
-	assert(*p == '[');  /* calling code should ensure this */
-	p++;
-
-	if (*str == '\0' || (pathname && *str == '/') ||
-	    (pathname && special_period && *str == '.' && *(str - 1) == '/')) {
-		/* No bracket expression matches end of string,
-		 * slash in pathname match or initial period with FNM_PERIOD
-		 * option.
-		 */
-		return 0;
-	}
-
-	if (*p == '^' || *p == '!') {
-		negative = true;
-		p++;
-	}
-
-	if (*p == ']') {
-		/* When ']' is first, treat it as a normal character. */
-		_matched(*str == ']');
-		p++;
-	}
-	
-	coll_elm_t current_elm = COLL_ELM_INVALID;
-	
-	while (*p != ']') {
-		if (*p == '-' && *(p + 1) != ']' &&
-		    current_elm != COLL_ELM_INVALID) {
-			/* Range expression. */
-			p++;
-			coll_elm_t end_elm = _next_coll_elm(&p, flags);
-			if (end_elm == COLL_ELM_INVALID) {
-				return INVALID_PATTERN;
-			}
-			_matched(_coll_elm_between(current_elm, end_elm, str));
-			continue;
-		}
-	
-		if (*p == '[' && *(p + 1) == ':') {
-			current_elm = COLL_ELM_INVALID;
-			_matched(_match_char_class(&p, str, flags));
-			continue;
-		}
-		
-		current_elm = _next_coll_elm(&p, flags);
-		if (current_elm == COLL_ELM_INVALID) {
-			return INVALID_PATTERN;
-		}
-		_matched(_coll_elm_match(current_elm, str));
-	}
-
-	/* No error occured - update pattern pointer. */
-	*pattern = p + 1;
-
-	if (matched == 0) {
-		/* No match found */
-		return negative;
-	} else {
-		/* Matched 'match' characters. */
-		return negative ? 0 : matched;
-	}
-
-	#undef _matched
-}
-
-/**
- * Matches a portion of the pattern containing no asterisks (*) against
- * the given string.
- * 
- * @param pattern Pointer to the unmatched portion of the pattern.
- *     On success, the pointer is moved to the first asterisk, or to the
- *     terminating nul character, whichever occurs first.
- * @param string Pointer to the input string. On success, the pointer is moved
- *     to the first character that wasn't explicitly matched.
- * @param flags Flags given to fnmatch().
- * @return True if the entire subpattern matched. False otherwise.
- */
-static bool _partial_match(const char **pattern, const char **string, int flags)
-{
-	/* Only a single *-delimited subpattern is matched here.
-	 * So in this function, '*' is understood as the end of pattern.
-	 */
-
-	const bool pathname = (flags & FNM_PATHNAME) != 0;
-	const bool special_period = (flags & FNM_PERIOD) != 0;
-	const bool noescape = (flags & FNM_NOESCAPE) != 0;
-	const bool leading_dir = (flags & FNM_LEADING_DIR) != 0;
-
-	const char *s = *string;
-	const char *p = *pattern;
-
-	while (*p != '*') {
-		/* Bracket expression. */
-		if (*p == '[') {
-			int matched = _match_bracket_expr(&p, s, flags);
-			if (matched == 0) {
-				/* Doesn't match. */
-				return false;
-			}
-			if (matched != INVALID_PATTERN) {
-				s += matched;
-				continue;
-			}
-
-			assert(matched == INVALID_PATTERN);
-			/* Fall through to match [ as an ordinary character. */
-		}
-
-		/* Wildcard match. */
-		if (*p == '?') {
-			if (*s == '\0') {
-				/* No character to match. */
-				return false;
-			}
-			if (pathname && *s == '/') {
-				/* Slash must be matched explicitly. */
-				return false;
-			}
-			if (special_period && pathname &&
-			    *s == '.' && *(s - 1) == '/') {
-				/* Initial period must be matched explicitly. */
-				return false;
-			}
-			
-			/* None of the above, match anything else. */
-			p++;
-			s++;
-			continue;
-		}
-
-		if (!noescape && *p == '\\') {
-			/* Escaped character. */
-			p++;
-		}
-
-		if (*p == '\0') {
-			/* End of pattern, must match end of string or
-			 * an end of subdirectory name (optional).
-			 */
-
-			if (*s == '\0' || (leading_dir && *s == '/')) {
-				break;
-			}
-
-			return false;
-		}
-
-		if (*p == *s) {
-			/* Exact match. */
-			p++;
-			s++;
-			continue;
-		}
-
-		/* Nothing matched. */
-		return false;
-	}
-
-	/* Entire sub-pattern matched. */
-	
-	/* postconditions */
-	assert(*p == '\0' || *p == '*');
-	assert(*p != '\0' || *s == '\0' || (leading_dir && *s == '/'));
-	
-	*pattern = p;
-	*string = s;
-	return true;
-}
-
-/**
- * Match string against a pattern.
- * 
- * @param pattern Pattern.
- * @param string String to match.
- * @param flags Flags given to fnmatch().
- * @return True if the string matched the pattern, false otherwise.
- */
-static bool _full_match(const char *pattern, const char *string, int flags)
-{
-	const bool pathname = (flags & FNM_PATHNAME) != 0;
-	const bool special_period = (flags & FNM_PERIOD) != 0;
-	const bool leading_dir = (flags & FNM_LEADING_DIR) != 0;
-
-	if (special_period && *string == '.') {
-		/* Initial dot must be matched by an explicit dot in pattern. */
-		if (*pattern != '.') {
-			return false;
-		}
-		pattern++;
-		string++;
-	}
-
-	if (*pattern != '*') {
-		if (!_partial_match(&pattern, &string, flags)) {
-			/* The initial match must succeed. */
-			return false;
-		}
-	}
-
-	while (*pattern != '\0') {
-		assert(*pattern == '*');
-		pattern++;
-
-		bool matched = false;
-
-		const char *end;
-		if (pathname && special_period &&
-		    *string == '.' && *(string - 1) == '/') {
-			end = string;
-		} else {
-			end = strchrnul(string, pathname ? '/' : '\0');
-		}
-
-		/* Try to match every possible offset. */
-		while (string <= end) {
-			if (_partial_match(&pattern, &string, flags)) {
-				matched = true;
-				break;
-			}
-			string++;
-		}
-
-		if (matched) {
-			continue;
-		}
-
-		return false;
-	}
-
-	return *string == '\0' || (leading_dir && *string == '/');
-}
-
-/**
- * Transform the entire string to lowercase.
- * 
- * @param s Input string.
- * @return Newly allocated copy of the input string with all uppercase
- *     characters folded to their lowercase variants.
- */
-static char *_casefold(const char *s)
-{
-	assert(s != NULL);
-	char *result = strdup(s);
-	for (char *i = result; *i != '\0'; ++i) {
-		*i = tolower(*i);
-	}
-	return result;
-}
-
-/**
- * Filename pattern matching.
- *
- * @param pattern Pattern to match the string against.
- * @param string Matched string.
- * @param flags Flags altering the matching of special characters
- *     (mainly for dot and slash).
- * @return Zero if the string matches the pattern, FNM_NOMATCH otherwise.
- */
-int posix_fnmatch(const char *pattern, const char *string, int flags)
-{
-	assert(pattern != NULL);
-	assert(string != NULL);
-
-	// TODO: don't fold everything in advance, but only when needed
-
-	if ((flags & FNM_CASEFOLD) != 0) {
-		/* Just fold the entire pattern and string. */
-		pattern = _casefold(pattern);
-		string = _casefold(string);
-	}
-
-	bool result = _full_match(pattern, string, flags);
-
-	if ((flags & FNM_CASEFOLD) != 0) {
-		if (pattern) {
-			free((char *) pattern);
-		}
-		if (string) {
-			free((char *) string);
-		}
-	}
-
-	return result ? 0 : FNM_NOMATCH;
-}
-
-// FIXME: put the testcases to the app/tester after fnmatch is included into libc
-
-#if 0
-
-#include <stdio.h>
-
-void __posix_fnmatch_test()
-{
-	int fail = 0;
-
-	#undef assert
-	#define assert(x) { if (x) printf("SUCCESS: "#x"\n"); else { printf("FAILED: "#x"\n"); fail++; } }
-	#define match(s1, s2, flags) assert(posix_fnmatch(s1, s2, flags) == 0)
-	#define nomatch(s1, s2, flags) assert(posix_fnmatch(s1, s2, flags) == FNM_NOMATCH)
-
-	assert(FNM_PATHNAME == FNM_FILE_NAME);
-	match("", "", 0);
-	match("*", "hello", 0);
-	match("hello", "hello", 0);
-	match("hello*", "hello", 0);
-	nomatch("hello?", "hello", 0);
-	match("*hello", "prdel hello", 0);
-	match("he[sl]lo", "hello", 0);
-	match("he[sl]lo", "heslo", 0);
-	nomatch("he[sl]lo", "heblo", 0);
-	nomatch("he[^sl]lo", "hello", 0);
-	nomatch("he[^sl]lo", "heslo", 0);
-	match("he[^sl]lo", "heblo", 0);
-	nomatch("he[!sl]lo", "hello", 0);
-	nomatch("he[!sl]lo", "heslo", 0);
-	match("he[!sl]lo", "heblo", 0);
-	match("al*[c-t]a*vis*ta", "alheimer talir jehovista", 0);
-	match("al*[c-t]a*vis*ta", "alfons had jehovista", 0);
-	match("[a-ce-z]", "a", 0);
-	match("[a-ce-z]", "c", 0);
-	nomatch("[a-ce-z]", "d", 0);
-	match("[a-ce-z]", "e", 0);
-	match("[a-ce-z]", "z", 0);
-	nomatch("[^a-ce-z]", "a", 0);
-	nomatch("[^a-ce-z]", "c", 0);
-	match("[^a-ce-z]", "d", 0);
-	nomatch("[^a-ce-z]", "e", 0);
-	nomatch("[^a-ce-z]", "z", 0);
-	match("helen??", "helenos", 0);
-	match("****booo****", "booo", 0);
-	
-	match("hello[[:space:]]world", "hello world", 0);
-	nomatch("hello[[:alpha:]]world", "hello world", 0);
-	
-	match("/hoooo*", "/hooooooo/hooo", 0);
-	nomatch("/hoooo*", "/hooooooo/hooo", FNM_PATHNAME);
-	nomatch("/hoooo*/", "/hooooooo/hooo", FNM_PATHNAME);
-	match("/hoooo*/*", "/hooooooo/hooo", FNM_PATHNAME);
-	match("/hoooo*/hooo", "/hooooooo/hooo", FNM_PATHNAME);
-	match("/hoooo*", "/hooooooo/hooo", FNM_PATHNAME | FNM_LEADING_DIR);
-	nomatch("/hoooo*/", "/hooooooo/hooo", FNM_PATHNAME | FNM_LEADING_DIR);
-	nomatch("/hoooo", "/hooooooo/hooo", FNM_LEADING_DIR);
-	match("/hooooooo", "/hooooooo/hooo", FNM_LEADING_DIR);
-	
-	match("*", "hell", 0);
-	match("*?", "hell", 0);
-	match("?*?", "hell", 0);
-	match("?*??", "hell", 0);
-	match("??*??", "hell", 0);
-	nomatch("???*??", "hell", 0);
-	
-	nomatch("", "hell", 0);
-	nomatch("?", "hell", 0);
-	nomatch("??", "hell", 0);
-	nomatch("???", "hell", 0);
-	match("????", "hell", 0);
-	
-	match("*", "h.ello", FNM_PERIOD);
-	match("*", "h.ello", FNM_PATHNAME | FNM_PERIOD);
-	nomatch("*", ".hello", FNM_PERIOD);
-	match("h?ello", "h.ello", FNM_PERIOD);
-	nomatch("?hello", ".hello", FNM_PERIOD);
-	match("/home/user/.*", "/home/user/.hello", FNM_PATHNAME | FNM_PERIOD);
-	match("/home/user/*", "/home/user/.hello", FNM_PERIOD);
-	nomatch("/home/user/*", "/home/user/.hello", FNM_PATHNAME | FNM_PERIOD);
-
-	nomatch("HeLlO", "hello", 0);
-	match("HeLlO", "hello", FNM_CASEFOLD);
-
-	printf("Failed: %d\n", fail);
-}
-
-#endif
-
-/** @}
- */
Index: pace/lib/posix/fnmatch.h
===================================================================
--- uspace/lib/posix/fnmatch.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,67 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Filename-matching.
- */
-
-#ifndef POSIX_FNMATCH_H_
-#define POSIX_FNMATCH_H_
-
-/* Error Values */
-#undef FNM_NOMATCH
-#define FNM_NOMATCH 1
-
-/* Flags */
-#undef FNM_PATHNAME
-#undef FNM_PERIOD
-#undef FNM_NOESCAPE
-#define FNM_PATHNAME 1
-#define FNM_PERIOD 2
-#define FNM_NOESCAPE 4
-
-/* GNU Extensions */
-#undef FNM_FILE_NAME
-#undef FNM_LEADING_DIR
-#undef FNM_CASEFOLD
-#define FNM_FILE_NAME FNM_PATHNAME
-#define FNM_LEADING_DIR 8
-#define FNM_CASEFOLD 16
-
-extern int posix_fnmatch(const char *pattern, const char *string, int flags);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define fnmatch posix_fnmatch
-#endif
-
-#endif /* POSIX_FNMATCH_H_ */
-
-/** @}
- */
Index: pace/lib/posix/getopt.c
===================================================================
--- uspace/lib/posix/getopt.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,54 +1,0 @@
-/*
- * Copyright (c) 2012 Vojtech Horky
- * 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 Command line argument parsing.
- */
-#define LIBPOSIX_INTERNAL
-
-#include "internal/common.h"
-#include "libc/getopt.h"
-#include "getopt.h"
-
-
-int posix_getopt_long(int argc, char * const argv[],
-    const char *opt_string, const struct option *long_opts, int *long_index)
-{
-	int rc = getopt_long(argc, argv, opt_string, long_opts, long_index);
-	posix_optarg = (char *) optarg;
-	return rc;
-}
-
-int posix_getopt(int argc, char * const argv[], const char *opt_string)
-{
-	int rc = getopt(argc, argv, opt_string);
-	posix_optarg = (char *) optarg;
-	return rc;
-}
Index: pace/lib/posix/getopt.h
===================================================================
--- uspace/lib/posix/getopt.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,64 +1,0 @@
-/*
- * Copyright (c) 2012 Vojtech Horky
- * 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 Command line argument parsing.
- */
-#ifndef POSIX_GETOPT_H
-#define POSIX_GETOPT_H
-
-#include "unistd.h"
-
-/* Option Arguments */
-#define no_argument        0
-#define required_argument  1
-#define optional_argument  2
-
-#ifndef LIBPOSIX_INTERNAL
-struct option {
-	const char *name;
-	int has_arg;
-	int *flag;
-	int val;
-};
-#endif
-
-extern int posix_getopt_long(int, char * const [], const char *, const struct option *, int *);
-
-
-#ifndef LIBPOSIX_INTERNAL
-	#define getopt_long posix_getopt_long
-#endif
-
-
-#endif
-/**
- * @}
- */
Index: uspace/lib/posix/include/posix/assert.h
===================================================================
--- uspace/lib/posix/include/posix/assert.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/assert.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Program assertion.
+ */
+
+/* NO include guard on purpose. */
+
+#include "libc/assert.h"
+
+#undef assert
+
+#ifndef NDEBUG
+	#define assert(expr) ((expr) ? (void) 0 : assert_abort(#expr, __FILE__, __LINE__))
+#else
+	#define assert(expr) ((void) 0)
+#endif
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/ctype.h
===================================================================
--- uspace/lib/posix/include/posix/ctype.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/ctype.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,73 @@
+/*
+ * 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 Character classification.
+ */
+
+#ifndef POSIX_CTYPE_H_
+#define POSIX_CTYPE_H_
+
+#include "libc/ctype.h"
+
+/* Classification of Characters */
+extern int posix_isxdigit(int c);
+extern int posix_isblank(int c);
+extern int posix_iscntrl(int c);
+extern int posix_isgraph(int c);
+extern int posix_isprint(int c);
+extern int posix_ispunct(int c);
+
+/* Obsolete Functions and Macros */
+extern int posix_isascii(int c);
+extern int posix_toascii(int c);
+#undef _tolower
+#define _tolower(c) ((c) - 'A' + 'a')
+#undef _toupper
+#define _toupper(c) ((c) - 'a' + 'A')
+
+
+#ifndef LIBPOSIX_INTERNAL
+	#define isxdigit posix_isxdigit
+	#define isblank posix_isblank
+	#define iscntrl posix_iscntrl
+	#define isgraph posix_isgraph
+	#define isprint posix_isprint
+	#define ispunct posix_ispunct
+	
+	#define isascii posix_isascii
+	#define toascii posix_toascii
+#endif
+
+#endif /* POSIX_CTYPE_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/errno.h
===================================================================
--- uspace/lib/posix/include/posix/errno.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/errno.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 System error numbers.
+ */
+
+#ifndef POSIX_ERRNO_H_
+#define POSIX_ERRNO_H_
+
+#include "libc/errno.h"
+
+/* IMPORTANT:
+ * Since libc uses negative errorcodes, some sort of conversion is necessary to
+ * keep POSIX programs and libraries from breaking. This file maps POSIX error
+ * codes to absolute values of corresponding libc codes where available, and
+ * assigns new code where there is no prior definition in libc.
+ *
+ * A new errno variable is defined. When accessed, the function first looks at
+ * libc errno and iff it is != 0, sets the POSIX errno to absolute value of
+ * libc errno. Given that no library function sets errno to 0 and that all
+ * POSIX libraries will be used solely by POSIX programs (thus, there only needs
+ * to be one way correspondence between errno and posix_errno), this approach
+ * should work as expected in most cases and does not require any wrappers for
+ * libc routines that would just change errno values.
+ *
+ * There is no conditioning by LIBPOSIX_INTERNAL for redefinitions of macros.
+ * If there is a need to check errno for a value not defined by POSIX, it's
+ * necessary to compare errno against abs(ECODE), because there is no
+ * redefinition for such error codes.
+ *
+ * XXX: maybe all HOS error codes should be redefined
+ *
+ * NOTE: This redefinition is slightly POSIX incompatible, since the
+ *  specification requires the macro values to be usable in preprocessing
+ *  directives. I don't think that's very important, though.
+ */
+
+#undef errno
+#define errno (*__posix_errno())
+
+extern int *__posix_errno(void);
+
+#define __TOP_ERRNO (-NO_DATA)
+
+enum {
+	POSIX_E2BIG = __TOP_ERRNO + 1,
+	POSIX_EACCES = __TOP_ERRNO + 2,
+	POSIX_EADDRINUSE = -EADDRINUSE,
+	POSIX_EADDRNOTAVAIL = -EADDRNOTAVAIL,
+	POSIX_EAFNOSUPPORT = -EAFNOSUPPORT,
+	POSIX_EAGAIN = -EAGAIN,
+	POSIX_EALREADY = __TOP_ERRNO + 3,
+	POSIX_EBADF = -EBADF,
+	POSIX_EBADMSG = __TOP_ERRNO + 4,
+	POSIX_EBUSY = -EBUSY,
+	POSIX_ECANCELED = __TOP_ERRNO + 5,
+	POSIX_ECHILD = __TOP_ERRNO + 6,
+	POSIX_ECONNABORTED = __TOP_ERRNO + 7,
+	POSIX_ECONNREFUSED = __TOP_ERRNO + 8,
+	POSIX_ECONNRESET = __TOP_ERRNO + 9,
+	POSIX_EDEADLK = __TOP_ERRNO + 10,
+	POSIX_EDESTADDRREQ = -EDESTADDRREQ,
+	POSIX_EDOM = __TOP_ERRNO + 11,
+	POSIX_EDQUOT = __TOP_ERRNO + 12,
+	POSIX_EEXIST = -EEXIST,
+	POSIX_EFAULT = __TOP_ERRNO + 13,
+	POSIX_EFBIG = __TOP_ERRNO + 14,
+	POSIX_EHOSTUNREACH = __TOP_ERRNO + 15,
+	POSIX_EIDRM = __TOP_ERRNO + 16,
+	POSIX_EILSEQ = __TOP_ERRNO + 17,
+	POSIX_EINPROGRESS = -EINPROGRESS,
+	POSIX_EINTR = -EINTR,
+	POSIX_EINVAL = -EINVAL,
+	POSIX_EIO = -EIO,
+	POSIX_EISCONN = __TOP_ERRNO + 18,
+	POSIX_EISDIR = -EISDIR,
+	POSIX_ELOOP = __TOP_ERRNO + 19,
+	POSIX_EMFILE = -EMFILE,
+	POSIX_EMLINK = -EMLINK,
+	POSIX_EMSGSIZE = __TOP_ERRNO + 20,
+	POSIX_EMULTIHOP = __TOP_ERRNO + 21,
+	POSIX_ENAMETOOLONG = -ENAMETOOLONG,
+	POSIX_ENETDOWN = __TOP_ERRNO + 22,
+	POSIX_ENETRESET = __TOP_ERRNO + 23,
+	POSIX_ENETUNREACH = __TOP_ERRNO + 24,
+	POSIX_ENFILE = __TOP_ERRNO + 25,
+	POSIX_ENOBUFS = __TOP_ERRNO + 26,
+	POSIX_ENODATA = -NO_DATA,
+	POSIX_ENODEV = __TOP_ERRNO + 27,
+	POSIX_ENOENT = -ENOENT,
+	POSIX_ENOEXEC = __TOP_ERRNO + 28,
+	POSIX_ENOLCK = __TOP_ERRNO + 29,
+	POSIX_ENOLINK = __TOP_ERRNO + 30,
+	POSIX_ENOMEM = -ENOMEM,
+	POSIX_ENOMSG = __TOP_ERRNO + 31,
+	POSIX_ENOPROTOOPT = __TOP_ERRNO + 32,
+	POSIX_ENOSPC = -ENOSPC,
+	POSIX_ENOSR = __TOP_ERRNO + 33,
+	POSIX_ENOSTR = __TOP_ERRNO + 34,
+	POSIX_ENOSYS = __TOP_ERRNO + 35,
+	POSIX_ENOTCONN = -ENOTCONN,
+	POSIX_ENOTDIR = -ENOTDIR,
+	POSIX_ENOTEMPTY = -ENOTEMPTY,
+	POSIX_ENOTRECOVERABLE = __TOP_ERRNO + 36,
+	POSIX_ENOTSOCK = -ENOTSOCK,
+	POSIX_ENOTSUP = -ENOTSUP,
+	POSIX_ENOTTY = __TOP_ERRNO + 37,
+	POSIX_ENXIO = __TOP_ERRNO + 38,
+	POSIX_EOPNOTSUPP = __TOP_ERRNO + 39,
+	POSIX_EOVERFLOW = -EOVERFLOW,
+	POSIX_EOWNERDEAD = __TOP_ERRNO + 40,
+	POSIX_EPERM = -EPERM,
+	POSIX_EPIPE = __TOP_ERRNO + 41,
+	POSIX_EPROTO = __TOP_ERRNO + 42,
+	POSIX_EPROTONOSUPPORT = -EPROTONOSUPPORT,
+	POSIX_EPROTOTYPE = __TOP_ERRNO + 43,
+	POSIX_ERANGE = -ERANGE,
+	POSIX_EROFS = __TOP_ERRNO + 44,
+	POSIX_ESPIPE = __TOP_ERRNO + 45,
+	POSIX_ESRCH = __TOP_ERRNO + 46,
+	POSIX_ESTALE = __TOP_ERRNO + 47,
+	POSIX_ETIME = __TOP_ERRNO + 48,
+	POSIX_ETIMEDOUT = __TOP_ERRNO + 49,
+	POSIX_ETXTBSY = __TOP_ERRNO + 50,
+	POSIX_EWOULDBLOCK = __TOP_ERRNO + 51,
+	POSIX_EXDEV = -EXDEV,
+};
+
+#undef __TOP_ERRNO
+
+#undef E2BIG
+#undef EACCES
+#undef EADDRINUSE
+#undef EADDRNOTAVAIL
+#undef EAFNOSUPPORT
+#undef EAGAIN
+#undef EALREADY
+#undef EBADF
+#undef EBADMSG
+#undef EBUSY
+#undef ECANCELED
+#undef ECHILD
+#undef ECONNABORTED
+#undef ECONNREFUSED
+#undef ECONNRESET
+#undef EDEADLK
+#undef EDESTADDRREQ
+#undef EDOM
+#undef EDQUOT
+#undef EEXIST
+#undef EFAULT
+#undef EFBIG
+#undef EHOSTUNREACH
+#undef EIDRM
+#undef EILSEQ
+#undef EINPROGRESS
+#undef EINTR
+#undef EINVAL
+#undef EIO
+#undef EISCONN
+#undef EISDIR
+#undef ELOOP
+#undef EMFILE
+#undef EMLINK
+#undef EMSGSIZE
+#undef EMULTIHOP
+#undef ENAMETOOLONG
+#undef ENETDOWN
+#undef ENETRESET
+#undef ENETUNREACH
+#undef ENFILE
+#undef ENOBUFS
+#undef ENODATA
+#undef ENODEV
+#undef ENOENT
+#undef ENOEXEC
+#undef ENOLCK
+#undef ENOLINK
+#undef ENOMEM
+#undef ENOMSG
+#undef ENOPROTOOPT
+#undef ENOSPC
+#undef ENOSR
+#undef ENOSTR
+#undef ENOSYS
+#undef ENOTCONN
+#undef ENOTDIR
+#undef ENOTEMPTY
+#undef ENOTRECOVERABLE
+#undef ENOTSOCK
+#undef ENOTSUP
+#undef ENOTTY
+#undef ENXIO
+#undef EOPNOTSUPP
+#undef EOVERFLOW
+#undef EOWNERDEAD
+#undef EPERM
+#undef EPIPE
+#undef EPROTO
+#undef EPROTONOSUPPORT
+#undef EPROTOTYPE
+#undef ERANGE
+#undef EROFS
+#undef ESPIPE
+#undef ESRCH
+#undef ESTALE
+#undef ETIME
+#undef ETIMEDOUT
+#undef ETXTBSY
+#undef EWOULDBLOCK
+#undef EXDEV
+
+#define E2BIG POSIX_E2BIG
+#define EACCES POSIX_EACCES
+#define EADDRINUSE POSIX_EADDRINUSE
+#define EADDRNOTAVAIL POSIX_EADDRNOTAVAIL
+#define EAFNOSUPPORT POSIX_EAFNOSUPPORT
+#define EAGAIN POSIX_EAGAIN
+#define EALREADY POSIX_EALREADY
+#define EBADF POSIX_EBADF
+#define EBADMSG POSIX_EBADMSG
+#define EBUSY POSIX_EBUSY
+#define ECANCELED POSIX_ECANCELED
+#define ECHILD POSIX_ECHILD
+#define ECONNABORTED POSIX_ECONNABORTED
+#define ECONNREFUSED POSIX_ECONNREFUSED
+#define ECONNRESET POSIX_ECONNRESET
+#define EDEADLK POSIX_EDEADLK
+#define EDESTADDRREQ POSIX_EDESTADDRREQ
+#define EDOM POSIX_EDOM
+#define EDQUOT POSIX_EDQUOT
+#define EEXIST POSIX_EEXIST
+#define EFAULT POSIX_EFAULT
+#define EFBIG POSIX_EFBIG
+#define EHOSTUNREACH POSIX_EHOSTUNREACH
+#define EIDRM POSIX_EIDRM
+#define EILSEQ POSIX_EILSEQ
+#define EINPROGRESS POSIX_EINPROGRESS
+#define EINTR POSIX_EINTR
+#define EINVAL POSIX_EINVAL
+#define EIO POSIX_EIO
+#define EISCONN POSIX_EISCONN
+#define EISDIR POSIX_EISDIR
+#define ELOOP POSIX_ELOOP
+#define EMFILE POSIX_EMFILE
+#define EMLINK POSIX_EMLINK
+#define EMSGSIZE POSIX_EMSGSIZE
+#define EMULTIHOP POSIX_EMULTIHOP
+#define ENAMETOOLONG POSIX_ENAMETOOLONG
+#define ENETDOWN POSIX_ENETDOWN
+#define ENETRESET POSIX_ENETRESET
+#define ENETUNREACH POSIX_ENETUNREACH
+#define ENFILE POSIX_ENFILE
+#define ENOBUFS POSIX_ENOBUFS
+#define ENODATA POSIX_ENODATA
+#define ENODEV POSIX_ENODEV
+#define ENOENT POSIX_ENOENT
+#define ENOEXEC POSIX_ENOEXEC
+#define ENOLCK POSIX_ENOLCK
+#define ENOLINK POSIX_ENOLINK
+#define ENOMEM POSIX_ENOMEM
+#define ENOMSG POSIX_ENOMSG
+#define ENOPROTOOPT POSIX_ENOPROTOOPT
+#define ENOSPC POSIX_ENOSPC
+#define ENOSR POSIX_ENOSR
+#define ENOSTR POSIX_ENOSTR
+#define ENOSYS POSIX_ENOSYS
+#define ENOTCONN POSIX_ENOTCONN
+#define ENOTDIR POSIX_ENOTDIR
+#define ENOTEMPTY POSIX_ENOTEMPTY
+#define ENOTRECOVERABLE POSIX_ENOTRECOVERABLE
+#define ENOTSOCK POSIX_ENOTSOCK
+#define ENOTSUP POSIX_ENOTSUP
+#define ENOTTY POSIX_ENOTTY
+#define ENXIO POSIX_ENXIO
+#define EOPNOTSUPP POSIX_EOPNOTSUPP
+#define EOVERFLOW POSIX_EOVERFLOW
+#define EOWNERDEAD POSIX_EOWNERDEAD
+#define EPERM POSIX_EPERM
+#define EPIPE POSIX_EPIPE
+#define EPROTO POSIX_EPROTO
+#define EPROTONOSUPPORT POSIX_EPROTONOSUPPORT
+#define EPROTOTYPE POSIX_EPROTOTYPE
+#define ERANGE POSIX_ERANGE
+#define EROFS POSIX_EROFS
+#define ESPIPE POSIX_ESPIPE
+#define ESRCH POSIX_ESRCH
+#define ESTALE POSIX_ESTALE
+#define ETIME POSIX_ETIME
+#define ETIMEDOUT POSIX_ETIMEDOUT
+#define ETXTBSY POSIX_ETXTBSY
+#define EWOULDBLOCK POSIX_EWOULDBLOCK
+#define EXDEV POSIX_EXDEV
+
+#endif /* POSIX_ERRNO_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/fcntl.h
===================================================================
--- uspace/lib/posix/include/posix/fcntl.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/fcntl.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,85 @@
+/*
+ * 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 File control.
+ */
+
+#ifndef POSIX_FCNTL_H_
+#define POSIX_FCNTL_H_
+
+#include "sys/types.h"
+#include "libc/fcntl.h"
+#include "errno.h"
+
+/* Mask for file access modes. */
+#undef O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
+
+/* fcntl commands */
+#undef F_DUPFD
+#undef F_DUPFD_CLOEXEC
+#undef F_GETFD
+#undef F_SETFD
+#undef F_GETFL
+#undef F_SETFL
+#undef F_GETOWN
+#undef F_SETOWN
+#undef F_GETLK
+#undef F_SETLK
+#undef F_SETLKW
+#define F_DUPFD            0 /* Duplicate file descriptor. */
+#define F_DUPFD_CLOEXEC    1 /* Same as F_DUPFD but with FD_CLOEXEC flag set. */
+#define F_GETFD            2 /* Get file descriptor flags. */
+#define F_SETFD            3 /* Set file descriptor flags. */
+#define F_GETFL            4 /* Get file status and access flags. */
+#define F_SETFL            5 /* Set file status flags. */
+#define F_GETOWN           6 /* Get socket owner. */
+#define F_SETOWN           7 /* Set socket owner. */
+#define F_GETLK            8 /* Get locking information. */
+#define F_SETLK            9 /* Set locking information. */
+#define F_SETLKW          10 /* Set locking information; wait if blocked. */
+
+/* File descriptor flags used with F_GETFD and F_SETFD. */
+#undef FD_CLOEXEC
+#define FD_CLOEXEC         1 /* Close on exec. */
+
+extern int posix_open(const char *pathname, int flags, ...);
+extern int posix_fcntl(int fd, int cmd, ...);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define fcntl posix_fcntl
+	#define open posix_open
+#endif
+
+#endif /* POSIX_FCNTL_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/float.h
===================================================================
--- uspace/lib/posix/include/posix/float.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/float.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,43 @@
+/*
+ * 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 Floating type support.
+ */
+
+#ifndef POSIX_FLOAT_H_
+#define POSIX_FLOAT_H_
+
+/* Empty. Just to satisfy preprocessor. */
+
+#endif /* POSIX_FLOAT_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/fnmatch.h
===================================================================
--- uspace/lib/posix/include/posix/fnmatch.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/fnmatch.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Filename-matching.
+ */
+
+#ifndef POSIX_FNMATCH_H_
+#define POSIX_FNMATCH_H_
+
+/* Error Values */
+#undef FNM_NOMATCH
+#define FNM_NOMATCH 1
+
+/* Flags */
+#undef FNM_PATHNAME
+#undef FNM_PERIOD
+#undef FNM_NOESCAPE
+#define FNM_PATHNAME 1
+#define FNM_PERIOD 2
+#define FNM_NOESCAPE 4
+
+/* GNU Extensions */
+#undef FNM_FILE_NAME
+#undef FNM_LEADING_DIR
+#undef FNM_CASEFOLD
+#define FNM_FILE_NAME FNM_PATHNAME
+#define FNM_LEADING_DIR 8
+#define FNM_CASEFOLD 16
+
+extern int posix_fnmatch(const char *pattern, const char *string, int flags);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define fnmatch posix_fnmatch
+#endif
+
+#endif /* POSIX_FNMATCH_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/getopt.h
===================================================================
--- uspace/lib/posix/include/posix/getopt.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/getopt.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 Command line argument parsing.
+ */
+#ifndef POSIX_GETOPT_H
+#define POSIX_GETOPT_H
+
+#include "unistd.h"
+
+/* Option Arguments */
+#define no_argument        0
+#define required_argument  1
+#define optional_argument  2
+
+#ifndef LIBPOSIX_INTERNAL
+struct option {
+	const char *name;
+	int has_arg;
+	int *flag;
+	int val;
+};
+#endif
+
+extern int posix_getopt_long(int, char * const [], const char *, const struct option *, int *);
+
+
+#ifndef LIBPOSIX_INTERNAL
+	#define getopt_long posix_getopt_long
+#endif
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/posix/include/posix/inttypes.h
===================================================================
--- uspace/lib/posix/include/posix/inttypes.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/inttypes.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,54 @@
+/*
+ * 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 Fixed size integer types.
+ */
+
+#ifndef POSIX_INTTYPES_H_
+#define POSIX_INTTYPES_H_
+
+#include "stdint.h"
+#include "libc/inttypes.h"
+
+extern posix_intmax_t posix_strtoimax(const char *restrict nptr,
+    char **restrict endptr, int base);
+extern posix_uintmax_t posix_strtoumax(const char *restrict nptr,
+    char **restrict endptr, int base);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define strtoimax posix_strtoimax
+	#define strtoumax posix_strtoumax
+#endif
+
+#endif /* POSIX_INTTYPES_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/iso646.h
===================================================================
--- uspace/lib/posix/include/posix/iso646.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/iso646.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Alternative spellings.
+ */
+
+#ifndef POSIX_ISO646_H_
+#define POSIX_ISO646_H_
+
+#define and &&
+#define and_eq &=
+#define bitand &
+#define bitor |
+#define compl ˜
+#define not !
+#define not_eq !=
+#define or ||
+#define or_eq |=
+#define xor ^
+#define xor_eq ^=
+
+#endif /* POSIX_ISO646_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/limits.h
===================================================================
--- uspace/lib/posix/include/posix/limits.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/limits.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,54 @@
+/*
+ * 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 Implementation-defined limit constants.
+ */
+
+#ifndef POSIX_LIMITS_H_
+#define POSIX_LIMITS_H_
+
+#include "stdint.h"
+#include "libc/sys/types.h"
+
+#undef SHRT_MIN
+#undef SHRT_MAX
+#undef USHRT_MAX
+#define SHRT_MIN SHORT_MIN
+#define SHRT_MAX SHORT_MAX
+#define USHRT_MAX USHORT_MAX
+
+#undef PATH_MAX
+#define PATH_MAX 256
+
+#endif /* POSIX_LIMITS_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/locale.h
===================================================================
--- uspace/lib/posix/include/posix/locale.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/locale.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Locale-specific definitions.
+ */
+
+#ifndef POSIX_LOCALE_H_
+#define POSIX_LOCALE_H_
+
+#ifndef NULL
+	#define NULL ((void *) 0)
+#endif
+
+#ifndef __locale_t_defined
+	#define __locale_t_defined
+	typedef struct __posix_locale *posix_locale_t;
+	#ifndef LIBPOSIX_INTERNAL
+		#define locale_t posix_locale_t
+	#endif
+#endif
+
+#undef LC_ALL
+#undef LC_COLLATE
+#undef LC_CTYPE
+#undef LC_MESSAGES
+#undef LC_MONETARY
+#undef LC_NUMERIC
+#undef LC_TIME
+#define LC_ALL 0
+#define LC_COLLATE 1
+#define LC_CTYPE 2
+#define LC_MESSAGES 3
+#define LC_MONETARY 4
+#define LC_NUMERIC 5
+#define LC_TIME 6
+
+#undef LC_COLLATE_MASK
+#undef LC_CTYPE_MASK
+#undef LC_MESSAGES_MASK
+#undef LC_MONETARY_MASK
+#undef LC_NUMERIC_MASK
+#undef LC_TIME_MASK
+#undef LC_ALL_MASK
+#define LC_COLLATE_MASK (1 << 0)
+#define LC_CTYPE_MASK (1 << 1)
+#define LC_MESSAGES_MASK (1 << 2)
+#define LC_MONETARY_MASK (1 << 3)
+#define LC_NUMERIC_MASK (1 << 4)
+#define LC_TIME_MASK (1 << 5)
+#define LC_ALL_MASK (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MESSAGES_MASK | \
+    LC_MONETARY_MASK | LC_NUMERIC_MASK | LC_TIME_MASK)
+
+#undef LC_GLOBAL_LOCALE
+#define LC_GLOBAL_LOCALE NULL
+
+struct posix_lconv {
+	char *currency_symbol;
+	char *decimal_point;
+	char  frac_digits;
+	char *grouping;
+	char *int_curr_symbol;
+	char  int_frac_digits;
+	char  int_n_cs_precedes;
+	char  int_n_sep_by_space;
+	char  int_n_sign_posn;
+	char  int_p_cs_precedes;
+	char  int_p_sep_by_space;
+	char  int_p_sign_posn;
+	char *mon_decimal_point;
+	char *mon_grouping;
+	char *mon_thousands_sep;
+	char *negative_sign;
+	char  n_cs_precedes;
+	char  n_sep_by_space;
+	char  n_sign_posn;
+	char *positive_sign;
+	char  p_cs_precedes;
+	char  p_sep_by_space;
+	char  p_sign_posn;
+	char *thousands_sep;
+};
+
+extern char *posix_setlocale(int category, const char *locale);
+extern struct posix_lconv *posix_localeconv(void);
+
+/* POSIX Extensions */
+extern posix_locale_t posix_duplocale(posix_locale_t locobj);
+extern void posix_freelocale(posix_locale_t locobj);
+extern posix_locale_t posix_newlocale(int category_mask, const char *locale,
+    posix_locale_t base);
+extern posix_locale_t posix_uselocale(posix_locale_t newloc);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define lconv posix_lconv
+
+	#define setlocale posix_setlocale
+	#define localeconv posix_localeconv
+
+	#define newlocale posix_newlocale
+	#define uselocale posix_uselocale
+	#define duplocale posix_duplocale
+	#define freelocale posix_freelocale
+#endif
+
+#endif /* POSIX_LOCALE_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/malloc.h
===================================================================
--- uspace/lib/posix/include/posix/malloc.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/malloc.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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
+ * @{
+ */
+#ifndef POSIX_MALLOC_H_
+#define POSIX_MALLOC_H_
+
+/* Empty. Just to satisfy preprocessor. */
+
+#endif /* POSIX_MALLOC_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/math.h
===================================================================
--- uspace/lib/posix/include/posix/math.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/math.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,50 @@
+/*
+ * 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 Mathematical operations.
+ */
+
+#ifndef POSIX_MATH_H_
+#define POSIX_MATH_H_
+
+/* Normalization Functions */
+extern double posix_ldexp(double x, int exp);
+extern double posix_frexp(double num, int *exp);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define ldexp posix_ldexp
+	#define frexp posix_frexp
+#endif
+
+#endif /* POSIX_MATH_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/pwd.h
===================================================================
--- uspace/lib/posix/include/posix/pwd.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/pwd.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Password handling.
+ */
+
+#ifndef POSIX_PWD_H_
+#define POSIX_PWD_H_
+
+#include "sys/types.h"
+
+struct posix_passwd {
+	char *pw_name;
+	posix_uid_t pw_uid;
+	posix_gid_t pw_gid;
+	char *pw_dir;
+	char *pw_shell;
+};
+
+extern struct posix_passwd *posix_getpwent(void);
+extern void posix_setpwent(void);
+extern void posix_endpwent(void);
+
+extern struct posix_passwd *posix_getpwnam(const char *name);
+extern int posix_getpwnam_r(const char *name, struct posix_passwd *pwd,
+    char *buffer, size_t bufsize, struct posix_passwd **result);
+
+extern struct posix_passwd *posix_getpwuid(posix_uid_t uid);
+extern int posix_getpwuid_r(posix_uid_t uid, struct posix_passwd *pwd,
+    char *buffer, size_t bufsize, struct posix_passwd **result);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define passwd posix_passwd
+	
+	#define getpwent posix_getpwent
+	#define setpwent posix_setpwent
+	#define endpwent posix_endpwent
+
+	#define getpwnam posix_getpwnam
+	#define getpwnam_r posix_getpwnam_r
+
+	#define getpwuid posix_getpwuid
+	#define getpwuid_r posix_getpwuid_r
+#endif
+
+#endif /* POSIX_PWD_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/signal.h
===================================================================
--- uspace/lib/posix/include/posix/signal.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/signal.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Signal handling.
+ */
+
+#ifndef POSIX_SIGNAL_H_
+#define POSIX_SIGNAL_H_
+
+#include "sys/types.h"
+
+extern void __posix_default_signal_handler(int signo);
+extern void __posix_hold_signal_handler(int signo);
+extern void __posix_ignore_signal_handler(int signo);
+
+#undef SIG_DFL
+#define SIG_DFL ((void (*)(int)) __posix_default_signal_handler)
+#undef SIG_ERR
+#define SIG_ERR ((void (*)(int)) NULL)
+#undef SIG_HOLD
+#define SIG_HOLD ((void (*)(int)) __posix_hold_signal_handler)
+#undef SIG_IGN
+#define SIG_IGN ((void (*)(int)) __posix_ignore_signal_handler)
+
+typedef int posix_sig_atomic_t;
+typedef uint32_t posix_sigset_t;
+typedef struct posix_mcontext {
+	/* must not be empty to avoid compiler warnings (-pedantic) */
+	int dummy;
+} posix_mcontext_t;
+
+union posix_sigval {
+	int sival_int;
+	void *sival_ptr;
+};
+
+struct posix_sigevent {
+	int sigev_notify; /* Notification type. */
+	int sigev_signo; /* Signal number. */
+	union posix_sigval sigev_value; /* Signal value. */
+	void (*sigev_notify_function)(union posix_sigval); /* Notification function. */
+	posix_thread_attr_t *sigev_notify_attributes; /* Notification attributes. */
+};
+
+typedef struct {
+	int si_signo;
+	int si_code;
+
+	int si_errno;
+
+	posix_pid_t si_pid;
+	posix_uid_t si_uid;
+	void *si_addr;
+	int si_status;
+
+	long si_band;
+
+	union posix_sigval si_value;
+} posix_siginfo_t;
+
+struct posix_sigaction {
+	void (*sa_handler)(int);
+	posix_sigset_t sa_mask;
+	int sa_flags;
+	void (*sa_sigaction)(int, posix_siginfo_t *, void *);
+};
+
+typedef struct {
+	void *ss_sp;
+	size_t ss_size;
+	int ss_flags;
+} posix_stack_t;
+
+typedef struct posix_ucontext {
+	struct posix_ucontext *uc_link;
+	posix_sigset_t uc_sigmask;
+	posix_stack_t uc_stack;
+	posix_mcontext_t uc_mcontext;
+} posix_ucontext_t;
+
+/* Values of posix_sigevent::sigev_notify */
+#undef SIGEV_NONE
+#undef SIGEV_SIGNAL
+#undef SIGEV_THREAD
+#define SIGEV_NONE 0
+#define SIGEV_SIGNAL 0
+#define SIGEV_THREAD 0
+
+#undef SIGRT_MIN
+#undef SIGRT_MAX
+#define SIGRT_MIN 0
+#define SIGRT_MAX 0
+
+#undef SIG_BLOCK
+#undef SIG_UNBLOCK
+#undef SIG_SETMASK
+#define SIG_BLOCK 0
+#define SIG_UNBLOCK 1
+#define SIG_SETMASK 2
+
+#undef SA_NOCLDSTOP
+#undef SA_ONSTACK
+#undef SA_RESETHAND
+#undef SA_RESTART
+#undef SA_SIGINFO
+#undef SA_NOCLDWAIT
+#undef SA_NODEFER
+#define SA_NOCLDSTOP (1 << 0)
+#define SA_ONSTACK (1 << 1)
+#define SA_RESETHAND (1 << 2)
+#define SA_RESTART (1 << 3)
+#define SA_SIGINFO (1 << 4)
+#define SA_NOCLDWAIT (1 << 5)
+#define SA_NODEFER (1 << 6)
+
+#undef SS_ONSTACK
+#undef SS_DISABLE
+#define SS_ONSTACK 0
+#define SS_DISABLE 0
+
+#undef MINSIGSTKSZ
+#undef SIGSTKSZ
+#define MINSIGSTKSZ 0
+#define SIGSTKSZ 0
+
+/* Full POSIX set */
+enum {
+	/* Termination Signals */
+	SIGABRT,
+	SIGQUIT,
+	SIGINT,
+	SIGTERM,
+	
+	/* Child Signal */
+	SIGCHLD,
+	
+	/* User signals */
+	SIGUSR1,
+	SIGUSR2,
+
+	/* Timer */
+	SIGALRM,
+	SIGVTALRM,
+	SIGPROF, /* obsolete */
+
+	_TOP_CATCHABLE_SIGNAL = SIGPROF,
+
+	/* Process Scheduler Interaction - not supported */
+	SIGSTOP,
+	SIGCONT,
+
+	/* Process Termination - can't be caught */
+	SIGKILL,
+
+	_TOP_SENDABLE_SIGNAL = SIGKILL,
+
+	/* Hardware Exceptions - can't be caught or sent */
+	SIGFPE,
+	SIGBUS,
+	SIGILL,
+	SIGSEGV,
+
+	/* Other Exceptions - not supported */
+	SIGSYS,
+	SIGXCPU,
+	SIGXFSZ,
+
+	/* Debugging - not supported */
+	SIGTRAP,
+
+	/* Communication Signals - not supported */
+	SIGHUP,
+	SIGPIPE,
+	SIGPOLL, /* obsolete */
+	SIGURG,
+
+	/* Terminal Signals - not supported */
+	SIGTSTP,
+	SIGTTIN,
+	SIGTTOU,
+	
+	_TOP_SIGNAL = SIGTTOU
+};
+
+/* Values for sigaction field si_code. */
+enum {
+	SI_USER,
+	SI_QUEUE,
+	SI_TIMER,
+	SI_ASYNCIO,
+	SI_MESGQ,
+	ILL_ILLOPC,
+	ILL_ILLOPN,
+	ILL_ILLADR,
+	ILL_ILLTRP,
+	ILL_PRVOPC,
+	ILL_PRVREG,
+	ILL_COPROC,
+	ILL_BADSTK,
+	FPE_INTDIV,
+	FPE_INTOVF,
+	FPE_FLTDIV,
+	FPE_FLTOVF,
+	FPE_FLTUND,
+	FPE_FLTRES,
+	FPE_FLTINV,
+	FPE_FLTSUB,
+	SEGV_MAPERR,
+	SEGV_ACCERR,
+	BUS_ADRALN,
+	BUS_ADRERR,
+	BUS_OBJERR,
+	TRAP_BRKPT,
+	TRAP_TRACE,
+	CLD_EXITED,
+	CLD_KILLED,
+	CLD_DUMPED,
+	CLD_TRAPPED,
+	CLD_STOPPED,
+	CLD_CONTINUED,
+	POLL_IN,
+	POLL_OUT,
+	POLL_MSG,
+	POLL_ERR,
+	POLL_PRI,
+	POLL_HUP
+};
+
+extern int posix_sigaction(int sig, const struct posix_sigaction *restrict act,
+    struct posix_sigaction *restrict oact);
+
+extern void (*posix_signal(int sig, void (*func)(int)))(int);
+extern int posix_raise(int sig);
+extern int posix_kill(posix_pid_t pid, int sig);
+extern int posix_killpg(posix_pid_t pid, int sig);
+
+extern void posix_psiginfo(const posix_siginfo_t *pinfo, const char *message);
+extern void posix_psignal(int signum, const char *message);
+
+extern int posix_sigemptyset(posix_sigset_t *set);
+extern int posix_sigfillset(posix_sigset_t *set);
+extern int posix_sigaddset(posix_sigset_t *set, int signo);
+extern int posix_sigdelset(posix_sigset_t *set, int signo);
+extern int posix_sigismember(const posix_sigset_t *set, int signo);
+
+extern int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
+    posix_sigset_t *restrict oset);
+extern int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
+    posix_sigset_t *restrict oset);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define sig_atomic_t posix_sig_atomic_t
+	#define sigset_t posix_sigset_t
+	#define sigval posix_sigval
+	#ifndef sigevent
+		#define sigevent posix_sigevent
+	#endif
+	#define mcontext_t posix_mcontext_t
+	#define ucontext_t posix_ucontext_t
+	#define stack_t posix_stack_t
+	#define siginfo_t posix_siginfo_t
+
+	#define sigaction posix_sigaction
+
+	#define signal posix_signal
+	#define raise posix_raise
+	#define kill posix_kill
+	#define killpg posix_killpg
+
+	#define psiginfo posix_psiginfo
+	#define psignal posix_psignal
+
+	#define sigemptyset posix_sigemptyset
+	#define sigfillset posix_sigfillset
+	#define sigaddset posix_sigaddset
+	#define sigdelset posix_sigdelset
+	#define sigismember posix_sigismember
+
+	#define pthread_sigmask posix_thread_sigmask
+	#define sigprocmask posix_sigprocmask
+#endif
+
+#endif /* POSIX_SIGNAL_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/stdarg.h
===================================================================
--- uspace/lib/posix/include/posix/stdarg.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/stdarg.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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
+ * @{
+ */
+
+#ifndef POSIX_STDARG_H_
+#define POSIX_STDARG_H_
+
+typedef __builtin_va_list va_list;
+
+#define va_start(ap, last)  __builtin_va_start(ap, last)
+#define va_arg(ap, type)    __builtin_va_arg(ap, type)
+#define va_end(ap)          __builtin_va_end(ap)
+#define va_copy(dst, src)   __builtin_va_copy(dst, src)
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/stdbool.h
===================================================================
--- uspace/lib/posix/include/posix/stdbool.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/stdbool.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Boolean type and values.
+ */
+
+#ifndef POSIX_STDBOOL_H_
+#define POSIX_STDBOOL_H_
+
+#ifdef LIBC_BOOL_H_
+
+#if (!defined(POSIX_STDIO_H_)) && \
+    (!defined(POSIX_STDLIB_H_)) && \
+    (!defined(POSIX_STRING_H_))
+	#error "You can't include bool.h and stdbool.h at the same time."
+#endif
+
+#endif /* LIBC_BOOL_H */
+
+#define LIBC_BOOL_H_
+
+#define bool _Bool
+#define true 1
+#define false 0
+#define __bool_true_false_are_defined 1
+
+#endif /* POSIX_STDBOOL_H_ */
Index: uspace/lib/posix/include/posix/stddef.h
===================================================================
--- uspace/lib/posix/include/posix/stddef.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/stddef.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,55 @@
+/*
+ * 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 type definitions.
+ */
+
+#ifndef POSIX_STDDEF_H_
+#define POSIX_STDDEF_H_
+
+#include "sys/types.h"
+
+#ifndef NULL
+	#define NULL  ((void *) 0)
+#endif
+
+#define offsetof(type,member) ((size_t) &(((type *) 0)->member))
+
+typedef ssize_t posix_ptrdiff_t;
+
+#ifndef LIBPOSIX_INTERNAL
+	#define ptrdiff_t posix_ptrdiff_t
+#endif
+
+#endif /* POSIX_STDDEF_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/stdint.h
===================================================================
--- uspace/lib/posix/include/posix/stdint.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/stdint.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,113 @@
+/*
+ * 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 Integer types.
+ */
+
+#ifndef POSIX_STDINT_H_
+#define POSIX_STDINT_H_
+
+#include "libc/stdint.h"
+
+#undef INT8_MAX
+#undef INT8_MIN
+#define INT8_MAX  127
+#define INT8_MIN  (-128)
+
+#undef UINT8_MAX
+#undef UINT8_MIN
+#define UINT8_MAX  255
+#define UINT8_MIN  0
+
+#undef INT16_MAX
+#undef INT16_MIN
+#define INT16_MAX  32767
+#define INT16_MIN  (-32768)
+
+#undef UINT16_MAX
+#undef UINT16_MIN
+#define UINT16_MAX  65535
+#define UINT16_MIN  0
+
+#undef INT32_MAX
+#undef INT32_MIN
+#define INT32_MAX  2147483647
+#define INT32_MIN  (-INT32_MAX - 1)
+
+#undef UINT32_MAX
+#undef UINT32_MIN
+#define UINT32_MAX  4294967295U
+#define UINT32_MIN  0U
+
+#undef INT64_MAX
+#undef INT64_MIN
+#define INT64_MAX  9223372036854775807LL
+#define INT64_MIN  (-INT64_MAX - 1LL)
+
+#undef UINT64_MAX
+#undef  UINT64_MIN
+#define UINT64_MAX  18446744073709551615ULL
+#define UINT64_MIN  0ULL
+
+#undef OFF64_MAX
+#undef OFF64_MIN
+#define OFF64_MAX  INT64_MAX
+#define OFF64_MIN  INT64_MIN
+
+#undef AOFF64_MAX
+#undef AOFF64_MIN
+#define AOFF64_MAX  UINT64_MAX
+#define AOFF64_MIN  UINT64_MIN
+
+#undef INTMAX_MIN
+#undef INTMAX_MAX
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+
+#undef UINTMAX_MIN
+#undef UINTMAX_MAX
+#define UINTMAX_MIN UINT64_MIN
+#define UINTMAX_MAX UINT64_MAX
+
+#include "libc/sys/types.h"
+
+typedef int64_t posix_intmax_t;
+typedef uint64_t posix_uintmax_t;
+
+#ifndef LIBPOSIX_INTERNAL
+	#define intmax_t posix_intmax_t
+	#define uintmax_t posix_uintmax_t
+#endif
+
+#endif /* POSIX_STDINT_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/stdio.h
===================================================================
--- uspace/lib/posix/include/posix/stdio.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/stdio.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,258 @@
+/*
+ * 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.
+ */
+
+#ifndef POSIX_STDIO_H_
+#define POSIX_STDIO_H_
+
+#include "stddef.h"
+#include "unistd.h"
+#include "libc/io/verify.h"
+#include "sys/types.h"
+#include "stdarg.h"
+#include "limits.h"
+
+/*
+ * These are the same as in HelenOS libc.
+ * It would be possible to directly include <stdio.h> but
+ * it is better not to pollute POSIX namespace with other functions
+ * defined in that header.
+ *
+ * Because libposix is always linked with libc, providing only these
+ * forward declarations ought to be enough.
+ */
+#define EOF (-1)
+
+#define BUFSIZ  4096
+#define SEEK_SET  0
+#define SEEK_CUR  1
+#define SEEK_END  2
+
+typedef struct _IO_FILE FILE;
+
+extern FILE *stdin;
+extern FILE *stdout;
+extern FILE *stderr;
+
+extern int fgetc(FILE *);
+extern char *fgets(char *, int, FILE *);
+
+extern int getchar(void);
+extern char *gets(char *, size_t);
+
+extern int fputc(wchar_t, FILE *);
+extern int fputs(const char *, FILE *);
+
+extern int putchar(wchar_t);
+extern int puts(const char *);
+
+extern int fprintf(FILE *, const char*, ...) PRINTF_ATTRIBUTE(2, 3);
+extern int vfprintf(FILE *, const char *, va_list);
+
+extern int printf(const char *, ...) PRINTF_ATTRIBUTE(1, 2);
+extern int vprintf(const char *, va_list);
+
+extern int snprintf(char *, size_t , const char *, ...) PRINTF_ATTRIBUTE(3, 4);
+#ifdef _GNU_SOURCE
+extern int asprintf(char **, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
+#endif
+extern int vsnprintf(char *, size_t, const char *, va_list);
+
+extern FILE *fopen(const char *, const char *);
+extern FILE *fdopen(int, const char *);
+extern int fclose(FILE *);
+
+extern size_t fread(void *, size_t, size_t, FILE *);
+extern size_t fwrite(const void *, size_t, size_t, FILE *);
+
+extern int fseek(FILE *, off64_t, int);
+extern void rewind(FILE *);
+extern off64_t ftell(FILE *);
+extern int feof(FILE *);
+extern int fileno(FILE *);
+
+extern int fflush(FILE *);
+extern int ferror(FILE *);
+extern void clearerr(FILE *);
+
+extern void setvbuf(FILE *, void *, int, size_t);
+
+
+/* POSIX specific stuff. */
+
+/* Identifying the Terminal */
+#undef L_ctermid
+#define L_ctermid PATH_MAX
+extern char *posix_ctermid(char *s);
+
+/* Error Recovery */
+extern void posix_clearerr(FILE *stream);
+
+/* Input/Output */
+#undef putc
+#define putc fputc
+extern int posix_fputs(const char *restrict s, FILE *restrict stream);
+#undef getc
+#define getc fgetc
+extern int posix_ungetc(int c, FILE *stream);
+extern ssize_t posix_getdelim(char **restrict lineptr, size_t *restrict n,
+    int delimiter, FILE *restrict stream);
+extern ssize_t posix_getline(char **restrict lineptr, size_t *restrict n,
+    FILE *restrict stream);
+
+/* Opening Streams */
+extern FILE *posix_freopen(const char *restrict filename,
+    const char *restrict mode, FILE *restrict stream);
+
+/* Error Messages */
+extern void posix_perror(const char *s);
+
+/* File Positioning */
+typedef struct _posix_fpos posix_fpos_t;
+extern int posix_fsetpos(FILE *stream, const posix_fpos_t *pos);
+extern int posix_fgetpos(FILE *restrict stream, posix_fpos_t *restrict pos);
+extern int posix_fseek(FILE *stream, long offset, int whence);
+extern int posix_fseeko(FILE *stream, posix_off_t offset, int whence);
+extern long posix_ftell(FILE *stream);
+extern posix_off_t posix_ftello(FILE *stream);
+
+/* Flushing Buffers */
+extern int posix_fflush(FILE *stream);
+
+/* Formatted Output */
+extern int posix_dprintf(int fildes, const char *restrict format, ...)
+    PRINTF_ATTRIBUTE(2, 3);
+extern int posix_vdprintf(int fildes, const char *restrict format, va_list ap);
+extern int posix_sprintf(char *restrict s, const char *restrict format, ...)
+    PRINTF_ATTRIBUTE(2, 3);
+extern int posix_vsprintf(char *restrict s, const char *restrict format, va_list ap);
+
+/* Formatted Input */
+extern int posix_fscanf(
+    FILE *restrict stream, const char *restrict format, ...);
+extern int posix_vfscanf(
+    FILE *restrict stream, const char *restrict format, va_list arg);
+extern int posix_scanf(const char *restrict format, ...);
+extern int posix_vscanf(const char *restrict format, va_list arg);
+extern int posix_sscanf(
+    const char *restrict s, const char *restrict format, ...);
+extern int posix_vsscanf(
+    const char *restrict s, const char *restrict format, va_list arg);
+
+/* File Locking */
+extern void posix_flockfile(FILE *file);
+extern int posix_ftrylockfile(FILE *file);
+extern void posix_funlockfile(FILE *file);
+extern int posix_getc_unlocked(FILE *stream);
+extern int posix_getchar_unlocked(void);
+extern int posix_putc_unlocked(int c, FILE *stream);
+extern int posix_putchar_unlocked(int c);
+
+/* Deleting Files */
+extern int posix_remove(const char *path);
+
+/* Renaming Files */
+extern int posix_rename(const char *old, const char *new);
+
+/* Temporary Files */
+#undef L_tmpnam
+#define L_tmpnam PATH_MAX
+extern char *posix_tmpnam(char *s);
+extern char *posix_tempnam(const char *dir, const char *pfx);
+extern FILE *posix_tmpfile(void);
+
+#ifndef LIBPOSIX_INTERNAL
+	/* DEBUG macro does not belong to POSIX stdio.h. Its unconditional
+	 * definition in the native stdio.h causes unexpected behaviour of
+	 * applications which uses their own DEBUG macro (e.g. debugging
+	 * output is printed even if not desirable). */
+	#undef DEBUG
+
+	#define ctermid posix_ctermid
+
+	#define clearerr posix_clearerr
+
+	#define fputs posix_fputs
+	#define ungetc posix_ungetc
+	#define getdelim posix_getdelim
+	#define getline posix_getline
+
+	#define freopen posix_freopen
+
+	#define perror posix_perror
+
+	#define fpos_t posix_fpos_t
+	#define fsetpos posix_fsetpos
+	#define fgetpos posix_fgetpos
+	#define fseek posix_fseek
+	#define fseeko posix_fseeko
+	#define ftell posix_ftell
+	#define ftello posix_ftello
+
+	#define fflush posix_fflush
+
+	#define dprintf posix_dprintf
+	#define vdprintf posix_vdprintf
+	#define sprintf posix_sprintf
+	#define vsprintf posix_vsprintf
+
+	#define fscanf posix_fscanf
+	#define vfscanf posix_vfscanf
+	#define vscanf posix_vscanf
+	#define scanf posix_scanf
+	#define sscanf posix_sscanf
+	#define vsscanf posix_vsscanf
+
+	#define flockfile posix_flockfile
+	#define ftrylockfile posix_ftrylockfile
+	#define funlockfile posix_funlockfile
+
+	#define getc_unlocked posix_getc_unlocked
+	#define getchar_unlocked posix_getchar_unlocked
+	#define putc_unlocked posix_putc_unlocked
+	#define putchar_unlocked posix_putchar_unlocked
+
+	#define remove posix_remove
+
+	#define rename posix_rename
+
+	#define tmpnam posix_tmpnam
+	#define tempnam posix_tempnam
+	#define tmpfile posix_tmpfile
+#endif
+
+#endif /* POSIX_STDIO_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/stdlib.h
===================================================================
--- uspace/lib/posix/include/posix/stdlib.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/stdlib.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 library definitions.
+ */
+
+#ifndef POSIX_STDLIB_H_
+#define POSIX_STDLIB_H_
+
+#include "sys/types.h"
+
+#ifndef NULL
+	#define NULL  ((void *) 0)
+#endif
+
+/* Process Termination */
+#undef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#undef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#define _Exit exit
+extern int posix_atexit(void (*func)(void));
+extern void exit(int status);
+extern void abort(void) __attribute__((noreturn));
+
+/* Absolute Value */
+extern int posix_abs(int i);
+extern long posix_labs(long i);
+extern long long posix_llabs(long long i);
+
+/* Integer Division */
+
+typedef struct {
+	int quot, rem;
+} posix_div_t;
+
+typedef struct {
+	long quot, rem;
+} posix_ldiv_t;
+
+typedef struct {
+	long long quot, rem;
+} posix_lldiv_t;
+
+extern posix_div_t posix_div(int numer, int denom);
+extern posix_ldiv_t posix_ldiv(long numer, long denom);
+extern posix_lldiv_t posix_lldiv(long long numer, long long denom);
+
+/* Array Functions */
+extern void posix_qsort(void *array, size_t count, size_t size,
+    int (*compare)(const void *, const void *));
+extern void *posix_bsearch(const void *key, const void *base,
+    size_t nmemb, size_t size, int (*compar)(const void *, const void *));
+
+/* Environment Access */
+extern char *posix_getenv(const char *name);
+extern int posix_putenv(char *string);
+extern int posix_system(const char *string);
+
+/* Symbolic Links */
+extern char *posix_realpath(const char *restrict name, char *restrict resolved);
+
+/* Floating Point Conversion */
+extern double posix_atof(const char *nptr);
+extern float posix_strtof(const char *restrict nptr, char **restrict endptr);
+extern double posix_strtod(const char *restrict nptr, char **restrict endptr);
+extern long double posix_strtold(const char *restrict nptr, char **restrict endptr);
+
+/* Integer Conversion */
+extern int posix_atoi(const char *nptr);
+extern long int posix_atol(const char *nptr);
+extern long long int posix_atoll(const char *nptr);
+extern long int posix_strtol(const char *restrict nptr,
+    char **restrict endptr, int base);
+extern long long int posix_strtoll(const char *restrict nptr,
+    char **restrict endptr, int base);
+extern unsigned long int posix_strtoul(const char *restrict nptr,
+    char **restrict endptr, int base);
+extern unsigned long long int posix_strtoull(
+    const char *restrict nptr, char **restrict endptr, int base);
+
+/* Memory Allocation */
+extern void *posix_malloc(size_t size);
+extern void *posix_calloc(size_t nelem, size_t elsize);
+extern void *posix_realloc(void *ptr, size_t size);
+extern void posix_free(void *ptr);
+
+/* Temporary Files */
+extern int posix_mkstemp(char *tmpl);
+
+/* Legacy Declarations */
+extern char *posix_mktemp(char *tmpl);
+extern int bsd_getloadavg(double loadavg[], int nelem);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define atexit posix_atexit
+
+	#define abs posix_abs
+	#define labs posix_labs
+	#define llabs posix_llabs
+
+	#define div_t posix_div_t
+	#define ldiv_t posix_ldiv_t
+	#define lldiv_t posix_lldiv_t
+	#define div posix_div
+	#define ldiv posix_ldiv
+	#define lldiv posix_lldiv
+
+	#define qsort posix_qsort
+	#define bsearch posix_bsearch
+
+	#define getenv posix_getenv
+	#define putenv posix_putenv
+	#define system posix_system
+
+	#define realpath posix_realpath
+	
+	#define atof posix_atof
+	#define strtof posix_strtof
+	#define strtod posix_strtod
+	#define strtold posix_strtold
+	
+	#define atoi posix_atoi
+	#define atol posix_atol
+	#define atoll posix_atoll
+	#define strtol posix_strtol
+	#define strtoll posix_strtoll
+	#define strtoul posix_strtoul
+	#define strtoull posix_strtoull
+
+	#define malloc posix_malloc
+	#define calloc posix_calloc
+	#define realloc posix_realloc
+	#define free posix_free
+
+	#define mkstemp posix_mkstemp
+
+	#define mktemp posix_mktemp
+	#define getloadavg bsd_getloadavg
+#endif
+
+#endif  // POSIX_STDLIB_H_
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/string.h
===================================================================
--- uspace/lib/posix/include/posix/string.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/string.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 String manipulation.
+ */
+
+#ifndef POSIX_STRING_H_
+#define POSIX_STRING_H_
+
+#include "sys/types.h"
+
+/*
+ * TODO: not implemented due to missing locale support
+ *
+ * int      strcoll_l(const char *, const char *, locale_t);
+ * char    *strerror_l(int, locale_t);
+ * size_t   strxfrm_l(char *restrict, const char *restrict, size_t, locale_t);
+ */
+
+#ifndef NULL
+	#define NULL  ((void *) 0)
+#endif
+
+/*
+ * These are the same as in HelenOS libc.
+ * It would be possible to directly include <str.h> and <mem.h> but
+ * it is better not to pollute POSIX namespace with other functions
+ * defined in that header.
+ *
+ * Because libposix is always linked with libc, providing only these
+ * forward declarations ought to be enough.
+ */
+/* From str.h. */
+extern char * strtok_r(char *, const char *, char **);
+extern char * strtok(char *, const char *);
+
+/* From mem.h */
+#define bzero(ptr, len)  memset((ptr), 0, (len))
+extern void *memset(void *, int, size_t);
+extern void *memcpy(void *, const void *, size_t);
+extern void *memmove(void *, const void *, size_t);
+
+
+/* Copying and Concatenation */
+extern char *posix_strcpy(char *restrict dest, const char *restrict src);
+extern char *posix_strncpy(char *restrict dest, const char *restrict src, size_t n);
+extern char *posix_stpcpy(char *restrict dest, const char *restrict src);
+extern char *posix_stpncpy(char *restrict dest, const char *restrict src, size_t n);
+extern char *posix_strcat(char *restrict dest, const char *restrict src);
+extern char *posix_strncat(char *restrict dest, const char *restrict src, size_t n);
+extern void *posix_memccpy(void *restrict dest, const void *restrict src, int c, size_t n);
+extern char *posix_strdup(const char *s);
+extern char *posix_strndup(const char *s, size_t n);
+
+/* String/Array Comparison */
+extern int posix_memcmp(const void *mem1, const void *mem2, size_t n);
+extern int posix_strcmp(const char *s1, const char *s2);
+extern int posix_strncmp(const char *s1, const char *s2, size_t n);
+
+/* Search Functions */
+extern void *posix_memchr(const void *mem, int c, size_t n);
+extern char *posix_strchr(const char *s, int c);
+extern char *posix_strrchr(const char *s, int c);
+extern char *gnu_strchrnul(const char *s, int c);
+extern char *posix_strpbrk(const char *s1, const char *s2);
+extern size_t posix_strcspn(const char *s1, const char *s2);
+extern size_t posix_strspn(const char *s1, const char *s2);
+extern char *posix_strstr(const char *haystack, const char *needle);
+
+/* Collation Functions */
+extern int posix_strcoll(const char *s1, const char *s2);
+extern size_t posix_strxfrm(char *restrict s1, const char *restrict s2, size_t n);
+
+/* Error Messages */
+extern char *posix_strerror(int errnum);
+extern int posix_strerror_r(int errnum, char *buf, size_t bufsz);
+
+/* String Length */
+extern size_t posix_strlen(const char *s);
+extern size_t posix_strnlen(const char *s, size_t n);
+
+/* Signal Messages */
+extern char *posix_strsignal(int signum);
+
+/* Legacy Declarations */
+#ifndef POSIX_STRINGS_H_
+extern int posix_ffs(int i);
+extern int posix_strcasecmp(const char *s1, const char *s2);
+extern int posix_strncasecmp(const char *s1, const char *s2, size_t n);
+#endif
+
+#ifndef LIBPOSIX_INTERNAL
+	#define strcpy posix_strcpy
+	#define strncpy posix_strncpy
+	#define stpcpy posix_stpcpy
+	#define stpncpy posix_stpncpy
+	#define strcat posix_strcat
+	#define strncat posix_strncat
+	#define memccpy posix_memccpy
+	#define strdup posix_strdup
+	#define strndup posix_strndup
+
+	#define memcmp posix_memcmp
+	#define strcmp posix_strcmp
+	#define strncmp posix_strncmp
+
+	#define memchr posix_memchr
+	#define strchr posix_strchr
+	#define strrchr posix_strrchr
+	#define strchrnul gnu_strchrnul
+	#define strpbrk posix_strpbrk
+	#define strcspn posix_strcspn
+	#define strspn posix_strspn
+	#define strstr posix_strstr
+
+	#define strcoll posix_strcoll
+	#define strxfrm posix_strxfrm
+
+	#define strerror posix_strerror
+	#define strerror_r posix_strerror_r
+
+	#define strlen posix_strlen
+	#define strnlen posix_strnlen
+
+	#define strsignal posix_strsignal
+
+	#define ffs posix_ffs
+	#define strcasecmp posix_strcasecmp
+	#define strncasecmp posix_strncasecmp
+#endif
+
+#endif  // POSIX_STRING_H_
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/strings.h
===================================================================
--- uspace/lib/posix/include/posix/strings.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/strings.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,80 @@
+/*
+ * 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 Additional string manipulation.
+ */
+
+#ifndef POSIX_STRINGS_H_
+#define POSIX_STRINGS_H_
+
+/* Search Functions */
+#ifndef POSIX_STRING_H_
+extern int posix_ffs(int i);
+#endif
+
+/* String/Array Comparison */
+#ifndef POSIX_STRING_H_
+extern int posix_strcasecmp(const char *s1, const char *s2);
+extern int posix_strncasecmp(const char *s1, const char *s2, size_t n);
+#endif
+
+/* TODO: not implemented due to missing locale support
+ *
+ * int strcasecmp_l(const char *, const char *, locale_t);
+ * int strncasecmp_l(const char *, const char *, size_t, locale_t);
+ */
+
+/* Legacy Functions */
+extern int posix_bcmp(const void *mem1, const void *mem2, size_t n);
+extern void posix_bcopy(const void *src, void *dest, size_t n);
+extern void posix_bzero(void *mem, size_t n);
+extern char *posix_index(const char *s, int c);
+extern char *posix_rindex(const char *s, int c);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define ffs posix_ffs
+
+	#define strcasecmp posix_strcasecmp
+	#define strncasecmp posix_strncasecmp
+
+	#define bcmp posix_bcmp
+	#define bcopy posix_bcopy
+	#undef bzero
+	#define bzero posix_bzero
+	#define index posix_index
+	#define rindex posix_rindex
+#endif
+
+#endif  // POSIX_STRINGS_H_
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/sys/mman.h
===================================================================
--- uspace/lib/posix/include/posix/sys/mman.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/sys/mman.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,64 @@
+/*
+ * 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 Memory management declarations.
+ */
+
+#ifndef POSIX_SYS_MMAN_H_
+#define POSIX_SYS_MMAN_H_
+
+#include "sys/types.h"
+#include <abi/mm/as.h>
+
+#define MAP_FAILED ((void *) -1)
+
+#define MAP_SHARED     (1 << 0)
+#define MAP_PRIVATE    (1 << 1)
+#define MAP_FIXED      (1 << 2)
+#define MAP_ANONYMOUS  (1 << 3)
+
+#undef PROT_NONE
+#undef PROT_READ
+#undef PROT_WRITE
+#undef PROT_EXEC
+#define PROT_NONE  0
+#define PROT_READ  AS_AREA_READ
+#define PROT_WRITE AS_AREA_WRITE
+#define PROT_EXEC  AS_AREA_EXEC
+
+extern void *mmap(void *start, size_t length, int prot, int flags, int fd,
+    posix_off_t offset);
+extern int munmap(void *start, size_t length);
+
+#endif /* POSIX_SYS_MMAN_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/sys/stat.h
===================================================================
--- uspace/lib/posix/include/posix/sys/stat.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/sys/stat.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,144 @@
+/*
+ * 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 File status handling.
+ */
+
+#ifndef POSIX_SYS_STAT_H_
+#define POSIX_SYS_STAT_H_
+
+#include "types.h"
+#include "../time.h"
+
+/* values are the same as on Linux */
+
+#undef S_IFMT
+#undef S_IFSOCK
+#undef S_IFLNK
+#undef S_IFREG
+#undef S_IFBLK
+#undef S_IFDIR
+#undef S_IFCHR
+#undef S_IFIFO
+#define S_IFMT     0170000   /* all file types */
+#define S_IFSOCK   0140000   /* socket */
+#define S_IFLNK    0120000   /* symbolic link */
+#define S_IFREG    0100000   /* regular file */
+#define S_IFBLK    0060000   /* block device */
+#define S_IFDIR    0040000   /* directory */
+#define S_IFCHR    0020000   /* character device */
+#define S_IFIFO    0010000   /* FIFO */
+
+#undef S_ISUID
+#undef S_ISGID
+#undef S_ISVTX
+#define S_ISUID    0004000   /* SUID */
+#define S_ISGID    0002000   /* SGID */
+#define S_ISVTX    0001000   /* sticky */
+
+#undef S_IRWXU
+#undef S_IRUSR
+#undef S_IWUSR
+#undef S_IXUSR
+#define S_IRWXU    00700     /* owner permissions */
+#define S_IRUSR    00400
+#define S_IWUSR    00200
+#define S_IXUSR    00100
+
+#undef S_IRWXG
+#undef S_IRGRP
+#undef S_IWGRP
+#undef S_IXGRP
+#define S_IRWXG    00070     /* group permissions */
+#define S_IRGRP    00040
+#define S_IWGRP    00020
+#define S_IXGRP    00010
+
+#undef S_IRWXO
+#undef S_IROTH
+#undef S_IWOTH
+#undef S_IXOTH
+#define S_IRWXO    00007     /* other permissions */
+#define S_IROTH    00004
+#define S_IWOTH    00002
+#define S_IXOTH    00001
+
+#undef S_ISREG
+#undef S_ISDIR
+#undef S_ISCHR
+#undef S_ISBLK
+#undef S_ISFIFO
+#undef S_ISLNK
+#undef S_ISSOCK
+#define S_ISREG(m) ((m & S_IFREG) != 0)
+#define S_ISDIR(m) ((m & S_IFDIR) != 0)
+#define S_ISCHR(m) ((m & S_IFCHR) != 0)
+#define S_ISBLK(m) ((m & S_IFBLK) != 0)
+#define S_ISFIFO(m) ((m & S_IFIFO) != 0)
+#define S_ISLNK(m) ((m & S_IFLNK) != 0) /* symbolic link? (Not in POSIX.1-1996.) */
+#define S_ISSOCK(m) ((m & S_IFSOCK) != 0) /* socket? (Not in POSIX.1-1996.) */
+
+struct posix_stat {
+	posix_dev_t     st_dev;     /* ID of device containing file */
+	posix_ino_t     st_ino;     /* inode number */
+	mode_t          st_mode;    /* protection */
+	posix_nlink_t   st_nlink;   /* number of hard links */
+	posix_uid_t     st_uid;     /* user ID of owner */
+	posix_gid_t     st_gid;     /* group ID of owner */
+	posix_dev_t     st_rdev;    /* device ID (if special file) */
+	posix_off_t     st_size;    /* total size, in bytes */
+	posix_blksize_t st_blksize; /* blocksize for file system I/O */
+	posix_blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
+	time_t          st_atime;   /* time of last access */
+	time_t          st_mtime;   /* time of last modification */
+	time_t          st_ctime;   /* time of last status change */
+};
+
+extern int posix_fstat(int fd, struct posix_stat *st);
+extern int posix_lstat(const char *restrict path, struct posix_stat *restrict st);
+extern int posix_stat(const char *restrict path, struct posix_stat *restrict st);
+extern int posix_chmod(const char *path, mode_t mode);
+extern mode_t posix_umask(mode_t mask);
+extern int mkdir(const char *, mode_t);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define fstat posix_fstat
+	#define lstat posix_lstat
+	#define stat posix_stat
+	#define chmod posix_chmod
+	#define umask posix_umask
+#endif
+
+#endif /* POSIX_SYS_STAT_H */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/sys/types.h
===================================================================
--- uspace/lib/posix/include/posix/sys/types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/sys/types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,79 @@
+/*
+ * 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 Data types definitions.
+ */
+
+#ifndef POSIX_SYS_TYPES_H_
+#define POSIX_SYS_TYPES_H_
+
+#include "libc/sys/types.h"
+#include "libc/sys/time.h"
+
+typedef unsigned int posix_ino_t;
+typedef unsigned int posix_nlink_t;
+typedef unsigned int posix_uid_t;
+typedef unsigned int posix_gid_t;
+typedef off64_t posix_off_t;
+typedef long posix_blksize_t;
+typedef long posix_blkcnt_t;
+typedef int64_t posix_pid_t;
+typedef sysarg_t posix_dev_t;
+
+/* PThread Types */
+typedef struct posix_thread_attr posix_thread_attr_t;
+
+/* Clock Types */
+typedef long posix_clock_t;
+typedef int posix_clockid_t;
+
+#ifndef LIBPOSIX_INTERNAL
+	#define ino_t posix_ino_t
+	#define nlink_t posix_nlink_t
+	#define uid_t posix_uid_t
+	#define gid_t posix_gid_t
+	#define off_t posix_off_t
+	#define blksize_t posix_blksize_t
+	#define blkcnt_t posix_blkcnt_t
+	#define pid_t posix_pid_t
+	#define dev_t posix_dev_t
+	
+	#define pthread_attr_t posix_thread_attr_t
+	
+	#define clock_t posix_clock_t
+	#define clockid_t posix_clockid_t
+#endif
+
+#endif /* POSIX_SYS_TYPES_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/sys/wait.h
===================================================================
--- uspace/lib/posix/include/posix/sys/wait.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/sys/wait.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,65 @@
+/*
+ * 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 Support for waiting.
+ */
+
+#ifndef POSIX_SYS_WAIT_H_
+#define POSIX_SYS_WAIT_H_
+
+#include "types.h"
+
+#undef WIFEXITED
+#undef WEXITSTATUS
+#undef WIFSIGNALED
+#undef WTERMSIG
+#define WIFEXITED(status) __posix_wifexited(status)
+#define WEXITSTATUS(status) __posix_wexitstatus(status)
+#define WIFSIGNALED(status) __posix_wifsignaled(status)
+#define WTERMSIG(status) __posix_wtermsig(status)
+
+extern int __posix_wifexited(int status);
+extern int __posix_wexitstatus(int status);
+extern int __posix_wifsignaled(int status);
+extern int __posix_wtermsig(int status);
+
+extern posix_pid_t posix_wait(int *stat_ptr);
+extern posix_pid_t posix_waitpid(posix_pid_t pid, int *stat_ptr, int options);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define wait posix_wait
+	#define waitpid posix_waitpid
+#endif
+
+#endif /* POSIX_SYS_WAIT_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/time.h
===================================================================
--- uspace/lib/posix/include/posix/time.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/time.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Time measurement support.
+ */
+
+#ifndef POSIX_TIME_H_
+#define POSIX_TIME_H_
+
+#include "sys/types.h"
+
+#ifndef NULL
+	#define NULL  ((void *) 0)
+#endif
+
+#ifndef CLOCKS_PER_SEC
+	#define CLOCKS_PER_SEC (1000000L)
+#endif
+
+#ifndef __locale_t_defined
+	#define __locale_t_defined
+	typedef struct __posix_locale *posix_locale_t;
+	#ifndef LIBPOSIX_INTERNAL
+		#define locale_t posix_locale_t
+	#endif
+#endif
+
+#ifndef POSIX_SIGNAL_H_
+	struct posix_sigevent;
+	#ifndef LIBPOSIX_INTERNAL
+		#define sigevent posix_sigevent
+	#endif
+#endif
+
+#undef CLOCK_REALTIME
+#define CLOCK_REALTIME ((posix_clockid_t) 0)
+
+struct posix_timespec {
+	time_t tv_sec; /* Seconds. */
+	long tv_nsec; /* Nanoseconds. */
+};
+
+struct posix_itimerspec {
+	struct posix_timespec it_interval; /* Timer period. */
+	struct posix_timespec it_value; /* Timer expiration. */
+};
+
+typedef struct __posix_timer *posix_timer_t;
+
+/* Timezones */
+extern int posix_daylight;
+extern long posix_timezone;
+extern char *posix_tzname[2];
+extern void posix_tzset(void);
+
+/* Broken-down Time */
+extern struct tm *posix_gmtime_r(const time_t *restrict timer,
+    struct tm *restrict result);
+extern struct tm *posix_gmtime(const time_t *restrict timep);
+extern struct tm *posix_localtime_r(const time_t *restrict timer,
+    struct tm *restrict result);
+extern struct tm *posix_localtime(const time_t *restrict timep);
+
+/* Formatting Calendar Time */
+extern char *posix_asctime_r(const struct tm *restrict timeptr,
+    char *restrict buf);
+extern char *posix_asctime(const struct tm *restrict timeptr);
+extern char *posix_ctime_r(const time_t *timer, char *buf);
+extern char *posix_ctime(const time_t *timer);
+
+/* Clocks */
+extern int posix_clock_getres(posix_clockid_t clock_id,
+    struct posix_timespec *res);
+extern int posix_clock_gettime(posix_clockid_t clock_id,
+    struct posix_timespec *tp);
+extern int posix_clock_settime(posix_clockid_t clock_id,
+    const struct posix_timespec *tp); 
+extern int posix_clock_nanosleep(posix_clockid_t clock_id, int flags,
+    const struct posix_timespec *rqtp, struct posix_timespec *rmtp);
+
+/* CPU Time */
+extern posix_clock_t posix_clock(void);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define timespec    posix_timespec
+	#define itimerspec  posix_itimerspec
+	#define timer_t     posix_timer_t
+
+	#define daylight    posix_daylight
+	#define timezone    posix_timezone
+	#define tzname      posix_tzname
+	#define tzset       posix_tzset
+
+	#define gmtime_r    posix_gmtime_r
+	#define gmtime      posix_gmtime
+	#define localtime_r posix_localtime_r
+	#define localtime   posix_localtime
+
+	#define asctime_r   posix_asctime_r
+	#define asctime     posix_asctime
+	#define ctime_r     posix_ctime_r
+	#define ctime       posix_ctime
+
+	#define clock_getres posix_clock_getres
+	#define clock_gettime posix_clock_gettime
+	#define clock_settime posix_clock_settime
+	#define clock_nanosleep posix_clock_nanosleep
+
+	#define clock posix_clock
+#endif
+
+#endif  // POSIX_TIME_H_
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/unistd.h
===================================================================
--- uspace/lib/posix/include/posix/unistd.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/include/posix/unistd.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,192 @@
+/*
+ * 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 Miscellaneous standard definitions.
+ */
+
+#ifndef POSIX_UNISTD_H_
+#define POSIX_UNISTD_H_
+
+#include "sys/types.h"
+#include "stddef.h"
+
+/* Process Termination */
+#define _exit exit
+
+extern char *posix_optarg;
+extern int optind, opterr, optopt;
+extern int posix_getopt(int, char * const [], const char *);
+
+/* Environment */
+extern char **posix_environ;
+
+/* Login Information */
+extern char *posix_getlogin(void);
+extern int posix_getlogin_r(char *name, size_t namesize);
+
+/* Identifying Terminals */
+extern int posix_isatty(int fd);
+
+/* Working Directory */
+extern char *posix_getcwd(char *buf, size_t size);
+extern int posix_chdir(const char *path);
+
+/* Query Memory Parameters */
+extern int posix_getpagesize(void);
+
+/* Process Identification */
+extern posix_pid_t posix_getpid(void);
+extern posix_uid_t posix_getuid(void);
+extern posix_gid_t posix_getgid(void);
+
+/* File Manipulation */
+extern int posix_close(int fildes);
+extern ssize_t posix_read(int fildes, void *buf, size_t nbyte);
+extern ssize_t posix_write(int fildes, const void *buf, size_t nbyte);
+extern int posix_fsync(int fildes);
+extern int posix_ftruncate(int fildes, posix_off_t length);
+extern int posix_rmdir(const char *path);
+extern int posix_unlink(const char *path);
+extern int posix_dup(int fildes);
+extern int posix_dup2(int fildes, int fildes2);
+
+/* Standard Streams */
+#undef STDIN_FILENO
+#define STDIN_FILENO (fileno(stdin))
+#undef STDOUT_FILENO
+#define STDOUT_FILENO (fileno(stdout))
+#undef STDERR_FILENO
+#define STDERR_FILENO (fileno(stderr))
+
+/* File Accessibility */
+#undef F_OK
+#undef X_OK
+#undef W_OK
+#undef R_OK
+#define	F_OK 0 /* Test for existence. */
+#define	X_OK 1 /* Test for execute permission. */
+#define	W_OK 2 /* Test for write permission. */
+#define	R_OK 4 /* Test for read permission. */
+extern int posix_access(const char *path, int amode);
+
+/* System Parameters */
+enum {
+	_SC_PHYS_PAGES,
+	_SC_AVPHYS_PAGES,
+	_SC_PAGESIZE,
+	_SC_CLK_TCK
+};
+extern long posix_sysconf(int name);
+
+/* Path Configuration Parameters */
+enum {
+	_PC_2_SYMLINKS,
+	_PC_ALLOC_SIZE_MIN,
+	_PC_ASYNC_IO,
+	_PC_CHOWN_RESTRICTED,
+	_PC_FILESIZEBITS,
+	_PC_LINK_MAX,
+	_PC_MAX_CANON,
+	_PC_MAX_INPUT,
+	_PC_NAME_MAX,
+	_PC_NO_TRUNC,
+	_PC_PATH_MAX,
+	_PC_PIPE_BUF,
+	_PC_PRIO_IO,
+	_PC_REC_INCR_XFER_SIZE,
+	_PC_REC_MIN_XFER_SIZE,
+	_PC_REC_XFER_ALIGN,
+	_PC_SYMLINK_MAX,
+	_PC_SYNC_IO,
+	_PC_VDISABLE
+};
+extern long posix_pathconf(const char *path, int name);
+
+/* Creating a Process */
+extern posix_pid_t posix_fork(void);
+
+/* Executing a File */
+extern int posix_execv(const char *path, char *const argv[]);
+extern int posix_execvp(const char *file, char *const argv[]);
+
+/* Creating a Pipe */
+extern int posix_pipe(int fildes[2]);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define getopt posix_getopt
+	#define optarg posix_optarg
+
+	#define environ posix_environ
+
+	#define getlogin posix_getlogin
+	#define getlogin_r posix_getlogin_r
+
+	#define getcwd posix_getcwd
+	#define chdir posix_chdir
+
+	#define isatty posix_isatty
+
+	#undef getpagesize
+	#define getpagesize posix_getpagesize
+
+	#define getpid posix_getpid
+	#define getuid posix_getuid
+	#define getgid posix_getgid
+
+	#define close posix_close
+	#define read posix_read
+	#define write posix_write
+	#define fsync posix_fsync
+	#define ftruncate posix_ftruncate
+	#define rmdir posix_rmdir
+	#define unlink posix_unlink
+	#define dup posix_dup
+	#define dup2 posix_dup2
+
+	#define access posix_access
+
+	#define sysconf posix_sysconf
+
+	#define pathconf posix_pathconf
+
+	#define fork posix_fork
+
+	#define execv posix_execv
+	#define execvp posix_execvp
+
+	#define pipe posix_pipe
+#endif
+
+#endif /* POSIX_UNISTD_H_ */
+
+/** @}
+ */
Index: pace/lib/posix/internal/common.h
===================================================================
--- uspace/lib/posix/internal/common.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,58 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Helper definitions common for all libposix files.
- */
-
-#ifndef LIBPOSIX_COMMON_H_
-#define LIBPOSIX_COMMON_H_
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#define not_implemented() (fprintf(stderr, \
-    "Function %s() in file %s at line %d is not implemented\n", \
-    __func__, __FILE__, __LINE__), abort())
-
-/* A little helper macro to avoid typing this over and over. */
-#define errnify(func, ...) ({ \
-	int rc = func(__VA_ARGS__); \
-	if (rc < 0) { \
-		errno = -rc; \
-		rc = -1; \
-	} \
-	rc; \
-})
-
-#endif /* LIBPOSIX_COMMON_H_ */
-
-/** @}
- */
Index: pace/lib/posix/inttypes.h
===================================================================
--- uspace/lib/posix/inttypes.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,54 +1,0 @@
-/*
- * 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 Fixed size integer types.
- */
-
-#ifndef POSIX_INTTYPES_H_
-#define POSIX_INTTYPES_H_
-
-#include "stdint.h"
-#include "libc/inttypes.h"
-
-extern posix_intmax_t posix_strtoimax(const char *restrict nptr,
-    char **restrict endptr, int base);
-extern posix_uintmax_t posix_strtoumax(const char *restrict nptr,
-    char **restrict endptr, int base);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define strtoimax posix_strtoimax
-	#define strtoumax posix_strtoumax
-#endif
-
-#endif /* POSIX_INTTYPES_H_ */
-
-/** @}
- */
Index: pace/lib/posix/iso646.h
===================================================================
--- uspace/lib/posix/iso646.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,53 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Alternative spellings.
- */
-
-#ifndef POSIX_ISO646_H_
-#define POSIX_ISO646_H_
-
-#define and &&
-#define and_eq &=
-#define bitand &
-#define bitor |
-#define compl ˜
-#define not !
-#define not_eq !=
-#define or ||
-#define or_eq |=
-#define xor ^
-#define xor_eq ^=
-
-#endif /* POSIX_ISO646_H_ */
-
-/** @}
- */
Index: pace/lib/posix/limits.h
===================================================================
--- uspace/lib/posix/limits.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,54 +1,0 @@
-/*
- * 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 Implementation-defined limit constants.
- */
-
-#ifndef POSIX_LIMITS_H_
-#define POSIX_LIMITS_H_
-
-#include "stdint.h"
-#include "libc/sys/types.h"
-
-#undef SHRT_MIN
-#undef SHRT_MAX
-#undef USHRT_MAX
-#define SHRT_MIN SHORT_MIN
-#define SHRT_MAX SHORT_MAX
-#define USHRT_MAX USHORT_MAX
-
-#undef PATH_MAX
-#define PATH_MAX 256
-
-#endif /* POSIX_LIMITS_H_ */
-
-/** @}
- */
Index: pace/lib/posix/locale.c
===================================================================
--- uspace/lib/posix/locale.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,183 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Locale-specific definitions.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "internal/common.h"
-#include "locale.h"
-
-#include "errno.h"
-#include "limits.h"
-#include "string.h"
-
-/* Just a very basic dummy implementation.
- * This should allow code using locales to work properly, but doesn't provide
- * any localization functionality.
- * Should be extended/rewritten when or if HelenOS supports locales natively.
- */
-
-struct __posix_locale {
-	int _dummy;
-};
-
-const struct posix_lconv C_LOCALE = {
-	.currency_symbol = (char *) "",
-	.decimal_point = (char *) ".",
-	.frac_digits = CHAR_MAX,
-	.grouping = (char *) "",
-	.int_curr_symbol = (char *) "",
-	.int_frac_digits = CHAR_MAX,
-	.int_n_cs_precedes = CHAR_MAX,
-	.int_n_sep_by_space = CHAR_MAX,
-	.int_n_sign_posn = CHAR_MAX,
-	.int_p_cs_precedes = CHAR_MAX,
-	.int_p_sep_by_space = CHAR_MAX,
-	.int_p_sign_posn = CHAR_MAX,
-	.mon_decimal_point = (char *) "",
-	.mon_grouping = (char *) "",
-	.mon_thousands_sep = (char *) "",
-	.negative_sign = (char *) "",
-	.n_cs_precedes = CHAR_MAX,
-	.n_sep_by_space = CHAR_MAX,
-	.n_sign_posn = CHAR_MAX,
-	.positive_sign = (char *) "",
-	.p_cs_precedes = CHAR_MAX,
-	.p_sep_by_space = CHAR_MAX,
-	.p_sign_posn = CHAR_MAX,
-	.thousands_sep = (char *) ""
-};
-
-/**
- * Set program locale.
- * 
- * @param category What category to set.
- * @param locale Locale name.
- * @return Original locale name on success, NULL on failure.
- */
-char *posix_setlocale(int category, const char *locale)
-{
-	// TODO
-	if (locale == NULL || *locale == '\0' ||
-	    posix_strcmp(locale, "C") == 0) {
-		return (char *) "C";
-	}
-	return NULL;
-}
-
-/**
- * Return locale-specific information.
- * 
- * @return Information about the current locale.
- */
-struct posix_lconv *posix_localeconv(void)
-{
-	// TODO
-	return (struct posix_lconv *) &C_LOCALE;
-}
-
-/**
- * Duplicate locale object.
- * 
- * @param locobj Object to duplicate.
- * @return Duplicated object.
- */
-posix_locale_t posix_duplocale(posix_locale_t locobj)
-{
-	if (locobj == NULL) {
-		errno = EINVAL;
-		return NULL;
-	}
-	posix_locale_t copy = malloc(sizeof(struct __posix_locale));
-	if (copy == NULL) {
-		errno = ENOMEM;
-		return NULL;
-	}
-	memcpy(copy, locobj, sizeof(struct __posix_locale));
-	return copy;
-}
-
-/**
- * Free locale object.
- * 
- * @param locobj Object to free.
- */
-void posix_freelocale(posix_locale_t locobj)
-{
-	if (locobj) {
-		free(locobj);
-	}
-}
-
-/**
- * Create or modify a locale object.
- * 
- * @param category_mask Mask of categories to be set or modified.
- * @param locale Locale to be used.
- * @param base Object to modify. 0 if new object is to be created.
- * @return The new/modified locale object.
- */
-posix_locale_t posix_newlocale(int category_mask, const char *locale,
-    posix_locale_t base)
-{
-	if (locale == NULL ||
-	    (category_mask & LC_ALL_MASK) != category_mask) {
-		errno = EINVAL;
-		return NULL;
-	}
-	// TODO
-	posix_locale_t new = malloc(sizeof(struct __posix_locale));
-	if (new == NULL) {
-		errno = ENOMEM;
-		return NULL;
-	}
-	if (base != NULL) {
-		posix_freelocale(base);
-	}
-	return new;
-}
-
-/**
- * Set locale for the current thread.
- * 
- * @param newloc Locale to use.
- * @return The previously set locale or LC_GLOBAL_LOCALE
- */
-posix_locale_t posix_uselocale(posix_locale_t newloc)
-{
-	// TODO
-	return LC_GLOBAL_LOCALE;
-}
-
-/** @}
- */
Index: pace/lib/posix/locale.h
===================================================================
--- uspace/lib/posix/locale.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,136 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Locale-specific definitions.
- */
-
-#ifndef POSIX_LOCALE_H_
-#define POSIX_LOCALE_H_
-
-#ifndef NULL
-	#define NULL ((void *) 0)
-#endif
-
-#ifndef __locale_t_defined
-	#define __locale_t_defined
-	typedef struct __posix_locale *posix_locale_t;
-	#ifndef LIBPOSIX_INTERNAL
-		#define locale_t posix_locale_t
-	#endif
-#endif
-
-#undef LC_ALL
-#undef LC_COLLATE
-#undef LC_CTYPE
-#undef LC_MESSAGES
-#undef LC_MONETARY
-#undef LC_NUMERIC
-#undef LC_TIME
-#define LC_ALL 0
-#define LC_COLLATE 1
-#define LC_CTYPE 2
-#define LC_MESSAGES 3
-#define LC_MONETARY 4
-#define LC_NUMERIC 5
-#define LC_TIME 6
-
-#undef LC_COLLATE_MASK
-#undef LC_CTYPE_MASK
-#undef LC_MESSAGES_MASK
-#undef LC_MONETARY_MASK
-#undef LC_NUMERIC_MASK
-#undef LC_TIME_MASK
-#undef LC_ALL_MASK
-#define LC_COLLATE_MASK (1 << 0)
-#define LC_CTYPE_MASK (1 << 1)
-#define LC_MESSAGES_MASK (1 << 2)
-#define LC_MONETARY_MASK (1 << 3)
-#define LC_NUMERIC_MASK (1 << 4)
-#define LC_TIME_MASK (1 << 5)
-#define LC_ALL_MASK (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MESSAGES_MASK | \
-    LC_MONETARY_MASK | LC_NUMERIC_MASK | LC_TIME_MASK)
-
-#undef LC_GLOBAL_LOCALE
-#define LC_GLOBAL_LOCALE NULL
-
-struct posix_lconv {
-	char *currency_symbol;
-	char *decimal_point;
-	char  frac_digits;
-	char *grouping;
-	char *int_curr_symbol;
-	char  int_frac_digits;
-	char  int_n_cs_precedes;
-	char  int_n_sep_by_space;
-	char  int_n_sign_posn;
-	char  int_p_cs_precedes;
-	char  int_p_sep_by_space;
-	char  int_p_sign_posn;
-	char *mon_decimal_point;
-	char *mon_grouping;
-	char *mon_thousands_sep;
-	char *negative_sign;
-	char  n_cs_precedes;
-	char  n_sep_by_space;
-	char  n_sign_posn;
-	char *positive_sign;
-	char  p_cs_precedes;
-	char  p_sep_by_space;
-	char  p_sign_posn;
-	char *thousands_sep;
-};
-
-extern char *posix_setlocale(int category, const char *locale);
-extern struct posix_lconv *posix_localeconv(void);
-
-/* POSIX Extensions */
-extern posix_locale_t posix_duplocale(posix_locale_t locobj);
-extern void posix_freelocale(posix_locale_t locobj);
-extern posix_locale_t posix_newlocale(int category_mask, const char *locale,
-    posix_locale_t base);
-extern posix_locale_t posix_uselocale(posix_locale_t newloc);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define lconv posix_lconv
-
-	#define setlocale posix_setlocale
-	#define localeconv posix_localeconv
-
-	#define newlocale posix_newlocale
-	#define uselocale posix_uselocale
-	#define duplocale posix_duplocale
-	#define freelocale posix_freelocale
-#endif
-
-#endif /* POSIX_LOCALE_H_ */
-
-/** @}
- */
Index: pace/lib/posix/math.c
===================================================================
--- uspace/lib/posix/math.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,65 +1,0 @@
-/*
- * 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 Mathematical operations.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "internal/common.h"
-#include "math.h"
-
-/**
- * 
- * @param x
- * @param exp
- * @return
- */
-double posix_ldexp(double x, int exp)
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
-/**
- * 
- * @param num
- * @param exp
- * @return
- */
-double posix_frexp(double num, int *exp)
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
-/** @}
- */
Index: pace/lib/posix/math.h
===================================================================
--- uspace/lib/posix/math.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,50 +1,0 @@
-/*
- * 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 Mathematical operations.
- */
-
-#ifndef POSIX_MATH_H_
-#define POSIX_MATH_H_
-
-/* Normalization Functions */
-extern double posix_ldexp(double x, int exp);
-extern double posix_frexp(double num, int *exp);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define ldexp posix_ldexp
-	#define frexp posix_frexp
-#endif
-
-#endif /* POSIX_MATH_H_ */
-
-/** @}
- */
Index: pace/lib/posix/pwd.c
===================================================================
--- uspace/lib/posix/pwd.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,190 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Password handling.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "pwd.h"
-#include "string.h"
-#include "errno.h"
-#include "assert.h"
-
-static bool entry_read = false;
-
-/* dummy user account */
-static const struct posix_passwd dummy_pwd = {
-	.pw_name = (char *) "user",
-	.pw_uid = 0,
-	.pw_gid = 0,
-	.pw_dir = (char *) "/",
-	.pw_shell = (char *) "/app/bdsh"
-};
-
-/**
- * Retrieve next broken-down entry from the user database.
- *
- * Since HelenOS doesn't have user accounts, this always returns
- * the same made-up entry.
- *
- * @return Next user database entry or NULL if not possible. Since HelenOS
- *     doesn't have user accounts, this always returns the same made-up entry.
- */
-struct posix_passwd *posix_getpwent(void)
-{
-	if (entry_read) {
-		return NULL;
-	}
-
-	entry_read = true;
-	return (struct posix_passwd *) &dummy_pwd;
-}
-
-/**
- * Rewind the user list.
- */
-void posix_setpwent(void)
-{
-	entry_read = false;
-}
-
-/**
- * Ends enumerating and releases all resources. (Noop)
- */
-void posix_endpwent(void)
-{
-	/* noop */
-}
-
-/**
- * Find an entry by name.
- *
- * @param name Name of the entry.
- * @return Either found entry or NULL if no such entry exists.
- */
-struct posix_passwd *posix_getpwnam(const char *name)
-{
-	assert(name != NULL);
-
-	if (posix_strcmp(name, "user") != 0) {
-		return NULL;
-	}
-
-	return (struct posix_passwd *) &dummy_pwd;
-}
-
-/**
- * Find an entry by name, thread safely.
- *
- * @param name Name of the entry.
- * @param pwd Original structure.
- * @param buffer Buffer for the strings referenced from the result structure.
- * @param bufsize Length of the buffer.
- * @param result Where to store updated structure.
- * @return Zero on success (either found or not found, but without an error),
- *     non-zero error number if error occured.
- */
-int posix_getpwnam_r(const char *name, struct posix_passwd *pwd,
-    char *buffer, size_t bufsize, struct posix_passwd **result)
-{
-	assert(name != NULL);
-	assert(pwd != NULL);
-	assert(buffer != NULL);
-	assert(result != NULL);
-	
-	if (posix_strcmp(name, "user") != 0) {
-		*result = NULL;
-		return 0;
-	}
-	
-	return posix_getpwuid_r(0, pwd, buffer, bufsize, result);
-}
-
-/**
- * Find an entry by UID.
- *
- * @param uid UID of the entry.
- * @return Either found entry or NULL if no such entry exists.
- */
-struct posix_passwd *posix_getpwuid(posix_uid_t uid)
-{
-	if (uid != 0) {
-		return NULL;
-	}
-
-	return (struct posix_passwd *) &dummy_pwd;
-}
-
-/**
- * Find an entry by UID, thread safely.
- *
- * @param uid UID of the entry.
- * @param pwd Original structure.
- * @param buffer Buffer for the strings referenced from the result structure.
- * @param bufsize Length of the buffer.
- * @param result Where to store updated structure.
- * @return Zero on success (either found or not found, but without an error),
- *     non-zero error number if error occured.
- */
-int posix_getpwuid_r(posix_uid_t uid, struct posix_passwd *pwd,
-    char *buffer, size_t bufsize, struct posix_passwd **result)
-{
-	assert(pwd != NULL);
-	assert(buffer != NULL);
-	assert(result != NULL);
-	
-	static const char bf[] = { 'u', 's', 'e', 'r', '\0',
-	    '/', '\0', 'b', 'd', 's', 'h', '\0' };
-	
-	if (uid != 0) {
-		*result = NULL;
-		return 0;
-	}
-	if (bufsize < sizeof(bf)) {
-		*result = NULL;
-		return ERANGE;
-	}
-
-	memcpy(buffer, bf, sizeof(bf));
-
-	pwd->pw_name = (char *) bf;
-	pwd->pw_uid = 0;
-	pwd->pw_gid = 0;
-	pwd->pw_dir = (char *) bf + 5;
-	pwd->pw_shell = (char *) bf + 7;
-	*result = (struct posix_passwd *) pwd;
-
-	return 0;
-}
-
-/** @}
- */
Index: pace/lib/posix/pwd.h
===================================================================
--- uspace/lib/posix/pwd.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,77 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Password handling.
- */
-
-#ifndef POSIX_PWD_H_
-#define POSIX_PWD_H_
-
-#include "sys/types.h"
-
-struct posix_passwd {
-	char *pw_name;
-	posix_uid_t pw_uid;
-	posix_gid_t pw_gid;
-	char *pw_dir;
-	char *pw_shell;
-};
-
-extern struct posix_passwd *posix_getpwent(void);
-extern void posix_setpwent(void);
-extern void posix_endpwent(void);
-
-extern struct posix_passwd *posix_getpwnam(const char *name);
-extern int posix_getpwnam_r(const char *name, struct posix_passwd *pwd,
-    char *buffer, size_t bufsize, struct posix_passwd **result);
-
-extern struct posix_passwd *posix_getpwuid(posix_uid_t uid);
-extern int posix_getpwuid_r(posix_uid_t uid, struct posix_passwd *pwd,
-    char *buffer, size_t bufsize, struct posix_passwd **result);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define passwd posix_passwd
-	
-	#define getpwent posix_getpwent
-	#define setpwent posix_setpwent
-	#define endpwent posix_endpwent
-
-	#define getpwnam posix_getpwnam
-	#define getpwnam_r posix_getpwnam_r
-
-	#define getpwuid posix_getpwuid
-	#define getpwuid_r posix_getpwuid_r
-#endif
-
-#endif /* POSIX_PWD_H_ */
-
-/** @}
- */
Index: pace/lib/posix/signal.c
===================================================================
--- uspace/lib/posix/signal.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,566 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Signal handling.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "signal.h"
-#include "internal/common.h"
-#include "limits.h"
-#include "stdlib.h"
-#include "string.h"
-#include "errno.h"
-
-#include "libc/fibril_synch.h"
-#include "libc/task.h"
-
-/* This file implements a fairly dumb and incomplete "simulation" of
- * POSIX signals. Since HelenOS doesn't support signals and mostly doesn't
- * have any equivalent functionality, most of the signals are useless. The
- * main purpose of this implementation is thus to help port applications using
- * signals with minimal modification, but if the application uses signals for
- * anything non-trivial, it's quite probable it won't work properly even if
- * it builds without problems.
- */
-
-/* Used to serialize signal handling. */
-static FIBRIL_MUTEX_INITIALIZE(_signal_mutex);
-
-static LIST_INITIALIZE(_signal_queue);
-
-static posix_sigset_t _signal_mask = 0;
-
-#define DEFAULT_HANDLER { .sa_handler = SIG_DFL, \
-    .sa_mask = 0, .sa_flags = 0, .sa_sigaction = NULL }
-
-/* Actions associated with each signal number. */
-static struct posix_sigaction _signal_actions[_TOP_SIGNAL + 1] = {
-	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
-	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
-	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
-	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
-	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
-	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
-	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER
-};
-
-/**
- * Default signal handler. Executes the default action for each signal,
- * as reasonable within HelenOS.
- *
- * @param signo Signal number.
- */
-void __posix_default_signal_handler(int signo)
-{
-	switch (signo) {
-	case SIGABRT:
-		abort();
-	case SIGQUIT:
-		fprintf(stderr, "Quit signal raised. Exiting.\n");
-		exit(EXIT_FAILURE);
-	case SIGINT:
-		fprintf(stderr, "Interrupt signal caught. Exiting.\n");
-		exit(EXIT_FAILURE);
-	case SIGTERM:
-		fprintf(stderr, "Termination signal caught. Exiting.\n");
-		exit(EXIT_FAILURE);
-	case SIGSTOP:
-		fprintf(stderr, "Stop signal caught, but unsupported. Ignoring.\n");
-		break;
-	case SIGKILL:
-		/* This will only occur when raise or similar is called. */
-		/* Commit suicide. */
-		task_kill(task_get_id());
-		
-		/* Should not be reached. */
-		abort();
-	case SIGFPE:
-	case SIGBUS:
-	case SIGILL:
-	case SIGSEGV:
-		posix_psignal(signo, "Hardware exception raised by user code");
-		abort();
-	case SIGSYS:
-	case SIGXCPU:
-	case SIGXFSZ:
-	case SIGTRAP:
-	case SIGHUP:
-	case SIGPIPE:
-	case SIGPOLL:
-	case SIGURG:
-	case SIGTSTP:
-	case SIGTTIN:
-	case SIGTTOU:
-		posix_psignal(signo, "Unsupported signal caught");
-		abort();
-	case SIGCHLD:
-	case SIGUSR1:
-	case SIGUSR2:
-	case SIGALRM:
-	case SIGVTALRM:
-	case SIGPROF:
-	case SIGCONT:
-		/* ignored */
-		break;
-	}
-}
-
-/**
- * Just an empty function to get an unique pointer value for comparison.
- *
- * @param signo Signal number.
- */
-void __posix_hold_signal_handler(int signo)
-{
-	/* Nothing */
-}
-
-/**
- * Empty function to be used as ignoring handler.
- * 
- * @param signo Signal number.
- */
-void __posix_ignore_signal_handler(int signo)
-{
-	/* Nothing */
-}
-
-/**
- * Clear the signal set.
- * 
- * @param set Pointer to the signal set.
- * @return Always returns zero.
- */
-int posix_sigemptyset(posix_sigset_t *set)
-{
-	assert(set != NULL);
-
-	*set = 0;
-	return 0;
-}
-
-/**
- * Fill the signal set (i.e. add all signals).
- * 
- * @param set Pointer to the signal set.
- * @return Always returns zero.
- */
-int posix_sigfillset(posix_sigset_t *set)
-{
-	assert(set != NULL);
-
-	*set = UINT32_MAX;
-	return 0;
-}
-
-/**
- * Add a signal to the set.
- * 
- * @param set Pointer to the signal set.
- * @param signo Signal number to add.
- * @return Always returns zero.
- */
-int posix_sigaddset(posix_sigset_t *set, int signo)
-{
-	assert(set != NULL);
-
-	*set |= (1 << signo);
-	return 0;
-}
-
-/**
- * Delete a signal from the set.
- * 
- * @param set Pointer to the signal set.
- * @param signo Signal number to remove.
- * @return Always returns zero.
- */
-int posix_sigdelset(posix_sigset_t *set, int signo)
-{
-	assert(set != NULL);
-
-	*set &= ~(1 << signo);
-	return 0;
-}
-
-/**
- * Inclusion test for a signal set.
- * 
- * @param set Pointer to the signal set.
- * @param signo Signal number to query.
- * @return 1 if the signal is in the set, 0 otherwise.
- */
-int posix_sigismember(const posix_sigset_t *set, int signo)
-{
-	assert(set != NULL);
-	
-	return (*set & (1 << signo)) != 0;
-}
-
-/**
- * Unsafe variant of the sigaction() function.
- * Doesn't do any checking of its arguments and
- * does not deal with thread-safety.
- * 
- * @param sig
- * @param act
- * @param oact
- */
-static void _sigaction_unsafe(int sig, const struct posix_sigaction *restrict act,
-    struct posix_sigaction *restrict oact)
-{
-	if (oact != NULL) {
-		memcpy(oact, &_signal_actions[sig],
-		    sizeof(struct posix_sigaction));
-	}
-
-	if (act != NULL) {
-		memcpy(&_signal_actions[sig], act,
-		    sizeof(struct posix_sigaction));
-	}
-}
-
-/**
- * Sets a new action for the given signal number.
- * 
- * @param sig Signal number to set action for.
- * @param act If not NULL, contents of this structure are
- *     used as the new action for the signal.
- * @param oact If not NULL, the original action associated with the signal
- *     is stored in the structure pointer to. 
- * @return -1 with errno set on failure, 0 on success.
- */
-int posix_sigaction(int sig, const struct posix_sigaction *restrict act,
-    struct posix_sigaction *restrict oact)
-{
-	if (sig > _TOP_SIGNAL || (act != NULL &&
-	    (sig == SIGKILL || sig == SIGSTOP))) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	if (sig > _TOP_CATCHABLE_SIGNAL) {
-		posix_psignal(sig,
-		    "WARNING: registering handler for a partially"
-		    " or fully unsupported signal. This handler may only be"
-		    " invoked by the raise() function, which may not be what"
-		    " the application developer intended");
-	}
-
-	fibril_mutex_lock(&_signal_mutex);
-	_sigaction_unsafe(sig, act, oact);
-	fibril_mutex_unlock(&_signal_mutex);
-
-	return 0;
-}
-
-/**
- * Sets a new handler for the given signal number.
- * 
- * @param sig Signal number to set handler for.
- * @param func Handler function.
- * @return SIG_ERR on failure, original handler on success.
- */
-void (*posix_signal(int sig, void (*func)(int)))(int)
-{
-	struct posix_sigaction new = {
-		.sa_handler = func,
-		.sa_mask = 0,
-		.sa_flags = 0,
-		.sa_sigaction = NULL
-	};
-	struct posix_sigaction old;
-	if (posix_sigaction(sig, func == NULL ? NULL : &new, &old) == 0) {
-		return old.sa_handler;
-	} else {
-		return SIG_ERR;
-	}
-}
-
-typedef struct {
-	link_t link;
-	int signo;
-	posix_siginfo_t siginfo;
-} signal_queue_item;
-
-/**
- * Queue blocked signal.
- *
- * @param signo Signal number.
- * @param siginfo Additional information about the signal.
- */
-static void _queue_signal(int signo, posix_siginfo_t *siginfo)
-{
-	assert(signo >= 0 && signo <= _TOP_SIGNAL);
-	assert(siginfo != NULL);
-	
-	signal_queue_item *item = malloc(sizeof(signal_queue_item));
-	link_initialize(&(item->link));
-	item->signo = signo;
-	memcpy(&item->siginfo, siginfo, sizeof(posix_siginfo_t));
-	list_append(&(item->link), &_signal_queue);
-}
-
-
-/**
- * Executes an action associated with the given signal.
- *
- * @param signo Signal number.
- * @param siginfo Additional information about the circumstances of this raise.
- * @return 0 if the action has been successfully executed. -1 if the signal is
- *     blocked.
- */
-static int _raise_sigaction(int signo, posix_siginfo_t *siginfo)
-{
-	assert(signo >= 0 && signo <= _TOP_SIGNAL);
-	assert(siginfo != NULL);
-
-	fibril_mutex_lock(&_signal_mutex);
-
-	struct posix_sigaction action = _signal_actions[signo];
-
-	if (posix_sigismember(&_signal_mask, signo) ||
-	    action.sa_handler == SIG_HOLD) {
-		_queue_signal(signo, siginfo);
-		fibril_mutex_unlock(&_signal_mutex);
-		return -1;
-	}
-
-	/* Modifying signal mask is unnecessary,
-	 * signal handling is serialized.
-	 */
-
-	if ((action.sa_flags & SA_RESETHAND) && signo != SIGILL && signo != SIGTRAP) {
-		_signal_actions[signo] = (struct posix_sigaction) DEFAULT_HANDLER;
-	}
-
-	if (action.sa_flags & SA_SIGINFO) {
-		assert(action.sa_sigaction != NULL);
-		action.sa_sigaction(signo, siginfo, NULL);
-	} else {
-		assert(action.sa_handler != NULL);
-		action.sa_handler(signo);
-	}
-
-	fibril_mutex_unlock(&_signal_mutex);
-
-	return 0;
-}
-
-/**
- * Raise all unblocked previously queued signals.
- */
-static void _dequeue_unblocked_signals()
-{
-	link_t *iterator = _signal_queue.head.next;
-	link_t *next;
-	
-	while (iterator != &(_signal_queue).head) {
-		next = iterator->next;
-		
-		signal_queue_item *item =
-		    list_get_instance(iterator, signal_queue_item, link);
-		
-		if (!posix_sigismember(&_signal_mask, item->signo) &&
-		    _signal_actions[item->signo].sa_handler != SIG_HOLD) {
-			list_remove(&(item->link));
-			_raise_sigaction(item->signo, &(item->siginfo));
-			free(item);
-		}
-		
-		iterator = next;
-	}
-}
-
-/**
- * Raise a signal for the calling process.
- * 
- * @param sig Signal number.
- * @return -1 with errno set on failure, 0 on success.
- */
-int posix_raise(int sig)
-{
-	if (sig >= 0 && sig <= _TOP_SIGNAL) {
-		posix_siginfo_t siginfo = {
-			.si_signo = sig,
-			.si_code = SI_USER
-		};
-		return _raise_sigaction(sig, &siginfo);
-	} else {
-		errno = EINVAL;
-		return -1;
-	}
-}
-
-/**
- * Raises a signal for a selected process.
- * 
- * @param pid PID of the process for which the signal shall be raised.
- * @param signo Signal to raise.
- * @return -1 with errno set on failure (possible errors include unsupported
- *     action, invalid signal number, lack of permissions, etc.), 0 on success.
- */
-int posix_kill(posix_pid_t pid, int signo)
-{
-	if (pid < 1) {
-		// TODO
-		errno = ENOTSUP;
-		return -1;
-	}
-
-	if (signo > _TOP_SIGNAL) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	if (pid == (posix_pid_t) task_get_id()) {
-		return posix_raise(signo);
-	}
-
-	switch (signo) {
-	case SIGKILL:
-		task_kill(pid);
-		break;
-	default:
-		/* Nothing else supported yet. */
-		errno = ENOTSUP;
-		return -1;
-	}
-
-	return 0;
-}
-
-/**
- * Send a signal to a process group. Always fails at the moment because of
- * lack of this functionality in HelenOS.
- * 
- * @param pid PID of the process group.
- * @param sig Signal number.
- * @return -1 on failure, 0 on success (see kill()).
- */
-int posix_killpg(posix_pid_t pid, int sig)
-{
-	assert(pid > 1);
-	return posix_kill(-pid, sig);
-}
-
-/**
- * Outputs information about the signal to the standard error stream.
- * 
- * @param pinfo SigInfo struct to write.
- * @param message String to output alongside human-readable signal description.
- */
-void posix_psiginfo(const posix_siginfo_t *pinfo, const char *message)
-{
-	assert(pinfo != NULL);
-	posix_psignal(pinfo->si_signo, message);
-	// TODO: print si_code
-}
-
-/**
- * Outputs information about the signal to the standard error stream.
- * 
- * @param signum Signal number.
- * @param message String to output alongside human-readable signal description.
- */
-void posix_psignal(int signum, const char *message)
-{
-	char *sigmsg = posix_strsignal(signum);
-	if (message == NULL || *message == '\0') {
-		fprintf(stderr, "%s\n", sigmsg);
-	} else {
-		fprintf(stderr, "%s: %s\n", message, sigmsg);
-	}
-}
-
-/**
- * Manipulate the signal mask of the calling thread.
- * 
- * @param how What to do with the mask.
- * @param set Signal set to work with.
- * @param oset If not NULL, the original signal mask is coppied here.
- * @return 0 success, errorcode on failure.
- */
-int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
-    posix_sigset_t *restrict oset)
-{
-	fibril_mutex_lock(&_signal_mutex);
-
-	if (oset != NULL) {
-		*oset = _signal_mask;
-	}
-	if (set != NULL) {
-		switch (how) {
-		case SIG_BLOCK:
-			_signal_mask |= *set;
-			break;
-		case SIG_UNBLOCK:
-			_signal_mask &= ~*set;
-			break;
-		case SIG_SETMASK:
-			_signal_mask = *set;
-			break;
-		default:
-			fibril_mutex_unlock(&_signal_mutex);
-			return EINVAL;
-		}
-	}
-	
-	_dequeue_unblocked_signals();
-
-	fibril_mutex_unlock(&_signal_mutex);
-
-	return 0;
-}
-
-/**
- * Manipulate the signal mask of the process.
- * 
- * @param how What to do with the mask.
- * @param set Signal set to work with.
- * @param oset If not NULL, the original signal mask is coppied here.
- * @return 0 on success, -1 with errno set on failure.
- */
-int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
-    posix_sigset_t *restrict oset)
-{
-	int result = posix_thread_sigmask(how, set, oset);
-	if (result != 0) {
-		errno = result;
-		return -1;
-	}
-	return 0;
-}
-
-/** @}
- */
Index: pace/lib/posix/signal.h
===================================================================
--- uspace/lib/posix/signal.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,315 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Signal handling.
- */
-
-#ifndef POSIX_SIGNAL_H_
-#define POSIX_SIGNAL_H_
-
-#include "libc/errno.h"
-#include "sys/types.h"
-
-extern void __posix_default_signal_handler(int signo);
-extern void __posix_hold_signal_handler(int signo);
-extern void __posix_ignore_signal_handler(int signo);
-
-#undef SIG_DFL
-#define SIG_DFL ((void (*)(int)) __posix_default_signal_handler)
-#undef SIG_ERR
-#define SIG_ERR ((void (*)(int)) NULL)
-#undef SIG_HOLD
-#define SIG_HOLD ((void (*)(int)) __posix_hold_signal_handler)
-#undef SIG_IGN
-#define SIG_IGN ((void (*)(int)) __posix_ignore_signal_handler)
-
-typedef int posix_sig_atomic_t;
-typedef uint32_t posix_sigset_t;
-typedef struct posix_mcontext {
-	/* must not be empty to avoid compiler warnings (-pedantic) */
-	int dummy;
-} posix_mcontext_t;
-
-union posix_sigval {
-	int sival_int;
-	void *sival_ptr;
-};
-
-struct posix_sigevent {
-	int sigev_notify; /* Notification type. */
-	int sigev_signo; /* Signal number. */
-	union posix_sigval sigev_value; /* Signal value. */
-	void (*sigev_notify_function)(union posix_sigval); /* Notification function. */
-	posix_thread_attr_t *sigev_notify_attributes; /* Notification attributes. */
-};
-
-typedef struct {
-	int si_signo;
-	int si_code;
-
-	int si_errno;
-
-	posix_pid_t si_pid;
-	posix_uid_t si_uid;
-	void *si_addr;
-	int si_status;
-
-	long si_band;
-
-	union posix_sigval si_value;
-} posix_siginfo_t;
-
-struct posix_sigaction {
-	void (*sa_handler)(int);
-	posix_sigset_t sa_mask;
-	int sa_flags;
-	void (*sa_sigaction)(int, posix_siginfo_t *, void *);
-};
-
-typedef struct {
-	void *ss_sp;
-	size_t ss_size;
-	int ss_flags;
-} posix_stack_t;
-
-typedef struct posix_ucontext {
-	struct posix_ucontext *uc_link;
-	posix_sigset_t uc_sigmask;
-	posix_stack_t uc_stack;
-	posix_mcontext_t uc_mcontext;
-} posix_ucontext_t;
-
-/* Values of posix_sigevent::sigev_notify */
-#undef SIGEV_NONE
-#undef SIGEV_SIGNAL
-#undef SIGEV_THREAD
-#define SIGEV_NONE 0
-#define SIGEV_SIGNAL 0
-#define SIGEV_THREAD 0
-
-#undef SIGRT_MIN
-#undef SIGRT_MAX
-#define SIGRT_MIN 0
-#define SIGRT_MAX 0
-
-#undef SIG_BLOCK
-#undef SIG_UNBLOCK
-#undef SIG_SETMASK
-#define SIG_BLOCK 0
-#define SIG_UNBLOCK 1
-#define SIG_SETMASK 2
-
-#undef SA_NOCLDSTOP
-#undef SA_ONSTACK
-#undef SA_RESETHAND
-#undef SA_RESTART
-#undef SA_SIGINFO
-#undef SA_NOCLDWAIT
-#undef SA_NODEFER
-#define SA_NOCLDSTOP (1 << 0)
-#define SA_ONSTACK (1 << 1)
-#define SA_RESETHAND (1 << 2)
-#define SA_RESTART (1 << 3)
-#define SA_SIGINFO (1 << 4)
-#define SA_NOCLDWAIT (1 << 5)
-#define SA_NODEFER (1 << 6)
-
-#undef SS_ONSTACK
-#undef SS_DISABLE
-#define SS_ONSTACK 0
-#define SS_DISABLE 0
-
-#undef MINSIGSTKSZ
-#undef SIGSTKSZ
-#define MINSIGSTKSZ 0
-#define SIGSTKSZ 0
-
-/* Full POSIX set */
-enum {
-	/* Termination Signals */
-	SIGABRT,
-	SIGQUIT,
-	SIGINT,
-	SIGTERM,
-	
-	/* Child Signal */
-	SIGCHLD,
-	
-	/* User signals */
-	SIGUSR1,
-	SIGUSR2,
-
-	/* Timer */
-	SIGALRM,
-	SIGVTALRM,
-	SIGPROF, /* obsolete */
-
-	_TOP_CATCHABLE_SIGNAL = SIGPROF,
-
-	/* Process Scheduler Interaction - not supported */
-	SIGSTOP,
-	SIGCONT,
-
-	/* Process Termination - can't be caught */
-	SIGKILL,
-
-	_TOP_SENDABLE_SIGNAL = SIGKILL,
-
-	/* Hardware Exceptions - can't be caught or sent */
-	SIGFPE,
-	SIGBUS,
-	SIGILL,
-	SIGSEGV,
-
-	/* Other Exceptions - not supported */
-	SIGSYS,
-	SIGXCPU,
-	SIGXFSZ,
-
-	/* Debugging - not supported */
-	SIGTRAP,
-
-	/* Communication Signals - not supported */
-	SIGHUP,
-	SIGPIPE,
-	SIGPOLL, /* obsolete */
-	SIGURG,
-
-	/* Terminal Signals - not supported */
-	SIGTSTP,
-	SIGTTIN,
-	SIGTTOU,
-	
-	_TOP_SIGNAL = SIGTTOU
-};
-
-/* Values for sigaction field si_code. */
-enum {
-	SI_USER,
-	SI_QUEUE,
-	SI_TIMER,
-	SI_ASYNCIO,
-	SI_MESGQ,
-	ILL_ILLOPC,
-	ILL_ILLOPN,
-	ILL_ILLADR,
-	ILL_ILLTRP,
-	ILL_PRVOPC,
-	ILL_PRVREG,
-	ILL_COPROC,
-	ILL_BADSTK,
-	FPE_INTDIV,
-	FPE_INTOVF,
-	FPE_FLTDIV,
-	FPE_FLTOVF,
-	FPE_FLTUND,
-	FPE_FLTRES,
-	FPE_FLTINV,
-	FPE_FLTSUB,
-	SEGV_MAPERR,
-	SEGV_ACCERR,
-	BUS_ADRALN,
-	BUS_ADRERR,
-	BUS_OBJERR,
-	TRAP_BRKPT,
-	TRAP_TRACE,
-	CLD_EXITED,
-	CLD_KILLED,
-	CLD_DUMPED,
-	CLD_TRAPPED,
-	CLD_STOPPED,
-	CLD_CONTINUED,
-	POLL_IN,
-	POLL_OUT,
-	POLL_MSG,
-	POLL_ERR,
-	POLL_PRI,
-	POLL_HUP
-};
-
-extern int posix_sigaction(int sig, const struct posix_sigaction *restrict act,
-    struct posix_sigaction *restrict oact);
-
-extern void (*posix_signal(int sig, void (*func)(int)))(int);
-extern int posix_raise(int sig);
-extern int posix_kill(posix_pid_t pid, int sig);
-extern int posix_killpg(posix_pid_t pid, int sig);
-
-extern void posix_psiginfo(const posix_siginfo_t *pinfo, const char *message);
-extern void posix_psignal(int signum, const char *message);
-
-extern int posix_sigemptyset(posix_sigset_t *set);
-extern int posix_sigfillset(posix_sigset_t *set);
-extern int posix_sigaddset(posix_sigset_t *set, int signo);
-extern int posix_sigdelset(posix_sigset_t *set, int signo);
-extern int posix_sigismember(const posix_sigset_t *set, int signo);
-
-extern int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
-    posix_sigset_t *restrict oset);
-extern int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
-    posix_sigset_t *restrict oset);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define sig_atomic_t posix_sig_atomic_t
-	#define sigset_t posix_sigset_t
-	#define sigval posix_sigval
-	#ifndef sigevent
-		#define sigevent posix_sigevent
-	#endif
-	#define mcontext_t posix_mcontext_t
-	#define ucontext_t posix_ucontext_t
-	#define stack_t posix_stack_t
-	#define siginfo_t posix_siginfo_t
-
-	#define sigaction posix_sigaction
-
-	#define signal posix_signal
-	#define raise posix_raise
-	#define kill posix_kill
-	#define killpg posix_killpg
-
-	#define psiginfo posix_psiginfo
-	#define psignal posix_psignal
-
-	#define sigemptyset posix_sigemptyset
-	#define sigfillset posix_sigfillset
-	#define sigaddset posix_sigaddset
-	#define sigdelset posix_sigdelset
-	#define sigismember posix_sigismember
-
-	#define pthread_sigmask posix_thread_sigmask
-	#define sigprocmask posix_sigprocmask
-#endif
-
-#endif /* POSIX_SIGNAL_H_ */
-
-/** @}
- */
Index: uspace/lib/posix/source/ctype.c
===================================================================
--- uspace/lib/posix/source/ctype.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/ctype.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,131 @@
+/*
+ * 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 Character classification.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "posix/ctype.h"
+
+/**
+ * Checks whether character is a hexadecimal digit.
+ *
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
+ */
+int posix_isxdigit(int c)
+{
+	return isdigit(c) ||
+	    (c >= 'a' && c <= 'f') ||
+	    (c >= 'A' && c <= 'F');
+}
+
+/**
+ * Checks whether character is a word separator.
+ *
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
+ */
+int posix_isblank(int c)
+{
+	return c == ' ' || c == '\t';
+}
+
+/**
+ * Checks whether character is a control character.
+ *
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
+ */
+int posix_iscntrl(int c)
+{
+	return c < 0x20 || c == 0x7E;
+}
+
+/**
+ * Checks whether character is any printing character except space.
+ *
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
+ */
+int posix_isgraph(int c)
+{
+	return posix_isprint(c) && c != ' ';
+}
+
+/**
+ * Checks whether character is a printing character.
+ *
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
+ */
+int posix_isprint(int c)
+{
+	return posix_isascii(c) && !posix_iscntrl(c);
+}
+
+/**
+ * Checks whether character is a punctuation.
+ *
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
+ */
+int posix_ispunct(int c)
+{
+	return !isspace(c) && !isalnum(c) && posix_isprint(c);
+}
+
+/**
+ * Checks whether character is ASCII. (obsolete)
+ *
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
+ */
+int posix_isascii(int c)
+{
+	return c >= 0 && c < 128;
+}
+
+/**
+ * Converts argument to a 7-bit ASCII character. (obsolete)
+ *
+ * @param c Character to convert.
+ * @return Coverted character.
+ */
+int posix_toascii(int c)
+{
+	return c & 0x7F;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/errno.c
===================================================================
--- uspace/lib/posix/source/errno.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/errno.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 System error numbers.
+ */
+
+#include "posix/errno.h"
+
+#include "posix/stdlib.h"
+#include "libc/fibril.h"
+
+static fibril_local int _posix_errno;
+
+int *__posix_errno(void)
+{
+	if (*__errno() != 0) {
+		_posix_errno = abs(*__errno());
+		*__errno() = 0;
+	}
+	return &_posix_errno;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/fcntl.c
===================================================================
--- uspace/lib/posix/source/fcntl.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/fcntl.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,123 @@
+/*
+ * 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 File control.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "internal/common.h"
+#include "posix/fcntl.h"
+
+#include "libc/unistd.h"
+#include "libc/vfs/vfs.h"
+#include "posix/errno.h"
+
+/**
+ * Performs set of operations on the opened files.
+ *
+ * @param fd File descriptor of the opened file.
+ * @param cmd Operation to carry out.
+ * @return Non-negative on success. Might have special meaning corresponding
+ *     to the requested operation.
+ */
+int posix_fcntl(int fd, int cmd, ...)
+{
+	int flags;
+
+	switch (cmd) {
+	case F_DUPFD:
+	case F_DUPFD_CLOEXEC:
+		/* VFS currently does not provide the functionality to duplicate
+		 * opened file descriptor. */
+		// FIXME: implement this once dup() is available
+		errno = ENOTSUP;
+		return -1;
+	case F_GETFD:
+		/* FD_CLOEXEC is not supported. There are no other flags. */
+		return 0;
+	case F_SETFD:
+		/* FD_CLOEXEC is not supported. Ignore arguments and report success. */
+		return 0;
+	case F_GETFL:
+		/* File status flags (i.e. O_APPEND) are currently private to the
+		 * VFS server so it cannot be easily retrieved. */
+		flags = 0;
+		/* File access flags are currently not supported for file descriptors.
+		 * Provide full access. */
+		flags |= O_RDWR;
+		return flags;
+	case F_SETFL:
+		/* File access flags are currently not supported for file descriptors.
+		 * Ignore arguments and report success. */
+		return 0;
+	case F_GETOWN:
+	case F_SETOWN:
+	case F_GETLK:
+	case F_SETLK:
+	case F_SETLKW:
+		/* Signals (SIGURG) and file locks are not supported. */
+		errno = ENOTSUP;
+		return -1;
+	default:
+		/* Unknown command */
+		errno = EINVAL;
+		return -1;
+	}
+}
+
+/**
+ * Open, possibly create, a file.
+ *
+ * @param pathname Path to the file.
+ * @param flags Access mode flags.
+ */
+int posix_open(const char *pathname, int flags, ...)
+{
+	mode_t mode = 0;
+	if ((flags & O_CREAT) > 0) {
+		va_list args;
+		va_start(args, flags);
+		mode = va_arg(args, mode_t);
+		va_end(args);
+	}
+
+	int rc = open(pathname, flags, mode);
+	if (rc < 0) {
+		errno = -rc;
+		rc = -1;
+	}
+
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/fnmatch.c
===================================================================
--- uspace/lib/posix/source/fnmatch.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/fnmatch.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,716 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Filename-matching.
+ */
+
+/* This file contains an implementation of the fnmatch() pattern matching
+ * function. There is more code than necessary to account for the possibility
+ * of adding POSIX-like locale support to the system in the future. Functions
+ * that are only necessary for locale support currently simply use single
+ * characters for "collation elements". 
+ * When (or if) locales are properly implemented, extending this implementation
+ * will be fairly straightforward.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "posix/stdbool.h"
+#include "posix/ctype.h"
+#include "posix/string.h"
+#include "posix/stdlib.h"
+#include "posix/assert.h"
+
+#include "internal/common.h"
+#include "posix/fnmatch.h"
+
+/* Returned by _match... functions. */
+#define INVALID_PATTERN -1
+
+/* Type for collating element, simple identity with characters now,
+ * but may be extended for better locale support.
+ */
+typedef int coll_elm_t;
+
+/** Return value indicating that the element in question
+ * is not valid in the current locale. (That is, if locales are supported.)
+ */
+#define COLL_ELM_INVALID -1
+
+/**
+ * Get collating element matching a string.
+ *
+ * @param str String representation of the element.
+ * @return Matching collating element or COLL_ELM_INVALID.
+ */
+static coll_elm_t _coll_elm_get(const char* str)
+{
+	if (str[0] == '\0' || str[1] != '\0') {
+		return COLL_ELM_INVALID;
+	}
+	return str[0];
+}
+
+/**
+ * Get collating element matching a single character.
+ *
+ * @param c Character representation of the element.
+ * @return Matching collating element.
+ */
+static coll_elm_t _coll_elm_char(int c)
+{
+	return c;
+}
+
+/**
+ * Match collating element with a beginning of a string.
+ *
+ * @param elm Collating element to match.
+ * @param str String which beginning should match the element.
+ * @return 0 if the element doesn't match, or the number of characters matched.
+ */
+static int _coll_elm_match(coll_elm_t elm, const char *str)
+{
+	return elm == *str;
+}
+
+/**
+ * Checks whether a string begins with a collating element in the given range.
+ * Ordering depends on the locale (if locales are supported).
+ *
+ * @param first First element of the range.
+ * @param second Last element of the range.
+ * @param str String to match.
+ * @return 0 if there is no match, or the number of characters matched.
+ */
+static int _coll_elm_between(coll_elm_t first, coll_elm_t second,
+    const char *str)
+{
+	return *str >= first && *str <= second;
+}
+
+/**
+ * Read a string delimited by [? and ?].
+ *
+ * @param pattern Pointer to the string to read from. Its position is moved
+ *    to the first character after the closing ].
+ * @param seq The character on the inside of brackets.
+ * @param buf Read buffer.
+ * @param buf_sz Read buffer's size. If the buffer is not large enough for
+ *    the entire string, the string is cut with no error indication.
+ * @param flags Flags modifying the behavior.
+ * @return True on success, false if the pattern is invalid.
+ */
+static bool _get_delimited(
+    const char **pattern, int seq,
+    char *buf, size_t buf_sz, int flags)
+{
+	const bool noescape = (flags & FNM_NOESCAPE) != 0;
+	const bool pathname = (flags & FNM_PATHNAME) != 0;
+
+	const char *p = *pattern;
+	assert(p[0] == '[' && p[1] == seq /* Caller should ensure this. */);
+	p += 2;
+
+	while (true) {
+		if (*p == seq && *(p + 1) == ']') {
+			/* String properly ended, return. */
+			*pattern = p + 2;
+			*buf = '\0';
+			return true;
+		}
+		if (!noescape && *p == '\\') {
+			p++;
+		}
+		if (*p == '\0') {
+			/* String not ended properly, invalid pattern. */
+			return false;
+		}
+		if (pathname && *p == '/') {
+			/* Slash in a pathname pattern is invalid. */
+			return false;
+		}
+		if (buf_sz > 1) {
+			/* Only add to the buffer if there is space. */
+			*buf = *p;
+			buf++;
+			buf_sz--;
+		}
+		p++;
+	}
+}
+
+/************** CHARACTER CLASSES ****************/
+
+#define MAX_CLASS_OR_COLL_LEN 6
+
+struct _char_class {
+	const char *name;
+	int (*func) (int);
+};
+
+/* List of supported character classes. */
+static const struct _char_class _char_classes[] = {
+	{ "alnum", isalnum },
+	{ "alpha", isalpha },
+	{ "blank", posix_isblank },
+	{ "cntrl", posix_iscntrl },
+	{ "digit", isdigit },
+	{ "graph", posix_isgraph },
+	{ "lower", islower },
+	{ "print", posix_isprint },
+	{ "punct", posix_ispunct },
+	{ "space", isspace },
+	{ "upper", isupper },
+	{ "xdigit", posix_isxdigit }
+};
+
+/**
+ * Compare function for binary search in the _char_classes array.
+ * 
+ * @param key Key of the searched element.
+ * @param elem Element of _char_classes array.
+ * @return Ordering indicator (-1 less than, 0 equal, 1 greater than).
+ */
+static int _class_compare(const void *key, const void *elem)
+{
+	const struct _char_class *class = elem;
+	return posix_strcmp((const char *) key, class->name);
+}
+
+/**
+ * Returns whether the given character belongs to the specified character class.
+ * 
+ * @param cname Name of the character class.
+ * @param c Character.
+ * @return True if the character belongs to the class, false otherwise.
+ */
+static bool _is_in_class (const char *cname, int c)
+{
+	/* Search for class in the array of supported character classes. */
+	const struct _char_class *class = posix_bsearch(cname, _char_classes,
+	    sizeof(_char_classes) / sizeof(struct _char_class),
+	    sizeof(struct _char_class), _class_compare);
+
+	if (class == NULL) {
+		/* No such class supported - treat as an empty class. */
+		return false;
+	} else {
+		/* Class matched. */
+		return class->func(c);
+	}
+}
+
+/**
+ * Tries to parse an initial part of the pattern as a character class pattern,
+ * and if successful, matches the beginning of the given string against the class.
+ * 
+ * @param pattern Pointer to the pattern to match. Must begin with a class
+ *    specifier and is repositioned to the first character after the specifier
+ *    if successful.
+ * @param str String to match.
+ * @param flags Flags modifying the behavior (see fnmatch()).
+ * @return INVALID_PATTERN if the pattern doesn't start with a valid class
+ *    specifier, 0 if the beginning of the matched string doesn't belong
+ *    to the class, or positive number of characters matched.
+ */
+static int _match_char_class(const char **pattern, const char *str, int flags)
+{
+	char class[MAX_CLASS_OR_COLL_LEN + 1];
+
+	if (!_get_delimited(pattern, ':', class, sizeof(class), flags)) {
+		return INVALID_PATTERN;
+	}
+
+	return _is_in_class(class, *str);
+}
+
+/************** END CHARACTER CLASSES ****************/
+
+/**
+ * Reads the next collating element in the pattern, taking into account
+ * locale (if supported) and flags (see fnmatch()).
+ * 
+ * @param pattern Pattern.
+ * @param flags Flags given to fnmatch().
+ * @return Collating element on success,
+ *     or COLL_ELM_INVALID if the pattern is invalid.
+ */
+static coll_elm_t _next_coll_elm(const char **pattern, int flags)
+{
+	assert(pattern != NULL);
+	assert(*pattern != NULL);
+	assert(**pattern != '\0');
+
+	const char *p = *pattern;
+	const bool noescape = (flags & FNM_NOESCAPE) != 0;
+	const bool pathname = (flags & FNM_PATHNAME) != 0;
+
+	if (*p == '[') {
+		if (*(p + 1) == '.') {
+			char buf[MAX_CLASS_OR_COLL_LEN + 1];
+			if (!_get_delimited(pattern, '.', buf, sizeof(buf), flags)) {
+				return COLL_ELM_INVALID;
+			}
+			return _coll_elm_get(buf);
+		}
+
+		if (*(p + 1) == '=') {
+			char buf[MAX_CLASS_OR_COLL_LEN + 1];
+			if (!_get_delimited(pattern, '=', buf, sizeof(buf), flags)) {
+				return COLL_ELM_INVALID;
+			}
+			return _coll_elm_get(buf);
+		}
+	}
+
+	if (!noescape && *p == '\\') {
+		p++;
+		if (*p == '\0') {
+			*pattern = p;
+			return COLL_ELM_INVALID;
+		}
+	}
+	if (pathname && *p == '/') {
+		return COLL_ELM_INVALID;
+	}
+	
+	*pattern = p + 1;
+	return _coll_elm_char(*p);
+}
+
+/**
+ * Matches the beginning of the given string against a bracket expression
+ * the pattern begins with.
+ * 
+ * @param pattern Pointer to the beginning of a bracket expression in a pattern.
+ *     On success, the pointer is moved to the first character after the
+ *     bracket expression.
+ * @param str Unmatched part of the string.
+ * @param flags Flags given to fnmatch().
+ * @return INVALID_PATTERN if the pattern is invalid, 0 if there is no match
+ *     or the number of matched characters on success.
+ */
+static int _match_bracket_expr(const char **pattern, const char *str, int flags)
+{
+	const bool pathname = (flags & FNM_PATHNAME) != 0;
+	const bool special_period = (flags & FNM_PERIOD) != 0;
+	const char *p = *pattern;
+	bool negative = false;
+	int matched = 0;
+
+	#define _matched(match) { \
+		int _match = match; \
+		if (_match < 0) { \
+			/* Invalid pattern */ \
+			return _match; \
+		} else if (matched == 0 && _match > 0) { \
+			/* First match */ \
+			matched = _match; \
+		} \
+	}
+
+	assert(*p == '[');  /* calling code should ensure this */
+	p++;
+
+	if (*str == '\0' || (pathname && *str == '/') ||
+	    (pathname && special_period && *str == '.' && *(str - 1) == '/')) {
+		/* No bracket expression matches end of string,
+		 * slash in pathname match or initial period with FNM_PERIOD
+		 * option.
+		 */
+		return 0;
+	}
+
+	if (*p == '^' || *p == '!') {
+		negative = true;
+		p++;
+	}
+
+	if (*p == ']') {
+		/* When ']' is first, treat it as a normal character. */
+		_matched(*str == ']');
+		p++;
+	}
+	
+	coll_elm_t current_elm = COLL_ELM_INVALID;
+	
+	while (*p != ']') {
+		if (*p == '-' && *(p + 1) != ']' &&
+		    current_elm != COLL_ELM_INVALID) {
+			/* Range expression. */
+			p++;
+			coll_elm_t end_elm = _next_coll_elm(&p, flags);
+			if (end_elm == COLL_ELM_INVALID) {
+				return INVALID_PATTERN;
+			}
+			_matched(_coll_elm_between(current_elm, end_elm, str));
+			continue;
+		}
+	
+		if (*p == '[' && *(p + 1) == ':') {
+			current_elm = COLL_ELM_INVALID;
+			_matched(_match_char_class(&p, str, flags));
+			continue;
+		}
+		
+		current_elm = _next_coll_elm(&p, flags);
+		if (current_elm == COLL_ELM_INVALID) {
+			return INVALID_PATTERN;
+		}
+		_matched(_coll_elm_match(current_elm, str));
+	}
+
+	/* No error occured - update pattern pointer. */
+	*pattern = p + 1;
+
+	if (matched == 0) {
+		/* No match found */
+		return negative;
+	} else {
+		/* Matched 'match' characters. */
+		return negative ? 0 : matched;
+	}
+
+	#undef _matched
+}
+
+/**
+ * Matches a portion of the pattern containing no asterisks (*) against
+ * the given string.
+ * 
+ * @param pattern Pointer to the unmatched portion of the pattern.
+ *     On success, the pointer is moved to the first asterisk, or to the
+ *     terminating nul character, whichever occurs first.
+ * @param string Pointer to the input string. On success, the pointer is moved
+ *     to the first character that wasn't explicitly matched.
+ * @param flags Flags given to fnmatch().
+ * @return True if the entire subpattern matched. False otherwise.
+ */
+static bool _partial_match(const char **pattern, const char **string, int flags)
+{
+	/* Only a single *-delimited subpattern is matched here.
+	 * So in this function, '*' is understood as the end of pattern.
+	 */
+
+	const bool pathname = (flags & FNM_PATHNAME) != 0;
+	const bool special_period = (flags & FNM_PERIOD) != 0;
+	const bool noescape = (flags & FNM_NOESCAPE) != 0;
+	const bool leading_dir = (flags & FNM_LEADING_DIR) != 0;
+
+	const char *s = *string;
+	const char *p = *pattern;
+
+	while (*p != '*') {
+		/* Bracket expression. */
+		if (*p == '[') {
+			int matched = _match_bracket_expr(&p, s, flags);
+			if (matched == 0) {
+				/* Doesn't match. */
+				return false;
+			}
+			if (matched != INVALID_PATTERN) {
+				s += matched;
+				continue;
+			}
+
+			assert(matched == INVALID_PATTERN);
+			/* Fall through to match [ as an ordinary character. */
+		}
+
+		/* Wildcard match. */
+		if (*p == '?') {
+			if (*s == '\0') {
+				/* No character to match. */
+				return false;
+			}
+			if (pathname && *s == '/') {
+				/* Slash must be matched explicitly. */
+				return false;
+			}
+			if (special_period && pathname &&
+			    *s == '.' && *(s - 1) == '/') {
+				/* Initial period must be matched explicitly. */
+				return false;
+			}
+			
+			/* None of the above, match anything else. */
+			p++;
+			s++;
+			continue;
+		}
+
+		if (!noescape && *p == '\\') {
+			/* Escaped character. */
+			p++;
+		}
+
+		if (*p == '\0') {
+			/* End of pattern, must match end of string or
+			 * an end of subdirectory name (optional).
+			 */
+
+			if (*s == '\0' || (leading_dir && *s == '/')) {
+				break;
+			}
+
+			return false;
+		}
+
+		if (*p == *s) {
+			/* Exact match. */
+			p++;
+			s++;
+			continue;
+		}
+
+		/* Nothing matched. */
+		return false;
+	}
+
+	/* Entire sub-pattern matched. */
+	
+	/* postconditions */
+	assert(*p == '\0' || *p == '*');
+	assert(*p != '\0' || *s == '\0' || (leading_dir && *s == '/'));
+	
+	*pattern = p;
+	*string = s;
+	return true;
+}
+
+/**
+ * Match string against a pattern.
+ * 
+ * @param pattern Pattern.
+ * @param string String to match.
+ * @param flags Flags given to fnmatch().
+ * @return True if the string matched the pattern, false otherwise.
+ */
+static bool _full_match(const char *pattern, const char *string, int flags)
+{
+	const bool pathname = (flags & FNM_PATHNAME) != 0;
+	const bool special_period = (flags & FNM_PERIOD) != 0;
+	const bool leading_dir = (flags & FNM_LEADING_DIR) != 0;
+
+	if (special_period && *string == '.') {
+		/* Initial dot must be matched by an explicit dot in pattern. */
+		if (*pattern != '.') {
+			return false;
+		}
+		pattern++;
+		string++;
+	}
+
+	if (*pattern != '*') {
+		if (!_partial_match(&pattern, &string, flags)) {
+			/* The initial match must succeed. */
+			return false;
+		}
+	}
+
+	while (*pattern != '\0') {
+		assert(*pattern == '*');
+		pattern++;
+
+		bool matched = false;
+
+		const char *end;
+		if (pathname && special_period &&
+		    *string == '.' && *(string - 1) == '/') {
+			end = string;
+		} else {
+			end = gnu_strchrnul(string, pathname ? '/' : '\0');
+		}
+
+		/* Try to match every possible offset. */
+		while (string <= end) {
+			if (_partial_match(&pattern, &string, flags)) {
+				matched = true;
+				break;
+			}
+			string++;
+		}
+
+		if (matched) {
+			continue;
+		}
+
+		return false;
+	}
+
+	return *string == '\0' || (leading_dir && *string == '/');
+}
+
+/**
+ * Transform the entire string to lowercase.
+ * 
+ * @param s Input string.
+ * @return Newly allocated copy of the input string with all uppercase
+ *     characters folded to their lowercase variants.
+ */
+static char *_casefold(const char *s)
+{
+	assert(s != NULL);
+	char *result = posix_strdup(s);
+	for (char *i = result; *i != '\0'; ++i) {
+		*i = tolower(*i);
+	}
+	return result;
+}
+
+/**
+ * Filename pattern matching.
+ *
+ * @param pattern Pattern to match the string against.
+ * @param string Matched string.
+ * @param flags Flags altering the matching of special characters
+ *     (mainly for dot and slash).
+ * @return Zero if the string matches the pattern, FNM_NOMATCH otherwise.
+ */
+int posix_fnmatch(const char *pattern, const char *string, int flags)
+{
+	assert(pattern != NULL);
+	assert(string != NULL);
+
+	// TODO: don't fold everything in advance, but only when needed
+
+	if ((flags & FNM_CASEFOLD) != 0) {
+		/* Just fold the entire pattern and string. */
+		pattern = _casefold(pattern);
+		string = _casefold(string);
+	}
+
+	bool result = _full_match(pattern, string, flags);
+
+	if ((flags & FNM_CASEFOLD) != 0) {
+		if (pattern) {
+			free((char *) pattern);
+		}
+		if (string) {
+			free((char *) string);
+		}
+	}
+
+	return result ? 0 : FNM_NOMATCH;
+}
+
+// FIXME: put the testcases to the app/tester after fnmatch is included into libc
+
+#if 0
+
+#include <stdio.h>
+
+void __posix_fnmatch_test()
+{
+	int fail = 0;
+
+	#undef assert
+	#define assert(x) { if (x) printf("SUCCESS: "#x"\n"); else { printf("FAILED: "#x"\n"); fail++; } }
+	#define match(s1, s2, flags) assert(posix_fnmatch(s1, s2, flags) == 0)
+	#define nomatch(s1, s2, flags) assert(posix_fnmatch(s1, s2, flags) == FNM_NOMATCH)
+
+	assert(FNM_PATHNAME == FNM_FILE_NAME);
+	match("", "", 0);
+	match("*", "hello", 0);
+	match("hello", "hello", 0);
+	match("hello*", "hello", 0);
+	nomatch("hello?", "hello", 0);
+	match("*hello", "prdel hello", 0);
+	match("he[sl]lo", "hello", 0);
+	match("he[sl]lo", "heslo", 0);
+	nomatch("he[sl]lo", "heblo", 0);
+	nomatch("he[^sl]lo", "hello", 0);
+	nomatch("he[^sl]lo", "heslo", 0);
+	match("he[^sl]lo", "heblo", 0);
+	nomatch("he[!sl]lo", "hello", 0);
+	nomatch("he[!sl]lo", "heslo", 0);
+	match("he[!sl]lo", "heblo", 0);
+	match("al*[c-t]a*vis*ta", "alheimer talir jehovista", 0);
+	match("al*[c-t]a*vis*ta", "alfons had jehovista", 0);
+	match("[a-ce-z]", "a", 0);
+	match("[a-ce-z]", "c", 0);
+	nomatch("[a-ce-z]", "d", 0);
+	match("[a-ce-z]", "e", 0);
+	match("[a-ce-z]", "z", 0);
+	nomatch("[^a-ce-z]", "a", 0);
+	nomatch("[^a-ce-z]", "c", 0);
+	match("[^a-ce-z]", "d", 0);
+	nomatch("[^a-ce-z]", "e", 0);
+	nomatch("[^a-ce-z]", "z", 0);
+	match("helen??", "helenos", 0);
+	match("****booo****", "booo", 0);
+	
+	match("hello[[:space:]]world", "hello world", 0);
+	nomatch("hello[[:alpha:]]world", "hello world", 0);
+	
+	match("/hoooo*", "/hooooooo/hooo", 0);
+	nomatch("/hoooo*", "/hooooooo/hooo", FNM_PATHNAME);
+	nomatch("/hoooo*/", "/hooooooo/hooo", FNM_PATHNAME);
+	match("/hoooo*/*", "/hooooooo/hooo", FNM_PATHNAME);
+	match("/hoooo*/hooo", "/hooooooo/hooo", FNM_PATHNAME);
+	match("/hoooo*", "/hooooooo/hooo", FNM_PATHNAME | FNM_LEADING_DIR);
+	nomatch("/hoooo*/", "/hooooooo/hooo", FNM_PATHNAME | FNM_LEADING_DIR);
+	nomatch("/hoooo", "/hooooooo/hooo", FNM_LEADING_DIR);
+	match("/hooooooo", "/hooooooo/hooo", FNM_LEADING_DIR);
+	
+	match("*", "hell", 0);
+	match("*?", "hell", 0);
+	match("?*?", "hell", 0);
+	match("?*??", "hell", 0);
+	match("??*??", "hell", 0);
+	nomatch("???*??", "hell", 0);
+	
+	nomatch("", "hell", 0);
+	nomatch("?", "hell", 0);
+	nomatch("??", "hell", 0);
+	nomatch("???", "hell", 0);
+	match("????", "hell", 0);
+	
+	match("*", "h.ello", FNM_PERIOD);
+	match("*", "h.ello", FNM_PATHNAME | FNM_PERIOD);
+	nomatch("*", ".hello", FNM_PERIOD);
+	match("h?ello", "h.ello", FNM_PERIOD);
+	nomatch("?hello", ".hello", FNM_PERIOD);
+	match("/home/user/.*", "/home/user/.hello", FNM_PATHNAME | FNM_PERIOD);
+	match("/home/user/*", "/home/user/.hello", FNM_PERIOD);
+	nomatch("/home/user/*", "/home/user/.hello", FNM_PATHNAME | FNM_PERIOD);
+
+	nomatch("HeLlO", "hello", 0);
+	match("HeLlO", "hello", FNM_CASEFOLD);
+
+	printf("Failed: %d\n", fail);
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/posix/source/getopt.c
===================================================================
--- uspace/lib/posix/source/getopt.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/getopt.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 Command line argument parsing.
+ */
+#define LIBPOSIX_INTERNAL
+
+#include "internal/common.h"
+#include "libc/getopt.h"
+#include "posix/getopt.h"
+
+
+int posix_getopt_long(int argc, char * const argv[],
+    const char *opt_string, const struct option *long_opts, int *long_index)
+{
+	int rc = getopt_long(argc, argv, opt_string, long_opts, long_index);
+	posix_optarg = (char *) optarg;
+	return rc;
+}
+
+int posix_getopt(int argc, char * const argv[], const char *opt_string)
+{
+	int rc = getopt(argc, argv, opt_string);
+	posix_optarg = (char *) optarg;
+	return rc;
+}
Index: uspace/lib/posix/source/internal/common.h
===================================================================
--- uspace/lib/posix/source/internal/common.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/internal/common.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Helper definitions common for all libposix files.
+ */
+
+#ifndef LIBPOSIX_COMMON_H_
+#define LIBPOSIX_COMMON_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define not_implemented() (fprintf(stderr, \
+    "Function %s() in file %s at line %d is not implemented\n", \
+    __func__, __FILE__, __LINE__), abort())
+
+/* A little helper macro to avoid typing this over and over. */
+#define errnify(func, ...) ({ \
+	int rc = func(__VA_ARGS__); \
+	if (rc < 0) { \
+		errno = -rc; \
+		rc = -1; \
+	} \
+	rc; \
+})
+
+#endif /* LIBPOSIX_COMMON_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/source/locale.c
===================================================================
--- uspace/lib/posix/source/locale.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/locale.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Locale-specific definitions.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "internal/common.h"
+#include "posix/locale.h"
+
+#include "posix/errno.h"
+#include "posix/limits.h"
+#include "posix/string.h"
+
+/* Just a very basic dummy implementation.
+ * This should allow code using locales to work properly, but doesn't provide
+ * any localization functionality.
+ * Should be extended/rewritten when or if HelenOS supports locales natively.
+ */
+
+struct __posix_locale {
+	int _dummy;
+};
+
+const struct posix_lconv C_LOCALE = {
+	.currency_symbol = (char *) "",
+	.decimal_point = (char *) ".",
+	.frac_digits = CHAR_MAX,
+	.grouping = (char *) "",
+	.int_curr_symbol = (char *) "",
+	.int_frac_digits = CHAR_MAX,
+	.int_n_cs_precedes = CHAR_MAX,
+	.int_n_sep_by_space = CHAR_MAX,
+	.int_n_sign_posn = CHAR_MAX,
+	.int_p_cs_precedes = CHAR_MAX,
+	.int_p_sep_by_space = CHAR_MAX,
+	.int_p_sign_posn = CHAR_MAX,
+	.mon_decimal_point = (char *) "",
+	.mon_grouping = (char *) "",
+	.mon_thousands_sep = (char *) "",
+	.negative_sign = (char *) "",
+	.n_cs_precedes = CHAR_MAX,
+	.n_sep_by_space = CHAR_MAX,
+	.n_sign_posn = CHAR_MAX,
+	.positive_sign = (char *) "",
+	.p_cs_precedes = CHAR_MAX,
+	.p_sep_by_space = CHAR_MAX,
+	.p_sign_posn = CHAR_MAX,
+	.thousands_sep = (char *) ""
+};
+
+/**
+ * Set program locale.
+ * 
+ * @param category What category to set.
+ * @param locale Locale name.
+ * @return Original locale name on success, NULL on failure.
+ */
+char *posix_setlocale(int category, const char *locale)
+{
+	// TODO
+	if (locale == NULL || *locale == '\0' ||
+	    posix_strcmp(locale, "C") == 0) {
+		return (char *) "C";
+	}
+	return NULL;
+}
+
+/**
+ * Return locale-specific information.
+ * 
+ * @return Information about the current locale.
+ */
+struct posix_lconv *posix_localeconv(void)
+{
+	// TODO
+	return (struct posix_lconv *) &C_LOCALE;
+}
+
+/**
+ * Duplicate locale object.
+ * 
+ * @param locobj Object to duplicate.
+ * @return Duplicated object.
+ */
+posix_locale_t posix_duplocale(posix_locale_t locobj)
+{
+	if (locobj == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+	posix_locale_t copy = malloc(sizeof(struct __posix_locale));
+	if (copy == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	memcpy(copy, locobj, sizeof(struct __posix_locale));
+	return copy;
+}
+
+/**
+ * Free locale object.
+ * 
+ * @param locobj Object to free.
+ */
+void posix_freelocale(posix_locale_t locobj)
+{
+	if (locobj) {
+		free(locobj);
+	}
+}
+
+/**
+ * Create or modify a locale object.
+ * 
+ * @param category_mask Mask of categories to be set or modified.
+ * @param locale Locale to be used.
+ * @param base Object to modify. 0 if new object is to be created.
+ * @return The new/modified locale object.
+ */
+posix_locale_t posix_newlocale(int category_mask, const char *locale,
+    posix_locale_t base)
+{
+	if (locale == NULL ||
+	    (category_mask & LC_ALL_MASK) != category_mask) {
+		errno = EINVAL;
+		return NULL;
+	}
+	// TODO
+	posix_locale_t new = malloc(sizeof(struct __posix_locale));
+	if (new == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	if (base != NULL) {
+		posix_freelocale(base);
+	}
+	return new;
+}
+
+/**
+ * Set locale for the current thread.
+ * 
+ * @param newloc Locale to use.
+ * @return The previously set locale or LC_GLOBAL_LOCALE
+ */
+posix_locale_t posix_uselocale(posix_locale_t newloc)
+{
+	// TODO
+	return LC_GLOBAL_LOCALE;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/math.c
===================================================================
--- uspace/lib/posix/source/math.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/math.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,65 @@
+/*
+ * 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 Mathematical operations.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "internal/common.h"
+#include "posix/math.h"
+
+/**
+ * 
+ * @param x
+ * @param exp
+ * @return
+ */
+double posix_ldexp(double x, int exp)
+{
+	// TODO: low priority, just a compile-time dependency of binutils
+	not_implemented();
+}
+
+/**
+ * 
+ * @param num
+ * @param exp
+ * @return
+ */
+double posix_frexp(double num, int *exp)
+{
+	// TODO: low priority, just a compile-time dependency of binutils
+	not_implemented();
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/pwd.c
===================================================================
--- uspace/lib/posix/source/pwd.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/pwd.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Password handling.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "posix/stdbool.h"
+#include "posix/pwd.h"
+#include "posix/string.h"
+#include "posix/errno.h"
+#include "posix/assert.h"
+
+static bool entry_read = false;
+
+/* dummy user account */
+static const struct posix_passwd dummy_pwd = {
+	.pw_name = (char *) "user",
+	.pw_uid = 0,
+	.pw_gid = 0,
+	.pw_dir = (char *) "/",
+	.pw_shell = (char *) "/app/bdsh"
+};
+
+/**
+ * Retrieve next broken-down entry from the user database.
+ *
+ * Since HelenOS doesn't have user accounts, this always returns
+ * the same made-up entry.
+ *
+ * @return Next user database entry or NULL if not possible. Since HelenOS
+ *     doesn't have user accounts, this always returns the same made-up entry.
+ */
+struct posix_passwd *posix_getpwent(void)
+{
+	if (entry_read) {
+		return NULL;
+	}
+
+	entry_read = true;
+	return (struct posix_passwd *) &dummy_pwd;
+}
+
+/**
+ * Rewind the user list.
+ */
+void posix_setpwent(void)
+{
+	entry_read = false;
+}
+
+/**
+ * Ends enumerating and releases all resources. (Noop)
+ */
+void posix_endpwent(void)
+{
+	/* noop */
+}
+
+/**
+ * Find an entry by name.
+ *
+ * @param name Name of the entry.
+ * @return Either found entry or NULL if no such entry exists.
+ */
+struct posix_passwd *posix_getpwnam(const char *name)
+{
+	assert(name != NULL);
+
+	if (posix_strcmp(name, "user") != 0) {
+		return NULL;
+	}
+
+	return (struct posix_passwd *) &dummy_pwd;
+}
+
+/**
+ * Find an entry by name, thread safely.
+ *
+ * @param name Name of the entry.
+ * @param pwd Original structure.
+ * @param buffer Buffer for the strings referenced from the result structure.
+ * @param bufsize Length of the buffer.
+ * @param result Where to store updated structure.
+ * @return Zero on success (either found or not found, but without an error),
+ *     non-zero error number if error occured.
+ */
+int posix_getpwnam_r(const char *name, struct posix_passwd *pwd,
+    char *buffer, size_t bufsize, struct posix_passwd **result)
+{
+	assert(name != NULL);
+	assert(pwd != NULL);
+	assert(buffer != NULL);
+	assert(result != NULL);
+	
+	if (posix_strcmp(name, "user") != 0) {
+		*result = NULL;
+		return 0;
+	}
+	
+	return posix_getpwuid_r(0, pwd, buffer, bufsize, result);
+}
+
+/**
+ * Find an entry by UID.
+ *
+ * @param uid UID of the entry.
+ * @return Either found entry or NULL if no such entry exists.
+ */
+struct posix_passwd *posix_getpwuid(posix_uid_t uid)
+{
+	if (uid != 0) {
+		return NULL;
+	}
+
+	return (struct posix_passwd *) &dummy_pwd;
+}
+
+/**
+ * Find an entry by UID, thread safely.
+ *
+ * @param uid UID of the entry.
+ * @param pwd Original structure.
+ * @param buffer Buffer for the strings referenced from the result structure.
+ * @param bufsize Length of the buffer.
+ * @param result Where to store updated structure.
+ * @return Zero on success (either found or not found, but without an error),
+ *     non-zero error number if error occured.
+ */
+int posix_getpwuid_r(posix_uid_t uid, struct posix_passwd *pwd,
+    char *buffer, size_t bufsize, struct posix_passwd **result)
+{
+	assert(pwd != NULL);
+	assert(buffer != NULL);
+	assert(result != NULL);
+	
+	static const char bf[] = { 'u', 's', 'e', 'r', '\0',
+	    '/', '\0', 'b', 'd', 's', 'h', '\0' };
+	
+	if (uid != 0) {
+		*result = NULL;
+		return 0;
+	}
+	if (bufsize < sizeof(bf)) {
+		*result = NULL;
+		return ERANGE;
+	}
+
+	memcpy(buffer, bf, sizeof(bf));
+
+	pwd->pw_name = (char *) bf;
+	pwd->pw_uid = 0;
+	pwd->pw_gid = 0;
+	pwd->pw_dir = (char *) bf + 5;
+	pwd->pw_shell = (char *) bf + 7;
+	*result = (struct posix_passwd *) pwd;
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/signal.c
===================================================================
--- uspace/lib/posix/source/signal.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/signal.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,566 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Signal handling.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "posix/signal.h"
+#include "internal/common.h"
+#include "posix/limits.h"
+#include "posix/stdlib.h"
+#include "posix/string.h"
+#include "posix/errno.h"
+
+#include "libc/fibril_synch.h"
+#include "libc/task.h"
+
+/* This file implements a fairly dumb and incomplete "simulation" of
+ * POSIX signals. Since HelenOS doesn't support signals and mostly doesn't
+ * have any equivalent functionality, most of the signals are useless. The
+ * main purpose of this implementation is thus to help port applications using
+ * signals with minimal modification, but if the application uses signals for
+ * anything non-trivial, it's quite probable it won't work properly even if
+ * it builds without problems.
+ */
+
+/* Used to serialize signal handling. */
+static FIBRIL_MUTEX_INITIALIZE(_signal_mutex);
+
+static LIST_INITIALIZE(_signal_queue);
+
+static posix_sigset_t _signal_mask = 0;
+
+#define DEFAULT_HANDLER { .sa_handler = SIG_DFL, \
+    .sa_mask = 0, .sa_flags = 0, .sa_sigaction = NULL }
+
+/* Actions associated with each signal number. */
+static struct posix_sigaction _signal_actions[_TOP_SIGNAL + 1] = {
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER
+};
+
+/**
+ * Default signal handler. Executes the default action for each signal,
+ * as reasonable within HelenOS.
+ *
+ * @param signo Signal number.
+ */
+void __posix_default_signal_handler(int signo)
+{
+	switch (signo) {
+	case SIGABRT:
+		abort();
+	case SIGQUIT:
+		fprintf(stderr, "Quit signal raised. Exiting.\n");
+		exit(EXIT_FAILURE);
+	case SIGINT:
+		fprintf(stderr, "Interrupt signal caught. Exiting.\n");
+		exit(EXIT_FAILURE);
+	case SIGTERM:
+		fprintf(stderr, "Termination signal caught. Exiting.\n");
+		exit(EXIT_FAILURE);
+	case SIGSTOP:
+		fprintf(stderr, "Stop signal caught, but unsupported. Ignoring.\n");
+		break;
+	case SIGKILL:
+		/* This will only occur when raise or similar is called. */
+		/* Commit suicide. */
+		task_kill(task_get_id());
+		
+		/* Should not be reached. */
+		abort();
+	case SIGFPE:
+	case SIGBUS:
+	case SIGILL:
+	case SIGSEGV:
+		posix_psignal(signo, "Hardware exception raised by user code");
+		abort();
+	case SIGSYS:
+	case SIGXCPU:
+	case SIGXFSZ:
+	case SIGTRAP:
+	case SIGHUP:
+	case SIGPIPE:
+	case SIGPOLL:
+	case SIGURG:
+	case SIGTSTP:
+	case SIGTTIN:
+	case SIGTTOU:
+		posix_psignal(signo, "Unsupported signal caught");
+		abort();
+	case SIGCHLD:
+	case SIGUSR1:
+	case SIGUSR2:
+	case SIGALRM:
+	case SIGVTALRM:
+	case SIGPROF:
+	case SIGCONT:
+		/* ignored */
+		break;
+	}
+}
+
+/**
+ * Just an empty function to get an unique pointer value for comparison.
+ *
+ * @param signo Signal number.
+ */
+void __posix_hold_signal_handler(int signo)
+{
+	/* Nothing */
+}
+
+/**
+ * Empty function to be used as ignoring handler.
+ * 
+ * @param signo Signal number.
+ */
+void __posix_ignore_signal_handler(int signo)
+{
+	/* Nothing */
+}
+
+/**
+ * Clear the signal set.
+ * 
+ * @param set Pointer to the signal set.
+ * @return Always returns zero.
+ */
+int posix_sigemptyset(posix_sigset_t *set)
+{
+	assert(set != NULL);
+
+	*set = 0;
+	return 0;
+}
+
+/**
+ * Fill the signal set (i.e. add all signals).
+ * 
+ * @param set Pointer to the signal set.
+ * @return Always returns zero.
+ */
+int posix_sigfillset(posix_sigset_t *set)
+{
+	assert(set != NULL);
+
+	*set = UINT32_MAX;
+	return 0;
+}
+
+/**
+ * Add a signal to the set.
+ * 
+ * @param set Pointer to the signal set.
+ * @param signo Signal number to add.
+ * @return Always returns zero.
+ */
+int posix_sigaddset(posix_sigset_t *set, int signo)
+{
+	assert(set != NULL);
+
+	*set |= (1 << signo);
+	return 0;
+}
+
+/**
+ * Delete a signal from the set.
+ * 
+ * @param set Pointer to the signal set.
+ * @param signo Signal number to remove.
+ * @return Always returns zero.
+ */
+int posix_sigdelset(posix_sigset_t *set, int signo)
+{
+	assert(set != NULL);
+
+	*set &= ~(1 << signo);
+	return 0;
+}
+
+/**
+ * Inclusion test for a signal set.
+ * 
+ * @param set Pointer to the signal set.
+ * @param signo Signal number to query.
+ * @return 1 if the signal is in the set, 0 otherwise.
+ */
+int posix_sigismember(const posix_sigset_t *set, int signo)
+{
+	assert(set != NULL);
+	
+	return (*set & (1 << signo)) != 0;
+}
+
+/**
+ * Unsafe variant of the sigaction() function.
+ * Doesn't do any checking of its arguments and
+ * does not deal with thread-safety.
+ * 
+ * @param sig
+ * @param act
+ * @param oact
+ */
+static void _sigaction_unsafe(int sig, const struct posix_sigaction *restrict act,
+    struct posix_sigaction *restrict oact)
+{
+	if (oact != NULL) {
+		memcpy(oact, &_signal_actions[sig],
+		    sizeof(struct posix_sigaction));
+	}
+
+	if (act != NULL) {
+		memcpy(&_signal_actions[sig], act,
+		    sizeof(struct posix_sigaction));
+	}
+}
+
+/**
+ * Sets a new action for the given signal number.
+ * 
+ * @param sig Signal number to set action for.
+ * @param act If not NULL, contents of this structure are
+ *     used as the new action for the signal.
+ * @param oact If not NULL, the original action associated with the signal
+ *     is stored in the structure pointer to. 
+ * @return -1 with errno set on failure, 0 on success.
+ */
+int posix_sigaction(int sig, const struct posix_sigaction *restrict act,
+    struct posix_sigaction *restrict oact)
+{
+	if (sig > _TOP_SIGNAL || (act != NULL &&
+	    (sig == SIGKILL || sig == SIGSTOP))) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (sig > _TOP_CATCHABLE_SIGNAL) {
+		posix_psignal(sig,
+		    "WARNING: registering handler for a partially"
+		    " or fully unsupported signal. This handler may only be"
+		    " invoked by the raise() function, which may not be what"
+		    " the application developer intended");
+	}
+
+	fibril_mutex_lock(&_signal_mutex);
+	_sigaction_unsafe(sig, act, oact);
+	fibril_mutex_unlock(&_signal_mutex);
+
+	return 0;
+}
+
+/**
+ * Sets a new handler for the given signal number.
+ * 
+ * @param sig Signal number to set handler for.
+ * @param func Handler function.
+ * @return SIG_ERR on failure, original handler on success.
+ */
+void (*posix_signal(int sig, void (*func)(int)))(int)
+{
+	struct posix_sigaction new = {
+		.sa_handler = func,
+		.sa_mask = 0,
+		.sa_flags = 0,
+		.sa_sigaction = NULL
+	};
+	struct posix_sigaction old;
+	if (posix_sigaction(sig, func == NULL ? NULL : &new, &old) == 0) {
+		return old.sa_handler;
+	} else {
+		return SIG_ERR;
+	}
+}
+
+typedef struct {
+	link_t link;
+	int signo;
+	posix_siginfo_t siginfo;
+} signal_queue_item;
+
+/**
+ * Queue blocked signal.
+ *
+ * @param signo Signal number.
+ * @param siginfo Additional information about the signal.
+ */
+static void _queue_signal(int signo, posix_siginfo_t *siginfo)
+{
+	assert(signo >= 0 && signo <= _TOP_SIGNAL);
+	assert(siginfo != NULL);
+	
+	signal_queue_item *item = malloc(sizeof(signal_queue_item));
+	link_initialize(&(item->link));
+	item->signo = signo;
+	memcpy(&item->siginfo, siginfo, sizeof(posix_siginfo_t));
+	list_append(&(item->link), &_signal_queue);
+}
+
+
+/**
+ * Executes an action associated with the given signal.
+ *
+ * @param signo Signal number.
+ * @param siginfo Additional information about the circumstances of this raise.
+ * @return 0 if the action has been successfully executed. -1 if the signal is
+ *     blocked.
+ */
+static int _raise_sigaction(int signo, posix_siginfo_t *siginfo)
+{
+	assert(signo >= 0 && signo <= _TOP_SIGNAL);
+	assert(siginfo != NULL);
+
+	fibril_mutex_lock(&_signal_mutex);
+
+	struct posix_sigaction action = _signal_actions[signo];
+
+	if (posix_sigismember(&_signal_mask, signo) ||
+	    action.sa_handler == SIG_HOLD) {
+		_queue_signal(signo, siginfo);
+		fibril_mutex_unlock(&_signal_mutex);
+		return -1;
+	}
+
+	/* Modifying signal mask is unnecessary,
+	 * signal handling is serialized.
+	 */
+
+	if ((action.sa_flags & SA_RESETHAND) && signo != SIGILL && signo != SIGTRAP) {
+		_signal_actions[signo] = (struct posix_sigaction) DEFAULT_HANDLER;
+	}
+
+	if (action.sa_flags & SA_SIGINFO) {
+		assert(action.sa_sigaction != NULL);
+		action.sa_sigaction(signo, siginfo, NULL);
+	} else {
+		assert(action.sa_handler != NULL);
+		action.sa_handler(signo);
+	}
+
+	fibril_mutex_unlock(&_signal_mutex);
+
+	return 0;
+}
+
+/**
+ * Raise all unblocked previously queued signals.
+ */
+static void _dequeue_unblocked_signals()
+{
+	link_t *iterator = _signal_queue.head.next;
+	link_t *next;
+	
+	while (iterator != &(_signal_queue).head) {
+		next = iterator->next;
+		
+		signal_queue_item *item =
+		    list_get_instance(iterator, signal_queue_item, link);
+		
+		if (!posix_sigismember(&_signal_mask, item->signo) &&
+		    _signal_actions[item->signo].sa_handler != SIG_HOLD) {
+			list_remove(&(item->link));
+			_raise_sigaction(item->signo, &(item->siginfo));
+			free(item);
+		}
+		
+		iterator = next;
+	}
+}
+
+/**
+ * Raise a signal for the calling process.
+ * 
+ * @param sig Signal number.
+ * @return -1 with errno set on failure, 0 on success.
+ */
+int posix_raise(int sig)
+{
+	if (sig >= 0 && sig <= _TOP_SIGNAL) {
+		posix_siginfo_t siginfo = {
+			.si_signo = sig,
+			.si_code = SI_USER
+		};
+		return _raise_sigaction(sig, &siginfo);
+	} else {
+		errno = EINVAL;
+		return -1;
+	}
+}
+
+/**
+ * Raises a signal for a selected process.
+ * 
+ * @param pid PID of the process for which the signal shall be raised.
+ * @param signo Signal to raise.
+ * @return -1 with errno set on failure (possible errors include unsupported
+ *     action, invalid signal number, lack of permissions, etc.), 0 on success.
+ */
+int posix_kill(posix_pid_t pid, int signo)
+{
+	if (pid < 1) {
+		// TODO
+		errno = ENOTSUP;
+		return -1;
+	}
+
+	if (signo > _TOP_SIGNAL) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (pid == (posix_pid_t) task_get_id()) {
+		return posix_raise(signo);
+	}
+
+	switch (signo) {
+	case SIGKILL:
+		task_kill(pid);
+		break;
+	default:
+		/* Nothing else supported yet. */
+		errno = ENOTSUP;
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * Send a signal to a process group. Always fails at the moment because of
+ * lack of this functionality in HelenOS.
+ * 
+ * @param pid PID of the process group.
+ * @param sig Signal number.
+ * @return -1 on failure, 0 on success (see kill()).
+ */
+int posix_killpg(posix_pid_t pid, int sig)
+{
+	assert(pid > 1);
+	return posix_kill(-pid, sig);
+}
+
+/**
+ * Outputs information about the signal to the standard error stream.
+ * 
+ * @param pinfo SigInfo struct to write.
+ * @param message String to output alongside human-readable signal description.
+ */
+void posix_psiginfo(const posix_siginfo_t *pinfo, const char *message)
+{
+	assert(pinfo != NULL);
+	posix_psignal(pinfo->si_signo, message);
+	// TODO: print si_code
+}
+
+/**
+ * Outputs information about the signal to the standard error stream.
+ * 
+ * @param signum Signal number.
+ * @param message String to output alongside human-readable signal description.
+ */
+void posix_psignal(int signum, const char *message)
+{
+	char *sigmsg = posix_strsignal(signum);
+	if (message == NULL || *message == '\0') {
+		fprintf(stderr, "%s\n", sigmsg);
+	} else {
+		fprintf(stderr, "%s: %s\n", message, sigmsg);
+	}
+}
+
+/**
+ * Manipulate the signal mask of the calling thread.
+ * 
+ * @param how What to do with the mask.
+ * @param set Signal set to work with.
+ * @param oset If not NULL, the original signal mask is coppied here.
+ * @return 0 success, errorcode on failure.
+ */
+int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
+    posix_sigset_t *restrict oset)
+{
+	fibril_mutex_lock(&_signal_mutex);
+
+	if (oset != NULL) {
+		*oset = _signal_mask;
+	}
+	if (set != NULL) {
+		switch (how) {
+		case SIG_BLOCK:
+			_signal_mask |= *set;
+			break;
+		case SIG_UNBLOCK:
+			_signal_mask &= ~*set;
+			break;
+		case SIG_SETMASK:
+			_signal_mask = *set;
+			break;
+		default:
+			fibril_mutex_unlock(&_signal_mutex);
+			return EINVAL;
+		}
+	}
+	
+	_dequeue_unblocked_signals();
+
+	fibril_mutex_unlock(&_signal_mutex);
+
+	return 0;
+}
+
+/**
+ * Manipulate the signal mask of the process.
+ * 
+ * @param how What to do with the mask.
+ * @param set Signal set to work with.
+ * @param oset If not NULL, the original signal mask is coppied here.
+ * @return 0 on success, -1 with errno set on failure.
+ */
+int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
+    posix_sigset_t *restrict oset)
+{
+	int result = posix_thread_sigmask(how, set, oset);
+	if (result != 0) {
+		errno = result;
+		return -1;
+	}
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/stdio.c
===================================================================
--- uspace/lib/posix/source/stdio.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/stdio.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,808 @@
+/*
+ * 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.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+/* Has to be first. */
+#include "posix/stdbool.h"
+
+#include "internal/common.h"
+#include "posix/stdio.h"
+
+#include "posix/assert.h"
+#include "posix/errno.h"
+#include "posix/stdlib.h"
+#include "posix/string.h"
+#include "posix/sys/types.h"
+#include "posix/unistd.h"
+
+#include "libc/stdio.h"
+#include "libc/io/printf_core.h"
+#include "libc/str.h"
+#include "libc/malloc.h"
+#include "libc/adt/list.h"
+#include "libc/sys/stat.h"
+
+
+/* not the best of solutions, but freopen and ungetc will eventually
+ * need to be implemented in libc anyway
+ */
+#include "../../c/generic/private/stdio.h"
+
+/** Clears the stream's error and end-of-file indicators.
+ *
+ * @param stream Stream whose indicators shall be cleared.
+ */
+void posix_clearerr(FILE *stream)
+{
+	stream->error = 0;
+	stream->eof = 0;
+}
+
+/**
+ * Generate a pathname for the controlling terminal.
+ *
+ * @param s Allocated buffer to which the pathname shall be put.
+ * @return Either s or static location filled with the requested pathname.
+ */
+char *posix_ctermid(char *s)
+{
+	/* Currently always returns an error value (empty string). */
+	// TODO: return a real terminal path
+
+	static char dummy_path[L_ctermid] = {'\0'};
+
+	if (s == NULL) {
+		return dummy_path;
+	}
+
+	s[0] = '\0';
+	return s;
+}
+
+/**
+ * Put a string on the stream.
+ * 
+ * @param s String to be written.
+ * @param stream Output stream.
+ * @return Non-negative on success, EOF on failure.
+ */
+int posix_fputs(const char *restrict s, FILE *restrict stream)
+{
+	int rc = fputs(s, stream);
+	if (rc == 0) {
+		return EOF;
+	} else {
+		return 0;
+	}
+}
+
+/**
+ * Push byte back into input stream.
+ * 
+ * @param c Byte to be pushed back.
+ * @param stream Stream to where the byte shall be pushed.
+ * @return Provided byte on success or EOF if not possible.
+ */
+int posix_ungetc(int c, FILE *stream)
+{
+	uint8_t b = (uint8_t) c;
+
+	bool can_unget =
+	    /* Provided character is legal. */
+	    c != EOF &&
+	    /* Stream is consistent. */
+	    !stream->error &&
+	    /* Stream is buffered. */
+	    stream->btype != _IONBF &&
+	    /* Last operation on the stream was a read operation. */
+	    stream->buf_state == _bs_read &&
+	    /* Stream buffer is already allocated (i.e. there was already carried
+	     * out either write or read operation on the stream). This is probably
+	     * redundant check but let's be safe. */
+	    stream->buf != NULL &&
+	    /* There is still space in the stream to retreat. POSIX demands the
+	     * possibility to unget at least 1 character. It should be always
+	     * possible, assuming the last operation on the stream read at least 1
+	     * character, because the buffer is refilled in the lazily manner. */
+	    stream->buf_tail > stream->buf;
+
+	if (can_unget) {
+		--stream->buf_tail;
+		stream->buf_tail[0] = b;
+		stream->eof = false;
+		return (int) b;
+	} else {
+		return EOF;
+	}
+}
+
+/**
+ * Read a stream until the delimiter (or EOF) is encountered.
+ *
+ * @param lineptr Pointer to the output buffer in which there will be stored
+ *     nul-terminated string together with the delimiter (if encountered).
+ *     Will be resized if necessary.
+ * @param n Pointer to the size of the output buffer. Will be increased if
+ *     necessary.
+ * @param delimiter Delimiter on which to finish reading the stream.
+ * @param stream Input stream.
+ * @return Number of fetched characters (including delimiter if encountered)
+ *     or -1 on error (set in errno).
+ */
+ssize_t posix_getdelim(char **restrict lineptr, size_t *restrict n,
+    int delimiter, FILE *restrict stream)
+{
+	/* Check arguments for sanity. */
+	if (!lineptr || !n) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	size_t alloc_step = 80; /* Buffer size gain during reallocation. */
+	char *pos = *lineptr; /* Next free byte of the output buffer. */
+	size_t cnt = 0; /* Number of fetched characters. */
+	int c = fgetc(stream); /* Current input character. Might be EOF. */
+
+	do {
+		/* Mask EOF as NUL to terminate string. */
+		if (c == EOF) {
+			c = '\0';
+		}
+
+		/* Ensure there is still space left in the buffer. */
+		if (pos == *lineptr + *n) {
+			*lineptr = realloc(*lineptr, *n + alloc_step);
+			if (*lineptr) {
+				pos = *lineptr + *n;
+				*n += alloc_step;
+			} else {
+				errno = ENOMEM;
+				return -1;
+			}
+		}
+
+		/* Store the fetched character. */
+		*pos = c;
+
+		/* Fetch the next character according to the current character. */
+		if (c != '\0') {
+			++pos;
+			++cnt;
+			if (c == delimiter) {
+				/* Delimiter was just stored. Provide EOF as the next
+				 * character - it will be masked as NUL and output string
+				 * will be properly terminated. */
+				c = EOF;
+			} else {
+				/* Neither delimiter nor EOF were encountered. Just fetch
+				 * the next character from the stream. */
+				c = fgetc(stream);
+			}
+		}
+	} while (c != '\0');
+
+	if (errno == EOK && cnt > 0) {
+		return cnt;
+	} else {
+		/* Either some error occured or the stream was already at EOF. */
+		return -1;
+	}
+}
+
+/**
+ * Read a stream until the newline (or EOF) is encountered.
+ * 
+ * @param lineptr Pointer to the output buffer in which there will be stored
+ *     nul-terminated string together with the delimiter (if encountered).
+ *     Will be resized if necessary.
+ * @param n Pointer to the size of the output buffer. Will be increased if
+ *     necessary.
+ * @param stream Input stream.
+ * @return Number of fetched characters (including newline if encountered)
+ *     or -1 on error (set in errno).
+ */
+ssize_t posix_getline(char **restrict lineptr, size_t *restrict n,
+    FILE *restrict stream)
+{
+	return posix_getdelim(lineptr, n, '\n', stream);
+}
+
+/**
+ * Reopen a file stream.
+ * 
+ * @param filename Pathname of a file to be reopened or NULL for changing
+ *     the mode of the stream.
+ * @param mode Mode to be used for reopening the file or changing current
+ *     mode of the stream.
+ * @param stream Current stream associated with the opened file.
+ * @return On success, either a stream of the reopened file or the provided
+ *     stream with a changed mode. NULL otherwise.
+ */
+FILE *posix_freopen(const char *restrict filename, 
+    const char *restrict mode, FILE *restrict stream)
+{
+	assert(mode != NULL);
+	assert(stream != NULL);
+	
+	if (filename == NULL) {
+		/* POSIX allows this to be imlementation-defined. HelenOS currently
+		 * does not support changing the mode. */
+		// FIXME: handle mode change once it is supported
+		return stream;
+	}
+	
+	/* Open a new stream. */
+	FILE* new = fopen(filename, mode);
+	if (new == NULL) {
+		fclose(stream);
+		/* errno was set by fopen() */
+		return NULL;
+	}
+	
+	/* Close the original stream without freeing it (ignoring errors). */
+	if (stream->buf != NULL) {
+		fflush(stream);
+	}
+	if (stream->sess != NULL) {
+		async_hangup(stream->sess);
+	}
+	if (stream->fd >= 0) {
+		close(stream->fd);
+	}
+	list_remove(&stream->link);
+	
+	/* Move the new stream to the original location. */
+	memcpy(stream, new, sizeof (FILE));
+	free(new);
+	
+	/* Update references in the file list. */
+	stream->link.next->prev = &stream->link;
+	stream->link.prev->next = &stream->link;
+	
+	return stream;
+}
+
+/**
+ * Write error messages to standard error.
+ *
+ * @param s Error message.
+ */
+void posix_perror(const char *s)
+{
+	if (s == NULL || s[0] == '\0') {
+		fprintf(stderr, "%s\n", posix_strerror(errno));
+	} else {
+		fprintf(stderr, "%s: %s\n", s, posix_strerror(errno));
+	}
+}
+
+struct _posix_fpos {
+	off64_t offset;
+};
+
+/** Restores stream a to position previously saved with fgetpos().
+ *
+ * @param stream Stream to restore
+ * @param pos Position to restore
+ * @return Zero on success, non-zero (with errno set) on failure
+ */
+int posix_fsetpos(FILE *stream, const posix_fpos_t *pos)
+{
+	return fseek(stream, pos->offset, SEEK_SET);
+}
+
+/** Saves the stream's position for later use by fsetpos().
+ *
+ * @param stream Stream to save
+ * @param pos Place to store the position
+ * @return Zero on success, non-zero (with errno set) on failure
+ */
+int posix_fgetpos(FILE *restrict stream, posix_fpos_t *restrict pos)
+{
+	off64_t ret = ftell(stream);
+	if (ret != -1) {
+		pos->offset = ret;
+		return 0;
+	} else {
+		return -1;
+	}
+}
+
+/**
+ * Reposition a file-position indicator in a stream.
+ * 
+ * @param stream Stream to seek in.
+ * @param offset Direction and amount of bytes to seek.
+ * @param whence From where to seek.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_fseek(FILE *stream, long offset, int whence)
+{
+	return fseek(stream, (off64_t) offset, whence);
+}
+
+/**
+ * Reposition a file-position indicator in a stream.
+ * 
+ * @param stream Stream to seek in.
+ * @param offset Direction and amount of bytes to seek.
+ * @param whence From where to seek.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_fseeko(FILE *stream, posix_off_t offset, int whence)
+{
+	return fseek(stream, (off64_t) offset, whence);
+}
+
+/**
+ * Discover current file offset in a stream.
+ * 
+ * @param stream Stream for which the offset shall be retrieved.
+ * @return Current offset or -1 if not possible.
+ */
+long posix_ftell(FILE *stream)
+{
+	return (long) ftell(stream);
+}
+
+/**
+ * Discover current file offset in a stream.
+ * 
+ * @param stream Stream for which the offset shall be retrieved.
+ * @return Current offset or -1 if not possible.
+ */
+posix_off_t posix_ftello(FILE *stream)
+{
+	return (posix_off_t) ftell(stream);
+}
+
+/**
+ * Discard prefetched data or write unwritten data.
+ * 
+ * @param stream Stream that shall be flushed.
+ * @return Zero on success, EOF on failure.
+ */
+int posix_fflush(FILE *stream)
+{
+	int rc = fflush(stream);
+	if (rc < 0) {
+		errno = -rc;
+		return EOF;
+	} else {
+		return 0;
+	}
+}
+
+/**
+ * Print formatted output to the opened file.
+ *
+ * @param fildes File descriptor of the opened file.
+ * @param format Format description.
+ * @return Either the number of printed characters or negative value on error.
+ */
+int posix_dprintf(int fildes, const char *restrict format, ...)
+{
+	va_list list;
+	va_start(list, format);
+	int result = posix_vdprintf(fildes, format, list);
+	va_end(list);
+	return result;
+}
+
+/**
+ * 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)) != EOK) {
+			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 posix_vdprintf(int fildes, const char *restrict 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 posix_sprintf(char *s, const char *restrict format, ...)
+{
+	va_list list;
+	va_start(list, format);
+	int result = posix_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 posix_vsprintf(char *s, const char *restrict format, va_list ap)
+{
+	return vsnprintf(s, STR_NO_LIMIT, format, ap);
+}
+
+/**
+ * Convert formatted input from the stream.
+ * 
+ * @param stream Input stream.
+ * @param format Format description.
+ * @return The number of converted output items or EOF on failure.
+ */
+int posix_fscanf(FILE *restrict stream, const char *restrict format, ...)
+{
+	va_list list;
+	va_start(list, format);
+	int result = posix_vfscanf(stream, format, list);
+	va_end(list);
+	return result;
+}
+
+/**
+ * Convert formatted input from the standard input.
+ * 
+ * @param format Format description.
+ * @return The number of converted output items or EOF on failure.
+ */
+int posix_scanf(const char *restrict format, ...)
+{
+	va_list list;
+	va_start(list, format);
+	int result = posix_vscanf(format, list);
+	va_end(list);
+	return result;
+}
+
+/**
+ * Convert formatted input from the standard input.
+ * 
+ * @param format Format description.
+ * @param arg Output items.
+ * @return The number of converted output items or EOF on failure.
+ */
+int posix_vscanf(const char *restrict format, va_list arg)
+{
+	return posix_vfscanf(stdin, format, arg);
+}
+
+/**
+ * Convert formatted input from the string.
+ * 
+ * @param s Input string.
+ * @param format Format description.
+ * @return The number of converted output items or EOF on failure.
+ */
+int posix_sscanf(const char *restrict s, const char *restrict format, ...)
+{
+	va_list list;
+	va_start(list, format);
+	int result = posix_vsscanf(s, format, list);
+	va_end(list);
+	return result;
+}
+
+/**
+ * Acquire file stream for the thread.
+ *
+ * @param file File stream to lock.
+ */
+void posix_flockfile(FILE *file)
+{
+	/* dummy */
+}
+
+/**
+ * Acquire file stream for the thread (non-blocking).
+ *
+ * @param file File stream to lock.
+ * @return Zero for success and non-zero if the lock cannot be acquired.
+ */
+int posix_ftrylockfile(FILE *file)
+{
+	/* dummy */
+	return 0;
+}
+
+/**
+ * Relinquish the ownership of the locked file stream.
+ *
+ * @param file File stream to unlock.
+ */
+void posix_funlockfile(FILE *file)
+{
+	/* dummy */
+}
+
+/**
+ * Get a byte from a stream (thread-unsafe).
+ *
+ * @param stream Input file stream.
+ * @return Either read byte or EOF.
+ */
+int posix_getc_unlocked(FILE *stream)
+{
+	return getc(stream);
+}
+
+/**
+ * Get a byte from the standard input stream (thread-unsafe).
+ *
+ * @return Either read byte or EOF.
+ */
+int posix_getchar_unlocked(void)
+{
+	return getchar();
+}
+
+/**
+ * Put a byte on a stream (thread-unsafe).
+ *
+ * @param c Byte to output.
+ * @param stream Output file stream.
+ * @return Either written byte or EOF.
+ */
+int posix_putc_unlocked(int c, FILE *stream)
+{
+	return putc(c, stream);
+}
+
+/**
+ * Put a byte on the standard output stream (thread-unsafe).
+ * 
+ * @param c Byte to output.
+ * @return Either written byte or EOF.
+ */
+int posix_putchar_unlocked(int c)
+{
+	return putchar(c);
+}
+
+/**
+ * Remove a file or directory.
+ *
+ * @param path Pathname of the file that shall be removed.
+ * @return Zero on success, -1 (with errno set) otherwise.
+ */
+int posix_remove(const char *path)
+{
+	struct stat st;
+	int rc = stat(path, &st);
+	
+	if (rc != EOK) {
+		errno = -rc;
+		return -1;
+	}
+	
+	if (st.is_directory) {
+		rc = rmdir(path);
+	} else {
+		rc = unlink(path);
+	}
+	
+	if (rc != EOK) {
+		errno = -rc;
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Rename a file or directory.
+ *
+ * @param old Old pathname.
+ * @param new New pathname.
+ * @return Zero on success, -1 (with errno set) otherwise.
+ */
+int posix_rename(const char *old, const char *new)
+{
+	return errnify(rename, old, new);
+}
+
+/**
+ * Get a unique temporary file name (obsolete).
+ *
+ * @param s Buffer for the file name. Must be at least L_tmpnam bytes long.
+ * @return The value of s on success, NULL on failure.
+ */
+char *posix_tmpnam(char *s)
+{
+	assert(L_tmpnam >= posix_strlen("/tmp/tnXXXXXX"));
+	
+	static char buffer[L_tmpnam + 1];
+	if (s == NULL) {
+		s = buffer;
+	}
+	
+	posix_strcpy(s, "/tmp/tnXXXXXX");
+	posix_mktemp(s);
+	
+	if (*s == '\0') {
+		/* Errno set by mktemp(). */
+		return NULL;
+	}
+	
+	return s;
+}
+
+/**
+ * Get an unique temporary file name with additional constraints (obsolete).
+ *
+ * @param dir Path to directory, where the file should be created.
+ * @param pfx Optional prefix up to 5 characters long.
+ * @return Newly allocated unique path for temporary file. NULL on failure.
+ */
+char *posix_tempnam(const char *dir, const char *pfx)
+{
+	/* Sequence number of the filename. */
+	static int seq = 0;
+	
+	size_t dir_len = posix_strlen(dir);
+	if (dir[dir_len - 1] == '/') {
+		dir_len--;
+	}
+	
+	size_t pfx_len = posix_strlen(pfx);
+	if (pfx_len > 5) {
+		pfx_len = 5;
+	}
+	
+	char *result = malloc(dir_len + /* slash*/ 1 +
+	    pfx_len + /* three-digit seq */ 3 + /* .tmp */ 4 + /* nul */ 1);
+	
+	if (result == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	char *res_ptr = result;
+	posix_strncpy(res_ptr, dir, dir_len);
+	res_ptr += dir_len;
+	posix_strncpy(res_ptr, pfx, pfx_len);
+	res_ptr += pfx_len;
+	
+	for (; seq < 1000; ++seq) {
+		snprintf(res_ptr, 8, "%03d.tmp", seq);
+		
+		int orig_errno = errno;
+		errno = 0;
+		/* Check if the file exists. */
+		if (posix_access(result, F_OK) == -1) {
+			if (errno == ENOENT) {
+				errno = orig_errno;
+				break;
+			} else {
+				/* errno set by access() */
+				return NULL;
+			}
+		}
+	}
+	
+	if (seq == 1000) {
+		free(result);
+		errno = EINVAL;
+		return NULL;
+	}
+	
+	return result;
+}
+
+/**
+ * Create and open an unique temporary file.
+ * The file is automatically removed when the stream is closed.
+ *
+ * @param dir Path to directory, where the file should be created.
+ * @param pfx Optional prefix up to 5 characters long.
+ * @return Newly allocated unique path for temporary file. NULL on failure.
+ */
+FILE *posix_tmpfile(void)
+{
+	char filename[] = "/tmp/tfXXXXXX";
+	int fd = posix_mkstemp(filename);
+	if (fd == -1) {
+		/* errno set by mkstemp(). */
+		return NULL;
+	}
+	
+	/* Unlink the created file, so that it's removed on close(). */
+	posix_unlink(filename);
+	return fdopen(fd, "w+");
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/stdio/scanf.c
===================================================================
--- uspace/lib/posix/source/stdio/scanf.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/stdio/scanf.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,1339 @@
+/*
+ * 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 Implementation of the scanf backend.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+/* Must be first. */
+#include "posix/stdbool.h"
+
+#include "posix/assert.h"
+#include "posix/errno.h"
+
+#include "posix/stdio.h"
+#include "posix/stdlib.h"
+#include "posix/stddef.h"
+#include "posix/string.h"
+#include "posix/ctype.h"
+#include "posix/sys/types.h"
+
+#include "../internal/common.h"
+#include "libc/malloc.h"
+
+/** Unified data type for possible data sources for scanf. */
+typedef union __data_source {
+	FILE *stream; /**< Input file stream. */
+	const char *string; /**< Input string. */
+} _data_source;
+
+/** Internal state of the input provider. */
+enum {
+	/** Partly constructed but not yet functional. */
+	_PROV_CONSTRUCTED,
+	/** Ready to serve any request. */
+	_PROV_READY,
+	/** Cursor is temporarily lent to the external entity. No action is
+	  * possible until the cursor is returned.  */
+	_PROV_CURSOR_LENT,
+};
+
+/** Universal abstraction over data input for scanf. */
+typedef struct __input_provider {
+	/** Source of data elements. */
+	_data_source source;
+	/** How many elements was already processed. */
+	int consumed;
+	/** How many elements was already fetched from the source. */
+	int fetched;
+	/** Elements are fetched from the source in batches (e.g. by getline())
+	  * to allow using strtol/strtod family even on streams. */
+	char *window;
+	/** Size of the current window. */
+	size_t window_size;
+	/** Points to the next element to be processed inside the current window. */
+	const char *cursor;
+	/** Internal state of the provider. */
+	int state;
+
+	/** Take control over data source. Finish initialization of the internal
+	  * structures (e.g. allocation of window). */
+	void (*capture)(struct __input_provider *);
+	/** Get a single element from the source and update the internal structures
+	  * accordingly (e.g. greedy update of the window). Return -1 if the
+	  * element cannot be obtained. */
+	int (*pop)(struct __input_provider *);
+	/** Undo the most recent not-undone pop operation. Might be necesarry to
+	  * flush current window and seek data source backwards. Return 0 if the
+	  * pop history is exhausted, non-zero on success. */
+	int (*undo)(struct __input_provider *);
+	/** Lend the cursor to the caller.  */
+	const char * (*borrow_cursor)(struct __input_provider *);
+	/** Take control over possibly incremented cursor and update the internal
+	  * structures if necessary. */
+	void (*return_cursor)(struct __input_provider *, const char *);
+	/** Release the control over the source. That is, synchronize any
+	  * fetched but non-consumed elements (e.g. by seeking) and destruct
+	  * internal structures (e.g. window deallocation). */
+	void (*release)(struct __input_provider *);
+} _input_provider;
+
+/** @see __input_provider */
+static void _capture_stream(_input_provider *self)
+{
+	assert(self->source.stream);
+	assert(self->state == _PROV_CONSTRUCTED);
+	/* Caller could already pre-allocated the window. */
+	assert((self->window == NULL && self->window_size == 0) ||
+	    (self->window && self->window_size > 0));
+
+	/* Initialize internal structures. */
+	self->consumed = 0;
+	ssize_t fetched = posix_getline(
+	    &self->window, &self->window_size, self->source.stream);
+	if (fetched != -1) {
+		self->fetched = fetched;
+		self->cursor = self->window;
+	} else {
+		/* EOF encountered. */
+		self->fetched = 0;
+		self->cursor = NULL;
+	}
+	self->state = _PROV_READY;
+}
+
+/** @see __input_provider */
+static void _capture_string(_input_provider *self)
+{
+	assert(self->source.string);
+	assert(self->state == _PROV_CONSTRUCTED);
+
+	/* Initialize internal structures. */
+	self->consumed = 0;
+	self->fetched = posix_strlen(self->source.string);
+	self->window = (char *) self->source.string;
+	self->window_size = self->fetched + 1;
+	self->cursor = self->window;
+	self->state = _PROV_READY;
+}
+
+/** @see __input_provider */
+static int _pop_stream(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+
+	if (self->cursor) {
+		int c = *self->cursor;
+		++self->consumed;
+		++self->cursor;
+		/* Do we need to fetch a new line from the source? */
+		if (*self->cursor == '\0') {
+			ssize_t fetched = posix_getline(&self->window,
+			    &self->window_size, self->source.stream);
+			if (fetched != -1) {
+				self->fetched += fetched;
+				self->cursor = self->window;
+			} else {
+				/* EOF encountered. */
+				self->cursor = NULL;
+			}
+		}
+		return c;
+	} else {
+		/* Already at EOF. */
+		return -1;
+	}
+}
+
+/** @see __input_provider */
+static int _pop_string(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+
+	if (*self->cursor != '\0') {
+		int c = *self->cursor;
+		++self->consumed;
+		++self->cursor;
+		return c;
+	} else {
+		/* String depleted. */
+		return -1;
+	}
+}
+
+/** @see __input_provider */
+static int _undo_stream(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+
+	if (self->consumed == 0) {
+		/* Undo history exhausted. */
+		return 0;
+	}
+
+	if (!self->cursor || self->window == self->cursor) {
+		/* Complex case. Either at EOF (cursor == NULL) or there is no more
+		 * place to retreat to inside the window. Seek the source backwards
+		 * and flush the window. Regarding the scanf, this could happend only
+		 * when matching unbounded string (%s) or unbounded scanset (%[) not
+		 * containing newline, while at the same time newline is the character
+		 * that breaks the matching process. */
+		int rc = posix_fseek(
+		    self->source.stream, -1, SEEK_CUR);
+		if (rc == -1) {
+			/* Seek failed.  */
+			return 0;
+		}
+		ssize_t fetched = posix_getline(&self->window,
+		    &self->window_size, self->source.stream);
+		if (fetched != -1) {
+			assert(fetched == 1);
+			self->fetched = self->consumed + 1;
+			self->cursor = self->window;
+		} else {
+			/* Stream is broken. */
+			return 0;
+		}
+	} else {
+		/* Simple case. Still inside window. */
+		--self->cursor;
+	}
+	--self->consumed;
+	return 1; /* Success. */
+}
+
+/** @see __input_provider */
+static int _undo_string(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+
+	if (self->consumed > 0) {
+		--self->consumed;
+		--self->cursor;
+	} else {
+		/* Undo history exhausted. */
+		return 0;
+	}
+	return 1; /* Success. */
+}
+
+/** @see __input_provider */
+static const char *_borrow_cursor_universal(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+
+	self->state = _PROV_CURSOR_LENT;
+	return self->cursor;
+}
+
+/** @see __input_provider */
+static void _return_cursor_stream(_input_provider *self, const char *cursor)
+{
+	assert(self->state == _PROV_CURSOR_LENT);
+
+	/* Check how much of the window did external entity consumed. */
+	self->consumed += cursor - self->cursor;
+	self->cursor = cursor;
+	if (*self->cursor == '\0') {
+		/* Window was completely consumed, fetch new data. */
+		ssize_t fetched = posix_getline(&self->window,
+		    &self->window_size, self->source.stream);
+		if (fetched != -1) {
+			self->fetched += fetched;
+			self->cursor = self->window;
+		} else {
+			/* EOF encountered. */
+			self->cursor = NULL;
+		}
+	}
+	self->state = _PROV_READY;
+}
+
+/** @see __input_provider */
+static void _return_cursor_string(_input_provider *self, const char *cursor)
+{
+	assert(self->state == _PROV_CURSOR_LENT);
+
+	/* Check how much of the window did external entity consumed. */
+	self->consumed += cursor - self->cursor;
+	self->cursor = cursor;
+	self->state = _PROV_READY;
+}
+
+/** @see __input_provider */
+static void _release_stream(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+	assert(self->consumed >= self->fetched);
+
+	/* Try to correct the difference between the stream position and what was
+	 * actually consumed. If it is not possible, continue anyway. */
+	posix_fseek(self->source.stream, self->consumed - self->fetched, SEEK_CUR);
+
+	/* Destruct internal structures. */
+	self->fetched = 0;
+	self->cursor = NULL;
+	if (self->window) {
+		free(self->window);
+		self->window = NULL;
+	}
+	self->window_size = 0;
+	self->state = _PROV_CONSTRUCTED;
+}
+
+/** @see __input_provider */
+static void _release_string(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+
+	/* Destruct internal structures. */
+	self->fetched = 0;
+	self->cursor = NULL;
+	self->window = NULL;
+	self->window_size = 0;
+	self->state = _PROV_CONSTRUCTED;
+}
+
+/** Length modifier values. */
+enum {
+	LMOD_NONE,
+	LMOD_hh,
+	LMOD_h,
+	LMOD_l,
+	LMOD_ll,
+	LMOD_j,
+	LMOD_z,
+	LMOD_t,
+	LMOD_L,
+	LMOD_p, /* Reserved for %p conversion. */
+};
+
+/**
+ * Decides whether provided characters specify length modifier. If so, the
+ * recognized modifier is stored through provider pointer.
+ *
+ * @param c Candidate on the length modifier.
+ * @param _c Next character (might be NUL).
+ * @param modifier Pointer to the modifier value.
+ * @return Whether the modifier was recognized or not.
+ */
+static inline int is_length_mod(int c, int _c, int *modifier)
+{
+	assert(modifier);
+
+	switch (c) {
+	case 'h':
+		/* Check whether the modifier was not already recognized. */
+		if (*modifier == LMOD_NONE) {
+			*modifier = _c == 'h' ? LMOD_hh : LMOD_h;
+		} else {
+			/* Format string is invalid. Notify the caller. */
+			*modifier = LMOD_NONE;
+		}
+		return 1;
+	case 'l':
+		if (*modifier == LMOD_NONE) {
+			*modifier = _c == 'l' ? LMOD_ll : LMOD_l;
+		} else {
+			*modifier = LMOD_NONE;
+		}
+		return 1;
+	case 'j':
+		*modifier = *modifier == LMOD_NONE ? LMOD_j : LMOD_NONE;
+		return 1;
+	case 'z':
+		*modifier = *modifier == LMOD_NONE ? LMOD_z : LMOD_NONE;
+		return 1;
+	case 't':
+		*modifier = *modifier == LMOD_NONE ? LMOD_t : LMOD_NONE;
+		return 1;
+	case 'L':
+		*modifier = *modifier == LMOD_NONE ? LMOD_L : LMOD_NONE;
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/**
+ * Decides whether provided character specifies integer conversion. If so, the
+ * semantics of the conversion is stored through provided pointers..
+ * 
+ * @param c Candidate on the integer conversion.
+ * @param is_unsigned Pointer to store whether the conversion is signed or not.
+ * @param base Pointer to store the base of the integer conversion.
+ * @return Whether the conversion was recognized or not.
+ */
+static inline int is_int_conv(int c, bool *is_unsigned, int *base)
+{
+	assert(is_unsigned && base);
+
+	switch (c) {
+	case 'd':
+		*is_unsigned = false;
+		*base = 10;
+		return 1;
+	case 'i':
+		*is_unsigned = false;
+		*base = 0;
+		return 1;
+	case 'o':
+		*is_unsigned = true;
+		*base = 8;
+		return 1;
+	case 'u':
+		*is_unsigned = true;
+		*base = 10;
+		return 1;
+	case 'p': /* According to POSIX, %p modifier is implementation defined but
+			   * must correspond to its printf counterpart. */
+	case 'x':
+	case 'X':
+		*is_unsigned = true;
+		*base = 16;
+		return 1;
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/**
+ * Decides whether provided character specifies conversion of the floating
+ * point number.
+ *
+ * @param c Candidate on the floating point conversion.
+ * @return Whether the conversion was recognized or not.
+ */
+static inline int is_float_conv(int c)
+{
+	switch (c) {
+	case 'a':
+	case 'A':
+	case 'e':
+	case 'E':
+	case 'f':
+	case 'F':
+	case 'g':
+	case 'G':
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/**
+ * Decides whether provided character specifies conversion of the character
+ * sequence.
+ *
+ * @param c Candidate on the character sequence conversion.
+ * @param modifier Pointer to store length modifier for wide chars.
+ * @return Whether the conversion was recognized or not.
+ */
+static inline int is_seq_conv(int c, int *modifier)
+{
+	assert(modifier);
+	
+	switch (c) {
+	case 'S':
+		*modifier = LMOD_l;
+		/* fallthrough */
+	case 's':
+		return 1;
+	case 'C':
+		*modifier = LMOD_l;
+		/* fallthrough */
+	case 'c':
+		return 1;
+	case '[':
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/**
+ * Backend for the whole family of scanf functions. Uses input provider
+ * to abstract over differences between strings and streams. Should be
+ * POSIX compliant (apart from the not supported stuff).
+ *
+ * NOT SUPPORTED: locale (see strtold), wide chars, numbered output arguments
+ * 
+ * @param in Input provider.
+ * @param fmt Format description.
+ * @param arg Output arguments.
+ * @return The number of converted output items or EOF on failure.
+ */
+static inline int _internal_scanf(
+    _input_provider *in, const char *restrict fmt, va_list arg)
+{
+	int c = -1;
+	int converted_cnt = 0;
+	bool converting = false;
+	bool matching_failure = false;
+
+	bool assign_supress = false;
+	bool assign_alloc = false;
+	long width = -1;
+	int length_mod = LMOD_NONE;
+	bool int_conv_unsigned = false;
+	int int_conv_base = 0;
+
+	/* Buffers allocated by scanf for optional 'm' specifier must be remembered
+	 * to deallocaate them in case of an error. Because each of those buffers
+	 * corresponds to one of the argument from va_list, there is an upper bound
+	 * on the number of those arguments. In case of C99, this uppper bound is
+	 * 127 arguments. */
+	char *buffers[127];
+	for (int i = 0; i < 127; ++i) {
+		buffers[i] = NULL;
+	}
+	int next_unused_buffer_idx = 0;
+
+	in->capture(in);
+
+	/* Interpret format string. Control shall prematurely jump from the cycle
+	 * on input failure, matching failure or illegal format string. In order
+	 * to keep error reporting simple enough and to keep input consistent,
+	 * error condition shall be always manifested as jump from the cycle,
+	 * not function return. Format string pointer shall be updated specifically
+	 * for each sub-case (i.e. there shall be no loop-wide increment).*/
+	while (*fmt) {
+
+		if (converting) {
+
+			/* Processing inside conversion specifier. Either collect optional
+			 * parameters or execute the conversion. When the conversion
+			 * is successfully completed, increment conversion count and switch
+			 * back to normal mode. */
+			if (*fmt == '*') {
+				/* Assignment-supression (optional). */
+				if (assign_supress) {
+					/* Already set. Illegal format string. */
+					break;
+				}
+				assign_supress = true;
+				++fmt;
+			} else if (*fmt == 'm') {
+				/* Assignment-allocation (optional). */
+				if (assign_alloc) {
+					/* Already set. Illegal format string. */
+					break;
+				}
+				assign_alloc = true;
+				++fmt;
+			} else if (*fmt == '$') {
+				/* Reference to numbered output argument. */
+				// TODO
+				not_implemented();
+			} else if (isdigit(*fmt)) {
+				/* Maximum field length (optional). */
+				if (width != -1) {
+					/* Already set. Illegal format string. */
+					break;
+				}
+				char *fmt_new = NULL;
+				width = posix_strtol(fmt, &fmt_new, 10);
+				if (width != 0) {
+					fmt = fmt_new;
+				} else {
+					/* Since POSIX requires width to be non-zero, it is
+					 * sufficient to interpret zero width as error without
+					 * referring to errno. */
+					break;
+				}
+			} else if (is_length_mod(*fmt, *(fmt + 1), &length_mod)) {
+				/* Length modifier (optional). */
+				if (length_mod == LMOD_NONE) {
+					/* Already set. Illegal format string. The actual detection
+					 * is carried out in the is_length_mod(). */
+					break;
+				}
+				if (length_mod == LMOD_hh || length_mod == LMOD_ll) {
+					/* Modifier was two characters long. */
+					++fmt;
+				}
+				++fmt;
+			} else if (is_int_conv(*fmt, &int_conv_unsigned, &int_conv_base)) {
+				/* Integer conversion. */
+
+				/* Check sanity of optional parts of conversion specifier. */
+				if (assign_alloc || length_mod == LMOD_L) {
+					/* Illegal format string. */
+					break;
+				}
+
+				/* Conversion of the integer with %p specifier needs special
+				 * handling, because it is not allowed to have arbitrary
+				 * length modifier.  */
+				if (*fmt == 'p') {
+					if (length_mod == LMOD_NONE) {
+						length_mod = LMOD_p;
+					} else {
+						/* Already set. Illegal format string. */
+						break;
+					}
+				}
+
+				/* First consume any white spaces, so we can borrow cursor
+				 * from the input provider. This way, the cursor will either
+				 * point to the non-white space while the input will be
+				 * prefetched up to the newline (which is suitable for strtol),
+				 * or the input will be at EOF. */
+				do {
+					c = in->pop(in);
+				} while (isspace(c));
+
+				/* After skipping the white spaces, can we actually continue? */
+				if (c == -1) {
+					/* Input failure. */
+					break;
+				} else {
+					/* Everything is OK, just undo the last pop, so the cursor
+					 * can be borrowed. */
+					in->undo(in);
+				}
+
+				const char *cur_borrowed = NULL;
+				const char *cur_limited = NULL;
+				char *cur_updated = NULL;
+
+				/* Borrow the cursor. Until it is returned to the provider
+				 * we cannot jump from the cycle, because it would leave
+				 * the input inconsistent. */
+				cur_borrowed = in->borrow_cursor(in);
+
+				/* If the width is limited, the cursor horizont must be
+				 * decreased accordingly. Otherwise the strtol could read more
+				 * than allowed by width. */
+				if (width != -1) {
+					cur_limited = posix_strndup(cur_borrowed, width);
+				} else {
+					cur_limited = cur_borrowed;
+				}
+				cur_updated = (char *) cur_limited;
+
+				long long sres = 0;
+				unsigned long long ures = 0;
+				errno = 0; /* Reset errno to recognize error later. */
+				/* Try to convert the integer. */
+				if (int_conv_unsigned) {
+					ures = posix_strtoull(cur_limited, &cur_updated, int_conv_base);
+				} else {
+					sres = posix_strtoll(cur_limited, &cur_updated, int_conv_base);
+				}
+
+				/* Update the cursor so it can be returned to the provider. */
+				cur_borrowed += cur_updated - cur_limited;
+				if (width != -1 && cur_limited != NULL) {
+					/* Deallocate duplicated part of the cursor view. */
+					free(cur_limited);
+				}
+				cur_limited = NULL;
+				cur_updated = NULL;
+				/* Return the cursor to the provider. Input consistency is again
+				 * the job of the provider, so we can report errors from
+				 * now on. */
+				in->return_cursor(in, cur_borrowed);
+				cur_borrowed = NULL;
+
+				/* Check whether the conversion was successful. */
+				if (errno != EOK) {
+					matching_failure = true;
+					break;
+				}
+
+				/* If not supressed, assign the converted integer into
+				 * the next output argument. */
+				if (!assign_supress) {
+					if (int_conv_unsigned) {
+						switch (length_mod) {
+						case LMOD_hh: ; /* Label cannot be part of declaration. */
+							unsigned char *phh = va_arg(arg, unsigned char *);
+							*phh = (unsigned char) ures;
+							break;
+						case LMOD_h: ;
+							unsigned short *ph = va_arg(arg, unsigned short *);
+							*ph = (unsigned short) ures;
+							break;
+						case LMOD_NONE: ;
+							unsigned *pdef = va_arg(arg, unsigned *);
+							*pdef = (unsigned) ures;
+							break;
+						case LMOD_l: ;
+							unsigned long *pl = va_arg(arg, unsigned long *);
+							*pl = (unsigned long) ures;
+							break;
+						case LMOD_ll: ;
+							unsigned long long *pll = va_arg(arg, unsigned long long *);
+							*pll = (unsigned long long) ures;
+							break;
+						case LMOD_j: ;
+							posix_uintmax_t *pj = va_arg(arg, posix_uintmax_t *);
+							*pj = (posix_uintmax_t) ures;
+							break;
+						case LMOD_z: ;
+							size_t *pz = va_arg(arg, size_t *);
+							*pz = (size_t) ures;
+							break;
+						case LMOD_t: ;
+							// XXX: What is unsigned counterpart of the ptrdiff_t?
+							size_t *pt = va_arg(arg, size_t *);
+							*pt = (size_t) ures;
+							break;
+						case LMOD_p: ;
+							void **pp = va_arg(arg, void **);
+							*pp = (void *) (uintptr_t) ures;
+							break;
+						default:
+							assert(false);
+						}
+					} else {
+						switch (length_mod) {
+						case LMOD_hh: ; /* Label cannot be part of declaration. */
+							signed char *phh = va_arg(arg, signed char *);
+							*phh = (signed char) sres;
+							break;
+						case LMOD_h: ;
+							short *ph = va_arg(arg, short *);
+							*ph = (short) sres;
+							break;
+						case LMOD_NONE: ;
+							int *pdef = va_arg(arg, int *);
+							*pdef = (int) sres;
+							break;
+						case LMOD_l: ;
+							long *pl = va_arg(arg, long *);
+							*pl = (long) sres;
+							break;
+						case LMOD_ll: ;
+							long long *pll = va_arg(arg, long long *);
+							*pll = (long long) sres;
+							break;
+						case LMOD_j: ;
+							posix_intmax_t *pj = va_arg(arg, posix_intmax_t *);
+							*pj = (posix_intmax_t) sres;
+							break;
+						case LMOD_z: ;
+							ssize_t *pz = va_arg(arg, ssize_t *);
+							*pz = (ssize_t) sres;
+							break;
+						case LMOD_t: ;
+							posix_ptrdiff_t *pt = va_arg(arg, posix_ptrdiff_t *);
+							*pt = (posix_ptrdiff_t) sres;
+							break;
+						default:
+							assert(false);
+						}
+					}
+					++converted_cnt;
+				}
+
+				converting = false;
+				++fmt;
+			} else if (is_float_conv(*fmt)) {
+				/* Floating point number conversion. */
+
+				/* Check sanity of optional parts of conversion specifier. */
+				if (assign_alloc) {
+					/* Illegal format string. */
+					break;
+				}
+				if (length_mod != LMOD_NONE &&
+				    length_mod != LMOD_l &&
+				    length_mod != LMOD_L) {
+					/* Illegal format string. */
+					break;
+				}
+
+				/* First consume any white spaces, so we can borrow cursor
+				 * from the input provider. This way, the cursor will either
+				 * point to the non-white space while the input will be
+				 * prefetched up to the newline (which is suitable for strtof),
+				 * or the input will be at EOF. */
+				do {
+					c = in->pop(in);
+				} while (isspace(c));
+
+				/* After skipping the white spaces, can we actually continue? */
+				if (c == -1) {
+					/* Input failure. */
+					break;
+				} else {
+					/* Everything is OK, just undo the last pop, so the cursor
+					 * can be borrowed. */
+					in->undo(in);
+				}
+
+				const char *cur_borrowed = NULL;
+				const char *cur_limited = NULL;
+				char *cur_updated = NULL;
+
+				/* Borrow the cursor. Until it is returned to the provider
+				 * we cannot jump from the cycle, because it would leave
+				 * the input inconsistent. */
+				cur_borrowed = in->borrow_cursor(in);
+
+				/* If the width is limited, the cursor horizont must be
+				 * decreased accordingly. Otherwise the strtof could read more
+				 * than allowed by width. */
+				if (width != -1) {
+					cur_limited = posix_strndup(cur_borrowed, width);
+				} else {
+					cur_limited = cur_borrowed;
+				}
+				cur_updated = (char *) cur_limited;
+
+				float fres = 0.0;
+				double dres = 0.0;
+				long double ldres = 0.0;
+				errno = 0; /* Reset errno to recognize error later. */
+				/* Try to convert the floating point nubmer. */
+				switch (length_mod) {
+				case LMOD_NONE:
+					fres = posix_strtof(cur_limited, &cur_updated);
+					break;
+				case LMOD_l:
+					dres = posix_strtod(cur_limited, &cur_updated);
+					break;
+				case LMOD_L:
+					ldres = posix_strtold(cur_limited, &cur_updated);
+					break;
+				default:
+					assert(false);
+				}
+
+				/* Update the cursor so it can be returned to the provider. */
+				cur_borrowed += cur_updated - cur_limited;
+				if (width != -1 && cur_limited != NULL) {
+					/* Deallocate duplicated part of the cursor view. */
+					free(cur_limited);
+				}
+				cur_limited = NULL;
+				cur_updated = NULL;
+				/* Return the cursor to the provider. Input consistency is again
+				 * the job of the provider, so we can report errors from
+				 * now on. */
+				in->return_cursor(in, cur_borrowed);
+				cur_borrowed = NULL;
+
+				/* Check whether the conversion was successful. */
+				if (errno != EOK) {
+					matching_failure = true;
+					break;
+				}
+
+				/* If nto supressed, assign the converted floating point number
+				 * into the next output argument. */
+				if (!assign_supress) {
+					switch (length_mod) {
+					case LMOD_NONE: ; /* Label cannot be part of declaration. */
+						float *pf = va_arg(arg, float *);
+						*pf = fres;
+						break;
+					case LMOD_l: ;
+						double *pd = va_arg(arg, double *);
+						*pd = dres;
+						break;
+					case LMOD_L: ;
+						long double *pld = va_arg(arg, long double *);
+						*pld = ldres;
+						break;
+					default:
+						assert(false);
+					}
+					++converted_cnt;
+				}
+
+				converting = false;
+				++fmt;
+			} else if (is_seq_conv(*fmt, &length_mod)) {
+				/* Character sequence conversion. */
+				
+				/* Check sanity of optional parts of conversion specifier. */
+				if (length_mod != LMOD_NONE &&
+				    length_mod != LMOD_l) {
+					/* Illegal format string. */
+					break;
+				}
+
+				if (length_mod == LMOD_l) {
+					/* Wide chars not supported. */
+					// TODO
+					not_implemented();
+				}
+
+				int term_size = 1; /* Size of the terminator (0 or 1)). */
+				if (*fmt == 'c') {
+					term_size = 0;
+					width = width == -1 ? 1 : width;
+				}
+
+				if (*fmt == 's') {
+					/* Skip white spaces. */
+					do {
+						c = in->pop(in);
+					} while (isspace(c));
+				} else {
+					/* Fetch a single character. */
+					c = in->pop(in);
+				}
+
+				/* Check whether there is still input to read. */
+				if (c == -1) {
+					/* Input failure. */
+					break;
+				}
+
+				/* Prepare scanset. */
+				char terminate_on[256];
+				for (int i = 0; i < 256; ++i) {
+					terminate_on[i] = 0;
+				}
+				if (*fmt == 'c') {
+					++fmt;
+				} else if (*fmt == 's') {
+					terminate_on[' '] = 1;
+					terminate_on['\n'] = 1;
+					terminate_on['\t'] = 1;
+					terminate_on['\f'] = 1;
+					terminate_on['\r'] = 1;
+					terminate_on['\v'] = 1;
+					++fmt;
+				} else {
+					assert(*fmt == '[');
+					bool not = false;
+					bool dash = false;
+					++fmt;
+					/* Check for negation. */
+					if (*fmt == '^') {
+						not = true;
+						++fmt;
+					}
+					/* Check for escape sequences. */
+					if (*fmt == '-' || *fmt == ']') {
+						terminate_on[(int) *fmt] = 1;
+						++fmt;
+					}
+					/* Check for ordinary characters and ranges. */
+					while (*fmt != '\0' && *fmt != ']') {
+						if (dash) {
+							for (char chr = *(fmt - 2); chr <= *fmt; ++chr) {
+								terminate_on[(int) chr] = 1;
+							}
+							dash = false;
+						} else if (*fmt == '-') {
+							dash = true;
+						} else {
+							terminate_on[(int) *fmt] = 1;
+						}
+						++fmt;
+					}
+					/* Check for escape sequence. */
+					if (dash == true) {
+						terminate_on['-'] = 1;
+					}
+					/* Check whether the specifier was correctly terminated.*/
+					if (*fmt == '\0') {
+						/* Illegal format string. */
+						break;
+					} else {
+						++fmt;
+					}
+					/* Inverse the scanset if necessary. */
+					if (not == false) {
+						for (int i = 0; i < 256; ++i) {
+							terminate_on[i] = terminate_on[i] ? 0 : 1;
+						}
+					}
+				}
+
+				char * buf = NULL;
+				size_t buf_size = 0;
+				char * cur = NULL;
+				size_t alloc_step = 80; /* Buffer size gain during reallocation. */
+				int my_buffer_idx = 0;
+
+				/* Retrieve the buffer into which popped characters
+				 * will be stored. */
+				if (!assign_supress) {
+					if (assign_alloc) {
+						/* We must allocate our own buffer. */
+						buf_size =
+						    width == -1 ? alloc_step : (size_t) width + term_size;
+						buf = malloc(buf_size);
+						if (!buf) {
+							/* No memory. */
+							break;
+						}
+						my_buffer_idx = next_unused_buffer_idx;
+						++next_unused_buffer_idx;
+						buffers[my_buffer_idx] = buf;
+						cur = buf;
+					} else {
+						/* Caller provided its buffer. */
+						buf = va_arg(arg, char *);
+						cur = buf;
+						buf_size =
+						    width == -1 ? SIZE_MAX : (size_t) width + term_size;
+					}
+				}
+
+				/* Match the string. The next character is already popped. */
+				while ((width == -1 || width > 0) && c != -1 && !terminate_on[c]) {
+
+					/* Check whether the buffer is still sufficiently large. */
+					if (!assign_supress) {
+						/* Always reserve space for the null terminator. */
+						if (cur == buf + buf_size - term_size) {
+							/* Buffer size must be increased. */
+							buf = realloc(buf, buf_size + alloc_step);
+							if (buf) {
+								buffers[my_buffer_idx] = buf;
+								cur = buf + buf_size - term_size;
+								buf_size += alloc_step;
+							} else {
+								/* Break just from this tight loop. Errno will
+								 * be checked after it. */
+								break;
+							}
+						}
+						/* Store the input character. */
+						*cur = c;
+					}
+
+					width = width == -1 ? -1 : width - 1;
+					++cur;
+					c = in->pop(in);
+				}
+				if (errno == ENOMEM) {
+					/* No memory. */
+					break;
+				}
+				if (c != -1) {
+					/* There is still more input, so undo the last pop. */
+					in->undo(in);
+				}
+
+				/* Check for failures. */
+				if (cur == buf) {
+					/* Matching failure. Input failure was already checked
+					 * earlier. */
+					matching_failure = true;
+					if (!assign_supress && assign_alloc) {
+						/* Roll back. */
+						free(buf);
+						buffers[my_buffer_idx] = NULL;
+						--next_unused_buffer_idx;
+					}
+					break;
+				}
+
+				/* Store the terminator. */
+				if (!assign_supress && term_size > 0) {
+					/* Space for the terminator was reserved. */
+					*cur = '\0';
+				}
+
+				/* Store the result if not already stored. */
+				if (!assign_supress) {
+					if (assign_alloc) {
+						char **pbuf = va_arg(arg, char **);
+						*pbuf = buf;
+					}
+					++converted_cnt;
+				}
+				
+				converting = false;
+				/* Format string pointer already incremented. */
+			} else if (*fmt == 'n') {
+				/* Report the number of consumed bytes so far. */
+
+				/* Sanity check. */
+				bool sane =
+				    width == -1 &&
+				    length_mod == LMOD_NONE &&
+				    assign_alloc == false &&
+				    assign_supress == false;
+
+				if (sane) {
+					int *pi = va_arg(arg, int *);
+					*pi = in->consumed;
+				} else {
+					/* Illegal format string. */
+					break;
+				}
+
+				/* This shall not be counted as conversion. */
+				converting = false;
+				++fmt;
+			} else {
+				/* Illegal format string. */
+				break;
+			}
+			
+		} else {
+
+			/* Processing outside conversion specifier. Either skip white
+			 * spaces or match characters one by one. If conversion specifier
+			 * is detected, switch to coversion mode. */
+			if (isspace(*fmt)) {
+				/* Skip white spaces in the format string. */
+				while (isspace(*fmt)) {
+					++fmt;
+				}
+				/* Skip white spaces in the input. */
+				do {
+					c = in->pop(in);
+				} while (isspace(c));
+				if (c != -1) {
+					/* Input is not at EOF, so undo the last pop operation. */
+					in->undo(in);
+				}
+			} else if (*fmt == '%' && *(fmt + 1) != '%') {
+				/* Conversion specifier detected. Switch modes. */
+				converting = true;
+				/* Reset the conversion context. */
+				assign_supress = false;
+				assign_alloc = false;
+				width = -1;
+				length_mod = LMOD_NONE;
+				int_conv_unsigned = false;
+				int_conv_base = 0;
+				++fmt;
+			} else {
+				/* One by one matching. */
+				if (*fmt == '%') {
+					/* Escape sequence detected. */
+					++fmt;
+					assert(*fmt == '%');
+				}
+				c = in->pop(in);
+				if (c == -1) {
+					/* Input failure. */
+					break;
+				} else if (c != *fmt) {
+					/* Matching failure. */
+					in->undo(in);
+					matching_failure = true;
+					break;
+				} else {
+					++fmt;
+				}
+			}
+			
+		}
+
+	}
+
+	in->release(in);
+
+	/* This somewhat complicated return value decision is required by POSIX. */
+	int rc;
+	if (matching_failure) {
+		rc = converted_cnt;
+	} else {
+		if (errno == EOK) {
+			rc = converted_cnt > 0 ? converted_cnt : EOF;
+		} else {
+			rc = EOF;
+		}
+	}
+	if (rc == EOF) {
+		/* Caller will not know how many arguments were successfully converted,
+		 * so the deallocation of buffers is our responsibility. */
+		for (int i = 0; i < next_unused_buffer_idx; ++i) {
+			free(buffers[i]);
+			buffers[i] = NULL;
+		}
+		next_unused_buffer_idx = 0;
+	}
+	return rc;
+}
+
+/**
+ * Convert formatted input from the stream.
+ *
+ * @param stream Input stream.
+ * @param format Format description.
+ * @param arg Output items.
+ * @return The number of converted output items or EOF on failure.
+ */
+int posix_vfscanf(
+    FILE *restrict stream, const char *restrict format, va_list arg)
+{
+	_input_provider provider = {
+	    { 0 }, 0, 0, NULL, 0, NULL, _PROV_CONSTRUCTED,
+	    _capture_stream, _pop_stream, _undo_stream,
+	    _borrow_cursor_universal, _return_cursor_stream, _release_stream
+	};
+	provider.source.stream = stream;
+	return _internal_scanf(&provider, format, arg);
+}
+
+/**
+ * Convert formatted input from the string.
+ *
+ * @param s Input string.
+ * @param format Format description.
+ * @param arg Output items.
+ * @return The number of converted output items or EOF on failure.
+ */
+int posix_vsscanf(
+    const char *restrict s, const char *restrict format, va_list arg)
+{
+	_input_provider provider = {
+	    { 0 }, 0, 0, NULL, 0, NULL, _PROV_CONSTRUCTED,
+	    _capture_string, _pop_string, _undo_string,
+	    _borrow_cursor_universal, _return_cursor_string, _release_string
+	};
+	provider.source.string = s;
+	return _internal_scanf(&provider, format, arg);
+}
+
+// FIXME: put the testcases to the app/tester after scanf is included into libc
+
+#if 0
+
+//#include <stdio.h>
+//#include <malloc.h>
+//#include <string.h>
+
+#define test_val(fmt, exp_val, act_val) \
+	if (exp_val == act_val) { \
+		printf("succ, expected "fmt", actual "fmt"\n", exp_val, act_val); \
+	} else { \
+		printf("fail, expected "fmt", actual "fmt"\n", exp_val, act_val); \
+		++fail; \
+	}
+
+#define test_str(fmt, exp_str, act_str) \
+	if (posix_strcmp(exp_str, act_str) == 0) { \
+		printf("succ, expected "fmt", actual "fmt"\n", exp_str, act_str); \
+	} else { \
+		printf("fail, expected "fmt", actual "fmt"\n", exp_str, act_str); \
+		++fail; \
+	}
+
+void __posix_scanf_test(void);
+void __posix_scanf_test(void)
+{
+	int fail = 0;
+
+	int ret;
+
+	unsigned char uhh;
+	signed char shh;
+	unsigned short uh;
+	short sh;
+	unsigned udef;
+	int sdef;
+	unsigned long ul;
+	long sl;
+	unsigned long long ull;
+	long long sll;
+	void *p;
+	
+	float f;
+	double d;
+	long double ld;
+
+	char str[20];
+	char seq[20];
+	char scanset[20];
+
+	char *pstr;
+	char *pseq;
+	char *pscanset;
+	
+	ret = posix_sscanf(
+	    "\n j tt % \t -121314 98765 aqw 0765 0x77 0xABCDEF88 -99 884",
+	    " j tt %%%3hhd%1hhu%3hd %3hu%u aqw%n %lo%llx %p %li %lld",
+	    &shh, &uhh, &sh, &uh, &udef, &sdef, &ul, &ull, &p, &sl, &sll);
+	test_val("%d", -12, shh);
+	test_val("%u", 1, uhh);
+	test_val("%d", 314, sh);
+	test_val("%u", 987, uh);
+	test_val("%u", 65, udef);
+	test_val("%d", 28, sdef);
+	test_val("%lo", (unsigned long) 0765, ul);
+	test_val("%llx", (unsigned long long) 0x77, ull);
+	test_val("%p", (void *) 0xABCDEF88, p);
+	test_val("%ld", (long) -99, sl);
+	test_val("%lld", (long long) 884, sll);
+	test_val("%d", 10, ret);
+
+	ret = posix_sscanf(
+	    "\n \t\t1.0 -0x555.AP10 1234.5678e12",
+	    "%f %lf %Lf",
+	    &f, &d, &ld);
+	test_val("%f", 1.0, f);
+	test_val("%lf", (double) -0x555.AP10, d);
+	test_val("%Lf", (long double) 1234.5678e12, ld);
+	test_val("%d", 3, ret);
+	 
+	ret = posix_sscanf(
+	    "\n\n\thello world    \n",
+	    "%5s %ms",
+	    str, &pstr);
+	test_str("%s", "hello", str);
+	test_str("%s", "world", pstr);
+	test_val("%d", 2, ret);
+	free(pstr);
+
+	ret = posix_sscanf(
+	    "\n\n\thello world    \n",
+	    " %5c %mc",
+	    seq, &pseq);
+	seq[5] = '\0';
+	pseq[1] = '\0';
+	test_str("%s", "hello", seq);
+	test_str("%s", "w", pseq);
+	test_val("%d", 2, ret);
+	free(pseq);
+
+	ret = posix_sscanf(
+	    "\n\n\th-e-l-l-o world-]    \n",
+	    " %9[-eh-o] %m[^]-]",
+	    scanset, &pscanset);
+	test_str("%s", "h-e-l-l-o", scanset);
+	test_str("%s", "world", pscanset);
+	test_val("%d", 2, ret);
+	free(pscanset);
+
+	printf("Failed: %d\n", fail);
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/posix/source/stdlib.c
===================================================================
--- uspace/lib/posix/source/stdlib.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/stdlib.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 library definitions.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "internal/common.h"
+#include "posix/stdlib.h"
+
+#include "posix/errno.h"
+#include "posix/fcntl.h"
+#include "posix/limits.h"
+#include "posix/string.h"
+#include "posix/sys/stat.h"
+#include "posix/unistd.h"
+
+#include "libc/sort.h"
+#include "libc/str.h"
+#include "libc/vfs/vfs.h"
+#include "libc/stats.h"
+
+/**
+ * 
+ * @param array
+ * @param count
+ * @param size
+ * @param compare
+ */
+int posix_atexit(void (*func)(void))
+{
+	// TODO: low priority, just a compile-time dependency of binutils
+	not_implemented();
+}
+
+/**
+ * Integer absolute value.
+ * 
+ * @param i Input value.
+ * @return Absolute value of the parameter.
+ */
+int posix_abs(int i)
+{
+	return i < 0 ? -i : i;
+}
+
+/**
+ * Long integer absolute value.
+ * 
+ * @param i Input value.
+ * @return Absolute value of the parameter.
+ */
+long posix_labs(long i)
+{
+	return i < 0 ? -i : i;
+}
+
+/**
+ * Long long integer absolute value.
+ * 
+ * @param i Input value.
+ * @return Absolute value of the parameter.
+ */
+long long posix_llabs(long long i)
+{
+	return i < 0 ? -i : i;
+}
+
+/**
+ * Compute the quotient and remainder of an integer division.
+ *
+ * @param numer Numerator.
+ * @param denom Denominator.
+ * @return Quotient and remainder packed into structure.
+ */
+posix_div_t posix_div(int numer, int denom)
+{
+	return (posix_div_t) { .quot = numer / denom, .rem = numer % denom };
+}
+
+/**
+ * Compute the quotient and remainder of a long integer division.
+ *
+ * @param numer Numerator.
+ * @param denom Denominator.
+ * @return Quotient and remainder packed into structure.
+ */
+posix_ldiv_t posix_ldiv(long numer, long denom)
+{
+	return (posix_ldiv_t) { .quot = numer / denom, .rem = numer % denom };
+}
+
+/**
+ * Compute the quotient and remainder of a long long integer division.
+ *
+ * @param numer Numerator.
+ * @param denom Denominator.
+ * @return Quotient and remainder packed into structure.
+ */
+posix_lldiv_t posix_lldiv(long long numer, long long denom)
+{
+	return (posix_lldiv_t) { .quot = numer / denom, .rem = numer % denom };
+}
+
+/**
+ * Private helper function that serves as a compare function for qsort().
+ *
+ * @param elem1 First element to compare.
+ * @param elem2 Second element to compare.
+ * @param compare Comparison function without userdata parameter.
+ * @return Relative ordering of the elements.
+ */
+static int sort_compare_wrapper(void *elem1, void *elem2, void *userdata)
+{
+	int (*compare)(const void *, const void *) = userdata;
+	int ret = compare(elem1, elem2);
+	
+	/* Native qsort internals expect this. */
+	if (ret < 0) {
+		return -1;
+	} else if (ret > 0) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+/**
+ * Array sorting utilizing the quicksort algorithm.
+ *
+ * @param array Array of elements to sort.
+ * @param count Number of elements in the array.
+ * @param size Width of each element.
+ * @param compare Decides relative ordering of two elements.
+ */
+void posix_qsort(void *array, size_t count, size_t size,
+    int (*compare)(const void *, const void *))
+{
+	/* Implemented in libc with one extra argument. */
+	qsort(array, count, size, sort_compare_wrapper, compare);
+}
+
+/**
+ * Binary search in a sorted array.
+ *
+ * @param key Object to search for.
+ * @param base Pointer to the first element of the array.
+ * @param nmemb Number of elements in the array.
+ * @param size Size of each array element.
+ * @param compar Comparison function.
+ * @return Pointer to a matching element, or NULL if none can be found.
+ */
+void *posix_bsearch(const void *key, const void *base,
+    size_t nmemb, size_t size, int (*compar)(const void *, const void *))
+{
+	while (nmemb > 0) {
+		const void *middle = base + (nmemb / 2) * size;
+		int cmp = compar(key, middle);
+		if (cmp == 0) {
+			return (void *) middle;
+		}
+		if (middle == base) {
+			/* There is just one member left to check and it
+			 * didn't match the key. Avoid infinite loop.
+			 */
+			break;
+		}
+		if (cmp < 0) {
+			nmemb = nmemb / 2;
+		} else if (cmp > 0) {
+			nmemb = nmemb - (nmemb / 2);
+			base = middle;
+		}
+	}
+	
+	return NULL;
+}
+
+/**
+ * Retrieve a value of the given environment variable.
+ *
+ * Since HelenOS doesn't support env variables at the moment,
+ * this function always returns NULL.
+ *
+ * @param name Name of the variable.
+ * @return Value of the variable or NULL if such variable does not exist.
+ */
+char *posix_getenv(const char *name)
+{
+	return NULL;
+}
+
+/**
+ * 
+ * @param name
+ * @param resolved
+ * @return
+ */
+int posix_putenv(char *string)
+{
+	// TODO: low priority, just a compile-time dependency of binutils
+	not_implemented();
+}
+
+/**
+ * Issue a command.
+ *
+ * @param string String to be passed to a command interpreter or NULL.
+ * @return Termination status of the command if the command is not NULL,
+ *     otherwise indicate whether there is a command interpreter (non-zero)
+ *     or not (zero).
+ */
+int posix_system(const char *string) {
+	// TODO: does nothing at the moment
+	return 0;
+}
+
+/**
+ * Resolve absolute pathname.
+ * 
+ * @param name Pathname to be resolved.
+ * @param resolved Either buffer for the resolved absolute pathname or NULL.
+ * @return On success, either resolved (if it was not NULL) or pointer to the
+ *     newly allocated buffer containing the absolute pathname (if resolved was
+ *     NULL). Otherwise NULL.
+ *
+ */
+char *posix_realpath(const char *restrict name, char *restrict resolved)
+{
+	#ifndef PATH_MAX
+		assert(resolved == NULL);
+	#endif
+	
+	if (name == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+	
+	// TODO: symlink resolution
+	
+	/* Function absolutize is implemented in libc and declared in vfs.h.
+	 * No more processing is required as HelenOS doesn't have symlinks
+	 * so far (as far as I can tell), although this function will need
+	 * to be updated when that support is implemented.
+	 */
+	char* absolute = absolutize(name, NULL);
+	
+	if (absolute == NULL) {
+		/* POSIX requires some specific errnos to be set
+		 * for some cases, but there is no way to find out from
+		 * absolutize().
+		 */
+		errno = EINVAL;
+		return NULL;
+	}
+	
+	if (resolved == NULL) {
+		return absolute;
+	} else {
+		#ifdef PATH_MAX
+			str_cpy(resolved, PATH_MAX, absolute);
+		#endif
+		free(absolute);
+		return resolved;
+	}
+}
+
+/**
+ * Converts a string representation of a floating-point number to
+ * its native representation. See posix_strtold().
+ *
+ * @param nptr String representation of a floating-point number.
+ * @return Double-precision number resulting from the string conversion.
+ */
+double posix_atof(const char *nptr)
+{
+	return posix_strtod(nptr, NULL);
+}
+
+/**
+ * Converts a string representation of a floating-point number to
+ * its native representation. See posix_strtold().
+ *
+ * @param nptr String representation of a floating-point number.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @return Single-precision number resulting from the string conversion.
+ */
+float posix_strtof(const char *restrict nptr, char **restrict endptr)
+{
+	return (float) posix_strtold(nptr, endptr);
+}
+
+/**
+ * Converts a string representation of a floating-point number to
+ * its native representation. See posix_strtold().
+ *
+ * @param nptr String representation of a floating-point number.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @return Double-precision number resulting from the string conversion.
+ */
+double posix_strtod(const char *restrict nptr, char **restrict endptr)
+{
+	return (double) posix_strtold(nptr, endptr);
+}
+
+/**
+ * Allocate memory chunk.
+ *
+ * @param size Size of the chunk to allocate.
+ * @return Either pointer to the allocated chunk or NULL if not possible.
+ */
+void *posix_malloc(size_t size)
+{
+	return malloc(size);
+}
+
+/**
+ * Allocate memory for an array of elements.
+ *
+ * @param nelem Number of elements in the array.
+ * @param elsize Size of each element.
+ * @return Either pointer to the allocated array or NULL if not possible.
+ */
+void *posix_calloc(size_t nelem, size_t elsize)
+{
+	return calloc(nelem, elsize);
+}
+
+/**
+ * Reallocate memory chunk to a new size.
+ *
+ * @param ptr Memory chunk to reallocate. Might be NULL.
+ * @param size Size of the reallocated chunk. Might be zero.
+ * @return Either NULL or the pointer to the newly reallocated chunk.
+ */
+void *posix_realloc(void *ptr, size_t size)
+{
+	if (ptr != NULL && size == 0) {
+		/* Native realloc does not handle this special case. */
+		free(ptr);
+		return NULL;
+	} else {
+		return realloc(ptr, size);
+	}
+}
+
+/**
+ * Free allocated memory chunk.
+ *
+ * @param ptr Memory chunk to be freed.
+ */
+void posix_free(void *ptr)
+{
+	if (ptr) {
+		free(ptr);
+	}
+}
+
+/**
+ * Creates and opens an unique temporary file from template.
+ *
+ * @param tmpl Template. Last six characters must be XXXXXX.
+ * @return The opened file descriptor or -1 on error.
+ */
+int posix_mkstemp(char *tmpl)
+{
+	int fd = -1;
+	
+	char *tptr = tmpl + posix_strlen(tmpl) - 6;
+	
+	while (fd < 0) {
+		if (*posix_mktemp(tmpl) == '\0') {
+			/* Errno set by mktemp(). */
+			return -1;
+		}
+		
+		fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+		
+		if (fd == -1) {
+			/* Restore template to it's original state. */
+			snprintf(tptr, 7, "XXXXXX");
+		}
+	}
+	
+	return fd;
+}
+
+/**
+ * Creates an unique temporary file name from template.
+ *
+ * @param tmpl Template. Last six characters must be XXXXXX.
+ * @return The value of tmpl. The template is modified in place.
+ *    If no temporary file name can be created, template is
+ *    reduced to an empty string.
+ */
+char *posix_mktemp(char *tmpl)
+{
+	int tmpl_len = posix_strlen(tmpl);
+	if (tmpl_len < 6) {
+		errno = EINVAL;
+		*tmpl = '\0';
+		return tmpl;
+	}
+	
+	char *tptr = tmpl + tmpl_len - 6;
+	if (posix_strcmp(tptr, "XXXXXX") != 0) {
+		errno = EINVAL;
+		*tmpl = '\0';
+		return tmpl;
+	}
+	
+	static int seq = 0;
+	
+	for (; seq < 1000000; ++seq) {
+		snprintf(tptr, 7, "%06d", seq);
+		
+		int orig_errno = errno;
+		errno = 0;
+		/* Check if the file exists. */
+		if (posix_access(tmpl, F_OK) == -1) {
+			if (errno == ENOENT) {
+				errno = orig_errno;
+				break;
+			} else {
+				/* errno set by access() */
+				*tmpl = '\0';
+				return tmpl;
+			}
+		}
+	}
+	
+	if (seq == 10000000) {
+		errno = EEXIST;
+		*tmpl = '\0';
+		return tmpl;
+	}
+	
+	return tmpl;
+}
+
+/**
+ * Get system load average statistics.
+ *
+ * @param loadavg Array where the load averages shall be placed.
+ * @param nelem Maximum number of elements to be placed into the array.
+ * @return Number of elements placed into the array on success, -1 otherwise.
+ */
+int bsd_getloadavg(double loadavg[], int nelem)
+{
+	assert(nelem > 0);
+	
+	size_t count;
+	load_t *loads = stats_get_load(&count);
+	
+	if (loads == NULL) {
+		return -1;
+	}
+	
+	if (((size_t) nelem) < count) {
+		count = nelem;
+	}
+	
+	for (size_t i = 0; i < count; ++i) {
+		loadavg[i] = (double) loads[i];
+	}
+	
+	free(loads);
+	return count;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/stdlib/strtol.c
===================================================================
--- uspace/lib/posix/source/stdlib/strtol.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/stdlib/strtol.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Backend for integer conversions.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "../internal/common.h"
+#include "posix/stdlib.h"
+
+#include "posix/ctype.h"
+#include "posix/errno.h"
+#include "posix/inttypes.h"
+#include "posix/limits.h"
+
+#define intmax_t posix_intmax_t
+#define uintmax_t posix_uintmax_t
+
+/**
+ * Decides whether a digit belongs to a particular base.
+ *
+ * @param c Character representation of the digit.
+ * @param base Base against which the digit shall be tested.
+ * @return True if the digit belongs to the base, false otherwise.
+ */
+static inline bool is_digit_in_base(int c, int base)
+{
+	if (base <= 10) {
+		return c >= '0' && c < '0' + base;
+	} else {
+		return isdigit(c) ||
+		    (tolower(c) >= 'a' && tolower(c) < ('a' + base - 10));
+	}
+}
+
+/**
+ * Derive a digit from its character representation.
+ *
+ * @param c Character representation of the digit.
+ * @return Digit value represented by an integer.
+ */
+static inline int digit_value(int c)
+{
+	if (c <= '9') {
+		return c - '0';
+	} else {
+		return 10 + tolower(c) - 'a';
+	}
+}
+
+/**
+ * Generic function for parsing an integer from it's string representation.
+ * Different variants differ in lower and upper bounds.
+ * The parsed string returned by this function is always positive, sign
+ * information is provided via a dedicated parameter.
+ *
+ * @param nptr Input string.
+ * @param endptr If non-NULL, *endptr is set to the position of the first
+ *     unrecognized character. If no digit has been parsed, value of
+ *     nptr is stored there (regardless of any skipped characters at the
+ *     beginning).
+ * @param base Expected base of the string representation. If 0, base is
+ *    determined to be decimal, octal or hexadecimal using the same rules
+ *    as C syntax. Otherwise, value must be between 2 and 36, inclusive.
+ * @param min_value Lower bound for the resulting conversion.
+ * @param max_value Upper bound for the resulting conversion.
+ * @param out_negative Either NULL for unsigned conversion or a pointer to the
+ *     bool variable into which shall be placed the negativity of the resulting
+ *     converted value.
+ * @return The absolute value of the parsed value, or the closest in-range value
+ *     if the parsed value is out of range. If the input is invalid, zero is
+ *     returned and errno is set to EINVAL.
+ */
+static inline uintmax_t internal_strtol(
+    const char *restrict nptr, char **restrict endptr, int base,
+    const intmax_t min_value, const uintmax_t max_value,
+    bool *restrict out_negative)
+{
+	if (nptr == NULL) {
+		errno = EINVAL;
+		return 0;
+	}
+	
+	if (base < 0 || base == 1 || base > 36) {
+		errno = EINVAL;
+		return 0;
+	}
+	
+	/* The maximal absolute value that can be returned in this run.
+	 * Depends on sign.
+	 */
+	uintmax_t real_max_value = max_value;
+	
+	/* Current index in the input string. */
+	size_t i = 0;
+	bool negative = false;
+	
+	/* Skip whitespace. */
+	while (isspace(nptr[i])) {
+		i++;
+	}
+	
+	/* Parse sign. */
+	switch (nptr[i]) {
+	case '-':
+		negative = true;
+		
+		/* The strange computation is are there to avoid a corner case
+		 * where -min_value can't be represented in intmax_t.
+		 * (I'm not exactly sure what the semantics are in such a
+		 *  case, but this should be safe for any case.)
+		 */
+		real_max_value = (min_value == 0)
+		    ? 0
+		    :(((uintmax_t) -(min_value + 1)) + 1);
+		
+		/* fallthrough */
+	case '+':
+		i++;
+	}
+	
+	/* Figure out the base. */
+	switch (base) {
+	case 0:
+		if (nptr[i] == '0') {
+			if (tolower(nptr[i + 1]) == 'x') {
+				/* 0x... is hex. */
+				base = 16;
+				i += 2;
+			} else {
+				/* 0... is octal. */
+				base = 8;
+			}
+		} else {
+			/* Anything else is decimal by default. */
+			base = 10;
+		}
+		break;
+	case 16:
+		/* Allow hex number to be prefixed with "0x". */
+		if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x') {
+			i += 2;
+		}
+		break;
+	}
+	
+	if (!is_digit_in_base(nptr[i], base)) {
+		/* No digits to parse, invalid input. */
+		
+		errno = EINVAL;
+		if (endptr != NULL) {
+			*endptr = (char *) nptr;
+		}
+		return 0;
+	}
+	
+	/* Maximal value to which a digit can be added without a risk
+	 * of overflow.
+	 */
+	uintmax_t max_safe_value = (real_max_value - base + 1) / base;
+	
+	uintmax_t result = 0;
+	
+	if (real_max_value == 0) {
+		/* Special case when a negative number is parsed as
+		 * unsigned integer. Only -0 is accepted.
+		 */
+		
+		while (is_digit_in_base(nptr[i], base)) {
+			if (nptr[i] != '0') {
+				errno = ERANGE;
+				result = 0;
+			}
+			i++;
+		}
+	}
+	
+	while (is_digit_in_base(nptr[i], base)) {
+		int digit = digit_value(nptr[i]);
+		
+		if (result > max_safe_value) {
+			/* corner case, check for overflow */
+			
+			uintmax_t boundary = (real_max_value - digit) / base;
+			
+			if (result > boundary) {
+				/* overflow */
+				errno = ERANGE;
+				result = real_max_value;
+				break;
+			}
+		}
+		
+		result = result * base + digit;
+		i++;
+	}
+	
+	if (endptr != NULL) {
+		/* Move the pointer to the end of the number,
+		 * in case it isn't there already.
+		 */
+		while (is_digit_in_base(nptr[i], base)) {
+			i++;
+		}
+		
+		*endptr = (char *) &nptr[i];
+	}
+	if (out_negative != NULL) {
+		*out_negative = negative;
+	}
+	return result;
+}
+
+/**
+ * Convert a string to an integer.
+ *
+ * @param nptr Input string.
+ * @return Result of the conversion.
+ */
+int posix_atoi(const char *nptr)
+{
+	bool neg = false;
+	uintmax_t result =
+	    internal_strtol(nptr, NULL, 10, INT_MIN, INT_MAX, &neg);
+
+	return (neg ? ((int) -result) : (int) result);
+}
+
+/**
+ * Convert a string to a long integer.
+ *
+ * @param nptr Input string.
+ * @return Result of the conversion.
+ */
+long posix_atol(const char *nptr)
+{
+	bool neg = false;
+	uintmax_t result =
+	    internal_strtol(nptr, NULL, 10, LONG_MIN, LONG_MAX, &neg);
+
+	return (neg ? ((long) -result) : (long) result);
+}
+
+/**
+ * Convert a string to a long long integer.
+ *
+ * @param nptr Input string.
+ * @return Result of the conversion.
+ */
+long long posix_atoll(const char *nptr)
+{
+	bool neg = false;
+	uintmax_t result =
+	    internal_strtol(nptr, NULL, 10, LLONG_MIN, LLONG_MAX, &neg);
+
+	return (neg ? ((long long) -result) : (long long) result);
+}
+
+/**
+ * Convert a string to a long integer.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
+long posix_strtol(const char *restrict nptr, char **restrict endptr, int base)
+{
+	bool neg = false;
+	uintmax_t result =
+	    internal_strtol(nptr, endptr, base, LONG_MIN, LONG_MAX, &neg);
+
+	return (neg ? ((long) -result) : ((long) result));
+}
+
+/**
+ * Convert a string to a long long integer.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
+long long posix_strtoll(
+    const char *restrict nptr, char **restrict endptr, int base)
+{
+	bool neg = false;
+	uintmax_t result =
+	    internal_strtol(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &neg);
+
+	return (neg ? ((long long) -result) : (long long) result);
+}
+
+/**
+ * Convert a string to a largest signed integer type.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
+intmax_t posix_strtoimax(
+    const char *restrict nptr, char **restrict endptr, int base)
+{
+	bool neg = false;
+	uintmax_t result =
+	    internal_strtol(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX, &neg);
+
+	return (neg ? ((intmax_t) -result) : (intmax_t) result);
+}
+
+/**
+ * Convert a string to an unsigned long integer.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
+unsigned long posix_strtoul(
+    const char *restrict nptr, char **restrict endptr, int base)
+{
+	uintmax_t result =
+	    internal_strtol(nptr, endptr, base, 0, ULONG_MAX, NULL);
+
+	return (unsigned long) result;
+}
+
+/**
+ * Convert a string to an unsigned long long integer.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
+unsigned long long posix_strtoull(
+    const char *restrict nptr, char **restrict endptr, int base)
+{
+	uintmax_t result =
+	    internal_strtol(nptr, endptr, base, 0, ULLONG_MAX, NULL);
+
+	return (unsigned long long) result;
+}
+
+/**
+ * Convert a string to a largest unsigned integer type.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
+uintmax_t posix_strtoumax(
+    const char *restrict nptr, char **restrict endptr, int base)
+{
+	uintmax_t result =
+	    internal_strtol(nptr, endptr, base, 0, UINTMAX_MAX, NULL);
+
+	return result;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/stdlib/strtold.c
===================================================================
--- uspace/lib/posix/source/stdlib/strtold.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/stdlib/strtold.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Backend for floating point conversions.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+/* Must be first. */
+#include "posix/stdbool.h"
+
+#include "../internal/common.h"
+#include "posix/stdlib.h"
+
+#include "posix/assert.h"
+#include "posix/ctype.h"
+#include "posix/stdint.h"
+#include "posix/strings.h"
+#include "posix/errno.h"
+#include "posix/limits.h"
+
+#include "posix/float.h"
+
+#ifndef HUGE_VALL
+	#define HUGE_VALL (+1.0l / +0.0l)
+#endif
+
+#ifndef abs
+	#define abs(x) (((x) < 0) ? -(x) : (x))
+#endif
+
+/* If the constants are not defined, use double precision as default. */
+#ifndef LDBL_MANT_DIG
+	#define LDBL_MANT_DIG 53
+#endif
+#ifndef LDBL_MAX_EXP
+	#define LDBL_MAX_EXP 1024
+#endif
+#ifndef LDBL_MIN_EXP
+	#define LDBL_MIN_EXP (-1021)
+#endif
+#ifndef LDBL_DIG
+	#define LDBL_DIG 15
+#endif
+#ifndef LDBL_MIN
+	#define LDBL_MIN 2.2250738585072014E-308
+#endif
+
+/* power functions ************************************************************/
+
+#if LDBL_MAX_EXP >= 16384
+const int MAX_POW5 = 12;
+#else
+const int MAX_POW5 = 8;
+#endif
+
+/* The value at index i is approximately 5**(2**i). */
+long double pow5[] = {
+	0x5p0l,
+	0x19p0l,
+	0x271p0l,
+	0x5F5E1p0l,
+	0x2386F26FC1p0l,
+	0x4EE2D6D415B85ACEF81p0l,
+	0x184F03E93FF9F4DAA797ED6E38ED6p36l,
+	0x127748F9301D319BF8CDE66D86D62p185l,
+	0x154FDD7F73BF3BD1BBB77203731FDp482l,
+#if LDBL_MAX_EXP >= 16384
+	0x1C633415D4C1D238D98CAB8A978A0p1076l,
+	0x192ECEB0D02EA182ECA1A7A51E316p2265l,
+	0x13D1676BB8A7ABBC94E9A519C6535p4643l,
+	0x188C0A40514412F3592982A7F0094p9398l,
+#endif
+};
+
+#if LDBL_MAX_EXP >= 16384
+const int MAX_POW2 = 15;
+#else
+const int MAX_POW2 = 9;
+#endif
+
+/* Powers of two. */
+long double pow2[] = {
+	0x1P1l,
+	0x1P2l,
+	0x1P4l,
+	0x1P8l,
+	0x1P16l,
+	0x1P32l,
+	0x1P64l,
+	0x1P128l,
+	0x1P256l,
+	0x1P512l,
+#if LDBL_MAX_EXP >= 16384
+	0x1P1024l,
+	0x1P2048l,
+	0x1P4096l,
+	0x1P8192l,
+#endif
+};
+
+/**
+ * Multiplies a number by a power of five.
+ * The result may be inexact and may not be the best possible approximation.
+ *
+ * @param mant Number to be multiplied.
+ * @param exp Base 5 exponent.
+ * @return mant multiplied by 5**exp
+ */
+static long double mul_pow5(long double mant, int exp)
+{
+	if (mant == 0.0l || mant == HUGE_VALL) {
+		return mant;
+	}
+	
+	if (abs(exp) >> (MAX_POW5 + 1) != 0) {
+		/* Too large exponent. */
+		errno = ERANGE;
+		return exp < 0 ? LDBL_MIN : HUGE_VALL;
+	}
+	
+	if (exp < 0) {
+		exp = abs(exp);
+		for (int bit = 0; bit <= MAX_POW5; ++bit) {
+			/* Multiply by powers of five bit-by-bit. */
+			if (((exp >> bit) & 1) != 0) {
+				mant /= pow5[bit];
+				if (mant == 0.0l) {
+					/* Underflow. */
+					mant = LDBL_MIN;
+					errno = ERANGE;
+					break;
+				}
+			}
+		}
+	} else {
+		for (int bit = 0; bit <= MAX_POW5; ++bit) {
+			/* Multiply by powers of five bit-by-bit. */
+			if (((exp >> bit) & 1) != 0) {
+				mant *= pow5[bit];
+				if (mant == HUGE_VALL) {
+					/* Overflow. */
+					errno = ERANGE;
+					break;
+				}
+			}
+		}
+	}
+	
+	return mant;
+}
+
+/**
+ * Multiplies a number by a power of two. This is always exact.
+ *
+ * @param mant Number to be multiplied.
+ * @param exp Base 2 exponent.
+ * @return mant multiplied by 2**exp.
+ */
+static long double mul_pow2(long double mant, int exp)
+{
+	if (mant == 0.0l || mant == HUGE_VALL) {
+		return mant;
+	}
+	
+	if (exp > LDBL_MAX_EXP || exp < LDBL_MIN_EXP) {
+		errno = ERANGE;
+		return exp < 0 ? LDBL_MIN : HUGE_VALL;
+	}
+	
+	if (exp < 0) {
+		exp = abs(exp);
+		for (int i = 0; i <= MAX_POW2; ++i) {
+			if (((exp >> i) & 1) != 0) {
+				mant /= pow2[i];
+				if (mant == 0.0l) {
+					mant = LDBL_MIN;
+					errno = ERANGE;
+					break;
+				}
+			}
+		}
+	} else {
+		for (int i = 0; i <= MAX_POW2; ++i) {
+			if (((exp >> i) & 1) != 0) {
+				mant *= pow2[i];
+				if (mant == HUGE_VALL) {
+					errno = ERANGE;
+					break;
+				}
+			}
+		}
+	}
+	
+	return mant;
+}
+
+/* end power functions ********************************************************/
+
+
+
+/**
+ * Convert decimal string representation of the floating point number.
+ * Function expects the string pointer to be already pointed at the first
+ * digit (i.e. leading optional sign was already consumed by the caller).
+ * 
+ * @param sptr Pointer to the storage of the string pointer. Upon successful
+ *     conversion, the string pointer is updated to point to the first
+ *     unrecognized character.
+ * @return An approximate representation of the input floating-point number.
+ */
+static long double parse_decimal(const char **sptr)
+{
+	assert(sptr != NULL);
+	assert (*sptr != NULL);
+	
+	const int DEC_BASE = 10;
+	const char DECIMAL_POINT = '.';
+	const char EXPONENT_MARK = 'e';
+	
+	const char *str = *sptr;
+	long double significand = 0;
+	long exponent = 0;
+	
+	/* number of digits parsed so far */
+	int parsed_digits = 0;
+	bool after_decimal = false;
+	
+	while (isdigit(*str) || (!after_decimal && *str == DECIMAL_POINT)) {
+		if (*str == DECIMAL_POINT) {
+			after_decimal = true;
+			str++;
+			continue;
+		}
+		
+		if (parsed_digits == 0 && *str == '0') {
+			/* Nothing, just skip leading zeros. */
+		} else if (parsed_digits < LDBL_DIG) {
+			significand = significand * DEC_BASE + (*str - '0');
+			parsed_digits++;
+		} else {
+			exponent++;
+		}
+		
+		if (after_decimal) {
+			/* Decrement exponent if we are parsing the fractional part. */
+			exponent--;
+		}
+		
+		str++;
+	}
+	
+	/* exponent */
+	if (tolower(*str) == EXPONENT_MARK) {
+		str++;
+		
+		/* Returns MIN/MAX value on error, which is ok. */
+		long exp = strtol(str, (char **) &str, DEC_BASE);
+		
+		if (exponent > 0 && exp > LONG_MAX - exponent) {
+			exponent = LONG_MAX;
+		} else if (exponent < 0 && exp < LONG_MIN - exponent) {
+			exponent = LONG_MIN;
+		} else {
+			exponent += exp;
+		}
+	}
+	
+	*sptr = str;
+	
+	/* Return multiplied by a power of ten. */
+	return mul_pow2(mul_pow5(significand, exponent), exponent);
+}
+
+/**
+ * Derive a hexadecimal digit from its character representation.
+ * 
+ * @param ch Character representation of the hexadecimal digit.
+ * @return Digit value represented by an integer.
+ */
+static inline int hex_value(char ch)
+{
+	if (ch <= '9') {
+		return ch - '0';
+	} else {
+		return 10 + tolower(ch) - 'a';
+	}
+}
+
+/**
+ * Convert hexadecimal string representation of the floating point number.
+ * Function expects the string pointer to be already pointed at the first
+ * digit (i.e. leading optional sign and 0x prefix were already consumed
+ * by the caller).
+ *
+ * @param sptr Pointer to the storage of the string pointer. Upon successful
+ *     conversion, the string pointer is updated to point to the first
+ *     unrecognized character.
+ * @return Representation of the input floating-point number.
+ */
+static long double parse_hexadecimal(const char **sptr)
+{
+	assert(sptr != NULL && *sptr != NULL);
+	
+	const int DEC_BASE = 10;
+	const int HEX_BASE = 16;
+	const char DECIMAL_POINT = '.';
+	const char EXPONENT_MARK = 'p';
+	
+	const char *str = *sptr;
+	long double significand = 0;
+	long exponent = 0;
+	
+	/* number of bits parsed so far */
+	int parsed_bits = 0;
+	bool after_decimal = false;
+	
+	while (posix_isxdigit(*str) || (!after_decimal && *str == DECIMAL_POINT)) {
+		if (*str == DECIMAL_POINT) {
+			after_decimal = true;
+			str++;
+			continue;
+		}
+		
+		if (parsed_bits == 0 && *str == '0') {
+			/* Nothing, just skip leading zeros. */
+		} else if (parsed_bits <= LDBL_MANT_DIG) {
+			significand = significand * HEX_BASE + hex_value(*str);
+			parsed_bits += 4;
+		} else {
+			exponent += 4;
+		}
+		
+		if (after_decimal) {
+			exponent -= 4;
+		}
+		
+		str++;
+	}
+	
+	/* exponent */
+	if (tolower(*str) == EXPONENT_MARK) {
+		str++;
+		
+		/* Returns MIN/MAX value on error, which is ok. */
+		long exp = strtol(str, (char **) &str, DEC_BASE);
+		
+		if (exponent > 0 && exp > LONG_MAX - exponent) {
+			exponent = LONG_MAX;
+		} else if (exponent < 0 && exp < LONG_MIN - exponent) {
+			exponent = LONG_MIN;
+		} else {
+			exponent += exp;
+		}
+	}
+	
+	*sptr = str;
+	
+	/* Return multiplied by a power of two. */
+	return mul_pow2(significand, exponent);
+}
+
+/**
+ * Converts a string representation of a floating-point number to
+ * its native representation. Largely POSIX compliant, except for
+ * locale differences (always uses '.' at the moment) and rounding.
+ * Decimal strings are NOT guaranteed to be correctly rounded. This function
+ * should return a good enough approximation for most purposes but if you
+ * depend on a precise conversion, use hexadecimal representation.
+ * Hexadecimal strings are currently always rounded towards zero, regardless
+ * of the current rounding mode.
+ *
+ * @param nptr Input string.
+ * @param endptr If non-NULL, *endptr is set to the position of the first
+ *     unrecognized character.
+ * @return An approximate representation of the input floating-point number.
+ */
+long double posix_strtold(const char *restrict nptr, char **restrict endptr)
+{
+	assert(nptr != NULL);
+	
+	const int RADIX = '.';
+	
+	/* minus sign */
+	bool negative = false;
+	/* current position in the string */
+	int i = 0;
+	
+	/* skip whitespace */
+	while (isspace(nptr[i])) {
+		i++;
+	}
+	
+	/* parse sign */
+	switch (nptr[i]) {
+	case '-':
+		negative = true;
+		/* fallthrough */
+	case '+':
+		i++;
+	}
+	
+	/* check for NaN */
+	if (posix_strncasecmp(&nptr[i], "nan", 3) == 0) {
+		// FIXME: return NaN
+		// TODO: handle the parenthesised case
+		
+		if (endptr != NULL) {
+			*endptr = (char *) nptr;
+		}
+		errno = EINVAL;
+		return 0;
+	}
+	
+	/* check for Infinity */
+	if (posix_strncasecmp(&nptr[i], "inf", 3) == 0) {
+		i += 3;
+		if (posix_strncasecmp(&nptr[i], "inity", 5) == 0) {
+			i += 5;
+		}
+		
+		if (endptr != NULL) {
+			*endptr = (char *) &nptr[i];
+		}
+		return negative ? -HUGE_VALL : +HUGE_VALL;
+	}
+
+	/* check for a hex number */
+	if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x' &&
+	    (posix_isxdigit(nptr[i + 2]) ||
+	    (nptr[i + 2] == RADIX && posix_isxdigit(nptr[i + 3])))) {
+		i += 2;
+		
+		const char *ptr = &nptr[i];
+		/* this call sets errno if appropriate. */
+		long double result = parse_hexadecimal(&ptr);
+		if (endptr != NULL) {
+			*endptr = (char *) ptr;
+		}
+		return negative ? -result : result;
+	}
+	
+	/* check for a decimal number */
+	if (isdigit(nptr[i]) || (nptr[i] == RADIX && isdigit(nptr[i + 1]))) {
+		const char *ptr = &nptr[i];
+		/* this call sets errno if appropriate. */
+		long double result = parse_decimal(&ptr);
+		if (endptr != NULL) {
+			*endptr = (char *) ptr;
+		}
+		return negative ? -result : result;
+	}
+	
+	/* nothing to parse */
+	if (endptr != NULL) {
+		*endptr = (char *) nptr;
+	}
+	errno = EINVAL;
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/string.c
===================================================================
--- uspace/lib/posix/source/string.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/string.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 String manipulation.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "internal/common.h"
+#include "posix/string.h"
+
+#include "posix/assert.h"
+#include "posix/errno.h"
+#include "posix/limits.h"
+#include "posix/stdlib.h"
+#include "posix/signal.h"
+
+#include "libc/str_error.h"
+
+/**
+ * The same as strpbrk, except it returns pointer to the nul terminator
+ * if no occurence is found.
+ *
+ * @param s1 String in which to look for the bytes.
+ * @param s2 String of bytes to look for.
+ * @return Pointer to the found byte on success, pointer to the
+ *     string terminator otherwise.
+ */
+static char *strpbrk_null(const char *s1, const char *s2)
+{
+	while (!posix_strchr(s2, *s1)) {
+		++s1;
+	}
+	
+	return (char *) s1;
+}
+
+/**
+ * Copy a string.
+ *
+ * @param dest Destination pre-allocated buffer.
+ * @param src Source string to be copied.
+ * @return Pointer to the destination buffer.
+ */
+char *posix_strcpy(char *restrict dest, const char *restrict src)
+{
+	posix_stpcpy(dest, src);
+	return dest;
+}
+
+/**
+ * Copy fixed length string.
+ *
+ * @param dest Destination pre-allocated buffer.
+ * @param src Source string to be copied.
+ * @param n Number of bytes to be stored into destination buffer.
+ * @return Pointer to the destination buffer.
+ */
+char *posix_strncpy(char *restrict dest, const char *restrict src, size_t n)
+{
+	posix_stpncpy(dest, src, n);
+	return dest;
+}
+
+/**
+ * Copy a string.
+ *
+ * @param dest Destination pre-allocated buffer.
+ * @param src Source string to be copied.
+ * @return Pointer to the nul character in the destination string.
+ */
+char *posix_stpcpy(char *restrict dest, const char *restrict src)
+{
+	assert(dest != NULL);
+	assert(src != NULL);
+
+	for (size_t i = 0; ; ++i) {
+		dest[i] = src[i];
+		
+		if (src[i] == '\0') {
+			/* pointer to the terminating nul character */
+			return &dest[i];
+		}
+	}
+	
+	/* unreachable */
+	return NULL;
+}
+
+/**
+ * Copy fixed length string.
+ *
+ * @param dest Destination pre-allocated buffer.
+ * @param src Source string to be copied.
+ * @param n Number of bytes to be stored into destination buffer.
+ * @return Pointer to the first written nul character or &dest[n].
+ */
+char *posix_stpncpy(char *restrict dest, const char *restrict src, size_t n)
+{
+	assert(dest != NULL);
+	assert(src != NULL);
+
+	for (size_t i = 0; i < n; ++i) {
+		dest[i] = src[i];
+	
+		/* the standard requires that nul characters
+		 * are appended to the length of n, in case src is shorter
+		 */
+		if (src[i] == '\0') {
+			char *result = &dest[i];
+			for (++i; i < n; ++i) {
+				dest[i] = '\0';
+			}
+			return result;
+		}
+	}
+	
+	return &dest[n];
+}
+
+/**
+ * Concatenate two strings.
+ *
+ * @param dest String to which src shall be appended.
+ * @param src String to be appended after dest.
+ * @return Pointer to destination buffer.
+ */
+char *posix_strcat(char *restrict dest, const char *restrict src)
+{
+	assert(dest != NULL);
+	assert(src != NULL);
+
+	posix_strcpy(posix_strchr(dest, '\0'), src);
+	return dest;
+}
+
+/**
+ * Concatenate a string with part of another.
+ *
+ * @param dest String to which part of src shall be appended.
+ * @param src String whose part shall be appended after dest.
+ * @param n Number of bytes to append after dest.
+ * @return Pointer to destination buffer.
+ */
+char *posix_strncat(char *restrict dest, const char *restrict src, size_t n)
+{
+	assert(dest != NULL);
+	assert(src != NULL);
+
+	char *zeroptr = posix_strncpy(posix_strchr(dest, '\0'), src, n);
+	/* strncpy doesn't append the nul terminator, so we do it here */
+	zeroptr[n] = '\0';
+	return dest;
+}
+
+/**
+ * Copy limited number of bytes in memory.
+ *
+ * @param dest Destination buffer.
+ * @param src Source buffer.
+ * @param c Character after which the copying shall stop.
+ * @param n Number of bytes that shall be copied if not stopped earlier by c.
+ * @return Pointer to the first byte after c in dest if found, NULL otherwise.
+ */
+void *posix_memccpy(void *restrict dest, const void *restrict src, int c, size_t n)
+{
+	assert(dest != NULL);
+	assert(src != NULL);
+	
+	unsigned char* bdest = dest;
+	const unsigned char* bsrc = src;
+	
+	for (size_t i = 0; i < n; ++i) {
+		bdest[i] = bsrc[i];
+	
+		if (bsrc[i] == (unsigned char) c) {
+			/* pointer to the next byte */
+			return &bdest[i + 1];
+		}
+	}
+	
+	return NULL;
+}
+
+/**
+ * Duplicate a string.
+ *
+ * @param s String to be duplicated.
+ * @return Newly allocated copy of the string.
+ */
+char *posix_strdup(const char *s)
+{
+	return posix_strndup(s, SIZE_MAX);
+}
+
+/**
+ * Duplicate a specific number of bytes from a string.
+ *
+ * @param s String to be duplicated.
+ * @param n Maximum length of the resulting string..
+ * @return Newly allocated string copy of length at most n.
+ */
+char *posix_strndup(const char *s, size_t n)
+{
+	assert(s != NULL);
+
+	size_t len = posix_strnlen(s, n);
+	char *dup = malloc(len + 1);
+	if (dup == NULL) {
+		return NULL;
+	}
+
+	memcpy(dup, s, len);
+	dup[len] = '\0';
+
+	return dup;
+}
+
+/**
+ * Compare bytes in memory.
+ *
+ * @param mem1 First area of memory to be compared.
+ * @param mem2 Second area of memory to be compared.
+ * @param n Maximum number of bytes to be compared.
+ * @return Difference of the first pair of inequal bytes,
+ *     or 0 if areas have the same content.
+ */
+int posix_memcmp(const void *mem1, const void *mem2, size_t n)
+{
+	assert(mem1 != NULL);
+	assert(mem2 != NULL);
+
+	const unsigned char *s1 = mem1;
+	const unsigned char *s2 = mem2;
+	
+	for (size_t i = 0; i < n; ++i) {
+		if (s1[i] != s2[i]) {
+			return s1[i] - s2[i];
+		}
+	}
+	
+	return 0;
+}
+
+/**
+ * Compare two strings.
+ *
+ * @param s1 First string to be compared.
+ * @param s2 Second string to be compared.
+ * @return Difference of the first pair of inequal characters,
+ *     or 0 if strings have the same content.
+ */
+int posix_strcmp(const char *s1, const char *s2)
+{
+	assert(s1 != NULL);
+	assert(s2 != NULL);
+
+	return posix_strncmp(s1, s2, STR_NO_LIMIT);
+}
+
+/**
+ * Compare part of two strings.
+ *
+ * @param s1 First string to be compared.
+ * @param s2 Second string to be compared.
+ * @param n Maximum number of characters to be compared.
+ * @return Difference of the first pair of inequal characters,
+ *     or 0 if strings have the same content.
+ */
+int posix_strncmp(const char *s1, const char *s2, size_t n)
+{
+	assert(s1 != NULL);
+	assert(s2 != NULL);
+
+	for (size_t i = 0; i < n; ++i) {
+		if (s1[i] != s2[i]) {
+			return s1[i] - s2[i];
+		}
+		if (s1[i] == '\0') {
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Find byte in memory.
+ *
+ * @param mem Memory area in which to look for the byte.
+ * @param c Byte to look for.
+ * @param n Maximum number of bytes to be inspected.
+ * @return Pointer to the specified byte on success,
+ *     NULL pointer otherwise.
+ */
+void *posix_memchr(const void *mem, int c, size_t n)
+{
+	assert(mem != NULL);
+	
+	const unsigned char *s = mem;
+	
+	for (size_t i = 0; i < n; ++i) {
+		if (s[i] == (unsigned char) c) {
+			return (void *) &s[i];
+		}
+	}
+	return NULL;
+}
+
+/**
+ * Scan string for a first occurence of a character.
+ *
+ * @param s String in which to look for the character.
+ * @param c Character to look for.
+ * @return Pointer to the specified character on success,
+ *     NULL pointer otherwise.
+ */
+char *posix_strchr(const char *s, int c)
+{
+	assert(s != NULL);
+	
+	char *res = gnu_strchrnul(s, c);
+	return (*res == c) ? res : NULL;
+}
+
+/**
+ * Scan string for a last occurence of a character.
+ *
+ * @param s String in which to look for the character.
+ * @param c Character to look for.
+ * @return Pointer to the specified character on success,
+ *     NULL pointer otherwise.
+ */
+char *posix_strrchr(const char *s, int c)
+{
+	assert(s != NULL);
+	
+	const char *ptr = posix_strchr(s, '\0');
+	
+	/* the same as in strchr, except it loops in reverse direction */
+	while (*ptr != (char) c) {
+		if (ptr == s) {
+			return NULL;
+		}
+
+		ptr--;
+	}
+
+	return (char *) ptr;
+}
+
+/**
+ * Scan string for a first occurence of a character.
+ *
+ * @param s String in which to look for the character.
+ * @param c Character to look for.
+ * @return Pointer to the specified character on success, pointer to the
+ *     string terminator otherwise.
+ */
+char *gnu_strchrnul(const char *s, int c)
+{
+	assert(s != NULL);
+	
+	while (*s != c && *s != '\0') {
+		s++;
+	}
+	
+	return (char *) s;
+}
+
+/**
+ * Scan a string for a first occurence of one of provided bytes.
+ *
+ * @param s1 String in which to look for the bytes.
+ * @param s2 String of bytes to look for.
+ * @return Pointer to the found byte on success,
+ *     NULL pointer otherwise.
+ */
+char *posix_strpbrk(const char *s1, const char *s2)
+{
+	assert(s1 != NULL);
+	assert(s2 != NULL);
+
+	char *ptr = strpbrk_null(s1, s2);
+	return (*ptr == '\0') ? NULL : ptr;
+}
+
+/**
+ * Get the length of a complementary substring.
+ *
+ * @param s1 String that shall be searched for complementary prefix.
+ * @param s2 String of bytes that shall not occur in the prefix.
+ * @return Length of the prefix.
+ */
+size_t posix_strcspn(const char *s1, const char *s2)
+{
+	assert(s1 != NULL);
+	assert(s2 != NULL);
+
+	char *ptr = strpbrk_null(s1, s2);
+	return (size_t) (ptr - s1);
+}
+
+/**
+ * Get length of a substring.
+ *
+ * @param s1 String that shall be searched for prefix.
+ * @param s2 String of bytes that the prefix must consist of.
+ * @return Length of the prefix.
+ */
+size_t posix_strspn(const char *s1, const char *s2)
+{
+	assert(s1 != NULL);
+	assert(s2 != NULL);
+
+	const char *ptr;
+	for (ptr = s1; *ptr != '\0'; ++ptr) {
+		if (!posix_strchr(s2, *ptr)) {
+			break;
+		}
+	}
+	return ptr - s1;
+}
+
+/**
+ * Find a substring. Uses Knuth-Morris-Pratt algorithm.
+ *
+ * @param s1 String in which to look for a substring.
+ * @param s2 Substring to look for.
+ * @return Pointer to the first character of the substring in s1, or NULL if
+ *     not found.
+ */
+char *posix_strstr(const char *haystack, const char *needle)
+{
+	assert(haystack != NULL);
+	assert(needle != NULL);
+	
+	/* Special case - needle is an empty string. */
+	if (needle[0] == '\0') {
+		return (char *) haystack;
+	}
+	
+	/* Preprocess needle. */
+	size_t nlen = posix_strlen(needle);
+	size_t prefix_table[nlen + 1];
+	
+	{
+		size_t i = 0;
+		ssize_t j = -1;
+		
+		prefix_table[i] = j;
+		
+		while (i < nlen) {
+			while (j >= 0 && needle[i] != needle[j]) {
+				j = prefix_table[j];
+			}
+			i++; j++;
+			prefix_table[i] = j;
+		}
+	}
+	
+	/* Search needle using the precomputed table. */
+	size_t npos = 0;
+	
+	for (size_t hpos = 0; haystack[hpos] != '\0'; ++hpos) {
+		while (npos != 0 && haystack[hpos] != needle[npos]) {
+			npos = prefix_table[npos];
+		}
+		
+		if (haystack[hpos] == needle[npos]) {
+			npos++;
+			
+			if (npos == nlen) {
+				return (char *) (haystack + hpos - nlen + 1);
+			}
+		}
+	}
+	
+	return NULL;
+}
+
+/**
+ * String comparison using collating information.
+ *
+ * Currently ignores locale and just calls strcmp.
+ *
+ * @param s1 First string to be compared.
+ * @param s2 Second string to be compared.
+ * @return Difference of the first pair of inequal characters,
+ *     or 0 if strings have the same content.
+ */
+int posix_strcoll(const char *s1, const char *s2)
+{
+	assert(s1 != NULL);
+	assert(s2 != NULL);
+
+	return posix_strcmp(s1, s2);
+}
+
+/**
+ * Transform a string in such a way that the resulting string yields the same
+ * results when passed to the strcmp as if the original string is passed to
+ * the strcoll.
+ *
+ * Since strcoll is equal to strcmp here, this just makes a copy.
+ *
+ * @param s1 Transformed string.
+ * @param s2 Original string.
+ * @param n Maximum length of the transformed string.
+ * @return Length of the transformed string.
+ */
+size_t posix_strxfrm(char *restrict s1, const char *restrict s2, size_t n)
+{
+	assert(s1 != NULL || n == 0);
+	assert(s2 != NULL);
+
+	size_t len = posix_strlen(s2);
+
+	if (n > len) {
+		posix_strcpy(s1, s2);
+	}
+
+	return len;
+}
+
+/**
+ * Get error message string.
+ *
+ * @param errnum Error code for which to obtain human readable string.
+ * @return Error message.
+ */
+char *posix_strerror(int errnum)
+{
+	static const char *error_msgs[] = {
+		[E2BIG] = "[E2BIG] Argument list too long",
+		[EACCES] = "[EACCES] Permission denied",
+		[EADDRINUSE] = "[EADDRINUSE] Address in use",
+		[EADDRNOTAVAIL] = "[EADDRNOTAVAIL] Address not available",
+		[EAFNOSUPPORT] = "[EAFNOSUPPORT] Address family not supported",
+		[EAGAIN] = "[EAGAIN] Resource unavailable, try again",
+		[EALREADY] = "[EALREADY] Connection already in progress",
+		[EBADF] = "[EBADF] Bad file descriptor",
+		[EBADMSG] = "[EBADMSG] Bad message",
+		[EBUSY] = "[EBUSY] Device or resource busy",
+		[ECANCELED] = "[ECANCELED] Operation canceled",
+		[ECHILD] = "[ECHILD] No child processes",
+		[ECONNABORTED] = "[ECONNABORTED] Connection aborted",
+		[ECONNREFUSED] = "[ECONNREFUSED] Connection refused",
+		[ECONNRESET] = "[ECONNRESET] Connection reset",
+		[EDEADLK] = "[EDEADLK] Resource deadlock would occur",
+		[EDESTADDRREQ] = "[EDESTADDRREQ] Destination address required",
+		[EDOM] = "[EDOM] Mathematics argument out of domain of function",
+		[EDQUOT] = "[EDQUOT] Reserved",
+		[EEXIST] = "[EEXIST] File exists",
+		[EFAULT] = "[EFAULT] Bad address",
+		[EFBIG] = "[EFBIG] File too large",
+		[EHOSTUNREACH] = "[EHOSTUNREACH] Host is unreachable",
+		[EIDRM] = "[EIDRM] Identifier removed",
+		[EILSEQ] = "[EILSEQ] Illegal byte sequence",
+		[EINPROGRESS] = "[EINPROGRESS] Operation in progress",
+		[EINTR] = "[EINTR] Interrupted function",
+		[EINVAL] = "[EINVAL] Invalid argument",
+		[EIO] = "[EIO] I/O error",
+		[EISCONN] = "[EISCONN] Socket is connected",
+		[EISDIR] = "[EISDIR] Is a directory",
+		[ELOOP] = "[ELOOP] Too many levels of symbolic links",
+		[EMFILE] = "[EMFILE] File descriptor value too large",
+		[EMLINK] = "[EMLINK] Too many links",
+		[EMSGSIZE] = "[EMSGSIZE] Message too large",
+		[EMULTIHOP] = "[EMULTIHOP] Reserved",
+		[ENAMETOOLONG] = "[ENAMETOOLONG] Filename too long",
+		[ENETDOWN] = "[ENETDOWN] Network is down",
+		[ENETRESET] = "[ENETRESET] Connection aborted by network",
+		[ENETUNREACH] = "[ENETUNREACH] Network unreachable",
+		[ENFILE] = "[ENFILE] Too many files open in system",
+		[ENOBUFS] = "[ENOBUFS] No buffer space available",
+		[ENODATA] = "[ENODATA] No message is available on the STREAM head read queue",
+		[ENODEV] = "[ENODEV] No such device",
+		[ENOENT] = "[ENOENT] No such file or directory",
+		[ENOEXEC] = "[ENOEXEC] Executable file format error",
+		[ENOLCK] = "[ENOLCK] No locks available",
+		[ENOLINK] = "[ENOLINK] Reserved",
+		[ENOMEM] = "[ENOMEM] Not enough space",
+		[ENOMSG] = "[ENOMSG] No message of the desired type",
+		[ENOPROTOOPT] = "[ENOPROTOOPT] Protocol not available",
+		[ENOSPC] = "[ENOSPC] No space left on device",
+		[ENOSR] = "[ENOSR] No STREAM resources.",
+		[ENOSTR] = "[ENOSTR] Not a STREAM",
+		[ENOSYS] = "[ENOSYS] Function not supported",
+		[ENOTCONN] = "[ENOTCONN] The socket is not connected",
+		[ENOTDIR] = "[ENOTDIR] Not a directory",
+		[ENOTEMPTY] = "[ENOTEMPTY] Directory not empty",
+		[ENOTRECOVERABLE] = "[ENOTRECOVERABLE] State not recoverable",
+		[ENOTSOCK] = "[ENOTSOCK] Not a socket",
+		[ENOTSUP] = "[ENOTSUP] Not supported",
+		[ENOTTY] = "[ENOTTY] Inappropriate I/O control operation",
+		[ENXIO] = "[ENXIO] No such device or address",
+		[EOPNOTSUPP] = "[EOPNOTSUPP] Operation not supported",
+		[EOVERFLOW] = "[EOVERFLOW] Value too large to be stored in data type",
+		[EOWNERDEAD] = "[EOWNERDEAD] Previous owned died",
+		[EPERM] = "[EPERM] Operation not permitted",
+		[EPIPE] = "[EPIPE] Broken pipe",
+		[EPROTO] = "[EPROTO] Protocol error",
+		[EPROTONOSUPPORT] = "[EPROTONOSUPPORT] Protocol not supported",
+		[EPROTOTYPE] = "[EPROTOTYPE] Protocol wrong type for socket",
+		[ERANGE] = "[ERANGE] Result too large",
+		[EROFS] = "[EROFS] Read-only file system",
+		[ESPIPE] = "[ESPIPE] Invalid seek",
+		[ESRCH] = "[ESRCH] No such process",
+		[ESTALE] = "[ESTALE] Reserved",
+		[ETIME] = "[ETIME] Stream ioctl() timeout",
+		[ETIMEDOUT] = "[ETIMEDOUT] Connection timed out",
+		[ETXTBSY] = "[ETXTBSY] Text file busy",
+		[EWOULDBLOCK] = "[EWOULDBLOCK] Operation would block",
+		[EXDEV] = "[EXDEV] Cross-device link",
+	};
+
+	return (char *) error_msgs[posix_abs(errnum)];
+}
+
+/**
+ * Get error message string.
+ *
+ * @param errnum Error code for which to obtain human readable string.
+ * @param buf Buffer to store a human readable string to.
+ * @param bufsz Size of buffer pointed to by buf.
+ * @return Zero on success, errno otherwise.
+ */
+int posix_strerror_r(int errnum, char *buf, size_t bufsz)
+{
+	assert(buf != NULL);
+	
+	char *errstr = posix_strerror(errnum);
+	
+	if (posix_strlen(errstr) + 1 > bufsz) {
+		return ERANGE;
+	} else {
+		posix_strcpy(buf, errstr);
+	}
+
+	return 0;
+}
+
+/**
+ * Get length of the string.
+ *
+ * @param s String which length shall be determined.
+ * @return Length of the string.
+ */
+size_t posix_strlen(const char *s)
+{
+	assert(s != NULL);
+	
+	return (size_t) (posix_strchr(s, '\0') - s);
+}
+
+/**
+ * Get limited length of the string.
+ *
+ * @param s String which length shall be determined.
+ * @param n Maximum number of bytes that can be examined to determine length.
+ * @return The lower of either string length or n limit.
+ */
+size_t posix_strnlen(const char *s, size_t n)
+{
+	assert(s != NULL);
+	
+	for (size_t sz = 0; sz < n; ++sz) {
+		
+		if (s[sz] == '\0') {
+			return sz;
+		}
+	}
+	
+	return n;
+}
+
+/**
+ * Get description of a signal.
+ *
+ * @param signum Signal number.
+ * @return Human readable signal description.
+ */
+char *posix_strsignal(int signum)
+{
+	static const char *const sigstrings[] = {
+		[SIGABRT] = "SIGABRT (Process abort signal)",
+		[SIGALRM] = "SIGALRM (Alarm clock)",
+		[SIGBUS] = "SIGBUS (Access to an undefined portion of a memory object)",
+		[SIGCHLD] = "SIGCHLD (Child process terminated, stopped, or continued)",
+		[SIGCONT] = "SIGCONT (Continue executing, if stopped)",
+		[SIGFPE] = "SIGFPE (Erroneous arithmetic operation)",
+		[SIGHUP] = "SIGHUP (Hangup)",
+		[SIGILL] = "SIGILL (Illegal instruction)",
+		[SIGINT] = "SIGINT (Terminal interrupt signal)",
+		[SIGKILL] = "SIGKILL (Kill process)",
+		[SIGPIPE] = "SIGPIPE (Write on a pipe with no one to read it)",
+		[SIGQUIT] = "SIGQUIT (Terminal quit signal)",
+		[SIGSEGV] = "SIGSEGV (Invalid memory reference)",
+		[SIGSTOP] = "SIGSTOP (Stop executing)",
+		[SIGTERM] = "SIGTERM (Termination signal)",
+		[SIGTSTP] = "SIGTSTP (Terminal stop signal)",
+		[SIGTTIN] = "SIGTTIN (Background process attempting read)",
+		[SIGTTOU] = "SIGTTOU (Background process attempting write)",
+		[SIGUSR1] = "SIGUSR1 (User-defined signal 1)",
+		[SIGUSR2] = "SIGUSR2 (User-defined signal 2)",
+		[SIGPOLL] = "SIGPOLL (Pollable event)",
+		[SIGPROF] = "SIGPROF (Profiling timer expired)",
+		[SIGSYS] = "SIGSYS (Bad system call)",
+		[SIGTRAP] = "SIGTRAP (Trace/breakpoint trap)",
+		[SIGURG] = "SIGURG (High bandwidth data is available at a socket)",
+		[SIGVTALRM] = "SIGVTALRM (Virtual timer expired)",
+		[SIGXCPU] = "SIGXCPU (CPU time limit exceeded)",
+		[SIGXFSZ] = "SIGXFSZ (File size limit exceeded)"
+	};
+
+	if (signum <= _TOP_SIGNAL) {
+		return (char *) sigstrings[signum];
+	}
+
+	return (char *) "ERROR, Invalid signal number";
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/strings.c
===================================================================
--- uspace/lib/posix/source/strings.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/strings.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,187 @@
+/*
+ * 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 Additional string manipulation.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "internal/common.h"
+#include "posix/strings.h"
+
+#include "posix/string.h"
+#include "posix/ctype.h"
+
+#include "libc/mem.h"
+
+/**
+ * Find first set bit (beginning with the least significant bit).
+ *
+ * @param i Integer in which to look for the first set bit.
+ * @return Index of first set bit. Bits are numbered starting at one.
+ */
+int posix_ffs(int i)
+{
+	if (i == 0) {
+		return 0;
+	}
+
+	int result = 0;
+
+	// XXX: assumes at most 32-bit int
+	if (!(i & 0xFFFF)) {
+		result |= 16;
+		i >>= 16;
+	}
+	if (!(i & 0xFF)) {
+		result |= 8;
+		i >>= 8;
+	}
+	if (!(i & 0xF)) {
+		result |= 4;
+		i >>= 4;
+	}
+	if (!(i & 0x3)) {
+		result |= 2;
+		i >>= 2;
+	}
+	if (!(i & 0x1)) {
+		result |= 1;
+	}
+
+	return result + 1;
+}
+
+/**
+ * Compare two strings (case-insensitive).
+ *
+ * @param s1 First string to be compared.
+ * @param s2 Second string to be compared.
+ * @return Difference of the first pair of inequal characters,
+ *     or 0 if strings have the same content.
+ */
+int posix_strcasecmp(const char *s1, const char *s2)
+{
+	return posix_strncasecmp(s1, s2, STR_NO_LIMIT);
+}
+
+/**
+ * Compare part of two strings (case-insensitive).
+ *
+ * @param s1 First string to be compared.
+ * @param s2 Second string to be compared.
+ * @param n Maximum number of characters to be compared.
+ * @return Difference of the first pair of inequal characters,
+ *     or 0 if strings have the same content.
+ */
+int posix_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+	for (size_t i = 0; i < n; ++i) {
+		int cmp = tolower(s1[i]) - tolower(s2[i]);
+		if (cmp != 0) {
+			return cmp;
+		}
+		
+		if (s1[i] == 0) {
+			return 0;
+		}
+	}
+	
+	return 0;
+}
+
+/**
+ * Compare two memory areas.
+ *
+ * @param mem1 Pointer to the first area to compare.
+ * @param mem2 Pointer to the second area to compare.
+ * @param n Common size of both areas.
+ * @return If n is 0, return zero. If the areas match, return
+ *     zero. Otherwise return non-zero.
+ */
+int posix_bcmp(const void *mem1, const void *mem2, size_t n)
+{
+	return bcmp(mem1, mem2, n);
+}
+
+/**
+ * Copy bytes in memory with overlapping areas.
+ *
+ * @param src Source area.
+ * @param dest Destination area.
+ * @param n Number of bytes to copy.
+ */
+void posix_bcopy(const void *src, void *dest, size_t n)
+{
+	/* Note that memmove has different order of arguments. */
+	memmove(dest, src, n);
+}
+
+/**
+ * Reset bytes in memory area to zero.
+ *
+ * @param mem Memory area to be zeroed.
+ * @param n Number of bytes to reset.
+ */
+void posix_bzero(void *mem, size_t n)
+{
+	bzero(mem, n);
+}
+
+/**
+ * Scan string for a first occurence of a character.
+ *
+ * @param s String in which to look for the character.
+ * @param c Character to look for.
+ * @return Pointer to the specified character on success,
+ *     NULL pointer otherwise.
+ */
+char *posix_index(const char *s, int c)
+{
+	return posix_strchr(s, c);
+}
+
+/**
+ * Scan string for a last occurence of a character.
+ *
+ * @param s String in which to look for the character.
+ * @param c Character to look for.
+ * @return Pointer to the specified character on success,
+ *     NULL pointer otherwise.
+ */
+char *posix_rindex(const char *s, int c)
+{
+	return posix_strrchr(s, c);
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/sys/stat.c
===================================================================
--- uspace/lib/posix/source/sys/stat.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/sys/stat.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,151 @@
+/*
+ * 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 File status handling.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "../internal/common.h"
+#include "posix/sys/stat.h"
+#include "libc/sys/stat.h"
+
+#include "posix/errno.h"
+#include "libc/mem.h"
+
+/**
+ * Convert HelenOS stat struct into POSIX stat struct (if possible).
+ *
+ * @param dest POSIX stat struct.
+ * @param src HelenOS stat struct.
+ */
+static void stat_to_posix(struct posix_stat *dest, struct stat *src)
+{
+	memset(dest, 0, sizeof(struct posix_stat));
+	
+	dest->st_dev = src->service;
+	dest->st_ino = src->index;
+	
+	/* HelenOS doesn't support permissions, so we set them all */
+	dest->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
+	if (src->is_file) {
+		dest->st_mode |= S_IFREG;
+	}
+	if (src->is_directory) {
+		dest->st_mode |= S_IFDIR;
+	}
+	
+	dest->st_nlink = src->lnkcnt;
+	dest->st_size = src->size;
+}
+
+/**
+ * Retrieve file status for file associated with file descriptor.
+ *
+ * @param fd File descriptor of the opened file.
+ * @param st Status structure to be filled with information.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_fstat(int fd, struct posix_stat *st)
+{
+	struct stat hst;
+	int rc = fstat(fd, &hst);
+	if (rc < 0) {
+		/* fstat() returns negative error code instead of using errno. */
+		errno = -rc;
+		return -1;
+	}
+	stat_to_posix(st, &hst);
+	return 0;
+}
+
+/**
+ * Retrieve file status for symbolic link.
+ * 
+ * @param path Path to the symbolic link.
+ * @param st Status structure to be filled with information.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_lstat(const char *restrict path, struct posix_stat *restrict st)
+{
+	/* There are currently no symbolic links in HelenOS. */
+	return posix_stat(path, st);
+}
+
+/**
+ * Retrieve file status for regular file (or symbolic link target).
+ *
+ * @param path Path to the file/link.
+ * @param st Status structure to be filled with information.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_stat(const char *restrict path, struct posix_stat *restrict st)
+{
+	struct stat hst;
+	int rc = stat(path, &hst);
+	if (rc < 0) {
+		/* stat() returns negative error code instead of using errno. */
+		errno = -rc;
+		return -1;
+	}
+	stat_to_posix(st, &hst);
+	return 0;
+}
+
+/**
+ * Change permission bits for the file if possible.
+ * 
+ * @param path Path to the file.
+ * @param mode Permission bits to be set.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_chmod(const char *path, mode_t mode)
+{
+	/* HelenOS doesn't support permissions, return success. */
+	return 0;
+}
+
+/**
+ * Set the file mode creation mask of the process.
+ * 
+ * @param mask Set permission bits are cleared in the related creation
+ *     functions. Non-permission bits are ignored.
+ * @return Previous file mode creation mask.
+ */
+mode_t posix_umask(mode_t mask)
+{
+	/* HelenOS doesn't support permissions, return empty mask. */
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/sys/wait.c
===================================================================
--- uspace/lib/posix/source/sys/wait.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/sys/wait.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Support for waiting.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "../internal/common.h"
+#include "posix/sys/wait.h"
+
+#include "libc/task.h"
+#include "posix/assert.h"
+#include "posix/errno.h"
+#include "posix/limits.h"
+#include "posix/signal.h"
+
+int __posix_wifexited(int status) {
+	return status != INT_MIN;
+}
+
+int __posix_wexitstatus(int status) {
+	assert(__posix_wifexited(status));
+	return status;
+}
+
+int __posix_wifsignaled(int status) {
+	return status == INT_MIN;
+}
+
+int __posix_wtermsig(int status) {
+	assert(__posix_wifsignaled(status));
+	/* There is no way to distinguish reason
+	 * for unexpected termination at the moment.
+	 */
+	return SIGABRT;
+}
+
+/**
+ * Wait for any child process to stop or terminate.
+ * 
+ * @param stat_ptr Location of the final status code of the child process.
+ * @return ID of the child process for which status is reported,
+ *     -1 on signal interrupt, (pid_t)-1 otherwise.
+ */
+posix_pid_t posix_wait(int *stat_ptr)
+{
+	/* HelenOS does not support this. */
+	errno = ENOSYS;
+	return (posix_pid_t) -1;
+}
+
+/**
+ * Wait for a child process to stop or terminate.
+ * 
+ * @param pid What child process shall the caller wait for. See POSIX manual
+ *     for details.
+ * @param stat_ptr Location of the final status code of the child process.
+ * @param options Constraints of the waiting. See POSIX manual for details.
+ * @return ID of the child process for which status is reported,
+ *     -1 on signal interrupt, 0 if non-blocking wait is requested but there is
+ *     no child process whose status can be reported, (pid_t)-1 otherwise.
+ */
+posix_pid_t posix_waitpid(posix_pid_t pid, int *stat_ptr, int options)
+{
+	assert(stat_ptr != NULL);
+	assert(options == 0 /* None of the options are supported. */);
+	
+	task_exit_t texit;
+	int retval;
+	
+	int rc = task_wait((task_id_t) pid, &texit, &retval);
+	
+	if (rc < 0) {
+		/* Unable to retrieve status. */
+		errno = -rc;
+		return (posix_pid_t) -1;
+	}
+	
+	if (texit == TASK_EXIT_NORMAL) {
+		// FIXME: relies on application not returning this value
+		assert(retval != INT_MIN);
+		*stat_ptr = retval;
+	} else {
+		/* Reserve the lowest value for unexpected termination. */
+		*stat_ptr = INT_MIN;
+	}
+	
+	return pid;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/time.c
===================================================================
--- uspace/lib/posix/source/time.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/time.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 Time measurement support.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+/* Must be first. */
+#include "posix/stdbool.h"
+
+#include "internal/common.h"
+#include "posix/time.h"
+
+#include "posix/ctype.h"
+#include "posix/errno.h"
+#include "posix/signal.h"
+#include "posix/assert.h"
+
+#include "libc/malloc.h"
+#include "libc/task.h"
+#include "libc/stats.h"
+#include "libc/sys/time.h"
+
+// TODO: test everything in this file
+
+/* In some places in this file, phrase "normalized broken-down time" is used.
+ * This means time broken down to components (year, month, day, hour, min, sec),
+ * in which every component is in its proper bounds. Non-normalized time could
+ * e.g. be 2011-54-5 29:13:-5, which would semantically mean start of year 2011
+ * + 53 months + 4 days + 29 hours + 13 minutes - 5 seconds.
+ */
+
+int posix_daylight;
+long posix_timezone;
+char *posix_tzname[2];
+
+/**
+ * Set timezone conversion information.
+ */
+void posix_tzset(void)
+{
+	// TODO: read environment
+	posix_tzname[0] = (char *) "GMT";
+	posix_tzname[1] = (char *) "GMT";
+	posix_daylight = 0;
+	posix_timezone = 0;
+}
+
+/**
+ * Converts a time value to a broken-down UTC time.
+ * 
+ * @param timer Time to convert.
+ * @param result Structure to store the result to.
+ * @return Value of result on success, NULL on overflow.
+ */
+struct tm *posix_gmtime_r(const time_t *restrict timer,
+    struct tm *restrict result)
+{
+	int rc = time_utc2tm(*timer, result);
+	if (rc != EOK) {
+		errno = rc;
+		return NULL;
+	}
+
+	return result;
+}
+
+/**
+ * Converts a time value to a broken-down UTC time.
+ * (non reentrant version)
+ *
+ * @param timep  Time to convert
+ * @return       Pointer to a statically allocated structure that stores
+ *               the result, NULL in case of error.
+ */
+struct tm *posix_gmtime(const time_t *restrict timep)
+{
+	static struct tm result;
+
+	return posix_gmtime_r(timep, &result);
+}
+
+/**
+ * Converts a time value to a broken-down local time.
+ * 
+ * @param timer Time to convert.
+ * @param result Structure to store the result to.
+ * @return Value of result on success, NULL on overflow.
+ */
+struct tm *posix_localtime_r(const time_t *restrict timer,
+    struct tm *restrict result)
+{
+	// TODO: deal with timezone
+	// currently assumes system and all times are in GMT
+	return posix_gmtime_r(timer, result);
+}
+
+/**
+ * Converts a time value to a broken-down local time.
+ * (non reentrant version)
+ *
+ * @param timep    Time to convert.
+ * @return         Pointer to a statically allocated structure that stores
+ *                 the result, NULL in case of error.
+ */
+struct tm *posix_localtime(const time_t *restrict timep)
+{
+	static struct tm result;
+
+	return posix_localtime_r(timep, &result);
+}
+
+/**
+ * Converts broken-down time to a string in format
+ * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
+ *
+ * @param timeptr Broken-down time structure.
+ * @param buf Buffer to store string to, must be at least ASCTIME_BUF_LEN
+ *     bytes long.
+ * @return Value of buf.
+ */
+char *posix_asctime_r(const struct tm *restrict timeptr,
+    char *restrict buf)
+{
+	time_tm2str(timeptr, buf);
+	return buf;
+}
+
+/**
+ * Convers broken-down time to a string in format
+ * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
+ * (non reentrant version)
+ *
+ * @param timeptr    Broken-down time structure.
+ * @return           Pointer to a statically allocated buffer that stores
+ *                   the result, NULL in case of error.
+ */
+char *posix_asctime(const struct tm *restrict timeptr)
+{
+	static char buf[ASCTIME_BUF_LEN];
+
+	return posix_asctime_r(timeptr, buf);
+}
+
+/**
+ * Converts the calendar time to a string in format
+ * "Sun Jan 1 00:00:00 1970\n" (Obsolete)
+ * 
+ * @param timer Time to convert.
+ * @param buf Buffer to store string to. Must be at least ASCTIME_BUF_LEN
+ *     bytes long.
+ * @return Pointer to buf on success, NULL on failure.
+ */
+char *posix_ctime_r(const time_t *timer, char *buf)
+{
+	int r = time_local2str(*timer, buf);
+	if (r != EOK) {
+		errno = r;
+		return NULL;
+	}
+
+	return buf;
+}
+
+/**
+ * Converts the calendar time to a string in format
+ * "Sun Jan 1 00:00:00 1970\n" (Obsolete)
+ * (non reentrant version)
+ *
+ * @param timep    Time to convert.
+ * @return         Pointer to a statically allocated buffer that stores
+ *                 the result, NULL in case of error.
+ */
+char *posix_ctime(const time_t *timep)
+{
+	static char buf[ASCTIME_BUF_LEN];
+
+	return posix_ctime_r(timep, buf);
+}
+
+/**
+ * Get clock resolution. Only CLOCK_REALTIME is supported.
+ *
+ * @param clock_id Clock ID.
+ * @param res Pointer to the variable where the resolution is to be written.
+ * @return 0 on success, -1 with errno set on failure.
+ */
+int posix_clock_getres(posix_clockid_t clock_id, struct posix_timespec *res)
+{
+	assert(res != NULL);
+
+	switch (clock_id) {
+		case CLOCK_REALTIME:
+			res->tv_sec = 0;
+			res->tv_nsec = 1000; /* Microsecond resolution. */
+			return 0;
+		default:
+			errno = EINVAL;
+			return -1;
+	}
+}
+
+/**
+ * Get time. Only CLOCK_REALTIME is supported.
+ * 
+ * @param clock_id ID of the clock to query.
+ * @param tp Pointer to the variable where the time is to be written.
+ * @return 0 on success, -1 with errno on failure.
+ */
+int posix_clock_gettime(posix_clockid_t clock_id, struct posix_timespec *tp)
+{
+	assert(tp != NULL);
+
+	switch (clock_id) {
+		case CLOCK_REALTIME:
+			;
+			struct timeval tv;
+			gettimeofday(&tv, NULL);
+			tp->tv_sec = tv.tv_sec;
+			tp->tv_nsec = tv.tv_usec * 1000;
+			return 0;
+		default:
+			errno = EINVAL;
+			return -1;
+	}
+}
+
+/**
+ * Set time on a specified clock. As HelenOS doesn't support this yet,
+ * this function always fails.
+ * 
+ * @param clock_id ID of the clock to set.
+ * @param tp Time to set.
+ * @return 0 on success, -1 with errno on failure.
+ */
+int posix_clock_settime(posix_clockid_t clock_id,
+    const struct posix_timespec *tp)
+{
+	assert(tp != NULL);
+
+	switch (clock_id) {
+		case CLOCK_REALTIME:
+			// TODO: setting clock
+			// FIXME: HelenOS doesn't actually support hardware
+			//        clock yet
+			errno = EPERM;
+			return -1;
+		default:
+			errno = EINVAL;
+			return -1;
+	}
+}
+
+/**
+ * Sleep on a specified clock.
+ * 
+ * @param clock_id ID of the clock to sleep on (only CLOCK_REALTIME supported).
+ * @param flags Flags (none supported).
+ * @param rqtp Sleep time.
+ * @param rmtp Remaining time is written here if sleep is interrupted.
+ * @return 0 on success, -1 with errno set on failure.
+ */
+int posix_clock_nanosleep(posix_clockid_t clock_id, int flags,
+    const struct posix_timespec *rqtp, struct posix_timespec *rmtp)
+{
+	assert(rqtp != NULL);
+	assert(rmtp != NULL);
+
+	switch (clock_id) {
+		case CLOCK_REALTIME:
+			// TODO: interruptible sleep
+			if (rqtp->tv_sec != 0) {
+				sleep(rqtp->tv_sec);
+			}
+			if (rqtp->tv_nsec != 0) {
+				usleep(rqtp->tv_nsec / 1000);
+			}
+			return 0;
+		default:
+			errno = EINVAL;
+			return -1;
+	}
+}
+
+/**
+ * Get CPU time used since the process invocation.
+ *
+ * @return Consumed CPU cycles by this process or -1 if not available.
+ */
+posix_clock_t posix_clock(void)
+{
+	posix_clock_t total_cycles = -1;
+	stats_task_t *task_stats = stats_get_task(task_get_id());
+	if (task_stats) {
+		total_cycles = (posix_clock_t) (task_stats->kcycles +
+		    task_stats->ucycles);
+		free(task_stats);
+		task_stats = 0;
+	}
+
+	return total_cycles;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/unistd.c
===================================================================
--- uspace/lib/posix/source/unistd.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/posix/source/unistd.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,424 @@
+/*
+ * 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 Miscellaneous standard definitions.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "internal/common.h"
+#include "posix/unistd.h"
+
+#include "posix/errno.h"
+#include "posix/string.h"
+#include "posix/fcntl.h"
+
+#include "libc/task.h"
+#include "libc/stats.h"
+#include "libc/malloc.h"
+
+/* Array of environment variable strings (NAME=VALUE). */
+char **posix_environ = NULL;
+char *posix_optarg;
+
+/**
+ * Get current user name.
+ *
+ * @return User name (static) string or NULL if not found.
+ */
+char *posix_getlogin(void)
+{
+	/* There is currently no support for user accounts in HelenOS. */
+	return (char *) "user";
+}
+
+/**
+ * Get current user name.
+ *
+ * @param name Pointer to a user supplied buffer.
+ * @param namesize Length of the buffer.
+ * @return Zero on success, error code otherwise.
+ */
+int posix_getlogin_r(char *name, size_t namesize)
+{
+	/* There is currently no support for user accounts in HelenOS. */
+	if (namesize >= 5) {
+		posix_strcpy(name, (char *) "user");
+		return 0;
+	} else {
+		errno = ERANGE;
+		return -1;
+	}
+}
+
+/**
+ * Test whether open file descriptor is associated with a terminal.
+ *
+ * @param fd Open file descriptor to test.
+ * @return Boolean result of the test.
+ */
+int posix_isatty(int fd)
+{
+	// TODO
+	/* Always returns false, because there is no easy way to find
+	 * out under HelenOS. */
+	return 0;
+}
+
+/**
+ * Get the pathname of the current working directory.
+ *
+ * @param buf Buffer into which the pathname shall be put.
+ * @param size Size of the buffer.
+ * @return Buffer pointer on success, NULL on failure.
+ */
+char *posix_getcwd(char *buf, size_t size)
+{
+	/* Native getcwd() does not set any errno despite the fact that general
+	 * usage pattern of this function depends on it (caller is repeatedly
+	 * guessing the required size of the buffer by checking for ERANGE on
+	 * failure). */
+	if (size == 0) {
+		errno = EINVAL;
+		return NULL;
+	}
+	
+	/* Save the original value to comply with the "no modification on
+	 * success" semantics.
+	 */
+	int orig_errno = errno;
+	errno = EOK;
+	
+	char *ret = getcwd(buf, size);
+	if (ret == NULL) {
+		/* Check errno to avoid shadowing other possible errors. */
+		if (errno == EOK) {
+			errno = ERANGE;
+		}
+	} else {
+		/* Success, restore previous errno value. */
+		errno = orig_errno;
+	}
+	
+	return ret;
+}
+
+/**
+ * Change the current working directory.
+ *
+ * @param path New working directory.
+ */
+int posix_chdir(const char *path)
+{
+	return errnify(chdir, path);
+}
+
+/**
+ * Determine the page size of the current run of the process.
+ *
+ * @return Page size of the process.
+ */
+int posix_getpagesize(void)
+{
+	return getpagesize();
+}
+
+/**
+ * Get the process ID of the calling process.
+ *
+ * @return Process ID.
+ */
+posix_pid_t posix_getpid(void)
+{
+	return task_get_id();
+}
+
+/**
+ * Get the real user ID of the calling process.
+ *
+ * @return User ID.
+ */
+posix_uid_t posix_getuid(void)
+{
+	/* There is currently no support for user accounts in HelenOS. */
+	return 0;
+}
+
+/**
+ * Get the real group ID of the calling process.
+ * 
+ * @return Group ID.
+ */
+posix_gid_t posix_getgid(void)
+{
+	/* There is currently no support for user accounts in HelenOS. */
+	return 0;
+}
+
+/**
+ * Close a file.
+ *
+ * @param fildes File descriptor of the opened file.
+ * @return 0 on success, -1 on error.
+ */
+int posix_close(int fildes)
+{
+	return errnify(close, fildes);
+}
+
+/**
+ * Read from a file.
+ *
+ * @param fildes File descriptor of the opened file.
+ * @param buf Buffer to which the read bytes shall be stored.
+ * @param nbyte Upper limit on the number of read bytes.
+ * @return Number of read bytes on success, -1 otherwise.
+ */
+ssize_t posix_read(int fildes, void *buf, size_t nbyte)
+{
+	return errnify(read, fildes, buf, nbyte);
+}
+
+/**
+ * Write to a file.
+ *
+ * @param fildes File descriptor of the opened file.
+ * @param buf Buffer to write.
+ * @param nbyte Size of the buffer.
+ * @return Number of written bytes on success, -1 otherwise.
+ */
+ssize_t posix_write(int fildes, const void *buf, size_t nbyte)
+{
+	return errnify(write, fildes, buf, nbyte);
+}
+
+/**
+ * Requests outstanding data to be written to the underlying storage device.
+ *
+ * @param fildes File descriptor of the opened file.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_fsync(int fildes)
+{
+	return errnify(fsync, fildes);
+}
+
+/**
+ * Truncate a file to a specified length.
+ *
+ * @param fildes File descriptor of the opened file.
+ * @param length New length of the file.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_ftruncate(int fildes, posix_off_t length)
+{
+	return errnify(ftruncate, fildes, (aoff64_t) length);
+}
+
+/**
+ * Remove a directory.
+ *
+ * @param path Directory pathname.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_rmdir(const char *path)
+{
+	return errnify(rmdir, path);
+}
+
+/**
+ * Remove a link to a file.
+ * 
+ * @param path File pathname.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_unlink(const char *path)
+{
+	return errnify(unlink, path);
+}
+
+/**
+ * Duplicate an open file descriptor.
+ *
+ * @param fildes File descriptor to be duplicated.
+ * @return On success, new file descriptor for the same file, otherwise -1.
+ */
+int posix_dup(int fildes)
+{
+	return posix_fcntl(fildes, F_DUPFD, 0);
+}
+
+/**
+ * Duplicate an open file descriptor.
+ * 
+ * @param fildes File descriptor to be duplicated.
+ * @param fildes2 File descriptor to be paired with the same file description
+ *     as is paired fildes.
+ * @return fildes2 on success, -1 otherwise.
+ */
+int posix_dup2(int fildes, int fildes2)
+{
+	return errnify(dup2, fildes, fildes2);
+}
+
+/**
+ * Determine accessibility of a file.
+ *
+ * @param path File to check accessibility for.
+ * @param amode Either check for existence or intended access mode.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_access(const char *path, int amode)
+{
+	if (amode == F_OK || (amode & (X_OK | W_OK | R_OK))) {
+		/* HelenOS doesn't support permissions, permission checks
+		 * are equal to existence check.
+		 *
+		 * Check file existence by attempting to open it.
+		 */
+		int fd = open(path, O_RDONLY);
+		if (fd < 0) {
+			errno = -fd;
+			return -1;
+		}
+		close(fd);
+		return 0;
+	} else {
+		/* Invalid amode argument. */
+		errno = EINVAL;
+		return -1;
+	}
+}
+
+/**
+ * Get configurable system variables.
+ * 
+ * @param name Variable name.
+ * @return Variable value.
+ */
+long posix_sysconf(int name)
+{
+	long clk_tck = 0;
+	size_t cpu_count = 0;
+	stats_cpu_t *cpu_stats = stats_get_cpus(&cpu_count);
+	if (cpu_stats && cpu_count > 0) {
+		clk_tck = ((long) cpu_stats[0].frequency_mhz) * 1000000L;
+	}
+	if (cpu_stats) {
+		free(cpu_stats);
+		cpu_stats = 0;
+	}
+
+	long phys_pages = 0;
+	long avphys_pages = 0;
+	stats_physmem_t *mem_stats = stats_get_physmem();
+	if (mem_stats) {
+		phys_pages = (long) (mem_stats->total / getpagesize());
+		avphys_pages = (long) (mem_stats->free / getpagesize());
+		free(mem_stats);
+		mem_stats = 0;
+	}
+
+	switch (name) {
+	case _SC_PHYS_PAGES:
+		return phys_pages;
+	case _SC_AVPHYS_PAGES:
+		return avphys_pages;
+	case _SC_PAGESIZE:
+		return getpagesize();
+	case _SC_CLK_TCK:
+		return clk_tck;
+	default:
+		errno = EINVAL;
+		return -1;
+	}
+}
+
+/**
+ * 
+ * @param path
+ * @param name
+ * @return
+ */
+long posix_pathconf(const char *path, int name)
+{
+	// TODO: low priority, just a compile-time dependency of binutils
+	not_implemented();
+}
+
+/**
+ * 
+ * @return
+ */
+posix_pid_t posix_fork(void)
+{
+	// TODO: low priority, just a compile-time dependency of binutils
+	not_implemented();
+}
+
+/**
+ * 
+ * @param path
+ * @param argv
+ * @return
+ */
+int posix_execv(const char *path, char *const argv[])
+{
+	// TODO: low priority, just a compile-time dependency of binutils
+	not_implemented();
+}
+
+/**
+ * 
+ * @param file
+ * @param argv
+ * @return
+ */
+int posix_execvp(const char *file, char *const argv[])
+{
+	// TODO: low priority, just a compile-time dependency of binutils
+	not_implemented();
+}
+
+/**
+ * 
+ * @param fildes
+ * @return
+ */
+int posix_pipe(int fildes[2])
+{
+	// TODO: low priority, just a compile-time dependency of binutils
+	not_implemented();
+}
+
+/** @}
+ */
Index: pace/lib/posix/stdbool.h
===================================================================
--- uspace/lib/posix/stdbool.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,55 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Boolean type and values.
- */
-
-#ifndef POSIX_STDBOOL_H_
-#define POSIX_STDBOOL_H_
-
-#ifdef LIBC_BOOL_H_
-
-#if (!defined(POSIX_STDIO_H_)) && \
-    (!defined(POSIX_STDLIB_H_)) && \
-    (!defined(POSIX_STRING_H_))
-	#error "You can't include bool.h and stdbool.h at the same time."
-#endif
-
-#endif /* LIBC_BOOL_H */
-
-#define LIBC_BOOL_H_
-
-#define bool _Bool
-#define true 1
-#define false 0
-#define __bool_true_false_are_defined 1
-
-#endif /* POSIX_STDBOOL_H_ */
Index: pace/lib/posix/stddef.h
===================================================================
--- uspace/lib/posix/stddef.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,55 +1,0 @@
-/*
- * 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 type definitions.
- */
-
-#ifndef POSIX_STDDEF_H_
-#define POSIX_STDDEF_H_
-
-#include "libc/stddef.h"
-
-#ifndef NULL
-	#define NULL  ((void *) 0)
-#endif
-
-#define offsetof(type,member) ((size_t) &(((type *) 0)->member))
-
-typedef ssize_t posix_ptrdiff_t;
-
-#ifndef LIBPOSIX_INTERNAL
-	#define ptrdiff_t posix_ptrdiff_t
-#endif
-
-#endif /* POSIX_STDDEF_H_ */
-
-/** @}
- */
Index: pace/lib/posix/stdint.h
===================================================================
--- uspace/lib/posix/stdint.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,113 +1,0 @@
-/*
- * 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 Integer types.
- */
-
-#ifndef POSIX_STDINT_H_
-#define POSIX_STDINT_H_
-
-#include "libc/stdint.h"
-
-#undef INT8_MAX
-#undef INT8_MIN
-#define INT8_MAX  127
-#define INT8_MIN  (-128)
-
-#undef UINT8_MAX
-#undef UINT8_MIN
-#define UINT8_MAX  255
-#define UINT8_MIN  0
-
-#undef INT16_MAX
-#undef INT16_MIN
-#define INT16_MAX  32767
-#define INT16_MIN  (-32768)
-
-#undef UINT16_MAX
-#undef UINT16_MIN
-#define UINT16_MAX  65535
-#define UINT16_MIN  0
-
-#undef INT32_MAX
-#undef INT32_MIN
-#define INT32_MAX  2147483647
-#define INT32_MIN  (-INT32_MAX - 1)
-
-#undef UINT32_MAX
-#undef UINT32_MIN
-#define UINT32_MAX  4294967295U
-#define UINT32_MIN  0U
-
-#undef INT64_MAX
-#undef INT64_MIN
-#define INT64_MAX  9223372036854775807LL
-#define INT64_MIN  (-INT64_MAX - 1LL)
-
-#undef UINT64_MAX
-#undef  UINT64_MIN
-#define UINT64_MAX  18446744073709551615ULL
-#define UINT64_MIN  0ULL
-
-#undef OFF64_MAX
-#undef OFF64_MIN
-#define OFF64_MAX  INT64_MAX
-#define OFF64_MIN  INT64_MIN
-
-#undef AOFF64_MAX
-#undef AOFF64_MIN
-#define AOFF64_MAX  UINT64_MAX
-#define AOFF64_MIN  UINT64_MIN
-
-#undef INTMAX_MIN
-#undef INTMAX_MAX
-#define INTMAX_MIN INT64_MIN
-#define INTMAX_MAX INT64_MAX
-
-#undef UINTMAX_MIN
-#undef UINTMAX_MAX
-#define UINTMAX_MIN UINT64_MIN
-#define UINTMAX_MAX UINT64_MAX
-
-#include "libc/sys/types.h"
-
-typedef int64_t posix_intmax_t;
-typedef uint64_t posix_uintmax_t;
-
-#ifndef LIBPOSIX_INTERNAL
-	#define intmax_t posix_intmax_t
-	#define uintmax_t posix_uintmax_t
-#endif
-
-#endif /* POSIX_STDINT_H_ */
-
-/** @}
- */
Index: pace/lib/posix/stdio.c
===================================================================
--- uspace/lib/posix/stdio.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,807 +1,0 @@
-/*
- * 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.
- */
-
-#define LIBPOSIX_INTERNAL
-
-/* Has to be first. */
-#include "stdbool.h"
-
-#include "internal/common.h"
-#include "stdio.h"
-
-#include "assert.h"
-#include "errno.h"
-#include "stdlib.h"
-#include "string.h"
-#include "sys/types.h"
-#include "unistd.h"
-
-#include "libc/io/printf_core.h"
-#include "libc/str.h"
-#include "libc/malloc.h"
-#include "libc/adt/list.h"
-#include "libc/sys/stat.h"
-
-
-/* not the best of solutions, but freopen and ungetc will eventually
- * need to be implemented in libc anyway
- */
-#include "../c/generic/private/stdio.h"
-
-/** Clears the stream's error and end-of-file indicators.
- *
- * @param stream Stream whose indicators shall be cleared.
- */
-void posix_clearerr(FILE *stream)
-{
-	stream->error = 0;
-	stream->eof = 0;
-}
-
-/**
- * Generate a pathname for the controlling terminal.
- *
- * @param s Allocated buffer to which the pathname shall be put.
- * @return Either s or static location filled with the requested pathname.
- */
-char *posix_ctermid(char *s)
-{
-	/* Currently always returns an error value (empty string). */
-	// TODO: return a real terminal path
-
-	static char dummy_path[L_ctermid] = {'\0'};
-
-	if (s == NULL) {
-		return dummy_path;
-	}
-
-	s[0] = '\0';
-	return s;
-}
-
-/**
- * Put a string on the stream.
- * 
- * @param s String to be written.
- * @param stream Output stream.
- * @return Non-negative on success, EOF on failure.
- */
-int posix_fputs(const char *restrict s, FILE *restrict stream)
-{
-	int rc = fputs(s, stream);
-	if (rc == 0) {
-		return EOF;
-	} else {
-		return 0;
-	}
-}
-
-/**
- * Push byte back into input stream.
- * 
- * @param c Byte to be pushed back.
- * @param stream Stream to where the byte shall be pushed.
- * @return Provided byte on success or EOF if not possible.
- */
-int posix_ungetc(int c, FILE *stream)
-{
-	uint8_t b = (uint8_t) c;
-
-	bool can_unget =
-	    /* Provided character is legal. */
-	    c != EOF &&
-	    /* Stream is consistent. */
-	    !stream->error &&
-	    /* Stream is buffered. */
-	    stream->btype != _IONBF &&
-	    /* Last operation on the stream was a read operation. */
-	    stream->buf_state == _bs_read &&
-	    /* Stream buffer is already allocated (i.e. there was already carried
-	     * out either write or read operation on the stream). This is probably
-	     * redundant check but let's be safe. */
-	    stream->buf != NULL &&
-	    /* There is still space in the stream to retreat. POSIX demands the
-	     * possibility to unget at least 1 character. It should be always
-	     * possible, assuming the last operation on the stream read at least 1
-	     * character, because the buffer is refilled in the lazily manner. */
-	    stream->buf_tail > stream->buf;
-
-	if (can_unget) {
-		--stream->buf_tail;
-		stream->buf_tail[0] = b;
-		stream->eof = false;
-		return (int) b;
-	} else {
-		return EOF;
-	}
-}
-
-/**
- * Read a stream until the delimiter (or EOF) is encountered.
- *
- * @param lineptr Pointer to the output buffer in which there will be stored
- *     nul-terminated string together with the delimiter (if encountered).
- *     Will be resized if necessary.
- * @param n Pointer to the size of the output buffer. Will be increased if
- *     necessary.
- * @param delimiter Delimiter on which to finish reading the stream.
- * @param stream Input stream.
- * @return Number of fetched characters (including delimiter if encountered)
- *     or -1 on error (set in errno).
- */
-ssize_t posix_getdelim(char **restrict lineptr, size_t *restrict n,
-    int delimiter, FILE *restrict stream)
-{
-	/* Check arguments for sanity. */
-	if (!lineptr || !n) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	size_t alloc_step = 80; /* Buffer size gain during reallocation. */
-	char *pos = *lineptr; /* Next free byte of the output buffer. */
-	size_t cnt = 0; /* Number of fetched characters. */
-	int c = fgetc(stream); /* Current input character. Might be EOF. */
-
-	do {
-		/* Mask EOF as NUL to terminate string. */
-		if (c == EOF) {
-			c = '\0';
-		}
-
-		/* Ensure there is still space left in the buffer. */
-		if (pos == *lineptr + *n) {
-			*lineptr = realloc(*lineptr, *n + alloc_step);
-			if (*lineptr) {
-				pos = *lineptr + *n;
-				*n += alloc_step;
-			} else {
-				errno = ENOMEM;
-				return -1;
-			}
-		}
-
-		/* Store the fetched character. */
-		*pos = c;
-
-		/* Fetch the next character according to the current character. */
-		if (c != '\0') {
-			++pos;
-			++cnt;
-			if (c == delimiter) {
-				/* Delimiter was just stored. Provide EOF as the next
-				 * character - it will be masked as NUL and output string
-				 * will be properly terminated. */
-				c = EOF;
-			} else {
-				/* Neither delimiter nor EOF were encountered. Just fetch
-				 * the next character from the stream. */
-				c = fgetc(stream);
-			}
-		}
-	} while (c != '\0');
-
-	if (errno == EOK && cnt > 0) {
-		return cnt;
-	} else {
-		/* Either some error occured or the stream was already at EOF. */
-		return -1;
-	}
-}
-
-/**
- * Read a stream until the newline (or EOF) is encountered.
- * 
- * @param lineptr Pointer to the output buffer in which there will be stored
- *     nul-terminated string together with the delimiter (if encountered).
- *     Will be resized if necessary.
- * @param n Pointer to the size of the output buffer. Will be increased if
- *     necessary.
- * @param stream Input stream.
- * @return Number of fetched characters (including newline if encountered)
- *     or -1 on error (set in errno).
- */
-ssize_t posix_getline(char **restrict lineptr, size_t *restrict n,
-    FILE *restrict stream)
-{
-	return posix_getdelim(lineptr, n, '\n', stream);
-}
-
-/**
- * Reopen a file stream.
- * 
- * @param filename Pathname of a file to be reopened or NULL for changing
- *     the mode of the stream.
- * @param mode Mode to be used for reopening the file or changing current
- *     mode of the stream.
- * @param stream Current stream associated with the opened file.
- * @return On success, either a stream of the reopened file or the provided
- *     stream with a changed mode. NULL otherwise.
- */
-FILE *posix_freopen(const char *restrict filename, 
-    const char *restrict mode, FILE *restrict stream)
-{
-	assert(mode != NULL);
-	assert(stream != NULL);
-	
-	if (filename == NULL) {
-		/* POSIX allows this to be imlementation-defined. HelenOS currently
-		 * does not support changing the mode. */
-		// FIXME: handle mode change once it is supported
-		return stream;
-	}
-	
-	/* Open a new stream. */
-	FILE* new = fopen(filename, mode);
-	if (new == NULL) {
-		fclose(stream);
-		/* errno was set by fopen() */
-		return NULL;
-	}
-	
-	/* Close the original stream without freeing it (ignoring errors). */
-	if (stream->buf != NULL) {
-		fflush(stream);
-	}
-	if (stream->sess != NULL) {
-		async_hangup(stream->sess);
-	}
-	if (stream->fd >= 0) {
-		close(stream->fd);
-	}
-	list_remove(&stream->link);
-	
-	/* Move the new stream to the original location. */
-	memcpy(stream, new, sizeof (FILE));
-	free(new);
-	
-	/* Update references in the file list. */
-	stream->link.next->prev = &stream->link;
-	stream->link.prev->next = &stream->link;
-	
-	return stream;
-}
-
-/**
- * Write error messages to standard error.
- *
- * @param s Error message.
- */
-void posix_perror(const char *s)
-{
-	if (s == NULL || s[0] == '\0') {
-		fprintf(stderr, "%s\n", posix_strerror(errno));
-	} else {
-		fprintf(stderr, "%s: %s\n", s, posix_strerror(errno));
-	}
-}
-
-struct _posix_fpos {
-	off64_t offset;
-};
-
-/** Restores stream a to position previously saved with fgetpos().
- *
- * @param stream Stream to restore
- * @param pos Position to restore
- * @return Zero on success, non-zero (with errno set) on failure
- */
-int posix_fsetpos(FILE *stream, const posix_fpos_t *pos)
-{
-	return fseek(stream, pos->offset, SEEK_SET);
-}
-
-/** Saves the stream's position for later use by fsetpos().
- *
- * @param stream Stream to save
- * @param pos Place to store the position
- * @return Zero on success, non-zero (with errno set) on failure
- */
-int posix_fgetpos(FILE *restrict stream, posix_fpos_t *restrict pos)
-{
-	off64_t ret = ftell(stream);
-	if (ret != -1) {
-		pos->offset = ret;
-		return 0;
-	} else {
-		return -1;
-	}
-}
-
-/**
- * Reposition a file-position indicator in a stream.
- * 
- * @param stream Stream to seek in.
- * @param offset Direction and amount of bytes to seek.
- * @param whence From where to seek.
- * @return Zero on success, -1 otherwise.
- */
-int posix_fseek(FILE *stream, long offset, int whence)
-{
-	return fseek(stream, (off64_t) offset, whence);
-}
-
-/**
- * Reposition a file-position indicator in a stream.
- * 
- * @param stream Stream to seek in.
- * @param offset Direction and amount of bytes to seek.
- * @param whence From where to seek.
- * @return Zero on success, -1 otherwise.
- */
-int posix_fseeko(FILE *stream, posix_off_t offset, int whence)
-{
-	return fseek(stream, (off64_t) offset, whence);
-}
-
-/**
- * Discover current file offset in a stream.
- * 
- * @param stream Stream for which the offset shall be retrieved.
- * @return Current offset or -1 if not possible.
- */
-long posix_ftell(FILE *stream)
-{
-	return (long) ftell(stream);
-}
-
-/**
- * Discover current file offset in a stream.
- * 
- * @param stream Stream for which the offset shall be retrieved.
- * @return Current offset or -1 if not possible.
- */
-posix_off_t posix_ftello(FILE *stream)
-{
-	return (posix_off_t) ftell(stream);
-}
-
-/**
- * Discard prefetched data or write unwritten data.
- * 
- * @param stream Stream that shall be flushed.
- * @return Zero on success, EOF on failure.
- */
-int posix_fflush(FILE *stream)
-{
-	int rc = fflush(stream);
-	if (rc < 0) {
-		errno = -rc;
-		return EOF;
-	} else {
-		return 0;
-	}
-}
-
-/**
- * Print formatted output to the opened file.
- *
- * @param fildes File descriptor of the opened file.
- * @param format Format description.
- * @return Either the number of printed characters or negative value on error.
- */
-int posix_dprintf(int fildes, const char *restrict format, ...)
-{
-	va_list list;
-	va_start(list, format);
-	int result = posix_vdprintf(fildes, format, list);
-	va_end(list);
-	return result;
-}
-
-/**
- * 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)) != EOK) {
-			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 posix_vdprintf(int fildes, const char *restrict 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 posix_sprintf(char *s, const char *restrict format, ...)
-{
-	va_list list;
-	va_start(list, format);
-	int result = posix_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 posix_vsprintf(char *s, const char *restrict format, va_list ap)
-{
-	return vsnprintf(s, STR_NO_LIMIT, format, ap);
-}
-
-/**
- * Convert formatted input from the stream.
- * 
- * @param stream Input stream.
- * @param format Format description.
- * @return The number of converted output items or EOF on failure.
- */
-int posix_fscanf(FILE *restrict stream, const char *restrict format, ...)
-{
-	va_list list;
-	va_start(list, format);
-	int result = posix_vfscanf(stream, format, list);
-	va_end(list);
-	return result;
-}
-
-/**
- * Convert formatted input from the standard input.
- * 
- * @param format Format description.
- * @return The number of converted output items or EOF on failure.
- */
-int posix_scanf(const char *restrict format, ...)
-{
-	va_list list;
-	va_start(list, format);
-	int result = posix_vscanf(format, list);
-	va_end(list);
-	return result;
-}
-
-/**
- * Convert formatted input from the standard input.
- * 
- * @param format Format description.
- * @param arg Output items.
- * @return The number of converted output items or EOF on failure.
- */
-int posix_vscanf(const char *restrict format, va_list arg)
-{
-	return posix_vfscanf(stdin, format, arg);
-}
-
-/**
- * Convert formatted input from the string.
- * 
- * @param s Input string.
- * @param format Format description.
- * @return The number of converted output items or EOF on failure.
- */
-int posix_sscanf(const char *restrict s, const char *restrict format, ...)
-{
-	va_list list;
-	va_start(list, format);
-	int result = posix_vsscanf(s, format, list);
-	va_end(list);
-	return result;
-}
-
-/**
- * Acquire file stream for the thread.
- *
- * @param file File stream to lock.
- */
-void posix_flockfile(FILE *file)
-{
-	/* dummy */
-}
-
-/**
- * Acquire file stream for the thread (non-blocking).
- *
- * @param file File stream to lock.
- * @return Zero for success and non-zero if the lock cannot be acquired.
- */
-int posix_ftrylockfile(FILE *file)
-{
-	/* dummy */
-	return 0;
-}
-
-/**
- * Relinquish the ownership of the locked file stream.
- *
- * @param file File stream to unlock.
- */
-void posix_funlockfile(FILE *file)
-{
-	/* dummy */
-}
-
-/**
- * Get a byte from a stream (thread-unsafe).
- *
- * @param stream Input file stream.
- * @return Either read byte or EOF.
- */
-int posix_getc_unlocked(FILE *stream)
-{
-	return getc(stream);
-}
-
-/**
- * Get a byte from the standard input stream (thread-unsafe).
- *
- * @return Either read byte or EOF.
- */
-int posix_getchar_unlocked(void)
-{
-	return getchar();
-}
-
-/**
- * Put a byte on a stream (thread-unsafe).
- *
- * @param c Byte to output.
- * @param stream Output file stream.
- * @return Either written byte or EOF.
- */
-int posix_putc_unlocked(int c, FILE *stream)
-{
-	return putc(c, stream);
-}
-
-/**
- * Put a byte on the standard output stream (thread-unsafe).
- * 
- * @param c Byte to output.
- * @return Either written byte or EOF.
- */
-int posix_putchar_unlocked(int c)
-{
-	return putchar(c);
-}
-
-/**
- * Remove a file or directory.
- *
- * @param path Pathname of the file that shall be removed.
- * @return Zero on success, -1 (with errno set) otherwise.
- */
-int posix_remove(const char *path)
-{
-	struct stat st;
-	int rc = stat(path, &st);
-	
-	if (rc != EOK) {
-		errno = -rc;
-		return -1;
-	}
-	
-	if (st.is_directory) {
-		rc = rmdir(path);
-	} else {
-		rc = unlink(path);
-	}
-	
-	if (rc != EOK) {
-		errno = -rc;
-		return -1;
-	}
-	return 0;
-}
-
-/**
- * Rename a file or directory.
- *
- * @param old Old pathname.
- * @param new New pathname.
- * @return Zero on success, -1 (with errno set) otherwise.
- */
-int posix_rename(const char *old, const char *new)
-{
-	return errnify(rename, old, new);
-}
-
-/**
- * Get a unique temporary file name (obsolete).
- *
- * @param s Buffer for the file name. Must be at least L_tmpnam bytes long.
- * @return The value of s on success, NULL on failure.
- */
-char *posix_tmpnam(char *s)
-{
-	assert(L_tmpnam >= posix_strlen("/tmp/tnXXXXXX"));
-	
-	static char buffer[L_tmpnam + 1];
-	if (s == NULL) {
-		s = buffer;
-	}
-	
-	posix_strcpy(s, "/tmp/tnXXXXXX");
-	posix_mktemp(s);
-	
-	if (*s == '\0') {
-		/* Errno set by mktemp(). */
-		return NULL;
-	}
-	
-	return s;
-}
-
-/**
- * Get an unique temporary file name with additional constraints (obsolete).
- *
- * @param dir Path to directory, where the file should be created.
- * @param pfx Optional prefix up to 5 characters long.
- * @return Newly allocated unique path for temporary file. NULL on failure.
- */
-char *posix_tempnam(const char *dir, const char *pfx)
-{
-	/* Sequence number of the filename. */
-	static int seq = 0;
-	
-	size_t dir_len = posix_strlen(dir);
-	if (dir[dir_len - 1] == '/') {
-		dir_len--;
-	}
-	
-	size_t pfx_len = posix_strlen(pfx);
-	if (pfx_len > 5) {
-		pfx_len = 5;
-	}
-	
-	char *result = malloc(dir_len + /* slash*/ 1 +
-	    pfx_len + /* three-digit seq */ 3 + /* .tmp */ 4 + /* nul */ 1);
-	
-	if (result == NULL) {
-		errno = ENOMEM;
-		return NULL;
-	}
-	
-	char *res_ptr = result;
-	posix_strncpy(res_ptr, dir, dir_len);
-	res_ptr += dir_len;
-	posix_strncpy(res_ptr, pfx, pfx_len);
-	res_ptr += pfx_len;
-	
-	for (; seq < 1000; ++seq) {
-		snprintf(res_ptr, 8, "%03d.tmp", seq);
-		
-		int orig_errno = errno;
-		errno = 0;
-		/* Check if the file exists. */
-		if (posix_access(result, F_OK) == -1) {
-			if (errno == ENOENT) {
-				errno = orig_errno;
-				break;
-			} else {
-				/* errno set by access() */
-				return NULL;
-			}
-		}
-	}
-	
-	if (seq == 1000) {
-		free(result);
-		errno = EINVAL;
-		return NULL;
-	}
-	
-	return result;
-}
-
-/**
- * Create and open an unique temporary file.
- * The file is automatically removed when the stream is closed.
- *
- * @param dir Path to directory, where the file should be created.
- * @param pfx Optional prefix up to 5 characters long.
- * @return Newly allocated unique path for temporary file. NULL on failure.
- */
-FILE *posix_tmpfile(void)
-{
-	char filename[] = "/tmp/tfXXXXXX";
-	int fd = posix_mkstemp(filename);
-	if (fd == -1) {
-		/* errno set by mkstemp(). */
-		return NULL;
-	}
-	
-	/* Unlink the created file, so that it's removed on close(). */
-	posix_unlink(filename);
-	return fdopen(fd, "w+");
-}
-
-/** @}
- */
Index: pace/lib/posix/stdio.h
===================================================================
--- uspace/lib/posix/stdio.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,190 +1,0 @@
-/*
- * 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.
- */
-
-#ifndef POSIX_STDIO_H_
-#define POSIX_STDIO_H_
-
-#include "stddef.h"
-#include "unistd.h"
-#include "libc/stdio.h"
-#include "sys/types.h"
-#include "libc/stdarg.h"
-#include "limits.h"
-
-/* Identifying the Terminal */
-#undef L_ctermid
-#define L_ctermid PATH_MAX
-extern char *posix_ctermid(char *s);
-
-/* Error Recovery */
-extern void posix_clearerr(FILE *stream);
-
-/* Input/Output */
-#undef putc
-#define putc fputc
-extern int posix_fputs(const char *restrict s, FILE *restrict stream);
-#undef getc
-#define getc fgetc
-extern int posix_ungetc(int c, FILE *stream);
-extern ssize_t posix_getdelim(char **restrict lineptr, size_t *restrict n,
-    int delimiter, FILE *restrict stream);
-extern ssize_t posix_getline(char **restrict lineptr, size_t *restrict n,
-    FILE *restrict stream);
-
-/* Opening Streams */
-extern FILE *posix_freopen(const char *restrict filename,
-    const char *restrict mode, FILE *restrict stream);
-
-/* Error Messages */
-extern void posix_perror(const char *s);
-
-/* File Positioning */
-typedef struct _posix_fpos posix_fpos_t;
-extern int posix_fsetpos(FILE *stream, const posix_fpos_t *pos);
-extern int posix_fgetpos(FILE *restrict stream, posix_fpos_t *restrict pos);
-extern int posix_fseek(FILE *stream, long offset, int whence);
-extern int posix_fseeko(FILE *stream, posix_off_t offset, int whence);
-extern long posix_ftell(FILE *stream);
-extern posix_off_t posix_ftello(FILE *stream);
-
-/* Flushing Buffers */
-extern int posix_fflush(FILE *stream);
-
-/* Formatted Output */
-extern int posix_dprintf(int fildes, const char *restrict format, ...)
-    PRINTF_ATTRIBUTE(2, 3);
-extern int posix_vdprintf(int fildes, const char *restrict format, va_list ap);
-extern int posix_sprintf(char *restrict s, const char *restrict format, ...)
-    PRINTF_ATTRIBUTE(2, 3);
-extern int posix_vsprintf(char *restrict s, const char *restrict format, va_list ap);
-
-/* Formatted Input */
-extern int posix_fscanf(
-    FILE *restrict stream, const char *restrict format, ...);
-extern int posix_vfscanf(
-    FILE *restrict stream, const char *restrict format, va_list arg);
-extern int posix_scanf(const char *restrict format, ...);
-extern int posix_vscanf(const char *restrict format, va_list arg);
-extern int posix_sscanf(
-    const char *restrict s, const char *restrict format, ...);
-extern int posix_vsscanf(
-    const char *restrict s, const char *restrict format, va_list arg);
-
-/* File Locking */
-extern void posix_flockfile(FILE *file);
-extern int posix_ftrylockfile(FILE *file);
-extern void posix_funlockfile(FILE *file);
-extern int posix_getc_unlocked(FILE *stream);
-extern int posix_getchar_unlocked(void);
-extern int posix_putc_unlocked(int c, FILE *stream);
-extern int posix_putchar_unlocked(int c);
-
-/* Deleting Files */
-extern int posix_remove(const char *path);
-
-/* Renaming Files */
-extern int posix_rename(const char *old, const char *new);
-
-/* Temporary Files */
-#undef L_tmpnam
-#define L_tmpnam PATH_MAX
-extern char *posix_tmpnam(char *s);
-extern char *posix_tempnam(const char *dir, const char *pfx);
-extern FILE *posix_tmpfile(void);
-
-#ifndef LIBPOSIX_INTERNAL
-	/* DEBUG macro does not belong to POSIX stdio.h. Its unconditional
-	 * definition in the native stdio.h causes unexpected behaviour of
-	 * applications which uses their own DEBUG macro (e.g. debugging
-	 * output is printed even if not desirable). */
-	#undef DEBUG
-
-	#define ctermid posix_ctermid
-
-	#define clearerr posix_clearerr
-
-	#define fputs posix_fputs
-	#define ungetc posix_ungetc
-	#define getdelim posix_getdelim
-	#define getline posix_getline
-
-	#define freopen posix_freopen
-
-	#define perror posix_perror
-
-	#define fpos_t posix_fpos_t
-	#define fsetpos posix_fsetpos
-	#define fgetpos posix_fgetpos
-	#define fseek posix_fseek
-	#define fseeko posix_fseeko
-	#define ftell posix_ftell
-	#define ftello posix_ftello
-
-	#define fflush posix_fflush
-
-	#define dprintf posix_dprintf
-	#define vdprintf posix_vdprintf
-	#define sprintf posix_sprintf
-	#define vsprintf posix_vsprintf
-
-	#define fscanf posix_fscanf
-	#define vfscanf posix_vfscanf
-	#define vscanf posix_vscanf
-	#define scanf posix_scanf
-	#define sscanf posix_sscanf
-	#define vsscanf posix_vsscanf
-
-	#define flockfile posix_flockfile
-	#define ftrylockfile posix_ftrylockfile
-	#define funlockfile posix_funlockfile
-
-	#define getc_unlocked posix_getc_unlocked
-	#define getchar_unlocked posix_getchar_unlocked
-	#define putc_unlocked posix_putc_unlocked
-	#define putchar_unlocked posix_putchar_unlocked
-
-	#define remove posix_remove
-
-	#define rename posix_rename
-
-	#define tmpnam posix_tmpnam
-	#define tempnam posix_tempnam
-	#define tmpfile posix_tmpfile
-#endif
-
-#endif /* POSIX_STDIO_H_ */
-
-/** @}
- */
Index: pace/lib/posix/stdio/scanf.c
===================================================================
--- uspace/lib/posix/stdio/scanf.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,1339 +1,0 @@
-/*
- * 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 Implementation of the scanf backend.
- */
-
-#define LIBPOSIX_INTERNAL
-
-/* Must be first. */
-#include "../stdbool.h"
-
-#include "../assert.h"
-#include "../errno.h"
-
-#include "../stdio.h"
-#include "../stdlib.h"
-#include "../stddef.h"
-#include "../string.h"
-#include "../ctype.h"
-#include "../sys/types.h"
-
-#include "../internal/common.h"
-#include "../libc/malloc.h"
-
-/** Unified data type for possible data sources for scanf. */
-typedef union __data_source {
-	FILE *stream; /**< Input file stream. */
-	const char *string; /**< Input string. */
-} _data_source;
-
-/** Internal state of the input provider. */
-enum {
-	/** Partly constructed but not yet functional. */
-	_PROV_CONSTRUCTED,
-	/** Ready to serve any request. */
-	_PROV_READY,
-	/** Cursor is temporarily lent to the external entity. No action is
-	  * possible until the cursor is returned.  */
-	_PROV_CURSOR_LENT,
-};
-
-/** Universal abstraction over data input for scanf. */
-typedef struct __input_provider {
-	/** Source of data elements. */
-	_data_source source;
-	/** How many elements was already processed. */
-	int consumed;
-	/** How many elements was already fetched from the source. */
-	int fetched;
-	/** Elements are fetched from the source in batches (e.g. by getline())
-	  * to allow using strtol/strtod family even on streams. */
-	char *window;
-	/** Size of the current window. */
-	size_t window_size;
-	/** Points to the next element to be processed inside the current window. */
-	const char *cursor;
-	/** Internal state of the provider. */
-	int state;
-
-	/** Take control over data source. Finish initialization of the internal
-	  * structures (e.g. allocation of window). */
-	void (*capture)(struct __input_provider *);
-	/** Get a single element from the source and update the internal structures
-	  * accordingly (e.g. greedy update of the window). Return -1 if the
-	  * element cannot be obtained. */
-	int (*pop)(struct __input_provider *);
-	/** Undo the most recent not-undone pop operation. Might be necesarry to
-	  * flush current window and seek data source backwards. Return 0 if the
-	  * pop history is exhausted, non-zero on success. */
-	int (*undo)(struct __input_provider *);
-	/** Lend the cursor to the caller.  */
-	const char * (*borrow_cursor)(struct __input_provider *);
-	/** Take control over possibly incremented cursor and update the internal
-	  * structures if necessary. */
-	void (*return_cursor)(struct __input_provider *, const char *);
-	/** Release the control over the source. That is, synchronize any
-	  * fetched but non-consumed elements (e.g. by seeking) and destruct
-	  * internal structures (e.g. window deallocation). */
-	void (*release)(struct __input_provider *);
-} _input_provider;
-
-/** @see __input_provider */
-static void _capture_stream(_input_provider *self)
-{
-	assert(self->source.stream);
-	assert(self->state == _PROV_CONSTRUCTED);
-	/* Caller could already pre-allocated the window. */
-	assert((self->window == NULL && self->window_size == 0) ||
-	    (self->window && self->window_size > 0));
-
-	/* Initialize internal structures. */
-	self->consumed = 0;
-	ssize_t fetched = posix_getline(
-	    &self->window, &self->window_size, self->source.stream);
-	if (fetched != -1) {
-		self->fetched = fetched;
-		self->cursor = self->window;
-	} else {
-		/* EOF encountered. */
-		self->fetched = 0;
-		self->cursor = NULL;
-	}
-	self->state = _PROV_READY;
-}
-
-/** @see __input_provider */
-static void _capture_string(_input_provider *self)
-{
-	assert(self->source.string);
-	assert(self->state == _PROV_CONSTRUCTED);
-
-	/* Initialize internal structures. */
-	self->consumed = 0;
-	self->fetched = posix_strlen(self->source.string);
-	self->window = (char *) self->source.string;
-	self->window_size = self->fetched + 1;
-	self->cursor = self->window;
-	self->state = _PROV_READY;
-}
-
-/** @see __input_provider */
-static int _pop_stream(_input_provider *self)
-{
-	assert(self->state == _PROV_READY);
-
-	if (self->cursor) {
-		int c = *self->cursor;
-		++self->consumed;
-		++self->cursor;
-		/* Do we need to fetch a new line from the source? */
-		if (*self->cursor == '\0') {
-			ssize_t fetched = posix_getline(&self->window,
-			    &self->window_size, self->source.stream);
-			if (fetched != -1) {
-				self->fetched += fetched;
-				self->cursor = self->window;
-			} else {
-				/* EOF encountered. */
-				self->cursor = NULL;
-			}
-		}
-		return c;
-	} else {
-		/* Already at EOF. */
-		return -1;
-	}
-}
-
-/** @see __input_provider */
-static int _pop_string(_input_provider *self)
-{
-	assert(self->state == _PROV_READY);
-
-	if (*self->cursor != '\0') {
-		int c = *self->cursor;
-		++self->consumed;
-		++self->cursor;
-		return c;
-	} else {
-		/* String depleted. */
-		return -1;
-	}
-}
-
-/** @see __input_provider */
-static int _undo_stream(_input_provider *self)
-{
-	assert(self->state == _PROV_READY);
-
-	if (self->consumed == 0) {
-		/* Undo history exhausted. */
-		return 0;
-	}
-
-	if (!self->cursor || self->window == self->cursor) {
-		/* Complex case. Either at EOF (cursor == NULL) or there is no more
-		 * place to retreat to inside the window. Seek the source backwards
-		 * and flush the window. Regarding the scanf, this could happend only
-		 * when matching unbounded string (%s) or unbounded scanset (%[) not
-		 * containing newline, while at the same time newline is the character
-		 * that breaks the matching process. */
-		int rc = posix_fseek(
-		    self->source.stream, -1, SEEK_CUR);
-		if (rc == -1) {
-			/* Seek failed.  */
-			return 0;
-		}
-		ssize_t fetched = posix_getline(&self->window,
-		    &self->window_size, self->source.stream);
-		if (fetched != -1) {
-			assert(fetched == 1);
-			self->fetched = self->consumed + 1;
-			self->cursor = self->window;
-		} else {
-			/* Stream is broken. */
-			return 0;
-		}
-	} else {
-		/* Simple case. Still inside window. */
-		--self->cursor;
-	}
-	--self->consumed;
-	return 1; /* Success. */
-}
-
-/** @see __input_provider */
-static int _undo_string(_input_provider *self)
-{
-	assert(self->state == _PROV_READY);
-
-	if (self->consumed > 0) {
-		--self->consumed;
-		--self->cursor;
-	} else {
-		/* Undo history exhausted. */
-		return 0;
-	}
-	return 1; /* Success. */
-}
-
-/** @see __input_provider */
-static const char *_borrow_cursor_universal(_input_provider *self)
-{
-	assert(self->state == _PROV_READY);
-
-	self->state = _PROV_CURSOR_LENT;
-	return self->cursor;
-}
-
-/** @see __input_provider */
-static void _return_cursor_stream(_input_provider *self, const char *cursor)
-{
-	assert(self->state == _PROV_CURSOR_LENT);
-
-	/* Check how much of the window did external entity consumed. */
-	self->consumed += cursor - self->cursor;
-	self->cursor = cursor;
-	if (*self->cursor == '\0') {
-		/* Window was completely consumed, fetch new data. */
-		ssize_t fetched = posix_getline(&self->window,
-		    &self->window_size, self->source.stream);
-		if (fetched != -1) {
-			self->fetched += fetched;
-			self->cursor = self->window;
-		} else {
-			/* EOF encountered. */
-			self->cursor = NULL;
-		}
-	}
-	self->state = _PROV_READY;
-}
-
-/** @see __input_provider */
-static void _return_cursor_string(_input_provider *self, const char *cursor)
-{
-	assert(self->state == _PROV_CURSOR_LENT);
-
-	/* Check how much of the window did external entity consumed. */
-	self->consumed += cursor - self->cursor;
-	self->cursor = cursor;
-	self->state = _PROV_READY;
-}
-
-/** @see __input_provider */
-static void _release_stream(_input_provider *self)
-{
-	assert(self->state == _PROV_READY);
-	assert(self->consumed >= self->fetched);
-
-	/* Try to correct the difference between the stream position and what was
-	 * actually consumed. If it is not possible, continue anyway. */
-	posix_fseek(self->source.stream, self->consumed - self->fetched, SEEK_CUR);
-
-	/* Destruct internal structures. */
-	self->fetched = 0;
-	self->cursor = NULL;
-	if (self->window) {
-		free(self->window);
-		self->window = NULL;
-	}
-	self->window_size = 0;
-	self->state = _PROV_CONSTRUCTED;
-}
-
-/** @see __input_provider */
-static void _release_string(_input_provider *self)
-{
-	assert(self->state == _PROV_READY);
-
-	/* Destruct internal structures. */
-	self->fetched = 0;
-	self->cursor = NULL;
-	self->window = NULL;
-	self->window_size = 0;
-	self->state = _PROV_CONSTRUCTED;
-}
-
-/** Length modifier values. */
-enum {
-	LMOD_NONE,
-	LMOD_hh,
-	LMOD_h,
-	LMOD_l,
-	LMOD_ll,
-	LMOD_j,
-	LMOD_z,
-	LMOD_t,
-	LMOD_L,
-	LMOD_p, /* Reserved for %p conversion. */
-};
-
-/**
- * Decides whether provided characters specify length modifier. If so, the
- * recognized modifier is stored through provider pointer.
- *
- * @param c Candidate on the length modifier.
- * @param _c Next character (might be NUL).
- * @param modifier Pointer to the modifier value.
- * @return Whether the modifier was recognized or not.
- */
-static inline int is_length_mod(int c, int _c, int *modifier)
-{
-	assert(modifier);
-
-	switch (c) {
-	case 'h':
-		/* Check whether the modifier was not already recognized. */
-		if (*modifier == LMOD_NONE) {
-			*modifier = _c == 'h' ? LMOD_hh : LMOD_h;
-		} else {
-			/* Format string is invalid. Notify the caller. */
-			*modifier = LMOD_NONE;
-		}
-		return 1;
-	case 'l':
-		if (*modifier == LMOD_NONE) {
-			*modifier = _c == 'l' ? LMOD_ll : LMOD_l;
-		} else {
-			*modifier = LMOD_NONE;
-		}
-		return 1;
-	case 'j':
-		*modifier = *modifier == LMOD_NONE ? LMOD_j : LMOD_NONE;
-		return 1;
-	case 'z':
-		*modifier = *modifier == LMOD_NONE ? LMOD_z : LMOD_NONE;
-		return 1;
-	case 't':
-		*modifier = *modifier == LMOD_NONE ? LMOD_t : LMOD_NONE;
-		return 1;
-	case 'L':
-		*modifier = *modifier == LMOD_NONE ? LMOD_L : LMOD_NONE;
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-/**
- * Decides whether provided character specifies integer conversion. If so, the
- * semantics of the conversion is stored through provided pointers..
- * 
- * @param c Candidate on the integer conversion.
- * @param is_unsigned Pointer to store whether the conversion is signed or not.
- * @param base Pointer to store the base of the integer conversion.
- * @return Whether the conversion was recognized or not.
- */
-static inline int is_int_conv(int c, bool *is_unsigned, int *base)
-{
-	assert(is_unsigned && base);
-
-	switch (c) {
-	case 'd':
-		*is_unsigned = false;
-		*base = 10;
-		return 1;
-	case 'i':
-		*is_unsigned = false;
-		*base = 0;
-		return 1;
-	case 'o':
-		*is_unsigned = true;
-		*base = 8;
-		return 1;
-	case 'u':
-		*is_unsigned = true;
-		*base = 10;
-		return 1;
-	case 'p': /* According to POSIX, %p modifier is implementation defined but
-			   * must correspond to its printf counterpart. */
-	case 'x':
-	case 'X':
-		*is_unsigned = true;
-		*base = 16;
-		return 1;
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-/**
- * Decides whether provided character specifies conversion of the floating
- * point number.
- *
- * @param c Candidate on the floating point conversion.
- * @return Whether the conversion was recognized or not.
- */
-static inline int is_float_conv(int c)
-{
-	switch (c) {
-	case 'a':
-	case 'A':
-	case 'e':
-	case 'E':
-	case 'f':
-	case 'F':
-	case 'g':
-	case 'G':
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-/**
- * Decides whether provided character specifies conversion of the character
- * sequence.
- *
- * @param c Candidate on the character sequence conversion.
- * @param modifier Pointer to store length modifier for wide chars.
- * @return Whether the conversion was recognized or not.
- */
-static inline int is_seq_conv(int c, int *modifier)
-{
-	assert(modifier);
-	
-	switch (c) {
-	case 'S':
-		*modifier = LMOD_l;
-		/* fallthrough */
-	case 's':
-		return 1;
-	case 'C':
-		*modifier = LMOD_l;
-		/* fallthrough */
-	case 'c':
-		return 1;
-	case '[':
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-/**
- * Backend for the whole family of scanf functions. Uses input provider
- * to abstract over differences between strings and streams. Should be
- * POSIX compliant (apart from the not supported stuff).
- *
- * NOT SUPPORTED: locale (see strtold), wide chars, numbered output arguments
- * 
- * @param in Input provider.
- * @param fmt Format description.
- * @param arg Output arguments.
- * @return The number of converted output items or EOF on failure.
- */
-static inline int _internal_scanf(
-    _input_provider *in, const char *restrict fmt, va_list arg)
-{
-	int c = -1;
-	int converted_cnt = 0;
-	bool converting = false;
-	bool matching_failure = false;
-
-	bool assign_supress = false;
-	bool assign_alloc = false;
-	long width = -1;
-	int length_mod = LMOD_NONE;
-	bool int_conv_unsigned = false;
-	int int_conv_base = 0;
-
-	/* Buffers allocated by scanf for optional 'm' specifier must be remembered
-	 * to deallocaate them in case of an error. Because each of those buffers
-	 * corresponds to one of the argument from va_list, there is an upper bound
-	 * on the number of those arguments. In case of C99, this uppper bound is
-	 * 127 arguments. */
-	char *buffers[127];
-	for (int i = 0; i < 127; ++i) {
-		buffers[i] = NULL;
-	}
-	int next_unused_buffer_idx = 0;
-
-	in->capture(in);
-
-	/* Interpret format string. Control shall prematurely jump from the cycle
-	 * on input failure, matching failure or illegal format string. In order
-	 * to keep error reporting simple enough and to keep input consistent,
-	 * error condition shall be always manifested as jump from the cycle,
-	 * not function return. Format string pointer shall be updated specifically
-	 * for each sub-case (i.e. there shall be no loop-wide increment).*/
-	while (*fmt) {
-
-		if (converting) {
-
-			/* Processing inside conversion specifier. Either collect optional
-			 * parameters or execute the conversion. When the conversion
-			 * is successfully completed, increment conversion count and switch
-			 * back to normal mode. */
-			if (*fmt == '*') {
-				/* Assignment-supression (optional). */
-				if (assign_supress) {
-					/* Already set. Illegal format string. */
-					break;
-				}
-				assign_supress = true;
-				++fmt;
-			} else if (*fmt == 'm') {
-				/* Assignment-allocation (optional). */
-				if (assign_alloc) {
-					/* Already set. Illegal format string. */
-					break;
-				}
-				assign_alloc = true;
-				++fmt;
-			} else if (*fmt == '$') {
-				/* Reference to numbered output argument. */
-				// TODO
-				not_implemented();
-			} else if (isdigit(*fmt)) {
-				/* Maximum field length (optional). */
-				if (width != -1) {
-					/* Already set. Illegal format string. */
-					break;
-				}
-				char *fmt_new = NULL;
-				width = posix_strtol(fmt, &fmt_new, 10);
-				if (width != 0) {
-					fmt = fmt_new;
-				} else {
-					/* Since POSIX requires width to be non-zero, it is
-					 * sufficient to interpret zero width as error without
-					 * referring to errno. */
-					break;
-				}
-			} else if (is_length_mod(*fmt, *(fmt + 1), &length_mod)) {
-				/* Length modifier (optional). */
-				if (length_mod == LMOD_NONE) {
-					/* Already set. Illegal format string. The actual detection
-					 * is carried out in the is_length_mod(). */
-					break;
-				}
-				if (length_mod == LMOD_hh || length_mod == LMOD_ll) {
-					/* Modifier was two characters long. */
-					++fmt;
-				}
-				++fmt;
-			} else if (is_int_conv(*fmt, &int_conv_unsigned, &int_conv_base)) {
-				/* Integer conversion. */
-
-				/* Check sanity of optional parts of conversion specifier. */
-				if (assign_alloc || length_mod == LMOD_L) {
-					/* Illegal format string. */
-					break;
-				}
-
-				/* Conversion of the integer with %p specifier needs special
-				 * handling, because it is not allowed to have arbitrary
-				 * length modifier.  */
-				if (*fmt == 'p') {
-					if (length_mod == LMOD_NONE) {
-						length_mod = LMOD_p;
-					} else {
-						/* Already set. Illegal format string. */
-						break;
-					}
-				}
-
-				/* First consume any white spaces, so we can borrow cursor
-				 * from the input provider. This way, the cursor will either
-				 * point to the non-white space while the input will be
-				 * prefetched up to the newline (which is suitable for strtol),
-				 * or the input will be at EOF. */
-				do {
-					c = in->pop(in);
-				} while (isspace(c));
-
-				/* After skipping the white spaces, can we actually continue? */
-				if (c == -1) {
-					/* Input failure. */
-					break;
-				} else {
-					/* Everything is OK, just undo the last pop, so the cursor
-					 * can be borrowed. */
-					in->undo(in);
-				}
-
-				const char *cur_borrowed = NULL;
-				const char *cur_limited = NULL;
-				char *cur_updated = NULL;
-
-				/* Borrow the cursor. Until it is returned to the provider
-				 * we cannot jump from the cycle, because it would leave
-				 * the input inconsistent. */
-				cur_borrowed = in->borrow_cursor(in);
-
-				/* If the width is limited, the cursor horizont must be
-				 * decreased accordingly. Otherwise the strtol could read more
-				 * than allowed by width. */
-				if (width != -1) {
-					cur_limited = posix_strndup(cur_borrowed, width);
-				} else {
-					cur_limited = cur_borrowed;
-				}
-				cur_updated = (char *) cur_limited;
-
-				long long sres = 0;
-				unsigned long long ures = 0;
-				errno = 0; /* Reset errno to recognize error later. */
-				/* Try to convert the integer. */
-				if (int_conv_unsigned) {
-					ures = posix_strtoull(cur_limited, &cur_updated, int_conv_base);
-				} else {
-					sres = posix_strtoll(cur_limited, &cur_updated, int_conv_base);
-				}
-
-				/* Update the cursor so it can be returned to the provider. */
-				cur_borrowed += cur_updated - cur_limited;
-				if (width != -1 && cur_limited != NULL) {
-					/* Deallocate duplicated part of the cursor view. */
-					free(cur_limited);
-				}
-				cur_limited = NULL;
-				cur_updated = NULL;
-				/* Return the cursor to the provider. Input consistency is again
-				 * the job of the provider, so we can report errors from
-				 * now on. */
-				in->return_cursor(in, cur_borrowed);
-				cur_borrowed = NULL;
-
-				/* Check whether the conversion was successful. */
-				if (errno != EOK) {
-					matching_failure = true;
-					break;
-				}
-
-				/* If not supressed, assign the converted integer into
-				 * the next output argument. */
-				if (!assign_supress) {
-					if (int_conv_unsigned) {
-						switch (length_mod) {
-						case LMOD_hh: ; /* Label cannot be part of declaration. */
-							unsigned char *phh = va_arg(arg, unsigned char *);
-							*phh = (unsigned char) ures;
-							break;
-						case LMOD_h: ;
-							unsigned short *ph = va_arg(arg, unsigned short *);
-							*ph = (unsigned short) ures;
-							break;
-						case LMOD_NONE: ;
-							unsigned *pdef = va_arg(arg, unsigned *);
-							*pdef = (unsigned) ures;
-							break;
-						case LMOD_l: ;
-							unsigned long *pl = va_arg(arg, unsigned long *);
-							*pl = (unsigned long) ures;
-							break;
-						case LMOD_ll: ;
-							unsigned long long *pll = va_arg(arg, unsigned long long *);
-							*pll = (unsigned long long) ures;
-							break;
-						case LMOD_j: ;
-							posix_uintmax_t *pj = va_arg(arg, posix_uintmax_t *);
-							*pj = (posix_uintmax_t) ures;
-							break;
-						case LMOD_z: ;
-							size_t *pz = va_arg(arg, size_t *);
-							*pz = (size_t) ures;
-							break;
-						case LMOD_t: ;
-							// XXX: What is unsigned counterpart of the ptrdiff_t?
-							size_t *pt = va_arg(arg, size_t *);
-							*pt = (size_t) ures;
-							break;
-						case LMOD_p: ;
-							void **pp = va_arg(arg, void **);
-							*pp = (void *) (uintptr_t) ures;
-							break;
-						default:
-							assert(false);
-						}
-					} else {
-						switch (length_mod) {
-						case LMOD_hh: ; /* Label cannot be part of declaration. */
-							signed char *phh = va_arg(arg, signed char *);
-							*phh = (signed char) sres;
-							break;
-						case LMOD_h: ;
-							short *ph = va_arg(arg, short *);
-							*ph = (short) sres;
-							break;
-						case LMOD_NONE: ;
-							int *pdef = va_arg(arg, int *);
-							*pdef = (int) sres;
-							break;
-						case LMOD_l: ;
-							long *pl = va_arg(arg, long *);
-							*pl = (long) sres;
-							break;
-						case LMOD_ll: ;
-							long long *pll = va_arg(arg, long long *);
-							*pll = (long long) sres;
-							break;
-						case LMOD_j: ;
-							posix_intmax_t *pj = va_arg(arg, posix_intmax_t *);
-							*pj = (posix_intmax_t) sres;
-							break;
-						case LMOD_z: ;
-							ssize_t *pz = va_arg(arg, ssize_t *);
-							*pz = (ssize_t) sres;
-							break;
-						case LMOD_t: ;
-							posix_ptrdiff_t *pt = va_arg(arg, posix_ptrdiff_t *);
-							*pt = (posix_ptrdiff_t) sres;
-							break;
-						default:
-							assert(false);
-						}
-					}
-					++converted_cnt;
-				}
-
-				converting = false;
-				++fmt;
-			} else if (is_float_conv(*fmt)) {
-				/* Floating point number conversion. */
-
-				/* Check sanity of optional parts of conversion specifier. */
-				if (assign_alloc) {
-					/* Illegal format string. */
-					break;
-				}
-				if (length_mod != LMOD_NONE &&
-				    length_mod != LMOD_l &&
-				    length_mod != LMOD_L) {
-					/* Illegal format string. */
-					break;
-				}
-
-				/* First consume any white spaces, so we can borrow cursor
-				 * from the input provider. This way, the cursor will either
-				 * point to the non-white space while the input will be
-				 * prefetched up to the newline (which is suitable for strtof),
-				 * or the input will be at EOF. */
-				do {
-					c = in->pop(in);
-				} while (isspace(c));
-
-				/* After skipping the white spaces, can we actually continue? */
-				if (c == -1) {
-					/* Input failure. */
-					break;
-				} else {
-					/* Everything is OK, just undo the last pop, so the cursor
-					 * can be borrowed. */
-					in->undo(in);
-				}
-
-				const char *cur_borrowed = NULL;
-				const char *cur_limited = NULL;
-				char *cur_updated = NULL;
-
-				/* Borrow the cursor. Until it is returned to the provider
-				 * we cannot jump from the cycle, because it would leave
-				 * the input inconsistent. */
-				cur_borrowed = in->borrow_cursor(in);
-
-				/* If the width is limited, the cursor horizont must be
-				 * decreased accordingly. Otherwise the strtof could read more
-				 * than allowed by width. */
-				if (width != -1) {
-					cur_limited = posix_strndup(cur_borrowed, width);
-				} else {
-					cur_limited = cur_borrowed;
-				}
-				cur_updated = (char *) cur_limited;
-
-				float fres = 0.0;
-				double dres = 0.0;
-				long double ldres = 0.0;
-				errno = 0; /* Reset errno to recognize error later. */
-				/* Try to convert the floating point nubmer. */
-				switch (length_mod) {
-				case LMOD_NONE:
-					fres = posix_strtof(cur_limited, &cur_updated);
-					break;
-				case LMOD_l:
-					dres = posix_strtod(cur_limited, &cur_updated);
-					break;
-				case LMOD_L:
-					ldres = posix_strtold(cur_limited, &cur_updated);
-					break;
-				default:
-					assert(false);
-				}
-
-				/* Update the cursor so it can be returned to the provider. */
-				cur_borrowed += cur_updated - cur_limited;
-				if (width != -1 && cur_limited != NULL) {
-					/* Deallocate duplicated part of the cursor view. */
-					free(cur_limited);
-				}
-				cur_limited = NULL;
-				cur_updated = NULL;
-				/* Return the cursor to the provider. Input consistency is again
-				 * the job of the provider, so we can report errors from
-				 * now on. */
-				in->return_cursor(in, cur_borrowed);
-				cur_borrowed = NULL;
-
-				/* Check whether the conversion was successful. */
-				if (errno != EOK) {
-					matching_failure = true;
-					break;
-				}
-
-				/* If nto supressed, assign the converted floating point number
-				 * into the next output argument. */
-				if (!assign_supress) {
-					switch (length_mod) {
-					case LMOD_NONE: ; /* Label cannot be part of declaration. */
-						float *pf = va_arg(arg, float *);
-						*pf = fres;
-						break;
-					case LMOD_l: ;
-						double *pd = va_arg(arg, double *);
-						*pd = dres;
-						break;
-					case LMOD_L: ;
-						long double *pld = va_arg(arg, long double *);
-						*pld = ldres;
-						break;
-					default:
-						assert(false);
-					}
-					++converted_cnt;
-				}
-
-				converting = false;
-				++fmt;
-			} else if (is_seq_conv(*fmt, &length_mod)) {
-				/* Character sequence conversion. */
-				
-				/* Check sanity of optional parts of conversion specifier. */
-				if (length_mod != LMOD_NONE &&
-				    length_mod != LMOD_l) {
-					/* Illegal format string. */
-					break;
-				}
-
-				if (length_mod == LMOD_l) {
-					/* Wide chars not supported. */
-					// TODO
-					not_implemented();
-				}
-
-				int term_size = 1; /* Size of the terminator (0 or 1)). */
-				if (*fmt == 'c') {
-					term_size = 0;
-					width = width == -1 ? 1 : width;
-				}
-
-				if (*fmt == 's') {
-					/* Skip white spaces. */
-					do {
-						c = in->pop(in);
-					} while (isspace(c));
-				} else {
-					/* Fetch a single character. */
-					c = in->pop(in);
-				}
-
-				/* Check whether there is still input to read. */
-				if (c == -1) {
-					/* Input failure. */
-					break;
-				}
-
-				/* Prepare scanset. */
-				char terminate_on[256];
-				for (int i = 0; i < 256; ++i) {
-					terminate_on[i] = 0;
-				}
-				if (*fmt == 'c') {
-					++fmt;
-				} else if (*fmt == 's') {
-					terminate_on[' '] = 1;
-					terminate_on['\n'] = 1;
-					terminate_on['\t'] = 1;
-					terminate_on['\f'] = 1;
-					terminate_on['\r'] = 1;
-					terminate_on['\v'] = 1;
-					++fmt;
-				} else {
-					assert(*fmt == '[');
-					bool not = false;
-					bool dash = false;
-					++fmt;
-					/* Check for negation. */
-					if (*fmt == '^') {
-						not = true;
-						++fmt;
-					}
-					/* Check for escape sequences. */
-					if (*fmt == '-' || *fmt == ']') {
-						terminate_on[(int) *fmt] = 1;
-						++fmt;
-					}
-					/* Check for ordinary characters and ranges. */
-					while (*fmt != '\0' && *fmt != ']') {
-						if (dash) {
-							for (char chr = *(fmt - 2); chr <= *fmt; ++chr) {
-								terminate_on[(int) chr] = 1;
-							}
-							dash = false;
-						} else if (*fmt == '-') {
-							dash = true;
-						} else {
-							terminate_on[(int) *fmt] = 1;
-						}
-						++fmt;
-					}
-					/* Check for escape sequence. */
-					if (dash == true) {
-						terminate_on['-'] = 1;
-					}
-					/* Check whether the specifier was correctly terminated.*/
-					if (*fmt == '\0') {
-						/* Illegal format string. */
-						break;
-					} else {
-						++fmt;
-					}
-					/* Inverse the scanset if necessary. */
-					if (not == false) {
-						for (int i = 0; i < 256; ++i) {
-							terminate_on[i] = terminate_on[i] ? 0 : 1;
-						}
-					}
-				}
-
-				char * buf = NULL;
-				size_t buf_size = 0;
-				char * cur = NULL;
-				size_t alloc_step = 80; /* Buffer size gain during reallocation. */
-				int my_buffer_idx = 0;
-
-				/* Retrieve the buffer into which popped characters
-				 * will be stored. */
-				if (!assign_supress) {
-					if (assign_alloc) {
-						/* We must allocate our own buffer. */
-						buf_size =
-						    width == -1 ? alloc_step : (size_t) width + term_size;
-						buf = malloc(buf_size);
-						if (!buf) {
-							/* No memory. */
-							break;
-						}
-						my_buffer_idx = next_unused_buffer_idx;
-						++next_unused_buffer_idx;
-						buffers[my_buffer_idx] = buf;
-						cur = buf;
-					} else {
-						/* Caller provided its buffer. */
-						buf = va_arg(arg, char *);
-						cur = buf;
-						buf_size =
-						    width == -1 ? SIZE_MAX : (size_t) width + term_size;
-					}
-				}
-
-				/* Match the string. The next character is already popped. */
-				while ((width == -1 || width > 0) && c != -1 && !terminate_on[c]) {
-
-					/* Check whether the buffer is still sufficiently large. */
-					if (!assign_supress) {
-						/* Always reserve space for the null terminator. */
-						if (cur == buf + buf_size - term_size) {
-							/* Buffer size must be increased. */
-							buf = realloc(buf, buf_size + alloc_step);
-							if (buf) {
-								buffers[my_buffer_idx] = buf;
-								cur = buf + buf_size - term_size;
-								buf_size += alloc_step;
-							} else {
-								/* Break just from this tight loop. Errno will
-								 * be checked after it. */
-								break;
-							}
-						}
-						/* Store the input character. */
-						*cur = c;
-					}
-
-					width = width == -1 ? -1 : width - 1;
-					++cur;
-					c = in->pop(in);
-				}
-				if (errno == ENOMEM) {
-					/* No memory. */
-					break;
-				}
-				if (c != -1) {
-					/* There is still more input, so undo the last pop. */
-					in->undo(in);
-				}
-
-				/* Check for failures. */
-				if (cur == buf) {
-					/* Matching failure. Input failure was already checked
-					 * earlier. */
-					matching_failure = true;
-					if (!assign_supress && assign_alloc) {
-						/* Roll back. */
-						free(buf);
-						buffers[my_buffer_idx] = NULL;
-						--next_unused_buffer_idx;
-					}
-					break;
-				}
-
-				/* Store the terminator. */
-				if (!assign_supress && term_size > 0) {
-					/* Space for the terminator was reserved. */
-					*cur = '\0';
-				}
-
-				/* Store the result if not already stored. */
-				if (!assign_supress) {
-					if (assign_alloc) {
-						char **pbuf = va_arg(arg, char **);
-						*pbuf = buf;
-					}
-					++converted_cnt;
-				}
-				
-				converting = false;
-				/* Format string pointer already incremented. */
-			} else if (*fmt == 'n') {
-				/* Report the number of consumed bytes so far. */
-
-				/* Sanity check. */
-				bool sane =
-				    width == -1 &&
-				    length_mod == LMOD_NONE &&
-				    assign_alloc == false &&
-				    assign_supress == false;
-
-				if (sane) {
-					int *pi = va_arg(arg, int *);
-					*pi = in->consumed;
-				} else {
-					/* Illegal format string. */
-					break;
-				}
-
-				/* This shall not be counted as conversion. */
-				converting = false;
-				++fmt;
-			} else {
-				/* Illegal format string. */
-				break;
-			}
-			
-		} else {
-
-			/* Processing outside conversion specifier. Either skip white
-			 * spaces or match characters one by one. If conversion specifier
-			 * is detected, switch to coversion mode. */
-			if (isspace(*fmt)) {
-				/* Skip white spaces in the format string. */
-				while (isspace(*fmt)) {
-					++fmt;
-				}
-				/* Skip white spaces in the input. */
-				do {
-					c = in->pop(in);
-				} while (isspace(c));
-				if (c != -1) {
-					/* Input is not at EOF, so undo the last pop operation. */
-					in->undo(in);
-				}
-			} else if (*fmt == '%' && *(fmt + 1) != '%') {
-				/* Conversion specifier detected. Switch modes. */
-				converting = true;
-				/* Reset the conversion context. */
-				assign_supress = false;
-				assign_alloc = false;
-				width = -1;
-				length_mod = LMOD_NONE;
-				int_conv_unsigned = false;
-				int_conv_base = 0;
-				++fmt;
-			} else {
-				/* One by one matching. */
-				if (*fmt == '%') {
-					/* Escape sequence detected. */
-					++fmt;
-					assert(*fmt == '%');
-				}
-				c = in->pop(in);
-				if (c == -1) {
-					/* Input failure. */
-					break;
-				} else if (c != *fmt) {
-					/* Matching failure. */
-					in->undo(in);
-					matching_failure = true;
-					break;
-				} else {
-					++fmt;
-				}
-			}
-			
-		}
-
-	}
-
-	in->release(in);
-
-	/* This somewhat complicated return value decision is required by POSIX. */
-	int rc;
-	if (matching_failure) {
-		rc = converted_cnt;
-	} else {
-		if (errno == EOK) {
-			rc = converted_cnt > 0 ? converted_cnt : EOF;
-		} else {
-			rc = EOF;
-		}
-	}
-	if (rc == EOF) {
-		/* Caller will not know how many arguments were successfully converted,
-		 * so the deallocation of buffers is our responsibility. */
-		for (int i = 0; i < next_unused_buffer_idx; ++i) {
-			free(buffers[i]);
-			buffers[i] = NULL;
-		}
-		next_unused_buffer_idx = 0;
-	}
-	return rc;
-}
-
-/**
- * Convert formatted input from the stream.
- *
- * @param stream Input stream.
- * @param format Format description.
- * @param arg Output items.
- * @return The number of converted output items or EOF on failure.
- */
-int posix_vfscanf(
-    FILE *restrict stream, const char *restrict format, va_list arg)
-{
-	_input_provider provider = {
-	    { 0 }, 0, 0, NULL, 0, NULL, _PROV_CONSTRUCTED,
-	    _capture_stream, _pop_stream, _undo_stream,
-	    _borrow_cursor_universal, _return_cursor_stream, _release_stream
-	};
-	provider.source.stream = stream;
-	return _internal_scanf(&provider, format, arg);
-}
-
-/**
- * Convert formatted input from the string.
- *
- * @param s Input string.
- * @param format Format description.
- * @param arg Output items.
- * @return The number of converted output items or EOF on failure.
- */
-int posix_vsscanf(
-    const char *restrict s, const char *restrict format, va_list arg)
-{
-	_input_provider provider = {
-	    { 0 }, 0, 0, NULL, 0, NULL, _PROV_CONSTRUCTED,
-	    _capture_string, _pop_string, _undo_string,
-	    _borrow_cursor_universal, _return_cursor_string, _release_string
-	};
-	provider.source.string = s;
-	return _internal_scanf(&provider, format, arg);
-}
-
-// FIXME: put the testcases to the app/tester after scanf is included into libc
-
-#if 0
-
-//#include <stdio.h>
-//#include <malloc.h>
-//#include <string.h>
-
-#define test_val(fmt, exp_val, act_val) \
-	if (exp_val == act_val) { \
-		printf("succ, expected "fmt", actual "fmt"\n", exp_val, act_val); \
-	} else { \
-		printf("fail, expected "fmt", actual "fmt"\n", exp_val, act_val); \
-		++fail; \
-	}
-
-#define test_str(fmt, exp_str, act_str) \
-	if (posix_strcmp(exp_str, act_str) == 0) { \
-		printf("succ, expected "fmt", actual "fmt"\n", exp_str, act_str); \
-	} else { \
-		printf("fail, expected "fmt", actual "fmt"\n", exp_str, act_str); \
-		++fail; \
-	}
-
-void __posix_scanf_test(void);
-void __posix_scanf_test(void)
-{
-	int fail = 0;
-
-	int ret;
-
-	unsigned char uhh;
-	signed char shh;
-	unsigned short uh;
-	short sh;
-	unsigned udef;
-	int sdef;
-	unsigned long ul;
-	long sl;
-	unsigned long long ull;
-	long long sll;
-	void *p;
-	
-	float f;
-	double d;
-	long double ld;
-
-	char str[20];
-	char seq[20];
-	char scanset[20];
-
-	char *pstr;
-	char *pseq;
-	char *pscanset;
-	
-	ret = posix_sscanf(
-	    "\n j tt % \t -121314 98765 aqw 0765 0x77 0xABCDEF88 -99 884",
-	    " j tt %%%3hhd%1hhu%3hd %3hu%u aqw%n %lo%llx %p %li %lld",
-	    &shh, &uhh, &sh, &uh, &udef, &sdef, &ul, &ull, &p, &sl, &sll);
-	test_val("%d", -12, shh);
-	test_val("%u", 1, uhh);
-	test_val("%d", 314, sh);
-	test_val("%u", 987, uh);
-	test_val("%u", 65, udef);
-	test_val("%d", 28, sdef);
-	test_val("%lo", (unsigned long) 0765, ul);
-	test_val("%llx", (unsigned long long) 0x77, ull);
-	test_val("%p", (void *) 0xABCDEF88, p);
-	test_val("%ld", (long) -99, sl);
-	test_val("%lld", (long long) 884, sll);
-	test_val("%d", 10, ret);
-
-	ret = posix_sscanf(
-	    "\n \t\t1.0 -0x555.AP10 1234.5678e12",
-	    "%f %lf %Lf",
-	    &f, &d, &ld);
-	test_val("%f", 1.0, f);
-	test_val("%lf", (double) -0x555.AP10, d);
-	test_val("%Lf", (long double) 1234.5678e12, ld);
-	test_val("%d", 3, ret);
-	 
-	ret = posix_sscanf(
-	    "\n\n\thello world    \n",
-	    "%5s %ms",
-	    str, &pstr);
-	test_str("%s", "hello", str);
-	test_str("%s", "world", pstr);
-	test_val("%d", 2, ret);
-	free(pstr);
-
-	ret = posix_sscanf(
-	    "\n\n\thello world    \n",
-	    " %5c %mc",
-	    seq, &pseq);
-	seq[5] = '\0';
-	pseq[1] = '\0';
-	test_str("%s", "hello", seq);
-	test_str("%s", "w", pseq);
-	test_val("%d", 2, ret);
-	free(pseq);
-
-	ret = posix_sscanf(
-	    "\n\n\th-e-l-l-o world-]    \n",
-	    " %9[-eh-o] %m[^]-]",
-	    scanset, &pscanset);
-	test_str("%s", "h-e-l-l-o", scanset);
-	test_str("%s", "world", pscanset);
-	test_val("%d", 2, ret);
-	free(pscanset);
-
-	printf("Failed: %d\n", fail);
-}
-
-#endif
-
-/** @}
- */
Index: pace/lib/posix/stdlib.c
===================================================================
--- uspace/lib/posix/stdlib.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,504 +1,0 @@
-/*
- * Copyright (c) 2011 Petr Koupy
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 library definitions.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "internal/common.h"
-#include "stdlib.h"
-
-#include "errno.h"
-#include "fcntl.h"
-#include "limits.h"
-#include "string.h"
-#include "sys/stat.h"
-#include "unistd.h"
-
-#include "libc/sort.h"
-#include "libc/str.h"
-#include "libc/vfs/vfs.h"
-#include "libc/stats.h"
-
-/**
- * 
- * @param array
- * @param count
- * @param size
- * @param compare
- */
-int posix_atexit(void (*func)(void))
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
-/**
- * Integer absolute value.
- * 
- * @param i Input value.
- * @return Absolute value of the parameter.
- */
-int posix_abs(int i)
-{
-	return i < 0 ? -i : i;
-}
-
-/**
- * Long integer absolute value.
- * 
- * @param i Input value.
- * @return Absolute value of the parameter.
- */
-long posix_labs(long i)
-{
-	return i < 0 ? -i : i;
-}
-
-/**
- * Long long integer absolute value.
- * 
- * @param i Input value.
- * @return Absolute value of the parameter.
- */
-long long posix_llabs(long long i)
-{
-	return i < 0 ? -i : i;
-}
-
-/**
- * Compute the quotient and remainder of an integer division.
- *
- * @param numer Numerator.
- * @param denom Denominator.
- * @return Quotient and remainder packed into structure.
- */
-posix_div_t posix_div(int numer, int denom)
-{
-	return (posix_div_t) { .quot = numer / denom, .rem = numer % denom };
-}
-
-/**
- * Compute the quotient and remainder of a long integer division.
- *
- * @param numer Numerator.
- * @param denom Denominator.
- * @return Quotient and remainder packed into structure.
- */
-posix_ldiv_t posix_ldiv(long numer, long denom)
-{
-	return (posix_ldiv_t) { .quot = numer / denom, .rem = numer % denom };
-}
-
-/**
- * Compute the quotient and remainder of a long long integer division.
- *
- * @param numer Numerator.
- * @param denom Denominator.
- * @return Quotient and remainder packed into structure.
- */
-posix_lldiv_t posix_lldiv(long long numer, long long denom)
-{
-	return (posix_lldiv_t) { .quot = numer / denom, .rem = numer % denom };
-}
-
-/**
- * Private helper function that serves as a compare function for qsort().
- *
- * @param elem1 First element to compare.
- * @param elem2 Second element to compare.
- * @param compare Comparison function without userdata parameter.
- * @return Relative ordering of the elements.
- */
-static int sort_compare_wrapper(void *elem1, void *elem2, void *userdata)
-{
-	int (*compare)(const void *, const void *) = userdata;
-	int ret = compare(elem1, elem2);
-	
-	/* Native qsort internals expect this. */
-	if (ret < 0) {
-		return -1;
-	} else if (ret > 0) {
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-/**
- * Array sorting utilizing the quicksort algorithm.
- *
- * @param array Array of elements to sort.
- * @param count Number of elements in the array.
- * @param size Width of each element.
- * @param compare Decides relative ordering of two elements.
- */
-void posix_qsort(void *array, size_t count, size_t size,
-    int (*compare)(const void *, const void *))
-{
-	/* Implemented in libc with one extra argument. */
-	qsort(array, count, size, sort_compare_wrapper, compare);
-}
-
-/**
- * Binary search in a sorted array.
- *
- * @param key Object to search for.
- * @param base Pointer to the first element of the array.
- * @param nmemb Number of elements in the array.
- * @param size Size of each array element.
- * @param compar Comparison function.
- * @return Pointer to a matching element, or NULL if none can be found.
- */
-void *posix_bsearch(const void *key, const void *base,
-    size_t nmemb, size_t size, int (*compar)(const void *, const void *))
-{
-	while (nmemb > 0) {
-		const void *middle = base + (nmemb / 2) * size;
-		int cmp = compar(key, middle);
-		if (cmp == 0) {
-			return (void *) middle;
-		}
-		if (middle == base) {
-			/* There is just one member left to check and it
-			 * didn't match the key. Avoid infinite loop.
-			 */
-			break;
-		}
-		if (cmp < 0) {
-			nmemb = nmemb / 2;
-		} else if (cmp > 0) {
-			nmemb = nmemb - (nmemb / 2);
-			base = middle;
-		}
-	}
-	
-	return NULL;
-}
-
-/**
- * Retrieve a value of the given environment variable.
- *
- * Since HelenOS doesn't support env variables at the moment,
- * this function always returns NULL.
- *
- * @param name Name of the variable.
- * @return Value of the variable or NULL if such variable does not exist.
- */
-char *posix_getenv(const char *name)
-{
-	return NULL;
-}
-
-/**
- * 
- * @param name
- * @param resolved
- * @return
- */
-int posix_putenv(char *string)
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
-/**
- * Issue a command.
- *
- * @param string String to be passed to a command interpreter or NULL.
- * @return Termination status of the command if the command is not NULL,
- *     otherwise indicate whether there is a command interpreter (non-zero)
- *     or not (zero).
- */
-int posix_system(const char *string) {
-	// TODO: does nothing at the moment
-	return 0;
-}
-
-/**
- * Resolve absolute pathname.
- * 
- * @param name Pathname to be resolved.
- * @param resolved Either buffer for the resolved absolute pathname or NULL.
- * @return On success, either resolved (if it was not NULL) or pointer to the
- *     newly allocated buffer containing the absolute pathname (if resolved was
- *     NULL). Otherwise NULL.
- *
- */
-char *posix_realpath(const char *restrict name, char *restrict resolved)
-{
-	#ifndef PATH_MAX
-		assert(resolved == NULL);
-	#endif
-	
-	if (name == NULL) {
-		errno = EINVAL;
-		return NULL;
-	}
-	
-	// TODO: symlink resolution
-	
-	/* Function absolutize is implemented in libc and declared in vfs.h.
-	 * No more processing is required as HelenOS doesn't have symlinks
-	 * so far (as far as I can tell), although this function will need
-	 * to be updated when that support is implemented.
-	 */
-	char* absolute = absolutize(name, NULL);
-	
-	if (absolute == NULL) {
-		/* POSIX requires some specific errnos to be set
-		 * for some cases, but there is no way to find out from
-		 * absolutize().
-		 */
-		errno = EINVAL;
-		return NULL;
-	}
-	
-	if (resolved == NULL) {
-		return absolute;
-	} else {
-		#ifdef PATH_MAX
-			str_cpy(resolved, PATH_MAX, absolute);
-		#endif
-		free(absolute);
-		return resolved;
-	}
-}
-
-/**
- * Converts a string representation of a floating-point number to
- * its native representation. See posix_strtold().
- *
- * @param nptr String representation of a floating-point number.
- * @return Double-precision number resulting from the string conversion.
- */
-double posix_atof(const char *nptr)
-{
-	return posix_strtod(nptr, NULL);
-}
-
-/**
- * Converts a string representation of a floating-point number to
- * its native representation. See posix_strtold().
- *
- * @param nptr String representation of a floating-point number.
- * @param endptr Pointer to the final part of the string which
- *     was not used for conversion.
- * @return Single-precision number resulting from the string conversion.
- */
-float posix_strtof(const char *restrict nptr, char **restrict endptr)
-{
-	return (float) posix_strtold(nptr, endptr);
-}
-
-/**
- * Converts a string representation of a floating-point number to
- * its native representation. See posix_strtold().
- *
- * @param nptr String representation of a floating-point number.
- * @param endptr Pointer to the final part of the string which
- *     was not used for conversion.
- * @return Double-precision number resulting from the string conversion.
- */
-double posix_strtod(const char *restrict nptr, char **restrict endptr)
-{
-	return (double) posix_strtold(nptr, endptr);
-}
-
-/**
- * Allocate memory chunk.
- *
- * @param size Size of the chunk to allocate.
- * @return Either pointer to the allocated chunk or NULL if not possible.
- */
-void *posix_malloc(size_t size)
-{
-	return malloc(size);
-}
-
-/**
- * Allocate memory for an array of elements.
- *
- * @param nelem Number of elements in the array.
- * @param elsize Size of each element.
- * @return Either pointer to the allocated array or NULL if not possible.
- */
-void *posix_calloc(size_t nelem, size_t elsize)
-{
-	return calloc(nelem, elsize);
-}
-
-/**
- * Reallocate memory chunk to a new size.
- *
- * @param ptr Memory chunk to reallocate. Might be NULL.
- * @param size Size of the reallocated chunk. Might be zero.
- * @return Either NULL or the pointer to the newly reallocated chunk.
- */
-void *posix_realloc(void *ptr, size_t size)
-{
-	if (ptr != NULL && size == 0) {
-		/* Native realloc does not handle this special case. */
-		free(ptr);
-		return NULL;
-	} else {
-		return realloc(ptr, size);
-	}
-}
-
-/**
- * Free allocated memory chunk.
- *
- * @param ptr Memory chunk to be freed.
- */
-void posix_free(void *ptr)
-{
-	if (ptr) {
-		free(ptr);
-	}
-}
-
-/**
- * Creates and opens an unique temporary file from template.
- *
- * @param tmpl Template. Last six characters must be XXXXXX.
- * @return The opened file descriptor or -1 on error.
- */
-int posix_mkstemp(char *tmpl)
-{
-	int fd = -1;
-	
-	char *tptr = tmpl + posix_strlen(tmpl) - 6;
-	
-	while (fd < 0) {
-		if (*posix_mktemp(tmpl) == '\0') {
-			/* Errno set by mktemp(). */
-			return -1;
-		}
-		
-		fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
-		
-		if (fd == -1) {
-			/* Restore template to it's original state. */
-			snprintf(tptr, 7, "XXXXXX");
-		}
-	}
-	
-	return fd;
-}
-
-/**
- * Creates an unique temporary file name from template.
- *
- * @param tmpl Template. Last six characters must be XXXXXX.
- * @return The value of tmpl. The template is modified in place.
- *    If no temporary file name can be created, template is
- *    reduced to an empty string.
- */
-char *posix_mktemp(char *tmpl)
-{
-	int tmpl_len = posix_strlen(tmpl);
-	if (tmpl_len < 6) {
-		errno = EINVAL;
-		*tmpl = '\0';
-		return tmpl;
-	}
-	
-	char *tptr = tmpl + tmpl_len - 6;
-	if (posix_strcmp(tptr, "XXXXXX") != 0) {
-		errno = EINVAL;
-		*tmpl = '\0';
-		return tmpl;
-	}
-	
-	static int seq = 0;
-	
-	for (; seq < 1000000; ++seq) {
-		snprintf(tptr, 7, "%06d", seq);
-		
-		int orig_errno = errno;
-		errno = 0;
-		/* Check if the file exists. */
-		if (posix_access(tmpl, F_OK) == -1) {
-			if (errno == ENOENT) {
-				errno = orig_errno;
-				break;
-			} else {
-				/* errno set by access() */
-				*tmpl = '\0';
-				return tmpl;
-			}
-		}
-	}
-	
-	if (seq == 10000000) {
-		errno = EEXIST;
-		*tmpl = '\0';
-		return tmpl;
-	}
-	
-	return tmpl;
-}
-
-/**
- * Get system load average statistics.
- *
- * @param loadavg Array where the load averages shall be placed.
- * @param nelem Maximum number of elements to be placed into the array.
- * @return Number of elements placed into the array on success, -1 otherwise.
- */
-int bsd_getloadavg(double loadavg[], int nelem)
-{
-	assert(nelem > 0);
-	
-	size_t count;
-	load_t *loads = stats_get_load(&count);
-	
-	if (loads == NULL) {
-		return -1;
-	}
-	
-	if (((size_t) nelem) < count) {
-		count = nelem;
-	}
-	
-	for (size_t i = 0; i < count; ++i) {
-		loadavg[i] = (double) loads[i];
-	}
-	
-	free(loads);
-	return count;
-}
-
-/** @}
- */
Index: pace/lib/posix/stdlib.h
===================================================================
--- uspace/lib/posix/stdlib.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,172 +1,0 @@
-/*
- * Copyright (c) 2011 Petr Koupy
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 library definitions.
- */
-
-#ifndef POSIX_STDLIB_H_
-#define POSIX_STDLIB_H_
-
-#include "libc/stdlib.h"
-
-#ifndef NULL
-	#define NULL  ((void *) 0)
-#endif
-
-/* Process Termination */
-#undef EXIT_FAILURE
-#define EXIT_FAILURE 1
-#undef EXIT_SUCCESS
-#define EXIT_SUCCESS 0
-#define _Exit exit
-extern int posix_atexit(void (*func)(void));
-
-/* Absolute Value */
-extern int posix_abs(int i);
-extern long posix_labs(long i);
-extern long long posix_llabs(long long i);
-
-/* Integer Division */
-
-typedef struct {
-	int quot, rem;
-} posix_div_t;
-
-typedef struct {
-	long quot, rem;
-} posix_ldiv_t;
-
-typedef struct {
-	long long quot, rem;
-} posix_lldiv_t;
-
-extern posix_div_t posix_div(int numer, int denom);
-extern posix_ldiv_t posix_ldiv(long numer, long denom);
-extern posix_lldiv_t posix_lldiv(long long numer, long long denom);
-
-/* Array Functions */
-extern void posix_qsort(void *array, size_t count, size_t size,
-    int (*compare)(const void *, const void *));
-extern void *posix_bsearch(const void *key, const void *base,
-    size_t nmemb, size_t size, int (*compar)(const void *, const void *));
-
-/* Environment Access */
-extern char *posix_getenv(const char *name);
-extern int posix_putenv(char *string);
-extern int posix_system(const char *string);
-
-/* Symbolic Links */
-extern char *posix_realpath(const char *restrict name, char *restrict resolved);
-
-/* Floating Point Conversion */
-extern double posix_atof(const char *nptr);
-extern float posix_strtof(const char *restrict nptr, char **restrict endptr);
-extern double posix_strtod(const char *restrict nptr, char **restrict endptr);
-extern long double posix_strtold(const char *restrict nptr, char **restrict endptr);
-
-/* Integer Conversion */
-extern int posix_atoi(const char *nptr);
-extern long int posix_atol(const char *nptr);
-extern long long int posix_atoll(const char *nptr);
-extern long int posix_strtol(const char *restrict nptr,
-    char **restrict endptr, int base);
-extern long long int posix_strtoll(const char *restrict nptr,
-    char **restrict endptr, int base);
-extern unsigned long int posix_strtoul(const char *restrict nptr,
-    char **restrict endptr, int base);
-extern unsigned long long int posix_strtoull(
-    const char *restrict nptr, char **restrict endptr, int base);
-
-/* Memory Allocation */
-extern void *posix_malloc(size_t size);
-extern void *posix_calloc(size_t nelem, size_t elsize);
-extern void *posix_realloc(void *ptr, size_t size);
-extern void posix_free(void *ptr);
-
-/* Temporary Files */
-extern int posix_mkstemp(char *tmpl);
-
-/* Legacy Declarations */
-extern char *posix_mktemp(char *tmpl);
-extern int bsd_getloadavg(double loadavg[], int nelem);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define atexit posix_atexit
-
-	#define abs posix_abs
-	#define labs posix_labs
-	#define llabs posix_llabs
-
-	#define div_t posix_div_t
-	#define ldiv_t posix_ldiv_t
-	#define lldiv_t posix_lldiv_t
-	#define div posix_div
-	#define ldiv posix_ldiv
-	#define lldiv posix_lldiv
-
-	#define qsort posix_qsort
-	#define bsearch posix_bsearch
-
-	#define getenv posix_getenv
-	#define putenv posix_putenv
-	#define system posix_system
-
-	#define realpath posix_realpath
-	
-	#define atof posix_atof
-	#define strtof posix_strtof
-	#define strtod posix_strtod
-	#define strtold posix_strtold
-	
-	#define atoi posix_atoi
-	#define atol posix_atol
-	#define atoll posix_atoll
-	#define strtol posix_strtol
-	#define strtoll posix_strtoll
-	#define strtoul posix_strtoul
-	#define strtoull posix_strtoull
-
-	#define malloc posix_malloc
-	#define calloc posix_calloc
-	#define realloc posix_realloc
-	#define free posix_free
-
-	#define mkstemp posix_mkstemp
-
-	#define mktemp posix_mktemp
-	#define getloadavg bsd_getloadavg
-#endif
-
-#endif  // POSIX_STDLIB_H_
-
-/** @}
- */
Index: pace/lib/posix/stdlib/strtol.c
===================================================================
--- uspace/lib/posix/stdlib/strtol.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,399 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Backend for integer conversions.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "../internal/common.h"
-#include "../stdlib.h"
-
-#include "../ctype.h"
-#include "../errno.h"
-#include "../inttypes.h"
-#include "../limits.h"
-
-#define intmax_t posix_intmax_t
-#define uintmax_t posix_uintmax_t
-
-/**
- * Decides whether a digit belongs to a particular base.
- *
- * @param c Character representation of the digit.
- * @param base Base against which the digit shall be tested.
- * @return True if the digit belongs to the base, false otherwise.
- */
-static inline bool is_digit_in_base(int c, int base)
-{
-	if (base <= 10) {
-		return c >= '0' && c < '0' + base;
-	} else {
-		return isdigit(c) ||
-		    (tolower(c) >= 'a' && tolower(c) < ('a' + base - 10));
-	}
-}
-
-/**
- * Derive a digit from its character representation.
- *
- * @param c Character representation of the digit.
- * @return Digit value represented by an integer.
- */
-static inline int digit_value(int c)
-{
-	if (c <= '9') {
-		return c - '0';
-	} else {
-		return 10 + tolower(c) - 'a';
-	}
-}
-
-/**
- * Generic function for parsing an integer from it's string representation.
- * Different variants differ in lower and upper bounds.
- * The parsed string returned by this function is always positive, sign
- * information is provided via a dedicated parameter.
- *
- * @param nptr Input string.
- * @param endptr If non-NULL, *endptr is set to the position of the first
- *     unrecognized character. If no digit has been parsed, value of
- *     nptr is stored there (regardless of any skipped characters at the
- *     beginning).
- * @param base Expected base of the string representation. If 0, base is
- *    determined to be decimal, octal or hexadecimal using the same rules
- *    as C syntax. Otherwise, value must be between 2 and 36, inclusive.
- * @param min_value Lower bound for the resulting conversion.
- * @param max_value Upper bound for the resulting conversion.
- * @param out_negative Either NULL for unsigned conversion or a pointer to the
- *     bool variable into which shall be placed the negativity of the resulting
- *     converted value.
- * @return The absolute value of the parsed value, or the closest in-range value
- *     if the parsed value is out of range. If the input is invalid, zero is
- *     returned and errno is set to EINVAL.
- */
-static inline uintmax_t internal_strtol(
-    const char *restrict nptr, char **restrict endptr, int base,
-    const intmax_t min_value, const uintmax_t max_value,
-    bool *restrict out_negative)
-{
-	if (nptr == NULL) {
-		errno = EINVAL;
-		return 0;
-	}
-	
-	if (base < 0 || base == 1 || base > 36) {
-		errno = EINVAL;
-		return 0;
-	}
-	
-	/* The maximal absolute value that can be returned in this run.
-	 * Depends on sign.
-	 */
-	uintmax_t real_max_value = max_value;
-	
-	/* Current index in the input string. */
-	size_t i = 0;
-	bool negative = false;
-	
-	/* Skip whitespace. */
-	while (isspace(nptr[i])) {
-		i++;
-	}
-	
-	/* Parse sign. */
-	switch (nptr[i]) {
-	case '-':
-		negative = true;
-		
-		/* The strange computation is are there to avoid a corner case
-		 * where -min_value can't be represented in intmax_t.
-		 * (I'm not exactly sure what the semantics are in such a
-		 *  case, but this should be safe for any case.)
-		 */
-		real_max_value = (min_value == 0)
-		    ? 0
-		    :(((uintmax_t) -(min_value + 1)) + 1);
-		
-		/* fallthrough */
-	case '+':
-		i++;
-	}
-	
-	/* Figure out the base. */
-	switch (base) {
-	case 0:
-		if (nptr[i] == '0') {
-			if (tolower(nptr[i + 1]) == 'x') {
-				/* 0x... is hex. */
-				base = 16;
-				i += 2;
-			} else {
-				/* 0... is octal. */
-				base = 8;
-			}
-		} else {
-			/* Anything else is decimal by default. */
-			base = 10;
-		}
-		break;
-	case 16:
-		/* Allow hex number to be prefixed with "0x". */
-		if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x') {
-			i += 2;
-		}
-		break;
-	}
-	
-	if (!is_digit_in_base(nptr[i], base)) {
-		/* No digits to parse, invalid input. */
-		
-		errno = EINVAL;
-		if (endptr != NULL) {
-			*endptr = (char *) nptr;
-		}
-		return 0;
-	}
-	
-	/* Maximal value to which a digit can be added without a risk
-	 * of overflow.
-	 */
-	uintmax_t max_safe_value = (real_max_value - base + 1) / base;
-	
-	uintmax_t result = 0;
-	
-	if (real_max_value == 0) {
-		/* Special case when a negative number is parsed as
-		 * unsigned integer. Only -0 is accepted.
-		 */
-		
-		while (is_digit_in_base(nptr[i], base)) {
-			if (nptr[i] != '0') {
-				errno = ERANGE;
-				result = 0;
-			}
-			i++;
-		}
-	}
-	
-	while (is_digit_in_base(nptr[i], base)) {
-		int digit = digit_value(nptr[i]);
-		
-		if (result > max_safe_value) {
-			/* corner case, check for overflow */
-			
-			uintmax_t boundary = (real_max_value - digit) / base;
-			
-			if (result > boundary) {
-				/* overflow */
-				errno = ERANGE;
-				result = real_max_value;
-				break;
-			}
-		}
-		
-		result = result * base + digit;
-		i++;
-	}
-	
-	if (endptr != NULL) {
-		/* Move the pointer to the end of the number,
-		 * in case it isn't there already.
-		 */
-		while (is_digit_in_base(nptr[i], base)) {
-			i++;
-		}
-		
-		*endptr = (char *) &nptr[i];
-	}
-	if (out_negative != NULL) {
-		*out_negative = negative;
-	}
-	return result;
-}
-
-/**
- * Convert a string to an integer.
- *
- * @param nptr Input string.
- * @return Result of the conversion.
- */
-int posix_atoi(const char *nptr)
-{
-	bool neg = false;
-	uintmax_t result =
-	    internal_strtol(nptr, NULL, 10, INT_MIN, INT_MAX, &neg);
-
-	return (neg ? ((int) -result) : (int) result);
-}
-
-/**
- * Convert a string to a long integer.
- *
- * @param nptr Input string.
- * @return Result of the conversion.
- */
-long posix_atol(const char *nptr)
-{
-	bool neg = false;
-	uintmax_t result =
-	    internal_strtol(nptr, NULL, 10, LONG_MIN, LONG_MAX, &neg);
-
-	return (neg ? ((long) -result) : (long) result);
-}
-
-/**
- * Convert a string to a long long integer.
- *
- * @param nptr Input string.
- * @return Result of the conversion.
- */
-long long posix_atoll(const char *nptr)
-{
-	bool neg = false;
-	uintmax_t result =
-	    internal_strtol(nptr, NULL, 10, LLONG_MIN, LLONG_MAX, &neg);
-
-	return (neg ? ((long long) -result) : (long long) result);
-}
-
-/**
- * Convert a string to a long integer.
- *
- * @param nptr Input string.
- * @param endptr Pointer to the final part of the string which
- *     was not used for conversion.
- * @param base Expected base of the string representation.
- * @return Result of the conversion.
- */
-long posix_strtol(const char *restrict nptr, char **restrict endptr, int base)
-{
-	bool neg = false;
-	uintmax_t result =
-	    internal_strtol(nptr, endptr, base, LONG_MIN, LONG_MAX, &neg);
-
-	return (neg ? ((long) -result) : ((long) result));
-}
-
-/**
- * Convert a string to a long long integer.
- *
- * @param nptr Input string.
- * @param endptr Pointer to the final part of the string which
- *     was not used for conversion.
- * @param base Expected base of the string representation.
- * @return Result of the conversion.
- */
-long long posix_strtoll(
-    const char *restrict nptr, char **restrict endptr, int base)
-{
-	bool neg = false;
-	uintmax_t result =
-	    internal_strtol(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &neg);
-
-	return (neg ? ((long long) -result) : (long long) result);
-}
-
-/**
- * Convert a string to a largest signed integer type.
- *
- * @param nptr Input string.
- * @param endptr Pointer to the final part of the string which
- *     was not used for conversion.
- * @param base Expected base of the string representation.
- * @return Result of the conversion.
- */
-intmax_t posix_strtoimax(
-    const char *restrict nptr, char **restrict endptr, int base)
-{
-	bool neg = false;
-	uintmax_t result =
-	    internal_strtol(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX, &neg);
-
-	return (neg ? ((intmax_t) -result) : (intmax_t) result);
-}
-
-/**
- * Convert a string to an unsigned long integer.
- *
- * @param nptr Input string.
- * @param endptr Pointer to the final part of the string which
- *     was not used for conversion.
- * @param base Expected base of the string representation.
- * @return Result of the conversion.
- */
-unsigned long posix_strtoul(
-    const char *restrict nptr, char **restrict endptr, int base)
-{
-	uintmax_t result =
-	    internal_strtol(nptr, endptr, base, 0, ULONG_MAX, NULL);
-
-	return (unsigned long) result;
-}
-
-/**
- * Convert a string to an unsigned long long integer.
- *
- * @param nptr Input string.
- * @param endptr Pointer to the final part of the string which
- *     was not used for conversion.
- * @param base Expected base of the string representation.
- * @return Result of the conversion.
- */
-unsigned long long posix_strtoull(
-    const char *restrict nptr, char **restrict endptr, int base)
-{
-	uintmax_t result =
-	    internal_strtol(nptr, endptr, base, 0, ULLONG_MAX, NULL);
-
-	return (unsigned long long) result;
-}
-
-/**
- * Convert a string to a largest unsigned integer type.
- *
- * @param nptr Input string.
- * @param endptr Pointer to the final part of the string which
- *     was not used for conversion.
- * @param base Expected base of the string representation.
- * @return Result of the conversion.
- */
-uintmax_t posix_strtoumax(
-    const char *restrict nptr, char **restrict endptr, int base)
-{
-	uintmax_t result =
-	    internal_strtol(nptr, endptr, base, 0, UINTMAX_MAX, NULL);
-
-	return result;
-}
-
-/** @}
- */
Index: pace/lib/posix/stdlib/strtold.c
===================================================================
--- uspace/lib/posix/stdlib/strtold.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,491 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Backend for floating point conversions.
- */
-
-#define LIBPOSIX_INTERNAL
-
-/* Must be first. */
-#include "../stdbool.h"
-
-#include "../internal/common.h"
-#include "../stdlib.h"
-
-#include "../assert.h"
-#include "../ctype.h"
-#include "../stdint.h"
-#include "../strings.h"
-#include "../errno.h"
-#include "../limits.h"
-
-#include "../float.h"
-
-#ifndef HUGE_VALL
-	#define HUGE_VALL (+1.0l / +0.0l)
-#endif
-
-#ifndef abs
-	#define abs(x) (((x) < 0) ? -(x) : (x))
-#endif
-
-/* If the constants are not defined, use double precision as default. */
-#ifndef LDBL_MANT_DIG
-	#define LDBL_MANT_DIG 53
-#endif
-#ifndef LDBL_MAX_EXP
-	#define LDBL_MAX_EXP 1024
-#endif
-#ifndef LDBL_MIN_EXP
-	#define LDBL_MIN_EXP (-1021)
-#endif
-#ifndef LDBL_DIG
-	#define LDBL_DIG 15
-#endif
-#ifndef LDBL_MIN
-	#define LDBL_MIN 2.2250738585072014E-308
-#endif
-
-/* power functions ************************************************************/
-
-#if LDBL_MAX_EXP >= 16384
-const int MAX_POW5 = 12;
-#else
-const int MAX_POW5 = 8;
-#endif
-
-/* The value at index i is approximately 5**(2**i). */
-long double pow5[] = {
-	0x5p0l,
-	0x19p0l,
-	0x271p0l,
-	0x5F5E1p0l,
-	0x2386F26FC1p0l,
-	0x4EE2D6D415B85ACEF81p0l,
-	0x184F03E93FF9F4DAA797ED6E38ED6p36l,
-	0x127748F9301D319BF8CDE66D86D62p185l,
-	0x154FDD7F73BF3BD1BBB77203731FDp482l,
-#if LDBL_MAX_EXP >= 16384
-	0x1C633415D4C1D238D98CAB8A978A0p1076l,
-	0x192ECEB0D02EA182ECA1A7A51E316p2265l,
-	0x13D1676BB8A7ABBC94E9A519C6535p4643l,
-	0x188C0A40514412F3592982A7F0094p9398l,
-#endif
-};
-
-#if LDBL_MAX_EXP >= 16384
-const int MAX_POW2 = 15;
-#else
-const int MAX_POW2 = 9;
-#endif
-
-/* Powers of two. */
-long double pow2[] = {
-	0x1P1l,
-	0x1P2l,
-	0x1P4l,
-	0x1P8l,
-	0x1P16l,
-	0x1P32l,
-	0x1P64l,
-	0x1P128l,
-	0x1P256l,
-	0x1P512l,
-#if LDBL_MAX_EXP >= 16384
-	0x1P1024l,
-	0x1P2048l,
-	0x1P4096l,
-	0x1P8192l,
-#endif
-};
-
-/**
- * Multiplies a number by a power of five.
- * The result may be inexact and may not be the best possible approximation.
- *
- * @param mant Number to be multiplied.
- * @param exp Base 5 exponent.
- * @return mant multiplied by 5**exp
- */
-static long double mul_pow5(long double mant, int exp)
-{
-	if (mant == 0.0l || mant == HUGE_VALL) {
-		return mant;
-	}
-	
-	if (abs(exp) >> (MAX_POW5 + 1) != 0) {
-		/* Too large exponent. */
-		errno = ERANGE;
-		return exp < 0 ? LDBL_MIN : HUGE_VALL;
-	}
-	
-	if (exp < 0) {
-		exp = abs(exp);
-		for (int bit = 0; bit <= MAX_POW5; ++bit) {
-			/* Multiply by powers of five bit-by-bit. */
-			if (((exp >> bit) & 1) != 0) {
-				mant /= pow5[bit];
-				if (mant == 0.0l) {
-					/* Underflow. */
-					mant = LDBL_MIN;
-					errno = ERANGE;
-					break;
-				}
-			}
-		}
-	} else {
-		for (int bit = 0; bit <= MAX_POW5; ++bit) {
-			/* Multiply by powers of five bit-by-bit. */
-			if (((exp >> bit) & 1) != 0) {
-				mant *= pow5[bit];
-				if (mant == HUGE_VALL) {
-					/* Overflow. */
-					errno = ERANGE;
-					break;
-				}
-			}
-		}
-	}
-	
-	return mant;
-}
-
-/**
- * Multiplies a number by a power of two. This is always exact.
- *
- * @param mant Number to be multiplied.
- * @param exp Base 2 exponent.
- * @return mant multiplied by 2**exp.
- */
-static long double mul_pow2(long double mant, int exp)
-{
-	if (mant == 0.0l || mant == HUGE_VALL) {
-		return mant;
-	}
-	
-	if (exp > LDBL_MAX_EXP || exp < LDBL_MIN_EXP) {
-		errno = ERANGE;
-		return exp < 0 ? LDBL_MIN : HUGE_VALL;
-	}
-	
-	if (exp < 0) {
-		exp = abs(exp);
-		for (int i = 0; i <= MAX_POW2; ++i) {
-			if (((exp >> i) & 1) != 0) {
-				mant /= pow2[i];
-				if (mant == 0.0l) {
-					mant = LDBL_MIN;
-					errno = ERANGE;
-					break;
-				}
-			}
-		}
-	} else {
-		for (int i = 0; i <= MAX_POW2; ++i) {
-			if (((exp >> i) & 1) != 0) {
-				mant *= pow2[i];
-				if (mant == HUGE_VALL) {
-					errno = ERANGE;
-					break;
-				}
-			}
-		}
-	}
-	
-	return mant;
-}
-
-/* end power functions ********************************************************/
-
-
-
-/**
- * Convert decimal string representation of the floating point number.
- * Function expects the string pointer to be already pointed at the first
- * digit (i.e. leading optional sign was already consumed by the caller).
- * 
- * @param sptr Pointer to the storage of the string pointer. Upon successful
- *     conversion, the string pointer is updated to point to the first
- *     unrecognized character.
- * @return An approximate representation of the input floating-point number.
- */
-static long double parse_decimal(const char **sptr)
-{
-	assert(sptr != NULL);
-	assert (*sptr != NULL);
-	
-	const int DEC_BASE = 10;
-	const char DECIMAL_POINT = '.';
-	const char EXPONENT_MARK = 'e';
-	
-	const char *str = *sptr;
-	long double significand = 0;
-	long exponent = 0;
-	
-	/* number of digits parsed so far */
-	int parsed_digits = 0;
-	bool after_decimal = false;
-	
-	while (isdigit(*str) || (!after_decimal && *str == DECIMAL_POINT)) {
-		if (*str == DECIMAL_POINT) {
-			after_decimal = true;
-			str++;
-			continue;
-		}
-		
-		if (parsed_digits == 0 && *str == '0') {
-			/* Nothing, just skip leading zeros. */
-		} else if (parsed_digits < LDBL_DIG) {
-			significand = significand * DEC_BASE + (*str - '0');
-			parsed_digits++;
-		} else {
-			exponent++;
-		}
-		
-		if (after_decimal) {
-			/* Decrement exponent if we are parsing the fractional part. */
-			exponent--;
-		}
-		
-		str++;
-	}
-	
-	/* exponent */
-	if (tolower(*str) == EXPONENT_MARK) {
-		str++;
-		
-		/* Returns MIN/MAX value on error, which is ok. */
-		long exp = strtol(str, (char **) &str, DEC_BASE);
-		
-		if (exponent > 0 && exp > LONG_MAX - exponent) {
-			exponent = LONG_MAX;
-		} else if (exponent < 0 && exp < LONG_MIN - exponent) {
-			exponent = LONG_MIN;
-		} else {
-			exponent += exp;
-		}
-	}
-	
-	*sptr = str;
-	
-	/* Return multiplied by a power of ten. */
-	return mul_pow2(mul_pow5(significand, exponent), exponent);
-}
-
-/**
- * Derive a hexadecimal digit from its character representation.
- * 
- * @param ch Character representation of the hexadecimal digit.
- * @return Digit value represented by an integer.
- */
-static inline int hex_value(char ch)
-{
-	if (ch <= '9') {
-		return ch - '0';
-	} else {
-		return 10 + tolower(ch) - 'a';
-	}
-}
-
-/**
- * Convert hexadecimal string representation of the floating point number.
- * Function expects the string pointer to be already pointed at the first
- * digit (i.e. leading optional sign and 0x prefix were already consumed
- * by the caller).
- *
- * @param sptr Pointer to the storage of the string pointer. Upon successful
- *     conversion, the string pointer is updated to point to the first
- *     unrecognized character.
- * @return Representation of the input floating-point number.
- */
-static long double parse_hexadecimal(const char **sptr)
-{
-	assert(sptr != NULL && *sptr != NULL);
-	
-	const int DEC_BASE = 10;
-	const int HEX_BASE = 16;
-	const char DECIMAL_POINT = '.';
-	const char EXPONENT_MARK = 'p';
-	
-	const char *str = *sptr;
-	long double significand = 0;
-	long exponent = 0;
-	
-	/* number of bits parsed so far */
-	int parsed_bits = 0;
-	bool after_decimal = false;
-	
-	while (posix_isxdigit(*str) || (!after_decimal && *str == DECIMAL_POINT)) {
-		if (*str == DECIMAL_POINT) {
-			after_decimal = true;
-			str++;
-			continue;
-		}
-		
-		if (parsed_bits == 0 && *str == '0') {
-			/* Nothing, just skip leading zeros. */
-		} else if (parsed_bits <= LDBL_MANT_DIG) {
-			significand = significand * HEX_BASE + hex_value(*str);
-			parsed_bits += 4;
-		} else {
-			exponent += 4;
-		}
-		
-		if (after_decimal) {
-			exponent -= 4;
-		}
-		
-		str++;
-	}
-	
-	/* exponent */
-	if (tolower(*str) == EXPONENT_MARK) {
-		str++;
-		
-		/* Returns MIN/MAX value on error, which is ok. */
-		long exp = strtol(str, (char **) &str, DEC_BASE);
-		
-		if (exponent > 0 && exp > LONG_MAX - exponent) {
-			exponent = LONG_MAX;
-		} else if (exponent < 0 && exp < LONG_MIN - exponent) {
-			exponent = LONG_MIN;
-		} else {
-			exponent += exp;
-		}
-	}
-	
-	*sptr = str;
-	
-	/* Return multiplied by a power of two. */
-	return mul_pow2(significand, exponent);
-}
-
-/**
- * Converts a string representation of a floating-point number to
- * its native representation. Largely POSIX compliant, except for
- * locale differences (always uses '.' at the moment) and rounding.
- * Decimal strings are NOT guaranteed to be correctly rounded. This function
- * should return a good enough approximation for most purposes but if you
- * depend on a precise conversion, use hexadecimal representation.
- * Hexadecimal strings are currently always rounded towards zero, regardless
- * of the current rounding mode.
- *
- * @param nptr Input string.
- * @param endptr If non-NULL, *endptr is set to the position of the first
- *     unrecognized character.
- * @return An approximate representation of the input floating-point number.
- */
-long double posix_strtold(const char *restrict nptr, char **restrict endptr)
-{
-	assert(nptr != NULL);
-	
-	const int RADIX = '.';
-	
-	/* minus sign */
-	bool negative = false;
-	/* current position in the string */
-	int i = 0;
-	
-	/* skip whitespace */
-	while (isspace(nptr[i])) {
-		i++;
-	}
-	
-	/* parse sign */
-	switch (nptr[i]) {
-	case '-':
-		negative = true;
-		/* fallthrough */
-	case '+':
-		i++;
-	}
-	
-	/* check for NaN */
-	if (posix_strncasecmp(&nptr[i], "nan", 3) == 0) {
-		// FIXME: return NaN
-		// TODO: handle the parenthesised case
-		
-		if (endptr != NULL) {
-			*endptr = (char *) nptr;
-		}
-		errno = EINVAL;
-		return 0;
-	}
-	
-	/* check for Infinity */
-	if (posix_strncasecmp(&nptr[i], "inf", 3) == 0) {
-		i += 3;
-		if (posix_strncasecmp(&nptr[i], "inity", 5) == 0) {
-			i += 5;
-		}
-		
-		if (endptr != NULL) {
-			*endptr = (char *) &nptr[i];
-		}
-		return negative ? -HUGE_VALL : +HUGE_VALL;
-	}
-
-	/* check for a hex number */
-	if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x' &&
-	    (posix_isxdigit(nptr[i + 2]) ||
-	    (nptr[i + 2] == RADIX && posix_isxdigit(nptr[i + 3])))) {
-		i += 2;
-		
-		const char *ptr = &nptr[i];
-		/* this call sets errno if appropriate. */
-		long double result = parse_hexadecimal(&ptr);
-		if (endptr != NULL) {
-			*endptr = (char *) ptr;
-		}
-		return negative ? -result : result;
-	}
-	
-	/* check for a decimal number */
-	if (isdigit(nptr[i]) || (nptr[i] == RADIX && isdigit(nptr[i + 1]))) {
-		const char *ptr = &nptr[i];
-		/* this call sets errno if appropriate. */
-		long double result = parse_decimal(&ptr);
-		if (endptr != NULL) {
-			*endptr = (char *) ptr;
-		}
-		return negative ? -result : result;
-	}
-	
-	/* nothing to parse */
-	if (endptr != NULL) {
-		*endptr = (char *) nptr;
-	}
-	errno = EINVAL;
-	return 0;
-}
-
-/** @}
- */
Index: pace/lib/posix/string.c
===================================================================
--- uspace/lib/posix/string.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,754 +1,0 @@
-/*
- * Copyright (c) 2011 Petr Koupy
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 String manipulation.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "internal/common.h"
-#include "string.h"
-
-#include "assert.h"
-#include "errno.h"
-#include "limits.h"
-#include "stdlib.h"
-#include "signal.h"
-
-#include "libc/str_error.h"
-
-/**
- * The same as strpbrk, except it returns pointer to the nul terminator
- * if no occurence is found.
- *
- * @param s1 String in which to look for the bytes.
- * @param s2 String of bytes to look for.
- * @return Pointer to the found byte on success, pointer to the
- *     string terminator otherwise.
- */
-static char *strpbrk_null(const char *s1, const char *s2)
-{
-	while (!posix_strchr(s2, *s1)) {
-		++s1;
-	}
-	
-	return (char *) s1;
-}
-
-/**
- * Copy a string.
- *
- * @param dest Destination pre-allocated buffer.
- * @param src Source string to be copied.
- * @return Pointer to the destination buffer.
- */
-char *posix_strcpy(char *restrict dest, const char *restrict src)
-{
-	posix_stpcpy(dest, src);
-	return dest;
-}
-
-/**
- * Copy fixed length string.
- *
- * @param dest Destination pre-allocated buffer.
- * @param src Source string to be copied.
- * @param n Number of bytes to be stored into destination buffer.
- * @return Pointer to the destination buffer.
- */
-char *posix_strncpy(char *restrict dest, const char *restrict src, size_t n)
-{
-	posix_stpncpy(dest, src, n);
-	return dest;
-}
-
-/**
- * Copy a string.
- *
- * @param dest Destination pre-allocated buffer.
- * @param src Source string to be copied.
- * @return Pointer to the nul character in the destination string.
- */
-char *posix_stpcpy(char *restrict dest, const char *restrict src)
-{
-	assert(dest != NULL);
-	assert(src != NULL);
-
-	for (size_t i = 0; ; ++i) {
-		dest[i] = src[i];
-		
-		if (src[i] == '\0') {
-			/* pointer to the terminating nul character */
-			return &dest[i];
-		}
-	}
-	
-	/* unreachable */
-	return NULL;
-}
-
-/**
- * Copy fixed length string.
- *
- * @param dest Destination pre-allocated buffer.
- * @param src Source string to be copied.
- * @param n Number of bytes to be stored into destination buffer.
- * @return Pointer to the first written nul character or &dest[n].
- */
-char *posix_stpncpy(char *restrict dest, const char *restrict src, size_t n)
-{
-	assert(dest != NULL);
-	assert(src != NULL);
-
-	for (size_t i = 0; i < n; ++i) {
-		dest[i] = src[i];
-	
-		/* the standard requires that nul characters
-		 * are appended to the length of n, in case src is shorter
-		 */
-		if (src[i] == '\0') {
-			char *result = &dest[i];
-			for (++i; i < n; ++i) {
-				dest[i] = '\0';
-			}
-			return result;
-		}
-	}
-	
-	return &dest[n];
-}
-
-/**
- * Concatenate two strings.
- *
- * @param dest String to which src shall be appended.
- * @param src String to be appended after dest.
- * @return Pointer to destination buffer.
- */
-char *posix_strcat(char *restrict dest, const char *restrict src)
-{
-	assert(dest != NULL);
-	assert(src != NULL);
-
-	posix_strcpy(posix_strchr(dest, '\0'), src);
-	return dest;
-}
-
-/**
- * Concatenate a string with part of another.
- *
- * @param dest String to which part of src shall be appended.
- * @param src String whose part shall be appended after dest.
- * @param n Number of bytes to append after dest.
- * @return Pointer to destination buffer.
- */
-char *posix_strncat(char *restrict dest, const char *restrict src, size_t n)
-{
-	assert(dest != NULL);
-	assert(src != NULL);
-
-	char *zeroptr = posix_strncpy(posix_strchr(dest, '\0'), src, n);
-	/* strncpy doesn't append the nul terminator, so we do it here */
-	zeroptr[n] = '\0';
-	return dest;
-}
-
-/**
- * Copy limited number of bytes in memory.
- *
- * @param dest Destination buffer.
- * @param src Source buffer.
- * @param c Character after which the copying shall stop.
- * @param n Number of bytes that shall be copied if not stopped earlier by c.
- * @return Pointer to the first byte after c in dest if found, NULL otherwise.
- */
-void *posix_memccpy(void *restrict dest, const void *restrict src, int c, size_t n)
-{
-	assert(dest != NULL);
-	assert(src != NULL);
-	
-	unsigned char* bdest = dest;
-	const unsigned char* bsrc = src;
-	
-	for (size_t i = 0; i < n; ++i) {
-		bdest[i] = bsrc[i];
-	
-		if (bsrc[i] == (unsigned char) c) {
-			/* pointer to the next byte */
-			return &bdest[i + 1];
-		}
-	}
-	
-	return NULL;
-}
-
-/**
- * Duplicate a string.
- *
- * @param s String to be duplicated.
- * @return Newly allocated copy of the string.
- */
-char *posix_strdup(const char *s)
-{
-	return posix_strndup(s, SIZE_MAX);
-}
-
-/**
- * Duplicate a specific number of bytes from a string.
- *
- * @param s String to be duplicated.
- * @param n Maximum length of the resulting string..
- * @return Newly allocated string copy of length at most n.
- */
-char *posix_strndup(const char *s, size_t n)
-{
-	assert(s != NULL);
-
-	size_t len = posix_strnlen(s, n);
-	char *dup = malloc(len + 1);
-	if (dup == NULL) {
-		return NULL;
-	}
-
-	memcpy(dup, s, len);
-	dup[len] = '\0';
-
-	return dup;
-}
-
-/**
- * Compare bytes in memory.
- *
- * @param mem1 First area of memory to be compared.
- * @param mem2 Second area of memory to be compared.
- * @param n Maximum number of bytes to be compared.
- * @return Difference of the first pair of inequal bytes,
- *     or 0 if areas have the same content.
- */
-int posix_memcmp(const void *mem1, const void *mem2, size_t n)
-{
-	assert(mem1 != NULL);
-	assert(mem2 != NULL);
-
-	const unsigned char *s1 = mem1;
-	const unsigned char *s2 = mem2;
-	
-	for (size_t i = 0; i < n; ++i) {
-		if (s1[i] != s2[i]) {
-			return s1[i] - s2[i];
-		}
-	}
-	
-	return 0;
-}
-
-/**
- * Compare two strings.
- *
- * @param s1 First string to be compared.
- * @param s2 Second string to be compared.
- * @return Difference of the first pair of inequal characters,
- *     or 0 if strings have the same content.
- */
-int posix_strcmp(const char *s1, const char *s2)
-{
-	assert(s1 != NULL);
-	assert(s2 != NULL);
-
-	return posix_strncmp(s1, s2, STR_NO_LIMIT);
-}
-
-/**
- * Compare part of two strings.
- *
- * @param s1 First string to be compared.
- * @param s2 Second string to be compared.
- * @param n Maximum number of characters to be compared.
- * @return Difference of the first pair of inequal characters,
- *     or 0 if strings have the same content.
- */
-int posix_strncmp(const char *s1, const char *s2, size_t n)
-{
-	assert(s1 != NULL);
-	assert(s2 != NULL);
-
-	for (size_t i = 0; i < n; ++i) {
-		if (s1[i] != s2[i]) {
-			return s1[i] - s2[i];
-		}
-		if (s1[i] == '\0') {
-			break;
-		}
-	}
-
-	return 0;
-}
-
-/**
- * Find byte in memory.
- *
- * @param mem Memory area in which to look for the byte.
- * @param c Byte to look for.
- * @param n Maximum number of bytes to be inspected.
- * @return Pointer to the specified byte on success,
- *     NULL pointer otherwise.
- */
-void *posix_memchr(const void *mem, int c, size_t n)
-{
-	assert(mem != NULL);
-	
-	const unsigned char *s = mem;
-	
-	for (size_t i = 0; i < n; ++i) {
-		if (s[i] == (unsigned char) c) {
-			return (void *) &s[i];
-		}
-	}
-	return NULL;
-}
-
-/**
- * Scan string for a first occurence of a character.
- *
- * @param s String in which to look for the character.
- * @param c Character to look for.
- * @return Pointer to the specified character on success,
- *     NULL pointer otherwise.
- */
-char *posix_strchr(const char *s, int c)
-{
-	assert(s != NULL);
-	
-	char *res = gnu_strchrnul(s, c);
-	return (*res == c) ? res : NULL;
-}
-
-/**
- * Scan string for a last occurence of a character.
- *
- * @param s String in which to look for the character.
- * @param c Character to look for.
- * @return Pointer to the specified character on success,
- *     NULL pointer otherwise.
- */
-char *posix_strrchr(const char *s, int c)
-{
-	assert(s != NULL);
-	
-	const char *ptr = posix_strchr(s, '\0');
-	
-	/* the same as in strchr, except it loops in reverse direction */
-	while (*ptr != (char) c) {
-		if (ptr == s) {
-			return NULL;
-		}
-
-		ptr--;
-	}
-
-	return (char *) ptr;
-}
-
-/**
- * Scan string for a first occurence of a character.
- *
- * @param s String in which to look for the character.
- * @param c Character to look for.
- * @return Pointer to the specified character on success, pointer to the
- *     string terminator otherwise.
- */
-char *gnu_strchrnul(const char *s, int c)
-{
-	assert(s != NULL);
-	
-	while (*s != c && *s != '\0') {
-		s++;
-	}
-	
-	return (char *) s;
-}
-
-/**
- * Scan a string for a first occurence of one of provided bytes.
- *
- * @param s1 String in which to look for the bytes.
- * @param s2 String of bytes to look for.
- * @return Pointer to the found byte on success,
- *     NULL pointer otherwise.
- */
-char *posix_strpbrk(const char *s1, const char *s2)
-{
-	assert(s1 != NULL);
-	assert(s2 != NULL);
-
-	char *ptr = strpbrk_null(s1, s2);
-	return (*ptr == '\0') ? NULL : ptr;
-}
-
-/**
- * Get the length of a complementary substring.
- *
- * @param s1 String that shall be searched for complementary prefix.
- * @param s2 String of bytes that shall not occur in the prefix.
- * @return Length of the prefix.
- */
-size_t posix_strcspn(const char *s1, const char *s2)
-{
-	assert(s1 != NULL);
-	assert(s2 != NULL);
-
-	char *ptr = strpbrk_null(s1, s2);
-	return (size_t) (ptr - s1);
-}
-
-/**
- * Get length of a substring.
- *
- * @param s1 String that shall be searched for prefix.
- * @param s2 String of bytes that the prefix must consist of.
- * @return Length of the prefix.
- */
-size_t posix_strspn(const char *s1, const char *s2)
-{
-	assert(s1 != NULL);
-	assert(s2 != NULL);
-
-	const char *ptr;
-	for (ptr = s1; *ptr != '\0'; ++ptr) {
-		if (!posix_strchr(s2, *ptr)) {
-			break;
-		}
-	}
-	return ptr - s1;
-}
-
-/**
- * Find a substring. Uses Knuth-Morris-Pratt algorithm.
- *
- * @param s1 String in which to look for a substring.
- * @param s2 Substring to look for.
- * @return Pointer to the first character of the substring in s1, or NULL if
- *     not found.
- */
-char *posix_strstr(const char *haystack, const char *needle)
-{
-	assert(haystack != NULL);
-	assert(needle != NULL);
-	
-	/* Special case - needle is an empty string. */
-	if (needle[0] == '\0') {
-		return (char *) haystack;
-	}
-	
-	/* Preprocess needle. */
-	size_t nlen = posix_strlen(needle);
-	size_t prefix_table[nlen + 1];
-	
-	{
-		size_t i = 0;
-		ssize_t j = -1;
-		
-		prefix_table[i] = j;
-		
-		while (i < nlen) {
-			while (j >= 0 && needle[i] != needle[j]) {
-				j = prefix_table[j];
-			}
-			i++; j++;
-			prefix_table[i] = j;
-		}
-	}
-	
-	/* Search needle using the precomputed table. */
-	size_t npos = 0;
-	
-	for (size_t hpos = 0; haystack[hpos] != '\0'; ++hpos) {
-		while (npos != 0 && haystack[hpos] != needle[npos]) {
-			npos = prefix_table[npos];
-		}
-		
-		if (haystack[hpos] == needle[npos]) {
-			npos++;
-			
-			if (npos == nlen) {
-				return (char *) (haystack + hpos - nlen + 1);
-			}
-		}
-	}
-	
-	return NULL;
-}
-
-/**
- * String comparison using collating information.
- *
- * Currently ignores locale and just calls strcmp.
- *
- * @param s1 First string to be compared.
- * @param s2 Second string to be compared.
- * @return Difference of the first pair of inequal characters,
- *     or 0 if strings have the same content.
- */
-int posix_strcoll(const char *s1, const char *s2)
-{
-	assert(s1 != NULL);
-	assert(s2 != NULL);
-
-	return posix_strcmp(s1, s2);
-}
-
-/**
- * Transform a string in such a way that the resulting string yields the same
- * results when passed to the strcmp as if the original string is passed to
- * the strcoll.
- *
- * Since strcoll is equal to strcmp here, this just makes a copy.
- *
- * @param s1 Transformed string.
- * @param s2 Original string.
- * @param n Maximum length of the transformed string.
- * @return Length of the transformed string.
- */
-size_t posix_strxfrm(char *restrict s1, const char *restrict s2, size_t n)
-{
-	assert(s1 != NULL || n == 0);
-	assert(s2 != NULL);
-
-	size_t len = posix_strlen(s2);
-
-	if (n > len) {
-		posix_strcpy(s1, s2);
-	}
-
-	return len;
-}
-
-/**
- * Get error message string.
- *
- * @param errnum Error code for which to obtain human readable string.
- * @return Error message.
- */
-char *posix_strerror(int errnum)
-{
-	static const char *error_msgs[] = {
-		[E2BIG] = "[E2BIG] Argument list too long",
-		[EACCES] = "[EACCES] Permission denied",
-		[EADDRINUSE] = "[EADDRINUSE] Address in use",
-		[EADDRNOTAVAIL] = "[EADDRNOTAVAIL] Address not available",
-		[EAFNOSUPPORT] = "[EAFNOSUPPORT] Address family not supported",
-		[EAGAIN] = "[EAGAIN] Resource unavailable, try again",
-		[EALREADY] = "[EALREADY] Connection already in progress",
-		[EBADF] = "[EBADF] Bad file descriptor",
-		[EBADMSG] = "[EBADMSG] Bad message",
-		[EBUSY] = "[EBUSY] Device or resource busy",
-		[ECANCELED] = "[ECANCELED] Operation canceled",
-		[ECHILD] = "[ECHILD] No child processes",
-		[ECONNABORTED] = "[ECONNABORTED] Connection aborted",
-		[ECONNREFUSED] = "[ECONNREFUSED] Connection refused",
-		[ECONNRESET] = "[ECONNRESET] Connection reset",
-		[EDEADLK] = "[EDEADLK] Resource deadlock would occur",
-		[EDESTADDRREQ] = "[EDESTADDRREQ] Destination address required",
-		[EDOM] = "[EDOM] Mathematics argument out of domain of function",
-		[EDQUOT] = "[EDQUOT] Reserved",
-		[EEXIST] = "[EEXIST] File exists",
-		[EFAULT] = "[EFAULT] Bad address",
-		[EFBIG] = "[EFBIG] File too large",
-		[EHOSTUNREACH] = "[EHOSTUNREACH] Host is unreachable",
-		[EIDRM] = "[EIDRM] Identifier removed",
-		[EILSEQ] = "[EILSEQ] Illegal byte sequence",
-		[EINPROGRESS] = "[EINPROGRESS] Operation in progress",
-		[EINTR] = "[EINTR] Interrupted function",
-		[EINVAL] = "[EINVAL] Invalid argument",
-		[EIO] = "[EIO] I/O error",
-		[EISCONN] = "[EISCONN] Socket is connected",
-		[EISDIR] = "[EISDIR] Is a directory",
-		[ELOOP] = "[ELOOP] Too many levels of symbolic links",
-		[EMFILE] = "[EMFILE] File descriptor value too large",
-		[EMLINK] = "[EMLINK] Too many links",
-		[EMSGSIZE] = "[EMSGSIZE] Message too large",
-		[EMULTIHOP] = "[EMULTIHOP] Reserved",
-		[ENAMETOOLONG] = "[ENAMETOOLONG] Filename too long",
-		[ENETDOWN] = "[ENETDOWN] Network is down",
-		[ENETRESET] = "[ENETRESET] Connection aborted by network",
-		[ENETUNREACH] = "[ENETUNREACH] Network unreachable",
-		[ENFILE] = "[ENFILE] Too many files open in system",
-		[ENOBUFS] = "[ENOBUFS] No buffer space available",
-		[ENODATA] = "[ENODATA] No message is available on the STREAM head read queue",
-		[ENODEV] = "[ENODEV] No such device",
-		[ENOENT] = "[ENOENT] No such file or directory",
-		[ENOEXEC] = "[ENOEXEC] Executable file format error",
-		[ENOLCK] = "[ENOLCK] No locks available",
-		[ENOLINK] = "[ENOLINK] Reserved",
-		[ENOMEM] = "[ENOMEM] Not enough space",
-		[ENOMSG] = "[ENOMSG] No message of the desired type",
-		[ENOPROTOOPT] = "[ENOPROTOOPT] Protocol not available",
-		[ENOSPC] = "[ENOSPC] No space left on device",
-		[ENOSR] = "[ENOSR] No STREAM resources.",
-		[ENOSTR] = "[ENOSTR] Not a STREAM",
-		[ENOSYS] = "[ENOSYS] Function not supported",
-		[ENOTCONN] = "[ENOTCONN] The socket is not connected",
-		[ENOTDIR] = "[ENOTDIR] Not a directory",
-		[ENOTEMPTY] = "[ENOTEMPTY] Directory not empty",
-		[ENOTRECOVERABLE] = "[ENOTRECOVERABLE] State not recoverable",
-		[ENOTSOCK] = "[ENOTSOCK] Not a socket",
-		[ENOTSUP] = "[ENOTSUP] Not supported",
-		[ENOTTY] = "[ENOTTY] Inappropriate I/O control operation",
-		[ENXIO] = "[ENXIO] No such device or address",
-		[EOPNOTSUPP] = "[EOPNOTSUPP] Operation not supported",
-		[EOVERFLOW] = "[EOVERFLOW] Value too large to be stored in data type",
-		[EOWNERDEAD] = "[EOWNERDEAD] Previous owned died",
-		[EPERM] = "[EPERM] Operation not permitted",
-		[EPIPE] = "[EPIPE] Broken pipe",
-		[EPROTO] = "[EPROTO] Protocol error",
-		[EPROTONOSUPPORT] = "[EPROTONOSUPPORT] Protocol not supported",
-		[EPROTOTYPE] = "[EPROTOTYPE] Protocol wrong type for socket",
-		[ERANGE] = "[ERANGE] Result too large",
-		[EROFS] = "[EROFS] Read-only file system",
-		[ESPIPE] = "[ESPIPE] Invalid seek",
-		[ESRCH] = "[ESRCH] No such process",
-		[ESTALE] = "[ESTALE] Reserved",
-		[ETIME] = "[ETIME] Stream ioctl() timeout",
-		[ETIMEDOUT] = "[ETIMEDOUT] Connection timed out",
-		[ETXTBSY] = "[ETXTBSY] Text file busy",
-		[EWOULDBLOCK] = "[EWOULDBLOCK] Operation would block",
-		[EXDEV] = "[EXDEV] Cross-device link",
-	};
-
-	return (char *) error_msgs[posix_abs(errnum)];
-}
-
-/**
- * Get error message string.
- *
- * @param errnum Error code for which to obtain human readable string.
- * @param buf Buffer to store a human readable string to.
- * @param bufsz Size of buffer pointed to by buf.
- * @return Zero on success, errno otherwise.
- */
-int posix_strerror_r(int errnum, char *buf, size_t bufsz)
-{
-	assert(buf != NULL);
-	
-	char *errstr = posix_strerror(errnum);
-	
-	if (posix_strlen(errstr) + 1 > bufsz) {
-		return ERANGE;
-	} else {
-		posix_strcpy(buf, errstr);
-	}
-
-	return 0;
-}
-
-/**
- * Get length of the string.
- *
- * @param s String which length shall be determined.
- * @return Length of the string.
- */
-size_t posix_strlen(const char *s)
-{
-	assert(s != NULL);
-	
-	return (size_t) (posix_strchr(s, '\0') - s);
-}
-
-/**
- * Get limited length of the string.
- *
- * @param s String which length shall be determined.
- * @param n Maximum number of bytes that can be examined to determine length.
- * @return The lower of either string length or n limit.
- */
-size_t posix_strnlen(const char *s, size_t n)
-{
-	assert(s != NULL);
-	
-	for (size_t sz = 0; sz < n; ++sz) {
-		
-		if (s[sz] == '\0') {
-			return sz;
-		}
-	}
-	
-	return n;
-}
-
-/**
- * Get description of a signal.
- *
- * @param signum Signal number.
- * @return Human readable signal description.
- */
-char *posix_strsignal(int signum)
-{
-	static const char *const sigstrings[] = {
-		[SIGABRT] = "SIGABRT (Process abort signal)",
-		[SIGALRM] = "SIGALRM (Alarm clock)",
-		[SIGBUS] = "SIGBUS (Access to an undefined portion of a memory object)",
-		[SIGCHLD] = "SIGCHLD (Child process terminated, stopped, or continued)",
-		[SIGCONT] = "SIGCONT (Continue executing, if stopped)",
-		[SIGFPE] = "SIGFPE (Erroneous arithmetic operation)",
-		[SIGHUP] = "SIGHUP (Hangup)",
-		[SIGILL] = "SIGILL (Illegal instruction)",
-		[SIGINT] = "SIGINT (Terminal interrupt signal)",
-		[SIGKILL] = "SIGKILL (Kill process)",
-		[SIGPIPE] = "SIGPIPE (Write on a pipe with no one to read it)",
-		[SIGQUIT] = "SIGQUIT (Terminal quit signal)",
-		[SIGSEGV] = "SIGSEGV (Invalid memory reference)",
-		[SIGSTOP] = "SIGSTOP (Stop executing)",
-		[SIGTERM] = "SIGTERM (Termination signal)",
-		[SIGTSTP] = "SIGTSTP (Terminal stop signal)",
-		[SIGTTIN] = "SIGTTIN (Background process attempting read)",
-		[SIGTTOU] = "SIGTTOU (Background process attempting write)",
-		[SIGUSR1] = "SIGUSR1 (User-defined signal 1)",
-		[SIGUSR2] = "SIGUSR2 (User-defined signal 2)",
-		[SIGPOLL] = "SIGPOLL (Pollable event)",
-		[SIGPROF] = "SIGPROF (Profiling timer expired)",
-		[SIGSYS] = "SIGSYS (Bad system call)",
-		[SIGTRAP] = "SIGTRAP (Trace/breakpoint trap)",
-		[SIGURG] = "SIGURG (High bandwidth data is available at a socket)",
-		[SIGVTALRM] = "SIGVTALRM (Virtual timer expired)",
-		[SIGXCPU] = "SIGXCPU (CPU time limit exceeded)",
-		[SIGXFSZ] = "SIGXFSZ (File size limit exceeded)"
-	};
-
-	if (signum <= _TOP_SIGNAL) {
-		return (char *) sigstrings[signum];
-	}
-
-	return (char *) "ERROR, Invalid signal number";
-}
-
-/** @}
- */
Index: pace/lib/posix/string.h
===================================================================
--- uspace/lib/posix/string.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,155 +1,0 @@
-/*
- * Copyright (c) 2011 Petr Koupy
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 String manipulation.
- */
-
-#ifndef POSIX_STRING_H_
-#define POSIX_STRING_H_
-
-#include <mem.h>
-#include <str.h>
-
-/* available in str.h
- *
- * char *strtok(char *restrict, const char *restrict);
- * char *strtok_r(char *restrict, const char *restrict, char **restrict);
- *
- * available in mem.h
- *
- * void *memset(void *, int, size_t);
- * void *memcpy(void *, const void *, size_t);
- * void *memmove(void *, const void *, size_t);
- *
- * TODO: not implemented due to missing locale support
- *
- * int      strcoll_l(const char *, const char *, locale_t);
- * char    *strerror_l(int, locale_t);
- * size_t   strxfrm_l(char *restrict, const char *restrict, size_t, locale_t);
- */
-
-#ifndef NULL
-	#define NULL  ((void *) 0)
-#endif
-
-/* Copying and Concatenation */
-extern char *posix_strcpy(char *restrict dest, const char *restrict src);
-extern char *posix_strncpy(char *restrict dest, const char *restrict src, size_t n);
-extern char *posix_stpcpy(char *restrict dest, const char *restrict src);
-extern char *posix_stpncpy(char *restrict dest, const char *restrict src, size_t n);
-extern char *posix_strcat(char *restrict dest, const char *restrict src);
-extern char *posix_strncat(char *restrict dest, const char *restrict src, size_t n);
-extern void *posix_memccpy(void *restrict dest, const void *restrict src, int c, size_t n);
-extern char *posix_strdup(const char *s);
-extern char *posix_strndup(const char *s, size_t n);
-
-/* String/Array Comparison */
-extern int posix_memcmp(const void *mem1, const void *mem2, size_t n);
-extern int posix_strcmp(const char *s1, const char *s2);
-extern int posix_strncmp(const char *s1, const char *s2, size_t n);
-
-/* Search Functions */
-extern void *posix_memchr(const void *mem, int c, size_t n);
-extern char *posix_strchr(const char *s, int c);
-extern char *posix_strrchr(const char *s, int c);
-extern char *gnu_strchrnul(const char *s, int c);
-extern char *posix_strpbrk(const char *s1, const char *s2);
-extern size_t posix_strcspn(const char *s1, const char *s2);
-extern size_t posix_strspn(const char *s1, const char *s2);
-extern char *posix_strstr(const char *haystack, const char *needle);
-
-/* Collation Functions */
-extern int posix_strcoll(const char *s1, const char *s2);
-extern size_t posix_strxfrm(char *restrict s1, const char *restrict s2, size_t n);
-
-/* Error Messages */
-extern char *posix_strerror(int errnum);
-extern int posix_strerror_r(int errnum, char *buf, size_t bufsz);
-
-/* String Length */
-extern size_t posix_strlen(const char *s);
-extern size_t posix_strnlen(const char *s, size_t n);
-
-/* Signal Messages */
-extern char *posix_strsignal(int signum);
-
-/* Legacy Declarations */
-#ifndef POSIX_STRINGS_H_
-extern int posix_ffs(int i);
-extern int posix_strcasecmp(const char *s1, const char *s2);
-extern int posix_strncasecmp(const char *s1, const char *s2, size_t n);
-#endif
-
-#ifndef LIBPOSIX_INTERNAL
-	#define strcpy posix_strcpy
-	#define strncpy posix_strncpy
-	#define stpcpy posix_stpcpy
-	#define stpncpy posix_stpncpy
-	#define strcat posix_strcat
-	#define strncat posix_strncat
-	#define memccpy posix_memccpy
-	#define strdup posix_strdup
-	#define strndup posix_strndup
-
-	#define memcmp posix_memcmp
-	#define strcmp posix_strcmp
-	#define strncmp posix_strncmp
-
-	#define memchr posix_memchr
-	#define strchr posix_strchr
-	#define strrchr posix_strrchr
-	#define strchrnul gnu_strchrnul
-	#define strpbrk posix_strpbrk
-	#define strcspn posix_strcspn
-	#define strspn posix_strspn
-	#define strstr posix_strstr
-
-	#define strcoll posix_strcoll
-	#define strxfrm posix_strxfrm
-
-	#define strerror posix_strerror
-	#define strerror_r posix_strerror_r
-
-	#define strlen posix_strlen
-	#define strnlen posix_strnlen
-
-	#define strsignal posix_strsignal
-
-	#define ffs posix_ffs
-	#define strcasecmp posix_strcasecmp
-	#define strncasecmp posix_strncasecmp
-#endif
-
-#endif  // POSIX_STRING_H_
-
-/** @}
- */
Index: pace/lib/posix/strings.c
===================================================================
--- uspace/lib/posix/strings.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,187 +1,0 @@
-/*
- * 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 Additional string manipulation.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "internal/common.h"
-#include "strings.h"
-
-#include "string.h"
-#include "ctype.h"
-
-#include "libc/mem.h"
-
-/**
- * Find first set bit (beginning with the least significant bit).
- *
- * @param i Integer in which to look for the first set bit.
- * @return Index of first set bit. Bits are numbered starting at one.
- */
-int posix_ffs(int i)
-{
-	if (i == 0) {
-		return 0;
-	}
-
-	int result = 0;
-
-	// XXX: assumes at most 32-bit int
-	if (!(i & 0xFFFF)) {
-		result |= 16;
-		i >>= 16;
-	}
-	if (!(i & 0xFF)) {
-		result |= 8;
-		i >>= 8;
-	}
-	if (!(i & 0xF)) {
-		result |= 4;
-		i >>= 4;
-	}
-	if (!(i & 0x3)) {
-		result |= 2;
-		i >>= 2;
-	}
-	if (!(i & 0x1)) {
-		result |= 1;
-	}
-
-	return result + 1;
-}
-
-/**
- * Compare two strings (case-insensitive).
- *
- * @param s1 First string to be compared.
- * @param s2 Second string to be compared.
- * @return Difference of the first pair of inequal characters,
- *     or 0 if strings have the same content.
- */
-int posix_strcasecmp(const char *s1, const char *s2)
-{
-	return posix_strncasecmp(s1, s2, STR_NO_LIMIT);
-}
-
-/**
- * Compare part of two strings (case-insensitive).
- *
- * @param s1 First string to be compared.
- * @param s2 Second string to be compared.
- * @param n Maximum number of characters to be compared.
- * @return Difference of the first pair of inequal characters,
- *     or 0 if strings have the same content.
- */
-int posix_strncasecmp(const char *s1, const char *s2, size_t n)
-{
-	for (size_t i = 0; i < n; ++i) {
-		int cmp = tolower(s1[i]) - tolower(s2[i]);
-		if (cmp != 0) {
-			return cmp;
-		}
-		
-		if (s1[i] == 0) {
-			return 0;
-		}
-	}
-	
-	return 0;
-}
-
-/**
- * Compare two memory areas.
- *
- * @param mem1 Pointer to the first area to compare.
- * @param mem2 Pointer to the second area to compare.
- * @param n Common size of both areas.
- * @return If n is 0, return zero. If the areas match, return
- *     zero. Otherwise return non-zero.
- */
-int posix_bcmp(const void *mem1, const void *mem2, size_t n)
-{
-	return bcmp(mem1, mem2, n);
-}
-
-/**
- * Copy bytes in memory with overlapping areas.
- *
- * @param src Source area.
- * @param dest Destination area.
- * @param n Number of bytes to copy.
- */
-void posix_bcopy(const void *src, void *dest, size_t n)
-{
-	/* Note that memmove has different order of arguments. */
-	memmove(dest, src, n);
-}
-
-/**
- * Reset bytes in memory area to zero.
- *
- * @param mem Memory area to be zeroed.
- * @param n Number of bytes to reset.
- */
-void posix_bzero(void *mem, size_t n)
-{
-	bzero(mem, n);
-}
-
-/**
- * Scan string for a first occurence of a character.
- *
- * @param s String in which to look for the character.
- * @param c Character to look for.
- * @return Pointer to the specified character on success,
- *     NULL pointer otherwise.
- */
-char *posix_index(const char *s, int c)
-{
-	return posix_strchr(s, c);
-}
-
-/**
- * Scan string for a last occurence of a character.
- *
- * @param s String in which to look for the character.
- * @param c Character to look for.
- * @return Pointer to the specified character on success,
- *     NULL pointer otherwise.
- */
-char *posix_rindex(const char *s, int c)
-{
-	return posix_strrchr(s, c);
-}
-
-/** @}
- */
Index: pace/lib/posix/strings.h
===================================================================
--- uspace/lib/posix/strings.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,80 +1,0 @@
-/*
- * 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 Additional string manipulation.
- */
-
-#ifndef POSIX_STRINGS_H_
-#define POSIX_STRINGS_H_
-
-/* Search Functions */
-#ifndef POSIX_STRING_H_
-extern int posix_ffs(int i);
-#endif
-
-/* String/Array Comparison */
-#ifndef POSIX_STRING_H_
-extern int posix_strcasecmp(const char *s1, const char *s2);
-extern int posix_strncasecmp(const char *s1, const char *s2, size_t n);
-#endif
-
-/* TODO: not implemented due to missing locale support
- *
- * int strcasecmp_l(const char *, const char *, locale_t);
- * int strncasecmp_l(const char *, const char *, size_t, locale_t);
- */
-
-/* Legacy Functions */
-extern int posix_bcmp(const void *mem1, const void *mem2, size_t n);
-extern void posix_bcopy(const void *src, void *dest, size_t n);
-extern void posix_bzero(void *mem, size_t n);
-extern char *posix_index(const char *s, int c);
-extern char *posix_rindex(const char *s, int c);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define ffs posix_ffs
-
-	#define strcasecmp posix_strcasecmp
-	#define strncasecmp posix_strncasecmp
-
-	#define bcmp posix_bcmp
-	#define bcopy posix_bcopy
-	#undef bzero
-	#define bzero posix_bzero
-	#define index posix_index
-	#define rindex posix_rindex
-#endif
-
-#endif  // POSIX_STRINGS_H_
-
-/** @}
- */
Index: pace/lib/posix/sys/mman.h
===================================================================
--- uspace/lib/posix/sys/mman.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,52 +1,0 @@
-/*
- * 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 Memory management declarations.
- */
-
-#ifndef POSIX_SYS_MMAN_H_
-#define POSIX_SYS_MMAN_H_
-
-#include "../libc/sys/mman.h"
-
-#undef PROT_NONE
-#undef PROT_READ
-#undef PROT_WRITE
-#undef PROT_EXEC
-#define PROT_NONE  0
-#define PROT_READ  PROTO_READ
-#define PROT_WRITE PROTO_WRITE
-#define PROT_EXEC  PROTO_EXEC
-
-#endif /* POSIX_SYS_MMAN_H_ */
-
-/** @}
- */
Index: pace/lib/posix/sys/stat.c
===================================================================
--- uspace/lib/posix/sys/stat.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,150 +1,0 @@
-/*
- * 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 File status handling.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "../internal/common.h"
-#include "stat.h"
-
-#include "../errno.h"
-#include "../libc/mem.h"
-
-/**
- * Convert HelenOS stat struct into POSIX stat struct (if possible).
- *
- * @param dest POSIX stat struct.
- * @param src HelenOS stat struct.
- */
-static void stat_to_posix(struct posix_stat *dest, struct stat *src)
-{
-	memset(dest, 0, sizeof(struct posix_stat));
-	
-	dest->st_dev = src->service;
-	dest->st_ino = src->index;
-	
-	/* HelenOS doesn't support permissions, so we set them all */
-	dest->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
-	if (src->is_file) {
-		dest->st_mode |= S_IFREG;
-	}
-	if (src->is_directory) {
-		dest->st_mode |= S_IFDIR;
-	}
-	
-	dest->st_nlink = src->lnkcnt;
-	dest->st_size = src->size;
-}
-
-/**
- * Retrieve file status for file associated with file descriptor.
- *
- * @param fd File descriptor of the opened file.
- * @param st Status structure to be filled with information.
- * @return Zero on success, -1 otherwise.
- */
-int posix_fstat(int fd, struct posix_stat *st)
-{
-	struct stat hst;
-	int rc = fstat(fd, &hst);
-	if (rc < 0) {
-		/* fstat() returns negative error code instead of using errno. */
-		errno = -rc;
-		return -1;
-	}
-	stat_to_posix(st, &hst);
-	return 0;
-}
-
-/**
- * Retrieve file status for symbolic link.
- * 
- * @param path Path to the symbolic link.
- * @param st Status structure to be filled with information.
- * @return Zero on success, -1 otherwise.
- */
-int posix_lstat(const char *restrict path, struct posix_stat *restrict st)
-{
-	/* There are currently no symbolic links in HelenOS. */
-	return posix_stat(path, st);
-}
-
-/**
- * Retrieve file status for regular file (or symbolic link target).
- *
- * @param path Path to the file/link.
- * @param st Status structure to be filled with information.
- * @return Zero on success, -1 otherwise.
- */
-int posix_stat(const char *restrict path, struct posix_stat *restrict st)
-{
-	struct stat hst;
-	int rc = stat(path, &hst);
-	if (rc < 0) {
-		/* stat() returns negative error code instead of using errno. */
-		errno = -rc;
-		return -1;
-	}
-	stat_to_posix(st, &hst);
-	return 0;
-}
-
-/**
- * Change permission bits for the file if possible.
- * 
- * @param path Path to the file.
- * @param mode Permission bits to be set.
- * @return Zero on success, -1 otherwise.
- */
-int posix_chmod(const char *path, mode_t mode)
-{
-	/* HelenOS doesn't support permissions, return success. */
-	return 0;
-}
-
-/**
- * Set the file mode creation mask of the process.
- * 
- * @param mask Set permission bits are cleared in the related creation
- *     functions. Non-permission bits are ignored.
- * @return Previous file mode creation mask.
- */
-mode_t posix_umask(mode_t mask)
-{
-	/* HelenOS doesn't support permissions, return empty mask. */
-	return 0;
-}
-
-/** @}
- */
Index: pace/lib/posix/sys/stat.h
===================================================================
--- uspace/lib/posix/sys/stat.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,144 +1,0 @@
-/*
- * 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 File status handling.
- */
-
-#ifndef POSIX_SYS_STAT_H_
-#define POSIX_SYS_STAT_H_
-
-#include "../libc/sys/stat.h"
-#include "types.h"
-#include "../time.h"
-
-/* values are the same as on Linux */
-
-#undef S_IFMT
-#undef S_IFSOCK
-#undef S_IFLNK
-#undef S_IFREG
-#undef S_IFBLK
-#undef S_IFDIR
-#undef S_IFCHR
-#undef S_IFIFO
-#define S_IFMT     0170000   /* all file types */
-#define S_IFSOCK   0140000   /* socket */
-#define S_IFLNK    0120000   /* symbolic link */
-#define S_IFREG    0100000   /* regular file */
-#define S_IFBLK    0060000   /* block device */
-#define S_IFDIR    0040000   /* directory */
-#define S_IFCHR    0020000   /* character device */
-#define S_IFIFO    0010000   /* FIFO */
-
-#undef S_ISUID
-#undef S_ISGID
-#undef S_ISVTX
-#define S_ISUID    0004000   /* SUID */
-#define S_ISGID    0002000   /* SGID */
-#define S_ISVTX    0001000   /* sticky */
-
-#undef S_IRWXU
-#undef S_IRUSR
-#undef S_IWUSR
-#undef S_IXUSR
-#define S_IRWXU    00700     /* owner permissions */
-#define S_IRUSR    00400
-#define S_IWUSR    00200
-#define S_IXUSR    00100
-
-#undef S_IRWXG
-#undef S_IRGRP
-#undef S_IWGRP
-#undef S_IXGRP
-#define S_IRWXG    00070     /* group permissions */
-#define S_IRGRP    00040
-#define S_IWGRP    00020
-#define S_IXGRP    00010
-
-#undef S_IRWXO
-#undef S_IROTH
-#undef S_IWOTH
-#undef S_IXOTH
-#define S_IRWXO    00007     /* other permissions */
-#define S_IROTH    00004
-#define S_IWOTH    00002
-#define S_IXOTH    00001
-
-#undef S_ISREG
-#undef S_ISDIR
-#undef S_ISCHR
-#undef S_ISBLK
-#undef S_ISFIFO
-#undef S_ISLNK
-#undef S_ISSOCK
-#define S_ISREG(m) ((m & S_IFREG) != 0)
-#define S_ISDIR(m) ((m & S_IFDIR) != 0)
-#define S_ISCHR(m) ((m & S_IFCHR) != 0)
-#define S_ISBLK(m) ((m & S_IFBLK) != 0)
-#define S_ISFIFO(m) ((m & S_IFIFO) != 0)
-#define S_ISLNK(m) ((m & S_IFLNK) != 0) /* symbolic link? (Not in POSIX.1-1996.) */
-#define S_ISSOCK(m) ((m & S_IFSOCK) != 0) /* socket? (Not in POSIX.1-1996.) */
-
-struct posix_stat {
-	posix_dev_t     st_dev;     /* ID of device containing file */
-	posix_ino_t     st_ino;     /* inode number */
-	mode_t          st_mode;    /* protection */
-	posix_nlink_t   st_nlink;   /* number of hard links */
-	posix_uid_t     st_uid;     /* user ID of owner */
-	posix_gid_t     st_gid;     /* group ID of owner */
-	posix_dev_t     st_rdev;    /* device ID (if special file) */
-	posix_off_t     st_size;    /* total size, in bytes */
-	posix_blksize_t st_blksize; /* blocksize for file system I/O */
-	posix_blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
-	time_t          st_atime;   /* time of last access */
-	time_t          st_mtime;   /* time of last modification */
-	time_t          st_ctime;   /* time of last status change */
-};
-
-extern int posix_fstat(int fd, struct posix_stat *st);
-extern int posix_lstat(const char *restrict path, struct posix_stat *restrict st);
-extern int posix_stat(const char *restrict path, struct posix_stat *restrict st);
-extern int posix_chmod(const char *path, mode_t mode);
-extern mode_t posix_umask(mode_t mask);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define fstat posix_fstat
-	#define lstat posix_lstat
-	#define stat posix_stat
-	#define chmod posix_chmod
-	#define umask posix_umask
-#endif
-
-#endif /* POSIX_SYS_STAT_H */
-
-/** @}
- */
Index: pace/lib/posix/sys/types.h
===================================================================
--- uspace/lib/posix/sys/types.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,78 +1,0 @@
-/*
- * 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 Data types definitions.
- */
-
-#ifndef POSIX_SYS_TYPES_H_
-#define POSIX_SYS_TYPES_H_
-
-#include "../libc/sys/types.h"
-
-typedef unsigned int posix_ino_t;
-typedef unsigned int posix_nlink_t;
-typedef unsigned int posix_uid_t;
-typedef unsigned int posix_gid_t;
-typedef off64_t posix_off_t;
-typedef long posix_blksize_t;
-typedef long posix_blkcnt_t;
-typedef int64_t posix_pid_t;
-typedef sysarg_t posix_dev_t;
-
-/* PThread Types */
-typedef struct posix_thread_attr posix_thread_attr_t;
-
-/* Clock Types */
-typedef long posix_clock_t;
-typedef int posix_clockid_t;
-
-#ifndef LIBPOSIX_INTERNAL
-	#define ino_t posix_ino_t
-	#define nlink_t posix_nlink_t
-	#define uid_t posix_uid_t
-	#define gid_t posix_gid_t
-	#define off_t posix_off_t
-	#define blksize_t posix_blksize_t
-	#define blkcnt_t posix_blkcnt_t
-	#define pid_t posix_pid_t
-	#define dev_t posix_dev_t
-	
-	#define pthread_attr_t posix_thread_attr_t
-	
-	#define clock_t posix_clock_t
-	#define clockid_t posix_clockid_t
-#endif
-
-#endif /* POSIX_SYS_TYPES_H_ */
-
-/** @}
- */
Index: pace/lib/posix/sys/wait.c
===================================================================
--- uspace/lib/posix/sys/wait.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,122 +1,0 @@
-/*
- * Copyright (c) 2011 Petr Koupy
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Support for waiting.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "../internal/common.h"
-#include "wait.h"
-
-#include "../libc/task.h"
-#include "../assert.h"
-#include "../errno.h"
-#include "../limits.h"
-#include "../signal.h"
-
-int __posix_wifexited(int status) {
-	return status != INT_MIN;
-}
-
-int __posix_wexitstatus(int status) {
-	assert(__posix_wifexited(status));
-	return status;
-}
-
-int __posix_wifsignaled(int status) {
-	return status == INT_MIN;
-}
-
-int __posix_wtermsig(int status) {
-	assert(__posix_wifsignaled(status));
-	/* There is no way to distinguish reason
-	 * for unexpected termination at the moment.
-	 */
-	return SIGABRT;
-}
-
-/**
- * Wait for any child process to stop or terminate.
- * 
- * @param stat_ptr Location of the final status code of the child process.
- * @return ID of the child process for which status is reported,
- *     -1 on signal interrupt, (pid_t)-1 otherwise.
- */
-posix_pid_t posix_wait(int *stat_ptr)
-{
-	/* HelenOS does not support this. */
-	errno = ENOSYS;
-	return (posix_pid_t) -1;
-}
-
-/**
- * Wait for a child process to stop or terminate.
- * 
- * @param pid What child process shall the caller wait for. See POSIX manual
- *     for details.
- * @param stat_ptr Location of the final status code of the child process.
- * @param options Constraints of the waiting. See POSIX manual for details.
- * @return ID of the child process for which status is reported,
- *     -1 on signal interrupt, 0 if non-blocking wait is requested but there is
- *     no child process whose status can be reported, (pid_t)-1 otherwise.
- */
-posix_pid_t posix_waitpid(posix_pid_t pid, int *stat_ptr, int options)
-{
-	assert(stat_ptr != NULL);
-	assert(options == 0 /* None of the options are supported. */);
-	
-	task_exit_t texit;
-	int retval;
-	
-	int rc = task_wait((task_id_t) pid, &texit, &retval);
-	
-	if (rc < 0) {
-		/* Unable to retrieve status. */
-		errno = -rc;
-		return (posix_pid_t) -1;
-	}
-	
-	if (texit == TASK_EXIT_NORMAL) {
-		// FIXME: relies on application not returning this value
-		assert(retval != INT_MIN);
-		*stat_ptr = retval;
-	} else {
-		/* Reserve the lowest value for unexpected termination. */
-		*stat_ptr = INT_MIN;
-	}
-	
-	return pid;
-}
-
-/** @}
- */
Index: pace/lib/posix/sys/wait.h
===================================================================
--- uspace/lib/posix/sys/wait.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,65 +1,0 @@
-/*
- * 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 Support for waiting.
- */
-
-#ifndef POSIX_SYS_WAIT_H_
-#define POSIX_SYS_WAIT_H_
-
-#include "types.h"
-
-#undef WIFEXITED
-#undef WEXITSTATUS
-#undef WIFSIGNALED
-#undef WTERMSIG
-#define WIFEXITED(status) __posix_wifexited(status)
-#define WEXITSTATUS(status) __posix_wexitstatus(status)
-#define WIFSIGNALED(status) __posix_wifsignaled(status)
-#define WTERMSIG(status) __posix_wtermsig(status)
-
-extern int __posix_wifexited(int status);
-extern int __posix_wexitstatus(int status);
-extern int __posix_wifsignaled(int status);
-extern int __posix_wtermsig(int status);
-
-extern posix_pid_t posix_wait(int *stat_ptr);
-extern posix_pid_t posix_waitpid(posix_pid_t pid, int *stat_ptr, int options);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define wait posix_wait
-	#define waitpid posix_waitpid
-#endif
-
-#endif /* POSIX_SYS_WAIT_H_ */
-
-/** @}
- */
Index: pace/lib/posix/time.c
===================================================================
--- uspace/lib/posix/time.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,905 +1,0 @@
-/*
- * Copyright (c) 2011 Petr Koupy
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Time measurement support.
- */
-
-#define LIBPOSIX_INTERNAL
-
-/* Must be first. */
-#include "stdbool.h"
-
-#include "internal/common.h"
-#include "time.h"
-
-#include "ctype.h"
-#include "errno.h"
-#include "signal.h"
-#include "assert.h"
-
-#include "libc/malloc.h"
-#include "libc/task.h"
-#include "libc/stats.h"
-#include "libc/sys/time.h"
-
-// TODO: test everything in this file
-
-/* In some places in this file, phrase "normalized broken-down time" is used.
- * This means time broken down to components (year, month, day, hour, min, sec),
- * in which every component is in its proper bounds. Non-normalized time could
- * e.g. be 2011-54-5 29:13:-5, which would semantically mean start of year 2011
- * + 53 months + 4 days + 29 hours + 13 minutes - 5 seconds.
- */
-
-
-
-/* Helper functions ***********************************************************/
-
-#define HOURS_PER_DAY (24)
-#define MINS_PER_HOUR (60)
-#define SECS_PER_MIN (60)
-#define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY)
-#define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR)
-#define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY)
-
-/**
- * Checks whether the year is a leap year.
- *
- * @param year Year since 1900 (e.g. for 1970, the value is 70).
- * @return true if year is a leap year, false otherwise
- */
-static bool _is_leap_year(time_t year)
-{
-	year += 1900;
-
-	if (year % 400 == 0)
-		return true;
-	if (year % 100 == 0)
-		return false;
-	if (year % 4 == 0)
-		return true;
-	return false;
-}
-
-/**
- * Returns how many days there are in the given month of the given year.
- * Note that year is only taken into account if month is February.
- *
- * @param year Year since 1900 (can be negative).
- * @param mon Month of the year. 0 for January, 11 for December.
- * @return Number of days in the specified month.
- */
-static int _days_in_month(time_t year, time_t mon)
-{
-	assert(mon >= 0 && mon <= 11);
-
-	static int month_days[] =
-		{ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
-	if (mon == 1) {
-		year += 1900;
-		/* february */
-		return _is_leap_year(year) ? 29 : 28;
-	} else {
-		return month_days[mon];
-	}
-}
-
-/**
- * For specified year, month and day of month, returns which day of that year
- * it is.
- *
- * For example, given date 2011-01-03, the corresponding expression is:
- *     _day_of_year(111, 0, 3) == 2
- *
- * @param year Year (year 1900 = 0, can be negative).
- * @param mon Month (January = 0).
- * @param mday Day of month (First day is 1).
- * @return Day of year (First day is 0).
- */
-static int _day_of_year(time_t year, time_t mon, time_t mday)
-{
-	static int mdays[] =
-	    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
-	static int leap_mdays[] =
-	    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
-
-	return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1;
-}
-
-/**
- * Integer division that rounds to negative infinity.
- * Used by some functions in this file.
- *
- * @param op1 Divident.
- * @param op2 Divisor.
- * @return Rounded quotient.
- */
-static time_t _floor_div(time_t op1, time_t op2)
-{
-	if (op1 >= 0 || op1 % op2 == 0) {
-		return op1 / op2;
-	} else {
-		return op1 / op2 - 1;
-	}
-}
-
-/**
- * Modulo that rounds to negative infinity.
- * Used by some functions in this file.
- *
- * @param op1 Divident.
- * @param op2 Divisor.
- * @return Remainder.
- */
-static time_t _floor_mod(time_t op1, time_t op2)
-{
-	int div = _floor_div(op1, op2);
-
-	/* (a / b) * b + a % b == a */
-	/* thus, a % b == a - (a / b) * b */
-
-	int result = op1 - div * op2;
-	
-	/* Some paranoid checking to ensure I didn't make a mistake here. */
-	assert(result >= 0);
-	assert(result < op2);
-	assert(div * op2 + result == op1);
-	
-	return result;
-}
-
-/**
- * Number of days since the Epoch.
- * Epoch is 1970-01-01, which is also equal to day 0.
- *
- * @param year Year (year 1900 = 0, may be negative).
- * @param mon Month (January = 0).
- * @param mday Day of month (first day = 1).
- * @return Number of days since the Epoch.
- */
-static time_t _days_since_epoch(time_t year, time_t mon, time_t mday)
-{
-	return (year - 70) * 365 + _floor_div(year - 69, 4) -
-	    _floor_div(year - 1, 100) + _floor_div(year + 299, 400) +
-	    _day_of_year(year, mon, mday);
-}
-
-/**
- * Seconds since the Epoch. see also _days_since_epoch().
- * 
- * @param tm Normalized broken-down time.
- * @return Number of seconds since the epoch, not counting leap seconds.
- */
-static time_t _secs_since_epoch(const struct posix_tm *tm)
-{
-	return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *
-	    SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR +
-	    tm->tm_min * SECS_PER_MIN + tm->tm_sec;
-}
-
-/**
- * Which day of week the specified date is.
- * 
- * @param year Year (year 1900 = 0).
- * @param mon Month (January = 0).
- * @param mday Day of month (first = 1).
- * @return Day of week (Sunday = 0).
- */
-static int _day_of_week(time_t year, time_t mon, time_t mday)
-{
-	/* 1970-01-01 is Thursday */
-	return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7);
-}
-
-/**
- * Normalizes the broken-down time and optionally adds specified amount of
- * seconds.
- * 
- * @param tm Broken-down time to normalize.
- * @param sec_add Seconds to add.
- * @return 0 on success, -1 on overflow
- */
-static int _normalize_time(struct posix_tm *tm, time_t sec_add)
-{
-	// TODO: DST correction
-
-	/* Set initial values. */
-	time_t sec = tm->tm_sec + sec_add;
-	time_t min = tm->tm_min;
-	time_t hour = tm->tm_hour;
-	time_t day = tm->tm_mday - 1;
-	time_t mon = tm->tm_mon;
-	time_t year = tm->tm_year;
-
-	/* Adjust time. */
-	min += _floor_div(sec, SECS_PER_MIN);
-	sec = _floor_mod(sec, SECS_PER_MIN);
-	hour += _floor_div(min, MINS_PER_HOUR);
-	min = _floor_mod(min, MINS_PER_HOUR);
-	day += _floor_div(hour, HOURS_PER_DAY);
-	hour = _floor_mod(hour, HOURS_PER_DAY);
-
-	/* Adjust month. */
-	year += _floor_div(mon, 12);
-	mon = _floor_mod(mon, 12);
-
-	/* Now the difficult part - days of month. */
-	
-	/* First, deal with whole cycles of 400 years = 146097 days. */
-	year += _floor_div(day, 146097) * 400;
-	day = _floor_mod(day, 146097);
-	
-	/* Then, go in one year steps. */
-	if (mon <= 1) {
-		/* January and February. */
-		while (day > 365) {
-			day -= _is_leap_year(year) ? 366 : 365;
-			year++;
-		}
-	} else {
-		/* Rest of the year. */
-		while (day > 365) {
-			day -= _is_leap_year(year + 1) ? 366 : 365;
-			year++;
-		}
-	}
-	
-	/* Finally, finish it off month per month. */
-	while (day >= _days_in_month(year, mon)) {
-		day -= _days_in_month(year, mon);
-		mon++;
-		if (mon >= 12) {
-			mon -= 12;
-			year++;
-		}
-	}
-	
-	/* Calculate the remaining two fields. */
-	tm->tm_yday = _day_of_year(year, mon, day + 1);
-	tm->tm_wday = _day_of_week(year, mon, day + 1);
-	
-	/* And put the values back to the struct. */
-	tm->tm_sec = (int) sec;
-	tm->tm_min = (int) min;
-	tm->tm_hour = (int) hour;
-	tm->tm_mday = (int) day + 1;
-	tm->tm_mon = (int) mon;
-	
-	/* Casts to work around libc brain-damage. */
-	if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) {
-		tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX);
-		return -1;
-	}
-	
-	tm->tm_year = (int) year;
-	return 0;
-}
-
-/**
- * Which day the week-based year starts on, relative to the first calendar day.
- * E.g. if the year starts on December 31st, the return value is -1.
- *
- * @param Year since 1900.
- * @return Offset of week-based year relative to calendar year.
- */
-static int _wbyear_offset(int year)
-{
-	int start_wday = _day_of_week(year, 0, 1);
-	return _floor_mod(4 - start_wday, 7) - 3;
-}
-
-/**
- * Returns week-based year of the specified time.
- *
- * @param tm Normalized broken-down time.
- * @return Week-based year.
- */
-static int _wbyear(const struct posix_tm *tm)
-{
-	int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
-	if (day < 0) {
-		/* Last week of previous year. */
-		return tm->tm_year - 1;
-	}
-	if (day > 364 + _is_leap_year(tm->tm_year)) {
-		/* First week of next year. */
-		return tm->tm_year + 1;
-	}
-	/* All the other days are in the calendar year. */
-	return tm->tm_year;
-}
-
-/**
- * Week number of the year, assuming weeks start on sunday.
- * The first Sunday of January is the first day of week 1;
- * days in the new year before this are in week 0.
- *
- * @param tm Normalized broken-down time.
- * @return The week number (0 - 53).
- */
-static int _sun_week_number(const struct posix_tm *tm)
-{
-	int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7;
-	return (tm->tm_yday - first_day + 7) / 7;
-}
-
-/**
- * Week number of the year, assuming weeks start on monday.
- * If the week containing January 1st has four or more days in the new year,
- * then it is considered week 1. Otherwise, it is the last week of the previous
- * year, and the next week is week 1. Both January 4th and the first Thursday
- * of January are always in week 1.
- *
- * @param tm Normalized broken-down time.
- * @return The week number (1 - 53).
- */
-static int _iso_week_number(const struct posix_tm *tm)
-{
-	int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
-	if (day < 0) {
-		/* Last week of previous year. */
-		return 53;
-	}
-	if (day > 364 + _is_leap_year(tm->tm_year)) {
-		/* First week of next year. */
-		return 1;
-	}
-	/* All the other days give correct answer. */
-	return (day / 7 + 1);
-}
-
-/**
- * Week number of the year, assuming weeks start on monday.
- * The first Monday of January is the first day of week 1;
- * days in the new year before this are in week 0. 
- *
- * @param tm Normalized broken-down time.
- * @return The week number (0 - 53).
- */
-static int _mon_week_number(const struct posix_tm *tm)
-{
-	int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7;
-	return (tm->tm_yday - first_day + 7) / 7;
-}
-
-/******************************************************************************/
-
-int posix_daylight;
-long posix_timezone;
-char *posix_tzname[2];
-
-/**
- * Set timezone conversion information.
- */
-void posix_tzset(void)
-{
-	// TODO: read environment
-	posix_tzname[0] = (char *) "GMT";
-	posix_tzname[1] = (char *) "GMT";
-	posix_daylight = 0;
-	posix_timezone = 0;
-}
-
-/**
- * Calculate the difference between two times, in seconds.
- * 
- * @param time1 First time.
- * @param time0 Second time.
- * @return Time in seconds.
- */
-double posix_difftime(time_t time1, time_t time0)
-{
-	return (double) (time1 - time0);
-}
-
-/**
- * This function first normalizes the provided broken-down time
- * (moves all values to their proper bounds) and then tries to
- * calculate the appropriate time_t representation.
- *
- * @param tm Broken-down time.
- * @return time_t representation of the time, undefined value on overflow.
- */
-time_t posix_mktime(struct posix_tm *tm)
-{
-	// TODO: take DST flag into account
-	// TODO: detect overflow
-
-	_normalize_time(tm, 0);
-	return _secs_since_epoch(tm);
-}
-
-/**
- * Converts a time value to a broken-down UTC time.
- *
- * @param timer Time to convert.
- * @return Normalized broken-down time in UTC, NULL on overflow.
- */
-struct posix_tm *posix_gmtime(const time_t *timer)
-{
-	assert(timer != NULL);
-
-	static struct posix_tm result;
-	return posix_gmtime_r(timer, &result);
-}
-
-/**
- * Converts a time value to a broken-down UTC time.
- * 
- * @param timer Time to convert.
- * @param result Structure to store the result to.
- * @return Value of result on success, NULL on overflow.
- */
-struct posix_tm *posix_gmtime_r(const time_t *restrict timer,
-    struct posix_tm *restrict result)
-{
-	assert(timer != NULL);
-	assert(result != NULL);
-
-	/* Set result to epoch. */
-	result->tm_sec = 0;
-	result->tm_min = 0;
-	result->tm_hour = 0;
-	result->tm_mday = 1;
-	result->tm_mon = 0;
-	result->tm_year = 70; /* 1970 */
-
-	if (_normalize_time(result, *timer) == -1) {
-		errno = EOVERFLOW;
-		return NULL;
-	}
-
-	return result;
-}
-
-/**
- * Converts a time value to a broken-down local time.
- *
- * @param timer Time to convert.
- * @return Normalized broken-down time in local timezone, NULL on overflow.
- */
-struct posix_tm *posix_localtime(const time_t *timer)
-{
-	static struct posix_tm result;
-	return posix_localtime_r(timer, &result);
-}
-
-/**
- * Converts a time value to a broken-down local time.
- * 
- * @param timer Time to convert.
- * @param result Structure to store the result to.
- * @return Value of result on success, NULL on overflow.
- */
-struct posix_tm *posix_localtime_r(const time_t *restrict timer,
-    struct posix_tm *restrict result)
-{
-	// TODO: deal with timezone
-	// currently assumes system and all times are in GMT
-	return posix_gmtime_r(timer, result);
-}
-
-/**
- * Converts broken-down time to a string in format
- * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
- *
- * @param timeptr Broken-down time structure.
- * @return Pointer to a statically allocated string.
- */
-char *posix_asctime(const struct posix_tm *timeptr)
-{
-	static char buf[ASCTIME_BUF_LEN];
-	return posix_asctime_r(timeptr, buf);
-}
-
-/**
- * Converts broken-down time to a string in format
- * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
- *
- * @param timeptr Broken-down time structure.
- * @param buf Buffer to store string to, must be at least ASCTIME_BUF_LEN
- *     bytes long.
- * @return Value of buf.
- */
-char *posix_asctime_r(const struct posix_tm *restrict timeptr,
-    char *restrict buf)
-{
-	assert(timeptr != NULL);
-	assert(buf != NULL);
-
-	static const char *wday[] = {
-		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-	};
-	static const char *mon[] = {
-		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
-		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-	};
-
-	snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n",
-	    wday[timeptr->tm_wday],
-	    mon[timeptr->tm_mon],
-	    timeptr->tm_mday, timeptr->tm_hour,
-	    timeptr->tm_min, timeptr->tm_sec,
-	    1900 + timeptr->tm_year);
-
-	return buf;
-}
-
-/**
- * Equivalent to asctime(localtime(clock)).
- * 
- * @param timer Time to convert.
- * @return Pointer to a statically allocated string holding the date.
- */
-char *posix_ctime(const time_t *timer)
-{
-	struct posix_tm *loctime = posix_localtime(timer);
-	if (loctime == NULL) {
-		return NULL;
-	}
-	return posix_asctime(loctime);
-}
-
-/**
- * Reentrant variant of ctime().
- * 
- * @param timer Time to convert.
- * @param buf Buffer to store string to. Must be at least ASCTIME_BUF_LEN
- *     bytes long.
- * @return Pointer to buf on success, NULL on falure.
- */
-char *posix_ctime_r(const time_t *timer, char *buf)
-{
-	struct posix_tm loctime;
-	if (posix_localtime_r(timer, &loctime) == NULL) {
-		return NULL;
-	}
-	return posix_asctime_r(&loctime, buf);
-}
-
-/**
- * Convert time and date to a string, based on a specified format and
- * current locale.
- * 
- * @param s Buffer to write string to.
- * @param maxsize Size of the buffer.
- * @param format Format of the output.
- * @param tm Broken-down time to format.
- * @return Number of bytes written.
- */
-size_t posix_strftime(char *restrict s, size_t maxsize,
-    const char *restrict format, const struct posix_tm *restrict tm)
-{
-	assert(s != NULL);
-	assert(format != NULL);
-	assert(tm != NULL);
-
-	// TODO: use locale
-	static const char *wday_abbr[] = {
-		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-	};
-	static const char *wday[] = {
-		"Sunday", "Monday", "Tuesday", "Wednesday",
-		"Thursday", "Friday", "Saturday"
-	};
-	static const char *mon_abbr[] = {
-		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
-		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-	};
-	static const char *mon[] = {
-		"January", "February", "March", "April", "May", "June", "July",
-		"August", "September", "October", "November", "December"
-	};
-	
-	if (maxsize < 1) {
-		return 0;
-	}
-	
-	char *ptr = s;
-	size_t consumed;
-	size_t remaining = maxsize;
-	
-	#define append(...) { \
-		/* FIXME: this requires POSIX-correct snprintf */ \
-		/*        otherwise it won't work with non-ascii chars */ \
-		consumed = snprintf(ptr, remaining, __VA_ARGS__); \
-		if (consumed >= remaining) { \
-			return 0; \
-		} \
-		ptr += consumed; \
-		remaining -= consumed; \
-	}
-	
-	#define recurse(fmt) { \
-		consumed = posix_strftime(ptr, remaining, fmt, tm); \
-		if (consumed == 0) { \
-			return 0; \
-		} \
-		ptr += consumed; \
-		remaining -= consumed; \
-	}
-	
-	#define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \
-	    (((hour) == 0) ? 12 : (hour)))
-	
-	while (*format != '\0') {
-		if (*format != '%') {
-			append("%c", *format);
-			format++;
-			continue;
-		}
-		
-		format++;
-		if (*format == '0' || *format == '+') {
-			// TODO: padding
-			format++;
-		}
-		while (isdigit(*format)) {
-			// TODO: padding
-			format++;
-		}
-		if (*format == 'O' || *format == 'E') {
-			// TODO: locale's alternative format
-			format++;
-		}
-		
-		switch (*format) {
-		case 'a':
-			append("%s", wday_abbr[tm->tm_wday]); break;
-		case 'A':
-			append("%s", wday[tm->tm_wday]); break;
-		case 'b':
-			append("%s", mon_abbr[tm->tm_mon]); break;
-		case 'B':
-			append("%s", mon[tm->tm_mon]); break;
-		case 'c':
-			// TODO: locale-specific datetime format
-			recurse("%Y-%m-%d %H:%M:%S"); break;
-		case 'C':
-			append("%02d", (1900 + tm->tm_year) / 100); break;
-		case 'd':
-			append("%02d", tm->tm_mday); break;
-		case 'D':
-			recurse("%m/%d/%y"); break;
-		case 'e':
-			append("%2d", tm->tm_mday); break;
-		case 'F':
-			recurse("%+4Y-%m-%d"); break;
-		case 'g':
-			append("%02d", _wbyear(tm) % 100); break;
-		case 'G':
-			append("%d", _wbyear(tm)); break;
-		case 'h':
-			recurse("%b"); break;
-		case 'H':
-			append("%02d", tm->tm_hour); break;
-		case 'I':
-			append("%02d", TO_12H(tm->tm_hour)); break;
-		case 'j':
-			append("%03d", tm->tm_yday); break;
-		case 'k':
-			append("%2d", tm->tm_hour); break;
-		case 'l':
-			append("%2d", TO_12H(tm->tm_hour)); break;
-		case 'm':
-			append("%02d", tm->tm_mon); break;
-		case 'M':
-			append("%02d", tm->tm_min); break;
-		case 'n':
-			append("\n"); break;
-		case 'p':
-			append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break;
-		case 'P':
-			append("%s", tm->tm_hour < 12 ? "am" : "PM"); break;
-		case 'r':
-			recurse("%I:%M:%S %p"); break;
-		case 'R':
-			recurse("%H:%M"); break;
-		case 's':
-			append("%ld", _secs_since_epoch(tm)); break;
-		case 'S':
-			append("%02d", tm->tm_sec); break;
-		case 't':
-			append("\t"); break;
-		case 'T':
-			recurse("%H:%M:%S"); break;
-		case 'u':
-			append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); break;
-		case 'U':
-			append("%02d", _sun_week_number(tm)); break;
-		case 'V':
-			append("%02d", _iso_week_number(tm)); break;
-		case 'w':
-			append("%d", tm->tm_wday); break;
-		case 'W':
-			append("%02d", _mon_week_number(tm)); break;
-		case 'x':
-			// TODO: locale-specific date format
-			recurse("%Y-%m-%d"); break;
-		case 'X':
-			// TODO: locale-specific time format
-			recurse("%H:%M:%S"); break;
-		case 'y':
-			append("%02d", tm->tm_year % 100); break;
-		case 'Y':
-			append("%d", 1900 + tm->tm_year); break;
-		case 'z':
-			// TODO: timezone
-			break;
-		case 'Z':
-			// TODO: timezone
-			break;
-		case '%':
-			append("%%");
-			break;
-		default:
-			/* Invalid specifier, print verbatim. */
-			while (*format != '%') {
-				format--;
-			}
-			append("%%");
-			break;
-		}
-		format++;
-	}
-	
-	#undef append
-	#undef recurse
-	
-	return maxsize - remaining;
-}
-
-/**
- * Get clock resolution. Only CLOCK_REALTIME is supported.
- *
- * @param clock_id Clock ID.
- * @param res Pointer to the variable where the resolution is to be written.
- * @return 0 on success, -1 with errno set on failure.
- */
-int posix_clock_getres(posix_clockid_t clock_id, struct posix_timespec *res)
-{
-	assert(res != NULL);
-
-	switch (clock_id) {
-		case CLOCK_REALTIME:
-			res->tv_sec = 0;
-			res->tv_nsec = 1000; /* Microsecond resolution. */
-			return 0;
-		default:
-			errno = EINVAL;
-			return -1;
-	}
-}
-
-/**
- * Get time. Only CLOCK_REALTIME is supported.
- * 
- * @param clock_id ID of the clock to query.
- * @param tp Pointer to the variable where the time is to be written.
- * @return 0 on success, -1 with errno on failure.
- */
-int posix_clock_gettime(posix_clockid_t clock_id, struct posix_timespec *tp)
-{
-	assert(tp != NULL);
-
-	switch (clock_id) {
-		case CLOCK_REALTIME:
-			;
-			struct timeval tv;
-			gettimeofday(&tv, NULL);
-			tp->tv_sec = tv.tv_sec;
-			tp->tv_nsec = tv.tv_usec * 1000;
-			return 0;
-		default:
-			errno = EINVAL;
-			return -1;
-	}
-}
-
-/**
- * Set time on a specified clock. As HelenOS doesn't support this yet,
- * this function always fails.
- * 
- * @param clock_id ID of the clock to set.
- * @param tp Time to set.
- * @return 0 on success, -1 with errno on failure.
- */
-int posix_clock_settime(posix_clockid_t clock_id,
-    const struct posix_timespec *tp)
-{
-	assert(tp != NULL);
-
-	switch (clock_id) {
-		case CLOCK_REALTIME:
-			// TODO: setting clock
-			// FIXME: HelenOS doesn't actually support hardware
-			//        clock yet
-			errno = EPERM;
-			return -1;
-		default:
-			errno = EINVAL;
-			return -1;
-	}
-}
-
-/**
- * Sleep on a specified clock.
- * 
- * @param clock_id ID of the clock to sleep on (only CLOCK_REALTIME supported).
- * @param flags Flags (none supported).
- * @param rqtp Sleep time.
- * @param rmtp Remaining time is written here if sleep is interrupted.
- * @return 0 on success, -1 with errno set on failure.
- */
-int posix_clock_nanosleep(posix_clockid_t clock_id, int flags,
-    const struct posix_timespec *rqtp, struct posix_timespec *rmtp)
-{
-	assert(rqtp != NULL);
-	assert(rmtp != NULL);
-
-	switch (clock_id) {
-		case CLOCK_REALTIME:
-			// TODO: interruptible sleep
-			if (rqtp->tv_sec != 0) {
-				sleep(rqtp->tv_sec);
-			}
-			if (rqtp->tv_nsec != 0) {
-				usleep(rqtp->tv_nsec / 1000);
-			}
-			return 0;
-		default:
-			errno = EINVAL;
-			return -1;
-	}
-}
-
-/**
- * Get CPU time used since the process invocation.
- *
- * @return Consumed CPU cycles by this process or -1 if not available.
- */
-posix_clock_t posix_clock(void)
-{
-	posix_clock_t total_cycles = -1;
-	stats_task_t *task_stats = stats_get_task(task_get_id());
-	if (task_stats) {
-		total_cycles = (posix_clock_t) (task_stats->kcycles + task_stats->ucycles);
-		free(task_stats);
-		task_stats = 0;
-	}
-
-	return total_cycles;
-}
-
-/** @}
- */
Index: pace/lib/posix/time.h
===================================================================
--- uspace/lib/posix/time.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,171 +1,0 @@
-/*
- * Copyright (c) 2011 Petr Koupy
- * Copyright (c) 2011 Jiri Zarevucky
- * 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 Time measurement support.
- */
-
-#ifndef POSIX_TIME_H_
-#define POSIX_TIME_H_
-
-#include "libc/time.h"
-#include "sys/types.h"
-
-#ifndef NULL
-	#define NULL  ((void *) 0)
-#endif
-
-#ifndef CLOCKS_PER_SEC
-	#define CLOCKS_PER_SEC (1000000L)
-#endif
-
-#ifndef __locale_t_defined
-	#define __locale_t_defined
-	typedef struct __posix_locale *posix_locale_t;
-	#ifndef LIBPOSIX_INTERNAL
-		#define locale_t posix_locale_t
-	#endif
-#endif
-
-#ifndef POSIX_SIGNAL_H_
-	struct posix_sigevent;
-	#ifndef LIBPOSIX_INTERNAL
-		#define sigevent posix_sigevent
-	#endif
-#endif
-
-#undef ASCTIME_BUF_LEN
-#define ASCTIME_BUF_LEN 26
-
-#undef CLOCK_REALTIME
-#define CLOCK_REALTIME ((posix_clockid_t) 0)
-
-struct posix_tm {
-	int tm_sec;         /* Seconds [0,60]. */
-	int tm_min;         /* Minutes [0,59]. */
-	int tm_hour;        /* Hour [0,23]. */
-	int tm_mday;        /* Day of month [1,31]. */
-	int tm_mon;         /* Month of year [0,11]. */
-	int tm_year;        /* Years since 1900. */
-	int tm_wday;        /* Day of week [0,6] (Sunday = 0). */
-	int tm_yday;        /* Day of year [0,365]. */
-	int tm_isdst;       /* Daylight Savings flag. */
-};
-
-struct posix_timespec {
-	time_t tv_sec; /* Seconds. */
-	long tv_nsec; /* Nanoseconds. */
-};
-
-struct posix_itimerspec {
-	struct posix_timespec it_interval; /* Timer period. */
-	struct posix_timespec it_value; /* Timer expiration. */
-};
-
-typedef struct __posix_timer *posix_timer_t;
-
-/* Timezones */
-extern int posix_daylight;
-extern long posix_timezone;
-extern char *posix_tzname[2];
-extern void posix_tzset(void);
-
-/* Elapsed Time */
-extern double posix_difftime(time_t time1, time_t time0);
-
-/* Broken-down Time */
-extern time_t posix_mktime(struct posix_tm *tm);
-extern struct posix_tm *posix_gmtime(const time_t *timer);
-extern struct posix_tm *posix_gmtime_r(const time_t *restrict timer,
-    struct posix_tm *restrict result);
-extern struct posix_tm *posix_localtime(const time_t *timer);
-extern struct posix_tm *posix_localtime_r(const time_t *restrict timer,
-    struct posix_tm *restrict result);
-
-/* Formatting Calendar Time */
-extern char *posix_asctime(const struct posix_tm *timeptr);
-extern char *posix_asctime_r(const struct posix_tm *restrict timeptr,
-    char *restrict buf);
-extern char *posix_ctime(const time_t *timer);
-extern char *posix_ctime_r(const time_t *timer, char *buf);
-extern size_t posix_strftime(char *restrict s, size_t maxsize,
-    const char *restrict format, const struct posix_tm *restrict tm);
-
-/* Clocks */
-extern int posix_clock_getres(posix_clockid_t clock_id,
-    struct posix_timespec *res);
-extern int posix_clock_gettime(posix_clockid_t clock_id,
-    struct posix_timespec *tp);
-extern int posix_clock_settime(posix_clockid_t clock_id,
-    const struct posix_timespec *tp); 
-extern int posix_clock_nanosleep(posix_clockid_t clock_id, int flags,
-    const struct posix_timespec *rqtp, struct posix_timespec *rmtp);
-
-/* CPU Time */
-extern posix_clock_t posix_clock(void);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define tm posix_tm
-	#define timespec posix_timespec
-	#define itimerspec posix_itimerspec
-	#define timer_t posix_timer_t
-
-	#define daylight posix_daylight
-	#define timezone posix_timezone
-	#define tzname posix_tzname
-	#define tzset posix_tzset
-
-	#define difftime posix_difftime
-
-	#define mktime posix_mktime
-	#define gmtime posix_gmtime
-	#define gmtime_r posix_gmtime_r
-	#define localtime posix_localtime
-	#define localtime_r posix_localtime_r
-
-	#define asctime posix_asctime
-	#define asctime_r posix_asctime_r
-	#define ctime posix_ctime
-	#define ctime_r posix_ctime_r
-	#define strftime posix_strftime
-
-	#define clock_getres posix_clock_getres
-	#define clock_gettime posix_clock_gettime
-	#define clock_settime posix_clock_settime
-	#define clock_nanosleep posix_clock_nanosleep
-
-	#define clock posix_clock
-#endif
-
-#endif  // POSIX_TIME_H_
-
-/** @}
- */
Index: pace/lib/posix/unistd.c
===================================================================
--- uspace/lib/posix/unistd.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,424 +1,0 @@
-/*
- * 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 Miscellaneous standard definitions.
- */
-
-#define LIBPOSIX_INTERNAL
-
-#include "internal/common.h"
-#include "unistd.h"
-
-#include "errno.h"
-#include "string.h"
-#include "fcntl.h"
-
-#include "libc/task.h"
-#include "libc/stats.h"
-#include "libc/malloc.h"
-
-/* Array of environment variable strings (NAME=VALUE). */
-char **posix_environ = NULL;
-char *posix_optarg;
-
-/**
- * Get current user name.
- *
- * @return User name (static) string or NULL if not found.
- */
-char *posix_getlogin(void)
-{
-	/* There is currently no support for user accounts in HelenOS. */
-	return (char *) "user";
-}
-
-/**
- * Get current user name.
- *
- * @param name Pointer to a user supplied buffer.
- * @param namesize Length of the buffer.
- * @return Zero on success, error code otherwise.
- */
-int posix_getlogin_r(char *name, size_t namesize)
-{
-	/* There is currently no support for user accounts in HelenOS. */
-	if (namesize >= 5) {
-		posix_strcpy(name, (char *) "user");
-		return 0;
-	} else {
-		errno = ERANGE;
-		return -1;
-	}
-}
-
-/**
- * Test whether open file descriptor is associated with a terminal.
- *
- * @param fd Open file descriptor to test.
- * @return Boolean result of the test.
- */
-int posix_isatty(int fd)
-{
-	// TODO
-	/* Always returns false, because there is no easy way to find
-	 * out under HelenOS. */
-	return 0;
-}
-
-/**
- * Get the pathname of the current working directory.
- *
- * @param buf Buffer into which the pathname shall be put.
- * @param size Size of the buffer.
- * @return Buffer pointer on success, NULL on failure.
- */
-char *posix_getcwd(char *buf, size_t size)
-{
-	/* Native getcwd() does not set any errno despite the fact that general
-	 * usage pattern of this function depends on it (caller is repeatedly
-	 * guessing the required size of the buffer by checking for ERANGE on
-	 * failure). */
-	if (size == 0) {
-		errno = EINVAL;
-		return NULL;
-	}
-	
-	/* Save the original value to comply with the "no modification on
-	 * success" semantics.
-	 */
-	int orig_errno = errno;
-	errno = EOK;
-	
-	char *ret = getcwd(buf, size);
-	if (ret == NULL) {
-		/* Check errno to avoid shadowing other possible errors. */
-		if (errno == EOK) {
-			errno = ERANGE;
-		}
-	} else {
-		/* Success, restore previous errno value. */
-		errno = orig_errno;
-	}
-	
-	return ret;
-}
-
-/**
- * Change the current working directory.
- *
- * @param path New working directory.
- */
-int posix_chdir(const char *path)
-{
-	return errnify(chdir, path);
-}
-
-/**
- * Determine the page size of the current run of the process.
- *
- * @return Page size of the process.
- */
-int posix_getpagesize(void)
-{
-	return getpagesize();
-}
-
-/**
- * Get the process ID of the calling process.
- *
- * @return Process ID.
- */
-posix_pid_t posix_getpid(void)
-{
-	return task_get_id();
-}
-
-/**
- * Get the real user ID of the calling process.
- *
- * @return User ID.
- */
-posix_uid_t posix_getuid(void)
-{
-	/* There is currently no support for user accounts in HelenOS. */
-	return 0;
-}
-
-/**
- * Get the real group ID of the calling process.
- * 
- * @return Group ID.
- */
-posix_gid_t posix_getgid(void)
-{
-	/* There is currently no support for user accounts in HelenOS. */
-	return 0;
-}
-
-/**
- * Close a file.
- *
- * @param fildes File descriptor of the opened file.
- * @return 0 on success, -1 on error.
- */
-int posix_close(int fildes)
-{
-	return errnify(close, fildes);
-}
-
-/**
- * Read from a file.
- *
- * @param fildes File descriptor of the opened file.
- * @param buf Buffer to which the read bytes shall be stored.
- * @param nbyte Upper limit on the number of read bytes.
- * @return Number of read bytes on success, -1 otherwise.
- */
-ssize_t posix_read(int fildes, void *buf, size_t nbyte)
-{
-	return errnify(read, fildes, buf, nbyte);
-}
-
-/**
- * Write to a file.
- *
- * @param fildes File descriptor of the opened file.
- * @param buf Buffer to write.
- * @param nbyte Size of the buffer.
- * @return Number of written bytes on success, -1 otherwise.
- */
-ssize_t posix_write(int fildes, const void *buf, size_t nbyte)
-{
-	return errnify(write, fildes, buf, nbyte);
-}
-
-/**
- * Requests outstanding data to be written to the underlying storage device.
- *
- * @param fildes File descriptor of the opened file.
- * @return Zero on success, -1 otherwise.
- */
-int posix_fsync(int fildes)
-{
-	return errnify(fsync, fildes);
-}
-
-/**
- * Truncate a file to a specified length.
- *
- * @param fildes File descriptor of the opened file.
- * @param length New length of the file.
- * @return Zero on success, -1 otherwise.
- */
-int posix_ftruncate(int fildes, posix_off_t length)
-{
-	return errnify(ftruncate, fildes, (aoff64_t) length);
-}
-
-/**
- * Remove a directory.
- *
- * @param path Directory pathname.
- * @return Zero on success, -1 otherwise.
- */
-int posix_rmdir(const char *path)
-{
-	return errnify(rmdir, path);
-}
-
-/**
- * Remove a link to a file.
- * 
- * @param path File pathname.
- * @return Zero on success, -1 otherwise.
- */
-int posix_unlink(const char *path)
-{
-	return errnify(unlink, path);
-}
-
-/**
- * Duplicate an open file descriptor.
- *
- * @param fildes File descriptor to be duplicated.
- * @return On success, new file descriptor for the same file, otherwise -1.
- */
-int posix_dup(int fildes)
-{
-	return posix_fcntl(fildes, F_DUPFD, 0);
-}
-
-/**
- * Duplicate an open file descriptor.
- * 
- * @param fildes File descriptor to be duplicated.
- * @param fildes2 File descriptor to be paired with the same file description
- *     as is paired fildes.
- * @return fildes2 on success, -1 otherwise.
- */
-int posix_dup2(int fildes, int fildes2)
-{
-	return errnify(dup2, fildes, fildes2);
-}
-
-/**
- * Determine accessibility of a file.
- *
- * @param path File to check accessibility for.
- * @param amode Either check for existence or intended access mode.
- * @return Zero on success, -1 otherwise.
- */
-int posix_access(const char *path, int amode)
-{
-	if (amode == F_OK || (amode & (X_OK | W_OK | R_OK))) {
-		/* HelenOS doesn't support permissions, permission checks
-		 * are equal to existence check.
-		 *
-		 * Check file existence by attempting to open it.
-		 */
-		int fd = open(path, O_RDONLY);
-		if (fd < 0) {
-			errno = -fd;
-			return -1;
-		}
-		close(fd);
-		return 0;
-	} else {
-		/* Invalid amode argument. */
-		errno = EINVAL;
-		return -1;
-	}
-}
-
-/**
- * Get configurable system variables.
- * 
- * @param name Variable name.
- * @return Variable value.
- */
-long posix_sysconf(int name)
-{
-	long clk_tck = 0;
-	size_t cpu_count = 0;
-	stats_cpu_t *cpu_stats = stats_get_cpus(&cpu_count);
-	if (cpu_stats && cpu_count > 0) {
-		clk_tck = ((long) cpu_stats[0].frequency_mhz) * 1000000L;
-	}
-	if (cpu_stats) {
-		free(cpu_stats);
-		cpu_stats = 0;
-	}
-
-	long phys_pages = 0;
-	long avphys_pages = 0;
-	stats_physmem_t *mem_stats = stats_get_physmem();
-	if (mem_stats) {
-		phys_pages = (long) (mem_stats->total / getpagesize());
-		avphys_pages = (long) (mem_stats->free / getpagesize());
-		free(mem_stats);
-		mem_stats = 0;
-	}
-
-	switch (name) {
-	case _SC_PHYS_PAGES:
-		return phys_pages;
-	case _SC_AVPHYS_PAGES:
-		return avphys_pages;
-	case _SC_PAGESIZE:
-		return getpagesize();
-	case _SC_CLK_TCK:
-		return clk_tck;
-	default:
-		errno = EINVAL;
-		return -1;
-	}
-}
-
-/**
- * 
- * @param path
- * @param name
- * @return
- */
-long posix_pathconf(const char *path, int name)
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
-/**
- * 
- * @return
- */
-posix_pid_t posix_fork(void)
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
-/**
- * 
- * @param path
- * @param argv
- * @return
- */
-int posix_execv(const char *path, char *const argv[])
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
-/**
- * 
- * @param file
- * @param argv
- * @return
- */
-int posix_execvp(const char *file, char *const argv[])
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
-/**
- * 
- * @param fildes
- * @return
- */
-int posix_pipe(int fildes[2])
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
-/** @}
- */
Index: pace/lib/posix/unistd.h
===================================================================
--- uspace/lib/posix/unistd.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,192 +1,0 @@
-/*
- * 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 Miscellaneous standard definitions.
- */
-
-#ifndef POSIX_UNISTD_H_
-#define POSIX_UNISTD_H_
-
-#include "libc/unistd.h"
-#include "sys/types.h"
-
-/* Process Termination */
-#define _exit exit
-
-extern char *posix_optarg;
-extern int optind, opterr, optopt;
-extern int posix_getopt(int, char * const [], const char *);
-
-/* Environment */
-extern char **posix_environ;
-
-/* Login Information */
-extern char *posix_getlogin(void);
-extern int posix_getlogin_r(char *name, size_t namesize);
-
-/* Identifying Terminals */
-extern int posix_isatty(int fd);
-
-/* Working Directory */
-extern char *posix_getcwd(char *buf, size_t size);
-extern int posix_chdir(const char *path);
-
-/* Query Memory Parameters */
-extern int posix_getpagesize(void);
-
-/* Process Identification */
-extern posix_pid_t posix_getpid(void);
-extern posix_uid_t posix_getuid(void);
-extern posix_gid_t posix_getgid(void);
-
-/* File Manipulation */
-extern int posix_close(int fildes);
-extern ssize_t posix_read(int fildes, void *buf, size_t nbyte);
-extern ssize_t posix_write(int fildes, const void *buf, size_t nbyte);
-extern int posix_fsync(int fildes);
-extern int posix_ftruncate(int fildes, posix_off_t length);
-extern int posix_rmdir(const char *path);
-extern int posix_unlink(const char *path);
-extern int posix_dup(int fildes);
-extern int posix_dup2(int fildes, int fildes2);
-
-/* Standard Streams */
-#undef STDIN_FILENO
-#define STDIN_FILENO (fileno(stdin))
-#undef STDOUT_FILENO
-#define STDOUT_FILENO (fileno(stdout))
-#undef STDERR_FILENO
-#define STDERR_FILENO (fileno(stderr))
-
-/* File Accessibility */
-#undef F_OK
-#undef X_OK
-#undef W_OK
-#undef R_OK
-#define	F_OK 0 /* Test for existence. */
-#define	X_OK 1 /* Test for execute permission. */
-#define	W_OK 2 /* Test for write permission. */
-#define	R_OK 4 /* Test for read permission. */
-extern int posix_access(const char *path, int amode);
-
-/* System Parameters */
-enum {
-	_SC_PHYS_PAGES,
-	_SC_AVPHYS_PAGES,
-	_SC_PAGESIZE,
-	_SC_CLK_TCK
-};
-extern long posix_sysconf(int name);
-
-/* Path Configuration Parameters */
-enum {
-	_PC_2_SYMLINKS,
-	_PC_ALLOC_SIZE_MIN,
-	_PC_ASYNC_IO,
-	_PC_CHOWN_RESTRICTED,
-	_PC_FILESIZEBITS,
-	_PC_LINK_MAX,
-	_PC_MAX_CANON,
-	_PC_MAX_INPUT,
-	_PC_NAME_MAX,
-	_PC_NO_TRUNC,
-	_PC_PATH_MAX,
-	_PC_PIPE_BUF,
-	_PC_PRIO_IO,
-	_PC_REC_INCR_XFER_SIZE,
-	_PC_REC_MIN_XFER_SIZE,
-	_PC_REC_XFER_ALIGN,
-	_PC_SYMLINK_MAX,
-	_PC_SYNC_IO,
-	_PC_VDISABLE
-};
-extern long posix_pathconf(const char *path, int name);
-
-/* Creating a Process */
-extern posix_pid_t posix_fork(void);
-
-/* Executing a File */
-extern int posix_execv(const char *path, char *const argv[]);
-extern int posix_execvp(const char *file, char *const argv[]);
-
-/* Creating a Pipe */
-extern int posix_pipe(int fildes[2]);
-
-#ifndef LIBPOSIX_INTERNAL
-	#define getopt posix_getopt
-	#define optarg posix_optarg
-
-	#define environ posix_environ
-
-	#define getlogin posix_getlogin
-	#define getlogin_r posix_getlogin_r
-
-	#define getcwd posix_getcwd
-	#define chdir posix_chdir
-
-	#define isatty posix_isatty
-
-	#undef getpagesize
-	#define getpagesize posix_getpagesize
-
-	#define getpid posix_getpid
-	#define getuid posix_getuid
-	#define getgid posix_getgid
-
-	#define close posix_close
-	#define read posix_read
-	#define write posix_write
-	#define fsync posix_fsync
-	#define ftruncate posix_ftruncate
-	#define rmdir posix_rmdir
-	#define unlink posix_unlink
-	#define dup posix_dup
-	#define dup2 posix_dup2
-
-	#define access posix_access
-
-	#define sysconf posix_sysconf
-
-	#define pathconf posix_pathconf
-
-	#define fork posix_fork
-
-	#define execv posix_execv
-	#define execvp posix_execvp
-
-	#define pipe posix_pipe
-#endif
-
-#endif /* POSIX_UNISTD_H_ */
-
-/** @}
- */
Index: uspace/lib/softfloat/Makefile
===================================================================
--- uspace/lib/softfloat/Makefile	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/softfloat/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -29,17 +29,16 @@
 
 USPACE_PREFIX = ../..
-EXTRA_CFLAGS = -Iinclude
 LIBRARY = libsoftfloat
 
 SOURCES = \
-	generic/add.c \
-	generic/common.c \
-	generic/comparison.c \
-	generic/conversion.c \
-	generic/div.c \
-	generic/mul.c \
-	generic/other.c \
-	generic/softfloat.c \
-	generic/sub.c
+	softfloat.c \
+	common.c \
+	add.c \
+	sub.c \
+	div.c \
+	mul.c \
+	comparison.c \
+	conversion.c \
+	other.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/softfloat/add.c
===================================================================
--- uspace/lib/softfloat/add.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/add.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Addition functions.
+ */
+
+#include "sftypes.h"
+#include "add.h"
+#include "comparison.h"
+#include "common.h"
+
+/** Add two single-precision floats with the same sign.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ * @return Result of addition.
+ */
+float32 add_float32(float32 a, float32 b)
+{
+	int expdiff;
+	uint32_t exp1, exp2, frac1, frac2;
+	
+	expdiff = a.parts.exp - b.parts.exp;
+	if (expdiff < 0) {
+		if (is_float32_nan(b)) {
+			/* TODO: fix SigNaN */
+			if (is_float32_signan(b)) {
+			}
+
+			return b;
+		}
+		
+		if (b.parts.exp == FLOAT32_MAX_EXPONENT) { 
+			return b;
+		}
+		
+		frac1 = b.parts.fraction;
+		exp1 = b.parts.exp;
+		frac2 = a.parts.fraction;
+		exp2 = a.parts.exp;
+		expdiff *= -1;
+	} else {
+		if ((is_float32_nan(a)) || (is_float32_nan(b))) {
+			/* TODO: fix SigNaN */
+			if (is_float32_signan(a) || is_float32_signan(b)) {
+			}
+			return (is_float32_nan(a) ? a : b);
+		}
+		
+		if (a.parts.exp == FLOAT32_MAX_EXPONENT) { 
+			return a;
+		}
+		
+		frac1 = a.parts.fraction;
+		exp1 = a.parts.exp;
+		frac2 = b.parts.fraction;
+		exp2 = b.parts.exp;
+	}
+	
+	if (exp1 == 0) {
+		/* both are denormalized */
+		frac1 += frac2;
+		if (frac1 & FLOAT32_HIDDEN_BIT_MASK) {
+			/* result is not denormalized */
+			a.parts.exp = 1;
+		}
+		a.parts.fraction = frac1;
+		return a;
+	}
+	
+	frac1 |= FLOAT32_HIDDEN_BIT_MASK; /* add hidden bit */
+
+	if (exp2 == 0) {
+		/* second operand is denormalized */
+		--expdiff;
+	} else {
+		/* add hidden bit to second operand */
+		frac2 |= FLOAT32_HIDDEN_BIT_MASK; 
+	}
+	
+	/* create some space for rounding */
+	frac1 <<= 6;
+	frac2 <<= 6;
+	
+	if (expdiff < (FLOAT32_FRACTION_SIZE + 2)) {
+		frac2 >>= expdiff;
+		frac1 += frac2;
+	} else {
+		a.parts.exp = exp1;
+		a.parts.fraction = (frac1 >> 6) & (~(FLOAT32_HIDDEN_BIT_MASK));
+		return a;
+	}
+	
+	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7)) {
+		++exp1;
+		frac1 >>= 1;
+	}
+	
+	/* rounding - if first bit after fraction is set then round up */
+	frac1 += (0x1 << 5);
+	
+	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7)) { 
+		/* rounding overflow */
+		++exp1;
+		frac1 >>= 1;
+	}
+	
+	if ((exp1 == FLOAT32_MAX_EXPONENT) || (exp2 > exp1)) {
+		/* overflow - set infinity as result */
+		a.parts.exp = FLOAT32_MAX_EXPONENT;
+		a.parts.fraction = 0;
+		return a;
+	}
+	
+	a.parts.exp = exp1;
+	
+	/* Clear hidden bit and shift */
+	a.parts.fraction = ((frac1 >> 6) & (~FLOAT32_HIDDEN_BIT_MASK)); 
+	return a;
+}
+
+/** Add two double-precision floats with the same sign.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ * @return Result of addition.
+ */
+float64 add_float64(float64 a, float64 b)
+{
+	int expdiff;
+	uint32_t exp1, exp2;
+	uint64_t frac1, frac2;
+	
+	expdiff = ((int) a.parts.exp) - b.parts.exp;
+	if (expdiff < 0) {
+		if (is_float64_nan(b)) {
+			/* TODO: fix SigNaN */
+			if (is_float64_signan(b)) {
+			}
+
+			return b;
+		}
+		
+		/* b is infinity and a not */
+		if (b.parts.exp == FLOAT64_MAX_EXPONENT) {
+			return b;
+		}
+		
+		frac1 = b.parts.fraction;
+		exp1 = b.parts.exp;
+		frac2 = a.parts.fraction;
+		exp2 = a.parts.exp;
+		expdiff *= -1;
+	} else {
+		if (is_float64_nan(a)) {
+			/* TODO: fix SigNaN */
+			if (is_float64_signan(a) || is_float64_signan(b)) {
+			}
+			return a;
+		}
+		
+		/* a is infinity and b not */
+		if (a.parts.exp == FLOAT64_MAX_EXPONENT) { 
+			return a;
+		}
+		
+		frac1 = a.parts.fraction;
+		exp1 = a.parts.exp;
+		frac2 = b.parts.fraction;
+		exp2 = b.parts.exp;
+	}
+	
+	if (exp1 == 0) {
+		/* both are denormalized */
+		frac1 += frac2;
+		if (frac1 & FLOAT64_HIDDEN_BIT_MASK) { 
+			/* result is not denormalized */
+			a.parts.exp = 1;
+		}
+		a.parts.fraction = frac1;
+		return a;
+	}
+	
+	/* add hidden bit - frac1 is sure not denormalized */
+	frac1 |= FLOAT64_HIDDEN_BIT_MASK;
+
+	/* second operand ... */
+	if (exp2 == 0) {
+		/* ... is denormalized */
+		--expdiff;	
+	} else {
+		/* is not denormalized */
+		frac2 |= FLOAT64_HIDDEN_BIT_MASK;
+	}
+	
+	/* create some space for rounding */
+	frac1 <<= 6;
+	frac2 <<= 6;
+	
+	if (expdiff < (FLOAT64_FRACTION_SIZE + 2)) {
+		frac2 >>= expdiff;
+		frac1 += frac2;
+	} else {
+		a.parts.exp = exp1;
+		a.parts.fraction = (frac1 >> 6) & (~(FLOAT64_HIDDEN_BIT_MASK));
+		return a;
+	}
+	
+	if (frac1 & (FLOAT64_HIDDEN_BIT_MASK << 7)) {
+		++exp1;
+		frac1 >>= 1;
+	}
+	
+	/* rounding - if first bit after fraction is set then round up */
+	frac1 += (0x1 << 5); 
+	
+	if (frac1 & (FLOAT64_HIDDEN_BIT_MASK << 7)) { 
+		/* rounding overflow */
+		++exp1;
+		frac1 >>= 1;
+	}
+	
+	if ((exp1 == FLOAT64_MAX_EXPONENT) || (exp2 > exp1)) {
+		/* overflow - set infinity as result */
+		a.parts.exp = FLOAT64_MAX_EXPONENT;
+		a.parts.fraction = 0;
+		return a;
+	}
+	
+	a.parts.exp = exp1;
+	/* Clear hidden bit and shift */
+	a.parts.fraction = ((frac1 >> 6) & (~FLOAT64_HIDDEN_BIT_MASK));
+	return a;
+}
+
+/** Add two quadruple-precision floats with the same sign.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ * @return Result of addition.
+ */
+float128 add_float128(float128 a, float128 b)
+{
+	int expdiff;
+	uint32_t exp1, exp2;
+	uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
+
+	expdiff = ((int) a.parts.exp) - b.parts.exp;
+	if (expdiff < 0) {
+		if (is_float128_nan(b)) {
+			/* TODO: fix SigNaN */
+			if (is_float128_signan(b)) {
+			}
+
+			return b;
+		}
+
+		/* b is infinity and a not */
+		if (b.parts.exp == FLOAT128_MAX_EXPONENT) {
+			return b;
+		}
+
+		frac1_hi = b.parts.frac_hi;
+		frac1_lo = b.parts.frac_lo;
+		exp1 = b.parts.exp;
+		frac2_hi = a.parts.frac_hi;
+		frac2_lo = a.parts.frac_lo;
+		exp2 = a.parts.exp;
+		expdiff *= -1;
+	} else {
+		if (is_float128_nan(a)) {
+			/* TODO: fix SigNaN */
+			if (is_float128_signan(a) || is_float128_signan(b)) {
+			}
+			return a;
+		}
+
+		/* a is infinity and b not */
+		if (a.parts.exp == FLOAT128_MAX_EXPONENT) {
+			return a;
+		}
+
+		frac1_hi = a.parts.frac_hi;
+		frac1_lo = a.parts.frac_lo;
+		exp1 = a.parts.exp;
+		frac2_hi = b.parts.frac_hi;
+		frac2_lo = b.parts.frac_lo;
+		exp2 = b.parts.exp;
+	}
+
+	if (exp1 == 0) {
+		/* both are denormalized */
+		add128(frac1_hi, frac1_lo, frac2_hi, frac2_lo, &frac1_hi, &frac1_lo);
+
+		and128(frac1_hi, frac1_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &tmp_hi, &tmp_lo);
+		if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+			/* result is not denormalized */
+			a.parts.exp = 1;
+		}
+
+		a.parts.frac_hi = frac1_hi;
+		a.parts.frac_lo = frac1_lo;
+		return a;
+	}
+
+	/* add hidden bit - frac1 is sure not denormalized */
+	or128(frac1_hi, frac1_lo,
+	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &frac1_hi, &frac1_lo);
+
+	/* second operand ... */
+	if (exp2 == 0) {
+		/* ... is denormalized */
+		--expdiff;
+	} else {
+		/* is not denormalized */
+		or128(frac2_hi, frac2_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &frac2_hi, &frac2_lo);
+	}
+
+	/* create some space for rounding */
+	lshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
+	lshift128(frac2_hi, frac2_lo, 6, &frac2_hi, &frac2_lo);
+
+	if (expdiff < (FLOAT128_FRACTION_SIZE + 2)) {
+		rshift128(frac2_hi, frac2_lo, expdiff, &frac2_hi, &frac2_lo);
+		add128(frac1_hi, frac1_lo, frac2_hi, frac2_lo, &frac1_hi, &frac1_lo);
+	} else {
+		a.parts.exp = exp1;
+
+		rshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
+		not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &tmp_hi, &tmp_lo);
+		and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+
+		a.parts.frac_hi = tmp_hi;
+		a.parts.frac_lo = tmp_lo;
+		return a;
+	}
+
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 7,
+	    &tmp_hi, &tmp_lo);
+	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+		++exp1;
+		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
+	}
+
+	/* rounding - if first bit after fraction is set then round up */
+	add128(frac1_hi, frac1_lo, 0x0ll, 0x1ll << 5, &frac1_hi, &frac1_lo);
+
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 7,
+	   &tmp_hi, &tmp_lo);
+	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+		/* rounding overflow */
+		++exp1;
+		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
+	}
+
+	if ((exp1 == FLOAT128_MAX_EXPONENT ) || (exp2 > exp1)) {
+		/* overflow - set infinity as result */
+		a.parts.exp = FLOAT64_MAX_EXPONENT;
+		a.parts.frac_hi = 0;
+		a.parts.frac_lo = 0;
+		return a;
+	}
+
+	a.parts.exp = exp1;
+	
+	/* Clear hidden bit and shift */
+	rshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
+	not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &tmp_hi, &tmp_lo);
+	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+
+	a.parts.frac_hi = tmp_hi;
+	a.parts.frac_lo = tmp_lo;
+
+	return a;
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/add.h
===================================================================
--- uspace/lib/softfloat/add.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/add.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Addition functions.
+ */
+
+#ifndef __ADD_H__
+#define __ADD_H__
+
+extern float32 add_float32(float32, float32);
+extern float64 add_float64(float64, float64);
+extern float96 add_float96(float96, float96);
+extern float128 add_float128(float128, float128);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/common.c
===================================================================
--- uspace/lib/softfloat/common.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/common.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Common helper operations.
+ */
+
+#include "sftypes.h"
+#include "common.h"
+
+/* Table for fast leading zeroes counting. */
+char zeroTable[256] = {
+	8, 7, 7, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, \
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, \
+	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
+	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/**
+ * Take fraction shifted by 10 bits to the left, round it, normalize it
+ * and detect exceptions
+ * 
+ * @param cexp Exponent with bias.
+ * @param cfrac Fraction shifted 10 bits to the left with added hidden bit.
+ * @param sign Resulting sign.
+ * @return Finished double-precision float.
+ */
+float64 finish_float64(int32_t cexp, uint64_t cfrac, char sign)
+{
+	float64 result;
+
+	result.parts.sign = sign;
+
+	/* find first nonzero digit and shift result and detect possibly underflow */
+	while ((cexp > 0) && (cfrac) &&
+	    (!(cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1))))) {
+		cexp--;
+		cfrac <<= 1;
+		/* TODO: fix underflow */
+	}
+	
+	if ((cexp < 0) || (cexp == 0 &&
+	    (!(cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1)))))) {
+		/* FIXME: underflow */
+		result.parts.exp = 0;
+		if ((cexp + FLOAT64_FRACTION_SIZE + 1) < 0) { /* +1 is place for rounding */
+			result.parts.fraction = 0;
+			return result;
+		}
+		
+		while (cexp < 0) {
+			cexp++;
+			cfrac >>= 1;
+		}
+	
+		cfrac += (0x1 << (64 - FLOAT64_FRACTION_SIZE - 3)); 
+		
+		if (!(cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1)))) {
+			result.parts.fraction =
+			    ((cfrac >> (64 - FLOAT64_FRACTION_SIZE - 2)) & (~FLOAT64_HIDDEN_BIT_MASK));
+			return result;
+		}	
+	} else {
+		cfrac += (0x1 << (64 - FLOAT64_FRACTION_SIZE - 3)); 
+	}
+	
+	++cexp;
+
+	if (cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1))) {
+		++cexp;
+		cfrac >>= 1;
+	}
+
+	/* check overflow */
+	if (cexp >= FLOAT64_MAX_EXPONENT) {
+		/* FIXME: overflow, return infinity */
+		result.parts.exp = FLOAT64_MAX_EXPONENT;
+		result.parts.fraction = 0;
+		return result;
+	}
+
+	result.parts.exp = (uint32_t) cexp;
+	
+	result.parts.fraction = 
+	    ((cfrac >> (64 - FLOAT64_FRACTION_SIZE - 2)) & (~FLOAT64_HIDDEN_BIT_MASK));
+	
+	return result;	
+}
+
+/**
+ * Take fraction, round it, normalize it and detect exceptions
+ * 
+ * @param cexp Exponent with bias.
+ * @param cfrac_hi High part of the fraction shifted 14 bits to the left
+ *     with added hidden bit.
+ * @param cfrac_lo Low part of the fraction shifted 14 bits to the left
+ *     with added hidden bit.
+ * @param sign Resulting sign.
+ * @param shift_out Bits right-shifted out from fraction by the caller.
+ * @return Finished quadruple-precision float.
+ */
+float128 finish_float128(int32_t cexp, uint64_t cfrac_hi, uint64_t cfrac_lo, 
+    char sign, uint64_t shift_out)
+{
+	float128 result;
+	uint64_t tmp_hi, tmp_lo;
+
+	result.parts.sign = sign;
+
+	/* find first nonzero digit and shift result and detect possibly underflow */
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    1, &tmp_hi, &tmp_lo);
+	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	while ((cexp > 0) && (lt128(0x0ll, 0x0ll, cfrac_hi, cfrac_lo)) &&
+	    (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo))) {
+		cexp--;
+		lshift128(cfrac_hi, cfrac_lo, 1, &cfrac_hi, &cfrac_lo);
+		/* TODO: fix underflow */
+
+		lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    1, &tmp_hi, &tmp_lo);
+		and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	}
+
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    1, &tmp_hi, &tmp_lo);
+	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	if ((cexp < 0) || (cexp == 0 &&
+	    (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)))) {
+		/* FIXME: underflow */
+		result.parts.exp = 0;
+		if ((cexp + FLOAT128_FRACTION_SIZE + 1) < 0) { /* +1 is place for rounding */
+			result.parts.frac_hi = 0x0ll;
+			result.parts.frac_lo = 0x0ll;
+			return result;
+		}
+
+		while (cexp < 0) {
+			cexp++;
+			rshift128(cfrac_hi, cfrac_lo, 1, &cfrac_hi, &cfrac_lo);
+		}
+
+		if (shift_out & (0x1ull < 64)) {
+			add128(cfrac_hi, cfrac_lo, 0x0ll, 0x1ll, &cfrac_hi, &cfrac_lo);
+		}
+
+		lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    1, &tmp_hi, &tmp_lo);
+		and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+		if (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+			not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+			    &tmp_hi, &tmp_lo);
+			and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+			result.parts.frac_hi = tmp_hi;
+			result.parts.frac_lo = tmp_lo;
+			return result;
+		}
+	} else {
+		if (shift_out & (0x1ull < 64)) {
+			add128(cfrac_hi, cfrac_lo, 0x0ll, 0x1ll, &cfrac_hi, &cfrac_lo);
+		}
+	}
+
+	++cexp;
+
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    1, &tmp_hi, &tmp_lo);
+	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+		++cexp;
+		rshift128(cfrac_hi, cfrac_lo, 1, &cfrac_hi, &cfrac_lo);
+	}
+
+	/* check overflow */
+	if (cexp >= FLOAT128_MAX_EXPONENT) {
+		/* FIXME: overflow, return infinity */
+		result.parts.exp = FLOAT128_MAX_EXPONENT;
+		result.parts.frac_hi = 0x0ll;
+		result.parts.frac_lo = 0x0ll;
+		return result;
+	}
+
+	result.parts.exp = (uint32_t) cexp;
+
+	not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &tmp_hi, &tmp_lo);
+	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	result.parts.frac_hi = tmp_hi;
+	result.parts.frac_lo = tmp_lo;
+
+	return result;	
+}
+
+/**
+ * Counts leading zeroes in byte.
+ *
+ * @param i Byte for which to count leading zeroes.
+ * @return Number of detected leading zeroes.
+ */
+int count_zeroes8(uint8_t i)
+{
+	return zeroTable[i];
+}
+
+/** 
+ * Counts leading zeroes in 32bit unsigned integer.
+ *
+ * @param i Integer for which to count leading zeroes.
+ * @return Number of detected leading zeroes.
+ */
+int count_zeroes32(uint32_t i)
+{
+	int j;
+	for (j = 0; j < 32; j += 8) {
+		if (i & (0xFF << (24 - j))) {
+			return (j + count_zeroes8(i >> (24 - j)));
+		}
+	}
+
+	return 32;
+}
+
+/**
+ * Counts leading zeroes in 64bit unsigned integer.
+ *
+ * @param i Integer for which to count leading zeroes.
+ * @return Number of detected leading zeroes.
+ */
+int count_zeroes64(uint64_t i)
+{
+	int j;
+	for (j = 0; j < 64; j += 8) {
+		if (i & (0xFFll << (56 - j))) {
+			return (j + count_zeroes8(i >> (56 - j)));
+		}
+	}
+
+	return 64;
+}
+
+/**
+ * Round and normalize number expressed by exponent and fraction with
+ * first bit (equal to hidden bit) at 30th bit.
+ *
+ * @param exp Exponent part.
+ * @param fraction Fraction with hidden bit shifted to 30th bit.
+ */
+void round_float32(int32_t *exp, uint32_t *fraction)
+{
+	/* rounding - if first bit after fraction is set then round up */
+	(*fraction) += (0x1 << (32 - FLOAT32_FRACTION_SIZE - 3));
+	
+	if ((*fraction) & 
+	    (FLOAT32_HIDDEN_BIT_MASK << (32 - FLOAT32_FRACTION_SIZE - 1))) {
+		/* rounding overflow */
+		++(*exp);
+		(*fraction) >>= 1;
+	}
+	
+	if (((*exp) >= FLOAT32_MAX_EXPONENT) || ((*exp) < 0)) {
+		/* overflow - set infinity as result */
+		(*exp) = FLOAT32_MAX_EXPONENT;
+		(*fraction) = 0;
+	}
+}
+
+/**
+ * Round and normalize number expressed by exponent and fraction with
+ * first bit (equal to hidden bit) at 62nd bit.
+ *
+ * @param exp Exponent part.
+ * @param fraction Fraction with hidden bit shifted to 62nd bit.
+ */
+void round_float64(int32_t *exp, uint64_t *fraction)
+{
+	/* rounding - if first bit after fraction is set then round up */
+	(*fraction) += (0x1 << (64 - FLOAT64_FRACTION_SIZE - 3));
+	
+	if ((*fraction) & 
+	    (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 3))) {
+		/* rounding overflow */
+		++(*exp);
+		(*fraction) >>= 1;
+	}
+	
+	if (((*exp) >= FLOAT64_MAX_EXPONENT) || ((*exp) < 0)) {
+		/* overflow - set infinity as result */
+		(*exp) = FLOAT64_MAX_EXPONENT;
+		(*fraction) = 0;
+	}
+}
+
+/**
+ * Round and normalize number expressed by exponent and fraction with
+ * first bit (equal to hidden bit) at 126th bit.
+ *
+ * @param exp Exponent part.
+ * @param frac_hi High part of fraction part with hidden bit shifted to 126th bit.
+ * @param frac_lo Low part of fraction part with hidden bit shifted to 126th bit.
+ */
+void round_float128(int32_t *exp, uint64_t *frac_hi, uint64_t *frac_lo)
+{
+	uint64_t tmp_hi, tmp_lo;
+
+	/* rounding - if first bit after fraction is set then round up */
+	lshift128(0x0ll, 0x1ll, (128 - FLOAT128_FRACTION_SIZE - 3), &tmp_hi, &tmp_lo);
+	add128(*frac_hi, *frac_lo, tmp_hi, tmp_lo, frac_hi, frac_lo);
+
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    (128 - FLOAT128_FRACTION_SIZE - 3), &tmp_hi, &tmp_lo);
+	and128(*frac_hi, *frac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+		/* rounding overflow */
+		++(*exp);
+		rshift128(*frac_hi, *frac_lo, 1, frac_hi, frac_lo);
+	}
+
+	if (((*exp) >= FLOAT128_MAX_EXPONENT) || ((*exp) < 0)) {
+		/* overflow - set infinity as result */
+		(*exp) = FLOAT128_MAX_EXPONENT;
+		(*frac_hi) = 0;
+		(*frac_lo) = 0;
+	}
+}
+
+/**
+ * Logical shift left on the 128-bit operand.
+ *
+ * @param a_hi High part of the input operand.
+ * @param a_lo Low part of the input operand.
+ * @param shift Number of bits by witch to shift.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void lshift128(
+    uint64_t a_hi, uint64_t a_lo, int shift,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	if (shift <= 0) {
+		/* do nothing */
+	} else if (shift >= 128) {
+		a_hi = 0;
+		a_lo = 0;
+	} else if (shift >= 64) {
+		a_hi = a_lo << (shift - 64);
+		a_lo = 0;
+	} else {
+		a_hi <<= shift;
+		a_hi |= a_lo >> (64 - shift);
+		a_lo <<= shift;
+	}
+
+	*r_hi = a_hi;
+	*r_lo = a_lo;
+}
+
+/**
+ * Logical shift right on the 128-bit operand.
+ *
+ * @param a_hi High part of the input operand.
+ * @param a_lo Low part of the input operand.
+ * @param shift Number of bits by witch to shift.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void rshift128(
+    uint64_t a_hi, uint64_t a_lo, int shift,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	if (shift <= 0) {
+		/* do nothing */
+	} else 	if (shift >= 128) {
+		a_hi = 0;
+		a_lo = 0;
+	} else if (shift >= 64) {
+		a_lo = a_hi >> (shift - 64);
+		a_hi = 0;
+	} else {
+		a_lo >>= shift;
+		a_lo |= a_hi << (64 - shift);
+		a_hi >>= shift;
+	}
+
+	*r_hi = a_hi;
+	*r_lo = a_lo;
+}
+
+/**
+ * Bitwise AND on 128-bit operands.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void and128(
+    uint64_t a_hi, uint64_t a_lo,
+    uint64_t b_hi, uint64_t b_lo,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	*r_hi = a_hi & b_hi;
+	*r_lo = a_lo & b_lo;
+}
+
+/**
+ * Bitwise inclusive OR on 128-bit operands.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void or128(
+    uint64_t a_hi, uint64_t a_lo,
+    uint64_t b_hi, uint64_t b_lo,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	*r_hi = a_hi | b_hi;
+	*r_lo = a_lo | b_lo;
+}
+
+/**
+ * Bitwise exclusive OR on 128-bit operands.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void xor128(
+    uint64_t a_hi, uint64_t a_lo,
+    uint64_t b_hi, uint64_t b_lo,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	*r_hi = a_hi ^ b_hi;
+	*r_lo = a_lo ^ b_lo;
+}
+
+/**
+ * Bitwise NOT on the 128-bit operand.
+ *
+ * @param a_hi High part of the input operand.
+ * @param a_lo Low part of the input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void not128(
+    uint64_t a_hi, uint64_t a_lo,
+	uint64_t *r_hi, uint64_t *r_lo)
+{
+	*r_hi = ~a_hi;
+	*r_lo = ~a_lo;
+}
+
+/**
+ * Equality comparison of 128-bit operands.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @return 1 if operands are equal, 0 otherwise.
+ */
+int eq128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo)
+{
+	return (a_hi == b_hi) && (a_lo == b_lo);
+}
+
+/**
+ * Lower-or-equal comparison of 128-bit operands.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @return 1 if a is lower or equal to b, 0 otherwise.
+ */
+int le128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo)
+{
+	return (a_hi < b_hi) || ((a_hi == b_hi) && (a_lo <= b_lo));
+}
+
+/**
+ * Lower-than comparison of 128-bit operands.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @return 1 if a is lower than b, 0 otherwise.
+ */
+int lt128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo)
+{
+	return (a_hi < b_hi) || ((a_hi == b_hi) && (a_lo < b_lo));
+}
+
+/**
+ * Addition of two 128-bit unsigned integers.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void add128(uint64_t a_hi, uint64_t a_lo,
+    uint64_t b_hi, uint64_t b_lo,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	uint64_t low = a_lo + b_lo;
+	*r_lo = low;
+	/* detect overflow to add a carry */
+	*r_hi = a_hi + b_hi + (low < a_lo);
+}
+
+/**
+ * Substraction of two 128-bit unsigned integers.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void sub128(uint64_t a_hi, uint64_t a_lo,
+    uint64_t b_hi, uint64_t b_lo,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	*r_lo = a_lo - b_lo;
+	/* detect underflow to substract a carry */
+	*r_hi = a_hi - b_hi - (a_lo < b_lo);
+}
+
+/**
+ * Multiplication of two 64-bit unsigned integers.
+ * 
+ * @param a First input operand.
+ * @param b Second input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void mul64(uint64_t a, uint64_t b, uint64_t *r_hi, uint64_t *r_lo)
+{
+	uint64_t low, high, middle1, middle2;
+	uint32_t alow, blow;
+
+	alow = a & 0xFFFFFFFF;
+	blow = b & 0xFFFFFFFF;
+
+	a >>= 32;
+	b >>= 32;
+
+	low = ((uint64_t) alow) * blow;
+	middle1 = a * blow;
+	middle2 = alow * b;
+	high = a * b;
+
+	middle1 += middle2;
+	high += (((uint64_t) (middle1 < middle2)) << 32) + (middle1 >> 32);
+	middle1 <<= 32;
+	low += middle1;
+	high += (low < middle1);
+	*r_lo = low;
+	*r_hi = high;
+}
+
+/**
+ * Multiplication of two 128-bit unsigned integers.
+ * 
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @param r_hihi Address to store first (highest) quarter of the result.
+ * @param r_hilo Address to store second quarter of the result.
+ * @param r_lohi Address to store third quarter of the result.
+ * @param r_lolo Address to store fourth (lowest) quarter of the result.
+ */
+void mul128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo,
+    uint64_t *r_hihi, uint64_t *r_hilo, uint64_t *r_lohi, uint64_t *r_lolo)
+{
+	uint64_t hihi, hilo, lohi, lolo;
+	uint64_t tmp1, tmp2;
+
+	mul64(a_lo, b_lo, &lohi, &lolo);
+	mul64(a_lo, b_hi, &hilo, &tmp2);
+	add128(hilo, tmp2, 0x0ll, lohi, &hilo, &lohi);
+	mul64(a_hi, b_hi, &hihi, &tmp1);
+	add128(hihi, tmp1, 0x0ll, hilo, &hihi, &hilo);
+	mul64(a_hi, b_lo, &tmp1, &tmp2);
+	add128(tmp1, tmp2, 0x0ll, lohi, &tmp1, &lohi);
+	add128(hihi, hilo, 0x0ll, tmp1, &hihi, &hilo);
+
+	*r_hihi = hihi;
+	*r_hilo = hilo;
+	*r_lohi = lohi;
+	*r_lolo = lolo;
+}
+
+/**
+ * Estimate the quotient of 128-bit unsigned divident and 64-bit unsigned
+ * divisor.
+ * 
+ * @param a_hi High part of the divident.
+ * @param a_lo Low part of the divident.
+ * @param b Divisor.
+ * @return Quotient approximation.
+ */
+uint64_t div128est(uint64_t a_hi, uint64_t a_lo, uint64_t b)
+{
+	uint64_t b_hi, b_lo;
+	uint64_t rem_hi, rem_lo;
+	uint64_t tmp_hi, tmp_lo;
+	uint64_t result;
+
+	if (b <= a_hi) {
+		return 0xFFFFFFFFFFFFFFFFull;
+	}
+
+	b_hi = b >> 32;
+	result = ((b_hi << 32) <= a_hi) ? (0xFFFFFFFFull << 32) : (a_hi / b_hi) << 32;
+	mul64(b, result, &tmp_hi, &tmp_lo);
+	sub128(a_hi, a_lo, tmp_hi, tmp_lo, &rem_hi, &rem_lo);
+	
+	while ((int64_t) rem_hi < 0) {
+		result -= 0x1ll << 32;
+		b_lo = b << 32;
+		add128(rem_hi, rem_lo, b_hi, b_lo, &rem_hi, &rem_lo);
+	}
+
+	rem_hi = (rem_hi << 32) | (rem_lo >> 32);
+	if ((b_hi << 32) <= rem_hi) {
+		result |= 0xFFFFFFFF;
+	} else {
+		result |= rem_hi / b_hi;
+	}
+
+	return result;
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/common.h
===================================================================
--- uspace/lib/softfloat/common.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/common.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Common helper operations.
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include "sftypes.h"
+
+extern float64 finish_float64(int32_t, uint64_t, char);
+extern float128 finish_float128(int32_t, uint64_t, uint64_t, char, uint64_t);
+
+extern int count_zeroes8(uint8_t);
+extern int count_zeroes32(uint32_t);
+extern int count_zeroes64(uint64_t);
+
+extern void round_float32(int32_t *, uint32_t *);
+extern void round_float64(int32_t *, uint64_t *);
+extern void round_float128(int32_t *, uint64_t *, uint64_t *);
+
+extern void lshift128(uint64_t, uint64_t, int, uint64_t *, uint64_t *);
+extern void rshift128(uint64_t, uint64_t, int, uint64_t *, uint64_t *);
+
+extern void and128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
+extern void or128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
+extern void xor128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
+extern void not128(uint64_t, uint64_t, uint64_t *, uint64_t *);
+
+extern int eq128(uint64_t, uint64_t, uint64_t, uint64_t);
+extern int le128(uint64_t, uint64_t, uint64_t, uint64_t);
+extern int lt128(uint64_t, uint64_t, uint64_t, uint64_t);
+
+extern void add128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
+extern void sub128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
+
+extern void mul64(uint64_t, uint64_t, uint64_t *, uint64_t *);
+extern void mul128(uint64_t, uint64_t, uint64_t, uint64_t,
+    uint64_t *, uint64_t *, uint64_t *, uint64_t *);
+
+extern uint64_t div128est(uint64_t, uint64_t, uint64_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/comparison.c
===================================================================
--- uspace/lib/softfloat/comparison.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/comparison.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Comparison functions.
+ */
+
+#include "sftypes.h"
+#include "comparison.h"
+#include "common.h"
+
+/**
+ * Determines whether the given float represents NaN (either signalling NaN or
+ * quiet NaN).
+ *
+ * @param f Single-precision float.
+ * @return 1 if float is NaN, 0 otherwise.
+ */
+int is_float32_nan(float32 f)
+{
+	/* NaN : exp = 0xff and nonzero fraction */
+	return ((f.parts.exp == 0xFF) && (f.parts.fraction));
+}
+
+/**
+ * Determines whether the given float represents NaN (either signalling NaN or
+ * quiet NaN).
+ *
+ * @param d Double-precision float.
+ * @return 1 if float is NaN, 0 otherwise.
+ */
+int is_float64_nan(float64 d)
+{
+	/* NaN : exp = 0x7ff and nonzero fraction */
+	return ((d.parts.exp == 0x7FF) && (d.parts.fraction));
+}
+
+/**
+ * Determines whether the given float represents NaN (either signalling NaN or
+ * quiet NaN).
+ *
+ * @param ld Quadruple-precision float.
+ * @return 1 if float is NaN, 0 otherwise.
+ */
+int is_float128_nan(float128 ld)
+{
+	/* NaN : exp = 0x7fff and nonzero fraction */
+	return ((ld.parts.exp == 0x7FF) &&
+	    !eq128(ld.parts.frac_hi, ld.parts.frac_lo, 0x0ll, 0x0ll));
+}
+
+/**
+ * Determines whether the given float represents signalling NaN.
+ *
+ * @param f Single-precision float.
+ * @return 1 if float is signalling NaN, 0 otherwise.
+ */
+int is_float32_signan(float32 f)
+{
+	/* SigNaN : exp = 0xff and fraction = 0xxxxx..x (binary),
+	 * where at least one x is nonzero */
+	return ((f.parts.exp == 0xFF) &&
+	    (f.parts.fraction < 0x400000) && (f.parts.fraction));
+}
+
+/**
+ * Determines whether the given float represents signalling NaN.
+ *
+ * @param d Double-precision float.
+ * @return 1 if float is signalling NaN, 0 otherwise.
+ */
+int is_float64_signan(float64 d)
+{
+	/* SigNaN : exp = 0x7ff and fraction = 0xxxxx..x (binary),
+	 * where at least one x is nonzero */
+	return ((d.parts.exp == 0x7FF) &&
+	    (d.parts.fraction) && (d.parts.fraction < 0x8000000000000ll));
+}
+
+/**
+ * Determines whether the given float represents signalling NaN.
+ *
+ * @param ld Quadruple-precision float.
+ * @return 1 if float is signalling NaN, 0 otherwise.
+ */
+int is_float128_signan(float128 ld)
+{
+	/* SigNaN : exp = 0x7fff and fraction = 0xxxxx..x (binary),
+	 * where at least one x is nonzero */
+	return ((ld.parts.exp == 0x7FFF) &&
+	    (ld.parts.frac_hi || ld.parts.frac_lo) &&
+	    lt128(ld.parts.frac_hi, ld.parts.frac_lo, 0x800000000000ll, 0x0ll));
+
+}
+
+/**
+ * Determines whether the given float represents positive or negative infinity.
+ *
+ * @param f Single-precision float.
+ * @return 1 if float is infinite, 0 otherwise.
+ */
+int is_float32_infinity(float32 f)
+{
+	/* NaN : exp = 0x7ff and zero fraction */
+	return ((f.parts.exp == 0xFF) && (f.parts.fraction == 0x0));
+}
+
+/**
+ * Determines whether the given float represents positive or negative infinity.
+ *
+ * @param d Double-precision float.
+ * @return 1 if float is infinite, 0 otherwise.
+ */
+int is_float64_infinity(float64 d)
+{
+	/* NaN : exp = 0x7ff and zero fraction */
+	return ((d.parts.exp == 0x7FF) && (d.parts.fraction == 0x0));
+}
+
+/**
+ * Determines whether the given float represents positive or negative infinity.
+ *
+ * @param ld Quadruple-precision float.
+ * @return 1 if float is infinite, 0 otherwise.
+ */
+int is_float128_infinity(float128 ld)
+{
+	/* NaN : exp = 0x7fff and zero fraction */
+	return ((ld.parts.exp == 0x7FFF) &&
+	    eq128(ld.parts.frac_hi, ld.parts.frac_lo, 0x0ll, 0x0ll));
+}
+
+/**
+ * Determines whether the given float represents positive or negative zero.
+ *
+ * @param f Single-precision float.
+ * @return 1 if float is zero, 0 otherwise.
+ */
+int is_float32_zero(float32 f)
+{
+	return (((f.bin) & 0x7FFFFFFF) == 0);
+}
+
+/**
+ * Determines whether the given float represents positive or negative zero.
+ *
+ * @param d Double-precision float.
+ * @return 1 if float is zero, 0 otherwise.
+ */
+int is_float64_zero(float64 d)
+{
+	return (((d.bin) & 0x7FFFFFFFFFFFFFFFll) == 0);
+}
+
+/**
+ * Determines whether the given float represents positive or negative zero.
+ *
+ * @param ld Quadruple-precision float.
+ * @return 1 if float is zero, 0 otherwise.
+ */
+int is_float128_zero(float128 ld)
+{
+	uint64_t tmp_hi;
+	uint64_t tmp_lo;
+	
+	and128(ld.bin.hi, ld.bin.lo,
+	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
+	
+	return eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll);
+}
+
+/**
+ * Determine whether two floats are equal. NaNs are not recognized.
+ *
+ * @a First single-precision operand.
+ * @b Second single-precision operand.
+ * @return 1 if both floats are equal, 0 otherwise.
+ */
+int is_float32_eq(float32 a, float32 b)
+{
+	/* a equals to b or both are zeros (with any sign) */
+	return ((a.bin == b.bin) ||
+	    (((a.bin | b.bin) & 0x7FFFFFFF) == 0));
+}
+
+/**
+ * Determine whether two floats are equal. NaNs are not recognized.
+ *
+ * @a First double-precision operand.
+ * @b Second double-precision operand.
+ * @return 1 if both floats are equal, 0 otherwise.
+ */
+int is_float64_eq(float64 a, float64 b)
+{
+	/* a equals to b or both are zeros (with any sign) */
+	return ((a.bin == b.bin) ||
+	    (((a.bin | b.bin) & 0x7FFFFFFFFFFFFFFFll) == 0));
+}
+
+/**
+ * Determine whether two floats are equal. NaNs are not recognized.
+ *
+ * @a First quadruple-precision operand.
+ * @b Second quadruple-precision operand.
+ * @return 1 if both floats are equal, 0 otherwise.
+ */
+int is_float128_eq(float128 a, float128 b)
+{
+	uint64_t tmp_hi;
+	uint64_t tmp_lo;
+	
+	/* both are zeros (with any sign) */
+	or128(a.bin.hi, a.bin.lo,
+	    b.bin.hi, b.bin.lo, &tmp_hi, &tmp_lo);
+	and128(tmp_hi, tmp_lo,
+	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
+	int both_zero = eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll);
+	
+	/* a equals to b */
+	int are_equal = eq128(a.bin.hi, a.bin.lo, b.bin.hi, b.bin.lo);
+	
+	return are_equal || both_zero;
+}
+
+/**
+ * Lower-than comparison between two floats. NaNs are not recognized.
+ *
+ * @a First single-precision operand.
+ * @b Second single-precision operand.
+ * @return 1 if a is lower than b, 0 otherwise.
+ */
+int is_float32_lt(float32 a, float32 b) 
+{
+	if (((a.bin | b.bin) & 0x7FFFFFFF) == 0) {
+		/* +- zeroes */
+		return 0;
+	}
+	
+	if ((a.parts.sign) && (b.parts.sign)) {
+		/* if both are negative, smaller is that with greater binary value */
+		return (a.bin > b.bin);
+	}
+	
+	/*
+	 * lets negate signs - now will be positive numbers always
+	 * bigger than negative (first bit will be set for unsigned
+	 * integer comparison)
+	 */
+	a.parts.sign = !a.parts.sign;
+	b.parts.sign = !b.parts.sign;
+	return (a.bin < b.bin);
+}
+
+/**
+ * Lower-than comparison between two floats. NaNs are not recognized.
+ *
+ * @a First double-precision operand.
+ * @b Second double-precision operand.
+ * @return 1 if a is lower than b, 0 otherwise.
+ */
+int is_float64_lt(float64 a, float64 b)
+{
+	if (((a.bin | b.bin) & 0x7FFFFFFFFFFFFFFFll) == 0) {
+		/* +- zeroes */
+		return 0;
+	}
+	
+	if ((a.parts.sign) && (b.parts.sign)) {
+		/* if both are negative, smaller is that with greater binary value */
+		return (a.bin > b.bin);
+	}
+	
+	/*
+	 * lets negate signs - now will be positive numbers always
+	 * bigger than negative (first bit will be set for unsigned
+	 * integer comparison)
+	 */
+	a.parts.sign = !a.parts.sign;
+	b.parts.sign = !b.parts.sign;
+	return (a.bin < b.bin);
+}
+
+/**
+ * Lower-than comparison between two floats. NaNs are not recognized.
+ *
+ * @a First quadruple-precision operand.
+ * @b Second quadruple-precision operand.
+ * @return 1 if a is lower than b, 0 otherwise.
+ */
+int is_float128_lt(float128 a, float128 b)
+{
+	uint64_t tmp_hi;
+	uint64_t tmp_lo;
+	
+	or128(a.bin.hi, a.bin.lo,
+	    b.bin.hi, b.bin.lo, &tmp_hi, &tmp_lo);
+	and128(tmp_hi, tmp_lo,
+	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
+	if (eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll)) {
+		/* +- zeroes */
+		return 0;
+	}
+	
+	if ((a.parts.sign) && (b.parts.sign)) {
+		/* if both are negative, smaller is that with greater binary value */
+		return lt128(b.bin.hi, b.bin.lo, a.bin.hi, a.bin.lo);
+	}
+	
+	/*
+	 * lets negate signs - now will be positive numbers always
+	 * bigger than negative (first bit will be set for unsigned
+	 * integer comparison)
+	 */
+	a.parts.sign = !a.parts.sign;
+	b.parts.sign = !b.parts.sign;
+	return lt128(a.bin.hi, a.bin.lo, b.bin.hi, b.bin.lo);
+}
+
+/**
+ * Greater-than comparison between two floats. NaNs are not recognized.
+ *
+ * @a First single-precision operand.
+ * @b Second single-precision operand.
+ * @return 1 if a is greater than b, 0 otherwise.
+ */
+int is_float32_gt(float32 a, float32 b) 
+{
+	if (((a.bin | b.bin) & 0x7FFFFFFF) == 0) {
+		/* zeroes are equal with any sign */
+		return 0;
+	}
+	
+	if ((a.parts.sign) && (b.parts.sign)) {
+		/* if both are negative, greater is that with smaller binary value */
+		return (a.bin < b.bin);
+	}
+	
+	/*
+	 * lets negate signs - now will be positive numbers always
+	 * bigger than negative (first bit will be set for unsigned
+	 * integer comparison)
+	 */
+	a.parts.sign = !a.parts.sign;
+	b.parts.sign = !b.parts.sign;
+	return (a.bin > b.bin);
+}
+
+/**
+ * Greater-than comparison between two floats. NaNs are not recognized.
+ *
+ * @a First double-precision operand.
+ * @b Second double-precision operand.
+ * @return 1 if a is greater than b, 0 otherwise.
+ */
+int is_float64_gt(float64 a, float64 b)
+{
+	if (((a.bin | b.bin) & 0x7FFFFFFFFFFFFFFFll) == 0) {
+		/* zeroes are equal with any sign */
+		return 0;
+	}
+	
+	if ((a.parts.sign) && (b.parts.sign)) {
+		/* if both are negative, greater is that with smaller binary value */
+		return (a.bin < b.bin);
+	}
+	
+	/*
+	 * lets negate signs - now will be positive numbers always
+	 * bigger than negative (first bit will be set for unsigned
+	 * integer comparison)
+	 */
+	a.parts.sign = !a.parts.sign;
+	b.parts.sign = !b.parts.sign;
+	return (a.bin > b.bin);
+}
+
+/**
+ * Greater-than comparison between two floats. NaNs are not recognized.
+ *
+ * @a First quadruple-precision operand.
+ * @b Second quadruple-precision operand.
+ * @return 1 if a is greater than b, 0 otherwise.
+ */
+int is_float128_gt(float128 a, float128 b)
+{
+	uint64_t tmp_hi;
+	uint64_t tmp_lo;
+	
+	or128(a.bin.hi, a.bin.lo,
+	    b.bin.hi, b.bin.lo, &tmp_hi, &tmp_lo);
+	and128(tmp_hi, tmp_lo,
+	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
+	if (eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll)) {
+		/* zeroes are equal with any sign */
+		return 0;
+	}
+	
+	if ((a.parts.sign) && (b.parts.sign)) {
+		/* if both are negative, greater is that with smaller binary value */
+		return lt128(a.bin.hi, a.bin.lo, b.bin.hi, b.bin.lo);
+	}
+	
+	/*
+	 * lets negate signs - now will be positive numbers always
+	 * bigger than negative (first bit will be set for unsigned
+	 * integer comparison)
+	 */
+	a.parts.sign = !a.parts.sign;
+	b.parts.sign = !b.parts.sign;
+	return lt128(b.bin.hi, b.bin.lo, a.bin.hi, a.bin.lo);
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/comparison.h
===================================================================
--- uspace/lib/softfloat/comparison.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/comparison.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Comparison functions.
+ */
+
+#ifndef __COMPARISON_H__
+#define __COMPARISON_H__
+
+extern int is_float32_nan(float32);
+extern int is_float32_signan(float32);
+
+extern int is_float32_infinity(float32);
+extern int is_float32_zero(float32);
+
+extern int is_float32_eq(float32, float32);
+extern int is_float32_lt(float32, float32);
+extern int is_float32_gt(float32, float32);
+
+extern int is_float64_nan(float64);
+extern int is_float64_signan(float64);
+
+extern int is_float64_infinity(float64);
+extern int is_float64_zero(float64);
+
+extern int is_float64_eq(float64, float64);
+extern int is_float64_lt(float64, float64);
+extern int is_float64_gt(float64, float64);
+
+extern int is_float96_nan(float96);
+extern int is_float96_signan(float96);
+
+extern int is_float96_infinity(float96);
+extern int is_float96_zero(float96);
+
+extern int is_float96_eq(float96, float96);
+extern int is_float96_lt(float96, float96);
+extern int is_float96_gt(float96, float96);
+
+extern int is_float128_nan(float128);
+extern int is_float128_signan(float128);
+
+extern int is_float128_infinity(float128);
+extern int is_float128_zero(float128);
+
+extern int is_float128_eq(float128, float128);
+extern int is_float128_lt(float128, float128);
+extern int is_float128_gt(float128, float128);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/conversion.c
===================================================================
--- uspace/lib/softfloat/conversion.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/conversion.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,1041 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Conversion of precision and conversion between integers and floats.
+ */
+
+#include "sftypes.h"
+#include "conversion.h"
+#include "comparison.h"
+#include "common.h"
+
+float64 float32_to_float64(float32 a)
+{
+	float64 result;
+	uint64_t frac;
+	
+	result.parts.sign = a.parts.sign;
+	result.parts.fraction = a.parts.fraction;
+	result.parts.fraction <<= (FLOAT64_FRACTION_SIZE - FLOAT32_FRACTION_SIZE);
+	
+	if ((is_float32_infinity(a)) || (is_float32_nan(a))) {
+		result.parts.exp = FLOAT64_MAX_EXPONENT;
+		// TODO; check if its correct for SigNaNs
+		return result;
+	}
+	
+	result.parts.exp = a.parts.exp + ((int) FLOAT64_BIAS - FLOAT32_BIAS);
+	if (a.parts.exp == 0) {
+		/* normalize denormalized numbers */
+		
+		if (result.parts.fraction == 0) { /* fix zero */
+			result.parts.exp = 0;
+			return result;
+		}
+			
+		frac = result.parts.fraction;
+		
+		while (!(frac & FLOAT64_HIDDEN_BIT_MASK)) {
+			frac <<= 1;
+			--result.parts.exp;
+		}
+		
+		++result.parts.exp;
+		result.parts.fraction = frac;
+	}
+	
+	return result;
+}
+
+float128 float32_to_float128(float32 a)
+{
+	float128 result;
+	uint64_t frac_hi, frac_lo;
+	uint64_t tmp_hi, tmp_lo;
+	
+	result.parts.sign = a.parts.sign;
+	result.parts.frac_hi = 0;
+	result.parts.frac_lo = a.parts.fraction;
+	lshift128(result.parts.frac_hi, result.parts.frac_lo,
+	    (FLOAT128_FRACTION_SIZE - FLOAT32_FRACTION_SIZE),
+	    &frac_hi, &frac_lo);
+	result.parts.frac_hi = frac_hi;
+	result.parts.frac_lo = frac_lo;
+	
+	if ((is_float32_infinity(a)) || (is_float32_nan(a))) {
+		result.parts.exp = FLOAT128_MAX_EXPONENT;
+		// TODO; check if its correct for SigNaNs
+		return result;
+	}
+	
+	result.parts.exp = a.parts.exp + ((int) FLOAT128_BIAS - FLOAT32_BIAS);
+	if (a.parts.exp == 0) {
+		/* normalize denormalized numbers */
+		
+		if (eq128(result.parts.frac_hi,
+		    result.parts.frac_lo, 0x0ll, 0x0ll)) { /* fix zero */
+			result.parts.exp = 0;
+			return result;
+		}
+		
+		frac_hi = result.parts.frac_hi;
+		frac_lo = result.parts.frac_lo;
+		
+		and128(frac_hi, frac_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &tmp_hi, &tmp_lo);
+		while (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+			lshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
+			--result.parts.exp;
+		}
+		
+		++result.parts.exp;
+		result.parts.frac_hi = frac_hi;
+		result.parts.frac_lo = frac_lo;
+	}
+	
+	return result;
+}
+
+float128 float64_to_float128(float64 a)
+{
+	float128 result;
+	uint64_t frac_hi, frac_lo;
+	uint64_t tmp_hi, tmp_lo;
+	
+	result.parts.sign = a.parts.sign;
+	result.parts.frac_hi = 0;
+	result.parts.frac_lo = a.parts.fraction;
+	lshift128(result.parts.frac_hi, result.parts.frac_lo,
+	    (FLOAT128_FRACTION_SIZE - FLOAT64_FRACTION_SIZE),
+	    &frac_hi, &frac_lo);
+	result.parts.frac_hi = frac_hi;
+	result.parts.frac_lo = frac_lo;
+	
+	if ((is_float64_infinity(a)) || (is_float64_nan(a))) {
+		result.parts.exp = FLOAT128_MAX_EXPONENT;
+		// TODO; check if its correct for SigNaNs
+		return result;
+	}
+	
+	result.parts.exp = a.parts.exp + ((int) FLOAT128_BIAS - FLOAT64_BIAS);
+	if (a.parts.exp == 0) {
+		/* normalize denormalized numbers */
+		
+		if (eq128(result.parts.frac_hi,
+		    result.parts.frac_lo, 0x0ll, 0x0ll)) { /* fix zero */
+			result.parts.exp = 0;
+			return result;
+		}
+		
+		frac_hi = result.parts.frac_hi;
+		frac_lo = result.parts.frac_lo;
+		
+		and128(frac_hi, frac_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &tmp_hi, &tmp_lo);
+		while (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+			lshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
+			--result.parts.exp;
+		}
+		
+		++result.parts.exp;
+		result.parts.frac_hi = frac_hi;
+		result.parts.frac_lo = frac_lo;
+	}
+	
+	return result;
+}
+
+float32 float64_to_float32(float64 a)
+{
+	float32 result;
+	int32_t exp;
+	uint64_t frac;
+	
+	result.parts.sign = a.parts.sign;
+	
+	if (is_float64_nan(a)) {
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		
+		if (is_float64_signan(a)) {
+			/* set first bit of fraction nonzero */
+			result.parts.fraction = FLOAT32_HIDDEN_BIT_MASK >> 1;
+			return result;
+		}
+		
+		/* fraction nonzero but its first bit is zero */
+		result.parts.fraction = 0x1;
+		return result;
+	}
+	
+	if (is_float64_infinity(a)) {
+		result.parts.fraction = 0;
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		return result;
+	}
+	
+	exp = (int) a.parts.exp - FLOAT64_BIAS + FLOAT32_BIAS;
+	
+	if (exp >= FLOAT32_MAX_EXPONENT) {
+		/* FIXME: overflow */
+		result.parts.fraction = 0;
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		return result;
+	} else if (exp <= 0) {
+		/* underflow or denormalized */
+		
+		result.parts.exp = 0;
+		
+		exp *= -1;	
+		if (exp > FLOAT32_FRACTION_SIZE) {
+			/* FIXME: underflow */
+			result.parts.fraction = 0;
+			return result;
+		}
+		
+		/* denormalized */
+		
+		frac = a.parts.fraction; 
+		frac |= FLOAT64_HIDDEN_BIT_MASK; /* denormalize and set hidden bit */
+		
+		frac >>= (FLOAT64_FRACTION_SIZE - FLOAT32_FRACTION_SIZE + 1);
+		
+		while (exp > 0) {
+			--exp;
+			frac >>= 1;
+		}
+		result.parts.fraction = frac;
+		
+		return result;
+	}
+	
+	result.parts.exp = exp;
+	result.parts.fraction =
+	    a.parts.fraction >> (FLOAT64_FRACTION_SIZE - FLOAT32_FRACTION_SIZE);
+	return result;
+}
+
+float32 float128_to_float32(float128 a)
+{
+	float32 result;
+	int32_t exp;
+	uint64_t frac_hi, frac_lo;
+	
+	result.parts.sign = a.parts.sign;
+	
+	if (is_float128_nan(a)) {
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		
+		if (is_float128_signan(a)) {
+			/* set first bit of fraction nonzero */
+			result.parts.fraction = FLOAT32_HIDDEN_BIT_MASK >> 1;
+			return result;
+		}
+		
+		/* fraction nonzero but its first bit is zero */
+		result.parts.fraction = 0x1;
+		return result;
+	}
+	
+	if (is_float128_infinity(a)) {
+		result.parts.fraction = 0;
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		return result;
+	}
+	
+	exp = (int) a.parts.exp - FLOAT128_BIAS + FLOAT32_BIAS;
+	
+	if (exp >= FLOAT32_MAX_EXPONENT) {
+		/* FIXME: overflow */
+		result.parts.fraction = 0;
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		return result;
+	} else if (exp <= 0) {
+		/* underflow or denormalized */
+		
+		result.parts.exp = 0;
+		
+		exp *= -1;
+		if (exp > FLOAT32_FRACTION_SIZE) {
+			/* FIXME: underflow */
+			result.parts.fraction = 0;
+			return result;
+		}
+		
+		/* denormalized */
+		
+		frac_hi = a.parts.frac_hi;
+		frac_lo = a.parts.frac_lo;
+		
+		/* denormalize and set hidden bit */
+		frac_hi |= FLOAT128_HIDDEN_BIT_MASK_HI;
+		
+		rshift128(frac_hi, frac_lo,
+		    (FLOAT128_FRACTION_SIZE - FLOAT32_FRACTION_SIZE + 1),
+		    &frac_hi, &frac_lo);
+		
+		while (exp > 0) {
+			--exp;
+			rshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
+		}
+		result.parts.fraction = frac_lo;
+		
+		return result;
+	}
+	
+	result.parts.exp = exp;
+	frac_hi = a.parts.frac_hi;
+	frac_lo = a.parts.frac_lo;
+	rshift128(frac_hi, frac_lo,
+	    (FLOAT128_FRACTION_SIZE - FLOAT32_FRACTION_SIZE + 1),
+	    &frac_hi, &frac_lo);
+	result.parts.fraction = frac_lo;
+	return result;
+}
+
+float64 float128_to_float64(float128 a)
+{
+	float64 result;
+	int32_t exp;
+	uint64_t frac_hi, frac_lo;
+	
+	result.parts.sign = a.parts.sign;
+	
+	if (is_float128_nan(a)) {
+		result.parts.exp = FLOAT64_MAX_EXPONENT;
+		
+		if (is_float128_signan(a)) {
+			/* set first bit of fraction nonzero */
+			result.parts.fraction = FLOAT64_HIDDEN_BIT_MASK >> 1;
+			return result;
+		}
+		
+		/* fraction nonzero but its first bit is zero */
+		result.parts.fraction = 0x1;
+		return result;
+	}
+	
+	if (is_float128_infinity(a)) {
+		result.parts.fraction = 0;
+		result.parts.exp = FLOAT64_MAX_EXPONENT;
+		return result;
+	}
+	
+	exp = (int) a.parts.exp - FLOAT128_BIAS + FLOAT64_BIAS;
+	
+	if (exp >= FLOAT64_MAX_EXPONENT) {
+		/* FIXME: overflow */
+		result.parts.fraction = 0;
+		result.parts.exp = FLOAT64_MAX_EXPONENT;
+		return result;
+	} else if (exp <= 0) {
+		/* underflow or denormalized */
+		
+		result.parts.exp = 0;
+		
+		exp *= -1;
+		if (exp > FLOAT64_FRACTION_SIZE) {
+			/* FIXME: underflow */
+			result.parts.fraction = 0;
+			return result;
+		}
+		
+		/* denormalized */
+		
+		frac_hi = a.parts.frac_hi;
+		frac_lo = a.parts.frac_lo;
+		
+		/* denormalize and set hidden bit */
+		frac_hi |= FLOAT128_HIDDEN_BIT_MASK_HI;
+		
+		rshift128(frac_hi, frac_lo,
+		    (FLOAT128_FRACTION_SIZE - FLOAT64_FRACTION_SIZE + 1),
+		    &frac_hi, &frac_lo);
+		
+		while (exp > 0) {
+			--exp;
+			rshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
+		}
+		result.parts.fraction = frac_lo;
+		
+		return result;
+	}
+	
+	result.parts.exp = exp;
+	frac_hi = a.parts.frac_hi;
+	frac_lo = a.parts.frac_lo;
+	rshift128(frac_hi, frac_lo,
+	    (FLOAT128_FRACTION_SIZE - FLOAT64_FRACTION_SIZE + 1),
+	    &frac_hi, &frac_lo);
+	result.parts.fraction = frac_lo;
+	return result;
+}
+
+/** Helper procedure for converting float32 to uint32.
+ *
+ * @param a Floating point number in normalized form
+ *     (NaNs or Inf are not checked).
+ * @return Converted unsigned integer.
+ */
+static uint32_t _float32_to_uint32_helper(float32 a)
+{
+	uint32_t frac;
+	
+	if (a.parts.exp < FLOAT32_BIAS) {
+		/* TODO: rounding */
+		return 0;
+	}
+	
+	frac = a.parts.fraction;
+	
+	frac |= FLOAT32_HIDDEN_BIT_MASK;
+	/* shift fraction to left so hidden bit will be the most significant bit */
+	frac <<= 32 - FLOAT32_FRACTION_SIZE - 1; 
+	
+	frac >>= 32 - (a.parts.exp - FLOAT32_BIAS) - 1;
+	if ((a.parts.sign == 1) && (frac != 0)) {
+		frac = ~frac;
+		++frac;
+	}
+	
+	return frac;
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+uint32_t float32_to_uint32(float32 a)
+{
+	if (is_float32_nan(a))
+		return UINT32_MAX;
+	
+	if (is_float32_infinity(a) || (a.parts.exp >= (32 + FLOAT32_BIAS))) {
+		if (a.parts.sign)
+			return UINT32_MIN;
+		
+		return UINT32_MAX;
+	}
+	
+	return _float32_to_uint32_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+int32_t float32_to_int32(float32 a)
+{
+	if (is_float32_nan(a))
+		return INT32_MAX;
+	
+	if (is_float32_infinity(a) || (a.parts.exp >= (32 + FLOAT32_BIAS))) {
+		if (a.parts.sign)
+			return INT32_MIN;
+		
+		return INT32_MAX;
+	}
+	
+	return _float32_to_uint32_helper(a);
+}
+
+/** Helper procedure for converting float32 to uint64.
+ *
+ * @param a Floating point number in normalized form
+ *     (NaNs or Inf are not checked).
+ * @return Converted unsigned integer.
+ */
+static uint64_t _float32_to_uint64_helper(float32 a)
+{
+	uint64_t frac;
+	
+	if (a.parts.exp < FLOAT32_BIAS) {
+		// TODO: rounding
+		return 0;
+	}
+	
+	frac = a.parts.fraction;
+	
+	frac |= FLOAT32_HIDDEN_BIT_MASK;
+	/* shift fraction to left so hidden bit will be the most significant bit */
+	frac <<= 64 - FLOAT32_FRACTION_SIZE - 1;
+	
+	frac >>= 64 - (a.parts.exp - FLOAT32_BIAS) - 1;
+	if ((a.parts.sign == 1) && (frac != 0)) {
+		frac = ~frac;
+		++frac;
+	}
+	
+	return frac;
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+uint64_t float32_to_uint64(float32 a)
+{
+	if (is_float32_nan(a))
+		return UINT64_MAX;
+	
+	if (is_float32_infinity(a) || (a.parts.exp >= (64 + FLOAT32_BIAS))) {
+		if (a.parts.sign)
+			return UINT64_MIN;
+		
+		return UINT64_MAX;
+	}
+	
+	return _float32_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+int64_t float32_to_int64(float32 a)
+{
+	if (is_float32_nan(a))
+		return INT64_MAX;
+	
+	if (is_float32_infinity(a) || (a.parts.exp >= (64 + FLOAT32_BIAS))) {
+		if (a.parts.sign)
+			return INT64_MIN;
+		
+		return INT64_MAX;
+	}
+	
+	return _float32_to_uint64_helper(a);
+}
+
+/** Helper procedure for converting float64 to uint64.
+ *
+ * @param a Floating point number in normalized form
+ *     (NaNs or Inf are not checked).
+ * @return Converted unsigned integer.
+ */
+static uint64_t _float64_to_uint64_helper(float64 a)
+{
+	uint64_t frac;
+	
+	if (a.parts.exp < FLOAT64_BIAS) {
+		// TODO: rounding
+		return 0;
+	}
+	
+	frac = a.parts.fraction;
+	
+	frac |= FLOAT64_HIDDEN_BIT_MASK;
+	/* shift fraction to left so hidden bit will be the most significant bit */
+	frac <<= 64 - FLOAT64_FRACTION_SIZE - 1;
+	
+	frac >>= 64 - (a.parts.exp - FLOAT64_BIAS) - 1;
+	if ((a.parts.sign == 1) && (frac != 0)) {
+		frac = ~frac;
+		++frac;
+	}
+	
+	return frac;
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+uint32_t float64_to_uint32(float64 a)
+{
+	if (is_float64_nan(a))
+		return UINT32_MAX;
+	
+	if (is_float64_infinity(a) || (a.parts.exp >= (32 + FLOAT64_BIAS))) {
+		if (a.parts.sign)
+			return UINT32_MIN;
+		
+		return UINT32_MAX;
+	}
+	
+	return (uint32_t) _float64_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+int32_t float64_to_int32(float64 a)
+{
+	if (is_float64_nan(a))
+		return INT32_MAX;
+	
+	if (is_float64_infinity(a) || (a.parts.exp >= (32 + FLOAT64_BIAS))) {
+		if (a.parts.sign)
+			return INT32_MIN;
+		
+		return INT32_MAX;
+	}
+	
+	return (int32_t) _float64_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens 
+ *  - now its the biggest or the smallest int
+ */
+uint64_t float64_to_uint64(float64 a)
+{
+	if (is_float64_nan(a))
+		return UINT64_MAX;
+	
+	if (is_float64_infinity(a) || (a.parts.exp >= (64 + FLOAT64_BIAS))) {
+		if (a.parts.sign)
+			return UINT64_MIN;
+		
+		return UINT64_MAX;
+	}
+	
+	return _float64_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens 
+ *  - now its the biggest or the smallest int
+ */
+int64_t float64_to_int64(float64 a)
+{
+	if (is_float64_nan(a))
+		return INT64_MAX;
+	
+	if (is_float64_infinity(a) || (a.parts.exp >= (64 + FLOAT64_BIAS))) {
+		if (a.parts.sign)
+			return INT64_MIN;
+		
+		return INT64_MAX;
+	}
+	
+	return _float64_to_uint64_helper(a);
+}
+
+/** Helper procedure for converting float128 to uint64.
+ *
+ * @param a Floating point number in normalized form
+ *     (NaNs or Inf are not checked).
+ * @return Converted unsigned integer.
+ */
+static uint64_t _float128_to_uint64_helper(float128 a)
+{
+	uint64_t frac_hi, frac_lo;
+	
+	if (a.parts.exp < FLOAT128_BIAS) {
+		// TODO: rounding
+		return 0;
+	}
+	
+	frac_hi = a.parts.frac_hi;
+	frac_lo = a.parts.frac_lo;
+	
+	frac_hi |= FLOAT128_HIDDEN_BIT_MASK_HI;
+	/* shift fraction to left so hidden bit will be the most significant bit */
+	lshift128(frac_hi, frac_lo,
+	    (128 - FLOAT128_FRACTION_SIZE - 1), &frac_hi, &frac_lo);
+	
+	rshift128(frac_hi, frac_lo,
+	    (128 - (a.parts.exp - FLOAT128_BIAS) - 1), &frac_hi, &frac_lo);
+	if ((a.parts.sign == 1) && !eq128(frac_hi, frac_lo, 0x0ll, 0x0ll)) {
+		not128(frac_hi, frac_lo, &frac_hi, &frac_lo);
+		add128(frac_hi, frac_lo, 0x0ll, 0x1ll, &frac_hi, &frac_lo);
+	}
+	
+	return frac_lo;
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+uint32_t float128_to_uint32(float128 a)
+{
+	if (is_float128_nan(a))
+		return UINT32_MAX;
+	
+	if (is_float128_infinity(a) || (a.parts.exp >= (32 + FLOAT128_BIAS))) {
+		if (a.parts.sign)
+			return UINT32_MIN;
+		
+		return UINT32_MAX;
+	}
+	
+	return (uint32_t) _float128_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+int32_t float128_to_int32(float128 a)
+{
+	if (is_float128_nan(a))
+		return INT32_MAX;
+	
+	if (is_float128_infinity(a) || (a.parts.exp >= (32 + FLOAT128_BIAS))) {
+		if (a.parts.sign)
+			return INT32_MIN;
+		
+		return INT32_MAX;
+	}
+	
+	return (int32_t) _float128_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+uint64_t float128_to_uint64(float128 a)
+{
+	if (is_float128_nan(a))
+		return UINT64_MAX;
+	
+	if (is_float128_infinity(a) || (a.parts.exp >= (64 + FLOAT128_BIAS))) {
+		if (a.parts.sign)
+			return UINT64_MIN;
+		
+		return UINT64_MAX;
+	}
+	
+	return _float128_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+int64_t float128_to_int64(float128 a)
+{
+	if (is_float128_nan(a))
+		return INT64_MAX;
+	
+	if (is_float128_infinity(a) || (a.parts.exp >= (64 + FLOAT128_BIAS))) {
+		if (a.parts.sign)
+			return INT64_MIN;
+		
+		return INT64_MAX;
+	}
+	
+	return _float128_to_uint64_helper(a);
+}
+
+float32 uint32_to_float32(uint32_t i)
+{
+	int counter;
+	int32_t exp;
+	float32 result;
+	
+	result.parts.sign = 0;
+	result.parts.fraction = 0;
+	
+	counter = count_zeroes32(i);
+	
+	exp = FLOAT32_BIAS + 32 - counter - 1;
+	
+	if (counter == 32) {
+		result.bin = 0;
+		return result;
+	}
+	
+	if (counter > 0) {
+		i <<= counter - 1;
+	} else {
+		i >>= 1;
+	}
+	
+	round_float32(&exp, &i);
+	
+	result.parts.fraction = i >> (32 - FLOAT32_FRACTION_SIZE - 2);
+	result.parts.exp = exp;
+	
+	return result;
+}
+
+float32 int32_to_float32(int32_t i)
+{
+	float32 result;
+	
+	if (i < 0)
+		result = uint32_to_float32((uint32_t) (-i));
+	else
+		result = uint32_to_float32((uint32_t) i);
+	
+	result.parts.sign = i < 0;
+	
+	return result;
+}
+
+float32 uint64_to_float32(uint64_t i)
+{
+	int counter;
+	int32_t exp;
+	uint32_t j;
+	float32 result;
+	
+	result.parts.sign = 0;
+	result.parts.fraction = 0;
+	
+	counter = count_zeroes64(i);
+	
+	exp = FLOAT32_BIAS + 64 - counter - 1;
+	
+	if (counter == 64) {
+		result.bin = 0;
+		return result;
+	}
+	
+	/* Shift all to the first 31 bits (31st will be hidden 1) */
+	if (counter > 33) {
+		i <<= counter - 1 - 32;
+	} else {
+		i >>= 1 + 32 - counter;
+	}
+	
+	j = (uint32_t) i;
+	round_float32(&exp, &j);
+	
+	result.parts.fraction = j >> (32 - FLOAT32_FRACTION_SIZE - 2);
+	result.parts.exp = exp;
+	return result;
+}
+
+float32 int64_to_float32(int64_t i)
+{
+	float32 result;
+	
+	if (i < 0)
+		result = uint64_to_float32((uint64_t) (-i));
+	else
+		result = uint64_to_float32((uint64_t) i);
+	
+	result.parts.sign = i < 0;
+	
+	return result;
+}
+
+float64 uint32_to_float64(uint32_t i)
+{
+	int counter;
+	int32_t exp;
+	float64 result;
+	uint64_t frac;
+	
+	result.parts.sign = 0;
+	result.parts.fraction = 0;
+	
+	counter = count_zeroes32(i);
+	
+	exp = FLOAT64_BIAS + 32 - counter - 1;
+	
+	if (counter == 32) {
+		result.bin = 0;
+		return result;
+	}
+	
+	frac = i;
+	frac <<= counter + 32 - 1;
+	
+	round_float64(&exp, &frac);
+	
+	result.parts.fraction = frac >> (64 - FLOAT64_FRACTION_SIZE - 2);
+	result.parts.exp = exp;
+	
+	return result;
+}
+
+float64 int32_to_float64(int32_t i)
+{
+	float64 result;
+	
+	if (i < 0)
+		result = uint32_to_float64((uint32_t) (-i));
+	else
+		result = uint32_to_float64((uint32_t) i);
+	
+	result.parts.sign = i < 0;
+	
+	return result;
+}
+
+
+float64 uint64_to_float64(uint64_t i)
+{
+	int counter;
+	int32_t exp;
+	float64 result;
+	
+	result.parts.sign = 0;
+	result.parts.fraction = 0;
+	
+	counter = count_zeroes64(i);
+	
+	exp = FLOAT64_BIAS + 64 - counter - 1;
+	
+	if (counter == 64) {
+		result.bin = 0;
+		return result;
+	}
+	
+	if (counter > 0) {
+		i <<= counter - 1;
+	} else {
+		i >>= 1;
+	}
+	
+	round_float64(&exp, &i);
+	
+	result.parts.fraction = i >> (64 - FLOAT64_FRACTION_SIZE - 2);
+	result.parts.exp = exp;
+	return result;
+}
+
+float64 int64_to_float64(int64_t i)
+{
+	float64 result;
+	
+	if (i < 0)
+		result = uint64_to_float64((uint64_t) (-i));
+	else
+		result = uint64_to_float64((uint64_t) i);
+	
+	result.parts.sign = i < 0;
+	
+	return result;
+}
+
+float128 uint32_to_float128(uint32_t i)
+{
+	int counter;
+	int32_t exp;
+	float128 result;
+	uint64_t frac_hi, frac_lo;
+	
+	result.parts.sign = 0;
+	result.parts.frac_hi = 0;
+	result.parts.frac_lo = 0;
+	
+	counter = count_zeroes32(i);
+	
+	exp = FLOAT128_BIAS + 32 - counter - 1;
+	
+	if (counter == 32) {
+		result.bin.hi = 0;
+		result.bin.lo = 0;
+		return result;
+	}
+	
+	frac_hi = 0;
+	frac_lo = i;
+	lshift128(frac_hi, frac_lo, (counter + 96 - 1), &frac_hi, &frac_lo);
+	
+	round_float128(&exp, &frac_hi, &frac_lo);
+	
+	rshift128(frac_hi, frac_lo,
+	    (128 - FLOAT128_FRACTION_SIZE - 2), &frac_hi, &frac_lo);
+	result.parts.frac_hi = frac_hi;
+	result.parts.frac_lo = frac_lo;
+	result.parts.exp = exp;
+	
+	return result;
+}
+
+float128 int32_to_float128(int32_t i)
+{
+	float128 result;
+	
+	if (i < 0)
+		result = uint32_to_float128((uint32_t) (-i));
+	else
+		result = uint32_to_float128((uint32_t) i);
+	
+	result.parts.sign = i < 0;
+	
+	return result;
+}
+
+
+float128 uint64_to_float128(uint64_t i)
+{
+	int counter;
+	int32_t exp;
+	float128 result;
+	uint64_t frac_hi, frac_lo;
+	
+	result.parts.sign = 0;
+	result.parts.frac_hi = 0;
+	result.parts.frac_lo = 0;
+	
+	counter = count_zeroes64(i);
+	
+	exp = FLOAT128_BIAS + 64 - counter - 1;
+	
+	if (counter == 64) {
+		result.bin.hi = 0;
+		result.bin.lo = 0;
+		return result;
+	}
+	
+	frac_hi = 0;
+	frac_lo = i;
+	lshift128(frac_hi, frac_lo, (counter + 64 - 1), &frac_hi, &frac_lo);
+	
+	round_float128(&exp, &frac_hi, &frac_lo);
+	
+	rshift128(frac_hi, frac_lo,
+	    (128 - FLOAT128_FRACTION_SIZE - 2), &frac_hi, &frac_lo);
+	result.parts.frac_hi = frac_hi;
+	result.parts.frac_lo = frac_lo;
+	result.parts.exp = exp;
+	
+	return result;
+}
+
+float128 int64_to_float128(int64_t i)
+{
+	float128 result;
+	
+	if (i < 0)
+		result = uint64_to_float128((uint64_t) (-i));
+	else
+		result = uint64_to_float128((uint64_t) i);
+	
+	result.parts.sign = i < 0;
+	
+	return result;
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/conversion.h
===================================================================
--- uspace/lib/softfloat/conversion.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/conversion.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Conversion of precision and conversion between integers and floats.
+ */
+
+#ifndef __CONVERSION_H__
+#define __CONVERSION_H__
+
+extern float64 float32_to_float64(float32);
+extern float96 float32_to_float96(float32);
+extern float128 float32_to_float128(float32);
+extern float96 float64_to_float96(float64);
+extern float128 float64_to_float128(float64);
+extern float128 float96_to_float128(float96);
+
+extern float32 float64_to_float32(float64);
+extern float32 float96_to_float32(float96);
+extern float64 float96_to_float64(float96);
+extern float32 float128_to_float32(float128);
+extern float64 float128_to_float64(float128);
+extern float96 float128_to_float96(float128);
+
+extern uint32_t float32_to_uint32(float32);
+extern int32_t float32_to_int32(float32);
+
+extern uint64_t float32_to_uint64(float32);
+extern int64_t float32_to_int64(float32);
+
+extern uint32_t float64_to_uint32(float64);
+extern int32_t float64_to_int32(float64);
+
+extern uint64_t float64_to_uint64(float64);
+extern int64_t float64_to_int64(float64);
+
+extern uint32_t float96_to_uint32(float96);
+extern int32_t float96_to_int32(float96);
+
+extern uint64_t float96_to_uint64(float96);
+extern int64_t float96_to_int64(float96);
+
+extern uint32_t float128_to_uint32(float128);
+extern int32_t float128_to_int32(float128);
+
+extern uint64_t float128_to_uint64(float128);
+extern int64_t float128_to_int64(float128);
+
+extern float32 uint32_to_float32(uint32_t);
+extern float32 int32_to_float32(int32_t);
+
+extern float32 uint64_to_float32(uint64_t);
+extern float32 int64_to_float32(int64_t);
+
+extern float64 uint32_to_float64(uint32_t);
+extern float64 int32_to_float64(int32_t);
+
+extern float64 uint64_to_float64(uint64_t);
+extern float64 int64_to_float64(int64_t);
+
+extern float96 uint32_to_float96(uint32_t);
+extern float96 int32_to_float96(int32_t);
+
+extern float96 uint64_to_float96(uint64_t);
+extern float96 int64_to_float96(int64_t);
+
+extern float128 uint32_to_float128(uint32_t);
+extern float128 int32_to_float128(int32_t);
+
+extern float128 uint64_to_float128(uint64_t);
+extern float128 int64_to_float128(int64_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/div.c
===================================================================
--- uspace/lib/softfloat/div.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/div.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Division functions.
+ */
+
+#include "sftypes.h"
+#include "add.h"
+#include "div.h"
+#include "comparison.h"
+#include "mul.h"
+#include "common.h"
+
+/** Divide two single-precision floats.
+ *
+ * @param a Nominator.
+ * @param b Denominator.
+ *
+ * @return Result of division.
+ *
+ */
+float32 div_float32(float32 a, float32 b)
+{
+	float32 result;
+	int32_t aexp, bexp, cexp;
+	uint64_t afrac, bfrac, cfrac;
+	
+	result.parts.sign = a.parts.sign ^ b.parts.sign;
+	
+	if (is_float32_nan(a)) {
+		if (is_float32_signan(a)) {
+			// FIXME: SigNaN
+		}
+		/* NaN */
+		return a;
+	}
+	
+	if (is_float32_nan(b)) {
+		if (is_float32_signan(b)) {
+			// FIXME: SigNaN
+		}
+		/* NaN */
+		return b;
+	}
+	
+	if (is_float32_infinity(a)) {
+		if (is_float32_infinity(b)) {
+			/*FIXME: inf / inf */
+			result.bin = FLOAT32_NAN;
+			return result;
+		}
+		/* inf / num */
+		result.parts.exp = a.parts.exp;
+		result.parts.fraction = a.parts.fraction;
+		return result;
+	}
+	
+	if (is_float32_infinity(b)) {
+		if (is_float32_zero(a)) {
+			/* FIXME 0 / inf */
+			result.parts.exp = 0;
+			result.parts.fraction = 0;
+			return result;
+		}
+		/* FIXME: num / inf*/
+		result.parts.exp = 0;
+		result.parts.fraction = 0;
+		return result;
+	}
+	
+	if (is_float32_zero(b)) {
+		if (is_float32_zero(a)) {
+			/*FIXME: 0 / 0*/
+			result.bin = FLOAT32_NAN;
+			return result;
+		}
+		/* FIXME: division by zero */
+		result.parts.exp = 0;
+		result.parts.fraction = 0;
+		return result;
+	}
+	
+	afrac = a.parts.fraction;
+	aexp = a.parts.exp;
+	bfrac = b.parts.fraction;
+	bexp = b.parts.exp;
+	
+	/* denormalized numbers */
+	if (aexp == 0) {
+		if (afrac == 0) {
+			result.parts.exp = 0;
+			result.parts.fraction = 0;
+			return result;
+		}
+		
+		/* normalize it*/
+		afrac <<= 1;
+		/* afrac is nonzero => it must stop */
+		while (!(afrac & FLOAT32_HIDDEN_BIT_MASK)) {
+			afrac <<= 1;
+			aexp--;
+		}
+	}
+	
+	if (bexp == 0) {
+		bfrac <<= 1;
+		/* bfrac is nonzero => it must stop */
+		while (!(bfrac & FLOAT32_HIDDEN_BIT_MASK)) {
+			bfrac <<= 1;
+			bexp--;
+		}
+	}
+	
+	afrac = (afrac | FLOAT32_HIDDEN_BIT_MASK) << (32 - FLOAT32_FRACTION_SIZE - 1);
+	bfrac = (bfrac | FLOAT32_HIDDEN_BIT_MASK) << (32 - FLOAT32_FRACTION_SIZE);
+	
+	if (bfrac <= (afrac << 1)) {
+		afrac >>= 1;
+		aexp++;
+	}
+	
+	cexp = aexp - bexp + FLOAT32_BIAS - 2;
+	
+	cfrac = (afrac << 32) / bfrac;
+	if ((cfrac & 0x3F) == 0) { 
+		cfrac |= (bfrac * cfrac != afrac << 32);
+	}
+	
+	/* pack and round */
+	
+	/* find first nonzero digit and shift result and detect possibly underflow */
+	while ((cexp > 0) && (cfrac) && (!(cfrac & (FLOAT32_HIDDEN_BIT_MASK << 7)))) {
+		cexp--;
+		cfrac <<= 1;
+		/* TODO: fix underflow */
+	}
+	
+	cfrac += (0x1 << 6); /* FIXME: 7 is not sure*/
+	
+	if (cfrac & (FLOAT32_HIDDEN_BIT_MASK << 7)) {
+		++cexp;
+		cfrac >>= 1;
+	}
+	
+	/* check overflow */
+	if (cexp >= FLOAT32_MAX_EXPONENT) {
+		/* FIXME: overflow, return infinity */
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		result.parts.fraction = 0;
+		return result;
+	}
+	
+	if (cexp < 0) {
+		/* FIXME: underflow */
+		result.parts.exp = 0;
+		if ((cexp + FLOAT32_FRACTION_SIZE) < 0) {
+			result.parts.fraction = 0;
+			return result;
+		}
+		cfrac >>= 1;
+		while (cexp < 0) {
+			cexp++;
+			cfrac >>= 1;
+		}
+	} else {
+		result.parts.exp = (uint32_t) cexp;
+	}
+	
+	result.parts.fraction = ((cfrac >> 6) & (~FLOAT32_HIDDEN_BIT_MASK)); 
+	
+	return result;
+}
+
+/** Divide two double-precision floats.
+ *
+ * @param a Nominator.
+ * @param b Denominator.
+ *
+ * @return Result of division.
+ *
+ */
+float64 div_float64(float64 a, float64 b) 
+{
+	float64 result;
+	int64_t aexp, bexp, cexp;
+	uint64_t afrac, bfrac, cfrac; 
+	uint64_t remlo, remhi;
+	uint64_t tmplo, tmphi;
+	
+	result.parts.sign = a.parts.sign ^ b.parts.sign;
+	
+	if (is_float64_nan(a)) {
+		if (is_float64_signan(b)) {
+			// FIXME: SigNaN
+			return b;
+		}
+		
+		if (is_float64_signan(a)) {
+			// FIXME: SigNaN
+		}
+		/* NaN */
+		return a;
+	}
+	
+	if (is_float64_nan(b)) {
+		if (is_float64_signan(b)) {
+			// FIXME: SigNaN
+		}
+		/* NaN */
+		return b;
+	}
+	
+	if (is_float64_infinity(a)) {
+		if (is_float64_infinity(b) || is_float64_zero(b)) {
+			// FIXME: inf / inf
+			result.bin = FLOAT64_NAN;
+			return result;
+		}
+		/* inf / num */
+		result.parts.exp = a.parts.exp;
+		result.parts.fraction = a.parts.fraction;
+		return result;
+	}
+	
+	if (is_float64_infinity(b)) {
+		if (is_float64_zero(a)) {
+			/* FIXME 0 / inf */
+			result.parts.exp = 0;
+			result.parts.fraction = 0;
+			return result;
+		}
+		/* FIXME: num / inf*/
+		result.parts.exp = 0;
+		result.parts.fraction = 0;
+		return result;
+	}
+	
+	if (is_float64_zero(b)) {
+		if (is_float64_zero(a)) {
+			/*FIXME: 0 / 0*/
+			result.bin = FLOAT64_NAN;
+			return result;
+		}
+		/* FIXME: division by zero */
+		result.parts.exp = 0;
+		result.parts.fraction = 0;
+		return result;
+	}
+	
+	afrac = a.parts.fraction;
+	aexp = a.parts.exp;
+	bfrac = b.parts.fraction;
+	bexp = b.parts.exp;
+	
+	/* denormalized numbers */
+	if (aexp == 0) {
+		if (afrac == 0) {
+			result.parts.exp = 0;
+			result.parts.fraction = 0;
+			return result;
+		}
+		
+		/* normalize it*/
+		aexp++;
+		/* afrac is nonzero => it must stop */	
+		while (!(afrac & FLOAT64_HIDDEN_BIT_MASK)) {
+			afrac <<= 1;
+			aexp--;
+		}
+	}
+	
+	if (bexp == 0) {
+		bexp++;
+		/* bfrac is nonzero => it must stop */	
+		while (!(bfrac & FLOAT64_HIDDEN_BIT_MASK)) {
+			bfrac <<= 1;
+			bexp--;
+		}
+	}
+	
+	afrac = (afrac | FLOAT64_HIDDEN_BIT_MASK) << (64 - FLOAT64_FRACTION_SIZE - 2);
+	bfrac = (bfrac | FLOAT64_HIDDEN_BIT_MASK) << (64 - FLOAT64_FRACTION_SIZE - 1);
+	
+	if (bfrac <= (afrac << 1)) {
+		afrac >>= 1;
+		aexp++;
+	}
+	
+	cexp = aexp - bexp + FLOAT64_BIAS - 2; 
+	
+	cfrac = div128est(afrac, 0x0ll, bfrac);
+	
+	if ((cfrac & 0x1FF) <= 2) {
+		mul64(bfrac, cfrac, &tmphi, &tmplo);
+		sub128(afrac, 0x0ll, tmphi, tmplo, &remhi, &remlo);
+		
+		while ((int64_t) remhi < 0) {
+			cfrac--;
+			add128(remhi, remlo, 0x0ll, bfrac, &remhi, &remlo);
+		}
+		cfrac |= (remlo != 0);
+	}
+	
+	/* round and shift */
+	result = finish_float64(cexp, cfrac, result.parts.sign);
+	return result;
+}
+
+/** Divide two quadruple-precision floats.
+ *
+ * @param a Nominator.
+ * @param b Denominator.
+ *
+ * @return Result of division.
+ *
+ */
+float128 div_float128(float128 a, float128 b)
+{
+	float128 result;
+	int64_t aexp, bexp, cexp;
+	uint64_t afrac_hi, afrac_lo, bfrac_hi, bfrac_lo, cfrac_hi, cfrac_lo;
+	uint64_t shift_out;
+	uint64_t rem_hihi, rem_hilo, rem_lohi, rem_lolo;
+	uint64_t tmp_hihi, tmp_hilo, tmp_lohi, tmp_lolo;
+	
+	result.parts.sign = a.parts.sign ^ b.parts.sign;
+	
+	if (is_float128_nan(a)) {
+		if (is_float128_signan(b)) {
+			// FIXME: SigNaN
+			return b;
+		}
+		
+		if (is_float128_signan(a)) {
+			// FIXME: SigNaN
+		}
+		/* NaN */
+		return a;
+	}
+	
+	if (is_float128_nan(b)) {
+		if (is_float128_signan(b)) {
+			// FIXME: SigNaN
+		}
+		/* NaN */
+		return b;
+	}
+	
+	if (is_float128_infinity(a)) {
+		if (is_float128_infinity(b) || is_float128_zero(b)) {
+			// FIXME: inf / inf
+			result.bin.hi = FLOAT128_NAN_HI;
+			result.bin.lo = FLOAT128_NAN_LO;
+			return result;
+		}
+		/* inf / num */
+		result.parts.exp = a.parts.exp;
+		result.parts.frac_hi = a.parts.frac_hi;
+		result.parts.frac_lo = a.parts.frac_lo;
+		return result;
+	}
+	
+	if (is_float128_infinity(b)) {
+		if (is_float128_zero(a)) {
+			// FIXME 0 / inf
+			result.parts.exp = 0;
+			result.parts.frac_hi = 0;
+			result.parts.frac_lo = 0;
+			return result;
+		}
+		// FIXME: num / inf
+		result.parts.exp = 0;
+		result.parts.frac_hi = 0;
+		result.parts.frac_lo = 0;
+		return result;
+	}
+	
+	if (is_float128_zero(b)) {
+		if (is_float128_zero(a)) {
+			// FIXME: 0 / 0
+			result.bin.hi = FLOAT128_NAN_HI;
+			result.bin.lo = FLOAT128_NAN_LO;
+			return result;
+		}
+		// FIXME: division by zero
+		result.parts.exp = 0;
+		result.parts.frac_hi = 0;
+		result.parts.frac_lo = 0;
+		return result;
+	}
+	
+	afrac_hi = a.parts.frac_hi;
+	afrac_lo = a.parts.frac_lo;
+	aexp = a.parts.exp;
+	bfrac_hi = b.parts.frac_hi;
+	bfrac_lo = b.parts.frac_lo;
+	bexp = b.parts.exp;
+	
+	/* denormalized numbers */
+	if (aexp == 0) {
+		if (eq128(afrac_hi, afrac_lo, 0x0ll, 0x0ll)) {
+			result.parts.exp = 0;
+			result.parts.frac_hi = 0;
+			result.parts.frac_lo = 0;
+			return result;
+		}
+		
+		/* normalize it*/
+		aexp++;
+		/* afrac is nonzero => it must stop */
+		and128(afrac_hi, afrac_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &tmp_hihi, &tmp_lolo);
+		while (!lt128(0x0ll, 0x0ll, tmp_hihi, tmp_lolo)) {
+			lshift128(afrac_hi, afrac_lo, 1, &afrac_hi, &afrac_lo);
+			aexp--;
+		}
+	}
+	
+	if (bexp == 0) {
+		bexp++;
+		/* bfrac is nonzero => it must stop */
+		and128(bfrac_hi, bfrac_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &tmp_hihi, &tmp_lolo);
+		while (!lt128(0x0ll, 0x0ll, tmp_hihi, tmp_lolo)) {
+			lshift128(bfrac_hi, bfrac_lo, 1, &bfrac_hi, &bfrac_lo);
+			bexp--;
+		}
+	}
+	
+	or128(afrac_hi, afrac_lo,
+	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &afrac_hi, &afrac_lo);
+	lshift128(afrac_hi, afrac_lo,
+	    (128 - FLOAT128_FRACTION_SIZE - 1), &afrac_hi, &afrac_lo);
+	or128(bfrac_hi, bfrac_lo,
+	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &bfrac_hi, &bfrac_lo);
+	lshift128(bfrac_hi, bfrac_lo,
+	    (128 - FLOAT128_FRACTION_SIZE - 1), &bfrac_hi, &bfrac_lo);
+	
+	if (le128(bfrac_hi, bfrac_lo, afrac_hi, afrac_lo)) {
+		rshift128(afrac_hi, afrac_lo, 1, &afrac_hi, &afrac_lo);
+		aexp++;
+	}
+	
+	cexp = aexp - bexp + FLOAT128_BIAS - 2;
+	
+	cfrac_hi = div128est(afrac_hi, afrac_lo, bfrac_hi);
+	
+	mul128(bfrac_hi, bfrac_lo, 0x0ll, cfrac_hi,
+	    &tmp_lolo /* dummy */, &tmp_hihi, &tmp_hilo, &tmp_lohi);
+	
+	/* sub192(afrac_hi, afrac_lo, 0,
+	 *     tmp_hihi, tmp_hilo, tmp_lohi
+	 *     &rem_hihi, &rem_hilo, &rem_lohi); */
+	sub128(afrac_hi, afrac_lo, tmp_hihi, tmp_hilo, &rem_hihi, &rem_hilo);
+	if (tmp_lohi > 0) {
+		sub128(rem_hihi, rem_hilo, 0x0ll, 0x1ll, &rem_hihi, &rem_hilo);
+	}
+	rem_lohi = -tmp_lohi;
+	
+	while ((int64_t) rem_hihi < 0) {
+		--cfrac_hi;
+		/* add192(rem_hihi, rem_hilo, rem_lohi,
+		 *     0, bfrac_hi, bfrac_lo,
+		 *     &rem_hihi, &rem_hilo, &rem_lohi); */
+		add128(rem_hilo, rem_lohi, bfrac_hi, bfrac_lo, &rem_hilo, &rem_lohi);
+		if (lt128(rem_hilo, rem_lohi, bfrac_hi, bfrac_lo)) {
+			++rem_hihi;
+		}
+	}
+	
+	cfrac_lo = div128est(rem_hilo, rem_lohi, bfrac_lo);
+	
+	if ((cfrac_lo & 0x3FFF) <= 4) {
+		mul128(bfrac_hi, bfrac_lo, 0x0ll, cfrac_lo,
+		    &tmp_hihi /* dummy */, &tmp_hilo, &tmp_lohi, &tmp_lolo);
+		
+		/* sub192(rem_hilo, rem_lohi, 0,
+		 *     tmp_hilo, tmp_lohi, tmp_lolo,
+		 *     &rem_hilo, &rem_lohi, &rem_lolo); */
+		sub128(rem_hilo, rem_lohi, tmp_hilo, tmp_lohi, &rem_hilo, &rem_lohi);
+		if (tmp_lolo > 0) {
+			sub128(rem_hilo, rem_lohi, 0x0ll, 0x1ll, &rem_hilo, &rem_lohi);
+		}
+		rem_lolo = -tmp_lolo;
+		
+		while ((int64_t) rem_hilo < 0) {
+			--cfrac_lo;
+			/* add192(rem_hilo, rem_lohi, rem_lolo,
+			 *     0, bfrac_hi, bfrac_lo,
+			 *     &rem_hilo, &rem_lohi, &rem_lolo); */
+			add128(rem_lohi, rem_lolo, bfrac_hi, bfrac_lo, &rem_lohi, &rem_lolo);
+			if (lt128(rem_lohi, rem_lolo, bfrac_hi, bfrac_lo)) {
+				++rem_hilo;
+			}
+		}
+		
+		cfrac_lo |= ((rem_hilo | rem_lohi | rem_lolo) != 0 );
+	}
+	
+	shift_out = cfrac_lo << (64 - (128 - FLOAT128_FRACTION_SIZE - 1));
+	rshift128(cfrac_hi, cfrac_lo, (128 - FLOAT128_FRACTION_SIZE - 1),
+	    &cfrac_hi, &cfrac_lo);
+	
+	result = finish_float128(cexp, cfrac_hi, cfrac_lo, result.parts.sign, shift_out);
+	return result;
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/div.h
===================================================================
--- uspace/lib/softfloat/div.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/div.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Division functions.
+ */
+
+#ifndef __DIV_H__
+#define __DIV_H__
+
+extern float32 div_float32(float32, float32);
+extern float64 div_float64(float64, float64);
+extern float96 div_float96(float96, float96);
+extern float128 div_float128(float128, float128);
+
+#endif
+
+/** @}
+ */
Index: pace/lib/softfloat/generic/add.c
===================================================================
--- uspace/lib/softfloat/generic/add.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,416 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Addition functions.
- */
-
-#include <sftypes.h>
-#include <add.h>
-#include <comparison.h>
-#include <common.h>
-
-/** Add two single-precision floats with the same sign.
- *
- * @param a First input operand.
- * @param b Second input operand.
- * @return Result of addition.
- */
-float32 add_float32(float32 a, float32 b)
-{
-	int expdiff;
-	uint32_t exp1, exp2, frac1, frac2;
-	
-	expdiff = a.parts.exp - b.parts.exp;
-	if (expdiff < 0) {
-		if (is_float32_nan(b)) {
-			/* TODO: fix SigNaN */
-			if (is_float32_signan(b)) {
-			}
-
-			return b;
-		}
-		
-		if (b.parts.exp == FLOAT32_MAX_EXPONENT) { 
-			return b;
-		}
-		
-		frac1 = b.parts.fraction;
-		exp1 = b.parts.exp;
-		frac2 = a.parts.fraction;
-		exp2 = a.parts.exp;
-		expdiff *= -1;
-	} else {
-		if ((is_float32_nan(a)) || (is_float32_nan(b))) {
-			/* TODO: fix SigNaN */
-			if (is_float32_signan(a) || is_float32_signan(b)) {
-			}
-			return (is_float32_nan(a) ? a : b);
-		}
-		
-		if (a.parts.exp == FLOAT32_MAX_EXPONENT) { 
-			return a;
-		}
-		
-		frac1 = a.parts.fraction;
-		exp1 = a.parts.exp;
-		frac2 = b.parts.fraction;
-		exp2 = b.parts.exp;
-	}
-	
-	if (exp1 == 0) {
-		/* both are denormalized */
-		frac1 += frac2;
-		if (frac1 & FLOAT32_HIDDEN_BIT_MASK ) {
-			/* result is not denormalized */
-			a.parts.exp = 1;
-		}
-		a.parts.fraction = frac1;
-		return a;
-	}
-	
-	frac1 |= FLOAT32_HIDDEN_BIT_MASK; /* add hidden bit */
-
-	if (exp2 == 0) {
-		/* second operand is denormalized */
-		--expdiff;
-	} else {
-		/* add hidden bit to second operand */
-		frac2 |= FLOAT32_HIDDEN_BIT_MASK; 
-	}
-	
-	/* create some space for rounding */
-	frac1 <<= 6;
-	frac2 <<= 6;
-	
-	if (expdiff < (FLOAT32_FRACTION_SIZE + 2) ) {
-		frac2 >>= expdiff;
-		frac1 += frac2;
-	} else {
-		a.parts.exp = exp1;
-		a.parts.fraction = (frac1 >> 6) & (~(FLOAT32_HIDDEN_BIT_MASK));
-		return a;
-	}
-	
-	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7) ) {
-		++exp1;
-		frac1 >>= 1;
-	}
-	
-	/* rounding - if first bit after fraction is set then round up */
-	frac1 += (0x1 << 5);
-	
-	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7)) { 
-		/* rounding overflow */
-		++exp1;
-		frac1 >>= 1;
-	}
-	
-	if ((exp1 == FLOAT32_MAX_EXPONENT ) || (exp2 > exp1)) {
-		/* overflow - set infinity as result */
-		a.parts.exp = FLOAT32_MAX_EXPONENT;
-		a.parts.fraction = 0;
-		return a;
-	}
-	
-	a.parts.exp = exp1;
-	
-	/* Clear hidden bit and shift */
-	a.parts.fraction = ((frac1 >> 6) & (~FLOAT32_HIDDEN_BIT_MASK)); 
-	return a;
-}
-
-/** Add two double-precision floats with the same sign.
- *
- * @param a First input operand.
- * @param b Second input operand.
- * @return Result of addition.
- */
-float64 add_float64(float64 a, float64 b)
-{
-	int expdiff;
-	uint32_t exp1, exp2;
-	uint64_t frac1, frac2;
-	
-	expdiff = ((int) a.parts.exp) - b.parts.exp;
-	if (expdiff < 0) {
-		if (is_float64_nan(b)) {
-			/* TODO: fix SigNaN */
-			if (is_float64_signan(b)) {
-			}
-
-			return b;
-		}
-		
-		/* b is infinity and a not */
-		if (b.parts.exp == FLOAT64_MAX_EXPONENT) {
-			return b;
-		}
-		
-		frac1 = b.parts.fraction;
-		exp1 = b.parts.exp;
-		frac2 = a.parts.fraction;
-		exp2 = a.parts.exp;
-		expdiff *= -1;
-	} else {
-		if (is_float64_nan(a)) {
-			/* TODO: fix SigNaN */
-			if (is_float64_signan(a) || is_float64_signan(b)) {
-			}
-			return a;
-		}
-		
-		/* a is infinity and b not */
-		if (a.parts.exp == FLOAT64_MAX_EXPONENT) { 
-			return a;
-		}
-		
-		frac1 = a.parts.fraction;
-		exp1 = a.parts.exp;
-		frac2 = b.parts.fraction;
-		exp2 = b.parts.exp;
-	}
-	
-	if (exp1 == 0) {
-		/* both are denormalized */
-		frac1 += frac2;
-		if (frac1 & FLOAT64_HIDDEN_BIT_MASK) { 
-			/* result is not denormalized */
-			a.parts.exp = 1;
-		}
-		a.parts.fraction = frac1;
-		return a;
-	}
-	
-	/* add hidden bit - frac1 is sure not denormalized */
-	frac1 |= FLOAT64_HIDDEN_BIT_MASK;
-
-	/* second operand ... */
-	if (exp2 == 0) {
-		/* ... is denormalized */
-		--expdiff;	
-	} else {
-		/* is not denormalized */
-		frac2 |= FLOAT64_HIDDEN_BIT_MASK;
-	}
-	
-	/* create some space for rounding */
-	frac1 <<= 6;
-	frac2 <<= 6;
-	
-	if (expdiff < (FLOAT64_FRACTION_SIZE + 2)) {
-		frac2 >>= expdiff;
-		frac1 += frac2;
-	} else {
-		a.parts.exp = exp1;
-		a.parts.fraction = (frac1 >> 6) & (~(FLOAT64_HIDDEN_BIT_MASK));
-		return a;
-	}
-	
-	if (frac1 & (FLOAT64_HIDDEN_BIT_MASK << 7)) {
-		++exp1;
-		frac1 >>= 1;
-	}
-	
-	/* rounding - if first bit after fraction is set then round up */
-	frac1 += (0x1 << 5); 
-	
-	if (frac1 & (FLOAT64_HIDDEN_BIT_MASK << 7)) { 
-		/* rounding overflow */
-		++exp1;
-		frac1 >>= 1;
-	}
-	
-	if ((exp1 == FLOAT64_MAX_EXPONENT ) || (exp2 > exp1)) {
-		/* overflow - set infinity as result */
-		a.parts.exp = FLOAT64_MAX_EXPONENT;
-		a.parts.fraction = 0;
-		return a;
-	}
-	
-	a.parts.exp = exp1;
-	/* Clear hidden bit and shift */
-	a.parts.fraction = ((frac1 >> 6 ) & (~FLOAT64_HIDDEN_BIT_MASK));
-	return a;
-}
-
-/** Add two quadruple-precision floats with the same sign.
- *
- * @param a First input operand.
- * @param b Second input operand.
- * @return Result of addition.
- */
-float128 add_float128(float128 a, float128 b)
-{
-	int expdiff;
-	uint32_t exp1, exp2;
-	uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
-
-	expdiff = ((int) a.parts.exp) - b.parts.exp;
-	if (expdiff < 0) {
-		if (is_float128_nan(b)) {
-			/* TODO: fix SigNaN */
-			if (is_float128_signan(b)) {
-			}
-
-			return b;
-		}
-
-		/* b is infinity and a not */
-		if (b.parts.exp == FLOAT128_MAX_EXPONENT) {
-			return b;
-		}
-
-		frac1_hi = b.parts.frac_hi;
-		frac1_lo = b.parts.frac_lo;
-		exp1 = b.parts.exp;
-		frac2_hi = a.parts.frac_hi;
-		frac2_lo = a.parts.frac_lo;
-		exp2 = a.parts.exp;
-		expdiff *= -1;
-	} else {
-		if (is_float128_nan(a)) {
-			/* TODO: fix SigNaN */
-			if (is_float128_signan(a) || is_float128_signan(b)) {
-			}
-			return a;
-		}
-
-		/* a is infinity and b not */
-		if (a.parts.exp == FLOAT128_MAX_EXPONENT) {
-			return a;
-		}
-
-		frac1_hi = a.parts.frac_hi;
-		frac1_lo = a.parts.frac_lo;
-		exp1 = a.parts.exp;
-		frac2_hi = b.parts.frac_hi;
-		frac2_lo = b.parts.frac_lo;
-		exp2 = b.parts.exp;
-	}
-
-	if (exp1 == 0) {
-		/* both are denormalized */
-		add128(frac1_hi, frac1_lo, frac2_hi, frac2_lo, &frac1_hi, &frac1_lo);
-
-		and128(frac1_hi, frac1_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &tmp_hi, &tmp_lo);
-		if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-			/* result is not denormalized */
-			a.parts.exp = 1;
-		}
-
-		a.parts.frac_hi = frac1_hi;
-		a.parts.frac_lo = frac1_lo;
-		return a;
-	}
-
-	/* add hidden bit - frac1 is sure not denormalized */
-	or128(frac1_hi, frac1_lo,
-	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &frac1_hi, &frac1_lo);
-
-	/* second operand ... */
-	if (exp2 == 0) {
-		/* ... is denormalized */
-		--expdiff;
-	} else {
-		/* is not denormalized */
-		or128(frac2_hi, frac2_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &frac2_hi, &frac2_lo);
-	}
-
-	/* create some space for rounding */
-	lshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
-	lshift128(frac2_hi, frac2_lo, 6, &frac2_hi, &frac2_lo);
-
-	if (expdiff < (FLOAT128_FRACTION_SIZE + 2)) {
-		rshift128(frac2_hi, frac2_lo, expdiff, &frac2_hi, &frac2_lo);
-		add128(frac1_hi, frac1_lo, frac2_hi, frac2_lo, &frac1_hi, &frac1_lo);
-	} else {
-		a.parts.exp = exp1;
-
-		rshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
-		not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &tmp_hi, &tmp_lo);
-		and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-
-		a.parts.frac_hi = tmp_hi;
-		a.parts.frac_lo = tmp_lo;
-		return a;
-	}
-
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 7,
-	    &tmp_hi, &tmp_lo);
-	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-		++exp1;
-		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
-	}
-
-	/* rounding - if first bit after fraction is set then round up */
-	add128(frac1_hi, frac1_lo, 0x0ll, 0x1ll << 5, &frac1_hi, &frac1_lo);
-
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 7,
-	   &tmp_hi, &tmp_lo);
-	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-		/* rounding overflow */
-		++exp1;
-		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
-	}
-
-	if ((exp1 == FLOAT128_MAX_EXPONENT ) || (exp2 > exp1)) {
-		/* overflow - set infinity as result */
-		a.parts.exp = FLOAT64_MAX_EXPONENT;
-		a.parts.frac_hi = 0;
-		a.parts.frac_lo = 0;
-		return a;
-	}
-
-	a.parts.exp = exp1;
-	
-	/* Clear hidden bit and shift */
-	rshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
-	not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &tmp_hi, &tmp_lo);
-	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-
-	a.parts.frac_hi = tmp_hi;
-	a.parts.frac_lo = tmp_lo;
-
-	return a;
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/common.c
===================================================================
--- uspace/lib/softfloat/generic/common.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,690 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Common helper operations.
- */
-
-#include <sftypes.h>
-#include <common.h>
-
-/* Table for fast leading zeroes counting. */
-char zeroTable[256] = {
-	8, 7, 7, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, \
-	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, \
-	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
-	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
-	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
-	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
-	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
-	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/** 
- * Take fraction shifted by 10 bits to the left, round it, normalize it
- * and detect exceptions
- * 
- * @param cexp Exponent with bias.
- * @param cfrac Fraction shifted 10 bits to the left with added hidden bit.
- * @param sign Resulting sign.
- * @return Finished double-precision float.
- */
-float64 finish_float64(int32_t cexp, uint64_t cfrac, char sign)
-{
-	float64 result;
-
-	result.parts.sign = sign;
-
-	/* find first nonzero digit and shift result and detect possibly underflow */
-	while ((cexp > 0) && (cfrac) &&
-	    (!(cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1))))) {
-		cexp--; 
-		cfrac <<= 1;
-		/* TODO: fix underflow */
-	}
-	
-	if ((cexp < 0) || (cexp == 0 &&
-	    (!(cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1)))))) {
-		/* FIXME: underflow */
-		result.parts.exp = 0;
-		if ((cexp + FLOAT64_FRACTION_SIZE + 1) < 0) { /* +1 is place for rounding */
-			result.parts.fraction = 0;
-			return result;
-		}
-		
-		while (cexp < 0) {
-			cexp++;
-			cfrac >>= 1;
-		}
-	
-		cfrac += (0x1 << (64 - FLOAT64_FRACTION_SIZE - 3)); 
-		
-		if (!(cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1)))) {
-			result.parts.fraction =
-			    ((cfrac >> (64 - FLOAT64_FRACTION_SIZE - 2)) & (~FLOAT64_HIDDEN_BIT_MASK));
-			return result;
-		}	
-	} else {
-		cfrac += (0x1 << (64 - FLOAT64_FRACTION_SIZE - 3)); 
-	}
-	
-	++cexp;
-
-	if (cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1))) {
-		++cexp;
-		cfrac >>= 1;
-	}	
-
-	/* check overflow */
-	if (cexp >= FLOAT64_MAX_EXPONENT) {
-		/* FIXME: overflow, return infinity */
-		result.parts.exp = FLOAT64_MAX_EXPONENT;
-		result.parts.fraction = 0;
-		return result;
-	}
-
-	result.parts.exp = (uint32_t) cexp;
-	
-	result.parts.fraction = 
-	    ((cfrac >> (64 - FLOAT64_FRACTION_SIZE - 2)) & (~FLOAT64_HIDDEN_BIT_MASK));
-	
-	return result;	
-}
-
-/**
- * Take fraction, round it, normalize it and detect exceptions
- * 
- * @param cexp Exponent with bias.
- * @param cfrac_hi High part of the fraction shifted 14 bits to the left
- *     with added hidden bit.
- * @param cfrac_lo Low part of the fraction shifted 14 bits to the left
- *     with added hidden bit.
- * @param sign Resulting sign.
- * @param shift_out Bits right-shifted out from fraction by the caller.
- * @return Finished quadruple-precision float.
- */
-float128 finish_float128(int32_t cexp, uint64_t cfrac_hi, uint64_t cfrac_lo, 
-    char sign, uint64_t shift_out)
-{
-	float128 result;
-	uint64_t tmp_hi, tmp_lo;
-
-	result.parts.sign = sign;
-
-	/* find first nonzero digit and shift result and detect possibly underflow */
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    1, &tmp_hi, &tmp_lo);
-	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	while ((cexp > 0) && (lt128(0x0ll, 0x0ll, cfrac_hi, cfrac_lo)) &&
-	    (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo))) {
-		cexp--;
-		lshift128(cfrac_hi, cfrac_lo, 1, &cfrac_hi, &cfrac_lo);
-		/* TODO: fix underflow */
-
-		lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    1, &tmp_hi, &tmp_lo);
-		and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	}
-
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    1, &tmp_hi, &tmp_lo);
-	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	if ((cexp < 0) || (cexp == 0 &&
-	    (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)))) {
-		/* FIXME: underflow */
-		result.parts.exp = 0;
-		if ((cexp + FLOAT128_FRACTION_SIZE + 1) < 0) { /* +1 is place for rounding */
-			result.parts.frac_hi = 0x0ll;
-			result.parts.frac_lo = 0x0ll;
-			return result;
-		}
-
-		while (cexp < 0) {
-			cexp++;
-			rshift128(cfrac_hi, cfrac_lo, 1, &cfrac_hi, &cfrac_lo);
-		}
-
-		if (shift_out & (0x1ull < 64)) {
-			add128(cfrac_hi, cfrac_lo, 0x0ll, 0x1ll, &cfrac_hi, &cfrac_lo);
-		}
-
-		lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    1, &tmp_hi, &tmp_lo);
-		and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-		if (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-			not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-			    &tmp_hi, &tmp_lo);
-			and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-			result.parts.frac_hi = tmp_hi;
-			result.parts.frac_lo = tmp_lo;
-			return result;
-		}
-	} else {
-		if (shift_out & (0x1ull < 64)) {
-			add128(cfrac_hi, cfrac_lo, 0x0ll, 0x1ll, &cfrac_hi, &cfrac_lo);
-		}
-	}
-
-	++cexp;
-
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    1, &tmp_hi, &tmp_lo);
-	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-		++cexp;
-		rshift128(cfrac_hi, cfrac_lo, 1, &cfrac_hi, &cfrac_lo);
-	}
-
-	/* check overflow */
-	if (cexp >= FLOAT128_MAX_EXPONENT) {
-		/* FIXME: overflow, return infinity */
-		result.parts.exp = FLOAT128_MAX_EXPONENT;
-		result.parts.frac_hi = 0x0ll;
-		result.parts.frac_lo = 0x0ll;
-		return result;
-	}
-
-	result.parts.exp = (uint32_t) cexp;
-
-	not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &tmp_hi, &tmp_lo);
-	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	result.parts.frac_hi = tmp_hi;
-	result.parts.frac_lo = tmp_lo;
-
-	return result;	
-}
-
-/**
- * Counts leading zeroes in byte.
- *
- * @param i Byte for which to count leading zeroes.
- * @return Number of detected leading zeroes.
- */
-int count_zeroes8(uint8_t i)
-{
-	return zeroTable[i];
-}
-
-/** 
- * Counts leading zeroes in 32bit unsigned integer.
- *
- * @param i Integer for which to count leading zeroes.
- * @return Number of detected leading zeroes.
- */
-int count_zeroes32(uint32_t i)
-{
-	int j;
-	for (j = 0; j < 32; j += 8) {
-		if (i & (0xFF << (24 - j))) {
-			return (j + count_zeroes8(i >> (24 - j)));
-		}
-	}
-
-	return 32;
-}
-
-/**
- * Counts leading zeroes in 64bit unsigned integer.
- *
- * @param i Integer for which to count leading zeroes.
- * @return Number of detected leading zeroes.
- */
-int count_zeroes64(uint64_t i)
-{
-	int j;
-	for (j = 0; j < 64; j += 8) {
-		if (i & (0xFFll << (56 - j))) {
-			return (j + count_zeroes8(i >> (56 - j)));
-		}
-	}
-
-	return 64;
-}
-
-/**
- * Round and normalize number expressed by exponent and fraction with
- * first bit (equal to hidden bit) at 30th bit.
- *
- * @param exp Exponent part.
- * @param fraction Fraction with hidden bit shifted to 30th bit.
- */
-void round_float32(int32_t *exp, uint32_t *fraction)
-{
-	/* rounding - if first bit after fraction is set then round up */
-	(*fraction) += (0x1 << (32 - FLOAT32_FRACTION_SIZE - 3));
-	
-	if ((*fraction) & 
-	    (FLOAT32_HIDDEN_BIT_MASK << (32 - FLOAT32_FRACTION_SIZE - 1))) {
-		/* rounding overflow */
-		++(*exp);
-		(*fraction) >>= 1;
-	}
-	
-	if (((*exp) >= FLOAT32_MAX_EXPONENT) || ((*exp) < 0)) {
-		/* overflow - set infinity as result */
-		(*exp) = FLOAT32_MAX_EXPONENT;
-		(*fraction) = 0;
-	}
-}
-
-/**
- * Round and normalize number expressed by exponent and fraction with
- * first bit (equal to hidden bit) at 62nd bit.
- *
- * @param exp Exponent part.
- * @param fraction Fraction with hidden bit shifted to 62nd bit.
- */
-void round_float64(int32_t *exp, uint64_t *fraction)
-{
-	/* rounding - if first bit after fraction is set then round up */
-	(*fraction) += (0x1 << (64 - FLOAT64_FRACTION_SIZE - 3));
-	
-	if ((*fraction) & 
-	    (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 3))) {
-		/* rounding overflow */
-		++(*exp);
-		(*fraction) >>= 1;
-	}
-	
-	if (((*exp) >= FLOAT64_MAX_EXPONENT) || ((*exp) < 0)) {
-		/* overflow - set infinity as result */
-		(*exp) = FLOAT64_MAX_EXPONENT;
-		(*fraction) = 0;
-	}
-}
-
-/**
- * Round and normalize number expressed by exponent and fraction with
- * first bit (equal to hidden bit) at 126th bit.
- *
- * @param exp Exponent part.
- * @param frac_hi High part of fraction part with hidden bit shifted to 126th bit.
- * @param frac_lo Low part of fraction part with hidden bit shifted to 126th bit.
- */
-void round_float128(int32_t *exp, uint64_t *frac_hi, uint64_t *frac_lo)
-{
-	uint64_t tmp_hi, tmp_lo;
-
-	/* rounding - if first bit after fraction is set then round up */
-	lshift128(0x0ll, 0x1ll, (128 - FLOAT128_FRACTION_SIZE - 3), &tmp_hi, &tmp_lo);
-	add128(*frac_hi, *frac_lo, tmp_hi, tmp_lo, frac_hi, frac_lo);
-
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    (128 - FLOAT128_FRACTION_SIZE - 3), &tmp_hi, &tmp_lo);
-	and128(*frac_hi, *frac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-		/* rounding overflow */
-		++(*exp);
-		rshift128(*frac_hi, *frac_lo, 1, frac_hi, frac_lo);
-	}
-
-	if (((*exp) >= FLOAT128_MAX_EXPONENT) || ((*exp) < 0)) {
-		/* overflow - set infinity as result */
-		(*exp) = FLOAT128_MAX_EXPONENT;
-		(*frac_hi) = 0;
-		(*frac_lo) = 0;
-	}
-}
-
-/**
- * Logical shift left on the 128-bit operand.
- *
- * @param a_hi High part of the input operand.
- * @param a_lo Low part of the input operand.
- * @param shift Number of bits by witch to shift.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void lshift128(
-    uint64_t a_hi, uint64_t a_lo, int shift,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	if (shift <= 0) {
-		/* do nothing */
-	} else if (shift >= 128) {
-		a_hi = 0;
-		a_lo = 0;
-	} else if (shift >= 64) {
-		a_hi = a_lo << (shift - 64);
-		a_lo = 0;
-	} else {
-		a_hi <<= shift;
-		a_hi |= a_lo >> (64 - shift);
-		a_lo <<= shift;
-	}
-
-	*r_hi = a_hi;
-	*r_lo = a_lo;
-}
-
-/**
- * Logical shift right on the 128-bit operand.
- *
- * @param a_hi High part of the input operand.
- * @param a_lo Low part of the input operand.
- * @param shift Number of bits by witch to shift.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void rshift128(
-    uint64_t a_hi, uint64_t a_lo, int shift,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	if (shift <= 0) {
-		/* do nothing */
-	} else 	if (shift >= 128) {
-		a_hi = 0;
-		a_lo = 0;
-	} else if (shift >= 64) {
-		a_lo = a_hi >> (shift - 64);
-		a_hi = 0;
-	} else {
-		a_lo >>= shift;
-		a_lo |= a_hi << (64 - shift);
-		a_hi >>= shift;
-	}
-
-	*r_hi = a_hi;
-	*r_lo = a_lo;
-}
-
-/**
- * Bitwise AND on 128-bit operands.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void and128(
-    uint64_t a_hi, uint64_t a_lo,
-    uint64_t b_hi, uint64_t b_lo,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	*r_hi = a_hi & b_hi;
-	*r_lo = a_lo & b_lo;
-}
-
-/**
- * Bitwise inclusive OR on 128-bit operands.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void or128(
-    uint64_t a_hi, uint64_t a_lo,
-    uint64_t b_hi, uint64_t b_lo,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	*r_hi = a_hi | b_hi;
-	*r_lo = a_lo | b_lo;
-}
-
-/**
- * Bitwise exclusive OR on 128-bit operands.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void xor128(
-    uint64_t a_hi, uint64_t a_lo,
-    uint64_t b_hi, uint64_t b_lo,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	*r_hi = a_hi ^ b_hi;
-	*r_lo = a_lo ^ b_lo;
-}
-
-/**
- * Bitwise NOT on the 128-bit operand.
- *
- * @param a_hi High part of the input operand.
- * @param a_lo Low part of the input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void not128(
-    uint64_t a_hi, uint64_t a_lo,
-	uint64_t *r_hi, uint64_t *r_lo)
-{
-	*r_hi = ~a_hi;
-	*r_lo = ~a_lo;
-}
-
-/**
- * Equality comparison of 128-bit operands.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @return 1 if operands are equal, 0 otherwise.
- */
-int eq128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo)
-{
-	return (a_hi == b_hi) && (a_lo == b_lo);
-}
-
-/**
- * Lower-or-equal comparison of 128-bit operands.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @return 1 if a is lower or equal to b, 0 otherwise.
- */
-int le128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo)
-{
-	return (a_hi < b_hi) || ((a_hi == b_hi) && (a_lo <= b_lo));
-}
-
-/**
- * Lower-than comparison of 128-bit operands.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @return 1 if a is lower than b, 0 otherwise.
- */
-int lt128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo)
-{
-	return (a_hi < b_hi) || ((a_hi == b_hi) && (a_lo < b_lo));
-}
-
-/**
- * Addition of two 128-bit unsigned integers.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void add128(uint64_t a_hi, uint64_t a_lo,
-    uint64_t b_hi, uint64_t b_lo,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	uint64_t low = a_lo + b_lo;
-	*r_lo = low;
-	/* detect overflow to add a carry */
-	*r_hi = a_hi + b_hi + (low < a_lo);
-}
-
-/**
- * Substraction of two 128-bit unsigned integers.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void sub128(uint64_t a_hi, uint64_t a_lo,
-    uint64_t b_hi, uint64_t b_lo,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	*r_lo = a_lo - b_lo;
-	/* detect underflow to substract a carry */
-	*r_hi = a_hi - b_hi - (a_lo < b_lo);
-}
-
-/**
- * Multiplication of two 64-bit unsigned integers.
- * 
- * @param a First input operand.
- * @param b Second input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void mul64(uint64_t a, uint64_t b, uint64_t *r_hi, uint64_t *r_lo)
-{
-	uint64_t low, high, middle1, middle2;
-	uint32_t alow, blow;
-
-	alow = a & 0xFFFFFFFF;
-	blow = b & 0xFFFFFFFF;
-
-	a >>= 32;
-	b >>= 32;
-
-	low = ((uint64_t) alow) * blow;
-	middle1 = a * blow;
-	middle2 = alow * b;
-	high = a * b;
-
-	middle1 += middle2;
-	high += (((uint64_t) (middle1 < middle2)) << 32) + (middle1 >> 32);
-	middle1 <<= 32;
-	low += middle1;
-	high += (low < middle1);
-	*r_lo = low;
-	*r_hi = high;
-}
-
-/**
- * Multiplication of two 128-bit unsigned integers.
- * 
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @param r_hihi Address to store first (highest) quarter of the result.
- * @param r_hilo Address to store second quarter of the result.
- * @param r_lohi Address to store third quarter of the result.
- * @param r_lolo Address to store fourth (lowest) quarter of the result.
- */
-void mul128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo,
-    uint64_t *r_hihi, uint64_t *r_hilo, uint64_t *r_lohi, uint64_t *r_lolo)
-{
-	uint64_t hihi, hilo, lohi, lolo;
-	uint64_t tmp1, tmp2;
-
-	mul64(a_lo, b_lo, &lohi, &lolo);
-	mul64(a_lo, b_hi, &hilo, &tmp2);
-	add128(hilo, tmp2, 0x0ll, lohi, &hilo, &lohi);
-	mul64(a_hi, b_hi, &hihi, &tmp1);
-	add128(hihi, tmp1, 0x0ll, hilo, &hihi, &hilo);
-	mul64(a_hi, b_lo, &tmp1, &tmp2);
-	add128(tmp1, tmp2, 0x0ll, lohi, &tmp1, &lohi);
-	add128(hihi, hilo, 0x0ll, tmp1, &hihi, &hilo);
-
-	*r_hihi = hihi;
-	*r_hilo = hilo;
-	*r_lohi = lohi;
-	*r_lolo = lolo;
-}
-
-/**
- * Estimate the quotient of 128-bit unsigned divident and 64-bit unsigned
- * divisor.
- * 
- * @param a_hi High part of the divident.
- * @param a_lo Low part of the divident.
- * @param b Divisor.
- * @return Quotient approximation.
- */
-uint64_t div128est(uint64_t a_hi, uint64_t a_lo, uint64_t b)
-{
-	uint64_t b_hi, b_lo;
-	uint64_t rem_hi, rem_lo;
-	uint64_t tmp_hi, tmp_lo;
-	uint64_t result;
-
-	if (b <= a_hi) {
-		return 0xFFFFFFFFFFFFFFFFull;
-	}
-
-	b_hi = b >> 32;
-	result = ((b_hi << 32) <= a_hi) ? (0xFFFFFFFFull << 32) : (a_hi / b_hi) << 32;
-	mul64(b, result, &tmp_hi, &tmp_lo);
-	sub128(a_hi, a_lo, tmp_hi, tmp_lo, &rem_hi, &rem_lo);
-	
-	while ((int64_t) rem_hi < 0) {
-		result -= 0x1ll << 32;
-		b_lo = b << 32;
-		add128(rem_hi, rem_lo, b_hi, b_lo, &rem_hi, &rem_lo);
-	}
-
-	rem_hi = (rem_hi << 32) | (rem_lo >> 32);
-	if ((b_hi << 32) <= rem_hi) {
-		result |= 0xFFFFFFFF;
-	} else {
-		result |= rem_hi / b_hi;
-	}
-
-	return result;
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/comparison.c
===================================================================
--- uspace/lib/softfloat/generic/comparison.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,442 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Comparison functions.
- */
-
-#include <sftypes.h>
-#include <comparison.h>
-#include <common.h>
-
-/**
- * Determines whether the given float represents NaN (either signalling NaN or
- * quiet NaN).
- *
- * @param f Single-precision float.
- * @return 1 if float is NaN, 0 otherwise.
- */
-int is_float32_nan(float32 f)
-{
-	/* NaN : exp = 0xff and nonzero fraction */
-	return ((f.parts.exp == 0xFF) && (f.parts.fraction));
-}
-
-/**
- * Determines whether the given float represents NaN (either signalling NaN or
- * quiet NaN).
- *
- * @param d Double-precision float.
- * @return 1 if float is NaN, 0 otherwise.
- */
-int is_float64_nan(float64 d)
-{
-	/* NaN : exp = 0x7ff and nonzero fraction */
-	return ((d.parts.exp == 0x7FF) && (d.parts.fraction));
-}
-
-/**
- * Determines whether the given float represents NaN (either signalling NaN or
- * quiet NaN).
- *
- * @param ld Quadruple-precision float.
- * @return 1 if float is NaN, 0 otherwise.
- */
-int is_float128_nan(float128 ld)
-{
-	/* NaN : exp = 0x7fff and nonzero fraction */
-	return ((ld.parts.exp == 0x7FF) &&
-	    !eq128(ld.parts.frac_hi, ld.parts.frac_lo, 0x0ll, 0x0ll));
-}
-
-/**
- * Determines whether the given float represents signalling NaN.
- *
- * @param f Single-precision float.
- * @return 1 if float is signalling NaN, 0 otherwise.
- */
-int is_float32_signan(float32 f)
-{
-	/* SigNaN : exp = 0xff and fraction = 0xxxxx..x (binary),
-	 * where at least one x is nonzero */
-	return ((f.parts.exp == 0xFF) &&
-	    (f.parts.fraction < 0x400000) && (f.parts.fraction));
-}
-
-/**
- * Determines whether the given float represents signalling NaN.
- *
- * @param d Double-precision float.
- * @return 1 if float is signalling NaN, 0 otherwise.
- */
-int is_float64_signan(float64 d)
-{
-	/* SigNaN : exp = 0x7ff and fraction = 0xxxxx..x (binary),
-	 * where at least one x is nonzero */
-	return ((d.parts.exp == 0x7FF) &&
-	    (d.parts.fraction) && (d.parts.fraction < 0x8000000000000ll));
-}
-
-/**
- * Determines whether the given float represents signalling NaN.
- *
- * @param ld Quadruple-precision float.
- * @return 1 if float is signalling NaN, 0 otherwise.
- */
-int is_float128_signan(float128 ld)
-{
-	/* SigNaN : exp = 0x7fff and fraction = 0xxxxx..x (binary),
-	 * where at least one x is nonzero */
-	return ((ld.parts.exp == 0x7FFF) &&
-	    (ld.parts.frac_hi || ld.parts.frac_lo) &&
-	    lt128(ld.parts.frac_hi, ld.parts.frac_lo, 0x800000000000ll, 0x0ll));
-
-}
-
-/**
- * Determines whether the given float represents positive or negative infinity.
- *
- * @param f Single-precision float.
- * @return 1 if float is infinite, 0 otherwise.
- */
-int is_float32_infinity(float32 f)
-{
-	/* NaN : exp = 0x7ff and zero fraction */
-	return ((f.parts.exp == 0xFF) && (f.parts.fraction == 0x0));
-}
-
-/**
- * Determines whether the given float represents positive or negative infinity.
- *
- * @param d Double-precision float.
- * @return 1 if float is infinite, 0 otherwise.
- */
-int is_float64_infinity(float64 d)
-{
-	/* NaN : exp = 0x7ff and zero fraction */
-	return ((d.parts.exp == 0x7FF) && (d.parts.fraction == 0x0));
-}
-
-/**
- * Determines whether the given float represents positive or negative infinity.
- *
- * @param ld Quadruple-precision float.
- * @return 1 if float is infinite, 0 otherwise.
- */
-int is_float128_infinity(float128 ld)
-{
-	/* NaN : exp = 0x7fff and zero fraction */
-	return ((ld.parts.exp == 0x7FFF) &&
-	    eq128(ld.parts.frac_hi, ld.parts.frac_lo, 0x0ll, 0x0ll));
-}
-
-/**
- * Determines whether the given float represents positive or negative zero.
- *
- * @param f Single-precision float.
- * @return 1 if float is zero, 0 otherwise.
- */
-int is_float32_zero(float32 f)
-{
-	return (((f.bin) & 0x7FFFFFFF) == 0);
-}
-
-/**
- * Determines whether the given float represents positive or negative zero.
- *
- * @param d Double-precision float.
- * @return 1 if float is zero, 0 otherwise.
- */
-int is_float64_zero(float64 d)
-{
-	return (((d.bin) & 0x7FFFFFFFFFFFFFFFll) == 0);
-}
-
-/**
- * Determines whether the given float represents positive or negative zero.
- *
- * @param ld Quadruple-precision float.
- * @return 1 if float is zero, 0 otherwise.
- */
-int is_float128_zero(float128 ld)
-{
-	uint64_t tmp_hi;
-	uint64_t tmp_lo;
-	
-	and128(ld.bin.hi, ld.bin.lo,
-	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
-	
-	return eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll);
-}
-
-/**
- * Determine whether two floats are equal. NaNs are not recognized.
- *
- * @a First single-precision operand.
- * @b Second single-precision operand.
- * @return 1 if both floats are equal, 0 otherwise.
- */
-int is_float32_eq(float32 a, float32 b)
-{
-	/* a equals to b or both are zeros (with any sign) */
-	return ((a.bin == b.bin) ||
-	    (((a.bin | b.bin) & 0x7FFFFFFF) == 0));
-}
-
-/**
- * Determine whether two floats are equal. NaNs are not recognized.
- *
- * @a First double-precision operand.
- * @b Second double-precision operand.
- * @return 1 if both floats are equal, 0 otherwise.
- */
-int is_float64_eq(float64 a, float64 b)
-{
-	/* a equals to b or both are zeros (with any sign) */
-	return ((a.bin == b.bin) ||
-	    (((a.bin | b.bin) & 0x7FFFFFFFFFFFFFFFll) == 0));
-}
-
-/**
- * Determine whether two floats are equal. NaNs are not recognized.
- *
- * @a First quadruple-precision operand.
- * @b Second quadruple-precision operand.
- * @return 1 if both floats are equal, 0 otherwise.
- */
-int is_float128_eq(float128 a, float128 b)
-{
-	uint64_t tmp_hi;
-	uint64_t tmp_lo;
-	
-	/* both are zeros (with any sign) */
-	or128(a.bin.hi, a.bin.lo,
-	    b.bin.hi, b.bin.lo, &tmp_hi, &tmp_lo);
-	and128(tmp_hi, tmp_lo,
-	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
-	int both_zero = eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll);
-	
-	/* a equals to b */
-	int are_equal = eq128(a.bin.hi, a.bin.lo, b.bin.hi, b.bin.lo);
-	
-	return are_equal || both_zero;
-}
-
-/**
- * Lower-than comparison between two floats. NaNs are not recognized.
- *
- * @a First single-precision operand.
- * @b Second single-precision operand.
- * @return 1 if a is lower than b, 0 otherwise.
- */
-int is_float32_lt(float32 a, float32 b) 
-{
-	if (((a.bin | b.bin) & 0x7FFFFFFF) == 0) {
-		/* +- zeroes */
-		return 0;
-	}
-	
-	if ((a.parts.sign) && (b.parts.sign)) {
-		/* if both are negative, smaller is that with greater binary value */
-		return (a.bin > b.bin);
-	}
-	
-	/*
-	 * lets negate signs - now will be positive numbers always
-	 * bigger than negative (first bit will be set for unsigned
-	 * integer comparison)
-	 */
-	a.parts.sign = !a.parts.sign;
-	b.parts.sign = !b.parts.sign;
-	return (a.bin < b.bin);
-}
-
-/**
- * Lower-than comparison between two floats. NaNs are not recognized.
- *
- * @a First double-precision operand.
- * @b Second double-precision operand.
- * @return 1 if a is lower than b, 0 otherwise.
- */
-int is_float64_lt(float64 a, float64 b)
-{
-	if (((a.bin | b.bin) & 0x7FFFFFFFFFFFFFFFll) == 0) {
-		/* +- zeroes */
-		return 0;
-	}
-	
-	if ((a.parts.sign) && (b.parts.sign)) {
-		/* if both are negative, smaller is that with greater binary value */
-		return (a.bin > b.bin);
-	}
-	
-	/*
-	 * lets negate signs - now will be positive numbers always
-	 * bigger than negative (first bit will be set for unsigned
-	 * integer comparison)
-	 */
-	a.parts.sign = !a.parts.sign;
-	b.parts.sign = !b.parts.sign;
-	return (a.bin < b.bin);
-}
-
-/**
- * Lower-than comparison between two floats. NaNs are not recognized.
- *
- * @a First quadruple-precision operand.
- * @b Second quadruple-precision operand.
- * @return 1 if a is lower than b, 0 otherwise.
- */
-int is_float128_lt(float128 a, float128 b)
-{
-	uint64_t tmp_hi;
-	uint64_t tmp_lo;
-	
-	or128(a.bin.hi, a.bin.lo,
-	    b.bin.hi, b.bin.lo, &tmp_hi, &tmp_lo);
-	and128(tmp_hi, tmp_lo,
-	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
-	if (eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll)) {
-		/* +- zeroes */
-		return 0;
-	}
-	
-	if ((a.parts.sign) && (b.parts.sign)) {
-		/* if both are negative, smaller is that with greater binary value */
-		return lt128(b.bin.hi, b.bin.lo, a.bin.hi, a.bin.lo);
-	}
-	
-	/*
-	 * lets negate signs - now will be positive numbers always
-	 * bigger than negative (first bit will be set for unsigned
-	 * integer comparison)
-	 */
-	a.parts.sign = !a.parts.sign;
-	b.parts.sign = !b.parts.sign;
-	return lt128(a.bin.hi, a.bin.lo, b.bin.hi, b.bin.lo);
-}
-
-/**
- * Greater-than comparison between two floats. NaNs are not recognized.
- *
- * @a First single-precision operand.
- * @b Second single-precision operand.
- * @return 1 if a is greater than b, 0 otherwise.
- */
-int is_float32_gt(float32 a, float32 b) 
-{
-	if (((a.bin | b.bin) & 0x7FFFFFFF) == 0) {
-		/* zeroes are equal with any sign */
-		return 0;
-	}
-	
-	if ((a.parts.sign) && (b.parts.sign)) {
-		/* if both are negative, greater is that with smaller binary value */
-		return (a.bin < b.bin);
-	}
-	
-	/*
-	 * lets negate signs - now will be positive numbers always
-	 * bigger than negative (first bit will be set for unsigned
-	 * integer comparison)
-	 */
-	a.parts.sign = !a.parts.sign;
-	b.parts.sign = !b.parts.sign;
-	return (a.bin > b.bin);
-}
-
-/**
- * Greater-than comparison between two floats. NaNs are not recognized.
- *
- * @a First double-precision operand.
- * @b Second double-precision operand.
- * @return 1 if a is greater than b, 0 otherwise.
- */
-int is_float64_gt(float64 a, float64 b)
-{
-	if (((a.bin | b.bin) & 0x7FFFFFFFFFFFFFFFll) == 0) {
-		/* zeroes are equal with any sign */
-		return 0;
-	}
-	
-	if ((a.parts.sign) && (b.parts.sign)) {
-		/* if both are negative, greater is that with smaller binary value */
-		return (a.bin < b.bin);
-	}
-	
-	/*
-	 * lets negate signs - now will be positive numbers always
-	 * bigger than negative (first bit will be set for unsigned
-	 * integer comparison)
-	 */
-	a.parts.sign = !a.parts.sign;
-	b.parts.sign = !b.parts.sign;
-	return (a.bin > b.bin);
-}
-
-/**
- * Greater-than comparison between two floats. NaNs are not recognized.
- *
- * @a First quadruple-precision operand.
- * @b Second quadruple-precision operand.
- * @return 1 if a is greater than b, 0 otherwise.
- */
-int is_float128_gt(float128 a, float128 b)
-{
-	uint64_t tmp_hi;
-	uint64_t tmp_lo;
-	
-	or128(a.bin.hi, a.bin.lo,
-	    b.bin.hi, b.bin.lo, &tmp_hi, &tmp_lo);
-	and128(tmp_hi, tmp_lo,
-	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
-	if (eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll)) {
-		/* zeroes are equal with any sign */
-		return 0;
-	}
-	
-	if ((a.parts.sign) && (b.parts.sign)) {
-		/* if both are negative, greater is that with smaller binary value */
-		return lt128(a.bin.hi, a.bin.lo, b.bin.hi, b.bin.lo);
-	}
-	
-	/*
-	 * lets negate signs - now will be positive numbers always
-	 * bigger than negative (first bit will be set for unsigned
-	 * integer comparison)
-	 */
-	a.parts.sign = !a.parts.sign;
-	b.parts.sign = !b.parts.sign;
-	return lt128(b.bin.hi, b.bin.lo, a.bin.hi, a.bin.lo);
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/conversion.c
===================================================================
--- uspace/lib/softfloat/generic/conversion.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,1041 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Conversion of precision and conversion between integers and floats.
- */
-
-#include <sftypes.h>
-#include <conversion.h>
-#include <comparison.h>
-#include <common.h>
-
-float64 float32_to_float64(float32 a)
-{
-	float64 result;
-	uint64_t frac;
-	
-	result.parts.sign = a.parts.sign;
-	result.parts.fraction = a.parts.fraction;
-	result.parts.fraction <<= (FLOAT64_FRACTION_SIZE - FLOAT32_FRACTION_SIZE);
-	
-	if ((is_float32_infinity(a)) || (is_float32_nan(a))) {
-		result.parts.exp = FLOAT64_MAX_EXPONENT;
-		// TODO; check if its correct for SigNaNs
-		return result;
-	}
-	
-	result.parts.exp = a.parts.exp + ((int) FLOAT64_BIAS - FLOAT32_BIAS);
-	if (a.parts.exp == 0) {
-		/* normalize denormalized numbers */
-		
-		if (result.parts.fraction == 0) { /* fix zero */
-			result.parts.exp = 0;
-			return result;
-		}
-			
-		frac = result.parts.fraction;
-		
-		while (!(frac & FLOAT64_HIDDEN_BIT_MASK)) {
-			frac <<= 1;
-			--result.parts.exp;
-		}
-		
-		++result.parts.exp;
-		result.parts.fraction = frac;
-	}
-	
-	return result;
-}
-
-float128 float32_to_float128(float32 a)
-{
-	float128 result;
-	uint64_t frac_hi, frac_lo;
-	uint64_t tmp_hi, tmp_lo;
-	
-	result.parts.sign = a.parts.sign;
-	result.parts.frac_hi = 0;
-	result.parts.frac_lo = a.parts.fraction;
-	lshift128(result.parts.frac_hi, result.parts.frac_lo,
-	    (FLOAT128_FRACTION_SIZE - FLOAT32_FRACTION_SIZE),
-	    &frac_hi, &frac_lo);
-	result.parts.frac_hi = frac_hi;
-	result.parts.frac_lo = frac_lo;
-	
-	if ((is_float32_infinity(a)) || (is_float32_nan(a))) {
-		result.parts.exp = FLOAT128_MAX_EXPONENT;
-		// TODO; check if its correct for SigNaNs
-		return result;
-	}
-	
-	result.parts.exp = a.parts.exp + ((int) FLOAT128_BIAS - FLOAT32_BIAS);
-	if (a.parts.exp == 0) {
-		/* normalize denormalized numbers */
-		
-		if (eq128(result.parts.frac_hi,
-		    result.parts.frac_lo, 0x0ll, 0x0ll)) { /* fix zero */
-			result.parts.exp = 0;
-			return result;
-		}
-		
-		frac_hi = result.parts.frac_hi;
-		frac_lo = result.parts.frac_lo;
-		
-		and128(frac_hi, frac_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &tmp_hi, &tmp_lo);
-		while (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-			lshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
-			--result.parts.exp;
-		}
-		
-		++result.parts.exp;
-		result.parts.frac_hi = frac_hi;
-		result.parts.frac_lo = frac_lo;
-	}
-	
-	return result;
-}
-
-float128 float64_to_float128(float64 a)
-{
-	float128 result;
-	uint64_t frac_hi, frac_lo;
-	uint64_t tmp_hi, tmp_lo;
-	
-	result.parts.sign = a.parts.sign;
-	result.parts.frac_hi = 0;
-	result.parts.frac_lo = a.parts.fraction;
-	lshift128(result.parts.frac_hi, result.parts.frac_lo,
-	    (FLOAT128_FRACTION_SIZE - FLOAT64_FRACTION_SIZE),
-	    &frac_hi, &frac_lo);
-	result.parts.frac_hi = frac_hi;
-	result.parts.frac_lo = frac_lo;
-	
-	if ((is_float64_infinity(a)) || (is_float64_nan(a))) {
-		result.parts.exp = FLOAT128_MAX_EXPONENT;
-		// TODO; check if its correct for SigNaNs
-		return result;
-	}
-	
-	result.parts.exp = a.parts.exp + ((int) FLOAT128_BIAS - FLOAT64_BIAS);
-	if (a.parts.exp == 0) {
-		/* normalize denormalized numbers */
-		
-		if (eq128(result.parts.frac_hi,
-		    result.parts.frac_lo, 0x0ll, 0x0ll)) { /* fix zero */
-			result.parts.exp = 0;
-			return result;
-		}
-		
-		frac_hi = result.parts.frac_hi;
-		frac_lo = result.parts.frac_lo;
-		
-		and128(frac_hi, frac_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &tmp_hi, &tmp_lo);
-		while (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-			lshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
-			--result.parts.exp;
-		}
-		
-		++result.parts.exp;
-		result.parts.frac_hi = frac_hi;
-		result.parts.frac_lo = frac_lo;
-	}
-	
-	return result;
-}
-
-float32 float64_to_float32(float64 a)
-{
-	float32 result;
-	int32_t exp;
-	uint64_t frac;
-	
-	result.parts.sign = a.parts.sign;
-	
-	if (is_float64_nan(a)) {
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		
-		if (is_float64_signan(a)) {
-			/* set first bit of fraction nonzero */
-			result.parts.fraction = FLOAT32_HIDDEN_BIT_MASK >> 1;
-			return result;
-		}
-		
-		/* fraction nonzero but its first bit is zero */
-		result.parts.fraction = 0x1;
-		return result;
-	}
-	
-	if (is_float64_infinity(a)) {
-		result.parts.fraction = 0;
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		return result;
-	}
-	
-	exp = (int) a.parts.exp - FLOAT64_BIAS + FLOAT32_BIAS;
-	
-	if (exp >= FLOAT32_MAX_EXPONENT) {
-		/* FIXME: overflow */
-		result.parts.fraction = 0;
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		return result;
-	} else if (exp <= 0) {
-		/* underflow or denormalized */
-		
-		result.parts.exp = 0;
-		
-		exp *= -1;	
-		if (exp > FLOAT32_FRACTION_SIZE) {
-			/* FIXME: underflow */
-			result.parts.fraction = 0;
-			return result;
-		}
-		
-		/* denormalized */
-		
-		frac = a.parts.fraction; 
-		frac |= FLOAT64_HIDDEN_BIT_MASK; /* denormalize and set hidden bit */
-		
-		frac >>= (FLOAT64_FRACTION_SIZE - FLOAT32_FRACTION_SIZE + 1);
-		
-		while (exp > 0) {
-			--exp;
-			frac >>= 1;
-		}
-		result.parts.fraction = frac;
-		
-		return result;
-	}
-	
-	result.parts.exp = exp;
-	result.parts.fraction =
-	    a.parts.fraction >> (FLOAT64_FRACTION_SIZE - FLOAT32_FRACTION_SIZE);
-	return result;
-}
-
-float32 float128_to_float32(float128 a)
-{
-	float32 result;
-	int32_t exp;
-	uint64_t frac_hi, frac_lo;
-	
-	result.parts.sign = a.parts.sign;
-	
-	if (is_float128_nan(a)) {
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		
-		if (is_float128_signan(a)) {
-			/* set first bit of fraction nonzero */
-			result.parts.fraction = FLOAT32_HIDDEN_BIT_MASK >> 1;
-			return result;
-		}
-		
-		/* fraction nonzero but its first bit is zero */
-		result.parts.fraction = 0x1;
-		return result;
-	}
-	
-	if (is_float128_infinity(a)) {
-		result.parts.fraction = 0;
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		return result;
-	}
-	
-	exp = (int) a.parts.exp - FLOAT128_BIAS + FLOAT32_BIAS;
-	
-	if (exp >= FLOAT32_MAX_EXPONENT) {
-		/* FIXME: overflow */
-		result.parts.fraction = 0;
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		return result;
-	} else if (exp <= 0) {
-		/* underflow or denormalized */
-		
-		result.parts.exp = 0;
-		
-		exp *= -1;
-		if (exp > FLOAT32_FRACTION_SIZE) {
-			/* FIXME: underflow */
-			result.parts.fraction = 0;
-			return result;
-		}
-		
-		/* denormalized */
-		
-		frac_hi = a.parts.frac_hi;
-		frac_lo = a.parts.frac_lo;
-		
-		/* denormalize and set hidden bit */
-		frac_hi |= FLOAT128_HIDDEN_BIT_MASK_HI;
-		
-		rshift128(frac_hi, frac_lo,
-		    (FLOAT128_FRACTION_SIZE - FLOAT32_FRACTION_SIZE + 1),
-		    &frac_hi, &frac_lo);
-		
-		while (exp > 0) {
-			--exp;
-			rshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
-		}
-		result.parts.fraction = frac_lo;
-		
-		return result;
-	}
-	
-	result.parts.exp = exp;
-	frac_hi = a.parts.frac_hi;
-	frac_lo = a.parts.frac_lo;
-	rshift128(frac_hi, frac_lo,
-	    (FLOAT128_FRACTION_SIZE - FLOAT32_FRACTION_SIZE + 1),
-	    &frac_hi, &frac_lo);
-	result.parts.fraction = frac_lo;
-	return result;
-}
-
-float64 float128_to_float64(float128 a)
-{
-	float64 result;
-	int32_t exp;
-	uint64_t frac_hi, frac_lo;
-	
-	result.parts.sign = a.parts.sign;
-	
-	if (is_float128_nan(a)) {
-		result.parts.exp = FLOAT64_MAX_EXPONENT;
-		
-		if (is_float128_signan(a)) {
-			/* set first bit of fraction nonzero */
-			result.parts.fraction = FLOAT64_HIDDEN_BIT_MASK >> 1;
-			return result;
-		}
-		
-		/* fraction nonzero but its first bit is zero */
-		result.parts.fraction = 0x1;
-		return result;
-	}
-	
-	if (is_float128_infinity(a)) {
-		result.parts.fraction = 0;
-		result.parts.exp = FLOAT64_MAX_EXPONENT;
-		return result;
-	}
-	
-	exp = (int) a.parts.exp - FLOAT128_BIAS + FLOAT64_BIAS;
-	
-	if (exp >= FLOAT64_MAX_EXPONENT) {
-		/* FIXME: overflow */
-		result.parts.fraction = 0;
-		result.parts.exp = FLOAT64_MAX_EXPONENT;
-		return result;
-	} else if (exp <= 0) {
-		/* underflow or denormalized */
-		
-		result.parts.exp = 0;
-		
-		exp *= -1;
-		if (exp > FLOAT64_FRACTION_SIZE) {
-			/* FIXME: underflow */
-			result.parts.fraction = 0;
-			return result;
-		}
-		
-		/* denormalized */
-		
-		frac_hi = a.parts.frac_hi;
-		frac_lo = a.parts.frac_lo;
-		
-		/* denormalize and set hidden bit */
-		frac_hi |= FLOAT128_HIDDEN_BIT_MASK_HI;
-		
-		rshift128(frac_hi, frac_lo,
-		    (FLOAT128_FRACTION_SIZE - FLOAT64_FRACTION_SIZE + 1),
-		    &frac_hi, &frac_lo);
-		
-		while (exp > 0) {
-			--exp;
-			rshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
-		}
-		result.parts.fraction = frac_lo;
-		
-		return result;
-	}
-	
-	result.parts.exp = exp;
-	frac_hi = a.parts.frac_hi;
-	frac_lo = a.parts.frac_lo;
-	rshift128(frac_hi, frac_lo,
-	    (FLOAT128_FRACTION_SIZE - FLOAT64_FRACTION_SIZE + 1),
-	    &frac_hi, &frac_lo);
-	result.parts.fraction = frac_lo;
-	return result;
-}
-
-/** Helper procedure for converting float32 to uint32.
- *
- * @param a Floating point number in normalized form
- *     (NaNs or Inf are not checked).
- * @return Converted unsigned integer.
- */
-static uint32_t _float32_to_uint32_helper(float32 a)
-{
-	uint32_t frac;
-	
-	if (a.parts.exp < FLOAT32_BIAS) {
-		/* TODO: rounding */
-		return 0;
-	}
-	
-	frac = a.parts.fraction;
-	
-	frac |= FLOAT32_HIDDEN_BIT_MASK;
-	/* shift fraction to left so hidden bit will be the most significant bit */
-	frac <<= 32 - FLOAT32_FRACTION_SIZE - 1; 
-	
-	frac >>= 32 - (a.parts.exp - FLOAT32_BIAS) - 1;
-	if ((a.parts.sign == 1) && (frac != 0)) {
-		frac = ~frac;
-		++frac;
-	}
-	
-	return frac;
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-uint32_t float32_to_uint32(float32 a)
-{
-	if (is_float32_nan(a))
-		return UINT32_MAX;
-	
-	if (is_float32_infinity(a) || (a.parts.exp >= (32 + FLOAT32_BIAS))) {
-		if (a.parts.sign)
-			return UINT32_MIN;
-		
-		return UINT32_MAX;
-	}
-	
-	return _float32_to_uint32_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-int32_t float32_to_int32(float32 a)
-{
-	if (is_float32_nan(a))
-		return INT32_MAX;
-	
-	if (is_float32_infinity(a) || (a.parts.exp >= (32 + FLOAT32_BIAS))) {
-		if (a.parts.sign)
-			return INT32_MIN;
-		
-		return INT32_MAX;
-	}
-	
-	return _float32_to_uint32_helper(a);
-}
-
-/** Helper procedure for converting float32 to uint64.
- *
- * @param a Floating point number in normalized form
- *     (NaNs or Inf are not checked).
- * @return Converted unsigned integer.
- */
-static uint64_t _float32_to_uint64_helper(float32 a)
-{
-	uint64_t frac;
-	
-	if (a.parts.exp < FLOAT32_BIAS) {
-		// TODO: rounding
-		return 0;
-	}
-	
-	frac = a.parts.fraction;
-	
-	frac |= FLOAT32_HIDDEN_BIT_MASK;
-	/* shift fraction to left so hidden bit will be the most significant bit */
-	frac <<= 64 - FLOAT32_FRACTION_SIZE - 1;
-	
-	frac >>= 64 - (a.parts.exp - FLOAT32_BIAS) - 1;
-	if ((a.parts.sign == 1) && (frac != 0)) {
-		frac = ~frac;
-		++frac;
-	}
-	
-	return frac;
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-uint64_t float32_to_uint64(float32 a)
-{
-	if (is_float32_nan(a))
-		return UINT64_MAX;
-	
-	if (is_float32_infinity(a) || (a.parts.exp >= (64 + FLOAT32_BIAS))) {
-		if (a.parts.sign)
-			return UINT64_MIN;
-		
-		return UINT64_MAX;
-	}
-	
-	return _float32_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-int64_t float32_to_int64(float32 a)
-{
-	if (is_float32_nan(a))
-		return INT64_MAX;
-	
-	if (is_float32_infinity(a) || (a.parts.exp >= (64 + FLOAT32_BIAS))) {
-		if (a.parts.sign)
-			return INT64_MIN;
-		
-		return INT64_MAX;
-	}
-	
-	return _float32_to_uint64_helper(a);
-}
-
-/** Helper procedure for converting float64 to uint64.
- *
- * @param a Floating point number in normalized form
- *     (NaNs or Inf are not checked).
- * @return Converted unsigned integer.
- */
-static uint64_t _float64_to_uint64_helper(float64 a)
-{
-	uint64_t frac;
-	
-	if (a.parts.exp < FLOAT64_BIAS) {
-		// TODO: rounding
-		return 0;
-	}
-	
-	frac = a.parts.fraction;
-	
-	frac |= FLOAT64_HIDDEN_BIT_MASK;
-	/* shift fraction to left so hidden bit will be the most significant bit */
-	frac <<= 64 - FLOAT64_FRACTION_SIZE - 1;
-	
-	frac >>= 64 - (a.parts.exp - FLOAT64_BIAS) - 1;
-	if ((a.parts.sign == 1) && (frac != 0)) {
-		frac = ~frac;
-		++frac;
-	}
-	
-	return frac;
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-uint32_t float64_to_uint32(float64 a)
-{
-	if (is_float64_nan(a))
-		return UINT32_MAX;
-	
-	if (is_float64_infinity(a) || (a.parts.exp >= (32 + FLOAT64_BIAS))) {
-		if (a.parts.sign)
-			return UINT32_MIN;
-		
-		return UINT32_MAX;
-	}
-	
-	return (uint32_t) _float64_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-int32_t float64_to_int32(float64 a)
-{
-	if (is_float64_nan(a))
-		return INT32_MAX;
-	
-	if (is_float64_infinity(a) || (a.parts.exp >= (32 + FLOAT64_BIAS))) {
-		if (a.parts.sign)
-			return INT32_MIN;
-		
-		return INT32_MAX;
-	}
-	
-	return (int32_t) _float64_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens 
- *  - now its the biggest or the smallest int
- */
-uint64_t float64_to_uint64(float64 a)
-{
-	if (is_float64_nan(a))
-		return UINT64_MAX;
-	
-	if (is_float64_infinity(a) || (a.parts.exp >= (64 + FLOAT64_BIAS))) {
-		if (a.parts.sign)
-			return UINT64_MIN;
-		
-		return UINT64_MAX;
-	}
-	
-	return _float64_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens 
- *  - now its the biggest or the smallest int
- */
-int64_t float64_to_int64(float64 a)
-{
-	if (is_float64_nan(a))
-		return INT64_MAX;
-	
-	if (is_float64_infinity(a) || (a.parts.exp >= (64 + FLOAT64_BIAS))) {
-		if (a.parts.sign)
-			return INT64_MIN;
-		
-		return INT64_MAX;
-	}
-	
-	return _float64_to_uint64_helper(a);
-}
-
-/** Helper procedure for converting float128 to uint64.
- *
- * @param a Floating point number in normalized form
- *     (NaNs or Inf are not checked).
- * @return Converted unsigned integer.
- */
-static uint64_t _float128_to_uint64_helper(float128 a)
-{
-	uint64_t frac_hi, frac_lo;
-	
-	if (a.parts.exp < FLOAT128_BIAS) {
-		// TODO: rounding
-		return 0;
-	}
-	
-	frac_hi = a.parts.frac_hi;
-	frac_lo = a.parts.frac_lo;
-	
-	frac_hi |= FLOAT128_HIDDEN_BIT_MASK_HI;
-	/* shift fraction to left so hidden bit will be the most significant bit */
-	lshift128(frac_hi, frac_lo,
-	    (128 - FLOAT128_FRACTION_SIZE - 1), &frac_hi, &frac_lo);
-	
-	rshift128(frac_hi, frac_lo,
-	    (128 - (a.parts.exp - FLOAT128_BIAS) - 1), &frac_hi, &frac_lo);
-	if ((a.parts.sign == 1) && !eq128(frac_hi, frac_lo, 0x0ll, 0x0ll)) {
-		not128(frac_hi, frac_lo, &frac_hi, &frac_lo);
-		add128(frac_hi, frac_lo, 0x0ll, 0x1ll, &frac_hi, &frac_lo);
-	}
-	
-	return frac_lo;
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-uint32_t float128_to_uint32(float128 a)
-{
-	if (is_float128_nan(a))
-		return UINT32_MAX;
-	
-	if (is_float128_infinity(a) || (a.parts.exp >= (32 + FLOAT128_BIAS))) {
-		if (a.parts.sign)
-			return UINT32_MIN;
-		
-		return UINT32_MAX;
-	}
-	
-	return (uint32_t) _float128_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-int32_t float128_to_int32(float128 a)
-{
-	if (is_float128_nan(a))
-		return INT32_MAX;
-	
-	if (is_float128_infinity(a) || (a.parts.exp >= (32 + FLOAT128_BIAS))) {
-		if (a.parts.sign)
-			return INT32_MIN;
-		
-		return INT32_MAX;
-	}
-	
-	return (int32_t) _float128_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-uint64_t float128_to_uint64(float128 a)
-{
-	if (is_float128_nan(a))
-		return UINT64_MAX;
-	
-	if (is_float128_infinity(a) || (a.parts.exp >= (64 + FLOAT128_BIAS))) {
-		if (a.parts.sign)
-			return UINT64_MIN;
-		
-		return UINT64_MAX;
-	}
-	
-	return _float128_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-int64_t float128_to_int64(float128 a)
-{
-	if (is_float128_nan(a))
-		return INT64_MAX;
-	
-	if (is_float128_infinity(a) || (a.parts.exp >= (64 + FLOAT128_BIAS))) {
-		if (a.parts.sign)
-			return INT64_MIN;
-		
-		return INT64_MAX;
-	}
-	
-	return _float128_to_uint64_helper(a);
-}
-
-float32 uint32_to_float32(uint32_t i)
-{
-	int counter;
-	int32_t exp;
-	float32 result;
-	
-	result.parts.sign = 0;
-	result.parts.fraction = 0;
-	
-	counter = count_zeroes32(i);
-	
-	exp = FLOAT32_BIAS + 32 - counter - 1;
-	
-	if (counter == 32) {
-		result.bin = 0;
-		return result;
-	}
-	
-	if (counter > 0) {
-		i <<= counter - 1;
-	} else {
-		i >>= 1;
-	}
-	
-	round_float32(&exp, &i);
-	
-	result.parts.fraction = i >> (32 - FLOAT32_FRACTION_SIZE - 2);
-	result.parts.exp = exp;
-	
-	return result;
-}
-
-float32 int32_to_float32(int32_t i)
-{
-	float32 result;
-	
-	if (i < 0)
-		result = uint32_to_float32((uint32_t) (-i));
-	else
-		result = uint32_to_float32((uint32_t) i);
-	
-	result.parts.sign = i < 0;
-	
-	return result;
-}
-
-float32 uint64_to_float32(uint64_t i)
-{
-	int counter;
-	int32_t exp;
-	uint32_t j;
-	float32 result;
-	
-	result.parts.sign = 0;
-	result.parts.fraction = 0;
-	
-	counter = count_zeroes64(i);
-	
-	exp = FLOAT32_BIAS + 64 - counter - 1;
-	
-	if (counter == 64) {
-		result.bin = 0;
-		return result;
-	}
-	
-	/* Shift all to the first 31 bits (31st will be hidden 1) */
-	if (counter > 33) {
-		i <<= counter - 1 - 32;
-	} else {
-		i >>= 1 + 32 - counter;
-	}
-	
-	j = (uint32_t) i;
-	round_float32(&exp, &j);
-	
-	result.parts.fraction = j >> (32 - FLOAT32_FRACTION_SIZE - 2);
-	result.parts.exp = exp;
-	return result;
-}
-
-float32 int64_to_float32(int64_t i)
-{
-	float32 result;
-	
-	if (i < 0)
-		result = uint64_to_float32((uint64_t) (-i));
-	else
-		result = uint64_to_float32((uint64_t) i);
-	
-	result.parts.sign = i < 0;
-	
-	return result;
-}
-
-float64 uint32_to_float64(uint32_t i)
-{
-	int counter;
-	int32_t exp;
-	float64 result;
-	uint64_t frac;
-	
-	result.parts.sign = 0;
-	result.parts.fraction = 0;
-	
-	counter = count_zeroes32(i);
-	
-	exp = FLOAT64_BIAS + 32 - counter - 1;
-	
-	if (counter == 32) {
-		result.bin = 0;
-		return result;
-	}
-	
-	frac = i;
-	frac <<= counter + 32 - 1;
-	
-	round_float64(&exp, &frac);
-	
-	result.parts.fraction = frac >> (64 - FLOAT64_FRACTION_SIZE - 2);
-	result.parts.exp = exp;
-	
-	return result;
-}
-
-float64 int32_to_float64(int32_t i)
-{
-	float64 result;
-	
-	if (i < 0)
-		result = uint32_to_float64((uint32_t) (-i));
-	else
-		result = uint32_to_float64((uint32_t) i);
-	
-	result.parts.sign = i < 0;
-	
-	return result;
-}
-
-
-float64 uint64_to_float64(uint64_t i)
-{
-	int counter;
-	int32_t exp;
-	float64 result;
-	
-	result.parts.sign = 0;
-	result.parts.fraction = 0;
-	
-	counter = count_zeroes64(i);
-	
-	exp = FLOAT64_BIAS + 64 - counter - 1;
-	
-	if (counter == 64) {
-		result.bin = 0;
-		return result;
-	}
-	
-	if (counter > 0) {
-		i <<= counter - 1;
-	} else {
-		i >>= 1;
-	}
-	
-	round_float64(&exp, &i);
-	
-	result.parts.fraction = i >> (64 - FLOAT64_FRACTION_SIZE - 2);
-	result.parts.exp = exp;
-	return result;
-}
-
-float64 int64_to_float64(int64_t i)
-{
-	float64 result;
-	
-	if (i < 0)
-		result = uint64_to_float64((uint64_t) (-i));
-	else
-		result = uint64_to_float64((uint64_t) i);
-	
-	result.parts.sign = i < 0;
-	
-	return result;
-}
-
-float128 uint32_to_float128(uint32_t i)
-{
-	int counter;
-	int32_t exp;
-	float128 result;
-	uint64_t frac_hi, frac_lo;
-	
-	result.parts.sign = 0;
-	result.parts.frac_hi = 0;
-	result.parts.frac_lo = 0;
-	
-	counter = count_zeroes32(i);
-	
-	exp = FLOAT128_BIAS + 32 - counter - 1;
-	
-	if (counter == 32) {
-		result.bin.hi = 0;
-		result.bin.lo = 0;
-		return result;
-	}
-	
-	frac_hi = 0;
-	frac_lo = i;
-	lshift128(frac_hi, frac_lo, (counter + 96 - 1), &frac_hi, &frac_lo);
-	
-	round_float128(&exp, &frac_hi, &frac_lo);
-	
-	rshift128(frac_hi, frac_lo,
-	    (128 - FLOAT128_FRACTION_SIZE - 2), &frac_hi, &frac_lo);
-	result.parts.frac_hi = frac_hi;
-	result.parts.frac_lo = frac_lo;
-	result.parts.exp = exp;
-	
-	return result;
-}
-
-float128 int32_to_float128(int32_t i)
-{
-	float128 result;
-	
-	if (i < 0)
-		result = uint32_to_float128((uint32_t) (-i));
-	else
-		result = uint32_to_float128((uint32_t) i);
-	
-	result.parts.sign = i < 0;
-	
-	return result;
-}
-
-
-float128 uint64_to_float128(uint64_t i)
-{
-	int counter;
-	int32_t exp;
-	float128 result;
-	uint64_t frac_hi, frac_lo;
-	
-	result.parts.sign = 0;
-	result.parts.frac_hi = 0;
-	result.parts.frac_lo = 0;
-	
-	counter = count_zeroes64(i);
-	
-	exp = FLOAT128_BIAS + 64 - counter - 1;
-	
-	if (counter == 64) {
-		result.bin.hi = 0;
-		result.bin.lo = 0;
-		return result;
-	}
-	
-	frac_hi = 0;
-	frac_lo = i;
-	lshift128(frac_hi, frac_lo, (counter + 64 - 1), &frac_hi, &frac_lo);
-	
-	round_float128(&exp, &frac_hi, &frac_lo);
-	
-	rshift128(frac_hi, frac_lo,
-	    (128 - FLOAT128_FRACTION_SIZE - 2), &frac_hi, &frac_lo);
-	result.parts.frac_hi = frac_hi;
-	result.parts.frac_lo = frac_lo;
-	result.parts.exp = exp;
-	
-	return result;
-}
-
-float128 int64_to_float128(int64_t i)
-{
-	float128 result;
-	
-	if (i < 0)
-		result = uint64_to_float128((uint64_t) (-i));
-	else
-		result = uint64_to_float128((uint64_t) i);
-	
-	result.parts.sign = i < 0;
-	
-	return result;
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/div.c
===================================================================
--- uspace/lib/softfloat/generic/div.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,542 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Division functions.
- */
-
-#include <sftypes.h>
-#include <add.h>
-#include <div.h>
-#include <comparison.h>
-#include <mul.h>
-#include <common.h>
-
-/** Divide two single-precision floats.
- *
- * @param a Nominator.
- * @param b Denominator.
- *
- * @return Result of division.
- *
- */
-float32 div_float32(float32 a, float32 b)
-{
-	float32 result;
-	int32_t aexp, bexp, cexp;
-	uint64_t afrac, bfrac, cfrac;
-	
-	result.parts.sign = a.parts.sign ^ b.parts.sign;
-	
-	if (is_float32_nan(a)) {
-		if (is_float32_signan(a)) {
-			// FIXME: SigNaN
-		}
-		/* NaN */
-		return a;
-	}
-	
-	if (is_float32_nan(b)) {
-		if (is_float32_signan(b)) {
-			// FIXME: SigNaN
-		}
-		/* NaN */
-		return b;
-	}
-	
-	if (is_float32_infinity(a)) {
-		if (is_float32_infinity(b)) {
-			/*FIXME: inf / inf */
-			result.bin = FLOAT32_NAN;
-			return result;
-		}
-		/* inf / num */
-		result.parts.exp = a.parts.exp;
-		result.parts.fraction = a.parts.fraction;
-		return result;
-	}
-	
-	if (is_float32_infinity(b)) {
-		if (is_float32_zero(a)) {
-			/* FIXME 0 / inf */
-			result.parts.exp = 0;
-			result.parts.fraction = 0;
-			return result;
-		}
-		/* FIXME: num / inf*/
-		result.parts.exp = 0;
-		result.parts.fraction = 0;
-		return result;
-	}
-	
-	if (is_float32_zero(b)) {
-		if (is_float32_zero(a)) {
-			/*FIXME: 0 / 0*/
-			result.bin = FLOAT32_NAN;
-			return result;
-		}
-		/* FIXME: division by zero */
-		result.parts.exp = 0;
-		result.parts.fraction = 0;
-		return result;
-	}
-	
-	afrac = a.parts.fraction;
-	aexp = a.parts.exp;
-	bfrac = b.parts.fraction;
-	bexp = b.parts.exp;
-	
-	/* denormalized numbers */
-	if (aexp == 0) {
-		if (afrac == 0) {
-			result.parts.exp = 0;
-			result.parts.fraction = 0;
-			return result;
-		}
-		
-		/* normalize it*/
-		afrac <<= 1;
-		/* afrac is nonzero => it must stop */
-		while (!(afrac & FLOAT32_HIDDEN_BIT_MASK)) {
-			afrac <<= 1;
-			aexp--;
-		}
-	}
-	
-	if (bexp == 0) {
-		bfrac <<= 1;
-		/* bfrac is nonzero => it must stop */
-		while (!(bfrac & FLOAT32_HIDDEN_BIT_MASK)) {
-			bfrac <<= 1;
-			bexp--;
-		}
-	}
-	
-	afrac = (afrac | FLOAT32_HIDDEN_BIT_MASK) << (32 - FLOAT32_FRACTION_SIZE - 1);
-	bfrac = (bfrac | FLOAT32_HIDDEN_BIT_MASK) << (32 - FLOAT32_FRACTION_SIZE);
-	
-	if (bfrac <= (afrac << 1)) {
-		afrac >>= 1;
-		aexp++;
-	}
-	
-	cexp = aexp - bexp + FLOAT32_BIAS - 2;
-	
-	cfrac = (afrac << 32) / bfrac;
-	if ((cfrac & 0x3F) == 0) { 
-		cfrac |= (bfrac * cfrac != afrac << 32);
-	}
-	
-	/* pack and round */
-	
-	/* find first nonzero digit and shift result and detect possibly underflow */
-	while ((cexp > 0) && (cfrac) && (!(cfrac & (FLOAT32_HIDDEN_BIT_MASK << 7)))) {
-		cexp--;
-		cfrac <<= 1;
-		/* TODO: fix underflow */
-	}
-	
-	cfrac += (0x1 << 6); /* FIXME: 7 is not sure*/
-	
-	if (cfrac & (FLOAT32_HIDDEN_BIT_MASK << 7)) {
-		++cexp;
-		cfrac >>= 1;
-	}
-	
-	/* check overflow */
-	if (cexp >= FLOAT32_MAX_EXPONENT) {
-		/* FIXME: overflow, return infinity */
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		result.parts.fraction = 0;
-		return result;
-	}
-	
-	if (cexp < 0) {
-		/* FIXME: underflow */
-		result.parts.exp = 0;
-		if ((cexp + FLOAT32_FRACTION_SIZE) < 0) {
-			result.parts.fraction = 0;
-			return result;
-		}
-		cfrac >>= 1;
-		while (cexp < 0) {
-			cexp++;
-			cfrac >>= 1;
-		}
-	} else {
-		result.parts.exp = (uint32_t) cexp;
-	}
-	
-	result.parts.fraction = ((cfrac >> 6) & (~FLOAT32_HIDDEN_BIT_MASK)); 
-	
-	return result;
-}
-
-/** Divide two double-precision floats.
- *
- * @param a Nominator.
- * @param b Denominator.
- *
- * @return Result of division.
- *
- */
-float64 div_float64(float64 a, float64 b) 
-{
-	float64 result;
-	int64_t aexp, bexp, cexp;
-	uint64_t afrac, bfrac, cfrac; 
-	uint64_t remlo, remhi;
-	uint64_t tmplo, tmphi;
-	
-	result.parts.sign = a.parts.sign ^ b.parts.sign;
-	
-	if (is_float64_nan(a)) {
-		if (is_float64_signan(b)) {
-			// FIXME: SigNaN
-			return b;
-		}
-		
-		if (is_float64_signan(a)) {
-			// FIXME: SigNaN
-		}
-		/* NaN */
-		return a;
-	}
-	
-	if (is_float64_nan(b)) {
-		if (is_float64_signan(b)) {
-			// FIXME: SigNaN
-		}
-		/* NaN */
-		return b;
-	}
-	
-	if (is_float64_infinity(a)) {
-		if (is_float64_infinity(b) || is_float64_zero(b)) {
-			// FIXME: inf / inf
-			result.bin = FLOAT64_NAN;
-			return result;
-		}
-		/* inf / num */
-		result.parts.exp = a.parts.exp;
-		result.parts.fraction = a.parts.fraction;
-		return result;
-	}
-	
-	if (is_float64_infinity(b)) {
-		if (is_float64_zero(a)) {
-			/* FIXME 0 / inf */
-			result.parts.exp = 0;
-			result.parts.fraction = 0;
-			return result;
-		}
-		/* FIXME: num / inf*/
-		result.parts.exp = 0;
-		result.parts.fraction = 0;
-		return result;
-	}
-	
-	if (is_float64_zero(b)) {
-		if (is_float64_zero(a)) {
-			/*FIXME: 0 / 0*/
-			result.bin = FLOAT64_NAN;
-			return result;
-		}
-		/* FIXME: division by zero */
-		result.parts.exp = 0;
-		result.parts.fraction = 0;
-		return result;
-	}
-	
-	afrac = a.parts.fraction;
-	aexp = a.parts.exp;
-	bfrac = b.parts.fraction;
-	bexp = b.parts.exp;
-	
-	/* denormalized numbers */
-	if (aexp == 0) {
-		if (afrac == 0) {
-			result.parts.exp = 0;
-			result.parts.fraction = 0;
-			return result;
-		}
-		
-		/* normalize it*/
-		aexp++;
-		/* afrac is nonzero => it must stop */	
-		while (!(afrac & FLOAT64_HIDDEN_BIT_MASK)) {
-			afrac <<= 1;
-			aexp--;
-		}
-	}
-	
-	if (bexp == 0) {
-		bexp++;
-		/* bfrac is nonzero => it must stop */	
-		while (!(bfrac & FLOAT64_HIDDEN_BIT_MASK)) {
-			bfrac <<= 1;
-			bexp--;
-		}
-	}
-	
-	afrac = (afrac | FLOAT64_HIDDEN_BIT_MASK) << (64 - FLOAT64_FRACTION_SIZE - 2);
-	bfrac = (bfrac | FLOAT64_HIDDEN_BIT_MASK) << (64 - FLOAT64_FRACTION_SIZE - 1);
-	
-	if (bfrac <= (afrac << 1)) {
-		afrac >>= 1;
-		aexp++;
-	}
-	
-	cexp = aexp - bexp + FLOAT64_BIAS - 2; 
-	
-	cfrac = div128est(afrac, 0x0ll, bfrac);
-	
-	if ((cfrac & 0x1FF) <= 2) {
-		mul64(bfrac, cfrac, &tmphi, &tmplo);
-		sub128(afrac, 0x0ll, tmphi, tmplo, &remhi, &remlo);
-		
-		while ((int64_t) remhi < 0) {
-			cfrac--;
-			add128(remhi, remlo, 0x0ll, bfrac, &remhi, &remlo);
-		}
-		cfrac |= (remlo != 0);
-	}
-	
-	/* round and shift */
-	result = finish_float64(cexp, cfrac, result.parts.sign);
-	return result;
-}
-
-/** Divide two quadruple-precision floats.
- *
- * @param a Nominator.
- * @param b Denominator.
- *
- * @return Result of division.
- *
- */
-float128 div_float128(float128 a, float128 b)
-{
-	float128 result;
-	int64_t aexp, bexp, cexp;
-	uint64_t afrac_hi, afrac_lo, bfrac_hi, bfrac_lo, cfrac_hi, cfrac_lo;
-	uint64_t shift_out;
-	uint64_t rem_hihi, rem_hilo, rem_lohi, rem_lolo;
-	uint64_t tmp_hihi, tmp_hilo, tmp_lohi, tmp_lolo;
-	
-	result.parts.sign = a.parts.sign ^ b.parts.sign;
-	
-	if (is_float128_nan(a)) {
-		if (is_float128_signan(b)) {
-			// FIXME: SigNaN
-			return b;
-		}
-		
-		if (is_float128_signan(a)) {
-			// FIXME: SigNaN
-		}
-		/* NaN */
-		return a;
-	}
-	
-	if (is_float128_nan(b)) {
-		if (is_float128_signan(b)) {
-			// FIXME: SigNaN
-		}
-		/* NaN */
-		return b;
-	}
-	
-	if (is_float128_infinity(a)) {
-		if (is_float128_infinity(b) || is_float128_zero(b)) {
-			// FIXME: inf / inf
-			result.bin.hi = FLOAT128_NAN_HI;
-			result.bin.lo = FLOAT128_NAN_LO;
-			return result;
-		}
-		/* inf / num */
-		result.parts.exp = a.parts.exp;
-		result.parts.frac_hi = a.parts.frac_hi;
-		result.parts.frac_lo = a.parts.frac_lo;
-		return result;
-	}
-	
-	if (is_float128_infinity(b)) {
-		if (is_float128_zero(a)) {
-			// FIXME 0 / inf
-			result.parts.exp = 0;
-			result.parts.frac_hi = 0;
-			result.parts.frac_lo = 0;
-			return result;
-		}
-		// FIXME: num / inf
-		result.parts.exp = 0;
-		result.parts.frac_hi = 0;
-		result.parts.frac_lo = 0;
-		return result;
-	}
-	
-	if (is_float128_zero(b)) {
-		if (is_float128_zero(a)) {
-			// FIXME: 0 / 0
-			result.bin.hi = FLOAT128_NAN_HI;
-			result.bin.lo = FLOAT128_NAN_LO;
-			return result;
-		}
-		// FIXME: division by zero
-		result.parts.exp = 0;
-		result.parts.frac_hi = 0;
-		result.parts.frac_lo = 0;
-		return result;
-	}
-	
-	afrac_hi = a.parts.frac_hi;
-	afrac_lo = a.parts.frac_lo;
-	aexp = a.parts.exp;
-	bfrac_hi = b.parts.frac_hi;
-	bfrac_lo = b.parts.frac_lo;
-	bexp = b.parts.exp;
-	
-	/* denormalized numbers */
-	if (aexp == 0) {
-		if (eq128(afrac_hi, afrac_lo, 0x0ll, 0x0ll)) {
-			result.parts.exp = 0;
-			result.parts.frac_hi = 0;
-			result.parts.frac_lo = 0;
-			return result;
-		}
-		
-		/* normalize it*/
-		aexp++;
-		/* afrac is nonzero => it must stop */
-		and128(afrac_hi, afrac_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &tmp_hihi, &tmp_lolo);
-		while (!lt128(0x0ll, 0x0ll, tmp_hihi, tmp_lolo)) {
-			lshift128(afrac_hi, afrac_lo, 1, &afrac_hi, &afrac_lo);
-			aexp--;
-		}
-	}
-	
-	if (bexp == 0) {
-		bexp++;
-		/* bfrac is nonzero => it must stop */
-		and128(bfrac_hi, bfrac_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &tmp_hihi, &tmp_lolo);
-		while (!lt128(0x0ll, 0x0ll, tmp_hihi, tmp_lolo)) {
-			lshift128(bfrac_hi, bfrac_lo, 1, &bfrac_hi, &bfrac_lo);
-			bexp--;
-		}
-	}
-	
-	or128(afrac_hi, afrac_lo,
-	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &afrac_hi, &afrac_lo);
-	lshift128(afrac_hi, afrac_lo,
-	    (128 - FLOAT128_FRACTION_SIZE - 1), &afrac_hi, &afrac_lo);
-	or128(bfrac_hi, bfrac_lo,
-	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &bfrac_hi, &bfrac_lo);
-	lshift128(bfrac_hi, bfrac_lo,
-	    (128 - FLOAT128_FRACTION_SIZE - 1), &bfrac_hi, &bfrac_lo);
-	
-	if (le128(bfrac_hi, bfrac_lo, afrac_hi, afrac_lo)) {
-		rshift128(afrac_hi, afrac_lo, 1, &afrac_hi, &afrac_lo);
-		aexp++;
-	}
-	
-	cexp = aexp - bexp + FLOAT128_BIAS - 2;
-	
-	cfrac_hi = div128est(afrac_hi, afrac_lo, bfrac_hi);
-	
-	mul128(bfrac_hi, bfrac_lo, 0x0ll, cfrac_hi,
-	    &tmp_lolo /* dummy */, &tmp_hihi, &tmp_hilo, &tmp_lohi);
-	
-	/* sub192(afrac_hi, afrac_lo, 0,
-	 *     tmp_hihi, tmp_hilo, tmp_lohi
-	 *     &rem_hihi, &rem_hilo, &rem_lohi); */
-	sub128(afrac_hi, afrac_lo, tmp_hihi, tmp_hilo, &rem_hihi, &rem_hilo);
-	if (tmp_lohi > 0) {
-		sub128(rem_hihi, rem_hilo, 0x0ll, 0x1ll, &rem_hihi, &rem_hilo);
-	}
-	rem_lohi = -tmp_lohi;
-	
-	while ((int64_t) rem_hihi < 0) {
-		--cfrac_hi;
-		/* add192(rem_hihi, rem_hilo, rem_lohi,
-		 *     0, bfrac_hi, bfrac_lo,
-		 *     &rem_hihi, &rem_hilo, &rem_lohi); */
-		add128(rem_hilo, rem_lohi, bfrac_hi, bfrac_lo, &rem_hilo, &rem_lohi);
-		if (lt128(rem_hilo, rem_lohi, bfrac_hi, bfrac_lo)) {
-			++rem_hihi;
-		}
-	}
-	
-	cfrac_lo = div128est(rem_hilo, rem_lohi, bfrac_lo);
-	
-	if ((cfrac_lo & 0x3FFF) <= 4) {
-		mul128(bfrac_hi, bfrac_lo, 0x0ll, cfrac_lo,
-		    &tmp_hihi /* dummy */, &tmp_hilo, &tmp_lohi, &tmp_lolo);
-		
-		/* sub192(rem_hilo, rem_lohi, 0,
-		 *     tmp_hilo, tmp_lohi, tmp_lolo,
-		 *     &rem_hilo, &rem_lohi, &rem_lolo); */
-		sub128(rem_hilo, rem_lohi, tmp_hilo, tmp_lohi, &rem_hilo, &rem_lohi);
-		if (tmp_lolo > 0) {
-			sub128(rem_hilo, rem_lohi, 0x0ll, 0x1ll, &rem_hilo, &rem_lohi);
-		}
-		rem_lolo = -tmp_lolo;
-		
-		while ((int64_t) rem_hilo < 0) {
-			--cfrac_lo;
-			/* add192(rem_hilo, rem_lohi, rem_lolo,
-			 *     0, bfrac_hi, bfrac_lo,
-			 *     &rem_hilo, &rem_lohi, &rem_lolo); */
-			add128(rem_lohi, rem_lolo, bfrac_hi, bfrac_lo, &rem_lohi, &rem_lolo);
-			if (lt128(rem_lohi, rem_lolo, bfrac_hi, bfrac_lo)) {
-				++rem_hilo;
-			}
-		}
-		
-		cfrac_lo |= ((rem_hilo | rem_lohi | rem_lolo) != 0 );
-	}
-	
-	shift_out = cfrac_lo << (64 - (128 - FLOAT128_FRACTION_SIZE - 1));
-	rshift128(cfrac_hi, cfrac_lo, (128 - FLOAT128_FRACTION_SIZE - 1),
-	    &cfrac_hi, &cfrac_lo);
-	
-	result = finish_float128(cexp, cfrac_hi, cfrac_lo, result.parts.sign, shift_out);
-	return result;
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/mul.c
===================================================================
--- uspace/lib/softfloat/generic/mul.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,383 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Multiplication functions.
- */
-
-#include <sftypes.h>
-#include <mul.h>
-#include <comparison.h>
-#include <common.h>
-
-/** Multiply two single-precision floats.
- *
- * @param a First input operand.
- * @param b Second input operand.
- *
- * @return Result of multiplication.
- *
- */
-float32 mul_float32(float32 a, float32 b)
-{
-	float32 result;
-	uint64_t frac1, frac2;
-	int32_t exp;
-	
-	result.parts.sign = a.parts.sign ^ b.parts.sign;
-	
-	if (is_float32_nan(a) || is_float32_nan(b)) {
-		/* TODO: fix SigNaNs */
-		if (is_float32_signan(a)) {
-			result.parts.fraction = a.parts.fraction;
-			result.parts.exp = a.parts.exp;
-			return result;
-		}
-		if (is_float32_signan(b)) { /* TODO: fix SigNaN */
-			result.parts.fraction = b.parts.fraction;
-			result.parts.exp = b.parts.exp;
-			return result;
-		}
-		/* set NaN as result */
-		result.bin = FLOAT32_NAN;
-		return result;
-	}
-	
-	if (is_float32_infinity(a)) {
-		if (is_float32_zero(b)) {
-			/* FIXME: zero * infinity */
-			result.bin = FLOAT32_NAN;
-			return result;
-		}
-		result.parts.fraction = a.parts.fraction;
-		result.parts.exp = a.parts.exp;
-		return result;
-	}
-	
-	if (is_float32_infinity(b)) {
-		if (is_float32_zero(a)) {
-			/* FIXME: zero * infinity */
-			result.bin = FLOAT32_NAN;
-			return result;
-		}
-		result.parts.fraction = b.parts.fraction;
-		result.parts.exp = b.parts.exp;
-		return result;
-	}
-	
-	/* exp is signed so we can easy detect underflow */
-	exp = a.parts.exp + b.parts.exp;
-	exp -= FLOAT32_BIAS;
-	
-	if (exp >= FLOAT32_MAX_EXPONENT) {
-		/* FIXME: overflow */
-		/* set infinity as result */
-		result.bin = FLOAT32_INF;
-		result.parts.sign = a.parts.sign ^ b.parts.sign;
-		return result;
-	}
-	
-	if (exp < 0) { 
-		/* FIXME: underflow */
-		/* return signed zero */
-		result.parts.fraction = 0x0;
-		result.parts.exp = 0x0;
-		return result;
-	}
-	
-	frac1 = a.parts.fraction;
-	if (a.parts.exp > 0) {
-		frac1 |= FLOAT32_HIDDEN_BIT_MASK;
-	} else {
-		++exp;
-	}
-	
-	frac2 = b.parts.fraction;
-	
-	if (b.parts.exp > 0) {
-		frac2 |= FLOAT32_HIDDEN_BIT_MASK;
-	} else {
-		++exp;
-	}
-	
-	frac1 <<= 1; /* one bit space for rounding */
-	
-	frac1 = frac1 * frac2;
-	
-	/* round and return */
-	while ((exp < FLOAT32_MAX_EXPONENT) &&
-	    (frac1 >= (1 << (FLOAT32_FRACTION_SIZE + 2)))) {
-		/* 23 bits of fraction + one more for hidden bit (all shifted 1 bit left) */
-		++exp;
-		frac1 >>= 1;
-	}
-	
-	/* rounding */
-	/* ++frac1; FIXME: not works - without it is ok */
-	frac1 >>= 1; /* shift off rounding space */
-	
-	if ((exp < FLOAT32_MAX_EXPONENT) &&
-	    (frac1 >= (1 << (FLOAT32_FRACTION_SIZE + 1)))) {
-		++exp;
-		frac1 >>= 1;
-	}
-	
-	if (exp >= FLOAT32_MAX_EXPONENT) {
-		/* TODO: fix overflow */
-		/* return infinity*/
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		result.parts.fraction = 0x0;
-		return result;
-	}
-	
-	exp -= FLOAT32_FRACTION_SIZE;
-	
-	if (exp <= FLOAT32_FRACTION_SIZE) {
-		/* denormalized number */
-		frac1 >>= 1; /* denormalize */
-		while ((frac1 > 0) && (exp < 0)) {
-			frac1 >>= 1;
-			++exp;
-		}
-		if (frac1 == 0) {
-			/* FIXME : underflow */
-			result.parts.exp = 0;
-			result.parts.fraction = 0;
-			return result;
-		}
-	}
-	result.parts.exp = exp; 
-	result.parts.fraction = frac1 & ((1 << FLOAT32_FRACTION_SIZE) - 1);
-	
-	return result;
-}
-
-/** Multiply two double-precision floats.
- *
- * @param a First input operand.
- * @param b Second input operand.
- *
- * @return Result of multiplication.
- *
- */
-float64 mul_float64(float64 a, float64 b)
-{
-	float64 result;
-	uint64_t frac1, frac2;
-	int32_t exp;
-	
-	result.parts.sign = a.parts.sign ^ b.parts.sign;
-	
-	if (is_float64_nan(a) || is_float64_nan(b)) {
-		/* TODO: fix SigNaNs */
-		if (is_float64_signan(a)) {
-			result.parts.fraction = a.parts.fraction;
-			result.parts.exp = a.parts.exp;
-			return result;
-		}
-		if (is_float64_signan(b)) { /* TODO: fix SigNaN */
-			result.parts.fraction = b.parts.fraction;
-			result.parts.exp = b.parts.exp;
-			return result;
-		}
-		/* set NaN as result */
-		result.bin = FLOAT64_NAN;
-		return result;
-	}
-	
-	if (is_float64_infinity(a)) {
-		if (is_float64_zero(b)) {
-			/* FIXME: zero * infinity */
-			result.bin = FLOAT64_NAN;
-			return result;
-		}
-		result.parts.fraction = a.parts.fraction;
-		result.parts.exp = a.parts.exp;
-		return result;
-	}
-	
-	if (is_float64_infinity(b)) {
-		if (is_float64_zero(a)) {
-			/* FIXME: zero * infinity */
-			result.bin = FLOAT64_NAN;
-			return result;
-		}
-		result.parts.fraction = b.parts.fraction;
-		result.parts.exp = b.parts.exp;
-		return result;
-	}
-	
-	/* exp is signed so we can easy detect underflow */
-	exp = a.parts.exp + b.parts.exp - FLOAT64_BIAS;
-	
-	frac1 = a.parts.fraction;
-	
-	if (a.parts.exp > 0) {
-		frac1 |= FLOAT64_HIDDEN_BIT_MASK;
-	} else {
-		++exp;
-	}
-	
-	frac2 = b.parts.fraction;
-	
-	if (b.parts.exp > 0) {
-		frac2 |= FLOAT64_HIDDEN_BIT_MASK;
-	} else {
-		++exp;
-	}
-	
-	frac1 <<= (64 - FLOAT64_FRACTION_SIZE - 1);
-	frac2 <<= (64 - FLOAT64_FRACTION_SIZE - 2);
-	
-	mul64(frac1, frac2, &frac1, &frac2);
-	
-	frac1 |= (frac2 != 0);
-	if (frac1 & (0x1ll << 62)) {
-		frac1 <<= 1;
-		exp--;
-	}
-	
-	result = finish_float64(exp, frac1, result.parts.sign);
-	return result;
-}
-
-/** Multiply two quadruple-precision floats.
- *
- * @param a First input operand.
- * @param b Second input operand.
- *
- * @return Result of multiplication.
- *
- */
-float128 mul_float128(float128 a, float128 b)
-{
-	float128 result;
-	uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
-	int32_t exp;
-	
-	result.parts.sign = a.parts.sign ^ b.parts.sign;
-	
-	if (is_float128_nan(a) || is_float128_nan(b)) {
-		/* TODO: fix SigNaNs */
-		if (is_float128_signan(a)) {
-			result.parts.frac_hi = a.parts.frac_hi;
-			result.parts.frac_lo = a.parts.frac_lo;
-			result.parts.exp = a.parts.exp;
-			return result;
-		}
-		if (is_float128_signan(b)) { /* TODO: fix SigNaN */
-			result.parts.frac_hi = b.parts.frac_hi;
-			result.parts.frac_lo = b.parts.frac_lo;
-			result.parts.exp = b.parts.exp;
-			return result;
-		}
-		/* set NaN as result */
-		result.bin.hi = FLOAT128_NAN_HI;
-		result.bin.lo = FLOAT128_NAN_LO;
-		return result;
-	}
-	
-	if (is_float128_infinity(a)) {
-		if (is_float128_zero(b)) {
-			/* FIXME: zero * infinity */
-			result.bin.hi = FLOAT128_NAN_HI;
-			result.bin.lo = FLOAT128_NAN_LO;
-			return result;
-		}
-		result.parts.frac_hi = a.parts.frac_hi;
-		result.parts.frac_lo = a.parts.frac_lo;
-		result.parts.exp = a.parts.exp;
-		return result;
-	}
-	
-	if (is_float128_infinity(b)) {
-		if (is_float128_zero(a)) {
-			/* FIXME: zero * infinity */
-			result.bin.hi = FLOAT128_NAN_HI;
-			result.bin.lo = FLOAT128_NAN_LO;
-			return result;
-		}
-		result.parts.frac_hi = b.parts.frac_hi;
-		result.parts.frac_lo = b.parts.frac_lo;
-		result.parts.exp = b.parts.exp;
-		return result;
-	}
-	
-	/* exp is signed so we can easy detect underflow */
-	exp = a.parts.exp + b.parts.exp - FLOAT128_BIAS - 1;
-	
-	frac1_hi = a.parts.frac_hi;
-	frac1_lo = a.parts.frac_lo;
-	
-	if (a.parts.exp > 0) {
-		or128(frac1_hi, frac1_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &frac1_hi, &frac1_lo);
-	} else {
-		++exp;
-	}
-	
-	frac2_hi = b.parts.frac_hi;
-	frac2_lo = b.parts.frac_lo;
-	
-	if (b.parts.exp > 0) {
-		or128(frac2_hi, frac2_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &frac2_hi, &frac2_lo);
-	} else {
-		++exp;
-	}
-	
-	lshift128(frac2_hi, frac2_lo,
-	    128 - FLOAT128_FRACTION_SIZE, &frac2_hi, &frac2_lo);
-	
-	tmp_hi = frac1_hi;
-	tmp_lo = frac1_lo;
-	mul128(frac1_hi, frac1_lo, frac2_hi, frac2_lo,
-	    &frac1_hi, &frac1_lo, &frac2_hi, &frac2_lo);
-	add128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &frac1_hi, &frac1_lo);
-	frac2_hi |= (frac2_lo != 0x0ll);
-	
-	if ((FLOAT128_HIDDEN_BIT_MASK_HI << 1) <= frac1_hi) {
-		frac2_hi >>= 1;
-		if (frac1_lo & 0x1ll) {
-			frac2_hi |= (0x1ull < 64);
-		}
-		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
-		++exp;
-	}
-	
-	result = finish_float128(exp, frac1_hi, frac1_lo, result.parts.sign, frac2_hi);
-	return result;
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/other.c
===================================================================
--- uspace/lib/softfloat/generic/other.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,37 +1,0 @@
-/*
- * Copyright (c) 2005 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 softfloat
- * @{
- */
-/** @file Other functions (power, complex).
- */
-
-
-/** @}
- */
Index: pace/lib/softfloat/generic/softfloat.c
===================================================================
--- uspace/lib/softfloat/generic/softfloat.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,1325 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat generic
- * @ingroup sfl
- * @brief Architecture independent parts of FPU software emulation library.
- * @{
- */
-/** @file Softfloat API.
- */
-
-#include <softfloat.h>
-#include <sftypes.h>
-
-#include <add.h>
-#include <sub.h>
-#include <mul.h>
-#include <div.h>
-
-#include <conversion.h>
-#include <comparison.h>
-#include <other.h>
-
-/* Arithmetic functions */
-
-float __addsf3(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	float_t res;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if (fa.data.parts.sign != fb.data.parts.sign) {
-		if (fa.data.parts.sign) {
-			fa.data.parts.sign = 0;
-			res.data = sub_float(fb.data, fa.data);
-			
-			return res.val;
-		}
-		
-		fb.data.parts.sign = 0;
-		res.data = sub_float(fa.data, fb.data);
-		
-		return res.val;
-	}
-	
-	res.data = add_float(fa.data, fb.data);
-	return res.val;
-}
-
-double __adddf3(double a, double b)
-{
-	double_t da;
-	double_t db;
-	double_t res;
-	
-	da.val = a;
-	db.val = b;
-	
-	if (da.data.parts.sign != db.data.parts.sign) {
-		if (da.data.parts.sign) {
-			da.data.parts.sign = 0;
-			res.data = sub_double(db.data, da.data);
-			
-			return res.val;
-		}
-		
-		db.data.parts.sign = 0;
-		res.data = sub_double(da.data, db.data);
-		
-		return res.val;
-	}
-	
-	res.data = add_double(da.data, db.data);
-	return res.val;
-}
-
-long double __addtf3(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	long_double_t res;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if (ta.data.parts.sign != tb.data.parts.sign) {
-		if (ta.data.parts.sign) {
-			ta.data.parts.sign = 0;
-			res.data = sub_long_double(tb.data, ta.data);
-			
-			return res.val;
-		}
-		
-		tb.data.parts.sign = 0;
-		res.data = sub_long_double(ta.data, tb.data);
-		
-		return res.val;
-	}
-	
-	res.data = add_long_double(ta.data, tb.data);
-	return res.val;
-}
-
-float __subsf3(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	float_t res;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if (fa.data.parts.sign != fb.data.parts.sign) {
-		fb.data.parts.sign = !fb.data.parts.sign;
-		res.data = add_float(fa.data, fb.data);
-		
-		return res.val;
-	}
-	
-	res.data = sub_float(fa.data, fb.data);
-	return res.val;
-}
-
-double __subdf3(double a, double b)
-{
-	double_t da;
-	double_t db;
-	double_t res;
-	
-	da.val = a;
-	db.val = b;
-	
-	if (da.data.parts.sign != db.data.parts.sign) {
-		db.data.parts.sign = !db.data.parts.sign;
-		res.data = add_double(da.data, db.data);
-		
-		return res.val;
-	}
-	
-	res.data = sub_double(da.data, db.data);
-	return res.val;
-}
-
-long double __subtf3(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	long_double_t res;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if (ta.data.parts.sign != tb.data.parts.sign) {
-		tb.data.parts.sign = !tb.data.parts.sign;
-		res.data = add_long_double(ta.data, tb.data);
-		
-		return res.val;
-	}
-	
-	res.data = sub_long_double(ta.data, tb.data);
-	return res.val;
-}
-
-float __mulsf3(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	float_t res;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	res.data = mul_float(fa.data, fb.data);
-	return res.val;
-}
-
-double __muldf3(double a, double b)
-{
-	double_t da;
-	double_t db;
-	double_t res;
-	
-	da.val = a;
-	db.val = b;
-	
-	res.data = mul_double(da.data, db.data);
-	return res.val;
-}
-
-long double __multf3(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	long_double_t res;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	res.data = mul_long_double(ta.data, tb.data);
-	return res.val;
-}
-
-float __divsf3(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	float_t res;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	res.data = div_float(fa.data, fb.data);
-	return res.val;
-}
-
-double __divdf3(double a, double b)
-{
-	double_t da;
-	double_t db;
-	double_t res;
-	
-	da.val = a;
-	db.val = b;
-	
-	res.data = div_double(da.data, db.data);
-	return res.val;
-}
-
-long double __divtf3(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	long_double_t res;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	res.data = div_long_double(ta.data, tb.data);
-	return res.val;
-}
-
-float __negsf2(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	fa.data.parts.sign = !fa.data.parts.sign;
-	
-	return fa.val;
-}
-
-double __negdf2(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	da.data.parts.sign = !da.data.parts.sign;
-	
-	return da.val;
-}
-
-long double __negtf2(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	ta.data.parts.sign = !ta.data.parts.sign;
-	
-	return ta.val;
-}
-
-/* Conversion functions */
-
-double __extendsfdf2(float a)
-{
-	float_t fa;
-	double_t res;
-	
-	fa.val = a;
-	res.data = float_to_double(fa.data);
-	
-	return res.val;
-}
-
-long double __extendsftf2(float a)
-{
-	float_t fa;
-	long_double_t res;
-	
-	fa.val = a;
-	res.data = float_to_long_double(fa.data);
-	
-	return res.val;
-}
-
-long double __extenddftf2(double a)
-{
-	double_t da;
-	long_double_t res;
-	
-	da.val = a;
-	res.data = double_to_long_double(da.data);
-	
-	return res.val;
-}
-
-float __truncdfsf2(double a)
-{
-	double_t da;
-	float_t res;
-	
-	da.val = a;
-	res.data = double_to_float(da.data);
-	
-	return res.val;
-}
-
-float __trunctfsf2(long double a)
-{
-	long_double_t ta;
-	float_t res;
-	
-	ta.val = a;
-	res.data = long_double_to_float(ta.data);
-	
-	return res.val;
-}
-
-double __trunctfdf2(long double a)
-{
-	long_double_t ta;
-	double_t res;
-	
-	ta.val = a;
-	res.data = long_double_to_double(ta.data);
-	
-	return res.val;
-}
-
-int __fixsfsi(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	return float_to_int(fa.data);
-}
-
-int __fixdfsi(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	return double_to_int(da.data);
-}
-
-int __fixtfsi(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	return long_double_to_int(ta.data);
-}
- 
-long __fixsfdi(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	return float_to_long(fa.data);
-}
-
-long __fixdfdi(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	return double_to_long(da.data);
-}
-
-long __fixtfdi(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	return long_double_to_long(ta.data);
-}
- 
-long long __fixsfti(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	return float_to_llong(fa.data);
-}
-
-long long __fixdfti(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	return double_to_llong(da.data);
-}
-
-long long __fixtfti(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	return long_double_to_llong(ta.data);
-}
-
-unsigned int __fixunssfsi(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	return float_to_uint(fa.data);
-}
-
-unsigned int __fixunsdfsi(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	return double_to_uint(da.data);
-}
-
-unsigned int __fixunstfsi(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	return long_double_to_uint(ta.data);
-}
- 
-unsigned long __fixunssfdi(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	return float_to_ulong(fa.data);
-}
-
-unsigned long __fixunsdfdi(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	return double_to_ulong(da.data);
-}
-
-unsigned long __fixunstfdi(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	return long_double_to_ulong(ta.data);
-}
- 
-unsigned long long __fixunssfti(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	return float_to_ullong(fa.data);
-}
-
-unsigned long long __fixunsdfti(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	return double_to_ullong(da.data);
-}
-
-unsigned long long __fixunstfti(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	return long_double_to_ullong(ta.data);
-}
- 
-float __floatsisf(int i)
-{
-	float_t res;
-	
-	res.data = int_to_float(i);
-	return res.val;
-}
-
-double __floatsidf(int i)
-{
-	double_t res;
-	
-	res.data = int_to_double(i);
-	return res.val;
-}
-
-long double __floatsitf(int i)
-{
-	long_double_t res;
-	
-	res.data = int_to_long_double(i);
-	return res.val;
-}
- 
-float __floatdisf(long i)
-{
-	float_t res;
-	
-	res.data = long_to_float(i);
-	return res.val;
-}
-
-double __floatdidf(long i)
-{
-	double_t res;
-	
-	res.data = long_to_double(i);
-	return res.val;
-}
-
-long double __floatditf(long i)
-{
-	long_double_t res;
-	
-	res.data = long_to_long_double(i);
-	return res.val;
-}
-
-float __floattisf(long long i)
-{
-	float_t res;
-	
-	res.data = llong_to_float(i);
-	return res.val;
-}
-
-double __floattidf(long long i)
-{
-	double_t res;
-	
-	res.data = llong_to_double(i);
-	return res.val;
-}
-
-long double __floattitf(long long i)
-{
-	long_double_t res;
-	
-	res.data = llong_to_long_double(i);
-	return res.val;
-}
-
-float __floatunsisf(unsigned int i)
-{
-	float_t res;
-	
-	res.data = uint_to_float(i);
-	return res.val;
-}
-
-double __floatunsidf(unsigned int i)
-{
-	double_t res;
-	
-	res.data = uint_to_double(i);
-	return res.val;
-}
-
-long double __floatunsitf(unsigned int i)
-{
-	long_double_t res;
-	
-	res.data = uint_to_long_double(i);
-	return res.val;
-}
- 
-float __floatundisf(unsigned long i)
-{
-	float_t res;
-	
-	res.data = ulong_to_float(i);
-	return res.val;
-}
-
-double __floatundidf(unsigned long i)
-{
-	double_t res;
-	
-	res.data = ulong_to_double(i);
-	return res.val;
-}
-
-long double __floatunditf(unsigned long i)
-{
-	long_double_t res;
-	
-	res.data = ulong_to_long_double(i);
-	return res.val;
-}
- 
-float __floatuntisf(unsigned long long i)
-{
-	float_t res;
-	
-	res.data = ullong_to_float(i);
-	return res.val;
-}
-
-double __floatuntidf(unsigned long long i)
-{
-	double_t res;
-	
-	res.data = ullong_to_double(i);
-	return res.val;
-}
-
-long double __floatuntitf(unsigned long long i)
-{
-	long_double_t res;
-	
-	res.data = ullong_to_long_double(i);
-	return res.val;
-}
-
-/* Comparison functions */
-
-int __cmpsf2(float a, float b) 
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
-		/* no special constant for unordered - maybe signaled? */
-		return 1;
-	}
-	
-	if (is_float_eq(fa.data, fb.data))
-		return 0;
-	
-	if (is_float_lt(fa.data, fb.data))
-		return -1;
-	
-	return 1;
-}
-
-int __cmpdf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
-		/* no special constant for unordered - maybe signaled? */
-		return 1;
-	}
-	
-	if (is_double_eq(da.data, db.data))
-		return 0;
-	
-	if (is_double_lt(da.data, db.data))
-		return -1;
-	
-	return 1;
-}
-
-int __cmptf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
-		/* no special constant for unordered - maybe signaled? */
-		return 1;
-	}
-	
-	if (is_long_double_eq(ta.data, tb.data))
-		return 0;
-	
-	if (is_long_double_lt(ta.data, tb.data))
-		return -1;
-	
-	return 1;
-}
-
-int __unordsf2(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	return ((is_float_nan(fa.data)) || (is_float_nan(fb.data)));
-}
-
-int __unorddf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	return ((is_double_nan(da.data)) || (is_double_nan(db.data)));
-}
-
-int __unordtf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	return ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)));
-}
-
-int __eqsf2(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	return is_float_eq(fa.data, fb.data) - 1;
-}
-
-int __eqdf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	return is_double_eq(da.data, db.data) - 1;
-}
-
-int __eqtf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	return is_long_double_eq(ta.data, tb.data) - 1;
-}
-
-int __nesf2(float a, float b)
-{
-	/* strange behavior, but it was in gcc documentation */
-	return __eqsf2(a, b);
-}
-
-int __nedf2(double a, double b)
-{
-	/* strange behavior, but it was in gcc documentation */
-	return __eqdf2(a, b);
-}
-
-int __netf2(long double a, long double b)
-{
-	/* strange behavior, but it was in gcc documentation */
-	return __eqtf2(a, b);
-}
-
-int __gesf2(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
-		// TODO: sigNaNs
-		return -1;
-	}
-	
-	if (is_float_eq(fa.data, fb.data))
-		return 0;
-	
-	if (is_float_gt(fa.data, fb.data))
-		return 1;
-	
-	return -1;
-}
-
-int __gedf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
-		// TODO: sigNaNs
-		return -1;
-	}
-	
-	if (is_double_eq(da.data, db.data))
-		return 0;
-	
-	if (is_double_gt(da.data, db.data))
-		return 1;
-	
-	return -1;
-}
-
-int __getf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
-		// TODO: sigNaNs
-		return -1;
-	}
-	
-	if (is_long_double_eq(ta.data, tb.data))
-		return 0;
-	
-	if (is_long_double_gt(ta.data, tb.data))
-		return 1;
-	
-	return -1;
-}
-
-int __ltsf2(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	if (is_float_lt(fa.data, fb.data))
-		return -1;
-	
-	return 0;
-}
-
-int __ltdf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	if (is_double_lt(da.data, db.data))
-		return -1;
-	
-	return 0;
-}
-
-int __lttf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	if (is_long_double_lt(ta.data, tb.data))
-		return -1;
-	
-	return 0;
-}
-
-int __lesf2(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	if (is_float_eq(fa.data, fb.data))
-		return 0;
-	
-	if (is_float_lt(fa.data, fb.data))
-		return -1;
-	
-	return 1;
-}
-
-int __ledf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	if (is_double_eq(da.data, db.data))
-		return 0;
-	
-	if (is_double_lt(da.data, db.data))
-		return -1;
-	
-	return 1;
-}
-
-int __letf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	if (is_long_double_eq(ta.data, tb.data))
-		return 0;
-	
-	if (is_long_double_lt(ta.data, tb.data))
-		return -1;
-	
-	return 1;
-}
-
-int __gtsf2(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
-		// TODO: sigNaNs
-		return -1;
-	}
-	
-	if (is_float_gt(fa.data, fb.data))
-		return 1;
-	
-	return 0;
-}
-
-int __gtdf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
-		// TODO: sigNaNs
-		return -1;
-	}
-	
-	if (is_double_gt(da.data, db.data))
-		return 1;
-	
-	return 0;
-}
-
-int __gttf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
-		// TODO: sigNaNs
-		return -1;
-	}
-	
-	if (is_long_double_gt(ta.data, tb.data))
-		return 1;
-	
-	return 0;
-}
-
-/* SPARC quadruple-precision wrappers */
-
-void _Qp_add(long double *c, long double *a, long double *b)
-{
-	*c = __addtf3(*a, *b);
-}
-
-void _Qp_sub(long double *c, long double *a, long double *b)
-{
-	*c = __subtf3(*a, *b);
-}
-
-void _Qp_mul(long double *c, long double *a, long double *b)
-{
-	*c = __multf3(*a, *b);
-}
-
-void _Qp_div(long double *c, long double *a, long double *b)
-{
-	*c = __divtf3(*a, *b);
-}
-
-void _Qp_neg(long double *c, long double *a)
-{
-	*c = __negtf2(*a);
-}
-
-void _Qp_stoq(long double *c, float a)
-{
-	*c = __extendsftf2(a);
-}
-
-void _Qp_dtoq(long double *c, double a)
-{
-	*c = __extenddftf2(a);
-}
-
-float _Qp_qtos(long double *a)
-{
-	return __trunctfsf2(*a);
-}
-
-double _Qp_qtod(long double *a)
-{
-	return __trunctfdf2(*a);
-}
-
-int _Qp_qtoi(long double *a)
-{
-	return __fixtfsi(*a);
-}
-
-unsigned int _Qp_qtoui(long double *a)
-{
-	return __fixunstfsi(*a);
-}
-
-long _Qp_qtox(long double *a)
-{
-	return __fixtfdi(*a);
-}
-
-unsigned long _Qp_qtoux(long double *a)
-{
-	return __fixunstfdi(*a);
-}
-
-void _Qp_itoq(long double *c, int a)
-{
-	*c = __floatsitf(a);
-}
-
-void _Qp_uitoq(long double *c, unsigned int a)
-{
-	*c = __floatunsitf(a);
-}
-
-void _Qp_xtoq(long double *c, long a)
-{
-	*c = __floatditf(a);
-}
-
-void _Qp_uxtoq(long double *c, unsigned long a)
-{
-	*c = __floatunditf(a);
-}
-
-int _Qp_cmp(long double *a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 3;
-	
-	if (is_long_double_eq(ta.data, tb.data))
-		return 0;
-	
-	if (is_long_double_lt(ta.data, tb.data))
-		return 1;
-	
-	return 2;
-}
-
-int _Qp_cmpe(long double *a, long double *b)
-{
-	/* strange, but is defined this way in SPARC Compliance Definition */
-	return _Qp_cmp(a, b);
-}
-
-int _Qp_feq(long double *a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 0;
-	
-	return is_long_double_eq(ta.data, tb.data);
-}
-
-int _Qp_fge(long double *a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 0;
-	
-	return is_long_double_eq(ta.data, tb.data) ||
-	    is_long_double_gt(ta.data, tb.data);
-}
-
-int _Qp_fgt(long double *a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 0;
-	
-	return is_long_double_gt(ta.data, tb.data);
-}
-
-int _Qp_fle(long double*a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 0;
-	
-	return is_long_double_eq(ta.data, tb.data) ||
-	    is_long_double_lt(ta.data, tb.data);
-}
-
-int _Qp_flt(long double *a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 0;
-	
-	return is_long_double_lt(ta.data, tb.data);
-}
-
-int _Qp_fne(long double *a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 0;
-	
-	return !is_long_double_eq(ta.data, tb.data);
-}
-
-double __aeabi_i2d(int i)
-{
-	return __floatsidf(i);
-}
-
-double __aeabi_ui2d(unsigned int i)
-{
-	return __floatunsidf(i);
-}
-
-int __aeabi_d2iz(double a)
-{
-	return __fixdfsi(a);
-}
-
-unsigned int __aeabi_d2uiz(double a)
-{
-	return __fixunsdfsi(a);
-}
-
-int __aeabi_dcmpge(double a, double b)
-{
-	return __gedf2(a, b);
-}
-
-int __aeabi_dcmpgt(double a, double b)
-{
-	return __gtdf2(a, b);
-}
-
-int __aeabi_dcmplt(double a, double b)
-{
-	return __ltdf2(a, b);
-}
-
-double __aeabi_dadd(double a, double b)
-{
-	return __adddf3(a, b);
-}
-
-double __aeabi_dsub(double a, double b)
-{
-	return __subdf3(a, b);
-}
-
-double __aeabi_dmul(double a, double b)
-{
-	return __muldf3(a, b);
-}
-
-double __aeabi_ddiv(double a, double b)
-{
-	return __divdf3(a, b);
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/sub.c
===================================================================
--- uspace/lib/softfloat/generic/sub.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,441 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Substraction functions.
- */
-
-#include <sftypes.h>
-#include <sub.h>
-#include <comparison.h>
-#include <common.h>
-
-/** Subtract two single-precision floats with the same sign.
- *
- * @param a First input operand.
- * @param b Second input operand.
- *
- * @return Result of substraction.
- *
- */
-float32 sub_float32(float32 a, float32 b)
-{
-	int expdiff;
-	uint32_t exp1, exp2, frac1, frac2;
-	float32 result;
-	
-	result.bin = 0;
-	
-	expdiff = a.parts.exp - b.parts.exp;
-	if ((expdiff < 0 ) || ((expdiff == 0) &&
-	    (a.parts.fraction < b.parts.fraction))) {
-		if (is_float32_nan(b)) {
-			if (is_float32_signan(b)) {
-				// TODO: fix SigNaN
-			}
-			
-			return b;
-		}
-		
-		if (b.parts.exp == FLOAT32_MAX_EXPONENT) {
-			/* num -(+-inf) = -+inf */
-			b.parts.sign = !b.parts.sign;
-			return b;
-		}
-		
-		result.parts.sign = !a.parts.sign;
-		
-		frac1 = b.parts.fraction;
-		exp1 = b.parts.exp;
-		frac2 = a.parts.fraction;
-		exp2 = a.parts.exp;
-		expdiff *= -1;
-	} else {
-		if (is_float32_nan(a)) {
-			if ((is_float32_signan(a)) || (is_float32_signan(b))) {
-				// TODO: fix SigNaN
-			}
-			
-			return a;
-		}
-		
-		if (a.parts.exp == FLOAT32_MAX_EXPONENT) {
-			if (b.parts.exp == FLOAT32_MAX_EXPONENT) {
-				/* inf - inf => nan */
-				// TODO: fix exception
-				result.bin = FLOAT32_NAN;
-				return result;
-			}
-			
-			return a;
-		}
-		
-		result.parts.sign = a.parts.sign;
-		
-		frac1 = a.parts.fraction;
-		exp1 = a.parts.exp;
-		frac2 = b.parts.fraction;
-		exp2 = b.parts.exp;
-	}
-	
-	if (exp1 == 0) {
-		/* both are denormalized */
-		result.parts.fraction = frac1 - frac2;
-		if (result.parts.fraction > frac1) {
-			// TODO: underflow exception
-			return result;
-		}
-		
-		result.parts.exp = 0;
-		return result;
-	}
-	
-	/* add hidden bit */
-	frac1 |= FLOAT32_HIDDEN_BIT_MASK;
-	
-	if (exp2 == 0) {
-		/* denormalized */
-		--expdiff;
-	} else {
-		/* normalized */
-		frac2 |= FLOAT32_HIDDEN_BIT_MASK;
-	}
-	
-	/* create some space for rounding */
-	frac1 <<= 6;
-	frac2 <<= 6;
-	
-	if (expdiff > FLOAT32_FRACTION_SIZE + 1)
-		goto done;
-	
-	frac1 = frac1 - (frac2 >> expdiff);
-	
-done:
-	/* TODO: find first nonzero digit and shift result and detect possibly underflow */
-	while ((exp1 > 0) && (!(frac1 & (FLOAT32_HIDDEN_BIT_MASK << 6 )))) {
-		--exp1;
-		frac1 <<= 1;
-		/* TODO: fix underflow - frac1 == 0 does not necessary means underflow... */
-	}
-	
-	/* rounding - if first bit after fraction is set then round up */
-	frac1 += 0x20;
-	
-	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7)) {
-		++exp1;
-		frac1 >>= 1;
-	}
-	
-	/* Clear hidden bit and shift */
-	result.parts.fraction = ((frac1 >> 6) & (~FLOAT32_HIDDEN_BIT_MASK));
-	result.parts.exp = exp1;
-	
-	return result;
-}
-
-/** Subtract two double-precision floats with the same sign.
- *
- * @param a First input operand.
- * @param b Second input operand.
- *
- * @return Result of substraction.
- *
- */
-float64 sub_float64(float64 a, float64 b)
-{
-	int expdiff;
-	uint32_t exp1, exp2;
-	uint64_t frac1, frac2;
-	float64 result;
-	
-	result.bin = 0;
-	
-	expdiff = a.parts.exp - b.parts.exp;
-	if ((expdiff < 0 ) ||
-	    ((expdiff == 0) && (a.parts.fraction < b.parts.fraction))) {
-		if (is_float64_nan(b)) {
-			if (is_float64_signan(b)) {
-				// TODO: fix SigNaN
-			}
-			
-			return b;
-		}
-		
-		if (b.parts.exp == FLOAT64_MAX_EXPONENT) {
-			/* num -(+-inf) = -+inf */
-			b.parts.sign = !b.parts.sign;
-			return b;
-		}
-		
-		result.parts.sign = !a.parts.sign;
-		
-		frac1 = b.parts.fraction;
-		exp1 = b.parts.exp;
-		frac2 = a.parts.fraction;
-		exp2 = a.parts.exp;
-		expdiff *= -1;
-	} else {
-		if (is_float64_nan(a)) {
-			if (is_float64_signan(a) || is_float64_signan(b)) {
-				// TODO: fix SigNaN
-			}
-			
-			return a;
-		}
-		
-		if (a.parts.exp == FLOAT64_MAX_EXPONENT) {
-			if (b.parts.exp == FLOAT64_MAX_EXPONENT) {
-				/* inf - inf => nan */
-				// TODO: fix exception
-				result.bin = FLOAT64_NAN;
-				return result;
-			}
-			
-			return a;
-		}
-		
-		result.parts.sign = a.parts.sign;
-		
-		frac1 = a.parts.fraction;
-		exp1 = a.parts.exp;
-		frac2 = b.parts.fraction;
-		exp2 = b.parts.exp;
-	}
-	
-	if (exp1 == 0) {
-		/* both are denormalized */
-		result.parts.fraction = frac1 - frac2;
-		if (result.parts.fraction > frac1) {
-			// TODO: underflow exception
-			return result;
-		}
-		
-		result.parts.exp = 0;
-		return result;
-	}
-	
-	/* add hidden bit */
-	frac1 |= FLOAT64_HIDDEN_BIT_MASK;
-	
-	if (exp2 == 0) {
-		/* denormalized */
-		--expdiff;
-	} else {
-		/* normalized */
-		frac2 |= FLOAT64_HIDDEN_BIT_MASK;
-	}
-	
-	/* create some space for rounding */
-	frac1 <<= 6;
-	frac2 <<= 6;
-	
-	if (expdiff > FLOAT64_FRACTION_SIZE + 1)
-		goto done;
-	
-	frac1 = frac1 - (frac2 >> expdiff);
-	
-done:
-	/* TODO: find first nonzero digit and shift result and detect possibly underflow */
-	while ((exp1 > 0) && (!(frac1 & (FLOAT64_HIDDEN_BIT_MASK << 6 )))) {
-		--exp1;
-		frac1 <<= 1;
-		/* TODO: fix underflow - frac1 == 0 does not necessary means underflow... */
-	}
-	
-	/* rounding - if first bit after fraction is set then round up */
-	frac1 += 0x20;
-	
-	if (frac1 & (FLOAT64_HIDDEN_BIT_MASK << 7)) {
-		++exp1;
-		frac1 >>= 1;
-	}
-	
-	/* Clear hidden bit and shift */
-	result.parts.fraction = ((frac1 >> 6) & (~FLOAT64_HIDDEN_BIT_MASK));
-	result.parts.exp = exp1;
-	
-	return result;
-}
-
-/** Subtract two quadruple-precision floats with the same sign.
- *
- * @param a First input operand.
- * @param b Second input operand.
- *
- * @return Result of substraction.
- *
- */
-float128 sub_float128(float128 a, float128 b)
-{
-	int expdiff;
-	uint32_t exp1, exp2;
-	uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
-	float128 result;
-	
-	result.bin.hi = 0;
-	result.bin.lo = 0;
-	
-	expdiff = a.parts.exp - b.parts.exp;
-	if ((expdiff < 0 ) || ((expdiff == 0) &&
-	    lt128(a.parts.frac_hi, a.parts.frac_lo, b.parts.frac_hi, b.parts.frac_lo))) {
-		if (is_float128_nan(b)) {
-			if (is_float128_signan(b)) {
-				// TODO: fix SigNaN
-			}
-			
-			return b;
-		}
-		
-		if (b.parts.exp == FLOAT128_MAX_EXPONENT) {
-			/* num -(+-inf) = -+inf */
-			b.parts.sign = !b.parts.sign;
-			return b;
-		}
-		
-		result.parts.sign = !a.parts.sign;
-		
-		frac1_hi = b.parts.frac_hi;
-		frac1_lo = b.parts.frac_lo;
-		exp1 = b.parts.exp;
-		frac2_hi = a.parts.frac_hi;
-		frac2_lo = a.parts.frac_lo;
-		exp2 = a.parts.exp;
-		expdiff *= -1;
-	} else {
-		if (is_float128_nan(a)) {
-			if (is_float128_signan(a) || is_float128_signan(b)) {
-				// TODO: fix SigNaN
-			}
-			
-			return a;
-		}
-		
-		if (a.parts.exp == FLOAT128_MAX_EXPONENT) {
-			if (b.parts.exp == FLOAT128_MAX_EXPONENT) {
-				/* inf - inf => nan */
-				// TODO: fix exception
-				result.bin.hi = FLOAT128_NAN_HI;
-				result.bin.lo = FLOAT128_NAN_LO;
-				return result;
-			}
-			return a;
-		}
-		
-		result.parts.sign = a.parts.sign;
-		
-		frac1_hi = a.parts.frac_hi;
-		frac1_lo = a.parts.frac_lo;
-		exp1 = a.parts.exp;
-		frac2_hi = b.parts.frac_hi;
-		frac2_lo = b.parts.frac_lo;
-		exp2 = b.parts.exp;
-	}
-	
-	if (exp1 == 0) {
-		/* both are denormalized */
-		sub128(frac1_hi, frac1_lo, frac2_hi, frac2_lo, &tmp_hi, &tmp_lo);
-		result.parts.frac_hi = tmp_hi;
-		result.parts.frac_lo = tmp_lo;
-		if (lt128(frac1_hi, frac1_lo, result.parts.frac_hi, result.parts.frac_lo)) {
-			// TODO: underflow exception
-			return result;
-		}
-		
-		result.parts.exp = 0;
-		return result;
-	}
-	
-	/* add hidden bit */
-	or128(frac1_hi, frac1_lo,
-	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &frac1_hi, &frac1_lo);
-	
-	if (exp2 == 0) {
-		/* denormalized */
-		--expdiff;
-	} else {
-		/* normalized */
-		or128(frac2_hi, frac2_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &frac2_hi, &frac2_lo);
-	}
-	
-	/* create some space for rounding */
-	lshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
-	lshift128(frac2_hi, frac2_lo, 6, &frac2_hi, &frac2_lo);
-	
-	if (expdiff > FLOAT128_FRACTION_SIZE + 1)
-		goto done;
-	
-	rshift128(frac2_hi, frac2_lo, expdiff, &tmp_hi, &tmp_lo);
-	sub128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &frac1_hi, &frac1_lo);
-	
-done:
-	/* TODO: find first nonzero digit and shift result and detect possibly underflow */
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 6,
-	    &tmp_hi, &tmp_lo);
-	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	while ((exp1 > 0) && (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo))) {
-		--exp1;
-		lshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
-		/* TODO: fix underflow - frac1 == 0 does not necessary means underflow... */
-		
-		lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 6,
-		    &tmp_hi, &tmp_lo);
-		and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	}
-	
-	/* rounding - if first bit after fraction is set then round up */
-	add128(frac1_hi, frac1_lo, 0x0ll, 0x20ll, &frac1_hi, &frac1_lo);
-	
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 7,
-	   &tmp_hi, &tmp_lo);
-	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-		++exp1;
-		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
-	}
-	
-	/* Clear hidden bit and shift */
-	rshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
-	not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &tmp_hi, &tmp_lo);
-	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	result.parts.frac_hi = tmp_hi;
-	result.parts.frac_lo = tmp_lo;
-	
-	result.parts.exp = exp1;
-	
-	return result;
-}
-
-/** @}
- */
Index: pace/lib/softfloat/include/add.h
===================================================================
--- uspace/lib/softfloat/include/add.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Addition functions.
- */
-
-#ifndef __ADD_H__
-#define __ADD_H__
-
-extern float32 add_float32(float32, float32);
-extern float64 add_float64(float64, float64);
-extern float96 add_float96(float96, float96);
-extern float128 add_float128(float128, float128);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/common.h
===================================================================
--- uspace/lib/softfloat/include/common.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,76 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Common helper operations.
- */
-
-#ifndef __COMMON_H__
-#define __COMMON_H__
-
-#include <sftypes.h>
-
-extern float64 finish_float64(int32_t, uint64_t, char);
-extern float128 finish_float128(int32_t, uint64_t, uint64_t, char, uint64_t);
-
-extern int count_zeroes8(uint8_t);
-extern int count_zeroes32(uint32_t);
-extern int count_zeroes64(uint64_t);
-
-extern void round_float32(int32_t *, uint32_t *);
-extern void round_float64(int32_t *, uint64_t *);
-extern void round_float128(int32_t *, uint64_t *, uint64_t *);
-
-extern void lshift128(uint64_t, uint64_t, int, uint64_t *, uint64_t *);
-extern void rshift128(uint64_t, uint64_t, int, uint64_t *, uint64_t *);
-
-extern void and128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
-extern void or128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
-extern void xor128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
-extern void not128(uint64_t, uint64_t, uint64_t *, uint64_t *);
-
-extern int eq128(uint64_t, uint64_t, uint64_t, uint64_t);
-extern int le128(uint64_t, uint64_t, uint64_t, uint64_t);
-extern int lt128(uint64_t, uint64_t, uint64_t, uint64_t);
-
-extern void add128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
-extern void sub128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
-
-extern void mul64(uint64_t, uint64_t, uint64_t *, uint64_t *);
-extern void mul128(uint64_t, uint64_t, uint64_t, uint64_t,
-    uint64_t *, uint64_t *, uint64_t *, uint64_t *);
-
-extern uint64_t div128est(uint64_t, uint64_t, uint64_t);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/comparison.h
===================================================================
--- uspace/lib/softfloat/include/comparison.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,82 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Comparison functions.
- */
-
-#ifndef __COMPARISON_H__
-#define __COMPARISON_H__
-
-extern int is_float32_nan(float32);
-extern int is_float32_signan(float32);
-
-extern int is_float32_infinity(float32);
-extern int is_float32_zero(float32);
-
-extern int is_float32_eq(float32, float32);
-extern int is_float32_lt(float32, float32);
-extern int is_float32_gt(float32, float32);
-
-extern int is_float64_nan(float64);
-extern int is_float64_signan(float64);
-
-extern int is_float64_infinity(float64);
-extern int is_float64_zero(float64);
-
-extern int is_float64_eq(float64, float64);
-extern int is_float64_lt(float64, float64);
-extern int is_float64_gt(float64, float64);
-
-extern int is_float96_nan(float96);
-extern int is_float96_signan(float96);
-
-extern int is_float96_infinity(float96);
-extern int is_float96_zero(float96);
-
-extern int is_float96_eq(float96, float96);
-extern int is_float96_lt(float96, float96);
-extern int is_float96_gt(float96, float96);
-
-extern int is_float128_nan(float128);
-extern int is_float128_signan(float128);
-
-extern int is_float128_infinity(float128);
-extern int is_float128_zero(float128);
-
-extern int is_float128_eq(float128, float128);
-extern int is_float128_lt(float128, float128);
-extern int is_float128_gt(float128, float128);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/conversion.h
===================================================================
--- uspace/lib/softfloat/include/conversion.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,104 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Conversion of precision and conversion between integers and floats.
- */
-
-#ifndef __CONVERSION_H__
-#define __CONVERSION_H__
-
-extern float64 float32_to_float64(float32);
-extern float96 float32_to_float96(float32);
-extern float128 float32_to_float128(float32);
-extern float96 float64_to_float96(float64);
-extern float128 float64_to_float128(float64);
-extern float128 float96_to_float128(float96);
-
-extern float32 float64_to_float32(float64);
-extern float32 float96_to_float32(float96);
-extern float64 float96_to_float64(float96);
-extern float32 float128_to_float32(float128);
-extern float64 float128_to_float64(float128);
-extern float96 float128_to_float96(float128);
-
-extern uint32_t float32_to_uint32(float32);
-extern int32_t float32_to_int32(float32);
-
-extern uint64_t float32_to_uint64(float32);
-extern int64_t float32_to_int64(float32);
-
-extern uint32_t float64_to_uint32(float64);
-extern int32_t float64_to_int32(float64);
-
-extern uint64_t float64_to_uint64(float64);
-extern int64_t float64_to_int64(float64);
-
-extern uint32_t float96_to_uint32(float96);
-extern int32_t float96_to_int32(float96);
-
-extern uint64_t float96_to_uint64(float96);
-extern int64_t float96_to_int64(float96);
-
-extern uint32_t float128_to_uint32(float128);
-extern int32_t float128_to_int32(float128);
-
-extern uint64_t float128_to_uint64(float128);
-extern int64_t float128_to_int64(float128);
-
-extern float32 uint32_to_float32(uint32_t);
-extern float32 int32_to_float32(int32_t);
-
-extern float32 uint64_to_float32(uint64_t);
-extern float32 int64_to_float32(int64_t);
-
-extern float64 uint32_to_float64(uint32_t);
-extern float64 int32_to_float64(int32_t);
-
-extern float64 uint64_to_float64(uint64_t);
-extern float64 int64_to_float64(int64_t);
-
-extern float96 uint32_to_float96(uint32_t);
-extern float96 int32_to_float96(int32_t);
-
-extern float96 uint64_to_float96(uint64_t);
-extern float96 int64_to_float96(int64_t);
-
-extern float128 uint32_to_float128(uint32_t);
-extern float128 int32_to_float128(int32_t);
-
-extern float128 uint64_to_float128(uint64_t);
-extern float128 int64_to_float128(int64_t);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/div.h
===================================================================
--- uspace/lib/softfloat/include/div.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Division functions.
- */
-
-#ifndef __DIV_H__
-#define __DIV_H__
-
-extern float32 div_float32(float32, float32);
-extern float64 div_float64(float64, float64);
-extern float96 div_float96(float96, float96);
-extern float128 div_float128(float128, float128);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/mul.h
===================================================================
--- uspace/lib/softfloat/include/mul.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Multiplication functions.
- */
-
-#ifndef __MUL_H__
-#define __MUL_H__
-
-extern float32 mul_float32(float32, float32);
-extern float64 mul_float64(float64, float64);
-extern float96 mul_float96(float96, float96);
-extern float128 mul_float128(float128, float128);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/other.h
===================================================================
--- uspace/lib/softfloat/include/other.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,41 +1,0 @@
-/*
- * Copyright (c) 2005 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 softfloat
- * @{
- */
-/** @file Other functions (power, complex).
- */
-
-#ifndef __OTHER_H__
-#define __OTHER_H__
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/sftypes.h
===================================================================
--- uspace/lib/softfloat/include/sftypes.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,608 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Floating point types and constants.
- */
-
-#ifndef __SFTYPES_H__
-#define __SFTYPES_H__
-
-#include <byteorder.h>
-#include <stdint.h>
-
-/*
- * For recognizing NaNs or infinity use specialized comparison
- * functions, comparing with these constants is not sufficient.
- */
-
-#define FLOAT32_NAN     UINT32_C(0x7FC00001)
-#define FLOAT32_SIGNAN  UINT32_C(0x7F800001)
-#define FLOAT32_INF     UINT32_C(0x7F800000)
-
-#define FLOAT64_NAN     UINT64_C(0x7FF8000000000001)
-#define FLOAT64_SIGNAN  UINT64_C(0x7FF0000000000001)
-#define FLOAT64_INF     UINT64_C(0x7FF0000000000000)
-
-#define FLOAT96_NAN_HI     UINT64_C(0x7FFF80000000)
-#define FLOAT96_NAN_LO     UINT32_C(0x00010000)
-#define FLOAT96_SIGNAN_HI  UINT64_C(0x7FFF00000000)
-#define FLOAT96_SIGNAN_LO  UINT32_C(0x00010000)
-
-#define FLOAT128_NAN_HI     UINT64_C(0x7FFF800000000000)
-#define FLOAT128_NAN_LO     UINT64_C(0x0000000000000001)
-#define FLOAT128_SIGNAN_HI  UINT64_C(0x7FFF000000000000)
-#define FLOAT128_SIGNAN_LO  UINT64_C(0x0000000000000001)
-#define FLOAT128_INF_HI     UINT64_C(0x7FFF000000000000)
-#define FLOAT128_INF_LO     UINT64_C(0x0000000000000000)
-
-#define FLOAT32_FRACTION_SIZE   23
-#define FLOAT64_FRACTION_SIZE   52
-#define FLOAT96_FRACTION_SIZE   64
-#define FLOAT128_FRACTION_SIZE  112
-#define FLOAT128_FRAC_HI_SIZE   48
-#define FLOAT128_FRAC_LO_SIZE   64
-
-#define FLOAT32_HIDDEN_BIT_MASK      UINT32_C(0x800000)
-#define FLOAT64_HIDDEN_BIT_MASK      UINT64_C(0x10000000000000)
-#define FLOAT128_HIDDEN_BIT_MASK_HI  UINT64_C(0x1000000000000)
-#define FLOAT128_HIDDEN_BIT_MASK_LO  UINT64_C(0x0000000000000000)
-
-#define FLOAT32_MAX_EXPONENT   0xFF
-#define FLOAT64_MAX_EXPONENT   0x7FF
-#define FLOAT96_MAX_EXPONENT   0x7FFF
-#define FLOAT128_MAX_EXPONENT  0x7FFF
-
-#define FLOAT32_BIAS   0x7F
-#define FLOAT64_BIAS   0x3FF
-#define FLOAT96_BIAS   0x3FFF
-#define FLOAT128_BIAS  0x3FFF
-
-#if defined(__BE__)
-
-typedef union {
-	uint32_t bin;
-	
-	struct {
-		uint32_t sign : 1;
-		uint32_t exp : 8;
-		uint32_t fraction : 23;
-	} parts __attribute__((packed));
-} float32;
-
-typedef union {
-	uint64_t bin;
-	
-	struct {
-		uint64_t sign : 1;
-		uint64_t exp : 11;
-		uint64_t fraction : 52;
-	} parts __attribute__((packed));
-} float64;
-
-typedef union {
-	struct {
-		uint64_t hi;
-		uint32_t lo;
-	} bin __attribute__((packed));
-	
-	struct {
-		uint64_t padding : 16;
-		uint64_t sign : 1;
-		uint64_t exp : 15;
-		uint64_t fraction : 64;
-	} parts __attribute__((packed));
-} float96;
-
-typedef union {
-	struct {
-		uint64_t hi;
-		uint64_t lo;
-	} bin __attribute__((packed));
-	
-	struct {
-		uint64_t sign : 1;
-		uint64_t exp : 15;
-		uint64_t frac_hi : 48;
-		uint64_t frac_lo : 64;
-	} parts __attribute__((packed));
-} float128;
-
-#elif defined(__LE__)
-
-typedef union {
-	uint32_t bin;
-	
-	struct {
-		uint32_t fraction : 23;
-		uint32_t exp : 8;
-		uint32_t sign : 1;
-	} parts __attribute__((packed));
-} float32;
-
-typedef union {
-	uint64_t bin;
-	
-	struct {
-		uint64_t fraction : 52;
-		uint64_t exp : 11;
-		uint64_t sign : 1;
-	} parts __attribute__((packed));
-} float64;
-
-typedef union {
-	struct {
-		uint32_t lo;
-		uint64_t hi;
-	} bin __attribute__((packed));
-	
-	struct {
-		uint64_t fraction : 64;
-		uint64_t exp : 15;
-		uint64_t sign : 1;
-		uint64_t padding : 16;
-	} parts __attribute__((packed));
-} float96;
-
-typedef union {
-	struct {
-		uint64_t lo;
-		uint64_t hi;
-	} bin __attribute__((packed));
-	
-	struct {
-		uint64_t frac_lo : 64;
-		uint64_t frac_hi : 48;
-		uint64_t exp : 15;
-		uint64_t sign : 1;
-	} parts __attribute__((packed));
-} float128;
-
-#else
-	#error Unknown endianess
-#endif
-
-typedef union {
-	float val;
-	
-#if defined(FLOAT_SIZE_32)
-	float32 data;
-#elif defined(FLOAT_SIZE_64)
-	float64 data;
-#elif defined(FLOAT_SIZE_96)
-	float96 data;
-#elif defined(FLOAT_SIZE_128)
-	float128 data;
-#else
-	#error Unsupported float size
-#endif
-} float_t;
-
-typedef union {
-	double val;
-	
-#if defined(DOUBLE_SIZE_32)
-	float32 data;
-#elif defined(DOUBLE_SIZE_64)
-	float64 data;
-#elif defined(DOUBLE_SIZE_96)
-	float96 data;
-#elif defined(DOUBLE_SIZE_128)
-	float128 data;
-#else
-	#error Unsupported double size
-#endif
-} double_t;
-
-typedef union {
-	long double val;
-	
-#if defined(LONG_DOUBLE_SIZE_32)
-	float32 data;
-#elif defined(LONG_DOUBLE_SIZE_64)
-	float64 data;
-#elif defined(LONG_DOUBLE_SIZE_96)
-	float96 data;
-#elif defined(LONG_DOUBLE_SIZE_128)
-	float128 data;
-#else
-	#error Unsupported long double size
-#endif
-} long_double_t;
-
-
-#if defined(INT_SIZE_8)
-
-#define _to_int   _to_int8
-#define from_int  int8
-
-#elif defined(INT_SIZE_16)
-
-#define _to_int   _to_int16
-#define from_int  int16
-
-#elif defined(INT_SIZE_32)
-
-#define _to_int   _to_int32
-#define from_int  int32
-
-#elif defined(INT_SIZE_64)
-
-#define _to_int   _to_int64
-#define from_int  int64
-
-#endif
-
-
-#if defined(UINT_SIZE_8)
-
-#define _to_uint   _to_uint8
-#define from_uint  uint8
-
-#elif defined(UINT_SIZE_16)
-
-#define _to_uint   _to_uint16
-#define from_uint  uint16
-
-#elif defined(UINT_SIZE_32)
-
-#define _to_uint   _to_uint32
-#define from_uint  uint32
-
-#elif defined(UINT_SIZE_64)
-
-#define _to_uint   _to_uint64
-#define from_uint  uint64
-
-#endif
-
-
-#if defined(LONG_SIZE_8)
-
-#define _to_long   _to_int8
-#define from_long  int8
-
-#elif defined(LONG_SIZE_16)
-
-#define _to_long   _to_int16
-#define from_long  int16
-
-#elif defined(LONG_SIZE_32)
-
-#define _to_long   _to_int32
-#define from_long  int32
-
-#elif defined(LONG_SIZE_64)
-
-#define _to_long   _to_int64
-#define from_long  int64
-
-#endif
-
-
-#if defined(ULONG_SIZE_8)
-
-#define _to_ulong   _to_uint8
-#define from_ulong  uint8
-
-#elif defined(ULONG_SIZE_16)
-
-#define _to_ulong   _to_uint16
-#define from_ulong  uint16
-
-#elif defined(ULONG_SIZE_32)
-
-#define _to_ulong   _to_uint32
-#define from_ulong  uint32
-
-#elif defined(ULONG_SIZE_64)
-
-#define _to_ulong   _to_uint64
-#define from_ulong  uint64
-
-#endif
-
-
-#if defined(LLONG_SIZE_8)
-
-#define _to_llong   _to_int8
-#define from_llong  int8
-
-#elif defined(LLONG_SIZE_16)
-
-#define _to_llong   _to_int16
-#define from_llong  int16
-
-#elif defined(LLONG_SIZE_32)
-
-#define _to_llong   _to_int32
-#define from_llong  int32
-
-#elif defined(LLONG_SIZE_64)
-
-#define _to_llong   _to_int64
-#define from_llong  int64
-
-#endif
-
-
-#if defined(ULLONG_SIZE_8)
-
-#define _to_ullong   _to_uint8
-#define from_ullong  uint8
-
-#elif defined(ULLONG_SIZE_16)
-
-#define _to_ullong   _to_uint16
-#define from_ullong  uint16
-
-#elif defined(ULLONG_SIZE_32)
-
-#define _to_ullong   _to_uint32
-#define from_ullong  uint32
-
-#elif defined(ULLONG_SIZE_64)
-
-#define _to_ullong   _to_uint64
-#define from_ullong  uint64
-
-#endif
-
-
-#if defined(FLOAT_SIZE_32)
-
-#define add_float     add_float32
-#define sub_float     sub_float32
-#define mul_float     mul_float32
-#define div_float     div_float32
-#define _to_float     _to_float32
-#define from_float    float32
-#define is_float_nan  is_float32_nan
-#define is_float_eq   is_float32_eq
-#define is_float_lt   is_float32_lt
-#define is_float_gt   is_float32_gt
-
-#elif defined(FLOAT_SIZE_64)
-
-#define add_float     add_float64
-#define sub_float     sub_float64
-#define mul_float     mul_float64
-#define div_float     div_float64
-#define _to_float     _to_float64
-#define from_float    float64
-#define is_float_nan  is_float64_nan
-#define is_float_eq   is_float64_eq
-#define is_float_lt   is_float64_lt
-#define is_float_gt   is_float64_gt
-
-#elif defined(FLOAT_SIZE_96)
-
-#define add_float     add_float96
-#define sub_float     sub_float96
-#define mul_float     mul_float96
-#define div_float     div_float96
-#define _to_float     _to_float96
-#define from_float    float96
-#define is_float_nan  is_float96_nan
-#define is_float_eq   is_float96_eq
-#define is_float_lt   is_float96_lt
-#define is_float_gt   is_float96_gt
-
-#elif defined(FLOAT_SIZE_128)
-
-#define add_float     add_float128
-#define sub_float     sub_float128
-#define mul_float     mul_float128
-#define div_float     div_float128
-#define _to_float     _to_float128
-#define from_float    float128
-#define is_float_nan  is_float128_nan
-#define is_float_eq   is_float128_eq
-#define is_float_lt   is_float128_lt
-#define is_float_gt   is_float128_gt
-
-#endif
-
-
-#if defined(DOUBLE_SIZE_32)
-
-#define add_double     add_float32
-#define sub_double     sub_float32
-#define mul_double     mul_float32
-#define div_double     div_float32
-#define _to_double     _to_float32
-#define from_double    float32
-#define is_double_nan  is_float32_nan
-#define is_double_eq   is_float32_eq
-#define is_double_lt   is_float32_lt
-#define is_double_gt   is_float32_gt
-
-#elif defined(DOUBLE_SIZE_64)
-
-#define add_double     add_float64
-#define sub_double     sub_float64
-#define mul_double     mul_float64
-#define div_double     div_float64
-#define _to_double     _to_float64
-#define from_double    float64
-#define is_double_nan  is_float64_nan
-#define is_double_eq   is_float64_eq
-#define is_double_lt   is_float64_lt
-#define is_double_gt   is_float64_gt
-
-#elif defined(DOUBLE_SIZE_96)
-
-#define add_double     add_float96
-#define sub_double     sub_float96
-#define mul_double     mul_float96
-#define div_double     div_float96
-#define _to_double     _to_float96
-#define from_double    float96
-#define is_double_nan  is_float96_nan
-#define is_double_eq   is_float96_eq
-#define is_double_lt   is_float96_lt
-#define is_double_gt   is_float96_gt
-
-#elif defined(DOUBLE_SIZE_128)
-
-#define add_double     add_float128
-#define sub_double     sub_float128
-#define mul_double     mul_float128
-#define div_double     div_float128
-#define _to_double     _to_float128
-#define from_double    float128
-#define is_double_nan  is_float128_nan
-#define is_double_eq   is_float128_eq
-#define is_double_lt   is_float128_lt
-#define is_double_gt   is_float128_gt
-
-#endif
-
-
-#if defined(LONG_DOUBLE_SIZE_32)
-
-#define add_long_double     add_float32
-#define sub_long_double     sub_float32
-#define mul_long_double     mul_float32
-#define div_long_double     div_float32
-#define _to_long_double     _to_float32
-#define from_long_double    float32
-#define is_long_double_nan  is_float32_nan
-#define is_long_double_eq   is_float32_eq
-#define is_long_double_lt   is_float32_lt
-#define is_long_double_gt   is_float32_gt
-
-#elif defined(LONG_DOUBLE_SIZE_64)
-
-#define add_long_double     add_float64
-#define sub_long_double     sub_float64
-#define mul_long_double     mul_float64
-#define div_long_double     div_float64
-#define _to_long_double     _to_float64
-#define from_long_double    float64
-#define is_long_double_nan  is_float64_nan
-#define is_long_double_eq   is_float64_eq
-#define is_long_double_lt   is_float64_lt
-#define is_long_double_gt   is_float64_gt
-
-#elif defined(LONG_DOUBLE_SIZE_96)
-
-#define add_long_double     add_float96
-#define sub_long_double     sub_float96
-#define mul_long_double     mul_float96
-#define div_long_double     div_float96
-#define _to_long_double     _to_float96
-#define from_long_double    float96
-#define is_long_double_nan  is_float96_nan
-#define is_long_double_eq   is_float96_eq
-#define is_long_double_lt   is_float96_lt
-#define is_long_double_gt   is_float96_gt
-
-#elif defined(LONG_DOUBLE_SIZE_128)
-
-#define add_long_double     add_float128
-#define sub_long_double     sub_float128
-#define mul_long_double     mul_float128
-#define div_long_double     div_float128
-#define _to_long_double     _to_float128
-#define from_long_double    float128
-#define is_long_double_nan  is_float128_nan
-#define is_long_double_eq   is_float128_eq
-#define is_long_double_lt   is_float128_lt
-#define is_long_double_gt   is_float128_gt
-
-#endif
-
-
-#define CONCAT(a, b)       CONCAT_ARGS(a, b)
-#define CONCAT_ARGS(a, b)  a ## b
-
-#define float32_to_float32(arg)    (arg)
-#define float64_to_float64(arg)    (arg)
-#define float96_to_float96(arg)    (arg)
-#define float128_to_float128(arg)  (arg)
-
-#define float_to_double       CONCAT(from_float, _to_double)
-#define float_to_long_double  CONCAT(from_float, _to_long_double)
-#define float_to_int          CONCAT(from_float, _to_int)
-#define float_to_uint         CONCAT(from_float, _to_uint)
-#define float_to_long         CONCAT(from_float, _to_long)
-#define float_to_ulong        CONCAT(from_float, _to_ulong)
-#define float_to_llong        CONCAT(from_float, _to_llong)
-#define float_to_ullong       CONCAT(from_float, _to_ullong)
-
-#define double_to_float        CONCAT(from_double, _to_float)
-#define double_to_long_double  CONCAT(from_double, _to_long_double)
-#define double_to_int          CONCAT(from_double, _to_int)
-#define double_to_uint         CONCAT(from_double, _to_uint)
-#define double_to_long         CONCAT(from_double, _to_long)
-#define double_to_ulong        CONCAT(from_double, _to_ulong)
-#define double_to_llong        CONCAT(from_double, _to_llong)
-#define double_to_ullong       CONCAT(from_double, _to_ullong)
-
-#define long_double_to_float   CONCAT(from_long_double, _to_float)
-#define long_double_to_double  CONCAT(from_long_double, _to_double)
-#define long_double_to_int     CONCAT(from_long_double, _to_int)
-#define long_double_to_uint    CONCAT(from_long_double, _to_uint)
-#define long_double_to_long    CONCAT(from_long_double, _to_long)
-#define long_double_to_ulong   CONCAT(from_long_double, _to_ulong)
-#define long_double_to_llong   CONCAT(from_long_double, _to_llong)
-#define long_double_to_ullong  CONCAT(from_long_double, _to_ullong)
-
-#define int_to_float        CONCAT(from_int, _to_float)
-#define int_to_double       CONCAT(from_int, _to_double)
-#define int_to_long_double  CONCAT(from_int, _to_long_double)
-
-#define uint_to_float        CONCAT(from_uint, _to_float)
-#define uint_to_double       CONCAT(from_uint, _to_double)
-#define uint_to_long_double  CONCAT(from_uint, _to_long_double)
-
-#define long_to_float        CONCAT(from_long, _to_float)
-#define long_to_double       CONCAT(from_long, _to_double)
-#define long_to_long_double  CONCAT(from_long, _to_long_double)
-
-#define ulong_to_float        CONCAT(from_ulong, _to_float)
-#define ulong_to_double       CONCAT(from_ulong, _to_double)
-#define ulong_to_long_double  CONCAT(from_ulong, _to_long_double)
-
-#define llong_to_float        CONCAT(from_llong, _to_float)
-#define llong_to_double       CONCAT(from_llong, _to_double)
-#define llong_to_long_double  CONCAT(from_llong, _to_long_double)
-
-#define ullong_to_float        CONCAT(from_ullong, _to_float)
-#define ullong_to_double       CONCAT(from_ullong, _to_double)
-#define ullong_to_long_double  CONCAT(from_ullong, _to_long_double)
-
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/softfloat.h
===================================================================
--- uspace/lib/softfloat/include/softfloat.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,226 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Softfloat API.
- */
-
-#ifndef __SOFTFLOAT_H__
-#define __SOFTFLOAT_H__
-
-extern float __addsf3(float, float);
-extern double __adddf3(double, double);
-extern long double __addtf3(long double, long double);
-extern long double __addxf3(long double, long double);
-
-extern float __subsf3(float, float);
-extern double __subdf3(double, double);
-extern long double __subtf3(long double, long double);
-extern long double __subxf3(long double, long double);
-
-extern float __mulsf3(float, float);
-extern double __muldf3(double, double);
-extern long double __multf3(long double, long double);
-extern long double __mulxf3(long double, long double);
-
-extern float __divsf3(float, float);
-extern double __divdf3(double, double);
-extern long double __divtf3(long double, long double);
-extern long double __divxf3(long double, long double);
-
-extern float __negsf2(float);
-extern double __negdf2(double);
-extern long double __negtf2(long double);
-extern long double __negxf2(long double);
-
-extern double __extendsfdf2(float);
-extern long double __extendsftf2(float);
-extern long double __extendsfxf2(float);
-extern long double __extenddftf2(double);
-extern long double __extenddfxf2(double);
-
-extern double __truncxfdf2(long double);
-extern double __trunctfdf2(long double);
-extern float __truncxfsf2(long double);
-extern float __trunctfsf2(long double);
-extern float __truncdfsf2(double);
-
-extern int __fixsfsi(float);
-extern int __fixdfsi(double);
-extern int __fixtfsi(long double);
-extern int __fixxfsi(long double);
-
-extern long __fixsfdi(float);
-extern long __fixdfdi(double);
-extern long __fixtfdi(long double);
-extern long __fixxfdi(long double);
-
-extern long long __fixsfti(float);
-extern long long __fixdfti(double);
-extern long long __fixtfti(long double);
-extern long long __fixxfti(long double);
-
-extern unsigned int __fixunssfsi(float);
-extern unsigned int __fixunsdfsi(double);
-extern unsigned int __fixunstfsi(long double);
-extern unsigned int __fixunsxfsi(long double);
-
-extern unsigned long __fixunssfdi(float);
-extern unsigned long __fixunsdfdi(double);
-extern unsigned long __fixunstfdi(long double);
-extern unsigned long __fixunsxfdi(long double);
-
-extern unsigned long long __fixunssfti(float);
-extern unsigned long long __fixunsdfti(double);
-extern unsigned long long __fixunstfti(long double);
-extern unsigned long long __fixunsxfti(long double);
-
-extern float __floatsisf(int);
-extern double __floatsidf(int);
-extern long double __floatsitf(int);
-extern long double __floatsixf(int);
-
-extern float __floatdisf(long);
-extern double __floatdidf(long);
-extern long double __floatditf(long);
-extern long double __floatdixf(long);
-
-extern float __floattisf(long long);
-extern double __floattidf(long long);
-extern long double __floattitf(long long);
-extern long double __floattixf(long long);
-
-extern float __floatunsisf(unsigned int);
-extern double __floatunsidf(unsigned int);
-extern long double __floatunsitf(unsigned int);
-extern long double __floatunsixf(unsigned int);
-
-extern float __floatundisf(unsigned long);
-extern double __floatundidf(unsigned long);
-extern long double __floatunditf(unsigned long);
-extern long double __floatundixf(unsigned long);
-
-extern float __floatuntisf(unsigned long long);
-extern double __floatuntidf(unsigned long long);
-extern long double __floatuntitf(unsigned long long);
-extern long double __floatuntixf(unsigned long long);
-
-extern int __cmpsf2(float, float);
-extern int __cmpdf2(double, double);
-extern int __cmptf2(long double, long double);
-
-extern int __unordsf2(float, float);
-extern int __unorddf2(double, double);
-extern int __unordtf2(long double, long double);
-
-extern int __eqsf2(float, float);
-extern int __eqdf2(double, double);
-extern int __eqtf2(long double, long double);
-
-extern int __nesf2(float, float);
-extern int __nedf2(double, double);
-extern int __netf2(long double, long double);
-
-extern int __gesf2(float, float);
-extern int __gedf2(double, double);
-extern int __getf2(long double, long double);
-
-extern int __ltsf2(float, float);
-extern int __ltdf2(double, double);
-extern int __lttf2(long double, long double);
-
-extern int __lesf2(float, float);
-extern int __ledf2(double, double);
-extern int __letf2(long double, long double);
-
-extern int __gtsf2(float, float);
-extern int __gtdf2(double, double);
-extern int __gttf2(long double, long double);
-
-/* Not implemented yet */
-extern float __powisf2(float, int);
-extern double __powidf2 (double, int);
-extern long double __powitf2(long double, int);
-extern long double __powixf2(long double, int);
-
-/* SPARC quadruple-precision wrappers */
-extern void _Qp_add(long double *, long double *, long double *);
-extern void _Qp_sub(long double *, long double *, long double *);
-extern void _Qp_mul(long double *, long double *, long double *);
-extern void _Qp_div(long double *, long double *, long double *);
-extern void _Qp_neg(long double *, long double *);
-
-extern void _Qp_stoq(long double *, float);
-extern void _Qp_dtoq(long double *, double);
-extern float _Qp_qtos(long double *);
-extern double _Qp_qtod(long double *);
-
-extern int _Qp_qtoi(long double *);
-extern unsigned int _Qp_qtoui(long double *);
-extern long _Qp_qtox(long double *);
-extern unsigned long _Qp_qtoux(long double *);
-
-extern void _Qp_itoq(long double *, int);
-extern void _Qp_uitoq(long double *, unsigned int);
-extern void _Qp_xtoq(long double *, long);
-extern void _Qp_uxtoq(long double *, unsigned long);
-
-extern int _Qp_cmp(long double *, long double *);
-extern int _Qp_cmpe(long double *, long double *);
-extern int _Qp_feq(long double *, long double *);
-extern int _Qp_fge(long double *, long double *);
-extern int _Qp_fgt(long double *, long double *);
-extern int _Qp_fle(long double*, long double *);
-extern int _Qp_flt(long double *, long double *);
-extern int _Qp_fne(long double *, long double *);
-
-/* ARM EABI */
-extern double __aeabi_i2d(int);
-extern double __aeabi_ui2d(unsigned int);
-extern unsigned int __aeabi_d2uiz(double);
-extern int __aeabi_d2iz(double);
-
-extern int __aeabi_dcmpge(double, double);
-extern int __aeabi_dcmpgt(double, double);
-extern int __aeabi_dcmplt(double, double);
-
-extern double __aeabi_dadd(double, double);
-extern double __aeabi_dsub(double, double);
-extern double __aeabi_dmul(double, double);
-extern double __aeabi_ddiv(double, double);
-
-/* Not implemented yet */
-extern void _Qp_sqrt(long double *, long double *);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/sub.h
===================================================================
--- uspace/lib/softfloat/include/sub.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Substraction functions.
- */
-
-#ifndef __SUB_H__
-#define __SUB_H__
-
-extern float32 sub_float32(float32, float32);
-extern float64 sub_float64(float64, float64);
-extern float96 sub_float96(float96, float96);
-extern float128 sub_float128(float128, float128);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/softfloat/mul.c
===================================================================
--- uspace/lib/softfloat/mul.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/mul.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Multiplication functions.
+ */
+
+#include "sftypes.h"
+#include "mul.h"
+#include "comparison.h"
+#include "common.h"
+
+/** Multiply two single-precision floats.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ *
+ * @return Result of multiplication.
+ *
+ */
+float32 mul_float32(float32 a, float32 b)
+{
+	float32 result;
+	uint64_t frac1, frac2;
+	int32_t exp;
+	
+	result.parts.sign = a.parts.sign ^ b.parts.sign;
+	
+	if (is_float32_nan(a) || is_float32_nan(b)) {
+		/* TODO: fix SigNaNs */
+		if (is_float32_signan(a)) {
+			result.parts.fraction = a.parts.fraction;
+			result.parts.exp = a.parts.exp;
+			return result;
+		}
+		if (is_float32_signan(b)) { /* TODO: fix SigNaN */
+			result.parts.fraction = b.parts.fraction;
+			result.parts.exp = b.parts.exp;
+			return result;
+		}
+		/* set NaN as result */
+		result.bin = FLOAT32_NAN;
+		return result;
+	}
+	
+	if (is_float32_infinity(a)) {
+		if (is_float32_zero(b)) {
+			/* FIXME: zero * infinity */
+			result.bin = FLOAT32_NAN;
+			return result;
+		}
+		result.parts.fraction = a.parts.fraction;
+		result.parts.exp = a.parts.exp;
+		return result;
+	}
+	
+	if (is_float32_infinity(b)) {
+		if (is_float32_zero(a)) {
+			/* FIXME: zero * infinity */
+			result.bin = FLOAT32_NAN;
+			return result;
+		}
+		result.parts.fraction = b.parts.fraction;
+		result.parts.exp = b.parts.exp;
+		return result;
+	}
+	
+	/* exp is signed so we can easy detect underflow */
+	exp = a.parts.exp + b.parts.exp;
+	exp -= FLOAT32_BIAS;
+	
+	if (exp >= FLOAT32_MAX_EXPONENT) {
+		/* FIXME: overflow */
+		/* set infinity as result */
+		result.bin = FLOAT32_INF;
+		result.parts.sign = a.parts.sign ^ b.parts.sign;
+		return result;
+	}
+	
+	if (exp < 0) { 
+		/* FIXME: underflow */
+		/* return signed zero */
+		result.parts.fraction = 0x0;
+		result.parts.exp = 0x0;
+		return result;
+	}
+	
+	frac1 = a.parts.fraction;
+	if (a.parts.exp > 0) {
+		frac1 |= FLOAT32_HIDDEN_BIT_MASK;
+	} else {
+		++exp;
+	}
+	
+	frac2 = b.parts.fraction;
+	
+	if (b.parts.exp > 0) {
+		frac2 |= FLOAT32_HIDDEN_BIT_MASK;
+	} else {
+		++exp;
+	}
+	
+	frac1 <<= 1; /* one bit space for rounding */
+	
+	frac1 = frac1 * frac2;
+	
+	/* round and return */
+	while ((exp < FLOAT32_MAX_EXPONENT) &&
+	    (frac1 >= (1 << (FLOAT32_FRACTION_SIZE + 2)))) {
+		/* 23 bits of fraction + one more for hidden bit (all shifted 1 bit left) */
+		++exp;
+		frac1 >>= 1;
+	}
+	
+	/* rounding */
+	/* ++frac1; FIXME: not works - without it is ok */
+	frac1 >>= 1; /* shift off rounding space */
+	
+	if ((exp < FLOAT32_MAX_EXPONENT) &&
+	    (frac1 >= (1 << (FLOAT32_FRACTION_SIZE + 1)))) {
+		++exp;
+		frac1 >>= 1;
+	}
+	
+	if (exp >= FLOAT32_MAX_EXPONENT) {
+		/* TODO: fix overflow */
+		/* return infinity*/
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		result.parts.fraction = 0x0;
+		return result;
+	}
+	
+	exp -= FLOAT32_FRACTION_SIZE;
+	
+	if (exp <= FLOAT32_FRACTION_SIZE) {
+		/* denormalized number */
+		frac1 >>= 1; /* denormalize */
+		while ((frac1 > 0) && (exp < 0)) {
+			frac1 >>= 1;
+			++exp;
+		}
+		if (frac1 == 0) {
+			/* FIXME : underflow */
+			result.parts.exp = 0;
+			result.parts.fraction = 0;
+			return result;
+		}
+	}
+	result.parts.exp = exp; 
+	result.parts.fraction = frac1 & ((1 << FLOAT32_FRACTION_SIZE) - 1);
+	
+	return result;
+}
+
+/** Multiply two double-precision floats.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ *
+ * @return Result of multiplication.
+ *
+ */
+float64 mul_float64(float64 a, float64 b)
+{
+	float64 result;
+	uint64_t frac1, frac2;
+	int32_t exp;
+	
+	result.parts.sign = a.parts.sign ^ b.parts.sign;
+	
+	if (is_float64_nan(a) || is_float64_nan(b)) {
+		/* TODO: fix SigNaNs */
+		if (is_float64_signan(a)) {
+			result.parts.fraction = a.parts.fraction;
+			result.parts.exp = a.parts.exp;
+			return result;
+		}
+		if (is_float64_signan(b)) { /* TODO: fix SigNaN */
+			result.parts.fraction = b.parts.fraction;
+			result.parts.exp = b.parts.exp;
+			return result;
+		}
+		/* set NaN as result */
+		result.bin = FLOAT64_NAN;
+		return result;
+	}
+	
+	if (is_float64_infinity(a)) {
+		if (is_float64_zero(b)) {
+			/* FIXME: zero * infinity */
+			result.bin = FLOAT64_NAN;
+			return result;
+		}
+		result.parts.fraction = a.parts.fraction;
+		result.parts.exp = a.parts.exp;
+		return result;
+	}
+	
+	if (is_float64_infinity(b)) {
+		if (is_float64_zero(a)) {
+			/* FIXME: zero * infinity */
+			result.bin = FLOAT64_NAN;
+			return result;
+		}
+		result.parts.fraction = b.parts.fraction;
+		result.parts.exp = b.parts.exp;
+		return result;
+	}
+	
+	/* exp is signed so we can easy detect underflow */
+	exp = a.parts.exp + b.parts.exp - FLOAT64_BIAS;
+	
+	frac1 = a.parts.fraction;
+	
+	if (a.parts.exp > 0) {
+		frac1 |= FLOAT64_HIDDEN_BIT_MASK;
+	} else {
+		++exp;
+	}
+	
+	frac2 = b.parts.fraction;
+	
+	if (b.parts.exp > 0) {
+		frac2 |= FLOAT64_HIDDEN_BIT_MASK;
+	} else {
+		++exp;
+	}
+	
+	frac1 <<= (64 - FLOAT64_FRACTION_SIZE - 1);
+	frac2 <<= (64 - FLOAT64_FRACTION_SIZE - 2);
+	
+	mul64(frac1, frac2, &frac1, &frac2);
+	
+	frac1 |= (frac2 != 0);
+	if (frac1 & (0x1ll << 62)) {
+		frac1 <<= 1;
+		exp--;
+	}
+	
+	result = finish_float64(exp, frac1, result.parts.sign);
+	return result;
+}
+
+/** Multiply two quadruple-precision floats.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ *
+ * @return Result of multiplication.
+ *
+ */
+float128 mul_float128(float128 a, float128 b)
+{
+	float128 result;
+	uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
+	int32_t exp;
+	
+	result.parts.sign = a.parts.sign ^ b.parts.sign;
+	
+	if (is_float128_nan(a) || is_float128_nan(b)) {
+		/* TODO: fix SigNaNs */
+		if (is_float128_signan(a)) {
+			result.parts.frac_hi = a.parts.frac_hi;
+			result.parts.frac_lo = a.parts.frac_lo;
+			result.parts.exp = a.parts.exp;
+			return result;
+		}
+		if (is_float128_signan(b)) { /* TODO: fix SigNaN */
+			result.parts.frac_hi = b.parts.frac_hi;
+			result.parts.frac_lo = b.parts.frac_lo;
+			result.parts.exp = b.parts.exp;
+			return result;
+		}
+		/* set NaN as result */
+		result.bin.hi = FLOAT128_NAN_HI;
+		result.bin.lo = FLOAT128_NAN_LO;
+		return result;
+	}
+	
+	if (is_float128_infinity(a)) {
+		if (is_float128_zero(b)) {
+			/* FIXME: zero * infinity */
+			result.bin.hi = FLOAT128_NAN_HI;
+			result.bin.lo = FLOAT128_NAN_LO;
+			return result;
+		}
+		result.parts.frac_hi = a.parts.frac_hi;
+		result.parts.frac_lo = a.parts.frac_lo;
+		result.parts.exp = a.parts.exp;
+		return result;
+	}
+	
+	if (is_float128_infinity(b)) {
+		if (is_float128_zero(a)) {
+			/* FIXME: zero * infinity */
+			result.bin.hi = FLOAT128_NAN_HI;
+			result.bin.lo = FLOAT128_NAN_LO;
+			return result;
+		}
+		result.parts.frac_hi = b.parts.frac_hi;
+		result.parts.frac_lo = b.parts.frac_lo;
+		result.parts.exp = b.parts.exp;
+		return result;
+	}
+	
+	/* exp is signed so we can easy detect underflow */
+	exp = a.parts.exp + b.parts.exp - FLOAT128_BIAS - 1;
+	
+	frac1_hi = a.parts.frac_hi;
+	frac1_lo = a.parts.frac_lo;
+	
+	if (a.parts.exp > 0) {
+		or128(frac1_hi, frac1_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &frac1_hi, &frac1_lo);
+	} else {
+		++exp;
+	}
+	
+	frac2_hi = b.parts.frac_hi;
+	frac2_lo = b.parts.frac_lo;
+	
+	if (b.parts.exp > 0) {
+		or128(frac2_hi, frac2_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &frac2_hi, &frac2_lo);
+	} else {
+		++exp;
+	}
+	
+	lshift128(frac2_hi, frac2_lo,
+	    128 - FLOAT128_FRACTION_SIZE, &frac2_hi, &frac2_lo);
+	
+	tmp_hi = frac1_hi;
+	tmp_lo = frac1_lo;
+	mul128(frac1_hi, frac1_lo, frac2_hi, frac2_lo,
+	    &frac1_hi, &frac1_lo, &frac2_hi, &frac2_lo);
+	add128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &frac1_hi, &frac1_lo);
+	frac2_hi |= (frac2_lo != 0x0ll);
+	
+	if ((FLOAT128_HIDDEN_BIT_MASK_HI << 1) <= frac1_hi) {
+		frac2_hi >>= 1;
+		if (frac1_lo & 0x1ll) {
+			frac2_hi |= (0x1ull < 64);
+		}
+		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
+		++exp;
+	}
+	
+	result = finish_float128(exp, frac1_hi, frac1_lo, result.parts.sign, frac2_hi);
+	return result;
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/mul.h
===================================================================
--- uspace/lib/softfloat/mul.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/mul.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Multiplication functions.
+ */
+
+#ifndef __MUL_H__
+#define __MUL_H__
+
+extern float32 mul_float32(float32, float32);
+extern float64 mul_float64(float64, float64);
+extern float96 mul_float96(float96, float96);
+extern float128 mul_float128(float128, float128);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/other.c
===================================================================
--- uspace/lib/softfloat/other.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/other.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005 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 softfloat
+ * @{
+ */
+/** @file Other functions (power, complex).
+ */
+
+
+/** @}
+ */
Index: uspace/lib/softfloat/other.h
===================================================================
--- uspace/lib/softfloat/other.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/other.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2005 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 softfloat
+ * @{
+ */
+/** @file Other functions (power, complex).
+ */
+
+#ifndef __OTHER_H__
+#define __OTHER_H__
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/sftypes.h
===================================================================
--- uspace/lib/softfloat/sftypes.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/sftypes.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Floating point types and constants.
+ */
+
+#ifndef __SFTYPES_H__
+#define __SFTYPES_H__
+
+#include <byteorder.h>
+#include <stdint.h>
+
+/*
+ * For recognizing NaNs or infinity use specialized comparison
+ * functions, comparing with these constants is not sufficient.
+ */
+
+#define FLOAT32_NAN     UINT32_C(0x7FC00001)
+#define FLOAT32_SIGNAN  UINT32_C(0x7F800001)
+#define FLOAT32_INF     UINT32_C(0x7F800000)
+
+#define FLOAT64_NAN     UINT64_C(0x7FF8000000000001)
+#define FLOAT64_SIGNAN  UINT64_C(0x7FF0000000000001)
+#define FLOAT64_INF     UINT64_C(0x7FF0000000000000)
+
+#define FLOAT96_NAN_HI     UINT64_C(0x7FFF80000000)
+#define FLOAT96_NAN_LO     UINT32_C(0x00010000)
+#define FLOAT96_SIGNAN_HI  UINT64_C(0x7FFF00000000)
+#define FLOAT96_SIGNAN_LO  UINT32_C(0x00010000)
+
+#define FLOAT128_NAN_HI     UINT64_C(0x7FFF800000000000)
+#define FLOAT128_NAN_LO     UINT64_C(0x0000000000000001)
+#define FLOAT128_SIGNAN_HI  UINT64_C(0x7FFF000000000000)
+#define FLOAT128_SIGNAN_LO  UINT64_C(0x0000000000000001)
+#define FLOAT128_INF_HI     UINT64_C(0x7FFF000000000000)
+#define FLOAT128_INF_LO     UINT64_C(0x0000000000000000)
+
+#define FLOAT32_FRACTION_SIZE   23
+#define FLOAT64_FRACTION_SIZE   52
+#define FLOAT96_FRACTION_SIZE   64
+#define FLOAT128_FRACTION_SIZE  112
+#define FLOAT128_FRAC_HI_SIZE   48
+#define FLOAT128_FRAC_LO_SIZE   64
+
+#define FLOAT32_HIDDEN_BIT_MASK      UINT32_C(0x800000)
+#define FLOAT64_HIDDEN_BIT_MASK      UINT64_C(0x10000000000000)
+#define FLOAT128_HIDDEN_BIT_MASK_HI  UINT64_C(0x1000000000000)
+#define FLOAT128_HIDDEN_BIT_MASK_LO  UINT64_C(0x0000000000000000)
+
+#define FLOAT32_MAX_EXPONENT   0xFF
+#define FLOAT64_MAX_EXPONENT   0x7FF
+#define FLOAT96_MAX_EXPONENT   0x7FFF
+#define FLOAT128_MAX_EXPONENT  0x7FFF
+
+#define FLOAT32_BIAS   0x7F
+#define FLOAT64_BIAS   0x3FF
+#define FLOAT96_BIAS   0x3FFF
+#define FLOAT128_BIAS  0x3FFF
+
+#if defined(__BE__)
+
+typedef union {
+	uint32_t bin;
+	
+	struct {
+		uint32_t sign : 1;
+		uint32_t exp : 8;
+		uint32_t fraction : 23;
+	} parts __attribute__((packed));
+} float32;
+
+typedef union {
+	uint64_t bin;
+	
+	struct {
+		uint64_t sign : 1;
+		uint64_t exp : 11;
+		uint64_t fraction : 52;
+	} parts __attribute__((packed));
+} float64;
+
+typedef union {
+	struct {
+		uint64_t hi;
+		uint32_t lo;
+	} bin __attribute__((packed));
+	
+	struct {
+		uint64_t padding : 16;
+		uint64_t sign : 1;
+		uint64_t exp : 15;
+		uint64_t fraction : 64;
+	} parts __attribute__((packed));
+} float96;
+
+typedef union {
+	struct {
+		uint64_t hi;
+		uint64_t lo;
+	} bin __attribute__((packed));
+	
+	struct {
+		uint64_t sign : 1;
+		uint64_t exp : 15;
+		uint64_t frac_hi : 48;
+		uint64_t frac_lo : 64;
+	} parts __attribute__((packed));
+} float128;
+
+#elif defined(__LE__)
+
+typedef union {
+	uint32_t bin;
+	
+	struct {
+		uint32_t fraction : 23;
+		uint32_t exp : 8;
+		uint32_t sign : 1;
+	} parts __attribute__((packed));
+} float32;
+
+typedef union {
+	uint64_t bin;
+	
+	struct {
+		uint64_t fraction : 52;
+		uint64_t exp : 11;
+		uint64_t sign : 1;
+	} parts __attribute__((packed));
+} float64;
+
+typedef union {
+	struct {
+		uint32_t lo;
+		uint64_t hi;
+	} bin __attribute__((packed));
+	
+	struct {
+		uint64_t fraction : 64;
+		uint64_t exp : 15;
+		uint64_t sign : 1;
+		uint64_t padding : 16;
+	} parts __attribute__((packed));
+} float96;
+
+typedef union {
+	struct {
+		uint64_t lo;
+		uint64_t hi;
+	} bin __attribute__((packed));
+	
+	struct {
+		uint64_t frac_lo : 64;
+		uint64_t frac_hi : 48;
+		uint64_t exp : 15;
+		uint64_t sign : 1;
+	} parts __attribute__((packed));
+} float128;
+
+#else
+	#error Unknown endianess
+#endif
+
+typedef union {
+	float val;
+	
+#if defined(FLOAT_SIZE_32)
+	float32 data;
+#elif defined(FLOAT_SIZE_64)
+	float64 data;
+#elif defined(FLOAT_SIZE_96)
+	float96 data;
+#elif defined(FLOAT_SIZE_128)
+	float128 data;
+#else
+	#error Unsupported float size
+#endif
+} float_t;
+
+typedef union {
+	double val;
+	
+#if defined(DOUBLE_SIZE_32)
+	float32 data;
+#elif defined(DOUBLE_SIZE_64)
+	float64 data;
+#elif defined(DOUBLE_SIZE_96)
+	float96 data;
+#elif defined(DOUBLE_SIZE_128)
+	float128 data;
+#else
+	#error Unsupported double size
+#endif
+} double_t;
+
+typedef union {
+	long double val;
+	
+#if defined(LONG_DOUBLE_SIZE_32)
+	float32 data;
+#elif defined(LONG_DOUBLE_SIZE_64)
+	float64 data;
+#elif defined(LONG_DOUBLE_SIZE_96)
+	float96 data;
+#elif defined(LONG_DOUBLE_SIZE_128)
+	float128 data;
+#else
+	#error Unsupported long double size
+#endif
+} long_double_t;
+
+
+#if defined(INT_SIZE_8)
+
+#define _to_int   _to_int8
+#define from_int  int8
+
+#elif defined(INT_SIZE_16)
+
+#define _to_int   _to_int16
+#define from_int  int16
+
+#elif defined(INT_SIZE_32)
+
+#define _to_int   _to_int32
+#define from_int  int32
+
+#elif defined(INT_SIZE_64)
+
+#define _to_int   _to_int64
+#define from_int  int64
+
+#endif
+
+
+#if defined(UINT_SIZE_8)
+
+#define _to_uint   _to_uint8
+#define from_uint  uint8
+
+#elif defined(UINT_SIZE_16)
+
+#define _to_uint   _to_uint16
+#define from_uint  uint16
+
+#elif defined(UINT_SIZE_32)
+
+#define _to_uint   _to_uint32
+#define from_uint  uint32
+
+#elif defined(UINT_SIZE_64)
+
+#define _to_uint   _to_uint64
+#define from_uint  uint64
+
+#endif
+
+
+#if defined(LONG_SIZE_8)
+
+#define _to_long   _to_int8
+#define from_long  int8
+
+#elif defined(LONG_SIZE_16)
+
+#define _to_long   _to_int16
+#define from_long  int16
+
+#elif defined(LONG_SIZE_32)
+
+#define _to_long   _to_int32
+#define from_long  int32
+
+#elif defined(LONG_SIZE_64)
+
+#define _to_long   _to_int64
+#define from_long  int64
+
+#endif
+
+
+#if defined(ULONG_SIZE_8)
+
+#define _to_ulong   _to_uint8
+#define from_ulong  uint8
+
+#elif defined(ULONG_SIZE_16)
+
+#define _to_ulong   _to_uint16
+#define from_ulong  uint16
+
+#elif defined(ULONG_SIZE_32)
+
+#define _to_ulong   _to_uint32
+#define from_ulong  uint32
+
+#elif defined(ULONG_SIZE_64)
+
+#define _to_ulong   _to_uint64
+#define from_ulong  uint64
+
+#endif
+
+
+#if defined(LLONG_SIZE_8)
+
+#define _to_llong   _to_int8
+#define from_llong  int8
+
+#elif defined(LLONG_SIZE_16)
+
+#define _to_llong   _to_int16
+#define from_llong  int16
+
+#elif defined(LLONG_SIZE_32)
+
+#define _to_llong   _to_int32
+#define from_llong  int32
+
+#elif defined(LLONG_SIZE_64)
+
+#define _to_llong   _to_int64
+#define from_llong  int64
+
+#endif
+
+
+#if defined(ULLONG_SIZE_8)
+
+#define _to_ullong   _to_uint8
+#define from_ullong  uint8
+
+#elif defined(ULLONG_SIZE_16)
+
+#define _to_ullong   _to_uint16
+#define from_ullong  uint16
+
+#elif defined(ULLONG_SIZE_32)
+
+#define _to_ullong   _to_uint32
+#define from_ullong  uint32
+
+#elif defined(ULLONG_SIZE_64)
+
+#define _to_ullong   _to_uint64
+#define from_ullong  uint64
+
+#endif
+
+
+#if defined(FLOAT_SIZE_32)
+
+#define add_float     add_float32
+#define sub_float     sub_float32
+#define mul_float     mul_float32
+#define div_float     div_float32
+#define _to_float     _to_float32
+#define from_float    float32
+#define is_float_nan  is_float32_nan
+#define is_float_eq   is_float32_eq
+#define is_float_lt   is_float32_lt
+#define is_float_gt   is_float32_gt
+
+#elif defined(FLOAT_SIZE_64)
+
+#define add_float     add_float64
+#define sub_float     sub_float64
+#define mul_float     mul_float64
+#define div_float     div_float64
+#define _to_float     _to_float64
+#define from_float    float64
+#define is_float_nan  is_float64_nan
+#define is_float_eq   is_float64_eq
+#define is_float_lt   is_float64_lt
+#define is_float_gt   is_float64_gt
+
+#elif defined(FLOAT_SIZE_96)
+
+#define add_float     add_float96
+#define sub_float     sub_float96
+#define mul_float     mul_float96
+#define div_float     div_float96
+#define _to_float     _to_float96
+#define from_float    float96
+#define is_float_nan  is_float96_nan
+#define is_float_eq   is_float96_eq
+#define is_float_lt   is_float96_lt
+#define is_float_gt   is_float96_gt
+
+#elif defined(FLOAT_SIZE_128)
+
+#define add_float     add_float128
+#define sub_float     sub_float128
+#define mul_float     mul_float128
+#define div_float     div_float128
+#define _to_float     _to_float128
+#define from_float    float128
+#define is_float_nan  is_float128_nan
+#define is_float_eq   is_float128_eq
+#define is_float_lt   is_float128_lt
+#define is_float_gt   is_float128_gt
+
+#endif
+
+
+#if defined(DOUBLE_SIZE_32)
+
+#define add_double     add_float32
+#define sub_double     sub_float32
+#define mul_double     mul_float32
+#define div_double     div_float32
+#define _to_double     _to_float32
+#define from_double    float32
+#define is_double_nan  is_float32_nan
+#define is_double_eq   is_float32_eq
+#define is_double_lt   is_float32_lt
+#define is_double_gt   is_float32_gt
+
+#elif defined(DOUBLE_SIZE_64)
+
+#define add_double     add_float64
+#define sub_double     sub_float64
+#define mul_double     mul_float64
+#define div_double     div_float64
+#define _to_double     _to_float64
+#define from_double    float64
+#define is_double_nan  is_float64_nan
+#define is_double_eq   is_float64_eq
+#define is_double_lt   is_float64_lt
+#define is_double_gt   is_float64_gt
+
+#elif defined(DOUBLE_SIZE_96)
+
+#define add_double     add_float96
+#define sub_double     sub_float96
+#define mul_double     mul_float96
+#define div_double     div_float96
+#define _to_double     _to_float96
+#define from_double    float96
+#define is_double_nan  is_float96_nan
+#define is_double_eq   is_float96_eq
+#define is_double_lt   is_float96_lt
+#define is_double_gt   is_float96_gt
+
+#elif defined(DOUBLE_SIZE_128)
+
+#define add_double     add_float128
+#define sub_double     sub_float128
+#define mul_double     mul_float128
+#define div_double     div_float128
+#define _to_double     _to_float128
+#define from_double    float128
+#define is_double_nan  is_float128_nan
+#define is_double_eq   is_float128_eq
+#define is_double_lt   is_float128_lt
+#define is_double_gt   is_float128_gt
+
+#endif
+
+
+#if defined(LONG_DOUBLE_SIZE_32)
+
+#define add_long_double     add_float32
+#define sub_long_double     sub_float32
+#define mul_long_double     mul_float32
+#define div_long_double     div_float32
+#define _to_long_double     _to_float32
+#define from_long_double    float32
+#define is_long_double_nan  is_float32_nan
+#define is_long_double_eq   is_float32_eq
+#define is_long_double_lt   is_float32_lt
+#define is_long_double_gt   is_float32_gt
+
+#elif defined(LONG_DOUBLE_SIZE_64)
+
+#define add_long_double     add_float64
+#define sub_long_double     sub_float64
+#define mul_long_double     mul_float64
+#define div_long_double     div_float64
+#define _to_long_double     _to_float64
+#define from_long_double    float64
+#define is_long_double_nan  is_float64_nan
+#define is_long_double_eq   is_float64_eq
+#define is_long_double_lt   is_float64_lt
+#define is_long_double_gt   is_float64_gt
+
+#elif defined(LONG_DOUBLE_SIZE_96)
+
+#define add_long_double     add_float96
+#define sub_long_double     sub_float96
+#define mul_long_double     mul_float96
+#define div_long_double     div_float96
+#define _to_long_double     _to_float96
+#define from_long_double    float96
+#define is_long_double_nan  is_float96_nan
+#define is_long_double_eq   is_float96_eq
+#define is_long_double_lt   is_float96_lt
+#define is_long_double_gt   is_float96_gt
+
+#elif defined(LONG_DOUBLE_SIZE_128)
+
+#define add_long_double     add_float128
+#define sub_long_double     sub_float128
+#define mul_long_double     mul_float128
+#define div_long_double     div_float128
+#define _to_long_double     _to_float128
+#define from_long_double    float128
+#define is_long_double_nan  is_float128_nan
+#define is_long_double_eq   is_float128_eq
+#define is_long_double_lt   is_float128_lt
+#define is_long_double_gt   is_float128_gt
+
+#endif
+
+
+#define CONCAT(a, b)       CONCAT_ARGS(a, b)
+#define CONCAT_ARGS(a, b)  a ## b
+
+#define float32_to_float32(arg)    (arg)
+#define float64_to_float64(arg)    (arg)
+#define float96_to_float96(arg)    (arg)
+#define float128_to_float128(arg)  (arg)
+
+#define float_to_double       CONCAT(from_float, _to_double)
+#define float_to_long_double  CONCAT(from_float, _to_long_double)
+#define float_to_int          CONCAT(from_float, _to_int)
+#define float_to_uint         CONCAT(from_float, _to_uint)
+#define float_to_long         CONCAT(from_float, _to_long)
+#define float_to_ulong        CONCAT(from_float, _to_ulong)
+#define float_to_llong        CONCAT(from_float, _to_llong)
+#define float_to_ullong       CONCAT(from_float, _to_ullong)
+
+#define double_to_float        CONCAT(from_double, _to_float)
+#define double_to_long_double  CONCAT(from_double, _to_long_double)
+#define double_to_int          CONCAT(from_double, _to_int)
+#define double_to_uint         CONCAT(from_double, _to_uint)
+#define double_to_long         CONCAT(from_double, _to_long)
+#define double_to_ulong        CONCAT(from_double, _to_ulong)
+#define double_to_llong        CONCAT(from_double, _to_llong)
+#define double_to_ullong       CONCAT(from_double, _to_ullong)
+
+#define long_double_to_float   CONCAT(from_long_double, _to_float)
+#define long_double_to_double  CONCAT(from_long_double, _to_double)
+#define long_double_to_int     CONCAT(from_long_double, _to_int)
+#define long_double_to_uint    CONCAT(from_long_double, _to_uint)
+#define long_double_to_long    CONCAT(from_long_double, _to_long)
+#define long_double_to_ulong   CONCAT(from_long_double, _to_ulong)
+#define long_double_to_llong   CONCAT(from_long_double, _to_llong)
+#define long_double_to_ullong  CONCAT(from_long_double, _to_ullong)
+
+#define int_to_float        CONCAT(from_int, _to_float)
+#define int_to_double       CONCAT(from_int, _to_double)
+#define int_to_long_double  CONCAT(from_int, _to_long_double)
+
+#define uint_to_float        CONCAT(from_uint, _to_float)
+#define uint_to_double       CONCAT(from_uint, _to_double)
+#define uint_to_long_double  CONCAT(from_uint, _to_long_double)
+
+#define long_to_float        CONCAT(from_long, _to_float)
+#define long_to_double       CONCAT(from_long, _to_double)
+#define long_to_long_double  CONCAT(from_long, _to_long_double)
+
+#define ulong_to_float        CONCAT(from_ulong, _to_float)
+#define ulong_to_double       CONCAT(from_ulong, _to_double)
+#define ulong_to_long_double  CONCAT(from_ulong, _to_long_double)
+
+#define llong_to_float        CONCAT(from_llong, _to_float)
+#define llong_to_double       CONCAT(from_llong, _to_double)
+#define llong_to_long_double  CONCAT(from_llong, _to_long_double)
+
+#define ullong_to_float        CONCAT(from_ullong, _to_float)
+#define ullong_to_double       CONCAT(from_ullong, _to_double)
+#define ullong_to_long_double  CONCAT(from_ullong, _to_long_double)
+
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/softfloat.c
===================================================================
--- uspace/lib/softfloat/softfloat.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/softfloat.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,1353 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat generic
+ * @ingroup sfl
+ * @brief Architecture independent parts of FPU software emulation library.
+ * @{
+ */
+/** @file Softfloat API.
+ */
+
+#include "softfloat.h"
+#include "sftypes.h"
+#include "add.h"
+#include "sub.h"
+#include "mul.h"
+#include "div.h"
+#include "conversion.h"
+#include "comparison.h"
+#include "other.h"
+
+/* Arithmetic functions */
+
+float __addsf3(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	float_t res;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if (fa.data.parts.sign != fb.data.parts.sign) {
+		if (fa.data.parts.sign) {
+			fa.data.parts.sign = 0;
+			res.data = sub_float(fb.data, fa.data);
+			
+			return res.val;
+		}
+		
+		fb.data.parts.sign = 0;
+		res.data = sub_float(fa.data, fb.data);
+		
+		return res.val;
+	}
+	
+	res.data = add_float(fa.data, fb.data);
+	return res.val;
+}
+
+double __adddf3(double a, double b)
+{
+	double_t da;
+	double_t db;
+	double_t res;
+	
+	da.val = a;
+	db.val = b;
+	
+	if (da.data.parts.sign != db.data.parts.sign) {
+		if (da.data.parts.sign) {
+			da.data.parts.sign = 0;
+			res.data = sub_double(db.data, da.data);
+			
+			return res.val;
+		}
+		
+		db.data.parts.sign = 0;
+		res.data = sub_double(da.data, db.data);
+		
+		return res.val;
+	}
+	
+	res.data = add_double(da.data, db.data);
+	return res.val;
+}
+
+long double __addtf3(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	long_double_t res;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if (ta.data.parts.sign != tb.data.parts.sign) {
+		if (ta.data.parts.sign) {
+			ta.data.parts.sign = 0;
+			res.data = sub_long_double(tb.data, ta.data);
+			
+			return res.val;
+		}
+		
+		tb.data.parts.sign = 0;
+		res.data = sub_long_double(ta.data, tb.data);
+		
+		return res.val;
+	}
+	
+	res.data = add_long_double(ta.data, tb.data);
+	return res.val;
+}
+
+float __subsf3(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	float_t res;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if (fa.data.parts.sign != fb.data.parts.sign) {
+		fb.data.parts.sign = !fb.data.parts.sign;
+		res.data = add_float(fa.data, fb.data);
+		
+		return res.val;
+	}
+	
+	res.data = sub_float(fa.data, fb.data);
+	return res.val;
+}
+
+double __subdf3(double a, double b)
+{
+	double_t da;
+	double_t db;
+	double_t res;
+	
+	da.val = a;
+	db.val = b;
+	
+	if (da.data.parts.sign != db.data.parts.sign) {
+		db.data.parts.sign = !db.data.parts.sign;
+		res.data = add_double(da.data, db.data);
+		
+		return res.val;
+	}
+	
+	res.data = sub_double(da.data, db.data);
+	return res.val;
+}
+
+long double __subtf3(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	long_double_t res;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if (ta.data.parts.sign != tb.data.parts.sign) {
+		tb.data.parts.sign = !tb.data.parts.sign;
+		res.data = add_long_double(ta.data, tb.data);
+		
+		return res.val;
+	}
+	
+	res.data = sub_long_double(ta.data, tb.data);
+	return res.val;
+}
+
+float __mulsf3(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	float_t res;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	res.data = mul_float(fa.data, fb.data);
+	return res.val;
+}
+
+double __muldf3(double a, double b)
+{
+	double_t da;
+	double_t db;
+	double_t res;
+	
+	da.val = a;
+	db.val = b;
+	
+	res.data = mul_double(da.data, db.data);
+	return res.val;
+}
+
+long double __multf3(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	long_double_t res;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	res.data = mul_long_double(ta.data, tb.data);
+	return res.val;
+}
+
+float __divsf3(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	float_t res;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	res.data = div_float(fa.data, fb.data);
+	return res.val;
+}
+
+double __divdf3(double a, double b)
+{
+	double_t da;
+	double_t db;
+	double_t res;
+	
+	da.val = a;
+	db.val = b;
+	
+	res.data = div_double(da.data, db.data);
+	return res.val;
+}
+
+long double __divtf3(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	long_double_t res;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	res.data = div_long_double(ta.data, tb.data);
+	return res.val;
+}
+
+float __negsf2(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	fa.data.parts.sign = !fa.data.parts.sign;
+	
+	return fa.val;
+}
+
+double __negdf2(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	da.data.parts.sign = !da.data.parts.sign;
+	
+	return da.val;
+}
+
+long double __negtf2(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	ta.data.parts.sign = !ta.data.parts.sign;
+	
+	return ta.val;
+}
+
+/* Conversion functions */
+
+double __extendsfdf2(float a)
+{
+	float_t fa;
+	double_t res;
+	
+	fa.val = a;
+	res.data = float_to_double(fa.data);
+	
+	return res.val;
+}
+
+long double __extendsftf2(float a)
+{
+	float_t fa;
+	long_double_t res;
+	
+	fa.val = a;
+	res.data = float_to_long_double(fa.data);
+	
+	return res.val;
+}
+
+long double __extenddftf2(double a)
+{
+	double_t da;
+	long_double_t res;
+	
+	da.val = a;
+	res.data = double_to_long_double(da.data);
+	
+	return res.val;
+}
+
+float __truncdfsf2(double a)
+{
+	double_t da;
+	float_t res;
+	
+	da.val = a;
+	res.data = double_to_float(da.data);
+	
+	return res.val;
+}
+
+float __trunctfsf2(long double a)
+{
+	long_double_t ta;
+	float_t res;
+	
+	ta.val = a;
+	res.data = long_double_to_float(ta.data);
+	
+	return res.val;
+}
+
+double __trunctfdf2(long double a)
+{
+	long_double_t ta;
+	double_t res;
+	
+	ta.val = a;
+	res.data = long_double_to_double(ta.data);
+	
+	return res.val;
+}
+
+int __fixsfsi(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	return float_to_int(fa.data);
+}
+
+int __fixdfsi(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	return double_to_int(da.data);
+}
+
+int __fixtfsi(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	return long_double_to_int(ta.data);
+}
+ 
+long __fixsfdi(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	return float_to_long(fa.data);
+}
+
+long __fixdfdi(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	return double_to_long(da.data);
+}
+
+long __fixtfdi(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	return long_double_to_long(ta.data);
+}
+ 
+long long __fixsfti(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	return float_to_llong(fa.data);
+}
+
+long long __fixdfti(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	return double_to_llong(da.data);
+}
+
+long long __fixtfti(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	return long_double_to_llong(ta.data);
+}
+
+unsigned int __fixunssfsi(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	return float_to_uint(fa.data);
+}
+
+unsigned int __fixunsdfsi(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	return double_to_uint(da.data);
+}
+
+unsigned int __fixunstfsi(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	return long_double_to_uint(ta.data);
+}
+ 
+unsigned long __fixunssfdi(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	return float_to_ulong(fa.data);
+}
+
+unsigned long __fixunsdfdi(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	return double_to_ulong(da.data);
+}
+
+unsigned long __fixunstfdi(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	return long_double_to_ulong(ta.data);
+}
+ 
+unsigned long long __fixunssfti(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	return float_to_ullong(fa.data);
+}
+
+unsigned long long __fixunsdfti(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	return double_to_ullong(da.data);
+}
+
+unsigned long long __fixunstfti(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	return long_double_to_ullong(ta.data);
+}
+ 
+float __floatsisf(int i)
+{
+	float_t res;
+	
+	res.data = int_to_float(i);
+	return res.val;
+}
+
+double __floatsidf(int i)
+{
+	double_t res;
+	
+	res.data = int_to_double(i);
+	return res.val;
+}
+
+long double __floatsitf(int i)
+{
+	long_double_t res;
+	
+	res.data = int_to_long_double(i);
+	return res.val;
+}
+ 
+float __floatdisf(long i)
+{
+	float_t res;
+	
+	res.data = long_to_float(i);
+	return res.val;
+}
+
+double __floatdidf(long i)
+{
+	double_t res;
+	
+	res.data = long_to_double(i);
+	return res.val;
+}
+
+long double __floatditf(long i)
+{
+	long_double_t res;
+	
+	res.data = long_to_long_double(i);
+	return res.val;
+}
+
+float __floattisf(long long i)
+{
+	float_t res;
+	
+	res.data = llong_to_float(i);
+	return res.val;
+}
+
+double __floattidf(long long i)
+{
+	double_t res;
+	
+	res.data = llong_to_double(i);
+	return res.val;
+}
+
+long double __floattitf(long long i)
+{
+	long_double_t res;
+	
+	res.data = llong_to_long_double(i);
+	return res.val;
+}
+
+float __floatunsisf(unsigned int i)
+{
+	float_t res;
+	
+	res.data = uint_to_float(i);
+	return res.val;
+}
+
+double __floatunsidf(unsigned int i)
+{
+	double_t res;
+	
+	res.data = uint_to_double(i);
+	return res.val;
+}
+
+long double __floatunsitf(unsigned int i)
+{
+	long_double_t res;
+	
+	res.data = uint_to_long_double(i);
+	return res.val;
+}
+ 
+float __floatundisf(unsigned long i)
+{
+	float_t res;
+	
+	res.data = ulong_to_float(i);
+	return res.val;
+}
+
+double __floatundidf(unsigned long i)
+{
+	double_t res;
+	
+	res.data = ulong_to_double(i);
+	return res.val;
+}
+
+long double __floatunditf(unsigned long i)
+{
+	long_double_t res;
+	
+	res.data = ulong_to_long_double(i);
+	return res.val;
+}
+ 
+float __floatuntisf(unsigned long long i)
+{
+	float_t res;
+	
+	res.data = ullong_to_float(i);
+	return res.val;
+}
+
+double __floatuntidf(unsigned long long i)
+{
+	double_t res;
+	
+	res.data = ullong_to_double(i);
+	return res.val;
+}
+
+long double __floatuntitf(unsigned long long i)
+{
+	long_double_t res;
+	
+	res.data = ullong_to_long_double(i);
+	return res.val;
+}
+
+/* Comparison functions */
+
+int __cmpsf2(float a, float b) 
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
+		/* no special constant for unordered - maybe signaled? */
+		return 1;
+	}
+	
+	if (is_float_eq(fa.data, fb.data))
+		return 0;
+	
+	if (is_float_lt(fa.data, fb.data))
+		return -1;
+	
+	return 1;
+}
+
+int __cmpdf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
+		/* no special constant for unordered - maybe signaled? */
+		return 1;
+	}
+	
+	if (is_double_eq(da.data, db.data))
+		return 0;
+	
+	if (is_double_lt(da.data, db.data))
+		return -1;
+	
+	return 1;
+}
+
+int __cmptf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
+		/* no special constant for unordered - maybe signaled? */
+		return 1;
+	}
+	
+	if (is_long_double_eq(ta.data, tb.data))
+		return 0;
+	
+	if (is_long_double_lt(ta.data, tb.data))
+		return -1;
+	
+	return 1;
+}
+
+int __unordsf2(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	return ((is_float_nan(fa.data)) || (is_float_nan(fb.data)));
+}
+
+int __unorddf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	return ((is_double_nan(da.data)) || (is_double_nan(db.data)));
+}
+
+int __unordtf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	return ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)));
+}
+
+int __eqsf2(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	return is_float_eq(fa.data, fb.data) - 1;
+}
+
+int __eqdf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	return is_double_eq(da.data, db.data) - 1;
+}
+
+int __eqtf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	return is_long_double_eq(ta.data, tb.data) - 1;
+}
+
+int __nesf2(float a, float b)
+{
+	/* strange behavior, but it was in gcc documentation */
+	return __eqsf2(a, b);
+}
+
+int __nedf2(double a, double b)
+{
+	/* strange behavior, but it was in gcc documentation */
+	return __eqdf2(a, b);
+}
+
+int __netf2(long double a, long double b)
+{
+	/* strange behavior, but it was in gcc documentation */
+	return __eqtf2(a, b);
+}
+
+int __gesf2(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
+		// TODO: sigNaNs
+		return -1;
+	}
+	
+	if (is_float_eq(fa.data, fb.data))
+		return 0;
+	
+	if (is_float_gt(fa.data, fb.data))
+		return 1;
+	
+	return -1;
+}
+
+int __gedf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
+		// TODO: sigNaNs
+		return -1;
+	}
+	
+	if (is_double_eq(da.data, db.data))
+		return 0;
+	
+	if (is_double_gt(da.data, db.data))
+		return 1;
+	
+	return -1;
+}
+
+int __getf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
+		// TODO: sigNaNs
+		return -1;
+	}
+	
+	if (is_long_double_eq(ta.data, tb.data))
+		return 0;
+	
+	if (is_long_double_gt(ta.data, tb.data))
+		return 1;
+	
+	return -1;
+}
+
+int __ltsf2(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	if (is_float_lt(fa.data, fb.data))
+		return -1;
+	
+	return 0;
+}
+
+int __ltdf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	if (is_double_lt(da.data, db.data))
+		return -1;
+	
+	return 0;
+}
+
+int __lttf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	if (is_long_double_lt(ta.data, tb.data))
+		return -1;
+	
+	return 0;
+}
+
+int __lesf2(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	if (is_float_eq(fa.data, fb.data))
+		return 0;
+	
+	if (is_float_lt(fa.data, fb.data))
+		return -1;
+	
+	return 1;
+}
+
+int __ledf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	if (is_double_eq(da.data, db.data))
+		return 0;
+	
+	if (is_double_lt(da.data, db.data))
+		return -1;
+	
+	return 1;
+}
+
+int __letf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	if (is_long_double_eq(ta.data, tb.data))
+		return 0;
+	
+	if (is_long_double_lt(ta.data, tb.data))
+		return -1;
+	
+	return 1;
+}
+
+int __gtsf2(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
+		// TODO: sigNaNs
+		return -1;
+	}
+	
+	if (is_float_gt(fa.data, fb.data))
+		return 1;
+	
+	return 0;
+}
+
+int __gtdf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
+		// TODO: sigNaNs
+		return -1;
+	}
+	
+	if (is_double_gt(da.data, db.data))
+		return 1;
+	
+	return 0;
+}
+
+int __gttf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
+		// TODO: sigNaNs
+		return -1;
+	}
+	
+	if (is_long_double_gt(ta.data, tb.data))
+		return 1;
+	
+	return 0;
+}
+
+/* SPARC quadruple-precision wrappers */
+
+void _Qp_add(long double *c, long double *a, long double *b)
+{
+	*c = __addtf3(*a, *b);
+}
+
+void _Qp_sub(long double *c, long double *a, long double *b)
+{
+	*c = __subtf3(*a, *b);
+}
+
+void _Qp_mul(long double *c, long double *a, long double *b)
+{
+	*c = __multf3(*a, *b);
+}
+
+void _Qp_div(long double *c, long double *a, long double *b)
+{
+	*c = __divtf3(*a, *b);
+}
+
+void _Qp_neg(long double *c, long double *a)
+{
+	*c = __negtf2(*a);
+}
+
+void _Qp_stoq(long double *c, float a)
+{
+	*c = __extendsftf2(a);
+}
+
+void _Qp_dtoq(long double *c, double a)
+{
+	*c = __extenddftf2(a);
+}
+
+float _Qp_qtos(long double *a)
+{
+	return __trunctfsf2(*a);
+}
+
+double _Qp_qtod(long double *a)
+{
+	return __trunctfdf2(*a);
+}
+
+int _Qp_qtoi(long double *a)
+{
+	return __fixtfsi(*a);
+}
+
+unsigned int _Qp_qtoui(long double *a)
+{
+	return __fixunstfsi(*a);
+}
+
+long _Qp_qtox(long double *a)
+{
+	return __fixtfdi(*a);
+}
+
+unsigned long _Qp_qtoux(long double *a)
+{
+	return __fixunstfdi(*a);
+}
+
+void _Qp_itoq(long double *c, int a)
+{
+	*c = __floatsitf(a);
+}
+
+void _Qp_uitoq(long double *c, unsigned int a)
+{
+	*c = __floatunsitf(a);
+}
+
+void _Qp_xtoq(long double *c, long a)
+{
+	*c = __floatditf(a);
+}
+
+void _Qp_uxtoq(long double *c, unsigned long a)
+{
+	*c = __floatunditf(a);
+}
+
+int _Qp_cmp(long double *a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 3;
+	
+	if (is_long_double_eq(ta.data, tb.data))
+		return 0;
+	
+	if (is_long_double_lt(ta.data, tb.data))
+		return 1;
+	
+	return 2;
+}
+
+int _Qp_cmpe(long double *a, long double *b)
+{
+	/* strange, but is defined this way in SPARC Compliance Definition */
+	return _Qp_cmp(a, b);
+}
+
+int _Qp_feq(long double *a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 0;
+	
+	return is_long_double_eq(ta.data, tb.data);
+}
+
+int _Qp_fge(long double *a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 0;
+	
+	return is_long_double_eq(ta.data, tb.data) ||
+	    is_long_double_gt(ta.data, tb.data);
+}
+
+int _Qp_fgt(long double *a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 0;
+	
+	return is_long_double_gt(ta.data, tb.data);
+}
+
+int _Qp_fle(long double*a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 0;
+	
+	return is_long_double_eq(ta.data, tb.data) ||
+	    is_long_double_lt(ta.data, tb.data);
+}
+
+int _Qp_flt(long double *a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 0;
+	
+	return is_long_double_lt(ta.data, tb.data);
+}
+
+int _Qp_fne(long double *a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 0;
+	
+	return !is_long_double_eq(ta.data, tb.data);
+}
+
+double __aeabi_i2d(int i)
+{
+	return __floatsidf(i);
+}
+
+double __aeabi_ui2d(unsigned int i)
+{
+	return __floatunsidf(i);
+}
+
+int __aeabi_f2iz(float a)
+{
+	return __fixsfsi(a);
+}
+
+int __aeabi_d2iz(double a)
+{
+	return __fixdfsi(a);
+}
+
+unsigned int __aeabi_d2uiz(double a)
+{
+	return __fixunsdfsi(a);
+}
+
+int __aeabi_dcmpge(double a, double b)
+{
+	return __gedf2(a, b);
+}
+
+int __aeabi_dcmpgt(double a, double b)
+{
+	return __gtdf2(a, b);
+}
+
+int __aeabi_dcmplt(double a, double b)
+{
+	return __ltdf2(a, b);
+}
+
+int __aeabi_dcmpeq(double a, double b)
+{
+	return __eqdf2(a, b);
+}
+
+float __aeabi_fadd(float a, float b)
+{
+	return __addsf3(a, b);
+}
+
+float __aeabi_fsub(float a, float b)
+{
+	return __subsf3(a, b);
+}
+
+float __aeabi_fmul(float a, float b)
+{
+	return __mulsf3(a, b);
+}
+
+float __aeabi_fdiv(float a, float b)
+{
+	return __divsf3(a, b);
+}
+
+double __aeabi_dadd(double a, double b)
+{
+	return __adddf3(a, b);
+}
+
+double __aeabi_dsub(double a, double b)
+{
+	return __subdf3(a, b);
+}
+
+double __aeabi_dmul(double a, double b)
+{
+	return __muldf3(a, b);
+}
+
+double __aeabi_ddiv(double a, double b)
+{
+	return __divdf3(a, b);
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/softfloat.h
===================================================================
--- uspace/lib/softfloat/softfloat.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/softfloat.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Softfloat API.
+ */
+
+#ifndef __SOFTFLOAT_H__
+#define __SOFTFLOAT_H__
+
+extern float __addsf3(float, float);
+extern double __adddf3(double, double);
+extern long double __addtf3(long double, long double);
+extern long double __addxf3(long double, long double);
+
+extern float __subsf3(float, float);
+extern double __subdf3(double, double);
+extern long double __subtf3(long double, long double);
+extern long double __subxf3(long double, long double);
+
+extern float __mulsf3(float, float);
+extern double __muldf3(double, double);
+extern long double __multf3(long double, long double);
+extern long double __mulxf3(long double, long double);
+
+extern float __divsf3(float, float);
+extern double __divdf3(double, double);
+extern long double __divtf3(long double, long double);
+extern long double __divxf3(long double, long double);
+
+extern float __negsf2(float);
+extern double __negdf2(double);
+extern long double __negtf2(long double);
+extern long double __negxf2(long double);
+
+extern double __extendsfdf2(float);
+extern long double __extendsftf2(float);
+extern long double __extendsfxf2(float);
+extern long double __extenddftf2(double);
+extern long double __extenddfxf2(double);
+
+extern double __truncxfdf2(long double);
+extern double __trunctfdf2(long double);
+extern float __truncxfsf2(long double);
+extern float __trunctfsf2(long double);
+extern float __truncdfsf2(double);
+
+extern int __fixsfsi(float);
+extern int __fixdfsi(double);
+extern int __fixtfsi(long double);
+extern int __fixxfsi(long double);
+
+extern long __fixsfdi(float);
+extern long __fixdfdi(double);
+extern long __fixtfdi(long double);
+extern long __fixxfdi(long double);
+
+extern long long __fixsfti(float);
+extern long long __fixdfti(double);
+extern long long __fixtfti(long double);
+extern long long __fixxfti(long double);
+
+extern unsigned int __fixunssfsi(float);
+extern unsigned int __fixunsdfsi(double);
+extern unsigned int __fixunstfsi(long double);
+extern unsigned int __fixunsxfsi(long double);
+
+extern unsigned long __fixunssfdi(float);
+extern unsigned long __fixunsdfdi(double);
+extern unsigned long __fixunstfdi(long double);
+extern unsigned long __fixunsxfdi(long double);
+
+extern unsigned long long __fixunssfti(float);
+extern unsigned long long __fixunsdfti(double);
+extern unsigned long long __fixunstfti(long double);
+extern unsigned long long __fixunsxfti(long double);
+
+extern float __floatsisf(int);
+extern double __floatsidf(int);
+extern long double __floatsitf(int);
+extern long double __floatsixf(int);
+
+extern float __floatdisf(long);
+extern double __floatdidf(long);
+extern long double __floatditf(long);
+extern long double __floatdixf(long);
+
+extern float __floattisf(long long);
+extern double __floattidf(long long);
+extern long double __floattitf(long long);
+extern long double __floattixf(long long);
+
+extern float __floatunsisf(unsigned int);
+extern double __floatunsidf(unsigned int);
+extern long double __floatunsitf(unsigned int);
+extern long double __floatunsixf(unsigned int);
+
+extern float __floatundisf(unsigned long);
+extern double __floatundidf(unsigned long);
+extern long double __floatunditf(unsigned long);
+extern long double __floatundixf(unsigned long);
+
+extern float __floatuntisf(unsigned long long);
+extern double __floatuntidf(unsigned long long);
+extern long double __floatuntitf(unsigned long long);
+extern long double __floatuntixf(unsigned long long);
+
+extern int __cmpsf2(float, float);
+extern int __cmpdf2(double, double);
+extern int __cmptf2(long double, long double);
+
+extern int __unordsf2(float, float);
+extern int __unorddf2(double, double);
+extern int __unordtf2(long double, long double);
+
+extern int __eqsf2(float, float);
+extern int __eqdf2(double, double);
+extern int __eqtf2(long double, long double);
+
+extern int __nesf2(float, float);
+extern int __nedf2(double, double);
+extern int __netf2(long double, long double);
+
+extern int __gesf2(float, float);
+extern int __gedf2(double, double);
+extern int __getf2(long double, long double);
+
+extern int __ltsf2(float, float);
+extern int __ltdf2(double, double);
+extern int __lttf2(long double, long double);
+
+extern int __lesf2(float, float);
+extern int __ledf2(double, double);
+extern int __letf2(long double, long double);
+
+extern int __gtsf2(float, float);
+extern int __gtdf2(double, double);
+extern int __gttf2(long double, long double);
+
+/* Not implemented yet */
+extern float __powisf2(float, int);
+extern double __powidf2 (double, int);
+extern long double __powitf2(long double, int);
+extern long double __powixf2(long double, int);
+
+/* SPARC quadruple-precision wrappers */
+extern void _Qp_add(long double *, long double *, long double *);
+extern void _Qp_sub(long double *, long double *, long double *);
+extern void _Qp_mul(long double *, long double *, long double *);
+extern void _Qp_div(long double *, long double *, long double *);
+extern void _Qp_neg(long double *, long double *);
+
+extern void _Qp_stoq(long double *, float);
+extern void _Qp_dtoq(long double *, double);
+extern float _Qp_qtos(long double *);
+extern double _Qp_qtod(long double *);
+
+extern int _Qp_qtoi(long double *);
+extern unsigned int _Qp_qtoui(long double *);
+extern long _Qp_qtox(long double *);
+extern unsigned long _Qp_qtoux(long double *);
+
+extern void _Qp_itoq(long double *, int);
+extern void _Qp_uitoq(long double *, unsigned int);
+extern void _Qp_xtoq(long double *, long);
+extern void _Qp_uxtoq(long double *, unsigned long);
+
+extern int _Qp_cmp(long double *, long double *);
+extern int _Qp_cmpe(long double *, long double *);
+extern int _Qp_feq(long double *, long double *);
+extern int _Qp_fge(long double *, long double *);
+extern int _Qp_fgt(long double *, long double *);
+extern int _Qp_fle(long double*, long double *);
+extern int _Qp_flt(long double *, long double *);
+extern int _Qp_fne(long double *, long double *);
+
+/* ARM EABI */
+extern double __aeabi_i2d(int);
+extern double __aeabi_ui2d(unsigned int);
+extern unsigned int __aeabi_d2uiz(double);
+
+extern int __aeabi_f2iz(float);
+extern int __aeabi_d2iz(double);
+
+extern int __aeabi_dcmpge(double, double);
+extern int __aeabi_dcmpgt(double, double);
+extern int __aeabi_dcmplt(double, double);
+extern int __aeabi_dcmpeq(double, double);
+
+extern float __aeabi_fadd(float, float);
+extern float __aeabi_fsub(float, float);
+extern float __aeabi_fmul(float, float);
+extern float __aeabi_fdiv(float, float);
+
+extern double __aeabi_dadd(double, double);
+extern double __aeabi_dsub(double, double);
+extern double __aeabi_dmul(double, double);
+extern double __aeabi_ddiv(double, double);
+
+/* Not implemented yet */
+extern void _Qp_sqrt(long double *, long double *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/sub.c
===================================================================
--- uspace/lib/softfloat/sub.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/sub.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Substraction functions.
+ */
+
+#include "sftypes.h"
+#include "sub.h"
+#include "comparison.h"
+#include "common.h"
+
+/** Subtract two single-precision floats with the same sign.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ *
+ * @return Result of substraction.
+ *
+ */
+float32 sub_float32(float32 a, float32 b)
+{
+	int expdiff;
+	uint32_t exp1, exp2, frac1, frac2;
+	float32 result;
+	
+	result.bin = 0;
+	
+	expdiff = a.parts.exp - b.parts.exp;
+	if ((expdiff < 0 ) || ((expdiff == 0) &&
+	    (a.parts.fraction < b.parts.fraction))) {
+		if (is_float32_nan(b)) {
+			if (is_float32_signan(b)) {
+				// TODO: fix SigNaN
+			}
+			
+			return b;
+		}
+		
+		if (b.parts.exp == FLOAT32_MAX_EXPONENT) {
+			/* num -(+-inf) = -+inf */
+			b.parts.sign = !b.parts.sign;
+			return b;
+		}
+		
+		result.parts.sign = !a.parts.sign;
+		
+		frac1 = b.parts.fraction;
+		exp1 = b.parts.exp;
+		frac2 = a.parts.fraction;
+		exp2 = a.parts.exp;
+		expdiff *= -1;
+	} else {
+		if (is_float32_nan(a)) {
+			if ((is_float32_signan(a)) || (is_float32_signan(b))) {
+				// TODO: fix SigNaN
+			}
+			
+			return a;
+		}
+		
+		if (a.parts.exp == FLOAT32_MAX_EXPONENT) {
+			if (b.parts.exp == FLOAT32_MAX_EXPONENT) {
+				/* inf - inf => nan */
+				// TODO: fix exception
+				result.bin = FLOAT32_NAN;
+				return result;
+			}
+			
+			return a;
+		}
+		
+		result.parts.sign = a.parts.sign;
+		
+		frac1 = a.parts.fraction;
+		exp1 = a.parts.exp;
+		frac2 = b.parts.fraction;
+		exp2 = b.parts.exp;
+	}
+	
+	if (exp1 == 0) {
+		/* both are denormalized */
+		result.parts.fraction = frac1 - frac2;
+		if (result.parts.fraction > frac1) {
+			// TODO: underflow exception
+			return result;
+		}
+		
+		result.parts.exp = 0;
+		return result;
+	}
+	
+	/* add hidden bit */
+	frac1 |= FLOAT32_HIDDEN_BIT_MASK;
+	
+	if (exp2 == 0) {
+		/* denormalized */
+		--expdiff;
+	} else {
+		/* normalized */
+		frac2 |= FLOAT32_HIDDEN_BIT_MASK;
+	}
+	
+	/* create some space for rounding */
+	frac1 <<= 6;
+	frac2 <<= 6;
+	
+	if (expdiff > FLOAT32_FRACTION_SIZE + 1)
+		goto done;
+	
+	frac1 = frac1 - (frac2 >> expdiff);
+	
+done:
+	/* TODO: find first nonzero digit and shift result and detect possibly underflow */
+	while ((exp1 > 0) && (!(frac1 & (FLOAT32_HIDDEN_BIT_MASK << 6 )))) {
+		--exp1;
+		frac1 <<= 1;
+		/* TODO: fix underflow - frac1 == 0 does not necessary means underflow... */
+	}
+	
+	/* rounding - if first bit after fraction is set then round up */
+	frac1 += 0x20;
+	
+	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7)) {
+		++exp1;
+		frac1 >>= 1;
+	}
+	
+	/* Clear hidden bit and shift */
+	result.parts.fraction = ((frac1 >> 6) & (~FLOAT32_HIDDEN_BIT_MASK));
+	result.parts.exp = exp1;
+	
+	return result;
+}
+
+/** Subtract two double-precision floats with the same sign.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ *
+ * @return Result of substraction.
+ *
+ */
+float64 sub_float64(float64 a, float64 b)
+{
+	int expdiff;
+	uint32_t exp1, exp2;
+	uint64_t frac1, frac2;
+	float64 result;
+	
+	result.bin = 0;
+	
+	expdiff = a.parts.exp - b.parts.exp;
+	if ((expdiff < 0 ) ||
+	    ((expdiff == 0) && (a.parts.fraction < b.parts.fraction))) {
+		if (is_float64_nan(b)) {
+			if (is_float64_signan(b)) {
+				// TODO: fix SigNaN
+			}
+			
+			return b;
+		}
+		
+		if (b.parts.exp == FLOAT64_MAX_EXPONENT) {
+			/* num -(+-inf) = -+inf */
+			b.parts.sign = !b.parts.sign;
+			return b;
+		}
+		
+		result.parts.sign = !a.parts.sign;
+		
+		frac1 = b.parts.fraction;
+		exp1 = b.parts.exp;
+		frac2 = a.parts.fraction;
+		exp2 = a.parts.exp;
+		expdiff *= -1;
+	} else {
+		if (is_float64_nan(a)) {
+			if (is_float64_signan(a) || is_float64_signan(b)) {
+				// TODO: fix SigNaN
+			}
+			
+			return a;
+		}
+		
+		if (a.parts.exp == FLOAT64_MAX_EXPONENT) {
+			if (b.parts.exp == FLOAT64_MAX_EXPONENT) {
+				/* inf - inf => nan */
+				// TODO: fix exception
+				result.bin = FLOAT64_NAN;
+				return result;
+			}
+			
+			return a;
+		}
+		
+		result.parts.sign = a.parts.sign;
+		
+		frac1 = a.parts.fraction;
+		exp1 = a.parts.exp;
+		frac2 = b.parts.fraction;
+		exp2 = b.parts.exp;
+	}
+	
+	if (exp1 == 0) {
+		/* both are denormalized */
+		result.parts.fraction = frac1 - frac2;
+		if (result.parts.fraction > frac1) {
+			// TODO: underflow exception
+			return result;
+		}
+		
+		result.parts.exp = 0;
+		return result;
+	}
+	
+	/* add hidden bit */
+	frac1 |= FLOAT64_HIDDEN_BIT_MASK;
+	
+	if (exp2 == 0) {
+		/* denormalized */
+		--expdiff;
+	} else {
+		/* normalized */
+		frac2 |= FLOAT64_HIDDEN_BIT_MASK;
+	}
+	
+	/* create some space for rounding */
+	frac1 <<= 6;
+	frac2 <<= 6;
+	
+	if (expdiff > FLOAT64_FRACTION_SIZE + 1)
+		goto done;
+	
+	frac1 = frac1 - (frac2 >> expdiff);
+	
+done:
+	/* TODO: find first nonzero digit and shift result and detect possibly underflow */
+	while ((exp1 > 0) && (!(frac1 & (FLOAT64_HIDDEN_BIT_MASK << 6 )))) {
+		--exp1;
+		frac1 <<= 1;
+		/* TODO: fix underflow - frac1 == 0 does not necessary means underflow... */
+	}
+	
+	/* rounding - if first bit after fraction is set then round up */
+	frac1 += 0x20;
+	
+	if (frac1 & (FLOAT64_HIDDEN_BIT_MASK << 7)) {
+		++exp1;
+		frac1 >>= 1;
+	}
+	
+	/* Clear hidden bit and shift */
+	result.parts.fraction = ((frac1 >> 6) & (~FLOAT64_HIDDEN_BIT_MASK));
+	result.parts.exp = exp1;
+	
+	return result;
+}
+
+/** Subtract two quadruple-precision floats with the same sign.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ *
+ * @return Result of substraction.
+ *
+ */
+float128 sub_float128(float128 a, float128 b)
+{
+	int expdiff;
+	uint32_t exp1, exp2;
+	uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
+	float128 result;
+	
+	result.bin.hi = 0;
+	result.bin.lo = 0;
+	
+	expdiff = a.parts.exp - b.parts.exp;
+	if ((expdiff < 0 ) || ((expdiff == 0) &&
+	    lt128(a.parts.frac_hi, a.parts.frac_lo, b.parts.frac_hi, b.parts.frac_lo))) {
+		if (is_float128_nan(b)) {
+			if (is_float128_signan(b)) {
+				// TODO: fix SigNaN
+			}
+			
+			return b;
+		}
+		
+		if (b.parts.exp == FLOAT128_MAX_EXPONENT) {
+			/* num -(+-inf) = -+inf */
+			b.parts.sign = !b.parts.sign;
+			return b;
+		}
+		
+		result.parts.sign = !a.parts.sign;
+		
+		frac1_hi = b.parts.frac_hi;
+		frac1_lo = b.parts.frac_lo;
+		exp1 = b.parts.exp;
+		frac2_hi = a.parts.frac_hi;
+		frac2_lo = a.parts.frac_lo;
+		exp2 = a.parts.exp;
+		expdiff *= -1;
+	} else {
+		if (is_float128_nan(a)) {
+			if (is_float128_signan(a) || is_float128_signan(b)) {
+				// TODO: fix SigNaN
+			}
+			
+			return a;
+		}
+		
+		if (a.parts.exp == FLOAT128_MAX_EXPONENT) {
+			if (b.parts.exp == FLOAT128_MAX_EXPONENT) {
+				/* inf - inf => nan */
+				// TODO: fix exception
+				result.bin.hi = FLOAT128_NAN_HI;
+				result.bin.lo = FLOAT128_NAN_LO;
+				return result;
+			}
+			return a;
+		}
+		
+		result.parts.sign = a.parts.sign;
+		
+		frac1_hi = a.parts.frac_hi;
+		frac1_lo = a.parts.frac_lo;
+		exp1 = a.parts.exp;
+		frac2_hi = b.parts.frac_hi;
+		frac2_lo = b.parts.frac_lo;
+		exp2 = b.parts.exp;
+	}
+	
+	if (exp1 == 0) {
+		/* both are denormalized */
+		sub128(frac1_hi, frac1_lo, frac2_hi, frac2_lo, &tmp_hi, &tmp_lo);
+		result.parts.frac_hi = tmp_hi;
+		result.parts.frac_lo = tmp_lo;
+		if (lt128(frac1_hi, frac1_lo, result.parts.frac_hi, result.parts.frac_lo)) {
+			// TODO: underflow exception
+			return result;
+		}
+		
+		result.parts.exp = 0;
+		return result;
+	}
+	
+	/* add hidden bit */
+	or128(frac1_hi, frac1_lo,
+	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &frac1_hi, &frac1_lo);
+	
+	if (exp2 == 0) {
+		/* denormalized */
+		--expdiff;
+	} else {
+		/* normalized */
+		or128(frac2_hi, frac2_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &frac2_hi, &frac2_lo);
+	}
+	
+	/* create some space for rounding */
+	lshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
+	lshift128(frac2_hi, frac2_lo, 6, &frac2_hi, &frac2_lo);
+	
+	if (expdiff > FLOAT128_FRACTION_SIZE + 1)
+		goto done;
+	
+	rshift128(frac2_hi, frac2_lo, expdiff, &tmp_hi, &tmp_lo);
+	sub128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &frac1_hi, &frac1_lo);
+	
+done:
+	/* TODO: find first nonzero digit and shift result and detect possibly underflow */
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 6,
+	    &tmp_hi, &tmp_lo);
+	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	while ((exp1 > 0) && (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo))) {
+		--exp1;
+		lshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
+		/* TODO: fix underflow - frac1 == 0 does not necessary means underflow... */
+		
+		lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 6,
+		    &tmp_hi, &tmp_lo);
+		and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	}
+	
+	/* rounding - if first bit after fraction is set then round up */
+	add128(frac1_hi, frac1_lo, 0x0ll, 0x20ll, &frac1_hi, &frac1_lo);
+	
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 7,
+	   &tmp_hi, &tmp_lo);
+	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+		++exp1;
+		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
+	}
+	
+	/* Clear hidden bit and shift */
+	rshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
+	not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &tmp_hi, &tmp_lo);
+	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	result.parts.frac_hi = tmp_hi;
+	result.parts.frac_lo = tmp_lo;
+	
+	result.parts.exp = exp1;
+	
+	return result;
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/sub.h
===================================================================
--- uspace/lib/softfloat/sub.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/lib/softfloat/sub.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Substraction functions.
+ */
+
+#ifndef __SUB_H__
+#define __SUB_H__
+
+extern float32 sub_float32(float32, float32);
+extern float64 sub_float64(float64, float64);
+extern float96 sub_float96(float96, float96);
+extern float128 sub_float128(float128, float128);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/usb/include/usb/debug.h
===================================================================
--- uspace/lib/usb/include/usb/debug.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/usb/include/usb/debug.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -38,4 +38,5 @@
 #include <inttypes.h>
 #include <usb/usb.h>
+#include <io/log.h>
 #include <assert.h>
 
@@ -43,52 +44,13 @@
     const uint8_t *, size_t);
 
-/** Logging level. */
-typedef enum {
-	/** Fatal, unrecoverable, error.
-	 * Such error prevents the driver from working at all.
-	 */
-	USB_LOG_LEVEL_FATAL,
+#define USB_LOG_LEVEL_FATAL LVL_FATAL
+#define USB_LOG_LEVEL_ERROR LVL_ERROR
+#define USB_LOG_LEVEL_WARNING LVL_WARN
+#define USB_LOG_LEVEL_INFO LVL_NOTE
+#define USB_LOG_LEVEL_DEBUG LVL_DEBUG
+#define USB_LOG_LEVEL_DEBUG2 LVL_DEBUG2
 
-	/** Serious but recoverable error
-	 * Shall be used for errors fatal for single device but not for
-	 * driver itself.
-	 */
-	USB_LOG_LEVEL_ERROR,
-
-	/** Warning.
-	 * Problems from which the driver is able to recover gracefully.
-	 */
-	USB_LOG_LEVEL_WARNING,
-
-	/** Information message.
-	 * This should be the last level that is printed by default to
-	 * the screen.
-	 * Typical usage is to inform that new device was found and what
-	 * are its capabilities.
-	 * Do not use for repetitive actions (such as device polling).
-	 */
-	USB_LOG_LEVEL_INFO,
-
-	/** Debugging message. */
-	USB_LOG_LEVEL_DEBUG,
-
-	/** More detailed debugging message. */
-	USB_LOG_LEVEL_DEBUG2,
-
-	/** Terminating constant for logging levels. */
-	USB_LOG_LEVEL_MAX
-} usb_log_level_t;
-
-/** Default log level. */
-#ifdef CONFIG_USB_VERBOSE
-	#define USB_LOG_LEVEL_DEFAULT USB_LOG_LEVEL_DEBUG
-#else
-	#define USB_LOG_LEVEL_DEFAULT USB_LOG_LEVEL_INFO
-#endif
-
-void usb_log_enable(usb_log_level_t, const char *);
-
-void usb_log_printf(usb_log_level_t, const char *, ...)
-	PRINTF_ATTRIBUTE(2, 3);
+#define usb_log_printf(level, format, ...) \
+	log_msg(LOG_DEFAULT, level, format, ##__VA_ARGS__)
 
 /** Log fatal error. */
Index: uspace/lib/usb/src/debug.c
===================================================================
--- uspace/lib/usb/src/debug.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/lib/usb/src/debug.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -40,115 +40,4 @@
 #include <ddf/log.h>
 #include <usb/debug.h>
-
-/** Level of logging messages. */
-static usb_log_level_t log_level = USB_LOG_LEVEL_WARNING;
-
-/** Prefix for logging messages. */
-static const char *log_prefix = "usb";
-
-/** Serialization mutex for logging functions. */
-static FIBRIL_MUTEX_INITIALIZE(log_serializer);
-
-/** File where to store the log. */
-static FILE *log_stream = NULL;
-
-
-/** Enable logging.
- *
- * @param level Maximal enabled level (including this one).
- * @param message_prefix Prefix for each printed message.
- */
-void usb_log_enable(usb_log_level_t level, const char *message_prefix)
-{
-	log_prefix = message_prefix;
-	log_level = level;
-	if (log_stream == NULL) {
-		char *fname;
-		int rc = asprintf(&fname, "/log/%s", message_prefix);
-		if (rc > 0) {
-			log_stream = fopen(fname, "w");
-			if (log_stream != NULL)
-				setvbuf(log_stream, NULL, _IOFBF, BUFSIZ);
-			
-			free(fname);
-		}
-	}
-}
-
-/** Get log level name prefix.
- *
- * @param level Log level.
- * @return String prefix for the message.
- */
-static const char *log_level_name(usb_log_level_t level)
-{
-	switch (level) {
-		case USB_LOG_LEVEL_FATAL:
-			return " FATAL";
-		case USB_LOG_LEVEL_ERROR:
-			return " ERROR";
-		case USB_LOG_LEVEL_WARNING:
-			return " WARN";
-		case USB_LOG_LEVEL_INFO:
-			return " info";
-		default:
-			return "";
-	}
-}
-
-/** Print logging message.
- *
- * @param level Verbosity level of the message.
- * @param format Formatting directive.
- */
-void usb_log_printf(usb_log_level_t level, const char *format, ...)
-{
-	FILE *screen_stream = NULL;
-	switch (level) {
-		case USB_LOG_LEVEL_FATAL:
-		case USB_LOG_LEVEL_ERROR:
-			screen_stream = stderr;
-			break;
-		default:
-			screen_stream = stdout;
-			break;
-	}
-	assert(screen_stream != NULL);
-
-	va_list args;
-
-	/*
-	 * Serialize access to log files.
-	 * Print to screen only messages with higher level than the one
-	 * specified during logging initialization.
-	 * Print also to file, to it print one more (lower) level as well.
-	 */
-	fibril_mutex_lock(&log_serializer);
-
-	const char *level_name = log_level_name(level);
-
-	if ((log_stream != NULL) && (level <= log_level + 1)) {
-		va_start(args, format);
-
-		fprintf(log_stream, "[%s]%s: ", log_prefix, level_name);
-		vfprintf(log_stream, format, args);
-		fflush(log_stream);
-
-		va_end(args);
-	}
-
-	if (level <= log_level) {
-		va_start(args, format);
-
-		fprintf(screen_stream, "[%s]%s: ", log_prefix, level_name);
-		vfprintf(screen_stream, format, args);
-		fflush(screen_stream);
-
-		va_end(args);
-	}
-
-	fibril_mutex_unlock(&log_serializer);
-}
-
 
 #define REMAINDER_STR_FMT " (%zu)..."
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/devman/devman.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -122,6 +122,6 @@
 	.key_hash = handle_key_hash,
 	.key_equal = devman_devices_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -130,6 +130,6 @@
 	.key_hash = handle_key_hash,
 	.key_equal = devman_functions_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -138,6 +138,6 @@
 	.key_hash = service_id_key_hash,
 	.key_equal = loc_functions_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -179,5 +179,5 @@
 	fibril_mutex_unlock(&drivers_list->drivers_mutex);
 
-	log_msg(LVL_NOTE, "Driver `%s' was added to the list of available "
+	log_msg(LOG_DEFAULT, LVL_NOTE, "Driver `%s' was added to the list of available "
 	    "drivers.", drv->name);
 }
@@ -270,5 +270,5 @@
 bool read_match_ids(const char *conf_path, match_id_list_t *ids)
 {
-	log_msg(LVL_DEBUG, "read_match_ids(conf_path=\"%s\")", conf_path);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "read_match_ids(conf_path=\"%s\")", conf_path);
 	
 	bool suc = false;
@@ -280,5 +280,5 @@
 	fd = open(conf_path, O_RDONLY);
 	if (fd < 0) {
-		log_msg(LVL_ERROR, "Unable to open `%s' for reading: %s.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to open `%s' for reading: %s.",
 		    conf_path, str_error(fd));
 		goto cleanup;
@@ -289,5 +289,5 @@
 	lseek(fd, 0, SEEK_SET);
 	if (len == 0) {
-		log_msg(LVL_ERROR, "Configuration file '%s' is empty.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Configuration file '%s' is empty.",
 		    conf_path);
 		goto cleanup;
@@ -296,5 +296,5 @@
 	buf = malloc(len + 1);
 	if (buf == NULL) {
-		log_msg(LVL_ERROR, "Memory allocation failed when parsing file "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failed when parsing file "
 		    "'%s'.", conf_path);
 		goto cleanup;
@@ -303,5 +303,5 @@
 	ssize_t read_bytes = read_all(fd, buf, len);
 	if (read_bytes <= 0) {
-		log_msg(LVL_ERROR, "Unable to read file '%s' (%zd).", conf_path,
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to read file '%s' (%zd).", conf_path,
 		    read_bytes);
 		goto cleanup;
@@ -342,5 +342,5 @@
 bool get_driver_info(const char *base_path, const char *name, driver_t *drv)
 {
-	log_msg(LVL_DEBUG, "get_driver_info(base_path=\"%s\", name=\"%s\")",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "get_driver_info(base_path=\"%s\", name=\"%s\")",
 	    base_path, name);
 	
@@ -374,5 +374,5 @@
 	struct stat s;
 	if (stat(drv->binary_path, &s) == ENOENT) { /* FIXME!! */
-		log_msg(LVL_ERROR, "Driver not found at path `%s'.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Driver not found at path `%s'.",
 		    drv->binary_path);
 		goto cleanup;
@@ -402,5 +402,5 @@
 int lookup_available_drivers(driver_list_t *drivers_list, const char *dir_path)
 {
-	log_msg(LVL_DEBUG, "lookup_available_drivers(dir=\"%s\")", dir_path);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "lookup_available_drivers(dir=\"%s\")", dir_path);
 	
 	int drv_cnt = 0;
@@ -436,5 +436,5 @@
 	dev_node_t *dev;
 	
-	log_msg(LVL_DEBUG, "create_root_nodes()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "create_root_nodes()");
 	
 	fibril_rwlock_write_lock(&tree->rwlock);
@@ -523,5 +523,5 @@
 void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
 {
-	log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
 	    dev->pfun->pathname, drv->name);
 	
@@ -548,5 +548,5 @@
 	assert(drv != NULL);
 	
-	log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
 	    dev->pfun->pathname, drv->name);
 	
@@ -573,9 +573,9 @@
 	assert(fibril_mutex_is_locked(&drv->driver_mutex));
 	
-	log_msg(LVL_DEBUG, "start_driver(drv=\"%s\")", drv->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "start_driver(drv=\"%s\")", drv->name);
 	
 	rc = task_spawnl(NULL, drv->binary_path, drv->binary_path, NULL);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Spawning driver `%s' (%s) failed: %s.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Spawning driver `%s' (%s) failed: %s.",
 		    drv->name, drv->binary_path, str_error(rc));
 		return false;
@@ -622,5 +622,5 @@
 	link_t *link;
 
-	log_msg(LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")",
 	    driver->name);
 
@@ -642,5 +642,5 @@
 		}
 
-		log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
 		    (int)atomic_get(&dev->refcnt));
 		dev_add_ref(dev);
@@ -678,5 +678,5 @@
 	 * immediately and possibly started here as well.
 	 */
-	log_msg(LVL_DEBUG, "Driver `%s' enters running state.", driver->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Driver `%s' enters running state.", driver->name);
 	driver->state = DRIVER_RUNNING;
 
@@ -695,5 +695,5 @@
 void initialize_running_driver(driver_t *driver, dev_tree_t *tree)
 {
-	log_msg(LVL_DEBUG, "initialize_running_driver(driver=\"%s\")",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "initialize_running_driver(driver=\"%s\")",
 	    driver->name);
 	
@@ -789,5 +789,5 @@
 	 * access any structures that would affect driver_t.
 	 */
-	log_msg(LVL_DEBUG, "add_device(drv=\"%s\", dev=\"%s\")",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "add_device(drv=\"%s\", dev=\"%s\")",
 	    drv->name, dev->pfun->name);
 	
@@ -855,5 +855,5 @@
 	driver_t *drv = find_best_match_driver(drivers_list, dev);
 	if (drv == NULL) {
-		log_msg(LVL_ERROR, "No driver found for device `%s'.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "No driver found for device `%s'.",
 		    dev->pfun->pathname);
 		return false;
@@ -895,5 +895,5 @@
 	assert(dev != NULL);
 	
-	log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_dev_remove(%p)", dev);
 	
 	fibril_rwlock_read_lock(&tree->rwlock);
@@ -918,5 +918,5 @@
 	assert(dev != NULL);
 	
-	log_msg(LVL_DEBUG, "driver_dev_gone(%p)", dev);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_dev_gone(%p)", dev);
 	
 	fibril_rwlock_read_lock(&tree->rwlock);
@@ -939,5 +939,5 @@
 	devman_handle_t handle;
 	
-	log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_fun_online(%p)", fun);
 
 	fibril_rwlock_read_lock(&tree->rwlock);
@@ -967,5 +967,5 @@
 	devman_handle_t handle;
 	
-	log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_fun_offline(%p)", fun);
 
 	fibril_rwlock_read_lock(&tree->rwlock);
@@ -998,5 +998,5 @@
 bool init_device_tree(dev_tree_t *tree, driver_list_t *drivers_list)
 {
-	log_msg(LVL_DEBUG, "init_device_tree()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "init_device_tree()");
 	
 	tree->current_handle = 0;
@@ -1278,5 +1278,5 @@
 	fun->pathname = (char *) malloc(pathsize);
 	if (fun->pathname == NULL) {
-		log_msg(LVL_ERROR, "Failed to allocate device path.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate device path.");
 		return false;
 	}
@@ -1306,5 +1306,5 @@
 	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
 	
-	log_msg(LVL_DEBUG, "insert_dev_node(dev=%p, pfun=%p [\"%s\"])",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "insert_dev_node(dev=%p, pfun=%p [\"%s\"])",
 	    dev, pfun, pfun->pathname);
 
@@ -1329,5 +1329,5 @@
 	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
 	
-	log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
 	
 	/* Remove node from the handle-to-node map. */
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/devman/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -73,5 +73,5 @@
 	char *drv_name = NULL;
 
-	log_msg(LVL_DEBUG, "devman_driver_register");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_driver_register");
 	
 	/* Get driver name. */
@@ -82,5 +82,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "The `%s' driver is trying to register.",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s' driver is trying to register.",
 	    drv_name);
 	
@@ -88,5 +88,5 @@
 	driver = find_driver(&drivers_list, drv_name);
 	if (driver == NULL) {
-		log_msg(LVL_ERROR, "No driver named `%s' was found.", drv_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "No driver named `%s' was found.", drv_name);
 		free(drv_name);
 		drv_name = NULL;
@@ -102,5 +102,5 @@
 	if (driver->sess) {
 		/* We already have a connection to the driver. */
-		log_msg(LVL_ERROR, "Driver '%s' already started.\n",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Driver '%s' already started.\n",
 		    driver->name);
 		fibril_mutex_unlock(&driver->driver_mutex);
@@ -112,5 +112,5 @@
 	case DRIVER_NOT_STARTED:
 		/* Somebody started the driver manually. */
-		log_msg(LVL_NOTE, "Driver '%s' started manually.\n",
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Driver '%s' started manually.\n",
 		    driver->name);
 		driver->state = DRIVER_STARTING;
@@ -125,5 +125,5 @@
 	
 	/* Create connection to the driver. */
-	log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Creating connection to the `%s' driver.",
 	    driver->name);
 	driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
@@ -136,5 +136,5 @@
 	async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);
 	
-	log_msg(LVL_NOTE,
+	log_msg(LOG_DEFAULT, LVL_NOTE,
 	    "The `%s' driver was successfully registered as running.",
 	    driver->name);
@@ -147,5 +147,5 @@
 	fid_t fid = fibril_create(init_running_drv, driver);
 	if (fid == 0) {
-		log_msg(LVL_ERROR, "Failed to create initialization fibril " \
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create initialization fibril " \
 		    "for driver `%s'.", driver->name);
 		fibril_mutex_unlock(&driver->driver_mutex);
@@ -176,5 +176,5 @@
 	callid = async_get_call(&call);
 	if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
-		log_msg(LVL_ERROR, 
+		log_msg(LOG_DEFAULT, LVL_ERROR, 
 		    "Invalid protocol when trying to receive match id.");
 		async_answer_0(callid, EINVAL); 
@@ -184,5 +184,5 @@
 	
 	if (match_id == NULL) {
-		log_msg(LVL_ERROR, "Failed to allocate match id.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate match id.");
 		async_answer_0(callid, ENOMEM);
 		return ENOMEM;
@@ -198,5 +198,5 @@
 	if (rc != EOK) {
 		delete_match_id(match_id);
-		log_msg(LVL_ERROR, "Failed to receive match id string: %s.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to receive match id string: %s.",
 		    str_error(rc));
 		return rc;
@@ -205,5 +205,5 @@
 	list_append(&match_id->link, &match_ids->ids);
 	
-	log_msg(LVL_DEBUG, "Received match id `%s', score %d.",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Received match id `%s', score %d.",
 	    match_id->id, match_id->score);
 	return rc;
@@ -248,5 +248,5 @@
 	if (fun->state == FUN_ON_LINE) {
 		fibril_rwlock_write_unlock(&device_tree.rwlock);
-		log_msg(LVL_WARN, "Function %s is already on line.",
+		log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already on line.",
 		    fun->pathname);
 		return EOK;
@@ -264,5 +264,5 @@
 	}
 	
-	log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
 	
 	if (fun->ftype == fun_inner) {
@@ -282,5 +282,5 @@
 		fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
 		if (assign_fibril == 0) {
-			log_msg(LVL_ERROR, "Failed to create fibril for "
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create fibril for "
 			    "assigning driver.");
 			/* XXX Cleanup */
@@ -305,5 +305,5 @@
 	if (fun->state == FUN_OFF_LINE) {
 		fibril_rwlock_write_unlock(&device_tree.rwlock);
-		log_msg(LVL_WARN, "Function %s is already off line.",
+		log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already off line.",
 		    fun->pathname);
 		return EOK;
@@ -311,5 +311,5 @@
 	
 	if (fun->ftype == fun_inner) {
-		log_msg(LVL_DEBUG, "Offlining inner function %s.",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Offlining inner function %s.",
 		    fun->pathname);
 		
@@ -359,5 +359,5 @@
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&device_tree.rwlock);
-			log_msg(LVL_ERROR, "Failed unregistering tree service.");
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree service.");
 			return EIO;
 		}
@@ -391,5 +391,5 @@
 	if (ftype != fun_inner && ftype != fun_exposed) {
 		/* Unknown function type */
-		log_msg(LVL_ERROR, 
+		log_msg(LOG_DEFAULT, LVL_ERROR, 
 		    "Unknown function type %d provided by driver.",
 		    (int) ftype);
@@ -507,8 +507,8 @@
 	if (rc == EOK) {
 		loc_service_add_to_cat(fun->service_id, cat_id);
-		log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Function `%s' added to category `%s'.",
 		    fun->pathname, cat_name);
 	} else {
-		log_msg(LVL_ERROR, "Failed adding function `%s' to category "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding function `%s' to category "
 		    "`%s'.", fun->pathname, cat_name);
 	}
@@ -529,5 +529,5 @@
 	int rc;
 	
-	log_msg(LVL_DEBUG, "devman_drv_fun_online()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_drv_fun_online()");
 	
 	fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
@@ -620,5 +620,5 @@
 	fibril_rwlock_write_lock(&tree->rwlock);
 	
-	log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
 	
 	/* Check function state */
@@ -653,5 +653,5 @@
 			/* Verify that driver succeeded and removed all functions */
 			if (gone_rc != EOK || !list_empty(&dev->functions)) {
-				log_msg(LVL_ERROR, "Driver did not remove "
+				log_msg(LOG_DEFAULT, LVL_ERROR, "Driver did not remove "
 				    "functions for device that is gone. "
 				    "Device node is now defunct.");
@@ -692,5 +692,5 @@
 			rc = loc_service_unregister(fun->service_id);
 			if (rc != EOK) {
-				log_msg(LVL_ERROR, "Failed unregistering tree "
+				log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree "
 				    "service.");
 				fibril_rwlock_write_unlock(&tree->rwlock);
@@ -712,5 +712,5 @@
 	fun_del_ref(fun);
 	
-	log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function() succeeded.");
 	async_answer_0(callid, EOK);
 }
@@ -726,5 +726,5 @@
 	
 	initialize_running_driver(driver, &device_tree);
-	log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s` driver was successfully initialized.",
 	    driver->name);
 	return 0;
@@ -742,5 +742,5 @@
 	client = async_get_client_data();
 	if (client == NULL) {
-		log_msg(LVL_ERROR, "Failed to allocate client data.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate client data.");
 		return;
 	}
@@ -1229,5 +1229,5 @@
 	 */
 	if (dev == NULL) {
-		log_msg(LVL_ERROR, "IPC forwarding failed - no device or "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding failed - no device or "
 		    "function with handle %" PRIun " was found.", handle);
 		async_answer_0(iid, ENOENT);
@@ -1236,5 +1236,5 @@
 
 	if (fun == NULL && !drv_to_parent) {
-		log_msg(LVL_ERROR, NAME ": devman_forward error - cannot "
+		log_msg(LOG_DEFAULT, LVL_ERROR, NAME ": devman_forward error - cannot "
 		    "connect to handle %" PRIun ", refers to a device.",
 		    handle);
@@ -1264,5 +1264,5 @@
 	
 	if (driver == NULL) {
-		log_msg(LVL_ERROR, "IPC forwarding refused - " \
+		log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding refused - " \
 		    "the device %" PRIun " is not in usable state.", handle);
 		async_answer_0(iid, ENOENT);
@@ -1277,5 +1277,5 @@
 	
 	if (!driver->sess) {
-		log_msg(LVL_ERROR,
+		log_msg(LOG_DEFAULT, LVL_ERROR,
 		    "Could not forward to driver `%s'.", driver->name);
 		async_answer_0(iid, EINVAL);
@@ -1284,9 +1284,9 @@
 
 	if (fun != NULL) {
-		log_msg(LVL_DEBUG,
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
 		    "Forwarding request for `%s' function to driver `%s'.",
 		    fun->pathname, driver->name);
 	} else {
-		log_msg(LVL_DEBUG,
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
 		    "Forwarding request for `%s' device to driver `%s'.",
 		    dev->pfun->pathname, driver->name);
@@ -1320,5 +1320,5 @@
 	
 	if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
-		log_msg(LVL_WARN, "devman_connection_loc(): function "
+		log_msg(LOG_DEFAULT, LVL_WARN, "devman_connection_loc(): function "
 		    "not found.\n");
 		fibril_rwlock_read_unlock(&device_tree.rwlock);
@@ -1338,5 +1338,5 @@
 	async_exchange_end(exch);
 	
-	log_msg(LVL_DEBUG,
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
 	    "Forwarding loc service request for `%s' function to driver `%s'.",
 	    fun->pathname, driver->name);
@@ -1394,5 +1394,5 @@
 static bool devman_init(void)
 {
-	log_msg(LVL_DEBUG, "devman_init - looking for available drivers.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - looking for available drivers.");
 	
 	/* Initialize list of available drivers. */
@@ -1400,13 +1400,13 @@
 	if (lookup_available_drivers(&drivers_list,
 	    DRIVER_DEFAULT_STORE) == 0) {
-		log_msg(LVL_FATAL, "No drivers found.");
+		log_msg(LOG_DEFAULT, LVL_FATAL, "No drivers found.");
 		return false;
 	}
 	
-	log_msg(LVL_DEBUG, "devman_init - list of drivers has been initialized.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - list of drivers has been initialized.");
 	
 	/* Create root device node. */
 	if (!init_device_tree(&device_tree, &drivers_list)) {
-		log_msg(LVL_FATAL, "Failed to initialize device tree.");
+		log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to initialize device tree.");
 		return false;
 	}
@@ -1428,5 +1428,5 @@
 	printf("%s: HelenOS Device Manager\n", NAME);
 	
-	int rc = log_init(NAME, LVL_WARN);
+	int rc = log_init(NAME);
 	if (rc != EOK) {
 		printf("%s: Error initializing logging subsystem.\n", NAME);
@@ -1440,5 +1440,5 @@
 	
 	if (!devman_init()) {
-		log_msg(LVL_ERROR, "Error while initializing service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error while initializing service.");
 		return -1;
 	}
@@ -1447,5 +1447,5 @@
 	rc = service_register(SERVICE_DEVMAN);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering as a service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering as a service.");
 		return rc;
 	}
Index: uspace/srv/fs/cdfs/cdfs_ops.c
===================================================================
--- uspace/srv/fs/cdfs/cdfs_ops.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/fs/cdfs/cdfs_ops.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -267,5 +267,5 @@
 	.key_hash = nodes_key_hash,
 	.key_equal = nodes_key_equal,
-	.equal = 0,
+	.equal = NULL,
 	.remove_callback = nodes_remove_callback
 };
Index: uspace/srv/fs/exfat/exfat_idx.c
===================================================================
--- uspace/srv/fs/exfat/exfat_idx.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/fs/exfat/exfat_idx.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -156,6 +156,6 @@
 	.key_hash = pos_key_hash,
 	.key_equal = pos_key_equal,
-	.equal = 0,
-	.remove_callback = 0,
+	.equal = NULL,
+	.remove_callback = NULL,
 };
 
@@ -202,5 +202,5 @@
 	.key_hash = idx_key_hash,
 	.key_equal = idx_key_equal,
-	.equal = 0,
+	.equal = NULL,
 	.remove_callback = idx_remove_callback,
 };
Index: uspace/srv/fs/ext2fs/ext2fs_ops.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -157,6 +157,6 @@
 	.key_hash = open_nodes_key_hash,
 	.key_equal = open_nodes_key_equal,
-	.equal = 0,
-	.remove_callback = 0,
+	.equal = NULL,
+	.remove_callback = NULL,
 };
 
Index: uspace/srv/fs/ext4fs/ext4fs_ops.c
===================================================================
--- uspace/srv/fs/ext4fs/ext4fs_ops.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/fs/ext4fs/ext4fs_ops.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -49,5 +49,4 @@
 #define EXT4FS_NODE(node) \
 	((node) ? (ext4fs_node_t *) (node)->data : NULL)
-
 
 /**
@@ -141,6 +140,6 @@
 	.key_hash = open_nodes_key_hash,
 	.key_equal = open_nodes_key_equal,
-	.equal = 0,
-	.remove_callback = 0,
+	.equal = NULL,
+	.remove_callback = NULL,
 };
 
Index: uspace/srv/fs/fat/fat_idx.c
===================================================================
--- uspace/srv/fs/fat/fat_idx.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/fs/fat/fat_idx.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -156,6 +156,6 @@
 	.key_hash = pos_key_hash,
 	.key_equal = pos_key_equal,
-	.equal = 0,
-	.remove_callback = 0,
+	.equal = NULL,
+	.remove_callback = NULL,
 };
 
@@ -202,5 +202,5 @@
 	.key_hash = idx_key_hash,
 	.key_equal = idx_key_equal,
-	.equal = 0,
+	.equal = NULL,
 	.remove_callback = idx_remove_callback,
 };
Index: uspace/srv/fs/locfs/locfs_ops.c
===================================================================
--- uspace/srv/fs/locfs/locfs_ops.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/fs/locfs/locfs_ops.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -99,5 +99,5 @@
 	.key_hash = services_key_hash,
 	.key_equal = services_key_equal,
-	.equal = 0, 
+	.equal = NULL, 
 	.remove_callback = services_remove_callback
 };
Index: uspace/srv/fs/mfs/mfs_ops.c
===================================================================
--- uspace/srv/fs/mfs/mfs_ops.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/fs/mfs/mfs_ops.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -122,6 +122,6 @@
 	.key_hash = open_nodes_key_hash,
 	.key_equal = open_nodes_key_equal,
-	.equal = 0,
-	.remove_callback = 0,
+	.equal = NULL,
+	.remove_callback = NULL,
 };
 
Index: uspace/srv/fs/tmpfs/tmpfs_ops.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -196,5 +196,5 @@
 	.key_hash = nodes_key_hash,
 	.key_equal = nodes_key_equal,
-	.equal = 0,
+	.equal = NULL,
 	.remove_callback = nodes_remove_callback
 };
Index: uspace/srv/fs/udf/Makefile
===================================================================
--- uspace/srv/fs/udf/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# Copyright (c) 2012 Julia Medvedeva
+# 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.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a
+EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX)
+BINARY = udf
+
+SOURCES = \
+	udf.c \
+	udf_volume.c \
+	udf_ops.c \
+	udf_osta.c \
+	udf_cksum.c \
+	udf_file.c \
+	udf_idx.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/fs/udf/udf.c
===================================================================
--- uspace/srv/fs/udf/udf.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2006 Martin Decky
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf.c
+ * @brief UDF 1.02 file system driver for HelenOS.
+ */
+
+#include <ipc/services.h>
+#include <ns.h>
+#include <async.h>
+#include <errno.h>
+#include <unistd.h>
+#include <task.h>
+#include <libfs.h>
+#include <str.h>
+#include <io/log.h>
+#include "../../vfs/vfs.h"
+#include "udf.h"
+#include "udf_idx.h"
+
+#define NAME  "udf"
+
+vfs_info_t udf_vfs_info = {
+	.name = NAME,
+	.concurrent_read_write = false,
+	.write_retains_size = false,
+	.instance = 0,
+};
+
+int main(int argc, char *argv[])
+{
+	log_init(NAME);
+	log_msg(LOG_DEFAULT, LVL_NOTE, "HelenOS UDF 1.02 file system server");
+	
+	if (argc == 3) {
+		if (!str_cmp(argv[1], "--instance"))
+			udf_vfs_info.instance = strtol(argv[2], NULL, 10);
+		else {
+			log_msg(LOG_DEFAULT, LVL_FATAL, "Unrecognized parameters");
+			return 1;
+		}
+	}
+	
+	async_sess_t *vfs_sess =
+	    service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_VFS, 0, 0);
+	if (!vfs_sess) {
+		log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to connect to VFS");
+		return 2;
+	}
+	
+	int rc = fs_register(vfs_sess, &udf_vfs_info, &udf_ops,
+	    &udf_libfs_ops);
+	if (rc != EOK)
+		goto err;
+	
+	rc = udf_idx_init();
+	if (rc != EOK)
+		goto err;
+	
+	log_msg(LOG_DEFAULT, LVL_NOTE, "Accepting connections");
+	task_retval(0);
+	async_manager();
+	
+	/* Not reached */
+	return 0;
+	
+err:
+	log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to register file system (%d)", rc);
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf.h
===================================================================
--- uspace/srv/fs/udf/udf.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+
+#ifndef UDF_UDF_H_
+#define UDF_UDF_H_
+
+#include <fibril_synch.h>
+#include <libfs.h>
+#include <atomic.h>
+#include <sys/types.h>
+#include <bool.h>
+#include "../../vfs/vfs.h"
+#include "udf_types.h"
+#include <adt/hash_table.h>
+
+#define UDF_NODE(node) \
+	((node) ? (udf_node_t *) (node)->data : NULL)
+
+#define FS_NODE(node) \
+	((node) ? (fs_node_t *) ((node)->fs_node) : NULL)
+
+#define BS_BLOCK     0
+#define MIN_SIZE     512
+#define MAX_SIZE     8192
+#define DEFAULT_VOL  0
+
+#define NODE_DIR   0
+#define NODE_FILE  1
+
+#define MAX_FILE_NAME_LEN  512
+
+#define MIN_FID_LEN  38
+
+#define SPACE_TABLE   0
+#define SPACE_BITMAP  1
+
+typedef struct udf_partition {
+	/* Partition info */
+	uint16_t number;
+	uint32_t access_type;
+	uint32_t start;
+	uint32_t lenght;
+} udf_partition_t;
+
+typedef struct udf_lvolume {
+	udf_partition_t **partitions;
+	size_t partition_cnt;
+	uint32_t logical_block_size;
+	fs_index_t root_dir;
+} udf_lvolume_t;
+
+typedef struct {
+	service_id_t service_id;
+	size_t open_nodes_count;
+	udf_charspec_t charset;
+	
+	uint32_t sector_size;
+	udf_lvolume_t *volumes;
+	udf_partition_t *partitions;
+	size_t partition_cnt;
+	udf_unallocated_space_descriptor_t *uasd;
+	uint64_t uaspace_start;
+	uint64_t uaspace_lenght;
+	uint8_t space_type;
+} udf_instance_t;
+
+typedef struct udf_allocator {
+	uint32_t length;
+	uint32_t position;
+} udf_allocator_t;
+
+typedef struct udf_node {
+	udf_instance_t *instance;
+	fs_node_t *fs_node;
+	fibril_mutex_t lock;
+	
+	fs_index_t index;  /* FID logical block */
+	ht_link_t link;
+	size_t ref_cnt;
+	size_t link_cnt;
+	
+	uint8_t type;  /* 1 - file, 0 - directory */
+	uint64_t data_size;
+	uint8_t *data;
+	udf_allocator_t *allocators;
+	size_t alloc_size;
+} udf_node_t;
+
+extern vfs_out_ops_t udf_ops;
+extern libfs_ops_t udf_libfs_ops;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_cksum.c
===================================================================
--- uspace/srv/fs/udf/udf_cksum.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf_cksum.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf_cksum.c
+ * @brief Implementation of various checksum functions.
+ */
+
+#include "udf_cksum.h"
+
+/** CRC 010041 */
+static uint16_t crc_table[256] = {
+	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+	0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+	0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+	0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+	0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+	0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+	0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+	0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+	0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+	0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+	0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+	0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+	0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+	0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+	0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+	0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+	0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+	0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+	0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+	0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+	0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+	0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+	0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+	0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+	0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+	0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+	0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+	0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+	0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+	0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+	0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+	0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+};
+
+/** Unicode checksum
+ *
+ */
+uint16_t udf_unicode_cksum(uint16_t *buf, size_t len)
+{
+	uint16_t crc = 0;
+	
+	while (len-- > 0) {
+		/*
+		 * Take high order byte first (corresponds to a big endian
+		 * byte stream).
+		 */
+		crc = crc_table[(crc >> 8 ^ (*buf >> 8)) & 0xff] ^ (crc << 8);
+		crc = crc_table[(crc >> 8 ^ (*buf++ & 0xff)) & 0xff] ^ (crc << 8);
+	}
+	
+	return crc;
+}
+
+/** Calculate descriptor tag checksum
+ *
+ */
+uint8_t udf_tag_checksum(uint8_t *tag)
+{
+	uint8_t result = 0;
+	
+	for (size_t i = 0; i < UDF_TAG_SIZE; i++) {
+		if (i == 4)
+			continue;
+		
+		result = (result + tag[i]) % 256;
+	}
+	
+	return result;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_cksum.h
===================================================================
--- uspace/srv/fs/udf/udf_cksum.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf_cksum.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+
+#ifndef UDF_CKSUM_H_
+#define UDF_CKSUM_H_
+
+#include <sys/types.h>
+#include <bool.h>
+
+#define UDF_TAG_SIZE  16
+
+extern uint16_t udf_unicode_cksum(uint16_t *, size_t);
+extern uint8_t udf_tag_checksum(uint8_t *);
+
+#endif /* UDF_CKSUM_H_ */
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_file.c
===================================================================
--- uspace/srv/fs/udf/udf_file.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf_file.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,627 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf_file.c
+ * @brief Implementation of file operations. Reading and writing functions.
+ */
+
+#include <block.h>
+#include <libfs.h>
+#include <errno.h>
+#include <malloc.h>
+#include <inttypes.h>
+#include <io/log.h>
+#include <mem.h>
+#include "udf.h"
+#include "udf_file.h"
+#include "udf_cksum.h"
+#include "udf_volume.h"
+
+/** Read extended allocator in allocation sequence
+ *
+ * @paran node     UDF node
+ * @param icb_flag Type of allocators in sequence.
+ *                 According to ECMA 167 4/14.8.8
+ * @param pos      Position with which we read
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_read_extended_allocator(udf_node_t *node, uint16_t icb_flag,
+    uint32_t pos)
+{
+	block_t *block = NULL;
+	int rc = block_get(&block, node->instance->service_id, pos,
+	    BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return rc;
+	
+	udf_ext_ad_t *exd = (udf_ext_ad_t *) block->data;
+	uint32_t start = node->instance->partitions[
+	    FLE16(exd->extent_location.partition_num)].start +
+	    FLE32(exd->extent_location.lblock_num);
+	
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
+	    "Extended allocator: start=%d, block_num=%d, len=%d", start,
+	    FLE32(exd->extent_location.lblock_num), FLE32(exd->info_length));
+	
+	uint32_t len = FLE32(exd->info_length);
+	block_put(block);
+	
+	return udf_read_allocation_sequence(node, NULL, icb_flag, start, len);
+}
+
+/** Read ICB sequence of allocators in (Extended) File entry descriptor
+ *
+ * @parem node     UDF node
+ * @param af       (Extended) File entry descriptor
+ * @param icb_flag Type of allocators in sequence.
+ *                 According to ECMA 167 4/14.8.8
+ * @param start_alloc Offset of the allocator
+ * @param len         Length of sequence
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_read_allocation_sequence(udf_node_t *node, uint8_t *af,
+    uint16_t icb_flag, uint32_t start_alloc, uint32_t len)
+{
+	node->alloc_size = 0;
+	
+	switch (icb_flag) {
+	case UDF_SHORT_AD:
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
+		    "ICB: sequence of allocation descriptors - icbflag = short_ad_t");
+		
+		/*
+		 * Identify number of current partition. Virtual partition
+		 * could placed inside of physical partition. It means that same
+		 * sector could be inside of both partition physical and virtual.
+		 */
+		size_t pd_num = (size_t) -1;
+		size_t min_start = 0;
+		
+		for (size_t i = 0; i < node->instance->partition_cnt; i++) {
+			if ((node->index >= node->instance->partitions[i].start) &&
+			    (node->index < node->instance->partitions[i].start +
+			    node->instance->partitions[i].lenght)) {
+				if (node->instance->partitions[i].start >= min_start) {
+					min_start = node->instance->partitions[i].start;
+					pd_num = i;
+				}
+			}
+		}
+		
+		if (pd_num == (size_t) -1)
+			return ENOENT;
+		
+		/*
+		 * According to doc, in this we should stop our loop if pass
+		 * all allocators. Count of items in sequence of allocators
+		 * cnt = len / sizeof(udf_long_ad_t)
+		 * But in case of Blu-Ray data len could be zero.
+		 * It means that we have only two conditions for stopping
+		 * which we check inside of loop.
+		 */
+		
+		while (true) {
+			udf_short_ad_t *short_d =
+			    (udf_short_ad_t *) (af + start_alloc +
+			    node->alloc_size * sizeof(udf_short_ad_t));
+			
+			if (FLE32(short_d->length) == 0)
+				break;
+			
+			/*
+			 * ECMA 167 4/12 - next sequence of allocation descriptors
+			 * condition according to 167 4/14.6.8
+			 */
+			if (FLE32(short_d->length) >> 30 == 3) {
+				udf_read_extended_allocator(node, icb_flag,
+				    node->instance->partitions[pd_num].start +
+				    FLE32(short_d->position));
+				break;
+			}
+			
+			node->allocators = realloc(node->allocators,
+			    (node->alloc_size + 1) * sizeof(udf_allocator_t));
+			node->allocators[node->alloc_size].length =
+			    EXT_LENGTH(FLE32(short_d->length));
+			node->allocators[node->alloc_size].position =
+			    node->instance->partitions[pd_num].start + FLE32(short_d->position);
+			node->alloc_size++;
+		}
+		
+		node->allocators = realloc(node->allocators,
+		    node->alloc_size * sizeof(udf_allocator_t));
+		break;
+		
+	case UDF_LONG_AD:
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
+		    "ICB: sequence of allocation descriptors - icbflag = long_ad_t");
+		
+		while (true) {
+			udf_long_ad_t *long_d =
+			    (udf_long_ad_t *) (af + start_alloc +
+			    node->alloc_size * sizeof(udf_long_ad_t));
+			
+			if (FLE32(long_d->length) == 0)
+				break;
+			
+			uint32_t pos_long_ad = udf_long_ad_to_pos(node->instance, long_d);
+			
+			/*
+			 * ECMA 167 4/12 - next sequence of allocation descriptors
+			 * condition according to 167 4/14.6.8
+			 */
+			if (FLE32(long_d->length) >> 30 == 3) {
+				udf_read_extended_allocator(node, icb_flag, pos_long_ad);
+				break;
+			}
+			
+			node->allocators = realloc(node->allocators,
+			    (node->alloc_size + 1) * sizeof(udf_allocator_t));
+			node->allocators[node->alloc_size].length =
+			    EXT_LENGTH(FLE32(long_d->length));
+			node->allocators[node->alloc_size].position = pos_long_ad;
+			
+			node->alloc_size++;
+		}
+		
+		node->allocators = realloc(node->allocators,
+		    node->alloc_size * sizeof(udf_allocator_t));
+		break;
+		
+	case UDF_EXTENDED_AD:
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
+		    "ICB: sequence of allocation descriptors - icbflag = extended_ad_t");
+		break;
+		
+	case UDF_DATA_AD:
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
+		    "ICB: sequence of allocation descriptors - icbflag = 3, node contains data itself");
+		
+		node->data = malloc(node->data_size);
+		if (!node->data)
+			return ENOMEM;
+		
+		memcpy(node->data, (af + start_alloc), node->data_size);
+		node->alloc_size = 0;
+		break;
+	}
+	
+	return EOK;
+}
+
+/** Read ICB sequence of descriptors
+ *
+ * Read sequence of descriptors (file entry descriptors or
+ * extended file entry descriptors). Each descriptor contains
+ * sequence of allocators.
+ *
+ * @param node    UDF node
+ *
+ * @return    EOK on success or a negative error code.
+ */
+int udf_read_icb(udf_node_t *node)
+{
+	while (true) {
+		fs_index_t pos = node->index;
+		
+		block_t *block = NULL;
+		int rc = block_get(&block, node->instance->service_id, pos,
+		    BLOCK_FLAGS_NONE);
+		if (rc != EOK)
+			return rc;
+		
+		udf_descriptor_tag_t *data = (udf_descriptor_tag_t *) block->data;
+		if (data->checksum != udf_tag_checksum((uint8_t *) data)) {
+			block_put(block);
+			return EINVAL;
+		}
+		
+		/* One sector size descriptors */
+		switch (FLE16(data->id)) {
+		case UDF_FILE_ENTRY:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: File entry descriptor found");
+			
+			udf_file_entry_descriptor_t *file =
+			    (udf_file_entry_descriptor_t *) block->data;
+			uint16_t icb_flag = FLE16(file->icbtag.flags) & UDF_ICBFLAG_MASK;
+			node->data_size = FLE64(file->info_lenght);
+			node->type = (file->icbtag.file_type == UDF_ICBTYPE_DIR) ? NODE_DIR : NODE_FILE;
+			
+			rc = udf_read_allocation_sequence(node, (uint8_t *) file, icb_flag,
+			    FLE32(file->ea_lenght) + UDF_FE_OFFSET, FLE32(file->ad_lenght));
+			block_put(block);
+			return rc;
+			
+		case UDF_EFILE_ENTRY:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Extended file entry descriptor found");
+			
+			udf_extended_file_entry_descriptor_t *efile =
+			    (udf_extended_file_entry_descriptor_t *) block->data;
+			icb_flag = FLE16(efile->icbtag.flags) & UDF_ICBFLAG_MASK;
+			node->data_size = FLE64(efile->info_lenght);
+			node->type = (efile->icbtag.file_type == UDF_ICBTYPE_DIR) ? NODE_DIR : NODE_FILE;
+			
+			rc = udf_read_allocation_sequence(node, (uint8_t *) efile, icb_flag,
+			    FLE32(efile->ea_lenght) + UDF_EFE_OFFSET, FLE32(efile->ad_lenght));
+			block_put(block);
+			return rc;
+			
+		case UDF_ICB_TERMINAL:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Terminal entry descriptor found");
+			block_put(block);
+			return EOK;
+		}
+		
+		pos++;
+		
+		rc = block_put(block);
+		if (rc != EOK)
+			return rc;
+	}
+	
+	return EOK;
+}
+
+/** Read data from disk - filling UDF node by allocators
+ *
+ * @param node UDF node
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_node_get_core(udf_node_t *node)
+{
+	node->link_cnt = 1;
+	return udf_read_icb(node);
+}
+
+/** Read directory entry if all FIDs is saved inside of descriptor
+ *
+ * @param fid  Returned value
+ * @param node UDF node
+ * @param pos  Number of FID which we need to find
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_get_fid_in_data(udf_file_identifier_descriptor_t **fid,
+    udf_node_t *node, aoff64_t pos)
+{
+	size_t fid_sum = 0;
+	size_t n = 0;
+	
+	while (node->data_size - fid_sum >= MIN_FID_LEN) {
+		udf_descriptor_tag_t *desc =
+		    (udf_descriptor_tag_t *) (node->data + fid_sum);
+		if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
+			if (fid_sum == 0)
+				return EINVAL;
+			else
+				return ENOENT;
+		}
+		
+		*fid = (udf_file_identifier_descriptor_t *)
+		    (node->data + fid_sum);
+		
+		/* According to ECMA 167 4/14.4.9 */
+		size_t padding = 4 * (((*fid)->lenght_file_id +
+		    FLE16((*fid)->lenght_iu) + 38 + 3) / 4) -
+		    ((*fid)->lenght_file_id + FLE16((*fid)->lenght_iu) + 38);
+		size_t size_fid = (*fid)->lenght_file_id +
+		    FLE16((*fid)->lenght_iu) + padding + 38;
+		
+		fid_sum += size_fid;
+		
+		/* aAcording to ECMA 167 4/8.6 */
+		if (((*fid)->lenght_file_id != 0) &&
+		    (((*fid)->file_characteristics & 4) == 0)) {
+			n++;
+			
+			if (n == pos + 1)
+				return EOK;
+		}
+	}
+	
+	return ENOENT;
+}
+
+/** Read directory entry
+ *
+ * @param fid   Returned value
+ * @param block Returned value
+ * @param node  UDF node
+ * @param pos   Number of FID which we need to find
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_get_fid(udf_file_identifier_descriptor_t **fid, block_t **block,
+    udf_node_t *node, aoff64_t pos)
+{
+	if (node->data == NULL)
+		return udf_get_fid_in_allocator(fid, block, node, pos);
+	
+	return udf_get_fid_in_data(fid, node, pos);
+}
+
+/** Read directory entry if all FIDS is saved in allocators.
+ *
+ * @param fid   Returned value
+ * @param block Returned value
+ * @param node  UDF node
+ * @param pos   Number of FID which we need to find
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_get_fid_in_allocator(udf_file_identifier_descriptor_t **fid,
+    block_t **block, udf_node_t *node, aoff64_t pos)
+{
+	void *buf = malloc(node->instance->sector_size);
+	
+	// FIXME: Check for NULL return value
+	
+	size_t j = 0;
+	size_t n = 0;
+	size_t len = 0;
+	
+	while (j < node->alloc_size) {
+		size_t i = 0;
+		while (i * node->instance->sector_size < node->allocators[j].length) {
+			int rc = block_get(block, node->instance->service_id,
+			    node->allocators[j].position + i, BLOCK_FLAGS_NONE);
+			if (rc != EOK) {
+				// FIXME: Memory leak
+				return rc;
+			}
+			
+			/*
+			 * Last item in allocator is a part of sector. We take
+			 * this fragment and join it to part of sector in next allocator.
+			 */
+			if ((node->allocators[j].length / node->instance->sector_size == i) &&
+			    (node->allocators[j].length - i * node->instance->sector_size <
+			    MIN_FID_LEN)) {
+				size_t len = node->allocators[j].length - i * node->instance->sector_size;
+				memcpy(buf, (*block)->data, len);
+				block_put(*block);
+				*block = NULL;
+				break;
+			}
+			
+			rc = udf_get_fid_in_sector(fid, block, node, pos, &n, &buf, &len);
+			if (rc == EOK) {
+				// FIXME: Memory leak
+				return EOK;
+			}
+			
+			if (rc == EINVAL) {
+				// FIXME: Memory leak
+				return ENOENT;
+			}
+			
+			if (rc == ENOENT) {
+				if (block) {
+					rc = block_put(*block);
+					*block = NULL;
+					
+					if (rc != EOK)
+						return rc;
+				}
+			}
+			
+			i++;
+		}
+		
+		j++;
+	}
+	
+	if (buf)
+		free(buf);
+	
+	return ENOENT;
+}
+
+/** Read FIDs in sector inside of current allocator
+ *
+ * @param fid   Returned value.
+ * @param block Returned value
+ * @param node  UDF node
+ * @param pos   Number FID which we need to find
+ * @param n     Count of FIDs which we already have passed
+ * @param buf   Part of FID from last sector (current allocator or previous)
+ * @param len   Length of buf
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_get_fid_in_sector(udf_file_identifier_descriptor_t **fid,
+    block_t **block, udf_node_t *node, aoff64_t pos, size_t *n, void **buf,
+    size_t *len)
+{
+	void *fidbuf = malloc(node->instance->sector_size);
+	
+	// FIXME: Check for NULL return value
+	
+	bool buf_flag;
+	
+	if (*len > 0) {
+		memcpy(fidbuf, *buf, *len);
+		buf_flag = true;
+	} else
+		buf_flag = false;
+	
+	size_t fid_sum = 0;
+	while (node->instance->sector_size - fid_sum > 0) {
+		if (node->instance->sector_size - fid_sum >= MIN_FID_LEN) {
+			void *fid_data;
+			
+			if (buf_flag) {
+				memcpy((fidbuf + *len), (*block)->data,
+				    node->instance->sector_size - *len);
+				fid_data = fidbuf;
+			} else
+				fid_data = (*block)->data + fid_sum;
+			
+			udf_descriptor_tag_t *desc =
+			    (udf_descriptor_tag_t *) fid_data;
+			
+			if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
+				if (fidbuf)
+					free(fidbuf);
+				
+				if (*buf) {
+					free(*buf);
+					*buf = NULL;
+					*len = 0;
+				}
+				
+				return EINVAL;
+			}
+			
+			*fid = (udf_file_identifier_descriptor_t *) fid_data;
+			
+			/* According to ECMA 167 4/14.4.9 */
+			size_t padding = 4 * (((*fid)->lenght_file_id +
+			    FLE16((*fid)->lenght_iu) + 38 + 3) / 4) -
+			    ((*fid)->lenght_file_id + FLE16((*fid)->lenght_iu) + 38);
+			size_t size_fid = (*fid)->lenght_file_id +
+			    FLE16((*fid)->lenght_iu) + padding + 38;
+			if (buf_flag)
+				fid_sum += size_fid - *len;
+			else
+				fid_sum += size_fid;
+			
+			/* According to ECMA 167 4/8.6 */
+			if (((*fid)->lenght_file_id != 0) &&
+			    (((*fid)->file_characteristics & 4) == 0)) {
+				(*n)++;
+				if (*n == pos + 1) {
+					if (fidbuf)
+						free(fidbuf);
+					
+					return EOK;
+				}
+			}
+			
+			if (fidbuf) {
+				buf_flag = false;
+				free(fidbuf);
+				fidbuf = NULL;
+			}
+			
+			if (*buf) {
+				free(*buf);
+				*buf = NULL;
+				*len = 0;
+			}
+		} else {
+			if (*buf)
+				free(*buf);
+			
+			*len = node->instance->sector_size - fid_sum;
+			*buf = malloc(*len);
+			buf_flag = false;
+			memcpy(*buf, ((*block)->data + fid_sum), *len);
+			
+			return ENOENT;
+		}
+	}
+	
+	return ENOENT;
+}
+
+/** Read file if it is saved in allocators.
+ *
+ * @param read_len Returned value. Length file or part file which we could read.
+ * @param callid
+ * @param node     UDF node
+ * @param pos      Position in file since we have to read.
+ * @param len      Length of data for reading
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_read_file(size_t *read_len, ipc_callid_t callid, udf_node_t *node,
+    aoff64_t pos, size_t len)
+{
+	size_t i = 0;
+	size_t l = 0;
+	
+	while (i < node->alloc_size) {
+		if (pos >= l + node->allocators[i].length) {
+			l += node->allocators[i].length;
+			i++;
+		} else
+			break;
+	}
+	
+	size_t sector_cnt = ALL_UP(l, node->instance->sector_size);
+	size_t sector_num = pos / node->instance->sector_size;
+	
+	block_t *block = NULL;
+	int rc = block_get(&block, node->instance->service_id,
+	    node->allocators[i].position + (sector_num - sector_cnt),
+	    BLOCK_FLAGS_NONE);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return rc;
+	}
+	
+	size_t sector_pos = pos % node->instance->sector_size;
+	
+	if (sector_pos + len < node->instance->sector_size)
+		*read_len = len;
+	else
+		*read_len = node->instance->sector_size - sector_pos;
+	
+	if (ALL_UP(node->allocators[i].length, node->instance->sector_size) ==
+	    sector_num - sector_cnt + 1) {
+		if (pos + len > node->allocators[i].length + l)
+			*read_len = node->allocators[i].length -
+			    (sector_num - sector_cnt) * node->instance->sector_size -
+			    sector_pos;
+		else
+			*read_len = len;
+	}
+	
+	async_data_read_finalize(callid, block->data + sector_pos, *read_len);
+	return block_put(block);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_file.h
===================================================================
--- uspace/srv/fs/udf/udf_file.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf_file.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+
+#ifndef UDF_FILE_H_
+#define UDF_FILE_H_
+
+#include <sys/types.h>
+#include <ipc/loc.h>
+#include <block.h>
+#include "udf_types.h"
+
+#define UDF_TAG_FILESET  256
+#define UDF_TAG_FILEID   257
+
+#define UDF_ICB_TERMINAL   260
+#define UDF_FILE_ENTRY     261
+#define UDF_UASPACE_ENTRY  263
+#define UDF_SPACE_BITMAP   264
+#define UDF_EFILE_ENTRY    266
+
+#define UDF_FE_OFFSET   176
+#define UDF_EFE_OFFSET  216
+#define UDF_SB_OFFSET   24
+
+/* ECMA 4/14.11 */
+#define UDF_UASE_OFFSET  40
+
+/* ECMA 167 4/14.6.8 */
+#define UDF_ICBFLAG_MASK  7
+
+/* ECMA 167 4/17 */
+#define UDF_ICBTYPE_UASE  1
+#define UDF_ICBTYPE_DIR   4
+
+/* ECMA 167 4/14.6.8 */
+#define UDF_SHORT_AD     0
+#define UDF_LONG_AD      1
+#define UDF_EXTENDED_AD  2
+
+/* File in allocation descriptor */
+#define UDF_DATA_AD  3
+
+/* File Set Descriptor (ECMA 167 4/14.1) */
+typedef struct udf_fileset_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_timestamp_t recording_date_and_time;
+	uint16_t interchange_level;
+	uint16_t max_interchange_level;
+	uint32_t charset_list;
+	uint32_t max_charset_list;
+	uint32_t fileset_number;
+	uint32_t fileset_descriptor_number;
+	udf_charspec_t logical_volume_id_charset;
+	udf_dstring logical_volume_id[128];
+	udf_charspec_t fileset_charset;
+	udf_dstring fileset_id[32];
+	udf_dstring copyright_file_id[32];
+	udf_dstring abstract_file_id[32];
+	udf_long_ad_t root_dir_icb;
+	udf_regid_t domain_id;
+	udf_long_ad_t next_extent;
+	udf_long_ad_t system_stream_dir_icb;
+	uint8_t reserved[32];
+} __attribute__((packed)) udf_fileset_descriptor_t;
+
+/* File identifier descriptor format (ECMA 167 4/14.4) */
+typedef struct udf_file_identifier_descriptor {
+	udf_descriptor_tag_t tag;
+	uint16_t file_version_number;
+	uint8_t file_characteristics;
+	uint8_t lenght_file_id;
+	udf_long_ad_t icb;
+	uint16_t lenght_iu;
+	uint8_t implementation_use[0];
+	udf_dstring file_id[0];
+}__attribute__((packed)) udf_file_identifier_descriptor_t;
+
+/* ICB tag - Information Control Block  (ECMA 167 4/14.6) */
+typedef struct udf_icbtag {
+	uint32_t prior_recorder_nimber;
+	uint16_t strategy_type;
+	uint8_t strategy_parameter[2];
+	uint16_t max_number;
+	uint8_t reserved[1];
+	uint8_t file_type;
+	udf_lb_addr_t parent_icb;
+	uint16_t flags;
+} __attribute__((packed)) udf_icbtag_t;
+
+/* File Entry format (ECMA 167 4/14.9) */
+typedef struct udf_file_entry_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_icbtag_t icbtag;
+	uint32_t uid;
+	uint32_t gid;
+	uint32_t permission;
+	uint16_t file_link_count;
+	uint8_t record_format;
+	uint8_t record_display_attributes;
+	uint32_t record_lenght;
+	uint64_t info_lenght;
+	uint64_t lblocks_recorded;
+	udf_timestamp_t access_data_and_time;
+	udf_timestamp_t mod_data_and_time;
+	udf_timestamp_t attribute_data_and_time;
+	uint32_t checkpoint;
+	udf_long_ad_t extended_attribute_icb;
+	udf_regid_t implementation_id;
+	uint64_t unique_id;
+	uint32_t ea_lenght;
+	uint32_t ad_lenght;
+	uint8_t extended_attributes [0];
+	uint8_t allocation_descriptors[0];
+} __attribute__((packed)) udf_file_entry_descriptor_t;
+
+/* Extended File Entry format (ECMA 167 4/14.17) */
+typedef struct udf_extended_file_entry_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_icbtag_t icbtag;
+	uint32_t uid;
+	uint32_t gid;
+	uint32_t permission;
+	uint16_t file_link_count;
+	uint8_t record_format;
+	uint8_t record_display_attributes;
+	uint32_t record_lenght;
+	uint64_t info_lenght;
+	uint64_t object_size;
+	uint64_t lblocks_recorded;
+	udf_timestamp_t access_data_and_time;
+	udf_timestamp_t mod_data_and_time;
+	udf_timestamp_t creation_data_and_time;
+	udf_timestamp_t attribute_data_and_time;
+	uint32_t checkpoint;
+	udf_long_ad_t extended_attribute_icb;
+	udf_regid_t implementation_id;
+	uint64_t unique_id;
+	uint32_t ea_lenght;
+	uint32_t ad_lenght;
+	uint8_t extended_attributes [0];
+	uint8_t allocation_descriptors[0];
+} __attribute__((packed)) udf_extended_file_entry_descriptor_t;
+
+/* Terminal Entry Descriptor (ECMA 167 4/14.8) */
+typedef struct terminal_entry_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_icbtag_t icbtag;
+} __attribute__((packed)) udf_terminal_entry_descriptor;
+
+/* Unallocated Space Entry format (ECMA 167 4/14.11)*/
+typedef struct udf_unallocated_space_entry_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_icbtag_t icbtag;
+	uint32_t ad_lenght;
+	uint8_t allocation_descriptors[0];
+}__attribute__((packed)) udf_unallocated_space_entry_descriptor_t;
+
+/* Space Bitmap Descriptor format (ECMA 167 4/14.12) */
+typedef struct udf_space_bitmap_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t bits_number;
+	uint32_t byts_number;
+	uint8_t bitmap[0];
+}__attribute__((packed)) udf_space_bitmap_descriptor_t;
+
+extern int udf_node_get_core(udf_node_t *);
+extern int udf_read_icb(udf_node_t *);
+extern int udf_read_allocation_sequence(udf_node_t *, uint8_t *, uint16_t,
+    uint32_t, uint32_t);
+extern int udf_read_file(size_t *, ipc_callid_t, udf_node_t *, aoff64_t,
+    size_t);
+extern int udf_get_fid(udf_file_identifier_descriptor_t **, block_t **,
+    udf_node_t *, aoff64_t);
+extern int udf_get_fid_in_allocator(udf_file_identifier_descriptor_t **,
+    block_t **, udf_node_t *, aoff64_t);
+extern int udf_get_fid_in_sector(udf_file_identifier_descriptor_t **,
+    block_t **, udf_node_t *, aoff64_t, size_t *, void **, size_t *);
+
+#endif /* UDF_FILE_H_ */
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_idx.c
===================================================================
--- uspace/srv/fs/udf/udf_idx.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf_idx.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf_idx.c
+ * @brief Very simple UDF hashtable for nodes
+ */
+
+#include "../../vfs/vfs.h"
+#include <errno.h>
+#include <str.h>
+#include <assert.h>
+#include <fibril_synch.h>
+#include <malloc.h>
+#include <adt/hash_table.h>
+#include <adt/hash.h>
+#include <adt/list.h>
+#include <bool.h>
+#include "udf_idx.h"
+#include "udf.h"
+
+static FIBRIL_MUTEX_INITIALIZE(udf_idx_lock);
+
+static hash_table_t udf_idx;
+
+typedef struct {
+	service_id_t service_id;
+	fs_index_t index;
+} udf_ht_key_t; 
+
+static size_t udf_idx_hash(const ht_link_t *item)
+{
+	udf_node_t *node = hash_table_get_inst(item, udf_node_t, link);
+	return hash_combine(node->instance->service_id, node->index);
+}
+
+static size_t udf_idx_key_hash(void *k)
+{
+	udf_ht_key_t *key = (udf_ht_key_t *) k;
+	return hash_combine(key->service_id, key->index);
+}
+
+static bool udf_idx_key_equal(void *k, const ht_link_t *item)
+{
+	udf_ht_key_t *key = (udf_ht_key_t *) k;
+	udf_node_t *node = hash_table_get_inst(item, udf_node_t, link);
+
+	return (key->service_id == node->instance->service_id) &&
+	    (key->index == node->index);
+}
+
+static hash_table_ops_t udf_idx_ops = {
+	.hash = udf_idx_hash,
+	.key_hash = udf_idx_key_hash,
+	.key_equal = udf_idx_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL 
+};
+
+/** Initialization of hash table
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_init(void)
+{
+	if (!hash_table_create(&udf_idx, 0, 0, &udf_idx_ops))
+		return ENOMEM;
+	
+	return EOK;
+}
+
+/** Delete hash table
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_fini(void)
+{
+	hash_table_destroy(&udf_idx);
+	return EOK;
+}
+
+/** Get node from hash table
+ *
+ * @param udfn     Returned value - UDF node
+ * @param instance UDF instance
+ * @param index    Absolute position of ICB (sector)
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_get(udf_node_t **udfn, udf_instance_t *instance, fs_index_t index)
+{
+	fibril_mutex_lock(&udf_idx_lock);
+
+	udf_ht_key_t key = {
+		.service_id = instance->service_id,
+		.index = index
+	};
+	
+	ht_link_t *already_open = hash_table_find(&udf_idx, &key);
+	if (already_open) {
+		udf_node_t *node = hash_table_get_inst(already_open,
+		    udf_node_t, link);
+		node->ref_cnt++;
+		
+		*udfn = node;
+		
+		fibril_mutex_unlock(&udf_idx_lock);
+		return EOK;
+	}
+	
+	fibril_mutex_unlock(&udf_idx_lock);
+	return ENOENT;
+}
+
+/** Create new node in hash table
+ *
+ * @param udfn     Returned value - new UDF node
+ * @param instance UDF instance
+ * @param index    Absolute position of ICB (sector)
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_add(udf_node_t **udfn, udf_instance_t *instance, fs_index_t index)
+{
+	fibril_mutex_lock(&udf_idx_lock);
+	
+	udf_node_t *udf_node = malloc(sizeof(udf_node_t));
+	if (udf_node == NULL) {
+		fibril_mutex_unlock(&udf_idx_lock);
+		return ENOMEM;
+	}
+	
+	fs_node_t *fs_node = malloc(sizeof(fs_node_t));
+	if (fs_node == NULL) {
+		free(udf_node);
+		fibril_mutex_unlock(&udf_idx_lock);
+		return ENOMEM;
+	}
+	
+	fs_node_initialize(fs_node);
+	
+	udf_node->index = index;
+	udf_node->instance = instance;
+	udf_node->ref_cnt = 1;
+	udf_node->link_cnt = 0;
+	udf_node->fs_node = fs_node;
+	udf_node->data = NULL;
+	udf_node->allocators = NULL;
+	
+	fibril_mutex_initialize(&udf_node->lock);
+	fs_node->data = udf_node;
+	
+	hash_table_insert(&udf_idx, &udf_node->link);
+	instance->open_nodes_count++;
+	
+	*udfn = udf_node;
+	
+	fibril_mutex_unlock(&udf_idx_lock);
+	return EOK;
+}
+
+/** Delete node from hash table
+ *
+ * @param node UDF node
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_del(udf_node_t *node)
+{
+	assert(node->ref_cnt == 0);
+	
+	fibril_mutex_lock(&udf_idx_lock);
+	
+	hash_table_remove_item(&udf_idx, &node->link);
+	
+	assert(node->instance->open_nodes_count > 0);
+	node->instance->open_nodes_count--;
+	
+	free(node->fs_node);
+	free(node);
+	
+	fibril_mutex_unlock(&udf_idx_lock);
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_idx.h
===================================================================
--- uspace/srv/fs/udf/udf_idx.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf_idx.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+
+#ifndef UDF_IDX_H_
+#define UDF_IDX_H_
+
+#include "udf.h"
+
+extern int udf_idx_init(void);
+extern int udf_idx_fini(void);
+extern int udf_idx_get(udf_node_t **, udf_instance_t *, fs_index_t);
+extern int udf_idx_add(udf_node_t **, udf_instance_t *, fs_index_t);
+extern int udf_idx_del(udf_node_t *);
+
+#endif /* UDF_IDX_H_ */
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_ops.c
===================================================================
--- uspace/srv/fs/udf/udf_ops.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf_ops.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf_ops.c
+ * @brief Implementation of VFS operations for the UDF file system
+ *        server.
+ */
+
+#include <libfs.h>
+#include <block.h>
+#include <ipc/services.h>
+#include <ipc/loc.h>
+#include <macros.h>
+#include <async.h>
+#include <errno.h>
+#include <str.h>
+#include <byteorder.h>
+#include <adt/hash_table.h>
+#include <adt/list.h>
+#include <assert.h>
+#include <fibril_synch.h>
+#include <sys/mman.h>
+#include <align.h>
+#include <malloc.h>
+#include <inttypes.h>
+#include <io/log.h>
+#include "../../vfs/vfs.h"
+#include "udf.h"
+#include "udf_cksum.h"
+#include "udf_volume.h"
+#include "udf_idx.h"
+#include "udf_file.h"
+#include "udf_osta.h"
+
+/** Mutex protecting the list of cached free nodes. */
+static FIBRIL_MUTEX_INITIALIZE(ffn_mutex);
+
+/** List of cached free nodes. */
+static LIST_INITIALIZE(ffn_list);
+
+static int udf_node_get(fs_node_t **rfn, service_id_t service_id,
+    fs_index_t index)
+{
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	udf_node_t *node;
+	rc = udf_idx_get(&node, instance, index);
+	if (rc != EOK) {
+		rc = udf_idx_add(&node, instance, index);
+		if (rc != EOK)
+			return rc;
+		
+		rc = udf_node_get_core(node);
+		if (rc != EOK) {
+			udf_idx_del(node);
+			return rc;
+		}
+	}
+	
+	*rfn = FS_NODE(node);
+	return EOK;
+}
+
+static int udf_root_get(fs_node_t **rfn, service_id_t service_id)
+{
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	return udf_node_get(rfn, service_id,
+	    instance->volumes[DEFAULT_VOL].root_dir);
+}
+
+static service_id_t udf_service_get(fs_node_t *node)
+{
+	udf_node_t *udfn = UDF_NODE(node);
+	if (udfn)
+		return udfn->instance->service_id;
+	
+	return 0;
+}
+
+static int udf_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
+{
+	char *name = malloc(MAX_FILE_NAME_LEN + 1);
+	if (name == NULL)
+		return ENOMEM;
+	
+	block_t *block = NULL;
+	udf_file_identifier_descriptor_t *fid = NULL;
+	size_t pos = 0;
+	
+	while (udf_get_fid(&fid, &block, UDF_NODE(pfn), pos) == EOK) {
+		udf_long_ad_t long_ad = fid->icb;
+		
+		udf_to_unix_name(name, MAX_FILE_NAME_LEN,
+		    (char *) fid->implementation_use + FLE16(fid->lenght_iu),
+		    fid->lenght_file_id, &UDF_NODE(pfn)->instance->charset);
+		
+		if (stricmp(name, component) == 0) {
+			int rc = udf_node_get(rfn, udf_service_get(pfn),
+			    udf_long_ad_to_pos(UDF_NODE(pfn)->instance, &long_ad));
+			
+			if (block != NULL)
+				block_put(block);
+			
+			free(name);
+			return rc;
+		}
+		
+		if (block != NULL) {
+			int rc = block_put(block);
+			if (rc != EOK)
+				return rc;
+		}
+		
+		pos++;
+	}
+	
+	free(name);
+	return ENOENT;
+}
+
+static int udf_node_open(fs_node_t *fn)
+{
+	return EOK;
+}
+
+static int udf_node_put(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (!node)
+		return EINVAL;
+	
+	fibril_mutex_lock(&node->lock);
+	node->ref_cnt--;
+	fibril_mutex_unlock(&node->lock);
+	
+	/* Delete node from hash table and memory */
+	if (!node->ref_cnt)
+		udf_idx_del(node);
+	
+	return EOK;
+}
+
+static int udf_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
+{
+	return ENOTSUP;
+}
+
+static int udf_destroy_node(fs_node_t *fn)
+{
+	return ENOTSUP;
+}
+
+static int udf_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	return ENOTSUP;
+}
+
+static int udf_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	return ENOTSUP;
+}
+
+static int udf_has_children(bool *has_children, fs_node_t *fn)
+{
+	*has_children = true;
+	return EOK;
+}
+
+static fs_index_t udf_index_get(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->index;
+	
+	return 0;
+}
+
+static aoff64_t udf_size_get(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->data_size;
+	
+	return 0;
+}
+
+static unsigned int udf_lnkcnt_get(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->link_cnt;
+	
+	return 0;
+}
+
+static bool udf_is_directory(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->type == NODE_DIR;
+	
+	return false;
+}
+
+static bool udf_is_file(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->type == NODE_FILE;
+	
+	return false;
+}
+
+libfs_ops_t udf_libfs_ops = {
+	.root_get = udf_root_get,
+	.match = udf_match,
+	.node_get = udf_node_get,
+	.node_open = udf_node_open,
+	.node_put = udf_node_put,
+	.create = udf_create_node,
+	.destroy = udf_destroy_node,
+	.link = udf_link,
+	.unlink = udf_unlink,
+	.has_children = udf_has_children,
+	.index_get = udf_index_get,
+	.size_get = udf_size_get,
+	.lnkcnt_get = udf_lnkcnt_get,
+	.is_directory = udf_is_directory,
+	.is_file = udf_is_file,
+	.service_get = udf_service_get
+};
+
+static int udf_mounted(service_id_t service_id, const char *opts,
+    fs_index_t *index, aoff64_t *size, unsigned *linkcnt)
+{
+	enum cache_mode cmode;
+	
+	/* Check for option enabling write through. */
+	if (str_cmp(opts, "wtcache") == 0)
+		cmode = CACHE_MODE_WT;
+	else
+		cmode = CACHE_MODE_WB;
+	
+	udf_instance_t *instance = malloc(sizeof(udf_instance_t));
+	if (!instance)
+		return ENOMEM;
+	
+	instance->sector_size = 0;
+	
+	/* Check for block size. Will be enhanced later */
+	if (str_cmp(opts, "bs=512") == 0)
+		instance->sector_size = 512;
+	else if (str_cmp(opts, "bs=1024") == 0)
+		instance->sector_size = 1024;
+	else if (str_cmp(opts, "bs=2048") == 0)
+		instance->sector_size = 2048;
+	
+	/* initialize block cache */
+	int rc = block_init(EXCHANGE_SERIALIZE, service_id, MAX_SIZE);
+	if (rc != EOK)
+		return rc;
+	
+	rc = fs_instance_create(service_id, instance);
+	if (rc != EOK) {
+		free(instance);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	instance->service_id = service_id;
+	instance->open_nodes_count = 0;
+	
+	/* Check Volume Recognition Sequence */
+	rc = udf_volume_recongnition(service_id);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "VRS failed");
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	/* Search for Anchor Volume Descriptor */
+	udf_anchor_volume_descriptor_t avd;
+	rc = udf_get_anchor_volume_descriptor(service_id, &avd);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Anchor read failed");
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
+	    "Volume: Anchor volume descriptor found. Sector size=%" PRIu32,
+	    instance->sector_size);
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
+	    "Anchor: main sequence [length=%" PRIu32 " (bytes), start=%"
+	    PRIu32 " (sector)]", avd.main_extent.length,
+	    avd.main_extent.location);
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
+	    "Anchor: reserve sequence [length=%" PRIu32 " (bytes), start=%"
+	    PRIu32 " (sector)]", avd.reserve_extent.length,
+	    avd.reserve_extent.location);
+	
+	/* Initialize the block cache */
+	rc = block_cache_init(service_id, instance->sector_size, 0, cmode);
+	if (rc != EOK) {
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	/* Read Volume Descriptor Sequence */
+	rc = udf_read_volume_descriptor_sequence(service_id, avd.main_extent);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Volume Descriptor Sequence read failed");
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_cache_fini(service_id);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	fs_node_t *rfn;
+	rc = udf_node_get(&rfn, service_id, instance->volumes[DEFAULT_VOL].root_dir);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Can't create root node");
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_cache_fini(service_id);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	udf_node_t *node = UDF_NODE(rfn);
+	*index = instance->volumes[DEFAULT_VOL].root_dir;
+	*size = node->data_size;
+	*linkcnt = node->link_cnt;
+	
+	return EOK;
+}
+
+static int udf_unmounted(service_id_t service_id)
+{
+	fs_node_t *fn;
+	int rc = udf_root_get(&fn, service_id);
+	if (rc != EOK)
+		return rc;
+	
+	udf_node_t *nodep = UDF_NODE(fn);
+	udf_instance_t *instance = nodep->instance;
+	
+	/*
+	 * We expect exactly two references on the root node.
+	 * One for the udf_root_get() above and one created in
+	 * udf_mounted().
+	 */
+	if (nodep->ref_cnt != 2) {
+		udf_node_put(fn);
+		return EBUSY;
+	}
+	
+	/*
+	 * Put the root node twice.
+	 */
+	udf_node_put(fn);
+	udf_node_put(fn);
+	
+	fs_instance_destroy(service_id);
+	free(instance);
+	block_cache_fini(service_id);
+	block_fini(service_id);
+	
+	return EOK;
+}
+
+static int udf_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
+    size_t *rbytes)
+{
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	fs_node_t *rfn;
+	rc = udf_node_get(&rfn, service_id, index);
+	if (rc != EOK)
+		return rc;
+	
+	udf_node_t *node = UDF_NODE(rfn);
+	
+	ipc_callid_t callid;
+	size_t len = 0;
+	if (!async_data_read_receive(&callid, &len)) {
+		async_answer_0(callid, EINVAL);
+		udf_node_put(rfn);
+		return EINVAL;
+	}
+	
+	if (node->type == NODE_FILE) {
+		if (pos >= node->data_size) {
+			*rbytes = 0;
+			async_data_read_finalize(callid, NULL, 0);
+			udf_node_put(rfn);
+			return EOK;
+		}
+		
+		size_t read_len = 0;
+		if (node->data == NULL)
+			rc = udf_read_file(&read_len, callid, node, pos, len);
+		else {
+			/* File in allocation descriptors area */
+			read_len = (len < node->data_size) ? len : node->data_size;
+			async_data_read_finalize(callid, node->data + pos, read_len);
+			rc = EOK;
+		}
+		
+		*rbytes = read_len;
+		(void) udf_node_put(rfn);
+		return rc;
+	} else {
+		block_t *block = NULL;
+		udf_file_identifier_descriptor_t *fid = NULL;
+		if (udf_get_fid(&fid, &block, node, pos) == EOK) {
+			char *name = malloc(MAX_FILE_NAME_LEN + 1);
+			
+			// FIXME: Check for NULL return value
+			
+			udf_to_unix_name(name, MAX_FILE_NAME_LEN,
+			    (char *) fid->implementation_use + FLE16(fid->lenght_iu),
+			    fid->lenght_file_id, &node->instance->charset);
+			
+			async_data_read_finalize(callid, name, str_size(name) + 1);
+			*rbytes = 1;
+			free(name);
+			udf_node_put(rfn);
+			
+			if (block != NULL)
+				return block_put(block);
+			
+			return EOK;
+		} else {
+			*rbytes = 0;
+			udf_node_put(rfn);
+			async_answer_0(callid, ENOENT);
+			return ENOENT;
+		}
+	}
+}
+
+static int udf_close(service_id_t service_id, fs_index_t index)
+{
+	return EOK;
+}
+
+static int udf_sync(service_id_t service_id, fs_index_t index)
+{
+	return ENOTSUP;
+}
+
+static int udf_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
+    size_t *wbytes, aoff64_t *nsize)
+{
+	return ENOTSUP;
+}
+
+static int udf_truncate(service_id_t service_id, fs_index_t index,
+    aoff64_t size)
+{
+	return ENOTSUP;
+}
+
+static int udf_destroy(service_id_t service_id, fs_index_t index)
+{
+	return ENOTSUP;
+}
+
+vfs_out_ops_t udf_ops = {
+	.mounted = udf_mounted,
+	.unmounted = udf_unmounted,
+	.read = udf_read,
+	.write = udf_write,
+	.truncate = udf_truncate,
+	.close = udf_close,
+	.destroy = udf_destroy,
+	.sync = udf_sync
+};
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_osta.c
===================================================================
--- uspace/srv/fs/udf/udf_osta.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf_osta.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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.
+ */
+
+/*
+ * OSTA compliant Unicode compression, uncompression routines,
+ * file name translation routine for OS/2, Windows 95, Windows NT,
+ * Macintosh and UNIX.
+ * Copyright 1995 Micro Design International, Inc.
+ * Written by Jason M. Rinn.
+ * Micro Design International gives permission for the free use of the
+ * following source code.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+/**
+ * @file udf_osta.c
+ * @brief OSTA compliant functions.
+ */
+
+#include <malloc.h>
+#include <str.h>
+#include <macros.h>
+#include <errno.h>
+#include "udf_osta.h"
+#include "udf_cksum.h"
+
+/** Calculate length of UTF-16 string
+ *
+ * FIXME: This is wrong! UTF-16 is not a fixed-width encoding,
+ *        it is a variable-width encoding (mind the surrogate
+ *        pairs).
+ *
+ */
+static size_t utf16_length(uint16_t *string) {
+	size_t len = 0;
+	
+	while (*string++ != 0)
+		len++;
+	
+	return len;
+}
+
+/** Illegal UNIX characters are NULL and slash.
+ *
+ */
+static bool legal_check(uint16_t ch)
+{
+	if ((ch == 0x0000) || (ch == 0x002F))
+		return false;
+	
+	return true;
+}
+
+/** Convert OSTA CS0 compressed Unicode name to Unicode.
+ *
+ * The Unicode output will be in the byte order that the local compiler
+ * uses for 16-bit values.
+ *
+ * NOTE: This routine only performs error checking on the comp_id.
+ * It is up to the user to ensure that the Unicode buffer is large
+ * enough, and that the compressed Unicode name is correct.
+ *
+ * @param[in]  number_of_bytes Number of bytes read from media
+ * @param[in]  udf_compressed  Bytes read from media
+ * @param[out] unicode         Uncompressed unicode characters
+ * @param[in]  unicode_max_len Size of output array
+ *
+ * @return Number of Unicode characters which were uncompressed.
+ *
+ */
+static size_t udf_uncompress_unicode(size_t number_of_bytes,
+    uint8_t *udf_compressed, uint16_t *unicode, size_t unicode_max_len)
+{
+	/* Use udf_compressed to store current byte being read. */
+	uint8_t comp_id = udf_compressed[0];
+	
+	/* First check for valid compID. */
+	if ((comp_id != 8) && (comp_id != 16))
+		return 0;
+	
+	size_t unicode_idx = 0;
+	size_t byte_idx = 1;
+	
+	/* Loop through all the bytes. */
+	while ((byte_idx < number_of_bytes) && (unicode_idx < unicode_max_len)) {
+		if (comp_id == 16) {
+			/*
+			 * Move the first byte to the high bits of the
+			 * Unicode char.
+			 */
+			unicode[unicode_idx] = udf_compressed[byte_idx++] << 8;
+		} else
+			unicode[unicode_idx] = 0;
+		
+		if (byte_idx < number_of_bytes) {
+			/* Then the next byte to the low bits. */
+			unicode[unicode_idx] |= udf_compressed[byte_idx++];
+		}
+		
+		unicode_idx++;
+	}
+	
+	return unicode_idx;
+}
+
+/** Translate a long file name
+ *
+ * Translate a long file name to one using a MAXLEN and an illegal char set
+ * in accord with the OSTA requirements. Assumes the name has already been
+ * translated to Unicode.
+ *
+ * @param[out] new_name Translated name. Must be of length MAXLEN
+ * @param[in]  udf_name Name from UDF volume
+ * @param[in]  udf_len  Length of UDF Name
+ *
+ * @return Number of Unicode characters in translated name.
+ *
+ */
+size_t udf_translate_name(uint16_t *new_name, uint16_t *udf_name,
+    size_t udf_len)
+{
+	bool needs_crc = false;
+	bool has_ext = false;
+	size_t ext_idx = 0;
+	size_t new_idx = 0;
+	size_t new_ext_idx = 0;
+	
+	for (size_t idx = 0; idx < udf_len; idx++) {
+		uint16_t current = udf_name[idx];
+		
+		if ((!legal_check(current)) || (!ascii_check(current))) {
+			needs_crc = true;
+			
+			/*
+			 * Replace Illegal and non-displayable chars with
+			 * underscore.
+			 */
+			current = ILLEGAL_CHAR_MARK;
+			
+			/*
+			 * Skip any other illegal or non-displayable
+			 * characters.
+			 */
+			while ((idx + 1 < udf_len) &&
+			    (!legal_check(udf_name[idx + 1]) ||
+			    (!ascii_check(udf_name[idx + 1]))))
+				idx++;
+		}
+		
+		/* Record position of extension, if one is found. */
+		if ((current == PERIOD) && ((udf_len - idx - 1) <= EXT_SIZE)) {
+			if (udf_len == idx + 1) {
+				/* A trailing period is NOT an extension. */
+				has_ext = false;
+			} else {
+				has_ext = true;
+				ext_idx = idx;
+				new_ext_idx = new_idx;
+			}
+		}
+		
+		if (new_idx < MAXLEN)
+			new_name[new_idx++] = current;
+		else
+			needs_crc = true;
+	}
+	
+	if (needs_crc) {
+		uint16_t ext[EXT_SIZE];
+		size_t local_ext_idx = 0;
+		
+		if (has_ext) {
+			size_t max_filename_len;
+			
+			/* Translate extension, and store it in ext. */
+			for (size_t idx = 0; (idx < EXT_SIZE) &&
+			    (ext_idx + idx + 1 < udf_len); idx++) {
+				uint16_t current = udf_name[ext_idx + idx + 1];
+				
+				if ((!legal_check(current)) || (!ascii_check(current))) {
+					needs_crc = true;
+					
+					/*
+					 * Replace Illegal and non-displayable
+					 * chars with underscore.
+					 */
+					current = ILLEGAL_CHAR_MARK;
+					
+					/*
+					 * Skip any other illegal or
+					 * non-displayable characters.
+					 */
+					while ((idx + 1 < EXT_SIZE) &&
+					    ((!legal_check(udf_name[ext_idx + idx + 2])) ||
+					    (!ascii_check(udf_name[ext_idx + idx + 2]))))
+						idx++;
+				}
+				
+				ext[local_ext_idx++] = current;
+			}
+			
+			/*
+			 * Truncate filename to leave room for extension and
+			 * CRC.
+			 */
+			max_filename_len = ((MAXLEN - 5) - local_ext_idx - 1);
+			if (new_idx > max_filename_len)
+				new_idx = max_filename_len;
+			else
+				new_idx = new_ext_idx;
+		} else if (new_idx > MAXLEN - 5) {
+			/* If no extension, make sure to leave room for CRC. */
+			new_idx = MAXLEN - 5;
+		}
+		
+		/* Add mark for CRC. */
+		new_name[new_idx++] = CRC_MARK;
+		
+		/* Calculate CRC from original filename. */
+		uint16_t value_crc = udf_unicode_cksum(udf_name, udf_len);
+		
+		/* Convert 16-bits of CRC to hex characters. */
+		const char hex_char[] = "0123456789ABCDEF";
+		
+		new_name[new_idx++] = hex_char[(value_crc & 0xf000) >> 12];
+		new_name[new_idx++] = hex_char[(value_crc & 0x0f00) >> 8];
+		new_name[new_idx++] = hex_char[(value_crc & 0x00f0) >> 4];
+		new_name[new_idx++] = hex_char[(value_crc & 0x000f)];
+		
+		/* Place a translated extension at end, if found. */
+		if (has_ext) {
+			new_name[new_idx++] = PERIOD;
+			
+			for (size_t idx = 0; idx < local_ext_idx; idx++)
+				new_name[new_idx++] = ext[idx];
+		}
+	}
+	
+	return new_idx;
+}
+
+/** Decode from dchar to utf8
+ *
+ * @param result     Returned value - utf8 string
+ * @param result_len Length of output string
+ * @param id         Input string
+ * @param len        Length of input string
+ * @param chsp       Decode method
+ *
+ */
+void udf_to_unix_name(char *result, size_t result_len, char *id, size_t len,
+    udf_charspec_t *chsp)
+{
+	const char *osta_id = "OSTA Compressed Unicode";
+	size_t ucode_chars, nice_uchars;
+	
+	uint16_t *raw_name = malloc(MAX_BUF * sizeof(uint16_t));
+	uint16_t *unix_name = malloc(MAX_BUF * sizeof(uint16_t));
+	
+	// FIXME: Check for malloc returning NULL
+	
+	bool is_osta_typ0 = (chsp->type == 0) &&
+	    (str_cmp((char *) chsp->info, osta_id) == 0);
+	
+	if (is_osta_typ0) {
+		*raw_name = 0;
+		*unix_name = 0;
+		
+		ucode_chars =
+		    udf_uncompress_unicode(len, (uint8_t *) id, raw_name, MAX_BUF);
+		ucode_chars = min(ucode_chars, utf16_length(raw_name));
+		nice_uchars =
+		    udf_translate_name(unix_name, raw_name, ucode_chars);
+		
+		/* Output UTF-8 */
+		unix_name[nice_uchars] = 0;
+		utf16_to_str(result, result_len, unix_name);
+	} else {
+		/* Assume 8 bit char length byte Latin-1 */
+		str_ncpy(result, result_len, (char *) (id + 1),
+		    str_size((char *) (id + 1)));
+	}
+	
+	free(raw_name);
+	free(unix_name);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_osta.h
===================================================================
--- uspace/srv/fs/udf/udf_osta.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf_osta.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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.
+ */
+
+/*
+ * OSTA compliant Unicode compression, uncompression routines,
+ * file name translation routine for OS/2, Windows 95, Windows NT,
+ * Macintosh and UNIX.
+ * Copyright 1995 Micro Design International, Inc.
+ * Written by Jason M. Rinn.
+ * Micro Design International gives permission for the free use of the
+ * following source code.
+ */
+
+#ifndef UDF_OSTA_H_
+#define UDF_OSTA_H_
+
+#include <sys/types.h>
+#include <bool.h>
+#include "udf_types.h"
+
+#define MAXLEN    255
+#define MAX_BUF   1024
+#define EXT_SIZE  5
+
+#define ILLEGAL_CHAR_MARK  0x005F
+#define CRC_MARK           0x0023
+#define PERIOD             0x002E
+
+extern size_t udf_translate_name(uint16_t *, uint16_t *, size_t);
+extern void udf_to_unix_name(char *, size_t, char *, size_t, udf_charspec_t *);
+
+#endif /* UDF_OSTA_H_ */
Index: uspace/srv/fs/udf/udf_types.h
===================================================================
--- uspace/srv/fs/udf/udf_types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf_types.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf_types.h
+ * @brief UDF common types
+ */
+
+#ifndef UDF_UDF_TYPES_H_
+#define UDF_UDF_TYPES_H_
+
+#include <sys/types.h>
+#include <bool.h>
+#include <byteorder.h>
+
+#define GET_LE16(x)  x = uint16_t_le2host(x)
+#define GET_LE32(x)  x = uint32_t_le2host(x)
+
+#define FLE16(x)  uint16_t_le2host(x)
+#define FLE32(x)  uint32_t_le2host(x)
+#define FLE64(x)  uint64_t_le2host(x)
+
+#define ALL_UP(n, b)  ((n) / (b) + ((n) % (b) != 0))
+
+#define EXT_LENGTH(x)  (x & 0x3FFFFFFF)
+
+typedef uint8_t udf_dstring;
+
+/* Timestamp descriptor (ECMA 167 1/7.3) */
+typedef struct udf_timestamp {
+	uint16_t type_and_tz;
+	uint16_t year;
+	uint8_t month;
+	uint8_t day;
+	uint8_t hour;
+	uint8_t min;
+	uint8_t sec;
+	uint8_t centisec;
+	uint8_t h_of_mcsec;
+	uint8_t mcsec;
+} __attribute__((packed)) udf_timestamp_t;
+
+/* Universal descriptor tag (ECMA 167 3/7.2) */
+typedef struct udf_descriptor_tag {
+	uint16_t id;
+	uint16_t version;
+	uint8_t checksum;
+	uint8_t reserved;
+	uint16_t serial;
+	uint16_t descriptor_crc;
+	uint16_t descriptor_crc_length;
+	uint32_t location;
+} __attribute__((packed)) udf_descriptor_tag_t;
+
+/* Entity descriptor (ECMA 167 1/7.4) */
+typedef struct udf_regid {
+	uint8_t flags;
+	uint8_t id[23];
+	uint8_t id_suffix[8];
+} __attribute__((packed)) udf_regid_t;
+
+/* Character set specification (ECMA 167 1/7.2.1) */
+typedef struct udf_charspec {
+	uint8_t type;
+	uint8_t info[63];
+} __attribute__((packed)) udf_charspec_t;
+
+/* Recorded address (ECMA 167 4/7.1) */
+typedef struct udf_lb_addr {
+	uint32_t lblock_num;     /* Relative to start of the partition (from 0) */
+	uint16_t partition_num;  /* Relative to logical volume or not? */
+} __attribute__((packed)) udf_lb_addr_t;
+
+/* Long Allocation Descriptor (ECMA 167 4/14.14.2) */
+typedef struct udf_long_ad {
+	uint32_t length;
+	udf_lb_addr_t location;
+	uint8_t implementation_use[6];
+} __attribute__((packed)) udf_long_ad_t;
+
+/* Short Allocation Descriptor (ECMA 167 4/14.14.1) */
+typedef struct udf_short_ad {
+	uint32_t length;
+	uint32_t position;
+} __attribute__((packed)) udf_short_ad_t;
+
+/* Extended Allocation Descriptor (ECMA 167 4/14.14.3) */
+typedef struct udf_ext_ad {
+	uint32_t extent_length;
+	uint32_t recorded_length;
+	uint32_t info_length;
+	udf_lb_addr_t extent_location;
+	uint8_t implementation_use[2];
+} __attribute__((packed)) udf_ext_ad_t;
+
+/* Extent descriptor (ECMA 167 3/7.1) */
+typedef struct udf_extent {
+	uint32_t length;    /* Bytes */
+	uint32_t location;  /* Sectors */
+} __attribute__((packed)) udf_extent_t;
+
+/* Terminating Descriptor (ECMA 167 3/10.9) */
+typedef struct udf_terminating_descriptor {
+	udf_descriptor_tag_t tag;
+	uint8_t reserved[496];
+} __attribute__((packed)) udf_terminating_descriptor_t;
+
+/* Unallocated Space Descriptor (ECMA 167 3/10.8) */
+typedef struct udf_unallocated_space_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	uint32_t allocation_descriptors_num;
+	udf_extent_t allocation_descriptors[0];
+} __attribute__((packed)) udf_unallocated_space_descriptor_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_volume.c
===================================================================
--- uspace/srv/fs/udf/udf_volume.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf_volume.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,850 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf_volume.c
+ * @brief Implementation of volume recognition operations.
+ */
+
+#include <byteorder.h>
+#include <block.h>
+#include <libfs.h>
+#include <errno.h>
+#include <str.h>
+#include <malloc.h>
+#include <mem.h>
+#include <inttypes.h>
+#include <io/log.h>
+#include "udf.h"
+#include "udf_volume.h"
+#include "udf_osta.h"
+#include "udf_cksum.h"
+#include "udf_file.h"
+
+/** Convert long_ad to absolute sector position
+ *
+ * Convert address sector concerning origin of partition to position
+ * sector concerning origin of start of disk.
+ *
+ * @param instance UDF instance
+ * @param long_ad  UDF long address
+ *
+ * @return Position of sector concerning origin of start of disk.
+ *
+ */
+fs_index_t udf_long_ad_to_pos(udf_instance_t *instance, udf_long_ad_t *long_ad)
+{
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Long_Ad to Pos: "
+	    "partition_num=%" PRIu16 ", partition_block=%" PRIu32,
+	    FLE16(long_ad->location.partition_num),
+	    FLE32(long_ad->location.lblock_num));
+	
+	return instance->partitions[
+	    FLE16(long_ad->location.partition_num)].start +
+	    FLE32(long_ad->location.lblock_num);
+}
+
+/** Check type and version of VRS
+ *
+ * Not exactly clear which values could have type and version.
+ *
+ * @param service_id
+ * @param addr       Position sector with Volume Descriptor
+ * @param vd         Returned value - Volume Descriptor.
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_volume_recongnition_structure_test(service_id_t service_id,
+    aoff64_t addr, udf_vrs_descriptor_t *vd)
+{
+	return block_read_bytes_direct(service_id, addr,
+	    sizeof(udf_vrs_descriptor_t), vd);
+}
+
+/** Read Volume Recognition Sequence
+ *
+ * It is a first udf data which we read.
+ * It stars from fixed address VRS_ADDR = 32768 (bytes)
+ *
+ * @param service_id
+ *
+ * @return    EOK on success or a negative error code.
+ */
+int udf_volume_recongnition(service_id_t service_id) 
+{
+	aoff64_t addr = VRS_ADDR;
+	bool nsr_found = false;
+
+	udf_vrs_descriptor_t *vd = malloc(sizeof(udf_vrs_descriptor_t));
+	if (!vd)
+		return ENOMEM;
+	
+	int rc = udf_volume_recongnition_structure_test(service_id, addr, vd);
+	if (rc != EOK) {
+		free(vd);
+		return rc;
+	}
+	
+	for (size_t i = 0; i < VRS_DEPTH; i++) {
+		addr += sizeof(udf_vrs_descriptor_t);
+		
+		rc = udf_volume_recongnition_structure_test(service_id, addr, vd);
+		if (rc != EOK) {
+			free(vd);
+			return rc;
+		}
+		
+		/*
+		 * UDF standard identifier. According to ECMA 167 2/9.1.2
+		 */
+		if ((str_lcmp(VRS_NSR2, (char *) vd->identifier, VRS_ID_LEN) == 0) ||
+		    (str_lcmp(VRS_NSR3, (char *) vd->identifier, VRS_ID_LEN) == 0)) {
+			nsr_found = true;
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "VRS: NSR found");
+			continue;
+		}
+		
+		if (str_lcmp(VRS_END, (char *) vd->identifier, VRS_ID_LEN) == 0) {
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "VRS: end found");
+			break;
+		}
+	}
+	
+	free(vd);
+	
+	if (nsr_found)
+		return EOK;
+	else
+		return EINVAL;
+}
+
+/** Convert descriptor tag fields from little-endian to current byte order
+ *
+ */
+static void udf_prepare_tag(udf_descriptor_tag_t *tag)
+{
+	GET_LE16(tag->id);
+	GET_LE16(tag->version);
+	GET_LE16(tag->serial);
+	GET_LE16(tag->descriptor_crc);
+	GET_LE16(tag->descriptor_crc_length);
+	GET_LE32(tag->location);
+}
+
+/** Read AVD by using one of default sector size from array
+ *
+ * @param service_id
+ * @param avd         Returned value - Anchor Volume Descriptor
+ * @param sector_size Expected sector size
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_get_anchor_volume_descriptor_by_ssize(service_id_t service_id,
+    udf_anchor_volume_descriptor_t *avd, uint32_t sector_size)
+{
+	int rc = block_read_bytes_direct(service_id,
+	    UDF_AVDP_SECTOR * sector_size,
+	    sizeof(udf_anchor_volume_descriptor_t), avd);
+	if (rc != EOK)
+		return rc;
+	
+	if (avd->tag.checksum != udf_tag_checksum((uint8_t *) &avd->tag))
+		return EINVAL;
+	
+	// TODO: Should be tested in big-endian mode
+	udf_prepare_tag(&avd->tag);
+	
+	if (avd->tag.id != UDF_TAG_AVDP)
+		return EINVAL;
+	
+	GET_LE32(avd->main_extent.length);
+	GET_LE32(avd->main_extent.location);
+	GET_LE32(avd->reserve_extent.length);
+	GET_LE32(avd->reserve_extent.location);
+	
+	return EOK;
+}
+
+/** Identification of the sector size
+ *
+ * We try to read Anchor Volume Descriptor by using one item from
+ * sequence of default values. If we could read avd, we found sector size.
+ *
+ * @param service_id
+ * @param avd        Returned value - Anchor Volume Descriptor
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_get_anchor_volume_descriptor(service_id_t service_id,
+    udf_anchor_volume_descriptor_t *avd)
+{
+	uint32_t default_sector_size[] = {512, 1024, 2048, 4096, 8192, 0};
+	
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	if (instance->sector_size) {
+		return udf_get_anchor_volume_descriptor_by_ssize(service_id, avd,
+		    instance->sector_size);
+	} else {
+		size_t i = 0;
+		while (default_sector_size[i] != 0) {
+			rc = udf_get_anchor_volume_descriptor_by_ssize(service_id, avd,
+			    default_sector_size[i]);
+			if (rc == EOK) {
+				instance->sector_size = default_sector_size[i];
+				return EOK;
+			}
+			
+			i++;
+		}
+	}
+	
+	return EINVAL;
+}
+
+/** Check on prevailing primary volume descriptor
+ *
+ * Some discs couldn't be rewritten and new information is identified
+ * by descriptors with same data as one of already created descriptors.
+ * We should find prevailing descriptor (descriptor with the highest number)
+ * and delete old descriptor.
+ *
+ * @param pvd  Array of primary volumes descriptors
+ * @param cnt  Count of items in array
+ * @param desc Descriptor which could prevail over one
+ *             of descriptors in array.
+ *
+ * @return True if desc prevails over some descriptor in array
+ *
+ */
+static bool udf_check_prevailing_pvd(udf_primary_volume_descriptor_t *pvd,
+    size_t cnt, udf_primary_volume_descriptor_t *desc)
+{
+	for (size_t i = 0; i < cnt; i++) {
+		/*
+		 * According to ECMA 167 3/8.4.3
+		 * PVD, each of which has same contents of the corresponding
+		 * Volume Identifier, Volume set identifier
+		 * and Descriptor char set field.
+		 */
+		if ((bcmp((uint8_t *) pvd[i].volume_id,
+		    (uint8_t *) desc->volume_id, 32) == 0) &&
+		    (bcmp((uint8_t *) pvd[i].volume_set_id,
+		    (uint8_t *) desc->volume_set_id, 128) == 0) &&
+		    (bcmp((uint8_t *) &pvd[i].descriptor_charset,
+		    (uint8_t *) &desc->descriptor_charset, 64) == 0) &&
+		    (FLE32(desc->sequence_number) > FLE32(pvd[i].sequence_number))) {
+			memcpy(&pvd[i], desc, sizeof(udf_primary_volume_descriptor_t));
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+/** Check on prevailing logic volume descriptor
+ *
+ * Some discs couldn't be rewritten and new information is identified
+ * by descriptors with same data as one of already created descriptors.
+ * We should find  prevailing descriptor (descriptor with the highest number)
+ * and delete old descriptor.
+ *
+ * @param lvd  Array of logic volumes descriptors
+ * @param cnt  Count of items in array
+ * @param desc Descriptor which could prevail over one
+ *             of descriptors in array.
+ *
+ * @return True if desc prevails over some descriptor in array
+ *
+ */
+static bool udf_check_prevailing_lvd(udf_logical_volume_descriptor_t *lvd,
+    size_t cnt, udf_logical_volume_descriptor_t *desc)
+{
+	for (size_t i = 0; i < cnt; i++) {
+		/*
+		 * According to ECMA 167 3/8.4.3
+		 * LVD, each of which has same contents of the corresponding
+		 * Logic Volume Identifier and Descriptor char set field.
+		 */
+		if ((bcmp((uint8_t *) lvd[i].logical_volume_id,
+		    (uint8_t *) desc->logical_volume_id, 128) == 0) &&
+		    (bcmp((uint8_t *) &lvd[i].charset,
+		    (uint8_t *) &desc->charset, 64) == 0) &&
+		    (FLE32(desc->sequence_number) > FLE32(lvd[i].sequence_number))) {
+			memcpy(&lvd[i], desc, sizeof(udf_logical_volume_descriptor_t));
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+/** Check on prevailing partition descriptor
+ *
+ * Some discs couldn't be rewritten and new information is identified
+ * by descriptors with same data as one of already created descriptors.
+ * We should find  prevailing descriptor (descriptor with the highest number)
+ * and delete old descriptor.
+ *
+ * @param pvd  Array of partition descriptors
+ * @param cnt  Count of items in array
+ * @param desc Descriptor which could prevail over one
+ *             of descriptors in array.
+ *
+ * @return True if desc prevails over some descriptor in array
+ *
+ */
+static bool udf_check_prevailing_pd(udf_partition_descriptor_t *pd, size_t cnt,
+    udf_partition_descriptor_t *desc)
+{
+	for (size_t i = 0; i < cnt; i++) {
+		/*
+		 * According to ECMA 167 3/8.4.3
+		 * Partition descriptors with identical Partition Number
+		 */
+		if ((FLE16(pd[i].number) == FLE16(desc->number)) &&
+		    (FLE32(desc->sequence_number) > FLE32(pd[i].sequence_number))) {
+			memcpy(&pd[i], desc, sizeof(udf_partition_descriptor_t));
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+/** Read information about virtual partition
+ *
+ * Fill start and length fields for partition. This function quite similar of
+ * udf_read_icd. But in this we can meet only two descriptors and
+ * we have to read only one allocator.
+ *
+ * @param instance UDF instance
+ * @param pos      Position (Extended) File entry descriptor
+ * @param id       Index of partition in instance::partitions array
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_read_virtual_partition(udf_instance_t *instance, uint32_t pos,
+    uint32_t id)
+{
+	block_t *block = NULL;
+	int rc = block_get(&block, instance->service_id, pos,
+	    BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return rc;
+	
+	udf_descriptor_tag_t *desc = (udf_descriptor_tag_t *) (block->data);
+	if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
+		block_put(block);
+		return EINVAL;
+	}
+	
+	/*
+	 * We think that we have only one allocator. It is means that virtual
+	 * partition, like physical, isn't fragmented.
+	 * According to doc the type of allocator is short_ad.
+	 */
+	switch (FLE16(desc->id)) {
+	case UDF_FILE_ENTRY:
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: File entry descriptor found");
+		
+		udf_file_entry_descriptor_t *fed =
+		    (udf_file_entry_descriptor_t *) block->data;
+		uint32_t start_alloc = FLE32(fed->ea_lenght) + UDF_FE_OFFSET;
+		udf_short_ad_t *short_d =
+		    (udf_short_ad_t *) ((uint8_t *) fed + start_alloc);
+		instance->partitions[id].start = FLE32(short_d->position);
+		instance->partitions[id].lenght = FLE32(short_d->length);
+		break;
+		
+	case UDF_EFILE_ENTRY:
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Extended file entry descriptor found");
+		
+		udf_extended_file_entry_descriptor_t *efed =
+		    (udf_extended_file_entry_descriptor_t *) block->data;
+		start_alloc = FLE32(efed->ea_lenght) + UDF_EFE_OFFSET;
+		short_d = (udf_short_ad_t *) ((uint8_t *) efed + start_alloc);
+		instance->partitions[id].start = FLE32(short_d->position);
+		instance->partitions[id].lenght = FLE32(short_d->length);
+		break;
+	}
+	
+	return block_put(block);
+}
+
+/** Search partition in array of partitions
+ *
+ * Used only in function udf_fill_volume_info
+ *
+ * @param pd     Array of partitions
+ * @param pd_cnt Count items in array
+ * @param id     Number partition (not index) which we want to find
+ *
+ * @return Index of partition or (size_t) -1 if we didn't find anything
+ *
+ */
+static size_t udf_find_partition(udf_partition_descriptor_t *pd, size_t pd_cnt,
+    size_t id)
+{
+	for (size_t i = 0; i < pd_cnt; i++) {
+		if (FLE16(pd[i].number) == id)
+			return i;
+	}
+	
+	return (size_t) -1;
+}
+
+/** Fill instance structures by information about partitions and logic
+ *
+ * @param lvd      Array of logic volumes descriptors
+ * @param lvd_cnt  Count of items in lvd array
+ * @param pd       Array of partition descriptors
+ * @param pd_cnt   Count of items in pd array
+ * @param instance UDF instance
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_fill_volume_info(udf_logical_volume_descriptor_t *lvd,
+    size_t lvd_cnt, udf_partition_descriptor_t *pd, size_t pd_cnt,
+    udf_instance_t *instance)
+{
+	instance->volumes = calloc(lvd_cnt, sizeof(udf_lvolume_t));
+	if (instance->volumes == NULL)
+		return ENOMEM;
+	
+	instance->partitions = calloc(pd_cnt, sizeof(udf_partition_t));
+	if (instance->partitions == NULL) {
+		free(instance->volumes);
+		return ENOMEM;
+	}
+	
+	instance->partition_cnt = pd_cnt;
+	
+	/*
+	 * Fill information about logical volumes. We will save
+	 * information about all partitions placed inside each volumes.
+	 */
+	
+	size_t vir_pd_cnt = 0;
+	for (size_t i = 0; i < lvd_cnt; i++) {
+		instance->volumes[i].partitions =
+		    calloc(FLE32(lvd[i].number_of_partitions_maps),
+		    sizeof(udf_partition_t *));
+		if (instance->volumes[i].partitions == NULL) {
+			// FIXME: Memory leak, cleanup code missing
+			return ENOMEM;
+		}
+		
+		instance->volumes[i].partition_cnt = 0;
+		instance->volumes[i].logical_block_size =
+		    FLE32(lvd[i].logical_block_size);
+		
+		/*
+		 * In theory we could have more than 1 logical volume. But now
+		 * for current work of driver we will think that it single and all
+		 * partitions from array pd belong to only first lvd
+		 */
+		
+		uint8_t *idx = lvd[i].partition_map;
+		for (size_t j = 0; j < FLE32(lvd[i].number_of_partitions_maps);
+		    j++) {
+			udf_type1_partition_map_t *pm1 =
+			    (udf_type1_partition_map_t *) idx;
+			
+			if (pm1->partition_map_type == 1) {
+				size_t pd_num = udf_find_partition(pd, pd_cnt,
+				    FLE16(pm1->partition_number));
+				if (pd_num == (size_t) -1) {
+					// FIXME: Memory leak, cleanup code missing
+					return ENOENT;
+				}
+				
+				/*
+				 * Fill information about physical partitions. We will save all
+				 * partitions (physical and virtual) inside one array
+				 * instance::partitions
+				 */
+				instance->partitions[j].access_type =
+				    FLE32(pd[pd_num].access_type);
+				instance->partitions[j].lenght =
+				    FLE32(pd[pd_num].length);
+				instance->partitions[j].number =
+				    FLE16(pm1->partition_number);
+				instance->partitions[j].start =
+				    FLE32(pd[pd_num].starting_location);
+				
+				instance->volumes[i].partitions[
+				    instance->volumes[i].partition_cnt] =
+				    &instance->partitions[j];
+				
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume[%" PRIun "]: partition [type %u] "
+				    "found and filled", i, pm1->partition_map_type);
+				
+				instance->volumes[i].partition_cnt++;
+				idx += pm1->partition_map_lenght;
+				continue;
+			}
+			
+			udf_type2_partition_map_t *pm2 =
+			    (udf_type2_partition_map_t *) idx;
+			
+			if (pm2->partition_map_type == 2) {
+				// TODO: check partition_ident for metadata_partition_map
+				
+				udf_metadata_partition_map_t *metadata =
+				    (udf_metadata_partition_map_t *) idx;
+				
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Metadata file location=%u",
+				    FLE32(metadata->metadata_fileloc));
+				
+				vir_pd_cnt++;
+				instance->partitions = realloc(instance->partitions,
+				    (pd_cnt + vir_pd_cnt) * sizeof(udf_partition_t));
+				if (instance->partitions == NULL) {
+					// FIXME: Memory leak, cleanup code missing
+					return ENOMEM;
+				}
+				
+				instance->partition_cnt++;
+				
+				size_t pd_num = udf_find_partition(pd, pd_cnt,
+				    FLE16(metadata->partition_number));
+				if (pd_num == (size_t) -1) {
+					// FIXME: Memory leak, cleanup code missing
+					return ENOENT;
+				}
+				
+				instance->partitions[j].number =
+				    FLE16(metadata->partition_number);
+				int rc = udf_read_virtual_partition(instance,
+				    FLE32(metadata->metadata_fileloc) +
+				    FLE32(pd[pd_num].starting_location), j);
+				if (rc != EOK) {
+					// FIXME: Memory leak, cleanup code missing
+					return rc;
+				}
+				
+				/* Virtual partition placed inside physical */
+				instance->partitions[j].start +=
+				    FLE32(pd[pd_num].starting_location);
+				
+				instance->volumes[i].partitions[
+				    instance->volumes[i].partition_cnt] =
+				    &instance->partitions[j];
+				
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Virtual partition: num=%d, start=%d",
+				    instance->partitions[j].number,
+				    instance->partitions[j].start);
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume[%" PRIun "]: partition [type %u] "
+				    "found and filled", i, pm2->partition_map_type);
+				
+				instance->volumes[i].partition_cnt++;
+				idx += metadata->partition_map_length;
+				continue;
+			}
+			
+			/* Not type 1 nor type 2 */
+			udf_general_type_t *pm = (udf_general_type_t *) idx;
+			
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume[%" PRIun "]: partition [type %u] "
+			    "found and skipped", i, pm->partition_map_type);
+			
+			idx += pm->partition_map_lenght;
+		}
+	}
+	
+	return EOK;
+}
+
+/** Read volume descriptors sequence
+ *
+ * @param service_id
+ * @param addr       UDF extent descriptor (ECMA 167 3/7.1)
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_read_volume_descriptor_sequence(service_id_t service_id,
+    udf_extent_t addr)
+{
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	aoff64_t pos = addr.location;
+	aoff64_t end = pos + (addr.length / instance->sector_size) - 1;
+	
+	if (pos == end)
+		return EINVAL;
+	
+	size_t max_descriptors = ALL_UP(addr.length, instance->sector_size);
+	
+	udf_primary_volume_descriptor_t *pvd = calloc(max_descriptors,
+	    sizeof(udf_primary_volume_descriptor_t));
+	if (pvd == NULL)
+		return ENOMEM;
+	
+	udf_logical_volume_descriptor_t *lvd = calloc(max_descriptors,
+	    instance->sector_size);
+	if (lvd == NULL) {
+		free(pvd);
+		return ENOMEM;
+	}
+	
+	udf_partition_descriptor_t *pd = calloc(max_descriptors,
+	    sizeof(udf_partition_descriptor_t));
+	if (pd == NULL) {
+		free(pvd);
+		free(lvd);
+		return ENOMEM;
+	}
+	
+	size_t pvd_cnt = 0;
+	size_t lvd_cnt = 0;
+	size_t pd_cnt = 0;
+	
+	while (pos <= end) {
+		block_t *block = NULL;
+		rc = block_get(&block, service_id, pos, BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			free(pvd);
+			free(lvd);
+			free(pd);
+			return rc;
+		}
+		
+		udf_volume_descriptor_t *vol =
+		    (udf_volume_descriptor_t *) block->data;
+		
+		switch (FLE16(vol->common.tag.id)) {
+		/* One sector size descriptors */
+		case UDF_TAG_PVD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Primary volume descriptor found");
+			
+			if (!udf_check_prevailing_pvd(pvd, pvd_cnt, &vol->volume)) {
+				memcpy(&pvd[pvd_cnt], &vol->volume,
+				    sizeof(udf_primary_volume_descriptor_t));
+				pvd_cnt++;
+			}
+			
+			pos++;
+			break;
+			
+		case UDF_TAG_VDP:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Volume descriptor pointer found");
+			pos++;
+			break;
+			
+		case UDF_TAG_IUVD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG,
+			    "Volume: Implementation use volume descriptor found");
+			pos++;
+			break;
+			
+		case UDF_TAG_PD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Partition descriptor found");
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Partition number: %u, contents: '%.6s', "
+			    "access type: %" PRIu32, FLE16(vol->partition.number),
+			    vol->partition.contents.id, FLE32(vol->partition.access_type));
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Partition start: %" PRIu32 " (sector), "
+			    "size: %" PRIu32 " (sectors)",
+			    FLE32(vol->partition.starting_location),
+			    FLE32(vol->partition.length));
+			
+			if (!udf_check_prevailing_pd(pd, pd_cnt, &vol->partition)) {
+				memcpy(&pd[pd_cnt], &vol->partition,
+				    sizeof(udf_partition_descriptor_t));
+				pd_cnt++;
+			}
+			
+			udf_partition_header_descriptor_t *phd =
+			    (udf_partition_header_descriptor_t *) vol->partition.contents_use;
+			if (FLE32(phd->unallocated_space_table.length)) {
+				log_msg(LOG_DEFAULT, LVL_DEBUG,
+				    "space table: length=%" PRIu32 ", pos=%" PRIu32,
+				    FLE32(phd->unallocated_space_table.length),
+				    FLE32(phd->unallocated_space_table.position));
+				
+				instance->space_type = SPACE_TABLE;
+				instance->uaspace_start =
+				    FLE32(vol->partition.starting_location) +
+				    FLE32(phd->unallocated_space_table.position);
+				instance->uaspace_lenght =
+				    FLE32(phd->unallocated_space_table.length);
+			}
+			
+			if (FLE32(phd->unallocated_space_bitmap.length)) {
+				log_msg(LOG_DEFAULT, LVL_DEBUG,
+				    "space bitmap: length=%" PRIu32 ", pos=%" PRIu32,
+				    FLE32(phd->unallocated_space_bitmap.length),
+				    FLE32(phd->unallocated_space_bitmap.position));
+				
+				instance->space_type = SPACE_BITMAP;
+				instance->uaspace_start =
+				    FLE32(vol->partition.starting_location) +
+				    FLE32(phd->unallocated_space_bitmap.position);
+				instance->uaspace_lenght =
+				    FLE32(phd->unallocated_space_bitmap.length);
+			}
+			
+			pos++;
+			break;
+			
+		/* Relative size descriptors */
+		case UDF_TAG_LVD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Logical volume descriptor found");
+			
+			aoff64_t sct =
+			    ALL_UP((sizeof(udf_logical_volume_descriptor_t) +
+			    FLE32(vol->logical.map_table_length)),
+			    sizeof(udf_common_descriptor_t));
+			pos += sct;
+			char tmp[130];
+			
+			udf_to_unix_name(tmp, 129,
+			    (char *) vol->logical.logical_volume_id, 128,
+			    &vol->logical.charset);
+			
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Logical Volume ID: '%s', "
+			    "logical block size: %" PRIu32 " (bytes)", tmp,
+			    FLE32(vol->logical.logical_block_size));
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Map table size: %" PRIu32 " (bytes), "
+			    "number of partition maps: %" PRIu32,
+			    FLE32(vol->logical.map_table_length),
+			    FLE32(vol->logical.number_of_partitions_maps));
+			
+			if (!udf_check_prevailing_lvd(lvd, lvd_cnt, &vol->logical)) {
+				memcpy(&lvd[lvd_cnt], &vol->logical,
+				    sizeof(udf_logical_volume_descriptor_t) +
+				    FLE32(vol->logical.map_table_length));
+				lvd_cnt++;
+			}
+			
+			break;
+			
+		case UDF_TAG_USD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Unallocated space descriptor found");
+			
+			sct = ALL_UP((sizeof(udf_unallocated_space_descriptor_t) +
+			    FLE32(vol->unallocated.allocation_descriptors_num)*
+			    sizeof(udf_extent_t)), sizeof(udf_common_descriptor_t));
+			instance->uaspace_start = pos;
+			instance->uaspace_lenght = sct;
+			instance->uasd = (udf_unallocated_space_descriptor_t *)
+			    malloc(sct * instance->sector_size);
+			if (instance->uasd == NULL) {
+				// FIXME: Memory leak, cleanup missing
+				return ENOMEM;
+			}
+			
+			memcpy(instance->uasd, block->data, instance->sector_size);
+			pos += sct;
+			break;
+			
+		case UDF_TAG_LVID:
+			log_msg(LOG_DEFAULT, LVL_DEBUG,
+			    "Volume: Logical volume integrity descriptor found");
+			
+			pos++;
+			break;
+			
+		case UDF_TAG_TD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Terminating descriptor found");
+			
+			/* Found terminating descriptor. Exiting */
+			pos = end + 1;
+			break;
+			
+		default:
+			pos++;
+		}
+		
+		rc = block_put(block);
+		if (rc != EOK) {
+			free(pvd);
+			free(lvd);
+			free(pd);
+			return rc;
+		}
+	}
+	
+	/* Fill the instance */
+	udf_fill_volume_info(lvd, lvd_cnt, pd, pd_cnt, instance);
+	
+	for (size_t i = 0; i < lvd_cnt; i++) {
+		pos = udf_long_ad_to_pos(instance,
+		    (udf_long_ad_t *) &lvd[i].logical_volume_conents_use);
+		
+		block_t *block = NULL;
+		rc = block_get(&block, instance->service_id, pos,
+		    BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			// FIXME: Memory leak, cleanup missing
+			return rc;
+		}
+		
+		udf_descriptor_tag_t *desc = block->data;
+		
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "First tag ID=%" PRIu16, desc->id);
+		
+		if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
+			// FIXME: Memory leak, cleanup missing
+			return EINVAL;
+		}
+		
+		udf_prepare_tag(desc);
+		
+		udf_fileset_descriptor_t *fd = block->data;
+		memcpy((uint8_t *) &instance->charset,
+		    (uint8_t *) &fd->fileset_charset, sizeof(fd->fileset_charset));
+		
+		instance->volumes[i].root_dir = udf_long_ad_to_pos(instance,
+		    &fd->root_dir_icb);
+	}
+	
+	free(pvd);
+	free(lvd);
+	free(pd);
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_volume.h
===================================================================
--- uspace/srv/fs/udf/udf_volume.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/fs/udf/udf_volume.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+
+#ifndef UDF_UDF_VOLUME_H_
+#define UDF_UDF_VOLUME_H_
+
+#include <sys/types.h>
+#include <ipc/loc.h>
+#include "udf_types.h"
+
+/* Descriptor Tag Identifier (ECMA 167 3/7.2.1) */
+#define UDF_TAG_PVD   0x0001  /* Primary Volume Descriptor */
+#define UDF_TAG_AVDP  0x0002  /* Anchor Volume Descriptor */
+#define UDF_TAG_VDP   0x0003  /* Volume Descriptor Pointer */
+#define UDF_TAG_IUVD  0x0004  /* Implementation Use Volume Descriptor */
+#define UDF_TAG_PD    0x0005  /* Partition Descriptor */
+#define UDF_TAG_LVD   0x0006  /* Logical Volume Descriptor */
+#define UDF_TAG_USD   0x0007  /* Unallocated Space Descriptor */
+#define UDF_TAG_TD    0x0008  /* Terminating Descriptor */
+#define UDF_TAG_LVID  0x0009  /* Logical Volume Integrity Descriptor */
+
+/* Start adress of Anchor Volume Descriptor */
+#define UDF_AVDP_SECTOR  256
+
+/* Volume Recognition Sequence params */
+#define VRS_ADDR     32768
+#define VRS_TYPE     0
+#define VRS_VERSION  1
+#define VRS_BEGIN    "BEA01"
+#define VRS_END      "TEA01"
+#define VRS_NSR2     "NSR02"
+#define VRS_NSR3     "NSR03"
+#define VRS_DEPTH    10
+#define VRS_ID_LEN   5
+
+/* Volume Structure Descriptor (ECMA 167 2/9.1) */
+typedef struct udf_vrs_descriptor {
+	uint8_t type;           /* Structure type */
+	uint8_t identifier[5];  /* Standart identifier */
+	uint8_t version;        /* Structure version */
+	uint8_t data[2041];     /* Structure data */
+} __attribute__((packed)) udf_vrs_descriptor_t;
+
+/* Anchor volume descriptor (ECMA 167 3/10.2) */
+typedef struct udf_anchor_volume_descriptor {
+	udf_descriptor_tag_t tag;     /* Descriptor tag */
+	udf_extent_t main_extent;     /* Main Volume Descriptor Sequence Extent */
+	udf_extent_t reserve_extent;  /* Reserve Volume Descriptor Sequence Extent */
+	uint8_t reserved[480];        /* Structure data */
+} __attribute__((packed)) udf_anchor_volume_descriptor_t;
+
+/* Common Volume Descriptor */
+typedef struct udf_common_descriptor {
+	udf_descriptor_tag_t tag;
+	uint8_t reserved[496];
+} __attribute__((packed)) udf_common_descriptor_t;
+
+/* Volume Descriptor Pointer (ECMA 167 3/10.3) */
+typedef struct udf_volume_pointer_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	udf_extent_t next_sequence;
+	uint8_t reserved[484];
+} __attribute__((packed)) udf_volume_pointer_descriptor_t;
+
+/* Primary Volume Descriptor (ECMA 167 3/10.1) */
+typedef struct udf_primary_volume_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	uint32_t primary_volume_descriptor_num;
+	udf_dstring volume_id[32];
+	uint16_t max_sequence_number;
+	uint16_t interchange_level;
+	uint16_t max_interchange_level;
+	uint32_t charset_list;
+	uint32_t max_charset_list;
+	udf_dstring volume_set_id[128];
+	udf_charspec_t descriptor_charset;
+	udf_charspec_t explanatory_charset;
+	udf_extent_t volume_abstract;
+	udf_extent_t volume_copyright_notice;
+	udf_regid_t application_id;
+	udf_timestamp_t recording_data_and_time;
+	udf_regid_t implementation_id;
+	uint8_t implementation_use[64];
+	uint32_t predecessor_vds_location;
+	uint16_t flags;
+	uint8_t reserved[22];
+} __attribute__((packed)) udf_primary_volume_descriptor_t;
+
+
+/* Partition Descriptor (ECMA 167 3/10.5) */
+typedef struct udf_partition_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	uint16_t flags;
+	uint16_t number;
+	udf_regid_t contents;
+	uint8_t contents_use[128];
+	uint32_t access_type;
+	uint32_t starting_location;
+	uint32_t length;
+	udf_regid_t implementation_id;
+	uint8_t implementation_use[128];
+	uint8_t reserved[156];
+} __attribute__((packed)) udf_partition_descriptor_t;
+
+/* Logical Volume Descriptor (ECMA 167 3/10.6) */
+typedef struct udf_logical_volume_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	udf_charspec_t charset;
+	udf_dstring logical_volume_id[128];
+	uint32_t logical_block_size;
+	udf_regid_t domain_id;
+	uint8_t logical_volume_conents_use[16];
+	uint32_t map_table_length;
+	uint32_t number_of_partitions_maps;
+	udf_regid_t implementation_id;
+	uint8_t implementation_use[128];
+	udf_extent_t integrity_sequence_extent;
+	uint8_t partition_map[0];
+} __attribute__((packed)) udf_logical_volume_descriptor_t;
+
+typedef struct udf_volume_descriptor {
+	union {
+		udf_common_descriptor_t common;
+		udf_terminating_descriptor_t terminating;
+		udf_volume_pointer_descriptor_t pointer;
+		udf_partition_descriptor_t partition;
+		udf_logical_volume_descriptor_t logical;
+		udf_unallocated_space_descriptor_t unallocated;
+		udf_primary_volume_descriptor_t volume;
+	};
+} __attribute__((packed)) udf_volume_descriptor_t;
+
+typedef struct udf_general_type {
+	uint8_t partition_map_type;
+	uint8_t partition_map_lenght;
+} __attribute__((packed)) udf_general_type_t;
+
+typedef struct udf_type1_partition_map {
+	uint8_t partition_map_type;
+	uint8_t partition_map_lenght;
+	uint16_t volume_sequence_number;
+	uint16_t partition_number;
+} __attribute__((packed)) udf_type1_partition_map_t;
+
+typedef struct udf_type2_partition_map {
+	uint8_t partition_map_type;
+	uint8_t partition_map_length;
+	uint8_t reserved1[2];
+	udf_regid_t partition_ident;
+	uint16_t volume_sequence_number;
+	uint16_t partition_number;
+} __attribute__((packed)) udf_type2_partition_map_t;
+
+/* Metadata Partition Map (UDF 2.4.0 2.2.10) */
+typedef struct udf_metadata_partition_map {
+	uint8_t partition_map_type;
+	uint8_t partition_map_length;
+	uint8_t reserved1[2];
+	udf_regid_t partition_ident;
+	uint16_t volume_sequence_number;
+	uint16_t partition_number;
+	uint32_t metadata_fileloc;
+	uint32_t metadata_mirror_fileloc;
+	uint32_t metadata_bitmap_fileloc;
+	uint32_t alloc_unit_size;
+	uint16_t align_unit_size;
+	uint8_t flags;
+	uint8_t reserved2[5];
+} __attribute__((packed)) udf_metadata_partition_map_t;
+
+/* Partition Header Descriptor (ECMA 167 4/14.3) */
+typedef struct udf_partition_header_descriptor {
+	udf_short_ad_t unallocated_space_table;
+	udf_short_ad_t unallocated_space_bitmap;
+	udf_short_ad_t partition_integrity_table;
+	udf_short_ad_t freed_space_table;
+	udf_short_ad_t freed_space_bitmap;
+	uint8_t reserved[88];
+} __attribute__((packed)) udf_partition_header_descriptor_t;
+
+extern int udf_volume_recongnition(service_id_t);
+extern int udf_get_anchor_volume_descriptor(service_id_t,
+    udf_anchor_volume_descriptor_t *);
+extern int udf_read_volume_descriptor_sequence(service_id_t, udf_extent_t);
+extern fs_index_t udf_long_ad_to_pos(udf_instance_t *, udf_long_ad_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/hid/compositor/compositor.c
===================================================================
--- uspace/srv/hid/compositor/compositor.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/hid/compositor/compositor.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -92,11 +92,8 @@
 	sysarg_t id;
 	uint8_t state;
-	sysarg_t hpos;
-	sysarg_t vpos;
+	desktop_point_t pos;
 	sysarg_t btn_num;
-	sysarg_t btn_hpos;
-	sysarg_t btn_vpos;
-	int accum_dx;
-	int accum_dy;
+	desktop_point_t btn_pos;
+	desktop_vector_t accum;
 	sysarg_t grab_flags;
 	bool pressed;
@@ -135,6 +132,5 @@
 	vslmode_t mode;
 	async_sess_t *sess;
-	sysarg_t hpos;
-	sysarg_t vpos;
+	desktop_point_t pos;
 	surface_t *surface;
 } viewport_t;
@@ -174,11 +170,10 @@
 
 	link_initialize(&p->link);
-	p->hpos = coord_origin;
-	p->vpos = coord_origin;
+	p->pos.x = coord_origin;
+	p->pos.y = coord_origin;
 	p->btn_num = 1;
-	p->btn_hpos = p->hpos;
-	p->btn_vpos = p->vpos;
-	p->accum_dx = 0;
-	p->accum_dy = 0;
+	p->btn_pos = p->pos;
+	p->accum.x = 0;
+	p->accum.y = 0;
 	p->grab_flags = GF_EMPTY;
 	p->pressed = false;
@@ -307,5 +302,5 @@
 		bool isec_vp = rectangle_intersect(
 		    x_dmg_glob, y_dmg_glob, w_dmg_glob, h_dmg_glob,
-		    vp->hpos, vp->vpos, w_dmg_vp, h_dmg_vp,
+		    vp->pos.x, vp->pos.y, w_dmg_vp, h_dmg_vp,
 		    &x_dmg_vp, &y_dmg_vp, &w_dmg_vp, &h_dmg_vp);
 
@@ -313,6 +308,6 @@
 
 			/* Paint background color. */
-			for (sysarg_t y = y_dmg_vp - vp->vpos; y <  y_dmg_vp - vp->vpos + h_dmg_vp; ++y) {
-				for (sysarg_t x = x_dmg_vp - vp->hpos; x < x_dmg_vp - vp->hpos + w_dmg_vp; ++x) {
+			for (sysarg_t y = y_dmg_vp - vp->pos.y; y <  y_dmg_vp - vp->pos.y + h_dmg_vp; ++y) {
+				for (sysarg_t x = x_dmg_vp - vp->pos.x; x < x_dmg_vp - vp->pos.x + w_dmg_vp; ++x) {
 					surface_put_pixel(vp->surface, x, y, bg_color);
 				}
@@ -352,7 +347,8 @@
 					 * coordinates. */
 					transform = win->transform;
-					double hpos = vp->hpos;
-					double vpos = vp->vpos;
-					transform_translate(&transform, -hpos, -vpos);
+					double_point_t pos;
+					pos.x = vp->pos.x;
+					pos.y = vp->pos.y;
+					transform_translate(&transform, -pos.x, -pos.y);
 
 					source_set_transform(&source, transform);				
@@ -361,5 +357,5 @@
 
 					drawctx_transfer(&context,
-					    x_dmg_win - vp->hpos, y_dmg_win - vp->vpos, w_dmg_win, h_dmg_win);
+					    x_dmg_win - vp->pos.x, y_dmg_win - vp->pos.y, w_dmg_win, h_dmg_win);
 				}
 			}
@@ -375,5 +371,5 @@
 				bool isec_ptr = rectangle_intersect(
 				    x_dmg_vp, y_dmg_vp, w_dmg_vp, h_dmg_vp,
-				    ptr->hpos, ptr->vpos, w_dmg_ptr, h_dmg_ptr,
+				    ptr->pos.x, ptr->pos.y, w_dmg_ptr, h_dmg_ptr,
 				    &x_dmg_ptr, &y_dmg_ptr, &w_dmg_ptr, &h_dmg_ptr);
 
@@ -386,8 +382,8 @@
 
 					pixel_t pix = 0;
-					sysarg_t x_vp = x_dmg_ptr - vp->hpos;
-					sysarg_t y_vp = y_dmg_ptr - vp->vpos;
-					sysarg_t x_ptr = x_dmg_ptr - ptr->hpos;
-					sysarg_t y_ptr = y_dmg_ptr - ptr->vpos;
+					sysarg_t x_vp = x_dmg_ptr - vp->pos.x;
+					sysarg_t y_vp = y_dmg_ptr - vp->pos.y;
+					sysarg_t x_ptr = x_dmg_ptr - ptr->pos.x;
+					sysarg_t y_ptr = y_dmg_ptr - ptr->pos.y;
 
 					for (sysarg_t y = 0; y < h_dmg_ptr; ++y) {
@@ -901,6 +897,6 @@
 
 	link_initialize(&vp->link);
-	vp->hpos = coord_origin;
-	vp->vpos = coord_origin;
+	vp->pos.x = coord_origin;
+	vp->pos.y = coord_origin;
 
 	/* Establish output bidirectional connection. */
@@ -1002,8 +998,8 @@
 	/* window_list_mtx locked by caller */
 
-	int dx = pointer->accum_dx;
-	int dy = pointer->accum_dy;
-	pointer->accum_dx = 0;
-	pointer->accum_dy = 0;
+	int dx = pointer->accum.x;
+	int dy = pointer->accum.y;
+	pointer->accum.x = 0;
+	pointer->accum.y = 0;
 
 	bool move = (pointer->grab_flags & GF_MOVE_X) || (pointer->grab_flags & GF_MOVE_Y);
@@ -1079,6 +1075,34 @@
     unsigned max_x, unsigned max_y)
 {
-	/* XXX TODO */
-	return EOK;
+	/* XXX TODO Use absolute coordinates directly */
+	
+	pointer_t *pointer = input_pointer(input);
+	
+	sysarg_t width, height;
+	
+	fibril_mutex_lock(&viewport_list_mtx);
+	if (list_empty(&viewport_list)) {
+		printf("No viewport found\n");
+		fibril_mutex_unlock(&viewport_list_mtx);
+		return EOK; /* XXX */
+	}
+	link_t *link = list_first(&viewport_list);
+	viewport_t *vp = list_get_instance(link, viewport_t, link);
+	surface_get_resolution(vp->surface, &width, &height);
+	desktop_point_t vp_pos = vp->pos;
+	fibril_mutex_unlock(&viewport_list_mtx);
+
+	desktop_point_t pos_in_viewport;
+	pos_in_viewport.x = x * width / max_x;
+	pos_in_viewport.y = y * height / max_y;
+	
+	/* Calculate offset from pointer */
+	fibril_mutex_lock(&pointer_list_mtx);
+	desktop_vector_t delta;
+	delta.x = (vp_pos.x + pos_in_viewport.x) - pointer->pos.x;
+	delta.y = (vp_pos.y + pos_in_viewport.y) - pointer->pos.y;
+	fibril_mutex_unlock(&pointer_list_mtx);
+	
+	return comp_mouse_move(input, delta.x, delta.y);
 }
 
@@ -1089,15 +1113,14 @@
 	/* Update pointer position. */
 	fibril_mutex_lock(&pointer_list_mtx);
-	sysarg_t old_hpos = pointer->hpos;
-	sysarg_t old_vpos = pointer->vpos;
+	desktop_point_t old_pos = pointer->pos;
 	sysarg_t cursor_width;
 	sysarg_t cursor_height;
 	surface_get_resolution(pointer->cursor.states[pointer->state], 
 	     &cursor_width, &cursor_height);
-	pointer->hpos += dx;
-	pointer->vpos += dy;
+	pointer->pos.x += dx;
+	pointer->pos.y += dy;
 	fibril_mutex_unlock(&pointer_list_mtx);
-	comp_damage(old_hpos, old_vpos, cursor_width, cursor_height);
-	comp_damage(old_hpos + dx, old_vpos + dy, cursor_width, cursor_height);
+	comp_damage(old_pos.x, old_pos.y, cursor_width, cursor_height);
+	comp_damage(old_pos.x + dx, old_pos.y + dy, cursor_width, cursor_height);
 
 	fibril_mutex_lock(&window_list_mtx);
@@ -1111,5 +1134,5 @@
 			sysarg_t width, height;
 			surface_get_resolution(top->surface, &width, &height);
-			within_client = comp_coord_to_client(pointer->hpos, pointer->vpos,
+			within_client = comp_coord_to_client(pointer->pos.x, pointer->pos.y,
 			    top->transform, width, height, &point_x, &point_y);
 			fibril_mutex_unlock(&window_list_mtx);
@@ -1130,6 +1153,6 @@
 		} else {
 			/* Pointer is grabbed by top-level window action. */
-			pointer->accum_dx += dx;
-			pointer->accum_dy += dy;
+			pointer->accum.x += dx;
+			pointer->accum.y += dy;
 #if ANIMATE_WINDOW_TRANSFORMS == 1
 			sysarg_t x, y, width, height;
@@ -1153,6 +1176,5 @@
 
 	if (bpress) {
-		pointer->btn_hpos = pointer->hpos;
-		pointer->btn_vpos = pointer->vpos;
+		pointer->btn_pos = pointer->pos;
 		pointer->btn_num = bnum;
 		pointer->pressed = true;
@@ -1167,5 +1189,5 @@
 		sysarg_t x, y, width, height;
 		surface_get_resolution(win->surface, &width, &height);
-		bool within_client = comp_coord_to_client(pointer->hpos, pointer->vpos,
+		bool within_client = comp_coord_to_client(pointer->pos.x, pointer->pos.y,
 		    win->transform, width, height, &x, &y);
 		fibril_mutex_unlock(&window_list_mtx);
@@ -1202,5 +1224,5 @@
 			if (win->surface) {
 				surface_get_resolution(win->surface, &width, &height);
-				within_client = comp_coord_to_client(pointer->hpos, pointer->vpos,
+				within_client = comp_coord_to_client(pointer->pos.x, pointer->pos.y,
 				    win->transform, width, height, &point_x, &point_y);
 			}
@@ -1518,27 +1540,27 @@
 			switch (key) {
 			case KC_I:
-				vp->hpos += 0;
-				vp->vpos += -20;
+				vp->pos.x += 0;
+				vp->pos.y += -20;
 				break;
 			case KC_K:
-				vp->hpos += 0;
-				vp->vpos += 20;
+				vp->pos.x += 0;
+				vp->pos.y += 20;
 				break;
 			case KC_J:
-				vp->hpos += -20;
-				vp->vpos += 0;
+				vp->pos.x += -20;
+				vp->pos.y += 0;
 				break;
 			case KC_L:
-				vp->hpos += 20;
-				vp->vpos += 0;
+				vp->pos.x += 20;
+				vp->pos.y += 0;
 				break;
 			default:
-				vp->hpos += 0;
-				vp->vpos += 0;
+				vp->pos.x += 0;
+				vp->pos.y += 0;
 				break;
 			}
 			
-			sysarg_t x = vp->hpos;
-			sysarg_t y = vp->vpos;
+			sysarg_t x = vp->pos.x;
+			sysarg_t y = vp->pos.y;
 			sysarg_t width, height;
 			surface_get_resolution(vp->surface, &width, &height);
Index: uspace/srv/hid/compositor/compositor.h
===================================================================
--- uspace/srv/hid/compositor/compositor.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/hid/compositor/compositor.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -36,4 +36,18 @@
 #define COMPOSITOR_COMPOSITOR_H_
 
+typedef native_t desktop_coord_t;
+typedef struct {
+	desktop_coord_t x;
+	desktop_coord_t y;
+} desktop_point_t;
+typedef desktop_point_t desktop_vector_t;
+
+/* TODO remove? */
+typedef struct {
+	double x;
+	double y;
+} double_point_t;
+typedef double_point_t double_vector_t;
+
 #endif
 
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/hid/console/console.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -37,5 +37,4 @@
 #include <adt/prodcons.h>
 #include <io/input.h>
-#include <ipc/console.h>
 #include <ipc/vfs.h>
 #include <errno.h>
@@ -43,8 +42,8 @@
 #include <loc.h>
 #include <event.h>
+#include <io/con_srv.h>
 #include <io/kbd_event.h>
 #include <io/keycode.h>
 #include <io/chargrid.h>
-#include <io/console.h>
 #include <io/output.h>
 #include <align.h>
@@ -80,4 +79,5 @@
 	chargrid_t *frontbuf;    /**< Front buffer */
 	frontbuf_handle_t fbid;  /**< Front buffer handle */
+	con_srvs_t srvs;         /**< Console service setup */
 } console_t;
 
@@ -114,4 +114,44 @@
 };
 
+static int cons_open(con_srvs_t *, con_srv_t *);
+static int cons_close(con_srv_t *);
+static int cons_read(con_srv_t *, void *, size_t);
+static int cons_write(con_srv_t *, void *, size_t);
+static void cons_sync(con_srv_t *);
+static void cons_clear(con_srv_t *);
+static void cons_set_pos(con_srv_t *, sysarg_t col, sysarg_t row);
+static int cons_get_pos(con_srv_t *, sysarg_t *, sysarg_t *);
+static int cons_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
+static int cons_get_color_cap(con_srv_t *, console_caps_t *);
+static void cons_set_style(con_srv_t *, console_style_t);
+static void cons_set_color(con_srv_t *, console_color_t, console_color_t,
+    console_color_attr_t);
+static void cons_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
+static void cons_set_cursor_visibility(con_srv_t *, bool);
+static int cons_get_event(con_srv_t *, kbd_event_t *);
+
+static con_ops_t con_ops = {
+	.open = cons_open,
+	.close = cons_close,
+	.read = cons_read,
+	.write = cons_write,
+	.sync = cons_sync,
+	.clear = cons_clear,
+	.set_pos = cons_set_pos,
+	.get_pos = cons_get_pos,
+	.get_size = cons_get_size,
+	.get_color_cap = cons_get_color_cap,
+	.set_style = cons_set_style,
+	.set_color = cons_set_color,
+	.set_rgb_color = cons_set_rgb_color,
+	.set_cursor_visibility = cons_set_cursor_visibility,
+	.get_event = cons_get_event
+};
+
+static console_t *srv_to_console(con_srv_t *srv)
+{
+	return srv->srvs->sarg;
+}
+
 static void cons_update(console_t *cons)
 {
@@ -138,13 +178,4 @@
 	fibril_mutex_unlock(&cons->mtx);
 	fibril_mutex_unlock(&switch_mtx);
-}
-
-static void cons_clear(console_t *cons)
-{
-	fibril_mutex_lock(&cons->mtx);
-	chargrid_clear(cons->frontbuf);
-	fibril_mutex_unlock(&cons->mtx);
-	
-	cons_update(cons);
 }
 
@@ -288,8 +319,8 @@
 }
 
-static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row)
-{
-	fibril_mutex_lock(&cons->mtx);
-	chargrid_set_cursor(cons->frontbuf, col, row);
+static void cons_set_cursor_vis(console_t *cons, bool visible)
+{
+	fibril_mutex_lock(&cons->mtx);
+	chargrid_set_cursor_visibility(cons->frontbuf, visible);
 	fibril_mutex_unlock(&cons->mtx);
 	
@@ -297,61 +328,18 @@
 }
 
-static void cons_set_cursor_visibility(console_t *cons, bool visible)
-{
-	fibril_mutex_lock(&cons->mtx);
-	chargrid_set_cursor_visibility(cons->frontbuf, visible);
-	fibril_mutex_unlock(&cons->mtx);
-	
-	cons_update_cursor(cons);
-}
-
-static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
-{
-	sysarg_t col;
-	sysarg_t row;
-	
-	fibril_mutex_lock(&cons->mtx);
-	chargrid_get_cursor(cons->frontbuf, &col, &row);
-	fibril_mutex_unlock(&cons->mtx);
-	
-	async_answer_2(iid, EOK, col, row);
-}
-
-static void cons_write(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
-{
-	void *buf;
-	size_t size;
-	int rc = async_data_write_accept(&buf, false, 0, 0, 0, &size);
-	
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	size_t off = 0;
-	while (off < size)
-		cons_write_char(cons, str_decode(buf, &off, size));
-	
-	async_answer_1(iid, EOK, size);
-	free(buf);
-}
-
-static void cons_read(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
-{
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_read_receive(&callid, &size)) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	char *buf = (char *) malloc(size);
-	if (buf == NULL) {
-		async_answer_0(callid, ENOMEM);
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
+static int cons_open(con_srvs_t *srvs, con_srv_t *srv)
+{
+	return EOK;
+}
+
+static int cons_close(con_srv_t *srv)
+{
+	return EOK;
+}
+
+static int cons_read(con_srv_t *srv, void *buf, size_t size)
+{
+	uint8_t *bbuf = buf;
+	console_t *cons = srv_to_console(srv);
 	size_t pos = 0;
 	
@@ -364,5 +352,5 @@
 		/* Copy to the buffer remaining characters. */
 		while ((pos < size) && (cons->char_remains_len > 0)) {
-			buf[pos] = cons->char_remains[0];
+			bbuf[pos] = cons->char_remains[0];
 			pos++;
 			
@@ -389,12 +377,85 @@
 		}
 	}
-	
-	(void) async_data_read_finalize(callid, buf, size);
-	async_answer_1(iid, EOK, size);
-	free(buf);
-}
-
-static void cons_set_style(console_t *cons, console_style_t style)
-{
+
+	return size;
+}
+
+static int cons_write(con_srv_t *srv, void *data, size_t size)
+{
+	console_t *cons = srv_to_console(srv);
+
+	size_t off = 0;
+	while (off < size)
+		cons_write_char(cons, str_decode(data, &off, size));
+	return size;
+}
+
+static void cons_sync(con_srv_t *srv)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	cons_update(cons);
+}
+
+static void cons_clear(con_srv_t *srv)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	chargrid_clear(cons->frontbuf);
+	fibril_mutex_unlock(&cons->mtx);
+	
+	cons_update(cons);
+}
+
+static void cons_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	chargrid_set_cursor(cons->frontbuf, col, row);
+	fibril_mutex_unlock(&cons->mtx);
+	
+	cons_update_cursor(cons);
+}
+
+static int cons_get_pos(con_srv_t *srv, sysarg_t *col, sysarg_t *row)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	chargrid_get_cursor(cons->frontbuf, col, row);
+	fibril_mutex_unlock(&cons->mtx);
+	
+	return EOK;
+}
+
+static int cons_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	*cols = cons->cols;
+	*rows = cons->rows;
+	fibril_mutex_unlock(&cons->mtx);
+	
+	return EOK;
+}
+
+static int cons_get_color_cap(con_srv_t *srv, console_caps_t *ccaps)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	*ccaps = cons->ccaps;
+	fibril_mutex_unlock(&cons->mtx);
+	
+	return EOK;
+}
+
+static void cons_set_style(con_srv_t *srv, console_style_t style)
+{
+	console_t *cons = srv_to_console(srv);
+	
 	fibril_mutex_lock(&cons->mtx);
 	chargrid_set_style(cons->frontbuf, style);
@@ -402,7 +463,9 @@
 }
 
-static void cons_set_color(console_t *cons, console_color_t bgcolor,
+static void cons_set_color(con_srv_t *srv, console_color_t bgcolor,
     console_color_t fgcolor, console_color_attr_t attr)
 {
+	console_t *cons = srv_to_console(srv);
+	
 	fibril_mutex_lock(&cons->mtx);
 	chargrid_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
@@ -410,7 +473,9 @@
 }
 
-static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor,
+static void cons_set_rgb_color(con_srv_t *srv, pixel_t bgcolor,
     pixel_t fgcolor)
 {
+	console_t *cons = srv_to_console(srv);
+	
 	fibril_mutex_lock(&cons->mtx);
 	chargrid_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
@@ -418,11 +483,20 @@
 }
 
-static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
-{
+static void cons_set_cursor_visibility(con_srv_t *srv, bool visible)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	cons_set_cursor_vis(cons, visible);
+}
+
+static int cons_get_event(con_srv_t *srv, kbd_event_t *event)
+{
+	console_t *cons = srv_to_console(srv);
 	link_t *link = prodcons_consume(&cons->input_pc);
-	kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
-	
-	async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
-	free(event);
+	kbd_event_t *kevent = list_get_instance(link, kbd_event_t, link);
+	
+	*event = *kevent;
+	free(kevent);
+	return EOK;
 }
 
@@ -447,69 +521,9 @@
 	
 	if (atomic_postinc(&cons->refcnt) == 0)
-		cons_set_cursor_visibility(cons, true);
-	
-	/* Accept the connection */
-	async_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			return;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case VFS_OUT_READ:
-			cons_read(cons, callid, &call);
-			break;
-		case VFS_OUT_WRITE:
-			cons_write(cons, callid, &call);
-			break;
-		case VFS_OUT_SYNC:
-			cons_update(cons);
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CLEAR:
-			cons_clear(cons);
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GOTO:
-			cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GET_POS:
-			cons_get_cursor(cons, callid, &call);
-			break;
-		case CONSOLE_GET_SIZE:
-			async_answer_2(callid, EOK, cons->cols, cons->rows);
-			break;
-		case CONSOLE_GET_COLOR_CAP:
-			async_answer_1(callid, EOK, cons->ccaps);
-			break;
-		case CONSOLE_SET_STYLE:
-			cons_set_style(cons, IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_SET_COLOR:
-			cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
-			    IPC_GET_ARG3(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_SET_RGB_COLOR:
-			cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CURSOR_VISIBILITY:
-			cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GET_EVENT:
-			cons_get_event(cons, callid, &call);
-			break;
-		default:
-			async_answer_0(callid, EINVAL);
-		}
-	}
-}
+		cons_set_cursor_vis(cons, true);
+	
+	con_conn(iid, icall, &cons->srvs);
+}
+
 
 static int input_connect(const char *svc)
@@ -624,4 +638,8 @@
 		}
 		
+		con_srvs_init(&consoles[i].srvs);
+		consoles[i].srvs.ops = &con_ops;
+		consoles[i].srvs.sarg = &consoles[i];
+		
 		char vc[LOC_NAME_MAXLEN + 1];
 		snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
Index: uspace/srv/hid/input/gsp.c
===================================================================
--- uspace/srv/hid/input/gsp.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/hid/input/gsp.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -87,6 +87,6 @@
 	.key_hash = trans_key_hash,
 	.key_equal = trans_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
Index: uspace/srv/hid/remcons/remcons.c
===================================================================
--- uspace/srv/hid/remcons/remcons.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/hid/remcons/remcons.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -34,10 +34,8 @@
 
 #include <async.h>
+#include <errno.h>
+#include <io/con_srv.h>
 #include <stdio.h>
-#include <adt/prodcons.h>
-#include <ipc/input.h>
-#include <ipc/console.h>
-#include <ipc/vfs.h>
-#include <errno.h>
+#include <stdlib.h>
 #include <str_error.h>
 #include <loc.h>
@@ -45,6 +43,4 @@
 #include <io/keycode.h>
 #include <align.h>
-#include <malloc.h>
-#include <as.h>
 #include <fibril_synch.h>
 #include <task.h>
@@ -75,116 +71,131 @@
     sizeof(telnet_force_character_mode_command) / sizeof(telnet_cmd_t);
 
-
-/** Handling client requests (VFS and console interface).
- *
- * @param user Telnet user the requests belong to.
- */
-static void client_connection_message_loop(telnet_user_t *user)
-{
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = 0;
-
-		/*
-		 * The getterm task might terminate while we are here,
-		 * waiting for a call. Also, the socket might be closed
-		 * meanwhile.
-		 * We want to detect this situation early, so we use a
-		 * timeout variant of async_get_call().
-		 */
-		while (callid == 0) {
-			callid = async_get_call_timeout(&call, 1000);
-
-			if (telnet_user_is_zombie(user)) {
-				if (callid != 0) {
-					async_answer_0(callid, EINTR);
-				}
-				return;
-			}
-		}
-		
-		if (!IPC_GET_IMETHOD(call)) {
-			return;
-		}
-
-		switch (IPC_GET_IMETHOD(call)) {
-		case CONSOLE_GET_SIZE:
-			async_answer_2(callid, EOK, 100, 1);
-			break;
-		case CONSOLE_GET_POS:
-			fibril_mutex_lock(&user->guard);
-			async_answer_2(callid, EOK, user->cursor_x, 0);
-			fibril_mutex_unlock(&user->guard);
-			break;
-		case CONSOLE_GET_EVENT: {
-			kbd_event_t event;
-			int rc = telnet_user_get_next_keyboard_event(user, &event);
-			if (rc != EOK) {
-				/* Silently ignore. */
-				async_answer_0(callid, EOK);
-				break;
-			}
-			async_answer_4(callid, EOK, event.type, event.key, event.mods, event.c);
-			break;
-		}
-		case CONSOLE_GOTO: {
-			int new_x = IPC_GET_ARG1(call);
-			telnet_user_update_cursor_x(user, new_x);
-			async_answer_0(callid, ENOTSUP);
-			break;
-		}
-		case VFS_OUT_READ:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		case VFS_OUT_WRITE: {
-			uint8_t *buf;
-			size_t size;
-			int rc = async_data_write_accept((void **)&buf, false, 0, 0, 0, &size);
-
-			if (rc != EOK) {
-				async_answer_0(callid, rc);
-				break;
-			}
-
-			rc = telnet_user_send_data(user, buf, size);
-			free(buf);
-
-			if (rc != EOK) {
-				async_answer_0(callid, rc);
-				break;
-			}
-
-			async_answer_1(callid, EOK, size);
-			break;
-		}
-		case VFS_OUT_SYNC:
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CLEAR:
-			async_answer_0(callid, EOK);
-			break;
-
-		case CONSOLE_GET_COLOR_CAP:
-			async_answer_1(callid, EOK, CONSOLE_CAP_NONE);
-			break;
-		case CONSOLE_SET_STYLE:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		case CONSOLE_SET_COLOR:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		case CONSOLE_SET_RGB_COLOR:
-			async_answer_0(callid, ENOTSUP);
-			break;
-
-		case CONSOLE_CURSOR_VISIBILITY:
-			async_answer_0(callid, ENOTSUP);
-			break;
-
-		default:
-			async_answer_0(callid, EINVAL);
-			break;
-		}
-	}
+static int remcons_open(con_srvs_t *, con_srv_t *);
+static int remcons_close(con_srv_t *);
+static int remcons_write(con_srv_t *, void *, size_t);
+static void remcons_sync(con_srv_t *);
+static void remcons_clear(con_srv_t *);
+static void remcons_set_pos(con_srv_t *, sysarg_t col, sysarg_t row);
+static int remcons_get_pos(con_srv_t *, sysarg_t *, sysarg_t *);
+static int remcons_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
+static int remcons_get_color_cap(con_srv_t *, console_caps_t *);
+static int remcons_get_event(con_srv_t *, kbd_event_t *);
+
+static con_ops_t con_ops = {
+	.open = remcons_open,
+	.close = remcons_close,
+	.read = NULL,
+	.write = remcons_write,
+	.sync = remcons_sync,
+	.clear = remcons_clear,
+	.set_pos = remcons_set_pos,
+	.get_pos = remcons_get_pos,
+	.get_size = remcons_get_size,
+	.get_color_cap = remcons_get_color_cap,
+	.set_style = NULL,
+	.set_color = NULL,
+	.set_rgb_color = NULL,
+	.set_cursor_visibility = NULL,
+	.get_event = remcons_get_event
+};
+
+static telnet_user_t *srv_to_user(con_srv_t *srv)
+{
+	return srv->srvs->sarg;
+}
+
+static int remcons_open(con_srvs_t *srvs, con_srv_t *srv)
+{
+	telnet_user_t *user = srv_to_user(srv);
+
+	telnet_user_log(user, "New client connected (%p).", srv);
+
+	/* Force character mode. */
+	send(user->socket, (void *)telnet_force_character_mode_command,
+	    telnet_force_character_mode_command_count, 0);
+
+	return EOK;
+}
+
+static int remcons_close(con_srv_t *srv)
+{
+	telnet_user_t *user = srv_to_user(srv);
+
+	telnet_user_notify_client_disconnected(user);
+	telnet_user_log(user, "Client disconnected (%p).", srv);
+
+	return EOK;
+}
+
+static int remcons_write(con_srv_t *srv, void *data, size_t size)
+{
+	telnet_user_t *user = srv_to_user(srv);
+	int rc;
+
+	rc = telnet_user_send_data(user, data, size);
+	if (rc != EOK)
+		return rc;
+
+	return size;
+}
+
+static void remcons_sync(con_srv_t *srv)
+{
+	(void) srv;
+}
+
+static void remcons_clear(con_srv_t *srv)
+{
+	(void) srv;
+}
+
+static void remcons_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
+{
+	telnet_user_t *user = srv_to_user(srv);
+
+	telnet_user_update_cursor_x(user, col);
+}
+
+static int remcons_get_pos(con_srv_t *srv, sysarg_t *col, sysarg_t *row)
+{
+	telnet_user_t *user = srv_to_user(srv);
+
+	*col = user->cursor_x;
+	*row = 0;
+
+	return EOK;
+}
+
+static int remcons_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
+{
+	(void) srv;
+
+	*cols = 100;
+	*rows = 1;
+
+	return EOK;
+}
+
+static int remcons_get_color_cap(con_srv_t *srv, console_caps_t *ccaps)
+{
+	(void) srv;
+	*ccaps = CONSOLE_CAP_NONE;
+
+	return EOK;
+}
+
+static int remcons_get_event(con_srv_t *srv, kbd_event_t *event)
+{
+	telnet_user_t *user = srv_to_user(srv);
+	int rc;
+
+	rc = telnet_user_get_next_keyboard_event(user, event);
+	if (rc != EOK) {
+		/* XXX What? */
+		memset(event, 0, sizeof(*event));
+		return EOK;
+	}
+
+	return EOK;
 }
 
@@ -198,17 +209,7 @@
 		return;
 	}
-	async_answer_0(iid, EOK);
-
-	telnet_user_log(user, "New client connected (%" PRIxn").", iid);
-
-	/* Force character mode. */
-	send(user->socket, (void *)telnet_force_character_mode_command,
-	    telnet_force_character_mode_command_count, 0);
 
 	/* Handle messages. */
-	client_connection_message_loop(user);
-
-	telnet_user_notify_client_disconnected(user);
-	telnet_user_log(user, "Client disconnected (%" PRIxn").", iid);
+	con_conn(iid, icall, &user->srvs);
 }
 
@@ -232,4 +233,5 @@
 		fibril_mutex_lock(&user->guard);
 		user->task_finished = true;
+		user->srvs.aborted = true;
 		fibril_condvar_signal(&user->refcount_cv);
 		fibril_mutex_unlock(&user->guard);
@@ -251,4 +253,5 @@
 	fibril_mutex_lock(&user->guard);
 	user->task_finished = true;
+	user->srvs.aborted = true;
 	fibril_condvar_signal(&user->refcount_cv);
 	fibril_mutex_unlock(&user->guard);
@@ -295,4 +298,5 @@
 			closesocket(user->socket);
 			user->socket_closed = true;
+			user->srvs.aborted = true;
 			continue;
 		} else if (user->socket_closed) {
@@ -380,4 +384,11 @@
 		assert(user);
 
+		con_srvs_init(&user->srvs);
+		user->srvs.ops = &con_ops;
+		user->srvs.sarg = user;
+		user->srvs.abort_timeout = 1000;
+
+		telnet_user_add(user);
+
 		fid_t fid = fibril_create(network_user_fibril, user);
 		assert(fid);
Index: uspace/srv/hid/remcons/user.c
===================================================================
--- uspace/srv/hid/remcons/user.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/hid/remcons/user.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -35,7 +35,4 @@
 #include <stdio.h>
 #include <adt/prodcons.h>
-#include <ipc/input.h>
-#include <ipc/console.h>
-#include <ipc/vfs.h>
 #include <errno.h>
 #include <str_error.h>
@@ -95,12 +92,14 @@
 	user->locsrv_connection_count = 0;
 
-
+	user->cursor_x = 0;
+
+	return user;
+}
+
+void telnet_user_add(telnet_user_t *user)
+{
 	fibril_mutex_lock(&users_guard);
 	list_append(&user->link, &users);
 	fibril_mutex_unlock(&users_guard);
-
-	user->cursor_x = 0;
-
-	return user;
 }
 
@@ -199,4 +198,5 @@
 		if ((recv_length == 0) || (recv_length == ENOTCONN)) {
 			user->socket_closed = true;
+			user->srvs.aborted = true;
 			return ENOENT;
 		}
Index: uspace/srv/hid/remcons/user.h
===================================================================
--- uspace/srv/hid/remcons/user.h	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/hid/remcons/user.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -36,6 +36,8 @@
 #define TELNET_USER_H_
 
+#include <adt/prodcons.h>
 #include <fibril_synch.h>
 #include <inttypes.h>
+#include <io/con_srv.h>
 #include "remcons.h"
 
@@ -55,4 +57,6 @@
 	/** Path name of the service. */
 	char *service_name;
+	/** Console service setup */
+	con_srvs_t srvs;
 
 	/** Producer-consumer of kbd_event_t. */
@@ -77,4 +81,5 @@
 
 extern telnet_user_t *telnet_user_create(int);
+extern void telnet_user_add(telnet_user_t *);
 extern void telnet_user_destroy(telnet_user_t *);
 extern telnet_user_t *telnet_user_get_for_client_connection(service_id_t);
Index: uspace/srv/locsrv/locsrv.c
===================================================================
--- uspace/srv/locsrv/locsrv.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/locsrv/locsrv.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -1353,4 +1353,7 @@
 	categ_dir_add_cat(&cdir, cat);
 
+	cat = category_new("clock");
+	categ_dir_add_cat(&cdir, cat);
+
 	cat = category_new("test3");
 	categ_dir_add_cat(&cdir, cat);
Index: uspace/srv/logger/Makefile
===================================================================
--- uspace/srv/logger/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/logger/Makefile	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2012 Vojtech Horky
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = logger
+STATIC_NEEDED = y
+
+SOURCES = \
+	ctl.c \
+	initlvl.c \
+	level.c \
+	logs.c \
+	main.c \
+	writer.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/logger/ctl.c
===================================================================
--- uspace/srv/logger/ctl.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/logger/ctl.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 logger
+ * @{
+ */
+
+/** @file
+ */
+
+#include <unistd.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <errno.h>
+#include <io/logctl.h>
+#include <ipc/logger.h>
+#include "logger.h"
+
+static int handle_log_level_change(sysarg_t new_level)
+{
+	void *full_name;
+	int rc = async_data_write_accept(&full_name, true, 0, 0, 0, NULL);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	logger_log_t *log = find_log_by_name_and_lock(full_name);
+	free(full_name);
+	if (log == NULL)
+		return ENOENT;
+
+	log->logged_level = new_level;
+
+	log_unlock(log);
+
+	return EOK;
+}
+
+void logger_connection_handler_control(ipc_callid_t callid)
+{
+	async_answer_0(callid, EOK);
+	logger_log("control: new client.\n");
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+
+		if (!IPC_GET_IMETHOD(call))
+			break;
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case LOGGER_CONTROL_SET_DEFAULT_LEVEL: {
+			int rc = set_default_logging_level(IPC_GET_ARG1(call));
+			async_answer_0(callid, rc);
+			break;
+		}
+		case LOGGER_CONTROL_SET_LOG_LEVEL: {
+			int rc = handle_log_level_change(IPC_GET_ARG1(call));
+			async_answer_0(callid, rc);
+			break;
+		}
+		default:
+			async_answer_0(callid, EINVAL);
+			break;
+		}
+	}
+
+	logger_log("control: client terminated.\n");
+}
+
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/initlvl.c
===================================================================
--- uspace/srv/logger/initlvl.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/logger/initlvl.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 logger
+ * @{
+ */
+
+/** @file
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <sysinfo.h>
+#include <str.h>
+#include "logger.h"
+
+static void parse_single_level_setting(char *setting)
+{
+	char *tmp;
+	char *key = strtok_r(setting, "=", &tmp);
+	char *value = strtok_r(NULL, "=", &tmp);
+	if (key == NULL)
+		return;
+	if (value == NULL) {
+		log_level_t level;
+		int rc = log_level_from_str(key, &level);
+		if (rc != EOK)
+			return;
+		set_default_logging_level(level);
+		return;
+	}
+
+
+	log_level_t level;
+	int rc = log_level_from_str(value, &level);
+	if (rc != EOK)
+		return;
+
+	logger_log_t *log = find_or_create_log_and_lock(key, 0);
+	if (log == NULL)
+		return;
+
+	log->logged_level = level;
+	log->ref_counter++;
+
+	log_unlock(log);
+}
+
+void parse_level_settings(char *settings)
+{
+	char *tmp;
+	char *single_setting = strtok_r(settings, " ", &tmp);
+	while (single_setting != NULL) {
+		parse_single_level_setting(single_setting);
+		single_setting = strtok_r(NULL, " ", &tmp);
+	}
+}
+
+void parse_initial_settings(void)
+{
+	size_t argument_size;
+	void *argument = sysinfo_get_data("init_args.logger", &argument_size);
+	if (argument == NULL)
+		return;
+
+	char level_str[200];
+	str_cpy(level_str, 200, (const char *) argument);
+
+	parse_level_settings(level_str);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/level.c
===================================================================
--- uspace/srv/logger/level.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/logger/level.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 logger
+ * @{
+ */
+
+/** @file
+ */
+
+#include <errno.h>
+#include "logger.h"
+
+log_level_t default_logging_level = LVL_NOTE;
+static FIBRIL_MUTEX_INITIALIZE(default_logging_level_guard);
+
+log_level_t get_default_logging_level(void)
+{
+	fibril_mutex_lock(&default_logging_level_guard);
+	log_level_t result = default_logging_level;
+	fibril_mutex_unlock(&default_logging_level_guard);
+	return result;
+}
+
+int set_default_logging_level(log_level_t new_level)
+{
+	if (new_level >= LVL_LIMIT)
+		return ERANGE;
+	fibril_mutex_lock(&default_logging_level_guard);
+	default_logging_level = new_level;
+	fibril_mutex_unlock(&default_logging_level_guard);
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/logger.h
===================================================================
--- uspace/srv/logger/logger.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/logger/logger.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 logger
+ * @{
+ */
+/** @file Common logger service definitions.
+ */
+
+#ifndef LOGGER_H_
+#define LOGGER_H_
+
+#include <adt/list.h>
+#include <adt/prodcons.h>
+#include <io/log.h>
+#include <async.h>
+#include <bool.h>
+#include <fibril_synch.h>
+#include <stdio.h>
+
+#define NAME "logger"
+#define LOG_LEVEL_USE_DEFAULT (LVL_LIMIT + 1)
+
+#ifdef LOGGER_LOG
+#define logger_log(fmt, ...) printf(NAME ": " fmt, ##__VA_ARGS__)
+#else
+#define logger_log(fmt, ...) (void)0
+#endif
+
+typedef struct logger_log logger_log_t;
+
+typedef struct {
+	fibril_mutex_t guard;
+	char *filename;
+	FILE *logfile;
+} logger_dest_t;
+
+struct logger_log {
+	link_t link;
+
+	size_t ref_counter;
+
+	fibril_mutex_t guard;
+
+	char *name;
+	char *full_name;
+	logger_log_t *parent;
+	log_level_t logged_level;
+	logger_dest_t *dest;
+};
+
+#define MAX_REFERENCED_LOGS_PER_CLIENT 100
+
+typedef struct {
+	size_t logs_count;
+	logger_log_t *logs[MAX_REFERENCED_LOGS_PER_CLIENT];
+} logger_registered_logs_t;
+
+logger_log_t *find_log_by_name_and_lock(const char *name);
+logger_log_t *find_or_create_log_and_lock(const char *, sysarg_t);
+logger_log_t *find_log_by_id_and_lock(sysarg_t);
+bool shall_log_message(logger_log_t *, log_level_t);
+void log_unlock(logger_log_t *);
+void write_to_log(logger_log_t *, log_level_t, const char *);
+void log_release(logger_log_t *);
+
+void registered_logs_init(logger_registered_logs_t *);
+bool register_log(logger_registered_logs_t *, logger_log_t *);
+void unregister_logs(logger_registered_logs_t *);
+
+log_level_t get_default_logging_level(void);
+int set_default_logging_level(log_level_t);
+
+
+void logger_connection_handler_control(ipc_callid_t);
+void logger_connection_handler_writer(ipc_callid_t);
+
+void parse_initial_settings(void);
+void parse_level_settings(char *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/logger/logs.c
===================================================================
--- uspace/srv/logger/logs.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/logger/logs.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 logger
+ * @{
+ */
+#include <assert.h>
+#include <malloc.h>
+#include <str.h>
+#include <stdio.h>
+#include <errno.h>
+#include "logger.h"
+
+
+static FIBRIL_MUTEX_INITIALIZE(log_list_guard);
+static LIST_INITIALIZE(log_list);
+
+
+static logger_log_t *find_log_by_name_and_parent_no_list_lock(const char *name, logger_log_t *parent)
+{
+	list_foreach(log_list, it) {
+		logger_log_t *log = list_get_instance(it, logger_log_t, link);
+		if ((parent == log->parent) && (str_cmp(log->name, name) == 0))
+			return log;
+	}
+
+	return NULL;
+}
+
+static int create_dest(const char *name, logger_dest_t **dest)
+{
+	logger_dest_t *result = malloc(sizeof(logger_dest_t));
+	if (result == NULL)
+		return ENOMEM;
+	int rc = asprintf(&result->filename, "/log/%s", name);
+	if (rc < 0) {
+		free(result);
+		return ENOMEM;
+	}
+	result->logfile = NULL;
+	fibril_mutex_initialize(&result->guard);
+	*dest = result;
+	return EOK;
+}
+
+static logger_log_t *create_log_no_locking(const char *name, logger_log_t *parent)
+{
+	logger_log_t *result = calloc(1, sizeof(logger_log_t));
+	if (result == NULL)
+		return NULL;
+
+	result->name = str_dup(name);
+	if (result->name == NULL)
+		goto error;
+
+	/*
+	 * Notice that we create new dest as the last
+	 * operation that can fail and thus there is no code
+	 * to deallocate dest.
+	 */
+	if (parent == NULL) {
+		result->full_name = str_dup(name);
+		if (result->full_name == NULL)
+			goto error;
+		int rc = create_dest(name, &result->dest);
+		if (rc != EOK)
+			goto error;
+	} else {
+		int rc = asprintf(&result->full_name, "%s/%s",
+		    parent->full_name, name);
+		if (rc < 0)
+			goto error;
+		result->dest = parent->dest;
+	}
+
+	/* Following initializations cannot fail. */
+	result->logged_level = LOG_LEVEL_USE_DEFAULT;
+	fibril_mutex_initialize(&result->guard);
+	link_initialize(&result->link);
+	result->parent = parent;
+
+	return result;
+
+error:
+	free(result->name);
+	free(result->full_name);
+	free(result);
+	return NULL;
+
+}
+
+logger_log_t *find_or_create_log_and_lock(const char *name, sysarg_t parent_id)
+{
+	logger_log_t *result = NULL;
+	logger_log_t *parent = (logger_log_t *) parent_id;
+
+	fibril_mutex_lock(&log_list_guard);
+
+	result = find_log_by_name_and_parent_no_list_lock(name, parent);
+	if (result == NULL) {
+		result = create_log_no_locking(name, parent);
+		if (result == NULL)
+			goto leave;
+		list_append(&result->link, &log_list);
+		if (result->parent != NULL) {
+			fibril_mutex_lock(&result->parent->guard);
+			result->parent->ref_counter++;
+			fibril_mutex_unlock(&result->parent->guard);
+		}
+	}
+
+	fibril_mutex_lock(&result->guard);
+
+leave:
+	fibril_mutex_unlock(&log_list_guard);
+
+	return result;
+}
+
+logger_log_t *find_log_by_name_and_lock(const char *name)
+{
+	logger_log_t *result = NULL;
+
+	fibril_mutex_lock(&log_list_guard);
+	list_foreach(log_list, it) {
+		logger_log_t *log = list_get_instance(it, logger_log_t, link);
+		if (str_cmp(log->full_name, name) == 0) {
+			fibril_mutex_lock(&log->guard);
+			result = log;
+			break;
+		}
+	}
+	fibril_mutex_unlock(&log_list_guard);
+
+	return result;
+}
+
+logger_log_t *find_log_by_id_and_lock(sysarg_t id)
+{
+	logger_log_t *result = NULL;
+
+	fibril_mutex_lock(&log_list_guard);
+	list_foreach(log_list, it) {
+		logger_log_t *log = list_get_instance(it, logger_log_t, link);
+		if ((sysarg_t) log == id) {
+			fibril_mutex_lock(&log->guard);
+			result = log;
+			break;
+		}
+	}
+	fibril_mutex_unlock(&log_list_guard);
+
+	return result;
+}
+
+static log_level_t get_actual_log_level(logger_log_t *log)
+{
+	/* Find recursively proper log level. */
+	if (log->logged_level == LOG_LEVEL_USE_DEFAULT) {
+		if (log->parent == NULL)
+			return get_default_logging_level();
+		else
+			return get_actual_log_level(log->parent);
+	}
+	return log->logged_level;
+}
+
+bool shall_log_message(logger_log_t *log, log_level_t level)
+{
+	fibril_mutex_lock(&log_list_guard);
+	bool result = level <= get_actual_log_level(log);
+	fibril_mutex_unlock(&log_list_guard);
+	return result;
+}
+
+void log_unlock(logger_log_t *log)
+{
+	assert(fibril_mutex_is_locked(&log->guard));
+	fibril_mutex_unlock(&log->guard);
+}
+
+/** Decreases reference counter on the log and destory the log if
+ * necessary.
+ *
+ * Precondition: log is locked.
+ *
+ * @param log Log to release from using by the caller.
+ */
+void log_release(logger_log_t *log)
+{
+	assert(fibril_mutex_is_locked(&log->guard));
+	assert(log->ref_counter > 0);
+
+	/* We are definitely not the last ones. */
+	if (log->ref_counter > 1) {
+		log->ref_counter--;
+		fibril_mutex_unlock(&log->guard);
+		return;
+	}
+
+	/*
+	 * To prevent deadlock, we need to get the list lock first.
+	 * Deadlock scenario:
+	 * Us: LOCKED(log), want to LOCK(list)
+	 * Someone else calls find_log_by_name_and_lock(log->fullname) ->
+	 *   LOCKED(list), wants to LOCK(log)
+	 */
+	fibril_mutex_unlock(&log->guard);
+
+	/* Ensuring correct locking order. */
+	fibril_mutex_lock(&log_list_guard);
+	/*
+	 * The reference must be still valid because we have not decreased
+	 * the reference counter.
+	 */
+	fibril_mutex_lock(&log->guard);
+	assert(log->ref_counter > 0);
+	log->ref_counter--;
+
+	if (log->ref_counter > 0) {
+		/*
+		 * Meanwhile, someone else increased the ref counter.
+		 * No big deal, we just return immediatelly.
+		 */
+		fibril_mutex_unlock(&log->guard);
+		fibril_mutex_unlock(&log_list_guard);
+		return;
+	}
+
+	/*
+	 * Here we are on a destroy path. We need to
+	 * - remove ourselves from the list
+	 * - decrease reference of the parent (if not top-level log)
+	 *   - we must do that after we relaase list lock to prevent
+	 *     deadlock with ourselves
+	 * - destroy dest (if top-level log)
+	 */
+	assert(log->ref_counter == 0);
+
+	list_remove(&log->link);
+	fibril_mutex_unlock(&log_list_guard);
+	fibril_mutex_unlock(&log->guard);
+
+	if (log->parent == NULL) {
+		/*
+		 * Due to lazy file opening in write_to_log(),
+		 * it is possible that no file was actually opened.
+		 */
+		if (log->dest->logfile != NULL) {
+			fclose(log->dest->logfile);
+		}
+		free(log->dest->filename);
+		free(log->dest);
+	} else {
+		fibril_mutex_lock(&log->parent->guard);
+		log_release(log->parent);
+	}
+
+	logger_log("Destroyed log %s.\n", log->full_name);
+
+	free(log->name);
+	free(log->full_name);
+
+	free(log);
+}
+
+
+void write_to_log(logger_log_t *log, log_level_t level, const char *message)
+{
+	assert(fibril_mutex_is_locked(&log->guard));
+	assert(log->dest != NULL);
+	fibril_mutex_lock(&log->dest->guard);
+	if (log->dest->logfile == NULL)
+		log->dest->logfile = fopen(log->dest->filename, "a");
+
+	if (log->dest->logfile != NULL) {
+		fprintf(log->dest->logfile, "[%s] %s: %s\n",
+		    log->full_name, log_level_str(level),
+		    (const char *) message);
+		fflush(log->dest->logfile);
+	}
+
+	fibril_mutex_unlock(&log->dest->guard);
+}
+
+void registered_logs_init(logger_registered_logs_t *logs)
+{
+	logs->logs_count = 0;
+}
+
+bool register_log(logger_registered_logs_t *logs, logger_log_t *new_log)
+{
+	if (logs->logs_count >= MAX_REFERENCED_LOGS_PER_CLIENT) {
+		return false;
+	}
+
+	assert(fibril_mutex_is_locked(&new_log->guard));
+	new_log->ref_counter++;
+
+	logs->logs[logs->logs_count] = new_log;
+	logs->logs_count++;
+
+	return true;
+}
+
+void unregister_logs(logger_registered_logs_t *logs)
+{
+	for (size_t i = 0; i < logs->logs_count; i++) {
+		logger_log_t *log = logs->logs[i];
+		fibril_mutex_lock(&log->guard);
+		log_release(log);
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/main.c
===================================================================
--- uspace/srv/logger/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/logger/main.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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.
+ */
+
+/**
+ * @defgroup logger Logging service.
+ * @brief HelenOS logging service.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <ipc/services.h>
+#include <ipc/logger.h>
+#include <io/log.h>
+#include <io/logctl.h>
+#include <ns.h>
+#include <async.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <malloc.h>
+#include "logger.h"
+
+static void connection_handler(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	logger_interface_t iface = IPC_GET_ARG1(*icall);
+
+	switch (iface) {
+	case LOGGER_INTERFACE_CONTROL:
+		logger_connection_handler_control(iid);
+		break;
+	case LOGGER_INTERFACE_WRITER:
+		logger_connection_handler_writer(iid);
+		break;
+	default:
+		async_answer_0(iid, EINVAL);
+		break;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS Logging Service\n");
+	
+	parse_initial_settings();
+	for (int i = 1; i < argc; i++) {
+		parse_level_settings(argv[i]);
+	}
+
+	async_set_client_connection(connection_handler);
+	
+	int rc = service_register(SERVICE_LOGGER);
+	if (rc != EOK) {
+		printf(NAME ": failed to register: %s.\n", str_error(rc));
+		return -1;
+	}
+	
+	printf(NAME ": Accepting connections\n");
+	async_manager();
+	
+	/* Never reached */
+	return 0;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/writer.c
===================================================================
--- uspace/srv/logger/writer.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ uspace/srv/logger/writer.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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.
+ */
+
+/**
+ * @defgroup logger Logging service.
+ * @brief HelenOS logging service.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <ipc/services.h>
+#include <ipc/logger.h>
+#include <io/log.h>
+#include <io/logctl.h>
+#include <ns.h>
+#include <async.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <malloc.h>
+#include "logger.h"
+
+
+static logger_log_t *handle_create_log(sysarg_t parent)
+{
+	void *name;
+	int rc = async_data_write_accept(&name, true, 1, 0, 0, NULL);
+	if (rc != EOK)
+		return NULL;
+
+	logger_log_t *log = find_or_create_log_and_lock(name, parent);
+
+	free(name);
+
+	return log;
+}
+
+static int handle_receive_message(sysarg_t log_id, sysarg_t level)
+{
+	logger_log_t *log = find_log_by_id_and_lock(log_id);
+	if (log == NULL)
+		return ENOENT;
+
+	void *message = NULL;
+	int rc = async_data_write_accept(&message, true, 1, 0, 0, NULL);
+	if (rc != EOK)
+		goto leave;
+
+	if (!shall_log_message(log, level)) {
+		rc = EOK;
+		goto leave;
+	}
+
+	printf("[%s] %s: %s\n",
+	    log->full_name, log_level_str(level),
+	    (const char *) message);
+	write_to_log(log, level, message);
+
+	rc = EOK;
+
+leave:
+	log_unlock(log);
+	free(message);
+
+	return rc;
+}
+
+void logger_connection_handler_writer(ipc_callid_t callid)
+{
+	/* Acknowledge the connection. */
+	async_answer_0(callid, EOK);
+
+	logger_log("writer: new client.\n");
+
+	logger_registered_logs_t registered_logs;
+	registered_logs_init(&registered_logs);
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+
+		if (!IPC_GET_IMETHOD(call))
+			break;
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case LOGGER_WRITER_CREATE_LOG: {
+			logger_log_t *log = handle_create_log(IPC_GET_ARG1(call));
+			if (log == NULL) {
+				async_answer_0(callid, ENOMEM);
+				break;
+			}
+			if (!register_log(&registered_logs, log)) {
+				log_unlock(log);
+				async_answer_0(callid, ELIMIT);
+				break;
+			}
+			log_unlock(log);
+			async_answer_1(callid, EOK, (sysarg_t) log);
+			break;
+		}
+		case LOGGER_WRITER_MESSAGE: {
+			int rc = handle_receive_message(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			async_answer_0(callid, rc);
+			break;
+		}
+		default:
+			async_answer_0(callid, EINVAL);
+			break;
+		}
+	}
+
+	unregister_logs(&registered_logs);
+	logger_log("writer: client terminated.\n");
+}
+
+
+/**
+ * @}
+ */
Index: uspace/srv/net/ethip/arp.c
===================================================================
--- uspace/srv/net/ethip/arp.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/ethip/arp.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -59,5 +59,5 @@
 	ethip_link_addr_t *laddr;
 
-	log_msg(LVL_DEBUG, "arp_received()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "arp_received()");
 
 	rc = arp_pdu_decode(frame->data, frame->size, &packet);
@@ -65,10 +65,10 @@
 		return;
 
-	log_msg(LVL_DEBUG, "ARP PDU decoded, opcode=%d, tpa=%x",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ARP PDU decoded, opcode=%d, tpa=%x",
 	    packet.opcode, packet.target_proto_addr.ipv4);
 
 	laddr = ethip_nic_addr_find(nic, &packet.target_proto_addr);
 	if (laddr != NULL) {
-		log_msg(LVL_DEBUG, "Request/reply to my address");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Request/reply to my address");
 
 		(void) atrans_add(&packet.sender_proto_addr,
@@ -122,5 +122,5 @@
 	size_t fsize;
 
-	log_msg(LVL_DEBUG, "arp_send_packet()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "arp_send_packet()");
 
 	rc = arp_pdu_encode(packet, &pdata, &psize);
Index: uspace/srv/net/ethip/ethip.c
===================================================================
--- uspace/srv/net/ethip/ethip.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/ethip/ethip.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -77,5 +77,5 @@
 	int rc = loc_server_register(NAME);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering server.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server.");
 		return rc;
 	}
@@ -96,5 +96,5 @@
 	char *svc_name = NULL;
 
-	log_msg(LVL_DEBUG, "ethip_iplink_init()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_iplink_init()");
 
 	iplink_srv_init(&nic->iplink);
@@ -104,5 +104,5 @@
 	rc = asprintf(&svc_name, "net/eth%u", ++link_num);
 	if (rc < 0) {
-		log_msg(LVL_ERROR, "Out of memory.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Out of memory.");
 		goto error;
 	}
@@ -110,5 +110,5 @@
 	rc = loc_service_register(svc_name, &sid);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering service %s.", svc_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service %s.", svc_name);
 		goto error;
 	}
@@ -118,5 +118,5 @@
 	rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed resolving category 'iplink'.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'iplink'.");
 		goto error;
 	}
@@ -124,5 +124,5 @@
 	rc = loc_service_add_to_cat(sid, iplink_cat);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed adding %s to category.", svc_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding %s to category.", svc_name);
 		goto error;
 	}
@@ -142,8 +142,8 @@
 
 	sid = (service_id_t)IPC_GET_ARG1(*icall);
-	log_msg(LVL_DEBUG, "ethip_client_conn(%u)", (unsigned)sid);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_client_conn(%u)", (unsigned)sid);
 	nic = ethip_nic_find_by_iplink_sid(sid);
 	if (nic == NULL) {
-		log_msg(LVL_WARN, "Uknown service ID.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Uknown service ID.");
 		return;
 	}
@@ -154,5 +154,5 @@
 static int ethip_open(iplink_srv_t *srv)
 {
-	log_msg(LVL_DEBUG, "ethip_open()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_open()");
 	return EOK;
 }
@@ -160,5 +160,5 @@
 static int ethip_close(iplink_srv_t *srv)
 {
-	log_msg(LVL_DEBUG, "ethip_close()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_close()");
 	return EOK;
 }
@@ -173,9 +173,9 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "ethip_send()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_send()");
 
 	rc = arp_translate(nic, &sdu->lsrc, &sdu->ldest, &dest_mac_addr);
 	if (rc != EOK) {
-		log_msg(LVL_WARN, "Failed to look up IP address 0x%" PRIx32,
+		log_msg(LOG_DEFAULT, LVL_WARN, "Failed to look up IP address 0x%" PRIx32,
 		    sdu->ldest.ipv4);
 		return rc;
@@ -200,5 +200,5 @@
 int ethip_received(iplink_srv_t *srv, void *data, size_t size)
 {
-	log_msg(LVL_DEBUG, "ethip_received(): srv=%p", srv);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_received(): srv=%p", srv);
 	ethip_nic_t *nic = (ethip_nic_t *)srv->arg;
 	eth_frame_t frame;
@@ -206,10 +206,10 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "ethip_received()");
-
-	log_msg(LVL_DEBUG, " - eth_pdu_decode");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_received()");
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - eth_pdu_decode");
 	rc = eth_pdu_decode(data, size, &frame);
 	if (rc != EOK) {
-		log_msg(LVL_DEBUG, " - eth_pdu_decode failed");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, " - eth_pdu_decode failed");
 		return rc;
 	}
@@ -220,14 +220,14 @@
 		break;
 	case ETYPE_IP:
-		log_msg(LVL_DEBUG, " - construct SDU");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, " - construct SDU");
 		sdu.lsrc.ipv4 = (192 << 24) | (168 << 16) | (0 << 8) | 1;
 		sdu.ldest.ipv4 = (192 << 24) | (168 << 16) | (0 << 8) | 4;
 		sdu.data = frame.data;
 		sdu.size = frame.size;
-		log_msg(LVL_DEBUG, " - call iplink_ev_recv");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, " - call iplink_ev_recv");
 		rc = iplink_ev_recv(&nic->iplink, &sdu);
 		break;
 	default:
-		log_msg(LVL_DEBUG, "Unknown ethertype 0x%" PRIx16,
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Unknown ethertype 0x%" PRIx16,
 		    frame.etype_len);
 	}
@@ -239,5 +239,5 @@
 static int ethip_get_mtu(iplink_srv_t *srv, size_t *mtu)
 {
-	log_msg(LVL_DEBUG, "ethip_get_mtu()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_get_mtu()");
 	*mtu = 1500;
 	return EOK;
@@ -248,5 +248,5 @@
 	ethip_nic_t *nic = (ethip_nic_t *)srv->arg;
 
-	log_msg(LVL_DEBUG, "ethip_addr_add(0x%" PRIx32 ")", addr->ipv4);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_addr_add(0x%" PRIx32 ")", addr->ipv4);
 	return ethip_nic_addr_add(nic, addr);
 }
@@ -256,5 +256,5 @@
 	ethip_nic_t *nic = (ethip_nic_t *)srv->arg;
 
-	log_msg(LVL_DEBUG, "ethip_addr_remove(0x%" PRIx32 ")", addr->ipv4);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_addr_remove(0x%" PRIx32 ")", addr->ipv4);
 	return ethip_nic_addr_add(nic, addr);
 }
@@ -266,5 +266,5 @@
 	printf(NAME ": HelenOS IP over Ethernet service\n");
 
-	if (log_init(NAME, LVL_WARN) != EOK) {
+	if (log_init(NAME) != EOK) {
 		printf(NAME ": Failed to initialize logging.\n");
 		return 1;
Index: uspace/srv/net/ethip/ethip_nic.c
===================================================================
--- uspace/srv/net/ethip/ethip_nic.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/ethip/ethip_nic.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -68,5 +68,5 @@
 	rc = loc_category_get_id("nic", &iplink_cat, IPC_FLAG_BLOCKING);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed resolving category 'nic'.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'nic'.");
 		fibril_mutex_unlock(&ethip_discovery_lock);
 		return ENOENT;
@@ -75,5 +75,5 @@
 	rc = loc_category_get_svcs(iplink_cat, &svcs, &count);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed getting list of IP links.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of IP links.");
 		fibril_mutex_unlock(&ethip_discovery_lock);
 		return EIO;
@@ -93,9 +93,9 @@
 
 		if (!already_known) {
-			log_msg(LVL_DEBUG, "Found NIC '%lu'",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Found NIC '%lu'",
 			    (unsigned long) svcs[i]);
 			rc = ethip_nic_open(svcs[i]);
 			if (rc != EOK)
-				log_msg(LVL_ERROR, "Could not open NIC.");
+				log_msg(LOG_DEFAULT, LVL_ERROR, "Could not open NIC.");
 		}
 	}
@@ -110,5 +110,5 @@
 
 	if (nic == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating NIC structure. "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating NIC structure. "
 		    "Out of memory.");
 		return NULL;
@@ -126,5 +126,5 @@
 
 	if (laddr == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating NIC address structure. "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating NIC address structure. "
 		    "Out of memory.");
 		return NULL;
@@ -153,5 +153,5 @@
 	nic_address_t nic_address;
 	
-	log_msg(LVL_DEBUG, "ethip_nic_open()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_open()");
 	ethip_nic_t *nic = ethip_nic_new();
 	if (nic == NULL)
@@ -160,5 +160,5 @@
 	int rc = loc_service_get_name(sid, &nic->svc_name);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed getting service name.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting service name.");
 		goto error;
 	}
@@ -166,5 +166,5 @@
 	nic->sess = loc_service_connect(EXCHANGE_SERIALIZE, sid, 0);
 	if (nic->sess == NULL) {
-		log_msg(LVL_ERROR, "Failed connecting '%s'", nic->svc_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed connecting '%s'", nic->svc_name);
 		goto error;
 	}
@@ -174,10 +174,10 @@
 	rc = nic_callback_create(nic->sess, ethip_nic_cb_conn, nic);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed creating callback connection "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed creating callback connection "
 		    "from '%s'", nic->svc_name);
 		goto error;
 	}
 
-	log_msg(LVL_DEBUG, "Opened NIC '%s'", nic->svc_name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Opened NIC '%s'", nic->svc_name);
 	list_append(&nic->nic_list, &ethip_nic_list);
 	in_list = true;
@@ -189,5 +189,5 @@
 	rc = nic_get_address(nic->sess, &nic_address);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Error getting MAC address of NIC '%s'.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting MAC address of NIC '%s'.",
 		    nic->svc_name);
 		goto error;
@@ -198,10 +198,10 @@
 	rc = nic_set_state(nic->sess, NIC_STATE_ACTIVE);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Error activating NIC '%s'.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error activating NIC '%s'.",
 		    nic->svc_name);
 		goto error;
 	}
 
-	log_msg(LVL_DEBUG, "Initialized IP link service, MAC = 0x%" PRIx64,
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Initialized IP link service, MAC = 0x%" PRIx64,
 	    nic->mac_addr.addr);
 
@@ -225,5 +225,5 @@
     ipc_call_t *call)
 {
-	log_msg(LVL_DEBUG, "ethip_nic_addr_changed()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_addr_changed()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -236,21 +236,21 @@
 	size_t size;
 
-	log_msg(LVL_DEBUG, "ethip_nic_received() nic=%p", nic);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_received() nic=%p", nic);
 
 	rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
 	if (rc != EOK) {
-		log_msg(LVL_DEBUG, "data_write_accept() failed");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "data_write_accept() failed");
 		return;
 	}
 
-	log_msg(LVL_DEBUG, "Ethernet PDU contents (%zu bytes)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Ethernet PDU contents (%zu bytes)",
 	    size);
 
-	log_msg(LVL_DEBUG, "call ethip_received");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "call ethip_received");
 	rc = ethip_received(&nic->iplink, data, size);
-	log_msg(LVL_DEBUG, "free data");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "free data");
 	free(data);
 
-	log_msg(LVL_DEBUG, "ethip_nic_received() done, rc=%d", rc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_received() done, rc=%d", rc);
 	async_answer_0(callid, rc);
 }
@@ -259,5 +259,5 @@
     ipc_call_t *call)
 {
-	log_msg(LVL_DEBUG, "ethip_nic_device_state()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_device_state()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -267,5 +267,5 @@
 	ethip_nic_t *nic = (ethip_nic_t *)arg;
 
-	log_msg(LVL_DEBUG, "ethnip_nic_cb_conn()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethnip_nic_cb_conn()");
 
 	while (true) {
@@ -298,5 +298,5 @@
 	int rc = loc_register_cat_change_cb(ethip_nic_cat_change_cb);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering callback for NIC "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback for NIC "
 		    "discovery (%d).", rc);
 		return rc;
@@ -308,19 +308,19 @@
 ethip_nic_t *ethip_nic_find_by_iplink_sid(service_id_t iplink_sid)
 {
-	log_msg(LVL_DEBUG, "ethip_nic_find_by_iplink_sid(%u)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_find_by_iplink_sid(%u)",
 	    (unsigned) iplink_sid);
 
 	list_foreach(ethip_nic_list, link) {
-		log_msg(LVL_DEBUG, "ethip_nic_find_by_iplink_sid - element");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_find_by_iplink_sid - element");
 		ethip_nic_t *nic = list_get_instance(link, ethip_nic_t,
 		    nic_list);
 
 		if (nic->iplink_sid == iplink_sid) {
-			log_msg(LVL_DEBUG, "ethip_nic_find_by_iplink_sid - found %p", nic);
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_find_by_iplink_sid - found %p", nic);
 			return nic;
 		}
 	}
 
-	log_msg(LVL_DEBUG, "ethip_nic_find_by_iplink_sid - not found");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_find_by_iplink_sid - not found");
 	return NULL;
 }
@@ -329,7 +329,7 @@
 {
 	int rc;
-	log_msg(LVL_DEBUG, "ethip_nic_send(size=%zu)", size);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_send(size=%zu)", size);
 	rc = nic_send_frame(nic->sess, data, size);
-	log_msg(LVL_DEBUG, "nic_send_frame -> %d", rc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "nic_send_frame -> %d", rc);
 	return rc;
 }
@@ -339,5 +339,5 @@
 	ethip_link_addr_t *laddr;
 
-	log_msg(LVL_DEBUG, "ethip_nic_addr_add()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_addr_add()");
 	laddr = ethip_nic_addr_new(addr);
 	if (laddr == NULL)
@@ -352,5 +352,5 @@
 	ethip_link_addr_t *laddr;
 
-	log_msg(LVL_DEBUG, "ethip_nic_addr_remove()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_addr_remove()");
 
 	laddr = ethip_nic_addr_find(nic, addr);
@@ -366,5 +366,5 @@
     iplink_srv_addr_t *addr)
 {
-	log_msg(LVL_DEBUG, "ethip_nic_addr_find()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_addr_find()");
 
 	list_foreach(nic->addr_list, link) {
Index: uspace/srv/net/ethip/pdu.c
===================================================================
--- uspace/srv/net/ethip/pdu.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/ethip/pdu.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -69,7 +69,8 @@
 	    frame->size);
 
-	log_msg(LVL_DEBUG, "Encoding Ethernet frame src=%llx dest=%llx etype=%x",
-	    frame->src, frame->dest, frame->etype_len);
-	log_msg(LVL_DEBUG, "Encoded Ethernet frame (%zu bytes)", size);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Encoding Ethernet frame "
+	    "src=%" PRIx64 " dest=%" PRIx64 " etype=%x",
+	    frame->src.addr, frame->dest.addr, frame->etype_len);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Encoded Ethernet frame (%zu bytes)", size);
 
 	*rdata = data;
@@ -83,8 +84,8 @@
 	eth_header_t *hdr;
 
-	log_msg(LVL_DEBUG, "eth_pdu_decode()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "eth_pdu_decode()");
 
 	if (size < sizeof(eth_header_t)) {
-		log_msg(LVL_DEBUG, "PDU too short (%zu)", size);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size);
 		return EINVAL;
 	}
@@ -104,7 +105,8 @@
 	    frame->size);
 
-	log_msg(LVL_DEBUG, "Decoding Ethernet frame src=%llx dest=%llx etype=%x",
-	    frame->src, frame->dest, frame->etype_len);
-	log_msg(LVL_DEBUG, "Decoded Ethernet frame payload (%zu bytes)", frame->size);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Decoding Ethernet frame "
+	    "src=%" PRIx64 " dest=%" PRIx64 " etype=%x",
+	    frame->src.addr, frame->dest.addr, frame->etype_len);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Decoded Ethernet frame payload (%zu bytes)", frame->size);
 
 	return EOK;
@@ -143,5 +145,5 @@
 	uint16_t fopcode;
 
-	log_msg(LVL_DEBUG, "arp_pdu_encode()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "arp_pdu_encode()");
 
 	size = sizeof(arp_eth_packet_fmt_t);
@@ -183,8 +185,8 @@
 	arp_eth_packet_fmt_t *pfmt;
 
-	log_msg(LVL_DEBUG, "arp_pdu_decode()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "arp_pdu_decode()");
 
 	if (size < sizeof(arp_eth_packet_fmt_t)) {
-		log_msg(LVL_DEBUG, "ARP PDU too short (%zu)", size);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "ARP PDU too short (%zu)", size);
 		return EINVAL;
 	}
@@ -193,5 +195,5 @@
 
 	if (uint16_t_be2host(pfmt->hw_addr_space) != AHRD_ETHERNET) {
-		log_msg(LVL_DEBUG, "HW address space != %u (%" PRIu16 ")",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "HW address space != %u (%" PRIu16 ")",
 		    AHRD_ETHERNET, uint16_t_be2host(pfmt->hw_addr_space));
 		return EINVAL;
@@ -199,5 +201,5 @@
 
 	if (uint16_t_be2host(pfmt->proto_addr_space) != 0x0800) {
-		log_msg(LVL_DEBUG, "Proto address space != %u (%" PRIu16 ")",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Proto address space != %u (%" PRIu16 ")",
 		    ETYPE_IP, uint16_t_be2host(pfmt->proto_addr_space));
 		return EINVAL;
@@ -205,5 +207,5 @@
 
 	if (pfmt->hw_addr_size != ETH_ADDR_SIZE) {
-		log_msg(LVL_DEBUG, "HW address size != %zu (%zu)",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "HW address size != %zu (%zu)",
 		    (size_t)ETH_ADDR_SIZE, (size_t)pfmt->hw_addr_size);
 		return EINVAL;
@@ -211,5 +213,5 @@
 
 	if (pfmt->proto_addr_size != IPV4_ADDR_SIZE) {
-		log_msg(LVL_DEBUG, "Proto address size != %zu (%zu)",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Proto address size != %zu (%zu)",
 		    (size_t)IPV4_ADDR_SIZE, (size_t)pfmt->proto_addr_size);
 		return EINVAL;
@@ -220,5 +222,5 @@
 	case AOP_REPLY: packet->opcode = aop_reply; break;
 	default:
-		log_msg(LVL_DEBUG, "Invalid ARP opcode (%" PRIu16 ")",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Invalid ARP opcode (%" PRIu16 ")",
 		    uint16_t_be2host(pfmt->opcode));
 		return EINVAL;
@@ -231,5 +233,5 @@
 	packet->target_proto_addr.ipv4 =
 	    uint32_t_be2host(pfmt->target_proto_addr);
-	log_msg(LVL_DEBUG, "packet->tpa = %x\n", pfmt->target_proto_addr);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "packet->tpa = %x\n", pfmt->target_proto_addr);
 
 	return EOK;
Index: uspace/srv/net/inetsrv/addrobj.c
===================================================================
--- uspace/srv/net/inetsrv/addrobj.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/inetsrv/addrobj.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -59,5 +59,5 @@
 
 	if (addr == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating address object. "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating address object. "
 		    "Out of memory.");
 		return NULL;
@@ -114,5 +114,5 @@
 	uint32_t mask;
 
-	log_msg(LVL_DEBUG, "inet_addrobj_find(%x)", (unsigned)addr->ipv4);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find(%x)", (unsigned)addr->ipv4);
 
 	fibril_mutex_lock(&addr_list_lock);
@@ -125,5 +125,5 @@
 		if ((naddr->naddr.ipv4 & mask) == (addr->ipv4 & mask)) {
 			fibril_mutex_unlock(&addr_list_lock);
-			log_msg(LVL_DEBUG, "inet_addrobj_find: found %p",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find: found %p",
 			    naddr);
 			return naddr;
@@ -131,5 +131,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "inet_addrobj_find: Not found");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find: Not found");
 	fibril_mutex_unlock(&addr_list_lock);
 
@@ -147,5 +147,5 @@
 	assert(fibril_mutex_is_locked(&addr_list_lock));
 
-	log_msg(LVL_DEBUG, "inet_addrobj_find_by_name_locked('%s', '%s')",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find_by_name_locked('%s', '%s')",
 	    name, ilink->svc_name);
 
@@ -155,5 +155,5 @@
 
 		if (naddr->ilink == ilink && str_cmp(naddr->name, name) == 0) {
-			log_msg(LVL_DEBUG, "inet_addrobj_find_by_name_locked: found %p",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find_by_name_locked: found %p",
 			    naddr);
 			return naddr;
@@ -161,5 +161,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "inet_addrobj_find_by_name_locked: Not found");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find_by_name_locked: Not found");
 
 	return NULL;
@@ -177,5 +177,5 @@
 	inet_addrobj_t *aobj;
 
-	log_msg(LVL_DEBUG, "inet_addrobj_find_by_name('%s', '%s')",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find_by_name('%s', '%s')",
 	    name, ilink->svc_name);
 
@@ -194,5 +194,5 @@
 inet_addrobj_t *inet_addrobj_get_by_id(sysarg_t id)
 {
-	log_msg(LVL_DEBUG, "inet_addrobj_get_by_id(%zu)", (size_t)id);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_get_by_id(%zu)", (size_t)id);
 
 	fibril_mutex_lock(&addr_list_lock);
Index: uspace/srv/net/inetsrv/icmp.c
===================================================================
--- uspace/srv/net/inetsrv/icmp.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/inetsrv/icmp.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -57,5 +57,5 @@
 	uint8_t type;
 
-	log_msg(LVL_DEBUG, "icmp_recv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "icmp_recv()");
 
 	if (dgram->size < 1)
@@ -84,5 +84,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "icmp_recv_echo_request()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "icmp_recv_echo_request()");
 
 	if (dgram->size < sizeof(icmp_echo_t))
@@ -124,5 +124,5 @@
 	uint16_t ident;
 
-	log_msg(LVL_DEBUG, "icmp_recv_echo_reply()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "icmp_recv_echo_reply()");
 
 	if (dgram->size < sizeof(icmp_echo_t))
Index: uspace/srv/net/inetsrv/inet_link.c
===================================================================
--- uspace/srv/net/inetsrv/inet_link.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/inetsrv/inet_link.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -64,14 +64,14 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inet_iplink_recv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv()");
 	rc = inet_pdu_decode(sdu->data, sdu->size, &packet);
 	if (rc != EOK) {
-		log_msg(LVL_DEBUG, "failed decoding PDU");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "failed decoding PDU");
 		return rc;
 	}
 
-	log_msg(LVL_DEBUG, "call inet_recv_packet()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet()");
 	rc = inet_recv_packet(&packet);
-	log_msg(LVL_DEBUG, "call inet_recv_packet -> %d", rc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet -> %d", rc);
 	free(packet.data);
 
@@ -91,5 +91,5 @@
 	rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed resolving category 'iplink'.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'iplink'.");
 		fibril_mutex_unlock(&inet_discovery_lock);
 		return ENOENT;
@@ -98,5 +98,5 @@
 	rc = loc_category_get_svcs(iplink_cat, &svcs, &count);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed getting list of IP links.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of IP links.");
 		fibril_mutex_unlock(&inet_discovery_lock);
 		return EIO;
@@ -116,9 +116,9 @@
 
 		if (!already_known) {
-			log_msg(LVL_DEBUG, "Found IP link '%lu'",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Found IP link '%lu'",
 			    (unsigned long) svcs[i]);
 			rc = inet_link_open(svcs[i]);
 			if (rc != EOK)
-				log_msg(LVL_ERROR, "Could not open IP link.");
+				log_msg(LOG_DEFAULT, LVL_ERROR, "Could not open IP link.");
 		}
 	}
@@ -133,5 +133,5 @@
 
 	if (ilink == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating link structure. "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating link structure. "
 		    "Out of memory.");
 		return NULL;
@@ -156,5 +156,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inet_link_open()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_link_open()");
 	ilink = inet_link_new();
 	if (ilink == NULL)
@@ -166,5 +166,5 @@
 	rc = loc_service_get_name(sid, &ilink->svc_name);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed getting service name.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting service name.");
 		goto error;
 	}
@@ -172,5 +172,5 @@
 	ilink->sess = loc_service_connect(EXCHANGE_SERIALIZE, sid, 0);
 	if (ilink->sess == NULL) {
-		log_msg(LVL_ERROR, "Failed connecting '%s'", ilink->svc_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed connecting '%s'", ilink->svc_name);
 		goto error;
 	}
@@ -178,5 +178,5 @@
 	rc = iplink_open(ilink->sess, &inet_iplink_ev_ops, &ilink->iplink);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed opening IP link '%s'",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed opening IP link '%s'",
 		    ilink->svc_name);
 		goto error;
@@ -185,10 +185,10 @@
 	rc = iplink_get_mtu(ilink->iplink, &ilink->def_mtu);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed determinning MTU of link '%s'",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed determinning MTU of link '%s'",
 		    ilink->svc_name);
 		goto error;
 	}
 
-	log_msg(LVL_DEBUG, "Opened IP link '%s'", ilink->svc_name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Opened IP link '%s'", ilink->svc_name);
 	list_append(&ilink->link_list, &inet_link_list);
 
@@ -209,5 +209,5 @@
 	rc = inet_addrobj_add(addr);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed setting IP address on internet link.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed setting IP address on internet link.");
 		inet_addrobj_delete(addr);
 		/* XXX Roll back */
@@ -218,5 +218,5 @@
 	rc = iplink_addr_add(ilink->iplink, &iaddr);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed setting IP address on internet link.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed setting IP address on internet link.");
 		inet_addrobj_remove(addr);
 		inet_addrobj_delete(addr);
@@ -245,5 +245,5 @@
 	rc = loc_register_cat_change_cb(inet_link_cat_change_cb);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering callback for IP link "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback for IP link "
 		    "discovery (%d).", rc);
 		return rc;
Index: uspace/srv/net/inetsrv/inetcfg.c
===================================================================
--- uspace/srv/net/inetsrv/inetcfg.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/inetsrv/inetcfg.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -61,5 +61,5 @@
 	ilink = inet_link_get_by_id(link_id);
 	if (ilink == NULL) {
-		log_msg(LVL_DEBUG, "Link %lu not found.",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Link %lu not found.",
 		    (unsigned long) link_id);
 		return ENOENT;
@@ -77,5 +77,5 @@
 	rc = inet_addrobj_add(addr);
 	if (rc != EOK) {
-		log_msg(LVL_DEBUG, "Duplicate address name '%s'.", addr->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Duplicate address name '%s'.", addr->name);
 		inet_addrobj_delete(addr);
 		return rc;
@@ -85,5 +85,5 @@
 	rc = iplink_addr_add(ilink->iplink, &iaddr);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed setting IP address on internet link.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed setting IP address on internet link.");
 		inet_addrobj_remove(addr);
 		inet_addrobj_delete(addr);
@@ -130,5 +130,5 @@
 	ilink = inet_link_get_by_id(link_id);
 	if (ilink == NULL) {
-		log_msg(LVL_DEBUG, "Link %zu not found.", (size_t) link_id);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Link %zu not found.", (size_t) link_id);
 		return ENOENT;
 	}
@@ -136,5 +136,5 @@
 	addr = inet_addrobj_find_by_name(name, ilink);
 	if (addr == NULL) {
-		log_msg(LVL_DEBUG, "Address '%s' not found.", name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Address '%s' not found.", name);
 		return ENOENT;
 	}
@@ -228,5 +228,5 @@
 	sroute = inet_sroute_find_by_name(name);
 	if (sroute == NULL) {
-		log_msg(LVL_DEBUG, "Static route '%s' not found.", name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Static route '%s' not found.", name);
 		return ENOENT;
 	}
@@ -245,5 +245,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_addr_create_static_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_addr_create_static_srv()");
 
 	rc = async_data_write_accept((void **) &name, true, 0, LOC_NAME_MAXLEN,
@@ -269,5 +269,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_addr_delete_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_addr_delete_srv()");
 
 	addr_id = IPC_GET_ARG1(*call);
@@ -287,5 +287,5 @@
 
 	addr_id = IPC_GET_ARG1(*call);
-	log_msg(LVL_DEBUG, "inetcfg_addr_get_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_addr_get_srv()");
 
 	ainfo.naddr.ipv4 = 0;
@@ -321,5 +321,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_addr_get_id_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_addr_get_id_srv()");
 
 	link_id = IPC_GET_ARG1(*call);
@@ -348,5 +348,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_get_addr_list_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_get_addr_list_srv()");
 
 	if (!async_data_read_receive(&rcallid, &max_size)) {
@@ -382,5 +382,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_get_link_list_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_get_link_list_srv()");
 
 	if (!async_data_read_receive(&rcallid, &max_size)) {
@@ -415,5 +415,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_get_sroute_list_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_get_sroute_list_srv()");
 
 	if (!async_data_read_receive(&rcallid, &max_size)) {
@@ -449,5 +449,5 @@
 
 	link_id = IPC_GET_ARG1(*call);
-	log_msg(LVL_DEBUG, "inetcfg_link_get_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_link_get_srv()");
 
 	linfo.name = NULL;
@@ -482,5 +482,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_sroute_create_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_sroute_create_srv()");
 
 	rc = async_data_write_accept((void **) &name, true, 0, LOC_NAME_MAXLEN,
@@ -506,5 +506,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_sroute_delete_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_sroute_delete_srv()");
 
 	sroute_id = IPC_GET_ARG1(*call);
@@ -524,5 +524,5 @@
 
 	sroute_id = IPC_GET_ARG1(*call);
-	log_msg(LVL_DEBUG, "inetcfg_sroute_get_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_sroute_get_srv()");
 
 	srinfo.dest.ipv4 = 0;
@@ -557,5 +557,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_sroute_get_id_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_sroute_get_id_srv()");
 
 	rc = async_data_write_accept((void **) &name, true, 0, LOC_NAME_MAXLEN,
@@ -574,5 +574,5 @@
 void inet_cfg_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
-	log_msg(LVL_DEBUG, "inet_cfg_conn()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_cfg_conn()");
 
 	/* Accept the connection */
Index: uspace/srv/net/inetsrv/inetping.c
===================================================================
--- uspace/srv/net/inetsrv/inetping.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/inetsrv/inetping.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -76,5 +76,5 @@
 	client = inetping_client_find(ident);
 	if (client == NULL) {
-		log_msg(LVL_DEBUG, "Unknown ICMP ident. Dropping.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Unknown ICMP ident. Dropping.");
 		return ENOENT;
 	}
@@ -107,5 +107,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetping_send_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_send_srv()");
 
 	rc = async_data_write_accept((void **) &sdu.data, false, 0, 0, 0,
@@ -133,5 +133,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetping_get_srcaddr_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_get_srcaddr_srv()");
 
 	remote.ipv4 = IPC_GET_ARG1(*call);
@@ -192,5 +192,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetping_conn()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_conn()");
 
 	/* Accept the connection */
Index: uspace/srv/net/inetsrv/inetsrv.c
===================================================================
--- uspace/srv/net/inetsrv/inetsrv.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/inetsrv/inetsrv.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -66,5 +66,5 @@
 static int inet_init(void)
 {
-	log_msg(LVL_DEBUG, "inet_init()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_init()");
 	
 	async_set_client_connection(inet_client_conn);
@@ -72,5 +72,5 @@
 	int rc = loc_server_register(NAME);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering server (%d).", rc);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server (%d).", rc);
 		return EEXIST;
 	}
@@ -80,5 +80,5 @@
 	    INET_PORT_DEFAULT);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
 		return EEXIST;
 	}
@@ -87,5 +87,5 @@
 	    INET_PORT_CFG);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
 		return EEXIST;
 	}
@@ -94,5 +94,5 @@
 	    INET_PORT_PING);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
 		return EEXIST;
 	}
@@ -108,5 +108,5 @@
     ipc_call_t *call)
 {
-	log_msg(LVL_DEBUG, "inet_callback_create_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_callback_create_srv()");
 
 	async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
@@ -143,5 +143,5 @@
 
 	if (dir->aobj == NULL) {
-		log_msg(LVL_DEBUG, "inet_send: No route to destination.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send: No route to destination.");
 		return ENOENT;
 	}
@@ -194,5 +194,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inet_get_srcaddr_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_get_srcaddr_srv()");
 
 	remote.ipv4 = IPC_GET_ARG1(*call);
@@ -212,5 +212,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inet_send_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send_srv()");
 
 	dgram.src.ipv4 = IPC_GET_ARG1(*call);
@@ -238,5 +238,5 @@
 
 	proto = IPC_GET_ARG1(*call);
-	log_msg(LVL_DEBUG, "inet_set_proto_srv(%lu)", (unsigned long) proto);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_set_proto_srv(%lu)", (unsigned long) proto);
 
 	if (proto > UINT8_MAX) {
@@ -272,5 +272,5 @@
 	inet_client_t client;
 
-	log_msg(LVL_DEBUG, "inet_default_conn()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_default_conn()");
 
 	/* Accept the connection */
@@ -378,5 +378,5 @@
 	inet_client_t *client;
 
-	log_msg(LVL_DEBUG, "inet_recv_dgram_local()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_recv_dgram_local()");
 
 	/* ICMP messages are handled internally */
@@ -386,5 +386,5 @@
 	client = inet_client_find(proto);
 	if (client == NULL) {
-		log_msg(LVL_DEBUG, "No client found for protocol 0x%" PRIx8,
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "No client found for protocol 0x%" PRIx8,
 		    proto);
 		return ENOENT;
@@ -428,5 +428,5 @@
 	printf(NAME ": HelenOS Internet Protocol service\n");
 
-	if (log_init(NAME, LVL_WARN) != EOK) {
+	if (log_init(NAME) != EOK) {
 		printf(NAME ": Failed to initialize logging.\n");
 		return 1;
Index: uspace/srv/net/inetsrv/pdu.c
===================================================================
--- uspace/srv/net/inetsrv/pdu.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/inetsrv/pdu.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -204,8 +204,8 @@
 	uint16_t foff;
 
-	log_msg(LVL_DEBUG, "inet_pdu_decode()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode()");
 
 	if (size < sizeof(ip_header_t)) {
-		log_msg(LVL_DEBUG, "PDU too short (%zu)", size);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size);
 		return EINVAL;
 	}
@@ -216,5 +216,5 @@
 	    hdr->ver_ihl);
 	if (version != 4) {
-		log_msg(LVL_DEBUG, "Version (%d) != 4", version);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 4", version);
 		return EINVAL;
 	}
@@ -222,10 +222,10 @@
 	tot_len = uint16_t_be2host(hdr->tot_len);
 	if (tot_len < sizeof(ip_header_t)) {
-		log_msg(LVL_DEBUG, "Total Length too small (%zu)", tot_len);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length too small (%zu)", tot_len);
 		return EINVAL;
 	}
 
 	if (tot_len > size) {
-		log_msg(LVL_DEBUG, "Total Length = %zu > PDU size = %zu",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu",
 			tot_len, size);
 		return EINVAL;
@@ -256,5 +256,5 @@
 	packet->data = calloc(packet->size, 1);
 	if (packet->data == NULL) {
-		log_msg(LVL_WARN, "Out of memory.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Out of memory.");
 		return ENOMEM;
 	}
Index: uspace/srv/net/inetsrv/reass.c
===================================================================
--- uspace/srv/net/inetsrv/reass.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/inetsrv/reass.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -86,5 +86,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inet_reass_queue_packet()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_reass_queue_packet()");
 
 	fibril_mutex_lock(&reass_dgram_map_lock);
@@ -95,5 +95,5 @@
 		/* Only happens when we are out of memory */
 		fibril_mutex_unlock(&reass_dgram_map_lock);
-		log_msg(LVL_DEBUG, "Allocation failed, packet dropped.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Allocation failed, packet dropped.");
 		return ENOMEM;
 	}
Index: uspace/srv/net/inetsrv/sroute.c
===================================================================
--- uspace/srv/net/inetsrv/sroute.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/inetsrv/sroute.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -57,5 +57,5 @@
 
 	if (sroute == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating static route object. "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating static route object. "
 		    "Out of memory.");
 		return NULL;
@@ -100,5 +100,5 @@
 	inet_sroute_t *best;
 
-	log_msg(LVL_DEBUG, "inet_sroute_find(%x)", (unsigned)addr->ipv4);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_find(%x)", (unsigned)addr->ipv4);
 
 	fibril_mutex_lock(&sroute_list_lock);
@@ -117,5 +117,5 @@
 		if ((sroute->dest.ipv4 & mask) == (addr->ipv4 & mask)) {
 			fibril_mutex_unlock(&sroute_list_lock);
-			log_msg(LVL_DEBUG, "inet_sroute_find: found %p",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_find: found %p",
 			    sroute);
 			return sroute;
@@ -123,5 +123,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "inet_sroute_find: Not found");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_find: Not found");
 	fibril_mutex_unlock(&sroute_list_lock);
 
@@ -136,5 +136,5 @@
 inet_sroute_t *inet_sroute_find_by_name(const char *name)
 {
-	log_msg(LVL_DEBUG, "inet_sroute_find_by_name('%s')",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_find_by_name('%s')",
 	    name);
 
@@ -147,5 +147,5 @@
 		if (str_cmp(sroute->name, name) == 0) {
 			fibril_mutex_unlock(&sroute_list_lock);
-			log_msg(LVL_DEBUG, "inet_sroute_find_by_name: found %p",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_find_by_name: found %p",
 			    sroute);
 			return sroute;
@@ -153,5 +153,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "inet_sroute_find_by_name: Not found");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_find_by_name: Not found");
 	fibril_mutex_unlock(&sroute_list_lock);
 
@@ -166,5 +166,5 @@
 inet_sroute_t *inet_sroute_get_by_id(sysarg_t id)
 {
-	log_msg(LVL_DEBUG, "inet_sroute_get_by_id(%zu)", (size_t)id);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_get_by_id(%zu)", (size_t)id);
 
 	fibril_mutex_lock(&sroute_list_lock);
Index: uspace/srv/net/loopip/loopip.c
===================================================================
--- uspace/srv/net/loopip/loopip.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/loopip/loopip.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -75,5 +75,5 @@
 {
 	while (true) {
-		log_msg(LVL_DEBUG, "loopip_recv_fibril(): Wait for one item");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_recv_fibril(): Wait for one item");
 		link_t *link = prodcons_consume(&loopip_rcv_queue);
 		rqueue_entry_t *rqe = list_get_instance(link, rqueue_entry_t, link);
@@ -96,5 +96,5 @@
 	rc = loc_server_register(NAME);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering server.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server.");
 		return rc;
 	}
@@ -108,5 +108,5 @@
 	rc = loc_service_register(svc_name, &sid);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering service %s.", svc_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service %s.", svc_name);
 		return rc;
 	}
@@ -114,5 +114,5 @@
 	rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed resolving category 'iplink'.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'iplink'.");
 		return rc;
 	}
@@ -120,5 +120,5 @@
 	rc = loc_service_add_to_cat(sid, iplink_cat);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed adding %s to category.", svc_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding %s to category.", svc_name);
 		return rc;
 	}
@@ -135,5 +135,5 @@
 static void loopip_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
-	log_msg(LVL_DEBUG, "loopip_client_conn()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_client_conn()");
 	iplink_conn(iid, icall, &loopip_iplink);
 }
@@ -141,5 +141,5 @@
 static int loopip_open(iplink_srv_t *srv)
 {
-	log_msg(LVL_DEBUG, "loopip_open()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_open()");
 	return EOK;
 }
@@ -147,5 +147,5 @@
 static int loopip_close(iplink_srv_t *srv)
 {
-	log_msg(LVL_DEBUG, "loopip_close()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_close()");
 	return EOK;
 }
@@ -155,5 +155,5 @@
 	rqueue_entry_t *rqe;
 
-	log_msg(LVL_DEBUG, "loopip_send()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_send()");
 
 	rqe = calloc(1, sizeof(rqueue_entry_t));
@@ -184,5 +184,5 @@
 static int loopip_get_mtu(iplink_srv_t *srv, size_t *mtu)
 {
-	log_msg(LVL_DEBUG, "loopip_get_mtu()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_get_mtu()");
 	*mtu = 1500;
 	return EOK;
@@ -191,5 +191,5 @@
 static int loopip_addr_add(iplink_srv_t *srv, iplink_srv_addr_t *addr)
 {
-	log_msg(LVL_DEBUG, "loopip_addr_add(0x%" PRIx32 ")", addr->ipv4);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_addr_add(0x%" PRIx32 ")", addr->ipv4);
 	return EOK;
 }
@@ -197,5 +197,5 @@
 static int loopip_addr_remove(iplink_srv_t *srv, iplink_srv_addr_t *addr)
 {
-	log_msg(LVL_DEBUG, "loopip_addr_remove(0x%" PRIx32 ")", addr->ipv4);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_addr_remove(0x%" PRIx32 ")", addr->ipv4);
 	return EOK;
 }
@@ -207,5 +207,5 @@
 	printf(NAME ": HelenOS loopback IP link provider\n");
 
-	if (log_init(NAME, LVL_WARN) != EOK) {
+	if (log_init(NAME) != EOK) {
 		printf(NAME ": Failed to initialize logging.\n");
 		return 1;
Index: uspace/srv/net/tcp/conn.c
===================================================================
--- uspace/srv/net/tcp/conn.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/tcp/conn.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -164,5 +164,5 @@
 static void tcp_conn_free(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_free(%p)", conn->name, conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_free(%p)", conn->name, conn);
 	tcp_tqueue_fini(&conn->retransmit);
 
@@ -184,5 +184,5 @@
 void tcp_conn_addref(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG2, "%s: tcp_conn_addref(%p)", conn->name, conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "%s: tcp_conn_addref(%p)", conn->name, conn);
 	atomic_inc(&conn->refcnt);
 }
@@ -196,5 +196,5 @@
 void tcp_conn_delref(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG2, "%s: tcp_conn_delref(%p)", conn->name, conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "%s: tcp_conn_delref(%p)", conn->name, conn);
 
 	if (atomic_predec(&conn->refcnt) == 0)
@@ -211,5 +211,5 @@
 void tcp_conn_delete(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_delete(%p)", conn->name, conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_delete(%p)", conn->name, conn);
 
 	assert(conn->deleted == false);
@@ -245,5 +245,5 @@
 	tcp_cstate_t old_state;
 
-	log_msg(LVL_DEBUG, "tcp_conn_state_set(%p)", conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set(%p)", conn);
 
 	old_state = conn->cstate;
@@ -253,8 +253,8 @@
 	/* Run user callback function */
 	if (conn->cstate_cb != NULL) {
-		log_msg(LVL_DEBUG, "tcp_conn_state_set() - run user CB");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set() - run user CB");
 		conn->cstate_cb(conn, conn->cstate_cb_arg);
 	} else {
-		log_msg(LVL_DEBUG, "tcp_conn_state_set() - no user CB");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set() - no user CB");
 	}
 
@@ -293,13 +293,13 @@
 	case st_syn_received:
 	case st_established:
-		log_msg(LVL_DEBUG, "%s: FIN sent -> Fin-Wait-1", conn->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN sent -> Fin-Wait-1", conn->name);
 		tcp_conn_state_set(conn, st_fin_wait_1);
 		break;
 	case st_close_wait:
-		log_msg(LVL_DEBUG, "%s: FIN sent -> Last-Ack", conn->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN sent -> Last-Ack", conn->name);
 		tcp_conn_state_set(conn, st_last_ack);
 		break;
 	default:
-		log_msg(LVL_ERROR, "%s: Connection state %d", conn->name,
+		log_msg(LOG_DEFAULT, LVL_ERROR, "%s: Connection state %d", conn->name,
 		    conn->cstate);
 		assert(false);
@@ -312,5 +312,5 @@
 static bool tcp_socket_match(tcp_sock_t *sock, tcp_sock_t *patt)
 {
-	log_msg(LVL_DEBUG2, "tcp_socket_match(sock=(%x,%u), pat=(%x,%u))",
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_socket_match(sock=(%x,%u), pat=(%x,%u))",
 	    sock->addr.ipv4, sock->port, patt->addr.ipv4, patt->port);
 
@@ -323,5 +323,5 @@
 		return false;
 
-	log_msg(LVL_DEBUG2, " -> match");
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " -> match");
 
 	return true;
@@ -331,5 +331,5 @@
 static bool tcp_sockpair_match(tcp_sockpair_t *sp, tcp_sockpair_t *pattern)
 {
-	log_msg(LVL_DEBUG2, "tcp_sockpair_match(%p, %p)", sp, pattern);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_sockpair_match(%p, %p)", sp, pattern);
 
 	if (!tcp_socket_match(&sp->local, &pattern->local))
@@ -353,5 +353,5 @@
 tcp_conn_t *tcp_conn_find_ref(tcp_sockpair_t *sp)
 {
-	log_msg(LVL_DEBUG, "tcp_conn_find_ref(%p)", sp);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_find_ref(%p)", sp);
 
 	fibril_mutex_lock(&conn_list_lock);
@@ -360,5 +360,5 @@
 		tcp_conn_t *conn = list_get_instance(link, tcp_conn_t, link);
 		tcp_sockpair_t *csp = &conn->ident;
-		log_msg(LVL_DEBUG2, "compare with conn (f:(%x,%u), l:(%x,%u))",
+		log_msg(LOG_DEFAULT, LVL_DEBUG2, "compare with conn (f:(%x,%u), l:(%x,%u))",
 		    csp->foreign.addr.ipv4, csp->foreign.port,
 		    csp->local.addr.ipv4, csp->local.port);
@@ -380,5 +380,5 @@
 static void tcp_conn_reset(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_reset()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_reset()", conn->name);
 	tcp_conn_state_set(conn, st_closed);
 	conn->reset = true;
@@ -398,5 +398,5 @@
 {
 	/* TODO */
-	log_msg(LVL_DEBUG, "%s: tcp_reset_signal()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_reset_signal()", conn->name);
 }
 
@@ -422,5 +422,5 @@
 		return true;
 	case st_closed:
-		log_msg(LVL_WARN, "state=%d", (int) conn->cstate);
+		log_msg(LOG_DEFAULT, LVL_WARN, "state=%d", (int) conn->cstate);
 		assert(false);
 	}
@@ -436,13 +436,13 @@
 static void tcp_conn_sa_listen(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "tcp_conn_sa_listen(%p, %p)", conn, seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_sa_listen(%p, %p)", conn, seg);
 
 	if ((seg->ctrl & CTL_RST) != 0) {
-		log_msg(LVL_DEBUG, "Ignoring incoming RST.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Ignoring incoming RST.");
 		return;
 	}
 
 	if ((seg->ctrl & CTL_ACK) != 0) {
-		log_msg(LVL_DEBUG, "Incoming ACK, send acceptable RST.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Incoming ACK, send acceptable RST.");
 		tcp_reply_rst(&conn->ident, seg);
 		return;
@@ -450,9 +450,9 @@
 
 	if ((seg->ctrl & CTL_SYN) == 0) {
-		log_msg(LVL_DEBUG, "SYN not present. Ignoring segment.");
-		return;
-	}
-
-	log_msg(LVL_DEBUG, "Got SYN, sending SYN, ACK.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "SYN not present. Ignoring segment.");
+		return;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Got SYN, sending SYN, ACK.");
 
 	conn->rcv_nxt = seg->seq + 1;
@@ -460,8 +460,8 @@
 
 
-	log_msg(LVL_DEBUG, "rcv_nxt=%u", conn->rcv_nxt);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "rcv_nxt=%u", conn->rcv_nxt);
 
 	if (seg->len > 1)
-		log_msg(LVL_WARN, "SYN combined with data, ignoring data.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "SYN combined with data, ignoring data.");
 
 	/* XXX select ISS */
@@ -493,15 +493,15 @@
 static void tcp_conn_sa_syn_sent(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "tcp_conn_sa_syn_sent(%p, %p)", conn, seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_sa_syn_sent(%p, %p)", conn, seg);
 
 	if ((seg->ctrl & CTL_ACK) != 0) {
-		log_msg(LVL_DEBUG, "snd_una=%u, seg.ack=%u, snd_nxt=%u",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "snd_una=%u, seg.ack=%u, snd_nxt=%u",
 		    conn->snd_una, seg->ack, conn->snd_nxt);
 		if (!seq_no_ack_acceptable(conn, seg->ack)) {
 			if ((seg->ctrl & CTL_RST) == 0) {
-				log_msg(LVL_WARN, "ACK not acceptable, send RST");
+				log_msg(LOG_DEFAULT, LVL_WARN, "ACK not acceptable, send RST");
 				tcp_reply_rst(&conn->ident, seg);
 			} else {
-				log_msg(LVL_WARN, "RST,ACK not acceptable, drop");
+				log_msg(LOG_DEFAULT, LVL_WARN, "RST,ACK not acceptable, drop");
 			}
 			return;
@@ -512,5 +512,5 @@
 		/* If we get here, we have either an acceptable ACK or no ACK */
 		if ((seg->ctrl & CTL_ACK) != 0) {
-			log_msg(LVL_DEBUG, "%s: Connection reset. -> Closed",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: Connection reset. -> Closed",
 			    conn->name);
 			/* Reset connection */
@@ -518,5 +518,5 @@
 			return;
 		} else {
-			log_msg(LVL_DEBUG, "%s: RST without ACK, drop",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: RST without ACK, drop",
 			    conn->name);
 			return;
@@ -527,5 +527,5 @@
 
 	if ((seg->ctrl & CTL_SYN) == 0) {
-		log_msg(LVL_DEBUG, "No SYN bit, ignoring segment.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "No SYN bit, ignoring segment.");
 		return;
 	}
@@ -544,5 +544,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "Sent SYN, got SYN.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Sent SYN, got SYN.");
 
 	/*
@@ -551,5 +551,5 @@
 	 * will always be accepted as new window setting.
 	 */
-	log_msg(LVL_DEBUG, "SND.WND := %" PRIu32 ", SND.WL1 := %" PRIu32 ", "
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "SND.WND := %" PRIu32 ", SND.WL1 := %" PRIu32 ", "
 	    "SND.WL2 = %" PRIu32, seg->wnd, seg->seq, seg->seq);
 	conn->snd_wnd = seg->wnd;
@@ -558,9 +558,9 @@
 
 	if (seq_no_syn_acked(conn)) {
-		log_msg(LVL_DEBUG, "%s: syn acked -> Established", conn->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: syn acked -> Established", conn->name);
 		tcp_conn_state_set(conn, st_established);
 		tcp_tqueue_ctrl_seg(conn, CTL_ACK /* XXX */);
 	} else {
-		log_msg(LVL_DEBUG, "%s: syn not acked -> Syn-Received",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: syn not acked -> Syn-Received",
 		    conn->name);
 		tcp_conn_state_set(conn, st_syn_received);
@@ -582,9 +582,9 @@
 	tcp_segment_t *pseg;
 
-	log_msg(LVL_DEBUG, "tcp_conn_sa_seq(%p, %p)", conn, seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_sa_seq(%p, %p)", conn, seg);
 
 	/* Discard unacceptable segments ("old duplicates") */
 	if (!seq_no_segment_acceptable(conn, seg)) {
-		log_msg(LVL_DEBUG, "Replying ACK to unacceptable segment.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Replying ACK to unacceptable segment.");
 		tcp_tqueue_ctrl_seg(conn, CTL_ACK);
 		tcp_segment_delete(seg);
@@ -682,5 +682,5 @@
 	assert(seq_no_in_rcv_wnd(conn, seg->seq));
 
-	log_msg(LVL_WARN, "SYN is in receive window, should send reset. XXX");
+	log_msg(LOG_DEFAULT, LVL_WARN, "SYN is in receive window, should send reset. XXX");
 
 	/*
@@ -705,5 +705,5 @@
 	if (!seq_no_ack_acceptable(conn, seg->ack)) {
 		/* ACK is not acceptable, send RST. */
-		log_msg(LVL_WARN, "Segment ACK not acceptable, sending RST.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Segment ACK not acceptable, sending RST.");
 		tcp_reply_rst(&conn->ident, seg);
 		tcp_segment_delete(seg);
@@ -711,5 +711,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "%s: SYN ACKed -> Established", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: SYN ACKed -> Established", conn->name);
 
 	tcp_conn_state_set(conn, st_established);
@@ -730,14 +730,14 @@
 static cproc_t tcp_conn_seg_proc_ack_est(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "tcp_conn_seg_proc_ack_est(%p, %p)", conn, seg);
-
-	log_msg(LVL_DEBUG, "SEG.ACK=%u, SND.UNA=%u, SND.NXT=%u",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_seg_proc_ack_est(%p, %p)", conn, seg);
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "SEG.ACK=%u, SND.UNA=%u, SND.NXT=%u",
 	    (unsigned)seg->ack, (unsigned)conn->snd_una,
 	    (unsigned)conn->snd_nxt);
 
 	if (!seq_no_ack_acceptable(conn, seg->ack)) {
-		log_msg(LVL_DEBUG, "ACK not acceptable.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "ACK not acceptable.");
 		if (!seq_no_ack_duplicate(conn, seg->ack)) {
-			log_msg(LVL_WARN, "Not acceptable, not duplicate. "
+			log_msg(LOG_DEFAULT, LVL_WARN, "Not acceptable, not duplicate. "
 			    "Send ACK and drop.");
 			/* Not acceptable, not duplicate. Send ACK and drop. */
@@ -746,5 +746,5 @@
 			return cp_done;
 		} else {
-			log_msg(LVL_DEBUG, "Ignoring duplicate ACK.");
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Ignoring duplicate ACK.");
 		}
 	} else {
@@ -758,5 +758,5 @@
 		conn->snd_wl2 = seg->ack;
 
-		log_msg(LVL_DEBUG, "Updating send window, SND.WND=%" PRIu32
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Updating send window, SND.WND=%" PRIu32
 		    ", SND.WL1=%" PRIu32 ", SND.WL2=%" PRIu32,
 		    conn->snd_wnd, conn->snd_wl1, conn->snd_wl2);
@@ -785,5 +785,5 @@
 
 	if (conn->fin_is_acked) {
-		log_msg(LVL_DEBUG, "%s: FIN acked -> Fin-Wait-2", conn->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN acked -> Fin-Wait-2", conn->name);
 		tcp_conn_state_set(conn, st_fin_wait_2);
 	}
@@ -850,5 +850,5 @@
 
 	if (conn->fin_is_acked) {
-		log_msg(LVL_DEBUG, "%s: FIN acked -> Closed", conn->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN acked -> Closed", conn->name);
 		tcp_conn_remove(conn);
 		tcp_conn_state_set(conn, st_closed);
@@ -881,9 +881,9 @@
 static cproc_t tcp_conn_seg_proc_ack(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_seg_proc_ack(%p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_seg_proc_ack(%p, %p)",
 	    conn->name, conn, seg);
 
 	if ((seg->ctrl & CTL_ACK) == 0) {
-		log_msg(LVL_WARN, "Segment has no ACK. Dropping.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Segment has no ACK. Dropping.");
 		tcp_segment_delete(seg);
 		return cp_done;
@@ -940,5 +940,5 @@
 	size_t xfer_size;
 
-	log_msg(LVL_DEBUG, "%s: tcp_conn_seg_proc_text(%p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_seg_proc_text(%p, %p)",
 	    conn->name, conn, seg);
 
@@ -982,5 +982,5 @@
 	fibril_condvar_broadcast(&conn->rcv_buf_cv);
 
-	log_msg(LVL_DEBUG, "Received %zu bytes of data.", xfer_size);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Received %zu bytes of data.", xfer_size);
 
 	/* Advance RCV.NXT */
@@ -998,7 +998,7 @@
 		tcp_conn_trim_seg_to_wnd(conn, seg);
 	} else {
-		log_msg(LVL_DEBUG, "%s: Nothing left in segment, dropping "
-		    "(xfer_size=%zu, SEG.LEN=%zu, seg->ctrl=%u)",
-		    conn->name, xfer_size, seg->len, (unsigned)seg->ctrl);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: Nothing left in segment, dropping "
+		    "(xfer_size=%zu, SEG.LEN=%" PRIu32 ", seg->ctrl=%u)",
+		    conn->name, xfer_size, seg->len, (unsigned int) seg->ctrl);
 		/* Nothing left in segment */
 		tcp_segment_delete(seg);
@@ -1018,12 +1018,12 @@
 static cproc_t tcp_conn_seg_proc_fin(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_seg_proc_fin(%p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_seg_proc_fin(%p, %p)",
 	    conn->name, conn, seg);
-	log_msg(LVL_DEBUG, " seg->len=%zu, seg->ctl=%u", (size_t) seg->len,
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " seg->len=%zu, seg->ctl=%u", (size_t) seg->len,
 	    (unsigned) seg->ctrl);
 
 	/* Only process FIN if no text is left in segment. */
 	if (tcp_segment_text_size(seg) == 0 && (seg->ctrl & CTL_FIN) != 0) {
-		log_msg(LVL_DEBUG, " - FIN found in segment.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, " - FIN found in segment.");
 
 		/* Send ACK */
@@ -1042,15 +1042,15 @@
 		case st_syn_received:
 		case st_established:
-			log_msg(LVL_DEBUG, "%s: FIN received -> Close-Wait",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN received -> Close-Wait",
 			    conn->name);
 			tcp_conn_state_set(conn, st_close_wait);
 			break;
 		case st_fin_wait_1:
-			log_msg(LVL_DEBUG, "%s: FIN received -> Closing",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN received -> Closing",
 			    conn->name);
 			tcp_conn_state_set(conn, st_closing);
 			break;
 		case st_fin_wait_2:
-			log_msg(LVL_DEBUG, "%s: FIN received -> Time-Wait",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN received -> Time-Wait",
 			    conn->name);
 			tcp_conn_state_set(conn, st_time_wait);
@@ -1091,5 +1091,5 @@
 static void tcp_conn_seg_process(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "tcp_conn_seg_process(%p, %p)", conn, seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_seg_process(%p, %p)", conn, seg);
 	tcp_segment_dump(seg);
 
@@ -1097,5 +1097,5 @@
 	/* XXX Permit valid ACKs, URGs and RSTs */
 /*	if (!seq_no_segment_acceptable(conn, seg)) {
-		log_msg(LVL_WARN, "Segment not acceptable, dropping.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Segment not acceptable, dropping.");
 		if ((seg->ctrl & CTL_RST) == 0) {
 			tcp_tqueue_ctrl_seg(conn, CTL_ACK);
@@ -1131,5 +1131,5 @@
 	 */
 	if (seg->len > 0) {
-		log_msg(LVL_DEBUG, "Re-insert segment %p. seg->len=%zu",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Re-insert segment %p. seg->len=%zu",
 		    seg, (size_t) seg->len);
 		tcp_iqueue_insert_seg(&conn->incoming, seg);
@@ -1146,5 +1146,5 @@
 void tcp_conn_segment_arrived(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "%c: tcp_conn_segment_arrived(%p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_segment_arrived(%p)",
 	    conn->name, seg);
 
@@ -1165,5 +1165,5 @@
 		tcp_conn_sa_queue(conn, seg); break;
 	case st_closed:
-		log_msg(LVL_DEBUG, "state=%d", (int) conn->cstate);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "state=%d", (int) conn->cstate);
 		assert(false);
 	}
@@ -1178,10 +1178,10 @@
 	tcp_conn_t *conn = (tcp_conn_t *) arg;
 
-	log_msg(LVL_DEBUG, "tw_timeout_func(%p)", conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tw_timeout_func(%p)", conn);
 
 	fibril_mutex_lock(&conn->lock);
 
 	if (conn->cstate == st_closed) {
-		log_msg(LVL_DEBUG, "Connection already closed.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Connection already closed.");
 		fibril_mutex_unlock(&conn->lock);
 		tcp_conn_delref(conn);
@@ -1189,5 +1189,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "%s: TW Timeout -> Closed", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: TW Timeout -> Closed", conn->name);
 	tcp_conn_remove(conn);
 	tcp_conn_state_set(conn, st_closed);
@@ -1240,5 +1240,5 @@
 void tcp_unexpected_segment(tcp_sockpair_t *sp, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "tcp_unexpected_segment(%p, %p)", sp, seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_unexpected_segment(%p, %p)", sp, seg);
 
 	if ((seg->ctrl & CTL_RST) == 0)
@@ -1268,5 +1268,5 @@
 	tcp_segment_t *rseg;
 
-	log_msg(LVL_DEBUG, "tcp_reply_rst(%p, %p)", sp, seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_reply_rst(%p, %p)", sp, seg);
 
 	rseg = tcp_segment_make_rst(seg);
Index: uspace/srv/net/tcp/iqueue.c
===================================================================
--- uspace/srv/net/tcp/iqueue.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/tcp/iqueue.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -67,9 +67,9 @@
 	tcp_iqueue_entry_t *qe;
 	link_t *link;
-	log_msg(LVL_DEBUG, "tcp_iqueue_insert_seg()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_iqueue_insert_seg()");
 
 	iqe = calloc(1, sizeof(tcp_iqueue_entry_t));
 	if (iqe == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating IQE.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating IQE.");
 		return;
 	}
@@ -108,9 +108,9 @@
 	link_t *link;
 
-	log_msg(LVL_DEBUG, "tcp_get_ready_seg()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_get_ready_seg()");
 
 	link = list_first(&iqueue->list);
 	if (link == NULL) {
-		log_msg(LVL_DEBUG, "iqueue is empty");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "iqueue is empty");
 		return ENOENT;
 	}
@@ -119,5 +119,5 @@
 
 	while (!seq_no_segment_acceptable(iqueue->conn, iqe->seg)) {
-		log_msg(LVL_DEBUG, "Skipping unacceptable segment (RCV.NXT=%"
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Skipping unacceptable segment (RCV.NXT=%"
 		    PRIu32 ", RCV.NXT+RCV.WND=%" PRIu32 ", SEG.SEQ=%" PRIu32
 		    ", SEG.LEN=%" PRIu32 ")", iqueue->conn->rcv_nxt,
@@ -130,5 +130,5 @@
          	link = list_first(&iqueue->list);
 		if (link == NULL) {
-			log_msg(LVL_DEBUG, "iqueue is empty");
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "iqueue is empty");
 			return ENOENT;
 		}
@@ -139,5 +139,5 @@
 	/* Do not return segments that are not ready for processing */
 	if (!seq_no_segment_ready(iqueue->conn, iqe->seg)) {
-		log_msg(LVL_DEBUG, "Next segment not ready: SEG.SEQ=%u, "
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Next segment not ready: SEG.SEQ=%u, "
 		    "RCV.NXT=%u, SEG.LEN=%u", iqe->seg->seq,
 		    iqueue->conn->rcv_nxt, iqe->seg->len);
@@ -145,5 +145,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "Returning ready segment %p", iqe->seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Returning ready segment %p", iqe->seg);
 	list_remove(&iqe->link);
 	*seg = iqe->seg;
Index: uspace/srv/net/tcp/ncsim.c
===================================================================
--- uspace/srv/net/tcp/ncsim.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/tcp/ncsim.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -74,5 +74,5 @@
 	link_t *link;
 
-	log_msg(LVL_DEBUG, "tcp_ncsim_bounce_seg()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ncsim_bounce_seg()");
 	tcp_rqueue_bounce_seg(sp, seg);
 	return;
@@ -80,5 +80,5 @@
 	if (0 /*random() % 4 == 3*/) {
 		/* Drop segment */
-		log_msg(LVL_ERROR, "NCSim dropping segment");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "NCSim dropping segment");
 		tcp_segment_delete(seg);
 		return;
@@ -87,5 +87,5 @@
 	sqe = calloc(1, sizeof(tcp_squeue_entry_t));
 	if (sqe == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating SQE.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating SQE.");
 		return;
 	}
@@ -126,5 +126,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_ncsim_fibril()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ncsim_fibril()");
 
 
@@ -139,5 +139,5 @@
 			sqe = list_get_instance(link, tcp_squeue_entry_t, link);
 
-			log_msg(LVL_DEBUG, "NCSim - Sleep");
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "NCSim - Sleep");
 			rc = fibril_condvar_wait_timeout(&sim_queue_cv,
 			    &sim_queue_lock, sqe->delay);
@@ -147,5 +147,5 @@
 		fibril_mutex_unlock(&sim_queue_lock);
 
-		log_msg(LVL_DEBUG, "NCSim - End Sleep");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "NCSim - End Sleep");
 		tcp_rqueue_bounce_seg(&sqe->sp, sqe->seg);
 		free(sqe);
@@ -161,9 +161,9 @@
 	fid_t fid;
 
-	log_msg(LVL_DEBUG, "tcp_ncsim_fibril_start()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ncsim_fibril_start()");
 
 	fid = fibril_create(tcp_ncsim_fibril, NULL);
 	if (fid == 0) {
-		log_msg(LVL_ERROR, "Failed creating ncsim fibril.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed creating ncsim fibril.");
 		return;
 	}
Index: uspace/srv/net/tcp/rqueue.c
===================================================================
--- uspace/srv/net/tcp/rqueue.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/tcp/rqueue.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -74,5 +74,5 @@
 	tcp_sockpair_t rident;
 
-	log_msg(LVL_DEBUG, "tcp_rqueue_bounce_seg()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_rqueue_bounce_seg()");
 
 #ifdef BOUNCE_TRANSCODE
@@ -81,10 +81,10 @@
 
 	if (tcp_pdu_encode(sp, seg, &pdu) != EOK) {
-		log_msg(LVL_WARN, "Not enough memory. Segment dropped.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. Segment dropped.");
 		return;
 	}
 
 	if (tcp_pdu_decode(pdu, &rident, &dseg) != EOK) {
-		log_msg(LVL_WARN, "Not enough memory. Segment dropped.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. Segment dropped.");
 		return;
 	}
@@ -112,5 +112,5 @@
 {
 	tcp_rqueue_entry_t *rqe;
-	log_msg(LVL_DEBUG, "tcp_rqueue_insert_seg()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_rqueue_insert_seg()");
 
 	tcp_segment_dump(seg);
@@ -118,5 +118,5 @@
 	rqe = calloc(1, sizeof(tcp_rqueue_entry_t));
 	if (rqe == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating RQE.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating RQE.");
 		return;
 	}
@@ -134,5 +134,5 @@
 	tcp_rqueue_entry_t *rqe;
 
-	log_msg(LVL_DEBUG, "tcp_rqueue_fibril()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_rqueue_fibril()");
 
 	while (true) {
@@ -152,9 +152,9 @@
 	fid_t fid;
 
-	log_msg(LVL_DEBUG, "tcp_rqueue_fibril_start()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_rqueue_fibril_start()");
 
 	fid = fibril_create(tcp_rqueue_fibril, NULL);
 	if (fid == 0) {
-		log_msg(LVL_ERROR, "Failed creating rqueue fibril.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed creating rqueue fibril.");
 		return;
 	}
Index: uspace/srv/net/tcp/segment.c
===================================================================
--- uspace/srv/net/tcp/segment.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/tcp/segment.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -248,11 +248,11 @@
 void tcp_segment_dump(tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG2, "Segment dump:");
-	log_msg(LVL_DEBUG2, " - ctrl = %u", (unsigned)seg->ctrl);
-	log_msg(LVL_DEBUG2, " - seq = % " PRIu32, seg->seq);
-	log_msg(LVL_DEBUG2, " - ack = % " PRIu32, seg->ack);
-	log_msg(LVL_DEBUG2, " - len = % " PRIu32, seg->len);
-	log_msg(LVL_DEBUG2, " - wnd = % " PRIu32, seg->wnd);
-	log_msg(LVL_DEBUG2, " - up = % " PRIu32, seg->up);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "Segment dump:");
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - ctrl = %u", (unsigned)seg->ctrl);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - seq = %" PRIu32, seg->seq);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - ack = %" PRIu32, seg->ack);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - len = %" PRIu32, seg->len);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - wnd = %" PRIu32, seg->wnd);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - up = %" PRIu32, seg->up);
 }
 
Index: uspace/srv/net/tcp/sock.c
===================================================================
--- uspace/srv/net/tcp/sock.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/tcp/sock.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -91,5 +91,5 @@
 static void tcp_sock_notify_data(socket_core_t *sock_core)
 {
-	log_msg(LVL_DEBUG, "tcp_sock_notify_data(%d)", sock_core->socket_id);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_notify_data(%d)", sock_core->socket_id);
 	async_exch_t *exch = async_exchange_begin(sock_core->sess);
 	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
@@ -100,5 +100,5 @@
 static void tcp_sock_notify_aconn(socket_core_t *lsock_core)
 {
-	log_msg(LVL_DEBUG, "tcp_sock_notify_aconn(%d)", lsock_core->socket_id);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_notify_aconn(%d)", lsock_core->socket_id);
 	async_exch_t *exch = async_exchange_begin(lsock_core->sess);
 	async_msg_5(exch, NET_SOCKET_ACCEPTED, (sysarg_t)lsock_core->socket_id,
@@ -111,8 +111,8 @@
 	tcp_sockdata_t *sock;
 
-	log_msg(LVL_DEBUG, "tcp_sock_create()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_create()");
 	*rsock = NULL;
 
-	sock = calloc(sizeof(tcp_sockdata_t), 1);
+	sock = calloc(1, sizeof(tcp_sockdata_t));
 	if (sock == NULL)
 		return ENOMEM;
@@ -133,5 +133,5 @@
 static void tcp_sock_uncreate(tcp_sockdata_t *sock)
 {
-	log_msg(LVL_DEBUG, "tcp_sock_uncreate()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_uncreate()");
 	free(sock);
 }
@@ -142,5 +142,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_sock_finish_setup()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_finish_setup()");
 
 	sock->recv_fibril = fibril_create(tcp_sock_recv_fibril, sock);
@@ -171,5 +171,5 @@
 	ipc_call_t answer;
 
-	log_msg(LVL_DEBUG, "tcp_sock_socket()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_socket()");
 
 	rc = tcp_sock_create(client, &sock);
@@ -208,6 +208,6 @@
 	tcp_sockdata_t *socket;
 
-	log_msg(LVL_DEBUG, "tcp_sock_bind()");
-	log_msg(LVL_DEBUG, " - async_data_write_accept");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_bind()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - async_data_write_accept");
 	rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
 	if (rc != EOK) {
@@ -216,5 +216,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - call socket_bind");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_bind");
 	rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
 	    addr, addr_len, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
@@ -225,5 +225,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - call socket_cores_find");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_cores_find");
 	sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
 	if (sock_core != NULL) {
@@ -233,5 +233,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - success");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - success");
 	async_answer_0(callid, EOK);
 }
@@ -250,5 +250,5 @@
 	int i;
 
-	log_msg(LVL_DEBUG, "tcp_sock_listen()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_listen()");
 
 	socket_id = SOCKET_GET_SOCKET_ID(call);
@@ -277,5 +277,5 @@
 
 	socket->backlog = backlog;
-	socket->lconn = calloc(sizeof(tcp_conn_t *), backlog);
+	socket->lconn = calloc(backlog, sizeof(tcp_conn_t *));
 	if (socket->lconn == NULL) {
 		fibril_mutex_unlock(&socket->lock);
@@ -284,5 +284,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - open connections");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - open connections");
 
 	lsocket.addr.ipv4 = TCP_IPV4_ANY;
@@ -293,5 +293,5 @@
 	for (i = 0; i < backlog; i++) {
 
-		lconn = calloc(sizeof(tcp_sock_lconn_t), 1);
+		lconn = calloc(1, sizeof(tcp_sock_lconn_t));
 		if (lconn == NULL) {
 			/* XXX Clean up */
@@ -337,5 +337,5 @@
 	tcp_sock_t fsocket;
 
-	log_msg(LVL_DEBUG, "tcp_sock_connect()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connect()");
 
 	rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
@@ -377,5 +377,5 @@
 			fibril_mutex_unlock(&socket->lock);
 			async_answer_0(callid, rc);
-			log_msg(LVL_DEBUG, "tcp_sock_connect: Failed to "
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connect: Failed to "
 			    "determine local address.");
 			return;
@@ -383,5 +383,5 @@
 
 		socket->laddr.ipv4 = loc_addr.ipv4;
-		log_msg(LVL_DEBUG, "Local IP address is %x", socket->laddr.ipv4);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Local IP address is %x", socket->laddr.ipv4);
 	}
 
@@ -431,5 +431,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_sock_accept()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept()");
 
 	socket_id = SOCKET_GET_SOCKET_ID(call);
@@ -445,5 +445,5 @@
 	fibril_mutex_lock(&socket->lock);
 
-	log_msg(LVL_DEBUG, " - verify socket->conn");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - verify socket->conn");
 	if (socket->conn != NULL) {
 		fibril_mutex_unlock(&socket->lock);
@@ -498,5 +498,5 @@
 
 	asocket->conn = conn;
-	log_msg(LVL_DEBUG, "tcp_sock_accept():create asocket\n");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept():create asocket\n");
 
 	rc = tcp_sock_finish_setup(asocket, &asock_id);
@@ -510,5 +510,5 @@
 	fibril_add_ready(asocket->recv_fibril);
 
-	log_msg(LVL_DEBUG, "tcp_sock_accept(): find acore\n");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept(): find acore\n");
 
 	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
@@ -521,5 +521,5 @@
 	
 	/* Push one fragment notification to client's queue */
-	log_msg(LVL_DEBUG, "tcp_sock_accept(): notify data\n");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept(): notify data\n");
 	fibril_mutex_unlock(&socket->lock);
 }
@@ -539,5 +539,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_sock_send()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_send()");
 	socket_id = SOCKET_GET_SOCKET_ID(call);
 	fragments = SOCKET_GET_DATA_FRAGMENTS(call);
@@ -611,5 +611,5 @@
 static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "tcp_sock_sendto()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_sendto()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -629,5 +629,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
 
 	socket_id = SOCKET_GET_SOCKET_ID(call);
@@ -651,13 +651,13 @@
 	(void)flags;
 
-	log_msg(LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock");
 	fibril_mutex_lock(&socket->recv_buffer_lock);
 	while (socket->recv_buffer_used == 0 && socket->recv_error == TCP_EOK) {
-		log_msg(LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0");
 		fibril_condvar_wait(&socket->recv_buffer_cv,
 		    &socket->recv_buffer_lock);
 	}
 
-	log_msg(LVL_DEBUG, "Got data in sock recv_buffer");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Got data in sock recv_buffer");
 
 	data_len = socket->recv_buffer_used;
@@ -679,5 +679,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "**** recv result -> %d", rc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "**** recv result -> %d", rc);
 	if (rc != EOK) {
 		fibril_mutex_unlock(&socket->recv_buffer_lock);
@@ -694,5 +694,5 @@
 		addr.sin_port = host2uint16_t_be(rsock->port);
 
-		log_msg(LVL_DEBUG, "addr read receive");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read receive");
 		if (!async_data_read_receive(&rcallid, &addr_length)) {
 			fibril_mutex_unlock(&socket->recv_buffer_lock);
@@ -705,5 +705,5 @@
 			addr_length = sizeof(addr);
 
-		log_msg(LVL_DEBUG, "addr read finalize");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read finalize");
 		rc = async_data_read_finalize(rcallid, &addr, addr_length);
 		if (rc != EOK) {
@@ -715,5 +715,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "data read receive");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "data read receive");
 	if (!async_data_read_receive(&rcallid, &length)) {
 		fibril_mutex_unlock(&socket->recv_buffer_lock);
@@ -726,9 +726,9 @@
 		length = data_len;
 
-	log_msg(LVL_DEBUG, "data read finalize");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "data read finalize");
 	rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
 
 	socket->recv_buffer_used -= length;
-	log_msg(LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer",
 	    socket->recv_buffer_used);
 	if (socket->recv_buffer_used > 0) {
@@ -758,5 +758,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_sock_close()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close()");
 	socket_id = SOCKET_GET_SOCKET_ID(call);
 
@@ -798,5 +798,5 @@
 static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "tcp_sock_getsockopt()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_getsockopt()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -804,5 +804,5 @@
 static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "tcp_sock_setsockopt()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_setsockopt()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -815,5 +815,5 @@
 	tcp_sockdata_t *socket = lconn->socket;
 
-	log_msg(LVL_DEBUG, "tcp_sock_cstate_cb()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb()");
 	fibril_mutex_lock(&socket->lock);
 	assert(conn == lconn->conn);
@@ -828,5 +828,5 @@
 	list_append(&lconn->ready_list, &socket->ready);
 
-	log_msg(LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
 
 	/* Push one accept notification to client's queue */
@@ -842,10 +842,10 @@
 	tcp_error_t trc;
 
-	log_msg(LVL_DEBUG, "tcp_sock_recv_fibril()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recv_fibril()");
 
 	fibril_mutex_lock(&sock->recv_buffer_lock);
 
 	while (true) {
-		log_msg(LVL_DEBUG, "call tcp_uc_receive()");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "call tcp_uc_receive()");
 		while (sock->recv_buffer_used != 0 && sock->sock_core != NULL)
 			fibril_condvar_wait(&sock->recv_buffer_cv,
@@ -863,5 +863,5 @@
 		}
 
-		log_msg(LVL_DEBUG, "got data - broadcast recv_buffer_cv");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "got data - broadcast recv_buffer_cv");
 
 		sock->recv_buffer_used = data_len;
@@ -895,5 +895,5 @@
 			break;
 
-		log_msg(LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
 		    (int)IPC_GET_IMETHOD(call));
 
@@ -940,5 +940,5 @@
 
 	/* Clean up */
-	log_msg(LVL_DEBUG, "tcp_sock_connection: Clean up");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: Clean up");
 	async_hangup(client.sess);
 	socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data);
Index: uspace/srv/net/tcp/tcp.c
===================================================================
--- uspace/srv/net/tcp/tcp.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/tcp/tcp.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -69,5 +69,5 @@
 	size_t pdu_raw_size;
 
-	log_msg(LVL_DEBUG, "tcp_inet_ev_recv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_inet_ev_recv()");
 
 	pdu_raw = dgram->data;
@@ -76,5 +76,5 @@
 	/* Split into header and payload. */
 
-	log_msg(LVL_DEBUG, "tcp_inet_ev_recv() - split header/payload");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_inet_ev_recv() - split header/payload");
 
 	tcp_pdu_t *pdu;
@@ -84,5 +84,5 @@
 
 	if (pdu_raw_size < sizeof(tcp_header_t)) {
-		log_msg(LVL_WARN, "pdu_raw_size = %zu < sizeof(tcp_header_t) = %zu",
+		log_msg(LOG_DEFAULT, LVL_WARN, "pdu_raw_size = %zu < sizeof(tcp_header_t) = %zu",
 		    pdu_raw_size, sizeof(tcp_header_t));
 		return EINVAL;
@@ -96,5 +96,5 @@
 
 	if (pdu_raw_size < hdr_size) {
-		log_msg(LVL_WARN, "pdu_raw_size = %zu < hdr_size = %zu",
+		log_msg(LOG_DEFAULT, LVL_WARN, "pdu_raw_size = %zu < hdr_size = %zu",
 		    pdu_raw_size, hdr_size);
 		return EINVAL;
@@ -102,14 +102,14 @@
 
 	if (hdr_size < sizeof(tcp_header_t)) {
-		log_msg(LVL_WARN, "hdr_size = %zu < sizeof(tcp_header_t) = %zu",
+		log_msg(LOG_DEFAULT, LVL_WARN, "hdr_size = %zu < sizeof(tcp_header_t) = %zu",
 		    hdr_size, sizeof(tcp_header_t));		return EINVAL;
 	}
 
-	log_msg(LVL_DEBUG, "pdu_raw_size=%zu, hdr_size=%zu",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "pdu_raw_size=%zu, hdr_size=%zu",
 	    pdu_raw_size, hdr_size);
 	pdu = tcp_pdu_create(pdu_raw, hdr_size, pdu_raw + hdr_size,
 	    pdu_raw_size - hdr_size);
 	if (pdu == NULL) {
-		log_msg(LVL_WARN, "Failed creating PDU. Dropped.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Failed creating PDU. Dropped.");
 		return ENOMEM;
 	}
@@ -117,5 +117,5 @@
 	pdu->src_addr.ipv4 = dgram->src.ipv4;
 	pdu->dest_addr.ipv4 = dgram->dest.ipv4;
-	log_msg(LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
 	    pdu->src_addr.ipv4, pdu->dest_addr.ipv4);
 
@@ -137,5 +137,5 @@
 	pdu_raw = malloc(pdu_raw_size);
 	if (pdu_raw == NULL) {
-		log_msg(LVL_ERROR, "Failed to transmit PDU. Out of memory.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to transmit PDU. Out of memory.");
 		return;
 	}
@@ -153,5 +153,5 @@
 	rc = inet_send(&dgram, INET_TTL_MAX, 0);
 	if (rc != EOK)
-		log_msg(LVL_ERROR, "Failed to transmit PDU.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to transmit PDU.");
 }
 
@@ -162,8 +162,8 @@
 	tcp_sockpair_t rident;
 
-	log_msg(LVL_DEBUG, "tcp_received_pdu()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_received_pdu()");
 
 	if (tcp_pdu_decode(pdu, &rident, &dseg) != EOK) {
-		log_msg(LVL_WARN, "Not enough memory. PDU dropped.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. PDU dropped.");
 		return;
 	}
@@ -177,5 +177,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_init()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_init()");
 
 	tcp_rqueue_init();
@@ -189,5 +189,5 @@
 	rc = inet_init(IP_PROTO_TCP, &tcp_inet_ev_ops);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed connecting to internet service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed connecting to internet service.");
 		return ENOENT;
 	}
@@ -195,5 +195,5 @@
 	rc = tcp_sock_init();
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed initializing socket service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed initializing socket service.");
 		return ENOENT;
 	}
@@ -208,5 +208,5 @@
 	printf(NAME ": TCP (Transmission Control Protocol) network module\n");
 
-	rc = log_init(NAME, LVL_WARN);
+	rc = log_init(NAME);
 	if (rc != EOK) {
 		printf(NAME ": Failed to initialize log.\n");
Index: uspace/srv/net/tcp/tqueue.c
===================================================================
--- uspace/srv/net/tcp/tqueue.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/tcp/tqueue.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -88,5 +88,5 @@
 	tcp_segment_t *seg;
 
-	log_msg(LVL_DEBUG, "tcp_tqueue_ctrl_seg(%p, %u)", conn, ctrl);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_tqueue_ctrl_seg(%p, %u)", conn, ctrl);
 
 	seg = tcp_segment_make_ctrl(ctrl);
@@ -99,5 +99,5 @@
 	tcp_tqueue_entry_t *tqe;
 
-	log_msg(LVL_DEBUG, "%s: tcp_tqueue_seg(%p, %p)", conn->name, conn,
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_tqueue_seg(%p, %p)", conn->name, conn,
 	    seg);
 
@@ -109,5 +109,5 @@
 		rt_seg = tcp_segment_dup(seg);
 		if (rt_seg == NULL) {
-			log_msg(LVL_ERROR, "Memory allocation failed.");
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failed.");
 			/* XXX Handle properly */
 			return;
@@ -116,5 +116,5 @@
 		tqe = calloc(1, sizeof(tcp_tqueue_entry_t));
 		if (tqe == NULL) {
-			log_msg(LVL_ERROR, "Memory allocation failed.");
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failed.");
 			/* XXX Handle properly */
 			return;
@@ -165,5 +165,5 @@
 	tcp_segment_t *seg;
 
-	log_msg(LVL_DEBUG, "%s: tcp_tqueue_new_data()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_tqueue_new_data()", conn->name);
 
 	/* Number of free sequence numbers in send window */
@@ -172,5 +172,5 @@
 
 	xfer_seqlen = min(snd_buf_seqlen, avail_wnd);
-	log_msg(LVL_DEBUG, "%s: snd_buf_seqlen = %zu, SND.WND = %zu, "
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: snd_buf_seqlen = %zu, SND.WND = %" PRIu32 ", "
 	    "xfer_seqlen = %zu", conn->name, snd_buf_seqlen, conn->snd_wnd,
 	    xfer_seqlen);
@@ -185,5 +185,5 @@
 
 	if (send_fin) {
-		log_msg(LVL_DEBUG, "%s: Sending out FIN.", conn->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: Sending out FIN.", conn->name);
 		/* We are sending out FIN */
 		ctrl = CTL_FIN;
@@ -194,5 +194,5 @@
 	seg = tcp_segment_make_data(ctrl, conn->snd_buf, data_size);
 	if (seg == NULL) {
-		log_msg(LVL_ERROR, "Memory allocation failure.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failure.");
 		return;
 	}
@@ -223,5 +223,5 @@
 	link_t *cur, *next;
 
-	log_msg(LVL_DEBUG, "%s: tcp_tqueue_ack_received(%p)", conn->name,
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_tqueue_ack_received(%p)", conn->name,
 	    conn);
 
@@ -239,6 +239,6 @@
 
 			if ((tqe->seg->ctrl & CTL_FIN) != 0) {
-				log_msg(LVL_DEBUG, "Fin has been acked");
-				log_msg(LVL_DEBUG, "SND.UNA=%" PRIu32
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Fin has been acked");
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "SND.UNA=%" PRIu32
 				    " SEG.SEQ=%" PRIu32 " SEG.LEN=%" PRIu32,
 				    conn->snd_una, tqe->seg->seq, tqe->seg->len);
@@ -267,5 +267,5 @@
 void tcp_conn_transmit_segment(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_transmit_segment(%p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_transmit_segment(%p, %p)",
 	    conn->name, conn, seg);
 
@@ -282,9 +282,9 @@
 void tcp_transmit_segment(tcp_sockpair_t *sp, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "tcp_transmit_segment(f:(%x,%u),l:(%x,%u), %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_transmit_segment(f:(%x,%u),l:(%x,%u), %p)",
 	    sp->foreign.addr.ipv4, sp->foreign.port,
 	    sp->local.addr.ipv4, sp->local.port, seg);
 
-	log_msg(LVL_DEBUG, "SEG.SEQ=%" PRIu32 ", SEG.WND=%" PRIu32,
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "SEG.SEQ=%" PRIu32 ", SEG.WND=%" PRIu32,
 	    seg->seq, seg->wnd);
 
@@ -300,5 +300,5 @@
 
 	if (tcp_pdu_encode(sp, seg, &pdu) != EOK) {
-		log_msg(LVL_WARN, "Not enough memory. Segment dropped.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. Segment dropped.");
 		return;
 	}
@@ -315,10 +315,10 @@
 	link_t *link;
 
-	log_msg(LVL_DEBUG, "### %s: retransmit_timeout_func(%p)", conn->name, conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: retransmit_timeout_func(%p)", conn->name, conn);
 
 	fibril_mutex_lock(&conn->lock);
 
 	if (conn->cstate == st_closed) {
-		log_msg(LVL_DEBUG, "Connection already closed.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Connection already closed.");
 		fibril_mutex_unlock(&conn->lock);
 		tcp_conn_delref(conn);
@@ -328,5 +328,5 @@
 	link = list_first(&conn->retransmit.list);
 	if (link == NULL) {
-		log_msg(LVL_DEBUG, "Nothing to retransmit");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Nothing to retransmit");
 		fibril_mutex_unlock(&conn->lock);
 		tcp_conn_delref(conn);
@@ -338,5 +338,5 @@
 	rt_seg = tcp_segment_dup(tqe->seg);
 	if (rt_seg == NULL) {
-		log_msg(LVL_ERROR, "Memory allocation failed.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failed.");
 		fibril_mutex_unlock(&conn->lock);
 		tcp_conn_delref(conn);
@@ -345,5 +345,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "### %s: retransmitting segment", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: retransmitting segment", conn->name);
 	tcp_conn_transmit_segment(tqe->conn, rt_seg);
 
@@ -358,5 +358,5 @@
 static void tcp_tqueue_timer_set(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "### %s: tcp_tqueue_timer_set()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: tcp_tqueue_timer_set()", conn->name);
 
 	/* Clear first to make sure we update refcnt correctly */
@@ -371,5 +371,5 @@
 static void tcp_tqueue_timer_clear(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "### %s: tcp_tqueue_timer_clear()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: tcp_tqueue_timer_clear()", conn->name);
 
 	if (fibril_timer_clear(conn->retransmit.timer) == fts_active)
Index: uspace/srv/net/tcp/ucall.c
===================================================================
--- uspace/srv/net/tcp/ucall.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/tcp/ucall.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -70,5 +70,5 @@
 	tcp_conn_t *nconn;
 
-	log_msg(LVL_DEBUG, "tcp_uc_open(%p, %p, %s, %s, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open(%p, %p, %s, %s, %p)",
 	    lsock, fsock, acpass == ap_active ? "active" : "passive",
 	    oflags == tcp_open_nonblock ? "nonblock" : "none", conn);
@@ -88,5 +88,5 @@
 
 	/* Wait for connection to be established or reset */
-	log_msg(LVL_DEBUG, "tcp_uc_open: Wait for connection.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open: Wait for connection.");
 	fibril_mutex_lock(&nconn->lock);
 	while (nconn->cstate == st_listen ||
@@ -97,5 +97,5 @@
 
 	if (nconn->cstate != st_established) {
-		log_msg(LVL_DEBUG, "tcp_uc_open: Connection was reset.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open: Connection was reset.");
 		assert(nconn->cstate == st_closed);
 		fibril_mutex_unlock(&nconn->lock);
@@ -104,8 +104,8 @@
 
 	fibril_mutex_unlock(&nconn->lock);
-	log_msg(LVL_DEBUG, "tcp_uc_open: Connection was established.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open: Connection was established.");
 
 	*conn = nconn;
-	log_msg(LVL_DEBUG, "tcp_uc_open -> %p", nconn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open -> %p", nconn);
 	return TCP_EOK;
 }
@@ -118,5 +118,5 @@
 	size_t xfer_size;
 
-	log_msg(LVL_DEBUG, "%s: tcp_uc_send()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_uc_send()", conn->name);
 
 	fibril_mutex_lock(&conn->lock);
@@ -141,5 +141,5 @@
 		buf_free = conn->snd_buf_size - conn->snd_buf_used;
 		while (buf_free == 0 && !conn->reset) {
-			log_msg(LVL_DEBUG, "%s: buf_free == 0, waiting.",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: buf_free == 0, waiting.",
 			    conn->name);
 			fibril_condvar_wait(&conn->snd_buf_cv, &conn->lock);
@@ -175,5 +175,5 @@
 	size_t xfer_size;
 
-	log_msg(LVL_DEBUG, "%s: tcp_uc_receive()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_uc_receive()", conn->name);
 
 	fibril_mutex_lock(&conn->lock);
@@ -186,5 +186,5 @@
 	/* Wait for data to become available */
 	while (conn->rcv_buf_used == 0 && !conn->rcv_buf_fin && !conn->reset) {
-		log_msg(LVL_DEBUG, "tcp_uc_receive() - wait for data");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_receive() - wait for data");
 		fibril_condvar_wait(&conn->rcv_buf_cv, &conn->lock);
 	}
@@ -223,5 +223,5 @@
 	tcp_tqueue_ctrl_seg(conn, CTL_ACK);
 
-	log_msg(LVL_DEBUG, "%s: tcp_uc_receive() - returning %zu bytes",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_uc_receive() - returning %zu bytes",
 	    conn->name, xfer_size);
 
@@ -234,5 +234,5 @@
 tcp_error_t tcp_uc_close(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_uc_close()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_uc_close()", conn->name);
 
 	fibril_mutex_lock(&conn->lock);
@@ -258,5 +258,5 @@
 void tcp_uc_abort(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "tcp_uc_abort()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_abort()");
 }
 
@@ -264,5 +264,5 @@
 void tcp_uc_status(tcp_conn_t *conn, tcp_conn_status_t *cstatus)
 {
-	log_msg(LVL_DEBUG, "tcp_uc_status()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_status()");
 	cstatus->cstate = conn->cstate;
 }
@@ -276,5 +276,5 @@
 void tcp_uc_delete(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "tcp_uc_delete()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_delete()");
 	tcp_conn_delete(conn);
 }
@@ -282,5 +282,5 @@
 void tcp_uc_set_cstate_cb(tcp_conn_t *conn, tcp_cstate_cb_t cb, void *arg)
 {
-	log_msg(LVL_DEBUG, "tcp_uc_set_ctate_cb(%p, %p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_set_ctate_cb(%p, %p, %p)",
 	    conn, cb, arg);
 
@@ -298,5 +298,5 @@
 	tcp_conn_t *conn;
 
-	log_msg(LVL_DEBUG, "tcp_as_segment_arrived(f:(%x,%u), l:(%x,%u))",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_as_segment_arrived(f:(%x,%u), l:(%x,%u))",
 	    sp->foreign.addr.ipv4, sp->foreign.port,
 	    sp->local.addr.ipv4, sp->local.port);
@@ -304,5 +304,5 @@
 	conn = tcp_conn_find_ref(sp);
 	if (conn == NULL) {
-		log_msg(LVL_WARN, "No connection found.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "No connection found.");
 		tcp_unexpected_segment(sp, seg);
 		return;
@@ -312,5 +312,5 @@
 
 	if (conn->cstate == st_closed) {
-		log_msg(LVL_WARN, "Connection is closed.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Connection is closed.");
 		tcp_unexpected_segment(sp, seg);
 		fibril_mutex_unlock(&conn->lock);
@@ -339,5 +339,5 @@
 void tcp_to_user(void)
 {
-	log_msg(LVL_DEBUG, "tcp_to_user()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_to_user()");
 }
 
Index: uspace/srv/net/udp/assoc.c
===================================================================
--- uspace/srv/net/udp/assoc.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/udp/assoc.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -104,5 +104,5 @@
 static void udp_assoc_free(udp_assoc_t *assoc)
 {
-	log_msg(LVL_DEBUG, "%s: udp_assoc_free(%p)", assoc->name, assoc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_assoc_free(%p)", assoc->name, assoc);
 
 	while (!list_empty(&assoc->rcv_queue)) {
@@ -127,5 +127,5 @@
 void udp_assoc_addref(udp_assoc_t *assoc)
 {
-	log_msg(LVL_DEBUG, "%s: upd_assoc_addref(%p)", assoc->name, assoc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: upd_assoc_addref(%p)", assoc->name, assoc);
 	atomic_inc(&assoc->refcnt);
 }
@@ -139,5 +139,5 @@
 void udp_assoc_delref(udp_assoc_t *assoc)
 {
-	log_msg(LVL_DEBUG, "%s: udp_assoc_delref(%p)", assoc->name, assoc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_assoc_delref(%p)", assoc->name, assoc);
 
 	if (atomic_predec(&assoc->refcnt) == 0)
@@ -154,5 +154,5 @@
 void udp_assoc_delete(udp_assoc_t *assoc)
 {
-	log_msg(LVL_DEBUG, "%s: udp_assoc_delete(%p)", assoc->name, assoc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_assoc_delete(%p)", assoc->name, assoc);
 
 	assert(assoc->deleted == false);
@@ -192,5 +192,5 @@
 void udp_assoc_set_foreign(udp_assoc_t *assoc, udp_sock_t *fsock)
 {
-	log_msg(LVL_DEBUG, "udp_assoc_set_foreign(%p, %p)", assoc, fsock);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_set_foreign(%p, %p)", assoc, fsock);
 	fibril_mutex_lock(&assoc->lock);
 	assoc->ident.foreign = *fsock;
@@ -205,5 +205,5 @@
 void udp_assoc_set_local(udp_assoc_t *assoc, udp_sock_t *lsock)
 {
-	log_msg(LVL_DEBUG, "udp_assoc_set_local(%p, %p)", assoc, lsock);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_set_local(%p, %p)", assoc, lsock);
 	fibril_mutex_lock(&assoc->lock);
 	assoc->ident.local = *lsock;
@@ -228,5 +228,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "udp_assoc_send(%p, %p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send(%p, %p, %p)",
 	    assoc, fsock, msg);
 
@@ -261,13 +261,13 @@
 	udp_rcv_queue_entry_t *rqe;
 
-	log_msg(LVL_DEBUG, "udp_assoc_recv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv()");
 
 	fibril_mutex_lock(&assoc->lock);
 	while (list_empty(&assoc->rcv_queue)) {
-		log_msg(LVL_DEBUG, "udp_assoc_recv() - waiting");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - waiting");
 		fibril_condvar_wait(&assoc->rcv_queue_cv, &assoc->lock);
 	}
 
-	log_msg(LVL_DEBUG, "udp_assoc_recv() - got a message");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - got a message");
 	link = list_first(&assoc->rcv_queue);
 	rqe = list_get_instance(link, udp_rcv_queue_entry_t, link);
@@ -291,9 +291,9 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "udp_assoc_received(%p, %p)", rsp, msg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_received(%p, %p)", rsp, msg);
 
 	assoc = udp_assoc_find_ref(rsp);
 	if (assoc == NULL) {
-		log_msg(LVL_DEBUG, "No association found. Message dropped.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "No association found. Message dropped.");
 		/* XXX Generate ICMP error. */
 		/* XXX Might propagate error directly by error return. */
@@ -303,5 +303,5 @@
 	rc = udp_assoc_queue_msg(assoc, rsp, msg);
 	if (rc != EOK) {
-		log_msg(LVL_DEBUG, "Out of memory. Message dropped.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Out of memory. Message dropped.");
 		/* XXX Generate ICMP error? */
 	}
@@ -313,5 +313,5 @@
 	udp_rcv_queue_entry_t *rqe;
 
-	log_msg(LVL_DEBUG, "udp_assoc_queue_msg(%p, %p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_queue_msg(%p, %p, %p)",
 	    assoc, sp, msg);
 
@@ -336,5 +336,5 @@
 static bool udp_socket_match(udp_sock_t *sock, udp_sock_t *patt)
 {
-	log_msg(LVL_DEBUG, "udp_socket_match(sock=(%x,%u), pat=(%x,%u))",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_socket_match(sock=(%x,%u), pat=(%x,%u))",
 	    sock->addr.ipv4, sock->port, patt->addr.ipv4, patt->port);
 
@@ -347,5 +347,5 @@
 		return false;
 
-	log_msg(LVL_DEBUG, " -> match");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " -> match");
 
 	return true;
@@ -355,5 +355,5 @@
 static bool udp_sockpair_match(udp_sockpair_t *sp, udp_sockpair_t *pattern)
 {
-	log_msg(LVL_DEBUG, "udp_sockpair_match(%p, %p)", sp, pattern);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sockpair_match(%p, %p)", sp, pattern);
 
 	if (!udp_socket_match(&sp->local, &pattern->local))
@@ -363,5 +363,5 @@
 		return false;
 
-	log_msg(LVL_DEBUG, "Socket pair matched.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Socket pair matched.");
 	return true;
 }
@@ -379,5 +379,5 @@
 static udp_assoc_t *udp_assoc_find_ref(udp_sockpair_t *sp)
 {
-	log_msg(LVL_DEBUG, "udp_assoc_find_ref(%p)", sp);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_find_ref(%p)", sp);
 
 	fibril_mutex_lock(&assoc_list_lock);
@@ -386,5 +386,5 @@
 		udp_assoc_t *assoc = list_get_instance(link, udp_assoc_t, link);
 		udp_sockpair_t *asp = &assoc->ident;
-		log_msg(LVL_DEBUG, "compare with assoc (f:(%x,%u), l:(%x,%u))",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "compare with assoc (f:(%x,%u), l:(%x,%u))",
 		    asp->foreign.addr.ipv4, asp->foreign.port,
 		    asp->local.addr.ipv4, asp->local.port);
@@ -395,5 +395,5 @@
 
 		if (udp_sockpair_match(sp, asp)) {
-			log_msg(LVL_DEBUG, "Returning assoc %p", assoc);
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Returning assoc %p", assoc);
 			udp_assoc_addref(assoc);
 			fibril_mutex_unlock(&assoc_list_lock);
Index: uspace/srv/net/udp/sock.c
===================================================================
--- uspace/srv/net/udp/sock.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/udp/sock.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -88,5 +88,5 @@
 static void udp_sock_notify_data(socket_core_t *sock_core)
 {
-	log_msg(LVL_DEBUG, "udp_sock_notify_data(%d)", sock_core->socket_id);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_notify_data(%d)", sock_core->socket_id);
 	async_exch_t *exch = async_exchange_begin(sock_core->sess);
 	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
@@ -103,6 +103,6 @@
 	ipc_call_t answer;
 
-	log_msg(LVL_DEBUG, "udp_sock_socket()");
-	sock = calloc(sizeof(udp_sockdata_t), 1);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_socket()");
+	sock = calloc(1, sizeof(udp_sockdata_t));
 	if (sock == NULL) {
 		async_answer_0(callid, ENOMEM);
@@ -167,6 +167,6 @@
 	udp_error_t urc;
 
-	log_msg(LVL_DEBUG, "udp_sock_bind()");
-	log_msg(LVL_DEBUG, " - async_data_write_accept");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_bind()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - async_data_write_accept");
 
 	addr = NULL;
@@ -178,5 +178,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - call socket_bind");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_bind");
 	rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
 	    addr, addr_size, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
@@ -192,5 +192,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - call socket_cores_find");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_cores_find");
 	sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
 	if (sock_core == NULL) {
@@ -222,5 +222,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - success");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - success");
 	async_answer_0(callid, rc);
 out:
@@ -231,5 +231,5 @@
 static void udp_sock_listen(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "udp_sock_listen()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_listen()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -237,5 +237,5 @@
 static void udp_sock_connect(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "udp_sock_connect()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connect()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -243,5 +243,5 @@
 static void udp_sock_accept(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "udp_sock_accept()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_accept()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -264,5 +264,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "udp_sock_send()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_send()");
 
 	addr = NULL;
@@ -323,5 +323,5 @@
 			fibril_mutex_unlock(&socket->lock);
 			async_answer_0(callid, rc);
-			log_msg(LVL_DEBUG, "udp_sock_sendto: Failed to "
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_sendto: Failed to "
 			    "determine local address.");
 			return;
@@ -329,5 +329,5 @@
 
 		socket->assoc->ident.local.addr.ipv4 = loc_addr.ipv4;
-		log_msg(LVL_DEBUG, "Local IP address is %x",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Local IP address is %x",
 		    socket->assoc->ident.local.addr.ipv4);
 	}
@@ -405,5 +405,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "%p: udp_sock_recv[from]()", client);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%p: udp_sock_recv[from]()", client);
 
 	socket_id = SOCKET_GET_SOCKET_ID(call);
@@ -427,13 +427,13 @@
 	(void)flags;
 
-	log_msg(LVL_DEBUG, "udp_sock_recvfrom(): lock recv_buffer lock");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recvfrom(): lock recv_buffer lock");
 	fibril_mutex_lock(&socket->recv_buffer_lock);
 	while (socket->recv_buffer_used == 0 && socket->recv_error == UDP_EOK) {
-		log_msg(LVL_DEBUG, "udp_sock_recvfrom(): wait for cv");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recvfrom(): wait for cv");
 		fibril_condvar_wait(&socket->recv_buffer_cv,
 		    &socket->recv_buffer_lock);
 	}
 
-	log_msg(LVL_DEBUG, "Got data in sock recv_buffer");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Got data in sock recv_buffer");
 
 	rsock = socket->recv_fsock;
@@ -441,5 +441,5 @@
 	urc = socket->recv_error;
 
-	log_msg(LVL_DEBUG, "**** recv data_len=%zu", data_len);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "**** recv data_len=%zu", data_len);
 
 	switch (urc) {
@@ -458,5 +458,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "**** udp_uc_receive -> %d", rc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "**** udp_uc_receive -> %d", rc);
 	if (rc != EOK) {
 		fibril_mutex_unlock(&socket->recv_buffer_lock);
@@ -472,5 +472,5 @@
 		addr.sin_port = host2uint16_t_be(rsock.port);
 
-		log_msg(LVL_DEBUG, "addr read receive");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read receive");
 		if (!async_data_read_receive(&rcallid, &addr_length)) {
 			fibril_mutex_unlock(&socket->recv_buffer_lock);
@@ -483,5 +483,5 @@
 			addr_length = sizeof(addr);
 
-		log_msg(LVL_DEBUG, "addr read finalize");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read finalize");
 		rc = async_data_read_finalize(rcallid, &addr, addr_length);
 		if (rc != EOK) {
@@ -493,5 +493,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "data read receive");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "data read receive");
 	if (!async_data_read_receive(&rcallid, &length)) {
 		fibril_mutex_unlock(&socket->recv_buffer_lock);
@@ -504,5 +504,5 @@
 		length = data_len;
 
-	log_msg(LVL_DEBUG, "data read finalize");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "data read finalize");
 	rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
 
@@ -510,5 +510,5 @@
 		rc = EOVERFLOW;
 
-	log_msg(LVL_DEBUG, "read_data_length <- %zu", length);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "read_data_length <- %zu", length);
 	IPC_SET_ARG2(answer, 0);
 	SOCKET_SET_READ_DATA_LENGTH(answer, length);
@@ -531,5 +531,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_sock_close()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close()");
 	socket_id = SOCKET_GET_SOCKET_ID(call);
 
@@ -557,5 +557,5 @@
 static void udp_sock_getsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "udp_sock_getsockopt()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_getsockopt()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -563,5 +563,5 @@
 static void udp_sock_setsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "udp_sock_setsockopt()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_setsockopt()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -574,8 +574,8 @@
 	size_t rcvd;
 
-	log_msg(LVL_DEBUG, "udp_sock_recv_fibril()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recv_fibril()");
 
 	while (true) {
-		log_msg(LVL_DEBUG, "[] wait for rcv buffer empty()");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "[] wait for rcv buffer empty()");
 		fibril_mutex_lock(&sock->recv_buffer_lock);
 		while (sock->recv_buffer_used != 0) {
@@ -584,5 +584,5 @@
 		}
 
-		log_msg(LVL_DEBUG, "[] call udp_uc_receive()");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "[] call udp_uc_receive()");
 		urc = udp_uc_receive(sock->assoc, sock->recv_buffer,
 		    UDP_FRAGMENT_SIZE, &rcvd, &xflags, &sock->recv_fsock);
@@ -597,5 +597,5 @@
 		}
 
-		log_msg(LVL_DEBUG, "[] got data - broadcast recv_buffer_cv");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "[] got data - broadcast recv_buffer_cv");
 
 		sock->recv_buffer_used = rcvd;
@@ -622,10 +622,10 @@
 
 	while (true) {
-		log_msg(LVL_DEBUG, "udp_sock_connection: wait");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: wait");
 		callid = async_get_call(&call);
 		if (!IPC_GET_IMETHOD(call))
 			break;
 
-		log_msg(LVL_DEBUG, "udp_sock_connection: METHOD=%d",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: METHOD=%d",
 		    (int)IPC_GET_IMETHOD(call));
 
@@ -670,5 +670,5 @@
 
 	/* Clean up */
-	log_msg(LVL_DEBUG, "udp_sock_connection: Clean up");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: Clean up");
 	async_hangup(client.sess);
 	socket_cores_release(NULL, &client.sockets, &gsock, udp_free_sock_data);
Index: uspace/srv/net/udp/ucall.c
===================================================================
--- uspace/srv/net/udp/ucall.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/udp/ucall.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -47,5 +47,5 @@
 	udp_assoc_t *nassoc;
 
-	log_msg(LVL_DEBUG, "udp_uc_create()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_uc_create()");
 	nassoc = udp_assoc_new(NULL, NULL);
 	if (nassoc == NULL)
@@ -59,5 +59,5 @@
 udp_error_t udp_uc_set_foreign(udp_assoc_t *assoc, udp_sock_t *fsock)
 {
-	log_msg(LVL_DEBUG, "udp_uc_set_foreign(%p, %p)", assoc, fsock);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_uc_set_foreign(%p, %p)", assoc, fsock);
 
 	udp_assoc_set_foreign(assoc, fsock);
@@ -67,5 +67,5 @@
 udp_error_t udp_uc_set_local(udp_assoc_t *assoc, udp_sock_t *lsock)
 {
-	log_msg(LVL_DEBUG, "udp_uc_set_local(%p, %p)", assoc, lsock);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_uc_set_local(%p, %p)", assoc, lsock);
 
 	udp_assoc_set_local(assoc, lsock);
@@ -79,5 +79,5 @@
 	udp_msg_t msg;
 
-	log_msg(LVL_DEBUG, "%s: udp_uc_send()", assoc->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_uc_send()", assoc->name);
 
 	msg.data = data;
@@ -103,5 +103,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "%s: udp_uc_receive()", assoc->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_uc_receive()", assoc->name);
 	rc = udp_assoc_recv(assoc, &msg, fsock);
 	switch (rc) {
@@ -118,5 +118,5 @@
 void udp_uc_status(udp_assoc_t *assoc, udp_assoc_status_t *astatus)
 {
-	log_msg(LVL_DEBUG, "udp_uc_status()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_uc_status()");
 //	cstatus->cstate = conn->cstate;
 }
@@ -124,5 +124,5 @@
 void udp_uc_destroy(udp_assoc_t *assoc)
 {
-	log_msg(LVL_DEBUG, "udp_uc_destroy()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_uc_destroy()");
 	udp_assoc_remove(assoc);
 	udp_assoc_delete(assoc);
Index: uspace/srv/net/udp/udp.c
===================================================================
--- uspace/srv/net/udp/udp.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/udp/udp.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -50,9 +50,9 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "udp_init()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_init()");
 
 	rc = udp_inet_init();
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed connecting to internet service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed connecting to internet service.");
 		return ENOENT;
 	}
@@ -60,5 +60,5 @@
 	rc = udp_sock_init();
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed initializing socket service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed initializing socket service.");
 		return ENOENT;
 	}
@@ -73,5 +73,5 @@
 	printf(NAME ": UDP (User Datagram Protocol) service\n");
 
-	rc = log_init(NAME, LVL_DEBUG);
+	rc = log_init(NAME);
 	if (rc != EOK) {
 		printf(NAME ": Failed to initialize log.\n");
Index: uspace/srv/net/udp/udp_inet.c
===================================================================
--- uspace/srv/net/udp/udp_inet.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/net/udp/udp_inet.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -61,5 +61,5 @@
 	udp_pdu_t *pdu;
 
-	log_msg(LVL_DEBUG, "udp_inet_ev_recv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_inet_ev_recv()");
 
 	pdu = udp_pdu_new();
@@ -69,5 +69,5 @@
 	pdu->src.ipv4 = dgram->src.ipv4;
 	pdu->dest.ipv4 = dgram->dest.ipv4;
-	log_msg(LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
 	    pdu->src.ipv4, pdu->dest.ipv4);
 
@@ -84,5 +84,5 @@
 	inet_dgram_t dgram;
 
-	log_msg(LVL_DEBUG, "udp_transmit_pdu()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_transmit_pdu()");
 
 	dgram.src.ipv4 = pdu->src.ipv4;
@@ -94,5 +94,5 @@
 	rc = inet_send(&dgram, INET_TTL_MAX, 0);
 	if (rc != EOK)
-		log_msg(LVL_ERROR, "Failed to transmit PDU.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to transmit PDU.");
 
 	return rc;
@@ -105,8 +105,8 @@
 	udp_sockpair_t rident;
 
-	log_msg(LVL_DEBUG, "udp_received_pdu()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_received_pdu()");
 
 	if (udp_pdu_decode(pdu, &rident, &dmsg) != EOK) {
-		log_msg(LVL_WARN, "Not enough memory. PDU dropped.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. PDU dropped.");
 		return;
 	}
@@ -124,9 +124,9 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "udp_inet_init()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_inet_init()");
 
 	rc = inet_init(IP_PROTO_UDP, &udp_inet_ev_ops);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed connecting to internet service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed connecting to internet service.");
 		return ENOENT;
 	}
Index: uspace/srv/ns/service.c
===================================================================
--- uspace/srv/ns/service.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/ns/service.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -72,6 +72,6 @@
 	.key_hash = service_key_hash,
 	.key_equal = service_key_equal,
-	.equal = 0,
-	.remove_callback = 0
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
Index: uspace/srv/ns/task.c
===================================================================
--- uspace/srv/ns/task.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/ns/task.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -90,5 +90,5 @@
 	.key_hash = task_key_hash,
 	.key_equal = task_key_equal,
-	.equal = 0,
+	.equal = NULL,
 	.remove_callback = task_remove
 };
@@ -141,5 +141,5 @@
 	.key_hash = p2i_key_hash,
 	.key_equal = p2i_key_equal,
-	.equal = 0,
+	.equal = NULL,
 	.remove_callback = p2i_remove
 };
Index: uspace/srv/vfs/vfs_node.c
===================================================================
--- uspace/srv/vfs/vfs_node.c	(revision fc89e32010e50e34041343fec03821fd9d0b07df)
+++ uspace/srv/vfs/vfs_node.c	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -69,6 +69,6 @@
 	.key_hash = nodes_key_hash,
 	.key_equal = nodes_key_equal,
-	.equal = 0,
-	.remove_callback = 0,
+	.equal = NULL,
+	.remove_callback = NULL,
 };
 
