* rework export svg/pdf/ps functionality to export images with 1:1 scale. Previously...
[geda-gerbv.git] / src / project.c
blob92118c417eabbd6e4d8efa0a142519f2ffc123db
1 /*
2 * gEDA - GNU Electronic Design Automation
3 * This file is a part of gerbv.
5 * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
6 * Copyright (c) 2008 Dan McMahill
8 * $Id$
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
25 /*! \file project.c
26 \brief routines for loading and saving project files
27 \ingroup gerbv
28 */
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
35 #ifdef HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
39 #include <ctype.h>
40 #include <stdio.h>
42 #ifdef HAVE_STRING_H
43 #include <string.h>
44 #endif
46 #ifdef HAVE_SYS_TYPES_H
47 #include <sys/types.h>
48 #endif
50 #ifdef HAVE_SYS_STAT_H
51 #include <sys/stat.h>
52 #endif
54 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
58 #include <errno.h>
60 #include "common.h"
61 #include "gerbv.h"
62 #include "gerb_file.h"
63 #include "lrealpath.h"
64 #include "project.h"
65 #include "scheme-private.h"
66 #include "main.h"
67 #include "interface.h"
68 #include "render.h"
72 * update this if the project file format changes.
74 * The format *must* be major.minor[A-Z]
76 * Do *not* update this simply because we have a new gerbv
77 * version.
79 * If you bump this version, then you must also bump the
80 * version of gerbv. For example, supplse the file version
81 * is 2.0A and gerbv has 2.4B in configure.ac. If you change
82 * the file format version, you should change both the version
83 * here *and* configure.ac to 2.4C.
86 #define GERBV_PROJECT_FILE_VERSION "2.0A"
88 /* default version for project files that do not specify a version.
89 * This is assumed for all older project files.
91 #define GERBV_DEFAULT_PROJECT_FILE_VERSION "1.9A"
93 /*
94 * List of versions that we can load with this version of
95 * gerbv
97 static const char * known_versions[] = {
98 "1.9A",
99 "2.0A",
100 NULL
103 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
104 #define dprintf if(DEBUG) printf
106 static project_list_t *plist_top = NULL;
109 /* When a project file is loaded, this variable is set to the
110 * version of the project file. That can be used by various
111 * functions which may need to do something different.
113 static int current_file_version = 0;
117 * Converts a string like "2.1A" "2.12C" or "3.2ZA" to the int
118 * we use internally
120 static int
121 version_str_to_int( const char * str)
123 int r = 0;
124 gchar *dup, *tmps, *ptr;
126 if(str == NULL) {
127 return -1;
128 } else {
129 dprintf("%s(\"%s\")\n", __FUNCTION__, str);
133 * Extract out the major number (versions are strings like 2.1A)
134 * and we want the "2" here.
136 tmps = g_strdup(str);
137 ptr = tmps;
138 while(*ptr != '\0' && *ptr != '.') { ptr++; }
139 if( *ptr == '\0' ) {
140 /* this should not have happened */
141 return -1;
144 *ptr = '\0';
145 r = 10000 * atoi(tmps);
146 dprintf("%s(): Converted \"%s\" to r = %d\n", __FUNCTION__, tmps, r);
148 g_free(tmps);
151 * Extract out the minor number (versions are strings like 2.1A)
152 * and we want the "1" here.
154 dup = g_strdup(str);
155 tmps = dup;
156 ptr = tmps;
158 while(*ptr != '\0' && *ptr != '.') { ptr++; }
159 if( *ptr == '\0' ) {
160 /* this should not have happened */
161 return -1;
163 ptr++;
164 tmps = ptr;
166 while(*ptr != '\0' && isdigit( (int) *ptr)) { ptr++; }
167 if( *ptr == '\0' ) {
168 /* this should not have happened */
169 return -1;
172 *ptr = '\0';
173 r += 100 * atoi(tmps);
174 dprintf("%s(): Converted \"%s\" to r = %d\n", __FUNCTION__, tmps, r);
176 g_free(dup);
179 * Extract out the revision letter(s) (versions are strings like 2.1A)
180 * and we want the "A" here.
183 dup = g_strdup(str);
184 tmps = dup;
185 ptr = tmps;
187 while(*ptr != '\0' && (isdigit( (int) *ptr) || *ptr == '.') ) { ptr++; }
188 if( *ptr == '\0' ) {
189 /* this should not have happened */
190 return -1;
192 tmps = ptr;
194 dprintf("%s(): Processing \"%s\"\n", __FUNCTION__, tmps);
196 if( strlen(tmps) == 1) {
197 r += *tmps - 'A' + 1;
198 dprintf( "%s(): Converted \"%s\" to r = %d\n", __FUNCTION__, tmps, r);
199 } else if( strlen(tmps) == 2 ) {
200 if( *tmps == 'Z' ) {
201 r += 26;
202 tmps++;
203 r += *tmps - 'A' + 1;
204 } else {
205 /* this should not have happened */
206 return -1;
208 } else {
209 /* this should not have happened */
210 return -1;
213 g_free(dup);
216 return r;
221 * convert the internal int we use for version numbers
222 * to the string that users can deal with
224 static char *
225 version_int_to_str( int ver )
227 int major, minor, teeny;
228 char l[3];
229 char *str;
231 l[0] = '\0';
232 l[1] = '\0';
233 l[2] = '\0';
235 major = ver / 10000;
236 minor = (ver - 10000*major) / 100;
237 teeny = (ver - 10000*major - 100*minor);
238 if(teeny >= 1 && teeny <= 26) {
239 l[0] = 'A' + teeny - 1;
240 } else if(teeny > 26 && teeny <= 52) {
241 l[0] = 'Z';
242 l[1] = 'A' + teeny - 26 - 1;
245 str = g_strdup_printf("%d.%d%s", major, minor, l);
246 return str;
249 static void
250 get_color(scheme *sc, pointer value, int *color)
252 int i;
253 pointer elem;
255 if (!sc->vptr->is_vector(value)) {
256 GERB_MESSAGE("Color parameter not a vector\n");
257 return;
259 if (sc->vptr->vector_length(value) != 3) {
260 GERB_MESSAGE("Color vector of incorrect length\n");
261 return;
264 for (i = 0; i < 3; i++) {
265 elem = sc->vptr->vector_elem(value, i);
266 if (sc->vptr->is_integer(elem) && sc->vptr->is_number(elem))
267 color[i] = sc->vptr->ivalue(elem);
268 else {
269 color[i] = -1;
270 GERB_MESSAGE("Illegal color in projectfile\n");
274 return;
275 } /* get_color */
277 /* ----------------------------------------------------------------------
278 * Figure out the canonical name of the executed program
279 * and fix up the defaults for various paths. This is largely
280 * taken from InitPaths() in main.c from pcb.
282 static char *bindir = NULL;
283 static char *exec_prefix = NULL;
284 static char *pkgdatadir = NULL;
285 static gchar *scmdatadir = NULL;
287 /* this really should not be needed but it could
288 * be hooked in to appease malloc debuggers as
289 * we don't otherwise free these variables. However,
290 * they only get malloc-ed once ever so this
291 * is a fixed leak of a small size.
293 #if 0
294 void
295 destroy_paths ()
297 if (bindir != NULL) {
298 free (bindir);
299 bindir = NULL;
302 if (exec_prefix != NULL) {
303 free (exec_prefix);
304 exec_prefix = NULL;
307 if (pkgdatadir != NULL) {
308 free (pkgdatadir);
309 pkgdatadir = NULL;
312 if (scmdatadir != NULL) {
313 g_free (scmdatadir);
314 scmdatadir = NULL;
319 #endif
321 static void
322 init_paths (char *argv0)
324 size_t l;
325 int i;
326 int haspath;
327 char *t1, *t2;
328 int found_bindir = 0;
330 /* Only do this stuff once */
331 if (bindir != NULL )
332 return;
334 /* see if argv0 has enough of a path to let lrealpath give the
335 * real path. This should be the case if you invoke gerbv with
336 * something like /usr/local/bin/gerbv or ./gerbv or ./foo/gerbv
337 * but if you just use gerbv and it exists in your path, you'll
338 * just get back gerbv again.
341 haspath = 0;
342 for (i = 0; i < strlen (argv0) ; i++)
344 if (argv0[i] == GERBV_DIR_SEPARATOR_C)
345 haspath = 1;
348 dprintf("%s (%s): haspath = %d\n", __FUNCTION__, argv0, haspath);
349 if (haspath)
351 bindir = strdup (lrealpath (argv0));
352 found_bindir = 1;
354 else
356 char *path, *p, *tmps;
357 struct stat sb;
358 int r;
360 tmps = getenv ("PATH");
362 if (tmps != NULL)
364 path = strdup (tmps);
366 /* search through the font path for a font file */
367 for (p = strtok (path, GERBV_PATH_DELIMETER); p && *p;
368 p = strtok (NULL, GERBV_PATH_DELIMETER))
370 dprintf ("Looking for %s in %s\n", argv0, p);
371 if ( (tmps = malloc ( (strlen (argv0) + strlen (p) + 2) * sizeof (char))) == NULL )
373 fprintf (stderr, "%s(): malloc failed\n", __FUNCTION__);
374 exit (1);
376 sprintf (tmps, "%s%s%s", p, GERBV_DIR_SEPARATOR_S, argv0);
377 r = stat (tmps, &sb);
378 if (r == 0)
380 dprintf ("Found it: \"%s\"\n", tmps);
381 bindir = lrealpath (tmps);
382 found_bindir = 1;
383 free (tmps);
384 break;
386 free (tmps);
388 free (path);
391 dprintf ("%s(): bindir = \"%s\"\n", __FUNCTION__, bindir);
394 if (found_bindir)
396 /* strip off the executible name leaving only the path */
397 t2 = NULL;
398 t1 = strchr (bindir, GERBV_DIR_SEPARATOR_C);
399 while (t1 != NULL && *t1 != '\0')
401 t2 = t1;
402 t1 = strchr (t2 + 1, GERBV_DIR_SEPARATOR_C);
404 if (t2 != NULL)
405 *t2 = '\0';
406 dprintf ("After stripping off the executible name, we found\n");
407 dprintf ("bindir = \"%s\"\n", bindir);
410 else
412 /* we have failed to find out anything from argv[0] so fall back to the original
413 * install prefix
415 bindir = strdup (BINDIR);
418 /* now find the path to exec_prefix */
419 l = strlen (bindir) + 1 + strlen (BINDIR_TO_EXECPREFIX) + 1;
420 if ( (exec_prefix = (char *) malloc (l * sizeof (char) )) == NULL )
422 fprintf (stderr, "%s(): malloc failed\n", __FUNCTION__);
423 exit (1);
425 sprintf (exec_prefix, "%s%s%s", bindir, GERBV_DIR_SEPARATOR_S,
426 BINDIR_TO_EXECPREFIX);
428 /* now find the path to PKGDATADIR */
429 l = strlen (bindir) + 1 + strlen (BINDIR_TO_PKGDATADIR) + 1;
430 if ( (pkgdatadir = (char *) malloc (l * sizeof (char) )) == NULL )
432 fprintf (stderr, "%s(): malloc failed\n", __FUNCTION__);
433 exit (1);
435 sprintf (pkgdatadir, "%s%s%s", bindir, GERBV_DIR_SEPARATOR_S,
436 BINDIR_TO_PKGDATADIR);
438 scmdatadir = g_strdup_printf ("%s%s%s", pkgdatadir, GERBV_DIR_SEPARATOR_S, SCMSUBDIR);
440 dprintf ("%s(): bindir = %s\n", __FUNCTION__, bindir);
441 dprintf ("%s(): exec_prefix = %s\n", __FUNCTION__, exec_prefix);
442 dprintf ("%s(): pkgdatadir = %s\n", __FUNCTION__, pkgdatadir);
443 dprintf ("%s(): scmdatadir = %s\n", __FUNCTION__, scmdatadir);
448 static char *
449 get_value_string(scheme *sc, pointer value)
451 if (!sc->vptr->is_string(value))
452 return NULL;
454 return sc->vptr->string_value(value);
455 } /* get_value_string */
458 /** Conversion of '\' into '/' and vice versa for compatibility under WIN32
459 platforms. */
460 static char *
461 convert_path_separators(char* path, int conv_flag)
463 #if defined (__MINGW32__)
464 char *hit_in_path;
466 switch (conv_flag) {
468 case MINGW_UNIX:
469 while ((hit_in_path = strchr(path, '\\'))) {
470 *hit_in_path = '/';
472 break;
473 case UNIX_MINGW:
474 while ((hit_in_path = strchr(path, '/'))) {
475 *hit_in_path = '\\';
477 break;
479 #endif
481 return path;
482 }/* convert_path_separators */
485 static pointer
486 define_layer(scheme *sc, pointer args)
488 pointer car_el, cdr_el, name, value;
489 int layerno;
490 project_list_t *plist_tmp = NULL;
492 dprintf("--> entering project.c:define_layer\n");
494 if (!sc->vptr->is_pair(args)){
495 GERB_MESSAGE("define-layer!: Too few arguments\n");
496 return sc->F;
499 car_el = sc->vptr->pair_car(args);
500 cdr_el = sc->vptr->pair_cdr(args);
502 if (!sc->vptr->is_integer(car_el) || !sc->vptr->is_number(car_el)) {
503 GERB_MESSAGE("define-layer!: Layer number missing/incorrect\n");
504 return sc->F;
507 layerno = sc->vptr->ivalue(car_el);
508 dprintf(" layerno = %d\n", layerno);
510 car_el = sc->vptr->pair_car(cdr_el);
511 cdr_el = sc->vptr->pair_cdr(cdr_el);
513 plist_tmp = (project_list_t *)g_malloc(sizeof(project_list_t));
514 memset(plist_tmp, 0, sizeof(project_list_t));
515 plist_tmp->next = plist_top;
516 plist_top = plist_tmp;
517 plist_top->layerno = layerno;
518 plist_top->visible = 1;
519 plist_top->n_attr = 0;
520 plist_top->attr_list = NULL;
522 while (sc->vptr->is_pair(car_el)) {
524 name = sc->vptr->pair_car(car_el);
525 value = sc->vptr->pair_cdr(car_el);
527 if (!sc->vptr->is_symbol(name)) {
528 GERB_MESSAGE("define-layer!:non-symbol found, ignoring\n");
529 goto end_name_value_parse;
532 if (strcmp(sc->vptr->symname(name), "color") == 0) {
533 get_color(sc, value, plist_top->rgb);
534 } else if (strcmp(sc->vptr->symname(name), "filename") == 0) {
536 plist_top->filename = g_strdup(get_value_string(sc, value));
537 plist_top->filename = convert_path_separators(plist_top->filename,
538 UNIX_MINGW);
539 plist_top->is_pnp = 0;
540 } else if (strcmp(sc->vptr->symname(name), "pick_and_place") == 0) {
542 plist_top->filename = g_strdup(get_value_string(sc, value));
543 plist_top->filename = convert_path_separators(plist_top->filename,
544 UNIX_MINGW);
545 plist_top->is_pnp = 1;
546 } else if (strcmp(sc->vptr->symname(name), "inverted") == 0) {
547 if (value == sc->F) {
548 plist_top->inverted = 0;
549 } else if (value == sc->T) {
550 plist_top->inverted = 1;
551 } else {
552 GERB_MESSAGE("Argument to inverted must be #t or #f\n");
554 } else if (strcmp(sc->vptr->symname(name), "visible") == 0) {
555 if (value == sc->F) {
556 plist_top->visible = 0;
557 } else if (value == sc->T) {
558 plist_top->visible = 1;
559 } else {
560 GERB_MESSAGE("Argument to visible must be #t or #f\n");
562 } else if (strcmp(sc->vptr->symname(name), "attribs") == 0) {
563 pointer attr_car_el, attr_cdr_el;
564 pointer attr_name, attr_type, attr_value;
565 char *type;
567 dprintf ("Parsing file attributes\n");
569 attr_car_el = sc->vptr->pair_car (value);
570 attr_cdr_el = sc->vptr->pair_cdr (value);
571 while (sc->vptr->is_pair(attr_car_el)) {
572 int p = plist_top->n_attr;
573 plist_top->n_attr++;
574 plist_top->attr_list = (gerbv_HID_Attribute *)
575 realloc (plist_top->attr_list,
576 plist_top->n_attr * sizeof (gerbv_HID_Attribute));
577 if (plist_top->attr_list == NULL ) {
578 fprintf (stderr, "%s(): realloc failed\n", __FUNCTION__);
579 exit (1);
582 /* car */
583 attr_name = sc->vptr->pair_car(attr_car_el);
585 /* cadr */
586 attr_type = sc->vptr->pair_cdr (attr_car_el);
587 attr_type = sc->vptr->pair_car (attr_type);
589 /* caddr */
590 attr_value = sc->vptr->pair_cdr (attr_car_el);
591 attr_value = sc->vptr->pair_cdr (attr_value);
592 attr_value = sc->vptr->pair_car (attr_value);
594 dprintf (" attribute %s, type is %s, value is ",
595 sc->vptr->symname(attr_name),
596 sc->vptr->symname(attr_type));
598 plist_top->attr_list[p].name = strdup (sc->vptr->symname (attr_name));
600 type = sc->vptr->symname (attr_type);
602 if (strcmp (type, "label") == 0) {
603 dprintf ("%s", sc->vptr->string_value (attr_value));
604 plist_top->attr_list[p].type = HID_Label;
605 plist_top->attr_list[p].default_val.str_value =
606 strdup (sc->vptr->string_value (attr_value));
608 } else if (strcmp (type, "integer") == 0) {
609 dprintf ("%ld", sc->vptr->ivalue (attr_value));
610 plist_top->attr_list[p].type = HID_Integer;
611 plist_top->attr_list[p].default_val.int_value =
612 sc->vptr->ivalue (attr_value);
614 } else if (strcmp (type, "real") == 0) {
615 dprintf ("%g", sc->vptr->rvalue (attr_value));
616 plist_top->attr_list[p].type = HID_Real;
617 plist_top->attr_list[p].default_val.real_value =
618 sc->vptr->rvalue (attr_value);
620 } else if (strcmp (type, "string") == 0) {
621 dprintf ("%s", sc->vptr->string_value (attr_value));
622 plist_top->attr_list[p].type = HID_String;
623 plist_top->attr_list[p].default_val.str_value =
624 strdup (sc->vptr->string_value (attr_value));
626 } else if (strcmp (type, "boolean") == 0) {
627 dprintf ("%ld", sc->vptr->ivalue (attr_value));
628 plist_top->attr_list[p].type = HID_Boolean;
629 plist_top->attr_list[p].default_val.int_value =
630 sc->vptr->ivalue (attr_value);
632 } else if (strcmp (type, "enum") == 0) {
633 dprintf ("%ld", sc->vptr->ivalue (attr_value));
634 plist_top->attr_list[p].type = HID_Enum;
635 plist_top->attr_list[p].default_val.int_value =
636 sc->vptr->ivalue (attr_value);
638 } else if (strcmp (type, "mixed") == 0) {
639 plist_top->attr_list[p].type = HID_Mixed;
640 plist_top->attr_list[p].default_val.str_value = NULL;
641 fprintf (stderr, "%s(): WARNING: HID_Mixed is not yet supported\n",
642 __FUNCTION__);
644 } else if (strcmp (type, "path") == 0) {
645 dprintf ("%s", sc->vptr->string_value (attr_value));
646 plist_top->attr_list[p].type = HID_Path;
647 plist_top->attr_list[p].default_val.str_value =
648 strdup (sc->vptr->string_value (attr_value));
649 } else {
650 fprintf (stderr, "%s(): Unknown attribute type: \"%s\"\n",
651 __FUNCTION__, type);
653 dprintf ("\n");
655 attr_car_el = sc->vptr->pair_car(attr_cdr_el);
656 attr_cdr_el = sc->vptr->pair_cdr(attr_cdr_el);
661 end_name_value_parse:
662 car_el = sc->vptr->pair_car(cdr_el);
663 cdr_el = sc->vptr->pair_cdr(cdr_el);
666 return sc->NIL;
667 } /* define_layer */
669 static pointer
670 set_render_type(scheme *sc, pointer args)
672 pointer car_el, cdr_el;
673 int r;
675 dprintf("--> entering project.c:%s()\n", __FUNCTION__);
677 if (!sc->vptr->is_pair(args)){
678 GERB_MESSAGE("set-render-type!: Too few arguments\n");
679 return sc->F;
682 car_el = sc->vptr->pair_car(args);
683 cdr_el = sc->vptr->pair_cdr(args);
685 r = sc->vptr->ivalue (car_el);
686 dprintf ("%s(): Setting render type to %d\n", __FUNCTION__, r);
687 interface_set_render_type (r);
689 return sc->NIL;
690 } /* set_render_type */
692 static pointer
693 gerbv_file_version(scheme *sc, pointer args)
695 pointer car_el, cdr_el;
696 int r;
697 char *vstr;
698 char *tmps;
700 dprintf("--> entering project.c:%s()\n", __FUNCTION__);
702 if (!sc->vptr->is_pair(args)){
703 GERB_MESSAGE("gerbv-file-version!: Too few arguments\n");
704 return sc->F;
707 car_el = sc->vptr->pair_car(args);
708 cdr_el = sc->vptr->pair_cdr(args);
709 vstr = get_value_string(sc, car_el);
711 /* find our internal integer code */
712 r = version_str_to_int( vstr );
714 if( r == -1) {
715 r = version_str_to_int( GERBV_DEFAULT_PROJECT_FILE_VERSION );
716 GERB_MESSAGE("The project file you are attempting to load has specified that it\n"
717 "uses project file version \"%s\" but this string is not\n"
718 "a valid version. Gerbv will attempt to load the file using\n"
719 "version \"%s\". You may experience unexpected results.\n",
720 vstr, version_int_to_str( r ));
721 vstr = GERBV_DEFAULT_PROJECT_FILE_VERSION;
723 if( DEBUG ) {
724 tmps = version_int_to_str( r );
725 printf ("%s(): Read a project file version of %s (%d)\n", __FUNCTION__, vstr, r);
726 printf (" Translated back to \"%s\"\n", tmps);
727 g_free (tmps);
730 dprintf ("%s(): Read a project file version of %s (%d)\n", __FUNCTION__, vstr, r);
732 if ( r > version_str_to_int( GERBV_PROJECT_FILE_VERSION )) {
733 /* The project file we're trying to load is too new for this version of gerbv */
734 GERB_MESSAGE("The project file you are attempting to load is version \"%s\"\n"
735 "but this copy of gerbv is only capable of loading project files\n"
736 "using version \"%s\" or older. You may experience unexpected results.",
737 vstr, GERBV_PROJECT_FILE_VERSION);
738 } else {
739 int i = 0;
740 int vok = 0;
742 while( known_versions[i] != NULL ) {
743 if( strcmp( known_versions[i], vstr) == 0 ) {
744 vok = 1;
746 i++;
749 if( ! vok ) {
750 /* The project file we're trying to load is not too new
751 * but it is unknown to us
753 GERB_MESSAGE("The project file you are attempting to load is version \"%s\"\n"
754 "which is an unknown version.\n"
755 "You may experience unexpected results.",
756 vstr);
762 * store the version of the file we're currently loading. This variable is used
763 * by the different functions called by the project file to do anything which is
764 * version specific.
766 current_file_version = r;
768 return sc->NIL;
769 } /* set_render_type */
772 /** Reads the content of a project file.
773 * Global:\n
774 * Background color,\n
775 * global path,\n
776 * corresponding pick and place file: labelled 'picknplace'\n
777 * Per layer:\n
778 * layer color,\n
779 * layer filename
781 project_list_t *
782 read_project_file(char const* filename)
784 struct stat stat_info;
785 scheme *sc;
786 FILE *fd;
787 /* always let the environment variable win so one can force
788 * a particular init.scm. Then we use the default installed
789 * directory based on where the binary has been installed to
790 * (including the possibility of relocation). Then use the
791 * default compiled in directory. After that try the directory
792 * where the binary lives and finally the current directory.
794 char *initdirs[] = {"$GERBV_SCHEMEINIT","", BACKEND_DIR,
795 mainProject->execpath, ".",
796 NULL};
797 char *initfile;
801 * Figure out some directories so we can find init.scm
803 init_paths(mainProject->execname);
804 initdirs[1] = scmdatadir;
806 #if defined(DEBUG)
807 if (DEBUG > 0)
809 int i=0;
811 while(initdirs[i] != NULL) {
812 printf("%s(): initdirs[%d] = \"%s\"\n", __FUNCTION__, i, initdirs[i]);
813 i++;
816 #endif
819 * set the current version of the project file to 1 day before we started adding
820 * versioning to the files. While the file is being loaded, this will
821 * be set to the correct version on newer files and ignored on older files
823 current_file_version = version_str_to_int( GERBV_DEFAULT_PROJECT_FILE_VERSION );
825 if (stat(filename, &stat_info)) {
826 GERB_MESSAGE("Failed to read %s\n", filename);
827 return NULL;
830 if (!S_ISREG(stat_info.st_mode)) {
831 GERB_MESSAGE("Failed to read %s\n", filename);
832 return NULL;
835 sc = scheme_init_new();
836 scheme_set_output_port_file(sc, stdout);
838 if(!sc){
839 GERB_FATAL_ERROR("Couldn't init scheme\n");
840 exit(1);
843 errno = 0;
844 initfile = gerb_find_file("init.scm", initdirs);
845 if (initfile == NULL) {
846 scheme_deinit(sc);
847 GERB_MESSAGE("Problem loading init.scm (%s)\n", strerror(errno));
848 return NULL;
850 dprintf("%s(): initfile = \"%s\"\n", __FUNCTION__, initfile);
852 if ((fd = fopen(initfile, "r")) == NULL) {
853 scheme_deinit(sc);
854 GERB_MESSAGE("Couldn't open %s (%s)\n", initfile, strerror(errno));
855 return NULL;
857 sc->vptr->load_file(sc, fd);
858 fclose(fd);
860 sc->vptr->scheme_define(sc, sc->global_env,
861 sc->vptr->mk_symbol(sc, "define-layer!"),
862 sc->vptr->mk_foreign_func(sc, define_layer));
864 sc->vptr->scheme_define(sc, sc->global_env,
865 sc->vptr->mk_symbol(sc, "set-render-type!"),
866 sc->vptr->mk_foreign_func(sc, set_render_type));
868 sc->vptr->scheme_define(sc, sc->global_env,
869 sc->vptr->mk_symbol(sc, "gerbv-file-version!"),
870 sc->vptr->mk_foreign_func(sc, gerbv_file_version));
872 if ((fd = fopen(filename, "r")) == NULL) {
873 scheme_deinit(sc);
874 GERB_MESSAGE("Couldn't open project file %s (%s)\n", filename,
875 strerror(errno));
876 return NULL;
879 plist_top = NULL;
881 scheme_load_file(sc, fd);
882 fclose(fd);
884 scheme_deinit(sc);
886 return plist_top;
887 } /* read_project */
890 void
891 project_destroy_project_list (project_list_t *projectList){
892 project_list_t *tempP,*tempP2;
894 for (tempP = projectList; tempP != NULL; ){
895 tempP2 = tempP->next;
897 g_free (tempP->filename);
898 gerbv_attribute_destroy_HID_attribute (tempP->attr_list, tempP->n_attr);
899 tempP->attr_list = NULL;
900 tempP = tempP2;
905 * Writes a description of a project to a file
906 * that can be parsed by read_project above
908 int
909 write_project_file(gerbv_project_t *gerbvProject, char const* filename, project_list_t *project)
911 FILE *fd;
912 project_list_t *p = project;
913 int n_attr = 0;
914 gerbv_HID_Attribute *attr_list = NULL;
915 int i;
917 if ((fd = fopen(filename, "w")) == NULL) {
918 GERB_MESSAGE("Couldn't save project %s\n", filename);
919 return(-1);
921 fprintf(fd, "(gerbv-file-version! \"%s\")\n", GERBV_PROJECT_FILE_VERSION);
922 while (p) {
923 fprintf(fd, "(define-layer! %d ", p->layerno);
925 #if defined (__MINGW32__)
926 fprintf(fd, "(cons 'filename \"%s\")", convert_path_separators(p->filename, MINGW_UNIX));
927 #else
928 fprintf(fd, "(cons 'filename \"%s\")", p->filename);
929 #endif
931 if (p->inverted)
932 fprintf(fd, "(cons 'inverted #t)");
933 if (p->visible)
934 fprintf(fd, "(cons 'visible #t)");
935 else
936 fprintf(fd, "(cons 'visible #f)");
938 fprintf(fd, "(cons 'color #(%d %d %d))", p->rgb[0], p->rgb[1], p->rgb[2]);
940 /* now write out the attribute list which specifies the
941 * file format
943 if (p->layerno < 0) {
944 attr_list = NULL;
945 n_attr = 0;
946 } else {
947 attr_list = gerbvProject->file[p->layerno]->image->info->attr_list;
948 n_attr = gerbvProject->file[p->layerno]->image->info->n_attr;
951 if (n_attr > 0) {
952 fprintf (fd, "(cons 'attribs (list");
954 for (i = 0; i < n_attr ; i++) {
955 switch (attr_list[i].type) {
956 case HID_Label:
957 fprintf(fd, " (list '%s 'Label \"%s\")", attr_list[i].name,
958 attr_list[i].default_val.str_value);
959 break;
961 case HID_Integer:
962 fprintf(fd, " (list '%s 'Integer %d)", attr_list[i].name,
963 attr_list[i].default_val.int_value);
964 break;
966 case HID_Real:
967 fprintf(fd, " (list '%s 'Real %g)", attr_list[i].name,
968 attr_list[i].default_val.real_value);
969 break;
971 case HID_String:
972 fprintf(fd, " (list '%s 'String \"%s\")", attr_list[i].name,
973 attr_list[i].default_val.str_value);
974 break;
976 case HID_Boolean:
977 fprintf(fd, " (list '%s 'Boolean %d)", attr_list[i].name,
978 attr_list[i].default_val.int_value);
979 break;
981 case HID_Enum:
982 fprintf(fd, " (list '%s 'Enum %d)", attr_list[i].name,
983 attr_list[i].default_val.int_value);
984 break;
986 case HID_Mixed:
987 dprintf ("HID_Mixed\n");
988 fprintf (stderr, "%s(): WARNING: HID_Mixed is not yet supported.\n",
989 __FUNCTION__);
990 break;
992 case HID_Path:
993 fprintf(fd, " (list '%s 'Path \"%s\")", attr_list[i].name,
994 attr_list[i].default_val.str_value);
995 break;
997 default:
998 fprintf (stderr, "%s: unknown type of HID attribute (%d)\n",
999 __FUNCTION__, attr_list[i].type);
1000 break;
1003 if (n_attr > 0) {
1004 fprintf (fd, "))");
1007 fprintf(fd, ")\n");
1008 p = p->next;
1011 fprintf (fd, "(set-render-type! %d)\n", screenRenderInfo.renderType);
1013 fclose(fd);
1015 return(0);
1016 } /* write_project */