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 */
60 /*------------------------------------------------------------------------*/
61 /* External Variable definitions */
62 /*------------------------------------------------------------------------*/
65 extern Tcl_Interp
*xcinterp
;
68 extern char _STR2
[250], _STR
[150];
69 extern Globaldata xobjs
;
70 extern XCWindowData
*areawin
;
71 extern fontinfo
*fonts
;
72 extern short fontcount
;
73 extern Cursor appcursors
[NUM_CURSORS
];
74 extern XtAppContext app
;
78 extern int number_colors
;
79 extern colorindex
*colorlist
;
82 /*------------------------------------------------------*/
83 /* Global variable definitions */
84 /*------------------------------------------------------*/
86 Boolean load_in_progress
= False
;
89 /* Structure for remembering what names refer to the same object */
93 /*------------------------------------------------------*/
94 /* Simple utility---get rid of newline character */
95 /*------------------------------------------------------*/
97 char *ridnewline(char *sptr
)
101 for (tstrp
= sptr
; *tstrp
!= '\0' && *tstrp
!= '\n'; tstrp
++);
102 if (*tstrp
== '\n') *tstrp
= '\0';
106 /*----------------------------------------------------------------------*/
107 /* Check if two filenames are equivalent. This requires separately */
108 /* checking any absolute or relative pathnames in front of the filename */
109 /* as well as the filename itself. */
110 /*----------------------------------------------------------------------*/
114 int filecmp(char *filename1
, char *filename2
)
116 char *root1
, *root2
, *path1
, *path2
, *end1
, *end2
;
120 const char *cwdname
= ".";
122 if (filename1
== NULL
|| filename2
== NULL
) return 1;
124 if (!strcmp(filename1
, filename2
)) return 0; /* exact match */
126 root1
= strrchr(filename1
, PATHSEP
);
127 root2
= strrchr(filename2
, PATHSEP
);
130 path1
= (char *)cwdname
;
141 path2
= (char *)cwdname
;
151 if (strcmp(root1
, root2
)) return 1; /* root names don't match */
153 /* If we got here, one or both filenames specify a directory */
154 /* path, and the directory paths are different strings. */
155 /* However, one may be an absolute path and the other a */
156 /* relative path, so we check the inodes of the paths for */
157 /* equivalence. Note that the file itself is not assumed to */
161 if (end1
!= NULL
) *end1
= '\0';
162 if (stat(path1
, &statbuf
) == 0 && S_ISDIR(statbuf
.st_mode
)) {
163 inode1
= statbuf
.st_ino
;
164 if (end2
!= NULL
) *end2
= '\0';
165 if (stat(path2
, &statbuf
) == 0 && S_ISDIR(statbuf
.st_mode
)) {
166 if (inode1
== statbuf
.st_ino
)
169 if (end2
!= NULL
) *end2
= PATHSEP
;
171 if (end1
!= NULL
) *end1
= PATHSEP
;
175 /*--------------------------------------------------------------*/
176 /* Make sure that a string (object or parameter name) is a */
177 /* valid PostScript name. We do this by converting illegal */
178 /* characters to the PostScript \ooo (octal value) form. */
180 /* This routine does not consider whether the name might be a */
181 /* PostScript numeric value. This problem is taken care of by */
182 /* having the load/save routines prepend '@' to parameters and */
183 /* a technology namespace to object names. */
185 /* If "need_prefix" is TRUE, then prepend "@" to the result */
186 /* string, unless teststring is a numerical parameter name */
188 /*--------------------------------------------------------------*/
190 char *create_valid_psname(char *teststring
, Boolean need_prefix
)
193 static char *optr
= NULL
;
195 Boolean prepend
= need_prefix
;
196 char illegalchars
[] = {'/', '}', '{', ']', '[', ')', '(', '<', '>', ' ', '%'};
198 /* Check for illegal characters which have syntactical meaning in */
199 /* PostScript, and the presence of nonprintable characters or */
202 ssize
= strlen(teststring
);
205 if (need_prefix
&& !strncmp(teststring
, "p_", 2))
210 for (sptr
= teststring
; *sptr
!= '\0'; sptr
++) {
211 if ((!isprint(*sptr
)) || isspace(*sptr
))
214 for (i
= 0; i
< sizeof(illegalchars
); i
++) {
215 if (*sptr
== illegalchars
[i
]) {
222 if (isize
== ssize
) return teststring
;
226 optr
= (char *)malloc(isize
);
228 optr
= (char *)realloc(optr
, isize
);
232 if (prepend
) *pptr
++ = '@';
234 for (sptr
= teststring
; *sptr
!= '\0'; sptr
++) {
235 if ((!isprint(*sptr
)) || isspace(*sptr
)) {
236 sprintf(pptr
, "\\%03o", *sptr
);
240 for (i
= 0; i
< sizeof(illegalchars
); i
++) {
241 if (*sptr
== illegalchars
[i
]) {
242 sprintf(pptr
, "\\%03o", *sptr
);
247 if (i
== sizeof(illegalchars
))
255 /*------------------------------------------------------*/
256 /* Turn a PostScript string with possible backslash */
257 /* escapes into a normal character string. */
259 /* if "spacelegal" is TRUE, we are parsing a PostScript */
260 /* string in parentheses () where whitespace is legal. */
261 /* If FALSE, we are parsing a PostScript name where */
262 /* whitespace is illegal, and any whitespace should be */
263 /* considered the end of the name. */
265 /* "dest" is ASSUMED to be large enough to hold the */
266 /* result. "dest" is always equal to or smaller than */
267 /* "src" in length. "size" should be the maximum size */
268 /* of the string, or 1 less that the allocated memory, */
269 /* allowing for a final NULL byte to be added. */
271 /* The fact that "dest" is always smaller than or equal */
272 /* to "src" means that parse_ps_string(a, a, ...) is */
275 /* Return 0 if the result is empty, 1 otherwise. */
276 /*------------------------------------------------------*/
278 int parse_ps_string(char *src
, char *dest
, int size
, Boolean spacelegal
, Boolean strip
)
282 int tmpdig
, rval
= 0;
284 /* Strip leading "@", inserted by XCircuit to */
285 /* prevent conflicts with PostScript reserved */
286 /* keywords or numbers. */
288 if (strip
&& (*sptr
== '@')) sptr
++;
291 if ((*sptr
== '\0') || (isspace(*sptr
) && !spacelegal
)) {
298 if (*sptr
>= '0' && *sptr
< '8') {
299 sscanf(sptr
, "%3o", &tmpdig
);
300 *tptr
++ = (u_char
)tmpdig
;
310 if ((int)(tptr
- dest
) > size
) {
311 Wprintf("Warning: Name \"%s\" in input exceeded buffer length!\n", src
);
319 /*------------------------------------------------------*/
320 /* Free memory allocated to a label string */
321 /*------------------------------------------------------*/
323 void freelabel(stringpart
*string
)
325 stringpart
*strptr
= string
, *tmpptr
;
327 while (strptr
!= NULL
) {
328 if (strptr
->type
== TEXT_STRING
|| strptr
->type
== PARAM_START
)
329 free(strptr
->data
.string
);
330 tmpptr
= strptr
->nextpart
;
336 /*------------------------------------------------------*/
337 /* Free memory for a single element */
338 /*------------------------------------------------------*/
340 void free_single(genericptr genobj
)
345 if (IS_POLYGON(genobj
)) free(((polyptr
)(genobj
))->points
);
346 else if (IS_LABEL(genobj
)) freelabel(((labelptr
)(genobj
))->string
);
347 else if (IS_GRAPHIC(genobj
)) freegraphic((graphicptr
)(genobj
));
348 else if (IS_PATH(genobj
)) free(((pathptr
)(genobj
))->plist
);
349 else if (IS_OBJINST(genobj
)) {
350 geninst
= (objinstptr
)genobj
;
351 ops
= geninst
->params
;
352 while (ops
!= NULL
) {
353 /* Don't try to free data from indirect parameters */
354 /* (That's not true---all data are copied by epsubstitute) */
355 /* if (find_indirect_param(geninst, ops->key) == NULL) { */
358 freelabel(ops
->parameter
.string
);
361 free(ops
->parameter
.expr
);
371 free_all_eparams(genobj
);
374 /*---------------------------------------------------------*/
375 /* Reset an object structure by freeing all alloc'd memory */
376 /*---------------------------------------------------------*/
378 void reset(objectptr localdata
, short mode
)
382 if (localdata
->polygons
!= NULL
|| localdata
->labels
!= NULL
)
383 destroynets(localdata
);
385 localdata
->valid
= False
;
387 if (localdata
->parts
> 0) {
392 for (genobj
= localdata
->plist
; genobj
< localdata
->plist
393 + localdata
->parts
; genobj
++)
395 /* (*genobj == NULL) only on library pages */
396 /* where the instances are kept in the library */
397 /* definition, and are only referenced on the page. */
399 if (*genobj
!= NULL
) {
400 free_single(*genobj
);
404 free(localdata
->plist
);
406 removeparams(localdata
);
410 free(localdata
->plist
);
414 /*---------------------------------------------------------*/
416 void pagereset(short rpage
)
418 /* free alloc'd filename */
420 if (xobjs
.pagelist
[rpage
]->filename
!= NULL
)
421 free(xobjs
.pagelist
[rpage
]->filename
);
422 xobjs
.pagelist
[rpage
]->filename
= (char *)NULL
;
424 if (xobjs
.pagelist
[rpage
]->background
.name
!= NULL
)
425 free(xobjs
.pagelist
[rpage
]->background
.name
);
426 xobjs
.pagelist
[rpage
]->background
.name
= (char *)NULL
;
430 /* New pages pick up their properties from page 0, which can be changed */
431 /* from the .xcircuitrc file on startup (or loaded from a script). */
432 /* Thanks to Norman Werner (norman.werner@student.uni-magdeburg.de) for */
433 /* pointing out this more obvious way of doing the reset, and providing */
436 xobjs
.pagelist
[rpage
]->wirewidth
= xobjs
.pagelist
[0]->wirewidth
;
437 xobjs
.pagelist
[rpage
]->orient
= xobjs
.pagelist
[0]->orient
;
438 xobjs
.pagelist
[rpage
]->pmode
= xobjs
.pagelist
[0]->pmode
;
439 xobjs
.pagelist
[rpage
]->outscale
= xobjs
.pagelist
[0]->outscale
;
440 xobjs
.pagelist
[rpage
]->drawingscale
.x
= xobjs
.pagelist
[0]->drawingscale
.x
;
441 xobjs
.pagelist
[rpage
]->drawingscale
.y
= xobjs
.pagelist
[0]->drawingscale
.y
;
442 xobjs
.pagelist
[rpage
]->gridspace
= xobjs
.pagelist
[0]->gridspace
;
443 xobjs
.pagelist
[rpage
]->snapspace
= xobjs
.pagelist
[0]->snapspace
;
444 xobjs
.pagelist
[rpage
]->coordstyle
= xobjs
.pagelist
[0]->coordstyle
;
445 xobjs
.pagelist
[rpage
]->margins
= xobjs
.pagelist
[0]->margins
;
447 if (xobjs
.pagelist
[rpage
]->coordstyle
== CM
) {
448 xobjs
.pagelist
[rpage
]->pagesize
.x
= 595;
449 xobjs
.pagelist
[rpage
]->pagesize
.y
= 842; /* A4 */
452 xobjs
.pagelist
[rpage
]->pagesize
.x
= 612; /* letter */
453 xobjs
.pagelist
[rpage
]->pagesize
.y
= 792;
457 /*---------------------------------------------------------*/
459 void initmem(objectptr localdata
)
461 localdata
->parts
= 0;
462 localdata
->plist
= (genericptr
*)malloc(sizeof(genericptr
));
463 localdata
->hidden
= False
;
464 localdata
->changes
= 0;
465 localdata
->params
= NULL
;
467 localdata
->viewscale
= 0.5;
469 /* Object should not reference the window: this needs to be rethunk! */
470 if (areawin
!= NULL
) {
471 localdata
->pcorner
.x
= -areawin
->width
;
472 localdata
->pcorner
.y
= -areawin
->height
;
474 localdata
->bbox
.width
= 0;
475 localdata
->bbox
.height
= 0;
476 localdata
->bbox
.lowerleft
.x
= 0;
477 localdata
->bbox
.lowerleft
.y
= 0;
479 localdata
->highlight
.netlist
= NULL
;
480 localdata
->highlight
.thisinst
= NULL
;
481 localdata
->schemtype
= PRIMARY
;
482 localdata
->symschem
= NULL
;
483 localdata
->netnames
= NULL
;
484 localdata
->polygons
= NULL
;
485 localdata
->labels
= NULL
;
486 localdata
->ports
= NULL
;
487 localdata
->calls
= NULL
;
488 localdata
->valid
= False
;
489 localdata
->infolabels
= False
;
490 localdata
->traversed
= False
;
493 /*--------------------------------------------------------------*/
494 /* Exhaustively compare the contents of two objects and return */
495 /* true if equivalent, false if not. */
496 /*--------------------------------------------------------------*/
498 Boolean
elemcompare(genericptr
*compgen
, genericptr
*gchk
)
501 switch(ELEMENTTYPE(*compgen
)) {
503 bres
= (TOARC(compgen
)->position
.x
== TOARC(gchk
)->position
.x
&&
504 TOARC(compgen
)->position
.y
== TOARC(gchk
)->position
.y
&&
505 TOARC(compgen
)->style
== TOARC(gchk
)->style
&&
506 TOARC(compgen
)->width
== TOARC(gchk
)->width
&&
507 abs(TOARC(compgen
)->radius
) == abs(TOARC(gchk
)->radius
) &&
508 TOARC(compgen
)->yaxis
== TOARC(gchk
)->yaxis
&&
509 TOARC(compgen
)->angle1
== TOARC(gchk
)->angle1
&&
510 TOARC(compgen
)->angle2
== TOARC(gchk
)->angle2
);
513 bres
= (TOSPLINE(compgen
)->style
== TOSPLINE(gchk
)->style
&&
514 TOSPLINE(compgen
)->width
== TOSPLINE(gchk
)->width
&&
515 TOSPLINE(compgen
)->ctrl
[0].x
== TOSPLINE(gchk
)->ctrl
[0].x
&&
516 TOSPLINE(compgen
)->ctrl
[0].y
== TOSPLINE(gchk
)->ctrl
[0].y
&&
517 TOSPLINE(compgen
)->ctrl
[1].x
== TOSPLINE(gchk
)->ctrl
[1].x
&&
518 TOSPLINE(compgen
)->ctrl
[1].y
== TOSPLINE(gchk
)->ctrl
[1].y
&&
519 TOSPLINE(compgen
)->ctrl
[2].x
== TOSPLINE(gchk
)->ctrl
[2].x
&&
520 TOSPLINE(compgen
)->ctrl
[2].y
== TOSPLINE(gchk
)->ctrl
[2].y
&&
521 TOSPLINE(compgen
)->ctrl
[3].x
== TOSPLINE(gchk
)->ctrl
[3].x
&&
522 TOSPLINE(compgen
)->ctrl
[3].y
== TOSPLINE(gchk
)->ctrl
[3].y
);
526 if (TOPOLY(compgen
)->style
== TOPOLY(gchk
)->style
&&
527 TOPOLY(compgen
)->width
== TOPOLY(gchk
)->width
&&
528 TOPOLY(compgen
)->number
== TOPOLY(gchk
)->number
) {
529 for (i
= 0; i
< TOPOLY(compgen
)->number
; i
++) {
530 if (TOPOLY(compgen
)->points
[i
].x
!= TOPOLY(gchk
)->points
[i
].x
531 || TOPOLY(compgen
)->points
[i
].y
!= TOPOLY(gchk
)->points
[i
].y
)
534 bres
= (i
== TOPOLY(compgen
)->number
);
542 /*--------------------------------------------------------------*/
543 /* Compare any element with any other element. */
544 /*--------------------------------------------------------------*/
546 Boolean
compare_single(genericptr
*compgen
, genericptr
*gchk
)
548 Boolean bres
= False
;
550 if ((*gchk
)->type
== (*compgen
)->type
) {
551 switch(ELEMENTTYPE(*compgen
)) {
553 objinst
*newobj
= TOOBJINST(compgen
);
554 objinst
*oldobj
= TOOBJINST(gchk
);
555 bres
= (newobj
->position
.x
== oldobj
->position
.x
&&
556 newobj
->position
.y
== oldobj
->position
.y
&&
557 newobj
->rotation
== oldobj
->rotation
&&
558 newobj
->scale
== oldobj
->scale
&&
559 newobj
->style
== oldobj
->style
&&
560 newobj
->thisobject
== oldobj
->thisobject
);
563 bres
= (TOLABEL(compgen
)->position
.x
== TOLABEL(gchk
)->position
.x
&&
564 TOLABEL(compgen
)->position
.y
== TOLABEL(gchk
)->position
.y
&&
565 TOLABEL(compgen
)->rotation
== TOLABEL(gchk
)->rotation
&&
566 TOLABEL(compgen
)->scale
== TOLABEL(gchk
)->scale
&&
567 TOLABEL(compgen
)->anchor
== TOLABEL(gchk
)->anchor
&&
568 TOLABEL(compgen
)->pin
== TOLABEL(gchk
)->pin
&&
569 !stringcomp(TOLABEL(compgen
)->string
, TOLABEL(gchk
)->string
));
571 case(PATH
): /* elements *must* be in same order for a path */
572 bres
= (TOPATH(compgen
)->parts
== TOPATH(gchk
)->parts
&&
573 TOPATH(compgen
)->style
== TOPATH(gchk
)->style
&&
574 TOPATH(compgen
)->width
== TOPATH(gchk
)->width
);
576 genericptr
*pathchk
, *gpath
;
577 for (pathchk
= TOPATH(compgen
)->plist
, gpath
=
578 TOPATH(gchk
)->plist
; pathchk
< TOPATH(compgen
)->plist
579 + TOPATH(compgen
)->parts
; pathchk
++, gpath
++) {
580 if (!elemcompare(pathchk
, gpath
)) bres
= False
;
584 case(ARC
): case(SPLINE
): case(POLYGON
):
585 bres
= elemcompare(compgen
, gchk
);
592 /*--------------------------------------------------------------------*/
594 short objcompare(objectptr obja
, objectptr objb
)
596 genericptr
*compgen
, *glist
, *gchk
, *remg
;
600 /* quick check on equivalence of number of objects */
602 if (obja
->parts
!= objb
->parts
) return False
;
604 /* check equivalence of parameters. Parameters need not be in any */
605 /* order; they must only match by key and value. */
607 if (obja
->params
== NULL
&& objb
->params
!= NULL
) return False
;
608 else if (obja
->params
!= NULL
&& objb
->params
== NULL
) return False
;
609 else if (obja
->params
!= NULL
|| objb
->params
!= NULL
) {
610 oparamptr opsa
, opsb
;
611 for (opsa
= obja
->params
; opsa
!= NULL
; opsa
= opsa
->next
) {
612 opsb
= match_param(objb
, opsa
->key
);
613 if (opsb
== NULL
) return False
;
614 else if (opsa
->type
!= opsb
->type
) return False
;
615 switch (opsa
->type
) {
617 if (stringcomp(opsa
->parameter
.string
, opsb
->parameter
.string
))
621 if (strcmp(opsa
->parameter
.expr
, opsb
->parameter
.expr
))
624 case XC_INT
: case XC_FLOAT
:
625 if (opsa
->parameter
.ivalue
!= opsb
->parameter
.ivalue
)
632 /* For the exhaustive check we must match component for component. */
633 /* Best not to assume that elements are in same order for both. */
637 glist
= (genericptr
*)malloc(csize
* sizeof(genericptr
));
638 for (compgen
= objb
->plist
; compgen
< objb
->plist
+ csize
; compgen
++)
639 (*(glist
+ (int)(compgen
- objb
->plist
))) = *compgen
;
640 for (compgen
= obja
->plist
; compgen
< obja
->plist
+ obja
->parts
;
643 for (gchk
= glist
; gchk
< glist
+ csize
; gchk
++) {
644 if ((*compgen
)->color
== (*gchk
)->color
)
645 bres
= compare_single(compgen
, gchk
);
648 for (remg
= gchk
; remg
< glist
+ csize
; remg
++)
655 if (csize
!= 0) return False
;
657 /* Both objects cannot attempt to set an associated schematic/symbol to */
658 /* separate objects, although it is okay for one to make the association */
659 /* and the other not to. */
661 if (obja
->symschem
!= NULL
&& objb
->symschem
!= NULL
)
662 if (obja
->symschem
!= objb
->symschem
)
668 /*------------------------*/
669 /* scale renormalization */
670 /*------------------------*/
672 float getpsscale(float value
, short page
)
674 if (xobjs
.pagelist
[page
]->coordstyle
!= CM
)
675 return (value
* INCHSCALE
);
677 return (value
* CMSCALE
);
680 /*---------------------------------------------------------------*/
681 /* Keep track of columns of output and split lines when too long */
682 /*---------------------------------------------------------------*/
684 void dostcount(FILE *ps
, short *count
, short addlength
)
687 if (*count
> OUTPUTWIDTH
) {
693 /*----------------------------------------------------------------------*/
694 /* Write a numerical value as a string to _STR, making a parameter */
695 /* substitution if appropriate. */
696 /* Return 1 if a parameter substitution was made, 0 if not. */
697 /*----------------------------------------------------------------------*/
699 Boolean
varpcheck(FILE *ps
, short value
, objectptr localdata
, int pointno
,
700 short *stptr
, genericptr thiselem
, u_char which
)
704 Boolean done
= False
;
706 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
707 if ((epp
->pdata
.pointno
!= -1) && (epp
->pdata
.pointno
!= pointno
)) continue;
708 ops
= match_param(localdata
, epp
->key
);
709 if (ops
!= NULL
&& (ops
->which
== which
)) {
710 sprintf(_STR
, "%s ", epp
->key
);
717 if (pointno
== -1) return done
;
718 sprintf(_STR
, "%d ", (int)value
);
720 else if ((epp
->pdata
.pointno
== -1) && (pointno
>= 0)) {
721 sprintf(_STR
, "%d ", (int)value
- ops
->parameter
.ivalue
);
724 dostcount (ps
, stptr
, strlen(_STR
));
729 /*----------------------------------------------------------------------*/
730 /* like varpcheck(), but without pointnumber */
731 /*----------------------------------------------------------------------*/
733 void varcheck(FILE *ps
, short value
, objectptr localdata
,
734 short *stptr
, genericptr thiselem
, u_char which
)
736 varpcheck(ps
, value
, localdata
, 0, stptr
, thiselem
, which
);
739 /*----------------------------------------------------------------------*/
740 /* like varcheck(), but for floating-point values */
741 /*----------------------------------------------------------------------*/
743 void varfcheck(FILE *ps
, float value
, objectptr localdata
, short *stptr
,
744 genericptr thiselem
, u_char which
)
748 Boolean done
= False
;
750 for (epp
= thiselem
->passed
; epp
!= NULL
; epp
= epp
->next
) {
751 ops
= match_param(localdata
, epp
->key
);
752 if (ops
!= NULL
&& (ops
->which
== which
)) {
753 sprintf(_STR
, "%s ", epp
->key
);
760 sprintf(_STR
, "%3.3f ", value
);
762 dostcount (ps
, stptr
, strlen(_STR
));
766 /*----------------------------------------------------------------------*/
767 /* Like varpcheck(), for path types only. */
768 /*----------------------------------------------------------------------*/
770 Boolean
varpathcheck(FILE *ps
, short value
, objectptr localdata
, int pointno
,
771 short *stptr
, genericptr
*thiselem
, pathptr thispath
, u_char which
)
775 Boolean done
= False
;
777 for (epp
= thispath
->passed
; epp
!= NULL
; epp
= epp
->next
) {
778 if ((epp
->pdata
.pathpt
[0] != -1) && (epp
->pdata
.pathpt
[1] != pointno
)) continue;
779 if ((epp
->pdata
.pathpt
[0] != -1) && (epp
->pdata
.pathpt
[0] !=
780 (short)(thiselem
- thispath
->plist
))) continue;
781 ops
= match_param(localdata
, epp
->key
);
782 if (ops
!= NULL
&& (ops
->which
== which
)) {
783 sprintf(_STR
, "%s ", epp
->key
);
790 if (pointno
== -1) return done
;
791 sprintf(_STR
, "%d ", (int)value
);
793 else if ((epp
->pdata
.pathpt
[0] == -1) && (pointno
>= 0)) {
794 sprintf(_STR
, "%d ", (int)value
- ops
->parameter
.ivalue
);
796 dostcount (ps
, stptr
, strlen(_STR
));
801 /* Structure used to hold data specific to each load mode. See */
802 /* xcircuit.h for the list of load modes (enum loadmodes) */
804 typedef struct _loaddata
{
805 void (*func
)(); /* Routine to run to load the file */
806 char *prompt
; /* Substring name of action, for prompting */
807 char *filext
; /* Default extention of file to load */
810 /*-------------------------------------------------------*/
811 /* Load a PostScript or Python (interpreter script) file */
812 /*-------------------------------------------------------*/
814 void getfile(xcWidget button
, pointertype mode
, caddr_t nulldata
)
816 static loaddata loadmodes
[LOAD_MODES
] = {
817 {normalloadfile
, "load", "ps"}, /* mode NORMAL */
818 {importfile
, "import", "ps"}, /* mode IMPORT */
819 {loadbackground
, "render", "ps"}, /* mode PSBKGROUND */
821 {execscript
, "execute", "py"},
823 {execscript
, "execute", ""}, /* mode SCRIPT */
825 {crashrecover
, "recover", "ps"}, /* mode RECOVER */
827 {importspice
, "import", "spice"}, /* mode IMPORTSPICE */
830 {importgraphic
, "import", "ppm"}, /* mode IMPORTGRAPHIC */
834 buttonsave
*savebutton
= NULL
;
835 char *promptstr
= NULL
;
836 /* char strext[10]; (jdk) */
839 if (is_page(topobject
) == -1) {
840 Wprintf("Can only read file into top-level page!");
843 else if (idx
>= LOAD_MODES
) {
844 Wprintf("Unknown mode passed to routine getfile()\n");
848 savebutton
= getgeneric(button
, getfile
, (void *)mode
);
850 if (idx
== RECOVER
) {
851 char *cfile
= getcrashfilename();
852 promptstr
= (char *)malloc(18 + ((cfile
== NULL
) ? 9 : strlen(cfile
)));
853 sprintf(promptstr
, "Recover file \'%s\'?", (cfile
== NULL
) ? "(unknown)" : cfile
);
854 popupprompt(button
, promptstr
, NULL
, loadmodes
[idx
].func
, savebutton
, NULL
);
855 if (cfile
) free(cfile
);
858 promptstr
= (char *)malloc(18 + strlen(loadmodes
[idx
].prompt
));
859 sprintf(promptstr
, "Select file to %s:", loadmodes
[idx
].prompt
);
860 popupprompt(button
, promptstr
, "\0", loadmodes
[idx
].func
,
861 savebutton
, loadmodes
[idx
].filext
);
866 /*--------------------------------------------------------------*/
867 /* Tilde ('~') expansion in file name. Assumes that filename */
868 /* is a static character array of size "nchars". */
869 /*--------------------------------------------------------------*/
871 Boolean
xc_tilde_expand(char *filename
, int nchars
)
874 struct passwd
*passwd
;
875 char *username
= NULL
, *expanded
, *sptr
;
877 if (*filename
== '~') {
879 if (*sptr
== '/' || *sptr
== ' ' || *sptr
== '\0')
880 username
= getenv("HOME");
882 for (; *sptr
!= '/' && *sptr
!= '\0'; sptr
++);
883 if (*sptr
== '\0') *(sptr
+ 1) = '\0';
886 passwd
= getpwnam(filename
+ 1);
888 username
= passwd
->pw_dir
;
892 if (username
!= NULL
) {
893 expanded
= (char *)malloc(strlen(username
) +
895 strcpy(expanded
, username
);
896 strcat(expanded
, sptr
);
897 strncpy(filename
, expanded
, nchars
);
908 /*--------------------------------------------------------------*/
909 /* Variable ('$') expansion in file name */
910 /*--------------------------------------------------------------*/
912 Boolean
xc_variable_expand(char *filename
, int nchars
)
914 char *expanded
, *sptr
, tmpchar
, *varpos
, *varsub
;
916 if ((varpos
= strchr(filename
, '$')) != NULL
) {
917 for (sptr
= varpos
; *sptr
!= '/' && *sptr
!= '\0'; sptr
++);
918 if (*sptr
== '\0') *(sptr
+ 1) = '\0';
923 /* Interpret as a Tcl variable */
924 varsub
= (char *)Tcl_GetVar(xcinterp
, varpos
+ 1, TCL_NAMESPACE_ONLY
);
926 /* Interpret as an environment variable */
927 varsub
= (char *)getenv((const char *)(varpos
+ 1));
930 if (varsub
!= NULL
) {
933 expanded
= (char *)malloc(strlen(varsub
) + strlen(filename
) +
934 strlen(sptr
+ 1) + 2);
935 strcpy(expanded
, filename
);
936 strcat(expanded
, varsub
);
938 strcat(expanded
, sptr
);
939 strncpy(filename
, expanded
, nchars
);
949 /*--------------------------------------------------------------*/
950 /* Attempt to find a file and open it. */
951 /*--------------------------------------------------------------*/
953 FILE *fileopen(char *filename
, char *suffix
, char *name_return
, int nchars
)
956 char inname
[250], expname
[250], *sptr
, *cptr
, *iptr
, *froot
;
959 sscanf(filename
, "%249s", expname
);
960 xc_tilde_expand(expname
, 249);
961 while (xc_variable_expand(expname
, 249));
963 sptr
= xobjs
.filesearchpath
;
965 if ((xobjs
.filesearchpath
== NULL
) || (expname
[0] == '/')) {
966 strcpy(inname
, expname
);
970 strcpy(inname
, sptr
);
971 cptr
= strchr(sptr
, ':');
972 slen
= (cptr
== NULL
) ? strlen(sptr
) : (int)(cptr
- sptr
);
973 sptr
+= (slen
+ ((cptr
== NULL
) ? 0 : 1));
974 iptr
= inname
+ slen
;
975 if (*(iptr
- 1) != '/') strcpy(iptr
++, "/");
976 strcpy(iptr
, expname
);
979 /* Attempt to open the filename with a suffix */
981 if ((froot
= strrchr(iptr
, '/')) == NULL
) froot
= iptr
;
982 if (strrchr(froot
, '.') == NULL
) {
984 if (suffix
[0] != '.')
985 strncat(inname
, ".", 249);
986 strncat(inname
, suffix
, 249);
988 file
= fopen(inname
, "r");
991 /* Attempt to open the filename as given, without a suffix */
994 strcpy(iptr
, expname
);
995 file
= fopen(inname
, "r");
998 if (file
!= NULL
) break;
999 else if (sptr
== NULL
) break;
1000 else if (*sptr
== '\0') break;
1003 if (name_return
) strncpy(name_return
, inname
, nchars
);
1007 /*---------------------------------------------------------*/
1009 Boolean
nextfilename() /* extract next filename from _STR2 into _STR */
1013 sprintf(_STR
, "%.149s", _STR2
);
1014 if ((cptr
= strrchr(_STR2
, ',')) != NULL
) {
1015 slptr
= strrchr(_STR
, '/');
1016 if (slptr
== NULL
|| ((slptr
- _STR
) > (cptr
- _STR2
))) slptr
= _STR
- 1;
1017 sprintf(slptr
+ 1, "%s", cptr
+ 1);
1024 /*---------------------------------------------------------*/
1028 loadlibrary(FONTLIB
);
1031 /*------------------------------------------------------*/
1032 /* Handle library loading and refresh current page if */
1033 /* it is a library page that just changed. */
1034 /*------------------------------------------------------*/
1036 void loadglib(Boolean lflag
, short ilib
, short tlib
)
1038 while (nextfilename()) {
1042 ilib
= createlibrary(False
);
1044 /* if (ilib == tlib) zoomview(NULL, NULL, NULL); */
1049 ilib
= createlibrary(False
);
1051 /* if (ilib == tlib) zoomview(NULL, NULL, NULL); */
1054 /*------------------------------------------------------*/
1055 /* Load new library: Create new library page and load */
1057 /*------------------------------------------------------*/
1061 loadglib(False
, (short)0, (short)is_library(topobject
) + LIBRARY
);
1064 /*-----------------------------------------------------------*/
1065 /* Add to library: If on library page, add to that library. */
1066 /* Otherwise, create a new library page and load to it. */
1067 /*-----------------------------------------------------------*/
1072 Boolean lflag
= True
;
1074 /* Flag whether current page is a library page or not */
1076 if ((tlib
= is_library(topobject
)) < 0) {
1081 ilib
= tlib
+ LIBRARY
;
1083 loadglib(lflag
, ilib
, tlib
+ LIBRARY
);
1086 /*---------------------------------------------------------*/
1088 void getlib(xcWidget button
, caddr_t clientdata
, caddr_t nulldata
)
1090 buttonsave
*savebutton
;
1092 savebutton
= getgeneric(button
, getlib
, NULL
);
1094 popupprompt(button
, "Enter library to load:", "\0", loadblib
, savebutton
,
1098 /*---------------------------------------------------------*/
1100 void getuserlib(xcWidget button
, caddr_t clientdata
, caddr_t nulldata
)
1102 buttonsave
*savebutton
;
1105 savebutton
= getgeneric(button
, getuserlib
, NULL
);
1107 popupprompt(button
, "Enter library to load:", "\0", loadulib
, savebutton
,
1111 /*------------------------------------------------------*/
1112 /* Add a new name to the list of aliases for an object */
1113 /*------------------------------------------------------*/
1115 Boolean
addalias(objectptr thisobj
, char *newname
)
1119 /* Boolean retval = False; (jdk) */
1120 char *origname
= thisobj
->name
;
1122 for (aref
= aliastop
; aref
!= NULL
; aref
= aref
->next
)
1123 if (aref
->baseobj
== thisobj
)
1126 /* An equivalence, not an alias */
1127 if (!strcmp(origname
, newname
)) return True
;
1129 if (aref
== NULL
) { /* entry does not exist; add new baseobj */
1130 aref
= (aliasptr
)malloc(sizeof(alias
));
1131 aref
->baseobj
= thisobj
;
1132 aref
->aliases
= NULL
;
1133 aref
->next
= aliastop
;
1137 for (sref
= aref
->aliases
; sref
!= NULL
; sref
= sref
->next
)
1138 if (!strcmp(sref
->alias
, newname
))
1141 if (sref
== NULL
) { /* needs new entry */
1142 sref
= (slistptr
)malloc(sizeof(stringlist
));
1143 sref
->alias
= strdup(newname
);
1144 sref
->next
= aref
->aliases
;
1145 aref
->aliases
= sref
;
1148 else return True
; /* alias already exists! */
1151 /*------------------------------------------------------*/
1152 /* Remove all object name aliases */
1153 /*------------------------------------------------------*/
1155 void cleanupaliases(short mode
)
1160 char *sptr
; /* *basename, (jdk) */
1163 if (aliastop
== NULL
) return;
1165 for (aref
= aliastop
; aref
!= NULL
; aref
= aref
->next
) {
1166 baseobj
= aref
->baseobj
;
1167 for (sref
= aref
->aliases
; sref
!= NULL
; sref
= sref
->next
)
1171 for (; (aref
= aliastop
->next
); aliastop
= aref
)
1176 /* Get rid of propagating underscores in names */
1178 for (i
= 0; i
< ((mode
== FONTLIB
) ? 1 : xobjs
.numlibs
); i
++) {
1179 for (j
= 0; j
< ((mode
== FONTLIB
) ? xobjs
.fontlib
.number
:
1180 xobjs
.userlibs
[i
].number
); j
++) {
1181 baseobj
= (mode
== FONTLIB
) ? *(xobjs
.fontlib
.library
+ j
) :
1182 *(xobjs
.userlibs
[i
].library
+ j
);
1184 sptr
= baseobj
->name
;
1185 while (*sptr
== '_') sptr
++;
1186 /* need memmove to avoid overwriting? */
1187 memmove((void *)baseobj
->name
, (const void *)sptr
, strlen(sptr
) + 1);
1193 /*------------------------------------------------------*/
1194 /* Open a library file by name and return a pointer to */
1195 /* the file structure, or NULL if an error occurred. */
1196 /*------------------------------------------------------*/
1198 FILE *libopen(char *libname
, short mode
, char *name_return
, int nchars
)
1201 char inname
[150], expname
[150], *sptr
, *cptr
, *iptr
;
1203 char *suffix
= (mode
== FONTENCODING
) ? ".xfe" : ".lps";
1205 sscanf(libname
, "%149s", expname
);
1206 xc_tilde_expand(expname
, 149);
1207 while(xc_variable_expand(expname
, 149));
1209 sptr
= xobjs
.libsearchpath
;
1212 if ((xobjs
.libsearchpath
== NULL
) || (expname
[0] == '/')) {
1213 strcpy(inname
, expname
);
1217 strcpy(inname
, sptr
);
1218 cptr
= strchr(sptr
, ':');
1219 slen
= (cptr
== NULL
) ? strlen(sptr
) : (int)(cptr
- sptr
);
1220 sptr
+= (slen
+ ((cptr
== NULL
) ? 0 : 1));
1221 iptr
= inname
+ slen
;
1222 if (*(iptr
- 1) != '/') strcpy(iptr
++, "/");
1223 strcpy(iptr
, expname
);
1226 /* Try to open the filename with a suffix if it doesn't have one */
1228 if (strrchr(iptr
, '.') == NULL
) {
1229 strncat(inname
, suffix
, 149);
1230 file
= fopen(inname
, "r");
1233 /* Try to open the filename as given, without a suffix */
1236 strcpy(iptr
, expname
);
1237 file
= fopen(inname
, "r");
1240 if (file
!= NULL
) break;
1241 else if (sptr
== NULL
) break;
1242 else if (*sptr
== '\0') break;
1245 if ((file
== NULL
) && (xobjs
.libsearchpath
== NULL
)) {
1247 /* if not found in cwd and there is no library search */
1248 /* path, look for environment variable "XCIRCUIT_LIB_DIR" */
1249 /* defined (Thanks to Ali Moini, U. Adelaide, S. Australia) */
1251 char *tmp_s
= getenv((const char *)"XCIRCUIT_LIB_DIR");
1253 if (tmp_s
!= NULL
) {
1254 sprintf(inname
, "%s/%s", tmp_s
, expname
);
1255 file
= fopen(inname
, "r");
1257 sprintf(inname
, "%s/%s%s", tmp_s
, expname
, suffix
);
1258 file
= fopen(inname
, "r");
1262 /* last resort: hard-coded directory BUILTINS_DIR */
1265 sprintf(inname
, "%s/%s", BUILTINS_DIR
, expname
);
1266 file
= fopen(inname
, "r");
1268 sprintf(inname
, "%s/%s%s", BUILTINS_DIR
, expname
, suffix
);
1269 file
= fopen(inname
, "r");
1274 if (name_return
) strncpy(name_return
, inname
, nchars
);
1278 /*--------------------------------------------------------------*/
1279 /* Add a record to the instlist list of the library indexed by */
1280 /* mode, create a new instance, and add it to the record. */
1282 /* objname is the name of the library object to be instanced, */
1283 /* and buffer is the line containing the instance parameters */
1284 /* of the new instance, optionally preceded by scale and */
1285 /* rotation values. */
1287 /*--------------------------------------------------------------*/
1289 objinstptr
new_library_instance(short mode
, char *objname
, char *buffer
,
1290 TechPtr defaulttech
)
1293 objectptr libobj
, localdata
;
1294 objinstptr newobjinst
;
1296 char *nsptr
, *fullname
= objname
;
1298 localdata
= xobjs
.libtop
[mode
+ LIBRARY
]->thisobject
;
1300 /* For (older) libraries that do not use technologies, give the */
1301 /* object a technology name in the form <library>::<object> */
1303 if ((nsptr
= strstr(objname
, "::")) == NULL
) {
1304 int deftechlen
= (defaulttech
== NULL
) ? 0 : strlen(defaulttech
->technology
);
1305 fullname
= (char *)malloc(deftechlen
+ strlen(objname
) + 3);
1306 if (defaulttech
== NULL
)
1307 sprintf(fullname
, "::%s", objname
);
1309 sprintf(fullname
, "%s::%s", defaulttech
->technology
, objname
);
1312 for (j
= 0; j
< xobjs
.userlibs
[mode
].number
; j
++) {
1313 libobj
= *(xobjs
.userlibs
[mode
].library
+ j
);
1314 if (!strcmp(fullname
, libobj
->name
)) {
1315 newobjinst
= addtoinstlist(mode
, libobj
, TRUE
);
1318 while (isspace(*lineptr
)) lineptr
++;
1319 if (*lineptr
!= '<') {
1320 /* May declare instanced scale and rotation first */
1321 lineptr
= varfscan(localdata
, lineptr
, &newobjinst
->scale
,
1322 (genericptr
)newobjinst
, P_SCALE
);
1323 lineptr
= varfscan(localdata
, lineptr
, &newobjinst
->rotation
,
1324 (genericptr
)newobjinst
, P_ROTATION
);
1326 readparams(NULL
, newobjinst
, libobj
, lineptr
);
1327 if (fullname
!= objname
) free(fullname
);
1331 if (fullname
!= objname
) free(fullname
);
1332 return NULL
; /* error finding the library object */
1335 /*------------------------------------------------------*/
1336 /* Import a single object from a library file. "mode" */
1337 /* is the number of the library into which the object */
1338 /* will be placed. This function allows new libraries */
1339 /* to be generated by "cutting and pasting" from */
1340 /* existing libraries. It also allows better library */
1341 /* management when the number of objects becomes very */
1342 /* large, such as when using "diplib" (7400 series */
1343 /* chips, created from the PCB library). */
1344 /*------------------------------------------------------*/
1346 void importfromlibrary(short mode
, char *libname
, char *objname
)
1349 char temp
[150], keyword
[100];
1350 char inname
[150], *tptr
;
1351 objectptr
*newobject
;
1354 Boolean dependencies
= False
;
1355 TechPtr nsptr
= NULL
;
1357 ps
= libopen(libname
, mode
, inname
, 149);
1359 Fprintf(stderr
, "Cannot open library %s for import.\n", libname
);
1363 version
= 2.0; /* Assume version is 2.0 unless found in header */
1366 if (fgets(temp
, 149, ps
) == NULL
) {
1367 Wprintf("Error in library.");
1370 else if (temp
[0] == '/') {
1372 if (temp
[1] == '@') s
= 2;
1373 sscanf(&temp
[s
], "%s", keyword
);
1374 if (!strcmp(keyword
, objname
))
1377 else if (*temp
== '%') {
1378 char *tptr
= temp
+ 1;
1379 while (isspace(*tptr
)) tptr
++;
1380 if (!strncmp(tptr
, "Version:", 8)) {
1383 if (sscanf(tptr
, "%f", &tmpv
) > 0) version
= tmpv
;
1385 else if (!strncmp(tptr
, "Library", 7)) {
1386 char *techname
= strstr(tptr
, ":");
1387 if (techname
!= NULL
) {
1388 techname
++; /* skip over colon */
1389 while(isspace(*techname
)) techname
++;
1390 ridnewline(techname
); /* Remove newline character */
1391 if ((tptr
= strrchr(techname
, '/')) != NULL
)
1392 techname
= tptr
+ 1;
1393 if ((tptr
= strrchr(techname
, '.')) != NULL
)
1394 if (!strncmp(tptr
, ".lps", 4))
1396 nsptr
= AddNewTechnology(techname
, inname
);
1398 // Set the IMPORTED flag, to help prevent overwriting
1399 // the techfile with a truncated version of it, unless
1400 // the filename of the techfile has been changed, in
1401 // which case the technology should be considered to
1402 // stand on its own, and is not considered a partially
1403 // complete imported version of the original techfile.
1405 if (!strcmp(inname
, nsptr
->filename
))
1406 nsptr
->flags
|= TECH_IMPORTED
;
1410 else if (!strncmp(tptr
, "Depend", 6)) {
1411 dependencies
= TRUE
;
1413 sscanf(tptr
, "%s", keyword
);
1414 if (!strcmp(keyword
, objname
)) {
1415 /* Load dependencies */
1417 tptr
+= strlen(keyword
) + 1;
1418 if (sscanf(tptr
, "%s", keyword
) != 1) break;
1419 if (keyword
[0] == '\n' || keyword
[0] == '\0') break;
1420 /* Recursive import */
1421 saveversion
= version
;
1422 importfromlibrary(mode
, libname
, keyword
);
1423 version
= saveversion
;
1430 if ((version
< 3.2) && (!dependencies
)) {
1431 Fprintf(stderr
, "Library does not have dependency list and cannot "
1432 "be trusted.\nLoad and rewrite library to update.\n");
1436 newobject
= new_library_object(mode
, keyword
, &redef
, nsptr
);
1438 load_in_progress
= True
;
1439 if (objectread(ps
, *newobject
, 0, 0, mode
, temp
, DEFAULTCOLOR
, nsptr
) == False
) {
1441 if (library_object_unique(mode
, *newobject
, redef
)) {
1442 add_object_to_library(mode
, *newobject
);
1443 cleanupaliases(mode
);
1445 /* pull in any instances of this object that */
1446 /* are defined in the library */
1449 if (fgets(temp
, 149, ps
) == NULL
) {
1450 Wprintf("Error in library.");
1453 else if (!strncmp(temp
, "% EndLib", 8))
1455 else if (strstr(temp
, "libinst") != NULL
) {
1456 if ((tptr
= strstr(temp
, objname
)) != NULL
) {
1457 if (*(tptr
- 1) == '/') {
1459 while (!isspace(*++eptr
));
1461 new_library_instance(mode
- LIBRARY
, tptr
, temp
, nsptr
);
1467 if (mode
!= FONTLIB
) {
1469 centerview(xobjs
.libtop
[mode
]);
1476 version
= PROG_VERSION
;
1477 load_in_progress
= False
;
1480 /*------------------------------------------------------*/
1481 /* Copy all technologies' replace flags into temp flag. */
1482 /* Then clear the replace flags (replace none) */
1483 /*------------------------------------------------------*/
1485 void TechReplaceSave()
1489 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
)
1491 if (nsp
->flags
& TECH_REPLACE
)
1492 nsp
->flags
|= TECH_REPLACE_TEMP
;
1494 nsp
->flags
&= ~TECH_REPLACE_TEMP
;
1495 nsp
->flags
&= ~TECH_REPLACE
;
1499 /*------------------------------------------------------*/
1500 /* Restore all technologies' replace flags */
1501 /*------------------------------------------------------*/
1503 void TechReplaceRestore()
1507 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
)
1509 if (nsp
->flags
& TECH_REPLACE_TEMP
)
1510 nsp
->flags
|= TECH_REPLACE
;
1512 nsp
->flags
&= ~TECH_REPLACE
;
1516 /*------------------------------------------------------*/
1517 /* Set all technologies' replace flags (replace all) */
1518 /*------------------------------------------------------*/
1520 void TechReplaceAll()
1524 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
)
1525 nsp
->flags
|= TECH_REPLACE
;
1528 /*------------------------------------------------------*/
1529 /* Clear all technologies' replace flags (replace none) */
1530 /*------------------------------------------------------*/
1532 void TechReplaceNone()
1536 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
)
1537 nsp
->flags
&= ~TECH_REPLACE
;
1541 /*------------------------------------------------------*/
1542 /* Compare an object's name with a specific technology */
1544 /* A missing "::" prefix separator or an empty prefix */
1545 /* both match a NULL technology or a technology name */
1546 /* that is an empty string (""). All of these */
1547 /* conditions indicate the default "user" technology. */
1548 /*------------------------------------------------------*/
1550 Boolean
CompareTechnology(objectptr cobj
, char *technology
)
1553 Boolean result
= FALSE
;
1555 if ((cptr
= strstr(cobj
->name
, "::")) != NULL
) {
1556 if (technology
== NULL
)
1557 result
= (cobj
->name
== cptr
) ? TRUE
: FALSE
;
1560 if (!strcmp(cobj
->name
, technology
)) result
= TRUE
;
1564 else if (technology
== NULL
)
1570 /*------------------------------------------------------*/
1571 /* Find a technology record */
1572 /*------------------------------------------------------*/
1574 TechPtr
LookupTechnology(char *technology
)
1577 Boolean usertech
= FALSE
;
1579 // A NULL technology is allowed as equivalent to a
1580 // technology name of "" (null string)
1582 if (technology
== NULL
)
1584 else if (*technology
== '\0')
1586 else if (!strcmp(technology
, "(user)"))
1589 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
) {
1590 if (usertech
== TRUE
) {
1591 if (*nsp
->technology
== '\0')
1594 if ((technology
!= NULL
) && !strcmp(technology
, nsp
->technology
))
1600 /*------------------------------------------------------*/
1601 /* Find a technology according to the filename */
1602 /*------------------------------------------------------*/
1604 TechPtr
GetFilenameTechnology(char *filename
)
1608 if (filename
== NULL
) return NULL
;
1610 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
)
1611 if (!filecmp(filename
, nsp
->filename
))
1617 /*------------------------------------------------------*/
1618 /* Find a technology record corresponding to the */
1619 /* indicated object's technology. */
1620 /*------------------------------------------------------*/
1622 TechPtr
GetObjectTechnology(objectptr thisobj
)
1626 /* int nlen; (jdk) */
1628 cptr
= strstr(thisobj
->name
, "::");
1629 if (cptr
== NULL
) return NULL
;
1632 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
)
1633 if (!strcmp(thisobj
->name
, nsp
->technology
))
1640 /*------------------------------------------------------*/
1641 /* Add a new technology name to the list */
1642 /*------------------------------------------------------*/
1644 TechPtr
AddNewTechnology(char *technology
, char *filename
)
1647 char usertech
[] = "";
1648 char *localtech
= technology
;
1650 // In the case where somebody has saved the contents of the user
1651 // technology to a file, create a technology->filename mapping
1652 // using a null string ("") for the technology name. If we are
1653 // only checking if a technology name exists (filename is NULL),
1654 // then ignore an reference to the user technology.
1656 if (technology
== NULL
) {
1657 if (filename
== NULL
) return NULL
;
1658 else localtech
= usertech
;
1661 for (nsp
= xobjs
.technologies
; nsp
!= NULL
; nsp
= nsp
->next
) {
1662 if (!strcmp(localtech
, nsp
->technology
)) {
1664 /* A namespace may be created for an object that is a dependency */
1665 /* in a different technology. If so, it will have a NULL */
1666 /* filename, and the filename should be replaced if we ever load */
1667 /* the file that properly defines the technology. */
1669 if ((nsp
->filename
== NULL
) && (filename
!= NULL
))
1670 nsp
->filename
= strdup(filename
);
1672 return nsp
; /* Namespace already exists */
1676 nsp
= (TechPtr
)malloc(sizeof(Technology
));
1677 nsp
->next
= xobjs
.technologies
;
1678 if (filename
== NULL
)
1679 nsp
->filename
= NULL
;
1681 nsp
->filename
= strdup(filename
);
1682 nsp
->technology
= strdup(localtech
);
1683 nsp
->flags
= (u_char
)0;
1684 xobjs
.technologies
= nsp
;
1689 /*------------------------------------------------------*/
1690 /* Check an object's name for a technology, and add it */
1691 /* to the list of technologies if it has one. */
1692 /*------------------------------------------------------*/
1694 void AddObjectTechnology(objectptr thisobj
)
1698 cptr
= strstr(thisobj
->name
, "::");
1701 AddNewTechnology(thisobj
->name
, NULL
);
1706 /*------------------------------------------------------*/
1707 /* Load a library page (given in parameter "mode") and */
1708 /* rename the library page to match the library name as */
1709 /* found in the file header. */
1710 /*------------------------------------------------------*/
1712 Boolean
loadlibrary(short mode
)
1715 objinstptr saveinst
;
1716 char temp
[150], keyword
[30], percentc
, inname
[150];
1717 TechPtr nsptr
= NULL
;
1719 ps
= libopen(_STR
, mode
, inname
, 149);
1721 if ((ps
== NULL
) && (mode
== FONTLIB
)) {
1722 /* We automatically try looking in all the usual places plus a */
1723 /* subdirectory named "fonts". */
1725 sprintf(temp
, "fonts/%s", _STR
);
1726 ps
= libopen(temp
, mode
, inname
, 149);
1729 Wprintf("Library not found.");
1733 /* current version is PROG_VERSION; however, all libraries newer than */
1734 /* version 2.0 require "Version" in the header. So unnumbered */
1735 /* libraries may be assumed to be version 1.9 or earlier. */
1739 if (fgets(temp
, 149, ps
) == NULL
) {
1740 Wprintf("Error in library.");
1744 sscanf(temp
, "%c %29s", &percentc
, keyword
);
1746 /* Commands in header are PostScript comments (%) */
1747 if (percentc
== '%') {
1749 /* The library name in the header corresponds to the object */
1750 /* technology defined by the library. This no longer has */
1751 /* anything to do with the name of the library page where we */
1752 /* are loading this file. */
1754 /* Save the technology, filename, and flags in the technology list. */
1756 if ((mode
!= FONTLIB
) && !strcmp(keyword
, "Library")) {
1758 cptr
= strchr(temp
, ':');
1762 /* Don't write terminating newline to the object's name string */
1765 /* The default user technology is written to the output */
1766 /* as "(user)". If this is found, replace it with a */
1768 if (!strcmp(cptr
, "(user)")) cptr
+= 6;
1770 /* Removing any leading pathname from the library name */
1771 if ((nptr
= strrchr(cptr
, '/')) != NULL
) cptr
= nptr
+ 1;
1773 /* Remove any ".lps" extension from the library name */
1775 nptr
= strrchr(cptr
, '.');
1776 if ((nptr
!= NULL
) && !strcmp(nptr
, ".lps")) *nptr
= '\0';
1778 nsptr
= AddNewTechnology(cptr
, inname
);
1781 // If anything was previously imported from this file
1782 // using importfromlibrary(), then the IMPORTED flag
1783 // will be set and needs to be cleared.
1784 nsptr
->flags
&= ~TECH_IMPORTED
;
1789 /* This comment gives the Xcircuit version number */
1790 else if (!strcmp(keyword
, "Version:")) {
1792 if (sscanf(temp
, "%*c %*s %f", &tmpv
) > 0) version
= tmpv
;
1795 /* This PostScript comment marks the end of the file header */
1796 else if (!strcmp(keyword
, "XCircuitLib")) break;
1800 /* Set the current top object to the library page so that any */
1801 /* expression parameters are computed with respect to the library, */
1802 /* not a page. Revert back to the page after loading the library. */
1804 saveinst
= areawin
->topinstance
;
1805 areawin
->topinstance
= xobjs
.libtop
[mode
];
1807 load_in_progress
= True
;
1808 objectread(ps
, topobject
, 0, 0, mode
, temp
, DEFAULTCOLOR
, nsptr
);
1809 load_in_progress
= False
;
1810 cleanupaliases(mode
);
1812 areawin
->topinstance
= saveinst
;
1814 if (mode
!= FONTLIB
) {
1816 centerview(xobjs
.libtop
[mode
]);
1817 if (nsptr
== NULL
) nsptr
= GetFilenameTechnology(inname
);
1819 Wprintf("Loaded library file %s", inname
);
1821 Wprintf("Loaded library file %s (technology %s)", inname
,
1825 Wprintf("Loaded font file %s", inname
);
1827 version
= PROG_VERSION
;
1830 /* Check if the library is read-only by opening for append */
1832 if ((mode
!= FONTLIB
) && (nsptr
!= NULL
)) {
1833 ps
= fopen(inname
, "a");
1835 nsptr
->flags
|= TECH_READONLY
;
1843 /*---------------------------------------------------------*/
1845 void startloadfile(int libnum
)
1848 short firstpage
= areawin
->page
;
1850 while (nextfilename()) {
1851 loadfile(0, libnum
);
1853 /* find next undefined page */
1855 while(areawin
->page
< xobjs
.pages
&&
1856 xobjs
.pagelist
[areawin
->page
]->pageinst
!= NULL
) areawin
->page
++;
1857 changepage(areawin
->page
);
1859 loadfile(0, libnum
);
1862 /* Prevent page change from being registered as an undoable action */
1863 savemode
= eventmode
;
1864 eventmode
= UNDO_MODE
;
1866 /* Display the first page loaded */
1868 eventmode
= savemode
;
1873 /*------------------------------------------------------*/
1874 /* normalloadfile() is a call to startloadfile(-1) */
1875 /* meaning load symbols to the User Library */
1876 /*------------------------------------------------------*/
1878 void normalloadfile()
1883 /*------------------------------------------------------*/
1884 /* Import an xcircuit file onto the current page */
1885 /*------------------------------------------------------*/
1889 while (nextfilename()) loadfile(1, -1);
1893 /*------------------------------------------------------*/
1894 /* Import an PPM graphic file onto the current page */
1895 /*------------------------------------------------------*/
1898 void importgraphic(void)
1903 if (eventmode
== CATALOG_MODE
) {
1904 Wprintf("Cannot import a graphic while in the library window.");
1908 if (!nextfilename()) {
1909 xc_tilde_expand(_STR
, 149);
1910 sscanf(_STR
, "%149s", inname
);
1911 if (!new_graphic(NULL
, inname
, 0, 0)) {
1912 Wprintf("Error: Graphic file not found.");
1917 Wprintf("Error: No graphic file to read.");
1921 #endif /* HAVE_CAIRO */
1923 /*--------------------------------------------------------------*/
1924 /* Skip forward in the input file to the next comment line */
1925 /*--------------------------------------------------------------*/
1927 void skiptocomment(char *temp
, int length
, FILE *ps
)
1933 } while (pch
== '\n');
1936 if (pch
== '%') fgets(temp
, length
, ps
);
1939 /*--------------------------------------------------------------*/
1940 /* ASG file import functions: */
1941 /* This function loads a SPICE deck (hspice format) */
1942 /*--------------------------------------------------------------*/
1951 if (eventmode
== CATALOG_MODE
) {
1952 Wprintf("Cannot import a netlist while in the library window.");
1956 if (!nextfilename()) {
1957 xc_tilde_expand(_STR
, 149);
1958 sscanf(_STR
, "%149s", inname
);
1959 spcfile
= fopen(inname
, "r");
1960 if (spcfile
!= NULL
) {
1962 Route(areawin
, False
);
1966 Wprintf("Error: Spice file not found.");
1971 Wprintf("Error: No spice file to read.");
1978 /*--------------------------------------------------------------*/
1979 /* Load an xcircuit file into xcircuit */
1981 /* mode = 0 is a "load" function. Behavior: load on */
1982 /* current page if empty. Otherwise, load on first empty */
1983 /* page found. If no empty pages exist, create a new page */
1984 /* and load there. */
1985 /* mode = 1 is an "import" function. Behavior: add */
1986 /* contents of file to the current page. */
1987 /* mode = 2 is a "library load" function. Behavior: add */
1988 /* objects in file to the user library but ignore the */
1989 /* page contents. */
1991 /* Return value: True if file was successfully loaded, False */
1993 /*--------------------------------------------------------------*/
1995 typedef struct _connects
*connectptr
;
1997 typedef struct _connects
{
2003 Boolean
loadfile(short mode
, int libnum
)
2006 char inname
[150], temp
[150], keyword
[30], percentc
, *pdchar
;
2007 char teststr
[50], teststr2
[20], pagestr
[100];
2008 short offx
, offy
, multipage
, page
, temppmode
= 0;
2011 connects
*connlist
= NULL
;
2012 struct stat statbuf
;
2013 int loclibnum
= (libnum
== -1) ? USERLIB
: libnum
;
2015 /* First, if we're in catalog mode, return with error */
2017 if (eventmode
== CATALOG_MODE
) {
2018 Wprintf("Cannot load file from library window");
2022 /* Do tilde/variable expansions on filename and open */
2023 ps
= fileopen(_STR
, "ps", inname
, 149);
2025 /* Could possibly be a library file? */
2026 /* (Note---loadfile() has no problems loading libraries */
2027 /* except for setting technology names and setting the */
2028 /* library page view at the end. The loadlibrary() routine */
2029 /* should probably be merged into this one.) */
2032 ps
= fileopen(_STR
, "lps", NULL
, 0);
2035 loadlibrary(loclibnum
);
2039 else if (!strcmp(inname
+ strlen(inname
) - 4, ".lps")) {
2041 loadlibrary(loclibnum
);
2047 /* Could possibly be an LGF file? */
2049 ps
= fileopen(_STR
, "lgf", NULL
, 0);
2057 /* Could possibly be an LGF backup (.lfo) file? */
2059 ps
= fileopen(_STR
, "lfo", NULL
, 0);
2068 /* Check for empty file---don't attempt to read empty files */
2070 if (fstat(fileno(ps
), &statbuf
) == 0 && (statbuf
.st_size
== (off_t
)0)) {
2076 /* What to do if no file was found. . . */
2079 if (topobject
->parts
== 0 && (mode
== 0)) {
2081 /* Check for file extension, and remove if "ps". */
2083 if ((pdchar
= strchr(_STR
, '.')) != NULL
)
2084 if (!strcmp(pdchar
+ 1, "ps")) *pdchar
= '\0';
2086 free(xobjs
.pagelist
[areawin
->page
]->filename
);
2087 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(_STR
);
2089 /* If the name has a path component, use only the root */
2090 /* for the object name, but the full path for the filename. */
2092 if ((pdchar
= strrchr(_STR
, '/')) != NULL
)
2093 sprintf(topobject
->name
, "%s", pdchar
+ 1);
2095 sprintf(topobject
->name
, "%s", _STR
);
2097 renamepage(areawin
->page
);
2098 printname(topobject
);
2099 Wprintf("Starting new drawing");
2102 Wprintf("Can't find file %s, won't overwrite current page", _STR
);
2113 if (fgets(temp
, 149, ps
) == NULL
) {
2114 Wprintf("Error: EOF in or before prolog.");
2117 sscanf(temp
, "%c%29s", &percentc
, keyword
);
2118 for (pdchar
= keyword
; isspace(*pdchar
); pdchar
++);
2119 if (percentc
== '%') {
2120 if (!strcmp(pdchar
, "XCircuit")) break;
2121 if (!strcmp(pdchar
, "XCircuitLib")) {
2122 /* version control in libraries is post version 1.9 */
2123 if (version
== 1.0) version
= 1.9;
2126 if (!strcmp(pdchar
, "%Page:")) break;
2127 if (strstr(pdchar
, "PS-Adobe") != NULL
)
2128 temppmode
= (strstr(temp
, "EPSF") != NULL
) ? 0 : 1;
2129 else if (!strcmp(pdchar
, "Version:"))
2130 sscanf(temp
, "%*c%*s %f", &version
);
2131 else if (!strcmp(pdchar
, "%Pages:")) {
2132 pdchar
= advancetoken(temp
);
2133 multipage
= atoi(pdchar
);
2135 /* Crash files get renamed back to their original filename */
2136 else if (!strcmp(pdchar
, "%Title:")) {
2137 if (xobjs
.tempfile
!= NULL
)
2138 if (!strcmp(inname
, xobjs
.tempfile
))
2139 sscanf(temp
, "%*c%*s %s", inname
);
2141 else if ((temppmode
== 1) && !strcmp(pdchar
, "%BoundingBox:")) {
2143 sscanf(temp
, "%*s %hd %hd %hd %hd", &botx
, &boty
,
2144 &(pagesize
.x
), &(pagesize
.y
));
2151 else if (percentc
== '-' && !strcmp(keyword
, "5")) {
2159 /* Look for old-style files (no %%Page; maximum one page in file) */
2161 if (!strcmp(pdchar
, "XCircuit"))
2162 skiptocomment(temp
, 149, ps
);
2164 for (page
= 0; page
< multipage
; page
++) {
2165 sprintf(pagestr
, "%d", page
+ 1);
2167 /* read out-of-page library definitions */
2169 if (strstr(temp
, "%%Page:") == NULL
&& strstr(temp
, "offsets") == NULL
) {
2170 load_in_progress
= True
;
2171 objectread(ps
, topobject
, 0, 0, loclibnum
, temp
, DEFAULTCOLOR
, NULL
);
2172 load_in_progress
= False
;
2175 if (strstr(temp
, "%%Page:") != NULL
) {
2176 sscanf(temp
+ 8, "%99s", pagestr
);
2178 /* Read the next line so any keywords in the Page name don't */
2179 /* confuse the parser. */
2180 if (fgets(temp
, 149, ps
) == NULL
) {
2181 Wprintf("Error: bad page header.");
2185 /* Library load mode: Ignore all pages, just load objects */
2187 while (strstr(temp
, "showpage") == NULL
) {
2188 if (fgets(temp
, 149, ps
) == NULL
) {
2189 Wprintf("Error: bad page definition.");
2193 skiptocomment(temp
, 149, ps
);
2198 /* go to new page if necessary */
2202 /* find next undefined page */
2204 while(areawin
->page
< xobjs
.pages
&&
2205 xobjs
.pagelist
[areawin
->page
]->pageinst
!= NULL
) areawin
->page
++;
2206 changepage(areawin
->page
);
2209 /* If this file was a library file then there is no page to load */
2211 if (strstr(temp
, "EndLib") != NULL
) {
2212 composelib(loclibnum
);
2213 centerview(xobjs
.libtop
[mode
]);
2214 Wprintf("Loaded library.");
2218 /* good so far; let's clear out the old data structure */
2221 reset(topobject
, NORMAL
);
2222 pagereset(areawin
->page
);
2223 xobjs
.pagelist
[areawin
->page
]->pmode
= temppmode
;
2224 if (temppmode
== 1) {
2225 xobjs
.pagelist
[areawin
->page
]->pagesize
.x
= pagesize
.x
;
2226 xobjs
.pagelist
[areawin
->page
]->pagesize
.y
= pagesize
.y
;
2230 invalidate_netlist(topobject
);
2231 /* ensure that the netlist for topobject is destroyed */
2232 freenetlist(topobject
);
2235 /* clear the undo record */
2238 /* read to the "scale" line, picking up inch/cm type, drawing */
2239 /* scale, and grid/snapspace along the way */
2243 if (strstr(temp
, "offsets") != NULL
) {
2244 /* Prior to version 3.1.28 only. . . */
2245 sscanf(temp
, "%c %hd %hd %*s", &percentc
, &offx
, &offy
);
2246 if(percentc
!= '%') {
2247 Wprintf("Something wrong in offsets line.");
2252 if ((temppmode
== 1) && strstr(temp
, "%%PageBoundingBox:") != NULL
) {
2253 /* Recast the individual page size if specified per page */
2254 sscanf(temp
, "%*s %*d %*d %hd %hd",
2255 &xobjs
.pagelist
[areawin
->page
]->pagesize
.x
,
2256 &xobjs
.pagelist
[areawin
->page
]->pagesize
.y
);
2258 else if (strstr(temp
, "drawingscale") != NULL
)
2259 sscanf(temp
, "%*c %hd:%hd %*s",
2260 &xobjs
.pagelist
[areawin
->page
]->drawingscale
.x
,
2261 &xobjs
.pagelist
[areawin
->page
]->drawingscale
.y
);
2263 else if (strstr(temp
, "hidden") != NULL
)
2264 topobject
->hidden
= True
;
2266 else if (strstr(temp
, "is_symbol") != NULL
) {
2267 sscanf(temp
, "%*c %49s", teststr
);
2268 checkschem(topobject
, teststr
);
2270 else if (strstr(temp
, "is_primary") != NULL
) {
2271 /* objectptr master; (jdk) */
2274 /* Save information about master schematic and link at end of load */
2275 sscanf(temp
, "%*c %49s", teststr
);
2276 newconn
= (connects
*)malloc(sizeof(connects
));
2277 newconn
->next
= connlist
;
2279 newconn
->page
= areawin
->page
;
2280 newconn
->master
= strdup(teststr
);
2283 else if (strstr(temp
, "gridspace"))
2284 sscanf(temp
, "%*c %f %f %*s", &xobjs
.pagelist
[areawin
->page
]->gridspace
,
2285 &xobjs
.pagelist
[areawin
->page
]->snapspace
);
2286 else if (strstr(temp
, "scale") != NULL
|| strstr(temp
, "rotate") != NULL
) {
2287 /* rotation (landscape mode) is optional; parse accordingly */
2289 sscanf(temp
, "%f %49s", &tmpfl
, teststr
);
2290 if (strstr(teststr
, "scale") != NULL
) {
2292 setgridtype(teststr
);
2294 if (strstr(teststr
, "inch"))
2295 Tcl_Eval(xcinterp
, "xcircuit::coordstyle inches");
2297 Tcl_Eval(xcinterp
, "xcircuit::coordstyle centimeters");
2299 xobjs
.pagelist
[areawin
->page
]->outscale
= tmpfl
;
2301 else if (!strcmp(teststr
, "rotate")) {
2302 xobjs
.pagelist
[areawin
->page
]->orient
= (short)tmpfl
;
2303 fgets(temp
, 149, ps
);
2304 sscanf(temp
, "%f %19s", &tmpfl
, teststr2
);
2305 if (strstr(teststr2
, "scale") != NULL
) {
2307 setgridtype(teststr2
);
2309 if (strstr(teststr2
, "inch"))
2310 Tcl_Eval(xcinterp
, "xcircuit::coordstyle inches");
2312 Tcl_Eval(xcinterp
, "xcircuit::coordstyle centimeters");
2314 xobjs
.pagelist
[areawin
->page
]->outscale
= tmpfl
;
2317 sscanf(temp
, "%*f %*f %19s", teststr2
);
2318 if (!strcmp(teststr2
, "scale"))
2319 xobjs
.pagelist
[areawin
->page
]->outscale
= tmpfl
/
2320 getpsscale(1.0, areawin
->page
);
2322 Wprintf("Error in scale/rotate constructs.");
2327 else { /* old style scale? */
2328 sscanf(temp
, "%*f %*s %19s", teststr2
);
2329 if ((teststr2
!= NULL
) && (!strcmp(teststr2
, "scale")))
2330 xobjs
.pagelist
[areawin
->page
]->outscale
= tmpfl
/
2331 getpsscale(1.0, areawin
->page
);
2333 Wprintf("Error in scale/rotate constructs.");
2338 else if (strstr(temp
, "setlinewidth") != NULL
) {
2339 sscanf(temp
, "%f %*s", &xobjs
.pagelist
[areawin
->page
]->wirewidth
);
2340 xobjs
.pagelist
[areawin
->page
]->wirewidth
/= 1.3;
2343 else if (strstr(temp
, "insertion") != NULL
) {
2344 /* read in an included background image */
2347 else if (strstr(temp
, "<<") != NULL
) {
2348 char *buffer
= temp
, *endptr
;
2349 /* Make sure we have the whole dictionary before calling */
2350 while (strstr(buffer
, ">>") == NULL
) {
2351 if (buffer
== temp
) {
2352 buffer
= (char *)malloc(strlen(buffer
) + 150);
2353 strcpy(buffer
, temp
);
2356 buffer
= (char *)realloc(buffer
, strlen(buffer
) + 150);
2357 endptr
= ridnewline(buffer
);
2359 fgets(endptr
, 149, ps
);
2361 /* read top-level parameter dictionary */
2362 readparams(NULL
, NULL
, topobject
, buffer
);
2363 if (buffer
!= temp
) free(buffer
);
2366 if (fgets(temp
, 149, ps
) == NULL
) {
2367 Wprintf("Error: Problems encountered in page header.");
2372 load_in_progress
= True
;
2373 objectread(ps
, topobject
, offx
, offy
, LIBRARY
, temp
, DEFAULTCOLOR
, NULL
);
2374 load_in_progress
= False
;
2376 /* skip to next page boundary or file trailer */
2378 if (strstr(temp
, "showpage") != NULL
&& multipage
!= 1) {
2381 skiptocomment(temp
, 149, ps
);
2383 /* check for new filename if this is a crash recovery file */
2384 if ((fstop
= strstr(temp
, "is_filename")) != NULL
) {
2385 strncpy(inname
, temp
+ 2, (int)(fstop
- temp
- 3));
2386 *(inname
+ (int)(fstop
- temp
) - 3) = '\0';
2387 fgets(temp
, 149, ps
);
2388 skiptocomment(temp
, 149, ps
);
2392 /* Finally: set the filename and pagename for this page */
2395 char tpstr
[6], *rootptr
;
2397 /* Set filename and page title. */
2399 if (xobjs
.pagelist
[areawin
->page
]->filename
!= NULL
)
2400 free(xobjs
.pagelist
[areawin
->page
]->filename
);
2401 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(inname
);
2403 /* Get the root name (after all path components) */
2405 rootptr
= strrchr(xobjs
.pagelist
[areawin
->page
]->filename
, '/');
2406 if (rootptr
== NULL
) rootptr
= xobjs
.pagelist
[areawin
->page
]->filename
;
2409 /* If we didn't read in a page name from the %%Page: header line, then */
2410 /* set the page name to the root name of the file. */
2412 sprintf(tpstr
, "%d", page
+ 1);
2413 if (!strcmp(pagestr
, tpstr
)) {
2414 if (rootptr
== NULL
)
2415 sprintf(topobject
->name
, "Page %d", page
+ 1);
2417 sprintf(topobject
->name
, "%.79s", rootptr
);
2419 /* Delete filename extensions ".ps" or ".eps" from the page name */
2420 if ((pdchar
= strrchr(topobject
->name
, '.')) != NULL
) {
2421 if (!strcmp(pdchar
+ 1, "ps") || !strcmp(pdchar
+ 1, "eps"))
2426 sprintf(topobject
->name
, "%.79s", pagestr
);
2428 renamepage(areawin
->page
);
2431 /* set object position to fit to window separately for each page */
2432 calcbbox(areawin
->topinstance
);
2433 centerview(areawin
->topinstance
);
2436 /* Crash file recovery: read any out-of-page library definitions tacked */
2437 /* onto the end of the file into the user library. */
2438 if (strncmp(temp
, "%%Trailer", 9)) {
2439 load_in_progress
= True
;
2440 objectread(ps
, topobject
, 0, 0, USERLIB
, temp
, DEFAULTCOLOR
, NULL
);
2441 load_in_progress
= False
;
2444 cleanupaliases(USERLIB
);
2446 /* Connect master->slave schematics */
2447 while (connlist
!= NULL
) {
2448 connects
*thisconn
= connlist
;
2449 objectptr master
= NameToPageObject(thisconn
->master
, NULL
, NULL
);
2451 xobjs
.pagelist
[thisconn
->page
]->pageinst
->thisobject
->symschem
= master
;
2452 xobjs
.pagelist
[thisconn
->page
]->pageinst
->thisobject
->schemtype
= SECONDARY
;
2455 Fprintf(stderr
, "Error: Cannot find primary schematic for %s\n",
2456 xobjs
.pagelist
[thisconn
->page
]->pageinst
->thisobject
->name
);
2458 connlist
= thisconn
->next
;
2459 free(thisconn
->master
);
2463 Wprintf("Loaded file: %s (%d page%s)", inname
, multipage
,
2464 (multipage
> 1 ? "s" : ""));
2466 composelib(loclibnum
);
2467 centerview(xobjs
.libtop
[loclibnum
]);
2468 composelib(PAGELIB
);
2470 if (version
> PROG_VERSION
+ VEPS
) {
2471 Wprintf("WARNING: file %s is version %2.1f vs. executable version %2.1f",
2472 inname
, version
, PROG_VERSION
);
2475 version
= PROG_VERSION
;
2480 /*------------------------------------------------------*/
2481 /* Object name comparison: True if names are equal, */
2482 /* not counting leading underscores. */
2483 /*------------------------------------------------------*/
2485 int objnamecmp(char *name1
, char *name2
)
2487 char *n1ptr
= name1
;
2488 char *n2ptr
= name2
;
2490 while (*n1ptr
== '_') n1ptr
++;
2491 while (*n2ptr
== '_') n2ptr
++;
2493 return (strcmp(n1ptr
, n2ptr
));
2496 /*------------------------------------------------------*/
2497 /* Standard delimiter matching character. */
2498 /*------------------------------------------------------*/
2500 char standard_delimiter_end(char source
)
2504 case '(': target
= ')'; break;
2505 case '[': target
= ']'; break;
2506 case '{': target
= '}'; break;
2507 case '<': target
= '>'; break;
2508 default: target
= source
;
2513 /*------------------------------------------------------*/
2514 /* Find matching parenthesis, bracket, brace, or tag */
2515 /* Don't count when backslash character '\' is in front */
2516 /*------------------------------------------------------*/
2518 u_char
*find_delimiter(u_char
*fstring
)
2522 u_char
*search
= fstring
;
2523 u_char source
= *fstring
;
2526 target
= (u_char
)standard_delimiter_end((char)source
);
2527 while (*++search
!= '\0') {
2528 if (*search
== source
&& *(search
- 1) != '\\') count
++;
2529 else if (*search
== target
&& *(search
- 1) != '\\') count
--;
2530 if (count
== 0) break;
2535 /*----------------------------------------------------------------------*/
2536 /* Remove unnecessary font change information from a label */
2537 /*----------------------------------------------------------------------*/
2539 void cleanuplabel(stringpart
**strhead
)
2541 stringpart
*curpart
= *strhead
;
2542 int oldfont
, curfont
;
2543 Boolean fline
= False
;
2545 oldfont
= curfont
= -1;
2547 while (curpart
!= NULL
) {
2548 switch (curpart
->type
) {
2550 if (curfont
== curpart
->data
.font
) {
2551 /* Font change is redundant: remove it */
2552 /* Careful! font changes remove overline/underline; if */
2553 /* either one is in effect, replace it with "noline" */
2555 curpart
->type
= NOLINE
;
2557 curpart
= deletestring(curpart
, strhead
, NULL
);
2560 curfont
= curpart
->data
.font
;
2565 /* Old style font scale is always written absolute, not relative. */
2566 /* Changes in scale were not allowed, so just get rid of them. */
2568 curpart
= deletestring(curpart
, strhead
, areawin
->topinstance
);
2571 /* A font change may occur inside a parameter, so any font */
2572 /* declaration after a parameter must be considered to be */
2576 curfont
= oldfont
= -1;
2579 case OVERLINE
: case UNDERLINE
:
2587 case NORMALSCRIPT
: case RETURN
:
2588 if (oldfont
!= -1) {
2594 case SUBSCRIPT
: case SUPERSCRIPT
:
2599 if (curpart
!= NULL
)
2600 curpart
= curpart
->nextpart
;
2604 /*----------------------------------------------------------------------*/
2605 /* Read label segments */
2606 /*----------------------------------------------------------------------*/
2608 void readlabel(objectptr localdata
, char *lineptr
, stringpart
**strhead
)
2610 Boolean fline
= False
;
2611 /* char *sptr; (jdk) */
2613 char *endptr
, *segptr
= lineptr
;
2615 stringpart
*newpart
;
2618 while (*segptr
!= '\0') { /* Look through all segments */
2620 while (isspace(*segptr
) && (*segptr
!= '\0')) segptr
++;
2622 if (*segptr
== '(' || *segptr
== '{') {
2623 endptr
= find_delimiter(segptr
);
2625 /* null string (e.g., null parameter substitution) */
2626 if ((*segptr
== '(') && (*(segptr
+ 1) == '\0')) {
2631 else if (*segptr
== '\0' || *segptr
== '}') break;
2633 makesegment(strhead
, *strhead
);
2636 /* Embedded command is in braces: {} */
2638 if (*segptr
== '{') {
2640 /* Find the command for this PostScript procedure */
2641 char *cmdptr
= endptr
- 2;
2642 while (isspace(*cmdptr
)) cmdptr
--;
2643 while (!isspace(*cmdptr
) && (cmdptr
> segptr
)) cmdptr
--;
2647 if (!strncmp(cmdptr
, "Ss", 2))
2648 newpart
->type
= SUPERSCRIPT
;
2649 else if (!strncmp(cmdptr
, "ss", 2))
2650 newpart
->type
= SUBSCRIPT
;
2651 else if (!strncmp(cmdptr
, "ns", 2))
2652 newpart
->type
= NORMALSCRIPT
;
2653 else if (!strncmp(cmdptr
, "hS", 2))
2654 newpart
->type
= HALFSPACE
;
2655 else if (!strncmp(cmdptr
, "qS", 2))
2656 newpart
->type
= QTRSPACE
;
2657 else if (!strncmp(cmdptr
, "CR", 2)) {
2658 newpart
->type
= RETURN
;
2659 newpart
->data
.flags
= 0;
2661 else if (!strcmp(cmdptr
, "Ts")) /* "Tab set" command */
2662 newpart
->type
= TABSTOP
;
2663 else if (!strcmp(cmdptr
, "Tf")) /* "Tab forward" command */
2664 newpart
->type
= TABFORWARD
;
2665 else if (!strcmp(cmdptr
, "Tb")) /* "Tab backward" command */
2666 newpart
->type
= TABBACKWARD
;
2667 else if (!strncmp(cmdptr
, "ol", 2)) {
2668 newpart
->type
= OVERLINE
;
2671 else if (!strncmp(cmdptr
, "ul", 2)) {
2672 newpart
->type
= UNDERLINE
;
2675 else if (!strncmp(cmdptr
, "sce", 3)) { /* revert to default color */
2676 newpart
->type
= FONT_COLOR
;
2677 newpart
->data
.color
= DEFAULTCOLOR
;
2679 else if (cmdptr
== segptr
) { /* cancel over- or underline */
2680 newpart
->type
= NOLINE
;
2683 /* To-do: replace old-style backspace with tab stop */
2684 else if (!strcmp(cmdptr
, "bs")) {
2685 Wprintf("Warning: Obsolete backspace command ommitted in text");
2687 else if (!strcmp(cmdptr
, "Kn")) { /* "Kern" command */
2689 sscanf(segptr
, "%d %d", &kx
, &ky
);
2690 newpart
->type
= KERN
;
2691 newpart
->data
.kern
[0] = kx
;
2692 newpart
->data
.kern
[1] = ky
;
2694 else if (!strcmp(cmdptr
, "MR")) { /* "Margin stop" command */
2696 sscanf(segptr
, "%d", &width
);
2697 newpart
->type
= MARGINSTOP
;
2698 newpart
->data
.width
= width
;
2700 else if (!strcmp(cmdptr
, "scb")) { /* change color command */
2703 sscanf(segptr
, "%f %f %f", &cr
, &cg
, &cb
);
2704 newpart
->type
= FONT_COLOR
;
2705 cindex
= rgb_alloccolor((int)(cr
* 65535), (int)(cg
* 65535),
2707 newpart
->data
.color
= cindex
;
2709 else if (!strcmp(cmdptr
, "cf")) { /* change font or scale command */
2710 char *nextptr
, *newptr
= segptr
;
2712 /* Set newptr to the fontname and nextptr to the next token. */
2713 while (*newptr
!= '/' && *newptr
!= '\0') newptr
++;
2714 if (*newptr
++ == '\0') {
2715 Wprintf("Error: Bad change-font command");
2716 newpart
->type
= NOLINE
; /* placeholder */
2718 for (nextptr
= newptr
; !isspace(*nextptr
); nextptr
++);
2719 *(nextptr
++) = '\0';
2720 while (isspace(*nextptr
)) nextptr
++;
2722 for (j
= 0; j
< fontcount
; j
++)
2723 if (!strcmp(newptr
, fonts
[j
].psname
))
2726 if (j
== fontcount
) /* this is a non-loaded font */
2727 if (loadfontfile(newptr
) < 0) {
2728 if (fontcount
> 0) {
2729 Wprintf("Error: Font \"%s\" not found---using default.", newptr
);
2733 Wprintf("Error: No fonts!");
2734 newpart
->type
= NOLINE
; /* placeholder */
2738 if (isdigit(*nextptr
)) { /* second form of "cf" command---includes scale */
2740 sscanf(nextptr
, "%f", &locscale
);
2741 newpart
->type
= FONT_SCALE
;
2742 newpart
->data
.scale
= locscale
;
2743 makesegment(strhead
, *strhead
);
2746 newpart
->type
= FONT_NAME
;
2747 newpart
->data
.font
= j
;
2749 else { /* This exec isn't a known label function */
2750 Wprintf("Error: unknown substring function");
2751 newpart
->type
= NOLINE
; /* placeholder */
2755 /* Text substring is in parentheses: () */
2757 else if (*segptr
== '(') {
2758 if (fline
== True
) {
2759 newpart
->type
= NOLINE
;
2760 makesegment(strhead
, *strhead
);
2764 newpart
->type
= TEXT_STRING
;
2765 newpart
->data
.string
= (u_char
*)malloc(1 + strlen(++segptr
));
2767 /* Copy string, translating octal codes into 8-bit characters */
2768 parse_ps_string(segptr
, newpart
->data
.string
, strlen(segptr
), TRUE
, TRUE
);
2771 /* Parameterized substrings are denoted by parameter key. */
2772 /* The parameter (default and/or substitution value) is */
2773 /* assumed to exist. */
2777 parse_ps_string(segptr
, key
, 99, FALSE
, TRUE
);
2778 if (strlen(key
) > 0) {
2779 newpart
->type
= PARAM_START
;
2780 newpart
->data
.string
= (char *)malloc(1 + strlen(key
));
2781 strcpy(newpart
->data
.string
, key
);
2783 /* check for compatibility between the parameter value and */
2784 /* the number of parameters and parameter type. */
2786 ops
= match_param(localdata
, key
);
2788 Fprintf(stderr
, "readlabel() error: No such parameter %s!\n", key
);
2789 deletestring(newpart
, strhead
, areawin
->topinstance
);
2792 /* Fprintf(stdout, "Parameter %s called from object %s\n", */
2793 /* key, localdata->name); */
2795 endptr
= segptr
+ 1;
2796 while (!isspace(*endptr
) && (*endptr
!= '\0')) endptr
++;
2802 /*--------------------------------------*/
2803 /* skip over whitespace in string input */
2804 /*--------------------------------------*/
2806 char *skipwhitespace(char *lineptr
)
2808 char *locptr
= lineptr
;
2810 while (isspace(*locptr
) && (*locptr
!= '\n') && (*locptr
!= '\0')) locptr
++;
2814 /*-------------------------------------------*/
2815 /* advance to the next token in string input */
2816 /*-------------------------------------------*/
2818 char *advancetoken(char *lineptr
)
2820 char *locptr
= lineptr
;
2822 while (!isspace(*locptr
) && (*locptr
!= '\n') && (*locptr
!= '\0')) locptr
++;
2823 while (isspace(*locptr
) && (*locptr
!= '\n') && (*locptr
!= '\0')) locptr
++;
2827 /*------------------------------------------------------*/
2828 /* Read a parameter list for an object instance call. */
2829 /* This uses the key-value dictionary method but also */
2830 /* allows the "old style" in which each parameter */
2831 /* was automatically assigned the key v1, v2, etc. */
2832 /*------------------------------------------------------*/
2834 void readparams(objectptr localdata
, objinstptr newinst
, objectptr libobj
,
2837 oparamptr newops
, objops
, fops
;
2838 char *arrayptr
, *endptr
, *arraynext
;
2842 if ((arrayptr
= strstr(buffer
, "<<")) == NULL
)
2843 if ((arrayptr
= strchr(buffer
, '[')) == NULL
)
2846 endptr
= find_delimiter(arrayptr
);
2847 if (*arrayptr
== '<') {
2848 arrayptr
++; /* move to second '<' in "<<" */
2849 endptr
--; /* back up to first '>' in ">>" */
2852 /* move to next non-space token after opening bracket */
2854 while (isspace(*arrayptr
) && *arrayptr
!= '\0') arrayptr
++;
2856 while ((*arrayptr
!= '\0') && (arrayptr
< endptr
)) {
2858 newops
= (oparamptr
)malloc(sizeof(oparam
));
2860 /* Arrays contain values only. Dictionaries contain key:value pairs */
2861 if (*endptr
== '>') { /* dictionary type */
2862 if (*arrayptr
!= '/') {
2863 Fprintf(stdout
, "Error: Dictionary key is a literal, not a name\n");
2865 else arrayptr
++; /* Skip PostScript name delimiter */
2866 parse_ps_string(arrayptr
, paramkey
, 99, FALSE
, TRUE
);
2867 newops
->key
= (char *)malloc(1 + strlen(paramkey
));
2868 strcpy(newops
->key
, paramkey
);
2869 arrayptr
= advancetoken(arrayptr
);
2871 else { /* array type; keys are "v1", "v2", etc. */
2873 newops
->key
= (char *)malloc(6);
2874 sprintf(newops
->key
, "v%d", paramno
);
2877 /* Find matching parameter in object definition */
2879 objops
= match_param(libobj
, newops
->key
);
2880 if (objops
== NULL
) {
2881 Fprintf(stdout
, "Error: parameter %s does not exist in object %s!\n",
2882 newops
->key
, libobj
->name
);
2889 /* Add to instance's parameter list */
2890 /* If newinst is null, then the parameters are added to libobj */
2891 newops
->next
= NULL
;
2894 /* Delete any parameters with duplicate names. This */
2895 /* This may indicate an expression parameter that was */
2896 /* precomputed while determining the bounding box. */
2898 for (fops
= newinst
->params
; fops
!= NULL
; fops
= fops
->next
)
2899 if (!strcmp(fops
->key
, newops
->key
))
2900 if ((fops
= free_instance_param(newinst
, fops
)) == NULL
)
2903 if (newinst
->params
== NULL
)
2904 newinst
->params
= newops
;
2906 for (fops
= newinst
->params
; fops
->next
!= NULL
; fops
= fops
->next
);
2907 fops
->next
= newops
;
2911 if (libobj
->params
== NULL
)
2912 libobj
->params
= newops
;
2914 for (fops
= libobj
->params
; fops
->next
!= NULL
; fops
= fops
->next
);
2915 fops
->next
= newops
;
2919 /* Fill in "which" entry from the object default */
2920 newops
->which
= (newinst
) ? objops
->which
: 0;
2922 /* Check next token. If not either end-of-dictionary or */
2923 /* the next parameter key, then value is an expression. */
2924 /* Expressions are written as two strings, the first the */
2925 /* result of evaluting the expression, and the second the */
2926 /* expression itself, followed by "pop" to prevent the */
2927 /* PostScript interpreter from trying to evaluate the */
2928 /* expression (which is not in PostScript). */
2930 if (*arrayptr
== '(' || *arrayptr
== '{')
2931 arraynext
= find_delimiter(arrayptr
);
2933 arraynext
= arrayptr
;
2934 arraynext
= advancetoken(arraynext
);
2936 if ((*endptr
== '>') && (arraynext
< endptr
) && (*arraynext
!= '/')) {
2937 char *substrend
, *arraysave
;
2939 if (*arraynext
== '(' || *arraynext
== '{') {
2941 substrend
= find_delimiter(arraynext
);
2942 arraysave
= arraynext
+ 1;
2943 arraynext
= advancetoken(substrend
);
2945 newops
->type
= (u_char
)XC_EXPR
;
2946 newops
->which
= P_EXPRESSION
; /* placeholder */
2949 if (strncmp(arraynext
, "pop ", 4)) {
2950 Wprintf("Error: bad expression parameter!\n");
2952 newops
->parameter
.expr
= strdup("expr 0");
2954 newops
->parameter
.expr
= strdup("0");
2956 arrayptr
= advancetoken(arrayptr
);
2959 newops
->parameter
.expr
= strdup(arraysave
);
2960 arrayptr
= advancetoken(arraynext
);
2964 else if (*arrayptr
== '(' || *arrayptr
== '{') {
2966 char *substrend
, csave
;
2967 stringpart
*endpart
;
2969 /* type XC_STRING */
2971 substrend
= find_delimiter(arrayptr
);
2972 csave
= *(++substrend
);
2974 if (*arrayptr
== '{') arrayptr
++;
2976 /* A numerical value immediately following the opening */
2977 /* brace indicates a color parameter. */
2978 if (sscanf(arrayptr
, "%f %f %f", &r
, &g
, &b
) == 3) {
2979 newops
->type
= (u_char
)XC_INT
;
2980 newops
->which
= P_COLOR
;
2981 newops
->parameter
.ivalue
= rgb_alloccolor((int)(r
* 65535),
2982 (int)(g
* 65535), (int)(b
* 65535));
2986 char *arraytmp
= arrayptr
;
2987 char linkdefault
[5] = "(%n)";
2989 newops
->type
= (u_char
)XC_STRING
;
2990 newops
->which
= P_SUBSTRING
;
2991 newops
->parameter
.string
= NULL
;
2993 /* Quick check for "link" parameter: make object name into "%n" */
2994 if (!strcmp(newops
->key
, "link"))
2995 if (!strncmp(arrayptr
+ 1, libobj
->name
, strlen(libobj
->name
)) &&
2996 !strcmp(arrayptr
+ strlen(libobj
->name
) + 1, ")"))
2997 arraytmp
= linkdefault
;
2999 readlabel(libobj
, arraytmp
, &(newops
->parameter
.string
));
3002 /* Append a PARAM_END to the parameter string */
3004 endpart
= makesegment(&(newops
->parameter
.string
), NULL
);
3005 endpart
->type
= PARAM_END
;
3006 endpart
->data
.string
= (u_char
*)NULL
;
3008 arrayptr
= substrend
;
3009 while (isspace(*arrayptr
) && *arrayptr
!= '\0')
3013 /* char *token; (jdk) */
3016 /* type XC_FLOAT or XC_INT, or an indirect reference */
3018 newops
->type
= (newinst
) ? objops
->type
: (u_char
)XC_FLOAT
;
3020 if (newops
->type
== XC_FLOAT
) {
3021 scanned
= sscanf(arrayptr
, "%f", &(newops
->parameter
.fvalue
));
3022 /* Fprintf(stdout, "Object %s called with parameter "
3023 "%s value %g\n", libobj->name,
3024 newops->key, newops->parameter.fvalue); */
3026 else if (newops
->type
== XC_INT
) {
3027 scanned
= sscanf(arrayptr
, "%d", &(newops
->parameter
.ivalue
));
3028 /* Fprintf(stdout, "Object %s called with parameter "
3029 "%s value %d\n", libobj->name,
3030 newops->key, newops->parameter.ivalue); */
3032 else if (newops
->type
== XC_EXPR
) {
3033 /* Instance values of parameters hold the last evaluated */
3034 /* result and will be regenerated, so we can ignore them */
3035 /* here. By ignoring it, we don't have to deal with issues */
3036 /* like type promotion. */
3037 free_instance_param(newinst
, newops
);
3038 scanned
= 1; /* avoid treating as an indirect ref */
3040 else if (newops
->type
== XC_STRING
) {
3041 /* Fill string record, so we have a valid record. This will */
3042 /* be blown away and replaced by opsubstitute(), but it must */
3043 /* have an initial valid entry. */
3045 newops
->parameter
.string
= NULL
;
3046 tmpptr
= makesegment(&newops
->parameter
.string
, NULL
);
3047 tmpptr
->type
= TEXT_STRING
;
3048 tmpptr
= makesegment(&newops
->parameter
.string
, NULL
);
3049 tmpptr
->type
= PARAM_END
;
3052 Fprintf(stderr
, "Error: unknown parameter type!\n");
3056 /* Indirect reference --- create an eparam in the instance */
3057 parse_ps_string(arrayptr
, paramkey
, 99, FALSE
, TRUE
);
3059 if (!newinst
|| !localdata
) {
3060 /* Only object instances can use indirect references */
3061 Fprintf(stderr
, "Error: parameter default %s cannot "
3062 "be parsed!\n", paramkey
);
3064 else if (match_param(localdata
, paramkey
) == NULL
) {
3065 /* Reference key must exist in the calling object */
3066 Fprintf(stderr
, "Error: parameter value %s cannot be parsed!\n",
3070 /* Create an eparam record in the instance */
3071 eparamptr newepp
= make_new_eparam(paramkey
);
3072 newepp
->flags
|= P_INDIRECT
;
3073 newepp
->pdata
.refkey
= strdup(newops
->key
);
3074 newepp
->next
= newinst
->passed
;
3075 newinst
->passed
= newepp
;
3079 arrayptr
= advancetoken(arrayptr
);
3083 /* Calculate the unique bounding box for the instance */
3085 if (newinst
&& (newinst
->params
!= NULL
)) {
3086 opsubstitute(libobj
, newinst
);
3087 calcbboxinst(newinst
);
3091 /*--------------------------------------------------------------*/
3092 /* Read a value which might be a short integer or a parameter. */
3093 /* If the value is a parameter, check the parameter list to see */
3094 /* if it needs to be re-typecast. Return the position to the */
3095 /* next token in "lineptr". */
3096 /*--------------------------------------------------------------*/
3098 char *varpscan(objectptr localdata
, char *lineptr
, short *hvalue
,
3099 genericptr thiselem
, int pointno
, int offset
, u_char which
)
3101 oparamptr ops
= NULL
;
3103 /* char *nexttok; (jdk) */
3106 if (sscanf(lineptr
, "%hd", hvalue
) != 1) {
3107 parse_ps_string(lineptr
, key
, 99, FALSE
, TRUE
);
3109 ops
= match_param(localdata
, key
);
3110 newepp
= make_new_eparam(key
);
3112 /* Add parameter to the linked list */
3113 newepp
->next
= thiselem
->passed
;
3114 thiselem
->passed
= newepp
;
3115 newepp
->pdata
.pointno
= pointno
;
3119 /* It cannot be known whether a parameter value is a float or int */
3120 /* until we see how the parameter is used. So we always read the */
3121 /* parameter default as a float, and re-typecast it if necessary. */
3123 if (ops
->type
== XC_FLOAT
) {
3125 /* (add 0.1 to avoid roundoff error in conversion to integer) */
3126 ops
->parameter
.ivalue
= (int)(ops
->parameter
.fvalue
+
3127 ((ops
->parameter
.fvalue
< 0) ? -0.1 : 0.1));
3130 *hvalue
= (short)ops
->parameter
.ivalue
;
3133 *hvalue
= 0; /* okay; will get filled in later */
3134 Fprintf(stderr
, "Error: parameter %s was used but not defined!\n", key
);
3138 *hvalue
-= (short)offset
;
3140 return advancetoken(skipwhitespace(lineptr
));
3143 /*--------------------------------------------------------------*/
3144 /* Read a value which might be a short integer or a parameter, */
3145 /* but which is not a point in a pointlist. */
3146 /*--------------------------------------------------------------*/
3148 char *varscan(objectptr localdata
, char *lineptr
, short *hvalue
,
3149 genericptr thiselem
, u_char which
)
3151 return varpscan(localdata
, lineptr
, hvalue
, thiselem
, 0, 0, which
);
3154 /*--------------------------------------------------------------*/
3155 /* Read a value which might be a float or a parameter. */
3156 /* Return the position to the next token in "lineptr". */
3157 /*--------------------------------------------------------------*/
3159 char *varfscan(objectptr localdata
, char *lineptr
, float *fvalue
,
3160 genericptr thiselem
, u_char which
)
3162 oparamptr ops
= NULL
;
3166 if (sscanf(lineptr
, "%f", fvalue
) != 1) {
3167 parse_ps_string(lineptr
, key
, 99, FALSE
, TRUE
);
3169 /* This bit of a hack takes care of scale-variant */
3170 /* linewidth specifiers for object instances. */
3172 if (!strncmp(key
, "/sv", 3)) {
3173 ((objinstptr
)thiselem
)->style
&= ~LINE_INVARIANT
;
3174 return varfscan(localdata
, advancetoken(skipwhitespace(lineptr
)),
3175 fvalue
, thiselem
, which
);
3178 ops
= match_param(localdata
, key
);
3179 newepp
= make_new_eparam(key
);
3181 /* Add parameter to the linked list */
3182 newepp
->next
= thiselem
->passed
;
3183 thiselem
->passed
= newepp
;
3187 *fvalue
= ops
->parameter
.fvalue
;
3190 Fprintf(stderr
, "Error: no parameter \"%s\" defined!\n", key
);
3193 /* advance to next token */
3194 return advancetoken(skipwhitespace(lineptr
));
3197 /*--------------------------------------------------------------*/
3198 /* Same as varpscan(), but for path types only. */
3199 /*--------------------------------------------------------------*/
3201 char *varpathscan(objectptr localdata
, char *lineptr
, short *hvalue
,
3202 genericptr
*thiselem
, pathptr thispath
, int pointno
, int offset
,
3203 u_char which
, eparamptr
*nepptr
)
3205 oparamptr ops
= NULL
;
3209 if (nepptr
!= NULL
) *nepptr
= NULL
;
3211 if (sscanf(lineptr
, "%hd", hvalue
) != 1) {
3212 parse_ps_string(lineptr
, key
, 99, FALSE
, TRUE
);
3213 ops
= match_param(localdata
, key
);
3214 newepp
= make_new_eparam(key
);
3215 newepp
->pdata
.pathpt
[1] = pointno
;
3217 if (thiselem
== NULL
)
3218 newepp
->pdata
.pathpt
[0] = (short)0;
3220 short elemidx
= (short)(thiselem
- thispath
->plist
);
3221 if (elemidx
>= 0 && elemidx
< thispath
->parts
)
3222 newepp
->pdata
.pathpt
[0] = (short)(thiselem
- thispath
->plist
);
3224 Fprintf(stderr
, "Error: Bad parameterized path point!\n");
3229 if (nepptr
!= NULL
) *nepptr
= newepp
;
3231 /* Add parameter to the linked list. */
3233 newepp
->next
= thispath
->passed
;
3234 thispath
->passed
= newepp
;
3238 /* It cannot be known whether a parameter value is a float or int */
3239 /* until we see how the parameter is used. So we always read the */
3240 /* parameter default as a float, and re-typecast it if necessary. */
3242 if (ops
->type
== XC_FLOAT
) {
3244 /* (add 0.1 to avoid roundoff error in conversion to integer) */
3245 ops
->parameter
.ivalue
= (int)(ops
->parameter
.fvalue
+
3246 ((ops
->parameter
.fvalue
< 0) ? -0.1 : 0.1));
3249 *hvalue
= (short)ops
->parameter
.ivalue
;
3252 *hvalue
= 0; /* okay; will get filled in later */
3253 Fprintf(stderr
, "Error: parameter %s was used but not defined!\n", key
);
3258 *hvalue
-= (short)offset
;
3259 return advancetoken(skipwhitespace(lineptr
));
3262 /*--------------------------------------------------------------*/
3263 /* Create a new instance of an object in the library's list of */
3264 /* instances. This instance will be used on the library page */
3265 /* when doing "composelib()". */
3266 /*--------------------------------------------------------------*/
3268 objinstptr
addtoinstlist(int libnum
, objectptr libobj
, Boolean
virtual)
3270 objinstptr newinst
= (objinstptr
) malloc(sizeof(objinst
));
3271 liblistptr spec
= (liblistptr
) malloc(sizeof(liblist
));
3274 newinst
->type
= OBJINST
;
3275 instancedefaults(newinst
, libobj
, 0, 0);
3277 spec
->virtual = (u_char
)virtual;
3278 spec
->thisinst
= newinst
;
3281 /* Add to end, so that duplicate, parameterized instances */
3282 /* always come after the original instance with the default */
3285 if ((srch
= xobjs
.userlibs
[libnum
].instlist
) == NULL
)
3286 xobjs
.userlibs
[libnum
].instlist
= spec
;
3288 while (srch
->next
!= NULL
) srch
= srch
->next
;
3292 /* Calculate the instance-specific bounding box */
3293 calcbboxinst(newinst
);
3298 /*--------------------------------------------------------------*/
3299 /* Deal with object reads: Create a new object and prepare for */
3300 /* reading. The library number is passed as "mode". */
3301 /*--------------------------------------------------------------*/
3303 objectptr
*new_library_object(short mode
, char *name
, objlistptr
*retlist
,
3304 TechPtr defaulttech
)
3306 objlistptr newdef
, redef
= NULL
;
3307 objectptr
*newobject
, *libobj
;
3308 objectptr
*curlib
= (mode
== FONTLIB
) ?
3309 xobjs
.fontlib
.library
: xobjs
.userlibs
[mode
- LIBRARY
].library
;
3310 short *libobjects
= (mode
== FONTLIB
) ?
3311 &xobjs
.fontlib
.number
: &xobjs
.userlibs
[mode
- LIBRARY
].number
;
3313 char *nsptr
, *fullname
= name
;
3315 curlib
= (objectptr
*) realloc(curlib
, (*libobjects
+ 1)
3316 * sizeof(objectptr
));
3317 if (mode
== FONTLIB
) xobjs
.fontlib
.library
= curlib
;
3318 else xobjs
.userlibs
[mode
- LIBRARY
].library
= curlib
;
3320 /* For (older) libraries that do not use technologies, give the */
3321 /* object a technology name in the form <library>::<object> */
3323 if ((nsptr
= strstr(name
, "::")) == NULL
) {
3324 int deftechlen
= (defaulttech
== NULL
) ? 0 : strlen(defaulttech
->technology
);
3325 fullname
= (char *)malloc(deftechlen
+ strlen(name
) + 3);
3326 if (defaulttech
== NULL
)
3327 sprintf(fullname
, "::%s", name
);
3329 sprintf(fullname
, "%s::%s", defaulttech
->technology
, name
);
3332 /* initial 1-pointer allocations */
3334 newobject
= curlib
+ (*libobjects
);
3335 *newobject
= (objectptr
) malloc(sizeof(object
));
3336 initmem(*newobject
);
3338 /* check that this object is not already in list of objects */
3340 if (mode
== FONTLIB
) {
3341 for (libobj
= xobjs
.fontlib
.library
; libobj
!= xobjs
.fontlib
.library
+
3342 xobjs
.fontlib
.number
; libobj
++) {
3343 /* This font character may be a redefinition of another */
3344 if (!objnamecmp(fullname
, (*libobj
)->name
)) {
3345 newdef
= (objlistptr
) malloc(sizeof(objlist
));
3346 newdef
->libno
= FONTLIB
;
3347 newdef
->thisobject
= *libobj
;
3348 newdef
->next
= redef
;
3354 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
3355 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
3356 libobj
= xobjs
.userlibs
[i
].library
+ j
;
3357 /* This object may be a redefinition of another object */
3358 if (!objnamecmp(fullname
, (*libobj
)->name
)) {
3359 newdef
= (objlistptr
) malloc(sizeof(objlist
));
3360 newdef
->libno
= i
+ LIBRARY
;
3361 newdef
->thisobject
= *libobj
;
3362 newdef
->next
= redef
;
3370 sprintf((*newobject
)->name
, "%s", fullname
);
3371 if (fullname
!= name
) free(fullname
);
3373 /* initmem() initialized schemtype to PRIMARY; change it. */
3374 (*newobject
)->schemtype
= (mode
== FONTLIB
) ? GLYPH
: SYMBOL
;
3376 /* If the object declares a technology name that is different from the */
3377 /* default, then add the technology name to the list of technologies, */
3378 /* with a NULL filename. */
3380 if (mode
!= FONTLIB
) AddObjectTechnology(*newobject
);
3386 /*--------------------------------------------------------------*/
3387 /* do an exhaustive comparison between a new object and any */
3388 /* object having the same name. If they are the same, destroy */
3389 /* the duplicate. If different, rename the original one. */
3390 /*--------------------------------------------------------------*/
3392 Boolean
library_object_unique(short mode
, objectptr newobject
, objlistptr redef
)
3394 Boolean is_unique
= True
;
3396 short *libobjects
= (mode
== FONTLIB
) ?
3397 &xobjs
.fontlib
.number
: &xobjs
.userlibs
[mode
- LIBRARY
].number
;
3400 return is_unique
; /* No name conflicts; object is okay as-is */
3402 for (newdef
= redef
; newdef
!= NULL
; newdef
= newdef
->next
) {
3404 /* Must make sure that default parameter values are */
3405 /* plugged into both objects! */
3406 opsubstitute(newdef
->thisobject
, NULL
);
3407 opsubstitute(newobject
, NULL
);
3409 if (objcompare(newobject
, newdef
->thisobject
) == True
) {
3410 addalias(newdef
->thisobject
, newobject
->name
);
3412 /* If the new object has declared an association to a */
3413 /* schematic, transfer it to the original, and make */
3414 /* sure that the page points to the object which will */
3415 /* be left, not the one which will be destroyed. */
3417 if (newobject
->symschem
!= NULL
) {
3418 newdef
->thisobject
->symschem
= newobject
->symschem
;
3419 newdef
->thisobject
->symschem
->symschem
= newdef
->thisobject
;
3422 reset(newobject
, DESTROY
);
3428 /* Not the same object, but has the same name. This can't */
3429 /* happen within the same input file, so the name of the */
3430 /* original object can safely be altered. */
3432 else if (!strcmp(newobject
->name
, newdef
->thisobject
->name
)) {
3434 /* Replacement---for project management, allow the technology */
3435 /* master version to take precedence over a local version. */
3437 TechPtr nsptr
= GetObjectTechnology(newobject
);
3439 if (nsptr
&& (nsptr
->flags
& TECH_REPLACE
)) {
3440 reset(newobject
, DESTROY
);
3445 checkname(newdef
->thisobject
);
3449 for (; (newdef
= redef
->next
); redef
= newdef
)
3456 /*--------------------------------------------------------------*/
3457 /* Add an instance of the object to the library's instance list */
3458 /*--------------------------------------------------------------*/
3460 void add_object_to_library(short mode
, objectptr newobject
)
3464 if (mode
== FONTLIB
) return;
3466 libinst
= addtoinstlist(mode
- LIBRARY
, newobject
, False
);
3467 calcbboxvalues(libinst
, (genericptr
*)NULL
);
3469 /* Center the view of the object in its instance */
3470 centerview(libinst
);
3473 /*--------------------------------------------------------------*/
3474 /* Continuation Line --- add memory to "buffer" as necessary. */
3475 /* Add a space character to the current text in "buffer" and */
3476 /* return a pointer to the new end-of-text. */
3477 /*--------------------------------------------------------------*/
3479 char *continueline(char **buffer
)
3484 for (lineptr
= *buffer
; (*lineptr
!= '\n') && (*lineptr
!= '\0'); lineptr
++);
3485 /* Repair Windoze-mangled files */
3486 if ((lineptr
> *buffer
) && (*lineptr
== '\n') && (*(lineptr
- 1) == '\r'))
3487 *(lineptr
- 1) = ' ';
3488 if (*lineptr
== '\n') *lineptr
++ = ' ';
3490 bufsize
= (int)(lineptr
- (*buffer
)) + 256;
3491 *buffer
= (char *)realloc((*buffer
), bufsize
* sizeof(char));
3493 return ((*buffer
) + (bufsize
- 256));
3496 /*--------------------------------------------------------------*/
3497 /* Read image data out of the Setup block of the input */
3498 /* We assume that width and height have been parsed from the */
3499 /* "imagedata" line and the file pointer is at the next line. */
3500 /*--------------------------------------------------------------*/
3502 void readimagedata(FILE *ps
, int width
, int height
)
3504 char temp
[150], ascbuf
[6];
3505 int x
, y
, p
, q
, r
, g
, b
, ilen
;
3508 Boolean do_flate
= False
, do_ascii
= False
;
3509 u_char
*filtbuf
, *flatebuf
;
3515 iptr
= addnewimage(NULL
, width
, height
);
3517 /* Read the image data */
3519 fgets(temp
, 149, ps
);
3520 if (strstr(temp
, "ASCII85Decode") != NULL
) do_ascii
= TRUE
;
3522 if (strstr(temp
, "FlateDecode") != NULL
) do_flate
= TRUE
;
3524 if (strstr(temp
, "FlateDecode") != NULL
)
3525 Fprintf(stderr
, "Error: Don't know how to Flate decode!"
3526 " Get zlib and recompile xcircuit!\n");
3528 while (strstr(temp
, "ReusableStreamDecode") == NULL
)
3529 fgets(temp
, 149, ps
); /* Additional piped filter lines */
3531 fgets(temp
, 149, ps
); /* Initial data line */
3534 ilen
= 3 * width
* height
;
3535 filtbuf
= (u_char
*)malloc(ilen
+ 4);
3537 if (!do_ascii
) { /* ASCIIHexDecode algorithm */
3539 for (y
= 0; y
< height
; y
++) {
3540 for (x
= 0; x
< width
; x
++) {
3541 sscanf(pptr
, "%02x%02x%02x", &r
, &g
, &b
);
3542 filtbuf
[q
++] = (u_char
)r
;
3543 filtbuf
[q
++] = (u_char
)g
;
3544 filtbuf
[q
++] = (u_char
)b
;
3546 if (*pptr
== '\n') {
3547 fgets(temp
, 149, ps
);
3553 else { /* ASCII85Decode algorithm */
3558 if (ascbuf
[0] == '~')
3560 else if (ascbuf
[0] == 'z') {
3561 for (y
= 0; y
< 5; y
++) ascbuf
[y
] = '\0';
3564 for (y
= 1; y
< 5; y
++) {
3565 if (*pptr
== '\n') {
3566 fgets(temp
, 149, ps
);
3570 if (ascbuf
[y
] == '~') {
3571 for (; y
< 5; y
++) {
3579 for (y
= 0; y
< 5; y
++) ascbuf
[y
] -= '!';
3582 if (*pptr
== '\n') {
3583 fgets(temp
, 149, ps
);
3587 /* Decode from ASCII85 to binary */
3589 pixel
.i
= ascbuf
[4] + ascbuf
[3] * 85 + ascbuf
[2] * 7225 +
3590 ascbuf
[1] * 614125 + ascbuf
[0] * 52200625;
3592 /* Add in roundoff for final bytes */
3596 pixel
.i
+= 0xff0000;
3604 for (y
= 0; y
< (4 - p
); y
++) {
3605 filtbuf
[q
+ y
] = pixel
.b
[3 - y
];
3608 if (q
>= ilen
) break;
3612 /* Extra decoding goes here */
3616 flatebuf
= (char *)malloc(ilen
);
3617 large_inflate(filtbuf
, q
, &flatebuf
, ilen
);
3626 for (y
= 0; y
< height
; y
++)
3627 for (x
= 0; x
< width
; x
++) {
3632 xcImagePutPixel(iptr
->image
, x
, y
, r
, g
, b
);
3637 fgets(temp
, 149, ps
); /* definition line */
3638 fgets(temp
, 149, ps
); /* pick up name of image from here */
3639 for (pptr
= temp
; !isspace(*pptr
); pptr
++);
3641 iptr
->filename
= strdup(temp
+ 1);
3642 for (x
= 0; x
< 5; x
++) fgets(temp
, 149, ps
); /* skip image dictionary */
3645 /*--------------------------------------------------------------*/
3646 /* Read an object (page) from a file into xcircuit */
3647 /*--------------------------------------------------------------*/
3649 Boolean
objectread(FILE *ps
, objectptr localdata
, short offx
, short offy
,
3650 short mode
, char *retstr
, int ccolor
, TechPtr defaulttech
)
3652 char *temp
, *buffer
, keyword
[80];
3654 float tmpscale
= 0.0;
3656 int curcolor
= ccolor
;
3657 char *colorkey
= NULL
;
3658 char *widthkey
= NULL
;
3661 objinstptr
*newinst
;
3662 eparamptr epptrx
, epptry
; /* used for paths only */
3664 /* path-handling variables */
3670 buffer
= (char *)malloc(256 * sizeof(char));
3674 char *lineptr
, *keyptr
, *saveptr
;
3676 if (fgets(temp
, 255, ps
) == NULL
) {
3677 if (strcmp(keyword
, "restore")) {
3678 Wprintf("Error: end of file.");
3685 /* because PostScript is a stack language, we will scan from the end */
3686 for (lineptr
= buffer
; (*lineptr
!= '\n') && (*lineptr
!= '\0'); lineptr
++);
3687 /* Avoid CR-LF at EOL added by stupid Windoze programs */
3688 if ((lineptr
> buffer
) && *(lineptr
- 1) == '\r') lineptr
--;
3689 if (lineptr
!= buffer
) { /* ignore any blank lines */
3690 for (keyptr
= lineptr
- 1; isspace(*keyptr
) && keyptr
!= buffer
; keyptr
--);
3691 for (; !isspace(*keyptr
) && keyptr
!= buffer
; keyptr
--);
3692 sscanf(keyptr
, "%79s", keyword
);
3694 if (!strcmp(keyword
, "showpage")) {
3695 strncpy(retstr
, buffer
, 150);
3699 /* If we have just read a schematic that is attached */
3700 /* to a symbol, check all of the pin labels in the symbol */
3701 /* to see if they correspond to pin names in the schematic. */
3702 /* The other way around (pin in schematic with no */
3703 /* corresponding name in the symbol) is not an error. */
3705 if (localdata
->symschem
!= NULL
) {
3706 genericptr
*pgen
, *lgen
;
3707 labelptr plab
, lcmp
;
3708 for (pgen
= localdata
->symschem
->plist
; pgen
< localdata
->
3709 symschem
->plist
+ localdata
->symschem
->parts
; pgen
++) {
3710 if (IS_LABEL(*pgen
)) {
3711 plab
= TOLABEL(pgen
);
3712 if (plab
->pin
== LOCAL
) {
3713 for (lgen
= localdata
->plist
; lgen
< localdata
->plist
+
3714 localdata
->parts
; lgen
++) {
3715 if (IS_LABEL(*lgen
)) {
3716 lcmp
= TOLABEL(lgen
);
3717 if (lcmp
->pin
== LOCAL
)
3718 if (!stringcomprelaxed(lcmp
->string
, plab
->string
,
3719 areawin
->topinstance
))
3723 if (lgen
== localdata
->plist
+ localdata
->parts
) {
3724 char *cptr
, *d1ptr
, *d2ptr
;
3725 char *pch
= textprint(plab
->string
, areawin
->topinstance
);
3727 /* Check for likely delimiters before applying warning */
3729 if ((cptr
= strchr(pch
, ':')) != NULL
) {
3730 d1ptr
= strchr(pch
, '[');
3731 d2ptr
= strchr(pch
, ']');
3732 if (d1ptr
!= NULL
&& d2ptr
!= NULL
&&
3733 d1ptr
< cptr
&& d2ptr
> cptr
) {
3734 if (areawin
->buschar
!= '[') {
3735 areawin
->buschar
= '[';
3736 Fprintf(stderr
, "Warning: Bus character \'[\'"
3737 " apparently used but not declared.\n");
3740 d1ptr
= strchr(pch
, '{');
3741 d2ptr
= strchr(pch
, '}');
3742 if (d1ptr
!= NULL
&& d2ptr
!= NULL
&&
3743 d1ptr
< cptr
&& d2ptr
> cptr
) {
3744 if (areawin
->buschar
!= '{') {
3745 areawin
->buschar
= '{';
3746 Fprintf(stderr
, "Warning: Bus character \'{\'"
3747 " apparently used in pin \"%s\""
3748 " but not declared.\n", pch
);
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 in pin \"%s\""
3759 " but not declared.\n", pch
);
3762 d1ptr
= strchr(pch
, '(');
3763 d2ptr
= strchr(pch
, ')');
3764 if (d1ptr
!= NULL
&& d2ptr
!= NULL
&&
3765 d1ptr
< cptr
&& d2ptr
> cptr
) {
3766 if (areawin
->buschar
!= '(') {
3767 areawin
->buschar
= '(';
3768 Fprintf(stderr
, "Warning: Bus character \'(\'"
3769 " apparently used in pin \"%s\""
3770 " but not declared.\n", pch
);
3775 Fprintf(stderr
, "Warning: Unattached pin \"%s\" in "
3777 localdata
->symschem
->name
);
3784 return False
; /* end of page */
3787 /* make a color change, adding the color if necessary */
3789 else if (!strcmp(keyword
, "scb")) {
3790 float red
, green
, blue
;
3791 if (sscanf(buffer
, "%f %f %f", &red
, &green
, &blue
) == 3) {
3792 curcolor
= rgb_alloccolor((int)(red
* 65535), (int)(green
* 65535),
3793 (int)(blue
* 65535));
3800 parse_ps_string(buffer
, tmpkey
, 29, FALSE
, TRUE
);
3801 ops
= match_param(localdata
, tmpkey
);
3803 /* Recast expression parameter, if necessary */
3804 if (ops
->which
== P_EXPRESSION
) ops
->which
= P_COLOR
;
3805 if (ops
->which
== P_COLOR
) {
3806 colorkey
= ops
->key
;
3807 switch (ops
->type
) {
3809 curcolor
= ops
->parameter
.ivalue
;
3812 curcolor
= DEFAULTCOLOR
; /* placeholder */
3820 /* end the color change, returning to default */
3822 else if (!strcmp(keyword
, "sce")) {
3827 /* begin a path constructor */
3829 else if (!strcmp(keyword
, "beginpath")) {
3832 NEW_PATH(newpath
, localdata
);
3833 (*newpath
)->plist
= (genericptr
*)malloc(sizeof(genericptr
));
3834 (*newpath
)->parts
= 0;
3835 (*newpath
)->color
= curcolor
;
3836 (*newpath
)->passed
= NULL
;
3838 for (--keyptr
; *keyptr
== ' '; keyptr
--);
3839 for (; *keyptr
!= ' '; keyptr
--);
3841 /* check for "addtox" and "addtoy" parameter specification */
3842 while (!strncmp(keyptr
+ 1, "addto", 5)) {
3843 saveptr
= keyptr
+ 1;
3845 for (--keyptr
; *keyptr
== ' '; keyptr
--);
3846 for (; *keyptr
!= ' '; keyptr
--);
3848 /* Get parameter and its value */
3849 if (*(saveptr
+ 5) == 'x')
3850 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newpath
,
3851 -1, offx
, P_POSITION_X
);
3853 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newpath
,
3854 -1, offy
, P_POSITION_Y
);
3856 for (--keyptr
; *keyptr
== ' '; keyptr
--);
3857 for (; *keyptr
!= ' '; keyptr
--);
3860 lineptr
= varpathscan(localdata
, buffer
, &startpoint
.x
,
3861 (genericptr
*)NULL
, *newpath
, 0, offx
+ px
, P_POSITION_X
,
3863 lineptr
= varpathscan(localdata
, lineptr
, &startpoint
.y
,
3864 (genericptr
*)NULL
, *newpath
, 0, offy
+ py
, P_POSITION_Y
,
3867 std_eparam((genericptr
)(*newpath
), colorkey
);
3870 /* end the path constructor */
3872 else if (!strcmp(keyword
, "endpath")) {
3874 lineptr
= varscan(localdata
, buffer
, &(*newpath
)->style
,
3875 (genericptr
)*newpath
, P_STYLE
);
3876 lineptr
= varfscan(localdata
, lineptr
, &(*newpath
)->width
,
3877 (genericptr
)*newpath
, P_LINEWIDTH
);
3879 if ((*newpath
)->parts
<= 0) { /* in case of an empty path */
3880 free((*newpath
)->plist
);
3887 /* read path parts */
3889 else if (!strcmp(keyword
, "polyc")) {
3891 pointlist newpoints
;
3896 NEW_POLY(newpoly
, (*newpath
));
3898 for (--keyptr
; *keyptr
== ' '; keyptr
--);
3899 for (; *keyptr
!= ' '; keyptr
--);
3901 /* check for "addtox" and "addtoy" parameter specification */
3902 while (!strncmp(keyptr
+ 1, "addto", 5)) {
3903 saveptr
= keyptr
+ 1;
3905 for (--keyptr
; *keyptr
== ' '; keyptr
--);
3906 for (; *keyptr
!= ' '; keyptr
--);
3908 /* Get parameter and its value */
3909 if (*(saveptr
+ 5) == 'x')
3910 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newpoly
,
3911 -1, offx
, P_POSITION_X
);
3913 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newpoly
,
3914 -1, offy
, P_POSITION_Y
);
3916 for (--keyptr
; *keyptr
== ' '; keyptr
--);
3917 for (; *keyptr
!= ' '; keyptr
--);
3920 sscanf(keyptr
, "%hd", &tmpnum
);
3921 (*newpoly
)->number
= tmpnum
+ 1;
3922 (*newpoly
)->width
= 1.0;
3923 (*newpoly
)->style
= UNCLOSED
;
3924 (*newpoly
)->color
= curcolor
;
3925 (*newpoly
)->passed
= NULL
;
3926 (*newpoly
)->cycle
= NULL
;
3928 (*newpoly
)->points
= (pointlist
) malloc((*newpoly
)->number
*
3931 /* If the last point on the last path part was parameterized, then */
3932 /* the first point of the spline must be, too. */
3934 if (epptrx
!= NULL
) {
3935 eparamptr newepp
= copyeparam(epptrx
, (genericptr
)(*newpath
));
3936 newepp
->next
= (*newpath
)->passed
;
3937 (*newpath
)->passed
= newepp
;
3938 newepp
->pdata
.pathpt
[1] = 0;
3939 newepp
->pdata
.pathpt
[0] = (*newpath
)->parts
- 1;
3941 if (epptry
!= NULL
) {
3942 eparamptr newepp
= copyeparam(epptry
, (genericptr
)(*newpath
));
3943 newepp
->next
= (*newpath
)->passed
;
3944 (*newpath
)->passed
= newepp
;
3945 newepp
->pdata
.pathpt
[1] = 0;
3946 newepp
->pdata
.pathpt
[0] = (*newpath
)->parts
- 1;
3951 newpoints
= (*newpoly
)->points
+ (*newpoly
)->number
- 1;
3952 lineptr
= varpathscan(localdata
, lineptr
, &newpoints
->x
,
3953 (genericptr
*)newpoly
, *newpath
, newpoints
- (*newpoly
)->points
,
3954 offx
+ px
, P_POSITION_X
, &epptrx
);
3955 lineptr
= varpathscan(localdata
, lineptr
, &newpoints
->y
,
3956 (genericptr
*)newpoly
, *newpath
, newpoints
- (*newpoly
)->points
,
3957 offy
+ py
, P_POSITION_Y
, &epptry
);
3959 for (--newpoints
; newpoints
> (*newpoly
)->points
; newpoints
--) {
3961 lineptr
= varpathscan(localdata
, lineptr
, &newpoints
->x
,
3962 (genericptr
*)newpoly
, *newpath
, newpoints
- (*newpoly
)->points
,
3963 offx
+ px
, P_POSITION_X
, NULL
);
3964 lineptr
= varpathscan(localdata
, lineptr
, &newpoints
->y
,
3965 (genericptr
*)newpoly
, *newpath
, newpoints
- (*newpoly
)->points
,
3966 offy
+ py
, P_POSITION_Y
, NULL
);
3968 newpoints
->x
= startpoint
.x
;
3969 newpoints
->y
= startpoint
.y
;
3970 startpoint
.x
= (newpoints
+ (*newpoly
)->number
- 1)->x
;
3971 startpoint
.y
= (newpoints
+ (*newpoly
)->number
- 1)->y
;
3974 else if (!strcmp(keyword
, "arc") || !strcmp(keyword
, "arcn")) {
3976 NEW_ARC(newarc
, (*newpath
));
3977 (*newarc
)->width
= 1.0;
3978 (*newarc
)->style
= UNCLOSED
;
3979 (*newarc
)->color
= curcolor
;
3980 (*newarc
)->passed
= NULL
;
3981 (*newarc
)->cycle
= NULL
;
3983 lineptr
= varpscan(localdata
, buffer
, &(*newarc
)->position
.x
,
3984 (genericptr
)*newarc
, 0, offx
, P_POSITION_X
);
3985 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.y
,
3986 (genericptr
)*newarc
, 0, offy
, P_POSITION_Y
);
3987 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->radius
,
3988 (genericptr
)*newarc
, P_RADIUS
);
3989 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle1
,
3990 (genericptr
)*newarc
, P_ANGLE1
);
3991 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle2
,
3992 (genericptr
)*newarc
, P_ANGLE2
);
3994 (*newarc
)->yaxis
= (*newarc
)->radius
;
3995 if (!strcmp(keyword
, "arcn")) {
3996 float tmpang
= (*newarc
)->angle1
;
3997 (*newarc
)->radius
= -((*newarc
)->radius
);
3998 (*newarc
)->angle1
= (*newarc
)->angle2
;
3999 (*newarc
)->angle2
= tmpang
;
4003 startpoint
.x
= (short)(*newarc
)->points
[(*newarc
)->number
- 1].x
;
4004 startpoint
.y
= (short)(*newarc
)->points
[(*newarc
)->number
- 1].y
;
4005 decomposearc(*newpath
);
4008 else if (!strcmp(keyword
, "pellip") || !strcmp(keyword
, "nellip")) {
4010 NEW_ARC(newarc
, (*newpath
));
4011 (*newarc
)->width
= 1.0;
4012 (*newarc
)->style
= UNCLOSED
;
4013 (*newarc
)->color
= curcolor
;
4014 (*newarc
)->passed
= NULL
;
4015 (*newarc
)->cycle
= NULL
;
4017 lineptr
= varpscan(localdata
, buffer
, &(*newarc
)->position
.x
,
4018 (genericptr
)*newarc
, 0, offx
, P_POSITION_X
);
4019 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.y
,
4020 (genericptr
)*newarc
, 0, offy
, P_POSITION_Y
);
4021 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->radius
,
4022 (genericptr
)*newarc
, P_RADIUS
);
4023 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->yaxis
,
4024 (genericptr
)*newarc
, P_MINOR_AXIS
);
4025 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle1
,
4026 (genericptr
)*newarc
, P_ANGLE1
);
4027 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle2
,
4028 (genericptr
)*newarc
, P_ANGLE2
);
4030 if (!strcmp(keyword
, "nellip")) {
4031 float tmpang
= (*newarc
)->angle1
;
4032 (*newarc
)->radius
= -((*newarc
)->radius
);
4033 (*newarc
)->angle1
= (*newarc
)->angle2
;
4034 (*newarc
)->angle2
= tmpang
;
4038 startpoint
.x
= (short)(*newarc
)->points
[(*newarc
)->number
- 1].x
;
4039 startpoint
.y
= (short)(*newarc
)->points
[(*newarc
)->number
- 1].y
;
4040 decomposearc(*newpath
);
4043 else if (!strcmp(keyword
, "curveto")) {
4044 splineptr
*newspline
;
4047 NEW_SPLINE(newspline
, (*newpath
));
4048 (*newspline
)->passed
= NULL
;
4049 (*newspline
)->cycle
= NULL
;
4050 (*newspline
)->width
= 1.0;
4051 (*newspline
)->style
= UNCLOSED
;
4052 (*newspline
)->color
= curcolor
;
4054 /* If the last point on the last path part was parameterized, then */
4055 /* the first point of the spline must be, too. */
4057 if (epptrx
!= NULL
) {
4058 eparamptr newepp
= copyeparam(epptrx
, (genericptr
)(*newpath
));
4059 newepp
->next
= (*newpath
)->passed
;
4060 (*newpath
)->passed
= newepp
;
4061 newepp
->pdata
.pathpt
[1] = 0;
4062 newepp
->pdata
.pathpt
[0] = (*newpath
)->parts
- 1;
4064 if (epptry
!= NULL
) {
4065 eparamptr newepp
= copyeparam(epptry
, (genericptr
)(*newpath
));
4066 newepp
->next
= (*newpath
)->passed
;
4067 (*newpath
)->passed
= newepp
;
4068 newepp
->pdata
.pathpt
[1] = 0;
4069 newepp
->pdata
.pathpt
[0] = (*newpath
)->parts
- 1;
4072 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4073 for (; *keyptr
!= ' '; keyptr
--);
4075 /* check for "addtox" and "addtoy" parameter specification */
4076 while (!strncmp(keyptr
+ 1, "addto", 5)) {
4077 saveptr
= keyptr
+ 1;
4079 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4080 for (; *keyptr
!= ' '; keyptr
--);
4082 /* Get parameter and its value */
4083 if (*(saveptr
+ 5) == 'x')
4084 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newspline
,
4085 -1, offx
, P_POSITION_X
);
4087 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newspline
,
4088 -1, offy
, P_POSITION_Y
);
4090 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4091 for (; *keyptr
!= ' '; keyptr
--);
4095 lineptr
= varpathscan(localdata
, buffer
, &(*newspline
)->ctrl
[1].x
,
4096 (genericptr
*)newspline
, *newpath
, 1, offx
+ px
, P_POSITION_X
,
4098 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[1].y
,
4099 (genericptr
*)newspline
, *newpath
, 1, offy
+ py
, P_POSITION_Y
,
4101 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[2].x
,
4102 (genericptr
*)newspline
, *newpath
, 2, offx
+ px
, P_POSITION_X
,
4104 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[2].y
,
4105 (genericptr
*)newspline
, *newpath
, 2, offy
+ py
, P_POSITION_Y
,
4107 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[3].x
,
4108 (genericptr
*)newspline
, *newpath
, 3, offx
+ px
, P_POSITION_X
,
4110 lineptr
= varpathscan(localdata
, lineptr
, &(*newspline
)->ctrl
[3].y
,
4111 (genericptr
*)newspline
, *newpath
, 3, offy
+ py
, P_POSITION_Y
,
4114 (*newspline
)->ctrl
[0].x
= startpoint
.x
;
4115 (*newspline
)->ctrl
[0].y
= startpoint
.y
;
4117 calcspline(*newspline
);
4118 startpoint
.x
= (*newspline
)->ctrl
[3].x
;
4119 startpoint
.y
= (*newspline
)->ctrl
[3].y
;
4124 else if (!strcmp(keyword
, "xcarc")) {
4127 NEW_ARC(newarc
, localdata
);
4128 (*newarc
)->color
= curcolor
;
4129 (*newarc
)->passed
= NULL
;
4130 (*newarc
)->cycle
= NULL
;
4132 /* backward compatibility */
4133 if (version
< 1.5) {
4134 sscanf(buffer
, "%hd %hd %hd %f %f %f %hd", &(*newarc
)->position
.x
,
4135 &(*newarc
)->position
.y
, &(*newarc
)->radius
, &(*newarc
)->angle1
,
4136 &(*newarc
)->angle2
, &(*newarc
)->width
, &(*newarc
)->style
);
4137 (*newarc
)->position
.x
-= offx
;
4138 (*newarc
)->position
.y
-= offy
;
4141 lineptr
= varscan(localdata
, buffer
, &(*newarc
)->style
,
4142 (genericptr
)*newarc
, P_STYLE
);
4143 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->width
,
4144 (genericptr
)*newarc
, P_LINEWIDTH
);
4145 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.x
,
4146 (genericptr
)*newarc
, 0, offx
, P_POSITION_X
);
4147 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.y
,
4148 (genericptr
)*newarc
, 0, offy
, P_POSITION_Y
);
4149 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->radius
,
4150 (genericptr
)*newarc
, P_RADIUS
);
4151 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle1
,
4152 (genericptr
)*newarc
, P_ANGLE1
);
4153 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle2
,
4154 (genericptr
)*newarc
, P_ANGLE2
);
4157 (*newarc
)->yaxis
= (*newarc
)->radius
;
4159 std_eparam((genericptr
)(*newarc
), colorkey
);
4164 else if (!strcmp(keyword
, "ellipse")) {
4167 NEW_ARC(newarc
, localdata
);
4169 (*newarc
)->color
= curcolor
;
4170 (*newarc
)->passed
= NULL
;
4171 (*newarc
)->cycle
= NULL
;
4173 lineptr
= varscan(localdata
, buffer
, &(*newarc
)->style
,
4174 (genericptr
)*newarc
, P_STYLE
);
4175 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->width
,
4176 (genericptr
)*newarc
, P_LINEWIDTH
);
4177 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.x
,
4178 (genericptr
)*newarc
, 0, offx
, P_POSITION_X
);
4179 lineptr
= varpscan(localdata
, lineptr
, &(*newarc
)->position
.y
,
4180 (genericptr
)*newarc
, 0, offy
, P_POSITION_Y
);
4181 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->radius
,
4182 (genericptr
)*newarc
, P_RADIUS
);
4183 lineptr
= varscan(localdata
, lineptr
, &(*newarc
)->yaxis
,
4184 (genericptr
)*newarc
, P_MINOR_AXIS
);
4185 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle1
,
4186 (genericptr
)*newarc
, P_ANGLE1
);
4187 lineptr
= varfscan(localdata
, lineptr
, &(*newarc
)->angle2
,
4188 (genericptr
)*newarc
, P_ANGLE2
);
4191 std_eparam((genericptr
)(*newarc
), colorkey
);
4195 /* (and wires---backward compatibility for v1.5 and earlier) */
4197 else if (!strcmp(keyword
, "polygon") || !strcmp(keyword
, "wire")) {
4199 pointlist newpoints
;
4202 NEW_POLY(newpoly
, localdata
);
4205 (*newpoly
)->passed
= NULL
;
4206 (*newpoly
)->cycle
= NULL
;
4208 if (!strcmp(keyword
, "wire")) {
4209 (*newpoly
)->number
= 2;
4210 (*newpoly
)->width
= 1.0;
4211 (*newpoly
)->style
= UNCLOSED
;
4214 /* backward compatibility */
4215 if (version
< 1.5) {
4216 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4217 for (; *keyptr
!= ' '; keyptr
--);
4218 sscanf(keyptr
, "%hd", &(*newpoly
)->style
);
4219 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4220 for (; *keyptr
!= ' '; keyptr
--);
4221 sscanf(keyptr
, "%f", &(*newpoly
)->width
);
4223 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4224 for (; *keyptr
!= ' '; keyptr
--);
4225 /* check for "addtox" and "addtoy" parameter specification */
4226 while (!strncmp(keyptr
+ 1, "addto", 5)) {
4227 saveptr
= keyptr
+ 1;
4229 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4230 for (; *keyptr
!= ' '; keyptr
--);
4232 /* Get parameter and its value */
4233 if (*(saveptr
+ 5) == 'x')
4234 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newpoly
,
4235 -1, offx
, P_POSITION_X
);
4237 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newpoly
,
4238 -1, offy
, P_POSITION_Y
);
4240 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4241 for (; *keyptr
!= ' '; keyptr
--);
4243 sscanf(keyptr
, "%hd", &(*newpoly
)->number
);
4245 if (version
>= 1.5) {
4246 lineptr
= varscan(localdata
, lineptr
, &(*newpoly
)->style
,
4247 (genericptr
)*newpoly
, P_STYLE
);
4248 lineptr
= varfscan(localdata
, lineptr
, &(*newpoly
)->width
,
4249 (genericptr
)*newpoly
, P_LINEWIDTH
);
4253 if ((*newpoly
)->style
& BBOX
)
4254 (*newpoly
)->color
= BBOXCOLOR
;
4256 (*newpoly
)->color
= curcolor
;
4257 (*newpoly
)->points
= (pointlist
) malloc((*newpoly
)->number
*
4260 for (newpoints
= (*newpoly
)->points
; newpoints
< (*newpoly
)->points
4261 + (*newpoly
)->number
; newpoints
++) {
4262 lineptr
= varpscan(localdata
, lineptr
, &newpoints
->x
,
4263 (genericptr
)*newpoly
, newpoints
- (*newpoly
)->points
,
4264 offx
+ px
, P_POSITION_X
);
4265 lineptr
= varpscan(localdata
, lineptr
, &newpoints
->y
,
4266 (genericptr
)*newpoly
, newpoints
- (*newpoly
)->points
,
4267 offy
+ py
, P_POSITION_Y
);
4269 std_eparam((genericptr
)(*newpoly
), colorkey
);
4272 /* read spline curves */
4274 else if (!strcmp(keyword
, "spline")) {
4275 splineptr
*newspline
;
4278 NEW_SPLINE(newspline
, localdata
);
4279 (*newspline
)->color
= curcolor
;
4280 (*newspline
)->passed
= NULL
;
4281 (*newspline
)->cycle
= NULL
;
4283 /* backward compatibility */
4284 if (version
< 1.5) {
4285 sscanf(buffer
, "%f %hd %hd %hd %hd %hd %hd %hd %hd %hd",
4286 &(*newspline
)->width
, &(*newspline
)->ctrl
[1].x
,
4287 &(*newspline
)->ctrl
[1].y
, &(*newspline
)->ctrl
[2].x
,
4288 &(*newspline
)->ctrl
[2].y
, &(*newspline
)->ctrl
[3].x
,
4289 &(*newspline
)->ctrl
[3].y
, &(*newspline
)->ctrl
[0].x
,
4290 &(*newspline
)->ctrl
[0].y
, &(*newspline
)->style
);
4291 (*newspline
)->ctrl
[1].x
-= offx
; (*newspline
)->ctrl
[2].x
-= offx
;
4292 (*newspline
)->ctrl
[0].x
-= offx
;
4293 (*newspline
)->ctrl
[3].x
-= offx
;
4294 (*newspline
)->ctrl
[1].y
-= offy
; (*newspline
)->ctrl
[2].y
-= offy
;
4295 (*newspline
)->ctrl
[3].y
-= offy
;
4296 (*newspline
)->ctrl
[0].y
-= offy
;
4300 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4301 for (; *keyptr
!= ' '; keyptr
--);
4302 /* check for "addtox" and "addtoy" parameter specification */
4303 while (!strncmp(keyptr
+ 1, "addto", 5)) {
4304 saveptr
= keyptr
+ 1;
4306 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4307 for (; *keyptr
!= ' '; keyptr
--);
4309 /* Get parameter and its value */
4310 if (*(saveptr
+ 5) == 'x')
4311 varpscan(localdata
, keyptr
+ 1, &px
, (genericptr
)*newspline
,
4312 -1, offx
, P_POSITION_X
);
4314 varpscan(localdata
, keyptr
+ 1, &py
, (genericptr
)*newspline
,
4315 -1, offy
, P_POSITION_Y
);
4317 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4318 for (; *keyptr
!= ' '; keyptr
--);
4321 lineptr
= varscan(localdata
, buffer
, &(*newspline
)->style
,
4322 (genericptr
)*newspline
, P_STYLE
);
4323 lineptr
= varfscan(localdata
, lineptr
, &(*newspline
)->width
,
4324 (genericptr
)*newspline
, P_LINEWIDTH
);
4325 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[1].x
,
4326 (genericptr
)*newspline
, 1, offx
+ px
, P_POSITION_X
);
4327 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[1].y
,
4328 (genericptr
)*newspline
, 1, offy
+ py
, P_POSITION_Y
);
4329 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[2].x
,
4330 (genericptr
)*newspline
, 2, offx
+ px
, P_POSITION_X
);
4331 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[2].y
,
4332 (genericptr
)*newspline
, 2, offy
+ py
, P_POSITION_Y
);
4333 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[3].x
,
4334 (genericptr
)*newspline
, 3, offx
+ px
, P_POSITION_X
);
4335 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[3].y
,
4336 (genericptr
)*newspline
, 3, offy
+ py
, P_POSITION_Y
);
4337 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[0].x
,
4338 (genericptr
)*newspline
, 0, offx
+ px
, P_POSITION_X
);
4339 lineptr
= varpscan(localdata
, lineptr
, &(*newspline
)->ctrl
[0].y
,
4340 (genericptr
)*newspline
, 0, offy
+ py
, P_POSITION_Y
);
4342 /* check for "addtox" and "addtoy" parameter specification */
4345 calcspline(*newspline
);
4346 std_eparam((genericptr
)(*newspline
), colorkey
);
4349 /* read graphics image instances */
4351 else if (!strcmp(keyword
, "graphic")) {
4355 lineptr
= buffer
+ 1;
4356 for (i
= 0; i
< xobjs
.images
; i
++) {
4357 img
= xobjs
.imagelist
+ i
;
4358 if (!strncmp(img
->filename
, lineptr
, strlen(img
->filename
))) {
4359 NEW_GRAPHIC(newgp
, localdata
);
4360 (*newgp
)->color
= curcolor
;
4361 (*newgp
)->passed
= NULL
;
4363 (*newgp
)->clipmask
= (Pixmap
)NULL
;
4364 (*newgp
)->target
= NULL
;
4365 (*newgp
)->valid
= False
;
4366 #endif /* HAVE_CAIRO */
4367 (*newgp
)->source
= img
->image
;
4369 lineptr
+= strlen(img
->filename
) + 1;
4373 if (i
== xobjs
.images
) {
4374 /* Error: Line points to a non-existant image (no data) */
4375 /* See if we can load the image name as a filename, and */
4376 /* if that fails, then we must throw an error and ignore */
4377 /* the image element. */
4380 char *sptr
= strchr(lineptr
, ' ');
4386 locgp
= new_graphic(NULL
, lineptr
, 0, 0);
4388 if (locgp
== NULL
) {
4389 Fprintf(stderr
, "Error: No graphic data for \"%s\".\n",
4399 if ((newgp
!= NULL
) && (*newgp
!= NULL
)) {
4400 lineptr
= varfscan(localdata
, lineptr
, &(*newgp
)->scale
,
4401 (genericptr
)*newgp
, P_SCALE
);
4402 lineptr
= varfscan(localdata
, lineptr
, &(*newgp
)->rotation
,
4403 (genericptr
)*newgp
, P_ROTATION
);
4404 lineptr
= varpscan(localdata
, lineptr
, &(*newgp
)->position
.x
,
4405 (genericptr
)*newgp
, 0, offx
, P_POSITION_X
);
4406 lineptr
= varpscan(localdata
, lineptr
, &(*newgp
)->position
.y
,
4407 (genericptr
)*newgp
, 0, offy
, P_POSITION_Y
);
4408 std_eparam((genericptr
)(*newgp
), colorkey
);
4414 else if (!strcmp(keyword
, "fontset")) { /* old style */
4415 char tmpstring
[100];
4417 sscanf(buffer
, "%f %*c%99s", &tmpscale
, tmpstring
);
4418 for (i
= 0; i
< fontcount
; i
++)
4419 if (!strcmp(tmpstring
, fonts
[i
].psname
)) {
4423 if (i
== fontcount
) i
= 0; /* Why bother with anything fancy? */
4426 else if (!strcmp(keyword
, "label") || !strcmp(keyword
, "pinlabel")
4427 || !strcmp(keyword
, "pinglobal") || !strcmp(keyword
, "infolabel")) {
4430 stringpart
*firstscale
, *firstfont
;
4432 NEW_LABEL(newlabel
, localdata
);
4433 (*newlabel
)->color
= curcolor
;
4434 (*newlabel
)->string
= NULL
;
4435 (*newlabel
)->passed
= NULL
;
4436 (*newlabel
)->cycle
= NULL
;
4438 /* scan backwards to get the number of substrings */
4439 lineptr
= keyptr
- 1;
4440 for (i
= 0; i
< ((version
< 2.25) ? 5 : 6); i
++) {
4441 for (; *lineptr
== ' '; lineptr
--);
4442 for (; *lineptr
!= ' '; lineptr
--);
4444 if ((strchr(lineptr
, '.') != NULL
) && (version
< 2.25)) {
4445 Fprintf(stderr
, "Error: File version claims to be %2.1f,"
4446 " but has version %2.1f labels\n", version
, PROG_VERSION
);
4447 Fprintf(stderr
, "Attempting to resolve problem by updating version.\n");
4448 version
= PROG_VERSION
;
4449 for (; *lineptr
== ' '; lineptr
--);
4450 for (; *lineptr
!= ' '; lineptr
--);
4452 /* no. segments is ignored---may be a derived quantity, anyway */
4453 if (version
< 2.25) {
4454 sscanf(lineptr
, "%*s %hd %hf %hd %hd", &(*newlabel
)->anchor
,
4455 &(*newlabel
)->rotation
, &(*newlabel
)->position
.x
,
4456 &(*newlabel
)->position
.y
);
4457 (*newlabel
)->position
.x
-= offx
; (*newlabel
)->position
.y
-= offy
;
4462 lineptr
= advancetoken(lineptr
); /* skip string token */
4463 lineptr
= varscan(localdata
, lineptr
, &(*newlabel
)->anchor
,
4464 (genericptr
)*newlabel
, P_ANCHOR
);
4465 lineptr
= varfscan(localdata
, lineptr
, &(*newlabel
)->rotation
,
4466 (genericptr
)*newlabel
, P_ROTATION
);
4467 lineptr
= varfscan(localdata
, lineptr
, &(*newlabel
)->scale
,
4468 (genericptr
)*newlabel
, P_SCALE
);
4469 lineptr
= varpscan(localdata
, lineptr
, &(*newlabel
)->position
.x
,
4470 (genericptr
)*newlabel
, 0, offx
, P_POSITION_X
);
4471 lineptr
= varpscan(localdata
, lineptr
, &(*newlabel
)->position
.y
,
4472 (genericptr
)*newlabel
, 0, offy
, P_POSITION_Y
);
4475 (*newlabel
)->rotation
= -(*newlabel
)->rotation
;
4476 while ((*newlabel
)->rotation
< 0.0) (*newlabel
)->rotation
+= 360.0;
4478 (*newlabel
)->pin
= False
;
4479 if (strcmp(keyword
, "label")) { /* all the schematic types */
4480 /* enable schematic capture if it is not already on. */
4481 if (!strcmp(keyword
, "pinlabel"))
4482 (*newlabel
)->pin
= LOCAL
;
4483 else if (!strcmp(keyword
, "pinglobal"))
4484 (*newlabel
)->pin
= GLOBAL
;
4485 else if (!strcmp(keyword
, "infolabel")) {
4486 /* Do not turn top-level pages into symbols! */
4487 /* Info labels on schematics are treated differently. */
4488 if (localdata
!= topobject
)
4489 localdata
->schemtype
= FUNDAMENTAL
;
4490 (*newlabel
)->pin
= INFO
;
4491 if (curcolor
== DEFAULTCOLOR
)
4492 (*newlabel
)->color
= INFOLABELCOLOR
;
4496 lineptr
= buffer
; /* back to beginning of string */
4497 if (!strncmp(lineptr
, "mark", 4)) lineptr
+= 4;
4499 readlabel(localdata
, lineptr
, &(*newlabel
)->string
);
4500 CheckMarginStop(*newlabel
, areawin
->topinstance
, FALSE
);
4502 if (version
< 2.25) {
4503 /* Switch 1st scale designator to overall font scale */
4505 firstscale
= (*newlabel
)->string
->nextpart
;
4506 if (firstscale
->type
!= FONT_SCALE
) {
4507 if (tmpscale
!= 0.0)
4508 (*newlabel
)->scale
= 0.0;
4510 (*newlabel
)->scale
= 1.0;
4513 (*newlabel
)->scale
= firstscale
->data
.scale
;
4514 deletestring(firstscale
, &((*newlabel
)->string
),
4515 areawin
->topinstance
);
4519 firstfont
= (*newlabel
)->string
;
4520 if ((firstfont
== NULL
) || (firstfont
->type
!= FONT_NAME
)) {
4521 if (tmpfont
== -1) {
4522 Fprintf(stderr
, "Error: Label with no font designator?\n");
4525 firstfont
= makesegment(&((*newlabel
)->string
), (*newlabel
)->string
);
4526 firstfont
->type
= FONT_NAME
;
4527 firstfont
->data
.font
= tmpfont
;
4529 cleanuplabel(&(*newlabel
)->string
);
4531 std_eparam((genericptr
)(*newlabel
), colorkey
);
4534 /* read symbol-to-schematic connection */
4536 else if (!strcmp(keyword
, "is_schematic")) {
4538 for (lineptr
= buffer
; *lineptr
== ' '; lineptr
++);
4539 parse_ps_string(++lineptr
, tempstr
, 49, FALSE
, FALSE
);
4540 checksym(localdata
, tempstr
);
4543 /* read bounding box (font files only) */
4545 else if (!strcmp(keyword
, "bbox")) {
4546 for (lineptr
= buffer
; *lineptr
== ' '; lineptr
++);
4547 if (*lineptr
!= '%') {
4548 Wprintf("Illegal bbox.");
4553 sscanf(++lineptr
, "%hd %hd %hd %hd",
4554 &localdata
->bbox
.lowerleft
.x
, &localdata
->bbox
.lowerleft
.y
,
4555 &localdata
->bbox
.width
, &localdata
->bbox
.height
);
4558 /* read "hidden" attribute */
4560 else if (!strcmp(keyword
, "hidden")) {
4561 localdata
->hidden
= True
;
4564 /* read "libinst" special instance of a library part */
4566 else if (!strcmp(keyword
, "libinst")) {
4568 /* Read backwards from keyword to find name of object instanced. */
4569 for (lineptr
= keyptr
; *lineptr
!= '/' && lineptr
> buffer
;
4571 parse_ps_string(++lineptr
, keyword
, 79, FALSE
, FALSE
);
4572 new_library_instance(mode
- LIBRARY
, keyword
, buffer
, defaulttech
);
4577 else if (!strcmp(keyword
, "{")) { /* This is an object definition */
4579 objectptr
*newobject
;
4581 for (lineptr
= buffer
; *lineptr
== ' '; lineptr
++);
4582 if (*lineptr
++ != '/') {
4583 /* This may be part of a label. . . treat as a continuation line */
4584 temp
= continueline(&buffer
);
4587 parse_ps_string(lineptr
, keyword
, 79, FALSE
, FALSE
);
4589 newobject
= new_library_object(mode
, keyword
, &redef
, defaulttech
);
4591 if (objectread(ps
, *newobject
, 0, 0, mode
, retstr
, curcolor
,
4592 defaulttech
) == True
) {
4593 strncpy(retstr
, buffer
, 150);
4599 if (library_object_unique(mode
, *newobject
, redef
))
4600 add_object_to_library(mode
, *newobject
);
4603 else if (!strcmp(keyword
, "def")) {
4604 strncpy(retstr
, buffer
, 150);
4607 return False
; /* end of object def or end of object library */
4610 else if (!strcmp(keyword
, "loadfontencoding")) {
4611 /* Deprecated, but retained for backward compatibility. */
4612 /* Load from script, .xcircuitrc, or command line instead. */
4613 for (lineptr
= buffer
; *lineptr
!= '%'; lineptr
++);
4614 sscanf (lineptr
+ 1, "%149s", _STR
);
4615 if (*(lineptr
+ 1) != '%') loadfontfile(_STR
);
4617 else if (!strcmp(keyword
, "loadlibrary")) {
4618 /* Deprecated, but retained for backward compatibility */
4619 /* Load from script, .xcircuitrc, or command line instead. */
4622 for (lineptr
= buffer
; *lineptr
!= '%'; lineptr
++);
4623 sscanf (++lineptr
, "%149s", _STR
);
4624 while (isspace(*lineptr
)) lineptr
++;
4625 while (!isspace(*++lineptr
));
4626 while (isspace(*++lineptr
));
4627 if (sscanf (lineptr
, "%d", &ilib
) > 0) {
4628 while ((ilib
- 2 + LIBRARY
) > xobjs
.numlibs
) {
4629 tlib
= createlibrary(False
);
4630 if (tlib
!= xobjs
.numlibs
- 2 + LIBRARY
) {
4635 mode
= ilib
- 1 + LIBRARY
;
4639 else if (!strcmp(keyword
, "beginparm")) { /* parameterized object */
4641 for (--keyptr
; *keyptr
== ' '; keyptr
--);
4642 for (; isdigit(*keyptr
) && (keyptr
>= buffer
); keyptr
--);
4643 sscanf(keyptr
, "%hd", &tmpnum
);
4645 while (isspace(*lineptr
)) lineptr
++;
4647 if (tmpnum
< 256) { /* read parameter defaults in order */
4648 stringpart
*newpart
;
4649 /* oparamptr newops; (jdk) */
4651 for (i
= 0; i
< tmpnum
; i
++) {
4654 newops
= (oparamptr
)malloc(sizeof(oparam
));
4655 newops
->next
= localdata
->params
;
4656 localdata
->params
= newops
;
4657 newops
->key
= (char *)malloc(6);
4658 sprintf(newops
->key
, "v%d", i
+ 1);
4660 if (*lineptr
== '(' || *lineptr
== '{') { /* type is XC_STRING */
4661 char *linetmp
, csave
;
4663 newops
->parameter
.string
= NULL
;
4665 /* get simple substring or set of substrings and commands */
4666 linetmp
= find_delimiter(lineptr
);
4667 csave
= *(++linetmp
);
4669 if (*lineptr
== '{') lineptr
++;
4670 readlabel(localdata
, lineptr
, &(newops
->parameter
.string
));
4672 /* Add the ending part to the parameter string */
4673 newpart
= makesegment(&(newops
->parameter
.string
), NULL
);
4674 newpart
->type
= PARAM_END
;
4675 newpart
->data
.string
= (u_char
*)NULL
;
4677 newops
->type
= (u_char
)XC_STRING
;
4678 newops
->which
= P_SUBSTRING
;
4679 /* Fprintf(stdout, "Parameter %d to object %s defaults "
4680 "to string \"%s\"\n", i + 1, localdata->name,
4681 ops->parameter.string); */
4684 while (isspace(*lineptr
)) lineptr
++;
4686 else { /* type is assumed to be XC_FLOAT */
4687 newops
->type
= (u_char
)XC_FLOAT
;
4688 sscanf(lineptr
, "%g", &newops
->parameter
.fvalue
);
4689 /* Fprintf(stdout, "Parameter %s to object %s defaults to "
4690 "value %g\n", newops->key, localdata->name,
4691 newops->parameter.fvalue); */
4692 lineptr
= advancetoken(lineptr
);
4697 else if (!strcmp(keyword
, "nonetwork")) {
4698 localdata
->valid
= True
;
4699 localdata
->schemtype
= NONETWORK
;
4701 else if (!strcmp(keyword
, "trivial")) {
4702 localdata
->schemtype
= TRIVIAL
;
4704 else if (!strcmp(keyword
, "begingate")) {
4705 localdata
->params
= NULL
;
4706 /* read dictionary of parameter key:value pairs */
4707 readparams(NULL
, NULL
, localdata
, buffer
);
4710 else if (!strcmp(keyword
, "%%Trailer")) break;
4711 else if (!strcmp(keyword
, "EndLib")) break;
4712 else if (!strcmp(keyword
, "restore")); /* handled at top */
4713 else if (!strcmp(keyword
, "grestore")); /* ignore */
4714 else if (!strcmp(keyword
, "endgate")); /* also ignore */
4715 else if (!strcmp(keyword
, "xyarray")); /* ignore for now */
4717 char *tmpptr
, *libobjname
, *objnamestart
;
4718 Boolean matchtech
, found
= False
;
4720 /* First, make sure this is not a general comment line */
4721 /* Return if we have a page boundary */
4722 /* Read an image if this is an imagedata line. */
4724 for (tmpptr
= buffer
; isspace(*tmpptr
); tmpptr
++);
4725 if (*tmpptr
== '%') {
4726 if (strstr(buffer
, "%%Page:") == tmpptr
) {
4727 strncpy(retstr
, buffer
, 150);
4732 else if (strstr(buffer
, "%imagedata") == tmpptr
) {
4734 sscanf(buffer
, "%*s %d %d", &width
, &height
);
4735 readimagedata(ps
, width
, height
);
4740 parse_ps_string(keyword
, keyword
, 79, FALSE
, FALSE
);
4741 matchtech
= (strstr(keyword
, "::") == NULL
) ? FALSE
: TRUE
;
4743 /* If the file contains a reference to a bare-word device */
4744 /* without a technology prefix, then it is probably an */
4745 /* older-version file. If this is the case, then the file */
4746 /* should define an unprefixed object, which will be given */
4747 /* a null prefix (just "::" by itself). Look for that */
4750 /* (Assume that this line calls an object instance) */
4751 /* Double loop through user libraries */
4753 for (k
= 0; k
< ((mode
== FONTLIB
) ? 1 : xobjs
.numlibs
); k
++) {
4754 for (j
= 0; j
< ((mode
== FONTLIB
) ? xobjs
.fontlib
.number
:
4755 xobjs
.userlibs
[k
].number
); j
++) {
4757 libobj
= (mode
== FONTLIB
) ? xobjs
.fontlib
.library
+ j
:
4758 xobjs
.userlibs
[k
].library
+ j
;
4760 /* Objects which have a technology ("<lib>::<obj>") */
4761 /* must compare exactly. Objects which don't can */
4762 /* only match an object of the same name with a null */
4763 /* technology prefix. */
4765 libobjname
= (*libobj
)->name
;
4767 objnamestart
= strstr(libobjname
, "::");
4768 if (objnamestart
!= NULL
) libobjname
= objnamestart
+ 2;
4770 if (!objnamecmp(keyword
, libobjname
)) {
4772 /* If the name is not exactly the same (appended underscores) */
4773 /* check if the name is on the list of aliases. */
4775 if (strcmp(keyword
, libobjname
)) {
4776 Boolean is_alias
= False
;
4777 aliasptr ckalias
= aliastop
;
4780 for (; ckalias
!= NULL
; ckalias
= ckalias
->next
) {
4781 if (ckalias
->baseobj
== (*libobj
)) {
4782 sref
= ckalias
->aliases
;
4783 for (; sref
!= NULL
; sref
= sref
->next
) {
4784 if (!strcmp(keyword
, sref
->alias
)) {
4789 if (is_alias
) break;
4792 if (!is_alias
) continue;
4795 if (!matchtech
&& ((*libobj
)->name
!= objnamestart
))
4797 continue; // no prefix in file must match
4798 // null prefix in library object.
4801 NEW_OBJINST(newinst
, localdata
);
4802 (*newinst
)->thisobject
= *libobj
;
4803 (*newinst
)->color
= curcolor
;
4804 (*newinst
)->params
= NULL
;
4805 (*newinst
)->passed
= NULL
;
4806 (*newinst
)->bbox
.lowerleft
.x
= (*libobj
)->bbox
.lowerleft
.x
;
4807 (*newinst
)->bbox
.lowerleft
.y
= (*libobj
)->bbox
.lowerleft
.y
;
4808 (*newinst
)->bbox
.width
= (*libobj
)->bbox
.width
;
4809 (*newinst
)->bbox
.height
= (*libobj
)->bbox
.height
;
4810 (*newinst
)->schembbox
= NULL
;
4812 lineptr
= varfscan(localdata
, buffer
, &(*newinst
)->scale
,
4813 (genericptr
)*newinst
, P_SCALE
);
4815 /* Format prior to xcircuit 3.7 did not have scale- */
4816 /* invariant linewidth. If scale is 1, though, keep it */
4817 /* invariant so as not to overuse the scale-variance */
4818 /* flag in the output file. */
4820 if ((version
< 3.7) && ((*newinst
)->scale
!= 1.0))
4821 (*newinst
)->style
= NORMAL
;
4823 (*newinst
)->style
= LINE_INVARIANT
;
4825 lineptr
= varfscan(localdata
, lineptr
, &(*newinst
)->rotation
,
4826 (genericptr
)*newinst
, P_ROTATION
);
4827 lineptr
= varpscan(localdata
, lineptr
, &(*newinst
)->position
.x
,
4828 (genericptr
)*newinst
, 0, offx
, P_POSITION_X
);
4829 lineptr
= varpscan(localdata
, lineptr
, &(*newinst
)->position
.y
,
4830 (genericptr
)*newinst
, 0, offy
, P_POSITION_Y
);
4832 /* Negative rotations = flip in x in version 2.3.6 and */
4833 /* earlier. Later versions don't allow negative rotation */
4835 if (version
< 2.4) {
4836 if ((*newinst
)->rotation
< 0.0) {
4837 (*newinst
)->scale
= -((*newinst
)->scale
);
4838 (*newinst
)->rotation
+= 1.0;
4840 (*newinst
)->rotation
= -(*newinst
)->rotation
;
4843 while ((*newinst
)->rotation
> 360.0)
4844 (*newinst
)->rotation
-= 360.0;
4845 while ((*newinst
)->rotation
< 0.0)
4846 (*newinst
)->rotation
+= 360.0;
4848 std_eparam((genericptr
)(*newinst
), colorkey
);
4850 /* Does this instance contain parameters? */
4851 readparams(localdata
, *newinst
, *libobj
, buffer
);
4853 calcbboxinst(*newinst
);
4861 if (!found
) /* will assume that we have a continuation line */
4862 temp
= continueline(&buffer
);
4866 strncpy(retstr
, buffer
, 150);
4872 /*------------------------*/
4873 /* Save a PostScript file */
4874 /*------------------------*/
4878 void setfile(char *filename
, int mode
)
4880 if ((filename
== NULL
) || (xobjs
.pagelist
[areawin
->page
]->filename
== NULL
)) {
4881 Wprintf("Error: No filename for schematic.");
4882 if (beeper
) XBell(dpy
, 100);
4886 /* see if name has been changed in the buffer */
4888 if (strcmp(xobjs
.pagelist
[areawin
->page
]->filename
, filename
)) {
4889 Wprintf("Changing name of edit file.");
4890 free(xobjs
.pagelist
[areawin
->page
]->filename
);
4891 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(filename
);
4894 if (strstr(xobjs
.pagelist
[areawin
->page
]->filename
, "Page ") != NULL
) {
4895 Wprintf("Warning: Enter a new name.");
4896 if (beeper
) XBell(dpy
, 100);
4900 if (beeper
) XBell(dpy
, 100);
4904 #else /* !TCL_WRAPPER */
4906 void setfile(xcWidget button
, xcWidget fnamewidget
, caddr_t clientdata
)
4908 /* see if name has been changed in the buffer */
4910 sprintf(_STR2
, "%.249s", (char *)XwTextCopyBuffer(fnamewidget
));
4911 if (xobjs
.pagelist
[areawin
->page
]->filename
== NULL
) {
4912 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(_STR2
);
4914 else if (strcmp(xobjs
.pagelist
[areawin
->page
]->filename
, _STR2
)) {
4915 Wprintf("Changing name of edit file.");
4916 free(xobjs
.pagelist
[areawin
->page
]->filename
);
4917 xobjs
.pagelist
[areawin
->page
]->filename
= strdup(_STR2
);
4919 if (strstr(xobjs
.pagelist
[areawin
->page
]->filename
, "Page ") != NULL
) {
4920 Wprintf("Warning: Enter a new name.");
4921 if (beeper
) XBell(dpy
, 100);
4928 savefile(CURRENT_PAGE
);
4930 /* Change "close" button to read "done" */
4932 di
= xcParent(button
);
4933 db
= XtNameToWidget(di
, "Close");
4934 XtSetArg(wargs
[0], XtNlabel
, " Done ");
4935 XtSetValues(db
, wargs
, 1);
4936 if (beeper
) XBell(dpy
, 100);
4940 #endif /* TCL_WRAPPER */
4942 /*--------------------------------------------------------------*/
4943 /* Update number of changes for an object and initiate a temp */
4944 /* file save if total number of unsaved changes exceeds 20. */
4945 /*--------------------------------------------------------------*/
4947 void incr_changes(objectptr thisobj
)
4949 /* It is assumed that empty pages are meant to be that way */
4950 /* and are not to be saved, so changes are marked as zero. */
4952 if (thisobj
->parts
== 0) {
4953 thisobj
->changes
= 0;
4957 /* Remove any pending timeout */
4959 if (xobjs
.timeout_id
!= (xcIntervalId
)NULL
) {
4960 xcRemoveTimeOut(xobjs
.timeout_id
);
4961 xobjs
.timeout_id
= (xcIntervalId
)NULL
;
4966 /* When in "suspend" mode, we assume that we are reading commands from
4967 * a script, and therefore we should not continuously increment changes
4968 * and keep saving the backup file.
4971 if (xobjs
.suspend
< 0)
4972 xobjs
.new_changes
++;
4974 if (xobjs
.new_changes
> MAXCHANGES
) {
4978 savetemp(NULL
, NULL
);
4982 /* Generate a new timeout */
4984 xobjs
.timeout_id
= xcAddTimeOut(app
, 60000 * xobjs
.save_interval
,
4988 /*--------------------------------------------------------------*/
4990 /*--------------------------------------------------------------*/
4994 void savetemp(ClientData clientdata
)
4999 void savetemp(XtPointer clientdata
, xcIntervalId
*id
)
5004 /* Remove the timeout ID. If this routine is called from */
5005 /* incr_changes() instead of from the timeout interrupt */
5006 /* service routine, then this value will already be NULL. */
5008 xobjs
.timeout_id
= (xcIntervalId
)NULL
;
5010 /* First see if there are any unsaved changes in the file. */
5011 /* If not, then just reset the counter and continue. */
5013 if (xobjs
.new_changes
> 0) {
5014 if (xobjs
.tempfile
== NULL
)
5017 char *template = (char *)malloc(20 + strlen(xobjs
.tempdir
));
5018 int pid
= (int)getpid();
5020 sprintf(template, "%s/XC%d.XXXXXX", xobjs
.tempdir
, pid
);
5023 fd
= mktemp(template);
5025 fd
= mkstemp(template);
5028 Fprintf(stderr
, "Error generating file for savetemp\n");
5032 xobjs
.tempfile
= strdup(template);
5035 /* Show the "wristwatch" cursor, as graphic data may cause this */
5036 /* step to be inordinately long. */
5038 XDefineCursor(dpy
, areawin
->window
, WAITFOR
);
5039 savefile(ALL_PAGES
);
5040 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5041 xobjs
.new_changes
= 0; /* reset the count */
5045 /*----------------------------------------------------------------------*/
5046 /* Set all objects in the list "wroteobjs" as having no unsaved changes */
5047 /*----------------------------------------------------------------------*/
5049 void setassaved(objectptr
*wroteobjs
, short written
)
5053 for (i
= 0; i
< written
; i
++)
5054 (*(wroteobjs
+ i
))->changes
= 0;
5057 /*---------------------------------------------------------------*/
5058 /* Save indicated library. If libno is 0, save current page if */
5059 /* the current page is a library. If not, save the user library */
5060 /*---------------------------------------------------------------*/
5062 void savelibpopup(xcWidget button
, char *technology
, caddr_t nulldata
)
5067 buttonsave
*savebutton
;
5070 nsptr
= LookupTechnology(technology
);
5072 if (nsptr
!= NULL
) {
5073 if ((nsptr
->flags
& TECH_READONLY
) != 0) {
5074 Wprintf("Library technology \"%s\" is read-only.", technology
);
5080 savebutton
= getgeneric(button
, savelibpopup
, technology
);
5081 popupprompt(button
, "Enter technology:", "\0", savelibrary
,
5086 /*---------------------------------------------------------*/
5090 void savelibrary(xcWidget w
, char *technology
)
5093 sscanf(_STR2
, "%249s", outname
);
5094 savetechnology(technology
, outname
);
5099 /*---------------------------------------------------------*/
5101 void savetechnology(char *technology
, char *outname
)
5104 char *outptr
, *validname
, outfile
[150];
5105 objectptr
*wroteobjs
, libobjptr
, *optr
, depobj
;
5111 char *hostname
= NULL
;
5112 struct passwd
*mypwentry
= NULL
;
5115 char *loctechnology
;
5117 // Don't use the string "(user)" as a technology name; this is just
5118 // a GUI placeholder for a null string (""). This shouldn't happen,
5119 // though, as technology should be NULL if the user technology is
5122 if (technology
&& (!strcmp(technology
, "(user)")))
5123 nsptr
= LookupTechnology(NULL
);
5125 nsptr
= LookupTechnology(technology
);
5127 if ((outptr
= strrchr(outname
, '/')) == NULL
)
5131 strcpy(outfile
, outname
);
5132 if (strchr(outptr
, '.') == NULL
) strcat(outfile
, ".lps");
5134 xc_tilde_expand(outfile
, 149);
5135 while(xc_variable_expand(outfile
, 149));
5137 if (nsptr
!= NULL
&& nsptr
->filename
!= NULL
) {
5138 // To be pedantic, we should probably check that the inodes of the
5139 // files are different, to be sure we are avoiding an unintentional
5142 if (!strcmp(outfile
, nsptr
->filename
)) {
5144 if ((nsptr
->flags
& TECH_READONLY
) != 0) {
5145 Wprintf("Technology file \"%s\" is read-only.", technology
);
5149 if ((nsptr
->flags
& TECH_IMPORTED
) != 0) {
5150 Wprintf("Attempt to write a truncated technology file!");
5156 ps
= fopen(outfile
, "wb");
5158 Wprintf("Can't open PS file.");
5159 if (nsptr
&& nsptr
->filename
&& (!strcmp(nsptr
->filename
, outfile
))) {
5160 Wprintf("Marking technology \"%s\" as read-only.", technology
);
5161 nsptr
->flags
|= TECH_READONLY
;
5166 /* Did the technology name change? If so, register the new name. */
5167 /* Clear any "IMPORTED" or "READONLY" flags. */
5169 if (nsptr
&& nsptr
->filename
&& strcmp(outfile
, nsptr
->filename
)) {
5170 Wprintf("Technology filename changed from \"%s\" to \"%s\".",
5171 nsptr
->filename
, outfile
);
5172 free(nsptr
->filename
);
5173 nsptr
->filename
= strdup(outfile
);
5174 nsptr
->flags
&= ~(TECH_READONLY
| TECH_IMPORTED
);
5176 else if (nsptr
&& !nsptr
->filename
) {
5177 nsptr
->filename
= strdup(outfile
);
5178 nsptr
->flags
&= ~(TECH_READONLY
| TECH_IMPORTED
);
5181 fprintf(ps
, "%%! PostScript set of library objects for XCircuit\n");
5182 fprintf(ps
, "%% Version: %2.1f\n", version
);
5183 fprintf(ps
, "%% Library name is: %s\n",
5184 (technology
== NULL
) ? "(user)" : technology
);
5186 uname
= getenv((const char *)"USERNAME");
5188 uname
= getenv((const char *)"USER");
5189 if (uname
!= NULL
) mypwentry
= getpwnam(uname
);
5192 /* Check for both $HOST and $HOSTNAME environment variables. Thanks */
5193 /* to frankie liu <frankliu@Stanford.EDU> for this fix. */
5195 if ((hostname
= getenv((const char *)"HOSTNAME")) == NULL
)
5196 if ((hostname
= getenv((const char *)"HOST")) == NULL
) {
5197 if (gethostname(_STR
, 149) != 0)
5204 if (mypwentry
!= NULL
)
5205 fprintf(ps
, "%% Author: %s <%s@%s>\n", mypwentry
->pw_gecos
, uname
,
5209 fprintf(ps
, "%%\n\n");
5211 /* Print lists of object dependencies, where they exist. */
5212 /* Note that objects can depend on objects in other technologies; */
5213 /* this is allowed. */
5215 wroteobjs
= (objectptr
*) malloc(sizeof(objectptr
));
5216 for (ilib
= 0; ilib
< xobjs
.numlibs
; ilib
++) {
5217 for (j
= 0; j
< xobjs
.userlibs
[ilib
].number
; j
++) {
5219 libobjptr
= *(xobjs
.userlibs
[ilib
].library
+ j
);
5220 if (CompareTechnology(libobjptr
, technology
)) {
5223 /* Search for all object definitions instantiated in this object, */
5224 /* and add them to the dependency list (non-recursive). */
5226 for (gptr
= libobjptr
->plist
; gptr
< libobjptr
->plist
5227 + libobjptr
->parts
; gptr
++) {
5228 if (IS_OBJINST(*gptr
)) {
5229 depobj
= TOOBJINST(gptr
)->thisobject
;
5231 /* Search among the list of objects already collected. */
5232 /* If this object has been previously, then ignore it. */
5233 /* Otherwise, update the list of object dependencies */
5235 for (optr
= wroteobjs
; optr
< wroteobjs
+ written
; optr
++)
5236 if (*optr
== depobj
)
5239 if (optr
== wroteobjs
+ written
) {
5240 wroteobjs
= (objectptr
*)realloc(wroteobjs
, (written
+ 1) *
5242 *(wroteobjs
+ written
) = depobj
;
5248 fprintf(ps
, "%% Depend %s", libobjptr
->name
);
5249 for (i
= 0; i
< written
; i
++) {
5250 depobj
= *(wroteobjs
+ i
);
5251 fprintf(ps
, " %s", depobj
->name
);
5259 fprintf(ps
, "\n%% XCircuitLib library objects\n");
5261 /* Start by looking for any graphic images in the library objects */
5262 /* and saving the graphic image data at the top of the file. */
5264 glist
= (short *)malloc(xobjs
.images
* sizeof(short));
5265 for (i
= 0; i
< xobjs
.images
; i
++) glist
[i
] = 0;
5267 for (ilib
= 0; ilib
< xobjs
.numlibs
; ilib
++) {
5268 for (spec
= xobjs
.userlibs
[ilib
].instlist
; spec
!= NULL
; spec
= spec
->next
) {
5269 libobjptr
= spec
->thisinst
->thisobject
;
5270 if (CompareTechnology(libobjptr
, technology
))
5271 count_graphics(spec
->thisinst
->thisobject
, glist
);
5274 output_graphic_data(ps
, glist
);
5277 /* list of library objects already written */
5279 wroteobjs
= (objectptr
*)realloc(wroteobjs
, sizeof(objectptr
));
5282 /* write all of the object definitions used, bottom up, with virtual */
5283 /* instances in the correct placement. The need to find virtual */
5284 /* instances is why we do a look through the library pages and not */
5285 /* the libraries themselves when looking for objects matching the */
5286 /* given technology. */
5288 for (ilib
= 0; ilib
< xobjs
.numlibs
; ilib
++) {
5289 for (spec
= xobjs
.userlibs
[ilib
].instlist
; spec
!= NULL
; spec
= spec
->next
) {
5290 libobjptr
= spec
->thisinst
->thisobject
;
5291 if (CompareTechnology(libobjptr
, technology
)) {
5292 if (!spec
->virtual) {
5293 printobjects(ps
, spec
->thisinst
->thisobject
, &wroteobjs
,
5294 &written
, DEFAULTCOLOR
);
5297 if ((spec
->thisinst
->scale
!= 1.0) ||
5298 (spec
->thisinst
->rotation
!= 0.0)) {
5299 fprintf(ps
, "%3.3f %3.3f ", spec
->thisinst
->scale
,
5300 spec
->thisinst
->rotation
);
5302 printparams(ps
, spec
->thisinst
, 0);
5303 validname
= create_valid_psname(spec
->thisinst
->thisobject
->name
, FALSE
);
5304 /* Names without technologies get '::' string (blank technology) */
5305 if (technology
== NULL
)
5306 fprintf(ps
, "/::%s libinst\n", validname
);
5308 fprintf(ps
, "/%s libinst\n", validname
);
5309 if ((spec
->next
!= NULL
) && (!(spec
->next
->virtual)))
5316 setassaved(wroteobjs
, written
);
5317 if (nsptr
) nsptr
->flags
&= (~TECH_CHANGED
);
5318 xobjs
.new_changes
= countchanges(NULL
);
5320 /* and the postlog */
5322 fprintf(ps
, "\n%% EndLib\n");
5324 if (technology
!= NULL
)
5325 Wprintf("Library technology \"%s\" saved as file %s.",technology
, outname
);
5327 Wprintf("Library technology saved as file %s.", outname
);
5332 /*----------------------------------------------------------------------*/
5333 /* Recursive routine to search the object hierarchy for fonts used */
5334 /*----------------------------------------------------------------------*/
5336 void findfonts(objectptr writepage
, short *fontsused
) {
5341 for (dfp
= writepage
->plist
; dfp
< writepage
->plist
+ writepage
->parts
; dfp
++) {
5342 if (IS_LABEL(*dfp
)) {
5343 for (chp
= TOLABEL(dfp
)->string
; chp
!= NULL
; chp
= chp
->nextpart
) {
5344 if (chp
->type
== FONT_NAME
) {
5345 findex
= chp
->data
.font
;
5346 if (fontsused
[findex
] == 0) {
5347 fontsused
[findex
] = 0x8000 | fonts
[findex
].flags
;
5352 else if (IS_OBJINST(*dfp
)) {
5353 findfonts(TOOBJINST(dfp
)->thisobject
, fontsused
);
5358 /*------------------------------------------------------*/
5359 /* Write graphics image data to file "ps". "glist" is */
5360 /* a pointer to a vector of short integers, each one */
5361 /* being an index into xobjs.images for an image that */
5362 /* is to be output. */
5363 /*------------------------------------------------------*/
5365 void output_graphic_data(FILE *ps
, short *glist
)
5367 char *fptr
, ascbuf
[6];
5369 for (i
= 0; i
< xobjs
.images
; i
++) {
5370 Imagedata
*img
= xobjs
.imagelist
+ i
;
5371 int ilen
, flen
, k
, m
= 0, n
, q
= 0;
5372 u_char
*filtbuf
, *flatebuf
;
5373 Boolean lastpix
= False
;
5378 int width
= xcImageGetWidth(img
->image
);
5379 int height
= xcImageGetHeight(img
->image
);
5381 if (glist
[i
] == 0) continue;
5383 fprintf(ps
, "%%imagedata %d %d\n", width
, height
);
5384 fprintf(ps
, "currentfile /ASCII85Decode filter ");
5387 fprintf(ps
, "/FlateDecode filter\n");
5390 fprintf(ps
, "/ReusableStreamDecode filter\n");
5392 /* creating a stream buffer is wasteful if we're just using ASCII85 */
5393 /* decoding but is a must for compression filters. */
5395 ilen
= 3 * width
* height
;
5396 filtbuf
= (u_char
*)malloc(ilen
+ 4);
5399 for (j
= 0; j
< height
; j
++)
5400 for (k
= 0; k
< width
; k
++) {
5401 unsigned char r
, g
, b
;
5402 xcImageGetPixel(img
->image
, k
, j
, &r
, &g
, &b
);
5408 /* Extra encoding goes here */
5411 flatebuf
= (char *)malloc(flen
);
5412 ilen
= large_deflate(flatebuf
, flen
, filtbuf
, ilen
);
5420 for (j
= 0; j
< ilen
; j
+= 4) {
5421 if ((j
+ 4) > ilen
) lastpix
= TRUE
;
5422 if (!lastpix
&& (flatebuf
[j
] + flatebuf
[j
+ 1] + flatebuf
[j
+ 2]
5423 + flatebuf
[j
+ 3] == 0)) {
5428 for (n
= 0; n
< 4; n
++)
5429 pixel
.b
[3 - n
] = flatebuf
[j
+ n
];
5431 ascbuf
[0] = '!' + (pixel
.i
/ 52200625);
5432 pixel
.i
%= 52200625;
5433 ascbuf
[1] = '!' + (pixel
.i
/ 614125);
5435 ascbuf
[2] = '!' + (pixel
.i
/ 7225);
5437 ascbuf
[3] = '!' + (pixel
.i
/ 85);
5439 ascbuf
[4] = '!' + pixel
.i
;
5441 for (n
= 0; n
< ilen
+ 1 - j
; n
++)
5442 fprintf(ps
, "%c", ascbuf
[n
]);
5444 fprintf(ps
, "%5s", ascbuf
);
5452 fprintf(ps
, "~>\n");
5455 /* Remove any filesystem path information from the image name. */
5456 /* Otherwise, the slashes will cause PostScript to err. */
5458 fptr
= strrchr(img
->filename
, '/');
5460 fptr
= img
->filename
;
5463 fprintf(ps
, "/%sdata exch def\n", fptr
);
5464 fprintf(ps
, "/%s <<\n", fptr
);
5465 fprintf(ps
, " /ImageType 1 /Width %d /Height %d /BitsPerComponent 8\n",
5467 fprintf(ps
, " /MultipleDataSources false\n");
5468 fprintf(ps
, " /Decode [0 1 0 1 0 1]\n");
5469 fprintf(ps
, " /ImageMatrix [1 0 0 -1 %d %d]\n",
5470 width
>> 1, height
>> 1);
5471 fprintf(ps
, " /DataSource %sdata >> def\n\n", fptr
);
5475 /*----------------------------------------------------------------------*/
5476 /* Main file saving routine */
5477 /*----------------------------------------------------------------------*/
5478 /* mode description */
5479 /*----------------------------------------------------------------------*/
5480 /* ALL_PAGES saves a crash recovery backup file */
5481 /* CURRENT_PAGE saves all pages associated with the same */
5482 /* filename as the current page, and all */
5483 /* dependent schematics (which have their */
5484 /* filenames changed to match). */
5485 /* NO_SUBCIRCUITS saves all pages associated with the same */
5486 /* filename as the current page, only. */
5487 /*----------------------------------------------------------------------*/
5489 void savefile(short mode
)
5491 FILE *ps
, *pro
, *enc
;
5492 char outname
[150], temp
[150], prologue
[150], *fname
, *fptr
, ascbuf
[6];
5493 /* u_char decodebuf[6]; (jdk */
5494 short written
, fontsused
[256], i
, page
, curpage
, multipage
;
5495 short savepage
, stcount
, *pagelist
, *glist
;
5496 objectptr
*wroteobjs
;
5497 objinstptr writepage
;
5502 if (mode
!= ALL_PAGES
) {
5503 /* doubly-protected file write: protect against errors during file write */
5504 fname
= xobjs
.pagelist
[areawin
->page
]->filename
;
5505 sprintf(outname
, "%s~", fname
);
5506 rename(fname
, outname
);
5509 /* doubly-protected backup: protect against errors during file write */
5510 sprintf(outname
, "%sB", xobjs
.tempfile
);
5511 rename(xobjs
.tempfile
, outname
);
5512 fname
= xobjs
.tempfile
;
5515 if ((fptr
= strrchr(fname
, '/')) != NULL
)
5520 if ((mode
!= ALL_PAGES
) && (strchr(fptr
, '.') == NULL
))
5521 sprintf(outname
, "%s.ps", fname
);
5522 else sprintf(outname
, "%s", fname
);
5524 xc_tilde_expand(outname
, 149);
5525 while(xc_variable_expand(outname
, 149));
5527 ps
= fopen(outname
, "wb");
5529 Wprintf("Can't open file %s for writing.", outname
);
5533 if ((mode
!= NO_SUBCIRCUITS
) && (mode
!= ALL_PAGES
))
5534 collectsubschems(areawin
->page
);
5536 /* Check for multiple-page output: get the number of pages; */
5537 /* ignore empty pages. */
5541 if (mode
== NO_SUBCIRCUITS
)
5542 pagelist
= pagetotals(areawin
->page
, INDEPENDENT
);
5543 else if (mode
== ALL_PAGES
)
5544 pagelist
= pagetotals(areawin
->page
, ALL_PAGES
);
5546 pagelist
= pagetotals(areawin
->page
, TOTAL_PAGES
);
5548 for (page
= 0; page
< xobjs
.pages
; page
++)
5549 if (pagelist
[page
] > 0)
5552 if (multipage
== 0) {
5553 Wprintf("Panic: could not find this page in page list!");
5559 /* Print the PostScript DSC Document Header */
5561 fprintf(ps
, "%%!PS-Adobe-3.0");
5562 if (multipage
== 1 && !(xobjs
.pagelist
[areawin
->page
]->pmode
& 1))
5563 fprintf(ps
, " EPSF-3.0\n");
5566 fprintf(ps
, "%%%%Title: %s\n", fptr
);
5567 fprintf(ps
, "%%%%Creator: XCircuit v%2.1f rev%d\n", PROG_VERSION
, PROG_REVISION
);
5569 fprintf(ps
, "%%%%CreationDate: %s", asctime(localtime(&tdate
)));
5570 fprintf(ps
, "%%%%Pages: %d\n", multipage
);
5572 /* This is just a default value; each bounding box is declared per */
5573 /* page by the DSC "PageBoundingBox" keyword. */
5574 /* However, encapsulated files adjust the bounding box to center on */
5575 /* the object, instead of centering the object on the page. */
5577 if (multipage
== 1 && !(xobjs
.pagelist
[areawin
->page
]->pmode
& 1)) {
5578 objectptr thisobj
= xobjs
.pagelist
[areawin
->page
]->pageinst
->thisobject
;
5579 float psscale
= getpsscale(xobjs
.pagelist
[areawin
->page
]->outscale
,
5582 /* The top-level bounding box determines the size of an encapsulated */
5583 /* drawing, regardless of the PageBoundingBox numbers. Therefore, */
5584 /* we size this to bound just the picture by closing up the 1" (72 */
5585 /* PostScript units) margins, except for a tiny sliver of a margin */
5586 /* (4 PostScript units) which covers a bit of sloppiness in the font */
5589 fprintf(ps
, "%%%%BoundingBox: 68 68 %d %d\n",
5590 (int)((float)thisobj
->bbox
.width
* psscale
)
5591 + xobjs
.pagelist
[areawin
->page
]->margins
.x
+ 4,
5592 (int)((float)thisobj
->bbox
.height
* psscale
)
5593 + xobjs
.pagelist
[areawin
->page
]->margins
.y
+ 4);
5595 else if (xobjs
.pagelist
[0]->coordstyle
== CM
)
5596 fprintf(ps
, "%%%%BoundingBox: 0 0 595 842\n"); /* A4 default (fixed by jdk) */
5598 fprintf(ps
, "%%%%BoundingBox: 0 0 612 792\n"); /* letter default */
5600 for (i
= 0; i
< fontcount
; i
++) fontsused
[i
] = 0;
5601 fprintf(ps
, "%%%%DocumentNeededResources: font ");
5604 /* find all of the fonts used in this document */
5605 /* log all fonts which are native PostScript */
5607 for (curpage
= 0; curpage
< xobjs
.pages
; curpage
++)
5608 if (pagelist
[curpage
] > 0) {
5609 writepage
= xobjs
.pagelist
[curpage
]->pageinst
;
5610 findfonts(writepage
->thisobject
, fontsused
);
5613 for (i
= 0; i
< fontcount
; i
++) {
5614 if (fontsused
[i
] & 0x8000)
5615 if ((fonts
[i
].flags
& 0x8018) == 0x0) {
5616 stcount
+= strlen(fonts
[i
].psname
) + 1;
5617 if (stcount
> OUTPUTWIDTH
) {
5618 stcount
= strlen(fonts
[i
].psname
) + 11;
5619 fprintf(ps
, "\n%%%%+ font ");
5621 fprintf(ps
, "%s ", fonts
[i
].psname
);
5625 fprintf(ps
, "\n%%%%EndComments\n");
5627 tmp_s
= getenv((const char *)"XCIRCUIT_LIB_DIR");
5628 if (tmp_s
!= NULL
) {
5629 sprintf(prologue
, "%s/%s", tmp_s
, PROLOGUE_FILE
);
5630 pro
= fopen(prologue
, "r");
5636 sprintf(prologue
, "%s/%s", PROLOGUE_DIR
, PROLOGUE_FILE
);
5637 pro
= fopen(prologue
, "r");
5639 sprintf(prologue
, "%s", PROLOGUE_FILE
);
5640 pro
= fopen(prologue
, "r");
5642 Wprintf("Can't open prolog.");
5650 /* write the prolog to the output */
5653 if (fgets(temp
, 149, pro
) == NULL
) break;
5654 if (!strncmp(temp
, "%%EndProlog", 11)) break;
5659 /* Special font encodings not known to PostScript */
5660 /* (anything other than Standard and ISOLatin-1) */
5662 for (findex
= 0; findex
< fontcount
; findex
++) {
5663 if ((fontsused
[findex
] & 0xf80) == 0x400) {
5664 /* Cyrillic (ISO8859-5) */
5665 sprintf(prologue
, "%s/%s", PROLOGUE_DIR
, CYRILLIC_ENC_FILE
);
5666 pro
= fopen(prologue
, "r");
5668 sprintf(prologue
, "%s", CYRILLIC_ENC_FILE
);
5669 pro
= fopen(prologue
, "r");
5671 Wprintf("Warning: Missing font encoding vectors.");
5672 Wprintf("Output may not print properly.");
5677 if (fgets(temp
, 149, pro
) == NULL
) break;
5683 else if ((fontsused
[findex
] & 0xf80) == 0x180) {
5684 /* Eastern European (ISOLatin2) */
5685 sprintf(prologue
, "%s/%s", PROLOGUE_DIR
, ISOLATIN2_ENC_FILE
);
5686 pro
= fopen(prologue
, "r");
5688 sprintf(prologue
, "%s", ISOLATIN2_ENC_FILE
);
5689 pro
= fopen(prologue
, "r");
5691 Wprintf("Warning: Missing font encoding vectors.");
5692 Wprintf("Output may not print properly.");
5697 if (fgets(temp
, 149, pro
) == NULL
) break;
5703 else if ((fontsused
[findex
] & 0xf80) == 0x300) {
5704 /* Turkish (ISOLatin5) */
5705 sprintf(prologue
, "%s/%s", PROLOGUE_DIR
, ISOLATIN5_ENC_FILE
);
5706 pro
= fopen(prologue
, "r");
5708 sprintf(prologue
, "%s", ISOLATIN5_ENC_FILE
);
5709 pro
= fopen(prologue
, "r");
5711 Wprintf("Warning: Missing font encoding vectors.");
5712 Wprintf("Output may not print properly.");
5717 if (fgets(temp
, 149, pro
) == NULL
) break;
5725 /* Finish off prolog */
5726 fputs("%%EndProlog\n", ps
);
5728 /* Special font handling */
5730 for (findex
= 0; findex
< fontcount
; findex
++) {
5732 /* Derived font slant */
5734 if ((fontsused
[findex
] & 0x032) == 0x032)
5735 fprintf(ps
, "/%s /%s .167 fontslant\n\n",
5736 fonts
[findex
].psname
, fonts
[findex
].family
);
5738 /* Derived ISO-Latin1 encoding */
5740 if ((fontsused
[findex
] & 0xf80) == 0x100) {
5741 char *fontorig
= NULL
;
5743 /* find the original standard-encoded font (can be itself) */
5744 for (i
= 0; i
< fontcount
; i
++) {
5745 if (i
== findex
) continue;
5746 if (!strcmp(fonts
[i
].family
, fonts
[findex
].family
) &&
5747 ((fonts
[i
].flags
& 0x03) == (fonts
[findex
].flags
& 0x03))) {
5748 fontorig
= fonts
[i
].psname
;
5752 if (fontorig
== NULL
) fontorig
= fonts
[findex
].psname
;
5753 fprintf(ps
, "/%s findfont dup length dict begin\n", fontorig
);
5754 fprintf(ps
, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
5755 fprintf(ps
, "/Encoding ISOLatin1Encoding def currentdict end\n");
5756 fprintf(ps
, "/%s exch definefont pop\n\n", fonts
[findex
].psname
);
5759 /* Derived Cyrillic (ISO8859-5) encoding */
5761 if ((fontsused
[findex
] & 0xf80) == 0x400) {
5762 char *fontorig
= NULL
;
5764 /* find the original standard-encoded font (can be itself) */
5765 for (i
= 0; i
< fontcount
; i
++) {
5766 if (i
== findex
) continue;
5767 if (!strcmp(fonts
[i
].family
, fonts
[findex
].family
) &&
5768 ((fonts
[i
].flags
& 0x03) == (fonts
[findex
].flags
& 0x03))) {
5769 fontorig
= fonts
[i
].psname
;
5773 if (fontorig
== NULL
) fontorig
= fonts
[findex
].psname
;
5774 fprintf(ps
, "/%s findfont dup length dict begin\n", fontorig
);
5775 fprintf(ps
, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
5776 fprintf(ps
, "/Encoding ISO8859_5Encoding def currentdict end\n");
5777 fprintf(ps
, "/%s exch definefont pop\n\n", fonts
[findex
].psname
);
5780 /* ISO-Latin2 encoding */
5782 if ((fontsused
[findex
] & 0xf80) == 0x180) {
5783 char *fontorig
= NULL
;
5785 /* find the original standard-encoded font (can be itself) */
5786 for (i
= 0; i
< fontcount
; i
++) {
5787 if (i
== findex
) continue;
5788 if (!strcmp(fonts
[i
].family
, fonts
[findex
].family
) &&
5789 ((fonts
[i
].flags
& 0x03) == (fonts
[findex
].flags
& 0x03))) {
5790 fontorig
= fonts
[i
].psname
;
5794 if (fontorig
== NULL
) fontorig
= fonts
[findex
].psname
;
5795 fprintf(ps
, "/%s findfont dup length dict begin\n", fontorig
);
5796 fprintf(ps
, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
5797 fprintf(ps
, "/Encoding ISOLatin2Encoding def currentdict end\n");
5798 fprintf(ps
, "/%s exch definefont pop\n\n", fonts
[findex
].psname
);
5801 /* ISO-Latin5 encoding */
5803 if ((fontsused
[findex
] & 0xf80) == 0x300) {
5804 char *fontorig
= NULL
;
5806 /* find the original standard-encoded font (can be itself) */
5807 for (i
= 0; i
< fontcount
; i
++) {
5808 if (i
== findex
) continue;
5809 if (!strcmp(fonts
[i
].family
, fonts
[findex
].family
) &&
5810 ((fonts
[i
].flags
& 0x03) == (fonts
[findex
].flags
& 0x03))) {
5811 fontorig
= fonts
[i
].psname
;
5815 if (fontorig
== NULL
) fontorig
= fonts
[findex
].psname
;
5816 fprintf(ps
, "/%s findfont dup length dict begin\n", fontorig
);
5817 fprintf(ps
, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
5818 fprintf(ps
, "/Encoding ISOLatin5Encoding def currentdict end\n");
5819 fprintf(ps
, "/%s exch definefont pop\n\n", fonts
[findex
].psname
);
5822 /* To do: Special encoding */
5824 if ((fontsused
[findex
] & 0xf80) == 0x80) {
5827 /* To do: Vectored (drawn) font */
5829 if (fontsused
[findex
] & 0x8) {
5833 /* List of objects already written */
5834 wroteobjs
= (objectptr
*) malloc (sizeof(objectptr
));
5837 fprintf(ps
, "%% XCircuit output starts here.\n\n");
5838 fprintf(ps
, "%%%%BeginSetup\n\n");
5840 /* Write out all of the images used */
5842 glist
= collect_graphics(pagelist
);
5843 output_graphic_data(ps
, glist
);
5846 for (curpage
= 0; curpage
< xobjs
.pages
; curpage
++) {
5847 if (pagelist
[curpage
] == 0) continue;
5849 /* Write all of the object definitions used, bottom up */
5850 printrefobjects(ps
, xobjs
.pagelist
[curpage
]->pageinst
->thisobject
,
5851 &wroteobjs
, &written
);
5854 fprintf(ps
, "\n%%%%EndSetup\n\n");
5857 for (curpage
= 0; curpage
< xobjs
.pages
; curpage
++) {
5858 if (pagelist
[curpage
] == 0) continue;
5860 /* Print the page header, all elements in the page, and page trailer */
5861 savepage
= areawin
->page
;
5862 /* Set the current page for the duration of printing so that any */
5863 /* page parameters will be printed correctly. */
5864 areawin
->page
= curpage
;
5865 printpageobject(ps
, xobjs
.pagelist
[curpage
]->pageinst
->thisobject
,
5867 areawin
->page
= savepage
;
5869 /* For crash recovery, log the filename for each page */
5870 if (mode
== ALL_PAGES
) {
5871 fprintf(ps
, "%% %s is_filename\n",
5872 (xobjs
.pagelist
[curpage
]->filename
== NULL
) ?
5873 xobjs
.pagelist
[curpage
]->pageinst
->thisobject
->name
:
5874 xobjs
.pagelist
[curpage
]->filename
);
5881 /* For crash recovery, save all objects that have been edited but are */
5882 /* not in the list of objects already saved. */
5884 if (mode
== ALL_PAGES
)
5889 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
5890 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
5891 thisobj
= *(xobjs
.userlibs
[i
].library
+ j
);
5892 if (thisobj
->changes
> 0 ) {
5893 for (k
= 0; k
< written
; k
++)
5894 if (thisobj
== *(wroteobjs
+ k
)) break;
5896 printobjects(ps
, thisobj
, &wroteobjs
, &written
, DEFAULTCOLOR
);
5901 else { /* No unsaved changes in these objects */
5902 setassaved(wroteobjs
, written
);
5903 for (i
= 0; i
< xobjs
.pages
; i
++)
5904 if (pagelist
[i
] > 0)
5905 xobjs
.pagelist
[i
]->pageinst
->thisobject
->changes
= 0;
5906 xobjs
.new_changes
= countchanges(NULL
);
5909 /* Free allocated memory */
5910 free((char *)pagelist
);
5911 free((char *)wroteobjs
);
5915 fprintf(ps
, "%%%%Trailer\n");
5916 fprintf(ps
, "XCIRCsave restore\n");
5917 fprintf(ps
, "%%%%EOF\n");
5920 Wprintf("File %s saved (%d page%s).", fname
, multipage
,
5921 (multipage
> 1 ? "s" : ""));
5923 if (mode
== ALL_PAGES
) {
5924 /* Remove the temporary redundant backup */
5925 sprintf(outname
, "%sB", xobjs
.tempfile
);
5928 else if (!xobjs
.retain_backup
) {
5929 /* Remove the backup file */
5930 sprintf(outname
, "%s~", fname
);
5934 /* Write LATEX strings, if any are present */
5938 /*----------------------------------------------------------------------*/
5939 /* Given a color index, print the R, G, B values */
5940 /*----------------------------------------------------------------------*/
5942 int printRGBvalues(char *tstr
, int index
, const char *postfix
)
5945 if (index
>= 0 && index
< number_colors
) {
5946 sprintf(tstr
, "%4.3f %4.3f %4.3f %s",
5947 (float)colorlist
[index
].color
.red
/ 65535,
5948 (float)colorlist
[index
].color
.green
/ 65535,
5949 (float)colorlist
[index
].color
.blue
/ 65535,
5954 /* The program can reach this point for any color which is */
5955 /* not listed in the table. This can happen when parameters */
5956 /* printed from printobjectparams object contain the string */
5957 /* "@p_color". Therefore print the default top-level */
5958 /* default color, which is black. */
5960 /* If the index is *not* DEFAULTCOLOR (-1), return an error */
5963 sprintf(tstr
, "0 0 0 %s", postfix
);
5964 return (index
== DEFAULTCOLOR
) ? 0 : -1;
5967 /*----------------------------------------------------*/
5968 /* Write string to PostScript string, ignoring NO_OPs */
5969 /*----------------------------------------------------*/
5971 char *nosprint(char *baseptr
, int *margin
, int *extsegs
)
5973 int qtmp
, slen
= 100;
5974 char *sptr
, *lptr
= NULL
, lsave
, *sptr2
;
5975 u_char
*pptr
, *qptr
, *bptr
;
5977 bptr
= (u_char
*)malloc(slen
); /* initial length 100 */
5980 while(1) { /* loop for breaking up margin-limited text into words */
5983 sptr
= strrchr(baseptr
, ' ');
5987 if (*(sptr
+ 1) == '\0') {
5988 while (*sptr
== ' ') sptr
--;
5990 sptr2
= strrchr(baseptr
, ' ');
6006 /* Includes extended character set (non-ASCII) */
6008 for (pptr
= sptr
; pptr
&& *pptr
!= '\0'; pptr
++) {
6009 /* Ensure enough space for the string, including everything */
6010 /* following the "for" loop */
6012 if (qtmp
+ 7 >= slen
) {
6014 bptr
= (char *)realloc(bptr
, slen
);
6018 /* Deal with non-printable characters and parentheses */
6019 if (*pptr
> (char)126) {
6020 sprintf(qptr
, "\\%3o", (int)(*pptr
));
6024 if ((*pptr
== '(') || (*pptr
== ')') || (*pptr
== '\\'))
6029 if (qptr
== bptr
+ 1) { /* Empty string gets a NULL result, not "()" */
6040 if (sptr
== baseptr
)
6051 return (char *)bptr
;
6054 /*--------------------------------------------------------------*/
6055 /* Write label segments to the output (in reverse order) */
6056 /*--------------------------------------------------------------*/
6058 short writelabel(FILE *ps
, stringpart
*chrtop
, short *stcount
)
6062 char **ostr
= (char **)malloc(sizeof(char *));
6064 float lastscale
= 1.0;
6069 /* Write segments into string array, in forward order */
6071 for (chrptr
= chrtop
; chrptr
!= NULL
; chrptr
= chrptr
->nextpart
) {
6072 ostr
= (char **)realloc(ostr
, (segs
+ 1) * sizeof(char *));
6073 if (chrtop
->type
== PARAM_END
) { /* NULL parameter is empty string */
6074 ostr
[segs
] = (char *)malloc(4);
6075 strcpy(ostr
[segs
], "() ");
6078 tmpstr
= writesegment(chrptr
, &lastscale
, &lastfont
, &margin
, &extsegs
);
6079 if (tmpstr
[0] != '\0')
6080 ostr
[segs
] = tmpstr
;
6087 /* Write string array to output in reverse order */
6088 for (i
= segs
- 1; i
>= 0; i
--) {
6089 dostcount(ps
, stcount
, strlen(ostr
[i
]));
6095 return segs
+ extsegs
;
6098 /*--------------------------------------------------------------*/
6099 /* Write a single label segment to the output */
6100 /* (Recursive, so we can write segments in the reverse order) */
6101 /*--------------------------------------------------------------*/
6103 char *writesegment(stringpart
*chrptr
, float *lastscale
, int *lastfont
, int *margin
,
6106 int type
= chrptr
->type
;
6107 char *retstr
, *validname
;
6111 validname
= create_valid_psname(chrptr
->data
.string
, TRUE
);
6112 sprintf(_STR
, "%s ", validname
);
6116 chrptr
->nextpart
= NULL
;
6119 sprintf(_STR
, "{ss} ");
6122 sprintf(_STR
, "{Ss} ");
6126 sprintf(_STR
, "{ns} ");
6129 sprintf(_STR
, "{ul} ");
6132 sprintf(_STR
, "{ol} ");
6135 sprintf(_STR
, "{} ");
6138 sprintf(_STR
, "{hS} ");
6141 sprintf(_STR
, "{qS} ");
6145 if (chrptr
->data
.flags
== 0)
6146 // Ignore automatically-generated line breaks
6147 sprintf(_STR
, "{CR} ");
6152 sprintf(_STR
, "{Ts} ");
6155 sprintf(_STR
, "{Tf} ");
6158 sprintf(_STR
, "{Tb} ");
6161 /* If font specifier is followed by a scale specifier, then */
6162 /* record the font change but defer the output. Otherwise, */
6163 /* output the font record now. */
6165 if ((chrptr
->nextpart
== NULL
) || (chrptr
->nextpart
->type
!= FONT_SCALE
))
6167 if (*lastscale
== 1.0)
6168 sprintf(_STR
, "{/%s cf} ", fonts
[chrptr
->data
.font
].psname
);
6170 sprintf(_STR
, "{/%s %5.3f cf} ", fonts
[chrptr
->data
.font
].psname
,
6175 *lastfont
= chrptr
->data
.font
;
6178 if (*lastfont
== -1) {
6179 Fprintf(stderr
, "Warning: Font may not be the one that was intended.\n");
6182 *lastscale
= chrptr
->data
.scale
;
6183 sprintf(_STR
, "{/%s %5.3f cf} ", fonts
[*lastfont
].psname
, *lastscale
);
6187 if (chrptr
->data
.color
== DEFAULTCOLOR
)
6188 strcat(_STR
, "sce} ");
6190 if (printRGBvalues(_STR
+ 1, chrptr
->data
.color
, "scb} ") < 0)
6191 strcat(_STR
, "sce} ");
6194 sprintf(_STR
, "{%d MR} ", chrptr
->data
.width
);
6195 *margin
= chrptr
->data
.width
;
6198 sprintf(_STR
, "{%d %d Kn} ", chrptr
->data
.kern
[0], chrptr
->data
.kern
[1]);
6201 /* Everything except TEXT_STRING will always fit in the _STR fixed- */
6202 /* length character array. */
6203 return nosprint(chrptr
->data
.string
, margin
, extsegs
);
6206 retstr
= (char *)malloc(1 + strlen(_STR
));
6207 strcpy(retstr
, _STR
);
6211 /*--------------------------------------------------------------*/
6212 /* Routine to write all the label segments as stored in _STR */
6213 /*--------------------------------------------------------------*/
6215 int writelabelsegs(FILE *ps
, short *stcount
, stringpart
*chrptr
)
6217 Boolean ismultipart
;
6220 if (chrptr
== NULL
) return 0;
6222 ismultipart
= ((chrptr
->nextpart
!= NULL
) &&
6223 (chrptr
->nextpart
->type
!= PARAM_END
)) ? True
: False
;
6225 /* If there is only one part, but it is not a string or the */
6226 /* end of a parameter (empty parameter), then set multipart */
6227 /* anyway so we get the double brace {{ }}. */
6229 if ((!ismultipart
) && (chrptr
->type
!= TEXT_STRING
) &&
6230 (chrptr
->type
!= PARAM_END
))
6233 /* nextpart is not NULL if there are multiple parts to the string */
6238 segs
= writelabel(ps
, chrptr
, stcount
);
6247 /*--------------------------------------------------------------*/
6248 /* Write the dictionary of parameters belonging to an object */
6249 /*--------------------------------------------------------------*/
6251 void printobjectparams(FILE *ps
, objectptr localdata
)
6256 char *ps_expr
, *validkey
;
6259 /* Check for parameters and default values */
6260 if (localdata
->params
== NULL
) return;
6265 for (ops
= localdata
->params
; ops
!= NULL
; ops
= ops
->next
) {
6266 validkey
= create_valid_psname(ops
->key
, TRUE
);
6267 fprintf(ps
, "/%s ", validkey
);
6268 dostcount (ps
, &stcount
, strlen(validkey
) + 2);
6270 switch (ops
->type
) {
6272 ps_expr
= evaluate_expr(localdata
, ops
, NULL
);
6273 if (ops
->which
== P_SUBSTRING
|| ops
->which
== P_EXPRESSION
) {
6274 dostcount(ps
, &stcount
, 3 + strlen(ps_expr
));
6279 else if (ops
->which
== P_COLOR
) {
6281 /* Write R, G, B components for PostScript */
6282 if (sscanf(ps_expr
, "%d", &ccol
) == 1) {
6284 printRGBvalues(_STR
, ccol
, "} ");
6285 dostcount(ps
, &stcount
, 1 + strlen(_STR
));
6289 dostcount(ps
, &stcount
, 8);
6290 fputs("{0 0 0} ", ps
);
6293 else if (sscanf(ps_expr
, "%g", &fp
) == 1) {
6294 dostcount(ps
, &stcount
, 1 + strlen(ps_expr
));
6298 else { /* Expression evaluates to error in object */
6299 dostcount(ps
, &stcount
, 2);
6302 dostcount(ps
, &stcount
, 7 + strlen(ops
->parameter
.expr
));
6304 fputs(ops
->parameter
.expr
, ps
);
6305 fputs(") pop ", ps
);
6309 segs
= writelabelsegs(ps
, &stcount
, ops
->parameter
.string
);
6311 /* When writing object parameters, we cannot allow a */
6312 /* NULL value. Instead, print an empty string (). */
6313 dostcount(ps
, &stcount
, 3);
6318 sprintf(_STR
, "%d ", ops
->parameter
.ivalue
);
6319 dostcount(ps
, &stcount
, strlen(_STR
));
6323 sprintf(_STR
, "%g ", ops
->parameter
.fvalue
);
6324 dostcount(ps
, &stcount
, strlen(_STR
));
6331 dostcount (ps
, &stcount
, 3);
6334 /*--------------------------------------------------------------*/
6335 /* Write the list of parameters belonging to an object instance */
6336 /*--------------------------------------------------------------*/
6338 short printparams(FILE *ps
, objinstptr sinst
, short stcount
)
6342 oparamptr ops
, objops
;
6344 char *ps_expr
, *validkey
, *validref
;
6345 short instances
= 0;
6347 if (sinst
->params
== NULL
) return stcount
;
6349 for (ops
= sinst
->params
; ops
!= NULL
; ops
= ops
->next
) {
6350 validref
= strdup(create_valid_psname(ops
->key
, TRUE
));
6352 /* Check for indirect parameter references */
6353 for (epp
= sinst
->passed
; epp
!= NULL
; epp
= epp
->next
) {
6354 if ((epp
->flags
& P_INDIRECT
) && (epp
->pdata
.refkey
!= NULL
)) {
6355 if (!strcmp(epp
->pdata
.refkey
, ops
->key
)) {
6356 if (instances
++ == 0) {
6357 fprintf(ps
, "<<"); /* begin PostScript dictionary */
6358 loccount
= stcount
+ 2;
6360 dostcount(ps
, &loccount
, strlen(validref
+ 3));
6361 fprintf(ps
, "/%s ", validref
);
6362 dostcount(ps
, &loccount
, strlen(epp
->key
+ 1));
6363 validkey
= create_valid_psname(epp
->key
, TRUE
);
6364 fprintf(ps
, "%s ", validkey
);
6369 if (epp
== NULL
) { /* No indirection */
6370 Boolean nondefault
= TRUE
;
6371 char *deflt_expr
= NULL
;
6373 /* For instance values that are expression results, ignore if */
6374 /* the instance value is the same as the default value. */
6375 /* Correction 9/08: We can't second-guess expression results, */
6376 /* in particular, this doesn't work for an expression like */
6377 /* "page", where the local and default values will evaluate to */
6378 /* the same result, when clearly each page is intended to have */
6379 /* its own instance value, and "page" for an object is not a */
6380 /* well-defined concept. */
6383 // objops = match_param(sinst->thisobject, ops->key);
6384 // if (objops && (objops->type == XC_EXPR)) {
6387 // deflt_expr = evaluate_expr(sinst->thisobject, objops, NULL);
6388 // switch (ops->type) {
6390 // if (!textcomp(ops->parameter.string, deflt_expr, sinst))
6391 // nondefault = FALSE;
6394 // ps_expr = evaluate_expr(sinst->thisobject, ops, sinst);
6395 // if (!strcmp(ps_expr, deflt_expr)) nondefault = FALSE;
6398 // sscanf(deflt_expr, "%d", &i);
6399 // if (i == ops->parameter.ivalue) nondefault = FALSE;
6402 // sscanf(deflt_expr, "%g", &f);
6403 // if (f == ops->parameter.fvalue) nondefault = FALSE;
6406 // if (deflt_expr) free(deflt_expr);
6407 // if (nondefault == FALSE) {
6408 // if (ps_expr) free(ps_expr);
6413 if (instances
++ == 0) {
6414 fprintf(ps
, "<<"); /* begin PostScript dictionary */
6415 loccount
= stcount
+ 2;
6417 dostcount(ps
, &loccount
, strlen(validref
) + 2);
6418 fprintf(ps
, "/%s ", validref
);
6420 switch (ops
->type
) {
6422 segs
= writelabelsegs(ps
, &loccount
, ops
->parameter
.string
);
6424 /* When writing object parameters, we cannot allow a */
6425 /* NULL value. Instead, print an empty string (). */
6426 dostcount(ps
, &stcount
, 3);
6431 ps_expr
= evaluate_expr(sinst
->thisobject
, ops
, sinst
);
6432 dostcount(ps
, &loccount
, 3 + strlen(ps_expr
));
6438 /* The instance parameter expression may have the */
6439 /* same expression as the object but a different */
6440 /* result if the expression uses another parameter. */
6441 /* Only print the expression itself if it's different */
6442 /* from the object's expression. */
6444 objops
= match_param(sinst
->thisobject
, ops
->key
);
6445 if (objops
&& strcmp(ops
->parameter
.expr
, objops
->parameter
.expr
)) {
6446 dostcount(ps
, &loccount
, 3 + strlen(ops
->parameter
.expr
));
6448 fputs(ops
->parameter
.expr
, ps
);
6449 fputs(") pop ", ps
);
6453 if (ops
->which
== P_COLOR
) {
6454 /* Write R, G, B components */
6456 printRGBvalues(_STR
+ 1, ops
->parameter
.ivalue
, "} ");
6459 sprintf(_STR
, "%d ", ops
->parameter
.ivalue
);
6460 dostcount(ps
, &loccount
, strlen(_STR
));
6464 sprintf(_STR
, "%g ", ops
->parameter
.fvalue
);
6465 dostcount(ps
, &loccount
, strlen(_STR
));
6472 if (instances
> 0) {
6473 fprintf(ps
, ">> "); /* end PostScript dictionary */
6479 /*------------------------------------------------------------------*/
6480 /* Macro for point output (calls varpcheck() on x and y components) */
6481 /*------------------------------------------------------------------*/
6483 #define xyvarcheck(z, n, t) \
6484 varpcheck(ps, (z).x, localdata, n, &stcount, *(t), P_POSITION_X); \
6485 varpcheck(ps, (z).y, localdata, n, &stcount, *(t), P_POSITION_Y)
6487 #define xypathcheck(z, n, t, p) \
6488 varpathcheck(ps, (z).x, localdata, n, &stcount, t, TOPATH(p), P_POSITION_X); \
6489 varpathcheck(ps, (z).y, localdata, n, &stcount, t, TOPATH(p), P_POSITION_Y)
6491 /*--------------------------------------------------------------*/
6492 /* Main routine for writing the contents of a single object to */
6493 /* output file "ps". */
6494 /*--------------------------------------------------------------*/
6496 void printOneObject(FILE *ps
, objectptr localdata
, int ccolor
)
6498 int i
, curcolor
= ccolor
;
6499 genericptr
*savegen
, *pgen
;
6506 Boolean has_parameter
;
6507 char *fptr
, *validname
;
6509 /* first, get a total count of all objects and give warning if large */
6512 if ((is_page(localdata
) == -1) && (localdata
->parts
> 255)) {
6513 Wprintf("Warning: \"%s\" may exceed printer's PS limit for definitions",
6517 for (savegen
= localdata
->plist
; savegen
< localdata
->plist
+
6518 localdata
->parts
; savegen
++) {
6520 /* Check if this color is parameterized */
6524 for (epp
= (*savegen
)->passed
; epp
!= NULL
; epp
= epp
->next
) {
6525 ops
= match_param(localdata
, epp
->key
);
6526 if (ops
!= NULL
&& (ops
->which
== P_COLOR
)) {
6527 /* Ensure that the next element forces a color change */
6528 curcolor
= ERRORCOLOR
;
6529 sprintf(_STR
, "%s scb\n", epp
->key
);
6535 /* Enforce the rule that clipmasks must always be DEFAULTCOLOR */
6537 switch(ELEMENTTYPE(*savegen
)) {
6538 case POLYGON
: case SPLINE
: case ARC
: case PATH
:
6539 if (TOPOLY(savegen
)->style
& CLIPMASK
)
6540 (*savegen
)->color
= DEFAULTCOLOR
;
6544 /* change current color if different */
6546 if ((epp
== NULL
) && ((*savegen
)->color
!= curcolor
)) {
6547 if ((curcolor
= (*savegen
)->color
) == DEFAULTCOLOR
)
6548 fprintf(ps
, "sce\n");
6550 if (printRGBvalues(_STR
, (*savegen
)->color
, "scb\n") < 0) {
6551 fprintf(ps
, "sce\n");
6552 curcolor
= DEFAULTCOLOR
;
6560 switch(ELEMENTTYPE(*savegen
)) {
6563 varcheck(ps
, TOPOLY(savegen
)->style
, localdata
, &stcount
,
6565 varfcheck(ps
, TOPOLY(savegen
)->width
, localdata
, &stcount
,
6566 *savegen
, P_LINEWIDTH
);
6567 for (savept
= TOPOLY(savegen
)->points
; savept
< TOPOLY(savegen
)->
6568 points
+ TOPOLY(savegen
)->number
; savept
++) {
6569 varpcheck(ps
, savept
->x
, localdata
,
6570 savept
- TOPOLY(savegen
)->points
, &stcount
, *savegen
,
6572 varpcheck(ps
, savept
->y
, localdata
,
6573 savept
- TOPOLY(savegen
)->points
, &stcount
, *savegen
,
6576 sprintf(_STR
, "%hd ", TOPOLY(savegen
)->number
);
6577 dostcount (ps
, &stcount
, strlen(_STR
));
6579 if (varpcheck(ps
, 0, localdata
, -1, &stcount
, *savegen
,
6581 sprintf(_STR
, "addtox ");
6582 dostcount (ps
, &stcount
, strlen(_STR
));
6585 if (varpcheck(ps
, 0, localdata
, -1, &stcount
, *savegen
,
6587 sprintf(_STR
, "addtoy ");
6588 dostcount (ps
, &stcount
, strlen(_STR
));
6591 sprintf(_STR
, "polygon\n");
6592 dostcount (ps
, &stcount
, strlen(_STR
));
6597 pgen
= TOPATH(savegen
)->plist
;
6598 switch(ELEMENTTYPE(*pgen
)) {
6600 xypathcheck(TOPOLY(pgen
)->points
[0], 0, pgen
, savegen
);
6603 xypathcheck(TOSPLINE(pgen
)->ctrl
[0], 0, pgen
, savegen
);
6606 dostcount(ps
, &stcount
, 9);
6607 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6608 TOPATH(savegen
), P_POSITION_X
)) {
6609 sprintf(_STR
, "addtox1 ");
6610 dostcount (ps
, &stcount
, strlen(_STR
));
6613 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6614 TOPATH(savegen
), P_POSITION_Y
)) {
6615 sprintf(_STR
, "addtoy1 ");
6616 dostcount (ps
, &stcount
, strlen(_STR
));
6619 fprintf(ps
, "beginpath\n");
6620 for (pgen
= TOPATH(savegen
)->plist
; pgen
< TOPATH(savegen
)->plist
6621 + TOPATH(savegen
)->parts
; pgen
++) {
6622 switch(ELEMENTTYPE(*pgen
)) {
6624 for (savept
= TOPOLY(pgen
)->points
+ TOPOLY(pgen
)->number
6625 - 1; savept
> TOPOLY(pgen
)->points
; savept
--) {
6626 xypathcheck(*savept
, savept
- TOPOLY(pgen
)->points
, pgen
,
6629 sprintf(_STR
, "%hd ", TOPOLY(pgen
)->number
- 1);
6630 dostcount (ps
, &stcount
, strlen(_STR
));
6632 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6633 TOPATH(savegen
), P_POSITION_X
)) {
6634 sprintf(_STR
, "addtox ");
6635 dostcount (ps
, &stcount
, strlen(_STR
));
6638 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6639 TOPATH(savegen
), P_POSITION_Y
)) {
6640 sprintf(_STR
, "addtoy ");
6641 dostcount (ps
, &stcount
, strlen(_STR
));
6644 sprintf(_STR
, "polyc\n");
6645 dostcount (ps
, &stcount
, strlen(_STR
));
6649 xypathcheck(TOSPLINE(pgen
)->ctrl
[1], 1, pgen
, savegen
);
6650 xypathcheck(TOSPLINE(pgen
)->ctrl
[2], 2, pgen
, savegen
);
6651 xypathcheck(TOSPLINE(pgen
)->ctrl
[3], 3, pgen
, savegen
);
6652 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6653 TOPATH(savegen
), P_POSITION_X
)) {
6654 sprintf(_STR
, "addtox3 ");
6655 dostcount (ps
, &stcount
, strlen(_STR
));
6658 if (varpathcheck(ps
, 0, localdata
, -1, &stcount
, pgen
,
6659 TOPATH(savegen
), P_POSITION_Y
)) {
6660 sprintf(_STR
, "addtoy3 ");
6661 dostcount (ps
, &stcount
, strlen(_STR
));
6664 fprintf(ps
, "curveto\n");
6668 varcheck(ps
, TOPATH(savegen
)->style
, localdata
, &stcount
,
6670 varfcheck(ps
, TOPATH(savegen
)->width
, localdata
, &stcount
,
6671 *savegen
, P_LINEWIDTH
);
6672 fprintf(ps
, "endpath\n");
6676 varcheck(ps
, TOSPLINE(savegen
)->style
, localdata
, &stcount
,
6678 varfcheck(ps
, TOSPLINE(savegen
)->width
, localdata
, &stcount
,
6679 *savegen
, P_LINEWIDTH
);
6680 xyvarcheck(TOSPLINE(savegen
)->ctrl
[1], 1, savegen
);
6681 xyvarcheck(TOSPLINE(savegen
)->ctrl
[2], 2, savegen
);
6682 xyvarcheck(TOSPLINE(savegen
)->ctrl
[3], 3, savegen
);
6683 xyvarcheck(TOSPLINE(savegen
)->ctrl
[0], 0, savegen
);
6684 if (varpcheck(ps
, 0, localdata
, -1, &stcount
, *savegen
,
6686 sprintf(_STR
, "addtox4 ");
6687 dostcount (ps
, &stcount
, strlen(_STR
));
6690 if (varpcheck(ps
, 0, localdata
, -1, &stcount
, *savegen
,
6692 sprintf(_STR
, "addtoy4 ");
6693 dostcount (ps
, &stcount
, strlen(_STR
));
6696 fprintf(ps
, "spline\n");
6700 varcheck(ps
, TOARC(savegen
)->style
, localdata
, &stcount
,
6702 varfcheck(ps
, TOARC(savegen
)->width
, localdata
, &stcount
,
6703 *savegen
, P_LINEWIDTH
);
6704 xyvarcheck(TOARC(savegen
)->position
, 0, savegen
);
6705 varcheck(ps
, abs(TOARC(savegen
)->radius
), localdata
, &stcount
,
6706 *savegen
, P_RADIUS
);
6707 if (abs(TOARC(savegen
)->radius
) == TOARC(savegen
)->yaxis
) {
6708 varfcheck(ps
, TOARC(savegen
)->angle1
, localdata
, &stcount
,
6709 *savegen
, P_ANGLE1
);
6710 varfcheck(ps
, TOARC(savegen
)->angle2
, localdata
, &stcount
,
6711 *savegen
, P_ANGLE2
);
6712 fprintf(ps
, "xcarc\n");
6715 varcheck(ps
, abs(TOARC(savegen
)->yaxis
), localdata
, &stcount
,
6716 *savegen
, P_MINOR_AXIS
);
6717 varfcheck(ps
, TOARC(savegen
)->angle1
, localdata
, &stcount
,
6718 *savegen
, P_ANGLE1
);
6719 varfcheck(ps
, TOARC(savegen
)->angle2
, localdata
, &stcount
,
6720 *savegen
, P_ANGLE2
);
6721 fprintf(ps
, "ellipse\n");
6726 sobj
= TOOBJINST(savegen
);
6727 varfcheck(ps
, sobj
->scale
, localdata
, &stcount
, *savegen
, P_SCALE
);
6728 if (!(sobj
->style
& LINE_INVARIANT
)) fprintf(ps
, "/sv ");
6729 varfcheck(ps
, sobj
->rotation
, localdata
, &stcount
, *savegen
, P_ROTATION
);
6730 xyvarcheck(sobj
->position
, 0, savegen
);
6732 opsubstitute(sobj
->thisobject
, sobj
);
6733 stcount
= printparams(ps
, sobj
, stcount
);
6735 validname
= create_valid_psname(sobj
->thisobject
->name
, FALSE
);
6737 /* Names without technologies get a leading string '::' */
6738 /* (blank technology) */
6740 if (strstr(validname
, "::") == NULL
)
6741 fprintf(ps
, "::%s\n", validname
);
6743 fprintf(ps
, "%s\n", validname
);
6747 sg
= TOGRAPHIC(savegen
);
6748 for (i
= 0; i
< xobjs
.images
; i
++) {
6749 img
= xobjs
.imagelist
+ i
;
6750 if (img
->image
== sg
->source
)
6754 fptr
= strrchr(img
->filename
, '/');
6756 fptr
= img
->filename
;
6759 fprintf(ps
, "/%s ", fptr
);
6760 stcount
+= (2 + strlen(fptr
));
6762 varfcheck(ps
, sg
->scale
, localdata
, &stcount
, *savegen
, P_SCALE
);
6763 varfcheck(ps
, sg
->rotation
, localdata
, &stcount
, *savegen
, P_ROTATION
);
6764 xyvarcheck(sg
->position
, 0, savegen
);
6765 fprintf(ps
, "graphic\n");
6770 /* Don't save temporary labels from schematic capture system */
6771 if (TOLABEL(savegen
)->string
->type
!= FONT_NAME
) break;
6773 /* Check for parameter --- must use "mark" to count # segments */
6774 has_parameter
= hasparameter(TOLABEL(savegen
));
6776 if (has_parameter
) {
6777 fprintf(ps
, "mark ");
6781 segs
= writelabel(ps
, TOLABEL(savegen
)->string
, &stcount
);
6785 sprintf(_STR
, "ctmk ");
6787 sprintf(_STR
, "%hd ", segs
);
6788 dostcount(ps
, &stcount
, strlen(_STR
));
6790 varcheck(ps
, TOLABEL(savegen
)->anchor
, localdata
, &stcount
,
6791 *savegen
, P_ANCHOR
);
6792 varfcheck(ps
, TOLABEL(savegen
)->rotation
, localdata
, &stcount
,
6793 *savegen
, P_ROTATION
);
6794 varfcheck(ps
, TOLABEL(savegen
)->scale
, localdata
, &stcount
,
6796 xyvarcheck(TOLABEL(savegen
)->position
, 0, savegen
);
6798 switch(TOLABEL(savegen
)->pin
) {
6800 strcpy(_STR
, "pinlabel\n"); break;
6802 strcpy(_STR
, "pinglobal\n"); break;
6804 strcpy(_STR
, "infolabel\n"); break;
6806 strcpy(_STR
, "label\n");
6808 dostcount(ps
, &stcount
, strlen(_STR
));
6816 /*----------------------------------------------------------------------*/
6817 /* Recursive routine to print out the library objects used in this */
6818 /* drawing, starting at the bottom of the object hierarchy so that each */
6819 /* object is defined before it is called. A list of objects already */
6820 /* written is maintained so that no object is written twice. */
6822 /* When object "localdata" is not a top-level page, call this routine */
6823 /* with mpage=-1 (simpler than checking whether localdata is a page). */
6824 /*----------------------------------------------------------------------*/
6826 void printobjects(FILE *ps
, objectptr localdata
, objectptr
**wrotelist
,
6827 short *written
, int ccolor
)
6831 /* oparamptr ops; (jdk) */
6833 int curcolor
= ccolor
;
6834 /* int libno; (jdk) */
6836 /* Search among the list of objects already written to the output */
6837 /* If this object has been written previously, then we ignore it. */
6839 for (optr
= *wrotelist
; optr
< *wrotelist
+ *written
; optr
++)
6840 if (*optr
== localdata
)
6843 /* If this page is a schematic, write out the definiton of any symbol */
6844 /* attached to it, because that symbol may not be used anywhere else. */
6846 if (localdata
->symschem
&& (localdata
->schemtype
== PRIMARY
))
6847 printobjects(ps
, localdata
->symschem
, wrotelist
, written
, curcolor
);
6849 /* Search for all object definitions instantiated in this object, */
6850 /* and (recursively) print them to the output. */
6852 for (gptr
= localdata
->plist
; gptr
< localdata
->plist
+ localdata
->parts
; gptr
++)
6853 if (IS_OBJINST(*gptr
))
6854 printobjects(ps
, TOOBJINST(gptr
)->thisobject
, wrotelist
, written
, curcolor
);
6856 /* Update the list of objects already written to the output */
6858 *wrotelist
= (objectptr
*)realloc(*wrotelist
, (*written
+ 1) *
6860 *(*wrotelist
+ *written
) = localdata
;
6863 validname
= create_valid_psname(localdata
->name
, FALSE
);
6864 if (strstr(validname
, "::") == NULL
)
6865 fprintf(ps
, "/::%s {\n", validname
);
6867 fprintf(ps
, "/%s {\n", validname
);
6869 /* No longer writes "bbox" record */
6870 if (localdata
->hidden
== True
) fprintf(ps
, "%% hidden\n");
6872 /* For symbols with schematics, and "trivial" schematics */
6873 if (localdata
->symschem
!= NULL
)
6874 fprintf(ps
, "%% %s is_schematic\n", localdata
->symschem
->name
);
6875 else if (localdata
->schemtype
== TRIVIAL
)
6876 fprintf(ps
, "%% trivial\n");
6877 else if (localdata
->schemtype
== NONETWORK
)
6878 fprintf(ps
, "%% nonetwork\n");
6880 printobjectparams(ps
, localdata
);
6881 fprintf(ps
, "begingate\n");
6883 /* Write all the elements in order */
6885 opsubstitute(localdata
, NULL
);
6886 printOneObject(ps
, localdata
, curcolor
);
6888 /* Write object (gate) trailer */
6890 fprintf(ps
, "endgate\n} def\n\n");
6893 /*--------------------------------------------------------------*/
6894 /* Print a page header followed by everything in the page. */
6895 /* this routine assumes that all objects used by the page have */
6896 /* already been handled and written to the output. */
6898 /* "page" is the page number, counting consecutively from one. */
6899 /* "mpage" is the page number in xcircuit's pagelist structure. */
6900 /*--------------------------------------------------------------*/
6902 void printpageobject(FILE *ps
, objectptr localdata
, short page
, short mpage
)
6904 /* genericptr *gptr; (jdk) */
6905 XPoint origin
, corner
;
6906 objinstptr writepage
;
6908 float psnorm
, psscale
;
6909 float xmargin
, ymargin
;
6910 char *rootptr
= NULL
;
6913 /* Output page header information */
6915 if (xobjs
.pagelist
[mpage
]->filename
)
6916 rootptr
= strrchr(xobjs
.pagelist
[mpage
]->filename
, '/');
6917 if (rootptr
== NULL
)
6918 rootptr
= xobjs
.pagelist
[mpage
]->filename
;
6921 writepage
= xobjs
.pagelist
[mpage
]->pageinst
;
6923 psnorm
= xobjs
.pagelist
[mpage
]->outscale
;
6924 psscale
= getpsscale(psnorm
, mpage
);
6926 /* Determine the margins (offset of drawing from page corner) */
6927 /* If a bounding box has been declared in the drawing, it is */
6928 /* centered on the page. Otherwise, the drawing itself is */
6929 /* centered on the page. If encapsulated, the bounding box */
6930 /* encompasses only the object itself. */
6932 width
= toplevelwidth(writepage
, &origin
.x
);
6933 height
= toplevelheight(writepage
, &origin
.y
);
6935 corner
.x
= origin
.x
+ width
;
6936 corner
.y
= origin
.y
+ height
;
6938 if (xobjs
.pagelist
[mpage
]->pmode
& 1) { /* full page */
6940 if (xobjs
.pagelist
[mpage
]->orient
== 90) {
6941 xmargin
= (xobjs
.pagelist
[mpage
]->pagesize
.x
-
6942 ((float)height
* psscale
)) / 2;
6943 ymargin
= (xobjs
.pagelist
[mpage
]->pagesize
.y
-
6944 ((float)width
* psscale
)) / 2;
6947 xmargin
= (xobjs
.pagelist
[mpage
]->pagesize
.x
-
6948 ((float)width
* psscale
)) / 2;
6949 ymargin
= (xobjs
.pagelist
[mpage
]->pagesize
.y
-
6950 ((float)height
* psscale
)) / 2;
6953 else { /* encapsulated --- should have 1" border so that any */
6954 /* drawing passed directly to a printer will not clip */
6955 xmargin
= xobjs
.pagelist
[mpage
]->margins
.x
;
6956 ymargin
= xobjs
.pagelist
[mpage
]->margins
.y
;
6959 /* If a framebox is declared, then we adjust the page to be */
6960 /* centered on the framebox by translating through the */
6961 /* difference between the object center and the framebox */
6964 if ((framebox
= checkforbbox(localdata
)) != NULL
) {
6965 int i
, fcentx
= 0, fcenty
= 0;
6967 for (i
= 0; i
< framebox
->number
; i
++) {
6968 fcentx
+= framebox
->points
[i
].x
;
6969 fcenty
+= framebox
->points
[i
].y
;
6971 fcentx
/= framebox
->number
;
6972 fcenty
/= framebox
->number
;
6974 xmargin
+= psscale
* (float)(origin
.x
+ (width
>> 1) - fcentx
);
6975 ymargin
+= psscale
* (float)(origin
.y
+ (height
>> 1) - fcenty
);
6978 /* If the page label is just the root name of the file, or has been left */
6979 /* as "Page n" or "Page_n", just do the normal page numbering. Otherwise, */
6980 /* write out the page label explicitly. */
6982 if ((rootptr
== NULL
) || (!strcmp(rootptr
, localdata
->name
))
6983 || (strchr(localdata
->name
, ' ') != NULL
)
6984 || (strstr(localdata
->name
, "Page_") != NULL
))
6985 fprintf (ps
, "%%%%Page: %d %d\n", page
, page
);
6987 fprintf (ps
, "%%%%Page: %s %d\n", localdata
->name
, page
);
6989 if (xobjs
.pagelist
[mpage
]->orient
== 90)
6990 fprintf (ps
, "%%%%PageOrientation: Landscape\n");
6992 fprintf (ps
, "%%%%PageOrientation: Portrait\n");
6994 if (xobjs
.pagelist
[mpage
]->pmode
& 1) { /* full page */
6995 fprintf(ps
, "%%%%PageBoundingBox: 0 0 %d %d\n",
6996 xobjs
.pagelist
[mpage
]->pagesize
.x
,
6997 xobjs
.pagelist
[mpage
]->pagesize
.y
);
7000 /* Encapsulated files do not get a PageBoundingBox line, */
7001 /* unless the bounding box was explicitly drawn. */
7003 else if (framebox
!= NULL
) {
7004 fprintf(ps
, "%%%%PageBoundingBox: %g %g %g %g\n",
7006 xmargin
+ psscale
* (float)(width
),
7007 ymargin
+ psscale
* (float)(height
));
7010 fprintf (ps
, "/pgsave save def bop\n");
7012 /* Top-page definitions */
7013 if (localdata
->params
!= NULL
) {
7014 printobjectparams(ps
, localdata
);
7015 fprintf(ps
, "begin\n");
7018 if (localdata
->symschem
!= NULL
) {
7019 if (is_page(localdata
->symschem
) == -1)
7020 fprintf(ps
, "%% %s is_symbol\n", localdata
->symschem
->name
);
7021 else if (localdata
->schemtype
== SECONDARY
)
7022 fprintf(ps
, "%% %s is_primary\n", localdata
->symschem
->name
);
7024 Wprintf("Something is wrong. . . schematic \"%s\" is connected to"
7025 " schematic \"%s\" but is not declared secondary.\n",
7026 localdata
->name
, localdata
->symschem
->name
);
7029 /* Extend bounding box around schematic pins */
7030 extendschembbox(xobjs
.pagelist
[mpage
]->pageinst
, &origin
, &corner
);
7032 if (xobjs
.pagelist
[mpage
]->drawingscale
.x
!= 1
7033 || xobjs
.pagelist
[mpage
]->drawingscale
.y
!= 1)
7034 fprintf(ps
, "%% %hd:%hd drawingscale\n", xobjs
.pagelist
[mpage
]->drawingscale
.x
,
7035 xobjs
.pagelist
[mpage
]->drawingscale
.y
);
7037 if (xobjs
.pagelist
[mpage
]->gridspace
!= 32
7038 || xobjs
.pagelist
[mpage
]->snapspace
!= 16)
7039 fprintf(ps
, "%% %4.2f %4.2f gridspace\n", xobjs
.pagelist
[mpage
]->gridspace
,
7040 xobjs
.pagelist
[mpage
]->snapspace
);
7042 if (xobjs
.pagelist
[mpage
]->background
.name
!= (char *)NULL
) {
7043 /* float iscale = (xobjs.pagelist[mpage]->coordstyle == CM) ? CMSCALE : INCHSCALE; (jdk) */
7044 if (xobjs
.pagelist
[mpage
]->orient
== 90)
7045 fprintf(ps
, "%5.4f %d %d 90 psinsertion\n", psnorm
,
7046 (int)(ymargin
- xmargin
),
7047 -((int)((float)(corner
.y
- origin
.y
) * psscale
) +
7048 (int)(xmargin
+ ymargin
)));
7050 fprintf(ps
, "%5.4f %d %d 0 psinsertion\n", psnorm
,
7051 (int)(xmargin
/ psscale
) - origin
.x
,
7052 (int)(ymargin
/ psscale
) - origin
.y
);
7053 savebackground(ps
, xobjs
.pagelist
[mpage
]->background
.name
);
7054 fprintf(ps
, "\nend_insert\n");
7057 if (xobjs
.pagelist
[mpage
]->orient
== 90)
7058 fprintf(ps
, "90 rotate %d %d translate\n", (int)(ymargin
- xmargin
),
7059 -((int)((float)(corner
.y
- origin
.y
) * psscale
) +
7060 (int)(xmargin
+ ymargin
)));
7062 fprintf(ps
, "%5.4f ", psnorm
);
7063 switch(xobjs
.pagelist
[mpage
]->coordstyle
) {
7065 fprintf(ps
, "cmscale\n");
7068 fprintf(ps
, "inchscale\n");
7072 /* Final scale and translation */
7073 fprintf(ps
, "%5.4f setlinewidth %d %d translate\n\n",
7074 1.3 * xobjs
.pagelist
[mpage
]->wirewidth
,
7075 (int)(xmargin
/ psscale
) - origin
.x
,
7076 (int)(ymargin
/ psscale
) - origin
.y
);
7078 /* Output all the elements in the page */
7079 printOneObject(ps
, localdata
, DEFAULTCOLOR
);
7082 if (localdata
->params
!= NULL
) fprintf(ps
, "end ");
7083 fprintf(ps
, "pgsave restore showpage\n");
7086 /*--------------------------------------------------------------*/
7087 /* Print objects referenced from a particular page. These get */
7088 /* bundled together at the beginning of the output file under */
7089 /* the DSC "Setup" section, so that the PostScript */
7090 /* interpreter knows that these definitions may be used by any */
7091 /* page. This prevents ghostscript from producing an error */
7092 /* when backing up in a multi-page document. */
7093 /*--------------------------------------------------------------*/
7095 void printrefobjects(FILE *ps
, objectptr localdata
, objectptr
**wrotelist
,
7100 /* If this page is a schematic, write out the definiton of any symbol */
7101 /* attached to it, because that symbol may not be used anywhere else. */
7103 if (localdata
->symschem
&& (localdata
->schemtype
== PRIMARY
))
7104 printobjects(ps
, localdata
->symschem
, wrotelist
, written
, DEFAULTCOLOR
);
7106 /* Search for all object definitions instantiated on the page and */
7107 /* write them to the output. */
7109 for (gptr
= localdata
->plist
; gptr
< localdata
->plist
+ localdata
->parts
; gptr
++)
7110 if (IS_OBJINST(*gptr
))
7111 printobjects(ps
, TOOBJINST(gptr
)->thisobject
, wrotelist
, written
,
7115 /*----------------------------------------------------------------------*/