|
@@ -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];
|
|
|
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')) {
|
|
@@ -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)
|
|
|
- && (*(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;
|
|
|
+ ccp = (const char *)(spec + 26);
|
|
|
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') {
|
|
|
|
|
@@ -1144,7 +1193,7 @@ LOOP:
|
|
|
#endif
|
|
|
|
|
|
if (*p == 'Z') {
|
|
|
- o = RSP_TZNAME;
|
|
|
+ ccp = RSP_TZNAME;
|
|
|
#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
|
|
|
|
|
|
* 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) {
|
|
|
- o = spec+30;
|
|
|
+ if (!ccp) {
|
|
|
+ ccp = spec+30;
|
|
|
}
|
|
|
#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
|
|
|
+#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;
|
|
|
-}
|
|
|
-#ifdef L_wcsftime_l
|
|
|
-libc_hidden_def(wcsftime_l)
|
|
|
-#endif
|
|
|
-
|
|
|
-#endif
|
|
|
+
|
|
|
|
|
|
#endif
|
|
|
|