summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
authormatthew <matthew@openbsd.org>2013-06-02 15:22:20 +0000
committermatthew <matthew@openbsd.org>2013-06-02 15:22:20 +0000
commit2480e29e8fefb66c16ae3318c7a444a94b169ec2 (patch)
tree53daae84269a6c1bc294e6f1421cfa5dbf4b7592 /lib/libc
parentsync (diff)
downloadwireguard-openbsd-2480e29e8fefb66c16ae3318c7a444a94b169ec2.tar.xz
wireguard-openbsd-2480e29e8fefb66c16ae3318c7a444a94b169ec2.zip
Fix wcsto{f,d,ld}() C99 compliance to now correctly
1. handle "inf", "infinity", "nan", and "nan(whatever)", 2. reject bare minus and plus signs, 3. handle multi-byte characters, and 4. set *endptr = nptr for all failure cases. Fixes libc++'s test cases for std::sto{f,d,ld}(). ok stsp
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/locale/_wcstod.h65
1 files changed, 45 insertions, 20 deletions
diff --git a/lib/libc/locale/_wcstod.h b/lib/libc/locale/_wcstod.h
index 70aa40d239d..ae993ad675e 100644
--- a/lib/libc/locale/_wcstod.h
+++ b/lib/libc/locale/_wcstod.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: _wcstod.h,v 1.1 2009/01/13 18:18:31 kettenis Exp $ */
+/* $OpenBSD: _wcstod.h,v 1.2 2013/06/02 15:22:20 matthew Exp $ */
/* $NetBSD: wcstod.c,v 1.4 2001/10/28 12:08:43 yamt Exp $ */
/*-
@@ -44,6 +44,7 @@ FUNCNAME(const wchar_t *nptr, wchar_t **endptr)
const wchar_t *src;
size_t size;
const wchar_t *start;
+ const wchar_t *aftersign;
/*
* check length of string and call strtod
@@ -59,6 +60,24 @@ FUNCNAME(const wchar_t *nptr, wchar_t **endptr)
start = src;
if (*src && wcschr(L"+-", *src))
src++;
+ aftersign = src;
+ if (wcsncasecmp(src, L"inf", 3) == 0) {
+ src += 3;
+ if (wcsncasecmp(src, L"inity", 5) == 0)
+ src += 5;
+ goto match;
+ }
+ if (wcsncasecmp(src, L"nan", 3) == 0) {
+ src += 3;
+ if (*src == L'(') {
+ size = 1;
+ while (src[size] != L'\0' && src[size] != L')')
+ size++;
+ if (src[size] == L')')
+ src += size + 1;
+ }
+ goto match;
+ }
size = wcsspn(src, L"0123456789");
src += size;
if (*src == L'.') {/* XXX use localeconv */
@@ -73,56 +92,62 @@ FUNCNAME(const wchar_t *nptr, wchar_t **endptr)
size = wcsspn(src, L"0123456789");
src += size;
}
+match:
size = src - start;
/*
* convert to a char-string and pass it to strtod.
- *
- * since all mb chars used to represent a double-constant
- * are in the portable character set, we can assume
- * that they are 1-byte chars.
*/
- if (size)
- {
+ if (src > aftersign) {
mbstate_t st;
char *buf;
char *end;
const wchar_t *s;
size_t size_converted;
float_type result;
-
- buf = malloc(size + 1);
+ size_t bufsize;
+
+ s = start;
+ memset(&st, 0, sizeof(st));
+ bufsize = wcsnrtombs(NULL, &s, size, 0, &st);
+
+ buf = malloc(bufsize + 1);
if (!buf) {
- /* error */
errno = ENOMEM; /* XXX */
- return 0;
+ goto fail;
}
-
+
s = start;
memset(&st, 0, sizeof(st));
- size_converted = wcsrtombs(buf, &s, size, &st);
- if (size != size_converted) {
+ size_converted = wcsnrtombs(buf, &s, size, bufsize, &st);
+ if (size_converted != bufsize) {
/* XXX should not happen */
free(buf);
errno = EILSEQ;
- return 0;
+ goto fail;
}
- buf[size] = 0;
+ buf[bufsize] = 0;
result = STRTOD_FUNC(buf, &end);
- free(buf);
+ if (endptr) {
+ const char *s = buf;
+ memset(&st, 0, sizeof(st));
+ size = mbsnrtowcs(NULL, &s, end - buf, 0, &st);
- if (endptr)
/* LINTED bad interface */
- *endptr = (wchar_t*)start + (end - buf);
+ *endptr = (wchar_t*)start + size;
+ }
+
+ free(buf);
return result;
}
+fail:
if (endptr)
/* LINTED bad interface */
- *endptr = (wchar_t*)start;
+ *endptr = (wchar_t*)nptr;
return 0;
}