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