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")) {
3997 NEW_ARC(newarc
, (*newpath
));
3998 (*newarc
)->width
= 1.0;
3999 (*newarc
)->style
= UNCLOSED
;
4000 (*newarc
)->color
= curcolor
;
4001 (*newarc
)->passed
= NULL
;
4002 (*newarc
)->cycle
= NULL
;
4004 lineptr
= varpscan(localdata
, buffer
, &(*newarc
)->position
.x
,
4005 (genericptr
)*newarc
, 0, offx
, P_POSITION_X
);
4006 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.y
,
4007 (genericptr
)*newarc
, 0, offy
, P_POSITION_Y
);
4008 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->radius
,
4009 (genericptr
)*newarc
, P_RADIUS
);
4010 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle1
,
4011 (genericptr
)*newarc
, P_ANGLE1
);
4012 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle2
,
4013 (genericptr
)*newarc
, P_ANGLE2
);
4015 (*newarc
)->yaxis
= (*newarc
)->radius
;
4016 if (!strcmp(keyword
, "arcn")) {
4017 float tmpang
= (*newarc
)->angle1
;
4018 (*newarc
)->radius
= -((*newarc
)->radius
);
4019 (*newarc
)->angle1
= (*newarc
)->angle2
;
4020 (*newarc
)->angle2
= tmpang
;
4024 startpoint
.x
= (short)(*newarc
)->points
[(*newarc
)->number
- 1].x
;
4025 startpoint
.y
= (short)(*newarc
)->points
[(*newarc
)->number
- 1].y
;
4026 decomposearc(*newpath
);
4029 else if (!strcmp(keyword
, "pellip") || !strcmp(keyword
, "nellip")) {
4031 NEW_ARC(newarc
, (*newpath
));
4032 (*newarc
)->width
= 1.0;
4033 (*newarc
)->style
= UNCLOSED
;
4034 (*newarc
)->color
= curcolor
;
4035 (*newarc
)->passed
= NULL
;
4036 (*newarc
)->cycle
= NULL
;
4038 lineptr
= varpscan(localdata
, buffer
, &(*newarc
)->position
.x
,
4039 (genericptr
)*newarc
, 0, offx
, P_POSITION_X
);
4040 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.y
,
4041 (genericptr
)*newarc
, 0, offy
, P_POSITION_Y
);
4042 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->radius
,
4043 (genericptr
)*newarc
, P_RADIUS
);
4044 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->yaxis
,
4045 (genericptr
)*newarc
, P_MINOR_AXIS
);
4046 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle1
,
4047 (genericptr
)*newarc
, P_ANGLE1
);
4048 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle2
,
4049 (genericptr
)*newarc
, P_ANGLE2
);
4051 if (!strcmp(keyword
, "nellip")) {
4052 float tmpang
= (*newarc
)->angle1
;
4053 (*newarc
)->radius
= -((*newarc
)->radius
);
4054 (*newarc
)->angle1
= (*newarc
)->angle2
;
4055 (*newarc
)->angle2
= tmpang
;
4059 startpoint
.x
= (short)(*newarc
)->points
[(*newarc
)->number
- 1].x
;
4060 startpoint
.y
= (short)(*newarc
)->points
[(*newarc
)->number
- 1].y
;
4061 decomposearc(*newpath
);
4064 else if (!strcmp(keyword
, "curveto")) {
4065 splineptr
*newspline
;
4068 NEW_SPLINE(newspline
, (*newpath
));
4069 (*newspline
)->passed
= NULL
;
4070 (*newspline
)->cycle
= NULL
;
4071 (*newspline
)->width
= 1.0;
4072 (*newspline
)->style
= UNCLOSED
;
4073 (*newspline
)->color
= curcolor
;
4075 /* If the last point on the last path part was parameterized, then */
4076 /* the first point of the spline must be, too. */
4078 if (epptrx
!= NULL
) {
4079 eparamptr newepp
= copyeparam(epptrx
, (genericptr
)(*newpath
));
4080 newepp
->next
= (*newpath
)->passed
;
4081 (*newpath
)->passed
= newepp
;
4082 newepp
->pdata
.pathpt
[1] = 0;
4083 newepp
->pdata
.pathpt
[0] = (*newpath
)->parts
- 1;
4085 if (epptry
!= NULL
) {
4086 eparamptr newepp
= copyeparam(epptry
, (genericptr
)(*newpath
));
4087 newepp
->next
= (*newpath
)->passed
;
4088 (*newpath
)->passed
= newepp
;
4089 newepp
->pdata
.pathpt
[1] = 0;
4090 newepp
->pdata
.pathpt
[0] = (*newpath
)->parts
- 1;
4093 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4094 for (; *keyptr
!= ' '; keyptr
--);
4096 /* check for "addtox" and "addtoy" parameter specification */
4097 while (!strncmp(keyptr
+ 1, "addto", 5)) {
4098 saveptr
= keyptr
+ 1;
4100 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4101 for (; *keyptr
!= ' '; keyptr
--);
4103 /* Get parameter and its value */
4104 if (*(saveptr
+ 5) == 'x')
4105 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newspline
,
4106 -1, offx
, P_POSITION_X
);
4108 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newspline
,
4109 -1, offy
, P_POSITION_Y
);
4111 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4112 for (; *keyptr
!= ' '; keyptr
--);
4116 lineptr
= varpathscan(localdata
, buffer
, &(*newspline
)->ctrl
[1].x
,
4117 (genericptr
*)newspline
, *newpath
, 1, offx
+ px
, P_POSITION_X
,
4119 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[1].y
,
4120 (genericptr
*)newspline
, *newpath
, 1, offy
+ py
, P_POSITION_Y
,
4122 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[2].x
,
4123 (genericptr
*)newspline
, *newpath
, 2, offx
+ px
, P_POSITION_X
,
4125 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[2].y
,
4126 (genericptr
*)newspline
, *newpath
, 2, offy
+ py
, P_POSITION_Y
,
4128 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[3].x
,
4129 (genericptr
*)newspline
, *newpath
, 3, offx
+ px
, P_POSITION_X
,
4131 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[3].y
,
4132 (genericptr
*)newspline
, *newpath
, 3, offy
+ py
, P_POSITION_Y
,
4135 (*newspline
)->ctrl
[0].x
= startpoint
.x
;
4136 (*newspline
)->ctrl
[0].y
= startpoint
.y
;
4138 calcspline(*newspline
);
4139 startpoint
.x
= (*newspline
)->ctrl
[3].x
;
4140 startpoint
.y
= (*newspline
)->ctrl
[3].y
;
4145 else if (!strcmp(keyword
, "xcarc")) {
4148 NEW_ARC(newarc
, localdata
);
4149 (*newarc
)->color
= curcolor
;
4150 (*newarc
)->passed
= NULL
;
4151 (*newarc
)->cycle
= NULL
;
4153 /* backward compatibility */
4154 if (compare_version(version
, "1.5") < 0) {
4155 sscanf(buffer
, "%hd %hd %hd %f %f %f %hd", &(*newarc
)->position
.x
,
4156 &(*newarc
)->position
.y
, &(*newarc
)->radius
, &(*newarc
)->angle1
,
4157 &(*newarc
)->angle2
, &(*newarc
)->width
, &(*newarc
)->style
);
4158 (*newarc
)->position
.x
-= offx
;
4159 (*newarc
)->position
.y
-= offy
;
4162 lineptr
= varscan(localdata
, buffer
, &(*newarc
)->style
,
4163 (genericptr
)*newarc
, P_STYLE
);
4164 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->width
,
4165 (genericptr
)*newarc
, P_LINEWIDTH
);
4166 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.x
,
4167 (genericptr
)*newarc
, 0, offx
, P_POSITION_X
);
4168 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.y
,
4169 (genericptr
)*newarc
, 0, offy
, P_POSITION_Y
);
4170 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->radius
,
4171 (genericptr
)*newarc
, P_RADIUS
);
4172 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle1
,
4173 (genericptr
)*newarc
, P_ANGLE1
);
4174 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle2
,
4175 (genericptr
)*newarc
, P_ANGLE2
);
4178 (*newarc
)->yaxis
= (*newarc
)->radius
;
4180 std_eparam((genericptr
)(*newarc
), colorkey
);
4185 else if (!strcmp(keyword
, "ellipse")) {
4188 NEW_ARC(newarc
, localdata
);
4190 (*newarc
)->color
= curcolor
;
4191 (*newarc
)->passed
= NULL
;
4192 (*newarc
)->cycle
= NULL
;
4194 lineptr
= varscan(localdata
, buffer
, &(*newarc
)->style
,
4195 (genericptr
)*newarc
, P_STYLE
);
4196 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->width
,
4197 (genericptr
)*newarc
, P_LINEWIDTH
);
4198 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.x
,
4199 (genericptr
)*newarc
, 0, offx
, P_POSITION_X
);
4200 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.y
,
4201 (genericptr
)*newarc
, 0, offy
, P_POSITION_Y
);
4202 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->radius
,
4203 (genericptr
)*newarc
, P_RADIUS
);
4204 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->yaxis
,
4205 (genericptr
)*newarc
, P_MINOR_AXIS
);
4206 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle1
,
4207 (genericptr
)*newarc
, P_ANGLE1
);
4208 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle2
,
4209 (genericptr
)*newarc
, P_ANGLE2
);
4212 std_eparam((genericptr
)(*newarc
), colorkey
);
4216 /* (and wires---backward compatibility for v1.5 and earlier) */
4218 else if (!strcmp(keyword
, "polygon") || !strcmp(keyword
, "wire")) {
4220 pointlist newpoints
;
4223 NEW_POLY(newpoly
, localdata
);
4226 (*newpoly
)->passed
= NULL
;
4227 (*newpoly
)->cycle
= NULL
;
4229 if (!strcmp(keyword
, "wire")) {
4230 (*newpoly
)->number
= 2;
4231 (*newpoly
)->width
= 1.0;
4232 (*newpoly
)->style
= UNCLOSED
;
4235 /* backward compatibility */
4236 if (compare_version(version
, "1.5") < 0) {
4237 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4238 for (; *keyptr
!= ' '; keyptr
--);
4239 sscanf(keyptr
, "%hd", &(*newpoly
)->style
);
4240 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4241 for (; *keyptr
!= ' '; keyptr
--);
4242 sscanf(keyptr
, "%f", &(*newpoly
)->width
);
4244 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4245 for (; *keyptr
!= ' '; keyptr
--);
4246 /* check for "addtox" and "addtoy" parameter specification */
4247 while (!strncmp(keyptr
+ 1, "addto", 5)) {
4248 saveptr
= keyptr
+ 1;
4250 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4251 for (; *keyptr
!= ' '; keyptr
--);
4253 /* Get parameter and its value */
4254 if (*(saveptr
+ 5) == 'x')
4255 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newpoly
,
4256 -1, offx
, P_POSITION_X
);
4258 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newpoly
,
4259 -1, offy
, P_POSITION_Y
);
4261 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4262 for (; *keyptr
!= ' '; keyptr
--);
4264 sscanf(keyptr
, "%hd", &(*newpoly
)->number
);
4266 if (compare_version(version
, "1.5") >= 0) {
4267 lineptr
= varscan(localdata
, lineptr
, &(*newpoly
)->style
,
4268 (genericptr
)*newpoly
, P_STYLE
);
4269 lineptr
= varfscan(localdata
, lineptr
, &(*newpoly
)->width
,
4270 (genericptr
)*newpoly
, P_LINEWIDTH
);
4274 if ((*newpoly
)->style
& BBOX
)
4275 (*newpoly
)->color
= BBOXCOLOR
;
4277 (*newpoly
)->color
= curcolor
;
4278 (*newpoly
)->points
= (pointlist
) malloc((*newpoly
)->number
*
4281 for (newpoints
= (*newpoly
)->points
; newpoints
< (*newpoly
)->points
4282 + (*newpoly
)->number
; newpoints
++) {
4283 lineptr
= varpscan(localdata
, lineptr
, &newpoints
->x
,
4284 (genericptr
)*newpoly
, newpoints
- (*newpoly
)->points
,
4285 offx
+ px
, P_POSITION_X
);
4286 lineptr
= varpscan(localdata
, lineptr
, &newpoints
->y
,
4287 (genericptr
)*newpoly
, newpoints
- (*newpoly
)->points
,
4288 offy
+ py
, P_POSITION_Y
);
4290 std_eparam((genericptr
)(*newpoly
), colorkey
);
4293 /* read spline curves */
4295 else if (!strcmp(keyword
, "spline")) {
4296 splineptr
*newspline
;
4299 NEW_SPLINE(newspline
, localdata
);
4300 (*newspline
)->color
= curcolor
;
4301 (*newspline
)->passed
= NULL
;
4302 (*newspline
)->cycle
= NULL
;
4304 /* backward compatibility */
4305 if (compare_version(version
, "1.5") < 0) {
4306 sscanf(buffer
, "%f %hd %hd %hd %hd %hd %hd %hd %hd %hd",
4307 &(*newspline
)->width
, &(*newspline
)->ctrl
[1].x
,
4308 &(*newspline
)->ctrl
[1].y
, &(*newspline
)->ctrl
[2].x
,
4309 &(*newspline
)->ctrl
[2].y
, &(*newspline
)->ctrl
[3].x
,
4310 &(*newspline
)->ctrl
[3].y
, &(*newspline
)->ctrl
[0].x
,
4311 &(*newspline
)->ctrl
[0].y
, &(*newspline
)->style
);
4312 (*newspline
)->ctrl
[1].x
-= offx
; (*newspline
)->ctrl
[2].x
-= offx
;
4313 (*newspline
)->ctrl
[0].x
-= offx
;
4314 (*newspline
)->ctrl
[3].x
-= offx
;
4315 (*newspline
)->ctrl
[1].y
-= offy
; (*newspline
)->ctrl
[2].y
-= offy
;
4316 (*newspline
)->ctrl
[3].y
-= offy
;
4317 (*newspline
)->ctrl
[0].y
-= offy
;
4321 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4322 for (; *keyptr
!= ' '; keyptr
--);
4323 /* check for "addtox" and "addtoy" parameter specification */
4324 while (!strncmp(keyptr
+ 1, "addto", 5)) {
4325 saveptr
= keyptr
+ 1;
4327 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4328 for (; *keyptr
!= ' '; keyptr
--);
4330 /* Get parameter and its value */
4331 if (*(saveptr
+ 5) == 'x')
4332 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newspline
,
4333 -1, offx
, P_POSITION_X
);
4335 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newspline
,
4336 -1, offy
, P_POSITION_Y
);
4338 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4339 for (; *keyptr
!= ' '; keyptr
--);
4342 lineptr
= varscan(localdata
, buffer
, &(*newspline
)->style
,
4343 (genericptr
)*newspline
, P_STYLE
);
4344 lineptr
= varfscan(localdata
, lineptr
, &(*newspline
)->width
,
4345 (genericptr
)*newspline
, P_LINEWIDTH
);
4346 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[1].x
,
4347 (genericptr
)*newspline
, 1, offx
+ px
, P_POSITION_X
);
4348 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[1].y
,
4349 (genericptr
)*newspline
, 1, offy
+ py
, P_POSITION_Y
);
4350 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[2].x
,
4351 (genericptr
)*newspline
, 2, offx
+ px
, P_POSITION_X
);
4352 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[2].y
,
4353 (genericptr
)*newspline
, 2, offy
+ py
, P_POSITION_Y
);
4354 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[3].x
,
4355 (genericptr
)*newspline
, 3, offx
+ px
, P_POSITION_X
);
4356 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[3].y
,
4357 (genericptr
)*newspline
, 3, offy
+ py
, P_POSITION_Y
);
4358 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[0].x
,
4359 (genericptr
)*newspline
, 0, offx
+ px
, P_POSITION_X
);
4360 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[0].y
,
4361 (genericptr
)*newspline
, 0, offy
+ py
, P_POSITION_Y
);
4363 /* check for "addtox" and "addtoy" parameter specification */
4366 calcspline(*newspline
);
4367 std_eparam((genericptr
)(*newspline
), colorkey
);
4370 /* read graphics image instances */
4372 else if (!strcmp(keyword
, "graphic")) {
4376 lineptr
= buffer
+ 1;
4377 for (i
= 0; i
< xobjs
.images
; i
++) {
4378 img
= xobjs
.imagelist
+ i
;
4379 if (!strncmp(img
->filename
, lineptr
, strlen(img
->filename
))) {
4380 NEW_GRAPHIC(newgp
, localdata
);
4381 (*newgp
)->color
= curcolor
;
4382 (*newgp
)->passed
= NULL
;
4384 (*newgp
)->clipmask
= (Pixmap
)NULL
;
4385 (*newgp
)->target
= NULL
;
4386 (*newgp
)->valid
= False
;
4387 #endif /* HAVE_CAIRO */
4388 (*newgp
)->source
= img
->image
;
4390 lineptr
+= strlen(img
->filename
) + 1;
4394 if (i
== xobjs
.images
) {
4395 /* Error: Line points to a non-existant image (no data) */
4396 /* See if we can load the image name as a filename, and */
4397 /* if that fails, then we must throw an error and ignore */
4398 /* the image element. */
4401 char *sptr
= strchr(lineptr
, ' ');
4407 locgp
= new_graphic(NULL
, lineptr
, 0, 0);
4409 if (locgp
== NULL
) {
4410 Fprintf(stderr
, "Error: No graphic data for \"%s\".\n",
4420 if ((newgp
!= NULL
) && (*newgp
!= NULL
)) {
4421 lineptr
= varfscan(localdata
, lineptr
, &(*newgp
)->scale
,
4422 (genericptr
)*newgp
, P_SCALE
);
4423 lineptr
= varfscan(localdata
, lineptr
, &(*newgp
)->rotation
,
4424 (genericptr
)*newgp
, P_ROTATION
);
4425 lineptr
= varpscan(localdata
, lineptr
, &(*newgp
)->position
.x
,
4426 (genericptr
)*newgp
, 0, offx
, P_POSITION_X
);
4427 lineptr
= varpscan(localdata
, lineptr
, &(*newgp
)->position
.y
,
4428 (genericptr
)*newgp
, 0, offy
, P_POSITION_Y
);
4429 std_eparam((genericptr
)(*newgp
), colorkey
);
4435 else if (!strcmp(keyword
, "fontset")) { /* old style */
4436 char tmpstring
[100];
4438 sscanf(buffer
, "%f %*c%99s", &tmpscale
, tmpstring
);
4439 for (i
= 0; i
< fontcount
; i
++)
4440 if (!strcmp(tmpstring
, fonts
[i
].psname
)) {
4444 if (i
== fontcount
) i
= 0; /* Why bother with anything fancy? */
4447 else if (!strcmp(keyword
, "label") || !strcmp(keyword
, "pinlabel")
4448 || !strcmp(keyword
, "pinglobal") || !strcmp(keyword
, "infolabel")) {
4451 stringpart
*firstscale
, *firstfont
;
4453 NEW_LABEL(newlabel
, localdata
);
4454 (*newlabel
)->color
= curcolor
;
4455 (*newlabel
)->string
= NULL
;
4456 (*newlabel
)->passed
= NULL
;
4457 (*newlabel
)->cycle
= NULL
;
4459 /* scan backwards to get the number of substrings */
4460 lineptr
= keyptr
- 1;
4461 for (i
= 0; i
< ((compare_version(version
, "2.3") < 0) ? 5 : 6); i
++) {
4462 for (; *lineptr
== ' '; lineptr
--);
4463 for (; *lineptr
!= ' '; lineptr
--);
4465 if ((strchr(lineptr
, '.') != NULL
) && (compare_version(version
, "2.3") < 0)) {
4466 Fprintf(stderr
, "Error: File version claims to be %s,"
4467 " but has version %s labels\n", version
, PROG_VERSION
);
4468 Fprintf(stderr
, "Attempting to resolve problem by updating version.\n");
4469 strcpy(version
, PROG_VERSION
);
4470 for (; *lineptr
== ' '; lineptr
--);
4471 for (; *lineptr
!= ' '; lineptr
--);
4473 /* no. segments is ignored---may be a derived quantity, anyway */
4474 if (compare_version(version
, "2.3") < 0) {
4475 sscanf(lineptr
, "%*s %hd %hf %hd %hd", &(*newlabel
)->anchor
,
4476 &(*newlabel
)->rotation
, &(*newlabel
)->position
.x
,
4477 &(*newlabel
)->position
.y
);
4478 (*newlabel
)->position
.x
-= offx
; (*newlabel
)->position
.y
-= offy
;
4483 lineptr
= advancetoken(lineptr
); /* skip string token */
4484 lineptr
= varscan(localdata
, lineptr
, &(*newlabel
)->anchor
,
4485 (genericptr
)*newlabel
, P_ANCHOR
);
4486 lineptr
= varfscan(localdata
, lineptr
, &(*newlabel
)->rotation
,
4487 (genericptr
)*newlabel
, P_ROTATION
);
4488 lineptr
= varfscan(localdata
, lineptr
, &(*newlabel
)->scale
,
4489 (genericptr
)*newlabel
, P_SCALE
);
4490 lineptr
= varpscan(localdata
, lineptr
, &(*newlabel
)->position
.x
,
4491 (genericptr
)*newlabel
, 0, offx
, P_POSITION_X
);
4492 lineptr
= varpscan(localdata
, lineptr
, &(*newlabel
)->position
.y
,
4493 (genericptr
)*newlabel
, 0, offy
, P_POSITION_Y
);
4495 if (compare_version(version
, "2.4") < 0)
4496 (*newlabel
)->rotation
= -(*newlabel
)->rotation
;
4497 while ((*newlabel
)->rotation
< 0.0) (*newlabel
)->rotation
+= 360.0;
4499 (*newlabel
)->pin
= False
;
4500 if (strcmp(keyword
, "label")) { /* all the schematic types */
4501 /* enable schematic capture if it is not already on. */
4502 if (!strcmp(keyword
, "pinlabel"))
4503 (*newlabel
)->pin
= LOCAL
;
4504 else if (!strcmp(keyword
, "pinglobal"))
4505 (*newlabel
)->pin
= GLOBAL
;
4506 else if (!strcmp(keyword
, "infolabel")) {
4507 /* Do not turn top-level pages into symbols! */
4508 /* Info labels on schematics are treated differently. */
4509 if (localdata
!= topobject
)
4510 localdata
->schemtype
= FUNDAMENTAL
;
4511 (*newlabel
)->pin
= INFO
;
4512 if (curcolor
== DEFAULTCOLOR
)
4513 (*newlabel
)->color
= INFOLABELCOLOR
;
4517 lineptr
= buffer
; /* back to beginning of string */
4518 if (!strncmp(lineptr
, "mark", 4)) lineptr
+= 4;
4520 readlabel(localdata
, lineptr
, &(*newlabel
)->string
);
4521 CheckMarginStop(*newlabel
, areawin
->topinstance
, FALSE
);
4523 if (compare_version(version
, "2.3") < 0) {
4524 /* Switch 1st scale designator to overall font scale */
4526 firstscale
= (*newlabel
)->string
->nextpart
;
4527 if (firstscale
->type
!= FONT_SCALE
) {
4528 if (tmpscale
!= 0.0)
4529 (*newlabel
)->scale
= 0.0;
4531 (*newlabel
)->scale
= 1.0;
4534 (*newlabel
)->scale
= firstscale
->data
.scale
;
4535 deletestring(firstscale
, &((*newlabel
)->string
),
4536 areawin
->topinstance
);
4540 firstfont
= (*newlabel
)->string
;
4541 if ((firstfont
== NULL
) || (firstfont
->type
!= FONT_NAME
)) {
4542 if (tmpfont
== -1) {
4543 Fprintf(stderr
, "Error: Label with no font designator?\n");
4546 firstfont
= makesegment(&((*newlabel
)->string
), (*newlabel
)->string
);
4547 firstfont
->type
= FONT_NAME
;
4548 firstfont
->data
.font
= tmpfont
;
4550 cleanuplabel(&(*newlabel
)->string
);
4552 std_eparam((genericptr
)(*newlabel
), colorkey
);
4555 /* read symbol-to-schematic connection */
4557 else if (!strcmp(keyword
, "is_schematic")) {
4559 for (lineptr
= buffer
; *lineptr
== ' '; lineptr
++);
4560 parse_ps_string(++lineptr
, tempstr
, 49, FALSE
, FALSE
);
4561 checksym(localdata
, tempstr
);
4564 /* read bounding box (font files only) */
4566 else if (!strcmp(keyword
, "bbox")) {
4567 for (lineptr
= buffer
; *lineptr
== ' '; lineptr
++);
4568 if (*lineptr
!= '%') {
4569 Wprintf("Illegal bbox.");
4574 sscanf(++lineptr
, "%hd %hd %hd %hd",
4575 &localdata
->bbox
.lowerleft
.x
, &localdata
->bbox
.lowerleft
.y
,
4576 &localdata
->bbox
.width
, &localdata
->bbox
.height
);
4578 // If this is *not* a FONTLIB, then the font character symbols
4579 // are being edited as a normal library, so copy the bounding
4580 // box into a FIXEDBBOX-type box.
4582 if (mode
!= FONTLIB
) {
4584 pointlist newpoints
;
4586 NEW_POLY(newpoly
, localdata
);
4587 (*newpoly
)->passed
= NULL
;
4588 (*newpoly
)->cycle
= NULL
;
4589 (*newpoly
)->number
= 4;
4590 (*newpoly
)->width
= 1.0;
4591 (*newpoly
)->style
= FIXEDBBOX
;
4592 (*newpoly
)->color
= FIXEDBBOXCOLOR
;
4593 (*newpoly
)->points
= (pointlist
) malloc(4 * sizeof(XPoint
));
4594 newpoints
= (*newpoly
)->points
;
4595 newpoints
->x
= localdata
->bbox
.lowerleft
.x
;
4596 newpoints
->y
= localdata
->bbox
.lowerleft
.y
;
4598 newpoints
->x
= localdata
->bbox
.lowerleft
.x
+ localdata
->bbox
.width
;
4599 newpoints
->y
= localdata
->bbox
.lowerleft
.y
;
4601 newpoints
->x
= localdata
->bbox
.lowerleft
.x
+ localdata
->bbox
.width
;
4602 newpoints
->y
= localdata
->bbox
.lowerleft
.y
+ localdata
->bbox
.height
;
4604 newpoints
->x
= localdata
->bbox
.lowerleft
.x
;
4605 newpoints
->y
= localdata
->bbox
.lowerleft
.y
+ localdata
->bbox
.height
;
4606 std_eparam((genericptr
)(*newpoly
), colorkey
);
4610 /* read "hidden" attribute */
4612 else if (!strcmp(keyword
, "hidden")) {
4613 localdata
->hidden
= True
;
4616 /* read "libinst" special instance of a library part */
4618 else if (!strcmp(keyword
, "libinst")) {
4620 /* Read backwards from keyword to find name of object instanced. */
4621 for (lineptr
= keyptr
; *lineptr
!= '/' && lineptr
> buffer
;
4623 parse_ps_string(++lineptr
, keyword
, 79, FALSE
, FALSE
);
4624 new_library_instance(mode
- LIBRARY
, keyword
, buffer
, defaulttech
);
4629 else if (!strcmp(keyword
, "{")) { /* This is an object definition */
4631 objectptr
*newobject
;
4633 for (lineptr
= buffer
; *lineptr
== ' '; lineptr
++);
4634 if (*lineptr
++ != '/') {
4635 /* This may be part of a label. . . treat as a continuation line */
4636 temp
= continueline(&buffer
);
4639 parse_ps_string(lineptr
, keyword
, 79, FALSE
, FALSE
);
4641 newobject
= new_library_object(mode
, keyword
, &redef
, defaulttech
);
4643 if (objectread(ps
, *newobject
, 0, 0, mode
, retstr
, curcolor
,
4644 defaulttech
) == True
) {
4645 strncpy(retstr
, buffer
, 150);
4651 if (library_object_unique(mode
, *newobject
, redef
))
4652 add_object_to_library(mode
, *newobject
);
4655 else if (!strcmp(keyword
, "def")) {
4656 strncpy(retstr
, buffer
, 150);
4659 return False
; /* end of object def or end of object library */
4662 else if (!strcmp(keyword
, "loadfontencoding")) {
4663 /* Deprecated, but retained for backward compatibility. */
4664 /* Load from script, .xcircuitrc, or command line instead. */
4665 for (lineptr
= buffer
; *lineptr
!= '%'; lineptr
++);
4666 sscanf (lineptr
+ 1, "%149s", _STR
);
4667 if (*(lineptr
+ 1) != '%') loadfontfile(_STR
);
4669 else if (!strcmp(keyword
, "loadlibrary")) {
4670 /* Deprecated, but retained for backward compatibility */
4671 /* Load from script, .xcircuitrc, or command line instead. */
4674 for (lineptr
= buffer
; *lineptr
!= '%'; lineptr
++);
4675 sscanf (++lineptr
, "%149s", _STR
);
4676 while (isspace(*lineptr
)) lineptr
++;
4677 while (!isspace(*++lineptr
));
4678 while (isspace(*++lineptr
));
4679 if (sscanf (lineptr
, "%d", &ilib
) > 0) {
4680 while ((ilib
- 2 + LIBRARY
) > xobjs
.numlibs
) {
4681 tlib
= createlibrary(False
);
4682 if (tlib
!= xobjs
.numlibs
- 2 + LIBRARY
) {
4687 mode
= ilib
- 1 + LIBRARY
;
4691 else if (!strcmp(keyword
, "beginparm")) { /* parameterized object */
4693 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4694 for (; isdigit(*keyptr
) && (keyptr
>= buffer
); keyptr
--);
4695 sscanf(keyptr
, "%hd", &tmpnum
);
4697 while (isspace(*lineptr
)) lineptr
++;
4699 if (tmpnum
< 256) { /* read parameter defaults in order */
4700 stringpart
*newpart
;
4701 /* oparamptr newops; (jdk) */
4703 for (i
= 0; i
< tmpnum
; i
++) {
4706 newops
= (oparamptr
)malloc(sizeof(oparam
));
4707 newops
->next
= localdata
->params
;
4708 localdata
->params
= newops
;
4709 newops
->key
= (char *)malloc(6);
4710 sprintf(newops
->key
, "v%d", i
+ 1);
4712 if (*lineptr
== '(' || *lineptr
== '{') { /* type is XC_STRING */
4713 char *linetmp
, csave
;
4715 newops
->parameter
.string
= NULL
;
4717 /* get simple substring or set of substrings and commands */
4718 linetmp
= find_delimiter(lineptr
);
4719 csave
= *(++linetmp
);
4721 if (*lineptr
== '{') lineptr
++;
4722 readlabel(localdata
, lineptr
, &(newops
->parameter
.string
));
4724 /* Add the ending part to the parameter string */
4725 newpart
= makesegment(&(newops
->parameter
.string
), NULL
);
4726 newpart
->type
= PARAM_END
;
4727 newpart
->data
.string
= (u_char
*)NULL
;
4729 newops
->type
= (u_char
)XC_STRING
;
4730 newops
->which
= P_SUBSTRING
;
4731 /* Fprintf(stdout, "Parameter %d to object %s defaults "
4732 "to string \"%s\"\n", i + 1, localdata->name,
4733 ops->parameter.string); */
4736 while (isspace(*lineptr
)) lineptr
++;
4738 else { /* type is assumed to be XC_FLOAT */
4739 newops
->type
= (u_char
)XC_FLOAT
;
4740 sscanf(lineptr
, "%g", &newops
->parameter
.fvalue
);
4741 /* Fprintf(stdout, "Parameter %s to object %s defaults to "
4742 "value %g\n", newops->key, localdata->name,
4743 newops->parameter.fvalue); */
4744 lineptr
= advancetoken(lineptr
);
4749 else if (!strcmp(keyword
, "nonetwork")) {
4750 localdata
->valid
= True
;
4751 localdata
->schemtype
= NONETWORK
;
4753 else if (!strcmp(keyword
, "trivial")) {
4754 localdata
->schemtype
= TRIVIAL
;
4756 else if (!strcmp(keyword
, "begingate")) {
4757 localdata
->params
= NULL
;
4758 /* read dictionary of parameter key:value pairs */
4759 readparams(NULL
, NULL
, localdata
, buffer
);
4762 else if (!strcmp(keyword
, "%%Trailer")) break;
4763 else if (!strcmp(keyword
, "EndLib")) break;
4764 else if (!strcmp(keyword
, "restore")); /* handled at top */
4765 else if (!strcmp(keyword
, "grestore")); /* ignore */
4766 else if (!strcmp(keyword
, "endgate")); /* also ignore */
4767 else if (!strcmp(keyword
, "xyarray")); /* ignore for now */
4769 char *tmpptr
, *libobjname
, *objnamestart
;
4770 Boolean matchtech
, found
= False
;
4772 /* First, make sure this is not a general comment line */
4773 /* Return if we have a page boundary */
4774 /* Read an image if this is an imagedata line. */
4776 for (tmpptr
= buffer
; isspace(*tmpptr
); tmpptr
++);
4777 if (*tmpptr
== '%') {
4778 if (strstr(buffer
, "%%Page:") == tmpptr
) {
4779 strncpy(retstr
, buffer
, 150);
4784 else if (strstr(buffer
, "%imagedata") == tmpptr
) {
4786 sscanf(buffer
, "%*s %d %d", &width
, &height
);
4787 readimagedata(ps
, width
, height
);
4792 parse_ps_string(keyword
, keyword
, 79, FALSE
, FALSE
);
4793 matchtech
= (strstr(keyword
, "::") == NULL
) ? FALSE
: TRUE
;
4795 /* If the file contains a reference to a bare-word device */
4796 /* without a technology prefix, then it is probably an */
4797 /* older-version file. If this is the case, then the file */
4798 /* should define an unprefixed object, which will be given */
4799 /* a null prefix (just "::" by itself). Look for that */
4802 /* (Assume that this line calls an object instance) */
4803 /* Double loop through user libraries */
4805 for (k
= 0; k
< ((mode
== FONTLIB
) ? 1 : xobjs
.numlibs
); k
++) {
4806 for (j
= 0; j
< ((mode
== FONTLIB
) ? xobjs
.fontlib
.number
:
4807 xobjs
.userlibs
[k
].number
); j
++) {
4809 libobj
= (mode
== FONTLIB
) ? xobjs
.fontlib
.library
+ j
:
4810 xobjs
.userlibs
[k
].library
+ j
;
4812 /* Objects which have a technology ("<lib>::<obj>") */
4813 /* must compare exactly. Objects which don't can */
4814 /* only match an object of the same name with a null */
4815 /* technology prefix. */
4817 libobjname
= (*libobj
)->name
;
4819 objnamestart
= strstr(libobjname
, "::");
4820 if (objnamestart
!= NULL
) libobjname
= objnamestart
+ 2;
4822 if (!objnamecmp(keyword
, libobjname
)) {
4824 /* If the name is not exactly the same (appended underscores) */
4825 /* check if the name is on the list of aliases. */
4827 if (strcmp(keyword
, libobjname
)) {
4828 Boolean is_alias
= False
;
4829 aliasptr ckalias
= aliastop
;
4832 for (; ckalias
!= NULL
; ckalias
= ckalias
->next
) {
4833 if (ckalias
->baseobj
== (*libobj
)) {
4834 sref
= ckalias
->aliases
;
4835 for (; sref
!= NULL
; sref
= sref
->next
) {
4836 if (!strcmp(keyword
, sref
->alias
)) {
4841 if (is_alias
) break;
4844 if (!is_alias
) continue;
4847 if (!matchtech
&& ((*libobj
)->name
!= objnamestart
))
4848 if (compare_version(version
, "3.7") > 0)
4849 continue; // no prefix in file must match
4850 // null prefix in library object.
4853 NEW_OBJINST(newinst
, localdata
);
4854 (*newinst
)->thisobject
= *libobj
;
4855 (*newinst
)->color
= curcolor
;
4856 (*newinst
)->params
= NULL
;
4857 (*newinst
)->passed
= NULL
;
4858 (*newinst
)->bbox
.lowerleft
.x
= (*libobj
)->bbox
.lowerleft
.x
;
4859 (*newinst
)->bbox
.lowerleft
.y
= (*libobj
)->bbox
.lowerleft
.y
;
4860 (*newinst
)->bbox
.width
= (*libobj
)->bbox
.width
;
4861 (*newinst
)->bbox
.height
= (*libobj
)->bbox
.height
;
4862 (*newinst
)->schembbox
= NULL
;
4864 lineptr
= varfscan(localdata
, buffer
, &(*newinst
)->scale
,
4865 (genericptr
)*newinst
, P_SCALE
);
4867 /* Format prior to xcircuit 3.7 did not have scale- */
4868 /* invariant linewidth. If scale is 1, though, keep it */
4869 /* invariant so as not to overuse the scale-variance */
4870 /* flag in the output file. */
4872 if ((compare_version(version
, "3.7") < 0) && ((*newinst
)->scale
!= 1.0))
4873 (*newinst
)->style
= NORMAL
;
4875 (*newinst
)->style
= LINE_INVARIANT
;
4877 lineptr
= varfscan(localdata
, lineptr
, &(*newinst
)->rotation
,
4878 (genericptr
)*newinst
, P_ROTATION
);
4879 lineptr
= varpscan(localdata
, lineptr
, &(*newinst
)->position
.x
,
4880 (genericptr
)*newinst
, 0, offx
, P_POSITION_X
);
4881 lineptr
= varpscan(localdata
, lineptr
, &(*newinst
)->position
.y
,
4882 (genericptr
)*newinst
, 0, offy
, P_POSITION_Y
);
4884 /* Negative rotations = flip in x in version 2.3.6 and */
4885 /* earlier. Later versions don't allow negative rotation */
4887 if (compare_version(version
, "2.4") < 0) {
4888 if ((*newinst
)->rotation
< 0.0) {
4889 (*newinst
)->scale
= -((*newinst
)->scale
);
4890 (*newinst
)->rotation
+= 1.0;
4892 (*newinst
)->rotation
= -(*newinst
)->rotation
;
4895 while ((*newinst
)->rotation
> 360.0)
4896 (*newinst
)->rotation
-= 360.0;
4897 while ((*newinst
)->rotation
< 0.0)
4898 (*newinst
)->rotation
+= 360.0;
4900 std_eparam((genericptr
)(*newinst
), colorkey
);
4902 /* Does this instance contain parameters? */
4903 readparams(localdata
, *newinst
, *libobj
, buffer
);
4905 calcbboxinst(*newinst
);
4913 if (!found
) /* will assume that we have a continuation line */
4914 temp
= continueline(&buffer
);
4918 strncpy(retstr
, buffer
, 150);
4924 /*------------------------*/
4925 /* Save a PostScript file */
4926 /*------------------------*/
4930 void setfile(char *filename
, int mode
)
4932 if ((filename
== NULL
) || (xobjs
.pagelist
[areawin
->page
]->filename
== NULL
)) {
4933 Wprintf("Error: No filename for schematic.");
4934 if (areawin
->area
&& beeper
) XBell(dpy
, 100);
4938 /* see if name has been changed in the buffer */
4940 if (strcmp(xobjs
.pagelist
[areawin
->page
]->filename
, filename
)) {
4941 Wprintf("Changing name of edit file.");
4942 free(xobjs
.pagelist
[areawin
->page
]->filename
);
4943 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(filename
);
4946 if (strstr(xobjs
.pagelist
[areawin
->page
]->filename
, "Page ") != NULL
) {
4947 Wprintf("Warning: Enter a new name.");
4948 if (areawin
->area
&& beeper
) XBell(dpy
, 100);
4952 if (areawin
->area
&& beeper
) XBell(dpy
, 100);
4956 #else /* !TCL_WRAPPER */
4958 void setfile(xcWidget button
, xcWidget fnamewidget
, caddr_t clientdata
)
4960 /* see if name has been changed in the buffer */
4962 sprintf(_STR2
, "%.249s", (char *)XwTextCopyBuffer(fnamewidget
));
4963 if (xobjs
.pagelist
[areawin
->page
]->filename
== NULL
) {
4964 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(_STR2
);
4966 else if (strcmp(xobjs
.pagelist
[areawin
->page
]->filename
, _STR2
)) {
4967 Wprintf("Changing name of edit file.");
4968 free(xobjs
.pagelist
[areawin
->page
]->filename
);
4969 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(_STR2
);
4971 if (strstr(xobjs
.pagelist
[areawin
->page
]->filename
, "Page ") != NULL
) {
4972 Wprintf("Warning: Enter a new name.");
4973 if (areawin
->area
&& beeper
) XBell(dpy
, 100);
4980 savefile(CURRENT_PAGE
);
4982 /* Change "close" button to read "done" */
4984 di
= xcParent(button
);
4985 db
= XtNameToWidget(di
, "Close");
4986 XtSetArg(wargs
[0], XtNlabel
, " Done ");
4987 XtSetValues(db
, wargs
, 1);
4988 if (areawin
->area
&& beeper
) XBell(dpy
, 100);
4992 #endif /* TCL_WRAPPER */
4994 /*--------------------------------------------------------------*/
4995 /* Update number of changes for an object and initiate a temp */
4996 /* file save if total number of unsaved changes exceeds 20. */
4997 /*--------------------------------------------------------------*/
4999 void incr_changes(objectptr thisobj
)
5001 /* It is assumed that empty pages are meant to be that way */
5002 /* and are not to be saved, so changes are marked as zero. */
5004 if (thisobj
->parts
== 0) {
5005 thisobj
->changes
= 0;
5009 /* Remove any pending timeout */
5011 if (xobjs
.timeout_id
!= (xcIntervalId
)NULL
) {
5012 xcRemoveTimeOut(xobjs
.timeout_id
);
5013 xobjs
.timeout_id
= (xcIntervalId
)NULL
;
5018 /* When in "suspend" mode, we assume that we are reading commands from
5019 * a script, and therefore we should not continuously increment changes
5020 * and keep saving the backup file.
5023 if (xobjs
.suspend
< 0)
5024 xobjs
.new_changes
++;
5026 if (xobjs
.new_changes
> MAXCHANGES
) {
5030 savetemp(NULL
, NULL
);
5034 /* Generate a new timeout */
5037 xobjs
.timeout_id
= xcAddTimeOut(app
, 60000 * xobjs
.save_interval
,
5041 /*--------------------------------------------------------------*/
5043 /*--------------------------------------------------------------*/
5047 void savetemp(ClientData clientdata
)
5052 void savetemp(XtPointer clientdata
, xcIntervalId
*id
)
5056 /* If areawin->area is NULL then xcircuit is running in */
5057 /* batch mode and should not make backups. */
5058 if (areawin
->area
== NULL
) return;
5060 /* Remove the timeout ID. If this routine is called from */
5061 /* incr_changes() instead of from the timeout interrupt */
5062 /* service routine, then this value will already be NULL. */
5064 xobjs
.timeout_id
= (xcIntervalId
)NULL
;
5066 /* First see if there are any unsaved changes in the file. */
5067 /* If not, then just reset the counter and continue. */
5069 if (xobjs
.new_changes
> 0) {
5070 if (xobjs
.tempfile
== NULL
)
5073 char *template = (char *)malloc(20 + strlen(xobjs
.tempdir
));
5074 int pid
= (int)getpid();
5076 sprintf(template, "%s/XC%d.XXXXXX", xobjs
.tempdir
, pid
);
5079 fd
= mktemp(template);
5081 fd
= mkstemp(template);
5084 Fprintf(stderr
, "Error generating file for savetemp\n");
5088 xobjs
.tempfile
= strdup(template);
5091 /* Show the "wristwatch" cursor, as graphic data may cause this */
5092 /* step to be inordinately long. */
5094 XDefineCursor(dpy
, areawin
->window
, WAITFOR
);
5095 savefile(ALL_PAGES
);
5096 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5097 xobjs
.new_changes
= 0; /* reset the count */
5101 /*----------------------------------------------------------------------*/
5102 /* Set all objects in the list "wroteobjs" as having no unsaved changes */
5103 /*----------------------------------------------------------------------*/
5105 void setassaved(objectptr
*wroteobjs
, short written
)
5109 for (i
= 0; i
< written
; i
++)
5110 (*(wroteobjs
+ i
))->changes
= 0;
5113 /*---------------------------------------------------------------*/
5114 /* Save indicated library. If libno is 0, save current page if */
5115 /* the current page is a library. If not, save the user library */
5116 /*---------------------------------------------------------------*/
5118 void savelibpopup(xcWidget button
, char *technology
, caddr_t nulldata
)
5123 buttonsave
*savebutton
;
5126 nsptr
= LookupTechnology(technology
);
5128 if (nsptr
!= NULL
) {
5129 if ((nsptr
->flags
& TECH_READONLY
) != 0) {
5130 Wprintf("Library technology \"%s\" is read-only.", technology
);
5136 savebutton
= getgeneric(button
, savelibpopup
, technology
);
5137 popupprompt(button
, "Enter technology:", "\0", savelibrary
,
5142 /*---------------------------------------------------------*/
5146 void savelibrary(xcWidget w
, char *technology
)
5149 sscanf(_STR2
, "%249s", outname
);
5150 savetechnology(technology
, outname
);
5155 /*---------------------------------------------------------*/
5157 void savetechnology(char *technology
, char *outname
)
5160 char *outptr
, *validname
, outfile
[150];
5161 objectptr
*wroteobjs
, libobjptr
, *optr
, depobj
;
5167 char *hostname
= NULL
;
5168 struct passwd
*mypwentry
= NULL
;
5171 char *loctechnology
;
5173 // Don't use the string "(user)" as a technology name; this is just
5174 // a GUI placeholder for a null string (""). This shouldn't happen,
5175 // though, as technology should be NULL if the user technology is
5178 if (technology
&& (!strcmp(technology
, "(user)")))
5179 nsptr
= LookupTechnology(NULL
);
5181 nsptr
= LookupTechnology(technology
);
5183 if ((outptr
= strrchr(outname
, '/')) == NULL
)
5187 strcpy(outfile
, outname
);
5188 if (strchr(outptr
, '.') == NULL
) strcat(outfile
, ".lps");
5190 xc_tilde_expand(outfile
, 149);
5191 while(xc_variable_expand(outfile
, 149));
5193 if (nsptr
!= NULL
&& nsptr
->filename
!= NULL
) {
5194 // To be pedantic, we should probably check that the inodes of the
5195 // files are different, to be sure we are avoiding an unintentional
5198 if (!strcmp(outfile
, nsptr
->filename
)) {
5200 if ((nsptr
->flags
& TECH_READONLY
) != 0) {
5201 Wprintf("Technology file \"%s\" is read-only.", technology
);
5205 if ((nsptr
->flags
& TECH_IMPORTED
) != 0) {
5206 Wprintf("Attempt to write a truncated technology file!");
5212 ps
= fopen(outfile
, "wb");
5214 Wprintf("Can't open PS file.");
5215 if (nsptr
&& nsptr
->filename
&& (!strcmp(nsptr
->filename
, outfile
))) {
5216 Wprintf("Marking technology \"%s\" as read-only.", technology
);
5217 nsptr
->flags
|= TECH_READONLY
;
5222 /* Did the technology name change? If so, register the new name. */
5223 /* Clear any "IMPORTED" or "READONLY" flags. */
5225 if (nsptr
&& nsptr
->filename
&& strcmp(outfile
, nsptr
->filename
)) {
5226 Wprintf("Technology filename changed from \"%s\" to \"%s\".",
5227 nsptr
->filename
, outfile
);
5228 free(nsptr
->filename
);
5229 nsptr
->filename
= strdup(outfile
);
5230 nsptr
->flags
&= ~(TECH_READONLY
| TECH_IMPORTED
);
5232 else if (nsptr
&& !nsptr
->filename
) {
5233 nsptr
->filename
= strdup(outfile
);
5234 nsptr
->flags
&= ~(TECH_READONLY
| TECH_IMPORTED
);
5237 fprintf(ps
, "%%! PostScript set of library objects for XCircuit\n");
5238 fprintf(ps
, "%% Version: %s\n", version
);
5239 fprintf(ps
, "%% Library name is: %s\n",
5240 (technology
== NULL
) ? "(user)" : technology
);
5242 uname
= getenv((const char *)"USERNAME");
5244 uname
= getenv((const char *)"USER");
5245 if (uname
!= NULL
) mypwentry
= getpwnam(uname
);
5248 /* Check for both $HOST and $HOSTNAME environment variables. Thanks */
5249 /* to frankie liu <frankliu@Stanford.EDU> for this fix. */
5251 if ((hostname
= getenv((const char *)"HOSTNAME")) == NULL
)
5252 if ((hostname
= getenv((const char *)"HOST")) == NULL
) {
5253 if (gethostname(_STR
, 149) != 0)
5260 if (mypwentry
!= NULL
)
5261 fprintf(ps
, "%% Author: %s <%s@%s>\n", mypwentry
->pw_gecos
, uname
,
5265 fprintf(ps
, "%%\n\n");
5267 /* Print lists of object dependencies, where they exist. */
5268 /* Note that objects can depend on objects in other technologies; */
5269 /* this is allowed. */
5271 wroteobjs
= (objectptr
*) malloc(sizeof(objectptr
));
5272 for (ilib
= 0; ilib
< xobjs
.numlibs
; ilib
++) {
5273 for (j
= 0; j
< xobjs
.userlibs
[ilib
].number
; j
++) {
5275 libobjptr
= *(xobjs
.userlibs
[ilib
].library
+ j
);
5276 if (CompareTechnology(libobjptr
, technology
)) {
5279 /* Search for all object definitions instantiated in this object, */
5280 /* and add them to the dependency list (non-recursive). */
5282 for (gptr
= libobjptr
->plist
; gptr
< libobjptr
->plist
5283 + libobjptr
->parts
; gptr
++) {
5284 if (IS_OBJINST(*gptr
)) {
5285 depobj
= TOOBJINST(gptr
)->thisobject
;
5287 /* Search among the list of objects already collected. */
5288 /* If this object has been previously, then ignore it. */
5289 /* Otherwise, update the list of object dependencies */
5291 for (optr
= wroteobjs
; optr
< wroteobjs
+ written
; optr
++)
5292 if (*optr
== depobj
)
5295 if (optr
== wroteobjs
+ written
) {
5296 wroteobjs
= (objectptr
*)realloc(wroteobjs
, (written
+ 1) *
5298 *(wroteobjs
+ written
) = depobj
;
5304 fprintf(ps
, "%% Depend %s", libobjptr
->name
);
5305 for (i
= 0; i
< written
; i
++) {
5306 depobj
= *(wroteobjs
+ i
);
5307 fprintf(ps
, " %s", depobj
->name
);
5315 fprintf(ps
, "\n%% XCircuitLib library objects\n");
5317 /* Start by looking for any graphic images in the library objects */
5318 /* and saving the graphic image data at the top of the file. */
5320 glist
= (short *)malloc(xobjs
.images
* sizeof(short));
5321 for (i
= 0; i
< xobjs
.images
; i
++) glist
[i
] = 0;
5323 for (ilib
= 0; ilib
< xobjs
.numlibs
; ilib
++) {
5324 for (spec
= xobjs
.userlibs
[ilib
].instlist
; spec
!= NULL
; spec
= spec
->next
) {
5325 libobjptr
= spec
->thisinst
->thisobject
;
5326 if (CompareTechnology(libobjptr
, technology
))
5327 count_graphics(spec
->thisinst
->thisobject
, glist
);
5330 output_graphic_data(ps
, glist
);
5333 /* list of library objects already written */
5335 wroteobjs
= (objectptr
*)realloc(wroteobjs
, sizeof(objectptr
));
5338 /* write all of the object definitions used, bottom up, with virtual */
5339 /* instances in the correct placement. The need to find virtual */
5340 /* instances is why we do a look through the library pages and not */
5341 /* the libraries themselves when looking for objects matching the */
5342 /* given technology. */
5344 for (ilib
= 0; ilib
< xobjs
.numlibs
; ilib
++) {
5345 for (spec
= xobjs
.userlibs
[ilib
].instlist
; spec
!= NULL
; spec
= spec
->next
) {
5346 libobjptr
= spec
->thisinst
->thisobject
;
5347 if (CompareTechnology(libobjptr
, technology
)) {
5348 if (!spec
->virtual) {
5349 printobjects(ps
, spec
->thisinst
->thisobject
, &wroteobjs
,
5350 &written
, DEFAULTCOLOR
);
5353 if ((spec
->thisinst
->scale
!= 1.0) ||
5354 (spec
->thisinst
->rotation
!= 0.0)) {
5355 fprintf(ps
, "%3.3f %3.3f ", spec
->thisinst
->scale
,
5356 spec
->thisinst
->rotation
);
5358 printparams(ps
, spec
->thisinst
, 0);
5359 validname
= create_valid_psname(spec
->thisinst
->thisobject
->name
, FALSE
);
5360 /* Names without technologies get '::' string (blank technology) */
5361 if (technology
== NULL
)
5362 fprintf(ps
, "/::%s libinst\n", validname
);
5364 fprintf(ps
, "/%s libinst\n", validname
);
5365 if ((spec
->next
!= NULL
) && (!(spec
->next
->virtual)))
5372 setassaved(wroteobjs
, written
);
5373 if (nsptr
) nsptr
->flags
&= (~TECH_CHANGED
);
5374 xobjs
.new_changes
= countchanges(NULL
);
5376 /* and the postlog */
5378 fprintf(ps
, "\n%% EndLib\n");
5380 if (technology
!= NULL
)
5381 Wprintf("Library technology \"%s\" saved as file %s.",technology
, outname
);
5383 Wprintf("Library technology saved as file %s.", outname
);
5388 /*----------------------------------------------------------------------*/
5389 /* Recursive routine to search the object hierarchy for fonts used */
5390 /*----------------------------------------------------------------------*/
5392 void findfonts(objectptr writepage
, short *fontsused
) {
5397 for (dfp
= writepage
->plist
; dfp
< writepage
->plist
+ writepage
->parts
; dfp
++) {
5398 if (IS_LABEL(*dfp
)) {
5399 for (chp
= TOLABEL(dfp
)->string
; chp
!= NULL
; chp
= chp
->nextpart
) {
5400 if (chp
->type
== FONT_NAME
) {
5401 findex
= chp
->data
.font
;
5402 if (fontsused
[findex
] == 0) {
5403 fontsused
[findex
] = 0x8000 | fonts
[findex
].flags
;
5408 else if (IS_OBJINST(*dfp
)) {
5409 findfonts(TOOBJINST(dfp
)->thisobject
, fontsused
);
5414 /*------------------------------------------------------*/
5415 /* Write graphics image data to file "ps". "glist" is */
5416 /* a pointer to a vector of short integers, each one */
5417 /* being an index into xobjs.images for an image that */
5418 /* is to be output. */
5419 /*------------------------------------------------------*/
5421 void output_graphic_data(FILE *ps
, short *glist
)
5423 char *fptr
, ascbuf
[6];
5425 for (i
= 0; i
< xobjs
.images
; i
++) {
5426 Imagedata
*img
= xobjs
.imagelist
+ i
;
5427 int ilen
, flen
, k
, m
= 0, n
, q
= 0;
5428 u_char
*filtbuf
, *flatebuf
;
5429 Boolean lastpix
= False
;
5434 int width
= xcImageGetWidth(img
->image
);
5435 int height
= xcImageGetHeight(img
->image
);
5437 if (glist
[i
] == 0) continue;
5439 fprintf(ps
, "%%imagedata %d %d\n", width
, height
);
5440 fprintf(ps
, "currentfile /ASCII85Decode filter ");
5443 fprintf(ps
, "/FlateDecode filter\n");
5446 fprintf(ps
, "/ReusableStreamDecode filter\n");
5448 /* creating a stream buffer is wasteful if we're just using ASCII85 */
5449 /* decoding but is a must for compression filters. */
5451 ilen
= 3 * width
* height
;
5452 filtbuf
= (u_char
*)malloc(ilen
+ 4);
5455 for (j
= 0; j
< height
; j
++)
5456 for (k
= 0; k
< width
; k
++) {
5457 unsigned char r
, g
, b
;
5458 xcImageGetPixel(img
->image
, k
, j
, &r
, &g
, &b
);
5464 /* Extra encoding goes here */
5467 flatebuf
= (char *)malloc(flen
);
5468 ilen
= large_deflate(flatebuf
, flen
, filtbuf
, ilen
);
5476 for (j
= 0; j
< ilen
; j
+= 4) {
5477 if ((j
+ 4) > ilen
) lastpix
= TRUE
;
5478 if (!lastpix
&& (flatebuf
[j
] + flatebuf
[j
+ 1] + flatebuf
[j
+ 2]
5479 + flatebuf
[j
+ 3] == 0)) {
5484 for (n
= 0; n
< 4; n
++)
5485 pixel
.b
[3 - n
] = flatebuf
[j
+ n
];
5487 ascbuf
[0] = '!' + (pixel
.i
/ 52200625);
5488 pixel
.i
%= 52200625;
5489 ascbuf
[1] = '!' + (pixel
.i
/ 614125);
5491 ascbuf
[2] = '!' + (pixel
.i
/ 7225);
5493 ascbuf
[3] = '!' + (pixel
.i
/ 85);
5495 ascbuf
[4] = '!' + pixel
.i
;
5497 for (n
= 0; n
< ilen
+ 1 - j
; n
++)
5498 fprintf(ps
, "%c", ascbuf
[n
]);
5500 fprintf(ps
, "%5s", ascbuf
);
5508 fprintf(ps
, "~>\n");
5511 /* Remove any filesystem path information from the image name. */
5512 /* Otherwise, the slashes will cause PostScript to err. */
5514 fptr
= strrchr(img
->filename
, '/');
5516 fptr
= img
->filename
;
5519 fprintf(ps
, "/%sdata exch def\n", fptr
);
5520 fprintf(ps
, "/%s <<\n", fptr
);
5521 fprintf(ps
, " /ImageType 1 /Width %d /Height %d /BitsPerComponent 8\n",
5523 fprintf(ps
, " /MultipleDataSources false\n");
5524 fprintf(ps
, " /Decode [0 1 0 1 0 1]\n");
5525 fprintf(ps
, " /ImageMatrix [1 0 0 -1 %d %d]\n",
5526 width
>> 1, height
>> 1);
5527 fprintf(ps
, " /DataSource %sdata >> def\n\n", fptr
);
5531 /*----------------------------------------------------------------------*/
5532 /* Main file saving routine */
5533 /*----------------------------------------------------------------------*/
5534 /* mode description */
5535 /*----------------------------------------------------------------------*/
5536 /* ALL_PAGES saves a crash recovery backup file */
5537 /* CURRENT_PAGE saves all pages associated with the same */
5538 /* filename as the current page, and all */
5539 /* dependent schematics (which have their */
5540 /* filenames changed to match). */
5541 /* NO_SUBCIRCUITS saves all pages associated with the same */
5542 /* filename as the current page, only. */
5543 /*----------------------------------------------------------------------*/
5545 void savefile(short mode
)
5547 FILE *ps
, *pro
, *enc
;
5548 char outname
[150], temp
[150], prologue
[150], *fname
, *fptr
, ascbuf
[6];
5549 /* u_char decodebuf[6]; (jdk */
5550 short written
, fontsused
[256], i
, page
, curpage
, multipage
;
5551 short savepage
, stcount
, *pagelist
, *glist
;
5552 objectptr
*wroteobjs
;
5553 objinstptr writepage
;
5558 if (mode
!= ALL_PAGES
) {
5559 /* doubly-protected file write: protect against errors during file write */
5560 fname
= xobjs
.pagelist
[areawin
->page
]->filename
;
5561 sprintf(outname
, "%s~", fname
);
5562 rename(fname
, outname
);
5565 /* doubly-protected backup: protect against errors during file write */
5566 sprintf(outname
, "%sB", xobjs
.tempfile
);
5567 rename(xobjs
.tempfile
, outname
);
5568 fname
= xobjs
.tempfile
;
5571 if ((fptr
= strrchr(fname
, '/')) != NULL
)
5576 if ((mode
!= ALL_PAGES
) && (strchr(fptr
, '.') == NULL
))
5577 sprintf(outname
, "%s.ps", fname
);
5578 else sprintf(outname
, "%s", fname
);
5580 xc_tilde_expand(outname
, 149);
5581 while(xc_variable_expand(outname
, 149));
5583 ps
= fopen(outname
, "wb");
5585 Wprintf("Can't open file %s for writing.", outname
);
5589 if ((mode
!= NO_SUBCIRCUITS
) && (mode
!= ALL_PAGES
))
5590 collectsubschems(areawin
->page
);
5592 /* Check for multiple-page output: get the number of pages; */
5593 /* ignore empty pages. */
5597 if (mode
== NO_SUBCIRCUITS
)
5598 pagelist
= pagetotals(areawin
->page
, INDEPENDENT
);
5599 else if (mode
== ALL_PAGES
)
5600 pagelist
= pagetotals(areawin
->page
, ALL_PAGES
);
5602 pagelist
= pagetotals(areawin
->page
, TOTAL_PAGES
);
5604 for (page
= 0; page
< xobjs
.pages
; page
++)
5605 if (pagelist
[page
] > 0)
5608 if (multipage
== 0) {
5609 Wprintf("Panic: could not find this page in page list!");
5615 /* Print the PostScript DSC Document Header */
5617 fprintf(ps
, "%%!PS-Adobe-3.0");
5618 if (multipage
== 1 && !(xobjs
.pagelist
[areawin
->page
]->pmode
& 1))
5619 fprintf(ps
, " EPSF-3.0\n");
5622 fprintf(ps
, "%%%%Title: %s\n", fptr
);
5623 fprintf(ps
, "%%%%Creator: XCircuit v%2.1f rev%d\n", PROG_VERSION
, PROG_REVISION
);
5625 fprintf(ps
, "%%%%CreationDate: %s", asctime(localtime(&tdate
)));
5626 fprintf(ps
, "%%%%Pages: %d\n", multipage
);
5628 /* This is just a default value; each bounding box is declared per */
5629 /* page by the DSC "PageBoundingBox" keyword. */
5630 /* However, encapsulated files adjust the bounding box to center on */
5631 /* the object, instead of centering the object on the page. */
5633 if (multipage
== 1 && !(xobjs
.pagelist
[areawin
->page
]->pmode
& 1)) {
5634 objectptr thisobj
= xobjs
.pagelist
[areawin
->page
]->pageinst
->thisobject
;
5635 float psscale
= getpsscale(xobjs
.pagelist
[areawin
->page
]->outscale
,
5638 /* The top-level bounding box determines the size of an encapsulated */
5639 /* drawing, regardless of the PageBoundingBox numbers. Therefore, */
5640 /* we size this to bound just the picture by closing up the 1" (72 */
5641 /* PostScript units) margins, except for a tiny sliver of a margin */
5642 /* (4 PostScript units) which covers a bit of sloppiness in the font */
5645 fprintf(ps
, "%%%%BoundingBox: 68 68 %d %d\n",
5646 (int)((float)thisobj
->bbox
.width
* psscale
)
5647 + xobjs
.pagelist
[areawin
->page
]->margins
.x
+ 4,
5648 (int)((float)thisobj
->bbox
.height
* psscale
)
5649 + xobjs
.pagelist
[areawin
->page
]->margins
.y
+ 4);
5651 else if (xobjs
.pagelist
[0]->coordstyle
== CM
)
5652 fprintf(ps
, "%%%%BoundingBox: 0 0 595 842\n"); /* A4 default (fixed by jdk) */
5654 fprintf(ps
, "%%%%BoundingBox: 0 0 612 792\n"); /* letter default */
5656 for (i
= 0; i
< fontcount
; i
++) fontsused
[i
] = 0;
5657 fprintf(ps
, "%%%%DocumentNeededResources: font ");
5660 /* find all of the fonts used in this document */
5661 /* log all fonts which are native PostScript */
5663 for (curpage
= 0; curpage
< xobjs
.pages
; curpage
++)
5664 if (pagelist
[curpage
] > 0) {
5665 writepage
= xobjs
.pagelist
[curpage
]->pageinst
;
5666 findfonts(writepage
->thisobject
, fontsused
);
5669 for (i
= 0; i
< fontcount
; i
++) {
5670 if (fontsused
[i
] & 0x8000)
5671 if ((fonts
[i
].flags
& 0x8018) == 0x0) {
5672 stcount
+= strlen(fonts
[i
].psname
) + 1;
5673 if (stcount
> OUTPUTWIDTH
) {
5674 stcount
= strlen(fonts
[i
].psname
) + 11;
5675 fprintf(ps
, "\n%%%%+ font ");
5677 fprintf(ps
, "%s ", fonts
[i
].psname
);
5681 fprintf(ps
, "\n%%%%EndComments\n");
5683 tmp_s
= getenv((const char *)"XCIRCUIT_LIB_DIR");
5684 if (tmp_s
!= NULL
) {
5685 sprintf(prologue
, "%s/%s", tmp_s
, PROLOGUE_FILE
);
5686 pro
= fopen(prologue
, "r");
5692 sprintf(prologue
, "%s/%s", PROLOGUE_DIR
, PROLOGUE_FILE
);
5693 pro
= fopen(prologue
, "r");
5695 sprintf(prologue
, "%s", PROLOGUE_FILE
);
5696 pro
= fopen(prologue
, "r");
5698 Wprintf("Can't open prolog.");
5706 /* write the prolog to the output */
5709 if (fgets(temp
, 149, pro
) == NULL
) break;
5710 if (!strncmp(temp
, "%%EndProlog", 11)) break;
5715 /* Special font encodings not known to PostScript */
5716 /* (anything other than Standard and ISOLatin-1) */
5718 for (findex
= 0; findex
< fontcount
; findex
++) {
5719 if ((fontsused
[findex
] & 0xf80) == 0x400) {
5720 /* Cyrillic (ISO8859-5) */
5721 sprintf(prologue
, "%s/%s", PROLOGUE_DIR
, CYRILLIC_ENC_FILE
);
5722 pro
= fopen(prologue
, "r");
5724 sprintf(prologue
, "%s", CYRILLIC_ENC_FILE
);
5725 pro
= fopen(prologue
, "r");
5727 Wprintf("Warning: Missing font encoding vectors.");
5728 Wprintf("Output may not print properly.");
5733 if (fgets(temp
, 149, pro
) == NULL
) break;
5739 else if ((fontsused
[findex
] & 0xf80) == 0x180) {
5740 /* Eastern European (ISOLatin2) */
5741 sprintf(prologue
, "%s/%s", PROLOGUE_DIR
, ISOLATIN2_ENC_FILE
);
5742 pro
= fopen(prologue
, "r");
5744 sprintf(prologue
, "%s", ISOLATIN2_ENC_FILE
);
5745 pro
= fopen(prologue
, "r");
5747 Wprintf("Warning: Missing font encoding vectors.");
5748 Wprintf("Output may not print properly.");
5753 if (fgets(temp
, 149, pro
) == NULL
) break;
5759 else if ((fontsused
[findex
] & 0xf80) == 0x300) {
5760 /* Turkish (ISOLatin5) */
5761 sprintf(prologue
, "%s/%s", PROLOGUE_DIR
, ISOLATIN5_ENC_FILE
);
5762 pro
= fopen(prologue
, "r");
5764 sprintf(prologue
, "%s", ISOLATIN5_ENC_FILE
);
5765 pro
= fopen(prologue
, "r");
5767 Wprintf("Warning: Missing font encoding vectors.");
5768 Wprintf("Output may not print properly.");
5773 if (fgets(temp
, 149, pro
) == NULL
) break;
5781 /* Finish off prolog */
5782 fputs("%%EndProlog\n", ps
);
5784 /* Special font handling */
5786 for (findex
= 0; findex
< fontcount
; findex
++) {
5788 /* Derived font slant */
5790 if ((fontsused
[findex
] & 0x032) == 0x032)
5791 fprintf(ps
, "/%s /%s .167 fontslant\n\n",
5792 fonts
[findex
].psname
, fonts
[findex
].family
);
5794 /* Derived ISO-Latin1 encoding */
5796 if ((fontsused
[findex
] & 0xf80) == 0x100) {
5797 char *fontorig
= NULL
;
5799 /* find the original standard-encoded font (can be itself) */
5800 for (i
= 0; i
< fontcount
; i
++) {
5801 if (i
== findex
) continue;
5802 if (!strcmp(fonts
[i
].family
, fonts
[findex
].family
) &&
5803 ((fonts
[i
].flags
& 0x03) == (fonts
[findex
].flags
& 0x03))) {
5804 fontorig
= fonts
[i
].psname
;
5808 if (fontorig
== NULL
) fontorig
= fonts
[findex
].psname
;
5809 fprintf(ps
, "/%s findfont dup length dict begin\n", fontorig
);
5810 fprintf(ps
, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
5811 fprintf(ps
, "/Encoding ISOLatin1Encoding def currentdict end\n");
5812 fprintf(ps
, "/%s exch definefont pop\n\n", fonts
[findex
].psname
);
5815 /* Derived Cyrillic (ISO8859-5) encoding */
5817 if ((fontsused
[findex
] & 0xf80) == 0x400) {
5818 char *fontorig
= NULL
;
5820 /* find the original standard-encoded font (can be itself) */
5821 for (i
= 0; i
< fontcount
; i
++) {
5822 if (i
== findex
) continue;
5823 if (!strcmp(fonts
[i
].family
, fonts
[findex
].family
) &&
5824 ((fonts
[i
].flags
& 0x03) == (fonts
[findex
].flags
& 0x03))) {
5825 fontorig
= fonts
[i
].psname
;
5829 if (fontorig
== NULL
) fontorig
= fonts
[findex
].psname
;
5830 fprintf(ps
, "/%s findfont dup length dict begin\n", fontorig
);
5831 fprintf(ps
, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
5832 fprintf(ps
, "/Encoding ISO8859_5Encoding def currentdict end\n");
5833 fprintf(ps
, "/%s exch definefont pop\n\n", fonts
[findex
].psname
);
5836 /* ISO-Latin2 encoding */
5838 if ((fontsused
[findex
] & 0xf80) == 0x180) {
5839 char *fontorig
= NULL
;
5841 /* find the original standard-encoded font (can be itself) */
5842 for (i
= 0; i
< fontcount
; i
++) {
5843 if (i
== findex
) continue;
5844 if (!strcmp(fonts
[i
].family
, fonts
[findex
].family
) &&
5845 ((fonts
[i
].flags
& 0x03) == (fonts
[findex
].flags
& 0x03))) {
5846 fontorig
= fonts
[i
].psname
;
5850 if (fontorig
== NULL
) fontorig
= fonts
[findex
].psname
;
5851 fprintf(ps
, "/%s findfont dup length dict begin\n", fontorig
);
5852 fprintf(ps
, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
5853 fprintf(ps
, "/Encoding ISOLatin2Encoding def currentdict end\n");
5854 fprintf(ps
, "/%s exch definefont pop\n\n", fonts
[findex
].psname
);
5857 /* ISO-Latin5 encoding */
5859 if ((fontsused
[findex
] & 0xf80) == 0x300) {
5860 char *fontorig
= NULL
;
5862 /* find the original standard-encoded font (can be itself) */
5863 for (i
= 0; i
< fontcount
; i
++) {
5864 if (i
== findex
) continue;
5865 if (!strcmp(fonts
[i
].family
, fonts
[findex
].family
) &&
5866 ((fonts
[i
].flags
& 0x03) == (fonts
[findex
].flags
& 0x03))) {
5867 fontorig
= fonts
[i
].psname
;
5871 if (fontorig
== NULL
) fontorig
= fonts
[findex
].psname
;
5872 fprintf(ps
, "/%s findfont dup length dict begin\n", fontorig
);
5873 fprintf(ps
, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
5874 fprintf(ps
, "/Encoding ISOLatin5Encoding def currentdict end\n");
5875 fprintf(ps
, "/%s exch definefont pop\n\n", fonts
[findex
].psname
);
5878 /* To do: Special encoding */
5880 if ((fontsused
[findex
] & 0xf80) == 0x80) {
5883 /* To do: Vectored (drawn) font */
5885 if (fontsused
[findex
] & 0x8) {
5889 /* List of objects already written */
5890 wroteobjs
= (objectptr
*) malloc (sizeof(objectptr
));
5893 fprintf(ps
, "%% XCircuit output starts here.\n\n");
5894 fprintf(ps
, "%%%%BeginSetup\n\n");
5896 /* Write out all of the images used */
5898 glist
= collect_graphics(pagelist
);
5899 output_graphic_data(ps
, glist
);
5902 for (curpage
= 0; curpage
< xobjs
.pages
; curpage
++) {
5903 if (pagelist
[curpage
] == 0) continue;
5905 /* Write all of the object definitions used, bottom up */
5906 printrefobjects(ps
, xobjs
.pagelist
[curpage
]->pageinst
->thisobject
,
5907 &wroteobjs
, &written
);
5910 fprintf(ps
, "\n%%%%EndSetup\n\n");
5913 for (curpage
= 0; curpage
< xobjs
.pages
; curpage
++) {
5914 if (pagelist
[curpage
] == 0) continue;
5916 /* Print the page header, all elements in the page, and page trailer */
5917 savepage
= areawin
->page
;
5918 /* Set the current page for the duration of printing so that any */
5919 /* page parameters will be printed correctly. */
5920 areawin
->page
= curpage
;
5921 printpageobject(ps
, xobjs
.pagelist
[curpage
]->pageinst
->thisobject
,
5923 areawin
->page
= savepage
;
5925 /* For crash recovery, log the filename for each page */
5926 if (mode
== ALL_PAGES
) {
5927 fprintf(ps
, "%% %s is_filename\n",
5928 (xobjs
.pagelist
[curpage
]->filename
== NULL
) ?
5929 xobjs
.pagelist
[curpage
]->pageinst
->thisobject
->name
:
5930 xobjs
.pagelist
[curpage
]->filename
);
5937 /* For crash recovery, save all objects that have been edited but are */
5938 /* not in the list of objects already saved. */
5940 if (mode
== ALL_PAGES
)
5945 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
5946 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
5947 thisobj
= *(xobjs
.userlibs
[i
].library
+ j
);
5948 if (thisobj
->changes
> 0 ) {
5949 for (k
= 0; k
< written
; k
++)
5950 if (thisobj
== *(wroteobjs
+ k
)) break;
5952 printobjects(ps
, thisobj
, &wroteobjs
, &written
, DEFAULTCOLOR
);
5957 else { /* No unsaved changes in these objects */
5958 setassaved(wroteobjs
, written
);
5959 for (i
= 0; i
< xobjs
.pages
; i
++)
5960 if (pagelist
[i
] > 0)
5961 xobjs
.pagelist
[i
]->pageinst
->thisobject
->changes
= 0;
5962 xobjs
.new_changes
= countchanges(NULL
);
5965 /* Free allocated memory */
5966 free((char *)pagelist
);
5967 free((char *)wroteobjs
);
5971 fprintf(ps
, "%%%%Trailer\n");
5972 fprintf(ps
, "XCIRCsave restore\n");
5973 fprintf(ps
, "%%%%EOF\n");
5976 Wprintf("File %s saved (%d page%s).", fname
, multipage
,
5977 (multipage
> 1 ? "s" : ""));
5979 if (mode
== ALL_PAGES
) {
5980 /* Remove the temporary redundant backup */
5981 sprintf(outname
, "%sB", xobjs
.tempfile
);
5984 else if (!xobjs
.retain_backup
) {
5985 /* Remove the backup file */
5986 sprintf(outname
, "%s~", fname
);
5990 /* Write LATEX strings, if any are present */
5994 /*----------------------------------------------------------------------*/
5995 /* Given a color index, print the R, G, B values */
5996 /*----------------------------------------------------------------------*/
5998 int printRGBvalues(char *tstr
, int index
, const char *postfix
)
6001 if (index
>= 0 && index
< number_colors
) {
6002 sprintf(tstr
, "%4.3f %4.3f %4.3f %s",
6003 (float)colorlist
[index
].color
.red
/ 65535,
6004 (float)colorlist
[index
].color
.green
/ 65535,
6005 (float)colorlist
[index
].color
.blue
/ 65535,
6010 /* The program can reach this point for any color which is */
6011 /* not listed in the table. This can happen when parameters */
6012 /* printed from printobjectparams object contain the string */
6013 /* "@p_color". Therefore print the default top-level */
6014 /* default color, which is black. */
6016 /* If the index is *not* DEFAULTCOLOR (-1), return an error */
6019 sprintf(tstr
, "0 0 0 %s", postfix
);
6020 return (index
== DEFAULTCOLOR
) ? 0 : -1;
6023 /*----------------------------------------------------*/
6024 /* Write string to PostScript string, ignoring NO_OPs */
6025 /*----------------------------------------------------*/
6027 char *nosprint(char *baseptr
, int *margin
, int *extsegs
)
6029 int qtmp
, slen
= 100;
6030 char *sptr
, *lptr
= NULL
, lsave
, *sptr2
;
6031 u_char
*pptr
, *qptr
, *bptr
;
6033 bptr
= (u_char
*)malloc(slen
); /* initial length 100 */
6036 while(1) { /* loop for breaking up margin-limited text into words */
6039 sptr
= strrchr(baseptr
, ' ');
6043 if (*(sptr
+ 1) == '\0') {
6044 while (*sptr
== ' ') sptr
--;
6046 sptr2
= strrchr(baseptr
, ' ');
6062 /* Includes extended character set (non-ASCII) */
6064 for (pptr
= sptr
; pptr
&& *pptr
!= '\0'; pptr
++) {
6065 /* Ensure enough space for the string, including everything */
6066 /* following the "for" loop */
6068 if (qtmp
+ 7 >= slen
) {
6070 bptr
= (char *)realloc(bptr
, slen
);
6074 /* Deal with non-printable characters and parentheses */
6075 if (*pptr
> (char)126) {
6076 sprintf(qptr
, "\\%3o", (int)(*pptr
));
6080 if ((*pptr
== '(') || (*pptr
== ')') || (*pptr
== '\\'))
6085 if (qptr
== bptr
+ 1) { /* Empty string gets a NULL result, not "()" */
6096 if (sptr
== baseptr
)
6107 return (char *)bptr
;
6110 /*--------------------------------------------------------------*/
6111 /* Write label segments to the output (in reverse order) */
6112 /*--------------------------------------------------------------*/
6114 short writelabel(FILE *ps
, stringpart
*chrtop
, short *stcount
)
6118 char **ostr
= (char **)malloc(sizeof(char *));
6120 float lastscale
= 1.0;
6125 /* Write segments into string array, in forward order */
6127 for (chrptr
= chrtop
; chrptr
!= NULL
; chrptr
= chrptr
->nextpart
) {
6128 ostr
= (char **)realloc(ostr
, (segs
+ 1) * sizeof(char *));
6129 if (chrtop
->type
== PARAM_END
) { /* NULL parameter is empty string */
6130 ostr
[segs
] = (char *)malloc(4);
6131 strcpy(ostr
[segs
], "() ");
6134 tmpstr
= writesegment(chrptr
, &lastscale
, &lastfont
, &margin
, &extsegs
);
6135 if (tmpstr
[0] != '\0')
6136 ostr
[segs
] = tmpstr
;
6143 /* Write string array to output in reverse order */
6144 for (i
= segs
- 1; i
>= 0; i
--) {
6145 dostcount(ps
, stcount
, strlen(ostr
[i
]));
6151 return segs
+ extsegs
;
6154 /*--------------------------------------------------------------*/
6155 /* Write a single label segment to the output */
6156 /* (Recursive, so we can write segments in the reverse order) */
6157 /*--------------------------------------------------------------*/
6159 char *writesegment(stringpart
*chrptr
, float *lastscale
, int *lastfont
, int *margin
,
6162 int type
= chrptr
->type
;
6163 char *retstr
, *validname
;
6167 validname
= create_valid_psname(chrptr
->data
.string
, TRUE
);
6168 sprintf(_STR
, "%s ", validname
);
6172 chrptr
->nextpart
= NULL
;
6175 sprintf(_STR
, "{ss} ");
6178 sprintf(_STR
, "{Ss} ");
6182 sprintf(_STR
, "{ns} ");
6185 sprintf(_STR
, "{ul} ");
6188 sprintf(_STR
, "{ol} ");
6191 sprintf(_STR
, "{} ");
6194 sprintf(_STR
, "{hS} ");
6197 sprintf(_STR
, "{qS} ");
6201 if (chrptr
->data
.flags
== 0)
6202 // Ignore automatically-generated line breaks
6203 sprintf(_STR
, "{CR} ");
6208 sprintf(_STR
, "{Ts} ");
6211 sprintf(_STR
, "{Tf} ");
6214 sprintf(_STR
, "{Tb} ");
6217 /* If font specifier is followed by a scale specifier, then */
6218 /* record the font change but defer the output. Otherwise, */
6219 /* output the font record now. */
6221 if ((chrptr
->nextpart
== NULL
) || (chrptr
->nextpart
->type
!= FONT_SCALE
))
6223 if (*lastscale
== 1.0)
6224 sprintf(_STR
, "{/%s cf} ", fonts
[chrptr
->data
.font
].psname
);
6226 sprintf(_STR
, "{/%s %5.3f cf} ", fonts
[chrptr
->data
.font
].psname
,
6231 *lastfont
= chrptr
->data
.font
;
6234 if (*lastfont
== -1) {
6235 Fprintf(stderr
, "Warning: Font may not be the one that was intended.\n");
6238 *lastscale
= chrptr
->data
.scale
;
6239 sprintf(_STR
, "{/%s %5.3f cf} ", fonts
[*lastfont
].psname
, *lastscale
);
6243 if (chrptr
->data
.color
== DEFAULTCOLOR
)
6244 strcat(_STR
, "sce} ");
6246 if (printRGBvalues(_STR
+ 1, chrptr
->data
.color
, "scb} ") < 0)
6247 strcat(_STR
, "sce} ");
6250 sprintf(_STR
, "{%d MR} ", chrptr
->data
.width
);
6251 *margin
= chrptr
->data
.width
;
6254 sprintf(_STR
, "{%d %d Kn} ", chrptr
->data
.kern
[0], chrptr
->data
.kern
[1]);
6257 /* Everything except TEXT_STRING will always fit in the _STR fixed- */
6258 /* length character array. */
6259 return nosprint(chrptr
->data
.string
, margin
, extsegs
);
6262 retstr
= (char *)malloc(1 + strlen(_STR
));
6263 strcpy(retstr
, _STR
);
6267 /*--------------------------------------------------------------*/
6268 /* Routine to write all the label segments as stored in _STR */
6269 /*--------------------------------------------------------------*/
6271 int writelabelsegs(FILE *ps
, short *stcount
, stringpart
*chrptr
)
6273 Boolean ismultipart
;
6276 if (chrptr
== NULL
) return 0;
6278 ismultipart
= ((chrptr
->nextpart
!= NULL
) &&
6279 (chrptr
->nextpart
->type
!= PARAM_END
)) ? True
: False
;
6281 /* If there is only one part, but it is not a string or the */
6282 /* end of a parameter (empty parameter), then set multipart */
6283 /* anyway so we get the double brace {{ }}. */
6285 if ((!ismultipart
) && (chrptr
->type
!= TEXT_STRING
) &&
6286 (chrptr
->type
!= PARAM_END
))
6289 /* nextpart is not NULL if there are multiple parts to the string */
6294 segs
= writelabel(ps
, chrptr
, stcount
);
6303 /*--------------------------------------------------------------*/
6304 /* Write the dictionary of parameters belonging to an object */
6305 /*--------------------------------------------------------------*/
6307 void printobjectparams(FILE *ps
, objectptr localdata
)
6312 char *ps_expr
, *validkey
;
6315 /* Check for parameters and default values */
6316 if (localdata
->params
== NULL
) return;
6321 for (ops
= localdata
->params
; ops
!= NULL
; ops
= ops
->next
) {
6322 validkey
= create_valid_psname(ops
->key
, TRUE
);
6323 fprintf(ps
, "/%s ", validkey
);
6324 dostcount (ps
, &stcount
, strlen(validkey
) + 2);
6326 switch (ops
->type
) {
6328 ps_expr
= evaluate_expr(localdata
, ops
, NULL
);
6329 if (ops
->which
== P_SUBSTRING
|| ops
->which
== P_EXPRESSION
) {
6330 dostcount(ps
, &stcount
, 3 + strlen(ps_expr
));
6335 else if (ops
->which
== P_COLOR
) {
6337 /* Write R, G, B components for PostScript */
6338 if (sscanf(ps_expr
, "%d", &ccol
) == 1) {
6340 printRGBvalues(_STR
, ccol
, "} ");
6341 dostcount(ps
, &stcount
, 1 + strlen(_STR
));
6345 dostcount(ps
, &stcount
, 8);
6346 fputs("{0 0 0} ", ps
);
6349 else if (sscanf(ps_expr
, "%g", &fp
) == 1) {
6350 dostcount(ps
, &stcount
, 1 + strlen(ps_expr
));
6354 else { /* Expression evaluates to error in object */
6355 dostcount(ps
, &stcount
, 2);
6358 dostcount(ps
, &stcount
, 7 + strlen(ops
->parameter
.expr
));
6360 fputs(ops
->parameter
.expr
, ps
);
6361 fputs(") pop ", ps
);
6365 segs
= writelabelsegs(ps
, &stcount
, ops
->parameter
.string
);
6367 /* When writing object parameters, we cannot allow a */
6368 /* NULL value. Instead, print an empty string (). */
6369 dostcount(ps
, &stcount
, 3);
6374 sprintf(_STR
, "%d ", ops
->parameter
.ivalue
);
6375 dostcount(ps
, &stcount
, strlen(_STR
));
6379 sprintf(_STR
, "%g ", ops
->parameter
.fvalue
);
6380 dostcount(ps
, &stcount
, strlen(_STR
));
6387 dostcount (ps
, &stcount
, 3);
6390 /*--------------------------------------------------------------*/
6391 /* Write the list of parameters belonging to an object instance */
6392 /*--------------------------------------------------------------*/
6394 short printparams(FILE *ps
, objinstptr sinst
, short stcount
)
6398 oparamptr ops
, objops
;
6400 char *ps_expr
, *validkey
, *validref
;
6401 short instances
= 0;
6403 if (sinst
->params
== NULL
) return stcount
;
6405 for (ops
= sinst
->params
; ops
!= NULL
; ops
= ops
->next
) {
6406 validref
= strdup(create_valid_psname(ops
->key
, TRUE
));
6408 /* Check for indirect parameter references */
6409 for (epp
= sinst
->passed
; epp
!= NULL
; epp
= epp
->next
) {
6410 if ((epp
->flags
& P_INDIRECT
) && (epp
->pdata
.refkey
!= NULL
)) {
6411 if (!strcmp(epp
->pdata
.refkey
, ops
->key
)) {
6412 if (instances
++ == 0) {
6413 fprintf(ps
, "<<"); /* begin PostScript dictionary */
6414 loccount
= stcount
+ 2;
6416 dostcount(ps
, &loccount
, strlen(validref
+ 3));
6417 fprintf(ps
, "/%s ", validref
);
6418 dostcount(ps
, &loccount
, strlen(epp
->key
+ 1));
6419 validkey
= create_valid_psname(epp
->key
, TRUE
);
6420 fprintf(ps
, "%s ", validkey
);
6425 if (epp
== NULL
) { /* No indirection */
6426 Boolean nondefault
= TRUE
;
6427 char *deflt_expr
= NULL
;
6429 /* For instance values that are expression results, ignore if */
6430 /* the instance value is the same as the default value. */
6431 /* Correction 9/08: We can't second-guess expression results, */
6432 /* in particular, this doesn't work for an expression like */
6433 /* "page", where the local and default values will evaluate to */
6434 /* the same result, when clearly each page is intended to have */
6435 /* its own instance value, and "page" for an object is not a */
6436 /* well-defined concept. */
6439 // objops = match_param(sinst->thisobject, ops->key);
6440 // if (objops && (objops->type == XC_EXPR)) {
6443 // deflt_expr = evaluate_expr(sinst->thisobject, objops, NULL);
6444 // switch (ops->type) {
6446 // if (!textcomp(ops->parameter.string, deflt_expr, sinst))
6447 // nondefault = FALSE;
6450 // ps_expr = evaluate_expr(sinst->thisobject, ops, sinst);
6451 // if (!strcmp(ps_expr, deflt_expr)) nondefault = FALSE;
6454 // sscanf(deflt_expr, "%d", &i);
6455 // if (i == ops->parameter.ivalue) nondefault = FALSE;
6458 // sscanf(deflt_expr, "%g", &f);
6459 // if (f == ops->parameter.fvalue) nondefault = FALSE;
6462 // if (deflt_expr) free(deflt_expr);
6463 // if (nondefault == FALSE) {
6464 // if (ps_expr) free(ps_expr);
6469 if (instances
++ == 0) {
6470 fprintf(ps
, "<<"); /* begin PostScript dictionary */
6471 loccount
= stcount
+ 2;
6473 dostcount(ps
, &loccount
, strlen(validref
) + 2);
6474 fprintf(ps
, "/%s ", validref
);
6476 switch (ops
->type
) {
6478 segs
= writelabelsegs(ps
, &loccount
, ops
->parameter
.string
);
6480 /* When writing object parameters, we cannot allow a */
6481 /* NULL value. Instead, print an empty string (). */
6482 dostcount(ps
, &stcount
, 3);
6487 ps_expr
= evaluate_expr(sinst
->thisobject
, ops
, sinst
);
6488 dostcount(ps
, &loccount
, 3 + strlen(ps_expr
));
6494 /* The instance parameter expression may have the */
6495 /* same expression as the object but a different */
6496 /* result if the expression uses another parameter. */
6497 /* Only print the expression itself if it's different */
6498 /* from the object's expression. */
6500 objops
= match_param(sinst
->thisobject
, ops
->key
);
6501 if (objops
&& strcmp(ops
->parameter
.expr
, objops
->parameter
.expr
)) {
6502 dostcount(ps
, &loccount
, 3 + strlen(ops
->parameter
.expr
));
6504 fputs(ops
->parameter
.expr
, ps
);
6505 fputs(") pop ", ps
);
6509 if (ops
->which
== P_COLOR
) {
6510 /* Write R, G, B components */
6512 printRGBvalues(_STR
+ 1, ops
->parameter
.ivalue
, "} ");
6515 sprintf(_STR
, "%d ", ops
->parameter
.ivalue
);
6516 dostcount(ps
, &loccount
, strlen(_STR
));
6520 sprintf(_STR
, "%g ", ops
->parameter
.fvalue
);
6521 dostcount(ps
, &loccount
, strlen(_STR
));
6528 if (instances
> 0) {
6529 fprintf(ps
, ">> "); /* end PostScript dictionary */
6535 /*------------------------------------------------------------------*/
6536 /* Macro for point output (calls varpcheck() on x and y components) */
6537 /*------------------------------------------------------------------*/
6539 #define xyvarcheck(z, n, t) \
6540 varpcheck(ps, (z).x, localdata, n, &stcount, *(t), P_POSITION_X); \
6541 varpcheck(ps, (z).y, localdata, n, &stcount, *(t), P_POSITION_Y)
6543 #define xypathcheck(z, n, t, p) \
6544 varpathcheck(ps, (z).x, localdata, n, &stcount, t, TOPATH(p), P_POSITION_X); \
6545 varpathcheck(ps, (z).y, localdata, n, &stcount, t, TOPATH(p), P_POSITION_Y)
6547 /*--------------------------------------------------------------*/
6548 /* Main routine for writing the contents of a single object to */
6549 /* output file "ps". */
6550 /*--------------------------------------------------------------*/
6552 void printOneObject(FILE *ps
, objectptr localdata
, int ccolor
)
6554 int i
, curcolor
= ccolor
;
6555 genericptr
*savegen
, *pgen
;
6562 Boolean has_parameter
;
6563 char *fptr
, *validname
;
6565 /* first, get a total count of all objects and give warning if large */
6567 if ((is_page(localdata
) == -1) && (localdata
->parts
> 255)) {
6568 Wprintf("Warning: \"%s\" may exceed printer's PS limit for definitions",
6572 for (savegen
= localdata
->plist
; savegen
< localdata
->plist
+
6573 localdata
->parts
; savegen
++) {
6575 /* Check if this color is parameterized */
6579 /* FIXEDBBOX style is handled in the object header and */
6580 /* the part should be skipped. */
6582 if (ELEMENTTYPE(*savegen
) == POLYGON
)
6583 if (TOPOLY(savegen
)->style
& FIXEDBBOX
)
6586 for (epp
= (*savegen
)->passed
; epp
!= NULL
; epp
= epp
->next
) {
6587 ops
= match_param(localdata
, epp
->key
);
6588 if (ops
!= NULL
&& (ops
->which
== P_COLOR
)) {
6589 /* Ensure that the next element forces a color change */
6590 curcolor
= ERRORCOLOR
;
6591 sprintf(_STR
, "%s scb\n", epp
->key
);
6597 /* Enforce the rule that clipmasks must always be DEFAULTCOLOR */
6599 switch(ELEMENTTYPE(*savegen
)) {
6600 case POLYGON
: case SPLINE
: case ARC
: case PATH
:
6601 if (TOPOLY(savegen
)->style
& CLIPMASK
)
6602 (*savegen
)->color
= DEFAULTCOLOR
;
6606 /* change current color if different */
6608 if ((epp
== NULL
) && ((*savegen
)->color
!= curcolor
)) {
6609 if ((curcolor
= (*savegen
)->color
) == DEFAULTCOLOR
)
6610 fprintf(ps
, "sce\n");
6612 if (printRGBvalues(_STR
, (*savegen
)->color
, "scb\n") < 0) {
6613 fprintf(ps
, "sce\n");
6614 curcolor
= DEFAULTCOLOR
;
6622 switch(ELEMENTTYPE(*savegen
)) {
6625 varcheck(ps
, TOPOLY(savegen
)->style
, localdata
, &stcount
,
6627 varfcheck(ps
, TOPOLY(savegen
)->width
, localdata
, &stcount
,
6628 *savegen
, P_LINEWIDTH
);
6629 for (savept
= TOPOLY(savegen
)->points
; savept
< TOPOLY(savegen
)->
6630 points
+ TOPOLY(savegen
)->number
; savept
++) {
6631 varpcheck(ps
, savept
->x
, localdata
,
6632 savept
- TOPOLY(savegen
)->points
, &stcount
, *savegen
,
6634 varpcheck(ps
, savept
->y
, localdata
,
6635 savept
- TOPOLY(savegen
)->points
, &stcount
, *savegen
,
6638 sprintf(_STR
, "%hd ", TOPOLY(savegen
)->number
);
6639 dostcount (ps
, &stcount
, strlen(_STR
));
6641 if (varpcheck(ps
, 0, localdata
, -1, &stcount
, *savegen
,
6643 sprintf(_STR
, "addtox ");
6644 dostcount (ps
, &stcount
, strlen(_STR
));
6647 if (varpcheck(ps
, 0, localdata
, -1, &stcount
, *savegen
,
6649 sprintf(_STR
, "addtoy ");
6650 dostcount (ps
, &stcount
, strlen(_STR
));
6653 sprintf(_STR
, "polygon\n");
6654 dostcount (ps
, &stcount
, strlen(_STR
));
6659 pgen
= TOPATH(savegen
)->plist
;
6660 switch(ELEMENTTYPE(*pgen
)) {
6662 xypathcheck(TOPOLY(pgen
)->points
[0], 0, pgen
, savegen
);
6665 xypathcheck(TOSPLINE(pgen
)->ctrl
[0], 0, pgen
, savegen
);
6668 dostcount(ps
, &stcount
, 9);
6669 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6670 TOPATH(savegen
), P_POSITION_X
)) {
6671 sprintf(_STR
, "addtox1 ");
6672 dostcount (ps
, &stcount
, strlen(_STR
));
6675 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6676 TOPATH(savegen
), P_POSITION_Y
)) {
6677 sprintf(_STR
, "addtoy1 ");
6678 dostcount (ps
, &stcount
, strlen(_STR
));
6681 fprintf(ps
, "beginpath\n");
6682 for (pgen
= TOPATH(savegen
)->plist
; pgen
< TOPATH(savegen
)->plist
6683 + TOPATH(savegen
)->parts
; pgen
++) {
6684 switch(ELEMENTTYPE(*pgen
)) {
6686 for (savept
= TOPOLY(pgen
)->points
+ TOPOLY(pgen
)->number
6687 - 1; savept
> TOPOLY(pgen
)->points
; savept
--) {
6688 xypathcheck(*savept
, savept
- TOPOLY(pgen
)->points
, pgen
,
6691 sprintf(_STR
, "%hd ", TOPOLY(pgen
)->number
- 1);
6692 dostcount (ps
, &stcount
, strlen(_STR
));
6694 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6695 TOPATH(savegen
), P_POSITION_X
)) {
6696 sprintf(_STR
, "addtox ");
6697 dostcount (ps
, &stcount
, strlen(_STR
));
6700 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6701 TOPATH(savegen
), P_POSITION_Y
)) {
6702 sprintf(_STR
, "addtoy ");
6703 dostcount (ps
, &stcount
, strlen(_STR
));
6706 sprintf(_STR
, "polyc\n");
6707 dostcount (ps
, &stcount
, strlen(_STR
));
6711 xypathcheck(TOSPLINE(pgen
)->ctrl
[1], 1, pgen
, savegen
);
6712 xypathcheck(TOSPLINE(pgen
)->ctrl
[2], 2, pgen
, savegen
);
6713 xypathcheck(TOSPLINE(pgen
)->ctrl
[3], 3, pgen
, savegen
);
6714 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6715 TOPATH(savegen
), P_POSITION_X
)) {
6716 sprintf(_STR
, "addtox3 ");
6717 dostcount (ps
, &stcount
, strlen(_STR
));
6720 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6721 TOPATH(savegen
), P_POSITION_Y
)) {
6722 sprintf(_STR
, "addtoy3 ");
6723 dostcount (ps
, &stcount
, strlen(_STR
));
6726 fprintf(ps
, "curveto\n");
6730 varcheck(ps
, TOPATH(savegen
)->style
, localdata
, &stcount
,
6732 varfcheck(ps
, TOPATH(savegen
)->width
, localdata
, &stcount
,
6733 *savegen
, P_LINEWIDTH
);
6734 fprintf(ps
, "endpath\n");
6738 varcheck(ps
, TOSPLINE(savegen
)->style
, localdata
, &stcount
,
6740 varfcheck(ps
, TOSPLINE(savegen
)->width
, localdata
, &stcount
,
6741 *savegen
, P_LINEWIDTH
);
6742 xyvarcheck(TOSPLINE(savegen
)->ctrl
[1], 1, savegen
);
6743 xyvarcheck(TOSPLINE(savegen
)->ctrl
[2], 2, savegen
);
6744 xyvarcheck(TOSPLINE(savegen
)->ctrl
[3], 3, savegen
);
6745 xyvarcheck(TOSPLINE(savegen
)->ctrl
[0], 0, savegen
);
6746 if (varpcheck(ps
, 0, localdata
, -1, &stcount
, *savegen
,
6748 sprintf(_STR
, "addtox4 ");
6749 dostcount (ps
, &stcount
, strlen(_STR
));
6752 if (varpcheck(ps
, 0, localdata
, -1, &stcount
, *savegen
,
6754 sprintf(_STR
, "addtoy4 ");
6755 dostcount (ps
, &stcount
, strlen(_STR
));
6758 fprintf(ps
, "spline\n");
6762 varcheck(ps
, TOARC(savegen
)->style
, localdata
, &stcount
,
6764 varfcheck(ps
, TOARC(savegen
)->width
, localdata
, &stcount
,
6765 *savegen
, P_LINEWIDTH
);
6766 xyvarcheck(TOARC(savegen
)->position
, 0, savegen
);
6767 varcheck(ps
, abs(TOARC(savegen
)->radius
), localdata
, &stcount
,
6768 *savegen
, P_RADIUS
);
6769 if (abs(TOARC(savegen
)->radius
) == TOARC(savegen
)->yaxis
) {
6770 varfcheck(ps
, TOARC(savegen
)->angle1
, localdata
, &stcount
,
6771 *savegen
, P_ANGLE1
);
6772 varfcheck(ps
, TOARC(savegen
)->angle2
, localdata
, &stcount
,
6773 *savegen
, P_ANGLE2
);
6774 fprintf(ps
, "xcarc\n");
6777 varcheck(ps
, abs(TOARC(savegen
)->yaxis
), localdata
, &stcount
,
6778 *savegen
, P_MINOR_AXIS
);
6779 varfcheck(ps
, TOARC(savegen
)->angle1
, localdata
, &stcount
,
6780 *savegen
, P_ANGLE1
);
6781 varfcheck(ps
, TOARC(savegen
)->angle2
, localdata
, &stcount
,
6782 *savegen
, P_ANGLE2
);
6783 fprintf(ps
, "ellipse\n");
6788 sobj
= TOOBJINST(savegen
);
6789 varfcheck(ps
, sobj
->scale
, localdata
, &stcount
, *savegen
, P_SCALE
);
6790 if (!(sobj
->style
& LINE_INVARIANT
)) fprintf(ps
, "/sv ");
6791 varfcheck(ps
, sobj
->rotation
, localdata
, &stcount
, *savegen
, P_ROTATION
);
6792 xyvarcheck(sobj
->position
, 0, savegen
);
6794 opsubstitute(sobj
->thisobject
, sobj
);
6795 stcount
= printparams(ps
, sobj
, stcount
);
6797 validname
= create_valid_psname(sobj
->thisobject
->name
, FALSE
);
6799 /* Names without technologies get a leading string '::' */
6800 /* (blank technology) */
6802 if (strstr(validname
, "::") == NULL
)
6803 fprintf(ps
, "::%s\n", validname
);
6805 fprintf(ps
, "%s\n", validname
);
6809 sg
= TOGRAPHIC(savegen
);
6810 for (i
= 0; i
< xobjs
.images
; i
++) {
6811 img
= xobjs
.imagelist
+ i
;
6812 if (img
->image
== sg
->source
)
6816 fptr
= strrchr(img
->filename
, '/');
6818 fptr
= img
->filename
;
6821 fprintf(ps
, "/%s ", fptr
);
6822 stcount
+= (2 + strlen(fptr
));
6824 varfcheck(ps
, sg
->scale
, localdata
, &stcount
, *savegen
, P_SCALE
);
6825 varfcheck(ps
, sg
->rotation
, localdata
, &stcount
, *savegen
, P_ROTATION
);
6826 xyvarcheck(sg
->position
, 0, savegen
);
6827 fprintf(ps
, "graphic\n");
6832 /* Don't save temporary labels from schematic capture system */
6833 if (TOLABEL(savegen
)->string
->type
!= FONT_NAME
) break;
6835 /* Check for parameter --- must use "mark" to count # segments */
6836 has_parameter
= hasparameter(TOLABEL(savegen
));
6838 if (has_parameter
) {
6839 fprintf(ps
, "mark ");
6843 segs
= writelabel(ps
, TOLABEL(savegen
)->string
, &stcount
);
6847 sprintf(_STR
, "ctmk ");
6849 sprintf(_STR
, "%hd ", segs
);
6850 dostcount(ps
, &stcount
, strlen(_STR
));
6852 varcheck(ps
, TOLABEL(savegen
)->anchor
, localdata
, &stcount
,
6853 *savegen
, P_ANCHOR
);
6854 varfcheck(ps
, TOLABEL(savegen
)->rotation
, localdata
, &stcount
,
6855 *savegen
, P_ROTATION
);
6856 varfcheck(ps
, TOLABEL(savegen
)->scale
, localdata
, &stcount
,
6858 xyvarcheck(TOLABEL(savegen
)->position
, 0, savegen
);
6860 switch(TOLABEL(savegen
)->pin
) {
6862 strcpy(_STR
, "pinlabel\n"); break;
6864 strcpy(_STR
, "pinglobal\n"); break;
6866 strcpy(_STR
, "infolabel\n"); break;
6868 strcpy(_STR
, "label\n");
6870 dostcount(ps
, &stcount
, strlen(_STR
));
6878 /*----------------------------------------------------------------------*/
6879 /* Recursive routine to print out the library objects used in this */
6880 /* drawing, starting at the bottom of the object hierarchy so that each */
6881 /* object is defined before it is called. A list of objects already */
6882 /* written is maintained so that no object is written twice. */
6884 /* When object "localdata" is not a top-level page, call this routine */
6885 /* with mpage=-1 (simpler than checking whether localdata is a page). */
6886 /*----------------------------------------------------------------------*/
6888 void printobjects(FILE *ps
, objectptr localdata
, objectptr
**wrotelist
,
6889 short *written
, int ccolor
)
6891 genericptr
*gptr
, *savegen
;
6893 /* oparamptr ops; (jdk) */
6895 int curcolor
= ccolor
;
6896 /* int libno; (jdk) */
6898 /* Search among the list of objects already written to the output */
6899 /* If this object has been written previously, then we ignore it. */
6901 for (optr
= *wrotelist
; optr
< *wrotelist
+ *written
; optr
++)
6902 if (*optr
== localdata
)
6905 /* If this page is a schematic, write out the definiton of any symbol */
6906 /* attached to it, because that symbol may not be used anywhere else. */
6908 if (localdata
->symschem
&& (localdata
->schemtype
== PRIMARY
))
6909 printobjects(ps
, localdata
->symschem
, wrotelist
, written
, curcolor
);
6911 /* Search for all object definitions instantiated in this object, */
6912 /* and (recursively) print them to the output. */
6914 for (gptr
= localdata
->plist
; gptr
< localdata
->plist
+ localdata
->parts
; gptr
++)
6915 if (IS_OBJINST(*gptr
))
6916 printobjects(ps
, TOOBJINST(gptr
)->thisobject
, wrotelist
, written
, curcolor
);
6918 /* Update the list of objects already written to the output */
6920 *wrotelist
= (objectptr
*)realloc(*wrotelist
, (*written
+ 1) *
6922 *(*wrotelist
+ *written
) = localdata
;
6925 validname
= create_valid_psname(localdata
->name
, FALSE
);
6926 if (strstr(validname
, "::") == NULL
)
6927 fprintf(ps
, "/::%s {\n", validname
);
6929 fprintf(ps
, "/%s {\n", validname
);
6931 /* Write a "bbox" record if there is an element with style FIXEDBBOX */
6932 /* This is the only time a "bbox" record is written for an object. */
6934 for (savegen
= localdata
->plist
; savegen
< localdata
->plist
+
6935 localdata
->parts
; savegen
++) {
6936 if (ELEMENTTYPE(*savegen
) == POLYGON
) {
6937 if (TOPOLY(savegen
)->style
& FIXEDBBOX
) {
6938 pointlist polypoints
;
6940 polypoints
= TOPOLY(savegen
)->points
+ 2;
6941 width
= polypoints
->x
;
6942 height
= polypoints
->y
;
6943 polypoints
= TOPOLY(savegen
)->points
;
6944 width
-= polypoints
->x
;
6945 height
-= polypoints
->y
;
6946 fprintf(ps
, "%% %d %d %d %d bbox\n",
6947 polypoints
->x
, polypoints
->y
,
6954 if (localdata
->hidden
== True
) fprintf(ps
, "%% hidden\n");
6956 /* For symbols with schematics, and "trivial" schematics */
6957 if (localdata
->symschem
!= NULL
)
6958 fprintf(ps
, "%% %s is_schematic\n", localdata
->symschem
->name
);
6959 else if (localdata
->schemtype
== TRIVIAL
)
6960 fprintf(ps
, "%% trivial\n");
6961 else if (localdata
->schemtype
== NONETWORK
)
6962 fprintf(ps
, "%% nonetwork\n");
6964 printobjectparams(ps
, localdata
);
6965 fprintf(ps
, "begingate\n");
6967 /* Write all the elements in order */
6969 opsubstitute(localdata
, NULL
);
6970 printOneObject(ps
, localdata
, curcolor
);
6972 /* Write object (gate) trailer */
6974 fprintf(ps
, "endgate\n} def\n\n");
6977 /*--------------------------------------------------------------*/
6978 /* Print a page header followed by everything in the page. */
6979 /* this routine assumes that all objects used by the page have */
6980 /* already been handled and written to the output. */
6982 /* "page" is the page number, counting consecutively from one. */
6983 /* "mpage" is the page number in xcircuit's pagelist structure. */
6984 /*--------------------------------------------------------------*/
6986 void printpageobject(FILE *ps
, objectptr localdata
, short page
, short mpage
)
6988 /* genericptr *gptr; (jdk) */
6989 XPoint origin
, corner
;
6990 objinstptr writepage
;
6992 float psnorm
, psscale
;
6993 float xmargin
, ymargin
;
6994 char *rootptr
= NULL
;
6997 /* Output page header information */
6999 if (xobjs
.pagelist
[mpage
]->filename
)
7000 rootptr
= strrchr(xobjs
.pagelist
[mpage
]->filename
, '/');
7001 if (rootptr
== NULL
)
7002 rootptr
= xobjs
.pagelist
[mpage
]->filename
;
7005 writepage
= xobjs
.pagelist
[mpage
]->pageinst
;
7007 psnorm
= xobjs
.pagelist
[mpage
]->outscale
;
7008 psscale
= getpsscale(psnorm
, mpage
);
7010 /* Determine the margins (offset of drawing from page corner) */
7011 /* If a bounding box has been declared in the drawing, it is */
7012 /* centered on the page. Otherwise, the drawing itself is */
7013 /* centered on the page. If encapsulated, the bounding box */
7014 /* encompasses only the object itself. */
7016 width
= toplevelwidth(writepage
, &origin
.x
);
7017 height
= toplevelheight(writepage
, &origin
.y
);
7019 corner
.x
= origin
.x
+ width
;
7020 corner
.y
= origin
.y
+ height
;
7022 if (xobjs
.pagelist
[mpage
]->pmode
& 1) { /* full page */
7024 if (xobjs
.pagelist
[mpage
]->orient
== 90) {
7025 xmargin
= (xobjs
.pagelist
[mpage
]->pagesize
.x
-
7026 ((float)height
* psscale
)) / 2;
7027 ymargin
= (xobjs
.pagelist
[mpage
]->pagesize
.y
-
7028 ((float)width
* psscale
)) / 2;
7031 xmargin
= (xobjs
.pagelist
[mpage
]->pagesize
.x
-
7032 ((float)width
* psscale
)) / 2;
7033 ymargin
= (xobjs
.pagelist
[mpage
]->pagesize
.y
-
7034 ((float)height
* psscale
)) / 2;
7037 else { /* encapsulated --- should have 1" border so that any */
7038 /* drawing passed directly to a printer will not clip */
7039 xmargin
= xobjs
.pagelist
[mpage
]->margins
.x
;
7040 ymargin
= xobjs
.pagelist
[mpage
]->margins
.y
;
7043 /* If a framebox is declared, then we adjust the page to be */
7044 /* centered on the framebox by translating through the */
7045 /* difference between the object center and the framebox */
7048 if ((framebox
= checkforbbox(localdata
)) != NULL
) {
7049 int i
, fcentx
= 0, fcenty
= 0;
7051 for (i
= 0; i
< framebox
->number
; i
++) {
7052 fcentx
+= framebox
->points
[i
].x
;
7053 fcenty
+= framebox
->points
[i
].y
;
7055 fcentx
/= framebox
->number
;
7056 fcenty
/= framebox
->number
;
7058 xmargin
+= psscale
* (float)(origin
.x
+ (width
>> 1) - fcentx
);
7059 ymargin
+= psscale
* (float)(origin
.y
+ (height
>> 1) - fcenty
);
7062 /* If the page label is just the root name of the file, or has been left */
7063 /* as "Page n" or "Page_n", just do the normal page numbering. Otherwise, */
7064 /* write out the page label explicitly. */
7066 if ((rootptr
== NULL
) || (!strcmp(rootptr
, localdata
->name
))
7067 || (strchr(localdata
->name
, ' ') != NULL
)
7068 || (strstr(localdata
->name
, "Page_") != NULL
))
7069 fprintf (ps
, "%%%%Page: %d %d\n", page
, page
);
7071 fprintf (ps
, "%%%%Page: %s %d\n", localdata
->name
, page
);
7073 if (xobjs
.pagelist
[mpage
]->orient
== 90)
7074 fprintf (ps
, "%%%%PageOrientation: Landscape\n");
7076 fprintf (ps
, "%%%%PageOrientation: Portrait\n");
7078 if (xobjs
.pagelist
[mpage
]->pmode
& 1) { /* full page */
7079 fprintf(ps
, "%%%%PageBoundingBox: 0 0 %d %d\n",
7080 xobjs
.pagelist
[mpage
]->pagesize
.x
,
7081 xobjs
.pagelist
[mpage
]->pagesize
.y
);
7084 /* Encapsulated files do not get a PageBoundingBox line, */
7085 /* unless the bounding box was explicitly drawn. */
7087 else if (framebox
!= NULL
) {
7088 fprintf(ps
, "%%%%PageBoundingBox: %g %g %g %g\n",
7090 xmargin
+ psscale
* (float)(width
),
7091 ymargin
+ psscale
* (float)(height
));
7094 fprintf (ps
, "/pgsave save def bop\n");
7096 /* Top-page definitions */
7097 if (localdata
->params
!= NULL
) {
7098 printobjectparams(ps
, localdata
);
7099 fprintf(ps
, "begin\n");
7102 if (localdata
->symschem
!= NULL
) {
7103 if (is_page(localdata
->symschem
) == -1)
7104 fprintf(ps
, "%% %s is_symbol\n", localdata
->symschem
->name
);
7105 else if (localdata
->schemtype
== SECONDARY
)
7106 fprintf(ps
, "%% %s is_primary\n", localdata
->symschem
->name
);
7108 Wprintf("Something is wrong. . . schematic \"%s\" is connected to"
7109 " schematic \"%s\" but is not declared secondary.\n",
7110 localdata
->name
, localdata
->symschem
->name
);
7113 /* Extend bounding box around schematic pins */
7114 extendschembbox(xobjs
.pagelist
[mpage
]->pageinst
, &origin
, &corner
);
7116 if (xobjs
.pagelist
[mpage
]->drawingscale
.x
!= 1
7117 || xobjs
.pagelist
[mpage
]->drawingscale
.y
!= 1)
7118 fprintf(ps
, "%% %hd:%hd drawingscale\n", xobjs
.pagelist
[mpage
]->drawingscale
.x
,
7119 xobjs
.pagelist
[mpage
]->drawingscale
.y
);
7121 if (xobjs
.pagelist
[mpage
]->gridspace
!= 32
7122 || xobjs
.pagelist
[mpage
]->snapspace
!= 16)
7123 fprintf(ps
, "%% %4.2f %4.2f gridspace\n", xobjs
.pagelist
[mpage
]->gridspace
,
7124 xobjs
.pagelist
[mpage
]->snapspace
);
7126 if (xobjs
.pagelist
[mpage
]->background
.name
!= (char *)NULL
) {
7127 /* float iscale = (xobjs.pagelist[mpage]->coordstyle == CM) ? CMSCALE : INCHSCALE; (jdk) */
7128 if (xobjs
.pagelist
[mpage
]->orient
== 90)
7129 fprintf(ps
, "%5.4f %d %d 90 psinsertion\n", psnorm
,
7130 (int)(ymargin
- xmargin
),
7131 -((int)((float)(corner
.y
- origin
.y
) * psscale
) +
7132 (int)(xmargin
+ ymargin
)));
7134 fprintf(ps
, "%5.4f %d %d 0 psinsertion\n", psnorm
,
7135 (int)(xmargin
/ psscale
) - origin
.x
,
7136 (int)(ymargin
/ psscale
) - origin
.y
);
7137 savebackground(ps
, xobjs
.pagelist
[mpage
]->background
.name
);
7138 fprintf(ps
, "\nend_insert\n");
7141 if (xobjs
.pagelist
[mpage
]->orient
== 90)
7142 fprintf(ps
, "90 rotate %d %d translate\n", (int)(ymargin
- xmargin
),
7143 -((int)((float)(corner
.y
- origin
.y
) * psscale
) +
7144 (int)(xmargin
+ ymargin
)));
7146 fprintf(ps
, "%5.4f ", psnorm
);
7147 switch(xobjs
.pagelist
[mpage
]->coordstyle
) {
7149 fprintf(ps
, "cmscale\n");
7152 fprintf(ps
, "inchscale\n");
7156 /* Final scale and translation */
7157 fprintf(ps
, "%5.4f setlinewidth %d %d translate\n\n",
7158 1.3 * xobjs
.pagelist
[mpage
]->wirewidth
,
7159 (int)(xmargin
/ psscale
) - origin
.x
,
7160 (int)(ymargin
/ psscale
) - origin
.y
);
7162 /* Output all the elements in the page */
7163 printOneObject(ps
, localdata
, DEFAULTCOLOR
);
7166 if (localdata
->params
!= NULL
) fprintf(ps
, "end ");
7167 fprintf(ps
, "pgsave restore showpage\n");
7170 /*--------------------------------------------------------------*/
7171 /* Print objects referenced from a particular page. These get */
7172 /* bundled together at the beginning of the output file under */
7173 /* the DSC "Setup" section, so that the PostScript */
7174 /* interpreter knows that these definitions may be used by any */
7175 /* page. This prevents ghostscript from producing an error */
7176 /* when backing up in a multi-page document. */
7177 /*--------------------------------------------------------------*/
7179 void printrefobjects(FILE *ps
, objectptr localdata
, objectptr
**wrotelist
,
7184 /* If this page is a schematic, write out the definiton of any symbol */
7185 /* attached to it, because that symbol may not be used anywhere else. */
7187 if (localdata
->symschem
&& (localdata
->schemtype
== PRIMARY
))
7188 printobjects(ps
, localdata
->symschem
, wrotelist
, written
, DEFAULTCOLOR
);
7190 /* Search for all object definitions instantiated on the page and */
7191 /* write them to the output. */
7193 for (gptr
= localdata
->plist
; gptr
< localdata
->plist
+ localdata
->parts
; gptr
++)
7194 if (IS_OBJINST(*gptr
))
7195 printobjects(ps
, TOOBJINST(gptr
)->thisobject
, wrotelist
, written
,
7199 /*----------------------------------------------------------------------*/