1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: iolefi.c
6  * Input/output tool: LEF (Library Exchange Format) reader
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 /*
33  * Note that this reader was built by examining LEF files and reverse-engineering them.
34  * It does not claim to be compliant with the LEF specification, but it also does not
35  * claim to define a new specification.  It is merely incomplete.
36  */
37 
38 #include "config.h"
39 #include "global.h"
40 #include "egraphics.h"
41 #include "efunction.h"
42 #include "edialogs.h"
43 #include "iolefdef.h"
44 #include "tecart.h"
45 #include "tecgen.h"
46 #include "eio.h"
47 #include "usr.h"
48 
49 /*************** LEF PATHS ***************/
50 
51 #define NOLEFPATH ((LEFPATH *)-1)
52 
53 typedef struct Ilefpath
54 {
55 	INTBIG     x[2], y[2];
56 	NODEINST  *ni[2];
57 	INTBIG     width;
58 	ARCPROTO  *arc;
59 	struct Ilefpath *nextlefpath;
60 } LEFPATH;
61 
62 LEFPATH *io_leffreepath = NOLEFPATH;
63 
64 /*************** MISCELLANEOUS ***************/
65 
66 #define MAXLINE 2500
67 
68 static INTBIG  io_leffilesize;
69 static INTBIG  io_leflineno;
70 static CHAR    io_lefline[MAXLINE];
71 static INTBIG  io_leflinepos;
72        VIADEF *io_leffirstviadef = NOVIADEF;
73 static void   *io_lefprogressdialog;
74 
75 /* prototypes for local routines */
76 static void       io_leffreepaths(LEFPATH *firstlp);
77 static ARCPROTO  *io_lefgetarc(INTBIG afunc);
78 static CHAR      *io_lefgetkeyword(FILE *f);
79 static NODEPROTO *io_lefgetnode(INTBIG lfunc);
80 static BOOLEAN    io_lefignoretosemicolon(FILE *f, CHAR *command);
81 static void       io_lefkillpath(LEFPATH *lp);
82 static LEFPATH   *io_lefnewpath(void);
83 static PORTPROTO *io_lefnewport(NODEPROTO *cell, NODEINST *ni, PORTPROTO *pp, CHAR *thename);
84 static void       io_lefparselayer(CHAR *layername, INTBIG *arcfunc, INTBIG *layerfunc);
85 static BOOLEAN    io_lefreadfile(FILE *f, LIBRARY *lib);
86 static BOOLEAN    io_lefreadlayer(FILE *f, LIBRARY *lib);
87 static BOOLEAN    io_lefreadmacro(FILE *f, LIBRARY *lib);
88 static BOOLEAN    io_lefreadvia(FILE *f, LIBRARY *lib);
89 static BOOLEAN    io_lefreadobs(FILE *f, NODEPROTO *cell);
90 static BOOLEAN    io_lefreadpin(FILE *f, NODEPROTO *cell);
91 static BOOLEAN    io_lefreadport(FILE *f, NODEPROTO *cell, CHAR *portname, INTBIG portbits);
92 static void       io_leffreevias(void);
93 
94 /*
95  * Routine to free all memory associated with this module.
96  */
io_freelefimemory(void)97 void io_freelefimemory(void)
98 {
99 	io_leffreevias();
100 }
101 
io_readleflibrary(LIBRARY * lib)102 BOOLEAN io_readleflibrary(LIBRARY *lib)
103 {
104 	FILE *fp;
105 	REGISTER BOOLEAN ret;
106 	CHAR *filename;
107 
108 	/* open the file */
109 	fp = xopen(lib->libfile, io_filetypelef, x_(""), &filename);
110 	if (fp == NULL)
111 	{
112 		ttyputerr(_("File %s not found"), lib->libfile);
113 		return(TRUE);
114 	}
115 
116 	/* remove any vias in the globals */
117 	io_leffreevias();
118 
119 	/* prepare for input */
120 	io_leffilesize = filesize(fp);
121 	io_lefprogressdialog = DiaInitProgress(_("Reading LEF file..."), 0);
122 	if (io_lefprogressdialog == 0)
123 	{
124 		xclose(fp);
125 		return(TRUE);
126 	}
127 	DiaSetProgress(io_lefprogressdialog, 0, io_leffilesize);
128 	io_leflineno = 0;
129 	io_leflinepos = 0;
130 	io_lefline[0] = 0;
131 
132 	/* read the file */
133 	ret = io_lefreadfile(fp, lib);
134 
135 	/* clean up */
136 	DiaDoneProgress(io_lefprogressdialog);
137 	xclose(fp);
138 	if (!ret) ttyputmsg(_("LEF file %s is read"), lib->libfile); else
139 		ttyputmsg(_("Error reading LEF file %s"), lib->libfile);
140 	return(FALSE);
141 }
142 
io_leffreevias(void)143 void io_leffreevias(void)
144 {
145 	VIADEF *vd;
146 
147 	while (io_leffirstviadef != NOVIADEF)
148 	{
149 		vd = io_leffirstviadef;
150 		io_leffirstviadef = io_leffirstviadef->nextviadef;
151 		efree((CHAR *)vd->vianame);
152 		efree((CHAR *)vd);
153 	}
154 }
155 
156 /*
157  * Routine to read the LEF file in "f".
158  */
io_lefreadfile(FILE * f,LIBRARY * lib)159 BOOLEAN io_lefreadfile(FILE *f, LIBRARY *lib)
160 {
161 	REGISTER CHAR *key;
162 
163 	for(;;)
164 	{
165 		/* get the next keyword */
166 		key = io_lefgetkeyword(f);
167 		if (key == 0) break;
168 		if (namesame(key, x_("LAYER")) == 0)
169 		{
170 			if (io_lefreadlayer(f, lib)) return(TRUE);
171 		}
172 		if (namesame(key, x_("MACRO")) == 0)
173 		{
174 			if (io_lefreadmacro(f, lib)) return(TRUE);
175 		}
176 		if (namesame(key, x_("VIA")) == 0)
177 		{
178 			if (io_lefreadvia(f, lib)) return(TRUE);
179 		}
180 	}
181 	return(FALSE);
182 }
183 
io_lefparselayer(CHAR * layername,INTBIG * arcfunc,INTBIG * layerfunc)184 void io_lefparselayer(CHAR *layername, INTBIG *arcfunc, INTBIG *layerfunc)
185 {
186 	REGISTER INTBIG laynum, j;
187 
188 	*arcfunc = APUNKNOWN;
189 	*layerfunc = LFUNKNOWN;
190 
191 	j = 0;
192 	if (namesamen(layername, x_("METAL"), 5) == 0) j = 5; else
193 		if (namesamen(layername, x_("MET"), 3) == 0) j = 3;
194 	if (j != 0)
195 	{
196 		laynum = eatoi(&layername[j]);
197 		switch (laynum)
198 		{
199 			case 1:  *arcfunc = APMETAL1;   *layerfunc = LFMETAL1;   break;
200 			case 2:  *arcfunc = APMETAL2;   *layerfunc = LFMETAL2;   break;
201 			case 3:  *arcfunc = APMETAL3;   *layerfunc = LFMETAL3;   break;
202 			case 4:  *arcfunc = APMETAL4;   *layerfunc = LFMETAL4;   break;
203 			case 5:  *arcfunc = APMETAL5;   *layerfunc = LFMETAL5;   break;
204 			case 6:  *arcfunc = APMETAL6;   *layerfunc = LFMETAL6;   break;
205 			case 7:  *arcfunc = APMETAL7;   *layerfunc = LFMETAL7;   break;
206 			case 8:  *arcfunc = APMETAL8;   *layerfunc = LFMETAL8;   break;
207 			case 9:  *arcfunc = APMETAL9;   *layerfunc = LFMETAL9;   break;
208 			case 10: *arcfunc = APMETAL10;  *layerfunc = LFMETAL10;  break;
209 			case 11: *arcfunc = APMETAL11;  *layerfunc = LFMETAL11;  break;
210 			case 12: *arcfunc = APMETAL12;  *layerfunc = LFMETAL12;  break;
211 		}
212 		return;
213 	}
214 
215 	if (namesamen(layername, x_("POLY"), 4) == 0)
216 	{
217 		laynum = eatoi(&layername[4]);
218 		switch (laynum)
219 		{
220 			case 1: *arcfunc = APPOLY1;   *layerfunc = LFPOLY1;   break;
221 			case 2: *arcfunc = APPOLY2;   *layerfunc = LFPOLY2;   break;
222 			case 3: *arcfunc = APPOLY3;   *layerfunc = LFPOLY3;   break;
223 		}
224 		return;
225 	}
226 
227 	if (namesame(layername, x_("PDIFF")) == 0)
228 	{
229 		*arcfunc = APDIFFP;
230 		*layerfunc = LFDIFF | LFPTYPE;
231 		return;
232 	}
233 	if (namesame(layername, x_("NDIFF")) == 0)
234 	{
235 		*arcfunc = APDIFFN;
236 		*layerfunc = LFDIFF | LFNTYPE;
237 		return;
238 	}
239 	if (namesame(layername, x_("DIFF")) == 0)
240 	{
241 		*arcfunc = APDIFF;
242 		*layerfunc = LFDIFF;
243 		return;
244 	}
245 
246 	if (namesame(layername, x_("CONT")) == 0)
247 	{
248 		*layerfunc = LFCONTACT1;
249 		return;
250 	}
251 	if (namesamen(layername, x_("VIA"), 3) == 0)
252 	{
253 		laynum = eatoi(&layername[3]);
254 		switch (laynum)
255 		{
256 			case 0:
257 			case 1:
258 			case 12: *layerfunc = LFCONTACT2;   break;
259 
260 			case 2:
261 			case 23: *layerfunc = LFCONTACT3;   break;
262 
263 			case 3:
264 			case 34: *layerfunc = LFCONTACT4;   break;
265 
266 			case 4:
267 			case 45: *layerfunc = LFCONTACT5;   break;
268 
269 			case 5:
270 			case 56: *layerfunc = LFCONTACT6;   break;
271 
272 			case 6:
273 			case 67: *layerfunc = LFCONTACT7;   break;
274 
275 			case 7:
276 			case 78: *layerfunc = LFCONTACT8;   break;
277 
278 			case 8:
279 			case 89: *layerfunc = LFCONTACT9;   break;
280 
281 			case 9:  *layerfunc = LFCONTACT10;  break;
282 
283 			case 10: *layerfunc = LFCONTACT11;  break;
284 
285 			case 11: *layerfunc = LFCONTACT12;  break;
286 		}
287 	}
288 }
289 
io_lefreadlayer(FILE * f,LIBRARY * lib)290 BOOLEAN io_lefreadlayer(FILE *f, LIBRARY *lib)
291 {
292 	REGISTER CHAR *layername, *key;
293 	CHAR curkey[200];
294 	REGISTER INTBIG defwidth;
295 	INTBIG afunc, layerfunc;
296 	REGISTER ARCPROTO *ap;
297 	float v;
298 
299 	layername = io_lefgetkeyword(f);
300 	if (layername == 0)
301 	{
302 		ttyputerr(_("EOF parsing LAYER header"));
303 		return(TRUE);
304 	}
305 	io_lefparselayer(layername, &afunc, &layerfunc);
306 	if (afunc == APUNKNOWN) ap = NOARCPROTO; else
307 	{
308 		for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
309 			if (((INTBIG)((ap->userbits&AFUNCTION)>>AFUNCTIONSH)) == afunc) break;
310 	}
311 
312 	for(;;)
313 	{
314 		/* get the next keyword */
315 		key = io_lefgetkeyword(f);
316 		if (key == 0)
317 		{
318 			ttyputerr(_("EOF parsing LAYER"));
319 			return(TRUE);
320 		}
321 
322 		if (namesame(key, x_("END")) == 0)
323 		{
324 			key = io_lefgetkeyword(f);
325 			break;
326 		}
327 
328 		if (namesame(key, x_("WIDTH")) == 0)
329 		{
330 			key = io_lefgetkeyword(f);
331 			if (key == 0)
332 			{
333 				ttyputerr(_("EOF reading WIDTH"));
334 				return(TRUE);
335 			}
336 			v = (float)eatof(key);
337 			defwidth = scalefromdispunit(v, DISPUNITMIC);
338 			if (ap != NOARCPROTO)
339 			{
340 				setval((INTBIG)ap, VARCPROTO, x_("IO_lef_width"), defwidth, VINTEGER);
341 			}
342 			if (io_lefignoretosemicolon(f, x_("WIDTH"))) return(TRUE);
343 			continue;
344 		}
345 
346 		if (namesame(key, x_("TYPE")) == 0 || namesame(key, x_("SPACING")) == 0 ||
347 			namesame(key, x_("PITCH")) == 0 || namesame(key, x_("DIRECTION")) == 0 ||
348 			namesame(key, x_("CAPACITANCE")) == 0 || namesame(key, x_("RESISTANCE")) == 0)
349 		{
350 			estrcpy(curkey, key);
351 			if (io_lefignoretosemicolon(f, curkey)) return(TRUE);
352 			continue;
353 		}
354 	}
355 	return(FALSE);
356 }
357 
io_lefreadmacro(FILE * f,LIBRARY * lib)358 BOOLEAN io_lefreadmacro(FILE *f, LIBRARY *lib)
359 {
360 	REGISTER CHAR *cellname, *key;
361 	REGISTER INTBIG ox, oy, blx, bhx, bly, bhy, dx, dy;
362 	INTBIG sx, sy;
363 	float x, y;
364 	REGISTER NODEPROTO *cell;
365 	REGISTER NODEINST *ni;
366 	CHAR curkey[200];
367 	REGISTER void *infstr;
368 
369 	cellname = io_lefgetkeyword(f);
370 	if (cellname == 0)
371 	{
372 		ttyputerr(_("EOF parsing MACRO header"));
373 		return(TRUE);
374 	}
375 	infstr = initinfstr();
376 	addstringtoinfstr(infstr, cellname);
377 	addstringtoinfstr(infstr, x_("{sk}"));
378 	cellname = returninfstr(infstr);
379 	cell = us_newnodeproto(cellname, lib);
380 	if (cell == NONODEPROTO)
381 	{
382 		ttyputerr(_("Cannot create cell '%s'"), cellname);
383 		return(TRUE);
384 	}
385 
386 	for(;;)
387 	{
388 		/* get the next keyword */
389 		key = io_lefgetkeyword(f);
390 		if (key == 0)
391 		{
392 			ttyputerr(_("EOF parsing MACRO"));
393 			return(TRUE);
394 		}
395 
396 		if (namesame(key, x_("END")) == 0)
397 		{
398 			key = io_lefgetkeyword(f);
399 			break;
400 		}
401 
402 		if (namesame(key, x_("SOURCE")) == 0 || namesame(key, x_("FOREIGN")) == 0 ||
403 			namesame(key, x_("SYMMETRY")) == 0 || namesame(key, x_("SITE")) == 0 ||
404 			namesame(key, x_("CLASS")) == 0 || namesame(key, x_("LEQ")) == 0 ||
405 			namesame(key, x_("POWER")) == 0)
406 		{
407 			estrcpy(curkey, key);
408 			if (io_lefignoretosemicolon(f, curkey)) return(TRUE);
409 			continue;
410 		}
411 
412 		if (namesame(key, x_("ORIGIN")) == 0)
413 		{
414 			key = io_lefgetkeyword(f);
415 			if (key == 0)
416 			{
417 				ttyputerr(_("EOF reading ORIGIN X"));
418 				return(TRUE);
419 			}
420 			x = (float)eatof(key);
421 			ox = scalefromdispunit(x, DISPUNITMIC);
422 
423 			key = io_lefgetkeyword(f);
424 			if (key == 0)
425 			{
426 				ttyputerr(_("EOF reading ORIGIN Y"));
427 				return(TRUE);
428 			}
429 			y = (float)eatof(key);
430 			oy = scalefromdispunit(y, DISPUNITMIC);
431 			if (io_lefignoretosemicolon(f, x_("ORIGIN"))) return(TRUE);
432 
433 			/* create or move the cell-center node */
434 			for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
435 				if (ni->proto == gen_cellcenterprim) break;
436 			if (ni == NONODEINST)
437 			{
438 				defaultnodesize(gen_cellcenterprim, &sx, &sy);
439 				blx = ox - sx/2;   bhx = blx + sx;
440 				bly = oy - sy/2;   bhy = bly + sy;
441 				ni = newnodeinst(gen_cellcenterprim, blx, bhx, bly, bhy, 0, 0, cell);
442 				if (ni == NONODEINST)
443 				{
444 					ttyputerr(_("Line %ld: Cannot create cell center node"), io_leflineno);
445 					return(TRUE);
446 				}
447 				ni->userbits |= HARDSELECTN|NVISIBLEINSIDE;
448 			} else
449 			{
450 				startobjectchange((INTBIG)ni, VNODEINST);
451 				dx = ox - (ni->lowx + ni->highx) / 2;
452 				dy = oy - (ni->lowy + ni->highy) / 2;
453 				modifynodeinst(ni, dx, dy, dx, dy, 0, 0);
454 			}
455 			endobjectchange((INTBIG)ni, VNODEINST);
456 			continue;
457 		}
458 
459 		if (namesame(key, x_("SIZE")) == 0)
460 		{
461 			key = io_lefgetkeyword(f);
462 			if (key == 0)
463 			{
464 				ttyputerr(_("EOF reading SIZE X"));
465 				return(TRUE);
466 			}
467 			x = (float)eatof(key);
468 			sx = scalefromdispunit(x, DISPUNITMIC);
469 
470 			key = io_lefgetkeyword(f);
471 			if (key == 0)
472 			{
473 				ttyputerr(_("EOF reading SIZE 'BY'"));
474 				return(TRUE);
475 			}
476 			if (namesame(key, x_("BY")) != 0)
477 			{
478 				ttyputerr(_("Line %ld: Expected 'by' in SIZE"), io_leflineno);
479 				return(TRUE);
480 			}
481 
482 			key = io_lefgetkeyword(f);
483 			if (key == 0)
484 			{
485 				ttyputerr(_("EOF reading SIZE Y"));
486 				return(TRUE);
487 			}
488 			y = (float)eatof(key);
489 			sy = scalefromdispunit(y, DISPUNITMIC);
490 			if (io_lefignoretosemicolon(f, x_("SIZE"))) return(TRUE);
491 			continue;
492 		}
493 
494 		if (namesame(key, x_("PIN")) == 0)
495 		{
496 			if (io_lefreadpin(f, cell)) return(TRUE);
497 			continue;
498 		}
499 
500 		if (namesame(key, x_("OBS")) == 0)
501 		{
502 			if (io_lefreadobs(f, cell)) return(TRUE);
503 			continue;
504 		}
505 
506 		ttyputerr(_("Line %ld: Unknown MACRO keyword (%s)"), io_leflineno, key);
507 		return(TRUE);
508 	}
509 	return(FALSE);
510 }
511 
io_lefreadvia(FILE * f,LIBRARY * lib)512 BOOLEAN io_lefreadvia(FILE *f, LIBRARY *lib)
513 {
514 	REGISTER CHAR *vianame, *key;
515 	REGISTER INTBIG lx, hx, ly, hy, i, lay1found, lay2found;
516 	INTBIG afunc, layerfunc;
517 	NODEPROTO *np;
518 	ARCPROTO *ap;
519 	float v;
520 	BOOLEAN ignoredefault;
521 	REGISTER PORTPROTO *pp;
522 	REGISTER VIADEF *vd;
523 
524 	/* get the via name */
525 	vianame = io_lefgetkeyword(f);
526 	if (vianame == 0) return(TRUE);
527 
528 	/* create a new via definition */
529 	vd = (VIADEF *)emalloc(sizeof (VIADEF), io_tool->cluster);
530 	if (vd == 0) return(TRUE);
531 	(void)allocstring(&vd->vianame, vianame, io_tool->cluster);
532 	vd->sx = vd->sy = 0;
533 	vd->via = NONODEPROTO;
534 	vd->lay1 = vd->lay2 = NOARCPROTO;
535 	vd->nextviadef = io_leffirstviadef;
536 	io_leffirstviadef = vd;
537 
538 	ignoredefault = TRUE;
539 	for(;;)
540 	{
541 		/* get the next keyword */
542 		key = io_lefgetkeyword(f);
543 		if (key == 0) return(TRUE);
544 		if (ignoredefault)
545 		{
546 			ignoredefault = FALSE;
547 			if (namesame(key, x_("DEFAULT")) == 0) continue;
548 		}
549 		if (namesame(key, x_("END")) == 0)
550 		{
551 			key = io_lefgetkeyword(f);
552 			break;
553 		}
554 		if (namesame(key, x_("RESISTANCE")) == 0)
555 		{
556 			if (io_lefignoretosemicolon(f, key)) return(TRUE);
557 			continue;
558 		}
559 		if (namesame(key, x_("LAYER")) == 0)
560 		{
561 			key = io_lefgetkeyword(f);
562 			if (key == 0) return(TRUE);
563 			io_lefparselayer(key, &afunc, &layerfunc);
564 			if (afunc == APUNKNOWN) ap = NOARCPROTO; else
565 			{
566 				for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
567 					if (((INTBIG)((ap->userbits&AFUNCTION)>>AFUNCTIONSH)) == afunc) break;
568 			}
569 			if (ap != NOARCPROTO)
570 			{
571 				if (vd->lay1 == NOARCPROTO) vd->lay1 = ap; else
572 					vd->lay2 = ap;
573 			}
574 			if (io_lefignoretosemicolon(f, x_("LAYER"))) return(TRUE);
575 			continue;
576 		}
577 		if (namesame(key, x_("RECT")) == 0)
578 		{
579 			/* handle definition of a via rectangle */
580 			key = io_lefgetkeyword(f);
581 			if (key == 0) return(TRUE);
582 			v = (float)eatof(key);
583 			lx = scalefromdispunit(v, DISPUNITMIC);
584 
585 			key = io_lefgetkeyword(f);
586 			if (key == 0) return(TRUE);
587 			v = (float)eatof(key);
588 			ly = scalefromdispunit(v, DISPUNITMIC);
589 
590 			key = io_lefgetkeyword(f);
591 			if (key == 0) return(TRUE);
592 			v = (float)eatof(key);
593 			hx = scalefromdispunit(v, DISPUNITMIC);
594 
595 			key = io_lefgetkeyword(f);
596 			if (key == 0) return(TRUE);
597 			v = (float)eatof(key);
598 			hy = scalefromdispunit(v, DISPUNITMIC);
599 
600 			/* accumulate largest layer size */
601 			if (hx-lx > vd->sx) vd->sx = hx - lx;
602 			if (hy-ly > vd->sy) vd->sy = hy - ly;
603 
604 			if (io_lefignoretosemicolon(f, x_("RECT"))) return(TRUE);
605 			continue;
606 		}
607 	}
608 	if (vd->lay1 != NOARCPROTO && vd->lay2 != NOARCPROTO)
609 	{
610 		for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
611 		{
612 			if (((np->userbits&NFUNCTION)>>NFUNCTIONSH) != NPCONTACT) continue;
613 			pp = np->firstportproto;
614 			lay1found = lay2found = 0;
615 			for(i=0; pp->connects[i] != NOARCPROTO; i++)
616 			{
617 				if (pp->connects[i] == vd->lay1) lay1found = 1;
618 				if (pp->connects[i] == vd->lay2) lay2found = 1;
619 			}
620 			if (lay1found != 0 && lay2found != 0) break;
621 		}
622 		vd->via = np;
623 	}
624 	return(FALSE);
625 }
626 
io_lefreadpin(FILE * f,NODEPROTO * cell)627 BOOLEAN io_lefreadpin(FILE *f, NODEPROTO *cell)
628 {
629 	REGISTER CHAR *key;
630 	REGISTER INTBIG portbits, usebits;
631 	CHAR curkey[200], pinname[200];
632 
633 	/* get the pin name */
634 	key = io_lefgetkeyword(f);
635 	if (key == 0)
636 	{
637 		ttyputerr(_("EOF parsing PIN name"));
638 		return(TRUE);
639 	}
640 	estrcpy(pinname, key);
641 
642 	portbits = usebits = 0;
643 	for(;;)
644 	{
645 		key = io_lefgetkeyword(f);
646 		if (key == 0)
647 		{
648 			ttyputerr(_("EOF parsing PIN"));
649 			return(TRUE);
650 		}
651 
652 		if (namesame(key, x_("END")) == 0)
653 		{
654 			key = io_lefgetkeyword(f);
655 			break;
656 		}
657 
658 		if (namesame(key, x_("SHAPE")) == 0 || namesame(key, x_("CAPACITANCE")) == 0 ||
659 			namesame(key, x_("ANTENNASIZE")) == 0)
660 		{
661 			estrcpy(curkey, key);
662 			if (io_lefignoretosemicolon(f, curkey)) return(TRUE);
663 			continue;
664 		}
665 
666 		if (namesame(key, x_("USE")) == 0)
667 		{
668 			key = io_lefgetkeyword(f);
669 			if (key == 0)
670 			{
671 				ttyputerr(_("EOF reading USE clause"));
672 				return(TRUE);
673 			}
674 			if (namesame(key, x_("POWER")) == 0) usebits = PWRPORT; else
675 			if (namesame(key, x_("GROUND")) == 0) usebits = GNDPORT; else
676 			if (namesame(key, x_("CLOCK")) == 0) usebits = CLKPORT; else
677 			{
678 				ttyputerr(_("Line %ld: Unknown USE keyword (%s)"),
679 					io_leflineno, key);
680 			}
681 			if (io_lefignoretosemicolon(f, x_("USE"))) return(TRUE);
682 			continue;
683 		}
684 
685 		if (namesame(key, x_("DIRECTION")) == 0)
686 		{
687 			key = io_lefgetkeyword(f);
688 			if (key == 0)
689 			{
690 				ttyputerr(_("EOF reading DIRECTION clause"));
691 				return(TRUE);
692 			}
693 			if (namesame(key, x_("INPUT")) == 0) portbits = INPORT; else
694 			if (namesame(key, x_("OUTPUT")) == 0) portbits = OUTPORT; else
695 			if (namesame(key, x_("INOUT")) == 0) portbits = BIDIRPORT; else
696 			{
697 				ttyputerr(_("Line %ld: Unknown DIRECTION keyword (%s)"),
698 					io_leflineno, key);
699 			}
700 			if (io_lefignoretosemicolon(f, x_("DIRECTION"))) return(TRUE);
701 			continue;
702 		}
703 
704 		if (namesame(key, x_("PORT")) == 0)
705 		{
706 			if (usebits != 0) portbits = usebits;
707 			if (io_lefreadport(f, cell, pinname, portbits))
708 				return(TRUE);
709 			continue;
710 		}
711 
712 		ttyputerr(_("Line %ld: Unknown PIN keyword (%s)"), io_leflineno, key);
713 		return(TRUE);
714 	}
715 	return(FALSE);
716 }
717 
io_lefreadport(FILE * f,NODEPROTO * cell,CHAR * portname,INTBIG portbits)718 BOOLEAN io_lefreadport(FILE *f, NODEPROTO *cell, CHAR *portname, INTBIG portbits)
719 {
720 	REGISTER CHAR *key;
721 	REGISTER INTBIG i, j, lx, hx, ly, hy, intx, inty, first,
722 		intwidth, lastintx, lastinty, sea, cx, cy;
723 	INTBIG afunc, layerfunc, sx, sy;
724 	REGISTER INTBIG afunc1, afunc2, found1, found2;
725 	REGISTER ARCPROTO *ap, *ap1, *ap2;
726 	REGISTER NODEPROTO *pin, *plnp;
727 	REGISTER ARCINST *ai;
728 	REGISTER NODEINST *ni;
729 	REGISTER PORTPROTO *pp;
730 	REGISTER GEOM *geom;
731 	float width, x, y;
732 	REGISTER LEFPATH *lefpaths, *lp, *olp;
733 
734 	ap = NOARCPROTO;
735 	plnp = NONODEPROTO;
736 	lefpaths = NOLEFPATH;
737 	first = 1;
738 	for(;;)
739 	{
740 		key = io_lefgetkeyword(f);
741 		if (key == 0)
742 		{
743 			ttyputerr(_("EOF parsing PORT"));
744 			return(TRUE);
745 		}
746 
747 		if (namesame(key, x_("END")) == 0)
748 		{
749 			break;
750 		}
751 
752 		if (namesame(key, x_("LAYER")) == 0)
753 		{
754 			key = io_lefgetkeyword(f);
755 			if (key == 0)
756 			{
757 				ttyputerr(_("EOF reading LAYER clause"));
758 				return(TRUE);
759 			}
760 			io_lefparselayer(key, &afunc, &layerfunc);
761 			if (afunc == APUNKNOWN) ap = NOARCPROTO; else
762 				ap = io_lefgetarc(afunc);
763 			plnp = io_lefgetnode(layerfunc);
764 			if (io_lefignoretosemicolon(f, x_("LAYER"))) return(TRUE);
765 			continue;
766 		}
767 
768 		if (namesame(key, x_("WIDTH")) == 0)
769 		{
770 			key = io_lefgetkeyword(f);
771 			if (key == 0)
772 			{
773 				ttyputerr(_("EOF reading WIDTH clause"));
774 				return(TRUE);
775 			}
776 			width = (float)eatof(key);
777 			intwidth = scalefromdispunit(width, DISPUNITMIC);
778 			if (io_lefignoretosemicolon(f, x_("WIDTH"))) return(TRUE);
779 			continue;
780 		}
781 
782 		if (namesame(key, x_("RECT")) == 0)
783 		{
784 			if (plnp == NONODEPROTO)
785 			{
786 				ttyputerr(_("Line %ld: No layers for RECT"), io_leflineno);
787 				return(TRUE);
788 			}
789 			key = io_lefgetkeyword(f);
790 			if (key == 0)
791 			{
792 				ttyputerr(_("EOF reading RECT low X"));
793 				return(TRUE);
794 			}
795 			x = (float)eatof(key);
796 			lx = scalefromdispunit(x, DISPUNITMIC);
797 
798 			key = io_lefgetkeyword(f);
799 			if (key == 0)
800 			{
801 				ttyputerr(_("EOF reading RECT low Y"));
802 				return(TRUE);
803 			}
804 			y = (float)eatof(key);
805 			ly = scalefromdispunit(y, DISPUNITMIC);
806 
807 			key = io_lefgetkeyword(f);
808 			if (key == 0)
809 			{
810 				ttyputerr(_("EOF reading RECT high X"));
811 				return(TRUE);
812 			}
813 			x = (float)eatof(key);
814 			hx = scalefromdispunit(x, DISPUNITMIC);
815 
816 			key = io_lefgetkeyword(f);
817 			if (key == 0)
818 			{
819 				ttyputerr(_("EOF reading RECT high Y"));
820 				return(TRUE);
821 			}
822 			y = (float)eatof(key);
823 			hy = scalefromdispunit(y, DISPUNITMIC);
824 
825 			if (io_lefignoretosemicolon(f, x_("RECT"))) return(TRUE);
826 
827 			/* make the pin */
828 			if (hx < lx) { j = hx;   hx = lx;   lx = j; }
829 			if (hy < ly) { j = hy;   hy = ly;   ly = j; }
830 			ni = newnodeinst(plnp, lx, hx, ly, hy, 0, 0, cell);
831 			if (ni == NONODEINST)
832 			{
833 				ttyputerr(_("Line %ld: Cannot create pin for RECT"), io_leflineno);
834 				return(TRUE);
835 			}
836 			endobjectchange((INTBIG)ni, VNODEINST);
837 
838 			if (first != 0)
839 			{
840 				/* create the port on the first pin */
841 				first = 0;
842 				pp = io_lefnewport(cell, ni, plnp->firstportproto, portname);
843 				pp->userbits = (pp->userbits & ~STATEBITS) | portbits;
844 			}
845 			continue;
846 		}
847 
848 		if (namesame(key, x_("PATH")) == 0)
849 		{
850 			if (ap == NOARCPROTO)
851 			{
852 				ttyputerr(_("Line %ld: No layers for PATH"), io_leflineno);
853 				return(TRUE);
854 			}
855 			for(i=0; ; i++)
856 			{
857 				key = io_lefgetkeyword(f);
858 				if (key == 0)
859 				{
860 					ttyputerr(_("EOF reading PATH clause"));
861 					return(TRUE);
862 				}
863 				if (estrcmp(key, x_(";")) == 0) break;
864 				x = (float)eatof(key);
865 
866 				key = io_lefgetkeyword(f);
867 				if (key == 0)
868 				{
869 					ttyputerr(_("EOF reading PATH clause"));
870 					return(TRUE);
871 				}
872 				y = (float)eatof(key);
873 
874 				/* plot this point */
875 				intx = scalefromdispunit(x, DISPUNITMIC);
876 				inty = scalefromdispunit(y, DISPUNITMIC);
877 				if (i != 0)
878 				{
879 					/* queue path */
880 					lp = io_lefnewpath();
881 					if (lp == NOLEFPATH) return(TRUE);
882 
883 					/* LINTED "lastintx" used in proper order */
884 					lp->x[0] = lastintx;     lp->x[1] = intx;
885 
886 					/* LINTED "lastinty" used in proper order */
887 					lp->y[0] = lastinty;     lp->y[1] = inty;
888 					lp->ni[0] = NONODEINST;  lp->ni[1] = NONODEINST;
889 					lp->width = intwidth;
890 					lp->arc = ap;
891 					lp->nextlefpath = lefpaths;
892 					lefpaths = lp;
893 				}
894 				lastintx = intx;   lastinty = inty;
895 			}
896 			continue;
897 		}
898 
899 		if (namesame(key, x_("VIA")) == 0)
900 		{
901 			/* get the coordinates */
902 			key = io_lefgetkeyword(f);
903 			if (key == 0)
904 			{
905 				ttyputerr(_("EOF reading VIA clause"));
906 				return(TRUE);
907 			}
908 			x = (float)eatof(key);
909 			intx = scalefromdispunit(x, DISPUNITMIC);
910 
911 			key = io_lefgetkeyword(f);
912 			if (key == 0)
913 			{
914 				ttyputerr(_("EOF reading VIA clause"));
915 				return(TRUE);
916 			}
917 			y = (float)eatof(key);
918 			inty = scalefromdispunit(y, DISPUNITMIC);
919 
920 			/* find the proper via */
921 			key = io_lefgetkeyword(f);
922 			afunc1 = afunc2 = APUNKNOWN;
923 			if (namesame(key, x_("via1")) == 0)
924 			{
925 				afunc1 = APMETAL1;
926 				afunc2 = APMETAL2;
927 			} else if (namesame(key, x_("via2")) == 0)
928 			{
929 				afunc1 = APMETAL2;
930 				afunc2 = APMETAL3;
931 			} else if (namesame(key, x_("via3")) == 0)
932 			{
933 				afunc1 = APMETAL3;
934 				afunc2 = APMETAL4;
935 			} else if (namesame(key, x_("via4")) == 0)
936 			{
937 				afunc1 = APMETAL4;
938 				afunc2 = APMETAL5;
939 			} else
940 			{
941 				ttyputerr(_("Line %ld: Unknown VIA type (%s)"), io_leflineno, key);
942 				return(TRUE);
943 			}
944 			ap1 = io_lefgetarc(afunc1);
945 			if (ap1 == NOARCPROTO) return(TRUE);
946 			ap2 = io_lefgetarc(afunc2);
947 			if (ap2 == NOARCPROTO) return(TRUE);
948 			for(pin = el_curtech->firstnodeproto; pin != NONODEPROTO; pin = pin->nextnodeproto)
949 			{
950 				if (((pin->userbits&NFUNCTION)>>NFUNCTIONSH) != NPCONTACT) continue;
951 				pp = pin->firstportproto;
952 				found1 = found2 = 0;
953 				for(i=0; pp->connects[i] != NOARCPROTO; i++)
954 				{
955 					if (pp->connects[i] == ap1) found1 = 1;
956 					if (pp->connects[i] == ap2) found2 = 1;
957 				}
958 				if (found1 != 0 && found2 != 0) break;
959 			}
960 			if (pin == NONODEPROTO)
961 			{
962 				ttyputerr(_("Line %ld: No Via in current technology connects %s to %s"),
963 					io_leflineno, arcfunctionname(afunc1),
964 					arcfunctionname(afunc2));
965 				return(TRUE);
966 			}
967 			if (io_lefignoretosemicolon(f, x_("VIA"))) return(TRUE);
968 
969 			/* create the via */
970 			defaultnodesize(pin, &sx, &sy);
971 			lx = intx - sx / 2;   hx = lx + sx;
972 			ly = inty - sy / 2;   hy = ly + sy;
973 			ni = newnodeinst(pin, lx, hx, ly, hy, 0, 0, cell);
974 			if (ni == NONODEINST)
975 			{
976 				ttyputerr(_("Line %ld: Cannot create VIA for PATH"), io_leflineno);
977 				return(TRUE);
978 			}
979 			endobjectchange((INTBIG)ni, VNODEINST);
980 			continue;
981 		}
982 
983 		ttyputerr(_("Line %ld: Unknown PORT keyword (%s)"), io_leflineno, key);
984 		return(TRUE);
985 	}
986 
987 	/* look for paths that end at vias */
988 	for(lp = lefpaths; lp != NOLEFPATH; lp = lp->nextlefpath)
989 	{
990 		for(i=0; i<2; i++)
991 		{
992 			if (lp->ni[i] != NONODEINST) continue;
993 			sea = initsearch(lp->x[i], lp->x[i], lp->y[i], lp->y[i], cell);
994 			for(;;)
995 			{
996 				geom = nextobject(sea);
997 				if (geom == NOGEOM) break;
998 				if (!geom->entryisnode) continue;
999 				ni = geom->entryaddr.ni;
1000 				cx = (ni->lowx + ni->highx) / 2;
1001 				cy = (ni->lowy + ni->highy) / 2;
1002 				if (cx != lp->x[i] || cy != lp->y[i]) continue;
1003 				lp->ni[i] = ni;
1004 				break;
1005 			}
1006 			if (lp->ni[i] == NONODEINST) continue;
1007 
1008 			/* use this via at other paths which meet here */
1009 			for(olp = lefpaths; olp != NOLEFPATH; olp = olp->nextlefpath)
1010 			{
1011 				for(j=0; j<2; j++)
1012 				{
1013 					if (olp->ni[j] != NONODEINST) continue;
1014 					if (olp->x[j] != lp->x[i] || olp->y[j] != lp->y[i]) continue;
1015 					olp->ni[j] = lp->ni[i];
1016 				}
1017 			}
1018 		}
1019 	}
1020 
1021 	/* create pins at all other path ends */
1022 	for(lp = lefpaths; lp != NOLEFPATH; lp = lp->nextlefpath)
1023 	{
1024 		for(i=0; i<2; i++)
1025 		{
1026 			if (lp->ni[i] != NONODEINST) continue;
1027 			pin = getpinproto(lp->arc);
1028 			if (pin == NONODEPROTO) continue;
1029 			defaultnodesize(pin, &sx, &sy);
1030 			lx = lp->x[i] - sx / 2;   hx = lx + sx;
1031 			ly = lp->y[i] - sy / 2;   hy = ly + sy;
1032 			lp->ni[i] = newnodeinst(pin, lx, hx, ly, hy, 0, 0, cell);
1033 			if (lp->ni[i] == NONODEINST)
1034 			{
1035 				ttyputerr(_("Line %ld: Cannot create pin for PATH"), io_leflineno);
1036 				return(TRUE);
1037 			}
1038 			endobjectchange((INTBIG)lp->ni[i], VNODEINST);
1039 
1040 			/* use this pin at other paths which meet here */
1041 			for(olp = lefpaths; olp != NOLEFPATH; olp = olp->nextlefpath)
1042 			{
1043 				for(j=0; j<2; j++)
1044 				{
1045 					if (olp->ni[j] != NONODEINST) continue;
1046 					if (olp->x[j] != lp->x[i] || olp->y[j] != lp->y[i]) continue;
1047 					olp->ni[j] = lp->ni[i];
1048 				}
1049 			}
1050 		}
1051 	}
1052 
1053 	/* now instantiate the paths */
1054 	for(lp = lefpaths; lp != NOLEFPATH; lp = lp->nextlefpath)
1055 	{
1056 		ai = newarcinst(lp->arc, lp->width, us_makearcuserbits(lp->arc),
1057 			lp->ni[0], lp->ni[0]->proto->firstportproto, lp->x[0], lp->y[0],
1058 				lp->ni[1], lp->ni[1]->proto->firstportproto, lp->x[1], lp->y[1], cell);
1059 		if (ai == NOARCINST)
1060 		{
1061 			ttyputerr(_("Line %ld: Cannot create arc for PATH"), io_leflineno);
1062 			return(TRUE);
1063 		}
1064 	}
1065 	io_leffreepaths(lefpaths);
1066 
1067 	return(FALSE);
1068 }
1069 
1070 /*
1071  * Routine to create a port called "thename" on port "pp" of node "ni" in cell "cell".
1072  * The name is modified if it already exists.
1073  */
io_lefnewport(NODEPROTO * cell,NODEINST * ni,PORTPROTO * pp,CHAR * thename)1074 PORTPROTO *io_lefnewport(NODEPROTO *cell, NODEINST *ni, PORTPROTO *pp, CHAR *thename)
1075 {
1076 	REGISTER PORTPROTO *ppt;
1077 	REGISTER INTBIG i, leng;
1078 	REGISTER CHAR *newname, *portname;
1079 
1080 	portname = thename;
1081 	newname = 0;
1082 	for(i=0; ; i++)
1083 	{
1084 		ppt = getportproto(cell, portname);
1085 		if (ppt == NOPORTPROTO)
1086 		{
1087 			ppt = newportproto(cell, ni, pp, portname);
1088 			break;
1089 		}
1090 
1091 		/* make space for modified name */
1092 		if (newname == 0)
1093 		{
1094 			leng = estrlen(thename)+10;
1095 			newname = (CHAR *)emalloc(leng * SIZEOFCHAR, el_tempcluster);
1096 		}
1097 		esnprintf(newname, leng, x_("%s-%ld"), thename, i);
1098 		portname = newname;
1099 	}
1100 	if (newname != 0) efree(newname);
1101 	return(ppt);
1102 }
1103 
io_lefreadobs(FILE * f,NODEPROTO * cell)1104 BOOLEAN io_lefreadobs(FILE *f, NODEPROTO *cell)
1105 {
1106 	REGISTER CHAR *key;
1107 	INTBIG lfunc, arcfunc;
1108 	REGISTER INTBIG lx, hx, ly, hy, j;
1109 	float x, y;
1110 	REGISTER NODEINST *ni;
1111 	REGISTER NODEPROTO *np;
1112 
1113 	np = NONODEPROTO;
1114 	for(;;)
1115 	{
1116 		key = io_lefgetkeyword(f);
1117 		if (key == 0)
1118 		{
1119 			ttyputerr(_("EOF parsing OBS"));
1120 			return(TRUE);
1121 		}
1122 
1123 		if (namesame(key, x_("END")) == 0) break;
1124 
1125 		if (namesame(key, x_("LAYER")) == 0)
1126 		{
1127 			key = io_lefgetkeyword(f);
1128 			if (key == 0)
1129 			{
1130 				ttyputerr(_("EOF reading LAYER clause"));
1131 				return(TRUE);
1132 			}
1133 			io_lefparselayer(key, &arcfunc, &lfunc);
1134 			if (lfunc == LFUNKNOWN)
1135 			{
1136 				ttyputerr(_("Line %ld: Unknown layer name (%s)"), io_leflineno, key);
1137 				return(TRUE);
1138 			}
1139 			np = io_lefgetnode(lfunc);
1140 			if (np == NONODEPROTO) return(TRUE);
1141 			if (io_lefignoretosemicolon(f, x_("LAYER"))) return(TRUE);
1142 			continue;
1143 		}
1144 
1145 		if (namesame(key, x_("RECT")) == 0)
1146 		{
1147 			if (np == NONODEPROTO)
1148 			{
1149 				ttyputerr(_("Line %ld: No layers for RECT"), io_leflineno);
1150 				return(TRUE);
1151 			}
1152 			key = io_lefgetkeyword(f);
1153 			if (key == 0)
1154 			{
1155 				ttyputerr(_("EOF reading RECT low X"));
1156 				return(TRUE);
1157 			}
1158 			x = (float)eatof(key);
1159 			lx = scalefromdispunit(x, DISPUNITMIC);
1160 
1161 			key = io_lefgetkeyword(f);
1162 			if (key == 0)
1163 			{
1164 				ttyputerr(_("EOF reading RECT low Y"));
1165 				return(TRUE);
1166 			}
1167 			y = (float)eatof(key);
1168 			ly = scalefromdispunit(y, DISPUNITMIC);
1169 
1170 			key = io_lefgetkeyword(f);
1171 			if (key == 0)
1172 			{
1173 				ttyputerr(_("EOF reading RECT high X"));
1174 				return(TRUE);
1175 			}
1176 			x = (float)eatof(key);
1177 			hx = scalefromdispunit(x, DISPUNITMIC);
1178 
1179 			key = io_lefgetkeyword(f);
1180 			if (key == 0)
1181 			{
1182 				ttyputerr(_("EOF reading RECT high Y"));
1183 				return(TRUE);
1184 			}
1185 			y = (float)eatof(key);
1186 			hy = scalefromdispunit(y, DISPUNITMIC);
1187 
1188 			if (io_lefignoretosemicolon(f, x_("RECT"))) return(TRUE);
1189 
1190 			/* make the pin */
1191 			if (hx < lx) { j = hx;   hx = lx;   lx = j; }
1192 			if (hy < ly) { j = hy;   hy = ly;   ly = j; }
1193 			ni = newnodeinst(np, lx, hx, ly, hy, 0, 0, cell);
1194 			if (ni == NONODEINST)
1195 			{
1196 				ttyputerr(_("Line %ld: Cannot create node for RECT"), io_leflineno);
1197 				return(TRUE);
1198 			}
1199 			endobjectchange((INTBIG)ni, VNODEINST);
1200 			continue;
1201 		}
1202 	}
1203 	return(FALSE);
1204 }
1205 
io_lefignoretosemicolon(FILE * f,CHAR * command)1206 BOOLEAN io_lefignoretosemicolon(FILE *f, CHAR *command)
1207 {
1208 	REGISTER CHAR *key;
1209 
1210 	/* ignore up to the next semicolon */
1211 	for(;;)
1212 	{
1213 		key = io_lefgetkeyword(f);
1214 		if (key == 0)
1215 		{
1216 			ttyputerr(_("EOF parsing %s"), command);
1217 			return(TRUE);
1218 		}
1219 		if (estrcmp(key, x_(";")) == 0) break;
1220 	}
1221 	return(FALSE);
1222 }
1223 
io_lefgetkeyword(FILE * f)1224 CHAR *io_lefgetkeyword(FILE *f)
1225 {
1226 	REGISTER CHAR *ret;
1227 	REGISTER INTBIG filepos, i;
1228 
1229 	/* keep reading from file until something is found on a line */
1230 	while (io_lefline[io_leflinepos] == 0)
1231 	{
1232 		/* read a line from the file, exit at EOF */
1233 		if (xfgets(io_lefline, MAXLINE, f)) return(0);
1234 		io_leflineno++;
1235 		if ((io_leflineno%50) == 0)
1236 		{
1237 			filepos = xtell(f);
1238 			DiaSetProgress(io_lefprogressdialog, filepos, io_leffilesize);
1239 		}
1240 
1241 		/* remove comments from the line */
1242 		for(i=0; io_lefline[i] != 0; i++)
1243 			if (io_lefline[i] == '#')
1244 		{
1245 			io_lefline[i] = 0;
1246 			break;
1247 		}
1248 
1249 		/* look for the first text on the line */
1250 		io_leflinepos = 0;
1251 		while (io_lefline[io_leflinepos] == ' ' || io_lefline[io_leflinepos] == '\t')
1252 			io_leflinepos++;
1253 	}
1254 
1255 	/* remember where the keyword begins */
1256 	ret = &io_lefline[io_leflinepos];
1257 
1258 	/* scan to the end of the keyword */
1259 	while (io_lefline[io_leflinepos] != 0 && io_lefline[io_leflinepos] != ' ' &&
1260 		io_lefline[io_leflinepos] != '\t') io_leflinepos++;
1261 	if (io_lefline[io_leflinepos] != 0) io_lefline[io_leflinepos++] = 0;
1262 
1263 	/* advance to the start of the next keyword */
1264 	while (io_lefline[io_leflinepos] == ' ' || io_lefline[io_leflinepos] == '\t')
1265 		io_leflinepos++;
1266 	return(ret);
1267 }
1268 
io_lefgetnode(INTBIG lfunc)1269 NODEPROTO *io_lefgetnode(INTBIG lfunc)
1270 {
1271 	REGISTER NODEPROTO *np;
1272 
1273 	np = getpurelayernode(el_curtech, -1, lfunc);
1274 	if (np == NONODEPROTO)
1275 	{
1276 		ttyputerr(_("Line %ld: Layer not in current technology"),
1277 			io_leflineno);
1278 		return(NONODEPROTO);
1279 	}
1280 	return(np);
1281 }
1282 
io_lefgetarc(INTBIG afunc)1283 ARCPROTO *io_lefgetarc(INTBIG afunc)
1284 {
1285 	REGISTER ARCPROTO *ap;
1286 
1287 	for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1288 		if ((INTBIG)((ap->userbits&AFUNCTION)>>AFUNCTIONSH) == afunc) break;
1289 	if (ap == NOARCPROTO)
1290 	{
1291 		ttyputerr(_("Line %ld: Layer %s not in current technology"),
1292 			io_leflineno, arcfunctionname(afunc));
1293 		return(NOARCPROTO);
1294 	}
1295 	return(ap);
1296 }
1297 
io_lefnewpath(void)1298 LEFPATH *io_lefnewpath(void)
1299 {
1300 	LEFPATH *lp;
1301 
1302 	if (io_leffreepath != NOLEFPATH)
1303 	{
1304 		lp = io_leffreepath;
1305 		io_leffreepath = lp->nextlefpath;
1306 	} else
1307 	{
1308 		lp = (LEFPATH *)emalloc(sizeof(LEFPATH), io_tool->cluster);
1309 		if (lp == 0) lp = NOLEFPATH;
1310 	}
1311 	return(lp);
1312 }
1313 
io_lefkillpath(LEFPATH * lp)1314 void io_lefkillpath(LEFPATH *lp)
1315 {
1316 	lp->nextlefpath = io_leffreepath;
1317 	io_leffreepath = lp;
1318 }
1319 
io_leffreepaths(LEFPATH * firstlp)1320 void io_leffreepaths(LEFPATH *firstlp)
1321 {
1322 	LEFPATH *lp, *nextlp;
1323 
1324 	for(lp = firstlp; lp != NOLEFPATH; lp = nextlp)
1325 	{
1326 		nextlp = lp->nextlefpath;
1327 		io_lefkillpath(lp);
1328 	}
1329 }
1330