Index: uspace/lib/pcut/include/pcut/asserts.h
===================================================================
--- uspace/lib/pcut/include/pcut/asserts.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/include/pcut/asserts.h	(revision 490e21b9ccf40a2a981b687963bd8eb63ffaaed6)
@@ -39,4 +39,11 @@
 #include <errno.h>
 
+/** @def PCUT_CURRENT_FILENAME
+ * Overwrite contents of __FILE__ when printing assertion errors.
+ */
+#ifndef PCUT_CURRENT_FILENAME
+#define PCUT_CURRENT_FILENAME __FILE__
+#endif
+
 /** @cond devel */
 
@@ -46,8 +53,10 @@
  * (if registered).
  *
+ * @param filename File where the assertion occurred.
+ * @param line Line where the assertion occurred.
  * @param fmt Printf-like format string.
  * @param ... Extra arguments.
  */
-void pcut_failed_assertion_fmt(const char *fmt, ...);
+void pcut_failed_assertion_fmt(const char *filename, int line, const char *fmt, ...);
 
 /** OS-agnostic string comparison.
@@ -70,4 +79,17 @@
 void pcut_str_error(int error, char *buffer, int size);
 
+/** Raise assertion error (internal version).
+ *
+ * We expect to be always called from PCUT_ASSERTION_FAILED() where
+ * the last argument is empty string to conform to strict ISO C99
+ * ("ISO C99 requires rest arguments to be used").
+ *
+ * @param fmt Printf-like format string.
+ * @param ... Extra arguments.
+ */
+#define PCUT_ASSERTION_FAILED_INTERNAL(fmt, ...) \
+	pcut_failed_assertion_fmt(PCUT_CURRENT_FILENAME, __LINE__, fmt, __VA_ARGS__)
+
+
 /** @endcond */
 
@@ -77,9 +99,8 @@
  * abort (tear-down function of the test suite is run when available).
  *
- * @param fmt Printf-like format string.
- * @param ... Extra arguments.
- */
-#define PCUT_ASSERTION_FAILED(fmt, ...) \
-	pcut_failed_assertion_fmt(__FILE__ ":%d: " fmt, __LINE__, ##__VA_ARGS__)
+ * @param ... Printf-like arguments.
+ */
+#define PCUT_ASSERTION_FAILED(...) \
+	PCUT_ASSERTION_FAILED_INTERNAL(__VA_ARGS__, "")
 
 
@@ -115,9 +136,9 @@
  */
 #define PCUT_ASSERT_EQUALS(expected, actual) \
-		do {\
-			if (!((expected) == (actual))) { \
-				PCUT_ASSERTION_FAILED("Expected <"#expected "> but got <" #actual ">"); \
-			} \
-		} while (0)
+	do {\
+		if (!((expected) == (actual))) { \
+			PCUT_ASSERTION_FAILED("Expected <"#expected "> but got <" #actual ">"); \
+		} \
+	} while (0)
 
 /** Asserts that given pointer is NULL.
Index: uspace/lib/pcut/include/pcut/datadef.h
===================================================================
--- uspace/lib/pcut/include/pcut/datadef.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/include/pcut/datadef.h	(revision 490e21b9ccf40a2a981b687963bd8eb63ffaaed6)
@@ -39,4 +39,13 @@
 /** @cond devel */
 
+#if defined(__GNUC__) || defined(__clang__)
+#define PCUT_CC_UNUSED_VARIABLE(name, initializer) \
+	name __attribute__((unused)) = initializer
+#else
+#define PCUT_CC_UNUSED_VARIABLE(name, initializer) \
+	name = initializer
+#endif
+
+
 enum {
 	PCUT_KIND_SKIP,
@@ -54,4 +63,11 @@
 };
 
+enum {
+	PCUT_MAIN_EXTRA_PREINIT_HOOK,
+	PCUT_MAIN_EXTRA_INIT_HOOK,
+	PCUT_MAIN_EXTRA_REPORT_XML,
+	PCUT_MAIN_EXTRA_LAST
+};
+
 /** Generic wrapper for test cases, test suites etc. */
 typedef struct pcut_item pcut_item_t;
@@ -59,4 +75,7 @@
 /** Extra information about a test. */
 typedef struct pcut_extra pcut_extra_t;
+
+/** Extra information for the main() function. */
+typedef struct pcut_main_extra pcut_main_extra_t;
 
 /** Test method type. */
@@ -73,8 +92,19 @@
 	 */
 	int type;
-	union {
-		/** Test-specific time-out in seconds. */
-		int timeout;
-	};
+	/** Test-specific time-out in seconds. */
+	int timeout;
+};
+
+/** @copydoc pcut_main_extra_t */
+struct pcut_main_extra {
+	/** Discriminator for the union.
+	 *
+	 * Use PCUT_MAIN_EXTRA_* to determine which field of the union is used.
+	 */
+	int type;
+	/** Callback once PCUT initializes itself. */
+	void (*init_hook)(void);
+	/** Callback even before command-line arguments are processed. */
+	void (*preinit_hook)(int *, char ***);
 };
 
@@ -89,48 +119,27 @@
 	int id;
 
-	/** Discriminator for the union.
-	 *
-	 * Use PCUT_KIND_* to determine which field of the union is used.
-	 */
+	/** Discriminator for this item. */
 	int kind;
-	union {
-		struct {
-			const char *name;
-			pcut_setup_func_t setup;
-			pcut_setup_func_t teardown;
-		} suite;
-		struct {
-			const char *name;
-			pcut_test_func_t func;
-			pcut_extra_t *extras;
-		} test;
-		/* setup is used for both set-up and tear-down */
-		struct {
-			pcut_setup_func_t func;
-		} setup;
-		struct {
-			pcut_item_t *last;
-		} nested;
-		struct {
-			int dummy;
-		} meta;
-	};
+
+	/** Name of this item. */
+	const char *name;
+
+	/** Test-case function. */
+	pcut_test_func_t test_func;
+
+	/** Set-up function of a suite. */
+	pcut_setup_func_t setup_func;
+	/** Tear-down function of a suite. */
+	pcut_setup_func_t teardown_func;
+
+	/** Extra attributes. */
+	pcut_extra_t *extras;
+
+	/** Extra attributes for main() function. */
+	pcut_main_extra_t *main_extras;
+
+	/** Nested lists. */
+	pcut_item_t *nested;
 };
-
-#ifdef PCUT_DEBUG_BUILD
-#define PCUT_DEBUG(msg, ...) \
-	printf("[PCUT]: Debug: " msg "\n", ##__VA_ARGS__)
-#else
-
-/** Debug printing.
- *
- * By default, this macro does nothing. Define PCUT_DEBUG_BUILD to
- * actually print the messages to the console.
- *
- * @param msg Printf-like formatting message.
- * @param ... Extra arguments for printf.
- */
-#define PCUT_DEBUG(msg, ...) (void)0
-#endif
 
 /** @endcond */
Index: uspace/lib/pcut/include/pcut/helper.h
===================================================================
--- uspace/lib/pcut/include/pcut/helper.h	(revision 490e21b9ccf40a2a981b687963bd8eb63ffaaed6)
+++ uspace/lib/pcut/include/pcut/helper.h	(revision 490e21b9ccf40a2a981b687963bd8eb63ffaaed6)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014 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.
+ */
+
+/** @file
+ * Helper macros.
+ */
+#ifndef PCUT_HELPER_H_GUARD
+#define PCUT_HELPER_H_GUARD
+
+/** @cond devel */
+
+/** Join the two arguments on preprocessor level (inner call). */
+#define PCUT_JOIN_IMPL(a, b) a##b
+
+/** Join the two arguments on preprocessor level. */
+#define PCUT_JOIN(a, b) PCUT_JOIN_IMPL(a, b)
+
+/** Quote the parameter (inner call). */
+#define PCUT_QUOTE_IMPL(x) #x
+
+/** Quote the parameter. */
+#define PCUT_QUOTE(x) PCUT_QUOTE_IMPL(x)
+
+/** Get first argument from macro var-args. */
+#define PCUT_VARG_GET_FIRST(x, ...) x
+
+/** Get all but first arguments from macro var-args. */
+#define PCUT_VARG_SKIP_FIRST(x, ...) __VA_ARGS__
+
+#endif
Index: uspace/lib/pcut/include/pcut/tests.h
===================================================================
--- uspace/lib/pcut/include/pcut/tests.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/include/pcut/tests.h	(revision 490e21b9ccf40a2a981b687963bd8eb63ffaaed6)
@@ -37,4 +37,5 @@
 #define PCUT_TESTS_H_GUARD
 
+#include <pcut/helper.h>
 #include <pcut/datadef.h>
 
@@ -81,10 +82,4 @@
 /** @cond devel */
 
-/** Join the two arguments on preprocessor level (inner call). */
-#define PCUT_JOIN_IMPL(a, b) a##b
-
-/** Join the two arguments on preprocessor level. */
-#define PCUT_JOIN(a, b) PCUT_JOIN_IMPL(a, b)
-
 /** Produce identifier name for an item with given number.
  *
@@ -132,11 +127,11 @@
  */
 #define PCUT_ADD_ITEM(number, itemkind, ...) \
-		static pcut_item_t PCUT_ITEM_NAME(number) = { \
-				.previous = &PCUT_ITEM_NAME_PREV(number), \
-				.next = NULL, \
-				.id = -1, \
-				.kind = itemkind, \
-				__VA_ARGS__ \
-		};
+	static pcut_item_t PCUT_ITEM_NAME(number) = { \
+		&PCUT_ITEM_NAME_PREV(number), \
+		NULL, \
+		-1, \
+		itemkind, \
+		__VA_ARGS__ \
+	}
 
 /** @endcond */
@@ -156,5 +151,5 @@
  */
 #define PCUT_TEST_SET_TIMEOUT(time_out) \
-	{ .type = PCUT_EXTRA_TIMEOUT, .timeout = (time_out) }
+	{ PCUT_EXTRA_TIMEOUT, (time_out) }
 
 /** Skip current test.
@@ -163,5 +158,5 @@
  */
 #define PCUT_TEST_SKIP \
-	{ .type = PCUT_EXTRA_SKIP }
+	{ PCUT_EXTRA_SKIP, 0 }
 
 
@@ -169,5 +164,5 @@
 
 /** Terminate list of extra test options. */
-#define PCUT_TEST_EXTRA_LAST { .type = PCUT_EXTRA_LAST }
+#define PCUT_TEST_EXTRA_LAST { PCUT_EXTRA_LAST, 0 }
 
 /** Define a new test with given name and given item number.
@@ -177,18 +172,19 @@
  * @param ... Extra test properties.
  */
-#define PCUT_TEST_WITH_NUMBER(testname, number, ...) \
-		PCUT_ITEM_COUNTER_INCREMENT \
-		static pcut_extra_t PCUT_ITEM_EXTRAS_NAME(number)[] = { \
-				__VA_ARGS__ \
-		}; \
-		static void PCUT_JOIN(test_, testname)(void); \
-		PCUT_ADD_ITEM(number, PCUT_KIND_TEST, \
-				.test = { \
-					.name = #testname, \
-					.func = PCUT_JOIN(test_, testname), \
-					.extras = PCUT_ITEM_EXTRAS_NAME(number), \
-				} \
-		) \
-		void PCUT_JOIN(test_, testname)(void)
+#define PCUT_TEST_WITH_NUMBER(number, testname, ...) \
+	PCUT_ITEM_COUNTER_INCREMENT \
+	static pcut_extra_t PCUT_ITEM_EXTRAS_NAME(number)[] = { \
+		__VA_ARGS__ \
+	}; \
+	static int PCUT_CC_UNUSED_VARIABLE(PCUT_JOIN(testname, 0_test_name_missing_or_duplicated), 0); \
+	static void PCUT_JOIN(test_, testname)(void); \
+	PCUT_ADD_ITEM(number, PCUT_KIND_TEST, \
+		PCUT_QUOTE(testname), \
+		PCUT_JOIN(test_, testname), \
+		NULL, NULL, \
+		PCUT_ITEM_EXTRAS_NAME(number), \
+		NULL, NULL \
+	); \
+	void PCUT_JOIN(test_, testname)(void)
 
 /** @endcond */
@@ -196,9 +192,11 @@
 /** Define a new test with given name.
  *
- * @param name A valid C identifier name (not quoted).
- * @param ... Extra test properties.
- */
-#define PCUT_TEST(name, ...) \
-	PCUT_TEST_WITH_NUMBER(name, PCUT_ITEM_COUNTER, ##__VA_ARGS__, PCUT_TEST_EXTRA_LAST)
+ * @param ... Test name (C identifier) followed by extra test properties.
+ */
+#define PCUT_TEST(...) \
+	PCUT_TEST_WITH_NUMBER(PCUT_ITEM_COUNTER, \
+		PCUT_VARG_GET_FIRST(__VA_ARGS__, this_arg_is_ignored), \
+		PCUT_VARG_SKIP_FIRST(__VA_ARGS__, PCUT_TEST_EXTRA_LAST) \
+	)
 
 
@@ -221,12 +219,12 @@
  */
 #define PCUT_TEST_SUITE_WITH_NUMBER(suitename, number) \
-		PCUT_ITEM_COUNTER_INCREMENT \
-		PCUT_ADD_ITEM(number, PCUT_KIND_TESTSUITE, \
-				.suite = { \
-					.name = #suitename, \
-					.setup = NULL, \
-					.teardown = NULL \
-				} \
-		)
+	PCUT_ITEM_COUNTER_INCREMENT \
+	PCUT_ADD_ITEM(number, PCUT_KIND_TESTSUITE, \
+		#suitename, \
+		NULL, \
+		NULL, NULL, \
+		NULL, NULL, \
+		NULL \
+	)
 
 /** Define a set-up function for a test suite.
@@ -237,10 +235,12 @@
  */
 #define PCUT_TEST_BEFORE_WITH_NUMBER(number) \
-		PCUT_ITEM_COUNTER_INCREMENT \
-		static void PCUT_ITEM_SETUP_NAME(number)(void); \
-		PCUT_ADD_ITEM(number, PCUT_KIND_SETUP, \
-				.setup.func = PCUT_ITEM_SETUP_NAME(number) \
-		) \
-		void PCUT_ITEM_SETUP_NAME(number)(void)
+	PCUT_ITEM_COUNTER_INCREMENT \
+	static void PCUT_ITEM_SETUP_NAME(number)(void); \
+	PCUT_ADD_ITEM(number, PCUT_KIND_SETUP, \
+		"setup", NULL, \
+		PCUT_ITEM_SETUP_NAME(number), \
+		NULL, NULL, NULL, NULL \
+	); \
+	void PCUT_ITEM_SETUP_NAME(number)(void)
 
 /** Define a tear-down function for a test suite.
@@ -251,10 +251,12 @@
  */
 #define PCUT_TEST_AFTER_WITH_NUMBER(number) \
-		PCUT_ITEM_COUNTER_INCREMENT \
-		static void PCUT_ITEM_SETUP_NAME(number)(void); \
-		PCUT_ADD_ITEM(number, PCUT_KIND_TEARDOWN, \
-				.setup.func = PCUT_ITEM_SETUP_NAME(number) \
-		) \
-		void PCUT_ITEM_SETUP_NAME(number)(void)
+	PCUT_ITEM_COUNTER_INCREMENT \
+	static void PCUT_ITEM_SETUP_NAME(number)(void); \
+	PCUT_ADD_ITEM(number, PCUT_KIND_TEARDOWN, \
+		"teardown", NULL, NULL, \
+		PCUT_ITEM_SETUP_NAME(number), \
+		NULL, NULL, NULL \
+	); \
+	void PCUT_ITEM_SETUP_NAME(number)(void)
 
 /** @endcond */
@@ -328,7 +330,9 @@
 	PCUT_ITEM_COUNTER_INCREMENT \
 	pcut_item_t pcut_exported_##identifier = { \
-		.previous = &PCUT_ITEM_NAME_PREV(number), \
-		.next = NULL, \
-		.kind = PCUT_KIND_SKIP \
+		&PCUT_ITEM_NAME_PREV(number), \
+		NULL, \
+		-1, \
+		PCUT_KIND_SKIP, \
+		"exported_" #identifier, NULL, NULL, NULL, NULL, NULL, NULL \
 	}
 
@@ -344,5 +348,6 @@
 	extern pcut_item_t pcut_exported_##identifier; \
 	PCUT_ADD_ITEM(number, PCUT_KIND_NESTED, \
-		.nested.last = &pcut_exported_##identifier \
+		"import_" #identifier, NULL, NULL, NULL, NULL, NULL, \
+		&pcut_exported_##identifier \
 	)
 
@@ -382,8 +387,9 @@
 	PCUT_ITEM_COUNTER_INCREMENT \
 	static pcut_item_t PCUT_ITEM_NAME(first_number) = { \
-		.previous = NULL, \
-		.next = NULL, \
-		.id = -1, \
-		.kind = PCUT_KIND_SKIP \
+		NULL, \
+		NULL, \
+		-1, \
+		PCUT_KIND_SKIP, \
+		"init", NULL, NULL, NULL, NULL, NULL, NULL \
 	}; \
 	PCUT_TEST_SUITE(Default);
@@ -395,9 +401,18 @@
  * @param number Item number.
  */
-#define PCUT_MAIN_WITH_NUMBER(number) \
-	PCUT_ITEM_COUNTER_INCREMENT \
+#define PCUT_MAIN_WITH_NUMBER(number, ...) \
+	PCUT_ITEM_COUNTER_INCREMENT \
+	static pcut_main_extra_t pcut_main_extras[] = { \
+		__VA_ARGS__ \
+	}; \
 	static pcut_item_t pcut_item_last = { \
-		.previous = &PCUT_ITEM_NAME_PREV(number), \
-		.kind = PCUT_KIND_SKIP \
+		&PCUT_ITEM_NAME_PREV(number), \
+		NULL, \
+		-1, \
+		PCUT_KIND_SKIP, \
+		"main", NULL, NULL, NULL, \
+		NULL, \
+		pcut_main_extras, \
+		NULL \
 	}; \
 	int main(int argc, char *argv[]) { \
@@ -405,4 +420,8 @@
 	}
 
+/** Terminate list of extra options for main. */
+#define PCUT_MAIN_EXTRA_SET_LAST \
+	{ PCUT_MAIN_EXTRA_LAST, NULL, NULL }
+
 /** @endcond */
 
@@ -413,6 +432,46 @@
 /** Insert code to run all the tests. */
 #define PCUT_MAIN() \
-	PCUT_MAIN_WITH_NUMBER(PCUT_ITEM_COUNTER)
-
+	PCUT_MAIN_WITH_NUMBER(PCUT_ITEM_COUNTER, PCUT_MAIN_EXTRA_SET_LAST)
+
+
+/** Set callback for PCUT initialization.
+ *
+ * Use from within PCUT_CUSTOM_MAIN().
+ *
+ * @warning The callback is called for each test and also for the wrapping
+ * invocation.
+ */
+#define PCUT_MAIN_SET_INIT_HOOK(callback) \
+	{ PCUT_MAIN_EXTRA_INIT_HOOK, callback, NULL }
+
+/** Set callback for PCUT pre-initialization.
+ *
+ * Use from within PCUT_CUSTOM_MAIN().
+ * This callback is useful only if you want to manipulate command-line
+ * arguments.
+ * You probably will not need this.
+ *
+ * @warning The callback is called for each test and also for the wrapping
+ * invocation.
+ */
+#define PCUT_MAIN_SET_PREINIT_HOOK(callback) \
+	{ PCUT_MAIN_EXTRA_PREINIT_HOOK, NULL, callback }
+
+
+/** Set XML report as default.
+ *
+ * Use from within PCUT_CUSTOM_MAIN().
+ *
+ */
+#define PCUT_MAIN_SET_XML_REPORT \
+	{ PCUT_MAIN_EXTRA_REPORT_XML, NULL, NULL }
+
+
+/** Insert code to run all tests. */
+#define PCUT_CUSTOM_MAIN(...) \
+	PCUT_MAIN_WITH_NUMBER(PCUT_ITEM_COUNTER, \
+		PCUT_VARG_GET_FIRST(__VA_ARGS__, PCUT_MAIN_EXTRA_SET_LAST), \
+		PCUT_VARG_SKIP_FIRST(__VA_ARGS__, PCUT_MAIN_EXTRA_SET_LAST) \
+ 	)
 
 /**
