]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR 61310 Rewrite implementation of CTIME and FDATE intrinsics.
authorJanne Blomqvist <jb@gcc.gnu.org>
Mon, 26 May 2014 18:17:13 +0000 (21:17 +0300)
committerJanne Blomqvist <jb@gcc.gnu.org>
Mon, 26 May 2014 18:17:13 +0000 (21:17 +0300)
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

gcc/fortran/ChangeLog
gcc/fortran/intrinsic.texi
libgfortran/ChangeLog
libgfortran/intrinsics/ctime.c

index 0a830a7ed6ebb49a16dd136f27011bdc4f06b8d5..91cb167b3fda586d4af6262e0455f2938727af49 100644 (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>
 
        PR fortran/55117
index 776cb00bf1166b5729f520d16e527b84a9b798c2..8402a1fc0bf7adb48d809145dee75b2acded200b 100644 (file)
@@ -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.
index efa6f053a0d49ca5111fc0e7b08b42a3783dc0d8..9b33b2ac8baa3fe6c729a3f18ad7f6aeba4c2157 100644 (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>
 
        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  <jvdelisle@gcc.gnu>
 
index db41f02cd41a23814f15525f8382dc034302d08f..9cda39b0e9ab5912448604cbfdd80679af3d40ba 100644 (file)
@@ -31,31 +31,53 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #include <string.h>
 
 
-/* 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.  */
-
-static size_t
-strctime (char *s, size_t max, const time_t *timep)
+/* 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
+
+
+/* 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, &ltm)) 
+  __builtin_choose_expr (__builtin_classify_type (localtime_r (&timev, &ltm)) 
                         == 5,
-                        failed = localtime_r (timep, &ltm) == NULL,
-                        failed = localtime_r (timep, &ltm) != 0);
+                        failed = localtime_r (&timev, &ltm) == NULL,
+                        failed = localtime_r (&timev, &ltm) != 0);
   if (failed)
-    return 0;
-  return strftime (s, max, "%c", &ltm);
+    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);
 }