diff options
| author | Waldemar Brodkorb <wbx@openadk.org> | 2014-12-01 20:47:00 +0100 | 
|---|---|---|
| committer | Waldemar Brodkorb <wbx@openadk.org> | 2014-12-01 20:47:00 +0100 | 
| commit | c37bec8802893e7cb3e8bfda8a6f7c61de5f231d (patch) | |
| tree | 1e7a838ef97617b95ec353eb4b1203d56accc74b /libc/misc/time/time.c | |
| parent | 19a696d410c8f2839ad4617ad8446fc3781ae684 (diff) | |
| parent | b36422960466777495933ed1eb50befd1c34e9a9 (diff) | |
Merge remote-tracking branch 'origin/upstream'
Diffstat (limited to 'libc/misc/time/time.c')
| -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  /**********************************************************************/ | 
