Commit 070edbc2 by Janne Blomqvist

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
parent 10a88311
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> 2013-04-16 Tobias Burnus <burnus@net-b.de>
PR fortran/39505 PR fortran/39505
......
...@@ -369,3 +369,5 @@ fortran/resolve.o: fortran/dependency.h fortran/data.h fortran/target-memory.h ...@@ -369,3 +369,5 @@ fortran/resolve.o: fortran/dependency.h fortran/data.h fortran/target-memory.h
fortran/data.o: fortran/data.h fortran/data.o: fortran/data.h
fortran/options.o: $(PARAMS_H) $(TARGET_H) fortran/cpp.h fortran/options.o: $(PARAMS_H) $(TARGET_H) fortran/cpp.h
fortran/cpp.o: fortran/cpp.c incpath.h incpath.o cppbuiltin.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
...@@ -71,15 +71,18 @@ along with GCC; see the file COPYING3. If not see ...@@ -71,15 +71,18 @@ along with GCC; see the file COPYING3. If not see
#include "arith.h" #include "arith.h"
#include "match.h" #include "match.h"
#include "parse.h" /* FIXME */ #include "parse.h" /* FIXME */
#include "md5.h"
#include "constructor.h" #include "constructor.h"
#include "cpp.h" #include "cpp.h"
#include "tree.h" #include "tree.h"
#include "scanner.h"
#include <zlib.h>
#define MODULE_EXTENSION ".mod" #define MODULE_EXTENSION ".mod"
/* Don't put any single quote (') in MOD_VERSION, /* Don't put any single quote (') in MOD_VERSION, if you want it to be
if yout want it to be recognized. */ recognized.
TODO: When the version is bumped, remove the extra empty line at
the beginning of module files. */
#define MOD_VERSION "10" #define MOD_VERSION "10"
...@@ -180,11 +183,9 @@ pointer_info; ...@@ -180,11 +183,9 @@ pointer_info;
/* Local variables */ /* Local variables */
/* The FILE for the module we're reading or writing. */ /* The gzFile for the module we're reading or writing. */
static FILE *module_fp; static gzFile module_fp;
/* MD5 context structure. */
static struct md5_ctx ctx;
/* The name of the module we're reading (USE'ing) or writing. */ /* The name of the module we're reading (USE'ing) or writing. */
static const char *module_name; static const char *module_name;
...@@ -976,6 +977,76 @@ free_true_name (true_name *t) ...@@ -976,6 +977,76 @@ free_true_name (true_name *t)
/* Module reading and writing. */ /* 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 typedef enum
{ {
ATOM_NAME, ATOM_LPAREN, ATOM_RPAREN, ATOM_INTEGER, ATOM_STRING ATOM_NAME, ATOM_LPAREN, ATOM_RPAREN, ATOM_INTEGER, ATOM_STRING
...@@ -1463,12 +1534,9 @@ read_string (void) ...@@ -1463,12 +1534,9 @@ read_string (void)
static void static void
write_char (char out) 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)); 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') if (out != '\n')
module_column++; module_column++;
else else
...@@ -5407,61 +5475,47 @@ write_module (void) ...@@ -5407,61 +5475,47 @@ write_module (void)
} }
/* Read a MD5 sum from the header of a module file. If the file cannot /* Read a CRC32 sum from the gzip trailer of a module file. Returns
be opened, or we have any other error, we return -1. */ true on success, false on failure. */
static int static bool
read_md5_from_module_file (const char * filename, unsigned char md5[16]) read_crc32_from_module_file (const char* filename, uLong* crc)
{ {
FILE *file; FILE *file;
char buf[1024]; char buf[4];
int n; unsigned int val;
/* Open the file. */ /* Open the file in binary mode. */
if ((file = fopen (filename, "r")) == NULL) if ((file = fopen (filename, "rb")) == NULL)
return -1; return false;
/* Read the first line. */ /* The gzip crc32 value is found in the [END-8, END-4] bytes of the
if (fgets (buf, sizeof (buf) - 1, file) == NULL) file. See RFC 1952. */
if (fseek (file, -8, SEEK_END) != 0)
{ {
fclose (file); fclose (file);
return -1; return false;
} }
/* The file also needs to be overwritten if the version number changed. */ /* Read the CRC32. */
n = strlen ("GFORTRAN module version '" MOD_VERSION "' created"); if (fread (buf, 1, 4, file) != 4)
if (strncmp (buf, "GFORTRAN module version '" MOD_VERSION "' created", n) != 0)
{ {
fclose (file); fclose (file);
return -1; return false;
}
/* Read a second line. */
if (fgets (buf, sizeof (buf) - 1, file) == NULL)
{
fclose (file);
return -1;
} }
/* Close the file. */ /* Close the file. */
fclose (file); fclose (file);
/* If the header is not what we expect, or is too short, bail out. */ val = (buf[0] & 0xFF) + ((buf[1] & 0xFF) << 8) + ((buf[2] & 0xFF) << 16)
if (strncmp (buf, "MD5:", 4) != 0 || strlen (buf) < 4 + 16) + ((buf[3] & 0xFF) << 24);
return -1; *crc = val;
/* Now, we have a real MD5, read it into the array. */ /* For debugging, the CRC value printed in hexadecimal should match
for (n = 0; n < 16; n++) the CRC printed by "zcat -l -v filename".
{ printf("CRC of file %s is %x\n", filename, val); */
unsigned int x;
if (sscanf (&(buf[4+2*n]), "%02x", &x) != 1)
return -1;
md5[n] = x;
}
return 0; return true;
} }
...@@ -5474,8 +5528,7 @@ gfc_dump_module (const char *name, int dump_flag) ...@@ -5474,8 +5528,7 @@ gfc_dump_module (const char *name, int dump_flag)
{ {
int n; int n;
char *filename, *filename_tmp; char *filename, *filename_tmp;
fpos_t md5_pos; uLong crc, crc_old;
unsigned char md5_new[16], md5_old[16];
n = strlen (name) + strlen (MODULE_EXTENSION) + 1; n = strlen (name) + strlen (MODULE_EXTENSION) + 1;
if (gfc_option.module_dir != NULL) if (gfc_option.module_dir != NULL)
...@@ -5509,20 +5562,18 @@ gfc_dump_module (const char *name, int dump_flag) ...@@ -5509,20 +5562,18 @@ gfc_dump_module (const char *name, int dump_flag)
gfc_cpp_add_target (filename); gfc_cpp_add_target (filename);
/* Write the module to the temporary file. */ /* Write the module to the temporary file. */
module_fp = fopen (filename_tmp, "w"); module_fp = gzopen (filename_tmp, "w");
if (module_fp == NULL) if (module_fp == NULL)
gfc_fatal_error ("Can't open module file '%s' for writing at %C: %s", gfc_fatal_error ("Can't open module file '%s' for writing at %C: %s",
filename_tmp, xstrerror (errno)); filename_tmp, xstrerror (errno));
/* Write the header, including space reserved for the MD5 sum. */ /* Write the header.
fprintf (module_fp, "GFORTRAN module version '%s' created from %s\n" FIXME: For backwards compatibility with the old uncompressed
"MD5:", MOD_VERSION, gfc_source_file); module format, write an extra empty line. When the module version
fgetpos (module_fp, &md5_pos); is bumped, this can be removed. */
fputs ("00000000000000000000000000000000 -- " gzprintf (module_fp, "GFORTRAN module version '%s' created from %s\n\n",
"If you edit this, you'll get what you deserve.\n\n", module_fp); MOD_VERSION, gfc_source_file);
/* Initialize the MD5 context that will be used for output. */
md5_init_ctx (&ctx);
/* Write the module itself. */ /* Write the module itself. */
iomode = IO_OUTPUT; iomode = IO_OUTPUT;
...@@ -5537,24 +5588,17 @@ gfc_dump_module (const char *name, int dump_flag) ...@@ -5537,24 +5588,17 @@ gfc_dump_module (const char *name, int dump_flag)
write_char ('\n'); write_char ('\n');
/* Write the MD5 sum to the header of the module file. */ if (gzclose (module_fp))
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))
gfc_fatal_error ("Error writing module file '%s' for writing: %s", gfc_fatal_error ("Error writing module file '%s' for writing: %s",
filename_tmp, xstrerror (errno)); filename_tmp, xstrerror (errno));
/* Read the MD5 from the header of the old module file and compare. */ /* Read the CRC32 from the gzip trailers of the module files and
if (read_md5_from_module_file (filename, md5_old) != 0 compare. */
|| memcmp (md5_old, md5_new, sizeof (md5_old)) != 0) 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. */ /* 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)) if (rename (filename_tmp, filename))
gfc_fatal_error ("Can't rename module file '%s' to '%s': %s", gfc_fatal_error ("Can't rename module file '%s' to '%s': %s",
filename_tmp, filename, xstrerror (errno)); filename_tmp, filename, xstrerror (errno));
...@@ -6023,17 +6067,27 @@ create_derived_type (const char *name, const char *modname, ...@@ -6023,17 +6067,27 @@ create_derived_type (const char *name, const char *modname,
static void static void
read_module_to_tmpbuf () read_module_to_tmpbuf ()
{ {
/* Find out the size of the file and reserve space. Assume we're at /* We don't know the uncompressed size, so enlarge the buffer as
the beginning. */ needed. */
fseek (module_fp, 0, SEEK_END); int cursz = 4096;
long file_size = ftell (module_fp); int rsize = cursz;
fseek (module_fp, 0, SEEK_SET); int len = 0;
module_content = XNEWVEC (char, cursz);
/* An extra byte for the terminating NULL. */ while (1)
module_content = XNEWVEC (char, file_size + 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 = XRESIZEVEC (char, module_content, len + 1);
module_content[file_size] = '\0'; module_content[len] = '\0';
module_pos = 0; module_pos = 0;
} }
...@@ -6254,7 +6308,7 @@ gfc_use_module (gfc_use_list *module) ...@@ -6254,7 +6308,7 @@ gfc_use_module (gfc_use_list *module)
specified that the module is intrinsic. */ specified that the module is intrinsic. */
module_fp = NULL; module_fp = NULL;
if (!module->intrinsic) 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 /* Then, see if it's an intrinsic one, unless the USE statement
specified that the module is non-intrinsic. */ specified that the module is non-intrinsic. */
...@@ -6283,7 +6337,7 @@ gfc_use_module (gfc_use_list *module) ...@@ -6283,7 +6337,7 @@ gfc_use_module (gfc_use_list *module)
return; return;
} }
module_fp = gfc_open_intrinsic_module (filename); module_fp = gzopen_intrinsic_module (filename);
if (module_fp == NULL && module->intrinsic) if (module_fp == NULL && module->intrinsic)
gfc_fatal_error ("Can't find an intrinsic module named '%s' at %C", gfc_fatal_error ("Can't find an intrinsic module named '%s' at %C",
...@@ -6308,7 +6362,7 @@ gfc_use_module (gfc_use_list *module) ...@@ -6308,7 +6362,7 @@ gfc_use_module (gfc_use_list *module)
start = 0; start = 0;
read_module_to_tmpbuf (); read_module_to_tmpbuf ();
fclose (module_fp); gzclose (module_fp);
/* Skip the first two lines of the module, after checking that this is /* Skip the first two lines of the module, after checking that this is
a gfortran module file. */ a gfortran module file. */
......
...@@ -48,18 +48,10 @@ along with GCC; see the file COPYING3. If not see ...@@ -48,18 +48,10 @@ along with GCC; see the file COPYING3. If not see
#include "debug.h" #include "debug.h"
#include "flags.h" #include "flags.h"
#include "cpp.h" #include "cpp.h"
#include "scanner.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;
/* List of include file search directories. */ /* 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; static gfc_file *file_head, *current_file;
......
/* 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;
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> 2013-04-16 Naveen H.S <Naveen.Hurugalawadi@caviumnetworks.com>
* gcc.target/aarch64/adds3.c: New. * gcc.target/aarch64/adds3.c: New.
......
! 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" } }
...@@ -633,7 +633,7 @@ proc cleanup-saved-temps { args } { ...@@ -633,7 +633,7 @@ proc cleanup-saved-temps { args } {
# Argument 1 is the regexp to match # Argument 1 is the regexp to match
proc scan-module { args } { proc scan-module { args } {
set modfilename [string tolower [lindex $args 0]].mod 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] set text [read $fd]
close $fd close $fd
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment