1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: iobinaryi.c
6  * Input/output tool: binary format input
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 #include "global.h"
32 #include "database.h"
33 #include "eio.h"
34 #include "tech.h"
35 #include "tecgen.h"
36 #include "tecart.h"
37 #include "tecschem.h"
38 #include "tecmocmos.h"
39 #include "tecmocmossub.h"
40 #include "edialogs.h"
41 #include "usr.h"
42 
43 #define REPORTINC   2000			/* bytes between graphical updates */
44 
45 #define LONGJMPABORTED 1			/* for "Aborted" */
46 #define LONGJMPEOF     2			/* for "Premature end of file" */
47 
48 typedef struct
49 {
50 	BOOLEAN      toolbitsmessed;	/* 0: tool order is correct */
51 	INTBIG       aabcount;			/* number of toolbits for old files */
52 	INTBIG       bytecount;			/* position within input file */
53 	CHAR       **realname;			/* variable names */
54 	INTBIG       namecount;			/* number of variable names */
55 	INTBIG       filelength;		/* length of the file */
56 	INTBIG       reported;			/* reported progress in file */
57 	UCHAR1       sizeofsmall;		/* number of bytes in file for an INTSML */
58 	UCHAR1       sizeofbig;			/* number of bytes in file for an INTBIG */
59 	UCHAR1       sizeofchar;		/* number of bytes in file for a CHAR */
60 
61 	/* totals of objects in the file */
62 	INTBIG       magic;				/* file's magic number */
63 	INTBIG       emajor, eminor, edetail;	/* library's version information */
64 	INTBIG       aacount;			/* number of tools */
65 	INTBIG       techcount;			/* number of technologies */
66 	INTBIG       nodepprotoindex;	/* number of primitive node prototypes */
67 	INTBIG       portpprotoindex;	/* number of primitive port prototypes */
68 	INTBIG       arcprotoindex;		/* number of arc prototypes */
69 	INTBIG       nodeprotoindex;	/* number of cells */
70 	INTBIG       nodeindex;			/* number of node instances */
71 	INTBIG       portprotoindex;	/* index of port prototypes */
72 	INTBIG       portprotolimit;	/* total number of port prototypes */
73 	INTBIG       arcindex;			/* number of arc instances */
74 	INTBIG       geomindex;			/* number of geometry modules */
75 	INTBIG       cellindex;			/* number of cells */
76 	INTBIG       curnodeproto;		/* current cell */
77 
78 	/* input error message arrays */
79 	CHAR       **techerror;			/* name of unknown technologies */
80 	CHAR       **toolerror;			/* name of unknown tools */
81 	BOOLEAN     *nodepprotoerror;	/* flag for unknown prim. NODEPROTOs */
82 	CHAR       **nodepprotoorig;	/* name of unknown prim. NODEPROTOs */
83 	INTBIG      *nodepprototech;	/* tech. assoc. with prim. NODEPROTOs */
84 	CHAR       **portpprotoerror;	/* name of unknown PORTPROTOs */
85 	CHAR       **arcprotoerror;		/* name of unknown ARCPROTOs */
86 	INTBIG       swap_bytes;		/* are the bytes swapped? 1 if so */
87 	BOOLEAN      converttextdescriptors;	/* convert textdescript fields */
88 	BOOLEAN      alwaystextdescriptors;	/* always have textdescript fields */
89 	INTBIG       swapped_floats;	/* number of swappped floating-point variables */
90 	INTBIG       swapped_doubles;	/* number of swappped double-precision variables */
91 	INTBIG       clipped_integers;	/* number of clipped integers */
92 	FILE        *filein;			/* channel for input */
93 	INTBIG      *newnames;			/* for adding new names to global namespace */
94 	jmp_buf      filerror;			/* nonlocal jump when I/O fails */
95 	NODEINST   **nodelist;			/* list of nodes for readin */
96 	INTBIG      *nodecount;			/* number of nodeinsts in each cell */
97 	ARCINST    **arclist;			/* list of arcs for readin */
98 	INTBIG      *arccount;			/* number of arcinsts in each cell */
99 	NODEPROTO  **nodeprotolist;		/* list of cells for readin */
100 	FAKECELL   **fakecelllist;		/* list of fakecells for readin */
101 	TECHNOLOGY **techlist;			/* list of technologies for readin */
102 	INTBIG      *toollist;			/* list of tools for readin */
103 	PORTPROTO  **portprotolist;		/* list of portprotos for readin */
104 	INTBIG      *portcount;			/* number of portprotos in each cell */
105 	PORTPROTO  **portpprotolist;	/* list of primitive portprotos for readin */
106 	NODEPROTO  **nodepprotolist;	/* list of primitive nodeprotos for readin */
107 	ARCPROTO   **arcprotolist;		/* list of arcprotos for readin */
108 } BININPUTDATA;
109 
110 static BININPUTDATA io_binindata;				/* all data pertaining to reading a file */
111 static CHAR1       *io_tempstring;				/* for reading temporary strings */
112 static INTBIG       io_tempstringlength = 0;	/* length of temporary string */
113 static CHAR         io_mainlibdirectory[500];	/* root directory where binary file lives */
114        void        *io_inputprogressdialog;		/* for showing input progress */
115 
116 /* prototypes for local routines */
117 static CHAR       *io_doreadlibrary(LIBRARY*);
118 static BOOLEAN     io_readnodeproto(NODEPROTO*, LIBRARY*);
119 static BOOLEAN     io_readnodeinst(NODEINST*);
120 static void        io_readgeom(BOOLEAN*, INTBIG*);
121 static BOOLEAN     io_readarcinst(ARCINST*);
122 static BOOLEAN     io_readnamespace(void);
123 static void        io_ignorevariables(void);
124 static INTBIG      io_readvariables(INTBIG, INTBIG);
125 static INTBIG      io_getinvar(INTBIG*, INTBIG);
126 static INTBIG      io_arrangetoolbits(INTBIG);
127 static INTBIG      io_convertnodeproto(NODEPROTO**, CHAR**);
128 static BOOLEAN     io_convertportproto(PORTPROTO**, BOOLEAN);
129 static void        io_convertarcproto(ARCPROTO**);
130 static ARCPROTO   *io_getarcprotolist(INTBIG);
131 static PORTPROTO  *io_getportpprotolist(INTBIG);
132 static NODEPROTO  *io_getnodepprotolist(INTBIG);
133 static TECHNOLOGY *io_gettechlist(INTBIG);
134 static void        io_getin(void *, INTBIG, INTBIG, BOOLEAN);
135 static CHAR       *io_getstring(CLUSTER*);
136 static CHAR       *io_gettempstring(void);
137 static void        io_getinbig(void *data);
138 static void        io_getinubig(void *data);
139 static void        io_readexternalnodeproto(LIBRARY *lib, INTBIG i);
140 static void        io_ensureallports(LIBRARY *lib);
141 static void        io_binfindallports(LIBRARY *lib, PORTPROTO *pp, INTBIG *lx, INTBIG *hx,
142 						INTBIG *ly, INTBIG *hy, BOOLEAN *first, ARCPROTO **onlyarc, XARRAY trans);
143 static void        io_fixexternalvariables(VARIABLE *firstvar, INTSML numvar);
144 
145 /*
146  * Routine to free all memory associated with this module.
147  */
io_freebininmemory(void)148 void io_freebininmemory(void)
149 {
150 	if (io_tempstringlength != 0) efree((CHAR *)io_tempstring);
151 }
152 
io_readbinlibrary(LIBRARY * lib)153 BOOLEAN io_readbinlibrary(LIBRARY *lib)
154 {
155 	REGISTER BOOLEAN ret;
156 	REGISTER INTBIG len, filelen;
157 	REGISTER LIBRARY *olib, *nextlib;
158 
159 	/* mark all libraries as "not being read", but "wanted" */
160 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
161 	{
162 		olib->temp1 = 0;
163 		olib->userbits &= ~UNWANTEDLIB;
164 	}
165 
166 	/* remember the path to this first library */
167 	estrcpy(io_mainlibdirectory, truepath(lib->libfile));
168 	filelen = estrlen(io_mainlibdirectory);
169 	len = estrlen(skippath(io_mainlibdirectory));
170 	if (len < filelen)
171 	{
172 		io_mainlibdirectory[filelen-len-1] = 0;
173 	} else
174 	{
175 		io_mainlibdirectory[0] = 0;
176 	}
177 
178 
179 	ret = io_doreadbinlibrary(lib, TRUE);
180 	if (ret == 0 && (lib->userbits&HIDDENLIBRARY) == 0)
181 	{
182 		ttyputmsg(_("Read library %s on %s"), lib->libname,
183 			timetostring(getcurrenttime()));
184 #ifdef ONUNIX
185 		efprintf(stdout, _("Read library %s on %s\n"), lib->libname,
186 			timetostring(getcurrenttime()));
187 #endif
188 	}
189 
190 	/* delete unwanted libraries */
191 	for(olib = el_curlib; olib != NOLIBRARY; olib = nextlib)
192 	{
193 		nextlib = olib->nextlibrary;
194 		if ((olib->userbits&UNWANTEDLIB) == 0) continue;
195 		killlibrary(olib);
196 	}
197 	return(ret);
198 }
199 
io_doreadbinlibrary(LIBRARY * lib,BOOLEAN newprogress)200 BOOLEAN io_doreadbinlibrary(LIBRARY *lib, BOOLEAN newprogress)
201 {
202 	REGISTER CHAR *result;
203 	CHAR *filename;
204 	REGISTER void *infstr;
205 
206 	/* find the library file */
207 	result = truepath(lib->libfile);
208 
209 	io_binindata.filein = xopen(result, io_filetypeblib, el_libdir, &filename);
210 	if (io_binindata.filein == NULL)
211 	{
212 		ttyputerr(_("File '%s' not found"), result);
213 		return(TRUE);
214 	}
215 
216 	/* update the library file name if the true location is different */
217 	if (estrcmp(filename, lib->libfile) != 0)
218 		(void)reallocstring(&lib->libfile, filename, lib->cluster);
219 
220 	/* prepare status dialog */
221 	if (io_verbose < 0)
222 	{
223 		io_binindata.filelength = filesize(io_binindata.filein);
224 		if (io_binindata.filelength > 0)
225 		{
226 			if (newprogress)
227 			{
228 				io_inputprogressdialog = DiaInitProgress(x_(""), _("Reading library"));
229 				if (io_inputprogressdialog == 0)
230 				{
231 					xclose(io_binindata.filein);
232 					return(TRUE);
233 				}
234 			}
235 			DiaSetProgress(io_inputprogressdialog, 0, io_binindata.filelength);
236 			infstr = initinfstr();
237 			formatinfstr(infstr, _("Reading library %s"), lib->libname);
238 			DiaSetCaptionProgress(io_inputprogressdialog, returninfstr(infstr));
239 			DiaSetTextProgress(io_inputprogressdialog, _("Initializing..."));
240 		}
241 	} else io_binindata.filelength = 0;
242 	io_binindata.reported = 0;
243 	io_binindata.bytecount = 0;
244 
245 	/* assume regular format */
246 	io_binindata.swap_bytes = 0;
247 	io_binindata.swapped_floats = 0;
248 	io_binindata.swapped_doubles = 0;
249 	io_binindata.clipped_integers = 0;
250 
251 	/* mark that the library is being read */
252 	lib->temp1 = 1;
253 
254 	/* now read the file */
255 	result = io_doreadlibrary(lib);
256 
257 	/* mark that the library is not being read */
258 	lib->temp1 = 0;
259 
260 	/* clean up */
261 	xclose(io_binindata.filein);
262 	if (io_verbose < 0 && io_binindata.filelength > 0 && newprogress && io_inputprogressdialog != 0)
263 	{
264 		DiaDoneProgress(io_inputprogressdialog);
265 		io_inputprogressdialog = 0;
266 		io_binindata.filelength = 0;
267 	}
268 	if (io_binindata.swapped_floats != 0)
269 		ttyputverbose(M_("Read %ld swapped float variables; may be incorrect"),
270 			io_binindata.swapped_floats);
271 	if (io_binindata.swapped_doubles != 0)
272 		ttyputverbose(M_("Read %ld swapped double variables; may be incorrect"),
273 			io_binindata.swapped_doubles);
274 	if (io_binindata.clipped_integers != 0)
275 		ttyputverbose(M_("Read %ld clipped integers; may be incorrect"),
276 			io_binindata.clipped_integers);
277 	if (*result == 0) return(FALSE);
278 	ttyputerr(_("Error reading library %s: %s"), lib->libname, result);
279 	return(TRUE);
280 }
281 
io_doreadlibrary(LIBRARY * lib)282 CHAR *io_doreadlibrary(LIBRARY *lib)
283 {
284 	REGISTER INTBIG te;
285 	REGISTER BOOLEAN imosconv, showerror;
286 	REGISTER BOOLEAN *geomtype;
287 	REGISTER INTBIG i, thisone, *geommoreup, top, advise, errorcode,
288 		bot, look, nodeindex, arcindex, geomindex, oldunit, convertmosiscmostechnologies;
289 	INTBIG num, den, j, count, cou, arcinstpos, nodeinstpos, portprotopos;
290 	REGISTER CHAR *name, *sname, *thecellname;
291 	REGISTER NODEPROTO *np, *onp, *lastnp, *newestversion;
292 	REGISTER NODEINST *ni;
293 	GEOM *geom;
294 	REGISTER ARCPROTO *ap;
295 	REGISTER ARCINST *ai;
296 	REGISTER PORTPROTO *pp;
297 	REGISTER TECHNOLOGY *tech;
298 	REGISTER PORTEXPINST **portexpinstlist;
299 	REGISTER PORTARCINST **portarcinstlist;
300 	REGISTER TOOL *tool;
301 	CHAR *version;
302 	UCHAR1 chmagic[4];
303 	REGISTER VIEW *v;
304 	REGISTER LIBRARY *savelib, *olib;
305 	REGISTER void *infstr;
306 
307 	errorcode = setjmp(io_binindata.filerror);
308 	if (errorcode != 0)
309 	{
310 		if (errorcode == LONGJMPABORTED) return(_("Aborted"));
311 		if (errorcode == LONGJMPEOF) return(_("Premature end of file"));
312 		return(_("Unknown error"));
313 	}
314 
315 	/* read magic number */
316 	io_getin(&io_binindata.magic, 4, SIZEOFINTBIG, TRUE);
317 	if (io_binindata.magic != MAGIC1 && io_binindata.magic != MAGIC2 &&
318 		io_binindata.magic != MAGIC3 && io_binindata.magic != MAGIC4 &&
319 		io_binindata.magic != MAGIC5 && io_binindata.magic != MAGIC6 &&
320 		io_binindata.magic != MAGIC7 && io_binindata.magic != MAGIC8 &&
321 		io_binindata.magic != MAGIC9 && io_binindata.magic != MAGIC10 &&
322 		io_binindata.magic != MAGIC11 && io_binindata.magic != MAGIC12 &&
323 		io_binindata.magic != MAGIC13)
324 	{
325 		/* try swapping the bytes */
326 		chmagic[0] = (UCHAR1)(io_binindata.magic & 0xFF);
327 		chmagic[1] = (UCHAR1)((io_binindata.magic >> 8) & 0xFF);
328 		chmagic[2] = (UCHAR1)((io_binindata.magic >> 16) & 0xFF);
329 		chmagic[3] = (UCHAR1)((io_binindata.magic >> 24) & 0xFF);
330 		io_binindata.magic = (chmagic[0] << 24) | (chmagic[1] << 16) |
331 			(chmagic[2] << 8) | chmagic[3];
332 		if (io_binindata.magic != MAGIC1 && io_binindata.magic != MAGIC2 &&
333 			io_binindata.magic != MAGIC3 && io_binindata.magic != MAGIC4 &&
334 			io_binindata.magic != MAGIC5 && io_binindata.magic != MAGIC6 &&
335 			io_binindata.magic != MAGIC7 && io_binindata.magic != MAGIC8 &&
336 			io_binindata.magic != MAGIC9 && io_binindata.magic != MAGIC10 &&
337 			io_binindata.magic != MAGIC11 && io_binindata.magic != MAGIC12 &&
338 			io_binindata.magic != MAGIC13)
339 				return(_("Bad file format")); else
340 		{
341 			io_binindata.swap_bytes = 1;
342 			ttyputverbose(M_("File has swapped bytes in the header. Will attempt to read it."));
343 		}
344 	}
345 	if (io_verbose > 0) switch (io_binindata.magic)
346 	{
347 		case MAGIC1:  ttyputmsg(M_("This library is 12 versions old"));  break;
348 		case MAGIC2:  ttyputmsg(M_("This library is 11 versions old"));  break;
349 		case MAGIC3:  ttyputmsg(M_("This library is 10 versions old"));   break;
350 		case MAGIC4:  ttyputmsg(M_("This library is 9 versions old"));   break;
351 		case MAGIC5:  ttyputmsg(M_("This library is 8 versions old"));   break;
352 		case MAGIC6:  ttyputmsg(M_("This library is 7 versions old"));   break;
353 		case MAGIC7:  ttyputmsg(M_("This library is 6 versions old"));   break;
354 		case MAGIC8:  ttyputmsg(M_("This library is 5 versions old"));   break;
355 		case MAGIC9:  ttyputmsg(M_("This library is 4 versions old"));   break;
356 		case MAGIC10: ttyputmsg(M_("This library is 3 version old"));    break;
357 		case MAGIC11: ttyputmsg(M_("This library is 2 version old"));    break;
358 		case MAGIC12: ttyputmsg(M_("This library is 1 version old"));    break;
359 	}
360 
361 	/* determine size of "big" and "small" integers on disk */
362 	if (io_binindata.magic <= MAGIC10)
363 	{
364 		io_getin(&io_binindata.sizeofsmall, 1, 1, FALSE);
365 		io_getin(&io_binindata.sizeofbig, 1, 1, FALSE);
366 	} else
367 	{
368 		io_binindata.sizeofsmall = 2;
369 		io_binindata.sizeofbig = 4;
370 	}
371 	if (io_binindata.magic <= MAGIC11)
372 	{
373 		io_getin(&io_binindata.sizeofchar, 1, 1, FALSE);
374 	} else
375 	{
376 		io_binindata.sizeofchar = 1;
377 	}
378 	if (io_binindata.sizeofsmall > SIZEOFINTSML || io_binindata.sizeofbig > SIZEOFINTBIG)
379 		ttyputmsg(_("Warning: file has larger integers than memory: clipping may occur."));
380 	if (io_binindata.sizeofchar > SIZEOFCHAR)
381 		ttyputmsg(_("Warning: file has unicode text: not all characters are preserved."));
382 
383 	/* get count of objects in the file */
384 	io_getinbig(&io_binindata.aacount);
385 	io_getinbig(&io_binindata.techcount);
386 	io_getinbig(&io_binindata.nodepprotoindex);
387 	io_getinbig(&io_binindata.portpprotoindex);
388 	io_getinbig(&io_binindata.arcprotoindex);
389 	io_getinbig(&io_binindata.nodeprotoindex);
390 	io_getinbig(&io_binindata.nodeindex);
391 	io_getinbig(&io_binindata.portprotoindex);
392 	io_binindata.portprotolimit = io_binindata.portprotoindex;
393 	io_getinbig(&io_binindata.arcindex);
394 	io_getinbig(&io_binindata.geomindex);
395 	if (io_binindata.magic <= MAGIC9 && io_binindata.magic >= MAGIC11)
396 	{
397 		/* versions 9 through 11 stored a "cell count" */
398 		io_getinbig(&io_binindata.cellindex);
399 	} else
400 	{
401 		io_binindata.cellindex = io_binindata.nodeprotoindex;
402 	}
403 	io_getinbig(&io_binindata.curnodeproto);
404 	if (io_verbose > 0)
405 	{
406 		ttyputmsg(M_("Reading %ld tools, %ld technologies"), io_binindata.aacount,
407 			io_binindata.techcount);
408 		ttyputmsg(M_("        %ld prim nodes, %ld prim ports, %ld arc protos"),
409 			io_binindata.nodepprotoindex, io_binindata.portpprotoindex,
410 			io_binindata.arcprotoindex);
411 		ttyputmsg(M_("        %ld cells, %ld cells, %ld ports, %ld nodes, %ld arcs"),
412 			io_binindata.cellindex, io_binindata.nodeprotoindex,
413 			io_binindata.portprotoindex, io_binindata.nodeindex,
414 			io_binindata.arcindex);
415 	}
416 
417 	/* get the Electric version (version 8 and later) */
418 	if (io_binindata.magic <= MAGIC8) version = io_getstring(el_tempcluster); else
419 		(void)allocstring(&version, x_("3.35"), el_tempcluster);
420 	parseelectricversion(version, &io_binindata.emajor, &io_binindata.eminor, &io_binindata.edetail);
421 
422 	/* for versions before 6.03q, convert MOSIS CMOS technology names */
423 	convertmosiscmostechnologies = 0;
424 	if (io_binindata.emajor < 6 ||
425 		(io_binindata.emajor == 6 && io_binindata.eminor < 3) ||
426 		(io_binindata.emajor == 6 && io_binindata.eminor == 3 && io_binindata.edetail < 17))
427 	{
428 		if ((asktech(mocmossub_tech, x_("get-state"))&MOCMOSSUBNOCONV) == 0)
429 			convertmosiscmostechnologies = 1;
430 	}
431 
432 	/* for versions before 6.04c, convert text descriptor values */
433 	io_binindata.converttextdescriptors = FALSE;
434 	if (io_binindata.emajor < 6 ||
435 		(io_binindata.emajor == 6 && io_binindata.eminor < 4) ||
436 		(io_binindata.emajor == 6 && io_binindata.eminor == 4 && io_binindata.edetail < 3))
437 	{
438 		io_binindata.converttextdescriptors = TRUE;
439 	}
440 
441 	/* for versions 6.05x and later, always have text descriptor values */
442 	io_binindata.alwaystextdescriptors = TRUE;
443 	if (io_binindata.emajor < 6 ||
444 		(io_binindata.emajor == 6 && io_binindata.eminor < 5) ||
445 		(io_binindata.emajor == 6 && io_binindata.eminor == 5 && io_binindata.edetail < 24))
446 	{
447 		io_binindata.alwaystextdescriptors = FALSE;
448 	}
449 
450 
451 #ifdef REPORTCONVERSION
452 	ttyputmsg(x_("Library is version %s (%ld.%ld.%ld)"), version, io_binindata.emajor,
453 		io_binindata.eminor, io_binindata.edetail);
454 	if (convertmosiscmostechnologies != 0)
455 		ttyputmsg(x_("   Converting MOSIS CMOS technologies (mocmossub => mocmos)"));
456 #endif
457 
458 	/* get the newly created views (version 9 and later) */
459 	for(v = el_views; v != NOVIEW; v = v->nextview) v->temp1 = 0;
460 	el_unknownview->temp1 = -1;
461 	el_layoutview->temp1 = -2;
462 	el_schematicview->temp1 = -3;
463 	el_iconview->temp1 = -4;
464 	el_simsnapview->temp1 = -5;
465 	el_skeletonview->temp1 = -6;
466 	el_vhdlview->temp1 = -7;
467 	el_netlistview->temp1 = -8;
468 	el_docview->temp1 = -9;
469 	el_netlistnetlispview->temp1 = -10;
470 	el_netlistalsview->temp1 = -11;
471 	el_netlistquiscview->temp1 = -12;
472 	el_netlistrsimview->temp1 = -13;
473 	el_netlistsilosview->temp1 = -14;
474 	el_verilogview->temp1 = -15;
475 	if (io_binindata.magic <= MAGIC9)
476 	{
477 		io_getinbig(&j);
478 		for(i=0; i<j; i++)
479 		{
480 			name = io_getstring(db_cluster);
481 			sname = io_getstring(db_cluster);
482 			v = getview(name);
483 			if (v == NOVIEW)
484 			{
485 				v = allocview();
486 				if (v == NOVIEW) return(_("No memory"));
487 				v->viewname = name;
488 				v->sviewname = sname;
489 				if (namesamen(name, x_("Schematic-Page-"), 15) == 0)
490 					v->viewstate |= MULTIPAGEVIEW;
491 				v->nextview = el_views;
492 				el_views = v;
493 			} else
494 			{
495 				efree(name);
496 				efree(sname);
497 			}
498 			v->temp1 = i + 1;
499 		}
500 	}
501 
502 	/* get the number of toolbits to ignore */
503 	if (io_binindata.magic <= MAGIC3 && io_binindata.magic >= MAGIC6)
504 	{
505 		/* versions 3, 4, 5, and 6 find this in the file */
506 		io_getinbig(&io_binindata.aabcount);
507 	} else
508 	{
509 		/* versions 1 and 2 compute this (versions 7 and later ignore it) */
510 		io_binindata.aabcount = io_binindata.aacount;
511 	}
512 
513 	/* erase the current database */
514 	if (io_verbose > 0) ttyputmsg(M_("Erasing old library"));
515 	eraselibrary(lib);
516 
517 	/* allocate pointers */
518 	io_binindata.nodelist = (NODEINST **)emalloc(((sizeof (NODEINST *)) * io_binindata.nodeindex), el_tempcluster);
519 	if (io_binindata.nodelist == 0) return(_("No memory"));
520 	io_binindata.nodecount = emalloc((SIZEOFINTBIG * io_binindata.nodeprotoindex), el_tempcluster);
521 	if (io_binindata.nodecount == 0) return(_("No memory"));
522 	io_binindata.nodeprotolist = (NODEPROTO **)emalloc(((sizeof (NODEPROTO *)) * io_binindata.nodeprotoindex), el_tempcluster);
523 	if (io_binindata.nodeprotolist == 0) return(_("No memory"));
524 	io_binindata.portprotolist = (PORTPROTO **)emalloc(((sizeof (PORTPROTO *)) * io_binindata.portprotoindex), el_tempcluster);
525 	if (io_binindata.portprotolist == 0) return(_("No memory"));
526 	io_binindata.portcount = emalloc((SIZEOFINTBIG * io_binindata.nodeprotoindex), el_tempcluster);
527 	if (io_binindata.portcount == 0) return(_("No memory"));
528 	io_binindata.portpprotolist = (PORTPROTO **)emalloc(((sizeof (PORTPROTO *)) * io_binindata.portpprotoindex), el_tempcluster);
529 	if (io_binindata.portpprotolist == 0) return(_("No memory"));
530 	io_binindata.portpprotoerror = (CHAR **)emalloc(((sizeof (CHAR *)) * io_binindata.portpprotoindex), el_tempcluster);
531 	if (io_binindata.portpprotoerror == 0) return(_("No memory"));
532 	portexpinstlist = (PORTEXPINST **)emalloc(((sizeof (PORTEXPINST *)) * io_binindata.portprotoindex), el_tempcluster);
533 	if (portexpinstlist == 0) return(_("No memory"));
534 	portarcinstlist = (PORTARCINST **)emalloc(((sizeof (PORTARCINST *)) * io_binindata.arcindex * 2), el_tempcluster);
535 	if (portarcinstlist == 0) return(_("No memory"));
536 	io_binindata.arclist = (ARCINST **)emalloc(((sizeof (ARCINST *)) * io_binindata.arcindex), el_tempcluster);
537 	if (io_binindata.arclist == 0) return(_("No memory"));
538 	io_binindata.arccount = emalloc((SIZEOFINTBIG * io_binindata.nodeprotoindex), el_tempcluster);
539 	if (io_binindata.arccount == 0) return(_("No memory"));
540 	io_binindata.nodepprotolist = (NODEPROTO **)emalloc(((sizeof (NODEPROTO *)) * io_binindata.nodepprotoindex), el_tempcluster);
541 	if (io_binindata.nodepprotolist == 0) return(_("No memory"));
542 	io_binindata.nodepprototech = emalloc((SIZEOFINTBIG * io_binindata.nodepprotoindex), el_tempcluster);
543 	if (io_binindata.nodepprototech == 0) return(_("No memory"));
544 	io_binindata.nodepprotoerror = (BOOLEAN *)emalloc(((sizeof (BOOLEAN)) * io_binindata.nodepprotoindex), el_tempcluster);
545 	if (io_binindata.nodepprotoerror == 0) return(_("No memory"));
546 	io_binindata.nodepprotoorig = (CHAR **)emalloc(((sizeof (CHAR *)) * io_binindata.nodepprotoindex), el_tempcluster);
547 	if (io_binindata.nodepprotoorig == 0) return(_("No memory"));
548 	io_binindata.arcprotolist = (ARCPROTO **)emalloc(((sizeof (ARCPROTO *)) * io_binindata.arcprotoindex), el_tempcluster);
549 	if (io_binindata.arcprotolist == 0) return(_("No memory"));
550 	io_binindata.arcprotoerror = (CHAR **)emalloc(((sizeof (CHAR *)) * io_binindata.arcprotoindex), el_tempcluster);
551 	if (io_binindata.arcprotoerror == 0) return(_("No memory"));
552 	io_binindata.techlist = (TECHNOLOGY **)emalloc(((sizeof (TECHNOLOGY *)) * io_binindata.techcount), el_tempcluster);
553 	if (io_binindata.techlist == 0) return(_("No memory"));
554 	io_binindata.techerror = (CHAR **)emalloc(((sizeof (CHAR *)) * io_binindata.techcount), el_tempcluster);
555 	if (io_binindata.techerror == 0) return(_("No memory"));
556 	io_binindata.toollist = emalloc((SIZEOFINTBIG * io_binindata.aacount), el_tempcluster);
557 	if (io_binindata.toollist == 0) return(_("No memory"));
558 	io_binindata.toolerror = (CHAR **)emalloc(((sizeof (CHAR *)) * io_binindata.aacount), el_tempcluster);
559 	if (io_binindata.toolerror == 0) return(_("No memory"));
560 
561 	/* versions 9 to 11 allocate cell pointers */
562 	if (io_binindata.magic <= MAGIC9 && io_binindata.magic >= MAGIC11)
563 	{
564 		io_binindata.fakecelllist = (FAKECELL **)emalloc(((sizeof (FAKECELL *)) * io_binindata.cellindex), el_tempcluster);
565 		if (io_binindata.fakecelllist == 0) return(_("No memory"));
566 	}
567 
568 	/* versions 4 and earlier allocate geometric pointers */
569 	if (io_binindata.magic > MAGIC5)
570 	{
571 		geomtype = (BOOLEAN *)emalloc(((sizeof (BOOLEAN)) * io_binindata.geomindex), el_tempcluster);
572 		if (geomtype == 0) return(_("No memory"));
573 		geommoreup = emalloc((SIZEOFINTBIG * io_binindata.geomindex), el_tempcluster);
574 		if (geommoreup == 0) return(_("No memory"));
575 		if (geomtype == 0 || geommoreup == 0) return(_("No memory"));
576 	}
577 
578 	/* get number of arcinsts and nodeinsts in each cell */
579 	if (io_binindata.magic != MAGIC1)
580 	{
581 		/* versions 2 and later find this in the file */
582 		nodeinstpos = arcinstpos = portprotopos = 0;
583 		for(i=0; i<io_binindata.nodeprotoindex; i++)
584 		{
585 			io_getinbig(&io_binindata.arccount[i]);
586 			io_getinbig(&io_binindata.nodecount[i]);
587 			io_getinbig(&io_binindata.portcount[i]);
588 			if (io_binindata.arccount[i] >= 0 || io_binindata.nodecount[i] >= 0)
589 			{
590 				arcinstpos += io_binindata.arccount[i];
591 				nodeinstpos += io_binindata.nodecount[i];
592 			}
593 			portprotopos += io_binindata.portcount[i];
594 		}
595 
596 		/* verify that the number of node instances is equal to the total in the file */
597 		if (nodeinstpos != io_binindata.nodeindex)
598 		{
599 			ttyputerr(_("Error: cells have %ld nodes but library has %ld"),
600 				nodeinstpos, io_binindata.nodeindex);
601 			return(_("Bad file"));
602 		}
603 		if (arcinstpos != io_binindata.arcindex)
604 		{
605 			ttyputerr(_("Error: cells have %ld arcs but library has %ld"),
606 				arcinstpos, io_binindata.arcindex);
607 			return(_("Bad file"));
608 		}
609 		if (portprotopos != io_binindata.portprotoindex)
610 		{
611 			ttyputerr(_("Error: cells have %ld ports but library has %ld"),
612 				portprotopos, io_binindata.portprotoindex);
613 			return(_("Bad file"));
614 		}
615 	} else
616 	{
617 		/* version 1 computes this information */
618 		io_binindata.arccount[0] = io_binindata.arcindex;
619 		io_binindata.nodecount[0] = io_binindata.nodeindex;
620 		io_binindata.portcount[0] = io_binindata.portprotoindex;
621 		for(i=1; i<io_binindata.nodeprotoindex; i++)
622 			io_binindata.arccount[i] = io_binindata.nodecount[i] = io_binindata.portcount[i] = 0;
623 	}
624 
625 	/* allocate all cells in the library */
626 	/* versions 9 to 11 allocate fakecells now */
627 	if (io_binindata.magic <= MAGIC9 && io_binindata.magic >= MAGIC11)
628 	{
629 		for(i=0; i<io_binindata.cellindex; i++)
630 		{
631 			io_binindata.fakecelllist[i] = (FAKECELL *)emalloc(sizeof (FAKECELL), io_tool->cluster);
632 			if (io_binindata.fakecelllist[i] == NOFAKECELL) return(_("No memory"));
633 		}
634 	}
635 
636 	/* allocate all cells in the library */
637 	lib->numnodeprotos = 0;
638 	for(i=0; i<io_binindata.nodeprotoindex; i++)
639 	{
640 		if (io_binindata.arccount[i] < 0 && io_binindata.nodecount[i] < 0)
641 		{
642 			/* this cell is from an external library */
643 			io_binindata.nodeprotolist[i] = 0;
644 		} else
645 		{
646 			io_binindata.nodeprotolist[i] = allocnodeproto(lib->cluster);
647 			if (io_binindata.nodeprotolist[i] == NONODEPROTO) return(_("No memory"));
648 			io_binindata.nodeprotolist[i]->cellview = el_unknownview;
649 			io_binindata.nodeprotolist[i]->newestversion = io_binindata.nodeprotolist[i];
650 			lib->numnodeprotos++;
651 		}
652 	}
653 
654 	/* allocate the nodes, arcs, and ports in each cell */
655 	nodeinstpos = arcinstpos = portprotopos = 0;
656 	for(i=0; i<io_binindata.nodeprotoindex; i++)
657 	{
658 		np = io_binindata.nodeprotolist[i];
659 		if (np == 0)
660 		{
661 			/* for external references, clear the port proto list */
662 			for(j=0; j<io_binindata.portcount[i]; j++)
663 				io_binindata.portprotolist[portprotopos+j] = NOPORTPROTO;
664 			portprotopos += io_binindata.portcount[i];
665 			continue;
666 		}
667 
668 		/* allocate node instances in this cell */
669 		for(j=0; j<io_binindata.nodecount[i]; j++)
670 		{
671 			io_binindata.nodelist[nodeinstpos+j] = allocnodeinst(lib->cluster);
672 			if (io_binindata.nodelist[nodeinstpos+j] == NONODEINST) return(_("No memory"));
673 		}
674 		if (io_binindata.nodecount[i] == 0) np->firstnodeinst = NONODEINST; else
675 			np->firstnodeinst = io_binindata.nodelist[nodeinstpos];
676 		for(j=0; j<io_binindata.nodecount[i]; j++)
677 		{
678 			ni = io_binindata.nodelist[j+nodeinstpos];
679 			geom = allocgeom(lib->cluster);
680 			if (geom == NOGEOM) return(_("No memory"));
681 			ni->geom = geom;
682 
683 			/* compute linked list of nodes in this cell */
684 			if (j == 0) ni->prevnodeinst = NONODEINST; else
685 				ni->prevnodeinst = io_binindata.nodelist[j+nodeinstpos-1];
686 			if (j+1 == io_binindata.nodecount[i]) ni->nextnodeinst = NONODEINST; else
687 				ni->nextnodeinst = io_binindata.nodelist[j+nodeinstpos+1];
688 		}
689 		nodeinstpos += io_binindata.nodecount[i];
690 
691 		/* allocate port prototypes in this cell */
692 		for(j=0; j<io_binindata.portcount[i]; j++)
693 		{
694 			thisone = j + portprotopos;
695 			io_binindata.portprotolist[thisone] = allocportproto(lib->cluster);
696 			if (io_binindata.portprotolist[thisone] == NOPORTPROTO) return(_("No memory"));
697 			portexpinstlist[thisone] = allocportexpinst(lib->cluster);
698 			if (portexpinstlist[thisone] == NOPORTEXPINST) return(_("No memory"));
699 			io_binindata.portprotolist[thisone]->subportexpinst = portexpinstlist[thisone];
700 		}
701 		portprotopos += io_binindata.portcount[i];
702 
703 		/* allocate arc instances and port arc instances in this cell */
704 		for(j=0; j<io_binindata.arccount[i]; j++)
705 		{
706 			io_binindata.arclist[arcinstpos+j] = allocarcinst(lib->cluster);
707 			if (io_binindata.arclist[arcinstpos+j] == NOARCINST) return(_("No memory"));
708 		}
709 		for(j=0; j<io_binindata.arccount[i]*2; j++)
710 		{
711 			portarcinstlist[arcinstpos*2+j] = allocportarcinst(lib->cluster);
712 			if (portarcinstlist[arcinstpos*2+j] == NOPORTARCINST) return(_("No memory"));
713 		}
714 		if (io_binindata.arccount[i] == 0) np->firstarcinst = NOARCINST; else
715 			np->firstarcinst = io_binindata.arclist[arcinstpos];
716 		for(j=0; j<io_binindata.arccount[i]; j++)
717 		{
718 			thisone = j + arcinstpos;
719 			ai = io_binindata.arclist[thisone];
720 			geom = allocgeom(lib->cluster);
721 			if (geom == NOGEOM) return(_("No memory"));
722 			ai->geom = geom;
723 			ai->end[0].portarcinst = portarcinstlist[thisone*2];
724 			ai->end[1].portarcinst = portarcinstlist[thisone*2+1];
725 
726 			/* compute linked list of arcs in this cell */
727 			if (j == 0) ai->prevarcinst = NOARCINST; else
728 				ai->prevarcinst = io_binindata.arclist[j+arcinstpos-1];
729 			if (j+1 == io_binindata.arccount[i]) ai->nextarcinst = NOARCINST; else
730 				ai->nextarcinst = io_binindata.arclist[j+arcinstpos+1];
731 		}
732 		arcinstpos += io_binindata.arccount[i];
733 
734 		if (io_verbose > 0)
735 			ttyputmsg(M_("Allocated %ld arcs, %ld nodes, %ld ports for cell %ld"),
736 				io_binindata.arccount[i], io_binindata.nodecount[i], io_binindata.portcount[i], i);
737 	}
738 
739 	efree((CHAR *)portarcinstlist);
740 	efree((CHAR *)portexpinstlist);
741 
742 	/* setup pointers for technologies and primitives */
743 	io_binindata.nodepprotoindex = 0;
744 	io_binindata.portpprotoindex = 0;
745 	io_binindata.arcprotoindex = 0;
746 	for(te=0; te<io_binindata.techcount; te++)
747 	{
748 		/* associate the technology name with the true technology */
749 		name = io_gettempstring();
750 		if (name == 0) return(_("No memory"));
751 		tech = NOTECHNOLOGY;
752 		if (convertmosiscmostechnologies != 0)
753 		{
754 			if (namesame(name, x_("mocmossub")) == 0) tech = gettechnology(x_("mocmos")); else
755 				if (namesame(name, x_("mocmos")) == 0) tech = gettechnology(x_("mocmosold"));
756 		}
757 		if (tech == NOTECHNOLOGY) tech = gettechnology(name);
758 
759 		/* conversion code for old technologies */
760 		imosconv = FALSE;
761 		if (tech == NOTECHNOLOGY)
762 		{
763 			if (namesame(name, x_("imos")) == 0)
764 			{
765 				tech = gettechnology(x_("mocmos"));
766 				if (tech != NOTECHNOLOGY) imosconv = TRUE;
767 			} else if (namesame(name, x_("logic")) == 0) tech = sch_tech;
768 		}
769 
770 		if (tech == NOTECHNOLOGY)
771 		{
772 			if (namesame(name, x_("epic8c")) == 0 || namesame(name, x_("epic7c")) == 0)
773 				tech = gettechnology(x_("epic7s"));
774 		}
775 
776 		if (tech == NOTECHNOLOGY)
777 		{
778 			tech = el_technologies;
779 			(void)allocstring(&io_binindata.techerror[te], name, el_tempcluster);
780 		} else io_binindata.techerror[te] = 0;
781 		io_binindata.techlist[te] = tech;
782 
783 		/* get the number of primitive node prototypes */
784 		io_getinbig(&count);
785 		for(j=0; j<count; j++)
786 		{
787 			io_binindata.nodepprotoorig[io_binindata.nodepprotoindex] = 0;
788 			io_binindata.nodepprotoerror[io_binindata.nodepprotoindex] = FALSE;
789 			name = io_gettempstring();
790 			if (name == 0) return(_("No memory"));
791 			if (imosconv) name += 6;
792 			for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
793 				if (estrcmp(np->protoname, name) == 0) break;
794 			if (np == NONODEPROTO)
795 			{
796 				/* automatic conversion of "Active-Node" in to "P-Active-Node" (MOSIS CMOS) */
797 				if (estrcmp(name, x_("Active-Node")) == 0)
798 				{
799 					for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
800 						if (estrcmp(np->protoname, x_("P-Active-Node")) == 0) break;
801 				}
802 			}
803 			if (np == NONODEPROTO)
804 			{
805 				if (io_verbose > 0)
806 					ttyputmsg(M_("No node exactly named %s in technology %s"), name, tech->techname);
807 				advise = 1;
808 
809 				/* look for substring name match at start of name */
810 				i = estrlen(name);
811 				for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
812 					if (namesamen(np->protoname, name, mini(estrlen(np->protoname), i)) == 0)
813 						break;
814 
815 				/* look for substring match at end of name */
816 				if (np == NONODEPROTO)
817 				{
818 					for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
819 					{
820 						thisone = estrlen(np->protoname);
821 						if (i >= thisone) continue;
822 						if (namesame(&np->protoname[thisone-i], name) == 0) break;
823 					}
824 				}
825 
826 				/* special cases: convert "message" and "cell-center" nodes */
827 				if (np == NONODEPROTO)
828 				{
829 					np = io_convertoldprimitives(tech, name);
830 					if (np != NONODEPROTO) advise = 0;
831 				}
832 
833 				/* give up and use first primitive in this technology */
834 				if (np == NONODEPROTO) np = tech->firstnodeproto;
835 
836 				/* construct the error message */
837 				if (advise != 0)
838 				{
839 					infstr = initinfstr();
840 					if (io_binindata.techerror[te] != 0) addstringtoinfstr(infstr, io_binindata.techerror[te]); else
841 						addstringtoinfstr(infstr, tech->techname);
842 					addtoinfstr(infstr, ':');
843 					addstringtoinfstr(infstr, name);
844 					(void)allocstring(&io_binindata.nodepprotoorig[io_binindata.nodepprotoindex], returninfstr(infstr), el_tempcluster);
845 					io_binindata.nodepprotoerror[io_binindata.nodepprotoindex] = TRUE;
846 				}
847 			}
848 			io_binindata.nodepprototech[io_binindata.nodepprotoindex] = te;
849 			io_binindata.nodepprotolist[io_binindata.nodepprotoindex] = np;
850 
851 			/* get the number of primitive port prototypes */
852 			io_getinbig(&cou);
853 			for(i=0; i<cou; i++)
854 			{
855 				io_binindata.portpprotoerror[io_binindata.portpprotoindex] = 0;
856 				name = io_gettempstring();
857 				if (name == 0) return(_("No memory"));
858 				pp = getportproto(np, name);
859 
860 				/* convert special port names */
861 				if (pp == NOPORTPROTO)
862 					pp = io_convertoldportname(name, np);
863 
864 				if (pp == NOPORTPROTO)
865 				{
866 					pp = np->firstportproto;
867 					if (!io_binindata.nodepprotoerror[io_binindata.nodepprotoindex])
868 					{
869 						infstr = initinfstr();
870 						addstringtoinfstr(infstr, name);
871 						addstringtoinfstr(infstr, _(" on "));
872 						if (io_binindata.nodepprotoorig[io_binindata.nodepprotoindex] != 0)
873 							addstringtoinfstr(infstr, io_binindata.nodepprotoorig[io_binindata.nodepprotoindex]); else
874 						{
875 							if (io_binindata.techerror[te] != 0)
876 								addstringtoinfstr(infstr, io_binindata.techerror[te]); else
877 									addstringtoinfstr(infstr, tech->techname);
878 							addtoinfstr(infstr, ':');
879 							addstringtoinfstr(infstr, np->protoname);
880 						}
881 						(void)allocstring(&io_binindata.portpprotoerror[io_binindata.portpprotoindex],
882 							returninfstr(infstr), el_tempcluster);
883 					}
884 				}
885 				io_binindata.portpprotolist[io_binindata.portpprotoindex++] = pp;
886 			}
887 			io_binindata.nodepprotoindex++;
888 		}
889 
890 		/* get the number of arc prototypes */
891 		io_getinbig(&count);
892 		for(j=0; j<count; j++)
893 		{
894 			io_binindata.arcprotoerror[io_binindata.arcprotoindex] = 0;
895 			name = io_gettempstring();
896 			if (name == 0) return(_("No memory"));
897 			if (imosconv) name += 6;
898 			for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
899 				if (estrcmp(ap->protoname, name) == 0) break;
900 			if (ap == NOARCPROTO)
901 			{
902 				if (tech == art_tech)
903 				{
904 					if (estrcmp(name, x_("Dash-1")) == 0) ap = art_dottedarc; else
905 					if (estrcmp(name, x_("Dash-2")) == 0) ap = art_dashedarc; else
906 					if (estrcmp(name, x_("Dash-3")) == 0) ap = art_thickerarc;
907 				}
908 			}
909 			if (ap == NOARCPROTO)
910 			{
911 				ap = tech->firstarcproto;
912 				infstr = initinfstr();
913 				if (io_binindata.techerror[te] != 0)
914 					addstringtoinfstr(infstr, io_binindata.techerror[te]); else
915 						addstringtoinfstr(infstr, tech->techname);
916 				addtoinfstr(infstr, ':');
917 				addstringtoinfstr(infstr, name);
918 				(void)allocstring(&io_binindata.arcprotoerror[io_binindata.arcprotoindex], returninfstr(infstr), el_tempcluster);
919 			}
920 			io_binindata.arcprotolist[io_binindata.arcprotoindex++] = ap;
921 		}
922 	}
923 
924 	/* setup pointers for tools */
925 	io_binindata.toolbitsmessed = FALSE;
926 	for(i=0; i<io_binindata.aacount; i++)
927 	{
928 		name = io_gettempstring();
929 		if (name == 0) return(_("No memory"));
930 		io_binindata.toolerror[i] = 0;
931 		for(j=0; j<el_maxtools; j++)
932 			if (estrcmp(name, el_tools[j].toolname) == 0) break;
933 		if (j >= el_maxtools)
934 		{
935 			(void)allocstring(&io_binindata.toolerror[i], name, el_tempcluster);
936 			j = -1;
937 		}
938 		if (i != j) io_binindata.toolbitsmessed = TRUE;
939 		io_binindata.toollist[i] = j;
940 	}
941 	if (io_binindata.magic <= MAGIC3 && io_binindata.magic >= MAGIC6)
942 	{
943 		/* versions 3, 4, 5, and 6 must ignore toolbits associations */
944 		for(i=0; i<io_binindata.aabcount; i++) (void)io_gettempstring();
945 	}
946 
947 	/* get the library userbits */
948 	if (io_binindata.magic <= MAGIC7)
949 	{
950 		/* version 7 and later simply read the relevant data */
951 		io_getinubig(&lib->userbits);
952 	} else
953 	{
954 		/* version 6 and earlier must sift through the information */
955 		if (io_binindata.aabcount >= 1) io_getinubig(&lib->userbits);
956 		for(i=1; i<io_binindata.aabcount; i++) io_getinubig(&j);
957 	}
958 	lib->userbits &= ~(LIBCHANGEDMAJOR | LIBCHANGEDMINOR);
959 	lib->userbits |= READFROMDISK;
960 
961 	/* set the lambda values in the library */
962 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
963 		lib->lambda[tech->techindex] = el_curlib->lambda[tech->techindex];
964 	for(i=0; i<io_binindata.techcount; i++)
965 	{
966 		io_getinbig(&j);
967 		if (io_binindata.techerror[i] != 0) continue;
968 		tech = io_binindata.techlist[i];
969 
970 		/* for version 4 or earlier, scale lambda by 20 */
971 		if (eatoi(version) <= 4) j *= 20;
972 
973 		/* account for any differences of internal unit in this library */
974 		oldunit = ((lib->userbits & LIBUNITS) >> LIBUNITSSH) << INTERNALUNITSSH;
975 		if (oldunit != (el_units&INTERNALUNITS))
976 		{
977 			db_getinternalunitscale(&num, &den, el_units, oldunit);
978 			j = muldiv(j, den, num);
979 		}
980 
981 		/* if this is to be the current library, adjust technologies */
982 		if (lib == el_curlib)
983 			changetechnologylambda(tech, j);
984 		lib->lambda[tech->techindex] = j;
985 	}
986 
987 	/* read the global namespace */
988 	io_binindata.realname = 0;
989 	io_binindata.newnames = 0;
990 	if (io_readnamespace()) return(_("No memory"));
991 
992 	/* read the library variables */
993 	if (io_verbose > 0) ttyputmsg(M_("Reading library variables"));
994 	if (io_readvariables((INTBIG)lib, VLIBRARY) < 0) return(_("Reading library variables"));
995 
996 	/* read the tool variables */
997 	if (io_verbose > 0) ttyputmsg(M_("Reading tool variables"));
998 	for(i=0; i<io_binindata.aacount; i++)
999 	{
1000 		j = io_binindata.toollist[i];
1001 		if (j < 0) io_ignorevariables(); else
1002 			if (io_readvariables((INTBIG)&el_tools[j], VTOOL) < 0)
1003 				return(_("Reading tool variables"));
1004 	}
1005 
1006 	/* read the technology variables */
1007 	if (io_verbose > 0) ttyputmsg(M_("Reading technology/primitive variables"));
1008 	for(te=0; te<io_binindata.techcount; te++)
1009 	{
1010 		tech = io_binindata.techlist[te];
1011 		j = io_readvariables((INTBIG)tech, VTECHNOLOGY);
1012 		if (j < 0) return(_("Reading technology/primitive variables"));
1013 		if (j > 0) (void)io_gettechlist(te);
1014 	}
1015 
1016 	/* read the arcproto variables */
1017 	for(i=0; i<io_binindata.arcprotoindex; i++)
1018 	{
1019 		ap = io_binindata.arcprotolist[i];
1020 		j = io_readvariables((INTBIG)ap, VARCPROTO);
1021 		if (j < 0) return(_("Reading arcproto variables"));
1022 		if (j > 0) (void)io_getarcprotolist(i);
1023 	}
1024 
1025 	/* read the primitive nodeproto variables */
1026 	for(i=0; i<io_binindata.nodepprotoindex; i++)
1027 	{
1028 		np = io_binindata.nodepprotolist[i];
1029 		j = io_readvariables((INTBIG)np, VNODEPROTO);
1030 		if (j < 0) return(_("Reading primitive variables"));
1031 		if (j > 0) (void)io_getnodepprotolist(i);
1032 	}
1033 
1034 	/* read the primitive portproto variables */
1035 	for(i=0; i<io_binindata.portpprotoindex; i++)
1036 	{
1037 		pp = io_binindata.portpprotolist[i];
1038 		j = io_readvariables((INTBIG)pp, VPORTPROTO);
1039 		if (j < 0) return(_("Reading export variables"));
1040 		if (j > 0) (void)io_getportpprotolist(i);
1041 	}
1042 
1043 	/* read the view variables (version 9 and later) */
1044 	if (io_binindata.magic <= MAGIC9)
1045 	{
1046 		io_getinbig(&count);
1047 		for(i=0; i<count; i++)
1048 		{
1049 			io_getinbig(&j);
1050 			for(v = el_views; v != NOVIEW; v = v->nextview)
1051 				if (v->temp1 == j) break;
1052 			if (v == NOVIEW)
1053 			{
1054 				ttyputmsg(_("View index %ld not found"), j);
1055 				io_ignorevariables();
1056 				continue;
1057 			}
1058 			if (io_readvariables((INTBIG)v, VVIEW) < 0)
1059 				return(_("Reading view variables"));
1060 		}
1061 	}
1062 
1063 	/* read the cells (version 9 to 11) */
1064 	if (io_binindata.magic <= MAGIC9 && io_binindata.magic >= MAGIC11)
1065 	{
1066 		for(i=0; i<io_binindata.cellindex; i++)
1067 		{
1068 			thecellname = io_getstring(lib->cluster);
1069 			io_ignorevariables();
1070 
1071 			allocstring(&io_binindata.fakecelllist[i]->cellname, thecellname, io_tool->cluster);
1072 		}
1073 	}
1074 
1075 	/* read the cells */
1076 	io_binindata.portprotoindex = 0;
1077 	lastnp = NONODEPROTO;
1078 	lib->firstnodeproto = NONODEPROTO;
1079 	for(i=0; i<io_binindata.nodeprotoindex; i++)
1080 	{
1081 		np = io_binindata.nodeprotolist[i];
1082 		if (np == 0) continue;
1083 		if (io_readnodeproto(np, lib)) return(_("Reading nodeproto"));
1084 		if (lastnp == NONODEPROTO)
1085 		{
1086 			lib->firstnodeproto = np;
1087 			np->prevnodeproto = NONODEPROTO;
1088 		} else
1089 		{
1090 			np->prevnodeproto = lastnp;
1091 			lastnp->nextnodeproto = np;
1092 		}
1093 		lastnp = np;
1094 		np->nextnodeproto = NONODEPROTO;
1095 	}
1096 	lib->tailnodeproto = lastnp;
1097 
1098 	/* add in external cells */
1099 	for(i=0; i<io_binindata.nodeprotoindex; i++)
1100 	{
1101 		np = io_binindata.nodeprotolist[i];
1102 		if (np != 0) continue;
1103 		io_readexternalnodeproto(lib, i);
1104 	}
1105 
1106 	/* now that external cells are resolved, fix all variables that may have used them */
1107 	io_fixexternalvariables(lib->firstvar, lib->numvar);
1108 	for(i=0; i<io_binindata.aacount; i++)
1109 	{
1110 		j = io_binindata.toollist[i];
1111 		if (j < 0) continue;
1112 		tool = &el_tools[j];
1113 		io_fixexternalvariables(tool->firstvar, tool->numvar);
1114 	}
1115 	for(te=0; te<io_binindata.techcount; te++)
1116 	{
1117 		tech = io_binindata.techlist[te];
1118 		io_fixexternalvariables(tech->firstvar, tech->numvar);
1119 	}
1120 	for(i=0; i<io_binindata.arcprotoindex; i++)
1121 	{
1122 		ap = io_binindata.arcprotolist[i];
1123 		io_fixexternalvariables(ap->firstvar, ap->numvar);
1124 	}
1125 	for(i=0; i<io_binindata.nodepprotoindex; i++)
1126 	{
1127 		np = io_binindata.nodepprotolist[i];
1128 		io_fixexternalvariables(np->firstvar, np->numvar);
1129 	}
1130 	for(i=0; i<io_binindata.portpprotoindex; i++)
1131 	{
1132 		pp = io_binindata.portpprotolist[i];
1133 		io_fixexternalvariables(pp->firstvar, pp->numvar);
1134 	}
1135 	for(v = el_views; v != NOVIEW; v = v->nextview)
1136 		io_fixexternalvariables(v->firstvar, v->numvar);
1137 	for(i=0; i<io_binindata.nodeprotoindex; i++)
1138 	{
1139 		np = io_binindata.nodeprotolist[i];
1140 		io_fixexternalvariables(np->firstvar, np->numvar);
1141 	}
1142 
1143 	/* convert port references in external cells */
1144 	for(i=0; i<io_binindata.nodeprotoindex; i++)
1145 	{
1146 		np = io_binindata.nodeprotolist[i];
1147 
1148 		/* ignore this cell if it is in a library being read */
1149 		olib = np->lib;
1150 		showerror = TRUE;
1151 		if (olib != lib && olib->temp1 != 0) showerror = FALSE;
1152 
1153 		/* convert its ports */
1154 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1155 		{
1156 			if (pp->temp2 == 0) continue;
1157 			if (io_convertportproto(&pp->subportproto, showerror))
1158 			{
1159 				if (showerror)
1160 					ttyputmsg(_("  While reading library %s, on cell %s, port %s (lib %s temp1 is %ld)"),
1161 						lib->libname, describenodeproto(np), pp->protoname, np->lib->libname,
1162 							np->lib->temp1);
1163 			}
1164 			pp->temp2 = 0;
1165 		}
1166 	}
1167 	if (io_verbose > 0) ttyputmsg(M_("Done reading cells"));
1168 
1169 	/* read the cell contents: arcs and nodes */
1170 	nodeindex = arcindex = geomindex = 0;
1171 	for(i=0; i<io_binindata.nodeprotoindex; i++)
1172 	{
1173 		if (stopping(STOPREASONBINARY)) return(_("Library incomplete"));
1174 		np = io_binindata.nodeprotolist[i];
1175 		if (io_verbose != 0)
1176 		{
1177 			savelib = el_curlib;   el_curlib = lib;
1178 			if (io_verbose < 0 && io_binindata.filelength > 0 && io_inputprogressdialog != 0)
1179 			{
1180 				infstr = initinfstr();
1181 				formatinfstr(infstr, _("Reading %s"), describenodeproto(np));
1182 				DiaSetTextProgress(io_inputprogressdialog, returninfstr(infstr));
1183 			} else ttyputmsg(_("Reading %s"), describenodeproto(np));
1184 			el_curlib = savelib;
1185 		}
1186 		if (io_binindata.magic > MAGIC5)
1187 		{
1188 			/* versions 4 and earlier must read some geometric information */
1189 			j = geomindex;
1190 			io_readgeom(&geomtype[j], &geommoreup[j]);   j++;
1191 			io_readgeom(&geomtype[j], &geommoreup[j]);   j++;
1192 			top = j;   io_readgeom(&geomtype[j], &geommoreup[j]);   j++;
1193 			bot = j;   io_readgeom(&geomtype[j], &geommoreup[j]);   j++;
1194 			for(;;)
1195 			{
1196 				io_readgeom(&geomtype[j], &geommoreup[j]);   j++;
1197 				if (geommoreup[j-1] == top) break;
1198 			}
1199 			geomindex = j;
1200 			for(look = bot; look != top; look = geommoreup[look])
1201 				if (!geomtype[look])
1202 			{
1203 				io_binindata.arclist[arcindex]->parent = np;
1204 				if (io_readarcinst(io_binindata.arclist[arcindex]))
1205 					return(_("Reading arc"));
1206 				arcindex++;
1207 			} else
1208 			{
1209 				io_binindata.nodelist[nodeindex]->parent = np;
1210 				if (io_readnodeinst(io_binindata.nodelist[nodeindex]))
1211 					return(_("Reading node"));
1212 				nodeindex++;
1213 			}
1214 		} else
1215 		{
1216 			/* version 5 and later find the arcs and nodes in linear order */
1217 			for(j=0; j<io_binindata.arccount[i]; j++)
1218 			{
1219 				io_binindata.arclist[arcindex]->parent = np;
1220 				if (io_readarcinst(io_binindata.arclist[arcindex]))
1221 					return(_("Reading arc"));
1222 				arcindex++;
1223 			}
1224 			for(j=0; j<io_binindata.nodecount[i]; j++)
1225 			{
1226 				io_binindata.nodelist[nodeindex]->parent = np;
1227 				if (io_readnodeinst(io_binindata.nodelist[nodeindex]))
1228 					return(_("Reading node"));
1229 				nodeindex++;
1230 			}
1231 		}
1232 	}
1233 
1234 	if (io_verbose < 0 && io_binindata.filelength > 0 && io_inputprogressdialog != 0)
1235 	{
1236 		DiaSetProgress(io_inputprogressdialog, 999, 1000);
1237 		DiaSetTextProgress(io_inputprogressdialog, _("Cleaning up..."));
1238 	}
1239 
1240 	/* transform indices to pointers */
1241 	if (io_binindata.curnodeproto >= 0 && io_binindata.curnodeproto < io_binindata.nodeprotoindex)
1242 		lib->curnodeproto = io_binindata.nodeprotolist[io_binindata.curnodeproto]; else
1243 			lib->curnodeproto = NONODEPROTO;
1244 
1245 	/* set version pointers (this may be slow for libraries with many cells) */
1246 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1247 	{
1248 		newestversion = NONODEPROTO;
1249 		for(onp = lib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
1250 		{
1251 			if (onp == np) continue;
1252 			if (onp->cellview != np->cellview) continue;
1253 			if (namesame(onp->protoname, np->protoname) != 0) continue;
1254 			if (onp->version <= np->version) continue;
1255 			if (newestversion != NONODEPROTO && newestversion->version >= onp->version)
1256 				continue;
1257 			newestversion = onp;
1258 		}
1259 		if (newestversion != NONODEPROTO)
1260 		{
1261 			/* cell "np" is an old one */
1262 			np->prevversion = newestversion->prevversion;
1263 			newestversion->prevversion = np;
1264 			np->newestversion = newestversion;
1265 		}
1266 	}
1267 
1268 	/* create proper cell lists (version 9 to 11) */
1269 	if (io_binindata.magic <= MAGIC9 && io_binindata.magic >= MAGIC11)
1270 		io_buildcellgrouppointersfromnames(lib);
1271 
1272 	/* link up the nodes and arcs to their geometry modules */
1273 	for(i=0; i<io_binindata.nodeindex; i++)
1274 	{
1275 		ni = io_binindata.nodelist[i];
1276 		geom = ni->geom;
1277 		geom->entryisnode = TRUE;  geom->entryaddr.ni = ni;
1278 		linkgeom(geom, ni->parent);
1279 	}
1280 	for(i=0; i<io_binindata.arcindex; i++)
1281 	{
1282 		ai = io_binindata.arclist[i];
1283 		(void)setshrinkvalue(ai, FALSE);
1284 		geom = ai->geom;
1285 		geom->entryisnode = FALSE;  geom->entryaddr.ai = ai;
1286 		linkgeom(geom, ai->parent);
1287 	}
1288 
1289 	/* create ports on cells that were not found in other libraries */
1290 	io_ensureallports(lib);
1291 
1292 	/* store the version number in the library */
1293 	nextchangequiet();
1294 	(void)setval((INTBIG)lib, VLIBRARY, x_("LIB_former_version"),
1295 		(INTBIG)version, VSTRING|VDONTSAVE);
1296 	efree(version);
1297 
1298 	/* create those pointers not on the disk file */
1299 	if (io_verbose < 0 && io_binindata.filelength > 0)
1300 		io_fixnewlib(lib, io_inputprogressdialog); else
1301 			io_fixnewlib(lib, 0);
1302 
1303 	/* look for any database changes that did not matter */
1304 	for(te=0; te<io_binindata.techcount; te++)
1305 		if (io_binindata.techerror[te] != 0)
1306 	{
1307 		if (io_verbose > 0)
1308 			ttyputmsg(M_("Unknown technology %s not used so all is well"),
1309 				io_binindata.techerror[te]);
1310 		efree(io_binindata.techerror[te]);
1311 	}
1312 	for(i=0; i<io_binindata.aacount; i++)
1313 		if (io_binindata.toolerror[i] != 0)
1314 	{
1315 		if (io_verbose > 0)
1316 			ttyputmsg(M_("Unknown tool %s not used so all is well"),
1317 				io_binindata.toolerror[i]);
1318 		efree(io_binindata.toolerror[i]);
1319 	}
1320 	for(i=0; i<io_binindata.nodepprotoindex; i++)
1321 		if (io_binindata.nodepprotoorig[i] != 0)
1322 	{
1323 		if (io_verbose > 0 && io_binindata.nodepprotoerror[i])
1324 			ttyputmsg(M_("Unknown node %s not used so all is well"),
1325 				io_binindata.nodepprotoorig[i]);
1326 		efree(io_binindata.nodepprotoorig[i]);
1327 	}
1328 	for(i=0; i<io_binindata.portpprotoindex; i++)
1329 		if (io_binindata.portpprotoerror[i] != 0)
1330 	{
1331 		if (io_verbose > 0) ttyputmsg(M_("Unknown port %s not used so all is well"),
1332 			io_binindata.portpprotoerror[i]);
1333 		efree(io_binindata.portpprotoerror[i]);
1334 	}
1335 	for(i=0; i<io_binindata.arcprotoindex; i++)
1336 		if (io_binindata.arcprotoerror[i] != 0)
1337 	{
1338 		if (io_verbose > 0) ttyputmsg(M_("Unknown arc %s not used so all is well"),
1339 			io_binindata.arcprotoerror[i]);
1340 		efree(io_binindata.arcprotoerror[i]);
1341 	}
1342 
1343 	/* warn if the MOSIS CMOS technologies were converted */
1344 	if (convertmosiscmostechnologies != 0)
1345 	{
1346 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1347 		{
1348 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1349 				if (ni->proto->primindex != 0 && ni->proto->tech == mocmos_tech) break;
1350 			if (ni != NONODEINST) break;
1351 			for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1352 				if (ai->proto->tech == mocmos_tech) break;
1353 			if (ai != NOARCINST) break;
1354 		}
1355 		if (np != NONODEPROTO)
1356 			DiaMessageInDialog(
1357 				_("Warning: library %s has older 'mocmossub' technology, converted to new 'mocmos'"),
1358 					lib->libname);
1359 	}
1360 
1361 	/* free the memory used here */
1362 	if (io_binindata.realname != 0)
1363 	{
1364 		for(i=0; i<io_binindata.namecount; i++) efree(io_binindata.realname[i]);
1365 		efree((CHAR *)io_binindata.realname);
1366 	}
1367 	if (io_binindata.newnames != 0) efree((CHAR *)io_binindata.newnames);
1368 	if (io_binindata.magic > MAGIC5)
1369 	{
1370 		/* versions 4 and earlier used geometric data */
1371 		efree((CHAR *)geomtype);
1372 		efree((CHAR *)geommoreup);
1373 	}
1374 	efree((CHAR *)io_binindata.nodelist);
1375 	efree((CHAR *)io_binindata.nodecount);
1376 	efree((CHAR *)io_binindata.nodeprotolist);
1377 	efree((CHAR *)io_binindata.arclist);
1378 	efree((CHAR *)io_binindata.arccount);
1379 	efree((CHAR *)io_binindata.nodepprotolist);
1380 	efree((CHAR *)io_binindata.nodepprototech);
1381 	efree((CHAR *)io_binindata.portprotolist);
1382 	efree((CHAR *)io_binindata.portcount);
1383 	efree((CHAR *)io_binindata.portpprotolist);
1384 	efree((CHAR *)io_binindata.arcprotolist);
1385 	efree((CHAR *)io_binindata.techlist);
1386 	efree((CHAR *)io_binindata.toollist);
1387 	efree((CHAR *)io_binindata.techerror);
1388 	efree((CHAR *)io_binindata.toolerror);
1389 	efree((CHAR *)io_binindata.nodepprotoerror);
1390 	efree((CHAR *)io_binindata.nodepprotoorig);
1391 	efree((CHAR *)io_binindata.portpprotoerror);
1392 	efree((CHAR *)io_binindata.arcprotoerror);
1393 	if (io_binindata.magic <= MAGIC9 && io_binindata.magic >= MAGIC11)
1394 		efree((CHAR *)io_binindata.fakecelllist);
1395 
1396 	return(x_(""));
1397 }
1398 
1399 /******************** COMPONENT INPUT ********************/
1400 
1401 /* routine to read node prototype.  returns true upon error */
io_readnodeproto(NODEPROTO * np,LIBRARY * lib)1402 BOOLEAN io_readnodeproto(NODEPROTO *np, LIBRARY *lib)
1403 {
1404 	INTBIG i, portcount, k;
1405 	REGISTER INTBIG j;
1406 	REGISTER CHAR *cellname;
1407 	REGISTER PORTPROTO *pp, *lpt;
1408 	REGISTER VIEW *v;
1409 
1410 	/* read the cell information (version 9 and later) */
1411 	if (io_binindata.magic <= MAGIC9)
1412 	{
1413 		if (io_binindata.magic >= MAGIC11)
1414 		{
1415 			/* only versions 9 to 11 */
1416 			io_getinbig(&k);
1417 			allocstring(&np->protoname, io_binindata.fakecelllist[k]->cellname, lib->cluster);
1418 		} else
1419 		{
1420 			/* version 12 or later */
1421 			np->protoname = io_getstring(db_cluster);
1422 			io_getinbig(&k);
1423 			np->nextcellgrp = io_binindata.nodeprotolist[k];
1424 			io_getinbig(&k);
1425 //			np->nextcont = io_binindata.nodeprotolist[k];
1426 		}
1427 		io_getinbig(&np->cellview);
1428 		for(v = el_views; v != NOVIEW; v = v->nextview)
1429 			if (v->temp1 == (INTBIG)np->cellview) break;
1430 		if (v == NOVIEW) v = el_unknownview;
1431 		np->cellview = v;
1432 		io_getinbig(&i);
1433 		np->version = i;
1434 		io_getinubig(&np->creationdate);
1435 		io_getinubig(&np->revisiondate);
1436 
1437 		/* copy cell information to the nodeproto */
1438 		np->lib = lib;
1439 	}
1440 
1441 	/* versions 8 and earlier read a cell name */
1442 	if (io_binindata.magic >= MAGIC8)
1443 	{
1444 		cellname = io_getstring(lib->cluster);
1445 		if (cellname == 0) return(TRUE);
1446 		if (io_verbose > 0) ttyputmsg(_("Reading cell %s"), cellname);
1447 
1448 		/* copy cell information to the nodeproto */
1449 		np->lib = lib;
1450 		np->protoname = cellname;
1451 	}
1452 
1453 	/* set the nodeproto primitive index */
1454 	np->primindex = 0;
1455 
1456 	/* read the nodeproto bounding box */
1457 	io_getinbig(&np->lowx);
1458 	io_getinbig(&np->highx);
1459 	io_getinbig(&np->lowy);
1460 	io_getinbig(&np->highy);
1461 
1462 	/* reset the first nodeinst index */
1463 	np->firstinst = NONODEINST;
1464 
1465 	/* zap the technology field */
1466 	np->tech = NOTECHNOLOGY;
1467 
1468 	/* read the library list of nodeproto indices (versions 5 or older) */
1469 	if (io_binindata.magic >= MAGIC5)
1470 	{
1471 		io_getinbig(&np->prevnodeproto);
1472 		if (io_convertnodeproto(&np->prevnodeproto, 0) != 0)
1473 			ttyputmsg(_("...while reading cell %s"), np->protoname);
1474 		io_getinbig(&np->nextnodeproto);
1475 		if (io_convertnodeproto(&np->nextnodeproto, 0) != 0)
1476 			ttyputmsg(_("...while reading cell %s"), np->protoname);
1477 	}
1478 
1479 	/* read the number of portprotos on this nodeproto */
1480 	io_getinbig(&portcount);
1481 	np->numportprotos = portcount;
1482 
1483 	/* read the portprotos on this nodeproto */
1484 	lpt = NOPORTPROTO;
1485 	for(j=0; j<portcount; j++)
1486 	{
1487 		/* set pointers to portproto */
1488 		pp = io_binindata.portprotolist[io_binindata.portprotoindex++];
1489 		if (lpt == NOPORTPROTO) np->firstportproto = pp; else
1490 			lpt->nextportproto = pp;
1491 		lpt = pp;
1492 
1493 		/* set the parent pointer */
1494 		pp->parent = np;
1495 
1496 		/* read the connecting subnodeinst for this portproto */
1497 		io_getinbig(&i);
1498 		if (i >= 0 && i < io_binindata.nodeindex)
1499 			pp->subnodeinst = io_binindata.nodelist[i]; else
1500 		{
1501 			ttyputerr(_("Warning: corrupt data on port.  Do a 'Check and Repair Library'"));
1502 			pp->subnodeinst = NONODEINST;
1503 		}
1504 
1505 		/* read the sub-port prototype of the subnodeinst */
1506 		io_getinbig(&i);
1507 		pp->subportproto = (PORTPROTO *)i;
1508 		if (i >= 0 && io_binindata.portprotolist[i] == NOPORTPROTO)
1509 		{
1510 			pp->temp2 = 1;
1511 		} else
1512 		{
1513 			(void)io_convertportproto(&pp->subportproto, TRUE);
1514 			pp->temp2 = 0;
1515 		}
1516 
1517 		/* read the portproto name and text descriptor */
1518 		pp->protoname = io_getstring(lib->cluster);
1519 		if (pp->protoname == 0) return(TRUE);
1520 		if (io_binindata.magic <= MAGIC9)
1521 		{
1522 			if (io_binindata.converttextdescriptors)
1523 			{
1524 				/* conversion is done later */
1525 				io_getinubig(&pp->textdescript[0]);
1526 				pp->textdescript[1] = 0;
1527 			} else
1528 			{
1529 				io_getinubig(&pp->textdescript[0]);
1530 				io_getinubig(&pp->textdescript[1]);
1531 			}
1532 		}
1533 
1534 		/* ignore the "seen" bits (versions 8 and older) */
1535 		if (io_binindata.magic > MAGIC9) io_getinubig(&k);
1536 
1537 		/* read the portproto tool information */
1538 		if (io_binindata.magic <= MAGIC7)
1539 		{
1540 			/* version 7 and later simply read the relevant data */
1541 			io_getinubig(&pp->userbits);
1542 
1543 			/* versions 7 and 8 ignore net number */
1544 			if (io_binindata.magic >= MAGIC8) io_getinbig(&k);
1545 		} else
1546 		{
1547 			/* version 6 and earlier must sift through the information */
1548 			if (io_binindata.aabcount >= 1) io_getinubig(&pp->userbits);
1549 			for(i=1; i<io_binindata.aabcount; i++) io_getinubig(&k);
1550 		}
1551 
1552 		/* read variable information */
1553 		if (io_readvariables((INTBIG)pp, VPORTPROTO) < 0) return(TRUE);
1554 	}
1555 
1556 	/* set final pointer in portproto list */
1557 	if (lpt == NOPORTPROTO) np->firstportproto = NOPORTPROTO; else
1558 		lpt->nextportproto = NOPORTPROTO;
1559 
1560 	/* read the cell's geometry modules */
1561 	if (io_binindata.magic > MAGIC5)
1562 	{
1563 		/* versions 4 and older have geometry module pointers (ignore it) */
1564 		io_getinbig(&i);
1565 		io_getinbig(&i);
1566 		io_getinbig(&i);
1567 		io_getinbig(&i);
1568 		io_getinbig(&i);
1569 	}
1570 
1571 	/* read tool information */
1572 	io_getinubig(&np->adirty);
1573 	np->adirty = io_arrangetoolbits((INTBIG)np->adirty);
1574 	if (io_binindata.magic <= MAGIC7)
1575 	{
1576 		/* version 7 and later simply read the relevant data */
1577 		io_getinubig(&np->userbits);
1578 
1579 		/* versions 7 and 8 ignore net number */
1580 		if (io_binindata.magic >= MAGIC8) io_getinbig(&k);
1581 	} else
1582 	{
1583 		/* version 6 and earlier must sift through the information */
1584 		if (io_binindata.aabcount >= 1) io_getinubig(&np->userbits);
1585 		for(i=1; i<io_binindata.aabcount; i++) io_getinubig(&k);
1586 	}
1587 	/* build the dummy geometric structure for this cell */
1588 	if (geomstructure(np)) return(TRUE);
1589 
1590 	/* read variable information */
1591 	if (io_readvariables((INTBIG)np, VNODEPROTO) < 0) return(TRUE);
1592 	return(FALSE);
1593 }
1594 
1595 /* routine to read node prototype for external references */
io_readexternalnodeproto(LIBRARY * lib,INTBIG i)1596 void io_readexternalnodeproto(LIBRARY *lib, INTBIG i)
1597 {
1598 	INTBIG portcount, k, vers, lowx, highx, lowy, highy, len, filelen, filetype;
1599 	UINTBIG creation, revision;
1600 	REGISTER INTBIG j, newcell, index;
1601 	REGISTER LIBRARY *elib;
1602 	REGISTER BOOLEAN failed;
1603 	REGISTER CHAR *protoname, *libname, *pt;
1604 	CHAR *filename, *libfile, *oldline2, *libfilepath, *libfilename,
1605 		*dummycellname, **localportnames, *cellname;
1606 	FILE *io;
1607 	REGISTER PORTPROTO *pp, *lpt;
1608 	REGISTER NODEPROTO *np, *onp, *npdummy;
1609 	REGISTER NODEINST *ni;
1610 	REGISTER VIEW *v;
1611 	REGISTER FAKECELL *fc;
1612 	BININPUTDATA savebinindata;
1613 	REGISTER void *infstr;
1614 
1615 	/* read the cell information */
1616 	if (io_binindata.magic >= MAGIC11)
1617 	{
1618 		/* version 11 and earlier */
1619 		io_getinbig(&k);
1620 		fc = io_binindata.fakecelllist[k];
1621 		cellname = fc->cellname;
1622 	} else
1623 	{
1624 		cellname = io_getstring(db_cluster);
1625 		io_getinbig(&k);
1626 		io_getinbig(&k);
1627 	}
1628 	io_getinbig(&k);
1629 	for(v = el_views; v != NOVIEW; v = v->nextview)
1630 		if (v->temp1 == k) break;
1631 	if (v == NOVIEW) v = el_unknownview;
1632 	io_getinbig(&vers);
1633 	io_getinubig(&creation);
1634 	io_getinubig(&revision);
1635 
1636 	/* read the nodeproto bounding box */
1637 	io_getinbig(&lowx);
1638 	io_getinbig(&highx);
1639 	io_getinbig(&lowy);
1640 	io_getinbig(&highy);
1641 
1642 	/* get the path to the library file */
1643 	libfile = io_getstring(el_tempcluster);
1644 	filelen = estrlen(libfile);
1645 
1646 	/* see if this library is already read in */
1647 	infstr = initinfstr();
1648 	addstringtoinfstr(infstr, skippath(libfile));
1649 	libname = returninfstr(infstr);
1650 	len = estrlen(libname);
1651 	if (len < filelen)
1652 	{
1653 		libfilename = &libfile[filelen-len-1];
1654 		*libfilename++ = 0;
1655 		libfilepath = libfile;
1656 	} else
1657 	{
1658 		libfilename = libfile;
1659 		libfilepath = x_("");
1660 	}
1661 
1662 	filetype = io_filetypeblib;
1663 	if (len > 5 && namesame(&libname[len-5], x_(".elib")) == 0)
1664 	{
1665 		libname[len-5] = 0;
1666 	} else if (len > 4 && namesame(&libname[len-4], x_(".txt")) == 0)
1667 	{
1668 		libname[len-4] = 0;
1669 		filetype = io_filetypetlib;
1670 	}
1671 	elib = getlibrary(libname);
1672 	if (elib == NOLIBRARY)
1673 	{
1674 		/* library does not exist: see if file is there */
1675 		io = xopen(libfilename, filetype, io_mainlibdirectory, &filename);
1676 		if (io == 0)
1677 		{
1678 			/* try the path specified in the reference */
1679 			io = xopen(libfilename, filetype, truepath(libfilepath), &filename);
1680 			if (io == 0)
1681 			{
1682 				/* try the library area */
1683 				io = xopen(libfilename, filetype, el_libdir, &filename);
1684 			}
1685 		}
1686 		if (io != 0)
1687 		{
1688 			xclose(io);
1689 			ttyputmsg(_("Reading referenced library %s on %s"), filename,
1690 				timetostring(getcurrenttime()));
1691 #ifdef ONUNIX
1692 			efprintf(stdout, _("Reading referenced library %s on %s\n"), filename,
1693 				timetostring(getcurrenttime()));
1694 #endif
1695 		} else
1696 		{
1697 			infstr = initinfstr();
1698 			formatinfstr(infstr, _("Reference library '%s'"), libname);
1699 			pt = fileselect(returninfstr(infstr), filetype, x_(""));
1700 			if (pt != 0) filename = pt;
1701 		}
1702 		elib = newlibrary(libname, filename);
1703 		if (elib == NOLIBRARY) { efree(libfile);   return; }
1704 
1705 		/* read the external library */
1706 		savebinindata = io_binindata;
1707 		if (io_verbose < 0 && io_binindata.filelength > 0 && io_inputprogressdialog != 0)
1708 		{
1709 			(void)allocstring(&oldline2, DiaGetTextProgress(io_inputprogressdialog), el_tempcluster);
1710 		}
1711 
1712 		len = estrlen(elib->libfile);
1713 		io_libinputrecursivedepth++;
1714 		io_libinputreadmany++;
1715 		if (len > 4 && namesame(&elib->libfile[len-4], x_(".txt")) == 0)
1716 		{
1717 			/* ends in ".txt", presume text file */
1718 			failed = io_doreadtextlibrary(elib, FALSE);
1719 		} else
1720 		{
1721 			/* all other endings: presume binary file */
1722 			failed = io_doreadbinlibrary(elib, FALSE);
1723 		}
1724 		io_libinputrecursivedepth--;
1725 		if (failed) elib->userbits |= UNWANTEDLIB; else
1726 		{
1727 			/* queue this library for announcement through change control */
1728 			io_queuereadlibraryannouncement(elib);
1729 		}
1730 		io_binindata = savebinindata;
1731 		if (io_verbose < 0 && io_binindata.filelength > 0 && io_inputprogressdialog != 0)
1732 		{
1733 			DiaSetProgress(io_inputprogressdialog, io_binindata.bytecount, io_binindata.filelength);
1734 			infstr = initinfstr();
1735 			formatinfstr(infstr, _("Reading library %s"), lib->libname);
1736 			DiaSetCaptionProgress(io_inputprogressdialog, returninfstr(infstr));
1737 			DiaSetTextProgress(io_inputprogressdialog, oldline2);
1738 			efree(oldline2);
1739 		}
1740 	}
1741 
1742 	/* read the portproto names on this nodeproto */
1743 	io_getinbig(&portcount);
1744 	if (portcount > 0)
1745 		localportnames = (CHAR **)emalloc(portcount * (sizeof (CHAR *)), el_tempcluster);
1746 	for(j=0; j<portcount; j++)
1747 	{
1748 		/* read the portproto name */
1749 		protoname = io_gettempstring();
1750 		if (protoname == 0) break;
1751 		(void)allocstring(&localportnames[j], protoname, el_tempcluster);
1752 	}
1753 
1754 	/* find this cell in the external library */
1755 	npdummy = NONODEPROTO;
1756 	for(index=0; ; index++)
1757 	{
1758 		infstr = initinfstr();
1759 		formatinfstr(infstr, _("%sFROM%s"), cellname, elib->libname);
1760 		if (index > 0) formatinfstr(infstr, x_(".%ld"), index);
1761 		(void)allocstring(&dummycellname, returninfstr(infstr), el_tempcluster);
1762 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1763 			if (namesame(np->protoname, dummycellname) == 0) break;
1764 		if (np == NONODEPROTO) break;
1765 		efree((CHAR *)dummycellname);
1766 	}
1767 	for(np = elib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1768 	{
1769 		if (np->lib != elib)
1770 		{
1771 			ttyputerr(_("ERROR: Bad cell in library %s"), elib->libname);
1772 			continue;
1773 		}
1774 		if (np->cellview != v) continue;
1775 		if (namesame(np->protoname, dummycellname) == 0) npdummy = np;
1776 		if (np->version != vers) continue;
1777 		if (namesame(np->protoname, cellname) != 0) continue;
1778 		break;
1779 	}
1780 	if (np == NONODEPROTO) np = npdummy;
1781 	if (np == NONODEPROTO)
1782 	{
1783 		/* cell not found in library: issue warning */
1784 		infstr = initinfstr();
1785 		addstringtoinfstr(infstr, cellname);
1786 		if (v != el_unknownview)
1787 			formatinfstr(infstr, x_("{%s}"), v->sviewname);
1788 		ttyputerr(_("Cannot find cell %s in library %s"),
1789 			returninfstr(infstr), elib->libname);
1790 	}
1791 
1792 	/* if cell found, check that size is unchanged */
1793 	if (np != NONODEPROTO)
1794 	{
1795 #if 0
1796 		if (np->lowx != lowx || np->highx != highx ||
1797 			np->lowy != lowy || np->highy != highy)
1798 #else
1799 		if (np->highx-np->lowx != highx-lowx ||
1800 			np->highy-np->lowy != highy-lowy)
1801 #endif
1802 		{
1803 			ttyputerr(_("Error: cell %s in library %s has changed size since its use in library %s"),
1804 				nldescribenodeproto(np), elib->libname, lib->libname);
1805 			ttyputerr(_("   Cell %s in library %s is now %sx%s but the instance in library %s is %sx%s"),
1806 				nldescribenodeproto(np), elib->libname, latoa(np->highx-np->lowx,0),
1807 				latoa(np->highy-np->lowy,0), lib->libname, latoa(highx-lowx,0), latoa(highy-lowy,0));
1808 			np = NONODEPROTO;
1809 		}
1810 	}
1811 
1812 	/* if cell found, check that ports match */
1813 	if (np != NONODEPROTO)
1814 	{
1815 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1816 			pp->temp1 = 0;
1817 		for(j=0; j<portcount; j++)
1818 		{
1819 			protoname = localportnames[j];
1820 			for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1821 				if (namesame(protoname, pp->protoname) == 0) break;
1822 			if (pp == NOPORTPROTO)
1823 			{
1824 				ttyputerr(_("Error: cell %s in library %s must have port %s"),
1825 					describenodeproto(np), elib->libname, protoname);
1826 				np = NONODEPROTO;
1827 				break;
1828 			}
1829 			pp->temp1 = 1;
1830 		}
1831 	}
1832 #if 0
1833 	if (np != NONODEPROTO)
1834 	{
1835 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1836 		{
1837 			if (pp->temp1 != 0) continue;
1838 			ttyputerr(_("Error: cell %s in library %s, should not have port %s"),
1839 				describenodeproto(np), elib->libname, pp->protoname);
1840 			np = NONODEPROTO;
1841 			break;
1842 		}
1843 	}
1844 #endif
1845 
1846 	/* if cell found, warn if minor modification was made */
1847 	if (np != NONODEPROTO)
1848 	{
1849 		if (np->revisiondate != revision)
1850 		{
1851 			ttyputerr(_("Warning: cell %s in library %s has changed since its use in library %s"),
1852 				describenodeproto(np), elib->libname, lib->libname);
1853 		}
1854 	}
1855 
1856 	/* make new cell if needed */
1857 	if (np != NONODEPROTO) newcell = 0; else
1858 	{
1859 		/* create a cell that meets these specs */
1860 		newcell = 1;
1861 		ttyputerr(_("...Creating dummy version of cell in library %s"), lib->libname);
1862 		np = allocnodeproto(lib->cluster);
1863 		if (np == NONODEPROTO) return;
1864 		np->primindex = 0;
1865 		np->lowx = lowx;
1866 		np->highx = highx;
1867 		np->lowy = lowy;
1868 		np->highy = highy;
1869 		np->firstinst = NONODEINST;
1870 		np->firstnodeinst = NONODEINST;
1871 		np->firstarcinst = NOARCINST;
1872 		np->tech = NOTECHNOLOGY;
1873 		np->lib = lib;
1874 		np->firstportproto = NOPORTPROTO;
1875 		np->adirty = 0;
1876 		np->cellview = v;
1877 		np->creationdate = creation;
1878 		np->revisiondate = revision;
1879 		setval((INTBIG)np, VNODEPROTO, x_("IO_true_library"), (INTBIG)elib->libname, VSTRING);
1880 
1881 		/* rename cell */
1882 		(void)allocstring(&np->protoname, dummycellname, lib->cluster);
1883 
1884 		/* determine version number of this cell */
1885 		np->version = 1;
1886 		FOR_CELLGROUP(onp, np)
1887 		{
1888 			if (onp->cellview == v && namesame(onp->protoname, np->protoname) == 0 &&
1889 				onp->version >= np->version)
1890 					np->version = onp->version + 1;
1891 		}
1892 
1893 		/* insert in the library and cell structures */
1894 		if (i != 0)		/* why not always? */
1895 		{
1896 			/* NEW CELL-based CODE */
1897 			db_insertnodeproto(np);
1898 		}
1899 
1900 		/* create initial R-tree data */
1901 		if (geomstructure(np)) return;
1902 
1903 		/* create an artwork "Crossed box" to define the cell size */
1904 		ni = allocnodeinst(lib->cluster);
1905 		ni->proto = art_crossedboxprim;
1906 		ni->parent = np;
1907 		ni->nextnodeinst = np->firstnodeinst;
1908 		np->firstnodeinst = ni;
1909 		ni->lowx = lowx;   ni->highx = highx;
1910 		ni->lowy = lowy;   ni->highy = highy;
1911 		ni->geom = allocgeom(lib->cluster);
1912 		ni->geom->entryisnode = TRUE;   ni->geom->entryaddr.ni = ni;
1913 		linkgeom(ni->geom, np);
1914 	}
1915 	io_binindata.nodeprotolist[i] = np;
1916 	efree(dummycellname);
1917 
1918 	/* read the portprotos on this nodeproto */
1919 	lpt = NOPORTPROTO;
1920 	for(j=0; j<portcount; j++)
1921 	{
1922 		/* read the portproto name */
1923 		protoname = localportnames[j];
1924 		pp = getportproto(np, protoname);
1925 		if (pp == NOPORTPROTO)
1926 		{
1927 			if (newcell == 0)
1928 				ttyputerr(_("Cannot find port %s on cell %s in library %s"),
1929 					protoname, describenodeproto(np), elib->libname);
1930 			pp = allocportproto(lib->cluster);
1931 			(void)allocstring(&pp->protoname, protoname, lib->cluster);
1932 			pp->parent = np;
1933 			if (lpt == NOPORTPROTO) np->firstportproto = pp; else
1934 				lpt->nextportproto = pp;
1935 			lpt = pp;
1936 			pp->temp2 = 0;
1937 		}
1938 		io_binindata.portprotolist[io_binindata.portprotoindex] = pp;
1939 		io_binindata.portprotoindex++;
1940 	}
1941 
1942 	/* free memory */
1943 	for(j=0; j<portcount; j++)
1944 		efree(localportnames[j]);
1945 	if (portcount > 0) efree((CHAR *)localportnames);
1946 	efree(libfile);
1947 }
1948 
1949 /* routine to read a node instance.  returns true upon error */
io_readnodeinst(NODEINST * ni)1950 BOOLEAN io_readnodeinst(NODEINST *ni)
1951 {
1952 	INTBIG i, k;
1953 	REGISTER INTBIG j, arcindex;
1954 	CHAR *inst;
1955 	REGISTER PORTARCINST *pi, *lpo;
1956 	REGISTER PORTEXPINST *pe, *lpe;
1957 	PORTPROTO *pp;
1958 	REGISTER ARCINST *ai;
1959 	static INTBIG orignodenamekey = 0;
1960 
1961 	/* read the nodeproto index */
1962 	io_getinbig(&ni->proto);
1963 	if (io_convertnodeproto(&ni->proto, &inst) != 0)
1964 		ttyputmsg(_("...while reading node instance"));
1965 	if (inst != 0)
1966 	{
1967 		if (orignodenamekey == 0) orignodenamekey = makekey(x_("NODE_original_name"));
1968 		nextchangequiet();
1969 		(void)setvalkey((INTBIG)ni, VNODEINST, orignodenamekey, (INTBIG)inst, VSTRING|VDONTSAVE);
1970 	}
1971 
1972 	/* read the descriptive information */
1973 	io_getinbig(&ni->lowx);
1974 	io_getinbig(&ni->lowy);
1975 	io_getinbig(&ni->highx);
1976 	io_getinbig(&ni->highy);
1977 
1978 	/* ignore anchor point for cell references (version 13 and later) */
1979 	if (io_binindata.magic <= MAGIC13)
1980 	{
1981 		if (ni->proto->primindex == 0)
1982 		{
1983 			io_getinbig(&i);
1984 			io_getinbig(&i);
1985 		}
1986 	}
1987 
1988 	/* read rotation and transposition */
1989 	io_getinbig(&i);
1990 	io_getinbig(&k);
1991 	ni->rotation = (INTSML)k;
1992 
1993 	/* in 7.01 and higher, allow mirror bits */
1994 	if (io_binindata.emajor > 7 || (io_binindata.emajor == 7 && io_binindata.eminor >= 1))
1995 	{
1996 		/* new version: allow mirror bits */
1997 		ni->transpose = 0;
1998 		if ((i&1) != 0)
1999 		{
2000 			/* the old-style transpose bit */
2001 			ni->transpose = 1;
2002 		} else
2003 		{
2004 			/* check for new style mirror bits */
2005 			if ((i&2) != 0)
2006 			{
2007 				if ((i&4) != 0)
2008 				{
2009 					/* mirror in X and Y */
2010 					ni->rotation = (ni->rotation + 1800) % 3600;
2011 				} else
2012 				{
2013 					/* mirror in X */
2014 					ni->rotation = (ni->rotation + 900) % 3600;
2015 					ni->transpose = 1;
2016 				}
2017 			} else if ((i&4) != 0)
2018 			{
2019 				/* mirror in Y */
2020 				ni->rotation = (ni->rotation + 2700) % 3600;
2021 				ni->transpose = 1;
2022 			}
2023 		}
2024 	} else
2025 	{
2026 		/* old version: just treat it as a transpose */
2027 		if (i != 0) ni->transpose = 1; else
2028 			ni->transpose = 0;
2029 	}
2030 
2031 	/* versions 9 and later get text descriptor for cell name */
2032 	if (io_binindata.magic <= MAGIC9)
2033 	{
2034 		if (io_binindata.converttextdescriptors)
2035 		{
2036 			/* conversion is done later */
2037 			io_getinubig(&ni->textdescript[0]);
2038 			ni->textdescript[1] = 0;
2039 		} else
2040 		{
2041 			io_getinubig(&ni->textdescript[0]);
2042 			io_getinubig(&ni->textdescript[1]);
2043 		}
2044 	}
2045 
2046 	/* read the nodeinst name (versions 1, 2, or 3 only) */
2047 	if (io_binindata.magic >= MAGIC3)
2048 	{
2049 		inst = io_getstring(el_tempcluster);
2050 		if (inst == 0) return(TRUE);
2051 		if (*inst != 0)
2052 		{
2053 			nextchangequiet();
2054 			if (setvalkey((INTBIG)ni, VNODEINST, el_node_name_key,
2055 				(INTBIG)inst, VSTRING|VDISPLAY) == NOVARIABLE) return(TRUE);
2056 		}
2057 		efree(inst);
2058 	}
2059 
2060 	/* ignore the geometry index (versions 4 or older) */
2061 	if (io_binindata.magic > MAGIC5) io_getinbig(&i);
2062 
2063 	/* read the arc ports */
2064 	io_getinbig(&i);
2065 	lpo = NOPORTARCINST;
2066 	for(j=0; j<i; j++)
2067 	{
2068 		/* read the arcinst information (and the particular end on the arc) */
2069 		io_getinbig(&k);
2070 		arcindex = k >> 1;
2071 		if (k < 0 || arcindex >= io_binindata.arcindex) return(TRUE);
2072 		ai = io_binindata.arclist[arcindex];
2073 		pi = ai->end[k&1].portarcinst;
2074 		pi->conarcinst = ai;
2075 
2076 		/* link in the portarcinst */
2077 		if (j == 0) ni->firstportarcinst = pi; else lpo->nextportarcinst = pi;
2078 		lpo = pi;
2079 
2080 		/* read the arcinst index */
2081 		io_getinbig(&pi->proto);
2082 		(void)io_convertportproto(&pi->proto, TRUE);
2083 
2084 		/* read variable information */
2085 		if (io_readvariables((INTBIG)pi, VPORTARCINST) < 0) return(TRUE);
2086 	}
2087 
2088 	/* setup the last portinst pointer */
2089 	if (i == 0) ni->firstportarcinst = NOPORTARCINST; else
2090 		lpo->nextportarcinst = NOPORTARCINST;
2091 
2092 	/* read the exports */
2093 	io_getinbig(&i);
2094 	lpe = NOPORTEXPINST;
2095 	for(j=0; j<i; j++)
2096 	{
2097 		/* read the export index */
2098 		io_getinbig(&pp);
2099 		(void)io_convertportproto(&pp, TRUE);
2100 		pe = pp->subportexpinst;
2101 		pe->exportproto = pp;
2102 
2103 		if (j == 0) ni->firstportexpinst = pe; else lpe->nextportexpinst = pe;
2104 		lpe = pe;
2105 
2106 		/* read the export prototype */
2107 		io_getinbig(&pe->proto);
2108 		(void)io_convertportproto(&pe->proto, TRUE);
2109 		pp->subportproto = pe->proto;
2110 
2111 		/* read variable information */
2112 		if (io_readvariables((INTBIG)pe, VPORTEXPINST) < 0) return(TRUE);
2113 	}
2114 
2115 	/* setup the last portinst pointer */
2116 	if (i == 0) ni->firstportexpinst = NOPORTEXPINST; else
2117 		lpe->nextportexpinst = NOPORTEXPINST;
2118 
2119 	/* ignore the "seen" bits (versions 8 and older) */
2120 	if (io_binindata.magic > MAGIC9) io_getinubig(&k);
2121 
2122 	/* read the tool information */
2123 	if (io_binindata.magic <= MAGIC7)
2124 	{
2125 		/* version 7 and later simply read the relevant data */
2126 		io_getinubig(&ni->userbits);
2127 	} else
2128 	{
2129 		/* version 6 and earlier must sift through the information */
2130 		if (io_binindata.aabcount >= 1) io_getinubig(&ni->userbits);
2131 		for(i=1; i<io_binindata.aabcount; i++) io_getinubig(&k);
2132 	}
2133 
2134 	/* read variable information */
2135 	if (io_readvariables((INTBIG)ni, VNODEINST) < 0) return(TRUE);
2136 
2137 	return(FALSE);
2138 }
2139 
2140 /* routine to read (and mostly ignore) a geometry module */
io_readgeom(BOOLEAN * isnode,INTBIG * moreup)2141 void io_readgeom(BOOLEAN *isnode, INTBIG *moreup)
2142 {
2143 	INTBIG i, type;
2144 
2145 	io_getinbig(&type);				/* read entrytype */
2146 	if (type != 0) *isnode = TRUE; else
2147 		*isnode = FALSE;
2148 	if (*isnode) io_getinbig(&i);/* skip entryaddr */
2149 	io_getinbig(&i);				/* skip lowx */
2150 	io_getinbig(&i);				/* skip highx */
2151 	io_getinbig(&i);				/* skip lowy */
2152 	io_getinbig(&i);				/* skip highy */
2153 	io_getinbig(&i);				/* skip moreleft */
2154 	io_getinbig(&i);				/* skip ll */
2155 	io_getinbig(&i);				/* skip moreright */
2156 	io_getinbig(&i);				/* skip lr */
2157 	io_getinbig(moreup);			/* read moreup */
2158 	io_getinbig(&i);				/* skip lu */
2159 	io_getinbig(&i);				/* skip moredown */
2160 	io_getinbig(&i);				/* skip ld */
2161 	io_ignorevariables();			/* skip variables */
2162 }
2163 
io_readarcinst(ARCINST * ai)2164 BOOLEAN io_readarcinst(ARCINST *ai)
2165 {
2166 	INTBIG i, j, index;
2167 	REGISTER CHAR *inst;
2168 
2169 	/* read the arcproto pointer */
2170 	io_getinbig(&ai->proto);
2171 	io_convertarcproto(&ai->proto);
2172 
2173 	/* read the arc length (versions 5 or older) */
2174 	if (io_binindata.magic >= MAGIC5) io_getinbig(&ai->length);
2175 
2176 	/* read the arc width */
2177 	io_getinbig(&ai->width);
2178 
2179 	/* ignore the signals value (versions 6, 7, or 8) */
2180 	if (io_binindata.magic <= MAGIC6 && io_binindata.magic >= MAGIC8)
2181 		io_getinbig(&i);
2182 
2183 	/* read the arcinst name (versions 3 or older) */
2184 	if (io_binindata.magic >= MAGIC3)
2185 	{
2186 		inst = io_getstring(el_tempcluster);
2187 		if (inst == 0) return(TRUE);
2188 		if (*inst != 0)
2189 		{
2190 			nextchangequiet();
2191 			if (setvalkey((INTBIG)ai, VARCINST, el_arc_name_key,
2192 				(INTBIG)inst, VSTRING|VDISPLAY) == NOVARIABLE) return(TRUE);
2193 		}
2194 		efree(inst);
2195 	}
2196 
2197 	/* read the arcinst end information */
2198 	for(i=0; i<2; i++)
2199 	{
2200 		io_getinbig(&ai->end[i].xpos);
2201 		io_getinbig(&ai->end[i].ypos);
2202 
2203 		/* read the arcinst's connecting nodeinst index */
2204 		io_getinbig(&ai->end[i].nodeinst);
2205 		index = (INTBIG)ai->end[i].nodeinst;
2206 		if (index >= 0 && index < io_binindata.nodeindex)
2207 			ai->end[i].nodeinst = io_binindata.nodelist[index]; else
2208 		{
2209 			ttyputerr(_("Warning: corrupt data on arc.  Do a 'Check and Repair Library'"));
2210 			ai->end[i].nodeinst = NONODEINST;
2211 		}
2212 	}
2213 
2214 	/* compute the arc length (versions 6 or newer) */
2215 	if (io_binindata.magic <= MAGIC6) ai->length = computedistance(ai->end[0].xpos,
2216 		ai->end[0].ypos, ai->end[1].xpos, ai->end[1].ypos);
2217 
2218 	/* ignore the geometry index (versions 4 or older) */
2219 	if (io_binindata.magic > MAGIC5) io_getinbig(&i);
2220 
2221 	/* ignore the "seen" bits (versions 8 and older) */
2222 	if (io_binindata.magic > MAGIC9) io_getinubig(&i);
2223 
2224 	/* read the arcinst's tool information */
2225 	if (io_binindata.magic <= MAGIC7)
2226 	{
2227 		/* version 7 and later simply read the relevant data */
2228 		io_getinubig(&ai->userbits);
2229 
2230 		/* versions 7 and 8 ignore net number */
2231 		if (io_binindata.magic >= MAGIC8) io_getinbig(&j);
2232 	} else
2233 	{
2234 		/* version 6 and earlier must sift through the information */
2235 		if (io_binindata.aabcount >= 1) io_getinubig(&ai->userbits);
2236 		for(i=1; i<io_binindata.aabcount; i++) io_getinubig(&j);
2237 	}
2238 
2239 	/* read variable information */
2240 	if (io_readvariables((INTBIG)ai, VARCINST) < 0) return(TRUE);
2241 	return(FALSE);
2242 }
2243 
2244 /******************** VARIABLE ROUTINES ********************/
2245 
2246 /* routine to read the global namespace.  returns true upon error */
io_readnamespace(void)2247 BOOLEAN io_readnamespace(void)
2248 {
2249 	REGISTER INTBIG i;
2250 
2251 	io_getinbig(&io_binindata.namecount);
2252 	if (io_verbose > 0) ttyputmsg(M_("Reading %ld variable names"), io_binindata.namecount);
2253 	if (io_binindata.namecount == 0) return(FALSE);
2254 
2255 	/* read in the namespace */
2256 	io_binindata.newnames = (INTBIG *)emalloc((SIZEOFINTBIG * io_binindata.namecount), el_tempcluster);
2257 	if (io_binindata.newnames == 0) return(TRUE);
2258 	io_binindata.realname = (CHAR **)emalloc(((sizeof (CHAR *)) * io_binindata.namecount), el_tempcluster);
2259 	if (io_binindata.realname == 0) return(TRUE);
2260 	for(i=0; i<io_binindata.namecount; i++)
2261 	{
2262 		io_binindata.realname[i] = io_getstring(el_tempcluster);
2263 		if (io_binindata.realname[i] == 0) return(TRUE);
2264 		io_binindata.newnames[i] = 0;
2265 	}
2266 	return(FALSE);
2267 }
2268 
2269 /*
2270  * routine to ignore one set of object variables on readin
2271  */
io_ignorevariables(void)2272 void io_ignorevariables(void)
2273 {
2274 	NODEINST node;
2275 
2276 	initdummynode(&node);
2277 	(void)io_readvariables((INTBIG)&node, VNODEINST);
2278 
2279 	/* this next line is not strictly legal!!! */
2280 	if (node.numvar != 0) db_freevars(&node.firstvar, &node.numvar);
2281 }
2282 
2283 /*
2284  * routine to read a set of object variables.  returns negative upon error and
2285  * otherwise returns the number of variables read
2286  */
io_readvariables(INTBIG addr,INTBIG type)2287 INTBIG io_readvariables(INTBIG addr, INTBIG type)
2288 {
2289 	REGISTER INTBIG i, j, datasize, ty, keyval;
2290 	REGISTER INTBIG ret;
2291 	REGISTER VARIABLE *var;
2292 	REGISTER BOOLEAN invalid;
2293 	INTBIG count, newtype, len, newaddr, cou, defineddescript;
2294 	UINTBIG newdescript[TEXTDESCRIPTSIZE];
2295 	INTSML key;
2296 
2297 	io_getinbig(&count);
2298 	if (io_verbose > 0 && count > 0)
2299 		 ttyputmsg(M_("Reading %ld variables on %s object"),
2300 			count, describeobject(addr, type));
2301 	for(i=0; i<count; i++)
2302 	{
2303 		io_getin(&key, io_binindata.sizeofsmall, SIZEOFINTSML, FALSE);
2304 		io_getinbig(&newtype);
2305 		ty = newtype;
2306 		if (io_verbose > 0 && (type == VTOOL || type == VTECHNOLOGY))
2307 			ttyputmsg(M_("   Reading variable %ld: %s (type=0%o)"), i, io_binindata.realname[key], ty);
2308 
2309 		/* version 9 and later reads text description on displayable variables */
2310 		defineddescript = 0;
2311 		if (io_binindata.magic <= MAGIC9)
2312 		{
2313 			if (io_binindata.alwaystextdescriptors)
2314 			{
2315 				io_getinubig(&newdescript[0]);
2316 				io_getinubig(&newdescript[1]);
2317 				defineddescript = 1;
2318 			} else
2319 			{
2320 				if ((ty&VDISPLAY) != 0)
2321 				{
2322 					if (io_binindata.converttextdescriptors)
2323 					{
2324 						/* conversion is done later */
2325 						io_getinubig(&newdescript[0]);
2326 						newdescript[1] = 0;
2327 					} else
2328 					{
2329 						io_getinubig(&newdescript[0]);
2330 						io_getinubig(&newdescript[1]);
2331 					}
2332 					defineddescript = 1;
2333 				}
2334 			}
2335 		}
2336 		if (defineddescript == 0)
2337 		{
2338 			TDCLEAR(newdescript);
2339 			defaulttextdescript(newdescript, NOGEOM);
2340 		}
2341 		if ((ty&VISARRAY) != 0)
2342 		{
2343 			io_getinbig(&len);
2344 			cou = len;
2345 			if ((ty&VLENGTH) == 0) cou++;
2346 			if ((ty&VTYPE) == VCHAR) datasize = SIZEOFCHAR; else
2347 				if ((ty&VTYPE) == VDOUBLE) datasize = SIZEOFINTBIG*2; else
2348 					if ((ty&VTYPE) == VSHORT) datasize = 2; else
2349 						datasize = SIZEOFINTBIG;
2350 			newaddr = (INTBIG)emalloc((cou*datasize), el_tempcluster);
2351 			if (newaddr == 0) return(-1);
2352 			if ((ty&VTYPE) == VGENERAL)
2353 			{
2354 				for(j=0; j<len; j += 2)
2355 				{
2356 					io_getinbig((INTBIG *)(newaddr + (j+1)*datasize));
2357 					ret = io_getinvar((INTBIG *)(newaddr + j*datasize),
2358 						*(INTBIG *)(newaddr + (j+1)*datasize));
2359 					if (ret < 0) return(-1);
2360 					if (ret > 0)
2361 					{
2362 						ttyputmsg(_("...while reading variable '%s' on %s object"),
2363 							io_binindata.realname[key], us_variabletypename(type));
2364 					}
2365 				}
2366 			} else
2367 			{
2368 				for(j=0; j<len; j++)
2369 				{
2370 					ret = io_getinvar((INTBIG *)(newaddr + j*datasize), ty);
2371 					if (ret < 0) return(-1);
2372 					if (ret > 0)
2373 					{
2374 						ttyputmsg(_("...while reading variable '%s' on %s object"),
2375 							io_binindata.realname[key], us_variabletypename(type));
2376 					}
2377 				}
2378 			}
2379 			if ((ty&VLENGTH) == 0)
2380 				for(j=0; j<datasize; j++)
2381 					((CHAR *)newaddr)[len*datasize+j] = -1;
2382 		} else
2383 		{
2384 			if ((newtype&VTYPE) == VDOUBLE) newtype = (newtype & ~VTYPE) | VFLOAT;
2385 			ret = io_getinvar(&newaddr, ty);
2386 			if (ret < 0) return(-1);
2387 			if (ret > 0)
2388 			{
2389 				ttyputmsg(_("...while reading variable '%s' on %s object"),
2390 					io_binindata.realname[key], us_variabletypename(type));
2391 			}
2392 		}
2393 
2394 		/* copy this variable into database */
2395 		if (key < 0 || key >= io_binindata.namecount)
2396 		{
2397 			ttyputmsg(_("Bad variable index (%ld, limit is %ld) on %s object"),
2398 				key, io_binindata.namecount, describeobject(addr, type));
2399 			return(-1);
2400 		}
2401 
2402 		/* see if the variable is deprecated */
2403 		invalid = isdeprecatedvariable(addr, type, io_binindata.realname[key]);
2404 		if (!invalid)
2405 		{
2406 			if (io_binindata.newnames[key] == 0)
2407 				io_binindata.newnames[key] = makekey(io_binindata.realname[key]);
2408 			keyval = io_binindata.newnames[key];
2409 			nextchangequiet();
2410 
2411 			var = setvalkey(addr, type, keyval, newaddr, newtype);
2412 			if (var == NOVARIABLE) return(-1);
2413 			TDCOPY(var->textdescript, newdescript);
2414 
2415 			/* handle updating of technology caches */
2416 			if (type == VTECHNOLOGY)
2417 				changedtechnologyvariable(keyval);
2418 		}
2419 
2420 		/* free the memory allocated for the creation of this variable */
2421 		if ((ty&VTYPE) == VSTRING || (ty&(VCODE1|VCODE2)) != 0)
2422 		{
2423 			if ((ty&VISARRAY) == 0) efree((CHAR *)newaddr); else
2424 				for(j=0; j<len; j++) efree((CHAR *)((INTBIG *)newaddr)[j]);
2425 		}
2426 		if ((ty&VISARRAY) != 0) efree((CHAR *)newaddr);
2427 	}
2428 	return(count);
2429 }
2430 
2431 /*
2432  * Helper routine to read a variable at address "addr" of type "ty".
2433  * Returns zero if OK, negative on memory error, positive if there were
2434  * correctable problems in the read.
2435  */
io_getinvar(INTBIG * addr,INTBIG ty)2436 INTBIG io_getinvar(INTBIG *addr, INTBIG ty)
2437 {
2438 	INTBIG i;
2439 	REGISTER CHAR *pp;
2440 	REGISTER ARCINST *ai;
2441 	PORTPROTO *ppr;
2442 	double doub;
2443 
2444 	if ((ty&(VCODE1|VCODE2)) != 0) ty = VSTRING;
2445 	switch (ty&VTYPE)
2446 	{
2447 		case VADDRESS:
2448 		case VINTEGER:
2449 		case VFRACT:
2450 			io_getinbig(addr);
2451 			if ((ty&VTYPE) == VFLOAT)
2452 			{
2453 				if (io_binindata.swap_bytes != 0) io_binindata.swapped_floats++;
2454 			}
2455 			break;
2456 		case VFLOAT:
2457 			io_getin(addr, sizeof(float), sizeof(float), FALSE);
2458 			if (io_binindata.swap_bytes != 0) io_binindata.swapped_doubles++;
2459 			break;
2460 		case VDOUBLE:
2461 			io_getin(&doub, sizeof(double), sizeof(double), FALSE);
2462 			*addr = castint((float)doub);
2463 			if (io_binindata.swap_bytes != 0) io_binindata.swapped_doubles++;
2464 			break;
2465 		case VSHORT:
2466 			io_getin(addr, io_binindata.sizeofsmall, SIZEOFINTSML, TRUE);
2467 			break;
2468 		case VBOOLEAN:
2469 		case VCHAR:
2470 			io_getin(addr, 1, 1, FALSE);
2471 			break;
2472 		case VSTRING:
2473 			pp = io_getstring(el_tempcluster);
2474 			if (pp == 0) return(-1);
2475 			*addr = (INTBIG)pp;
2476 			break;
2477 		case VNODEINST:
2478 			io_getinbig(addr);
2479 			if (*addr < 0 || *addr >= io_binindata.nodeindex) *addr = -1; else
2480 				*addr = (INTBIG)io_binindata.nodelist[*addr];
2481 			break;
2482 		case VNODEPROTO:
2483 			io_getinbig(addr);
2484 			if (io_convertnodeproto((NODEPROTO **)addr, 0) != 0) return(1);
2485 			break;
2486 		case VARCPROTO:
2487 			io_getinbig(addr);
2488 			io_convertarcproto((ARCPROTO **)addr);
2489 			break;
2490 		case VPORTPROTO:
2491 			io_getinbig(addr);
2492 			(void)io_convertportproto((PORTPROTO **)addr, TRUE);
2493 			break;
2494 		case VARCINST:
2495 			io_getinbig(addr);
2496 			if (*addr < 0 || *addr >= io_binindata.arcindex) *addr = -1; else
2497 				*addr = (INTBIG)io_binindata.arclist[*addr];
2498 			break;
2499 		case VGEOM:
2500 			*addr = -1;
2501 			io_getinbig(&i);
2502 			if (io_binindata.magic <= MAGIC5)
2503 			{
2504 				/* versions 5 and later store extra information */
2505 				if (i != 0)
2506 				{
2507 					io_getinbig(addr);
2508 					if (*addr < 0 || *addr >= io_binindata.nodeindex) *addr = -1;
2509 						else *addr = (INTBIG)io_binindata.nodelist[*addr]->geom;
2510 				} else
2511 				{
2512 					io_getinbig(addr);
2513 					if (*addr < 0 || *addr >= io_binindata.arcindex) *addr = -1;
2514 						else *addr = (INTBIG)io_binindata.arclist[*addr]->geom;
2515 				}
2516 			}
2517 			break;
2518 		case VTECHNOLOGY:
2519 			io_getinbig(addr);
2520 			if (*addr != -1) *addr = (INTBIG)io_gettechlist(*addr);
2521 			break;
2522 		case VPORTARCINST:
2523 			io_getinbig(addr);
2524 			if (*addr != -1)
2525 			{
2526 				ai = io_binindata.arclist[(*addr) >> 1];
2527 				i = (*addr) & 1;
2528 				*addr = (INTBIG)ai->end[i].portarcinst;
2529 			}
2530 			break;
2531 		case VPORTEXPINST:
2532 			io_getinbig(addr);
2533 			if (*addr != -1)
2534 			{
2535 				ppr = (PORTPROTO *)*addr;
2536 				(void)io_convertportproto(&ppr, TRUE);
2537 				*addr = (INTBIG)ppr->subportexpinst;
2538 			}
2539 			break;
2540 		case VLIBRARY:
2541 			pp = io_getstring(el_tempcluster);
2542 			if (pp == 0) return(-1);
2543 			*addr = (INTBIG)getlibrary(pp);
2544 			break;
2545 		case VTOOL:
2546 			io_getinbig(addr);
2547 			if (*addr < 0 || *addr >= io_binindata.aacount) *addr = -1; else
2548 			{
2549 				i = io_binindata.toollist[*addr];
2550 				if (i < 0 || i >= el_maxtools)
2551 				{
2552 					i = 0;
2553 					if (io_binindata.toolerror[*addr] != 0)
2554 					{
2555 						ttyputerr(_("WARNING: no tool called '%s', using 'user'"),
2556 							io_binindata.toolerror[*addr]);
2557 						efree(io_binindata.toolerror[*addr]);
2558 						io_binindata.toolerror[*addr] = 0;
2559 					}
2560 				}
2561 				*addr = (INTBIG)&el_tools[i];
2562 			}
2563 			break;
2564 		case VRTNODE:
2565 			*addr = -1;
2566 			break;
2567    }
2568    return(0);
2569 }
2570 
2571 /*
2572  * routine to fix variables that make reference to external cells.
2573  */
io_fixexternalvariables(VARIABLE * firstvar,INTSML numvar)2574 void io_fixexternalvariables(VARIABLE *firstvar, INTSML numvar)
2575 {
2576 	REGISTER INTBIG i;
2577 	REGISTER INTBIG j, k, type, len;
2578 	REGISTER VARIABLE *var;
2579 	REGISTER NODEPROTO *np, **nparray;
2580 
2581 	for(i=0; i<numvar; i++)
2582 	{
2583 		var = &firstvar[i];
2584 		type = var->type;
2585 		if ((type&VDONTSAVE) != 0) continue;
2586 		if ((type&VTYPE) != VNODEPROTO) continue;
2587 		if ((type&VISARRAY) != 0)
2588 		{
2589 			len = (type&VLENGTH) >> VLENGTHSH;
2590 			nparray = (NODEPROTO **)var->addr;
2591 			if (len == 0) for(len=0; nparray[len] != NONODEPROTO; len++) ;
2592 			for(j=0; j<len; j++)
2593 			{
2594 				np = nparray[j];
2595 				if ((INTBIG)np >= 0 && (INTBIG)np < io_binindata.nodeprotoindex)
2596 				{
2597 					k = (INTBIG)np;
2598 					nparray[j] = io_binindata.nodeprotolist[k];
2599 				}
2600 			}
2601 		} else
2602 		{
2603 			np = (NODEPROTO *)var->addr;
2604 			if ((INTBIG)np >= 0 && (INTBIG)np < io_binindata.nodeprotoindex)
2605 			{
2606 				k = (INTBIG)np;
2607 				var->addr = (INTBIG)io_binindata.nodeprotolist[k];
2608 			}
2609 		}
2610 	}
2611 }
2612 
2613 /******************** INPUT HELPER ROUTINES ********************/
2614 
2615 /*
2616  * routine to return the proper tool bits word given the arrangement
2617  * of tools.  These words have one bit per tool according to
2618  * the tool's position which may get re-arranged.
2619  */
io_arrangetoolbits(INTBIG val)2620 INTBIG io_arrangetoolbits(INTBIG val)
2621 {
2622 	REGISTER INTBIG out, i, j;
2623 
2624 	/* if the bits are not re-arranged, result is simple */
2625 	if (!io_binindata.toolbitsmessed) return(val);
2626 
2627 	/* re-arrange the bits in the word */
2628 	out = 0;
2629 	for(i=0; i<io_binindata.aacount; i++)
2630 	{
2631 		j = io_binindata.toollist[i];
2632 		if (j < 0) continue;
2633 		if ((val & (1 << i)) != 0) out |= 1 << j;
2634 	}
2635 	return(out);
2636 }
2637 
2638 /*
2639  * routine to convert the nodeproto index at "np" to a true nodeproto pointer.
2640  * Sets "origname" to a string with the original name of this prototype (if there were
2641  * conversion problems in the file).  Sets "origname" to zero if the pointer is fine.
2642  */
io_convertnodeproto(NODEPROTO ** np,CHAR ** origname)2643 INTBIG io_convertnodeproto(NODEPROTO **np, CHAR **origname)
2644 {
2645 	REGISTER INTBIG i, nindex, error;
2646 
2647 	if (*np == NONODEPROTO) return(0);
2648 	i = (INTBIG)*np;
2649 	if (origname != 0) *origname = 0;
2650 	error = 0;
2651 	if (i < 0)
2652 	{
2653 		nindex = -i - 2;
2654 		if (nindex >= io_binindata.nodepprotoindex)
2655 		{
2656 			ttyputerr(_("Error: want primitive node index %ld when limit is %ld"),
2657 				nindex, io_binindata.nodepprotoindex);
2658 			nindex = 0;
2659 			error = 1;
2660 		}
2661 		*np = io_getnodepprotolist(nindex);
2662 		if (origname != 0) *origname = io_binindata.nodepprotoorig[nindex];
2663 	} else
2664 	{
2665 		if (i >= io_binindata.nodeprotoindex)
2666 		{
2667 			ttyputerr(_("Error: want cell index %ld when limit is %ld"),
2668 				i, io_binindata.nodeprotoindex);
2669 			*np = io_getnodepprotolist(0);
2670 			error = 1;
2671 		} else
2672 		{
2673 			*np = io_binindata.nodeprotolist[i];
2674 			if (*np == 0)
2675 			{
2676 				/* reference to cell in another library: unresolved now */
2677 				*np = (NODEPROTO *)i;
2678 			}
2679 		}
2680 	}
2681 	return(error);
2682 }
2683 
io_convertportproto(PORTPROTO ** pp,BOOLEAN showerror)2684 BOOLEAN io_convertportproto(PORTPROTO **pp, BOOLEAN showerror)
2685 {
2686 	REGISTER INTBIG i, pindex;
2687 	REGISTER BOOLEAN err;
2688 
2689 	if (*pp == NOPORTPROTO) return(FALSE);
2690 	i = (INTBIG)*pp;
2691 	err = FALSE;
2692 	if (i < 0)
2693 	{
2694 		pindex = -i - 2;
2695 		if (pindex >= io_binindata.portpprotoindex)
2696 		{
2697 			if (showerror)
2698 				ttyputerr(_("Error: want primitive port index %ld when limit is %ld"),
2699 					pindex, io_binindata.portpprotoindex);
2700 			pindex = 0;
2701 			err = TRUE;
2702 		}
2703 		*pp = io_getportpprotolist(pindex);
2704 	} else
2705 	{
2706 		if (i >= io_binindata.portprotolimit)
2707 		{
2708 			if (showerror)
2709 				ttyputerr(_("Error: want port index %ld when limit is %ld"),
2710 					i, io_binindata.portprotolimit);
2711 			i = 0;
2712 			err = TRUE;
2713 		}
2714 		*pp = io_binindata.portprotolist[i];
2715 	}
2716 	return(err);
2717 }
2718 
io_convertarcproto(ARCPROTO ** ap)2719 void io_convertarcproto(ARCPROTO **ap)
2720 {
2721 	REGISTER INTBIG i, aindex;
2722 
2723 	if (*ap == NOARCPROTO) return;
2724 	i = (INTBIG)*ap;
2725 	aindex = -i - 2;
2726 	if (aindex >= io_binindata.arcprotoindex || aindex < 0)
2727 	{
2728 		ttyputerr(_("Want primitive arc index %ld when range is 0 to %ld"),
2729 			aindex, io_binindata.arcprotoindex);
2730 		aindex = 0;
2731 	}
2732 	*ap = io_getarcprotolist(aindex);
2733 }
2734 
2735 /*
2736  * Routine to ensure that all ports in library "lib" are valid.  Invalid ports are
2737  * caused when references to cells outside of this library cannot be found.  When
2738  * that happens, dummy cells are generated with invalid ports.  At this point, the
2739  * ports can be defined by examining their usage.
2740  */
io_ensureallports(LIBRARY * lib)2741 void io_ensureallports(LIBRARY *lib)
2742 {
2743 	REGISTER NODEPROTO *np, *onp, *pin;
2744 	REGISTER PORTPROTO *pp;
2745 	REGISTER NODEINST *ni;
2746 	REGISTER ARCINST *ai;
2747 	REGISTER ARCPROTO *ap;
2748 	ARCPROTO *onlyarc;
2749 	REGISTER TECHNOLOGY *tech;
2750 	REGISTER PORTARCINST *pi;
2751 	REGISTER PORTEXPINST *pe;
2752 	REGISTER INTBIG thisend;
2753 	INTBIG lx, hx, ly, hy, x, y;
2754 	BOOLEAN first;
2755 	XARRAY rot, trn, trans;
2756 
2757 	/* look at every port in the library */
2758 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2759 	{
2760 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2761 		{
2762 			if (pp->subnodeinst != NONODEINST) continue;
2763 
2764 			/* undefined port: figure out what connects to it */
2765 			for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
2766 				for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
2767 					ap->temp1 = 0;
2768 			first = TRUE;
2769 			onlyarc = NOARCPROTO;
2770 			for(onp = lib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
2771 			{
2772 				for(ni = onp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2773 				{
2774 					if (ni->proto != np) continue;
2775 					makerotI(ni, rot);
2776 					maketransI(ni, trn);
2777 					transmult(rot, trn, trans);
2778 
2779 					/* found an instance of the external cell */
2780 					for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2781 					{
2782 						if (pi->proto != pp) continue;
2783 						ai = pi->conarcinst;
2784 						if (!first && ai->proto != onlyarc) onlyarc = NOARCPROTO;
2785 						if (first) onlyarc = ai->proto;
2786 						ai->proto->temp1 = 1;
2787 						if (ai->end[0].portarcinst == pi) thisend = 0; else thisend = 1;
2788 						x = ai->end[thisend].xpos;
2789 						y = ai->end[thisend].ypos;
2790 						xform(x, y, &x, &y, trans);
2791 						if (first)
2792 						{
2793 							lx = hx = x;
2794 							ly = hy = y;
2795 							first = FALSE;
2796 						} else
2797 						{
2798 							if (x < lx) lx = x;
2799 							if (x > hx) hx = x;
2800 							if (y < ly) ly = y;
2801 							if (y > hy) hy = y;
2802 						}
2803 					}
2804 					for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
2805 					{
2806 						if (pe->proto != pp) continue;
2807 						io_binfindallports(lib, pe->exportproto, &lx, &hx, &ly, &hy, &first,
2808 							&onlyarc, trans);
2809 					}
2810 				}
2811 			}
2812 
2813 			if (first)
2814 			{
2815 				/* nothing found to tell where the port should go: put it in the middle */
2816 				lx = hx = (np->lowx + np->highx) / 2;
2817 				ly = hy = (np->lowy + np->highy) / 2;
2818 			}
2819 
2820 			/* found where the port should go: create it */
2821 			if (onlyarc == NOARCPROTO) pin = gen_univpinprim; else
2822 				pin = getpinproto(onlyarc);
2823 			lx = hx = (lx + hx) / 2;
2824 			ly = hy = (ly + hy) / 2;
2825 
2826 			ni = allocnodeinst(lib->cluster);
2827 			ni->proto = pin;
2828 			ni->parent = np;
2829 			ni->nextnodeinst = np->firstnodeinst;
2830 			np->firstnodeinst = ni;
2831 			ni->lowx = lx;   ni->highx = hx;
2832 			ni->lowy = ly;   ni->highy = hy;
2833 			ni->geom = allocgeom(lib->cluster);
2834 			ni->geom->entryisnode = TRUE;   ni->geom->entryaddr.ni = ni;
2835 			linkgeom(ni->geom, np);
2836 
2837 			pe = allocportexpinst(lib->cluster);
2838 			pe->exportproto = pp;
2839 			pe->proto = ni->proto->firstportproto;
2840 			ni->firstportexpinst = pe;
2841 			pp->subnodeinst = ni;
2842 			pp->subportexpinst = pe;
2843 			pp->connects = pe->proto->connects;
2844 			pp->subportproto = pe->proto;
2845 			pp->userbits = pe->proto->userbits;
2846 			TDCLEAR(pp->textdescript);
2847 			defaulttextsize(1, pp->textdescript);
2848 			defaulttextdescript(pp->textdescript, NOGEOM);
2849 		}
2850 	}
2851 }
2852 
2853 /*
2854  * Helper routine for "io_ensureallports" to find all exports in library "lib" attached
2855  * to port "pp" and gather the bounding box of all arc connections in "lx", "hx", "ly", and
2856  * "hy".  Sets "first" to false once a wire is found, and sets "onlyarc" to the type of arc
2857  * found.  Uses "prevtrans" as the transformation matrix to this point.
2858  */
io_binfindallports(LIBRARY * lib,PORTPROTO * pp,INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy,BOOLEAN * first,ARCPROTO ** onlyarc,XARRAY prevtrans)2859 void io_binfindallports(LIBRARY *lib, PORTPROTO *pp, INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy,
2860 	BOOLEAN *first, ARCPROTO **onlyarc, XARRAY prevtrans)
2861 {
2862 	REGISTER NODEINST *ni;
2863 	REGISTER NODEPROTO *np;
2864 	REGISTER PORTARCINST *pi;
2865 	REGISTER PORTEXPINST *pe;
2866 	REGISTER ARCINST *ai;
2867 	REGISTER INTBIG thisend;
2868 	INTBIG x, y;
2869 	XARRAY rot, trn, thistran, trans;
2870 
2871 	/* look at all nodes that use the instance with this port */
2872 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2873 	{
2874 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2875 		{
2876 			if (ni->proto != pp->parent) continue;
2877 
2878 			/* find an arc at this port */
2879 			makerotI(ni, rot);
2880 			maketransI(ni, trn);
2881 			transmult(rot, trn, thistran);
2882 			transmult(thistran, prevtrans, trans);
2883 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2884 			{
2885 				if (pi->proto != pp) continue;
2886 				ai = pi->conarcinst;
2887 				if (!(*first) && ai->proto != *onlyarc) *onlyarc = NOARCPROTO;
2888 				if (*first) *onlyarc = ai->proto;
2889 				ai->proto->temp1 = 1;
2890 				if (ai->end[0].portarcinst == pi) thisend = 0; else thisend = 1;
2891 				x = ai->end[thisend].xpos;
2892 				y = ai->end[thisend].ypos;
2893 				xform(x, y, &x, &y, trans);
2894 				if (*first)
2895 				{
2896 					*lx = *hx = x;
2897 					*ly = *hy = y;
2898 					*first = FALSE;
2899 				} else
2900 				{
2901 					if (x < *lx) *lx = x;
2902 					if (x > *hx) *hx = x;
2903 					if (y < *ly) *ly = y;
2904 					if (y > *hy) *hy = y;
2905 				}
2906 			}
2907 			for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
2908 			{
2909 				if (pe->proto != pp) continue;
2910 				io_binfindallports(lib, pe->exportproto, lx, hx, ly, hy, first,
2911 					onlyarc, trans);
2912 			}
2913 		}
2914 	}
2915 }
2916 
2917 /******************** DATA ACCESS ROUTINES ********************/
2918 
io_getarcprotolist(INTBIG i)2919 ARCPROTO *io_getarcprotolist(INTBIG i)
2920 {
2921 	REGISTER ARCPROTO *ap;
2922 	REGISTER CHAR *name;
2923 	REGISTER void *infstr;
2924 
2925 	if (io_binindata.arcprotoerror[i] != 0)
2926 	{
2927 		ap = NOARCPROTO;
2928 		while (ap == NOARCPROTO)
2929 		{
2930 			infstr = initinfstr();
2931 			formatinfstr(infstr, _("Cannot find arc %s', use which instead [%s] "),
2932 				io_binindata.arcprotoerror[i], io_binindata.arcprotolist[i]->protoname);
2933 			name = ttygetline(returninfstr(infstr));
2934 			if (name == 0 || *name == 0) break;
2935 			for(ap = io_binindata.arcprotolist[i]->tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
2936 				if (namesame(ap->protoname, name) == 0) break;
2937 		}
2938 		if (ap != NOARCPROTO) io_binindata.arcprotolist[i] = ap;
2939 		efree(io_binindata.arcprotoerror[i]);
2940 		io_binindata.arcprotoerror[i] = 0;
2941 	}
2942 	return(io_binindata.arcprotolist[i]);
2943 }
2944 
io_getportpprotolist(INTBIG i)2945 PORTPROTO *io_getportpprotolist(INTBIG i)
2946 {
2947 	if (io_binindata.portpprotoerror[i] != 0)
2948 	{
2949 		ttyputerr(_("WARNING: port %s not found, using %s"), io_binindata.portpprotoerror[i],
2950 			io_binindata.portpprotolist[i]->protoname);
2951 		efree(io_binindata.portpprotoerror[i]);
2952 		io_binindata.portpprotoerror[i] = 0;
2953 	}
2954 	return(io_binindata.portpprotolist[i]);
2955 }
2956 
io_getnodepprotolist(INTBIG i)2957 NODEPROTO *io_getnodepprotolist(INTBIG i)
2958 {
2959 	REGISTER NODEPROTO *np;
2960 	REGISTER CHAR *name;
2961 	REGISTER void *infstr;
2962 
2963 	(void)io_gettechlist(io_binindata.nodepprototech[i]);
2964 	if (io_binindata.nodepprotoerror[i])
2965 	{
2966 		np = NONODEPROTO;
2967 		while (np == NONODEPROTO)
2968 		{
2969 			infstr = initinfstr();
2970 			formatinfstr(infstr, _("Cannot find primitive '%s', use which instead [%s] "),
2971 				io_binindata.nodepprotoorig[i], io_binindata.nodepprotolist[i]->protoname);
2972 			name = ttygetline(returninfstr(infstr));
2973 			if (name == 0 || *name == 0) break;
2974 			for(np = io_binindata.nodepprotolist[i]->tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2975 				if (namesame(np->protoname, name) == 0) break;
2976 		}
2977 		if (np != NONODEPROTO) io_binindata.nodepprotolist[i] = np;
2978 		io_binindata.nodepprotoerror[i] = FALSE;
2979 	}
2980 	return(io_binindata.nodepprotolist[i]);
2981 }
2982 
io_gettechlist(INTBIG i)2983 TECHNOLOGY *io_gettechlist(INTBIG i)
2984 {
2985 	extern COMCOMP us_noyesp;
2986 	REGISTER INTBIG count;
2987 	CHAR *pars[10];
2988 
2989 	if (io_binindata.techerror[i] != 0)
2990 	{
2991 		ttyputerr(_("WARNING: technology '%s' does not exist, using '%s'"),
2992 			io_binindata.techerror[i], io_binindata.techlist[i]->techname);
2993 		efree(io_binindata.techerror[i]);
2994 		io_binindata.techerror[i] = 0;
2995 		count = ttygetparam(_("Is this OK? [n] "), &us_noyesp, 2, pars);
2996 		if (count <= 0 || namesamen(pars[0], x_("yes"), estrlen(pars[0])) != 0)
2997 			longjmp(io_binindata.filerror, LONGJMPABORTED);
2998 		ttyputerr(_("WARNING: saving this library with a substitute technology may corrupt it!"));
2999 	}
3000 	return(io_binindata.techlist[i]);
3001 }
3002 
3003 /******************** I/O ROUTINES ********************/
3004 
io_getinbig(void * data)3005 void io_getinbig(void *data)
3006 {
3007 	io_getin(data, io_binindata.sizeofbig, SIZEOFINTBIG, TRUE);
3008 }
3009 
io_getinubig(void * data)3010 void io_getinubig(void *data)
3011 {
3012 	io_getin(data, io_binindata.sizeofbig, SIZEOFINTBIG, FALSE);
3013 }
3014 
3015 /*
3016  * routine to read "disksize" bytes of data from disk and store them in the "memorysize"-
3017  * long object at "data".  If "signextend" is nonzero, do sign-extension if the
3018  * memory object is larger.
3019  */
io_getin(void * data,INTBIG disksize,INTBIG memorysize,BOOLEAN signextend)3020 void io_getin(void *data, INTBIG disksize, INTBIG memorysize, BOOLEAN signextend)
3021 {
3022 	REGISTER INTBIG ret;
3023 	UCHAR1 swapbyte;
3024 	UCHAR1 buf[128];
3025 	INTBIG i;
3026 
3027 	/* sanity check */
3028 	if (disksize == 0)
3029 	{
3030 		ttyputmsg(_("Warning: null length data; database may be bad (byte %ld)"),
3031 			io_binindata.bytecount);
3032 		return;
3033 	}
3034 
3035 	/* check for direct transfer */
3036 	if (disksize == memorysize && io_binindata.swap_bytes == 0)
3037 	{
3038 		/* just peel it off the disk */
3039 		ret = xfread((UCHAR1*)data, 1, disksize, io_binindata.filein);
3040 		if (ret == 0) longjmp(io_binindata.filerror, LONGJMPEOF);
3041 	} else
3042 	{
3043 		/* not a simple read, use a buffer */
3044 		ret = xfread(buf, 1, disksize, io_binindata.filein);
3045 		if (ret == 0) longjmp(io_binindata.filerror, LONGJMPEOF);
3046 		if (io_binindata.swap_bytes > 0)
3047 		{
3048 			switch (disksize)
3049 			{
3050 				case 2:
3051 					swapbyte = buf[0]; buf[0] = buf[1]; buf[1] = swapbyte;
3052 					break;
3053 				case 4:
3054 					swapbyte = buf[3]; buf[3] = buf[0]; buf[0] = swapbyte;
3055 					swapbyte = buf[2]; buf[2] = buf[1]; buf[1] = swapbyte;
3056 					break;
3057 				case 8:
3058 					swapbyte = buf[7]; buf[7] = buf[0]; buf[0] = swapbyte;
3059 					swapbyte = buf[6]; buf[6] = buf[1]; buf[1] = swapbyte;
3060 					swapbyte = buf[5]; buf[5] = buf[2]; buf[2] = swapbyte;
3061 					swapbyte = buf[4]; buf[4] = buf[3]; buf[3] = swapbyte;
3062 					break;
3063 			}
3064 		}
3065 		if (disksize == memorysize)
3066 		{
3067 			for(i=0; i<memorysize; i++) ((UCHAR1 *)data)[i] = buf[i];
3068 		} else
3069 		{
3070 			if (disksize > memorysize)
3071 			{
3072 				/* trouble! disk has more bits than memory.  check for clipping */
3073 				for(i=0; i<memorysize; i++) ((UCHAR1 *)data)[i] = buf[i];
3074 				for(i=memorysize; i<disksize; i++)
3075 					if (buf[i] != 0 && buf[i] != (UCHAR1)0xFF)
3076 						io_binindata.clipped_integers++;
3077 			} else
3078 			{
3079 				/* disk has smaller integer */
3080 				if (!signextend || (buf[disksize-1] & 0x80) == 0)
3081 				{
3082 					for(i=disksize; i<memorysize; i++) buf[i] = 0;
3083 				} else
3084 				{
3085 					for(i=disksize; i<memorysize; i++) buf[i] = (UCHAR1)0xFF;
3086 				}
3087 				for(i=0; i<memorysize; i++) ((UCHAR1 *)data)[i] = buf[i];
3088 			}
3089 		}
3090 	}
3091 	io_binindata.bytecount += disksize;
3092 	if (io_verbose < 0 && io_binindata.filelength > 0 && io_inputprogressdialog != 0)
3093 	{
3094 		if (io_binindata.bytecount > io_binindata.reported + REPORTINC)
3095 		{
3096 			DiaSetProgress(io_inputprogressdialog, io_binindata.bytecount, io_binindata.filelength);
3097 			io_binindata.reported = io_binindata.bytecount;
3098 		}
3099 	}
3100 }
3101 
io_getstring(CLUSTER * cluster)3102 CHAR *io_getstring(CLUSTER *cluster)
3103 {
3104 	INTBIG len;
3105 	REGISTER INTBIG oldswapbytes;
3106 	CHAR *name;
3107 	REGISTER CHAR *tempstr;
3108 
3109 	if (SIZEOFCHAR != io_binindata.sizeofchar)
3110 	{
3111 		/* disk and memory don't match: read into temporary string */
3112 		tempstr = io_gettempstring();
3113 		if (allocstring(&name, tempstr, cluster)) return(0);
3114 	} else
3115 	{
3116 		/* disk and memory match: read the data */
3117 		io_getinbig(&len);
3118 		name = (CHAR *)emalloc((len+1) * SIZEOFCHAR, cluster);
3119 		if (name == 0) return(0);
3120 		if (len != 0)
3121 		{
3122 			oldswapbytes = io_binindata.swap_bytes;
3123 			io_binindata.swap_bytes = 0;     /* prevent swapping */
3124 			io_getin(name, len * SIZEOFCHAR, len * SIZEOFCHAR, FALSE);
3125 			io_binindata.swap_bytes = oldswapbytes;
3126 		}
3127 		name[len] = 0;
3128 	}
3129 	return(name);
3130 }
3131 
io_gettempstring(void)3132 CHAR *io_gettempstring(void)
3133 {
3134 	INTBIG len;
3135 	REGISTER INTBIG oldswapbytes, maxbytesperchar, i;
3136 
3137 	io_getinbig(&len);
3138 	if (len+1 > io_tempstringlength)
3139 	{
3140 		if (io_tempstringlength != 0) efree((CHAR *)io_tempstring);
3141 		io_tempstringlength = len+1;
3142 		maxbytesperchar = maxi(SIZEOFCHAR, io_binindata.sizeofchar);
3143 		io_tempstring = (CHAR1 *)emalloc(io_tempstringlength * maxbytesperchar, io_tool->cluster);
3144 		if (io_tempstring == 0) { io_tempstringlength = 0; return(0); }
3145 	}
3146 	oldswapbytes = io_binindata.swap_bytes;
3147 	if (io_binindata.swap_bytes != 0 && len != 0) io_binindata.swap_bytes = 0;
3148 	if (len != 0) io_getin(io_tempstring, len * io_binindata.sizeofchar,
3149 		len * io_binindata.sizeofchar, FALSE);
3150 	io_binindata.swap_bytes = oldswapbytes;
3151 	if (SIZEOFCHAR != io_binindata.sizeofchar)
3152 	{
3153 		/* size of strings on disk different than in memory: adjust */
3154 		if (SIZEOFCHAR == 1)
3155 		{
3156 			/* disk has unicode, memory has 1-byte: reduce the data */
3157 			for(i=0; i<len; i++)
3158 				io_tempstring[i] = io_tempstring[i*2];
3159 			io_tempstring[len] = 0;
3160 		} else
3161 		{
3162 			/* disk has 1-byte, memory uses unicode: expand the data */
3163 			for(i=len-1; i>=0; i--)
3164 				((CHAR *)io_tempstring)[i] = io_tempstring[i] & 0xFF;
3165 			((CHAR *)io_tempstring)[len] = 0;
3166 		}
3167 	} else
3168 	{
3169 		((CHAR *)io_tempstring)[len] = 0;
3170 	}
3171 	return((CHAR *)io_tempstring);
3172 }
3173