diff options
Diffstat (limited to 'libc/misc/time')
-rw-r--r-- | libc/misc/time/time.c | 144 |
1 files changed, 89 insertions, 55 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 /**********************************************************************/ |