On Thu, Apr 17, 2014 at 11:52:09AM -0500, Vladimir Támara Patiño wrote: > I see a lot of duplication between lib/libc/time/strftime.c and > lib/libc/time/wcsftime.c. > > Since I would like to implement LC_TIME support, I would prefer to > change only in one place but before that I prepared a simple regression test > for strftime and wcsftime that is attached. > > Checking NetBSD and FreeBSD sources I see they implemented wcsftime by > translating the wide character strings to multibyte, then calling strftime > and finally converting the result back to wide character: > http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/locale/wcsftime.c?rev=1.5&content-type=text/x-cvsweb-markup&only_with_tag=MAIN > https://github.com/freebsd/freebsd/blob/master/lib/libc/locale/wcsftime.c > > The drawbacks I see are: > 1. It is a little less efficient (because it has to translate before > calling strftime and translate again after) > 2. If there is no memory or the conversions fail the function must > return 0 and set errno, and that is not specified in POSIX > http://pubs.opengroup.org/onlinepubs/009696799/functions/wcsftime.html > > What way do you suggest me? > 1. Implement like FreeBSD and NetBSD did > 2. Change both functions? they use differente structures lc_time_T that at > least I would like to unify.
I think a better step forward for LC_TIME support would be to focus on nl_langinfo() first and make it return locale-specific data for LC_TIME. The functions you're looking at are icing on the cake. We should be looking at adding more LC_TIME foundations first. How and where do you intend to store locale-specific LC_TIME data? Do you intend to copy FreeBSD's format? An alternative (but more work) would be to implement a localedef utility and switch locale definition data to the format specified by POSIX. I'm not sure how widespread the localedef format really is. But having a data format that follows the same spec as the functions using the data might be easier to maintain in the long term. Your regression test has at least one bug ('bad' is never initialised). > diff -ruN src56-orig/regress/lib/libc/time/Makefile > src/regress/lib/libc/time/Makefile > --- src56-orig/regress/lib/libc/time/Makefile Tue Jan 20 11:47:55 2004 > +++ src/regress/lib/libc/time/Makefile Thu Apr 17 08:37:20 2014 > @@ -1,5 +1,5 @@ > # $OpenBSD: Makefile,v 1.1 2004/01/20 16:47:55 millert Exp $ > > -SUBDIR+=strptime > +SUBDIR+=ftime strptime > > .include <bsd.subdir.mk> > diff -ruN src56-orig/regress/lib/libc/time/ftime/Makefile > src/regress/lib/libc/time/ftime/Makefile > --- src56-orig/regress/lib/libc/time/ftime/Makefile Wed Dec 31 19:00:00 1969 > +++ src/regress/lib/libc/time/ftime/Makefile Thu Apr 17 08:37:05 2014 > @@ -0,0 +1,11 @@ > + > +NOMAN= > +PROG=check_ftime > + > +CFLAGS=-g > + > + > +run-regress-check_ftime: ${PROG} > + ./${PROG} >/dev/null > + > +.include <bsd.regress.mk> > diff -ruN src56-orig/regress/lib/libc/time/ftime/check_ftime.c > src/regress/lib/libc/time/ftime/check_ftime.c > --- src56-orig/regress/lib/libc/time/ftime/check_ftime.c Wed Dec 31 > 19:00:00 1969 > +++ src/regress/lib/libc/time/ftime/check_ftime.c Thu Apr 17 11:46:19 2014 > @@ -0,0 +1,268 @@ > +/** > + * Public domain according to Colombian Legislation. > + * http://www.pasosdejesus.org/dominio_publico_colombia.html > + * 2014. vtam...@pasosdejesus.org > + * > + * $OpenBSD$ > + */ > + > +#include <locale.h> > +#include <stdio.h> > +#include <stdlib.h> > + > +int bad; > + > +#define p(t) printf("%s:\t ",#t); \ > + if (t) { \ > + printf("\x1b[38;5;2mOK\x1b[0m\n"); \ > + } else { \ > + bad++; \ > + printf("\x1b[38;5;1mERROR\x1b[0m\n"); \ > + } > + > + > +void test_ftime_posix() > +{ > + char nom[256]; > + char col[512]; > + wchar_t wcol[512]; > + char *nl; > + char *enc[]= { "ISO8859-1", "ISO8859-15", "UTF-8" }; > + struct lconv *p; > + struct tm tl; > + int i; > + time_t ti; > + long ts; > + for(i = 0; i < sizeof(enc) / sizeof(char *) ; i++) { > + snprintf(nom, sizeof(nom), "POSIX.%s", enc[i]); > + printf("nom=%s\n", nom); > + nl = setlocale(LC_ALL, nom); > + printf("locale %s\n", nl); > + p = localeconv(); > + ti = (time_t)1396950000; //Tue Apr 8 09:40:00 2014 > + gmtime_r(&ti, &tl) ; > + /*p = strptime("", "", &tm); */ > + strftime(col, sizeof(col), "%A", &tl); > + p(strcmp(col, "Tuesday") == 0); > + wcsftime(wcol, sizeof(wcol), L"%A", &tl); > + p(wcscmp(wcol, L"Tuesday") == 0); > + > + strftime(col, sizeof(col), "%a", &tl); > + p(strcmp(col, "Tue") == 0); > + wcsftime(wcol, sizeof(wcol), L"%a", &tl); > + p(wcscmp(wcol, L"Tue") == 0); > + > + strftime(col, sizeof(col), "%B", &tl); > + p(strcmp(col, "April") == 0); > + wcsftime(wcol, sizeof(wcol), L"%B", &tl); > + p(wcscmp(wcol, L"April") == 0); > + > + strftime(col, sizeof(col), "%b", &tl); > + p(strcmp(col, "Apr") == 0); > + wcsftime(wcol, sizeof(wcol), L"%b", &tl); > + p(wcscmp(wcol, L"Apr") == 0); > + > + strftime(col, sizeof(col), "%C", &tl); > + p(strcmp(col, "20") == 0); > + wcsftime(wcol, sizeof(wcol), L"%C", &tl); > + p(wcscmp(wcol, L"20") == 0); > + > + strftime(col, sizeof(col), "%c", &tl); > + printf("%s\n", col); > + p(strcmp(col, "Tue Apr 8 09:40:00 2014") == 0); > + wcsftime(wcol, sizeof(wcol), L"%c", &tl); > + p(wcscmp(wcol, L"Tue Apr 8 09:40:00 2014") == 0); > + > + strftime(col, sizeof(col), "%D", &tl); > + p(strcmp(col, "04/08/14") == 0); > + wcsftime(wcol, sizeof(wcol), L"%D", &tl); > + p(wcscmp(wcol, L"04/08/14") == 0); > + > + strftime(col, sizeof(col), "%d", &tl); > + p(strcmp(col, "08") == 0); > + wcsftime(wcol, sizeof(wcol), L"%d", &tl); > + p(wcscmp(wcol, L"08") == 0); > + > + strftime(col, sizeof(col), "%e", &tl); > + p(strcmp(col, " 8") == 0); > + wcsftime(wcol, sizeof(wcol), L"%e", &tl); > + p(wcscmp(wcol, L" 8") == 0); > + > + strftime(col, sizeof(col), "%F", &tl); > + p(strcmp(col, "2014-04-08") == 0); > + wcsftime(wcol, sizeof(wcol), L"%F", &tl); > + p(wcscmp(wcol, L"2014-04-08") == 0); > + > + strftime(col, sizeof(col), "%G", &tl); > + p(strcmp(col, "2014") == 0); > + wcsftime(wcol, sizeof(wcol), L"%G", &tl); > + p(wcscmp(wcol, L"2014") == 0); > + > + strftime(col, sizeof(col), "%g", &tl); > + p(strcmp(col, "14") == 0); > + wcsftime(wcol, sizeof(wcol), L"%g", &tl); > + p(wcscmp(wcol, L"14") == 0); > + > + strftime(col, sizeof(col), "%H", &tl); > + p(strcmp(col, "09") == 0); > + wcsftime(wcol, sizeof(wcol), L"%H", &tl); > + p(wcscmp(wcol, L"09") == 0); > + > + strftime(col, sizeof(col), "%I", &tl); > + p(strcmp(col, "09") == 0); > + wcsftime(wcol, sizeof(wcol), L"%I", &tl); > + p(wcscmp(wcol, L"09") == 0); > + > + strftime(col, sizeof(col), "%j", &tl); > + p(strcmp(col, "098") == 0); > + wcsftime(wcol, sizeof(wcol), L"%j", &tl); > + p(wcscmp(wcol, L"098") == 0); > + > + strftime(col, sizeof(col), "%k", &tl); > + p(strcmp(col, " 9") == 0); > + wcsftime(wcol, sizeof(wcol), L"%k", &tl); > + p(wcscmp(wcol, L" 9") == 0); > + > + strftime(col, sizeof(col), "%l", &tl); > + p(strcmp(col, " 9") == 0); > + wcsftime(wcol, sizeof(wcol), L"%l", &tl); > + p(wcscmp(wcol, L" 9") == 0); > + > + strftime(col, sizeof(col), "%M", &tl); > + p(strcmp(col, "40") == 0); > + wcsftime(wcol, sizeof(wcol), L"%M", &tl); > + p(wcscmp(wcol, L"40") == 0); > + > + strftime(col, sizeof(col), "%m", &tl); > + p(strcmp(col, "04") == 0); > + wcsftime(wcol, sizeof(wcol), L"%m", &tl); > + p(wcscmp(wcol, L"04") == 0); > + > + strftime(col, sizeof(col), "%n", &tl); > + p(strcmp(col, "\n") == 0); > + wcsftime(wcol, sizeof(wcol), L"%n", &tl); > + p(wcscmp(wcol, L"\n") == 0); > + > + strftime(col, sizeof(col), "%p", &tl); > + p(strcmp(col, "AM") == 0); > + wcsftime(wcol, sizeof(wcol), L"%p", &tl); > + p(wcscmp(wcol, L"AM") == 0); > + > + strftime(col, sizeof(col), "%R", &tl); > + p(strcmp(col, "09:40") == 0); > + wcsftime(wcol, sizeof(wcol), L"%R", &tl); > + p(wcscmp(wcol, L"09:40") == 0); > + > + strftime(col, sizeof(col), "%r", &tl); > + p(strcmp(col, "09:40:00 AM") == 0); > + wcsftime(wcol, sizeof(wcol), L"%r", &tl); > + p(wcscmp(wcol, L"09:40:00 AM") == 0); > + > + strftime(col, sizeof(col), "%S", &tl); > + p(strcmp(col, "00") == 0); > + wcsftime(wcol, sizeof(wcol), L"%S", &tl); > + p(wcscmp(wcol, L"00") == 0); > + > + strftime(col, sizeof(col), "%s", &tl); > + ts = atol(col); > + printf("%li\n", ts); > + // Checking from any timezone from GMT-12 to GMT+12 > + p(1396950000-43200 <= ts && ts <=1396950000+43200); > + wcsftime(wcol, sizeof(wcol), L"%s", &tl); > + ts = wcstol(wcol, NULL, 10); > + printf("%li\n", ts); > + p(1396950000-43200 <= ts && ts <=1396950000+43200); > + > + strftime(col, sizeof(col), "%T", &tl); > + p(strcmp(col, "09:40:00") == 0); > + wcsftime(wcol, sizeof(wcol), L"%T", &tl); > + p(wcscmp(wcol, L"09:40:00") == 0); > + > + strftime(col, sizeof(col), "%t", &tl); > + p(strcmp(col, "\t") == 0); > + wcsftime(wcol, sizeof(wcol), L"%t", &tl); > + p(wcscmp(wcol, L"\t") == 0); > + > + strftime(col, sizeof(col), "%U", &tl); > + p(strcmp(col, "14") == 0); > + wcsftime(wcol, sizeof(wcol), L"%U", &tl); > + p(wcscmp(wcol, L"14") == 0); > + > + strftime(col, sizeof(col), "%u", &tl); > + p(strcmp(col, "2") == 0); > + wcsftime(wcol, sizeof(wcol), L"%u", &tl); > + p(wcscmp(wcol, L"2") == 0); > + > + strftime(col, sizeof(col), "%V", &tl); > + p(strcmp(col, "15") == 0); > + wcsftime(wcol, sizeof(wcol), L"%V", &tl); > + p(wcscmp(wcol, L"15") == 0); > + > + strftime(col, sizeof(col), "%v", &tl); > + p(strcmp(col, " 8-Apr-2014") == 0); > + wcsftime(wcol, sizeof(wcol), L"%v", &tl); > + p(wcscmp(wcol, L" 8-Apr-2014") == 0); > + > + strftime(col, sizeof(col), "%w", &tl); > + p(strcmp(col, "2") == 0); > + wcsftime(wcol, sizeof(wcol), L"%w", &tl); > + p(wcscmp(wcol, L"2") == 0); > + > + strftime(col, sizeof(col), "%W", &tl); > + p(strcmp(col, "14") == 0); > + wcsftime(wcol, sizeof(wcol), L"%W", &tl); > + p(wcscmp(wcol, L"14") == 0); > + > + strftime(col, sizeof(col), "%X", &tl); > + p(strcmp(col, "09:40:00") == 0); > + wcsftime(wcol, sizeof(wcol), L"%X", &tl); > + p(wcscmp(wcol, L"09:40:00") == 0); > + > + strftime(col, sizeof(col), "%x", &tl); > + p(strcmp(col, "04/08/14") == 0); > + wcsftime(wcol, sizeof(wcol), L"%x", &tl); > + p(wcscmp(wcol, L"04/08/14") == 0); > + > + strftime(col, sizeof(col), "%Y", &tl); > + p(strcmp(col, "2014") == 0); > + wcsftime(wcol, sizeof(wcol), L"%Y", &tl); > + p(wcscmp(wcol, L"2014") == 0); > + > + strftime(col, sizeof(col), "%y", &tl); > + p(strcmp(col, "14") == 0); > + wcsftime(wcol, sizeof(wcol), L"%y", &tl); > + p(wcscmp(wcol, L"14") == 0); > + > + strftime(col, sizeof(col), "%Z", &tl); > + p(strcmp(col, "GMT") == 0); > + wcsftime(wcol, sizeof(wcol), L"%Z", &tl); > + p(wcscmp(wcol, L"GMT") == 0); > + > + strftime(col, sizeof(col), "%z", &tl); > + p(strcmp(col, "+0000") == 0); > + wcsftime(wcol, sizeof(wcol), L"%z", &tl); > + p(wcscmp(wcol, L"+0000") == 0); > + > + strftime(col, sizeof(col), "%%", &tl); > + p(strcmp(col, "%") == 0); > + wcsftime(wcol, sizeof(wcol), L"%%", &tl); > + p(wcscmp(wcol, L"%") == 0); > + > + strftime(col, sizeof(col), "%+", &tl); > + p(strcmp(col, "Tue Apr 8 09:40:00 GMT 2014") == 0); > + wcsftime(wcol, sizeof(wcol), L"%+", &tl); > + p(wcscmp(wcol, L"Tue Apr 8 09:40:00 GMT 2014") == 0); > + > + > + > + } > +} > + > + > +int main() > +{ > + test_ftime_posix(); > + > + return bad != 0; > +} > +