Continuing to track down the issue with a crash on startup on
[xcircuit.git] / python.c
blobc95d3e126733a928fb5e67c395ff54adeb247cab
1 /*--------------------------------------------------------------*/
2 /* python.c --- Embedded python interpreter for xcircuit */
3 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
4 /*--------------------------------------------------------------*/
5 /* NOTE: These routines work only if python-2.0 is installed. */
6 /* Requires library file libpython2.0.a. Hopefully */
7 /* one day there will be a standard libpython${VERSION}.so */
8 /* so that the whole thing doesn't have to be linked */
9 /* into the xcircuit executable. . . */
10 /* */
11 /* Modeled after demo.c in Python2.0 source Demo/embed */
12 /*--------------------------------------------------------------*/
14 #if defined(HAVE_PYTHON) && !defined(TCL_WRAPPER)
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h> /* for usleep() */
19 #include <string.h>
21 #include <Python.h>
23 #include <X11/Intrinsic.h>
24 #include <X11/StringDefs.h>
25 #include "Xw/Xw.h"
26 #include "Xw/MenuBtn.h"
28 #ifdef HAVE_XPM
29 #include <X11/xpm.h>
30 #include "lib/pixmaps/q.xpm"
31 #endif
33 PyObject *xcmod;
35 /*----------------------------------------------------------------------*/
36 /* Local includes */
37 /*----------------------------------------------------------------------*/
39 #include "xcircuit.h"
40 #include "menudep.h"
41 #include "colordefs.h"
43 /*----------------------------------------------------------------------*/
44 /* Function prototype declarations */
45 /*----------------------------------------------------------------------*/
47 #include "prototypes.h"
49 static PyObject *xc_new(PyObject *, PyObject *);
50 static PyObject *xc_set(PyObject *, PyObject *);
51 static PyObject *xc_override(PyObject *, PyObject *);
52 static PyObject *xc_library(PyObject *, PyObject *);
53 static PyObject *xc_font(PyObject *, PyObject *);
54 static PyObject *xc_color(PyObject *, PyObject *);
55 static PyObject *xc_pause(PyObject *, PyObject *);
56 static PyObject *xc_refresh(PyObject *, PyObject *);
57 static PyObject *xc_bind(PyObject *, PyObject *);
58 static PyObject *xc_unbind(PyObject *, PyObject *);
59 static PyObject *xc_simplepopup(PyObject *, PyObject *);
60 static PyObject *xc_popupprompt(PyObject *, PyObject *);
61 static PyObject *xc_filepopup(PyObject *, PyObject *);
62 static PyObject *xc_newbutton(PyObject *, PyObject *);
63 static PyObject *xc_page(PyObject *, PyObject *);
64 static PyObject *xc_load(PyObject *, PyObject *);
65 static PyObject *xc_pan(PyObject *, PyObject *);
66 static PyObject *xc_zoom(PyObject *, PyObject *);
67 static PyObject *xc_getcursor();
68 static PyObject *xc_getwindow();
69 static PyObject *xc_reset();
70 static PyObject *xc_netlist();
71 #ifdef HAVE_XPM
72 static PyObject *xc_newtool(PyObject *, PyObject *);
73 #endif
75 int string_to_type(const char *);
77 /*----------------------------------------------------------------------*/
78 /* External variable declarations */
79 /*----------------------------------------------------------------------*/
81 extern char _STR2[250], _STR[150];
82 extern fontinfo *fonts;
83 extern short fontcount;
84 extern XCWindowData *areawin;
85 extern Globaldata xobjs;
86 extern short beeper;
87 extern Widget menuwidgets[];
88 extern Display *dpy;
89 extern keybinding *keylist;
90 extern int number_colors;
91 extern colorindex *colorlist;
92 extern ApplicationData appdata;
93 #ifdef HAVE_XPM
94 extern Widget toolbar;
95 #endif
97 /*----------------------------------------------------------------------*/
99 short flags = -1;
101 #define LIBOVERRIDE 1
102 #define LIBLOADED 2
103 #define COLOROVERRIDE 4
104 #define FONTOVERRIDE 8
105 #define KEYOVERRIDE 16
107 /*----------------------------------------------------------------*/
108 /* Similar to "PyRun_SimpleString()" but returns a PyObject value */
109 /* rather than a status word. */
110 /*----------------------------------------------------------------*/
112 PyObject *PyRun_ObjString(char *string)
114 PyObject *m, *d, *v;
115 m = PyImport_AddModule("__main__");
116 if (m == NULL) return NULL;
117 d = PyModule_GetDict(m);
118 v = PyRun_String(string, Py_file_input, d, d);
119 return v;
122 /*--------------------------------------------------------------*/
123 /* Define all of the xcircuit functions available to Python */
124 /* Currently this does the bare minimum of having Python do the */
125 /* argument parsing; ideally, we would like to be doing more */
126 /* fundamental processing here. */
127 /*--------------------------------------------------------------*/
129 /*--------------------------------------------------------------*/
130 /* Extract text from a popup and call the indicated python */
131 /* function. If there is no text, function is called without */
132 /* arguments. */
133 /*--------------------------------------------------------------*/
135 void pypromptvalue(Widget w, char *functionptr)
137 if (strlen(_STR2) == 0)
138 sprintf(_STR, "%s()\n", functionptr);
139 else
140 sprintf(_STR, "%s('%s')\n", functionptr, _STR2);
142 PyRun_SimpleString(_STR);
143 refresh(NULL, NULL, NULL);
146 /*--------------------------------------------------------------*/
147 /* Pop up a prompt, and return the value to the indicated */
148 /* python function. */
149 /*--------------------------------------------------------------*/
151 static PyObject *pypopupprompt(PyObject *self, PyObject *args,
152 const char *dofile, char *displaystr)
154 const char *pfunction = NULL;
155 const char *prompt = NULL;
156 buttonsave *savebutton;
158 if (!PyArg_ParseTuple(args, "ss:popupprompt", &prompt, &pfunction))
159 return PyInt_FromLong(-1L);
162 savebutton = getgeneric(NULL, NULL, (void *)pfunction);
163 popupprompt(areawin->area, (char *)prompt, displaystr,
164 pypromptvalue, savebutton, dofile);
166 return PyInt_FromLong(0L);
169 /*--------------------------------------------------------------*/
170 /* Wrappers for pypopuprompt() */
171 /*--------------------------------------------------------------*/
173 static PyObject *xc_popupprompt(PyObject *self, PyObject *args)
175 return pypopupprompt(self, args, NULL, "");
178 static PyObject *xc_filepopup(PyObject *self, PyObject *args)
180 return pypopupprompt(self, args, "", "");
183 static PyObject *xc_simplepopup(PyObject *self, PyObject *args)
185 _STR2[0] = '\0';
186 return pypopupprompt(self, args, False, NULL);
189 /*--------------------------------------------------------------*/
190 /* Create objects and return a handle to that object in the */
191 /* form of a Python integer Object. */
192 /*--------------------------------------------------------------*/
194 static PyObject *xc_new(PyObject *self, PyObject *args)
196 const char *etype;
197 int type;
199 genericptr *newgen;
200 arcptr *newarc;
201 splineptr *newspline;
202 polyptr *newpoly;
203 labelptr *newlabel;
204 pathptr *newpath;
205 objinstptr *newobjinst;
207 if (!PyArg_ParseTuple(args, "s:newelement", &etype))
208 return NULL;
210 switch(type = string_to_type(etype)) {
211 case ARC:
212 NEW_ARC(newarc, topobject);
213 arcdefaults(*newarc, 0, 0);
214 newgen = (genericptr *)newarc;
215 break;
216 case SPLINE:
217 NEW_SPLINE(newspline, topobject);
218 splinedefaults(*newspline, 0, 0);
219 newgen = (genericptr *)newspline;
220 break;
221 case POLYGON:
222 NEW_POLY(newpoly, topobject);
223 polydefaults(*newpoly, 4, 0, 0);
224 newgen = (genericptr *)newpoly;
225 break;
226 case LABEL:
227 NEW_LABEL(newlabel, topobject);
228 labeldefaults(*newlabel, 0, 0, 0);
229 newgen = (genericptr *)newlabel;
230 break;
231 case PATH:
232 NEW_PATH(newpath, topobject);
233 pathdefaults(*newpath, 0, 0);
234 newgen = (genericptr *)newpath;
235 break;
236 case OBJINST:
237 NEW_OBJINST(newobjinst, topobject);
238 instancedefaults(*newobjinst, NULL, 0, 0);
239 newgen = (genericptr *)newobjinst;
240 break;
241 default:
242 PyErr_SetString(PyExc_TypeError,
243 "newelement() 2nd argument must be a valid element type");
244 return NULL;
246 incr_changes(topobject);
247 invalidate_netlist(topobject);
249 return PyInt_FromLong((long)(*newgen));
252 /*--------------------------------------------------------------*/
253 /* Convert object type to a string */
254 /*--------------------------------------------------------------*/
256 char *type_to_string(int type)
258 char *retstr = NULL;
260 switch(type) {
261 case LABEL:
262 retstr = malloc(6);
263 strcpy(retstr, "Label");
264 break;
265 case POLYGON:
266 retstr = malloc(8);
267 strcpy(retstr, "Polygon");
268 break;
269 case SPLINE:
270 retstr = malloc(12);
271 strcpy(retstr, "Bezier Curve");
272 break;
273 case OBJINST:
274 retstr = malloc(16);
275 strcpy(retstr, "Object Instance");
276 break;
277 case PATH:
278 retstr = malloc(5);
279 strcpy(retstr, "Path");
280 break;
281 case ARC:
282 retstr = malloc(4);
283 strcpy(retstr, "Arc");
284 break;
286 return retstr;
289 /*--------------------------------------------------------------*/
290 /* Convert a string to an element type */
291 /*--------------------------------------------------------------*/
293 int string_to_type(const char *etype)
295 if (!strcmp(etype, "Arc"))
296 return ARC;
297 else if (!strcmp(etype, "Bezier Curve"))
298 return SPLINE;
299 else if (!strcmp(etype, "Polygon"))
300 return POLYGON;
301 else if (!strcmp(etype, "Label"))
302 return LABEL;
303 else if (!strcmp(etype, "Path"))
304 return PATH;
305 else if (!strcmp(etype, "Object Instance"))
306 return OBJINST;
307 else
308 return -1;
311 /*--------------------------------------------------------------*/
312 /* Convert color index to 3-tuple and vice versa */
313 /* We assume that this color exists in the color table. */
314 /*--------------------------------------------------------------*/
316 PyObject *PyIndexToRGB(int cidx)
318 int i;
319 PyObject *RGBTuple;
321 if (cidx < 0) { /* Handle "default color" */
322 return PyString_FromString("Default");
325 for (i = 0; i < number_colors; i++) {
326 if (cidx == colorlist[i].color.pixel) {
327 RGBTuple = PyTuple_New(3);
328 PyTuple_SetItem(RGBTuple, 0,
329 PyInt_FromLong((long)(colorlist[i].color.red / 256)));
330 PyTuple_SetItem(RGBTuple, 1,
331 PyInt_FromLong((long)(colorlist[i].color.green / 256)));
332 PyTuple_SetItem(RGBTuple, 2,
333 PyInt_FromLong((long)(colorlist[i].color.blue / 256)));
334 return RGBTuple;
337 PyErr_SetString(PyExc_TypeError, "invalid or unknown color index");
338 return NULL;
341 /*--------------------------------------------------------------*/
342 /* Convert color 3-tuple (RGB) or name to a color index */
343 /*--------------------------------------------------------------*/
345 int PyRGBToIndex(PyObject *cobj)
347 PyObject *tobj;
348 int ccolor, r, g, b;
350 if (PyTuple_Check(cobj) && PyTuple_Size(cobj) == 3) { /* RGB 3-tuple */
351 tobj = PyTuple_GetItem(cobj, 0);
352 if (PyFloat_Check(tobj)) {
353 r = (int)(65535 * (float)PyFloat_AsDouble(tobj));
354 g = (int)(65535 * (float)PyFloat_AsDouble(PyTuple_GetItem(cobj, 1)));
355 b = (int)(65535 * (float)PyFloat_AsDouble(PyTuple_GetItem(cobj, 2)));
357 else if (PyInt_Check(tobj)) {
358 r = (int)(256 * PyInt_AsLong(tobj));
359 g = (int)(256 * PyInt_AsLong(PyTuple_GetItem(cobj, 1)));
360 b = (int)(256 * PyInt_AsLong(PyTuple_GetItem(cobj, 2)));
362 else {
363 PyErr_SetString(PyExc_TypeError, "tuple components must be integer or float");
364 return -1;
366 ccolor = rgb_alloccolor(r, g, b);
368 else if (PyString_Check(cobj)) { /* color name */
369 ccolor = xc_alloccolor(PyString_AsString(cobj));
371 else if (PyInt_Check(cobj)) { /* index (for backward compatibility) */
372 ccolor = (int)PyInt_AsLong(cobj);
374 else {
375 PyErr_SetString(PyExc_TypeError, "argument must be a string or 3-tuple");
376 return -1;
379 addnewcolorentry(ccolor);
380 return ccolor;
383 /*--------------------------------------------------------------*/
384 /* Convert a Python list to a stringpart* */
385 /*--------------------------------------------------------------*/
387 stringpart *PySetStringParts(PyObject *dval)
389 PyObject *lstr, *litem, *ditem, *sitem, *titem;
390 int i, j, llen;
391 stringpart *strptr, *newpart;
392 char *string;
394 /* If we pass a string, create a list of size 1 to hold the string. */
395 /* Otherwise, the argument must be a list. */
397 if (PyList_Check(dval)) {
398 lstr = dval;
400 else {
401 if (PyString_Check(dval)) {
402 lstr = PyList_New(1);
403 PyList_SetItem(lstr, 0, dval);
405 else {
406 PyErr_SetString(PyExc_TypeError, "argument must be a string or a list");
407 return NULL;
411 strptr = NULL;
412 llen = PyList_Size(lstr);
413 for (i = 0; i < llen; i++) {
414 newpart = makesegment(&strptr, NULL);
415 newpart->nextpart = NULL;
417 litem = PyList_GetItem(lstr, i);
418 if (PyDict_Check(litem)) {
419 if ((ditem = PyDict_GetItemString(litem, "Parameter")) != NULL) {
420 newpart->type = PARAM_START;
421 newpart->data.string = strdup(PyString_AsString(ditem));
423 else if ((ditem = PyDict_GetItemString(litem, "Font")) != NULL) {
424 newpart->type = FONT_NAME;
425 string = PyString_AsString(ditem);
426 for (j = 0; j < fontcount; j++)
427 if (!strcmp(fonts[j].psname, string)) break;
428 if (j == fontcount) loadfontfile(string);
429 newpart->data.font = j;
431 else if ((ditem = PyDict_GetItemString(litem, "Kern")) != NULL) {
432 newpart->type = KERN;
433 newpart->data.kern[0] = (int)PyInt_AsLong(PyTuple_GetItem(ditem, 0));
434 newpart->data.kern[1] = (int)PyInt_AsLong(PyTuple_GetItem(ditem, 1));
436 else if ((ditem = PyDict_GetItemString(litem, "Color")) != NULL) {
437 newpart->type = FONT_COLOR;
438 newpart->data.color = PyRGBToIndex(ditem);
440 else if ((ditem = PyDict_GetItemString(litem, "Font Scale")) != NULL) {
441 newpart->type = FONT_SCALE;
442 newpart->data.scale = (float)PyFloat_AsDouble(ditem);
444 else if ((ditem = PyDict_GetItemString(litem, "Text")) != NULL) {
445 newpart->type = TEXT_STRING;
446 newpart->data.string = strdup(PyString_AsString(ditem));
449 else if (PyString_Check(litem)) {
450 string = PyString_AsString(litem);
451 if (!strcmp(string, "End Parameter")) {
452 newpart->type = PARAM_END;
453 newpart->data.string = (u_char *)NULL;
455 else if (!strcmp(string, "Tab Stop")) {
456 newpart->type = TABSTOP;
458 else if (!strcmp(string, "Tab Forward")) {
459 newpart->type = TABFORWARD;
461 else if (!strcmp(string, "Tab Backward")) {
462 newpart->type = TABBACKWARD;
464 else if (!strcmp(string, "Return")) {
465 newpart->type = RETURN;
467 else if (!strcmp(string, "Subscript")) {
468 newpart->type = SUBSCRIPT;
470 else if (!strcmp(string, "Superscript")) {
471 newpart->type = SUPERSCRIPT;
473 else if (!strcmp(string, "Normalscript")) {
474 newpart->type = NORMALSCRIPT;
476 else if (!strcmp(string, "Underline")) {
477 newpart->type = UNDERLINE;
479 else if (!strcmp(string, "Overline")) {
480 newpart->type = OVERLINE;
482 else if (!strcmp(string, "No Line")) {
483 newpart->type = NOLINE;
485 else if (!strcmp(string, "Half Space")) {
486 newpart->type = HALFSPACE;
488 else if (!strcmp(string, "Quarter Space")) {
489 newpart->type = QTRSPACE;
491 else {
492 newpart->type = TEXT_STRING;
493 newpart->data.string = strdup(string);
497 return strptr;
500 /*--------------------------------------------------------------*/
501 /* Convert a stringpart* to a Python list */
502 /*--------------------------------------------------------------*/
504 PyObject *PyGetStringParts(stringpart *thisstring)
506 PyObject *lstr, *sdict, *stup;
507 int i, llen;
508 stringpart *strptr;
510 llen = stringparts(thisstring);
511 lstr = PyList_New(llen);
512 for (strptr = thisstring, i = 0; strptr != NULL;
513 strptr = strptr->nextpart, i++) {
514 switch(strptr->type) {
515 case TEXT_STRING:
516 sdict = PyDict_New();
517 PyDict_SetItem(sdict, PyString_FromString("Text"),
518 PyString_FromString(strptr->data.string));
519 PyList_SetItem(lstr, i, sdict);
520 break;
521 case PARAM_START:
522 sdict = PyDict_New();
523 PyDict_SetItem(sdict, PyString_FromString("Parameter"),
524 PyString_FromString(strptr->data.string));
525 PyList_SetItem(lstr, i, sdict);
526 break;
527 case PARAM_END:
528 PyList_SetItem(lstr, i, PyString_FromString("End Parameter"));
529 break;
530 case FONT_NAME:
531 sdict = PyDict_New();
532 PyDict_SetItem(sdict, PyString_FromString("Font"),
533 PyString_FromString(fonts[strptr->data.font].psname));
534 PyList_SetItem(lstr, i, sdict);
535 break;
536 case FONT_SCALE:
537 sdict = PyDict_New();
538 PyDict_SetItem(sdict, PyString_FromString("Font Scale"),
539 PyFloat_FromDouble((double)strptr->data.scale));
540 PyList_SetItem(lstr, i, sdict);
541 break;
542 case KERN:
543 sdict = PyDict_New();
544 stup = PyTuple_New(2);
545 PyTuple_SetItem(stup, 0, PyInt_FromLong((long)strptr->data.kern[0]));
546 PyTuple_SetItem(stup, 1, PyInt_FromLong((long)strptr->data.kern[1]));
547 PyDict_SetItem(sdict, PyString_FromString("Kern"), stup);
548 PyList_SetItem(lstr, i, sdict);
549 break;
550 case FONT_COLOR:
551 stup = PyIndexToRGB(strptr->data.color);
552 if (stup != NULL) {
553 sdict = PyDict_New();
554 PyDict_SetItem(sdict, PyString_FromString("Color"), stup);
555 PyList_SetItem(lstr, i, sdict);
557 break;
558 case TABSTOP:
559 PyList_SetItem(lstr, i, PyString_FromString("Tab Stop"));
560 break;
561 case TABFORWARD:
562 PyList_SetItem(lstr, i, PyString_FromString("Tab Forward"));
563 break;
564 case TABBACKWARD:
565 PyList_SetItem(lstr, i, PyString_FromString("Tab Backward"));
566 break;
567 case RETURN:
568 PyList_SetItem(lstr, i, PyString_FromString("Return"));
569 break;
570 case SUBSCRIPT:
571 PyList_SetItem(lstr, i, PyString_FromString("Subscript"));
572 break;
573 case SUPERSCRIPT:
574 PyList_SetItem(lstr, i, PyString_FromString("Superscript"));
575 break;
576 case NORMALSCRIPT:
577 PyList_SetItem(lstr, i, PyString_FromString("Normalscript"));
578 break;
579 case UNDERLINE:
580 PyList_SetItem(lstr, i, PyString_FromString("Underline"));
581 break;
582 case OVERLINE:
583 PyList_SetItem(lstr, i, PyString_FromString("Overline"));
584 break;
585 case NOLINE:
586 PyList_SetItem(lstr, i, PyString_FromString("No Line"));
587 break;
588 case HALFSPACE:
589 PyList_SetItem(lstr, i, PyString_FromString("Half Space"));
590 break;
591 case QTRSPACE:
592 PyList_SetItem(lstr, i, PyString_FromString("Quarter Space"));
593 break;
596 return lstr;
599 /*--------------------------------------------------------------*/
600 /* Check if the handle (integer) is an existing element */
601 /*--------------------------------------------------------------*/
603 genericptr *CheckHandle(PyObject *ehandle)
605 genericptr *gelem;
606 int i, j;
607 long int eaddr;
608 objectptr thisobj;
609 Library *thislib;
611 eaddr = PyInt_AsLong(ehandle);
612 for (gelem = topobject->plist; gelem < topobject->plist +
613 topobject->parts; gelem++)
614 if ((long int)(*gelem) == eaddr) goto exists;
616 /* Okay, it isn't in topobject. Try all other pages. */
618 for (i = 0; i < xobjs.pages; i++) {
619 if (xobjs.pagelist[i]->pageinst == NULL) continue;
620 thisobj = xobjs.pagelist[i]->pageinst->thisobject;
621 for (gelem = thisobj->plist; gelem < thisobj->plist + thisobj->parts; gelem++)
622 if ((long int)(*gelem) == eaddr) goto exists;
625 /* Still not found? Maybe in a library */
627 for (i = 0; i < xobjs.numlibs; i++) {
628 thislib = xobjs.userlibs + i;
629 for (j = 0; j < thislib->number; j++) {
630 thisobj = thislib->library[j];
631 for (gelem = thisobj->plist; gelem < thisobj->plist + thisobj->parts; gelem++)
632 if ((long int)(*gelem) == eaddr) goto exists;
636 /* Either in the delete list (where we don't want to go) or */
637 /* is an invalid number. */
638 return NULL;
640 exists:
641 return gelem;
644 /*--------------------------------------------------------------*/
645 /* Check if the handle (integer) is an existing page */
646 /*--------------------------------------------------------------*/
648 objectptr CheckPageHandle(PyObject *ehandle)
650 int pageno;
651 long int eaddr;
653 eaddr = PyInt_AsLong(ehandle);
654 pageno = is_page((objectptr)eaddr);
655 if (pageno < 0) return NULL;
656 return (objectptr)eaddr;
659 /*--------------------------------------------------------------*/
660 /* Form a 2-tuple from a pair of integers. */
661 /*--------------------------------------------------------------*/
663 static PyObject *make_pair(XPoint *thispoint)
665 PyObject *dtup;
667 dtup = PyTuple_New(2);
669 PyTuple_SetItem(dtup, 0,
670 PyInt_FromLong((long)(thispoint->x)));
671 PyTuple_SetItem(dtup, 1,
672 PyInt_FromLong((long)(thispoint->y)));
673 return dtup;
676 /*--------------------------------------------------------------*/
677 /* Get the properties of a page (returned as a dictionary) */
678 /*--------------------------------------------------------------*/
680 static PyObject *xc_getpage(PyObject *self, PyObject *args)
682 Pagedata *thispage;
683 PyObject *rdict, *dlist;
684 int pageno = areawin->page + 1, i;
686 if (!PyArg_ParseTuple(args, "|d:getpage", &pageno))
687 return NULL;
689 if (pageno <= 0 || pageno > xobjs.pages) return NULL;
690 else pageno--;
692 thispage = xobjs.pagelist[pageno];
694 rdict = PyDict_New();
696 PyDict_SetItem(rdict, PyString_FromString("filename"),
697 PyString_FromString(thispage->filename));
699 PyDict_SetItem(rdict, PyString_FromString("page label"),
700 PyString_FromString(thispage->pageinst->thisobject->name));
702 PyDict_SetItem(rdict, PyString_FromString("output scale"),
703 PyFloat_FromDouble((double)thispage->outscale));
705 /* To be done: change these from internal units to "natural" units */
707 PyDict_SetItem(rdict, PyString_FromString("grid space"),
708 PyFloat_FromDouble((double)thispage->gridspace));
710 PyDict_SetItem(rdict, PyString_FromString("snap space"),
711 PyFloat_FromDouble((double)thispage->snapspace));
713 PyDict_SetItem(rdict, PyString_FromString("orientation"),
714 PyInt_FromLong((long)thispage->orient));
716 PyDict_SetItem(rdict, PyString_FromString("output mode"),
717 PyInt_FromLong((long)thispage->pmode));
719 PyDict_SetItem(rdict, PyString_FromString("coordinate style"),
720 PyInt_FromLong((long)thispage->coordstyle));
722 PyDict_SetItem(rdict, PyString_FromString("page size"),
723 make_pair(&(thispage->pagesize)));
725 PyDict_SetItem(rdict, PyString_FromString("drawing scale"),
726 make_pair(&(thispage->drawingscale)));
728 return rdict;
731 /*--------------------------------------------------------------*/
732 /* Get the properties of a library (returned as a dictionary) */
733 /*--------------------------------------------------------------*/
735 static PyObject *xc_getlibrary(PyObject *self, PyObject *args)
737 PyObject *rdict, *dlist;
738 const char *lname = NULL;
739 objectptr *curlib = NULL, thisobj;
740 char *errptr;
741 int i, lpage;
742 int curobjs;
744 if (!PyArg_ParseTuple(args, "s:getlibrary", &lname))
745 return NULL;
747 lpage = strtol(lname, &errptr, 10);
748 if (*lname != '\0' && *errptr == '\0' && lpage <= xobjs.numlibs &&
749 lpage > 0) { /* numerical */
750 curlib = xobjs.userlibs[lpage - 1].library;
752 else {
753 for (lpage = 0; lpage < xobjs.numlibs; lpage++) {
754 if (!strcmp(lname, xobjs.libtop[lpage + LIBRARY]->thisobject->name)) {
755 curlib = xobjs.userlibs[lpage - 1].library;
756 break;
758 else if (!strncmp(xobjs.libtop[lpage + LIBRARY]->thisobject->name,
759 "Library: ", 9)) {
760 if (!strcmp(lname, xobjs.libtop[lpage + LIBRARY]->thisobject->name + 9)) {
761 curlib = xobjs.userlibs[lpage - 1].library;
762 break;
768 if (curlib == NULL) {
769 PyErr_SetString(PyExc_TypeError,
770 "getlibrary() 2nd argument must be a library page or name");
771 return NULL;
773 curobjs = xobjs.userlibs[lpage - 1].number;
775 /* Argument to getlibrary() can be a library name or library page # */
777 rdict = PyDict_New();
779 PyDict_SetItem(rdict, PyString_FromString("name"),
780 PyString_FromString(xobjs.libtop[lpage + LIBRARY]->thisobject->name));
782 if (curobjs > 0) {
783 dlist = PyList_New(curobjs);
784 for (i = 0; i < curobjs; i++) {
785 thisobj = *(curlib + i);
786 PyList_SetItem(dlist, i, PyString_FromString(thisobj->name));
788 PyDict_SetItem(rdict, PyString_FromString("objects"), dlist);
790 return rdict;
793 /*--------------------------------------------------------------*/
794 /* Get the properties of an object (returned as a dictionary) */
795 /*--------------------------------------------------------------*/
797 static PyObject *xc_getobject(PyObject *self, PyObject *args)
799 objectptr thisobj = NULL, *libobj;
800 oparamptr ops;
801 PyObject *rdict, *dlist, *tpos;
802 const char *oname;
803 int i, j, k, nparam;
805 if (!PyArg_ParseTuple(args, "s:getobject", &oname))
806 return NULL;
808 for (k = 0; k < xobjs.numlibs; k++) {
809 for (j = 0; j < xobjs.userlibs[k].number; j++) {
810 libobj = xobjs.userlibs[k].library + j;
811 if (!strcmp(oname, (*libobj)->name)) {
812 thisobj = *libobj;
813 break;
816 if (thisobj != NULL) break;
819 if (thisobj == NULL) { /* try the page objects */
820 for (k = 0; k < xobjs.pages; k++) {
821 if (xobjs.pagelist[k]->pageinst != NULL)
822 if (!strcmp(oname, xobjs.pagelist[k]->pageinst->thisobject->name))
823 break;
825 if (k == xobjs.pages) return NULL; /* not found */
828 /* return all the object's properties as a dictionary */
830 rdict = PyDict_New();
832 PyDict_SetItem(rdict, PyString_FromString("name"),
833 PyString_FromString(thisobj->name));
834 PyDict_SetItem(rdict, PyString_FromString("width"),
835 PyInt_FromLong((long)(thisobj->bbox.width)));
836 PyDict_SetItem(rdict, PyString_FromString("height"),
837 PyInt_FromLong((long)(thisobj->bbox.height)));
838 PyDict_SetItem(rdict, PyString_FromString("viewscale"),
839 PyFloat_FromDouble((double)(thisobj->viewscale)));
841 tpos = PyTuple_New(2);
842 PyTuple_SetItem(tpos, 0, PyInt_FromLong((long)thisobj->bbox.lowerleft.x));
843 PyTuple_SetItem(tpos, 1, PyInt_FromLong((long)thisobj->bbox.lowerleft.y));
844 PyDict_SetItem(rdict, PyString_FromString("boundingbox"), tpos);
846 tpos = PyTuple_New(2);
847 PyTuple_SetItem(tpos, 0, PyInt_FromLong((long)thisobj->pcorner.x));
848 PyTuple_SetItem(tpos, 1, PyInt_FromLong((long)thisobj->pcorner.y));
849 PyDict_SetItem(rdict, PyString_FromString("viewcorner"), tpos);
851 dlist = PyList_New(thisobj->parts);
852 for (i = 0; i < thisobj->parts; i++)
853 PyList_SetItem(dlist, i, PyInt_FromLong((long)(*(thisobj->plist + i))));
854 PyDict_SetItem(rdict, PyString_FromString("parts"), dlist);
856 nparam = get_num_params(thisobj);
857 if (nparam > 0) {
858 dlist = PyList_New(nparam);
859 i = 0;
860 for (ops = thisobj->params; ops != NULL; ops = ops->next) {
861 i++;
862 if (ops->type == XC_INT)
863 PyList_SetItem(dlist, i, PyInt_FromLong((long)(ops->parameter.ivalue)));
864 else if (ops->type == XC_FLOAT)
865 PyList_SetItem(dlist, i,
866 PyFloat_FromDouble((double)(ops->parameter.fvalue)));
867 else if (ops->type == XC_STRING)
868 PyList_SetItem(dlist, i, PyGetStringParts(ops->parameter.string));
870 PyDict_SetItem(rdict, PyString_FromString("parameters"), dlist);
872 return rdict;
875 /*--------------------------------------------------------------*/
876 /* Reset the current page */
877 /*--------------------------------------------------------------*/
879 static PyObject *xc_reset()
881 resetbutton(NULL, (pointertype)0, NULL);
882 return PyInt_FromLong(0L);
885 /*--------------------------------------------------------------*/
886 /* Get a netlist */
887 /*--------------------------------------------------------------*/
889 extern PyObject *pyglobals(objectptr);
890 extern PyObject *pytoplevel(objectptr);
892 static PyObject *xc_netlist()
894 PyObject *rdict = NULL;
896 if (updatenets(areawin->topinstance, FALSE) <= 0) {
897 PyErr_SetString(PyExc_TypeError, "Error: Check circuit for infinite recursion.");
898 return NULL;
901 rdict = PyDict_New();
902 PyDict_SetItem(rdict, PyString_FromString("globals"), pyglobals(topobject));
903 PyDict_SetItem(rdict, PyString_FromString("circuit"), pytoplevel(topobject));
904 return rdict;
907 /*--------------------------------------------------------------*/
908 /* Load the specified file */
909 /*--------------------------------------------------------------*/
911 static PyObject *xc_load(PyObject *self, PyObject *args)
913 char *filename;
914 int pageno = 0, savepage;
916 if (!PyArg_ParseTuple(args, "s|i:load", &filename, &pageno))
917 return PyInt_FromLong((long)areawin->page);
919 if (--pageno < 0) pageno = areawin->page;
920 savepage = areawin->page;
922 strcpy(_STR2, filename);
923 if (savepage != pageno) newpage(pageno);
924 startloadfile(-1);
925 if (savepage != pageno) newpage(savepage);
927 return PyString_FromString(filename);
930 /*--------------------------------------------------------------*/
931 /* Go to the specified page */
932 /*--------------------------------------------------------------*/
934 static PyObject *xc_page(PyObject *self, PyObject *args)
936 int pageno;
938 if (!PyArg_ParseTuple(args, "i:page", &pageno))
939 return PyInt_FromLong((long)areawin->page);
941 newpage(pageno - 1);
942 return PyInt_FromLong((long)pageno);
945 /*--------------------------------------------------------------*/
946 /* Zoom */
947 /*--------------------------------------------------------------*/
949 static PyObject *xc_zoom(PyObject *self, PyObject *args)
951 float factor, save;
953 if (!PyArg_ParseTuple(args, "f:zoom", &factor))
954 return NULL;
956 if (factor <= 0) {
957 PyErr_SetString(PyExc_TypeError, "Argument must be positive.");
958 return NULL;
961 save = areawin->zoomfactor;
963 if (factor < 1.0) {
964 areawin->zoomfactor = 1.0 / factor;
965 zoomout(0, 0); /* Needs to be fixed---give x, y for drag fn */
967 else {
968 areawin->zoomfactor = factor;
969 zoomin(0, 0); /* Needs to be fixed---see above */
972 areawin->zoomfactor = save;
973 return PyFloat_FromDouble((double)topobject->viewscale);
976 /*--------------------------------------------------------------*/
977 /* Pan */
978 /*--------------------------------------------------------------*/
980 static PyObject *xc_pan(PyObject *self, PyObject *args)
982 PyObject *cornerpos, *xobj, *yobj = NULL, *pval;
983 int x, y;
984 XPoint upoint, wpoint;
986 if (!PyArg_ParseTuple(args, "O|O:pan", &xobj, &yobj))
987 return NULL;
989 if (yobj == NULL) {
990 if (PyTuple_Check(xobj) && PyTuple_Size(xobj) == 2) {
991 if ((pval = PyTuple_GetItem(xobj, 0)) != NULL)
992 upoint.x = PyInt_AsLong(pval);
993 if ((pval = PyTuple_GetItem(xobj, 1)) != NULL)
994 upoint.y = PyInt_AsLong(pval);
996 else return NULL;
998 else {
999 upoint.x = PyInt_AsLong(xobj);
1000 upoint.y = PyInt_AsLong(yobj);
1003 user_to_window(upoint, &wpoint);
1004 panbutton((u_int)5, wpoint.x, wpoint.y, 0.33); /* fixed fraction */
1006 cornerpos = PyTuple_New(2);
1007 PyTuple_SetItem(cornerpos, 0, PyInt_FromLong((long)areawin->pcorner.x));
1008 PyTuple_SetItem(cornerpos, 1, PyInt_FromLong((long)areawin->pcorner.y));
1010 return cornerpos;
1013 /*--------------------------------------------------------------*/
1014 /* Get the window size */
1015 /*--------------------------------------------------------------*/
1017 static PyObject *xc_getwindow()
1019 PyObject *windowsize;
1021 windowsize = PyTuple_New(2);
1022 PyTuple_SetItem(windowsize, 0, PyInt_FromLong((long)areawin->width));
1023 PyTuple_SetItem(windowsize, 1, PyInt_FromLong((long)areawin->height));
1025 return windowsize;
1028 /*--------------------------------------------------------------*/
1029 /* Get the cursor position */
1030 /*--------------------------------------------------------------*/
1032 static PyObject *xc_getcursor()
1034 PyObject *cursorpos;
1035 XPoint newpos;
1037 newpos = UGetCursorPos();
1038 u2u_snap(&newpos);
1040 cursorpos = PyTuple_New(2);
1041 PyTuple_SetItem(cursorpos, 0, PyInt_FromLong((long)newpos.x));
1042 PyTuple_SetItem(cursorpos, 1, PyInt_FromLong((long)newpos.y));
1044 return cursorpos;
1047 /*--------------------------------------------------------------*/
1048 /* Get the properties of an element (returned as a dictionary) */
1049 /*--------------------------------------------------------------*/
1051 static PyObject *xc_getattr(PyObject *self, PyObject *args)
1053 genericptr *gelem;
1054 PyObject *ehandle, *rdict, *dlist, *lstr, *sdict, *stup;
1055 int i, llen;
1056 char *tstr;
1057 stringpart *strptr;
1060 if (!PyArg_ParseTuple(args, "O:getattr", &ehandle))
1061 return NULL;
1063 /* Check to make sure that handle exists! */
1064 if ((gelem = CheckHandle(ehandle)) == NULL) {
1065 PyErr_SetString(PyExc_TypeError,
1066 "Argument must be a valid handle to an element.");
1067 return NULL;
1070 /* return the element's properties as a dictionary */
1072 rdict = PyDict_New();
1073 tstr = type_to_string((*gelem)->type);
1074 if (tstr == NULL) {
1075 PyErr_SetString(PyExc_TypeError,
1076 "Element type is unknown.");
1077 return NULL;
1079 PyDict_SetItem(rdict, PyString_FromString("type"),
1080 PyString_FromString(tstr));
1081 free(tstr);
1082 lstr = PyIndexToRGB((*gelem)->color);
1083 if (lstr != NULL)
1084 PyDict_SetItem(rdict, PyString_FromString("color"), lstr);
1086 switch(ELEMENTTYPE(*gelem)) {
1087 case LABEL:
1088 PyDict_SetItem(rdict, PyString_FromString("position"),
1089 make_pair(&(TOLABEL(gelem)->position)));
1090 PyDict_SetItem(rdict, PyString_FromString("rotation"),
1091 PyFloat_FromDouble((double)TOLABEL(gelem)->rotation));
1092 PyDict_SetItem(rdict, PyString_FromString("scale"),
1093 PyFloat_FromDouble((double)TOLABEL(gelem)->scale));
1094 PyDict_SetItem(rdict, PyString_FromString("anchor"),
1095 PyInt_FromLong((long)TOLABEL(gelem)->anchor));
1096 PyDict_SetItem(rdict, PyString_FromString("pin"),
1097 PyInt_FromLong((long)TOLABEL(gelem)->pin));
1098 lstr = PyGetStringParts(TOLABEL(gelem)->string);
1100 PyDict_SetItem(rdict, PyString_FromString("string"), lstr);
1101 break;
1102 case POLYGON:
1103 PyDict_SetItem(rdict, PyString_FromString("style"),
1104 PyInt_FromLong((long)TOPOLY(gelem)->style));
1105 PyDict_SetItem(rdict, PyString_FromString("linewidth"),
1106 PyFloat_FromDouble((double)TOPOLY(gelem)->width));
1107 dlist = PyList_New(TOPOLY(gelem)->number);
1108 for (i = 0; i < TOPOLY(gelem)->number; i++) {
1109 PyList_SetItem(dlist, i, make_pair(&(TOPOLY(gelem)->points[i])));
1111 PyDict_SetItem(rdict, PyString_FromString("points"), dlist);
1112 break;
1113 case ARC:
1114 PyDict_SetItem(rdict, PyString_FromString("style"),
1115 PyInt_FromLong((long)TOARC(gelem)->style));
1116 PyDict_SetItem(rdict, PyString_FromString("linewidth"),
1117 PyFloat_FromDouble((double)TOARC(gelem)->width));
1118 PyDict_SetItem(rdict, PyString_FromString("radius"),
1119 PyInt_FromLong((long)TOARC(gelem)->radius));
1120 PyDict_SetItem(rdict, PyString_FromString("minor axis"),
1121 PyInt_FromLong((long)TOARC(gelem)->yaxis));
1122 PyDict_SetItem(rdict, PyString_FromString("start angle"),
1123 PyFloat_FromDouble((double)TOARC(gelem)->angle1));
1124 PyDict_SetItem(rdict, PyString_FromString("end angle"),
1125 PyFloat_FromDouble((double)TOARC(gelem)->angle2));
1126 PyDict_SetItem(rdict, PyString_FromString("position"),
1127 make_pair(&(TOARC(gelem)->position)));
1128 break;
1129 case SPLINE:
1130 PyDict_SetItem(rdict, PyString_FromString("style"),
1131 PyInt_FromLong((long)TOSPLINE(gelem)->style));
1132 PyDict_SetItem(rdict, PyString_FromString("linewidth"),
1133 PyFloat_FromDouble((double)TOSPLINE(gelem)->width));
1134 dlist = PyList_New(4);
1135 for (i = 0; i < 4; i++) {
1136 PyList_SetItem(dlist, i, make_pair(&(TOSPLINE(gelem)->ctrl[i])));
1138 PyDict_SetItem(rdict, PyString_FromString("control points"), dlist);
1139 break;
1140 case PATH:
1141 PyDict_SetItem(rdict, PyString_FromString("style"),
1142 PyInt_FromLong((long)TOPATH(gelem)->style));
1143 PyDict_SetItem(rdict, PyString_FromString("linewidth"),
1144 PyFloat_FromDouble((double)TOPATH(gelem)->width));
1145 dlist = PyList_New(TOPATH(gelem)->parts);
1146 for (i = 0; i < TOPATH(gelem)->parts; i++) {
1147 PyList_SetItem(dlist, i,
1148 PyInt_FromLong((long)(*(TOPATH(gelem)->plist + i))));
1150 PyDict_SetItem(rdict, PyString_FromString("parts"), dlist);
1151 break;
1152 case OBJINST:
1153 PyDict_SetItem(rdict, PyString_FromString("position"),
1154 make_pair(&(TOOBJINST(gelem)->position)));
1155 PyDict_SetItem(rdict, PyString_FromString("rotation"),
1156 PyFloat_FromDouble((double)TOOBJINST(gelem)->rotation));
1157 PyDict_SetItem(rdict, PyString_FromString("scale"),
1158 PyFloat_FromDouble((double)TOOBJINST(gelem)->scale));
1159 PyDict_SetItem(rdict, PyString_FromString("name"),
1160 PyString_FromString(TOOBJINST(gelem)->thisobject->name));
1161 break;
1163 return rdict;
1166 /*--------------------------------------------------------------*/
1167 /* Set properties of an element (supplied as a dictionary) */
1168 /*--------------------------------------------------------------*/
1170 static PyObject *xc_setattr(PyObject *self, PyObject *args)
1172 genericptr *gelem;
1173 PyObject *ehandle, *attrdict, *dval, *pval, *qval;
1174 int i;
1176 if (!PyArg_ParseTuple(args, "OO:setattr", &ehandle, &attrdict))
1177 return NULL;
1179 /* Check to make sure that handle exists! */
1180 if ((gelem = CheckHandle(ehandle)) == NULL) return NULL;
1182 /* Is the argument a dictionary? */
1183 if (!PyDict_Check(attrdict)) {
1184 PyErr_SetString(PyExc_TypeError,
1185 "setatrr() 2nd argument must be a dictionary");
1186 return NULL;
1189 /* First, make sure no attempt is made to change the object type. */
1191 if ((dval = PyDict_GetItemString(attrdict, "type")) != NULL) {
1192 int dtype = string_to_type(PyString_AsString(dval));
1193 if (dtype < 0) return NULL;
1194 if (dtype != ELEMENTTYPE(*gelem)) {
1195 PyErr_SetString(PyExc_TypeError,
1196 "Attempt to change the type of an object.");
1197 return NULL;
1201 /* Next, look for dictionary strings containing values which apply */
1202 /* to a number of different elements (position, color, etc.) */
1204 if ((dval = PyDict_GetItemString(attrdict, "color")) != NULL) {
1205 (*gelem)->color = (short)PyRGBToIndex(dval);
1208 if ((dval = PyDict_GetItemString(attrdict, "position")) != NULL) {
1209 if (PyTuple_Check(dval) && PyTuple_Size(dval) == 2) {
1210 if ((pval = PyTuple_GetItem(dval, 0)) != NULL) {
1211 short xpos = (short)PyInt_AsLong(pval);
1212 switch(ELEMENTTYPE(*gelem)) {
1213 case ARC:
1214 TOARC(gelem)->position.x = xpos;
1215 calcarc(TOARC(gelem));
1216 break;
1217 case LABEL:
1218 TOLABEL(gelem)->position.x = xpos;
1219 break;
1220 case OBJINST:
1221 TOOBJINST(gelem)->position.x = xpos;
1222 break;
1223 default:
1224 PyErr_SetString(PyExc_TypeError,
1225 "attempt to set position on Spline, Polygon, or Path");
1229 if ((pval = PyTuple_GetItem(dval, 1)) != NULL) {
1230 short ypos = (short)PyInt_AsLong(pval);
1231 switch(ELEMENTTYPE(*gelem)) {
1232 case ARC:
1233 TOARC(gelem)->position.y = ypos;
1234 calcarc(TOARC(gelem));
1235 break;
1236 case LABEL:
1237 TOLABEL(gelem)->position.y = ypos;
1238 break;
1239 case OBJINST:
1240 TOOBJINST(gelem)->position.y = ypos;
1241 break;
1242 default:
1243 PyErr_SetString(PyExc_TypeError,
1244 "attempt to set position on Spline, Polygon, or Path");
1248 else {
1249 PyErr_SetString(PyExc_TypeError,
1250 "position must be a tuple containing two integer values");
1254 if ((dval = PyDict_GetItemString(attrdict, "style")) != NULL) {
1255 short dstyle = (short)PyInt_AsLong(dval);
1256 switch(ELEMENTTYPE(*gelem)) {
1257 case POLYGON:
1258 TOPOLY(gelem)->style = dstyle;
1259 break;
1260 case PATH:
1261 TOPATH(gelem)->style = dstyle;
1262 break;
1263 case ARC:
1264 TOARC(gelem)->style = dstyle;
1265 break;
1266 case SPLINE:
1267 TOSPLINE(gelem)->style = dstyle;
1268 break;
1269 default:
1270 PyErr_SetString(PyExc_TypeError,
1271 "attempt to set style on an Object Instance or Label");
1275 if ((dval = PyDict_GetItemString(attrdict, "linewidth")) != NULL) {
1276 float dwidth = (float)PyFloat_AsDouble(dval);
1277 switch(ELEMENTTYPE(*gelem)) {
1278 case POLYGON:
1279 TOPOLY(gelem)->width = dwidth;
1280 break;
1281 case PATH:
1282 TOPATH(gelem)->width = dwidth;
1283 break;
1284 case ARC:
1285 TOARC(gelem)->width = dwidth;
1286 break;
1287 case SPLINE:
1288 TOSPLINE(gelem)->width = dwidth;
1289 break;
1290 default:
1291 PyErr_SetString(PyExc_TypeError,
1292 "attempt to set linewidth on an Object Instance or Label");
1296 if ((dval = PyDict_GetItemString(attrdict, "scale")) != NULL) {
1297 float dscale = (float)PyFloat_AsDouble(dval);
1298 switch(ELEMENTTYPE(*gelem)) {
1299 case LABEL:
1300 TOLABEL(gelem)->scale = dscale;
1301 break;
1302 case OBJINST:
1303 TOOBJINST(gelem)->scale = dscale;
1304 break;
1305 default:
1306 PyErr_SetString(PyExc_TypeError,
1307 "attempt to set scale on something not a Label or Object Instance");
1311 if ((dval = PyDict_GetItemString(attrdict, "rotation")) != NULL) {
1312 float drot = (float)PyFloat_AsDouble(dval);
1313 switch(ELEMENTTYPE(*gelem)) {
1314 case LABEL:
1315 TOLABEL(gelem)->rotation = drot;
1316 break;
1317 case OBJINST:
1318 TOOBJINST(gelem)->rotation = drot;
1319 break;
1320 default:
1321 PyErr_SetString(PyExc_TypeError,
1322 "attempt to set rotation on something not a Label or Object Instance");
1326 /* Dictionary entries specific to certain xcircuit types */
1328 switch(ELEMENTTYPE(*gelem)) {
1329 case LABEL:
1330 if ((dval = PyDict_GetItemString(attrdict, "anchor")) != NULL) {
1331 TOLABEL(gelem)->anchor = PyInt_AsLong(dval);
1333 if ((dval = PyDict_GetItemString(attrdict, "string")) != NULL) {
1334 freelabel(TOLABEL(gelem)->string);
1335 TOLABEL(gelem)->string = PySetStringParts(dval);
1337 if ((dval = PyDict_GetItemString(attrdict, "pin")) != NULL) {
1338 TOLABEL(gelem)->pin = PyInt_AsLong(dval);
1340 break;
1341 case ARC:
1342 if ((dval = PyDict_GetItemString(attrdict, "start angle")) != NULL) {
1343 TOARC(gelem)->angle1 = (float)PyFloat_AsDouble(dval);
1345 if ((dval = PyDict_GetItemString(attrdict, "end angle")) != NULL) {
1346 TOARC(gelem)->angle2 = (float)PyFloat_AsDouble(dval);
1348 if ((dval = PyDict_GetItemString(attrdict, "radius")) != NULL) {
1349 TOARC(gelem)->radius = PyInt_AsLong(dval);
1351 if ((dval = PyDict_GetItemString(attrdict, "minor axis")) != NULL) {
1352 TOARC(gelem)->yaxis = PyInt_AsLong(dval);
1354 break;
1355 case SPLINE:
1356 if ((dval = PyDict_GetItemString(attrdict, "control points")) != NULL) {
1357 if (PyList_Check(dval) && PyList_Size(dval) == 4) {
1358 for (i = 0; i < 4; i++) {
1359 pval = PyList_GetItem(dval, i);
1360 if (PyTuple_Check(pval) && PyTuple_Size(pval) == 2) {
1361 qval = PyTuple_GetItem(pval, 0);
1362 TOSPLINE(gelem)->ctrl[i].x = (short)PyInt_AsLong(qval);
1363 qval = PyTuple_GetItem(pval, 1);
1364 TOSPLINE(gelem)->ctrl[i].y = (short)PyInt_AsLong(qval);
1366 else {
1367 PyErr_SetString(PyExc_TypeError,
1368 "must have a tuple of 2 values per point");
1369 break;
1373 else {
1374 PyErr_SetString(PyExc_TypeError,
1375 "must have 4 control points in a list");
1376 break;
1379 break;
1380 case POLYGON:
1381 if ((dval = PyDict_GetItemString(attrdict, "points")) != NULL) {
1382 if (PyList_Check(dval)) {
1383 int number = PyList_Size(dval);
1384 if (TOPOLY(gelem)->number != number) {
1385 TOPOLY(gelem)->points = (pointlist)realloc(
1386 TOPOLY(gelem)->points, number * sizeof(XPoint));
1387 TOPOLY(gelem)->number = number;
1389 for (i = 0; i < number; i++) {
1390 pval = PyList_GetItem(dval, i);
1391 if (PyTuple_Check(pval) && PyTuple_Size(pval) == 2) {
1392 qval = PyTuple_GetItem(pval, 0);
1393 TOPOLY(gelem)->points[i].x = (short)PyInt_AsLong(qval);
1394 qval = PyTuple_GetItem(pval, 1);
1395 TOPOLY(gelem)->points[i].y = (short)PyInt_AsLong(qval);
1397 else {
1398 PyErr_SetString(PyExc_TypeError,
1399 "must have a tuple of 2 values per point");
1400 break;
1404 else {
1405 PyErr_SetString(PyExc_TypeError,
1406 "points must be in a list of tuples");
1407 break;
1410 break;
1413 calcbbox(areawin->topinstance);
1414 return PyInt_FromLong((long)(*gelem));
1416 /*--------------------------------------------------------------*/
1417 /* Set various options through the "set" command. */
1418 /* "set <option> on|off" supercedes "enable|disable <option>" */
1419 /*--------------------------------------------------------------*/
1421 static PyObject *xc_set(PyObject *self, PyObject *args)
1423 const char *sarg1, *sarg2;
1424 int i;
1425 Boolean a = True;
1426 short cpage = areawin->page;
1428 if (!PyArg_ParseTuple(args, "ss:set", &sarg1, &sarg2))
1429 return NULL;
1431 if (!strcmp(sarg2, "On") || !strcmp(sarg2, "on") || !strcmp(sarg2, "True")
1432 || !strcmp(sarg2, "true"))
1433 a = False; /* has to be backwards; toggle() inverts the value! */
1435 if (!strcmp(sarg1, "font")) {
1436 for (i = 0; i < fontcount; i++)
1437 if (!strcmp(fonts[i].psname, sarg2)) break;
1439 if (i == fontcount)
1440 loadfontfile((char *)sarg2);
1442 /* loadfontfile() may load multiple fonts, so we have to check again */
1443 /* to see which one matches. */
1445 for (i = 0; i < fontcount; i++) {
1446 if (!strcmp(fonts[i].psname, sarg2)) {
1447 areawin->psfont = i;
1448 setdefaultfontmarks();
1449 break;
1453 else if (!strcmp(sarg1, "fontscale")) {
1454 sscanf(sarg2, "%f", &areawin->textscale);
1456 else if (!strcmp(sarg1, "axis") || !strcmp(sarg1, "axes")) {
1457 areawin->axeson = a;
1458 toggle(GridAxesButton, (pointertype)&areawin->axeson, NULL);
1460 else if (!strcmp(sarg1, "grid")) {
1461 areawin->gridon = a;
1462 toggle(GridGridButton, (pointertype)&areawin->gridon, NULL);
1464 else if (!strcmp(sarg1, "snap") || !strcmp(sarg1, "snap-to")) {
1465 areawin->snapto = a;
1466 toggle(SnaptoSnaptoButton, (pointertype)&areawin->snapto, NULL);
1468 else if (!strcmp(sarg1, "gridspace")) {
1469 sscanf(sarg2, "%f", &xobjs.pagelist[cpage]->gridspace);
1471 else if (!strcmp(sarg1, "snapspace")) {
1472 sscanf(sarg2, "%f", &xobjs.pagelist[cpage]->snapspace);
1474 else if (!strcmp(sarg1, "pagestyle")) {
1475 if (!strcmp(sarg2, "encapsulated") || !strcmp(sarg2, "eps"))
1476 xobjs.pagelist[cpage]->pmode = 0;
1477 else
1478 xobjs.pagelist[cpage]->pmode = 1;
1480 else if (!strcmp(sarg1, "boxedit")) {
1481 if (!strcmp(sarg2, "rhomboid-x")) boxedit(NULL, RHOMBOIDX, NULL);
1482 else if (!strcmp(sarg2, "rhomboid-y")) boxedit(NULL, RHOMBOIDY, NULL);
1483 else if (!strcmp(sarg2, "rhomboid-a")) boxedit(NULL, RHOMBOIDA, NULL);
1484 else if (!strcmp(sarg2, "manhattan")) boxedit(NULL, MANHATTAN, NULL);
1485 else if (!strcmp(sarg2, "normal")) boxedit(NULL, NORMAL, NULL);
1487 else if (!strcmp(sarg1, "linewidth")) {
1488 sscanf(sarg2, "%f", &areawin->linewidth);
1490 else if (!strcmp(sarg1, "colorscheme")) {
1491 if (!strcmp(sarg2, "inverse"))
1492 areawin->invert = False;
1493 inversecolor(NULL, (pointertype)&areawin->invert, NULL);
1495 else if (!strcmp(sarg1, "coordstyle")) {
1496 if (!strcmp(sarg2, "cm") || !strcmp(sarg2, "centimeters")) {
1497 xobjs.pagelist[cpage]->coordstyle = CM;
1498 xobjs.pagelist[cpage]->pagesize.x = 595; /* A4 size */
1499 xobjs.pagelist[cpage]->pagesize.y = 842;
1500 togglegrid((u_short)xobjs.pagelist[cpage]->coordstyle);
1503 else if (!strcmp(sarg1, "orient")) { /* "orient" or "orientation" */
1504 if (!strcmp(sarg2, "landscape"))
1505 xobjs.pagelist[cpage]->orient = 90; /* Landscape */
1506 else
1507 xobjs.pagelist[cpage]->orient = 0; /* Portrait */
1510 else if (!strcmp(sarg1, "xschema") || !strcmp(sarg1, "schema")) {
1511 /* Do nothing---retained for backward compatibility only */
1513 #ifdef HAVE_XPM
1514 else if (!strcmp(sarg1, "toolbar")) {
1515 areawin->toolbar_on = a;
1516 dotoolbar(OptionsDisableToolbarButton, NULL, NULL);
1518 #endif
1520 return PyString_FromString(sarg2);
1523 /*--------------------------------------------------------------*/
1525 static PyObject *xc_override(PyObject *self, PyObject *args)
1527 const char *sarg1;
1529 if (!PyArg_ParseTuple(args, "s:override", &sarg1))
1530 return NULL;
1532 if (!strcmp(sarg1, "library") || !strcmp(sarg1, "libraries"))
1533 flags |= LIBOVERRIDE;
1534 else if (!strcmp(sarg1, "color") || !strcmp(sarg1, "colors"))
1535 flags |= COLOROVERRIDE;
1536 else if (!strcmp(sarg1, "font") || !strcmp(sarg1, "fonts"))
1537 flags |= FONTOVERRIDE;
1538 if (!strcmp(sarg1, "key") || !strcmp(sarg1, "keybindings"))
1539 flags |= KEYOVERRIDE;
1541 return PyInt_FromLong(0L);
1544 /*--------------------------------------------------------------*/
1546 static PyObject *xc_library(PyObject *self, PyObject *args)
1548 const char *libname;
1549 int libnum = 1;
1551 if (!PyArg_ParseTuple(args, "s|i:library", &libname, &libnum))
1552 return NULL;
1554 /* if loading of default libraries is not overridden, load them first */
1556 if (!(flags & (LIBOVERRIDE | LIBLOADED))) {
1557 defaultscript();
1558 flags |= LIBLOADED; /* Pass through a Python variable? */
1561 if (libnum >= xobjs.numlibs || libnum < 0)
1562 libnum = createlibrary(FALSE);
1563 else
1564 libnum += LIBRARY - 1;
1566 strcpy(_STR, libname);
1567 loadlibrary(libnum);
1568 return PyInt_FromLong((long)libnum);
1571 /*--------------------------------------------------------------*/
1573 static PyObject *xc_font(PyObject *self, PyObject *args)
1575 const char *fontname;
1577 if (!PyArg_ParseTuple(args, "s:font", &fontname))
1578 return NULL;
1580 if (!(flags & FONTOVERRIDE)) {
1581 loadfontfile("Helvetica");
1582 flags |= FONTOVERRIDE;
1584 loadfontfile((char *)fontname);
1585 return PyString_FromString(fontname);
1588 /*--------------------------------------------------------------*/
1590 static PyObject *xc_color(PyObject *self, PyObject *args)
1592 PyObject *pcolor;
1593 int cidx;
1595 if (!PyArg_ParseTuple(args, "O:color", &pcolor))
1596 return NULL;
1598 cidx = PyRGBToIndex(pcolor);
1599 return PyIndexToRGB(cidx);
1602 /*--------------------------------------------------------------*/
1604 static PyObject *xc_bind(PyObject *self, PyObject *args)
1606 const char *keyname = NULL;
1607 const char *function = NULL;
1608 PyObject *retobj;
1609 int keywstate;
1611 if (!PyArg_ParseTuple(args, "|ss:bind", &keyname, &function))
1612 return NULL;
1614 /* If we're in .xcircuitrc and we're not overriding the key */
1615 /* bindings, then the first binding function should precipitate */
1616 /* calling the defaults, then specify the bindings as overridden */
1617 if (!(flags & KEYOVERRIDE)) {
1618 default_keybindings();
1619 flags |= KEYOVERRIDE;
1622 /* No arguments? Return a dictionary of bound pairs */
1623 if (!keyname) {
1624 PyObject *key, *value;
1625 char *keyname, *funcname;
1626 keybinding *ksearch;
1628 retobj = PyDict_New();
1629 for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding) {
1630 keyname = key_to_string(ksearch->keywstate);
1631 if (ksearch->value >= 0) {
1632 funcname = malloc(strlen(func_to_string(ksearch->function)) + 5);
1633 sprintf(funcname, "%s %d", func_to_string(ksearch->function),
1634 ksearch->value);
1636 else
1637 funcname = func_to_string(ksearch->function);
1638 key = PyString_FromString(keyname);
1639 value = PyString_FromString(funcname);
1640 PyDict_SetItem(retobj, key, value);
1641 free(keyname);
1642 if (ksearch->value >= 0) free(funcname);
1645 /* One argument? Argument is a key or a function */
1646 else if (!function) {
1647 char *binding;
1648 int func = -1;
1649 keywstate = string_to_key(keyname);
1650 if (keywstate == 0) { /* first argument (keyname) is function? */
1651 keywstate = -1;
1652 func = string_to_func(keyname, NULL);
1654 if (keywstate == -1)
1655 binding = function_binding_to_string(0, func);
1656 else
1657 binding = key_binding_to_string(0, keywstate);
1658 retobj = PyString_FromString(binding);
1659 free(binding);
1661 else {
1662 if (add_keybinding(0, keyname, function) < 0) {
1663 /* Function may be a Python function, not a C function */
1664 keywstate = string_to_key(keyname);
1665 sprintf(_STR2, "keydict[%d] = %s\n", keywstate, function);
1666 PyRun_SimpleString(_STR2);
1668 retobj = PyString_FromString(keyname);
1670 return retobj;
1673 /*--------------------------------------------------------------*/
1675 static PyObject *xc_unbind(PyObject *self, PyObject *args)
1677 const char *keyname = NULL;
1678 const char *function = NULL;
1680 if (!PyArg_ParseTuple(args, "ss:unbind", &keyname, &function))
1681 return NULL;
1683 /* If we're in .xcircuitrc and we're not overriding the key */
1684 /* bindings, then the first binding function should precipitate */
1685 /* calling the defaults, then specify the bindings as overridden */
1686 if (!(flags & KEYOVERRIDE)) {
1687 default_keybindings();
1688 flags |= KEYOVERRIDE;
1691 remove_keybinding(areawin->area, keyname, function);
1692 return PyString_FromString(keyname);
1695 /*--------------------------------------------------------------*/
1696 /* active delay */
1697 /*--------------------------------------------------------------*/
1699 static PyObject *xc_pause(PyObject *self, PyObject *args)
1701 float delay;
1703 if (!PyArg_ParseTuple(args, "f:pause", &delay))
1704 return NULL;
1706 usleep((int)(1e6 * delay));
1707 return PyInt_FromLong((int)(1e6 * delay));
1710 /*--------------------------------------------------------------*/
1711 /* active refresh */
1712 /*--------------------------------------------------------------*/
1714 static PyObject *xc_refresh(PyObject *self, PyObject *args)
1716 XEvent event;
1718 if (!PyArg_ParseTuple(args, ":refresh"))
1719 return NULL;
1721 refresh(NULL, NULL, NULL);
1723 while (XCheckWindowEvent(dpy, areawin->window, ~NoEventMask, &event))
1724 XtDispatchEvent(&event);
1726 return PyInt_FromLong(0L);
1729 /*--------------------------------------------------------------*/
1730 /* Callback procedure for Python-generated buttons */
1731 /*--------------------------------------------------------------*/
1733 int pybutton(Widget w, caddr_t clientdata, caddr_t calldata)
1735 int status;
1737 sprintf(_STR2, "buttondict[%ld]()\n", (long int)w);
1738 status = PyRun_SimpleString(_STR2);
1739 refresh(NULL, NULL, NULL);
1740 return status;
1743 /*--------------------------------------------------------------*/
1744 /* Add a new button to the specified (by name) cascade menu */
1745 /*--------------------------------------------------------------*/
1747 static PyObject *xc_newbutton(PyObject *self, PyObject *args)
1749 const char *pname = NULL;
1750 const char *newbname = NULL;
1751 const char *pfunction = NULL;
1752 int status;
1753 Arg wargs[1];
1754 int i, n = 0;
1755 Widget newbutton, cascade, tbutton;
1757 if (!PyArg_ParseTuple(args, "sss:newbutton", &pname, &newbname, &pfunction))
1758 return NULL;
1760 for (i = 0; i < MaxMenuWidgets; i++) {
1761 tbutton = menuwidgets[i];
1762 cascade = XtParent(tbutton);
1763 if (!strcmp(XtName(cascade), pname)) break;
1765 if (i == MaxMenuWidgets) {
1766 Wprintf("Cannot find specified menu.");
1767 return NULL;
1770 XtnSetArg(XtNfont, appdata.xcfont);
1771 newbutton = XtCreateWidget(newbname, XwmenubuttonWidgetClass,
1772 cascade, wargs, n);
1774 XtAddCallback (newbutton, XtNselect, (XtCallbackProc)pybutton, newbutton);
1775 XtManageChild(newbutton);
1777 sprintf(_STR2, "buttondict[%ld] = %s\n", (long int)newbutton, pfunction);
1778 status = PyRun_SimpleString(_STR2);
1779 return PyInt_FromLong((long)status);
1782 #ifdef HAVE_XPM
1784 /*--------------------------------------------------------------*/
1785 /* Callback procedure for Python-generated toolbar tool */
1786 /*--------------------------------------------------------------*/
1788 int pytool(Widget w, caddr_t clientdata, caddr_t calldata)
1790 int status;
1792 sprintf(_STR2, "tooldict[%ld]()\n", (long int)w);
1793 status = PyRun_SimpleString(_STR2);
1794 refresh(NULL, NULL, NULL);
1795 return status;
1798 /*--------------------------------------------------------------*/
1799 /* Add a new tool to the toolbar */
1800 /*--------------------------------------------------------------*/
1802 static PyObject *xc_newtool(PyObject *self, PyObject *args)
1804 const char *thint = NULL;
1805 const char *pixfile = NULL;
1806 const char *newtname = NULL;
1807 const char *pfunction = NULL;
1808 int status;
1809 Arg wargs[8];
1810 int i, n = 0;
1811 Widget newtool, cascade, tbutton;
1812 XImage *iret;
1813 XpmAttributes attr;
1815 attr.valuemask = XpmSize | XpmCloseness;
1816 attr.closeness = 65536;
1818 if (!PyArg_ParseTuple(args, "sss|s:newtool", &newtname, &pfunction, &pixfile,
1819 &thint))
1820 return NULL;
1822 if (XpmReadFileToImage(dpy, (char *)pixfile, &iret, NULL, &attr) < 0) {
1823 Wprintf("Cannot find or open pixmap file \'%s\'", pixfile);
1824 XpmCreateImageFromData(dpy, q_xpm, &iret, NULL, &attr);
1827 XtnSetArg(XtNlabelType, XwIMAGE);
1828 XtnSetArg(XtNlabelImage, iret);
1829 XtnSetArg(XtNwidth, attr.width + 4);
1830 XtnSetArg(XtNheight, attr.height + 4);
1831 XtnSetArg(XtNborderWidth, TBBORDER);
1832 XtnSetArg(XtNnoPad, True);
1833 if (thint != NULL) {
1834 XtnSetArg(XtNhint, thint);
1835 XtnSetArg(XtNhintProc, Wprintf);
1837 newtool = XtCreateWidget(newtname, XwmenubuttonWidgetClass, toolbar, wargs, n);
1839 XtAddCallback (newtool, XtNselect, (XtCallbackProc)pybutton, newtool);
1840 XtManageChild(newtool);
1842 sprintf(_STR2, "tooldict[%ld] = %s\n", (long int)newtool, pfunction);
1843 status = PyRun_SimpleString(_STR2);
1844 return PyInt_FromLong((long)status);
1847 /*------------------------------------------------------------------*/
1848 /* Return a list of the widgets in tooldict */
1849 /* (memory for list is allocated here and must be free'd elsewhere) */
1850 /*------------------------------------------------------------------*/
1852 Widget *pytoolbuttons(int *num_tools)
1854 Widget *ptools;
1855 PyObject *rval;
1856 int i;
1858 if (xcmod == NULL) {
1859 *num_tools = 0;
1860 return NULL;
1862 rval = PyRun_ObjString("len(tooldict)");
1863 if (!rval) {
1864 PyErr_Clear();
1865 return NULL;
1867 *num_tools = (int)PyInt_AsLong(rval);
1868 Py_DECREF(rval);
1869 /* fprintf(stderr, "num_tools = %d\n", *num_tools); */
1871 if (*num_tools <= 0) return NULL;
1873 ptools = (Widget *)malloc(*num_tools * sizeof(Widget));
1875 for (i = 0; i < *num_tools; i++) {
1876 sprintf(_STR2, "tooldict[%d]", i);
1877 rval = PyRun_ObjString(_STR2);
1878 if (!rval) {
1879 PyErr_Clear();
1880 return NULL;
1882 ptools[i] = (Widget)PyInt_AsLong(rval);
1883 Py_DECREF(rval);
1885 return ptools;
1888 #endif
1890 /*----------------------------------------------------------------*/
1891 /* Execute a python command from the key-function pair dictionary */
1892 /*----------------------------------------------------------------*/
1894 int python_key_command(int keystate)
1896 PyObject *rval;
1897 int status;
1898 sprintf(_STR2, "keydict[%d]\n", keystate);
1899 rval = PyRun_ObjString(_STR2);
1900 if (!rval) {
1901 PyErr_Clear();
1902 return -1;
1904 Py_DECREF(rval);
1906 sprintf(_STR2, "keydict[%d]()\n", keystate);
1907 PyRun_SimpleString(_STR2);
1908 refresh(NULL, NULL, NULL);
1909 return 0;
1912 /*--------------------------------------------------------------*/
1913 /* Declaration of the xcircuit Python functions */
1914 /*--------------------------------------------------------------*/
1916 static PyMethodDef xc_methods[] = {
1917 {"set", xc_set, 1},
1918 {"override", xc_override, 1},
1919 {"library", xc_library, 1},
1920 {"font", xc_font, 1},
1921 {"color", xc_color, 1},
1922 {"newelement", xc_new, 1},
1923 {"getpage", xc_getpage, 1},
1924 {"getlibrary", xc_getlibrary, 1},
1925 {"getobject", xc_getobject, 1},
1926 {"getattr", xc_getattr, 1},
1927 {"setattr", xc_setattr, 1},
1928 {"refresh", xc_refresh, 1},
1929 {"pause", xc_pause, 1},
1930 {"bind", xc_bind, 1},
1931 {"unbind", xc_unbind, 1},
1932 {"getcursor", xc_getcursor, 1},
1933 {"getwindow", xc_getwindow, 1},
1934 {"zoom", xc_zoom, 1},
1935 {"pan", xc_pan, 1},
1936 {"popupprompt", xc_popupprompt, 1},
1937 {"filepopup", xc_filepopup, 1},
1938 {"simplepopup", xc_simplepopup, 1},
1939 {"newbutton", xc_newbutton, 1},
1940 {"reset", xc_reset, 1},
1941 {"page", xc_page, 1},
1942 {"load", xc_load, 1},
1943 #ifdef HAVE_XPM
1944 {"newtool", xc_newtool, 1},
1945 #endif
1946 {"netlist", xc_netlist, 1},
1947 {NULL, NULL} /* sentinel */
1950 /*--------------------------------------------------------------*/
1951 /* Initialize Python interpreter and load all xcircuit methods */
1952 /*--------------------------------------------------------------*/
1953 void init_interpreter()
1955 Py_SetProgramName("XCircuit");
1956 Py_Initialize();
1957 PyImport_AddModule("xc");
1958 xcmod = Py_InitModule("xc", xc_methods);
1959 PyRun_SimpleString("from xc import *\n");
1960 PyRun_SimpleString("keydict = {}\n"); /* initialize key/function pairs */
1961 PyRun_SimpleString("buttondict = {}\n"); /* initialize button/function pairs */
1962 PyRun_SimpleString("tooldict = {}\n"); /* initialize tool/function pairs */
1963 sprintf(_STR, "xc_version = %s\n", PROG_VERSION);
1964 PyRun_SimpleString(_STR);
1967 /*--------------------------------------------------------------*/
1968 /* Exit the Python interpreter */
1969 /*--------------------------------------------------------------*/
1971 void exit_interpreter()
1973 Py_Exit(0);
1976 /*--------------------------------------------------------------*/
1977 /* Replace the functions of the simple rcfile.c interpreter. */
1978 /*--------------------------------------------------------------*/
1980 /*----------------------------------------------------------------------*/
1981 /* Execute a single command from a script or from the command line */
1982 /*----------------------------------------------------------------------*/
1984 short execcommand(short pflags, char *cmdptr)
1986 flags = pflags;
1987 PyRun_SimpleString(cmdptr);
1988 refresh(NULL, NULL, NULL);
1989 return flags;
1992 /*----------------------------------------------------------------------*/
1993 /* Load the default script (like execscript() but don't allow recursive */
1994 /* loading of the startup script) */
1995 /*----------------------------------------------------------------------*/
1997 void defaultscript()
1999 FILE *fd;
2000 char *tmp_s = getenv((const char *)"XCIRCUIT_SRC_DIR");
2002 flags = LIBOVERRIDE | LIBLOADED | FONTOVERRIDE;
2004 if (!tmp_s) tmp_s = SCRIPTS_DIR;
2005 sprintf(_STR2, "%s/%s", tmp_s, STARTUP_FILE);
2007 if ((fd = fopen(_STR2, "r")) == NULL) {
2008 sprintf(_STR2, "%s/%s", SCRIPTS_DIR, STARTUP_FILE);
2009 if ((fd = fopen(_STR2, "r")) == NULL) {
2010 Wprintf("Failed to open startup script \"%s\"\n", STARTUP_FILE);
2011 return;
2014 PyRun_SimpleFile(fd, _STR2);
2017 /*----------------------------------------------------------------------*/
2018 /* Execute a script */
2019 /*----------------------------------------------------------------------*/
2021 void execscript()
2023 FILE *fd;
2025 flags = 0;
2027 xc_tilde_expand(_STR2, 249);
2028 if ((fd = fopen(_STR2, "r")) != NULL) {
2029 PyRun_SimpleFile(fd, _STR2);
2030 refresh(NULL, NULL, NULL);
2032 else {
2033 Wprintf("Failed to open script file \"%s\"\n", _STR2);
2037 /*----------------------------------------------------------------------*/
2038 /* Execute the .xcircuitrc startup script */
2039 /*----------------------------------------------------------------------*/
2041 void loadrcfile()
2043 char *userdir = getenv((const char *)"HOME");
2044 FILE *fd;
2045 short i;
2047 /* Initialize flags */
2049 flags = 0;
2051 sprintf(_STR2, "%s", USER_RC_FILE); /* Name imported from Makefile */
2053 /* try first in current directory, then look in user's home directory */
2055 xc_tilde_expand(_STR2, 249);
2056 if ((fd = fopen(_STR2, "r")) == NULL) {
2057 if (userdir != NULL) {
2058 sprintf(_STR2, "%s/%s", userdir, USER_RC_FILE);
2059 fd = fopen(_STR2, "r");
2062 if (fd != NULL)
2063 PyRun_SimpleFile(fd, _STR2);
2065 /* Add the default font if not loaded already */
2067 if (!(flags & FONTOVERRIDE)) {
2068 loadfontfile("Helvetica");
2069 if (areawin->psfont == -1)
2070 for (i = 0; i < fontcount; i++)
2071 if (!strcmp(fonts[i].psname, "Helvetica")) {
2072 areawin->psfont = i;
2073 break;
2077 if (areawin->psfont == -1) areawin->psfont = 0;
2079 setdefaultfontmarks();
2081 /* arrange the loaded libraries */
2083 if (!(flags & (LIBOVERRIDE | LIBLOADED)))
2084 defaultscript();
2086 /* Add the default colors */
2088 if (!(flags & COLOROVERRIDE)) {
2089 addnewcolorentry(xc_alloccolor("Gray40"));
2090 addnewcolorentry(xc_alloccolor("Gray60"));
2091 addnewcolorentry(xc_alloccolor("Gray80"));
2092 addnewcolorentry(xc_alloccolor("Gray90"));
2093 addnewcolorentry(xc_alloccolor("Red"));
2094 addnewcolorentry(xc_alloccolor("Blue"));
2095 addnewcolorentry(xc_alloccolor("Green2"));
2096 addnewcolorentry(xc_alloccolor("Yellow"));
2097 addnewcolorentry(xc_alloccolor("Purple"));
2098 addnewcolorentry(xc_alloccolor("SteelBlue2"));
2099 addnewcolorentry(xc_alloccolor("Red3"));
2100 addnewcolorentry(xc_alloccolor("Tan"));
2101 addnewcolorentry(xc_alloccolor("Brown"));
2104 /* These colors must be enabled whether or not colors are overridden, */
2105 /* because they are needed by the schematic capture system. */
2107 addnewcolorentry(xc_getlayoutcolor(LOCALPINCOLOR));
2108 addnewcolorentry(xc_getlayoutcolor(GLOBALPINCOLOR));
2109 addnewcolorentry(xc_getlayoutcolor(INFOLABELCOLOR));
2110 addnewcolorentry(xc_getlayoutcolor(RATSNESTCOLOR));
2111 addnewcolorentry(xc_getlayoutcolor(BBOXCOLOR));
2113 if (!(flags & KEYOVERRIDE))
2114 default_keybindings();
2117 #endif
2118 /* #endif HAVE_PYTHON and !TCL_WRAPPER */
2119 /*--------------------------------------------------------------*/