/* File: save.c * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit * simulation. * Copyright (C) 1998-2020 Stefan Frederik Schippers * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "xschem.h" #ifdef __unix__ #include /* waitpid */ #endif struct Lcc *lcc; /* read an unknown xschem record usually like: text {string} text {string}.... until a '\n' (outside the '{' '}' brackets) or EOF is found. within the brackets use load_ascii_string so escapes and string newlines are correctly handled */ void read_record(int firstchar, FILE *fp) { int c; char *str = NULL; dbg(0, "\n-----1- SKIPPING -------\n"); if(firstchar != '{') dbg(0, "%c", firstchar); while((c = fgetc(fp)) != EOF) { if(c == '\n') { dbg(0, "\n"); ungetc(c, fp); /* so following read_line does not skip next line */ break; } if(c == '{') { ungetc(c, fp); load_ascii_string(&str, fp); dbg(0, "{%s}", str); } else { dbg(0, "%c", c); } } dbg(0, "------------------------\n"); my_free(881, &str); } /* skip line of text from file, stopping before '\n' or EOF */ char *read_line(FILE *fp, int dbg_level) { static char s[300]; int first = 0; s[0] = '\0'; while(fscanf(fp, "%298[^\n]s", s)>0) { if(!s[0]) break; if(!first) { dbg(dbg_level, "\n-----2- SKIPPING -------\n"); first = 1; } dbg(dbg_level, "|%s|", s); } if(first) dbg(dbg_level, "\n------------------------\n"); return s[0] ? s : NULL; } /* */ /* 20180923 */ /* return "/" */ /* example: "/xschem_undo_dj5hcG38T2" */ /* */ const char *random_string(const char *prefix) { static const char charset[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; static int random_size=10; static char str[PATH_MAX]; int prefix_size; static unsigned short once=1; int i; int idx; if(once) { srand((unsigned short) time(NULL)); once=0; } prefix_size = strlen(prefix); str[0]='/'; memcpy(str+1, prefix, prefix_size); for(i=prefix_size+1; i < prefix_size + random_size+1; i++) { idx = rand()%(sizeof(charset)-1); str[i] = charset[idx]; } str[i] ='\0'; return str; } /* */ /* 20180923 */ /* try to create a tmp directory in $HOME */ /* ${HOME}/ */ /* after 5 unsuccessfull attemps give up */ /* and return NULL */ /* */ const char *create_tmpdir(char *prefix) { static char str[PATH_MAX]; int i; struct stat buf; for(i=0; i<5;i++) { my_snprintf(str, S(str), "%s%s", tclgetvar("XSCHEM_TMP_DIR"), random_string(prefix)); if(stat(str, &buf) && !mkdir(str, 0700) ) { /* dir must not exist */ dbg(1, "created dir: %s\n", str); return str; break; } dbg(1, "failed to create %s\n", str); } fprintf(errfp, "create_tmpdir(): failed to create %s, aborting\n", str); return NULL; /* failed to create random dir 5 times */ } /* */ /* 20180924 */ /* try to create a tmp file in $HOME */ /* ${HOME}/ */ /* after 5 unsuccessfull attemps give up */ /* and return NULL */ /* */ FILE *open_tmpfile(char *prefix, char **filename) { static char str[PATH_MAX]; int i; FILE *fd; struct stat buf; for(i=0; i<5;i++) { my_snprintf(str, S(str), "%s%s", tclgetvar("XSCHEM_TMP_DIR"), random_string(prefix)); *filename = str; if(stat(str, &buf) && (fd = fopen(str, "w")) ) { /* file must not exist */ dbg(1, "created file: %s\n", str); return fd; break; } dbg(1, "failed to create %s\n", str); } fprintf(errfp, "open_tmpfile(): failed to create %s, aborting\n", str); return NULL; /* failed to create random filename 5 times */ } void updatebbox(int count, Box *boundbox, Box *tmp) { RECTORDER(tmp->x1, tmp->y1, tmp->x2, tmp->y2); /* dbg(1, "updatebbox(): count=%d, tmp = %g %g %g %g\n", count, tmp->x1, tmp->y1, tmp->x2, tmp->y2); */ if(count==1) *boundbox = *tmp; else { if(tmp->x1x1) boundbox->x1 = tmp->x1; if(tmp->x2>boundbox->x2) boundbox->x2 = tmp->x2; if(tmp->y1y1) boundbox->y1 = tmp->y1; if(tmp->y2>boundbox->y2) boundbox->y2 = tmp->y2; } } void save_ascii_string(const char *ptr, FILE *fd) { int i=0; int c; fputc('{',fd); while( ptr && (c=ptr[i++]) ) { if( c=='\\' || c=='{' || c=='}') fputc('\\',fd); fputc(c,fd); } fputc('}',fd); } void save_embedded_symbol(Instdef *s, FILE *fd) { int c, i, j; fprintf(fd, "v {xschem version=%s file_version=%s}\n", XSCHEM_VERSION, XSCHEM_FILE_VERSION); fprintf(fd, "G "); save_ascii_string(s->prop_ptr,fd); fputc('\n' ,fd); fprintf(fd, "V {}\n"); fprintf(fd, "S {}\n"); fprintf(fd, "E {}\n"); /* 20180912 */ for(c=0;clineptr[c]; for(i=0;ilines[c];i++) { fprintf(fd, "L %d %.16g %.16g %.16g %.16g ", c,ptr[i].x1, ptr[i].y1,ptr[i].x2, ptr[i].y2 ); save_ascii_string(ptr[i].prop_ptr,fd); fputc('\n' ,fd); } } for(c=0;cboxptr[c]; for(i=0;irects[c];i++) { fprintf(fd, "B %d %.16g %.16g %.16g %.16g ", c,ptr[i].x1, ptr[i].y1,ptr[i].x2, ptr[i].y2); save_ascii_string(ptr[i].prop_ptr,fd); fputc('\n' ,fd); } } for(c=0;carcptr[c]; for(i=0;iarcs[c];i++) { fprintf(fd, "A %d %.16g %.16g %.16g %.16g %.16g ", c,ptr[i].x, ptr[i].y,ptr[i].r, ptr[i].a, ptr[i].b); save_ascii_string(ptr[i].prop_ptr,fd); fputc('\n' ,fd); } } for(i=0;itexts;i++) { Text *ptr; ptr = s->txtptr; fprintf(fd, "T "); save_ascii_string(ptr[i].txt_ptr,fd); fprintf(fd, " %.16g %.16g %d %d %.16g %.16g ", ptr[i].x0, ptr[i].y0, ptr[i].rot, ptr[i].flip, ptr[i].xscale, ptr[i].yscale); save_ascii_string(ptr[i].prop_ptr,fd); fputc('\n' ,fd); } for(c=0;cpolygonptr[c]; for(i=0;ipolygons[c];i++) { fprintf(fd, "P %d %d ", c,ptr[i].points); for(j=0;j", inst_ptr[i].prop_ptr? inst_ptr[i].prop_ptr:""); lastinst++; } my_free(884, &tmp); my_free(885, &prop_ptr); } static void load_polygon(FILE *fd) { int i,c, j, points; xPolygon *ptr; const char *dash; dbg(3, "load_polygon(): start\n"); if(fscanf(fd, "%d %d",&c, &points)<2) { fprintf(errfp,"WARNING: missing fields for POLYGON object, ignoring.\n"); read_line(fd, 0); return; } if(c<0 || c>=cadlayers) { fprintf(errfp,"WARNING: wrong layer number for POLYGON object, ignoring.\n"); read_line(fd, 0); return; } check_polygon_storage(c); i=lastpolygon[c]; ptr=polygon[c]; ptr[i].x=NULL; ptr[i].y=NULL; ptr[i].selected_point=NULL; ptr[i].prop_ptr=NULL; ptr[i].x = my_calloc(321, points, sizeof(double)); ptr[i].y = my_calloc(322, points, sizeof(double)); ptr[i].selected_point= my_calloc(323, points, sizeof(unsigned short)); ptr[i].points=points; ptr[i].sel=0; for(j=0;j= 0 ? d : 0; } else { ptr[i].dash = 0; } lastpolygon[c]++; } static void load_arc(FILE *fd) { int i,c; xArc *ptr; const char *dash; dbg(3, "load_arc(): start\n"); fscanf(fd, "%d",&c); if(c<0 || c>=cadlayers) { fprintf(errfp,"WARNING: wrong layer number for ARC object, ignoring.\n"); read_line(fd, 0); return; } check_arc_storage(c); i=lastarc[c]; ptr=arc[c]; if(fscanf(fd, "%lf %lf %lf %lf %lf ",&ptr[i].x, &ptr[i].y, &ptr[i].r, &ptr[i].a, &ptr[i].b) < 5) { fprintf(errfp,"WARNING: missing fields for ARC object, ignoring\n"); read_line(fd, 0); return; } ptr[i].prop_ptr=NULL; ptr[i].sel=0; load_ascii_string(&ptr[i].prop_ptr, fd); if( !strcmp(get_tok_value(ptr[i].prop_ptr,"fill",0),"true") ) ptr[i].fill =1; else ptr[i].fill =0; dash = get_tok_value(ptr[i].prop_ptr,"dash",0); if(strcmp(dash, "")) { int d = atoi(dash); ptr[i].dash = d >= 0 ? d : 0; } else { ptr[i].dash = 0; } lastarc[c]++; } static void load_box(FILE *fd) { int i,c; Box *ptr; const char *dash; dbg(3, "load_box(): start\n"); fscanf(fd, "%d",&c); if(c<0 || c>=cadlayers) { fprintf(errfp,"WARNING: wrong layer number for xRECT object, ignoring.\n"); read_line(fd, 0); return; } check_box_storage(c); i=lastrect[c]; ptr=rect[c]; if(fscanf(fd, "%lf %lf %lf %lf ",&ptr[i].x1, &ptr[i].y1, &ptr[i].x2, &ptr[i].y2) < 4) { fprintf(errfp,"WARNING: missing fields for xRECT object, ignoring\n"); read_line(fd, 0); return; } RECTORDER(ptr[i].x1, ptr[i].y1, ptr[i].x2, ptr[i].y2); /* 20180108 */ ptr[i].prop_ptr=NULL; ptr[i].sel=0; load_ascii_string( &ptr[i].prop_ptr, fd); dash = get_tok_value(ptr[i].prop_ptr,"dash",0); if(strcmp(dash, "")) { int d = atoi(dash); ptr[i].dash = d >= 0 ? d : 0; } else { ptr[i].dash = 0; } lastrect[c]++; } static void load_line(FILE *fd) { int i,c; Line *ptr; const char *dash; dbg(3, "load_line(): start\n"); fscanf(fd, "%d",&c); if(c<0 || c>=cadlayers) { fprintf(errfp,"WARNING: Wrong layer number for LINE object, ignoring\n"); read_line(fd, 0); return; } check_line_storage(c); i=lastline[c]; ptr=line[c]; if(fscanf(fd, "%lf %lf %lf %lf ",&ptr[i].x1, &ptr[i].y1, &ptr[i].x2, &ptr[i].y2) < 4) { fprintf(errfp,"WARNING: missing fields for LINE object, ignoring\n"); read_line(fd, 0); return; } ORDER(ptr[i].x1, ptr[i].y1, ptr[i].x2, ptr[i].y2); /* 20180108 */ ptr[i].prop_ptr=NULL; ptr[i].sel=0; load_ascii_string( &ptr[i].prop_ptr, fd); if(!strcmp(get_tok_value(ptr[i].prop_ptr, "bus", 0), "true") ) ptr[i].bus = 1; else ptr[i].bus = 0; dash = get_tok_value(ptr[i].prop_ptr,"dash",0); if(strcmp(dash, "")) { int d = atoi(dash); ptr[i].dash = d >= 0 ? d : 0; } else { ptr[i].dash = 0; } lastline[c]++; } void read_xschem_file(FILE *fd) /* 20180912 */ { int i, found, endfile; char name_embedded[PATH_MAX]; char tag[1]; int inst_cnt; int version_found = 0; int ty=0; dbg(2, "read_xschem_file(): start\n"); inst_cnt = endfile = 0; file_version[0] = '\0'; while(!endfile) { if(fscanf(fd," %c",tag)==EOF) break; switch(tag[0]) { case 'v': load_ascii_string(&xschem_version_string, fd); if(xschem_version_string) { my_snprintf(file_version, S(file_version), "%s", get_tok_value(xschem_version_string, "file_version", 0)); version_found = 1; } dbg(1, "read_xschem_file(): file_version=%s\n", file_version); break; case 'E': load_ascii_string(&schtedaxprop,fd); /*20100217 */ break; case 'S': load_ascii_string(&schprop,fd); /*20100217 */ break; case 'V': load_ascii_string(&schverilogprop,fd); /*09112003 */ break; case 'K': load_ascii_string(&schsymbolprop,fd); /*09112003 */ break; case 'G': load_ascii_string(&schvhdlprop,fd); break; case 'L': load_line(fd); break; case 'P': load_polygon(fd); break; case 'A': load_arc(fd); break; case 'B': load_box(fd); break; case 'T': load_text(fd); break; case 'N': load_wire(fd); break; case 'C': load_inst(inst_cnt++, fd); break; case '[': my_strdup(324, &inst_ptr[lastinst-1].prop_ptr, subst_token(inst_ptr[lastinst-1].prop_ptr, "embed", "true")); if(inst_ptr[lastinst-1].name) { char *str; int dbg_level = 1; my_snprintf(name_embedded, S(name_embedded), "%s/.xschem_embedded_%d_%s", tclgetvar("XSCHEM_TMP_DIR"), getpid(), get_cell_w_ext(inst_ptr[lastinst-1].name, 0)); found=0; for(i=0;istrlength) my_realloc(326, &str,(strlength+=CADCHUNKALLOC)); c=fgetc(fd); if(c==EOF) { fprintf(errfp, "EOF reached, malformed {...} string input, missing close brace\n"); my_free(1149, ptr); my_free(889, &str); return; } if(begin) { if(!escape) { if(c=='}') { str[i]='\0'; break; } if(c=='\\') { escape=1; continue; } } str[i]=c; escape = 0; i++; } else if(c=='{') begin=1; } dbg(2, "load_ascii_string(): string read=%s\n",str? str:""); my_strdup(329, ptr, str); dbg(2, "load_ascii_string(): loaded %s\n",*ptr? *ptr:""); my_free(891, &str); } void make_symbol(void) { char name[1024]; /* overflow safe 20161122 */ if( strcmp(schematic[currentsch],"") ) { my_snprintf(name, S(name), "make_symbol {%s}", schematic[currentsch] ); dbg(1, "make_symbol(): making symbol: name=%s\n", name); tcleval(name); } } int save_schematic(const char *schname) /* 20171020 added return value */ { FILE *fd; char name[PATH_MAX]; /* overflow safe 20161122 */ if( strcmp(schname,"") ) my_strncpy(schematic[currentsch], schname, S(schematic[currentsch])); else return -1; dbg(1, "save_schematic(): currentsch=%d name=%s\n",currentsch, schname); dbg(1, "save_schematic(): schematic[currentsch]=%s\n", schematic[currentsch]); dbg(1, "save_schematic(): abs_sym_path=%s\n", abs_sym_path(schematic[currentsch], "")); my_strncpy(name, schematic[currentsch], S(name)); if(has_x) { tcleval( "wm title . \"xschem - [file tail [xschem get schname]]\""); /* 20161207 */ tcleval( "wm iconname . \"xschem - [file tail [xschem get schname]]\""); /* 20161207 */ } if(!(fd=fopen(name,"w"))) { fprintf(errfp, "save_schematic(): problems opening file %s \n",name); tcleval("alert_ {file opening for write failed!} {}"); /* 20171020 */ return -1; } unselect_all(); write_xschem_file(fd); fclose(fd); my_strncpy(current_name, rel_sym_path(name), S(current_name)); /* 20190519 */ prepared_hilight_structs=0; /* 20171212 */ prepared_netlist_structs=0; /* 20171212 */ prepared_hash_instances=0; /* 20171224 */ prepared_hash_wires=0; /* 20171224 */ if(!strstr(schematic[currentsch], ".xschem_embedded_")) { set_modify(0); } return 0; } void link_symbols_to_instances(void) /* 20150326 separated from load_schematic() */ { int i; char *type=NULL; /* 20150407 added static */ int cond; for(i=0;i"); my_snprintf(msg, S(msg), "alert_ {Unable to open file: %s}", filename ? filename: "(null)"); tcleval(msg); clear_drawing(); } else { clear_drawing(); dbg(1, "load_schematic(): reading file: %s\n", name); read_xschem_file(fd); fclose(fd); /* 20150326 moved before load symbols */ set_modify(0); dbg(2, "load_schematic(): loaded file:wire=%d inst=%d\n",lastwire , lastinst); if(load_symbols) link_symbols_to_instances(); if(reset_undo) { Tcl_VarEval(interp, "is_xschem_file ", schematic[currentsch], NULL); if(!strcmp(tclresult(), "SYMBOL")) { save_netlist_type = netlist_type; netlist_type = CAD_SYMBOL_ATTRS; loaded_symbol = 1; tclsetvar("netlist_type","symbol"); } else { if(loaded_symbol) { netlist_type = save_netlist_type; if(netlist_type==CAD_VHDL_NETLIST) tclsetvar("netlist_type","vhdl"); else if(netlist_type==CAD_VERILOG_NETLIST) tclsetvar("netlist_type","verilog"); else if(netlist_type==CAD_TEDAX_NETLIST) tclsetvar("netlist_type","tedax"); else if(netlist_type==CAD_SYMBOL_ATTRS) tclsetvar("netlist_type","symbol"); else tclsetvar("netlist_type","spice"); } loaded_symbol = 0; } } } dbg(1, "load_schematic(): %s, returning\n", schematic[currentsch]); } else { set_modify(0); clear_drawing(); for(i=0;;i++) { if(i == 0) my_snprintf(name, S(name), "%s.sch", "untitled"); else my_snprintf(name, S(name), "%s-%d.sch", "untitled", i); if(stat(name, &buf)) break; } my_snprintf(schematic[currentsch], S(schematic[currentsch]), "%s/%s", pwd_dir, name); my_strncpy(current_name, name, S(current_name)); /* 20190519 */ } if(has_x) { /* 20161207 moved after if( (fd=..)) */ if(strcmp(get_cell(schematic[currentsch],1), "systemlib/font")) { tcleval( "wm title . \"xschem - [file tail [xschem get schname]]\""); /* 20150417 set window and icon title */ tcleval( "wm iconname . \"xschem - [file tail [xschem get schname]]\""); } } update_conn_cues(0, 0); } #ifndef IN_MEMORY_UNDO void delete_undo(void) /* 20150327 */ { int i; char diff_name[PATH_MAX]; /* overflow safe 20161122 */ for(i=0; i %s/undo%d", undo_dirname, cur_undo_ptr%max_undo); fd = popen(diff_name,"w"); if(!fd) { fprintf(errfp, "push_undo(): failed to open write pipe %s\n", diff_name); no_undo=1; return; } #elif HAS_PIPE==1 my_snprintf(diff_name, S(diff_name), "%s/undo%d", undo_dirname, cur_undo_ptr%max_undo); pipe(pd); if((pid = fork()) ==0) { /* child process */ static char f[PATH_MAX] = ""; close(pd[1]); /* close write side of pipe */ if(!(diff_fd=freopen(diff_name,"w", stdout))) /* redirect stdout to file diff_name */ { dbg(1, "push_undo(): problems opening file %s \n",diff_name); Tcl_Eval(interp, "exit"); } /* the following 2 statements are a replacement for dup2() which is not c89 * however these are not atomic, if another thread takes stdin * in between we are in trouble */ close(0); /* close stdin */ dup(pd[0]); /* duplicate read side of pipe to stdin */ if(!f[0]) my_strncpy(f, get_file_path("gzip"), S(f)); execl(f, f, "-c", NULL); /* replace current process with comand */ /* never gets here */ fprintf(errfp, "push_undo(): problems with execl\n"); Tcl_Eval(interp, "exit"); } close(pd[0]); /* close read side of pipe */ fd=fdopen(pd[1],"w"); #else /* uncompressed undo */ my_snprintf(diff_name, S(diff_name), "%s/undo%d", undo_dirname, cur_undo_ptr%max_undo); fd = fopen(diff_name,"w"); if(!fd) { fprintf(errfp, "push_undo(): failed to open undo file %s\n", diff_name); no_undo=1; return; } #endif write_xschem_file(fd); cur_undo_ptr++; head_undo_ptr = cur_undo_ptr; tail_undo_ptr = head_undo_ptr <= max_undo? 0: head_undo_ptr-max_undo; #if HAS_POPEN==1 pclose(fd); #elif HAS_PIPE==1 fclose(fd); waitpid(pid, NULL,0); #else fclose(fd); #endif } void pop_undo(int redo) /* 20150327 */ { FILE *fd; char diff_name[PATH_MAX+12]; #if HAS_PIPE==1 int pd[2]; pid_t pid; FILE *diff_fd; #endif if(no_undo)return; if(redo) { if(cur_undo_ptr < head_undo_ptr) { dbg(1, "pop_undo(): redo; cur_undo_ptr=%d tail_undo_ptr=%d head_undo_ptr=%d\n", cur_undo_ptr, tail_undo_ptr, head_undo_ptr); cur_undo_ptr++; } else { return; } } else { /*redo=0 (undo) */ if(cur_undo_ptr == tail_undo_ptr) return; dbg(1, "pop_undo(): undo; cur_undo_ptr=%d tail_undo_ptr=%d head_undo_ptr=%d\n", cur_undo_ptr, tail_undo_ptr, head_undo_ptr); if(head_undo_ptr == cur_undo_ptr) { push_undo(); head_undo_ptr--; cur_undo_ptr--; } if(cur_undo_ptr<=0) return; /* check undo tail */ cur_undo_ptr--; } clear_drawing(); unselect_all(); #if HAS_POPEN==1 my_snprintf(diff_name, S(diff_name), "gunzip -c %s/undo%d", undo_dirname, cur_undo_ptr%max_undo); fd=popen(diff_name, "r"); if(!fd) { fprintf(errfp, "pop_undo(): failed to open read pipe %s\n", diff_name); no_undo=1; return; } #elif HAS_PIPE==1 my_snprintf(diff_name, S(diff_name), "%s/undo%d", undo_dirname, cur_undo_ptr%max_undo); pipe(pd); if((pid = fork())==0) { /* child process */ static char f[PATH_MAX] = ""; close(pd[0]); /* close read side of pipe */ if(!(diff_fd=freopen(diff_name,"r", stdin))) /* redirect stdin from file name */ { dbg(1, "pop_undo(): problems opening file %s \n",diff_name); Tcl_Eval(interp, "exit"); } /* connect write side of pipe to stdout */ close(1); /* close stdout */ dup(pd[1]); /* write side of pipe --> stdout */ if(!f[0]) my_strncpy(f, get_file_path("gunzip"), S(f)); execl(f, f, "-c", NULL); /* replace current process with command */ /* never gets here */ dbg(1, "pop_undo(): problems with execl\n"); Tcl_Eval(interp, "exit"); } close(pd[1]); /* close write side of pipe */ fd=fdopen(pd[0],"r"); #else /* uncompressed undo */ my_snprintf(diff_name, S(diff_name), "%s/undo%d", undo_dirname, cur_undo_ptr%max_undo); fd=fopen(diff_name, "r"); if(!fd) { fprintf(errfp, "pop_undo(): failed to open read pipe %s\n", diff_name); no_undo=1; return; } #endif read_xschem_file(fd); #if HAS_POPEN==1 pclose(fd); /* 20150326 moved before load symbols */ #elif HAS_PIPE==1 fclose(fd); waitpid(pid, NULL, 0); #else fclose(fd); #endif dbg(2, "pop_undo(): loaded file:wire=%d inst=%d\n",lastwire , lastinst); link_symbols_to_instances(); set_modify(1); prepared_hash_instances=0; /* 20171224 */ prepared_hash_wires=0; /* 20171224 */ prepared_netlist_structs=0; /* 20171224 */ prepared_hilight_structs=0; /* 20171224 */ update_conn_cues(0, 0); dbg(2, "pop_undo(): returning\n"); if(event_reporting) { if(redo) printf("xschem redo\n"); else printf("xschem undo\n"); printf("xschem redraw\n"); fflush(stdout); } } #endif /* ifndef IN_MEMORY_UNDO */ static int Gcurrent_sym=0; int CmpSchBbox(const void *a, const void *b) { char *labela, *labelb; const char *name; Box *boxa = (Box*)a; Box *boxb = (Box*)b; int i, aa = -1, bb = -1; labela=NULL; labelb=NULL; my_strdup(658, &labela, get_tok_value(boxa->prop_ptr, "name", 0)); my_strdup(659, &labelb, get_tok_value(boxb->prop_ptr, "name", 0)); for (i = 0; i < instdef[Gcurrent_sym].rects[PINLAYER]; ++i) { name = get_tok_value(instdef[Gcurrent_sym].boxptr[PINLAYER][i].prop_ptr, "name", 0); if (!strcmp(name, labela)) {aa = i;} if (!strcmp(name, labelb)) {bb = i;} if (aa>=0 && bb>=0) break; } my_free(896, &labela); my_free(897, &labelb); return(aa-bb); } int load_sym_def(const char *name, FILE *embed_fd) { static int recursion_counter=0; struct Lcc *lcc; /* size = level */ FILE *fd_tmp; int rot,flip; double angle; double rx1,ry1,rx2,ry2; int current_sym; int incremented_level=0; int level = 0; int max_level, save; char name2[PATH_MAX]; /* 20161122 overflow safe */ char name3[PATH_MAX]; /* 20161122 overflow safe */ char name4[PATH_MAX]; /* 20161122 overflow safe */ Box tmp,boundbox; int i,c,count=0, k, poly_points; /* 20171115 polygon stuff */ char *aux_ptr=NULL; char *prop_ptr=NULL, *symtype=NULL; double inst_x0, inst_y0; int inst_rot, inst_flip; char *symname = NULL; char tag[1]; /* overflow safe 20161122 */ int *lastl = my_malloc(333, cadlayers * sizeof(lastl)); int *lastr = my_malloc(334, cadlayers * sizeof(int)); int *lastp = my_malloc(335, cadlayers * sizeof(int)); int *lasta = my_malloc(336, cadlayers * sizeof(int)); Line **ll = my_malloc(337, cadlayers * sizeof(Line *)); Box **bb = my_malloc(338, cadlayers * sizeof(Box *)); xArc **aa = my_malloc(339, cadlayers * sizeof(xArc *)); xPolygon **pp = my_malloc(340, cadlayers * sizeof(xPolygon *)); int lastt; /* 20171115 lastp */ Text *tt; int endfile; const char *str; const char *label; char *pin_label = NULL, *recover_str=NULL; char *skip_line; const char *dash; dbg(1, "load_sym_def(): recursion_counter=%d\n", recursion_counter); recursion_counter++; dbg(1, "load_sym_def(): name=%s\n", name); lcc=NULL; my_realloc(647, &lcc, (level + 1) * sizeof(struct Lcc)); max_level = level + 1; if(!strcmp(file_version,"1.0")) { my_strncpy(name3, abs_sym_path(name, ".sym"), S(name3)); } else { my_strncpy(name3, abs_sym_path(name, ""), S(name3)); } if(!embed_fd) { if((lcc[level].fd=fopen(name3,"r"))==NULL) { if(recursion_counter == 1) dbg(0, "load_sym_def(): Symbol not found: %s\n",name3); my_snprintf(name2, S(name2), "%s/%s.sym", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/missing"); if((lcc[level].fd=fopen(name2, "r"))==NULL) { fprintf(errfp, "load_sym_def(): systemlib/missing.sym missing, I give up\n"); tcleval( "exit"); } my_strncpy(name3, name2, S(name3)); } dbg(1, "load_sym_def(): fopen1(%s), level=%d, fd=%p\n",name3, level, lcc[level].fd); } else { dbg(1, "load_sym_def(): getting embed_fd, level=%d\n", level); lcc[level].fd = embed_fd; } endfile=0; for(c=0;c=cadlayers) { fprintf(errfp,"WARNING: wrong line layer\n"); read_line(lcc[level].fd, 0); continue; } /* 20150408 */ i=lastl[c]; my_realloc(343, &ll[c],(i+1)*sizeof(Line)); if(fscanf(lcc[level].fd, "%lf %lf %lf %lf ",&ll[c][i].x1, &ll[c][i].y1, &ll[c][i].x2, &ll[c][i].y2) < 4 ) { fprintf(errfp,"WARNING: missing fields for LINE object, ignoring\n"); read_line(lcc[level].fd, 0); continue; } if (level>0) { rot = lcc[level].rot; flip = lcc[level].flip; ROTATION(0.0, 0.0, ll[c][i].x1, ll[c][i].y1, rx1, ry1); ROTATION(0.0, 0.0, ll[c][i].x2, ll[c][i].y2, rx2, ry2); ll[c][i].x1 = lcc[level].x0 + rx1; ll[c][i].y1 = lcc[level].y0 + ry1; ll[c][i].x2 = lcc[level].x0 + rx2; ll[c][i].y2 = lcc[level].y0 + ry2; } ORDER(ll[c][i].x1, ll[c][i].y1, ll[c][i].x2, ll[c][i].y2); /* 20180108 */ ll[c][i].prop_ptr=NULL; load_ascii_string( &ll[c][i].prop_ptr, lcc[level].fd); dbg(2, "l_d_s(): loaded line: ptr=%lx\n", (unsigned long)ll[c]); if(!strcmp(get_tok_value(ll[c][i].prop_ptr,"bus", 0), "true") ) ll[c][i].bus = 1; else ll[c][i].bus = 0; dash = get_tok_value(ll[c][i].prop_ptr,"dash", 0); if( strcmp(dash, "") ) { int d = atoi(dash); ll[c][i].dash = d >= 0 ? d : 0; } else ll[c][i].dash = 0; ll[c][i].sel = 0; lastl[c]++; break; case 'P': /* 20171115 */ if(fscanf(lcc[level].fd, "%d %d",&c, &poly_points) < 2 ) { fprintf(errfp,"WARNING: missing fields for POLYGON object, ignoring\n"); read_line(lcc[level].fd, 0); continue; } if(c < 0 || c>=cadlayers) { fprintf(errfp,"WARNING: wrong polygon layer\n"); read_line(lcc[level].fd, 0); continue; } /* 20150408 */ i=lastp[c]; my_realloc(344, &pp[c],(i+1)*sizeof(xPolygon)); pp[c][i].x = my_calloc(345, poly_points, sizeof(double)); pp[c][i].y = my_calloc(346, poly_points, sizeof(double)); pp[c][i].selected_point = my_calloc(347, poly_points, sizeof(unsigned short)); pp[c][i].points = poly_points; for(k=0;k0) { rot = lcc[level].rot; flip = lcc[level].flip; ROTATION(0.0, 0.0, pp[c][i].x[k], pp[c][i].y[k], rx1, ry1); pp[c][i].x[k] = lcc[level].x0 + rx1; pp[c][i].y[k] = lcc[level].y0 + ry1; } } pp[c][i].prop_ptr=NULL; load_ascii_string( &pp[c][i].prop_ptr, lcc[level].fd); /* 20180914 */ if( !strcmp(get_tok_value(pp[c][i].prop_ptr,"fill",0),"true") ) pp[c][i].fill =1; else pp[c][i].fill =0; dash = get_tok_value(pp[c][i].prop_ptr,"dash", 0); if( strcmp(dash, "") ) { int d = atoi(dash); pp[c][i].dash = d >= 0 ? d : 0; } else pp[c][i].dash = 0; pp[c][i].sel = 0; dbg(2, "l_d_s(): loaded polygon: ptr=%lx\n", (unsigned long)pp[c]); lastp[c]++; break; case 'A': fscanf(lcc[level].fd, "%d",&c); if(c < 0 || c>=cadlayers) { fprintf(errfp,"Wrong arc layer\n"); read_line(lcc[level].fd, 0); continue; } i=lasta[c]; my_realloc(348, &aa[c],(i+1)*sizeof(xArc)); if( fscanf(lcc[level].fd, "%lf %lf %lf %lf %lf ",&aa[c][i].x, &aa[c][i].y, &aa[c][i].r, &aa[c][i].a, &aa[c][i].b) < 5 ) { fprintf(errfp,"WARNING: missing fields for ARC object, ignoring\n"); read_line(lcc[level].fd, 0); continue; } if (level>0) { rot = lcc[level].rot; flip = lcc[level].flip; if (flip) { angle = 270. * rot + 180. - aa[c][i].b - aa[c][i].a; } else { angle = aa[c][i].a + rot * 270.; } angle = fmod(angle, 360.); if (angle < 0.) angle += 360.; ROTATION(0.0, 0.0, aa[c][i].x, aa[c][i].y, rx1, ry1); aa[c][i].x = lcc[level].x0 + rx1; aa[c][i].y = lcc[level].y0 + ry1; aa[c][i].a = angle; } aa[c][i].prop_ptr=NULL; load_ascii_string( &aa[c][i].prop_ptr, lcc[level].fd); if( !strcmp(get_tok_value(aa[c][i].prop_ptr,"fill",0),"true") ) aa[c][i].fill =1; else aa[c][i].fill =0; dash = get_tok_value(aa[c][i].prop_ptr,"dash", 0); if( strcmp(dash, "") ) { int d = atoi(dash); aa[c][i].dash = d >= 0 ? d : 0; } else aa[c][i].dash = 0; aa[c][i].sel = 0; dbg(2, "l_d_s(): loaded arc: ptr=%lx\n", (unsigned long)aa[c]); lasta[c]++; break; case 'B': fscanf(lcc[level].fd, "%d",&c); if(c>=cadlayers) { fprintf(errfp,"FATAL: box layer > defined cadlayers, increase cadlayers\n"); tcleval( "exit"); } /* 20150408 */ if (level>0 && c == PINLAYER) /* Don't care about pins inside SYM */ c = 7; i=lastr[c]; my_realloc(349, &bb[c],(i+1)*sizeof(Box)); fscanf(lcc[level].fd, "%lf %lf %lf %lf ",&bb[c][i].x1, &bb[c][i].y1, &bb[c][i].x2, &bb[c][i].y2); if (level>0) { rot = lcc[level].rot; flip = lcc[level].flip; ROTATION(0.0, 0.0, bb[c][i].x1, bb[c][i].y1, rx1, ry1); ROTATION(0.0, 0.0, bb[c][i].x2, bb[c][i].y2, rx2, ry2); bb[c][i].x1 = lcc[level].x0 + rx1; bb[c][i].y1 = lcc[level].y0 + ry1; bb[c][i].x2 = lcc[level].x0 + rx2; bb[c][i].y2 = lcc[level].y0 + ry2; } RECTORDER(bb[c][i].x1, bb[c][i].y1, bb[c][i].x2, bb[c][i].y2); /* 20180108 */ bb[c][i].prop_ptr=NULL; load_ascii_string( &bb[c][i].prop_ptr, lcc[level].fd); dbg(2, "l_d_s(): loaded rect: ptr=%lx\n", (unsigned long)bb[c]); dash = get_tok_value(bb[c][i].prop_ptr,"dash", 0); if( strcmp(dash, "") ) { int d = atoi(dash); bb[c][i].dash = d >= 0 ? d : 0; } else bb[c][i].dash = 0; bb[c][i].sel = 0; lastr[c]++; break; case 'T': i=lastt; my_realloc(350, &tt,(i+1)*sizeof(Text)); tt[i].txt_ptr=NULL; tt[i].font=NULL; load_ascii_string(&tt[i].txt_ptr, lcc[level].fd); fscanf(lcc[level].fd, "%lf %lf %d %d %lf %lf ",&tt[i].x0, &tt[i].y0, &tt[i].rot, &tt[i].flip, &tt[i].xscale, &tt[i].yscale); if (level>0) { const char* tmp = translate2(lcc, level, tt[i].txt_ptr); if (tmp) my_strdup(651, &tt[i].txt_ptr, tmp); ROTATION(0.0, 0.0, tt[i].x0, tt[i].y0, rx1, ry1); tt[i].x0 = lcc[level].x0 + rx1; tt[i].y0 = lcc[level].y0 + ry1; tt[i].rot = (tt[i].rot + ((lcc[level].flip && (tt[i].rot & 1)) ? lcc[level].rot + 2 : lcc[level].rot)) & 0x3; tt[i].flip = lcc[level].flip ^ tt[i].flip; } tt[i].prop_ptr=NULL; load_ascii_string(&tt[i].prop_ptr, lcc[level].fd); if(level > 0 && symtype && !strcmp(symtype, "label")) { char lay[30]; my_snprintf(lay, S(lay), " layer=%d", WIRELAYER); my_strcat(1163, &tt[i].prop_ptr, lay); } dbg(1, "l_d_s(): loaded text : t=%s p=%s\n", tt[i].txt_ptr, tt[i].prop_ptr); my_strdup(351, &tt[i].font, get_tok_value(tt[i].prop_ptr, "font", 0));/*20171206 */ str = get_tok_value(tt[i].prop_ptr, "hcenter", 0); tt[i].hcenter = strcmp(str, "true") ? 0 : 1; str = get_tok_value(tt[i].prop_ptr, "vcenter", 0); tt[i].vcenter = strcmp(str, "true") ? 0 : 1; str = get_tok_value(tt[i].prop_ptr, "layer", 0); /*20171206 */ if(str[0]) tt[i].layer = atoi(str); else tt[i].layer = -1; tt[i].flags = 0; str = get_tok_value(tt[i].prop_ptr, "slant", 0); tt[i].flags |= strcmp(str, "oblique") ? 0 : TEXT_OBLIQUE; tt[i].flags |= strcmp(str, "italic") ? 0 : TEXT_ITALIC; str = get_tok_value(tt[i].prop_ptr, "weight", 0); tt[i].flags |= strcmp(str, "bold") ? 0 : TEXT_BOLD; lastt++; break; case 'N': /* store wires as lines on layer WIRELAYER. */ i = lastl[WIRELAYER]; my_realloc(314, &ll[WIRELAYER],(i+1)*sizeof(Line)); if(fscanf(lcc[level].fd, "%lf %lf %lf %lf ",&ll[WIRELAYER][i].x1, &ll[WIRELAYER][i].y1, &ll[WIRELAYER][i].x2, &ll[WIRELAYER][i].y2) < 4 ) { fprintf(errfp,"WARNING: missing fields for LINE object, ignoring\n"); read_line(lcc[level].fd, 0); continue; } if (level>0) { rot = lcc[level].rot; flip = lcc[level].flip; ROTATION(0.0, 0.0, ll[WIRELAYER][i].x1, ll[WIRELAYER][i].y1, rx1, ry1); ROTATION(0.0, 0.0, ll[WIRELAYER][i].x2, ll[WIRELAYER][i].y2, rx2, ry2); ll[WIRELAYER][i].x1 = lcc[level].x0 + rx1; ll[WIRELAYER][i].y1 = lcc[level].y0 + ry1; ll[WIRELAYER][i].x2 = lcc[level].x0 + rx2; ll[WIRELAYER][i].y2 = lcc[level].y0 + ry2; } ORDER(ll[WIRELAYER][i].x1, ll[WIRELAYER][i].y1, ll[WIRELAYER][i].x2, ll[WIRELAYER][i].y2); /* 20180108 */ ll[WIRELAYER][i].prop_ptr=NULL; load_ascii_string( &ll[WIRELAYER][i].prop_ptr, lcc[level].fd); dbg(2, "l_d_s(): loaded line: ptr=%lx\n", (unsigned long)ll[WIRELAYER]); ll[WIRELAYER][i].dash = 0; if(!strcmp(get_tok_value(ll[WIRELAYER][i].prop_ptr, "bus", 0), "true")) ll[WIRELAYER][i].bus = 1; else ll[WIRELAYER][i].bus = 0; ll[WIRELAYER][i].sel = 0; lastl[WIRELAYER]++; break; case 'C': load_ascii_string(&symname, lcc[level].fd); dbg(1, "C line: symname=%s\n", symname); if (fscanf(lcc[level].fd, "%lf %lf %d %d", &inst_x0, &inst_y0, &inst_rot, &inst_flip) < 4) { fprintf(errfp, "WARNING: missing fields for COMPONENT object, ignoring\n"); read_line(lcc[level].fd, 0); continue; } load_ascii_string(&prop_ptr, lcc[level].fd); if(level + 1 >=CADMAXHIER) { fprintf(errfp, "Symbol recursively instantiating symbol: max depth reached, skipping\n"); if(has_x) tcleval("alert_ {Symbol recursively instantiating symbol: max depth reached, skipping} {} 1"); endfile = 1; continue; } lastinstdef++; /* do not allow match_symbol() to overwrite current symbol we are loading */ save = lastinstdef; dbg(1, "load_sym_def(): call1 match_symbol\n"); if ((recover_str = strrchr(symname, '.')) && !strcmp(recover_str, ".sch")) current_sym = match_symbol(add_ext(symname, ".sym")); else current_sym=match_symbol(symname); my_strdup2(316, &symtype, instdef[current_sym].type); dbg(1, "load_sym_def(): level=%d, current_sym=%d symname=%s symtype=%s\n", level, current_sym, symname, symtype); if(lastinstdef> save) remove_symbol(lastinstdef - 1); /* if previous match_symbol() caused a symbol to be loaded unload it now */ lastinstdef--; /* restore symbol we are loading */ if( /* add here symbol types not to consider when loading schematic-as-symbol instances */ !strcmp(symtype, "logo") || !strcmp(symtype, "netlist_commands") || !strcmp(symtype, "arch_declarations") || !strcmp(symtype, "architecture") || !strcmp(symtype, "attributes") || !strcmp(symtype, "package") || !strcmp(symtype, "port_attributes") || !strcmp(symtype, "use") || !strcmp(symtype, "launcher") || !strcmp(symtype, "verilog_preprocessor") || !strcmp(symtype, "timescale") ) break; /* add PINLAYER boxes (symbol pins) at schematic i/o/iopin coordinates. */ if (level==0 && (!strcmp(symtype, "ipin") || !strcmp(symtype, "opin") || !strcmp(symtype, "iopin"))) { i = lastr[PINLAYER]; my_realloc(652, &bb[PINLAYER], (i + 1) * sizeof(Box)); bb[PINLAYER][i].x1 = inst_x0 - 2.5; bb[PINLAYER][i].x2 = inst_x0 + 2.5; bb[PINLAYER][i].y1 = inst_y0 - 2.5; bb[PINLAYER][i].y2 = inst_y0 + 2.5; RECTORDER(bb[PINLAYER][i].x1, bb[PINLAYER][i].y1, bb[PINLAYER][i].x2, bb[PINLAYER][i].y2); /* 20180108 */ bb[PINLAYER][i].prop_ptr = NULL; label = get_tok_value(prop_ptr, "lab", 0); save = strlen(label)+30; pin_label = my_malloc(315, save); pin_label[0] = '\0'; if (!strcmp(symtype, "ipin")) { my_snprintf(pin_label, save, "name=%s dir=in ", label); } else if (!strcmp(symtype, "opin")) { my_snprintf(pin_label, save, "name=%s dir=out ", label); } else if (!strcmp(symtype, "iopin")) { my_snprintf(pin_label, save, "name=%s dir=inout ", label); } my_strdup(463, &bb[PINLAYER][i].prop_ptr, pin_label); bb[PINLAYER][i].dash = 0; bb[PINLAYER][i].sel = 0; /* add to symbol pins remaining attributes from schematic pins, except name= and lab= */ my_strdup(157, &pin_label, get_sym_template(prop_ptr, "lab")); /* remove name=... and lab=... */ my_strcat(159, &bb[PINLAYER][i].prop_ptr, pin_label); my_free(900, &pin_label); lastr[PINLAYER]++; } if (!strcmp(file_version, "1.0")) { my_strncpy(name4, abs_sym_path(symname, ".sym"), S(name4)); } else { my_strncpy(name4, abs_sym_path(symname, ""), S(name4)); } /* replace i/o/iopin.sym with better looking (for symbol) pins */ if(level == 0) { if (!strcmp(symtype, "ipin")) { my_snprintf(name4, S(name4), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/ipin_lcc_top.sym"); } else if (!strcmp(symtype, "opin")) { my_snprintf(name4, S(name4), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/opin_lcc_top.sym"); } else if (!strcmp(symtype, "iopin")) { my_snprintf(name4, S(name4), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/iopin_lcc_top.sym"); } } else { if (!strcmp(symtype, "ipin")) { my_snprintf(name4, S(name4), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/ipin_lcc.sym"); } else if (!strcmp(symtype, "opin")) { my_snprintf(name4, S(name4), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/opin_lcc.sym"); } else if (!strcmp(symtype, "iopin")) { my_snprintf(name4, S(name4), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/iopin_lcc.sym"); } } if ((fd_tmp = fopen(name4, "r")) == NULL) { fprintf(errfp, "load_sym_def(): unable to open file to read schematic: %s\n", name4); } else { if (level+1 >= max_level) { my_realloc(653, &lcc, (max_level + 1) * sizeof(struct Lcc)); max_level++; } dbg(1, "load_sym_def(): fopen2(%s), level=%d, fd=%p\n", name4, level, fd_tmp); ++level; incremented_level = 1; lcc[level].fd = fd_tmp; lcc[level].prop_ptr = NULL; lcc[level].symname = NULL; lcc[level].x0 = inst_x0; lcc[level].y0 = inst_y0; lcc[level].rot = inst_rot; lcc[level].flip = inst_flip; /* calculate LCC sub-schematic x0, y0, rotation and flip */ if (level > 1) { int rot, flip; static int map[4]={0,3,2,1}; flip = lcc[level-1].flip; rot = lcc[level-1].rot; ROTATION(0.0, 0.0, lcc[level].x0, lcc[level].y0,lcc[level].x0, lcc[level].y0); lcc[level].rot = (lcc[(level-1)].flip ? map[lcc[level].rot] : lcc[level].rot) + lcc[(level-1)].rot; lcc[level].rot &= 0x3; lcc[level].flip = lcc[level].flip ^ lcc[level-1].flip; lcc[level].x0 += lcc[(level-1)].x0; lcc[level].y0 += lcc[(level-1)].y0; } my_strdup(654, &lcc[level].prop_ptr, prop_ptr); my_strdup(657, &lcc[level].symname, symname); dbg(1, "level incremented: level=%d, symname=%s, name4=%s\n", level, symname, name4); } break; case '[': read_line(lcc[level].fd, 0); fscanf(lcc[level].fd, "\n"); while(1) { /* skip embedded [ ... ] */ skip_line = read_line(lcc[level].fd, 0); if(!skip_line) { break; } if(!strcmp(skip_line, "]")) break; fscanf(lcc[level].fd, "\n"); } break; case ']': read_line(lcc[level].fd, 0); endfile=1; break; default: if( tag[0] == '{' ) ungetc(tag[0], lcc[level].fd); read_record(tag[0], lcc[level].fd); break; } /* if a 'C' line was encountered and level was incremented, rest of line must be read with lcc[level-1].fd file pointer */ if(incremented_level) read_line(lcc[level-1].fd, 0); /* discard any remaining characters till (but not including) newline */ else read_line(lcc[level].fd, 0); /* discard any remaining characters till (but not including) newline */ } if(!embed_fd) { dbg(1, "load_sym_def(): fclose2, level=%d, fd=%p\n", level, lcc[0].fd); fclose(lcc[0].fd); } if(embed_fd || strstr(name, ".xschem_embedded_")) { instdef[lastinstdef].flags |= EMBEDDED; } else { instdef[lastinstdef].flags &= ~EMBEDDED; } dbg(2, "l_d_s(): finished parsing file\n"); for(c=0;c x2) x2 = pp[c][i].x[k]; if(k==0 || pp[c][i].y[k] > y2) y2 = pp[c][i].y[k]; } tmp.x1=x1;tmp.y1=y1;tmp.x2=x2;tmp.y2=y2; updatebbox(count,&boundbox,&tmp); } } /* * do not include symbol text in bounding box, since text length * is variable from one instance to another. * * for(i=0;i save) remove_symbol(lastinstdef - 1); /* if previous match_symbol() caused a symbol to be loaded unload it now */ } recursion_counter--; dbg(1, "load_sym_def(): exiting, recursion_counter=%d\n", recursion_counter); return 1; } /* 20171004 */ void create_sch_from_sym(void) { Instdef *ptr; int i, j, npin, ypos; double x; int p=0; Box *rect; FILE *fd; char *pindir[3] = {"in", "out", "inout"}; char *pinname[3] = {"devices/ipin.sym", "devices/opin.sym", "devices/iopin.sym"}; char *generic_pin = {"devices/generic_pin.sym"}; char *pinname2[3] = {"ipin.sym", "opin.sym", "iopin.sym"}; char *generic_pin2 = {"generic_pin.sym"}; int indirect; char *dir = NULL; char *prop = NULL; char schname[PATH_MAX]; char *savecmd=NULL; char *sub_prop; char *sub2_prop=NULL; char *str=NULL; struct stat buf; int ln; if(!stat(abs_sym_path(pinname[0], ""), &buf)) { indirect=1; } else { indirect=0; } /* printf("indirect=%d\n", indirect); */ rebuild_selected_array(); if(lastselected > 1) return; if(lastselected==1 && selectedgroup[0].type==ELEMENT) { my_strncpy(schname, abs_sym_path(get_tok_value( (inst_ptr[selectedgroup[0].n].ptr+instdef)->prop_ptr, "schematic",0 ), "") , S(schname)); if(!schname[0]) { my_strncpy(schname, add_ext(abs_sym_path(inst_ptr[selectedgroup[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); if(strcmp(tclresult(), "yes") ) { my_free(914, &savecmd); return; } } if(!(fd=fopen(schname,"w"))) { fprintf(errfp, "create_sch_from_sym(): problems opening file %s \n",schname); tcleval("alert_ {file opening for write failed!} {}"); /* 20171020 */ my_free(915, &savecmd); return; } fprintf(fd, "v {xschem version=%s file_version=%s}\n", XSCHEM_VERSION, XSCHEM_FILE_VERSION); fprintf(fd, "G {}"); fputc('\n', fd); fprintf(fd, "V {}"); fputc('\n', fd); fprintf(fd, "E {}"); /* 20180912 */ fputc('\n', fd); fprintf(fd, "S {}"); fputc('\n', fd); ptr = inst_ptr[selectedgroup[0].n].ptr+instdef; npin = ptr->rects[GENERICLAYER]; rect = ptr->boxptr[GENERICLAYER]; ypos=0; for(i=0;irects[PINLAYER]; rect = ptr->boxptr[PINLAYER]; for(j=0;j<3;j++) { if(j==1) ypos=0; for(i=0;i 1) return; /*20121122 */ if(lastselected==1 && selectedgroup[0].type==ELEMENT) { if(modified) { /* 20161209 */ if(save(1)) return; } my_snprintf(name, S(name), "%s", inst_ptr[selectedgroup[0].n].name); /* dont allow descend in the default missing symbol */ if((inst_ptr[selectedgroup[0].n].ptr+instdef)->type && !strcmp( (inst_ptr[selectedgroup[0].n].ptr+instdef)->type,"missing")) return; } else return; /* build up current hierarchy path */ my_strdup(363, &str, inst_ptr[selectedgroup[0].n].instname); /* 20180911 */ my_strdup(364, &sch_path[currentsch+1], sch_path[currentsch]); my_strcat(365, &sch_path[currentsch+1], str); my_strcat(366, &sch_path[currentsch+1], "."); sch_inst_number[currentsch+1] = 1; my_free(921, &str); previous_instance[currentsch]=selectedgroup[0].n; zoom_array[currentsch].x=xorigin; zoom_array[currentsch].y=yorigin; zoom_array[currentsch].zoom=zoom; ++currentsch; if((inst_ptr[selectedgroup[0].n].ptr+instdef)->flags & EMBEDDED || !strcmp(get_tok_value(inst_ptr[selectedgroup[0].n].prop_ptr,"embed", 0), "true")) { /* save embedded symbol into a temporary file */ my_snprintf(name_embedded, S(name_embedded), "%s/.xschem_embedded_%d_%s", tclgetvar("XSCHEM_TMP_DIR"), getpid(), get_cell_w_ext(name, 0)); if(!(fd = fopen(name_embedded, "w")) ) { fprintf(errfp, "descend_symbol(): problems opening file %s \n", name_embedded); } save_embedded_symbol(inst_ptr[selectedgroup[0].n].ptr+instdef, fd); fclose(fd); unselect_all(); remove_symbols(); /* must follow save (if) embedded */ /* load_symbol(name_embedded); */ load_schematic(1, name_embedded, 1); } else { /* load_symbol(abs_sym_path(name, "")); */ unselect_all(); remove_symbols(); /* must follow save (if) embedded */ load_schematic(1, abs_sym_path(name, ""), 1); } zoom_full(1, 0); } /* 20111023 align selected object to current grid setting */ #define SNAP_TO_GRID(a) (a=ROUND(( a)/cadsnap)*cadsnap ) void round_schematic_to_grid(double cadsnap) { int i, c, n, p; rebuild_selected_array(); for(i=0;i