diff options
| -rw-r--r-- | libc/misc/time/time.c | 144 | ||||
| -rw-r--r-- | test/time/Makefile.in | 7 | ||||
| -rw-r--r-- | test/time/tst_wcsftime.c | 70 | 
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 a2613784b..83bc07dbb 100644 --- a/test/time/Makefile.in +++ b/test/time/Makefile.in @@ -9,8 +9,13 @@ TESTS_DISABLED += tst-timerfd  endif  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  | 
