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