PR 61310 Rewrite implementation of CTIME and FDATE intrinsics.

2014-05-26  Janne Blomqvist  <jb@gcc.gnu.org>

	PR libfortran/61310
	* intrinsics.texi (CTIME): Remove mention of locale-dependent
	behavior.

2014-05-26  Janne Blomqvist  <jb@gcc.gnu.org>

	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
This commit is contained in:
Janne Blomqvist 2014-05-26 21:17:13 +03:00
parent b8140cd629
commit ab75303f7d
4 changed files with 61 additions and 31 deletions

View File

@ -1,3 +1,9 @@
2014-05-26 Janne Blomqvist <jb@gcc.gnu.org>
PR libfortran/61310
* intrinsics.texi (CTIME): Remove mention of locale-dependent
behavior.
2014-05-26 Tobias Burnus <burnus@net-b.de> 2014-05-26 Tobias Burnus <burnus@net-b.de>
PR fortran/55117 PR fortran/55117

View File

@ -3508,10 +3508,8 @@ end program test_cshift
@table @asis @table @asis
@item @emph{Description}: @item @emph{Description}:
@code{CTIME} converts a system time value, such as returned by @code{CTIME} converts a system time value, such as returned by
@code{TIME8}, to a string. Unless the application has called @code{TIME8}, to a string. The output will be of the form @samp{Sat
@code{setlocale}, the output will be in the default locale, of length Aug 19 18:13:14 1995}.
24 and of the form @samp{Sat Aug 19 18:13:14 1995}. In other locales,
a longer string may result.
This intrinsic is provided in both subroutine and function forms; however, This intrinsic is provided in both subroutine and function forms; however,
only one form can be used in any given program unit. only one form can be used in any given program unit.

View File

@ -1,3 +1,13 @@
2014-05-26 Janne Blomqvist <jb@gcc.gnu.org>
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 <jvdelisle@gcc.gnu.org> 2014-05-26 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR libgfortran/55117 PR libgfortran/55117
@ -6,7 +16,7 @@
extended type parent indicator. (str_comp_extended): New extended type parent indicator. (str_comp_extended): New
helper function to compare the namelist name with the varname helper function to compare the namelist name with the varname
namelist. (find_nml_name): Use the new helper functions to match namelist. (find_nml_name): Use the new helper functions to match
the extended type varnames. the extended type varnames.
2014-05-23 Jerry DeLisle <jvdelisle@gcc.gnu> 2014-05-23 Jerry DeLisle <jvdelisle@gcc.gnu>

View File

@ -31,31 +31,53 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include <string.h> #include <string.h>
/* strftime-like function that fills a C string with %c format which /* Maximum space a ctime-like string might need. A "normal" ctime
is identical to ctime in the default locale. As ctime and ctime_r string is 26 bytes, and in our case 24 bytes as we don't include
are poorly specified and their usage not recommended, the the trailing newline and null. However, the longest possible year
implementation instead uses strftime. */ 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; struct tm ltm;
int failed; int failed;
char buf[CTIME_BUFSZ + 1];
/* Some targets provide a localtime_r based on a draft of the POSIX /* Some targets provide a localtime_r based on a draft of the POSIX
standard where the return type is int rather than the standard where the return type is int rather than the
standardized struct tm*. */ standardized struct tm*. */
__builtin_choose_expr (__builtin_classify_type (localtime_r (timep, &ltm)) __builtin_choose_expr (__builtin_classify_type (localtime_r (&timev, &ltm))
== 5, == 5,
failed = localtime_r (timep, &ltm) == NULL, failed = localtime_r (&timev, &ltm) == NULL,
failed = localtime_r (timep, &ltm) != 0); failed = localtime_r (&timev, &ltm) != 0);
if (failed) if (failed)
return 0; goto blank;
return strftime (s, max, "%c", &ltm); 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 *); extern void fdate (char **, gfc_charlen_type *);
export_proto(fdate); export_proto(fdate);
@ -64,8 +86,8 @@ void
fdate (char ** date, gfc_charlen_type * date_len) fdate (char ** date, gfc_charlen_type * date_len)
{ {
time_t now = time(NULL); time_t now = time(NULL);
*date = xmalloc (CSZ); *date = xmalloc (CTIME_BUFSZ);
*date_len = strctime (*date, CSZ, &now); *date_len = gf_ctime (*date, CTIME_BUFSZ, now);
} }
@ -76,10 +98,7 @@ void
fdate_sub (char * date, gfc_charlen_type date_len) fdate_sub (char * date, gfc_charlen_type date_len)
{ {
time_t now = time(NULL); time_t now = time(NULL);
char *s = xmalloc (date_len + 1); gf_ctime (date, date_len, now);
size_t n = strctime (s, date_len + 1, &now);
fstrcpy (date, date_len, s, n);
free (s);
} }
@ -91,8 +110,8 @@ void
PREFIX(ctime) (char ** date, gfc_charlen_type * date_len, GFC_INTEGER_8 t) PREFIX(ctime) (char ** date, gfc_charlen_type * date_len, GFC_INTEGER_8 t)
{ {
time_t now = t; time_t now = t;
*date = xmalloc (CSZ); *date = xmalloc (CTIME_BUFSZ);
*date_len = strctime (*date, CSZ, &now); *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) ctime_sub (GFC_INTEGER_8 * t, char * date, gfc_charlen_type date_len)
{ {
time_t now = *t; time_t now = *t;
char *s = xmalloc (date_len + 1); gf_ctime (date, date_len, now);
size_t n = strctime (s, date_len + 1, &now);
fstrcpy (date, date_len, s, n);
free (s);
} }