aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/module.c
diff options
context:
space:
mode:
authorJanne Blomqvist <jb@gcc.gnu.org>2013-04-17 13:19:40 +0300
committerJanne Blomqvist <jb@gcc.gnu.org>2013-04-17 13:19:40 +0300
commit070edbc29c4f4a716cc6f4d9b038c9f38f9300a0 (patch)
treebdc067d3b77ecfbdb6d53c500ae6f5cefa3c906d /gcc/fortran/module.c
parent10a883113b6d5657efeb9d3eedef1a13f97185f3 (diff)
downloadgcc-070edbc29c4f4a716cc6f4d9b038c9f38f9300a0.zip
gcc-070edbc29c4f4a716cc6f4d9b038c9f38f9300a0.tar.gz
gcc-070edbc29c4f4a716cc6f4d9b038c9f38f9300a0.tar.bz2
PR 40958 Compress module files with zlib.
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
Diffstat (limited to 'gcc/fortran/module.c')
-rw-r--r--gcc/fortran/module.c224
1 files changed, 139 insertions, 85 deletions
diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c
index 046ba48..e6a4cd7 100644
--- a/gcc/fortran/module.c
+++ b/gcc/fortran/module.c
@@ -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. */