1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: iobinaryo.c
6 * Input/output tool: binary format output
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2000 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 */
31
32 #include "global.h"
33 #include "eio.h"
34 #include "usr.h"
35 #include "edialogs.h"
36
37 #define FILECOPYBUFSIZE 4096
38
39 static BOOLEAN io_outputstage; /* progress of database (aborting) */
40 static INTSML *io_namesave; /* for saving the global namespace */
41 static CHAR *io_outfilename = 0; /* the name of the file being written */
42
43 /* prototypes for local routines */
44 static void io_cleanup(void);
45 static BOOLEAN io_copyfile(CHAR *src, CHAR *dst, BOOLEAN);
46 static void io_writenodeproto(NODEPROTO*, BOOLEAN);
47 static void io_writenodeinst(NODEINST*);
48 static void io_writearcinst(ARCINST*);
49 static void io_writenamespace(void);
50 static void io_restorenamespace(void);
51 static void io_writevariables(VARIABLE*, INTSML, INTBIG);
52 static void io_findxlibvariables(VARIABLE*, INTSML);
53 static void io_putoutvar(INTBIG*, INTBIG);
54 static void io_putout(void*, INTBIG);
55 static void io_putoutbig(void*);
56 static void io_putstring(CHAR*);
57
58 /*
59 * Routine to free all memory associated with this module.
60 */
io_freebinoutmemory(void)61 void io_freebinoutmemory(void)
62 {
63 if (io_outfilename != 0) efree(io_outfilename);
64 }
65
io_writebinlibrary(LIBRARY * lib,BOOLEAN nobackup)66 BOOLEAN io_writebinlibrary(LIBRARY *lib, BOOLEAN nobackup)
67 {
68 INTBIG i, a, n, p, magic, aacount, techcount, nodepprotoindex,
69 portprotoindex, portpprotoindex, arcprotoindex, nodeprotoindex, nodeindex,
70 arcindex, geomindex, curnodeproto, cellindex,
71 *curstate, cellshere, filestatus;
72 BOOLEAN err, createit;
73 time_t olddate;
74 INTBIG year, month, mday, hour, minute, second;
75 REGISTER NODEPROTO *np;
76 REGISTER ARCPROTO *ap;
77 REGISTER PORTPROTO *pp;
78 REGISTER NODEINST *ni;
79 REGISTER PORTARCINST *pi;
80 REGISTER PORTEXPINST *pe;
81 REGISTER ARCINST *ai;
82 REGISTER LIBRARY *olib;
83 REGISTER TECHNOLOGY *tech;
84 REGISTER CHAR *rename, *istrue, *dotaddr, *msg, *ext;
85 CHAR *truename, *name, *arg[3], datesuffix[30];
86 UCHAR1 wordsize;
87 REGISTER VIEW *v;
88 REGISTER void *infstr;
89
90 /* get the name of the file to write */
91 io_outputstage = FALSE;
92 dotaddr = 0;
93 ext = &lib->libfile[estrlen(lib->libfile)-5];
94 if (estrcmp(ext, x_(".elib")) == 0)
95 {
96 dotaddr = ext;
97 *ext = 0;
98 } else
99 {
100 ext = &lib->libfile[estrlen(lib->libfile)-4];
101 if (estrcmp(ext, x_(".txt")) == 0)
102 {
103 dotaddr = ext;
104 *ext = 0;
105 }
106 }
107 istrue = truepath(lib->libfile);
108 infstr = initinfstr();
109 addstringtoinfstr(infstr, istrue);
110 addstringtoinfstr(infstr, x_(".elib"));
111 err = FALSE;
112 if (io_outfilename == 0)
113 {
114 err |= allocstring(&io_outfilename, returninfstr(infstr), io_tool->cluster);
115 } else
116 {
117 err |= reallocstring(&io_outfilename, returninfstr(infstr), io_tool->cluster);
118 }
119 if (dotaddr != 0) *dotaddr = '.';
120 if (err)
121 {
122 DiaMessageInDialog(_("No memory! saving to 'PANIC'"));
123 name = _("PANIC");
124 } else
125 {
126 name = io_outfilename;
127 }
128
129 curstate = io_getstatebits();
130 if ((curstate[0]&CHECKATWRITE) != 0)
131 {
132 ttyputmsg(_("Checking all libraries..."));
133 us_checkdatabase(FALSE);
134 }
135 if (nobackup) curstate[0] &= ~(BINOUTBACKUP|CHECKATWRITE);
136
137 rename = 0;
138 createit = TRUE;
139 filestatus = fileexistence(name);
140 if ((lib->userbits&READFROMDISK) != 0)
141 {
142 /* library came from disk: write it back there unless protected */
143 if (filestatus == 3) lib->userbits &= ~READFROMDISK;
144 }
145 if ((lib->userbits&READFROMDISK) == 0) msg = _("Library File"); else
146 {
147 msg = 0;
148
149 /* if the file already exists, rename it */
150 if (filestatus == 1)
151 rename = (CHAR *)emalloc((estrlen(name)+15) * SIZEOFCHAR, el_tempcluster);
152 if (rename != 0)
153 {
154 switch (curstate[0]&BINOUTBACKUP)
155 {
156 case BINOUTNOBACK:
157 (void)estrcpy(rename, name);
158 (void)estrcat(rename, x_(".XXXXXX"));
159 if (io_copyfile(name, rename, TRUE))
160 {
161 efree(rename);
162 rename = 0;
163 }
164 createit = FALSE;
165 break;
166 case BINOUTONEBACK:
167 (void)estrcpy(rename, name);
168 (void)estrcat(rename, x_("~"));
169 if (fileexistence(rename) == 1) (void)eunlink(rename);
170 (void)io_copyfile(name, rename, FALSE);
171 createit = FALSE;
172 efree(rename);
173 rename = 0;
174 break;
175 case BINOUTFULLBACK:
176 olddate = filedate(name);
177 parsetime(olddate, &year, &month, &mday, &hour, &minute, &second);
178 for(i=0; i<1000; i++)
179 {
180 if (i == 0)
181 {
182 esnprintf(datesuffix, 30, x_("-%ld-%ld-%ld"),
183 year, month+1, mday);
184 } else
185 {
186 esnprintf(datesuffix, 30, x_("-%ld-%ld-%ld--%ld"),
187 year, month+1, mday, i);
188 }
189 (void)estrcpy(rename, name);
190 rename[estrlen(rename)-5] = 0;
191 (void)estrcat(rename, datesuffix);
192 (void)estrcat(rename, x_(".elib"));
193 if (fileexistence(rename) == 0) break;
194 }
195 (void)io_copyfile(name, rename, FALSE);
196 createit = FALSE;
197 efree(rename);
198 rename = 0;
199 break;
200 }
201 }
202 }
203
204 /* create the new library file */
205 if (createit)
206 {
207 io_fileout = xcreate(name, io_filetypeblib, msg, &truename);
208 } else
209 {
210 /* remove the ".elib" because "xopen()" adds it */
211 i = estrlen(name);
212 name[i-5] = 0;
213 io_fileout = xopen(name, io_filetypeblib|FILETYPEWRITE, 0, &truename);
214 if (io_outfilename == 0)
215 (void)allocstring(&io_outfilename, truename, io_tool->cluster); else
216 (void)reallocstring(&io_outfilename, truename, io_tool->cluster);
217 name = io_outfilename;
218 }
219 if (io_fileout == NULL)
220 {
221 if (truename != 0) DiaMessageInDialog(_("Cannot write %s"), name);
222 if (rename != 0) efree(rename);
223 return(TRUE);
224 }
225
226 /* if the user got a dialog, replace the library and file name */
227 if (msg != 0)
228 {
229 arg[0] = lib->libname;
230 arg[1] = truename;
231 arg[2] = x_("library");
232 us_rename(3, arg);
233 if (io_outfilename == 0)
234 (void)allocstring(&io_outfilename, truename, io_tool->cluster); else
235 (void)reallocstring(&io_outfilename, truename, io_tool->cluster);
236 name = io_outfilename;
237 }
238
239 if (setjmp(io_filerror) != 0)
240 {
241 DiaMessageInDialog(_("Error writing %s"), name);
242 xclose(io_fileout);
243 io_cleanup();
244 if (rename != 0)
245 {
246 ttyputmsg(_("Old binary file saved in %s"), rename);
247 efree(rename);
248 }
249 return(TRUE);
250 }
251
252 /* first flush all changes so that database is clean */
253 noundoallowed();
254
255 /* initialize the file (writing version 13) */
256 magic = MAGIC13;
257 io_putout(&magic, 4);
258 wordsize = SIZEOFINTSML; io_putout(&wordsize, 1);
259 wordsize = SIZEOFINTBIG; io_putout(&wordsize, 1);
260 wordsize = SIZEOFCHAR; io_putout(&wordsize, 1);
261 aacount = el_maxtools;
262 io_putoutbig(&aacount);
263 techcount = el_maxtech;
264 io_putoutbig(&techcount);
265
266 /* initialize the number of objects in the database */
267 nodeindex = portprotoindex = nodeprotoindex = arcindex = nodepprotoindex =
268 portpprotoindex = arcprotoindex = cellindex = 0;
269
270 /* count and number the cells, nodes, arcs, and ports in this library */
271 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
272 {
273 np->temp1 = nodeprotoindex++;
274 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
275 pp->temp1 = portprotoindex++;
276 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
277 ai->temp1 = arcindex++;
278 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
279 ni->temp1 = nodeindex++;
280 }
281 cellshere = nodeprotoindex;
282
283 /* prepare to locate references to cells in other libraries */
284 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
285 {
286 for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
287 np->temp2 = 0;
288 }
289
290 /* scan for all cross-library references */
291 io_findxlibvariables(lib->firstvar, lib->numvar);
292 for(i=0; i<el_maxtools; i++)
293 io_findxlibvariables(el_tools[i].firstvar, el_tools[i].numvar);
294 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
295 {
296 io_findxlibvariables(tech->firstvar, tech->numvar);
297 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
298 io_findxlibvariables(ap->firstvar, ap->numvar);
299 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
300 {
301 io_findxlibvariables(np->firstvar, np->numvar);
302 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
303 io_findxlibvariables(pp->firstvar, pp->numvar);
304 }
305 }
306 for(v = el_views; v != NOVIEW; v = v->nextview)
307 io_findxlibvariables(v->firstvar, v->numvar);
308 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
309 {
310 io_findxlibvariables(np->firstvar, np->numvar);
311 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
312 io_findxlibvariables(pp->firstvar, pp->numvar);
313 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
314 {
315 io_findxlibvariables(ni->firstvar, ni->numvar);
316 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
317 io_findxlibvariables(pi->firstvar, pi->numvar);
318 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
319 io_findxlibvariables(pe->firstvar, pe->numvar);
320 if (ni->proto->primindex == 0)
321 {
322 ni->proto->temp2 = 1;
323 }
324 }
325 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
326 io_findxlibvariables(ai->firstvar, ai->numvar);
327 }
328
329 /* count and number the cells in other libraries */
330 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
331 {
332 if (olib == lib) continue;
333 for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
334 {
335 if (np->temp2 == 0) continue;
336 np->temp1 = nodeprotoindex++;
337 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
338 pp->temp1 = portprotoindex++;
339 }
340 }
341
342 /* count and number the primitive node and port prototypes */
343 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
344 {
345 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
346 {
347 np->temp1 = -2 - nodepprotoindex++;
348 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
349 pp->temp1 = -2 - portpprotoindex++;
350 }
351 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
352 ap->temp1 = -2 - arcprotoindex++;
353 }
354
355 /* write number of objects */
356 io_putoutbig(&nodepprotoindex);
357 io_putoutbig(&portpprotoindex);
358 io_putoutbig(&arcprotoindex);
359 io_putoutbig(&nodeprotoindex);
360 io_putoutbig(&nodeindex);
361 io_putoutbig(&portprotoindex);
362 io_putoutbig(&arcindex);
363 io_putoutbig(&geomindex);
364
365 /* write the current cell */
366 if (lib->curnodeproto == NONODEPROTO) curnodeproto = -1; else
367 curnodeproto = lib->curnodeproto->temp1;
368 io_putoutbig(&curnodeproto);
369
370 if (io_verbose > 0)
371 {
372 ttyputmsg(M_("Writing %ld tools, %ld technologies"), aacount, techcount);
373 ttyputmsg(M_(" %ld prim nodes, %ld prim ports, %ld arc protos"),
374 nodepprotoindex, portpprotoindex, arcprotoindex);
375 ttyputmsg(M_(" %ld cells %ld cells, %ld ports, %ld nodes, %ld arcs"),
376 cellindex, nodeprotoindex, portprotoindex, nodeindex, arcindex);
377 }
378
379 /* write the version number */
380 io_putstring(el_version);
381
382 /* number the views and write nonstandard ones */
383 for(v = el_views; v != NOVIEW; v = v->nextview) v->temp1 = 0;
384 el_unknownview->temp1 = -1;
385 el_layoutview->temp1 = -2;
386 el_schematicview->temp1 = -3;
387 el_iconview->temp1 = -4;
388 el_simsnapview->temp1 = -5;
389 el_skeletonview->temp1 = -6;
390 el_vhdlview->temp1 = -7;
391 el_netlistview->temp1 = -8;
392 el_docview->temp1 = -9;
393 el_netlistnetlispview->temp1 = -10;
394 el_netlistalsview->temp1 = -11;
395 el_netlistquiscview->temp1 = -12;
396 el_netlistrsimview->temp1 = -13;
397 el_netlistsilosview->temp1 = -14;
398 el_verilogview->temp1 = -15;
399 i = 1;
400 for(v = el_views; v != NOVIEW; v = v->nextview)
401 if (v->temp1 == 0) v->temp1 = i++;
402 i--;
403 io_putoutbig(&i);
404 for(v = el_views; v != NOVIEW; v = v->nextview)
405 {
406 if (v->temp1 < 0) continue;
407 io_putstring(v->viewname);
408 io_putstring(v->sviewname);
409 }
410
411 /* write total number of arcinsts, nodeinsts, and ports in each cell */
412 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
413 {
414 for(a = 0, ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst) a++;
415 io_putoutbig(&a);
416 for(n = 0, ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst) n++;
417 io_putoutbig(&n);
418 for(p = 0, pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto) p++;
419 io_putoutbig(&p);
420 if (io_verbose > 0) ttyputmsg(M_("Cell %s has %ld arcs, %ld nodes, %ld ports"),
421 describenodeproto(np), a, n, p);
422 }
423
424 /* write dummy numbers of arcinsts and nodeinst; count ports for external cells */
425 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
426 {
427 if (olib == lib) continue;
428 for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
429 {
430 if (np->temp2 == 0) continue;
431 a = -1;
432 io_putoutbig(&a);
433 io_putoutbig(&a);
434 for(p = 0, pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto) p++;
435 io_putoutbig(&p);
436 }
437 }
438
439 /* write the names of technologies and primitive prototypes */
440 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
441 {
442 /* write the technology name */
443 io_putstring(tech->techname);
444
445 /* count and write the number of primitive node prototypes */
446 for(np = tech->firstnodeproto, i=0; np != NONODEPROTO; np = np->nextnodeproto) i++;
447 io_putoutbig(&i);
448
449 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
450 {
451 /* write the primitive node prototype name */
452 io_putstring(np->protoname);
453 for(pp = np->firstportproto, i=0; pp != NOPORTPROTO; pp = pp->nextportproto) i++;
454 io_putoutbig(&i);
455 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
456 io_putstring(pp->protoname);
457 }
458
459 /* count and write the number of arc prototypes */
460 for(ap = tech->firstarcproto, i=0; ap != NOARCPROTO; ap = ap->nextarcproto) i++;
461 io_putoutbig(&i);
462
463 /* write the primitive arc prototype names */
464 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
465 io_putstring(ap->protoname);
466 }
467
468 /* write the names of the tools */
469 for(i=0; i<el_maxtools; i++) io_putstring(el_tools[i].toolname);
470
471 /* write the userbits for the library */
472 io_putoutbig(&lib->userbits);
473
474 /* write the tool lambda values */
475 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
476 io_putoutbig(&lib->lambda[tech->techindex]);
477
478 /* write the global namespace */
479 io_writenamespace();
480 io_outputstage = TRUE;
481
482 /* write the library variables */
483 io_writevariables(lib->firstvar, lib->numvar, VLIBRARY);
484
485 /* write the tool variables */
486 for(i=0; i<el_maxtools; i++)
487 io_writevariables(el_tools[i].firstvar, el_tools[i].numvar, VTOOL);
488
489 /* write the variables on technologies */
490 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
491 io_writevariables(tech->firstvar, tech->numvar, VTECHNOLOGY);
492
493 /* write the arcproto variables */
494 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
495 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
496 io_writevariables(ap->firstvar, ap->numvar, VARCPROTO);
497
498 /* write the variables on primitive node prototypes */
499 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
500 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
501 io_writevariables(np->firstvar, np->numvar, VNODEPROTO);
502
503 /* write the variables on primitive port prototypes */
504 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
505 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
506 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
507 io_writevariables(pp->firstvar, pp->numvar, VPORTPROTO);
508
509 /* write the view variables */
510 i = 0;
511 for(v = el_views; v != NOVIEW; v = v->nextview) i++;
512 io_putoutbig(&i);
513 for(v = el_views; v != NOVIEW; v = v->nextview)
514 {
515 io_putoutbig(&v->temp1);
516 io_writevariables(v->firstvar, v->numvar, VVIEW);
517 }
518
519 /* write all of the cells in this library */
520 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
521 {
522 if (stopping(STOPREASONBINARY)) longjmp(io_filerror, 1);
523 io_writenodeproto(np, TRUE);
524 }
525
526 /* write all of the cells in external libraries */
527 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
528 {
529 if (olib == lib) continue;
530 for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
531 {
532 if (np->temp2 == 0) continue;
533 io_writenodeproto(np, FALSE);
534 }
535 }
536
537 /* write all of the arcs and nodes in this library */
538 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
539 {
540 if (stopping(STOPREASONBINARY)) longjmp(io_filerror, 1);
541 a = n = 0;
542 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
543 {
544 io_writearcinst(ai);
545 a++;
546 }
547 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
548 {
549 io_writenodeinst(ni);
550 n++;
551 }
552 if (io_verbose > 0) ttyputmsg(M_("Wrote %ld arcs and %ld nodes in cell %s"),
553 a, n, describenodeproto(np));
554 }
555
556 /* close the output file */
557 xclose(io_fileout);
558
559 /* restore any damage to the database */
560 io_cleanup();
561
562 /* if the file was renamed, kill the backup copy */
563 if (rename != 0)
564 {
565 if (eunlink(rename) < 0) ttyputerr(_("Error: cannot delete backup file %s"), rename);
566 efree(rename);
567 }
568
569 if ((lib->userbits&HIDDENLIBRARY) == 0)
570 {
571 ttyputmsg(_("%s written on %s (%ld %s)"), name,
572 timetostring(getcurrenttime()), cellshere,
573 makeplural(_("cell"), nodeprotoindex));
574 #ifdef ONUNIX
575 efprintf(stdout, _("%s written on %s (%ld %s)\n"), name,
576 timetostring(getcurrenttime()), cellshere,
577 makeplural(_("cell"), nodeprotoindex));
578 #endif
579 }
580 lib->userbits = (lib->userbits & ~(LIBCHANGEDMAJOR | LIBCHANGEDMINOR)) | READFROMDISK;
581 return(FALSE);
582 }
583
584 /*
585 * routine to clean-up the internal database after it has been modified
586 * for binary output
587 */
io_cleanup(void)588 void io_cleanup(void)
589 {
590 /* if binary output didn't get far, no cleanup needed */
591 if (!io_outputstage) return;
592
593 /* restore damage to the global namespace */
594 io_restorenamespace();
595 }
596
597 /******************** COMPONENT OUTPUT ********************/
598
io_writenodeproto(NODEPROTO * np,BOOLEAN thislib)599 void io_writenodeproto(NODEPROTO *np, BOOLEAN thislib)
600 {
601 INTBIG i;
602 REGISTER PORTPROTO *pp;
603 REGISTER LIBRARY *instlib;
604 static INTBIG nullptr = -1;
605
606 /* write cell information */
607 io_putstring(np->protoname);
608 io_putoutbig(&np->nextcellgrp->temp1);
609 if (np->nextcont != NONODEPROTO) io_putoutbig(&np->nextcont->temp1); else
610 io_putoutbig(&nullptr);
611 io_putoutbig(&np->cellview->temp1);
612 i = np->version; io_putoutbig(&i);
613 io_putoutbig(&np->creationdate);
614 io_putoutbig(&np->revisiondate);
615
616 /* write the nodeproto bounding box */
617 io_putoutbig(&np->lowx);
618 io_putoutbig(&np->highx);
619 io_putoutbig(&np->lowy);
620 io_putoutbig(&np->highy);
621
622 if (!thislib)
623 {
624 instlib = np->lib;
625 io_putstring(instlib->libfile);
626 }
627
628 /* write the number of portprotos on this nodeproto */
629 i = 0;
630 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto) i++;
631 io_putoutbig(&i);
632
633 /* write the portprotos on this nodeproto */
634 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
635 {
636 if (thislib)
637 {
638 /* write the connecting subnodeinst for this portproto */
639 if (pp->subnodeinst != NONODEINST) i = pp->subnodeinst->temp1; else
640 {
641 ttyputmsg(_("ERROR: Library %s, cell %s, export %s has no node"),
642 np->lib->libname, describenodeproto(np), pp->protoname);
643 i = -1;
644 }
645 io_putoutbig(&i);
646
647 /* write the portproto index in the subnodeinst */
648 if (pp->subnodeinst != NONODEINST && pp->subportproto != NOPORTPROTO)
649 {
650 i = pp->subportproto->temp1;
651 } else
652 {
653 if (pp->subportproto != NOPORTPROTO)
654 ttyputmsg(_("ERROR: Library %s, cell %s, export %s has no subport"),
655 np->lib->libname, describenodeproto(np), pp->protoname);
656 i = -1;
657 }
658 io_putoutbig(&i);
659 }
660
661 /* write the portproto name */
662 io_putstring(pp->protoname);
663
664 if (thislib)
665 {
666 /* write the text descriptor */
667 io_putoutbig(&pp->textdescript[0]);
668 io_putoutbig(&pp->textdescript[1]);
669
670 /* write the portproto tool information */
671 io_putoutbig(&pp->userbits);
672
673 /* write variable information */
674 io_writevariables(pp->firstvar, pp->numvar, VPORTPROTO);
675 }
676 }
677
678 if (thislib)
679 {
680 /* write tool information */
681 io_putoutbig(&np->adirty);
682 io_putoutbig(&np->userbits);
683
684 /* write variable information */
685 io_writevariables(np->firstvar, np->numvar, VNODEPROTO);
686 }
687
688 if (io_verbose > 0) ttyputmsg(M_("Wrote cell %s"), describenodeproto(np));
689 }
690
691 void io_getnodedisplayposition(NODEINST *ni, INTBIG *xpos, INTBIG *ypos);
692
693 /*
694 * Similar to "us_getnodedisplayposition()"
695 */
io_getnodedisplayposition(NODEINST * ni,INTBIG * xpos,INTBIG * ypos)696 void io_getnodedisplayposition(NODEINST *ni, INTBIG *xpos, INTBIG *ypos)
697 {
698 REGISTER NODEPROTO *np;
699 INTBIG cox, coy;
700 REGISTER INTBIG dx, dy, cx, cy;
701 REGISTER VARIABLE *var;
702 XARRAY trans;
703
704 np = ni->proto;
705 if ((us_useroptions&CENTEREDPRIMITIVES) == 0)
706 {
707 corneroffset(ni, np, ni->rotation, ni->transpose, &cox, &coy, FALSE);
708 *xpos = ni->lowx+cox;
709 *ypos = ni->lowy+coy;
710 } else
711 {
712 var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
713 cx = cy = 0;
714 if (var != NOVARIABLE)
715 {
716 cx = ((INTBIG *)var->addr)[0];
717 cy = ((INTBIG *)var->addr)[1];
718 }
719 dx = cx + (ni->lowx+ni->highx)/2 - (np->lowx+np->highx)/2;
720 dy = cy + (ni->lowy+ni->highy)/2 - (np->lowy+np->highy)/2;
721 makerot(ni, trans);
722 xform(dx, dy, &cox, &coy, trans);
723 *xpos = cox;
724 *ypos = coy;
725 }
726 }
727
io_writenodeinst(NODEINST * ni)728 void io_writenodeinst(NODEINST *ni)
729 {
730 INTBIG i, x, y;
731 REGISTER ARCINST *ai;
732 REGISTER PORTARCINST *pi;
733 REGISTER PORTEXPINST *pe;
734
735 /* write the nodeproto pointer */
736 io_putoutbig(&ni->proto->temp1);
737
738 /* write descriptive information */
739 io_putoutbig(&ni->lowx);
740 io_putoutbig(&ni->lowy);
741 io_putoutbig(&ni->highx);
742 io_putoutbig(&ni->highy);
743
744 /* if writing a cell reference, include the anchor point */
745 if (ni->proto->primindex == 0)
746 {
747 /* write the anchor point of the cell */
748 io_getnodedisplayposition(ni, &x, &y);
749 io_putoutbig(&x);
750 io_putoutbig(&y);
751 }
752
753 if (ni->transpose != 0) i = 1; else i = 0;
754 io_putoutbig(&i);
755 i = ni->rotation;
756 io_putoutbig(&i);
757
758 io_putoutbig(&ni->textdescript[0]);
759 io_putoutbig(&ni->textdescript[1]);
760
761 /* count the arc ports */
762 i = 0;
763 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst) i++;
764 io_putoutbig(&i);
765
766 /* write the arc ports */
767 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
768 {
769 /* write the arcinst index (and the particular end on that arc) */
770 ai = pi->conarcinst;
771 if (ai->end[0].portarcinst == pi) i = 0; else i = 1;
772 i = (ai->temp1 << 1) + (ai->end[0].portarcinst == pi ? 0 : 1);
773 io_putoutbig(&i);
774
775 /* write the portinst prototype */
776 io_putoutbig(&pi->proto->temp1);
777
778 /* write the variable information */
779 io_writevariables(pi->firstvar, pi->numvar, VPORTARCINST);
780 }
781
782 /* count the exports */
783 i = 0;
784 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst) i++;
785 io_putoutbig(&i);
786
787 /* write the exports */
788 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
789 {
790 io_putoutbig(&pe->exportproto->temp1);
791
792 /* write the portinst prototype */
793 io_putoutbig(&pe->proto->temp1);
794
795 /* write the variable information */
796 io_writevariables(pe->firstvar, pe->numvar, VPORTEXPINST);
797 }
798
799 /* write the tool information */
800 io_putoutbig(&ni->userbits);
801
802 /* write variable information */
803 io_writevariables(ni->firstvar, ni->numvar, VNODEINST);
804 }
805
io_writearcinst(ARCINST * arcinst)806 void io_writearcinst(ARCINST *arcinst)
807 {
808 INTBIG i;
809
810 /* write the arcproto pointer */
811 io_putoutbig(&arcinst->proto->temp1);
812
813 /* write basic arcinst information */
814 io_putoutbig(&arcinst->width);
815
816 /* write the arcinst end information */
817 for(i=0; i<2; i++)
818 {
819 io_putoutbig(&arcinst->end[i].xpos);
820 io_putoutbig(&arcinst->end[i].ypos);
821
822 /* write the arcinst's connecting nodeinst index */
823 io_putoutbig(&arcinst->end[i].nodeinst->temp1);
824 }
825
826 /* write the arcinst's tool information */
827 io_putoutbig(&arcinst->userbits);
828
829 /* write variable information */
830 io_writevariables(arcinst->firstvar, arcinst->numvar, VARCINST);
831 }
832
833 /******************** VARIABLE ROUTINES ********************/
834
835 /* routine to write the global namespace */
io_writenamespace(void)836 void io_writenamespace(void)
837 {
838 REGISTER INTBIG i;
839 INTBIG val;
840
841 val = el_numnames;
842 io_putoutbig(&val);
843 if (el_numnames == 0) return;
844
845 for(i=0; i<el_numnames; i++) io_putstring(el_namespace[i]);
846
847 io_namesave = (INTSML *)emalloc(el_numnames*SIZEOFINTSML, el_tempcluster);
848 if (io_namesave == 0)
849 {
850 ttyputerr(_("No memory! destroying internal variables to save file"));
851 ttyputerr(_("Saved file is good, memory NOT: quit when save finishes!"));
852 for(i=0; i<el_numnames; i++) *((INTSML *)el_namespace[i]) = (INTSML)i;
853 } else for(i=0; i<el_numnames; i++)
854 {
855 io_namesave[i] = *((INTSML *)el_namespace[i]);
856 *((INTSML *)el_namespace[i]) = (INTSML)i;
857 }
858 }
859
io_restorenamespace(void)860 void io_restorenamespace(void)
861 {
862 REGISTER INTBIG i;
863
864 if (el_numnames == 0) return;
865 for(i=0; i<el_numnames; i++)
866 *((INTSML *)el_namespace[i]) = io_namesave[i];
867 efree((CHAR *)io_namesave);
868 }
869
870 /*
871 * Routine to scan the variables on an object (which are in "firstvar" and "numvar")
872 * for NODEPROTO references. Any found are marked (by setting "temp2" to 1).
873 * This is used to gather cross-library references.
874 */
io_findxlibvariables(VARIABLE * firstvar,INTSML numvar)875 void io_findxlibvariables(VARIABLE *firstvar, INTSML numvar)
876 {
877 REGISTER INTBIG i;
878 REGISTER INTBIG len, type, j;
879 REGISTER VARIABLE *var;
880 REGISTER NODEPROTO *np, **nparray;
881
882 for(i=0; i<numvar; i++)
883 {
884 var = &firstvar[i];
885 type = var->type;
886 if ((type&VDONTSAVE) != 0) continue;
887 if ((type&VTYPE) != VNODEPROTO) continue;
888 if ((type&VISARRAY) != 0)
889 {
890 len = (type&VLENGTH) >> VLENGTHSH;
891 nparray = (NODEPROTO **)var->addr;
892 if (len == 0) for(len=0; nparray[len] != NONODEPROTO; len++) ;
893 for(j=0; j<len; j++)
894 {
895 np = nparray[j];
896 if (np != NONODEPROTO && np->primindex == 0)
897 {
898 np->temp2 = 1;
899 }
900 }
901 } else
902 {
903 np = (NODEPROTO *)var->addr;
904 if (np != NONODEPROTO && np->primindex == 0)
905 {
906 np->temp2 = 1;
907 }
908 }
909 }
910 }
911
io_writevariables(VARIABLE * firstvar,INTSML numvar,INTBIG type)912 void io_writevariables(VARIABLE *firstvar, INTSML numvar, INTBIG type)
913 {
914 REGISTER INTBIG i, j, datasize;
915 INTBIG num, ty, len, addr;
916
917 for(num=i=0; i<numvar; i++)
918 if ((firstvar[i].type&VDONTSAVE) == 0) num++;
919 io_putoutbig(&num);
920 for(i=0; i<numvar; i++)
921 {
922 if ((firstvar[i].type&VDONTSAVE) != 0) continue;
923 io_putout((void *)firstvar[i].key, SIZEOFINTSML);
924 ty = firstvar[i].type;
925 io_putoutbig(&ty);
926 io_putoutbig(&firstvar[i].textdescript[0]);
927 io_putoutbig(&firstvar[i].textdescript[1]);
928 addr = firstvar[i].addr;
929 if ((ty&VISARRAY) != 0)
930 {
931 len = (ty&VLENGTH) >> VLENGTHSH;
932 if ((ty&VTYPE) == VCHAR)
933 {
934 datasize = 1;
935 if (len == 0)
936 for(len=0; ((((CHAR *)addr)[len])&0377) != 0377; len++)
937 ;
938 } else if ((ty&VTYPE) == VDOUBLE)
939 {
940 datasize = SIZEOFINTBIG*2;
941 if (len == 0)
942 for(len=0; ((INTBIG *)addr)[len*2] != -1 &&
943 ((INTBIG *)addr)[len*2+1] != -1; len++)
944 ;
945 } else if ((ty&VTYPE) == VSHORT)
946 {
947 datasize = 2;
948 if (len == 0)
949 for(len=0; ((INTSML *)addr)[len] != -1; len++)
950 ;
951 } else
952 {
953 datasize = SIZEOFINTBIG;
954 if (len == 0) for(len=0; ((INTBIG *)addr)[len] != -1; len++)
955 ;
956 }
957 io_putoutbig(&len);
958 if ((ty&VTYPE) == VGENERAL)
959 {
960 for(j=0; j<len; j += 2)
961 {
962 io_putoutbig(((INTBIG *)(addr + (j+1)*datasize)));
963 io_putoutvar((INTBIG *)(addr + j*datasize), *(INTBIG *)(addr + (j+1)*datasize));
964 }
965 } else
966 {
967 for(j=0; j<len; j++) io_putoutvar((INTBIG *)(addr + j*datasize), ty);
968 }
969 } else io_putoutvar(&addr, ty);
970 }
971 }
972
io_putoutvar(INTBIG * addr,INTBIG ty)973 void io_putoutvar(INTBIG *addr, INTBIG ty)
974 {
975 REGISTER ARCINST *ai;
976 REGISTER PORTARCINST *pi;
977 REGISTER GEOM *geom;
978 REGISTER NODEPROTO *np;
979 INTBIG j;
980 static INTBIG nullptr = -1;
981
982 if ((ty&(VCODE1|VCODE2)) != 0) ty = VSTRING;
983 switch (ty&VTYPE)
984 {
985 case VADDRESS:
986 case VFRACT:
987 case VINTEGER:
988 io_putoutbig(addr);
989 break;
990 case VFLOAT:
991 io_putout(addr, sizeof(float));
992 break;
993 case VDOUBLE:
994 io_putout(addr, sizeof(double));
995 break;
996 case VBOOLEAN:
997 case VCHAR:
998 io_putout(addr, sizeof (CHAR));
999 break;
1000 case VSTRING:
1001 io_putstring((CHAR *)*addr);
1002 break;
1003 case VTECHNOLOGY:
1004 if ((TECHNOLOGY *)*addr != NOTECHNOLOGY)
1005 {
1006 j = ((TECHNOLOGY *)*addr)->techindex;
1007 io_putoutbig(&j);
1008 } else io_putoutbig(&nullptr);
1009 break;
1010 case VNODEINST:
1011 if ((NODEINST *)*addr != NONODEINST)
1012 io_putoutbig(&((NODEINST *)*addr)->temp1); else
1013 io_putoutbig(&nullptr);
1014 break;
1015 case VNODEPROTO:
1016 np = (NODEPROTO *)*addr;
1017 if (np != NONODEPROTO) io_putoutbig(&np->temp1); else
1018 io_putoutbig(&nullptr);
1019 break;
1020 case VARCPROTO:
1021 if ((ARCPROTO *)*addr != NOARCPROTO)
1022 io_putoutbig(&((ARCPROTO *)*addr)->temp1); else
1023 io_putoutbig(&nullptr);
1024 break;
1025 case VPORTPROTO:
1026 if ((PORTPROTO *)*addr != NOPORTPROTO)
1027 io_putoutbig(&((PORTPROTO *)*addr)->temp1); else
1028 io_putoutbig(&nullptr);
1029 break;
1030 case VARCINST:
1031 if ((ARCINST *)*addr != NOARCINST)
1032 io_putoutbig(&((ARCINST *)*addr)->temp1); else
1033 io_putoutbig(&nullptr);
1034 break;
1035 case VGEOM:
1036 geom = (GEOM *)*addr;
1037 if (geom->entryisnode) j = 1; else j = 0;
1038 io_putoutbig(&j);
1039 if ((INTBIG)geom->entryaddr.blind == -1) io_putoutbig(&nullptr); else
1040 {
1041 if (geom->entryisnode)
1042 io_putoutbig(&geom->entryaddr.ni->temp1); else
1043 io_putoutbig(&geom->entryaddr.ai->temp1);
1044 }
1045 break;
1046 case VPORTARCINST:
1047 pi = (PORTARCINST *)*addr;
1048 if (pi != NOPORTARCINST)
1049 {
1050 ai = pi->conarcinst;
1051 j = (ai->temp1 << 1) + (ai->end[0].portarcinst == pi ? 0 : 1);
1052 io_putoutbig(&j);
1053 } else io_putoutbig(&nullptr);
1054 break;
1055 case VPORTEXPINST:
1056 if ((PORTEXPINST *)*addr != NOPORTEXPINST)
1057 io_putoutbig(&((PORTEXPINST *)*addr)->exportproto->temp1); else
1058 io_putoutbig(&nullptr);
1059 break;
1060 case VLIBRARY:
1061 if ((LIBRARY *)*addr != NOLIBRARY)
1062 io_putstring(((LIBRARY *)*addr)->libname); else
1063 io_putstring(x_("noname"));
1064 break;
1065 case VTOOL:
1066 if ((TOOL *)*addr != NOTOOL)
1067 io_putoutbig(&((TOOL *)*addr)->toolindex); else
1068 io_putoutbig(&nullptr);
1069 break;
1070 case VSHORT:
1071 io_putout(addr, SIZEOFINTSML);
1072 break;
1073 }
1074 }
1075
1076 /******************** I/O ROUTINES ********************/
1077
1078 /*
1079 * Routine to copy file "src" to file "dst". Displays an message and returns TRUE on error.
1080 */
io_copyfile(CHAR * src,CHAR * dst,BOOLEAN tempfile)1081 BOOLEAN io_copyfile(CHAR *src, CHAR *dst, BOOLEAN tempfile)
1082 {
1083 FILE *srcf, *dstf;
1084 UCHAR1 buf[FILECOPYBUFSIZE];
1085 CHAR *truesrcname, *truedstname;
1086 REGISTER INTBIG total, written, filetype;
1087
1088 srcf = xopen(src, io_filetypeblib, 0, &truesrcname);
1089 if (srcf == NULL)
1090 {
1091 ttyputerr(_("Error: cannot open old library file %s"), src);
1092 return(TRUE);
1093 }
1094 filetype = io_filetypeblib;
1095 if (tempfile) filetype |= FILETYPETEMPFILE;
1096 dstf = xcreate(dst, filetype, 0, &truedstname);
1097 if (dstf == NULL)
1098 {
1099 xclose(srcf);
1100 ttyputerr(_("Error: cannot create new library file %s"), dst);
1101 return(TRUE);
1102 }
1103 for(;;)
1104 {
1105 total = xfread(buf, 1, FILECOPYBUFSIZE, srcf);
1106 if (total <= 0) break;
1107 written = xfwrite(buf, 1, total, dstf);
1108 if (written != total)
1109 {
1110 ttyputerr(_("Error: only wrote %ld out of %ld bytes to file %s"),
1111 written, total, truedstname);
1112 xclose(srcf);
1113 xclose(dstf);
1114 return(TRUE);
1115 }
1116 }
1117 xclose(srcf);
1118 xclose(dstf);
1119 return(FALSE);
1120 }
1121
io_putoutbig(void * data)1122 void io_putoutbig(void *data)
1123 {
1124 io_putout(data, SIZEOFINTBIG);
1125 }
1126
io_putout(void * data,INTBIG size)1127 void io_putout(void *data, INTBIG size)
1128 {
1129 REGISTER INTBIG ret;
1130
1131 if (size == 0)
1132 {
1133 ttyputmsg(_("Warning: null length data item; database may be bad"));
1134 return;
1135 }
1136 ret = xfwrite((UCHAR1 *)data, size, 1, io_fileout);
1137 if (ret == 0) longjmp(io_filerror, 1);
1138 }
1139
io_putstring(CHAR * name)1140 void io_putstring(CHAR *name)
1141 {
1142 INTBIG len;
1143
1144 len = estrlen(name);
1145 io_putoutbig(&len);
1146 if (len != 0) io_putout(name, len * SIZEOFCHAR);
1147 }
1148