From: Janne Blomqvist Date: Mon, 26 May 2014 19:44:24 +0000 (+0300) Subject: PR 61310 Rewrite implementation of CTIME and FDATE intrinsics. X-Git-Tag: releases/gcc-4.7.4~67 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8485aed47a3f041edca5fe3143fed3c68cd75429;p=thirdparty%2Fgcc.git PR 61310 Rewrite implementation of CTIME and FDATE intrinsics. 2014-05-26 Janne Blomqvist Backport from mainline PR libfortran/61310 * intrinsics.texi (CTIME): Remove mention of locale-dependent behavior. 2014-05-26 Janne Blomqvist Backport from mainline 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: r210947 --- diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 6694c5955334..a66d0c9aad95 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,10 @@ +2014-05-26 Janne Blomqvist + + Backport from mainline + PR libfortran/61310 + * intrinsics.texi (CTIME): Remove mention of locale-dependent + behavior. + 2014-05-24 Dominique d'Humieres Backport r195492 and r195815 diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi index d0a29cc25ea4..327bce743052 100644 --- a/gcc/fortran/intrinsic.texi +++ b/gcc/fortran/intrinsic.texi @@ -3314,10 +3314,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 75805d2bbcf4..f013b298614c 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,14 @@ +2014-05-26 Janne Blomqvist + + Backport from mainline + 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-16 Janne Blomqvist Backport from trunk: diff --git a/libgfortran/intrinsics/ctime.c b/libgfortran/intrinsics/ctime.c index 05bf31fc779d..86e8e565cb47 100644 --- a/libgfortran/intrinsics/ctime.c +++ b/libgfortran/intrinsics/ctime.c @@ -1,5 +1,5 @@ /* Implementation of the CTIME and FDATE g77 intrinsics. - Copyright (C) 2005, 2007, 2009, 2011 Free Software Foundation, Inc. + Copyright (C) 2005-2013 Free Software Foundation, Inc. Contributed by François-Xavier Coudert This file is part of the GNU Fortran runtime library (libgfortran). @@ -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 = get_mem (CSZ); - *date_len = strctime (*date, CSZ, &now); + *date = get_mem (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 = get_mem (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 = get_mem (CSZ); - *date_len = strctime (*date, CSZ, &now); + *date = get_mem (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 = get_mem (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); }