diff options
Diffstat (limited to 'sim')
-rw-r--r-- | sim/igen/lf.c | 79 | ||||
-rw-r--r-- | sim/ppc/lf.c | 85 |
2 files changed, 148 insertions, 16 deletions
diff --git a/sim/igen/lf.c b/sim/igen/lf.c index ca7a56a..9316dd6 100644 --- a/sim/igen/lf.c +++ b/sim/igen/lf.c @@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ - +#include <stdbool.h> #include <stdio.h> #include <stdarg.h> #include <ctype.h> @@ -37,7 +37,9 @@ struct _lf int line_nr; /* nr complete lines written, curr line is line_nr+1 */ int indent; int line_blank; - const char *name; + const char *name; /* Output name with diagnostics. */ + const char *filename; /* Output filename. */ + char *tmpname; /* Temporary output filename. */ const char *program; lf_file_references references; lf_file_type type; @@ -56,6 +58,7 @@ lf_open (const char *name, new_lf->references = references; new_lf->type = type; new_lf->name = (real_name == NULL ? name : real_name); + new_lf->filename = name; new_lf->program = program; /* attach to stdout if pipe */ if (!strcmp (name, "-")) @@ -65,7 +68,11 @@ lf_open (const char *name, else { /* create a new file */ - new_lf->stream = fopen (name, "w"); + char *tmpname = zalloc (strlen (name) + 5); + sprintf (tmpname, "%s.tmp", name); + new_lf->filename = name; + new_lf->tmpname = tmpname; + new_lf->stream = fopen (tmpname, "w+"); if (new_lf->stream == NULL) { perror (name); @@ -86,15 +93,73 @@ lf_get_file_type (const lf *file) void lf_close (lf *file) { - if (file->stream != stdout) + FILE *fp; + bool update = true; + + /* If we wrote to stdout, no house keeping needed. */ + if (file->stream == stdout) + return; + + /* Rename the temp file to the real file if it's changed. */ + fp = fopen (file->filename, "r"); + if (fp != NULL) { - if (fclose (file->stream)) + off_t len; + + fseek (fp, 0, SEEK_END); + len = ftell (fp); + + if (len == ftell (file->stream)) { - perror ("lf_close.fclose"); + off_t off; + size_t cnt; + char *oldbuf = zalloc (len); + char *newbuf = zalloc (len); + + rewind (fp); + off = 0; + while ((cnt = fread (oldbuf + off, 1, len - off, fp)) > 0) + off += cnt; + ASSERT (off == len); + + rewind (file->stream); + off = 0; + while ((cnt = fread (newbuf + off, 1, len - off, file->stream)) > 0) + off += cnt; + ASSERT (off == len); + + if (memcmp (oldbuf, newbuf, len) == 0) + update = false; + } + + fclose (fp); + } + + if (fclose (file->stream)) + { + perror ("lf_close.fclose"); + exit (1); + } + + if (update) + { + if (rename (file->tmpname, file->filename) != 0) + { + perror ("lf_close.rename"); + exit (1); + } + } + else + { + if (remove (file->tmpname) != 0) + { + perror ("lf_close.unlink"); exit (1); } - free (file); } + + free (file->tmpname); + free (file); } diff --git a/sim/ppc/lf.c b/sim/ppc/lf.c index c40de5b..e170a47 100644 --- a/sim/ppc/lf.c +++ b/sim/ppc/lf.c @@ -17,7 +17,7 @@ */ - +#include <stdbool.h> #include <stdio.h> #include <stdarg.h> #include <ctype.h> @@ -34,7 +34,9 @@ struct _lf { int line_nr; /* nr complete lines written, curr line is line_nr+1 */ int indent; int line_blank; - const char *name; + const char *name; /* Output name with diagnostics. */ + const char *filename; /* Output filename. */ + char *tmpname; /* Temporary output filename. */ const char *program; lf_file_references references; lf_file_type type; @@ -54,6 +56,7 @@ lf_open(const char *name, new_lf->references = references; new_lf->type = type; new_lf->name = (real_name == NULL ? name : real_name); + new_lf->filename = name; new_lf->program = program; /* attach to stdout if pipe */ if (!strcmp(name, "-")) { @@ -61,7 +64,11 @@ lf_open(const char *name, } else { /* create a new file */ - new_lf->stream = fopen(name, "w"); + char *tmpname = zalloc (strlen (name) + 5); + sprintf (tmpname, "%s.tmp", name); + new_lf->filename = name; + new_lf->tmpname = tmpname; + new_lf->stream = fopen(tmpname, "w+"); if (new_lf->stream == NULL) { perror(name); exit(1); @@ -74,13 +81,73 @@ lf_open(const char *name, void lf_close(lf *file) { - if (file->stream != stdout) { - if (fclose(file->stream)) { - perror("lf_close.fclose"); - exit(1); + FILE *fp; + bool update = true; + + /* If we wrote to stdout, no house keeping needed. */ + if (file->stream == stdout) + return; + + /* Rename the temp file to the real file if it's changed. */ + fp = fopen (file->filename, "r"); + if (fp != NULL) + { + off_t len; + + fseek (fp, 0, SEEK_END); + len = ftell (fp); + + if (len == ftell (file->stream)) + { + off_t off; + size_t cnt; + char *oldbuf = zalloc (len); + char *newbuf = zalloc (len); + + rewind (fp); + off = 0; + while ((cnt = fread (oldbuf + off, 1, len - off, fp)) > 0) + off += cnt; + ASSERT (off == len); + + rewind (file->stream); + off = 0; + while ((cnt = fread (newbuf + off, 1, len - off, file->stream)) > 0) + off += cnt; + ASSERT (off == len); + + if (memcmp (oldbuf, newbuf, len) == 0) + update = false; + } + + fclose (fp); } - free(file); - } + + if (fclose (file->stream)) + { + perror ("lf_close.fclose"); + exit (1); + } + + if (update) + { + if (rename (file->tmpname, file->filename) != 0) + { + perror ("lf_close.rename"); + exit (1); + } + } + else + { + if (remove (file->tmpname) != 0) + { + perror ("lf_close.unlink"); + exit (1); + } + } + + free (file->tmpname); + free (file); } |