From a495ada2ed9d1d351fbc89691999ae3534bb74a3 Mon Sep 17 00:00:00 2001 From: Stefan Frederik Date: Sat, 20 Nov 2021 13:33:40 +0100 Subject: [PATCH] When saving a schematic issue a warning if disk file has been changed since opening --- src/editprop.c | 1 + src/save.c | 35 ++++++++++++++++++++++++++--------- src/token.c | 19 ++++++++----------- src/xinit.c | 1 + src/xschem.h | 1 + src/xschem.tcl | 22 +++++++++++++++------- 6 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/editprop.c b/src/editprop.c index 2759ae88..eda4cb43 100644 --- a/src/editprop.c +++ b/src/editprop.c @@ -373,6 +373,7 @@ char *strtoupper(char* s) { return s; } +/* call hash_all_names() (once) before (repeatedly) using this function */ void set_inst_prop(int i) { char *ptr; diff --git a/src/save.c b/src/save.c index bc612f08..047c90f5 100644 --- a/src/save.c +++ b/src/save.c @@ -928,8 +928,9 @@ void make_symbol(void) void make_schematic(const char *schname) { FILE *fd=NULL; + rebuild_selected_array(); - if (!xctx->lastsel) return; + if(!xctx->lastsel) return; if (!(fd = fopen(schname, "w"))) { fprintf(errfp, "make_schematic(): problems opening file %s \n", schname); @@ -965,6 +966,7 @@ int save_schematic(const char *schname) /* 20171020 added return value */ FILE *fd; char name[PATH_MAX]; /* overflow safe 20161122 */ char *top_path; + struct stat buf; top_path = xctx->top_path[0] ? xctx->top_path : "."; @@ -978,6 +980,17 @@ int save_schematic(const char *schname) /* 20171020 added return value */ Tcl_VarEval(interp, "wm title ", top_path, " \"xschem - [file tail [xschem get schname]]\"", NULL); Tcl_VarEval(interp, "wm iconname ", top_path, " \"xschem - [file tail [xschem get schname]]\"", NULL); } + + if(!stat(name, &buf)) { + if(xctx->time_last_modify && xctx->time_last_modify != buf.st_mtime) { + Tcl_VarEval(interp, "ask_save \"Schematic file: ", name, + " has been changed since opening.\nSave anyway?\" 0", NULL); + if(strcmp(tclresult(), "yes") ) { + return -1; + } + } + } + if(!(fd=fopen(name,"w"))) { fprintf(errfp, "save_schematic(): problems opening file %s \n",name); @@ -987,6 +1000,10 @@ int save_schematic(const char *schname) /* 20171020 added return value */ unselect_all(); write_xschem_file(fd); fclose(fd); + /* update time stamp */ + if(!stat(name)) { + xctx->time_last_modify = buf.st_mtime; + } my_strncpy(xctx->current_name, rel_sym_path(name), S(xctx->current_name)); /* <<<<< >>>> why clear all these? */ xctx->prep_hi_structs=0; @@ -1058,6 +1075,12 @@ void load_schematic(int load_symbols, const char *filename, int reset_undo) /* 2 dbg(1, "load_schematic(): opening file for loading:%s, filename=%s\n", name, filename); dbg(1, "load_schematic(): sch[currsch]=%s\n", xctx->sch[xctx->currsch]); if(!name[0]) return; + + if(!stat(name, &buf)) { /* file exists */ + xctx->time_last_modify = buf.st_mtime; + } else { + xctx->time_last_modify = 0; + } if( (fd=fopen(name,fopen_read_mode))== NULL) { fprintf(errfp, "load_schematic(): unable to open file: %s, filename=%s\n", name, filename ? filename : ""); @@ -2208,7 +2231,6 @@ void create_sch_from_sym(void) char *dir = NULL; char *prop = NULL; char schname[PATH_MAX]; - char *savecmd=NULL; char *sub_prop; char *sub2_prop=NULL; char *str=NULL; @@ -2235,12 +2257,9 @@ void create_sch_from_sym(void) my_strncpy(schname, add_ext(abs_sym_path(xctx->inst[xctx->sel_array[0].n].name, ""), ".sch"), S(schname)); } if( !stat(schname, &buf) ) { - my_strdup(353, &savecmd, "ask_save \" create schematic file: "); - my_strcat(354, &savecmd, schname); - my_strcat(355, &savecmd, " ?\nWARNING: This schematic file already exists, it will be overwritten\""); - tcleval(savecmd); + Tcl_VarEval(interp, "ask_save \"Create schematic file: ", schname, + "?\nWARNING: This schematic file already exists, it will be overwritten\"", NULL); if(strcmp(tclresult(), "yes") ) { - my_free(914, &savecmd); return; } } @@ -2248,7 +2267,6 @@ void create_sch_from_sym(void) { fprintf(errfp, "create_sch_from_sym(): problems opening file %s \n",schname); tcleval("alert_ {file opening for write failed!} {}"); - my_free(915, &savecmd); return; } fprintf(fd, "v {xschem version=%s file_version=%s}\n", XSCHEM_VERSION, XSCHEM_FILE_VERSION); @@ -2311,7 +2329,6 @@ void create_sch_from_sym(void) } /* if(xctx->lastsel...) */ my_free(916, &dir); my_free(917, &prop); - my_free(918, &savecmd); my_free(919, &sub2_prop); my_free(920, &str); } diff --git a/src/token.c b/src/token.c index 954e9c8f..ea07057f 100644 --- a/src/token.c +++ b/src/token.c @@ -32,7 +32,7 @@ struct inst_hashentry { }; -static struct inst_hashentry *table[HASHSIZE]; +static struct inst_hashentry *table[HASHSIZE]; /* safe with multiple schematics, hash rebuilt before usage */ enum status {TOK_BEGIN, TOK_TOKEN, TOK_SEP, TOK_VALUE, TOK_END, TOK_ENDTOK}; @@ -670,7 +670,7 @@ void new_prop_string(int i, const char *old_prop, int fast, int dis_uniq_names) const char *tmp; const char *tmp2; int q,qq; - static int last[256]; + static int last[256]; /* safe to keep with multiple schematics, reset on 1st invocation */ int old_name_len; int new_name_len; int n; @@ -1690,8 +1690,7 @@ int print_spice_element(FILE *fd, int inst) /* fputs(value,fd); */ } } - else if (strcmp(token,"@symname")==0) /* of course symname must not be present */ - /* in hash table */ + else if (strcmp(token,"@symname")==0) /* of course symname must not be present in attributes */ { const char *s = skip_dir(xctx->inst[inst].name); tmp = strlen(s) +100 ; /* always make room for some extra chars @@ -1700,8 +1699,7 @@ int print_spice_element(FILE *fd, int inst) result_pos += my_snprintf(result + result_pos, tmp, "%s", s); /* fputs(s,fd); */ } - else if (strcmp(token,"@symname_ext")==0) /* of course symname must not be present */ - /* in hash table */ + else if (strcmp(token,"@symname_ext")==0) /* of course symname must not be present in attributes */ { const char *s = get_cell_w_ext(xctx->inst[inst].name, 0); tmp = strlen(s) +100 ; /* always make room for some extra chars @@ -1710,8 +1708,7 @@ int print_spice_element(FILE *fd, int inst) result_pos += my_snprintf(result + result_pos, tmp, "%s", s); /* fputs(s,fd); */ } - else if(strcmp(token,"@schname")==0) /* of course schname must not be present */ - /* in hash table */ + else if(strcmp(token,"@schname")==0) /* of course schname must not be present in attributes */ { tmp = strlen(xctx->current_name) +100 ; /* always make room for some extra chars * so 1-char writes to result do not need reallocs */ @@ -1720,8 +1717,8 @@ int print_spice_element(FILE *fd, int inst) /* fputs(xctx->current_name, fd); */ } - else if(strcmp(token,"@pinlist")==0) /* of course pinlist must not be present */ - /* in hash table. print multiplicity */ + else if(strcmp(token,"@pinlist")==0) /* of course pinlist must not be present in attributes */ + /* print multiplicity */ { /* and node number: m1 n1 m2 n2 .... */ for(i=0;iinitialized = 0; /* in_memory_undo */ #endif + xctx->time_last_modify = 0; } void delete_schematic_data(void) diff --git a/src/xschem.h b/src/xschem.h index a58ae03e..d49ffd7a 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -709,6 +709,7 @@ typedef struct { int *fill_type; /* for every layer: 0: no fill, 1, solid fill, 2: stipple fill */ int fill_pattern; int draw_window; + time_t time_last_modify; } Xschem_ctx; struct Lcc { /* used for symbols containing schematics as instances (LCC, Local Custom Cell) */ diff --git a/src/xschem.tcl b/src/xschem.tcl index dd1e6f31..3b8e33f5 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -2270,7 +2270,7 @@ proc attach_labels_to_inst {} { return {} } -proc ask_save { {ask {save file?}} } { +proc ask_save { {ask {save file?}} {cancel 1}} { global rcode wm_fix set rcode {} if { [winfo exists .dialog] } return @@ -2290,10 +2290,12 @@ proc ask_save { {ask {save file?}} } { set rcode {yes} destroy .dialog } - button .dialog.f1.b2 -text {Cancel} -command\ - { - set rcode {} - destroy .dialog + if {$cancel} { + button .dialog.f1.b2 -text {Cancel} -command\ + { + set rcode {} + destroy .dialog + } } button .dialog.f1.b3 -text {No} -command\ { @@ -2301,8 +2303,14 @@ proc ask_save { {ask {save file?}} } { destroy .dialog } pack .dialog.l1 .dialog.f1 -side top -fill x - pack .dialog.f1.b1 .dialog.f1.b2 .dialog.f1.b3 -side left -fill x -expand yes - bind .dialog {.dialog.f1.b2 invoke} + pack .dialog.f1.b1 -side left -fill x -expand yes + if { $cancel} { + pack .dialog.f1.b2 -side left -fill x -expand yes + } + pack .dialog.f1.b3 -side left -fill x -expand yes + if {$cancel} { + bind .dialog {.dialog.f1.b2 invoke} + } # needed, otherwise problems when descending with double clixk 23012004 tkwait visibility .dialog grab set .dialog