gerbv  2.6A
project.c
Go to the documentation of this file.
1 /*
2  * gEDA - GNU Electronic Design Automation
3  * This file is a part of gerbv.
4  *
5  * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
6  * Copyright (c) 2008 Dan McMahill
7  *
8  * $Id$
9  *
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.
14  *
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.
19  *
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
23  */
24 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 
35 #ifdef HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
38 
39 #include <ctype.h>
40 #include <stdio.h>
41 
42 #ifdef HAVE_STRING_H
43 #include <string.h>
44 #endif
45 
46 #ifdef HAVE_SYS_TYPES_H
47 #include <sys/types.h>
48 #endif
49 
50 #ifdef HAVE_SYS_STAT_H
51 #include <sys/stat.h>
52 #endif
53 
54 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57 
58 #include <errno.h>
59 #include <locale.h>
60 #include <math.h>
61 
62 #include "common.h"
63 #include "gerbv.h"
64 #include "gerb_file.h"
65 #include "lrealpath.h"
66 #include "project.h"
67 #include "scheme-private.h"
68 #include "main.h"
69 #include "interface.h"
70 #include "render.h"
71 
72 
73 /*
74  * update this if the project file format changes.
75  *
76  * The format *must* be major.minor[A-Z]
77  *
78  * Do *not* update this simply because we have a new gerbv
79  * version.
80  *
81  * If you bump this version, then you must also bump the
82  * version of gerbv. For example, supplse the file version
83  * is 2.0A and gerbv has 2.4B in configure.ac. If you change
84  * the file format version, you should change both the version
85  * here *and* configure.ac to 2.4C.
86  */
87 
88 #define GERBV_PROJECT_FILE_VERSION "2.0A"
89 
90 /* default version for project files that do not specify a version.
91  * This is assumed for all older project files.
92  */
93 #define GERBV_DEFAULT_PROJECT_FILE_VERSION "1.9A"
94 
95 /*
96  * List of versions that we can load with this version of
97  * gerbv
98  */
99 static const char * known_versions[] = {
100  "1.9A",
101  "2.0A",
102  NULL
103 };
104 
105 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
106 #define dprintf if(DEBUG) printf
107 
108 static project_list_t *project_list_top = NULL;
109 
110 static const int alpha_def_value = 177*257;
111 
112 /* When a project file is loaded, this variable is set to the
113  * version of the project file. That can be used by various
114  * functions which may need to do something different.
115  */
116 static int current_file_version = 0;
117 
118 
119 /*
120  * Converts a string like "2.1A" "2.12C" or "3.2ZA" to the int
121  * we use internally
122  */
123 static int
124 version_str_to_int( const char * str)
125 {
126  int r = 0;
127  gchar *dup, *tmps, *ptr;
128 
129  if(str == NULL) {
130  return -1;
131  } else {
132  dprintf("%s(\"%s\")\n", __FUNCTION__, str);
133 
134 
135  /*
136  * Extract out the major number (versions are strings like 2.1A)
137  * and we want the "2" here.
138  */
139  tmps = g_strdup(str);
140  ptr = tmps;
141  while(*ptr != '\0' && *ptr != '.') { ptr++; }
142  if( *ptr == '\0' ) {
143  /* this should not have happened */
144  return -1;
145  }
146 
147  *ptr = '\0';
148  r = 10000 * atoi(tmps);
149  dprintf("%s(): Converted \"%s\" to r = %d\n", __FUNCTION__, tmps, r);
150 
151  g_free(tmps);
152 
153  /*
154  * Extract out the minor number (versions are strings like 2.1A)
155  * and we want the "1" here.
156  */
157  dup = g_strdup(str);
158  tmps = dup;
159  ptr = tmps;
160 
161  while(*ptr != '\0' && *ptr != '.') { ptr++; }
162  if( *ptr == '\0' ) {
163  /* this should not have happened */
164  return -1;
165  }
166  ptr++;
167  tmps = ptr;
168 
169  while(*ptr != '\0' && isdigit( (int) *ptr)) { ptr++; }
170  if( *ptr == '\0' ) {
171  /* this should not have happened */
172  return -1;
173  }
174 
175  *ptr = '\0';
176  r += 100 * atoi(tmps);
177  dprintf("%s(): Converted \"%s\" to r = %d\n", __FUNCTION__, tmps, r);
178 
179  g_free(dup);
180 
181  /*
182  * Extract out the revision letter(s) (versions are strings like 2.1A)
183  * and we want the "A" here.
184  */
185 
186  dup = g_strdup(str);
187  tmps = dup;
188  ptr = tmps;
189 
190  while(*ptr != '\0' && (isdigit( (int) *ptr) || *ptr == '.') ) { ptr++; }
191  if( *ptr == '\0' ) {
192  /* this should not have happened */
193  return -1;
194  }
195  tmps = ptr;
196 
197  dprintf("%s(): Processing \"%s\"\n", __FUNCTION__, tmps);
198 
199  if( strlen(tmps) == 1) {
200  r += *tmps - 'A' + 1;
201  dprintf( "%s(): Converted \"%s\" to r = %d\n", __FUNCTION__, tmps, r);
202  } else if( strlen(tmps) == 2 ) {
203  if( *tmps == 'Z' ) {
204  r += 26;
205  tmps++;
206  r += *tmps - 'A' + 1;
207  } else {
208  /* this should not have happened */
209  return -1;
210  }
211  } else {
212  /* this should not have happened */
213  return -1;
214  }
215 
216  g_free(dup);
217 
218  }
219  return r;
220 
221 }
222 
223 /*
224  * convert the internal int we use for version numbers
225  * to the string that users can deal with
226  */
227 static char *
228 version_int_to_str( int ver )
229 {
230  int major, minor, teeny;
231  char l[3];
232  char *str;
233 
234  l[0] = '\0';
235  l[1] = '\0';
236  l[2] = '\0';
237 
238  major = ver / 10000;
239  minor = (ver - 10000*major) / 100;
240  teeny = (ver - 10000*major - 100*minor);
241  if(teeny >= 1 && teeny <= 26) {
242  l[0] = 'A' + teeny - 1;
243  } else if(teeny > 26 && teeny <= 52) {
244  l[0] = 'Z';
245  l[1] = 'A' + teeny - 26 - 1;
246  }
247 
248  str = g_strdup_printf("%d.%d%s", major, minor, l);
249  return str;
250 }
251 
252 static int
253 check_vector_and_length(scheme *sc, pointer value,
254  unsigned int length, const char *item)
255 {
256  if (!sc->vptr->is_vector(value)) {
257  GERB_MESSAGE(_("'%s' parameter not a vector"), item);
258 
259  return 1;
260  }
261 
262  if (sc->vptr->vector_length(value) != length) {
263  GERB_MESSAGE(_("'%s' vector of incorrect length"), item);
264 
265  return 2;
266  }
267 
268  return 0;
269 }
270 
271 static void
272 get_color(scheme *sc, pointer value, int *color)
273 {
274  int i;
275  pointer elem;
276 
277  if (check_vector_and_length(sc, value, 3, "color"))
278  return;
279 
280  for (i = 0; i < 3; i++) {
281  elem = sc->vptr->vector_elem(value, i);
282  if (sc->vptr->is_integer(elem) && sc->vptr->is_number(elem))
283  color[i] = sc->vptr->ivalue(elem);
284  else {
285  color[i] = -1;
286  GERB_MESSAGE(_("Illegal color in projectfile"));
287  }
288  }
289 
290  return;
291 } /* get_color */
292 
293 static void
294 get_alpha(scheme *sc, pointer value, int *alpha)
295 {
296  pointer elem;
297 
298  if (check_vector_and_length(sc, value, 1, "alpha"))
299  return;
300 
301  elem = sc->vptr->vector_elem(value, 0);
302  if (sc->vptr->is_integer(elem) && sc->vptr->is_number(elem)) {
303  *alpha = sc->vptr->ivalue(elem);
304  return;
305  }
306 
307  GERB_MESSAGE(_("Illegal alpha value in projectfile"));
308 } /* get_alpha */
309 
310 static void
311 get_double(scheme *sc, pointer value, char *item, double *x, double def)
312 {
313  pointer elem;
314 
315  if (check_vector_and_length(sc, value, 1, item))
316  return;
317 
318  elem = sc->vptr->vector_elem(value, 0);
319  if (sc->vptr->is_real(elem) && sc->vptr->is_number(elem)) {
320  *x = sc->vptr->rvalue(elem);
321  } else {
322  *x = def;
323  GERB_MESSAGE(_("Illegal %s in projectfile"), item);
324  }
325 } /* get_double */
326 
327 static void
328 get_double_pair(scheme *sc, pointer value, char *item,
329  double *x, double *y, double def)
330 {
331  pointer elem;
332 
333  if (check_vector_and_length(sc, value, 2, item))
334  return;
335 
336  elem = sc->vptr->vector_elem(value, 0);
337  if (sc->vptr->is_real(elem) && sc->vptr->is_number(elem)) {
338  *x = sc->vptr->rvalue(elem);
339  } else {
340  *x = def;
341  GERB_MESSAGE(_("Illegal %s in projectfile"), item);
342  }
343 
344  elem = sc->vptr->vector_elem(value, 1);
345  if (sc->vptr->is_real(elem) && sc->vptr->is_number(elem)) {
346  *y = sc->vptr->rvalue(elem);
347  } else {
348  *y = def;
349  GERB_MESSAGE(_("Illegal %s in projectfile"), item);
350  }
351 } /* get_double_pair */
352 
353 static void
354 get_bool_pair(scheme *sc, pointer value, char *item,
355  char *x, char *y, char def)
356 {
357  pointer elem;
358 
359  if (check_vector_and_length(sc, value, 2, item))
360  return;
361 
362  elem = sc->vptr->vector_elem(value, 0);
363  if (elem == sc->F) {
364  *x = 0;
365  } else if (elem == sc->T) {
366  *x = 1;
367  } else {
368  *x = def;
369  GERB_MESSAGE(_("Illegal %s in projectfile"), item);
370  }
371 
372  elem = sc->vptr->vector_elem(value, 1);
373  if (elem == sc->F) {
374  *y = 0;
375  } else if (elem == sc->T) {
376  *y = 1;
377  } else {
378  *y = def;
379  GERB_MESSAGE(_("Illegal %s in projectfile"), item);
380  }
381 } /* get_bool_pair */
382 
383 /* ----------------------------------------------------------------------
384  * Figure out the canonical name of the executed program
385  * and fix up the defaults for various paths. This is largely
386  * taken from InitPaths() in main.c from pcb.
387  */
388 static char *bindir = NULL;
389 static char *exec_prefix = NULL;
390 static char *pkgdatadir = NULL;
391 static gchar *scmdatadir = NULL;
392 
393 /* this really should not be needed but it could
394  * be hooked in to appease malloc debuggers as
395  * we don't otherwise free these variables. However,
396  * they only get malloc-ed once ever so this
397  * is a fixed leak of a small size.
398  */
399 #if 0
400 void
401 destroy_paths ()
402 {
403  if (bindir != NULL) {
404  free (bindir);
405  bindir = NULL;
406  }
407 
408  if (exec_prefix != NULL) {
409  free (exec_prefix);
410  exec_prefix = NULL;
411  }
412 
413  if (pkgdatadir != NULL) {
414  free (pkgdatadir);
415  pkgdatadir = NULL;
416  }
417 
418  if (scmdatadir != NULL) {
419  g_free (scmdatadir);
420  scmdatadir = NULL;
421  }
422 
423 
424 }
425 #endif
426 
427 static void
428 init_paths (char *argv0)
429 {
430  size_t l;
431  int i;
432  int haspath;
433  char *t1, *t2;
434  int found_bindir = 0;
435 
436  /* Only do this stuff once */
437  if (bindir != NULL )
438  return;
439 
440  /* see if argv0 has enough of a path to let lrealpath give the
441  * real path. This should be the case if you invoke gerbv with
442  * something like /usr/local/bin/gerbv or ./gerbv or ./foo/gerbv
443  * but if you just use gerbv and it exists in your path, you'll
444  * just get back gerbv again.
445  */
446 
447  haspath = 0;
448  for (i = 0; i < strlen (argv0) ; i++)
449  {
450  if (argv0[i] == GERBV_DIR_SEPARATOR_C)
451  haspath = 1;
452  }
453 
454  dprintf("%s (%s): haspath = %d\n", __FUNCTION__, argv0, haspath);
455  if (haspath)
456  {
457  bindir = strdup (lrealpath (argv0));
458  found_bindir = 1;
459  }
460  else
461  {
462  char *path, *p, *tmps;
463  struct stat sb;
464  int r;
465 
466  tmps = getenv ("PATH");
467 
468  if (tmps != NULL)
469  {
470  path = strdup (tmps);
471 
472  /* search through the font path for a font file */
473  for (p = strtok (path, GERBV_PATH_DELIMETER); p && *p;
474  p = strtok (NULL, GERBV_PATH_DELIMETER))
475  {
476  dprintf ("Looking for %s in %s\n", argv0, p);
477  if ( (tmps = malloc ( (strlen (argv0) + strlen (p) + 2) * sizeof (char))) == NULL )
478  {
479  fprintf (stderr, _("%s(): malloc failed\n"), __FUNCTION__);
480  exit (1);
481  }
482  sprintf (tmps, "%s%s%s", p, GERBV_DIR_SEPARATOR_S, argv0);
483  r = stat (tmps, &sb);
484  if (r == 0)
485  {
486  dprintf ("Found it: \"%s\"\n", tmps);
487  bindir = lrealpath (tmps);
488  found_bindir = 1;
489  free (tmps);
490  break;
491  }
492  free (tmps);
493  }
494  free (path);
495  }
496  }
497  dprintf ("%s(): bindir = \"%s\"\n", __FUNCTION__, bindir);
498 
499 
500  if (found_bindir)
501  {
502  /* strip off the executible name leaving only the path */
503  t2 = NULL;
504  t1 = strchr (bindir, GERBV_DIR_SEPARATOR_C);
505  while (t1 != NULL && *t1 != '\0')
506  {
507  t2 = t1;
508  t1 = strchr (t2 + 1, GERBV_DIR_SEPARATOR_C);
509  }
510  if (t2 != NULL)
511  *t2 = '\0';
512  dprintf ("After stripping off the executible name, we found\n");
513  dprintf ("bindir = \"%s\"\n", bindir);
514 
515  }
516  else
517  {
518  /* we have failed to find out anything from argv[0] so fall back to the original
519  * install prefix
520  */
521  bindir = strdup (BINDIR);
522  }
523 
524  /* now find the path to exec_prefix */
525  l = strlen (bindir) + 1 + strlen (BINDIR_TO_EXECPREFIX) + 1;
526  if ( (exec_prefix = (char *) malloc (l * sizeof (char) )) == NULL )
527  {
528  fprintf (stderr, _("%s(): malloc failed\n"), __FUNCTION__);
529  exit (1);
530  }
531  sprintf (exec_prefix, "%s%s%s", bindir, GERBV_DIR_SEPARATOR_S,
532  BINDIR_TO_EXECPREFIX);
533 
534  /* now find the path to PKGDATADIR */
535  l = strlen (bindir) + 1 + strlen (BINDIR_TO_PKGDATADIR) + 1;
536  if ( (pkgdatadir = (char *) malloc (l * sizeof (char) )) == NULL )
537  {
538  fprintf (stderr, _("%s(): malloc failed\n"), __FUNCTION__);
539  exit (1);
540  }
541  sprintf (pkgdatadir, "%s%s%s", bindir, GERBV_DIR_SEPARATOR_S,
542  BINDIR_TO_PKGDATADIR);
543 
544  scmdatadir = g_strdup_printf ("%s%s%s", pkgdatadir, GERBV_DIR_SEPARATOR_S, SCMSUBDIR);
545 
546  dprintf ("%s(): bindir = %s\n", __FUNCTION__, bindir);
547  dprintf ("%s(): exec_prefix = %s\n", __FUNCTION__, exec_prefix);
548  dprintf ("%s(): pkgdatadir = %s\n", __FUNCTION__, pkgdatadir);
549  dprintf ("%s(): scmdatadir = %s\n", __FUNCTION__, scmdatadir);
550 
551 }
552 
553 
554 static char *
555 get_value_string(scheme *sc, pointer value)
556 {
557  if (!sc->vptr->is_string(value))
558  return NULL;
559 
560  return sc->vptr->string_value(value);
561 } /* get_value_string */
562 
563 
566 static char *
567 convert_path_separators(char* path, int conv_flag)
568 {
569 #if defined (__MINGW32__)
570  char *hit_in_path;
571 
572  switch (conv_flag) {
573 
574  case MINGW_UNIX:
575  while ((hit_in_path = strchr(path, '\\'))) {
576  *hit_in_path = '/';
577  }
578  break;
579  case UNIX_MINGW:
580  while ((hit_in_path = strchr(path, '/'))) {
581  *hit_in_path = '\\';
582  }
583  break;
584  }
585 #endif
586 
587  return path;
588 }/* convert_path_separators */
589 
590 
591 static pointer
592 define_layer(scheme *sc, pointer args)
593 {
594  pointer car_el, cdr_el, name, value;
595  project_list_t *plist;
596  const char *str;
597  int layerno;
598 
599  dprintf("--> entering %s: %s\n", __FILE__, __func__);
600 
601  if (!sc->vptr->is_pair(args)) {
602  GERB_MESSAGE(_("%s(): too few arguments"), __func__);
603 
604  return sc->F;
605  }
606 
607  car_el = sc->vptr->pair_car(args);
608  cdr_el = sc->vptr->pair_cdr(args);
609 
610  if (!sc->vptr->is_integer(car_el) || !sc->vptr->is_number(car_el)) {
611  GERB_MESSAGE(_("%s(): layer number missing/incorrect"), __func__);
612 
613  return sc->F;
614  }
615 
616  layerno = sc->vptr->ivalue(car_el);
617  dprintf(" layerno = %d\n", layerno);
618 
619  car_el = sc->vptr->pair_car(cdr_el);
620  cdr_el = sc->vptr->pair_cdr(cdr_el);
621 
622  plist = (project_list_t *)g_malloc(sizeof(project_list_t));
623  memset(plist, 0, sizeof(project_list_t));
624  plist->next = project_list_top;
625  project_list_top = plist;
626  plist->layerno = layerno;
627  plist->visible = 1;
628  plist->n_attr = 0;
629  plist->attr_list = NULL;
630  plist->translate_x = plist->translate_y = 0.0;
631  plist->scale_x = plist->scale_y = 1.0;
632  plist->mirror_x = plist->mirror_y = 0;
633 
634  /* Set default alpha value, if alpha value is not in project file */
635  plist->alpha = alpha_def_value;
636 
637  while (sc->vptr->is_pair(car_el)) {
638 
639  name = sc->vptr->pair_car(car_el);
640  value = sc->vptr->pair_cdr(car_el);
641 
642  if (!sc->vptr->is_symbol(name)) {
643  GERB_MESSAGE(_("%s(): non-symbol found, ignoring"), __func__);
644  goto end_name_value_parse;
645  }
646 
647  str = sc->vptr->symname(name);
648  if (strcmp(str, "color") == 0) {
649  get_color(sc, value, plist->rgb);
650  } else if (strcmp(str, "alpha") == 0) {
651  get_alpha(sc, value, &plist->alpha);
652  } else if (strcmp(str, "translate") == 0) {
653  get_double_pair(sc, value, "translate",
654  &plist->translate_x, &plist->translate_y, 0.0);
655  } else if (strcmp(str, "rotation") == 0) {
656  get_double(sc, value, "rotation", &plist->rotation, 0.0);
657  } else if (strcmp(str, "scale") == 0) {
658  get_double_pair(sc, value, "scale",
659  &plist->scale_x, &plist->scale_y, 1.0);
660  } else if (strcmp(str, "mirror") == 0) {
661  get_bool_pair(sc, value, "mirror",
662  &plist->mirror_x, &plist->mirror_y, 0);
663  } else if (strcmp(str, "filename") == 0) {
664  plist->filename = g_strdup(get_value_string(sc, value));
665  plist->filename = convert_path_separators(plist->filename,
666  UNIX_MINGW);
667  plist->is_pnp = 0;
668  } else if (strcmp(str, "pick_and_place") == 0) {
669  plist->filename = g_strdup(get_value_string(sc, value));
670  plist->filename = convert_path_separators(plist->filename,
671  UNIX_MINGW);
672  plist->is_pnp = 1;
673  } else if (strcmp(str, "inverted") == 0) {
674  if (value == sc->F) {
675  plist->inverted = 0;
676  } else if (value == sc->T) {
677  plist->inverted = 1;
678  } else {
679  GERB_MESSAGE(_("Argument to inverted must be #t or #f"));
680  }
681  } else if (strcmp(str, "visible") == 0) {
682  if (value == sc->F) {
683  plist->visible = 0;
684  } else if (value == sc->T) {
685  plist->visible = 1;
686  } else {
687  GERB_MESSAGE(_("Argument to visible must be #t or #f"));
688  }
689  } else if (strcmp(str, "attribs") == 0) {
690  pointer attr_car_el, attr_cdr_el;
691  pointer attr_name, attr_type, attr_value;
692  char *type;
693 
694  dprintf ("Parsing file attributes\n");
695 
696  attr_car_el = sc->vptr->pair_car (value);
697  attr_cdr_el = sc->vptr->pair_cdr (value);
698  while (sc->vptr->is_pair(attr_car_el)) {
699  int p = plist->n_attr;
700  plist->n_attr++;
701  plist->attr_list = (gerbv_HID_Attribute *)
702  realloc (plist->attr_list,
703  plist->n_attr * sizeof (gerbv_HID_Attribute));
704  if (plist->attr_list == NULL ) {
705  fprintf (stderr, _("%s(): realloc failed\n"), __FUNCTION__);
706  exit (1);
707  }
708 
709  /* car */
710  attr_name = sc->vptr->pair_car(attr_car_el);
711 
712  /* cadr */
713  attr_type = sc->vptr->pair_cdr (attr_car_el);
714  attr_type = sc->vptr->pair_car (attr_type);
715 
716  /* caddr */
717  attr_value = sc->vptr->pair_cdr (attr_car_el);
718  attr_value = sc->vptr->pair_cdr (attr_value);
719  attr_value = sc->vptr->pair_car (attr_value);
720 
721  dprintf (" attribute %s, type is %s, value is ",
722  sc->vptr->symname(attr_name),
723  sc->vptr->symname(attr_type));
724 
725  plist->attr_list[p].name = strdup (sc->vptr->symname (attr_name));
726 
727  type = sc->vptr->symname (attr_type);
728 
729  if (strcmp (type, "label") == 0) {
730  dprintf ("%s", sc->vptr->string_value (attr_value));
731  plist->attr_list[p].type = HID_Label;
732  plist->attr_list[p].default_val.str_value =
733  strdup (sc->vptr->string_value (attr_value));
734 
735  } else if (strcmp (type, "integer") == 0) {
736  dprintf ("%ld", sc->vptr->ivalue (attr_value));
737  plist->attr_list[p].type = HID_Integer;
738  plist->attr_list[p].default_val.int_value =
739  sc->vptr->ivalue (attr_value);
740 
741  } else if (strcmp (type, "real") == 0) {
742  dprintf ("%g", sc->vptr->rvalue (attr_value));
743  plist->attr_list[p].type = HID_Real;
744  plist->attr_list[p].default_val.real_value =
745  sc->vptr->rvalue (attr_value);
746 
747  } else if (strcmp (type, "string") == 0) {
748  dprintf ("%s", sc->vptr->string_value (attr_value));
749  plist->attr_list[p].type = HID_String;
750  plist->attr_list[p].default_val.str_value =
751  strdup (sc->vptr->string_value (attr_value));
752 
753  } else if (strcmp (type, "boolean") == 0) {
754  dprintf ("%ld", sc->vptr->ivalue (attr_value));
755  plist->attr_list[p].type = HID_Boolean;
756  plist->attr_list[p].default_val.int_value =
757  sc->vptr->ivalue (attr_value);
758 
759  } else if (strcmp (type, "enum") == 0) {
760  dprintf ("%ld", sc->vptr->ivalue (attr_value));
761  plist->attr_list[p].type = HID_Enum;
762  plist->attr_list[p].default_val.int_value =
763  sc->vptr->ivalue (attr_value);
764 
765  } else if (strcmp (type, "mixed") == 0) {
766  plist->attr_list[p].type = HID_Mixed;
767  plist->attr_list[p].default_val.str_value = NULL;
768  fprintf (stderr, _("%s(): WARNING: HID_Mixed is not yet supported\n"),
769  __FUNCTION__);
770 
771  } else if (strcmp (type, "path") == 0) {
772  dprintf ("%s", sc->vptr->string_value (attr_value));
773  plist->attr_list[p].type = HID_Path;
774  plist->attr_list[p].default_val.str_value =
775  strdup (sc->vptr->string_value (attr_value));
776  } else {
777  fprintf (stderr, _("%s(): Unknown attribute type: \"%s\"\n"),
778  __FUNCTION__, type);
779  }
780  dprintf ("\n");
781 
782  attr_car_el = sc->vptr->pair_car(attr_cdr_el);
783  attr_cdr_el = sc->vptr->pair_cdr(attr_cdr_el);
784  }
785  }
786 
787 end_name_value_parse:
788  car_el = sc->vptr->pair_car(cdr_el);
789  cdr_el = sc->vptr->pair_cdr(cdr_el);
790  }
791 
792  return sc->NIL;
793 } /* define_layer */
794 
795 static pointer
796 set_render_type(scheme *sc, pointer args)
797 {
798  pointer car_el;
799  int r;
800 
801  dprintf("--> entering project.c:%s()\n", __FUNCTION__);
802 
803  if (!sc->vptr->is_pair(args)){
804  GERB_MESSAGE(_("set-render-type!: Too few arguments"));
805  return sc->F;
806  }
807 
808  car_el = sc->vptr->pair_car(args);
809 
810  r = sc->vptr->ivalue (car_el);
811  dprintf ("%s(): Setting render type to %d\n", __FUNCTION__, r);
812  interface_set_render_type (r);
813 
814  return sc->NIL;
815 } /* set_render_type */
816 
817 static pointer
818 gerbv_file_version(scheme *sc, pointer args)
819 {
820  pointer car_el;
821  int r;
822  char *vstr;
823  char *tmps;
824 
825  dprintf("--> entering project.c:%s()\n", __FUNCTION__);
826 
827  if (!sc->vptr->is_pair(args)){
828  GERB_MESSAGE(_("gerbv-file-version!: Too few arguments"));
829  return sc->F;
830  }
831 
832  car_el = sc->vptr->pair_car(args);
833  vstr = get_value_string(sc, car_el);
834 
835  /* find our internal integer code */
836  r = version_str_to_int( vstr );
837 
838  if( r == -1) {
839  r = version_str_to_int( GERBV_DEFAULT_PROJECT_FILE_VERSION );
840  GERB_MESSAGE(_("The project file you are attempting to load has specified that it\n"
841  "uses project file version \"%s\" but this string is not\n"
842  "a valid version. Gerbv will attempt to load the file using\n"
843  "version \"%s\". You may experience unexpected results."),
844  vstr, version_int_to_str( r ));
845  vstr = GERBV_DEFAULT_PROJECT_FILE_VERSION;
846  }
847  if( DEBUG ) {
848  tmps = version_int_to_str( r );
849  printf (_("%s(): Read a project file version of %s (%d)\n"), __FUNCTION__, vstr, r);
850  printf (_(" Translated back to \"%s\"\n"), tmps);
851  g_free (tmps);
852  }
853 
854  dprintf ("%s(): Read a project file version of %s (%d)\n", __FUNCTION__, vstr, r);
855 
856  if ( r > version_str_to_int( GERBV_PROJECT_FILE_VERSION )) {
857  /* The project file we're trying to load is too new for this version of gerbv */
858  GERB_MESSAGE(_("The project file you are attempting to load is version \"%s\"\n"
859  "but this copy of gerbv is only capable of loading project files\n"
860  "using version \"%s\" or older. You may experience unexpected results."),
861  vstr, GERBV_PROJECT_FILE_VERSION);
862  } else {
863  int i = 0;
864  int vok = 0;
865 
866  while( known_versions[i] != NULL ) {
867  if( strcmp( known_versions[i], vstr) == 0 ) {
868  vok = 1;
869  }
870  i++;
871  }
872 
873  if( ! vok ) {
874  /* The project file we're trying to load is not too new
875  * but it is unknown to us
876  */
877  GERB_MESSAGE(_("The project file you are attempting to load is version \"%s\"\n"
878  "which is an unknown version.\n"
879  "You may experience unexpected results."),
880  vstr);
881 
882  }
883  }
884 
885  /*
886  * store the version of the file we're currently loading. This variable is used
887  * by the different functions called by the project file to do anything which is
888  * version specific.
889  */
890  current_file_version = r;
891 
892  return sc->NIL;
893 } /* gerbv_file_version */
894 
895 
905 project_list_t *
906 read_project_file(char const* filename)
907 {
908  struct stat stat_info;
909  scheme *sc;
910  FILE *fd;
911  /* always let the environment variable win so one can force
912  * a particular init.scm. Then we use the default installed
913  * directory based on where the binary has been installed to
914  * (including the possibility of relocation). Then use the
915  * default compiled in directory. After that try the directory
916  * where the binary lives and finally the current directory.
917  */
918  char *initdirs[] = {"$GERBV_SCHEMEINIT","", BACKEND_DIR,
919  mainProject->execpath, ".",
920  NULL};
921  char *initfile;
922 
923 
924  /*
925  * Figure out some directories so we can find init.scm
926  */
927  init_paths(mainProject->execname);
928  initdirs[1] = scmdatadir;
929 
930 #if defined(DEBUG)
931  if (DEBUG > 0)
932  {
933  int i=0;
934 
935  while(initdirs[i] != NULL) {
936  printf("%s(): initdirs[%d] = \"%s\"\n", __FUNCTION__, i, initdirs[i]);
937  i++;
938  }
939  }
940 #endif
941 
942  /*
943  * set the current version of the project file to 1 day before we started adding
944  * versioning to the files. While the file is being loaded, this will
945  * be set to the correct version on newer files and ignored on older files
946  */
947  current_file_version =
948  version_str_to_int(GERBV_DEFAULT_PROJECT_FILE_VERSION);
949 
950  if (stat(filename, &stat_info) || !S_ISREG(stat_info.st_mode)) {
951  GERB_MESSAGE(_("Failed to read %s"), filename);
952 
953  return NULL;
954  }
955 
956  sc = scheme_init_new();
957  scheme_set_output_port_file(sc, stdout);
958 
959  if(!sc){
960  GERB_FATAL_ERROR(_("Couldn't init scheme"));
961  exit(1);
962  }
963 
964  errno = 0;
965  initfile = gerb_find_file("init.scm", initdirs);
966  if (initfile == NULL) {
967  scheme_deinit(sc);
968  GERB_MESSAGE(_("Problem loading init.scm (%s)"), strerror(errno));
969  return NULL;
970  }
971  dprintf("%s(): initfile = \"%s\"\n", __FUNCTION__, initfile);
972 
973  if ((fd = fopen(initfile, "r")) == NULL) {
974  scheme_deinit(sc);
975  GERB_MESSAGE(_("Couldn't open %s (%s)"), initfile, strerror(errno));
976  return NULL;
977  }
978 
979  /* Force gerbv to input decimals as dots */
980  setlocale(LC_NUMERIC, "C");
981 
982  sc->vptr->load_file(sc, fd);
983  fclose(fd);
984 
985  sc->vptr->scheme_define(sc, sc->global_env,
986  sc->vptr->mk_symbol(sc, "define-layer!"),
987  sc->vptr->mk_foreign_func(sc, define_layer));
988 
989  sc->vptr->scheme_define(sc, sc->global_env,
990  sc->vptr->mk_symbol(sc, "set-render-type!"),
991  sc->vptr->mk_foreign_func(sc, set_render_type));
992 
993  sc->vptr->scheme_define(sc, sc->global_env,
994  sc->vptr->mk_symbol(sc, "gerbv-file-version!"),
995  sc->vptr->mk_foreign_func(sc, gerbv_file_version));
996 
997  if ((fd = fopen(filename, "r")) == NULL) {
998  setlocale(LC_NUMERIC, ""); /* Default locale */
999  scheme_deinit(sc);
1000  GERB_MESSAGE(_("Couldn't open project file %s (%s)"), filename,
1001  strerror(errno));
1002 
1003  return NULL;
1004  }
1005 
1006  project_list_top = NULL;
1007 
1008  scheme_load_file(sc, fd);
1009  fclose(fd);
1010 
1011  setlocale(LC_NUMERIC, ""); /* Default locale */
1012  scheme_deinit(sc);
1013 
1014  return project_list_top;
1015 } /* read_project */
1016 
1017 
1018 void
1019 project_destroy_project_list (project_list_t *projectList){
1020  project_list_t *tempP,*tempP2;
1021 
1022  for (tempP = projectList; tempP != NULL; ){
1023  tempP2 = tempP->next;
1024 
1025  g_free (tempP->filename);
1026  gerbv_attribute_destroy_HID_attribute (tempP->attr_list, tempP->n_attr);
1027  tempP->attr_list = NULL;
1028  tempP = tempP2;
1029  }
1030 }
1031 
1032 /*
1033  * Writes a description of a project to a file
1034  * that can be parsed by read_project above
1035  */
1036 int
1037 write_project_file(gerbv_project_t *gerbvProject, char const* filename, project_list_t *project)
1038 {
1039  FILE *fd;
1040  project_list_t *p = project;
1041  int n_attr = 0;
1042  gerbv_HID_Attribute *attr_list = NULL;
1043  const float min_val = 0.000001;
1044  int i;
1045 
1046  if ((fd = fopen(filename, "w")) == NULL) {
1047  GERB_MESSAGE(_("Couldn't save project %s"), filename);
1048  return -1;
1049  }
1050 
1051  /* Force gerbv to input decimals as dots */
1052  setlocale(LC_NUMERIC, "C");
1053 
1054  fprintf(fd, "(gerbv-file-version! \"%s\")\n", GERBV_PROJECT_FILE_VERSION);
1055 
1056  while (p) {
1057  fprintf(fd, "(define-layer! %d ", p->layerno);
1058 
1059  fprintf(fd, "(cons 'filename \"%s\")\n",
1060  convert_path_separators(p->filename, MINGW_UNIX));
1061 
1062  if (p->inverted)
1063  fprintf(fd, "\t(cons 'inverted #t)\n");
1064 
1065  if (p->layerno >= 0) {
1066  fprintf(fd, "\t(cons 'visible #%c)\n", p->visible? 't': 'f');
1067  }
1068 
1069  fprintf(fd, "\t(cons 'color #(%d %d %d))\n",
1070  p->rgb[0], p->rgb[1], p->rgb[2]);
1071 
1072  if (p->layerno >= 0) {
1073  if (p->alpha != alpha_def_value)
1074  fprintf(fd, "\t(cons 'alpha #(%d))\n", p->alpha);
1075 
1076  /* Check if there is transformation. Write if so. */
1077  if ((fabs(p->translate_x) > min_val)
1078  || (fabs(p->translate_y) > min_val)) {
1079  fprintf(fd, "\t(cons 'translate #(%f %f))\n",
1080  p->translate_x, p->translate_y);
1081  }
1082  if (fabs(p->rotation) > min_val) {
1083  fprintf(fd, "\t(cons 'rotation #(%f))\n", p->rotation);
1084  }
1085  if ((fabs(p->scale_x - 1.0) > min_val)
1086  || (fabs(p->scale_y - 1.0) > min_val)) {
1087  fprintf(fd, "\t(cons 'scale #(%f %f))\n",
1088  p->scale_x, p->scale_y);
1089  }
1090  if (p->mirror_x || p->mirror_y) {
1091  fprintf(fd, "\t(cons 'mirror #(#%c #%c))\n",
1092  p->mirror_x? 't': 'f', p->mirror_y? 't': 'f');
1093  }
1094  }
1095  /* now write out the attribute list which specifies the
1096  * file format
1097  */
1098  if (p->layerno < 0) {
1099  attr_list = NULL;
1100  n_attr = 0;
1101  } else {
1102  attr_list = gerbvProject->file[p->layerno]->image->info->attr_list;
1103  n_attr = gerbvProject->file[p->layerno]->image->info->n_attr;
1104  }
1105 
1106  if (n_attr > 0) {
1107  fprintf(fd, "\t(cons 'attribs (list\n");
1108  }
1109  for (i = 0; i < n_attr ; i++) {
1110  switch (attr_list[i].type) {
1111  case HID_Label:
1112  fprintf(fd, "\t\t(list '%s 'Label \"%s\")\n", attr_list[i].name,
1113  attr_list[i].default_val.str_value);
1114  break;
1115 
1116  case HID_Integer:
1117  fprintf(fd, "\t\t(list '%s 'Integer %d)\n", attr_list[i].name,
1118  attr_list[i].default_val.int_value);
1119  break;
1120 
1121  case HID_Real:
1122  fprintf(fd, "\t\t(list '%s 'Real %g)\n", attr_list[i].name,
1123  attr_list[i].default_val.real_value);
1124  break;
1125 
1126  case HID_String:
1127  fprintf(fd, "\t\t(list '%s 'String \"%s\")\n", attr_list[i].name,
1128  attr_list[i].default_val.str_value);
1129  break;
1130 
1131  case HID_Boolean:
1132  fprintf(fd, "\t\t(list '%s 'Boolean %d)\n", attr_list[i].name,
1133  attr_list[i].default_val.int_value);
1134  break;
1135 
1136  case HID_Enum:
1137  fprintf(fd, "\t\t(list '%s 'Enum %d)\n", attr_list[i].name,
1138  attr_list[i].default_val.int_value);
1139  break;
1140 
1141  case HID_Mixed:
1142  dprintf ("HID_Mixed\n");
1143  fprintf (stderr, _("%s(): WARNING: HID_Mixed is not yet supported.\n"),
1144  __FUNCTION__);
1145  break;
1146 
1147  case HID_Path:
1148  fprintf(fd, "\t\t(list '%s 'Path \"%s\")\n", attr_list[i].name,
1149  attr_list[i].default_val.str_value);
1150  break;
1151 
1152  default:
1153  fprintf (stderr, _("%s: unknown type of HID attribute (%d)\n"),
1154  __FUNCTION__, attr_list[i].type);
1155  break;
1156  }
1157  }
1158  if (n_attr > 0) {
1159  fprintf (fd, "\t))\n");
1160  }
1161 
1162  fprintf(fd, ")\n");
1163  p = p->next;
1164  }
1165 
1166  fprintf (fd, "(set-render-type! %d)\n", screenRenderInfo.renderType);
1167 
1168  setlocale(LC_NUMERIC, ""); /* Default locale */
1169 
1170  fclose(fd);
1171 
1172  return 0;
1173 } /* write_project */