From 780d7c53a8479b62fe8d90e16a3045187e347cc7 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 2 Aug 2015 21:44:04 +0100 Subject: generates files with temporary name and only overwites on change --- src/duk-libdom.c | 35 ++++++++----- src/utils.c | 149 ++++++++++++++++++++++++++++++++++++++++++++----------- src/utils.h | 14 ++++++ 3 files changed, 158 insertions(+), 40 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index bc27dfc..3e2fbe4 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -366,7 +366,7 @@ static FILE *open_header(struct interface_map *interface_map, const char *name) snprintf(fname, fnamel, "%s.h", name); /* open output file */ - hdrf = genb_fopen(fname, "w"); + hdrf = genb_fopen_tmp(fname); free(fname); if (hdrf == NULL) { return NULL; @@ -387,8 +387,17 @@ static FILE *open_header(struct interface_map *interface_map, const char *name) return hdrf; } -static int close_header(struct interface_map *interface_map, FILE *hdrf) +static int close_header(struct interface_map *interface_map, + FILE *hdrf, + const char *name) { + char *fname; + int fnamel; + + fnamel = strlen(name) + 4; + fname = malloc(fnamel); + snprintf(fname, fnamel, "%s.h", name); + fprintf(hdrf, "\n#endif\n"); /* binding postface */ @@ -396,7 +405,8 @@ static int close_header(struct interface_map *interface_map, FILE *hdrf) interface_map->binding_node, GENBIND_NODE_TYPE_POSTFACE); - fclose(hdrf); + genb_fclose_tmp(hdrf, fname); + free(fname); return 0; } @@ -1056,7 +1066,7 @@ static int output_interface(struct interface_map *interface_map, "%s.c", interfacee->class_name); /* open output file */ - ifacef = genb_fopen(interfacee->filename, "w"); + ifacef = genb_fopen_tmp(interfacee->filename); if (ifacef == NULL) { return -1; } @@ -1131,7 +1141,7 @@ static int output_interface(struct interface_map *interface_map, GENBIND_NODE_TYPE_POSTFACE); op_error: - fclose(ifacef); + genb_fclose_tmp(ifacef, interfacee->filename); return res; } @@ -1193,7 +1203,7 @@ output_private_header(struct interface_map *interface_map) } - close_header(interface_map, privf); + close_header(interface_map, privf, "private"); return 0; } @@ -1249,7 +1259,7 @@ output_prototype_header(struct interface_map *interface_map) fprintf(protof, ";\n\n"); } - close_header(interface_map, protof); + close_header(interface_map, protof, "prototype"); return 0; } @@ -1264,7 +1274,7 @@ output_makefile(struct interface_map *interface_map) FILE *makef; /* open output file */ - makef = genb_fopen("Makefile", "w"); + makef = genb_fopen_tmp("Makefile"); if (makef == NULL) { return -1; } @@ -1286,7 +1296,7 @@ output_makefile(struct interface_map *interface_map) } fprintf(makef, "\nNSGENBIND_PREFIX:=%s\n", options->outdirname); - fclose(makef); + genb_fclose_tmp(makef, "Makefile"); return 0; } @@ -1331,7 +1341,7 @@ output_binding_header(struct interface_map *interface_map) fprintf(bindf, "duk_ret_t %s_create_prototypes(duk_context *ctx);\n", DLPFX); - close_header(interface_map, bindf); + close_header(interface_map, bindf, "binding"); return 0; } @@ -1352,7 +1362,7 @@ output_binding_src(struct interface_map *interface_map) char *proto_name; /* open output file */ - bindf = genb_fopen("binding.c", "w"); + bindf = genb_fopen_tmp("binding.c"); if (bindf == NULL) { return -1; } @@ -1523,7 +1533,8 @@ output_binding_src(struct interface_map *interface_map) interface_map->binding_node, GENBIND_NODE_TYPE_POSTFACE); - fclose(bindf); + genb_fclose_tmp(bindf, "binding.c"); + return 0; } diff --git a/src/utils.c b/src/utils.c index 9e50a93..1e8ec23 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,3 +1,11 @@ +/* utility functions + * + * This file is part of nsgenbind. + * Published under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2015 Vincent Sanders + */ + #include #include #include @@ -10,34 +18,120 @@ /* exported function documented in utils.h */ char *genb_fpath(const char *fname) { - char *fpath; - int fpathl; + char *fpath; + int fpathl; + + fpathl = strlen(options->outdirname) + strlen(fname) + 2; + fpath = malloc(fpathl); + snprintf(fpath, fpathl, "%s/%s", options->outdirname, fname); + + return fpath; +} + +static char *genb_fpath_tmp(const char *fname) +{ + char *fpath; + int fpathl; - fpathl = strlen(options->outdirname) + strlen(fname) + 2; - fpath = malloc(fpathl); - snprintf(fpath, fpathl, "%s/%s", options->outdirname, fname); + fpathl = strlen(options->outdirname) + strlen(fname) + 3; + fpath = malloc(fpathl); + snprintf(fpath, fpathl, "%s/%s~", options->outdirname, fname); - return fpath; + return fpath; } /* exported function documented in utils.h */ FILE *genb_fopen(const char *fname, const char *mode) { - char *fpath; - FILE *filef; + char *fpath; + FILE *filef; + + fpath = genb_fpath(fname); + + filef = fopen(fpath, mode); + if (filef == NULL) { + fprintf(stderr, "Error: unable to open file %s (%s)\n", + fpath, strerror(errno)); + free(fpath); + return NULL; + } + free(fpath); + + return filef; +} + +/* exported function documented in utils.h */ +FILE *genb_fopen_tmp(const char *fname) +{ + char *fpath; + FILE *filef; + + fpath = genb_fpath_tmp(fname); + + filef = fopen(fpath, "w+"); + if (filef == NULL) { + fprintf(stderr, "Error: unable to open file %s (%s)\n", + fpath, strerror(errno)); + free(fpath); + return NULL; + } + free(fpath); - fpath = genb_fpath(fname); + return filef; +} - filef = fopen(fpath, mode); - if (filef == NULL) { - fprintf(stderr, "Error: unable to open file %s (%s)\n", - fpath, strerror(errno)); +int genb_fclose_tmp(FILE *filef_tmp, const char *fname) +{ + char *fpath; + char *tpath; + FILE *filef; + char tbuf[1024]; + char fbuf[1024]; + size_t trd; + size_t frd; + + fpath = genb_fpath(fname); + tpath = genb_fpath_tmp(fname); + + filef = fopen(fpath, "r"); + if (filef == NULL) { + /* unable to open target file for comparison */ + + fclose(filef_tmp); /* close tmpfile */ + + remove(fpath); + rename(tpath, fpath); + } else { + rewind(filef_tmp); + + frd = fread(fbuf, 1, 1024, filef); + while (frd != 0) { + trd = fread(tbuf, 1, frd, filef_tmp); + if ((trd != frd) || + (memcmp(tbuf, fbuf, trd) != 0)) { + /* file doesnt match */ + fclose(filef_tmp); + + remove(fpath); + rename(tpath, fpath); + + goto close_done; + } + + frd = fread(fbuf, 1, 1024, filef); + } + + /* was the same kill temporary file */ + fclose(filef_tmp); + fclose(filef); + remove(tpath); + } + +close_done: free(fpath); - return NULL; - } - free(fpath); + free(tpath); - return filef; + return 0; } @@ -45,20 +139,19 @@ FILE *genb_fopen(const char *fname, const char *mode) char *strndup(const char *s, size_t n) { - size_t len; - char *s2; + size_t len; + char *s2; - for (len = 0; len != n && s[len]; len++) - continue; + for (len = 0; len != n && s[len]; len++) + continue; - s2 = malloc(len + 1); - if (!s2) - return 0; + s2 = malloc(len + 1); + if (!s2) + return 0; - memcpy(s2, s, len); - s2[len] = 0; - return s2; + memcpy(s2, s, len); + s2[len] = 0; + return s2; } #endif - diff --git a/src/utils.h b/src/utils.h index b37d755..508d1c1 100644 --- a/src/utils.h +++ b/src/utils.h @@ -22,6 +22,20 @@ char *genb_fpath(const char *fname); */ FILE *genb_fopen(const char *fname, const char *mode); +/** + * Open file allowing for output path prefix + * + * file is opened for reading/writing with a temporary suffix allowing for the + * matching close call to check the output is different before touching the + * target file. + */ +FILE *genb_fopen_tmp(const char *fname); + +/** + * Close file opened with genb_fopen + */ +int genb_fclose_tmp(FILE *filef, const char *fname); + #ifdef _WIN32 #define NEED_STRNDUP 1 char *strndup(const char *s, size_t n); -- cgit v1.2.3