am b88da065: Merge "Upgrade to current vfprintf."

* commit 'b88da06580a22d9a1ee5a1c573c49e89207bc71b':
  Upgrade to current vfprintf.
This commit is contained in:
Elliott Hughes 2014-04-18 21:15:28 +00:00 committed by Android Git Automerger
commit 06b5431eaa
8 changed files with 650 additions and 263 deletions

View File

@ -79,7 +79,6 @@ libc_common_src_files := \
stdio/fvwrite.c \
stdio/snprintf.c\
stdio/sprintf.c \
stdio/vfprintf.c \
stdlib/atexit.c \
stdlib/getenv.c \
stdlib/putenv.c \
@ -395,6 +394,7 @@ libc_upstream_openbsd_src_files := \
upstream-openbsd/lib/libc/stdio/tmpnam.c \
upstream-openbsd/lib/libc/stdio/ungetc.c \
upstream-openbsd/lib/libc/stdio/vasprintf.c \
upstream-openbsd/lib/libc/stdio/vfprintf.c \
upstream-openbsd/lib/libc/stdio/vfscanf.c \
upstream-openbsd/lib/libc/stdio/vprintf.c \
upstream-openbsd/lib/libc/stdio/vscanf.c \

View File

@ -243,21 +243,42 @@ size_t wcsftime(wchar_t* wcs, size_t maxsize, const wchar_t* format, const stru
return strftime(reinterpret_cast<char*>(wcs), maxsize, reinterpret_cast<const char*>(format), timptr);
}
size_t wcsrtombs(char* dst, const wchar_t** src, size_t len, mbstate_t* /*ps*/) {
const char* s = reinterpret_cast<const char*>(*src);
const char* s2 = reinterpret_cast<const char*>(memchr(s, 0, len));
if (s2 != NULL) {
len = (s2 - s)+1;
size_t wcsrtombs(char* dst, const wchar_t** src, size_t n, mbstate_t* /*ps*/) {
size_t i = 0; // Number of input characters read.
size_t o = 0; // Number of output bytes written.
for (; (*src)[i] != 0; ++i) {
// TODO: UTF-8 support.
if ((*src)[i] > 0x7f) {
errno = EILSEQ;
return static_cast<size_t>(-1);
}
if (dst != NULL) {
if (o + 1 > n) {
break;
}
dst[o++] = static_cast<char>((*src)[i]);
} else {
++o;
}
}
// If we consumed all the input, terminate the output.
if (dst != NULL && o < n) {
dst[o] = 0;
}
// If we were actually consuming input, record how far we got.
if (dst != NULL) {
memcpy( dst, s, len );
if ((*src)[i] != 0) {
*src = &(*src)[i]; // This is where the next call should pick up.
} else {
*src = NULL; // We consumed everything.
}
}
*src = (wchar_t*)(s + len);
return len;
return o;
}
size_t wcstombs(char* dst, const wchar_t* src, size_t len) {
return wcsrtombs(dst, &src, len, NULL);
const wchar_t* p = src;
return wcsrtombs(dst, &p, len, NULL);
}
double wcstod(const wchar_t* nptr, wchar_t** endptr) {

View File

@ -95,6 +95,8 @@ extern int __sdidinit;
#define FUNLOCKFILE(fp) funlockfile(fp)
#define FLOATING_POINT
#define PRINTF_WIDE_CHAR
#define SCANF_WIDE_CHAR
/* OpenBSD exposes these in <stdio.h>, but we only want them exposed to the implementation. */
__BEGIN_DECLS

View File

@ -0,0 +1,3 @@
/* Hack to build "vfprintf.c". */
#define RADIXCHAR 1
#define nl_langinfo(i) ((i == RADIXCHAR) ? (char*) "." : NULL)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: floatio.h,v 1.3 2003/06/02 20:18:37 millert Exp $ */
/* $OpenBSD: floatio.h,v 1.4 2008/09/07 20:36:08 martynas Exp $ */
/*-
* Copyright (c) 1990, 1993
@ -40,3 +40,19 @@
#define MAXEXP 308
/* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
#define MAXFRACT 39
/*
* MAXEXPDIG is the maximum number of decimal digits needed to store a
* floating point exponent in the largest supported format. It should
* be ceil(log10(LDBL_MAX_10_EXP)) or, if hexadecimal floating point
* conversions are supported, ceil(log10(LDBL_MAX_EXP)). But since it
* is presently never greater than 5 in practice, we fudge it.
*/
#define MAXEXPDIG 6
#if LDBL_MAX_EXP > 999999
#error "floating point buffers too small"
#endif
char *__hdtoa(double, const char *, int, int *, int *, char **);
char *__hldtoa(long double, const char *, int, int *, int *, char **);
char *__ldtoa(long double *, int, int, int *, int *, char **);

View File

@ -23,6 +23,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wchar.h>
TEST(stdio, tmpfile_fileno_fprintf_rewind_fgets) {
FILE* fp = tmpfile();
@ -192,18 +193,38 @@ TEST(stdio, printf_ssize_t) {
snprintf(buf, sizeof(buf), "%zd", v);
}
TEST(stdio, snprintf_n_format_specifier_not_implemented) {
#if defined(__BIONIC__)
// https://code.google.com/p/android/issues/detail?id=64886
TEST(stdio, snprintf_a) {
char buf[BUFSIZ];
EXPECT_EQ(23, snprintf(buf, sizeof(buf), "<%a>", 9990.235));
EXPECT_STREQ("<0x1.3831e147ae148p+13>", buf);
}
TEST(stdio, snprintf_lc) {
char buf[BUFSIZ];
wint_t wc = L'a';
EXPECT_EQ(3, snprintf(buf, sizeof(buf), "<%lc>", wc));
EXPECT_STREQ("<a>", buf);
}
TEST(stdio, snprintf_ls) {
char buf[BUFSIZ];
wchar_t* ws = NULL;
EXPECT_EQ(8, snprintf(buf, sizeof(buf), "<%ls>", ws));
EXPECT_STREQ("<(null)>", buf);
wchar_t chars[] = { L'h', L'i', 0 };
ws = chars;
EXPECT_EQ(4, snprintf(buf, sizeof(buf), "<%ls>", ws));
EXPECT_STREQ("<hi>", buf);
}
TEST(stdio, snprintf_n) {
char buf[32];
int i = 0;
// We deliberately don't implement %n, so it's treated like
// any other unrecognized format specifier.
EXPECT_EQ(5, snprintf(buf, sizeof(buf), "a %n b", &i));
EXPECT_EQ(0, i);
EXPECT_STREQ("a n b", buf);
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif // __BIONIC__
EXPECT_EQ(4, snprintf(buf, sizeof(buf), "a %n b", &i));
EXPECT_EQ(2, i);
EXPECT_STREQ("a b", buf);
}
TEST(stdio, snprintf_smoke) {

View File

@ -16,6 +16,7 @@
#include <gtest/gtest.h>
#include <errno.h>
#include <limits.h>
#include <wchar.h>
@ -55,3 +56,102 @@ TEST(wchar, wctomb_wcrtomb) {
EXPECT_EQ(1U, wcrtomb(bytes, L'h', NULL));
EXPECT_EQ('h', bytes[0]);
}
TEST(wchar, wcstombs_wcrtombs) {
wchar_t chars[] = { L'h', L'e', L'l', L'l', L'o', 0 };
wchar_t bad_chars[] = { L'h', L'i', 666, 0 };
const wchar_t* src;
char bytes[BUFSIZ];
// Given a NULL destination, these functions count valid characters.
EXPECT_EQ(5U, wcstombs(NULL, chars, 0));
EXPECT_EQ(5U, wcstombs(NULL, chars, 4));
EXPECT_EQ(5U, wcstombs(NULL, chars, 256));
src = chars;
EXPECT_EQ(5U, wcsrtombs(NULL, &src, 0, NULL));
EXPECT_EQ(&chars[0], src);
src = chars;
EXPECT_EQ(5U, wcsrtombs(NULL, &src, 4, NULL));
EXPECT_EQ(&chars[0], src);
src = chars;
EXPECT_EQ(5U, wcsrtombs(NULL, &src, 256, NULL));
EXPECT_EQ(&chars[0], src);
// An unrepresentable char just returns an error from wcstombs...
errno = 0;
EXPECT_EQ(static_cast<size_t>(-1), wcstombs(NULL, bad_chars, 0));
EXPECT_EQ(EILSEQ, errno);
errno = 0;
EXPECT_EQ(static_cast<size_t>(-1), wcstombs(NULL, bad_chars, 256));
EXPECT_EQ(EILSEQ, errno);
// And wcsrtombs doesn't tell us where it got stuck because we didn't ask it
// to actually convert anything...
errno = 0;
src = bad_chars;
EXPECT_EQ(static_cast<size_t>(-1), wcsrtombs(NULL, &src, 0, NULL));
EXPECT_EQ(&bad_chars[0], src);
EXPECT_EQ(EILSEQ, errno);
errno = 0;
src = bad_chars;
EXPECT_EQ(static_cast<size_t>(-1), wcsrtombs(NULL, &src, 256, NULL));
EXPECT_EQ(&bad_chars[0], src);
EXPECT_EQ(EILSEQ, errno);
// Okay, now let's test actually converting something...
memset(bytes, 'x', sizeof(bytes));
EXPECT_EQ(0U, wcstombs(bytes, chars, 0));
memset(bytes, 'x', sizeof(bytes));
EXPECT_EQ(4U, wcstombs(bytes, chars, 4));
bytes[5] = 0;
EXPECT_STREQ("hellx", bytes);
memset(bytes, 'x', sizeof(bytes));
EXPECT_EQ(5U, wcstombs(bytes, chars, 256));
EXPECT_STREQ("hello", bytes);
memset(bytes, 'x', sizeof(bytes));
EXPECT_EQ(5U, wcstombs(bytes, chars, 6));
EXPECT_STREQ("hello", bytes);
errno = 0;
memset(bytes, 'x', sizeof(bytes));
EXPECT_EQ(static_cast<size_t>(-1), wcstombs(bytes, bad_chars, 256));
EXPECT_EQ(EILSEQ, errno);
bytes[3] = 0;
EXPECT_STREQ("hix", bytes);
// wcsrtombs is a bit more informative...
memset(bytes, 'x', sizeof(bytes));
src = chars;
EXPECT_EQ(0U, wcsrtombs(bytes, &src, 0, NULL));
EXPECT_EQ(&chars[0], src); // No input consumed.
EXPECT_EQ(EILSEQ, errno);
memset(bytes, 'x', sizeof(bytes));
src = chars;
EXPECT_EQ(4U, wcsrtombs(bytes, &src, 4, NULL));
EXPECT_EQ(&chars[4], src); // Some input consumed.
EXPECT_EQ(EILSEQ, errno);
bytes[5] = 0;
EXPECT_STREQ("hellx", bytes);
memset(bytes, 'x', sizeof(bytes));
src = chars;
EXPECT_EQ(5U, wcsrtombs(bytes, &src, 256, NULL));
EXPECT_EQ(NULL, src); // All input consumed!
EXPECT_EQ(EILSEQ, errno);
EXPECT_STREQ("hello", bytes);
memset(bytes, 'x', sizeof(bytes));
src = chars;
EXPECT_EQ(5U, wcsrtombs(bytes, &src, 6, NULL));
EXPECT_EQ(NULL, src); // All input consumed.
EXPECT_EQ(EILSEQ, errno);
EXPECT_STREQ("hello", bytes);
memset(bytes, 'x', sizeof(bytes));
src = bad_chars;
EXPECT_EQ(static_cast<size_t>(-1), wcsrtombs(bytes, &src, 256, NULL));
EXPECT_EQ(&bad_chars[2], src);
EXPECT_EQ(EILSEQ, errno);
bytes[3] = 0;
EXPECT_STREQ("hix", bytes);
}