1 /*-------------------------------------------------------------------------*/
2 /* schema.c --- xcircuit routines specific to the schematic capture system */
3 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
4 /*-------------------------------------------------------------------------*/
6 /*-------------------------------------------------------------------------*/
7 /* written by Tim Edwards, 10/13/97 */
8 /*-------------------------------------------------------------------------*/
15 #include <X11/Intrinsic.h>
16 #include <X11/StringDefs.h>
24 #include "Xw/MenuBtn.h"
28 /*-------------------------------------------------------------------------*/
30 /*-------------------------------------------------------------------------*/
33 #include "colordefs.h"
36 /*----------------------------------------------------------------------*/
37 /* Function prototype declarations */
38 /*----------------------------------------------------------------------*/
39 #include "prototypes.h"
41 /*------------------------------------------------------------------------*/
42 /* External Variable definitions */
43 /*------------------------------------------------------------------------*/
46 extern Tcl_Interp
*xcinterp
;
49 extern Globaldata xobjs
;
50 extern XCWindowData
*areawin
;
51 extern xcWidget menuwidgets
[];
52 extern xcWidget netbutton
;
53 extern char _STR
[150];
54 extern char _STR2
[250];
55 extern colorindex
*colorlist
;
57 /*-------------------------------------------------------------------------*/
59 extern xcWidget wsymb
, wschema
;
61 /*--------------------------------------------------------*/
62 /* Menu calls (procedure wrappers) */
63 /*--------------------------------------------------------*/
65 void callwritenet(xcWidget w
, pointertype mode
, caddr_t calldata
)
69 writenet(topobject
, "spice", "spc");
72 writenet(topobject
, "flatsim", "sim");
75 writenet(topobject
, "pcb", "pcbnet");
78 writenet(topobject
, "flatspice", "fspc");
81 /* Auto-numbering: no output generated */
82 writenet(topobject
, "indexpcb", "");
87 /*----------------------------------------------------------------------*/
88 /* Find the page object and instance with the indicated name. */
89 /*----------------------------------------------------------------------*/
91 objectptr
NameToPageObject(char *objname
, objinstptr
*ret_inst
, int *ret_page
)
95 for (i
= 0; i
< xobjs
.pages
; i
++) {
96 if (xobjs
.pagelist
[i
]->pageinst
== NULL
) continue;
97 if (!strcmp(objname
, xobjs
.pagelist
[i
]->pageinst
->thisobject
->name
)) {
98 if (ret_inst
) *ret_inst
= xobjs
.pagelist
[i
]->pageinst
;
99 if (ret_page
) *ret_page
= i
;
100 return xobjs
.pagelist
[i
]->pageinst
->thisobject
;
106 /*--------------------------------------------------------------*/
107 /* Get the canonical name of an object (the part without the */
108 /* technology prefix, if any). */
109 /*--------------------------------------------------------------*/
111 char *GetCanonicalName(char *fullname
)
113 char *canonname
= strstr(fullname
, "::");
114 if (canonname
== NULL
) return fullname
;
115 return canonname
+ 2;
118 /*----------------------------------------------------------------------*/
119 /* Find the object with the indicated name. */
121 /* WARNING: If no library technology is given, XCircuit will return */
122 /* the first object with the name "objname". If there are multiple */
123 /* objects of the same name in different technologies, then the one */
124 /* returned may not be the one expected! */
126 /* UPDATE (4/17/2020): The "technology prefer" option can be used to */
127 /* set a precedence of one library over another in case of a naming */
128 /* conflict. This should be used appropriately, as ambiguous object */
129 /* names in two technologies both marked "preferred" cannot be */
131 /*----------------------------------------------------------------------*/
133 objectptr
NameToObject(char *objname
, objinstptr
*ret_inst
, Boolean dopages
)
137 Boolean notech
= FALSE
;
138 Boolean preferred
= FALSE
;
140 objectptr retobj
= NULL
;
143 if (strstr(objname
, "::") == NULL
) notech
= TRUE
;
145 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
146 for (spec
= xobjs
.userlibs
[i
].instlist
; spec
!= NULL
; spec
= spec
->next
) {
147 techptr
= spec
->thisinst
->thisobject
->name
;
149 techptr
= GetCanonicalName(spec
->thisinst
->thisobject
->name
);
150 if (!strcmp(objname
, techptr
)) {
151 if ((retobj
== NULL
) || ((retobj
!= NULL
) && (preferred
== FALSE
))) {
152 if (ret_inst
) *ret_inst
= spec
->thisinst
;
153 retobj
= spec
->thisinst
->thisobject
;
154 nsp
= GetObjectTechnology(retobj
);
155 preferred
= (nsp
&& (nsp
->flags
& TECH_PREFER
)) ? TRUE
: FALSE
;
161 if (retobj
!= NULL
) return retobj
;
164 return NameToPageObject(objname
, ret_inst
, NULL
);
169 /*------------------------------------------------------------------------*/
170 /* Ensure that a page name is unique (required for schematic association) */
171 /*------------------------------------------------------------------------*/
173 int checkpagename(objectptr thispageobj
)
176 /* char *objname = thispageobj->name; (jdk) */
178 Boolean update
= False
;
182 /* Check for ":n" suffix and prepare for possible update */
183 clnptr
= strrchr(thispageobj
->name
, ':');
185 if (sscanf(clnptr
+ 1, "%d", &n
) != 1)
188 /* Find the page number of this page object */
189 for (p
= 0; p
< xobjs
.pages
; p
++) {
190 if (xobjs
.pagelist
[p
]->pageinst
!= NULL
) {
191 if (xobjs
.pagelist
[p
]->pageinst
->thisobject
== thispageobj
) {
197 if (p
== xobjs
.pages
) {
198 Fprintf(stderr
, "Error: Object is not a page object!\n");
202 /* Look for any other pages with the same name */
205 for (p
= 0; p
< xobjs
.pages
; p
++) {
206 if (p
== thispage
) continue;
207 if (xobjs
.pagelist
[p
]->pageinst
!= NULL
) {
208 if (!filecmp(xobjs
.pagelist
[p
]->pageinst
->thisobject
->name
,
209 thispageobj
->name
)) {
210 /* append ":2" to name or update suffix to ensure uniqueness */
212 sprintf(thispageobj
->name
, "%s:2", thispageobj
->name
);
214 sprintf(clnptr
+ 1, "%d", n
+ 1);
223 renamepage(thispage
);
229 /*--------------------------------------*/
230 /* Find connectivity of a selection */
231 /*--------------------------------------*/
233 void startconnect(xcWidget button
, caddr_t clientdata
, caddr_t calldata
)
235 if (areawin
->selects
> 0)
236 connectivity(button
, clientdata
, calldata
);
239 /*----------------------------------------------------------------------*/
240 /* connectivity(): Find electrical connections into a node. */
241 /* (does recursive search on object heirarchy) */
242 /*----------------------------------------------------------------------*/
244 void connectivity(xcWidget button
, caddr_t clientdata
, caddr_t calldata
)
247 selection
*rselect
= NULL
, *nextselect
;
248 genericptr ggen
= NULL
;
249 Genericlist
*netlist
= NULL
;
250 int depth
, lbus
, netid
, subnetid
;
252 pushlistptr seltop
, nextptr
;
253 objectptr nettop
, pschem
; /* thisobj, (jdk) */
257 /* erase any existing highlighted network */
258 highlightnetlist(topobject
, areawin
->topinstance
, 0);
260 seltop
= (pushlistptr
)malloc(sizeof(pushlist
));
261 seltop
->thisinst
= areawin
->topinstance
;
264 /* pick the first selection that looks like a valid network part */
266 if (areawin
->selects
> 0) {
267 for (gsel
= areawin
->selectlist
; gsel
< areawin
->selectlist
+
268 areawin
->selects
; gsel
++) {
269 ggen
= *(topobject
->plist
+ *gsel
);
270 if (SELECTTYPE(gsel
) == LABEL
) {
271 labelptr glab
= SELTOLABEL(gsel
);
272 if (glab
->pin
== LOCAL
|| glab
->pin
== GLOBAL
) break;
274 else if (SELECTTYPE(gsel
) == POLYGON
) {
275 polyptr gpoly
= SELTOPOLY(gsel
);
276 if (!nonnetwork(gpoly
)) break;
280 if ((areawin
->selects
== 0) || (gsel
== areawin
->selectlist
281 + areawin
->selects
)) {
282 rselect
= recurselect(POLYGON
| LABEL
| OBJINST
, MODE_CONNECT
, &seltop
);
283 /* Should look at the top scorer, when scoring has been implemented */
284 if (rselect
&& (rselect
->selects
> 0)) {
285 for (nextselect
= rselect
; (nextselect
->next
!= NULL
) &&
286 (nextselect
->selects
> 0); nextselect
= nextselect
->next
);
287 ggen
= *(nextselect
->thisinst
->thisobject
->plist
+ *(nextselect
->selectlist
));
288 while (rselect
!= NULL
) {
289 nextselect
= rselect
->next
;
290 free(rselect
->selectlist
);
292 rselect
= nextselect
;
297 /* Determine the net and the topmost object in which that */
298 /* net appears. Then build the transformation matrix down */
299 /* to that object. highlightnet() should end by popping the */
300 /* entire matrix stack. */
303 if (checkvalid(topobject
) == -1) {
304 destroynets(topobject
);
305 createnets(areawin
->topinstance
, FALSE
);
307 if ((netlist
= is_resolved(&ggen
, seltop
, &nettop
)) != NULL
) {
308 depth
= pushnetwork(seltop
, nettop
);
309 /* Fprintf(stdout, ">> Pushed network %d levels deep\n", depth); */
311 while (nextptr
->thisinst
->thisobject
!= nettop
)
312 nextptr
= nextptr
->next
;
314 nextptr
->thisinst
->thisobject
->highlight
.netlist
= netlist
;
315 nextptr
->thisinst
->thisobject
->highlight
.thisinst
= nextptr
->thisinst
;
316 highlightnetlist(nettop
, nextptr
->thisinst
, 1);
318 /* pop the matrix stack */
322 /* get the primary schematic */
323 pschem
= (nettop
->schemtype
== SECONDARY
) ? nettop
->symschem
: nettop
;
325 /* print the net name to the message window */
327 if (netlist
->subnets
== 0) {
328 ppin
= nettopin(netlist
->net
.id
, pschem
, NULL
);
329 snew
= textprint(ppin
, areawin
->topinstance
);
330 sprintf(_STR2
, "Network is \"%s\" in %s", snew
, nettop
->name
);
335 sprintf(_STR2
, "Network(s): ");
336 sptr
= _STR2
+ strlen(_STR2
);
337 for (lbus
= 0; lbus
< netlist
->subnets
; lbus
++) {
338 sbus
= netlist
->net
.list
+ lbus
;
340 subnetid
= sbus
->subnetid
;
341 ppin
= nettopin(netid
, pschem
, NULL
);
342 snew
= textprintsubnet(ppin
, areawin
->topinstance
, subnetid
);
343 sprintf(sptr
, "%s ", snew
);
344 sptr
+= strlen(snew
) + 1;
347 sprintf(sptr
, "in %s", nettop
->name
);
349 Wprintf("%s", _STR2
);
352 Tcl_SetObjResult(xcinterp
, Tcl_NewStringObj(snew
, strlen(snew
)));
356 Wprintf("Selected element is not part of a valid network.");
359 Wprintf("No networks found near the cursor position");
363 /* free up linked list */
365 while (seltop
!= NULL
) {
366 nextptr
= seltop
->next
;
372 /*--------------------------------------------------------------*/
373 /* Set object type to FUNDAMENTAL if it contains one or more */
374 /* info labels and is not associated with a schematic/symbol. */
376 /* Return TRUE if the object has electrically relevant */
377 /* networks, FALSE if not. */
378 /*--------------------------------------------------------------*/
380 Boolean
setobjecttype(objectptr cschem
)
385 /* If networks are specifically prohibited. . . */
386 if (cschem
->schemtype
== NONETWORK
) return False
;
388 /* Apply only to schematic objects */
390 if ((cschem
->schemtype
!= PRIMARY
) && (cschem
->schemtype
!= SECONDARY
)) {
391 if (cschem
->schemtype
== FUNDAMENTAL
)
392 cschem
->schemtype
= SYMBOL
;
393 if (cschem
->symschem
== NULL
) {
394 for (cgen
= cschem
->plist
; cgen
< cschem
->plist
+ cschem
->parts
; cgen
++) {
395 if (IS_LABEL(*cgen
)) {
396 clab
= TOLABEL(cgen
);
397 if (clab
->pin
== INFO
) {
398 cschem
->schemtype
= FUNDAMENTAL
;
406 if ((cschem
->symschem
!= NULL
) && (cschem
->schemtype
== SYMBOL
))
408 else if ((cschem
->schemtype
== TRIVIAL
) || (cschem
->schemtype
== FUNDAMENTAL
))
414 /*------------------------------------------------------*/
415 /* Pin conversion subroutine for dopintype() */
416 /*------------------------------------------------------*/
418 void pinconvert(labelptr thislab
, pointertype mode
)
423 thislab
->color
= DEFAULTCOLOR
; /* nominally black */
426 thislab
->color
= GLOBALPINCOLOR
; /* orange */
429 thislab
->color
= LOCALPINCOLOR
; /* red */
432 thislab
->color
= INFOLABELCOLOR
; /* green */
437 /*---------------------------------------------------------*/
438 /* Change a label's type to NORMAL, GLOBAL, INFO, or LOCAL */
439 /*---------------------------------------------------------*/
441 void dopintype(xcWidget w
, pointertype mode
, caddr_t calldata
)
447 if (areawin
->selects
== 0) {
448 Wprintf("Must first select a label to change type");
452 strcpy(typestr
, "Changed label to ");
455 strcat(typestr
, "normal label");
458 strcat(typestr
, "global pin");
461 strcat(typestr
, "local pin");
464 strcat(typestr
, "info-label");
468 for (gsel
= areawin
->selectlist
; gsel
< areawin
->selectlist
+
469 areawin
->selects
; gsel
++)
470 if (SELECTTYPE(gsel
) == LABEL
) {
471 labelptr glab
= SELTOLABEL(gsel
);
472 savetype
= glab
->pin
;
473 pinconvert(glab
, mode
);
474 setobjecttype(topobject
);
479 drawarea(NULL
, NULL
, NULL
);
480 Wprintf("%s", typestr
);
483 Wprintf("No labels selected.");
487 /*----------------------------------------------------------*/
488 /* Set colors on the symbol/schematic buttons appropriately */
489 /*----------------------------------------------------------*/
495 XcInternalTagCall(xcinterp
, 1, "schematic");
502 Arg aargs
[2], bargs
[2];
504 /* Set menu items appropriately for this object */
506 if (topobject
->symschem
!= NULL
) {
507 if (topobject
->schemtype
== PRIMARY
|| topobject
->schemtype
== SECONDARY
) {
508 XtSetArg(aargs
[0], XtNlabel
, "Go To Symbol");
509 XtSetArg(bargs
[0], XtNlabel
, "Disassociate Symbol");
512 XtSetArg(aargs
[0], XtNlabel
, "Go To Schematic");
513 XtSetArg(bargs
[0], XtNlabel
, "Disassociate Schematic");
517 if (topobject
->schemtype
== PRIMARY
|| topobject
->schemtype
== SECONDARY
) {
518 XtSetArg(aargs
[0], XtNlabel
, "Make Matching Symbol");
519 XtSetArg(bargs
[0], XtNlabel
, "Associate with Symbol");
522 XtSetArg(aargs
[0], XtNlabel
, "Make Matching Schematic");
523 XtSetArg(bargs
[0], XtNlabel
, "Associate with Schematic");
526 XtSetValues(NetlistMakeMatchingSymbolButton
, aargs
, 1);
527 XtSetValues(NetlistAssociatewithSymbolButton
, bargs
, 1);
529 /* Set colors on the symbol and schematic buttons */
531 if (topobject
->schemtype
== PRIMARY
|| topobject
->schemtype
== SECONDARY
) {
532 if (topobject
->symschem
== NULL
) {
533 XtSetArg(aargs
[0], XtNbackground
, colorlist
[OFFBUTTONCOLOR
].color
.pixel
);
534 XtSetArg(aargs
[1], XtNforeground
, colorlist
[OFFBUTTONCOLOR
].color
.pixel
);
537 XtSetArg(aargs
[0], XtNbackground
, colorlist
[BACKGROUND
].color
.pixel
);
538 XtSetArg(aargs
[1], XtNforeground
, colorlist
[FOREGROUND
].color
.pixel
);
541 XtSetArg(bargs
[1], XtNforeground
, colorlist
[FOREGROUND
].color
.pixel
);
542 XtSetArg(bargs
[0], XtNbackground
, colorlist
[SNAPCOLOR
].color
.pixel
);
545 if (topobject
->symschem
!= NULL
) {
546 XtSetArg(bargs
[0], XtNbackground
, colorlist
[BACKGROUND
].color
.pixel
);
547 XtSetArg(bargs
[1], XtNforeground
, colorlist
[FOREGROUND
].color
.pixel
);
550 XtSetArg(bargs
[0], XtNbackground
, colorlist
[OFFBUTTONCOLOR
].color
.pixel
);
551 XtSetArg(bargs
[1], XtNforeground
, colorlist
[OFFBUTTONCOLOR
].color
.pixel
);
554 XtSetArg(aargs
[1], XtNforeground
, colorlist
[FOREGROUND
].color
.pixel
);
555 if (topobject
->schemtype
== FUNDAMENTAL
)
556 XtSetArg(aargs
[0], XtNbackground
, colorlist
[AUXCOLOR
].color
.pixel
);
557 else if (topobject
->schemtype
== TRIVIAL
|| topobject
->symschem
!= NULL
)
558 XtSetArg(aargs
[0], XtNbackground
, colorlist
[SNAPCOLOR
].color
.pixel
);
560 XtSetArg(aargs
[0], XtNbackground
, colorlist
[OFFBUTTONCOLOR
].color
.pixel
);
561 XtSetArg(aargs
[1], XtNforeground
, colorlist
[OFFBUTTONCOLOR
].color
.pixel
);
562 XtSetArg(bargs
[0], XtNbackground
, colorlist
[BBOXCOLOR
].color
.pixel
);
563 XtSetArg(bargs
[1], XtNforeground
, colorlist
[FOREGROUND
].color
.pixel
);
567 XtSetValues(wsymb
, aargs
, 2);
568 XtSetValues(wschema
, bargs
, 2);
573 /*--------------------------------------------------------*/
574 /* Find the page number for an object */
575 /*--------------------------------------------------------*/
577 int findpageobj(objectptr pobj
)
581 for (tpage
= 0; tpage
< xobjs
.pages
; tpage
++)
582 if (xobjs
.pagelist
[tpage
]->pageinst
!= NULL
)
583 if (xobjs
.pagelist
[tpage
]->pageinst
->thisobject
== pobj
)
589 /*------------------------------------------------------*/
590 /* Enumerate all of the pages which are subschematics */
591 /* of "toppage" and return the result in the list */
592 /* passed as a pointer. The list is assumed to be */
593 /* already allocated, and equal to the total number of */
594 /* pages (xobjs.pages). */
596 /* Avoid possible recursion problems by limiting the */
597 /* number of recursion levels. Presumably no circuit */
598 /* would have more than several hundred hierarchical */
601 /* If "dolinks" is TRUE, ennumerate and follow pages */
602 /* that are descendents of the top level when the */
603 /* calling symbol instance has a "link" parameter and */
604 /* that parameter points to the same filename as the */
605 /* page. This indicates a multiple-file project; the */
606 /* pages keep separate records of changes, and are */
607 /* saved independently, and loaded through the link */
608 /* dependency method. */
609 /*------------------------------------------------------*/
611 int findsubschems(int toppage
, objectptr cschem
, int level
, short *pagelist
,
616 if (level
== HIERARCHY_LIMIT
) return -1; /* sanity check */
618 for (cgen
= cschem
->plist
; cgen
< cschem
->plist
+ cschem
->parts
; cgen
++) {
619 if (IS_OBJINST(*cgen
)) {
620 objinstptr cinst
= TOOBJINST(cgen
);
621 objectptr cobj
= cinst
->thisobject
;
623 if (cobj
->symschem
!= NULL
) {
624 int pageno
= findpageobj(cobj
->symschem
);
626 if ((pageno
>= 0) && (pageno
< xobjs
.pages
)) {
628 /* Look for a "link" parameter */
629 if (dolinks
== FALSE
) {
631 ops
= find_param(cinst
, "link");
632 if ((ops
!= NULL
) && (ops
->type
== XC_STRING
)) {
633 char *filename
= textprint(ops
->parameter
.string
, cinst
);
634 if (!strcmp(filename
, "%n") || !strcmp(filename
, "%N") ||
635 !strcmp(filename
, xobjs
.pagelist
[pageno
]->filename
)) {
643 /* Add this page to the list */
647 /* A symbol on its own schematic page is allowed for clarity */
648 /* of the schematic, but this cannot be a functional part of */
649 /* the schematic circuit! */
651 if (cobj
->symschem
!= cschem
) {
652 if (findsubschems(toppage
, cobj
->symschem
,
653 level
+ 1, pagelist
, dolinks
) == -1)
657 else if (cobj
->schemtype
!= FUNDAMENTAL
&& cobj
->schemtype
!= TRIVIAL
) {
658 /* Check symbols acting as their own schematics */
659 if (findsubschems(toppage
, cobj
, level
+ 1, pagelist
, dolinks
) == -1)
667 /*------------------------------------------------------*/
668 /* Recursively find all sub-circuits associated with */
669 /* the top-level circuit. For each schematic that does */
670 /* not have a valid filename, set the filename equal to */
671 /* the filename of the "toppage" schematic. */
672 /*------------------------------------------------------*/
674 void collectsubschems(int toppage
)
678 short *pagelist
, pageno
;
682 curpage
= xobjs
.pagelist
[loctop
];
683 if (curpage
->pageinst
== NULL
) return;
684 cschem
= curpage
->pageinst
->thisobject
;
685 if (cschem
->schemtype
== SECONDARY
) {
686 cschem
= cschem
->symschem
;
687 loctop
= is_page(cschem
);
688 if (loctop
< 0) return;
689 curpage
= xobjs
.pagelist
[loctop
];
692 pagelist
= (short *)malloc(xobjs
.pages
* sizeof(short));
694 for (pageno
= 0; pageno
< xobjs
.pages
; pageno
++)
695 pagelist
[pageno
] = 0;
697 findsubschems(loctop
, cschem
, 0, pagelist
, FALSE
);
699 for (pageno
= 0; pageno
< xobjs
.pages
; pageno
++) {
700 if (pageno
== loctop
) continue;
701 if (pagelist
[pageno
] > 0) {
702 if (xobjs
.pagelist
[pageno
]->filename
!= NULL
)
703 free(xobjs
.pagelist
[pageno
]->filename
);
704 xobjs
.pagelist
[pageno
]->filename
=
705 strdup(xobjs
.pagelist
[loctop
]->filename
);
708 free((char *)pagelist
);
711 /*------------------------------------------------------*/
712 /* compare_qualified(str1, str2) --- */
714 /* String comparison for technology-qualified */
715 /* names. str2" must be a fully-qualified name. */
716 /* "str1" may be qualified or unqualified. If */
717 /* unqualified, compare_qualified will return TRUE */
718 /* for any "str2" that matches the name part of */
719 /* the technology::name format. */
721 /* Return value: TRUE if match, FALSE if not. */
722 /*------------------------------------------------------*/
724 Boolean
compare_qualified(char *str1
, char *str2
)
727 Boolean qual1
, qual2
;
729 sptr2
= strstr(str2
, "::");
730 qual2
= (sptr2
== NULL
) ? FALSE
: TRUE
;
732 if (!qual2
) return (!strcmp(str1
, str2
));
734 sptr1
= strstr(str1
, "::");
735 qual1
= (sptr1
== NULL
) ? FALSE
: TRUE
;
737 if (qual1
) return (!strcmp(str1
, str2
));
740 return (!strcmp(str1
, sptr2
));
743 /*-------------------------------------------------------*/
744 /* Check if top-level page is the same name as a library */
745 /* object; if so, connect it. */
746 /* Note that it is not an error not to find the matching */
747 /* symbol/schematic. "is_schematic" and "is_symbol" */
748 /* comments in the .ps file are complementary, so the */
749 /* first one encountered will always fail, and the other */
751 /*-------------------------------------------------------*/
753 int checkschem(objectptr thisobj
, char *cname
)
758 if (thisobj
->symschem
!= NULL
) return 0;
760 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
761 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
762 tlib
= xobjs
.userlibs
[i
].library
+ j
;
764 if (compare_qualified(cname
, (*tlib
)->name
)) {
765 thisobj
->symschem
= (*tlib
);
766 thisobj
->schemtype
= PRIMARY
;
767 (*tlib
)->symschem
= thisobj
;
768 (*tlib
)->schemtype
= SYMBOL
;
776 /*--------------------------------------------------------*/
777 /* Complement to the above routine: If a library object */
778 /* name is the same as a top-level page, connect them. */
779 /*--------------------------------------------------------*/
781 int checksym(objectptr symobj
, char *cname
)
786 if (symobj
->symschem
!= NULL
) return 0;
788 for (cpage
= 0; cpage
< xobjs
.pages
; cpage
++) {
789 if (xobjs
.pagelist
[cpage
]->pageinst
!= NULL
) {
790 checkpage
= xobjs
.pagelist
[cpage
]->pageinst
->thisobject
;
791 if (compare_qualified(cname
, checkpage
->name
)) {
792 symobj
->symschem
= checkpage
;
793 symobj
->schemtype
= SYMBOL
;
794 checkpage
->symschem
= symobj
;
795 checkpage
->schemtype
= PRIMARY
;
803 /*----------------------------------------------------------------------*/
804 /* Find location of corresponding pin in symbol/schematic and change it */
805 /* to the text of the indicated label. */
807 /* Return the number of other pins changed. zero indicates that no */
808 /* corresponding pins were found, and therefore nothing was changed. */
809 /*----------------------------------------------------------------------*/
811 int changeotherpins(labelptr newlabel
, stringpart
*oldstring
)
813 objectptr other
= topobject
->symschem
;
818 if (other
== NULL
) return rval
;
820 for (tgen
= other
->plist
; tgen
< other
->plist
+ other
->parts
; tgen
++) {
821 if (IS_LABEL(*tgen
)) {
822 tlab
= TOLABEL(tgen
);
823 if (tlab
->pin
!= LOCAL
) continue;
824 if (!stringcomp(tlab
->string
, oldstring
)) {
825 if (newlabel
!= NULL
) {
827 tlab
->string
= stringcopy(newlabel
->string
);
836 /*----------------------------------------------------------------------*/
837 /* Xt wrapper for swapschem() */
838 /*----------------------------------------------------------------------*/
840 void xlib_swapschem(xcWidget w
, pointertype mode
, caddr_t calldata
)
842 swapschem((int)mode
, -1, NULL
);
845 /*----------------------------------------------------------------------*/
846 /* Swap object schematic and symbol pages. */
847 /* allow_create = 0 disallows creation of a new schematic or symbol; */
848 /* i.e., if there is no corresponding schematic/symbol, nothing */
850 /*----------------------------------------------------------------------*/
852 void swapschem(int allow_create
, int libnum
, char *fullname
)
854 objectptr savepage
= topobject
;
858 pushlistptr stacktop
;
859 short loclibnum
= libnum
;
862 if (libnum
== -1) loclibnum
= USERLIB
- LIBRARY
;
864 /* Create symbol or schematic, if allowed by allow_create */
866 if ((topobject
->symschem
== NULL
) && (allow_create
!= 0)
867 && (topobject
->schemtype
!= SECONDARY
)) {
869 if (topobject
->schemtype
!= PRIMARY
) {
872 /* create a new page for the new schematic */
874 for (tpage
= 0; tpage
< xobjs
.pages
; tpage
++)
875 if (xobjs
.pagelist
[tpage
]->pageinst
== NULL
) break;
877 /* Push the current instance onto the push stack */
878 /* Change the page without destroying the pushlist */
880 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
881 stacktop
= areawin
->stack
;
882 areawin
->stack
= NULL
;
884 areawin
->stack
= stacktop
;
887 objectptr
*newobject
;
889 /* create a new library object for the new symbol */
891 xobjs
.userlibs
[loclibnum
].library
= (objectptr
*)
892 realloc(xobjs
.userlibs
[loclibnum
].library
,
893 ++xobjs
.userlibs
[loclibnum
].number
* sizeof(objectptr
));
894 newobject
= xobjs
.userlibs
[loclibnum
].library
895 + xobjs
.userlibs
[loclibnum
].number
- 1;
896 *newobject
= (objectptr
) malloc(sizeof(object
));
898 (*newobject
)->schemtype
= SYMBOL
;
899 (*newobject
)->hidden
= False
;
901 incr_changes(*newobject
);
903 if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
)
904 standard_element_delete(ERASE
);
908 /* Generate a library instance for this object and set the */
909 /* top instance to point to it. */
911 topobject
->viewscale
= areawin
->vscale
;
912 topobject
->pcorner
= areawin
->pcorner
;
913 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
914 areawin
->topinstance
= addtoinstlist(loclibnum
, *newobject
, FALSE
);
916 /* Generate the default bounding box for a size-zero object */
917 calcbbox(areawin
->topinstance
);
920 /* set links between the two objects */
922 savepage
->symschem
= topobject
;
923 topobject
->symschem
= savepage
;
925 /* Make the name of the new object equal to that of the old, */
926 /* except that symbols get the full name while schematics */
927 /* get the canonical name (without the technology prefix) */
929 if (fullname
== NULL
)
930 canonname
= GetCanonicalName(savepage
->name
);
932 canonname
= strstr(fullname
, "::");
933 if ((canonname
== NULL
) || (topobject
->schemtype
!= PRIMARY
))
934 canonname
= fullname
;
938 strcpy(topobject
->name
, canonname
);
939 checkname(topobject
);
941 /* copy all pin labels into the new object */
943 for (plab
= savepage
->plist
; plab
< savepage
->plist
+ savepage
->parts
;
945 if (IS_LABEL(*plab
)) {
947 labelptr tlab
, lpin
= (labelptr
)*plab
;
949 if (lpin
->pin
== LOCAL
) {
951 /* Only make one copy of each pin name */
954 for (tgen
= topobject
->plist
; tgen
<
955 topobject
->plist
+ topobject
->parts
; tgen
++) {
956 if (IS_LABEL(*tgen
)) {
957 tlab
= TOLABEL(tgen
);
958 if (!stringcomp(tlab
->string
, lpin
->string
)) lflag
= True
;
961 if (lflag
== True
) continue;
963 NEW_LABEL(pinlab
, topobject
);
964 (*pinlab
)->pin
= lpin
->pin
;
965 (*pinlab
)->color
= lpin
->color
;
966 (*pinlab
)->rotation
= 0.0;
967 (*pinlab
)->scale
= 1.0;
968 (*pinlab
)->anchor
= areawin
->anchor
;
969 (*pinlab
)->position
.x
= 0;
970 (*pinlab
)->position
.y
= topobject
->parts
* (TEXTHEIGHT
+ 10);
971 (*pinlab
)->passed
= NULL
;
972 (*pinlab
)->cycle
= NULL
;
973 u2u_snap(&((*pinlab
)->position
));
974 (*pinlab
)->string
= stringcopy(lpin
->string
);
975 incr_changes(topobject
);
979 calcbbox(areawin
->topinstance
);
981 /* Recreate the user library with the new symbol */
982 if (savepage
->schemtype
!= SYMBOL
) composelib(loclibnum
+ LIBRARY
);
984 else if (topobject
->symschem
!= NULL
) {
986 /* If symschem matches the last entry on the push stack, then we */
987 /* pop; otherwise, we push. */
989 if (areawin
->stack
&& areawin
->stack
->thisinst
->thisobject
990 == topobject
->symschem
) {
991 topobject
->viewscale
= areawin
->vscale
;
992 topobject
->pcorner
= areawin
->pcorner
;
993 areawin
->topinstance
= areawin
->stack
->thisinst
;
994 pop_stack(&areawin
->stack
);
998 objinstptr syminst
= NULL
;
1001 /* If symschem is a schematic, find the appropriate page */
1003 for (p
= 0; p
< xobjs
.pages
; p
++) {
1004 syminst
= xobjs
.pagelist
[p
]->pageinst
;
1005 if (syminst
!= NULL
)
1006 if (syminst
->thisobject
== topobject
->symschem
)
1009 if (p
== xobjs
.pages
) {
1011 /* If symschem is a symbol, and it wasn't on the push stack, */
1012 /* get the library default symbol and go there. */
1014 for (p
= 0; p
< xobjs
.numlibs
; p
++) {
1015 for (symlist
= xobjs
.userlibs
[p
].instlist
; symlist
!= NULL
;
1016 symlist
= symlist
->next
) {
1017 syminst
= symlist
->thisinst
;
1018 if (syminst
->thisobject
== topobject
->symschem
&&
1019 symlist
->virtual == FALSE
)
1022 if (symlist
!= NULL
) break;
1024 if (p
== xobjs
.numlibs
) {
1025 Fprintf(stderr
, "swapschem(): BAD SYMSCHEM\n");
1030 if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
)
1031 delete_for_xfer(NORMAL
, areawin
->selectlist
, areawin
->selects
);
1033 topobject
->viewscale
= areawin
->vscale
;
1034 topobject
->pcorner
= areawin
->pcorner
;
1035 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
1036 areawin
->topinstance
= syminst
;
1040 /* If there was no action, then there is nothing more to do. */
1042 if (topobject
== savepage
) return;
1046 refresh(NULL
, NULL
, NULL
);
1052 /*----------------------------------------------------------------------*/
1053 /* Wrapper for swapschem() when generating a new symbol. */
1054 /*----------------------------------------------------------------------*/
1056 void makesymbol(xcWidget w
, caddr_t calldata
)
1058 /* copy name from popup prompt buffer and check */
1060 swapschem(1, -1, _STR2
);
1063 /*----------------------------------------------------------------------*/
1064 /* Check name before doing a swap: If name begins with "Page", prompt */
1065 /* for the object name, as you would when doing selectsave(). */
1066 /*----------------------------------------------------------------------*/
1068 void dobeforeswap(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
1070 buttonsave
*popdata
= (buttonsave
*)malloc(sizeof(buttonsave
));
1072 /* Check for requirement to change the name before creating the symbol */
1074 if ((topobject
->symschem
== NULL
) && (topobject
->schemtype
== PRIMARY
)
1075 && (strstr(topobject
->name
, "Page ") != NULL
)) {
1077 /* Get a name for the new object */
1079 eventmode
= NORMAL_MODE
;
1080 popdata
->dataptr
= NULL
;
1081 popdata
->button
= NULL
; /* indicates that no button is assc'd w/ the popup */
1082 popupprompt(w
, "Enter name for new object:", "\0", makesymbol
, popdata
, NULL
);
1085 swapschem(1, -1, NULL
);
1088 #endif /* !TCL_WRAPPER */
1090 /*------------------------------------------*/
1091 /* Disassociate a symbol from its schematic */
1092 /*------------------------------------------*/
1094 void schemdisassoc()
1096 if (eventmode
!= NORMAL
) {
1097 Wprintf("Cannot disassociate schematics in this mode");
1100 topobject
->symschem
->symschem
= NULL
;
1101 topobject
->symschem
= NULL
;
1103 Wprintf("Schematic and symbol are now unlinked.");
1107 /*--------------------------------------------------------------*/
1108 /* Schematic<-->symbol association. Determine whether action */
1109 /* acts on a symbol or a schematic from context. */
1110 /* mode == 0 associate only. */
1111 /* mode == 1 determine action (associate or disassociate) from */
1112 /* context (toggle) */
1113 /*--------------------------------------------------------------*/
1115 void startschemassoc(xcWidget w
, pointertype mode
, caddr_t calldata
)
1117 if ((topobject
->symschem
!= NULL
) && (mode
== 1))
1119 else if ((topobject
->symschem
!= NULL
) && (mode
== 0)) {
1120 Wprintf("Refusing to undo current association.");
1122 else if (topobject
->schemtype
== SECONDARY
) {
1123 Wprintf("Cannot attach symbol to a secondary schematic page.");
1126 eventmode
= ASSOC_MODE
;
1127 if (topobject
->schemtype
== PRIMARY
) {
1128 /* Find a symbol to associate */
1129 startcatalog(w
, LIBLIB
, NULL
);
1130 Wprintf("Select library page, then symbol to associate.");
1133 /* Find a schematic (page) to associate */
1134 startcatalog(w
, PAGELIB
, NULL
);
1135 Wprintf("Select schematic page to associate.");
1140 /*--------------------------------------------------------------*/
1141 /* Callback procedures on the schematic/symbol buttons. */
1142 /*--------------------------------------------------------------*/
1144 Boolean
schemassoc(objectptr schemobj
, objectptr symbolobj
)
1146 if (schemobj
->symschem
!= NULL
|| symbolobj
->symschem
!= NULL
) {
1147 Wprintf("Both objects must be disassociated first.");
1149 Tcl_SetResult(xcinterp
, "Both objects must be disassociated first.", NULL
);
1154 schemobj
->symschem
= symbolobj
;
1155 symbolobj
->symschem
= schemobj
;
1156 if (symbolobj
->schemtype
== TRIVIAL
)
1157 symbolobj
->schemtype
= SYMBOL
;
1159 /* Schematic takes the name of its associated symbol, by default */
1160 /* Don't copy any technology prefix. */
1161 strcpy(schemobj
->name
, GetCanonicalName(symbolobj
->name
));
1163 /* Ensure that schematic (page) name is unique */
1164 while (checkpagename(schemobj
) < 0);
1165 setsymschem(); /* Set buttons and menu items appropriately */
1170 /*-------------------------------------------------------------------------*/