Merge "Add stpcpy/stpncpy."
diff --git a/libc/Android.mk b/libc/Android.mk
index 3eaff2f..e4e58b7 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -71,7 +71,6 @@
bionic/sigsetmask.c \
bionic/strntoimax.c \
bionic/strntoumax.c \
- bionic/strtotimeval.c \
bionic/system_properties_compat.c \
bionic/time64.c \
bionic/unlockpt.c \
diff --git a/libc/bionic/ndk_cruft.cpp b/libc/bionic/ndk_cruft.cpp
index b0346d4..7826651 100644
--- a/libc/bionic/ndk_cruft.cpp
+++ b/libc/bionic/ndk_cruft.cpp
@@ -29,6 +29,8 @@
// This file perpetuates the mistakes of the past, but only for 32-bit targets.
#if !defined(__LP64__)
+#include <ctype.h>
+#include <inttypes.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/resource.h>
@@ -87,4 +89,31 @@
return 0;
}
+// Non-standard cruft that should only ever have been in system/core/toolbox.
+extern "C" char* strtotimeval(const char* str, struct timeval* ts) {
+ char* s;
+ ts->tv_sec = strtoumax(str, &s, 10);
+
+ long fractional_seconds = 0;
+ if (*s == '.') {
+ s++;
+ int count = 0;
+
+ // Read up to 6 digits (microseconds).
+ while (*s && isdigit(*s)) {
+ if (++count < 7) {
+ fractional_seconds = fractional_seconds*10 + (*s - '0');
+ }
+ s++;
+ }
+
+ for (; count < 6; count++) {
+ fractional_seconds *= 10;
+ }
+ }
+
+ ts->tv_usec = fractional_seconds;
+ return s;
+}
+
#endif
diff --git a/libc/bionic/strtotimeval.c b/libc/bionic/strtotimeval.c
deleted file mode 100644
index 195381b..0000000
--- a/libc/bionic/strtotimeval.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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
- * COPYRIGHT OWNER OR CONTRIBUTORS 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.
- */
-#include <ctype.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <sys/time.h>
-
-char * strtotimeval(const char *str, struct timeval *ts) {
- char *s;
- long fs = 0; /* fractional seconds */
-
- ts->tv_sec = strtoumax(str, &s, 10);
-
- if (*s == '.') {
- s++;
- int count = 0;
-
- /* read up to 6 digits (microseconds) */
- while (*s && isdigit(*s)) {
- if (++count < 7) {
- fs = fs*10 + (*s - '0');
- }
- s++;
- }
-
- for (; count < 6; count++) {
- fs *= 10;
- }
- }
-
- ts->tv_usec = fs;
- return s;
-}
diff --git a/libc/include/time.h b/libc/include/time.h
index 3f2047c..0f86fd3 100644
--- a/libc/include/time.h
+++ b/libc/include/time.h
@@ -61,8 +61,6 @@
extern time_t time(time_t*);
extern int nanosleep(const struct timespec*, struct timespec*);
-extern char* strtotimeval(const char*, struct timeval*);
-
extern char* asctime(const struct tm*);
extern char* asctime_r(const struct tm*, char*);
diff --git a/libc/stdio/vfprintf.c b/libc/stdio/vfprintf.c
index b101145..efc8fd0 100644
--- a/libc/stdio/vfprintf.c
+++ b/libc/stdio/vfprintf.c
@@ -51,7 +51,35 @@
#include "local.h"
#include "fvwrite.h"
-static void __find_arguments(const char *fmt0, va_list ap, va_list **argtable,
+union arg {
+ int intarg;
+ unsigned int uintarg;
+ long longarg;
+ unsigned long ulongarg;
+ long long longlongarg;
+ unsigned long long ulonglongarg;
+ ptrdiff_t ptrdiffarg;
+ size_t sizearg;
+ size_t ssizearg;
+ intmax_t intmaxarg;
+ uintmax_t uintmaxarg;
+ void *pvoidarg;
+ char *pchararg;
+ signed char *pschararg;
+ short *pshortarg;
+ int *pintarg;
+ long *plongarg;
+ long long *plonglongarg;
+ ptrdiff_t *pptrdiffarg;
+ size_t *pssizearg;
+ intmax_t *pintmaxarg;
+#ifdef FLOATING_POINT
+ double doublearg;
+ long double longdoublearg;
+#endif
+};
+
+static int __find_arguments(const char *fmt0, va_list ap, union arg **argtable,
size_t *argtablesiz);
static int __grow_type_table(unsigned char **typetable, int *tablesize);
@@ -169,13 +197,13 @@
int
__vfprintf(FILE *fp, const char *fmt0, __va_list ap)
{
- char *fmt; /* format string */
- int ch; /* character from fmt */
- int n, m, n2; /* handy integers (short term usage) */
- char *cp; /* handy char pointer (short term usage) */
- char *cp_free = NULL; /* BIONIC: copy of cp to be freed after usage */
- struct __siov *iovp;/* for PRINT macro */
- int flags; /* flags as above */
+ char *fmt; /* format string */
+ int ch; /* character from fmt */
+ int n, m, n2; /* handy integers (short term usage) */
+ char *cp; /* handy char pointer (short term usage) */
+ char *cp_free = NULL; /* BIONIC: copy of cp to be freed after usage */
+ struct __siov *iovp; /* for PRINT macro */
+ int flags; /* flags as above */
int ret; /* return value accumulator */
int width; /* width from format (%8d), or 0 */
int prec; /* precision from format (%.3d), or -1 */
@@ -203,8 +231,8 @@
struct __siov iov[NIOV];/* ... and individual io vectors */
char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
char ox[2]; /* space for 0x hex-prefix */
- va_list *argtable; /* args, built due to positional arg */
- va_list statargtable[STATIC_ARG_TBL_SIZE];
+ union arg *argtable; /* args, built due to positional arg */
+ union arg statargtable[STATIC_ARG_TBL_SIZE];
size_t argtablesiz;
int nextarg; /* 1-based argument index */
va_list orgap; /* original argument pointer */
@@ -303,8 +331,8 @@
* argument (and arguments must be gotten sequentially).
*/
#define GETARG(type) \
- (((argtable != NULL) ? (void)(ap = argtable[nextarg]) : (void)0), \
- nextarg++, va_arg(ap, type))
+ ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
+ (nextarg++, va_arg(ap, type)))
_SET_ORIENTATION(fp, -1);
/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
@@ -548,15 +576,16 @@
size = expt;
if (prec || flags & ALT)
size += prec + 1;
- } else /* "0.X" */
+ } else { /* "0.X" */
size = prec + 2;
+ }
} else if (expt >= ndig) { /* fixed g fmt */
size = expt;
if (flags & ALT)
++size;
- } else
- size = ndig + (expt > 0 ?
- 1 : 2 - expt);
+ } else {
+ size = ndig + (expt > 0 ? 1 : 2 - expt);
+ }
if (softsign)
sign = '-';
@@ -624,10 +653,12 @@
size = p - cp;
if (size > prec)
size = prec;
- } else
+ } else {
size = prec;
- } else
+ }
+ } else {
size = strlen(cp);
+ }
sign = '\0';
break;
case 'U':
@@ -793,11 +824,13 @@
PRINT(ox, 2);
if (_double) {
PRINT(cp, ndig-1);
- } else /* 0.[0..] */
+ } else {/* 0.[0..] */
/* __dtoa irregularity */
PAD(ndig - 1, zeroes);
- } else /* XeYYY */
+ }
+ } else { /* XeYYY */
PRINT(cp, 1);
+ }
PRINT(expstr, expsize);
}
}
@@ -874,15 +907,15 @@
* used since we are attempting to make snprintf thread safe, and alloca is
* problematic since we have nested functions..)
*/
-static void
-__find_arguments(const char *fmt0, va_list ap, va_list **argtable,
+static int
+__find_arguments(const char *fmt0, va_list ap, union arg **argtable,
size_t *argtablesiz)
{
- char *fmt; /* format string */
- int ch; /* character from fmt */
- int n, n2; /* handy integer (short term usage) */
- char *cp; /* handy char pointer (short term usage) */
- int flags; /* flags as above */
+ char *fmt; /* format string */
+ int ch; /* character from fmt */
+ int n, n2; /* handy integer (short term usage) */
+ char *cp; /* handy char pointer (short term usage) */
+ int flags; /* flags as above */
unsigned char *typetable; /* table of types */
unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
int tablesize; /* current size of type table */
@@ -1105,86 +1138,89 @@
* Build the argument table.
*/
if (tablemax >= STATIC_ARG_TBL_SIZE) {
- *argtablesiz = sizeof (va_list) * (tablemax + 1);
- *argtable = (va_list *)mmap(NULL, *argtablesiz,
+ *argtablesiz = sizeof(union arg) * (tablemax + 1);
+ *argtable = mmap(NULL, *argtablesiz,
PROT_WRITE|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if (*argtable == MAP_FAILED)
+ return (-1);
}
#if 0
/* XXX is this required? */
- (*argtable) [0] = NULL;
+ (*argtable)[0].intarg = 0;
#endif
for (n = 1; n <= tablemax; n++) {
- va_copy((*argtable)[n], ap);
switch (typetable[n]) {
case T_UNUSED:
- (void) va_arg(ap, int);
+ (*argtable)[n].intarg = va_arg(ap, int);
break;
case T_SHORT:
- (void) va_arg(ap, int);
+ (*argtable)[n].intarg = va_arg(ap, int);
break;
case T_U_SHORT:
- (void) va_arg(ap, int);
+ (*argtable)[n].intarg = va_arg(ap, int);
break;
case TP_SHORT:
- (void) va_arg(ap, short *);
+ (*argtable)[n].pshortarg = va_arg(ap, short *);
break;
case T_INT:
- (void) va_arg(ap, int);
+ (*argtable)[n].intarg = va_arg(ap, int);
break;
case T_U_INT:
- (void) va_arg(ap, unsigned int);
+ (*argtable)[n].uintarg = va_arg(ap, unsigned int);
break;
case TP_INT:
- (void) va_arg(ap, int *);
+ (*argtable)[n].pintarg = va_arg(ap, int *);
break;
case T_LONG:
- (void) va_arg(ap, long);
+ (*argtable)[n].longarg = va_arg(ap, long);
break;
case T_U_LONG:
- (void) va_arg(ap, unsigned long);
+ (*argtable)[n].ulongarg = va_arg(ap, unsigned long);
break;
case TP_LONG:
- (void) va_arg(ap, long *);
+ (*argtable)[n].plongarg = va_arg(ap, long *);
break;
case T_LLONG:
- (void) va_arg(ap, long long);
+ (*argtable)[n].longlongarg = va_arg(ap, long long);
break;
case T_U_LLONG:
- (void) va_arg(ap, unsigned long long);
+ (*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long);
break;
case TP_LLONG:
- (void) va_arg(ap, long long *);
+ (*argtable)[n].plonglongarg = va_arg(ap, long long *);
break;
+#ifdef FLOATING_POINT
case T_DOUBLE:
- (void) va_arg(ap, double);
+ (*argtable)[n].doublearg = va_arg(ap, double);
break;
case T_LONG_DOUBLE:
- (void) va_arg(ap, long double);
+ (*argtable)[n].longdoublearg = va_arg(ap, long double);
break;
+#endif
case TP_CHAR:
- (void) va_arg(ap, char *);
+ (*argtable)[n].pchararg = va_arg(ap, char *);
break;
case TP_VOID:
- (void) va_arg(ap, void *);
+ (*argtable)[n].pvoidarg = va_arg(ap, void *);
break;
case T_PTRINT:
- (void) va_arg(ap, ptrdiff_t);
+ (*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t);
break;
case TP_PTRINT:
- (void) va_arg(ap, ptrdiff_t *);
+ (*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t *);
break;
case T_SIZEINT:
- (void) va_arg(ap, size_t);
+ (*argtable)[n].sizearg = va_arg(ap, size_t);
break;
case T_SSIZEINT:
- (void) va_arg(ap, ssize_t);
+ (*argtable)[n].ssizearg = va_arg(ap, ssize_t);
break;
case TP_SSIZEINT:
- (void) va_arg(ap, ssize_t *);
+ (*argtable)[n].pssizearg = va_arg(ap, ssize_t *);
break;
case TP_MAXINT:
- (void) va_arg(ap, intmax_t *);
+ (*argtable)[n].intmaxarg = va_arg(ap, intmax_t);
break;
}
}
@@ -1193,6 +1229,7 @@
munmap(typetable, *argtablesiz);
typetable = NULL;
}
+ return (0);
}
/*
@@ -1205,24 +1242,24 @@
int newsize = *tablesize * 2;
if (*tablesize == STATIC_ARG_TBL_SIZE) {
- *typetable = (unsigned char *)mmap(NULL,
- sizeof (unsigned char) * newsize, PROT_WRITE|PROT_READ,
+ *typetable = mmap(NULL, newsize, PROT_WRITE|PROT_READ,
MAP_ANON|MAP_PRIVATE, -1, 0);
- /* XXX unchecked */
+ if (*typetable == MAP_FAILED)
+ return (-1);
memcpy( *typetable, oldtable, *tablesize);
} else {
- unsigned char *new = (unsigned char *)mmap(NULL,
- sizeof (unsigned char) * newsize, PROT_WRITE|PROT_READ,
+ unsigned char *new = mmap(NULL, newsize, PROT_WRITE|PROT_READ,
MAP_ANON|MAP_PRIVATE, -1, 0);
+ if (new == MAP_FAILED)
+ return (-1);
memmove(new, *typetable, *tablesize);
munmap(*typetable, *tablesize);
*typetable = new;
- /* XXX unchecked */
}
memset(*typetable + *tablesize, T_UNUSED, (newsize - *tablesize));
*tablesize = newsize;
- return(0);
+ return (0);
}
@@ -1256,7 +1293,7 @@
} else
*sign = '\000';
digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
- if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
+ if ((ch != 'g' && ch != 'G') || flags & ALT) {/* Print trailing zeros */
bp = digits + ndigits;
if (ch == 'f') {
if (*digits == '0' && value)
@@ -1283,8 +1320,7 @@
if (exp < 0) {
exp = -exp;
*p++ = '-';
- }
- else
+ } else
*p++ = '+';
t = expbuf + MAXEXP;
if (exp > 9) {
@@ -1292,9 +1328,9 @@
*--t = to_char(exp % 10);
} while ((exp /= 10) > 9);
*--t = to_char(exp);
- for (; t < expbuf + MAXEXP; *p++ = *t++);
- }
- else {
+ for (; t < expbuf + MAXEXP; *p++ = *t++)
+ /* nothing */;
+ } else {
*p++ = '0';
*p++ = to_char(exp);
}
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 8c1cef9..cc1fd85 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -297,6 +297,9 @@
snprintf(buf, sizeof(buf), "a_%g_b", 3.14);
EXPECT_STREQ("a_3.14_b", buf);
+
+ snprintf(buf, sizeof(buf), "%1$s %1$s", "print_me_twice");
+ EXPECT_STREQ("print_me_twice print_me_twice", buf);
}
TEST(stdio, snprintf_d_INT_MAX) {
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index c055769..26b7775 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -387,51 +387,3 @@
ASSERT_EQ(ESRCH, pthread_detach(tdd.thread_id));
#endif
}
-
-TEST(time, strtotimeval) {
-#if defined(__BIONIC__)
- struct timeval tv1;
- char* rest1 = strtotimeval("10.123456", &tv1);
- ASSERT_EQ(10, tv1.tv_sec);
- ASSERT_EQ(123456, tv1.tv_usec);
- ASSERT_EQ('\0', *rest1);
-
- // strtotimeval interprets the fractional part as microseconds and thus will
- // only consider its first 6 digits. Even so it should consume all valid
- // digits.
- struct timeval tv2;
- char* rest2 = strtotimeval(".1234567", &tv2);
- ASSERT_EQ(0, tv2.tv_sec);
- ASSERT_EQ(123456, tv2.tv_usec);
- ASSERT_EQ('\0', *rest2);
-
- struct timeval tv3;
- char* rest3 = strtotimeval("1.1a", &tv3);
- ASSERT_EQ(1, tv3.tv_sec);
- ASSERT_EQ(100000, tv3.tv_usec);
- ASSERT_EQ('a', *rest3);
-
- struct timeval tv4;
- char* rest4 = strtotimeval("a", &tv4);
- ASSERT_EQ(0, tv4.tv_sec);
- ASSERT_EQ(0, tv4.tv_usec);
- ASSERT_EQ('a', *rest4);
-
- struct timeval tv5;
- char* rest5 = strtotimeval("0", &tv5);
- ASSERT_EQ(0, tv5.tv_sec);
- ASSERT_EQ(0, tv5.tv_usec);
- ASSERT_EQ('\0', *rest5);
-
- // TODO: should we reject this case and just return '.'?
- struct timeval tv6;
- char* rest6 = strtotimeval(".", &tv6);
- ASSERT_EQ(0, tv6.tv_sec);
- ASSERT_EQ(0, tv6.tv_usec);
- ASSERT_EQ('\0', *rest6);
-
-#else // __BIONIC__
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-