diff --git a/COPYING.SOFORT b/COPYING.SOFORT
new file mode 100644
index 0000000..9360291
--- /dev/null
+++ b/COPYING.SOFORT
@@ -0,0 +1,26 @@
+/*****************************************************************************/
+/*                                                                           */
+/*  sofort: portable software project template                               */
+/*                                                                           */
+/*  Copyright (C) 2015  Z. Gilboa                                            */
+/*                                                                           */
+/*  Permission is hereby granted, free of charge, to any person obtaining    */
+/*  a copy of this software and associated documentation files (the          */
+/*  "Software"), to deal in the Software without restriction, including      */
+/*  without limitation the rights to use, copy, modify, merge, publish,      */
+/*  distribute, sublicense, and/or sell copies of the Software, and to       */
+/*  permit persons to whom the Software is furnished to do so, subject to    */
+/*  the following conditions:                                                */
+/*                                                                           */
+/*  The above copyright notice and this permission notice shall be included  */
+/*  in all copies or substantial portions of the Software.                   */
+/*                                                                           */
+/*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  */
+/*  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               */
+/*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   */
+/*  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY     */
+/*  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,     */
+/*  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE        */
+/*  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                   */
+/*                                                                           */
+/*****************************************************************************/
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..df3113b
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,298 @@
+PACKAGE 		= @package@
+PROJECT_DIR 		= @project_dir@
+
+BUILD 			= @build@
+HOST 			= @host@
+TARGET 			= @target@
+ARCH 			= @arch@
+TOOLCHAIN 		= @toolchain@
+SYSROOT 		= @sysroot@
+CROSS_COMPILE 		= @cross_compile@
+SHELL 			= @shell@
+
+CFLAGS_DEBUG 		= @cflags_debug@
+CFLAGS_COMMON 		= @cflags_common@
+CFLAGS_CMDLINE 		= @cflags_cmdline@
+CFLAGS_CONFIG 		= @cflags_config@
+CFLAGS_SYSROOT 		= @cflags_sysroot@
+CFLAGS_PATH 		= @cflags_path@
+
+LDFLAGS_DEBUG 		= @ldflags_debug@
+LDFLAGS_COMMON 		= @ldflags_common@
+LDFLAGS_CMDLINE 	= @ldflags_cmdline@
+LDFLAGS_CONFIG 		= @ldflags_config@
+LDFLAGS_SYSROOT 	= @ldflags_sysroot@
+LDFLAGS_PATH 		= @ldflags_path@
+
+PE_SUBSYSTEM 		= @pe_subsystem@
+PE_IMAGE_BASE 		= @pe_image_base@
+PE_CONFIG_DEFS  	= @pe_config_defs@
+
+ELF_EH_FRAME 		= @elf_eh_frame@
+ELF_HASH_STYLE 		= @elf_hash_style@
+ELF_CONFIG_DEFS 	= @elf_config_defs@
+
+PREFIX 			= @prefix@
+BINDIR 			= @bindir@
+LIBDIR 			= @libdir@
+INCLUDEDIR 		= @includedir@
+SYSLIBDIR 		= @syslibdir@
+MANDIR 			= @mandir@
+DOCDIR 			= @docdir@
+LIBEXECDIR 		= @libexecdir@
+
+NATIVE_CC 		= @native_cc@
+NATIVE_OS 		= @native_os@
+NATIVE_OS_BITS 		= @native_os_bits@
+NATIVE_OS_UNDERSCORE	= @native_os_underscore@
+
+USER_CC                 = @user_cc@
+USER_CPP                = @user_cpp@
+USER_CXX                = @user_cxx@
+
+
+all:
+install:
+shared:
+static:
+
+
+
+include $(PROJECT_DIR)/sysinfo/host/$(HOST).mk
+include $(PROJECT_DIR)/sysinfo/toolchain/$(TOOLCHAIN).mk
+
+include $(PROJECT_DIR)/project/defs.mk
+include $(PROJECT_DIR)/project/tree.mk
+include $(PROJECT_DIR)/project/depends.mk
+include $(PROJECT_DIR)/project/headers.mk
+include $(PROJECT_DIR)/project/common.mk
+include $(PROJECT_DIR)/project/arch.mk
+include $(PROJECT_DIR)/project/extras.mk
+include $(PROJECT_DIR)/project/overrides.mk
+
+
+
+$(APP_SRCS:%.c=%.o): CFLAGS_STATIC = $(CFLAGS_APP)
+
+src/%.lo: 	$(PROJECT_DIR)/src/%.c $(ALL_HEADERS) host.tag tree.tag
+		$(CC) -c -o $@ $< $(CFLAGS_SHARED)
+
+src/%.o: 	$(PROJECT_DIR)/src/%.c $(ALL_HEADERS) host.tag tree.tag
+		$(CC) -c -o $@ $< $(CFLAGS_STATIC)
+
+$(LIBDIR)/%$(OS_LIB_SUFFIX):
+		$(CC) -shared -o $@ $^ $(LDFLAGS_SHARED)
+
+$(LIBDIR)/%$(OS_ARCHIVE_EXT):
+		rm -f $@
+		$(AR) -rcs $@ $^
+
+
+
+all:		shared static app
+
+install:	install-libs install-headers install-app
+
+app:		default-app
+
+
+install-libs:	install-shared install-static install-implib
+
+install-headers:shared static
+		mkdir -p $(DESTDIR)/./$(PREFIX)/./$(INCLUDEDIR)/$(PACKAGE)
+		cp $(API_HEADERS) $(DESTDIR)/./$(PREFIX)/./$(INCLUDEDIR)/$(PACKAGE)
+
+install-shared:	shared install-implib
+		mkdir -p $(DESTDIR)/./$(PREFIX)/./$(LIBDIR)
+		cp $(SHARED_LIB) $(DESTDIR)/./$(PREFIX)/./$(LIBDIR)
+
+install-static:	static
+		mkdir -p $(DESTDIR)/./$(PREFIX)/./$(LIBDIR)
+		cp $(STATIC_LIB) $(DESTDIR)/./$(PREFIX)/./$(LIBDIR)
+
+install-app:	app
+		mkdir -p $(DESTDIR)/./$(PREFIX)/./$(BINDIR)
+		cp $(APP) $(DESTDIR)/./$(PREFIX)/./$(BINDIR)
+
+
+
+shared:		shared-lib shared-implib
+
+static:		static-lib
+
+shared-lib:	shared-objs $(SHARED_LIB)
+
+static-lib:	static-objs $(STATIC_LIB)
+
+shared-implib:	shared-lib
+
+
+
+default-app:	version.tag static $(DEFAULT_APP) $(APP)
+
+shared-app:	version.tag shared $(SHARED_APP)
+
+static-app:	version.tag static $(STATIC_APP)
+
+
+
+shared-objs:	dirs $(SHARED_OBJS)
+
+static-objs:	dirs $(STATIC_OBJS)
+
+app-objs:	dirs $(APP_OBJS)
+
+
+
+$(SHARED_LIB):	$(SHARED_OBJS)
+
+$(STATIC_LIB):	$(STATIC_OBJS)
+
+$(APP):		$(DEFAULT_APP)
+		cp $^ $@
+
+$(DEFAULT_APP):	$(STATIC_OBJS) $(APP_OBJS)
+		$(CC) -o $@ $^ $(LDFLAGS_APP)
+
+$(SHARED_APP):	$(SHARED_LIB) $(APP_OBJS)
+		$(CC) -o $@ $(APP_OBJS) -l$(PACKAGE) $(LDFLAGS_APP)
+
+$(STATIC_APP):	$(STATIC_OBJS) $(APP_OBJS)
+		$(CC) -static -o $@ $^ -l$(PACKAGE) $(LDFLAGS_STATIC)
+
+
+dirs: 		dirs.tag tree.tag
+
+dirs.tag:
+		mkdir -p $(BINDIR)
+		mkdir -p $(LIBDIR)
+		touch dirs.tag
+
+host.tag:	Makefile
+		$(PROJECT_DIR)/sysinfo/host/host.sh --compiler="$(CC)" --cflags="$(CFLAGS)"
+		touch host.tag
+
+version.tag:
+		$(PROJECT_DIR)/sysinfo/version.sh	\
+			-s $(PROJECT_DIR)		\
+			-o build/$(PACKAGE)_version.h	\
+			-p $(PACKAGE)
+		touch version.tag
+
+distclean:	clean
+		rm -f Makefile
+
+clean:
+		rm -f tree.tag
+		rm -f dirs.tag
+		rm -f host.tag
+		rm -f version.tag
+		rm -f $(SHARED_OBJS)
+		rm -f $(STATIC_OBJS)
+		rm -f $(APP_OBJS)
+		rm -f $(SHARED_LIB)
+		rm -f $(STATIC_LIB)
+		rm -f $(SHARED_IMPLIB)
+		rm -f $(APP)
+		rm -f $(DEFAULT_APP)
+		rm -f $(SHARED_APP)
+		rm -f $(STATIC_APP)
+
+
+.display:	.display-env .display-tools .display-flags \
+		.display-pe .display-elf .display-dirs .display-build
+
+.display-env:
+		@echo BUILD:'                  '$(BUILD)
+		@echo HOST:'                   '$(HOST)
+		@echo TARGET:'                 '$(TARGET)
+		@echo ARCH:'                   '$(ARCH)
+		@echo TOOLCHAIN:'              '$(TOOLCHAIN)
+		@echo SYSROOT:'                '$(SYSROOT)
+		@echo XCOMPILE:'               '$(CROSS_COMPILE)
+		@echo SHELL:'                  '$(SHELL)
+		@echo
+
+.display-tools:
+		@echo CC:'                     '$(CC)
+		@echo CPP:'                    '$(CPP)
+		@echo CXX:'                    '$(CXX)
+		@echo
+		@echo AS:'                     '$(AS)
+		@echo AR:'                     '$(AR)
+		@echo LD:'                     '$(LD)
+		@echo NM:'                     '$(NM)
+		@echo OBJDUMP:'                '$(OBJDUMP)
+		@echo RANLIB:'                 '$(RANLIB)
+		@echo SIZE:'                   '$(SIZE)
+		@echo STRIP:'                  '$(STRIP)
+		@echo STRINGS:'                '$(STRINGS)
+		@echo
+		@echo ADDR2LINE:'              '$(ADDR2LINE)
+		@echo COV:'                    '$(COV)
+		@echo CXXFILT'                 '$(CXXFILT)
+		@echo ELFEDIT:'                '$(ELFEDIT)
+		@echo OBJCOPY:'                '$(OBJCOPY)
+		@echo READELF:'                '$(READELF)
+		@echo
+
+.display-flags:
+		@echo CFLAGS_DEBUG:'           '$(CFLAGS_DEBUG)
+		@echo CFLAGS_COMMON:'          '$(CFLAGS_COMMON)
+		@echo CFLAGS_CMDLINE:'         '$(CFLAGS_CMDLINE)
+		@echo CFLAGS_CONFIG:'          '$(CFLAGS_CONFIG)
+		@echo CFLAGS_SYSROOT:'         '$(CFLAGS_SYSROOT)
+		@echo CFLAGS_PATH:'            '$(CFLAGS_PATH)
+		@echo
+		@echo LDFLAGS_DEBUG:'           '$(LDFLAGS_DEBUG)
+		@echo LDFLAGS_COMMON:'          '$(LDFLAGS_COMMON)
+		@echo LDFLAGS_CMDLINE:'         '$(LDFLAGS_CMDLINE)
+		@echo LDFLAGS_CONFIG:'          '$(LDFLAGS_CONFIG)
+		@echo LDFLAGS_SYSROOT:'         '$(LDFLAGS_SYSROOT)
+		@echo LDFLAGS_PATH:'            '$(LDFLAGS_PATH)
+		@echo
+
+.display-pe:
+		@echo PE_SUBSYSTEM:'           '$(PE_SUBSYSTEM)
+		@echo PE_IMAGE_BASE:'          '$(PE_IMAGE_BASE)
+		@echo PE_CONFIG_DEFS:'         '$(PE_CONFIG_DEFS)
+		@echo
+
+.display-elf:
+		@echo ELF_EH_FRAME:'           '$(ELF_EH_FRAME)
+		@echo ELF_HASH_STYLE:'         '$(ELF_HASH_STYLE)
+		@echo ELF_CONFIG_DEFS:'        '$(ELF_CONFIG_DEFS)
+		@echo
+
+.display-dirs:
+		@echo PREFIX:'                 '$(PREFIX)
+		@echo BINDIR:'                 '$(BINDIR)
+		@echo LIBDIR:'                 '$(LIBDIR)
+		@echo INCLUDEDIR:'             '$(INCLUDEDIR)
+		@echo SYSLIBDIR:'              '$(SYSLIBDIR)
+		@echo MANDIR:'                 '$(MANDIR)
+		@echo DOCDIR:'                 '$(DOCDIR)
+		@echo LIBEXECDIR:'             '$(LIBEXECDIR)
+		@echo
+
+.display-build:
+		@echo NATIVE_CC:'              '$(NATIVE_CC)
+		@echo NATIVE_OS:'              '$(NATIVE_OS)
+		@echo NATIVE_OS_BITS:'         '$(NATIVE_OS_BITS)
+		@echo NATIVE_OS_UNDERSCORE:'   '$(NATIVE_OS_UNDERSCORE)
+		@echo
+		@echo USER_CC:'                '$(USER_CC)
+		@echo USER_CPP:'               '$(USER_CPP)
+		@echo USER_CXX:'               '$(USER_CXX)
+		@echo
+
+
+.PHONY:		all install shared static app .display \
+		shared-objs shared-lib shared-implib \
+		static-objs static-lib \
+		default-app shared-app static-app \
+		install-shared install-static install-implib \
+		install-headers install-app \
+		clean distclean version \
+		.display-env .display-tools .display-flags \
+		.display-pe .display-elf .display-dirs .display-build
diff --git a/config.project b/config.project
new file mode 100644
index 0000000..1f4c68c
--- /dev/null
+++ b/config.project
@@ -0,0 +1,49 @@
+# project
+mb_package=sofort
+mb_require_out_of_tree=no
+
+
+# dirs
+mb_default_prefix=
+mb_default_bindir=bin
+mb_default_libdir=lib
+mb_default_includedir=include
+mb_default_syslibdir=lib
+mb_default_mandir=man
+mb_default_docdir=doc
+mb_default_libexecdir=libexec
+
+
+# build
+mb_default_build=
+mb_default_host=
+mb_default_target=
+mb_default_arch=
+mb_default_toolchain=
+mb_default_sysroot=
+mb_default_cross_compile=
+mb_default_shell=sh
+
+
+# switches
+mb_default_cflags_debug=
+mb_default_cflags_common="-std=c99 -D_XOPEN_SOURCE=700 -I\$(PROJECT_DIR)/src/internal -I\$(PROJECT_DIR)/include -Ibuild"
+mb_default_cflags_cmdline=
+mb_default_cflags_config=
+mb_default_cflags_sysroot=
+mb_default_cflags_path=
+
+mb_default_ldflags_debug=
+mb_default_ldflags_common="-Llib"
+mb_default_ldflags_cmdline=
+mb_default_ldflags_config=
+mb_default_ldflags_sysroot=
+mb_default_ldflags_path=
+
+mb_default_pe_subsystem=windows
+mb_default_pe_image_base=
+mb_default_pe_config_defs=
+
+mb_default_elf_eh_frame=
+mb_default_elf_hash_style=
+mb_default_elf_config_defs=
diff --git a/config.usage b/config.usage
new file mode 100644
index 0000000..2175510
--- /dev/null
+++ b/config.usage
@@ -0,0 +1,77 @@
+configure: a skinny configuration script.
+
+supported switches:
+-------------------
+	--help
+
+	--prefix
+	--bindir
+	--libdir
+	--includedir
+	--syslibdir
+	--mandir
+	--libexecdir
+
+	--build
+	--host
+	--target
+	--arch
+	--toolchain
+	--sysroot
+	--cross-compile
+	--shell
+	--debug
+
+
+supported variables:
+--------------------
+	PREFIX
+	BINDIR
+	LIBDIR
+	INCLUDEDIR
+	LIBDIR
+	MANDIR
+	DOCDIR
+	LIBEXECDIR
+
+	CC
+	CPP
+	CXX
+
+	BUILD
+	HOST
+	TARGET
+	ARCH
+	TOOLCHAIN
+	SYSROOT
+	CROSS_COMPILE
+	SHELL
+
+	CFLAGS
+	CFLAGS_DEBUG
+	CFLAGS_COMMON
+	CFLAGS_CMDLINE
+	CFLAGS_CONFIG
+	CFLAGS_SYSROOT
+	CFLAGS_PATH
+
+	LDFLAGS
+	LDFLAGS_DEBUG
+	LDFLAGS_COMMON
+	LDFLAGS_CMDLINE
+	LDFLAGS_CONFIG
+	LDFLAGS_SYSROOT
+	LDFLAGS_PATH
+
+	PE_SUBSYSTEM
+	PE_IMAGE_BASE
+	PE_CONFIG_DEFS
+
+	ELF_EH_FRAME
+	ELF_HASH_STYLE
+	ELF_CONFIG_DEFS
+
+	NATIVE_CC
+	NATIVE_OS
+	NATIVE_OS_BITS
+	NATIVE_OS_UNDERSCORE
diff --git a/configure b/configure
new file mode 100755
index 0000000..3e222ce
--- /dev/null
+++ b/configure
@@ -0,0 +1,432 @@
+#!/bin/sh
+# we are no longer lazy.
+
+# this script respects both CFLAGS and CFLAGS_CMDLINE,
+# as well as both LDFLAGS and LDFLAGS_CMDLINE, however
+# the latter variable of each pair should be preferred.
+
+usage()
+{
+	cat config.usage
+	exit $?
+}
+
+error_msg()
+{
+	echo $@ >&2
+}
+
+
+init_vars()
+{
+	mb_project_dir=$(cd `dirname $0` ; pwd)
+	mb_pwd=`pwd`
+
+	if [ x"$mb_config" = x ]; then
+		. $mb_project_dir/config.project || exit 2
+	else
+		. "$mb_config" || exit 2
+	fi
+
+	# dirs
+	mb_prefix=$PREFIX
+	mb_bindir=$BINDIR
+	mb_libdir=$LIBDIR
+	mb_includedir=$INCLUDEDIR
+	mb_syslibdir=$LIBDIR
+	mb_mandir=$MANDIR
+	mb_docdir=$DOCDIR
+	mb_libexecdir=$LIBEXECDIR
+
+
+	# build
+	mb_build=$BUILD
+	mb_host=$HOST
+	mb_target=$TARGET
+	mb_arch=$ARCH
+	mb_toolchain=$TOOLCHAIN
+	mb_sysroot=$SYSROOT
+	mb_cross_compile=$CROSS_COMPILE
+	mb_shell=$SHELL
+
+	# switches
+	mb_cflags=$CFLAGS
+	mb_cflags_debug=$CFLAGS_DEBUG
+	mb_cflags_common=$CFLAGS_COMMON
+	mb_cflags_cmdline=$CFLAGS_CMDLINE
+	mb_cflags_config=$CFLAGS_CONFIG
+	mb_cflags_sysroot=$CFLAGS_SYSROOT
+	mb_cflags_path=$CFLAGS_PATH
+
+	mb_ldflags=$LDFLAGS
+	mb_ldflags_debug=$LDFLAGS_DEBUG
+	mb_ldflags_common=$LDFLAGS_COMMON
+	mb_ldflags_cmdline=$LDFLAGS_CMDLINE
+	mb_ldflags_config=$LDFLAGS_CONFIG
+	mb_ldflags_sysroot=$LDFLAGS_SYSROOT
+	mb_ldflags_path=$LDFLAGS_PATH
+
+	mb_pe_subsystem=$PE_SUBSYSTEM
+	mb_pe_image_base=$PE_IMAGE_BASE
+	mb_pe_config_defs=$PE_CONFIG_DEFS
+
+	mb_elf_eh_frame=$ELF_EH_FRAME
+	mb_elf_hash_style=$ELF_HASH_STYLE
+	mb_elf_config_defs=$ELF_CONFIG_DEFS
+
+	# overrides
+	mb_native_cc=$NATIVE_CC
+	mb_native_os=$NATIVE_OS
+	mb_native_os_bits=$NATIVE_OS_BITS
+	mb_native_os_underscore=$NATIVE_OS_UNDERSCORE
+
+	mb_user_cc=$CC
+	mb_user_cpp=$CPP
+	mb_user_cxx=$CXX
+}
+
+
+verify_build_directory()
+{
+	if [ x"$mb_project_dir" = x"$mb_pwd" ]; then
+		if [ x"$mb_require_out_of_tree" = xyes ]; then
+			error_msg "$mb_package: out-of-tree builds are required."
+			error_msg "please invoke configure again from a clean build directory."
+			exit 2
+		else
+			mb_project_dir='.'
+		fi
+	fi
+}
+
+
+common_defaults()
+{
+	# dirs
+	[ -z "$mb_prefix" ] 		&& mb_prefix=$mb_default_prefix
+	[ -z "$mb_bindir" ] 		&& mb_bindir=$mb_default_bindir
+	[ -z "$mb_libdir" ] 		&& mb_libdir=$mb_default_libdir
+	[ -z "$mb_includedir" ]		&& mb_includedir=$mb_default_includedir
+	[ -z "$mb_syslibdir" ] 		&& mb_syslibdir=$mb_default_syslibdir
+	[ -z "$mb_mandir" ] 		&& mb_mandir=$mb_default_mandir
+	[ -z "$mb_docdir" ] 		&& mb_docdir=$mb_default_docdir
+	[ -z "$mb_libexecdir" ]		&& mb_libexecdir=$mb_default_libexecdir
+
+	# build
+	[ -z "$mb_build" ] 		&& mb_build=$mb_default_build
+	[ -z "$mb_host" ] 		&& mb_host=$mb_default_host
+	[ -z "$mb_target" ] 		&& mb_target=$mb_default_target
+	[ -z "$mb_arch" ] 		&& mb_arch=$mb_default_arch
+	[ -z "$mb_toolchain" ] 		&& mb_toolchain=$mb_default_toolchain
+	[ -z "$mb_sysroot" ] 		&& mb_sysroot=$mb_default_sysroot
+	[ -z "$mb_cross_compile" ] 	&& mb_cross_compile=$mb_default_cross_compile
+	[ -z "$mb_shell" ] 		&& mb_shell=$mb_default_shell
+
+	# switches
+	[ -z "$mb_cflags_debug" ]	&& mb_cflags_debug=$mb_default_cflags_debug
+	[ -z "$mb_cflags_common" ]	&& mb_cflags_common=$mb_default_cflags_common
+	[ -z "$mb_cflags_cmdline" ]	&& mb_cflags_cmdline=$mb_default_cflags_cmdline
+	[ -z "$mb_cflags_config" ]	&& mb_cflags_config=$mb_default_cflags_config
+	[ -z "$mb_cflags_sysroot" ]	&& mb_cflags_sysroot=$mb_default_cflags_sysroot
+	[ -z "$mb_cflags_path" ]	&& mb_cflags_path=$mb_default_cflags_path
+
+	[ -z "$mb_ldflags_debug" ]	&& mb_ldflags_debug=$mb_default_ldflags_debug
+	[ -z "$mb_ldflags_common" ]	&& mb_ldflags_common=$mb_default_ldflags_common
+	[ -z "$mb_ldflags_cmdline" ]	&& mb_ldflags_cmdline=$mb_default_ldflags_cmdline
+	[ -z "$mb_ldflags_config" ]	&& mb_ldflags_config=$mb_default_ldflags_config
+	[ -z "$mb_ldflags_sysroot" ]	&& mb_ldflags_sysroot=$mb_default_ldflags_sysroot
+	[ -z "$mb_ldflags_path" ]	&& mb_ldflags_path=$mb_default_ldflags_path
+
+	[ -z "$mb_pe_subsystem" ]	&& mb_pe_subsystem=$mb_default_pe_subsystem
+	[ -z "$mb_pe_image_base" ]	&& mb_pe_image_base=$mb_default_pe_image_base
+	[ -z "$mb_pe_config_defs" ]	&& mb_pe_config_defs=$mb_default_pe_config_defs
+
+	[ -z "$mb_elf_eh_frame" ]	&& mb_elf_eh_frame=$mb_default_elf_eh_frame
+	[ -z "$mb_elf_hash_style" ]	&& mb_elf_hash_style=$mb_default_elf_hash_style
+	[ -z "$mb_elf_config_defs" ]	&& mb_elf_config_defs=$mb_default_elf_config_defs
+
+	# host/target
+	[ -z "$mb_host" ] 		&& mb_host=$mb_target
+	[ -z "$mb_target" ] 		&& mb_target=$mb_host
+
+	# sysroot
+	if [ x"$mb_sysroot" != x ]; then
+		if [ x"$mb_cflags_sysroot" = x ]; then
+			mb_cflags_sysroot="--sysroot=$mb_sysroot"
+		fi
+
+		if [ x"$mb_ldflags_sysroot" = x ]; then
+			mb_ldflags_sysroot="-Wl,--sysroot,$mb_sysroot"
+		fi
+	fi
+
+	# debug
+	if [ x"$mb_debug" = xyes ]; then
+		if [ x"$mb_cflags_debug" = x ]; then
+			mb_cflags_debug='-g3 -O0'
+		fi
+	fi
+
+	# toolchain
+	if [ x"$mb_toolchain" != x ]; then
+		if [ x"$mb_native_cc" = x ]; then
+			mb_native_cc=$mb_toolchain
+		fi
+	fi
+}
+
+
+native_defaults()
+{
+	# CC (when set, must be valid)
+	if [ x"$CC" != x ]; then
+		$CC -dM -E - < /dev/null > /dev/null || exit 2
+	fi
+
+	# toolchain
+	[ -z "$mb_native_cc" ] && mb_native_cc=$CC
+	[ -z "$mb_native_cc" ] && mb_native_cc='cc'
+	$mb_native_cc -dM -E - < /dev/null > /dev/null 2>/dev/null || mb_native_cc=
+
+	[ -z "$mb_native_cc" ] && mb_native_cc='gcc'
+	$mb_native_cc -dM -E - < /dev/null > /dev/null 2>/dev/null || mb_native_cc=
+
+	[ -z "$mb_native_cc" ] && mb_native_cc='clang'
+	$mb_native_cc -dM -E - < /dev/null > /dev/null 2>/dev/null || mb_native_cc=
+
+	[ -z "$mb_native_cc" ] && mb_native_cc='cparser'
+	$mb_native_cc -dM -E - < /dev/null > /dev/null 2>/dev/null || mb_native_cc=
+
+	if [ x"$mb_native_cc" = x ]; then
+		error_msg "config error: could not find a working native compiler."
+		exit 2
+	fi
+
+	if [ x"$mb_toolchain" = x ]; then
+		$mb_native_cc -dM -E - < /dev/null | grep '__clang__' > /dev/null && mb_toolchain='clang'
+	fi
+
+	if [ x"$mb_toolchain" = x ]; then
+		$mb_native_cc -dM -E - < /dev/null | grep '__GCC' > /dev/null && mb_toolchain='gcc'
+	fi
+
+	if [ x"$mb_toolchain" = x ]; then
+		$mb_native_cc -dM -E - < /dev/null | grep '__CPARSER__' > /dev/null && mb_toolchain='cparser'
+	fi
+
+	if [ x"$mb_toolchain" = x ]; then
+		error_msg "config error: could not identify the native compiler."
+		exit 2
+	fi
+
+
+	# host
+	if [ x"$mb_host" = x ]; then
+		mb_host='native'
+	fi
+
+
+	# target
+	if [ x"$mb_target" = x ]; then
+		mb_target='native'
+	fi
+
+
+	# os
+	mb_native_os=`uname | tr '[:upper:]' '[:lower:]'`
+
+	mb_native_os_sizeof_pointer=`$mb_native_cc -dM -E - < /dev/null \
+			| grep __SIZEOF_POINTER__  \
+			| cut -d ' ' -f3`
+
+	mb_native_os_bits=`expr '8' '*' '0'"$mb_native_os_sizeof_pointer"`
+
+	if [ $mb_native_os_bits = 32 ]; then
+		mb_native_os_underscore='_'
+	else
+		mb_native_os_underscore=''
+	fi
+
+	if [ x"$mb_native_os_sizeof_pointer" = x ]; then
+		error_msg "config error: could not determine size of pointer on native system."
+		exit 2
+	fi
+
+	[ -z "$mb_native_os" ] 			&& mb_native_os=$mb_native_os
+	[ -z "$mb_native_os_bits" ] 		&& mb_native_os_bits=$mb_native_os_bits
+	[ -z "$mb_native_os_underscore" ]	&& mb_native_os_underscore=$mb_native_os_underscore
+}
+
+
+cross_defaults()
+{
+	if [ x"$mb_cross_compile" = x ] && [ x"$mb_host" != xnative ]; then
+		mb_cross_compile=$mb_host'-'
+	fi
+}
+
+
+config_copy()
+{
+	sed 		-e 's^@package@^'"$mb_package"'^g' 				\
+			-e 's^@project_dir@^'"$mb_project_dir"'^g'			\
+											\
+			-e 's^@build@^'"$mb_build"'^g'					\
+			-e 's^@host@^'"$mb_host"'^g'					\
+			-e 's^@target@^'"$mb_target"'^g'				\
+			-e 's^@arch@^'"$mb_arch"'^g'					\
+			-e 's^@toolchain@^'"$mb_toolchain"'^g'				\
+			-e 's^@sysroot@^'"$mb_sysroot"'^g'				\
+			-e 's^@cross_compile@^'"$mb_cross_compile"'^g'			\
+			-e 's^@shell@^'"$mb_shell"'^g'					\
+											\
+			-e 's^@cflags@^'"$mb_cflags"'^g'				\
+			-e 's^@cflags_debug@^'"$mb_cflags_debug"'^g'			\
+			-e 's^@cflags_common@^'"$mb_cflags_common"'^g'			\
+			-e 's^@cflags_cmdline@^'"$mb_cflags $mb_cflags_cmdline"'^g'	\
+			-e 's^@cflags_config@^'"$mb_cflags_config"'^g'			\
+			-e 's^@cflags_sysroot@^'"$mb_cflags_sysroot"'^g'		\
+			-e 's^@cflags_path@^'"$mb_cflags_path"'^g'			\
+											\
+			-e 's^@ldflags@^'"$mb_ldflags"'^g'				\
+			-e 's^@ldflags_debug@^'"$mb_ldflags_debug"'^g'			\
+			-e 's^@ldflags_common@^'"$mb_ldflags_common"'^g'		\
+			-e 's^@ldflags_cmdline@^'"$mb_ldflags $mb_ldflags_cmdline"'^g'	\
+			-e 's^@ldflags_config@^'"$mb_ldflags_config"'^g'		\
+			-e 's^@ldflags_sysroot@^'"$mb_ldflags_sysroot"'^g'		\
+			-e 's^@ldflags_path@^'"$mb_ldflags_path"'^g'			\
+											\
+			-e 's^@pe_subsystem@^'"$mb_pe_subsystem"'^g'			\
+			-e 's^@pe_image\_base@^'"$mb_pe_image_base"'^g'			\
+			-e 's^@pe_config\_defs@^'"$mb_pe_config_defs"'^g'		\
+											\
+			-e 's^@elf_eh\_frame@^'"$mb_elf_eh_frame"'^g'			\
+			-e 's^@elf_hash\_style@^'"$mb_elf_hash_style"'^g'		\
+			-e 's^@elf_config\_defs@^'"$mb_elf_config_defs"'^g'		\
+											\
+			-e 's^@prefix@^'"$mb_prefix"'^g'				\
+			-e 's^@bindir@^'"$mb_bindir"'^g'				\
+			-e 's^@libdir@^'"$mb_libdir"'^g'				\
+			-e 's^@includedir@^'"$mb_includedir"'^g'			\
+			-e 's^@syslibdir@^'"$mb_syslibdir"'^g'				\
+			-e 's^@mandir@^'"$mb_mandir"'^g'				\
+			-e 's^@docdir@^'"$mb_docdir"'^g'				\
+			-e 's^@libexecdir@^'"$mb_libexecdir"'^g'			\
+											\
+			-e 's^@native_cc@^'"$mb_native_cc"'^g'				\
+			-e 's^@native_os@^'"$mb_native_os"'^g'				\
+			-e 's^@native_os_bits@^'"$mb_native_os_bits"'^g'		\
+			-e 's^@native_os_underscore@^'"$mb_native_os_underscore"'^g'	\
+											\
+			-e 's^@user_cc@^'"$mb_user_cc"'^g'				\
+			-e 's^@user_cpp@^'"$mb_user_cpp"'^g'				\
+			-e 's^@user_cxx@^'"$mb_user_cxx"'^g'				\
+		$mb_project_dir/Makefile.in > $mb_pwd/Makefile
+}
+
+
+config_host()
+{
+	make host.tag && return 0
+
+	error_msg "configure was able to generate a Makefile for the selected host,"
+	error_msg "however the host-targeting toolchain was found to be missing"
+	error_msg "at least one of the required headers or features."
+	exit 2
+}
+
+
+config_status()
+{
+	printf "\n\n"
+	make .display
+	printf "\nconfiguration completed successfully.\n\n"
+}
+
+# one: init
+init_vars
+verify_build_directory
+
+
+# two: args
+for arg ; do
+	case "$arg" in
+		--help)	usage
+			;;
+
+		# dirs
+		--prefix=*)
+			mb_prefix=${arg#*=}
+			;;
+		--bindir=*)
+			mb_bindir=${arg#*=}
+			;;
+		--libdir=*)
+			mb_libdir=${arg#*=}
+			;;
+		--includedir=*)
+			mb_includedir=${arg#*=}
+			;;
+		--syslibdir=*)
+			mb_syslibdir=${arg#*=}
+			;;
+		--mandir=*)
+			mb_mandir=${arg#*=}
+			;;
+		--libexecdir=*)
+			mb_libexecdir=${arg#*=}
+			;;
+
+
+		# build
+		--build=*)
+			mb_build=${arg#*=}
+			;;
+		--host=*)
+			mb_host=${arg#*=}
+			;;
+		--target=*)
+			mb_target=${arg#*=}
+			;;
+		--arch=*)
+			mb_arch=${arg#*=}
+			;;
+		--toolchain=*)
+			mb_toolchain=${arg#*=}
+			;;
+		--sysroot=*)
+			mb_sysroot=${arg#*=}
+			;;
+		--cross-compile=*)
+			mb_cross_compile=${arg#*=}
+			;;
+		--shell=*)
+			mb_shell=${arg#*=}
+			;;
+		--debug)
+			mb_debug='yes'
+			;;
+		*)
+			error_msg ${arg#}: "unsupported config argument."
+			exit 2
+			;;
+	esac
+done
+
+
+
+# three: defaults
+common_defaults
+native_defaults
+cross_defaults
+
+
+
+# four: config
+config_copy
+config_host
+config_status
+
+
+# all done
+exit 0
diff --git a/include/sofort/sofort.h b/include/sofort/sofort.h
new file mode 100644
index 0000000..ee5072f
--- /dev/null
+++ b/include/sofort/sofort.h
@@ -0,0 +1,93 @@
+#ifndef SFRT_H
+#define SFRT_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "sofort_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* pre-alpha */
+#ifndef SFRT_APP
+#ifndef SFRT_PRE_ALPHA
+#error  libsofort: pre-alpha: ABI is not final!
+#error  to use the library, please pass -DSFRT_PRE_ALPHA to the compiler.
+#endif
+#endif
+
+/* status codes */
+#define SFRT_OK				0x00
+#define SFRT_USAGE			0x01
+#define SFRT_BAD_OPT			0x02
+#define SFRT_BAD_OPT_VAL		0x03
+#define SFRT_IO_ERROR			0xA0
+#define SFRT_MAP_ERROR			0xA1
+
+/* driver flags */
+#define SFRT_DRIVER_VERBOSITY_NONE	0x0000
+#define SFRT_DRIVER_VERBOSITY_ERRORS	0x0001
+#define SFRT_DRIVER_VERBOSITY_STATUS	0x0002
+#define SFRT_DRIVER_VERBOSITY_USAGE	0x0004
+#define SFRT_DRIVER_CLONE_VECTOR	0x0008
+
+#define SFRT_DRIVER_VERSION		0x0010
+#define SFRT_DRIVER_DRY_RUN		0x0020
+
+/* unit action flags */
+#define SFRT_OUTPUT_NAME		0x0001
+#define SFRT_OUTPUT_ADDRESS		0x0002
+
+struct sfrt_input {
+	void *	addr;
+	size_t	size;
+};
+
+struct sfrt_common_ctx {
+	uint64_t			drvflags;
+	uint64_t			actflags;
+	uint64_t			fmtflags;
+	const char *			anystring;
+};
+
+struct sfrt_driver_ctx {
+	const char **			units;
+	const char *			program;
+	const char *			module;
+	const struct sfrt_common_ctx *	cctx;
+	void *				any;
+	int				status;
+	int				nerrors;
+};
+
+struct sfrt_unit_ctx {
+	const char * const *		path;
+	const struct sfrt_input *	map;
+	const struct sfrt_common_ctx *	cctx;
+	void *				any;
+	int				status;
+	int				nerrors;
+};
+
+/* driver api */
+sfrt_api int  sfrt_get_driver_ctx	(const char ** argv, const char ** envp, uint32_t flags, struct sfrt_driver_ctx **);
+sfrt_api void sfrt_free_driver_ctx	(struct sfrt_driver_ctx *);
+
+sfrt_api int  sfrt_get_unit_ctx		(const struct sfrt_driver_ctx *, const char * path, struct sfrt_unit_ctx **);
+sfrt_api void sfrt_free_unit_ctx	(struct sfrt_unit_ctx *);
+
+sfrt_api int  sfrt_map_input		(int fd, const char * path, int prot, struct sfrt_input *);
+sfrt_api int  sfrt_unmap_input		(struct sfrt_input *);
+
+/* utility api */
+sfrt_api int  sfrt_output_dummy		(const struct sfrt_common_ctx *, FILE *);
+sfrt_api int  sfrt_output_name		(const struct sfrt_unit_ctx *, FILE *);
+sfrt_api int  sfrt_output_address	(const struct sfrt_unit_ctx *, FILE *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/sofort/sofort_api.h b/include/sofort/sofort_api.h
new file mode 100644
index 0000000..5f0b2d9
--- /dev/null
+++ b/include/sofort/sofort_api.h
@@ -0,0 +1,35 @@
+#ifndef SFRT_API_H
+#define SFRT_API_H
+
+#include <limits.h>
+
+/* sfrt_export */
+#if	defined(__dllexport)
+#define sfrt_export __dllexport
+#else
+#define sfrt_export
+#endif
+
+/* sfrt_import */
+#if	defined(__dllimport)
+#define sfrt_import __dllimport
+#else
+#define sfrt_import
+#endif
+
+/* sfrt_api */
+#ifndef SFRT_APP
+#if     defined (SFRT_BUILD)
+#define sfrt_api sfrt_export
+#elif   defined (SFRT_SHARED)
+#define sfrt_api sfrt_import
+#elif   defined (SFRT_STATIC)
+#define sfrt_api
+#else
+#define sfrt_api
+#endif
+#else
+#define sfrt_api
+#endif
+
+#endif
diff --git a/project/arch.mk b/project/arch.mk
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/arch.mk
diff --git a/project/common.mk b/project/common.mk
new file mode 100644
index 0000000..3bc5e54
--- /dev/null
+++ b/project/common.mk
@@ -0,0 +1,11 @@
+COMMON_SRCS = \
+	src/driver/sfrt_driver_ctx.c \
+	src/driver/sfrt_unit_ctx.c \
+	src/logic/sfrt_map_input.c \
+	src/output/sfrt_output_address.c \
+	src/output/sfrt_output_dummy.c \
+	src/output/sfrt_output_name.c \
+	src/skin/sfrt_skin_default.c \
+
+APP_SRCS = \
+	src/sofort.c
diff --git a/project/defs.mk b/project/defs.mk
new file mode 100644
index 0000000..f089d08
--- /dev/null
+++ b/project/defs.mk
@@ -0,0 +1,44 @@
+SHARED_LIB_DEPS =
+SHARED_APP_DEPS =
+STATIC_APP_DEPS =
+
+COMMON_LOBJS	= $(COMMON_SRCS:.c=.lo)
+COMMON_OBJS	= $(COMMON_SRCS:.c=.o)
+
+ARCH_LOBJS	= $(ARCH_SRCS:.c=.lo)
+ARCH_OBJS	= $(ARCH_SRCS:.c=.o)
+
+APP_LOBJS	= $(APP_SRCS:.c=.lo)
+APP_OBJS	= $(APP_SRCS:.c=.o)
+
+SHARED_OBJS	= $(COMMON_LOBJS) $(ARCH_LOBJS)
+STATIC_OBJS	= $(COMMON_OBJS)  $(ARCH_OBJS)
+
+SHARED_LIB	= $(LIBDIR)/$(OS_LIB_PREFIX)$(PACKAGE)$(OS_LIB_SUFFIX)
+STATIC_LIB	= $(LIBDIR)/$(OS_LIB_PREFIX)$(PACKAGE)$(OS_ARCHIVE_EXT)
+SHARED_IMPLIB	= $(LIBDIR)/$(OS_LIB_PREFIX)$(PACKAGE)$(OS_IMPLIB_EXT)
+
+APP		= $(BINDIR)/$(OS_APP_PREFIX)$(PACKAGE)$(OS_APP_SUFFIX)
+DEFAULT_APP	= $(BINDIR)/$(OS_APP_PREFIX)$(PACKAGE)-default$(OS_APP_SUFFIX)
+SHARED_APP	= $(BINDIR)/$(OS_APP_PREFIX)$(PACKAGE)-shared$(OS_APP_SUFFIX)
+STATIC_APP	= $(BINDIR)/$(OS_APP_PREFIX)$(PACKAGE)-static$(OS_APP_SUFFIX)
+
+CFLAGS		= $(CFLAGS_DEBUG)  $(CFLAGS_CONFIG)  $(CFLAGS_SYSROOT) \
+		   $(CFLAGS_COMMON) $(CFLAGS_CMDLINE) $(CFLAGS_HOST)	\
+		   $(CFLAGS_PATH)
+
+CFLAGS_SHARED	= $(CFLAGS) $(CFLAGS_PIC) $(CFLAGS_SHARED_ATTR)
+CFLAGS_STATIC	= $(CFLAGS) $(CFLAGS_OBJ) $(CFLAGS_STATIC_ATTR)
+CFLAGS_APP	= $(CFLAGS) $(CFLAGS_OBJ) $(CFLAGS_APP_ATTR)
+
+LDFLAGS_SHARED	= $(LDFLAGS_DEBUG)   $(LDFLAGS_CONFIG)  $(LDFLAGS_SYSROOT) \
+		   $(LDFLAGS_COMMON)  $(LDFLAGS_CMDLINE) $(LDFLAGS_HOST)    \
+		   $(LDFLAGS_PATH)    $(SHARED_LIB_DEPS) $(LDFLAGS_LAST)
+
+LDFLAGS_APP	= $(LDFLAGS_DEBUG)   $(LDFLAGS_CONFIG)  $(LDFLAGS_SYSROOT) \
+		   $(LDFLAGS_COMMON)  $(LDFLAGS_CMDLINE) $(LDFLAGS_HOST)    \
+		   $(LDFLAGS_PATH)    $(SHARED_APP_DEPS) $(LDFLAGS_LAST)
+
+LDFLAGS_STATIC	= $(LDFLAGS_DEBUG)   $(LDFLAGS_CONFIG)  $(LDFLAGS_SYSROOT) \
+		   $(LDFLAGS_COMMON)  $(LDFLAGS_CMDLINE) $(LDFLAGS_HOST)    \
+		   $(LDFLAGS_PATH)    $(STATIC_APP_DEPS) $(LDFLAGS_LAST)
diff --git a/project/depends.mk b/project/depends.mk
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/depends.mk
diff --git a/project/extras.mk b/project/extras.mk
new file mode 100644
index 0000000..6a64c50
--- /dev/null
+++ b/project/extras.mk
@@ -0,0 +1,3 @@
+CFLAGS_SHARED_ATTR	+= -DSFRT_PRE_ALPHA -DSFRT_BUILD
+CFLAGS_STATIC_ATTR	+= -DSFRT_PRE_ALPHA -DSFRT_STATIC
+CFLAGS_APP_ATTR		+= -DSFRT_APP
diff --git a/project/headers.mk b/project/headers.mk
new file mode 100644
index 0000000..1fb0cd2
--- /dev/null
+++ b/project/headers.mk
@@ -0,0 +1,9 @@
+API_HEADERS = \
+	$(PROJECT_DIR)/include/$(PACKAGE)/sofort.h \
+	$(PROJECT_DIR)/include/$(PACKAGE)/sofort_api.h \
+
+INTERNAL_HEADERS = \
+	$(PROJECT_DIR)/src/internal/argv/argv.h \
+	$(PROJECT_DIR)/src/internal/$(PACKAGE)_driver_impl.h \
+
+ALL_HEADERS = $(API_HEADERS) $(INTERNAL_HEADERS)
diff --git a/project/overrides.mk b/project/overrides.mk
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/overrides.mk
diff --git a/project/tree.mk b/project/tree.mk
new file mode 100644
index 0000000..d91f6a2
--- /dev/null
+++ b/project/tree.mk
@@ -0,0 +1,8 @@
+tree.tag:
+		mkdir -p src
+		mkdir -p src/driver
+		mkdir -p src/internal
+		mkdir -p src/logic
+		mkdir -p src/output
+		mkdir -p src/skin
+		touch tree.tag
diff --git a/sofort.sh b/sofort.sh
new file mode 100755
index 0000000..951e0eb
--- /dev/null
+++ b/sofort.sh
@@ -0,0 +1,122 @@
+#!/bin/sh
+
+usage()
+{
+cat << EOF >&2
+
+Usage:
+  -h            show this HELP message
+  -d  DSTDIR    set destination directory
+  -p  PROJECT   set project name (i.e. sofort)
+  -n  PREFIX    set namespace prefix (i.e. sfrt)
+
+EOF
+exit 1
+}
+
+error_dstdir_exists()
+{
+	echo "the destination directory '$dstdir' already exists!" >&2
+	exit 2
+}
+
+# one: args
+dstdir=
+project=
+namespace=
+
+srcdir=`dirname $0` || exit 2
+cd "$srcdir" || exit 2
+srcdir=`pwd` || exit 2
+
+while getopts "hd:p:n:" opt; do
+	case $opt in
+	h)
+  		usage
+  		;;
+	d)
+    		dstdir="$OPTARG"
+    		;;
+	p)
+    		project="$OPTARG"
+    		;;
+	n)
+    		namespace="$OPTARG"
+    		;;
+	\?)
+    		printf "Invalid option: -%s" "$OPTARG" >&2
+    		usage
+    		;;
+	esac
+done
+
+# two: clone
+if [ -z "$dstdir" ] || [ -z "$project" ] || [ -z "$namespace" ]; then
+	usage
+fi
+
+stat "$dstdir" >/dev/null 2>/dev/null && error_dstdir_exists
+mkdir -p "$(dirname $dstdir)" || exit 2
+cp -r "$srcdir" "$dstdir" || exit 2
+rm "$dstdir"/sofort.sh || exit 2
+rm -rf "$dstdir"/.git || exit 2
+
+# three: content
+cd "$dstdir" || exit 2
+files=$(find . -type f)
+lowerspace=`echo "$namespace" | tr '[:upper:]' '[:lower:]'`_
+upperspace=`echo "$namespace" | tr '[:lower:]' '[:upper:]'`_
+
+for f in $files; do
+	sed -e s/sofort/$project/g "$f" > "$f.tmp" || exit 2
+	mv "$f.tmp" "$f" || exit 2
+
+	sed -e s/sfrt_/$lowerspace/g "$f" > "$f.tmp" || exit 2
+	mv "$f.tmp" "$f" || exit 2
+
+	sed -e s/sfrt_/$upperspace/g "$f" > "$f.tmp" || exit 2
+	mv "$f.tmp" "$f" || exit 2
+done
+
+# four: directory names
+mv include/sofort include/$project || exit 2
+dirs=$(find . -type d)
+
+for d in $dirs; do
+	name=`echo "$d" | sed -e s/sfrt_/$lowerspace/g -e s/sofort/$project/g`
+
+	if [ "$d" != "$name" ]; then
+		mv "$d" "$name" || exit 2
+	fi
+done
+
+# five: file names
+files=$(find . -type f)
+
+for f in $files; do
+	name=`echo "$f" | sed -e s/sfrt_/$lowerspace/g -e s/sofort/$project/g`
+
+	if [ "$f" != "$name" ]; then
+		mv "$f" "$name" || exit 2
+	fi
+done
+
+# six: references
+cp "$srcdir"/COPYING.SOFORT "$dstdir" || exit 2
+
+# seven: finalize
+uppername=`echo "$project" | tr '[:lower:]' '[:upper:]'`
+utilcsrc=src/$project.c
+
+sed -e s/SOFORT/$uppername/g $utilcsrc> $utilcsrc.tmp || exit 2
+mv $utilcsrc.tmp $utilcsrc || exit 2
+
+touch COPYING.$uppername || exit 2
+echo "$project: project description" > README || exit 2
+
+chmod +x sysinfo/host/host.sh || exit 2
+chmod +x sysinfo/version.sh   || exit 2
+chmod +x ./configure          || exit 2
+
+# all done
+exit 0
diff --git a/src/driver/sfrt_driver_ctx.c b/src/driver/sfrt_driver_ctx.c
new file mode 100644
index 0000000..75afd0c
--- /dev/null
+++ b/src/driver/sfrt_driver_ctx.c
@@ -0,0 +1,169 @@
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define ARGV_DRIVER
+
+#include <sofort/sofort.h>
+#include "sofort_driver_impl.h"
+#include "argv/argv.h"
+
+extern const struct argv_option sfrt_default_options[];
+
+struct sfrt_driver_ctx_alloc {
+	struct argv_meta *		meta;
+	struct sfrt_driver_ctx_impl	ctx;
+	uint64_t			guard;
+	const char *			units[];
+};
+
+static uint32_t sfrt_argv_flags(uint32_t flags)
+{
+	uint32_t ret = 0;
+
+	if (flags & SFRT_DRIVER_VERBOSITY_NONE)
+		ret |= ARGV_VERBOSITY_NONE;
+
+	if (flags & SFRT_DRIVER_VERBOSITY_ERRORS)
+		ret |= ARGV_VERBOSITY_ERRORS;
+
+	if (flags & SFRT_DRIVER_VERBOSITY_STATUS)
+		ret |= ARGV_VERBOSITY_STATUS;
+
+	return ret;
+}
+
+static int sfrt_driver_usage(
+	const char *			program,
+	const char *			arg,
+	const struct argv_option *	options,
+	struct argv_meta *		meta)
+{
+	char header[512];
+
+	snprintf(header,sizeof(header),
+		"Usage: %s [options] <file>...\n" "Options:\n",
+		program);
+
+	argv_usage(stdout,header,options,arg);
+	argv_free(meta);
+
+	return SFRT_USAGE;
+}
+
+static struct sfrt_driver_ctx_impl * sfrt_driver_ctx_alloc(struct argv_meta * meta, size_t nunits)
+{
+	struct sfrt_driver_ctx_alloc *	ictx;
+	size_t				size;
+	struct argv_entry *		entry;
+	const char **			units;
+
+	size =  sizeof(struct sfrt_driver_ctx_alloc);
+	size += (nunits+1)*sizeof(const char *);
+
+	if (!(ictx = calloc(size,1)))
+		return 0;
+
+	for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++)
+		if (!entry->fopt)
+			*units++ = entry->arg;
+
+	ictx->ctx.ctx.units = ictx->units;
+	return &ictx->ctx;
+}
+
+int sfrt_get_driver_ctx_fail(struct argv_meta * meta)
+{
+	argv_free(meta);
+	return -1;
+}
+
+int sfrt_get_driver_ctx(
+	const char **		argv,
+	const char **		envp,
+	uint32_t		flags,
+	struct sfrt_driver_ctx ** pctx)
+{
+	struct sfrt_driver_ctx_impl *	ctx;
+	const struct argv_option *	options;
+	struct argv_meta *		meta;
+	struct argv_entry *		entry;
+	size_t				nunits;
+	uint64_t			dflags;
+	uint64_t			aflags;
+	const char *			program;
+	const char *			astring;
+
+	options = sfrt_default_options;
+
+	if (!(meta = argv_get(argv,options,sfrt_argv_flags(flags))))
+		return -1;
+
+	dflags	= 0;
+	aflags	= 0;
+	nunits	= 0;
+	astring = 0;
+	program = argv_program_name(argv[0]);
+
+	if (!argv[1] && (flags & SFRT_DRIVER_VERBOSITY_USAGE))
+		return sfrt_driver_usage(program,0,options,meta);
+
+	/* get options, count units */
+	for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
+		if (entry->fopt) {
+			switch (entry->tag) {
+				case TAG_HELP:
+					if (flags & SFRT_DRIVER_VERBOSITY_USAGE)
+						return sfrt_driver_usage(program,entry->arg,options,meta);
+
+				case TAG_VERSION:
+					dflags |= SFRT_DRIVER_VERSION;
+					break;
+
+				case TAG_OUTPUT_DUMMY:
+					astring = entry->arg;
+					break;
+
+				case TAG_OUTPUT_PROPERTY:
+					if (!(strcmp(entry->arg,"name")))
+						aflags |= SFRT_OUTPUT_NAME;
+					else if (!(strcmp(entry->arg,"address")))
+						aflags |= SFRT_OUTPUT_ADDRESS;
+					break;
+			}
+		} else
+			nunits++;
+	}
+
+	if (!(ctx = sfrt_driver_ctx_alloc(meta,nunits)))
+		return sfrt_get_driver_ctx_fail(meta);
+
+	ctx->ctx.program	= program;
+	ctx->cctx.drvflags	= dflags;
+	ctx->cctx.actflags	= aflags;
+	ctx->cctx.anystring	= astring;
+
+	ctx->ctx.cctx		= &ctx->cctx;
+
+	*pctx = &ctx->ctx;
+	return SFRT_OK;
+}
+
+static void sfrt_free_driver_ctx_impl(struct sfrt_driver_ctx_alloc * ictx)
+{
+	argv_free(ictx->meta);
+	free(ictx);
+}
+
+void sfrt_free_driver_ctx(struct sfrt_driver_ctx * ctx)
+{
+	struct sfrt_driver_ctx_alloc *	ictx;
+	uintptr_t			addr;
+
+	if (ctx) {
+		addr = (uintptr_t)ctx - offsetof(struct sfrt_driver_ctx_alloc,ctx);
+		addr = addr - offsetof(struct sfrt_driver_ctx_impl,ctx);
+		ictx = (struct sfrt_driver_ctx_alloc *)addr;
+		sfrt_free_driver_ctx_impl(ictx);
+	}
+}
diff --git a/src/driver/sfrt_unit_ctx.c b/src/driver/sfrt_unit_ctx.c
new file mode 100644
index 0000000..cef9913
--- /dev/null
+++ b/src/driver/sfrt_unit_ctx.c
@@ -0,0 +1,56 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <sofort/sofort.h>
+#include "sofort_driver_impl.h"
+
+static int sfrt_free_unit_ctx_impl(struct sfrt_unit_ctx_impl * ctx, int status)
+{
+	if (ctx) {
+		sfrt_unmap_input(&ctx->map);
+		free(ctx);
+	}
+
+	return status;
+}
+
+int sfrt_get_unit_ctx(
+	const struct sfrt_driver_ctx *	dctx,
+	const char *			path,
+	struct sfrt_unit_ctx **		pctx)
+{
+	struct sfrt_unit_ctx_impl *	ctx;
+
+	if (!dctx || !(ctx = calloc(sizeof(*ctx),1)))
+		return -1;
+
+	if (sfrt_map_input(-1,path,PROT_READ,&ctx->map))
+		return sfrt_free_unit_ctx_impl(ctx,-1);
+
+	memcpy(&ctx->cctx,dctx->cctx,
+		sizeof(ctx->cctx));
+
+	ctx->path	= path;
+
+	ctx->uctx.path	= &ctx->path;
+	ctx->uctx.map	= &ctx->map;
+	ctx->uctx.cctx	= &ctx->cctx;
+
+	*pctx = &ctx->uctx;
+	return 0;
+}
+
+void sfrt_free_unit_ctx(struct sfrt_unit_ctx * ctx)
+{
+	struct sfrt_unit_ctx_impl *	ictx;
+	uintptr_t			addr;
+
+	if (ctx) {
+		addr = (uintptr_t)ctx - offsetof(struct sfrt_unit_ctx_impl,uctx);
+		ictx = (struct sfrt_unit_ctx_impl *)addr;
+		sfrt_free_unit_ctx_impl(ictx,0);
+	}
+}
diff --git a/src/internal/argv/argv.h b/src/internal/argv/argv.h
new file mode 100644
index 0000000..9cb1e02
--- /dev/null
+++ b/src/internal/argv/argv.h
@@ -0,0 +1,876 @@
+/****************************************************************************/
+/*  argv.h: a thread-safe argument vector parser and usage screen generator */
+/*  Copyright (C) 2015  Z. Gilboa                                           */
+/*  Released under the Standard MIT License; see COPYING.SOFORT.            */
+/*  This file is (also) part of sofort: portable software project template. */
+/****************************************************************************/
+
+#ifndef ARGV_H
+#define ARGV_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define ARGV_VERBOSITY_NONE		0x00
+#define ARGV_VERBOSITY_ERRORS		0x01
+#define ARGV_VERBOSITY_STATUS		0x02
+#define ARGV_CLONE_VECTOR		0x80
+
+enum argv_optarg {
+	ARGV_OPTARG_NONE,
+	ARGV_OPTARG_REQUIRED,
+	ARGV_OPTARG_OPTIONAL,
+};
+
+enum argv_mode {
+	ARGV_MODE_SCAN,
+	ARGV_MODE_COPY,
+};
+
+enum argv_error {
+	ARGV_ERROR_OK,
+	ARGV_ERROR_INTERNAL,
+	ARGV_ERROR_SHORT_OPTION,
+	ARGV_ERROR_LONG_OPTION,
+	ARGV_ERROR_OPTARG_NONE,
+	ARGV_ERROR_OPTARG_REQUIRED,
+	ARGV_ERROR_OPTARG_PARADIGM,
+};
+
+struct argv_option {
+	const char *		long_name;
+	const char		short_name;
+	int			tag;
+	enum argv_optarg	optarg;
+	const char *		paradigm;
+	const char *		argname;
+	const char *		description;
+};
+
+struct argv_entry {
+	const char *	arg;
+	int		tag;
+	bool		fopt;
+	bool		fval;
+	bool		fnoscan;
+	enum argv_error errcode;
+};
+
+struct argv_meta {
+	const char **		argv;
+	struct argv_entry *	entries;
+};
+
+struct argv_meta_impl {
+	const char **		argv;
+	char *			strbuf;
+	struct argv_meta	meta;
+};
+
+struct argv_ctx {
+	int				flags;
+	int				mode;
+	int				nentries;
+	enum argv_error 		errcode;
+	const char *			errch;
+	const struct argv_option *	erropt;
+	const char *			program;
+};
+
+static const char * argv_program_name(const char *);
+
+static void argv_usage(
+	FILE *,
+	const char *	header,
+	const struct	argv_option[],
+	const char *	mode);
+
+static struct argv_meta * argv_get(
+	const char **,
+	const struct argv_option[],
+	int flags);
+
+static void argv_free(struct argv_meta *);
+
+
+
+
+/*------------------------------------*/
+/* implementation of static functions */
+/*------------------------------------*/
+
+#ifdef ARGV_DRIVER
+
+static const struct argv_option * argv_short_option(
+	const char *			ch,
+	const struct argv_option	options[],
+	struct argv_entry *		entry)
+{
+	const struct argv_option *	option;
+
+	for (option=options; option->long_name || option->short_name; option++) {
+		if (option->short_name == *ch) {
+			entry->tag	= option->tag;
+			entry->fopt	= true;
+			return option;
+		}
+	}
+
+	return 0;
+}
+
+static const struct argv_option * argv_long_option(
+	const char *			ch,
+	const struct argv_option	options[],
+	struct argv_entry *		entry)
+{
+	const struct argv_option *	option;
+	const char *			arg;
+	size_t				len;
+
+	for (option=options; option->long_name || option->short_name; option++) {
+		len = option->long_name ? strlen(option->long_name) : 0;
+
+		if (len && !(strncmp(option->long_name,ch,len))) {
+			arg = ch + len;
+
+			if (!*arg || (*arg == '=')) {
+				entry->tag	= option->tag;
+				entry->fopt	= true;
+				return option;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static inline bool is_short_option(const char * arg)
+{
+	return (arg[0]=='-') && arg[1] && (arg[1]!='-');
+}
+
+static inline bool is_long_option(const char * arg)
+{
+	return (arg[0]=='-') && (arg[1]=='-') && arg[2];
+}
+
+static inline bool is_last_option(const char * arg)
+{
+	return (arg[0]=='-') && (arg[1]=='-') && !arg[2];
+}
+
+static inline bool is_arg_in_paradigm(const char * arg, const char * paradigm)
+{
+	size_t		len;
+	const char *	ch;
+
+	for (ch=paradigm,len=strlen(arg); ch; ) {
+		if (!strncmp(arg,ch,len)) {
+			if (!*(ch += len))
+				return true;
+			else if (*ch == '|')
+				return true;
+		}
+
+		if ((ch = strchr(ch,'|')))
+			ch++;
+	}
+
+	return false;
+}
+
+static inline const struct argv_option * option_from_tag(
+	const struct argv_option	options[],
+	int				tag)
+{
+	const struct argv_option *	option;
+
+	for (option=options; option->short_name || option->long_name; option++)
+		if (option->tag == tag)
+			return option;
+	return 0;
+}
+
+static void argv_scan(
+	const char **			argv,
+	const struct argv_option	options[],
+	struct argv_ctx *		ctx,
+	struct argv_meta *		meta)
+{
+	const char **			parg;
+	const char *			ch;
+	const char *			val;
+	const struct argv_option *	option;
+	struct argv_entry		entry;
+	struct argv_entry *		mentry;
+	enum argv_error			ferror;
+	bool				fval;
+	bool				fnext;
+	bool				fshort;
+	bool				fnoscan;
+
+	argv++;
+	parg	= argv;
+	ch	= *parg;
+	ferror	= ARGV_ERROR_OK;
+	fshort	= false;
+	fnoscan	= false;
+	fval	= false;
+	mentry	= meta ? meta->entries : 0;
+
+	while (ch && (ferror == ARGV_ERROR_OK)) {
+		option = 0;
+
+		if (fnoscan)
+			fval = true;
+
+		else if (is_last_option(ch))
+			fnoscan = true;
+
+		else if ((fshort || is_short_option(ch))) {
+			if (!fshort)
+				ch++;
+
+			if ((option = argv_short_option(ch,options,&entry))) {
+				if (ch[1]) {
+					ch++;
+					fnext	= false;
+					fshort	= (option->optarg == ARGV_OPTARG_NONE);
+				} else {
+					parg++;
+					ch	= *parg;
+					fnext	= true;
+					fshort	= false;
+				}
+
+				if (option->optarg == ARGV_OPTARG_NONE) {
+					if (!fnext && ch && (*ch == '-'))
+						ferror = ARGV_ERROR_OPTARG_NONE;
+					else
+						fval = false;
+				} else if (!fnext)
+					fval = true;
+				else if (option->optarg == ARGV_OPTARG_REQUIRED) {
+					if (ch && is_short_option(ch))
+						ferror = ARGV_ERROR_OPTARG_REQUIRED;
+					else if (ch && is_long_option(ch))
+						ferror = ARGV_ERROR_OPTARG_REQUIRED;
+					else if (ch && is_last_option(ch))
+						ferror = ARGV_ERROR_OPTARG_REQUIRED;
+					else if (ch)
+						fval = true;
+					else
+						ferror = ARGV_ERROR_OPTARG_REQUIRED;
+				} else {
+					/* ARGV_OPTARG_OPTIONAL */
+					if (ch && is_short_option(ch))
+						fval = false;
+					else if (ch && is_long_option(ch))
+						fval = false;
+					else if (ch && is_last_option(ch))
+						fval = false;
+					else
+						fval = ch;
+				}
+			} else
+				ferror = ARGV_ERROR_SHORT_OPTION;
+
+		} else if ((is_long_option(ch))) {
+			if ((option = argv_long_option(ch+=2,options,&entry))) {
+				val = ch + strlen(option->long_name);
+
+				/* val[0] is either '=' or '\0' */
+				if (!val[0]) {
+					parg++;
+					ch = *parg;
+				}
+
+				if (option->optarg == ARGV_OPTARG_NONE) {
+					if (val[0]) {
+						ferror = ARGV_ERROR_OPTARG_NONE;
+						ctx->errch = val + 1;
+					} else
+						fval = false;
+				} else if (val[0] && !val[1])
+					ferror = ARGV_ERROR_OPTARG_REQUIRED;
+				else if (val[0] && val[1]) {
+					fval = true;
+					ch   = ++val;
+				} else if (option->optarg == ARGV_OPTARG_REQUIRED) {
+					if (!val[0] && !*parg)
+						ferror = ARGV_ERROR_OPTARG_REQUIRED;
+					else if (*parg && is_short_option(*parg))
+						ferror = ARGV_ERROR_OPTARG_REQUIRED;
+					else if (*parg && is_long_option(*parg))
+						ferror = ARGV_ERROR_OPTARG_REQUIRED;
+					else if (*parg && is_last_option(*parg))
+						ferror = ARGV_ERROR_OPTARG_REQUIRED;
+					else
+						fval = true;
+				} else {
+					/* ARGV_OPTARG_OPTIONAL */
+					if (!val[0] && !*parg)
+						fval = false;
+					if (*parg && is_short_option(*parg))
+						fval = false;
+					else if (*parg && is_long_option(*parg))
+						fval = false;
+					else if (*parg && is_last_option(*parg))
+						fval = false;
+					else
+						fval = *parg;
+				}
+			} else
+				ferror = ARGV_ERROR_LONG_OPTION;
+		}
+
+		if (ferror == ARGV_ERROR_OK)
+			if (option && fval && option->paradigm)
+				if (!is_arg_in_paradigm(ch,option->paradigm))
+					ferror = ARGV_ERROR_OPTARG_PARADIGM;
+
+		if (ferror != ARGV_ERROR_OK) {
+			ctx->errcode = ferror;
+			ctx->errch   = ctx->errch ? ctx->errch : ch;
+			ctx->erropt  = option;
+			return;
+		} else if (ctx->mode == ARGV_MODE_SCAN) {
+			if (!fnoscan)
+				ctx->nentries++;
+			else if (fval)
+				ctx->nentries++;
+
+			if (fval || !option) {
+				parg++;
+				ch = *parg;
+			}
+		} else if (ctx->mode == ARGV_MODE_COPY) {
+			if (fnoscan) {
+				if (fval) {
+					mentry->arg	= ch;
+					mentry->fnoscan = true;
+					mentry++;
+				}
+
+				parg++;
+				ch = *parg;
+			} else if (option) {
+				mentry->arg	= fval ? ch : 0;
+				mentry->tag	= option->tag;
+				mentry->fopt	= true;
+				mentry->fval	= fval;
+				mentry++;
+
+				if (fval) {
+					parg++;
+					ch = *parg;
+				}
+			} else {
+				mentry->arg = ch;
+				mentry++;
+				parg++;
+				ch = *parg;
+			}
+		}
+	}
+}
+
+static const char * argv_program_name(const char * program_path)
+{
+	const char * ch;
+
+	if (program_path) {
+		if ((ch = strrchr(program_path,'/')))
+			return *(++ch) ? ch : 0;
+
+		if ((ch = strrchr(program_path,'\\')))
+			return *(++ch) ? ch : 0;
+	}
+
+	return program_path;
+}
+
+static void argv_show_error(struct argv_ctx * ctx)
+{
+	fprintf(stderr,"%s: error: ",ctx->program);
+
+	switch (ctx->errcode) {
+		case ARGV_ERROR_SHORT_OPTION:
+			fprintf(stderr,"'%c' is not a valid short option\n",*ctx->errch);
+			break;
+
+		case ARGV_ERROR_LONG_OPTION:
+			fprintf(stderr,"'--%s' is not a valid long option\n",ctx->errch);
+			break;
+
+		case ARGV_ERROR_OPTARG_NONE:
+			fprintf(stderr,"'%s' is not a valid option value for [%s%c%s%s%s] (option values may not be specified)\n",
+				ctx->errch,
+				ctx->erropt->short_name ? "-" : "",
+				ctx->erropt->short_name,
+				ctx->erropt->short_name ? "," : "",
+				ctx->erropt->long_name ? "--" : "",
+				ctx->erropt->long_name);
+			break;
+
+		case ARGV_ERROR_OPTARG_REQUIRED:
+			fprintf(stderr,"option [%s%c%s%s%s] requires %s %s%s%s\n",
+				ctx->erropt->short_name ? "-" : "",
+				ctx->erropt->short_name,
+				ctx->erropt->short_name ? "," : "",
+				ctx->erropt->long_name ? "--" : "",
+				ctx->erropt->long_name,
+				ctx->erropt->paradigm ? "one of the following values:" : "a value",
+				ctx->erropt->paradigm ? "{" : "",
+				ctx->erropt->paradigm ? ctx->erropt->paradigm : "",
+				ctx->erropt->paradigm ? "}" : "");
+			break;
+
+		case ARGV_ERROR_OPTARG_PARADIGM:
+			fprintf(stderr,"'%s' is not a valid option value for [%s%c%s%s%s]={%s}\n",
+				ctx->errch,
+				ctx->erropt->short_name ? "-" : "",
+				ctx->erropt->short_name,
+				ctx->erropt->short_name ? "," : "",
+				ctx->erropt->long_name ? "--" : "",
+				ctx->erropt->long_name,
+				ctx->erropt->paradigm);
+			break;
+
+		case ARGV_ERROR_INTERNAL:
+			fputs("internal error",stderr);
+			break;
+
+		default:
+			break;
+	}
+}
+
+static void argv_show_status(
+	const struct argv_option	options[],
+	struct argv_ctx *		ctx,
+	struct argv_meta *		meta)
+{
+	int				argc;
+	const char **			argv;
+	struct argv_entry *		entry;
+	const struct argv_option *	option;
+	char				short_name[2] = {0};
+	const char *			space = "";
+
+	fputs("\n\nconcatenated command line:\n",stderr);
+	for (argv=meta->argv; *argv; argv++) {
+		fprintf(stderr,"%s%s",space,*argv);
+		space = " ";
+	}
+
+	fputs("\n\nargument vector:\n",stderr);
+	for (argc=0,argv=meta->argv; *argv; argc++,argv++)
+		fprintf(stderr,"argv[%d]: %s\n",argc,*argv);
+
+	fputs("\n\nparsed entries:\n",stderr);
+	for (entry=meta->entries; entry->arg || entry->fopt; entry++)
+		if (entry->fopt) {
+			option = option_from_tag(options,entry->tag);
+			short_name[0] = option->short_name;
+
+			if (entry->fval)
+				fprintf(stderr,"[-%s,--%s] := %s\n",
+					short_name,option->long_name,entry->arg);
+			else
+				fprintf(stderr,"[-%s,--%s]\n",
+					short_name,option->long_name);
+		} else
+			fprintf(stderr,"<program arg> := %s\n",entry->arg);
+
+	fputs("\n\n",stderr);
+}
+
+static struct argv_meta * argv_free_impl(struct argv_meta_impl * imeta)
+{
+	if (imeta->argv)
+		free(imeta->argv);
+
+	if (imeta->strbuf)
+		free(imeta->strbuf);
+
+	if (imeta->meta.entries)
+		free(imeta->meta.entries);
+
+	free(imeta);
+	return 0;
+}
+
+static struct argv_meta * argv_alloc(const char ** argv, struct argv_ctx * ctx)
+{
+	struct argv_meta_impl * imeta;
+	const char **		vector;
+	char *			dst;
+	size_t			size;
+	int			argc;
+	int			i;
+
+	if (!(imeta = calloc(sizeof(*imeta),1)))
+		return 0;
+
+	if (ctx->flags & ARGV_CLONE_VECTOR) {
+		for (vector=argv,argc=0,size=0; *vector; vector++) {
+			size += strlen(*vector) + 1;
+			argc++;
+		}
+
+		if (!(imeta->argv = calloc(sizeof(char *),argc+1)))
+			return argv_free_impl(imeta);
+		else if (!(imeta->strbuf = calloc(size+1,1)))
+			return argv_free_impl(imeta);
+
+		for (i=0,dst=imeta->strbuf; i<argc; i++) {
+			strcpy(dst,argv[i]);
+			imeta->argv[i] = dst;
+			dst += strlen(dst)+1;
+		}
+
+		imeta->meta.argv = imeta->argv;
+	} else
+		imeta->meta.argv = argv;
+
+	if (!(imeta->meta.entries = calloc(sizeof(struct argv_entry),ctx->nentries+1)))
+		return argv_free_impl(imeta);
+	else
+		return &imeta->meta;
+}
+
+static struct argv_meta * argv_get(
+	const char *			argv[],
+	const struct argv_option	options[],
+	int				flags)
+{
+	struct argv_meta *	meta;
+	struct argv_ctx		ctx = {flags,ARGV_MODE_SCAN,0,0,0,0};
+
+	argv_scan(argv,options,&ctx,0);
+
+	if (ctx.errcode != ARGV_ERROR_OK) {
+		if (!ctx.program)
+			ctx.program = argv_program_name(argv[0]);
+
+		if (ctx.flags & ARGV_VERBOSITY_ERRORS)
+			argv_show_error(&ctx);
+
+		return 0;
+	}
+
+	if (!(meta = argv_alloc(argv,&ctx)))
+		return 0;
+
+	ctx.mode = ARGV_MODE_COPY;
+	argv_scan(meta->argv,options,&ctx,meta);
+
+	if (ctx.errcode != ARGV_ERROR_OK) {
+		if (!ctx.program)
+			ctx.program = argv[0];
+
+		ctx.errcode = ARGV_ERROR_INTERNAL;
+		argv_show_error(&ctx);
+		argv_free(meta);
+
+		return 0;
+	}
+
+	if (ctx.flags & ARGV_VERBOSITY_STATUS)
+		argv_show_status(options,&ctx,meta);
+
+	return meta;
+}
+
+static void argv_free(struct argv_meta * xmeta)
+{
+	struct argv_meta_impl * imeta;
+	uintptr_t		addr;
+
+	if (xmeta) {
+		addr  = (uintptr_t)xmeta - offsetof(struct argv_meta_impl,meta);
+		imeta = (struct argv_meta_impl *)addr;
+		argv_free_impl(imeta);
+	}
+}
+
+static void argv_usage(
+	FILE *				file,
+	const char *    		header,
+	const struct argv_option	options[],
+	const char *			mode)
+{
+	const struct argv_option *	option;
+	bool				fshort,flong;
+	bool				fnewline;
+	size_t				len,optlen;
+	size_t				paralen,rparalen,mparalen;
+	size_t				desclen,rdesclen;
+
+	char *				para;
+	char *				next_para;
+	char *				desc;
+	char *				next_desc;
+	char *				paradigm;
+	char *				buf;
+	size_t				buflen;
+	const char *			sdescription;
+	const char *			sargname;
+
+	const char			indent[] = "  ";
+	const int			rblen  = sizeof("}") - sizeof(char);
+	const int			rbblen = sizeof("{]") - sizeof(char);
+	const int			brcklen= sizeof("[]") - sizeof(char);
+	const int			solen  = sizeof("-") - sizeof(char);
+	const int			lolen  = sizeof("--") - sizeof(char);
+	const int			slolen = sizeof("-X,--") - sizeof(char);
+
+	fshort = mode ? !strcmp(mode,"short") : 0;
+	flong  = fshort ? 0 : mode && !strcmp(mode,"long");
+
+	if (header)
+		fprintf(stdout,"%s",header);
+
+	for (option=options,optlen=0,paralen=0; option->short_name || option->long_name; option++) {
+		if (fshort)
+			len = option->short_name ? sizeof(char) + solen : 0;
+		else if (flong)
+			len = option->long_name ? strlen(option->long_name) + lolen : 0;
+		else
+			len = option->long_name ? strlen(option->long_name) + slolen : 0;
+
+		if (len) {
+			if (len > optlen)
+				optlen = len;
+
+			if (option->paradigm)
+				len = strlen(option->paradigm) + strlen("{}");
+			else if (option->argname)
+				len = strlen(option->argname);
+			else if (option->optarg != ARGV_OPTARG_NONE)
+				len = strlen("<val>");
+
+			if (option->optarg == ARGV_OPTARG_OPTIONAL)
+				len += strlen("[]");
+
+			if (len > paralen)
+				paralen = len;
+		}
+	}
+
+	optlen += 8;
+	optlen &= (~7);
+
+	if (paralen) {
+		paralen += (8);
+		paralen &= (~7);
+		mparalen = paralen + 2*rbblen;
+
+		if (optlen + paralen > 64)
+			paralen = 32;
+	}
+
+	/* account for '  ','\t', try to fit in 80 or 96 columns */
+	if (optlen+paralen+2+8 < 80-32)
+		desclen = 80 - (optlen+paralen+2+8);
+	else if (optlen+paralen+2+8 < 96-32)
+		desclen = 96 - (optlen+paralen+2+8);
+	else
+		desclen = 32;
+
+	paradigm = next_para = buf = 0;
+	fnewline = false;
+	rparalen = 0;
+	mparalen = 0;
+
+	for (option=options,buflen=0,rdesclen=1; option->short_name || option->long_name; option++) {
+		if (option->paradigm) {
+			if (option->optarg == ARGV_OPTARG_OPTIONAL)
+				rparalen = strlen(option->paradigm) - 2*rbblen;
+			else
+				rparalen = strlen(option->paradigm) - 2*rblen;
+		}
+
+		sdescription 	= option->description ? option->description : "";
+		sargname	= option->argname ? option->argname : "";
+
+		if (option->paradigm)
+			rdesclen = snprintf(buf,buflen,sdescription,option->paradigm);
+		else
+			rdesclen = snprintf(buf,buflen,sdescription,sargname);
+
+		if (fnewline)
+			(void)0;
+
+		if ((rparalen > paralen) || (rdesclen > desclen)) {
+			if (!fnewline) {
+				(void)0;
+				fnewline = true;
+			}
+		} else
+			fnewline = false;
+
+		if (fshort)
+			fprintf(file,"%s-%-*c",indent,(int)(optlen-solen),option->short_name);
+		else if (flong)
+			fprintf(file,"%s--%-*s",indent,(int)(optlen-lolen),option->long_name);
+		else {
+			if (option->short_name && option->long_name)
+				fprintf(file,"%s-%c,--%-*s",indent,option->short_name,(int)(optlen-slolen),option->long_name);
+			else if (option->short_name)
+				 fprintf(file,"%s-%-*c",indent,(int)(optlen-solen),option->short_name);
+			else
+				fprintf(file,"%s%3s--%-*s",indent,"",(int)(optlen-slolen),option->long_name);
+		}
+
+		if (rdesclen > buflen) {
+			if (buf) {
+				free(buf);
+				buf = 0;
+			}
+
+			len =  rdesclen + 512;
+			len &= (~511);
+
+			if ((buf = calloc(len,1))) {
+				buflen = len;
+
+				if (option->paradigm)
+					rdesclen = snprintf(buf,buflen,option->description,option->paradigm);
+				else
+					rdesclen = snprintf(buf,buflen,option->description,option->argname);
+			} else {
+				buflen = 0;
+				continue;
+			}
+		}
+
+		if (option->paradigm && (rparalen <= paralen)) {
+			if (option->optarg == ARGV_OPTARG_OPTIONAL)
+				fprintf(file,"[{%s}]%-*c",option->paradigm,(int)(paralen-strlen(option->paradigm)-2*rbblen),' ');
+			else
+				fprintf(file,"{%s}%-*c",option->paradigm,(int)(paralen-strlen(option->paradigm)-rbblen),' ');
+			para = (char *)0;
+		} else if (option->paradigm) {
+			if (!paradigm && !(paradigm = calloc(mparalen,1))) {
+				fputc('\n',file);
+				continue;
+			} else
+				para = strcpy(paradigm,option->paradigm);
+
+			if (option->optarg == ARGV_OPTARG_OPTIONAL) {
+				fputs("[{",file);
+				rparalen = paralen - rbblen;
+			} else {
+				fputc('{',file);
+				rparalen = paralen - rblen;
+			}
+		} else if (option->argname) {
+			if (option->optarg == ARGV_OPTARG_OPTIONAL)
+				fprintf(file,"[%s]%-*c",option->argname,(int)(paralen-strlen(option->argname)-brcklen),' ');
+			else
+				fprintf(file,"%s%-*c",option->argname,(int)(paralen-strlen(option->argname)),' ');
+			para = (char *)0;
+		} else {
+			fprintf(file,"%-*c",(int)paralen,' ');
+			para = (char *)0;
+		}
+
+
+		if (!para && option->description && rdesclen <= desclen) {
+			fputc('\t',file);
+			fputs(buf,file);
+			desc = (char *)0;
+		} else if (option->description)
+			desc = buf;
+		else
+			desc = (char *)0;
+
+		while (para || desc) {
+			if (para) {
+				for (next_para=para+rparalen-1; (next_para>para) && (*next_para!='|'); )
+					next_para--;
+
+				if (para > paradigm) {
+					if (option->optarg == ARGV_OPTARG_OPTIONAL)
+						fputs("  ",file);
+					else
+						fputc(' ',file);
+				}
+
+				if (*next_para != '|') {
+					fprintf(file,"%s",para);
+					para = (char *)0;
+				} else if (next_para > para) {
+					*next_para = '\0';
+					fprintf(file,"%-*s",(int)rparalen,para);
+					*next_para = '|';
+					para = next_para;
+					rparalen = strlen(para);
+
+					/* 2*rbblen,2*rblen, etc.: account for indentation */
+					if (option->optarg == ARGV_OPTARG_OPTIONAL)
+						rparalen = (rparalen+2*rbblen > paralen) ? paralen-rbblen : rparalen;
+					else
+						rparalen = (rparalen+2*rblen > paralen) ? paralen-rblen : rparalen;
+				} else {
+					if (option->optarg == ARGV_OPTARG_OPTIONAL)
+						fprintf(file,"%s}]%-*c",para,(int)(paralen-strlen(para)-rbblen),' ');
+					else
+						fprintf(file,"%s}%-*c",para,(int)(paralen-strlen(para)-rblen),' ');
+					para = (char *)0;
+				}
+			} else if (desc > buf)
+				fprintf(file,"%-*c",(int)paralen,' ');
+
+			if (desc) {
+				if (desc > buf)
+					fputs("\t ",file);
+				else
+					fputc('\t',file);
+
+				if ((rdesclen = strlen(desc)+(desc>buf)) <= desclen) {
+					fputs(desc,file);
+					desc = (char *)0;
+				} else {
+					for (next_desc=desc+desclen-1; (next_desc>desc) && (*next_desc!=' ') && (*next_desc!='\n'); )
+						next_desc--;
+
+					if ((*next_desc != ' ') && (*next_desc!='\n')) {
+						fputs(desc,file);
+						desc = (char *)0;
+					} else if (next_desc > desc) {
+						*next_desc = '\0';
+						fputs(desc,file);
+						desc = ++next_desc;
+					} else {
+						fputs(desc,file);
+						desc = (char *)0;
+					}
+				}
+			}
+
+			if (para || desc)
+				fprintf(file,"\n%s%-*c",indent,(int)optlen,' ');
+		}
+
+		fputc('\n',file);
+	}
+
+	if (paradigm)
+		free(paradigm);
+
+	if (buf)
+		free(buf);
+}
+
+#endif
+
+#endif
diff --git a/src/internal/sofort_driver_impl.h b/src/internal/sofort_driver_impl.h
new file mode 100644
index 0000000..f72d200
--- /dev/null
+++ b/src/internal/sofort_driver_impl.h
@@ -0,0 +1,29 @@
+#ifndef SFRT_DRIVER_IMPL_H
+#define SFRT_DRIVER_IMPL_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <sofort/sofort.h>
+
+enum app_tags {
+	TAG_HELP,
+	TAG_VERSION,
+	TAG_OUTPUT_DUMMY,
+	TAG_OUTPUT_PROPERTY,
+};
+
+struct sfrt_driver_ctx_impl {
+	struct sfrt_common_ctx	cctx;
+	struct sfrt_driver_ctx	ctx;
+};
+
+struct sfrt_unit_ctx_impl {
+	const char *		path;
+	struct sfrt_input	map;
+	struct sfrt_common_ctx	cctx;
+	struct sfrt_unit_ctx	uctx;
+};
+
+#endif
diff --git a/src/logic/sfrt_map_input.c b/src/logic/sfrt_map_input.c
new file mode 100644
index 0000000..74fbdb5
--- /dev/null
+++ b/src/logic/sfrt_map_input.c
@@ -0,0 +1,45 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <sofort/sofort.h>
+
+int sfrt_map_input(
+	int			fd,
+	const char *		path,
+	int			prot,
+	struct sfrt_input *	map)
+{
+	struct stat	stat;
+	bool		fnew;
+	int		ret;
+
+	if ((fnew = (fd < 0)))
+		fd  = open(path,O_RDONLY | O_CLOEXEC);
+
+	if (fd < 0)
+		return -1;
+
+	if ((ret = fstat(fd,&stat) < 0) && fnew)
+		close(fd);
+
+	if (ret < 0)
+		return -1;
+
+	map->size = stat.st_size;
+	map->addr = mmap(0,map->size,prot,MAP_PRIVATE,fd,0);
+
+	if (fnew)
+		close(fd);
+
+	return (map->addr == MAP_FAILED) ? -1 : 0;
+}
+
+int sfrt_unmap_input(struct sfrt_input * map)
+{
+	return munmap(map->addr,map->size);
+}
diff --git a/src/output/sfrt_output_address.c b/src/output/sfrt_output_address.c
new file mode 100644
index 0000000..d447818
--- /dev/null
+++ b/src/output/sfrt_output_address.c
@@ -0,0 +1,13 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sofort/sofort.h>
+
+sfrt_api
+int sfrt_output_address(const struct sfrt_unit_ctx * uctx, FILE * f)
+{
+	return fprintf(f,"%0*p\n",2*sizeof(size_t),uctx->map->addr);
+}
diff --git a/src/output/sfrt_output_dummy.c b/src/output/sfrt_output_dummy.c
new file mode 100644
index 0000000..4342737
--- /dev/null
+++ b/src/output/sfrt_output_dummy.c
@@ -0,0 +1,13 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sofort/sofort.h>
+
+sfrt_api
+int sfrt_output_dummy (const struct sfrt_common_ctx * cctx, FILE * f)
+{
+	return fprintf(f,"%s\n",cctx->anystring ? cctx->anystring : "(null)");
+}
diff --git a/src/output/sfrt_output_name.c b/src/output/sfrt_output_name.c
new file mode 100644
index 0000000..c0aff5e
--- /dev/null
+++ b/src/output/sfrt_output_name.c
@@ -0,0 +1,13 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sofort/sofort.h>
+
+sfrt_api
+int sfrt_output_name(const struct sfrt_unit_ctx * uctx, FILE * f)
+{
+	return fprintf(f,"%s\n",*uctx->path);
+}
diff --git a/src/skin/sfrt_skin_default.c b/src/skin/sfrt_skin_default.c
new file mode 100644
index 0000000..ef3f6b9
--- /dev/null
+++ b/src/skin/sfrt_skin_default.c
@@ -0,0 +1,18 @@
+#include "sofort_driver_impl.h"
+#include "argv/argv.h"
+
+const struct argv_option sfrt_default_options[] = {
+	{"version",		'v',TAG_VERSION,ARGV_OPTARG_NONE,0,0,
+				"show version information"},
+
+	{"help",		'h',TAG_HELP,ARGV_OPTARG_OPTIONAL,"short|long",0,
+				"show usage information [listing %s options only]"},
+
+	{"output-dummy",	'o',TAG_OUTPUT_DUMMY,ARGV_OPTARG_REQUIRED,0,"<anystring>",
+				"output %s"},
+
+	{"output-property",	'p',TAG_OUTPUT_PROPERTY,ARGV_OPTARG_REQUIRED,"name|address",0,
+				"output %s"},
+
+	{0}
+};
diff --git a/src/sofort.c b/src/sofort.c
new file mode 100644
index 0000000..af04373
--- /dev/null
+++ b/src/sofort.c
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <sofort/sofort.h>
+#include "sofort_version.h"
+
+#ifndef SFRT_DRIVER_FLAGS
+#define SFRT_DRIVER_FLAGS	SFRT_DRIVER_VERBOSITY_ERRORS \
+				| SFRT_DRIVER_VERBOSITY_USAGE
+#endif
+
+static const char vermsg[] = "%s (git://midipix.org/sofort): commit %s.\n";
+
+static ssize_t sofort_version(struct sfrt_driver_ctx * dctx)
+{
+	return fprintf(stdout,vermsg,dctx->program,SOFORT_GIT_VERSION);
+}
+
+static void sofort_perform_unit_actions(struct sfrt_unit_ctx * uctx)
+{
+	uint64_t flags = uctx->cctx->actflags;
+
+	if (flags & SFRT_OUTPUT_NAME) {
+		uctx->status = sfrt_output_name(uctx,stdout);
+		uctx->nerrors += !!uctx->status;
+	}
+
+	if (flags & SFRT_OUTPUT_ADDRESS) {
+		uctx->status = sfrt_output_address(uctx,stdout);
+		uctx->nerrors += !!uctx->status;
+	}
+}
+
+static int sofort_exit(struct sfrt_driver_ctx * dctx, int nerrors)
+{
+	sfrt_free_driver_ctx(dctx);
+	return nerrors ? 2 : 0;
+}
+
+int sofort_main(int argc, const char ** argv, const char ** envp)
+{
+	int				ret;
+	struct sfrt_driver_ctx *	dctx;
+	struct sfrt_unit_ctx *		uctx;
+	const char **			unit;
+
+	if ((ret = sfrt_get_driver_ctx(argv,envp,SFRT_DRIVER_FLAGS,&dctx)))
+		return (ret == SFRT_USAGE) ? !--argc : 2;
+
+	if (dctx->cctx->drvflags & SFRT_DRIVER_VERSION)
+		if ((sofort_version(dctx)) < 0)
+			return sofort_exit(dctx,2);
+
+	if (dctx->cctx->anystring)
+		if ((sfrt_output_dummy(dctx->cctx,stdout)) < 0)
+			return sofort_exit(dctx,2);
+
+	for (unit=dctx->units; *unit; unit++) {
+		if (!(sfrt_get_unit_ctx(dctx,*unit,&uctx))) {
+			sofort_perform_unit_actions(uctx);
+			ret += uctx->nerrors;
+			sfrt_free_unit_ctx(uctx);
+		}
+	}
+
+	return sofort_exit(dctx,ret);
+}
+
+#ifndef SOFORT_IN_A_BOX
+
+int main(int argc, const char ** argv, const char ** envp)
+{
+	return sofort_main(argc,argv,envp);
+}
+
+#endif
diff --git a/sysinfo/host/host.sh b/sysinfo/host/host.sh
new file mode 100755
index 0000000..5d963c9
--- /dev/null
+++ b/sysinfo/host/host.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+error_msg()
+{
+	echo $@ >&2
+}
+
+host_test()
+{
+	mb_hdrdir=$(pwd)/build
+	mkdir -p $mb_hdrdir || exit 2
+
+	if [ x"$mb_compiler" = x ]; then
+                echo "config error: compiler not set."
+		exit 2
+	fi
+
+	$mb_compiler -dM -E - < /dev/null > /dev/null && return 0
+
+	error_msg "config error: invalid compiler."
+	exit 2
+}
+
+host_endian_h()
+{
+	mb_header='endian.h'
+	rm -f "$mb_hdrdir"/$mb_header
+
+	# portable
+	printf "#include <$mb_header>" | $mb_compiler $mb_cflags \
+		-E - > /dev/null 2>/dev/null \
+		&& return 0
+
+	# non-portable
+	mb_hosthdr=
+
+	[ -z $mb_hosthdr ] && printf "#include <sys/$mb_header>" | $mb_compiler $mb_cflags \
+		-E - > /dev/null 2>/dev/null \
+		&& mb_hosthdr='sys/'$mb_header
+
+	[ -z $mb_hosthdr ] && printf "#include <machine/$mb_header>" | $mb_compiler $mb_cflags \
+		-E - > /dev/null 2>/dev/null \
+		&& mb_hosthdr='machine/'$mb_header
+
+	if [ x"$mb_hosthdr" = x ]; then
+		error_msg "config error: could not find an alternate <$mb_header>."
+		exit 2
+	fi
+
+	printf "#include <%s>\\n" $mb_hosthdr > "$mb_hdrdir"/$mb_header || exit 2
+}
+
+
+# one: args
+for arg ; do
+	case "$arg" in
+		--help)	usage
+			;;
+		--compiler=*)
+			mb_compiler=${arg#*=}
+			;;
+		--cflags=*)
+			mb_cflags=${arg#*=}
+			;;
+		*)
+			error_msg ${arg#}: "unsupported config argument."
+			exit 2
+			;;
+	esac
+done
+
+
+# two: test
+host_test
+
+
+# three: headers
+host_endian_h
+
+
+# all done
+exit 0
diff --git a/sysinfo/host/i686-nt32-midipix.mk b/sysinfo/host/i686-nt32-midipix.mk
new file mode 100644
index 0000000..df3185b
--- /dev/null
+++ b/sysinfo/host/i686-nt32-midipix.mk
@@ -0,0 +1,5 @@
+include $(PROJECT_DIR)/sysinfo/os/midipix.mk
+
+ARCH 		= nt32
+HOST_BITS 	= 32
+HOST_UNDERSCORE = '_'
diff --git a/sysinfo/host/i686-unknown-linux.mk b/sysinfo/host/i686-unknown-linux.mk
new file mode 100644
index 0000000..79d497b
--- /dev/null
+++ b/sysinfo/host/i686-unknown-linux.mk
@@ -0,0 +1,5 @@
+include $(PROJECT_DIR)/sysinfo/os/linux.mk
+
+ARCH 		= i386
+HOST_BITS 	= 32
+HOST_UNDERSCORE = '_'
diff --git a/sysinfo/host/i686-w64-mingw32.mk b/sysinfo/host/i686-w64-mingw32.mk
new file mode 100644
index 0000000..b8ba461
--- /dev/null
+++ b/sysinfo/host/i686-w64-mingw32.mk
@@ -0,0 +1,5 @@
+include $(PROJECT_DIR)/sysinfo/os/mingw.mk
+
+ARCH 		= w32
+HOST_BITS 	= 32
+HOST_UNDERSCORE = '_'
diff --git a/sysinfo/host/native.mk b/sysinfo/host/native.mk
new file mode 100644
index 0000000..08b02b6
--- /dev/null
+++ b/sysinfo/host/native.mk
@@ -0,0 +1,45 @@
+include $(PROJECT_DIR)/sysinfo/os/$(NATIVE_OS).mk
+
+OS 		= $(NATIVE_OS)
+HOST_BITS 	= $(NATIVE_OS_BITS)
+HOST_UNDERSCORE = $(NATIVE_OS_UNDERSCORE)
+
+ifeq ($(OS),linux)
+	ifeq ($(HOST_BITS),32)
+		ARCH = i386
+	else ifeq ($(HOST_BITS),64)
+		ARCH = x86_64
+	endif
+endif
+
+ifeq ($(OS),midipix)
+	ifeq ($(HOST_BITS),32)
+		ARCH = nt32
+	else ifeq ($(HOST_BITS),64)
+		ARCH = nt64
+	endif
+endif
+
+ifeq ($(OS),mingw)
+	ifeq ($(HOST_BITS),32)
+		ARCH = w32
+	else ifeq ($(HOST_BITS),64)
+		ARCH = w64
+	endif
+endif
+
+ifeq ($(OS),bsd)
+	ifeq ($(HOST_BITS),32)
+		ARCH = bsd32
+	else ifeq ($(HOST_BITS),64)
+		ARCH = bsd64
+	endif
+endif
+
+ifeq ($(OS),darwin)
+	ifeq ($(HOST_BITS),32)
+		ARCH = dw32
+	else ifeq ($(HOST_BITS),64)
+		ARCH = dw64
+	endif
+endif
diff --git a/sysinfo/host/x86_64-nt64-midipix.mk b/sysinfo/host/x86_64-nt64-midipix.mk
new file mode 100644
index 0000000..fef6345
--- /dev/null
+++ b/sysinfo/host/x86_64-nt64-midipix.mk
@@ -0,0 +1,5 @@
+include $(PROJECT_DIR)/sysinfo/os/midipix.mk
+
+ARCH 		= nt64
+HOST_BITS 	= 64
+HOST_UNDERSCORE = ''
diff --git a/sysinfo/host/x86_64-unknown-linux.mk b/sysinfo/host/x86_64-unknown-linux.mk
new file mode 100644
index 0000000..76afb56
--- /dev/null
+++ b/sysinfo/host/x86_64-unknown-linux.mk
@@ -0,0 +1,5 @@
+include $(PROJECT_DIR)/sysinfo/os/linux.mk
+
+ARCH 		= x86_64
+HOST_BITS 	= 64
+HOST_UNDERSCORE = ''
diff --git a/sysinfo/host/x86_64-w64-mingw32.mk b/sysinfo/host/x86_64-w64-mingw32.mk
new file mode 100644
index 0000000..7cded15
--- /dev/null
+++ b/sysinfo/host/x86_64-w64-mingw32.mk
@@ -0,0 +1,5 @@
+include $(PROJECT_DIR)/sysinfo/os/mingw.mk
+
+ARCH 		= w64
+HOST_BITS 	= 64
+HOST_UNDERSCORE = ''
diff --git a/sysinfo/os/bsd.mk b/sysinfo/os/bsd.mk
new file mode 100644
index 0000000..3fe6711
--- /dev/null
+++ b/sysinfo/os/bsd.mk
@@ -0,0 +1,10 @@
+OS 		= bsd
+OS_APP_PREFIX 	=
+OS_APP_SUFFIX 	=
+OS_LIB_PREFIX 	= lib
+OS_LIB_SUFFIX 	= .so
+OS_IMPLIB_EXT 	= .invalid
+OS_LIBDEF_EXT 	= .invalid
+OS_ARCHIVE_EXT 	= .a
+
+.PHONY:		$(SHARED_IMPLIB)
diff --git a/sysinfo/os/darwin.mk b/sysinfo/os/darwin.mk
new file mode 100644
index 0000000..b27a486
--- /dev/null
+++ b/sysinfo/os/darwin.mk
@@ -0,0 +1,10 @@
+OS 		= darwin
+OS_APP_PREFIX 	=
+OS_APP_SUFFIX 	=
+OS_LIB_PREFIX 	= lib
+OS_LIB_SUFFIX 	= .dylib
+OS_IMPLIB_EXT 	= .invalid
+OS_LIBDEF_EXT 	= .invalid
+OS_ARCHIVE_EXT 	= .a
+
+.PHONY:		$(SHARED_IMPLIB)
diff --git a/sysinfo/os/linux.mk b/sysinfo/os/linux.mk
new file mode 100644
index 0000000..d6221cf
--- /dev/null
+++ b/sysinfo/os/linux.mk
@@ -0,0 +1,10 @@
+OS 		= linux
+OS_APP_PREFIX 	=
+OS_APP_SUFFIX 	=
+OS_LIB_PREFIX 	= lib
+OS_LIB_SUFFIX 	= .so
+OS_IMPLIB_EXT 	= .invalid
+OS_LIBDEF_EXT 	= .invalid
+OS_ARCHIVE_EXT 	= .a
+
+.PHONY:		$(SHARED_IMPLIB)
diff --git a/sysinfo/os/midipix.mk b/sysinfo/os/midipix.mk
new file mode 100644
index 0000000..fded25e
--- /dev/null
+++ b/sysinfo/os/midipix.mk
@@ -0,0 +1,14 @@
+OS 		= midipix
+OS_APP_PREFIX 	=
+OS_APP_SUFFIX 	=
+OS_LIB_PREFIX 	= lib
+OS_LIB_SUFFIX 	= .so
+OS_IMPLIB_EXT 	= .lib.a
+OS_LIBDEF_EXT 	= .so.def
+OS_ARCHIVE_EXT 	= .a
+
+LDFLAGS_CONFIG	+= -mout-implib
+
+install-implib: shared-implib
+		mkdir -p $(DESTDIR)/./$(PREFIX)/./$(LIBDIR)
+		cp $(SHARED_IMPLIB) $(DESTDIR)/./$(PREFIX)/./$(LIBDIR)
diff --git a/sysinfo/os/mingw.mk b/sysinfo/os/mingw.mk
new file mode 100644
index 0000000..75aba53
--- /dev/null
+++ b/sysinfo/os/mingw.mk
@@ -0,0 +1,15 @@
+OS 		= mingw
+OS_APP_PREFIX 	=
+OS_APP_SUFFIX 	= .exe
+OS_LIB_PREFIX 	= lib
+OS_LIB_SUFFIX 	= .dll
+OS_IMPLIB_EXT 	= .dll.a
+OS_LIBDEF_EXT 	= .def
+OS_ARCHIVE_EXT 	= .a
+
+CFLAGS_PIC 	=
+LDFLAGS_CONFIG	+= -Wl,--out-implib,$(SHARED_IMPLIB)
+
+install-implib:	shared-implib
+		mkdir -p $(DESTDIR)/./$(PREFIX)/./$(LIBDIR)
+		cp $(SHARED_IMPLIB) $(DESTDIR)/./$(PREFIX)/./$(LIBDIR)
diff --git a/sysinfo/toolchain/clang.mk b/sysinfo/toolchain/clang.mk
new file mode 100644
index 0000000..3e4a795
--- /dev/null
+++ b/sysinfo/toolchain/clang.mk
@@ -0,0 +1,48 @@
+ifeq ($(CROSS_COMPILE)x,x)
+	CROSS_HOST 	=
+	CROSS_HOST_SPEC =
+else
+	CROSS_HOST 	= $(HOST)
+	CROSS_HOST_SPEC = --target=$(HOST)
+endif
+
+
+ifeq ($(USER_CC)x,x)
+	CC	= $(NATIVE_CC) $(CROSS_HOST_SPEC)
+else
+	CC	= $(USER_CC) $(CROSS_HOST_SPEC)
+endif
+
+ifeq ($(USER_CPP)x,x)
+	CPP	= $(NATIVE_CC) $(CROSS_HOST_SPEC) -E
+else
+	CPP	= $(USER_CPP) $(CROSS_HOST_SPEC) -E
+endif
+
+ifeq ($(USER_CXX)x,x)
+	CXX	= $(NATIVE_CC)++ $(CROSS_HOST_SPEC)
+else
+	CXX	= $(USER_CXX) $(CROSS_HOST_SPEC)
+endif
+
+
+AS 		= $(CROSS_COMPILE)as
+AR 		= $(CROSS_COMPILE)ar
+LD 		= $(CROSS_COMPILE)ld
+NM 		= $(CROSS_COMPILE)nm
+OBJDUMP 	= $(CROSS_COMPILE)objdump
+RANLIB 		= $(CROSS_COMPILE)ranlib
+SIZE 		= $(CROSS_COMPILE)size
+STRIP 		= $(CROSS_COMPILE)strip
+STRINGS 	= $(CROSS_COMPILE)strings
+
+
+ADDR2LINE 	= $(CROSS_COMPILE)addr2line
+COV 		= $(CROSS_COMPILE)gcov
+CXXFILT 	= $(CROSS_COMPILE)c++filt
+ELFEDIT 	= $(CROSS_COMPILE)elfedit
+OBJCOPY 	= $(CROSS_COMPILE)objcopy
+READELF 	= $(CROSS_COMPILE)readelf
+
+
+CFLAGS_PIC 	= -fPIC
diff --git a/sysinfo/toolchain/cparser.mk b/sysinfo/toolchain/cparser.mk
new file mode 100644
index 0000000..762a6e6
--- /dev/null
+++ b/sysinfo/toolchain/cparser.mk
@@ -0,0 +1,48 @@
+ifeq ($(CROSS_COMPILE)x,x)
+	CROSS_HOST 	=
+	CROSS_HOST_SPEC =
+else
+	CROSS_HOST 	= $(HOST)
+	CROSS_HOST_SPEC = --target=$(HOST)
+endif
+
+
+ifeq ($(USER_CC)x,x)
+	CC	= $(NATIVE_CC) $(CROSS_HOST_SPEC) -Wno-experimental -integrated-cpp
+else
+	CC	= $(USER_CC) $(CROSS_HOST_SPEC) -Wno-experimental -integrated-cpp
+endif
+
+ifeq ($(USER_CPP)x,x)
+	CPP	= $(NATIVE_CC) $(CROSS_HOST_SPEC) -Wno-experimental -integrated-cpp -E
+else
+	CPP	= $(USER_CPP) $(CROSS_HOST_SPEC) -Wno-experimental -integrated-cpp -E
+endif
+
+ifeq ($(USER_CXX)x,x)
+	CXX	= $(NATIVE_CC) $(CROSS_HOST_SPEC) -Wno-experimental -integrated-cpp -std=c++
+else
+	CXX	= $(USER_CXX) $(CROSS_HOST_SPEC) -Wno-experimental -integrated-cpp -std=c++
+endif
+
+
+AS 		= $(CROSS_COMPILE)as
+AR 		= $(CROSS_COMPILE)ar
+LD 		= $(CROSS_COMPILE)ld
+NM 		= $(CROSS_COMPILE)nm
+OBJDUMP 	= $(CROSS_COMPILE)objdump
+RANLIB 		= $(CROSS_COMPILE)ranlib
+SIZE 		= $(CROSS_COMPILE)size
+STRIP 		= $(CROSS_COMPILE)strip
+STRINGS 	= $(CROSS_COMPILE)strings
+
+
+ADDR2LINE 	= $(CROSS_COMPILE)addr2line
+COV 		= $(CROSS_COMPILE)gcov
+CXXFILT 	= $(CROSS_COMPILE)c++filt
+ELFEDIT 	= $(CROSS_COMPILE)elfedit
+OBJCOPY 	= $(CROSS_COMPILE)objcopy
+READELF 	= $(CROSS_COMPILE)readelf
+
+
+CFLAGS_PIC 	= -fPIC
diff --git a/sysinfo/toolchain/gcc.mk b/sysinfo/toolchain/gcc.mk
new file mode 100644
index 0000000..52a2545
--- /dev/null
+++ b/sysinfo/toolchain/gcc.mk
@@ -0,0 +1,43 @@
+ifeq ($(USER_CC)x,x)
+	ifeq ($(CROSS_COMPILE)x,x)
+		CC = $(CROSS_COMPILE)$(NATIVE_CC)
+	else
+		CC = $(CROSS_COMPILE)gcc
+	endif
+else
+	CC	= $(USER_CC)
+endif
+
+ifeq ($(USER_CPP)x,x)
+	CPP	= $(CROSS_COMPILE)cpp
+else
+	CPP	= $(USER_CPP)
+endif
+
+ifeq ($(USER_CXX)x,x)
+	CXX	= $(CROSS_COMPILE)c++
+else
+	CXX	= $(USER_CXX)
+endif
+
+
+AS 		= $(CROSS_COMPILE)as
+AR 		= $(CROSS_COMPILE)ar
+LD 		= $(CROSS_COMPILE)ld
+NM 		= $(CROSS_COMPILE)nm
+OBJDUMP 	= $(CROSS_COMPILE)objdump
+RANLIB 		= $(CROSS_COMPILE)ranlib
+SIZE 		= $(CROSS_COMPILE)size
+STRIP 		= $(CROSS_COMPILE)strip
+STRINGS 	= $(CROSS_COMPILE)strings
+
+
+ADDR2LINE 	= $(CROSS_COMPILE)addr2line
+COV 		= $(CROSS_COMPILE)gcov
+CXXFILT 	= $(CROSS_COMPILE)c++filt
+ELFEDIT 	= $(CROSS_COMPILE)elfedit
+OBJCOPY 	= $(CROSS_COMPILE)objcopy
+READELF 	= $(CROSS_COMPILE)readelf
+
+
+CFLAGS_PIC 	= -fPIC
diff --git a/sysinfo/version.sh b/sysinfo/version.sh
new file mode 100755
index 0000000..fb1e8c3
--- /dev/null
+++ b/sysinfo/version.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+usage()
+{
+cat << EOF >&2
+
+Usage:
+  -h            show this HELP message
+  -s  SRCDIR    set source directory
+  -o  OUTPUT    set output header
+  -p  PREFIX    set macro prefix
+
+EOF
+exit 1
+}
+
+
+# one
+workdir=$(pwd)
+srcdir=
+output=
+prefix=
+
+
+while getopts "hs:o:p:" opt; do
+	case $opt in
+	h)
+  		usage
+  		;;
+	s)
+    		srcdir="$OPTARG"
+    		;;
+	o)
+    		output="$OPTARG"
+    		;;
+	p)
+    		prefix="$OPTARG"
+    		;;
+	\?)
+    		printf "Invalid option: -%s" "$OPTARG" >&2
+    		usage
+    		;;
+	esac
+done
+
+
+# two
+if [ -z "$srcdir" ] || [ -z "$output" ] || [ -z "$prefix" ]; then
+	usage
+fi
+
+cd "$srcdir" || exit 2
+
+gitver=`git rev-parse --verify HEAD` || gitver="unknown"
+macro=`echo "$prefix"_GIT_VERSION | tr '[:lower:]' '[:upper:]'`
+
+cd "$workdir" || exit 2
+printf "#define $macro\t\"$gitver\"\n" > "$output"
+
+# all done
+exit 0