1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: ioedifi.c
6  * Input/output tool: EDIF 2 0 0 netlist reader
7  * Written by: Glen Lawson
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 #define IGNORESTRINGSWITHSQUAREBRACKETS 1		/* uncomment to ignore strings starting with "[" */
33 #define SLOPDISTANCE                    1		/* allow connections when this many lambda away (0 to force exact placement) */
34 
35 /*
36  * Notes (11/12/92):
37  *	I have tried EDIF files from CADENCE and VALID only.
38  *	Does not fully support portbundles
39  *	Multiple ports of the same name are named port_x (x is 1 to n duplicate)
40  *	Keywords such as ARRAY have unnamed parameters, ie (array (name..) 5 6)
41  *	this is handled in the io_edprocess_integer function called by io_edget_keyword,
42  *	this is a hack to fix this problem, a real table driven parser should be used.
43  * Improved (3/9/92) by Steven Rubin:
44  *	handle progress dialogs during input
45  *	changed "malloc" and "free" to "emalloc" and "efree"
46  *    memory allocation bug in "io_edpop_stack()" caused crash when current technology gas GDS layers
47  * gml (1/94)
48  *	Use circle arcs instead of splines.
49  *	Support text justifications and text height
50  * 	Better NAME/RENAME/STRINGDISPLAY/ANNOTATE text handling.
51  * gml (3/94)
52  *  ANSI prototypes
53  * gml (9/94)
54  *	Changed arcs to simple polygons plus ARC attribute
55  * gml (12/94)
56  *  Can read NETLIST views
57  */
58 
59 #include "config.h"
60 #include "global.h"
61 #include "egraphics.h"
62 #include "efunction.h"
63 #include "database.h"
64 #include "edialogs.h"
65 #include "tecgen.h"
66 #include "tecart.h"
67 #include "tecschem.h"
68 #include "eio.h"
69 #include "network.h"
70 #include "usr.h"
71 #include <math.h>
72 
73 /* some length defines */
74 #define LINE      4096
75 #define WORD      4096
76 #define MAXLAYERS  256
77 
78 #define LONGJMPEOF       1		/* error: "Unexpected end-of-file" */
79 #define LONGJMPNOMEM     2		/* error: "No memory" */
80 #define LONGJMPPTMIS     3		/* error: "Point list mismatch" */
81 #define LONGJMPNOLIB     4		/* error: "Could not create library" */
82 #define LONGJMPNOINT     5		/* error: "No integer value" */
83 #define LONGJMPILLNUM    6		/* error: "Illegal number value" */
84 #define LONGJMPNOMANT    7		/* error: "No matissa value" */
85 #define LONGJMPNOEXP     8		/* error: "No exponent value" */
86 #define LONGJMPILLNAME   9		/* error: "Illegal name" */
87 #define LONGJMPILLDELIM 10		/* error: "Illegal delimeter" */
88 
89 typedef enum
90 {
91 	UPPERLEFT,
92 	UPPERCENTER,
93 	UPPERRIGHT,
94 	CENTERLEFT,
95 	CENTERCENTER,
96 	CENTERRIGHT,
97 	LOWERLEFT,
98 	LOWERCENTER,
99 	LOWERRIGHT
100 } TEXTJUST;
101 
102 /* generic defines */
103 static CHAR *DELIMETERS = x_(" \t\r\n=.:;'()}\"");
104 
105 /* name table for layers */
106 #define NONAMETABLE ((NAMETABLE_PTR)0)
107 typedef struct
108 {
109 	CHAR *original;					/* the original MASK layer */
110 	CHAR *replace;					/* the replacement layer */
111 	NODEPROTO *node;				/* the basic electric node */
112 	ARCPROTO *arc;					/* the basic arc type */
113 	int textheight;					/* default text height */
114 	TEXTJUST justification;			/* default justification */
115 	int visible; 					/* layer is visible */
116 } NAMETABLE, *NAMETABLE_PTR;
117 
118 /* the following is a table of EDIF keywords, and functions */
119 typedef enum
120 {
121 	KUNKNOWN,
122 	KINIT,
123 	KANNOTATE,
124 	KARC,
125 	KARRAY,
126 	KAUTHOR,
127 	KBOOLEAN,
128 	KBORDERWIDTH,
129 	KBOUNDINGBOX,
130 	KCELL,
131 	KCELLREF,
132 	KCELLTYPE,
133 	KCIRCLE,
134 	KCOLOR,
135 	KCONTENTS,
136 	KCOMMENT,
137 	KCOMMENTGRAPHICS,
138 	KCONNECTLOCATION,
139 	KCORNERTYPE,
140 	KCURVE,
141 	KDATAORIGIN,
142 	KDCFANOUTLOAD,
143 	KDCMAXFANOUT,
144 	KDELTA,
145 	KDESIGN,
146 	KDESIGNATOR,
147 	KDIRECTION,
148 	KDISPLAY,
149 	KDOT,
150 	KEDIF,
151 	KEDIFLEVEL,
152 	KEDIFVERSION,
153 	KENDTYPE,
154 	KEXTERNAL,
155 	KFABRICATE,
156 	KFALSE,
157 	KFIGURE,
158 	KFIGUREGROUP,
159 	KFIGUREGROUPOVERRIDE,
160 	KFIGUREGROUPREF,
161 	KFILLPATTERN,
162 	KGRIDMAP,
163 	KINSTANCE,
164 	KINSTANCEREF,
165 	KINTEGER,
166 	KINTERFACE,
167 	KJOINED,
168 	KJUSTIFY,
169 	KKEYWORDDISPLAY,
170 	KEDIFKEYMAP,
171 	KEDIFKEYLEVEL,
172 	KLIBRARY,
173 	KLIBRARYREF,
174 	KLISTOFNETS,
175 	KLISTOFPORTS,
176 	KLOGICREF,
177 	KMEMBER,
178 	KMUSTJOIN,
179 	KNAME,
180 	KNET,
181 	KNETBUNDLE,
182 	KNETREF,
183 	KNUMBER,
184 	KNUMBERDEFINITION,
185 	KORIENTATION,
186 	KORIGIN,
187 	KOWNER,
188 	KPAGE,
189 	KPAGESIZE,
190 	KPARAMETER,
191 	KPATH,
192 	KPATHWIDTH,
193 	KPOINT,
194 	KPOINTLIST,
195 	KPOLYGON,
196 	KPORT,
197 	KPORTBUNDLE,
198 	KPORTIMPLEMENTATION,
199 	KPORTINSTANCE,
200 	KPORTLIST,
201 	KPORTREF,
202 	KPROGRAM,
203 	KPROPERTY,
204 	KPROPERTYDISPLAY,
205 	KPT,
206 	KNAMEDEF,
207 	KOPENSHAPE,
208 	KRECTANGLE,
209 	KRENAME,
210 	KSCALE,
211 	KSCALEDINTEGER,
212 	KSCALEX,
213 	KSCALEY,
214 	KSITE,
215 	KSHAPE,
216 	KSTATUS,
217 	KSTRING,
218 	KSTRINGDISPLAY,
219 	KSYMBOL,
220 	KTECHNOLOGY,
221 	KTEXTHEIGHT,
222 	KTIMESTAMP,
223 	KTRANSFORM,
224 	KTRUE,
225 	KUNIT,
226 	KUSERDATA,
227 	KVERSION,
228 	KVIEW,
229 	KVIEWLIST,
230 	KVIEWREF,
231 	KVIEWTYPE,
232 	KVISIBLE,
233 	KWEAKJOINED,
234 	KWRITTEN
235 } KSTATE;
236 
237 #define KNULL ((KSTATE *) 0)
238 typedef struct
239 {
240 	CHAR *name;							/* the name of the keyword */
241 	INTBIG (*func)(void);				/* the function to execute */
242 	KSTATE next;						/* the next state, if any */
243 	KSTATE *state;						/* edif state */
244 } EDIFKEY, *EDIFKEY_PTR;
245 #define NOEDIFKEY ((EDIFKEY_PTR) 0)
246 
247 /* Edif viewtypes ... */
248 typedef enum
249 {
250 	VNULL,
251 	VBEHAVIOR,
252 	VDOCUMENT,
253 	VGRAPHIC,
254 	VLOGICMODEL,
255 	VMASKLAYOUT,
256 	VNETLIST,
257 	VPCBLAYOUT,
258 	VSCHEMATIC,
259 	VSTRANGER,
260 	VSYMBOLIC,
261 	VSYMBOL 	/* not a real EDIF view, but electric has one */
262 } VTYPES;
263 
264 /* Edif geometry types ... */
265 typedef enum
266 {
267 	GUNKNOWN,
268 	GRECTANGLE,
269 	GPOLYGON,
270 	GSHAPE,
271 	GOPENSHAPE,
272 	GTEXT,
273 	GPATH,
274 	GINSTANCE,
275 	GCIRCLE,
276 	GARC,
277 	GPIN,
278 	GNET,
279 	GBUS
280 } GTYPES;
281 
282 /* 8 standard orientations */
283 typedef enum
284 {
285 	OUNKNOWN,
286 	OR0,
287 	OR90,
288 	OR180,
289 	OR270,
290 	OMX,
291 	OMY,
292 	OMYR90,
293 	OMXR90
294 } OTYPES;
295 
296 typedef struct _ept
297 {
298 	int x, y;
299 	struct _ept *nextpt;
300 } EPT, *EPT_PTR;
301 #define NOEPT ((EPT_PTR)0)
302 
303 typedef enum {INOUT, INPUTE, OUTPUTE} EDPORTDIR;
304 
305 #define INCH (10*el_curlib->lambda[io_edifgbl.technology->techindex])
306 
307 typedef struct _edport
308 {
309 	CHAR *name;
310 	CHAR *reference;
311 	EDPORTDIR direction;
312 	int arrayx, arrayy;
313 	struct _edport *next;
314 } EDPORT, *EDPORT_PTR;
315 #define NOEDPORT ((EDPORT_PTR)0)
316 
317 typedef struct _ednetport
318 {
319 	NODEINST *ni;					/* unique node port is attached to */
320 	PORTPROTO *pp;					/* port type (no portarc yet) */
321 	int member;						/* member for an array */
322 	struct _ednetport *next;		/* next common to a net */
323 } EDNETPORT, *EDNETPORT_PTR;
324 #define NOEDNETPORT ((EDNETPORT_PTR)0)
325 
326 typedef enum
327 {
328 	EVUNKNOWN,
329 	EVCADENCE,
330 	EVVALID,
331 	EVSYNOPSYS,
332 	EVMENTOR,
333 	EVVIEWLOGIC
334 } EDVENDOR;
335 
336 #define MAXSHEETS 6
337 typedef enum
338 {
339 	SHEET_ASIZE = 0,
340 	SHEET_BSIZE = 1,
341 	SHEET_CSIZE = 2,
342 	SHEET_DSIZE = 3,
343 	SHEET_ESIZE = 4,
344 	SHEET_INFSIZE = 5
345 } SHEET_SIZE;
346 
347 typedef enum
348 {
349 	PUNKNOWN,
350 	PSTRING,
351 	PINTEGER,
352 	PNUMBER
353 } PROPERTY_TYPE;
354 
355 typedef struct _edproperty
356 {
357 	CHAR *name;
358 	union
359 	{
360 		int integer;
361 		float number;
362 		CHAR *string;
363 	} val;
364 	PROPERTY_TYPE type;
365 	struct _edproperty *next;
366 } EDPROPERTY, *EDPROPERTY_PTR;
367 #define NOEDPROPERTY ((EDPROPERTY_PTR)0)
368 
369 /* edifgbl declaration */
370 typedef struct
371 {
372 	/* general information variables */
373 	FILE *edif_file;             	/* the input file */
374 	jmp_buf env;					/* longjmp return */
375 
376 	/* view information ... */
377 	int pageno;						/* the schematic page number */
378 	VTYPES active_view;				/* indicates we are in a NETLIST view */
379 	int drawing_number;				/* the current drawing number */
380 	int p_ref, c_ref;				/* peripheral and core reference names */
381 	EDVENDOR vendor;				/* the current vendor type */
382 
383 	/* parser variables ... */
384 	KSTATE state;			    	/* the current parser state */
385 	int lineno;                  	/* the current line number */
386 	CHAR buffer[LINE+1];         	/* the read buffer */
387 	CHAR *pos;                   	/* the position within the buffer */
388 	int ignoreblock;				/* no update flag */
389 	CHAR *delimeters;				/* parsing delimeters for edif */
390 	int errors, warnings;			/* load status */
391 
392 	/* electric context data ... */
393 	LIBRARY *library;				/* the new library */
394 	TECHNOLOGY *technology;			/* the active technology */
395 	NODEPROTO *current_cell;		/* the current active cell */
396 	NODEINST *current_node;			/* the current active instance */
397 	ARCINST *current_arc;			/* the current active arc */
398 	NODEPROTO *figure_group;		/* the current figure group node */
399 	ARCPROTO *arc_type;				/* the current (if exists) arc type */
400 	NODEPROTO *proto;				/* the cellRef type */
401 	PORTPROTO *current_port;		/* the current port proto */
402 
403 	/* general geometry information ... */
404 	GTYPES geometry;				/* the current geometry type */
405 	EPT *points;					/* the list of points */
406 	EPT *lastpt;					/* the end of the list */
407 	int pt_count;					/* the count of points */
408 	OTYPES orientation;				/* the orientation of the structure */
409 	EDPORTDIR direction;			/* port direction */
410 
411 	/* geometric path constructors ... */
412 	int path_width;					/* the width of the path */
413 	int extend_corner;				/* extend path corner flag */
414 	int extend_end;              	/* extend path end flag */
415 
416 	/* array variables ... */
417 	int isarray;					/* set if truely an array */
418 	int arrayx, arrayy;				/* the bounds of the array */
419 	int deltaxX, deltaxY;			/* offsets in x and y for an X increment */
420 	int deltayX, deltayY;			/* offsets in x and y for an Y increment */
421 	int deltapts;					/* which offset flag */
422 	int memberx, membery;			/* the element of the array */
423 
424 	/* text variables ... */
425 	CHAR string[LINE+1];			/* Text string */
426 	int textheight;					/* the current default text height */
427 	TEXTJUST justification;			/* the current text justificaton */
428 	int visible;					/* is stringdisplay visible */
429 	struct {						/* save block for name and rename strings */
430 		CHAR string[LINE+1];		/* the saved string, if NULL not saved */
431 		EPT *points;				/* origin x and y */
432 		int pt_count;				/* count of points (usually 1) */
433 		int textheight;				/* the height of text */
434 		int visible;				/* visiblity of the text */
435 		TEXTJUST justification; 	/* justification of the text */
436 		OTYPES orientation;			/* orientation of the text */
437 	} save_text;
438 
439 	/* technology data ... */
440 	double scale;					/* scaling value */
441 	double dbunit;					/* database units */
442 	double meters;					/* per number of meters */
443 	double val1, val2;				/* temporary storage */
444 
445 	/* current name and rename of EDIF objects ... */
446 	CHAR cell_reference[WORD+1];	/* the current cell name */
447 	CHAR cell_name[WORD+1];			/* the current cell name (original) */
448 	CHAR port_reference[WORD+1];	/* the current port name */
449 	CHAR port_name[WORD+1];			/* the current port name (original) */
450 	CHAR instance_reference[WORD+1]; /* the current instance name */
451 	CHAR instance_name[WORD+1];		/* the current instance name (original) */
452 	CHAR bundle_reference[WORD+1];	/* the current bundle name */
453 	CHAR bundle_name[WORD+1];		/* the current bundle name (original) */
454 	CHAR net_reference[WORD+1];		/* the current net name */
455 	CHAR net_name[WORD+1];			/* the current net name (original) */
456 	CHAR property_reference[WORD+1]; /* the current property name */
457 	CHAR property_name[WORD+1];		/* the current property name (original) */
458 
459 	PROPERTY_TYPE ptype;			/* the type of property */
460 	union {
461 		CHAR *string;				/* string buffer */
462 		int integer;				/* integer buffer */
463 		float number;				/* number buffer */
464 	} pval;
465 
466 	CHAR name[WORD+1];				/* the name of the object */
467 	CHAR original[WORD+1];			/* the original name of the object */
468 
469 	/* layer or figure information ... */
470 	int layer_ptr;					/* pointer to layer table entry */
471 	NAMETABLE_PTR nametbl[MAXLAYERS]; /* the current name mapping table */
472 	NAMETABLE_PTR cur_nametbl; 		/* the current name table entry */
473 
474 	/* cell name lookup (from rename) */
475 	NAMETABLE_PTR *celltbl;			/* the cell lookup table */
476 	int celltbl_cnt;				/* the count of entries in the cell table */
477 	int celltbl_sze;				/* maximum size of the table */
478 
479 	/* port data for port exporting */
480 	EDPORT_PTR ports;				/* active port list */
481 	EDPORT_PTR free_ports;			/* the list of free ports */
482 
483 	/* property data for all objects */
484 	EDPROPERTY_PTR properties;		/* active property list */
485 	EDPROPERTY_PTR free_properties;	/* the list of free properties */
486 
487 	/* net constructors */
488 	EDNETPORT_PTR firstnetport;		/* the list of ports on a net */
489 	EDNETPORT_PTR lastnetport; 		/* the last in the list on a net */
490 	EDNETPORT_PTR free_netports;	/* the list of free ports */
491 
492 	/* view NETLIST layout */
493 	SHEET_SIZE sheet_size;			/* the size of the target sheet */
494 	int sh_xpos, sh_ypos;			/* current sheet position */
495 	int sh_offset;					/* next x offset */
496 	int ipos, bpos, opos;			/* current position pointers */
497 } EDIFGBL;
498 
499 BOOLEAN io_edgblinited = FALSE;
500 
501 static EDIFGBL io_edifgbl;
502 
503 /* prototypes for local routines */
504 static INTBIG      io_edload_edif(INTBIG key_count, EDIFKEY_PTR keywords);
505 static INTBIG      io_edfreesavedptlist(void);
506 static double      io_edgetnumber(void);
507 static INTBIG      io_edcheck_name(void);
508 static INTBIG      io_edpop_stack(void);
509 static void        io_edprocess_integer(INTBIG value);
510 static INTSML      io_edgetrot(OTYPES orientation);
511 static INTSML      io_edgettrans(OTYPES orientation);
512 static int         io_edcompare_name(const void *name1, const void *name2);
513 static INTBIG      io_edis_integer(CHAR *buffer);
514 static CHAR       *io_edget_keyword(CHAR *buffer);
515 static CHAR       *io_edget_token(CHAR *buffer, CHAR idelim);
516 static CHAR       *io_edpos_token(void);
517 static BOOLEAN     io_edget_line(CHAR *line, INTBIG limit, FILE *file);
518 static void        io_edget_delim(CHAR delim);
519 static INTBIG      io_edallocport(void);
520 static INTBIG      io_edallocproperty(CHAR *name, PROPERTY_TYPE type, int integer,
521 						float number, CHAR *string);
522 static INTBIG      io_edallocnetport(void);
523 static void        io_edeq_of_a_line(double sx, double sy, double ex, double ey, double *A, double *B, double *C);
524 static INTBIG      io_eddetermine_intersection(double A[2], double B[2], double C[2], double *x, double *y);
525 static void        io_ededif_arc(INTBIG x[3], INTBIG y[3], INTBIG *xc, INTBIG *yc, INTBIG *r, double *so,
526 						double *ar, INTBIG *rot, INTBIG *trans);
527 static NODEPROTO  *io_edmakeiconcell(PORTPROTO *fpp, CHAR *iconname, CHAR *pt, LIBRARY *lib);
528 static void        io_ednamearc(ARCINST *ai);
529 static INTBIG      io_edfindport(NODEPROTO *cell, INTBIG x, INTBIG y, ARCPROTO *ap, NODEINST *nis[],
530 						PORTPROTO *pps[]);
531 static INTBIG      io_edfindport_geom(NODEPROTO *cell, INTBIG x, INTBIG y, ARCPROTO *ap,
532 						NODEINST *nis[], PORTPROTO *pps[], ARCINST **ai);
533 static void        io_edfreenetports(void);
534 static INTBIG      io_ediftextsize(INTBIG textheight);
535 static NODEINST   *io_edifiplacepin(NODEPROTO *np, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy,
536 						INTBIG trans, INTBIG angle, NODEPROTO *parent);
537 
538 /* keyword parser entry points, only these keywords are supported by this parser,
539    if you need more, add them. Each entry point can have an exit point in the
540    function io_edpop_stack. This is processed when ')' is encountered in the EDIF
541    file.
542  */
543 static INTBIG io_ednoop(void);
544 static INTBIG io_edtechnology(void);
545 static INTBIG io_edfabricate(void);
546 static INTBIG io_edpage(void);
547 static INTBIG io_edfigure(void);
548 static INTBIG io_edfigureGroupOverride(void);
549 static INTBIG io_edscale(void);
550 static INTBIG io_edendType(void);
551 static INTBIG io_edcornerType(void);
552 static INTBIG io_edstringDisplay(void);
553 static INTBIG io_edtrue(void);
554 static INTBIG io_edfalse(void);
555 static INTBIG io_edgetlayer(void);
556 static INTBIG io_edpointList(void);
557 static INTBIG io_edpoint(void);
558 static INTBIG io_edjustify(void);
559 static INTBIG io_edtextHeight(void);
560 static INTBIG io_edpt(void);
561 static INTBIG io_edorientation(void);
562 static INTBIG io_edpathWidth(void);
563 static INTBIG io_edrectangle(void);
564 static INTBIG io_edcircle(void);
565 static INTBIG io_edpath(void);
566 static INTBIG io_edpolygon(void);
567 static INTBIG io_edopenShape(void);
568 static INTBIG io_edfreeptlist(void);
569 static INTBIG io_edlibrary(void);
570 static INTBIG io_eddesign(void);
571 static INTBIG io_edcell(void);
572 static INTBIG io_edview(void);
573 static INTBIG io_edviewType(void);
574 static INTBIG io_edcontents(void);
575 static INTBIG io_edport(void);
576 static INTBIG io_eddirection(void);
577 static INTBIG io_edinstance(void);
578 static INTBIG io_edarray(void);
579 static INTBIG io_eddelta(void);
580 static INTBIG io_edcellRef(void);
581 static INTBIG io_edproperty(void);
582 static INTBIG io_ednet(void);
583 static INTBIG io_ednetBundle(void);
584 static INTBIG io_edjoined(void);
585 static INTBIG io_edportRef(void);
586 static INTBIG io_edinstanceRef(void);
587 static INTBIG io_edmember(void);
588 static INTBIG io_edname(void);
589 static INTBIG io_edrename(void);
590 static INTBIG io_edboundingBox(void);
591 static INTBIG io_edsymbol(void);
592 static INTBIG io_edportImplementation(void);
593 static INTBIG io_edconnectLocation(void);
594 static INTBIG io_eddot(void);
595 static INTBIG io_edprogram(void);
596 static INTBIG io_edunit(void);
597 static INTBIG io_edinteger(void);
598 static INTBIG io_ednumber(void);
599 static INTBIG io_edstring(void);
600 static INTBIG io_edinterface(void);
601 
602 /* Parser keyword state tables, only some are provided, others are simply incomplete.
603    If you have time, please feel free to complete these keyword tables and the following
604    parse array. Note that a bad state does not cause the parser to quit, the action is
605    still executed.
606  */
607 static KSTATE Sarray[] = {KINSTANCE, KPORT, KNET, KUNKNOWN};
608 static KSTATE Sauthor[] = {KWRITTEN, KUNKNOWN};
609 static KSTATE SboundingBox[] = {KSYMBOL, KCONTENTS, KUNKNOWN};
610 static KSTATE Scell[] = {KEXTERNAL, KLIBRARY, KUNKNOWN};
611 static KSTATE ScellRef[] = {KDESIGN, KVIEWREF, KINSTANCE, KUNKNOWN};
612 static KSTATE ScellType[] = {KCELL, KUNKNOWN};
613 static KSTATE Scontents[] = {KVIEW, KUNKNOWN};
614 static KSTATE Sdesign[] = {KEDIF, KUNKNOWN};
615 static KSTATE Sdirection[] = {KPORT, KUNKNOWN};
616 static KSTATE Sedif[] = {KINIT, KUNKNOWN};
617 static KSTATE SedifLevel[] = {KEDIF, KEXTERNAL, KLIBRARY, KUNKNOWN};
618 static KSTATE SedifVersion[] = {KEDIF, KUNKNOWN};
619 static KSTATE Sinstance[] = {KCONTENTS, KPAGE, KPORTIMPLEMENTATION, KCOMMENTGRAPHICS, KUNKNOWN};
620 static KSTATE SinstanceRef[] = {KINSTANCEREF, KPORTREF, KUNKNOWN};
621 static KSTATE Sinterface[] = {KVIEW, KUNKNOWN};
622 static KSTATE Sjoined[] = {KINTERFACE, KNET, KMUSTJOIN, KWEAKJOINED, KUNKNOWN};
623 static KSTATE SkeywordMap[] = {KEDIF, KUNKNOWN};
624 static KSTATE Slibrary[] = {KEDIF, KUNKNOWN};
625 static KSTATE SlibraryRef[] = {KCELLREF, KFIGUREGROUPREF, KLOGICREF, KUNKNOWN};
626 static KSTATE SlistOfNets[] = {KNETBUNDLE, KUNKNOWN};
627 static KSTATE Snet[] = {KCONTENTS, KPAGE, KLISTOFNETS, KUNKNOWN};
628 static KSTATE SnetBundle[] = {KCONTENTS, KPAGE, KUNKNOWN};
629 static KSTATE SnumberDefinition[] = {KTECHNOLOGY, KUNKNOWN};
630 static KSTATE Sport[] = {KINTERFACE, KLISTOFPORTS, KUNKNOWN};
631 static KSTATE Sscale[] = {KNUMBERDEFINITION, KUNKNOWN};
632 static KSTATE Sstatus[] = {KCELL, KDESIGN, KEDIF, KEXTERNAL, KLIBRARY, KVIEW, KUNKNOWN};
633 static KSTATE Ssymbol[] = {KINTERFACE, KUNKNOWN};
634 static KSTATE Stechnology[] = {KEXTERNAL, KLIBRARY, KUNKNOWN};
635 static KSTATE Stimestamp[] = {KWRITTEN, KUNKNOWN};
636 static KSTATE Sunit[] = {KPARAMETER, KPROPERTY, KSCALE, KUNKNOWN};
637 static KSTATE Sview[] = {KCELL, KUNKNOWN};
638 static KSTATE SviewRef[] = {KINSTANCE, KINSTANCEREF, KNETREF, KPORTREF, KSITE, KVIEWLIST, KUNKNOWN};
639 static KSTATE SviewType[] = {KVIEW, KUNKNOWN};
640 static KSTATE Swritten[] = {KSTATUS, KUNKNOWN};
641 
642 /* To add a new keyword, insert into this sorted list and into the enumerated keyword
643    list in ioedif.h. If no action is required, just use the io_ednoop as the action
644    routine. If some action is required, add a new function. Note that all operations
645    are dependent on the current state. If a keyword is correct, but the required state
646    table is not, add it to the above data structure (_kstate). Or make it non-state
647    dependent with a KNULL in the last field.
648  */
649 static EDIFKEY edif_keywords[] =
650 {
651 	{x_("annotate"), io_ednoop, KANNOTATE, KNULL},
652 	{x_("arc"), io_ednoop, KARC, KNULL},
653 	{x_("array"), io_edarray, KARRAY, Sarray},
654 	{x_("author"), io_ednoop, KAUTHOR, Sauthor},
655 	{x_("boolean"), io_ednoop, KBOOLEAN, KNULL},
656 	{x_("borderWidth"), io_ednoop, KBORDERWIDTH, KNULL},
657 	{x_("boundingBox"), io_edboundingBox, KBOUNDINGBOX, SboundingBox},
658 	{x_("cell"), io_edcell, KCELL, Scell },
659 	{x_("cellRef"), io_edcellRef, KCELLREF, ScellRef},
660 	{x_("cellType"), io_ednoop, KCELLTYPE, ScellType},
661 	{x_("circle"), io_edcircle, KCIRCLE, KNULL},
662 	{x_("color"), io_ednoop, KCOLOR, KNULL},
663 	{x_("comment"), io_ednoop, KCOMMENT, KNULL},
664 	{x_("commentGraphics"), io_ednoop, KCOMMENTGRAPHICS, KNULL},
665 	{x_("connectLocation"), io_edconnectLocation, KCONNECTLOCATION, KNULL},
666 	{x_("contents"), io_edcontents, KCONTENTS, Scontents},
667 	{x_("cornerType"), io_edcornerType, KCORNERTYPE, KNULL},
668 	{x_("curve"), io_ednoop, KCURVE, KNULL},
669 	{x_("dataOrigin"), io_ednoop, KDATAORIGIN, KNULL},
670 	{x_("dcFanoutLoad"), io_ednoop, KDCFANOUTLOAD, KNULL},
671 	{x_("dcMaxFanout"), io_ednoop, KDCMAXFANOUT, KNULL},
672 	{x_("delta"), io_eddelta, KDELTA, KNULL},
673 	{x_("design"), io_eddesign, KDESIGN, Sdesign},
674 	{x_("designator"), io_ednoop, KDESIGNATOR, KNULL},
675 	{x_("direction"), io_eddirection, KDIRECTION, Sdirection},
676 	{x_("display"), io_edfigure, KDISPLAY, KNULL},
677 	{x_("dot"), io_eddot, KDOT, KNULL},
678 	{x_("e"), io_ednoop, KSCALEDINTEGER, KNULL},
679 	{x_("edif"), io_ednoop, KEDIF, Sedif},
680 	{x_("edifLevel"), io_ednoop, KEDIFLEVEL, SedifLevel},
681 	{x_("edifVersion"), io_ednoop, KEDIFVERSION, SedifVersion},
682 	{x_("endType"), io_edendType, KENDTYPE, KNULL},
683 	{x_("external"), io_edlibrary, KEXTERNAL, Slibrary},
684 	{x_("fabricate"), io_edfabricate, KFABRICATE, KNULL},
685 	{x_("false"), io_edfalse, KFALSE, KNULL},
686 	{x_("figure"), io_edfigure, KFIGURE, KNULL},
687 	{x_("figureGroup"), io_ednoop, KFIGUREGROUP, KNULL},
688 	{x_("figureGroupOverride"), io_edfigureGroupOverride, KFIGUREGROUPOVERRIDE, KNULL},
689 	{x_("fillpattern"), io_ednoop, KFILLPATTERN, KNULL},
690 	{x_("gridMap"), io_ednoop, KGRIDMAP, KNULL},
691 	{x_("instance"), io_edinstance, KINSTANCE, Sinstance},
692 	{x_("instanceRef"), io_edinstanceRef, KINSTANCEREF, SinstanceRef},
693 	{x_("integer"), io_edinteger, KINTEGER, KNULL},
694 	{x_("interface"), io_edinterface, KINTERFACE, Sinterface},
695 	{x_("joined"), io_edjoined, KJOINED, Sjoined},
696 	{x_("justify"), io_edjustify, KJUSTIFY, KNULL},
697 	{x_("keywordDisplay"), io_ednoop, KKEYWORDDISPLAY, KNULL},
698 	{x_("keywordLevel"), io_ednoop, KEDIFKEYLEVEL, KNULL},
699 	{x_("keywordMap"), io_ednoop, KEDIFKEYMAP, SkeywordMap},
700 	{x_("library"), io_edlibrary, KLIBRARY, Slibrary},
701 	{x_("libraryRef"), io_ednoop, KLIBRARYREF, SlibraryRef},
702 	{x_("listOfNets"), io_ednoop, KLISTOFNETS, SlistOfNets},
703 	{x_("listOfPorts"), io_ednoop, KLISTOFPORTS, KNULL},
704 	{x_("member"), io_edmember, KMEMBER, KNULL},
705 	{x_("name"), io_edname, KNAME, KNULL},
706 	{x_("net"), io_ednet, KNET, Snet},
707 	{x_("netBundle"), io_ednetBundle, KNETBUNDLE, SnetBundle},
708 	{x_("number"), io_ednumber, KNUMBER, KNULL},
709 	{x_("numberDefinition"), io_ednoop, KNUMBERDEFINITION, SnumberDefinition},
710 	{x_("openShape"), io_edopenShape, KOPENSHAPE, KNULL},
711 	{x_("orientation"), io_edorientation, KORIENTATION, KNULL},
712 	{x_("origin"), io_ednoop, KORIGIN, KNULL},
713 	{x_("owner"), io_ednoop, KOWNER, KNULL},
714 	{x_("page"), io_edpage, KPAGE, KNULL},
715 	{x_("pageSize"), io_ednoop, KPAGESIZE, KNULL},
716 	{x_("path"), io_edpath, KPATH, KNULL},
717 	{x_("pathWidth"), io_edpathWidth, KPATHWIDTH, KNULL},
718 	{x_("point"), io_edpoint, KPOINT, KNULL},
719 	{x_("pointList"), io_edpointList, KPOINTLIST, KNULL},
720 	{x_("polygon"), io_edpolygon, KPOLYGON, KNULL},
721 	{x_("port"), io_edport, KPORT, Sport},
722 	{x_("portBundle"), io_ednoop, KPORTBUNDLE, KNULL},
723 	{x_("portImplementation"), io_edportImplementation, KPORTIMPLEMENTATION, KNULL},
724 	{x_("portInstance"), io_ednoop,KPORTINSTANCE, KNULL},
725 	{x_("portList"), io_ednoop, KPORTLIST, KNULL},
726 	{x_("portRef"), io_edportRef, KPORTREF, KNULL},
727 	{x_("program"), io_edprogram, KPROGRAM, KNULL},
728 	{x_("property"), io_edproperty, KPROPERTY, KNULL},
729 	{x_("propertyDisplay"), io_ednoop, KPROPERTYDISPLAY, KNULL},
730 	{x_("pt"), io_edpt, KPT, KNULL},
731 	{x_("rectangle"), io_edrectangle, KRECTANGLE, KNULL},
732 	{x_("rename"), io_edrename, KRENAME, KNULL},
733 	{x_("scale"), io_edscale, KSCALE, Sscale},
734 	{x_("scaleX"), io_ednoop, KSCALEX, KNULL},
735 	{x_("scaleY"), io_ednoop, KSCALEY, KNULL},
736 	{x_("shape"), io_ednoop, KSHAPE, KNULL},
737 	{x_("status"), io_ednoop, KSTATUS, Sstatus},
738 	{x_("string"), io_edstring, KSTRING, KNULL},
739 	{x_("stringDisplay"), io_edstringDisplay, KSTRINGDISPLAY, KNULL},
740 	{x_("symbol"), io_edsymbol, KSYMBOL, Ssymbol},
741 	{x_("technology"), io_edtechnology, KTECHNOLOGY, Stechnology},
742 	{x_("textHeight"), io_edtextHeight, KTEXTHEIGHT, KNULL},
743 	{x_("timestamp"), io_ednoop, KTIMESTAMP, Stimestamp},
744 	{x_("transform"), io_ednoop, KTRANSFORM, KNULL},
745 	{x_("true"), io_edtrue, KTRUE, KNULL},
746 	{x_("unit"), io_edunit, KUNIT, Sunit},
747 	{x_("userData"), io_ednoop, KUSERDATA, KNULL},
748 	{x_("version"), io_ednoop, KVERSION, KNULL},
749 	{x_("view"), io_edview, KVIEW, Sview},
750 	{x_("viewRef"), io_ednoop, KVIEWREF, SviewRef},
751 	{x_("viewType"), io_edviewType, KVIEWTYPE, SviewType},
752 	{x_("visible"), io_ednoop, KVISIBLE, KNULL},
753 	{x_("written"), io_ednoop, KWRITTEN, Swritten},
754 	{0,0,KUNKNOWN,0}
755 };
756 
757 /* edif keyword stack, this stack matches the current depth of the EDIF file,
758    for the keyword instance it would be KEDIF, KLIBRARY, KCELL, KCONTENTS, KINSTANCE
759  */
760 static KSTATE kstack[1000];
761 static INTBIG kstack_ptr = 0;
762 static INTBIG filelen, filepos;
763 
764 /* some standard artwork primitivies */
765 static PORTPROTO *default_port = NOPORTPROTO;
766 static PORTPROTO *default_iconport = NOPORTPROTO;
767 static PORTPROTO *default_busport = NOPORTPROTO;
768 static PORTPROTO *default_input = NOPORTPROTO;
769 static PORTPROTO *default_output = NOPORTPROTO;
770        INTBIG     EDIF_name_key = 0;
771 static INTBIG     EDIF_array_key = 0;
772 static INTBIG     EDIF_annotate_key = 0;
773 static void      *io_edifprogressdialog;
774 static struct
775 {
776 	int width;
777 	int height;
778 } EDIF_sheet_bounds[MAXSHEETS] =
779 {
780 	{8, 10},
781 	{16, 10},
782 	{16, 20},
783 	{32, 20},
784 	{32, 40},
785 	{64, 40}
786 };
787 
788 #define RET_NOMEMORY() { ttyputnomemory(); return(1); }
789 
790 
791 /*
792  * Routine to free all memory associated with this module.
793  */
io_freeedifinmemory(void)794 void io_freeedifinmemory(void)
795 {
796 	EDNETPORT_PTR nport, nnport;
797 
798 	/* free the netport freelist */
799 	for (nport = io_edifgbl.free_netports; nport != NOEDNETPORT; nport = nnport)
800 	{
801 		nnport = nport->next;
802 		efree((CHAR *)nport);
803 	}
804 	if (io_edifgbl.ptype == PSTRING) efree(io_edifgbl.pval.string);
805 	io_edfreesavedptlist();
806 	io_edfreeptlist();
807 }
808 
809 /*
810  * routine to write a ".edif" file from the library "lib"
811  */
io_readediflibrary(LIBRARY * lib)812 BOOLEAN io_readediflibrary(LIBRARY *lib)
813 {
814 	INTBIG key_count, i;
815 	CHAR *filename, *msg;
816 	NODEPROTO *np;
817 	REGISTER VARIABLE *var;
818 	REGISTER void *infstr;
819 
820 	io_edifgbl.edif_file = xopen(lib->libfile, io_filetypeedif, x_(""), &filename);
821 	if (io_edifgbl.edif_file == NULL)
822 	{
823 		ttyputerr(_("File %s not found"), lib->libfile);
824 		return(TRUE);
825 	}
826 	filelen = filesize(io_edifgbl.edif_file);
827 	filepos = 0;
828 
829 	/* one-time inits */
830 	if (!io_edgblinited)
831 	{
832 		io_edifgbl.firstnetport = io_edifgbl.lastnetport = io_edifgbl.free_netports = NOEDNETPORT;
833 		io_edifgbl.ptype = PUNKNOWN;
834 		io_edifgbl.points = io_edifgbl.lastpt = NOEPT;
835 		io_edifgbl.pt_count = 0;
836 		io_edifgbl.save_text.points = NOEPT;
837 		io_edifgbl.save_text.pt_count = 0;
838 		io_edgblinited = TRUE;
839 	}
840 
841 	/* parser inits */
842 	io_edifgbl.state = KINIT;
843 	io_edifgbl.lineno = 1;
844 	io_edifgbl.buffer[0] = 0;
845 	io_edifgbl.pos = io_edifgbl.buffer;
846 	io_edifgbl.delimeters = DELIMETERS;
847 	io_edifgbl.errors = io_edifgbl.warnings = 0;
848 	io_edifgbl.ignoreblock = 0;
849 	io_edifgbl.vendor = EVUNKNOWN;
850 
851 	/* general inits */
852 	var = getval((INTBIG)io_tool, VTOOL, VFLOAT, x_("IO_edif_input_scale"));
853 	if (var == NOVARIABLE) io_edifgbl.scale = 1.0; else
854 		io_edifgbl.scale = castfloat(var->addr);
855 	io_edifgbl.dbunit = 1.0;
856 	/*  io_edifgbl.meters = 0.000000001; */ /* default 1 db unit per nanometer */
857 	io_edifgbl.meters = scaletodispunit(1, DISPUNITCM) / 100.0;
858 	io_edifgbl.library = lib;
859 	io_edifgbl.technology = sch_tech;
860 	io_edifgbl.celltbl_sze = io_edifgbl.celltbl_cnt = 0;
861 	io_edifgbl.ports = io_edifgbl.free_ports = NOEDPORT;
862 	io_edifgbl.properties = io_edifgbl.free_properties = NOEDPROPERTY;
863 	io_edfreenetports();
864 
865 	/* active database inits */
866 	io_edifgbl.current_cell = NONODEPROTO;
867 	io_edifgbl.current_node = NONODEINST;
868 	io_edifgbl.current_arc = NOARCINST;
869 	io_edifgbl.current_port = NOPORTPROTO;
870 	io_edifgbl.figure_group = NONODEPROTO;
871 	io_edifgbl.arc_type = NOARCPROTO;
872 	io_edifgbl.proto = NONODEPROTO;
873 
874 	/* name inits */
875 	io_edifgbl.cell_reference[0] = 0;
876 	io_edifgbl.port_reference[0] = 0;
877 	io_edifgbl.instance_reference[0] = 0;
878 	io_edifgbl.bundle_reference[0] = 0;
879 	io_edifgbl.net_reference[0] = 0;
880 	io_edifgbl.property_reference[0] = 0;
881 
882 	/* geometry inits */
883 	io_edifgbl.layer_ptr = 0;
884 	io_edifgbl.cur_nametbl = NONAMETABLE;
885 	io_edfreeptlist();
886 
887 	/* text inits */
888 	io_edifgbl.textheight = 0;
889 	io_edifgbl.justification = LOWERLEFT;
890 	io_edifgbl.visible = 1;
891 	io_edifgbl.save_text.string[0] = 0;
892 	io_edfreesavedptlist();
893 
894 	io_edifgbl.sheet_size = SHEET_DSIZE;
895 	io_edifgbl.sh_xpos = -1;
896 	io_edifgbl.sh_ypos = -1;
897 
898 	kstack_ptr = 0;
899 
900 	if (default_port == NOPORTPROTO) default_port = getportproto(sch_wirepinprim, x_("wire"));
901 	default_iconport = sch_wirepinprim->firstportproto;
902 	if (default_busport == NOPORTPROTO) default_busport = getportproto(sch_buspinprim, x_("bus"));
903 	if (default_input == NOPORTPROTO) default_input = getportproto(sch_offpageprim, x_("y"));
904 	if (default_output == NOPORTPROTO) default_output = getportproto(sch_offpageprim, x_("a"));
905 
906 	if (EDIF_name_key == 0) EDIF_name_key = makekey(x_("EDIF_name"));
907 	if (EDIF_array_key == 0) EDIF_array_key = makekey(x_("EDIF_array"));
908 	if (EDIF_annotate_key == 0) EDIF_annotate_key = makekey(x_("EDIF_annotate"));
909 
910 	/* now load the edif netlist */
911 	infstr = initinfstr();
912 	formatinfstr(infstr, _("Reading %s"), filename);
913 	msg = returninfstr(infstr);
914 	if (io_verbose < 0)
915 	{
916 		io_edifprogressdialog = DiaInitProgress(msg, 0);
917 		if (io_edifprogressdialog == 0)
918 		{
919 			xclose(io_edifgbl.edif_file);
920 			return(TRUE);
921 		}
922 		DiaSetProgress(io_edifprogressdialog, 0, filelen);
923 	} else ttyputmsg(msg);
924 
925 	/* count the number of keywords */
926 	key_count = 0;
927 	while (edif_keywords[key_count].name != 0) key_count++;
928 	if (io_edload_edif(key_count, edif_keywords))
929 	{
930 		ttyputerr(_("error: bad design, aborting netlist translation"));
931 		if (io_verbose < 0) DiaDoneProgress(io_edifprogressdialog);
932 		return(TRUE);
933 	}
934 	if (io_edifgbl.errors || io_edifgbl.warnings)
935 		ttyputmsg(_("info: a total of %d errors, and %d warnings encountered during load"),
936 			io_edifgbl.errors, io_edifgbl.warnings);
937 
938 	xclose(io_edifgbl.edif_file);
939 	if (io_verbose < 0)
940 	{
941 		DiaSetProgress(io_edifprogressdialog, 999, 1000);
942 		DiaSetTextProgress(io_edifprogressdialog, _("Cleaning Up..."));
943 	}
944 
945 	/* free the layer table */
946 	for (i = 0; i < io_edifgbl.layer_ptr; i++)
947 	{
948 		if (io_edifgbl.nametbl[i]->original != io_edifgbl.nametbl[i]->replace)
949 			efree(io_edifgbl.nametbl[i]->replace);
950 		efree(io_edifgbl.nametbl[i]->original);
951 		efree((CHAR *)io_edifgbl.nametbl[i]);
952 	}
953 	/* note the master list is static */
954 
955 	/* now the cell name table */
956 	for(i = 0; i < io_edifgbl.celltbl_cnt; i++)
957 	{
958 		if (io_edifgbl.celltbl[i]->original != io_edifgbl.celltbl[i]->replace)
959 			efree(io_edifgbl.celltbl[i]->replace);
960 		efree(io_edifgbl.celltbl[i]->original);
961 		efree((CHAR *)io_edifgbl.celltbl[i]);
962 	}
963 
964 	/* and the master list ... */
965 	if (io_edifgbl.celltbl_cnt != 0)
966 	{
967 		efree((CHAR *)io_edifgbl.celltbl);
968 	} else
969 	{
970 		ttyputerr(_("error: no data"));
971 		if (io_verbose < 0) DiaDoneProgress(io_edifprogressdialog);
972 		return(TRUE);
973 	}
974 
975 	if (io_edifgbl.library->curnodeproto == NONODEPROTO)
976 		io_edifgbl.library->curnodeproto = io_edifgbl.library->firstnodeproto;
977 
978 	for (np = io_edifgbl.library->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
979 		net_examinenodeproto(np);
980 
981 	/* recompute bounds */
982 	(*el_curconstraint->solve)(NONODEPROTO);
983 
984 	if (io_verbose < 0) DiaDoneProgress(io_edifprogressdialog);
985 	return(FALSE);
986 }
987 
988 /*
989  * Module: io_edload_edif
990  * Function:  Will load the edif netlist into memory
991  * Method:  Does a simple keyword lookup to load the lisp structured
992  *		 EDIF language into Electric's database
993  */
io_edload_edif(INTBIG key_count,EDIFKEY_PTR keywords)994 INTBIG io_edload_edif(INTBIG key_count, EDIFKEY_PTR keywords)
995 {
996 	KSTATE *state;
997 	CHAR *msg;
998 	CHAR *token, word[WORD+1];
999 	INTBIG low, high, mid, change, errcode;
1000 	INTBIG keycount;
1001 	INTBIG savestack;
1002 
1003 	/* setup the error return location */
1004 	errcode = setjmp(io_edifgbl.env);
1005 	if (errcode != 0)
1006 	{
1007 		switch (errcode)
1008 		{
1009 			case LONGJMPEOF:      msg = _("Unexpected end-of-file");   break;
1010 			case LONGJMPNOMEM:    msg = _("No memory");                break;
1011 			case LONGJMPPTMIS:    msg = _("Point list mismatch");      break;
1012 			case LONGJMPNOLIB:    msg = _("Could not create library"); break;
1013 			case LONGJMPNOINT:    msg = _("No integer value");         break;
1014 			case LONGJMPILLNUM:   msg = _("Illegal number value");     break;
1015 			case LONGJMPNOMANT:   msg = _("No matissa value");         break;
1016 			case LONGJMPNOEXP:    msg = _("No exponent value");        break;
1017 			case LONGJMPILLNAME:  msg = _("Illegal name");             break;
1018 			case LONGJMPILLDELIM: msg = _("Illegal delimeter");        break;
1019 			default:              msg = _("Unknown error");            break;
1020 		}
1021 		ttyputerr(_("line #%d: %s"), io_edifgbl.lineno, msg);
1022 		return(1);
1023 	}
1024 
1025 	savestack = -1;
1026 
1027 	/* now read and parse the edif netlist */
1028 	keycount = 0;
1029 	while ((token = io_edget_keyword(word)) != NULL)
1030 	{
1031 		keycount++;
1032 		if ((keycount%100) == 0)
1033 		{
1034 			if (io_verbose < 0) DiaSetProgress(io_edifprogressdialog, filepos, filelen); else
1035 				ttyputmsg(_("%ld keywords read (%d%% done)"), keycount, filepos*100/filelen);
1036 		}
1037 
1038 		/* locate the keyword, and execute the function */
1039 		low = 0;
1040 		high = key_count - 1;
1041 		while (low <= high)
1042 		{
1043 			mid = (low + high) / 2;
1044 			change = namesame(token, keywords[mid].name);
1045 			if (change < 0) high = mid - 1; else
1046 				if (change > 0) low = mid + 1; else
1047 			{
1048 				/* found the function, check state */
1049 				if (keywords[mid].state != KNULL && io_edifgbl.state != KUNKNOWN)
1050 				{
1051 					state = keywords[mid].state;
1052 					while (*state && io_edifgbl.state != *state) state++;
1053 					if (io_edifgbl.state != *state)
1054 					{
1055 						ttyputerr(_("error, line #%d: illegal state for keyword <%s>"),
1056 							io_edifgbl.lineno, token);
1057 						io_edifgbl.errors++;
1058 					}
1059 				}
1060 
1061 				/* call the function */
1062 				kstack[kstack_ptr++] = io_edifgbl.state;
1063 				io_edifgbl.state = keywords[mid].next;
1064 				if (savestack >= kstack_ptr)
1065 				{
1066 					savestack = -1;
1067 					io_edifgbl.ignoreblock = 0;
1068 				}
1069 				if (!io_edifgbl.ignoreblock) (keywords[mid].func)();
1070 				if (io_edifgbl.ignoreblock)
1071 				{
1072 					if (savestack == -1) savestack = kstack_ptr;
1073 				}
1074 				break;
1075 			}
1076 		}
1077 		if (low > high)
1078 		{
1079 			ttyputerr(_("warning, line #%d: unknown keyword <%s>"), io_edifgbl.lineno, token);
1080 			io_edifgbl.warnings++;
1081 			kstack[kstack_ptr++] = io_edifgbl.state;
1082 			io_edifgbl.state = KUNKNOWN;
1083 		}
1084 	}
1085 	if (io_edifgbl.state != KINIT)
1086 	{
1087 		ttyputerr(_("line #%d: unexpected end-of-file encountered"), io_edifgbl.lineno);
1088 		io_edifgbl.errors++;
1089 	}
1090 	return(0);
1091 }
1092 
1093 /* parser routines */
io_ednoop(void)1094 INTBIG io_ednoop(void)
1095 {
1096 	return(0);
1097 }
1098 
io_edtechnology(void)1099 INTBIG io_edtechnology(void)
1100 {
1101 	return(0);
1102 }
1103 
io_edfabricate(void)1104 INTBIG io_edfabricate(void)
1105 {
1106 	INTBIG pos;
1107 	CHAR name[WORD+1];
1108 
1109 	pos = io_edifgbl.layer_ptr;
1110 
1111 	io_edifgbl.nametbl[pos] = (NAMETABLE_PTR)emalloc(sizeof(NAMETABLE), io_tool->cluster);
1112 	if (io_edifgbl.nametbl[pos] == NONAMETABLE) RET_NOMEMORY();
1113 
1114 	/* first get the original and replacement layers */
1115 	if ((io_edget_token(name, 0)) == NULL)
1116 		longjmp(io_edifgbl.env, LONGJMPEOF);
1117 	if (allocstring(&io_edifgbl.nametbl[pos]->original, name, io_tool->cluster)) RET_NOMEMORY();
1118 	if ((io_edget_token(name, 0)) == NULL)
1119 		longjmp(io_edifgbl.env, LONGJMPEOF);
1120 	if (allocstring(&io_edifgbl.nametbl[pos]->replace, name, io_tool->cluster)) RET_NOMEMORY();
1121 	io_edifgbl.nametbl[pos]->textheight = 0;
1122 	io_edifgbl.nametbl[pos]->justification = LOWERLEFT;
1123 	io_edifgbl.nametbl[pos]->visible = 1;
1124 
1125 	/* now bump the position */
1126 	io_edifgbl.layer_ptr++;
1127 	return(0);
1128 }
1129 
io_edpage(void)1130 INTBIG io_edpage(void)
1131 {
1132 	CHAR view[WORD+1], cname[WORD+1];
1133 	NODEPROTO *proto;
1134 
1135 	/* check for the name */
1136 	(void)io_edcheck_name();
1137 
1138 	(void)esnprintf(view, WORD+1, x_("p%d"), ++io_edifgbl.pageno);
1139 
1140 	/* locate this in the list of cells */
1141 	for (proto = io_edifgbl.library->firstnodeproto; proto != NONODEPROTO; proto = proto->nextnodeproto)
1142 	{
1143 		if (!namesame(proto->protoname, io_edifgbl.cell_name) &&
1144 			!namesame(proto->cellview->sviewname, view)) break;
1145 	}
1146 	if (proto == NONODEPROTO)
1147 	{
1148 		/* allocate the cell */
1149 		esnprintf(cname, WORD+1, x_("%s{%s}"), io_edifgbl.cell_name, view);
1150 		proto = us_newnodeproto(cname, io_edifgbl.library);
1151 		if (proto == NONODEPROTO) longjmp(io_edifgbl.env, LONGJMPNOMEM);
1152 		proto->temp1 = 0;
1153 	}
1154 	else if (proto->temp1) io_edifgbl.ignoreblock = 1;
1155 
1156 	io_edifgbl.current_cell = proto;
1157 	return(0);
1158 }
1159 
io_edfigure(void)1160 INTBIG io_edfigure(void)
1161 {
1162 	CHAR layer[WORD+1];
1163 	INTBIG low, high, change, mid;
1164 	INTBIG pos;
1165 
1166 	/* get the layer name */
1167 	/* check for figuregroup override */
1168 	if (*io_edpos_token() == '(') return(0);
1169 	if (io_edget_token(layer, 0) == NULL)
1170 		longjmp(io_edifgbl.env, LONGJMPEOF);
1171 
1172 	/* now look for this layer in the list of layers */
1173 	low = 0;
1174 	high = io_edifgbl.layer_ptr - 1;
1175 	while (low <= high)
1176 	{
1177 		mid = (low + high) / 2;
1178 		change = namesame(layer, io_edifgbl.nametbl[mid]->original);
1179 		if (change < 0) high = mid - 1; else
1180 			if (change > 0) low = mid + 1; else
1181 		{
1182 			/* found the layer */
1183 			io_edifgbl.figure_group = io_edifgbl.nametbl[mid]->node;
1184 			io_edifgbl.arc_type = io_edifgbl.nametbl[mid]->arc;
1185 			io_edifgbl.textheight = io_edifgbl.nametbl[mid]->textheight;
1186 			io_edifgbl.justification = io_edifgbl.nametbl[mid]->justification;
1187 			io_edifgbl.visible = io_edifgbl.nametbl[mid]->visible;
1188 
1189 			/* allow new definitions */
1190 			io_edifgbl.cur_nametbl = io_edifgbl.nametbl[mid];
1191 			break;
1192 		}
1193 	}
1194 	if (low > high)
1195 	{
1196 		pos = io_edifgbl.layer_ptr;
1197 		io_edifgbl.nametbl[pos] = (NAMETABLE_PTR)emalloc(sizeof(NAMETABLE), io_tool->cluster);
1198 		if (io_edifgbl.nametbl[pos] == NONAMETABLE ||
1199 			allocstring(&io_edifgbl.nametbl[pos]->original, layer, io_tool->cluster))
1200 				longjmp(io_edifgbl.env, LONGJMPNOMEM);
1201 		io_edifgbl.nametbl[pos]->replace = io_edifgbl.nametbl[pos]->original;
1202 		io_edifgbl.figure_group = io_edifgbl.nametbl[pos]->node = art_boxprim;
1203 		io_edifgbl.arc_type = io_edifgbl.nametbl[pos]->arc = sch_wirearc;
1204 		io_edifgbl.textheight = io_edifgbl.nametbl[pos]->textheight = 0;
1205 		io_edifgbl.justification = io_edifgbl.nametbl[pos]->justification = LOWERLEFT;
1206 		io_edifgbl.visible = io_edifgbl.nametbl[pos]->visible = 1;
1207 
1208 		/* allow new definitions */
1209 		io_edifgbl.cur_nametbl = io_edifgbl.nametbl[pos];
1210 
1211 		/* now sort the list */
1212 		io_edifgbl.layer_ptr++;
1213 		esort(io_edifgbl.nametbl, io_edifgbl.layer_ptr, sizeof(NAMETABLE_PTR),
1214 			io_edcompare_name);
1215 	}
1216 	return(0);
1217 }
1218 
io_edfigureGroupOverride(void)1219 INTBIG io_edfigureGroupOverride(void)
1220 {
1221 	return(io_edgetlayer());
1222 }
1223 
io_edscale(void)1224 INTBIG io_edscale(void)
1225 {
1226 	/* get the scale */
1227 	io_edifgbl.val1 = io_edgetnumber();
1228 	io_edifgbl.val2 = io_edgetnumber();
1229 	return(0);
1230 }
1231 
io_edendType(void)1232 INTBIG io_edendType(void)
1233 {
1234 	CHAR type[WORD+1];
1235 
1236 	/* get the endtype */
1237 	if (io_edget_token(type, 0) == NULL)
1238 		longjmp(io_edifgbl.env, LONGJMPEOF);
1239 
1240 	if (!namesame(type, x_("EXTEND"))) io_edifgbl.extend_end = 1;
1241 	return(0);
1242 }
1243 
io_edcornerType(void)1244 INTBIG io_edcornerType(void)
1245 {
1246 	CHAR type[WORD+1];
1247 
1248 	/* get the endtype */
1249 	if (io_edget_token(type, 0) == NULL)
1250 		longjmp(io_edifgbl.env, LONGJMPEOF);
1251 
1252 	if (!namesame(type, x_("EXTEND"))) io_edifgbl.extend_corner = 1;
1253 	return(0);
1254 }
1255 
io_edstringDisplay(void)1256 INTBIG io_edstringDisplay(void)
1257 {
1258 	INTBIG kptr;
1259 
1260 	/* init the point lists */
1261 	io_edfreeptlist();
1262 	io_edifgbl.points = io_edifgbl.lastpt = NOEPT;
1263 	io_edifgbl.orientation = OR0;
1264 	io_edifgbl.visible = 1;
1265 	io_edifgbl.justification = LOWERLEFT;
1266 	io_edifgbl.textheight = 0;
1267 
1268 	/* get the string, remove the quote */
1269 	io_edget_delim('\"');
1270 	if (io_edget_token(io_edifgbl.string, '\"') == NULL)
1271 		longjmp(io_edifgbl.env, LONGJMPEOF);
1272 
1273 	/* check for RENAME */
1274 	if (kstack[kstack_ptr-1] != KRENAME) return(0);
1275 	(void)estrcpy(io_edifgbl.original, io_edifgbl.string);
1276 	if (kstack[kstack_ptr - 2] == KARRAY) kptr = kstack_ptr - 3; else
1277 		kptr = kstack_ptr - 2;
1278 	switch (kstack[kptr])
1279 	{
1280 		case KCELL:
1281 			(void)estrcpy(io_edifgbl.cell_name, io_edifgbl.original);
1282 			break;
1283 		case KPORT:
1284 			(void)estrcpy(io_edifgbl.port_name, io_edifgbl.original);
1285 			break;
1286 		case KINSTANCE:
1287 			(void)estrcpy(io_edifgbl.instance_name, io_edifgbl.original);
1288 			break;
1289 		case KNET:
1290 			(void)estrcpy(io_edifgbl.net_name, io_edifgbl.original);
1291 			break;
1292 		case KNETBUNDLE:
1293 			(void)estrcpy(io_edifgbl.bundle_name, io_edifgbl.original);
1294 			break;
1295 		case KPROPERTY:
1296 			(void)estrcpy(io_edifgbl.property_name, io_edifgbl.original);
1297 			break;
1298 		default:
1299 			break;
1300 	}
1301 	return(0);
1302 }
1303 
io_edtrue(void)1304 INTBIG io_edtrue(void)
1305 {
1306 	/* check previous keyword */
1307 	if (kstack_ptr > 1 && kstack[kstack_ptr-1] == KVISIBLE)
1308 	{
1309 		io_edifgbl.visible = 1;
1310 		if (io_edifgbl.cur_nametbl != NONAMETABLE)
1311 			io_edifgbl.cur_nametbl->visible = 1;
1312 	}
1313 	return(0);
1314 }
1315 
io_edfalse(void)1316 INTBIG io_edfalse(void)
1317 {
1318 	/* check previous keyword */
1319 	if (kstack_ptr > 1 && kstack[kstack_ptr-1] == KVISIBLE)
1320 	{
1321 		io_edifgbl.visible = 0;
1322 		if (io_edifgbl.cur_nametbl != NONAMETABLE)
1323 			io_edifgbl.cur_nametbl->visible = 0;
1324 	}
1325 	return(0);
1326 }
1327 
io_edgetlayer(void)1328 INTBIG io_edgetlayer(void)
1329 {
1330 	CHAR layer[WORD+1];
1331 	INTBIG low, high, change, mid;
1332 	INTBIG pos;
1333 
1334 	/* get the layer name */
1335 	if (io_edget_token(layer, 0) == NULL)
1336 		longjmp(io_edifgbl.env, LONGJMPEOF);
1337 
1338 	/* now look for this layer in the list of layers */
1339 	low = 0;
1340 	high = io_edifgbl.layer_ptr - 1;
1341 	while (low <= high)
1342 	{
1343 		mid = (low + high) / 2;
1344 		change = namesame(layer, io_edifgbl.nametbl[mid]->original);
1345 		if (change < 0) high = mid - 1; else
1346 			if (change > 0) low = mid + 1; else
1347 		{
1348 			/* found the layer */
1349 			io_edifgbl.figure_group = io_edifgbl.nametbl[mid]->node;
1350 			io_edifgbl.arc_type = io_edifgbl.nametbl[mid]->arc;
1351 			io_edifgbl.textheight = io_edifgbl.nametbl[mid]->textheight;
1352 			io_edifgbl.justification = io_edifgbl.nametbl[mid]->justification;
1353 			io_edifgbl.visible = io_edifgbl.nametbl[mid]->visible;
1354 			break;
1355 		}
1356 	}
1357 	if (low > high)
1358 	{
1359 #ifdef LAYERWARNING
1360 		ttyputerr(_("warning, line #%d: unknown layer <%s>"), io_edifgbl.lineno, layer);
1361 		io_edifgbl.warnings++;
1362 #endif
1363 
1364 		/* insert and resort the list */
1365 		pos = io_edifgbl.layer_ptr;
1366 
1367 		io_edifgbl.nametbl[pos] = (NAMETABLE_PTR)emalloc(sizeof(NAMETABLE), io_tool->cluster);
1368 		if (io_edifgbl.nametbl[pos] == NONAMETABLE ||
1369 			allocstring(&io_edifgbl.nametbl[pos]->original, layer, io_tool->cluster))
1370 				longjmp(io_edifgbl.env, LONGJMPNOMEM);
1371 
1372 		io_edifgbl.nametbl[pos]->replace = io_edifgbl.nametbl[pos]->original;
1373 		io_edifgbl.figure_group = io_edifgbl.nametbl[pos]->node = art_boxprim;
1374 		io_edifgbl.arc_type = io_edifgbl.nametbl[pos]->arc = sch_wirearc;
1375 		io_edifgbl.textheight = io_edifgbl.nametbl[pos]->textheight = 0;
1376 		io_edifgbl.justification = io_edifgbl.nametbl[pos]->justification = LOWERLEFT;
1377 		io_edifgbl.visible = io_edifgbl.nametbl[pos]->visible = 1;
1378 
1379 		/* now sort the list */
1380 		io_edifgbl.layer_ptr++;
1381 		esort(io_edifgbl.nametbl, io_edifgbl.layer_ptr, sizeof(NAMETABLE_PTR),
1382 			io_edcompare_name);
1383 	}
1384 	return(0);
1385 }
1386 
1387 /* geometry routines */
io_edpointList(void)1388 INTBIG io_edpointList(void)
1389 {
1390 	return(0);
1391 }
1392 
io_edpoint(void)1393 INTBIG io_edpoint(void)
1394 {
1395 	return(0);
1396 }
1397 
io_edjustify(void)1398 INTBIG io_edjustify(void)
1399 {
1400 	CHAR val[WORD+1];
1401 
1402 	/* get the textheight value of the point */
1403 	if (io_edget_token(val, 0) == NULL)
1404 		longjmp(io_edifgbl.env, LONGJMPEOF);
1405 	if (namesame(val, x_("UPPERLEFT")))
1406 		io_edifgbl.justification = UPPERLEFT;
1407 	else if (namesame(val, x_("UPPERCENTER")))
1408 		io_edifgbl.justification = UPPERCENTER;
1409 	else if (namesame(val, x_("UPPERRIGHT")))
1410 		io_edifgbl.justification = UPPERRIGHT;
1411 	else if (namesame(val, x_("CENTERLEFT")))
1412 		io_edifgbl.justification = CENTERLEFT;
1413 	else if (namesame(val, x_("CENTERCENTER")))
1414 		io_edifgbl.justification = CENTERCENTER;
1415 	else if (namesame(val, x_("CENTERRIGHT")))
1416 		io_edifgbl.justification = CENTERRIGHT;
1417 	else if (namesame(val, x_("LOWERLEFT")))
1418 		io_edifgbl.justification = LOWERLEFT;
1419 	else if (namesame(val, x_("LOWERCENTER")))
1420 		io_edifgbl.justification = LOWERCENTER;
1421 	else if (namesame(val, x_("LOWERRIGHT")))
1422 		io_edifgbl.justification = LOWERRIGHT;
1423 	else
1424 	{
1425 		ttyputerr(_("warning, line #%d: unknown keyword <%s>"), io_edifgbl.lineno, val);
1426 		io_edifgbl.warnings++;
1427 		return(0);
1428 	}
1429 
1430 	if (io_edifgbl.cur_nametbl != NONAMETABLE)
1431 		io_edifgbl.cur_nametbl->justification = io_edifgbl.justification;
1432 	return(0);
1433 }
1434 
io_edtextHeight(void)1435 INTBIG io_edtextHeight(void)
1436 {
1437 	CHAR val[WORD+1];
1438 
1439 	/* get the textheight value of the point */
1440 	if (io_edget_token(val, 0) == NULL)
1441 		longjmp(io_edifgbl.env, LONGJMPEOF);
1442 	io_edifgbl.textheight = (INTBIG)(eatol(val) * io_edifgbl.scale);
1443 
1444 	if (io_edifgbl.cur_nametbl != NONAMETABLE)
1445 		io_edifgbl.cur_nametbl->textheight = io_edifgbl.textheight;
1446 
1447 	return(0);
1448 }
1449 
io_edpt(void)1450 INTBIG io_edpt(void)
1451 {
1452 	CHAR xstr[WORD+1], ystr[WORD+1];
1453 	EPT_PTR point;
1454 	INTBIG x, y, s;
1455 
1456 	/* get the x and y values of the point */
1457 	if (io_edget_token(xstr, 0) == NULL)
1458 		longjmp(io_edifgbl.env, LONGJMPEOF);
1459 	if (io_edget_token(ystr, 0) == NULL)
1460 		longjmp(io_edifgbl.env, LONGJMPEOF);
1461 
1462 	if (kstack_ptr > 1 && kstack[kstack_ptr-1] == KDELTA)
1463 	{
1464 		x = (INTBIG)(eatol(xstr) * io_edifgbl.scale);
1465 		y = (INTBIG)(eatol(ystr) * io_edifgbl.scale);
1466 
1467 		/* transform the points per orientation */
1468 		switch (io_edifgbl.orientation)
1469 		{
1470 			case OR0:                               break;
1471 			case OR90:   s = x;   x = -y;  y = s;   break;
1472 			case OR180:  x = -x;  y = -y;           break;
1473 			case OR270:  s = x;   x = y;   y = -s;  break;
1474 			case OMY:    x = -x;                    break;
1475 			case OMX:    y = -y;                    break;
1476 			case OMYR90: s = y;   y = -x;  x = -s;  break;
1477 			case OMXR90: s = x;   x = y;   y = s;   break;
1478 			default:                                break;
1479 		}
1480 
1481 		/* set the array deltas */
1482 		if (io_edifgbl.deltapts == 0)
1483 		{
1484 			io_edifgbl.deltaxX = x;
1485 			io_edifgbl.deltaxY = y;
1486 		} else
1487 		{
1488 			io_edifgbl.deltayX = x;
1489 			io_edifgbl.deltayY = y;
1490 		}
1491 		io_edifgbl.deltapts++;
1492 	} else
1493 	{
1494 		/* allocate a point to read */
1495 		point = (EPT_PTR) emalloc(sizeof (EPT), io_tool->cluster);
1496 		if (point == NOEPT) RET_NOMEMORY();
1497 
1498 		/* and set the values */
1499 		point->x = eatol(xstr);
1500 		if (point->x > 0) point->x = (INTBIG)(point->x * io_edifgbl.scale + 0.5); else
1501 			point->x = (INTBIG)(point->x * io_edifgbl.scale - 0.5);
1502 		point->y = eatol(ystr);
1503 		if (point->y > 0) point->y = (INTBIG)(point->y * io_edifgbl.scale + 0.5); else
1504 			point->y = (INTBIG)(point->y * io_edifgbl.scale - 0.5);
1505 		point->nextpt = NOEPT;
1506 
1507 		/* add it to the list of points */
1508 		if (io_edifgbl.points) io_edifgbl.lastpt->nextpt = point; else
1509 			io_edifgbl.points = point;
1510 		io_edifgbl.lastpt = point;
1511 		io_edifgbl.pt_count++;
1512 	}
1513 	return(0);
1514 }
1515 
io_edorientation(void)1516 INTBIG io_edorientation(void)
1517 {
1518 	CHAR orient[WORD+1];
1519 
1520 	/* get the orientation keyword */
1521 	if (io_edget_token(orient, 0) == NULL)
1522 		longjmp(io_edifgbl.env, LONGJMPEOF);
1523 
1524 	if (!namesame(orient, x_("R0"))) io_edifgbl.orientation = OR0;
1525 	else if (!namesame(orient, x_("R90"))) io_edifgbl.orientation = OR90;
1526 	else if (!namesame(orient, x_("R180"))) io_edifgbl.orientation = OR180;
1527 	else if (!namesame(orient, x_("R270"))) io_edifgbl.orientation = OR270;
1528 	else if (!namesame(orient, x_("MY"))) io_edifgbl.orientation = OMY;
1529 	else if (!namesame(orient, x_("MX"))) io_edifgbl.orientation = OMX;
1530 	else if (!namesame(orient, x_("MYR90"))) io_edifgbl.orientation = OMYR90;
1531 	else if (!namesame(orient, x_("MXR90"))) io_edifgbl.orientation = OMXR90;
1532 	else
1533 	{
1534 		ttyputerr(_("warning, line #%d: unknown orientation value <%s>"), io_edifgbl.lineno, orient);
1535 		io_edifgbl.warnings++;
1536 	}
1537 	return(0);
1538 }
1539 
io_edpathWidth(void)1540 INTBIG io_edpathWidth(void)
1541 {
1542 	CHAR width[WORD+1];
1543 
1544 	/* get the width string */
1545 	if (io_edget_token(width, 0) == NULL)
1546 		longjmp(io_edifgbl.env, LONGJMPEOF);
1547 
1548 	io_edifgbl.path_width = eatol(width);
1549 
1550 	return(0);
1551 }
1552 
io_edrectangle(void)1553 INTBIG io_edrectangle(void)
1554 {
1555 	io_edfreeptlist();
1556 	io_edifgbl.points = io_edifgbl.lastpt = NOEPT;
1557 	io_edifgbl.orientation = OR0;
1558 	return(0);
1559 }
1560 
io_edcircle(void)1561 INTBIG io_edcircle(void)
1562 {
1563 	io_edfreeptlist();
1564 	io_edifgbl.points = io_edifgbl.lastpt = NOEPT;
1565 	io_edifgbl.orientation = OR0;
1566 	return(0);
1567 }
1568 
io_edpath(void)1569 INTBIG io_edpath(void)
1570 {
1571 	io_edfreeptlist();
1572 	io_edifgbl.points = io_edifgbl.lastpt = NOEPT;
1573 	io_edifgbl.orientation = OR0;
1574 	io_edifgbl.path_width = 0;
1575 	return(0);
1576 }
1577 
io_edpolygon(void)1578 INTBIG io_edpolygon(void)
1579 {
1580 	io_edfreeptlist();
1581 	io_edifgbl.points = io_edifgbl.lastpt = NOEPT;
1582 	io_edifgbl.orientation = OR0;
1583 	return(0);
1584 }
1585 
io_edopenShape(void)1586 INTBIG io_edopenShape(void)
1587 {
1588 	io_edfreeptlist();
1589 	io_edifgbl.points = io_edifgbl.lastpt = NOEPT;
1590 	io_edifgbl.orientation = OR0;
1591 	return(0);
1592 }
1593 
io_edfreeptlist(void)1594 INTBIG io_edfreeptlist(void)
1595 {
1596 	while (io_edifgbl.points != NOEPT)
1597 	{
1598 		io_edifgbl.lastpt = io_edifgbl.points->nextpt;
1599 		efree((CHAR *)io_edifgbl.points);
1600 		io_edifgbl.points = io_edifgbl.lastpt;
1601 		io_edifgbl.pt_count--;
1602 	}
1603 	if (io_edifgbl.pt_count != 0)
1604 		longjmp(io_edifgbl.env, LONGJMPPTMIS);
1605 	return(0);
1606 }
1607 
io_edfreesavedptlist(void)1608 INTBIG io_edfreesavedptlist(void)
1609 {
1610 	EPT_PTR lastpt;
1611 
1612 	while (io_edifgbl.save_text.points != NOEPT)
1613 	{
1614 		lastpt = io_edifgbl.save_text.points->nextpt;
1615 		efree((CHAR *)io_edifgbl.save_text.points);
1616 		io_edifgbl.save_text.points = lastpt;
1617 		io_edifgbl.save_text.pt_count--;
1618 	}
1619 	if (io_edifgbl.save_text.pt_count != 0)
1620 		longjmp(io_edifgbl.env, LONGJMPPTMIS);
1621 	return(0);
1622 }
1623 
io_edprogram(void)1624 INTBIG io_edprogram(void)
1625 {
1626 	CHAR program[WORD+1];
1627 
1628 	if (io_edget_token(program, 0) == NULL)
1629 		longjmp(io_edifgbl.env, LONGJMPEOF);
1630 	if (!namesamen(&program[1], x_("VIEWlogic"), 9))
1631 	{
1632 		io_edifgbl.vendor = EVVIEWLOGIC;
1633 	} else if (!namesamen(&program[1], x_("edifout"), 7))
1634 	{
1635 		io_edifgbl.vendor = EVCADENCE;
1636 	}
1637 	return(0);
1638 }
1639 
io_edunit(void)1640 INTBIG io_edunit(void)
1641 {
1642 	CHAR type[WORD+1];
1643 	REGISTER VARIABLE *var;
1644 	float edifscale;
1645 
1646 	if (io_edget_token(type, 0) == NULL)
1647 		longjmp(io_edifgbl.env, LONGJMPEOF);
1648 	if (kstack[kstack_ptr-1] == KSCALE && !namesame(type, x_("DISTANCE")))
1649 	{
1650 		/* get the scale */
1651 		io_edifgbl.dbunit = io_edifgbl.val1;
1652 		io_edifgbl.meters = io_edifgbl.val2;
1653 
1654 		/* just make the scale be so that the specified number of database units becomes 1 lambda */
1655 		io_edifgbl.scale = el_curlib->lambda[sch_tech->techindex];
1656 
1657 		var = getval((INTBIG)io_tool, VTOOL, VFLOAT, x_("IO_edif_input_scale"));
1658 		if (var == NOVARIABLE) edifscale = 1.0; else
1659 			edifscale = castfloat(var->addr);
1660 		io_edifgbl.scale *= edifscale;
1661 	}
1662 	return(0);
1663 }
1664 
io_edlibrary(void)1665 INTBIG io_edlibrary(void)
1666 {
1667 	CHAR *name, nbuf[WORD+1];
1668 
1669 	/* get the name of the library */
1670 	name = nbuf;
1671 	if (io_edget_token(name, 0) == NULL)
1672 		longjmp(io_edifgbl.env, LONGJMPEOF);
1673 #ifdef EDIFLIBNAME
1674 	/* retrieve the library */
1675 	io_edifgbl.library = getlibrary(name);
1676 	if (io_edifgbl.library == NOLIBRARY)
1677 	{
1678 		/* create the library */
1679 		io_edifgbl.library = newlibrary(name, name);
1680 		if (io_edifgbl.library == NOLIBRARY)
1681 			longjmp(io_edifgbl.env, LONGJMPNOLIB);
1682 		ttyputmsg(_("Reading library %s", name);
1683 	} else
1684 	{
1685 		/* flag existing cells */
1686 		for (np = io_edifgbl.library->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1687 			np->temp1 = 1;
1688 		ttyputmsg(_("Updating library %s", name);
1689 	}
1690 #endif
1691 	return(0);
1692 }
1693 
1694 /* cell definition routines */
1695 INTBIG io_eddesign(void)
1696 {
1697 	CHAR name[WORD+1];
1698 
1699 	/* get the name of the cell */
1700 	if (io_edget_token(name, 0) == NULL)
1701 		longjmp(io_edifgbl.env, LONGJMPEOF);
1702 
1703 	return(0);
1704 }
1705 
1706 /* note: cells are considered primitive unless they contain instance
1707    information, i.e. (contents  (instance ... , this cell will become
1708    a COMPLEX cell.
1709  */
1710 INTBIG io_edcell(void)
1711 {
1712 	io_edifgbl.active_view = VNULL;
1713 	io_edifgbl.name[0] = io_edifgbl.original[0] = 0;
1714 	io_edifgbl.pageno = 0;
1715 	io_edifgbl.sh_xpos = io_edifgbl.sh_ypos = -1;
1716 	if (io_edcheck_name())
1717 	{
1718 		(void)estrcpy(io_edifgbl.cell_reference, io_edifgbl.name);
1719 		(void)estrcpy(io_edifgbl.cell_name, io_edifgbl.name);
1720 	}
1721 	return(0);
1722 }
1723 
1724 /* view: Indicates a new view of the cell
1725  * 	 just clears the active view flag
1726  */
1727 INTBIG io_edview(void)
1728 {
1729 	io_edifgbl.active_view = VNULL;
1730 	return(0);
1731 }
1732 
1733 /* viewType:  Indicates the view style for this cell, ie
1734  *	BEHAVIOR, DOCUMENT, GRAPHIC, LOGICMODEL, MASKLAYOUT, NETLIST,
1735  *  	PCBLAYOUT, SCHEMATIC, STRANGER, SYMBOLIC
1736  * we are only concerned about the viewType NETLIST.
1737  */
1738 INTBIG io_edviewType(void)
1739 {
1740 	CHAR name[WORD+1], cname[WORD+1], view[WORD+1];
1741 	NODEPROTO *proto;
1742 
1743 	/* get the viewType */
1744 	if (io_edget_token(name, 0) == NULL)
1745 		longjmp(io_edifgbl.env, LONGJMPEOF);
1746 
1747 	if (!namesame(name, x_("BEHAVIOR"))) io_edifgbl.active_view = VBEHAVIOR;
1748 	else if (!namesame(name, x_("DOCUMENT"))) io_edifgbl.active_view = VDOCUMENT;
1749 	else if (!namesame(name, x_("GRAPHIC")))
1750 	{
1751 		io_edifgbl.active_view = VGRAPHIC;
1752 		estrcpy(view, x_(""));
1753 	}
1754 	else if (!namesame(name, x_("LOGICMODEL"))) io_edifgbl.active_view = VLOGICMODEL;
1755 	else if (!namesame(name, x_("MASKLAYOUT")))
1756 	{
1757 		io_edifgbl.active_view = VMASKLAYOUT;
1758 		estrcpy(view, x_("lay"));
1759 	}
1760 	else if (!namesame(name, x_("NETLIST")))
1761 	{
1762 		io_edifgbl.active_view = VNETLIST;
1763 		estrcpy(view, x_("sch"));
1764 	}
1765 	else if (!namesame(name, x_("PCBLAYOUT"))) io_edifgbl.active_view = VPCBLAYOUT;
1766 	else if (!namesame(name, x_("SCHEMATIC")))
1767 	{
1768 		io_edifgbl.active_view = VSCHEMATIC;
1769 		estrcpy(view, x_("sch"));
1770 	}
1771 	else if (!namesame(name, x_("STRANGER"))) io_edifgbl.active_view = VSTRANGER;
1772 	else if (!namesame(name, x_("SYMBOLIC"))) io_edifgbl.active_view = VSYMBOLIC;
1773 
1774 	/* immediately allocate MASKLAYOUT and VGRAPHIC viewtypes */
1775 	if (io_edifgbl.active_view == VMASKLAYOUT || io_edifgbl.active_view == VGRAPHIC ||
1776 		io_edifgbl.active_view == VNETLIST || io_edifgbl.active_view == VSCHEMATIC)
1777 	{
1778 		/* locate this in the list of cells */
1779 		for (proto = io_edifgbl.library->firstnodeproto; proto != NONODEPROTO;
1780 			proto = proto->nextnodeproto)
1781 		{
1782 			if (!namesame(proto->protoname, io_edifgbl.cell_name) &&
1783 				!namesame(proto->cellview->sviewname, view)) break;
1784 		}
1785 		if (proto == NONODEPROTO)
1786 		{
1787 			/* allocate the cell */
1788 			esnprintf(cname, WORD+1, x_("%s{%s}"), io_edifgbl.cell_name, view);
1789 			proto = us_newnodeproto(cname, io_edifgbl.library);
1790 			if (proto == NONODEPROTO) longjmp(io_edifgbl.env, LONGJMPNOMEM);
1791 			proto->temp1 = 0;
1792 		}
1793 		else if (proto->temp1) io_edifgbl.ignoreblock = 1;
1794 
1795 		io_edifgbl.current_cell = proto;
1796 	}
1797 	else io_edifgbl.current_cell = NONODEPROTO;
1798 
1799 	/* add the name to the celltbl */
1800 	if (io_edifgbl.celltbl_cnt == io_edifgbl.celltbl_sze)
1801 	{
1802 		io_edifgbl.celltbl_sze += 100;
1803 		if (io_edifgbl.celltbl_cnt == 0)
1804 		{
1805 			io_edifgbl.celltbl = (NAMETABLE_PTR *)emalloc(sizeof (NAMETABLE_PTR) *
1806 				io_edifgbl.celltbl_sze, io_tool->cluster);
1807 			if (io_edifgbl.celltbl == (NAMETABLE_PTR *)0) RET_NOMEMORY();
1808 		} else
1809 		{
1810 			NAMETABLE_PTR *newtbl;
1811 			long i;
1812 
1813 			newtbl = (NAMETABLE_PTR *)emalloc(sizeof (NAMETABLE_PTR) * io_edifgbl.celltbl_sze,
1814 				io_tool->cluster);
1815 			if (newtbl == (NAMETABLE_PTR *)0) RET_NOMEMORY();
1816 			for(i=0; i<io_edifgbl.celltbl_cnt; i++) newtbl[i] = io_edifgbl.celltbl[i];
1817 			io_edifgbl.celltbl = newtbl;
1818 		}
1819 	}
1820 	io_edifgbl.celltbl[io_edifgbl.celltbl_cnt] = (NAMETABLE_PTR)emalloc(sizeof (NAMETABLE),
1821 		io_tool->cluster);
1822 	if (io_edifgbl.celltbl[io_edifgbl.celltbl_cnt] == NONAMETABLE) RET_NOMEMORY();
1823 	if (allocstring(&io_edifgbl.celltbl[io_edifgbl.celltbl_cnt]->original, io_edifgbl.cell_reference,
1824 		io_tool->cluster)) RET_NOMEMORY();
1825 	if (allocstring(&io_edifgbl.celltbl[io_edifgbl.celltbl_cnt]->replace, io_edifgbl.cell_name,
1826 		io_tool->cluster)) RET_NOMEMORY();
1827 
1828 	/* now sort by name */
1829 	esort(io_edifgbl.celltbl, ++(io_edifgbl.celltbl_cnt), sizeof (NAMETABLE_PTR),
1830 		io_edcompare_name);
1831 	return(0);
1832 }
1833 
1834 /* contents:  Indicates additional information about higher level blocks
1835  * initially verifies the appropriate state, ie
1836  * 	(view XXX (viewType Netlist)
1837  *	  (contents ...
1838  */
1839 INTBIG io_edcontents(void)
1840 {
1841 	return(0);
1842 }
1843 
1844 /* port: Define connection point for the cell, must be in INTERFACE */
1845 INTBIG io_edport(void)
1846 {
1847 	io_edifgbl.name[0] = io_edifgbl.original[0] = 0;
1848 	io_edifgbl.direction = INPUTE;
1849 	io_edifgbl.port_reference[0] = 0;
1850 	io_edifgbl.isarray = 0;
1851 	io_edifgbl.arrayx = io_edifgbl.arrayy = 1;
1852 	if (io_edcheck_name())
1853 	{
1854 		(void)estrcpy(io_edifgbl.port_reference, io_edifgbl.name);
1855 		(void)estrcpy(io_edifgbl.port_name, io_edifgbl.name);
1856 	}
1857 	return(0);
1858 }
1859 
1860 /* direction:  Set the direction of a port */
1861 INTBIG io_eddirection(void)
1862 {
1863 	CHAR name[WORD+1];
1864 
1865 	/* get the direction */
1866 	if (io_edget_token(name, 0) == NULL)
1867 		longjmp(io_edifgbl.env, LONGJMPEOF);
1868 
1869 	if (!namesame(name, x_("INOUT"))) io_edifgbl.direction = INOUT; else
1870 		if (!namesame(name, x_("INPUT"))) io_edifgbl.direction = INPUTE; else
1871 			if (!namesame(name, x_("OUTPUT"))) io_edifgbl.direction = OUTPUTE;
1872 	return(0);
1873 }
1874 
1875 /* instance definition routines */
1876 /* instance:  Indicates a new instance within the cell
1877  */
1878 INTBIG io_edinstance(void)
1879 {
1880 	/* set the current geometry type */
1881 	io_edfreeptlist();
1882 	io_edifgbl.proto = NONODEPROTO;
1883 	io_edifgbl.geometry = GINSTANCE;
1884 	io_edifgbl.points = io_edifgbl.lastpt = NOEPT;
1885 	io_edifgbl.orientation = OR0;
1886 	io_edifgbl.isarray = 0;
1887 	io_edifgbl.arrayx = io_edifgbl.arrayy = 1;
1888 	io_edifgbl.name[0] = io_edifgbl.original[0] = 0;
1889 	io_edifgbl.instance_reference[0] = 0;
1890 	io_edifgbl.current_node = NONODEINST;
1891 	if (io_edcheck_name())
1892 	{
1893 		(void)estrcpy(io_edifgbl.instance_reference, io_edifgbl.name);
1894 		(void)estrcpy(io_edifgbl.instance_name, io_edifgbl.name);
1895 	}
1896 	return(0);
1897 }
1898 
1899 INTBIG io_edarray(void)
1900 {
1901 	/* note array is a special process integer value function */
1902 	io_edifgbl.isarray = 1;
1903 	io_edifgbl.arrayx = io_edifgbl.arrayy = 0;
1904 	io_edifgbl.deltaxX = io_edifgbl.deltaxY = 0;
1905 	io_edifgbl.deltayX = io_edifgbl.deltayY = 0;
1906 	io_edifgbl.deltapts = 0;
1907 	if (io_edcheck_name())
1908 	{
1909 		switch (kstack[kstack_ptr-1])
1910 		{
1911 			case KCELL:
1912 				(void)estrcpy(io_edifgbl.cell_reference, io_edifgbl.name);
1913 				(void)estrcpy(io_edifgbl.cell_name, io_edifgbl.name);
1914 				break;
1915 			case KPORT:
1916 				(void)estrcpy(io_edifgbl.port_name, io_edifgbl.name);
1917 				(void)estrcpy(io_edifgbl.port_reference, io_edifgbl.name);
1918 				break;
1919 			case KINSTANCE:
1920 				(void)estrcpy(io_edifgbl.instance_name, io_edifgbl.name);
1921 				(void)estrcpy(io_edifgbl.instance_reference, io_edifgbl.name);
1922 				break;
1923 			case KNET:
1924 				(void)estrcpy(io_edifgbl.net_reference, io_edifgbl.name);
1925 				(void)estrcpy(io_edifgbl.net_name, io_edifgbl.name);
1926 				break;
1927 			case KPROPERTY:
1928 				(void)estrcpy(io_edifgbl.property_reference, io_edifgbl.name);
1929 				(void)estrcpy(io_edifgbl.property_name, io_edifgbl.name);
1930 				break;
1931 			default:
1932 				break;
1933 		}
1934 	}
1935 	return(0);
1936 }
1937 
1938 INTBIG io_eddelta(void)
1939 {
1940 	io_edifgbl.deltaxX = io_edifgbl.deltaxY = 0;
1941 	io_edifgbl.deltayX = io_edifgbl.deltayY = 0;
1942 	io_edifgbl.deltapts = 0;
1943 	return(0);
1944 }
1945 
1946 /* cellRef:  determines the cell type of an instance
1947  */
1948 INTBIG io_edcellRef(void)
1949 {
1950 	CHAR name[WORD+1], view[WORD+1];
1951 	NODEPROTO *proto;
1952 	INTBIG low, high, change, mid;
1953 
1954 	/* get the name of the cell */
1955 	if (io_edget_token(name, 0) == NULL)
1956 		longjmp(io_edifgbl.env, LONGJMPEOF);
1957 
1958 	switch (io_edifgbl.active_view)
1959 	{
1960 		case VMASKLAYOUT:
1961 			estrcpy(view, x_("lay"));
1962 			break;
1963 		default:
1964 			if (kstack[kstack_ptr - 1] == KDESIGN) estrcpy(view, x_("p1")); else
1965 				estrcpy(view, x_("ic"));
1966 	}
1967 	if (io_edifgbl.vendor == EVVIEWLOGIC && !namesame(name, x_("SPLITTER")))
1968 	{
1969 		io_edifgbl.proto = NONODEPROTO;
1970 		return(0);
1971 	}
1972 
1973 	/* look for this cell name in the cell list */
1974 	low = 0;
1975 	high = io_edifgbl.celltbl_cnt - 1;
1976 	while (low <= high)
1977 	{
1978 		mid = (low + high) / 2;
1979 		change = namesame(name, io_edifgbl.celltbl[mid]->original);
1980 		if (change < 0) high = mid - 1; else
1981 			if (change > 0) low = mid + 1; else
1982 		{
1983 			/* found the name */
1984 			(void)estrcpy(name, io_edifgbl.celltbl[mid]->replace);
1985 			break;
1986 		}
1987 	}
1988 	if (low > high)
1989 	{
1990 		ttyputerr(_("could not find cellRef <%s>"), name);
1991 	}
1992 
1993 	/* now look for this cell in the list of cells, if not found create it */
1994 	/* locate this in the list of cells */
1995 	for (proto = io_edifgbl.library->firstnodeproto; proto != NONODEPROTO; proto = proto->nextnodeproto)
1996 	{
1997 		if (!namesame(proto->protoname, name) &&
1998 			!namesame(proto->cellview->sviewname, view)) break;
1999 	}
2000 	if (proto == NONODEPROTO)
2001 	{
2002 		/* allocate the cell */
2003 		if (view[0] != 0)
2004 		{
2005 			estrcat(name, x_("{"));
2006 			estrcat(name, view);
2007 			estrcat(name, x_("}"));
2008 		}
2009 		proto = us_newnodeproto(name, io_edifgbl.library);
2010 		if (proto == NONODEPROTO) longjmp(io_edifgbl.env, LONGJMPNOMEM);
2011 		proto->temp1 = 0;
2012 	}
2013 
2014 	/* set the parent */
2015 	io_edifgbl.proto = proto;
2016 	return(0);
2017 }
2018 
2019 INTBIG io_edinteger(void)
2020 {
2021 	CHAR value[WORD+1];
2022 
2023 	if (io_edget_token(value, 0) == NULL)
2024 		longjmp(io_edifgbl.env, LONGJMPEOF);
2025 
2026 	if (io_edifgbl.ptype == PSTRING) efree(io_edifgbl.pval.string);
2027 	io_edifgbl.pval.integer = eatoi(value);
2028 	io_edifgbl.ptype = PINTEGER;
2029 	return(0);
2030 }
2031 
2032 INTBIG io_ednumber(void)
2033 {
2034 	if (io_edifgbl.ptype == PSTRING) efree(io_edifgbl.pval.string);
2035 	io_edifgbl.pval.number = (float)io_edgetnumber();
2036 	io_edifgbl.ptype = PNUMBER;
2037 	return(0);
2038 }
2039 
2040 INTBIG io_edstring(void)
2041 {
2042 	CHAR *token, value[WORD+1];
2043 
2044 	if (*(token = io_edpos_token()) != '(' && *token != ')')
2045 	{
2046 		if (io_edget_token(value, 0) == NULL)
2047 			longjmp(io_edifgbl.env, LONGJMPEOF);
2048 		if (io_edifgbl.ptype == PSTRING) efree(io_edifgbl.pval.string);
2049 
2050 		value[estrlen(value) - 1] = 0;
2051 		io_edifgbl.pval.string = (CHAR *)emalloc(estrlen(value) * SIZEOFCHAR, io_tool->cluster);
2052 		if (io_edifgbl.pval.string == NULL)
2053 			longjmp(io_edifgbl.env, LONGJMPNOMEM);
2054 
2055 		(void)estrcpy(io_edifgbl.pval.string, &value[1]);
2056 		io_edifgbl.ptype = PSTRING;
2057 	}
2058 	return(0);
2059 }
2060 
2061 INTBIG io_edproperty(void)
2062 {
2063 	io_edifgbl.property_reference[0] = 0;
2064 	io_edifgbl.name[0] = io_edifgbl.original[0] = 0;
2065 	if (io_edifgbl.ptype == PSTRING) efree(io_edifgbl.pval.string);
2066 	io_edifgbl.ptype = PUNKNOWN;
2067 	if (io_edcheck_name())
2068 	{
2069 		(void)estrcpy(io_edifgbl.property_reference, io_edifgbl.name);
2070 		(void)estrcpy(io_edifgbl.property_name, io_edifgbl.name);
2071 	}
2072 	return(0);
2073 }
2074 
2075 /* net:  Define a net name followed by edifgbl and local pin list
2076  *		(net NAME
2077  *			(joined
2078  *			(portRef NAME (instanceRef NAME))
2079  *			(portRef NAME)))
2080  */
2081 INTBIG io_ednet(void)
2082 {
2083 	io_edifgbl.net_reference[0] = 0;
2084 	io_edifgbl.name[0] = io_edifgbl.original[0] = 0;
2085 	io_edifgbl.current_arc = NOARCINST;
2086 	io_edifgbl.current_node = NONODEINST;
2087 	io_edifgbl.current_port = NOPORTPROTO;
2088 	io_edfreenetports();
2089 	io_edifgbl.isarray = 0;
2090 	io_edifgbl.arrayx = io_edifgbl.arrayy = 1;
2091 	if (kstack[kstack_ptr-2] != KNETBUNDLE) io_edifgbl.geometry = GNET;
2092 	if (io_edcheck_name())
2093 	{
2094 		(void)estrcpy(io_edifgbl.net_reference, io_edifgbl.name);
2095 		(void)estrcpy(io_edifgbl.net_name, io_edifgbl.name);
2096 	}
2097 	return(0);
2098 }
2099 
2100 INTBIG io_ednetBundle(void)
2101 {
2102 	io_edifgbl.geometry = GBUS;
2103 	io_edifgbl.bundle_reference[0] = 0;
2104 	io_edifgbl.name[0] = io_edifgbl.original[0] = 0;
2105 	io_edifgbl.isarray = 0;
2106 	if (io_edcheck_name())
2107 	{
2108 		(void)estrcpy(io_edifgbl.bundle_reference, io_edifgbl.name);
2109 		(void)estrcpy(io_edifgbl.bundle_name, io_edifgbl.name);
2110 	}
2111 	return(0);
2112 }
2113 
2114 INTBIG io_edjoined(void)
2115 {
2116 	return(0);
2117 }
2118 
2119 /* portRef:  specifies a pin on a net */
2120 INTBIG io_edportRef(void)
2121 {
2122 	io_edifgbl.port_reference[0] = 0;
2123 	io_edifgbl.instance_reference[0] = 0;
2124 	if (io_edcheck_name())
2125 	{
2126 		(void)estrcpy(io_edifgbl.port_reference, io_edifgbl.name);
2127 	}
2128 
2129 	/* allocate a netport */
2130 	if (io_edallocnetport())
2131 		longjmp(io_edifgbl.env, LONGJMPNOMEM);
2132 	return(0);
2133 }
2134 
2135 /* instanceRef:  identifies the name of the instance attached to the net */
2136 INTBIG io_edinstanceRef(void)
2137 {
2138 	io_edifgbl.instance_reference[0] = 0;
2139 	if (io_edcheck_name())
2140 	{
2141 		(void)estrcpy(io_edifgbl.instance_reference, io_edifgbl.name);
2142 	}
2143 	return(0);
2144 }
2145 
2146 /* array member function, determines a specific element of an array */
2147 INTBIG io_edmember(void)
2148 {
2149 	io_edifgbl.memberx = -1; /* no member */
2150 	io_edifgbl.membery = -1; /* no member */
2151 	if (io_edcheck_name())
2152 	{
2153 		switch (kstack[kstack_ptr-1])
2154 		{
2155 			case KPORTREF:
2156 				(void)estrcpy(io_edifgbl.port_reference, io_edifgbl.name);
2157 				break;
2158 			case KINSTANCEREF:
2159 				(void)estrcpy(io_edifgbl.instance_reference, io_edifgbl.name);
2160 				break;
2161 			default:
2162 				break;
2163 		}
2164 	}
2165 	return(0);
2166 }
2167 
2168 INTBIG io_edname(void)
2169 {
2170 	INTBIG kptr;
2171 
2172 	if (kstack[kstack_ptr-1] == KARRAY || kstack[kstack_ptr-1] == KMEMBER) kptr = kstack_ptr-2; else
2173 		kptr = kstack_ptr - 1;
2174 	if (io_edcheck_name())
2175 	{
2176 		switch (kstack[kptr])
2177 		{
2178 			case KCELL:
2179 				(void)estrcpy(io_edifgbl.cell_reference, io_edifgbl.name);
2180 				(void)estrcpy(io_edifgbl.cell_name, io_edifgbl.name);
2181 				break;
2182 			case KPORTIMPLEMENTATION:		/* added by smr */
2183 			case KPORT:
2184 				(void)estrcpy(io_edifgbl.port_name, io_edifgbl.name);
2185 				/* FALLTHROUGH */
2186 			case KPORTREF:
2187 				(void)estrcpy(io_edifgbl.port_reference, io_edifgbl.name);
2188 				break;
2189 			case KINSTANCE:
2190 				(void)estrcpy(io_edifgbl.instance_name, io_edifgbl.name);
2191 				/* FALLTHROUGH */
2192 			case KINSTANCEREF:
2193 				(void)estrcpy(io_edifgbl.instance_reference, io_edifgbl.name);
2194 				break;
2195 			case KNET:
2196 				(void)estrcpy(io_edifgbl.net_reference, io_edifgbl.name);
2197 				(void)estrcpy(io_edifgbl.net_name, io_edifgbl.name);
2198 				break;
2199 			case KPROPERTY:
2200 				(void)estrcpy(io_edifgbl.property_reference, io_edifgbl.name);
2201 				(void)estrcpy(io_edifgbl.property_name, io_edifgbl.name);
2202 				break;
2203 			default:
2204 				break;
2205 		}
2206 
2207 		/* init the point lists */
2208 		io_edfreeptlist();
2209 		io_edifgbl.points = io_edifgbl.lastpt = NOEPT;
2210 		io_edifgbl.orientation = OR0;
2211 		io_edifgbl.visible = 1;
2212 		io_edifgbl.justification = LOWERLEFT;
2213 		io_edifgbl.textheight = 0;
2214 		(void)estrcpy(io_edifgbl.string, io_edifgbl.name);
2215 	}
2216 	return(0);
2217 }
2218 
2219 INTBIG io_edrename(void)
2220 {
2221 	CHAR name[WORD+1];
2222 	INTBIG kptr;
2223 
2224 	/* get the name of the object */
2225 	if (io_edget_token(name, 0) == NULL)
2226 		longjmp(io_edifgbl.env, LONGJMPEOF);
2227 	(void)estrcpy(io_edifgbl.name, (name[0] == '&') ? &name[1] : name);
2228 
2229 	/* and the original name */
2230 	if (*io_edpos_token() == '(')
2231 	{
2232 		/* must be stringDisplay, copy name to original */
2233 		(void)estrcpy(io_edifgbl.original, io_edifgbl.name);
2234 	} else
2235 	{
2236 		if  (io_edget_token(name, 0) == NULL)
2237 			longjmp(io_edifgbl.env, LONGJMPEOF);
2238 
2239 		/* copy name without quotes */
2240 		(void)estrcpy(io_edifgbl.original, &name[1]);
2241 		io_edifgbl.original[estrlen(name)-2] = 0;
2242 	}
2243 	if (kstack[kstack_ptr - 1]  == KNAME) kptr = kstack_ptr - 1; else
2244 		kptr = kstack_ptr;
2245 	if (kstack[kptr - 1] == KARRAY) kptr = kptr - 2; else
2246 		kptr = kptr -1;
2247 	switch (kstack[kptr])
2248 	{
2249 		case KCELL:
2250 			(void)estrcpy(io_edifgbl.cell_reference, io_edifgbl.name);
2251 			(void)estrcpy(io_edifgbl.cell_name, io_edifgbl.original);
2252 			break;
2253 		case KPORT:
2254 			(void)estrcpy(io_edifgbl.port_reference, io_edifgbl.name);
2255 			(void)estrcpy(io_edifgbl.port_name, io_edifgbl.original);
2256 			break;
2257 		case KINSTANCE:
2258 			(void)estrcpy(io_edifgbl.instance_reference, io_edifgbl.name);
2259 			(void)estrcpy(io_edifgbl.instance_name, io_edifgbl.original);
2260 			break;
2261 		case KNETBUNDLE:
2262 			(void)estrcpy(io_edifgbl.bundle_reference, io_edifgbl.name);
2263 			(void)estrcpy(io_edifgbl.bundle_name, io_edifgbl.original);
2264 			break;
2265 		case KNET:
2266 			(void)estrcpy(io_edifgbl.net_reference, io_edifgbl.name);
2267 			(void)estrcpy(io_edifgbl.net_name, io_edifgbl.original);
2268 			break;
2269 		case KPROPERTY:
2270 			(void)estrcpy(io_edifgbl.property_reference, io_edifgbl.name);
2271 			(void)estrcpy(io_edifgbl.property_name, io_edifgbl.original);
2272 			break;
2273 		default:
2274 			break;
2275 	}
2276 	return(0);
2277 }
2278 
2279 /* symbol routines and schematic routines */
2280 /* boundingBox - describes the bounding box of a schematic symbol */
2281 INTBIG io_edboundingBox(void)
2282 {
2283 	io_edifgbl.figure_group = art_openeddottedpolygonprim;
2284 	return(0);
2285 }
2286 
2287 /* symbol - describes a schematic symbol */
2288 INTBIG io_edsymbol(void)
2289 {
2290 	CHAR cname[WORD+1];
2291 	NODEPROTO *proto;
2292 	INTBIG center[2];
2293 
2294 	io_edifgbl.active_view = VSYMBOL;
2295 
2296 	/* locate this in the list of cells */
2297 	for (proto = io_edifgbl.library->firstnodeproto; proto != NONODEPROTO; proto = proto->nextnodeproto)
2298 	{
2299 		if (!namesame(proto->protoname, io_edifgbl.cell_name) &&
2300 			!namesame(proto->cellview->sviewname, x_("ic"))) break;
2301 	}
2302 	if (proto == NONODEPROTO)
2303 	{
2304 		/* allocate the cell */
2305 		esnprintf(cname, WORD+1, x_("%s{ic}"), io_edifgbl.cell_name);
2306 		proto = us_newnodeproto(cname, io_edifgbl.library);
2307 		if (proto == NONODEPROTO) longjmp(io_edifgbl.env, LONGJMPNOMEM);
2308 		proto->userbits |= WANTNEXPAND;
2309 		proto->temp1 = 0;
2310 		center[0] = center[1] = 0;
2311 		(void)setvalkey((INTBIG)proto, VNODEPROTO, el_prototype_center_key,
2312 			(INTBIG)center, VINTEGER|VISARRAY|(2<<VLENGTHSH));
2313 
2314 	}
2315 	else if (proto->temp1) io_edifgbl.ignoreblock = 1;
2316 
2317 	io_edifgbl.current_cell = proto;
2318 	io_edifgbl.figure_group = NONODEPROTO;
2319 	return(0);
2320 }
2321 
2322 INTBIG io_edportImplementation(void)
2323 {
2324 	/* set the current geometry type */
2325 	io_edfreeptlist();
2326 	io_edifgbl.proto = sch_wirepinprim;
2327 	io_edifgbl.geometry = GPIN;
2328 	io_edifgbl.points = io_edifgbl.lastpt = NOEPT;
2329 	io_edifgbl.orientation = OR0;
2330 	io_edifgbl.isarray = 0;
2331 	io_edifgbl.arrayx = io_edifgbl.arrayy = 1;
2332 	io_edifgbl.name[0] = io_edifgbl.original[0] = 0;
2333 	(void)io_edcheck_name();
2334 	return(0);
2335 }
2336 
2337 INTBIG io_edconnectLocation(void)
2338 {
2339 	return(0);
2340 }
2341 
2342 INTBIG io_edinterface(void)
2343 {
2344 	NODEPROTO *np;
2345 	CHAR nodename[WORD+1];
2346 
2347 	/* create schematic page 1 to represent all I/O for this schematic */
2348 	/* locate this in the list of cells */
2349 	for (np = io_edifgbl.library->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2350 	{
2351 		if (!namesame(np->protoname, io_edifgbl.cell_name) &&
2352 			!namesame(np->cellview->sviewname, x_("sch"))) break;
2353 	}
2354 	if (np == NONODEPROTO)
2355 	{
2356 		/* allocate the cell */
2357 		esnprintf(nodename, WORD+1, x_("%s{sch}"), io_edifgbl.cell_name);
2358 		io_edifgbl.current_cell = us_newnodeproto(nodename, io_edifgbl.library);
2359 		if (io_edifgbl.current_cell == NONODEPROTO)
2360 			longjmp(io_edifgbl.env, LONGJMPNOMEM);
2361 		io_edifgbl.current_cell->temp1 = 0;
2362 	}
2363 	else io_edifgbl.current_cell = np;
2364 
2365 	/* now set the current position in the schematic page */
2366 	io_edifgbl.ipos = io_edifgbl.bpos = io_edifgbl.opos = 0;
2367 	return(0);
2368 }
2369 
2370 INTBIG io_eddot(void)
2371 {
2372 	io_edfreeptlist();
2373 	io_edifgbl.points = io_edifgbl.lastpt = NOEPT;
2374 	io_edifgbl.orientation = OR0;
2375 	return(0);
2376 }
2377 
2378 double io_edgetnumber(void)
2379 {
2380 	CHAR value[WORD+1];
2381 	INTBIG matissa, exponent;
2382 
2383 	if (io_edget_token(value, 0) == NULL)
2384 	{
2385 		longjmp(io_edifgbl.env, LONGJMPNOINT);
2386 	}
2387 	if (value[0] == '(')
2388 	{
2389 		/* must be in e notation */
2390 		if (io_edget_token(value, 0) == NULL ||
2391 			namesame(value, x_("e")))
2392 			longjmp(io_edifgbl.env, LONGJMPILLNUM);
2393 
2394 		/* now the matissa */
2395 		if (io_edget_token(value, 0) == NULL)
2396 			longjmp(io_edifgbl.env, LONGJMPNOMANT);
2397 		matissa = eatoi(value);
2398 
2399 		/* now the exponent */
2400 		if (io_edget_token(value, 0) == NULL)
2401 			longjmp(io_edifgbl.env, LONGJMPNOEXP);
2402 		exponent = eatoi(value);
2403 		io_edget_delim(')');
2404 		return((double)matissa * pow(10.0, (double)exponent));
2405 	}
2406 	return((double) eatoi(value));
2407 }
2408 
2409 INTBIG io_edcheck_name(void)
2410 {
2411 	CHAR *pp;
2412 	CHAR name[WORD+1];
2413 
2414 	if (*(pp = io_edpos_token()) != '(' && *pp != ')')
2415 	{
2416 		if (io_edget_token(name, 0) == NULL)
2417 			longjmp(io_edifgbl.env, LONGJMPILLNAME);
2418 		(void)estrcpy(io_edifgbl.name, (name[0] == '&') ? &name[1] : name);
2419 		return(1);
2420 	}
2421 	return(0);
2422 }
2423 
2424 static void io_edmake_electric_name(CHAR *ref, CHAR *name, int x, int y)
2425 {
2426 }
2427 
2428 /* general utilities ... */
2429 static void io_edcheck_busnames(ARCINST *ai, CHAR *base)
2430 {
2431 	PORTARCINST *pai;
2432 	NODEINST *ni;
2433 	INTBIG i, l;
2434 	VARIABLE *var;
2435 	CHAR *name, newname[WORD+1];
2436 
2437 	if (ai->proto != sch_busarc)
2438 	{
2439 		/* verify the name */
2440 		var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
2441 		if (var != NOVARIABLE && ((name = (CHAR *)var->addr) != NULL))
2442 		{
2443 			l = estrlen(base);
2444 			if (!namesamen(name, base, l) && isdigit(name[l]))
2445 			{
2446 				(void)esnprintf(newname, WORD+1, x_("%s[%s]"), base, &name[l]);
2447 				var = setvalkey((INTBIG)ai, VARCINST, el_arc_name_key, (INTBIG)newname, VSTRING);
2448 				if (var != NOVARIABLE)
2449 					defaulttextsize(4, var->textdescript);
2450 			}
2451 		}
2452 	}
2453 	ai->temp1 = 1;
2454 	for (i = 0; i < 2; i++)
2455 	{
2456 		ni = ai->end[i].nodeinst;
2457 		if (((ni->proto->userbits & NFUNCTION) >> NFUNCTIONSH) == NPPIN)
2458 		{
2459 			/* scan through this nodes portarcinst's */
2460 			for (pai = ni->firstportarcinst; pai != NOPORTARCINST; pai = pai->nextportarcinst)
2461 			{
2462 				if (pai->conarcinst->temp1 == 0)
2463 					io_edcheck_busnames(pai->conarcinst, base);
2464 			}
2465 		}
2466 	}
2467 }
2468 
2469 /* pop the keyword state stack, called when ')' is encountered. Note this function
2470    needs to broken into a simple function call structure. */
2471 #define MAXBUSPINS 256
2472 INTBIG io_edpop_stack(void)
2473 {
2474 	INTBIG eindex, key, lambda;
2475 	INTBIG lx, ly, hx, hy, cx, cy, cnt, Ix, Iy, gx, gy, xoff, yoff, dist;
2476 	INTBIG *trace, *pt, pts[26], fcnt, tcnt, psx, psy;
2477 	INTBIG width, height, x[3], y[3], radius, trans;
2478 	INTBIG count, user_max, i, j, dup, fbus, tbus, instcount, instptx, instpty;
2479 	UINTBIG descript[TEXTDESCRIPTSIZE];
2480 	CHAR nodename[WORD+1], portname[WORD+1], basename[WORD+1], *name, orig[WORD+1];
2481 	CHAR **layers, **layer_numbers;
2482 	NODEPROTO *np, *nnp;
2483 	ARCPROTO *ap, *lap;
2484 	ARCINST *ai;
2485 	PORTPROTO *ppt, *fpp, *lpp, *pp, *lastport;
2486 	NODEINST *ni, *lastpin, *fni, *lni;
2487 	EPT_PTR point;
2488 	EDPROPERTY_PTR property, nproperty;
2489 	double ar, so;
2490 	VARIABLE *var;
2491 	XARRAY rot;
2492 	EDPORT_PTR eport, neport;
2493 	/* bus connection variables */
2494 	PORTPROTO *fpps[MAXBUSPINS], *tpps[MAXBUSPINS];
2495 	NODEINST *fnis[MAXBUSPINS], *tnis[MAXBUSPINS];
2496 	REGISTER void *infstr;
2497 
2498 	lambda = el_curlib->lambda[io_edifgbl.technology->techindex];
2499 	if (kstack_ptr)
2500 	{
2501 		if (!io_edifgbl.ignoreblock)
2502 		{
2503 			switch (io_edifgbl.state)
2504 			{
2505 			case KFIGURE:
2506 				io_edifgbl.cur_nametbl = NONAMETABLE;
2507 				io_edifgbl.visible = 1;
2508 				io_edifgbl.justification = LOWERLEFT;
2509 				io_edifgbl.textheight = 0;
2510 				break;
2511 			case KBOUNDINGBOX:
2512 				io_edifgbl.figure_group = NONODEPROTO;
2513 				break;
2514 			case KTECHNOLOGY:
2515 				var = getval((INTBIG)io_edifgbl.technology, VTECHNOLOGY, VSTRING|VISARRAY,
2516 					x_("IO_gds_layer_numbers"));
2517 				if (var != NOVARIABLE)
2518 				{
2519 					layer_numbers = (CHAR **)var->addr;
2520 					count = getlength(var);
2521 					var = getval((INTBIG)io_edifgbl.technology, VTECHNOLOGY, VSTRING|VISARRAY,
2522 						x_("TECH_layer_names"));
2523 					if (var != NOVARIABLE)
2524 					{
2525 						layers = (CHAR **) var->addr;
2526 						user_max = io_edifgbl.layer_ptr;
2527 						/* for all layers assign their GDS number */
2528 						for (i=0; i<count; i++)
2529 						{
2530 							if (*layer_numbers[i] != 0)
2531 							{
2532 								/* search for this layer */
2533 								for (j=0; j<user_max; j++)
2534 								{
2535 									if (!namesame(io_edifgbl.nametbl[j]->replace, layers[i])) break;
2536 								}
2537 								if (user_max == j)
2538 								{
2539 									/* add to the list */
2540 									io_edifgbl.nametbl[io_edifgbl.layer_ptr] = (NAMETABLE_PTR)
2541 										emalloc(sizeof(NAMETABLE), io_tool->cluster);
2542 									if (io_edifgbl.nametbl[io_edifgbl.layer_ptr] == NONAMETABLE) RET_NOMEMORY();
2543 									if (allocstring(&io_edifgbl.nametbl[io_edifgbl.layer_ptr]->replace, layers[i],
2544 										io_tool->cluster)) RET_NOMEMORY();
2545 									esnprintf(orig, WORD+1, x_("layer_%s"), layer_numbers[i]);
2546 									if (allocstring(&io_edifgbl.nametbl[io_edifgbl.layer_ptr]->original,
2547 										orig, io_tool->cluster)) RET_NOMEMORY();
2548 									io_edifgbl.nametbl[io_edifgbl.layer_ptr]->textheight = 0;
2549 									io_edifgbl.nametbl[io_edifgbl.layer_ptr]->justification = LOWERLEFT;
2550 									io_edifgbl.layer_ptr++;
2551 								}
2552 							}
2553 						}
2554 					}
2555 				}
2556 
2557 				/* sort the layer list */
2558 				esort(io_edifgbl.nametbl, io_edifgbl.layer_ptr, sizeof(NAMETABLE_PTR),
2559 					io_edcompare_name);
2560 
2561 				/* now look for nodes to map MASK layers to */
2562 				for (eindex = 0; eindex < io_edifgbl.layer_ptr; eindex++)
2563 				{
2564 					esnprintf(nodename, WORD+1, x_("%s-node"), io_edifgbl.nametbl[eindex]->replace);
2565 					for (np = io_edifgbl.technology->firstnodeproto; np != NONODEPROTO;
2566 						np = np->nextnodeproto)
2567 					{
2568 						if (!namesame(nodename, np->protoname)) break;
2569 					}
2570 					if (np == NONODEPROTO)
2571 					{
2572 						np = art_boxprim;
2573 					}
2574 					for (ap = io_edifgbl.technology->firstarcproto; ap != NOARCPROTO;
2575 						ap = ap->nextarcproto)
2576 					{
2577 						if (!namesame(ap->protoname, io_edifgbl.nametbl[eindex]->replace))
2578 							break;
2579 					}
2580 					io_edifgbl.nametbl[eindex]->node = np;
2581 					io_edifgbl.nametbl[eindex]->arc = ap;
2582 				}
2583 				break;
2584 			case KINTERFACE:
2585 				if (io_edifgbl.active_view == VNETLIST)
2586 				{
2587 					/* create a black-box symbol at the current scale */
2588 					np = io_edifgbl.current_cell;
2589 					(void)esnprintf(nodename, WORD+1, x_("%s{ic}"), np->protoname);
2590 					nnp = io_edmakeiconcell(np->firstportproto, np->protoname,
2591 						nodename, io_edifgbl.library);
2592 					if (nnp == NONODEPROTO)
2593 					{
2594 						ttyputerr(_("error, line #%d: could not create icon <%s>"),
2595 							io_edifgbl.lineno, nodename);
2596 						io_edifgbl.errors++;
2597 					} else
2598 					{
2599 						/* now compute the bounds of this cell */
2600 						db_boundcell(nnp, &nnp->lowx, &nnp->highx, &nnp->lowy, &nnp->highy);
2601 					}
2602 				}
2603 				break;
2604 			case KVIEW:
2605 
2606 				if (io_edifgbl.vendor == EVVIEWLOGIC && io_edifgbl.active_view != VNETLIST)
2607 				{
2608 					/* fixup incorrect bus nets */
2609 					for (ai = io_edifgbl.current_cell->firstarcinst; ai != NOARCINST;
2610 						ai = ai->nextarcinst)
2611 					{
2612 						ai->temp1 = ai->temp2 = 0;
2613 					}
2614 
2615 					/* now scan for BUS nets, and verify all wires connected to bus */
2616 					for (ai = io_edifgbl.current_cell->firstarcinst; ai != NOARCINST;
2617 						ai = ai->nextarcinst)
2618 					{
2619 						if (ai->temp1 == 0 && ai->proto == sch_busarc)
2620 						{
2621 							/* get name of arc */
2622 							var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
2623 							if (var != NOVARIABLE && ((name = (CHAR *)var->addr) != NULL))
2624 							{
2625 								/* create the basename */
2626 								(void)estrcpy(basename, name);
2627 								name = estrrchr(basename, '[');
2628 								if (name != NULL) *name = 0;
2629 
2630 								/* expand this arc, and locate non-bracketed names */
2631 								io_edcheck_busnames(ai, basename);
2632 							}
2633 						}
2634 					}
2635 				}
2636 
2637 				/* move the port list to the free list */
2638 				for (eport = io_edifgbl.ports; eport != NOEDPORT; eport = neport)
2639 				{
2640 					neport = eport->next;
2641 					eport->next = io_edifgbl.free_ports;
2642 					io_edifgbl.free_ports = eport;
2643 					efree(eport->name);
2644 					efree(eport->reference);
2645 				}
2646 				io_edifgbl.ports = NOEDPORT;
2647 				break;
2648 			case KPORT:
2649 				if (io_edallocport()) return(1);
2650 				eport = io_edifgbl.ports;
2651 				np = io_edifgbl.current_cell;
2652 				switch (eport->direction)
2653 				{
2654 					case INPUTE:
2655 						cx = 0;
2656 						cy = io_edifgbl.ipos;
2657 						io_edifgbl.ipos += INCH;
2658 						fpp = default_input;
2659 						break;
2660 					case INOUT:
2661 						cx = 3*INCH;
2662 						cy = io_edifgbl.bpos;
2663 						io_edifgbl.bpos += INCH;
2664 						fpp = default_input;
2665 						break;
2666 					case OUTPUTE:
2667 						cx = 6*INCH;
2668 						cy = io_edifgbl.opos;
2669 						io_edifgbl.opos += INCH;
2670 						fpp = default_output;
2671 						break;
2672 				}
2673 
2674 				/* now create the off-page reference */
2675 				defaultnodesize(sch_offpageprim, &psx, &psy);
2676 				ni = newnodeinst(sch_offpageprim,
2677 					cx + (sch_offpageprim->lowx+sch_offpageprim->highx-psx)/2,
2678 					cx + (sch_offpageprim->lowx+sch_offpageprim->highx+psx)/2,
2679 					cy + (sch_offpageprim->lowy+sch_offpageprim->highy-psy)/2,
2680 					cy + (sch_offpageprim->lowy+sch_offpageprim->highy+psy)/2, 0,0, np);
2681 				if (ni == NONODEINST)
2682 				{
2683 					ttyputerr(_("error, line #%d: could not create external port"),
2684 						io_edifgbl.lineno);
2685 					io_edifgbl.errors++;
2686 					break;
2687 				}
2688 
2689 				/* now create the port */
2690 				ppt = newportproto(ni->parent, ni, fpp, eport->name);
2691 				if (ppt == NOPORTPROTO)
2692 				{
2693 					ttyputerr(_("error, line #%d: could not create port <%s>"),
2694 						io_edifgbl.lineno, eport->name);
2695 					io_edifgbl.errors++;
2696 				} else
2697 				{
2698 					switch (eport->direction)
2699 					{
2700 						case INPUTE:
2701 							ppt->userbits = (ppt->userbits & ~STATEBITS) | INPORT;
2702 							break;
2703 						case OUTPUTE:
2704 							ppt->userbits = (ppt->userbits & ~STATEBITS) | OUTPORT;
2705 							break;
2706 						case INOUT:
2707 							ppt->userbits = (ppt->userbits & ~STATEBITS) | BIDIRPORT;
2708 							break;
2709 					}
2710 				}
2711 				io_edifgbl.port_reference[0] = 0;
2712 
2713 				/* move the property list to the free list */
2714 				for (property = io_edifgbl.properties; property != NOEDPROPERTY; property = nproperty)
2715 				{
2716 					key = makekey(property->name);
2717 					switch (property->type)
2718 					{
2719 						case PINTEGER:
2720 							var = setvalkey((INTBIG)ppt, VPORTPROTO, key, (INTBIG)property->val.integer,
2721 								VINTEGER);
2722 							break;
2723 						case PNUMBER:
2724 							var = setvalkey((INTBIG)ppt, VPORTPROTO, key, castint(property->val.number),
2725 								VFLOAT);
2726 							break;
2727 						case PSTRING:
2728 							var = setvalkey((INTBIG)ppt, VPORTPROTO, key, (INTBIG)property->val.string,
2729 								VSTRING);
2730 							break;
2731 						default:
2732 							break;
2733 					}
2734 					nproperty = property->next;
2735 					property->next = io_edifgbl.free_properties;
2736 					io_edifgbl.free_properties = property;
2737 					efree(property->name);
2738 				}
2739 				io_edifgbl.properties = NOEDPROPERTY;
2740 				break;
2741 			case KINSTANCE:
2742 				if (io_edifgbl.active_view == VNETLIST)
2743 				{
2744 					for (Ix = 0; Ix < io_edifgbl.arrayx; Ix++)
2745 					{
2746 						for (Iy = 0; Iy < io_edifgbl.arrayy; Iy++)
2747 						{
2748 							/* create this instance in the current sheet */
2749 							width = io_edifgbl.proto->highx - io_edifgbl.proto->lowx;
2750 							height = io_edifgbl.proto->highy - io_edifgbl.proto->lowy;
2751 							width = (width + INCH - 1) / INCH;
2752 							height = (height + INCH - 1) / INCH;
2753 
2754 							/* verify room for the icon */
2755 							if (io_edifgbl.sh_xpos != -1)
2756 							{
2757 								if ((io_edifgbl.sh_ypos + (height + 1)) >=
2758 									EDIF_sheet_bounds[io_edifgbl.sheet_size].height)
2759 								{
2760 									io_edifgbl.sh_ypos = 1;
2761 									if ((io_edifgbl.sh_xpos += io_edifgbl.sh_offset) >=
2762 										EDIF_sheet_bounds[io_edifgbl.sheet_size].width)
2763 											io_edifgbl.sh_xpos = io_edifgbl.sh_ypos = -1; else
2764 												io_edifgbl.sh_offset = 2;
2765 								}
2766 							}
2767 							if (io_edifgbl.sh_xpos == -1)
2768 							{
2769 								/* create the new page */
2770 								(void)esnprintf(nodename, WORD+1, x_("%s{p%d}"), io_edifgbl.cell_name,
2771 									++io_edifgbl.pageno);
2772 								io_edifgbl.current_cell = np = us_newnodeproto(nodename, io_edifgbl.library);
2773 								if (io_edifgbl.current_cell == NONODEPROTO)
2774 									longjmp(io_edifgbl.env, LONGJMPNOMEM);
2775 								np->temp1 = 0;
2776 								io_edifgbl.sh_xpos = io_edifgbl.sh_ypos = 1;
2777 								io_edifgbl.sh_offset = 2;
2778 							}
2779 
2780 							/* create this instance */
2781 							/* find out where true center moves */
2782 							cx = ((io_edifgbl.proto->lowx+io_edifgbl.proto->highx) >> 1) +
2783 								((io_edifgbl.sh_xpos -
2784 								(EDIF_sheet_bounds[io_edifgbl.sheet_size].width >> 1)) * INCH);
2785 							cy = ((io_edifgbl.proto->lowy+io_edifgbl.proto->highy) >> 1) +
2786 								((io_edifgbl.sh_ypos -
2787 								(EDIF_sheet_bounds[io_edifgbl.sheet_size].height >> 1)) * INCH);
2788 							io_edifgbl.current_node = ni = newnodeinst(io_edifgbl.proto,
2789 								io_edifgbl.proto->lowx + cx,
2790 								io_edifgbl.proto->highx + cx,
2791 								io_edifgbl.proto->lowy + cy,
2792 								io_edifgbl.proto->highy + cy,
2793 								io_edgettrans(io_edifgbl.orientation),
2794 								io_edgetrot(io_edifgbl.orientation),
2795 								io_edifgbl.current_cell);
2796 							if (ni == NONODEINST)
2797 							{
2798 								ttyputerr(_("error, line #%d: could not create instance"),
2799 									io_edifgbl.lineno);
2800 								io_edifgbl.errors++;
2801 								break;
2802 							} else
2803 							{
2804 								if (io_edifgbl.proto->userbits & WANTNEXPAND)
2805 									ni->userbits |= NEXPAND;
2806 
2807 								/* update the current position */
2808 								if ((width + 2) > io_edifgbl.sh_offset)
2809 									io_edifgbl.sh_offset = width + 2;
2810 								if ((io_edifgbl.sh_ypos += (height + 1)) >=
2811 									EDIF_sheet_bounds[io_edifgbl.sheet_size].height)
2812 								{
2813 									io_edifgbl.sh_ypos = 1;
2814 									if ((io_edifgbl.sh_xpos += io_edifgbl.sh_offset) >=
2815 										EDIF_sheet_bounds[io_edifgbl.sheet_size].width)
2816 										io_edifgbl.sh_xpos = io_edifgbl.sh_ypos = -1; else
2817 											io_edifgbl.sh_offset = 2;
2818 								}
2819 
2820 								/* name the instance */
2821 								if (io_edifgbl.instance_reference[0] != 0)
2822 								{
2823 									/* if single element or array with no offset */
2824 									/* construct the representative extended EDIF name (includes [...]) */
2825 									if ((io_edifgbl.arrayx == 1 && io_edifgbl.arrayy == 1) ||
2826 										(io_edifgbl.deltaxX == 0 && io_edifgbl.deltaxY == 0 &&
2827 										io_edifgbl.deltayX == 0 && io_edifgbl.deltayY == 0))
2828 											(void)estrcpy(nodename, io_edifgbl.instance_reference);
2829 										/* if array in the x dimension */
2830 									else if (io_edifgbl.arrayx > 1)
2831 									{
2832 										if (io_edifgbl.arrayy > 1)
2833 											(void)esnprintf(nodename, WORD+1, x_("%s[%ld,%ld]"),
2834 												io_edifgbl.instance_reference, Ix, Iy);
2835 										else
2836 											(void)esnprintf(nodename, WORD+1, x_("%s[%ld]"),
2837 												io_edifgbl.instance_reference, Ix);
2838 									}
2839 									/* if array in the y dimension */
2840 									else if (io_edifgbl.arrayy > 1)
2841 										(void)esnprintf(nodename, WORD+1, x_("%s[%ld]"),
2842 											io_edifgbl.instance_reference, Iy);
2843 
2844 									/* check for array element descriptor */
2845 									if (io_edifgbl.arrayx > 1 || io_edifgbl.arrayy > 1)
2846 									{
2847 										/* array descriptor is of the form index:index:range index:index:range */
2848 										(void)esnprintf(basename, WORD+1, x_("%ld:%ld:%d %ld:%ld:%d"), Ix,
2849 											(io_edifgbl.deltaxX == 0 && io_edifgbl.deltayX == 0) ?
2850 											io_edifgbl.arrayx-1:Ix, io_edifgbl.arrayx, Iy,
2851 											(io_edifgbl.deltaxY == 0 && io_edifgbl.deltayY == 0) ?
2852 											io_edifgbl.arrayy-1:Iy, io_edifgbl.arrayy);
2853 										var = setvalkey((INTBIG)ni, VNODEINST, EDIF_array_key, (INTBIG)basename,
2854 											VSTRING);
2855 
2856 									}
2857 
2858 									/* now set the name of the component (note that Electric allows any string
2859 									 * of characters as a name, this name is open to the user, for ECO and other
2860 									 * consistancies, the EDIF_name is saved on a variable)
2861 									 */
2862 									if (!namesame(io_edifgbl.instance_reference, io_edifgbl.instance_name))
2863 									{
2864 										var = setvalkey((INTBIG)ni, VNODEINST, el_node_name_key,
2865 											(INTBIG)nodename, VSTRING|VDISPLAY);
2866 										if (var != NOVARIABLE)
2867 											defaulttextsize(3, var->textdescript);
2868 									} else
2869 									{
2870 										/* now add the original name as the displayed name (only to the first element) */
2871 										if (Ix == 0 && Iy == 0)
2872 										{
2873 											var = setvalkey((INTBIG)ni, VNODEINST, el_node_name_key,
2874 												(INTBIG)io_edifgbl.instance_name, VSTRING|VDISPLAY);
2875 											if (var != NOVARIABLE)
2876 												defaulttextsize(3, var->textdescript);
2877 										}
2878 										/* now save the EDIF name (not displayed) */
2879 										var = setvalkey((INTBIG)ni, VNODEINST, EDIF_name_key,
2880 											(INTBIG)nodename, VSTRING);
2881 									}
2882 								}
2883 							}
2884 						}
2885 					}
2886 				}
2887 
2888 				/* move the property list to the free list */
2889 				for (property = io_edifgbl.properties; property != NOEDPROPERTY; property = nproperty)
2890 				{
2891 					if (io_edifgbl.current_node != NONODEINST)
2892 					{
2893 						key = makekey(property->name);
2894 						switch (property->type)
2895 						{
2896 							case PINTEGER:
2897 								var = setvalkey((INTBIG)io_edifgbl.current_node, VNODEINST, key,
2898 									(INTBIG)property->val.integer, VINTEGER);
2899 								break;
2900 							case PNUMBER:
2901 								var = setvalkey((INTBIG)io_edifgbl.current_node, VNODEINST, key,
2902 									castint(property->val.number), VFLOAT);
2903 								break;
2904 							case PSTRING:
2905 								var = setvalkey((INTBIG)io_edifgbl.current_node, VNODEINST, key,
2906 									(INTBIG)property->val.string, VSTRING);
2907 								break;
2908 							default:
2909 								break;
2910 						}
2911 					}
2912 					nproperty = property->next;
2913 					property->next = io_edifgbl.free_properties;
2914 					io_edifgbl.free_properties = property;
2915 					efree(property->name);
2916 				}
2917 				io_edifgbl.properties = NOEDPROPERTY;
2918 				io_edifgbl.instance_reference[0] = 0;
2919 				io_edifgbl.current_node = NONODEINST;
2920 				io_edfreesavedptlist();
2921 				break;
2922 			case KNET:
2923 				/* move the property list to the free list */
2924 				for (property = io_edifgbl.properties; property != NOEDPROPERTY; property = nproperty)
2925 				{
2926 					if (io_edifgbl.current_arc != NOARCINST)
2927 					{
2928 						key = makekey(property->name);
2929 						switch (property->type)
2930 						{
2931 							case PINTEGER:
2932 								var = setvalkey((INTBIG)io_edifgbl.current_arc, VARCINST, key,
2933 									(INTBIG)property->val.integer, VINTEGER);
2934 								break;
2935 							case PNUMBER:
2936 								var = setvalkey((INTBIG)io_edifgbl.current_arc, VARCINST, key,
2937 									castint(property->val.number), VFLOAT);
2938 								break;
2939 							case PSTRING:
2940 								var = setvalkey((INTBIG)io_edifgbl.current_arc, VARCINST, key,
2941 									(INTBIG)property->val.string, VSTRING);
2942 								break;
2943 							default:
2944 								break;
2945 						}
2946 					}
2947 					nproperty = property->next;
2948 					property->next = io_edifgbl.free_properties;
2949 					io_edifgbl.free_properties = property;
2950 					efree(property->name);
2951 				}
2952 				io_edifgbl.properties = NOEDPROPERTY;
2953 				io_edifgbl.net_reference[0] = 0;
2954 				io_edifgbl.current_arc = NOARCINST;
2955 				if (io_edifgbl.geometry != GBUS)
2956 					io_edifgbl.geometry = GUNKNOWN;
2957 				io_edfreesavedptlist();
2958 				break;
2959 			case KNETBUNDLE:
2960 				io_edifgbl.bundle_reference[0] = 0;
2961 				io_edifgbl.current_arc = NOARCINST;
2962 				io_edifgbl.geometry = GUNKNOWN;
2963 				io_edfreesavedptlist();
2964 				break;
2965 			case KPROPERTY:
2966 				if (io_edifgbl.active_view == VNETLIST || io_edifgbl.active_view == VSCHEMATIC)
2967 				{
2968 					/* add as a variable to the current object */
2969 					i = 0;
2970 					switch (kstack[kstack_ptr - 1])
2971 					{
2972 						case KINTERFACE:
2973 							/* add to the {sch} view nodeproto */
2974 							for (np = io_edifgbl.library->firstnodeproto; np != NONODEPROTO;
2975 								np = np->nextnodeproto)
2976 							{
2977 								if (!namesame(np->protoname, io_edifgbl.cell_name) &&
2978 									!namesame(np->cellview->sviewname, x_("sch"))) break;
2979 							}
2980 							if (np == NONODEPROTO)
2981 							{
2982 								/* allocate the cell */
2983 								esnprintf(nodename, WORD+1, x_("%s{sch}"), io_edifgbl.cell_name);
2984 								np = us_newnodeproto(nodename, io_edifgbl.library);
2985 								if (np == NONODEPROTO) longjmp(io_edifgbl.env, LONGJMPNOMEM);
2986 								np->temp1 = 0;
2987 							}
2988 							i = (INTBIG) np;
2989 							j = VNODEPROTO;
2990 							break;
2991 						case KINSTANCE:
2992 						case KNET:
2993 						case KPORT:
2994 							i = -1;
2995 							break;
2996 						default:
2997 							i = 0;
2998 							break;
2999 					}
3000 					if (i > 0)
3001 					{
3002 						key = makekey(io_edifgbl.property_reference);
3003 						switch (io_edifgbl.ptype)
3004 						{
3005 							case PINTEGER:
3006 								var = setvalkey(i, j, key, (INTBIG)io_edifgbl.pval.integer, VINTEGER);
3007 								break;
3008 							case PNUMBER:
3009 								var = setvalkey(i, j, key, castint(io_edifgbl.pval.number), VFLOAT);
3010 								break;
3011 							case PSTRING:
3012 								var = setvalkey(i, j, key, (INTBIG)io_edifgbl.pval.string, VSTRING);
3013 								break;
3014 							default:
3015 								break;
3016 						}
3017 					} else if (i == -1)
3018 					{
3019 						/* add to the current property list, will be added latter */
3020 						switch (io_edifgbl.ptype)
3021 						{
3022 							case PINTEGER:
3023 								(void)io_edallocproperty(io_edifgbl.property_reference, io_edifgbl.ptype,
3024 									(INTBIG)io_edifgbl.pval.integer, 0.0, NULL);
3025 								break;
3026 							case PNUMBER:
3027 								(void)io_edallocproperty(io_edifgbl.property_reference, io_edifgbl.ptype,
3028 									0, io_edifgbl.pval.number, NULL);
3029 								break;
3030 							case PSTRING:
3031 								(void)io_edallocproperty(io_edifgbl.property_reference, io_edifgbl.ptype,
3032 									0, 0.0, io_edifgbl.pval.string);
3033 								break;
3034 							default:
3035 								break;
3036 						}
3037 					}
3038 				}
3039 				io_edifgbl.property_reference[0] = 0;
3040 				io_edfreesavedptlist();
3041 				break;
3042 			case KPORTIMPLEMENTATION:
3043 				io_edifgbl.geometry = GUNKNOWN;
3044 				break;
3045 			case KTRANSFORM:
3046 				if (kstack_ptr <= 1 || kstack[kstack_ptr-1] != KINSTANCE)
3047 				{
3048 					io_edfreeptlist();
3049 					break;
3050 				}
3051 
3052 				/* get the corner offset */
3053 				instcount = io_edifgbl.pt_count;
3054 				if (instcount > 0)
3055 				{
3056 					instptx = io_edifgbl.points->x;
3057 					instpty = io_edifgbl.points->y;
3058 				}
3059 
3060 				/* if no points are specified, presume the origin */
3061 				if (instcount == 0)
3062 				{
3063 					instptx = instpty = 0;
3064 					instcount = 1;
3065 				}
3066 
3067 				/* create node instance rotations about the origin not center */
3068 				makeangle(io_edgetrot(io_edifgbl.orientation), io_edgettrans(io_edifgbl.orientation), rot);
3069 
3070 				if (instcount == 1 && io_edifgbl.proto != NONODEPROTO)
3071 				{
3072 					for (Ix = 0; Ix < io_edifgbl.arrayx; Ix++)
3073 					{
3074 						lx = instptx + Ix * io_edifgbl.deltaxX;
3075 						ly = instpty + Ix * io_edifgbl.deltaxY;
3076 						for (Iy = 0; Iy < io_edifgbl.arrayy; Iy++)
3077 						{
3078 							/* find out where true center moves */
3079 							cx = (io_edifgbl.proto->lowx+io_edifgbl.proto->highx)/2;
3080 							cy = (io_edifgbl.proto->lowy+io_edifgbl.proto->highy)/2;
3081 							xform(cx, cy, &gx, &gy, rot);
3082 
3083 							/* now calculate the delta movement of the center */
3084 							cx = gx - cx;
3085 							cy = gy - cy;
3086 							io_edifgbl.current_node = ni = newnodeinst(io_edifgbl.proto,
3087 								lx + io_edifgbl.proto->lowx + cx,
3088 								lx + io_edifgbl.proto->highx + cx,
3089 								ly + io_edifgbl.proto->lowy + cy,
3090 								ly + io_edifgbl.proto->highy + cy,
3091 								io_edgettrans(io_edifgbl.orientation),
3092 								io_edgetrot(io_edifgbl.orientation),
3093 								io_edifgbl.current_cell);
3094 							if (ni == NONODEINST)
3095 							{
3096 								ttyputerr(_("error, line #%d: could not create instance"),
3097 									io_edifgbl.lineno);
3098 								io_edifgbl.errors++;
3099 
3100 								/* and exit for loop */
3101 								Ix = io_edifgbl.arrayx;
3102 								Iy = io_edifgbl.arrayy;
3103 							} else
3104 							{
3105 								if (io_edifgbl.proto->userbits & WANTNEXPAND)
3106 									ni->userbits |= NEXPAND;
3107 							}
3108 							if (io_edifgbl.geometry == GPIN && lx == 0 && ly == 0)
3109 							{
3110 								/* determine an appropriate port name */
3111 								(void)estrcpy(portname, io_edifgbl.port_name);
3112 
3113 								/* check if port already exists (will occur for multiple portImplementation statements */
3114 								for (dup = 0, (void)estrcpy(basename, portname);
3115 									(ppt = getportproto(ni->parent, portname)) != NOPORTPROTO;
3116 									dup++)
3117 								{
3118 									if (dup == 0) pp = ppt;
3119 									(void)esnprintf(portname, WORD+1, x_("%s_%ld"), basename, dup+1);
3120 								}
3121 
3122 								/* only once */
3123 								Ix = io_edifgbl.arrayx;
3124 								Iy = io_edifgbl.arrayy;
3125 								ppt = newportproto(ni->parent, ni, default_iconport, portname);
3126 								if (ppt == NOPORTPROTO)
3127 								{
3128 									ttyputerr(_("error, line #%d: could not create port <%s>"),
3129 										io_edifgbl.lineno, portname);
3130 									io_edifgbl.errors++;
3131 								} else
3132 								{
3133 									/* locate the direction of the port */
3134 									for (eport = io_edifgbl.ports; eport != NOEDPORT; eport = eport->next)
3135 									{
3136 										if (!namesame(eport->reference, io_edifgbl.port_reference))
3137 										{
3138 											/* set the direction */
3139 											switch (eport->direction)
3140 											{
3141 												case INPUTE:
3142 													ppt->userbits = (ppt->userbits & ~STATEBITS) | INPORT;
3143 													break;
3144 												case OUTPUTE:
3145 													ppt->userbits = (ppt->userbits & ~STATEBITS) | OUTPORT;
3146 													break;
3147 												case INOUT:
3148 													ppt->userbits = (ppt->userbits & ~STATEBITS) | BIDIRPORT;
3149 													break;
3150 											}
3151 											break;
3152 										}
3153 									}
3154 								}
3155 							} else
3156 							{
3157 								/* name the instance */
3158 								if (io_edifgbl.instance_reference[0] != 0)
3159 								{
3160 									/* if single element or array with no offset */
3161 									/* construct the representative extended EDIF name (includes [...]) */
3162 									if ((io_edifgbl.arrayx == 1 && io_edifgbl.arrayy == 1) ||
3163 										(io_edifgbl.deltaxX == 0 && io_edifgbl.deltaxY == 0 &&
3164 										io_edifgbl.deltayX == 0 && io_edifgbl.deltayY == 0))
3165 										(void)estrcpy(nodename, io_edifgbl.instance_reference);
3166 										/* if array in the x dimension */
3167 									else if (io_edifgbl.arrayx > 1)
3168 									{
3169 										if (io_edifgbl.arrayy > 1)
3170 											(void)esnprintf(nodename, WORD+1, x_("%s[%ld,%ld]"),
3171 												io_edifgbl.instance_reference, Ix, Iy);
3172 										else
3173 											(void)esnprintf(nodename, WORD+1, x_("%s[%ld]"),
3174 												io_edifgbl.instance_reference, Ix);
3175 									}
3176 									/* if array in the y dimension */
3177 									else if (io_edifgbl.arrayy > 1)
3178 										(void)esnprintf(nodename, WORD+1, x_("%s[%ld]"),
3179 											io_edifgbl.instance_reference, Iy);
3180 
3181 									/* check for array element descriptor */
3182 									if (io_edifgbl.arrayx > 1 || io_edifgbl.arrayy > 1)
3183 									{
3184 										/* array descriptor is of the form index:index:range index:index:range */
3185 										(void)esnprintf(basename, WORD+1, x_("%ld:%ld:%d %ld:%ld:%d"),
3186 											Ix, (io_edifgbl.deltaxX == 0 && io_edifgbl.deltayX == 0) ? io_edifgbl.arrayx-1:Ix,
3187 											io_edifgbl.arrayx, Iy,
3188 											(io_edifgbl.deltaxY == 0 && io_edifgbl.deltayY == 0) ? io_edifgbl.arrayy-1:Iy,
3189 											io_edifgbl.arrayy);
3190 										var = setvalkey((INTBIG)ni, VNODEINST, EDIF_array_key, (INTBIG)basename,
3191 											VSTRING);
3192 									}
3193 
3194 									/* now set the name of the component (note that Electric allows any string
3195 			   						 * of characters as a name, this name is open to the user, for ECO and other
3196 									 * consistancies, the EDIF_name is saved on a variable)
3197 									 */
3198 									if (!namesame(io_edifgbl.instance_reference, io_edifgbl.instance_name))
3199 									{
3200 										var = setvalkey((INTBIG)ni, VNODEINST, el_node_name_key,
3201 											(INTBIG)nodename, VSTRING|VDISPLAY);
3202 										if (var != NOVARIABLE)
3203 											defaulttextsize(3, var->textdescript);
3204 									} else
3205 									{
3206 										/* now add the original name as the displayed name (only to the first element) */
3207 										if (Ix == 0 && Iy == 0)
3208 										{
3209 											var = setvalkey((INTBIG)ni, VNODEINST, el_node_name_key,
3210 												(INTBIG)io_edifgbl.instance_name, VSTRING|VDISPLAY);
3211 											if (var != NOVARIABLE)
3212 												defaulttextsize(3, var->textdescript);
3213 										}
3214 
3215 										/* now save the EDIF name (not displayed) */
3216 										var = setvalkey((INTBIG)ni, VNODEINST, EDIF_name_key,
3217 											(INTBIG)nodename, VSTRING);
3218 									}
3219 
3220 									/* now check for saved name attributes */
3221 									if (io_edifgbl.save_text.points != NOEPT)
3222 									{
3223 										/* now set the position, relative to the center of the current object */
3224 										xoff = io_edifgbl.save_text.points->x - ((ni->highx+ni->lowx)>>1);
3225 										yoff = io_edifgbl.save_text.points->y - ((ni->highy+ni->lowy)>>1);
3226 
3227 										/* convert to quarter lambda units */
3228 										xoff = 4*xoff / lambda;
3229 										yoff = 4*yoff / lambda;
3230 
3231 										/*
3232 										 * determine the size of text, 0.0278 in == 2 points or 36 (2xpixels) == 1 in
3233 										 * fonts range from 4 to 20 points
3234 										 */
3235 										if (io_edifgbl.save_text.textheight == 0) i = TXTSETQLAMBDA(4); else
3236 										{
3237 											i = io_ediftextsize(io_edifgbl.save_text.textheight);
3238 										}
3239 										TDCOPY(descript, var->textdescript);
3240 										TDSETOFF(descript, xoff, yoff);
3241 										TDSETSIZE(descript, i);
3242 										TDSETPOS(descript, VTPOSCENT);
3243 										switch (io_edifgbl.save_text.justification)
3244 										{
3245 											case UPPERLEFT:
3246 												TDSETPOS(descript, VTPOSUPRIGHT);
3247 												break;
3248 											case UPPERCENTER:
3249 												TDSETPOS(descript, VTPOSUP);
3250 												break;
3251 											case UPPERRIGHT:
3252 												TDSETPOS(descript, VTPOSUPLEFT);
3253 												break;
3254 											case CENTERLEFT:
3255 												TDSETPOS(descript, VTPOSRIGHT);
3256 												break;
3257 											case CENTERCENTER:
3258 												TDSETPOS(descript, VTPOSCENT);
3259 												break;
3260 											case CENTERRIGHT:
3261 												TDSETPOS(descript, VTPOSLEFT);
3262 												break;
3263 											case LOWERLEFT:
3264 												TDSETPOS(descript, VTPOSDOWNRIGHT);
3265 												break;
3266 											case LOWERCENTER:
3267 												TDSETPOS(descript, VTPOSDOWN);
3268 												break;
3269 											case LOWERRIGHT:
3270 												TDSETPOS(descript, VTPOSDOWNLEFT);
3271 												break;
3272 										}
3273 										TDCOPY(var->textdescript, descript);
3274 									}
3275 								}
3276 							}
3277 							if (io_edifgbl.deltayX == 0 && io_edifgbl.deltayY == 0) break;
3278 
3279 							/* bump the y delta and x deltas */
3280 							lx += io_edifgbl.deltayX;
3281 							ly += io_edifgbl.deltayY;
3282 						}
3283 						if (io_edifgbl.deltaxX == 0 && io_edifgbl.deltaxY == 0) break;
3284 					}
3285 				}
3286 				io_edfreeptlist();
3287 				break;
3288 			case KPORTREF:
3289 				/* check for the last pin */
3290 				fni = io_edifgbl.current_node;
3291 				fpp = io_edifgbl.current_port;
3292 				if (io_edifgbl.port_reference[0] != 0)
3293 				{
3294 					/* For internal pins of an instance, determine the base port location and
3295 					 * other pin assignments
3296 					 */
3297 					if (io_edifgbl.instance_reference[0] != 0)
3298 					{
3299 						(void)estrcpy(nodename, io_edifgbl.instance_reference);
3300 
3301 						/* locate the node and and port */
3302 						if (io_edifgbl.active_view == VNETLIST)
3303 						{
3304 							/* scan all pages for this nodeinst */
3305 							ni = NONODEINST;
3306 							for (np = io_edifgbl.library->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3307 							{
3308 								if (namesame(np->protoname, io_edifgbl.cell_name) != 0) continue;
3309 								for (ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3310 								{
3311 									if ((var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, EDIF_name_key)) == NOVARIABLE &&
3312 										(var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key)) == NOVARIABLE)
3313 											continue;
3314 									if (!namesame((CHAR *)var->addr, nodename)) break;
3315 								}
3316 								if (ni != NONODEINST) break;
3317 							}
3318 							if (ni == NONODEINST)
3319 							{
3320 								(void)ttyputmsg(_("error, line #%d: could not locate netlist node (%s)"),
3321 									io_edifgbl.lineno, nodename);
3322 								break;
3323 							}
3324 							ap = gen_unroutedarc;
3325 						} else
3326 						{
3327 							/* net always references the current page */
3328 							for (ni = io_edifgbl.current_cell->firstnodeinst; ni != NONODEINST;
3329 								ni = ni->nextnodeinst)
3330 							{
3331 								if ((var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, EDIF_name_key)) == NOVARIABLE &&
3332 									(var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key)) == NOVARIABLE)
3333 										continue;
3334 								if (!namesame((CHAR *)var->addr, nodename)) break;
3335 							}
3336 							if (ni == NONODEINST)
3337 							{
3338 								(void)ttyputmsg(_("error, line #%d: could not locate schematic node '%s' in cell %s"),
3339 									io_edifgbl.lineno, nodename, describenodeproto(io_edifgbl.current_cell));
3340 								break;
3341 							}
3342 							if (io_edifgbl.isarray == 0) ap = sch_wirearc; else
3343 								ap = sch_busarc;
3344 						}
3345 
3346 						/* locate the port for this portref */
3347 						pp = getportproto(ni->proto, io_edifgbl.port_reference);
3348 						if (pp == NOPORTPROTO)
3349 						{
3350 							(void)ttyputmsg(_("error, line #%d: could not locate port (%s) on node (%s)"),
3351 								io_edifgbl.lineno, io_edifgbl.port_reference, nodename);
3352 							break;
3353 						}
3354 
3355 						/* we have both, set global variable */
3356 						io_edifgbl.current_node = ni;
3357 						io_edifgbl.current_port = pp;
3358 						np = ni->parent;
3359 
3360 						/* create extensions for net labels on single pin nets (externals), and
3361 						 * placeholder for auto-routing later
3362 						 */
3363 						if (io_edifgbl.active_view == VNETLIST)
3364 						{
3365 							/* route all pins with an extension */
3366 							if (ni != NONODEINST)
3367 							{
3368 								portposition(ni, pp, &hx, &hy);
3369 								lx = hx;
3370 								ly = hy;
3371 								switch (pp->userbits&STATEBITS)
3372 								{
3373 									case INPORT:
3374 										lx = hx - (INCH/10);
3375 										break;
3376 									case BIDIRPORT:
3377 										ly = hy - (INCH/10);
3378 										break;
3379 									case OUTPORT:
3380 										lx = hx + (INCH/10);
3381 										break;
3382 								}
3383 
3384 								/* need to create a destination for the wire */
3385 								if (io_edifgbl.isarray != 0)
3386 								{
3387 									lni = io_edifiplacepin(sch_buspinprim, lx + sch_buspinprim->lowx,
3388 										lx + sch_buspinprim->highx, ly + sch_buspinprim->lowy,
3389 										ly + sch_buspinprim->highy, 0, 0, np);
3390 									if (lni == NONODEINST)
3391 									{
3392 										ttyputmsg(_("error, line#%d: could not create bus pin"),
3393 											io_edifgbl.lineno);
3394 										break;
3395 									}
3396 									lpp = default_busport;
3397 									lap = sch_busarc;
3398 								} else
3399 								{
3400 									lni = io_edifiplacepin(sch_wirepinprim, lx + sch_wirepinprim->lowx,
3401 										lx + sch_wirepinprim->highx, ly + sch_wirepinprim->lowy,
3402 										ly + sch_wirepinprim->highy, 0, 0, np);
3403 									if (lni == NONODEINST)
3404 									{
3405 										ttyputmsg(_("error, line#%d: could not create wire pin"),
3406 											io_edifgbl.lineno);
3407 										break;
3408 									}
3409 									lpp = default_port;
3410 									lap = sch_wirearc;
3411 								}
3412 								io_edifgbl.current_arc = newarcinst(lap, defaultarcwidth(lap), CANTSLIDE,
3413 									lni, lpp, lx, ly, ni, pp, hx, hy, np);
3414 								if (io_edifgbl.current_arc == NOARCINST)
3415 									ttyputmsg(_("error, line #%d: could not create auto-path"),
3416 										io_edifgbl.lineno);
3417 								else
3418 									io_ednamearc(io_edifgbl.current_arc);
3419 							}
3420 						}
3421 					} else
3422 					{
3423 						/* external port reference, look for a off-page reference in {sch} with this
3424 			 			  port name */
3425 						for (np = io_edifgbl.library->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3426 						{
3427 							if (namesame(np->protoname, io_edifgbl.cell_name) != 0) continue;
3428 							if (np->cellview == el_schematicview) break;
3429 						}
3430 						if (np == NONODEPROTO)
3431 						{
3432 							ttyputmsg(_("error, line #%d: could not locate top level schematic"),
3433 								io_edifgbl.lineno);
3434 							break;
3435 						}
3436 
3437 						/* now look for an instance with the correct port name */
3438 						pp = getportproto(np, io_edifgbl.port_reference);
3439 						if (pp == NOPORTPROTO)
3440 						{
3441 							if (io_edifgbl.original != 0 && *io_edifgbl.original != 0)
3442 								pp = getportproto(np, io_edifgbl.original);
3443 							if (pp == NOPORTPROTO)
3444 							{
3445 								ttyputmsg(_("error, line #%d: could not locate port '%s'"), io_edifgbl.lineno,
3446 									io_edifgbl.port_reference);
3447 								break;
3448 							}
3449 						}
3450 						fni = pp->subnodeinst;
3451 						fpp = pp->subportproto;
3452 						portposition(fni, fpp, &lx, &ly);
3453 
3454 						/* determine x position by original placement */
3455 						switch (pp->userbits&STATEBITS)
3456 						{
3457 							case INPORT:
3458 								lx = 1*INCH;
3459 								break;
3460 							case BIDIRPORT:
3461 								lx = 4*INCH;
3462 								break;
3463 							case OUTPORT:
3464 								lx = 5*INCH;
3465 								break;
3466 						}
3467 
3468 						/* need to create a destination for the wire */
3469 						if (io_edifgbl.isarray != 0)
3470 						{
3471 							ni = io_edifiplacepin(sch_buspinprim, lx + sch_buspinprim->lowx,
3472 								lx + sch_buspinprim->highx, ly + sch_buspinprim->lowy,
3473 								ly + sch_buspinprim->highy, 0, 0, np);
3474 							if (ni == NONODEINST)
3475 							{
3476 								ttyputmsg(_("error, line#%d: could not create bus pin"),
3477 									io_edifgbl.lineno);
3478 								break;
3479 							}
3480 							pp = default_busport;
3481 						} else
3482 						{
3483 							ni = io_edifiplacepin(sch_wirepinprim, lx + sch_wirepinprim->lowx,
3484 								lx + sch_wirepinprim->highx, ly + sch_wirepinprim->lowy,
3485 								ly + sch_wirepinprim->highy, 0, 0, np);
3486 							if (ni == NONODEINST)
3487 							{
3488 								ttyputmsg(_("error, line#%d: could not create wire pin"),
3489 									io_edifgbl.lineno);
3490 								break;
3491 							}
3492 							pp = default_port;
3493 						}
3494 						if (io_edifgbl.isarray == 0) ap = sch_wirearc; else
3495 							ap = sch_busarc;
3496 					}
3497 
3498 					/* now connect if we have from node and port */
3499 					if (fni != NONODEINST && fpp != NOPORTPROTO)
3500 					{
3501 						if (fni->parent != ni->parent)
3502 						{
3503 							ttyputmsg(_("error, line #%d: could not create path (arc) between cells %s and %s"),
3504 								io_edifgbl.lineno, describenodeproto(fni->parent), describenodeproto(ni->parent));
3505 						} else
3506 						{
3507 							/* locate the position of the new ports */
3508 							portposition(fni, fpp, &lx, &ly);
3509 							portposition(ni, pp, &hx, &hy);
3510 
3511 							/* for nets with no physical representation ... */
3512 							io_edifgbl.current_arc = NOARCINST;
3513 							if (lx == hx && ly == hy) dist = 0; else
3514 								dist = computedistance(lx, ly, hx, hy);
3515 							if (dist <= lambda*SLOPDISTANCE)
3516 							{
3517 								io_edifgbl.current_arc = newarcinst(ap, defaultarcwidth(ap),
3518 									FIXANG|CANTSLIDE, fni, fpp, lx, ly, ni, pp, hx, hy, np);
3519 								if (io_edifgbl.current_arc == NOARCINST)
3520 								{
3521 									ttyputmsg(_("error, line #%d: could not create path (arc)"),
3522 										io_edifgbl.lineno);
3523 								}
3524 							}
3525 							/* use unrouted connection for NETLIST views */
3526 							else if (io_edifgbl.active_view == VNETLIST)
3527 							{
3528 								io_edifgbl.current_arc = newarcinst(ap, defaultarcwidth(ap),
3529 									CANTSLIDE, fni, fpp, lx, ly, ni, pp, hx, hy, np);
3530 								if (io_edifgbl.current_arc == NOARCINST)
3531 								{
3532 									ttyputmsg(_("error, line #%d: could not create auto-path"),
3533 										io_edifgbl.lineno);
3534 								}
3535 							}
3536 
3537 							/* add the net name */
3538 							if (io_edifgbl.current_arc != NOARCINST)
3539 								io_ednamearc(io_edifgbl.current_arc);
3540 						}
3541 					}
3542 				}
3543 				break;
3544 			case KINSTANCEREF:
3545 				break;
3546 			case KPATH:
3547 				/* check for openShape type path */
3548 				if (io_edifgbl.path_width == 0 &&
3549 					io_edifgbl.geometry != GNET && io_edifgbl.geometry != GBUS) goto dopoly;
3550 				fcnt = 0;
3551 				if (io_edifgbl.geometry == GBUS || io_edifgbl.isarray) np = sch_buspinprim;
3552 				else np = sch_wirepinprim;
3553 				if (io_edifgbl.points == NOEPT) break;
3554 				for (point = io_edifgbl.points; point->nextpt != NOEPT; point = point->nextpt)
3555 				{
3556 					if (io_edifgbl.geometry == GNET || io_edifgbl.geometry == GBUS)
3557 					{
3558 						/* create a pin to pin connection */
3559 						if (fcnt == 0)
3560 						{
3561 							/* look for the first pin */
3562 							fcnt = io_edfindport(io_edifgbl.current_cell, point->x,
3563 								point->y, sch_wirearc, fnis, fpps);
3564 							if (fcnt == 0)
3565 							{
3566 								/* create the "from" pin */
3567 								fnis[0] = io_edifiplacepin(np, point->x + np->lowx, point->x + np->highx,
3568 									point->y + np->lowy, point->y + np->highy,
3569 									0, 0, io_edifgbl.current_cell);
3570 								if (fnis[0] == NONODEINST) fcnt = 0; else
3571 								{
3572 									fpps[0] = (io_edifgbl.geometry == GBUS || io_edifgbl.isarray) ?
3573 										default_busport : default_port;
3574 									fcnt = 1;
3575 								}
3576 							}
3577 						}
3578 						/* now the second ... */
3579 						tcnt = io_edfindport(io_edifgbl.current_cell, point->nextpt->x,
3580 							point->nextpt->y, sch_wirearc, tnis, tpps);
3581 						if (tcnt == 0)
3582 						{
3583 							/* create the "to" pin */
3584 							tnis[0] = io_edifiplacepin(np, point->nextpt->x + np->lowx,
3585 								point->nextpt->x + np->highx,
3586 								point->nextpt->y + np->lowy,
3587 								point->nextpt->y + np->highy,
3588 								0, 0, io_edifgbl.current_cell);
3589 							if (tnis[0] == NONODEINST) tcnt = 0; else
3590 							{
3591 								tpps[0] = (io_edifgbl.geometry == GBUS || io_edifgbl.isarray) ?
3592 									default_busport : default_port;
3593 								tcnt = 1;
3594 							}
3595 						}
3596 
3597 						if (tcnt == 0 || fcnt == 0)
3598 						{
3599 							ttyputerr(_("error, line #%d: could not create path"), io_edifgbl.lineno);
3600 							io_edifgbl.errors++;
3601 						} else
3602 						{
3603 							/* connect it */
3604 							for (count = 0; count < fcnt || count < tcnt; count++)
3605 							{
3606 								if (count < fcnt)
3607 								{
3608 									lastpin = fnis[count];
3609 									lastport = fpps[count];
3610 
3611 									/* check node for array variable */
3612 									var = getvalkey((INTBIG)lastpin, VNODEINST, VSTRING, EDIF_array_key);
3613 									if (var != NOVARIABLE) fbus = 1; else
3614 										if (lastport->protoname[estrlen(lastport->protoname)-1] == ']') fbus = 1; else
3615 											fbus = 0;
3616 								}
3617 								if (count < tcnt)
3618 								{
3619 									ni = tnis[count];
3620 									pp = tpps[count];
3621 
3622 									/* check node for array variable */
3623 									var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, EDIF_array_key);
3624 									if (var != NOVARIABLE) tbus = 1; else
3625 										if (pp->protoname[estrlen(pp->protoname)-1] == ']') tbus = 1; else
3626 											tbus = 0;
3627 								}
3628 
3629 								/* if bus to bus */
3630 								if ((lastport == default_busport || fbus) &&
3631 									(pp == default_busport || tbus)) ap = sch_busarc;
3632 										/* wire to other */
3633 								else ap = sch_wirearc;
3634 
3635 								ai = newarcinst(ap, defaultarcwidth(ap), FIXANG|CANTSLIDE,
3636 									lastpin, lastport, point->x, point->y,
3637 									ni, pp, point->nextpt->x, point->nextpt->y,
3638 									io_edifgbl.current_cell);
3639 								if (ai == NOARCINST)
3640 								{
3641 									ttyputerr(_("error, line #%d: could not create path (arc)"),
3642 										io_edifgbl.lineno);
3643 									io_edifgbl.errors++;
3644 								} else if (io_edifgbl.geometry == GNET && io_edifgbl.points == point)
3645 								{
3646 									if (io_edifgbl.net_reference)
3647 									{
3648 										var = setvalkey((INTBIG)ai, VARCINST, EDIF_name_key,
3649 											(INTBIG)io_edifgbl.net_reference, VSTRING);
3650 									}
3651 									if (io_edifgbl.net_name)
3652 									{
3653 										/* set name of arc but don't display name */
3654 										var = setvalkey((INTBIG)ai, VARCINST, el_arc_name_key,
3655 											(INTBIG)io_edifgbl.net_name, VSTRING);
3656 										if (var != NOVARIABLE)
3657 											defaulttextsize(4, var->textdescript);
3658 									}
3659 								} else if (io_edifgbl.geometry == GBUS && io_edifgbl.points == point)
3660 								{
3661 									if (io_edifgbl.bundle_reference)
3662 									{
3663 										var = setvalkey((INTBIG)ai, VARCINST, EDIF_name_key,
3664 											(INTBIG)io_edifgbl.bundle_reference, VSTRING);
3665 									}
3666 									if (io_edifgbl.bundle_name)
3667 									{
3668 										/* set bus' EDIF name but don't display name */
3669 										var = setvalkey((INTBIG)ai, VARCINST, el_arc_name_key,
3670 											(INTBIG)io_edifgbl.bundle_name, VSTRING);
3671 										if (var != NOVARIABLE)
3672 											defaulttextsize(4, var->textdescript);
3673 									}
3674 								}
3675 							}
3676 							if (ai != NOARCINST) io_edifgbl.current_arc = ai;
3677 							for (count = 0; count < tcnt; count++)
3678 							{
3679 								fnis[count] = tnis[count];
3680 								fpps[count] = tpps[count];
3681 							}
3682 							fcnt = tcnt;
3683 						}
3684 					} else
3685 					{
3686 						/* rectalinear paths with some width */
3687 						/* create a path from here to there (orthogonal only now) */
3688 						lx = hx = point->x;
3689 						ly = hy = point->y;
3690 						if (lx > point->nextpt->x) lx = point->nextpt->x;
3691 						if (hx < point->nextpt->x) hx = point->nextpt->x;
3692 						if (ly > point->nextpt->y) ly = point->nextpt->y;
3693 						if (hy < point->nextpt->y) hy = point->nextpt->y;
3694 						if (ly == hy || io_edifgbl.extend_end)
3695 						{
3696 							ly -= io_edifgbl.path_width/2;
3697 							hy += io_edifgbl.path_width/2;
3698 						}
3699 						if (lx == hx || io_edifgbl.extend_end)
3700 						{
3701 							lx -= io_edifgbl.path_width/2;
3702 							hx += io_edifgbl.path_width/2;
3703 						}
3704 						ni = io_edifiplacepin(io_edifgbl.figure_group, lx, hx, ly, hy,
3705 							io_edgettrans(io_edifgbl.orientation),
3706 							io_edgetrot(io_edifgbl.orientation),
3707 							io_edifgbl.current_cell);
3708 						if (ni == NONODEINST)
3709 						{
3710 							ttyputerr(_("error, line #%d: could not create path"),
3711 								io_edifgbl.lineno);
3712 							io_edifgbl.errors++;
3713 						}
3714 					}
3715 				}
3716 				io_edfreeptlist();
3717 				break;
3718 			case KCIRCLE:
3719 				if (io_edifgbl.pt_count == 2)
3720 				{
3721 					lx = mini(io_edifgbl.points->x, io_edifgbl.lastpt->x);
3722 					hx = maxi(io_edifgbl.points->x, io_edifgbl.lastpt->x);
3723 					ly = mini(io_edifgbl.points->y, io_edifgbl.lastpt->y);
3724 					hy = maxi(io_edifgbl.points->y, io_edifgbl.lastpt->y);
3725 					if (lx == hx)
3726 					{
3727 						lx -= (hy - ly)>>1;
3728 						hx += (hy - ly)>>1;
3729 					} else
3730 					{
3731 						ly -= (hx - lx)>>1;
3732 						hy += (hx - lx)>>1;
3733 					}
3734 
3735 					/* create the node instance */
3736 					ni = newnodeinst(art_circleprim, lx, hx, ly, hy,
3737 						io_edgettrans(io_edifgbl.orientation),
3738 						io_edgetrot(io_edifgbl.orientation),
3739 						io_edifgbl.current_cell);
3740 					if (ni == NONODEINST)
3741 					{
3742 						ttyputerr(_("error, line #%d: could not create circle"),
3743 							io_edifgbl.lineno);
3744 						io_edifgbl.errors++;
3745 					}
3746 				}
3747 				io_edfreeptlist();
3748 				break;
3749 			case KNAME:
3750 				/* save the data and break */
3751 				io_edfreesavedptlist();
3752 				(void)estrcpy(io_edifgbl.save_text.string, io_edifgbl.string);
3753 				io_edifgbl.string[0] = 0;
3754 				io_edifgbl.save_text.points = io_edifgbl.points;
3755 				io_edifgbl.points = NOEPT;
3756 				io_edifgbl.save_text.pt_count = io_edifgbl.pt_count;
3757 				io_edifgbl.pt_count = 0;
3758 				io_edifgbl.save_text.textheight = io_edifgbl.textheight;
3759 				io_edifgbl.textheight = 0;
3760 				io_edifgbl.save_text.justification = io_edifgbl.justification;
3761 				io_edifgbl.justification = LOWERLEFT;
3762 				io_edifgbl.save_text.orientation = io_edifgbl.orientation;
3763 				io_edifgbl.orientation = OR0;
3764 				io_edifgbl.save_text.visible = io_edifgbl.visible;
3765 				io_edifgbl.visible = 1;
3766 				break;
3767 			case KSTRINGDISPLAY:
3768 				if (kstack_ptr <= 1)
3769 				{
3770 					ttyputerr(_("error, line #%d: bad location for \"stringDisplay\""),
3771 						io_edifgbl.lineno);
3772 					io_edifgbl.errors++;
3773 				}
3774 				else if (kstack[kstack_ptr-1] == KRENAME)
3775 				{
3776 					/* save the data and break */
3777 					io_edfreesavedptlist();
3778 					(void)estrcpy(io_edifgbl.save_text.string, io_edifgbl.string);
3779 					io_edifgbl.string[0] = 0;
3780 					io_edifgbl.save_text.points = io_edifgbl.points;
3781 					io_edifgbl.points = NOEPT;
3782 					io_edifgbl.save_text.pt_count = io_edifgbl.pt_count;
3783 					io_edifgbl.pt_count = 0;
3784 					io_edifgbl.save_text.textheight = io_edifgbl.textheight;
3785 					io_edifgbl.textheight = 0;
3786 					io_edifgbl.save_text.justification = io_edifgbl.justification;
3787 					io_edifgbl.justification = LOWERLEFT;
3788 					io_edifgbl.save_text.orientation = io_edifgbl.orientation;
3789 					io_edifgbl.orientation = OR0;
3790 					io_edifgbl.save_text.visible = io_edifgbl.visible;
3791 					io_edifgbl.visible = 1;
3792 				}
3793 
3794 				/* output the data for annotate (display graphics) and string (on properties) */
3795 				else if (kstack[kstack_ptr-1] == KANNOTATE || kstack[kstack_ptr-1] == KSTRING)
3796 				{
3797 #ifdef IGNORESTRINGSWITHSQUAREBRACKETS
3798 					/* supress this if it starts with "[" */
3799 					if (io_edifgbl.string[0] != '[' && io_edifgbl.points != 0)
3800 #endif
3801 					{
3802 						/* see if a pre-existing node or arc exists to add text */
3803 						ai = NOARCINST;
3804 						ni = NONODEINST;
3805 						if (io_edifgbl.property_reference[0] != 0 && io_edifgbl.current_node != NONODEINST)
3806 						{
3807 							ni = io_edifgbl.current_node;
3808 							key = makekey(io_edifgbl.property_reference);
3809 							xoff = io_edifgbl.points->x - ((ni->highx+ni->lowx)>>1);
3810 							yoff = io_edifgbl.points->y - ((ni->highy+ni->lowy)>>1);
3811 						}
3812 						else if (io_edifgbl.property_reference[0] != 0 && io_edifgbl.current_arc != NOARCINST)
3813 						{
3814 							ai = io_edifgbl.current_arc;
3815 							key = makekey(io_edifgbl.property_reference);
3816 							xoff = io_edifgbl.points->x - ((ai->end[0].xpos + ai->end[1].xpos)>>1);
3817 							yoff = io_edifgbl.points->y - ((ai->end[0].ypos + ai->end[1].ypos)>>1);
3818 						} else
3819 						{
3820 							/* create the node instance */
3821 							xoff = yoff = 0;
3822 							ni = newnodeinst(gen_invispinprim,
3823 								io_edifgbl.points->x, io_edifgbl.points->x,
3824 								io_edifgbl.points->y, io_edifgbl.points->y, 0, 0,
3825 								io_edifgbl.current_cell);
3826 							key = EDIF_annotate_key;
3827 						}
3828 						if (ni != NONODEINST || ai != NOARCINST)
3829 						{
3830 							if (ni != NONODEINST)
3831 							{
3832 								var = setvalkey((INTBIG)ni, VNODEINST, key, (INTBIG)io_edifgbl.string,
3833 									(io_edifgbl.visible ? VSTRING|VDISPLAY : VSTRING));
3834 
3835 								/* now set the position, relative to the center of the current object */
3836 								xoff = io_edifgbl.points->x - ((ni->highx+ni->lowx)>>1);
3837 								yoff = io_edifgbl.points->y - ((ni->highy+ni->lowy)>>1);
3838 							} else
3839 							{
3840 								var = setvalkey((INTBIG)ai, VARCINST, key, (INTBIG)io_edifgbl.string,
3841 									(io_edifgbl.visible ? VSTRING|VDISPLAY : VSTRING));
3842 
3843 								/* now set the position, relative to the center of the current object */
3844 								xoff = io_edifgbl.points->x - ((ai->end[0].xpos + ai->end[1].xpos)>>1);
3845 								yoff = io_edifgbl.points->y - ((ai->end[0].ypos + ai->end[1].ypos)>>1);
3846 							}
3847 
3848 							/* convert to quarter lambda units */
3849 							xoff = 4*xoff / lambda;
3850 							yoff = 4*yoff / lambda;
3851 
3852 							/* determine the size of text, 0.0278 in == 2 points or 36 (2xpixels) == 1 in
3853 		 					fonts range from 4 to 31 */
3854 							if (io_edifgbl.textheight == 0) i = TXTSETQLAMBDA(4); else
3855 							{
3856 								i = io_ediftextsize(io_edifgbl.textheight);
3857 							}
3858 							TDCOPY(descript, var->textdescript);
3859 							TDSETSIZE(descript, i);
3860 							TDSETOFF(descript, xoff, yoff);
3861 							TDSETPOS(descript, VTPOSCENT);
3862 							switch (io_edifgbl.justification)
3863 							{
3864 								case UPPERLEFT:    TDSETPOS(descript, VTPOSUPRIGHT);    break;
3865 								case UPPERCENTER:  TDSETPOS(descript, VTPOSUP);         break;
3866 								case UPPERRIGHT:   TDSETPOS(descript, VTPOSUPLEFT);     break;
3867 								case CENTERLEFT:   TDSETPOS(descript, VTPOSRIGHT);      break;
3868 								case CENTERCENTER: TDSETPOS(descript, VTPOSCENT);       break;
3869 								case CENTERRIGHT:  TDSETPOS(descript, VTPOSLEFT);       break;
3870 								case LOWERLEFT:    TDSETPOS(descript, VTPOSDOWNRIGHT);  break;
3871 								case LOWERCENTER:  TDSETPOS(descript, VTPOSDOWN);       break;
3872 								case LOWERRIGHT:   TDSETPOS(descript, VTPOSDOWNLEFT);   break;
3873 							}
3874 							TDCOPY(var->textdescript, descript);
3875 						} else
3876 						{
3877 							ttyputerr(_("error, line #%d: nothing to attach text to"), io_edifgbl.lineno);
3878 							io_edifgbl.errors++;
3879 						}
3880 					}
3881 				}
3882 
3883 				/* clean up DISPLAY attributes */
3884 				io_edfreeptlist();
3885 				io_edifgbl.cur_nametbl = NONAMETABLE;
3886 				io_edifgbl.visible = 1;
3887 				io_edifgbl.justification = LOWERLEFT;
3888 				io_edifgbl.textheight = 0;
3889 				break;
3890 			case KDOT:
3891 				if (io_edifgbl.geometry == GPIN)
3892 				{
3893 					for (eport = io_edifgbl.ports; eport != NOEDPORT; eport = eport->next)
3894 					{
3895 						if (!namesame(eport->reference, io_edifgbl.name)) break;
3896 					}
3897 					if (eport != NOEDPORT)
3898 					{
3899 						/* create a internal wire port using the pin-proto, and create the port
3900 	  					and export */
3901 						ni = io_edifiplacepin(io_edifgbl.proto,
3902 							io_edifgbl.points->x+io_edifgbl.proto->lowx,
3903 							io_edifgbl.points->x+io_edifgbl.proto->highx,
3904 							io_edifgbl.points->y+io_edifgbl.proto->lowy,
3905 							io_edifgbl.points->y+io_edifgbl.proto->highy,
3906 							io_edgettrans(io_edifgbl.orientation),
3907 							io_edgetrot(io_edifgbl.orientation),
3908 							io_edifgbl.current_cell);
3909 						if (ni == NONODEINST)
3910 						{
3911 							ttyputerr(_("error, line #%d: could not create pin"), io_edifgbl.lineno);
3912 							io_edifgbl.errors++;
3913 						}
3914 						(void)estrcpy(portname, eport->name);
3915 						for (dup = 0, (void)estrcpy(basename, portname);
3916 							(ppt = getportproto(ni->parent, portname)) != NOPORTPROTO; dup++)
3917 						{
3918 							if (dup == 0) pp = ppt;
3919 							(void)esnprintf(portname, WORD+1, x_("%s_%ld"), basename, dup+1);
3920 						}
3921 						ppt = newportproto(ni->parent, ni, default_iconport, portname);
3922 						if (ppt == NOPORTPROTO)
3923 						{
3924 							ttyputerr(_("error, line #%d: could not create port <%s>"),
3925 								io_edifgbl.lineno, portname);
3926 							io_edifgbl.errors++;
3927 						} else
3928 						{
3929 							/* set the direction */
3930 							switch (eport->direction)
3931 							{
3932 								case INPUTE:
3933 									ppt->userbits = (ppt->userbits & ~STATEBITS) | INPORT;
3934 									break;
3935 								case OUTPUTE:
3936 									ppt->userbits = (ppt->userbits & ~STATEBITS) | OUTPORT;
3937 									break;
3938 								case INOUT:
3939 									ppt->userbits = (ppt->userbits & ~STATEBITS) | BIDIRPORT;
3940 									break;
3941 							}
3942 						}
3943 					}
3944 				} else
3945 				{
3946 					/* create the node instance */
3947 					ni = newnodeinst(io_edifgbl.figure_group != NONODEPROTO ?
3948 						io_edifgbl.figure_group : art_boxprim,
3949 						io_edifgbl.points->x, io_edifgbl.points->x,
3950 						io_edifgbl.points->y, io_edifgbl.points->y,
3951 						io_edgettrans(io_edifgbl.orientation),
3952 						io_edgetrot(io_edifgbl.orientation),
3953 						io_edifgbl.current_cell);
3954 					if (ni == NONODEINST)
3955 					{
3956 						ttyputerr(_("error, line #%d: could not create rectangle"),
3957 							io_edifgbl.lineno);
3958 						io_edifgbl.errors++;
3959 					}
3960 				}
3961 				io_edfreeptlist();
3962 				break;
3963 			case KRECTANGLE:
3964 				if (kstack_ptr > 1 && (kstack[kstack_ptr-1] == KPAGESIZE ||
3965 					kstack[kstack_ptr-1] == KBOUNDINGBOX)) break;
3966 				if (io_edifgbl.pt_count == 2)
3967 				{
3968 					/* create the node instance */
3969 					if (io_edifgbl.points->x > io_edifgbl.lastpt->x)
3970 					{
3971 						lx = io_edifgbl.lastpt->x;
3972 						hx = io_edifgbl.points->x;
3973 					} else
3974 					{
3975 						hx = io_edifgbl.lastpt->x;
3976 						lx = io_edifgbl.points->x;
3977 					}
3978 					if (io_edifgbl.points->y > io_edifgbl.lastpt->y)
3979 					{
3980 						ly = io_edifgbl.lastpt->y;
3981 						hy = io_edifgbl.points->y;
3982 					} else
3983 					{
3984 						hy = io_edifgbl.lastpt->y;
3985 						ly = io_edifgbl.points->y;
3986 					}
3987 					ni = newnodeinst(io_edifgbl.figure_group != NONODEPROTO ?
3988 						io_edifgbl.figure_group : art_boxprim,
3989 						lx, hx, ly, hy,
3990 						io_edgettrans(io_edifgbl.orientation),
3991 						io_edgetrot(io_edifgbl.orientation),
3992 						io_edifgbl.current_cell);
3993 					if (ni == NONODEINST)
3994 					{
3995 						ttyputerr(_("error, line #%d: could not create rectangle"),
3996 							io_edifgbl.lineno);
3997 						io_edifgbl.errors++;
3998 					}
3999 					else if (io_edifgbl.figure_group == art_openeddottedpolygonprim)
4000 					{
4001 						cnt = 5;
4002 						cx = (io_edifgbl.points->x + io_edifgbl.lastpt->x) / 2;
4003 						cy = (io_edifgbl.points->y + io_edifgbl.lastpt->y) / 2;
4004 						pts[0] = io_edifgbl.points->x-cx;
4005 						pts[1] = io_edifgbl.points->y-cy;
4006 						pts[2] = io_edifgbl.points->x-cx;
4007 						pts[3] = io_edifgbl.lastpt->y-cy;
4008 						pts[4] = io_edifgbl.lastpt->x-cx;
4009 						pts[5] = io_edifgbl.lastpt->y-cy;
4010 						pts[6] = io_edifgbl.lastpt->x-cx;
4011 						pts[7] = io_edifgbl.points->y-cy;
4012 						pts[8] = io_edifgbl.points->x-cx;
4013 						pts[9] = io_edifgbl.points->y-cy;
4014 
4015 						/* store the trace information */
4016 						(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)pts,
4017 							VINTEGER|VISARRAY|((cnt*2)<<VLENGTHSH));
4018 					}
4019 					else if (io_edifgbl.geometry == GPIN)
4020 					{
4021 						/* create a rectangle using the pin-proto, and create the port
4022 	   					 * and export
4023 	   					 */
4024 						/* ensure full sized port */
4025 						lx += io_edifgbl.proto->lowx;
4026 						hx += io_edifgbl.proto->highx;
4027 						ly += io_edifgbl.proto->lowy;
4028 						hy += io_edifgbl.proto->highy;
4029 
4030 						/* create the node instance */
4031 						ni = io_edifiplacepin(io_edifgbl.proto, lx, hx, ly, hy,
4032 							io_edgettrans(io_edifgbl.orientation),
4033 							io_edgetrot(io_edifgbl.orientation),
4034 							io_edifgbl.current_cell);
4035 						if (ni == NONODEINST)
4036 						{
4037 							ttyputerr(_("error, line #%d: could not create pin"),
4038 								io_edifgbl.lineno);
4039 							io_edifgbl.errors++;
4040 						}
4041 						ppt = getportproto(ni->parent, io_edifgbl.name);
4042 						if (ppt == NOPORTPROTO)
4043 							ppt = newportproto(ni->parent, ni, default_iconport, io_edifgbl.name);
4044 						if (ppt == NOPORTPROTO)
4045 						{
4046 							ttyputerr(_("error, line #%d: could not create port <%s>"),
4047 								io_edifgbl.lineno, io_edifgbl.name);
4048 							io_edifgbl.errors++;
4049 						}
4050 					}
4051 				}
4052 				io_edfreeptlist();
4053 
4054 				break;
4055 
4056 			case KARC:
4057 				/* set array values */
4058 				for (point = io_edifgbl.points, i = 0; point && i < 3; point = point->nextpt,i++)
4059 				{
4060 					x[i] = point->x;
4061 					y[i] = point->y;
4062 				}
4063 				io_ededif_arc(x, y, &cx, &cy, &radius, &so, &ar, &j, &trans);
4064 				lx = cx - radius;   hx = cx + radius;
4065 				ly = cy - radius;   hy = cy + radius;
4066 
4067 				/* get the bounds of the circle */
4068 				ni = newnodeinst(io_edifgbl.figure_group != NONODEPROTO &&
4069 					io_edifgbl.figure_group != art_boxprim ?
4070 					io_edifgbl.figure_group : art_circleprim, lx, hx, ly, hy,
4071 					trans, j, io_edifgbl.current_cell);
4072 				if (ni == NONODEINST)
4073 				{
4074 					ttyputerr(_("error, line #%d: could not create arc"), io_edifgbl.lineno);
4075 					io_edifgbl.errors++;
4076 				} else
4077 				{
4078 					/* store the angle of the arc */
4079 					setarcdegrees(ni, so, ar*EPI/1800.0);
4080 				}
4081 				io_edfreeptlist();
4082 				break;
4083 
4084 			case KSYMBOL:
4085 			case KPAGE:
4086 				np = io_edifgbl.current_cell;
4087 				if (np != NONODEPROTO)
4088 				{
4089 					/* now compute the bounds of this cell */
4090 					db_boundcell(np, &np->lowx, &np->highx, &np->lowy, &np->highy);
4091 				}
4092 				io_edifgbl.active_view = VNULL;
4093 				break;
4094 
4095 			case KOPENSHAPE:
4096 			case KPOLYGON:
4097 dopoly:
4098 				if (io_edifgbl.pt_count == 0) break;
4099 
4100 				/* get the bounds of the poly */
4101 				lx = hx = io_edifgbl.points->x;
4102 				ly = hy = io_edifgbl.points->y;
4103 				point = io_edifgbl.points->nextpt;
4104 				while (point)
4105 				{
4106 					if (lx > point->x) lx = point->x;
4107 					if (hx < point->x) hx = point->x;
4108 					if (ly > point->y) ly = point->y;
4109 					if (hy < point->y) hy = point->y;
4110 					point = point->nextpt;
4111 				}
4112 				if (lx != hx || ly != hy)
4113 				{
4114 					if (io_edifgbl.figure_group != NONODEPROTO && io_edifgbl.figure_group != art_boxprim)
4115 						np = io_edifgbl.figure_group; else
4116 					{
4117 						if (io_edifgbl.state == KPOLYGON) np = art_closedpolygonprim; else
4118 							np = art_openedpolygonprim;
4119 					}
4120 					ni = newnodeinst(np, lx, hx, ly, hy, io_edgettrans(io_edifgbl.orientation),
4121 						io_edgetrot(io_edifgbl.orientation), io_edifgbl.current_cell);
4122 					if (ni == NONODEINST)
4123 					{
4124 						ttyputerr(_("error, line #%d: could not create polygon"), io_edifgbl.lineno);
4125 						io_edifgbl.errors++;
4126 					} else
4127 					{
4128 						pt = trace = emalloc((io_edifgbl.pt_count*2*SIZEOFINTBIG), el_tempcluster);
4129 						if (trace == 0) RET_NOMEMORY();
4130 						cx = (hx + lx) / 2;
4131 						cy = (hy + ly) / 2;
4132 						point = io_edifgbl.points;
4133 						while (point != NOEPT)
4134 						{
4135 							*pt++ = point->x - cx;
4136 							*pt++ = point->y - cy;
4137 							point = point->nextpt;
4138 						}
4139 
4140 						/* store the trace information */
4141 						(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)trace,
4142 							VINTEGER|VISARRAY|((io_edifgbl.pt_count*2)<<VLENGTHSH));
4143 
4144 						/* free the polygon memory */
4145 						efree((CHAR *)trace);
4146 					}
4147 				}
4148 				io_edfreeptlist();
4149 				break;
4150 			case KARRAY:
4151 				switch (kstack[kstack_ptr-1])
4152 				{
4153 					case KPORT:
4154 						io_edmake_electric_name(io_edifgbl.port_reference, io_edifgbl.port_name, io_edifgbl.arrayx,
4155 							io_edifgbl.arrayy);
4156 					default:
4157 						break;
4158 				}
4159 				if (io_edifgbl.arrayx == 0) io_edifgbl.arrayx = 1;
4160 				if (io_edifgbl.arrayy == 0) io_edifgbl.arrayy = 1;
4161 				break;
4162 			case KMEMBER:
4163 				if (io_edifgbl.memberx != -1)
4164 				{
4165 					/* adjust the name of the current INSTANCE/NET/PORT(/VALUE) */
4166 					if (io_edifgbl.membery != -1)
4167 						(void)esnprintf(basename, WORD+1, x_("[%d,%d]"), io_edifgbl.memberx, io_edifgbl.membery);
4168 					else (void)esnprintf(basename, WORD+1, x_("[%d]"), io_edifgbl.memberx);
4169 					switch (kstack[kstack_ptr-1])
4170 					{
4171 						case KINSTANCEREF:
4172 							(void)estrcat(io_edifgbl.instance_reference, basename);
4173 							break;
4174 						case KPORTREF:
4175 							(void)estrcat(io_edifgbl.port_reference, basename);
4176 							break;
4177 						default:
4178 							break;
4179 					}
4180 				}
4181 				break;
4182 			case KDESIGN:
4183 				if (io_edifgbl.proto != NONODEPROTO)
4184 				{
4185 					if (io_verbose < 0)
4186 					{
4187 						infstr = initinfstr();
4188 						formatinfstr(infstr, _("Design %s"),
4189 							io_edifgbl.proto->protoname);
4190 						DiaSetTextProgress(io_edifprogressdialog, returninfstr(infstr));
4191 					}
4192 					else ttyputmsg(_("Design %s"), io_edifgbl.proto->protoname);
4193 					io_edifgbl.library->curnodeproto = io_edifgbl.proto;
4194 				}
4195 				break;
4196 
4197 			case KEDIF:
4198 				/* free the port freelist */
4199 				for (eport = io_edifgbl.free_ports; eport != NOEDPORT; eport = neport)
4200 				{
4201 					neport = eport->next;
4202 					efree((CHAR *)eport);
4203 				}
4204 				io_edifgbl.free_ports = NOEDPORT;
4205 
4206 				/* free the netport list */
4207 				io_edfreenetports();
4208 				break;
4209 			default:
4210 				break;
4211 			}
4212 		}
4213 		if (kstack_ptr) io_edifgbl.state = kstack[--kstack_ptr]; else
4214 			io_edifgbl.state = KINIT;
4215 		return(0);
4216 	}
4217 	else return(1);
4218 }
4219 
4220 /* module: io_edprocess_integer
4221    function: will do cleanup processing of an integer argument such as in (array (...) 1 2)
4222  */
4223 void io_edprocess_integer(INTBIG value)
4224 {
4225 	if (kstack_ptr)
4226 	{
4227 		if (!io_edifgbl.ignoreblock)
4228 		{
4229 			switch (io_edifgbl.state)
4230 			{
4231 				case KARRAY:
4232 					if (io_edifgbl.arrayx == 0) io_edifgbl.arrayx = value;
4233 						else if (io_edifgbl.arrayy == 0) io_edifgbl.arrayy = value;
4234 					break;
4235 				case KMEMBER:
4236 					if (io_edifgbl.memberx == -1) io_edifgbl.memberx = value;
4237 						else if (io_edifgbl.membery == -1) io_edifgbl.membery = value;
4238 					break;
4239 				default:
4240 					break;
4241 			}
4242 		}
4243 	}
4244 }
4245 
4246 INTSML io_edgetrot(OTYPES orientation)
4247 {
4248 	switch (orientation)
4249 	{
4250 		case OR0:     return(0);
4251 		case OR90:    return(90*10);
4252 		case OR180:   return(180*10);
4253 		case OR270:   return(270*10);
4254 		case OMX:     return(270*10);
4255 		case OMY:     return(90*10);
4256 		case OMXR90:  return(180*10);
4257 		case OMYR90:  return(0);
4258 		default:      break;
4259 	}
4260 	return(0);
4261 }
4262 
4263 INTSML io_edgettrans(OTYPES orientation)
4264 {
4265 	switch (orientation)
4266 	{
4267 		case OR0:     return(0);
4268 		case OR90:    return(0);
4269 		case OR180:   return(0);
4270 		case OR270:   return(0);
4271 		case OMY:     return(1);
4272 		case OMX:     return(1);
4273 		case OMYR90:  return(1);
4274 		case OMXR90:  return(1);
4275 		default:      break;
4276 	}
4277 	return(0);
4278 }
4279 
4280 /*
4281  * Routine to return the text height to use when it says "textheight" units in the EDIF file.
4282  */
4283 INTBIG io_ediftextsize(INTBIG textheight)
4284 {
4285 	REGISTER INTBIG i, lambda;
4286 
4287 	lambda = el_curlib->lambda[io_edifgbl.technology->techindex];
4288 	i = io_edifgbl.textheight / lambda;
4289 	if (i < 0) i = 4;
4290 	if (i > TXTMAXQLAMBDA) i = TXTMAXQLAMBDA;
4291 	i = TXTSETQLAMBDA(i);
4292 	return(i);
4293 }
4294 
4295 /* helper routine for "esort" */
4296 int io_edcompare_name(const void *name1, const void *name2)
4297 {
4298 	REGISTER NAMETABLE_PTR *n1, *n2;
4299 
4300 	n1 = (NAMETABLE_PTR *)name1;
4301 	n2 = (NAMETABLE_PTR *)name2;
4302 	return(namesame((*n1)->original, (*n2)->original));
4303 }
4304 
4305 /* Will check if a string is an valid integer */
4306 INTBIG io_edis_integer(CHAR *buffer)
4307 {
4308 	/* remove sign */
4309 	if (*buffer == '+' || *buffer == '-') buffer++;
4310 	while (isdigit(*buffer))
4311 	{
4312 		buffer++;
4313 		if (*buffer == 0) return(1);
4314 	}
4315 	return(0);
4316 }
4317 
4318 /* get a keyword routine */
4319 CHAR *io_edget_keyword(CHAR *buffer)
4320 {
4321 	CHAR *p;
4322 
4323 	/* look for a '(' before the edif keyword */
4324 	while ((p = io_edget_token(buffer, 0)) && (*p != '('))
4325 	{
4326 		if (*p == ')') io_edpop_stack(); else
4327 			if (io_edis_integer(buffer)) io_edprocess_integer(eatoi(buffer));
4328 	}
4329 	return(io_edget_token(buffer, 0));
4330 }
4331 
4332 /* get a token routine */
4333 CHAR *io_edget_token(CHAR *buffer, CHAR idelim)
4334 {
4335 	CHAR *sptr;
4336 	CHAR delim;
4337 
4338 	/* locate the first non-white space character for non-delimited searches */
4339 	delim = idelim;
4340 	if (!delim)
4341 	{
4342 		if (io_edpos_token() == NULL)
4343 			return(NULL);
4344 	}
4345 
4346 	/* set up the string copy */
4347 	sptr = buffer;
4348 	if (!delim && *io_edifgbl.pos == '"')
4349 	{
4350 		/* string search */
4351 		delim = '"';
4352 		*(sptr++) = *(io_edifgbl.pos++);
4353 	}
4354 
4355 	/* non locate the next white space or the delimiter */
4356 	for(;;)
4357 	{
4358 		if (*io_edifgbl.pos == 0)
4359 		{
4360 			/* end of string, get the next line */
4361 			if (!io_edget_line(io_edifgbl.buffer, LINE, io_edifgbl.edif_file))
4362 			{
4363 				/* end-of-file, if no delimiter return NULL, otherwise the string */
4364 				if (delim) break;
4365 				*sptr = 0;
4366 				return(buffer);
4367 			}
4368 			io_edifgbl.pos = io_edifgbl.buffer;
4369 		} else if (!delim)
4370 		{
4371 			switch (*io_edifgbl.pos)
4372 			{
4373 				/* the space characters */
4374 				case '\n':
4375 				case '\r':
4376 					io_edifgbl.lineno++;
4377 					/* FALLTHROUGH */
4378 				case ' ':
4379 				case '\t':
4380 					*sptr = 0;
4381 					/* skip to the next character */
4382 					io_edifgbl.pos++;
4383 					return(buffer);
4384 					/* special EDIF delimiters */
4385 				case '(':
4386 				case ')':
4387 					if (sptr == buffer)
4388 						*(sptr++) = *(io_edifgbl.pos++);
4389 					*sptr = 0;
4390 					return(buffer);
4391 				default:
4392 					*(sptr++) = *(io_edifgbl.pos++);
4393 					break;
4394 			}
4395 		} else
4396 		{
4397 			/* check for user specified delimiter */
4398 			if (*io_edifgbl.pos == delim)
4399 			{
4400 				/* skip the delimiter, unless string */
4401 				if (delim != idelim) *(sptr++) = *(io_edifgbl.pos++); else
4402 					io_edifgbl.pos++;
4403 				*sptr = 0;
4404 				return(buffer);
4405 			} else
4406 			{
4407 				if (*io_edifgbl.pos == '\r' || *io_edifgbl.pos == '\n')
4408 				{
4409 					io_edifgbl.lineno++;
4410 				}
4411 
4412 				*(sptr++) = *(io_edifgbl.pos++);
4413 			}
4414 		}
4415 	}
4416 	return(NULL);
4417 }
4418 
4419 /*
4420  * Module: io_edpos_token
4421  * Function: special routine to position to the next token
4422  */
4423 CHAR *io_edpos_token(void)
4424 {
4425 	for(;;)
4426 	{
4427 		switch (*io_edifgbl.pos)
4428 		{
4429 			case 0:
4430 				/* end of string, get the next line */
4431 				if (!io_edget_line(io_edifgbl.buffer, LINE, io_edifgbl.edif_file))
4432 				{
4433 					/* end-of-file */
4434 					return(NULL);
4435 				}
4436 				io_edifgbl.pos = io_edifgbl.buffer;
4437 				break;
4438 
4439 				/* the space characters */
4440 			case '\n':
4441 			case '\r':
4442 				io_edifgbl.lineno++;
4443 				/* FALLTHROUGH */
4444 			case ' ':
4445 			case '\t':
4446 				io_edifgbl.pos++;
4447 				break;
4448 			default:
4449 				return(io_edifgbl.pos);
4450 		}
4451 	}
4452 }
4453 
4454 /*
4455  * routine to read a line from file "file" and place it in "line" (which has
4456  * up to "limit" characters).  Returns FALSE on end-of-file.  Updates "filepos".
4457  */
4458 BOOLEAN io_edget_line(CHAR *line, INTBIG limit, FILE *file)
4459 {
4460 	REGISTER CHAR *pp;
4461 	REGISTER INTSML c;
4462 	REGISTER INTBIG total;
4463 
4464 	pp = line;
4465 	total = 1;
4466 	for(;;)
4467 	{
4468 		c = xgetc(file);
4469 		if (c == EOF)
4470 		{
4471 			if (pp == line) return(FALSE);
4472 			break;
4473 		}
4474 		filepos++;
4475 		*pp = (CHAR)c;
4476 		if (*pp == '\n')
4477 		{
4478 			pp++;
4479 			break;
4480 		}
4481 		pp++;
4482 		if ((++total) >= limit) break;
4483 	}
4484 	*pp = 0;
4485 	return(TRUE);
4486 }
4487 
4488 /* get a delimeter routine */
4489 void io_edget_delim(CHAR delim)
4490 {
4491 	CHAR *token;
4492 
4493 	token = io_edpos_token();
4494 	if (token == NULL) longjmp(io_edifgbl.env, LONGJMPEOF);
4495 	if (*token != delim) longjmp(io_edifgbl.env, LONGJMPILLDELIM); else
4496 		io_edifgbl.pos++;
4497 }
4498 
4499 /************ INPUT SUPPORT *********/
4500 
4501 /* This function allocates ports */
4502 INTBIG io_edallocport(void)
4503 {
4504 	EDPORT_PTR port;
4505 
4506 	if (io_edifgbl.free_ports != NOEDPORT)
4507 	{
4508 		port = io_edifgbl.free_ports;
4509 		io_edifgbl.free_ports = port->next;
4510 	} else
4511 	{
4512 		port = (EDPORT_PTR)emalloc(sizeof (EDPORT), io_tool->cluster);
4513 		if (port == NOEDPORT) RET_NOMEMORY();
4514 	}
4515 
4516 	port->next = io_edifgbl.ports;
4517 	io_edifgbl.ports = port;
4518 	if (allocstring(&port->reference, io_edifgbl.port_reference, io_tool->cluster))
4519 		RET_NOMEMORY();
4520 	if (allocstring(&port->name, io_edifgbl.port_name, io_tool->cluster))
4521 		RET_NOMEMORY();
4522 
4523 	port->direction = io_edifgbl.direction;
4524 	port->arrayx = io_edifgbl.arrayx;
4525 	port->arrayy = io_edifgbl.arrayy;
4526 	return(0);
4527 }
4528 
4529 INTBIG io_edallocproperty(CHAR *name, PROPERTY_TYPE type, int integer,
4530 	float number, CHAR *string)
4531 {
4532 	EDPROPERTY_PTR property;
4533 	REGISTER void *infstr;
4534 
4535 	if (io_edifgbl.free_properties != NOEDPROPERTY)
4536 	{
4537 		property = io_edifgbl.free_properties;
4538 		io_edifgbl.free_properties = property->next;
4539 	} else
4540 	{
4541 		property = (EDPROPERTY_PTR)emalloc(sizeof (EDPROPERTY), io_tool->cluster);
4542 		if (property == NOEDPROPERTY)
4543 			RET_NOMEMORY();
4544 	}
4545 
4546 	property->next = io_edifgbl.properties;
4547 	io_edifgbl.properties = property;
4548 	infstr = initinfstr();
4549 	formatinfstr(infstr, x_("ATTR_%s"), name);
4550 	if (allocstring(&property->name, returninfstr(infstr), io_tool->cluster))
4551 		RET_NOMEMORY();
4552 	property->type = type;
4553 	switch (property->type)
4554 	{
4555 		case PINTEGER:
4556 			property->val.integer = integer;
4557 			break;
4558 		case PNUMBER:
4559 			property->val.number = number;
4560 			break;
4561 		case PSTRING:
4562 			if (allocstring(&property->val.string, string, io_tool->cluster))
4563 				RET_NOMEMORY();
4564 			break;
4565 		default:
4566 			break;
4567 	}
4568 	return(0);
4569 }
4570 
4571 /* This function allocates net ports */
4572 INTBIG io_edallocnetport(void)
4573 {
4574 	EDNETPORT_PTR netport;
4575 
4576 	if (io_edifgbl.free_netports != NOEDNETPORT)
4577 	{
4578 		netport = io_edifgbl.free_netports;
4579 		io_edifgbl.free_netports = netport->next;
4580 	} else
4581 	{
4582 		netport = (EDNETPORT_PTR)emalloc(sizeof (EDNETPORT), io_tool->cluster);
4583 		if (netport == NOEDNETPORT) RET_NOMEMORY();
4584 	}
4585 
4586 	if (io_edifgbl.firstnetport == NOEDNETPORT)io_edifgbl.firstnetport = netport; else
4587 		io_edifgbl.lastnetport->next = netport;
4588 
4589 	io_edifgbl.lastnetport = netport;
4590 	netport->next = NOEDNETPORT;
4591 	netport->ni = NONODEINST;
4592 	netport->pp = NOPORTPROTO;
4593 	netport->member = 0;
4594 	return(0);
4595 }
4596 
4597 /* free the netport list */
4598 void io_edfreenetports(void)
4599 {
4600 	EDNETPORT_PTR nport;
4601 
4602 	while (io_edifgbl.firstnetport != NOEDNETPORT)
4603 	{
4604 		nport = io_edifgbl.firstnetport;
4605 		io_edifgbl.firstnetport = nport->next;
4606 		nport->next = io_edifgbl.free_netports;
4607 		io_edifgbl.free_netports = nport;
4608 	}
4609 	io_edifgbl.firstnetport = io_edifgbl.lastnetport = NOEDNETPORT;
4610 }
4611 
4612 /*
4613  * Module: io_edeq_of_a_line
4614  * Function: Calculates the equation of a line (Ax + By + C = 0)
4615  * Inputs:  sx, sy  - Start point
4616  *          ex, ey  - End point
4617  *          px, py  - Point line should pass through
4618  * Outputs: A, B, C - constants for the line
4619  */
4620 void io_edeq_of_a_line(double sx, double sy, double ex, double ey, double *A, double *B, double *C)
4621 {
4622 	if (sx == ex)
4623 	{
4624 		*A = 1.0;
4625 		*B = 0.0;
4626 		*C = -ex;
4627 	} else if (sy == ey)
4628 	{
4629 		*A = 0.0;
4630 		*B = 1.0;
4631 		*C = -ey;
4632 	} else
4633 	{
4634 		/* let B = 1 then */
4635 		*B = 1.0;
4636 		if (sx != 0.0)
4637 		{
4638 			/* Ax1 + y1 + C = 0    =>    A = -(C + y1) / x1 */
4639 			/* C = -Ax2 - y2       =>    C = (Cx2 + y1x2) / x1 - y2   =>   Cx1 - Cx2 = y1x2 - y2x1  */
4640 			/* C = (y2x1 - y1x2) / (x2 - x1) */
4641 			*C = (ey * sx - sy * ex) / (ex - sx);
4642 			*A = -(*C + sy) / sx;
4643 		} else
4644 		{
4645 			*C = (sy * ex - ey * sx) / (sx - ex);
4646 			*A = -(*C + ey) / ex;
4647 		}
4648 	}
4649 }
4650 
4651 /*
4652  * Module: io_eddetermine_intersection
4653  * Function: Will determine the intersection of two lines
4654  * Inputs: Ax + By + C = 0 form
4655  * Outputs: x, y - the point of intersection
4656  * returns 1 if found, 0 if non-intersecting
4657  */
4658 INTBIG io_eddetermine_intersection(double A[2], double B[2], double C[2], double *x, double *y)
4659 {
4660 	double A1B2, A2B1;
4661 	double A2C1, A1C2;
4662 	double X, Y;
4663 
4664 	/* check for parallel lines */
4665 	if ((A1B2 = A[0] * B[1]) == (A2B1 = A[1] * B[0]))
4666 	{
4667 		/* check for coincident lines */
4668 		if (C[0] == C[1]) return(-1);
4669 		return(0);
4670 	}
4671 	A1C2 = A[0] * C[1];
4672 	A2C1 = A[1] * C[0];
4673 
4674 	if (A[0])
4675 	{
4676 		Y = (A2C1 - A1C2) / (A1B2 - A2B1);
4677 		X = -(B[0] * Y + C[0]) / A[0];
4678 	} else
4679 	{
4680 		Y = (A1C2 - A2C1) / (A2B1 - A1B2);
4681 		X = -(B[1] * Y + C[1]) / A[1];
4682 	}
4683 	*y = Y;
4684 	*x = X;
4685 	return(1);
4686 }
4687 
4688 void io_ededif_arc(INTBIG ix[3], INTBIG iy[3], INTBIG *ixc, INTBIG *iyc, INTBIG *r, double *so,
4689 	double *ar, INTBIG *rot, INTBIG *trans)
4690 {
4691 	double x[3], y[3], px[3], py[3], a[3];
4692 	double A[2], B[2], C[2];
4693 	double dx, dy, R, area, xc, yc;
4694 	INTBIG i;
4695 
4696 	for(i=0; i<3; i++)
4697 	{
4698 		x[i] = (double)ix[i];
4699 		y[i] = (double)iy[i];
4700 	}
4701 
4702 	/* get line equations of perpendicular bi-sectors of p1 to p2 */
4703 	px[1] = (x[0] + x[1]) / 2.0;
4704 	py[1] = (y[0] + y[1]) / 2.0;
4705 
4706 	/* now rotate end point 90 degrees */
4707 	px[0] = px[1] - (y[0] - py[1]);
4708 	py[0] = py[1] + (x[0] - px[1]);
4709 	io_edeq_of_a_line(px[0], py[0], px[1], py[1], &A[0], &B[0], &C[0]);
4710 
4711 	/* get line equations of perpendicular bi-sectors of p2 to p3 */
4712 	px[1] = (x[2] + x[1]) / 2.0;
4713 	py[1] = (y[2] + y[1]) / 2.0;
4714 
4715 	/* now rotate end point 90 degrees */
4716 	px[2] = px[1] - (y[2] - py[1]);
4717 	py[2] = py[1] + (x[2] - px[1]);
4718 	io_edeq_of_a_line(px[1], py[1], px[2], py[2], &A[1], &B[1], &C[1]);
4719 
4720 	/* determine the point of intersection */
4721 	(void)io_eddetermine_intersection(A, B, C, &xc, &yc);
4722 
4723 	*ixc = rounddouble(xc);
4724 	*iyc = rounddouble(yc);
4725 
4726 	dx = ((double)*ixc) - x[0];
4727 	dy = ((double)*iyc) - y[0];
4728 	R = sqrt(dx * dx + dy * dy);
4729 	*r = rounddouble(R);
4730 
4731 	/* now calculate the angle to the start and endpoint */
4732 	dx = x[0] - xc;  dy = y[0] - yc;
4733 	if (dx == 0.0 && dy == 0.0)
4734 	{
4735 		ttyputerr(_("Domain error doing arc computation"));
4736 		return;
4737 	}
4738 	a[0] = atan2(dy, dx) * 1800.0 / EPI;
4739 	if (a[0] < 0.0) a[0] += 3600.0;
4740 
4741 	dx = x[2] - xc;  dy = y[2] - yc;
4742 	if (dx == 0.0 && dy == 0.0)
4743 	{
4744 		ttyputerr(_("Domain error doing arc computation"));
4745 		return;
4746 	}
4747 	a[2] = atan2(dy, dx) * 1800.0 / EPI;
4748 	if (a[2] < 0.0) a[2] += 3600.0;
4749 
4750 	/* determine the angle of rotation and object orientation */
4751 	/* determine the direction */
4752 	/* calculate x1*y2 + x2*y3 + x3*y1 - y1*x2 - y2*x3 - y3*x1 */
4753 	area = x[0]*y[1] + x[1]*y[2] + x[2]*y[0] - y[0]*x[1] - y[1]*x[2] - y[2]*x[0];
4754 	if (area > 0.0)
4755 	{
4756 		/* counter clockwise */
4757 		if (a[2] < a[0]) a[2] += 3600.0;
4758 		*ar = a[2] - a[0];
4759 		*rot = rounddouble(a[0]);
4760 		*so = (a[0] - (double)*rot) * EPI / 1800.0;
4761 		*trans = 0;
4762 	} else
4763 	{
4764 		/* clockwise */
4765 		if (a[0] > 2700)
4766 		{
4767 			*rot = 3600 - rounddouble(a[0]) + 2700;
4768 			*so = ((3600.0 - a[0] + 2700.0) - (double)*rot) * EPI / 1800.0;
4769 		} else
4770 		{
4771 			*rot = 2700 - rounddouble(a[0]);
4772 			*so = ((2700.0 - a[0]) - (double)*rot) * EPI / 1800.0;
4773 		}
4774 		if (a[0] < a[2]) a[0] += 3600;
4775 		*ar = a[0] - a[2];
4776 		*trans = 1;
4777 	}
4778 }
4779 
4780 /*
4781  * routine to generate an icon in library "lib" with name "iconname" from the
4782  * port list in "fpp".  The icon cell is called "pt".  The icon cell is
4783  * returned (NONODEPROTO on error). (Note: copied and adapted from us_makeiconcell)
4784  */
4785 NODEPROTO *io_edmakeiconcell(PORTPROTO *fpp, CHAR *iconname, CHAR *pt, LIBRARY *lib)
4786 {
4787 	REGISTER NODEPROTO *np, *bbproto, *pinproto, *buspproto, *pintype;
4788 	REGISTER NODEINST *bbni, *pinni;
4789 	REGISTER PORTPROTO *pp, *port, *inputport, *outputport, *bidirport,
4790 		*topport, *whichport, *bpp;
4791 	REGISTER ARCPROTO *wireproto, *busproto, *wiretype;
4792 	REGISTER INTBIG inputside, outputside, bidirside, topside;
4793 	REGISTER INTBIG eindex, xsize, ysize, xpos, ypos, xbbpos, ybbpos, spacing,
4794 		lambda;
4795 	REGISTER UINTBIG character;
4796 	REGISTER VARIABLE *var;
4797 
4798 	/* get the necessary symbols */
4799 	pinproto = sch_wirepinprim;
4800 	buspproto = sch_buspinprim;
4801 	bbproto = sch_bboxprim;
4802 	wireproto = sch_wirearc;
4803 	busproto = sch_busarc;
4804 	outputport = bbproto->firstportproto;
4805 	topport = outputport->nextportproto;
4806 	inputport = topport->nextportproto;
4807 	bidirport = inputport->nextportproto;
4808 
4809 	/* create the new icon cell */
4810 	lambda = lib->lambda[sch_tech->techindex];
4811 	np = us_newnodeproto(pt, lib);
4812 	if (np == NONODEPROTO)
4813 	{
4814 		ttyputerr(_("Cannot create icon %s"), pt);
4815 		return(NONODEPROTO);
4816 	}
4817 	np->userbits |= WANTNEXPAND;
4818 
4819 	/* determine number of inputs and outputs */
4820 	inputside = outputside = bidirside = topside = 0;
4821 	for(pp = fpp; pp != NOPORTPROTO; pp = pp->nextportproto)
4822 	{
4823 		if ((pp->userbits&BODYONLY) != 0) continue;
4824 		character = pp->userbits & STATEBITS;
4825 
4826 		/* special detection for power and ground ports */
4827 		if (portispower(pp) || portisground(pp)) character = GNDPORT;
4828 
4829 		/* make a count of the types of ports and save it on the ports */
4830 		switch (character)
4831 		{
4832 			case OUTPORT:
4833 				pp->temp1 = outputside++;
4834 				break;
4835 			case BIDIRPORT:
4836 				pp->temp1 = bidirside++;
4837 				break;
4838 			case PWRPORT:
4839 			case GNDPORT:
4840 				pp->temp1 = topside++;
4841 				break;
4842 			default:		/* INPORT, unlabeled, and all CLOCK ports */
4843 				pp->temp1 = inputside++;
4844 				break;
4845 		}
4846 	}
4847 
4848 	/* create the Black Box with the correct size */
4849 	ysize = maxi(maxi(inputside, outputside), 5) * 2 * lambda;
4850 	xsize = maxi(maxi(topside, bidirside), 3) * 2 * lambda;
4851 
4852 	/* create the Black Box instance */
4853 	bbni = newnodeinst(bbproto, 0, xsize, 0, ysize, 0, 0, np);
4854 	if (bbni == NONODEINST) return(NONODEPROTO);
4855 
4856 	/* put the original cell name on the Black Box */
4857 	var = setval((INTBIG)bbni, VNODEINST, x_("SCHEM_function"), (INTBIG)iconname, VSTRING|VDISPLAY);
4858 	if (var != NOVARIABLE) defaulttextdescript(var->textdescript, bbni->geom);
4859 
4860 	/* place pins around the Black Box */
4861 	for(pp = fpp; pp != NOPORTPROTO; pp = pp->nextportproto)
4862 	{
4863 		if ((pp->userbits&BODYONLY) != 0) continue;
4864 		character = pp->userbits & STATEBITS;
4865 
4866 		/* special detection for power and ground ports */
4867 		if (portispower(pp) || portisground(pp)) character = GNDPORT;
4868 
4869 		/* make a count of the types of ports and save it on the ports */
4870 		switch (character)
4871 		{
4872 			case OUTPORT:
4873 				xpos = xsize + 2 * lambda;
4874 				xbbpos = xsize;
4875 				eindex = pp->temp1;
4876 				spacing = 2 * lambda;
4877 				if (outputside*2 < inputside) spacing = 4 * lambda;
4878 				ybbpos = ypos = ysize - ((ysize - (outputside-1)*spacing) / 2 + eindex * spacing);
4879 				whichport = outputport;
4880 				break;
4881 			case BIDIRPORT:
4882 				eindex = pp->temp1;
4883 				spacing = 2 * lambda;
4884 				if (bidirside*2 < topside) spacing = 4 * lambda;
4885 				xbbpos = xpos = xsize - ((xsize - (bidirside-1)*spacing) / 2 + eindex * spacing);
4886 				ypos = -2 * lambda;
4887 				ybbpos = 0;
4888 				whichport = bidirport;
4889 				break;
4890 			case PWRPORT:
4891 			case GNDPORT:
4892 				eindex = pp->temp1;
4893 				spacing = 2 * lambda;
4894 				if (topside*2 < bidirside) spacing = 4 * lambda;
4895 				xbbpos = xpos = xsize - ((xsize - (topside-1)*spacing) / 2 + eindex * spacing);
4896 				ypos = ysize + 2 * lambda;
4897 				ybbpos = ysize;
4898 				whichport = topport;
4899 				break;
4900 			default:		/* INPORT, unlabeled, and all CLOCK ports */
4901 				xpos = -2 * lambda;
4902 				xbbpos = 0;
4903 				eindex = pp->temp1;
4904 				spacing = 2 * lambda;
4905 				if (inputside*2 < outputside) spacing = 4 * lambda;
4906 				ybbpos = ypos = ysize - ((ysize - (inputside-1)*spacing) / 2 + eindex * spacing);
4907 				whichport = inputport;
4908 				break;
4909 		}
4910 
4911 		/* determine type of pin */
4912 		pintype = pinproto;
4913 		wiretype = wireproto;
4914 		if (pp->subnodeinst != NONODEINST)
4915 		{
4916 			bpp = pp;
4917 			while (bpp->subnodeinst->proto->primindex == 0) bpp = bpp->subportproto;
4918 			if (bpp->subnodeinst->proto == buspproto)
4919 			{
4920 				pintype = buspproto;
4921 				wiretype = busproto;
4922 			}
4923 		}
4924 
4925 		/* create the pin */
4926 		pinni = io_edifiplacepin(pintype, xpos, xpos, ypos, ypos, 0, 0, np);
4927 		if (pinni == NONODEINST) return(NONODEPROTO);
4928 
4929 		/* export the port that should be on this pin */
4930 		port = newportproto(np, pinni, pintype->firstportproto, pp->protoname);
4931 		if (port != NOPORTPROTO)
4932 			port->userbits = pp->userbits | PORTDRAWN;
4933 
4934 		/* wire this pin to the black box */
4935 		(void)newarcinst(wiretype, defaultarcwidth(wiretype),
4936 			us_makearcuserbits(wiretype), pinni, pintype->firstportproto,
4937 			xpos, ypos, bbni, whichport, xbbpos, ybbpos, np);
4938 	}
4939 	return(np);
4940 }
4941 
4942 void io_ednamearc(ARCINST *ai)
4943 {
4944 	int Ix, Iy;
4945 	REGISTER VARIABLE *var;
4946 	CHAR *name, basename[WORD+1] ;
4947 
4948 	if (io_edifgbl.isarray)
4949 	{
4950 		/* name the bus */
4951 		if (io_edifgbl.net_reference)
4952 		{
4953 			(void)setvalkey((INTBIG)ai, VARCINST, EDIF_name_key,
4954 				(INTBIG)io_edifgbl.net_reference, VSTRING);
4955 		}
4956 
4957 		/* a typical foreign array bus will have some range value appended
4958 		 * to the name. This will cause some odd names with duplicate values
4959 		 */
4960 		name = basename;
4961 		*name = 0;
4962 		for (Ix = 0; Ix < io_edifgbl.arrayx; Ix++)
4963 		{
4964 			for (Iy = 0; Iy < io_edifgbl.arrayy; Iy++)
4965 			{
4966 				if (name != basename) *name++ = ',';
4967 				if (io_edifgbl.arrayx > 1)
4968 				{
4969 					if (io_edifgbl.arrayy > 1)
4970 						(void)esnprintf(name, WORD, x_("%s[%d,%d]"), io_edifgbl.net_name, Ix, Iy);
4971 					else
4972 						(void)esnprintf(name, WORD, x_("%s[%d]"), io_edifgbl.net_name, Ix);
4973 				}
4974 				else (void)esnprintf(name, WORD, x_("%s[%d]"), io_edifgbl.net_name, Iy);
4975 				name += estrlen(name);
4976 			}
4977 		}
4978 		var = setvalkey((INTBIG)ai, VARCINST, el_arc_name_key, (INTBIG)basename, VSTRING);
4979 		if (var != NOVARIABLE)
4980 			defaulttextsize(4, var->textdescript);
4981 	} else
4982 	{
4983 		if (io_edifgbl.net_reference)
4984 		{
4985 			(void)setvalkey((INTBIG)ai, VARCINST, EDIF_name_key,
4986 				(INTBIG)io_edifgbl.net_reference, VSTRING);
4987 		}
4988 		if (io_edifgbl.net_name)
4989 		{
4990 			/* set name of arc but don't display name */
4991 			var = setvalkey((INTBIG)ai, VARCINST, el_arc_name_key,
4992 				(INTBIG)io_edifgbl.net_name, VSTRING);
4993 			if (var != NOVARIABLE)
4994 				defaulttextsize(4, var->textdescript);
4995 		}
4996 	}
4997 }
4998 
4999 INTBIG io_edfindport(NODEPROTO *cell, INTBIG x, INTBIG y, ARCPROTO *ap, NODEINST *nis[],
5000 	PORTPROTO *pps[])
5001 {
5002 	INTBIG cnt;
5003 	ARCINST *ai = NOARCINST, *ar1,*ar2;
5004 	ARCPROTO *nap;
5005 	NODEINST *ni, *fno, *tno;
5006 	PORTPROTO *fpt, *tpt, *pp;
5007 	NODEPROTO *np, *pnt;
5008 	INTBIG wid, bits1, bits2, lx, hx, ly, hy, j;
5009 	INTBIG fendx, fendy, tendx, tendy;
5010 
5011 	cnt = io_edfindport_geom(cell, x, y, ap, nis, pps, &ai);
5012 
5013 	if (cnt == 0 && ai != NOARCINST)
5014 	{
5015 		/* direct hit on an arc, verify connection */
5016 		nap = ai->proto;
5017 		np = getpinproto(nap);
5018 		if (np == NONODEPROTO) return(0);
5019 		pp = np->firstportproto;
5020 		for (j = 0; pp->connects[j] != NOARCPROTO; j++)
5021 			if (pp->connects[j] == ap) break;
5022 		if (pp->connects[j] == NOARCPROTO) return(0);
5023 
5024 		/* try to split arc (from us_getnodeonarcinst)*/
5025 		/* break is at (prefx, prefy): save information about the arcinst */
5026 		fno = ai->end[0].nodeinst;	fpt = ai->end[0].portarcinst->proto;
5027 		tno = ai->end[1].nodeinst;	tpt = ai->end[1].portarcinst->proto;
5028 		fendx = ai->end[0].xpos;	  fendy = ai->end[0].ypos;
5029 		tendx = ai->end[1].xpos;	  tendy = ai->end[1].ypos;
5030 		wid = ai->width;  pnt = ai->parent;
5031 		bits1 = bits2 = ai->userbits;
5032 		if ((bits1&ISNEGATED) != 0)
5033 		{
5034 			if ((bits1&REVERSEEND) == 0) bits2 &= ~ISNEGATED; else
5035 				bits1 &= ~ISNEGATED;
5036 		}
5037 		if (figureangle(fendx,fendy, x,y) != figureangle(x,y, tendx, tendy))
5038 		{
5039 			bits1 &= ~FIXANG;
5040 			bits2 &= ~FIXANG;
5041 		}
5042 
5043 		/* create the splitting pin */
5044 		lx = x - (np->highx-np->lowx)/2;   hx = lx + np->highx-np->lowx;
5045 		ly = y - (np->highy-np->lowy)/2;   hy = ly + np->highy-np->lowy;
5046 		ni = io_edifiplacepin(np, lx,hx, ly,hy, 0, 0, pnt);
5047 		if (ni == NONODEINST)
5048 		{
5049 			ttyputerr(_("Cannot create splitting pin"));
5050 			return(0);
5051 		}
5052 		endobjectchange((INTBIG)ni, VNODEINST);
5053 
5054 		/* set the node, and port */
5055 		nis[cnt] = ni;
5056 		pps[cnt++] = pp;
5057 
5058 		/* create the two new arcinsts */
5059 		ar1 = newarcinst(nap, wid, bits1, fno, fpt, fendx, fendy, ni, pp, x, y, pnt);
5060 		ar2 = newarcinst(nap, wid, bits2, ni, pp, x, y, tno, tpt, tendx, tendy, pnt);
5061 		if (ar1 == NOARCINST || ar2 == NOARCINST)
5062 		{
5063 			ttyputerr(_("Error creating the split arc parts"));
5064 			return(cnt);
5065 		}
5066 		(void)copyvars((INTBIG)ai, VARCINST, (INTBIG)ar1, VARCINST, FALSE);
5067 		endobjectchange((INTBIG)ar1, VARCINST);
5068 		endobjectchange((INTBIG)ar2, VARCINST);
5069 
5070 		/* delete the old arcinst */
5071 		startobjectchange((INTBIG)ai, VARCINST);
5072 		if (killarcinst(ai))
5073 			ttyputerr(_("Error deleting original arc"));
5074 	}
5075 
5076 	return(cnt);
5077 }
5078 
5079 /* module: ro_mazefindport
5080    function: will locate the nodeinstance and portproto corresponding to
5081    to a direct intersection with the given point.
5082    inputs:
5083    cell - cell to search
5084    x, y  - the point to exam
5085    ap    - the arc used to connect port (must match pp)
5086    nis   - pointer to ni pointer buffer.
5087    pps   - pointer to portproto pointer buffer.
5088    outputs:
5089    returns cnt if found, 0 not found, -1 on error
5090    ni = found ni instance
5091    pp = found pp proto.
5092  */
5093 INTBIG io_edfindport_geom(NODEPROTO *cell, INTBIG x, INTBIG y, ARCPROTO *ap,
5094 	NODEINST *nis[], PORTPROTO *pps[], ARCINST **ai)
5095 {
5096 	REGISTER INTBIG j, cnt, sea, dist, bestdist, bestpx, bestpy, bits, wid,
5097 		lx, hx, ly, hy, xs, ys;
5098 	INTBIG px, py;
5099 	REGISTER GEOM *geom;
5100 	REGISTER ARCINST *newai;
5101 	static POLYGON *poly = NOPOLYGON;
5102 	REGISTER PORTPROTO *pp, *bestpp;
5103 	REGISTER NODEINST *ni, *bestni;
5104 	NODEPROTO *np;
5105 
5106 	(void)needstaticpolygon(&poly, 4, io_tool->cluster);
5107 
5108 	cnt = 0;
5109 	bestni = NONODEINST;
5110 	sea = initsearch(x, x, y, y, cell);
5111 	for(;;)
5112 	{
5113 		geom = nextobject(sea);
5114 		if (geom == NOGEOM) break;
5115 
5116 		switch (geom->entryisnode)
5117 		{
5118 			case TRUE:
5119 				/* now locate a portproto */
5120 				ni = geom->entryaddr.ni;
5121 				for (pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
5122 				{
5123 					shapeportpoly(ni, pp, poly, FALSE);
5124 					if (isinside(x, y, poly))
5125 					{
5126 						/* check if port connects to arc ...*/
5127 						for (j = 0; pp->connects[j] != NOARCPROTO; j++)
5128 							if (pp->connects[j] == ap)
5129 						{
5130 							nis[cnt] = ni;
5131 							pps[cnt] = pp;
5132 							cnt++;
5133 						}
5134 					} else
5135 					{
5136 						portposition(ni, pp, &px, &py);
5137 						dist = computedistance(x, y, px, py);
5138 						if (bestni == NONODEINST || dist < bestdist)
5139 						{
5140 							bestni = ni;
5141 							bestpp = pp;
5142 							bestdist = dist;
5143 							bestpx = px;
5144 							bestpy = py;
5145 						}
5146 					}
5147 				}
5148 				break;
5149 
5150 			case FALSE:
5151 				/* only accept valid wires */
5152 				if (geom->entryaddr.ai->proto->tech == sch_tech)
5153 					*ai = geom->entryaddr.ai;
5154 				break;
5155 		}
5156 	}
5157 
5158 	/* special case: make it connect to anything that is near */
5159 	if (cnt == 0 && bestni != NONODEINST)
5160 	{
5161 		/* create a new node in the proper position */
5162 		np = getpinproto(ap);
5163 		xs = np->highx - np->lowx;   lx = x - xs/2;   hx = lx + xs;
5164 		ys = np->highy - np->lowy;   ly = y - ys/2;   hy = ly + ys;
5165 		ni = io_edifiplacepin(np, lx, hx, ly, hy, 0, 0, cell);
5166 		wid = ap->nominalwidth;
5167 		bits = us_makearcuserbits(ap);
5168 		newai = newarcinst(ap, wid, bits, ni, ni->proto->firstportproto, x, y, bestni, bestpp, bestpx, bestpy, cell);
5169 		nis[cnt] = ni;
5170 		pps[cnt] = ni->proto->firstportproto;
5171 		cnt++;
5172 	}
5173 	return(cnt);
5174 }
5175 
5176 
5177 NODEINST *io_edifiplacepin(NODEPROTO *np, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy,
5178 	INTBIG trans, INTBIG angle, NODEPROTO *parent)
5179 {
5180 	REGISTER NODEINST *ni;
5181 	REGISTER INTBIG cx, cy, sx, sy, icx, icy, isx, isy;
5182 
5183 	cx = (lx + hx) / 2;
5184 	cy = (ly + hy) / 2;
5185 	sx = hx - lx;
5186 	sy = hy - ly;
5187 
5188 	for(ni = parent->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
5189 	{
5190 		if (ni->proto != np) continue;
5191 		if (ni->rotation != angle || ni->transpose != trans) continue;
5192 		icx = (ni->lowx + ni->highx) / 2;
5193 		icy = (ni->lowy + ni->highy) / 2;
5194 		isx = ni->highx - ni->lowx;
5195 		isy = ni->highy - ni->lowy;
5196 		if (icx != cx || icy != cy) continue;
5197 		return(ni);
5198 	}
5199 	ni = newnodeinst(np, lx, hx, ly, hy, trans, angle, parent);
5200 	return(ni);
5201 }
5202 
5203