1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: iotexti.c
6  * Input/output tool: textual format input
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "global.h"
33 #include "database.h"
34 #include "eio.h"
35 #include "tecgen.h"
36 #include "tecart.h"
37 #include "tecschem.h"
38 #include "tecmocmos.h"
39 #include "tecmocmossub.h"
40 #include "edialogs.h"
41 
42 #define REPORTRATE  100		/* number of elements between graphical update */
43 
44 #define LONGJMPNOMEM         1		/* error: No Memory */
45 #define LONGJMPMISCOLON      2		/* error: Missing colon */
46 #define LONGJMPUKNKEY        3		/* error: Unknown keyword */
47 #define LONGJMPEOF           4		/* error: EOF too soon */
48 #define LONGJMPEOFVAR        5		/* error: EOF in variables */
49 #define LONGJMPMISCOLVAR     6		/* error: Missing ':' in variable */
50 #define LONGJMPMISOSBVAR     7		/* error: Missing '[' in variable */
51 #define LONGJMPMISOSBVARARR  8		/* error: Missing '[' in variable array */
52 #define LONGJMPSHORTARR      9		/* error: Short array specification */
53 #define LONGJMPUKNNOPROTO   10		/* error: Unknown node prototype */
54 #define LONGJMPMISVIEWABR   11		/* error: Missing view abbreviation */
55 #define LONGJMPBADVIEWABR   12		/* error: View abbreviation bad */
56 #define LONGJMPINCVIEWABR   13		/* error: View abbreviation inconsistent */
57 #define LONGJMPSECCELLNAME  14		/* error: Second cell name */
58 #define LONGJMPUKNTECH      15		/* error: Unknown technology */
59 #define LONGJMPINVARCPROTO  16		/* error: Invalid arc prototype */
60 #define LONGJMPUKNPORPROTO  17		/* error: Unknown port prototype name */
61 
62 /* state of input (value of "io_txtindata.textlevel") */
63 #define INLIB       1
64 #define INCELL      2
65 #define INPORTPROTO 3
66 #define INNODEINST  4
67 #define INPOR       5
68 #define INARCINST   6
69 #define INARCEND    7
70 
71 /* state of variable reading (value of "io_txtindata.varpos") */
72 #define INVTOOL        1
73 #define INVTECHNOLOGY  2
74 #define INVLIBRARY     3
75 #define INVNODEPROTO   4
76 #define INVNODEINST    5
77 #define INVPORTARCINST 6
78 #define INVPORTEXPINST 7
79 #define INVPORTPROTO   8
80 #define INVARCINST     9
81 
82 typedef struct
83 {
84 	INTBIG      cellcount;
85 	INTBIG      textlevel;
86 	INTBIG      bitcount;
87 	INTBIG      maincell;
88 	INTBIG      curarcend;
89 	INTBIG      nodeinstcount;
90 	INTBIG      arcinstcount;
91 	INTBIG      varaddr;
92 	INTBIG      portprotocount;
93 	INTBIG      linenumber;
94 	INTBIG      curportcount;
95 	INTBIG      varpos;
96 	INTBIG      filelength;
97 	INTBIG      fileposition;
98 	INTBIG      curcellnumber;
99 	CHAR       *version;
100 	INTBIG      emajor, eminor, edetail;
101 	NODEINST   *curnodeinst;
102 	ARCINST    *curarcinst;
103 	PORTPROTO  *curportproto;
104 	NODEPROTO  *curnodeproto;
105 	CHAR       *cellnameread;
106 	LIBRARY    *curlib;
107 	TECHNOLOGY *curtech;
108 	PORTPROTO **portprotolist;		/* list of portprotos for readin */
109 	NODEPROTO **nodeprotolist;		/* list of cells for readin */
110 	ARCINST   **arclist;			/* list of arcs for readin */
111 	NODEINST  **nodelist;			/* list of nodes for readin */
112 	FILE       *textfilein;
113 	INTBIG      nodeinsterror;
114 	INTBIG      portarcinsterror;
115 	INTBIG      portexpinsterror;
116 	INTBIG      portprotoerror;
117 	INTBIG      arcinsterror;
118 	INTBIG      geomerror;
119 	INTBIG      rtnodeerror;
120 	INTBIG      libraryerror;
121 	INTBIG      convertmosiscmostechnologies;
122 } TXTINPUTDATA;
123 
124 static TXTINPUTDATA io_txtindata;			/* all data pertaining to reading a file */
125 
126 /* input string buffer */
127 static INTBIG io_maxinputline = 0;
128 static CHAR *io_keyword;
129 
130 /* prototypes for local routines */
131 static void io_newlib(void);
132 static BOOLEAN io_getkeyword(void);
133 static BOOLEAN io_grabbuffers(INTBIG);
134 static PORTPROTO *io_getport(CHAR*, NODEPROTO*);
135 static void io_null(void);
136 static void io_newlib(void);
137 static void io_versn(void);
138 static void io_libkno(void);
139 static void io_libain(void);
140 static void io_libaib(void);
141 static void io_libbit(void);
142 static void io_libusb(void);
143 static void io_libte(void);
144 static void io_libten(void);
145 static void io_lambda(void);
146 static void io_getvar(void);
147 static INTBIG io_decode(CHAR*, INTBIG);
148 static void io_libcc(void);
149 static void io_libms(void);
150 static void io_libvie(void);
151 static void io_newcel(void);
152 static void io_celnam(void);
153 static void io_celver(void);
154 static void io_celcre(void);
155 static void io_celrev(void);
156 static void io_celext(void);
157 static void io_cellx(void);
158 static void io_celhx(void);
159 static void io_celly(void);
160 static void io_celhy(void);
161 static void io_tech(void);
162 static void io_celaad(void);
163 static void io_celbit(void);
164 static void io_celusb(void);
165 static void io_celnet(void);
166 static void io_celnoc(void);
167 static void io_celarc(void);
168 static void io_celptc(void);
169 static void io_celdon(void);
170 static void io_newno(void);
171 static void io_nodtyp(void);
172 static void io_nodlx(void);
173 static void io_nodhx(void);
174 static void io_nodly(void);
175 static void io_nodhy(void);
176 static void io_nodnam(void);
177 static void io_noddes(void);
178 static void io_nodrot(void);
179 static void io_nodtra(void);
180 static void io_nodkse(void);
181 static void io_nodpoc(void);
182 static void io_nodbit(void);
183 static void io_nodusb(void);
184 static void io_newpor(void);
185 static void io_porarc(void);
186 static void io_porexp(void);
187 static void io_newar(void);
188 static void io_arctyp(void);
189 static void io_arcnam(void);
190 static void io_arcwid(void);
191 static void io_arclen(void);
192 static void io_arcsig(void);
193 static void io_newend(void);
194 static void io_endnod(void);
195 static void io_endpt(void);
196 static void io_endxp(void);
197 static void io_endyp(void);
198 static void io_arckse(void);
199 static void io_arcbit(void);
200 static void io_arcusb(void);
201 static void io_arcnet(void);
202 static void io_newpt(void);
203 static void io_ptnam(void);
204 static void io_ptdes(void);
205 static void io_ptsno(void);
206 static void io_ptspt(void);
207 static void io_ptkse(void);
208 static void io_ptbit(void);
209 static void io_ptusb(void);
210 static void io_ptnet(void);
211 static TECHNOLOGY *io_gettechnology(CHAR*);
212 
213 struct keyroutine
214 {
215 	CHAR *matchstring;
216 	void (*routine)(void);
217 };
218 
219 /* possible keywords while reading libraries */
220 static struct keyroutine io_libraryroutines[] =
221 {
222 	{x_("****library"),     io_newlib},
223 	{x_("bits"),            io_libbit},
224 	{x_("lambda"),          io_lambda},
225 	{x_("version"),         io_versn},
226 	{x_("aids"),            io_libkno},
227 	{x_("aidname"),         io_libain},
228 	{x_("aidbits"),         io_libaib},
229 	{x_("userbits"),        io_libusb},
230 	{x_("techcount"),       io_libte},
231 	{x_("techname"),        io_libten},
232 	{x_("cellcount"),       io_libcc},
233 	{x_("maincell"),        io_libms},
234 	{x_("view"),            io_libvie},
235 	{x_("***cell"),         io_newcel},
236 	{x_("variables"),       io_getvar},
237    {NULL, NULL}
238 };
239 
240 /* possible keywords while reading cells */
241 static struct keyroutine io_cellroutines[] =
242 {
243 	{x_("bits"),            io_celbit},
244 	{x_("userbits"),        io_celusb},
245 	{x_("netnum"),          io_celnet},
246 	{x_("name"),            io_celnam},
247 	{x_("version"),         io_celver},
248 	{x_("creationdate"),    io_celcre},
249 	{x_("revisiondate"),    io_celrev},
250 	{x_("lowx"),            io_cellx},
251 	{x_("highx"),           io_celhx},
252 	{x_("lowy"),            io_celly},
253 	{x_("highy"),           io_celhy},
254 	{x_("externallibrary"), io_celext},
255 	{x_("aadirty"),         io_celaad},
256 	{x_("nodes"),           io_celnoc},
257 	{x_("arcs"),            io_celarc},
258 	{x_("porttypes"),       io_celptc},
259 	{x_("celldone"),        io_celdon},
260 	{x_("technology"),      io_tech},
261 	{x_("**node"),          io_newno},
262 	{x_("**arc"),           io_newar},
263 	{x_("***cell"),         io_newcel},
264 	{x_("variables"),       io_getvar},
265    {NULL, NULL}
266 };
267 
268 /* possible keywords while reading ports */
269 static struct keyroutine io_portroutines[] =
270 {
271 	{x_("bits"),            io_ptbit},
272 	{x_("userbits"),        io_ptusb},
273 	{x_("netnum"),          io_ptnet},
274 	{x_("subnode"),         io_ptsno},
275 	{x_("subport"),         io_ptspt},
276 	{x_("name"),            io_ptnam},
277 	{x_("descript"),        io_ptdes},
278 	{x_("aseen"),           io_ptkse},
279 	{x_("**porttype"),      io_newpt},
280 	{x_("**arc"),           io_newar},
281 	{x_("**node"),          io_newno},
282 	{x_("celldone"),        io_celdon},
283 	{x_("***cell"),         io_newcel},
284 	{x_("variables"),       io_getvar},
285 	{x_("arcbits"),         io_null},	/* used no more: ignored for compatibility */
286    {NULL, NULL}
287 };
288 
289 /* possible keywords while reading nodes */
290 static struct keyroutine io_noderoutines[] =
291 {
292 	{x_("bits"),            io_nodbit},
293 	{x_("userbits"),        io_nodusb},
294 	{x_("type"),            io_nodtyp},
295 	{x_("lowx"),            io_nodlx},
296 	{x_("highx"),           io_nodhx},
297 	{x_("lowy"),            io_nodly},
298 	{x_("highy"),           io_nodhy},
299 	{x_("rotation"),        io_nodrot},
300 	{x_("transpose"),       io_nodtra},
301 	{x_("aseen"),           io_nodkse},
302 	{x_("name"),            io_nodnam},
303 	{x_("descript"),        io_noddes},
304 	{x_("*port"),           io_newpor},
305 	{x_("**node"),          io_newno},
306 	{x_("**porttype"),      io_newpt},
307 	{x_("**arc"),           io_newar},
308 	{x_("celldone"),        io_celdon},
309 	{x_("variables"),       io_getvar},
310 	{x_("***cell"),         io_newcel},
311 	{x_("ports"),           io_nodpoc},
312 	{x_("exportcount"),     io_null},	/* used no more: ignored for compatibility */
313    {NULL, NULL}
314 };
315 
316 /* possible keywords while reading portinsts */
317 static struct keyroutine io_portinstroutines[] =
318 {
319 	{x_("arc"),             io_porarc},
320 	{x_("exported"),        io_porexp},
321 	{x_("*port"),           io_newpor},
322 	{x_("**node"),          io_newno},
323 	{x_("**porttype"),      io_newpt},
324 	{x_("**arc"),           io_newar},
325 	{x_("variables"),       io_getvar},
326 	{x_("celldone"),        io_celdon},
327 	{x_("***cell"),         io_newcel},
328    {NULL, NULL}
329 };
330 
331 /* possible keywords while reading arcs */
332 static struct keyroutine io_arcroutines[] =
333 {
334 	{x_("bits"),            io_arcbit},
335 	{x_("userbits"),        io_arcusb},
336 	{x_("netnum"),          io_arcnet},
337 	{x_("type"),            io_arctyp},
338 	{x_("width"),           io_arcwid},
339 	{x_("length"),          io_arclen},
340 	{x_("signals"),         io_arcsig},
341 	{x_("aseen"),           io_arckse},
342 	{x_("name"),            io_arcnam},
343 	{x_("*end"),            io_newend},
344 	{x_("**arc"),           io_newar},
345 	{x_("**node"),          io_newno},
346 	{x_("variables"),       io_getvar},
347 	{x_("celldone"),        io_celdon},
348 	{x_("***cell"),         io_newcel},
349    {NULL, NULL}
350 };
351 
352 /* possible keywords while reading arc ends */
353 static struct keyroutine io_arcendroutines[] =
354 {
355 	{x_("node"),            io_endnod},
356 	{x_("nodeport"),        io_endpt},
357 	{x_("xpos"),            io_endxp},
358 	{x_("ypos"),            io_endyp},
359 	{x_("*end"),            io_newend},
360 	{x_("**arc"),           io_newar},
361 	{x_("**node"),          io_newno},
362 	{x_("variables"),       io_getvar},
363 	{x_("celldone"),        io_celdon},
364 	{x_("***cell"),         io_newcel},
365    {NULL, NULL}
366 };
367 
io_readtextlibrary(LIBRARY * lib)368 BOOLEAN io_readtextlibrary(LIBRARY *lib)
369 {
370 	REGISTER LIBRARY *olib, *nextlib;
371 	REGISTER BOOLEAN ret;
372 
373 	/* mark all libraries as "not being read", but "wanted" */
374 	for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
375 	{
376 		olib->temp1 = 0;
377 		olib->userbits &= ~UNWANTEDLIB;
378 	}
379 
380 	ret = io_doreadtextlibrary(lib, TRUE);
381 
382 	/* delete unwanted libraries */
383 	for(olib = el_curlib; olib != NOLIBRARY; olib = nextlib)
384 	{
385 		nextlib = olib->nextlibrary;
386 		if ((olib->userbits&UNWANTEDLIB) == 0) continue;
387 		killlibrary(olib);
388 	}
389 	return(ret);
390 }
391 
io_doreadtextlibrary(LIBRARY * lib,BOOLEAN newprogress)392 BOOLEAN io_doreadtextlibrary(LIBRARY *lib, BOOLEAN newprogress)
393 {
394 	struct keyroutine *table;
395 	REGISTER CHAR *pp;
396 	REGISTER INTBIG i, j, reportcount, lambda, errcode;
397 	INTBIG num, den;
398 	REGISTER INTBIG oldunit;
399 	REGISTER NODEPROTO *np, *onp, *prevmatch;
400 	REGISTER TECHNOLOGY *tech;
401 	REGISTER NODEINST *ni;
402 	REGISTER ARCINST *ai;
403 	CHAR *filename;
404 	REGISTER void *infstr;
405 
406 	/* initialize the input string buffers */
407 	if (io_maxinputline == 0)
408 		if (io_grabbuffers(1000)) return(TRUE);
409 
410 	io_txtindata.textfilein = xopen(truepath(lib->libfile), io_filetypetlib,
411 		el_libdir, &filename);
412 	if (io_txtindata.textfilein == NULL)
413 	{
414 		ttyputerr(_("File %s not found"), lib->libfile);
415 		return(TRUE);
416 	}
417 
418 	/* update the library file name if the true location is different */
419 	if (estrcmp(filename, lib->libfile) != 0)
420 		(void)reallocstring(&lib->libfile, filename, lib->cluster);
421 
422 	reportcount = io_txtindata.fileposition = 0;
423 	if (io_verbose < 0)
424 	{
425 		io_txtindata.filelength = filesize(io_txtindata.textfilein);
426 		if (io_txtindata.filelength > 0)
427 		{
428 			if (newprogress)
429 			{
430 				io_inputprogressdialog = DiaInitProgress(x_(""), _("Reading library"));
431 				if (io_inputprogressdialog == 0)
432 				{
433 					xclose(io_txtindata.textfilein);
434 					return(TRUE);
435 				}
436 			}
437 			infstr = initinfstr();
438 			formatinfstr(infstr, _("Reading library %s"), lib->libname);
439 			DiaSetCaptionProgress(io_inputprogressdialog, returninfstr(infstr));
440 			DiaSetTextProgress(io_inputprogressdialog, _("Initializing..."));
441 			DiaSetProgress(io_inputprogressdialog, 0, io_txtindata.filelength);
442 		}
443 	} else io_txtindata.filelength = 0;
444 
445 	/* the error recovery point */
446 	errcode = setjmp(io_filerror);
447 	if (errcode != 0)
448 	{
449 		switch (errcode)
450 		{
451 			case LONGJMPNOMEM:        pp = _("No Memory");                        break;
452 			case LONGJMPMISCOLON:     pp = _("Missing colon");                    break;
453 			case LONGJMPUKNKEY:       pp = _("Unknown keyword");                  break;
454 			case LONGJMPEOF:          pp = _("EOF too soon");                     break;
455 			case LONGJMPEOFVAR:       pp = _("EOF in variables");                 break;
456 			case LONGJMPMISCOLVAR:    pp = _("Missing ':' in variable");          break;
457 			case LONGJMPMISOSBVAR:    pp = _("Missing '[' in variable");          break;
458 			case LONGJMPMISOSBVARARR: pp = _("Missing '[' in variable array");    break;
459 			case LONGJMPSHORTARR:     pp = _("Short array specification");        break;
460 			case LONGJMPUKNNOPROTO:   pp = _("Unknown node prototype");           break;
461 			case LONGJMPMISVIEWABR:   pp = _("Missing view abbreviation");        break;
462 			case LONGJMPBADVIEWABR:   pp = _("View abbreviation bad");            break;
463 			case LONGJMPINCVIEWABR:   pp = _("View abbreviation inconsistent");   break;
464 			case LONGJMPSECCELLNAME:  pp = _("Second cell name");                 break;
465 			case LONGJMPUKNTECH:      pp = _("Unknown technology");               break;
466 			case LONGJMPINVARCPROTO:  pp = _("Invalid arc prototype");            break;
467 			case LONGJMPUKNPORPROTO:  pp = _("Unknown port prototype name");      break;
468 			default:                  pp = _("Unknown");                          break;
469 		}
470 		ttyputerr(_("Error: %s on line %ld, keyword '%s'"), pp,
471 			io_txtindata.linenumber, io_keyword);
472 		xclose(io_txtindata.textfilein);
473 		if (io_verbose < 0 && io_txtindata.filelength > 0 && io_inputprogressdialog != 0)
474 		{
475 			DiaDoneProgress(io_inputprogressdialog);
476 			io_inputprogressdialog = 0;
477 		}
478 		return(TRUE);
479 	}
480 
481 	/* force the library name to be the proper file name without the "txt" */
482 	infstr = initinfstr();
483 	for(i=estrlen(lib->libfile)-1; i>=0; i--) if (lib->libfile[i] == DIRSEP) break;
484 	pp = &lib->libfile[i+1];
485 	j = estrlen(pp);
486 	if (j > 4 && namesame(&pp[j-4], x_(".txt")) == 0) j -= 4;
487 	for(i=0; i<j; i++) addtoinfstr(infstr, pp[i]);
488 	if (reallocstring(&lib->libname, returninfstr(infstr), lib->cluster))
489 		longjmp(io_filerror, LONGJMPNOMEM);
490 
491 	io_txtindata.curlib = lib;
492 	eraselibrary(lib);
493 
494 	/* clear error counters */
495 	io_txtindata.nodeinsterror = io_txtindata.portarcinsterror = 0;
496 	io_txtindata.portexpinsterror = io_txtindata.portprotoerror = 0;
497 	io_txtindata.arcinsterror = io_txtindata.geomerror = 0;
498 	io_txtindata.libraryerror = io_txtindata.rtnodeerror = 0;
499 
500 	io_txtindata.textlevel = INLIB;
501 	io_txtindata.linenumber = 0;
502 	for(;;)
503 	{
504 		/* get keyword from file */
505 		if (io_getkeyword()) break;
506 		pp = io_keyword;   while (*pp != 0) pp++;
507 		if (pp[-1] != ':') longjmp(io_filerror, LONGJMPMISCOLON);
508 		pp[-1] = 0;
509 
510 		if (reportcount++ > REPORTRATE)
511 		{
512 			reportcount = 0;
513 			if (io_verbose < 0 && io_txtindata.filelength > 0 && io_inputprogressdialog != 0)
514 				DiaSetProgress(io_inputprogressdialog, io_txtindata.fileposition, io_txtindata.filelength);
515 		}
516 
517 		/* determine which keyword table to use */
518 		switch (io_txtindata.textlevel)
519 		{
520 			case INLIB:       table = io_libraryroutines;   break;
521 			case INCELL:      table = io_cellroutines;      break;
522 			case INPORTPROTO: table = io_portroutines;      break;
523 			case INNODEINST:  table = io_noderoutines;      break;
524 			case INPOR:       table = io_portinstroutines;  break;
525 			case INARCINST:   table = io_arcroutines;       break;
526 			case INARCEND:    table = io_arcendroutines;    break;
527 		}
528 
529 		/* parse keyword and argument */
530 		for(i=0; table[i].matchstring != 0; i++)
531 			if (estrcmp(table[i].matchstring, io_keyword) == 0) break;
532 		if (table[i].matchstring == 0)
533 			longjmp(io_filerror, LONGJMPUKNKEY);
534 
535 		/* get argument to routine and call it */
536 		if (io_getkeyword()) longjmp(io_filerror, LONGJMPEOF);
537 		(*(table[i].routine))();
538 	}
539 	xclose(io_txtindata.textfilein);
540 	if (io_verbose < 0 && io_txtindata.filelength > 0 && io_inputprogressdialog != 0)
541 	{
542 		DiaSetProgress(io_inputprogressdialog, 999, 1000);
543 		DiaSetTextProgress(io_inputprogressdialog, _("Cleaning up..."));
544 	}
545 
546 	/* set the former version number on the library */
547 	nextchangequiet();
548 	(void)setval((INTBIG)io_txtindata.curlib, VLIBRARY, x_("LIB_former_version"),
549 		(INTBIG)io_txtindata.version, VSTRING|VDONTSAVE);
550 
551 	/* fill in any lambda values that are not specified */
552 	oldunit = ((io_txtindata.curlib->userbits & LIBUNITS) >> LIBUNITSSH) << INTERNALUNITSSH;
553 	if (oldunit == (el_units&INTERNALUNITS)) num = den = 1; else
554 		db_getinternalunitscale(&num, &den, el_units, oldunit);
555 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
556 	{
557 		lambda = io_txtindata.curlib->lambda[tech->techindex];
558 		if (lambda != 0) lambda = muldiv(lambda, den, num); else
559 		{
560 			lambda = el_curlib->lambda[tech->techindex];
561 			if (lambda == 0) lambda = tech->deflambda;
562 		}
563 		io_txtindata.curlib->lambda[tech->techindex] = lambda;
564 	}
565 
566 	/* see if cellgroup information was included */
567 	for(np = io_txtindata.curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
568 		if (np->temp1 == -1) break;
569 	if (np != NONODEPROTO)
570 	{
571 		/* missing cellgroup information, construct it from names */
572 		if (io_txtindata.emajor > 7 ||
573 			(io_txtindata.emajor == 7 && io_txtindata.eminor > 0) ||
574 			(io_txtindata.emajor == 7 && io_txtindata.eminor == 0 && io_txtindata.edetail > 11))
575 		{
576 			ttyputmsg(M_("Unusual!  Version %s library has no cellgroup information"), io_txtindata.version);
577 		}
578 		io_buildcellgrouppointersfromnames(io_txtindata.curlib);
579 	} else if (io_txtindata.curlib->firstnodeproto != NONODEPROTO)
580 	{
581 		/* convert numbers to cellgroup pointers */
582 		if (io_txtindata.emajor < 7 ||
583 			(io_txtindata.emajor == 7 && io_txtindata.eminor == 0 && io_txtindata.edetail <= 11))
584 		{
585 			ttyputmsg(M_("Unusual!  Version %s library has cellgroup information"), io_txtindata.version);
586 		}
587 		for(np = io_txtindata.curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
588 			np->nextcellgrp = NONODEPROTO;
589 		for(np = io_txtindata.curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
590 		{
591 			if (np->nextcellgrp != NONODEPROTO) continue;
592 			prevmatch = np;
593 			for(onp = np->nextnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
594 			{
595 				if (onp->temp1 != prevmatch->temp1) continue;
596 				prevmatch->nextcellgrp = onp;
597 				prevmatch = onp;
598 			}
599 			prevmatch->nextcellgrp = np;
600 		}
601 	}
602 
603 	/* if converting MOSIS CMOS technologies, store lambda in the right place */
604 	if (io_txtindata.convertmosiscmostechnologies != 0)
605 		io_txtindata.curlib->lambda[mocmos_tech->techindex] =
606 			io_txtindata.curlib->lambda[mocmossub_tech->techindex];
607 
608 	/* if this is to be the current library, adjust technologies */
609 	if (io_txtindata.curlib == el_curlib)
610 		for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
611 			changetechnologylambda(tech, io_txtindata.curlib->lambda[tech->techindex]);
612 
613 	/* warn if the MOSIS CMOS technologies were converted */
614 	if (io_txtindata.convertmosiscmostechnologies != 0)
615 	{
616 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
617 		{
618 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
619 				if (ni->proto->primindex != 0 && ni->proto->tech == mocmos_tech) break;
620 			if (ni != NONODEINST) break;
621 			for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
622 				if (ai->proto->tech == mocmos_tech) break;
623 			if (ai != NOARCINST) break;
624 		}
625 		if (np != NONODEPROTO)
626 			DiaMessageInDialog(
627 				_("Warning: library %s has older 'mocmossub' technology, converted to new 'mocmos'"),
628 					lib->libname);
629 	}
630 
631 	/* print any variable-related error messages */
632 	if (io_txtindata.nodeinsterror != 0)
633 		ttyputmsg(_("Warning: %ld invalid NODEINST pointers"), io_txtindata.nodeinsterror);
634 	if (io_txtindata.arcinsterror != 0)
635 		ttyputmsg(_("Warning: %ld invalid ARCINST pointers"), io_txtindata.arcinsterror);
636 	if (io_txtindata.portprotoerror != 0)
637 		ttyputmsg(_("Warning: %ld invalid PORTPROTO pointers"), io_txtindata.portprotoerror);
638 	if (io_txtindata.portarcinsterror != 0)
639 		ttyputmsg(_("Warning: %ld PORTARCINST pointers not restored"), io_txtindata.portarcinsterror);
640 	if (io_txtindata.portexpinsterror != 0)
641 		ttyputmsg(_("Warning: %ld PORTEXPINST pointers not restored"), io_txtindata.portexpinsterror);
642 	if (io_txtindata.geomerror != 0)
643 		ttyputmsg(_("Warning: %ld GEOM pointers not restored"), io_txtindata.geomerror);
644 	if (io_txtindata.rtnodeerror != 0)
645 		ttyputmsg(_("Warning: %ld RTNODE pointers not restored"), io_txtindata.rtnodeerror);
646 	if (io_txtindata.libraryerror != 0)
647 		ttyputmsg(_("Warning: %ld LIBRARY pointers not restored"), io_txtindata.libraryerror);
648 
649 	if (io_txtindata.maincell != -1 && io_txtindata.maincell < io_txtindata.cellcount)
650 		io_txtindata.curlib->curnodeproto = io_txtindata.nodeprotolist[io_txtindata.maincell]; else
651 			io_txtindata.curlib->curnodeproto = NONODEPROTO;
652 	if (io_txtindata.cellcount != 0) efree((CHAR *)io_txtindata.nodeprotolist);
653 	if (io_verbose < 0 && io_txtindata.filelength > 0 && newprogress && io_inputprogressdialog != 0)
654 	{
655 		DiaDoneProgress(io_inputprogressdialog);
656 		io_inputprogressdialog = 0;
657 	}
658 
659 	/* clean up the library */
660 	io_fixnewlib(io_txtindata.curlib, 0);
661 	io_txtindata.curlib->userbits &= ~(LIBCHANGEDMAJOR | LIBCHANGEDMINOR);
662 	efree(io_txtindata.version);
663 	return(FALSE);
664 }
665 
666 /******************** GENERAL PARSING ROUTINES ********************/
667 
io_getkeyword(void)668 BOOLEAN io_getkeyword(void)
669 {
670 	REGISTER INTBIG c, cindex, inquote;
671 
672 	/* skip leading blanks */
673 	for(;;)
674 	{
675 		c = xgetc(io_txtindata.textfilein);
676 		io_txtindata.fileposition++;
677 		if (c == '\n')
678 		{
679 			io_txtindata.linenumber++;
680 			if (io_verbose == 0 && io_txtindata.linenumber%1000 == 0)
681 				ttyputmsg(_("%ld lines read"), io_txtindata.linenumber);
682 			continue;
683 		}
684 		if (c != ' ') break;
685 	}
686 
687 	/* if the file ended, quit now */
688 	if (c == EOF) return(TRUE);
689 
690 	/* collect the word */
691 	cindex = 0;
692 	if (c == '"') inquote = 1; else inquote = 0;
693 	io_keyword[cindex++] = (CHAR)c;
694 	for(;;)
695 	{
696 		c = xgetc(io_txtindata.textfilein);
697 		if (c == EOF) return(TRUE);
698 		io_txtindata.fileposition++;
699 		if (c == '\n' || (c == ' ' && inquote == 0)) break;
700 		if (cindex >= io_maxinputline)
701 		{
702 			/* try to allocate more space */
703 			if (io_grabbuffers(io_maxinputline*2)) break;
704 		}
705 		if (c == '"' && (cindex == 0 || io_keyword[cindex-1] != '^'))
706 			inquote = 1 - inquote;
707 		io_keyword[cindex++] = (CHAR)c;
708 	}
709 	if (c == '\n')
710 	{
711 		io_txtindata.linenumber++;
712 		if (io_verbose == 0 && io_txtindata.linenumber%1000 == 0)
713 			ttyputmsg(_("%ld lines read"), io_txtindata.linenumber);
714 	}
715 	io_keyword[cindex] = 0;
716 	return(FALSE);
717 }
718 
719 /*
720  * routine to allocate the keyword buffer to be the specified size
721  */
io_grabbuffers(INTBIG size)722 BOOLEAN io_grabbuffers(INTBIG size)
723 {
724 	REGISTER CHAR *p;
725 	REGISTER INTBIG i;
726 
727 	/* first get the new buffer */
728 	p = (CHAR *)emalloc((size+1) * SIZEOFCHAR, io_tool->cluster);
729 	if (p == 0)
730 	{
731 		ttyputnomemory();
732 		return(TRUE);
733 	}
734 
735 	/* if there was an old buffer, copy it */
736 	if (io_maxinputline != 0)
737 	{
738 		for(i=0; i<io_maxinputline; i++) p[i] = io_keyword[i];
739 		efree(io_keyword);
740 	}
741 
742 	/* set the new size and buffer */
743 	io_maxinputline = size;
744 	io_keyword = p;
745 	return(FALSE);
746 }
747 
748 /*
749  * helper routine to parse a port prototype name "line" that should be
750  * in node prototype "np".  The routine returns NOPORTPROTO if it cannot
751  * figure out what port this name refers to.
752  */
io_getport(CHAR * line,NODEPROTO * np)753 PORTPROTO *io_getport(CHAR *line, NODEPROTO *np)
754 {
755 	REGISTER PORTPROTO *pp;
756 	REGISTER INTBIG i;
757 
758 	pp = getportproto(np, line);
759 	if (pp != NOPORTPROTO) return(pp);
760 
761 	/* convert special port names */
762 	pp = io_convertoldportname(line, np);
763 	if (pp != NOPORTPROTO) return(pp);
764 
765 	/* try to parse version 1 port names */
766 	if (io_txtindata.version[0] == '1')
767 	{
768 		/* see if database uses shortened name */
769 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
770 		{
771 			i = estrlen(pp->protoname);
772 			if (namesamen(line, pp->protoname, i) == 0) return(pp);
773 		}
774 
775 		/* see if the port name ends in a digit, fake with that */
776 		i = estrlen(line);
777 		if (line[i-2] == '-' && line[i-1] >= '0' && line[i-1] <= '9')
778 		{
779 			i = (eatoi(&line[i-1])-1) / 3;
780 			for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
781 				if (i-- == 0) return(pp);
782 		}
783 	}
784 
785 	/* sorry, cannot figure out what port prototype this is */
786 	return(NOPORTPROTO);
787 }
788 
789 /*
790  * null routine for ignoring keywords
791  */
io_null(void)792 void io_null(void) {}
793 
794 /******************** LIBRARY PARSING ROUTINES ********************/
795 
796 /*
797  * a new library is introduced (keyword "****library")
798  * This should be the first keyword in the file
799  */
io_newlib(void)800 void io_newlib(void)
801 {
802 	REGISTER TECHNOLOGY *tech;
803 
804 	/* set defaults */
805 	io_txtindata.maincell = -1;
806 	(void)allocstring(&io_txtindata.version, x_("1.00"), el_tempcluster);
807 	io_txtindata.varpos = INVTOOL;
808 	io_txtindata.curtech = NOTECHNOLOGY;
809 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
810 		io_txtindata.curlib->lambda[tech->techindex] = 0;
811 	io_txtindata.textlevel = INLIB;
812 }
813 
814 /*
815  * get the file's Electric version number (keyword "version")
816  */
io_versn(void)817 void io_versn(void)
818 {
819 	(void)reallocstring(&io_txtindata.version, io_keyword, el_tempcluster);
820 
821 	/* for versions before 6.03q, convert MOSIS CMOS technology names */
822 	parseelectricversion(io_txtindata.version, &io_txtindata.emajor, &io_txtindata.eminor,
823 		&io_txtindata.edetail);
824 	io_txtindata.convertmosiscmostechnologies = 0;
825 	if (io_txtindata.emajor < 6 ||
826 		(io_txtindata.emajor == 6 && io_txtindata.eminor < 3) ||
827 		(io_txtindata.emajor == 6 && io_txtindata.eminor == 3 && io_txtindata.edetail < 17))
828 	{
829 		if ((asktech(mocmossub_tech, x_("get-state"))&MOCMOSSUBNOCONV) == 0)
830 			io_txtindata.convertmosiscmostechnologies = 1;
831 	}
832 #ifdef REPORTCONVERSION
833 	ttyputmsg(x_("Library is version %s (%ld.%ld.%ld)"), io_txtindata.version, io_txtindata.emajor,
834 		io_txtindata.eminor, io_txtindata.edetail);
835 	if (io_txtindata.convertmosiscmostechnologies != 0)
836 		ttyputmsg(x_("   Converting MOSIS CMOS technologies (mocmossub => mocmos)"));
837 #endif
838 }
839 
840 /*
841  * get the number of tools (keyword "aids")
842  */
io_libkno(void)843 void io_libkno(void)
844 {
845 	io_txtindata.bitcount = 0;
846 }
847 
848 /*
849  * get the name of the tool (keyword "aidname")
850  */
io_libain(void)851 void io_libain(void)
852 {
853 	REGISTER TOOL *tool;
854 
855 	tool = gettool(io_keyword);
856 	if (tool == NOTOOL) io_txtindata.bitcount = -1; else
857 		io_txtindata.bitcount = tool->toolindex + 1;
858 }
859 
860 /*
861  * get the number of toolbits (keyword "aidbits")
862  */
io_libaib(void)863 void io_libaib(void)
864 {
865 	io_txtindata.bitcount = 0;
866 }
867 
868 /*
869  * get tool information for the library (keyword "bits")
870  */
io_libbit(void)871 void io_libbit(void)
872 {
873 	if (io_txtindata.bitcount == 0)
874 		io_txtindata.curlib->userbits = eatoi(io_keyword);
875 	io_txtindata.bitcount++;
876 }
877 
878 /*
879  * get the number of toolbits (keyword "userbits")
880  */
io_libusb(void)881 void io_libusb(void)
882 {
883 	io_txtindata.curlib->userbits = eatoi(io_keyword);
884 
885 	/* this library came as readable dump, so don't automatically save it to disk */
886 	io_txtindata.curlib->userbits &= ~READFROMDISK;
887 }
888 
889 /*
890  * get the number of technologies (keyword "techcount")
891  */
io_libte(void)892 void io_libte(void)
893 {
894 	io_txtindata.varpos = INVTECHNOLOGY;
895 	io_txtindata.bitcount = 0;
896 }
897 
898 /*
899  * get the name of the technology (keyword "techname")
900  */
io_libten(void)901 void io_libten(void)
902 {
903 	REGISTER TECHNOLOGY *tech;
904 
905 	tech = gettechnology(io_keyword);
906 	if (tech == NOTECHNOLOGY) io_txtindata.bitcount = -1; else
907 		io_txtindata.bitcount = tech->techindex;
908 }
909 
910 /*
911  * get lambda values for each technology in library (keyword "lambda")
912  */
io_lambda(void)913 void io_lambda(void)
914 {
915 	REGISTER INTBIG lam;
916 
917 	if (io_txtindata.bitcount >= el_maxtech ||
918 		io_txtindata.bitcount < 0) return;
919 	lam = eatoi(io_keyword);
920 
921 	/* for version 4.0 and earlier, scale lambda by 20 */
922 	if (eatoi(io_txtindata.version) <= 4) lam *= 20;
923 	io_txtindata.curlib->lambda[io_txtindata.bitcount++] = lam;
924 }
925 
926 /*
927  * get variables on current object (keyword "variables")
928  */
io_getvar(void)929 void io_getvar(void)
930 {
931 	REGISTER INTBIG i, j, count, type, len, naddr, ntype, thisnaddr, *store, key, ret;
932 	REGISTER float *fstore;
933 	REGISTER INTSML *sstore;
934 	UINTBIG descript[TEXTDESCRIPTSIZE];
935 	REGISTER CHAR *pt, *start, *varname;
936 	REGISTER VARIABLE *var;
937 	REGISTER TECHNOLOGY *t;
938 	REGISTER void *infstr;
939 
940 	naddr = -1;
941 	switch (io_txtindata.varpos)
942 	{
943 		case INVTOOL:				/* keyword applies to tools */
944 			if (io_txtindata.bitcount < 0) break;
945 			naddr = (INTBIG)&el_tools[io_txtindata.bitcount-1];
946 			ntype = VTOOL;
947 			break;
948 		case INVTECHNOLOGY:			/* keyword applies to technologies */
949 			if (io_txtindata.bitcount < 0) break;
950 			for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
951 				if (t->techindex == io_txtindata.bitcount-1) break;
952 			naddr = (INTBIG)t;
953 			ntype = VTECHNOLOGY;
954 			break;
955 		case INVLIBRARY:			/* keyword applies to library */
956 			naddr = (INTBIG)io_txtindata.curlib;
957 			ntype = VLIBRARY;
958 			break;
959 		case INVNODEPROTO:			/* keyword applies to nodeproto */
960 			naddr = (INTBIG)io_txtindata.curnodeproto;    ntype = VNODEPROTO;
961 			break;
962 		case INVNODEINST:			/* keyword applies to nodeinst */
963 			naddr = (INTBIG)io_txtindata.curnodeinst;    ntype = VNODEINST;
964 			break;
965 		case INVPORTARCINST:		/* keyword applies to portarcinsts */
966 			naddr = (INTBIG)io_txtindata.varaddr;    ntype = VPORTARCINST;
967 			break;
968 		case INVPORTEXPINST:		/* keyword applies to portexpinsts */
969 			naddr = (INTBIG)io_txtindata.varaddr;    ntype = VPORTEXPINST;
970 			break;
971 		case INVPORTPROTO:			/* keyword applies to portproto */
972 			naddr = (INTBIG)io_txtindata.curportproto;    ntype = VPORTPROTO;
973 			break;
974 		case INVARCINST:			/* keyword applies to arcinst */
975 			naddr = (INTBIG)io_txtindata.curarcinst;    ntype = VARCINST;
976 			break;
977 	}
978 
979 	/* find out how many variables to read */
980 	count = eatoi(io_keyword);
981 	for(i=0; i<count; i++)
982 	{
983 		/* read the first keyword with the name, type, and descriptor */
984 		if (io_getkeyword()) longjmp(io_filerror, LONGJMPEOFVAR);
985 		if (io_keyword[estrlen(io_keyword)-1] != ':')
986 			longjmp(io_filerror, LONGJMPMISCOLVAR);
987 
988 		/* get the variable name */
989 		infstr = initinfstr();
990 		for(pt = io_keyword; *pt != 0; pt++)
991 		{
992 			if (*pt == '^' && pt[1] != 0)
993 			{
994 				pt++;
995 				addtoinfstr(infstr, *pt);
996 			}
997 			if (*pt == '(' || *pt == '[' || *pt == ':') break;
998 			addtoinfstr(infstr, *pt);
999 		}
1000 		varname = returninfstr(infstr);
1001 		key = makekey(varname);
1002 
1003 		/* see if the variable is valid */
1004 		thisnaddr = naddr;
1005 		if (isdeprecatedvariable(naddr, ntype, varname)) thisnaddr = -1;
1006 
1007 		/* get optional length */
1008 		if (*pt == '(')
1009 		{
1010 			len = myatoi(&pt[1]);
1011 			while (*pt != '[' && *pt != ':' && *pt != 0) pt++;
1012 		} else len = -1;
1013 
1014 		/* get type */
1015 		if (*pt != '[') longjmp(io_filerror, LONGJMPMISOSBVAR);
1016 		type = myatoi(&pt[1]);
1017 
1018 		/* get the descriptor */
1019 		while (*pt != ',' && *pt != ':' && *pt != 0) pt++;
1020 		TDCLEAR(descript);
1021 		if (*pt == ',')
1022 		{
1023 			descript[0] = myatoi(&pt[1]);
1024 			for(pt++; *pt != 0 && *pt != '/' && *pt != ']'; pt++) ;
1025 			if (*pt == '/')
1026 				descript[1] = myatoi(pt+1);
1027 		}
1028 
1029 		/* get value */
1030 		if (io_getkeyword()) longjmp(io_filerror, LONGJMPEOFVAR);
1031 		if ((type&VISARRAY) != 0)
1032 		{
1033 			if (len < 0)
1034 			{
1035 				len = (type&VLENGTH) >> VLENGTHSH;
1036 				store = emalloc((len * SIZEOFINTBIG), el_tempcluster);
1037 				if (store == 0) longjmp(io_filerror, LONGJMPNOMEM);
1038 				fstore = (float *)store;
1039 				sstore = (INTSML *)store;
1040 			} else
1041 			{
1042 				store = emalloc(((len+1) * SIZEOFINTBIG), el_tempcluster);
1043 				if (store == 0) longjmp(io_filerror, LONGJMPNOMEM);
1044 				fstore = (float *)store;
1045 				sstore = (INTSML *)store;
1046 				store[len] = -1;
1047 				if ((type&VTYPE) == VFLOAT) fstore[len] = castfloat(-1);
1048 				if ((type&VTYPE) == VSHORT) sstore[len] = -1;
1049 			}
1050 			pt = io_keyword;
1051 			if (*pt++ != '[')
1052 				longjmp(io_filerror, LONGJMPMISOSBVARARR);
1053 			for(j=0; j<len; j++)
1054 			{
1055 				/* string arrays must be handled specially */
1056 				if ((type&VTYPE) == VSTRING)
1057 				{
1058 					while (*pt != '"' && *pt != 0) pt++;
1059 					if (*pt != 0)
1060 					{
1061 						start = pt++;
1062 						for(;;)
1063 						{
1064 							if (pt[0] == '^' && pt[1] != 0)
1065 							{
1066 								pt += 2;
1067 								continue;
1068 							}
1069 							if (pt[0] == '"' || pt[0] == 0) break;
1070 							pt++;
1071 						}
1072 						if (*pt != 0) pt++;
1073 					}
1074 				} else
1075 				{
1076 					start = pt;
1077 					while (*pt != ',' && *pt != ']' && *pt != 0) pt++;
1078 				}
1079 				if (*pt == 0)
1080 					longjmp(io_filerror, LONGJMPSHORTARR);
1081 				*pt++ = 0;
1082 				if ((type&VTYPE) == VGENERAL)
1083 				{
1084 					if ((j&1) == 0)
1085 					{
1086 						store[j+1] = myatoi(start);
1087 					} else
1088 					{
1089 						store[j-1] = io_decode(start, store[j]);
1090 					}
1091 				} else
1092 				{
1093 					if ((type&VTYPE) == VFLOAT)
1094 					{
1095 						fstore[j] = castfloat(io_decode(start, type));
1096 					} else if ((type&VTYPE) == VSHORT)
1097 					{
1098 						sstore[j] = (INTSML)io_decode(start, type);
1099 					} else
1100 					{
1101 						store[j] = io_decode(start, type);
1102 					}
1103 				}
1104 			}
1105 			if (thisnaddr != -1)
1106 			{
1107 				nextchangequiet();
1108 				var = setvalkey(thisnaddr, ntype, key, (INTBIG)store, type);
1109 				if (var == NOVARIABLE) longjmp(io_filerror, LONGJMPNOMEM);
1110 				TDCOPY(var->textdescript, descript);
1111 
1112 				/* handle updating of technology caches */
1113 				if (ntype == VTECHNOLOGY)
1114 					changedtechnologyvariable(key);
1115 			}
1116 			efree((CHAR *)store);
1117 		} else
1118 		{
1119 			ret = io_decode(io_keyword, type);
1120 			if (thisnaddr != -1)
1121 			{
1122 				nextchangequiet();
1123 				var = setvalkey(thisnaddr, ntype, key, ret, type);
1124 				if (var == NOVARIABLE) longjmp(io_filerror, LONGJMPNOMEM);
1125 				TDCOPY(var->textdescript, descript);
1126 
1127 				/* handle updating of technology caches */
1128 				if (ntype == VTECHNOLOGY)
1129 					changedtechnologyvariable(key);
1130 			}
1131 		}
1132 	}
1133 }
1134 
io_decode(CHAR * name,INTBIG type)1135 INTBIG io_decode(CHAR *name, INTBIG type)
1136 {
1137 	REGISTER INTBIG thistype, cindex;
1138 	REGISTER CHAR *out, *retur;
1139 	REGISTER NODEPROTO *np;
1140 
1141 	thistype = type;
1142 	if ((thistype&(VCODE1|VCODE2)) != 0) thistype = VSTRING;
1143 
1144 	switch (thistype&VTYPE)
1145 	{
1146 		case VINTEGER:
1147 		case VSHORT:
1148 		case VBOOLEAN:
1149 		case VFRACT:
1150 		case VADDRESS:
1151 			return(myatoi(name));
1152 		case VCHAR:
1153 			return((INTBIG)name);
1154 		case VSTRING:
1155 			if (*name == '"') name++;
1156 			retur = name;
1157 			for(out = name; *name != 0; name++)
1158 			{
1159 				if (*name == '^' && name[1] != 0)
1160 				{
1161 					name++;
1162 					*out++ = *name;
1163 					continue;
1164 				}
1165 				if (*name == '"') break;
1166 				*out++ = *name;
1167 			}
1168 			*out = 0;
1169 			return((INTBIG)retur);
1170 		case VFLOAT:
1171 		case VDOUBLE:
1172 			return(castint((float)eatof(name)));
1173 		case VNODEINST:
1174 			cindex = myatoi(name);
1175 			if (cindex >= 0 && cindex < io_txtindata.nodeinstcount)
1176 				return((INTBIG)io_txtindata.nodelist[cindex]);
1177 			io_txtindata.nodeinsterror++;
1178 			return(-1);
1179 		case VNODEPROTO:
1180 			cindex = myatoi(name);
1181 			if (cindex == -1) return(-1);
1182 
1183 			/* see if there is a ":" in the type */
1184 			for(out = name; *out != 0; out++) if (*out == ':') break;
1185 			if (*out == 0)
1186 			{
1187 				cindex = eatoi(name);
1188 				if (cindex == -1) return(-1);
1189 				return((INTBIG)io_txtindata.nodeprotolist[cindex]);
1190 			}
1191 
1192 			/* parse primitive nodeproto name */
1193 			np = getnodeproto(name);
1194 			if (np == NONODEPROTO)
1195 				longjmp(io_filerror, LONGJMPUKNNOPROTO);
1196 			if (np->primindex == 0)
1197 				longjmp(io_filerror, LONGJMPUKNNOPROTO);
1198 			return((INTBIG)np);
1199 		case VPORTARCINST:
1200 			io_txtindata.portarcinsterror++;   break;
1201 		case VPORTEXPINST:
1202 			io_txtindata.portexpinsterror++;   break;
1203 		case VPORTPROTO:
1204 			cindex = myatoi(name);
1205 			if (cindex >= 0 && cindex < io_txtindata.portprotocount)
1206 				return((INTBIG)io_txtindata.portprotolist[cindex]);
1207 			io_txtindata.portprotoerror++;
1208 			return(-1);
1209 		case VARCINST:
1210 			cindex = myatoi(name);
1211 			if (cindex >= 0 && cindex < io_txtindata.arcinstcount)
1212 				return((INTBIG)io_txtindata.arclist[cindex]);
1213 			io_txtindata.arcinsterror++;
1214 			return(-1);
1215 		case VARCPROTO:
1216 			return((INTBIG)getarcproto(name));
1217 		case VGEOM:
1218 			io_txtindata.geomerror++;   break;
1219 		case VLIBRARY:
1220 			io_txtindata.libraryerror++;   break;
1221 		case VTECHNOLOGY:
1222 			return((INTBIG)io_gettechnology(name));
1223 		case VTOOL:
1224 			return((INTBIG)gettool(name));
1225 		case VRTNODE:
1226 			io_txtindata.rtnodeerror++;   break;
1227 	}
1228 	return(-1);
1229 }
1230 
1231 /*
1232  * get the number of cells in this library (keyword "cellcount")
1233  */
io_libcc(void)1234 void io_libcc(void)
1235 {
1236 	REGISTER INTBIG i;
1237 
1238 	io_txtindata.varpos = INVLIBRARY;
1239 
1240 	io_txtindata.cellcount = eatoi(io_keyword);
1241 	if (io_txtindata.cellcount == 0)
1242 	{
1243 		io_txtindata.curlib->firstnodeproto = NONODEPROTO;
1244 		io_txtindata.curlib->tailnodeproto = NONODEPROTO;
1245 		io_txtindata.curlib->numnodeprotos = 0;
1246 		return;
1247 	}
1248 
1249 	/* allocate a list of node prototypes for this library */
1250 	io_txtindata.nodeprotolist = (NODEPROTO **)emalloc(((sizeof (NODEPROTO *)) * io_txtindata.cellcount),
1251 		el_tempcluster);
1252 	if (io_txtindata.nodeprotolist == 0) longjmp(io_filerror, LONGJMPNOMEM);
1253 	for(i=0; i<io_txtindata.cellcount; i++)
1254 	{
1255 		io_txtindata.nodeprotolist[i] = allocnodeproto(io_txtindata.curlib->cluster);
1256 		if (io_txtindata.nodeprotolist[i] == NONODEPROTO)
1257 			longjmp(io_filerror, LONGJMPNOMEM);
1258 		io_txtindata.nodeprotolist[i]->cellview = el_unknownview;
1259 		io_txtindata.nodeprotolist[i]->newestversion = io_txtindata.nodeprotolist[i];
1260 		io_txtindata.nodeprotolist[i]->primindex = 0;
1261 		io_txtindata.nodeprotolist[i]->firstportproto = NOPORTPROTO;
1262 		io_txtindata.nodeprotolist[i]->firstnodeinst = NONODEINST;
1263 		io_txtindata.nodeprotolist[i]->firstarcinst = NOARCINST;
1264 	}
1265 }
1266 
1267 /*
1268  * get the main cell of this library (keyword "maincell")
1269  */
io_libms(void)1270 void io_libms(void)
1271 {
1272 	io_txtindata.maincell = eatoi(io_keyword);
1273 }
1274 
1275 /*
1276  * get a view (keyword "view")
1277  */
io_libvie(void)1278 void io_libvie(void)
1279 {
1280 	REGISTER CHAR *pt;
1281 	REGISTER INTBIG len;
1282 	REGISTER VIEW *v;
1283 
1284 	pt = io_keyword;
1285 	while (*pt != 0 && *pt != '{') pt++;
1286 	if (*pt != '{') longjmp(io_filerror, LONGJMPMISVIEWABR);
1287 	*pt++ = 0;
1288 	len = estrlen(pt);
1289 	if (pt[len-1] != '}') longjmp(io_filerror, LONGJMPBADVIEWABR);
1290 	pt[len-1] = 0;
1291 	v = getview(io_keyword);
1292 	if (v == NOVIEW)
1293 	{
1294 		v = allocview();
1295 		if (v == NOVIEW) longjmp(io_filerror, LONGJMPNOMEM);
1296 		(void)allocstring(&v->viewname, io_keyword, db_cluster);
1297 		(void)allocstring(&v->sviewname, pt, db_cluster);
1298 		if (namesamen(io_keyword, x_("Schematic-Page-"), 15) == 0)
1299 			v->viewstate |= MULTIPAGEVIEW;
1300 		v->nextview = el_views;
1301 		el_views = v;
1302 	} else
1303 	{
1304 		if (namesame(v->sviewname, pt) != 0)
1305 			longjmp(io_filerror, LONGJMPINCVIEWABR);
1306 	}
1307 	pt[-1] = '{';   pt[len-1] = '}';
1308 }
1309 
1310 /******************** CELL PARSING ROUTINES ********************/
1311 
1312 /*
1313  * initialize for a new cell (keyword "***cell")
1314  */
io_newcel(void)1315 void io_newcel(void)
1316 {
1317 	REGISTER CHAR *pt;
1318 
1319 	io_txtindata.curcellnumber = eatoi(io_keyword);
1320 	for(pt = io_keyword; *pt != 0; pt++) if (*pt == '/') break;
1321 	io_txtindata.curnodeproto = io_txtindata.nodeprotolist[io_txtindata.curcellnumber];
1322 	if (*pt == '/') io_txtindata.curnodeproto->temp1 = eatoi(pt+1); else
1323 		io_txtindata.curnodeproto->temp1 = -1;
1324 	io_txtindata.textlevel = INCELL;
1325 	io_txtindata.varpos = INVNODEPROTO;
1326 }
1327 
1328 /*
1329  * get the name of the current cell (keyword "name")
1330  */
io_celnam(void)1331 void io_celnam(void)
1332 {
1333 	REGISTER CHAR *pt;
1334 	REGISTER VIEW *v;
1335 	REGISTER void *infstr;
1336 
1337 	if (io_verbose != 0)
1338 	{
1339 		if (io_verbose < 0 && io_txtindata.filelength > 0 && io_inputprogressdialog != 0)
1340 		{
1341 			infstr = initinfstr();
1342 			formatinfstr(infstr, _("Reading %s"), io_keyword);
1343 			DiaSetTextProgress(io_inputprogressdialog, returninfstr(infstr));
1344 		} else ttyputmsg(_("Reading %s"), io_keyword);
1345 	}
1346 	io_txtindata.curnodeproto->cellview = el_unknownview;
1347 	pt = io_keyword;
1348 	while (*pt != 0 && *pt != '{') pt++;
1349 	if (*pt == '{')
1350 	{
1351 		*pt = 0;
1352 		if (allocstring(&io_txtindata.curnodeproto->protoname, io_keyword,
1353 			io_txtindata.curlib->cluster))
1354 				longjmp(io_filerror, LONGJMPNOMEM);
1355 		pt++;
1356 		pt[estrlen(pt)-1] = 0;
1357 		for(v = el_views; v != NOVIEW; v = v->nextview)
1358 			if (*v->sviewname != 0 && namesame(pt, v->sviewname) == 0) break;
1359 		if (v != NOVIEW) io_txtindata.curnodeproto->cellview = v;
1360 	} else
1361 	{
1362 		if (allocstring(&io_txtindata.curnodeproto->protoname, io_keyword,
1363 			io_txtindata.curlib->cluster))
1364 				longjmp(io_filerror, LONGJMPNOMEM);
1365 	}
1366 	io_txtindata.curnodeproto->lib = io_txtindata.curlib;
1367 }
1368 
1369 /*
1370  * get the version of the current cell (keyword "version")
1371  */
io_celver(void)1372 void io_celver(void)
1373 {
1374 	io_txtindata.curnodeproto->version = eatoi(io_keyword);
1375 	db_insertnodeproto(io_txtindata.curnodeproto);
1376 }
1377 
1378 /*
1379  * get the creation date of the current cell (keyword "creationdate")
1380  */
io_celcre(void)1381 void io_celcre(void)
1382 {
1383 	io_txtindata.curnodeproto->creationdate = eatoi(io_keyword);
1384 }
1385 
1386 /*
1387  * get the revision date of the current cell (keyword "revisiondate")
1388  */
io_celrev(void)1389 void io_celrev(void)
1390 {
1391 	io_txtindata.curnodeproto->revisiondate = eatoi(io_keyword);
1392 }
1393 
1394 /*
1395  * get the external library file (keyword "externallibrary")
1396  */
io_celext(void)1397 void io_celext(void)
1398 {
1399 	INTBIG len, filetype, filelen;
1400 	REGISTER LIBRARY *elib;
1401 	REGISTER CHAR *libname, *pt;
1402 	CHAR *filename, *libfile, *oldline2, *libfilename, *libfilepath;
1403 	FILE *io;
1404 	REGISTER BOOLEAN failed;
1405 	CHAR *cellname;
1406 	REGISTER NODEPROTO *np, *onp;
1407 	REGISTER NODEINST *ni;
1408 	TXTINPUTDATA savetxtindata;
1409 	REGISTER void *infstr;
1410 
1411 	/* get the path to the library file */
1412 	libfile = io_keyword;
1413 	if (libfile[0] == '"')
1414 	{
1415 		libfile++;
1416 		len = estrlen(libfile) - 1;
1417 		if (libfile[len] == '"') libfile[len] = 0;
1418 	}
1419 
1420 	/* see if this library is already read in */
1421 	infstr = initinfstr();
1422 	addstringtoinfstr(infstr, skippath(libfile));
1423 	libname = returninfstr(infstr);
1424 	len = estrlen(libname);
1425 	filelen = estrlen(libfile);
1426 	if (len < filelen)
1427 	{
1428 		libfilename = &libfile[filelen-len-1];
1429 		*libfilename++ = 0;
1430 		libfilepath = libfile;
1431 	} else
1432 	{
1433 		libfilename = libfile;
1434 		libfilepath = x_("");
1435 	}
1436 
1437 	filetype = io_filetypetlib;
1438 	if (len > 5 && namesame(&libname[len-5], x_(".elib")) == 0)
1439 	{
1440 		libname[len-5] = 0;
1441 		filetype = io_filetypeblib;
1442 	} else
1443 	{
1444 		if (len > 4 && namesame(&libname[len-4], x_(".txt")) == 0) libname[len-4] = 0;
1445 	}
1446 	elib = getlibrary(libname);
1447 	if (elib == NOLIBRARY)
1448 	{
1449 		/* library does not exist: see if file is there */
1450 		io = xopen(libfilename, filetype, truepath(libfilepath), &filename);
1451 		if (io == 0)
1452 		{
1453 			/* try the library area */
1454 			io = xopen(libfilename, filetype, el_libdir, &filename);
1455 		}
1456 		if (io != 0)
1457 		{
1458 			xclose(io);
1459 			ttyputmsg(_("Reading referenced library %s"), libname);
1460 		} else
1461 		{
1462 			infstr = initinfstr();
1463 			formatinfstr(infstr, _("Reference library '%s'"), libname);
1464 			pt = fileselect(returninfstr(infstr), filetype, x_(""));
1465 			if (pt != 0)
1466 			{
1467 				estrcpy(libfile, pt);
1468 				filename = libfile;
1469 			}
1470 		}
1471 		elib = newlibrary(libname, filename);
1472 		if (elib == NOLIBRARY) return;
1473 
1474 		/* read the external library */
1475 		savetxtindata = io_txtindata;
1476 		if (io_verbose < 0 && io_txtindata.filelength > 0 && io_inputprogressdialog != 0)
1477 		{
1478 			(void)allocstring(&oldline2, DiaGetTextProgress(io_inputprogressdialog), el_tempcluster);
1479 		}
1480 
1481 		len = estrlen(libfilename);
1482 		io_libinputrecursivedepth++;
1483 		io_libinputreadmany++;
1484 		if (len > 4 && namesame(&libfilename[len-4], x_(".txt")) == 0)
1485 		{
1486 			/* ends in ".txt", presume text file */
1487 			failed = io_doreadtextlibrary(elib, FALSE);
1488 		} else
1489 		{
1490 			/* all other endings: presume binary file */
1491 			failed = io_doreadbinlibrary(elib, FALSE);
1492 		}
1493 		io_libinputrecursivedepth--;
1494 		if (failed) elib->userbits |= UNWANTEDLIB; else
1495 		{
1496 			/* queue this library for announcement through change control */
1497 			io_queuereadlibraryannouncement(elib);
1498 		}
1499 		io_txtindata = savetxtindata;
1500 		if (io_verbose < 0 && io_txtindata.filelength > 0 && io_inputprogressdialog != 0)
1501 		{
1502 			DiaSetProgress(io_inputprogressdialog, io_txtindata.fileposition, io_txtindata.filelength);
1503 			infstr = initinfstr();
1504 			formatinfstr(infstr, _("Reading library %s"), io_txtindata.curlib->libname);
1505 			DiaSetCaptionProgress(io_inputprogressdialog, returninfstr(infstr));
1506 			DiaSetTextProgress(io_inputprogressdialog, oldline2);
1507 			efree(oldline2);
1508 		}
1509 	}
1510 
1511 	/* find this cell in the external library */
1512 	cellname = io_txtindata.curnodeproto->protoname;
1513 	for(np = elib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1514 	{
1515 		if (namesame(np->protoname, cellname) != 0) continue;
1516 		if (np->cellview != io_txtindata.curnodeproto->cellview) continue;
1517 		if (np->version != io_txtindata.curnodeproto->version) continue;
1518 		break;
1519 	}
1520 	if (np == NONODEPROTO)
1521 	{
1522 		/* cell not found in library: issue warning */
1523 		infstr = initinfstr();
1524 		addstringtoinfstr(infstr, cellname);
1525 		if (io_txtindata.curnodeproto->cellview != el_unknownview)
1526 		{
1527 			addtoinfstr(infstr, '{');
1528 			addstringtoinfstr(infstr, io_txtindata.curnodeproto->cellview->sviewname);
1529 			addtoinfstr(infstr, '}');
1530 		}
1531 		ttyputerr(_("Cannot find cell %s in library %s..creating dummy version"),
1532 			returninfstr(infstr), elib->libname);
1533 	} else
1534 	{
1535 		/* cell found: make sure it is valid */
1536 		if (np->revisiondate != io_txtindata.curnodeproto->revisiondate ||
1537 			np->lowx != io_txtindata.curnodeproto->lowx ||
1538 			np->highx != io_txtindata.curnodeproto->highx ||
1539 			np->lowy != io_txtindata.curnodeproto->lowy ||
1540 			np->highy != io_txtindata.curnodeproto->highy)
1541 		{
1542 			ttyputerr(_("Warning: cell %s in library %s has been modified"),
1543 				describenodeproto(np), elib->libname);
1544 			np = NONODEPROTO;
1545 		}
1546 	}
1547 	if (np != NONODEPROTO)
1548 	{
1549 		/* get rid of existing cell and plug in the external reference */
1550 		onp = io_txtindata.nodeprotolist[io_txtindata.curcellnumber];
1551 		db_retractnodeproto(onp);
1552 		freenodeproto(onp);
1553 		io_txtindata.nodeprotolist[io_txtindata.curcellnumber] = np;
1554 	} else
1555 	{
1556 		/* rename the cell */
1557 		np = io_txtindata.curnodeproto;
1558 		infstr = initinfstr();
1559 		formatinfstr(infstr, x_("%sFROM%s"), cellname, elib->libname);
1560 		db_retractnodeproto(np);
1561 
1562 		cellname = returninfstr(infstr);
1563 		(void)allocstring(&np->protoname, cellname, io_txtindata.curlib->cluster);
1564 		db_insertnodeproto(np);
1565 
1566 		/* create an artwork "Crossed box" to define the cell size */
1567 		ni = allocnodeinst(io_txtindata.curlib->cluster);
1568 		ni->proto = art_crossedboxprim;
1569 		ni->parent = np;
1570 		ni->nextnodeinst = np->firstnodeinst;
1571 		np->firstnodeinst = ni;
1572 		ni->lowx = np->lowx;   ni->highx = np->highx;
1573 		ni->lowy = np->lowy;   ni->highy = np->highy;
1574 		ni->geom = allocgeom(io_txtindata.curlib->cluster);
1575 		ni->geom->entryisnode = TRUE;   ni->geom->entryaddr.ni = ni;
1576 		linkgeom(ni->geom, np);
1577 	}
1578 }
1579 
1580 /*
1581  * get the boundary of the current cell
1582  */
io_cellx(void)1583 void io_cellx(void)
1584 {
1585 	io_txtindata.curnodeproto->lowx = eatoi(io_keyword);
1586 }
1587 
io_celhx(void)1588 void io_celhx(void)
1589 {
1590 	io_txtindata.curnodeproto->highx = eatoi(io_keyword);
1591 }
1592 
io_celly(void)1593 void io_celly(void)
1594 {
1595 	io_txtindata.curnodeproto->lowy = eatoi(io_keyword);
1596 }
1597 
io_celhy(void)1598 void io_celhy(void)
1599 {
1600 	io_txtindata.curnodeproto->highy = eatoi(io_keyword);
1601 }
1602 
1603 /*
1604  * get the default technology for objects in this cell (keyword "technology")
1605  */
io_tech(void)1606 void io_tech(void)
1607 {
1608 	REGISTER TECHNOLOGY *tech;
1609 
1610 	tech = io_gettechnology(io_keyword);
1611 	if (tech == NOTECHNOLOGY) longjmp(io_filerror, LONGJMPUKNTECH);
1612 	io_txtindata.curtech = tech;
1613 }
1614 
1615 /*
1616  * get the tool dirty word for the current cell (keyword "aadirty")
1617  */
io_celaad(void)1618 void io_celaad(void)
1619 {
1620 	io_txtindata.curnodeproto->adirty = eatoi(io_keyword);
1621 	io_txtindata.bitcount = 0;
1622 }
1623 
1624 /*
1625  * get tool information for current cell (keyword "bits")
1626  */
io_celbit(void)1627 void io_celbit(void)
1628 {
1629 	if (io_txtindata.bitcount == 0) io_txtindata.curnodeproto->userbits = eatoi(io_keyword);
1630 	io_txtindata.bitcount++;
1631 }
1632 
1633 /*
1634  * get tool information for current cell (keyword "userbits")
1635  */
io_celusb(void)1636 void io_celusb(void)
1637 {
1638 	io_txtindata.curnodeproto->userbits = eatoi(io_keyword);
1639 }
1640 
1641 /*
1642  * get tool information for current cell (keyword "netnum")
1643  */
io_celnet(void)1644 void io_celnet(void) {}
1645 
1646 /*
1647  * get the number of node instances in the current cell (keyword "nodes")
1648  */
io_celnoc(void)1649 void io_celnoc(void)
1650 {
1651 	REGISTER INTBIG i;
1652 	REGISTER NODEINST *ni;
1653 	REGISTER GEOM **geomlist;
1654 
1655 	io_txtindata.nodeinstcount = eatoi(io_keyword);
1656 	if (io_txtindata.nodeinstcount == 0) return;
1657 	io_txtindata.nodelist = (NODEINST **)emalloc(((sizeof (NODEINST *)) * io_txtindata.nodeinstcount),
1658 		el_tempcluster);
1659 	if (io_txtindata.nodelist == 0) longjmp(io_filerror, LONGJMPNOMEM);
1660 	geomlist = (GEOM **)emalloc(((sizeof (GEOM *)) * io_txtindata.nodeinstcount), el_tempcluster);
1661 	if (geomlist == 0) longjmp(io_filerror, LONGJMPNOMEM);
1662 	for(i=0; i<io_txtindata.nodeinstcount; i++)
1663 	{
1664 		ni = allocnodeinst(io_txtindata.curlib->cluster);
1665 		geomlist[i] = allocgeom(io_txtindata.curlib->cluster);
1666 		if (ni == NONODEINST || geomlist[i] == NOGEOM)
1667 			longjmp(io_filerror, LONGJMPNOMEM);
1668 		io_txtindata.nodelist[i] = ni;
1669 		ni->parent = io_txtindata.curnodeproto;
1670 		ni->firstportarcinst = NOPORTARCINST;
1671 		ni->firstportexpinst = NOPORTEXPINST;
1672 		ni->geom = geomlist[i];
1673 
1674 		/* compute linked list of nodes in this cell */
1675 		if (io_txtindata.curnodeproto->firstnodeinst != NONODEINST)
1676 			io_txtindata.curnodeproto->firstnodeinst->prevnodeinst = ni;
1677 		ni->nextnodeinst = io_txtindata.curnodeproto->firstnodeinst;
1678 		ni->prevnodeinst = NONODEINST;
1679 		io_txtindata.curnodeproto->firstnodeinst = ni;
1680 	}
1681 	efree((CHAR *)geomlist);
1682 }
1683 
1684 /*
1685  * get the number of arc instances in the current cell (keyword "arcs")
1686  */
io_celarc(void)1687 void io_celarc(void)
1688 {
1689 	REGISTER INTBIG i;
1690 	REGISTER ARCINST *ai;
1691 	REGISTER GEOM **geomlist;
1692 
1693 	io_txtindata.arcinstcount = eatoi(io_keyword);
1694 	if (io_txtindata.arcinstcount == 0) return;
1695 	io_txtindata.arclist = (ARCINST **)emalloc(((sizeof (ARCINST *)) * io_txtindata.arcinstcount),
1696 		el_tempcluster);
1697 	if (io_txtindata.arclist == 0) longjmp(io_filerror, LONGJMPNOMEM);
1698 	geomlist = (GEOM **)emalloc(((sizeof (GEOM *)) * io_txtindata.arcinstcount), el_tempcluster);
1699 	if (geomlist == 0) longjmp(io_filerror, LONGJMPNOMEM);
1700 	for(i=0; i<io_txtindata.arcinstcount; i++)
1701 	{
1702 		ai = allocarcinst(io_txtindata.curlib->cluster);
1703 		geomlist[i] = allocgeom(io_txtindata.curlib->cluster);
1704 		if (ai == NOARCINST || geomlist[i] == NOGEOM)
1705 			longjmp(io_filerror, LONGJMPNOMEM);
1706 		io_txtindata.arclist[i] = ai;
1707 		ai->parent = io_txtindata.curnodeproto;
1708 		ai->geom = geomlist[i];
1709 
1710 		/* compute linked list of arcs in this cell */
1711 		if (io_txtindata.curnodeproto->firstarcinst != NOARCINST)
1712 			io_txtindata.curnodeproto->firstarcinst->prevarcinst = ai;
1713 		ai->nextarcinst = io_txtindata.curnodeproto->firstarcinst;
1714 		ai->prevarcinst = NOARCINST;
1715 		io_txtindata.curnodeproto->firstarcinst = ai;
1716 	}
1717 	efree((CHAR *)geomlist);
1718 }
1719 
1720 /*
1721  * get the number of port prototypes in the current cell (keyword "porttypes")
1722  */
io_celptc(void)1723 void io_celptc(void)
1724 {
1725 	REGISTER INTBIG i;
1726 
1727 	io_txtindata.portprotocount = eatoi(io_keyword);
1728 	io_txtindata.curnodeproto->numportprotos = io_txtindata.portprotocount;
1729 	if (io_txtindata.portprotocount == 0) return;
1730 	io_txtindata.portprotolist = (PORTPROTO **)emalloc(((sizeof (PORTPROTO *)) *
1731 		io_txtindata.portprotocount), el_tempcluster);
1732 	if (io_txtindata.portprotolist == 0) longjmp(io_filerror, LONGJMPNOMEM);
1733 	for(i=0; i<io_txtindata.portprotocount; i++)
1734 	{
1735 		io_txtindata.portprotolist[i] = allocportproto(io_txtindata.curlib->cluster);
1736 		if (io_txtindata.portprotolist[i] == NOPORTPROTO)
1737 			longjmp(io_filerror, LONGJMPNOMEM);
1738 		io_txtindata.portprotolist[i]->parent = io_txtindata.curnodeproto;
1739 	}
1740 
1741 	/* link the portprotos */
1742 	io_txtindata.curnodeproto->firstportproto = io_txtindata.portprotolist[0];
1743 	for(i=1; i<io_txtindata.portprotocount; i++)
1744 		io_txtindata.portprotolist[i-1]->nextportproto = io_txtindata.portprotolist[i];
1745 	io_txtindata.portprotolist[io_txtindata.portprotocount-1]->nextportproto = NOPORTPROTO;
1746 }
1747 
1748 /*
1749  * close the current cell (keyword "celldone")
1750  */
io_celdon(void)1751 void io_celdon(void)
1752 {
1753 	REGISTER INTBIG i;
1754 	REGISTER NODEINST *ni;
1755 	REGISTER ARCINST *ai;
1756 	REGISTER PORTARCINST *pi;
1757 	REGISTER GEOM *geom;
1758 
1759 	/* verify cell name */
1760 	if (namesame(io_keyword, io_txtindata.curnodeproto->protoname) != 0)
1761 		ttyputmsg(_("Warning: cell '%s' wants to be '%s'"),
1762 			io_txtindata.curnodeproto->protoname, io_keyword);
1763 
1764 	/* silly hack: convert arcinst->end->portarcinst pointers */
1765 	for(i=0; i<io_txtindata.nodeinstcount; i++)
1766 	{
1767 		ni = io_txtindata.nodelist[i];
1768 		for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1769 		{
1770 			ai = pi->conarcinst;
1771 			if (ai->end[0].nodeinst != ni)
1772 			{
1773 				ai->end[1].portarcinst = pi;
1774 				continue;
1775 			}
1776 			if (ai->end[1].nodeinst != ni)
1777 			{
1778 				ai->end[0].portarcinst = pi;
1779 				continue;
1780 			}
1781 			if ((PORTPROTO *)ai->end[0].portarcinst == pi->proto) ai->end[0].portarcinst = pi;
1782 			if ((PORTPROTO *)ai->end[1].portarcinst == pi->proto) ai->end[1].portarcinst = pi;
1783 		}
1784 	}
1785 
1786 	/* create geometry structure in the cell */
1787 	if (geomstructure(io_txtindata.curnodeproto))
1788 		longjmp(io_filerror, LONGJMPNOMEM);
1789 
1790 	/* fill geometry module for each nodeinst */
1791 	for(i=0; i<io_txtindata.nodeinstcount; i++)
1792 	{
1793 		ni = io_txtindata.nodelist[i];
1794 		geom = ni->geom;
1795 		geom->entryisnode = TRUE;  geom->entryaddr.ni = ni;
1796 		linkgeom(geom, io_txtindata.curnodeproto);
1797 	}
1798 
1799 	/* fill geometry modules for each arcinst */
1800 	for(i=0; i<io_txtindata.arcinstcount; i++)
1801 	{
1802 		ai = io_txtindata.arclist[i];
1803 		(void)setshrinkvalue(ai, FALSE);
1804 		geom = ai->geom;
1805 		geom->entryisnode = FALSE;  geom->entryaddr.ai = ai;
1806 		linkgeom(geom, io_txtindata.curnodeproto);
1807 	}
1808 
1809 	/* free the lists of objects in this cell */
1810 	if (io_txtindata.nodeinstcount != 0) efree((CHAR *)io_txtindata.nodelist);
1811 	if (io_txtindata.portprotocount != 0) efree((CHAR *)io_txtindata.portprotolist);
1812 	if (io_txtindata.arcinstcount != 0) efree((CHAR *)io_txtindata.arclist);
1813 }
1814 
1815 /******************** NODE INSTANCE PARSING ROUTINES ********************/
1816 
1817 /*
1818  * initialize for a new node instance (keyword "**node")
1819  */
io_newno(void)1820 void io_newno(void)
1821 {
1822 	io_txtindata.curnodeinst = io_txtindata.nodelist[eatoi(io_keyword)];
1823 	io_txtindata.textlevel = INNODEINST;
1824 	io_txtindata.varpos = INVNODEINST;
1825 }
1826 
1827 /*
1828  * get the type of the current nodeinst (keyword "type")
1829  */
io_nodtyp(void)1830 void io_nodtyp(void)
1831 {
1832 	REGISTER NODEPROTO *np;
1833 	REGISTER TECHNOLOGY *tech;
1834 	REGISTER CHAR *pt, *line;
1835 	CHAR orig[50];
1836 	static INTBIG orignodenamekey = 0;
1837 
1838 	line = io_keyword;
1839 	if (*line == '[')
1840 	{
1841 		io_txtindata.curnodeinst->proto = io_txtindata.nodeprotolist[eatoi(&line[1])];
1842 	} else
1843 	{
1844 		for(pt = line; *pt != 0; pt++) if (*pt == ':') break;
1845 		if (*pt == ':')
1846 		{
1847 			*pt = 0;
1848 			tech = io_gettechnology(line);
1849 			if (tech == NOTECHNOLOGY) longjmp(io_filerror, LONGJMPUKNTECH);
1850 			*pt++ = ':';
1851 			line = pt;
1852 		} else tech = io_txtindata.curtech;
1853 		if (io_txtindata.curtech == NOTECHNOLOGY) io_txtindata.curtech = tech;
1854 		for(np = tech->firstnodeproto; np != NONODEPROTO;
1855 			np = np->nextnodeproto) if (namesame(np->protoname, line) == 0)
1856 		{
1857 			io_txtindata.curnodeinst->proto = np;
1858 			return;
1859 		}
1860 
1861 		/* convert "Active-Node" to "P-Active-Node" (MOSIS CMOS) */
1862 		if (estrcmp(line, x_("Active-Node")) == 0)
1863 		{
1864 			for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1865 				if (estrcmp(np->protoname, x_("P-Active-Node")) == 0)
1866 			{
1867 				io_txtindata.curnodeinst->proto = np;
1868 				return;
1869 			}
1870 		}
1871 
1872 		/* convert "message" and "cell-center" nodes */
1873 		io_txtindata.curnodeinst->proto = io_convertoldprimitives(tech, line);
1874 		if (io_txtindata.curnodeinst->proto == gen_invispinprim)
1875 		{
1876 			(void)estrcpy(orig, x_("artwork:"));
1877 			(void)estrcat(orig, line);
1878 			if (orignodenamekey == 0) orignodenamekey = makekey(x_("NODE_original_name"));
1879 			nextchangequiet();
1880 			(void)setvalkey((INTBIG)io_txtindata.curnodeinst, VNODEINST,
1881 				orignodenamekey, (INTBIG)orig, VSTRING|VDONTSAVE);
1882 		}
1883 		if (io_txtindata.curnodeinst->proto != NONODEPROTO) return;
1884 
1885 		longjmp(io_filerror, LONGJMPUKNNOPROTO);
1886 	}
1887 }
1888 
1889 /*
1890  * get the bounding box information for the current node instance
1891  */
io_nodlx(void)1892 void io_nodlx(void)
1893 {
1894 	io_txtindata.curnodeinst->lowx = eatoi(io_keyword);
1895 }
1896 
io_nodhx(void)1897 void io_nodhx(void)
1898 {
1899 	io_txtindata.curnodeinst->highx = eatoi(io_keyword);
1900 }
1901 
io_nodly(void)1902 void io_nodly(void)
1903 {
1904 	io_txtindata.curnodeinst->lowy = eatoi(io_keyword);
1905 }
1906 
io_nodhy(void)1907 void io_nodhy(void)
1908 {
1909 	io_txtindata.curnodeinst->highy = eatoi(io_keyword);
1910 }
1911 
1912 /*
1913  * get the instance name of the current node instance (keyword "name")
1914  */
io_nodnam(void)1915 void io_nodnam(void)
1916 {
1917 	nextchangequiet();
1918 	(void)setvalkey((INTBIG)io_txtindata.curnodeinst, VNODEINST, el_node_name_key,
1919 		(INTBIG)io_keyword, VSTRING|VDISPLAY);
1920 }
1921 
1922 /*
1923  * get the text descriptor of the current node instance (keyword "descript")
1924  */
io_noddes(void)1925 void io_noddes(void)
1926 {
1927 	REGISTER CHAR *pt;
1928 
1929 	io_txtindata.curnodeinst->textdescript[0] = eatoi(io_keyword);
1930 	for(pt = io_keyword; *pt != 0 && *pt != '/'; pt++) ;
1931 	if (*pt == 0)
1932 	{
1933 		io_txtindata.curnodeinst->textdescript[1] = 0;
1934 	} else
1935 	{
1936 		io_txtindata.curnodeinst->textdescript[1] = eatoi(pt+1);
1937 	}
1938 }
1939 
1940 /*
1941  * get the rotation for the current nodeinst (keyword "rotation");
1942  */
io_nodrot(void)1943 void io_nodrot(void)
1944 {
1945 	io_txtindata.curnodeinst->rotation = eatoi(io_keyword);
1946 }
1947 
1948 /*
1949  * get the transposition for the current nodeinst (keyword "transpose")
1950  */
io_nodtra(void)1951 void io_nodtra(void)
1952 {
1953 	REGISTER INTSML tvalue;
1954 
1955 	tvalue = eatoi(io_keyword);
1956 
1957 	/* in 7.01 and higher, allow mirror bits */
1958 	if (io_txtindata.emajor > 7 ||
1959 		(io_txtindata.emajor == 7 && io_txtindata.eminor >= 1))
1960 	{
1961 		/* new version: allow mirror bits */
1962 		io_txtindata.curnodeinst->transpose = 0;
1963 		if ((tvalue&1) != 0)
1964 		{
1965 			/* the old-style transpose bit */
1966 			io_txtindata.curnodeinst->transpose = 1;
1967 		} else
1968 		{
1969 			/* check for new style mirror bits */
1970 			if ((tvalue&2) != 0)
1971 			{
1972 				if ((tvalue&4) != 0)
1973 				{
1974 					/* mirror in X and Y */
1975 					io_txtindata.curnodeinst->rotation = (io_txtindata.curnodeinst->rotation + 1800) % 3600;
1976 				} else
1977 				{
1978 					/* mirror in X */
1979 					io_txtindata.curnodeinst->rotation = (io_txtindata.curnodeinst->rotation + 900) % 3600;
1980 					io_txtindata.curnodeinst->transpose = 1;
1981 				}
1982 			} else if ((tvalue&4) != 0)
1983 			{
1984 				/* mirror in Y */
1985 				io_txtindata.curnodeinst->rotation = (io_txtindata.curnodeinst->rotation + 2700) % 3600;
1986 				io_txtindata.curnodeinst->transpose = 1;
1987 			}
1988 		}
1989 	} else
1990 	{
1991 		/* old version: just treat it as a transpose */
1992 		io_txtindata.curnodeinst->transpose = tvalue;
1993 	}
1994 }
1995 
1996 /*
1997  * get the tool seen bits for the current nodeinst (keyword "aseen")
1998  */
io_nodkse(void)1999 void io_nodkse(void)
2000 {
2001 	io_txtindata.bitcount = 0;
2002 }
2003 
2004 /*
2005  * get the port count for the current nodeinst (keyword "ports")
2006  */
io_nodpoc(void)2007 void io_nodpoc(void)
2008 {
2009 	io_txtindata.curportcount = eatoi(io_keyword);
2010 }
2011 
2012 /*
2013  * get tool information for current nodeinst (keyword "bits")
2014  */
io_nodbit(void)2015 void io_nodbit(void)
2016 {
2017 	if (io_txtindata.bitcount == 0) io_txtindata.curnodeinst->userbits = eatoi(io_keyword);
2018 	io_txtindata.bitcount++;
2019 }
2020 
2021 /*
2022  * get tool information for current nodeinst (keyword "userbits")
2023  */
io_nodusb(void)2024 void io_nodusb(void)
2025 {
2026 	io_txtindata.curnodeinst->userbits = eatoi(io_keyword);
2027 }
2028 
2029 /*
2030  * initialize for a new portinst on the current nodeinst (keyword "*port")
2031  */
io_newpor(void)2032 void io_newpor(void)
2033 {
2034 	REGISTER INTBIG i, cindex;
2035 	REGISTER PORTPROTO *pp;
2036 
2037 	if (io_txtindata.version[0] == '1')
2038 	{
2039 		/* version 1 files used an index here */
2040 		cindex = eatoi(io_keyword);
2041 
2042 		/* dividing is a heuristic used to decypher version 1 files */
2043 		for(pp = io_txtindata.curnodeinst->proto->firstportproto, i=0; pp != NOPORTPROTO;
2044 			pp = pp->nextportproto) i++;
2045 		if (i < io_txtindata.curportcount)
2046 		{
2047 			for(;;)
2048 			{
2049 				cindex /= 3;
2050 				if (cindex < i) break;
2051 			}
2052 		}
2053 
2054 		for(io_txtindata.curportproto = io_txtindata.curnodeinst->proto->firstportproto, i=0;
2055 			io_txtindata.curportproto != NOPORTPROTO;
2056 				io_txtindata.curportproto = io_txtindata.curportproto->nextportproto, i++)
2057 					if (i == cindex) break;
2058 	} else
2059 	{
2060 		/* version 2 and later use port prototype names */
2061 		io_txtindata.curportproto = io_getport(io_keyword, io_txtindata.curnodeinst->proto);
2062 	}
2063 	io_txtindata.textlevel = INPOR;
2064 }
2065 
2066 /*
2067  * get an arc connection for the current nodeinst (keyword "arc")
2068  */
io_porarc(void)2069 void io_porarc(void)
2070 {
2071 	REGISTER PORTARCINST *pi;
2072 
2073 	pi = allocportarcinst(io_txtindata.curlib->cluster);
2074 	if (pi == NOPORTARCINST) longjmp(io_filerror, LONGJMPNOMEM);
2075 	pi->proto = io_txtindata.curportproto;
2076 	db_addportarcinst(io_txtindata.curnodeinst, pi);
2077 	pi->conarcinst = io_txtindata.arclist[eatoi(io_keyword)];
2078 	io_txtindata.varpos = INVPORTARCINST;
2079 	io_txtindata.varaddr = (INTBIG)pi;
2080 }
2081 
2082 /*
2083  * get an export site for the current nodeinst (keyword "exported")
2084  */
io_porexp(void)2085 void io_porexp(void)
2086 {
2087 	REGISTER PORTEXPINST *pe;
2088 
2089 	pe = allocportexpinst(io_txtindata.curlib->cluster);
2090 	if (pe == NOPORTEXPINST) longjmp(io_filerror, LONGJMPNOMEM);
2091 	pe->proto = io_txtindata.curportproto;
2092 	db_addportexpinst(io_txtindata.curnodeinst, pe);
2093 	pe->exportproto = io_txtindata.portprotolist[eatoi(io_keyword)];
2094 	io_txtindata.varpos = INVPORTEXPINST;
2095 	io_txtindata.varaddr = (INTBIG)pe;
2096 }
2097 
2098 /******************** ARC INSTANCE PARSING ROUTINES ********************/
2099 
2100 /*
2101  * initialize for a new arc instance (keyword "**arc")
2102  */
io_newar(void)2103 void io_newar(void)
2104 {
2105 	io_txtindata.curarcinst = io_txtindata.arclist[eatoi(io_keyword)];
2106 	io_txtindata.textlevel = INARCINST;
2107 	io_txtindata.varpos = INVARCINST;
2108 }
2109 
2110 /*
2111  * get the type of the current arc instance (keyword "type")
2112  */
io_arctyp(void)2113 void io_arctyp(void)
2114 {
2115 	REGISTER ARCPROTO *ap;
2116 	REGISTER CHAR *pt, *line;
2117 	REGISTER TECHNOLOGY *tech;
2118 
2119 	line = io_keyword;
2120 	for(pt = line; *pt != 0; pt++) if (*pt == ':') break;
2121 	if (*pt == ':')
2122 	{
2123 		*pt = 0;
2124 		tech = io_gettechnology(line);
2125 		if (tech == NOTECHNOLOGY) longjmp(io_filerror, LONGJMPUKNTECH);
2126 		*pt++ = ':';
2127 		line = pt;
2128 	} else tech = io_txtindata.curtech;
2129 	if (io_txtindata.curtech == NOTECHNOLOGY) io_txtindata.curtech = tech;
2130 	for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
2131 		if (namesame(line, ap->protoname) == 0)
2132 	{
2133 		io_txtindata.curarcinst->proto = ap;
2134 		return;
2135 	}
2136 
2137 	/* convert old Artwork names */
2138 	if (tech == art_tech)
2139 	{
2140 		if (estrcmp(line, x_("Dash-1")) == 0)
2141 		{
2142 			io_txtindata.curarcinst->proto = art_dottedarc;
2143 			return;
2144 		}
2145 		if (estrcmp(line, x_("Dash-2")) == 0)
2146 		{
2147 			io_txtindata.curarcinst->proto = art_dashedarc;
2148 			return;
2149 		}
2150 		if (estrcmp(line, x_("Dash-3")) == 0)
2151 		{
2152 			io_txtindata.curarcinst->proto = art_thickerarc;
2153 			return;
2154 		}
2155 	}
2156 
2157 	/* special hack: try the generic technology if name is not found */
2158 	for(ap = gen_tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
2159 		if (namesame(line, ap->protoname) == 0)
2160 	{
2161 		io_txtindata.curarcinst->proto = ap;
2162 		return;
2163 	}
2164 
2165 	longjmp(io_filerror, LONGJMPINVARCPROTO);
2166 }
2167 
2168 /*
2169  * get the instance name of the current arc instance (keyword "name")
2170  */
io_arcnam(void)2171 void io_arcnam(void)
2172 {
2173 	nextchangequiet();
2174 	(void)setvalkey((INTBIG)io_txtindata.curarcinst, VARCINST, el_arc_name_key,
2175 		(INTBIG)io_keyword, VSTRING|VDISPLAY);
2176 }
2177 
2178 /*
2179  * get the width of the current arc instance (keyword "width")
2180  */
io_arcwid(void)2181 void io_arcwid(void)
2182 {
2183 	io_txtindata.curarcinst->width = eatoi(io_keyword);
2184 }
2185 
2186 /*
2187  * get the length of the current arc instance (keyword "length")
2188  */
io_arclen(void)2189 void io_arclen(void)
2190 {
2191 	io_txtindata.curarcinst->length = eatoi(io_keyword);
2192 }
2193 
2194 /*
2195  * get the signals information of the current arc instance (keyword "signals")
2196  */
io_arcsig(void)2197 void io_arcsig(void) {}
2198 
2199 /*
2200  * initialize for an end of the current arcinst (keyword "*end")
2201  */
io_newend(void)2202 void io_newend(void)
2203 {
2204 	io_txtindata.curarcend = eatoi(io_keyword);
2205 	io_txtindata.textlevel = INARCEND;
2206 }
2207 
2208 /*
2209  * get the node at the current end of the current arcinst (keyword "node")
2210  */
io_endnod(void)2211 void io_endnod(void)
2212 {
2213 	io_txtindata.curarcinst->end[io_txtindata.curarcend].nodeinst = io_txtindata.nodelist[eatoi(io_keyword)];
2214 }
2215 
2216 /*
2217  * get the porttype at the current end of current arcinst (keyword "nodeport")
2218  */
io_endpt(void)2219 void io_endpt(void)
2220 {
2221 	REGISTER PORTPROTO *pp;
2222 
2223 	pp = io_getport(io_keyword,io_txtindata.curarcinst->end[io_txtindata.curarcend].nodeinst->proto);
2224 	if (pp == NOPORTPROTO) longjmp(io_filerror, LONGJMPUKNPORPROTO);
2225 	io_txtindata.curarcinst->end[io_txtindata.curarcend].portarcinst = (PORTARCINST *)pp;
2226 }
2227 
2228 /*
2229  * get the coordinates of the current end of the current arcinst
2230  */
io_endxp(void)2231 void io_endxp(void)
2232 {
2233 	io_txtindata.curarcinst->end[io_txtindata.curarcend].xpos = eatoi(io_keyword);
2234 }
2235 
io_endyp(void)2236 void io_endyp(void)
2237 {
2238 	io_txtindata.curarcinst->end[io_txtindata.curarcend].ypos = eatoi(io_keyword);
2239 }
2240 
2241 /*
2242  * get the tool information for the current arcinst (keyword "aseen")
2243  */
io_arckse(void)2244 void io_arckse(void)
2245 {
2246 	io_txtindata.bitcount = 0;
2247 }
2248 
2249 /*
2250  * get tool information for current arcinst (keyword "bits")
2251  */
io_arcbit(void)2252 void io_arcbit(void)
2253 {
2254 	if (io_txtindata.bitcount == 0) io_txtindata.curarcinst->userbits = eatoi(io_keyword);
2255 	io_txtindata.bitcount++;
2256 }
2257 
2258 /*
2259  * get tool information for current arcinst (keyword "userbits")
2260  */
io_arcusb(void)2261 void io_arcusb(void)
2262 {
2263 	io_txtindata.curarcinst->userbits = eatoi(io_keyword);
2264 }
2265 
2266 /*
2267  * get tool information for current arcinst (keyword "netnum")
2268  */
io_arcnet(void)2269 void io_arcnet(void) {}
2270 
2271 /******************** PORT PROTOTYPE PARSING ROUTINES ********************/
2272 
2273 /*
2274  * initialize for a new port prototype (keyword "**porttype")
2275  */
io_newpt(void)2276 void io_newpt(void)
2277 {
2278 	io_txtindata.curportproto = io_txtindata.portprotolist[eatoi(io_keyword)];
2279 	io_txtindata.textlevel = INPORTPROTO;
2280 	io_txtindata.varpos = INVPORTPROTO;
2281 }
2282 
2283 /*
2284  * get the name for the current port prototype (keyword "name")
2285  */
io_ptnam(void)2286 void io_ptnam(void)
2287 {
2288 	if (allocstring(&io_txtindata.curportproto->protoname, io_keyword, io_txtindata.curlib->cluster))
2289 		longjmp(io_filerror, LONGJMPNOMEM);
2290 }
2291 
2292 /*
2293  * get the text descriptor for the current port prototype (keyword "descript")
2294  */
io_ptdes(void)2295 void io_ptdes(void)
2296 {
2297 	REGISTER CHAR *pt;
2298 
2299 	io_txtindata.curportproto->textdescript[0] = eatoi(io_keyword);
2300 	for(pt = io_keyword; *pt != 0 && *pt != '/'; pt++) ;
2301 	if (*pt == 0)
2302 	{
2303 		io_txtindata.curportproto->textdescript[1] = 0;
2304 	} else
2305 	{
2306 		io_txtindata.curportproto->textdescript[1] = eatoi(pt+1);
2307 	}
2308 }
2309 
2310 /*
2311  * get the sub-nodeinst for the current port prototype (keyword "subnode")
2312  */
io_ptsno(void)2313 void io_ptsno(void)
2314 {
2315 	io_txtindata.curportproto->subnodeinst = io_txtindata.nodelist[eatoi(io_keyword)];
2316 }
2317 
2318 /*
2319  * get the sub-portproto for the current port prototype (keyword "subport")
2320  */
io_ptspt(void)2321 void io_ptspt(void)
2322 {
2323 	REGISTER PORTPROTO *pp;
2324 
2325 	pp = io_getport(io_keyword, io_txtindata.curportproto->subnodeinst->proto);
2326 	if (pp == NOPORTPROTO) longjmp(io_filerror, LONGJMPUKNPORPROTO);
2327 	io_txtindata.curportproto->subportproto = pp;
2328 }
2329 
2330 /*
2331  * get the tool seen for the current port prototype (keyword "aseen")
2332  */
io_ptkse(void)2333 void io_ptkse(void)
2334 {
2335 	io_txtindata.bitcount = 0;
2336 }
2337 
2338 /*
2339  * get the tool data for the current port prototype (keyword "bits")
2340  */
io_ptbit(void)2341 void io_ptbit(void)
2342 {
2343 	if (io_txtindata.bitcount == 0) io_txtindata.curportproto->userbits = eatoi(io_keyword);
2344 	io_txtindata.bitcount++;
2345 }
2346 
2347 /*
2348  * get the tool data for the current port prototype (keyword "userbits")
2349  */
io_ptusb(void)2350 void io_ptusb(void)
2351 {
2352 	io_txtindata.curportproto->userbits = eatoi(io_keyword);
2353 }
2354 
2355 /*
2356  * get the tool data for the current port prototype (keyword "netnum")
2357  */
io_ptnet(void)2358 void io_ptnet(void) {}
2359 
2360 /*
2361  * routine to convert the technology name in "line" to a technology.
2362  * also handles conversion of the old technology name "logic"
2363  */
io_gettechnology(CHAR * line)2364 TECHNOLOGY *io_gettechnology(CHAR *line)
2365 {
2366 	REGISTER TECHNOLOGY *tech;
2367 
2368 	tech = NOTECHNOLOGY;
2369 	if (io_txtindata.convertmosiscmostechnologies != 0)
2370 	{
2371 		if (namesame(line, x_("mocmossub")) == 0) tech = gettechnology(x_("mocmos")); else
2372 			if (namesame(line, x_("mocmos")) == 0) tech = gettechnology(x_("mocmosold"));
2373 	}
2374 	if (tech == NOTECHNOLOGY) tech = gettechnology(line);
2375 	if (tech != NOTECHNOLOGY) return(tech);
2376 	if (namesame(line, x_("logic")) == 0) tech = sch_tech;
2377 	return(tech);
2378 }
2379 
2380 /*
2381  * Routine to free all memory associated with this module.
2382  */
io_freetextinmemory(void)2383 void io_freetextinmemory(void)
2384 {
2385 	if (io_maxinputline != 0)
2386 		efree(io_keyword);
2387 }
2388