1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: io.c
6  * Input/output tool: controller module
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "global.h"
33 #include "database.h"
34 #include "conlay.h"
35 #include "egraphics.h"
36 #include "efunction.h"
37 #include "dbcontour.h"
38 #include "eio.h"
39 #include "usr.h"
40 #include "drc.h"
41 #include "network.h"
42 #include "usredtec.h"
43 #include "edialogs.h"
44 #include "tecart.h"
45 #include "tecschem.h"
46 #include "tecgen.h"
47 #include "tecmocmos.h"
48 #include <math.h>
49 
50 /* the command parsing table */
51 static KEYWORD iocifoopt[] =
52 {
53 	{x_("fully-instantiated"),    0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
54 	{x_("exactly-as-displayed"),  0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
55 	{x_("individual-boxes"),      0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
56 	{x_("merge-boxes"),           0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
57 	{x_("include-cloak-layer"),   0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
58 	{x_("ignore-cloak-layer"),    0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
59 	{x_("normalized"),            0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
60 	{x_("not-normalized"),        0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
61 	{x_("exactly-as-displayed"),  0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
62 	{x_("instantiate-top"),       0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
63 	{x_("dont-instantiate-top"),  0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
64 	{x_("highlight-resolution"),  0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
65 	{x_("hide-resolution"),       0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
66 	TERMKEY
67 };
68 COMCOMP io_cifop = {iocifoopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
69 	INPUTOPT, x_(" \t"), M_("style of CIF output"), 0};
70 static KEYWORD iocifiopt[] =
71 {
72 	{x_("rounded-wires"),    0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
73 	{x_("squared-wires"),    0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
74 	TERMKEY
75 };
76 static COMCOMP iocifip = {iocifiopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
77 	INPUTOPT, x_(" \t"), M_("style of CIF input"), 0};
78 static KEYWORD iocifopt[] =
79 {
80 	{x_("input"),     1,{&iocifip,NOKEY,NOKEY,NOKEY,NOKEY}},
81 	{x_("output"),    1,{&io_cifop,NOKEY,NOKEY,NOKEY,NOKEY}},
82 	TERMKEY
83 };
84 COMCOMP io_cifp = {iocifopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
85 	INPUTOPT, x_(" \t"), M_("control of CIF"), 0};
86 
87 static KEYWORD iodxfaopt[] =
88 {
89 	{x_("all"),                  0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
90 	{x_("restrict"),             0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
91 	TERMKEY
92 };
93 static COMCOMP iodxfap = {iodxfaopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
94 	INPUTOPT, x_(" \t"), M_("DXF layer restriction options"), 0};
95 static KEYWORD iodxfopt[] =
96 {
97 	{x_("acceptable-layers"),   1,{&iodxfap,NOKEY,NOKEY,NOKEY,NOKEY}},
98 	{x_("flatten-input"),       0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
99 	{x_("not-flatten-input"),   0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
100 	TERMKEY
101 };
102 COMCOMP io_dxfp = {iodxfopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
103 	INPUTOPT, x_(" \t"), M_("DXF options"), 0};
104 
105 static COMCOMP iogdsoarp = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
106 	INPUTOPT, x_(" \t"), M_("maximum number of degrees per arc segment"), 0};
107 static COMCOMP iogdsoasp = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
108 	INPUTOPT, x_(" \t"), M_("maximum sag distance for an arc segment"), 0};
109 static KEYWORD iogdsoopt[] =
110 {
111 	{x_("individual-boxes"),         0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
112 	{x_("merge-boxes"),              0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
113 	{x_("include-cloak-layer"),      0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
114 	{x_("ignore-cloak-layer"),       0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
115 	{x_("arc-resolution"),           1,{&iogdsoarp,NOKEY,NOKEY,NOKEY,NOKEY}},
116 	{x_("arc-sag"),                  1,{&iogdsoasp,NOKEY,NOKEY,NOKEY,NOKEY}},
117 	TERMKEY
118 };
119 static COMCOMP iogdsop = {iogdsoopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
120 	INPUTOPT, x_(" \t"), M_("style of GDS output"), 0};
121 static KEYWORD iogdsiopt[] =
122 {
123 	{x_("text"),                     0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
124 	{x_("expand"),                   0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
125 	{x_("arrays"),                   0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
126 	{x_("unknown-layers"),           0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
127 	{x_("no-text"),                  0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
128 	{x_("no-expand"),                0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
129 	{x_("no-arrays"),                0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
130 	{x_("no-unknown-layers"),        0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
131 	TERMKEY
132 };
133 static COMCOMP iogdsiop = {iogdsiopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
134 	INPUTOPT, x_(" \t"), M_("style of GDS input"), 0};
135 static KEYWORD iogdsopt[] =
136 {
137 	{x_("output"),   1,{&iogdsop,NOKEY,NOKEY,NOKEY,NOKEY}},
138 	{x_("input"),    1,{&iogdsiop,NOKEY,NOKEY,NOKEY,NOKEY}},
139 	TERMKEY
140 };
141 COMCOMP io_gdsp = {iogdsopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
142 	INPUTOPT, x_(" \t"), M_("control of GDS"), 0};
143 
144 static KEYWORD ioedifopt[] =
145 {
146 	{x_("schematic"),         0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
147 	{x_("netlist"),           0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
148 	TERMKEY
149 };
150 COMCOMP io_edifp = {ioedifopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
151 	INPUTOPT, x_(" \t"), M_("EDIF output option"), 0};
152 
153 static KEYWORD ioplotnopt[] =
154 {
155 	{x_("focus"),       0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
156 	{x_("include-date"),0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
157 	TERMKEY
158 };
159 static COMCOMP ioplotnp = {ioplotnopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
160 	INPUTOPT, x_(" \t"), M_("negating control of plot output"), 0};
161 static KEYWORD ioplotopt[] =
162 {
163 	{x_("not"),               1,{&ioplotnp,NOKEY,NOKEY,NOKEY,NOKEY}},
164 	{x_("focus-highlighted"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
165 	{x_("focus-window"),      0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
166 	{x_("include-date"),      0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
167 	TERMKEY
168 };
169 static COMCOMP ioplotp = {ioplotopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
170 	INPUTOPT, x_(" \t"), M_("control of plot output"), 0};
171 
172 static KEYWORD ioveropt[] =
173 {
174 	{x_("off"),              0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
175 	{x_("on"),               0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
176 	{x_("graphical"),        0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
177 	TERMKEY
178 };
179 static COMCOMP ioverp = {ioveropt,NOTOPLIST,NONEXTLIST,NOPARAMS,
180 	INPUTOPT, x_(" \t"), M_("verbose option"), 0};
181 
182 static COMCOMP iopostsynch = {NOKEYWORD, topoffile, nextfile, NOPARAMS,
183 	NOFILL|INPUTOPT, x_(" \t"), M_("PostScript synchronization file name"), 0};
184 static COMCOMP iopostplotwid = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
185 	INPUTOPT, x_(" \t"), M_("PostScript plotter width"), 0};
186 static COMCOMP iopostprintwid = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
187 	INPUTOPT, x_(" \t"), M_("PostScript printer width"), 0};
188 static COMCOMP iopostprinthei = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
189 	INPUTOPT, x_(" \t"), M_("PostScript printer height"), 0};
190 static COMCOMP iopostmargin = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
191 	INPUTOPT, x_(" \t"), M_("PostScript margin"), 0};
192 static KEYWORD iopostopt[] =
193 {
194 	{x_("plain"),            0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
195 	{x_("encapsulated"),     0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
196 	{x_("rotate"),           0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
197 	{x_("no-rotate"),        0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
198 	{x_("auto-rotate"),      0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
199 	{x_("color"),            0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
200 	{x_("stippled-color"),   0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
201 	{x_("merged-color"),     0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
202 	{x_("gray-scale"),       0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
203 	{x_("printer"),          2,{&iopostprintwid,&iopostprinthei,NOKEY,NOKEY,NOKEY}},
204 	{x_("plotter"),          1,{&iopostplotwid,NOKEY,NOKEY,NOKEY,NOKEY}},
205 	{x_("margin"),           1,{&iopostmargin,NOKEY,NOKEY,NOKEY,NOKEY}},
206 	{x_("unsynchronize"),    0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
207 	{x_("synchronize"),      1,{&iopostsynch,NOKEY,NOKEY,NOKEY,NOKEY}},
208 	TERMKEY
209 };
210 static COMCOMP iopostp = {iopostopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
211 	INPUTOPT, x_(" \t"), M_("control of PostScript format"), 0};
212 
213 static COMCOMP iohpgl2sp = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
214 	INPUTOPT, x_(" \t"), M_("internal units per pixel"), 0};
215 static KEYWORD iohpgl2opt[] =
216 {
217 	{x_("scale"),           1,{&iohpgl2sp,NOKEY,NOKEY,NOKEY,NOKEY}},
218 	TERMKEY
219 };
220 static COMCOMP iohpgl2p = {iohpgl2opt,NOTOPLIST,NONEXTLIST,NOPARAMS,
221 	INPUTOPT, x_(" \t"), M_("HPGL/2 scaling option"), 0};
222 static KEYWORD iohpglopt[] =
223 {
224 	{x_("1"),               0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
225 	{x_("2"),               1,{&iohpgl2p,NOKEY,NOKEY,NOKEY,NOKEY}},
226 	TERMKEY
227 };
228 static COMCOMP iohpglp = {iohpglopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
229 	INPUTOPT, x_(" \t"), M_("HPGL version"), 0};
230 
231 static COMCOMP iobloatlp = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
232 	INPUTOPT, x_(" \t"), M_("Layer name to bloat"), 0};
233 static COMCOMP iobloatap = {NOKEYWORD,NOTOPLIST,NONEXTLIST,NOPARAMS,
234 	0, x_(" \t"), M_("amount to bloat layer (in internal units)"), 0};
235 
236 static KEYWORD iobinopt[] =
237 {
238 	{x_("no-backup"),           0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
239 	{x_("one-level-backup"),    0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
240 	{x_("many-level-backup"),   0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
241 	{x_("no-check"),            0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
242 	{x_("check"),               0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
243 	TERMKEY
244 };
245 static COMCOMP iobinp = {iobinopt,NOTOPLIST,NONEXTLIST,NOPARAMS,
246 	INPUTOPT, x_(" \t"), M_("Binary options"), 0};
247 
248 static KEYWORD ioopt[] =
249 {
250 	{x_("cif"),            1,{&io_cifp,NOKEY,NOKEY,NOKEY,NOKEY}},
251 	{x_("dxf"),            1,{&io_dxfp,NOKEY,NOKEY,NOKEY,NOKEY}},
252 	{x_("gds"),            1,{&io_gdsp,NOKEY,NOKEY,NOKEY,NOKEY}},
253 	{x_("edif"),           1,{&io_edifp,NOKEY,NOKEY,NOKEY,NOKEY}},
254 	{x_("binary"),         1,{&iobinp,NOKEY,NOKEY,NOKEY,NOKEY}},
255 	{x_("plot"),           1,{&ioplotp,NOKEY,NOKEY,NOKEY,NOKEY}},
256 	{x_("verbose"),        1,{&ioverp,NOKEY,NOKEY,NOKEY,NOKEY}},
257 	{x_("postscript"),     1,{&iopostp,NOKEY,NOKEY,NOKEY,NOKEY}},
258 	{x_("hpgl"),           1,{&iohpglp,NOKEY,NOKEY,NOKEY,NOKEY}},
259 	{x_("bloat-output"),   2,{&iobloatlp,&iobloatap,NOKEY,NOKEY,NOKEY}},
260 	TERMKEY
261 };
262 COMCOMP io_iop = {ioopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
263 		0, x_(" \t"), M_("Input/Output action"), 0};
264 
265 static struct
266 {
267 	CHAR *name;
268 	INTBIG required, bits;
269 } io_formatlist[] =
270 {
271 	{x_("binary"),             1, FBINARY},
272 	{x_("nobackupbinary"),     1, FBINARYNOBACKUP},
273 	{x_("cif"),                1, FCIF},
274 	{x_("def"),                2, FDEF},
275 	{x_("dxf"),                2, FDXF},
276 	{x_("eagle"),              2, FEAGLE},
277 	{x_("ecad"),               2, FECAD},
278 	{x_("edif"),               2, FEDIF},
279 	{x_("gds"),                1, FGDS},
280 	{x_("hpgl"),               1, FHPGL},
281 	{x_("l"),                  1, FL},
282 	{x_("lef"),                2, FLEF},
283 	{x_("pads"),               2, FPADS},
284 	{x_("postscript"),         2, FPOSTSCRIPT},
285 	{x_("printed-postscript"), 2, FPRINTEDPOSTSCRIPT},
286 #if defined(MACOS) && !defined(MACOSX)
287 	{x_("quickdraw"),          1, FQUICKDRAW},
288 #endif
289 	{x_("sdf"),                2, FSDF},
290 #ifdef FORCECADENCE
291 	{x_("skill"),              2, FSKILL},
292 #endif
293 	{x_("sue"),                2, FSUE},
294 	{x_("text"),               1, FTEXT},
295 #if VHDLTOOL
296 	{x_("vhdl"),               1, FVHDL},
297 #endif
298 	{NULL, 0, 0}
299 };
300 
301 #define NOBLOAT ((BLOAT *)-1)
302 
303 typedef struct Ibloat
304 {
305 	CHAR  *layer;
306 	INTBIG  amount;
307 	struct Ibloat *nextbloat;
308 } BLOAT;
309 
310 static BLOAT *io_curbloat = NOBLOAT;
311 
312 /* working memory for "io_setuptechorder()" */
313 static INTBIG      io_maxlayers;
314 static INTBIG      io_mostlayers = 0;
315 static INTBIG     *io_overlaporder;
316 
317 /* miscellaneous */
318        FILE       *io_fileout;					/* channel for output */
319        jmp_buf     io_filerror;					/* nonlocal jump when I/O fails */
320        INTBIG      io_cifbase;					/* index used when writing CIF */
321        INTBIG      io_postscriptfilenamekey;	/* key for "IO_postscript_filename" */
322        INTBIG      io_postscriptfiledatekey;	/* key for "IO_postscript_filedate" */
323        INTBIG      io_postscriptepsscalekey;	/* key for "IO_postscript_EPS_scale" */
324        INTBIG      io_verbose;					/* 0: silent  1:chattier  -1:graphical */
325        TOOL       *io_tool;						/* the I/O tool object */
326        INTBIG      io_filetypeblib;				/* Binary library disk file descriptor */
327        INTBIG      io_filetypecif;				/* CIF disk file descriptor */
328        INTBIG      io_filetypedef;				/* DEF disk file descriptor */
329        INTBIG      io_filetypedxf;				/* DXF disk file descriptor */
330        INTBIG      io_filetypeeagle;			/* EAGLE disk netlist file descriptor */
331        INTBIG      io_filetypeecad;				/* ECAD disk netlist file descriptor */
332        INTBIG      io_filetypeedif;				/* EDIF disk file descriptor */
333        INTBIG      io_filetypegds;				/* GDS disk file descriptor */
334        INTBIG      io_filetypehpgl;				/* HPGL disk file descriptor */
335        INTBIG      io_filetypehpgl2;			/* HPGL2 disk file descriptor */
336        INTBIG      io_filetypel;				/* L disk file descriptor */
337        INTBIG      io_filetypelef;				/* LEF disk file descriptor */
338        INTBIG      io_filetypepads;				/* PADS netlist disk file descriptor */
339        INTBIG      io_filetypeps;				/* PostScript disk file descriptor */
340        INTBIG      io_filetypesdf;				/* SDF disk file descriptor */
341        INTBIG      io_filetypeskill;			/* SKILL commands disk file descriptor */
342        INTBIG      io_filetypesue;				/* SUE disk file descriptor */
343        INTBIG      io_filetypetlib;				/* Text library disk file descriptor */
344        INTBIG      io_filetypevhdl;				/* VHDL disk file descriptor */
345        INTBIG      io_libinputrecursivedepth;	/* for recursing when reading dependent libraries */
346        INTBIG      io_libinputreadmany;			/* nonzero if reading dependent libraries */
347 static INTBIG      io_state_key;				/* key for "IO_state" */
348 static INTBIG      io_libraryannouncetotal = 0;	/* size of library announcement queue */
349 static INTBIG      io_libraryannouncecount;		/* number of libraries queued for announcement */
350 static LIBRARY   **io_libraryannounce;			/* list of libraries queued for announcement */
351 
352 /* shared prototypes */
353 void io_compute_center(INTBIG xc, INTBIG yc, INTBIG x1, INTBIG y1,
354 		INTBIG x2, INTBIG y2, INTBIG *cx, INTBIG *cy);
355 
356 /* prototypes for local routines */
357 static double io_calc_angle(double r, double dx, double dy);
358 static void   io_fixrtree(RTNODE*);
359 static void   io_fixtechlayers(LIBRARY *lib);
360 static void   io_unifylambdavalues(LIBRARY *lib);
361 static void   io_libraryoptiondlog(void);
362 static void   io_cdloptionsdialog(void);
363 static void   io_sueoptionsdialog(void);
364 static void   io_getversion(LIBRARY *lib, INTBIG *major, INTBIG *minor, INTBIG *detail);
365 static void   io_convertallrelativetext(INTSML numvar, VARIABLE *firstvar);
366 static void   io_convertrelativetext(UINTBIG *descript);
367 static void   io_fixupnodeinst(NODEINST *ni, INTBIG dlx, INTBIG dly, INTBIG dhx, INTBIG dhy);
368 static void   io_convertalltextdescriptors(INTSML numvar, VARIABLE *firstvar, INTBIG how);
369 static void   io_converteverytextdescriptor(LIBRARY *lib, INTBIG how);
370 static void   io_converttextdescriptor(UINTBIG *descript, INTBIG how);
371 static void   io_setoutputbloat(CHAR *layer, INTBIG amount);
372 
io_getstatebits(void)373 INTBIG *io_getstatebits(void)
374 {
375 	REGISTER VARIABLE *var;
376 	REGISTER INTBIG i, len;
377 	static INTBIG mybits[NUMIOSTATEBITWORDS];
378 
379 	var = getvalkey((INTBIG)io_tool, VTOOL, -1, io_state_key);
380 	if (var == NOVARIABLE)
381 	{
382 		for(i=1; i<NUMIOSTATEBITWORDS; i++) mybits[i] = 0;
383 		mybits[0] = DXFFLATTENINPUT|GDSINARRAYS;
384 		return(mybits);
385 	}
386 	if ((var->type&VISARRAY) != 0)
387 	{
388 		for(i=0; i<NUMIOSTATEBITWORDS; i++) mybits[i] = 0;
389 		len = getlength(var);
390 		for(i=0; i<len; i++) mybits[i] = ((INTBIG *)var->addr)[i];
391 		return(mybits);
392 	}
393 	for(i=1; i<NUMIOSTATEBITWORDS; i++) mybits[i] = 0;
394 	mybits[0] = var->addr;
395 	return(mybits);
396 }
397 
io_setstatebits(INTBIG * bits)398 void io_setstatebits(INTBIG *bits)
399 {
400 	(void)setvalkey((INTBIG)io_tool, VTOOL, io_state_key, (INTBIG)bits,
401 		VINTEGER|VISARRAY|(NUMIOSTATEBITWORDS<<VLENGTHSH));
402 }
403 
io_init(INTBIG * argc,CHAR1 * argv[],TOOL * thistool)404 void io_init(INTBIG  *argc, CHAR1 *argv[], TOOL *thistool)
405 {
406 	INTBIG statebits[NUMIOSTATEBITWORDS], i;
407 
408 	/* nothing for pass 2 or 3 initialization */
409 	if (thistool == NOTOOL || thistool == 0) return;
410 
411 	/* pass 1 initialization */
412 	io_tool = thistool;
413 	io_state_key = makekey(x_("IO_state"));
414 	io_postscriptfilenamekey = makekey(x_("IO_postscript_filename"));
415 	io_postscriptfiledatekey = makekey(x_("IO_postscript_filedate"));
416 	io_postscriptepsscalekey = makekey(x_("IO_postscript_EPS_scale"));
417 	nextchangequiet();
418 	for(i=1; i<NUMIOSTATEBITWORDS; i++) statebits[i] = 0;
419 	statebits[0] = DXFFLATTENINPUT|GDSINARRAYS|HPGL2;
420 	(void)setvalkey((INTBIG)io_tool, VTOOL, io_state_key, (INTBIG)statebits,
421 		VINTEGER|VISARRAY|(NUMIOSTATEBITWORDS<<VLENGTHSH)|VDONTSAVE);
422 	io_verbose = 0;
423 
424 	DiaDeclareHook(x_("libopt"), &ioverp, io_libraryoptiondlog);
425 	DiaDeclareHook(x_("cdlopt"), &iobloatlp, io_cdloptionsdialog);
426 	DiaDeclareHook(x_("sueopt"), &iobloatap, io_sueoptionsdialog);
427 
428 	/* create disk file descriptors */
429 	io_filetypeblib  = setupfiletype(x_("elib"), x_("*.elib"),       MACFSTAG('Elec'), TRUE,  x_("blib"),  _("Binary library"));
430 	io_filetypecif   = setupfiletype(x_("cif"),  x_("*.cif"),        MACFSTAG('TEXT'), FALSE, x_("cif"),   _("CIF"));
431 	io_filetypedef   = setupfiletype(x_("def"),  x_("*.def"),        MACFSTAG('TEXT'), FALSE, x_("def"),   _("DEF"));
432 	io_filetypedxf   = setupfiletype(x_("dxf"),  x_("*.dxf"),        MACFSTAG('TEXT'), FALSE, x_("dxf"),   _("AutoCAD DXF"));
433 	io_filetypeeagle = setupfiletype(x_("txt"),  x_("*.txt"),        MACFSTAG('TEXT'), FALSE, x_("eagle"), _("Eagle netlist"));
434 	io_filetypeecad  = setupfiletype(x_("enl"),  x_("*.enl"),        MACFSTAG('TEXT'), FALSE, x_("ecad"),  _("ECAD netlist"));
435 	io_filetypeedif  = setupfiletype(x_("edif"), x_("*.edif;*.ed?"), MACFSTAG('TEXT'), FALSE, x_("edif"),  _("EDIF"));
436 	io_filetypegds   = setupfiletype(x_("gds"),  x_("*.gds"),        MACFSTAG('GDS '), TRUE,  x_("gds"),   _("GDS II"));
437 	io_filetypehpgl  = setupfiletype(x_("hpgl"), x_("*.hpgl"),       MACFSTAG('TEXT'), FALSE, x_("hpgl"),  _("HPGL"));
438 	io_filetypehpgl2 = setupfiletype(x_("hpgl2"),x_("*.hpgl2"),      MACFSTAG('TEXT'), FALSE, x_("hpgl2"), _("HPGL/2"));
439 	io_filetypel     = setupfiletype(x_("l"),    x_("*.l"),          MACFSTAG('TEXT'), FALSE, x_("l"),     _("L"));
440 	io_filetypelef   = setupfiletype(x_("lef"),  x_("*.lef"),        MACFSTAG('TEXT'), FALSE, x_("lef"),   _("LEF"));
441 	io_filetypepads  = setupfiletype(x_("asc"),  x_("*.asc"),        MACFSTAG('TEXT'), FALSE, x_("pad"),   _("PADS netlist"));
442 	io_filetypeps    = setupfiletype(x_("ps"),   x_("*.ps;*.eps"),   MACFSTAG('TEXT'), FALSE, x_("ps"),    _("PostScript"));
443 	io_filetypesdf   = setupfiletype(x_("sdf"),  x_("*.sdf"),        MACFSTAG('TEXT'), FALSE, x_("sdf"),   _("SDF"));
444 	io_filetypeskill = setupfiletype(x_("il"),   x_("*.il"),         MACFSTAG('TEXT'), FALSE, x_("skill"), _("SKILL commands"));
445 	io_filetypesue   = setupfiletype(x_("sue"),  x_("*.sue"),        MACFSTAG('TEXT'), FALSE, x_("sue"),   _("SUE"));
446 	io_filetypetlib  = setupfiletype(x_("txt"),  x_("*.txt"),        MACFSTAG('TEXT'), FALSE, x_("tlib"),  _("Text library"));
447 	io_filetypevhdl  = setupfiletype(x_("vhdl"), x_("*.vhdl;*.vhd"), MACFSTAG('TEXT'), FALSE, x_("vhdl"),  _("VHDL"));
448 
449 	io_initcif();
450 	io_initdef();
451 	io_initdxf();
452 	io_initedif();
453 	io_initgds();
454 #ifdef FORCECADENCE
455 	io_initskill();
456 #endif
457 }
458 
io_done(void)459 void io_done(void)
460 {
461 #ifdef DEBUGMEMORY
462 	if (io_mostlayers > 0) efree((CHAR *)io_overlaporder);
463 	io_freebininmemory();
464 	io_freebinoutmemory();
465 	io_freepostscriptmemory();
466 	io_freetextinmemory();
467 	io_freecifinmemory();
468 	io_freecifparsmemory();
469 	io_freecifoutmemory();
470 	io_freedefimemory();
471 	io_freedxfmemory();
472 	io_freeedifinmemory();
473 	io_freegdsinmemory();
474 	io_freegdsoutmemory();
475 	io_freelefimemory();
476 	io_freesdfimemory();
477 	io_freesuememory();
478 	if (io_libraryannouncetotal > 0)
479 		efree((CHAR *)io_libraryannounce);
480 #endif
481 }
482 
io_slice(void)483 void io_slice(void)
484 {
485 	ttyputmsg(M_("Input and Output are performed with the 'library' command"));
486 	ttyputmsg(M_("...I/O tool turned off"));
487 	toolturnoff(io_tool, FALSE);
488 }
489 
io_set(INTBIG count,CHAR * par[])490 void io_set(INTBIG count, CHAR *par[])
491 {
492 	REGISTER INTBIG l;
493 	REGISTER INTBIG *curstate, scale, wid, hei;
494 	REGISTER NODEPROTO *np;
495 	REGISTER CHAR *pp;
496 	REGISTER VARIABLE *var;
497 	INTBIG arcres, arcsag;
498 
499 	if (count == 0)
500 	{
501 		count = ttygetparam(M_("IO option:"), &io_iop, MAXPARS, par);
502 		if (count == 0)
503 		{
504 			ttyputerr(M_("Aborted"));
505 			return;
506 		}
507 	}
508 	l = estrlen(pp = par[0]);
509 
510 	/* get current state of I/O tool */
511 	curstate = io_getstatebits();
512 
513 	/* check for bloating specifications */
514 	if (namesamen(pp, x_("bloat-output"), l) == 0)
515 	{
516 		if (count <= 1)
517 		{
518 			io_setoutputbloat(x_(""), 0);
519 			return;
520 		}
521 		if (count < 3)
522 		{
523 			ttyputusage(x_("telltool io bloat-output LAYER AMOUNT"));
524 			return;
525 		}
526 		io_setoutputbloat(par[1], myatoi(par[2]));
527 		return;
528 	}
529 
530 	/* check for format specifications */
531 	if (namesamen(pp, x_("plot"), l) == 0)
532 	{
533 		if (count <= 1)
534 		{
535 			ttyputusage(x_("telltool io plot OPTIONS"));
536 			return;
537 		}
538 
539 		l = estrlen(pp = par[1]);
540 		if (namesamen(pp, x_("not"), l) == 0)
541 		{
542 			if (count <= 2)
543 			{
544 				ttyputusage(x_("telltool io plot not OPTION"));
545 				return;
546 			}
547 			l = estrlen(pp = par[2]);
548 			if (namesamen(pp, x_("focus"), l) == 0)
549 			{
550 				curstate[0] &= ~(PLOTFOCUS|PLOTFOCUSDPY);
551 				io_setstatebits(curstate);
552 				ttyputverbose(M_("Plot output will display entire cell"));
553 				return;
554 			}
555 			if (namesamen(pp, x_("include-date"), l) == 0)
556 			{
557 				curstate[0] &= ~PLOTDATES;
558 				io_setstatebits(curstate);
559 				ttyputverbose(M_("Plot output will not include dates"));
560 				return;
561 			}
562 			ttyputbadusage(x_("telltool io plot not"));
563 			return;
564 		}
565 		if (namesamen(pp, x_("focus-highlighted"), l) == 0 && l >= 7)
566 		{
567 			curstate[0] = (curstate[0] & ~PLOTFOCUSDPY) | PLOTFOCUS;
568 			io_setstatebits(curstate);
569 			ttyputverbose(M_("Plot output will focus on highlighted area"));
570 			return;
571 		}
572 		if (namesamen(pp, x_("focus-window"), l) == 0 && l >= 7)
573 		{
574 			curstate[0] |= (PLOTFOCUSDPY|PLOTFOCUS);
575 			io_setstatebits(curstate);
576 			ttyputverbose(M_("Plot output will focus on highlighted area"));
577 			return;
578 		}
579 		if (namesamen(pp, x_("include-date"), l) == 0)
580 		{
581 			curstate[0] |= PLOTDATES;
582 			io_setstatebits(curstate);
583 			ttyputverbose(M_("Plot output will include dates"));
584 			return;
585 		}
586 		ttyputbadusage(x_("telltool io plot"));
587 		return;
588 	}
589 
590 	/* check for binary specifications */
591 	if (namesamen(pp, x_("binary"), l) == 0)
592 	{
593 		l = estrlen(pp = par[1]);
594 		if (namesamen(pp, x_("no-backup"), l) == 0 && l >= 4)
595 		{
596 			curstate[0] = (curstate[0] & ~BINOUTBACKUP) | BINOUTNOBACK;
597 			io_setstatebits(curstate);
598 			ttyputverbose(M_("Binary output will not keep backups"));
599 			return;
600 		}
601 		if (namesamen(pp, x_("one-level-backup"), l) == 0)
602 		{
603 			curstate[0] = (curstate[0] & ~BINOUTBACKUP) | BINOUTONEBACK;
604 			io_setstatebits(curstate);
605 			ttyputverbose(M_("Binary output will keep one backup"));
606 			return;
607 		}
608 		if (namesamen(pp, x_("many-level-backup"), l) == 0)
609 		{
610 			curstate[0] = (curstate[0] & ~BINOUTBACKUP) | BINOUTFULLBACK;
611 			io_setstatebits(curstate);
612 			ttyputverbose(M_("Binary output will keep full backups"));
613 			return;
614 		}
615 
616 		if (namesamen(pp, x_("no-check"), l) == 0 && l >= 4)
617 		{
618 			curstate[0] &= ~CHECKATWRITE;
619 			io_setstatebits(curstate);
620 			ttyputverbose(M_("Binary output will not check the database"));
621 			return;
622 		}
623 		if (namesamen(pp, x_("check"), l) == 0)
624 		{
625 			curstate[0] |= CHECKATWRITE;
626 			io_setstatebits(curstate);
627 			ttyputverbose(M_("Binary output will check the database"));
628 			return;
629 		}
630 		ttyputbadusage(x_("telltool io binary"));
631 		return;
632 	}
633 
634 	if (namesamen(pp, x_("cif"), l) == 0)
635 	{
636 		if (count <= 1)
637 		{
638 			ttyputusage(x_("telltool io cif (input|output)"));
639 			return;
640 		}
641 		l = estrlen(pp = par[1]);
642 		if (namesamen(pp, x_("input"), l) == 0)
643 		{
644 			if (count <= 2)
645 			{
646 				ttyputusage(x_("telltool io cif input OPTIONS"));
647 				return;
648 			}
649 			l = estrlen(pp = par[2]);
650 			switch (*pp)
651 			{
652 				case 'r':
653 					curstate[0] &= ~CIFINSQUARE;
654 					io_setstatebits(curstate);
655 					ttyputverbose(M_("CIF wires will have rounded ends"));
656 					break;
657 				case 's':
658 					curstate[0] |= CIFINSQUARE;
659 					io_setstatebits(curstate);
660 					ttyputverbose(M_("CIF wires will have squared ends"));
661 					break;
662 				default:
663 					ttyputbadusage(x_("telltool io cif input"));
664 			}
665 			return;
666 		}
667 		if (namesamen(pp, x_("output"), l) == 0)
668 		{
669 			if (count <= 2)
670 			{
671 				ttyputusage(x_("telltool io cif output OPTIONS"));
672 				return;
673 			}
674 
675 			l = estrlen(pp = par[2]);
676 			if (namesamen(pp, x_("fully-instantiated"), l) == 0)
677 			{
678 				curstate[0] &= ~CIFOUTEXACT;
679 				io_setstatebits(curstate);
680 				ttyputverbose(M_("CIF generation will include all cells"));
681 				return;
682 			}
683 			if (namesamen(pp, x_("exactly-as-displayed"), l) == 0)
684 			{
685 				curstate[0] |= CIFOUTEXACT;
686 				io_setstatebits(curstate);
687 				ttyputverbose(M_("CIF generation will duplicate screen"));
688 				return;
689 			}
690 			if (namesamen(pp, x_("merge-boxes"), l) == 0)
691 			{
692 				curstate[0] |= CIFOUTMERGE;
693 				io_setstatebits(curstate);
694 				ttyputverbose(M_("CIF generation will merge boxes"));
695 				return;
696 			}
697 			if (namesamen(pp, x_("individual-boxes"), l) == 0 && l >= 3)
698 			{
699 				curstate[0] &= ~CIFOUTMERGE;
700 				io_setstatebits(curstate);
701 				ttyputverbose(M_("CIF generation will list individual boxes"));
702 				return;
703 			}
704 			if (namesamen(pp, x_("include-cloak-layer"), l) == 0 && l >= 3)
705 			{
706 				curstate[0] |= CIFOUTADDDRC;
707 				io_setstatebits(curstate);
708 				ttyputverbose(M_("CIF generation will include DRC cloak layer"));
709 				return;
710 			}
711 			if (namesamen(pp, x_("ignore-cloak-layer"), l) == 0 && l >= 2)
712 			{
713 				curstate[0] &= ~CIFOUTADDDRC;
714 				io_setstatebits(curstate);
715 				ttyputverbose(M_("CIF generation will ignore DRC cloak layer"));
716 				return;
717 			}
718 			if (namesamen(pp, x_("normalized"), l) == 0 && l >= 3)
719 			{
720 				curstate[0] |= CIFOUTNORMALIZE;
721 				io_setstatebits(curstate);
722 				ttyputverbose(M_("CIF generation will normalize coordinates"));
723 				return;
724 			}
725 			if (namesamen(pp, x_("not-normalized"), l) == 0 && l >= 3)
726 			{
727 				curstate[0] &= ~CIFOUTNORMALIZE;
728 				io_setstatebits(curstate);
729 				ttyputverbose(M_("CIF generation will use cell coordinates"));
730 				return;
731 			}
732 			if (namesamen(pp, x_("instantiate-top"), l) == 0 && l >= 3)
733 			{
734 				curstate[0] &= ~CIFOUTNOTOPCALL;
735 				io_setstatebits(curstate);
736 				ttyputverbose(M_("CIF generation will instantiate top-level cell"));
737 				return;
738 			}
739 			if (namesamen(pp, x_("dont-instantiate-top"), l) == 0 && l >= 3)
740 			{
741 				curstate[0] |= CIFOUTNOTOPCALL;
742 				io_setstatebits(curstate);
743 				ttyputverbose(M_("CIF generation will not instantiate top-level cell"));
744 				return;
745 			}
746 			if (namesamen(pp, x_("highlight-resolution"), l) == 0 && l >= 3)
747 			{
748 				curstate[1] |= CIFRESHIGH;
749 				io_setstatebits(curstate);
750 				ttyputverbose(M_("CIF generation will highlight resolution errors"));
751 				return;
752 			}
753 			if (namesamen(pp, x_("hide-resolution"), l) == 0 && l >= 3)
754 			{
755 				curstate[1] &= ~CIFRESHIGH;
756 				io_setstatebits(curstate);
757 				ttyputverbose(M_("CIF generation will not highlight resolution errors"));
758 				return;
759 			}
760 			ttyputbadusage(x_("telltool io cif output"));
761 		}
762 		ttyputbadusage(x_("telltool io cif"));
763 		return;
764 	}
765 
766 	if (namesamen(pp, x_("gds"), l) == 0)
767 	{
768 		if (count <= 1)
769 		{
770 			ttyputusage(x_("telltool io gds OPTION"));
771 			return;
772 		}
773 		l = estrlen(pp = par[1]);
774 		if (namesamen(pp, x_("input"), l) == 0)
775 		{
776 			if (count <= 2)
777 			{
778 				ttyputusage(x_("telltool io gds input OPTION"));
779 				return;
780 			}
781 			l = estrlen(pp = par[2]);
782 			if (namesamen(pp, x_("text"), l) == 0)
783 			{
784 				curstate[0] |= GDSINTEXT;
785 				io_setstatebits(curstate);
786 				ttyputverbose(M_("GDS input includes text"));
787 				return;
788 			}
789 			if (namesamen(pp, x_("no-text"), l) == 0 && l >= 4)
790 			{
791 				curstate[0] &= ~GDSINTEXT;
792 				io_setstatebits(curstate);
793 				ttyputverbose(M_("GDS input ignores text"));
794 				return;
795 			}
796 			if (namesamen(pp, x_("expand"), l) == 0)
797 			{
798 				curstate[0] |= GDSINEXPAND;
799 				io_setstatebits(curstate);
800 				ttyputverbose(M_("GDS input expands instances"));
801 				return;
802 			}
803 			if (namesamen(pp, x_("no-expand"), l) == 0 && l >= 4)
804 			{
805 				curstate[0] &= ~GDSINEXPAND;
806 				io_setstatebits(curstate);
807 				ttyputverbose(M_("GDS input does not expand instances"));
808 				return;
809 			}
810 			if (namesamen(pp, x_("arrays"), l) == 0)
811 			{
812 				curstate[0] |= GDSINARRAYS;
813 				io_setstatebits(curstate);
814 				ttyputverbose(M_("GDS input instantiates arrays"));
815 				return;
816 			}
817 			if (namesamen(pp, x_("no-arrays"), l) == 0 && l >= 4)
818 			{
819 				curstate[0] &= ~GDSINARRAYS;
820 				io_setstatebits(curstate);
821 				ttyputverbose(M_("GDS input does not instantiate arrays"));
822 				return;
823 			}
824 			if (namesamen(pp, x_("unknown-layers"), l) == 0)
825 			{
826 				curstate[0] |= GDSINIGNOREUKN;
827 				io_setstatebits(curstate);
828 				ttyputverbose(M_("GDS input includes unknown layers"));
829 				return;
830 			}
831 			if (namesamen(pp, x_("no-unknown-layers"), l) == 0 && l >= 4)
832 			{
833 				curstate[0] &= ~GDSINIGNOREUKN;
834 				io_setstatebits(curstate);
835 				ttyputverbose(M_("GDS input ignores unknown layers"));
836 				return;
837 			}
838 			ttyputbadusage(x_("telltool io gds input"));
839 			return;
840 		}
841 		if (namesamen(pp, x_("output"), l) == 0)
842 		{
843 			if (count <= 2)
844 			{
845 				ttyputusage(x_("telltool io gds output OPTION"));
846 				return;
847 			}
848 			l = estrlen(pp = par[2]);
849 			if (namesamen(pp, x_("merge-boxes"), l) == 0)
850 			{
851 				curstate[0] |= GDSOUTMERGE;
852 				io_setstatebits(curstate);
853 				ttyputverbose(M_("GDS generation will merge boxes"));
854 				return;
855 			}
856 			if (namesamen(pp, x_("individual-boxes"), l) == 0 && l >= 3)
857 			{
858 				curstate[0] &= ~GDSOUTMERGE;
859 				io_setstatebits(curstate);
860 				ttyputverbose(M_("GDS generation will list individual boxes"));
861 				return;
862 			}
863 			if (namesamen(pp, x_("include-cloak-layer"), l) == 0 && l >= 3)
864 			{
865 				curstate[0] |= GDSOUTADDDRC;
866 				io_setstatebits(curstate);
867 				ttyputverbose(M_("GDS generation will include DRC cloak layer"));
868 				return;
869 			}
870 			if (namesamen(pp, x_("ignore-cloak-layer"), l) == 0 && l >= 2)
871 			{
872 				curstate[0] &= ~GDSOUTADDDRC;
873 				io_setstatebits(curstate);
874 				ttyputverbose(M_("GDS generation will ignore DRC cloak layer"));
875 				return;
876 			}
877 			if (namesamen(pp, x_("arc-resolution"), l) == 0 && l >= 5)
878 			{
879 				getcontoursegmentparameters(&arcres, &arcsag);
880 				if (count > 3) arcres = atofr(par[3]) * 10 / WHOLE;
881 				ttyputverbose(M_("GDS arc generation will create a line every %s degrees"),
882 					frtoa(arcres*WHOLE/10));
883 				setcontoursegmentparameters(arcres, arcsag);
884 				return;
885 			}
886 			if (namesamen(pp, x_("arc-sag"), l) == 0 && l >= 5)
887 			{
888 				getcontoursegmentparameters(&arcres, &arcsag);
889 				if (count > 3) arcsag = atola(par[3], 0);
890 				ttyputverbose(M_("GDS arc generation will sag no more than %s"), latoa(arcsag, 0));
891 				setcontoursegmentparameters(arcres, arcsag);
892 				return;
893 			}
894 			ttyputbadusage(x_("telltool io gds output"));
895 			return;
896 		}
897 		ttyputbadusage(x_("telltool io gds"));
898 		return;
899 	}
900 
901 	if (namesamen(pp, x_("dxf"), l) == 0)
902 	{
903 		if (count <= 1)
904 		{
905 			ttyputusage(x_("telltool io dxf OPTION"));
906 			return;
907 		}
908 		l = estrlen(pp = par[1]);
909 		if (namesamen(pp, x_("acceptable-layers"), l) == 0)
910 		{
911 			if (count <= 2)
912 			{
913 				if ((curstate[0]&DXFALLLAYERS) == 0)
914 					ttyputmsg(M_("DXF input will accept only layers listed by technology")); else
915 						ttyputmsg(M_("DXF input will accept all layers"));
916 				return;
917 			}
918 			l = estrlen(pp = par[2]);
919 			if (namesamen(pp, x_("all"), l) == 0)
920 			{
921 				curstate[0] |= DXFALLLAYERS;
922 				io_setstatebits(curstate);
923 				ttyputverbose(M_("DXF input will accept all layers"));
924 				return;
925 			}
926 			if (namesamen(pp, x_("restrict"), l) == 0)
927 			{
928 				curstate[0] &= ~DXFALLLAYERS;
929 				io_setstatebits(curstate);
930 				ttyputverbose(M_("DXF input will accept only layers listed by technology"));
931 				return;
932 			}
933 		}
934 		if (namesamen(pp, x_("flatten-input"), l) == 0)
935 		{
936 			curstate[0] |= DXFFLATTENINPUT;
937 			io_setstatebits(curstate);
938 			ttyputverbose(M_("DXF input will flatten input blocks"));
939 			return;
940 		}
941 		if (namesamen(pp, x_("not-flatten-input"), l) == 0)
942 		{
943 			curstate[0] &= ~DXFFLATTENINPUT;
944 			io_setstatebits(curstate);
945 			ttyputverbose(M_("DXF input will retain input hierarchy"));
946 			return;
947 		}
948 		ttyputbadusage(x_("telltool io dxf"));
949 		return;
950 	}
951 
952 	if (namesamen(pp, x_("postscript"), l) == 0)
953 	{
954 		if (count <= 1)
955 		{
956 			ttyputusage(x_("telltool io postscript OPTION"));
957 			return;
958 		}
959 		l = estrlen(pp = par[1]);
960 		if (namesamen(pp, x_("encapsulated"), l) == 0)
961 		{
962 			curstate[0] |= EPSPSCRIPT;
963 			io_setstatebits(curstate);
964 			ttyputverbose(M_("PostScript output will be encapsulated format"));
965 			return;
966 		}
967 		if (namesamen(pp, x_("plain"), l) == 0 && l >= 2)
968 		{
969 			curstate[0] &= ~EPSPSCRIPT;
970 			io_setstatebits(curstate);
971 			ttyputverbose(M_("PostScript output will be plain format"));
972 			return;
973 		}
974 		if (namesamen(pp, x_("color"), l) == 0)
975 		{
976 			curstate[0] = (curstate[0] & ~PSCOLOR2) | PSCOLOR1;
977 			io_setstatebits(curstate);
978 			ttyputverbose(M_("PostScript output will use color"));
979 			return;
980 		}
981 		if (namesamen(pp, x_("merged-color"), l) == 0 && l >= 2)
982 		{
983 			curstate[0] = (curstate[0] & ~PSCOLOR1) | PSCOLOR2;
984 			io_setstatebits(curstate);
985 			ttyputverbose(M_("PostScript output will use merged color"));
986 			return;
987 		}
988 		if (namesamen(pp, x_("stippled-color"), l) == 0 && l >= 2)
989 		{
990 			curstate[0] |= PSCOLOR1 | PSCOLOR2;
991 			io_setstatebits(curstate);
992 			ttyputverbose(M_("PostScript output will use color"));
993 			return;
994 		}
995 		if (namesamen(pp, x_("gray-scale"), l) == 0)
996 		{
997 			curstate[0] &= ~(PSCOLOR1|PSCOLOR2);
998 			io_setstatebits(curstate);
999 			ttyputverbose(M_("PostScript output will be gray-scale"));
1000 			return;
1001 		}
1002 		if (namesamen(pp, x_("rotate"), l) == 0)
1003 		{
1004 			curstate[0] |= PSROTATE;
1005 			curstate[1] &= ~PSAUTOROTATE;
1006 			io_setstatebits(curstate);
1007 			ttyputverbose(M_("PostScript output will be rotated 90 degrees"));
1008 			return;
1009 		}
1010 		if (namesamen(pp, x_("no-rotate"), l) == 0)
1011 		{
1012 			curstate[0] &= ~PSROTATE;
1013 			curstate[1] &= ~PSAUTOROTATE;
1014 			io_setstatebits(curstate);
1015 			ttyputverbose(M_("PostScript output will appear unrotated"));
1016 			return;
1017 		}
1018 		if (namesamen(pp, x_("auto-rotate"), l) == 0)
1019 		{
1020 			curstate[0] &= ~PSROTATE;
1021 			curstate[1] |= PSAUTOROTATE;
1022 			io_setstatebits(curstate);
1023 			ttyputverbose(M_("PostScript output will automatically rotate to fit best"));
1024 			return;
1025 		}
1026 		if (namesamen(pp, x_("margin"), l) == 0 && l >= 2)
1027 		{
1028 			if (count == 3)
1029 			{
1030 				wid = atofr(par[2]);
1031 				(void)setval((INTBIG)io_tool, VTOOL, x_("IO_postscript_margin"), wid, VFRACT);
1032 			} else
1033 			{
1034 				var = getval((INTBIG)io_tool, VTOOL, VFRACT, x_("IO_postscript_margin"));
1035 				if (var == NOVARIABLE) wid = muldiv(DEFAULTPSMARGIN, WHOLE, 75); else
1036 					wid = var->addr;
1037 			}
1038 			ttyputverbose(M_("PostScript output will use a %s-wide margin"), frtoa(wid));
1039 			return;
1040 		}
1041 		if (namesamen(pp, x_("plotter"), l) == 0 && l >= 2)
1042 		{
1043 			curstate[0] |= PSPLOTTER;
1044 			io_setstatebits(curstate);
1045 			if (count == 3)
1046 			{
1047 				wid = atofr(par[2]);
1048 				(void)setval((INTBIG)io_tool, VTOOL, x_("IO_postscript_width"), wid, VFRACT);
1049 				ttyputverbose(M_("PostScript output will assume a %s-wide plotter"), frtoa(wid));
1050 			} else
1051 				ttyputverbose(M_("PostScript output will assume a continuous-roll plotter"));
1052 			return;
1053 		}
1054 		if (namesamen(pp, x_("printer"), l) == 0 && l >= 2)
1055 		{
1056 			curstate[0] &= ~PSPLOTTER;
1057 			io_setstatebits(curstate);
1058 			if (count == 4)
1059 			{
1060 				wid = atofr(par[2]);
1061 				(void)setval((INTBIG)io_tool, VTOOL, x_("IO_postscript_width"), wid, VFRACT);
1062 				hei = atofr(par[3]);
1063 				(void)setval((INTBIG)io_tool, VTOOL, x_("IO_postscript_height"), hei, VFRACT);
1064 				ttyputverbose(M_("PostScript output will assume a %s x %s page"),
1065 					frtoa(wid), frtoa(hei));
1066 			} else
1067 				ttyputverbose(M_("PostScript output will be assume a fixed-size sheet"));
1068 			return;
1069 		}
1070 		if (namesamen(pp, x_("unsynchronize"), l) == 0)
1071 		{
1072 			np = el_curlib->curnodeproto;
1073 			if (np == NONODEPROTO)
1074 			{
1075 				ttyputerr(M_("Edit a cell before removing synchronization"));
1076 				return;
1077 			}
1078 			if (getvalkey((INTBIG)np, VNODEPROTO, VSTRING, io_postscriptfilenamekey) != NOVARIABLE)
1079 			{
1080 				(void)delvalkey((INTBIG)np, VNODEPROTO, io_postscriptfilenamekey);
1081 				ttyputverbose(M_("Cell %s no longer synchronized to PostScript disk file"),
1082 					describenodeproto(np));
1083 			}
1084 			return;
1085 		}
1086 		if (namesamen(pp, x_("synchronize"), l) == 0 && l >= 2)
1087 		{
1088 			if (count <= 2)
1089 			{
1090 				ttyputusage(x_("telltool io postscript synchronize FILENAME"));
1091 				return;
1092 			}
1093 			np = el_curlib->curnodeproto;
1094 			if (np == NONODEPROTO)
1095 			{
1096 				ttyputerr(M_("Edit a cell to synchronize it to a PostScript file"));
1097 				return;
1098 			}
1099 			(void)setvalkey((INTBIG)np, VNODEPROTO, io_postscriptfilenamekey,
1100 				(INTBIG)par[1], VSTRING);
1101 			ttyputverbose(M_("Cell %s synchronized to PostScript file %s"),
1102 				describenodeproto(np), par[1]);
1103 			return;
1104 		}
1105 		ttyputbadusage(x_("telltool io postscript"));
1106 		return;
1107 	}
1108 
1109 	if (namesamen(pp, x_("hpgl"), l) == 0)
1110 	{
1111 		if (count <= 1)
1112 		{
1113 			ttyputusage(x_("telltool io hpgl (1|2)"));
1114 			return;
1115 		}
1116 		l = estrlen(pp = par[1]);
1117 		if (namesamen(pp, x_("1"), l) == 0)
1118 		{
1119 			curstate[0] &= ~HPGL2;
1120 			io_setstatebits(curstate);
1121 			ttyputmsg(M_("HPGL output will use older (version 1) format"));
1122 			return;
1123 		}
1124 		if (namesamen(pp, x_("2"), l) == 0)
1125 		{
1126 			curstate[0] |= HPGL2;
1127 			io_setstatebits(curstate);
1128 			ttyputverbose(M_("HPGL output will use newer (HPGL/2) format"));
1129 			if (count >= 4 && namesamen(par[2], x_("scale"), estrlen(par[2])) == 0)
1130 			{
1131 				scale = myatoi(par[3]);
1132 				(void)setval((INTBIG)io_tool, VTOOL, x_("IO_hpgl2_scale"),
1133 					scale, VINTEGER);
1134 				ttyputverbose(M_("HPGL/2 plots will scale at %ld %ss per pixel"),
1135 					scale, unitsname(el_units));
1136 			}
1137 			return;
1138 		}
1139 		ttyputbadusage(x_("telltool io hpgl"));
1140 		return;
1141 	}
1142 
1143 	if (namesamen(pp, x_("edif"), l) == 0)
1144 	{
1145 		if (count <= 1)
1146 		{
1147 			ttyputusage(x_("telltool io edif (schematic|netlist)"));
1148 			return;
1149 		}
1150 		l = estrlen(pp = par[1]);
1151 		if (namesamen(pp, x_("schematic"), l) == 0)
1152 		{
1153 			curstate[0] |= EDIFSCHEMATIC;
1154 			io_setstatebits(curstate);
1155 			ttyputverbose(M_("EDIF output will write schematics"));
1156 			return;
1157 		}
1158 		if (namesamen(pp, x_("netlist"), l) == 0)
1159 		{
1160 			curstate[0] &= ~EDIFSCHEMATIC;
1161 			io_setstatebits(curstate);
1162 			ttyputverbose(M_("EDIF output will write netlists"));
1163 			return;
1164 		}
1165 		ttyputbadusage(x_("telltool io edif"));
1166 		return;
1167 	}
1168 
1169 	if (namesamen(pp, x_("verbose"), l) == 0)
1170 	{
1171 		if (count <= 1)
1172 		{
1173 			ttyputusage(x_("telltool io verbose OPTION"));
1174 			return;
1175 		}
1176 		l = estrlen(pp = par[1]);
1177 		if (namesamen(pp, x_("off"), l) == 0 && l >= 2)
1178 		{
1179 			io_verbose = 0;
1180 			ttyputverbose(M_("I/O done silently"));
1181 			return;
1182 		}
1183 		if (namesamen(pp, x_("on"), l) == 0 && l >= 2)
1184 		{
1185 			io_verbose = 1;
1186 			ttyputverbose(M_("I/O prints status"));
1187 			return;
1188 		}
1189 		if (namesamen(pp, x_("graphical"), l) == 0 && l >= 1)
1190 		{
1191 			io_verbose = -1;
1192 			ttyputverbose(M_("I/O shows graphical progress"));
1193 			return;
1194 		}
1195 		ttyputbadusage(x_("telltool io verbose"));
1196 		return;
1197 	}
1198 
1199 	ttyputbadusage(x_("telltool io"));
1200 }
1201 
1202 /*
1203  * make I/O requests of this tool:
1204  *
1205  * "read" TAKES: LIBRARY to read and string style
1206  * "write" TAKES: LIBRARY to write and string style
1207  * "verbose" TAKES: new verbose factor, RETURNS: old verbose factor
1208  */
io_request(CHAR * command,va_list ap)1209 INTBIG io_request(CHAR *command, va_list ap)
1210 {
1211 	REGISTER LIBRARY *lib;
1212 	REGISTER INTBIG i, j, len, format;
1213 	REGISTER BOOLEAN err;
1214 	REGISTER INTBIG arg1, arg3;
1215 	CHAR *arg2;
1216 
1217 	if (namesame(command, x_("verbose")) == 0)
1218 	{
1219 		i = io_verbose;
1220 		io_verbose = va_arg(ap, INTBIG);
1221 		return(i);
1222 	}
1223 
1224 	/* get the arguments */
1225 	arg1 = va_arg(ap, INTBIG);
1226 	arg2 = va_arg(ap, CHAR*);
1227 
1228 	/* find desired library and format */
1229 	lib = (LIBRARY *)arg1;
1230 	format = -1;
1231 	len = estrlen(arg2);
1232 	for(i=0; io_formatlist[i].name != 0; i++)
1233 		if (namesamen(arg2, io_formatlist[i].name, len) == 0 && len >= io_formatlist[i].required)
1234 	{
1235 		format = io_formatlist[i].bits;
1236 		break;
1237 	}
1238 	if (format < 0)
1239 	{
1240 		ttyputerr(M_("Unknown I/O format: %s"), arg2);
1241 		return(1);
1242 	}
1243 
1244 	if (namesame(command, x_("write")) == 0)
1245 	{
1246 		/* announce the beginning of library output */
1247 		for(i=0; i<el_maxtools; i++)
1248 			if (el_tools[i].writelibrary != 0)
1249 				(*el_tools[i].writelibrary)(lib, FALSE);
1250 
1251 		switch (format)
1252 		{
1253 			case FBINARY:
1254 				err = io_writebinlibrary(lib, FALSE);
1255 				break;
1256 
1257 			case FBINARYNOBACKUP:
1258 				err = io_writebinlibrary(lib, TRUE);
1259 				break;
1260 
1261 			case FCIF:
1262 				err = io_writeciflibrary(lib);
1263 				break;
1264 
1265 			case FDXF:
1266 				err = io_writedxflibrary(lib);
1267 				break;
1268 
1269 			case FEAGLE:
1270 				err = io_writeeaglelibrary(lib);
1271 				break;
1272 
1273 			case FECAD:
1274 				err = io_writeecadlibrary(lib);
1275 				break;
1276 
1277 			case FEDIF:
1278 				err = io_writeediflibrary(lib);
1279 				break;
1280 
1281 			case FGDS:
1282 				err = io_writegdslibrary(lib);
1283 				break;
1284 
1285 			case FHPGL:
1286 				err = io_writehpgllibrary(lib);
1287 				break;
1288 
1289 			case FL:
1290 				err = io_writellibrary(lib);
1291 				break;
1292 
1293 			case FLEF:
1294 				err = io_writeleflibrary(lib);
1295 				break;
1296 
1297 			case FPADS:
1298 				err = io_writepadslibrary(lib);
1299 				break;
1300 
1301 			case FPOSTSCRIPT:
1302 			case FPRINTEDPOSTSCRIPT:
1303 				err = io_writepostscriptlibrary(lib,
1304 					(BOOLEAN)(format == FPRINTEDPOSTSCRIPT));
1305 				break;
1306 
1307 #if defined(MACOS) && !defined(MACOSX)
1308 			case FQUICKDRAW:
1309 				err = io_writequickdrawlibrary(lib);
1310 				break;
1311 #endif
1312 
1313 #ifdef FORCECADENCE
1314 			case FSKILL:
1315 				err = io_writeskilllibrary(lib);
1316 				break;
1317 #endif
1318 
1319 			case FTEXT:
1320 				err = io_writetextlibrary(lib);
1321 				break;
1322 
1323 			default:
1324 				for(i=0; io_formatlist[i].name != 0; i++)
1325 					if (io_formatlist[i].bits == format)
1326 				{
1327 					ttyputerr(M_("Cannot write %s files"), io_formatlist[i].name);
1328 					return(1);
1329 				}
1330 		}
1331 
1332 		/* announce the ending of library output */
1333 		if (err) return(1);
1334 		for(i=0; i<el_maxtools; i++)
1335 			if (el_tools[i].writelibrary != 0)
1336 				(*el_tools[i].writelibrary)(lib, TRUE);
1337 		return(0);
1338 	}
1339 
1340 	if (namesame(command, x_("read")) == 0)
1341 	{
1342 		arg3 = va_arg(ap, INTBIG);
1343 		io_libinputrecursivedepth = io_libinputreadmany = 0;
1344 		io_libraryannouncecount = 0;
1345 		switch (format)
1346 		{
1347 			case FBINARY:
1348 				err = io_readbinlibrary(lib);
1349 				/* make sure that the lambda values are consistent */
1350 				if (!err) io_unifylambdavalues(lib);
1351 				break;
1352 
1353 			case FCIF:
1354 				err = io_readciflibrary(lib);
1355 				break;
1356 
1357 			case FDEF:
1358 				err = io_readdeflibrary(lib);
1359 				break;
1360 
1361 			case FDXF:
1362 				err = io_readdxflibrary(lib);
1363 				break;
1364 
1365 			case FEDIF:
1366 				err = io_readediflibrary(lib);
1367 				break;
1368 
1369 			case FGDS:
1370 				err = io_readgdslibrary(lib, arg3);
1371 				break;
1372 
1373 			case FLEF:
1374 				err = io_readleflibrary(lib);
1375 				break;
1376 
1377 			case FSDF:
1378 				err = io_readsdflibrary(lib);
1379 				break;
1380 
1381 			case FSUE:
1382 				err = io_readsuelibrary(lib);
1383 				break;
1384 
1385 			case FTEXT:
1386 				err = io_readtextlibrary(lib);
1387 				/* make sure that the lambda values are consistent */
1388 				if (!err) io_unifylambdavalues(lib);
1389 				break;
1390 
1391 #if VHDLTOOL
1392 			case FVHDL:
1393 				err = io_readvhdllibrary(lib);
1394 				break;
1395 #endif
1396 
1397 			default:
1398 				for(i=0; io_formatlist[i].name != 0; i++)
1399 					if (io_formatlist[i].bits == format)
1400 				{
1401 					ttyputerr(M_("Cannot read %s files"), io_formatlist[i].name);
1402 					return(1);
1403 				}
1404 		}
1405 
1406 		/* announce the completion of library input */
1407 		if (err) return(1);
1408 		io_queuereadlibraryannouncement(lib);
1409 		for(i=0; i<el_maxtools; i++)
1410 		{
1411 			if (el_tools[i].readlibrary != 0)
1412 			{
1413 				for(j=0; j<io_libraryannouncecount; j++)
1414 					(*el_tools[i].readlibrary)(io_libraryannounce[j]);
1415 			}
1416 		}
1417 		return(0);
1418 	}
1419 	return(-1);
1420 }
1421 
io_queuereadlibraryannouncement(LIBRARY * lib)1422 void io_queuereadlibraryannouncement(LIBRARY *lib)
1423 {
1424 	REGISTER INTBIG i, newtotal;
1425 	REGISTER LIBRARY **newlist;
1426 
1427 	if (io_libraryannouncecount >= io_libraryannouncetotal)
1428 	{
1429 		newtotal = io_libraryannouncetotal * 2;
1430 		if (io_libraryannouncecount >= newtotal)
1431 			newtotal = io_libraryannouncecount + 5;
1432 		newlist = (LIBRARY **)emalloc(newtotal * (sizeof (LIBRARY *)), io_tool->cluster);
1433 		if (newlist == 0) return;
1434 		for(i=0; i<io_libraryannouncecount; i++)
1435 			newlist[i] = io_libraryannounce[i];
1436 		if (io_libraryannouncetotal > 0)
1437 			efree((CHAR *)io_libraryannounce);
1438 		io_libraryannounce = newlist;
1439 		io_libraryannouncetotal = newtotal;
1440 	}
1441 	io_libraryannounce[io_libraryannouncecount++] = lib;
1442 }
1443 
1444 /******************************* BLOATING *******************************/
1445 
1446 /*
1447  * routine to indicate that CIF layer "layer" is to be bloated by "amount"
1448  */
io_setoutputbloat(CHAR * layer,INTBIG amount)1449 void io_setoutputbloat(CHAR *layer, INTBIG amount)
1450 {
1451 	REGISTER BLOAT *bl;
1452 
1453 	/* special case when bloating the null layer */
1454 	if (*layer == 0)
1455 	{
1456 		for(bl = io_curbloat; bl != NOBLOAT; bl = bl->nextbloat)
1457 			ttyputmsg(M_("Bloating layer %s by %ld %ss"), bl->layer, bl->amount, unitsname(el_units));
1458 		return;
1459 	}
1460 
1461 	/* first see if this layer is already being bloated */
1462 	for(bl = io_curbloat; bl != NOBLOAT; bl = bl->nextbloat)
1463 		if (namesame(bl->layer, layer) == 0)
1464 	{
1465 		if (bl->amount == amount)
1466 		{
1467 			ttyputmsg(M_("Layer %s is already being bloated by %ld %ss"),
1468 				bl->layer, amount, unitsname(el_units));
1469 			return;
1470 		}
1471 		ttyputmsg(M_("Layer %s was being bloated by %ld %ss, now by %ld"),
1472 			bl->layer, bl->amount, unitsname(el_units), amount);
1473 		bl->amount = amount;
1474 		return;
1475 	}
1476 
1477 	bl = (BLOAT *)emalloc(sizeof (BLOAT), io_tool->cluster);
1478 	if (bl == 0)
1479 	{
1480 		ttyputnomemory();
1481 		return;
1482 	}
1483 	(void)allocstring(&bl->layer, layer, io_tool->cluster);
1484 	bl->amount = amount;
1485 	bl->nextbloat = io_curbloat;
1486 	io_curbloat = bl;
1487 	ttyputmsg(M_("Layer %s will be bloated by %ld %ss"), layer, amount, unitsname(el_units));
1488 }
1489 
1490 /*
1491  * routine to tell the amount to bloat layer "lay"
1492  */
io_getoutputbloat(CHAR * layer)1493 INTBIG io_getoutputbloat(CHAR *layer)
1494 {
1495 	REGISTER BLOAT *bl;
1496 
1497 	for(bl = io_curbloat; bl != NOBLOAT; bl = bl->nextbloat)
1498 		if (namesame(bl->layer, layer) == 0) return(bl->amount);
1499 	return(0);
1500 }
1501 
1502 /******************************* LIBRARY REPAIR *******************************/
1503 
1504 #define OLDSOURCEDCV               0		/* Source is DC Voltage */
1505 #define OLDSOURCEAC          0400000		/* Source is AC analysis */
1506 #define OLDSOURCEBULK       01000000		/* Source is Bulk */
1507 #define OLDSOURCEDCC        01400000		/* Source is DC Current */
1508 #define OLDSOURCECURMTR     02000000		/* Source is Current meter */
1509 #define OLDSOURCENODE       02400000		/* Source is Nodeset */
1510 #define OLDSOURCESPEC       03000000		/* Source is Special */
1511 #define OLDSOURCETRAN       03400000		/* Source is Transient Analysis */
1512 #define OLDSOURCEDCAN       04000000		/* Source is DC Analysis */
1513 #define OLDSOURCEEXT        04400000		/* Source is Extension */
1514 
1515 /*
1516  * routine to complete formation of library "lib" that has just been read from
1517  * disk.  Some data is not read, but computed from other data.
1518  */
io_fixnewlib(LIBRARY * lib,void * dia)1519 void io_fixnewlib(LIBRARY *lib, void *dia)
1520 {
1521 	REGISTER NODEPROTO *np, *pnt, *onp;
1522 	REGISTER NODEINST *ni, *newni;
1523 	REGISTER ARCINST *ai;
1524 	REGISTER LIBRARY *olib;
1525 	REGISTER BOOLEAN first, changed;
1526 	REGISTER INTBIG libunits, i, j, lam, oldtype, size, len, lambda,
1527 		celllambda, totlx, tothx, totly, tothy, numchanged, *intkey;
1528 	INTBIG lx, ly, hx, hy, major, minor, detail, type, addr, xoff, yoff, growx, growy,
1529 		shiftx, shifty;
1530 	UINTBIG olddescript[TEXTDESCRIPTSIZE];
1531 	REGISTER CHAR *str, *pt, **newlist;
1532 	float value;
1533 	XARRAY trans;
1534 	static POLYGON *poly = NOPOLYGON;
1535 	static INTBIG sch_flipfloptypekey = 0;
1536 	static INTBIG sch_transistortypekey = 0;
1537 	static INTBIG sch_sourcekey = 0;
1538 	static INTBIG sch_twoportkey = 0;
1539 	CHAR line[200], *par[4], *newname;
1540 	REGISTER VARIABLE *var, *newvar;
1541 	REGISTER TECHNOLOGY *tech;
1542 	REGISTER PORTPROTO *pp, *inpp;
1543 	REGISTER PORTARCINST *pi;
1544 	REGISTER PORTEXPINST *pe;
1545 	extern ARCPROTO **gen_upconn;
1546 	REGISTER void *infstr;
1547 
1548 	/* make sure units are correct */
1549 	libunits = ((lib->userbits & LIBUNITS) >> LIBUNITSSH) << INTERNALUNITSSH;
1550 	if ((libunits & INTERNALUNITS) != (el_units & INTERNALUNITS))
1551 	{
1552 		ttyputmsg(_("Converting library from %s units to %s units"), unitsname(libunits),
1553 			unitsname(el_units));
1554 		changeinternalunits(lib, libunits, el_units);
1555 	}
1556 
1557 	/* check validity of instances */
1558 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1559 	{
1560 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
1561 			if (olib == np->lib) break;
1562 		if (olib == NOLIBRARY)
1563 		{
1564 			ttyputerr(_("ERROR: Cell %s: has invalid cell structure"), describenodeproto(np));
1565 			continue;
1566 		}
1567 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1568 		{
1569 			if (ni->proto->primindex != 0) continue;
1570 			olib = ni->proto->lib;
1571 			if (olib == lib) continue;
1572 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
1573 				if (olib == ni->proto->lib) break;
1574 			if (olib == NOLIBRARY)
1575 			{
1576 				ttyputerr(_("ERROR: Cell %s: has instance from invalid library"), describenodeproto(np));
1577 				ni->proto = gen_univpinprim;
1578 				continue;
1579 			}
1580 			for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
1581 				if (onp == ni->proto) break;
1582 			if (onp == NONODEPROTO)
1583 			{
1584 				ttyputerr(_("ERROR: Cell %s: has instance with invalid prototype"), describenodeproto(np));
1585 				ni->proto = gen_univpinprim;
1586 				continue;
1587 			}
1588 		}
1589 	}
1590 
1591 	/* create name hash table */
1592 	db_buildnodeprotohashtable(lib);
1593 
1594 	/* create port name hash tables */
1595 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1596 		db_buildportprotohashtable(np);
1597 
1598 	/* adjust every cell in the library */
1599 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1600 	{
1601 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1602 			for(pe = pp->subnodeinst->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1603 				if (pe->proto == pp->subportproto)
1604 		{
1605 			pp->subportexpinst = pe;  break;
1606 		}
1607 #ifdef MACOS
1608 		/*
1609 		 * The Macintosh uses a different date epoch than other machines, and this
1610 		 * is handled in "dbtext.c".  However, the adjustment code is recent,
1611 		 * and some old Macintosh libraries may have incorrect date information.
1612 		 *
1613 		 * The Macintosh epoch is 1904, but every other machine uses 1970.
1614 		 * Therefore, the Macintosh numbers are 66 years larger.
1615 		 *
1616 		 * To check for bogus date information, see if the date is larger
1617 		 * than the constant 0x9FE3EB1F.  This constant is 1989 in Mac time
1618 		 * but is 2055 elsewhere (1989 is the earliest possible incarnation
1619 		 * of Electric on the Mac).  If the date is that large, then either it
1620 		 * is 2055 and Macs still exist (unlikely) or the date is bad and needs
1621 		 * to have 66 years (0x7C254E10) subtracted from it.
1622 		 */
1623 		if (np->creationdate > 0x9FE3EB1F) np->creationdate -= 0x7C254E10;
1624 		if (np->revisiondate > 0x9FE3EB1F) np->revisiondate -= 0x7C254E10;
1625 #endif
1626 	}
1627 
1628 	/* look for arrayed node specifications */
1629 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1630 	{
1631 		if (!isschematicview(np)) continue;
1632 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1633 		{
1634 			net_setnodewidth(ni);
1635 		}
1636 	}
1637 
1638 	/*
1639 	 * see if this is version 4 or earlier...
1640 	 * In version 4 and earlier, the basic unit was the centimicron and rotation
1641 	 * was specified in degrees.  From version 5 and up, the basic unit is scaled
1642 	 * by 20 to the half-nanometer and the rotation fields are scaled by 10 to
1643 	 * tenth-degrees.  Also, must convert some variable names.
1644 	 */
1645 	io_getversion(lib, &major, &minor, &detail);
1646 
1647 	/* this is only done after all libraries are read */
1648 	if (io_libinputrecursivedepth == 0)
1649 	{
1650 		/* now fill in the connection lists on the ports */
1651 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
1652 			for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1653 				for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1654 		{
1655 			inpp = pp;
1656 			for(;;)
1657 			{
1658 				if (inpp == NOPORTPROTO) break;
1659 				if (inpp->parent->primindex != 0) break;
1660 				inpp = inpp->subportproto;
1661 			}
1662 			if (inpp != NOPORTPROTO)
1663 				pp->connects = inpp->connects;
1664 			if (pp->connects == 0)
1665 			{
1666 				if (gen_upconn[0] != 0) pp->connects = gen_upconn; else
1667 					pp->connects = &gen_upconn[1];
1668 				pp->subportproto = pp->subnodeinst->proto->firstportproto;
1669 			}
1670 		}
1671 
1672 		/* rebuild list of node instances */
1673 		for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
1674 			for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1675 				np->firstinst = NONODEINST;
1676 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
1677 			for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1678 				np->firstinst = NONODEINST;
1679 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
1680 			for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1681 		{
1682 			/* examine every nodeinst in the cell */
1683 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1684 			{
1685 				/* compute linked list of node instances */
1686 				pnt = ni->proto;
1687 				if (pnt == NONODEPROTO)
1688 				{
1689 					ttyputerr(_("Cell %s: has a node without a prototype"), describenodeproto(np));
1690 					ni->proto = gen_univpinprim;
1691 				}
1692 				if (pnt->firstinst != NONODEINST) pnt->firstinst->previnst = ni;
1693 				ni->nextinst = pnt->firstinst;
1694 				ni->previnst = NONODEINST;
1695 				pnt->firstinst = ni;
1696 			}
1697 		}
1698 
1699 		/* for versions 8.00 or later, look for arcs with negation in other "head" bit */
1700 		if (major >= 8)
1701 		{
1702 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
1703 				for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1704 			{
1705 				for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1706 				{
1707 					if ((ai->userbits&ISHEADNEGATED) != 0)
1708 					{
1709 						if ((ai->userbits&ISNEGATED) != 0)
1710 						{
1711 							ttyputmsg("Cell %s, arc %s is negated at both ends which is unsupported in this version of Electric.  Ignoring head negation.",
1712 								describenodeproto(np), describearcinst(ai));
1713 						} else
1714 						{
1715 							/* only the head is negated: reverse the arc */
1716 							if ((ai->userbits&REVERSEEND) != 0)
1717 								ai->userbits &= ~REVERSEEND; else
1718 									ai->userbits |= REVERSEEND;
1719 							ai->userbits |= ISNEGATED;
1720 							ai->userbits &= ~ISHEADNEGATED;
1721 						}
1722 					}
1723 				}
1724 			}
1725 		}
1726 
1727 		/* for versions before 6.05bc, look for icon cells that are wrong */
1728 		if (major < 6 ||
1729 			(major == 6 && minor < 5) ||
1730 			(major == 6 && minor == 5 && detail < 55))
1731 		{
1732 			numchanged = 0;
1733 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
1734 				for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1735 			{
1736 				first = TRUE;
1737 				for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1738 				{
1739 					boundobj(ni->geom, &lx, &hx, &ly, &hy);
1740 					if (first)
1741 					{
1742 						first = FALSE;
1743 						totlx = lx;   tothx = hx;
1744 						totly = ly;   tothy = hy;
1745 					} else
1746 					{
1747 						if (lx < totlx) totlx = lx;
1748 						if (hx > tothx) tothx = hx;
1749 						if (ly < totly) totly = ly;
1750 						if (hy > tothy) tothy = hy;
1751 					}
1752 				}
1753 				for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1754 				{
1755 					boundobj(ai->geom, &lx, &hx, &ly, &hy);
1756 					if (lx < totlx) totlx = lx;
1757 					if (hx > tothx) tothx = hx;
1758 					if (ly < totly) totly = ly;
1759 					if (hy > tothy) tothy = hy;
1760 				}
1761 				if (first) continue;
1762 				if (np->lowx == totlx && np->highx == tothx &&
1763 					np->lowy == totly && np->highy == tothy) continue;
1764 
1765 				for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
1766 				{
1767 					growx = ((tothx - np->highx) + (totlx - np->lowx)) / 2;
1768 					growy = ((tothy - np->highy) + (totly - np->lowy)) / 2;
1769 					if (ni->transpose != 0)
1770 					{
1771 						makeangle(ni->rotation, ni->transpose, trans);
1772 					} else
1773 					{
1774 						makeangle((3600 - ni->rotation)%3600, 0, trans);
1775 					}
1776 					xform(growx, growy, &shiftx, &shifty, trans);
1777 					ni->lowx += totlx - np->lowx - growx + shiftx;
1778 					ni->highx += tothx - np->highx - growx + shiftx;
1779 					ni->lowy += totly - np->lowy - growy + shifty;
1780 					ni->highy += tothy - np->highy - growy + shifty;
1781 					updategeom(ni->geom, ni->parent);
1782 				}
1783 				np->lowx = totlx;   np->highx = tothx;
1784 				np->lowy = totly;   np->highy = tothy;
1785 				numchanged++;
1786 			}
1787 			if (numchanged != 0)
1788 			{
1789 				ttyputmsg(_("WARNING: due to changes in bounds calculation, %ld cell sizes were adjusted"),
1790 					numchanged);
1791 				ttyputmsg(_("...should do Check&Repair library"));
1792 			}
1793 		}
1794 
1795 		/* create network information */
1796 		if (dia != 0) DiaSetTextProgress(dia, _("Building network data..."));
1797 		if (io_libinputreadmany > 0)
1798 		{
1799 			/* many libraries read: renumber everything */
1800 			(void)asktool(net_tool, x_("total-re-number"));
1801 		} else
1802 		{
1803 			/* just 1 library read: renumber it */
1804 			(void)asktool(net_tool, x_("library-re-number"), (INTBIG)lib);
1805 		}
1806 	}
1807 
1808 	/* set the cell's technology */
1809 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1810 		np->tech = whattech(np);
1811 
1812 	/* check for incorrect layer counts on stored variables */
1813 	io_fixtechlayers(lib);
1814 
1815 	/* for versions 7.01 or later, convert floating-point outline information */
1816 	if (major >= 7 || (major == 7 && minor >= 1))
1817 	{
1818 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1819 		{
1820 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1821 			{
1822 				var = getvalkey((INTBIG)ni, VNODEINST, VFLOAT|VISARRAY, el_trace_key);
1823 				if (var == NOVARIABLE) continue;
1824 				len = getlength(var);
1825 				intkey = (INTBIG *)emalloc(len*SIZEOFINTBIG, el_tempcluster);
1826 				lambda = lambdaofnode(ni);
1827 				for(i=0; i<len; i++)
1828 				{
1829 					intkey[i] = (int)(((float *)var->addr)[i] * lambda);
1830 				}
1831 				setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)intkey,
1832 					VINTEGER|VISARRAY|(len<<VLENGTHSH));
1833 			}
1834 		}
1835 	}
1836 
1837 	/* for versions 6.02 or earlier, convert text sizes */
1838 	if (major < 6 || (major == 6 && minor <= 2))
1839 	{
1840 #ifdef REPORTCONVERSION
1841 		ttyputmsg(x_("   Converting text sizes"));
1842 #endif
1843 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1844 		{
1845 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1846 			{
1847 				io_convertallrelativetext(ni->numvar, ni->firstvar);
1848 				for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1849 					io_convertallrelativetext(pi->numvar, pi->firstvar);
1850 				for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1851 					io_convertallrelativetext(pe->numvar, pe->firstvar);
1852 				if (ni->proto->primindex == 0)
1853 					io_convertrelativetext(ni->textdescript);
1854 			}
1855 			for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1856 				io_convertallrelativetext(ai->numvar, ai->firstvar);
1857 			for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1858 			{
1859 				io_convertallrelativetext(pp->numvar, pp->firstvar);
1860 				io_convertrelativetext(pp->textdescript);
1861 			}
1862 			io_convertallrelativetext(np->numvar, np->firstvar);
1863 		}
1864 		io_convertallrelativetext(lib->numvar, lib->firstvar);
1865 	}
1866 
1867 	/* for versions before 6.04c, convert text descriptor values */
1868 	if (major < 6 ||
1869 		(major == 6 && minor < 4) ||
1870 		(major == 6 && minor == 4 && detail < 3))
1871 	{
1872 #ifdef REPORTCONVERSION
1873 		ttyputmsg(x_("   Converting text descriptors"));
1874 #endif
1875 		io_converteverytextdescriptor(lib, 0);
1876 	}
1877 
1878 	/* for versions before 6.03r, convert variables on schematic primitives */
1879 	if (major < 6 ||
1880 		(major == 6 && minor < 3) ||
1881 		(major == 6 && minor == 3 && detail < 18))
1882 	{
1883 		if (sch_transistortypekey == 0)
1884 			sch_transistortypekey = makekey(x_("SCHEM_transistor_type"));
1885 		if (sch_sourcekey == 0)
1886 			sch_sourcekey = makekey(x_("SCHEM_source"));
1887 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1888 		{
1889 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1890 			{
1891 				if (ni->proto->primindex == 0) continue;
1892 				if (ni->proto->tech == sch_tech)
1893 				{
1894 					if (ni->proto == sch_transistorprim)
1895 					{
1896 						var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_transistortypekey);
1897 						if (var != NOVARIABLE)
1898 						{
1899 							str = (CHAR *)var->addr;
1900 							if (namesamen(str, x_("nmos"), 4) == 0)
1901 							{
1902 								ni->userbits |= TRANNMOS;    str += 4;
1903 							} else if (namesamen(str, x_("dmos"), 4) == 0)
1904 							{
1905 								ni->userbits |= TRANDMOS;    str += 4;
1906 							} else if (namesamen(str, x_("pmos"), 4) == 0)
1907 							{
1908 								ni->userbits |= TRANPMOS;    str += 4;
1909 							} else if (namesamen(str, x_("npn"), 3) == 0)
1910 							{
1911 								ni->userbits |= TRANNPN;     str += 3;
1912 							} else if (namesamen(str, x_("pnp"), 3) == 0)
1913 							{
1914 								ni->userbits |= TRANPNP;     str += 3;
1915 							} else if (namesamen(str, x_("njfet"), 5) == 0)
1916 							{
1917 								ni->userbits |= TRANNJFET;   str += 5;
1918 							} else if (namesamen(str, x_("pjfet"), 5) == 0)
1919 							{
1920 								ni->userbits |= TRANPJFET;   str += 5;
1921 							} else if (namesamen(str, x_("dmes"), 4) == 0)
1922 							{
1923 								ni->userbits |= TRANDMES;    str += 4;
1924 							} else if (namesamen(str, x_("emes"), 4) == 0)
1925 							{
1926 								ni->userbits |= TRANEMES;    str += 4;
1927 							}
1928 							if (*str == 0) (void)delvalkey((INTBIG)ni, VNODEINST, sch_transistortypekey); else
1929 							{
1930 								TDCOPY(olddescript, var->textdescript);
1931 								infstr = initinfstr();
1932 								addstringtoinfstr(infstr, str);
1933 								allocstring(&newname, returninfstr(infstr), el_tempcluster);
1934 								var = setvalkey((INTBIG)ni, VNODEINST, sch_transistortypekey,
1935 									(INTBIG)newname, var->type);
1936 								efree(newname);
1937 								if (var != NOVARIABLE)
1938 									TDCOPY(var->textdescript, olddescript);
1939 							}
1940 						}
1941 					} else if (ni->proto == sch_sourceprim)
1942 					{
1943 						var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_sourcekey);
1944 						if (var != NOVARIABLE)
1945 						{
1946 							str = (CHAR *)var->addr;
1947 							if (namesamen(str, x_("vd"), 2) == 0)
1948 							{
1949 								ni->userbits |= OLDSOURCEDCAN;   str += 2;
1950 							} else if (namesamen(str, x_("v"), 1) == 0)
1951 							{
1952 								ni->userbits |= OLDSOURCEDCV;   str++;
1953 							} else if (namesamen(str, x_("cm"), 2) == 0)
1954 							{
1955 								ni->userbits |= OLDSOURCECURMTR;   str += 2;
1956 							} else if (namesamen(str, x_("c"), 1) == 0)
1957 							{
1958 								ni->userbits |= OLDSOURCEDCC;   str++;
1959 							} else if (namesamen(str, x_("t"), 1) == 0)
1960 							{
1961 								ni->userbits |= OLDSOURCETRAN;   str++;
1962 							} else if (namesamen(str, x_("a"), 1) == 0)
1963 							{
1964 								ni->userbits |= OLDSOURCEAC;   str++;
1965 							} else if (namesamen(str, x_("n"), 1) == 0)
1966 							{
1967 								ni->userbits |= OLDSOURCENODE;   str++;
1968 							} else if (namesamen(str, x_("x"), 1) == 0)
1969 							{
1970 								ni->userbits |= OLDSOURCEEXT;   str++;
1971 							} else if (namesamen(str, x_("b"), 1) == 0)
1972 							{
1973 								ni->userbits |= OLDSOURCEBULK;   str++;
1974 							} else if (namesamen(str, x_("s"), 1) == 0)
1975 							{
1976 								ni->userbits |= OLDSOURCESPEC;   str++;
1977 							}
1978 							if (*str == '/') str++;
1979 							if (*str == 0) (void)delvalkey((INTBIG)ni, VNODEINST, sch_sourcekey); else
1980 							{
1981 								TDCOPY(olddescript, var->textdescript);
1982 								infstr = initinfstr();
1983 								addstringtoinfstr(infstr, str);
1984 								allocstring(&newname, returninfstr(infstr), el_tempcluster);
1985 								var = setvalkey((INTBIG)ni, VNODEINST, sch_sourcekey,
1986 									(INTBIG)newname, var->type|VDISPLAY);
1987 								efree(newname);
1988 								if (var != NOVARIABLE)
1989 									TDCOPY(var->textdescript, olddescript);
1990 							}
1991 						}
1992 					} else if (ni->proto == sch_diodeprim)
1993 					{
1994 						var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_diodekey);
1995 						if (var != NOVARIABLE)
1996 						{
1997 							str = (CHAR *)var->addr;
1998 							while (*str == ' ' || *str == '\t') str++;
1999 							if (tolower(*str) == 'z')
2000 							{
2001 								str++;
2002 								ni->userbits |= DIODEZENER;
2003 							}
2004 							if (*str == 0) (void)delvalkey((INTBIG)ni, VNODEINST, sch_diodekey); else
2005 							{
2006 								TDCOPY(olddescript, var->textdescript);
2007 								infstr = initinfstr();
2008 								addstringtoinfstr(infstr, str);
2009 								allocstring(&newname, returninfstr(infstr), el_tempcluster);
2010 								var = setvalkey((INTBIG)ni, VNODEINST, sch_diodekey,
2011 									(INTBIG)newname, var->type|VDISPLAY);
2012 								efree(newname);
2013 								if (var != NOVARIABLE)
2014 									TDCOPY(var->textdescript, olddescript);
2015 							}
2016 						}
2017 					} else if (ni->proto == sch_capacitorprim)
2018 					{
2019 						var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_capacitancekey);
2020 						if (var != NOVARIABLE)
2021 						{
2022 							str = (CHAR *)var->addr;
2023 							while (*str == ' ' || *str == '\t') str++;
2024 							if (tolower(*str) == 'e')
2025 							{
2026 								str++;
2027 								ni->userbits |= CAPACELEC;
2028 							}
2029 							if (*str == 0) (void)delvalkey((INTBIG)ni, VNODEINST, sch_capacitancekey); else
2030 							{
2031 								TDCOPY(olddescript, var->textdescript);
2032 								infstr = initinfstr();
2033 								addstringtoinfstr(infstr, str);
2034 								allocstring(&newname, returninfstr(infstr), el_tempcluster);
2035 								var = setvalkey((INTBIG)ni, VNODEINST, sch_capacitancekey,
2036 									(INTBIG)newname, var->type|VDISPLAY);
2037 								efree(newname);
2038 								if (var != NOVARIABLE)
2039 									TDCOPY(var->textdescript, olddescript);
2040 							}
2041 						}
2042 					} else if (ni->proto == sch_twoportprim)
2043 					{
2044 						if (sch_twoportkey == 0)
2045 							sch_twoportkey = makekey(x_("SCHEM_twoport_type"));
2046 						var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_twoportkey);
2047 						if (var != NOVARIABLE)
2048 						{
2049 							str = (CHAR *)var->addr;
2050 							while (*str == ' ') str++;
2051 							switch (tolower(*str))
2052 							{
2053 								case 'u': ni->userbits |= TWOPVCVS;    str++;   break;
2054 								case 'g': ni->userbits |= TWOPVCCS;    str++;   break;
2055 								case 'h': ni->userbits |= TWOPCCVS;    str++;   break;
2056 								case 'f': ni->userbits |= TWOPCCCS;    str++;   break;
2057 								case 'l': ni->userbits |= TWOPTLINE;   str++;   break;
2058 							}
2059 							nextchangequiet();
2060 							if (*str == 0) (void)delvalkey((INTBIG)ni, VNODEINST, sch_twoportkey); else
2061 							{
2062 								TDCOPY(olddescript, var->textdescript);
2063 								infstr = initinfstr();
2064 								addstringtoinfstr(infstr, str);
2065 								allocstring(&newname, returninfstr(infstr), el_tempcluster);
2066 								var = setvalkey((INTBIG)ni, VNODEINST, sch_spicemodelkey,
2067 									(INTBIG)newname, var->type|VDISPLAY);
2068 								efree(newname);
2069 								if (var != NOVARIABLE)
2070 									TDCOPY(var->textdescript, olddescript);
2071 							}
2072 						}
2073 					} else if (ni->proto == sch_ffprim)
2074 					{
2075 						if (sch_flipfloptypekey == 0)
2076 							sch_flipfloptypekey = makekey(x_("SCHEM_flipflop_type"));
2077 						var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_flipfloptypekey);
2078 						if (var != NOVARIABLE)
2079 						{
2080 							for (str = (CHAR *)var->addr; *str != 0; str++)
2081 							{
2082 								if (namesamen(str, x_("rs"), 2) == 0)
2083 								{
2084 									ni->userbits |= FFTYPERS;
2085 									str++;
2086 									continue;
2087 								}
2088 								if (namesamen(str, x_("jk"), 2) == 0)
2089 								{
2090 									ni->userbits |= FFTYPEJK;
2091 									str++;
2092 									continue;
2093 								}
2094 								if (namesamen(str, x_("t"), 1) == 0)
2095 								{
2096 									ni->userbits |= FFTYPET;
2097 									continue;
2098 								}
2099 								if (namesamen(str, x_("d"), 1) == 0)
2100 								{
2101 									ni->userbits |= FFTYPED;
2102 									continue;
2103 								}
2104 								if (namesamen(str, x_("ms"), 2) == 0)
2105 								{
2106 									ni->userbits |= FFCLOCKMS;
2107 									str++;
2108 									continue;
2109 								}
2110 								if (namesamen(str, x_("p"), 1) == 0)
2111 								{
2112 									ni->userbits |= FFCLOCKP;
2113 									continue;
2114 								}
2115 								if (namesamen(str, x_("n"), 1) == 0)
2116 								{
2117 									ni->userbits |= FFCLOCKN;
2118 									continue;
2119 								}
2120 							}
2121 							nextchangequiet();
2122 							(void)delvalkey((INTBIG)ni, VNODEINST, sch_flipfloptypekey);
2123 						}
2124 					}
2125 				}
2126 			}
2127 		}
2128 	}
2129 
2130 	/* for versions before 6.05bh, make sure that "far text" bit is set right */
2131 	if (io_libinputrecursivedepth == 0)
2132 	{
2133 		if (major < 6 ||
2134 			(major == 6 && minor < 5) ||
2135 			(major == 6 && minor == 5 && detail < 60))
2136 		{
2137 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
2138 				for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2139 			{
2140 				for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2141 					us_computenodefartextbit(ni);
2142 				for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
2143 					us_computearcfartextbit(ai);
2144 			}
2145 		}
2146 	}
2147 
2148 	/* for versions before 6.05bi, make all cell centers be "visible only inside cell" */
2149 	if (major < 6 ||
2150 		(major == 6 && minor < 5) ||
2151 		(major == 6 && minor == 5 && detail < 61))
2152 	{
2153 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2154 		{
2155 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2156 			{
2157 				if (ni->proto != gen_cellcenterprim) continue;
2158 				ni->userbits |= NVISIBLEINSIDE;
2159 			}
2160 		}
2161 	}
2162 
2163 	/* for versions before 6.05ba, convert source nodes */
2164 	if (major < 6 ||
2165 		(major == 6 && minor < 5) ||
2166 		(major == 6 && minor == 5 && detail < 53))
2167 	{
2168 		/* change all Wire_Pins that are 1x1 to be 0.5x0.5 */
2169 		numchanged = 0;
2170 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2171 		{
2172 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2173 			{
2174 				if (ni->proto->primindex == 0) continue;
2175 				if (ni->proto->tech != sch_tech) continue;
2176 				if (ni->proto != sch_wirepinprim) continue;
2177 				lambda = lambdaofnode(ni);
2178 				if (ni->highx - ni->lowx == lambda &&
2179 					ni->highy - ni->lowy == lambda)
2180 				{
2181 					modifynodeinst(ni, lambda/4, lambda/4, -lambda/4, -lambda/4, 0, 0);
2182 					numchanged++;
2183 				}
2184 			}
2185 		}
2186 		if (numchanged != 0)
2187 			ttyputmsg(_("Note: reduced the size of %ld schematic wire pins from 1x1 to 0.5x0.5"),
2188 				numchanged);
2189 	}
2190 
2191 	/* for versions before 6.05al, convert source nodes */
2192 	if (major < 6 ||
2193 		(major == 6 && minor < 5) ||
2194 		(major == 6 && minor == 5 && detail < 38))
2195 	{
2196 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2197 		{
2198 			changed = FALSE;
2199 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2200 			{
2201 				if (ni->proto->primindex == 0) continue;
2202 				if (ni->proto->tech != sch_tech) continue;
2203 				if (ni->proto != sch_sourceprim) continue;
2204 				str = 0;
2205 				switch (ni->userbits&NTECHBITS)
2206 				{
2207 					case OLDSOURCEDCAN:   str = x_("AnalysisDC");         break;
2208 					case OLDSOURCEDCV:    str = x_("DCVoltage");          break;
2209 					case OLDSOURCEDCC:    str = x_("DCCurrent");          break;
2210 					case OLDSOURCETRAN:   str = x_("AnalysisTransient");  break;
2211 					case OLDSOURCEAC:     str = x_("AnalysisAC");         break;
2212 					case OLDSOURCENODE:   str = x_("NodeSet");            break;
2213 					case OLDSOURCEEXT:    str = x_("Extension");          break;
2214 				}
2215 				if (str == 0) continue;
2216 
2217 				/* make sure the "spiceparts" library is read */
2218 				olib = getlibrary(x_("spiceparts"));
2219 				if (olib == NOLIBRARY)
2220 				{
2221 					par[0] = x_("library");
2222 					par[1] = x_("read");
2223 					par[2] = x_("spiceparts.txt");
2224 					par[3] = x_("text");
2225 					telltool(us_tool, 4, par);
2226 					olib = getlibrary(x_("spiceparts"));
2227 					if (olib == NOLIBRARY)
2228 					{
2229 						ttyputerr(_("Cannot find spice parts library for source conversion"));
2230 						break;
2231 					}
2232 				}
2233 				esnprintf(line, 200, x_("spiceparts:%s"), str);
2234 				onp = getnodeproto(line);
2235 				if (onp == NONODEPROTO)
2236 				{
2237 					ttyputerr(_("Cannot find '%s' for source conversion"), line);
2238 					break;
2239 				}
2240 				newni = replacenodeinst(ni, onp, TRUE, TRUE);
2241 				if (newni != NONODEINST)
2242 					newni->userbits |= NEXPAND;
2243 				changed = TRUE;
2244 			}
2245 			if (ni != NONODEINST) break;
2246 			if (changed)
2247 				ttyputmsg(_("Warning: SPICE components converted in cell %s.  Additional editing may be required."),
2248 					describenodeproto(np));
2249 		}
2250 	}
2251 
2252 	/* for versions before 6.07ap, make parameters visible by default  */
2253 	if (major < 6 ||
2254 		(major == 6 && minor < 7) ||
2255 		(major == 6 && minor == 7 && detail < 26+16))
2256 	{
2257 		j = 0;
2258 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2259 		{
2260 			for(i=0; i<np->numvar; i++)
2261 			{
2262 				var = &np->firstvar[i];
2263 				if (TDGETISPARAM(var->textdescript) == 0) continue;
2264 				if (TDGETINTERIOR(var->textdescript) == 0) continue;
2265 				TDSETINTERIOR(var->textdescript, 0);
2266 				j++;
2267 			}
2268 		}
2269 		if (j > 0)
2270 		{
2271 			ttyputmsg(x_("Library %s: cleaned up %ld old parameter visibility settings"),
2272 				lib->libname, j);
2273 			lib->userbits |= LIBCHANGEDMINOR;
2274 		}
2275 	}
2276 
2277 	/* for versions before 6.07b, adjust text  */
2278 	if (major < 6 ||
2279 		(major == 6 && minor < 7) ||
2280 		(major == 6 && minor == 7 && detail < 2))
2281 	{
2282 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2283 		{
2284 			tech = np->tech;
2285 			if (tech == NOTECHNOLOGY) tech = whattech(np);
2286 			celllambda = lib->lambda[tech->techindex];
2287 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2288 			{
2289 				onp = ni->proto;
2290 				tech = onp->tech;
2291 				if (tech == NOTECHNOLOGY) tech = whattech(onp);
2292 				lambda = lib->lambda[tech->techindex];
2293 				if (lambda == celllambda) continue;
2294 				for(i=0; i<ni->numvar; i++)
2295 				{
2296 					var = &ni->firstvar[i];
2297 					if ((var->type & VDISPLAY) == 0) continue;
2298 					xoff = muldiv(TDGETXOFF(var->textdescript), lambda, celllambda);
2299 					yoff = muldiv(TDGETYOFF(var->textdescript), lambda, celllambda);
2300 					TDSETOFF(var->textdescript, xoff, yoff);
2301 				}
2302 				us_computenodefartextbit(ni);
2303 			}
2304 			for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
2305 			{
2306 				tech = ai->proto->tech;
2307 				lambda = lib->lambda[tech->techindex];
2308 				if (lambda == celllambda) continue;
2309 				for(i=0; i<ai->numvar; i++)
2310 				{
2311 					var = &ai->firstvar[i];
2312 					if ((var->type & VDISPLAY) == 0) continue;
2313 					xoff = muldiv(TDGETXOFF(var->textdescript), lambda, celllambda);
2314 					yoff = muldiv(TDGETYOFF(var->textdescript), lambda, celllambda);
2315 					TDSETOFF(var->textdescript, xoff, yoff);
2316 				}
2317 				us_computearcfartextbit(ai);
2318 			}
2319 		}
2320 	}
2321 
2322 	/* for versions before 6.04o, separate transistor size and SPICE info */
2323 	if (major < 6 ||
2324 		(major == 6 && minor < 4) ||
2325 		(major == 6 && minor == 4 && detail < 15))
2326 	{
2327 		if (sch_transistortypekey == 0)
2328 			sch_transistortypekey = makekey(x_("SCHEM_transistor_type"));
2329 		if (sch_sourcekey == 0)
2330 			sch_sourcekey = makekey(x_("SCHEM_source"));
2331 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2332 		{
2333 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2334 			{
2335 				if (ni->proto->primindex == 0) continue;
2336 				if (ni->proto->tech != sch_tech) continue;
2337 
2338 				/* convert "SCHEM_source" to "SIM_spice_model" */
2339 				var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_sourcekey);
2340 				if (var != NOVARIABLE)
2341 				{
2342 					TDCOPY(olddescript, var->textdescript);
2343 					newvar = setvalkey((INTBIG)ni, VNODEINST, sch_spicemodelkey, var->addr,
2344 						var->type);
2345 					if (newvar != 0)
2346 						TDCOPY(newvar->textdescript, olddescript);
2347 					(void)delvalkey((INTBIG)ni, VNODEINST, sch_sourcekey);
2348 				}
2349 
2350 				if (ni->proto != sch_transistorprim &&
2351 					ni->proto != sch_transistor4prim) continue;
2352 				var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, sch_transistortypekey);
2353 				if (var == NOVARIABLE) continue;
2354 
2355 				/* look for "/" and split into Width and Length */
2356 				str = (CHAR *)var->addr;
2357 				oldtype = var->type;
2358 				TDCOPY(olddescript, var->textdescript);
2359 				for(pt = str; *pt != 0; pt++) if (*pt == '/') break;
2360 				if (*pt == '/')
2361 				{
2362 					*pt++ = 0;
2363 
2364 					/* determine separation of descriptors */
2365 					us_getlenwidoffset(ni, olddescript, &xoff, &yoff);
2366 					getsimpletype(str, &type, &addr, 0);
2367 					type |= oldtype & (VCODE1 | VCODE2 | VDISPLAY | VDONTSAVE);
2368 					newvar = setvalkey((INTBIG)ni, VNODEINST, el_attrkey_width, addr, type);
2369 					if (newvar != NOVARIABLE)
2370 					{
2371 						TDCOPY(newvar->textdescript, olddescript);
2372 						TDSETOFF(newvar->textdescript, TDGETXOFF(newvar->textdescript)+xoff,
2373 							TDGETYOFF(newvar->textdescript)+yoff);
2374 					}
2375 
2376 					str = pt;
2377 					for(pt = str; *pt != 0; pt++) if (*pt == '/') break;
2378 					if (*pt == '/') *pt++ = 0;
2379 					getsimpletype(str, &type, &addr, 0);
2380 					type |= oldtype & (VCODE1 | VCODE2 | VDISPLAY | VDONTSAVE);
2381 					newvar = setvalkey((INTBIG)ni, VNODEINST, el_attrkey_length, addr, type);
2382 					if (newvar != NOVARIABLE)
2383 					{
2384 						TDCOPY(newvar->textdescript, olddescript);
2385 						size = TDGETSIZE(newvar->textdescript);
2386 						i = TXTGETPOINTS(size);
2387 						if (i > 3) size = TXTSETPOINTS(i-2); else
2388 						{
2389 							i = TXTGETQLAMBDA(size);
2390 							if (i > 3) size = TXTSETQLAMBDA(i-2);
2391 						}
2392 						TDSETSIZE(newvar->textdescript, size);
2393 						TDSETOFF(newvar->textdescript, TDGETXOFF(newvar->textdescript)-xoff,
2394 							TDGETYOFF(newvar->textdescript)-yoff);
2395 					}
2396 
2397 					/* see if a SPICE model is at the end */
2398 					if (*pt != 0)
2399 					{
2400 						type = VSTRING | (oldtype & (VCODE1 | VCODE2 | VDISPLAY | VDONTSAVE));
2401 						newvar = setvalkey((INTBIG)ni, VNODEINST, sch_spicemodelkey,
2402 							(INTBIG)pt, type);
2403 						if (newvar != NOVARIABLE)
2404 							TDCOPY(newvar->textdescript, olddescript);
2405 					}
2406 				} else
2407 				{
2408 					/* single number: just save Area */
2409 					getsimpletype(str, &type, &addr, 0);
2410 					type |= oldtype & (VCODE1 | VCODE2 | VDISPLAY | VDONTSAVE);
2411 					newvar = setvalkey((INTBIG)ni, VNODEINST, el_attrkey_area, addr, type);
2412 					if (newvar != NOVARIABLE)
2413 						TDCOPY(newvar->textdescript, olddescript);
2414 				}
2415 				(void)delvalkey((INTBIG)ni, VNODEINST, sch_transistortypekey);
2416 			}
2417 		}
2418 	}
2419 
2420 	/* for versions before 6.03g, convert schematic and mocmossub primitives */
2421 	if (major < 6 ||
2422 		(major == 6 && minor < 3) ||
2423 		(major == 6 && minor == 3 && detail < 7))
2424 	{
2425 #ifdef REPORTCONVERSION
2426 		ttyputmsg(x_("   Converting schematic and MOSIS CMOS primitives"));
2427 #endif
2428 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2429 		{
2430 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2431 			{
2432 				if (ni->proto->primindex == 0) continue;
2433 				if (ni->proto->tech == sch_tech)
2434 				{
2435 					if (ni->proto == sch_pwrprim)
2436 					{
2437 						lam = lib->lambda[sch_tech->techindex];
2438 						io_fixupnodeinst(ni, lam/2, lam/2, -lam/2, -lam/2);
2439 					} else if (ni->proto == sch_gndprim)
2440 					{
2441 						lam = lib->lambda[sch_tech->techindex];
2442 						io_fixupnodeinst(ni, lam/2, 0, -lam/2, 0);
2443 					} else if (ni->proto == sch_capacitorprim)
2444 					{
2445 						lam = lib->lambda[sch_tech->techindex];
2446 						io_fixupnodeinst(ni, lam/2, 0, -lam/2, 0);
2447 					} else if (ni->proto == sch_resistorprim)
2448 					{
2449 						lam = lib->lambda[sch_tech->techindex];
2450 						io_fixupnodeinst(ni, 0, lam/2, 0, -lam/2);
2451 					}
2452 				} else if (ni->proto->tech == mocmos_tech)
2453 				{
2454 					if (ni->proto == mocmos_metal1metal2prim)
2455 					{
2456 						lam = lib->lambda[mocmos_tech->techindex];
2457 						io_fixupnodeinst(ni, -lam/2, -lam/2, lam/2, lam/2);
2458 					} else if (ni->proto == mocmos_metal4metal5prim)
2459 					{
2460 						lam = lib->lambda[mocmos_tech->techindex];
2461 						io_fixupnodeinst(ni, -lam/2, -lam/2, lam/2, lam/2);
2462 					} else if (ni->proto == mocmos_metal5metal6prim)
2463 					{
2464 						lam = lib->lambda[mocmos_tech->techindex];
2465 						io_fixupnodeinst(ni, -lam, -lam, lam, lam);
2466 					} else if (ni->proto == mocmos_ptransistorprim)
2467 					{
2468 						lam = lib->lambda[mocmos_tech->techindex];
2469 						io_fixupnodeinst(ni, 0, -lam, 0, lam);
2470 					} else if (ni->proto == mocmos_ntransistorprim)
2471 					{
2472 						lam = lib->lambda[mocmos_tech->techindex];
2473 						io_fixupnodeinst(ni, 0, -lam, 0, lam);
2474 					} else if (ni->proto == mocmos_metal1poly2prim)
2475 					{
2476 						lam = lib->lambda[mocmos_tech->techindex];
2477 						io_fixupnodeinst(ni, -lam*3, -lam*3, lam*3, lam*3);
2478 					} else if (ni->proto == mocmos_metal1poly12prim)
2479 					{
2480 						lam = lib->lambda[mocmos_tech->techindex];
2481 						io_fixupnodeinst(ni, -lam*4, -lam*4, lam*4, lam*4);
2482 					}
2483 				}
2484 			}
2485 		}
2486 	}
2487 
2488 	/* for versions before 6.03l, convert mocmossub via4-via6 */
2489 	if (major < 6 ||
2490 		(major == 6 && minor < 3) ||
2491 		(major == 6 && minor == 3 && detail < 12))
2492 	{
2493 #ifdef REPORTCONVERSION
2494 		ttyputmsg(x_("   Converting MOSIS CMOS vias"));
2495 #endif
2496 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2497 		{
2498 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2499 			{
2500 				if (ni->proto->primindex == 0) continue;
2501 				if (ni->proto->tech != mocmos_tech) continue;
2502 				if (namesame(ni->proto->protoname, x_("Metal-3-Metal-4-Con")) == 0 ||
2503 					namesame(ni->proto->protoname, x_("Metal-4-Metal-5-Con")) == 0 ||
2504 					namesame(ni->proto->protoname, x_("Metal-5-Metal-6-Con")) == 0)
2505 				{
2506 					lam = lib->lambda[mocmos_tech->techindex];
2507 					io_fixupnodeinst(ni, -lam, -lam, lam, lam);
2508 				}
2509 			}
2510 		}
2511 	}
2512 
2513 	/* for versions before 6.03aa, convert mocmossub well contacts */
2514 	if (major < 6 ||
2515 		(major == 6 && minor < 3) ||
2516 		(major == 6 && minor == 3 && detail < 27))
2517 	{
2518 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2519 		{
2520 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2521 			{
2522 				if (ni->proto->primindex == 0) continue;
2523 				if (ni->proto->tech != mocmos_tech) continue;
2524 				if (namesame(ni->proto->protoname, x_("Metal-1-N-Well-Con")) == 0 ||
2525 					namesame(ni->proto->protoname, x_("Metal-1-P-Well-Con")) == 0)
2526 				{
2527 					lam = lib->lambda[mocmos_tech->techindex];
2528 					io_fixupnodeinst(ni, -lam-lam/2, -lam-lam/2, lam+lam/2, lam+lam/2);
2529 				}
2530 			}
2531 		}
2532 	}
2533 
2534 	/* for versions before 6.05ab, derive "far text" bits */
2535 	if (major < 6 ||
2536 		(major == 6 && minor < 5) ||
2537 		(major == 6 && minor == 5 && detail < 28))
2538 	{
2539 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2540 		{
2541 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2542 				us_computenodefartextbit(ni);
2543 			for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
2544 				us_computearcfartextbit(ai);
2545 		}
2546 	}
2547 
2548 	/* for versions before 6.05ak, convert quick-key bindings */
2549 	if (major < 6 ||
2550 		(major == 6 && minor < 5) ||
2551 		(major == 6 && minor == 5 && detail < 37))
2552 	{
2553 		var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_quickkeyskey);
2554 		if (var != NOVARIABLE)
2555 		{
2556 			len = getlength(var);
2557 			newlist = (CHAR **)emalloc(len * (sizeof (CHAR *)), el_tempcluster);
2558 			changed = FALSE;
2559 			for(i=0; i<len; i++)
2560 			{
2561 				pt = ((CHAR **)var->addr)[i];
2562 				(void)allocstring(&newlist[i], pt, el_tempcluster);
2563 				if (pt[1] != '/') continue;
2564 				j = pt[0] & 0xFF;
2565 				if (j >= 0216 && j <= 0231)
2566 				{
2567 					/* convert former "function" key */
2568 					esnprintf(line, 200, x_("F%ld%s"), j - 0215, &pt[1]);
2569 					(void)reallocstring(&newlist[i], line, el_tempcluster);
2570 					changed = TRUE;
2571 				}
2572 			}
2573 			if (changed)
2574 			{
2575 				nextchangequiet();
2576 				setvalkey((INTBIG)us_tool, VTOOL, us_quickkeyskey, (INTBIG)newlist,
2577 					VSTRING|VISARRAY|(len<<VLENGTHSH));
2578 			}
2579 			for(i=0; i<len; i++) efree((CHAR *)newlist[i]);
2580 			efree((CHAR *)newlist);
2581 		}
2582 	}
2583 
2584 	/* for versions before 6.06i, convert electrical units */
2585 	if (major < 6 ||
2586 		(major == 6 && minor < 6) ||
2587 		(major == 6 && minor == 6 && detail < 9))
2588 	{
2589 		var = getvalkey((INTBIG)lib, VLIBRARY, VINTEGER, us_electricalunitskey);
2590 		if (var != NOVARIABLE)
2591 		{
2592 			j = var->addr;
2593 			i = (j&INTERNALCAPUNITS) >> INTERNALCAPUNITSSH;
2594 			if (i >= INTCAPUNITNFARAD)
2595 			{
2596 				j = (j & ~INTERNALCAPUNITS) | ((i+1) << INTERNALCAPUNITSSH);
2597 				nextchangequiet();
2598 				setvalkey((INTBIG)lib, VLIBRARY, us_electricalunitskey, j, VINTEGER);
2599 				us_electricalunits = j;
2600 			}
2601 		}
2602 		if (j != us_electricalunits)
2603 		io_converteverytextdescriptor(lib, 1);
2604 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2605 		{
2606 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2607 			{
2608 				if (ni->proto == sch_resistorprim)
2609 				{
2610 					var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_resistancekey);
2611 					if (var != NOVARIABLE)
2612 					{
2613 						pt = describesimplevariable(var);
2614 						value = (float)eatof(pt);
2615 						i = estrlen(pt);
2616 						if (i > 0)
2617 						{
2618 							if (tolower(pt[i-1]) == 'g')
2619 							{
2620 								value = value * 1000000000.0f;
2621 							} else if (i > 2 && namesame(&pt[i-3], x_("meg")) == 0)
2622 							{
2623 								value = value * 1000000.0f;
2624 							} else if (tolower(pt[i-1]) == 'k')
2625 							{
2626 								value = value * 1000.0f;
2627 							}
2628 						}
2629 						var = setvalkey((INTBIG)ni, VNODEINST, sch_resistancekey,
2630 							castint(value), VFLOAT | (var->type & ~VTYPE));
2631 						if (var != NOVARIABLE)
2632 							TDSETUNITS(var->textdescript, VTUNITSRES);
2633 					}
2634 					continue;
2635 				}
2636 				if (ni->proto == sch_capacitorprim)
2637 				{
2638 					var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_capacitancekey);
2639 					if (var != NOVARIABLE)
2640 					{
2641 						pt = describesimplevariable(var);
2642 						value = (float)eatof(pt);
2643 						i = estrlen(pt);
2644 						if (i > 0)
2645 						{
2646 							if (tolower(pt[i-1]) == 'f')
2647 							{
2648 								value = value / 1000000000000000.0f;
2649 							} else if (tolower(pt[i-1]) == 'p')
2650 							{
2651 								value = value / 1000000000000.0f;
2652 							} else if (tolower(pt[i-1]) == 'u')
2653 							{
2654 								value = value / 1000000.0f;
2655 							} else if (tolower(pt[i-1]) == 'm')
2656 							{
2657 								value = value / 1000.0f;
2658 							}
2659 						}
2660 						var = setvalkey((INTBIG)ni, VNODEINST, sch_capacitancekey,
2661 							castint(value), VFLOAT | (var->type & ~VTYPE));
2662 						if (var != NOVARIABLE)
2663 							TDSETUNITS(var->textdescript, VTUNITSCAP);
2664 					}
2665 					continue;
2666 				}
2667 				if (ni->proto == sch_inductorprim)
2668 				{
2669 					var = getvalkey((INTBIG)ni, VNODEINST, -1, sch_inductancekey);
2670 					if (var != NOVARIABLE)
2671 					{
2672 						pt = describesimplevariable(var);
2673 						value = (float)eatof(pt);
2674 						i = estrlen(pt);
2675 						if (i > 0)
2676 						{
2677 							if (tolower(pt[i-1]) == 'u')
2678 							{
2679 								value = value / 1000000.0f;
2680 							} else if (tolower(pt[i-1]) == 'm')
2681 							{
2682 								value = value / 1000.0f;
2683 							}
2684 						}
2685 						var = setvalkey((INTBIG)ni, VNODEINST, sch_inductancekey,
2686 							castint(value), VFLOAT | (var->type & ~VTYPE));
2687 						if (var != NOVARIABLE)
2688 							TDSETUNITS(var->textdescript, VTUNITSIND);
2689 					}
2690 					continue;
2691 				}
2692 			}
2693 		}
2694 	}
2695 
2696 	/* for versions before 6.08, adjust ports in technology-edit libraries */
2697 	if (major < 6 ||
2698 		(major == 6 && minor < 8))
2699 	{
2700 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2701 		{
2702 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2703 			{
2704 				if (ni->proto == gen_portprim)
2705 					modifynodeinst(ni, -4000, -4000, 4000, 4000, 0, 0);
2706 			}
2707 		}
2708 	}
2709 
2710 	/* for versions before 6.08v, set "technology edit" bit for appropriate cells */
2711 	if (major < 6 ||
2712 		(major == 6 && minor < 8) ||
2713 		(major == 6 && minor == 8 && detail < 22))
2714 	{
2715 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2716 		{
2717 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2718 			{
2719 				var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, us_edtec_option_key);
2720 				if (var != NOVARIABLE) break;
2721 			}
2722 			if (ni != NONODEINST)
2723 				np->userbits |= TECEDITCELL;
2724 		}
2725 	}
2726 
2727 	/* for versions before 7.00l, convert quick key bindings that refer to "facets" */
2728 	if (major < 7 ||
2729 		(major == 7 && minor < 0) ||
2730 		(major == 7 && minor == 0 && detail < 12))
2731 	{
2732 		var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_quickkeyskey);
2733 		if (var != NOVARIABLE)
2734 		{
2735 			len = getlength(var);
2736 			for(i=0; i<len; i++)
2737 			{
2738 				for(pt = ((CHAR **)var->addr)[i]; *pt != 0; pt++)
2739 				{
2740 					if (namesamen(pt, "facet", 5) != 0) continue;
2741 					strcpy(pt, "Cell");
2742 					strcpy(&pt[4], &pt[5]);
2743 				}
2744 			}
2745 		}
2746 	}
2747 
2748 	/* the rest of the changes are just for version 4 or earlier */
2749 	if (major >= 5) return;
2750 
2751 	/* setup for units conversion */
2752 	(void)needstaticpolygon(&poly, 4, io_tool->cluster);
2753 
2754 	/* must scale, first make sure the technologies agree with this library */
2755 	if (lib != el_curlib)
2756 		for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
2757 			changetechnologylambda(tech, lib->lambda[tech->techindex]);
2758 
2759 	/* now scale */
2760 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2761 	{
2762 		var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
2763 		if (var != NOVARIABLE)
2764 		{
2765 			((INTBIG *)var->addr)[0] *= 20;
2766 			((INTBIG *)var->addr)[1] *= 20;
2767 		}
2768 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2769 		{
2770 			ni->lowx *= 20;   ni->highx *= 20;
2771 			ni->lowy *= 20;   ni->highy *= 20;
2772 			ni->rotation *= 10;
2773 			var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, us_edtec_option_key);
2774 			if (var != NOVARIABLE)
2775 			{
2776 				if (var->addr == TECHLAMBDA)
2777 				{
2778 					var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
2779 					if (var != NOVARIABLE)
2780 					{
2781 						lam = myatoi(&((CHAR *)var->addr)[8]);
2782 						(void)esnprintf(line, 200, x_("Lambda: %ld"), lam*20);
2783 						nextchangequiet();
2784 						(void)setvalkey((INTBIG)ni, VNODEINST, art_messagekey,
2785 							(INTBIG)line, VSTRING|VDISPLAY);
2786 					}
2787 				}
2788 			}
2789 			var = gettrace(ni);
2790 			if (var != NOVARIABLE)
2791 			{
2792 				i = getlength(var);
2793 				for(j=0; j<i; j++) ((INTBIG *)var->addr)[j] *= 20;
2794 			}
2795 			var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, art_degreeskey);
2796 			if (var != NOVARIABLE) var->addr *= 10;
2797 			boundobj(ni->geom, &ni->geom->lowx, &ni->geom->highx, &ni->geom->lowy, &ni->geom->highy);
2798 		}
2799 	}
2800 
2801 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2802 	{
2803 		for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
2804 		{
2805 			ai->width *= 20;
2806 			ai->end[0].xpos *= 20;   ai->end[0].ypos *= 20;
2807 			ai->end[1].xpos *= 20;   ai->end[1].ypos *= 20;
2808 			(void)setshrinkvalue(ai, FALSE);
2809 			var = getvalkey((INTBIG)ai, VARCINST, VINTEGER, el_arc_radius_key);
2810 			if (var != NOVARIABLE) var->addr *= 20;
2811 			for(i=0; i<2; i++)
2812 			{
2813 				/* make sure arcinst connects in portinst area */
2814 				shapeportpoly(ai->end[i].nodeinst, ai->end[i].portarcinst->proto, poly, FALSE);
2815 				if (isinside(ai->end[i].xpos, ai->end[i].ypos, poly)) continue;
2816 				portposition(ai->end[i].nodeinst, ai->end[i].portarcinst->proto, &lx, &ly);
2817 				if (lx == ai->end[i].xpos && ly == ai->end[i].ypos) continue;
2818 
2819 				/* try to make manhattan fix */
2820 				if ((ai->end[0].xpos == ai->end[1].xpos) && isinside(ai->end[i].xpos, ly, poly))
2821 					ai->end[i].ypos = ly; else
2822 						if ((ai->end[0].ypos == ai->end[1].ypos) &&
2823 							isinside(lx, ai->end[i].ypos, poly))
2824 								ai->end[i].xpos = lx; else
2825 				{
2826 					ai->end[i].xpos = lx;   ai->end[i].ypos = ly;
2827 				}
2828 			}
2829 			ai->length = computedistance(ai->end[0].xpos,ai->end[0].ypos,
2830 				ai->end[1].xpos,ai->end[1].ypos);
2831 			boundobj(ai->geom, &ai->geom->lowx, &ai->geom->highx, &ai->geom->lowy, &ai->geom->highy);
2832 		}
2833 		db_boundcell(np, &np->lowx, &np->highx, &np->lowy, &np->highy);
2834 		io_fixrtree(np->rtree);
2835 	}
2836 
2837 	/* now restore the technology lambda values */
2838 	if (lib != el_curlib)
2839 		for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
2840 			changetechnologylambda(tech, el_curlib->lambda[tech->techindex]);
2841 }
2842 
2843 #define OLDSIZE      01700
2844 #define OLDSIZESH        6
2845 #define OLDTXT4P         0			/* 4 point text     */
2846 #define OLDTXT6P         1			/* 6 point text     */
2847 #define OLDTXT8P         2			/* 8 point text     */
2848 #define OLDTXT10P        3			/* 10 point text    */
2849 #define OLDTXT12P        4			/* 12 point text    */
2850 #define OLDTXT14P        5			/* 14 point text    */
2851 #define OLDTXT16P        6			/* 16 point text    */
2852 #define OLDTXT18P        7			/* 18 point text    */
2853 #define OLDTXT20P        8			/* 20 point text    */
2854 #define OLDTXTHL         9			/* half-lambda text */
2855 #define OLDTXT1L        10			/* 1-lambda text    */
2856 #define OLDTXT2L        11			/* 2-lambda text    */
2857 #define OLDTXT3L        12			/* 3-lambda text    */
2858 #define OLDTXT4L        13			/* 4-lambda text    */
2859 #define OLDTXT5L        14			/* 5-lambda text    */
2860 #define OLDTXT6L        15			/* 6-lambda text    */
2861 
2862 #define OLDOFFSCALE  07700000000	/* old scale of text offset */
2863 
2864 /*
2865  * Routine to do conversion "how" on every text descriptor in library "lib".
2866  * If "how" is 0, convert old-style text sizes to new style
2867  * If "how" is 1, shorten the text offset scale field by 1 bit
2868  */
io_converteverytextdescriptor(LIBRARY * lib,INTBIG how)2869 void io_converteverytextdescriptor(LIBRARY *lib, INTBIG how)
2870 {
2871 	REGISTER NODEPROTO *np;
2872 	REGISTER NODEINST *ni;
2873 	REGISTER ARCINST *ai;
2874 	REGISTER PORTARCINST *pi;
2875 	REGISTER PORTEXPINST *pe;
2876 	REGISTER PORTPROTO *pp;
2877 
2878 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2879 	{
2880 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2881 		{
2882 			io_convertalltextdescriptors(ni->numvar, ni->firstvar, how);
2883 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2884 				io_convertalltextdescriptors(pi->numvar, pi->firstvar, how);
2885 			for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
2886 				io_convertalltextdescriptors(pe->numvar, pe->firstvar, how);
2887 			if (ni->proto->primindex == 0)
2888 				io_converttextdescriptor(ni->textdescript, how);
2889 		}
2890 		for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
2891 			io_convertalltextdescriptors(ai->numvar, ai->firstvar, how);
2892 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2893 		{
2894 			io_convertalltextdescriptors(pp->numvar, pp->firstvar, how);
2895 			io_converttextdescriptor(pp->textdescript, how);
2896 		}
2897 		io_convertalltextdescriptors(np->numvar, np->firstvar, how);
2898 	}
2899 	io_convertalltextdescriptors(lib->numvar, lib->firstvar, how);
2900 }
2901 
2902 /*
2903  * Routine to do conversion "how" on all text descriptors on all "numvar" variables
2904  * in "firstvar".
2905  */
io_convertalltextdescriptors(INTSML numvar,VARIABLE * firstvar,INTBIG how)2906 void io_convertalltextdescriptors(INTSML numvar, VARIABLE *firstvar, INTBIG how)
2907 {
2908 	REGISTER INTBIG i;
2909 	REGISTER VARIABLE *var;
2910 
2911 	for(i=0; i<numvar; i++)
2912 	{
2913 		var = &firstvar[i];
2914 		io_converttextdescriptor(var->textdescript, how);
2915 	}
2916 }
2917 
2918 /*
2919  * Routine to do conversion "how" on text descriptor "descript".
2920  */
io_converttextdescriptor(UINTBIG * descript,INTBIG how)2921 void io_converttextdescriptor(UINTBIG *descript, INTBIG how)
2922 {
2923 	REGISTER INTBIG size, oldscale;
2924 
2925 	switch (how)
2926 	{
2927 		case 0:		/* convert size information */
2928 			size = (descript[0]&OLDSIZE) >> OLDSIZESH;
2929 			switch (size)
2930 			{
2931 				case OLDTXT4P:  size = TXTSETPOINTS(4);     break;
2932 				case OLDTXT6P:  size = TXTSETPOINTS(6);     break;
2933 				case OLDTXT8P:  size = TXTSETPOINTS(8);     break;
2934 				case OLDTXT10P: size = TXTSETPOINTS(10);    break;
2935 				case OLDTXT12P: size = TXTSETPOINTS(12);    break;
2936 				case OLDTXT14P: size = TXTSETPOINTS(14);    break;
2937 				case OLDTXT16P: size = TXTSETPOINTS(16);    break;
2938 				case OLDTXT18P: size = TXTSETPOINTS(18);    break;
2939 				case OLDTXT20P: size = TXTSETPOINTS(20);    break;
2940 				case OLDTXTHL:  size = TXTSETQLAMBDA(4/2);  break;
2941 				case OLDTXT1L:  size = TXTSETQLAMBDA(1*4);  break;
2942 				case OLDTXT2L:  size = TXTSETQLAMBDA(2*4);  break;
2943 				case OLDTXT3L:  size = TXTSETQLAMBDA(3*4);  break;
2944 				case OLDTXT4L:  size = TXTSETQLAMBDA(4*4);  break;
2945 				case OLDTXT5L:  size = TXTSETQLAMBDA(5*4);  break;
2946 				case OLDTXT6L:  size = TXTSETQLAMBDA(6*4);  break;
2947 			}
2948 			descript[0] &= ~OLDSIZE;
2949 			descript[1] = size << VTSIZESH;
2950 			break;
2951 
2952 		case 1:		/* shorten offset scale field */
2953 			oldscale = descript[1] & OLDOFFSCALE;
2954 			descript[1] = (descript[1] & ~VTOFFSCALE) | (oldscale & VTOFFSCALE);
2955 			break;
2956 	}
2957 }
2958 
io_fixupnodeinst(NODEINST * ni,INTBIG dlx,INTBIG dly,INTBIG dhx,INTBIG dhy)2959 void io_fixupnodeinst(NODEINST *ni, INTBIG dlx, INTBIG dly, INTBIG dhx, INTBIG dhy)
2960 {
2961 	REGISTER PORTARCINST *pi;
2962 	REGISTER ARCINST *ai;
2963 
2964 	for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2965 	{
2966 		ai = pi->conarcinst;
2967 		(void)(*el_curconstraint->setobject)((INTBIG)ai, VARCINST, CHANGETYPETEMPUNRIGID, 0);
2968 	}
2969 	modifynodeinst(ni, dlx, dly, dhx, dhy, 0, 0);
2970 }
2971 
io_convertallrelativetext(INTSML numvar,VARIABLE * firstvar)2972 void io_convertallrelativetext(INTSML numvar, VARIABLE *firstvar)
2973 {
2974 	REGISTER INTBIG i;
2975 	REGISTER VARIABLE *var;
2976 
2977 	for(i=0; i<numvar; i++)
2978 	{
2979 		var = &firstvar[i];
2980 		io_convertrelativetext(var->textdescript);
2981 	}
2982 }
2983 
io_convertrelativetext(UINTBIG * descript)2984 void io_convertrelativetext(UINTBIG *descript)
2985 {
2986 	REGISTER INTBIG size;
2987 
2988 	size = (descript[0]&OLDSIZE) >> OLDSIZESH;
2989 	if (size >= OLDTXT4P && size <= OLDTXT20P) return;
2990 
2991 	if (size <= 13)
2992 	{
2993 		/* TXTSMALL */
2994 		descript[0] = (descript[0] & ~OLDSIZE) | (OLDTXT1L << OLDSIZESH);
2995 		return;
2996 	}
2997 
2998 	if (size == 14)
2999 	{
3000 		/* TXTMEDIUM */
3001 		descript[0] = (descript[0] & ~OLDSIZE) | (OLDTXT2L << OLDSIZESH);
3002 		return;
3003 	}
3004 
3005 	/* TXTLARGE */
3006 	descript[0] = (descript[0] & ~OLDSIZE) | (OLDTXT3L << OLDSIZESH);
3007 }
3008 
3009 /*
3010  * Routine to convert old primitive names to their proper nodeprotos.
3011  */
io_convertoldprimitives(TECHNOLOGY * tech,CHAR * name)3012 NODEPROTO *io_convertoldprimitives(TECHNOLOGY *tech, CHAR *name)
3013 {
3014 	if (namesame(name, x_("Cell-Center")) == 0) return(gen_cellcenterprim);
3015 	if (tech == art_tech)
3016 	{
3017 		if (namesame(name, x_("Message")) == 0 ||
3018 			namesame(name, x_("Centered-Message")) == 0 ||
3019 			namesame(name, x_("Left-Message")) == 0 ||
3020 			namesame(name, x_("Right-Message")) == 0) return(gen_invispinprim);
3021 		if (namesame(name, x_("Opened-FarDotted-Polygon")) == 0)
3022 			return(art_openedthickerpolygonprim);
3023 	}
3024 	if (tech == mocmos_tech)
3025 	{
3026 		if (namesame(name, x_("Metal-1-Substrate-Con")) == 0)
3027 			return(mocmos_metal1nwellprim);
3028 		if (namesame(name, x_("Metal-1-Well-Con")) == 0)
3029 			return(mocmos_metal1pwellprim);
3030 	}
3031 	return(NONODEPROTO);
3032 }
3033 
3034 /*
3035  * Routine to convert old libraries that have no cellgroup pointers.  Finds
3036  * matching names and presumes that they are in the same cellgroup.
3037  */
io_buildcellgrouppointersfromnames(LIBRARY * lib)3038 void io_buildcellgrouppointersfromnames(LIBRARY *lib)
3039 {
3040 	REGISTER NODEPROTO *np, *onp, *prevmatch;
3041 
3042 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3043 		np->nextcellgrp = np;
3044 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3045 	{
3046 		/* ignore old versions */
3047 		if (np->newestversion != np) continue;
3048 
3049 		/* skip if already in a cellgroup */
3050 		if (np->nextcellgrp != np) continue;
3051 
3052 		/* find others in this cell group */
3053 		prevmatch = np;
3054 		for(onp = np->nextnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
3055 		{
3056 			/* ignore old versions */
3057 			if (onp->newestversion != onp) continue;
3058 
3059 			/* ignore if the name doesn't match */
3060 			if (namesame(np->protoname, onp->protoname) != 0) continue;
3061 
3062 			/* add this to the cellgroup */
3063 			prevmatch->nextcellgrp = onp;
3064 			prevmatch = onp;
3065 		}
3066 
3067 		/* make this cellgroup's list circular */
3068 		if (prevmatch != np)
3069 			prevmatch->nextcellgrp = np;
3070 	}
3071 }
3072 
3073 /*
3074  * Routine to find the version of Electric that generated library "lib" and
3075  * parse it into three fields: the major version number, minor version, and
3076  * a detail version number.
3077  */
io_getversion(LIBRARY * lib,INTBIG * major,INTBIG * minor,INTBIG * detail)3078 void io_getversion(LIBRARY *lib, INTBIG *major, INTBIG *minor, INTBIG *detail)
3079 {
3080 	REGISTER VARIABLE *var;
3081 	INTBIG emajor, eminor, edetail;
3082 	CHAR *libversion;
3083 
3084 	var = getval((INTBIG)lib, VLIBRARY, VSTRING, x_("LIB_former_version"));
3085 	if (var == NOVARIABLE)
3086 	{
3087 		*major = *minor = *detail = 0;
3088 		return;
3089 	}
3090 	libversion = (CHAR *)var->addr;
3091 	parseelectricversion(libversion, major, minor, detail);
3092 
3093 	/* see if this library is newer than the current version of Electric */
3094 	parseelectricversion(el_version, &emajor, &eminor, &edetail);
3095 	if (*major > emajor ||
3096 		(*major == emajor && *minor > eminor) ||
3097 		(*major == emajor && *minor == eminor && *detail > edetail))
3098 	{
3099 		ttyputerr(_("Warning: library %s comes from a NEWER version of Electric (%s)"),
3100 			lib->libname, libversion);
3101 	}
3102 }
3103 
3104 /* Technology: Lambda Adjustment */
3105 static DIALOGITEM io_techadjlamdialogitems[] =
3106 {
3107  /*  1 */ {0, {232,220,256,300}, BUTTON, N_("Done")},
3108  /*  2 */ {0, {204,264,220,512}, BUTTON, N_("Use New Size for all Technologies")},
3109  /*  3 */ {0, {204,8,220,256}, BUTTON, N_("Use Current Size for all Technologies")},
3110  /*  4 */ {0, {28,300,128,512}, SCROLL, x_("")},
3111  /*  5 */ {0, {148,8,164,164}, MESSAGE, N_("Current lambda size:")},
3112  /*  6 */ {0, {148,264,164,416}, MESSAGE, N_("New lambda size:")},
3113  /*  7 */ {0, {148,164,164,256}, MESSAGE, x_("")},
3114  /*  8 */ {0, {148,416,164,512}, MESSAGE, x_("")},
3115  /*  9 */ {0, {176,264,192,512}, BUTTON, N_("<< Use New Size in Current Library")},
3116  /* 10 */ {0, {176,8,192,256}, BUTTON, N_("Use Current Size in New Library >>")},
3117  /* 11 */ {0, {80,16,96,292}, MESSAGE, N_("and choose from the actions below.")},
3118  /* 12 */ {0, {8,8,24,508}, MESSAGE, N_("This new library uses different lambda values than existing libraries.")},
3119  /* 13 */ {0, {28,8,44,292}, MESSAGE, N_("You should unify the lambda values.")},
3120  /* 14 */ {0, {60,8,76,292}, MESSAGE, N_("Click on each technology in this list")},
3121  /* 15 */ {0, {136,8,137,512}, DIVIDELINE, x_("")},
3122  /* 16 */ {0, {112,8,128,284}, MESSAGE, N_("Use 'Check and Repair Libraries' when done.")}
3123 };
3124 static DIALOG io_techadjlamdialog = {{75,75,340,596}, N_("Lambda Value Adjustment"), 0, 16, io_techadjlamdialogitems, 0, 0};
3125 
3126 /* special items for the "lambda adjustment" dialog: */
3127 #define DTLA_USENEWALWAYS   2		/* Use new unit always (button) */
3128 #define DTLA_USECURALWAYS   3		/* Use current unit always (button) */
3129 #define DTLA_TECHLIST       4		/* List of technologies (scroll) */
3130 #define DTLA_CURLAMBDA      7		/* Current lambda value (stat text) */
3131 #define DTLA_NEWLAMBDA      8		/* New lambda value (stat text) */
3132 #define DTLA_USENEW         9		/* Use new unit (button) */
3133 #define DTLA_USECUR        10		/* Use current unit (button) */
3134 
3135 /*
3136  * Routine to examine new library "lib" and make sure that the lambda values in it are
3137  * the same as existing libraries/technologies.  Automatically adjusts values if possible,
3138  * and prompts the user to help out if necessary.
3139  */
io_unifylambdavalues(LIBRARY * lib)3140 void io_unifylambdavalues(LIBRARY *lib)
3141 {
3142 	REGISTER TECHNOLOGY *tech, *otech, **techarray;
3143 	REGISTER LIBRARY *olib;
3144 	REGISTER NODEPROTO *np, **libcells;
3145 	REGISTER NODEINST *ni;
3146 	REGISTER ARCINST *ai;
3147 	REGISTER INTBIG itemHit, i, count, recompute, newunit, curunit, *newlamarray,
3148 		oldbits;
3149 	REGISTER CHAR *pt;
3150 	float lambdainmicrons;
3151 	CHAR line[50];
3152 	REGISTER void *dia;
3153 
3154 	/* see if this library has incompatible lambda values */
3155 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
3156 	{
3157 		if (tech == art_tech) continue;
3158 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3159 		{
3160 			if (lib->lambda[tech->techindex] != olib->lambda[tech->techindex])
3161 				break;
3162 		}
3163 		if (olib != NOLIBRARY) break;
3164 	}
3165 	if (tech == NOTECHNOLOGY) return;
3166 
3167 	/* this library has different values: check usage in this and other libraries */
3168 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3169 	{
3170 		olib->temp1 = (INTBIG)emalloc(el_maxtech * (sizeof (NODEPROTO *)), el_tempcluster);
3171 		if (olib->temp1 == 0) return;
3172 		for(i=0; i<el_maxtech; i++) ((NODEPROTO **)olib->temp1)[i] = NONODEPROTO;
3173 	}
3174 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3175 	{
3176 		libcells = (NODEPROTO **)olib->temp1;
3177 		for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3178 		{
3179 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3180 			{
3181 				if (ni->proto->primindex == 0) continue;
3182 				tech = ni->proto->tech;
3183 				libcells[tech->techindex] = np;
3184 			}
3185 			for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
3186 			{
3187 				tech = ai->proto->tech;
3188 				libcells[tech->techindex] = np;
3189 			}
3190 		}
3191 	}
3192 
3193 	/* see if there are inconsistencies that cannot be automatically resolved */
3194 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
3195 	{
3196 		if (tech == art_tech) continue;
3197 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3198 		{
3199 			if (((NODEPROTO **)olib->temp1)[tech->techindex] == NONODEPROTO) continue;
3200 			if (((NODEPROTO **)lib->temp1)[tech->techindex] == NONODEPROTO) continue;
3201 			if (lib->lambda[tech->techindex] != olib->lambda[tech->techindex])
3202 				break;
3203 		}
3204 		if (olib != NOLIBRARY) break;
3205 	}
3206 	if (tech != NOTECHNOLOGY)
3207 	{
3208 		/* get the user to resolve the inconsistencies */
3209 		dia = DiaInitDialog(&io_techadjlamdialog);
3210 		if (dia == 0) return;
3211 		DiaInitTextDialog(dia, DTLA_TECHLIST, DiaNullDlogList, DiaNullDlogItem,
3212 			DiaNullDlogDone, -1, SCSELMOUSE|SCREPORT);
3213 		DiaUnDimItem(dia, DTLA_USECURALWAYS);
3214 		DiaUnDimItem(dia, DTLA_USENEWALWAYS);
3215 		for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
3216 		{
3217 			if (tech == art_tech) continue;
3218 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3219 			{
3220 				if (((NODEPROTO **)olib->temp1)[tech->techindex] == NONODEPROTO) continue;
3221 				if (((NODEPROTO **)lib->temp1)[tech->techindex] == NONODEPROTO) continue;
3222 				if (lib->lambda[tech->techindex] != olib->lambda[tech->techindex])
3223 					break;
3224 			}
3225 			if (olib == NOLIBRARY) continue;
3226 			DiaStuffLine(dia, DTLA_TECHLIST, tech->techname);
3227 		}
3228 		DiaSelectLine(dia, DTLA_TECHLIST, 0);
3229 		recompute = 1;
3230 		tech = NOTECHNOLOGY;
3231 		for(;;)
3232 		{
3233 			if (recompute != 0)
3234 			{
3235 				recompute = 0;
3236 
3237 				/* figure out which technology is selected */
3238 				i = DiaGetCurLine(dia, DTLA_TECHLIST);
3239 				pt = DiaGetScrollLine(dia, DTLA_TECHLIST, i);
3240 				for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
3241 					if (namesame(pt, tech->techname) == 0) break;
3242 				if (tech == NOTECHNOLOGY) continue;
3243 
3244 				/* figure out which units are in force */
3245 				curunit = newunit = lib->lambda[tech->techindex];
3246 				for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3247 				{
3248 					if ((olib->userbits&HIDDENLIBRARY) != 0) continue;
3249 					if (((NODEPROTO **)olib->temp1)[tech->techindex] == NONODEPROTO) continue;
3250 					if (((NODEPROTO **)olib->temp1)[tech->techindex] == 0) continue;
3251 					if (olib->lambda[tech->techindex] != lib->lambda[tech->techindex]) break;
3252 				}
3253 				if (olib != NOLIBRARY) curunit = olib->lambda[tech->techindex];
3254 
3255 				/* see if it has already been overridden */
3256 				if (((INTBIG *)lib->temp1)[tech->techindex] == 0) newunit = curunit;
3257 
3258 				/* set dialog values and offer choices */
3259 				lambdainmicrons = scaletodispunit(curunit, DISPUNITMIC);
3260 				esnprintf(line, 50, x_("%gu"), lambdainmicrons);
3261 				DiaSetText(dia, DTLA_CURLAMBDA, line);
3262 				lambdainmicrons = scaletodispunit(newunit, DISPUNITMIC);
3263 				esnprintf(line, 50, x_("%gu"), lambdainmicrons);
3264 				DiaSetText(dia, DTLA_NEWLAMBDA, line);
3265 				if (newunit == curunit)
3266 				{
3267 					DiaDimItem(dia, DTLA_USENEW);
3268 					DiaDimItem(dia, DTLA_USECUR);
3269 				} else
3270 				{
3271 					DiaUnDimItem(dia, DTLA_USENEW);
3272 					DiaUnDimItem(dia, DTLA_USECUR);
3273 				}
3274 			}
3275 			itemHit = DiaNextHit(dia);
3276 			if (itemHit == OK) break;
3277 			if (itemHit == DTLA_TECHLIST) recompute = 1;
3278 			if (itemHit == DTLA_USENEW)
3279 			{
3280 				/* use new unit */
3281 				if (tech != NOTECHNOLOGY)
3282 				{
3283 					for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3284 					{
3285 						if ((olib->userbits&HIDDENLIBRARY) != 0) continue;
3286 						if (((NODEPROTO **)olib->temp1)[tech->techindex] == NONODEPROTO) continue;
3287 						((NODEPROTO **)olib->temp1)[tech->techindex] = 0;
3288 					}
3289 				}
3290 				recompute = 1;
3291 				continue;
3292 			}
3293 			if (itemHit == DTLA_USENEWALWAYS)
3294 			{
3295 				/* use new unit always */
3296 				for(otech = el_technologies; otech != NOTECHNOLOGY; otech = otech->nexttechnology)
3297 				{
3298 					for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3299 					{
3300 						if ((olib->userbits&HIDDENLIBRARY) != 0) continue;
3301 						if (((NODEPROTO **)olib->temp1)[otech->techindex] == NONODEPROTO) continue;
3302 						((NODEPROTO **)olib->temp1)[otech->techindex] = 0;
3303 					}
3304 				}
3305 				recompute = 1;
3306 				DiaDimItem(dia, DTLA_USECURALWAYS);
3307 				DiaDimItem(dia, DTLA_USENEWALWAYS);
3308 				continue;
3309 			}
3310 			if (itemHit == DTLA_USECURALWAYS)
3311 			{
3312 				/* use current unit always */
3313 				for(otech = el_technologies; otech != NOTECHNOLOGY; otech = otech->nexttechnology)
3314 					((NODEPROTO **)lib->temp1)[otech->techindex] = 0;
3315 				recompute = 1;
3316 				DiaDimItem(dia, DTLA_USECURALWAYS);
3317 				DiaDimItem(dia, DTLA_USENEWALWAYS);
3318 				continue;
3319 			}
3320 			if (itemHit == DTLA_USECUR)
3321 			{
3322 				/* use current unit */
3323 				if (tech != NOTECHNOLOGY) ((NODEPROTO **)lib->temp1)[tech->techindex] = 0;
3324 				recompute = 1;
3325 				continue;
3326 			}
3327 		}
3328 		DiaDoneDialog(dia);
3329 	}
3330 
3331 	/* do automatic conversions */
3332 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
3333 	{
3334 		if (tech == art_tech) continue;
3335 		if (((NODEPROTO **)lib->temp1)[tech->techindex] == NONODEPROTO)
3336 			((NODEPROTO **)lib->temp1)[tech->techindex] = 0;
3337 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3338 		{
3339 			if (((NODEPROTO **)olib->temp1)[tech->techindex] == NONODEPROTO)
3340 				((NODEPROTO **)olib->temp1)[tech->techindex] = 0;
3341 		}
3342 	}
3343 
3344 	/* adjust lambda values in old libraries to match this one */
3345 	techarray = (TECHNOLOGY **)emalloc(el_maxtech * (sizeof (TECHNOLOGY *)), el_tempcluster);
3346 	if (techarray == 0) return;
3347 	newlamarray = (INTBIG *)emalloc(el_maxtech * SIZEOFINTBIG, el_tempcluster);
3348 	if (newlamarray == 0) return;
3349 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3350 	{
3351 		if (olib == lib) continue;
3352 
3353 		/* see how many technologies are affected */
3354 		count = 0;
3355 		for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
3356 		{
3357 			if (((NODEPROTO **)olib->temp1)[tech->techindex] != 0) continue;
3358 			if (lib->lambda[tech->techindex] == olib->lambda[tech->techindex]) continue;
3359 			techarray[count] = tech;
3360 			newlamarray[count] = lib->lambda[tech->techindex];
3361 			count++;
3362 		}
3363 		if (count == 0) continue;
3364 
3365 		/* adjust this library */
3366 		oldbits = olib->userbits;
3367 		changelambda(count, techarray, newlamarray, olib, 1);
3368 		olib->userbits = (olib->userbits & ~LIBCHANGEDMAJOR) |
3369 			(oldbits & LIBCHANGEDMAJOR);
3370 	}
3371 
3372 	/* change lambda values in this library to match old ones */
3373 	count = 0;
3374 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
3375 	{
3376 		if (((NODEPROTO **)lib->temp1)[tech->techindex] != 0) continue;
3377 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3378 		{
3379 			if ((olib->userbits&HIDDENLIBRARY) != 0) continue;
3380 			if (olib->lambda[tech->techindex] == lib->lambda[tech->techindex]) continue;
3381 			if (((NODEPROTO **)olib->temp1)[tech->techindex] != 0) break;
3382 		}
3383 		if (olib == NOLIBRARY) continue;
3384 		techarray[count] = tech;
3385 		newlamarray[count] = olib->lambda[tech->techindex];
3386 		count++;
3387 	}
3388 	if (count != 0)
3389 	{
3390 		/* adjust new library */
3391 		changelambda(count, techarray, newlamarray, lib, 1);
3392 	}
3393 
3394 	/* free memory used here */
3395 	efree((CHAR *)techarray);
3396 	efree((CHAR *)newlamarray);
3397 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3398 		efree((CHAR *)olib->temp1);
3399 }
3400 
3401 /****************************** LIBRARY OPTIONS DIALOG ******************************/
3402 
3403 /* Library: Options */
3404 static DIALOGITEM io_liboptdialogitems[] =
3405 {
3406  /*  1 */ {0, {124,148,148,228}, BUTTON, N_("OK")},
3407  /*  2 */ {0, {124,16,148,96}, BUTTON, N_("Cancel")},
3408  /*  3 */ {0, {8,8,24,236}, RADIO, N_("No backup of library files")},
3409  /*  4 */ {0, {32,8,48,236}, RADIO, N_("Backup of last library file")},
3410  /*  5 */ {0, {56,8,72,236}, RADIO, N_("Backup history of library files")},
3411  /*  6 */ {0, {92,8,108,236}, CHECK, N_("Check database after write")}
3412 };
3413 static DIALOG io_liboptdialog = {{75,75,232,321}, N_("Library Options"), 0, 6, io_liboptdialogitems, 0, 0};
3414 
3415 /* special items for the "library options" dialog: */
3416 #define DLBO_NOBACKUP         3		/* no backup (radio) */
3417 #define DLBO_ONEBACKUP        4		/* backup one level (radio) */
3418 #define DLBO_FULLBACKUP       5		/* backup history (radio) */
3419 #define DLBO_CHECKAFTERWRITE  6		/* check after write (check) */
3420 
io_libraryoptiondlog(void)3421 void io_libraryoptiondlog(void)
3422 {
3423 	INTBIG itemHit, i, *origstate, curstate[NUMIOSTATEBITWORDS];
3424 	REGISTER void *dia;
3425 
3426 	/* display the library paths dialog box */
3427 	dia = DiaInitDialog(&io_liboptdialog);
3428 	if (dia == 0) return;
3429 
3430 	/* get current state of I/O tool */
3431 	origstate = io_getstatebits();
3432 	for(i=0; i<NUMIOSTATEBITWORDS; i++) curstate[i] = origstate[i];
3433 	switch (curstate[0]&BINOUTBACKUP)
3434 	{
3435 		case BINOUTNOBACK:   DiaSetControl(dia, DLBO_NOBACKUP, 1);    break;
3436 		case BINOUTONEBACK:  DiaSetControl(dia, DLBO_ONEBACKUP, 1);   break;
3437 		case BINOUTFULLBACK: DiaSetControl(dia, DLBO_FULLBACKUP, 1);  break;
3438 	}
3439 	if ((curstate[0]&CHECKATWRITE) != 0) DiaSetControl(dia, DLBO_CHECKAFTERWRITE, 1);
3440 
3441 	/* loop until done */
3442 	for(;;)
3443 	{
3444 		itemHit = DiaNextHit(dia);
3445 		if (itemHit == OK || itemHit == CANCEL) break;
3446 		if (itemHit == DLBO_NOBACKUP || itemHit == DLBO_ONEBACKUP ||
3447 			itemHit == DLBO_FULLBACKUP)
3448 		{
3449 			DiaSetControl(dia, DLBO_NOBACKUP, 0);
3450 			DiaSetControl(dia, DLBO_ONEBACKUP, 0);
3451 			DiaSetControl(dia, DLBO_FULLBACKUP, 0);
3452 			DiaSetControl(dia, itemHit, 1);
3453 			continue;
3454 		}
3455 		if (itemHit == DLBO_CHECKAFTERWRITE)
3456 		{
3457 			DiaSetControl(dia, itemHit, 1 - DiaGetControl(dia, itemHit));
3458 			continue;
3459 		}
3460 	}
3461 
3462 	if (itemHit != CANCEL)
3463 	{
3464 		curstate[0] &= ~(BINOUTBACKUP|CHECKATWRITE);
3465 		if (DiaGetControl(dia, DLBO_ONEBACKUP) != 0) curstate[0] |= BINOUTONEBACK; else
3466 			if (DiaGetControl(dia, DLBO_FULLBACKUP) != 0) curstate[0] |= BINOUTFULLBACK;
3467 		if (DiaGetControl(dia, DLBO_CHECKAFTERWRITE) != 0) curstate[0] |= CHECKATWRITE;
3468 		for(i=0; i<NUMIOSTATEBITWORDS; i++)
3469 			if (curstate[i] != origstate[i]) break;
3470 		if (i < NUMIOSTATEBITWORDS)
3471 			io_setstatebits(curstate);
3472 	}
3473 	DiaDoneDialog(dia);
3474 }
3475 
3476 /* CDL Options */
3477 static DIALOGITEM io_cdloptdialogitems[] =
3478 {
3479  /*  1 */ {0, {100,236,124,316}, BUTTON, N_("OK")},
3480  /*  2 */ {0, {100,64,124,144}, BUTTON, N_("Cancel")},
3481  /*  3 */ {0, {8,8,24,184}, MESSAGE, N_("Cadence Library Name:")},
3482  /*  4 */ {0, {8,187,24,363}, EDITTEXT, x_("")},
3483  /*  5 */ {0, {32,8,48,184}, MESSAGE, N_("Cadence Library Path:")},
3484  /*  6 */ {0, {32,187,64,363}, EDITTEXT, x_("")},
3485  /*  7 */ {0, {72,8,88,176}, CHECK, N_("Convert brackets")}
3486 };
3487 static DIALOG io_cdloptdialog = {{75,75,208,447}, N_("CDL Options"), 0, 7, io_cdloptdialogitems, 0, 0};
3488 
3489 /* special items for the "CDL Options" dialog: */
3490 #define DCDL_LIBNAME     4		/* Cadence Library Name (edit text) */
3491 #define DCDL_LIBPATH     6		/* Cadence Library Path (edit text) */
3492 #define DCDL_CONVBRACKET 7		/* Convert brackets (check) */
3493 
3494 /*
3495  * Routine to run the CDL Options dialog.
3496  */
io_cdloptionsdialog(void)3497 void io_cdloptionsdialog(void)
3498 {
3499 	INTBIG i, itemHit, *curstate, newstate[NUMIOSTATEBITWORDS];
3500 	REGISTER VARIABLE *var;
3501 	REGISTER CHAR *inilibname, *inilibpath;
3502 	BOOLEAN libnamechanged, libpathchanged;
3503 	REGISTER void *dia;
3504 
3505 	dia = DiaInitDialog(&io_cdloptdialog);
3506 	if (dia == 0) return;
3507 	var = getval((INTBIG)io_tool, VTOOL, VSTRING, x_("IO_cdl_library_name"));
3508 	if (var == NOVARIABLE) inilibname = x_(""); else
3509 		inilibname = (CHAR *)var->addr;
3510 	DiaSetText(dia, DCDL_LIBNAME, inilibname);
3511 	var = getval((INTBIG)io_tool, VTOOL, VSTRING, x_("IO_cdl_library_path"));
3512 	if (var == NOVARIABLE) inilibpath = x_(""); else
3513 		inilibpath = (CHAR *)var->addr;
3514 	DiaSetText(dia, DCDL_LIBPATH, inilibpath);
3515 	curstate = io_getstatebits();
3516 	if ((curstate[1]&CDLNOBRACKETS) != 0) DiaSetControl(dia, DCDL_CONVBRACKET, 1);
3517 
3518 	libnamechanged = libpathchanged = FALSE;
3519 	for(;;)
3520 	{
3521 		itemHit = DiaNextHit(dia);
3522 		if (itemHit == OK || itemHit == CANCEL) break;
3523 		if (itemHit == DCDL_CONVBRACKET)
3524 		{
3525 			DiaSetControl(dia, itemHit, 1 - DiaGetControl(dia, itemHit));
3526 			continue;
3527 		}
3528 		if (itemHit == DCDL_LIBNAME)
3529 		{
3530 			if (estrcmp(inilibname, DiaGetText(dia, DCDL_LIBNAME)) != 0)
3531 				libnamechanged = TRUE;
3532 			continue;
3533 		}
3534 		if (itemHit == DCDL_LIBPATH)
3535 		{
3536 			if (estrcmp(inilibpath, DiaGetText(dia, DCDL_LIBPATH)) != 0)
3537 				libpathchanged = TRUE;
3538 			continue;
3539 		}
3540 	}
3541 	if (itemHit == OK)
3542 	{
3543 		if (libnamechanged != 0)
3544 		{
3545 			(void)setval((INTBIG)io_tool, VTOOL, x_("IO_cdl_library_name"),
3546 				(INTBIG)DiaGetText(dia, DCDL_LIBNAME), VSTRING);
3547 		}
3548 		if (libpathchanged != 0)
3549 		{
3550 			(void)setval((INTBIG)io_tool, VTOOL, x_("IO_cdl_library_path"),
3551 				(INTBIG)DiaGetText(dia, DCDL_LIBPATH), VSTRING);
3552 		}
3553 		for(i=0; i<NUMIOSTATEBITWORDS; i++) newstate[i] = curstate[i];
3554 		if (DiaGetControl(dia, DCDL_CONVBRACKET) != 0) newstate[1] |= CDLNOBRACKETS; else
3555 			newstate[1] &= ~CDLNOBRACKETS;
3556 		for(i=0; i<NUMIOSTATEBITWORDS; i++) if (curstate[i] != newstate[i]) break;
3557 		if (i < NUMIOSTATEBITWORDS) io_setstatebits(newstate);
3558 	}
3559 	DiaDoneDialog(dia);
3560 }
3561 
3562 /* Sue Options */
3563 static DIALOGITEM io_sueoptdialogitems[] =
3564 {
3565  /*  1 */ {0, {36,120,60,192}, BUTTON, N_("OK")},
3566  /*  2 */ {0, {36,16,60,88}, BUTTON, N_("Cancel")},
3567  /*  3 */ {0, {8,8,24,200}, CHECK, N_("Make 4-port transistors")}
3568 };
3569 static DIALOG io_sueoptdialog = {{50,75,119,285}, N_("SUE Options"), 0, 3, io_sueoptdialogitems, 0, 0};
3570 
3571 /* special items for the "Sue Options" dialog: */
3572 #define DSUE_USE4PORTS  3		/* Use 4-port transistors (check) */
3573 
3574 /*
3575  * Routine to run the Sue Options dialog.
3576  */
io_sueoptionsdialog(void)3577 void io_sueoptionsdialog(void)
3578 {
3579 	INTBIG i, itemHit, *curstate, newstate[NUMIOSTATEBITWORDS];
3580 	REGISTER void *dia;
3581 
3582 	dia = DiaInitDialog(&io_sueoptdialog);
3583 	if (dia == 0) return;
3584 	curstate = io_getstatebits();
3585 	if ((curstate[1]&SUEUSE4PORTTRANS) != 0) DiaSetControl(dia, DSUE_USE4PORTS, 1);
3586 
3587 	for(;;)
3588 	{
3589 		itemHit = DiaNextHit(dia);
3590 		if (itemHit == OK || itemHit == CANCEL) break;
3591 		if (itemHit == DSUE_USE4PORTS)
3592 		{
3593 			DiaSetControl(dia, itemHit, 1 - DiaGetControl(dia, itemHit));
3594 			continue;
3595 		}
3596 	}
3597 	if (itemHit == OK)
3598 	{
3599 		for(i=0; i<NUMIOSTATEBITWORDS; i++) newstate[i] = curstate[i];
3600 		if (DiaGetControl(dia, DSUE_USE4PORTS) != 0) newstate[1] |= SUEUSE4PORTTRANS; else
3601 			newstate[1] &= ~SUEUSE4PORTTRANS;
3602 		for(i=0; i<NUMIOSTATEBITWORDS; i++) if (curstate[i] != newstate[i]) break;
3603 		if (i < NUMIOSTATEBITWORDS) io_setstatebits(newstate);
3604 	}
3605 	DiaDoneDialog(dia);
3606 }
3607 
3608 #define VARTYPELAYTOLAY    0		/* this variable is a layer-to-layer list */
3609 #define VARTYPELAYER       1		/* this variable is a layer list */
3610 #define VARTYPELAYERNONDRC 2		/* this variable is a layer list, not related to DRC */
3611 #define VARTYPENODE        3		/* this variable is a node list */
3612 #define VARTYPENODE2       4		/* this variable has 2 entries per node */
3613 
3614 static struct
3615 {
3616 	CHAR   *variable;
3617 	CHAR   *meaning;
3618 	INTBIG  variabletype;
3619 	INTBIG  key;
3620 	INTBIG  defaultint;
3621 	CHAR   *defaultstring;
3622 	float   defaultfloat;
3623 } io_techlayervariables[] =
3624 {
3625 	{x_("IO_cif_layer_names"),                      N_("CIF Layer Names"),                          VARTYPELAYERNONDRC,0,  0,     x_(""), 0.0},
3626 	{x_("IO_dxf_layer_names"),                      N_("DXF Layer Names"),                          VARTYPELAYERNONDRC,0,  0,     x_(""), 0.0},
3627 	{x_("IO_gds_layer_numbers"),                    N_("GDS Layer Numbers"),                        VARTYPELAYERNONDRC,0, -1,     x_(""), 0.0},
3628 	{x_("IO_skill_layer_names"),                    N_("SKILL Layer Names"),                        VARTYPELAYERNONDRC,0,  0,     x_(""), 0.0},
3629 	{x_("SIM_spice_resistance"),                    N_("SPICE Layer Resistances"),                  VARTYPELAYERNONDRC,0,  0,     x_(""), 0.0},
3630 	{x_("SIM_spice_capacitance"),                   N_("SPICE Layer Capacitances"),                 VARTYPELAYERNONDRC,0,  0,     x_(""), 0.0},
3631 	{x_("DRC_min_connected_distances"),             N_("Normal Connected Design Rule spacings"),    VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3632 	{x_("DRC_min_connected_distances_rule"),        N_("Normal Connected Design Rule"),             VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3633 	{x_("DRC_min_unconnected_distances"),           N_("Normal Unconnected Design Rule spacings"),  VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3634 	{x_("DRC_min_unconnected_distances_rule"),      N_("Normal Unconnected Design Rule"),           VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3635 	{x_("DRC_min_connected_distances_wide"),        N_("Wide Connected Design Rule spacings"),      VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3636 	{x_("DRC_min_connected_distances_wide_rule"),   N_("Wide Connected Design Rule"),               VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3637 	{x_("DRC_min_unconnected_distances_wide"),      N_("Wide Unconnected Design Rule spacings"),    VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3638 	{x_("DRC_min_unconnected_distances_wide_rule"), N_("Wide Unconnected Design Rule"),             VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3639 	{x_("DRC_min_connected_distances_multi"),       N_("Multicut Connected Design Rule spacings"),  VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3640 	{x_("DRC_min_connected_distances_multi_rule"),  N_("Multicut Connected Design Rule"),           VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3641 	{x_("DRC_min_unconnected_distances_wide"),      N_("Wide Unconnected Design Rule spacings"),    VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3642 	{x_("DRC_min_unconnected_distances_wide_rule"), N_("Wide Unconnected Design Rule"),             VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3643 	{x_("DRC_min_unconnected_distances_multi"),     N_("Multicut Unconnected Design Rule spacings"),VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3644 	{x_("DRC_min_edge_distances"),                  N_("Edge Design Rule spacings"),                VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3645 	{x_("DRC_min_edge_distances_rule"),             N_("Edge Design Rules"),                        VARTYPELAYTOLAY,   0, -WHOLE, x_(""), 0.0},
3646 	{x_("DRC_min_width"),			                N_("Minimum Layer Widths"),                     VARTYPELAYER,      0, -WHOLE, x_(""), 0.0},
3647 	{x_("DRC_min_width_rule"),			            N_("Minimum Layer Width Rules"),                VARTYPELAYER,      0,  0,     x_(""), 0.0},
3648 	{x_("DRC_min_node_size"),			            N_("Minimum Node Sizes"),                       VARTYPENODE2,      0, -WHOLE, x_(""), 0.0},
3649 	{x_("DRC_min_node_size_rule"),			        N_("Minimum Node Size Rules"),                  VARTYPENODE,       0,  0,     x_(""), 0.0},
3650 	{0, 0, FALSE, 0, 0, x_(""), 0.0}
3651 };
3652 
3653 /*
3654  * this table rearranges the MOSIS CMOS Submicron layer tables from
3655  * their old 4-layer metal (34 layers) to 6-layer metal (40 layers)
3656  */
3657 static INTBIG tech_mocmossubarrange[] =
3658 {
3659 	 0,  1,  2,  3,  6,  7,  8,  9, 10, 11,
3660 	12, 13, 14, 15, 16, 17, 18, 21, 22, 23,
3661 	24, 25, 26, 27, 28, 31, 32, 33, 34, 35,
3662 	36, 37, 38, 39
3663 };
3664 
3665 static struct
3666 {
3667 	CHAR *techname;
3668 	INTBIG oldlayercount, newlayercount;
3669 	INTBIG *arrangement;
3670 } io_techlayerfixes[] =
3671 {
3672 	{x_("mocmossub"), 34, 40, tech_mocmossubarrange},
3673 	{x_("mocmos"),    34, 40, tech_mocmossubarrange},
3674 	{0, 0, 0, 0}
3675 };
3676 
io_fixtechlayers(LIBRARY * lib)3677 void io_fixtechlayers(LIBRARY *lib)
3678 {
3679 	REGISTER INTBIG i, j, k, l, l1, l2, oldpos, newpos, newl1, newl2, *newints;
3680 	REGISTER float *newfloats;
3681 	REGISTER BOOLEAN factorywarned;
3682 	REGISTER CHAR **newstrings;
3683 	REGISTER TECHNOLOGY *tech;
3684 	REGISTER VARIABLE *var;
3685 
3686 	factorywarned = FALSE;
3687 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
3688 	{
3689 		for(i=0; io_techlayervariables[i].variable != 0; i++)
3690 		{
3691 			if (io_techlayervariables[i].key == 0)
3692 				io_techlayervariables[i].key = makekey(io_techlayervariables[i].variable);
3693 			var = getvalkey((INTBIG)tech, VTECHNOLOGY, -1, io_techlayervariables[i].key);
3694 			if (var == NOVARIABLE) continue;
3695 			switch (io_techlayervariables[i].variabletype)
3696 			{
3697 				case VARTYPELAYTOLAY:
3698 					/* this variable should have one per layer-to-layer combination in the technology */
3699 					l = tech->layercount;
3700 					if (getlength(var) == (l * l + l) / 2) continue;
3701 					break;
3702 				case VARTYPELAYER:
3703 				case VARTYPELAYERNONDRC:
3704 					/* this variable should have one per layer in the technology */
3705 					if (getlength(var) == tech->layercount) continue;
3706 					break;
3707 				case VARTYPENODE:
3708 					/* this variable should have one per node in the technology */
3709 					if (getlength(var) == tech->nodeprotocount) continue;
3710 					break;
3711 				case VARTYPENODE2:
3712 					/* this variable should have two per node in the technology */
3713 					if (getlength(var) == tech->nodeprotocount*2) continue;
3714 					break;
3715 			}
3716 
3717 			/* layers are inconsistent: see if there are rules to fix it */
3718 			for(j=0; io_techlayerfixes[j].techname != 0; j++)
3719 			{
3720 				if (namesame(tech->techname, io_techlayerfixes[j].techname) != 0) continue;
3721 				switch (io_techlayervariables[i].variabletype)
3722 				{
3723 					case VARTYPELAYTOLAY:
3724 						l = io_techlayerfixes[j].oldlayercount;
3725 						if ((l*l+l)/2 != getlength(var)) continue;
3726 						break;
3727 					case VARTYPELAYER:
3728 					case VARTYPELAYERNONDRC:
3729 						if (io_techlayerfixes[j].oldlayercount != getlength(var)) continue;
3730 						break;
3731 					default:
3732 						continue;
3733 				}
3734 				if (io_techlayerfixes[j].newlayercount != tech->layercount) continue;
3735 				break;
3736 			}
3737 			if (io_techlayerfixes[j].techname != 0)
3738 			{
3739 				if (io_techlayervariables[i].variabletype == VARTYPELAYTOLAY)
3740 				{
3741 					k = tech->layercount;
3742 					l = (k * k + k)/2;
3743 					newints = (INTBIG *)emalloc(l * SIZEOFINTBIG, tech->cluster);
3744 					for(k=0; k<l; k++)
3745 						newints[k] = io_techlayervariables[i].defaultint;
3746 					for(l1=0; l1<io_techlayerfixes[j].oldlayercount; l1++)
3747 					{
3748 						for(l2=l1; l2<io_techlayerfixes[j].oldlayercount; l2++)
3749 						{
3750 							oldpos = (l1+1) * (l1/2) + (l1&1) * ((l1+1)/2);
3751 							oldpos = l2 + io_techlayerfixes[j].oldlayercount * l1 - oldpos;
3752 							newl1 = io_techlayerfixes[j].arrangement[l1];
3753 							newl2 = io_techlayerfixes[j].arrangement[l2];
3754 							newpos = (newl1+1) * (newl1/2) + (newl1&1) * ((newl1+1)/2);
3755 							newpos = newl2 + tech->layercount * newl1 - newpos;
3756 							newints[newpos] = ((INTBIG *)var->addr)[oldpos];
3757 						}
3758 					}
3759 					(void)setvalkey((INTBIG)tech, VTECHNOLOGY, io_techlayervariables[i].key,
3760 						(INTBIG)newints, (var->type&VTYPE)|VISARRAY|(l<<VLENGTHSH));
3761 					efree((CHAR *)newints);
3762 				} else
3763 				{
3764 					/* able to fix the ordering */
3765 					if ((var->type&VTYPE) == VSTRING)
3766 					{
3767 						newstrings = (CHAR **)emalloc(tech->layercount * (sizeof (CHAR *)),
3768 							tech->cluster);
3769 						for(k=0; k<tech->layercount; k++)
3770 							newstrings[k] = io_techlayervariables[i].defaultstring;
3771 						for(k=0; k<getlength(var); k++)
3772 							newstrings[io_techlayerfixes[j].arrangement[k]] =
3773 								((CHAR **)var->addr)[k];
3774 						(void)setvalkey((INTBIG)tech, VTECHNOLOGY, io_techlayervariables[i].key,
3775 							(INTBIG)newstrings, (var->type&VTYPE)|VISARRAY|(tech->layercount<<VLENGTHSH));
3776 						efree((CHAR *)newstrings);
3777 					} else if ((var->type&VTYPE) == VFLOAT)
3778 					{
3779 						newfloats = (float *)emalloc(tech->layercount * (sizeof (float)),
3780 							tech->cluster);
3781 						for(k=0; k<tech->layercount; k++)
3782 							newfloats[k] = io_techlayervariables[i].defaultfloat;
3783 						for(k=0; k<getlength(var); k++)
3784 							newfloats[io_techlayerfixes[j].arrangement[k]] =
3785 								((float *)var->addr)[k];
3786 						(void)setvalkey((INTBIG)tech, VTECHNOLOGY, io_techlayervariables[i].key,
3787 							(INTBIG)newfloats, (var->type&VTYPE)|VISARRAY|(tech->layercount<<VLENGTHSH));
3788 						efree((CHAR *)newfloats);
3789 					} else
3790 					{
3791 						newints = (INTBIG *)emalloc(tech->layercount * SIZEOFINTBIG,
3792 							tech->cluster);
3793 						for(k=0; k<tech->layercount; k++)
3794 							newints[k] = io_techlayervariables[i].defaultint;
3795 						for(k=0; k<getlength(var); k++)
3796 							newints[io_techlayerfixes[j].arrangement[k]] =
3797 								((INTBIG *)var->addr)[k];
3798 						(void)setvalkey((INTBIG)tech, VTECHNOLOGY, io_techlayervariables[i].key,
3799 							(INTBIG)newints, (var->type&VTYPE)|VISARRAY|(tech->layercount<<VLENGTHSH));
3800 						efree((CHAR *)newints);
3801 					}
3802 				}
3803 				continue;
3804 			}
3805 
3806 			/* unable to fix: issue a warning */
3807 			ttyputmsg(_("Warning: library %s has %s in technology %s which are inconsistent"),
3808 				lib->libname, TRANSLATE(io_techlayervariables[i].meaning), tech->techname);
3809 			if (io_techlayervariables[i].variabletype != VARTYPELAYERNONDRC)
3810 			{
3811 				if (!factorywarned)
3812 				{
3813 					factorywarned = TRUE;
3814 					ttyputmsg(_("Should do a 'Factory Reset' of design rules in 'DRC Rules' dialog"));
3815 				}
3816 			}
3817 		}
3818 	}
3819 }
3820 
io_fixrtree(RTNODE * rtree)3821 void io_fixrtree(RTNODE *rtree)
3822 {
3823 	REGISTER INTBIG i;
3824 	REGISTER GEOM *geom;
3825 	REGISTER RTNODE *subrt;
3826 
3827 	if (rtree->total <= 0) return;
3828 	if (rtree->flag != 0)
3829 	{
3830 		geom = (GEOM *)rtree->pointers[0];
3831 		rtree->lowx = geom->lowx;   rtree->highx = geom->highx;
3832 		rtree->lowy = geom->lowy;   rtree->highy = geom->highy;
3833 		for(i=1; i<rtree->total; i++)
3834 		{
3835 			geom = (GEOM *)rtree->pointers[i];
3836 			if (geom->lowx < rtree->lowx) rtree->lowx = geom->lowx;
3837 			if (geom->highx > rtree->highx) rtree->highx = geom->highx;
3838 			if (geom->lowy < rtree->lowy) rtree->lowy = geom->lowy;
3839 			if (geom->highy > rtree->highy) rtree->highy = geom->highy;
3840 		}
3841 	} else
3842 	{
3843 		subrt = (RTNODE *)rtree->pointers[0];
3844 		io_fixrtree(subrt);
3845 		rtree->lowx = subrt->lowx;   rtree->highx = subrt->highx;
3846 		rtree->lowy = subrt->lowy;   rtree->highy = subrt->highy;
3847 		for(i=1; i<rtree->total; i++)
3848 		{
3849 			subrt = (RTNODE *)rtree->pointers[i];
3850 			io_fixrtree(subrt);
3851 			if (subrt->lowx < rtree->lowx) rtree->lowx = subrt->lowx;
3852 			if (subrt->highx > rtree->highx) rtree->highx = subrt->highx;
3853 			if (subrt->lowy < rtree->lowy) rtree->lowy = subrt->lowy;
3854 			if (subrt->highy > rtree->highy) rtree->highy = subrt->highy;
3855 		}
3856 	}
3857 }
3858 
3859 /*
3860  * routine to convert port names that have changed (specifically those
3861  * in the Schematics technology).  Given the port name on a node proto,
3862  * returns the correct port (or NOPORTPROTO if not known).
3863  */
io_convertoldportname(CHAR * portname,NODEPROTO * np)3864 PORTPROTO *io_convertoldportname(CHAR *portname, NODEPROTO *np)
3865 {
3866 	REGISTER PORTPROTO *pp;
3867 	REGISTER INTBIG len;
3868 	CHAR truename[300];
3869 
3870 	if (np->primindex == 0) return(NOPORTPROTO);
3871 	if (np == sch_sourceprim || np == sch_meterprim)
3872 	{
3873 		if (namesame(portname, x_("top")) == 0)
3874 			return(np->firstportproto);
3875 		if (namesame(portname, x_("bottom")) == 0)
3876 			return(np->firstportproto->nextportproto);
3877 	}
3878 	if (np == sch_twoportprim)
3879 	{
3880 		if (namesame(portname, x_("upperleft")) == 0)
3881 			return(np->firstportproto);
3882 		if (namesame(portname, x_("lowerleft")) == 0)
3883 			return(np->firstportproto->nextportproto);
3884 		if (namesame(portname, x_("upperright")) == 0)
3885 			return(np->firstportproto->nextportproto->nextportproto);
3886 		if (namesame(portname, x_("lowerright")) == 0)
3887 			return(np->firstportproto->nextportproto->nextportproto->nextportproto);
3888 	}
3889 
3890 	/* some technologies switched from ports ending in "-bot" to the ending "-bottom" */
3891 	len = estrlen(portname) - 4;
3892 	if (len > 0 && namesame(&portname[len], x_("-bot")) == 0)
3893 	{
3894 		estrcpy(truename, portname);
3895 		estrcat(truename, x_("tom"));
3896 		pp = getportproto(np, truename);
3897 		if (pp != NOPORTPROTO) return(pp);
3898 	}
3899 	return(NOPORTPROTO);
3900 }
3901 
3902 /*
3903  * Routine to determine the area of cell "np" that is to be printed.
3904  * Returns true if the area cannot be determined.
3905  */
io_getareatoprint(NODEPROTO * np,INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy,BOOLEAN reduce)3906 BOOLEAN io_getareatoprint(NODEPROTO *np, INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy, BOOLEAN reduce)
3907 {
3908 	REGISTER INTBIG wid, hei, *curstate;
3909 	INTBIG hlx, hhx, hly, hhy;
3910 	REGISTER NODEPROTO *onp;
3911 
3912 	curstate = io_getstatebits();
3913 	us_fullview(np, lx, hx, ly, hy);
3914 
3915 	/* extend it and make it square */
3916 	wid = *hx - *lx;
3917 	hei = *hy - *ly;
3918 	if (reduce)
3919 	{
3920 		*lx -= wid/8;   *hx += wid/8;
3921 		*ly -= hei/8;   *hy += hei/8;
3922 		us_squarescreen(el_curwindowpart, NOWINDOWPART, FALSE, lx, hx, ly, hy, 0);
3923 	}
3924 
3925 	if ((curstate[0]&PLOTFOCUS) != 0)
3926 	{
3927 		if ((curstate[0]&PLOTFOCUSDPY) != 0)
3928 		{
3929 			*lx = el_curwindowpart->screenlx;
3930 			*hx = el_curwindowpart->screenhx;
3931 			*ly = el_curwindowpart->screenly;
3932 			*hy = el_curwindowpart->screenhy;
3933 		} else
3934 		{
3935 			onp = (NODEPROTO *)asktool(us_tool, x_("get-highlighted-area"),
3936 				(INTBIG)&hlx, (INTBIG)&hhx, (INTBIG)&hly, (INTBIG)&hhy);
3937 			if (onp == NONODEPROTO)
3938 				ttyputerr(_("Warning: no highlighted area; printing entire cell")); else
3939 			{
3940 				if (hhx == hlx || hhy == hly)
3941 				{
3942 					ttyputerr(_("Warning: no highlighted area; highlight area and reissue command"));
3943 					return(TRUE);
3944 				}
3945 				*lx = hlx;   *hx = hhx;
3946 				*ly = hly;   *hy = hhy;
3947 			}
3948 		}
3949 	}
3950 	return(FALSE);
3951 }
3952 
3953 /******************** LAYER ORDERING FOR GRAPHIC COPY/PRINT ********************/
3954 
io_setuptechorder(TECHNOLOGY * tech)3955 INTBIG io_setuptechorder(TECHNOLOGY *tech)
3956 {
3957 	REGISTER INTBIG i, j, k, l, m, *neworder, newamount;
3958 	REGISTER INTBIG *layers;
3959 	INTBIG order[LFNUMLAYERS];
3960 	REGISTER VARIABLE *var;
3961 
3962 	/* determine order of overlappable layers in current technology */
3963 	io_maxlayers = 0;
3964 	i = tech->layercount;
3965 	var = getval((INTBIG)tech, VTECHNOLOGY, VINTEGER|VISARRAY,
3966 		x_("TECH_layer_function"));
3967 	if (var != NOVARIABLE)
3968 	{
3969 		layers = (INTBIG *)var->addr;
3970 		for(j=0; j<LFNUMLAYERS; j++)
3971 			order[j] = layerfunctionheight(j);
3972 		for(j=0; j<LFNUMLAYERS; j++)
3973 		{
3974 			for(k=0; k<LFNUMLAYERS; k++)
3975 			{
3976 				if (order[k] != j) continue;
3977 				for(l=0; l<i; l++)
3978 				{
3979 					if ((layers[l]&LFTYPE) != k) continue;
3980 					if (io_maxlayers >= io_mostlayers)
3981 					{
3982 						newamount = io_mostlayers * 2;
3983 						if (newamount <= 0) newamount = 10;
3984 						if (newamount < io_maxlayers) newamount = io_maxlayers;
3985 						neworder = (INTBIG *)emalloc(newamount * SIZEOFINTBIG, io_tool->cluster);
3986 						if (neworder == 0) return(io_maxlayers);
3987 						for(m=0; m<io_maxlayers; m++)
3988 							neworder[m] = io_overlaporder[m];
3989 						if (io_mostlayers > 0) efree((CHAR *)io_overlaporder);
3990 						io_overlaporder = neworder;
3991 						io_mostlayers = newamount;
3992 					}
3993 					io_overlaporder[io_maxlayers++] = l;
3994 				}
3995 				break;
3996 			}
3997 		}
3998 	}
3999 	return(io_maxlayers);
4000 }
4001 
4002 /*
4003  * Routine to return the layer in plotting position "i" (from 0 to the value returned
4004  * by "io_setuptechorder" - 1).
4005  */
io_nextplotlayer(INTBIG i)4006 INTBIG io_nextplotlayer(INTBIG i)
4007 {
4008 	return(io_overlaporder[i]);
4009 }
4010 
4011 /******************** MATH HELPERS ********************/
4012 
4013 /*
4014  * This routine is used by "ioedifo.c" and "routmaze.c".
4015  */
io_compute_center(INTBIG xc,INTBIG yc,INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2,INTBIG * cx,INTBIG * cy)4016 void io_compute_center(INTBIG xc, INTBIG yc, INTBIG x1, INTBIG y1,
4017 	INTBIG x2, INTBIG y2, INTBIG *cx, INTBIG *cy)
4018 {
4019 	int r, dx, dy, a1, a2, a;
4020 	double pie, theta, radius, Dx, Dy;
4021 
4022 	/* reconstruct angles to p1 and p2 */
4023 	Dx = x1 - xc;
4024 	Dy = y1 - yc;
4025 	radius = sqrt(Dx * Dx + Dy * Dy);
4026 	r = rounddouble(radius);
4027 	a1 = (int)io_calc_angle(r, (double)(x1 - xc), (double)(y1 - yc));
4028 	a2 = (int)io_calc_angle(r, (double)(x2 - xc), (double)(y2 - yc));
4029 	if (a1 < a2) a1 += 3600;
4030 	a = (a1 + a2) >> 1;
4031 	pie = acos(-1.0);
4032 	theta = (double) a *pie / 1800.0;	/* in radians */
4033 	Dx = radius * cos(theta);
4034 	Dy = radius * sin(theta);
4035 	dx = rounddouble(Dx);
4036 	dy = rounddouble(Dy);
4037 	*cx = xc + dx;
4038 	*cy = yc + dy;
4039 }
4040 
io_calc_angle(double r,double dx,double dy)4041 double io_calc_angle(double r, double dx, double dy)
4042 {
4043 	double ratio, a1, a2;
4044 
4045 	ratio = 1800.0 / EPI;
4046 	a1 = acos(dx/r) * ratio;
4047 	a2 = asin(dy/r) * ratio;
4048 	if (a2 < 0.0) return(3600.0 - a1);
4049 	return(a1);
4050 }
4051