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! */
125 /*----------------------------------------------------------------------*/
127 objectptr
NameToObject(char *objname
, objinstptr
*ret_inst
, Boolean dopages
)
131 Boolean notech
= FALSE
;
134 if (strstr(objname
, "::") == NULL
) notech
= TRUE
;
136 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
137 for (spec
= xobjs
.userlibs
[i
].instlist
; spec
!= NULL
; spec
= spec
->next
) {
138 techptr
= spec
->thisinst
->thisobject
->name
;
140 techptr
= GetCanonicalName(spec
->thisinst
->thisobject
->name
);
141 if (!strcmp(objname
, techptr
)) {
142 if (ret_inst
) *ret_inst
= spec
->thisinst
;
143 return spec
->thisinst
->thisobject
;
149 return NameToPageObject(objname
, ret_inst
, NULL
);
154 /*------------------------------------------------------------------------*/
155 /* Ensure that a page name is unique (required for schematic association) */
156 /*------------------------------------------------------------------------*/
158 int checkpagename(objectptr thispageobj
)
161 /* char *objname = thispageobj->name; (jdk) */
163 Boolean update
= False
;
167 /* Check for ":n" suffix and prepare for possible update */
168 clnptr
= strrchr(thispageobj
->name
, ':');
170 if (sscanf(clnptr
+ 1, "%d", &n
) != 1)
173 /* Find the page number of this page object */
174 for (p
= 0; p
< xobjs
.pages
; p
++) {
175 if (xobjs
.pagelist
[p
]->pageinst
!= NULL
) {
176 if (xobjs
.pagelist
[p
]->pageinst
->thisobject
== thispageobj
) {
182 if (p
== xobjs
.pages
) {
183 Fprintf(stderr
, "Error: Object is not a page object!\n");
187 /* Look for any other pages with the same name */
190 for (p
= 0; p
< xobjs
.pages
; p
++) {
191 if (p
== thispage
) continue;
192 if (xobjs
.pagelist
[p
]->pageinst
!= NULL
) {
193 if (!filecmp(xobjs
.pagelist
[p
]->pageinst
->thisobject
->name
,
194 thispageobj
->name
)) {
195 /* append ":2" to name or update suffix to ensure uniqueness */
197 sprintf(thispageobj
->name
, "%s:2", thispageobj
->name
);
199 sprintf(clnptr
+ 1, "%d", n
+ 1);
208 renamepage(thispage
);
214 /*--------------------------------------*/
215 /* Find connectivity of a selection */
216 /*--------------------------------------*/
218 void startconnect(xcWidget button
, caddr_t clientdata
, caddr_t calldata
)
220 if (areawin
->selects
> 0)
221 connectivity(button
, clientdata
, calldata
);
224 /*----------------------------------------------------------------------*/
225 /* connectivity(): Find electrical connections into a node. */
226 /* (does recursive search on object heirarchy) */
227 /*----------------------------------------------------------------------*/
229 void connectivity(xcWidget button
, caddr_t clientdata
, caddr_t calldata
)
232 selection
*rselect
= NULL
, *nextselect
;
233 genericptr ggen
= NULL
;
234 Genericlist
*netlist
= NULL
;
235 int depth
, lbus
, netid
, subnetid
;
237 pushlistptr seltop
, nextptr
;
238 objectptr nettop
, pschem
; /* thisobj, (jdk) */
242 /* erase any existing highlighted network */
243 highlightnetlist(topobject
, areawin
->topinstance
, 0);
245 seltop
= (pushlistptr
)malloc(sizeof(pushlist
));
246 seltop
->thisinst
= areawin
->topinstance
;
249 /* pick the first selection that looks like a valid network part */
251 if (areawin
->selects
> 0) {
252 for (gsel
= areawin
->selectlist
; gsel
< areawin
->selectlist
+
253 areawin
->selects
; gsel
++) {
254 ggen
= *(topobject
->plist
+ *gsel
);
255 if (SELECTTYPE(gsel
) == LABEL
) {
256 labelptr glab
= SELTOLABEL(gsel
);
257 if (glab
->pin
== LOCAL
|| glab
->pin
== GLOBAL
) break;
259 else if (SELECTTYPE(gsel
) == POLYGON
) {
260 polyptr gpoly
= SELTOPOLY(gsel
);
261 if (!nonnetwork(gpoly
)) break;
265 if ((areawin
->selects
== 0) || (gsel
== areawin
->selectlist
266 + areawin
->selects
)) {
267 rselect
= recurselect(POLYGON
| LABEL
| OBJINST
, MODE_CONNECT
, &seltop
);
268 /* Should look at the top scorer, when scoring has been implemented */
269 if (rselect
&& (rselect
->selects
> 0)) {
270 for (nextselect
= rselect
; (nextselect
->next
!= NULL
) &&
271 (nextselect
->selects
> 0); nextselect
= nextselect
->next
);
272 ggen
= *(nextselect
->thisinst
->thisobject
->plist
+ *(nextselect
->selectlist
));
273 while (rselect
!= NULL
) {
274 nextselect
= rselect
->next
;
275 free(rselect
->selectlist
);
277 rselect
= nextselect
;
282 /* Determine the net and the topmost object in which that */
283 /* net appears. Then build the transformation matrix down */
284 /* to that object. highlightnet() should end by popping the */
285 /* entire matrix stack. */
288 if (checkvalid(topobject
) == -1) {
289 destroynets(topobject
);
290 createnets(areawin
->topinstance
, FALSE
);
292 if ((netlist
= is_resolved(&ggen
, seltop
, &nettop
)) != NULL
) {
293 depth
= pushnetwork(seltop
, nettop
);
294 /* Fprintf(stdout, ">> Pushed network %d levels deep\n", depth); */
296 while (nextptr
->thisinst
->thisobject
!= nettop
)
297 nextptr
= nextptr
->next
;
299 nextptr
->thisinst
->thisobject
->highlight
.netlist
= netlist
;
300 nextptr
->thisinst
->thisobject
->highlight
.thisinst
= nextptr
->thisinst
;
301 highlightnetlist(nettop
, nextptr
->thisinst
, 1);
303 /* pop the matrix stack */
307 /* get the primary schematic */
308 pschem
= (nettop
->schemtype
== SECONDARY
) ? nettop
->symschem
: nettop
;
310 /* print the net name to the message window */
312 if (netlist
->subnets
== 0) {
313 ppin
= nettopin(netlist
->net
.id
, pschem
, NULL
);
314 snew
= textprint(ppin
, areawin
->topinstance
);
315 sprintf(_STR2
, "Network is \"%s\" in %s", snew
, nettop
->name
);
320 sprintf(_STR2
, "Network(s): ");
321 sptr
= _STR2
+ strlen(_STR2
);
322 for (lbus
= 0; lbus
< netlist
->subnets
; lbus
++) {
323 sbus
= netlist
->net
.list
+ lbus
;
325 subnetid
= sbus
->subnetid
;
326 ppin
= nettopin(netid
, pschem
, NULL
);
327 snew
= textprintsubnet(ppin
, areawin
->topinstance
, subnetid
);
328 sprintf(sptr
, "%s ", snew
);
329 sptr
+= strlen(snew
) + 1;
332 sprintf(sptr
, "in %s", nettop
->name
);
334 Wprintf("%s", _STR2
);
337 Tcl_SetObjResult(xcinterp
, Tcl_NewStringObj(snew
, strlen(snew
)));
341 Wprintf("Selected element is not part of a valid network.");
344 Wprintf("No networks found near the cursor position");
348 /* free up linked list */
350 while (seltop
!= NULL
) {
351 nextptr
= seltop
->next
;
357 /*--------------------------------------------------------------*/
358 /* Set object type to FUNDAMENTAL if it contains one or more */
359 /* info labels and is not associated with a schematic/symbol. */
361 /* Return TRUE if the object has electrically relevant */
362 /* networks, FALSE if not. */
363 /*--------------------------------------------------------------*/
365 Boolean
setobjecttype(objectptr cschem
)
370 /* If networks are specifically prohibited. . . */
371 if (cschem
->schemtype
== NONETWORK
) return False
;
373 /* Apply only to schematic objects */
375 if ((cschem
->schemtype
!= PRIMARY
) && (cschem
->schemtype
!= SECONDARY
)) {
376 if (cschem
->schemtype
== FUNDAMENTAL
)
377 cschem
->schemtype
= SYMBOL
;
378 if (cschem
->symschem
== NULL
) {
379 for (cgen
= cschem
->plist
; cgen
< cschem
->plist
+ cschem
->parts
; cgen
++) {
380 if (IS_LABEL(*cgen
)) {
381 clab
= TOLABEL(cgen
);
382 if (clab
->pin
== INFO
) {
383 cschem
->schemtype
= FUNDAMENTAL
;
391 if ((cschem
->symschem
!= NULL
) && (cschem
->schemtype
== SYMBOL
))
393 else if ((cschem
->schemtype
== TRIVIAL
) || (cschem
->schemtype
== FUNDAMENTAL
))
399 /*------------------------------------------------------*/
400 /* Pin conversion subroutine for dopintype() */
401 /*------------------------------------------------------*/
403 void pinconvert(labelptr thislab
, pointertype mode
)
408 thislab
->color
= DEFAULTCOLOR
; /* nominally black */
411 thislab
->color
= GLOBALPINCOLOR
; /* orange */
414 thislab
->color
= LOCALPINCOLOR
; /* red */
417 thislab
->color
= INFOLABELCOLOR
; /* green */
422 /*---------------------------------------------------------*/
423 /* Change a label's type to NORMAL, GLOBAL, INFO, or LOCAL */
424 /*---------------------------------------------------------*/
426 void dopintype(xcWidget w
, pointertype mode
, caddr_t calldata
)
432 if (areawin
->selects
== 0) {
433 Wprintf("Must first select a label to change type");
437 strcpy(typestr
, "Changed label to ");
440 strcat(typestr
, "normal label");
443 strcat(typestr
, "global pin");
446 strcat(typestr
, "local pin");
449 strcat(typestr
, "info-label");
453 for (gsel
= areawin
->selectlist
; gsel
< areawin
->selectlist
+
454 areawin
->selects
; gsel
++)
455 if (SELECTTYPE(gsel
) == LABEL
) {
456 labelptr glab
= SELTOLABEL(gsel
);
457 savetype
= glab
->pin
;
458 pinconvert(glab
, mode
);
459 setobjecttype(topobject
);
464 drawarea(NULL
, NULL
, NULL
);
465 Wprintf("%s", typestr
);
468 Wprintf("No labels selected.");
472 /*----------------------------------------------------------*/
473 /* Set colors on the symbol/schematic buttons appropriately */
474 /*----------------------------------------------------------*/
480 XcInternalTagCall(xcinterp
, 1, "schematic");
487 Arg aargs
[2], bargs
[2];
489 /* Set menu items appropriately for this object */
491 if (topobject
->symschem
!= NULL
) {
492 if (topobject
->schemtype
== PRIMARY
|| topobject
->schemtype
== SECONDARY
) {
493 XtSetArg(aargs
[0], XtNlabel
, "Go To Symbol");
494 XtSetArg(bargs
[0], XtNlabel
, "Disassociate Symbol");
497 XtSetArg(aargs
[0], XtNlabel
, "Go To Schematic");
498 XtSetArg(bargs
[0], XtNlabel
, "Disassociate Schematic");
502 if (topobject
->schemtype
== PRIMARY
|| topobject
->schemtype
== SECONDARY
) {
503 XtSetArg(aargs
[0], XtNlabel
, "Make Matching Symbol");
504 XtSetArg(bargs
[0], XtNlabel
, "Associate with Symbol");
507 XtSetArg(aargs
[0], XtNlabel
, "Make Matching Schematic");
508 XtSetArg(bargs
[0], XtNlabel
, "Associate with Schematic");
511 XtSetValues(NetlistMakeMatchingSymbolButton
, aargs
, 1);
512 XtSetValues(NetlistAssociatewithSymbolButton
, bargs
, 1);
514 /* Set colors on the symbol and schematic buttons */
516 if (topobject
->schemtype
== PRIMARY
|| topobject
->schemtype
== SECONDARY
) {
517 if (topobject
->symschem
== NULL
) {
518 XtSetArg(aargs
[0], XtNbackground
, colorlist
[OFFBUTTONCOLOR
].color
.pixel
);
519 XtSetArg(aargs
[1], XtNforeground
, colorlist
[OFFBUTTONCOLOR
].color
.pixel
);
522 XtSetArg(aargs
[0], XtNbackground
, colorlist
[BACKGROUND
].color
.pixel
);
523 XtSetArg(aargs
[1], XtNforeground
, colorlist
[FOREGROUND
].color
.pixel
);
526 XtSetArg(bargs
[1], XtNforeground
, colorlist
[FOREGROUND
].color
.pixel
);
527 XtSetArg(bargs
[0], XtNbackground
, colorlist
[SNAPCOLOR
].color
.pixel
);
530 if (topobject
->symschem
!= NULL
) {
531 XtSetArg(bargs
[0], XtNbackground
, colorlist
[BACKGROUND
].color
.pixel
);
532 XtSetArg(bargs
[1], XtNforeground
, colorlist
[FOREGROUND
].color
.pixel
);
535 XtSetArg(bargs
[0], XtNbackground
, colorlist
[OFFBUTTONCOLOR
].color
.pixel
);
536 XtSetArg(bargs
[1], XtNforeground
, colorlist
[OFFBUTTONCOLOR
].color
.pixel
);
539 XtSetArg(aargs
[1], XtNforeground
, colorlist
[FOREGROUND
].color
.pixel
);
540 if (topobject
->schemtype
== FUNDAMENTAL
)
541 XtSetArg(aargs
[0], XtNbackground
, colorlist
[AUXCOLOR
].color
.pixel
);
542 else if (topobject
->schemtype
== TRIVIAL
|| topobject
->symschem
!= NULL
)
543 XtSetArg(aargs
[0], XtNbackground
, colorlist
[SNAPCOLOR
].color
.pixel
);
545 XtSetArg(aargs
[0], XtNbackground
, colorlist
[OFFBUTTONCOLOR
].color
.pixel
);
546 XtSetArg(aargs
[1], XtNforeground
, colorlist
[OFFBUTTONCOLOR
].color
.pixel
);
547 XtSetArg(bargs
[0], XtNbackground
, colorlist
[BBOXCOLOR
].color
.pixel
);
548 XtSetArg(bargs
[1], XtNforeground
, colorlist
[FOREGROUND
].color
.pixel
);
552 XtSetValues(wsymb
, aargs
, 2);
553 XtSetValues(wschema
, bargs
, 2);
558 /*--------------------------------------------------------*/
559 /* Find the page number for an object */
560 /*--------------------------------------------------------*/
562 int findpageobj(objectptr pobj
)
566 for (tpage
= 0; tpage
< xobjs
.pages
; tpage
++)
567 if (xobjs
.pagelist
[tpage
]->pageinst
!= NULL
)
568 if (xobjs
.pagelist
[tpage
]->pageinst
->thisobject
== pobj
)
574 /*------------------------------------------------------*/
575 /* Enumerate all of the pages which are subschematics */
576 /* of "toppage" and return the result in the list */
577 /* passed as a pointer. The list is assumed to be */
578 /* already allocated, and equal to the total number of */
579 /* pages (xobjs.pages). */
581 /* Avoid possible recursion problems by limiting the */
582 /* number of recursion levels. Presumably no circuit */
583 /* would have more than several hundred hierarchical */
586 /* If "dolinks" is TRUE, ennumerate and follow pages */
587 /* that are descendents of the top level when the */
588 /* calling symbol instance has a "link" parameter and */
589 /* that parameter points to the same filename as the */
590 /* page. This indicates a multiple-file project; the */
591 /* pages keep separate records of changes, and are */
592 /* saved independently, and loaded through the link */
593 /* dependency method. */
594 /*------------------------------------------------------*/
596 int findsubschems(int toppage
, objectptr cschem
, int level
, short *pagelist
,
601 if (level
== HIERARCHY_LIMIT
) return -1; /* sanity check */
603 for (cgen
= cschem
->plist
; cgen
< cschem
->plist
+ cschem
->parts
; cgen
++) {
604 if (IS_OBJINST(*cgen
)) {
605 objinstptr cinst
= TOOBJINST(cgen
);
606 objectptr cobj
= cinst
->thisobject
;
608 if (cobj
->symschem
!= NULL
) {
609 int pageno
= findpageobj(cobj
->symschem
);
611 if ((pageno
>= 0) && (pageno
< xobjs
.pages
)) {
613 /* Look for a "link" parameter */
614 if (dolinks
== FALSE
) {
616 ops
= find_param(cinst
, "link");
617 if ((ops
!= NULL
) && (ops
->type
== XC_STRING
)) {
618 char *filename
= textprint(ops
->parameter
.string
, cinst
);
619 if (!strcmp(filename
, "%n") || !strcmp(filename
, "%N") ||
620 !strcmp(filename
, xobjs
.pagelist
[pageno
]->filename
)) {
628 /* Add this page to the list */
632 /* A symbol on its own schematic page is allowed for clarity */
633 /* of the schematic, but this cannot be a functional part of */
634 /* the schematic circuit! */
636 if (cobj
->symschem
!= cschem
) {
637 if (findsubschems(toppage
, cobj
->symschem
,
638 level
+ 1, pagelist
, dolinks
) == -1)
642 else if (cobj
->schemtype
!= FUNDAMENTAL
&& cobj
->schemtype
!= TRIVIAL
) {
643 /* Check symbols acting as their own schematics */
644 if (findsubschems(toppage
, cobj
, level
+ 1, pagelist
, dolinks
) == -1)
652 /*------------------------------------------------------*/
653 /* Recursively find all sub-circuits associated with */
654 /* the top-level circuit. For each schematic that does */
655 /* not have a valid filename, set the filename equal to */
656 /* the filename of the "toppage" schematic. */
657 /*------------------------------------------------------*/
659 void collectsubschems(int toppage
)
663 short *pagelist
, pageno
;
667 curpage
= xobjs
.pagelist
[loctop
];
668 if (curpage
->pageinst
== NULL
) return;
669 cschem
= curpage
->pageinst
->thisobject
;
670 if (cschem
->schemtype
== SECONDARY
) {
671 cschem
= cschem
->symschem
;
672 loctop
= is_page(cschem
);
673 if (loctop
< 0) return;
674 curpage
= xobjs
.pagelist
[loctop
];
677 pagelist
= (short *)malloc(xobjs
.pages
* sizeof(short));
679 for (pageno
= 0; pageno
< xobjs
.pages
; pageno
++)
680 pagelist
[pageno
] = 0;
682 findsubschems(loctop
, cschem
, 0, pagelist
, FALSE
);
684 for (pageno
= 0; pageno
< xobjs
.pages
; pageno
++) {
685 if (pageno
== loctop
) continue;
686 if (pagelist
[pageno
] > 0) {
687 if (xobjs
.pagelist
[pageno
]->filename
!= NULL
)
688 free(xobjs
.pagelist
[pageno
]->filename
);
689 xobjs
.pagelist
[pageno
]->filename
=
690 strdup(xobjs
.pagelist
[loctop
]->filename
);
693 free((char *)pagelist
);
696 /*------------------------------------------------------*/
697 /* compare_qualified(str1, str2) --- */
699 /* String comparison for technology-qualified */
700 /* names. str2" must be a fully-qualified name. */
701 /* "str1" may be qualified or unqualified. If */
702 /* unqualified, compare_qualified will return TRUE */
703 /* for any "str2" that matches the name part of */
704 /* the technology::name format. */
706 /* Return value: TRUE if match, FALSE if not. */
707 /*------------------------------------------------------*/
709 Boolean
compare_qualified(char *str1
, char *str2
)
712 Boolean qual1
, qual2
;
714 sptr2
= strstr(str2
, "::");
715 qual2
= (sptr2
== NULL
) ? FALSE
: TRUE
;
717 if (!qual2
) return (!strcmp(str1
, str2
));
719 sptr1
= strstr(str1
, "::");
720 qual1
= (sptr1
== NULL
) ? FALSE
: TRUE
;
722 if (qual1
) return (!strcmp(str1
, str2
));
725 return (!strcmp(str1
, sptr2
));
728 /*-------------------------------------------------------*/
729 /* Check if top-level page is the same name as a library */
730 /* object; if so, connect it. */
731 /* Note that it is not an error not to find the matching */
732 /* symbol/schematic. "is_schematic" and "is_symbol" */
733 /* comments in the .ps file are complementary, so the */
734 /* first one encountered will always fail, and the other */
736 /*-------------------------------------------------------*/
738 int checkschem(objectptr thisobj
, char *cname
)
743 if (thisobj
->symschem
!= NULL
) return 0;
745 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
746 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
747 tlib
= xobjs
.userlibs
[i
].library
+ j
;
749 if (compare_qualified(cname
, (*tlib
)->name
)) {
750 thisobj
->symschem
= (*tlib
);
751 thisobj
->schemtype
= PRIMARY
;
752 (*tlib
)->symschem
= thisobj
;
753 (*tlib
)->schemtype
= SYMBOL
;
761 /*--------------------------------------------------------*/
762 /* Complement to the above routine: If a library object */
763 /* name is the same as a top-level page, connect them. */
764 /*--------------------------------------------------------*/
766 int checksym(objectptr symobj
, char *cname
)
771 if (symobj
->symschem
!= NULL
) return 0;
773 for (cpage
= 0; cpage
< xobjs
.pages
; cpage
++) {
774 if (xobjs
.pagelist
[cpage
]->pageinst
!= NULL
) {
775 checkpage
= xobjs
.pagelist
[cpage
]->pageinst
->thisobject
;
776 if (compare_qualified(cname
, checkpage
->name
)) {
777 symobj
->symschem
= checkpage
;
778 symobj
->schemtype
= SYMBOL
;
779 checkpage
->symschem
= symobj
;
780 checkpage
->schemtype
= PRIMARY
;
788 /*----------------------------------------------------------------------*/
789 /* Find location of corresponding pin in symbol/schematic and change it */
790 /* to the text of the indicated label. */
792 /* Return the number of other pins changed. zero indicates that no */
793 /* corresponding pins were found, and therefore nothing was changed. */
794 /*----------------------------------------------------------------------*/
796 int changeotherpins(labelptr newlabel
, stringpart
*oldstring
)
798 objectptr other
= topobject
->symschem
;
803 if (other
== NULL
) return rval
;
805 for (tgen
= other
->plist
; tgen
< other
->plist
+ other
->parts
; tgen
++) {
806 if (IS_LABEL(*tgen
)) {
807 tlab
= TOLABEL(tgen
);
808 if (tlab
->pin
!= LOCAL
) continue;
809 if (!stringcomp(tlab
->string
, oldstring
)) {
810 if (newlabel
!= NULL
) {
812 tlab
->string
= stringcopy(newlabel
->string
);
821 /*----------------------------------------------------------------------*/
822 /* Xt wrapper for swapschem() */
823 /*----------------------------------------------------------------------*/
825 void xlib_swapschem(xcWidget w
, pointertype mode
, caddr_t calldata
)
827 swapschem((int)mode
, -1, NULL
);
830 /*----------------------------------------------------------------------*/
831 /* Swap object schematic and symbol pages. */
832 /* allow_create = 0 disallows creation of a new schematic or symbol; */
833 /* i.e., if there is no corresponding schematic/symbol, nothing */
835 /*----------------------------------------------------------------------*/
837 void swapschem(int allow_create
, int libnum
, char *fullname
)
839 objectptr savepage
= topobject
;
843 pushlistptr stacktop
;
844 short loclibnum
= libnum
;
847 if (libnum
== -1) loclibnum
= USERLIB
- LIBRARY
;
849 /* Create symbol or schematic, if allowed by allow_create */
851 if ((topobject
->symschem
== NULL
) && (allow_create
!= 0)
852 && (topobject
->schemtype
!= SECONDARY
)) {
854 if (topobject
->schemtype
!= PRIMARY
) {
857 /* create a new page for the new schematic */
859 for (tpage
= 0; tpage
< xobjs
.pages
; tpage
++)
860 if (xobjs
.pagelist
[tpage
]->pageinst
== NULL
) break;
862 /* Push the current instance onto the push stack */
863 /* Change the page without destroying the pushlist */
865 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
866 stacktop
= areawin
->stack
;
867 areawin
->stack
= NULL
;
869 areawin
->stack
= stacktop
;
872 objectptr
*newobject
;
874 /* create a new library object for the new symbol */
876 xobjs
.userlibs
[loclibnum
].library
= (objectptr
*)
877 realloc(xobjs
.userlibs
[loclibnum
].library
,
878 ++xobjs
.userlibs
[loclibnum
].number
* sizeof(objectptr
));
879 newobject
= xobjs
.userlibs
[loclibnum
].library
880 + xobjs
.userlibs
[loclibnum
].number
- 1;
881 *newobject
= (objectptr
) malloc(sizeof(object
));
883 (*newobject
)->schemtype
= SYMBOL
;
884 (*newobject
)->hidden
= False
;
886 incr_changes(*newobject
);
888 if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
)
889 standard_element_delete(ERASE
);
893 /* Generate a library instance for this object and set the */
894 /* top instance to point to it. */
896 topobject
->viewscale
= areawin
->vscale
;
897 topobject
->pcorner
= areawin
->pcorner
;
898 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
899 areawin
->topinstance
= addtoinstlist(loclibnum
, *newobject
, FALSE
);
901 /* Generate the default bounding box for a size-zero object */
902 calcbbox(areawin
->topinstance
);
905 /* set links between the two objects */
907 savepage
->symschem
= topobject
;
908 topobject
->symschem
= savepage
;
910 /* Make the name of the new object equal to that of the old, */
911 /* except that symbols get the full name while schematics */
912 /* get the canonical name (without the technology prefix) */
914 if (fullname
== NULL
)
915 canonname
= GetCanonicalName(savepage
->name
);
917 canonname
= strstr(fullname
, "::");
918 if ((canonname
== NULL
) || (topobject
->schemtype
!= PRIMARY
))
919 canonname
= fullname
;
923 strcpy(topobject
->name
, canonname
);
924 checkname(topobject
);
926 /* copy all pin labels into the new object */
928 for (plab
= savepage
->plist
; plab
< savepage
->plist
+ savepage
->parts
;
930 if (IS_LABEL(*plab
)) {
932 labelptr tlab
, lpin
= (labelptr
)*plab
;
934 if (lpin
->pin
== LOCAL
) {
936 /* Only make one copy of each pin name */
939 for (tgen
= topobject
->plist
; tgen
<
940 topobject
->plist
+ topobject
->parts
; tgen
++) {
941 if (IS_LABEL(*tgen
)) {
942 tlab
= TOLABEL(tgen
);
943 if (!stringcomp(tlab
->string
, lpin
->string
)) lflag
= True
;
946 if (lflag
== True
) continue;
948 NEW_LABEL(pinlab
, topobject
);
949 (*pinlab
)->pin
= lpin
->pin
;
950 (*pinlab
)->color
= lpin
->color
;
951 (*pinlab
)->rotation
= 0.0;
952 (*pinlab
)->scale
= 1.0;
953 (*pinlab
)->anchor
= areawin
->anchor
;
954 (*pinlab
)->position
.x
= 0;
955 (*pinlab
)->position
.y
= topobject
->parts
* (TEXTHEIGHT
+ 10);
956 (*pinlab
)->passed
= NULL
;
957 (*pinlab
)->cycle
= NULL
;
958 u2u_snap(&((*pinlab
)->position
));
959 (*pinlab
)->string
= stringcopy(lpin
->string
);
960 incr_changes(topobject
);
964 calcbbox(areawin
->topinstance
);
966 /* Recreate the user library with the new symbol */
967 if (savepage
->schemtype
!= SYMBOL
) composelib(loclibnum
+ LIBRARY
);
969 else if (topobject
->symschem
!= NULL
) {
971 /* If symschem matches the last entry on the push stack, then we */
972 /* pop; otherwise, we push. */
974 if (areawin
->stack
&& areawin
->stack
->thisinst
->thisobject
975 == topobject
->symschem
) {
976 topobject
->viewscale
= areawin
->vscale
;
977 topobject
->pcorner
= areawin
->pcorner
;
978 areawin
->topinstance
= areawin
->stack
->thisinst
;
979 pop_stack(&areawin
->stack
);
983 objinstptr syminst
= NULL
;
986 /* If symschem is a schematic, find the appropriate page */
988 for (p
= 0; p
< xobjs
.pages
; p
++) {
989 syminst
= xobjs
.pagelist
[p
]->pageinst
;
991 if (syminst
->thisobject
== topobject
->symschem
)
994 if (p
== xobjs
.pages
) {
996 /* If symschem is a symbol, and it wasn't on the push stack, */
997 /* get the library default symbol and go there. */
999 for (p
= 0; p
< xobjs
.numlibs
; p
++) {
1000 for (symlist
= xobjs
.userlibs
[p
].instlist
; symlist
!= NULL
;
1001 symlist
= symlist
->next
) {
1002 syminst
= symlist
->thisinst
;
1003 if (syminst
->thisobject
== topobject
->symschem
&&
1004 symlist
->virtual == FALSE
)
1007 if (symlist
!= NULL
) break;
1009 if (p
== xobjs
.numlibs
) {
1010 Fprintf(stderr
, "swapschem(): BAD SYMSCHEM\n");
1015 if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
)
1016 delete_for_xfer(NORMAL
, areawin
->selectlist
, areawin
->selects
);
1018 topobject
->viewscale
= areawin
->vscale
;
1019 topobject
->pcorner
= areawin
->pcorner
;
1020 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
1021 areawin
->topinstance
= syminst
;
1025 /* If there was no action, then there is nothing more to do. */
1027 if (topobject
== savepage
) return;
1031 refresh(NULL
, NULL
, NULL
);
1037 /*----------------------------------------------------------------------*/
1038 /* Wrapper for swapschem() when generating a new symbol. */
1039 /*----------------------------------------------------------------------*/
1041 void makesymbol(xcWidget w
, caddr_t calldata
)
1043 /* copy name from popup prompt buffer and check */
1045 swapschem(1, -1, _STR2
);
1048 /*----------------------------------------------------------------------*/
1049 /* Check name before doing a swap: If name begins with "Page", prompt */
1050 /* for the object name, as you would when doing selectsave(). */
1051 /*----------------------------------------------------------------------*/
1053 void dobeforeswap(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
1055 buttonsave
*popdata
= (buttonsave
*)malloc(sizeof(buttonsave
));
1057 /* Check for requirement to change the name before creating the symbol */
1059 if ((topobject
->symschem
== NULL
) && (topobject
->schemtype
== PRIMARY
)
1060 && (strstr(topobject
->name
, "Page ") != NULL
)) {
1062 /* Get a name for the new object */
1064 eventmode
= NORMAL_MODE
;
1065 popdata
->dataptr
= NULL
;
1066 popdata
->button
= NULL
; /* indicates that no button is assc'd w/ the popup */
1067 popupprompt(w
, "Enter name for new object:", "\0", makesymbol
, popdata
, NULL
);
1070 swapschem(1, -1, NULL
);
1073 #endif /* !TCL_WRAPPER */
1075 /*------------------------------------------*/
1076 /* Disassociate a symbol from its schematic */
1077 /*------------------------------------------*/
1079 void schemdisassoc()
1081 if (eventmode
!= NORMAL
) {
1082 Wprintf("Cannot disassociate schematics in this mode");
1085 topobject
->symschem
->symschem
= NULL
;
1086 topobject
->symschem
= NULL
;
1088 Wprintf("Schematic and symbol are now unlinked.");
1092 /*--------------------------------------------------------------*/
1093 /* Schematic<-->symbol association. Determine whether action */
1094 /* acts on a symbol or a schematic from context. */
1095 /* mode == 0 associate only. */
1096 /* mode == 1 determine action (associate or disassociate) from */
1097 /* context (toggle) */
1098 /*--------------------------------------------------------------*/
1100 void startschemassoc(xcWidget w
, pointertype mode
, caddr_t calldata
)
1102 if ((topobject
->symschem
!= NULL
) && (mode
== 1))
1104 else if ((topobject
->symschem
!= NULL
) && (mode
== 0)) {
1105 Wprintf("Refusing to undo current association.");
1107 else if (topobject
->schemtype
== SECONDARY
) {
1108 Wprintf("Cannot attach symbol to a secondary schematic page.");
1111 eventmode
= ASSOC_MODE
;
1112 if (topobject
->schemtype
== PRIMARY
) {
1113 /* Find a symbol to associate */
1114 startcatalog(w
, LIBLIB
, NULL
);
1115 Wprintf("Select library page, then symbol to associate.");
1118 /* Find a schematic (page) to associate */
1119 startcatalog(w
, PAGELIB
, NULL
);
1120 Wprintf("Select schematic page to associate.");
1125 /*--------------------------------------------------------------*/
1126 /* Callback procedures on the schematic/symbol buttons. */
1127 /*--------------------------------------------------------------*/
1129 Boolean
schemassoc(objectptr schemobj
, objectptr symbolobj
)
1131 if (schemobj
->symschem
!= NULL
|| symbolobj
->symschem
!= NULL
) {
1132 Wprintf("Both objects must be disassociated first.");
1134 Tcl_SetResult(xcinterp
, "Both objects must be disassociated first.", NULL
);
1139 schemobj
->symschem
= symbolobj
;
1140 symbolobj
->symschem
= schemobj
;
1141 if (symbolobj
->schemtype
== TRIVIAL
)
1142 symbolobj
->schemtype
= SYMBOL
;
1144 /* Schematic takes the name of its associated symbol, by default */
1145 /* Don't copy any technology prefix. */
1146 strcpy(schemobj
->name
, GetCanonicalName(symbolobj
->name
));
1148 /* Ensure that schematic (page) name is unique */
1149 while (checkpagename(schemobj
) < 0);
1150 setsymschem(); /* Set buttons and menu items appropriately */
1155 /*-------------------------------------------------------------------------*/