]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR 40958 Compress module files with zlib.
authorJanne Blomqvist <jb@gcc.gnu.org>
Wed, 17 Apr 2013 10:19:40 +0000 (13:19 +0300)
committerJanne Blomqvist <jb@gcc.gnu.org>
Wed, 17 Apr 2013 10:19:40 +0000 (13:19 +0300)
frontend ChangeLog:

2013-04-17  Janne Blomqvist  <jb@gcc.gnu.org>

PR fortran/40958
* scanner.h: New file.
* Make-lang.in: Dependencies on scanner.h.
* scanner.c (gfc_directorylist): Move to scanner.h.
* module.c: Don't include md5.h, include scanner.h and zlib.h.
(MOD_VERSION): Add comment about backwards compatibility.
(module_fp): Change type to gzFile.
(ctx): Remove.
(gzopen_included_file_1): New function.
(gzopen_included_file): New function.
(gzopen_intrinsic_module): New function.
(write_char): Use gzputc.
(read_crc32_from_module_file): New function.
(read_md5_from_module_file): Remove.
(gfc_dump_module): Use gz* functions instead of stdio, check gzip
crc32 instead of md5.
(read_module_to_tmpbuf): Use gz* functions instead of stdio.
(gfc_use_module): Use gz* functions.

testsuite ChangeLog:

2013-04-17  Janne Blomqvist  <jb@gcc.gnu.org>

        PR fortran/40958
        * lib/gcc-dg.exp (scan-module): Uncompress module file before
        scanning.
        * gfortran.dg/module_md5_1.f90: Remove.

From-SVN: r198023

gcc/fortran/ChangeLog
gcc/fortran/Make-lang.in
gcc/fortran/module.c
gcc/fortran/scanner.c
gcc/fortran/scanner.h [new file with mode: 0644]
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/module_md5_1.f90 [deleted file]
gcc/testsuite/lib/gcc-dg.exp

index 2f99025ea3361e1cb555aef357c536ffe4b411bd..af1370813dcb34a9423a2dc769c90fa40a136b4c 100644 (file)
@@ -1,3 +1,24 @@
+2013-04-17  Janne Blomqvist  <jb@gcc.gnu.org>
+
+       PR fortran/40958
+       * scanner.h: New file.
+       * Make-lang.in: Dependencies on scanner.h.
+       * scanner.c (gfc_directorylist): Move to scanner.h.
+       * module.c: Don't include md5.h, include scanner.h and zlib.h.
+       (MOD_VERSION): Add comment about backwards compatibility.
+       (module_fp): Change type to gzFile.
+       (ctx): Remove.
+       (gzopen_included_file_1): New function.
+       (gzopen_included_file): New function.
+       (gzopen_intrinsic_module): New function.
+       (write_char): Use gzputc.
+       (read_crc32_from_module_file): New function.
+       (read_md5_from_module_file): Remove.
+       (gfc_dump_module): Use gz* functions instead of stdio, check gzip
+       crc32 instead of md5.
+       (read_module_to_tmpbuf): Use gz* functions instead of stdio.
+       (gfc_use_module): Use gz* functions.
+
 2013-04-16  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/39505
index 8c9e7eabac469fdc286f8f9f8607071982cb64be..5ce2a2451525d4cdb818cc9ba6fd4f7dfafdebf1 100644 (file)
@@ -369,3 +369,5 @@ fortran/resolve.o: fortran/dependency.h fortran/data.h fortran/target-memory.h
 fortran/data.o: fortran/data.h
 fortran/options.o: $(PARAMS_H) $(TARGET_H) fortran/cpp.h
 fortran/cpp.o: fortran/cpp.c incpath.h incpath.o cppbuiltin.h
+fortran/scanner.o: fortran/scanner.h
+fortran/module.o: fortran/scanner.h
index 046ba4835f287ccc16c7121195a30fabcc771ed4..e6a4cd7046a6a32cc498f2fc4475a92028136aeb 100644 (file)
@@ -71,15 +71,18 @@ along with GCC; see the file COPYING3.  If not see
 #include "arith.h"
 #include "match.h"
 #include "parse.h" /* FIXME */
-#include "md5.h"
 #include "constructor.h"
 #include "cpp.h"
 #include "tree.h"
+#include "scanner.h"
+#include <zlib.h>
 
 #define MODULE_EXTENSION ".mod"
 
-/* Don't put any single quote (') in MOD_VERSION, 
-   if yout want it to be recognized.  */
+/* Don't put any single quote (') in MOD_VERSION, if you want it to be
+   recognized.  
+   TODO: When the version is bumped, remove the extra empty line at
+   the beginning of module files.  */
 #define MOD_VERSION "10"
 
 
@@ -180,11 +183,9 @@ pointer_info;
 
 /* Local variables */
 
-/* The FILE for the module we're reading or writing.  */
-static FILE *module_fp;
+/* The gzFile for the module we're reading or writing.  */
+static gzFile module_fp;
 
-/* MD5 context structure.  */
-static struct md5_ctx ctx;
 
 /* The name of the module we're reading (USE'ing) or writing.  */
 static const char *module_name;
@@ -976,6 +977,76 @@ free_true_name (true_name *t)
 
 /* Module reading and writing.  */
 
+/* The following are versions similar to the ones in scanner.c, but
+   for dealing with compressed module files.  */
+
+static gzFile
+gzopen_included_file_1 (const char *name, gfc_directorylist *list,
+                     bool module, bool system)
+{
+  char *fullname;
+  gfc_directorylist *p;
+  gzFile f;
+
+  for (p = list; p; p = p->next)
+    {
+      if (module && !p->use_for_modules)
+       continue;
+
+      fullname = (char *) alloca(strlen (p->path) + strlen (name) + 1);
+      strcpy (fullname, p->path);
+      strcat (fullname, name);
+
+      f = gzopen (fullname, "r");
+      if (f != NULL)
+       {
+         if (gfc_cpp_makedep ())
+           gfc_cpp_add_dep (fullname, system);
+
+         return f;
+       }
+    }
+
+  return NULL;
+}
+
+static gzFile 
+gzopen_included_file (const char *name, bool include_cwd, bool module)
+{
+  gzFile f = NULL;
+
+  if (IS_ABSOLUTE_PATH (name) || include_cwd)
+    {
+      f = gzopen (name, "r");
+      if (f && gfc_cpp_makedep ())
+       gfc_cpp_add_dep (name, false);
+    }
+
+  if (!f)
+    f = gzopen_included_file_1 (name, include_dirs, module, false);
+
+  return f;
+}
+
+static gzFile
+gzopen_intrinsic_module (const char* name)
+{
+  gzFile f = NULL;
+
+  if (IS_ABSOLUTE_PATH (name))
+    {
+      f = gzopen (name, "r");
+      if (f && gfc_cpp_makedep ())
+        gfc_cpp_add_dep (name, true);
+    }
+
+  if (!f)
+    f = gzopen_included_file_1 (name, intrinsic_modules_dirs, true, true);
+
+  return f;
+}
+
+
 typedef enum
 {
   ATOM_NAME, ATOM_LPAREN, ATOM_RPAREN, ATOM_INTEGER, ATOM_STRING
@@ -1463,12 +1534,9 @@ read_string (void)
 static void
 write_char (char out)
 {
-  if (putc (out, module_fp) == EOF)
+  if (gzputc (module_fp, out) == EOF)
     gfc_fatal_error ("Error writing modules file: %s", xstrerror (errno));
 
-  /* Add this to our MD5.  */
-  md5_process_bytes (&out, sizeof (out), &ctx);
-  
   if (out != '\n')
     module_column++;
   else
@@ -5407,61 +5475,47 @@ write_module (void)
 }
 
 
-/* Read a MD5 sum from the header of a module file.  If the file cannot
-   be opened, or we have any other error, we return -1.  */
+/* Read a CRC32 sum from the gzip trailer of a module file.  Returns
+   true on success, false on failure.  */
 
-static int
-read_md5_from_module_file (const char * filename, unsigned char md5[16])
+static bool
+read_crc32_from_module_file (const char* filename, uLong* crc)
 {
   FILE *file;
-  char buf[1024];
-  int n;
+  char buf[4];
+  unsigned int val;
 
-  /* Open the file.  */
-  if ((file = fopen (filename, "r")) == NULL)
-    return -1;
+  /* Open the file in binary mode.  */
+  if ((file = fopen (filename, "rb")) == NULL)
+    return false;
 
-  /* Read the first line.  */
-  if (fgets (buf, sizeof (buf) - 1, file) == NULL)
+  /* The gzip crc32 value is found in the [END-8, END-4] bytes of the
+     file. See RFC 1952.  */
+  if (fseek (file, -8, SEEK_END) != 0)
     {
       fclose (file);
-      return -1;
+      return false;
     }
 
-  /* The file also needs to be overwritten if the version number changed.  */
-  n = strlen ("GFORTRAN module version '" MOD_VERSION "' created");
-  if (strncmp (buf, "GFORTRAN module version '" MOD_VERSION "' created", n) != 0)
+  /* Read the CRC32.  */
+  if (fread (buf, 1, 4, file) != 4)
     {
       fclose (file);
-      return -1;
-    }
-  /* Read a second line.  */
-  if (fgets (buf, sizeof (buf) - 1, file) == NULL)
-    {
-      fclose (file);
-      return -1;
+      return false;
     }
 
   /* Close the file.  */
   fclose (file);
 
-  /* If the header is not what we expect, or is too short, bail out.  */
-  if (strncmp (buf, "MD5:", 4) != 0 || strlen (buf) < 4 + 16)
-    return -1;
-
-  /* Now, we have a real MD5, read it into the array.  */
-  for (n = 0; n < 16; n++)
-    {
-      unsigned int x;
-
-      if (sscanf (&(buf[4+2*n]), "%02x", &x) != 1)
-       return -1;
-
-      md5[n] = x;
-    }
+  val = (buf[0] & 0xFF) + ((buf[1] & 0xFF) << 8) + ((buf[2] & 0xFF) << 16) 
+    + ((buf[3] & 0xFF) << 24);
+  *crc = val;
+  
+  /* For debugging, the CRC value printed in hexadecimal should match
+     the CRC printed by "zcat -l -v filename".
+     printf("CRC of file %s is %x\n", filename, val); */
 
-  return 0;
+  return true;
 }
 
 
@@ -5474,8 +5528,7 @@ gfc_dump_module (const char *name, int dump_flag)
 {
   int n;
   char *filename, *filename_tmp;
-  fpos_t md5_pos;
-  unsigned char md5_new[16], md5_old[16];
+  uLong crc, crc_old;
 
   n = strlen (name) + strlen (MODULE_EXTENSION) + 1;
   if (gfc_option.module_dir != NULL)
@@ -5509,20 +5562,18 @@ gfc_dump_module (const char *name, int dump_flag)
     gfc_cpp_add_target (filename);
 
   /* Write the module to the temporary file.  */
-  module_fp = fopen (filename_tmp, "w");
+  module_fp = gzopen (filename_tmp, "w");
   if (module_fp == NULL)
     gfc_fatal_error ("Can't open module file '%s' for writing at %C: %s",
                     filename_tmp, xstrerror (errno));
 
-  /* Write the header, including space reserved for the MD5 sum.  */
-  fprintf (module_fp, "GFORTRAN module version '%s' created from %s\n"
-          "MD5:", MOD_VERSION, gfc_source_file);
-  fgetpos (module_fp, &md5_pos);
-  fputs ("00000000000000000000000000000000 -- "
-       "If you edit this, you'll get what you deserve.\n\n", module_fp);
+  /* Write the header.
+     FIXME: For backwards compatibility with the old uncompressed
+     module format, write an extra empty line. When the module version
+     is bumped, this can be removed.  */
+  gzprintf (module_fp, "GFORTRAN module version '%s' created from %s\n\n",
+           MOD_VERSION, gfc_source_file);
 
-  /* Initialize the MD5 context that will be used for output.  */
-  md5_init_ctx (&ctx);
 
   /* Write the module itself.  */
   iomode = IO_OUTPUT;
@@ -5537,24 +5588,17 @@ gfc_dump_module (const char *name, int dump_flag)
 
   write_char ('\n');
 
-  /* Write the MD5 sum to the header of the module file.  */
-  md5_finish_ctx (&ctx, md5_new);
-  fsetpos (module_fp, &md5_pos);
-  for (n = 0; n < 16; n++)
-    fprintf (module_fp, "%02x", md5_new[n]);
-
-  if (fclose (module_fp))
+  if (gzclose (module_fp))
     gfc_fatal_error ("Error writing module file '%s' for writing: %s",
                     filename_tmp, xstrerror (errno));
 
-  /* Read the MD5 from the header of the old module file and compare.  */
-  if (read_md5_from_module_file (filename, md5_old) != 0
-      || memcmp (md5_old, md5_new, sizeof (md5_old)) != 0)
+  /* Read the CRC32 from the gzip trailers of the module files and
+     compare.  */
+  if (!read_crc32_from_module_file (filename_tmp, &crc)
+      || !read_crc32_from_module_file (filename, &crc_old)
+      || crc_old != crc)
     {
       /* Module file have changed, replace the old one.  */
-      if (unlink (filename) && errno != ENOENT)
-       gfc_fatal_error ("Can't delete module file '%s': %s", filename,
-                        xstrerror (errno));
       if (rename (filename_tmp, filename))
        gfc_fatal_error ("Can't rename module file '%s' to '%s': %s",
                         filename_tmp, filename, xstrerror (errno));
@@ -6023,17 +6067,27 @@ create_derived_type (const char *name, const char *modname,
 static void
 read_module_to_tmpbuf ()
 {
-  /* Find out the size of the file and reserve space.  Assume we're at
-     the beginning.  */
-  fseek (module_fp, 0, SEEK_END);
-  long file_size = ftell (module_fp);
-  fseek (module_fp, 0, SEEK_SET);
+  /* We don't know the uncompressed size, so enlarge the buffer as
+     needed.  */
+  int cursz = 4096;
+  int rsize = cursz;
+  int len = 0;
+
+  module_content = XNEWVEC (char, cursz);
 
-  /* An extra byte for the terminating NULL.  */
-  module_content = XNEWVEC (char, file_size + 1);
+  while (1)
+    {
+      int nread = gzread (module_fp, module_content + len, rsize);
+      len += nread;
+      if (nread < rsize)
+       break;
+      cursz *= 2;
+      module_content = XRESIZEVEC (char, module_content, cursz);
+      rsize = cursz - len;
+    }
 
-  fread (module_content, 1, file_size, module_fp);
-  module_content[file_size] = '\0';
+  module_content = XRESIZEVEC (char, module_content, len + 1);
+  module_content[len] = '\0';
 
   module_pos = 0;
 }
@@ -6254,7 +6308,7 @@ gfc_use_module (gfc_use_list *module)
      specified that the module is intrinsic.  */
   module_fp = NULL;
   if (!module->intrinsic)
-    module_fp = gfc_open_included_file (filename, true, true);
+    module_fp = gzopen_included_file (filename, true, true);
 
   /* Then, see if it's an intrinsic one, unless the USE statement
      specified that the module is non-intrinsic.  */
@@ -6283,7 +6337,7 @@ gfc_use_module (gfc_use_list *module)
          return;
        }
 
-      module_fp = gfc_open_intrinsic_module (filename);
+      module_fp = gzopen_intrinsic_module (filename);
 
       if (module_fp == NULL && module->intrinsic)
        gfc_fatal_error ("Can't find an intrinsic module named '%s' at %C",
@@ -6308,7 +6362,7 @@ gfc_use_module (gfc_use_list *module)
   start = 0;
 
   read_module_to_tmpbuf ();
-  fclose (module_fp);
+  gzclose (module_fp);
 
   /* Skip the first two lines of the module, after checking that this is
      a gfortran module file.  */
index fd8f284827c16350049983c6ef7dfcc07064b993..882e2d5e06f46c8080a25e37e7d5f4f46bee2b81 100644 (file)
@@ -48,18 +48,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "debug.h"
 #include "flags.h"
 #include "cpp.h"
-
-/* Structure for holding module and include file search path.  */
-typedef struct gfc_directorylist
-{
-  char *path;
-  bool use_for_modules;
-  struct gfc_directorylist *next;
-}
-gfc_directorylist;
+#include "scanner.h"
 
 /* List of include file search directories.  */
-static gfc_directorylist *include_dirs, *intrinsic_modules_dirs;
+gfc_directorylist *include_dirs, *intrinsic_modules_dirs;
 
 static gfc_file *file_head, *current_file;
 
diff --git a/gcc/fortran/scanner.h b/gcc/fortran/scanner.h
new file mode 100644 (file)
index 0000000..4c559fb
--- /dev/null
@@ -0,0 +1,32 @@
+/* Character scanner header.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   Contributed by Janne Blomqvist
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+/* Structure for holding module and include file search path.  */
+typedef struct gfc_directorylist
+{
+  char *path;
+  bool use_for_modules;
+  struct gfc_directorylist *next;
+}
+gfc_directorylist;
+
+/* List of include file search directories.  */
+extern gfc_directorylist *include_dirs, *intrinsic_modules_dirs;
index d9a432cb2cbb54bf7a640d844777c9356ec53108..7bfc68db9dd67e5ef8c2c907241ad6b214cf7150 100644 (file)
@@ -1,3 +1,10 @@
+2013-04-17  Janne Blomqvist  <jb@gcc.gnu.org>
+
+        PR fortran/40958
+        * lib/gcc-dg.exp (scan-module): Uncompress module file before
+        scanning.
+        * gfortran.dg/module_md5_1.f90: Remove.
+
 2013-04-16   Naveen H.S  <Naveen.Hurugalawadi@caviumnetworks.com>
 
        * gcc.target/aarch64/adds3.c: New.
diff --git a/gcc/testsuite/gfortran.dg/module_md5_1.f90 b/gcc/testsuite/gfortran.dg/module_md5_1.f90
deleted file mode 100644 (file)
index 1f522cb..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-! Check that we can write a module file, that it has a correct MD5 sum,
-! and that we can read it back.
-!
-! { dg-do compile }
-module foo
-  integer(kind=4), parameter :: pi = 3_4
-end module foo
-
-program test
-  use foo
-  print *, pi
-end program test
-! { dg-final { scan-module "foo" "MD5:510304affe70481794fecdb22fc9ca0c" } }
index 3a612a55f8a78bcde32fa7f129fd20530ac8baed..f64f4a121cf8e5090d24fda94514c25857e72c59 100644 (file)
@@ -633,7 +633,7 @@ proc cleanup-saved-temps { args } {
 # Argument 1 is the regexp to match
 proc scan-module { args } {
     set modfilename [string tolower [lindex $args 0]].mod
-    set fd [open $modfilename r]
+    set fd [open [list | gzip -dc $modfilename] r]
     set text [read $fd]
     close $fd