1 /*-----------------------------------------------------------------------*/
2 /* files.c --- file handling routines for xcircuit */
3 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
4 /*-----------------------------------------------------------------------*/
14 #include <sys/types.h>
19 #include <X11/Intrinsic.h>
20 #include <X11/StringDefs.h>
29 #include "Xw/TextEdit.h" /* for XwTextCopyBuffer() */
33 /*------------------------------------------------------------------------*/
35 /*------------------------------------------------------------------------*/
37 #include "colordefs.h"
40 /*----------------------------------------------------------------------*/
41 /* Function prototype declarations */
42 /*----------------------------------------------------------------------*/
43 #include "prototypes.h"
46 extern void Route(XCWindowData
*, Boolean
);
47 extern int ReadSpice(FILE *);
50 /*------------------------------------------------------------------------*/
51 /* Useful (local) defines */
52 /*------------------------------------------------------------------------*/
54 #define OUTPUTWIDTH 80 /* maximum text width of output */
56 #define S_OBLIQUE 13 /* position of Symbol-Oblique in font array */
58 /*------------------------------------------------------------------------*/
59 /* External Variable definitions */
60 /*------------------------------------------------------------------------*/
63 extern Tcl_Interp
*xcinterp
;
66 extern char _STR2
[250], _STR
[150];
67 extern Globaldata xobjs
;
68 extern XCWindowData
*areawin
;
69 extern fontinfo
*fonts
;
70 extern short fontcount
;
71 extern Cursor appcursors
[NUM_CURSORS
];
72 extern XtAppContext app
;
76 extern int number_colors
;
77 extern colorindex
*colorlist
;
80 /*------------------------------------------------------*/
81 /* Global variable definitions */
82 /*------------------------------------------------------*/
84 Boolean load_in_progress
= False
;
87 /* Structure for remembering what names refer to the same object */
91 /*------------------------------------------------------*/
92 /* Utility routine---compare version numbers */
93 /* Given version strings v1 and v2, return -1 if */
94 /* version v1 < v2, +1 if version v1 > v2, and 0 if */
96 /*------------------------------------------------------*/
98 int compare_version(char *v1
, char *v2
)
100 int vers1
, subvers1
, vers2
, subvers2
;
102 sscanf(v1
, "%d.%d", &vers1
, &subvers1
);
103 sscanf(v2
, "%d.%d", &vers2
, &subvers2
);
105 if (vers1
< vers2
) return -1;
106 else if (vers1
> vers2
) return 1;
108 if (subvers1
< subvers2
) return -1;
109 if (subvers1
> subvers2
) return 1;
114 /*------------------------------------------------------*/
115 /* Simple utility---get rid of newline character */
116 /*------------------------------------------------------*/
118 char *ridnewline(char *sptr
)
122 for (tstrp
= sptr
; *tstrp
!= '\0' && *tstrp
!= '\n'; tstrp
++);
123 if (*tstrp
== '\n') *tstrp
= '\0';
127 /*----------------------------------------------------------------------*/
128 /* Check if two filenames are equivalent. This requires separately */
129 /* checking any absolute or relative pathnames in front of the filename */
130 /* as well as the filename itself. */
131 /*----------------------------------------------------------------------*/
135 int filecmp(char *filename1
, char *filename2
)
137 char *root1
, *root2
, *path1
, *path2
, *end1
, *end2
;
141 const char *cwdname
= ".";
143 if (filename1
== NULL
|| filename2
== NULL
) return 1;
145 if (!strcmp(filename1
, filename2
)) return 0; /* exact match */
147 root1
= strrchr(filename1
, PATHSEP
);
148 root2
= strrchr(filename2
, PATHSEP
);
151 path1
= (char *)cwdname
;
162 path2
= (char *)cwdname
;
172 if (strcmp(root1
, root2
)) return 1; /* root names don't match */
174 /* If we got here, one or both filenames specify a directory */
175 /* path, and the directory paths are different strings. */
176 /* However, one may be an absolute path and the other a */
177 /* relative path, so we check the inodes of the paths for */
178 /* equivalence. Note that the file itself is not assumed to */
182 if (end1
!= NULL
) *end1
= '\0';
183 if (stat(path1
, &statbuf
) == 0 && S_ISDIR(statbuf
.st_mode
)) {
184 inode1
= statbuf
.st_ino
;
185 if (end2
!= NULL
) *end2
= '\0';
186 if (stat(path2
, &statbuf
) == 0 && S_ISDIR(statbuf
.st_mode
)) {
187 if (inode1
== statbuf
.st_ino
)
190 if (end2
!= NULL
) *end2
= PATHSEP
;
192 if (end1
!= NULL
) *end1
= PATHSEP
;
196 /*--------------------------------------------------------------*/
197 /* Make sure that a string (object or parameter name) is a */
198 /* valid PostScript name. We do this by converting illegal */
199 /* characters to the PostScript \ooo (octal value) form. */
201 /* This routine does not consider whether the name might be a */
202 /* PostScript numeric value. This problem is taken care of by */
203 /* having the load/save routines prepend '@' to parameters and */
204 /* a technology namespace to object names. */
206 /* If "need_prefix" is TRUE, then prepend "@" to the result */
207 /* string, unless teststring is a numerical parameter name */
209 /*--------------------------------------------------------------*/
211 char *create_valid_psname(char *teststring
, Boolean need_prefix
)
214 static char *optr
= NULL
;
216 Boolean prepend
= need_prefix
;
217 char illegalchars
[] = {'/', '}', '{', ']', '[', ')', '(', '<', '>', ' ', '%'};
219 /* Check for illegal characters which have syntactical meaning in */
220 /* PostScript, and the presence of nonprintable characters or */
223 ssize
= strlen(teststring
);
226 if (need_prefix
&& !strncmp(teststring
, "p_", 2))
231 for (sptr
= teststring
; *sptr
!= '\0'; sptr
++) {
232 if ((!isprint(*sptr
)) || isspace(*sptr
))
235 for (i
= 0; i
< sizeof(illegalchars
); i
++) {
236 if (*sptr
== illegalchars
[i
]) {
243 if (isize
== ssize
) return teststring
;
247 optr
= (char *)malloc(isize
);
249 optr
= (char *)realloc(optr
, isize
);
253 if (prepend
) *pptr
++ = '@';
255 for (sptr
= teststring
; *sptr
!= '\0'; sptr
++) {
256 if ((!isprint(*sptr
)) || isspace(*sptr
)) {
257 sprintf(pptr
, "\\%03o", *sptr
);
261 for (i
= 0; i
< sizeof(illegalchars
); i
++) {
262 if (*sptr
== illegalchars
[i
]) {
263 sprintf(pptr
, "\\%03o", *sptr
);
268 if (i
== sizeof(illegalchars
))
276 /*------------------------------------------------------*/
277 /* Turn a PostScript string with possible backslash */
278 /* escapes into a normal character string. */
280 /* if "spacelegal" is TRUE, we are parsing a PostScript */
281 /* string in parentheses () where whitespace is legal. */
282 /* If FALSE, we are parsing a PostScript name where */
283 /* whitespace is illegal, and any whitespace should be */
284 /* considered the end of the name. */
286 /* "dest" is ASSUMED to be large enough to hold the */
287 /* result. "dest" is always equal to or smaller than */
288 /* "src" in length. "size" should be the maximum size */
289 /* of the string, or 1 less that the allocated memory, */
290 /* allowing for a final NULL byte to be added. */
292 /* The fact that "dest" is always smaller than or equal */
293 /* to "src" means that parse_ps_string(a, a, ...) is */
296 /* Return 0 if the result is empty, 1 otherwise. */
297 /*------------------------------------------------------*/
299 int parse_ps_string(char *src
, char *dest
, int size
, Boolean spacelegal
, Boolean strip
)
303 int tmpdig
, rval
= 0;
305 /* Strip leading "@", inserted by XCircuit to */
306 /* prevent conflicts with PostScript reserved */
307 /* keywords or numbers. */
309 if (strip
&& (*sptr
== '@')) sptr
++;
312 if ((*sptr
== '\0') || (isspace(*sptr
) && !spacelegal
)) {
319 if (*sptr
>= '0' && *sptr
< '8') {
320 sscanf(sptr
, "%3o", &tmpdig
);
321 *tptr
++ = (u_char
)tmpdig
;
331 if ((int)(tptr
- dest
) > size
) {
332 Wprintf("Warning: Name \"%s\" in input exceeded buffer length!\n", src
);
340 /*------------------------------------------------------*/
341 /* Free memory allocated to a label string */
342 /*------------------------------------------------------*/
344 void freelabel(stringpart
*string
)
346 stringpart
*strptr
= string
, *tmpptr
;
348 while (strptr
!= NULL
) {
349 if (strptr
->type
== TEXT_STRING
|| strptr
->type
== PARAM_START
)
350 free(strptr
->data
.string
);
351 tmpptr
= strptr
->nextpart
;
357 /*------------------------------------------------------*/
358 /* Free memory for a single element */
359 /*------------------------------------------------------*/
361 void free_single(genericptr genobj
)
366 if (IS_POLYGON(genobj
)) free(((polyptr
)(genobj
))->points
);
367 else if (IS_LABEL(genobj
)) freelabel(((labelptr
)(genobj
))->string
);
368 else if (IS_GRAPHIC(genobj
)) freegraphic((graphicptr
)(genobj
));
369 else if (IS_PATH(genobj
)) free(((pathptr
)(genobj
))->plist
);
370 else if (IS_OBJINST(genobj
)) {
371 geninst
= (objinstptr
)genobj
;
372 ops
= geninst
->params
;
373 while (ops
!= NULL
) {
374 /* Don't try to free data from indirect parameters */
375 /* (That's not true---all data are copied by epsubstitute) */
376 /* if (find_indirect_param(geninst, ops->key) == NULL) { */
379 freelabel(ops
->parameter
.string
);
382 free(ops
->parameter
.expr
);
392 free_all_eparams(genobj
);
395 /*---------------------------------------------------------*/
396 /* Reset an object structure by freeing all alloc'd memory */
397 /*---------------------------------------------------------*/
399 void reset(objectptr localdata
, short mode
)
403 if (localdata
->polygons
!= NULL
|| localdata
->labels
!= NULL
)
404 destroynets(localdata
);
406 localdata
->valid
= False
;
408 if (localdata
->parts
> 0) {
413 for (genobj
= localdata
->plist
; genobj
< localdata
->plist
414 + localdata
->parts
; genobj
++)
416 /* (*genobj == NULL) only on library pages */
417 /* where the instances are kept in the library */
418 /* definition, and are only referenced on the page. */
420 if (*genobj
!= NULL
) {
421 free_single(*genobj
);
425 free(localdata
->plist
);
427 removeparams(localdata
);
431 free(localdata
->plist
);
435 /*---------------------------------------------------------*/
437 void pagereset(short rpage
)
439 /* free alloc'd filename */
441 if (xobjs
.pagelist
[rpage
]->filename
!= NULL
)
442 free(xobjs
.pagelist
[rpage
]->filename
);
443 xobjs
.pagelist
[rpage
]->filename
= (char *)NULL
;
445 if (xobjs
.pagelist
[rpage
]->background
.name
!= NULL
)
446 free(xobjs
.pagelist
[rpage
]->background
.name
);
447 xobjs
.pagelist
[rpage
]->background
.name
= (char *)NULL
;
451 /* New pages pick up their properties from page 0, which can be changed */
452 /* from the .xcircuitrc file on startup (or loaded from a script). */
453 /* Thanks to Norman Werner (norman.werner@student.uni-magdeburg.de) for */
454 /* pointing out this more obvious way of doing the reset, and providing */
457 xobjs
.pagelist
[rpage
]->wirewidth
= xobjs
.pagelist
[0]->wirewidth
;
458 xobjs
.pagelist
[rpage
]->orient
= xobjs
.pagelist
[0]->orient
;
459 xobjs
.pagelist
[rpage
]->pmode
= xobjs
.pagelist
[0]->pmode
;
460 xobjs
.pagelist
[rpage
]->outscale
= xobjs
.pagelist
[0]->outscale
;
461 xobjs
.pagelist
[rpage
]->drawingscale
.x
= xobjs
.pagelist
[0]->drawingscale
.x
;
462 xobjs
.pagelist
[rpage
]->drawingscale
.y
= xobjs
.pagelist
[0]->drawingscale
.y
;
463 xobjs
.pagelist
[rpage
]->gridspace
= xobjs
.pagelist
[0]->gridspace
;
464 xobjs
.pagelist
[rpage
]->snapspace
= xobjs
.pagelist
[0]->snapspace
;
465 xobjs
.pagelist
[rpage
]->coordstyle
= xobjs
.pagelist
[0]->coordstyle
;
466 xobjs
.pagelist
[rpage
]->margins
= xobjs
.pagelist
[0]->margins
;
468 if (xobjs
.pagelist
[rpage
]->coordstyle
== CM
) {
469 xobjs
.pagelist
[rpage
]->pagesize
.x
= 595;
470 xobjs
.pagelist
[rpage
]->pagesize
.y
= 842; /* A4 */
473 xobjs
.pagelist
[rpage
]->pagesize
.x
= 612; /* letter */
474 xobjs
.pagelist
[rpage
]->pagesize
.y
= 792;
478 /*---------------------------------------------------------*/
480 void initmem(objectptr localdata
)
482 localdata
->parts
= 0;
483 localdata
->plist
= (genericptr
*)malloc(sizeof(genericptr
));
484 localdata
->hidden
= False
;
485 localdata
->changes
= 0;
486 localdata
->params
= NULL
;
488 localdata
->viewscale
= 0.5;
490 /* Object should not reference the window: this needs to be rethunk! */
491 if (areawin
!= NULL
) {
492 localdata
->pcorner
.x
= -areawin
->width
;
493 localdata
->pcorner
.y
= -areawin
->height
;
495 localdata
->bbox
.width
= 0;
496 localdata
->bbox
.height
= 0;
497 localdata
->bbox
.lowerleft
.x
= 0;
498 localdata
->bbox
.lowerleft
.y
= 0;
500 localdata
->highlight
.netlist
= NULL
;
501 localdata
->highlight
.thisinst
= NULL
;
502 localdata
->schemtype
= PRIMARY
;
503 localdata
->symschem
= NULL
;
504 localdata
->netnames
= NULL
;
505 localdata
->polygons
= NULL
;
506 localdata
->labels
= NULL
;
507 localdata
->ports
= NULL
;
508 localdata
->calls
= NULL
;
509 localdata
->valid
= False
;
510 localdata
->infolabels
= False
;
511 localdata
->traversed
= False
;
514 /*--------------------------------------------------------------*/
515 /* Exhaustively compare the contents of two objects and return */
516 /* true if equivalent, false if not. */
517 /*--------------------------------------------------------------*/
519 Boolean
elemcompare(genericptr
*compgen
, genericptr
*gchk
)
522 switch(ELEMENTTYPE(*compgen
)) {
524 bres
= (TOARC(compgen
)->position
.x
== TOARC(gchk
)->position
.x
&&
525 TOARC(compgen
)->position
.y
== TOARC(gchk
)->position
.y
&&
526 TOARC(compgen
)->style
== TOARC(gchk
)->style
&&
527 TOARC(compgen
)->width
== TOARC(gchk
)->width
&&
528 abs(TOARC(compgen
)->radius
) == abs(TOARC(gchk
)->radius
) &&
529 TOARC(compgen
)->yaxis
== TOARC(gchk
)->yaxis
&&
530 TOARC(compgen
)->angle1
== TOARC(gchk
)->angle1
&&
531 TOARC(compgen
)->angle2
== TOARC(gchk
)->angle2
);
534 bres
= (TOSPLINE(compgen
)->style
== TOSPLINE(gchk
)->style
&&
535 TOSPLINE(compgen
)->width
== TOSPLINE(gchk
)->width
&&
536 TOSPLINE(compgen
)->ctrl
[0].x
== TOSPLINE(gchk
)->ctrl
[0].x
&&
537 TOSPLINE(compgen
)->ctrl
[0].y
== TOSPLINE(gchk
)->ctrl
[0].y
&&
538 TOSPLINE(compgen
)->ctrl
[1].x
== TOSPLINE(gchk
)->ctrl
[1].x
&&
539 TOSPLINE(compgen
)->ctrl
[1].y
== TOSPLINE(gchk
)->ctrl
[1].y
&&
540 TOSPLINE(compgen
)->ctrl
[2].x
== TOSPLINE(gchk
)->ctrl
[2].x
&&
541 TOSPLINE(compgen
)->ctrl
[2].y
== TOSPLINE(gchk
)->ctrl
[2].y
&&
542 TOSPLINE(compgen
)->ctrl
[3].x
== TOSPLINE(gchk
)->ctrl
[3].x
&&
543 TOSPLINE(compgen
)->ctrl
[3].y
== TOSPLINE(gchk
)->ctrl
[3].y
);
547 if (TOPOLY(compgen
)->style
== TOPOLY(gchk
)->style
&&
548 TOPOLY(compgen
)->width
== TOPOLY(gchk
)->width
&&
549 TOPOLY(compgen
)->number
== TOPOLY(gchk
)->number
) {
550 for (i
= 0; i
< TOPOLY(compgen
)->number
; i
++) {
551 if (TOPOLY(compgen
)->points
[i
].x
!= TOPOLY(gchk
)->points
[i
].x
552 || TOPOLY(compgen
)->points
[i
].y
!= TOPOLY(gchk
)->points
[i
].y
)
555 bres
= (i
== TOPOLY(compgen
)->number
);
563 /*--------------------------------------------------------------*/
564 /* Compare any element with any other element. */
565 /*--------------------------------------------------------------*/
567 Boolean
compare_single(genericptr
*compgen
, genericptr
*gchk
)
569 Boolean bres
= False
;
571 if ((*gchk
)->type
== (*compgen
)->type
) {
572 switch(ELEMENTTYPE(*compgen
)) {
574 objinst
*newobj
= TOOBJINST(compgen
);
575 objinst
*oldobj
= TOOBJINST(gchk
);
576 bres
= (newobj
->position
.x
== oldobj
->position
.x
&&
577 newobj
->position
.y
== oldobj
->position
.y
&&
578 newobj
->rotation
== oldobj
->rotation
&&
579 newobj
->scale
== oldobj
->scale
&&
580 newobj
->style
== oldobj
->style
&&
581 newobj
->thisobject
== oldobj
->thisobject
);
584 bres
= (TOLABEL(compgen
)->position
.x
== TOLABEL(gchk
)->position
.x
&&
585 TOLABEL(compgen
)->position
.y
== TOLABEL(gchk
)->position
.y
&&
586 TOLABEL(compgen
)->rotation
== TOLABEL(gchk
)->rotation
&&
587 TOLABEL(compgen
)->scale
== TOLABEL(gchk
)->scale
&&
588 TOLABEL(compgen
)->anchor
== TOLABEL(gchk
)->anchor
&&
589 TOLABEL(compgen
)->pin
== TOLABEL(gchk
)->pin
&&
590 !stringcomp(TOLABEL(compgen
)->string
, TOLABEL(gchk
)->string
));
592 case(PATH
): /* elements *must* be in same order for a path */
593 bres
= (TOPATH(compgen
)->parts
== TOPATH(gchk
)->parts
&&
594 TOPATH(compgen
)->style
== TOPATH(gchk
)->style
&&
595 TOPATH(compgen
)->width
== TOPATH(gchk
)->width
);
597 genericptr
*pathchk
, *gpath
;
598 for (pathchk
= TOPATH(compgen
)->plist
, gpath
=
599 TOPATH(gchk
)->plist
; pathchk
< TOPATH(compgen
)->plist
600 + TOPATH(compgen
)->parts
; pathchk
++, gpath
++) {
601 if (!elemcompare(pathchk
, gpath
)) bres
= False
;
605 case(ARC
): case(SPLINE
): case(POLYGON
):
606 bres
= elemcompare(compgen
, gchk
);
613 /*--------------------------------------------------------------------*/
615 short objcompare(objectptr obja
, objectptr objb
)
617 genericptr
*compgen
, *glist
, *gchk
, *remg
;
621 /* quick check on equivalence of number of objects */
623 if (obja
->parts
!= objb
->parts
) return False
;
625 /* check equivalence of parameters. Parameters need not be in any */
626 /* order; they must only match by key and value. */
628 if (obja
->params
== NULL
&& objb
->params
!= NULL
) return False
;
629 else if (obja
->params
!= NULL
&& objb
->params
== NULL
) return False
;
630 else if (obja
->params
!= NULL
|| objb
->params
!= NULL
) {
631 oparamptr opsa
, opsb
;
632 for (opsa
= obja
->params
; opsa
!= NULL
; opsa
= opsa
->next
) {
633 opsb
= match_param(objb
, opsa
->key
);
634 if (opsb
== NULL
) return False
;
635 else if (opsa
->type
!= opsb
->type
) return False
;
636 switch (opsa
->type
) {
638 if (stringcomp(opsa
->parameter
.string
, opsb
->parameter
.string
))
642 if (strcmp(opsa
->parameter
.expr
, opsb
->parameter
.expr
))
645 case XC_INT
: case XC_FLOAT
:
646 if (opsa
->parameter
.ivalue
!= opsb
->parameter
.ivalue
)
653 /* For the exhaustive check we must match component for component. */
654 /* Best not to assume that elements are in same order for both. */
658 glist
= (genericptr
*)malloc(csize
* sizeof(genericptr
));
659 for (compgen
= objb
->plist
; compgen
< objb
->plist
+ csize
; compgen
++)
660 (*(glist
+ (int)(compgen
- objb
->plist
))) = *compgen
;
661 for (compgen
= obja
->plist
; compgen
< obja
->plist
+ obja
->parts
;
664 for (gchk
= glist
; gchk
< glist
+ csize
; gchk
++) {
665 if ((*compgen
)->color
== (*gchk
)->color
)
666 bres
= compare_single(compgen
, gchk
);
669 for (remg
= gchk
; remg
< glist
+ csize
; remg
++)
676 if (csize
!= 0) return False
;
678 /* Both objects cannot attempt to set an associated schematic/symbol to */
679 /* separate objects, although it is okay for one to make the association */
680 /* and the other not to. */
682 if (obja
->symschem
!= NULL
&& objb
->symschem
!= NULL
)
683 if (obja
->symschem
!= objb
->symschem
)
689 /*------------------------*/
690 /* scale renormalization */
691 /*------------------------*/
693 float getpsscale(float value
, short page
)
695 if (xobjs
.pagelist
[page
]->coordstyle
!= CM
)
696 return (value
* INCHSCALE
);
698 return (value
* CMSCALE
);
701 /*---------------------------------------------------------------*/
702 /* Keep track of columns of output and split lines when too long */
703 /*---------------------------------------------------------------*/
705 void dostcount(FILE *ps
, short *count
, short addlength
)
708 if (*count
> OUTPUTWIDTH
) {
714 /*----------------------------------------------------------------------*/
715 /* Write a numerical value as a string to _STR, making a parameter */
716 /* substitution if appropriate. */
717 /* Return 1 if a parameter substitution was made, 0 if not. */
718 /*----------------------------------------------------------------------*/
720 Boolean
varpcheck(FILE *ps
, short value
, objectptr localdata
, int pointno
,
721 short *stptr
, genericptr thiselem
, u_char which
)
725 Boolean done
= False
;
727 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
728 if ((epp
->pdata
.pointno
!= -1) && (epp
->pdata
.pointno
!= pointno
)) continue;
729 ops
= match_param(localdata
, epp
->key
);
730 if (ops
!= NULL
&& (ops
->which
== which
)) {
731 sprintf(_STR
, "%s ", epp
->key
);
738 if (pointno
== -1) return done
;
739 sprintf(_STR
, "%d ", (int)value
);
741 else if ((epp
->pdata
.pointno
== -1) && (pointno
>= 0)) {
742 sprintf(_STR
, "%d ", (int)value
- ops
->parameter
.ivalue
);
745 dostcount (ps
, stptr
, strlen(_STR
));
750 /*----------------------------------------------------------------------*/
751 /* like varpcheck(), but without pointnumber */
752 /*----------------------------------------------------------------------*/
754 void varcheck(FILE *ps
, short value
, objectptr localdata
,
755 short *stptr
, genericptr thiselem
, u_char which
)
757 varpcheck(ps
, value
, localdata
, 0, stptr
, thiselem
, which
);
760 /*----------------------------------------------------------------------*/
761 /* like varcheck(), but for floating-point values */
762 /*----------------------------------------------------------------------*/
764 void varfcheck(FILE *ps
, float value
, objectptr localdata
, short *stptr
,
765 genericptr thiselem
, u_char which
)
769 Boolean done
= False
;
771 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
772 ops
= match_param(localdata
, epp
->key
);
773 if (ops
!= NULL
&& (ops
->which
== which
)) {
774 sprintf(_STR
, "%s ", epp
->key
);
781 sprintf(_STR
, "%3.3f ", value
);
783 dostcount (ps
, stptr
, strlen(_STR
));
787 /*----------------------------------------------------------------------*/
788 /* Like varpcheck(), for path types only. */
789 /*----------------------------------------------------------------------*/
791 Boolean
varpathcheck(FILE *ps
, short value
, objectptr localdata
, int pointno
,
792 short *stptr
, genericptr
*thiselem
, pathptr thispath
, u_char which
)
796 Boolean done
= False
;
798 for (epp
= thispath
->passed
; epp
!= NULL
; epp
= epp
->next
) {
799 if ((epp
->pdata
.pathpt
[0] != -1) && (epp
->pdata
.pathpt
[1] != pointno
)) continue;
800 if ((epp
->pdata
.pathpt
[0] != -1) && (epp
->pdata
.pathpt
[0] !=
801 (short)(thiselem
- thispath
->plist
))) continue;
802 ops
= match_param(localdata
, epp
->key
);
803 if (ops
!= NULL
&& (ops
->which
== which
)) {
804 sprintf(_STR
, "%s ", epp
->key
);
811 if (pointno
== -1) return done
;
812 sprintf(_STR
, "%d ", (int)value
);
814 else if ((epp
->pdata
.pathpt
[0] == -1) && (pointno
>= 0)) {
815 sprintf(_STR
, "%d ", (int)value
- ops
->parameter
.ivalue
);
817 dostcount (ps
, stptr
, strlen(_STR
));
822 /* Structure used to hold data specific to each load mode. See */
823 /* xcircuit.h for the list of load modes (enum loadmodes) */
825 typedef struct _loaddata
{
826 void (*func
)(); /* Routine to run to load the file */
827 char *prompt
; /* Substring name of action, for prompting */
828 char *filext
; /* Default extention of file to load */
831 /*-------------------------------------------------------*/
832 /* Load a PostScript or Python (interpreter script) file */
833 /*-------------------------------------------------------*/
835 void getfile(xcWidget button
, pointertype mode
, caddr_t nulldata
)
837 static loaddata loadmodes
[LOAD_MODES
] = {
838 {normalloadfile
, "load", "ps"}, /* mode NORMAL */
839 {importfile
, "import", "ps"}, /* mode IMPORT */
840 {loadbackground
, "render", "ps"}, /* mode PSBKGROUND */
842 {execscript
, "execute", "py"},
844 {execscript
, "execute", ""}, /* mode SCRIPT */
846 {crashrecover
, "recover", "ps"}, /* mode RECOVER */
848 {importspice
, "import", "spice"}, /* mode IMPORTSPICE */
851 {importgraphic
, "import", "ppm"}, /* mode IMPORTGRAPHIC */
855 buttonsave
*savebutton
= NULL
;
856 char *promptstr
= NULL
;
857 /* char strext[10]; (jdk) */
860 if (is_page(topobject
) == -1) {
861 Wprintf("Can only read file into top-level page!");
864 else if (idx
>= LOAD_MODES
) {
865 Wprintf("Unknown mode passed to routine getfile()\n");
869 savebutton
= getgeneric(button
, getfile
, (void *)mode
);
871 if (idx
== RECOVER
) {
872 char *cfile
= getcrashfilename();
873 promptstr
= (char *)malloc(18 + ((cfile
== NULL
) ? 9 : strlen(cfile
)));
874 sprintf(promptstr
, "Recover file \'%s\'?", (cfile
== NULL
) ? "(unknown)" : cfile
);
875 popupprompt(button
, promptstr
, NULL
, loadmodes
[idx
].func
, savebutton
, NULL
);
876 if (cfile
) free(cfile
);
879 promptstr
= (char *)malloc(18 + strlen(loadmodes
[idx
].prompt
));
880 sprintf(promptstr
, "Select file to %s:", loadmodes
[idx
].prompt
);
881 popupprompt(button
, promptstr
, "\0", loadmodes
[idx
].func
,
882 savebutton
, loadmodes
[idx
].filext
);
887 /*--------------------------------------------------------------*/
888 /* Tilde ('~') expansion in file name. Assumes that filename */
889 /* is a static character array of size "nchars". */
890 /*--------------------------------------------------------------*/
892 Boolean
xc_tilde_expand(char *filename
, int nchars
)
895 struct passwd
*passwd
;
896 char *username
= NULL
, *expanded
, *sptr
;
898 if (*filename
== '~') {
900 if (*sptr
== '/' || *sptr
== ' ' || *sptr
== '\0')
901 username
= getenv("HOME");
903 for (; *sptr
!= '/' && *sptr
!= '\0'; sptr
++);
904 if (*sptr
== '\0') *(sptr
+ 1) = '\0';
907 passwd
= getpwnam(filename
+ 1);
909 username
= passwd
->pw_dir
;
913 if (username
!= NULL
) {
914 expanded
= (char *)malloc(strlen(username
) +
916 strcpy(expanded
, username
);
917 strcat(expanded
, sptr
);
918 strncpy(filename
, expanded
, nchars
);
929 /*--------------------------------------------------------------*/
930 /* Variable ('$') expansion in file name */
931 /*--------------------------------------------------------------*/
933 Boolean
xc_variable_expand(char *filename
, int nchars
)
935 char *expanded
, *sptr
, tmpchar
, *varpos
, *varsub
;
937 if ((varpos
= strchr(filename
, '$')) != NULL
) {
938 for (sptr
= varpos
; *sptr
!= '/' && *sptr
!= '\0'; sptr
++);
939 if (*sptr
== '\0') *(sptr
+ 1) = '\0';
944 /* Interpret as a Tcl variable */
945 varsub
= (char *)Tcl_GetVar(xcinterp
, varpos
+ 1, TCL_NAMESPACE_ONLY
);
947 /* Interpret as an environment variable */
948 varsub
= (char *)getenv((const char *)(varpos
+ 1));
951 if (varsub
!= NULL
) {
954 expanded
= (char *)malloc(strlen(varsub
) + strlen(filename
) +
955 strlen(sptr
+ 1) + 2);
956 strcpy(expanded
, filename
);
957 strcat(expanded
, varsub
);
959 strcat(expanded
, sptr
);
960 strncpy(filename
, expanded
, nchars
);
970 /*--------------------------------------------------------------*/
971 /* Attempt to find a file and open it. */
972 /*--------------------------------------------------------------*/
974 FILE *fileopen(char *filename
, char *suffix
, char *name_return
, int nchars
)
977 char inname
[250], expname
[250], *sptr
, *cptr
, *iptr
, *froot
;
980 sscanf(filename
, "%249s", expname
);
981 xc_tilde_expand(expname
, 249);
982 while (xc_variable_expand(expname
, 249));
984 sptr
= xobjs
.filesearchpath
;
986 if ((xobjs
.filesearchpath
== NULL
) || (expname
[0] == '/')) {
987 strcpy(inname
, expname
);
991 strcpy(inname
, sptr
);
992 cptr
= strchr(sptr
, ':');
993 slen
= (cptr
== NULL
) ? strlen(sptr
) : (int)(cptr
- sptr
);
994 sptr
+= (slen
+ ((cptr
== NULL
) ? 0 : 1));
995 iptr
= inname
+ slen
;
996 if (*(iptr
- 1) != '/') strcpy(iptr
++, "/");
997 strcpy(iptr
, expname
);
1000 /* Attempt to open the filename with a suffix */
1002 if ((froot
= strrchr(iptr
, '/')) == NULL
) froot
= iptr
;
1003 if (strrchr(froot
, '.') == NULL
) {
1005 if (suffix
[0] != '.')
1006 strncat(inname
, ".", 249);
1007 strncat(inname
, suffix
, 249);
1009 file
= fopen(inname
, "r");
1012 /* Attempt to open the filename as given, without a suffix */
1015 strcpy(iptr
, expname
);
1016 file
= fopen(inname
, "r");
1019 if (file
!= NULL
) break;
1020 else if (sptr
== NULL
) break;
1021 else if (*sptr
== '\0') break;
1024 if (name_return
) strncpy(name_return
, inname
, nchars
);
1028 /*---------------------------------------------------------*/
1030 Boolean
nextfilename() /* extract next filename from _STR2 into _STR */
1034 sprintf(_STR
, "%.149s", _STR2
);
1035 if ((cptr
= strrchr(_STR2
, ',')) != NULL
) {
1036 slptr
= strrchr(_STR
, '/');
1037 if (slptr
== NULL
|| ((slptr
- _STR
) > (cptr
- _STR2
))) slptr
= _STR
- 1;
1038 sprintf(slptr
+ 1, "%s", cptr
+ 1);
1045 /*---------------------------------------------------------*/
1049 loadlibrary(FONTLIB
);
1052 /*------------------------------------------------------*/
1053 /* Handle library loading and refresh current page if */
1054 /* it is a library page that just changed. */
1055 /*------------------------------------------------------*/
1057 void loadglib(Boolean lflag
, short ilib
, short tlib
)
1059 while (nextfilename()) {
1063 ilib
= createlibrary(False
);
1065 /* if (ilib == tlib) zoomview(NULL, NULL, NULL); */
1070 ilib
= createlibrary(False
);
1072 /* if (ilib == tlib) zoomview(NULL, NULL, NULL); */
1075 /*------------------------------------------------------*/
1076 /* Load new library: Create new library page and load */
1078 /*------------------------------------------------------*/
1082 loadglib(False
, (short)0, (short)is_library(topobject
) + LIBRARY
);
1085 /*-----------------------------------------------------------*/
1086 /* Add to library: If on library page, add to that library. */
1087 /* Otherwise, create a new library page and load to it. */
1088 /*-----------------------------------------------------------*/
1093 Boolean lflag
= True
;
1095 /* Flag whether current page is a library page or not */
1097 if ((tlib
= is_library(topobject
)) < 0) {
1102 ilib
= tlib
+ LIBRARY
;
1104 loadglib(lflag
, ilib
, tlib
+ LIBRARY
);
1107 /*---------------------------------------------------------*/
1109 void getlib(xcWidget button
, caddr_t clientdata
, caddr_t nulldata
)
1111 buttonsave
*savebutton
;
1113 savebutton
= getgeneric(button
, getlib
, NULL
);
1115 popupprompt(button
, "Enter library to load:", "\0", loadblib
, savebutton
,
1119 /*---------------------------------------------------------*/
1121 void getuserlib(xcWidget button
, caddr_t clientdata
, caddr_t nulldata
)
1123 buttonsave
*savebutton
;
1126 savebutton
= getgeneric(button
, getuserlib
, NULL
);
1128 popupprompt(button
, "Enter library to load:", "\0", loadulib
, savebutton
,
1132 /*------------------------------------------------------*/
1133 /* Add a new name to the list of aliases for an object */
1134 /*------------------------------------------------------*/
1136 Boolean
addalias(objectptr thisobj
, char *newname
)
1140 /* Boolean retval = False; (jdk) */
1141 char *origname
= thisobj
->name
;
1143 for (aref
= aliastop
; aref
!= NULL
; aref
= aref
->next
)
1144 if (aref
->baseobj
== thisobj
)
1147 /* An equivalence, not an alias */
1148 if (!strcmp(origname
, newname
)) return True
;
1150 if (aref
== NULL
) { /* entry does not exist; add new baseobj */
1151 aref
= (aliasptr
)malloc(sizeof(alias
));
1152 aref
->baseobj
= thisobj
;
1153 aref
->aliases
= NULL
;
1154 aref
->next
= aliastop
;
1158 for (sref
= aref
->aliases
; sref
!= NULL
; sref
= sref
->next
)
1159 if (!strcmp(sref
->alias
, newname
))
1162 if (sref
== NULL
) { /* needs new entry */
1163 sref
= (slistptr
)malloc(sizeof(stringlist
));
1164 sref
->alias
= strdup(newname
);
1165 sref
->next
= aref
->aliases
;
1166 aref
->aliases
= sref
;
1169 else return True
; /* alias already exists! */
1172 /*------------------------------------------------------*/
1173 /* Remove all object name aliases */
1174 /*------------------------------------------------------*/
1176 void cleanupaliases(short mode
)
1181 char *sptr
; /* *basename, (jdk) */
1184 if (aliastop
== NULL
) return;
1186 for (aref
= aliastop
; aref
!= NULL
; aref
= aref
->next
) {
1187 baseobj
= aref
->baseobj
;
1188 for (sref
= aref
->aliases
; sref
!= NULL
; sref
= sref
->next
)
1192 for (; (aref
= aliastop
->next
); aliastop
= aref
)
1197 /* Get rid of propagating underscores in names */
1199 for (i
= 0; i
< ((mode
== FONTLIB
) ? 1 : xobjs
.numlibs
); i
++) {
1200 for (j
= 0; j
< ((mode
== FONTLIB
) ? xobjs
.fontlib
.number
:
1201 xobjs
.userlibs
[i
].number
); j
++) {
1202 baseobj
= (mode
== FONTLIB
) ? *(xobjs
.fontlib
.library
+ j
) :
1203 *(xobjs
.userlibs
[i
].library
+ j
);
1205 sptr
= baseobj
->name
;
1206 while (*sptr
== '_') sptr
++;
1207 /* need memmove to avoid overwriting? */
1208 memmove((void *)baseobj
->name
, (const void *)sptr
, strlen(sptr
) + 1);
1214 /*------------------------------------------------------*/
1215 /* Open a library file by name and return a pointer to */
1216 /* the file structure, or NULL if an error occurred. */
1217 /*------------------------------------------------------*/
1219 FILE *libopen(char *libname
, short mode
, char *name_return
, int nchars
)
1222 char inname
[150], expname
[150], *sptr
, *cptr
, *iptr
;
1224 char *suffix
= (mode
== FONTENCODING
) ? ".xfe" : ".lps";
1226 sscanf(libname
, "%149s", expname
);
1227 xc_tilde_expand(expname
, 149);
1228 while(xc_variable_expand(expname
, 149));
1230 sptr
= xobjs
.libsearchpath
;
1233 if ((xobjs
.libsearchpath
== NULL
) || (expname
[0] == '/')) {
1234 strcpy(inname
, expname
);
1238 strcpy(inname
, sptr
);
1239 cptr
= strchr(sptr
, ':');
1240 slen
= (cptr
== NULL
) ? strlen(sptr
) : (int)(cptr
- sptr
);
1241 sptr
+= (slen
+ ((cptr
== NULL
) ? 0 : 1));
1242 iptr
= inname
+ slen
;
1243 if (*(iptr
- 1) != '/') strcpy(iptr
++, "/");
1244 strcpy(iptr
, expname
);
1247 /* Try to open the filename with a suffix if it doesn't have one */
1249 if (strrchr(iptr
, '.') == NULL
) {
1250 strncat(inname
, suffix
, 149);
1251 file
= fopen(inname
, "r");
1254 /* Try to open the filename as given, without a suffix */
1257 strcpy(iptr
, expname
);
1258 file
= fopen(inname
, "r");
1261 if (file
!= NULL
) break;
1262 else if (sptr
== NULL
) break;
1263 else if (*sptr
== '\0') break;
1266 if ((file
== NULL
) && (xobjs
.libsearchpath
== NULL
)) {
1268 /* if not found in cwd and there is no library search */
1269 /* path, look for environment variable "XCIRCUIT_LIB_DIR" */
1270 /* defined (Thanks to Ali Moini, U. Adelaide, S. Australia) */
1272 char *tmp_s
= getenv((const char *)"XCIRCUIT_LIB_DIR");
1274 if (tmp_s
!= NULL
) {
1275 sprintf(inname
, "%s/%s", tmp_s
, expname
);
1276 file
= fopen(inname
, "r");
1278 sprintf(inname
, "%s/%s%s", tmp_s
, expname
, suffix
);
1279 file
= fopen(inname
, "r");
1283 /* last resort: hard-coded directory BUILTINS_DIR */
1286 sprintf(inname
, "%s/%s", BUILTINS_DIR
, expname
);
1287 file
= fopen(inname
, "r");
1289 sprintf(inname
, "%s/%s%s", BUILTINS_DIR
, expname
, suffix
);
1290 file
= fopen(inname
, "r");
1295 if (name_return
) strncpy(name_return
, inname
, nchars
);
1299 /*--------------------------------------------------------------*/
1300 /* Add a record to the instlist list of the library indexed by */
1301 /* mode, create a new instance, and add it to the record. */
1303 /* objname is the name of the library object to be instanced, */
1304 /* and buffer is the line containing the instance parameters */
1305 /* of the new instance, optionally preceded by scale and */
1306 /* rotation values. */
1308 /*--------------------------------------------------------------*/
1310 objinstptr
new_library_instance(short mode
, char *objname
, char *buffer
,
1311 TechPtr defaulttech
)
1314 objectptr libobj
, localdata
;
1315 objinstptr newobjinst
;
1317 char *nsptr
, *fullname
= objname
;
1319 localdata
= xobjs
.libtop
[mode
+ LIBRARY
]->thisobject
;
1321 /* For (older) libraries that do not use technologies, give the */
1322 /* object a technology name in the form <library>::<object> */
1324 if ((nsptr
= strstr(objname
, "::")) == NULL
) {
1325 int deftechlen
= (defaulttech
== NULL
) ? 0 : strlen(defaulttech
->technology
);
1326 fullname
= (char *)malloc(deftechlen
+ strlen(objname
) + 3);
1327 if (defaulttech
== NULL
)
1328 sprintf(fullname
, "::%s", objname
);
1330 sprintf(fullname
, "%s::%s", defaulttech
->technology
, objname
);
1333 for (j
= 0; j
< xobjs
.userlibs
[mode
].number
; j
++) {
1334 libobj
= *(xobjs
.userlibs
[mode
].library
+ j
);
1335 if (!strcmp(fullname
, libobj
->name
)) {
1336 newobjinst
= addtoinstlist(mode
, libobj
, TRUE
);
1339 while (isspace(*lineptr
)) lineptr
++;
1340 if (*lineptr
!= '<') {
1341 /* May declare instanced scale and rotation first */
1342 lineptr
= varfscan(localdata
, lineptr
, &newobjinst
->scale
,
1343 (genericptr
)newobjinst
, P_SCALE
);
1344 lineptr
= varfscan(localdata
, lineptr
, &newobjinst
->rotation
,
1345 (genericptr
)newobjinst
, P_ROTATION
);
1347 readparams(NULL
, newobjinst
, libobj
, lineptr
);
1348 if (fullname
!= objname
) free(fullname
);
1352 if (fullname
!= objname
) free(fullname
);
1353 return NULL
; /* error finding the library object */
1356 /*------------------------------------------------------*/
1357 /* Import a single object from a library file. "mode" */
1358 /* is the number of the library into which the object */
1359 /* will be placed. This function allows new libraries */
1360 /* to be generated by "cutting and pasting" from */
1361 /* existing libraries. It also allows better library */
1362 /* management when the number of objects becomes very */
1363 /* large, such as when using "diplib" (7400 series */
1364 /* chips, created from the PCB library). */
1365 /*------------------------------------------------------*/
1367 void importfromlibrary(short mode
, char *libname
, char *objname
)
1370 char temp
[150], keyword
[100];
1371 char inname
[150], *tptr
;
1372 objectptr
*newobject
;
1374 char saveversion
[20];
1375 Boolean dependencies
= False
;
1376 TechPtr nsptr
= NULL
;
1378 ps
= libopen(libname
, mode
, inname
, 149);
1380 Fprintf(stderr
, "Cannot open library %s for import.\n", libname
);
1384 strcpy(version
, "2.0"); /* Assume version is 2.0 unless found in header */
1387 if (fgets(temp
, 149, ps
) == NULL
) {
1388 Wprintf("Error in library.");
1391 else if (temp
[0] == '/') {
1393 if (temp
[1] == '@') s
= 2;
1394 sscanf(&temp
[s
], "%s", keyword
);
1395 if (!strcmp(keyword
, objname
))
1398 else if (*temp
== '%') {
1399 char *tptr
= temp
+ 1;
1400 while (isspace(*tptr
)) tptr
++;
1401 if (!strncmp(tptr
, "Version:", 8)) {
1403 sscanf(tptr
, "%20s", version
);
1404 ridnewline(version
);
1406 else if (!strncmp(tptr
, "Library", 7)) {
1407 char *techname
= strstr(tptr
, ":");
1408 if (techname
!= NULL
) {
1409 techname
++; /* skip over colon */
1410 while(isspace(*techname
)) techname
++;
1411 ridnewline(techname
); /* Remove newline character */
1412 if ((tptr
= strrchr(techname
, '/')) != NULL
)
1413 techname
= tptr
+ 1;
1414 if ((tptr
= strrchr(techname
, '.')) != NULL
)
1415 if (!strncmp(tptr
, ".lps", 4))
1417 nsptr
= AddNewTechnology(techname
, inname
);
1419 // Set the IMPORTED flag, to help prevent overwriting
1420 // the techfile with a truncated version of it, unless
1421 // the filename of the techfile has been changed, in
1422 // which case the technology should be considered to
1423 // stand on its own, and is not considered a partially
1424 // complete imported version of the original techfile.
1426 if (!strcmp(inname
, nsptr
->filename
))
1427 nsptr
->flags
|= TECH_IMPORTED
;
1431 else if (!strncmp(tptr
, "Depend", 6)) {
1432 dependencies
= TRUE
;
1434 sscanf(tptr
, "%s", keyword
);
1435 if (!strcmp(keyword
, objname
)) {
1436 /* Load dependencies */
1438 tptr
+= strlen(keyword
) + 1;
1439 if (sscanf(tptr
, "%s", keyword
) != 1) break;
1440 if (keyword
[0] == '\n' || keyword
[0] == '\0') break;
1441 /* Recursive import */
1442 strcpy(saveversion
, version
);
1443 importfromlibrary(mode
, libname
, keyword
);
1444 strcpy(version
, saveversion
);
1451 if ((compare_version(version
, "3.2") < 0) && (!dependencies
)) {
1452 Fprintf(stderr
, "Library does not have dependency list and cannot "
1453 "be trusted.\nLoad and rewrite library to update.\n");
1457 newobject
= new_library_object(mode
, keyword
, &redef
, nsptr
);
1459 load_in_progress
= True
;
1460 if (objectread(ps
, *newobject
, 0, 0, mode
, temp
, DEFAULTCOLOR
, nsptr
) == False
) {
1462 if (library_object_unique(mode
, *newobject
, redef
)) {
1463 add_object_to_library(mode
, *newobject
);
1464 cleanupaliases(mode
);
1466 /* pull in any instances of this object that */
1467 /* are defined in the library */
1470 if (fgets(temp
, 149, ps
) == NULL
) {
1471 Wprintf("Error in library.");
1474 else if (!strncmp(temp
, "% EndLib", 8))
1476 else if (strstr(temp
, "libinst") != NULL
) {
1477 if ((tptr
= strstr(temp
, objname
)) != NULL
) {
1478 if (*(tptr
- 1) == '/') {
1480 while (!isspace(*++eptr
));
1482 new_library_instance(mode
- LIBRARY
, tptr
, temp
, nsptr
);
1488 if (mode
!= FONTLIB
) {
1490 centerview(xobjs
.libtop
[mode
]);
1497 strcpy(version
, PROG_VERSION
);
1498 load_in_progress
= False
;
1501 /*------------------------------------------------------*/
1502 /* Copy all technologies' replace flags into temp flag. */
1503 /* Then clear the replace flags (replace none) */
1504 /*------------------------------------------------------*/
1506 void TechReplaceSave()
1510 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
)
1512 if (nsp
->flags
& TECH_REPLACE
)
1513 nsp
->flags
|= TECH_REPLACE_TEMP
;
1515 nsp
->flags
&= ~TECH_REPLACE_TEMP
;
1516 nsp
->flags
&= ~TECH_REPLACE
;
1520 /*------------------------------------------------------*/
1521 /* Restore all technologies' replace flags */
1522 /*------------------------------------------------------*/
1524 void TechReplaceRestore()
1528 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
)
1530 if (nsp
->flags
& TECH_REPLACE_TEMP
)
1531 nsp
->flags
|= TECH_REPLACE
;
1533 nsp
->flags
&= ~TECH_REPLACE
;
1537 /*------------------------------------------------------*/
1538 /* Set all technologies' replace flags (replace all) */
1539 /*------------------------------------------------------*/
1541 void TechReplaceAll()
1545 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
)
1546 nsp
->flags
|= TECH_REPLACE
;
1549 /*------------------------------------------------------*/
1550 /* Clear all technologies' replace flags (replace none) */
1551 /*------------------------------------------------------*/
1553 void TechReplaceNone()
1557 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
)
1558 nsp
->flags
&= ~TECH_REPLACE
;
1562 /*------------------------------------------------------*/
1563 /* Compare an object's name with a specific technology */
1565 /* A missing "::" prefix separator or an empty prefix */
1566 /* both match a NULL technology or a technology name */
1567 /* that is an empty string (""). All of these */
1568 /* conditions indicate the default "user" technology. */
1569 /*------------------------------------------------------*/
1571 Boolean
CompareTechnology(objectptr cobj
, char *technology
)
1574 Boolean result
= FALSE
;
1576 if ((cptr
= strstr(cobj
->name
, "::")) != NULL
) {
1577 if (technology
== NULL
)
1578 result
= (cobj
->name
== cptr
) ? TRUE
: FALSE
;
1581 if (!strcmp(cobj
->name
, technology
)) result
= TRUE
;
1585 else if (technology
== NULL
)
1591 /*------------------------------------------------------*/
1592 /* Find a technology record */
1593 /*------------------------------------------------------*/
1595 TechPtr
LookupTechnology(char *technology
)
1598 Boolean usertech
= FALSE
;
1600 // A NULL technology is allowed as equivalent to a
1601 // technology name of "" (null string)
1603 if (technology
== NULL
)
1605 else if (*technology
== '\0')
1607 else if (!strcmp(technology
, "(user)"))
1610 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
) {
1611 if (usertech
== TRUE
) {
1612 if (*nsp
->technology
== '\0')
1615 if ((technology
!= NULL
) && !strcmp(technology
, nsp
->technology
))
1621 /*------------------------------------------------------*/
1622 /* Find a technology according to the filename */
1623 /*------------------------------------------------------*/
1625 TechPtr
GetFilenameTechnology(char *filename
)
1629 if (filename
== NULL
) return NULL
;
1631 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
)
1632 if (!filecmp(filename
, nsp
->filename
))
1638 /*------------------------------------------------------*/
1639 /* Find a technology record corresponding to the */
1640 /* indicated object's technology. */
1641 /*------------------------------------------------------*/
1643 TechPtr
GetObjectTechnology(objectptr thisobj
)
1647 /* int nlen; (jdk) */
1649 cptr
= strstr(thisobj
->name
, "::");
1650 if (cptr
== NULL
) return NULL
;
1653 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
)
1654 if (!strcmp(thisobj
->name
, nsp
->technology
))
1661 /*------------------------------------------------------*/
1662 /* Add a new technology name to the list */
1663 /*------------------------------------------------------*/
1665 TechPtr
AddNewTechnology(char *technology
, char *filename
)
1668 char usertech
[] = "";
1669 char *localtech
= technology
;
1671 // In the case where somebody has saved the contents of the user
1672 // technology to a file, create a technology->filename mapping
1673 // using a null string ("") for the technology name. If we are
1674 // only checking if a technology name exists (filename is NULL),
1675 // then ignore an reference to the user technology.
1677 if (technology
== NULL
) {
1678 if (filename
== NULL
) return NULL
;
1679 else localtech
= usertech
;
1682 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
) {
1683 if (!strcmp(localtech
, nsp
->technology
)) {
1685 /* A namespace may be created for an object that is a dependency */
1686 /* in a different technology. If so, it will have a NULL */
1687 /* filename, and the filename should be replaced if we ever load */
1688 /* the file that properly defines the technology. */
1690 if ((nsp
->filename
== NULL
) && (filename
!= NULL
))
1691 nsp
->filename
= strdup(filename
);
1693 return nsp
; /* Namespace already exists */
1697 nsp
= (TechPtr
)malloc(sizeof(Technology
));
1698 nsp
->next
= xobjs
.technologies
;
1699 if (filename
== NULL
)
1700 nsp
->filename
= NULL
;
1702 nsp
->filename
= strdup(filename
);
1703 nsp
->technology
= strdup(localtech
);
1704 nsp
->flags
= (u_char
)0;
1705 xobjs
.technologies
= nsp
;
1710 /*------------------------------------------------------*/
1711 /* Check an object's name for a technology, and add it */
1712 /* to the list of technologies if it has one. */
1713 /*------------------------------------------------------*/
1715 void AddObjectTechnology(objectptr thisobj
)
1719 cptr
= strstr(thisobj
->name
, "::");
1722 AddNewTechnology(thisobj
->name
, NULL
);
1727 /*------------------------------------------------------*/
1728 /* Load a library page (given in parameter "mode") and */
1729 /* rename the library page to match the library name as */
1730 /* found in the file header. */
1731 /*------------------------------------------------------*/
1733 Boolean
loadlibrary(short mode
)
1736 objinstptr saveinst
;
1737 char temp
[150], keyword
[30], percentc
, inname
[150];
1738 TechPtr nsptr
= NULL
;
1740 ps
= libopen(_STR
, mode
, inname
, 149);
1742 if ((ps
== NULL
) && (mode
== FONTLIB
)) {
1743 /* We automatically try looking in all the usual places plus a */
1744 /* subdirectory named "fonts". */
1746 sprintf(temp
, "fonts/%s", _STR
);
1747 ps
= libopen(temp
, mode
, inname
, 149);
1750 Wprintf("Library not found.");
1754 /* current version is PROG_VERSION; however, all libraries newer than */
1755 /* version 2.0 require "Version" in the header. So unnumbered */
1756 /* libraries may be assumed to be version 1.9 or earlier. */
1758 strcpy(version
, "1.9");
1760 if (fgets(temp
, 149, ps
) == NULL
) {
1761 Wprintf("Error in library.");
1765 sscanf(temp
, "%c %29s", &percentc
, keyword
);
1767 /* Commands in header are PostScript comments (%) */
1768 if (percentc
== '%') {
1770 /* The library name in the header corresponds to the object */
1771 /* technology defined by the library. This no longer has */
1772 /* anything to do with the name of the library page where we */
1773 /* are loading this file. */
1775 /* Save the technology, filename, and flags in the technology list. */
1777 if ((mode
!= FONTLIB
) && !strcmp(keyword
, "Library")) {
1779 cptr
= strchr(temp
, ':');
1783 /* Don't write terminating newline to the object's name string */
1786 /* The default user technology is written to the output */
1787 /* as "(user)". If this is found, replace it with a */
1789 if (!strcmp(cptr
, "(user)")) cptr
+= 6;
1791 /* Removing any leading pathname from the library name */
1792 if ((nptr
= strrchr(cptr
, '/')) != NULL
) cptr
= nptr
+ 1;
1794 /* Remove any ".lps" extension from the library name */
1796 nptr
= strrchr(cptr
, '.');
1797 if ((nptr
!= NULL
) && !strcmp(nptr
, ".lps")) *nptr
= '\0';
1799 nsptr
= AddNewTechnology(cptr
, inname
);
1802 // If anything was previously imported from this file
1803 // using importfromlibrary(), then the IMPORTED flag
1804 // will be set and needs to be cleared.
1805 nsptr
->flags
&= ~TECH_IMPORTED
;
1810 /* This comment gives the Xcircuit version number */
1811 else if (!strcmp(keyword
, "Version:")) {
1813 if (sscanf(temp
, "%*c %*s %s", tmpv
) > 0) strcpy(version
, tmpv
);
1816 /* This PostScript comment marks the end of the file header */
1817 else if (!strcmp(keyword
, "XCircuitLib")) break;
1821 /* Set the current top object to the library page so that any */
1822 /* expression parameters are computed with respect to the library, */
1823 /* not a page. Revert back to the page after loading the library. */
1825 saveinst
= areawin
->topinstance
;
1826 areawin
->topinstance
= xobjs
.libtop
[mode
];
1828 load_in_progress
= True
;
1829 objectread(ps
, topobject
, 0, 0, mode
, temp
, DEFAULTCOLOR
, nsptr
);
1830 load_in_progress
= False
;
1831 cleanupaliases(mode
);
1833 areawin
->topinstance
= saveinst
;
1835 if (mode
!= FONTLIB
) {
1837 centerview(xobjs
.libtop
[mode
]);
1838 if (nsptr
== NULL
) nsptr
= GetFilenameTechnology(inname
);
1840 Wprintf("Loaded library file %s", inname
);
1842 Wprintf("Loaded library file %s (technology %s)", inname
,
1846 Wprintf("Loaded font file %s", inname
);
1848 strcpy(version
, PROG_VERSION
);
1851 /* Check if the library is read-only by opening for append */
1853 if ((mode
!= FONTLIB
) && (nsptr
!= NULL
)) {
1854 ps
= fopen(inname
, "a");
1856 nsptr
->flags
|= TECH_READONLY
;
1864 /*---------------------------------------------------------*/
1866 void startloadfile(int libnum
)
1869 short firstpage
= areawin
->page
;
1871 while (nextfilename()) {
1872 loadfile(0, libnum
);
1874 /* find next undefined page */
1876 while(areawin
->page
< xobjs
.pages
&&
1877 xobjs
.pagelist
[areawin
->page
]->pageinst
!= NULL
) areawin
->page
++;
1878 changepage(areawin
->page
);
1880 loadfile(0, libnum
);
1883 /* Prevent page change from being registered as an undoable action */
1884 savemode
= eventmode
;
1885 eventmode
= UNDO_MODE
;
1887 /* Display the first page loaded */
1889 eventmode
= savemode
;
1894 /*------------------------------------------------------*/
1895 /* normalloadfile() is a call to startloadfile(-1) */
1896 /* meaning load symbols to the User Library */
1897 /*------------------------------------------------------*/
1899 void normalloadfile()
1904 /*------------------------------------------------------*/
1905 /* Import an xcircuit file onto the current page */
1906 /*------------------------------------------------------*/
1910 while (nextfilename()) loadfile(1, -1);
1914 /*------------------------------------------------------*/
1915 /* Import an PPM graphic file onto the current page */
1916 /*------------------------------------------------------*/
1919 void importgraphic(void)
1924 if (eventmode
== CATALOG_MODE
) {
1925 Wprintf("Cannot import a graphic while in the library window.");
1929 if (!nextfilename()) {
1930 xc_tilde_expand(_STR
, 149);
1931 sscanf(_STR
, "%149s", inname
);
1932 if (!new_graphic(NULL
, inname
, 0, 0)) {
1933 Wprintf("Error: Graphic file not found.");
1938 Wprintf("Error: No graphic file to read.");
1942 #endif /* HAVE_CAIRO */
1944 /*--------------------------------------------------------------*/
1945 /* Skip forward in the input file to the next comment line */
1946 /*--------------------------------------------------------------*/
1948 void skiptocomment(char *temp
, int length
, FILE *ps
)
1954 } while (pch
== '\n');
1957 if (pch
== '%') fgets(temp
, length
, ps
);
1960 /*--------------------------------------------------------------*/
1961 /* ASG file import functions: */
1962 /* This function loads a SPICE deck (hspice format) */
1963 /*--------------------------------------------------------------*/
1972 if (eventmode
== CATALOG_MODE
) {
1973 Wprintf("Cannot import a netlist while in the library window.");
1977 if (!nextfilename()) {
1978 xc_tilde_expand(_STR
, 149);
1979 sscanf(_STR
, "%149s", inname
);
1980 spcfile
= fopen(inname
, "r");
1981 if (spcfile
!= NULL
) {
1983 Route(areawin
, False
);
1987 Wprintf("Error: Spice file not found.");
1992 Wprintf("Error: No spice file to read.");
1999 /*--------------------------------------------------------------*/
2000 /* Load an xcircuit file into xcircuit */
2002 /* mode = 0 is a "load" function. Behavior: load on */
2003 /* current page if empty. Otherwise, load on first empty */
2004 /* page found. If no empty pages exist, create a new page */
2005 /* and load there. */
2006 /* mode = 1 is an "import" function. Behavior: add */
2007 /* contents of file to the current page. */
2008 /* mode = 2 is a "library load" function. Behavior: add */
2009 /* objects in file to the user library but ignore the */
2010 /* page contents. */
2012 /* Return value: True if file was successfully loaded, False */
2014 /*--------------------------------------------------------------*/
2016 typedef struct _connects
*connectptr
;
2018 typedef struct _connects
{
2024 Boolean
loadfile(short mode
, int libnum
)
2027 char inname
[150], temp
[150], keyword
[30], percentc
, *pdchar
;
2028 char teststr
[50], teststr2
[20], pagestr
[100];
2029 short offx
, offy
, multipage
, page
, temppmode
= 0;
2032 connects
*connlist
= NULL
;
2033 struct stat statbuf
;
2034 int loclibnum
= (libnum
== -1) ? USERLIB
: libnum
;
2036 /* First, if we're in catalog mode, return with error */
2038 if (eventmode
== CATALOG_MODE
) {
2039 Wprintf("Cannot load file from library window");
2043 /* Do tilde/variable expansions on filename and open */
2044 ps
= fileopen(_STR
, "ps", inname
, 149);
2046 /* Could possibly be a library file? */
2047 /* (Note---loadfile() has no problems loading libraries */
2048 /* except for setting technology names and setting the */
2049 /* library page view at the end. The loadlibrary() routine */
2050 /* should probably be merged into this one.) */
2053 ps
= fileopen(_STR
, "lps", NULL
, 0);
2056 loadlibrary(loclibnum
);
2060 else if (!strcmp(inname
+ strlen(inname
) - 4, ".lps")) {
2062 loadlibrary(loclibnum
);
2068 /* Could possibly be an LGF file? */
2070 ps
= fileopen(_STR
, "lgf", NULL
, 0);
2078 /* Could possibly be an LGF backup (.lfo) file? */
2080 ps
= fileopen(_STR
, "lfo", NULL
, 0);
2089 /* Check for empty file---don't attempt to read empty files */
2091 if (fstat(fileno(ps
), &statbuf
) == 0 && (statbuf
.st_size
== (off_t
)0)) {
2097 /* What to do if no file was found. . . */
2100 if (topobject
->parts
== 0 && (mode
== 0)) {
2102 /* Check for file extension, and remove if "ps". */
2104 if ((pdchar
= strchr(_STR
, '.')) != NULL
)
2105 if (!strcmp(pdchar
+ 1, "ps")) *pdchar
= '\0';
2107 free(xobjs
.pagelist
[areawin
->page
]->filename
);
2108 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(_STR
);
2110 /* If the name has a path component, use only the root */
2111 /* for the object name, but the full path for the filename. */
2113 if ((pdchar
= strrchr(_STR
, '/')) != NULL
)
2114 sprintf(topobject
->name
, "%s", pdchar
+ 1);
2116 sprintf(topobject
->name
, "%s", _STR
);
2118 renamepage(areawin
->page
);
2119 printname(topobject
);
2120 Wprintf("Starting new drawing");
2123 Wprintf("Can't find file %s, won't overwrite current page", _STR
);
2128 strcpy(version
, "1.0");
2134 if (fgets(temp
, 149, ps
) == NULL
) {
2135 Wprintf("Error: EOF in or before prolog.");
2138 sscanf(temp
, "%c%29s", &percentc
, keyword
);
2139 for (pdchar
= keyword
; isspace(*pdchar
); pdchar
++);
2140 if (percentc
== '%') {
2141 if (!strcmp(pdchar
, "XCircuit")) break;
2142 if (!strcmp(pdchar
, "XCircuitLib")) {
2143 /* version control in libraries is post version 1.9 */
2144 if (compare_version(version
, "1.0") == 0) strcpy(version
, "1.9");
2147 if (!strcmp(pdchar
, "%Page:")) break;
2148 if (strstr(pdchar
, "PS-Adobe") != NULL
)
2149 temppmode
= (strstr(temp
, "EPSF") != NULL
) ? 0 : 1;
2150 else if (!strcmp(pdchar
, "Version:"))
2151 sscanf(temp
, "%*c%*s %20s", version
);
2152 else if (!strcmp(pdchar
, "%Pages:")) {
2153 pdchar
= advancetoken(temp
);
2154 multipage
= atoi(pdchar
);
2156 /* Crash files get renamed back to their original filename */
2157 else if (!strcmp(pdchar
, "%Title:")) {
2158 if (xobjs
.tempfile
!= NULL
)
2159 if (!strcmp(inname
, xobjs
.tempfile
))
2160 sscanf(temp
, "%*c%*s %s", inname
);
2162 else if ((temppmode
== 1) && !strcmp(pdchar
, "%BoundingBox:")) {
2164 sscanf(temp
, "%*s %hd %hd %hd %hd", &botx
, &boty
,
2165 &(pagesize
.x
), &(pagesize
.y
));
2172 else if (percentc
== '-' && !strcmp(keyword
, "5")) {
2180 /* Look for old-style files (no %%Page; maximum one page in file) */
2182 if (!strcmp(pdchar
, "XCircuit"))
2183 skiptocomment(temp
, 149, ps
);
2185 for (page
= 0; page
< multipage
; page
++) {
2186 sprintf(pagestr
, "%d", page
+ 1);
2188 /* read out-of-page library definitions */
2190 if (strstr(temp
, "%%Page:") == NULL
&& strstr(temp
, "offsets") == NULL
) {
2191 load_in_progress
= True
;
2192 objectread(ps
, topobject
, 0, 0, loclibnum
, temp
, DEFAULTCOLOR
, NULL
);
2193 load_in_progress
= False
;
2196 if (strstr(temp
, "%%Page:") != NULL
) {
2197 sscanf(temp
+ 8, "%99s", pagestr
);
2199 /* Read the next line so any keywords in the Page name don't */
2200 /* confuse the parser. */
2201 if (fgets(temp
, 149, ps
) == NULL
) {
2202 Wprintf("Error: bad page header.");
2206 /* Library load mode: Ignore all pages, just load objects */
2208 while (strstr(temp
, "showpage") == NULL
) {
2209 if (fgets(temp
, 149, ps
) == NULL
) {
2210 Wprintf("Error: bad page definition.");
2214 skiptocomment(temp
, 149, ps
);
2219 /* go to new page if necessary */
2223 /* find next undefined page */
2225 while(areawin
->page
< xobjs
.pages
&&
2226 xobjs
.pagelist
[areawin
->page
]->pageinst
!= NULL
) areawin
->page
++;
2227 changepage(areawin
->page
);
2230 /* If this file was a library file then there is no page to load */
2232 if (strstr(temp
, "EndLib") != NULL
) {
2233 composelib(loclibnum
);
2234 centerview(xobjs
.libtop
[mode
]);
2235 Wprintf("Loaded library.");
2239 /* good so far; let's clear out the old data structure */
2242 reset(topobject
, NORMAL
);
2243 pagereset(areawin
->page
);
2244 xobjs
.pagelist
[areawin
->page
]->pmode
= temppmode
;
2245 if (temppmode
== 1) {
2246 xobjs
.pagelist
[areawin
->page
]->pagesize
.x
= pagesize
.x
;
2247 xobjs
.pagelist
[areawin
->page
]->pagesize
.y
= pagesize
.y
;
2251 invalidate_netlist(topobject
);
2252 /* ensure that the netlist for topobject is destroyed */
2253 freenetlist(topobject
);
2256 /* clear the undo record */
2259 /* read to the "scale" line, picking up inch/cm type, drawing */
2260 /* scale, and grid/snapspace along the way */
2264 if (strstr(temp
, "offsets") != NULL
) {
2265 /* Prior to version 3.1.28 only. . . */
2266 sscanf(temp
, "%c %hd %hd %*s", &percentc
, &offx
, &offy
);
2267 if(percentc
!= '%') {
2268 Wprintf("Something wrong in offsets line.");
2273 if ((temppmode
== 1) && strstr(temp
, "%%PageBoundingBox:") != NULL
) {
2274 /* Recast the individual page size if specified per page */
2275 sscanf(temp
, "%*s %*d %*d %hd %hd",
2276 &xobjs
.pagelist
[areawin
->page
]->pagesize
.x
,
2277 &xobjs
.pagelist
[areawin
->page
]->pagesize
.y
);
2279 else if (strstr(temp
, "drawingscale") != NULL
)
2280 sscanf(temp
, "%*c %hd:%hd %*s",
2281 &xobjs
.pagelist
[areawin
->page
]->drawingscale
.x
,
2282 &xobjs
.pagelist
[areawin
->page
]->drawingscale
.y
);
2284 else if (strstr(temp
, "hidden") != NULL
)
2285 topobject
->hidden
= True
;
2287 else if (strstr(temp
, "is_symbol") != NULL
) {
2288 sscanf(temp
, "%*c %49s", teststr
);
2289 checkschem(topobject
, teststr
);
2291 else if (strstr(temp
, "is_primary") != NULL
) {
2292 /* objectptr master; (jdk) */
2295 /* Save information about master schematic and link at end of load */
2296 sscanf(temp
, "%*c %49s", teststr
);
2297 newconn
= (connects
*)malloc(sizeof(connects
));
2298 newconn
->next
= connlist
;
2300 newconn
->page
= areawin
->page
;
2301 newconn
->master
= strdup(teststr
);
2304 else if (strstr(temp
, "gridspace"))
2305 sscanf(temp
, "%*c %f %f %*s", &xobjs
.pagelist
[areawin
->page
]->gridspace
,
2306 &xobjs
.pagelist
[areawin
->page
]->snapspace
);
2307 else if (strstr(temp
, "scale") != NULL
|| strstr(temp
, "rotate") != NULL
) {
2308 /* rotation (landscape mode) is optional; parse accordingly */
2310 sscanf(temp
, "%f %49s", &tmpfl
, teststr
);
2311 if (strstr(teststr
, "scale") != NULL
) {
2313 setgridtype(teststr
);
2315 if (strstr(teststr
, "inch"))
2316 Tcl_Eval(xcinterp
, "xcircuit::coordstyle inches");
2318 Tcl_Eval(xcinterp
, "xcircuit::coordstyle centimeters");
2320 xobjs
.pagelist
[areawin
->page
]->outscale
= tmpfl
;
2322 else if (!strcmp(teststr
, "rotate")) {
2323 xobjs
.pagelist
[areawin
->page
]->orient
= (short)tmpfl
;
2324 fgets(temp
, 149, ps
);
2325 sscanf(temp
, "%f %19s", &tmpfl
, teststr2
);
2326 if (strstr(teststr2
, "scale") != NULL
) {
2328 setgridtype(teststr2
);
2330 if (strstr(teststr2
, "inch"))
2331 Tcl_Eval(xcinterp
, "xcircuit::coordstyle inches");
2333 Tcl_Eval(xcinterp
, "xcircuit::coordstyle centimeters");
2335 xobjs
.pagelist
[areawin
->page
]->outscale
= tmpfl
;
2338 sscanf(temp
, "%*f %*f %19s", teststr2
);
2339 if (!strcmp(teststr2
, "scale"))
2340 xobjs
.pagelist
[areawin
->page
]->outscale
= tmpfl
/
2341 getpsscale(1.0, areawin
->page
);
2343 Wprintf("Error in scale/rotate constructs.");
2348 else { /* old style scale? */
2349 sscanf(temp
, "%*f %*s %19s", teststr2
);
2350 if ((teststr2
!= NULL
) && (!strcmp(teststr2
, "scale")))
2351 xobjs
.pagelist
[areawin
->page
]->outscale
= tmpfl
/
2352 getpsscale(1.0, areawin
->page
);
2354 Wprintf("Error in scale/rotate constructs.");
2359 else if (strstr(temp
, "setlinewidth") != NULL
) {
2360 sscanf(temp
, "%f %*s", &xobjs
.pagelist
[areawin
->page
]->wirewidth
);
2361 xobjs
.pagelist
[areawin
->page
]->wirewidth
/= 1.3;
2364 else if (strstr(temp
, "insertion") != NULL
) {
2365 /* read in an included background image */
2368 else if (strstr(temp
, "<<") != NULL
) {
2369 char *buffer
= temp
, *endptr
;
2370 /* Make sure we have the whole dictionary before calling */
2371 while (strstr(buffer
, ">>") == NULL
) {
2372 if (buffer
== temp
) {
2373 buffer
= (char *)malloc(strlen(buffer
) + 150);
2374 strcpy(buffer
, temp
);
2377 buffer
= (char *)realloc(buffer
, strlen(buffer
) + 150);
2378 endptr
= ridnewline(buffer
);
2380 fgets(endptr
, 149, ps
);
2382 /* read top-level parameter dictionary */
2383 readparams(NULL
, NULL
, topobject
, buffer
);
2384 if (buffer
!= temp
) free(buffer
);
2387 if (fgets(temp
, 149, ps
) == NULL
) {
2388 Wprintf("Error: Problems encountered in page header.");
2393 load_in_progress
= True
;
2394 objectread(ps
, topobject
, offx
, offy
, LIBRARY
, temp
, DEFAULTCOLOR
, NULL
);
2395 load_in_progress
= False
;
2397 /* skip to next page boundary or file trailer */
2399 if (strstr(temp
, "showpage") != NULL
&& multipage
!= 1) {
2402 skiptocomment(temp
, 149, ps
);
2404 /* check for new filename if this is a crash recovery file */
2405 if ((fstop
= strstr(temp
, "is_filename")) != NULL
) {
2406 strncpy(inname
, temp
+ 2, (int)(fstop
- temp
- 3));
2407 *(inname
+ (int)(fstop
- temp
) - 3) = '\0';
2408 fgets(temp
, 149, ps
);
2409 skiptocomment(temp
, 149, ps
);
2413 /* Finally: set the filename and pagename for this page */
2416 char tpstr
[6], *rootptr
;
2418 /* Set filename and page title. */
2420 if (xobjs
.pagelist
[areawin
->page
]->filename
!= NULL
)
2421 free(xobjs
.pagelist
[areawin
->page
]->filename
);
2422 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(inname
);
2424 /* Get the root name (after all path components) */
2426 rootptr
= strrchr(xobjs
.pagelist
[areawin
->page
]->filename
, '/');
2427 if (rootptr
== NULL
) rootptr
= xobjs
.pagelist
[areawin
->page
]->filename
;
2430 /* If we didn't read in a page name from the %%Page: header line, then */
2431 /* set the page name to the root name of the file. */
2433 sprintf(tpstr
, "%d", page
+ 1);
2434 if (!strcmp(pagestr
, tpstr
)) {
2435 if (rootptr
== NULL
)
2436 sprintf(topobject
->name
, "Page %d", page
+ 1);
2438 sprintf(topobject
->name
, "%.79s", rootptr
);
2440 /* Delete filename extensions ".ps" or ".eps" from the page name */
2441 if ((pdchar
= strrchr(topobject
->name
, '.')) != NULL
) {
2442 if (!strcmp(pdchar
+ 1, "ps") || !strcmp(pdchar
+ 1, "eps"))
2447 sprintf(topobject
->name
, "%.79s", pagestr
);
2449 renamepage(areawin
->page
);
2452 /* set object position to fit to window separately for each page */
2453 calcbbox(areawin
->topinstance
);
2454 centerview(areawin
->topinstance
);
2457 /* Crash file recovery: read any out-of-page library definitions tacked */
2458 /* onto the end of the file into the user library. */
2459 if (strncmp(temp
, "%%Trailer", 9)) {
2460 load_in_progress
= True
;
2461 objectread(ps
, topobject
, 0, 0, USERLIB
, temp
, DEFAULTCOLOR
, NULL
);
2462 load_in_progress
= False
;
2465 cleanupaliases(USERLIB
);
2467 /* Connect master->slave schematics */
2468 while (connlist
!= NULL
) {
2469 connects
*thisconn
= connlist
;
2470 objectptr master
= NameToPageObject(thisconn
->master
, NULL
, NULL
);
2472 xobjs
.pagelist
[thisconn
->page
]->pageinst
->thisobject
->symschem
= master
;
2473 xobjs
.pagelist
[thisconn
->page
]->pageinst
->thisobject
->schemtype
= SECONDARY
;
2476 Fprintf(stderr
, "Error: Cannot find primary schematic for %s\n",
2477 xobjs
.pagelist
[thisconn
->page
]->pageinst
->thisobject
->name
);
2479 connlist
= thisconn
->next
;
2480 free(thisconn
->master
);
2484 Wprintf("Loaded file: %s (%d page%s)", inname
, multipage
,
2485 (multipage
> 1 ? "s" : ""));
2487 composelib(loclibnum
);
2488 centerview(xobjs
.libtop
[loclibnum
]);
2489 composelib(PAGELIB
);
2491 if (compare_version(version
, PROG_VERSION
) == 1) {
2492 Wprintf("WARNING: file %s is version %s vs. executable version %s",
2493 inname
, version
, PROG_VERSION
);
2496 strcpy(version
, PROG_VERSION
);
2501 /*------------------------------------------------------*/
2502 /* Object name comparison: True if names are equal, */
2503 /* not counting leading underscores. */
2504 /*------------------------------------------------------*/
2506 int objnamecmp(char *name1
, char *name2
)
2508 char *n1ptr
= name1
;
2509 char *n2ptr
= name2
;
2511 while (*n1ptr
== '_') n1ptr
++;
2512 while (*n2ptr
== '_') n2ptr
++;
2514 return (strcmp(n1ptr
, n2ptr
));
2517 /*------------------------------------------------------*/
2518 /* Standard delimiter matching character. */
2519 /*------------------------------------------------------*/
2521 char standard_delimiter_end(char source
)
2525 case '(': target
= ')'; break;
2526 case '[': target
= ']'; break;
2527 case '{': target
= '}'; break;
2528 case '<': target
= '>'; break;
2529 default: target
= source
;
2534 /*------------------------------------------------------*/
2535 /* Find matching parenthesis, bracket, brace, or tag */
2536 /* Don't count when backslash character '\' is in front */
2537 /*------------------------------------------------------*/
2539 u_char
*find_delimiter(u_char
*fstring
)
2543 u_char
*search
= fstring
;
2544 u_char source
= *fstring
;
2547 target
= (u_char
)standard_delimiter_end((char)source
);
2548 while (*++search
!= '\0') {
2549 if (*search
== source
&& *(search
- 1) != '\\') count
++;
2550 else if (*search
== target
&& *(search
- 1) != '\\') count
--;
2551 if (count
== 0) break;
2556 /*----------------------------------------------------------------------*/
2557 /* Remove unnecessary font change information from a label */
2558 /*----------------------------------------------------------------------*/
2560 void cleanuplabel(stringpart
**strhead
)
2562 stringpart
*curpart
= *strhead
;
2563 int oldfont
, curfont
;
2564 Boolean fline
= False
;
2566 oldfont
= curfont
= -1;
2568 while (curpart
!= NULL
) {
2569 switch (curpart
->type
) {
2571 if (curfont
== curpart
->data
.font
) {
2572 /* Font change is redundant: remove it */
2573 /* Careful! font changes remove overline/underline; if */
2574 /* either one is in effect, replace it with "noline" */
2576 curpart
->type
= NOLINE
;
2578 curpart
= deletestring(curpart
, strhead
, NULL
);
2581 curfont
= curpart
->data
.font
;
2586 /* Old style font scale is always written absolute, not relative. */
2587 /* Changes in scale were not allowed, so just get rid of them. */
2588 if (compare_version(version
, "2.3") < 0)
2589 curpart
= deletestring(curpart
, strhead
, areawin
->topinstance
);
2592 /* A font change may occur inside a parameter, so any font */
2593 /* declaration after a parameter must be considered to be */
2597 curfont
= oldfont
= -1;
2600 case OVERLINE
: case UNDERLINE
:
2608 case NORMALSCRIPT
: case RETURN
:
2609 if (oldfont
!= -1) {
2615 case SUBSCRIPT
: case SUPERSCRIPT
:
2620 if (curpart
!= NULL
)
2621 curpart
= curpart
->nextpart
;
2625 /*----------------------------------------------------------------------*/
2626 /* Read label segments */
2627 /*----------------------------------------------------------------------*/
2629 void readlabel(objectptr localdata
, char *lineptr
, stringpart
**strhead
)
2631 Boolean fline
= False
;
2632 /* char *sptr; (jdk) */
2634 char *endptr
, *segptr
= lineptr
;
2636 stringpart
*newpart
;
2639 while (*segptr
!= '\0') { /* Look through all segments */
2641 while (isspace(*segptr
) && (*segptr
!= '\0')) segptr
++;
2643 if (*segptr
== '(' || *segptr
== '{') {
2644 endptr
= find_delimiter(segptr
);
2646 /* null string (e.g., null parameter substitution) */
2647 if ((*segptr
== '(') && (*(segptr
+ 1) == '\0')) {
2652 else if (*segptr
== '\0' || *segptr
== '}') break;
2654 makesegment(strhead
, *strhead
);
2657 /* Embedded command is in braces: {} */
2659 if (*segptr
== '{') {
2661 /* Find the command for this PostScript procedure */
2662 char *cmdptr
= endptr
- 2;
2663 while (isspace(*cmdptr
)) cmdptr
--;
2664 while (!isspace(*cmdptr
) && (cmdptr
> segptr
)) cmdptr
--;
2668 if (!strncmp(cmdptr
, "Ss", 2))
2669 newpart
->type
= SUPERSCRIPT
;
2670 else if (!strncmp(cmdptr
, "ss", 2))
2671 newpart
->type
= SUBSCRIPT
;
2672 else if (!strncmp(cmdptr
, "ns", 2))
2673 newpart
->type
= NORMALSCRIPT
;
2674 else if (!strncmp(cmdptr
, "hS", 2))
2675 newpart
->type
= HALFSPACE
;
2676 else if (!strncmp(cmdptr
, "qS", 2))
2677 newpart
->type
= QTRSPACE
;
2678 else if (!strncmp(cmdptr
, "CR", 2)) {
2679 newpart
->type
= RETURN
;
2680 newpart
->data
.flags
= 0;
2682 else if (!strcmp(cmdptr
, "Ts")) /* "Tab set" command */
2683 newpart
->type
= TABSTOP
;
2684 else if (!strcmp(cmdptr
, "Tf")) /* "Tab forward" command */
2685 newpart
->type
= TABFORWARD
;
2686 else if (!strcmp(cmdptr
, "Tb")) /* "Tab backward" command */
2687 newpart
->type
= TABBACKWARD
;
2688 else if (!strncmp(cmdptr
, "ol", 2)) {
2689 newpart
->type
= OVERLINE
;
2692 else if (!strncmp(cmdptr
, "ul", 2)) {
2693 newpart
->type
= UNDERLINE
;
2696 else if (!strncmp(cmdptr
, "sce", 3)) { /* revert to default color */
2697 newpart
->type
= FONT_COLOR
;
2698 newpart
->data
.color
= DEFAULTCOLOR
;
2700 else if (cmdptr
== segptr
) { /* cancel over- or underline */
2701 newpart
->type
= NOLINE
;
2704 /* To-do: replace old-style backspace with tab stop */
2705 else if (!strcmp(cmdptr
, "bs")) {
2706 Wprintf("Warning: Obsolete backspace command ommitted in text");
2708 else if (!strcmp(cmdptr
, "Kn")) { /* "Kern" command */
2710 sscanf(segptr
, "%d %d", &kx
, &ky
);
2711 newpart
->type
= KERN
;
2712 newpart
->data
.kern
[0] = kx
;
2713 newpart
->data
.kern
[1] = ky
;
2715 else if (!strcmp(cmdptr
, "MR")) { /* "Margin stop" command */
2717 sscanf(segptr
, "%d", &width
);
2718 newpart
->type
= MARGINSTOP
;
2719 newpart
->data
.width
= width
;
2721 else if (!strcmp(cmdptr
, "scb")) { /* change color command */
2724 sscanf(segptr
, "%f %f %f", &cr
, &cg
, &cb
);
2725 newpart
->type
= FONT_COLOR
;
2726 cindex
= rgb_alloccolor((int)(cr
* 65535), (int)(cg
* 65535),
2728 newpart
->data
.color
= cindex
;
2730 else if (!strcmp(cmdptr
, "cf")) { /* change font or scale command */
2731 char *nextptr
, *newptr
= segptr
;
2733 /* Set newptr to the fontname and nextptr to the next token. */
2734 while (*newptr
!= '/' && *newptr
!= '\0') newptr
++;
2735 if (*newptr
++ == '\0') {
2736 Wprintf("Error: Bad change-font command");
2737 newpart
->type
= NOLINE
; /* placeholder */
2739 for (nextptr
= newptr
; !isspace(*nextptr
); nextptr
++);
2740 *(nextptr
++) = '\0';
2741 while (isspace(*nextptr
)) nextptr
++;
2743 for (j
= 0; j
< fontcount
; j
++)
2744 if (!strcmp(newptr
, fonts
[j
].psname
))
2747 if (j
== fontcount
) /* this is a non-loaded font */
2748 if (loadfontfile(newptr
) < 0) {
2749 if (fontcount
> 0) {
2750 Wprintf("Error: Font \"%s\" not found---using default.", newptr
);
2754 Wprintf("Error: No fonts!");
2755 newpart
->type
= NOLINE
; /* placeholder */
2759 if (isdigit(*nextptr
)) { /* second form of "cf" command---includes scale */
2761 sscanf(nextptr
, "%f", &locscale
);
2762 newpart
->type
= FONT_SCALE
;
2763 newpart
->data
.scale
= locscale
;
2764 makesegment(strhead
, *strhead
);
2767 newpart
->type
= FONT_NAME
;
2768 newpart
->data
.font
= j
;
2770 else { /* This exec isn't a known label function */
2771 Wprintf("Error: unknown substring function");
2772 newpart
->type
= NOLINE
; /* placeholder */
2776 /* Text substring is in parentheses: () */
2778 else if (*segptr
== '(') {
2779 if (fline
== True
) {
2780 newpart
->type
= NOLINE
;
2781 makesegment(strhead
, *strhead
);
2785 newpart
->type
= TEXT_STRING
;
2786 newpart
->data
.string
= (u_char
*)malloc(1 + strlen(++segptr
));
2788 /* Copy string, translating octal codes into 8-bit characters */
2789 parse_ps_string(segptr
, newpart
->data
.string
, strlen(segptr
), TRUE
, TRUE
);
2792 /* Parameterized substrings are denoted by parameter key. */
2793 /* The parameter (default and/or substitution value) is */
2794 /* assumed to exist. */
2798 parse_ps_string(segptr
, key
, 99, FALSE
, TRUE
);
2799 if (strlen(key
) > 0) {
2800 newpart
->type
= PARAM_START
;
2801 newpart
->data
.string
= (char *)malloc(1 + strlen(key
));
2802 strcpy(newpart
->data
.string
, key
);
2804 /* check for compatibility between the parameter value and */
2805 /* the number of parameters and parameter type. */
2807 ops
= match_param(localdata
, key
);
2809 Fprintf(stderr
, "readlabel() error: No such parameter %s!\n", key
);
2810 deletestring(newpart
, strhead
, areawin
->topinstance
);
2813 /* Fprintf(stdout, "Parameter %s called from object %s\n", */
2814 /* key, localdata->name); */
2816 endptr
= segptr
+ 1;
2817 while (!isspace(*endptr
) && (*endptr
!= '\0')) endptr
++;
2823 /*--------------------------------------*/
2824 /* skip over whitespace in string input */
2825 /*--------------------------------------*/
2827 char *skipwhitespace(char *lineptr
)
2829 char *locptr
= lineptr
;
2831 while (isspace(*locptr
) && (*locptr
!= '\n') && (*locptr
!= '\0')) locptr
++;
2835 /*-------------------------------------------*/
2836 /* advance to the next token in string input */
2837 /*-------------------------------------------*/
2839 char *advancetoken(char *lineptr
)
2841 char *locptr
= lineptr
;
2843 while (!isspace(*locptr
) && (*locptr
!= '\n') && (*locptr
!= '\0')) locptr
++;
2844 while (isspace(*locptr
) && (*locptr
!= '\n') && (*locptr
!= '\0')) locptr
++;
2848 /*------------------------------------------------------*/
2849 /* Read a parameter list for an object instance call. */
2850 /* This uses the key-value dictionary method but also */
2851 /* allows the "old style" in which each parameter */
2852 /* was automatically assigned the key v1, v2, etc. */
2853 /*------------------------------------------------------*/
2855 void readparams(objectptr localdata
, objinstptr newinst
, objectptr libobj
,
2858 oparamptr newops
, objops
, fops
;
2859 char *arrayptr
, *endptr
, *arraynext
;
2863 if ((arrayptr
= strstr(buffer
, "<<")) == NULL
)
2864 if ((arrayptr
= strchr(buffer
, '[')) == NULL
)
2867 endptr
= find_delimiter(arrayptr
);
2868 if (*arrayptr
== '<') {
2869 arrayptr
++; /* move to second '<' in "<<" */
2870 endptr
--; /* back up to first '>' in ">>" */
2873 /* move to next non-space token after opening bracket */
2875 while (isspace(*arrayptr
) && *arrayptr
!= '\0') arrayptr
++;
2877 while ((*arrayptr
!= '\0') && (arrayptr
< endptr
)) {
2879 newops
= (oparamptr
)malloc(sizeof(oparam
));
2881 /* Arrays contain values only. Dictionaries contain key:value pairs */
2882 if (*endptr
== '>') { /* dictionary type */
2883 if (*arrayptr
!= '/') {
2884 Fprintf(stdout
, "Error: Dictionary key is a literal, not a name\n");
2886 else arrayptr
++; /* Skip PostScript name delimiter */
2887 parse_ps_string(arrayptr
, paramkey
, 99, FALSE
, TRUE
);
2888 newops
->key
= (char *)malloc(1 + strlen(paramkey
));
2889 strcpy(newops
->key
, paramkey
);
2890 arrayptr
= advancetoken(arrayptr
);
2892 else { /* array type; keys are "v1", "v2", etc. */
2894 newops
->key
= (char *)malloc(6);
2895 sprintf(newops
->key
, "v%d", paramno
);
2898 /* Find matching parameter in object definition */
2900 objops
= match_param(libobj
, newops
->key
);
2901 if (objops
== NULL
) {
2902 Fprintf(stdout
, "Error: parameter %s does not exist in object %s!\n",
2903 newops
->key
, libobj
->name
);
2910 /* Add to instance's parameter list */
2911 /* If newinst is null, then the parameters are added to libobj */
2912 newops
->next
= NULL
;
2915 /* Delete any parameters with duplicate names. This */
2916 /* This may indicate an expression parameter that was */
2917 /* precomputed while determining the bounding box. */
2919 for (fops
= newinst
->params
; fops
!= NULL
; fops
= fops
->next
)
2920 if (!strcmp(fops
->key
, newops
->key
))
2921 if ((fops
= free_instance_param(newinst
, fops
)) == NULL
)
2924 if (newinst
->params
== NULL
)
2925 newinst
->params
= newops
;
2927 for (fops
= newinst
->params
; fops
->next
!= NULL
; fops
= fops
->next
);
2928 fops
->next
= newops
;
2932 if (libobj
->params
== NULL
)
2933 libobj
->params
= newops
;
2935 for (fops
= libobj
->params
; fops
->next
!= NULL
; fops
= fops
->next
);
2936 fops
->next
= newops
;
2940 /* Fill in "which" entry from the object default */
2941 newops
->which
= (newinst
) ? objops
->which
: 0;
2943 /* Check next token. If not either end-of-dictionary or */
2944 /* the next parameter key, then value is an expression. */
2945 /* Expressions are written as two strings, the first the */
2946 /* result of evaluting the expression, and the second the */
2947 /* expression itself, followed by "pop" to prevent the */
2948 /* PostScript interpreter from trying to evaluate the */
2949 /* expression (which is not in PostScript). */
2951 if (*arrayptr
== '(' || *arrayptr
== '{')
2952 arraynext
= find_delimiter(arrayptr
);
2954 arraynext
= arrayptr
;
2955 arraynext
= advancetoken(arraynext
);
2957 if ((*endptr
== '>') && (arraynext
< endptr
) && (*arraynext
!= '/')) {
2958 char *substrend
, *arraysave
;
2960 if (*arraynext
== '(' || *arraynext
== '{') {
2962 substrend
= find_delimiter(arraynext
);
2963 arraysave
= arraynext
+ 1;
2964 arraynext
= advancetoken(substrend
);
2966 newops
->type
= (u_char
)XC_EXPR
;
2967 newops
->which
= P_EXPRESSION
; /* placeholder */
2970 if (strncmp(arraynext
, "pop ", 4)) {
2971 Wprintf("Error: bad expression parameter!\n");
2973 newops
->parameter
.expr
= strdup("expr 0");
2975 newops
->parameter
.expr
= strdup("0");
2977 arrayptr
= advancetoken(arrayptr
);
2980 newops
->parameter
.expr
= strdup(arraysave
);
2981 arrayptr
= advancetoken(arraynext
);
2985 else if (*arrayptr
== '(' || *arrayptr
== '{') {
2987 char *substrend
, csave
;
2988 stringpart
*endpart
;
2990 /* type XC_STRING */
2992 substrend
= find_delimiter(arrayptr
);
2993 csave
= *(++substrend
);
2995 if (*arrayptr
== '{') arrayptr
++;
2997 /* A numerical value immediately following the opening */
2998 /* brace indicates a color parameter. */
2999 if (sscanf(arrayptr
, "%f %f %f", &r
, &g
, &b
) == 3) {
3000 newops
->type
= (u_char
)XC_INT
;
3001 newops
->which
= P_COLOR
;
3002 newops
->parameter
.ivalue
= rgb_alloccolor((int)(r
* 65535),
3003 (int)(g
* 65535), (int)(b
* 65535));
3007 char *arraytmp
= arrayptr
;
3008 char linkdefault
[5] = "(%n)";
3010 newops
->type
= (u_char
)XC_STRING
;
3011 newops
->which
= P_SUBSTRING
;
3012 newops
->parameter
.string
= NULL
;
3014 /* Quick check for "link" parameter: make object name into "%n" */
3015 if (!strcmp(newops
->key
, "link"))
3016 if (!strncmp(arrayptr
+ 1, libobj
->name
, strlen(libobj
->name
)) &&
3017 !strcmp(arrayptr
+ strlen(libobj
->name
) + 1, ")"))
3018 arraytmp
= linkdefault
;
3020 readlabel(libobj
, arraytmp
, &(newops
->parameter
.string
));
3023 /* Append a PARAM_END to the parameter string */
3025 endpart
= makesegment(&(newops
->parameter
.string
), NULL
);
3026 endpart
->type
= PARAM_END
;
3027 endpart
->data
.string
= (u_char
*)NULL
;
3029 arrayptr
= substrend
;
3030 while (isspace(*arrayptr
) && *arrayptr
!= '\0')
3034 /* char *token; (jdk) */
3037 /* type XC_FLOAT or XC_INT, or an indirect reference */
3039 newops
->type
= (newinst
) ? objops
->type
: (u_char
)XC_FLOAT
;
3041 if (newops
->type
== XC_FLOAT
) {
3042 scanned
= sscanf(arrayptr
, "%f", &(newops
->parameter
.fvalue
));
3043 /* Fprintf(stdout, "Object %s called with parameter "
3044 "%s value %g\n", libobj->name,
3045 newops->key, newops->parameter.fvalue); */
3047 else if (newops
->type
== XC_INT
) {
3048 scanned
= sscanf(arrayptr
, "%d", &(newops
->parameter
.ivalue
));
3049 /* Fprintf(stdout, "Object %s called with parameter "
3050 "%s value %d\n", libobj->name,
3051 newops->key, newops->parameter.ivalue); */
3053 else if (newops
->type
== XC_EXPR
) {
3054 /* Instance values of parameters hold the last evaluated */
3055 /* result and will be regenerated, so we can ignore them */
3056 /* here. By ignoring it, we don't have to deal with issues */
3057 /* like type promotion. */
3058 free_instance_param(newinst
, newops
);
3059 scanned
= 1; /* avoid treating as an indirect ref */
3061 else if (newops
->type
== XC_STRING
) {
3062 /* Fill string record, so we have a valid record. This will */
3063 /* be blown away and replaced by opsubstitute(), but it must */
3064 /* have an initial valid entry. */
3066 newops
->parameter
.string
= NULL
;
3067 tmpptr
= makesegment(&newops
->parameter
.string
, NULL
);
3068 tmpptr
->type
= TEXT_STRING
;
3069 tmpptr
= makesegment(&newops
->parameter
.string
, NULL
);
3070 tmpptr
->type
= PARAM_END
;
3073 Fprintf(stderr
, "Error: unknown parameter type!\n");
3077 /* Indirect reference --- create an eparam in the instance */
3078 parse_ps_string(arrayptr
, paramkey
, 99, FALSE
, TRUE
);
3080 if (!newinst
|| !localdata
) {
3081 /* Only object instances can use indirect references */
3082 Fprintf(stderr
, "Error: parameter default %s cannot "
3083 "be parsed!\n", paramkey
);
3085 else if (match_param(localdata
, paramkey
) == NULL
) {
3086 /* Reference key must exist in the calling object */
3087 Fprintf(stderr
, "Error: parameter value %s cannot be parsed!\n",
3091 /* Create an eparam record in the instance */
3092 eparamptr newepp
= make_new_eparam(paramkey
);
3093 newepp
->flags
|= P_INDIRECT
;
3094 newepp
->pdata
.refkey
= strdup(newops
->key
);
3095 newepp
->next
= newinst
->passed
;
3096 newinst
->passed
= newepp
;
3100 arrayptr
= advancetoken(arrayptr
);
3104 /* Calculate the unique bounding box for the instance */
3106 if (newinst
&& (newinst
->params
!= NULL
)) {
3107 opsubstitute(libobj
, newinst
);
3108 calcbboxinst(newinst
);
3112 /*--------------------------------------------------------------*/
3113 /* Read a value which might be a short integer or a parameter. */
3114 /* If the value is a parameter, check the parameter list to see */
3115 /* if it needs to be re-typecast. Return the position to the */
3116 /* next token in "lineptr". */
3117 /*--------------------------------------------------------------*/
3119 char *varpscan(objectptr localdata
, char *lineptr
, short *hvalue
,
3120 genericptr thiselem
, int pointno
, int offset
, u_char which
)
3122 oparamptr ops
= NULL
;
3124 /* char *nexttok; (jdk) */
3127 if (sscanf(lineptr
, "%hd", hvalue
) != 1) {
3128 parse_ps_string(lineptr
, key
, 99, FALSE
, TRUE
);
3130 ops
= match_param(localdata
, key
);
3131 newepp
= make_new_eparam(key
);
3133 /* Add parameter to the linked list */
3134 newepp
->next
= thiselem
->passed
;
3135 thiselem
->passed
= newepp
;
3136 newepp
->pdata
.pointno
= pointno
;
3140 /* It cannot be known whether a parameter value is a float or int */
3141 /* until we see how the parameter is used. So we always read the */
3142 /* parameter default as a float, and re-typecast it if necessary. */
3144 if (ops
->type
== XC_FLOAT
) {
3146 /* (add 0.1 to avoid roundoff error in conversion to integer) */
3147 ops
->parameter
.ivalue
= (int)(ops
->parameter
.fvalue
+
3148 ((ops
->parameter
.fvalue
< 0) ? -0.1 : 0.1));
3151 *hvalue
= (short)ops
->parameter
.ivalue
;
3154 *hvalue
= 0; /* okay; will get filled in later */
3155 Fprintf(stderr
, "Error: parameter %s was used but not defined!\n", key
);
3159 *hvalue
-= (short)offset
;
3161 return advancetoken(skipwhitespace(lineptr
));
3164 /*--------------------------------------------------------------*/
3165 /* Read a value which might be a short integer or a parameter, */
3166 /* but which is not a point in a pointlist. */
3167 /*--------------------------------------------------------------*/
3169 char *varscan(objectptr localdata
, char *lineptr
, short *hvalue
,
3170 genericptr thiselem
, u_char which
)
3172 return varpscan(localdata
, lineptr
, hvalue
, thiselem
, 0, 0, which
);
3175 /*--------------------------------------------------------------*/
3176 /* Read a value which might be a float or a parameter. */
3177 /* Return the position to the next token in "lineptr". */
3178 /*--------------------------------------------------------------*/
3180 char *varfscan(objectptr localdata
, char *lineptr
, float *fvalue
,
3181 genericptr thiselem
, u_char which
)
3183 oparamptr ops
= NULL
;
3187 if (sscanf(lineptr
, "%f", fvalue
) != 1) {
3188 parse_ps_string(lineptr
, key
, 99, FALSE
, TRUE
);
3190 /* This bit of a hack takes care of scale-variant */
3191 /* linewidth specifiers for object instances. */
3193 if (!strncmp(key
, "/sv", 3)) {
3194 ((objinstptr
)thiselem
)->style
&= ~LINE_INVARIANT
;
3195 return varfscan(localdata
, advancetoken(skipwhitespace(lineptr
)),
3196 fvalue
, thiselem
, which
);
3199 ops
= match_param(localdata
, key
);
3200 newepp
= make_new_eparam(key
);
3202 /* Add parameter to the linked list */
3203 newepp
->next
= thiselem
->passed
;
3204 thiselem
->passed
= newepp
;
3208 *fvalue
= ops
->parameter
.fvalue
;
3211 Fprintf(stderr
, "Error: no parameter \"%s\" defined!\n", key
);
3214 /* advance to next token */
3215 return advancetoken(skipwhitespace(lineptr
));
3218 /*--------------------------------------------------------------*/
3219 /* Same as varpscan(), but for path types only. */
3220 /*--------------------------------------------------------------*/
3222 char *varpathscan(objectptr localdata
, char *lineptr
, short *hvalue
,
3223 genericptr
*thiselem
, pathptr thispath
, int pointno
, int offset
,
3224 u_char which
, eparamptr
*nepptr
)
3226 oparamptr ops
= NULL
;
3230 if (nepptr
!= NULL
) *nepptr
= NULL
;
3232 if (sscanf(lineptr
, "%hd", hvalue
) != 1) {
3233 parse_ps_string(lineptr
, key
, 99, FALSE
, TRUE
);
3234 ops
= match_param(localdata
, key
);
3235 newepp
= make_new_eparam(key
);
3236 newepp
->pdata
.pathpt
[1] = pointno
;
3238 if (thiselem
== NULL
)
3239 newepp
->pdata
.pathpt
[0] = (short)0;
3241 short elemidx
= (short)(thiselem
- thispath
->plist
);
3242 if (elemidx
>= 0 && elemidx
< thispath
->parts
)
3243 newepp
->pdata
.pathpt
[0] = (short)(thiselem
- thispath
->plist
);
3245 Fprintf(stderr
, "Error: Bad parameterized path point!\n");
3250 if (nepptr
!= NULL
) *nepptr
= newepp
;
3252 /* Add parameter to the linked list. */
3254 newepp
->next
= thispath
->passed
;
3255 thispath
->passed
= newepp
;
3259 /* It cannot be known whether a parameter value is a float or int */
3260 /* until we see how the parameter is used. So we always read the */
3261 /* parameter default as a float, and re-typecast it if necessary. */
3263 if (ops
->type
== XC_FLOAT
) {
3265 /* (add 0.1 to avoid roundoff error in conversion to integer) */
3266 ops
->parameter
.ivalue
= (int)(ops
->parameter
.fvalue
+
3267 ((ops
->parameter
.fvalue
< 0) ? -0.1 : 0.1));
3270 *hvalue
= (short)ops
->parameter
.ivalue
;
3273 *hvalue
= 0; /* okay; will get filled in later */
3274 Fprintf(stderr
, "Error: parameter %s was used but not defined!\n", key
);
3279 *hvalue
-= (short)offset
;
3280 return advancetoken(skipwhitespace(lineptr
));
3283 /*--------------------------------------------------------------*/
3284 /* Create a new instance of an object in the library's list of */
3285 /* instances. This instance will be used on the library page */
3286 /* when doing "composelib()". */
3287 /*--------------------------------------------------------------*/
3289 objinstptr
addtoinstlist(int libnum
, objectptr libobj
, Boolean
virtual)
3291 objinstptr newinst
= (objinstptr
) malloc(sizeof(objinst
));
3292 liblistptr spec
= (liblistptr
) malloc(sizeof(liblist
));
3295 newinst
->type
= OBJINST
;
3296 instancedefaults(newinst
, libobj
, 0, 0);
3298 spec
->virtual = (u_char
)virtual;
3299 spec
->thisinst
= newinst
;
3302 /* Add to end, so that duplicate, parameterized instances */
3303 /* always come after the original instance with the default */
3306 if ((srch
= xobjs
.userlibs
[libnum
].instlist
) == NULL
)
3307 xobjs
.userlibs
[libnum
].instlist
= spec
;
3309 while (srch
->next
!= NULL
) srch
= srch
->next
;
3313 /* Calculate the instance-specific bounding box */
3314 calcbboxinst(newinst
);
3319 /*--------------------------------------------------------------*/
3320 /* Deal with object reads: Create a new object and prepare for */
3321 /* reading. The library number is passed as "mode". */
3322 /*--------------------------------------------------------------*/
3324 objectptr
*new_library_object(short mode
, char *name
, objlistptr
*retlist
,
3325 TechPtr defaulttech
)
3327 objlistptr newdef
, redef
= NULL
;
3328 objectptr
*newobject
, *libobj
;
3329 objectptr
*curlib
= (mode
== FONTLIB
) ?
3330 xobjs
.fontlib
.library
: xobjs
.userlibs
[mode
- LIBRARY
].library
;
3331 short *libobjects
= (mode
== FONTLIB
) ?
3332 &xobjs
.fontlib
.number
: &xobjs
.userlibs
[mode
- LIBRARY
].number
;
3334 char *nsptr
, *fullname
= name
;
3336 curlib
= (objectptr
*) realloc(curlib
, (*libobjects
+ 1)
3337 * sizeof(objectptr
));
3338 if (mode
== FONTLIB
) xobjs
.fontlib
.library
= curlib
;
3339 else xobjs
.userlibs
[mode
- LIBRARY
].library
= curlib
;
3341 /* For (older) libraries that do not use technologies, give the */
3342 /* object a technology name in the form <library>::<object> */
3344 if ((nsptr
= strstr(name
, "::")) == NULL
) {
3345 int deftechlen
= (defaulttech
== NULL
) ? 0 : strlen(defaulttech
->technology
);
3346 fullname
= (char *)malloc(deftechlen
+ strlen(name
) + 3);
3347 if (defaulttech
== NULL
)
3348 sprintf(fullname
, "::%s", name
);
3350 sprintf(fullname
, "%s::%s", defaulttech
->technology
, name
);
3353 /* initial 1-pointer allocations */
3355 newobject
= curlib
+ (*libobjects
);
3356 *newobject
= (objectptr
) malloc(sizeof(object
));
3357 initmem(*newobject
);
3359 /* check that this object is not already in list of objects */
3361 if (mode
== FONTLIB
) {
3362 for (libobj
= xobjs
.fontlib
.library
; libobj
!= xobjs
.fontlib
.library
+
3363 xobjs
.fontlib
.number
; libobj
++) {
3364 /* This font character may be a redefinition of another */
3365 if (!objnamecmp(fullname
, (*libobj
)->name
)) {
3366 newdef
= (objlistptr
) malloc(sizeof(objlist
));
3367 newdef
->libno
= FONTLIB
;
3368 newdef
->thisobject
= *libobj
;
3369 newdef
->next
= redef
;
3375 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
3376 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
3377 libobj
= xobjs
.userlibs
[i
].library
+ j
;
3378 /* This object may be a redefinition of another object */
3379 if (!objnamecmp(fullname
, (*libobj
)->name
)) {
3380 newdef
= (objlistptr
) malloc(sizeof(objlist
));
3381 newdef
->libno
= i
+ LIBRARY
;
3382 newdef
->thisobject
= *libobj
;
3383 newdef
->next
= redef
;
3391 sprintf((*newobject
)->name
, "%s", fullname
);
3392 if (fullname
!= name
) free(fullname
);
3394 /* initmem() initialized schemtype to PRIMARY; change it. */
3395 (*newobject
)->schemtype
= (mode
== FONTLIB
) ? GLYPH
: SYMBOL
;
3397 /* If the object declares a technology name that is different from the */
3398 /* default, then add the technology name to the list of technologies, */
3399 /* with a NULL filename. */
3401 if (mode
!= FONTLIB
) AddObjectTechnology(*newobject
);
3407 /*--------------------------------------------------------------*/
3408 /* do an exhaustive comparison between a new object and any */
3409 /* object having the same name. If they are the same, destroy */
3410 /* the duplicate. If different, rename the original one. */
3411 /*--------------------------------------------------------------*/
3413 Boolean
library_object_unique(short mode
, objectptr newobject
, objlistptr redef
)
3415 Boolean is_unique
= True
;
3417 short *libobjects
= (mode
== FONTLIB
) ?
3418 &xobjs
.fontlib
.number
: &xobjs
.userlibs
[mode
- LIBRARY
].number
;
3421 return is_unique
; /* No name conflicts; object is okay as-is */
3423 for (newdef
= redef
; newdef
!= NULL
; newdef
= newdef
->next
) {
3425 /* Must make sure that default parameter values are */
3426 /* plugged into both objects! */
3427 opsubstitute(newdef
->thisobject
, NULL
);
3428 opsubstitute(newobject
, NULL
);
3430 if (objcompare(newobject
, newdef
->thisobject
) == True
) {
3431 addalias(newdef
->thisobject
, newobject
->name
);
3433 /* If the new object has declared an association to a */
3434 /* schematic, transfer it to the original, and make */
3435 /* sure that the page points to the object which will */
3436 /* be left, not the one which will be destroyed. */
3438 if (newobject
->symschem
!= NULL
) {
3439 newdef
->thisobject
->symschem
= newobject
->symschem
;
3440 newdef
->thisobject
->symschem
->symschem
= newdef
->thisobject
;
3443 reset(newobject
, DESTROY
);
3449 /* Not the same object, but has the same name. This can't */
3450 /* happen within the same input file, so the name of the */
3451 /* original object can safely be altered. */
3453 else if (!strcmp(newobject
->name
, newdef
->thisobject
->name
)) {
3455 /* Replacement---for project management, allow the technology */
3456 /* master version to take precedence over a local version. */
3458 TechPtr nsptr
= GetObjectTechnology(newobject
);
3460 if (nsptr
&& (nsptr
->flags
& TECH_REPLACE
)) {
3461 reset(newobject
, DESTROY
);
3466 checkname(newdef
->thisobject
);
3470 for (; (newdef
= redef
->next
); redef
= newdef
)
3477 /*--------------------------------------------------------------*/
3478 /* Add an instance of the object to the library's instance list */
3479 /*--------------------------------------------------------------*/
3481 void add_object_to_library(short mode
, objectptr newobject
)
3485 if (mode
== FONTLIB
) return;
3487 libinst
= addtoinstlist(mode
- LIBRARY
, newobject
, False
);
3488 calcbboxvalues(libinst
, (genericptr
*)NULL
);
3490 /* Center the view of the object in its instance */
3491 centerview(libinst
);
3494 /*--------------------------------------------------------------*/
3495 /* Continuation Line --- add memory to "buffer" as necessary. */
3496 /* Add a space character to the current text in "buffer" and */
3497 /* return a pointer to the new end-of-text. */
3498 /*--------------------------------------------------------------*/
3500 char *continueline(char **buffer
)
3505 for (lineptr
= *buffer
; (*lineptr
!= '\n') && (*lineptr
!= '\0'); lineptr
++);
3506 /* Repair Windoze-mangled files */
3507 if ((lineptr
> *buffer
) && (*lineptr
== '\n') && (*(lineptr
- 1) == '\r'))
3508 *(lineptr
- 1) = ' ';
3509 if (*lineptr
== '\n') *lineptr
++ = ' ';
3511 bufsize
= (int)(lineptr
- (*buffer
)) + 256;
3512 *buffer
= (char *)realloc((*buffer
), bufsize
* sizeof(char));
3514 return ((*buffer
) + (bufsize
- 256));
3517 /*--------------------------------------------------------------*/
3518 /* Read image data out of the Setup block of the input */
3519 /* We assume that width and height have been parsed from the */
3520 /* "imagedata" line and the file pointer is at the next line. */
3521 /*--------------------------------------------------------------*/
3523 void readimagedata(FILE *ps
, int width
, int height
)
3525 char temp
[150], ascbuf
[6];
3526 int x
, y
, p
, q
, r
, g
, b
, ilen
;
3529 Boolean do_flate
= False
, do_ascii
= False
;
3530 u_char
*filtbuf
, *flatebuf
;
3536 iptr
= addnewimage(NULL
, width
, height
);
3538 /* Read the image data */
3540 fgets(temp
, 149, ps
);
3541 if (strstr(temp
, "ASCII85Decode") != NULL
) do_ascii
= TRUE
;
3543 if (strstr(temp
, "FlateDecode") != NULL
) do_flate
= TRUE
;
3545 if (strstr(temp
, "FlateDecode") != NULL
)
3546 Fprintf(stderr
, "Error: Don't know how to Flate decode!"
3547 " Get zlib and recompile xcircuit!\n");
3549 while (strstr(temp
, "ReusableStreamDecode") == NULL
)
3550 fgets(temp
, 149, ps
); /* Additional piped filter lines */
3552 fgets(temp
, 149, ps
); /* Initial data line */
3555 ilen
= 3 * width
* height
;
3556 filtbuf
= (u_char
*)malloc(ilen
+ 4);
3558 if (!do_ascii
) { /* ASCIIHexDecode algorithm */
3560 for (y
= 0; y
< height
; y
++) {
3561 for (x
= 0; x
< width
; x
++) {
3562 sscanf(pptr
, "%02x%02x%02x", &r
, &g
, &b
);
3563 filtbuf
[q
++] = (u_char
)r
;
3564 filtbuf
[q
++] = (u_char
)g
;
3565 filtbuf
[q
++] = (u_char
)b
;
3567 if (*pptr
== '\n') {
3568 fgets(temp
, 149, ps
);
3574 else { /* ASCII85Decode algorithm */
3579 if (ascbuf
[0] == '~')
3581 else if (ascbuf
[0] == 'z') {
3582 for (y
= 0; y
< 5; y
++) ascbuf
[y
] = '\0';
3585 for (y
= 1; y
< 5; y
++) {
3586 if (*pptr
== '\n') {
3587 fgets(temp
, 149, ps
);
3591 if (ascbuf
[y
] == '~') {
3592 for (; y
< 5; y
++) {
3600 for (y
= 0; y
< 5; y
++) ascbuf
[y
] -= '!';
3603 if (*pptr
== '\n') {
3604 fgets(temp
, 149, ps
);
3608 /* Decode from ASCII85 to binary */
3610 pixel
.i
= ascbuf
[4] + ascbuf
[3] * 85 + ascbuf
[2] * 7225 +
3611 ascbuf
[1] * 614125 + ascbuf
[0] * 52200625;
3613 /* Add in roundoff for final bytes */
3617 pixel
.i
+= 0xff0000;
3625 for (y
= 0; y
< (4 - p
); y
++) {
3626 filtbuf
[q
+ y
] = pixel
.b
[3 - y
];
3629 if (q
>= ilen
) break;
3633 /* Extra decoding goes here */
3637 flatebuf
= (char *)malloc(ilen
);
3638 large_inflate(filtbuf
, q
, &flatebuf
, ilen
);
3647 for (y
= 0; y
< height
; y
++)
3648 for (x
= 0; x
< width
; x
++) {
3653 xcImagePutPixel(iptr
->image
, x
, y
, r
, g
, b
);
3658 fgets(temp
, 149, ps
); /* definition line */
3659 fgets(temp
, 149, ps
); /* pick up name of image from here */
3660 for (pptr
= temp
; !isspace(*pptr
); pptr
++);
3662 iptr
->filename
= strdup(temp
+ 1);
3663 for (x
= 0; x
< 5; x
++) fgets(temp
, 149, ps
); /* skip image dictionary */
3666 /*--------------------------------------------------------------*/
3667 /* Read an object (page) from a file into xcircuit */
3668 /*--------------------------------------------------------------*/
3670 Boolean
objectread(FILE *ps
, objectptr localdata
, short offx
, short offy
,
3671 short mode
, char *retstr
, int ccolor
, TechPtr defaulttech
)
3673 char *temp
, *buffer
, keyword
[80];
3675 float tmpscale
= 0.0;
3677 int curcolor
= ccolor
;
3678 char *colorkey
= NULL
;
3679 char *widthkey
= NULL
;
3682 objinstptr
*newinst
;
3683 eparamptr epptrx
, epptry
; /* used for paths only */
3685 /* path-handling variables */
3691 buffer
= (char *)malloc(256 * sizeof(char));
3695 char *lineptr
, *keyptr
, *saveptr
;
3697 if (fgets(temp
, 255, ps
) == NULL
) {
3698 if (strcmp(keyword
, "restore")) {
3699 Wprintf("Error: end of file.");
3706 /* because PostScript is a stack language, we will scan from the end */
3707 for (lineptr
= buffer
; (*lineptr
!= '\n') && (*lineptr
!= '\0'); lineptr
++);
3708 /* Avoid CR-LF at EOL added by stupid Windoze programs */
3709 if ((lineptr
> buffer
) && *(lineptr
- 1) == '\r') lineptr
--;
3710 if (lineptr
!= buffer
) { /* ignore any blank lines */
3711 for (keyptr
= lineptr
- 1; isspace(*keyptr
) && keyptr
!= buffer
; keyptr
--);
3712 for (; !isspace(*keyptr
) && keyptr
!= buffer
; keyptr
--);
3713 sscanf(keyptr
, "%79s", keyword
);
3715 if (!strcmp(keyword
, "showpage")) {
3716 strncpy(retstr
, buffer
, 150);
3720 /* If we have just read a schematic that is attached */
3721 /* to a symbol, check all of the pin labels in the symbol */
3722 /* to see if they correspond to pin names in the schematic. */
3723 /* The other way around (pin in schematic with no */
3724 /* corresponding name in the symbol) is not an error. */
3726 if (localdata
->symschem
!= NULL
) {
3727 genericptr
*pgen
, *lgen
;
3728 labelptr plab
, lcmp
;
3729 for (pgen
= localdata
->symschem
->plist
; pgen
< localdata
->
3730 symschem
->plist
+ localdata
->symschem
->parts
; pgen
++) {
3731 if (IS_LABEL(*pgen
)) {
3732 plab
= TOLABEL(pgen
);
3733 if (plab
->pin
== LOCAL
) {
3734 for (lgen
= localdata
->plist
; lgen
< localdata
->plist
+
3735 localdata
->parts
; lgen
++) {
3736 if (IS_LABEL(*lgen
)) {
3737 lcmp
= TOLABEL(lgen
);
3738 if (lcmp
->pin
== LOCAL
)
3739 if (!stringcomprelaxed(lcmp
->string
, plab
->string
,
3740 areawin
->topinstance
))
3744 if (lgen
== localdata
->plist
+ localdata
->parts
) {
3745 char *cptr
, *d1ptr
, *d2ptr
;
3746 char *pch
= textprint(plab
->string
, areawin
->topinstance
);
3748 /* Check for likely delimiters before applying warning */
3750 if ((cptr
= strchr(pch
, ':')) != NULL
) {
3751 d1ptr
= strchr(pch
, '[');
3752 d2ptr
= strchr(pch
, ']');
3753 if (d1ptr
!= NULL
&& d2ptr
!= NULL
&&
3754 d1ptr
< cptr
&& d2ptr
> cptr
) {
3755 if (areawin
->buschar
!= '[') {
3756 areawin
->buschar
= '[';
3757 Fprintf(stderr
, "Warning: Bus character \'[\'"
3758 " apparently used but not declared.\n");
3761 d1ptr
= strchr(pch
, '{');
3762 d2ptr
= strchr(pch
, '}');
3763 if (d1ptr
!= NULL
&& d2ptr
!= NULL
&&
3764 d1ptr
< cptr
&& d2ptr
> cptr
) {
3765 if (areawin
->buschar
!= '{') {
3766 areawin
->buschar
= '{';
3767 Fprintf(stderr
, "Warning: Bus character \'{\'"
3768 " apparently used in pin \"%s\""
3769 " but not declared.\n", pch
);
3772 d1ptr
= strchr(pch
, '<');
3773 d2ptr
= strchr(pch
, '>');
3774 if (d1ptr
!= NULL
&& d2ptr
!= NULL
&&
3775 d1ptr
< cptr
&& d2ptr
> cptr
) {
3776 if (areawin
->buschar
!= '<') {
3777 areawin
->buschar
= '<';
3778 Fprintf(stderr
, "Warning: Bus character \'<\'"
3779 " apparently used in pin \"%s\""
3780 " but not declared.\n", pch
);
3783 d1ptr
= strchr(pch
, '(');
3784 d2ptr
= strchr(pch
, ')');
3785 if (d1ptr
!= NULL
&& d2ptr
!= NULL
&&
3786 d1ptr
< cptr
&& d2ptr
> cptr
) {
3787 if (areawin
->buschar
!= '(') {
3788 areawin
->buschar
= '(';
3789 Fprintf(stderr
, "Warning: Bus character \'(\'"
3790 " apparently used in pin \"%s\""
3791 " but not declared.\n", pch
);
3796 Fprintf(stderr
, "Warning: Unattached pin \"%s\" in "
3798 localdata
->symschem
->name
);
3805 return False
; /* end of page */
3808 /* make a color change, adding the color if necessary */
3810 else if (!strcmp(keyword
, "scb")) {
3811 float red
, green
, blue
;
3812 if (sscanf(buffer
, "%f %f %f", &red
, &green
, &blue
) == 3) {
3813 curcolor
= rgb_alloccolor((int)(red
* 65535), (int)(green
* 65535),
3814 (int)(blue
* 65535));
3821 parse_ps_string(buffer
, tmpkey
, 29, FALSE
, TRUE
);
3822 ops
= match_param(localdata
, tmpkey
);
3824 /* Recast expression parameter, if necessary */
3825 if (ops
->which
== P_EXPRESSION
) ops
->which
= P_COLOR
;
3826 if (ops
->which
== P_COLOR
) {
3827 colorkey
= ops
->key
;
3828 switch (ops
->type
) {
3830 curcolor
= ops
->parameter
.ivalue
;
3833 curcolor
= DEFAULTCOLOR
; /* placeholder */
3841 /* end the color change, returning to default */
3843 else if (!strcmp(keyword
, "sce")) {
3848 /* begin a path constructor */
3850 else if (!strcmp(keyword
, "beginpath")) {
3853 NEW_PATH(newpath
, localdata
);
3854 (*newpath
)->plist
= (genericptr
*)malloc(sizeof(genericptr
));
3855 (*newpath
)->parts
= 0;
3856 (*newpath
)->color
= curcolor
;
3857 (*newpath
)->passed
= NULL
;
3859 for (--keyptr
; *keyptr
== ' '; keyptr
--);
3860 for (; *keyptr
!= ' '; keyptr
--);
3862 /* check for "addtox" and "addtoy" parameter specification */
3863 while (!strncmp(keyptr
+ 1, "addto", 5)) {
3864 saveptr
= keyptr
+ 1;
3866 for (--keyptr
; *keyptr
== ' '; keyptr
--);
3867 for (; *keyptr
!= ' '; keyptr
--);
3869 /* Get parameter and its value */
3870 if (*(saveptr
+ 5) == 'x')
3871 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newpath
,
3872 -1, offx
, P_POSITION_X
);
3874 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newpath
,
3875 -1, offy
, P_POSITION_Y
);
3877 for (--keyptr
; *keyptr
== ' '; keyptr
--);
3878 for (; *keyptr
!= ' '; keyptr
--);
3881 lineptr
= varpathscan(localdata
, buffer
, &startpoint
.x
,
3882 (genericptr
*)NULL
, *newpath
, 0, offx
+ px
, P_POSITION_X
,
3884 lineptr
= varpathscan(localdata
, lineptr
, &startpoint
.y
,
3885 (genericptr
*)NULL
, *newpath
, 0, offy
+ py
, P_POSITION_Y
,
3888 std_eparam((genericptr
)(*newpath
), colorkey
);
3891 /* end the path constructor */
3893 else if (!strcmp(keyword
, "endpath")) {
3895 lineptr
= varscan(localdata
, buffer
, &(*newpath
)->style
,
3896 (genericptr
)*newpath
, P_STYLE
);
3897 lineptr
= varfscan(localdata
, lineptr
, &(*newpath
)->width
,
3898 (genericptr
)*newpath
, P_LINEWIDTH
);
3900 if ((*newpath
)->parts
<= 0) { /* in case of an empty path */
3901 free((*newpath
)->plist
);
3908 /* read path parts */
3910 else if (!strcmp(keyword
, "polyc")) {
3912 pointlist newpoints
;
3917 NEW_POLY(newpoly
, (*newpath
));
3919 for (--keyptr
; *keyptr
== ' '; keyptr
--);
3920 for (; *keyptr
!= ' '; keyptr
--);
3922 /* check for "addtox" and "addtoy" parameter specification */
3923 while (!strncmp(keyptr
+ 1, "addto", 5)) {
3924 saveptr
= keyptr
+ 1;
3926 for (--keyptr
; *keyptr
== ' '; keyptr
--);
3927 for (; *keyptr
!= ' '; keyptr
--);
3929 /* Get parameter and its value */
3930 if (*(saveptr
+ 5) == 'x')
3931 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newpoly
,
3932 -1, offx
, P_POSITION_X
);
3934 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newpoly
,
3935 -1, offy
, P_POSITION_Y
);
3937 for (--keyptr
; *keyptr
== ' '; keyptr
--);
3938 for (; *keyptr
!= ' '; keyptr
--);
3941 sscanf(keyptr
, "%hd", &tmpnum
);
3942 (*newpoly
)->number
= tmpnum
+ 1;
3943 (*newpoly
)->width
= 1.0;
3944 (*newpoly
)->style
= UNCLOSED
;
3945 (*newpoly
)->color
= curcolor
;
3946 (*newpoly
)->passed
= NULL
;
3947 (*newpoly
)->cycle
= NULL
;
3949 (*newpoly
)->points
= (pointlist
) malloc((*newpoly
)->number
*
3952 /* If the last point on the last path part was parameterized, then */
3953 /* the first point of the spline must be, too. */
3955 if (epptrx
!= NULL
) {
3956 eparamptr newepp
= copyeparam(epptrx
, (genericptr
)(*newpath
));
3957 newepp
->next
= (*newpath
)->passed
;
3958 (*newpath
)->passed
= newepp
;
3959 newepp
->pdata
.pathpt
[1] = 0;
3960 newepp
->pdata
.pathpt
[0] = (*newpath
)->parts
- 1;
3962 if (epptry
!= NULL
) {
3963 eparamptr newepp
= copyeparam(epptry
, (genericptr
)(*newpath
));
3964 newepp
->next
= (*newpath
)->passed
;
3965 (*newpath
)->passed
= newepp
;
3966 newepp
->pdata
.pathpt
[1] = 0;
3967 newepp
->pdata
.pathpt
[0] = (*newpath
)->parts
- 1;
3972 newpoints
= (*newpoly
)->points
+ (*newpoly
)->number
- 1;
3973 lineptr
= varpathscan(localdata
, lineptr
, &newpoints
->x
,
3974 (genericptr
*)newpoly
, *newpath
, newpoints
- (*newpoly
)->points
,
3975 offx
+ px
, P_POSITION_X
, &epptrx
);
3976 lineptr
= varpathscan(localdata
, lineptr
, &newpoints
->y
,
3977 (genericptr
*)newpoly
, *newpath
, newpoints
- (*newpoly
)->points
,
3978 offy
+ py
, P_POSITION_Y
, &epptry
);
3980 for (--newpoints
; newpoints
> (*newpoly
)->points
; newpoints
--) {
3982 lineptr
= varpathscan(localdata
, lineptr
, &newpoints
->x
,
3983 (genericptr
*)newpoly
, *newpath
, newpoints
- (*newpoly
)->points
,
3984 offx
+ px
, P_POSITION_X
, NULL
);
3985 lineptr
= varpathscan(localdata
, lineptr
, &newpoints
->y
,
3986 (genericptr
*)newpoly
, *newpath
, newpoints
- (*newpoly
)->points
,
3987 offy
+ py
, P_POSITION_Y
, NULL
);
3989 newpoints
->x
= startpoint
.x
;
3990 newpoints
->y
= startpoint
.y
;
3991 startpoint
.x
= (newpoints
+ (*newpoly
)->number
- 1)->x
;
3992 startpoint
.y
= (newpoints
+ (*newpoly
)->number
- 1)->y
;
3995 else if (!strcmp(keyword
, "arc") || !strcmp(keyword
, "arcn")) {
3998 NEW_ARC(newarc
, (*newpath
));
3999 (*newarc
)->width
= 1.0;
4000 (*newarc
)->style
= UNCLOSED
;
4001 (*newarc
)->color
= curcolor
;
4002 (*newarc
)->passed
= NULL
;
4003 (*newarc
)->cycle
= NULL
;
4005 lineptr
= varpscan(localdata
, buffer
, &(*newarc
)->position
.x
,
4006 (genericptr
)*newarc
, 0, offx
, P_POSITION_X
);
4007 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.y
,
4008 (genericptr
)*newarc
, 0, offy
, P_POSITION_Y
);
4009 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->radius
,
4010 (genericptr
)*newarc
, P_RADIUS
);
4011 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle1
,
4012 (genericptr
)*newarc
, P_ANGLE1
);
4013 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle2
,
4014 (genericptr
)*newarc
, P_ANGLE2
);
4016 (*newarc
)->yaxis
= (*newarc
)->radius
;
4017 if (!strcmp(keyword
, "arcn")) {
4018 float tmpang
= (*newarc
)->angle1
;
4019 (*newarc
)->radius
= -((*newarc
)->radius
);
4020 (*newarc
)->angle1
= (*newarc
)->angle2
;
4021 (*newarc
)->angle2
= tmpang
;
4025 temppoint
.x
= startpoint
.x
;
4026 temppoint
.y
= startpoint
.y
;
4027 startpoint
.x
= (short)(*newarc
)->points
[(*newarc
)->number
- 1].x
;
4028 startpoint
.y
= (short)(*newarc
)->points
[(*newarc
)->number
- 1].y
;
4029 decomposearc(*newpath
, &temppoint
);
4032 else if (!strcmp(keyword
, "pellip") || !strcmp(keyword
, "nellip")) {
4035 NEW_ARC(newarc
, (*newpath
));
4036 (*newarc
)->width
= 1.0;
4037 (*newarc
)->style
= UNCLOSED
;
4038 (*newarc
)->color
= curcolor
;
4039 (*newarc
)->passed
= NULL
;
4040 (*newarc
)->cycle
= NULL
;
4042 lineptr
= varpscan(localdata
, buffer
, &(*newarc
)->position
.x
,
4043 (genericptr
)*newarc
, 0, offx
, P_POSITION_X
);
4044 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.y
,
4045 (genericptr
)*newarc
, 0, offy
, P_POSITION_Y
);
4046 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->radius
,
4047 (genericptr
)*newarc
, P_RADIUS
);
4048 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->yaxis
,
4049 (genericptr
)*newarc
, P_MINOR_AXIS
);
4050 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle1
,
4051 (genericptr
)*newarc
, P_ANGLE1
);
4052 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle2
,
4053 (genericptr
)*newarc
, P_ANGLE2
);
4055 if (!strcmp(keyword
, "nellip")) {
4056 float tmpang
= (*newarc
)->angle1
;
4057 (*newarc
)->radius
= -((*newarc
)->radius
);
4058 (*newarc
)->angle1
= (*newarc
)->angle2
;
4059 (*newarc
)->angle2
= tmpang
;
4063 temppoint
.x
= startpoint
.x
;
4064 temppoint
.y
= startpoint
.y
;
4065 startpoint
.x
= (short)(*newarc
)->points
[(*newarc
)->number
- 1].x
;
4066 startpoint
.y
= (short)(*newarc
)->points
[(*newarc
)->number
- 1].y
;
4067 decomposearc(*newpath
, &temppoint
);
4070 else if (!strcmp(keyword
, "curveto")) {
4071 splineptr
*newspline
;
4074 NEW_SPLINE(newspline
, (*newpath
));
4075 (*newspline
)->passed
= NULL
;
4076 (*newspline
)->cycle
= NULL
;
4077 (*newspline
)->width
= 1.0;
4078 (*newspline
)->style
= UNCLOSED
;
4079 (*newspline
)->color
= curcolor
;
4081 /* If the last point on the last path part was parameterized, then */
4082 /* the first point of the spline must be, too. */
4084 if (epptrx
!= NULL
) {
4085 eparamptr newepp
= copyeparam(epptrx
, (genericptr
)(*newpath
));
4086 newepp
->next
= (*newpath
)->passed
;
4087 (*newpath
)->passed
= newepp
;
4088 newepp
->pdata
.pathpt
[1] = 0;
4089 newepp
->pdata
.pathpt
[0] = (*newpath
)->parts
- 1;
4091 if (epptry
!= NULL
) {
4092 eparamptr newepp
= copyeparam(epptry
, (genericptr
)(*newpath
));
4093 newepp
->next
= (*newpath
)->passed
;
4094 (*newpath
)->passed
= newepp
;
4095 newepp
->pdata
.pathpt
[1] = 0;
4096 newepp
->pdata
.pathpt
[0] = (*newpath
)->parts
- 1;
4099 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4100 for (; *keyptr
!= ' '; keyptr
--);
4102 /* check for "addtox" and "addtoy" parameter specification */
4103 while (!strncmp(keyptr
+ 1, "addto", 5)) {
4104 saveptr
= keyptr
+ 1;
4106 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4107 for (; *keyptr
!= ' '; keyptr
--);
4109 /* Get parameter and its value */
4110 if (*(saveptr
+ 5) == 'x')
4111 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newspline
,
4112 -1, offx
, P_POSITION_X
);
4114 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newspline
,
4115 -1, offy
, P_POSITION_Y
);
4117 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4118 for (; *keyptr
!= ' '; keyptr
--);
4122 lineptr
= varpathscan(localdata
, buffer
, &(*newspline
)->ctrl
[1].x
,
4123 (genericptr
*)newspline
, *newpath
, 1, offx
+ px
, P_POSITION_X
,
4125 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[1].y
,
4126 (genericptr
*)newspline
, *newpath
, 1, offy
+ py
, P_POSITION_Y
,
4128 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[2].x
,
4129 (genericptr
*)newspline
, *newpath
, 2, offx
+ px
, P_POSITION_X
,
4131 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[2].y
,
4132 (genericptr
*)newspline
, *newpath
, 2, offy
+ py
, P_POSITION_Y
,
4134 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[3].x
,
4135 (genericptr
*)newspline
, *newpath
, 3, offx
+ px
, P_POSITION_X
,
4137 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[3].y
,
4138 (genericptr
*)newspline
, *newpath
, 3, offy
+ py
, P_POSITION_Y
,
4141 (*newspline
)->ctrl
[0].x
= startpoint
.x
;
4142 (*newspline
)->ctrl
[0].y
= startpoint
.y
;
4144 calcspline(*newspline
);
4145 startpoint
.x
= (*newspline
)->ctrl
[3].x
;
4146 startpoint
.y
= (*newspline
)->ctrl
[3].y
;
4151 else if (!strcmp(keyword
, "xcarc")) {
4154 NEW_ARC(newarc
, localdata
);
4155 (*newarc
)->color
= curcolor
;
4156 (*newarc
)->passed
= NULL
;
4157 (*newarc
)->cycle
= NULL
;
4159 /* backward compatibility */
4160 if (compare_version(version
, "1.5") < 0) {
4161 sscanf(buffer
, "%hd %hd %hd %f %f %f %hd", &(*newarc
)->position
.x
,
4162 &(*newarc
)->position
.y
, &(*newarc
)->radius
, &(*newarc
)->angle1
,
4163 &(*newarc
)->angle2
, &(*newarc
)->width
, &(*newarc
)->style
);
4164 (*newarc
)->position
.x
-= offx
;
4165 (*newarc
)->position
.y
-= offy
;
4168 lineptr
= varscan(localdata
, buffer
, &(*newarc
)->style
,
4169 (genericptr
)*newarc
, P_STYLE
);
4170 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->width
,
4171 (genericptr
)*newarc
, P_LINEWIDTH
);
4172 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.x
,
4173 (genericptr
)*newarc
, 0, offx
, P_POSITION_X
);
4174 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.y
,
4175 (genericptr
)*newarc
, 0, offy
, P_POSITION_Y
);
4176 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->radius
,
4177 (genericptr
)*newarc
, P_RADIUS
);
4178 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle1
,
4179 (genericptr
)*newarc
, P_ANGLE1
);
4180 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle2
,
4181 (genericptr
)*newarc
, P_ANGLE2
);
4184 (*newarc
)->yaxis
= (*newarc
)->radius
;
4186 std_eparam((genericptr
)(*newarc
), colorkey
);
4191 else if (!strcmp(keyword
, "ellipse")) {
4194 NEW_ARC(newarc
, localdata
);
4196 (*newarc
)->color
= curcolor
;
4197 (*newarc
)->passed
= NULL
;
4198 (*newarc
)->cycle
= NULL
;
4200 lineptr
= varscan(localdata
, buffer
, &(*newarc
)->style
,
4201 (genericptr
)*newarc
, P_STYLE
);
4202 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->width
,
4203 (genericptr
)*newarc
, P_LINEWIDTH
);
4204 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.x
,
4205 (genericptr
)*newarc
, 0, offx
, P_POSITION_X
);
4206 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.y
,
4207 (genericptr
)*newarc
, 0, offy
, P_POSITION_Y
);
4208 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->radius
,
4209 (genericptr
)*newarc
, P_RADIUS
);
4210 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->yaxis
,
4211 (genericptr
)*newarc
, P_MINOR_AXIS
);
4212 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle1
,
4213 (genericptr
)*newarc
, P_ANGLE1
);
4214 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle2
,
4215 (genericptr
)*newarc
, P_ANGLE2
);
4218 std_eparam((genericptr
)(*newarc
), colorkey
);
4222 /* (and wires---backward compatibility for v1.5 and earlier) */
4224 else if (!strcmp(keyword
, "polygon") || !strcmp(keyword
, "wire")) {
4226 pointlist newpoints
;
4229 NEW_POLY(newpoly
, localdata
);
4232 (*newpoly
)->passed
= NULL
;
4233 (*newpoly
)->cycle
= NULL
;
4235 if (!strcmp(keyword
, "wire")) {
4236 (*newpoly
)->number
= 2;
4237 (*newpoly
)->width
= 1.0;
4238 (*newpoly
)->style
= UNCLOSED
;
4241 /* backward compatibility */
4242 if (compare_version(version
, "1.5") < 0) {
4243 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4244 for (; *keyptr
!= ' '; keyptr
--);
4245 sscanf(keyptr
, "%hd", &(*newpoly
)->style
);
4246 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4247 for (; *keyptr
!= ' '; keyptr
--);
4248 sscanf(keyptr
, "%f", &(*newpoly
)->width
);
4250 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4251 for (; *keyptr
!= ' '; keyptr
--);
4252 /* check for "addtox" and "addtoy" parameter specification */
4253 while (!strncmp(keyptr
+ 1, "addto", 5)) {
4254 saveptr
= keyptr
+ 1;
4256 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4257 for (; *keyptr
!= ' '; keyptr
--);
4259 /* Get parameter and its value */
4260 if (*(saveptr
+ 5) == 'x')
4261 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newpoly
,
4262 -1, offx
, P_POSITION_X
);
4264 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newpoly
,
4265 -1, offy
, P_POSITION_Y
);
4267 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4268 for (; *keyptr
!= ' '; keyptr
--);
4270 sscanf(keyptr
, "%hd", &(*newpoly
)->number
);
4272 if (compare_version(version
, "1.5") >= 0) {
4273 lineptr
= varscan(localdata
, lineptr
, &(*newpoly
)->style
,
4274 (genericptr
)*newpoly
, P_STYLE
);
4275 lineptr
= varfscan(localdata
, lineptr
, &(*newpoly
)->width
,
4276 (genericptr
)*newpoly
, P_LINEWIDTH
);
4280 if ((*newpoly
)->style
& BBOX
)
4281 (*newpoly
)->color
= BBOXCOLOR
;
4283 (*newpoly
)->color
= curcolor
;
4284 (*newpoly
)->points
= (pointlist
) malloc((*newpoly
)->number
*
4287 for (newpoints
= (*newpoly
)->points
; newpoints
< (*newpoly
)->points
4288 + (*newpoly
)->number
; newpoints
++) {
4289 lineptr
= varpscan(localdata
, lineptr
, &newpoints
->x
,
4290 (genericptr
)*newpoly
, newpoints
- (*newpoly
)->points
,
4291 offx
+ px
, P_POSITION_X
);
4292 lineptr
= varpscan(localdata
, lineptr
, &newpoints
->y
,
4293 (genericptr
)*newpoly
, newpoints
- (*newpoly
)->points
,
4294 offy
+ py
, P_POSITION_Y
);
4296 std_eparam((genericptr
)(*newpoly
), colorkey
);
4299 /* read spline curves */
4301 else if (!strcmp(keyword
, "spline")) {
4302 splineptr
*newspline
;
4305 NEW_SPLINE(newspline
, localdata
);
4306 (*newspline
)->color
= curcolor
;
4307 (*newspline
)->passed
= NULL
;
4308 (*newspline
)->cycle
= NULL
;
4310 /* backward compatibility */
4311 if (compare_version(version
, "1.5") < 0) {
4312 sscanf(buffer
, "%f %hd %hd %hd %hd %hd %hd %hd %hd %hd",
4313 &(*newspline
)->width
, &(*newspline
)->ctrl
[1].x
,
4314 &(*newspline
)->ctrl
[1].y
, &(*newspline
)->ctrl
[2].x
,
4315 &(*newspline
)->ctrl
[2].y
, &(*newspline
)->ctrl
[3].x
,
4316 &(*newspline
)->ctrl
[3].y
, &(*newspline
)->ctrl
[0].x
,
4317 &(*newspline
)->ctrl
[0].y
, &(*newspline
)->style
);
4318 (*newspline
)->ctrl
[1].x
-= offx
; (*newspline
)->ctrl
[2].x
-= offx
;
4319 (*newspline
)->ctrl
[0].x
-= offx
;
4320 (*newspline
)->ctrl
[3].x
-= offx
;
4321 (*newspline
)->ctrl
[1].y
-= offy
; (*newspline
)->ctrl
[2].y
-= offy
;
4322 (*newspline
)->ctrl
[3].y
-= offy
;
4323 (*newspline
)->ctrl
[0].y
-= offy
;
4327 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4328 for (; *keyptr
!= ' '; keyptr
--);
4329 /* check for "addtox" and "addtoy" parameter specification */
4330 while (!strncmp(keyptr
+ 1, "addto", 5)) {
4331 saveptr
= keyptr
+ 1;
4333 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4334 for (; *keyptr
!= ' '; keyptr
--);
4336 /* Get parameter and its value */
4337 if (*(saveptr
+ 5) == 'x')
4338 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newspline
,
4339 -1, offx
, P_POSITION_X
);
4341 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newspline
,
4342 -1, offy
, P_POSITION_Y
);
4344 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4345 for (; *keyptr
!= ' '; keyptr
--);
4348 lineptr
= varscan(localdata
, buffer
, &(*newspline
)->style
,
4349 (genericptr
)*newspline
, P_STYLE
);
4350 lineptr
= varfscan(localdata
, lineptr
, &(*newspline
)->width
,
4351 (genericptr
)*newspline
, P_LINEWIDTH
);
4352 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[1].x
,
4353 (genericptr
)*newspline
, 1, offx
+ px
, P_POSITION_X
);
4354 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[1].y
,
4355 (genericptr
)*newspline
, 1, offy
+ py
, P_POSITION_Y
);
4356 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[2].x
,
4357 (genericptr
)*newspline
, 2, offx
+ px
, P_POSITION_X
);
4358 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[2].y
,
4359 (genericptr
)*newspline
, 2, offy
+ py
, P_POSITION_Y
);
4360 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[3].x
,
4361 (genericptr
)*newspline
, 3, offx
+ px
, P_POSITION_X
);
4362 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[3].y
,
4363 (genericptr
)*newspline
, 3, offy
+ py
, P_POSITION_Y
);
4364 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[0].x
,
4365 (genericptr
)*newspline
, 0, offx
+ px
, P_POSITION_X
);
4366 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[0].y
,
4367 (genericptr
)*newspline
, 0, offy
+ py
, P_POSITION_Y
);
4369 /* check for "addtox" and "addtoy" parameter specification */
4372 calcspline(*newspline
);
4373 std_eparam((genericptr
)(*newspline
), colorkey
);
4376 /* read graphics image instances */
4378 else if (!strcmp(keyword
, "graphic")) {
4382 lineptr
= buffer
+ 1;
4383 for (i
= 0; i
< xobjs
.images
; i
++) {
4384 img
= xobjs
.imagelist
+ i
;
4385 if (!strncmp(img
->filename
, lineptr
, strlen(img
->filename
))) {
4386 NEW_GRAPHIC(newgp
, localdata
);
4387 (*newgp
)->color
= curcolor
;
4388 (*newgp
)->passed
= NULL
;
4390 (*newgp
)->clipmask
= (Pixmap
)NULL
;
4391 (*newgp
)->target
= NULL
;
4392 (*newgp
)->valid
= False
;
4393 #endif /* HAVE_CAIRO */
4394 (*newgp
)->source
= img
->image
;
4396 lineptr
+= strlen(img
->filename
) + 1;
4400 if (i
== xobjs
.images
) {
4401 /* Error: Line points to a non-existant image (no data) */
4402 /* See if we can load the image name as a filename, and */
4403 /* if that fails, then we must throw an error and ignore */
4404 /* the image element. */
4407 char *sptr
= strchr(lineptr
, ' ');
4413 locgp
= new_graphic(NULL
, lineptr
, 0, 0);
4415 if (locgp
== NULL
) {
4416 Fprintf(stderr
, "Error: No graphic data for \"%s\".\n",
4426 if ((newgp
!= NULL
) && (*newgp
!= NULL
)) {
4427 lineptr
= varfscan(localdata
, lineptr
, &(*newgp
)->scale
,
4428 (genericptr
)*newgp
, P_SCALE
);
4429 lineptr
= varfscan(localdata
, lineptr
, &(*newgp
)->rotation
,
4430 (genericptr
)*newgp
, P_ROTATION
);
4431 lineptr
= varpscan(localdata
, lineptr
, &(*newgp
)->position
.x
,
4432 (genericptr
)*newgp
, 0, offx
, P_POSITION_X
);
4433 lineptr
= varpscan(localdata
, lineptr
, &(*newgp
)->position
.y
,
4434 (genericptr
)*newgp
, 0, offy
, P_POSITION_Y
);
4435 std_eparam((genericptr
)(*newgp
), colorkey
);
4441 else if (!strcmp(keyword
, "fontset")) { /* old style */
4442 char tmpstring
[100];
4444 sscanf(buffer
, "%f %*c%99s", &tmpscale
, tmpstring
);
4445 for (i
= 0; i
< fontcount
; i
++)
4446 if (!strcmp(tmpstring
, fonts
[i
].psname
)) {
4450 if (i
== fontcount
) i
= 0; /* Why bother with anything fancy? */
4453 else if (!strcmp(keyword
, "label") || !strcmp(keyword
, "pinlabel")
4454 || !strcmp(keyword
, "pinglobal") || !strcmp(keyword
, "infolabel")) {
4457 stringpart
*firstscale
, *firstfont
;
4459 NEW_LABEL(newlabel
, localdata
);
4460 (*newlabel
)->color
= curcolor
;
4461 (*newlabel
)->string
= NULL
;
4462 (*newlabel
)->passed
= NULL
;
4463 (*newlabel
)->cycle
= NULL
;
4465 /* scan backwards to get the number of substrings */
4466 lineptr
= keyptr
- 1;
4467 for (i
= 0; i
< ((compare_version(version
, "2.3") < 0) ? 5 : 6); i
++) {
4468 for (; *lineptr
== ' '; lineptr
--);
4469 for (; *lineptr
!= ' '; lineptr
--);
4471 if ((strchr(lineptr
, '.') != NULL
) && (compare_version(version
, "2.3") < 0)) {
4472 Fprintf(stderr
, "Error: File version claims to be %s,"
4473 " but has version %s labels\n", version
, PROG_VERSION
);
4474 Fprintf(stderr
, "Attempting to resolve problem by updating version.\n");
4475 strcpy(version
, PROG_VERSION
);
4476 for (; *lineptr
== ' '; lineptr
--);
4477 for (; *lineptr
!= ' '; lineptr
--);
4479 /* no. segments is ignored---may be a derived quantity, anyway */
4480 if (compare_version(version
, "2.3") < 0) {
4481 sscanf(lineptr
, "%*s %hd %hf %hd %hd", &(*newlabel
)->anchor
,
4482 &(*newlabel
)->rotation
, &(*newlabel
)->position
.x
,
4483 &(*newlabel
)->position
.y
);
4484 (*newlabel
)->position
.x
-= offx
; (*newlabel
)->position
.y
-= offy
;
4489 lineptr
= advancetoken(lineptr
); /* skip string token */
4490 lineptr
= varscan(localdata
, lineptr
, &(*newlabel
)->anchor
,
4491 (genericptr
)*newlabel
, P_ANCHOR
);
4492 lineptr
= varfscan(localdata
, lineptr
, &(*newlabel
)->rotation
,
4493 (genericptr
)*newlabel
, P_ROTATION
);
4494 lineptr
= varfscan(localdata
, lineptr
, &(*newlabel
)->scale
,
4495 (genericptr
)*newlabel
, P_SCALE
);
4496 lineptr
= varpscan(localdata
, lineptr
, &(*newlabel
)->position
.x
,
4497 (genericptr
)*newlabel
, 0, offx
, P_POSITION_X
);
4498 lineptr
= varpscan(localdata
, lineptr
, &(*newlabel
)->position
.y
,
4499 (genericptr
)*newlabel
, 0, offy
, P_POSITION_Y
);
4501 if (compare_version(version
, "2.4") < 0)
4502 (*newlabel
)->rotation
= -(*newlabel
)->rotation
;
4503 while ((*newlabel
)->rotation
< 0.0) (*newlabel
)->rotation
+= 360.0;
4505 (*newlabel
)->pin
= False
;
4506 if (strcmp(keyword
, "label")) { /* all the schematic types */
4507 /* enable schematic capture if it is not already on. */
4508 if (!strcmp(keyword
, "pinlabel"))
4509 (*newlabel
)->pin
= LOCAL
;
4510 else if (!strcmp(keyword
, "pinglobal"))
4511 (*newlabel
)->pin
= GLOBAL
;
4512 else if (!strcmp(keyword
, "infolabel")) {
4513 /* Do not turn top-level pages into symbols! */
4514 /* Info labels on schematics are treated differently. */
4515 if (localdata
!= topobject
)
4516 localdata
->schemtype
= FUNDAMENTAL
;
4517 (*newlabel
)->pin
= INFO
;
4518 if (curcolor
== DEFAULTCOLOR
)
4519 (*newlabel
)->color
= INFOLABELCOLOR
;
4523 lineptr
= buffer
; /* back to beginning of string */
4524 if (!strncmp(lineptr
, "mark", 4)) lineptr
+= 4;
4526 readlabel(localdata
, lineptr
, &(*newlabel
)->string
);
4527 CheckMarginStop(*newlabel
, areawin
->topinstance
, FALSE
);
4529 if (compare_version(version
, "2.3") < 0) {
4530 /* Switch 1st scale designator to overall font scale */
4532 firstscale
= (*newlabel
)->string
->nextpart
;
4533 if (firstscale
->type
!= FONT_SCALE
) {
4534 if (tmpscale
!= 0.0)
4535 (*newlabel
)->scale
= 0.0;
4537 (*newlabel
)->scale
= 1.0;
4540 (*newlabel
)->scale
= firstscale
->data
.scale
;
4541 deletestring(firstscale
, &((*newlabel
)->string
),
4542 areawin
->topinstance
);
4546 firstfont
= (*newlabel
)->string
;
4547 if ((firstfont
== NULL
) || (firstfont
->type
!= FONT_NAME
)) {
4548 if (tmpfont
== -1) {
4549 Fprintf(stderr
, "Error: Label with no font designator?\n");
4552 firstfont
= makesegment(&((*newlabel
)->string
), (*newlabel
)->string
);
4553 firstfont
->type
= FONT_NAME
;
4554 firstfont
->data
.font
= tmpfont
;
4556 cleanuplabel(&(*newlabel
)->string
);
4558 std_eparam((genericptr
)(*newlabel
), colorkey
);
4561 /* read symbol-to-schematic connection */
4563 else if (!strcmp(keyword
, "is_schematic")) {
4565 for (lineptr
= buffer
; *lineptr
== ' '; lineptr
++);
4566 parse_ps_string(++lineptr
, tempstr
, 49, FALSE
, FALSE
);
4567 checksym(localdata
, tempstr
);
4570 /* read bounding box (font files only) */
4572 else if (!strcmp(keyword
, "bbox")) {
4573 for (lineptr
= buffer
; *lineptr
== ' '; lineptr
++);
4574 if (*lineptr
!= '%') {
4575 Wprintf("Illegal bbox.");
4580 sscanf(++lineptr
, "%hd %hd %hd %hd",
4581 &localdata
->bbox
.lowerleft
.x
, &localdata
->bbox
.lowerleft
.y
,
4582 &localdata
->bbox
.width
, &localdata
->bbox
.height
);
4584 // If this is *not* a FONTLIB, then the font character symbols
4585 // are being edited as a normal library, so copy the bounding
4586 // box into a FIXEDBBOX-type box.
4588 if (mode
!= FONTLIB
) {
4590 pointlist newpoints
;
4592 NEW_POLY(newpoly
, localdata
);
4593 (*newpoly
)->passed
= NULL
;
4594 (*newpoly
)->cycle
= NULL
;
4595 (*newpoly
)->number
= 4;
4596 (*newpoly
)->width
= 1.0;
4597 (*newpoly
)->style
= FIXEDBBOX
;
4598 (*newpoly
)->color
= FIXEDBBOXCOLOR
;
4599 (*newpoly
)->points
= (pointlist
) malloc(4 * sizeof(XPoint
));
4600 newpoints
= (*newpoly
)->points
;
4601 newpoints
->x
= localdata
->bbox
.lowerleft
.x
;
4602 newpoints
->y
= localdata
->bbox
.lowerleft
.y
;
4604 newpoints
->x
= localdata
->bbox
.lowerleft
.x
+ localdata
->bbox
.width
;
4605 newpoints
->y
= localdata
->bbox
.lowerleft
.y
;
4607 newpoints
->x
= localdata
->bbox
.lowerleft
.x
+ localdata
->bbox
.width
;
4608 newpoints
->y
= localdata
->bbox
.lowerleft
.y
+ localdata
->bbox
.height
;
4610 newpoints
->x
= localdata
->bbox
.lowerleft
.x
;
4611 newpoints
->y
= localdata
->bbox
.lowerleft
.y
+ localdata
->bbox
.height
;
4612 std_eparam((genericptr
)(*newpoly
), colorkey
);
4616 /* read "hidden" attribute */
4618 else if (!strcmp(keyword
, "hidden")) {
4619 localdata
->hidden
= True
;
4622 /* read "libinst" special instance of a library part */
4624 else if (!strcmp(keyword
, "libinst")) {
4626 /* Read backwards from keyword to find name of object instanced. */
4627 for (lineptr
= keyptr
; *lineptr
!= '/' && lineptr
> buffer
;
4629 parse_ps_string(++lineptr
, keyword
, 79, FALSE
, FALSE
);
4630 new_library_instance(mode
- LIBRARY
, keyword
, buffer
, defaulttech
);
4635 else if (!strcmp(keyword
, "{")) { /* This is an object definition */
4637 objectptr
*newobject
;
4639 for (lineptr
= buffer
; *lineptr
== ' '; lineptr
++);
4640 if (*lineptr
++ != '/') {
4641 /* This may be part of a label. . . treat as a continuation line */
4642 temp
= continueline(&buffer
);
4645 parse_ps_string(lineptr
, keyword
, 79, FALSE
, FALSE
);
4647 newobject
= new_library_object(mode
, keyword
, &redef
, defaulttech
);
4649 if (objectread(ps
, *newobject
, 0, 0, mode
, retstr
, curcolor
,
4650 defaulttech
) == True
) {
4651 strncpy(retstr
, buffer
, 150);
4657 if (library_object_unique(mode
, *newobject
, redef
))
4658 add_object_to_library(mode
, *newobject
);
4661 else if (!strcmp(keyword
, "def")) {
4662 strncpy(retstr
, buffer
, 150);
4665 return False
; /* end of object def or end of object library */
4668 else if (!strcmp(keyword
, "loadfontencoding")) {
4669 /* Deprecated, but retained for backward compatibility. */
4670 /* Load from script, .xcircuitrc, or command line instead. */
4671 for (lineptr
= buffer
; *lineptr
!= '%'; lineptr
++);
4672 sscanf (lineptr
+ 1, "%149s", _STR
);
4673 if (*(lineptr
+ 1) != '%') loadfontfile(_STR
);
4675 else if (!strcmp(keyword
, "loadlibrary")) {
4676 /* Deprecated, but retained for backward compatibility */
4677 /* Load from script, .xcircuitrc, or command line instead. */
4680 for (lineptr
= buffer
; *lineptr
!= '%'; lineptr
++);
4681 sscanf (++lineptr
, "%149s", _STR
);
4682 while (isspace(*lineptr
)) lineptr
++;
4683 while (!isspace(*++lineptr
));
4684 while (isspace(*++lineptr
));
4685 if (sscanf (lineptr
, "%d", &ilib
) > 0) {
4686 while ((ilib
- 2 + LIBRARY
) > xobjs
.numlibs
) {
4687 tlib
= createlibrary(False
);
4688 if (tlib
!= xobjs
.numlibs
- 2 + LIBRARY
) {
4693 mode
= ilib
- 1 + LIBRARY
;
4697 else if (!strcmp(keyword
, "beginparm")) { /* parameterized object */
4699 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4700 for (; isdigit(*keyptr
) && (keyptr
>= buffer
); keyptr
--);
4701 sscanf(keyptr
, "%hd", &tmpnum
);
4703 while (isspace(*lineptr
)) lineptr
++;
4705 if (tmpnum
< 256) { /* read parameter defaults in order */
4706 stringpart
*newpart
;
4707 /* oparamptr newops; (jdk) */
4709 for (i
= 0; i
< tmpnum
; i
++) {
4712 newops
= (oparamptr
)malloc(sizeof(oparam
));
4713 newops
->next
= localdata
->params
;
4714 localdata
->params
= newops
;
4715 newops
->key
= (char *)malloc(6);
4716 sprintf(newops
->key
, "v%d", i
+ 1);
4718 if (*lineptr
== '(' || *lineptr
== '{') { /* type is XC_STRING */
4719 char *linetmp
, csave
;
4721 newops
->parameter
.string
= NULL
;
4723 /* get simple substring or set of substrings and commands */
4724 linetmp
= find_delimiter(lineptr
);
4725 csave
= *(++linetmp
);
4727 if (*lineptr
== '{') lineptr
++;
4728 readlabel(localdata
, lineptr
, &(newops
->parameter
.string
));
4730 /* Add the ending part to the parameter string */
4731 newpart
= makesegment(&(newops
->parameter
.string
), NULL
);
4732 newpart
->type
= PARAM_END
;
4733 newpart
->data
.string
= (u_char
*)NULL
;
4735 newops
->type
= (u_char
)XC_STRING
;
4736 newops
->which
= P_SUBSTRING
;
4737 /* Fprintf(stdout, "Parameter %d to object %s defaults "
4738 "to string \"%s\"\n", i + 1, localdata->name,
4739 ops->parameter.string); */
4742 while (isspace(*lineptr
)) lineptr
++;
4744 else { /* type is assumed to be XC_FLOAT */
4745 newops
->type
= (u_char
)XC_FLOAT
;
4746 sscanf(lineptr
, "%g", &newops
->parameter
.fvalue
);
4747 /* Fprintf(stdout, "Parameter %s to object %s defaults to "
4748 "value %g\n", newops->key, localdata->name,
4749 newops->parameter.fvalue); */
4750 lineptr
= advancetoken(lineptr
);
4755 else if (!strcmp(keyword
, "nonetwork")) {
4756 localdata
->valid
= True
;
4757 localdata
->schemtype
= NONETWORK
;
4759 else if (!strcmp(keyword
, "trivial")) {
4760 localdata
->schemtype
= TRIVIAL
;
4762 else if (!strcmp(keyword
, "begingate")) {
4763 localdata
->params
= NULL
;
4764 /* read dictionary of parameter key:value pairs */
4765 readparams(NULL
, NULL
, localdata
, buffer
);
4768 else if (!strcmp(keyword
, "%%Trailer")) break;
4769 else if (!strcmp(keyword
, "EndLib")) break;
4770 else if (!strcmp(keyword
, "restore")); /* handled at top */
4771 else if (!strcmp(keyword
, "grestore")); /* ignore */
4772 else if (!strcmp(keyword
, "endgate")); /* also ignore */
4773 else if (!strcmp(keyword
, "xyarray")); /* ignore for now */
4775 char *tmpptr
, *libobjname
, *objnamestart
;
4776 Boolean matchtech
, found
= False
;
4778 /* First, make sure this is not a general comment line */
4779 /* Return if we have a page boundary */
4780 /* Read an image if this is an imagedata line. */
4782 for (tmpptr
= buffer
; isspace(*tmpptr
); tmpptr
++);
4783 if (*tmpptr
== '%') {
4784 if (strstr(buffer
, "%%Page:") == tmpptr
) {
4785 strncpy(retstr
, buffer
, 150);
4790 else if (strstr(buffer
, "%imagedata") == tmpptr
) {
4792 sscanf(buffer
, "%*s %d %d", &width
, &height
);
4793 readimagedata(ps
, width
, height
);
4798 parse_ps_string(keyword
, keyword
, 79, FALSE
, FALSE
);
4799 matchtech
= (strstr(keyword
, "::") == NULL
) ? FALSE
: TRUE
;
4801 /* If the file contains a reference to a bare-word device */
4802 /* without a technology prefix, then it is probably an */
4803 /* older-version file. If this is the case, then the file */
4804 /* should define an unprefixed object, which will be given */
4805 /* a null prefix (just "::" by itself). Look for that */
4808 /* (Assume that this line calls an object instance) */
4809 /* Double loop through user libraries */
4811 for (k
= 0; k
< ((mode
== FONTLIB
) ? 1 : xobjs
.numlibs
); k
++) {
4812 for (j
= 0; j
< ((mode
== FONTLIB
) ? xobjs
.fontlib
.number
:
4813 xobjs
.userlibs
[k
].number
); j
++) {
4815 libobj
= (mode
== FONTLIB
) ? xobjs
.fontlib
.library
+ j
:
4816 xobjs
.userlibs
[k
].library
+ j
;
4818 /* Objects which have a technology ("<lib>::<obj>") */
4819 /* must compare exactly. Objects which don't can */
4820 /* only match an object of the same name with a null */
4821 /* technology prefix. */
4823 libobjname
= (*libobj
)->name
;
4825 objnamestart
= strstr(libobjname
, "::");
4826 if (objnamestart
!= NULL
) libobjname
= objnamestart
+ 2;
4828 if (!objnamecmp(keyword
, libobjname
)) {
4830 /* If the name is not exactly the same (appended underscores) */
4831 /* check if the name is on the list of aliases. */
4833 if (strcmp(keyword
, libobjname
)) {
4834 Boolean is_alias
= False
;
4835 aliasptr ckalias
= aliastop
;
4838 for (; ckalias
!= NULL
; ckalias
= ckalias
->next
) {
4839 if (ckalias
->baseobj
== (*libobj
)) {
4840 sref
= ckalias
->aliases
;
4841 for (; sref
!= NULL
; sref
= sref
->next
) {
4842 if (!strcmp(keyword
, sref
->alias
)) {
4847 if (is_alias
) break;
4850 if (!is_alias
) continue;
4853 if (!matchtech
&& ((*libobj
)->name
!= objnamestart
))
4854 if (compare_version(version
, "3.7") > 0)
4855 continue; // no prefix in file must match
4856 // null prefix in library object.
4859 NEW_OBJINST(newinst
, localdata
);
4860 (*newinst
)->thisobject
= *libobj
;
4861 (*newinst
)->color
= curcolor
;
4862 (*newinst
)->params
= NULL
;
4863 (*newinst
)->passed
= NULL
;
4864 (*newinst
)->bbox
.lowerleft
.x
= (*libobj
)->bbox
.lowerleft
.x
;
4865 (*newinst
)->bbox
.lowerleft
.y
= (*libobj
)->bbox
.lowerleft
.y
;
4866 (*newinst
)->bbox
.width
= (*libobj
)->bbox
.width
;
4867 (*newinst
)->bbox
.height
= (*libobj
)->bbox
.height
;
4868 (*newinst
)->schembbox
= NULL
;
4870 lineptr
= varfscan(localdata
, buffer
, &(*newinst
)->scale
,
4871 (genericptr
)*newinst
, P_SCALE
);
4873 /* Format prior to xcircuit 3.7 did not have scale- */
4874 /* invariant linewidth. If scale is 1, though, keep it */
4875 /* invariant so as not to overuse the scale-variance */
4876 /* flag in the output file. */
4878 if ((compare_version(version
, "3.7") < 0) && ((*newinst
)->scale
!= 1.0))
4879 (*newinst
)->style
= NORMAL
;
4881 (*newinst
)->style
= LINE_INVARIANT
;
4883 lineptr
= varfscan(localdata
, lineptr
, &(*newinst
)->rotation
,
4884 (genericptr
)*newinst
, P_ROTATION
);
4885 lineptr
= varpscan(localdata
, lineptr
, &(*newinst
)->position
.x
,
4886 (genericptr
)*newinst
, 0, offx
, P_POSITION_X
);
4887 lineptr
= varpscan(localdata
, lineptr
, &(*newinst
)->position
.y
,
4888 (genericptr
)*newinst
, 0, offy
, P_POSITION_Y
);
4890 /* Look for the "not netlistable" flag */
4891 if (*lineptr
== '/') {
4892 if (!strncmp(lineptr
, "/nn", 3))
4893 (*newinst
)->style
|= INST_NONETLIST
;
4896 /* Negative rotations = flip in x in version 2.3.6 and */
4897 /* earlier. Later versions don't allow negative rotation */
4899 if (compare_version(version
, "2.4") < 0) {
4900 if ((*newinst
)->rotation
< 0.0) {
4901 (*newinst
)->scale
= -((*newinst
)->scale
);
4902 (*newinst
)->rotation
+= 1.0;
4904 (*newinst
)->rotation
= -(*newinst
)->rotation
;
4907 while ((*newinst
)->rotation
> 360.0)
4908 (*newinst
)->rotation
-= 360.0;
4909 while ((*newinst
)->rotation
< 0.0)
4910 (*newinst
)->rotation
+= 360.0;
4912 std_eparam((genericptr
)(*newinst
), colorkey
);
4914 /* Does this instance contain parameters? */
4915 readparams(localdata
, *newinst
, *libobj
, buffer
);
4917 calcbboxinst(*newinst
);
4925 if (!found
) /* will assume that we have a continuation line */
4926 temp
= continueline(&buffer
);
4930 strncpy(retstr
, buffer
, 150);
4936 /*------------------------*/
4937 /* Save a PostScript file */
4938 /*------------------------*/
4942 void setfile(char *filename
, int mode
)
4944 if ((filename
== NULL
) || (xobjs
.pagelist
[areawin
->page
]->filename
== NULL
)) {
4945 Wprintf("Error: No filename for schematic.");
4946 if (areawin
->area
&& beeper
) XBell(dpy
, 100);
4950 /* see if name has been changed in the buffer */
4952 if (strcmp(xobjs
.pagelist
[areawin
->page
]->filename
, filename
)) {
4953 Wprintf("Changing name of edit file.");
4954 free(xobjs
.pagelist
[areawin
->page
]->filename
);
4955 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(filename
);
4958 if (strstr(xobjs
.pagelist
[areawin
->page
]->filename
, "Page ") != NULL
) {
4959 Wprintf("Warning: Enter a new name.");
4960 if (areawin
->area
&& beeper
) XBell(dpy
, 100);
4964 if (areawin
->area
&& beeper
) XBell(dpy
, 100);
4968 #else /* !TCL_WRAPPER */
4970 void setfile(xcWidget button
, xcWidget fnamewidget
, caddr_t clientdata
)
4972 /* see if name has been changed in the buffer */
4974 sprintf(_STR2
, "%.249s", (char *)XwTextCopyBuffer(fnamewidget
));
4975 if (xobjs
.pagelist
[areawin
->page
]->filename
== NULL
) {
4976 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(_STR2
);
4978 else if (strcmp(xobjs
.pagelist
[areawin
->page
]->filename
, _STR2
)) {
4979 Wprintf("Changing name of edit file.");
4980 free(xobjs
.pagelist
[areawin
->page
]->filename
);
4981 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(_STR2
);
4983 if (strstr(xobjs
.pagelist
[areawin
->page
]->filename
, "Page ") != NULL
) {
4984 Wprintf("Warning: Enter a new name.");
4985 if (areawin
->area
&& beeper
) XBell(dpy
, 100);
4992 savefile(CURRENT_PAGE
);
4994 /* Change "close" button to read "done" */
4996 di
= xcParent(button
);
4997 db
= XtNameToWidget(di
, "Close");
4998 XtSetArg(wargs
[0], XtNlabel
, " Done ");
4999 XtSetValues(db
, wargs
, 1);
5000 if (areawin
->area
&& beeper
) XBell(dpy
, 100);
5004 #endif /* TCL_WRAPPER */
5006 /*--------------------------------------------------------------*/
5007 /* Update number of changes for an object and initiate a temp */
5008 /* file save if total number of unsaved changes exceeds 20. */
5009 /*--------------------------------------------------------------*/
5011 void incr_changes(objectptr thisobj
)
5013 /* It is assumed that empty pages are meant to be that way */
5014 /* and are not to be saved, so changes are marked as zero. */
5016 if (thisobj
->parts
== 0) {
5017 thisobj
->changes
= 0;
5021 /* Remove any pending timeout */
5023 if (xobjs
.timeout_id
!= (xcIntervalId
)NULL
) {
5024 xcRemoveTimeOut(xobjs
.timeout_id
);
5025 xobjs
.timeout_id
= (xcIntervalId
)NULL
;
5030 /* When in "suspend" mode, we assume that we are reading commands from
5031 * a script, and therefore we should not continuously increment changes
5032 * and keep saving the backup file.
5035 if (xobjs
.suspend
< 0)
5036 xobjs
.new_changes
++;
5038 if (xobjs
.new_changes
> MAXCHANGES
) {
5042 savetemp(NULL
, NULL
);
5046 /* Generate a new timeout */
5049 xobjs
.timeout_id
= xcAddTimeOut(app
, 60000 * xobjs
.save_interval
,
5053 /*--------------------------------------------------------------*/
5055 /*--------------------------------------------------------------*/
5059 void savetemp(ClientData clientdata
)
5064 void savetemp(XtPointer clientdata
, xcIntervalId
*id
)
5068 /* If areawin->area is NULL then xcircuit is running in */
5069 /* batch mode and should not make backups. */
5070 if (areawin
->area
== NULL
) return;
5072 /* Remove the timeout ID. If this routine is called from */
5073 /* incr_changes() instead of from the timeout interrupt */
5074 /* service routine, then this value will already be NULL. */
5076 xobjs
.timeout_id
= (xcIntervalId
)NULL
;
5078 /* First see if there are any unsaved changes in the file. */
5079 /* If not, then just reset the counter and continue. */
5081 if (xobjs
.new_changes
> 0) {
5082 if (xobjs
.tempfile
== NULL
)
5085 char *template = (char *)malloc(20 + strlen(xobjs
.tempdir
));
5086 int pid
= (int)getpid();
5088 sprintf(template, "%s/XC%d.XXXXXX", xobjs
.tempdir
, pid
);
5091 fd
= mktemp(template);
5093 fd
= mkstemp(template);
5096 Fprintf(stderr
, "Error generating file for savetemp\n");
5100 xobjs
.tempfile
= strdup(template);
5103 /* Show the "wristwatch" cursor, as graphic data may cause this */
5104 /* step to be inordinately long. */
5106 XDefineCursor(dpy
, areawin
->window
, WAITFOR
);
5107 savefile(ALL_PAGES
);
5108 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5109 xobjs
.new_changes
= 0; /* reset the count */
5113 /*----------------------------------------------------------------------*/
5114 /* Set all objects in the list "wroteobjs" as having no unsaved changes */
5115 /*----------------------------------------------------------------------*/
5117 void setassaved(objectptr
*wroteobjs
, short written
)
5121 for (i
= 0; i
< written
; i
++)
5122 (*(wroteobjs
+ i
))->changes
= 0;
5125 /*---------------------------------------------------------------*/
5126 /* Save indicated library. If libno is 0, save current page if */
5127 /* the current page is a library. If not, save the user library */
5128 /*---------------------------------------------------------------*/
5130 void savelibpopup(xcWidget button
, char *technology
, caddr_t nulldata
)
5135 buttonsave
*savebutton
;
5138 nsptr
= LookupTechnology(technology
);
5140 if (nsptr
!= NULL
) {
5141 if ((nsptr
->flags
& TECH_READONLY
) != 0) {
5142 Wprintf("Library technology \"%s\" is read-only.", technology
);
5148 savebutton
= getgeneric(button
, savelibpopup
, technology
);
5149 popupprompt(button
, "Enter technology:", "\0", savelibrary
,
5154 /*---------------------------------------------------------*/
5158 void savelibrary(xcWidget w
, char *technology
)
5161 sscanf(_STR2
, "%249s", outname
);
5162 savetechnology(technology
, outname
);
5167 /*---------------------------------------------------------*/
5169 void savetechnology(char *technology
, char *outname
)
5172 char *outptr
, *validname
, outfile
[150];
5173 objectptr
*wroteobjs
, libobjptr
, *optr
, depobj
;
5179 char *hostname
= NULL
;
5180 struct passwd
*mypwentry
= NULL
;
5183 char *loctechnology
;
5185 // Don't use the string "(user)" as a technology name; this is just
5186 // a GUI placeholder for a null string (""). This shouldn't happen,
5187 // though, as technology should be NULL if the user technology is
5190 if (technology
&& (!strcmp(technology
, "(user)")))
5191 nsptr
= LookupTechnology(NULL
);
5193 nsptr
= LookupTechnology(technology
);
5195 if ((outptr
= strrchr(outname
, '/')) == NULL
)
5199 strcpy(outfile
, outname
);
5200 if (strchr(outptr
, '.') == NULL
) strcat(outfile
, ".lps");
5202 xc_tilde_expand(outfile
, 149);
5203 while(xc_variable_expand(outfile
, 149));
5205 if (nsptr
!= NULL
&& nsptr
->filename
!= NULL
) {
5206 // To be pedantic, we should probably check that the inodes of the
5207 // files are different, to be sure we are avoiding an unintentional
5210 if (!strcmp(outfile
, nsptr
->filename
)) {
5212 if ((nsptr
->flags
& TECH_READONLY
) != 0) {
5213 Wprintf("Technology file \"%s\" is read-only.", technology
);
5217 if ((nsptr
->flags
& TECH_IMPORTED
) != 0) {
5218 Wprintf("Attempt to write a truncated technology file!");
5224 ps
= fopen(outfile
, "wb");
5226 Wprintf("Can't open PS file.");
5227 if (nsptr
&& nsptr
->filename
&& (!strcmp(nsptr
->filename
, outfile
))) {
5228 Wprintf("Marking technology \"%s\" as read-only.", technology
);
5229 nsptr
->flags
|= TECH_READONLY
;
5234 /* Did the technology name change? If so, register the new name. */
5235 /* Clear any "IMPORTED" or "READONLY" flags. */
5237 if (nsptr
&& nsptr
->filename
&& strcmp(outfile
, nsptr
->filename
)) {
5238 Wprintf("Technology filename changed from \"%s\" to \"%s\".",
5239 nsptr
->filename
, outfile
);
5240 free(nsptr
->filename
);
5241 nsptr
->filename
= strdup(outfile
);
5242 nsptr
->flags
&= ~(TECH_READONLY
| TECH_IMPORTED
);
5244 else if (nsptr
&& !nsptr
->filename
) {
5245 nsptr
->filename
= strdup(outfile
);
5246 nsptr
->flags
&= ~(TECH_READONLY
| TECH_IMPORTED
);
5249 fprintf(ps
, "%%! PostScript set of library objects for XCircuit\n");
5250 fprintf(ps
, "%% Version: %s\n", version
);
5251 fprintf(ps
, "%% Library name is: %s\n",
5252 (technology
== NULL
) ? "(user)" : technology
);
5254 uname
= getenv((const char *)"USERNAME");
5256 uname
= getenv((const char *)"USER");
5257 if (uname
!= NULL
) mypwentry
= getpwnam(uname
);
5260 /* Check for both $HOST and $HOSTNAME environment variables. Thanks */
5261 /* to frankie liu <frankliu@Stanford.EDU> for this fix. */
5263 if ((hostname
= getenv((const char *)"HOSTNAME")) == NULL
)
5264 if ((hostname
= getenv((const char *)"HOST")) == NULL
) {
5265 if (gethostname(_STR
, 149) != 0)
5272 if (mypwentry
!= NULL
)
5273 fprintf(ps
, "%% Author: %s <%s@%s>\n", mypwentry
->pw_gecos
, uname
,
5277 fprintf(ps
, "%%\n\n");
5279 /* Print lists of object dependencies, where they exist. */
5280 /* Note that objects can depend on objects in other technologies; */
5281 /* this is allowed. */
5283 wroteobjs
= (objectptr
*) malloc(sizeof(objectptr
));
5284 for (ilib
= 0; ilib
< xobjs
.numlibs
; ilib
++) {
5285 for (j
= 0; j
< xobjs
.userlibs
[ilib
].number
; j
++) {
5287 libobjptr
= *(xobjs
.userlibs
[ilib
].library
+ j
);
5288 if (CompareTechnology(libobjptr
, technology
)) {
5291 /* Search for all object definitions instantiated in this object, */
5292 /* and add them to the dependency list (non-recursive). */
5294 for (gptr
= libobjptr
->plist
; gptr
< libobjptr
->plist
5295 + libobjptr
->parts
; gptr
++) {
5296 if (IS_OBJINST(*gptr
)) {
5297 depobj
= TOOBJINST(gptr
)->thisobject
;
5299 /* Search among the list of objects already collected. */
5300 /* If this object has been previously, then ignore it. */
5301 /* Otherwise, update the list of object dependencies */
5303 for (optr
= wroteobjs
; optr
< wroteobjs
+ written
; optr
++)
5304 if (*optr
== depobj
)
5307 if (optr
== wroteobjs
+ written
) {
5308 wroteobjs
= (objectptr
*)realloc(wroteobjs
, (written
+ 1) *
5310 *(wroteobjs
+ written
) = depobj
;
5316 fprintf(ps
, "%% Depend %s", libobjptr
->name
);
5317 for (i
= 0; i
< written
; i
++) {
5318 depobj
= *(wroteobjs
+ i
);
5319 fprintf(ps
, " %s", depobj
->name
);
5327 fprintf(ps
, "\n%% XCircuitLib library objects\n");
5329 /* Start by looking for any graphic images in the library objects */
5330 /* and saving the graphic image data at the top of the file. */
5332 glist
= (short *)malloc(xobjs
.images
* sizeof(short));
5333 for (i
= 0; i
< xobjs
.images
; i
++) glist
[i
] = 0;
5335 for (ilib
= 0; ilib
< xobjs
.numlibs
; ilib
++) {
5336 for (spec
= xobjs
.userlibs
[ilib
].instlist
; spec
!= NULL
; spec
= spec
->next
) {
5337 libobjptr
= spec
->thisinst
->thisobject
;
5338 if (CompareTechnology(libobjptr
, technology
))
5339 count_graphics(spec
->thisinst
->thisobject
, glist
);
5342 output_graphic_data(ps
, glist
);
5345 /* list of library objects already written */
5347 wroteobjs
= (objectptr
*)realloc(wroteobjs
, sizeof(objectptr
));
5350 /* write all of the object definitions used, bottom up, with virtual */
5351 /* instances in the correct placement. The need to find virtual */
5352 /* instances is why we do a look through the library pages and not */
5353 /* the libraries themselves when looking for objects matching the */
5354 /* given technology. */
5356 for (ilib
= 0; ilib
< xobjs
.numlibs
; ilib
++) {
5357 for (spec
= xobjs
.userlibs
[ilib
].instlist
; spec
!= NULL
; spec
= spec
->next
) {
5358 libobjptr
= spec
->thisinst
->thisobject
;
5359 if (CompareTechnology(libobjptr
, technology
)) {
5360 if (!spec
->virtual) {
5361 printobjects(ps
, spec
->thisinst
->thisobject
, &wroteobjs
,
5362 &written
, DEFAULTCOLOR
);
5365 if ((spec
->thisinst
->scale
!= 1.0) ||
5366 (spec
->thisinst
->rotation
!= 0.0)) {
5367 fprintf(ps
, "%3.3f %3.3f ", spec
->thisinst
->scale
,
5368 spec
->thisinst
->rotation
);
5370 printparams(ps
, spec
->thisinst
, 0);
5371 validname
= create_valid_psname(spec
->thisinst
->thisobject
->name
, FALSE
);
5372 /* Names without technologies get '::' string (blank technology) */
5373 if (technology
== NULL
)
5374 fprintf(ps
, "/::%s libinst\n", validname
);
5376 fprintf(ps
, "/%s libinst\n", validname
);
5377 if ((spec
->next
!= NULL
) && (!(spec
->next
->virtual)))
5384 setassaved(wroteobjs
, written
);
5385 if (nsptr
) nsptr
->flags
&= (~TECH_CHANGED
);
5386 xobjs
.new_changes
= countchanges(NULL
);
5388 /* and the postlog */
5390 fprintf(ps
, "\n%% EndLib\n");
5392 if (technology
!= NULL
)
5393 Wprintf("Library technology \"%s\" saved as file %s.",technology
, outname
);
5395 Wprintf("Library technology saved as file %s.", outname
);
5400 /*----------------------------------------------------------------------*/
5401 /* Recursive routine to search the object hierarchy for fonts used */
5402 /*----------------------------------------------------------------------*/
5404 void findfonts(objectptr writepage
, short *fontsused
) {
5409 for (dfp
= writepage
->plist
; dfp
< writepage
->plist
+ writepage
->parts
; dfp
++) {
5410 if (IS_LABEL(*dfp
)) {
5411 for (chp
= TOLABEL(dfp
)->string
; chp
!= NULL
; chp
= chp
->nextpart
) {
5412 if (chp
->type
== FONT_NAME
) {
5413 findex
= chp
->data
.font
;
5414 if (fontsused
[findex
] == 0) {
5415 fontsused
[findex
] = 0x8000 | fonts
[findex
].flags
;
5420 else if (IS_OBJINST(*dfp
)) {
5421 findfonts(TOOBJINST(dfp
)->thisobject
, fontsused
);
5426 /*------------------------------------------------------*/
5427 /* Write graphics image data to file "ps". "glist" is */
5428 /* a pointer to a vector of short integers, each one */
5429 /* being an index into xobjs.images for an image that */
5430 /* is to be output. */
5431 /*------------------------------------------------------*/
5433 void output_graphic_data(FILE *ps
, short *glist
)
5435 char *fptr
, ascbuf
[6];
5437 for (i
= 0; i
< xobjs
.images
; i
++) {
5438 Imagedata
*img
= xobjs
.imagelist
+ i
;
5439 int ilen
, flen
, k
, m
= 0, n
, q
= 0;
5440 u_char
*filtbuf
, *flatebuf
;
5441 Boolean lastpix
= False
;
5446 int width
= xcImageGetWidth(img
->image
);
5447 int height
= xcImageGetHeight(img
->image
);
5449 if (glist
[i
] == 0) continue;
5451 fprintf(ps
, "%%imagedata %d %d\n", width
, height
);
5452 fprintf(ps
, "currentfile /ASCII85Decode filter ");
5455 fprintf(ps
, "/FlateDecode filter\n");
5458 fprintf(ps
, "/ReusableStreamDecode filter\n");
5460 /* creating a stream buffer is wasteful if we're just using ASCII85 */
5461 /* decoding but is a must for compression filters. */
5463 ilen
= 3 * width
* height
;
5464 filtbuf
= (u_char
*)malloc(ilen
+ 4);
5467 for (j
= 0; j
< height
; j
++)
5468 for (k
= 0; k
< width
; k
++) {
5469 unsigned char r
, g
, b
;
5470 xcImageGetPixel(img
->image
, k
, j
, &r
, &g
, &b
);
5476 /* Extra encoding goes here */
5479 flatebuf
= (char *)malloc(flen
);
5480 ilen
= large_deflate(flatebuf
, flen
, filtbuf
, ilen
);
5488 for (j
= 0; j
< ilen
; j
+= 4) {
5489 if ((j
+ 4) > ilen
) lastpix
= TRUE
;
5490 if (!lastpix
&& (flatebuf
[j
] + flatebuf
[j
+ 1] + flatebuf
[j
+ 2]
5491 + flatebuf
[j
+ 3] == 0)) {
5496 for (n
= 0; n
< 4; n
++)
5497 pixel
.b
[3 - n
] = flatebuf
[j
+ n
];
5499 ascbuf
[0] = '!' + (pixel
.i
/ 52200625);
5500 pixel
.i
%= 52200625;
5501 ascbuf
[1] = '!' + (pixel
.i
/ 614125);
5503 ascbuf
[2] = '!' + (pixel
.i
/ 7225);
5505 ascbuf
[3] = '!' + (pixel
.i
/ 85);
5507 ascbuf
[4] = '!' + pixel
.i
;
5509 for (n
= 0; n
< ilen
+ 1 - j
; n
++)
5510 fprintf(ps
, "%c", ascbuf
[n
]);
5512 fprintf(ps
, "%5s", ascbuf
);
5520 fprintf(ps
, "~>\n");
5523 /* Remove any filesystem path information from the image name. */
5524 /* Otherwise, the slashes will cause PostScript to err. */
5526 fptr
= strrchr(img
->filename
, '/');
5528 fptr
= img
->filename
;
5531 fprintf(ps
, "/%sdata exch def\n", fptr
);
5532 fprintf(ps
, "/%s <<\n", fptr
);
5533 fprintf(ps
, " /ImageType 1 /Width %d /Height %d /BitsPerComponent 8\n",
5535 fprintf(ps
, " /MultipleDataSources false\n");
5536 fprintf(ps
, " /Decode [0 1 0 1 0 1]\n");
5537 fprintf(ps
, " /ImageMatrix [1 0 0 -1 %d %d]\n",
5538 width
>> 1, height
>> 1);
5539 fprintf(ps
, " /DataSource %sdata >> def\n\n", fptr
);
5543 /*----------------------------------------------------------------------*/
5544 /* Main file saving routine */
5545 /*----------------------------------------------------------------------*/
5546 /* mode description */
5547 /*----------------------------------------------------------------------*/
5548 /* ALL_PAGES saves a crash recovery backup file */
5549 /* CURRENT_PAGE saves all pages associated with the same */
5550 /* filename as the current page, and all */
5551 /* dependent schematics (which have their */
5552 /* filenames changed to match). */
5553 /* NO_SUBCIRCUITS saves all pages associated with the same */
5554 /* filename as the current page, only. */
5555 /*----------------------------------------------------------------------*/
5557 void savefile(short mode
)
5559 FILE *ps
, *pro
, *enc
;
5560 char outname
[150], temp
[150], prologue
[150], *fname
, *fptr
, ascbuf
[6];
5561 /* u_char decodebuf[6]; (jdk */
5562 short written
, fontsused
[256], i
, page
, curpage
, multipage
;
5563 short savepage
, stcount
, *pagelist
, *glist
;
5564 objectptr
*wroteobjs
;
5565 objinstptr writepage
;
5570 if (mode
!= ALL_PAGES
) {
5571 /* doubly-protected file write: protect against errors during file write */
5572 fname
= xobjs
.pagelist
[areawin
->page
]->filename
;
5573 sprintf(outname
, "%s~", fname
);
5574 rename(fname
, outname
);
5577 /* doubly-protected backup: protect against errors during file write */
5578 sprintf(outname
, "%sB", xobjs
.tempfile
);
5579 rename(xobjs
.tempfile
, outname
);
5580 fname
= xobjs
.tempfile
;
5583 if ((fptr
= strrchr(fname
, '/')) != NULL
)
5588 if ((mode
!= ALL_PAGES
) && (strchr(fptr
, '.') == NULL
))
5589 sprintf(outname
, "%s.ps", fname
);
5590 else sprintf(outname
, "%s", fname
);
5592 xc_tilde_expand(outname
, 149);
5593 while(xc_variable_expand(outname
, 149));
5595 ps
= fopen(outname
, "wb");
5597 Wprintf("Can't open file %s for writing.", outname
);
5601 if ((mode
!= NO_SUBCIRCUITS
) && (mode
!= ALL_PAGES
))
5602 collectsubschems(areawin
->page
);
5604 /* Check for multiple-page output: get the number of pages; */
5605 /* ignore empty pages. */
5609 if (mode
== NO_SUBCIRCUITS
)
5610 pagelist
= pagetotals(areawin
->page
, INDEPENDENT
);
5611 else if (mode
== ALL_PAGES
)
5612 pagelist
= pagetotals(areawin
->page
, ALL_PAGES
);
5614 pagelist
= pagetotals(areawin
->page
, TOTAL_PAGES
);
5616 for (page
= 0; page
< xobjs
.pages
; page
++)
5617 if (pagelist
[page
] > 0)
5620 if (multipage
== 0) {
5621 Wprintf("Panic: could not find this page in page list!");
5627 /* Print the PostScript DSC Document Header */
5629 fprintf(ps
, "%%!PS-Adobe-3.0");
5630 if (multipage
== 1 && !(xobjs
.pagelist
[areawin
->page
]->pmode
& 1))
5631 fprintf(ps
, " EPSF-3.0\n");
5634 fprintf(ps
, "%%%%Title: %s\n", fptr
);
5635 fprintf(ps
, "%%%%Creator: XCircuit v%2.1f rev%d\n", PROG_VERSION
, PROG_REVISION
);
5637 fprintf(ps
, "%%%%CreationDate: %s", asctime(localtime(&tdate
)));
5638 fprintf(ps
, "%%%%Pages: %d\n", multipage
);
5640 /* This is just a default value; each bounding box is declared per */
5641 /* page by the DSC "PageBoundingBox" keyword. */
5642 /* However, encapsulated files adjust the bounding box to center on */
5643 /* the object, instead of centering the object on the page. */
5645 if (multipage
== 1 && !(xobjs
.pagelist
[areawin
->page
]->pmode
& 1)) {
5646 objectptr thisobj
= xobjs
.pagelist
[areawin
->page
]->pageinst
->thisobject
;
5647 float psscale
= getpsscale(xobjs
.pagelist
[areawin
->page
]->outscale
,
5650 /* The top-level bounding box determines the size of an encapsulated */
5651 /* drawing, regardless of the PageBoundingBox numbers. Therefore, */
5652 /* we size this to bound just the picture by closing up the 1" (72 */
5653 /* PostScript units) margins, except for a tiny sliver of a margin */
5654 /* (4 PostScript units) which covers a bit of sloppiness in the font */
5657 fprintf(ps
, "%%%%BoundingBox: 68 68 %d %d\n",
5658 (int)((float)thisobj
->bbox
.width
* psscale
)
5659 + xobjs
.pagelist
[areawin
->page
]->margins
.x
+ 4,
5660 (int)((float)thisobj
->bbox
.height
* psscale
)
5661 + xobjs
.pagelist
[areawin
->page
]->margins
.y
+ 4);
5663 else if (xobjs
.pagelist
[0]->coordstyle
== CM
)
5664 fprintf(ps
, "%%%%BoundingBox: 0 0 595 842\n"); /* A4 default (fixed by jdk) */
5666 fprintf(ps
, "%%%%BoundingBox: 0 0 612 792\n"); /* letter default */
5668 for (i
= 0; i
< fontcount
; i
++) fontsused
[i
] = 0;
5669 fprintf(ps
, "%%%%DocumentNeededResources: font ");
5672 /* find all of the fonts used in this document */
5673 /* log all fonts which are native PostScript */
5675 for (curpage
= 0; curpage
< xobjs
.pages
; curpage
++)
5676 if (pagelist
[curpage
] > 0) {
5677 writepage
= xobjs
.pagelist
[curpage
]->pageinst
;
5678 findfonts(writepage
->thisobject
, fontsused
);
5681 for (i
= 0; i
< fontcount
; i
++) {
5682 if (fontsused
[i
] & 0x8000)
5683 if ((fonts
[i
].flags
& 0x8018) == 0x0) {
5684 stcount
+= strlen(fonts
[i
].psname
) + 1;
5685 if (stcount
> OUTPUTWIDTH
) {
5686 stcount
= strlen(fonts
[i
].psname
) + 11;
5687 fprintf(ps
, "\n%%%%+ font ");
5689 fprintf(ps
, "%s ", fonts
[i
].psname
);
5693 fprintf(ps
, "\n%%%%EndComments\n");
5695 tmp_s
= getenv((const char *)"XCIRCUIT_LIB_DIR");
5696 if (tmp_s
!= NULL
) {
5697 sprintf(prologue
, "%s/%s", tmp_s
, PROLOGUE_FILE
);
5698 pro
= fopen(prologue
, "r");
5704 sprintf(prologue
, "%s/%s", PROLOGUE_DIR
, PROLOGUE_FILE
);
5705 pro
= fopen(prologue
, "r");
5707 sprintf(prologue
, "%s", PROLOGUE_FILE
);
5708 pro
= fopen(prologue
, "r");
5710 Wprintf("Can't open prolog.");
5718 /* write the prolog to the output */
5721 if (fgets(temp
, 149, pro
) == NULL
) break;
5722 if (!strncmp(temp
, "%%EndProlog", 11)) break;
5727 /* Special font encodings not known to PostScript */
5728 /* (anything other than Standard and ISOLatin-1) */
5730 for (findex
= 0; findex
< fontcount
; findex
++) {
5731 if ((fontsused
[findex
] & 0xf80) == 0x400) {
5732 /* Cyrillic (ISO8859-5) */
5733 sprintf(prologue
, "%s/%s", PROLOGUE_DIR
, CYRILLIC_ENC_FILE
);
5734 pro
= fopen(prologue
, "r");
5736 sprintf(prologue
, "%s", CYRILLIC_ENC_FILE
);
5737 pro
= fopen(prologue
, "r");
5739 Wprintf("Warning: Missing font encoding vectors.");
5740 Wprintf("Output may not print properly.");
5745 if (fgets(temp
, 149, pro
) == NULL
) break;
5751 else if ((fontsused
[findex
] & 0xf80) == 0x180) {
5752 /* Eastern European (ISOLatin2) */
5753 sprintf(prologue
, "%s/%s", PROLOGUE_DIR
, ISOLATIN2_ENC_FILE
);
5754 pro
= fopen(prologue
, "r");
5756 sprintf(prologue
, "%s", ISOLATIN2_ENC_FILE
);
5757 pro
= fopen(prologue
, "r");
5759 Wprintf("Warning: Missing font encoding vectors.");
5760 Wprintf("Output may not print properly.");
5765 if (fgets(temp
, 149, pro
) == NULL
) break;
5771 else if ((fontsused
[findex
] & 0xf80) == 0x300) {
5772 /* Turkish (ISOLatin5) */
5773 sprintf(prologue
, "%s/%s", PROLOGUE_DIR
, ISOLATIN5_ENC_FILE
);
5774 pro
= fopen(prologue
, "r");
5776 sprintf(prologue
, "%s", ISOLATIN5_ENC_FILE
);
5777 pro
= fopen(prologue
, "r");
5779 Wprintf("Warning: Missing font encoding vectors.");
5780 Wprintf("Output may not print properly.");
5785 if (fgets(temp
, 149, pro
) == NULL
) break;
5793 /* Finish off prolog */
5794 fputs("%%EndProlog\n", ps
);
5796 /* Special font handling */
5798 for (findex
= 0; findex
< fontcount
; findex
++) {
5800 /* Derived font slant */
5802 if ((fontsused
[findex
] & 0x032) == 0x032)
5803 fprintf(ps
, "/%s /%s .167 fontslant\n\n",
5804 fonts
[findex
].psname
, fonts
[findex
].family
);
5806 /* Derived ISO-Latin1 encoding */
5808 if ((fontsused
[findex
] & 0xf80) == 0x100) {
5809 char *fontorig
= NULL
;
5811 /* find the original standard-encoded font (can be itself) */
5812 for (i
= 0; i
< fontcount
; i
++) {
5813 if (i
== findex
) continue;
5814 if (!strcmp(fonts
[i
].family
, fonts
[findex
].family
) &&
5815 ((fonts
[i
].flags
& 0x03) == (fonts
[findex
].flags
& 0x03))) {
5816 fontorig
= fonts
[i
].psname
;
5820 if (fontorig
== NULL
) fontorig
= fonts
[findex
].psname
;
5821 fprintf(ps
, "/%s findfont dup length dict begin\n", fontorig
);
5822 fprintf(ps
, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
5823 fprintf(ps
, "/Encoding ISOLatin1Encoding def currentdict end\n");
5824 fprintf(ps
, "/%s exch definefont pop\n\n", fonts
[findex
].psname
);
5827 /* Derived Cyrillic (ISO8859-5) encoding */
5829 if ((fontsused
[findex
] & 0xf80) == 0x400) {
5830 char *fontorig
= NULL
;
5832 /* find the original standard-encoded font (can be itself) */
5833 for (i
= 0; i
< fontcount
; i
++) {
5834 if (i
== findex
) continue;
5835 if (!strcmp(fonts
[i
].family
, fonts
[findex
].family
) &&
5836 ((fonts
[i
].flags
& 0x03) == (fonts
[findex
].flags
& 0x03))) {
5837 fontorig
= fonts
[i
].psname
;
5841 if (fontorig
== NULL
) fontorig
= fonts
[findex
].psname
;
5842 fprintf(ps
, "/%s findfont dup length dict begin\n", fontorig
);
5843 fprintf(ps
, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
5844 fprintf(ps
, "/Encoding ISO8859_5Encoding def currentdict end\n");
5845 fprintf(ps
, "/%s exch definefont pop\n\n", fonts
[findex
].psname
);
5848 /* ISO-Latin2 encoding */
5850 if ((fontsused
[findex
] & 0xf80) == 0x180) {
5851 char *fontorig
= NULL
;
5853 /* find the original standard-encoded font (can be itself) */
5854 for (i
= 0; i
< fontcount
; i
++) {
5855 if (i
== findex
) continue;
5856 if (!strcmp(fonts
[i
].family
, fonts
[findex
].family
) &&
5857 ((fonts
[i
].flags
& 0x03) == (fonts
[findex
].flags
& 0x03))) {
5858 fontorig
= fonts
[i
].psname
;
5862 if (fontorig
== NULL
) fontorig
= fonts
[findex
].psname
;
5863 fprintf(ps
, "/%s findfont dup length dict begin\n", fontorig
);
5864 fprintf(ps
, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
5865 fprintf(ps
, "/Encoding ISOLatin2Encoding def currentdict end\n");
5866 fprintf(ps
, "/%s exch definefont pop\n\n", fonts
[findex
].psname
);
5869 /* ISO-Latin5 encoding */
5871 if ((fontsused
[findex
] & 0xf80) == 0x300) {
5872 char *fontorig
= NULL
;
5874 /* find the original standard-encoded font (can be itself) */
5875 for (i
= 0; i
< fontcount
; i
++) {
5876 if (i
== findex
) continue;
5877 if (!strcmp(fonts
[i
].family
, fonts
[findex
].family
) &&
5878 ((fonts
[i
].flags
& 0x03) == (fonts
[findex
].flags
& 0x03))) {
5879 fontorig
= fonts
[i
].psname
;
5883 if (fontorig
== NULL
) fontorig
= fonts
[findex
].psname
;
5884 fprintf(ps
, "/%s findfont dup length dict begin\n", fontorig
);
5885 fprintf(ps
, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
5886 fprintf(ps
, "/Encoding ISOLatin5Encoding def currentdict end\n");
5887 fprintf(ps
, "/%s exch definefont pop\n\n", fonts
[findex
].psname
);
5890 /* To do: Special encoding */
5892 if ((fontsused
[findex
] & 0xf80) == 0x80) {
5895 /* To do: Vectored (drawn) font */
5897 if (fontsused
[findex
] & 0x8) {
5901 /* List of objects already written */
5902 wroteobjs
= (objectptr
*) malloc (sizeof(objectptr
));
5905 fprintf(ps
, "%% XCircuit output starts here.\n\n");
5906 fprintf(ps
, "%%%%BeginSetup\n\n");
5908 /* Write out all of the images used */
5910 glist
= collect_graphics(pagelist
);
5911 output_graphic_data(ps
, glist
);
5914 for (curpage
= 0; curpage
< xobjs
.pages
; curpage
++) {
5915 if (pagelist
[curpage
] == 0) continue;
5917 /* Write all of the object definitions used, bottom up */
5918 printrefobjects(ps
, xobjs
.pagelist
[curpage
]->pageinst
->thisobject
,
5919 &wroteobjs
, &written
);
5922 fprintf(ps
, "\n%%%%EndSetup\n\n");
5925 for (curpage
= 0; curpage
< xobjs
.pages
; curpage
++) {
5926 if (pagelist
[curpage
] == 0) continue;
5928 /* Print the page header, all elements in the page, and page trailer */
5929 savepage
= areawin
->page
;
5930 /* Set the current page for the duration of printing so that any */
5931 /* page parameters will be printed correctly. */
5932 areawin
->page
= curpage
;
5933 printpageobject(ps
, xobjs
.pagelist
[curpage
]->pageinst
->thisobject
,
5935 areawin
->page
= savepage
;
5937 /* For crash recovery, log the filename for each page */
5938 if (mode
== ALL_PAGES
) {
5939 fprintf(ps
, "%% %s is_filename\n",
5940 (xobjs
.pagelist
[curpage
]->filename
== NULL
) ?
5941 xobjs
.pagelist
[curpage
]->pageinst
->thisobject
->name
:
5942 xobjs
.pagelist
[curpage
]->filename
);
5949 /* For crash recovery, save all objects that have been edited but are */
5950 /* not in the list of objects already saved. */
5952 if (mode
== ALL_PAGES
)
5957 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
5958 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
5959 thisobj
= *(xobjs
.userlibs
[i
].library
+ j
);
5960 if (thisobj
->changes
> 0 ) {
5961 for (k
= 0; k
< written
; k
++)
5962 if (thisobj
== *(wroteobjs
+ k
)) break;
5964 printobjects(ps
, thisobj
, &wroteobjs
, &written
, DEFAULTCOLOR
);
5969 else { /* No unsaved changes in these objects */
5970 setassaved(wroteobjs
, written
);
5971 for (i
= 0; i
< xobjs
.pages
; i
++)
5972 if (pagelist
[i
] > 0)
5973 xobjs
.pagelist
[i
]->pageinst
->thisobject
->changes
= 0;
5974 xobjs
.new_changes
= countchanges(NULL
);
5977 /* Free allocated memory */
5978 free((char *)pagelist
);
5979 free((char *)wroteobjs
);
5983 fprintf(ps
, "%%%%Trailer\n");
5984 fprintf(ps
, "XCIRCsave restore\n");
5985 fprintf(ps
, "%%%%EOF\n");
5988 Wprintf("File %s saved (%d page%s).", fname
, multipage
,
5989 (multipage
> 1 ? "s" : ""));
5991 if (mode
== ALL_PAGES
) {
5992 /* Remove the temporary redundant backup */
5993 sprintf(outname
, "%sB", xobjs
.tempfile
);
5996 else if (!xobjs
.retain_backup
) {
5997 /* Remove the backup file */
5998 sprintf(outname
, "%s~", fname
);
6002 /* Write LATEX strings, if any are present */
6006 /*----------------------------------------------------------------------*/
6007 /* Given a color index, print the R, G, B values */
6008 /*----------------------------------------------------------------------*/
6010 int printRGBvalues(char *tstr
, int index
, const char *postfix
)
6013 if (index
>= 0 && index
< number_colors
) {
6014 sprintf(tstr
, "%4.3f %4.3f %4.3f %s",
6015 (float)colorlist
[index
].color
.red
/ 65535,
6016 (float)colorlist
[index
].color
.green
/ 65535,
6017 (float)colorlist
[index
].color
.blue
/ 65535,
6022 /* The program can reach this point for any color which is */
6023 /* not listed in the table. This can happen when parameters */
6024 /* printed from printobjectparams object contain the string */
6025 /* "@p_color". Therefore print the default top-level */
6026 /* default color, which is black. */
6028 /* If the index is *not* DEFAULTCOLOR (-1), return an error */
6031 sprintf(tstr
, "0 0 0 %s", postfix
);
6032 return (index
== DEFAULTCOLOR
) ? 0 : -1;
6035 /*----------------------------------------------------*/
6036 /* Write string to PostScript string, ignoring NO_OPs */
6037 /*----------------------------------------------------*/
6039 char *nosprint(char *baseptr
, int *margin
, int *extsegs
)
6041 int qtmp
, slen
= 100;
6042 char *sptr
, *lptr
= NULL
, lsave
, *sptr2
;
6043 u_char
*pptr
, *qptr
, *bptr
;
6045 bptr
= (u_char
*)malloc(slen
); /* initial length 100 */
6048 while(1) { /* loop for breaking up margin-limited text into words */
6051 sptr
= strrchr(baseptr
, ' ');
6055 if (*(sptr
+ 1) == '\0') {
6056 while (*sptr
== ' ') sptr
--;
6058 sptr2
= strrchr(baseptr
, ' ');
6074 /* Includes extended character set (non-ASCII) */
6076 for (pptr
= sptr
; pptr
&& *pptr
!= '\0'; pptr
++) {
6077 /* Ensure enough space for the string, including everything */
6078 /* following the "for" loop */
6080 if (qtmp
+ 7 >= slen
) {
6082 bptr
= (char *)realloc(bptr
, slen
);
6086 /* Deal with non-printable characters and parentheses */
6087 if (*pptr
> (char)126) {
6088 sprintf(qptr
, "\\%3o", (int)(*pptr
));
6092 if ((*pptr
== '(') || (*pptr
== ')') || (*pptr
== '\\'))
6097 if (qptr
== bptr
+ 1) { /* Empty string gets a NULL result, not "()" */
6108 if (sptr
== baseptr
)
6119 return (char *)bptr
;
6122 /*--------------------------------------------------------------*/
6123 /* Write label segments to the output (in reverse order) */
6124 /*--------------------------------------------------------------*/
6126 short writelabel(FILE *ps
, stringpart
*chrtop
, short *stcount
)
6130 char **ostr
= (char **)malloc(sizeof(char *));
6132 float lastscale
= 1.0;
6137 /* Write segments into string array, in forward order */
6139 for (chrptr
= chrtop
; chrptr
!= NULL
; chrptr
= chrptr
->nextpart
) {
6140 ostr
= (char **)realloc(ostr
, (segs
+ 1) * sizeof(char *));
6141 if (chrtop
->type
== PARAM_END
) { /* NULL parameter is empty string */
6142 ostr
[segs
] = (char *)malloc(4);
6143 strcpy(ostr
[segs
], "() ");
6146 tmpstr
= writesegment(chrptr
, &lastscale
, &lastfont
, &margin
, &extsegs
);
6147 if (tmpstr
[0] != '\0')
6148 ostr
[segs
] = tmpstr
;
6155 /* Write string array to output in reverse order */
6156 for (i
= segs
- 1; i
>= 0; i
--) {
6157 dostcount(ps
, stcount
, strlen(ostr
[i
]));
6163 return segs
+ extsegs
;
6166 /*--------------------------------------------------------------*/
6167 /* Write a single label segment to the output */
6168 /* (Recursive, so we can write segments in the reverse order) */
6169 /*--------------------------------------------------------------*/
6171 char *writesegment(stringpart
*chrptr
, float *lastscale
, int *lastfont
, int *margin
,
6174 int type
= chrptr
->type
;
6175 char *retstr
, *validname
;
6179 validname
= create_valid_psname(chrptr
->data
.string
, TRUE
);
6180 sprintf(_STR
, "%s ", validname
);
6184 chrptr
->nextpart
= NULL
;
6187 sprintf(_STR
, "{ss} ");
6190 sprintf(_STR
, "{Ss} ");
6194 sprintf(_STR
, "{ns} ");
6197 sprintf(_STR
, "{ul} ");
6200 sprintf(_STR
, "{ol} ");
6203 sprintf(_STR
, "{} ");
6206 sprintf(_STR
, "{hS} ");
6209 sprintf(_STR
, "{qS} ");
6213 if (chrptr
->data
.flags
== 0)
6214 // Ignore automatically-generated line breaks
6215 sprintf(_STR
, "{CR} ");
6220 sprintf(_STR
, "{Ts} ");
6223 sprintf(_STR
, "{Tf} ");
6226 sprintf(_STR
, "{Tb} ");
6229 /* If font specifier is followed by a scale specifier, then */
6230 /* record the font change but defer the output. Otherwise, */
6231 /* output the font record now. */
6233 if ((chrptr
->nextpart
== NULL
) || (chrptr
->nextpart
->type
!= FONT_SCALE
))
6235 if (*lastscale
== 1.0)
6236 sprintf(_STR
, "{/%s cf} ", fonts
[chrptr
->data
.font
].psname
);
6238 sprintf(_STR
, "{/%s %5.3f cf} ", fonts
[chrptr
->data
.font
].psname
,
6243 *lastfont
= chrptr
->data
.font
;
6246 if (*lastfont
== -1) {
6247 Fprintf(stderr
, "Warning: Font may not be the one that was intended.\n");
6250 *lastscale
= chrptr
->data
.scale
;
6251 sprintf(_STR
, "{/%s %5.3f cf} ", fonts
[*lastfont
].psname
, *lastscale
);
6255 if (chrptr
->data
.color
== DEFAULTCOLOR
)
6256 strcat(_STR
, "sce} ");
6258 if (printRGBvalues(_STR
+ 1, chrptr
->data
.color
, "scb} ") < 0)
6259 strcat(_STR
, "sce} ");
6262 sprintf(_STR
, "{%d MR} ", chrptr
->data
.width
);
6263 *margin
= chrptr
->data
.width
;
6266 sprintf(_STR
, "{%d %d Kn} ", chrptr
->data
.kern
[0], chrptr
->data
.kern
[1]);
6269 /* Everything except TEXT_STRING will always fit in the _STR fixed- */
6270 /* length character array. */
6271 return nosprint(chrptr
->data
.string
, margin
, extsegs
);
6274 retstr
= (char *)malloc(1 + strlen(_STR
));
6275 strcpy(retstr
, _STR
);
6279 /*--------------------------------------------------------------*/
6280 /* Routine to write all the label segments as stored in _STR */
6281 /*--------------------------------------------------------------*/
6283 int writelabelsegs(FILE *ps
, short *stcount
, stringpart
*chrptr
)
6285 Boolean ismultipart
;
6288 if (chrptr
== NULL
) return 0;
6290 ismultipart
= ((chrptr
->nextpart
!= NULL
) &&
6291 (chrptr
->nextpart
->type
!= PARAM_END
)) ? True
: False
;
6293 /* If there is only one part, but it is not a string or the */
6294 /* end of a parameter (empty parameter), then set multipart */
6295 /* anyway so we get the double brace {{ }}. */
6297 if ((!ismultipart
) && (chrptr
->type
!= TEXT_STRING
) &&
6298 (chrptr
->type
!= PARAM_END
))
6301 /* nextpart is not NULL if there are multiple parts to the string */
6306 segs
= writelabel(ps
, chrptr
, stcount
);
6315 /*--------------------------------------------------------------*/
6316 /* Write the dictionary of parameters belonging to an object */
6317 /*--------------------------------------------------------------*/
6319 void printobjectparams(FILE *ps
, objectptr localdata
)
6324 char *ps_expr
, *validkey
;
6327 /* Check for parameters and default values */
6328 if (localdata
->params
== NULL
) return;
6333 for (ops
= localdata
->params
; ops
!= NULL
; ops
= ops
->next
) {
6334 validkey
= create_valid_psname(ops
->key
, TRUE
);
6335 fprintf(ps
, "/%s ", validkey
);
6336 dostcount (ps
, &stcount
, strlen(validkey
) + 2);
6338 switch (ops
->type
) {
6340 ps_expr
= evaluate_expr(localdata
, ops
, NULL
);
6341 if (ops
->which
== P_SUBSTRING
|| ops
->which
== P_EXPRESSION
) {
6342 dostcount(ps
, &stcount
, 3 + strlen(ps_expr
));
6347 else if (ops
->which
== P_COLOR
) {
6349 /* Write R, G, B components for PostScript */
6350 if (sscanf(ps_expr
, "%d", &ccol
) == 1) {
6352 printRGBvalues(_STR
, ccol
, "} ");
6353 dostcount(ps
, &stcount
, 1 + strlen(_STR
));
6357 dostcount(ps
, &stcount
, 8);
6358 fputs("{0 0 0} ", ps
);
6361 else if (sscanf(ps_expr
, "%g", &fp
) == 1) {
6362 dostcount(ps
, &stcount
, 1 + strlen(ps_expr
));
6366 else { /* Expression evaluates to error in object */
6367 dostcount(ps
, &stcount
, 2);
6370 dostcount(ps
, &stcount
, 7 + strlen(ops
->parameter
.expr
));
6372 fputs(ops
->parameter
.expr
, ps
);
6373 fputs(") pop ", ps
);
6377 segs
= writelabelsegs(ps
, &stcount
, ops
->parameter
.string
);
6379 /* When writing object parameters, we cannot allow a */
6380 /* NULL value. Instead, print an empty string (). */
6381 dostcount(ps
, &stcount
, 3);
6386 sprintf(_STR
, "%d ", ops
->parameter
.ivalue
);
6387 dostcount(ps
, &stcount
, strlen(_STR
));
6391 sprintf(_STR
, "%g ", ops
->parameter
.fvalue
);
6392 dostcount(ps
, &stcount
, strlen(_STR
));
6399 dostcount (ps
, &stcount
, 3);
6402 /*--------------------------------------------------------------*/
6403 /* Write the list of parameters belonging to an object instance */
6404 /*--------------------------------------------------------------*/
6406 short printparams(FILE *ps
, objinstptr sinst
, short stcount
)
6410 oparamptr ops
, objops
;
6412 char *ps_expr
, *validkey
, *validref
;
6413 short instances
= 0;
6415 if (sinst
->params
== NULL
) return stcount
;
6417 for (ops
= sinst
->params
; ops
!= NULL
; ops
= ops
->next
) {
6418 validref
= strdup(create_valid_psname(ops
->key
, TRUE
));
6420 /* Check for indirect parameter references */
6421 for (epp
= sinst
->passed
; epp
!= NULL
; epp
= epp
->next
) {
6422 if ((epp
->flags
& P_INDIRECT
) && (epp
->pdata
.refkey
!= NULL
)) {
6423 if (!strcmp(epp
->pdata
.refkey
, ops
->key
)) {
6424 if (instances
++ == 0) {
6425 fprintf(ps
, "<<"); /* begin PostScript dictionary */
6426 loccount
= stcount
+ 2;
6428 dostcount(ps
, &loccount
, strlen(validref
+ 3));
6429 fprintf(ps
, "/%s ", validref
);
6430 dostcount(ps
, &loccount
, strlen(epp
->key
+ 1));
6431 validkey
= create_valid_psname(epp
->key
, TRUE
);
6432 fprintf(ps
, "%s ", validkey
);
6437 if (epp
== NULL
) { /* No indirection */
6438 Boolean nondefault
= TRUE
;
6439 char *deflt_expr
= NULL
;
6441 /* For instance values that are expression results, ignore if */
6442 /* the instance value is the same as the default value. */
6443 /* Correction 9/08: We can't second-guess expression results, */
6444 /* in particular, this doesn't work for an expression like */
6445 /* "page", where the local and default values will evaluate to */
6446 /* the same result, when clearly each page is intended to have */
6447 /* its own instance value, and "page" for an object is not a */
6448 /* well-defined concept. */
6451 // objops = match_param(sinst->thisobject, ops->key);
6452 // if (objops && (objops->type == XC_EXPR)) {
6455 // deflt_expr = evaluate_expr(sinst->thisobject, objops, NULL);
6456 // switch (ops->type) {
6458 // if (!textcomp(ops->parameter.string, deflt_expr, sinst))
6459 // nondefault = FALSE;
6462 // ps_expr = evaluate_expr(sinst->thisobject, ops, sinst);
6463 // if (!strcmp(ps_expr, deflt_expr)) nondefault = FALSE;
6466 // sscanf(deflt_expr, "%d", &i);
6467 // if (i == ops->parameter.ivalue) nondefault = FALSE;
6470 // sscanf(deflt_expr, "%g", &f);
6471 // if (f == ops->parameter.fvalue) nondefault = FALSE;
6474 // if (deflt_expr) free(deflt_expr);
6475 // if (nondefault == FALSE) {
6476 // if (ps_expr) free(ps_expr);
6481 if (instances
++ == 0) {
6482 fprintf(ps
, "<<"); /* begin PostScript dictionary */
6483 loccount
= stcount
+ 2;
6485 dostcount(ps
, &loccount
, strlen(validref
) + 2);
6486 fprintf(ps
, "/%s ", validref
);
6488 switch (ops
->type
) {
6490 segs
= writelabelsegs(ps
, &loccount
, ops
->parameter
.string
);
6492 /* When writing object parameters, we cannot allow a */
6493 /* NULL value. Instead, print an empty string (). */
6494 dostcount(ps
, &stcount
, 3);
6499 ps_expr
= evaluate_expr(sinst
->thisobject
, ops
, sinst
);
6500 dostcount(ps
, &loccount
, 3 + strlen(ps_expr
));
6506 /* The instance parameter expression may have the */
6507 /* same expression as the object but a different */
6508 /* result if the expression uses another parameter. */
6509 /* Only print the expression itself if it's different */
6510 /* from the object's expression. */
6512 objops
= match_param(sinst
->thisobject
, ops
->key
);
6513 if (objops
&& strcmp(ops
->parameter
.expr
, objops
->parameter
.expr
)) {
6514 dostcount(ps
, &loccount
, 3 + strlen(ops
->parameter
.expr
));
6516 fputs(ops
->parameter
.expr
, ps
);
6517 fputs(") pop ", ps
);
6521 if (ops
->which
== P_COLOR
) {
6522 /* Write R, G, B components */
6524 printRGBvalues(_STR
+ 1, ops
->parameter
.ivalue
, "} ");
6527 sprintf(_STR
, "%d ", ops
->parameter
.ivalue
);
6528 dostcount(ps
, &loccount
, strlen(_STR
));
6532 sprintf(_STR
, "%g ", ops
->parameter
.fvalue
);
6533 dostcount(ps
, &loccount
, strlen(_STR
));
6540 if (instances
> 0) {
6541 fprintf(ps
, ">> "); /* end PostScript dictionary */
6547 /*------------------------------------------------------------------*/
6548 /* Macro for point output (calls varpcheck() on x and y components) */
6549 /*------------------------------------------------------------------*/
6551 #define xyvarcheck(z, n, t) \
6552 varpcheck(ps, (z).x, localdata, n, &stcount, *(t), P_POSITION_X); \
6553 varpcheck(ps, (z).y, localdata, n, &stcount, *(t), P_POSITION_Y)
6555 #define xypathcheck(z, n, t, p) \
6556 varpathcheck(ps, (z).x, localdata, n, &stcount, t, TOPATH(p), P_POSITION_X); \
6557 varpathcheck(ps, (z).y, localdata, n, &stcount, t, TOPATH(p), P_POSITION_Y)
6559 /*--------------------------------------------------------------*/
6560 /* Main routine for writing the contents of a single object to */
6561 /* output file "ps". */
6562 /*--------------------------------------------------------------*/
6564 void printOneObject(FILE *ps
, objectptr localdata
, int ccolor
)
6566 int i
, curcolor
= ccolor
;
6567 genericptr
*savegen
, *pgen
;
6574 Boolean has_parameter
;
6575 char *fptr
, *validname
;
6577 /* first, get a total count of all objects and give warning if large */
6579 if ((is_page(localdata
) == -1) && (localdata
->parts
> 255)) {
6580 Wprintf("Warning: \"%s\" may exceed printer's PS limit for definitions",
6584 for (savegen
= localdata
->plist
; savegen
< localdata
->plist
+
6585 localdata
->parts
; savegen
++) {
6587 /* Check if this color is parameterized */
6591 /* FIXEDBBOX style is handled in the object header and */
6592 /* the part should be skipped. */
6594 if (ELEMENTTYPE(*savegen
) == POLYGON
)
6595 if (TOPOLY(savegen
)->style
& FIXEDBBOX
)
6598 for (epp
= (*savegen
)->passed
; epp
!= NULL
; epp
= epp
->next
) {
6599 ops
= match_param(localdata
, epp
->key
);
6600 if (ops
!= NULL
&& (ops
->which
== P_COLOR
)) {
6601 /* Ensure that the next element forces a color change */
6602 curcolor
= ERRORCOLOR
;
6603 sprintf(_STR
, "%s scb\n", epp
->key
);
6609 /* Enforce the rule that clipmasks must always be DEFAULTCOLOR */
6611 switch(ELEMENTTYPE(*savegen
)) {
6612 case POLYGON
: case SPLINE
: case ARC
: case PATH
:
6613 if (TOPOLY(savegen
)->style
& CLIPMASK
)
6614 (*savegen
)->color
= DEFAULTCOLOR
;
6618 /* change current color if different */
6620 if ((epp
== NULL
) && ((*savegen
)->color
!= curcolor
)) {
6621 if ((curcolor
= (*savegen
)->color
) == DEFAULTCOLOR
)
6622 fprintf(ps
, "sce\n");
6624 if (printRGBvalues(_STR
, (*savegen
)->color
, "scb\n") < 0) {
6625 fprintf(ps
, "sce\n");
6626 curcolor
= DEFAULTCOLOR
;
6634 switch(ELEMENTTYPE(*savegen
)) {
6637 varcheck(ps
, TOPOLY(savegen
)->style
, localdata
, &stcount
,
6639 varfcheck(ps
, TOPOLY(savegen
)->width
, localdata
, &stcount
,
6640 *savegen
, P_LINEWIDTH
);
6641 for (savept
= TOPOLY(savegen
)->points
; savept
< TOPOLY(savegen
)->
6642 points
+ TOPOLY(savegen
)->number
; savept
++) {
6643 varpcheck(ps
, savept
->x
, localdata
,
6644 savept
- TOPOLY(savegen
)->points
, &stcount
, *savegen
,
6646 varpcheck(ps
, savept
->y
, localdata
,
6647 savept
- TOPOLY(savegen
)->points
, &stcount
, *savegen
,
6650 sprintf(_STR
, "%hd ", TOPOLY(savegen
)->number
);
6651 dostcount (ps
, &stcount
, strlen(_STR
));
6653 if (varpcheck(ps
, 0, localdata
, -1, &stcount
, *savegen
,
6655 sprintf(_STR
, "addtox ");
6656 dostcount (ps
, &stcount
, strlen(_STR
));
6659 if (varpcheck(ps
, 0, localdata
, -1, &stcount
, *savegen
,
6661 sprintf(_STR
, "addtoy ");
6662 dostcount (ps
, &stcount
, strlen(_STR
));
6665 sprintf(_STR
, "polygon\n");
6666 dostcount (ps
, &stcount
, strlen(_STR
));
6671 pgen
= TOPATH(savegen
)->plist
;
6672 switch(ELEMENTTYPE(*pgen
)) {
6674 xypathcheck(TOPOLY(pgen
)->points
[0], 0, pgen
, savegen
);
6677 xypathcheck(TOSPLINE(pgen
)->ctrl
[0], 0, pgen
, savegen
);
6680 dostcount(ps
, &stcount
, 9);
6681 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6682 TOPATH(savegen
), P_POSITION_X
)) {
6683 sprintf(_STR
, "addtox1 ");
6684 dostcount (ps
, &stcount
, strlen(_STR
));
6687 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6688 TOPATH(savegen
), P_POSITION_Y
)) {
6689 sprintf(_STR
, "addtoy1 ");
6690 dostcount (ps
, &stcount
, strlen(_STR
));
6693 fprintf(ps
, "beginpath\n");
6694 for (pgen
= TOPATH(savegen
)->plist
; pgen
< TOPATH(savegen
)->plist
6695 + TOPATH(savegen
)->parts
; pgen
++) {
6696 switch(ELEMENTTYPE(*pgen
)) {
6698 for (savept
= TOPOLY(pgen
)->points
+ TOPOLY(pgen
)->number
6699 - 1; savept
> TOPOLY(pgen
)->points
; savept
--) {
6700 xypathcheck(*savept
, savept
- TOPOLY(pgen
)->points
, pgen
,
6703 sprintf(_STR
, "%hd ", TOPOLY(pgen
)->number
- 1);
6704 dostcount (ps
, &stcount
, strlen(_STR
));
6706 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6707 TOPATH(savegen
), P_POSITION_X
)) {
6708 sprintf(_STR
, "addtox ");
6709 dostcount (ps
, &stcount
, strlen(_STR
));
6712 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6713 TOPATH(savegen
), P_POSITION_Y
)) {
6714 sprintf(_STR
, "addtoy ");
6715 dostcount (ps
, &stcount
, strlen(_STR
));
6718 sprintf(_STR
, "polyc\n");
6719 dostcount (ps
, &stcount
, strlen(_STR
));
6723 xypathcheck(TOSPLINE(pgen
)->ctrl
[1], 1, pgen
, savegen
);
6724 xypathcheck(TOSPLINE(pgen
)->ctrl
[2], 2, pgen
, savegen
);
6725 xypathcheck(TOSPLINE(pgen
)->ctrl
[3], 3, pgen
, savegen
);
6726 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6727 TOPATH(savegen
), P_POSITION_X
)) {
6728 sprintf(_STR
, "addtox3 ");
6729 dostcount (ps
, &stcount
, strlen(_STR
));
6732 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6733 TOPATH(savegen
), P_POSITION_Y
)) {
6734 sprintf(_STR
, "addtoy3 ");
6735 dostcount (ps
, &stcount
, strlen(_STR
));
6738 fprintf(ps
, "curveto\n");
6742 varcheck(ps
, TOPATH(savegen
)->style
, localdata
, &stcount
,
6744 varfcheck(ps
, TOPATH(savegen
)->width
, localdata
, &stcount
,
6745 *savegen
, P_LINEWIDTH
);
6746 fprintf(ps
, "endpath\n");
6750 varcheck(ps
, TOSPLINE(savegen
)->style
, localdata
, &stcount
,
6752 varfcheck(ps
, TOSPLINE(savegen
)->width
, localdata
, &stcount
,
6753 *savegen
, P_LINEWIDTH
);
6754 xyvarcheck(TOSPLINE(savegen
)->ctrl
[1], 1, savegen
);
6755 xyvarcheck(TOSPLINE(savegen
)->ctrl
[2], 2, savegen
);
6756 xyvarcheck(TOSPLINE(savegen
)->ctrl
[3], 3, savegen
);
6757 xyvarcheck(TOSPLINE(savegen
)->ctrl
[0], 0, savegen
);
6758 if (varpcheck(ps
, 0, localdata
, -1, &stcount
, *savegen
,
6760 sprintf(_STR
, "addtox4 ");
6761 dostcount (ps
, &stcount
, strlen(_STR
));
6764 if (varpcheck(ps
, 0, localdata
, -1, &stcount
, *savegen
,
6766 sprintf(_STR
, "addtoy4 ");
6767 dostcount (ps
, &stcount
, strlen(_STR
));
6770 fprintf(ps
, "spline\n");
6774 varcheck(ps
, TOARC(savegen
)->style
, localdata
, &stcount
,
6776 varfcheck(ps
, TOARC(savegen
)->width
, localdata
, &stcount
,
6777 *savegen
, P_LINEWIDTH
);
6778 xyvarcheck(TOARC(savegen
)->position
, 0, savegen
);
6779 varcheck(ps
, abs(TOARC(savegen
)->radius
), localdata
, &stcount
,
6780 *savegen
, P_RADIUS
);
6781 if (abs(TOARC(savegen
)->radius
) == TOARC(savegen
)->yaxis
) {
6782 varfcheck(ps
, TOARC(savegen
)->angle1
, localdata
, &stcount
,
6783 *savegen
, P_ANGLE1
);
6784 varfcheck(ps
, TOARC(savegen
)->angle2
, localdata
, &stcount
,
6785 *savegen
, P_ANGLE2
);
6786 fprintf(ps
, "xcarc\n");
6789 varcheck(ps
, abs(TOARC(savegen
)->yaxis
), localdata
, &stcount
,
6790 *savegen
, P_MINOR_AXIS
);
6791 varfcheck(ps
, TOARC(savegen
)->angle1
, localdata
, &stcount
,
6792 *savegen
, P_ANGLE1
);
6793 varfcheck(ps
, TOARC(savegen
)->angle2
, localdata
, &stcount
,
6794 *savegen
, P_ANGLE2
);
6795 fprintf(ps
, "ellipse\n");
6800 sobj
= TOOBJINST(savegen
);
6801 varfcheck(ps
, sobj
->scale
, localdata
, &stcount
, *savegen
, P_SCALE
);
6802 if (!(sobj
->style
& LINE_INVARIANT
)) fprintf(ps
, "/sv ");
6803 varfcheck(ps
, sobj
->rotation
, localdata
, &stcount
, *savegen
, P_ROTATION
);
6804 xyvarcheck(sobj
->position
, 0, savegen
);
6805 if (sobj
->style
& INST_NONETLIST
) fprintf(ps
, "/nn ");
6807 opsubstitute(sobj
->thisobject
, sobj
);
6808 stcount
= printparams(ps
, sobj
, stcount
);
6810 validname
= create_valid_psname(sobj
->thisobject
->name
, FALSE
);
6812 /* Names without technologies get a leading string '::' */
6813 /* (blank technology) */
6815 if (strstr(validname
, "::") == NULL
)
6816 fprintf(ps
, "::%s\n", validname
);
6818 fprintf(ps
, "%s\n", validname
);
6822 sg
= TOGRAPHIC(savegen
);
6823 for (i
= 0; i
< xobjs
.images
; i
++) {
6824 img
= xobjs
.imagelist
+ i
;
6825 if (img
->image
== sg
->source
)
6829 fptr
= strrchr(img
->filename
, '/');
6831 fptr
= img
->filename
;
6834 fprintf(ps
, "/%s ", fptr
);
6835 stcount
+= (2 + strlen(fptr
));
6837 varfcheck(ps
, sg
->scale
, localdata
, &stcount
, *savegen
, P_SCALE
);
6838 varfcheck(ps
, sg
->rotation
, localdata
, &stcount
, *savegen
, P_ROTATION
);
6839 xyvarcheck(sg
->position
, 0, savegen
);
6840 fprintf(ps
, "graphic\n");
6845 /* Don't save temporary labels from schematic capture system */
6846 if (TOLABEL(savegen
)->string
->type
!= FONT_NAME
) break;
6848 /* Check for parameter --- must use "mark" to count # segments */
6849 has_parameter
= hasparameter(TOLABEL(savegen
));
6851 if (has_parameter
) {
6852 fprintf(ps
, "mark ");
6856 segs
= writelabel(ps
, TOLABEL(savegen
)->string
, &stcount
);
6860 sprintf(_STR
, "ctmk ");
6862 sprintf(_STR
, "%hd ", segs
);
6863 dostcount(ps
, &stcount
, strlen(_STR
));
6865 varcheck(ps
, TOLABEL(savegen
)->anchor
, localdata
, &stcount
,
6866 *savegen
, P_ANCHOR
);
6867 varfcheck(ps
, TOLABEL(savegen
)->rotation
, localdata
, &stcount
,
6868 *savegen
, P_ROTATION
);
6869 varfcheck(ps
, TOLABEL(savegen
)->scale
, localdata
, &stcount
,
6871 xyvarcheck(TOLABEL(savegen
)->position
, 0, savegen
);
6873 switch(TOLABEL(savegen
)->pin
) {
6875 strcpy(_STR
, "pinlabel\n"); break;
6877 strcpy(_STR
, "pinglobal\n"); break;
6879 strcpy(_STR
, "infolabel\n"); break;
6881 strcpy(_STR
, "label\n");
6883 dostcount(ps
, &stcount
, strlen(_STR
));
6891 /*----------------------------------------------------------------------*/
6892 /* Recursive routine to print out the library objects used in this */
6893 /* drawing, starting at the bottom of the object hierarchy so that each */
6894 /* object is defined before it is called. A list of objects already */
6895 /* written is maintained so that no object is written twice. */
6897 /* When object "localdata" is not a top-level page, call this routine */
6898 /* with mpage=-1 (simpler than checking whether localdata is a page). */
6899 /*----------------------------------------------------------------------*/
6901 void printobjects(FILE *ps
, objectptr localdata
, objectptr
**wrotelist
,
6902 short *written
, int ccolor
)
6904 genericptr
*gptr
, *savegen
;
6906 /* oparamptr ops; (jdk) */
6908 int curcolor
= ccolor
;
6909 /* int libno; (jdk) */
6911 /* Search among the list of objects already written to the output */
6912 /* If this object has been written previously, then we ignore it. */
6914 for (optr
= *wrotelist
; optr
< *wrotelist
+ *written
; optr
++)
6915 if (*optr
== localdata
)
6918 /* If this page is a schematic, write out the definiton of any symbol */
6919 /* attached to it, because that symbol may not be used anywhere else. */
6921 if (localdata
->symschem
&& (localdata
->schemtype
== PRIMARY
))
6922 printobjects(ps
, localdata
->symschem
, wrotelist
, written
, curcolor
);
6924 /* Search for all object definitions instantiated in this object, */
6925 /* and (recursively) print them to the output. */
6927 for (gptr
= localdata
->plist
; gptr
< localdata
->plist
+ localdata
->parts
; gptr
++)
6928 if (IS_OBJINST(*gptr
))
6929 printobjects(ps
, TOOBJINST(gptr
)->thisobject
, wrotelist
, written
, curcolor
);
6931 /* Update the list of objects already written to the output */
6933 *wrotelist
= (objectptr
*)realloc(*wrotelist
, (*written
+ 1) *
6935 *(*wrotelist
+ *written
) = localdata
;
6938 validname
= create_valid_psname(localdata
->name
, FALSE
);
6939 if (strstr(validname
, "::") == NULL
)
6940 fprintf(ps
, "/::%s {\n", validname
);
6942 fprintf(ps
, "/%s {\n", validname
);
6944 /* Write a "bbox" record if there is an element with style FIXEDBBOX */
6945 /* This is the only time a "bbox" record is written for an object. */
6947 for (savegen
= localdata
->plist
; savegen
< localdata
->plist
+
6948 localdata
->parts
; savegen
++) {
6949 if (ELEMENTTYPE(*savegen
) == POLYGON
) {
6950 if (TOPOLY(savegen
)->style
& FIXEDBBOX
) {
6951 pointlist polypoints
;
6953 polypoints
= TOPOLY(savegen
)->points
+ 2;
6954 width
= polypoints
->x
;
6955 height
= polypoints
->y
;
6956 polypoints
= TOPOLY(savegen
)->points
;
6957 width
-= polypoints
->x
;
6958 height
-= polypoints
->y
;
6959 fprintf(ps
, "%% %d %d %d %d bbox\n",
6960 polypoints
->x
, polypoints
->y
,
6967 if (localdata
->hidden
== True
) fprintf(ps
, "%% hidden\n");
6969 /* For symbols with schematics, and "trivial" schematics */
6970 if (localdata
->symschem
!= NULL
)
6971 fprintf(ps
, "%% %s is_schematic\n", localdata
->symschem
->name
);
6972 else if (localdata
->schemtype
== TRIVIAL
)
6973 fprintf(ps
, "%% trivial\n");
6974 else if (localdata
->schemtype
== NONETWORK
)
6975 fprintf(ps
, "%% nonetwork\n");
6977 printobjectparams(ps
, localdata
);
6978 fprintf(ps
, "begingate\n");
6980 /* Write all the elements in order */
6982 opsubstitute(localdata
, NULL
);
6983 printOneObject(ps
, localdata
, curcolor
);
6985 /* Write object (gate) trailer */
6987 fprintf(ps
, "endgate\n} def\n\n");
6990 /*--------------------------------------------------------------*/
6991 /* Print a page header followed by everything in the page. */
6992 /* this routine assumes that all objects used by the page have */
6993 /* already been handled and written to the output. */
6995 /* "page" is the page number, counting consecutively from one. */
6996 /* "mpage" is the page number in xcircuit's pagelist structure. */
6997 /*--------------------------------------------------------------*/
6999 void printpageobject(FILE *ps
, objectptr localdata
, short page
, short mpage
)
7001 /* genericptr *gptr; (jdk) */
7002 XPoint origin
, corner
;
7003 objinstptr writepage
;
7005 float psnorm
, psscale
;
7006 float xmargin
, ymargin
;
7007 char *rootptr
= NULL
;
7010 /* Output page header information */
7012 if (xobjs
.pagelist
[mpage
]->filename
)
7013 rootptr
= strrchr(xobjs
.pagelist
[mpage
]->filename
, '/');
7014 if (rootptr
== NULL
)
7015 rootptr
= xobjs
.pagelist
[mpage
]->filename
;
7018 writepage
= xobjs
.pagelist
[mpage
]->pageinst
;
7020 psnorm
= xobjs
.pagelist
[mpage
]->outscale
;
7021 psscale
= getpsscale(psnorm
, mpage
);
7023 /* Determine the margins (offset of drawing from page corner) */
7024 /* If a bounding box has been declared in the drawing, it is */
7025 /* centered on the page. Otherwise, the drawing itself is */
7026 /* centered on the page. If encapsulated, the bounding box */
7027 /* encompasses only the object itself. */
7029 width
= toplevelwidth(writepage
, &origin
.x
);
7030 height
= toplevelheight(writepage
, &origin
.y
);
7032 corner
.x
= origin
.x
+ width
;
7033 corner
.y
= origin
.y
+ height
;
7035 if (xobjs
.pagelist
[mpage
]->pmode
& 1) { /* full page */
7037 if (xobjs
.pagelist
[mpage
]->orient
== 90) {
7038 xmargin
= (xobjs
.pagelist
[mpage
]->pagesize
.x
-
7039 ((float)height
* psscale
)) / 2;
7040 ymargin
= (xobjs
.pagelist
[mpage
]->pagesize
.y
-
7041 ((float)width
* psscale
)) / 2;
7044 xmargin
= (xobjs
.pagelist
[mpage
]->pagesize
.x
-
7045 ((float)width
* psscale
)) / 2;
7046 ymargin
= (xobjs
.pagelist
[mpage
]->pagesize
.y
-
7047 ((float)height
* psscale
)) / 2;
7050 else { /* encapsulated --- should have 1" border so that any */
7051 /* drawing passed directly to a printer will not clip */
7052 xmargin
= xobjs
.pagelist
[mpage
]->margins
.x
;
7053 ymargin
= xobjs
.pagelist
[mpage
]->margins
.y
;
7056 /* If a framebox is declared, then we adjust the page to be */
7057 /* centered on the framebox by translating through the */
7058 /* difference between the object center and the framebox */
7061 if ((framebox
= checkforbbox(localdata
)) != NULL
) {
7062 int i
, fcentx
= 0, fcenty
= 0;
7064 for (i
= 0; i
< framebox
->number
; i
++) {
7065 fcentx
+= framebox
->points
[i
].x
;
7066 fcenty
+= framebox
->points
[i
].y
;
7068 fcentx
/= framebox
->number
;
7069 fcenty
/= framebox
->number
;
7071 xmargin
+= psscale
* (float)(origin
.x
+ (width
>> 1) - fcentx
);
7072 ymargin
+= psscale
* (float)(origin
.y
+ (height
>> 1) - fcenty
);
7075 /* If the page label is just the root name of the file, or has been left */
7076 /* as "Page n" or "Page_n", just do the normal page numbering. Otherwise, */
7077 /* write out the page label explicitly. */
7079 if ((rootptr
== NULL
) || (!strcmp(rootptr
, localdata
->name
))
7080 || (strchr(localdata
->name
, ' ') != NULL
)
7081 || (strstr(localdata
->name
, "Page_") != NULL
))
7082 fprintf (ps
, "%%%%Page: %d %d\n", page
, page
);
7084 fprintf (ps
, "%%%%Page: %s %d\n", localdata
->name
, page
);
7086 if (xobjs
.pagelist
[mpage
]->orient
== 90)
7087 fprintf (ps
, "%%%%PageOrientation: Landscape\n");
7089 fprintf (ps
, "%%%%PageOrientation: Portrait\n");
7091 if (xobjs
.pagelist
[mpage
]->pmode
& 1) { /* full page */
7092 fprintf(ps
, "%%%%PageBoundingBox: 0 0 %d %d\n",
7093 xobjs
.pagelist
[mpage
]->pagesize
.x
,
7094 xobjs
.pagelist
[mpage
]->pagesize
.y
);
7097 /* Encapsulated files do not get a PageBoundingBox line, */
7098 /* unless the bounding box was explicitly drawn. */
7100 else if (framebox
!= NULL
) {
7101 fprintf(ps
, "%%%%PageBoundingBox: %g %g %g %g\n",
7103 xmargin
+ psscale
* (float)(width
),
7104 ymargin
+ psscale
* (float)(height
));
7107 fprintf (ps
, "/pgsave save def bop\n");
7109 /* Top-page definitions */
7110 if (localdata
->params
!= NULL
) {
7111 printobjectparams(ps
, localdata
);
7112 fprintf(ps
, "begin\n");
7115 if (localdata
->symschem
!= NULL
) {
7116 if (is_page(localdata
->symschem
) == -1)
7117 fprintf(ps
, "%% %s is_symbol\n", localdata
->symschem
->name
);
7118 else if (localdata
->schemtype
== SECONDARY
)
7119 fprintf(ps
, "%% %s is_primary\n", localdata
->symschem
->name
);
7121 Wprintf("Something is wrong. . . schematic \"%s\" is connected to"
7122 " schematic \"%s\" but is not declared secondary.\n",
7123 localdata
->name
, localdata
->symschem
->name
);
7126 /* Extend bounding box around schematic pins */
7127 extendschembbox(xobjs
.pagelist
[mpage
]->pageinst
, &origin
, &corner
);
7129 if (xobjs
.pagelist
[mpage
]->drawingscale
.x
!= 1
7130 || xobjs
.pagelist
[mpage
]->drawingscale
.y
!= 1)
7131 fprintf(ps
, "%% %hd:%hd drawingscale\n", xobjs
.pagelist
[mpage
]->drawingscale
.x
,
7132 xobjs
.pagelist
[mpage
]->drawingscale
.y
);
7134 if (xobjs
.pagelist
[mpage
]->gridspace
!= 32
7135 || xobjs
.pagelist
[mpage
]->snapspace
!= 16)
7136 fprintf(ps
, "%% %4.2f %4.2f gridspace\n", xobjs
.pagelist
[mpage
]->gridspace
,
7137 xobjs
.pagelist
[mpage
]->snapspace
);
7139 if (xobjs
.pagelist
[mpage
]->background
.name
!= (char *)NULL
) {
7140 /* float iscale = (xobjs.pagelist[mpage]->coordstyle == CM) ? CMSCALE : INCHSCALE; (jdk) */
7141 if (xobjs
.pagelist
[mpage
]->orient
== 90)
7142 fprintf(ps
, "%5.4f %d %d 90 psinsertion\n", psnorm
,
7143 (int)(ymargin
- xmargin
),
7144 -((int)((float)(corner
.y
- origin
.y
) * psscale
) +
7145 (int)(xmargin
+ ymargin
)));
7147 fprintf(ps
, "%5.4f %d %d 0 psinsertion\n", psnorm
,
7148 (int)(xmargin
/ psscale
) - origin
.x
,
7149 (int)(ymargin
/ psscale
) - origin
.y
);
7150 savebackground(ps
, xobjs
.pagelist
[mpage
]->background
.name
);
7151 fprintf(ps
, "\nend_insert\n");
7154 if (xobjs
.pagelist
[mpage
]->orient
== 90)
7155 fprintf(ps
, "90 rotate %d %d translate\n", (int)(ymargin
- xmargin
),
7156 -((int)((float)(corner
.y
- origin
.y
) * psscale
) +
7157 (int)(xmargin
+ ymargin
)));
7159 fprintf(ps
, "%5.4f ", psnorm
);
7160 switch(xobjs
.pagelist
[mpage
]->coordstyle
) {
7162 fprintf(ps
, "cmscale\n");
7165 fprintf(ps
, "inchscale\n");
7169 /* Final scale and translation */
7170 fprintf(ps
, "%5.4f setlinewidth %d %d translate\n\n",
7171 1.3 * xobjs
.pagelist
[mpage
]->wirewidth
,
7172 (int)(xmargin
/ psscale
) - origin
.x
,
7173 (int)(ymargin
/ psscale
) - origin
.y
);
7175 /* Output all the elements in the page */
7176 printOneObject(ps
, localdata
, DEFAULTCOLOR
);
7179 if (localdata
->params
!= NULL
) fprintf(ps
, "end ");
7180 fprintf(ps
, "pgsave restore showpage\n");
7183 /*--------------------------------------------------------------*/
7184 /* Print objects referenced from a particular page. These get */
7185 /* bundled together at the beginning of the output file under */
7186 /* the DSC "Setup" section, so that the PostScript */
7187 /* interpreter knows that these definitions may be used by any */
7188 /* page. This prevents ghostscript from producing an error */
7189 /* when backing up in a multi-page document. */
7190 /*--------------------------------------------------------------*/
7192 void printrefobjects(FILE *ps
, objectptr localdata
, objectptr
**wrotelist
,
7197 /* If this page is a schematic, write out the definiton of any symbol */
7198 /* attached to it, because that symbol may not be used anywhere else. */
7200 if (localdata
->symschem
&& (localdata
->schemtype
== PRIMARY
))
7201 printobjects(ps
, localdata
->symschem
, wrotelist
, written
, DEFAULTCOLOR
);
7203 /* Search for all object definitions instantiated on the page and */
7204 /* write them to the output. */
7206 for (gptr
= localdata
->plist
; gptr
< localdata
->plist
+ localdata
->parts
; gptr
++)
7207 if (IS_OBJINST(*gptr
))
7208 printobjects(ps
, TOOBJINST(gptr
)->thisobject
, wrotelist
, written
,
7212 /*----------------------------------------------------------------------*/