summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libc/misc/time/time.c144
-rw-r--r--test/time/Makefile.in7
-rw-r--r--test/time/tst_wcsftime.c70
3 files changed, 143 insertions, 78 deletions
diff --git a/libc/misc/time/time.c b/libc/misc/time/time.c
index 347c8990c..a3fccb251 100644
--- a/libc/misc/time/time.c
+++ b/libc/misc/time/time.c
@@ -146,8 +146,24 @@
#include <bits/uClibc_uintmaxtostr.h>
#include <bits/uClibc_mutex.h>
-#ifdef __UCLIBC_HAS_WCHAR__
+#if defined __UCLIBC_HAS_WCHAR__ && (defined L_wcsftime || defined L_wcsftime_l)
#include <wchar.h>
+# define CHAR_T wchar_t
+# define UCHAR_T unsigned int
+# ifdef L_wcsftime
+# define strftime wcsftime
+# define L_strftime
+# if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
+# define strftime_l wcsftime_l
+# endif
+# endif
+# ifdef L_wcsftime_l
+# define strftime_l wcsftime_l
+# define L_strftime_l
+# endif
+#else
+# define CHAR_T char
+# define UCHAR_T unsigned char
#endif
#ifndef __isleap
@@ -787,12 +803,13 @@ time_t timegm(struct tm *timeptr)
#endif
/**********************************************************************/
-#if defined(L_strftime) || defined(L_strftime_l)
+#if defined(L_strftime) || defined(L_strftime_l) \
+ || defined(L_wcsftime) || defined(L_wcsftime_l)
#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
-size_t strftime(char *__restrict s, size_t maxsize,
- const char *__restrict format,
+size_t strftime(CHAR_T *__restrict s, size_t maxsize,
+ const CHAR_T *__restrict format,
const struct tm *__restrict timeptr)
{
return strftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
@@ -990,29 +1007,58 @@ static int load_field(int k, const struct tm *__restrict timeptr)
return r;
}
+#if defined __UCLIBC_HAS_WCHAR__ && (defined L_wcsftime || defined L_wcsftime_l)
+static wchar_t* fmt_to_wc_1(const char *src)
+{
+ mbstate_t mbstate;
+ size_t src_len = strlen(src);
+ wchar_t *dest = (wchar_t *)malloc((src_len + 1) * sizeof(wchar_t));
+ if (dest == NULL)
+ return NULL;
+ mbstate.__mask = 0;
+ if (mbsrtowcs(dest, &src, src_len + 1, &mbstate) == (size_t) -1) {
+ free(dest);
+ return NULL;
+ }
+ return dest;
+}
+# define fmt_to_wc(dest, src) \
+ dest = alloc[++allocno] = fmt_to_wc_1(src)
+# define to_wc(dest, src) \
+ dest = fmt_to_wc_1(src)
+#else
+# define fmt_to_wc(dest, src) (dest) = (src)
+# define to_wc(dest, src) (dest) = (src)
+#endif
+
#define MAX_PUSH 4
#ifdef __UCLIBC_MJN3_ONLY__
#warning TODO: Check multibyte format string validity.
#endif
-size_t __XL_NPP(strftime)(char *__restrict s, size_t maxsize,
- const char *__restrict format,
+size_t __XL_NPP(strftime)(CHAR_T *__restrict s, size_t maxsize,
+ const CHAR_T *__restrict format,
const struct tm *__restrict timeptr __LOCALE_PARAM )
{
long tzo;
- register const char *p;
- register const char *o;
+ register const CHAR_T *p;
+ const CHAR_T *o;
+ const char *ccp;
#ifndef __UCLIBC_HAS_TM_EXTENSIONS__
const rule_struct *rsp;
#endif
- const char *stack[MAX_PUSH];
+ const CHAR_T *stack[MAX_PUSH];
+#if defined __UCLIBC_HAS_WCHAR__ && (defined L_wcsftime || defined L_wcsftime_l)
+ const CHAR_T *alloc[MAX_PUSH];
+ int allocno = -1;
+#endif
size_t count;
size_t o_count;
int field_val = 0, i = 0, j, lvl;
int x[3]; /* wday, yday, year */
int isofm, days;
- char buf[__UIM_BUFLEN_LONG];
+ char buf[__UIM_BUFLEN_LONG] = {0,};
unsigned char mod;
unsigned char code;
@@ -1037,7 +1083,7 @@ LOOP:
}
o_count = 1;
- if ((*(o = p) == '%') && (*++p != '%')) {
+ if ((*(o = (CHAR_T *)p) == '%') && (*++p != '%')) {
o_count = 2;
mod = ILLEGAL_SPEC;
if ((*p == 'O') || (*p == 'E')) { /* modifier */
@@ -1062,31 +1108,33 @@ LOOP:
}
stack[lvl++] = ++p;
if ((code &= 0xf) < 8) {
- p = ((const char *) spec) + STACKED_STRINGS_START + code;
- p += *((unsigned char *)p);
+ ccp = (const char *)(spec + STACKED_STRINGS_START + code);
+ ccp += *ccp;
+ fmt_to_wc(p, ccp);
goto LOOP;
}
- p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
- + (code & 7);
+ ccp = (const char *)spec + STACKED_STRINGS_NL_ITEM_START + (code & 7);
+ fmt_to_wc(p, ccp);
#ifdef ENABLE_ERA_CODE
if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
- && (*(o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
+ && (*(ccp = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
(int)(((unsigned char *)p)[4]))
__LOCALE_ARG
)))
) {
- p = o;
+ fmt_to_wc(p, ccp);
goto LOOP;
}
#endif
- p = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
+ ccp = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
(int)(*((unsigned char *)p)))
__LOCALE_ARG
);
+ fmt_to_wc(p, ccp);
goto LOOP;
}
- o = ((const char *) spec) + 26; /* set to "????" */
+ ccp = (const char *)(spec + 26); /* set to "????" */
if ((code & MASK_SPEC) == CALC_SPEC) {
if (*p == 's') {
@@ -1101,15 +1149,16 @@ LOOP:
goto OUTPUT;
}
#ifdef TIME_T_IS_UNSIGNED
- o = _uintmaxtostr(buf + sizeof(buf) - 1,
+ ccp = _uintmaxtostr(buf + sizeof(buf) - 1,
(uintmax_t) t,
10, __UIM_DECIMAL);
#else
- o = _uintmaxtostr(buf + sizeof(buf) - 1,
+ ccp = _uintmaxtostr(buf + sizeof(buf) - 1,
(uintmax_t) t,
-10, __UIM_DECIMAL);
#endif
o_count = sizeof(buf);
+ fmt_to_wc(o, ccp);
goto OUTPUT;
} else if (((*p) | 0x20) == 'z') { /* 'z' or 'Z' */
@@ -1144,7 +1193,7 @@ LOOP:
#endif
if (*p == 'Z') {
- o = RSP_TZNAME;
+ ccp = RSP_TZNAME;
#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
/* Sigh... blasted glibc extensions. Of course we can't
* count on the pointer being valid. Best we can do is
@@ -1155,17 +1204,18 @@ LOOP:
* case... although it always seems to use the embedded
* tm_gmtoff value. What we'll do instead is treat the
* timezone name as unknown/invalid and return "???". */
- if (!o) {
- o = "???";
+ if (!ccp) {
+ ccp = (const char *)(spec + 27); /* "???" */
}
#endif
- assert(o != NULL);
+ assert(ccp != NULL);
#if 0
- if (!o) { /* PARANOIA */
- o = spec+30; /* empty string */
+ if (!ccp) { /* PARANOIA */
+ ccp = spec+30; /* empty string */
}
#endif
o_count = SIZE_MAX;
+ fmt_to_wc(o, ccp);
#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
goto OUTPUT;
#endif
@@ -1264,17 +1314,19 @@ ISO_LOOP:
if ((code & MASK_SPEC) == STRING_SPEC) {
o_count = SIZE_MAX;
field_val += spec[STRINGS_NL_ITEM_START + (code & 0xf)];
- o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME, field_val) __LOCALE_ARG);
+ ccp = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME, field_val) __LOCALE_ARG);
+ fmt_to_wc(o, ccp);
} else {
o_count = ((i >> 1) & 3) + 1;
- o = buf + o_count;
+ ccp = buf + o_count;
do {
- *(char *)(--o) = '0' + (field_val % 10);
+ *(char *)(--ccp) = '0' + (field_val % 10);
field_val /= 10;
- } while (o > buf);
+ } while (ccp > buf);
if (*buf == '0') {
*buf = ' ' + (i & 16);
}
+ fmt_to_wc(o, ccp);
}
}
@@ -1285,6 +1337,10 @@ OUTPUT:
--o_count;
--count;
}
+#if defined __UCLIBC_HAS_WCHAR__ && (defined L_wcsftime || defined L_wcsftime_l)
+ if (allocno >= 0)
+ free((void *)alloc[allocno--]);
+#endif
goto LOOP;
}
# ifdef L_strftime_l
@@ -2444,31 +2500,9 @@ DONE:
#endif
/**********************************************************************/
-#if defined(L_wcsftime) || defined(L_wcsftime_l)
-
-#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
-
-size_t wcsftime(wchar_t *__restrict s, size_t maxsize,
- const wchar_t *__restrict format,
- const struct tm *__restrict timeptr)
-{
- return wcsftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
-}
-
-#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+#if (defined(L_wcsftime) || defined(L_wcsftime_l))
-size_t __XL_NPP(wcsftime)(wchar_t *__restrict s, size_t maxsize,
- const wchar_t *__restrict format,
- const struct tm *__restrict timeptr __LOCALE_PARAM )
-{
-#warning wcsftime always fails
- return 0; /* always fail */
-}
-#ifdef L_wcsftime_l
-libc_hidden_def(wcsftime_l)
-#endif
-
-#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+/* Implemented via strftime / strftime_l wchar_t variants */
#endif
/**********************************************************************/
diff --git a/test/time/Makefile.in b/test/time/Makefile.in
index 02c8d910c..bb11e18bd 100644
--- a/test/time/Makefile.in
+++ b/test/time/Makefile.in
@@ -5,8 +5,13 @@ TESTS_DISABLED := bug-asctime bug-asctime_r time tst-mktime2 tst-posixtz \
tst-strftime tst-strptime tst-timezone
ifneq ($(UCLIBC_HAS_XLOCALE),y)
-TESTS_DISABLED += tst-ftime_l tst_wcsftime
+TESTS_DISABLED += tst-ftime_l
+endif
+
+ifneq ($(UCLIBC_HAS_WCHAR)$(UCLIBC_HAS_LOCALE),yy)
+TESTS_DISABLED += tst_wcsftime
endif
CFLAGS_tst-strptime2 := -std=c99
DODIFF_futimens1 := 1
+DODIFF_tst_wcsftime := 1
diff --git a/test/time/tst_wcsftime.c b/test/time/tst_wcsftime.c
index 6e35f1e6f..5631d952a 100644
--- a/test/time/tst_wcsftime.c
+++ b/test/time/tst_wcsftime.c
@@ -1,39 +1,65 @@
#include <stdio.h>
#include <time.h>
#include <features.h>
-#ifdef __UCLIBC_HAS_WCHAR__
#include <wchar.h>
+#include <locale.h>
+
+#define NUM_OF_DATES 7
+#define NUM_OF_LOCALES 3
+#define BUF_SIZE 256
int
-main (int argc, char *argv[])
+main (void)
{
- wchar_t buf[200];
- time_t t;
+ wchar_t buf[BUF_SIZE];
struct tm *tp;
- int result = 0;
+ time_t time_list[NUM_OF_DATES] = {
+ 500, 68200000, 694223999,
+ 694224000, 704900000, 705000000,
+ 705900000
+ };
+ char *locale_list[NUM_OF_LOCALES] = {
+ "C",
+ "fr_FR.ISO-8859-1",
+ "ja_JP.UTF-8"
+ };
+ int result = 0, ddd, lll;
size_t n;
- time (&t);
- tp = gmtime (&t);
+ for (lll = 0; lll < NUM_OF_LOCALES; lll++) {
+ printf ("\nUsing locale: %s\n", locale_list[lll]);
+ char* set = setlocale(LC_ALL, locale_list[lll]);
+ if (set == NULL) {
+ printf ("FAILED!\n\n");
+ continue;
+ } else
+ printf ("\n");
+ for (ddd = 0; ddd < NUM_OF_DATES; ddd++) {
+ tp = localtime(&time_list[ddd]);
+ printf ("%ld corresponds to ", time_list[ddd]);
- n = wcsftime (buf, sizeof (buf) / sizeof (buf[0]),
- L"%H:%M:%S %Y-%m-%d\n", tp);
- if (n != 21)
- result = 1;
+ n = wcsftime (buf, sizeof (buf) / sizeof (buf[0]),
+ L"%H:%M:%S %Y-%m-%d%n", tp);
+ if (n != 21) {
+ result = 1;
+ printf ("FAILED!\n");
+ }
- wprintf (L"It is now %ls", buf);
+ printf ("%ls", buf);
- wcsftime (buf, sizeof (buf) / sizeof (buf[0]), L"%A\n", tp);
+ wcsftime (buf, sizeof (buf) / sizeof (buf[0]),
+ L"%tor, as %%D %%T: %D %T%n", tp);
+ printf ("%ls", buf);
- wprintf (L"The weekday is %ls", buf);
+ wcsftime (buf, sizeof (buf) / sizeof (buf[0]), L"%A (%a)%n", tp);
+ printf ("The weekday was %ls", buf);
+ wcsftime (buf, sizeof (buf) / sizeof (buf[0]), L"%B (%b) %Y%n", tp);
+ /* glibc bug? forgets aigu from french february février
+ * See s/printf (/wprintf (L/g */
+ //wprintf (L"Month was %ls", buf);
+ printf ("Month was %ls", buf);
+ }
+ }
return result;
}
-
-#else
-int main(void)
-{
- puts("Test requires WCHAR support; skipping");
- return 0;
-}
-#endif