Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
+++ uspace/lib/c/Makefile	(revision 99d3123e7ab9ecf412fde9af4e2b084aac7c5dc1)
@@ -79,4 +79,5 @@
 	generic/mem.c \
 	generic/str.c \
+	generic/string.c \
 	generic/str_error.c \
 	generic/strtol.c \
@@ -203,5 +204,6 @@
 	test/stdio.c \
 	test/stdlib.c \
-	test/str.c
+	test/str.c \
+	test/string.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/c/generic/string.c
===================================================================
--- uspace/lib/c/generic/string.c	(revision 99d3123e7ab9ecf412fde9af4e2b084aac7c5dc1)
+++ uspace/lib/c/generic/string.c	(revision 99d3123e7ab9ecf412fde9af4e2b084aac7c5dc1)
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+/* Prevent an error from being generated */
+#undef _HELENOS_SOURCE
+#include <string.h>
+#define _HELENOS_SOURCE
+
+#include <stddef.h>
+#include <str_error.h>
+
+/** Copy string.
+ *
+ * Copy the string pointed to by @a s2 to the array pointed to by @a s1
+ * including the terminating null character. The source and destination
+ * must not overlap.
+ *
+ * @param s1 Destination array
+ * @param s2 Source string
+ * @return @a s1
+ */
+char *strcpy(char *s1, const char *s2)
+{
+	char *dp = s1;
+
+	/* Copy characters */
+	while (*s2 != '\0')
+		*dp++ = *s2++;
+
+	/* Copy the terminating null character */
+	*dp++ = *s2++;
+
+	return s1;
+}
+
+/** Copy not more than @a n characters.
+ *
+ * Copy not more than @a n characters from  @a s2 to @a s1. Characters
+ * following a null character are not copied. If The string @a s2 is
+ * shorter than @a n characters, null characters are appended to the
+ * copy in @a s1, until @a n characters in all have been written.
+ *
+ * (I.e. @a s1 is padded with null characters up to size @a n).
+ * The source and destination must not overlap.
+ *
+ * @param s1 Destination array
+ * @param s2 Source string
+ * @param n Number of characters to copy
+ * @return @a s1
+ */
+char *strncpy(char *s1, const char *s2, size_t n)
+{
+	char *dp = s1;
+	size_t i;
+
+	for (i = 0; i < n; i++) {
+		*dp++ = *s2;
+		if (*s2 != '\0')
+			++s2;
+	}
+
+	return s1;
+}
+
+/** Append string.
+ *
+ * Append a copy of string in @a s2 to the string pointed to by @a s1
+ * (including the terminating null character). @a s1 and @a s2 must not
+ * overlap.
+ *
+ * @param s1 Destination buffer holding a string to be appended to
+ * @param s2 String to be appended
+ * @return @a s1
+ */
+char *strcat(char *s1, const char *s2)
+{
+	char *dp = s1;
+
+	/* Find end of first string */
+	while (*dp != '\0')
+		++dp;
+
+	/* Copy second string */
+	while (*s2 != '\0')
+		*dp++ = *s2++;
+
+	/* Copy null character */
+	*dp = '\0';
+
+	return s1;
+}
+
+/** Append not more than @a n characters.
+ *
+ * Append a copy of max. @a n characters from string in @a s2 to the string
+ * pointed to by @a s1. The resulting string is always null-terminated.
+ *
+ * @param s1 Destination buffer holding a string to be appended to
+ * @param s2 String to be appended
+ * @param n Maximum number of characters to copy
+ * @return @a s1
+ */
+char *strncat(char *s1, const char *s2, size_t n)
+{
+	char *dp = s1;
+
+	/* Find end of first string */
+	while (*dp != '\0')
+		++dp;
+
+	/* Copy second string */
+	while (*s2 != '\0' && n > 0) {
+		*dp++ = *s2++;
+		--n;
+	}
+
+	/* Copy null character */
+	*dp = '\0';
+
+	return s1;
+}
+
+/** Compare two strings.
+ *
+ * @param s1 First string
+ * @param s2 Second string
+ * @return Greater than, equal to, less than zero if @a s1 > @a s2,
+ *         @a s1 == @a s2, @a s1 < @a s2, resp.
+ */
+int strcmp(const char *s1, const char *s2)
+{
+	while (*s1 == *s2 && *s1 != '\0') {
+		++s1;
+		++s2;
+	}
+
+	return *s1 - *s2;
+}
+
+/** Compare two strings based on LC_COLLATE of current locale.
+ *
+ * @param s1 First string
+ * @param s2 Second string
+ * @return Greater than, equal to, less than zero if @a s1 > @a s2,
+ *         @a s1 == @a s2, @a s1 < @a s2, resp.
+ */
+int strcoll(const char *s1, const char *s2)
+{
+	/* Note: we don't support locale other than "C" */
+	return strcmp(s1, s2);
+}
+
+/** Compare not more than @a n characters.
+ *
+ * @param s1 First string
+ * @param s2 Second string
+ * @param n Maximum number of characters to compare
+ * @return Greater than, equal to, less than zero if @a s1 > @a s2,
+ *         @a s1 == @a s2, @a s1 < @a s2, resp. (within the first @a n chars.)
+ */
+int strncmp(const char *s1, const char *s2, size_t n)
+{
+	while (*s1 == *s2 && *s1 != '\0' && n > 0) {
+		++s1;
+		++s2;
+		--n;
+	}
+
+	if (n > 0)
+		return *s1 - *s2;
+
+	return 0;
+}
+
+/** Transform string for collation.
+ *
+ * Transform string in @a s2 to the buffer @a s1, writing no more than
+ * @a n characters (including the terminating null character). The transformed
+ * string is such that using strcmp on two transformed strings should be
+ * equivalent to using strcoll on the original strings.
+ *
+ * @param s1 Destination buffer
+ * @param s2 Source string
+ * @param n Max. number of characters to write (including terminating null)
+ * @return Length of the transformed string not including the null terminator.
+ *         If the value returned is @a n or more, the contents of the buffer
+ *         pointed to by @a s1 are undefined.
+ */
+int strxfrm(char *s1, const char *s2, size_t n)
+{
+	size_t i;
+	size_t len;
+
+	len = strlen(s2);
+
+	for (i = 0; i < n; i++) {
+		*s1++ = *s2;
+		if (*s2 == '\0')
+			break;
+		++s2;
+	}
+
+	return len;
+}
+
+/** Find the first occurrence of a character in a string.
+ *
+ * The character @a c is converted to char. The null character is
+ * considered part of the string.
+ *
+ * @param s String
+ * @param c Character
+ * @return Pointer to the located character or @c NULL if the character
+ *         does not occur in the string.
+ */
+char *strchr(const char *s, int c)
+{
+	do {
+		if (*s == (char) c)
+			return (char *) s;
+	} while (*s++ != '\0');
+
+	return NULL;
+}
+
+/** Compute the size of max. initial segment consisting of a complementary
+ * set of characters.
+ *
+ * Compute the size of the max. initial segment of @a s1 consisting only
+ * of characters *not* from @a s2.
+ *
+ * @param s1 String to search
+ * @param s2 String containing set of characters
+ * @return Size of initial segment of @a s1 consisting only of characters
+ *         not from @a s2.
+ */
+size_t strcspn(const char *s1, const char *s2)
+{
+	char *p;
+	size_t n;
+
+	n = 0;
+	while (*s1 != '\0') {
+		/* Look for current character in s2 */
+		p = strchr(s2, *s1);
+
+		/* If found, return current character count. */
+		if (p != NULL)
+			break;
+
+		++s1;
+		++n;
+	}
+
+	return n;
+}
+
+/** Search string for occurrence of any of a set of characters.
+ *
+ * @param s1 String to search
+ * @param s2 String containing a set of characters
+ *
+ * @return Pointer to first character found or @c NULL if not found
+ */
+char *strpbrk(const char *s1, const char *s2)
+{
+	char *p;
+
+	while (*s1 != '\0') {
+		/* Look for current character in s2 */
+		p = strchr(s2, *s1);
+
+		/* If found, return pointer to current character. */
+		if (p != NULL)
+			return (char *) s1;
+
+		++s1;
+	}
+
+	return NULL;
+}
+
+/** Find the last occurrence of a character in a string.
+ *
+ * The character @a c is converted to char. The null character is
+ * considered part of the string.
+ *
+ * @param s String
+ * @param c Character
+ * @return Pointer to the located character or @c NULL if the character
+ *         does not occur in the string.
+ */
+char *strrchr(const char *s, int c)
+{
+	size_t i = strlen(s);
+
+	while (i > 0) {
+		if (s[i] == (char) c)
+			return (char *)s + i;
+		--i;
+	}
+
+	return NULL;
+}
+
+/** Compute the size of max. initial segment consisting of a set of characters.
+ *
+ * Compute tha size of the max. initial segment of @a s1 consisting only
+ * of characters from @a s2.
+ *
+ * @param s1 String to search
+ * @param s2 String containing set of characters
+ * @return Size of initial segment of @a s1 consisting only of characters
+ *         from @a s2.
+ */
+size_t strspn(const char *s1, const char *s2)
+{
+	char *p;
+	size_t n;
+
+	n = 0;
+	while (*s1 != '\0') {
+		/* Look for current character in s2 */
+		p = strchr(s2, *s1);
+
+		/* If not found, return current character count. */
+		if (p == NULL)
+			break;
+
+		++s1;
+		++n;
+	}
+
+	return n;
+}
+
+/** Find occurrence of substring in a string.
+ *
+ * Find the first occurrence in @a s1 of the characters in @a s2, excluding
+ * the terminating null character. If s2 is an empty string, returns @a s1.
+ *
+ * @param s1 String to search
+ * @param s2 Sequence of characters to find
+ *
+ * @return Pointer inside @a s1 or @c NULL if not found.
+ */
+char *strstr(const char *s1, const char *s2)
+{
+	size_t len;
+
+	/*
+	 * Naive search algorithm.
+	 *
+	 * Two-Way String-Matching might be a plausible alternative
+	 * for larger haystack+needle combinations.
+	 */
+
+	len = strlen(s2);
+	while (*s1 != '\0') {
+		if (strncmp(s1, s2, len) == 0)
+			return (char *) s1;
+		++s1;
+	}
+
+	return NULL;
+}
+
+/** Tokenize a string (reentrant).
+ *
+ * The contents of @a s1 are modified (the separators get overwritten by null
+ * characters). The separators can be different each iteration, their identity\
+ * is, however, lost.
+ *
+ * @param s1 String buffer to get the first token, @c NULL to get the next
+ *           token
+ * @param s2 String containing current separators
+ * @return Pointer to the next token
+ */
+char *__strtok_r(char *s1, const char *s2, char **saveptr)
+{
+	char *s;
+	char *tbegin;
+	char *tend;
+
+	if (s1 != NULL) {
+		/* Starting tokenization of a new string */
+		s = s1;
+	} else {
+		/* Use saved position of next token */
+		s = *saveptr;
+
+		/* Check if we ran out of tokens */
+		if (s == NULL)
+			return NULL;
+	}
+
+	/* Find position of first character that is not a separator */
+	tbegin = s;
+	while (*tbegin != '\0' && strchr(s2, *tbegin) != NULL)
+		++tbegin;
+
+	/* If no such character is found, there are no tokens */
+	if (*tbegin == '\0')
+		return NULL;
+
+	/* Find first character that is a separator */
+	tend = strpbrk(tbegin, s2);
+	if (tend != NULL) {
+		/* Overwrite the separator, next token starts just after */
+		*tend = '\0';
+		*saveptr = tend + 1;
+	} else {
+		/* No more tokens will be returned next time */
+		*saveptr = NULL;
+	}
+
+	return tbegin;
+}
+
+/** Saved position of next token for function strtok */
+static char *strtok_saveptr = NULL;
+
+/** Tokenize a string.
+ *
+ * This function has internal state and thus is not reentrant.
+ * ISO C says the implementation should behave as if no (standard) library
+ * call calls strtok. The contents of @a s1 are modified (the separators
+ * get overwritten by null characters). The separators can be different
+ * each iteration, their identity is, however, lost.
+ *
+ * Never use this function since it's not reentrant.
+ *
+ * @param s1 String buffer to get the first token, @c NULL to get the next
+ *           token
+ * @param s2 String containing current separators
+ * @return Pointer to the next token
+ */
+char *strtok(char *s1, const char *s2)
+{
+	return __strtok_r(s1, s2, &strtok_saveptr);
+}
+
+/** Map error number to a string.
+ *
+ * The string returned by the function may be overwritten by a subsequent
+ * call to strerror (ISO C). In our implementation the function is, in fact,
+ * reentrant, as the string returned is static and never modified.
+ *
+ * @param errnum Error number
+ * @return Pointer to error message
+ */
+char *strerror(int errnum)
+{
+	return (char *) str_error(errnum);
+}
+
+/** Return number of characters in string.
+ *
+ * @param s String
+ * @return Number of characters preceding the null character.
+ */
+size_t strlen(const char *s)
+{
+	size_t n;
+
+	n = 0;
+	while (*s != '\0') {
+		++s;
+		++n;
+	}
+
+	return n;
+}
+
+/** @}
+ */
Index: uspace/lib/c/include/string.h
===================================================================
--- uspace/lib/c/include/string.h	(revision 99d3123e7ab9ecf412fde9af4e2b084aac7c5dc1)
+++ uspace/lib/c/include/string.h	(revision 99d3123e7ab9ecf412fde9af4e2b084aac7c5dc1)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_STRING_H_
+#define LIBC_STRING_H_
+
+#ifdef _HELENOS_SOURCE
+#error Please use str.h and mem.h instead
+#endif
+
+#include <_bits/size_t.h>
+#include <_bits/NULL.h>
+#include <mem.h>
+
+extern char *strcpy(char *, const char *);
+extern char *strncpy(char *, const char *, size_t);
+extern char *strcat(char *, const char *);
+extern char *strncat(char *, const char *, size_t);
+extern int strcmp(const char *, const char *);
+extern int strcoll(const char *, const char *);
+extern int strncmp(const char *, const char *, size_t);
+extern int strxfrm(char *, const char *, size_t);
+extern char *strchr(const char *, int);
+extern size_t strcspn(const char *, const char *);
+extern char *strpbrk(const char *, const char *);
+extern char *strrchr(const char *, int);
+extern size_t strspn(const char *, const char *);
+extern char *strstr(const char *, const char *);
+extern char *strtok(char *, const char *);
+extern char *__strtok_r(char *, const char *, char **);
+extern char *strerror(int);
+extern size_t strlen(const char *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/test/main.c
===================================================================
--- uspace/lib/c/test/main.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
+++ uspace/lib/c/test/main.c	(revision 99d3123e7ab9ecf412fde9af4e2b084aac7c5dc1)
@@ -42,4 +42,5 @@
 PCUT_IMPORT(stdlib);
 PCUT_IMPORT(str);
+PCUT_IMPORT(string);
 PCUT_IMPORT(table);
 
Index: uspace/lib/c/test/string.c
===================================================================
--- uspace/lib/c/test/string.c	(revision 99d3123e7ab9ecf412fde9af4e2b084aac7c5dc1)
+++ uspace/lib/c/test/string.c	(revision 99d3123e7ab9ecf412fde9af4e2b084aac7c5dc1)
@@ -0,0 +1,719 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Prevent an error from being generated */
+#undef _HELENOS_SOURCE
+#include <string.h>
+#define _HELENOS_SOURCE
+#include <pcut/pcut.h>
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(string);
+
+/** strcpy function */
+PCUT_TEST(strcpy)
+{
+	const char *s = "hello";
+	char buf[7];
+	size_t i;
+	char *p;
+
+	for (i = 0; i < 7; i++)
+		buf[i] = 'X';
+
+	p = strcpy(buf, s);
+
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(buf[0] == 'h');
+	PCUT_ASSERT_TRUE(buf[1] == 'e');
+	PCUT_ASSERT_TRUE(buf[2] == 'l');
+	PCUT_ASSERT_TRUE(buf[3] == 'l');
+	PCUT_ASSERT_TRUE(buf[4] == 'o');
+	PCUT_ASSERT_TRUE(buf[5] == '\0');
+	PCUT_ASSERT_TRUE(buf[6] == 'X');
+}
+
+/** strncpy function with n == 0 */
+PCUT_TEST(strncpy_zero)
+{
+	const char *s = "hello";
+	char buf[1];
+	char *p;
+
+	buf[0] = 'X';
+
+	p = strncpy(buf, s, 0);
+
+	/* No characters are copied */
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(buf[0] == 'X');
+}
+
+/** strncpy function with string longer than n argument */
+PCUT_TEST(strncpy_long)
+{
+	const char *s = "hello";
+	char buf[5];
+	size_t i;
+	char *p;
+
+	for (i = 0; i < 5; i++)
+		buf[i] = 'X';
+
+	p = strncpy(buf, s, 4);
+
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(buf[0] == 'h');
+	PCUT_ASSERT_TRUE(buf[1] == 'e');
+	PCUT_ASSERT_TRUE(buf[2] == 'l');
+	PCUT_ASSERT_TRUE(buf[3] == 'l');
+	PCUT_ASSERT_TRUE(buf[4] == 'X');
+}
+
+/** strncpy function with string containing exactly n characters */
+PCUT_TEST(strncpy_just)
+{
+	const char *s = "hello";
+	char buf[6];
+	size_t i;
+	char *p;
+
+	for (i = 0; i < 6; i++)
+		buf[i] = 'X';
+
+	p = strncpy(buf, s, 5);
+
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(buf[0] == 'h');
+	PCUT_ASSERT_TRUE(buf[1] == 'e');
+	PCUT_ASSERT_TRUE(buf[2] == 'l');
+	PCUT_ASSERT_TRUE(buf[3] == 'l');
+	PCUT_ASSERT_TRUE(buf[4] == 'o');
+	PCUT_ASSERT_TRUE(buf[5] == 'X');
+}
+
+/** strncpy function with string containing exactly n - 1 characters */
+PCUT_TEST(strncpy_just_over)
+{
+	const char *s = "hello";
+	char buf[7];
+	size_t i;
+	char *p;
+
+	for (i = 0; i < 7; i++)
+		buf[i] = 'X';
+
+	p = strncpy(buf, s, 6);
+
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(buf[0] == 'h');
+	PCUT_ASSERT_TRUE(buf[1] == 'e');
+	PCUT_ASSERT_TRUE(buf[2] == 'l');
+	PCUT_ASSERT_TRUE(buf[3] == 'l');
+	PCUT_ASSERT_TRUE(buf[4] == 'o');
+	PCUT_ASSERT_TRUE(buf[5] == '\0');
+	PCUT_ASSERT_TRUE(buf[6] == 'X');
+}
+
+/** strncpy function with string containing less than n - 1 characters */
+PCUT_TEST(strncpy_over)
+{
+	const char *s = "hello";
+	char buf[8];
+	size_t i;
+	char *p;
+
+	for (i = 0; i < 8; i++)
+		buf[i] = 'X';
+
+	p = strncpy(buf, s, 7);
+
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(buf[0] == 'h');
+	PCUT_ASSERT_TRUE(buf[1] == 'e');
+	PCUT_ASSERT_TRUE(buf[2] == 'l');
+	PCUT_ASSERT_TRUE(buf[3] == 'l');
+	PCUT_ASSERT_TRUE(buf[4] == 'o');
+	PCUT_ASSERT_TRUE(buf[5] == '\0');
+	PCUT_ASSERT_TRUE(buf[6] == '\0');
+	PCUT_ASSERT_TRUE(buf[7] == 'X');
+}
+
+/** strcat function */
+PCUT_TEST(strcat)
+{
+	char buf[7];
+	const char *s = "cde";
+	size_t i;
+	char *p;
+
+	buf[0] = 'a';
+	buf[1] = 'b';
+	buf[2] = '\0';
+
+	for (i = 3; i < 7; i++)
+		buf[i] = 'X';
+
+	p = strcat(buf, s);
+
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(buf[0] == 'a');
+	PCUT_ASSERT_TRUE(buf[1] == 'b');
+	PCUT_ASSERT_TRUE(buf[2] == 'c');
+	PCUT_ASSERT_TRUE(buf[3] == 'd');
+	PCUT_ASSERT_TRUE(buf[4] == 'e');
+	PCUT_ASSERT_TRUE(buf[5] == '\0');
+	PCUT_ASSERT_TRUE(buf[6] == 'X');
+}
+
+/** strncat function with n == 0 */
+PCUT_TEST(strncat_zero)
+{
+	const char *s = "cde";
+	char buf[4];
+	char *p;
+
+	buf[0] = 'a';
+	buf[1] = 'b';
+	buf[2] = '\0';
+	buf[3] = 'X';
+
+	p = strncat(buf, s, 0);
+
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(buf[0] == 'a');
+	PCUT_ASSERT_TRUE(buf[1] == 'b');
+	PCUT_ASSERT_TRUE(buf[2] == '\0');
+	PCUT_ASSERT_TRUE(buf[3] == 'X');
+}
+
+/** strncat function with string longer than n argument */
+PCUT_TEST(strncat_long)
+{
+	const char *s = "cde";
+	char buf[6];
+	size_t i;
+	char *p;
+
+	buf[0] = 'a';
+	buf[1] = 'b';
+	buf[2] = '\0';
+
+	for (i = 3; i < 6; i++)
+		buf[i] = 'X';
+
+	p = strncat(buf, s, 2);
+
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(buf[0] == 'a');
+	PCUT_ASSERT_TRUE(buf[1] == 'b');
+	PCUT_ASSERT_TRUE(buf[2] == 'c');
+	PCUT_ASSERT_TRUE(buf[3] == 'd');
+	PCUT_ASSERT_TRUE(buf[4] == '\0');
+	PCUT_ASSERT_TRUE(buf[5] == 'X');
+}
+
+/** strncat function with string containing exactly n characters */
+PCUT_TEST(strncat_just)
+{
+	const char *s = "cde";
+	char buf[7];
+	size_t i;
+	char *p;
+
+	buf[0] = 'a';
+	buf[1] = 'b';
+	buf[2] = '\0';
+
+	for (i = 3; i < 7; i++)
+		buf[i] = 'X';
+
+	p = strncat(buf, s, 3);
+
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(buf[0] == 'a');
+	PCUT_ASSERT_TRUE(buf[1] == 'b');
+	PCUT_ASSERT_TRUE(buf[2] == 'c');
+	PCUT_ASSERT_TRUE(buf[3] == 'd');
+	PCUT_ASSERT_TRUE(buf[4] == 'e');
+	PCUT_ASSERT_TRUE(buf[5] == '\0');
+	PCUT_ASSERT_TRUE(buf[6] == 'X');
+}
+
+/** strncat function with string containing exactly n - 1 characters */
+PCUT_TEST(strncat_just_over)
+{
+	const char *s = "cde";
+	char buf[7];
+	size_t i;
+	char *p;
+
+	buf[0] = 'a';
+	buf[1] = 'b';
+	buf[2] = '\0';
+
+	for (i = 3; i < 7; i++)
+		buf[i] = 'X';
+
+	p = strncat(buf, s, 4);
+
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(buf[0] == 'a');
+	PCUT_ASSERT_TRUE(buf[1] == 'b');
+	PCUT_ASSERT_TRUE(buf[2] == 'c');
+	PCUT_ASSERT_TRUE(buf[3] == 'd');
+	PCUT_ASSERT_TRUE(buf[4] == 'e');
+	PCUT_ASSERT_TRUE(buf[5] == '\0');
+	PCUT_ASSERT_TRUE(buf[6] == 'X');
+}
+
+/** strncat function with string containing less than n - 1 characters */
+PCUT_TEST(strncat_over)
+{
+	const char *s = "cde";
+	char buf[7];
+	size_t i;
+	char *p;
+
+	buf[0] = 'a';
+	buf[1] = 'b';
+	buf[2] = '\0';
+
+	for (i = 3; i < 7; i++)
+		buf[i] = 'X';
+
+	p = strncat(buf, s, 5);
+
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(buf[0] == 'a');
+	PCUT_ASSERT_TRUE(buf[1] == 'b');
+	PCUT_ASSERT_TRUE(buf[2] == 'c');
+	PCUT_ASSERT_TRUE(buf[3] == 'd');
+	PCUT_ASSERT_TRUE(buf[4] == 'e');
+	PCUT_ASSERT_TRUE(buf[5] == '\0');
+	PCUT_ASSERT_TRUE(buf[6] == 'X');
+}
+
+/** strcmp function with different characters after terminating null */
+PCUT_TEST(strcmp_same)
+{
+	PCUT_ASSERT_TRUE(strcmp("apples\0#", "apples\0$") == 0);
+}
+
+/** strcmp function with first string less than second */
+PCUT_TEST(strcmp_less_than)
+{
+	PCUT_ASSERT_TRUE(strcmp("apples", "oranges") < 0);
+}
+
+/** strcmp function with first string greater than second */
+PCUT_TEST(strcmp_greater_than)
+{
+	PCUT_ASSERT_TRUE(strcmp("oranges", "apples") > 0);
+}
+
+/* strcmp function with first string a prefix of second string */
+PCUT_TEST(strcmp_prefix)
+{
+	PCUT_ASSERT_TRUE(strcmp("apple", "apples") < 0);
+}
+
+/** strcoll function */
+PCUT_TEST(strcoll)
+{
+	/* Same string with different characters after terminating null */
+	PCUT_ASSERT_TRUE(strcoll("apples\0#", "apples\0$") == 0);
+
+	/* First string less than second */
+	PCUT_ASSERT_TRUE(strcoll("apples", "oranges") < 0);
+
+	/* First string greater than second */
+	PCUT_ASSERT_TRUE(strcoll("oranges", "apples") > 0);
+
+	/* First string is prefix of second */
+	PCUT_ASSERT_TRUE(strcoll("apple", "apples") < 0);
+}
+
+/** strncmp function with n == 0 */
+PCUT_TEST(strncmp_zero)
+{
+	PCUT_ASSERT_TRUE(strncmp("apple", "orange", 0) == 0);
+}
+
+/** strncmp function with strings differing after n characters */
+PCUT_TEST(strncmp_long)
+{
+	PCUT_ASSERT_TRUE(strncmp("apple", "apricot", 2) == 0);
+}
+
+/** strncmp function with strings differing in (n-1)th character */
+PCUT_TEST(strncmp_just)
+{
+	PCUT_ASSERT_TRUE(strncmp("apple", "apricot", 3) < 0);
+}
+
+/** strncmp function with strings differing before (n-1)th character */
+PCUT_TEST(strncmp_over)
+{
+	PCUT_ASSERT_TRUE(strncmp("dart", "tart", 3) < 0);
+}
+
+/** strxfrm function with null destination to determine size needed */
+PCUT_TEST(strxfrm_null)
+{
+	size_t n;
+
+	n = strxfrm(NULL, "hello", 0);
+	PCUT_ASSERT_INT_EQUALS(5, n);
+}
+
+/** strxfrm function with string longer than n argument */
+PCUT_TEST(strxfrm_long)
+{
+	const char *s = "hello";
+	char buf[5];
+	size_t i;
+	size_t n;
+
+	for (i = 0; i < 5; i++)
+		buf[i] = 'X';
+
+	n = strxfrm(buf, s, 4);
+
+	PCUT_ASSERT_INT_EQUALS(5, n);
+	PCUT_ASSERT_TRUE(buf[0] == 'h');
+	PCUT_ASSERT_TRUE(buf[1] == 'e');
+	PCUT_ASSERT_TRUE(buf[2] == 'l');
+	PCUT_ASSERT_TRUE(buf[3] == 'l');
+	PCUT_ASSERT_TRUE(buf[4] == 'X');
+}
+
+/** strxfrm function with string containing exactly n characters */
+PCUT_TEST(strxfrm_just)
+{
+	const char *s = "hello";
+	char buf[6];
+	size_t i;
+	size_t n;
+
+	for (i = 0; i < 6; i++)
+		buf[i] = 'X';
+
+	n = strxfrm(buf, s, 5);
+
+	PCUT_ASSERT_INT_EQUALS(5, n);
+	PCUT_ASSERT_TRUE(buf[0] == 'h');
+	PCUT_ASSERT_TRUE(buf[1] == 'e');
+	PCUT_ASSERT_TRUE(buf[2] == 'l');
+	PCUT_ASSERT_TRUE(buf[3] == 'l');
+	PCUT_ASSERT_TRUE(buf[4] == 'o');
+	PCUT_ASSERT_TRUE(buf[5] == 'X');
+}
+
+/** strxfrm function with string containing exactly n - 1 characters */
+PCUT_TEST(strxfrm_just_over)
+{
+	const char *s = "hello";
+	char buf[7];
+	size_t i;
+	size_t n;
+
+	for (i = 0; i < 7; i++)
+		buf[i] = 'X';
+
+	n = strxfrm(buf, s, 6);
+
+	PCUT_ASSERT_INT_EQUALS(5, n);
+	PCUT_ASSERT_TRUE(buf[0] == 'h');
+	PCUT_ASSERT_TRUE(buf[1] == 'e');
+	PCUT_ASSERT_TRUE(buf[2] == 'l');
+	PCUT_ASSERT_TRUE(buf[3] == 'l');
+	PCUT_ASSERT_TRUE(buf[4] == 'o');
+	PCUT_ASSERT_TRUE(buf[5] == '\0');
+	PCUT_ASSERT_TRUE(buf[6] == 'X');
+}
+
+/** strxfrm function with string containing less than n - 1 characters */
+PCUT_TEST(strxfrm_over)
+{
+	const char *s = "hello";
+	char buf[8];
+	size_t i;
+	size_t n;
+
+	for (i = 0; i < 8; i++)
+		buf[i] = 'X';
+
+	n = strxfrm(buf, s, 7);
+
+	PCUT_ASSERT_INT_EQUALS(5, n);
+	PCUT_ASSERT_TRUE(buf[0] == 'h');
+	PCUT_ASSERT_TRUE(buf[1] == 'e');
+	PCUT_ASSERT_TRUE(buf[2] == 'l');
+	PCUT_ASSERT_TRUE(buf[3] == 'l');
+	PCUT_ASSERT_TRUE(buf[4] == 'o');
+	PCUT_ASSERT_TRUE(buf[5] == '\0');
+	PCUT_ASSERT_TRUE(buf[6] == 'X');
+	PCUT_ASSERT_TRUE(buf[7] == 'X');
+}
+
+/** strchr function searching for null character */
+PCUT_TEST(strchr_nullchar)
+{
+	const char *s = "abcabc";
+	char *p;
+
+	p = strchr(s, '\0');
+	PCUT_ASSERT_TRUE((const char *)p == &s[6]);
+}
+
+/** strchr function with character occurring in string */
+PCUT_TEST(strchr_found)
+{
+	const char *s = "abcabc";
+	char *p;
+
+	p = strchr(s, 'b');
+	PCUT_ASSERT_TRUE((const char *)p == &s[1]);
+}
+
+/** strchr function with character not occurring in string */
+PCUT_TEST(strchr_not_found)
+{
+	const char *s = "abcabc";
+	char *p;
+
+	p = strchr(s, 'd');
+	PCUT_ASSERT_TRUE(p == NULL);
+}
+
+/** strcspn function with empty search string */
+PCUT_TEST(strcspn_empty_str)
+{
+	size_t n;
+
+	n = strcspn("", "abc");
+	PCUT_ASSERT_INT_EQUALS(0, n);
+}
+
+/** strcspn function with empty character set */
+PCUT_TEST(strcspn_empty_set)
+{
+	size_t n;
+
+	n = strcspn("abc", "");
+	PCUT_ASSERT_INT_EQUALS(3, n);
+}
+
+/** strcspn function with regular arguments */
+PCUT_TEST(strcspn_regular)
+{
+	size_t n;
+
+	n = strcspn("baBAba", "AB");
+	PCUT_ASSERT_INT_EQUALS(2, n);
+}
+
+/** strpbrk function with empty search string */
+PCUT_TEST(strpbrk_empty_string)
+{
+	char *p;
+
+	p = strpbrk("", "abc");
+	PCUT_ASSERT_NULL(p);
+}
+
+/** strpbrk function with empty character set */
+PCUT_TEST(strpbrk_empty_set)
+{
+	char *p;
+
+	p = strpbrk("abc", "");
+	PCUT_ASSERT_NULL(p);
+}
+
+/** strpbrk function with regular parameters */
+PCUT_TEST(strpbrk_regular)
+{
+	const char *s = "baBAba";
+	char *p;
+
+	p = strpbrk(s, "ab");
+	PCUT_ASSERT_TRUE((const char *)p == s);
+}
+
+/** strrchr function searching for null character */
+PCUT_TEST(strrchr_nullchar)
+{
+	const char *s = "abcabc";
+	char *p;
+
+	p = strrchr(s, '\0');
+	PCUT_ASSERT_TRUE((const char *)p == &s[6]);
+}
+
+/** strrchr function with character occurring in string */
+PCUT_TEST(strrchr_found)
+{
+	const char *s = "abcabc";
+	char *p;
+
+	p = strrchr(s, 'b');
+	PCUT_ASSERT_TRUE((const char *)p == &s[4]);
+}
+
+/** strrchr function with character not occurring in string */
+PCUT_TEST(strrchr_not_found)
+{
+	const char *s = "abcabc";
+	char *p;
+
+	p = strrchr(s, 'd');
+	PCUT_ASSERT_TRUE(p == NULL);
+}
+
+/** strspn function with empty search string */
+PCUT_TEST(strspn_empty_str)
+{
+	size_t n;
+
+	n = strspn("", "abc");
+	PCUT_ASSERT_INT_EQUALS(0, n);
+}
+
+/** strspn function with empty character set */
+PCUT_TEST(strspn_empty_set)
+{
+	size_t n;
+
+	n = strspn("abc", "");
+	PCUT_ASSERT_INT_EQUALS(0, n);
+}
+
+/** strspn function with regular arguments */
+PCUT_TEST(strspn_regular)
+{
+	size_t n;
+
+	n = strspn("baBAba", "ab");
+	PCUT_ASSERT_INT_EQUALS(2, n);
+}
+
+/** strstr function looking for empty substring */
+PCUT_TEST(strstr_empty)
+{
+	const char *str = "abcabcabcdabc";
+	char *p;
+
+	p = strstr(str, "");
+	PCUT_ASSERT_TRUE((const char *) p == str);
+}
+
+/** strstr function looking for substring with success */
+PCUT_TEST(strstr_found)
+{
+	const char *str = "abcabcabcdabc";
+	char *p;
+
+	p = strstr(str, "abcd");
+	PCUT_ASSERT_TRUE((const char *) p == &str[6]);
+}
+
+/** strstr function looking for substring with failure */
+PCUT_TEST(strstr_notfound)
+{
+	const char *str = "abcabcabcdabc";
+	char *p;
+
+	p = strstr(str, "abcde");
+	PCUT_ASSERT_NULL(p);
+}
+
+/** strtok function */
+PCUT_TEST(strtok)
+{
+	char str[] = ":a::b;;;$c";
+	char *t;
+
+	t = strtok(str, ":");
+	PCUT_ASSERT_TRUE(t == &str[1]);
+	PCUT_ASSERT_INT_EQUALS(0, strcmp(t, "a"));
+
+	t = strtok(NULL, ";");
+	PCUT_ASSERT_TRUE(t == &str[3]);
+	PCUT_ASSERT_INT_EQUALS(0, strcmp(t, ":b"));
+
+	t = strtok(NULL, "$;");
+	PCUT_ASSERT_TRUE(t == &str[9]);
+	PCUT_ASSERT_INT_EQUALS(0, strcmp(t, "c"));
+
+	t = strtok(NULL, "$");
+	PCUT_ASSERT_NULL(t);
+}
+
+/** strerror function with zero argument */
+PCUT_TEST(strerror_zero)
+{
+	char *p;
+
+	p = strerror(0);
+	PCUT_ASSERT_NOT_NULL(p);
+}
+
+/** strerror function with errno value argument */
+PCUT_TEST(strerror_errno)
+{
+	char *p;
+
+	p = strerror(EINVAL);
+	PCUT_ASSERT_NOT_NULL(p);
+}
+
+/** strerror function with negative argument */
+PCUT_TEST(strerror_negative)
+{
+	char *p;
+
+	p = strerror(-1);
+	PCUT_ASSERT_NOT_NULL(p);
+}
+
+/** strlen function with empty string */
+PCUT_TEST(strlen_empty)
+{
+	PCUT_ASSERT_INT_EQUALS(0, strlen(""));
+}
+
+/** strlen function with non-empty string */
+PCUT_TEST(strlen_nonempty)
+{
+	PCUT_ASSERT_INT_EQUALS(3, strlen("abc"));
+}
+
+PCUT_EXPORT(string);
Index: uspace/lib/posix/include/posix/string.h
===================================================================
--- uspace/lib/posix/include/posix/string.h	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
+++ uspace/lib/posix/include/posix/string.h	(revision 99d3123e7ab9ecf412fde9af4e2b084aac7c5dc1)
@@ -48,44 +48,24 @@
 
 #include "libc/mem.h"
+#undef _HELENOS_SOURCE
+#include "libc/string.h"
 
 /* Copying and Concatenation */
-extern char *strcpy(char *__restrict__ dest, const char *__restrict__ src);
-extern char *strncpy(char *__restrict__ dest, const char *__restrict__ src, size_t n);
 extern char *stpcpy(char *__restrict__ dest, const char *__restrict__ src);
 extern char *stpncpy(char *__restrict__ dest, const char *__restrict__ src, size_t n);
-extern char *strcat(char *__restrict__ dest, const char *__restrict__ src);
-extern char *strncat(char *__restrict__ dest, const char *__restrict__ src, size_t n);
 extern void *memccpy(void *__restrict__ dest, const void *__restrict__ src, int c, size_t n);
 extern char *strdup(const char *s);
 extern char *strndup(const char *s, size_t n);
 
-/* String Comparison */
-extern int strcmp(const char *s1, const char *s2);
-extern int strncmp(const char *s1, const char *s2, size_t n);
-
 /* Search Functions */
-extern char *strchr(const char *s, int c);
-extern char *strrchr(const char *s, int c);
 extern char *gnu_strchrnul(const char *s, int c);
-extern char *strpbrk(const char *s1, const char *s2);
-extern size_t strcspn(const char *s1, const char *s2);
-extern size_t strspn(const char *s1, const char *s2);
-extern char *strstr(const char *haystack, const char *needle);
 
 /* Tokenization functions. */
 extern char *strtok_r(char *, const char *, char **);
-extern char *strtok(char *, const char *);
-
-
-/* Collation Functions */
-extern int strcoll(const char *s1, const char *s2);
-extern size_t strxfrm(char *__restrict__ s1, const char *__restrict__ s2, size_t n);
 
 /* Error Messages */
-extern char *strerror(int errnum);
 extern int strerror_r(int errnum, char *buf, size_t bufsz);
 
 /* String Length */
-extern size_t strlen(const char *s);
 extern size_t strnlen(const char *s, size_t n);
 
Index: uspace/lib/posix/src/string.c
===================================================================
--- uspace/lib/posix/src/string.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
+++ uspace/lib/posix/src/string.c	(revision 99d3123e7ab9ecf412fde9af4e2b084aac7c5dc1)
@@ -2,4 +2,5 @@
  * Copyright (c) 2011 Petr Koupy
  * Copyright (c) 2011 Jiri Zarevucky
+ * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -49,49 +50,4 @@
 
 /**
- * The same as strpbrk, except it returns pointer to the nul terminator
- * if no occurence is found.
- *
- * @param s1 String in which to look for the bytes.
- * @param s2 String of bytes to look for.
- * @return Pointer to the found byte on success, pointer to the
- *     string terminator otherwise.
- */
-static char *strpbrk_null(const char *s1, const char *s2)
-{
-	while (!strchr(s2, *s1)) {
-		++s1;
-	}
-
-	return (char *) s1;
-}
-
-/**
- * Copy a string.
- *
- * @param dest Destination pre-allocated buffer.
- * @param src Source string to be copied.
- * @return Pointer to the destination buffer.
- */
-char *strcpy(char *restrict dest, const char *restrict src)
-{
-	stpcpy(dest, src);
-	return dest;
-}
-
-/**
- * Copy fixed length string.
- *
- * @param dest Destination pre-allocated buffer.
- * @param src Source string to be copied.
- * @param n Number of bytes to be stored into destination buffer.
- * @return Pointer to the destination buffer.
- */
-char *strncpy(char *restrict dest, const char *restrict src, size_t n)
-{
-	stpncpy(dest, src, n);
-	return dest;
-}
-
-/**
  * Copy a string.
  *
@@ -151,39 +107,4 @@
 
 /**
- * Concatenate two strings.
- *
- * @param dest String to which src shall be appended.
- * @param src String to be appended after dest.
- * @return Pointer to destination buffer.
- */
-char *strcat(char *restrict dest, const char *restrict src)
-{
-	assert(dest != NULL);
-	assert(src != NULL);
-
-	strcpy(strchr(dest, '\0'), src);
-	return dest;
-}
-
-/**
- * Concatenate a string with part of another.
- *
- * @param dest String to which part of src shall be appended.
- * @param src String whose part shall be appended after dest.
- * @param n Number of bytes to append after dest.
- * @return Pointer to destination buffer.
- */
-char *strncat(char *restrict dest, const char *restrict src, size_t n)
-{
-	assert(dest != NULL);
-	assert(src != NULL);
-
-	char *zeroptr = strncpy(strchr(dest, '\0'), src, n);
-	/* strncpy doesn't append the nul terminator, so we do it here */
-	zeroptr[n] = '\0';
-	return dest;
-}
-
-/**
  * Copy limited number of bytes in memory.
  *
@@ -249,88 +170,4 @@
 
 /**
- * Compare two strings.
- *
- * @param s1 First string to be compared.
- * @param s2 Second string to be compared.
- * @return Difference of the first pair of inequal characters,
- *     or 0 if strings have the same content.
- */
-int strcmp(const char *s1, const char *s2)
-{
-	assert(s1 != NULL);
-	assert(s2 != NULL);
-
-	return strncmp(s1, s2, STR_NO_LIMIT);
-}
-
-/**
- * Compare part of two strings.
- *
- * @param s1 First string to be compared.
- * @param s2 Second string to be compared.
- * @param n Maximum number of characters to be compared.
- * @return Difference of the first pair of inequal characters,
- *     or 0 if strings have the same content.
- */
-int strncmp(const char *s1, const char *s2, size_t n)
-{
-	assert(s1 != NULL);
-	assert(s2 != NULL);
-
-	for (size_t i = 0; i < n; ++i) {
-		if (s1[i] != s2[i]) {
-			return s1[i] - s2[i];
-		}
-		if (s1[i] == '\0') {
-			break;
-		}
-	}
-
-	return 0;
-}
-
-/**
- * Scan string for a first occurence of a character.
- *
- * @param s String in which to look for the character.
- * @param c Character to look for.
- * @return Pointer to the specified character on success,
- *     NULL pointer otherwise.
- */
-char *strchr(const char *s, int c)
-{
-	assert(s != NULL);
-
-	char *res = gnu_strchrnul(s, c);
-	return (*res == c) ? res : NULL;
-}
-
-/**
- * Scan string for a last occurence of a character.
- *
- * @param s String in which to look for the character.
- * @param c Character to look for.
- * @return Pointer to the specified character on success,
- *     NULL pointer otherwise.
- */
-char *strrchr(const char *s, int c)
-{
-	assert(s != NULL);
-
-	const char *ptr = strchr(s, '\0');
-
-	/* the same as in strchr, except it loops in reverse direction */
-	while (*ptr != (char) c) {
-		if (ptr == s) {
-			return NULL;
-		}
-
-		ptr--;
-	}
-
-	return (char *) ptr;
-}
-
-/**
  * Scan string for a first occurence of a character.
  *
@@ -350,130 +187,4 @@
 	return (char *) s;
 }
-
-/**
- * Scan a string for a first occurence of one of provided bytes.
- *
- * @param s1 String in which to look for the bytes.
- * @param s2 String of bytes to look for.
- * @return Pointer to the found byte on success,
- *     NULL pointer otherwise.
- */
-char *strpbrk(const char *s1, const char *s2)
-{
-	assert(s1 != NULL);
-	assert(s2 != NULL);
-
-	char *ptr = strpbrk_null(s1, s2);
-	return (*ptr == '\0') ? NULL : ptr;
-}
-
-/**
- * Get the length of a complementary substring.
- *
- * @param s1 String that shall be searched for complementary prefix.
- * @param s2 String of bytes that shall not occur in the prefix.
- * @return Length of the prefix.
- */
-size_t strcspn(const char *s1, const char *s2)
-{
-	assert(s1 != NULL);
-	assert(s2 != NULL);
-
-	char *ptr = strpbrk_null(s1, s2);
-	return (size_t) (ptr - s1);
-}
-
-/**
- * Get length of a substring.
- *
- * @param s1 String that shall be searched for prefix.
- * @param s2 String of bytes that the prefix must consist of.
- * @return Length of the prefix.
- */
-size_t strspn(const char *s1, const char *s2)
-{
-	assert(s1 != NULL);
-	assert(s2 != NULL);
-
-	const char *ptr;
-	for (ptr = s1; *ptr != '\0'; ++ptr) {
-		if (!strchr(s2, *ptr)) {
-			break;
-		}
-	}
-	return ptr - s1;
-}
-
-/**
- * Find a substring. Uses Knuth-Morris-Pratt algorithm.
- *
- * @param s1 String in which to look for a substring.
- * @param s2 Substring to look for.
- * @return Pointer to the first character of the substring in s1, or NULL if
- *     not found.
- */
-char *strstr(const char *haystack, const char *needle)
-{
-	assert(haystack != NULL);
-	assert(needle != NULL);
-
-	/* Special case - needle is an empty string. */
-	if (needle[0] == '\0') {
-		return (char *) haystack;
-	}
-
-	/* Preprocess needle. */
-	size_t nlen = strlen(needle);
-	size_t prefix_table[nlen + 1];
-
-	size_t i = 0;
-	ssize_t j = -1;
-
-	prefix_table[i] = j;
-
-	while (i < nlen) {
-		while (j >= 0 && needle[i] != needle[j]) {
-			j = prefix_table[j];
-		}
-		i++;
-		j++;
-		prefix_table[i] = j;
-	}
-
-	/* Search needle using the precomputed table. */
-	size_t npos = 0;
-
-	for (size_t hpos = 0; haystack[hpos] != '\0'; ++hpos) {
-		while (npos != 0 && haystack[hpos] != needle[npos]) {
-			npos = prefix_table[npos];
-		}
-
-		if (haystack[hpos] == needle[npos]) {
-			npos++;
-
-			if (npos == nlen) {
-				return (char *) (haystack + hpos - nlen + 1);
-			}
-		}
-	}
-
-	return NULL;
-}
-
-/** Split string by delimiters.
- *
- * @param s             String to be tokenized. May not be NULL.
- * @param delim		String with the delimiters.
- * @return              Pointer to the prefix of @a s before the first
- *                      delimiter character. NULL if no such prefix
- *                      exists.
- */
-char *strtok(char *s, const char *delim)
-{
-	static char *next;
-
-	return strtok_r(s, delim, &next);
-}
-
 
 /** Split string by delimiters.
@@ -491,83 +202,5 @@
 char *strtok_r(char *s, const char *delim, char **next)
 {
-	char *start, *end;
-
-	if (s == NULL)
-		s = *next;
-
-	/* Skip over leading delimiters. */
-	while (*s && (strchr(delim, *s) != NULL))
-		++s;
-	start = s;
-
-	/* Skip over token characters. */
-	while (*s && (strchr(delim, *s) == NULL))
-		++s;
-	end = s;
-	*next = (*s ? s + 1 : s);
-
-	if (start == end) {
-		return NULL;	/* No more tokens. */
-	}
-
-	/* Overwrite delimiter with NULL terminator. */
-	*end = '\0';
-	return start;
-}
-
-/**
- * String comparison using collating information.
- *
- * Currently ignores locale and just calls strcmp.
- *
- * @param s1 First string to be compared.
- * @param s2 Second string to be compared.
- * @return Difference of the first pair of inequal characters,
- *     or 0 if strings have the same content.
- */
-int strcoll(const char *s1, const char *s2)
-{
-	assert(s1 != NULL);
-	assert(s2 != NULL);
-
-	return strcmp(s1, s2);
-}
-
-/**
- * Transform a string in such a way that the resulting string yields the same
- * results when passed to the strcmp as if the original string is passed to
- * the strcoll.
- *
- * Since strcoll is equal to strcmp here, this just makes a copy.
- *
- * @param s1 Transformed string.
- * @param s2 Original string.
- * @param n Maximum length of the transformed string.
- * @return Length of the transformed string.
- */
-size_t strxfrm(char *restrict s1, const char *restrict s2, size_t n)
-{
-	assert(s1 != NULL || n == 0);
-	assert(s2 != NULL);
-
-	size_t len = strlen(s2);
-
-	if (n > len) {
-		strcpy(s1, s2);
-	}
-
-	return len;
-}
-
-/**
- * Get error message string.
- *
- * @param errnum Error code for which to obtain human readable string.
- * @return Error message.
- */
-char *strerror(int errnum)
-{
-	// FIXME: move strerror() and strerror_r() to libc.
-	return (char *) str_error(errnum);
+	return __strtok_r(s, delim, next);
 }
 
@@ -593,17 +226,4 @@
 
 	return EOK;
-}
-
-/**
- * Get length of the string.
- *
- * @param s String which length shall be determined.
- * @return Length of the string.
- */
-size_t strlen(const char *s)
-{
-	assert(s != NULL);
-
-	return (size_t) (strchr(s, '\0') - s);
 }
 
