1 /***************************************************************************
2 SCED - Schematic Capture Editor
3 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
4 Copyright 1990 Regents of the University of California.  All rights reserved.
5 Authors: 1981 Giles C. Billingsley  (parts of KIC layout editor)
6          1992 Stephen R. Whiteley
7 ****************************************************************************/
8 
9 /*
10  * SCED displayable object management code.
11  */
12 
13 #include "spice.h"
14 #include "sced.h"
15 #include "scedmacs.h"
16 
17 
18 
19 /***********************************************************************
20  *
21  * Routine for deleting objects.
22  *
23  *
24  ***********************************************************************/
25 
26 extern char *MenuDELET;
27 extern char *MenuUNDO;
28 #ifdef __STDC__
29 static void do_del(int,struct ka*);
30 #else
31 static void do_del();
32 #endif
33 
34 
35 void
Del(LookedAhead)36 Del(LookedAhead)
37 
38 int *LookedAhead;
39 {
40     struct ks *SQDesc;
41     int Info = SQ_GONE;
42 
43     MenuSelect(MenuDELET);
44     if (SelectQHead == NULL) {
45         ShowPrompt("There are no selected objects to delete.");
46         MenuDeselect(MenuDELET);
47         return;
48     }
49     SQComputeBB();
50     /* take care of instance markers */
51     SelectQBB.kaRight  += 600;
52     SelectQBB.kaLeft   -= 600;
53     SelectQBB.kaTop    += 600;
54     SelectQBB.kaBottom -= 600;
55 
56     do_del(SQ_GONE,&SelectQBB);
57     MenuDeselect(MenuDELET);
58 
59 top:
60     switch (PointLoop(LookedAhead)) {
61         case PL_UND:
62             MenuSelect(MenuUNDO);
63             if (Info == SQ_GONE) Info = SQ_OLDSEL;
64             else Info = SQ_GONE;
65             do_del(Info,&SelectQBB);
66             MenuDeselect(MenuUNDO);
67         case PL_ESC:
68         case PL_PCW:
69             goto top;
70         case PL_CMD:
71             break;
72     }
73     if (Info == SQ_GONE) {
74         for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
75             CDDelete(Parameters.kpCellDesc,SQDesc->ksPointer);
76         }
77         SQClear();
78         SelectQBB.kaLeft = SelectQBB.kaBottom =
79             SelectQBB.kaRight = SelectQBB.kaTop = 0;
80         Parameters.kpModified = True;
81     }
82     else
83         SQComputeBB();
84 }
85 
86 
87 static void
do_del(Info,BB)88 do_del(Info,BB)
89 
90 int Info;
91 struct ka *BB;
92 {
93     struct ks *SQDesc;
94     /*
95      * Change Info field and redisplay.
96      */
97     for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc)
98         SQDesc->ksPointer->oInfo = Info;
99 
100     EraseBox(BB);
101     Redisplay(BB);
102     DevUpdate();
103 }
104 
105 
106 
107 /***********************************************************************
108  *
109  * Routines for managing wires.
110  *
111  *
112  ***********************************************************************/
113 
114 extern char *MenuWIRES;
115 extern char *MenuUNDO;
116 #ifdef __STDC__
117 static void allocate_wire(int,struct p*,long,struct ka*,struct o**,int);
118 static void record_wire(struct o*);
119 static void zap_last_point(struct p**);
120 static void append_point(long,long,struct p**);
121 static void last_path_point(long*,long*,struct p*);
122 static struct p *allocate_path(long,long);
123 #else
124 static void allocate_wire();
125 static void record_wire();
126 static void zap_last_point();
127 static void append_point();
128 static void last_path_point();
129 static struct p *allocate_path();
130 #endif
131 
132 
133 void
Wires(LookedAhead)134 Wires(LookedAhead)
135 
136 /*  Wires command - create wires. */
137 int *LookedAhead;
138 {
139     struct p *Path;
140     struct ka BB,OldBB;
141     struct o *Pointer = NULL,*OldPointer = NULL;
142     long Width;
143     long X,Y,FX,FY;
144     int NumVertices = 0;
145     int ExpectFirstPoint = True;
146     int Modified = 0;
147     int Undo = False;
148 
149     MenuSelect(MenuWIRES);
150     Path = NULL;
151 
152     Width = 0;
153 
154     ShowPrompt("Point to reference points.");
155     loop {
156         switch (PointLoop(LookedAhead)) {
157             case PL_UND:
158                 MenuSelect(MenuUNDO);
159                 if (NumVertices == 0) {
160                     if (OldPointer == NULL) {
161                         MenuDeselect(MenuUNDO);
162                         goto quit;
163                     }
164                     if (Undo == False) {
165                         OldPointer->oInfo = SQ_GONE;
166                         Modified--;
167                         Undo = True;
168                     }
169                     else {
170                         OldPointer->oInfo = SQ_NEW;
171                         Modified++;
172                         Undo = False;
173                     }
174                     EraseBox(&OldBB);
175                     Redisplay(&OldBB);
176                     MenuDeselect(MenuUNDO);
177                     continue;
178                 }
179                 if (NumVertices > 1)
180                     zap_last_point(&Path);
181                 CDDelete(Parameters.kpCellDesc,Pointer);
182                 EraseBox(&BB);
183                 Redisplay(&BB);
184                 FBSetRubberBanding(0);
185                 if (NumVertices == 1) {
186                     ExpectFirstPoint = True;
187                 }
188                 else {
189                     long tmpX, tmpY;
190 
191                     allocate_wire(1,Path,Width,&BB,&Pointer,5);
192                     ShowWire(DrawingColor,Width,Path);
193                     last_path_point(&X,&Y,Path);
194                     tmpX = SCursor.kcX;
195                     tmpY = SCursor.kcY;
196                     SCursor.kcX = X;
197                     SCursor.kcY = Y;
198                     FBSetRubberBanding('l');
199                     SCursor.kcX = tmpX;
200                     SCursor.kcY = tmpY;
201                 }
202                 NumVertices--;
203                 MenuDeselect(MenuUNDO);
204                 continue;
205             case PL_ESC:
206                 if (Not ExpectFirstPoint) {
207                     CDDelete(Parameters.kpCellDesc,Pointer);
208                     Pointer = NULL;
209                     EraseBox(&BB);
210                     Redisplay(&BB);
211                 }
212                 goto quit;
213             case PL_CMD:
214                 if (Not ExpectFirstPoint) {
215                     if (NumVertices == 1) {
216                         CDDelete(Parameters.kpCellDesc,Pointer);
217                     }
218                     else {
219                         Modified++;
220                         record_wire(Pointer);
221                     }
222                     Pointer = NULL;
223                     EraseBox(&BB);
224                     Redisplay(&BB);
225                 }
226                 goto quit;
227         }
228         if (ExpectFirstPoint) {
229             NumVertices++;
230             ExpectFirstPoint = False;
231             FX = X = SCursor.kcX;
232             FY = Y = SCursor.kcY;
233             Path = allocate_path(X,Y);
234             allocate_wire(1,Path,Width,&BB,&Pointer,SQ_INCMPLT);
235             ShowWire(DrawingColor,Width,Path);
236             FBSetRubberBanding('l');
237             continue;
238         }
239         if (SCursor.kcX == X And SCursor.kcY == Y) {
240             if (NumVertices == 1) {
241                 /* click twice to exit */
242                 CDDelete(Parameters.kpCellDesc,Pointer);
243                 Pointer = NULL;
244                 goto quit;
245             }
246             else {
247                 Pointer->oInfo = SQ_NEW;
248                 record_wire(OldPointer);
249                 OldPointer = Pointer;
250                 Pointer = NULL;
251                 OldBB = BB;
252                 Modified++;
253                 FBSetRubberBanding(0);
254             }
255             NumVertices = 0;
256             ExpectFirstPoint = True;
257             EraseBox(&BB);
258             Redisplay(&BB);
259             Undo = False;
260         }
261         else {
262             X = SCursor.kcX;
263             Y = SCursor.kcY;
264             append_point(X,Y,&Path);
265             CDDelete(Parameters.kpCellDesc,Pointer);
266             allocate_wire(1,Path,Width,&BB,&Pointer,SQ_INCMPLT);
267             FBSetRubberBanding(0);
268             FBSetRubberBanding('l');
269             ShowWire(DrawingColor,Width,Path);
270             NumVertices++;
271         }
272     }
273 quit:
274     record_wire(OldPointer);
275     record_wire(Pointer);
276     if (Modified)
277         Parameters.kpModified = True;
278     ErasePrompt();
279     FBSetRubberBanding(0);
280     MenuDeselect(MenuWIRES);
281 }
282 
283 
284 /* ARGSUSED */
285 void
ShowWire(Color,Width,Path)286 ShowWire(Color,Width,Path)
287 
288 /* Display a wire. */
289 int Color;
290 long Width;
291 struct p *Path;
292 {
293     ShowPath(Color,Path,0);
294 }
295 
296 
297 int
IsManhattan(X1,Y1,X2,Y2)298 IsManhattan(X1,Y1,X2,Y2)
299 
300 /* return True if coordinates are Manhattan. */
301 long X1,Y1,X2,Y2;
302 {
303     if (X1 == X2 Or Y1 == Y2)
304         return (True);
305     else return (False);
306 }
307 
308 
309 static void
allocate_wire(Layer,Path,Width,BB,Pointer,Info)310 allocate_wire(Layer,Path,Width,BB,Pointer,Info)
311 
312 /* Create a new wire. */
313 int Layer;
314 struct p *Path;
315 long Width;
316 struct ka *BB;
317 struct o **Pointer;
318 int Info;
319 {
320     if (Not CDMakeWire(Parameters.kpCellDesc,
321         Layer,Width,Path,Pointer)) MallocFailed();
322     (*Pointer)->oInfo = Info;
323     CDStatusInt = CDBB(Parameters.kpCellDesc,*Pointer,
324         &BB->kaLeft,&BB->kaBottom,&BB->kaRight,&BB->kaTop);
325     OversizeBox(BB,Width);
326 }
327 
328 
329 static void
record_wire(Pointer)330 record_wire(Pointer)
331 
332 /* Check the Info field, and delete if conditionally deleted.
333  * Otherwise set Info to SQ_OLD, and add default properties to wire.
334  */
335 struct o *Pointer;
336 {
337     int Info;
338 
339     if (Pointer == NULL) return;
340     if (Pointer->oInfo == SQ_GONE)
341         CDDelete(Parameters.kpCellDesc,Pointer);
342     else {
343         Pointer->oInfo = SQ_OLD;
344         if (Pointer->oPrptyList == NULL)
345             AssignWireProperties(Pointer);
346     }
347 }
348 
349 
350 static void
zap_last_point(Path)351 zap_last_point(Path)
352 
353 /* Create a new path with the last point removed.  Delete the old path. */
354 struct p **Path;
355 {
356     struct p *OldPair;
357     struct p *NewPair;
358 
359     OldPair = *Path;
360     if (OldPair == NULL Or OldPair->pSucc == NULL)
361         return;
362     if ((NewPair = alloc(p)) == NULL)
363         MallocFailed();
364     *Path = NewPair;
365     NewPair->pX = OldPair->pX;
366     NewPair->pY = OldPair->pY;
367     NewPair->pSucc = NULL;
368     OldPair = OldPair->pSucc;
369     while (OldPair->pSucc != NULL) {
370         if ((NewPair->pSucc = alloc(p)) == NULL)
371             MallocFailed();
372         NewPair = NewPair->pSucc;
373         NewPair->pX = OldPair->pX;
374         NewPair->pY = OldPair->pY;
375         NewPair->pSucc = NULL;
376         OldPair = OldPair->pSucc;
377     }
378 }
379 
380 
381 static void
append_point(X,Y,Path)382 append_point(X,Y,Path)
383 
384 /* Create a new path with an added point.  Delete the old path. */
385 struct p **Path;
386 long X,Y;
387 {
388     struct p *OldPair;
389     struct p *NewPair;
390 
391     if (Path == NULL || *Path == NULL)
392         return;
393     OldPair = *Path;
394     if ((NewPair = alloc(p)) == NULL)
395         MallocFailed();
396     *Path = NewPair;
397     NewPair->pX = OldPair->pX;
398     NewPair->pY = OldPair->pY;
399     NewPair->pSucc = NULL;
400     OldPair = OldPair->pSucc;
401     while (OldPair != NULL) {
402         if ((NewPair->pSucc = alloc(p)) == NULL)
403             MallocFailed();
404         NewPair = NewPair->pSucc;
405         NewPair->pX = OldPair->pX;
406         NewPair->pY = OldPair->pY;
407         NewPair->pSucc = NULL;
408         OldPair = OldPair->pSucc;
409     }
410     /* Append the new reference point */
411     if ((NewPair->pSucc = alloc(p)) == NULL)
412         MallocFailed();
413     NewPair = NewPair->pSucc;
414     NewPair->pX = X;
415     NewPair->pY = Y;
416     NewPair->pSucc = NULL;
417 }
418 
419 
420 static void
last_path_point(X,Y,Path)421 last_path_point(X,Y,Path)
422 
423 /* Return in pointers the last point in path. */
424 long *X,*Y;
425 struct p *Path;
426 {
427     struct p *p;
428 
429     for (p = Path; p && p->pSucc; p = p->pSucc) ;
430     if (p) {
431         *X = p->pX;
432         *Y = p->pY;
433     }
434 }
435 
436 
437 static struct p *
allocate_path(X,Y)438 allocate_path(X,Y)
439 
440 /* Allocate an element of a path list. */
441 long X,Y;
442 {
443     struct p *Path;
444 
445     if ((Path = alloc(p)) == NULL) MallocFailed();
446     Path->pX = X;
447     Path->pY = Y;
448     Path->pSucc = NULL;
449     return (Path);
450 }
451 
452 
453 /***********************************************************************
454  *
455  * Routines for rendering line paths and polygons.
456  *
457  *
458  ***********************************************************************/
459 
460 
461 void
ShowPath(Color,Path,Terminate)462 ShowPath(Color,Path,Terminate)
463 
464 /* display a line path. */
465 int Color;
466 struct p *Path;
467 int Terminate;     /* If True, the path is closed */
468 {
469     struct p *Pair;
470     long firstX,firstY,X,Y,lastX,lastY;
471 
472     Pair = Path;
473     firstX = lastX = Pair->pX;
474     firstY = lastY = Pair->pY;
475     Pair = Pair->pSucc;
476     while (Pair != NULL) {
477         X = Pair->pX;
478         Y = Pair->pY;
479         ShowLine(Color,lastX,lastY,X,Y);
480         lastX = X;
481         lastY = Y;
482         Pair = Pair->pSucc;
483     }
484     if (Terminate)
485         ShowLine(Color,firstX,firstY,lastX,lastY);
486 }
487 
488 
489 void
ShowPolygon(Color,Path)490 ShowPolygon(Color,Path)
491 
492 /* Display a polygon. */
493 int Color;
494 struct p *Path;
495 {
496     struct p *Pair;
497     struct ka Fw, Cw;
498     static long PolygonBuffer[POLYGONBUFSIZE];
499     char oldRedisplay;
500     int i,n,nfine,ncoarse,n2;
501     long X,Y;
502 
503 
504     if (Color == HighlightingColor) {
505         ShowPath(Color,Path,True);
506         return;
507     }
508 
509     for (n = 0,Pair = Path; Pair != NULL; n++,Pair = Pair->pSucc) ;
510     n = Min(MAXPOLYGONVERTICES,n);
511     n2 = n << 1;
512     ncoarse = nfine = n;
513 
514     if (Parameters.kpRedisplayControl != FINEVIEWPORTONLY And
515         CurrentAOI.aInCoarse) {
516 
517         for (i = 0,Pair = Path; i < n2; i += 2,Pair = Pair->pSucc) {
518             X = Pair->pX;
519             Y = Pair->pY;
520             TPoint(&X,&Y);
521             CoarseLToP(X,Y,PolygonBuffer[i],PolygonBuffer[i+1]);
522         }
523 
524         FBPolygonClip(PolygonBuffer,&ncoarse,(struct ka*)&CurrentAOI.aLC);
525         FBPolygon(Color,FILL,PolygonBuffer,ncoarse);
526     }
527 
528     if (Parameters.kpRedisplayControl != COARSEVIEWPORTONLY And
529         CurrentAOI.aInFine) {
530 
531         for (i = 0,Pair = Path; i < n2; i += 2,Pair = Pair->pSucc) {
532             X = Pair->pX;
533             Y = Pair->pY;
534             TPoint(&X,&Y);
535             FineLToP(X,Y,PolygonBuffer[i],PolygonBuffer[i+1]);
536         }
537 
538         FBPolygonClip(PolygonBuffer,&nfine,(struct ka*)&CurrentAOI.aLF);
539         FBPolygon(Color,FILL,PolygonBuffer,nfine);
540     }
541 
542 }
543 
544 
545 /***********************************************************************
546  *
547  * Routines for managing rectangles.
548  *
549  *
550  ***********************************************************************/
551 
552 #define ka_copy(BB1,BB2) BB1.kaLeft = BB2->kaLeft; \
553     BB1.kaRight = BB2->kaRight; \
554     BB1.kaBottom = BB2->kaBottom; \
555     BB1.kaTop = BB2->kaTop; \
556     TPoint(&BB1.kaLeft,&BB1.kaBottom); \
557     TPoint(&BB1.kaRight,&BB1.kaTop); \
558     if (BB1.kaLeft > BB1.kaRight) \
559         SwapInts(BB1.kaLeft,BB1.kaRight); \
560     if (BB1.kaBottom > BB1.kaTop) \
561         SwapInts(BB1.kaBottom,BB1.kaTop);
562 
563 
564 int
InBox(X,Y,AOI)565 InBox(X,Y,AOI)
566 
567 /* return True if X,Y in AOI */
568 long X,Y;
569 struct ka *AOI;
570 {
571     if (((AOI->kaLeft <= X And X <= AOI->kaRight) Or
572         (AOI->kaRight <= X And X <= AOI->kaLeft)) And
573         ((AOI->kaBottom <= Y And Y <= AOI->kaTop) Or
574         (AOI->kaTop <= Y And Y <= AOI->kaBottom)))
575         return (True);
576     return (False);
577 }
578 
579 
580 void
OversizeBox(BB,Delta)581 OversizeBox(BB,Delta)
582 
583 /* expand BB by Delta */
584 struct ka *BB;
585 int Delta;
586 {
587     BB->kaTop += Delta;
588     BB->kaRight += Delta;
589     BB->kaBottom -= Delta;
590     BB->kaLeft -= Delta;
591 }
592 
593 
594 void
OutlineBox(AOI)595 OutlineBox(AOI)
596 
597 /* Draw a line box. AOI is pixel coordinates. */
598 struct ka *AOI;
599 {
600     int x1,y1,x2,y2;
601     x1 = AOI->kaLeft;
602     y1 = AOI->kaBottom;
603     x2 = AOI->kaRight;
604     y2 = AOI->kaTop;
605     DevLine(x1,y1,x2,y1);
606     DevLine(x2,y1,x2,y2);
607     DevLine(x2,y2,x1,y2);
608     DevLine(x1,y2,x1,y1);
609 }
610 
611 
612 void
ShowEmptyBox(Color,boxBB)613 ShowEmptyBox(Color,boxBB)
614 
615 /* Draw a line box (window coordinates). */
616 int Color;
617 struct ka *boxBB;
618 {
619     struct ka BB,BB1;
620     int ShowLeft   = True;
621     int ShowBottom = True;
622     int ShowRight  = True;
623     int ShowTop    = True;
624 
625     ka_copy(BB,boxBB);
626 
627     if (Parameters.kpRedisplayControl != FINEVIEWPORTONLY And
628         CurrentAOI.aInCoarse) {
629 
630         CoarseLToP(BB.kaLeft,BB.kaBottom,BB1.kaLeft,BB1.kaBottom);
631         CoarseLToP(BB.kaRight,BB.kaTop,BB1.kaRight,BB1.kaTop);
632 
633         if (BB1.kaLeft <= CurrentAOI.aRC And BB1.kaRight >= CurrentAOI.aLC And
634             BB1.kaBottom <= CurrentAOI.aTC And BB1.kaTop >= CurrentAOI.aBC) {
635 
636             if (BB1.kaLeft < CurrentAOI.aLC) {
637                 BB1.kaLeft = CurrentAOI.aLC;
638                 ShowLeft = False;
639             }
640             if (BB1.kaBottom < CurrentAOI.aBC) {
641                 BB1.kaBottom = CurrentAOI.aBC;
642                 ShowBottom = False;
643             }
644             if (BB1.kaRight > CurrentAOI.aRC) {
645                 BB1.kaRight = CurrentAOI.aRC;
646                 ShowRight = False;
647             }
648             if (BB1.kaTop > CurrentAOI.aTC) {
649                 BB1.kaTop = CurrentAOI.aTC;
650                 ShowTop = False;
651             }
652             DevSetColor(Color);
653 
654             if (ShowTop)
655                 DevLine((int)BB1.kaLeft,(int)BB1.kaTop,
656                     (int)BB1.kaRight,(int)BB1.kaTop);
657             if (ShowRight)
658                 DevLine((int)BB1.kaRight,(int)BB1.kaTop,
659                     (int)BB1.kaRight,(int)BB1.kaBottom);
660             if (ShowBottom)
661                 DevLine((int)BB1.kaRight,(int)BB1.kaBottom,
662                     (int)BB1.kaLeft,(int)BB1.kaBottom);
663             if (ShowLeft)
664                 DevLine((int)BB1.kaLeft,(int)BB1.kaBottom,
665                     (int)BB1.kaLeft,(int)BB1.kaTop);
666         }
667     }
668 
669     ShowLeft   = True;
670     ShowBottom = True;
671     ShowRight  = True;
672     ShowTop    = True;
673 
674     if (Parameters.kpRedisplayControl != COARSEVIEWPORTONLY And
675         CurrentAOI.aInFine) {
676 
677         FineLToP(BB.kaLeft,BB.kaBottom,BB1.kaLeft,BB1.kaBottom);
678         FineLToP(BB.kaRight,BB.kaTop,BB1.kaRight,BB1.kaTop);
679 
680         if (BB1.kaLeft <= CurrentAOI.aRF And BB1.kaRight >= CurrentAOI.aLF And
681             BB1.kaBottom <= CurrentAOI.aTF And BB1.kaTop >= CurrentAOI.aBF) {
682 
683             if (BB1.kaLeft < CurrentAOI.aLF) {
684                 BB1.kaLeft = CurrentAOI.aLF;
685                 ShowLeft = False;
686             }
687             if (BB1.kaBottom < CurrentAOI.aBF) {
688                 BB1.kaBottom = CurrentAOI.aBF;
689                 ShowBottom = False;
690             }
691             if (BB1.kaRight > CurrentAOI.aRF) {
692                 BB1.kaRight = CurrentAOI.aRF;
693                 ShowRight = False;
694             }
695             if (BB1.kaTop > CurrentAOI.aTF) {
696                 BB1.kaTop = CurrentAOI.aTF;
697                 ShowTop = False;
698             }
699             DevSetColor(Color);
700 
701             if (ShowTop)
702                 DevLine((int)BB1.kaLeft,(int)BB1.kaTop,
703                     (int)BB1.kaRight,(int)BB1.kaTop);
704             if (ShowRight)
705                 DevLine((int)BB1.kaRight,(int)BB1.kaTop,
706                     (int)BB1.kaRight,(int)BB1.kaBottom);
707             if (ShowBottom)
708                 DevLine((int)BB1.kaRight,(int)BB1.kaBottom,
709                     (int)BB1.kaLeft,(int)BB1.kaBottom);
710             if (ShowLeft)
711                 DevLine((int)BB1.kaLeft,(int)BB1.kaBottom,
712                     (int)BB1.kaLeft,(int)BB1.kaTop);
713         }
714     }
715 }
716 
717 
718 void
EraseBox(boxBB)719 EraseBox(boxBB)
720 
721 /* Erase area in boxBB (window coordinates). */
722 struct ka *boxBB;
723 {
724     struct ka BB,BB1;
725 
726     SetCurrentAOI(boxBB);
727     ka_copy(BB,boxBB);
728 
729     if (Parameters.kpRedisplayControl != FINEVIEWPORTONLY And
730         CurrentAOI.aInCoarse) {
731 
732         CoarseLToP(BB.kaLeft,BB.kaBottom,BB1.kaLeft,BB1.kaBottom);
733         CoarseLToP(BB.kaRight,BB.kaTop,BB1.kaRight,BB1.kaTop);
734 
735         if (BB1.kaLeft <= CurrentAOI.aRC And BB1.kaRight >= CurrentAOI.aLC And
736             BB1.kaBottom <= CurrentAOI.aTC And BB1.kaTop >= CurrentAOI.aBC) {
737 
738             if (BB1.kaLeft < CurrentAOI.aLC)
739                 BB1.kaLeft = CurrentAOI.aLC;
740             if (BB1.kaBottom < CurrentAOI.aBC)
741                 BB1.kaBottom = CurrentAOI.aBC;
742             if (BB1.kaRight > CurrentAOI.aRC)
743                 BB1.kaRight = CurrentAOI.aRC;
744             if (BB1.kaTop > CurrentAOI.aTC)
745                 BB1.kaTop = CurrentAOI.aTC;
746             FBEraseBox(BB1.kaLeft,BB1.kaBottom,
747                 BB1.kaRight,BB1.kaTop);
748         }
749     }
750 
751     if (Parameters.kpRedisplayControl != COARSEVIEWPORTONLY And
752         CurrentAOI.aInFine) {
753 
754         FineLToP(BB.kaLeft,BB.kaBottom,BB1.kaLeft,BB1.kaBottom);
755         FineLToP(BB.kaRight,BB.kaTop,BB1.kaRight,BB1.kaTop);
756 
757         if (BB1.kaLeft <= CurrentAOI.aRF And BB1.kaRight >= CurrentAOI.aLF And
758             BB1.kaBottom <= CurrentAOI.aTF And BB1.kaTop >= CurrentAOI.aBF) {
759 
760             if (BB1.kaLeft < CurrentAOI.aLF)
761                 BB1.kaLeft = CurrentAOI.aLF;
762             if (BB1.kaBottom < CurrentAOI.aBF)
763                 BB1.kaBottom = CurrentAOI.aBF;
764             if (BB1.kaRight > CurrentAOI.aRF)
765                 BB1.kaRight = CurrentAOI.aRF;
766             if (BB1.kaTop > CurrentAOI.aTF)
767                 BB1.kaTop = CurrentAOI.aTF;
768             FBEraseBox(BB1.kaLeft,BB1.kaBottom,
769                 BB1.kaRight,BB1.kaTop);
770         }
771     }
772 }
773 
774 
775 /***********************************************************************
776  *
777  * Strch command.
778  * Move wire vertices around.
779  *
780  ***********************************************************************/
781 
782 extern char *MenuSTRCH;
783 extern char *MenuUNDO;
784 #ifdef __STDC__
785 static void restore_stretch(void);
786 static void do_stretch_path(long,long,long,long,struct ka*,int);
787 static struct p *get_nearest_vertex(struct p*,long,long);
788 static void set_ref_to_vertex(long*,long*);
789 #else
790 static void restore_stretch();
791 static void do_stretch_path();
792 static struct p *get_nearest_vertex();
793 static void set_ref_to_vertex();
794 #endif
795 
796 
797 void
StretchPath(LookedAhead)798 StretchPath(LookedAhead)
799 
800 /* Strch command, move vertices. */
801 int *LookedAhead;
802 {
803     struct ka NBB,OBB;
804     long RefX,RefY,LastRefX,LastRefY,MapX,MapY;
805     long RefTmpX, RefTmpY;
806     int FirstTime = True;
807     int GotOne = False;
808     int Undo = False;
809     int Modified = 0;
810     int Pt;
811     char Types[2];
812 
813     MenuSelect(MenuSTRCH);
814 
815     Types[0] = CDWIRE;
816     Types[1] = '\0';
817 
818     if (AreTypesInQ(Types))
819         GotOne = True;
820 
821     loop {
822 top:
823         if (Not GotOne) {
824             ShowPrompt("Point at wire to stretch");
825 
826             switch (PointLoop(LookedAhead)) {
827                 case PL_ESC:
828                 case PL_CMD:
829                     goto quit;
830                 case PL_UND:
831                     if (FirstTime) goto quit;
832                     if (Undo  == False) {
833                         MenuSelect(MenuUNDO);
834                         if (Parameters.kpShowTerminals)
835                             DisplayTerminals(ERASE);
836                         UndoReferenceTransform();
837                         HYundoTransform();
838                         SQRestore(True);
839                         /* restored objects have Info = SQ_NEWSEL */
840                         Modified--;
841                         Undo = True;
842                         NBB = OBB;
843                         EraseBox(&OBB);
844                         Redisplay(&OBB);
845                         if (Parameters.kpShowTerminals)
846                             DisplayTerminals(DISPLAY);
847                         MenuDeselect(MenuUNDO);
848                         break;
849                     }
850                     else {
851                         if (Parameters.kpShowTerminals)
852                             DisplayTerminals(ERASE);
853                         /* should have only Info = SQ_NEW objects here */
854                         do_stretch_path(RefX,RefY,MapX,MapY,&NBB,False);
855                         Modified++;
856                         EraseBox(&NBB);
857                         Redisplay(&NBB);
858                         if (Parameters.kpShowTerminals)
859                             DisplayTerminals(DISPLAY);
860                         Undo = False;
861                         MenuDeselect(MenuUNDO);
862                         continue;
863                     }
864                 case PL_PCW:
865                     SelectTypes(Types);
866                     if (Not AreTypesInQ(Types))
867                         goto top;
868                     SQComputeBB();
869                     NBB = SelectQBB;
870             }
871         }
872 
873 next:
874         ShowPrompt("Point to the vertex.");
875 
876         switch (PointLoop(LookedAhead)) {
877             case PL_ESC:
878             case PL_CMD:
879                 goto quit;
880             case PL_UND:
881                 MenuSelect(MenuUNDO);
882                 if (Not GotOne)
883                      SQDesel(Types);
884                     /* newly selected objects deleted, restored objects
885                      * have Info = SQ_NEW.
886                      */
887                 else {
888                     if (FirstTime) {
889                         MenuDeselect(MenuUNDO);
890                         goto quit;
891                     }
892                     if (Undo == False) {
893                         if (Parameters.kpShowTerminals)
894                             DisplayTerminals(ERASE);
895                         UndoReferenceTransform();
896                         HYundoTransform();
897                         SQRestore(True);
898                         /* restored objects have Info = SQ_NEWSEL */
899                         Modified--;
900                         Undo = True;
901                     }
902                     else {
903                         if (Parameters.kpShowTerminals)
904                             DisplayTerminals(ERASE);
905                         /* should have only Info = SQ_NEWSEL objects here */
906                         do_stretch_path(RefX,RefY,MapX,MapY,&NBB,True);
907                         Modified++;
908                         Undo = False;
909                     }
910                 }
911                 EraseBox(&NBB);
912                 Redisplay(&NBB);
913                 if (GotOne && Parameters.kpShowTerminals)
914                     DisplayTerminals(DISPLAY);
915                 MenuDeselect(MenuUNDO);
916                 goto top;
917         }
918 
919         LastRefX = RefX;
920         LastRefY = RefY;
921         RefX = SCursor.kcX;
922         RefY = SCursor.kcY;
923         set_ref_to_vertex(&RefX,&RefY);
924         ShowPrompt("Point to where it should stretch.");
925 
926         RefTmpX = SCursor.kcX;
927         RefTmpY = SCursor.kcY;
928         SCursor.kcX = RefX;
929         SCursor.kcY = RefY;
930         restore_stretch();
931         FBSetRubberBanding('s');
932         SCursor.kcX = RefTmpX;
933         SCursor.kcY = RefTmpY;
934         Pt = PointLoop(LookedAhead);
935         FBSetRubberBanding(0);
936 
937         switch (Pt) {
938             case PL_ESC:
939             case PL_CMD:
940                 goto quit;
941             case PL_UND:
942                 MenuSelect(MenuUNDO);
943                 RefX = LastRefX;
944                 RefY = LastRefY;
945                 MenuDeselect(MenuUNDO);
946                 goto next;
947         }
948 
949         SQRestore(False);
950         /* should have only Info = SQ_OLDSEL objects here */
951         FirstTime = False;
952 
953         MapX = SCursor.kcX;
954         MapY = SCursor.kcY;
955 
956         if (Parameters.kpShowTerminals) DisplayTerminals(ERASE);
957         do_stretch_path(RefX,RefY,MapX,MapY,&NBB,GotOne);
958         EraseBox(&NBB);
959         Redisplay(&NBB);
960         if (Parameters.kpShowTerminals) DisplayTerminals(DISPLAY);
961         OBB = NBB;
962         Modified++;
963         Undo = False;
964     }
965 
966 quit:
967     ClearReferenceUndoFlags();
968     HYclearUndoFlags();
969     SQRestore(False);
970     if (Not GotOne And AreTypesInQ(Types)) {
971         SQComputeBB();
972         SQDesel(Types);
973         EraseBox(&SelectQBB);
974         Redisplay(&SelectQBB);
975     }
976     if (Modified)
977         Parameters.kpModified = True;
978     ErasePrompt();
979     MenuDeselect(MenuUNDO);
980     MenuDeselect(MenuSTRCH);
981 }
982 
983 
984 void
ShowStretch(MapX,MapY,RefX,RefY)985 ShowStretch(MapX,MapY,RefX,RefY)
986 
987 /* Called from rubber banding routine. */
988 long RefX,RefY,MapX,MapY;
989 {
990     struct ks *SQDesc, *SQDesc1;
991     struct p *Path, *pp;
992     int Layer;
993     long Width;
994 
995     for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
996         if (SQDesc->ksPointer->oInfo != SQ_OLDSEL &&
997             SQDesc->ksPointer->oInfo != SQ_NEWSEL) continue;
998         if (SQDesc->ksPointer->oType != CDWIRE) continue;
999 
1000         /* draw only once if in queue more than once */
1001         for (SQDesc1 = SQDesc->ksSucc; SQDesc1; SQDesc1 = SQDesc1->ksSucc)
1002             if (SQDesc1->ksPointer == SQDesc->ksPointer) break;
1003 
1004         if (SQDesc1 == NULL) {
1005             CDWire(SQDesc->ksPointer,&Layer,&Width,&Path);
1006             pp = get_nearest_vertex(Path,RefX,RefY);
1007             pp->pX += MapX - RefX;
1008             pp->pY += MapY - RefY;
1009             ShowWire(HighlightingColor,Width,Path);
1010             pp->pX -= MapX - RefX;
1011             pp->pY -= MapY - RefY;
1012         }
1013     }
1014 }
1015 
1016 static void
restore_stretch()1017 restore_stretch()
1018 
1019 /* Repaint objects to be stretched. */
1020 {
1021     struct ks *SQDesc;
1022     struct p *Path;
1023     int Layer;
1024     long Width;
1025 
1026     for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
1027         if (SQDesc->ksPointer->oInfo == SQ_GONE) continue;
1028         if (SQDesc->ksPointer->oType != CDWIRE) continue;
1029 
1030         CDWire(SQDesc->ksPointer,&Layer,&Width,&Path);
1031         ShowWire(DrawingColor,Width,Path);
1032     }
1033 }
1034 
1035 
1036 static void
do_stretch_path(RefX,RefY,MapX,MapY,NBB,SelectNew)1037 do_stretch_path(RefX,RefY,MapX,MapY,NBB,SelectNew)
1038 
1039 /* Perform the stretch. */
1040 long RefX,RefY,MapX,MapY;
1041 struct ka *NBB;
1042 int SelectNew;
1043 {
1044     struct ks *SQDesc;
1045     struct ka OBB,BB;
1046     struct o *Pointer;
1047     struct p *Path, *pp;
1048     int Layer;
1049     long Width;
1050 
1051     NBB->kaLeft   = CDINFINITY;
1052     NBB->kaRight  = -CDINFINITY;
1053     NBB->kaBottom = CDINFINITY;
1054     NBB->kaTop    = -CDINFINITY;
1055 
1056     for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
1057         if (SQDesc->ksPointer->oInfo == SQ_GONE) continue;
1058         if (SQDesc->ksPointer->oType != CDWIRE) continue;
1059 
1060         CDWire(SQDesc->ksPointer,&Layer,&Width,&Path);
1061         CDStatusInt = CDBB(Parameters.kpCellDesc,SQDesc->ksPointer,
1062             &OBB.kaLeft,&OBB.kaBottom,&OBB.kaRight,&OBB.kaTop);
1063 
1064         Path = CopyPath(Path);
1065         pp = get_nearest_vertex(Path,RefX,RefY);
1066         pp->pX += MapX - RefX;
1067         pp->pY += MapY - RefY;
1068 
1069         if (Not CDMakeWire(Parameters.kpCellDesc,Layer,Width,Path,
1070             &Pointer)) MallocFailed();
1071         AssignWireProperties(Pointer);
1072 
1073         if (SelectNew)
1074             Pointer->oInfo = SQ_NEWSEL;
1075         else
1076             Pointer->oInfo = SQ_NEW;
1077 
1078         SQInsert(Pointer);
1079 
1080         CDStatusInt = CDBB(Parameters.kpCellDesc,Pointer,
1081             &BB.kaLeft,&BB.kaBottom,&BB.kaRight,&BB.kaTop);
1082 
1083         if (OBB.kaLeft   < BB.kaLeft)   BB.kaLeft   = OBB.kaLeft;
1084         if (OBB.kaRight  > BB.kaRight)  BB.kaRight  = OBB.kaRight;
1085         if (OBB.kaBottom < BB.kaBottom) BB.kaBottom = OBB.kaBottom;
1086         if (OBB.kaTop    > BB.kaTop)    BB.kaTop    = OBB.kaTop;
1087 
1088         if (BB.kaLeft   < NBB->kaLeft)   NBB->kaLeft   = BB.kaLeft;
1089         if (BB.kaRight  > NBB->kaRight)  NBB->kaRight  = BB.kaRight;
1090         if (BB.kaBottom < NBB->kaBottom) NBB->kaBottom = BB.kaBottom;
1091         if (BB.kaTop    > NBB->kaTop)    NBB->kaTop    = BB.kaTop;
1092 
1093         TPush();
1094         TIdentity();
1095         TTranslate(MapX-RefX,MapY-RefY);
1096         TransformReferencePoint(SQDesc->ksPointer,RefX,RefY);
1097         HYtransformStretch(SQDesc->ksPointer,Pointer,RefX,RefY,MapX,MapY);
1098         TPop();
1099         SQDesc->ksPointer->oInfo = SQ_GONE;
1100     }
1101 }
1102 
1103 
1104 static struct p *
get_nearest_vertex(Path,X,Y)1105 get_nearest_vertex(Path,X,Y)
1106 
1107 /* return the path vertex nearest X,Y. */
1108 struct p *Path;
1109 long X,Y;
1110 {
1111     double dx,dy,d,mind;
1112     struct p *p;
1113     int i,indx = 0;
1114 
1115     mind = 1e30;
1116     for (p = Path,i = 0; p; p = p->pSucc,i++) {
1117         dx = p->pX - X;
1118         dy = p->pY - Y;
1119         d = dx*dx + dy*dy;
1120         if (d < mind) {
1121             mind = d;
1122             indx = i;
1123         }
1124     }
1125     for (p = Path, i = 0; i < indx; p = p->pSucc,i++) ;
1126     return (p);
1127 }
1128 
1129 
1130 static void
set_ref_to_vertex(X,Y)1131 set_ref_to_vertex(X,Y)
1132 
1133 /* Return in pointers the vertex closest to the given coordinates. */
1134 long *X,*Y;
1135 {
1136     struct ks *SQDesc;
1137     struct o *Pointer;
1138     struct p *p,*Path;
1139     double dx,dy,d,mind;
1140     int i,indx;
1141 
1142 
1143     mind = 1e30;
1144     for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
1145 
1146         if (SQDesc->ksPointer->oInfo == SQ_GONE) continue;
1147         if (SQDesc->ksPointer->oType != CDWIRE) continue;
1148         Path = ((struct w *)SQDesc->ksPointer->oRep)->wPath;
1149 
1150         for (p = Path,i = 0; p; p = p->pSucc,i++) {
1151             dx = p->pX - *X;
1152             dy = p->pY - *Y;
1153             d = dx*dx + dy*dy;
1154             if (d < mind) {
1155                 mind = d;
1156                 indx = i;
1157                 Pointer = SQDesc->ksPointer;
1158             }
1159         }
1160     }
1161     Path = ((struct w *)Pointer->oRep)->wPath;
1162     for (p = Path, i = 0; i < indx; p = p->pSucc,i++) ;
1163     *X = p->pX;
1164     *Y = p->pY;
1165 }
1166 
1167 
1168 /***********************************************************************
1169  *
1170  * Dot command.
1171  * Place dots at connections.
1172  *
1173  ***********************************************************************/
1174 
1175 extern char *MenuDOTS;
1176 extern char *MenuUNDO;
1177 
1178 static char DotP[] =  {0,60, 40,40, 60,0, 40,-40, 0,-60, -40,-40,
1179                       -60,0, -40,40, 0,60};
1180 
1181 static struct p *DotList;
1182 
1183 struct pp {
1184     int ppX, ppY;
1185     int ppType;
1186     struct pp *ppSucc;
1187 };
1188 static struct pp *VertexList;
1189 
1190 struct clist {
1191     char *name;
1192     struct s *cd;
1193     struct clist *next;
1194 };
1195 static struct clist *CList;
1196 
1197 #ifdef __STDC__
1198 static void clear_dots(struct s*);
1199 static void create_dots(struct s*);
1200 static void save_vertex(int,int,int);
1201 static void save_dot(int,int);
1202 static void add_dots(struct s*);
1203 static void list_cells(void);
1204 static void mlist(struct m*);
1205 static struct s *add_to_list(char*);
1206 #else
1207 static void clear_dots();
1208 static void create_dots();
1209 static void save_vertex();
1210 static void save_dot();
1211 static void add_dots();
1212 static void list_cells();
1213 static void mlist();
1214 static struct s *add_to_list();
1215 #endif
1216 
1217 
1218 void
Dots(LookedAhead)1219 Dots(LookedAhead)
1220 
1221 int *LookedAhead;
1222 {
1223     struct clist *s;
1224 
1225     MenuSelect(MenuDOTS);
1226     Parameters.kpShowDots = True;
1227     list_cells();
1228     for (s = CList; s; s = s->next)
1229         create_dots(s->cd);
1230     EraseLargeCoarseViewport();
1231     Redisplay(View->kvCoarseWindow);
1232 
1233     loop {
1234         switch (PointLoop(LookedAhead)) {
1235             case PL_CMD:
1236                 if (Matching(MenuDOTS))
1237                     Parameters.kpCommand[0] = '\0';
1238             case PL_ESC:
1239             case PL_UND:
1240                 goto quit;
1241             case PL_PCW:
1242                 break;
1243         }
1244     }
1245 quit:
1246     for (s = CList; s; s = s->next)
1247         clear_dots(s->cd);
1248     for (; CList; CList = s) {
1249         s = CList->next;
1250         txfree((char*)CList);
1251     }
1252     CList = NULL;
1253     MenuDeselect(MenuDOTS);
1254     Parameters.kpShowDots = False;
1255     EraseLargeCoarseViewport();
1256     Redisplay(View->kvCoarseWindow);
1257 }
1258 
1259 
1260 static void
clear_dots(CellDesc)1261 clear_dots(CellDesc)
1262 
1263 struct s *CellDesc;
1264 {
1265     struct g *GenDesc;
1266     struct o *Pointer;
1267 
1268     if (Not CDInitGen(CellDesc,1,-CDINFINITY,-CDINFINITY,
1269         CDINFINITY,CDINFINITY,&GenDesc)) MallocFailed();
1270 
1271     loop {
1272         CDGen(CellDesc,GenDesc,&Pointer);
1273         if (Pointer == NULL) break;
1274         if (Pointer->oInfo == SQ_GONE Or Pointer->oInfo == SQ_INCMPLT)
1275             continue;
1276         if (Pointer->oType == CDPOLYGON) {
1277             CDDelete(CellDesc,Pointer);
1278         }
1279     }
1280 }
1281 
1282 static void
create_dots(CellDesc)1283 create_dots(CellDesc)
1284 
1285 struct s *CellDesc;
1286 {
1287     struct g *GenDesc;
1288     struct o *Pointer;
1289     struct p *p;
1290     struct prpty *pd;
1291 
1292     /* Process wires */
1293 
1294     if (Not CDInitGen(CellDesc,1,-CDINFINITY,-CDINFINITY,
1295         CDINFINITY,CDINFINITY,&GenDesc)) MallocFailed();
1296 
1297     loop {
1298         CDGen(CellDesc,GenDesc,&Pointer);
1299         if (Pointer == NULL) break;
1300         if (Pointer->oInfo == SQ_GONE Or Pointer->oInfo == SQ_INCMPLT)
1301             continue;
1302         if (Pointer->oType == CDWIRE) {
1303             p = ((struct w *)Pointer->oRep)->wPath;
1304             save_vertex(p->pX,p->pY,0);
1305             for (p = p->pSucc; p && p->pSucc; p = p->pSucc)
1306                 save_vertex(p->pX,p->pY,1);
1307             if (p)
1308                 save_vertex(p->pX,p->pY,0);
1309         }
1310     }
1311 
1312     /* Process devices */
1313 
1314     if (Not CDInitGen(CellDesc,0,-CDINFINITY,-CDINFINITY,CDINFINITY,
1315         CDINFINITY,&GenDesc)) MallocFailed();
1316 
1317     loop {
1318         CDGen(CellDesc,GenDesc,&Pointer);
1319         if (Pointer == NULL) break;
1320         if (Pointer->oInfo == SQ_GONE) continue;
1321 
1322         pd = Pointer->oPrptyList;
1323         for (; pd; pd = pd->prpty_Succ) {
1324             if (pd->prpty_Value != P_NODE)
1325                 continue;
1326             save_vertex(pd->prpty_Data->p_node.x,
1327                 pd->prpty_Data->p_node.y,0);
1328         }
1329     }
1330     add_dots(CellDesc);
1331 }
1332 
1333 
1334 static void
save_vertex(x,y,type)1335 save_vertex(x,y,type)
1336 
1337 /* Consider saving point in vertex list; if it is already there,
1338  * update the type field or add it to the dot list.
1339  */
1340 int x, y, type;
1341 {
1342     struct pp *p;
1343 
1344     for (p = VertexList; p; p = p->ppSucc) {
1345         if (p->ppX == x && p->ppY == y) {
1346             /* already there, if both types are zero,
1347              * update the stored entry to type 1 (so as
1348              * not to mark two abutting line segments)
1349              */
1350             if (p->ppType == 0 && type == 0)
1351                 p->ppType = 1;
1352             else
1353                 save_dot(x,y);
1354             return;
1355         }
1356     }
1357     p = alloc(pp);
1358     if (p == NULL) MallocFailed();
1359     p->ppX = x;
1360     p->ppY = y;
1361     p->ppType = type;
1362     p->ppSucc = VertexList;
1363     VertexList = p;
1364 }
1365 
1366 
1367 static void
save_dot(x,y)1368 save_dot(x,y)
1369 
1370 /* Save point in the dot list; if it is already
1371  * there, just return.
1372  */
1373 int x, y;
1374 {
1375     struct p *p;
1376 
1377     for (p = DotList; p; p = p->pSucc) {
1378         if (p->pX == x && p->pY == y)
1379             return;
1380     }
1381     p = alloc(p);
1382     if (p == NULL) MallocFailed();
1383     p->pX = x;
1384     p->pY = y;
1385     p->pSucc = DotList;
1386     DotList = p;
1387 }
1388 
1389 
1390 static void
add_dots(CellDesc)1391 add_dots(CellDesc)
1392 
1393 /* Process and clear the dot and vertex lists. */
1394 struct s *CellDesc;
1395 {
1396     struct p *p, *pd, *Path;
1397     struct o *Pointer;
1398     int i;
1399 
1400     for (pd = DotList; pd; pd = pd->pSucc) {
1401 
1402         p = Path = alloc(p);
1403         if (p == NULL) MallocFailed();
1404         p->pX = pd->pX + DotP[0];
1405         p->pY = pd->pY + DotP[1];
1406         for (i = 1; i < 9; i++) {
1407             p->pSucc = alloc(p);
1408             p = p->pSucc;
1409             if (p == NULL) MallocFailed();
1410             p->pX = pd->pX + DotP[2*i];
1411             p->pY = pd->pY + DotP[2*i+1];
1412         }
1413         p->pSucc = NULL;
1414         if (!CDMakePolygon(CellDesc,1,Path,&Pointer))
1415             MallocFailed();
1416     }
1417     for (; DotList; DotList = p) {
1418         p = DotList->pSucc;
1419         txfree((char*)DotList);
1420     }
1421     for (; VertexList; VertexList = (struct pp*)p) {
1422         p = (struct p*)VertexList->ppSucc;
1423         txfree((char*)VertexList);
1424     }
1425     DotList = NULL;
1426     VertexList = NULL;
1427 }
1428 
1429 
1430 static void
list_cells()1431 list_cells()
1432 
1433 /* get a list of cells in hierarchy */
1434 {
1435     CList = alloc(clist);
1436     if (CList == NULL)
1437         MallocFailed();
1438     CList->name = Parameters.kpCellName;
1439     CList->cd = Parameters.kpCellDesc;
1440     CList->next = NULL;
1441     mlist(Parameters.kpCellDesc->sMasterList);
1442 }
1443 
1444 
1445 static void
mlist(md)1446 mlist(md)
1447 
1448 /* walk the master list and recursively add subcircuits */
1449 struct m *md;
1450 {
1451     struct s *cd;
1452 
1453     for (; md; md = md->mSucc) {
1454         if (!IsCellInLib(md->mName)) {
1455             cd = add_to_list(md->mName);
1456             if (cd) {
1457                 mlist(cd->sMasterList);
1458             }
1459         }
1460     }
1461 }
1462 
1463 
1464 static struct s *
add_to_list(name)1465 add_to_list(name)
1466 
1467 /* add the cell if not already there, return descr of new addition */
1468 char *name;
1469 {
1470     struct clist *s;
1471     struct s *cd;
1472 
1473     for (s = CList; s; s = s->next) {
1474         if (!strcmp(s->name,name))
1475             return (NULL);
1476     }
1477     if (!CDOpen(name,&cd,'r'))
1478         return (NULL);
1479     s = alloc(clist);
1480     if (s == NULL)
1481         MallocFailed();
1482     s->name = name;
1483     s->cd = cd;
1484     s->next = CList;
1485     CList = s;
1486     return (cd);
1487 }
1488