mailing list of musl libc
 help / color / mirror / code / Atom feed
* [PATCH] implement strftime GNU extension padding specifiers '_', '-' and '0'
@ 2016-11-22  8:29 Timo Teräs
  2016-12-20 20:13 ` Rich Felker
  2017-12-09 22:56 ` Rich Felker
  0 siblings, 2 replies; 8+ messages in thread
From: Timo Teräs @ 2016-11-22  8:29 UTC (permalink / raw)
  To: musl; +Cc: Timo Teräs

---
For review. GNU and most BSDs seem to implement these extensions.

This applies them to numbers only. There might be few cases where this
could be applied more, but I think covers most of the uses. Is there any
test suite I could verify this against?

 src/time/strftime.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/src/time/strftime.c b/src/time/strftime.c
index e103e02..14fe6f5 100644
--- a/src/time/strftime.c
+++ b/src/time/strftime.c
@@ -48,12 +48,12 @@ static int week_num(const struct tm *tm)
 const char *__tm_to_tzname(const struct tm *);
 size_t __strftime_l(char *restrict, size_t, const char *restrict, const struct tm *restrict, locale_t);
 
-const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc)
+const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc, int pad)
 {
 	nl_item item;
 	long long val;
 	const char *fmt = "-";
-	int width = 2;
+	int width = 2, def_pad = '0';
 
 	switch (f) {
 	case 'a':
@@ -79,15 +79,14 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *
 	case 'C':
 		val = (1900LL+tm->tm_year) / 100;
 		goto number;
+	case 'e':
+		def_pad = '_';
 	case 'd':
 		val = tm->tm_mday;
 		goto number;
 	case 'D':
 		fmt = "%m/%d/%y";
 		goto recu_strftime;
-	case 'e':
-		*l = snprintf(*s, sizeof *s, "%2d", tm->tm_mday);
-		return *s;
 	case 'F':
 		fmt = "%Y-%m-%d";
 		goto recu_strftime;
@@ -200,7 +199,12 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *
 		return 0;
 	}
 number:
-	*l = snprintf(*s, sizeof *s, "%0*lld", width, val);
+	switch (pad ? pad : def_pad) {
+	case '-': *l = snprintf(*s, sizeof *s, "%lld", val); break;
+	case '_': *l = snprintf(*s, sizeof *s, "%*lld", width, val); break;
+	case '0':
+	default:  *l = snprintf(*s, sizeof *s, "%0*lld", width, val); break;
+	}
 	return *s;
 nl_strcat:
 	fmt = __nl_langinfo_l(item, loc);
@@ -221,7 +225,7 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
 	char buf[100];
 	char *p;
 	const char *t;
-	int plus;
+	int pad, plus;
 	unsigned long width;
 	for (l=0; l<n; f++) {
 		if (!*f) {
@@ -233,6 +237,8 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
 			continue;
 		}
 		f++;
+		pad = 0;
+		if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
 		if ((plus = (*f == '+'))) f++;
 		width = strtoul(f, &p, 10);
 		if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
@@ -242,7 +248,7 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
 		}
 		f = p;
 		if (*f == 'E' || *f == 'O') f++;
-		t = __strftime_fmt_1(&buf, &k, *f, tm, loc);
+		t = __strftime_fmt_1(&buf, &k, *f, tm, loc, pad);
 		if (!t) break;
 		if (width) {
 			for (; *t=='+' || *t=='-' || (*t=='0'&&t[1]); t++, k--);
-- 
2.10.2



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] implement strftime GNU extension padding specifiers '_', '-' and '0'
  2016-11-22  8:29 [PATCH] implement strftime GNU extension padding specifiers '_', '-' and '0' Timo Teräs
@ 2016-12-20 20:13 ` Rich Felker
  2016-12-21  0:27   ` Felix Janda
  2017-12-09 22:56 ` Rich Felker
  1 sibling, 1 reply; 8+ messages in thread
From: Rich Felker @ 2016-12-20 20:13 UTC (permalink / raw)
  To: musl

On Tue, Nov 22, 2016 at 10:29:08AM +0200, Timo Teräs wrote:
> ---
> For review. GNU and most BSDs seem to implement these extensions.

From what I can tell, only FreeBSD does and they call it a GNU
extension. OpenBSD does not have them at all, and also lacks the
POSIX-mandated width specifiers. Not sure if FreeBSD has those.

> This applies them to numbers only. There might be few cases where this
> could be applied more, but I think covers most of the uses. Is there any
> test suite I could verify this against?
> 
>  src/time/strftime.c | 22 ++++++++++++++--------
>  1 file changed, 14 insertions(+), 8 deletions(-)

I'm not aware of any test suite. Test cases for strftime (standard
features especially -- to make sure none of them are broken by
changes) would be really nice to have in libc-test.

Overall I'm not too excited about adding nonstandard extensions like
this unless there's indication that there's some good chance of
consensus among implementations. They have the potential to conflict
with future standard requirements and there's no reliable way to test
for them at build time (unlike nonstd functions where you can at least
check if the symbol is present). So the main thing I'd like before we
move forward with this is research into whether other implementations
support these already, and if not, what their attitudes towards it
are. OTOH if the BSDs aren't even going to adopt the POSIX
requirements then maybe they're not terribly relevant here.

As we discussed on IRC, python documents that these are nonstandard
and depend on your system's strftime, so adding them just for python
does not seem justified.

I'm not saying no to this outright but I think it should have some
more thought before deciding one way or the other.

Rich

> diff --git a/src/time/strftime.c b/src/time/strftime.c
> index e103e02..14fe6f5 100644
> --- a/src/time/strftime.c
> +++ b/src/time/strftime.c
> @@ -48,12 +48,12 @@ static int week_num(const struct tm *tm)
>  const char *__tm_to_tzname(const struct tm *);
>  size_t __strftime_l(char *restrict, size_t, const char *restrict, const struct tm *restrict, locale_t);
>  
> -const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc)
> +const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc, int pad)
>  {
>  	nl_item item;
>  	long long val;
>  	const char *fmt = "-";
> -	int width = 2;
> +	int width = 2, def_pad = '0';
>  
>  	switch (f) {
>  	case 'a':
> @@ -79,15 +79,14 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *
>  	case 'C':
>  		val = (1900LL+tm->tm_year) / 100;
>  		goto number;
> +	case 'e':
> +		def_pad = '_';
>  	case 'd':
>  		val = tm->tm_mday;
>  		goto number;
>  	case 'D':
>  		fmt = "%m/%d/%y";
>  		goto recu_strftime;
> -	case 'e':
> -		*l = snprintf(*s, sizeof *s, "%2d", tm->tm_mday);
> -		return *s;
>  	case 'F':
>  		fmt = "%Y-%m-%d";
>  		goto recu_strftime;
> @@ -200,7 +199,12 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *
>  		return 0;
>  	}
>  number:
> -	*l = snprintf(*s, sizeof *s, "%0*lld", width, val);
> +	switch (pad ? pad : def_pad) {
> +	case '-': *l = snprintf(*s, sizeof *s, "%lld", val); break;
> +	case '_': *l = snprintf(*s, sizeof *s, "%*lld", width, val); break;
> +	case '0':
> +	default:  *l = snprintf(*s, sizeof *s, "%0*lld", width, val); break;
> +	}
>  	return *s;
>  nl_strcat:
>  	fmt = __nl_langinfo_l(item, loc);
> @@ -221,7 +225,7 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
>  	char buf[100];
>  	char *p;
>  	const char *t;
> -	int plus;
> +	int pad, plus;
>  	unsigned long width;
>  	for (l=0; l<n; f++) {
>  		if (!*f) {
> @@ -233,6 +237,8 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
>  			continue;
>  		}
>  		f++;
> +		pad = 0;
> +		if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
>  		if ((plus = (*f == '+'))) f++;
>  		width = strtoul(f, &p, 10);
>  		if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
> @@ -242,7 +248,7 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
>  		}
>  		f = p;
>  		if (*f == 'E' || *f == 'O') f++;
> -		t = __strftime_fmt_1(&buf, &k, *f, tm, loc);
> +		t = __strftime_fmt_1(&buf, &k, *f, tm, loc, pad);
>  		if (!t) break;
>  		if (width) {
>  			for (; *t=='+' || *t=='-' || (*t=='0'&&t[1]); t++, k--);
> -- 
> 2.10.2


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] implement strftime GNU extension padding specifiers '_', '-' and '0'
  2016-12-20 20:13 ` Rich Felker
@ 2016-12-21  0:27   ` Felix Janda
  2016-12-21  3:20     ` Rich Felker
  2016-12-21  6:01     ` [PATCH] " Timo Teras
  0 siblings, 2 replies; 8+ messages in thread
From: Felix Janda @ 2016-12-21  0:27 UTC (permalink / raw)
  To: musl

Rich Felker wrote:
> On Tue, Nov 22, 2016 at 10:29:08AM +0200, Timo Teräs wrote:
> > ---
> > For review. GNU and most BSDs seem to implement these extensions.
> 
> From what I can tell, only FreeBSD does and they call it a GNU
> extension. OpenBSD does not have them at all, and also lacks the
> POSIX-mandated width specifiers. Not sure if FreeBSD has those.

Just to add one more data point: Solaris seems to support these
extensions since Solaris 11:

https://docs.oracle.com/cd/E36784_01/html/E36874/strftime-3c.html

Felix


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] implement strftime GNU extension padding specifiers '_', '-' and '0'
  2016-12-21  0:27   ` Felix Janda
@ 2016-12-21  3:20     ` Rich Felker
  2017-01-06  6:59       ` [PATCH v2] " Timo Teräs
  2016-12-21  6:01     ` [PATCH] " Timo Teras
  1 sibling, 1 reply; 8+ messages in thread
From: Rich Felker @ 2016-12-21  3:20 UTC (permalink / raw)
  To: musl

On Tue, Dec 20, 2016 at 07:27:30PM -0500, Felix Janda wrote:
> Rich Felker wrote:
> > On Tue, Nov 22, 2016 at 10:29:08AM +0200, Timo Teräs wrote:
> > > ---
> > > For review. GNU and most BSDs seem to implement these extensions.
> > 
> > From what I can tell, only FreeBSD does and they call it a GNU
> > extension. OpenBSD does not have them at all, and also lacks the
> > POSIX-mandated width specifiers. Not sure if FreeBSD has those.
> 
> Just to add one more data point: Solaris seems to support these
> extensions since Solaris 11:
> 
> https://docs.oracle.com/cd/E36784_01/html/E36874/strftime-3c.html

Thanks. That suggests some interest in common adoption. Unfortunately
it also includes the weird case-mapping ones that we hoped to omit.

Rich


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] implement strftime GNU extension padding specifiers '_', '-' and '0'
  2016-12-21  0:27   ` Felix Janda
  2016-12-21  3:20     ` Rich Felker
@ 2016-12-21  6:01     ` Timo Teras
  1 sibling, 0 replies; 8+ messages in thread
From: Timo Teras @ 2016-12-21  6:01 UTC (permalink / raw)
  To: Felix Janda; +Cc: musl

On Tue, 20 Dec 2016 19:27:30 -0500
Felix Janda <felix.janda@posteo.de> wrote:

> Rich Felker wrote:
> > On Tue, Nov 22, 2016 at 10:29:08AM +0200, Timo Teräs wrote:  
> > > ---
> > > For review. GNU and most BSDs seem to implement these
> > > extensions.  
> > 
> > From what I can tell, only FreeBSD does and they call it a GNU
> > extension. OpenBSD does not have them at all, and also lacks the
> > POSIX-mandated width specifiers. Not sure if FreeBSD has those.  
> 
> Just to add one more data point: Solaris seems to support these
> extensions since Solaris 11:
> 
> https://docs.oracle.com/cd/E36784_01/html/E36874/strftime-3c.html

Also supported in:

Mac OSX:
https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/strftime.3.html

DragonflyBSD:
https://www.dragonflybsd.org/cgi/web-man?command=strftime&section=3



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2] implement strftime GNU extension padding specifiers '_', '-' and '0'
  2016-12-21  3:20     ` Rich Felker
@ 2017-01-06  6:59       ` Timo Teräs
  0 siblings, 0 replies; 8+ messages in thread
From: Timo Teräs @ 2017-01-06  6:59 UTC (permalink / raw)
  To: musl; +Cc: Timo Teräs

---
v2: support these specifiers for recursive built format strings
such as '%F'

 src/time/strftime.c | 31 +++++++++++++++++++++----------
 1 file changed, 21 insertions(+), 10 deletions(-)

diff --git a/src/time/strftime.c b/src/time/strftime.c
index a3039204..733e4e28 100644
--- a/src/time/strftime.c
+++ b/src/time/strftime.c
@@ -46,9 +46,9 @@ static int week_num(const struct tm *tm)
 }
 
 const char *__tm_to_tzname(const struct tm *);
-size_t __strftime_l(char *restrict, size_t, const char *restrict, const struct tm *restrict, locale_t);
+static size_t __strftime_impl(char *restrict, size_t, const char *restrict, const struct tm *restrict, locale_t, int);
 
-const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc)
+const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc, int pad)
 {
 	nl_item item;
 	long long val;
@@ -79,15 +79,14 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *
 	case 'C':
 		val = (1900LL+tm->tm_year) / 100;
 		goto number;
+	case 'e':
+		pad = '_';
 	case 'd':
 		val = tm->tm_mday;
 		goto number;
 	case 'D':
 		fmt = "%m/%d/%y";
 		goto recu_strftime;
-	case 'e':
-		*l = snprintf(*s, sizeof *s, "%2d", tm->tm_mday);
-		return *s;
 	case 'F':
 		fmt = "%Y-%m-%d";
 		goto recu_strftime;
@@ -200,7 +199,12 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *
 		return 0;
 	}
 number:
-	*l = snprintf(*s, sizeof *s, "%0*lld", width, val);
+	switch (pad) {
+	case '-': *l = snprintf(*s, sizeof *s, "%lld", val); break;
+	case '_': *l = snprintf(*s, sizeof *s, "%*lld", width, val); break;
+	case '0':
+	default:  *l = snprintf(*s, sizeof *s, "%0*lld", width, val); break;
+	}
 	return *s;
 nl_strcat:
 	fmt = __nl_langinfo_l(item, loc);
@@ -210,18 +214,18 @@ string:
 nl_strftime:
 	fmt = __nl_langinfo_l(item, loc);
 recu_strftime:
-	*l = __strftime_l(*s, sizeof *s, fmt, tm, loc);
+	*l = __strftime_impl(*s, sizeof *s, fmt, tm, loc, pad);
 	if (!*l) return 0;
 	return *s;
 }
 
-size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm, locale_t loc)
+static size_t __strftime_impl(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm, locale_t loc, int def_pad)
 {
 	size_t l, k;
 	char buf[100];
 	char *p;
 	const char *t;
-	int plus;
+	int plus, pad;
 	unsigned long width;
 	for (l=0; l<n; f++) {
 		if (!*f) {
@@ -233,6 +237,8 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
 			continue;
 		}
 		f++;
+		pad = def_pad;
+		if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
 		if ((plus = (*f == '+'))) f++;
 		width = strtoul(f, &p, 10);
 		if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
@@ -242,7 +248,7 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
 		}
 		f = p;
 		if (*f == 'E' || *f == 'O') f++;
-		t = __strftime_fmt_1(&buf, &k, *f, tm, loc);
+		t = __strftime_fmt_1(&buf, &k, *f, tm, loc, pad);
 		if (!t) break;
 		if (width) {
 			for (; *t=='+' || *t=='-' || (*t=='0'&&t[1]); t++, k--);
@@ -267,6 +273,11 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
 	return 0;
 }
 
+size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm, locale_t loc)
+{
+	return __strftime_impl(s, n, f, tm, loc, '0');
+}
+
 size_t strftime(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm)
 {
 	return __strftime_l(s, n, f, tm, CURRENT_LOCALE);
-- 
2.11.0



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] implement strftime GNU extension padding specifiers '_', '-' and '0'
  2016-11-22  8:29 [PATCH] implement strftime GNU extension padding specifiers '_', '-' and '0' Timo Teräs
  2016-12-20 20:13 ` Rich Felker
@ 2017-12-09 22:56 ` Rich Felker
  2017-12-09 23:27   ` Rich Felker
  1 sibling, 1 reply; 8+ messages in thread
From: Rich Felker @ 2017-12-09 22:56 UTC (permalink / raw)
  To: musl

On Tue, Nov 22, 2016 at 10:29:08AM +0200, Timo Teräs wrote:
> ---
> For review. GNU and most BSDs seem to implement these extensions.
> 
> This applies them to numbers only. There might be few cases where this
> could be applied more, but I think covers most of the uses. Is there any
> test suite I could verify this against?

I'm reasonably conviced this doesn't break anything -- for now I just
did a test of all the standard formats before and after, with explicit
padding and width specifiers for the year ones specified to support
it, and didn't see any change in output. I'm not sure all of them are
right now, but they're no worse with the patch, so that's ok.

I do have some questions about inefficiency:

>  src/time/strftime.c | 22 ++++++++++++++--------
>  1 file changed, 14 insertions(+), 8 deletions(-)
> 
> diff --git a/src/time/strftime.c b/src/time/strftime.c
> index e103e02..14fe6f5 100644
> --- a/src/time/strftime.c
> +++ b/src/time/strftime.c
> @@ -48,12 +48,12 @@ static int week_num(const struct tm *tm)
>  const char *__tm_to_tzname(const struct tm *);
>  size_t __strftime_l(char *restrict, size_t, const char *restrict, const struct tm *restrict, locale_t);
>  
> -const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc)
> +const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc, int pad)
>  {
>  	nl_item item;
>  	long long val;
>  	const char *fmt = "-";
> -	int width = 2;
> +	int width = 2, def_pad = '0';
>  
>  	switch (f) {
>  	case 'a':
> @@ -79,15 +79,14 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *
>  	case 'C':
>  		val = (1900LL+tm->tm_year) / 100;
>  		goto number;
> +	case 'e':
> +		def_pad = '_';
>  	case 'd':
>  		val = tm->tm_mday;
>  		goto number;
>  	case 'D':
>  		fmt = "%m/%d/%y";
>  		goto recu_strftime;
> -	case 'e':
> -		*l = snprintf(*s, sizeof *s, "%2d", tm->tm_mday);
> -		return *s;

This looks like a nice change.

>  	case 'F':
>  		fmt = "%Y-%m-%d";
>  		goto recu_strftime;
> @@ -200,7 +199,12 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *
>  		return 0;
>  	}
>  number:
> -	*l = snprintf(*s, sizeof *s, "%0*lld", width, val);
> +	switch (pad ? pad : def_pad) {
> +	case '-': *l = snprintf(*s, sizeof *s, "%lld", val); break;
> +	case '_': *l = snprintf(*s, sizeof *s, "%*lld", width, val); break;
> +	case '0':
> +	default:  *l = snprintf(*s, sizeof *s, "%0*lld", width, val); break;
> +	}

This looks like gratuitous duplication of the call point; instead, the
format string can just vary, and there are only two possibilities:
%*lld and %0*lld. The '-' case can just be implemented by setting
width to 0.

>  	return *s;
>  nl_strcat:
>  	fmt = __nl_langinfo_l(item, loc);
> @@ -221,7 +225,7 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
>  	char buf[100];
>  	char *p;
>  	const char *t;
> -	int plus;
> +	int pad, plus;
>  	unsigned long width;
>  	for (l=0; l<n; f++) {
>  		if (!*f) {
> @@ -233,6 +237,8 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
>  			continue;
>  		}
>  		f++;
> +		pad = 0;
> +		if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
>  		if ((plus = (*f == '+'))) f++;

I think this is OK since POSIX leaves it unspecified what happens with
more than one flag character.

>  		width = strtoul(f, &p, 10);
>  		if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
> @@ -242,7 +248,7 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
>  		}
>  		f = p;
>  		if (*f == 'E' || *f == 'O') f++;
> -		t = __strftime_fmt_1(&buf, &k, *f, tm, loc);
> +		t = __strftime_fmt_1(&buf, &k, *f, tm, loc, pad);
>  		if (!t) break;
>  		if (width) {
>  			for (; *t=='+' || *t=='-' || (*t=='0'&&t[1]); t++, k--);
> -- 
> 2.10.2

If you're tired of working and waiting on this and just want me to
commit it as-is and make any improvements later, just let me know.
I'll try to adapt the (freeform, non-checking) tests I did into
something that can go into libc-test.

Rich


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] implement strftime GNU extension padding specifiers '_', '-' and '0'
  2017-12-09 22:56 ` Rich Felker
@ 2017-12-09 23:27   ` Rich Felker
  0 siblings, 0 replies; 8+ messages in thread
From: Rich Felker @ 2017-12-09 23:27 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 441 bytes --]

On Sat, Dec 09, 2017 at 05:56:50PM -0500, Rich Felker wrote:
> If you're tired of working and waiting on this and just want me to
> commit it as-is and make any improvements later, just let me know.
> I'll try to adapt the (freeform, non-checking) tests I did into
> something that can go into libc-test.

Attached is my first draft of what could go in libc-test. It doesn't
cover any subtleties of value computation, only formatting.

Rich

[-- Attachment #2: strftime.c --]
[-- Type: text/plain, Size: 1732 bytes --]

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include "test.h"

#define T1 3724

static const struct {
	time_t t;
	const char *fmt;
	const char *expect;
} tests[] = {
	{ T1, "%a", "Thu" },
	{ T1, "%A", "Thursday" },
	{ T1, "%b", "Jan" },
	{ T1, "%B", "January" },
	{ T1, "%c", "Thu Jan  1 01:02:04 1970" },
	{ T1, "%C", "19" },
	{ T1, "%04C", "0019" },
	//{ T1, "%+4C", "0019" }, // correct?
	{ T1, "%d", "01" },
	{ T1, "%D", "01/01/70" },
	{ T1, "%e", " 1" },
	{ T1, "%F", "1970-01-01" },
	{ T1, "%012F", "001970-01-01" },
	// { T1, "%+12F", "001970-01-01" }, //correct?
	{ T1, "%g", "70" },
	{ T1, "%G", "1970" },
	{ T1, "%06G", "001970" },
	// { T1, "%+6G", "001970" }, // correct?
	{ T1, "%h", "Jan" },
	{ T1, "%H", "01" },
	{ T1, "%I", "01" },
	{ T1, "%j", "001" },
	{ T1, "%m", "01" },
	{ T1, "%M", "02" },
	{ T1, "%n", "\n" },
	{ T1, "%p", "AM" },
	{ T1, "%r", "01:02:04 AM" },
	{ T1, "%R", "01:02" },
	{ T1, "%s", "3724" },
	{ T1, "%S", "04" },
	{ T1, "%T", "01:02:04" },
	{ T1, "%u", "4" },
	{ T1, "%U", "00" },
	{ T1, "%V", "01" },
	{ T1, "%w", "4" },
	{ T1, "%W", "00" },
	{ T1, "%x", "01/01/70" },
	{ T1, "%X", "01:02:04" },
	{ T1, "%Y", "1970" },
	{ T1, "%06Y", "001970" },
	// { T1, "%+6Y", "001970" }, //correct ?
};

int main(int argc, char **argv)
{
	for (size_t i=0; i<sizeof tests/sizeof *tests; i++) {
		time_t t = tests[i].t;
		struct tm *tm = gmtime(&t);
		char buf[500];
		size_t n = strftime(buf, sizeof buf, tests[i].fmt, tm);
		size_t l = strlen(tests[i].expect);
		if (n != l)
			t_error("strftime returned %zu expected %zu\n", n, l);
		if (n && strcmp(buf, tests[i].expect))
			t_error("strftime wrote '%s' expected '%s'\n", buf, tests[i].expect);
	}

	return t_status;
}

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-12-09 23:27 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-22  8:29 [PATCH] implement strftime GNU extension padding specifiers '_', '-' and '0' Timo Teräs
2016-12-20 20:13 ` Rich Felker
2016-12-21  0:27   ` Felix Janda
2016-12-21  3:20     ` Rich Felker
2017-01-06  6:59       ` [PATCH v2] " Timo Teräs
2016-12-21  6:01     ` [PATCH] " Timo Teras
2017-12-09 22:56 ` Rich Felker
2017-12-09 23:27   ` Rich Felker

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).