Index: uspace/lib/c/generic/private/scanf.h
===================================================================
--- uspace/lib/c/generic/private/scanf.h	(revision 0d83cf6f04f9a3bfef021c71a4d4e0c172f9ad79)
+++ uspace/lib/c/generic/private/scanf.h	(revision 0d83cf6f04f9a3bfef021c71a4d4e0c172f9ad79)
@@ -0,0 +1,46 @@
+/*
+ * 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_PRIVATE_SCANF_H_
+#define LIBC_PRIVATE_SCANF_H_
+
+#include <stddef.h>
+#include <stdio.h>
+
+extern errno_t __fstrtold(FILE *, int *, size_t, long double *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/generic/private/sstream.h
===================================================================
--- uspace/lib/c/generic/private/sstream.h	(revision 42f5860963db60eafa4b16ddff590121a76573c6)
+++ uspace/lib/c/generic/private/sstream.h	(revision 0d83cf6f04f9a3bfef021c71a4d4e0c172f9ad79)
@@ -39,4 +39,5 @@
 
 extern void __sstream_init(const char *, FILE *);
+extern const char *__sstream_getpos(FILE *);
 
 #endif
Index: uspace/lib/c/generic/stdio/scanf.c
===================================================================
--- uspace/lib/c/generic/stdio/scanf.c	(revision 42f5860963db60eafa4b16ddff590121a76573c6)
+++ uspace/lib/c/generic/stdio/scanf.c	(revision 0d83cf6f04f9a3bfef021c71a4d4e0c172f9ad79)
@@ -46,4 +46,6 @@
 #include <stdio.h>
 #include <stdlib.h>
+
+#include "../private/scanf.h"
 
 typedef enum {
@@ -348,5 +350,5 @@
  * @return EOK on success, ENOMEM if out of memory
  */
-static int strbuf_init(strbuf_t *strbuf, cvtspec_t *spec, va_encaps_t *va)
+static errno_t strbuf_init(strbuf_t *strbuf, cvtspec_t *spec, va_encaps_t *va)
 {
 	if (spec->noassign) {
@@ -393,5 +395,5 @@
  * @return EOK on sucess, ENOMEM if out of memory
  */
-static int strbuf_write(strbuf_t *strbuf, size_t idx, char c)
+static errno_t strbuf_write(strbuf_t *strbuf, size_t idx, char c)
 {
 	if (strbuf->memalloc && idx >= strbuf->size) {
@@ -449,5 +451,5 @@
 
 /* Skip whitespace in input stream */
-static int vfscanf_skip_ws(FILE *f, int *numchar)
+static errno_t vfscanf_skip_ws(FILE *f, int *numchar)
 {
 	int c;
@@ -471,7 +473,7 @@
 
 /* Match whitespace. */
-static int vfscanf_match_ws(FILE *f, int *numchar, const char **fmt)
-{
-	int rc;
+static errno_t vfscanf_match_ws(FILE *f, int *numchar, const char **fmt)
+{
+	errno_t rc;
 
 	rc = vfscanf_skip_ws(f, numchar);
@@ -492,11 +494,16 @@
  * @return EOK on success, EIO on I/O error, EINVAL if input is not valid
  */
-static int __fstrtoimax(FILE *f, int *numchar, int base, size_t width,
+static errno_t __fstrtoimax(FILE *f, int *numchar, int base, size_t width,
     intmax_t *dest)
 {
+	errno_t rc;
 	int c;
 	intmax_t v;
 	int digit;
 	int sign;
+
+	rc = vfscanf_skip_ws(f, numchar);
+	if (rc == EIO)
+		return EIO;
 
 	c = __fgetc(f, numchar);
@@ -579,10 +586,15 @@
  * @return EOK on success, EIO on I/O error, EINVAL if input is not valid
  */
-static int __fstrtoumax(FILE *f, int *numchar, int base, size_t width,
+static errno_t __fstrtoumax(FILE *f, int *numchar, int base, size_t width,
     uintmax_t *dest)
 {
+	errno_t rc;
 	int c;
 	uintmax_t v;
 	int digit;
+
+	rc = vfscanf_skip_ws(f, numchar);
+	if (rc == EIO)
+		return EIO;
 
 	c = __fgetc(f, numchar);
@@ -653,6 +665,8 @@
  * @return EOK on success, EIO on I/O error, EINVAL if input is not valid
  */
-static int __fstrtold(FILE *f, int *numchar, size_t width, long double *dest)
-{
+errno_t __fstrtold(FILE *f, int *numchar, size_t width,
+    long double *dest)
+{
+	errno_t rc;
 	int c;
 	long double v;
@@ -665,4 +679,8 @@
 	int exp;
 	int expsign;
+
+	rc = vfscanf_skip_ws(f, numchar);
+	if (rc == EIO)
+		return EIO;
 
 	c = __fgetc(f, numchar);
@@ -823,11 +841,12 @@
 
 /* Read characters from stream */
-static int __fgetchars(FILE *f, int *numchar, size_t width, strbuf_t *strbuf,
-    size_t *nread)
+static errno_t __fgetchars(FILE *f, int *numchar, size_t width,
+    strbuf_t *strbuf, size_t *nread)
 {
 	size_t cnt;
 	int c;
-	int rc;
-
+	errno_t rc;
+
+	*nread = 0;
 	for (cnt = 0; cnt < width; cnt++) {
 		c = __fgetc(f, numchar);
@@ -849,11 +868,17 @@
 
 /* Read non-whitespace string from stream */
-static int __fgetstr(FILE *f, int *numchar, size_t width, strbuf_t *strbuf,
+static errno_t __fgetstr(FILE *f, int *numchar, size_t width, strbuf_t *strbuf,
     size_t *nread)
 {
 	size_t cnt;
 	int c;
-	int rc;
-	int rc2;
+	errno_t rc;
+	errno_t rc2;
+
+	*nread = 0;
+
+	rc = vfscanf_skip_ws(f, numchar);
+	if (rc == EIO)
+		return EIO;
 
 	rc = EOK;
@@ -949,11 +974,11 @@
 
 /* Read string of characters from scanset from stream */
-static int __fgetscanstr(FILE *f, int *numchar, size_t width,
+static errno_t __fgetscanstr(FILE *f, int *numchar, size_t width,
     const char *scanset, strbuf_t *strbuf, size_t *nread)
 {
 	size_t cnt;
 	int c;
-	int rc;
-	int rc2;
+	errno_t rc;
+	errno_t rc2;
 
 	rc = EOK;
@@ -990,8 +1015,8 @@
 
 /** Perform a single conversion. */
-static int vfscanf_cvt(FILE *f, const char **fmt, va_encaps_t *va,
+static errno_t vfscanf_cvt(FILE *f, const char **fmt, va_encaps_t *va,
     int *numchar, unsigned *ncvt)
 {
-	int rc;
+	errno_t rc;
 	int c;
 	intmax_t ival;
@@ -1027,14 +1052,4 @@
 	cvtspec_parse(fmt, &cvtspec);
 
-	if (cvtspec.spcr != cs_set && cvtspec.spcr != cs_char &&
-	    cvtspec.spcr != cs_numchar) {
-		/* Skip whitespace */
-		rc = vfscanf_skip_ws(f, numchar);
-		if (rc == EIO)
-			return EIO;
-
-		assert(rc == EOK);
-	}
-
 	width = cvtspec.have_width ? cvtspec.width : SIZE_MAX;
 
@@ -1042,4 +1057,8 @@
 	case cs_percent:
 		/* Match % character */
+		rc = vfscanf_skip_ws(f, numchar);
+		if (rc == EOF)
+			return EIO;
+
 		c = __fgetc(f, numchar);
 		if (c == EOF)
Index: uspace/lib/c/generic/stdio/sstream.c
===================================================================
--- uspace/lib/c/generic/stdio/sstream.c	(revision 42f5860963db60eafa4b16ddff590121a76573c6)
+++ uspace/lib/c/generic/stdio/sstream.c	(revision 0d83cf6f04f9a3bfef021c71a4d4e0c172f9ad79)
@@ -99,4 +99,15 @@
 }
 
+/** Return current string stream position.
+ *
+ * @param stream String stream
+ * @return Pointer into the backing string at the current position
+ */
+const char *__sstream_getpos(FILE *stream)
+{
+	assert(stream->ops == &stdio_str_ops);
+	return (char *) stream->arg;
+}
+
 /** @}
  */
Index: uspace/lib/c/generic/stdlib.c
===================================================================
--- uspace/lib/c/generic/stdlib.c	(revision 42f5860963db60eafa4b16ddff590121a76573c6)
+++ uspace/lib/c/generic/stdlib.c	(revision 0d83cf6f04f9a3bfef021c71a4d4e0c172f9ad79)
@@ -38,5 +38,8 @@
 #include <stdlib.h>
 #include "private/libc.h"
+#include "private/scanf.h"
 #include "private/stdlib.h"
+#include "private/stdio.h"
+#include "private/sstream.h"
 
 static int glbl_seed = 1;
@@ -48,4 +51,30 @@
 static FIBRIL_MUTEX_INITIALIZE(quick_exit_handlers_lock);
 
+/** Convert string to long double.
+ *
+ */
+long double strtold(const char *nptr, char **endptr)
+{
+	int numchar;
+	long double ld;
+	errno_t rc;
+	FILE f;
+
+	numchar = 0;
+	__sstream_init(nptr, &f);
+
+	rc = __fstrtold(&f, &numchar, SIZE_MAX, &ld);
+	if (rc != EOK) {
+		ld = 0;
+		if (endptr != NULL)
+			*endptr = (char *) nptr;
+		errno = rc;
+	} else {
+		if (endptr != NULL)
+			*endptr = (char *) __sstream_getpos(&f);
+	}
+
+	return ld;
+}
 
 int rand(void)
