From ab75303f7d67ec56b43c7a5d4220e0002665c310 Mon Sep 17 00:00:00 2001 From: Janne Blomqvist Date: Mon, 26 May 2014 21:17:13 +0300 Subject: [PATCH] PR 61310 Rewrite implementation of CTIME and FDATE intrinsics. 2014-05-26 Janne Blomqvist PR libfortran/61310 * intrinsics.texi (CTIME): Remove mention of locale-dependent behavior. 2014-05-26 Janne Blomqvist PR libfortran/61310 * intrinsics/ctime.c (strctime): Rename to gf_ctime, use snprintf instead of strftime. (fdate): Use gf_ctime. (fdate_sub): Likewise. (ctime): Likewise. (ctime_sub): Likewise. From-SVN: r210938 --- gcc/fortran/ChangeLog | 6 +++ gcc/fortran/intrinsic.texi | 6 +-- libgfortran/ChangeLog | 12 +++++- libgfortran/intrinsics/ctime.c | 68 +++++++++++++++++++++------------- 4 files changed, 61 insertions(+), 31 deletions(-) diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 0a830a7ed6e..91cb167b3fd 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2014-05-26 Janne Blomqvist + + PR libfortran/61310 + * intrinsics.texi (CTIME): Remove mention of locale-dependent + behavior. + 2014-05-26 Tobias Burnus PR fortran/55117 diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi index 776cb00bf11..8402a1fc0bf 100644 --- a/gcc/fortran/intrinsic.texi +++ b/gcc/fortran/intrinsic.texi @@ -3508,10 +3508,8 @@ end program test_cshift @table @asis @item @emph{Description}: @code{CTIME} converts a system time value, such as returned by -@code{TIME8}, to a string. Unless the application has called -@code{setlocale}, the output will be in the default locale, of length -24 and of the form @samp{Sat Aug 19 18:13:14 1995}. In other locales, -a longer string may result. +@code{TIME8}, to a string. The output will be of the form @samp{Sat +Aug 19 18:13:14 1995}. This intrinsic is provided in both subroutine and function forms; however, only one form can be used in any given program unit. diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index efa6f053a0d..9b33b2ac8ba 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,13 @@ +2014-05-26 Janne Blomqvist + + PR libfortran/61310 + * intrinsics/ctime.c (strctime): Rename to gf_ctime, use snprintf + instead of strftime. + (fdate): Use gf_ctime. + (fdate_sub): Likewise. + (ctime): Likewise. + (ctime_sub): Likewise. + 2014-05-26 Jerry DeLisle PR libgfortran/55117 @@ -6,7 +16,7 @@ extended type parent indicator. (str_comp_extended): New helper function to compare the namelist name with the varname namelist. (find_nml_name): Use the new helper functions to match - the extended type varnames. + the extended type varnames. 2014-05-23 Jerry DeLisle diff --git a/libgfortran/intrinsics/ctime.c b/libgfortran/intrinsics/ctime.c index db41f02cd41..9cda39b0e9a 100644 --- a/libgfortran/intrinsics/ctime.c +++ b/libgfortran/intrinsics/ctime.c @@ -31,31 +31,53 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include -/* strftime-like function that fills a C string with %c format which - is identical to ctime in the default locale. As ctime and ctime_r - are poorly specified and their usage not recommended, the - implementation instead uses strftime. */ +/* Maximum space a ctime-like string might need. A "normal" ctime + string is 26 bytes, and in our case 24 bytes as we don't include + the trailing newline and null. However, the longest possible year + number is -2,147,481,748 (1900 - 2,147,483,648, since tm_year is a + 32-bit signed integer) so an extra 7 bytes are needed. */ +#define CTIME_BUFSZ 31 -static size_t -strctime (char *s, size_t max, const time_t *timep) + +/* Thread-safe ctime-like function that fills a Fortran + string. ctime_r is a portability headache and marked as obsolescent + in POSIX 2008, which recommends strftime in its place. However, + strftime(..., "%c",...) doesn't produce ctime-like output on + MinGW, so do it manually with snprintf. */ + +static int +gf_ctime (char *s, size_t max, const time_t timev) { struct tm ltm; int failed; + char buf[CTIME_BUFSZ + 1]; /* Some targets provide a localtime_r based on a draft of the POSIX standard where the return type is int rather than the standardized struct tm*. */ - __builtin_choose_expr (__builtin_classify_type (localtime_r (timep, <m)) + __builtin_choose_expr (__builtin_classify_type (localtime_r (&timev, <m)) == 5, - failed = localtime_r (timep, <m) == NULL, - failed = localtime_r (timep, <m) != 0); + failed = localtime_r (&timev, <m) == NULL, + failed = localtime_r (&timev, <m) != 0); if (failed) - return 0; - return strftime (s, max, "%c", <m); + goto blank; + int n = snprintf (buf, sizeof (buf), + "%3.3s %3.3s%3d %.2d:%.2d:%.2d %d", + "SunMonTueWedThuFriSat" + ltm.tm_wday * 3, + "JanFebMarAprMayJunJulAugSepOctNovDec" + ltm.tm_mon * 3, + ltm.tm_mday, ltm.tm_hour, ltm.tm_min, ltm.tm_sec, + 1900 + ltm.tm_year); + if (n < 0) + goto blank; + if ((size_t) n <= max) + { + cf_strcpy (s, max, buf); + return n; + } + blank: + memset (s, ' ', max); + return 0; } -/* In the default locale, the date and time representation fits in 26 - bytes. However, other locales might need more space. */ -#define CSZ 100 extern void fdate (char **, gfc_charlen_type *); export_proto(fdate); @@ -64,8 +86,8 @@ void fdate (char ** date, gfc_charlen_type * date_len) { time_t now = time(NULL); - *date = xmalloc (CSZ); - *date_len = strctime (*date, CSZ, &now); + *date = xmalloc (CTIME_BUFSZ); + *date_len = gf_ctime (*date, CTIME_BUFSZ, now); } @@ -76,10 +98,7 @@ void fdate_sub (char * date, gfc_charlen_type date_len) { time_t now = time(NULL); - char *s = xmalloc (date_len + 1); - size_t n = strctime (s, date_len + 1, &now); - fstrcpy (date, date_len, s, n); - free (s); + gf_ctime (date, date_len, now); } @@ -91,8 +110,8 @@ void PREFIX(ctime) (char ** date, gfc_charlen_type * date_len, GFC_INTEGER_8 t) { time_t now = t; - *date = xmalloc (CSZ); - *date_len = strctime (*date, CSZ, &now); + *date = xmalloc (CTIME_BUFSZ); + *date_len = gf_ctime (*date, CTIME_BUFSZ, now); } @@ -103,8 +122,5 @@ void ctime_sub (GFC_INTEGER_8 * t, char * date, gfc_charlen_type date_len) { time_t now = *t; - char *s = xmalloc (date_len + 1); - size_t n = strctime (s, date_len + 1, &now); - fstrcpy (date, date_len, s, n); - free (s); + gf_ctime (date, date_len, now); }