Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ boot/Makefile.common	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -159,4 +159,5 @@
 
 RD_APPS_NON_ESSENTIAL = \
+	$(USPACE_PATH)/app/bithenge/bithenge \
 	$(USPACE_PATH)/app/blkdump/blkdump \
 	$(USPACE_PATH)/app/bnchmark/bnchmark \
Index: contrib/bazaar/bzreml/__init__.py
===================================================================
--- contrib/bazaar/bzreml/__init__.py	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ contrib/bazaar/bzreml/__init__.py	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 b801f2d6becda84795177e84564a610b886dbea0)
+++ contrib/bazaar/mbprotect/__init__.py	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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: kernel/generic/include/ipc/sysipc_ops.h
===================================================================
--- kernel/generic/include/ipc/sysipc_ops.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ kernel/generic/include/ipc/sysipc_ops.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -38,4 +38,51 @@
 #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 {
 	/**
@@ -59,5 +106,5 @@
 	 * Invoked on:		all forgotten calls
 	 */	
-	void (* request_forget)(call_t *);
+	int (* request_forget)(call_t *);
 
 	/**
@@ -67,5 +114,5 @@
 	 * Caller alive:	no guarantee
 	 * Races with:		request_forget()
-	 * Invoked on:		calls that are received by the callee
+	 * Invoked on:		all calls delivered to the callee
 	 */	
 	int (* request_process)(call_t *, answerbox_t *);
@@ -80,5 +127,5 @@
 	 * Invoked on:		all forgotten calls
 	 */
-	void (* answer_cleanup)(call_t *, ipc_data_t *);
+	int (* answer_cleanup)(call_t *, ipc_data_t *);
 
 	/**
@@ -107,7 +154,7 @@
 
 extern int null_request_preprocess(call_t *, phone_t *);
-extern void null_request_forget(call_t *);
+extern int null_request_forget(call_t *);
 extern int null_request_process(call_t *, answerbox_t *);
-extern void null_answer_cleanup(call_t *, ipc_data_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 *);
Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ kernel/generic/src/ipc/ipc.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -255,15 +255,5 @@
 }
 
-/** Simulate sending back a message.
- *
- * Most errors are better handled by forming a normal backward
- * message and sending it as a normal answer.
- *
- * @param phone Phone structure the call should appear to come from.
- * @param call  Call structure to be answered.
- * @param err   Return value to be used for the answer.
- *
- */
-void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
+static void _ipc_call_actions_internal(phone_t *phone, call_t *call)
 {
 	task_t *caller = phone->caller;
@@ -279,5 +269,20 @@
 
 	call->data.phone = phone;
-
+	call->data.task_id = caller->taskid;
+}
+
+/** Simulate sending back a message.
+ *
+ * Most errors are better handled by forming a normal backward
+ * message and sending it as a normal answer.
+ *
+ * @param phone Phone structure the call should appear to come from.
+ * @param call  Call structure to be answered.
+ * @param err   Return value to be used for the answer.
+ *
+ */
+void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
+{
+	_ipc_call_actions_internal(phone, call);
 	IPC_SET_RETVAL(call->data, err);
 	_ipc_answer_free_call(call, false);
@@ -300,17 +305,6 @@
 	irq_spinlock_unlock(&caller->lock, true);
 	
-	if (!(call->flags & IPC_CALL_FORWARDED)) {
-		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;
-	}
+	if (!(call->flags & IPC_CALL_FORWARDED))
+		_ipc_call_actions_internal(phone, call);
 	
 	irq_spinlock_lock(&box->lock, true);
@@ -518,4 +512,7 @@
 
 		irq_spinlock_unlock(&box->lock, true);
+
+		if (lst == &box->calls)
+			SYSIPC_OP(request_process, call, box);
 
 		ipc_data_t old = call->data;
@@ -643,7 +640,5 @@
 	atomic_dec(&call->caller_phone->active_calls);
 
-	sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
-	if (ops->request_forget)
-		ops->request_forget(call);
+	SYSIPC_OP(request_forget, call);
 
 	ipc_call_release(call);
@@ -713,4 +708,7 @@
 	    SYNCH_FLAGS_NONE);
 	ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
+
+	SYSIPC_OP(answer_process, call);
+
 	ipc_call_free(call);
 	goto restart;
@@ -754,7 +752,7 @@
 	
 	/* Answer all messages in 'calls' and 'dispatched_calls' queues */
+	ipc_cleanup_call_list(&TASK->answerbox, &TASK->answerbox.calls);
 	ipc_cleanup_call_list(&TASK->answerbox,
 	    &TASK->answerbox.dispatched_calls);
-	ipc_cleanup_call_list(&TASK->answerbox, &TASK->answerbox.calls);
 
 	ipc_forget_all_active_calls();
Index: kernel/generic/src/ipc/kbox.c
===================================================================
--- kernel/generic/src/ipc/kbox.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ kernel/generic/src/ipc/kbox.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -96,6 +96,6 @@
 	
 	/* Answer all messages in 'calls' and 'dispatched_calls' queues. */
+	ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.calls);
 	ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.dispatched_calls);
-	ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.calls);
 }
 
Index: kernel/generic/src/ipc/ops/clnestab.c
===================================================================
--- kernel/generic/src/ipc/ops/clnestab.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ kernel/generic/src/ipc/ops/clnestab.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -45,5 +45,5 @@
 }
 
-static void answer_cleanup(call_t *answer, ipc_data_t *olddata)
+static int answer_cleanup(call_t *answer, ipc_data_t *olddata)
 {
 	phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
@@ -57,4 +57,6 @@
 	}
 	mutex_unlock(&phone->lock);
+
+	return EOK;
 }
 
Index: kernel/generic/src/ipc/ops/conctmeto.c
===================================================================
--- kernel/generic/src/ipc/ops/conctmeto.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ kernel/generic/src/ipc/ops/conctmeto.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -54,7 +54,8 @@
 }
 
-static void request_forget(call_t *call)
+static int request_forget(call_t *call)
 {
 	phone_dealloc(call->priv);
+	return EOK;
 }
 
Index: kernel/generic/src/ipc/ops/concttome.c
===================================================================
--- kernel/generic/src/ipc/ops/concttome.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ kernel/generic/src/ipc/ops/concttome.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -40,11 +40,4 @@
 #include <arch.h>
 
-static int request_preprocess(call_t *call, phone_t *phone)
-{
-	/* Start with the assumption that there is no allocated phoneid. */
-	IPC_SET_ARG5(call->data, -1);
-	return EOK;
-}
-
 static int request_process(call_t *call, answerbox_t *box)
 {
@@ -56,5 +49,5 @@
 }
 
-static void answer_cleanup(call_t *answer, ipc_data_t *olddata)
+static int answer_cleanup(call_t *answer, ipc_data_t *olddata)
 {
 	int phoneid = (int) IPC_GET_ARG5(*olddata);
@@ -62,4 +55,6 @@
 	if (phoneid >= 0)
 		phone_dealloc(phoneid);
+
+	return EOK;
 }
 
@@ -91,5 +86,5 @@
 
 sysipc_ops_t ipc_m_connect_to_me_ops = {
-	.request_preprocess = request_preprocess,
+	.request_preprocess = null_request_preprocess,
 	.request_forget = null_request_forget,
 	.request_process = request_process,
Index: kernel/generic/src/ipc/ops/connclone.c
===================================================================
--- kernel/generic/src/ipc/ops/connclone.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ kernel/generic/src/ipc/ops/connclone.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -97,5 +97,5 @@
 }
 
-static void answer_cleanup(call_t *answer, ipc_data_t *olddata)
+static int answer_cleanup(call_t *answer, ipc_data_t *olddata)
 {
 	int phoneid = (int) IPC_GET_ARG1(*olddata);
@@ -116,4 +116,6 @@
 	}
 	mutex_unlock(&phone->lock);
+
+	return EOK;
 }
 
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ kernel/generic/src/ipc/sysipc.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -161,5 +161,4 @@
 {
 	int rc = EOK;
-	sysipc_ops_t *ops;
 
 	spinlock_lock(&answer->forget_lock);
@@ -170,8 +169,5 @@
 		spinlock_unlock(&answer->forget_lock);
 
-		ops = sysipc_ops_get(answer->request_method);
-		if (ops->answer_cleanup)
-			ops->answer_cleanup(answer, olddata);
-
+		SYSIPC_OP(answer_cleanup, answer, olddata);
 		return rc;
 	} else {
@@ -213,9 +209,5 @@
 		return rc;
 
-	ops = sysipc_ops_get(answer->request_method);
-	if (ops->answer_preprocess)
-		rc = ops->answer_preprocess(answer, olddata);
-	
-	return rc;
+	return SYSIPC_OP(answer_preprocess, answer, olddata);
 }
 
@@ -230,13 +222,6 @@
 static int request_preprocess(call_t *call, phone_t *phone)
 {
-	int rc = EOK;
-
 	call->request_method = IPC_GET_IMETHOD(call->data);
-
-	sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
-	if (ops->request_preprocess)
-		rc = ops->request_preprocess(call, phone);
-	
-	return rc;
+	return SYSIPC_OP(request_preprocess, call, phone);
 }
 
@@ -256,7 +241,5 @@
 		IPC_SET_RETVAL(call->data, EFORWARD);
 	
-	sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
-	if (ops->answer_process)
-		(void) ops->answer_process(call);
+	SYSIPC_OP(answer_process, call);
 }
 
@@ -273,11 +256,5 @@
 static int process_request(answerbox_t *box, call_t *call)
 {
-	int rc = EOK;
-
-	sysipc_ops_t *ops = sysipc_ops_get(call->request_method);
-	if (ops->request_process)
-		rc = ops->request_process(call, box);
-	
-	return rc;
+	return SYSIPC_OP(request_process, call, box);
 }
 
Index: kernel/generic/src/ipc/sysipc_ops.c
===================================================================
--- kernel/generic/src/ipc/sysipc_ops.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ kernel/generic/src/ipc/sysipc_ops.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -76,6 +76,7 @@
 }
 
-void null_request_forget(call_t *call)
+int null_request_forget(call_t *call)
 {
+	return EOK;
 }
 
@@ -85,6 +86,7 @@
 }
 
-void null_answer_cleanup(call_t *call, ipc_data_t *data)
+int null_answer_cleanup(call_t *call, ipc_data_t *data)
 {
+	return EOK;
 }
 
Index: tools/toolchain.sh
===================================================================
--- tools/toolchain.sh	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ tools/toolchain.sh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/Makefile	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -35,4 +35,5 @@
 DIRS = \
 	app/bdsh \
+	app/bithenge \
 	app/blkdump \
 	app/bnchmark \
@@ -219,4 +220,5 @@
 	lib/usbhid \
 	lib/usbvirt \
+	lib/bithenge \
 	lib/posix
 
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/Makefile.common	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/app/bdsh/Makefile	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/app/bdsh/cmds/modules/cmp/cmp.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/app/bdsh/cmds/modules/cmp/cmp.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/app/bdsh/cmds/modules/cmp/cmp_def.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/app/bdsh/cmds/modules/cmp/entry.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/app/bdsh/cmds/modules/modules.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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/bithenge/Makefile
===================================================================
--- uspace/app/bithenge/Makefile	(revision 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/app/bithenge/Makefile	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/app/bithenge/Makefile.linux	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/app/bithenge/test.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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/mkexfat/mkexfat.c
===================================================================
--- uspace/app/mkexfat/mkexfat.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/app/mkexfat/mkexfat.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -49,4 +49,5 @@
 #include <str.h>
 #include <getopt.h>
+#include <macros.h>
 #include "exfat.h"
 #include "upcase.h"
@@ -87,5 +88,4 @@
 #define FIRST_FREE_CLUSTER   2
 
-#define min(x, y) ((x) < (y) ? (x) : (y))
 
 typedef struct exfat_cfg {
Index: uspace/app/msim/arch_helenos/input.c
===================================================================
--- uspace/app/msim/arch_helenos/input.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/app/msim/arch_helenos/input.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/app/msim/arch_helenos/misc.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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/float/softfloat1.c
===================================================================
--- uspace/app/tester/float/softfloat1.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/app/tester/float/softfloat1.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -31,8 +31,11 @@
 #include <sftypes.h>
 #include <add.h>
+#include <sub.h>
+#include <mul.h>
+#include <div.h>
 #include <bool.h>
 #include "../tester.h"
 
-#define OPERANDS   5
+#define OPERANDS  6 
 #define PRECISION  10000
 
@@ -40,10 +43,20 @@
 
 typedef int32_t cmptype_t;
-
-static float float_op_a[OPERANDS] =
-	{3.5, -2.1, 100.0, 50.0, -1024.0};
-
-static float float_op_b[OPERANDS] =
-	{-2.1, 100.0, 50.0, -1024.0, 3.5};
+typedef void (* float_op_t)(float, float, float *, float_t *);
+typedef void (* double_op_t)(double, double, double *, double_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)
@@ -55,28 +68,49 @@
 }
 
-static bool test_float_add(void)
+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 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++) {
-			float a = float_op_a[i];
-			float b = float_op_b[j];
-			float c = a + b;
-			
-			float_t sa;
-			float_t sb;
-			float_t sc;
-			
-			sa.val = float_op_a[i];
-			sb.val = float_op_b[i];
-			sc.data = add_float(sa.data, sb.data);
-			
-			cmptype_t ic = (cmptype_t) (c * PRECISION);
-			cmptype_t isc = (cmptype_t) (sc.val * PRECISION);
+		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);
+				TPRINTF("i=%u, j=%u diff=%" PRIdCMPTYPE "\n",
+				    i, j, diff);
 				correct = false;
 			}
@@ -87,9 +121,134 @@
 }
 
+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);
+}
+
 const char *test_softfloat1(void)
 {
-	if (!test_float_add())
-		return "Float addition failed";
-	
-	return NULL;
-}
+	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);
+	}
+	
+	return err;
+}
+
Index: uspace/app/trace/ipcp.c
===================================================================
--- uspace/app/trace/ipcp.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/app/trace/ipcp.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -38,4 +38,5 @@
 #include <sys/typefmt.h>
 #include <abi/ipc/methods.h>
+#include <macros.h>
 #include "ipc_desc.h"
 #include "proto.h"
@@ -52,5 +53,5 @@
 	ipc_callid_t call_hash;
 
-	link_t link;
+	ht_link_t link;
 } pending_call_t;
 
@@ -64,6 +65,5 @@
 int have_conn[MAX_PHONE];
 
-#define PCALL_TABLE_CHAINS 32
-hash_table_t pending_calls;
+static hash_table_t pending_calls;
 
 /*
@@ -73,38 +73,32 @@
 proto_t	*proto_unknown;		/**< Protocol with no known methods. */
 
-static hash_index_t pending_call_hash(unsigned long key[]);
-static int pending_call_compare(unsigned long key[], hash_count_t keys,
-    link_t *item);
-static void pending_call_remove_callback(link_t *item);
-
-hash_table_operations_t pending_call_ops = {
+
+static size_t pending_call_key_hash(void *key)
+{
+	ipc_callid_t *call_id = (ipc_callid_t *)key;
+	return *call_id;
+}
+
+static size_t pending_call_hash(const ht_link_t *item)
+{
+	pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
+	return hs->call_hash;
+}
+
+static bool pending_call_key_equal(void *key, const ht_link_t *item)
+{
+	ipc_callid_t *call_id = (ipc_callid_t *)key;
+	pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
+
+	return *call_id == hs->call_hash;
+}
+
+static hash_table_ops_t pending_call_ops = {
 	.hash = pending_call_hash,
-	.compare = pending_call_compare,
-	.remove_callback = pending_call_remove_callback
+	.key_hash = pending_call_key_hash,
+	.key_equal = pending_call_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
 };
-
-
-static hash_index_t pending_call_hash(unsigned long key[])
-{
-//	printf("pending_call_hash\n");
-	return key[0] % PCALL_TABLE_CHAINS;
-}
-
-static int pending_call_compare(unsigned long key[], hash_count_t keys,
-    link_t *item)
-{
-	pending_call_t *hs;
-
-//	printf("pending_call_compare\n");
-	hs = hash_table_get_instance(item, pending_call_t, link);
-
-	// FIXME: this will fail if sizeof(long) < sizeof(void *).
-	return key[0] == hs->call_hash;
-}
-
-static void pending_call_remove_callback(link_t *item)
-{
-//	printf("pending_call_remove_callback\n");
-}
 
 
@@ -177,5 +171,6 @@
 	}
 
-	hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
+	bool ok = hash_table_create(&pending_calls, 0, 0, &pending_call_ops);
+	assert(ok);
 }
 
@@ -190,5 +185,4 @@
 	pending_call_t *pcall;
 	proto_t *proto;
-	unsigned long key[1];
 	oper_t *oper;
 	sysarg_t *args;
@@ -254,7 +248,5 @@
 	pcall->oper = oper;
 
-	key[0] = hash;
-
-	hash_table_insert(&pending_calls, key, &pcall->link);
+	hash_table_insert(&pending_calls, &pcall->link);
 }
 
@@ -334,7 +326,6 @@
 void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
 {
-	link_t *item;
+	ht_link_t *item;
 	pending_call_t *pcall;
-	unsigned long key[1];
 	
 	if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
@@ -347,7 +338,6 @@
 	
 	hash = hash & ~IPC_CALLID_ANSWERED;
-	key[0] = hash;
-	
-	item = hash_table_find(&pending_calls, key);
+	
+	item = hash_table_find(&pending_calls, &hash);
 	if (item == NULL)
 		return; /* No matching question found */
@@ -357,6 +347,6 @@
 	 */
 	
-	pcall = hash_table_get_instance(item, pending_call_t, link);
-	hash_table_remove(&pending_calls, key, 1);
+	pcall = hash_table_get_inst(item, pending_call_t, link);
+	hash_table_remove(&pending_calls, &hash);
 	
 	parse_answer(hash, pcall, call);
Index: uspace/app/trace/proto.c
===================================================================
--- uspace/app/trace/proto.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/app/trace/proto.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -40,117 +40,103 @@
 #include "proto.h"
 
-#define SRV_PROTO_TABLE_CHAINS 32
-#define METHOD_OPER_TABLE_CHAINS 32
-
-hash_table_t srv_proto;
+
+/* Maps service number to protocol */
+static hash_table_t srv_proto;
 
 typedef struct {
-	unsigned srv;
+	int srv;
 	proto_t *proto;
-	link_t link;
+	ht_link_t link;
 } srv_proto_t;
 
 typedef struct {
-	sysarg_t method;
+	int method;
 	oper_t *oper;
-	link_t link;
+	ht_link_t link;
 } method_oper_t;
 
-static hash_index_t srv_proto_hash(unsigned long key[]);
-static int srv_proto_compare(unsigned long key[], hash_count_t keys,
-    link_t *item);
-static void srv_proto_remove_callback(link_t *item);
-
-hash_table_operations_t srv_proto_ops = {
+/* Hash table operations. */
+
+static size_t srv_proto_key_hash(void *key)
+{
+	return *(int *)key;
+}
+
+static size_t srv_proto_hash(const ht_link_t *item)
+{
+	srv_proto_t *sp = hash_table_get_inst(item, srv_proto_t, link);
+	return sp->srv;
+}
+
+static bool srv_proto_key_equal(void *key, const ht_link_t *item)
+{
+	srv_proto_t *sp = hash_table_get_inst(item, srv_proto_t, link);
+	return sp->srv == *(int *)key;
+}
+
+static hash_table_ops_t srv_proto_ops = {
 	.hash = srv_proto_hash,
-	.compare = srv_proto_compare,
-	.remove_callback = srv_proto_remove_callback
+	.key_hash = srv_proto_key_hash,
+	.key_equal = srv_proto_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
-static hash_index_t method_oper_hash(unsigned long key[]);
-static int method_oper_compare(unsigned long key[], hash_count_t keys,
-    link_t *item);
-static void method_oper_remove_callback(link_t *item);
-
-hash_table_operations_t method_oper_ops = {
+
+static size_t method_oper_key_hash(void *key)
+{
+	return *(int *)key;
+}
+
+static size_t method_oper_hash(const ht_link_t *item)
+{
+	method_oper_t *mo = hash_table_get_inst(item, method_oper_t, link);
+	return mo->method;
+}
+
+static bool method_oper_key_equal(void *key, const ht_link_t *item)
+{
+	method_oper_t *mo = hash_table_get_inst(item, method_oper_t, link);
+	return mo->method == *(int *)key;
+}
+
+static hash_table_ops_t method_oper_ops = {
 	.hash = method_oper_hash,
-	.compare = method_oper_compare,
-	.remove_callback = method_oper_remove_callback
+	.key_hash = method_oper_key_hash,
+	.key_equal = method_oper_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
-static hash_index_t srv_proto_hash(unsigned long key[])
-{
-	return key[0] % SRV_PROTO_TABLE_CHAINS;
-}
-
-static int srv_proto_compare(unsigned long key[], hash_count_t keys,
-    link_t *item)
+
+void proto_init(void)
+{
+	/* todo: check return value. */
+	bool ok = hash_table_create(&srv_proto, 0, 0, &srv_proto_ops);
+	assert(ok);
+}
+
+void proto_cleanup(void)
+{
+	hash_table_destroy(&srv_proto);
+}
+
+void proto_register(int srv, proto_t *proto)
 {
 	srv_proto_t *sp;
-
-	sp = hash_table_get_instance(item, srv_proto_t, link);
-
-	return key[0] == sp->srv;
-}
-
-static void srv_proto_remove_callback(link_t *item)
-{
-}
-
-static hash_index_t method_oper_hash(unsigned long key[])
-{
-	return key[0] % METHOD_OPER_TABLE_CHAINS;
-}
-
-static int method_oper_compare(unsigned long key[], hash_count_t keys,
-    link_t *item)
-{
-	method_oper_t *mo;
-
-	mo = hash_table_get_instance(item, method_oper_t, link);
-
-	return key[0] == mo->method;
-}
-
-static void method_oper_remove_callback(link_t *item)
-{
-}
-
-
-void proto_init(void)
-{
-	hash_table_create(&srv_proto, SRV_PROTO_TABLE_CHAINS, 1,
-	    &srv_proto_ops);
-}
-
-void proto_cleanup(void)
-{
-	hash_table_destroy(&srv_proto);
-}
-
-void proto_register(int srv, proto_t *proto)
-{
-	srv_proto_t *sp;
-	unsigned long key;
 
 	sp = malloc(sizeof(srv_proto_t));
 	sp->srv = srv;
 	sp->proto = proto;
-	key = srv;
-
-	hash_table_insert(&srv_proto, &key, &sp->link);
+
+	hash_table_insert(&srv_proto, &sp->link);
 }
 
 proto_t *proto_get_by_srv(int srv)
 {
-	unsigned long key;
-	link_t *item;
-	srv_proto_t *sp;
-
-	key = srv;
-	item = hash_table_find(&srv_proto, &key);
+	ht_link_t *item = hash_table_find(&srv_proto, &srv);
 	if (item == NULL) return NULL;
 
-	sp = hash_table_get_instance(item, srv_proto_t, link);
+	srv_proto_t *sp = hash_table_get_inst(item, srv_proto_t, link);
 	return sp->proto;
 }
@@ -159,6 +145,7 @@
 {
 	proto->name = name;
-	hash_table_create(&proto->method_oper, SRV_PROTO_TABLE_CHAINS, 1,
-	    &method_oper_ops);
+	/* todo: check return value. */
+	bool ok = hash_table_create(&proto->method_oper, 0, 0, &method_oper_ops);
+	assert(ok);
 }
 
@@ -181,25 +168,18 @@
 {
 	method_oper_t *mo;
-	unsigned long key;
 
 	mo = malloc(sizeof(method_oper_t));
 	mo->method = method;
 	mo->oper = oper;
-	key = method;
-
-	hash_table_insert(&proto->method_oper, &key, &mo->link);	
+
+	hash_table_insert(&proto->method_oper, &mo->link);	
 }
 
 oper_t *proto_get_oper(proto_t *proto, int method)
 {
-	unsigned long key;
-	link_t *item;
-	method_oper_t *mo;
-
-	key = method;
-	item = hash_table_find(&proto->method_oper, &key);
+	ht_link_t *item = hash_table_find(&proto->method_oper, &method);
 	if (item == NULL) return NULL;
 
-	mo = hash_table_get_instance(item, method_oper_t, link);
+	method_oper_t *mo = hash_table_get_inst(item, method_oper_t, link);
 	return mo->oper;
 }
Index: uspace/app/trace/proto.h
===================================================================
--- uspace/app/trace/proto.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/app/trace/proto.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -62,6 +62,4 @@
 } proto_t;
 
-/* Maps service number to protocol */
-extern hash_table_t srv_proto;
 
 extern void proto_init(void);
Index: uspace/dist/src/bithenge/basic.bh
===================================================================
--- uspace/dist/src/bithenge/basic.bh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/basic.bh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/basic.dat	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -0,0 +1,2 @@
+ªðð!CeeC!þÜºvT22TvºÜþ0~
+\"'	
Index: uspace/dist/src/bithenge/basic.out
===================================================================
--- uspace/dist/src/bithenge/basic.out	(revision 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/basic.out	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/bits.bh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/bits.dat	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -0,0 +1,1 @@
+ee¤BB%
Index: uspace/dist/src/bithenge/bits.out
===================================================================
--- uspace/dist/src/bithenge/bits.out	(revision 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/bits.out	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/cond.bh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/cond.out	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/expression.bh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/expression.dat	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -0,0 +1,1 @@
+17
Index: uspace/dist/src/bithenge/expression.out
===================================================================
--- uspace/dist/src/bithenge/expression.out	(revision 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/expression.out	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/fat.bh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/fat.out	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/gif/gif.bh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/gif/readme	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/repeat.bh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/repeat.out	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/test.bdsh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/test.sh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/trip.bh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/trip.out	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/usbdesc.bh	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/dist/src/bithenge/usbdesc.kbd.out	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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/lib/bithenge/Makefile
===================================================================
--- uspace/lib/bithenge/Makefile	(revision 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/Makefile	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/Makefile.linux	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/include/bithenge/blob.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/include/bithenge/compound.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/include/bithenge/expression.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/include/bithenge/file.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/include/bithenge/os.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/include/bithenge/print.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/include/bithenge/script.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/include/bithenge/sequence.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/include/bithenge/source.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/include/bithenge/transform.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/include/bithenge/tree.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/blob.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/common.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/compound.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/expression.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/failure.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/failure.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/file.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/helenos/block.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/helenos/block.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/helenos/common.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/linux/common.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/print.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/script.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/sequence.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/source.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/transform.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/bithenge/src/tree.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/block/block.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -62,6 +62,4 @@
 static LIST_INITIALIZE(dcl);
 
-#define CACHE_BUCKETS_LOG2  10
-#define CACHE_BUCKETS       (1 << CACHE_BUCKETS_LOG2)
 
 typedef struct {
@@ -233,23 +231,30 @@
 }
 
-static hash_index_t cache_hash(unsigned long *key)
-{
-	return MERGE_LOUP32(key[0], key[1]) & (CACHE_BUCKETS - 1);
-}
-
-static int cache_compare(unsigned long *key, hash_count_t keys, link_t *item)
-{
-	block_t *b = hash_table_get_instance(item, block_t, hash_link);
-	return b->lba == MERGE_LOUP32(key[0], key[1]);
-}
-
-static void cache_remove_callback(link_t *item)
-{
-}
-
-static hash_table_operations_t cache_ops = {
+static size_t cache_key_hash(void *key)
+{
+	aoff64_t *lba = (aoff64_t*)key;
+	return *lba;
+}
+
+static size_t cache_hash(const ht_link_t *item)
+{
+	block_t *b = hash_table_get_inst(item, block_t, hash_link);
+	return b->lba;
+}
+
+static bool cache_key_equal(void *key, const ht_link_t *item)
+{
+	aoff64_t *lba = (aoff64_t*)key;
+	block_t *b = hash_table_get_inst(item, block_t, hash_link);
+	return b->lba == *lba;
+}
+
+
+static hash_table_ops_t cache_ops = {
 	.hash = cache_hash,
-	.compare = cache_compare,
-	.remove_callback = cache_remove_callback
+	.key_hash = cache_key_hash,
+	.key_equal = cache_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -282,6 +287,5 @@
 	cache->blocks_cluster = cache->lblock_size / devcon->pblock_size;
 
-	if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 2,
-	    &cache_ops)) {
+	if (!hash_table_create(&cache->block_hash, 0, 0, &cache_ops)) {
 		free(cache);
 		return ENOMEM;
@@ -321,9 +325,5 @@
 		}
 
-		unsigned long key[2] = {
-			LOWER32(b->lba),
-			UPPER32(b->lba)
-		};
-		hash_table_remove(&cache->block_hash, key, 2);
+		hash_table_remove_item(&cache->block_hash, &b->hash_link);
 		
 		free(b->data);
@@ -357,5 +357,4 @@
 	fibril_rwlock_initialize(&b->contents_lock);
 	link_initialize(&b->free_link);
-	link_initialize(&b->hash_link);
 }
 
@@ -377,9 +376,5 @@
 	cache_t *cache;
 	block_t *b;
-	link_t *l;
-	unsigned long key[2] = {
-		LOWER32(ba),
-		UPPER32(ba)
-	};
+	link_t *link;
 
 	int rc;
@@ -397,11 +392,11 @@
 
 	fibril_mutex_lock(&cache->lock);
-	l = hash_table_find(&cache->block_hash, key);
-	if (l) {
+	ht_link_t *hlink = hash_table_find(&cache->block_hash, &ba);
+	if (hlink) {
 found:
 		/*
 		 * We found the block in the cache.
 		 */
-		b = hash_table_get_instance(l, block_t, hash_link);
+		b = hash_table_get_inst(hlink, block_t, hash_link);
 		fibril_mutex_lock(&b->lock);
 		if (b->refcnt++ == 0)
@@ -441,6 +436,6 @@
 				goto out;
 			}
-			l = list_first(&cache->free_list);
-			b = list_get_instance(l, block_t, free_link);
+			link = list_first(&cache->free_list);
+			b = list_get_instance(link, block_t, free_link);
 
 			fibril_mutex_lock(&b->lock);
@@ -479,6 +474,6 @@
 					goto retry;
 				}
-				l = hash_table_find(&cache->block_hash, key);
-				if (l) {
+				hlink = hash_table_find(&cache->block_hash, &ba);
+				if (hlink) {
 					/*
 					 * Someone else must have already
@@ -502,9 +497,5 @@
 			 */
 			list_remove(&b->free_link);
-			unsigned long temp_key[2] = {
-				LOWER32(b->lba),
-				UPPER32(b->lba)
-			};
-			hash_table_remove(&cache->block_hash, temp_key, 2);
+			hash_table_remove_item(&cache->block_hash, &b->hash_link);
 		}
 
@@ -514,5 +505,5 @@
 		b->lba = ba;
 		b->pba = ba_ltop(devcon, b->lba);
-		hash_table_insert(&cache->block_hash, key, &b->hash_link);
+		hash_table_insert(&cache->block_hash, &b->hash_link);
 
 		/*
@@ -622,9 +613,5 @@
 			 * Take the block out of the cache and free it.
 			 */
-			unsigned long key[2] = {
-				LOWER32(block->lba),
-				UPPER32(block->lba)
-			};
-			hash_table_remove(&cache->block_hash, key, 2);
+			hash_table_remove_item(&cache->block_hash, &block->hash_link);
 			fibril_mutex_unlock(&block->lock);
 			free(block->data);
Index: uspace/lib/block/block.h
===================================================================
--- uspace/lib/block/block.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/block/block.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -84,5 +84,5 @@
 	link_t free_link;
 	/** Link for placing the block into the block hash table. */ 
-	link_t hash_link;
+	ht_link_t hash_link;
 	/** Buffer with the block data. */
 	void *data;
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/c/Makefile	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -124,5 +124,4 @@
 	generic/adt/list.c \
 	generic/adt/hash_table.c \
-	generic/adt/hash_set.c \
 	generic/adt/dynamic_fifo.c \
 	generic/adt/char_map.c \
Index: pace/lib/c/generic/adt/hash_set.c
===================================================================
--- uspace/lib/c/generic/adt/hash_set.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(revision )
@@ -1,382 +1,0 @@
-/*
- * Copyright (c) 2008 Jakub Jermar
- * Copyright (c) 2011 Radim Vansa
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (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 <adt/hash_set.h>
-#include <adt/list.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <str.h>
-
-/** Create chained hash set
- *
- * @param     h         Hash set structure to be initialized.
- * @param[in] hash      Hash function
- * @param[in] equals    Equals function
- * @param[in] init_size Initial hash set size
- *
- * @return True on success
- *
- */
-int hash_set_init(hash_set_t *h, hash_set_hash hash, hash_set_equals equals,
-    size_t init_size)
-{
-	assert(h);
-	assert(hash);
-	assert(equals);
-	
-	if (init_size < HASH_SET_MIN_SIZE)
-		init_size = HASH_SET_MIN_SIZE;
-	
-	h->table = malloc(init_size * sizeof(link_t));
-	if (!h->table)
-		return false;
-	
-	for (size_t i = 0; i < init_size; i++)
-		list_initialize(&h->table[i]);
-	
-	h->size = init_size;
-	h->count = 0;
-	h->hash = hash;
-	h->equals = equals;
-	
-	return true;
-}
-
-/** Destroy a hash table instance.
- *
- * @param h Hash table to be destroyed.
- *
- */
-void hash_set_destroy(hash_set_t *h)
-{
-	assert(h);
-	free(h->table);
-}
-
-/** Rehash the internal table to new table
- *
- * @param h         Original hash set
- * @param new_table Memory for the new table
- * @param new_size  Size of the new table
- */
-static void hash_set_rehash(hash_set_t *h, list_t *new_table,
-    size_t new_size)
-{
-	assert(new_size >= HASH_SET_MIN_SIZE);
-	
-	for (size_t bucket = 0; bucket < new_size; bucket++)
-		list_initialize(&new_table[bucket]);
-	
-	for (size_t bucket = 0; bucket < h->size; bucket++) {
-		link_t *cur;
-		link_t *next;
-		
-		for (cur = h->table[bucket].head.next;
-		    cur != &h->table[bucket].head;
-		    cur = next) {
-			next = cur->next;
-			list_append(cur, &new_table[h->hash(cur) % new_size]);
-		}
-	}
-	
-	list_t *old_table = h->table;
-	h->table = new_table;
-	free(old_table);
-	h->size = new_size;
-}
-
-/** Insert item into the set.
- *
- * If the set already contains equivalent object,
- * the function fails.
- *
- * @param h    Hash table.
- * @param key  Array of all keys necessary to compute hash index.
- * @param item Item to be inserted into the hash table.
- *
- * @return True if the object was inserted
- * @return Ffalse if the set already contained equivalent object.
- *
- */
-int hash_set_insert(hash_set_t *h, link_t *item)
-{
-	assert(item);
-	assert(h);
-	assert(h->hash);
-	assert(h->equals);
-	
-	unsigned long hash = h->hash(item);
-	unsigned long chain = hash % h->size;
-	
-	list_foreach(h->table[chain], cur) {
-		if (h->equals(cur, item))
-			return false;
-	}
-	
-	if (h->count + 1 > h->size) {
-		size_t new_size = h->size * 2;
-		list_t *temp = malloc(new_size * sizeof(list_t));
-		if (temp != NULL)
-			hash_set_rehash(h, temp, new_size);
-		
-		/*
-		 * If the allocation fails, just use the same
-		 * old table and try to rehash next time.
-		 */
-		chain = hash % h->size;
-	}
-	
-	h->count++;
-	list_append(item, &h->table[chain]);
-	
-	return true;
-}
-
-/** Search the hash set for a matching object and return it
- *
- * @param h    Hash set
- * @param item The item that should equal to the matched object
- *
- * @return Matching item on success, NULL if there is no such item.
- *
- */
-link_t *hash_set_find(hash_set_t *h, const link_t *item)
-{
-	assert(h);
-	assert(h->hash);
-	assert(h->equals);
-	
-	unsigned long chain = h->hash(item) % h->size;
-	
-	list_foreach(h->table[chain], cur) {
-		if (h->equals(cur, item))
-			return cur;
-	}
-	
-	return NULL;
-}
-
-/** Remove first matching object from the hash set and return it
- *
- * @param h    Hash set.
- * @param item The item that should be equal to the matched object
- *
- * @return The removed item or NULL if this is not found.
- *
- */
-link_t *hash_set_remove(hash_set_t *h, const link_t *item)
-{
-	assert(h);
-	assert(h->hash);
-	assert(h->equals);
-	
-	link_t *cur = hash_set_find(h, item);
-	if (cur) {
-		list_remove(cur);
-		
-		h->count--;
-		if (4 * h->count < h->size && h->size > HASH_SET_MIN_SIZE) {
-			size_t new_size = h->size / 2;
-			if (new_size < HASH_SET_MIN_SIZE)
-				/* possible e.g. if init_size == HASH_SET_MIN_SIZE + 1 */
-				new_size = HASH_SET_MIN_SIZE;
-			
-			list_t *temp = malloc(new_size * sizeof (list_t));
-			if (temp != NULL)
-				hash_set_rehash(h, temp, new_size);
-		}
-	}
-	
-	return cur;
-}
-
-/** Remove all elements for which the function returned non-zero
- *
- * The function can also destroy the element.
- *
- * @param h   Hash set.
- * @param f   Function to be applied.
- * @param arg Argument to be passed to the function.
- *
- */
-void hash_set_remove_selected(hash_set_t *h, int (*f)(link_t *, void *),
-    void *arg)
-{
-	assert(h);
-	assert(h->table);
-	
-	for (size_t bucket = 0; bucket < h->size; bucket++) {
-		link_t *prev = &h->table[bucket].head;
-		link_t *cur;
-		link_t *next;
-		
-		for (cur = h->table[bucket].head.next;
-		    cur != &h->table[bucket].head;
-		    cur = next) {
-			next = cur->next;
-			if (f(cur, arg)) {
-				prev->next = next;
-				next->prev = prev;
-				h->count--;
-			} else
-				prev = cur;
-		}
-	}
-	
-	if (4 * h->count < h->size && h->size > HASH_SET_MIN_SIZE) {
-		size_t new_size = h->size / 2;
-		if (new_size < HASH_SET_MIN_SIZE)
-			/* possible e.g. if init_size == HASH_SET_MIN_SIZE + 1 */
-			new_size = HASH_SET_MIN_SIZE;
-		
-		list_t *temp = malloc(new_size * sizeof (list_t));
-		if (temp != NULL)
-			hash_set_rehash(h, temp, new_size);
-	}
-}
-
-/** Apply function to all items in hash set
- *
- * @param h   Hash set.
- * @param f   Function to be applied.
- * @param arg Argument to be passed to the function.
- *
- */
-void hash_set_apply(hash_set_t *h, void (*f)(link_t *, void *), void *arg)
-{
-	assert(h);
-	assert(h->table);
-	
-	for (size_t bucket = 0; bucket < h->size; bucket++) {
-		link_t *cur;
-		link_t *next;
-		
-		for (cur = h->table[bucket].head.next;
-		    cur != &h->table[bucket].head;
-		    cur = next) {
-			
-			/*
-			 * The next pointer must be stored prior to the functor
-			 * call to allow using destructor as the functor (the
-			 * free function could overwrite the cur->next pointer).
-			 */
-			next = cur->next;
-			f(cur, arg);
-		}
-	}
-}
-
-/** Remove all elements from the set.
- *
- * The table is reallocated to the minimum size.
- *
- * @param h   Hash set
- * @param f   Function (destructor?) applied to all element. Can be NULL.
- * @param arg Argument to the destructor.
- *
- */
-void hash_set_clear(hash_set_t *h, void (*f)(link_t *, void *), void *arg)
-{
-	assert(h);
-	assert(h->table);
-	
-	for (size_t bucket = 0; bucket < h->size; bucket++) {
-		link_t *cur;
-		link_t *next;
-		
-		for (cur = h->table[bucket].head.next;
-		    cur != &h->table[bucket].head;
-		    cur = next) {
-			next = cur->next;
-			list_remove(cur);
-			if (f != NULL)
-				f(cur, arg);
-		}
-	}
-	
-	assert(h->size >= HASH_SET_MIN_SIZE);
-	list_t *new_table =
-	    realloc(h->table, HASH_SET_MIN_SIZE * sizeof(list_t));
-	
-	/* We are shrinking, therefore we shouldn't get NULL */
-	assert(new_table);
-	
-	if (h->table != new_table) {
-		/* Init the lists, pointers to itself are used in them */
-		for (size_t bucket = 0; bucket < HASH_SET_MIN_SIZE; ++bucket)
-			list_initialize(&new_table[bucket]);
-		
-		h->table = new_table;
-	}
-	
-	h->count = 0;
-	h->size = HASH_SET_MIN_SIZE;
-}
-
-/** Get hash set size
- *
- * @param hHash set
- *
- * @return Number of elements in the set.
- *
- */
-size_t hash_set_count(const hash_set_t *h)
-{
-	assert(h);
-	return h->count;
-}
-
-/** Check whether element is contained in the hash set
- *
- * @param h    Hash set
- * @param item Item that should be equal to the matched object
- *
- * @return True if the hash set contains equal object
- * @return False otherwise
- *
- */
-int hash_set_contains(const hash_set_t *h, const link_t *item)
-{
-	/*
-	 * The hash_set_find cannot accept constant hash set,
-	 * because we can modify the returned element. But in
-	 * this case we are using it safely.
-	 */
-	return hash_set_find((hash_set_t *) h, item) != NULL;
-}
-
-/** @}
- */
Index: uspace/lib/c/generic/adt/hash_table.c
===================================================================
--- uspace/lib/c/generic/adt/hash_table.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/c/generic/adt/hash_table.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -1,4 +1,6 @@
 /*
  * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2012 Adam Hraska
+ * 
  * All rights reserved.
  *
@@ -34,5 +36,15 @@
 
 /*
- * This is an implementation of generic chained hash table.
+ * This is an implementation of a generic resizable chained hash table.
+ * 
+ * The table grows to 2*n+1 buckets each time, starting at n == 89, 
+ * per Thomas Wang's recommendation:
+ * http://www.concentric.net/~Ttwang/tech/hashsize.htm
+ * 
+ * This policy produces prime table sizes for the first five resizes
+ * and generally produces table sizes which are either prime or 
+ * have fairly large (prime/odd) divisors. Having a prime table size
+ * mitigates the use of suboptimal hash functions and distributes
+ * items over the whole table.
  */
 
@@ -44,38 +56,99 @@
 #include <str.h>
 
+/* Optimal initial bucket count. See comment above. */
+#define HT_MIN_BUCKETS  89
+/* The table is resized when the average load per bucket exceeds this number. */
+#define HT_MAX_LOAD     2
+
+
+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. */
+static void nop_remove_callback(ht_link_t *item)
+{
+	/* no-op */
+}
+
+
 /** Create chained hash table.
  *
  * @param h        Hash table structure. Will be initialized by this call.
- * @param m        Number of hash table buckets.
+ * @param init_size Initial desired number of hash table buckets. Pass zero
+ *                 if you want the default initial size. 
  * @param max_keys Maximal number of keys needed to identify an item.
- * @param op       Hash table operations structure.
+ * @param op       Hash table operations structure. remove_callback()
+ *                 is optional and can be NULL if no action is to be taken
+ *                 upon removal. equal() is optional if and only if
+ *                 hash_table_insert_unique() will never be invoked.
+ *                 All other operations are mandatory. 
  *
  * @return True on success
  *
  */
-bool hash_table_create(hash_table_t *h, hash_count_t m, hash_count_t max_keys,
-    hash_table_operations_t *op)
+bool hash_table_create(hash_table_t *h, size_t init_size, size_t max_load,
+    hash_table_ops_t *op)
 {
 	assert(h);
-	assert(op && op->hash && op->compare);
-	assert(max_keys > 0);
-	
-	h->entry = malloc(m * sizeof(list_t));
-	if (!h->entry)
+	assert(op && op->hash && op->key_hash && op->key_equal);
+	
+	/* Check for compulsory ops. */
+	if (!op || !op->hash || !op->key_hash || !op->key_equal)
 		return false;
 	
-	memset((void *) h->entry, 0,  m * sizeof(list_t));
-	
-	hash_count_t i;
-	for (i = 0; i < m; i++)
-		list_initialize(&h->entry[i]);
-	
-	h->entries = m;
-	h->max_keys = max_keys;
+	h->bucket_cnt = round_up_size(init_size);
+	
+	if (!alloc_table(h->bucket_cnt, &h->bucket))
+		return false;
+	
+	h->max_load = (max_load == 0) ? HT_MAX_LOAD : max_load;
+	h->item_cnt = 0;
 	h->op = op;
+	h->full_item_cnt = h->max_load * h->bucket_cnt;
+	h->apply_ongoing = false;
+
+	if (h->op->remove_callback == NULL) {
+		h->op->remove_callback = nop_remove_callback;
+	}
 	
 	return true;
 }
 
+/** Destroy a hash table instance.
+ *
+ * @param h Hash table to be destroyed.
+ *
+ */
+void hash_table_destroy(hash_table_t *h)
+{
+	assert(h && h->bucket);
+	assert(!h->apply_ongoing);
+	
+	clear_items(h);
+	
+	free(h->bucket);
+
+	h->bucket = 0;
+	h->bucket_cnt = 0;
+}
+
+/** Returns true if there are no items in the table. */
+bool hash_table_empty(hash_table_t *h)
+{
+	assert(h && h->bucket);
+	return h->item_cnt == 0;
+}
+
+/** Returns the number of items in the table. */
+size_t hash_table_size(hash_table_t *h)
+{
+	assert(h && h->bucket);
+	return h->item_cnt;
+}
+
 /** Remove all elements from the hash table
  *
@@ -84,29 +157,32 @@
 void hash_table_clear(hash_table_t *h)
 {
-	for (hash_count_t chain = 0; chain < h->entries; ++chain) {
-		link_t *cur;
-		link_t *next;
-		
-		for (cur = h->entry[chain].head.next;
-		    cur != &h->entry[chain].head;
-		    cur = next) {
-			next = cur->next;
+	assert(h && h->bucket);
+	assert(!h->apply_ongoing);
+	
+	clear_items(h);
+	
+	/* Shrink the table to its minimum size if possible. */
+	if (HT_MIN_BUCKETS < h->bucket_cnt) {
+		resize(h, HT_MIN_BUCKETS);
+	}
+}
+
+/** Unlinks and removes all items but does not resize. */
+static void clear_items(hash_table_t *h)
+{
+	if (h->item_cnt == 0)
+		return;
+	
+	for (size_t idx = 0; idx < h->bucket_cnt; ++idx) {
+		list_foreach_safe(h->bucket[idx], cur, next) {
+			assert(cur);
+			ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link);
+			
 			list_remove(cur);
-			h->op->remove_callback(cur);
-		}
-	}
-}
-
-/** Destroy a hash table instance.
- *
- * @param h Hash table to be destroyed.
- *
- */
-void hash_table_destroy(hash_table_t *h)
-{
-	assert(h);
-	assert(h->entry);
-	
-	free(h->entry);
+			h->op->remove_callback(cur_link);
+		}
+	}
+	
+	h->item_cnt = 0;
 }
 
@@ -117,13 +193,52 @@
  * @param item Item to be inserted into the hash table.
  */
-void hash_table_insert(hash_table_t *h, unsigned long key[], link_t *item)
+void hash_table_insert(hash_table_t *h, ht_link_t *item)
 {
 	assert(item);
-	assert(h && h->op && h->op->hash && h->op->compare);
-	
-	hash_index_t chain = h->op->hash(key);
-	assert(chain < h->entries);
-	
-	list_append(item, &h->entry[chain]);
+	assert(h && h->bucket);
+	assert(!h->apply_ongoing);
+	
+	size_t idx = h->op->hash(item) % h->bucket_cnt;
+	
+	list_append(&item->link, &h->bucket[idx]);
+	++h->item_cnt;
+	grow_if_needed(h);
+}
+
+
+/** Insert item into a hash table if not already present.
+ *
+ * @param h    Hash table.
+ * @param key  Array of all keys necessary to compute hash index.
+ * @param item Item to be inserted into the hash table.
+ * 
+ * @return False if such an item had already been inserted. 
+ * @return True if the inserted item was the only item with such a lookup key.
+ */
+bool hash_table_insert_unique(hash_table_t *h, ht_link_t *item)
+{
+	assert(item);
+	assert(h && h->bucket && h->bucket_cnt);
+	assert(h->op && h->op->hash && h->op->equal);
+	assert(!h->apply_ongoing);
+	
+	size_t idx = h->op->hash(item) % h->bucket_cnt;
+	
+	/* Check for duplicates. */
+	list_foreach(h->bucket[idx], cur) {
+		/* 
+		 * We could filter out items using their hashes first, but 
+		 * calling equal() might very well be just as fast.
+		 */
+		ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link);
+		if (h->op->equal(cur_link, item))
+			return false;
+	}
+	
+	list_append(&item->link, &h->bucket[idx]);
+	++h->item_cnt;
+	grow_if_needed(h);
+	
+	return true;
 }
 
@@ -136,20 +251,45 @@
  *
  */
-link_t *hash_table_find(hash_table_t *h, unsigned long key[])
-{
-	assert(h && h->op && h->op->hash && h->op->compare);
-	
-	hash_index_t chain = h->op->hash(key);
-	assert(chain < h->entries);
-	
-	list_foreach(h->entry[chain], cur) {
-		if (h->op->compare(key, h->max_keys, cur)) {
-			/*
-			 * The entry is there.
-			 */
-			return cur;
-		}
-	}
-	
+ht_link_t *hash_table_find(const hash_table_t *h, void *key)
+{
+	assert(h && h->bucket);
+	
+	size_t idx = h->op->key_hash(key) % h->bucket_cnt;
+
+	list_foreach(h->bucket[idx], cur) {
+		ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link);
+		/* 
+		 * Is this is the item we are looking for? We could have first 
+		 * checked if the hashes match but op->key_equal() may very well be 
+		 * just as fast as op->hash().
+		 */
+		if (h->op->key_equal(key, cur_link)) {
+			return cur_link;
+		}
+	}
+	
+	return NULL;
+}
+
+/** Find the next item equal to item. */
+ht_link_t *hash_table_find_next(const hash_table_t *h, ht_link_t *item)
+{
+	assert(item);
+	assert(h && h->bucket);
+
+	/* Traverse the circular list until we reach the starting item again. */
+	for (link_t *cur = item->link.next; cur != &item->link; cur = cur->next) {
+		assert(cur);
+		ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link);
+		/* 
+		 * Is this is the item we are looking for? We could have first 
+		 * checked if the hashes match but op->equal() may very well be 
+		 * just as fast as op->hash().
+		 */
+		if (h->op->equal(cur_link, item)) {
+			return cur_link;
+		}
+	}
+
 	return NULL;
 }
@@ -163,76 +303,170 @@
  *             the hash table.
  * @param keys Number of keys in the 'key' array.
- *
- */
-void hash_table_remove(hash_table_t *h, unsigned long key[], hash_count_t keys)
-{
-	assert(h && h->op && h->op->hash && h->op->compare &&
-	    h->op->remove_callback);
-	assert(keys <= h->max_keys);
-	
-	if (keys == h->max_keys) {
-		/*
-		 * All keys are known, hash_table_find() can be used to find the
-		 * entry.
+ * 
+ * @return Returns the number of removed items.
+ */
+size_t hash_table_remove(hash_table_t *h, void *key)
+{
+	assert(h && h->bucket);
+	assert(!h->apply_ongoing);
+	
+	size_t idx = h->op->key_hash(key) % h->bucket_cnt;
+
+	size_t removed = 0;
+	
+	list_foreach_safe(h->bucket[idx], cur, next) {
+		ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link);
+		
+		if (h->op->key_equal(key, cur_link)) {
+			++removed;
+			list_remove(cur);
+			h->op->remove_callback(cur_link);
+		}
+	}
+
+	h->item_cnt -= removed;
+	shrink_if_needed(h);
+	
+	return removed;
+}
+
+/** Removes an item already present in the table. The item must be in the table.*/
+void hash_table_remove_item(hash_table_t *h, ht_link_t *item)
+{
+	assert(item);
+	assert(h && h->bucket);
+	assert(link_in_use(&item->link));
+
+	list_remove(&item->link);
+	--h->item_cnt;
+	h->op->remove_callback(item);
+	shrink_if_needed(h);
+}
+
+/** Apply function to all items in hash table.
+ *
+ * @param h   Hash table.
+ * @param f   Function to be applied. Return false if no more items 
+ *            should be visited. The functor may only delete the supplied
+ *            item. It must not delete the successor of the item passed 
+ *            in the first argument.
+ * @param arg Argument to be passed to the function.
+ */
+void hash_table_apply(hash_table_t *h, bool (*f)(ht_link_t *, void *), void *arg)
+{	
+	assert(f);
+	assert(h && h->bucket);
+	
+	if (h->item_cnt == 0)
+		return;
+	
+	h->apply_ongoing = true;
+	
+	for (size_t idx = 0; idx < h->bucket_cnt; ++idx) {
+		list_foreach_safe(h->bucket[idx], cur, next) {
+			ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link);
+			/* 
+			 * The next pointer had already been saved. f() may safely 
+			 * delete cur (but not next!).
+			 */
+			if (!f(cur_link, arg))
+				return;
+		}
+	}
+	
+	h->apply_ongoing = false;
+	
+	shrink_if_needed(h);
+	grow_if_needed(h);
+}
+
+/** Rounds up size to the nearest suitable table size. */
+static size_t round_up_size(size_t size)
+{
+	size_t rounded_size = HT_MIN_BUCKETS;
+	
+	while (rounded_size < size) {
+		rounded_size = 2 * rounded_size + 1;
+	}
+	
+	return rounded_size;
+}
+
+/** Allocates and initializes the desired number of buckets. True if successful.*/
+static bool alloc_table(size_t bucket_cnt, list_t **pbuckets)
+{
+	assert(pbuckets && HT_MIN_BUCKETS <= bucket_cnt);
+		
+	list_t *buckets = malloc(bucket_cnt * sizeof(list_t));
+	if (!buckets)
+		return false;
+	
+	for (size_t i = 0; i < bucket_cnt; i++)
+		list_initialize(&buckets[i]);
+
+	*pbuckets = buckets;
+	return true;
+}
+
+
+/** Shrinks the table if the table is only sparely populated. */
+static inline void shrink_if_needed(hash_table_t *h)
+{
+	if (h->item_cnt <= h->full_item_cnt / 4 && HT_MIN_BUCKETS < h->bucket_cnt) {
+		/* 
+		 * Keep the bucket_cnt odd (possibly also prime). 
+		 * Shrink from 2n + 1 to n. Integer division discards the +1.
 		 */
-		
-		link_t *cur = hash_table_find(h, key);
-		if (cur) {
-			list_remove(cur);
-			h->op->remove_callback(cur);
-		}
-		
+		size_t new_bucket_cnt = h->bucket_cnt / 2;
+		resize(h, new_bucket_cnt);
+	}
+}
+
+/** Grows the table if table load exceeds the maximum allowed. */
+static inline void grow_if_needed(hash_table_t *h)
+{
+	/* Grow the table if the average bucket load exceeds the maximum. */
+	if (h->full_item_cnt < h->item_cnt) {
+		/* Keep the bucket_cnt odd (possibly also prime). */
+		size_t new_bucket_cnt = 2 * h->bucket_cnt + 1;
+		resize(h, new_bucket_cnt);
+	}
+}
+
+/** Allocates and rehashes items to a new table. Frees the old table. */
+static void resize(hash_table_t *h, size_t new_bucket_cnt) 
+{
+	assert(h && h->bucket);
+	assert(HT_MIN_BUCKETS <= new_bucket_cnt);
+	
+	/* We are traversing the table and resizing would mess up the buckets. */
+	if (h->apply_ongoing)
 		return;
-	}
-	
-	/*
-	 * Fewer keys were passed.
-	 * Any partially matching entries are to be removed.
-	 */
-	hash_index_t chain;
-	for (chain = 0; chain < h->entries; chain++) {
-		for (link_t *cur = h->entry[chain].head.next;
-		    cur != &h->entry[chain].head;
-		    cur = cur->next) {
-			if (h->op->compare(key, keys, cur)) {
-				link_t *hlp;
-				
-				hlp = cur;
-				cur = cur->prev;
-				
-				list_remove(hlp);
-				h->op->remove_callback(hlp);
-				
-				continue;
+	
+	list_t *new_buckets;
+
+	/* Leave the table as is if we cannot resize. */
+	if (!alloc_table(new_bucket_cnt, &new_buckets))
+		return;
+	
+	if (0 < h->item_cnt) {
+		/* Rehash all the items to the new table. */
+		for (size_t old_idx = 0; old_idx < h->bucket_cnt; ++old_idx) {
+			list_foreach_safe(h->bucket[old_idx], cur, next) {
+				ht_link_t *cur_link = member_to_inst(cur, ht_link_t, link);
+
+				size_t new_idx = h->op->hash(cur_link) % new_bucket_cnt;
+				list_remove(cur);
+				list_append(cur, &new_buckets[new_idx]);
 			}
 		}
 	}
-}
-
-/** Apply function to all items in hash table.
- *
- * @param h   Hash table.
- * @param f   Function to be applied.
- * @param arg Argument to be passed to the function.
- *
- */
-void hash_table_apply(hash_table_t *h, void (*f)(link_t *, void *), void *arg)
-{	
-	for (hash_index_t bucket = 0; bucket < h->entries; bucket++) {
-		link_t *cur;
-		link_t *next;
-
-		for (cur = h->entry[bucket].head.next; cur != &h->entry[bucket].head;
-		    cur = next) {
-			/*
-			 * The next pointer must be stored prior to the functor
-			 * call to allow using destructor as the functor (the
-			 * free function could overwrite the cur->next pointer).
-			 */
-			next = cur->next;
-			f(cur, arg);
-		}
-	}
-}
+	
+	free(h->bucket);
+	h->bucket = new_buckets;
+	h->bucket_cnt = new_bucket_cnt;
+	h->full_item_cnt = h->max_load * h->bucket_cnt;
+}
+
 
 /** @}
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/c/generic/async.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -116,6 +116,4 @@
 #include "private/libc.h"
 
-#define CLIENT_HASH_TABLE_BUCKETS  32
-#define CONN_HASH_TABLE_BUCKETS    32
 
 /** Session data */
@@ -205,5 +203,5 @@
 /* Client connection data */
 typedef struct {
-	link_t link;
+	ht_link_t link;
 	
 	task_id_t in_task_id;
@@ -217,5 +215,5 @@
 	
 	/** Hash table link. */
-	link_t link;
+	ht_link_t link;
 	
 	/** Incoming client task ID. */
@@ -393,31 +391,31 @@
 static LIST_INITIALIZE(timeout_list);
 
-static hash_index_t client_hash(unsigned long key[])
-{
-	assert(key);
-	
-	return (((key[0]) >> 4) % CLIENT_HASH_TABLE_BUCKETS);
-}
-
-static int client_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	assert(key);
-	assert(keys == 2);
-	assert(item);
-	
-	client_t *client = hash_table_get_instance(item, client_t, link);
-	return (key[0] == LOWER32(client->in_task_id) &&
-	    (key[1] == UPPER32(client->in_task_id)));
-}
-
-static void client_remove(link_t *item)
-{
-}
+static size_t client_key_hash(void *k)
+{
+	task_id_t key = *(task_id_t*)k;
+	return key;
+}
+
+static size_t client_hash(const ht_link_t *item)
+{
+	client_t *client = hash_table_get_inst(item, client_t, link);
+	return client_key_hash(&client->in_task_id);
+}
+
+static bool client_key_equal(void *k, const ht_link_t *item)
+{
+	task_id_t key = *(task_id_t*)k;
+	client_t *client = hash_table_get_inst(item, client_t, link);
+	return key == client->in_task_id;
+}
+
 
 /** Operations for the client hash table. */
-static hash_table_operations_t client_hash_table_ops = {
+static hash_table_ops_t client_hash_table_ops = {
 	.hash = client_hash,
-	.compare = client_compare,
-	.remove_callback = client_remove
+	.key_hash = client_key_hash,
+	.key_equal = client_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -429,38 +427,31 @@
  *
  */
-static hash_index_t conn_hash(unsigned long key[])
-{
-	assert(key);
-	
-	return (((key[0]) >> 4) % CONN_HASH_TABLE_BUCKETS);
-}
-
-/** Compare hash table item with a key.
- *
- * @param key  Array containing the source phone hash as the only item.
- * @param keys Expected 1 but ignored.
- * @param item Connection hash table item.
- *
- * @return True on match, false otherwise.
- *
- */
-static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	assert(key);
-	assert(item);
-	
-	connection_t *conn = hash_table_get_instance(item, connection_t, link);
-	return (key[0] == conn->in_phone_hash);
-}
-
-static void conn_remove(link_t *item)
-{
-}
+static size_t conn_key_hash(void *key)
+{
+	sysarg_t in_phone_hash  = *(sysarg_t*)key;
+	return in_phone_hash ;
+}
+
+static size_t conn_hash(const ht_link_t *item)
+{
+	connection_t *conn = hash_table_get_inst(item, connection_t, link);
+	return conn_key_hash(&conn->in_phone_hash);
+}
+
+static bool conn_key_equal(void *key, const ht_link_t *item)
+{
+	sysarg_t in_phone_hash = *(sysarg_t*)key;
+	connection_t *conn = hash_table_get_inst(item, connection_t, link);
+	return (in_phone_hash == conn->in_phone_hash);
+}
+
 
 /** Operations for the connection hash table. */
-static hash_table_operations_t conn_hash_table_ops = {
+static hash_table_ops_t conn_hash_table_ops = {
 	.hash = conn_hash,
-	.compare = conn_compare,
-	.remove_callback = conn_remove
+	.key_hash = conn_key_hash,
+	.key_equal = conn_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -510,6 +501,5 @@
 	futex_down(&async_futex);
 	
-	unsigned long key = call->in_phone_hash;
-	link_t *hlp = hash_table_find(&conn_hash_table, &key);
+	ht_link_t *hlp = hash_table_find(&conn_hash_table, &call->in_phone_hash);
 	
 	if (!hlp) {
@@ -518,5 +508,5 @@
 	}
 	
-	connection_t *conn = hash_table_get_instance(hlp, connection_t, link);
+	connection_t *conn = hash_table_get_inst(hlp, connection_t, link);
 	
 	msg_t *msg = malloc(sizeof(*msg));
@@ -698,14 +688,10 @@
 static client_t *async_client_get(task_id_t client_id, bool create)
 {
-	unsigned long key[2] = {
-		LOWER32(client_id),
-		UPPER32(client_id),
-	};
 	client_t *client = NULL;
 
 	futex_down(&async_futex);
-	link_t *lnk = hash_table_find(&client_hash_table, key);
+	ht_link_t *lnk = hash_table_find(&client_hash_table, &client_id);
 	if (lnk) {
-		client = hash_table_get_instance(lnk, client_t, link);
+		client = hash_table_get_inst(lnk, client_t, link);
 		atomic_inc(&client->refcnt);
 	} else if (create) {
@@ -716,5 +702,5 @@
 		
 			atomic_set(&client->refcnt, 1);
-			hash_table_insert(&client_hash_table, key, &client->link);
+			hash_table_insert(&client_hash_table, &client->link);
 		}
 	}
@@ -727,13 +713,9 @@
 {
 	bool destroy;
-	unsigned long key[2] = {
-		LOWER32(client->in_task_id),
-		UPPER32(client->in_task_id)
-	};
-	
+
 	futex_down(&async_futex);
 	
 	if (atomic_predec(&client->refcnt) == 0) {
-		hash_table_remove(&client_hash_table, key, 2);
+		hash_table_remove(&client_hash_table, &client->in_task_id);
 		destroy = true;
 	} else
@@ -831,6 +813,5 @@
 	 */
 	futex_down(&async_futex);
-	unsigned long key = fibril_connection->in_phone_hash;
-	hash_table_remove(&conn_hash_table, &key, 1);
+	hash_table_remove(&conn_hash_table, &fibril_connection->in_phone_hash);
 	futex_up(&async_futex);
 	
@@ -916,8 +897,7 @@
 	
 	/* Add connection to the connection hash table */
-	unsigned long key = conn->in_phone_hash;
 	
 	futex_down(&async_futex);
-	hash_table_insert(&conn_hash_table, &key, &conn->link);
+	hash_table_insert(&conn_hash_table, &conn->link);
 	futex_up(&async_futex);
 	
@@ -1111,10 +1091,8 @@
 void __async_init(void)
 {
-	if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS,
-	    2, &client_hash_table_ops))
+	if (!hash_table_create(&client_hash_table, 0, 0, &client_hash_table_ops))
 		abort();
 	
-	if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS,
-	    1, &conn_hash_table_ops))
+	if (!hash_table_create(&conn_hash_table, 0, 0, &conn_hash_table_ops))
 		abort();
 	
Index: uspace/lib/c/include/adt/hash.h
===================================================================
--- uspace/lib/c/include/adt/hash.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/c/include/adt/hash.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/** @addtogroup genericadt
+ * @{
+ */
+/** @file
+ */
+#ifndef KERN_HASH_H_
+#define KERN_HASH_H_
+
+#include <stdint.h>
+
+/** Produces a uniform hash affecting all output bits from the skewed input. */
+static inline uint32_t hash_mix32(uint32_t hash)
+{
+	/*
+	 * Thomas Wang's modification of Bob Jenkin's hash mixing function:
+	 * http://www.concentric.net/~Ttwang/tech/inthash.htm
+	 * Public domain.
+	 */
+	hash = ~hash + (hash << 15); 
+	hash = hash ^ (hash >> 12);
+	hash = hash + (hash << 2);
+	hash = hash ^ (hash >> 4);
+	hash = hash * 2057; 
+	hash = hash ^ (hash >> 16);
+	return hash;	
+}
+
+/** Produces a uniform hash affecting all output bits from the skewed input. */
+static inline uint64_t hash_mix64(uint64_t hash)
+{
+	/*
+	 * Thomas Wang's public domain 64-bit hash mixing function:
+	 * http://www.concentric.net/~Ttwang/tech/inthash.htm
+	 */
+	hash = (hash ^ 61) ^ (hash >> 16);
+	hash = hash + (hash << 3);
+	hash = hash ^ (hash >> 4);
+	hash = hash * 0x27d4eb2d;
+	hash = hash ^ (hash >> 15);	
+	/* 
+	 * Lower order bits are mixed more thoroughly. Swap them with
+	 * the higher order bits and make the resulting higher order bits
+	 * more usable.
+	 */
+	return (hash << 32) | (hash >> 32);
+}
+
+/** Produces a uniform hash affecting all output bits from the skewed input. */
+static inline size_t hash_mix(size_t hash) 
+{
+#ifdef __32_BITS__
+	return hash_mix32(hash);
+#elif defined(__64_BITS__)
+	return hash_mix64(hash);
+#else
+#error Unknown size_t size - cannot select proper hash mix function.
+#endif
+}
+
+/** Use to create a hash from multiple values.
+ * 
+ * Typical usage:
+ * @code
+ * int car_id;
+ * bool car_convertible;
+ * // ..
+ * size_t hash = 0;
+ * hash = hash_combine(hash, car_id);
+ * hash = hash_combine(hash, car_convertible);
+ * // Now use hash as a hash of both car_id and car_convertible.
+ * @endcode
+ */
+static inline size_t hash_combine(size_t seed, size_t hash)
+{
+	/* 
+	 * todo: use Bob Jenkin's proper mixing hash pass:
+	 * http://burtleburtle.net/bob/c/lookup3.c
+	 */
+	seed ^= hash + 0x9e3779b9 
+		+ ((seed << 5) | (seed >> (sizeof(size_t) * 8 - 5)));
+	return seed;	
+}
+
+#endif
Index: pace/lib/c/include/adt/hash_set.h
===================================================================
--- uspace/lib/c/include/adt/hash_set.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(revision )
@@ -1,84 +1,0 @@
-/*
- * Copyright (c) 2006 Jakub Jermar
- * Copyright (c) 2011 Radim Vansa
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (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_HASH_SET_H_
-#define LIBC_HASH_SET_H_
-
-#include <adt/list.h>
-#include <unistd.h>
-
-#define HASH_SET_MIN_SIZE  8
-
-typedef unsigned long (*hash_set_hash)(const link_t *);
-typedef int (*hash_set_equals)(const link_t *, const link_t *);
-
-/** Hash table structure. */
-typedef struct {
-	list_t *table;
-	
-	/** Current table size */
-	size_t size;
-	
-	/**
-	 * Current number of entries. If count > size,
-	 * the table is rehashed into table with double
-	 * size. If (4 * count < size) && (size > min_size),
-	 * the table is rehashed into table with half the size.
-	 */
-	size_t count;
-	
-	/** Hash function */
-	hash_set_hash hash;
-	
-	/** Hash table item equals function */
-	hash_set_equals equals;
-} hash_set_t;
-
-extern int hash_set_init(hash_set_t *, hash_set_hash, hash_set_equals, size_t);
-extern int hash_set_insert(hash_set_t *, link_t *);
-extern link_t *hash_set_find(hash_set_t *, const link_t *);
-extern int hash_set_contains(const hash_set_t *, const link_t *);
-extern size_t hash_set_count(const hash_set_t *);
-extern link_t *hash_set_remove(hash_set_t *, const link_t *);
-extern void hash_set_remove_selected(hash_set_t *,
-    int (*)(link_t *, void *), void *);
-extern void hash_set_destroy(hash_set_t *);
-extern void hash_set_apply(hash_set_t *, void (*)(link_t *, void *), void *);
-extern void hash_set_clear(hash_set_t *, void (*)(link_t *, void *), void *);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/include/adt/hash_table.h
===================================================================
--- uspace/lib/c/include/adt/hash_table.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/c/include/adt/hash_table.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -1,4 +1,6 @@
 /*
  * Copyright (c) 2006 Jakub Jermar
+ * Copyright (c) 2012 Adam Hraska
+ * 
  * All rights reserved.
  *
@@ -39,58 +41,65 @@
 #include <unistd.h>
 #include <bool.h>
+#include <macros.h>
 
-typedef unsigned long hash_count_t;
-typedef unsigned long hash_index_t;
+/** Opaque hash table link type. */
+typedef struct ht_link {
+	link_t link;
+} ht_link_t;
 
 /** Set of operations for hash table. */
 typedef struct {
-	/** Hash function.
-	 *
-	 * @param key Array of keys needed to compute hash index.
-	 *            All keys must be passed.
-	 *
-	 * @return Index into hash table.
-	 *
-	 */
-	hash_index_t (*hash)(unsigned long key[]);
+	/** Returns the hash of the key stored in the item (ie its lookup key). */
+	size_t (*hash)(const ht_link_t *item);
 	
-	/** Hash table item comparison function.
-	 *
-	 * @param key Array of keys that will be compared with item. It is
-	 *            not necessary to pass all keys.
-	 *
-	 * @return True if the keys match, false otherwise.
-	 *
-	 */
-	int (*compare)(unsigned long key[], hash_count_t keys, link_t *item);
+	/** Returns the hash of the key. */
+	size_t (*key_hash)(void *key);
 	
+	/** True if the items are equal (have the same lookup keys). */
+	bool (*equal)(const ht_link_t *item1, const ht_link_t *item2);
+
+	/** Returns true if the key is equal to the item's lookup key. */
+	bool (*key_equal)(void *key, const ht_link_t *item);
+
 	/** Hash table item removal callback.
+	 * 
+	 * Must not invoke any mutating functions of the hash table.
 	 *
 	 * @param item Item that was removed from the hash table.
-	 *
 	 */
-	void (*remove_callback)(link_t *item);
-} hash_table_operations_t;
+	void (*remove_callback)(ht_link_t *item);
+} hash_table_ops_t;
 
 /** Hash table structure. */
 typedef struct {
-	list_t *entry;
-	hash_count_t entries;
-	hash_count_t max_keys;
-	hash_table_operations_t *op;
+	hash_table_ops_t *op;
+	list_t *bucket;
+	size_t bucket_cnt;
+	size_t full_item_cnt;
+	size_t item_cnt;
+	size_t max_load;
+	bool apply_ongoing;
 } hash_table_t;
 
-#define hash_table_get_instance(item, type, member) \
-    list_get_instance((item), type, member)
+#define hash_table_get_inst(item, type, member) \
+	member_to_inst((item), type, member)
 
-extern bool hash_table_create(hash_table_t *, hash_count_t, hash_count_t,
-    hash_table_operations_t *);
+extern bool hash_table_create(hash_table_t *, size_t, size_t, 
+	hash_table_ops_t *);
+extern void hash_table_destroy(hash_table_t *);
+
+extern bool hash_table_empty(hash_table_t *);
+extern size_t hash_table_size(hash_table_t *);
+
 extern void hash_table_clear(hash_table_t *);
-extern void hash_table_insert(hash_table_t *, unsigned long [], link_t *);
-extern link_t *hash_table_find(hash_table_t *, unsigned long []);
-extern void hash_table_remove(hash_table_t *, unsigned long [], hash_count_t);
-extern void hash_table_destroy(hash_table_t *);
-extern void hash_table_apply(hash_table_t *, void (*)(link_t *, void *),
-    void *);
+extern void hash_table_insert(hash_table_t *, ht_link_t *);
+extern bool hash_table_insert_unique(hash_table_t *, ht_link_t *);
+extern ht_link_t *hash_table_find(const hash_table_t *, void *);
+extern ht_link_t *hash_table_find_next(const hash_table_t *, ht_link_t *);
+extern size_t hash_table_remove(hash_table_t *, void *);
+extern void hash_table_remove_item(hash_table_t *, ht_link_t *);
+extern void hash_table_apply(hash_table_t *, bool (*)(ht_link_t *, void *), 
+	void *);
+
 
 #endif
Index: uspace/lib/c/include/adt/list.h
===================================================================
--- uspace/lib/c/include/adt/list.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/c/include/adt/list.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -71,6 +71,43 @@
 	    iterator != &(list).head; iterator = iterator->next)
 
+/** Unlike list_foreach(), allows removing items while traversing a list.
+ * 
+ * @code
+ * list_t mylist;
+ * typedef struct item {
+ *     int value;
+ *     link_t item_link;
+ * } item_t;
+ * 
+ * //..
+ * 
+ * // Print each list element's value and remove the element from the list.
+ * list_foreach_safe(mylist, cur_link, next_link) {
+ *     item_t *cur_item = list_get_instance(cur_link, item_t, item_link);
+ *     printf("%d\n", cur_item->value);
+ *     list_remove(cur_link);
+ * }
+ * @endcode
+ * 
+ * @param list List to traverse.
+ * @param iterator Iterator to the current element of the list.
+ *             The item this iterator points may be safely removed
+ *             from the list.
+ * @param next_iter Iterator to the next element of the list.
+ */
+#define list_foreach_safe(list, iterator, next_iter) \
+	for (link_t *iterator = (list).head.next, \
+		*next_iter = iterator->next; \
+		iterator != &(list).head; \
+		iterator = next_iter, next_iter = iterator->next)
+
 #define assert_link_not_used(link) \
 	assert(((link)->prev == NULL) && ((link)->next == NULL))
+
+/** Returns true if the link is definitely part of a list. False if not sure. */
+static inline int link_in_use(link_t *link)
+{
+	return link->prev != NULL && link->next != NULL;
+}
 
 /** Initialize doubly-linked circular list link
Index: uspace/lib/c/include/macros.h
===================================================================
--- uspace/lib/c/include/macros.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/c/include/macros.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -52,4 +52,10 @@
 	    | ((((uint64_t) (up)) & 0xffffffff) << 32))
 
+#ifndef member_to_inst
+#define member_to_inst(ptr_member, type, member_identif) \
+	((type*) (((void*)(ptr_member)) - ((void*)&(((type*)0)->member_identif))))
+#endif
+
+
 #endif
 
Index: uspace/lib/ext4/libext4_crc.c
===================================================================
--- uspace/lib/ext4/libext4_crc.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/ext4/libext4_crc.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/ext4/libext4_filesystem.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -471,6 +471,4 @@
 
 /** Compute checksum of block group descriptor.
- *
- * It uses crc functions from Linux kernel implementation.
  *
  * @param sb   Superblock
Index: uspace/lib/ext4/libext4_hash.c
===================================================================
--- uspace/lib/ext4/libext4_hash.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/ext4/libext4_hash.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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/nic/include/nic.h
===================================================================
--- uspace/lib/nic/include/nic.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/nic/include/nic.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -40,4 +40,5 @@
 
 #include <adt/list.h>
+#include <adt/hash_table.h>
 #include <ddf/driver.h>
 #include <device/hw_res_parsed.h>
@@ -53,5 +54,5 @@
  */
 typedef struct nic_wol_virtue {
-	link_t item;
+	ht_link_t item;
 	nic_wv_id_t id;
 	nic_wv_type_t type;
Index: uspace/lib/nic/include/nic_addr_db.h
===================================================================
--- uspace/lib/nic/include/nic_addr_db.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/nic/include/nic_addr_db.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -43,14 +43,5 @@
 #endif
 
-#include <adt/hash_set.h>
-
-/**
- * Initial size of DB's hash set
- */
-#define NIC_ADDR_DB_INIT_SIZE 	8
-/**
- * Maximal length of addresses in the DB (in bytes).
- */
-#define NIC_ADDR_MAX_LENGTH		16
+#include <adt/hash_table.h>
 
 /**
@@ -58,25 +49,14 @@
  */
 typedef struct nic_addr_db {
-	hash_set_t set;
+	hash_table_t set;
 	size_t addr_len;
 } nic_addr_db_t;
 
-/**
- * Helper structure for keeping the address in the hash set.
- */
-typedef struct nic_addr_entry {
-	link_t item;
-	size_t addr_len;
-	uint8_t addr[NIC_ADDR_MAX_LENGTH];
-} nic_addr_entry_t;
 
 extern int nic_addr_db_init(nic_addr_db_t *db, size_t addr_len);
 extern void nic_addr_db_clear(nic_addr_db_t *db);
 extern void nic_addr_db_destroy(nic_addr_db_t *db);
-extern size_t nic_addr_db_count(const nic_addr_db_t *db);
 extern int nic_addr_db_insert(nic_addr_db_t *db, const uint8_t *addr);
 extern int nic_addr_db_remove(nic_addr_db_t *db, const uint8_t *addr);
-extern void nic_addr_db_remove_selected(nic_addr_db_t *db,
-	int (*func)(const uint8_t *, void *), void *arg);
 extern int nic_addr_db_contains(const nic_addr_db_t *db, const uint8_t *addr);
 extern void nic_addr_db_foreach(const nic_addr_db_t *db,
Index: uspace/lib/nic/include/nic_wol_virtues.h
===================================================================
--- uspace/lib/nic/include/nic_wol_virtues.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/nic/include/nic_wol_virtues.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -51,5 +51,5 @@
 	 * Operations for table
 	 */
-	hash_table_operations_t table_operations;
+	hash_table_ops_t table_operations;
 	/**
 	 * WOL virtues hashed by their ID's.
Index: uspace/lib/nic/src/nic_addr_db.c
===================================================================
--- uspace/lib/nic/src/nic_addr_db.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/nic/src/nic_addr_db.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -35,4 +35,6 @@
  * @brief Generic hash-set based database of addresses
  */
+#include "nic_addr_db.h"
+#include "libarch/common.h"
 #include <assert.h>
 #include <stdlib.h>
@@ -40,49 +42,72 @@
 #include <errno.h>
 #include <mem.h>
-
-#include "nic_addr_db.h"
-
-/**
- * Hash set helper function
- */
-static int nic_addr_equals(const link_t *item1, const link_t *item2)
-{
-	assert(item1 && item2);
-	size_t addr_len = ((const nic_addr_entry_t *) item1)->addr_len;
-
-	assert(addr_len	== ((const nic_addr_entry_t *) item2)->addr_len);
-
-	size_t i;
-	for (i = 0; i < addr_len; ++i) {
-		if (((nic_addr_entry_t *) item1)->addr[i] !=
-			((nic_addr_entry_t *) item2)->addr[i])
-			return false;
+#include <adt/hash_table.h>
+#include <macros.h>
+#include <stdint.h>
+
+
+/**
+ * Helper structure for keeping the address in the hash set.
+ */
+typedef struct nic_addr_entry {
+	ht_link_t link;
+	uint8_t len;
+	uint8_t addr[1];
+} nic_addr_entry_t;
+
+
+/* 
+ * Hash table helper functions 
+ */
+typedef struct {
+	size_t len;
+	const uint8_t *addr;
+} addr_key_t;
+
+static bool nic_addr_key_equal(void *key_arg, const ht_link_t *item)
+{
+	addr_key_t *key = (addr_key_t*)key_arg;
+	nic_addr_entry_t *entry = member_to_inst(item, nic_addr_entry_t, link);
+	
+	return 0 == bcmp(entry->addr, key->addr, entry->len);
+}
+
+static size_t addr_hash(size_t len, const uint8_t *addr)
+{
+	size_t hash = 0;
+	
+	for (size_t i = 0; i < len; ++i) {
+		hash = (hash << 5) ^ addr[i];
 	}
-	return true;
-}
-
-/**
- * Hash set helper function
- */
-static unsigned long nic_addr_hash(const link_t *item)
-{
-	assert(item);
-	const nic_addr_entry_t *entry = (const nic_addr_entry_t *) item;
-	unsigned long hash = 0;
-
-	size_t i;
-	for (i = 0; i < entry->addr_len; ++i) {
-		hash = (hash << 8) ^ (hash >> 24) ^ entry->addr[i];
-	}
+	
 	return hash;
 }
 
-/**
- * Helper wrapper
- */
-static void nic_addr_destroy(link_t *item, void *unused)
-{
-	free(item);
-}
+static size_t nic_addr_key_hash(void *k)
+{
+	addr_key_t *key = (addr_key_t*)k;
+	return addr_hash(key->len, key->addr);
+}
+
+static size_t nic_addr_hash(const ht_link_t *item)
+{
+	nic_addr_entry_t *entry = member_to_inst(item, nic_addr_entry_t, link);
+	return addr_hash(entry->len, entry->addr);
+}
+
+static void nic_addr_removed(ht_link_t *item)
+{
+	nic_addr_entry_t *entry = member_to_inst(item, nic_addr_entry_t, link);
+	
+	free(entry);
+}
+
+static hash_table_ops_t set_ops = {
+	.hash = nic_addr_hash,
+	.key_hash = nic_addr_key_hash,
+	.key_equal = nic_addr_key_equal,
+	.equal = NULL,
+	.remove_callback = nic_addr_removed
+};
 
 /**
@@ -99,11 +124,11 @@
 {
 	assert(db);
-	if (addr_len > NIC_ADDR_MAX_LENGTH) {
+	
+	if (addr_len > UCHAR_MAX)
 		return EINVAL;
-	}
-	if (!hash_set_init(&db->set, nic_addr_hash, nic_addr_equals,
-		NIC_ADDR_DB_INIT_SIZE)) {
+	
+	if (!hash_table_create(&db->set, 0, 0, &set_ops))
 		return ENOMEM;
-	}
+	
 	db->addr_len = addr_len;
 	return EOK;
@@ -118,5 +143,5 @@
 {
 	assert(db);
-	hash_set_clear(&db->set, nic_addr_destroy, NULL);
+	hash_table_clear(&db->set);
 }
 
@@ -129,20 +154,7 @@
 {
 	assert(db);
-	hash_set_apply(&db->set, nic_addr_destroy, NULL);
-	hash_set_destroy(&db->set);
-}
-
-/**
- * Get number of addresses in the db
- *
- * @param	db
- *
- * @return Number of adresses
- */
-size_t nic_addr_db_count(const nic_addr_db_t *db)
-{
-	assert(db);
-	return hash_set_count(&db->set);
-}
+	hash_table_destroy(&db->set);
+}
+
 
 /**
@@ -160,12 +172,22 @@
 {
 	assert(db && addr);
-	nic_addr_entry_t *entry = malloc(sizeof (nic_addr_entry_t));
-	if (entry == NULL) {
+
+	addr_key_t key = {
+		.len = db->addr_len,
+		.addr = addr
+	};
+	
+	if (hash_table_find(&db->set, &key))
+		return EEXIST;
+	
+	nic_addr_entry_t *entry = malloc(sizeof(nic_addr_entry_t) + db->addr_len - 1);
+	if (entry == NULL) 
 		return ENOMEM;
-	}
-	entry->addr_len = db->addr_len;
+
+	entry->len = (uint8_t) db->addr_len;
 	memcpy(entry->addr, addr, db->addr_len);
-
-	return hash_set_insert(&db->set, &entry->item) ? EOK : EEXIST;
+	
+	hash_table_insert(&db->set, &entry->link);
+	return EOK;
 }
 
@@ -182,11 +204,14 @@
 {
 	assert(db && addr);
-	nic_addr_entry_t entry;
-	entry.addr_len = db->addr_len;
-	memcpy(entry.addr, addr, db->addr_len);
-
-	link_t *removed = hash_set_remove(&db->set, &entry.item);
-	free(removed);
-	return removed != NULL ? EOK : ENOENT;
+	
+	addr_key_t key = {
+		.len = db->addr_len,
+		.addr = addr
+	};
+	
+	if (hash_table_remove(&db->set, &key))
+		return EOK;
+	else
+		return ENOENT;
 }
 
@@ -202,9 +227,11 @@
 {
 	assert(db && addr);
-	nic_addr_entry_t entry;
-	entry.addr_len = db->addr_len;
-	memcpy(entry.addr, addr, db->addr_len);
-
-	return hash_set_contains(&db->set, &entry.item);
+	
+	addr_key_t key = {
+		.len = db->addr_len,
+		.addr = addr
+	};
+	
+	return 0 != hash_table_find(&db->set, &key);
 }
 
@@ -220,7 +247,10 @@
  * Helper function for nic_addr_db_foreach
  */
-static void nic_addr_db_fe_helper(link_t *item, void *arg) {
+static bool nic_addr_db_fe_helper(ht_link_t *item, void *arg) 
+{
 	nic_addr_db_fe_arg_t *hs = (nic_addr_db_fe_arg_t *) arg;
-	hs->func(((nic_addr_entry_t *) item)->addr, hs->arg);
+	nic_addr_entry_t *entry = member_to_inst(item, nic_addr_entry_t, link);
+	hs->func(entry->addr, hs->arg);
+	return true;
 }
 
@@ -237,39 +267,5 @@
 {
 	nic_addr_db_fe_arg_t hs = { .func = func, .arg = arg };
-	hash_set_apply((hash_set_t *) &db->set, nic_addr_db_fe_helper, &hs);
-}
-
-/**
- * Helper structure for nic_addr_db_remove_selected
- */
-typedef struct {
-	int (*func)(const uint8_t *, void *);
-	void *arg;
-} nic_addr_db_rs_arg_t;
-
-/**
- * Helper function for nic_addr_db_foreach
- */
-static int nic_addr_db_rs_helper(link_t *item, void *arg) {
-	nic_addr_db_rs_arg_t *hs = (nic_addr_db_rs_arg_t *) arg;
-	int retval = hs->func(((nic_addr_entry_t *) item)->addr, hs->arg);
-	if (retval) {
-		free(item);
-	}
-	return retval;
-}
-
-/**
- * Removes all addresses for which the function returns non-zero.
- *
- * @param	db
- * @param	func	User-defined function
- * @param	arg		Custom argument passed to the function
- */
-void nic_addr_db_remove_selected(nic_addr_db_t *db,
-	int (*func)(const uint8_t *, void *), void *arg)
-{
-	nic_addr_db_rs_arg_t hs = { .func = func, .arg = arg };
-	hash_set_remove_selected(&db->set, nic_addr_db_rs_helper, &hs);
+	hash_table_apply((hash_table_t*)&db->set, nic_addr_db_fe_helper, &hs);
 }
 
Index: uspace/lib/nic/src/nic_wol_virtues.c
===================================================================
--- uspace/lib/nic/src/nic_wol_virtues.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/nic/src/nic_wol_virtues.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -37,32 +37,28 @@
 
 #include "nic_wol_virtues.h"
+#include "nic.h"
 #include <assert.h>
 #include <errno.h>
 
-#define NIC_WV_HASH_COUNT 32
-
-/**
- * Hash table helper function
- */
-static int nic_wv_compare(unsigned long key[], hash_count_t keys,
-	link_t *item)
+
+/*
+ * Hash table helper functions
+ */
+
+static size_t nic_wv_key_hash(void *key)
+{
+	return *(nic_wv_id_t*) key;
+}
+
+static size_t nic_wv_hash(const ht_link_t *item)
 {
 	nic_wol_virtue_t *virtue = (nic_wol_virtue_t *) item;
-	return (virtue->id == (nic_wv_id_t) key[0]);
-}
-
-/**
- * Hash table helper function
- */
-static void nic_wv_rc(link_t *item)
-{
-}
-
-/**
- * Hash table helper function
- */
-static hash_index_t nic_wv_hash(unsigned long keys[])
-{
-	return keys[0] % NIC_WV_HASH_COUNT;
+	return virtue->id;
+}
+
+static bool nic_wv_key_equal(void *key, const ht_link_t *item)
+{
+	nic_wol_virtue_t *virtue = (nic_wol_virtue_t *) item;
+	return (virtue->id == *(nic_wv_id_t*) key);
 }
 
@@ -77,10 +73,12 @@
 int nic_wol_virtues_init(nic_wol_virtues_t *wvs)
 {
-	bzero(wvs, sizeof (nic_wol_virtues_t));
-	wvs->table_operations.compare = nic_wv_compare;
+	bzero(wvs, sizeof(nic_wol_virtues_t));
 	wvs->table_operations.hash = nic_wv_hash;
-	wvs->table_operations.remove_callback = nic_wv_rc;
-	if (!hash_table_create(&wvs->table, NIC_WV_HASH_COUNT, 1,
-		&wvs->table_operations)) {
+	wvs->table_operations.key_hash = nic_wv_key_hash;
+	wvs->table_operations.key_equal = nic_wv_key_equal;
+	wvs->table_operations.equal = 0;
+	wvs->table_operations.remove_callback = 0;
+	
+	if (!hash_table_create(&wvs->table, 0, 0, &wvs->table_operations)) {
 		return ENOMEM;
 	}
@@ -170,8 +168,6 @@
 	do {
 		virtue->id = wvs->next_id++;
-	} while (NULL !=
-		hash_table_find(&wvs->table, (unsigned long *) &virtue->id));
-	hash_table_insert(&wvs->table,
-		(unsigned long *) &virtue->id, &virtue->item);
+	} while (NULL != hash_table_find(&wvs->table, &virtue->id));
+	hash_table_insert(&wvs->table, &virtue->item);
 	virtue->next = wvs->lists[virtue->type];
 	wvs->lists[virtue->type] = virtue;
@@ -191,6 +187,6 @@
 nic_wol_virtue_t *nic_wol_virtues_remove(nic_wol_virtues_t *wvs, nic_wv_id_t id)
 {
-	nic_wol_virtue_t *virtue = (nic_wol_virtue_t *)
-		hash_table_find(&wvs->table, (unsigned long *) &id);
+	nic_wol_virtue_t *virtue = 
+		(nic_wol_virtue_t *) hash_table_find(&wvs->table, &id);
 	if (virtue == NULL) {
 		return NULL;
@@ -198,5 +194,5 @@
 
 	/* Remove from filter_table */
-	hash_table_remove(&wvs->table, (unsigned long *) &id, 1);
+	hash_table_remove_item(&wvs->table, &virtue->item);
 
 	/* Remove from filter_types */
@@ -235,6 +231,5 @@
 	 * constant virtue the retyping is correct.
 	 */
-	link_t *virtue = hash_table_find(
-		&((nic_wol_virtues_t *) wvs)->table, (unsigned long *) &id);
+	ht_link_t *virtue = hash_table_find(&((nic_wol_virtues_t *) wvs)->table, &id);
 	return (const nic_wol_virtue_t *) virtue;
 }
Index: uspace/lib/posix/Makefile
===================================================================
--- uspace/lib/posix/Makefile	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/posix/Makefile	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/assert.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/ctype.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/errno.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/fcntl.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/float.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/fnmatch.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/getopt.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/inttypes.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/iso646.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/limits.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/locale.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/malloc.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/math.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/pwd.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/signal.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/stdarg.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/stdbool.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/stddef.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/stdint.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/stdio.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/stdlib.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/string.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/strings.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/sys/mman.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/sys/stat.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/sys/types.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/sys/wait.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/time.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/include/posix/unistd.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/ctype.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/errno.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/fcntl.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/fnmatch.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/getopt.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/internal/common.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/locale.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/math.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/pwd.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/signal.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/stdio.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/stdio/scanf.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/stdlib.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/stdlib/strtol.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/stdlib/strtold.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/string.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/strings.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/sys/stat.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/sys/wait.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/time.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 5c90e3e8776092fd096406931971a147268d3db1)
+++ uspace/lib/posix/source/unistd.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(revision )
@@ -1,335 +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.
- */
-
-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: pace/lib/posix/time.h
===================================================================
--- uspace/lib/posix/time.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(revision )
@@ -1,145 +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 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: pace/lib/posix/unistd.c
===================================================================
--- uspace/lib/posix/unistd.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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 b801f2d6becda84795177e84564a610b886dbea0)
+++ 	(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/add.c
===================================================================
--- uspace/lib/softfloat/add.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/lib/softfloat/add.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -90,5 +90,5 @@
 		/* both are denormalized */
 		frac1 += frac2;
-		if (frac1 & FLOAT32_HIDDEN_BIT_MASK ) {
+		if (frac1 & FLOAT32_HIDDEN_BIT_MASK) {
 			/* result is not denormalized */
 			a.parts.exp = 1;
@@ -112,5 +112,5 @@
 	frac2 <<= 6;
 	
-	if (expdiff < (FLOAT32_FRACTION_SIZE + 2) ) {
+	if (expdiff < (FLOAT32_FRACTION_SIZE + 2)) {
 		frac2 >>= expdiff;
 		frac1 += frac2;
@@ -121,5 +121,5 @@
 	}
 	
-	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7) ) {
+	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7)) {
 		++exp1;
 		frac1 >>= 1;
@@ -135,5 +135,5 @@
 	}
 	
-	if ((exp1 == FLOAT32_MAX_EXPONENT ) || (exp2 > exp1)) {
+	if ((exp1 == FLOAT32_MAX_EXPONENT) || (exp2 > exp1)) {
 		/* overflow - set infinity as result */
 		a.parts.exp = FLOAT32_MAX_EXPONENT;
@@ -250,5 +250,5 @@
 	}
 	
-	if ((exp1 == FLOAT64_MAX_EXPONENT ) || (exp2 > exp1)) {
+	if ((exp1 == FLOAT64_MAX_EXPONENT) || (exp2 > exp1)) {
 		/* overflow - set infinity as result */
 		a.parts.exp = FLOAT64_MAX_EXPONENT;
@@ -259,5 +259,5 @@
 	a.parts.exp = exp1;
 	/* Clear hidden bit and shift */
-	a.parts.fraction = ((frac1 >> 6 ) & (~FLOAT64_HIDDEN_BIT_MASK));
+	a.parts.fraction = ((frac1 >> 6) & (~FLOAT64_HIDDEN_BIT_MASK));
 	return a;
 }
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/devman/devman.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -66,50 +66,78 @@
 /* hash table operations */
 
-static hash_index_t devices_hash(unsigned long key[])
-{
-	return key[0] % DEVICE_BUCKETS;
-}
-
-static int devman_devices_compare(unsigned long key[], hash_count_t keys,
-    link_t *item)
-{
-	dev_node_t *dev = hash_table_get_instance(item, dev_node_t, devman_dev);
-	return (dev->handle == (devman_handle_t) key[0]);
-}
-
-static int devman_functions_compare(unsigned long key[], hash_count_t keys,
-    link_t *item)
-{
-	fun_node_t *fun = hash_table_get_instance(item, fun_node_t, devman_fun);
-	return (fun->handle == (devman_handle_t) key[0]);
-}
-
-static int loc_functions_compare(unsigned long key[], hash_count_t keys,
-    link_t *item)
-{
-	fun_node_t *fun = hash_table_get_instance(item, fun_node_t, loc_fun);
-	return (fun->service_id == (service_id_t) key[0]);
-}
-
-static void devices_remove_callback(link_t *item)
-{
-}
-
-static hash_table_operations_t devman_devices_ops = {
-	.hash = devices_hash,
-	.compare = devman_devices_compare,
-	.remove_callback = devices_remove_callback
+static inline size_t handle_key_hash(void *key)
+{
+	devman_handle_t handle = *(devman_handle_t*)key;
+	return handle;
+}
+
+static size_t devman_devices_hash(const ht_link_t *item)
+{
+	dev_node_t *dev = hash_table_get_inst(item, dev_node_t, devman_dev);
+	return handle_key_hash(&dev->handle);
+}
+
+static size_t devman_functions_hash(const ht_link_t *item)
+{
+	fun_node_t *fun = hash_table_get_inst(item, fun_node_t, devman_fun);
+	return handle_key_hash(&fun->handle);
+}
+
+static bool devman_devices_key_equal(void *key, const ht_link_t *item)
+{
+	devman_handle_t handle = *(devman_handle_t*)key;
+	dev_node_t *dev = hash_table_get_inst(item, dev_node_t, devman_dev);
+	return dev->handle == handle;
+}
+
+static bool devman_functions_key_equal(void *key, const ht_link_t *item)
+{
+	devman_handle_t handle = *(devman_handle_t*)key;
+	fun_node_t *fun = hash_table_get_inst(item, fun_node_t, devman_fun);
+	return fun->handle == handle;
+}
+
+static inline size_t service_id_key_hash(void *key)
+{
+	service_id_t service_id = *(service_id_t*)key;
+	return service_id;
+}
+
+static size_t loc_functions_hash(const ht_link_t *item)
+{
+	fun_node_t *fun = hash_table_get_inst(item, fun_node_t, loc_fun);
+	return service_id_key_hash(&fun->service_id);
+}
+
+static bool loc_functions_key_equal(void *key, const ht_link_t *item)
+{
+	service_id_t service_id = *(service_id_t*)key;
+	fun_node_t *fun = hash_table_get_inst(item, fun_node_t, loc_fun);
+	return fun->service_id == service_id;
+}
+
+
+static hash_table_ops_t devman_devices_ops = {
+	.hash = devman_devices_hash,
+	.key_hash = handle_key_hash,
+	.key_equal = devman_devices_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
-static hash_table_operations_t devman_functions_ops = {
-	.hash = devices_hash,
-	.compare = devman_functions_compare,
-	.remove_callback = devices_remove_callback
+static hash_table_ops_t devman_functions_ops = {
+	.hash = devman_functions_hash,
+	.key_hash = handle_key_hash,
+	.key_equal = devman_functions_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
-static hash_table_operations_t loc_devices_ops = {
-	.hash = devices_hash,
-	.compare = loc_functions_compare,
-	.remove_callback = devices_remove_callback
+static hash_table_ops_t loc_devices_ops = {
+	.hash = loc_functions_hash,
+	.key_hash = service_id_key_hash,
+	.key_equal = loc_functions_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -974,10 +1002,7 @@
 	tree->current_handle = 0;
 	
-	hash_table_create(&tree->devman_devices, DEVICE_BUCKETS, 1,
-	    &devman_devices_ops);
-	hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1,
-	    &devman_functions_ops);
-	hash_table_create(&tree->loc_functions, DEVICE_BUCKETS, 1,
-	    &loc_devices_ops);
+	hash_table_create(&tree->devman_devices, 0, 0, &devman_devices_ops);
+	hash_table_create(&tree->devman_functions, 0, 0, &devman_functions_ops);
+	hash_table_create(&tree->loc_functions, 0, 0, &loc_devices_ops);
 	
 	fibril_rwlock_initialize(&tree->rwlock);
@@ -1013,5 +1038,4 @@
 	list_initialize(&dev->functions);
 	link_initialize(&dev->driver_devices);
-	link_initialize(&dev->devman_dev);
 	
 	return dev;
@@ -1060,14 +1084,11 @@
 dev_node_t *find_dev_node_no_lock(dev_tree_t *tree, devman_handle_t handle)
 {
-	unsigned long key = handle;
-	link_t *link;
-	
 	assert(fibril_rwlock_is_locked(&tree->rwlock));
 	
-	link = hash_table_find(&tree->devman_devices, &key);
+	ht_link_t *link = hash_table_find(&tree->devman_devices, &handle);
 	if (link == NULL)
 		return NULL;
 	
-	return hash_table_get_instance(link, dev_node_t, devman_dev);
+	return hash_table_get_inst(link, dev_node_t, devman_dev);
 }
 
@@ -1144,6 +1165,4 @@
 	link_initialize(&fun->dev_functions);
 	list_initialize(&fun->match_ids.ids);
-	link_initialize(&fun->devman_fun);
-	link_initialize(&fun->loc_fun);
 	
 	return fun;
@@ -1206,15 +1225,13 @@
 fun_node_t *find_fun_node_no_lock(dev_tree_t *tree, devman_handle_t handle)
 {
-	unsigned long key = handle;
-	link_t *link;
 	fun_node_t *fun;
 	
 	assert(fibril_rwlock_is_locked(&tree->rwlock));
 	
-	link = hash_table_find(&tree->devman_functions, &key);
+	ht_link_t *link = hash_table_find(&tree->devman_functions, &handle);
 	if (link == NULL)
 		return NULL;
 	
-	fun = hash_table_get_instance(link, fun_node_t, devman_fun);
+	fun = hash_table_get_inst(link, fun_node_t, devman_fun);
 	
 	return fun;
@@ -1294,6 +1311,5 @@
 	/* Add the node to the handle-to-node map. */
 	dev->handle = ++tree->current_handle;
-	unsigned long key = dev->handle;
-	hash_table_insert(&tree->devman_devices, &key, &dev->devman_dev);
+	hash_table_insert(&tree->devman_devices, &dev->devman_dev);
 
 	/* Add the node to the list of its parent's children. */
@@ -1316,6 +1332,5 @@
 	
 	/* Remove node from the handle-to-node map. */
-	unsigned long key = dev->handle;
-	hash_table_remove(&tree->devman_devices, &key, 1);
+	hash_table_remove(&tree->devman_devices, &dev->handle);
 	
 	/* Unlink from parent function. */
@@ -1358,6 +1373,5 @@
 	/* Add the node to the handle-to-node map. */
 	fun->handle = ++tree->current_handle;
-	unsigned long key = fun->handle;
-	hash_table_insert(&tree->devman_functions, &key, &fun->devman_fun);
+	hash_table_insert(&tree->devman_functions, &fun->devman_fun);
 
 	/* Add the node to the list of its parent's children. */
@@ -1379,6 +1393,5 @@
 	
 	/* Remove the node from the handle-to-node map. */
-	unsigned long key = fun->handle;
-	hash_table_remove(&tree->devman_functions, &key, 1);
+	hash_table_remove(&tree->devman_functions, &fun->handle);
 	
 	/* Remove the node from the list of its parent's children. */
@@ -1493,11 +1506,9 @@
 {
 	fun_node_t *fun = NULL;
-	link_t *link;
-	unsigned long key = (unsigned long) service_id;
 	
 	fibril_rwlock_read_lock(&tree->rwlock);
-	link = hash_table_find(&tree->loc_functions, &key);
+	ht_link_t *link = hash_table_find(&tree->loc_functions, &service_id);
 	if (link != NULL) {
-		fun = hash_table_get_instance(link, fun_node_t, loc_fun);
+		fun = hash_table_get_inst(link, fun_node_t, loc_fun);
 		fun_add_ref(fun);
 	}
@@ -1511,6 +1522,5 @@
 	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
 	
-	unsigned long key = (unsigned long) fun->service_id;
-	hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
+	hash_table_insert(&tree->loc_functions, &fun->loc_fun);
 }
 
Index: uspace/srv/devman/devman.h
===================================================================
--- uspace/srv/devman/devman.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/devman/devman.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -52,5 +52,4 @@
 
 #define MATCH_EXT ".ma"
-#define DEVICE_BUCKETS 256
 
 #define LOC_DEVICE_NAMESPACE "devices"
@@ -151,5 +150,5 @@
 	 * Used by the hash table of devices indexed by devman device handles.
 	 */
-	link_t devman_dev;
+	ht_link_t devman_dev;
 	
 	/**
@@ -204,10 +203,10 @@
 	 * Used by the hash table of functions indexed by devman device handles.
 	 */
-	link_t devman_fun;
+	ht_link_t devman_fun;
 	
 	/**
 	 * Used by the hash table of functions indexed by service IDs.
 	 */
-	link_t loc_fun;
+	ht_link_t loc_fun;
 };
 
Index: uspace/srv/fs/cdfs/cdfs_ops.c
===================================================================
--- uspace/srv/fs/cdfs/cdfs_ops.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/cdfs/cdfs_ops.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -37,6 +37,8 @@
  */
 
+#include "cdfs_ops.h"
 #include <bool.h>
 #include <adt/hash_table.h>
+#include <adt/hash.h>
 #include <malloc.h>
 #include <mem.h>
@@ -50,21 +52,9 @@
 #include "cdfs.h"
 #include "cdfs_endian.h"
-#include "cdfs_ops.h"
 
 /** Standard CD-ROM block size */
 #define BLOCK_SIZE  2048
 
-/** Implicit node cache size
- *
- * More nodes can be actually cached if the files remain
- * opended.
- *
- */
-#define NODE_CACHE_SIZE  200
-
-#define NODES_BUCKETS  256
-
-#define NODES_KEY_SRVC   0
-#define NODES_KEY_INDEX  1
+#define NODE_CACHE_SIZE 200
 
 /** All root nodes have index 0 */
@@ -205,5 +195,5 @@
 	service_id_t service_id;  /**< Service ID of block device */
 	
-	link_t nh_link;           /**< Nodes hash table link */
+	ht_link_t nh_link;        /**< Nodes hash table link */
 	cdfs_dentry_type_t type;  /**< Dentry type */
 	
@@ -226,31 +216,36 @@
 static hash_table_t nodes;
 
-static hash_index_t nodes_hash(unsigned long key[])
-{
-	return key[NODES_KEY_INDEX] % NODES_BUCKETS;
-}
-
-static int nodes_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	cdfs_node_t *node =
-	    hash_table_get_instance(item, cdfs_node_t, nh_link);
-	
-	switch (keys) {
-	case 1:
-		return (node->service_id == key[NODES_KEY_SRVC]);
-	case 2:
-		return ((node->service_id == key[NODES_KEY_SRVC]) &&
-		    (node->index == key[NODES_KEY_INDEX]));
-	default:
-		assert((keys == 1) || (keys == 2));
-	}
-	
-	return 0;
-}
-
-static void nodes_remove_callback(link_t *item)
-{
-	cdfs_node_t *node =
-	    hash_table_get_instance(item, cdfs_node_t, nh_link);
+/* 
+ * Hash table support functions.
+ */
+
+typedef struct {
+	service_id_t service_id;
+    fs_index_t index;
+} ht_key_t;
+
+static size_t nodes_key_hash(void *k)
+{
+	ht_key_t *key = (ht_key_t*)k;
+	return hash_combine(key->service_id, key->index);
+}
+
+static size_t nodes_hash(const ht_link_t *item)
+{
+	cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link);
+	return hash_combine(node->service_id, node->index);
+}
+
+static bool nodes_key_equal(void *k, const ht_link_t *item)
+{
+	cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link);
+	ht_key_t *key = (ht_key_t*)k;
+	
+	return key->service_id == node->service_id && key->index == node->index;
+}
+
+static void nodes_remove_callback(ht_link_t *item)
+{
+	cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link);
 	
 	assert(node->type == CDFS_DIRECTORY);
@@ -268,7 +263,9 @@
 
 /** Nodes hash table operations */
-static hash_table_operations_t nodes_ops = {
+static hash_table_ops_t nodes_ops = {
 	.hash = nodes_hash,
-	.compare = nodes_compare,
+	.key_hash = nodes_key_hash,
+	.key_equal = nodes_key_equal,
+	.equal = NULL,
 	.remove_callback = nodes_remove_callback
 };
@@ -277,13 +274,13 @@
     fs_index_t index)
 {
-	unsigned long key[] = {
-		[NODES_KEY_SRVC] = service_id,
-		[NODES_KEY_INDEX] = index
+	ht_key_t key = {
+		.index = index,
+		.service_id = service_id
 	};
 	
-	link_t *link = hash_table_find(&nodes, key);
+	ht_link_t *link = hash_table_find(&nodes, &key);
 	if (link) {
 		cdfs_node_t *node =
-		    hash_table_get_instance(link, cdfs_node_t, nh_link);
+		    hash_table_get_inst(link, cdfs_node_t, nh_link);
 		
 		*rfn = FS_NODE(node);
@@ -311,5 +308,4 @@
 	node->opened = 0;
 	
-	link_initialize(&node->nh_link);
 	list_initialize(&node->cs_list);
 }
@@ -353,10 +349,5 @@
 	
 	/* Insert the new node into the nodes hash table. */
-	unsigned long key[] = {
-		[NODES_KEY_SRVC] = node->service_id,
-		[NODES_KEY_INDEX] = node->index
-	};
-	
-	hash_table_insert(&nodes, key, &node->nh_link);
+	hash_table_insert(&nodes, &node->nh_link);
 	
 	*rfn = FS_NODE(node);
@@ -508,13 +499,13 @@
 static fs_node_t *get_cached_node(service_id_t service_id, fs_index_t index)
 {
-	unsigned long key[] = {
-		[NODES_KEY_SRVC] = service_id,
-		[NODES_KEY_INDEX] = index
+	ht_key_t key = {
+		.index = index,
+		.service_id = service_id
 	};
 	
-	link_t *link = hash_table_find(&nodes, key);
+	ht_link_t *link = hash_table_find(&nodes, &key);
 	if (link) {
 		cdfs_node_t *node =
-		    hash_table_get_instance(link, cdfs_node_t, nh_link);
+		    hash_table_get_inst(link, cdfs_node_t, nh_link);
 		return FS_NODE(node);
 	}
@@ -802,11 +793,19 @@
 }
 
+static bool rm_service_id_nodes(ht_link_t *item, void *arg) 
+{
+	service_id_t service_id = *(service_id_t*)arg;
+	cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link);
+	
+	if (node->service_id == service_id) {
+		hash_table_remove_item(&nodes, &node->nh_link);
+	}
+	
+	return true;
+}
+
 static void cdfs_instance_done(service_id_t service_id)
 {
-	unsigned long key[] = {
-		[NODES_KEY_SRVC] = service_id
-	};
-	
-	hash_table_remove(&nodes, key, 1);
+	hash_table_apply(&nodes, rm_service_id_nodes, &service_id);
 	block_cache_fini(service_id);
 	block_fini(service_id);
@@ -822,15 +821,15 @@
     size_t *rbytes)
 {
-	unsigned long key[] = {
-		[NODES_KEY_SRVC] = service_id,
-		[NODES_KEY_INDEX] = index
+	ht_key_t key = {
+		.index = index,
+		.service_id = service_id
 	};
 	
-	link_t *link = hash_table_find(&nodes, key);
+	ht_link_t *link = hash_table_find(&nodes, &key);
 	if (link == NULL)
 		return ENOENT;
 	
 	cdfs_node_t *node =
-	    hash_table_get_instance(link, cdfs_node_t, nh_link);
+	    hash_table_get_inst(link, cdfs_node_t, nh_link);
 	
 	if (!node->processed) {
@@ -912,34 +911,31 @@
 }
 
+static bool cache_remove_closed(ht_link_t *item, void *arg)
+{
+	size_t *premove_cnt = (size_t*)arg;
+	
+	/* Some nodes were requested to be removed from the cache. */
+	if (0 < *premove_cnt) {
+		cdfs_node_t *node =	hash_table_get_inst(item, cdfs_node_t, nh_link);
+
+		if (!node->opened) {
+			hash_table_remove_item(&nodes, item);
+			
+			--nodes_cached;
+			--*premove_cnt;
+		}
+	}
+	
+	/* Only continue if more nodes were requested to be removed. */
+	return 0 < *premove_cnt;
+}
+
 static void cleanup_cache(service_id_t service_id)
 {
 	if (nodes_cached > NODE_CACHE_SIZE) {
-		size_t remove = nodes_cached - NODE_CACHE_SIZE;
-		
-		// FIXME: this accesses the internals of the hash table
-		//        and should be rewritten in a clean way
-		
-		for (hash_index_t chain = 0; chain < nodes.entries; chain++) {
-			for (link_t *link = nodes.entry[chain].head.next;
-			    link != &nodes.entry[chain].head;
-			    link = link->next) {
-				if (remove == 0)
-					return;
-				
-				cdfs_node_t *node =
-				    hash_table_get_instance(link, cdfs_node_t, nh_link);
-				if (node->opened == 0) {
-					link_t *tmp = link;
-					link = link->prev;
-					
-					list_remove(tmp);
-					nodes.op->remove_callback(tmp);
-					nodes_cached--;
-					remove--;
-					
-					continue;
-				}
-			}
-		}
+		size_t remove_cnt = nodes_cached - NODE_CACHE_SIZE;
+		
+		if (0 < remove_cnt)
+			hash_table_apply(&nodes, cache_remove_closed, &remove_cnt);
 	}
 }
@@ -951,15 +947,15 @@
 		return EOK;
 	
-	unsigned long key[] = {
-		[NODES_KEY_SRVC] = service_id,
-		[NODES_KEY_INDEX] = index
+	ht_key_t key = {
+		.index = index,
+		.service_id = service_id
 	};
 	
-	link_t *link = hash_table_find(&nodes, key);
+	ht_link_t *link = hash_table_find(&nodes, &key);
 	if (link == 0)
 		return ENOENT;
 	
 	cdfs_node_t *node =
-	    hash_table_get_instance(link, cdfs_node_t, nh_link);
+	    hash_table_get_inst(link, cdfs_node_t, nh_link);
 	
 	assert(node->opened > 0);
@@ -1007,5 +1003,5 @@
 bool cdfs_init(void)
 {
-	if (!hash_table_create(&nodes, NODES_BUCKETS, 2, &nodes_ops))
+	if (!hash_table_create(&nodes, 0, 0, &nodes_ops))
 		return false;
 	
Index: uspace/srv/fs/exfat/exfat.h
===================================================================
--- uspace/srv/fs/exfat/exfat.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/exfat/exfat.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -106,7 +106,7 @@
 typedef struct {
 	/** Used indices (position) hash table link. */
-	link_t		uph_link;
+	ht_link_t		uph_link;
 	/** Used indices (index) hash table link. */
-	link_t		uih_link;
+	ht_link_t		uih_link;
 
 	fibril_mutex_t	lock;
Index: uspace/srv/fs/exfat/exfat_idx.c
===================================================================
--- uspace/srv/fs/exfat/exfat_idx.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/exfat/exfat_idx.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -41,4 +41,5 @@
 #include <str.h>
 #include <adt/hash_table.h>
+#include <adt/hash.h>
 #include <adt/list.h>
 #include <assert.h>
@@ -91,4 +92,5 @@
 	if (lock)
 		fibril_mutex_lock(&unused_lock);
+
 	list_foreach(unused_list, l) {
 		u = list_get_instance(l, unused_t, link);
@@ -112,70 +114,48 @@
 static hash_table_t up_hash;
 
-#define UPH_BUCKETS_LOG	12
-#define UPH_BUCKETS	(1 << UPH_BUCKETS_LOG)
-
-#define UPH_SID_KEY	0
-#define UPH_PFC_KEY	1
-#define UPH_PDI_KEY	2
-
-static hash_index_t pos_hash(unsigned long key[])
-{
-	service_id_t service_id = (service_id_t)key[UPH_SID_KEY];
-	exfat_cluster_t pfc = (exfat_cluster_t)key[UPH_PFC_KEY];
-	unsigned pdi = (unsigned)key[UPH_PDI_KEY];
-
-	hash_index_t h;
-
-	/*
-	 * The least significant half of all bits are the least significant bits
-	 * of the parent node's first cluster.
-	 *
-	 * The least significant half of the most significant half of all bits
-	 * are the least significant bits of the node's dentry index within the
-	 * parent directory node.
-	 *
-	 * The most significant half of the most significant half of all bits
-	 * are the least significant bits of the device handle.
-	 */
-	h = pfc & ((1 << (UPH_BUCKETS_LOG / 2)) - 1);
-	h |= (pdi & ((1 << (UPH_BUCKETS_LOG / 4)) - 1)) <<
-	    (UPH_BUCKETS_LOG / 2); 
-	h |= (service_id & ((1 << (UPH_BUCKETS_LOG / 4)) - 1)) <<
-	    (3 * (UPH_BUCKETS_LOG / 4));
-
-	return h;
-}
-
-static int pos_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	service_id_t service_id = (service_id_t)key[UPH_SID_KEY];
+typedef struct {
+	service_id_t service_id;
 	exfat_cluster_t pfc;
 	unsigned pdi;
-	exfat_idx_t *fidx = list_get_instance(item, exfat_idx_t, uph_link);
-
-	switch (keys) {
-	case 1:
-		return (service_id == fidx->service_id);
-	case 3:
-		pfc = (exfat_cluster_t) key[UPH_PFC_KEY];
-		pdi = (unsigned) key[UPH_PDI_KEY];
-		return (service_id == fidx->service_id) && (pfc == fidx->pfc) &&
-		    (pdi == fidx->pdi);
-	default:
-		assert((keys == 1) || (keys == 3));
-	}
-
-	return 0;
-}
-
-static void pos_remove_callback(link_t *item)
-{
-	/* nothing to do */
-}
-
-static hash_table_operations_t uph_ops = {
+} pos_key_t;
+
+static inline size_t pos_key_hash(void *key)
+{
+	pos_key_t *pos = (pos_key_t*)key;
+	
+	size_t hash = 0;
+	hash = hash_combine(pos->pfc, pos->pdi);
+	return hash_combine(hash, pos->service_id);
+}
+
+static size_t pos_hash(const ht_link_t *item)
+{
+	exfat_idx_t *fidx = hash_table_get_inst(item, exfat_idx_t, uph_link);
+	
+	pos_key_t pkey = {
+		.service_id = fidx->service_id,
+		.pfc = fidx->pfc,
+		.pdi = fidx->pdi,
+	};
+	
+	return pos_key_hash(&pkey);
+}
+
+static bool pos_key_equal(void *key, const ht_link_t *item)
+{
+	pos_key_t *pos = (pos_key_t*)key;
+	exfat_idx_t *fidx = hash_table_get_inst(item, exfat_idx_t, uph_link);
+	
+	return pos->service_id == fidx->service_id
+		&& pos->pdi == fidx->pdi
+		&& pos->pfc == fidx->pfc;
+}
+
+static hash_table_ops_t uph_ops = {
 	.hash = pos_hash,
-	.compare = pos_compare,
-	.remove_callback = pos_remove_callback,
+	.key_hash = pos_key_hash,
+	.key_equal = pos_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL,
 };
 
@@ -186,54 +166,41 @@
 static hash_table_t ui_hash;
 
-#define UIH_BUCKETS_LOG	12
-#define UIH_BUCKETS	(1 << UIH_BUCKETS_LOG)
-
-#define UIH_SID_KEY	0
-#define UIH_INDEX_KEY	1
-
-static hash_index_t idx_hash(unsigned long key[])
-{
-	service_id_t service_id = (service_id_t)key[UIH_SID_KEY];
-	fs_index_t index = (fs_index_t)key[UIH_INDEX_KEY];
-
-	hash_index_t h;
-
-	h = service_id & ((1 << (UIH_BUCKETS_LOG / 2)) - 1);
-	h |= (index & ((1 << (UIH_BUCKETS_LOG / 2)) - 1)) <<
-	    (UIH_BUCKETS_LOG / 2);
-
-	return h;
-}
-
-static int idx_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	service_id_t service_id = (service_id_t)key[UIH_SID_KEY];
+typedef struct {
+	service_id_t service_id;
 	fs_index_t index;
-	exfat_idx_t *fidx = list_get_instance(item, exfat_idx_t, uih_link);
-
-	switch (keys) {
-	case 1:
-		return (service_id == fidx->service_id);
-	case 2:
-		index = (fs_index_t) key[UIH_INDEX_KEY];
-		return (service_id == fidx->service_id) &&
-		    (index == fidx->index);
-	default:
-		assert((keys == 1) || (keys == 2));
-	}
-
-	return 0;
-}
-
-static void idx_remove_callback(link_t *item)
-{
-	exfat_idx_t *fidx = list_get_instance(item, exfat_idx_t, uih_link);
+} idx_key_t;
+
+static size_t idx_key_hash(void *key_arg)
+{
+	idx_key_t *key = (idx_key_t*)key_arg;
+	return hash_combine(key->service_id, key->index);
+}
+
+static size_t idx_hash(const ht_link_t *item)
+{
+	exfat_idx_t *fidx = hash_table_get_inst(item, exfat_idx_t, uih_link);
+	return hash_combine(fidx->service_id, fidx->index);
+}
+
+static bool idx_key_equal(void *key_arg, const ht_link_t *item)
+{
+	exfat_idx_t *fidx = hash_table_get_inst(item, exfat_idx_t, uih_link);
+	idx_key_t *key = (idx_key_t*)key_arg;
+	
+	return key->index == fidx->index && key->service_id == fidx->service_id;
+}
+
+static void idx_remove_callback(ht_link_t *item)
+{
+	exfat_idx_t *fidx = hash_table_get_inst(item, exfat_idx_t, uih_link);
 
 	free(fidx);
 }
 
-static hash_table_operations_t uih_ops = {
+static hash_table_ops_t uih_ops = {
 	.hash = idx_hash,
-	.compare = idx_compare,
+	.key_hash = idx_key_hash,
+	.key_equal = idx_key_equal,
+	.equal = NULL,
 	.remove_callback = idx_remove_callback,
 };
@@ -376,6 +343,4 @@
 	}
 		
-	link_initialize(&fidx->uph_link);
-	link_initialize(&fidx->uih_link);
 	fibril_mutex_initialize(&fidx->lock);
 	fidx->service_id = service_id;
@@ -400,10 +365,5 @@
 	}
 		
-	unsigned long ikey[] = {
-		[UIH_SID_KEY] = service_id,
-		[UIH_INDEX_KEY] = fidx->index,
-	};
-	
-	hash_table_insert(&ui_hash, ikey, &fidx->uih_link);
+	hash_table_insert(&ui_hash, &fidx->uih_link);
 	fibril_mutex_lock(&fidx->lock);
 	fibril_mutex_unlock(&used_lock);
@@ -417,15 +377,15 @@
 {
 	exfat_idx_t *fidx;
-	link_t *l;
-	unsigned long pkey[] = {
-		[UPH_SID_KEY] = service_id,
-		[UPH_PFC_KEY] = pfc,
-		[UPH_PDI_KEY] = pdi,
+	
+	pos_key_t pos_key = {
+		.service_id = service_id,
+		.pfc = pfc,
+		.pdi = pdi,
 	};
 
 	fibril_mutex_lock(&used_lock);
-	l = hash_table_find(&up_hash, pkey);
+	ht_link_t *l = hash_table_find(&up_hash, &pos_key);
 	if (l) {
-		fidx = hash_table_get_instance(l, exfat_idx_t, uph_link);
+		fidx = hash_table_get_inst(l, exfat_idx_t, uph_link);
 	} else {
 		int rc;
@@ -437,14 +397,9 @@
 		}
 		
-		unsigned long ikey[] = {
-			[UIH_SID_KEY] = service_id,
-			[UIH_INDEX_KEY] = fidx->index,
-		};
-	
 		fidx->pfc = pfc;
 		fidx->pdi = pdi;
 
-		hash_table_insert(&up_hash, pkey, &fidx->uph_link);
-		hash_table_insert(&ui_hash, ikey, &fidx->uih_link);
+		hash_table_insert(&up_hash, &fidx->uph_link);
+		hash_table_insert(&ui_hash, &fidx->uih_link);
 	}
 	fibril_mutex_lock(&fidx->lock);
@@ -456,12 +411,6 @@
 void exfat_idx_hashin(exfat_idx_t *idx)
 {
-	unsigned long pkey[] = {
-		[UPH_SID_KEY] = idx->service_id,
-		[UPH_PFC_KEY] = idx->pfc,
-		[UPH_PDI_KEY] = idx->pdi,
-	};
-
-	fibril_mutex_lock(&used_lock);
-	hash_table_insert(&up_hash, pkey, &idx->uph_link);
+	fibril_mutex_lock(&used_lock);
+	hash_table_insert(&up_hash, &idx->uph_link);
 	fibril_mutex_unlock(&used_lock);
 }
@@ -469,12 +418,6 @@
 void exfat_idx_hashout(exfat_idx_t *idx)
 {
-	unsigned long pkey[] = {
-		[UPH_SID_KEY] = idx->service_id,
-		[UPH_PFC_KEY] = idx->pfc,
-		[UPH_PDI_KEY] = idx->pdi,
-	};
-
-	fibril_mutex_lock(&used_lock);
-	hash_table_remove(&up_hash, pkey, 3);
+	fibril_mutex_lock(&used_lock);
+	hash_table_remove_item(&up_hash, &idx->uph_link);
 	fibril_mutex_unlock(&used_lock);
 }
@@ -484,14 +427,14 @@
 {
 	exfat_idx_t *fidx = NULL;
-	link_t *l;
-	unsigned long ikey[] = {
-		[UIH_SID_KEY] = service_id,
-		[UIH_INDEX_KEY] = index,
+
+	idx_key_t idx_key = {
+		.service_id = service_id,
+		.index = index,
 	};
 
 	fibril_mutex_lock(&used_lock);
-	l = hash_table_find(&ui_hash, ikey);
+	ht_link_t *l = hash_table_find(&ui_hash, &idx_key);
 	if (l) {
-		fidx = hash_table_get_instance(l, exfat_idx_t, uih_link);
+		fidx = hash_table_get_inst(l, exfat_idx_t, uih_link);
 		fibril_mutex_lock(&fidx->lock);
 	}
@@ -507,10 +450,8 @@
 void exfat_idx_destroy(exfat_idx_t *idx)
 {
-	unsigned long ikey[] = {
-		[UIH_SID_KEY] = idx->service_id,
-		[UIH_INDEX_KEY] = idx->index,
+	idx_key_t idx_key = {
+		.service_id = idx->service_id,
+		.index = idx->index,
 	};
-	service_id_t service_id = idx->service_id;
-	fs_index_t index = idx->index;
 
 	/* TODO: assert(idx->pfc == FAT_CLST_RES0); */
@@ -523,8 +464,8 @@
 	 * the index hash only.
 	 */
-	hash_table_remove(&ui_hash, ikey, 2);
+	hash_table_remove(&ui_hash, &idx_key);
 	fibril_mutex_unlock(&used_lock);
 	/* Release the VFS index. */
-	exfat_index_free(service_id, index);
+	exfat_index_free(idx_key.service_id, idx_key.index);
 	/* The index structure itself is freed in idx_remove_callback(). */
 }
@@ -532,7 +473,7 @@
 int exfat_idx_init(void)
 {
-	if (!hash_table_create(&up_hash, UPH_BUCKETS, 3, &uph_ops)) 
+	if (!hash_table_create(&up_hash, 0, 0, &uph_ops)) 
 		return ENOMEM;
-	if (!hash_table_create(&ui_hash, UIH_BUCKETS, 2, &uih_ops)) {
+	if (!hash_table_create(&ui_hash, 0, 0, &uih_ops)) {
 		hash_table_destroy(&up_hash);
 		return ENOMEM;
@@ -544,4 +485,5 @@
 {
 	/* We assume the hash tables are empty. */
+	assert(hash_table_empty(&up_hash) && hash_table_empty(&ui_hash));
 	hash_table_destroy(&up_hash);
 	hash_table_destroy(&ui_hash);
@@ -568,13 +510,30 @@
 }
 
+static bool rm_pos_service_id(ht_link_t *item, void *arg)
+{
+	service_id_t service_id = *(service_id_t*)arg;
+	exfat_idx_t *fidx = hash_table_get_inst(item, exfat_idx_t, uph_link);
+
+	if (fidx->service_id == service_id) {
+		hash_table_remove_item(&up_hash, item);
+	}
+	
+	return true;
+}
+
+static bool rm_idx_service_id(ht_link_t *item, void *arg)
+{
+	service_id_t service_id = *(service_id_t*)arg;
+	exfat_idx_t *fidx = hash_table_get_inst(item, exfat_idx_t, uih_link);
+
+	if (fidx->service_id == service_id) {
+		hash_table_remove_item(&ui_hash, item);
+	}
+	
+	return true;
+}
+
 void exfat_idx_fini_by_service_id(service_id_t service_id)
 {
-	unsigned long ikey[] = {
-		[UIH_SID_KEY] = service_id 
-	};
-	unsigned long pkey[] = {
-		[UPH_SID_KEY] = service_id 
-	};
-
 	/*
 	 * Remove this instance's index structure from up_hash and ui_hash.
@@ -583,6 +542,6 @@
 	 */
 	fibril_mutex_lock(&used_lock);
-	hash_table_remove(&up_hash, pkey, 1);
-	hash_table_remove(&ui_hash, ikey, 1);
+	hash_table_apply(&up_hash, rm_pos_service_id, &service_id);
+	hash_table_apply(&ui_hash, rm_idx_service_id, &service_id);
 	fibril_mutex_unlock(&used_lock);
 
Index: uspace/srv/fs/exfat/exfat_ops.c
===================================================================
--- uspace/srv/fs/exfat/exfat_ops.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/exfat/exfat_ops.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -54,4 +54,5 @@
 #include <byteorder.h>
 #include <adt/hash_table.h>
+#include <adt/hash.h>
 #include <adt/list.h>
 #include <assert.h>
Index: uspace/srv/fs/ext2fs/ext2fs_ops.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -49,4 +49,5 @@
 #include <byteorder.h>
 #include <adt/hash_table.h>
+#include <adt/hash.h>
 #include <adt/list.h>
 #include <assert.h>
@@ -62,8 +63,4 @@
 #define EXT2FS_NODE(node)	((node) ? (ext2fs_node_t *) (node)->data : NULL)
 #define EXT2FS_DBG(format, ...) {if (false) printf("ext2fs: %s: " format "\n", __FUNCTION__, ##__VA_ARGS__);}
-#define OPEN_NODES_KEYS 2
-#define OPEN_NODES_DEV_HANDLE_KEY 0
-#define OPEN_NODES_INODE_KEY 1
-#define OPEN_NODES_BUCKETS 256
 
 typedef struct ext2fs_instance {
@@ -78,5 +75,5 @@
 	ext2_inode_ref_t *inode_ref;
 	fs_node_t *fs_node;
-	link_t link;
+	ht_link_t link;
 	unsigned int references;
 } ext2fs_node_t;
@@ -122,36 +119,44 @@
 static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
 
-/* Hash table interface for open nodes hash table */
-static hash_index_t open_nodes_hash(unsigned long key[])
-{
-	/* TODO: This is very simple and probably can be improved */
-	return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
-}
-
-static int open_nodes_compare(unsigned long key[], hash_count_t keys, 
-    link_t *item)
-{
-	ext2fs_node_t *enode = hash_table_get_instance(item, ext2fs_node_t, link);
-	assert(keys > 0);
-	if (enode->instance->service_id !=
-	    ((service_id_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {
-		return false;
-	}
-	if (keys == 1) {
-		return true;
-	}
-	assert(keys == 2);
-	return (enode->inode_ref->index == key[OPEN_NODES_INODE_KEY]);
-}
-
-static void open_nodes_remove_cb(link_t *link)
-{
-	/* We don't use remove callback for this hash table */
-}
-
-static hash_table_operations_t open_nodes_ops = {
+/* 
+ * Hash table interface for open nodes hash table 
+ */
+
+typedef struct {
+	service_id_t service_id;
+	fs_index_t index;
+} node_key_t;
+
+static size_t open_nodes_key_hash(void *key)
+{
+	node_key_t *node_key = (node_key_t*)key;
+	return hash_combine(node_key->service_id, node_key->index);
+}
+
+static size_t open_nodes_hash(const ht_link_t *item)
+{
+	ext2fs_node_t *enode = hash_table_get_inst(item, ext2fs_node_t, link);
+
+	assert(enode->instance);
+	assert(enode->inode_ref);
+	
+	return hash_combine(enode->instance->service_id, enode->inode_ref->index);
+}
+
+static bool open_nodes_key_equal(void *key, const ht_link_t *item)
+{
+	node_key_t *node_key = (node_key_t*)key;
+	ext2fs_node_t *enode = hash_table_get_inst(item, ext2fs_node_t, link);
+	
+	return node_key->service_id == enode->instance->service_id
+		&& node_key->index == enode->inode_ref->index;
+}
+
+static hash_table_ops_t open_nodes_ops = {
 	.hash = open_nodes_hash,
-	.compare = open_nodes_compare,
-	.remove_callback = open_nodes_remove_cb,
+	.key_hash = open_nodes_key_hash,
+	.key_equal = open_nodes_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL,
 };
 
@@ -161,6 +166,5 @@
 int ext2fs_global_init(void)
 {
-	if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
-	    OPEN_NODES_KEYS, &open_nodes_ops)) {
+	if (!hash_table_create(&open_nodes, 0, 0, &open_nodes_ops)) {
 		return ENOMEM;
 	}
@@ -316,12 +320,12 @@
 	
 	/* Check if the node is not already open */
-	unsigned long key[] = {
-		[OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id,
-		[OPEN_NODES_INODE_KEY] = index,
+	node_key_t key = {
+		.service_id = inst->service_id,
+		.index = index
 	};
-	link_t *already_open = hash_table_find(&open_nodes, key);
+	ht_link_t *already_open = hash_table_find(&open_nodes, &key);
 
 	if (already_open) {
-		enode = hash_table_get_instance(already_open, ext2fs_node_t, link);
+		enode = hash_table_get_inst(already_open, ext2fs_node_t, link);
 		*rfn = enode->fs_node;
 		enode->references++;
@@ -357,10 +361,9 @@
 	enode->references = 1;
 	enode->fs_node = node;
-	link_initialize(&enode->link);
 	
 	node->data = enode;
 	*rfn = node;
 	
-	hash_table_insert(&open_nodes, key, &enode->link);
+	hash_table_insert(&open_nodes, &enode->link);
 	inst->open_nodes_count++;
 	
@@ -408,15 +411,15 @@
 int ext2fs_node_put_core(ext2fs_node_t *enode)
 {
-	int rc;
-
-	unsigned long key[] = {
-		[OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->service_id,
-		[OPEN_NODES_INODE_KEY] = enode->inode_ref->index,
+	node_key_t key = {
+		.service_id = enode->instance->service_id,
+		.index = enode->inode_ref->index
 	};
-	hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
+
+	hash_table_remove(&open_nodes, &key);
+	
 	assert(enode->instance->open_nodes_count > 0);
 	enode->instance->open_nodes_count--;
 
-	rc = ext2_filesystem_put_inode_ref(enode->inode_ref);
+	int rc = ext2_filesystem_put_inode_ref(enode->inode_ref);
 	if (rc != EOK) {
 		EXT2FS_DBG("ext2_filesystem_put_inode_ref failed");
Index: uspace/srv/fs/ext4fs/ext4fs_ops.c
===================================================================
--- uspace/srv/fs/ext4fs/ext4fs_ops.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/ext4fs/ext4fs_ops.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -42,4 +42,5 @@
 #include <malloc.h>
 #include <adt/hash_table.h>
+#include <adt/hash.h>
 #include <ipc/loc.h>
 #include "ext4fs.h"
@@ -48,11 +49,4 @@
 #define EXT4FS_NODE(node) \
 	((node) ? (ext4fs_node_t *) (node)->data : NULL)
-
-#define OPEN_NODES_KEYS  2
-
-#define OPEN_NODES_DEV_HANDLE_KEY  0
-#define OPEN_NODES_INODE_KEY       1
-
-#define OPEN_NODES_BUCKETS  256
 
 /**
@@ -73,5 +67,5 @@
 	ext4_inode_ref_t *inode_ref;
 	fs_node_t *fs_node;
-	link_t link;
+	ht_link_t link;
 	unsigned int references;
 } ext4fs_node_t;
@@ -115,45 +109,37 @@
 
 /* Hash table interface for open nodes hash table */
-static hash_index_t open_nodes_hash(unsigned long key[])
-{
-	/* TODO: This is very simple and probably can be improved */
-	return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
-}
-
-/** Compare given item with values in hash table.
- *
- */
-static int open_nodes_compare(unsigned long key[], hash_count_t keys,
-    link_t *item)
-{
-	assert(keys > 0);
-	
-	ext4fs_node_t *enode =
-	    hash_table_get_instance(item, ext4fs_node_t, link);
-	
-	if (enode->instance->service_id !=
-	    ((service_id_t) key[OPEN_NODES_DEV_HANDLE_KEY]))
-		return false;
-	
-	if (keys == 1)
-		return true;
-	
-	assert(keys == 2);
-	
-	return (enode->inode_ref->index == key[OPEN_NODES_INODE_KEY]);
-}
-
-/** Empty callback to correct hash table initialization.
- *
- */
-static void open_nodes_remove_cb(link_t *link)
-{
-	/* We don't use remove callback for this hash table */
-}
-
-static hash_table_operations_t open_nodes_ops = {
+
+typedef struct {
+	service_id_t service_id;
+	fs_index_t index;
+} node_key_t;
+
+static size_t open_nodes_key_hash(void *key_arg)
+{
+	node_key_t *key = (node_key_t *)key_arg;
+	return hash_combine(key->service_id, key->index);
+}
+
+static size_t open_nodes_hash(const ht_link_t *item)
+{
+	ext4fs_node_t *enode = hash_table_get_inst(item, ext4fs_node_t, link);
+	return hash_combine(enode->instance->service_id, enode->inode_ref->index);	
+}
+
+static bool open_nodes_key_equal(void *key_arg, const ht_link_t *item)
+{
+	node_key_t *key = (node_key_t *)key_arg;
+	ext4fs_node_t *enode = hash_table_get_inst(item, ext4fs_node_t, link);
+	
+	return key->service_id == enode->instance->service_id
+		&& key->index == enode->inode_ref->index;
+}
+
+static hash_table_ops_t open_nodes_ops = {
 	.hash = open_nodes_hash,
-	.compare = open_nodes_compare,
-	.remove_callback = open_nodes_remove_cb,
+	.key_hash = open_nodes_key_hash,
+	.key_equal = open_nodes_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL,
 };
 
@@ -168,6 +154,5 @@
 int ext4fs_global_init(void)
 {
-	if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
-	    OPEN_NODES_KEYS, &open_nodes_ops))
+	if (!hash_table_create(&open_nodes, 0, 0, &open_nodes_ops))
 		return ENOMEM;
 	
@@ -315,13 +300,13 @@
 	
 	/* Check if the node is not already open */
-	unsigned long key[] = {
-		[OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id,
-		[OPEN_NODES_INODE_KEY] = index
+	node_key_t key = {
+		.service_id = inst->service_id,
+		.index = index
 	};
 	
-	link_t *already_open = hash_table_find(&open_nodes, key);
+	ht_link_t *already_open = hash_table_find(&open_nodes, &key);
 	ext4fs_node_t *enode = NULL;
 	if (already_open) {
-		enode = hash_table_get_instance(already_open, ext4fs_node_t, link);
+		enode = hash_table_get_inst(already_open, ext4fs_node_t, link);
 		*rfn = enode->fs_node;
 		enode->references++;
@@ -364,10 +349,9 @@
 	enode->references = 1;
 	enode->fs_node = fs_node;
-	link_initialize(&enode->link);
 	
 	fs_node->data = enode;
 	*rfn = fs_node;
 	
-	hash_table_insert(&open_nodes, key, &enode->link);
+	hash_table_insert(&open_nodes, &enode->link);
 	inst->open_nodes_count++;
 	
@@ -386,10 +370,5 @@
 int ext4fs_node_put_core(ext4fs_node_t *enode)
 {
-	unsigned long key[] = {
-		[OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->service_id,
-		[OPEN_NODES_INODE_KEY] = enode->inode_ref->index
-	};
-	
-	hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
+	hash_table_remove_item(&open_nodes, &enode->link);
 	assert(enode->instance->open_nodes_count > 0);
 	enode->instance->open_nodes_count--;
@@ -498,13 +477,6 @@
 	enode->references = 1;
 	
-	link_initialize(&enode->link);
-	
-	unsigned long key[] = {
-		[OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id,
-		[OPEN_NODES_INODE_KEY] = inode_ref->index
-	};
-	
 	fibril_mutex_lock(&open_nodes_lock);
-	hash_table_insert(&open_nodes, key, &enode->link);
+	hash_table_insert(&open_nodes, &enode->link);
 	fibril_mutex_unlock(&open_nodes_lock);
 	inst->open_nodes_count++;
Index: uspace/srv/fs/fat/fat.h
===================================================================
--- uspace/srv/fs/fat/fat.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/fat/fat.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -190,7 +190,7 @@
 typedef struct {
 	/** Used indices (position) hash table link. */
-	link_t		uph_link;
+	ht_link_t		uph_link;
 	/** Used indices (index) hash table link. */
-	link_t		uih_link;
+	ht_link_t		uih_link;
 
 	fibril_mutex_t	lock;
Index: uspace/srv/fs/fat/fat_idx.c
===================================================================
--- uspace/srv/fs/fat/fat_idx.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/fat/fat_idx.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -41,4 +41,5 @@
 #include <str.h>
 #include <adt/hash_table.h>
+#include <adt/hash.h>
 #include <adt/list.h>
 #include <assert.h>
@@ -58,6 +59,6 @@
  */
 typedef struct {
-	link_t		link;
-	service_id_t	service_id;
+	link_t link;
+	service_id_t service_id;
 
 	/** Next unassigned index. */
@@ -97,5 +98,5 @@
 			return u;
 	}
-	
+
 	if (lock)
 		fibril_mutex_unlock(&unused_lock);
@@ -113,70 +114,48 @@
 static hash_table_t up_hash;
 
-#define UPH_BUCKETS_LOG	12
-#define UPH_BUCKETS	(1 << UPH_BUCKETS_LOG)
-
-#define UPH_SID_KEY	0
-#define UPH_PFC_KEY	1
-#define UPH_PDI_KEY	2
-
-static hash_index_t pos_hash(unsigned long key[])
-{
-	service_id_t service_id = (service_id_t)key[UPH_SID_KEY];
-	fat_cluster_t pfc = (fat_cluster_t)key[UPH_PFC_KEY];
-	unsigned pdi = (unsigned)key[UPH_PDI_KEY];
-
-	hash_index_t h;
-
-	/*
-	 * The least significant half of all bits are the least significant bits
-	 * of the parent node's first cluster.
-	 *
-	 * The least significant half of the most significant half of all bits
-	 * are the least significant bits of the node's dentry index within the
-	 * parent directory node.
-	 *
-	 * The most significant half of the most significant half of all bits
-	 * are the least significant bits of the device handle.
-	 */
-	h = pfc & ((1 << (UPH_BUCKETS_LOG / 2)) - 1);
-	h |= (pdi & ((1 << (UPH_BUCKETS_LOG / 4)) - 1)) <<
-	    (UPH_BUCKETS_LOG / 2); 
-	h |= (service_id & ((1 << (UPH_BUCKETS_LOG / 4)) - 1)) <<
-	    (3 * (UPH_BUCKETS_LOG / 4));
-
-	return h;
-}
-
-static int pos_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	service_id_t service_id = (service_id_t)key[UPH_SID_KEY];
+typedef struct {
+	service_id_t service_id;
 	fat_cluster_t pfc;
 	unsigned pdi;
-	fat_idx_t *fidx = list_get_instance(item, fat_idx_t, uph_link);
-
-	switch (keys) {
-	case 1:
-		return (service_id == fidx->service_id);
-	case 3:
-		pfc = (fat_cluster_t) key[UPH_PFC_KEY];
-		pdi = (unsigned) key[UPH_PDI_KEY];
-		return (service_id == fidx->service_id) && (pfc == fidx->pfc) &&
-		    (pdi == fidx->pdi);
-	default:
-		assert((keys == 1) || (keys == 3));
-	}
-
-	return 0;
-}
-
-static void pos_remove_callback(link_t *item)
-{
-	/* nothing to do */
-}
-
-static hash_table_operations_t uph_ops = {
+} pos_key_t;
+
+static inline size_t pos_key_hash(void *key)
+{
+	pos_key_t *pos = (pos_key_t*)key;
+	
+	size_t hash = 0;
+	hash = hash_combine(pos->pfc, pos->pdi);
+	return hash_combine(hash, pos->service_id);
+}
+
+static size_t pos_hash(const ht_link_t *item)
+{
+	fat_idx_t *fidx = hash_table_get_inst(item, fat_idx_t, uph_link);
+	
+	pos_key_t pkey = {
+		.service_id = fidx->service_id,
+		.pfc = fidx->pfc,
+		.pdi = fidx->pdi,
+	};
+	
+	return pos_key_hash(&pkey);
+}
+
+static bool pos_key_equal(void *key, const ht_link_t *item)
+{
+	pos_key_t *pos = (pos_key_t*)key;
+	fat_idx_t *fidx = hash_table_get_inst(item, fat_idx_t, uph_link);
+	
+	return pos->service_id == fidx->service_id
+		&& pos->pdi == fidx->pdi
+		&& pos->pfc == fidx->pfc;
+}
+
+static hash_table_ops_t uph_ops = {
 	.hash = pos_hash,
-	.compare = pos_compare,
-	.remove_callback = pos_remove_callback,
+	.key_hash = pos_key_hash,
+	.key_equal = pos_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL,
 };
 
@@ -187,54 +166,41 @@
 static hash_table_t ui_hash;
 
-#define UIH_BUCKETS_LOG	12
-#define UIH_BUCKETS	(1 << UIH_BUCKETS_LOG)
-
-#define UIH_SID_KEY	0
-#define UIH_INDEX_KEY	1
-
-static hash_index_t idx_hash(unsigned long key[])
-{
-	service_id_t service_id = (service_id_t)key[UIH_SID_KEY];
-	fs_index_t index = (fs_index_t)key[UIH_INDEX_KEY];
-
-	hash_index_t h;
-
-	h = service_id & ((1 << (UIH_BUCKETS_LOG / 2)) - 1);
-	h |= (index & ((1 << (UIH_BUCKETS_LOG / 2)) - 1)) <<
-	    (UIH_BUCKETS_LOG / 2);
-
-	return h;
-}
-
-static int idx_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	service_id_t service_id = (service_id_t)key[UIH_SID_KEY];
+typedef struct {
+	service_id_t service_id;
 	fs_index_t index;
-	fat_idx_t *fidx = list_get_instance(item, fat_idx_t, uih_link);
-
-	switch (keys) {
-	case 1:
-		return (service_id == fidx->service_id);
-	case 2:
-		index = (fs_index_t) key[UIH_INDEX_KEY];
-		return (service_id == fidx->service_id) &&
-		    (index == fidx->index);
-	default:
-		assert((keys == 1) || (keys == 2));
-	}
-
-	return 0;
-}
-
-static void idx_remove_callback(link_t *item)
-{
-	fat_idx_t *fidx = list_get_instance(item, fat_idx_t, uih_link);
+} idx_key_t;
+
+static size_t idx_key_hash(void *key_arg)
+{
+	idx_key_t *key = (idx_key_t*)key_arg;
+	return hash_combine(key->service_id, key->index);
+}
+
+static size_t idx_hash(const ht_link_t *item)
+{
+	fat_idx_t *fidx = hash_table_get_inst(item, fat_idx_t, uih_link);
+	return hash_combine(fidx->service_id, fidx->index);
+}
+
+static bool idx_key_equal(void *key_arg, const ht_link_t *item)
+{
+	fat_idx_t *fidx = hash_table_get_inst(item, fat_idx_t, uih_link);
+	idx_key_t *key = (idx_key_t*)key_arg;
+	
+	return key->index == fidx->index && key->service_id == fidx->service_id;
+}
+
+static void idx_remove_callback(ht_link_t *item)
+{
+	fat_idx_t *fidx = hash_table_get_inst(item, fat_idx_t, uih_link);
 
 	free(fidx);
 }
 
-static hash_table_operations_t uih_ops = {
+static hash_table_ops_t uih_ops = {
 	.hash = idx_hash,
-	.compare = idx_compare,
+	.key_hash = idx_key_hash,
+	.key_equal = idx_key_equal,
+	.equal = NULL,
 	.remove_callback = idx_remove_callback,
 };
@@ -377,6 +343,4 @@
 	}
 		
-	link_initialize(&fidx->uph_link);
-	link_initialize(&fidx->uih_link);
 	fibril_mutex_initialize(&fidx->lock);
 	fidx->service_id = service_id;
@@ -401,10 +365,5 @@
 	}
 		
-	unsigned long ikey[] = {
-		[UIH_SID_KEY] = service_id,
-		[UIH_INDEX_KEY] = fidx->index,
-	};
-	
-	hash_table_insert(&ui_hash, ikey, &fidx->uih_link);
+	hash_table_insert(&ui_hash, &fidx->uih_link);
 	fibril_mutex_lock(&fidx->lock);
 	fibril_mutex_unlock(&used_lock);
@@ -418,15 +377,15 @@
 {
 	fat_idx_t *fidx;
-	link_t *l;
-	unsigned long pkey[] = {
-		[UPH_SID_KEY] = service_id,
-		[UPH_PFC_KEY] = pfc,
-		[UPH_PDI_KEY] = pdi,
+
+	pos_key_t pos_key = {
+		.service_id = service_id,
+		.pfc = pfc,
+		.pdi = pdi,
 	};
 
 	fibril_mutex_lock(&used_lock);
-	l = hash_table_find(&up_hash, pkey);
+	ht_link_t *l = hash_table_find(&up_hash, &pos_key);
 	if (l) {
-		fidx = hash_table_get_instance(l, fat_idx_t, uph_link);
+		fidx = hash_table_get_inst(l, fat_idx_t, uph_link);
 	} else {
 		int rc;
@@ -438,14 +397,9 @@
 		}
 		
-		unsigned long ikey[] = {
-			[UIH_SID_KEY] = service_id,
-			[UIH_INDEX_KEY] = fidx->index,
-		};
-	
 		fidx->pfc = pfc;
 		fidx->pdi = pdi;
 
-		hash_table_insert(&up_hash, pkey, &fidx->uph_link);
-		hash_table_insert(&ui_hash, ikey, &fidx->uih_link);
+		hash_table_insert(&up_hash, &fidx->uph_link);
+		hash_table_insert(&ui_hash, &fidx->uih_link);
 	}
 	fibril_mutex_lock(&fidx->lock);
@@ -457,12 +411,6 @@
 void fat_idx_hashin(fat_idx_t *idx)
 {
-	unsigned long pkey[] = {
-		[UPH_SID_KEY] = idx->service_id,
-		[UPH_PFC_KEY] = idx->pfc,
-		[UPH_PDI_KEY] = idx->pdi,
-	};
-
-	fibril_mutex_lock(&used_lock);
-	hash_table_insert(&up_hash, pkey, &idx->uph_link);
+	fibril_mutex_lock(&used_lock);
+	hash_table_insert(&up_hash, &idx->uph_link);
 	fibril_mutex_unlock(&used_lock);
 }
@@ -470,12 +418,6 @@
 void fat_idx_hashout(fat_idx_t *idx)
 {
-	unsigned long pkey[] = {
-		[UPH_SID_KEY] = idx->service_id,
-		[UPH_PFC_KEY] = idx->pfc,
-		[UPH_PDI_KEY] = idx->pdi,
-	};
-
-	fibril_mutex_lock(&used_lock);
-	hash_table_remove(&up_hash, pkey, 3);
+	fibril_mutex_lock(&used_lock);
+	hash_table_remove_item(&up_hash, &idx->uph_link);
 	fibril_mutex_unlock(&used_lock);
 }
@@ -485,14 +427,14 @@
 {
 	fat_idx_t *fidx = NULL;
-	link_t *l;
-	unsigned long ikey[] = {
-		[UIH_SID_KEY] = service_id,
-		[UIH_INDEX_KEY] = index,
+
+	idx_key_t idx_key = {
+		.service_id = service_id,
+		.index = index,
 	};
 
 	fibril_mutex_lock(&used_lock);
-	l = hash_table_find(&ui_hash, ikey);
+	ht_link_t *l = hash_table_find(&ui_hash, &idx_key);
 	if (l) {
-		fidx = hash_table_get_instance(l, fat_idx_t, uih_link);
+		fidx = hash_table_get_inst(l, fat_idx_t, uih_link);
 		fibril_mutex_lock(&fidx->lock);
 	}
@@ -508,10 +450,8 @@
 void fat_idx_destroy(fat_idx_t *idx)
 {
-	unsigned long ikey[] = {
-		[UIH_SID_KEY] = idx->service_id,
-		[UIH_INDEX_KEY] = idx->index,
+	idx_key_t idx_key = {
+		.service_id = idx->service_id,
+		.index = idx->index,
 	};
-	service_id_t service_id = idx->service_id;
-	fs_index_t index = idx->index;
 
 	assert(idx->pfc == FAT_CLST_RES0);
@@ -523,8 +463,8 @@
 	 * the index hash only.
 	 */
-	hash_table_remove(&ui_hash, ikey, 2);
+	hash_table_remove(&ui_hash, &idx_key);
 	fibril_mutex_unlock(&used_lock);
 	/* Release the VFS index. */
-	fat_index_free(service_id, index);
+	fat_index_free(idx_key.service_id, idx_key.index);
 	/* The index structure itself is freed in idx_remove_callback(). */
 }
@@ -532,7 +472,7 @@
 int fat_idx_init(void)
 {
-	if (!hash_table_create(&up_hash, UPH_BUCKETS, 3, &uph_ops)) 
+	if (!hash_table_create(&up_hash, 0, 0, &uph_ops)) 
 		return ENOMEM;
-	if (!hash_table_create(&ui_hash, UIH_BUCKETS, 2, &uih_ops)) {
+	if (!hash_table_create(&ui_hash, 0, 0, &uih_ops)) {
 		hash_table_destroy(&up_hash);
 		return ENOMEM;
@@ -544,4 +484,5 @@
 {
 	/* We assume the hash tables are empty. */
+	assert(hash_table_empty(&up_hash) && hash_table_empty(&ui_hash));
 	hash_table_destroy(&up_hash);
 	hash_table_destroy(&ui_hash);
@@ -568,13 +509,30 @@
 }
 
+static bool rm_pos_service_id(ht_link_t *item, void *arg)
+{
+	service_id_t service_id = *(service_id_t*)arg;
+	fat_idx_t *fidx = hash_table_get_inst(item, fat_idx_t, uph_link);
+
+	if (fidx->service_id == service_id) {
+		hash_table_remove_item(&up_hash, item);
+	}
+	
+	return true;
+}
+
+static bool rm_idx_service_id(ht_link_t *item, void *arg)
+{
+	service_id_t service_id = *(service_id_t*)arg;
+	fat_idx_t *fidx = hash_table_get_inst(item, fat_idx_t, uih_link);
+
+	if (fidx->service_id == service_id) {
+		hash_table_remove_item(&ui_hash, item);
+	}
+	
+	return true;
+}
+
 void fat_idx_fini_by_service_id(service_id_t service_id)
 {
-	unsigned long ikey[] = {
-		[UIH_SID_KEY] = service_id
-	};
-	unsigned long pkey[] = {
-		[UPH_SID_KEY] = service_id
-	};
-
 	/*
 	 * Remove this instance's index structure from up_hash and ui_hash.
@@ -583,6 +541,6 @@
 	 */
 	fibril_mutex_lock(&used_lock);
-	hash_table_remove(&up_hash, pkey, 1);
-	hash_table_remove(&ui_hash, ikey, 1);
+	hash_table_apply(&up_hash, rm_pos_service_id, &service_id);
+	hash_table_apply(&ui_hash, rm_idx_service_id, &service_id);
 	fibril_mutex_unlock(&used_lock);
 
Index: uspace/srv/fs/locfs/locfs_ops.c
===================================================================
--- uspace/srv/fs/locfs/locfs_ops.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/locfs/locfs_ops.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -61,5 +61,5 @@
 	async_sess_t *sess;       /**< If NULL, the structure is incomplete. */
 	size_t refcount;
-	link_t link;
+	ht_link_t link;
 	fibril_condvar_t cv;      /**< Broadcast when completed. */
 } service_t;
@@ -71,28 +71,33 @@
 static FIBRIL_MUTEX_INITIALIZE(services_mutex);
 
-#define SERVICES_KEYS        1
-#define SERVICES_KEY_HANDLE  0
-#define SERVICES_BUCKETS     256
-
 /* Implementation of hash table interface for the nodes hash table. */
-static hash_index_t services_hash(unsigned long key[])
-{
-	return key[SERVICES_KEY_HANDLE] % SERVICES_BUCKETS;
-}
-
-static int services_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	service_t *dev = hash_table_get_instance(item, service_t, link);
-	return (dev->service_id == (service_id_t) key[SERVICES_KEY_HANDLE]);
-}
-
-static void services_remove_callback(link_t *item)
-{
-	free(hash_table_get_instance(item, service_t, link));
-}
-
-static hash_table_operations_t services_ops = {
+
+static size_t services_key_hash(void *key)
+{
+	return *(service_id_t*)key;
+}
+
+static size_t services_hash(const ht_link_t *item)
+{
+	service_t *dev = hash_table_get_inst(item, service_t, link);
+	return dev->service_id;
+}
+
+static bool services_key_equal(void *key, const ht_link_t *item)
+{
+	service_t *dev = hash_table_get_inst(item, service_t, link);
+	return (dev->service_id == *(service_id_t*)key);
+}
+
+static void services_remove_callback(ht_link_t *item)
+{
+	free(hash_table_get_inst(item, service_t, link));
+}
+
+static hash_table_ops_t services_ops = {
 	.hash = services_hash,
-	.compare = services_compare,
+	.key_hash = services_key_hash,
+	.key_equal = services_key_equal,
+	.equal = NULL, 
 	.remove_callback = services_remove_callback
 };
@@ -229,12 +234,8 @@
 		/* Device node */
 		
-		unsigned long key[] = {
-			[SERVICES_KEY_HANDLE] = (unsigned long) node->service_id
-		};
-		link_t *lnk;
-		
 		fibril_mutex_lock(&services_mutex);
+		ht_link_t *lnk;
 restart:
-		lnk = hash_table_find(&services, key);
+		lnk = hash_table_find(&services, &node->service_id);
 		if (lnk == NULL) {
 			service_t *dev = (service_t *) malloc(sizeof(service_t));
@@ -256,5 +257,5 @@
 			 * below.
 			 */
-			hash_table_insert(&services, key, &dev->link);
+			hash_table_insert(&services, &dev->link);
 			
 			/*
@@ -279,5 +280,5 @@
 				 * entry and free the device structure.
 				 */
-				hash_table_remove(&services, key, SERVICES_KEYS);
+				hash_table_remove(&services, &node->service_id);
 				fibril_mutex_unlock(&services_mutex);
 				
@@ -288,5 +289,5 @@
 			dev->sess = sess;
 		} else {
-			service_t *dev = hash_table_get_instance(lnk, service_t, link);
+			service_t *dev = hash_table_get_inst(lnk, service_t, link);
 			
 			if (!dev->sess) {
@@ -450,6 +451,5 @@
 bool locfs_init(void)
 {
-	if (!hash_table_create(&services, SERVICES_BUCKETS,
-	    SERVICES_KEYS, &services_ops))
+	if (!hash_table_create(&services, 0,  0, &services_ops))
 		return false;
 	
@@ -555,10 +555,7 @@
 		/* Device node */
 		
-		unsigned long key[] = {
-			[SERVICES_KEY_HANDLE] = (unsigned long) index
-		};
-		
 		fibril_mutex_lock(&services_mutex);
-		link_t *lnk = hash_table_find(&services, key);
+		service_id_t service_index = index;
+		ht_link_t *lnk = hash_table_find(&services, &service_index);
 		if (lnk == NULL) {
 			fibril_mutex_unlock(&services_mutex);
@@ -566,5 +563,5 @@
 		}
 		
-		service_t *dev = hash_table_get_instance(lnk, service_t, link);
+		service_t *dev = hash_table_get_inst(lnk, service_t, link);
 		assert(dev->sess);
 		
@@ -621,10 +618,8 @@
 	if (type == LOC_OBJECT_SERVICE) {
 		/* Device node */
-		unsigned long key[] = {
-			[SERVICES_KEY_HANDLE] = (unsigned long) index
-		};
 		
 		fibril_mutex_lock(&services_mutex);
-		link_t *lnk = hash_table_find(&services, key);
+		service_id_t service_index = index;
+		ht_link_t *lnk = hash_table_find(&services, &service_index);
 		if (lnk == NULL) {
 			fibril_mutex_unlock(&services_mutex);
@@ -632,5 +627,5 @@
 		}
 		
-		service_t *dev = hash_table_get_instance(lnk, service_t, link);
+		service_t *dev = hash_table_get_inst(lnk, service_t, link);
 		assert(dev->sess);
 		
@@ -691,10 +686,8 @@
 	
 	if (type == LOC_OBJECT_SERVICE) {
-		unsigned long key[] = {
-			[SERVICES_KEY_HANDLE] = (unsigned long) index
-		};
 		
 		fibril_mutex_lock(&services_mutex);
-		link_t *lnk = hash_table_find(&services, key);
+		service_id_t service_index = index;
+		ht_link_t *lnk = hash_table_find(&services, &service_index);
 		if (lnk == NULL) {
 			fibril_mutex_unlock(&services_mutex);
@@ -702,5 +695,5 @@
 		}
 		
-		service_t *dev = hash_table_get_instance(lnk, service_t, link);
+		service_t *dev = hash_table_get_inst(lnk, service_t, link);
 		assert(dev->sess);
 		dev->refcount--;
@@ -708,5 +701,6 @@
 		if (dev->refcount == 0) {
 			async_hangup(dev->sess);
-			hash_table_remove(&services, key, SERVICES_KEYS);
+			service_id_t service_index = index;
+			hash_table_remove(&services, &service_index);
 		}
 		
@@ -732,10 +726,8 @@
 	
 	if (type == LOC_OBJECT_SERVICE) {
-		unsigned long key[] = {
-			[SERVICES_KEY_HANDLE] = (unsigned long) index
-		};
-		
+
 		fibril_mutex_lock(&services_mutex);
-		link_t *lnk = hash_table_find(&services, key);
+		service_id_t service_index = index;
+		ht_link_t *lnk = hash_table_find(&services, &service_index);
 		if (lnk == NULL) {
 			fibril_mutex_unlock(&services_mutex);
@@ -743,5 +735,5 @@
 		}
 		
-		service_t *dev = hash_table_get_instance(lnk, service_t, link);
+		service_t *dev = hash_table_get_inst(lnk, service_t, link);
 		assert(dev->sess);
 		
Index: uspace/srv/fs/mfs/mfs.h
===================================================================
--- uspace/srv/fs/mfs/mfs.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/mfs/mfs.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -142,5 +142,5 @@
 	unsigned refcnt;
 	fs_node_t *fsnode;
-	link_t link;
+	ht_link_t link;
 };
 
Index: uspace/srv/fs/mfs/mfs_ops.c
===================================================================
--- uspace/srv/fs/mfs/mfs_ops.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/mfs/mfs_ops.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -35,10 +35,7 @@
 #include <align.h>
 #include <adt/hash_table.h>
+#include <adt/hash.h>
 #include "mfs.h"
 
-#define OPEN_NODES_KEYS 2
-#define OPEN_NODES_SERVICE_KEY 0
-#define OPEN_NODES_INODE_KEY 1
-#define OPEN_NODES_BUCKETS 256
 
 static bool check_magic_number(uint16_t magic, bool *native,
@@ -61,8 +58,4 @@
 static int mfs_unlink(fs_node_t *, fs_node_t *, const char *name);
 static int mfs_destroy_node(fs_node_t *fn);
-static hash_index_t open_nodes_hash(unsigned long key[]);
-static int open_nodes_compare(unsigned long key[], hash_count_t keys,
-    link_t *item);
-static void open_nodes_remove_cb(link_t *link);
 static int mfs_node_get(fs_node_t **rfn, service_id_t service_id,
     fs_index_t index);
@@ -95,38 +88,40 @@
 
 /* Hash table interface for open nodes hash table */
-static hash_index_t
-open_nodes_hash(unsigned long key[])
-{
-	/* TODO: This is very simple and probably can be improved */
-	return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
-}
-
-static int
-open_nodes_compare(unsigned long key[], hash_count_t keys,
-    link_t *item)
-{
-	struct mfs_node *mnode = hash_table_get_instance(item, struct mfs_node, link);
-	assert(keys > 0);
-	if (mnode->instance->service_id !=
-	    ((service_id_t) key[OPEN_NODES_SERVICE_KEY])) {
-		return false;
-	}
-	if (keys == 1) {
-		return true;
-	}
-	assert(keys == 2);
-	return (mnode->ino_i->index == key[OPEN_NODES_INODE_KEY]);
-}
-
-static void
-open_nodes_remove_cb(link_t *link)
-{
-	/* We don't use remove callback for this hash table */
-}
-
-static hash_table_operations_t open_nodes_ops = {
+
+typedef struct {
+	service_id_t service_id;
+	fs_index_t index;
+} node_key_t;
+
+static size_t
+open_nodes_key_hash(void *key)
+{
+	node_key_t *node_key = (node_key_t*)key;
+	return hash_combine(node_key->service_id, node_key->index);
+}
+
+static size_t
+open_nodes_hash(const ht_link_t *item)
+{
+	struct mfs_node *m = hash_table_get_inst(item, struct mfs_node, link);
+	return hash_combine(m->instance->service_id, m->ino_i->index);
+}
+
+static bool
+open_nodes_key_equal(void *key, const ht_link_t *item)
+{
+	node_key_t *node_key = (node_key_t*)key;
+	struct mfs_node *mnode = hash_table_get_inst(item, struct mfs_node, link);
+
+	return node_key->service_id == mnode->instance->service_id
+		&& node_key->index == mnode->ino_i->index;
+}
+
+static hash_table_ops_t open_nodes_ops = {
 	.hash = open_nodes_hash,
-	.compare = open_nodes_compare,
-	.remove_callback = open_nodes_remove_cb,
+	.key_hash = open_nodes_key_hash,
+	.key_equal = open_nodes_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL,
 };
 
@@ -134,6 +129,5 @@
 mfs_global_init(void)
 {
-	if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
-	    OPEN_NODES_KEYS, &open_nodes_ops)) {
+	if (!hash_table_create(&open_nodes, 0, 0, &open_nodes_ops)) {
 		return ENOMEM;
 	}
@@ -406,13 +400,6 @@
 	mnode->refcnt = 1;
 
-	link_initialize(&mnode->link);
-
-	unsigned long key[] = {
-		[OPEN_NODES_SERVICE_KEY] = inst->service_id,
-		[OPEN_NODES_INODE_KEY] = inum,
-	};
-
 	fibril_mutex_lock(&open_nodes_lock);
-	hash_table_insert(&open_nodes, key, &mnode->link);
+	hash_table_insert(&open_nodes, &mnode->link);
 	fibril_mutex_unlock(&open_nodes_lock);
 	inst->open_nodes_cnt++;
@@ -513,9 +500,5 @@
 	mnode->refcnt--;
 	if (mnode->refcnt == 0) {
-		unsigned long key[] = {
-			[OPEN_NODES_SERVICE_KEY] = mnode->instance->service_id,
-			[OPEN_NODES_INODE_KEY] = mnode->ino_i->index
-		};
-		hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
+		hash_table_remove_item(&open_nodes, &mnode->link);
 		assert(mnode->instance->open_nodes_cnt > 0);
 		mnode->instance->open_nodes_cnt--;
@@ -576,12 +559,13 @@
 
 	/* Check if the node is not already open */
-	unsigned long key[] = {
-		[OPEN_NODES_SERVICE_KEY] = inst->service_id,
-		[OPEN_NODES_INODE_KEY] = index,
+	node_key_t key = {
+		.service_id = inst->service_id,
+		.index = index
 	};
-	link_t *already_open = hash_table_find(&open_nodes, key);
+	
+	ht_link_t *already_open = hash_table_find(&open_nodes, &key);
 
 	if (already_open) {
-		mnode = hash_table_get_instance(already_open, struct mfs_node, link);
+		mnode = hash_table_get_inst(already_open, struct mfs_node, link);
 		*rfn = mnode->fsnode;
 		mnode->refcnt++;
@@ -614,5 +598,4 @@
 	mnode->ino_i = ino_i;
 	mnode->refcnt = 1;
-	link_initialize(&mnode->link);
 
 	mnode->instance = inst;
@@ -621,5 +604,5 @@
 	*rfn = node;
 
-	hash_table_insert(&open_nodes, key, &mnode->link);
+	hash_table_insert(&open_nodes, &mnode->link);
 	inst->open_nodes_cnt++;
 
Index: uspace/srv/fs/tmpfs/tmpfs.h
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/tmpfs/tmpfs.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -62,5 +62,5 @@
 	fs_index_t index;	/**< TMPFS node index. */
 	service_id_t service_id;/**< Service ID of block device. */
-	link_t nh_link;		/**< Nodes hash table link. */
+	ht_link_t nh_link;		/**< Nodes hash table link. */
 	tmpfs_dentry_type_t type;
 	unsigned lnkcnt;	/**< Link count. */
Index: uspace/srv/fs/tmpfs/tmpfs_ops.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -50,4 +50,5 @@
 #include <sys/types.h>
 #include <adt/hash_table.h>
+#include <adt/hash.h>
 #include <as.h>
 #include <libfs.h>
@@ -55,6 +56,4 @@
 #define min(a, b)		((a) < (b) ? (a) : (b))
 #define max(a, b)		((a) > (b) ? (a) : (b))
-
-#define NODES_BUCKETS	256
 
 /** All root nodes have index 0. */
@@ -142,35 +141,36 @@
 hash_table_t nodes;
 
-#define NODES_KEY_DEV	0	
-#define NODES_KEY_INDEX	1
-
-/* Implementation of hash table interface for the nodes hash table. */
-static hash_index_t nodes_hash(unsigned long key[])
-{
-	return key[NODES_KEY_INDEX] % NODES_BUCKETS;
-}
-
-static int nodes_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	tmpfs_node_t *nodep = hash_table_get_instance(item, tmpfs_node_t,
-	    nh_link);
-	
-	switch (keys) {
-	case 1:
-		return (nodep->service_id == key[NODES_KEY_DEV]);
-	case 2:	
-		return ((nodep->service_id == key[NODES_KEY_DEV]) &&
-		    (nodep->index == key[NODES_KEY_INDEX]));
-	default:
-		assert((keys == 1) || (keys == 2));
-	}
-
-	return 0;
-}
-
-static void nodes_remove_callback(link_t *item)
-{
-	tmpfs_node_t *nodep = hash_table_get_instance(item, tmpfs_node_t,
-	    nh_link);
+/* 
+ * Implementation of hash table interface for the nodes hash table. 
+ */
+
+typedef struct {
+	service_id_t service_id;
+	fs_index_t index;
+} node_key_t;
+
+static size_t nodes_key_hash(void *k)
+{
+	node_key_t *key = (node_key_t *)k;
+	return hash_combine(key->service_id, key->index);
+}
+
+static size_t nodes_hash(const ht_link_t *item)
+{
+	tmpfs_node_t *nodep = hash_table_get_inst(item, tmpfs_node_t, nh_link);
+	return hash_combine(nodep->service_id, nodep->index);
+}
+
+static bool nodes_key_equal(void *key_arg, const ht_link_t *item)
+{
+	tmpfs_node_t *node = hash_table_get_inst(item, tmpfs_node_t, nh_link);
+	node_key_t *key = (node_key_t *)key_arg;
+	
+	return key->service_id == node->service_id && key->index == node->index;
+}
+
+static void nodes_remove_callback(ht_link_t *item)
+{
+	tmpfs_node_t *nodep = hash_table_get_inst(item, tmpfs_node_t, nh_link);
 
 	while (!list_empty(&nodep->cs_list)) {
@@ -192,7 +192,9 @@
 
 /** TMPFS nodes hash table operations. */
-hash_table_operations_t nodes_ops = {
+hash_table_ops_t nodes_ops = {
 	.hash = nodes_hash,
-	.compare = nodes_compare,
+	.key_hash = nodes_key_hash,
+	.key_equal = nodes_key_equal,
+	.equal = NULL,
 	.remove_callback = nodes_remove_callback
 };
@@ -207,5 +209,4 @@
 	nodep->size = 0;
 	nodep->data = NULL;
-	link_initialize(&nodep->nh_link);
 	list_initialize(&nodep->cs_list);
 }
@@ -220,5 +221,5 @@
 bool tmpfs_init(void)
 {
-	if (!hash_table_create(&nodes, NODES_BUCKETS, 2, &nodes_ops))
+	if (!hash_table_create(&nodes, 0, 0, &nodes_ops))
 		return false;
 	
@@ -238,17 +239,18 @@
 }
 
+static bool rm_service_id_nodes(ht_link_t *item, void *arg)
+{
+	service_id_t sid = *(service_id_t*)arg;
+	tmpfs_node_t *node = hash_table_get_inst(item, tmpfs_node_t, nh_link);
+	
+	if (node->service_id == sid) {
+		hash_table_remove_item(&nodes, &node->nh_link);
+	}
+	return true;
+}
+
 static void tmpfs_instance_done(service_id_t service_id)
-{
-	unsigned long key[] = {
-		[NODES_KEY_DEV] = service_id
-	};
-	/*
-	 * Here we are making use of one special feature of our hash table
-	 * implementation, which allows to remove more items based on a partial
-	 * key match. In the following, we are going to remove all nodes
-	 * matching our device handle. The nodes_remove_callback() function will
-	 * take care of resource deallocation.
-	 */
-	hash_table_remove(&nodes, key, 1);
+{	
+	hash_table_apply(&nodes, rm_service_id_nodes, &service_id);
 }
 
@@ -272,12 +274,14 @@
 int tmpfs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
 {
-	unsigned long key[] = {
-		[NODES_KEY_DEV] = service_id,
-		[NODES_KEY_INDEX] = index
+	node_key_t key = {
+		.service_id = service_id,
+		.index = index
 	};
-	link_t *lnk = hash_table_find(&nodes, key);
+	
+	ht_link_t *lnk = hash_table_find(&nodes, &key);
+	
 	if (lnk) {
 		tmpfs_node_t *nodep;
-		nodep = hash_table_get_instance(lnk, tmpfs_node_t, nh_link);
+		nodep = hash_table_get_inst(lnk, tmpfs_node_t, nh_link);
 		*rfn = FS_NODE(nodep);
 	} else {
@@ -331,9 +335,5 @@
 
 	/* Insert the new node into the nodes hash table. */
-	unsigned long key[] = {
-		[NODES_KEY_DEV] = nodep->service_id,
-		[NODES_KEY_INDEX] = nodep->index
-	};
-	hash_table_insert(&nodes, key, &nodep->nh_link);
+	hash_table_insert(&nodes, &nodep->nh_link);
 	*rfn = FS_NODE(nodep);
 	return EOK;
@@ -346,10 +346,6 @@
 	assert(!nodep->lnkcnt);
 	assert(list_empty(&nodep->cs_list));
-
-	unsigned long key[] = {
-		[NODES_KEY_DEV] = nodep->service_id,
-		[NODES_KEY_INDEX] = nodep->index
-	};
-	hash_table_remove(&nodes, key, 2);
+	
+	hash_table_remove_item(&nodes, &nodep->nh_link);
 
 	/*
@@ -476,14 +472,14 @@
 	 * Lookup the respective TMPFS node.
 	 */
-	link_t *hlp;
-	unsigned long key[] = {
-		[NODES_KEY_DEV] = service_id,
-		[NODES_KEY_INDEX] = index
+	node_key_t key = {
+		.service_id = service_id,
+		.index = index
 	};
-	hlp = hash_table_find(&nodes, key);
+	
+	ht_link_t *hlp = hash_table_find(&nodes, &key);
 	if (!hlp)
 		return ENOENT;
-	tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
-	    nh_link);
+	
+	tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t, nh_link);
 	
 	/*
@@ -538,14 +534,15 @@
 	 * Lookup the respective TMPFS node.
 	 */
-	link_t *hlp;
-	unsigned long key[] = {
-		[NODES_KEY_DEV] = service_id,
-		[NODES_KEY_INDEX] = index
+	node_key_t key = {
+		.service_id = service_id,
+		.index = index
 	};
-	hlp = hash_table_find(&nodes, key);
+	
+	ht_link_t *hlp = hash_table_find(&nodes, &key);
+	
 	if (!hlp)
 		return ENOENT;
-	tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
-	    nh_link);
+	
+	tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t, nh_link);
 
 	/*
@@ -600,12 +597,14 @@
 	 * Lookup the respective TMPFS node.
 	 */
-	unsigned long key[] = {
-		[NODES_KEY_DEV] = service_id,
-		[NODES_KEY_INDEX] = index
+	node_key_t key = {
+		.service_id = service_id,
+		.index = index
 	};
-	link_t *hlp = hash_table_find(&nodes, key);
+	
+	ht_link_t *hlp = hash_table_find(&nodes, &key);
+	
 	if (!hlp)
 		return ENOENT;
-	tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t, nh_link);
+	tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t, nh_link);
 	
 	if (size == nodep->size)
@@ -636,13 +635,13 @@
 static int tmpfs_destroy(service_id_t service_id, fs_index_t index)
 {
-	link_t *hlp;
-	unsigned long key[] = {
-		[NODES_KEY_DEV] = service_id,
-		[NODES_KEY_INDEX] = index
+	node_key_t key = {
+		.service_id = service_id,
+		.index = index
 	};
-	hlp = hash_table_find(&nodes, key);
+	
+	ht_link_t *hlp = hash_table_find(&nodes, &key);
 	if (!hlp)
 		return ENOENT;
-	tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
+	tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t,
 	    nh_link);
 	return tmpfs_destroy_node(FS_NODE(nodep));
Index: uspace/srv/fs/udf/udf.h
===================================================================
--- uspace/srv/fs/udf/udf.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/udf/udf.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -42,4 +42,5 @@
 #include "../../vfs/vfs.h"
 #include "udf_types.h"
+#include <adt/hash_table.h>
 
 #define UDF_NODE(node) \
@@ -105,5 +106,5 @@
 	
 	fs_index_t index;  /* FID logical block */
-	link_t link;
+	ht_link_t link;
 	size_t ref_cnt;
 	size_t link_cnt;
Index: uspace/srv/fs/udf/udf_idx.c
===================================================================
--- uspace/srv/fs/udf/udf_idx.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/fs/udf/udf_idx.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -42,66 +42,46 @@
 #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"
 
-#define UDF_IDX_KEYS  2
-#define UDF_IDX_KEY   1
-
-#define UDF_IDX_SERVICE_ID_KEY  0
-#define UDF_IDX_BUCKETS         1024
-
 static FIBRIL_MUTEX_INITIALIZE(udf_idx_lock);
 
 static hash_table_t udf_idx;
 
-/** Calculate value of hash by key
- *
- * @param Key for calculation of function
- *
- * @return Value of hash function
- *
- */
-static hash_index_t udf_idx_hash(unsigned long key[])
-{
-	/* TODO: This is very simple and probably can be improved */
-	return key[UDF_IDX_KEY] % UDF_IDX_BUCKETS;
-}
-
-/** Compare two items of hash table
- *
- * @param key  Key of hash table item. Include several items.
- * @param keys Number of parts of key.
- * @param item Item of hash table
- *
- * @return True if input value of key equivalent key of node from hash table
- *
- */
-static int udf_idx_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	assert(keys > 0);
-	
-	udf_node_t *node = hash_table_get_instance(item, udf_node_t, link);
-	
-	if (node->instance->service_id !=
-	    ((service_id_t) key[UDF_IDX_SERVICE_ID_KEY]))
-		return false;
-	
-	assert(keys == 2);
-	return (node->index == key[UDF_IDX_KEY]);
-}
-
-/** Remove callback
- *
- */
-static void udf_idx_remove_cb(link_t *link)
-{
-	/* We don't use remove callback for this hash table */
-}
-
-static hash_table_operations_t udf_idx_ops = {
+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,
-	.compare = udf_idx_compare,
-	.remove_callback = udf_idx_remove_cb,
+	.key_hash = udf_idx_key_hash,
+	.key_equal = udf_idx_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL 
 };
 
@@ -113,6 +93,5 @@
 int udf_idx_init(void)
 {
-	if (!hash_table_create(&udf_idx, UDF_IDX_BUCKETS, UDF_IDX_KEYS,
-	    &udf_idx_ops))
+	if (!hash_table_create(&udf_idx, 0, 0, &udf_idx_ops))
 		return ENOMEM;
 	
@@ -143,13 +122,13 @@
 {
 	fibril_mutex_lock(&udf_idx_lock);
-	
-	unsigned long key[] = {
-		[UDF_IDX_SERVICE_ID_KEY] = instance->service_id,
-		[UDF_IDX_KEY] = index
+
+	udf_ht_key_t key = {
+		.service_id = instance->service_id,
+		.index = index
 	};
 	
-	link_t *already_open = hash_table_find(&udf_idx, key);
+	ht_link_t *already_open = hash_table_find(&udf_idx, &key);
 	if (already_open) {
-		udf_node_t *node = hash_table_get_instance(already_open,
+		udf_node_t *node = hash_table_get_inst(already_open,
 		    udf_node_t, link);
 		node->ref_cnt++;
@@ -202,13 +181,7 @@
 	
 	fibril_mutex_initialize(&udf_node->lock);
-	link_initialize(&udf_node->link);
 	fs_node->data = udf_node;
 	
-	unsigned long key[] = {
-		[UDF_IDX_SERVICE_ID_KEY] = instance->service_id,
-		[UDF_IDX_KEY] = index
-	};
-	
-	hash_table_insert(&udf_idx, key, &udf_node->link);
+	hash_table_insert(&udf_idx, &udf_node->link);
 	instance->open_nodes_count++;
 	
@@ -232,10 +205,5 @@
 	fibril_mutex_lock(&udf_idx_lock);
 	
-	unsigned long key[] = {
-		[UDF_IDX_SERVICE_ID_KEY] = node->instance->service_id,
-		[UDF_IDX_KEY] = node->index
-	};
-	
-	hash_table_remove(&udf_idx, key, UDF_IDX_KEYS);
+	hash_table_remove_item(&udf_idx, &node->link);
 	
 	assert(node->instance->open_nodes_count > 0);
Index: uspace/srv/hid/input/gsp.c
===================================================================
--- uspace/srv/hid/input/gsp.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/hid/input/gsp.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -50,24 +50,45 @@
 
 #include <adt/hash_table.h>
+#include <adt/hash.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include "gsp.h"
 
-#define TRANS_TABLE_CHAINS  256
-
 /*
- * Hash table operations for the transition function.
- */
-
-static hash_index_t trans_op_hash(unsigned long key[]);
-static int trans_op_compare(unsigned long key[], hash_count_t keys,
-    link_t *item);
-static void trans_op_remove_callback(link_t *item);
-
-static hash_table_operations_t trans_ops = {
-	.hash = trans_op_hash,
-	.compare = trans_op_compare,
-	.remove_callback = trans_op_remove_callback
+ * Transition function hash table operations.
+ */
+typedef struct {
+	int old_state;
+	int input;
+} trans_key_t;
+
+static size_t trans_key_hash(void *key)
+{
+	trans_key_t *trans_key = (trans_key_t *)key;
+	return hash_combine(trans_key->input, trans_key->old_state);
+}
+
+static size_t trans_hash(const ht_link_t *item)
+{
+	gsp_trans_t *t = hash_table_get_inst(item, gsp_trans_t, link);
+	return hash_combine(t->input, t->old_state);
+}
+
+static bool trans_key_equal(void *key, const ht_link_t *item)
+{
+	trans_key_t *trans_key = (trans_key_t *)key;
+	gsp_trans_t *t = hash_table_get_inst(item, gsp_trans_t, link);
+	
+	return trans_key->input == t->input && trans_key->old_state == t->old_state;
+}
+
+static hash_table_ops_t trans_ops = {
+	.hash = trans_hash,
+	.key_hash = trans_key_hash,
+	.key_equal = trans_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
 };
+
 
 static gsp_trans_t *trans_lookup(gsp_t *p, int state, int input);
@@ -75,9 +96,9 @@
 static gsp_trans_t *trans_new(void);
 
-/** Initialise scancode parser. */
+/** Initialize scancode parser. */
 void gsp_init(gsp_t *p)
 {
 	p->states = 1;
-	hash_table_create(&p->trans, TRANS_TABLE_CHAINS, 2, &trans_ops);
+	hash_table_create(&p->trans, 0, 0, &trans_ops);
 }
 
@@ -223,14 +244,15 @@
 static gsp_trans_t *trans_lookup(gsp_t *p, int state, int input)
 {
-	link_t *item;
-	unsigned long key[2];
-
-	key[0] = state;
-	key[1] = input;
-
-	item = hash_table_find(&p->trans, key);
+	ht_link_t *item;
+	
+	trans_key_t key = {
+		.input = input,
+		.old_state = state
+	};
+
+	item = hash_table_find(&p->trans, &key);
 	if (item == NULL) return NULL;
 
-	return hash_table_get_instance(item, gsp_trans_t, link);
+	return hash_table_get_inst(item, gsp_trans_t, link);
 }
 
@@ -242,10 +264,5 @@
 static void trans_insert(gsp_t *p, gsp_trans_t *t)
 {
-	unsigned long key[2];
-
-	key[0] = t->old_state;
-	key[1] = t->input;
-
-	hash_table_insert(&p->trans, key, &t->link);
+	hash_table_insert(&p->trans, &t->link);
 }
 
@@ -264,26 +281,4 @@
 }
 
-/*
- * Transition function hash table operations.
- */
-
-static hash_index_t trans_op_hash(unsigned long key[])
-{
-	return (key[0] * 17 + key[1]) % TRANS_TABLE_CHAINS;
-}
-
-static int trans_op_compare(unsigned long key[], hash_count_t keys,
-    link_t *item)
-{
-	gsp_trans_t *t;
-
-	t = hash_table_get_instance(item, gsp_trans_t, link);
-	return ((key[0] == (unsigned long) t->old_state)
-	    && (key[1] == (unsigned long) t->input));
-}
-
-static void trans_op_remove_callback(link_t *item)
-{
-}
 
 /**
Index: uspace/srv/hid/input/gsp.h
===================================================================
--- uspace/srv/hid/input/gsp.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/hid/input/gsp.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -56,5 +56,5 @@
 /** Scancode parser transition. */
 typedef struct {
-	link_t link;		/**< Link to hash table in @c gsp_t */ 
+	ht_link_t link;		/**< Link to hash table in @c gsp_t */ 
 
 	/* Preconditions */
Index: uspace/srv/logger/logs.c
===================================================================
--- uspace/srv/logger/logs.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/logger/logs.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -268,5 +268,11 @@
 
 	if (log->parent == NULL) {
-		fclose(log->dest->logfile);
+		/*
+		 * 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);
Index: uspace/srv/ns/service.c
===================================================================
--- uspace/srv/ns/service.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/ns/service.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -40,9 +40,8 @@
 #include "ns.h"
 
-#define SERVICE_HASH_TABLE_CHAINS  20
 
 /** Service hash table item. */
 typedef struct {
-	link_t link;
+	ht_link_t link;
 	sysarg_t service;        /**< Service ID. */
 	sysarg_t phone;          /**< Phone registered with the service. */
@@ -50,63 +49,29 @@
 } hashed_service_t;
 
-/** Compute hash index into service hash table.
- *
- * @param key Pointer keys. However, only the first key (i.e. service number)
- *            is used to compute the hash index.
- *
- * @return Hash index corresponding to key[0].
- *
- */
-static hash_index_t service_hash(unsigned long key[])
+
+static size_t service_key_hash(void *key)
 {
-	assert(key);
-	return (key[0] % SERVICE_HASH_TABLE_CHAINS);
+	return *(sysarg_t*)key;
 }
 
-/** Compare a key with hashed item.
- *
- * This compare function always ignores the third key.
- * It exists only to make it possible to remove records
- * originating from connection with key[1] in_phone_hash
- * value. Note that this is close to being classified
- * as a nasty hack.
- *
- * @param key  Array of keys.
- * @param keys Must be lesser or equal to 3.
- * @param item Pointer to a hash table item.
- *
- * @return Non-zero if the key matches the item, zero otherwise.
- *
- */
-static int service_compare(unsigned long key[], hash_count_t keys, link_t *item)
+static size_t service_hash(const ht_link_t *item)
 {
-	assert(key);
-	assert(keys <= 3);
-	assert(item);
-	
-	hashed_service_t *hs = hash_table_get_instance(item, hashed_service_t, link);
-	
-	if (keys == 2)
-		return ((key[0] == hs->service) && (key[1] == hs->in_phone_hash));
-	else
-		return (key[0] == hs->service);
+	hashed_service_t *hs = hash_table_get_inst(item, hashed_service_t, link);
+	return hs->service;
 }
 
-/** Perform actions after removal of item from the hash table.
- *
- * @param item Item that was removed from the hash table.
- *
- */
-static void service_remove(link_t *item)
+static bool service_key_equal(void *key, const ht_link_t *item)
 {
-	assert(item);
-	free(hash_table_get_instance(item, hashed_service_t, link));
+	hashed_service_t *hs = hash_table_get_inst(item, hashed_service_t, link);
+	return hs->service == *(sysarg_t*)key;
 }
 
 /** Operations for service hash table. */
-static hash_table_operations_t service_hash_table_ops = {
+static hash_table_ops_t service_hash_table_ops = {
 	.hash = service_hash,
-	.compare = service_compare,
-	.remove_callback = service_remove
+	.key_hash = service_key_hash,
+	.key_equal = service_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
 };
 
@@ -127,6 +92,5 @@
 int service_init(void)
 {
-	if (!hash_table_create(&service_hash_table, SERVICE_HASH_TABLE_CHAINS,
-	    3, &service_hash_table_ops)) {
+	if (!hash_table_create(&service_hash_table, 0, 0, &service_hash_table_ops)) {
 		printf(NAME ": No memory available for services\n");
 		return ENOMEM;
@@ -145,15 +109,9 @@
 		pending_conn_t *pr = list_get_instance(cur, pending_conn_t, link);
 		
-		unsigned long keys[3] = {
-			pr->service,
-			0,
-			0
-		};
-		
-		link_t *link = hash_table_find(&service_hash_table, keys);
+		ht_link_t *link = hash_table_find(&service_hash_table, &pr->service);
 		if (!link)
 			continue;
 		
-		hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
+		hashed_service_t *hs = hash_table_get_inst(link, hashed_service_t, link);
 		(void) ipc_forward_fast(pr->callid, hs->phone, pr->arg2,
 		    pr->arg3, 0, IPC_FF_NONE);
@@ -176,11 +134,5 @@
 int register_service(sysarg_t service, sysarg_t phone, ipc_call_t *call)
 {
-	unsigned long keys[3] = {
-		service,
-		call->in_phone_hash,
-		0
-	};
-	
-	if (hash_table_find(&service_hash_table, keys))
+	if (hash_table_find(&service_hash_table, &service))
 		return EEXISTS;
 	
@@ -189,9 +141,8 @@
 		return ENOMEM;
 	
-	link_initialize(&hs->link);
 	hs->service = service;
 	hs->phone = phone;
 	hs->in_phone_hash = call->in_phone_hash;
-	hash_table_insert(&service_hash_table, keys, &hs->link);
+	hash_table_insert(&service_hash_table, &hs->link);
 	
 	return EOK;
@@ -210,11 +161,6 @@
 {
 	sysarg_t retval;
-	unsigned long keys[3] = {
-		service,
-		0,
-		0
-	};
 	
-	link_t *link = hash_table_find(&service_hash_table, keys);
+	ht_link_t *link = hash_table_find(&service_hash_table, &service);
 	if (!link) {
 		if (IPC_GET_ARG4(*call) & IPC_FLAG_BLOCKING) {
@@ -239,5 +185,5 @@
 	}
 	
-	hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
+	hashed_service_t *hs = hash_table_get_inst(link, hashed_service_t, link);
 	(void) ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call),
 	    IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
Index: uspace/srv/ns/task.c
===================================================================
--- uspace/srv/ns/task.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/ns/task.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -43,6 +43,4 @@
 #include "ns.h"
 
-#define TASK_HASH_TABLE_CHAINS  256
-#define P2I_HASH_TABLE_CHAINS   256
 
 /* TODO:
@@ -55,5 +53,5 @@
 /** Task hash table item. */
 typedef struct {
-	link_t link;
+	ht_link_t link;
 	
 	task_id_t id;    /**< Task ID. */
@@ -63,57 +61,34 @@
 } hashed_task_t;
 
-/** Compute hash index into task hash table.
- *
- * @param key Pointer keys. However, only the first key (i.e. truncated task
- *            number) is used to compute the hash index.
- *
- * @return Hash index corresponding to key[0].
- *
- */
-static hash_index_t task_hash(unsigned long key[])
-{
-	assert(key);
-	return (LOWER32(key[0]) % TASK_HASH_TABLE_CHAINS);
-}
-
-/** Compare a key with hashed item.
- *
- * @param key  Array of keys.
- * @param keys Must be less than or equal to 2.
- * @param item Pointer to a hash table item.
- *
- * @return Non-zero if the key matches the item, zero otherwise.
- *
- */
-static int task_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	assert(key);
-	assert(keys <= 2);
-	assert(item);
-	
-	hashed_task_t *ht = hash_table_get_instance(item, hashed_task_t, link);
-	
-	if (keys == 2)
-		return ((LOWER32(key[1]) == UPPER32(ht->id))
-		    && (LOWER32(key[0]) == LOWER32(ht->id)));
-	else
-		return (LOWER32(key[0]) == LOWER32(ht->id));
-}
-
-/** Perform actions after removal of item from the hash table.
- *
- * @param item Item that was removed from the hash table.
- *
- */
-static void task_remove(link_t *item)
-{
-	assert(item);
-	free(hash_table_get_instance(item, hashed_task_t, link));
+
+static size_t task_key_hash(void *key)
+{
+	return *(task_id_t*)key;
+}
+
+static size_t task_hash(const ht_link_t  *item)
+{
+	hashed_task_t *ht = hash_table_get_inst(item, hashed_task_t, link);
+	return ht->id;
+}
+
+static bool task_key_equal(void *key, const ht_link_t *item)
+{
+	hashed_task_t *ht = hash_table_get_inst(item, hashed_task_t, link);
+	return ht->id == *(task_id_t*)key;
+}
+
+/** Perform actions after removal of item from the hash table. */
+static void task_remove(ht_link_t *item)
+{
+	free(hash_table_get_inst(item, hashed_task_t, link));
 }
 
 /** Operations for task hash table. */
-static hash_table_operations_t task_hash_table_ops = {
+static hash_table_ops_t task_hash_table_ops = {
 	.hash = task_hash,
-	.compare = task_compare,
+	.key_hash = task_key_hash,
+	.key_equal = task_key_equal,
+	.equal = NULL,
 	.remove_callback = task_remove
 };
@@ -123,57 +98,48 @@
 
 typedef struct {
-	link_t link;
+	ht_link_t link;
 	sysarg_t in_phone_hash;  /**< Incoming phone hash. */
 	task_id_t id;            /**< Task ID. */
 } p2i_entry_t;
 
-/** Compute hash index into task hash table.
- *
- * @param key Array of keys.
- *
- * @return Hash index corresponding to key[0].
- *
- */
-static hash_index_t p2i_hash(unsigned long key[])
-{
-	assert(key);
-	return (key[0] % TASK_HASH_TABLE_CHAINS);
-}
-
-/** Compare a key with hashed item.
- *
- * @param key  Array of keys.
- * @param keys Must be less than or equal to 1.
- * @param item Pointer to a hash table item.
- *
- * @return Non-zero if the key matches the item, zero otherwise.
- *
- */
-static int p2i_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	assert(key);
-	assert(keys == 1);
+/* phone-to-id hash table operations */
+
+static size_t p2i_key_hash(void *key)
+{
+	sysarg_t in_phone_hash = *(sysarg_t*)key;
+	return in_phone_hash;
+}
+
+static size_t p2i_hash(const ht_link_t *item)
+{
+	p2i_entry_t *entry = hash_table_get_inst(item, p2i_entry_t, link);
+	return entry->in_phone_hash;
+}
+
+static bool p2i_key_equal(void *key, const ht_link_t *item)
+{
+	sysarg_t in_phone_hash = *(sysarg_t*)key;
+	p2i_entry_t *entry = hash_table_get_inst(item, p2i_entry_t, link);
+	
+	return (in_phone_hash == entry->in_phone_hash);
+}
+
+/** Perform actions after removal of item from the hash table.
+ *
+ * @param item Item that was removed from the hash table.
+ *
+ */
+static void p2i_remove(ht_link_t *item)
+{
 	assert(item);
-	
-	p2i_entry_t *entry = hash_table_get_instance(item, p2i_entry_t, link);
-	
-	return (key[0] == entry->in_phone_hash);
-}
-
-/** Perform actions after removal of item from the hash table.
- *
- * @param item Item that was removed from the hash table.
- *
- */
-static void p2i_remove(link_t *item)
-{
-	assert(item);
-	free(hash_table_get_instance(item, p2i_entry_t, link));
+	free(hash_table_get_inst(item, p2i_entry_t, link));
 }
 
 /** Operations for task hash table. */
-static hash_table_operations_t p2i_ops = {
+static hash_table_ops_t p2i_ops = {
 	.hash = p2i_hash,
-	.compare = p2i_compare,
+	.key_hash = p2i_key_hash,
+	.key_equal = p2i_key_equal,
+	.equal = NULL,
 	.remove_callback = p2i_remove
 };
@@ -193,12 +159,10 @@
 int task_init(void)
 {
-	if (!hash_table_create(&task_hash_table, TASK_HASH_TABLE_CHAINS,
-	    2, &task_hash_table_ops)) {
+	if (!hash_table_create(&task_hash_table, 0, 0, &task_hash_table_ops)) {
 		printf(NAME ": No memory available for tasks\n");
 		return ENOMEM;
 	}
 	
-	if (!hash_table_create(&phone_to_id, P2I_HASH_TABLE_CHAINS,
-	    1, &p2i_ops)) {
+	if (!hash_table_create(&phone_to_id, 0, 0, &p2i_ops)) {
 		printf(NAME ": No memory available for tasks\n");
 		return ENOMEM;
@@ -218,14 +182,9 @@
 		pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link);
 		
-		unsigned long keys[2] = {
-			LOWER32(pr->id),
-			UPPER32(pr->id)
-		};
-		
-		link_t *link = hash_table_find(&task_hash_table, keys);
+		ht_link_t *link = hash_table_find(&task_hash_table, &pr->id);
 		if (!link)
 			continue;
 		
-		hashed_task_t *ht = hash_table_get_instance(link, hashed_task_t, link);
+		hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
 		if (!ht->finished)
 			continue;
@@ -238,5 +197,5 @@
 		}
 		
-		hash_table_remove(&task_hash_table, keys, 2);
+		hash_table_remove(&task_hash_table, &pr->id);
 		list_remove(cur);
 		free(pr);
@@ -250,12 +209,7 @@
 	task_exit_t texit;
 	
-	unsigned long keys[2] = {
-		LOWER32(id),
-		UPPER32(id)
-	};
-	
-	link_t *link = hash_table_find(&task_hash_table, keys);
+	ht_link_t *link = hash_table_find(&task_hash_table, &id);
 	hashed_task_t *ht = (link != NULL) ?
-	    hash_table_get_instance(link, hashed_task_t, link) : NULL;
+	    hash_table_get_inst(link, hashed_task_t, link) : NULL;
 	
 	if (ht == NULL) {
@@ -281,5 +235,5 @@
 	}
 	
-	hash_table_remove(&task_hash_table, keys, 2);
+	hash_table_remove_item(&task_hash_table, link);
 	retval = EOK;
 	
@@ -293,10 +247,8 @@
 int ns_task_id_intro(ipc_call_t *call)
 {
-	unsigned long keys[2];
 	
 	task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call));
-	keys[0] = call->in_phone_hash;
-	
-	link_t *link = hash_table_find(&phone_to_id, keys);
+
+	ht_link_t *link = hash_table_find(&phone_to_id, &call->in_phone_hash);
 	if (link != NULL)
 		return EEXISTS;
@@ -314,8 +266,7 @@
 	 */
 	
-	link_initialize(&entry->link);
 	entry->in_phone_hash = call->in_phone_hash;
 	entry->id = id;
-	hash_table_insert(&phone_to_id, keys, &entry->link);
+	hash_table_insert(&phone_to_id, &entry->link);
 	
 	/*
@@ -323,13 +274,9 @@
 	 */
 	
-	keys[0] = LOWER32(id);
-	keys[1] = UPPER32(id);
-	
-	link_initialize(&ht->link);
 	ht->id = id;
 	ht->finished = false;
 	ht->have_rval = false;
 	ht->retval = -1;
-	hash_table_insert(&task_hash_table, keys, &ht->link);
+	hash_table_insert(&task_hash_table, &ht->link);
 	
 	return EOK;
@@ -338,11 +285,9 @@
 static int get_id_by_phone(sysarg_t phone_hash, task_id_t *id)
 {
-	unsigned long keys[1] = {phone_hash};
-	
-	link_t *link = hash_table_find(&phone_to_id, keys);
+	ht_link_t *link = hash_table_find(&phone_to_id, &phone_hash);
 	if (link == NULL)
 		return ENOENT;
 	
-	p2i_entry_t *entry = hash_table_get_instance(link, p2i_entry_t, link);
+	p2i_entry_t *entry = hash_table_get_inst(link, p2i_entry_t, link);
 	*id = entry->id;
 	
@@ -357,12 +302,7 @@
 		return rc;
 	
-	unsigned long keys[2] = {
-		LOWER32(id),
-		UPPER32(id)
-	};
-	
-	link_t *link = hash_table_find(&task_hash_table, keys);
+	ht_link_t *link = hash_table_find(&task_hash_table, &id);
 	hashed_task_t *ht = (link != NULL) ?
-	    hash_table_get_instance(link, hashed_task_t, link) : NULL;
+	    hash_table_get_inst(link, hashed_task_t, link) : NULL;
 	
 	if ((ht == NULL) || (ht->finished))
@@ -378,6 +318,4 @@
 int ns_task_disconnect(ipc_call_t *call)
 {
-	unsigned long keys[2];
-	
 	task_id_t id;
 	int rc = get_id_by_phone(call->in_phone_hash, &id);
@@ -386,16 +324,12 @@
 	
 	/* Delete from phone-to-id map. */
-	keys[0] = call->in_phone_hash;
-	hash_table_remove(&phone_to_id, keys, 1);
+	hash_table_remove(&phone_to_id, &call->in_phone_hash);
 	
 	/* Mark task as finished. */
-	keys[0] = LOWER32(id);
-	keys[1] = UPPER32(id);
-	
-	link_t *link = hash_table_find(&task_hash_table, keys);
-	hashed_task_t *ht =
-	    hash_table_get_instance(link, hashed_task_t, link);
-	if (ht == NULL)
+	ht_link_t *link = hash_table_find(&task_hash_table, &id);
+	if (link == NULL)
 		return EOK;
+
+	hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
 	
 	ht->finished = true;
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/vfs/vfs.h	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -36,4 +36,5 @@
 #include <async.h>
 #include <adt/list.h>
+#include <adt/hash_table.h>
 #include <fibril_synch.h>
 #include <sys/types.h>
@@ -112,5 +113,5 @@
 	unsigned lnkcnt;
 
-	link_t nh_link;		/**< Node hash-table link. */
+	ht_link_t nh_link;		/**< Node hash-table link. */
 
 	vfs_node_type_t type;	/**< Partial info about the node type. */
Index: uspace/srv/vfs/vfs_node.c
===================================================================
--- uspace/srv/vfs/vfs_node.c	(revision b801f2d6becda84795177e84564a610b886dbea0)
+++ uspace/srv/vfs/vfs_node.c	(revision 5c90e3e8776092fd096406931971a147268d3db1)
@@ -41,4 +41,5 @@
 #include <fibril_synch.h>
 #include <adt/hash_table.h>
+#include <adt/hash.h>
 #include <assert.h>
 #include <async.h>
@@ -58,13 +59,16 @@
 #define KEY_INDEX	2
 
-static hash_index_t nodes_hash(unsigned long []);
-static int nodes_compare(unsigned long [], hash_count_t, link_t *);
-static void nodes_remove_callback(link_t *);
+static size_t nodes_key_hash(void *);
+static size_t nodes_hash(const ht_link_t *);
+static bool nodes_key_equal(void *, const ht_link_t *);
+static vfs_triplet_t node_triplet(vfs_node_t *node);
 
 /** VFS node hash table operations. */
-hash_table_operations_t nodes_ops = {
+hash_table_ops_t nodes_ops = {
 	.hash = nodes_hash,
-	.compare = nodes_compare,
-	.remove_callback = nodes_remove_callback
+	.key_hash = nodes_key_hash,
+	.key_equal = nodes_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL,
 };
 
@@ -75,5 +79,5 @@
 bool vfs_nodes_init(void)
 {
-	return hash_table_create(&nodes, NODES_BUCKETS, 3, &nodes_ops);
+	return hash_table_create(&nodes, 0, 0, &nodes_ops);
 }
 
@@ -114,11 +118,5 @@
 		 */
 		
-		unsigned long key[] = {
-			[KEY_FS_HANDLE] = node->fs_handle,
-			[KEY_DEV_HANDLE] = node->service_id,
-			[KEY_INDEX] = node->index
-		};
-		
-		hash_table_remove(&nodes, key, 3);
+		hash_table_remove_item(&nodes, &node->nh_link);
 		free_vfs_node = true;
 		
@@ -158,10 +156,5 @@
 {
 	fibril_mutex_lock(&nodes_mutex);
-	unsigned long key[] = {
-		[KEY_FS_HANDLE] = node->fs_handle,
-		[KEY_DEV_HANDLE] = node->service_id,
-		[KEY_INDEX] = node->index
-	};
-	hash_table_remove(&nodes, key, 3);
+	hash_table_remove_item(&nodes, &node->nh_link);
 	fibril_mutex_unlock(&nodes_mutex);
 	free(node);
@@ -182,14 +175,8 @@
 vfs_node_t *vfs_node_get(vfs_lookup_res_t *result)
 {
-	unsigned long key[] = {
-		[KEY_FS_HANDLE] = result->triplet.fs_handle,
-		[KEY_DEV_HANDLE] = result->triplet.service_id,
-		[KEY_INDEX] = result->triplet.index
-	};
-	link_t *tmp;
 	vfs_node_t *node;
 
 	fibril_mutex_lock(&nodes_mutex);
-	tmp = hash_table_find(&nodes, key);
+	ht_link_t *tmp = hash_table_find(&nodes, &result->triplet);
 	if (!tmp) {
 		node = (vfs_node_t *) malloc(sizeof(vfs_node_t));
@@ -205,9 +192,8 @@
 		node->lnkcnt = result->lnkcnt;
 		node->type = result->type;
-		link_initialize(&node->nh_link);
 		fibril_rwlock_initialize(&node->contents_rwlock);
-		hash_table_insert(&nodes, key, &node->nh_link);
+		hash_table_insert(&nodes, &node->nh_link);
 	} else {
-		node = hash_table_get_instance(tmp, vfs_node_t, nh_link);
+		node = hash_table_get_inst(tmp, vfs_node_t, nh_link);
 		if (node->type == VFS_NODE_UNKNOWN &&
 		    result->type != VFS_NODE_UNKNOWN) {
@@ -240,24 +226,4 @@
 }
 
-hash_index_t nodes_hash(unsigned long key[])
-{
-	hash_index_t a = key[KEY_FS_HANDLE] << (NODES_BUCKETS_LOG / 4);
-	hash_index_t b = (a | key[KEY_DEV_HANDLE]) << (NODES_BUCKETS_LOG / 2);
-	
-	return (b | key[KEY_INDEX]) & (NODES_BUCKETS - 1);
-}
-
-int nodes_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	vfs_node_t *node = hash_table_get_instance(item, vfs_node_t, nh_link);
-	return (node->fs_handle == (fs_handle_t) key[KEY_FS_HANDLE]) &&
-	    (node->service_id == key[KEY_DEV_HANDLE]) &&
-	    (node->index == key[KEY_INDEX]);
-}
-
-void nodes_remove_callback(link_t *item)
-{
-}
-
 struct refcnt_data {
 	/** Sum of all reference counts for this file system instance. */
@@ -267,7 +233,7 @@
 };
 
-static void refcnt_visitor(link_t *item, void *arg)
-{
-	vfs_node_t *node = hash_table_get_instance(item, vfs_node_t, nh_link);
+static bool refcnt_visitor(ht_link_t *item, void *arg)
+{
+	vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
 	struct refcnt_data *rd = (void *) arg;
 
@@ -275,4 +241,6 @@
 	    (node->service_id == rd->service_id))
 		rd->refcnt += node->refcnt;
+	
+	return true;
 }
 
@@ -315,4 +283,39 @@
 }
 
+
+static size_t nodes_key_hash(void *key)
+{
+	vfs_triplet_t *tri = key;
+	size_t hash = hash_combine(tri->fs_handle, tri->index);
+	return hash_combine(hash, tri->service_id);
+}
+
+static size_t nodes_hash(const ht_link_t *item)
+{
+	vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
+	vfs_triplet_t tri = node_triplet(node);
+	return nodes_key_hash(&tri);
+}
+
+static bool nodes_key_equal(void *key, const ht_link_t *item)
+{
+	vfs_triplet_t *tri = key;
+	vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
+	return node->fs_handle == tri->fs_handle 
+		&& node->service_id == tri->service_id
+		&& node->index == tri->index;
+}
+
+static inline vfs_triplet_t node_triplet(vfs_node_t *node)
+{
+	vfs_triplet_t tri = {
+		.fs_handle = node->fs_handle,
+		.service_id = node->service_id,
+		.index = node->index
+	};
+	
+	return tri;
+}
+
 /**
  * @}
