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 
395 /* this really should not be needed but it could
396  * be hooked in to appease malloc debuggers as
397  * we don't otherwise free these variables. However,
398  * they only get malloc-ed once ever so this
399  * is a fixed leak of a small size.
400  */
401 #if 0
402 void
403 destroy_paths ()
404 {
405  if (bindir != NULL) {
406  free (bindir);
407  bindir = NULL;
408  }
409 
410  if (exec_prefix != NULL) {
411  free (exec_prefix);
412  exec_prefix = NULL;
413  }
414 
415  if (pkgdatadir != NULL) {
416  free (pkgdatadir);
417  pkgdatadir = NULL;
418  }
419 
420  if (scmdatadir != NULL) {
421  g_free (scmdatadir);
422  scmdatadir = NULL;
423  }
424 
425 
426 }
427 #endif
428 
429 static void
430 init_paths (char *argv0)
431 {
432  size_t l;
433  int haspath;
434  char *t1, *t2;
435  int found_bindir = 0;
436 
437  /* Only do this stuff once */
438  if (bindir != NULL )
439  return;
440 
441  /* see if argv0 has enough of a path to let lrealpath give the
442  * real path. This should be the case if you invoke gerbv with
443  * something like /usr/local/bin/gerbv or ./gerbv or ./foo/gerbv
444  * but if you just use gerbv and it exists in your path, you'll
445  * just get back gerbv again.
446  */
447 
448  haspath = 0;
449  for (unsigned int i = 0; i < strlen (argv0) ; i++)
450  {
451  if (argv0[i] == GERBV_DIR_SEPARATOR_C)
452  haspath = 1;
453  }
454 
455  DPRINTF("%s (%s): haspath = %d\n", __FUNCTION__, argv0, haspath);
456  if (haspath)
457  {
458  bindir = strdup (lrealpath (argv0));
459  found_bindir = 1;
460  }
461  else
462  {
463  char *path, *p, *tmps;
464  struct stat sb;
465  int r;
466 
467  tmps = getenv ("PATH");
468 
469  if (tmps != NULL)
470  {
471  path = strdup (tmps);
472 
473  /* search through the font path for a font file */
474  for (p = strtok (path, GERBV_PATH_DELIMETER); p && *p;
475  p = strtok (NULL, GERBV_PATH_DELIMETER))
476  {
477  DPRINTF("Looking for %s in %s\n", argv0, p);
478  if ( (tmps = malloc ( (strlen (argv0) + strlen (p) + 2) * sizeof (char))) == NULL )
479  {
480  fprintf (stderr, "malloc failed in %s()\n", __FUNCTION__);
481  exit (1);
482  }
483  sprintf (tmps, "%s%s%s", p, GERBV_DIR_SEPARATOR_S, argv0);
484  r = stat (tmps, &sb);
485  if (r == 0)
486  {
487  DPRINTF("Found it: \"%s\"\n", tmps);
488  bindir = lrealpath (tmps);
489  found_bindir = 1;
490  free (tmps);
491  break;
492  }
493  free (tmps);
494  }
495  free (path);
496  }
497  }
498  DPRINTF("%s(): bindir = \"%s\"\n", __FUNCTION__, bindir);
499 
500 
501  if (found_bindir)
502  {
503  /* strip off the executible name leaving only the path */
504  t2 = NULL;
505  t1 = strchr (bindir, GERBV_DIR_SEPARATOR_C);
506  while (t1 != NULL && *t1 != '\0')
507  {
508  t2 = t1;
509  t1 = strchr (t2 + 1, GERBV_DIR_SEPARATOR_C);
510  }
511  if (t2 != NULL)
512  *t2 = '\0';
513  DPRINTF("After stripping off the executible name, we found\n");
514  DPRINTF("bindir = \"%s\"\n", bindir);
515 
516  }
517  else
518  {
519  /* we have failed to find out anything from argv[0] so fall back to the original
520  * install prefix
521  */
522  bindir = strdup (GERBV_BINDIR);
523  }
524 
525  /* now find the path to exec_prefix */
526  l = strlen (bindir) + 1 + strlen (BINDIR_TO_EXECPREFIX) + 1;
527  if ( (exec_prefix = (char *) malloc (l * sizeof (char) )) == NULL )
528  {
529  fprintf (stderr, "malloc failed in %s()\n", __FUNCTION__);
530  exit (1);
531  }
532  sprintf (exec_prefix, "%s%s%s", bindir, GERBV_DIR_SEPARATOR_S,
533  BINDIR_TO_EXECPREFIX);
534 
535  /* now find the path to PKGDATADIR */
536  l = strlen (bindir) + 1 + strlen (BINDIR_TO_PKGDATADIR) + 1;
537  if ( (pkgdatadir = (char *) malloc (l * sizeof (char) )) == NULL )
538  {
539  fprintf (stderr, "malloc failed in %s()\n", __FUNCTION__);
540  exit (1);
541  }
542  sprintf (pkgdatadir, "%s%s%s", bindir, GERBV_DIR_SEPARATOR_S,
543  BINDIR_TO_PKGDATADIR);
544 
545  scmdatadir = g_strdup_printf ("%s%s%s", pkgdatadir, GERBV_DIR_SEPARATOR_S, GERBV_SCMSUBDIR);
546 
547  DPRINTF("%s(): bindir = %s\n", __FUNCTION__, bindir);
548  DPRINTF("%s(): exec_prefix = %s\n", __FUNCTION__, exec_prefix);
549  DPRINTF("%s(): pkgdatadir = %s\n", __FUNCTION__, pkgdatadir);
550  DPRINTF("%s(): scmdatadir = %s\n", __FUNCTION__, scmdatadir);
551 
552 }
553 
554 
555 static char *
556 get_value_string(scheme *sc, pointer value)
557 {
558  if (!sc->vptr->is_string(value))
559  return NULL;
560 
561  return sc->vptr->string_value(value);
562 } /* get_value_string */
563 
564 
567 static char *
568 convert_path_separators(char* path, int conv_flag)
569 {
570  if (path == NULL) return NULL;
571 
572 #if defined (__MINGW32__)
573  char *hit_in_path;
574 
575  switch (conv_flag) {
576 
577  case MINGW_UNIX:
578  while ((hit_in_path = strchr(path, '\\'))) {
579  *hit_in_path = '/';
580  }
581  break;
582  case UNIX_MINGW:
583  while ((hit_in_path = strchr(path, '/'))) {
584  *hit_in_path = '\\';
585  }
586  break;
587  }
588 #endif
589 
590  return path;
591 }/* convert_path_separators */
592 
593 
594 static pointer
595 define_layer(scheme *sc, pointer args)
596 {
597  pointer car_el, cdr_el, name, value;
598  project_list_t *plist;
599  const char *str;
600  int layerno;
601 
602  DPRINTF("--> entering %s: %s\n", __FILE__, __func__);
603 
604  if (!sc->vptr->is_pair(args)) {
605  GERB_MESSAGE(_("%s(): too few arguments"), __func__);
606 
607  return sc->F;
608  }
609 
610  car_el = sc->vptr->pair_car(args);
611  cdr_el = sc->vptr->pair_cdr(args);
612 
613  if (!sc->vptr->is_integer(car_el) || !sc->vptr->is_number(car_el)) {
614  GERB_MESSAGE(_("%s(): layer number missing/incorrect"), __func__);
615 
616  return sc->F;
617  }
618 
619  layerno = sc->vptr->ivalue(car_el);
620  DPRINTF(" layerno = %d\n", layerno);
621 
622  car_el = sc->vptr->pair_car(cdr_el);
623  cdr_el = sc->vptr->pair_cdr(cdr_el);
624 
625  plist = g_new0(project_list_t, 1);
626  plist->next = project_list_top;
627  project_list_top = plist;
628  plist->layerno = layerno;
629  plist->visible = 1;
630  plist->n_attr = 0;
631  plist->attr_list = NULL;
632  plist->translate_x = plist->translate_y = 0.0;
633  plist->scale_x = plist->scale_y = 1.0;
634  plist->mirror_x = plist->mirror_y = 0;
635 
636  /* Set default alpha value, if alpha value is not in project file */
637  plist->alpha = alpha_def_value;
638 
639  while (sc->vptr->is_pair(car_el)) {
640 
641  name = sc->vptr->pair_car(car_el);
642  value = sc->vptr->pair_cdr(car_el);
643 
644  if (!sc->vptr->is_symbol(name)) {
645  GERB_MESSAGE(_("%s(): non-symbol found, ignoring"), __func__);
646  goto end_name_value_parse;
647  }
648 
649  str = sc->vptr->symname(name);
650  if (strcmp(str, "color") == 0) {
651  get_color(sc, value, plist->rgb);
652  } else if (strcmp(str, "alpha") == 0) {
653  get_alpha(sc, value, &plist->alpha);
654  } else if (strcmp(str, "translate") == 0) {
655  get_double_pair(sc, value, "translate",
656  &plist->translate_x, &plist->translate_y, 0.0);
657  } else if (strcmp(str, "rotation") == 0) {
658  get_double(sc, value, "rotation", &plist->rotation, 0.0);
659  } else if (strcmp(str, "scale") == 0) {
660  get_double_pair(sc, value, "scale",
661  &plist->scale_x, &plist->scale_y, 1.0);
662  } else if (strcmp(str, "mirror") == 0) {
663  get_bool_pair(sc, value, "mirror",
664  &plist->mirror_x, &plist->mirror_y, 0);
665  } else if (strcmp(str, "filename") == 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 = 0;
670  } else if (strcmp(str, "pick_and_place") == 0) {
671  plist->filename = g_strdup(get_value_string(sc, value));
672  plist->filename = convert_path_separators(plist->filename,
673  UNIX_MINGW);
674  plist->is_pnp = 1;
675  } else if (strcmp(str, "inverted") == 0) {
676  if (value == sc->F) {
677  plist->inverted = 0;
678  } else if (value == sc->T) {
679  plist->inverted = 1;
680  } else {
681  GERB_MESSAGE(_("Argument to inverted must be #t or #f"));
682  }
683  } else if (strcmp(str, "visible") == 0) {
684  if (value == sc->F) {
685  plist->visible = 0;
686  } else if (value == sc->T) {
687  plist->visible = 1;
688  } else {
689  GERB_MESSAGE(_("Argument to visible must be #t or #f"));
690  }
691  } else if (strcmp(str, "attribs") == 0) {
692  pointer attr_car_el, attr_cdr_el;
693  pointer attr_name, attr_type, attr_value;
694  char *type;
695 
696  DPRINTF("Parsing file attributes\n");
697 
698  attr_car_el = sc->vptr->pair_car (value);
699  attr_cdr_el = sc->vptr->pair_cdr (value);
700  while (sc->vptr->is_pair(attr_car_el)) {
701  int p = plist->n_attr;
702  plist->n_attr++;
703  plist->attr_list = (gerbv_HID_Attribute *)
704  realloc (plist->attr_list,
705  plist->n_attr * sizeof (gerbv_HID_Attribute));
706  if (plist->attr_list == NULL ) {
707  fprintf (stderr, _("%s(): realloc failed\n"), __FUNCTION__);
708  exit (1);
709  }
710 
711  /* car */
712  attr_name = sc->vptr->pair_car(attr_car_el);
713 
714  /* cadr */
715  attr_type = sc->vptr->pair_cdr (attr_car_el);
716  attr_type = sc->vptr->pair_car (attr_type);
717 
718  /* caddr */
719  attr_value = sc->vptr->pair_cdr (attr_car_el);
720  attr_value = sc->vptr->pair_cdr (attr_value);
721  attr_value = sc->vptr->pair_car (attr_value);
722 
723  DPRINTF(" attribute %s, type is %s, value is ",
724  sc->vptr->symname(attr_name),
725  sc->vptr->symname(attr_type));
726 
727  plist->attr_list[p].name = strdup (sc->vptr->symname (attr_name));
728 
729  type = sc->vptr->symname (attr_type);
730 
731  plist->attr_list[p].default_val.str_value = NULL;
732  if (strcmp (type, "label") == 0) {
733  DPRINTF("%s", sc->vptr->string_value (attr_value));
734  plist->attr_list[p].type = HID_Label;
735  plist->attr_list[p].default_val.str_value =
736  strdup (sc->vptr->string_value (attr_value));
737 
738  } else if (strcmp (type, "integer") == 0) {
739  DPRINTF("%ld", sc->vptr->ivalue (attr_value));
740  plist->attr_list[p].type = HID_Integer;
741  plist->attr_list[p].default_val.int_value =
742  sc->vptr->ivalue (attr_value);
743 
744  } else if (strcmp (type, "real") == 0) {
745  DPRINTF("%g", sc->vptr->rvalue (attr_value));
746  plist->attr_list[p].type = HID_Real;
747  plist->attr_list[p].default_val.real_value =
748  sc->vptr->rvalue (attr_value);
749 
750  } else if (strcmp (type, "string") == 0) {
751  DPRINTF("%s", sc->vptr->string_value (attr_value));
752  plist->attr_list[p].type = HID_String;
753  plist->attr_list[p].default_val.str_value =
754  strdup (sc->vptr->string_value (attr_value));
755 
756  } else if (strcmp (type, "boolean") == 0) {
757  DPRINTF("%ld", sc->vptr->ivalue (attr_value));
758  plist->attr_list[p].type = HID_Boolean;
759  plist->attr_list[p].default_val.int_value =
760  sc->vptr->ivalue (attr_value);
761 
762  } else if (strcmp (type, "enum") == 0) {
763  DPRINTF("%ld", sc->vptr->ivalue (attr_value));
764  plist->attr_list[p].type = HID_Enum;
765  plist->attr_list[p].default_val.int_value =
766  sc->vptr->ivalue (attr_value);
767 
768  } else if (strcmp (type, "mixed") == 0) {
769  plist->attr_list[p].type = HID_Mixed;
770  plist->attr_list[p].default_val.str_value = NULL;
771  fprintf (stderr, _("%s(): WARNING: HID_Mixed is not yet supported\n"),
772  __FUNCTION__);
773 
774  } else if (strcmp (type, "path") == 0) {
775  DPRINTF("%s", sc->vptr->string_value (attr_value));
776  plist->attr_list[p].type = HID_Path;
777  plist->attr_list[p].default_val.str_value =
778  strdup (sc->vptr->string_value (attr_value));
779  } else {
780  fprintf (stderr, _("%s(): Unknown attribute type: \"%s\"\n"),
781  __FUNCTION__, type);
782  }
783  DPRINTF("\n");
784 
785  attr_car_el = sc->vptr->pair_car(attr_cdr_el);
786  attr_cdr_el = sc->vptr->pair_cdr(attr_cdr_el);
787  }
788  } else {
789  GERB_MESSAGE(_("Ignoring \"%s\" in project file"), str);
790  }
791 
792 end_name_value_parse:
793  car_el = sc->vptr->pair_car(cdr_el);
794  cdr_el = sc->vptr->pair_cdr(cdr_el);
795  }
796 
797  return sc->NIL;
798 } /* define_layer */
799 
800 static pointer
801 set_render_type(scheme *sc, pointer args)
802 {
803  pointer car_el;
804  int r;
805 
806  DPRINTF("--> entering project.c:%s()\n", __FUNCTION__);
807 
808  if (!sc->vptr->is_pair(args)){
809  GERB_MESSAGE(_("set-render-type!: Too few arguments"));
810  return sc->F;
811  }
812 
813  car_el = sc->vptr->pair_car(args);
814 
815  r = sc->vptr->ivalue (car_el);
816  DPRINTF("%s(): Setting render type to %d\n", __FUNCTION__, r);
817  interface_set_render_type (r);
818 
819  return sc->NIL;
820 } /* set_render_type */
821 
822 static pointer
823 gerbv_file_version(scheme *sc, pointer args)
824 {
825  pointer car_el;
826  int r;
827  char *vstr;
828  char *tmps;
829 
830  DPRINTF("--> entering project.c:%s()\n", __FUNCTION__);
831 
832  if (!sc->vptr->is_pair(args)){
833  GERB_MESSAGE(_("gerbv-file-version!: Too few arguments"));
834  return sc->F;
835  }
836 
837  car_el = sc->vptr->pair_car(args);
838  vstr = get_value_string(sc, car_el);
839 
840  /* find our internal integer code */
841  r = version_str_to_int( vstr );
842 
843  if( r == -1) {
844  r = version_str_to_int( GERBV_DEFAULT_PROJECT_FILE_VERSION );
845  GERB_MESSAGE(_("The project file you are attempting to load has specified that it\n"
846  "uses project file version \"%s\" but this string is not\n"
847  "a valid version. Gerbv will attempt to load the file using\n"
848  "version \"%s\". You may experience unexpected results."),
849  vstr, version_int_to_str( r ));
850  vstr = GERBV_DEFAULT_PROJECT_FILE_VERSION;
851  }
852  if( DEBUG ) {
853  tmps = version_int_to_str( r );
854  printf (_("%s(): Read a project file version of %s (%d)\n"), __FUNCTION__, vstr, r);
855  printf (_(" Translated back to \"%s\"\n"), tmps);
856  g_free (tmps);
857  }
858 
859  DPRINTF("%s(): Read a project file version of %s (%d)\n", __FUNCTION__, vstr, r);
860 
861  if ( r > version_str_to_int( GERBV_PROJECT_FILE_VERSION )) {
862  /* The project file we're trying to load is too new for this version of gerbv */
863  GERB_MESSAGE(_("The project file you are attempting to load is version \"%s\"\n"
864  "but this copy of gerbv is only capable of loading project files\n"
865  "using version \"%s\" or older. You may experience unexpected results."),
866  vstr, GERBV_PROJECT_FILE_VERSION);
867  } else {
868  int i = 0;
869  int vok = 0;
870 
871  while( known_versions[i] != NULL ) {
872  if( strcmp( known_versions[i], vstr) == 0 ) {
873  vok = 1;
874  }
875  i++;
876  }
877 
878  if( ! vok ) {
879  /* The project file we're trying to load is not too new
880  * but it is unknown to us
881  */
882  GERB_MESSAGE(_("The project file you are attempting to load is version \"%s\"\n"
883  "which is an unknown version.\n"
884  "You may experience unexpected results."),
885  vstr);
886 
887  }
888  }
889 
890  /*
891  * store the version of the file we're currently loading. This variable is used
892  * by the different functions called by the project file to do anything which is
893  * version specific.
894  */
895  current_file_version = r;
896 
897  return sc->NIL;
898 } /* gerbv_file_version */
899 
905 int
906 project_is_gerbv_project(const char *filename, gboolean *ret)
907 {
908  FILE *fd;
909  *ret = FALSE;
910  char *buf;
911  const gsize buf_size = 200;
912 
913  fd = g_fopen(filename, "rb");
914  if (fd == NULL) {
915  GERB_MESSAGE(_("Failed to open \"%s\" for reading: %s"),
916  filename, strerror(errno));
917  return -1;
918  }
919 
920  buf = (char *) g_malloc(buf_size);
921  if (buf == NULL)
922  GERB_FATAL_ERROR("malloc buf failed while checking for "
923  "Gerbv project in %s()", __FUNCTION__);
924 
925  if (fgets(buf, buf_size, fd) != NULL)
926  *ret = (g_strrstr(buf, "gerbv-file-version") != NULL);
927 
928  fclose(fd);
929  g_free(buf);
930 
931  return 0;
932 }
933 
943 project_list_t *
944 read_project_file(char const* filename)
945 {
946  struct stat stat_info;
947  scheme *sc;
948  FILE *fd;
949  /* always let the environment variable win so one can force
950  * a particular init.scm. Then we use the default installed
951  * directory based on where the binary has been installed to
952  * (including the possibility of relocation). Then use the
953  * default compiled in directory. After that try the directory
954  * where the binary lives and finally the current directory.
955  */
956  char *initdirs[] = {"$GERBV_SCHEMEINIT","", GERBV_BACKEND_DIR,
957  mainProject->execpath, ".",
958  NULL};
959  char *initfile;
960 
961 
962  /*
963  * Figure out some directories so we can find init.scm
964  */
965  init_paths(mainProject->execname);
966  initdirs[1] = scmdatadir;
967 
968 #if defined(DEBUG)
969  if (DEBUG > 0)
970  {
971  int i=0;
972 
973  while(initdirs[i] != NULL) {
974  printf("%s(): initdirs[%d] = \"%s\"\n", __FUNCTION__, i, initdirs[i]);
975  i++;
976  }
977  }
978 #endif
979 
980  /*
981  * set the current version of the project file to 1 day before we started adding
982  * versioning to the files. While the file is being loaded, this will
983  * be set to the correct version on newer files and ignored on older files
984  */
985  current_file_version =
986  version_str_to_int(GERBV_DEFAULT_PROJECT_FILE_VERSION);
987 
988  if (stat(filename, &stat_info) || !S_ISREG(stat_info.st_mode)) {
989  GERB_MESSAGE(_("Failed to read %s"), filename);
990 
991  return NULL;
992  }
993 
994  sc = scheme_init_new();
995  scheme_set_output_port_file(sc, stdout);
996 
997  if(!sc){
998  GERB_FATAL_ERROR(_("Couldn't init scheme"));
999  exit(1);
1000  }
1001 
1002  errno = 0;
1003  initfile = gerb_find_file("init.scm", initdirs);
1004  if (initfile == NULL) {
1005  scheme_deinit(sc);
1006  GERB_MESSAGE(_("Problem loading init.scm (%s)"), strerror(errno));
1007  return NULL;
1008  }
1009  DPRINTF("%s(): initfile = \"%s\"\n", __FUNCTION__, initfile);
1010 
1011  if ((fd = g_fopen(initfile, "r")) == NULL) {
1012  scheme_deinit(sc);
1013  GERB_MESSAGE(_("Couldn't open %s (%s)"), initfile, strerror(errno));
1014  return NULL;
1015  }
1016 
1017  /* Force gerbv to input decimals as dots */
1018  setlocale(LC_NUMERIC, "C");
1019 
1020  sc->vptr->load_file(sc, fd);
1021  fclose(fd);
1022 
1023  sc->vptr->scheme_define(sc, sc->global_env,
1024  sc->vptr->mk_symbol(sc, "define-layer!"),
1025  sc->vptr->mk_foreign_func(sc, define_layer));
1026 
1027  sc->vptr->scheme_define(sc, sc->global_env,
1028  sc->vptr->mk_symbol(sc, "set-render-type!"),
1029  sc->vptr->mk_foreign_func(sc, set_render_type));
1030 
1031  sc->vptr->scheme_define(sc, sc->global_env,
1032  sc->vptr->mk_symbol(sc, "gerbv-file-version!"),
1033  sc->vptr->mk_foreign_func(sc, gerbv_file_version));
1034 
1035  if ((fd = g_fopen(filename, "r")) == NULL) {
1036  setlocale(LC_NUMERIC, ""); /* Default locale */
1037  scheme_deinit(sc);
1038  GERB_MESSAGE(_("Couldn't open project file %s (%s)"), filename,
1039  strerror(errno));
1040 
1041  return NULL;
1042  }
1043 
1044  project_list_top = NULL;
1045 
1046  scheme_load_file(sc, fd);
1047  fclose(fd);
1048 
1049  setlocale(LC_NUMERIC, ""); /* Default locale */
1050  scheme_deinit(sc);
1051 
1052  return project_list_top;
1053 } /* read_project */
1054 
1055 
1056 void
1057 project_destroy_project_list (project_list_t *projectList){
1058  project_list_t *tempP,*tempP2;
1059 
1060  for (tempP = projectList; tempP != NULL; ){
1061  tempP2 = tempP->next;
1062 
1063  g_free (tempP->filename);
1064  gerbv_attribute_destroy_HID_attribute (tempP->attr_list, tempP->n_attr);
1065  tempP->attr_list = NULL;
1066  tempP = tempP2;
1067  }
1068 }
1069 
1070 /*
1071  * Writes a description of a project to a file
1072  * that can be parsed by read_project above
1073  */
1074 int
1075 write_project_file(gerbv_project_t *gerbvProject, char const* filename, project_list_t *project)
1076 {
1077  FILE *fd;
1078  project_list_t *p = project;
1079  int n_attr = 0;
1080  gerbv_HID_Attribute *attr_list = NULL;
1081  const float min_val = GERBV_PRECISION_LINEAR_INCH;
1082  int i;
1083 
1084  if ((fd = g_fopen(filename, "w")) == NULL) {
1085  GERB_MESSAGE(_("Couldn't save project %s"), filename);
1086  return -1;
1087  }
1088 
1089  /* Force gerbv to input decimals as dots */
1090  setlocale(LC_NUMERIC, "C");
1091 
1092  fprintf(fd, "(gerbv-file-version! \"%s\")\n", GERBV_PROJECT_FILE_VERSION);
1093 
1094  while (p) {
1095  fprintf(fd, "(define-layer! %d ", p->layerno);
1096 
1097  fprintf(fd, "(cons 'filename \"%s\")\n",
1098  convert_path_separators(p->filename, MINGW_UNIX));
1099 
1100  if (p->inverted)
1101  fprintf(fd, "\t(cons 'inverted #t)\n");
1102 
1103  if (p->layerno >= 0) {
1104  fprintf(fd, "\t(cons 'visible #%c)\n", p->visible? 't': 'f');
1105  }
1106 
1107  fprintf(fd, "\t(cons 'color #(%d %d %d))\n",
1108  p->rgb[0], p->rgb[1], p->rgb[2]);
1109 
1110  if (p->layerno >= 0) {
1111  if (p->alpha != alpha_def_value)
1112  fprintf(fd, "\t(cons 'alpha #(%d))\n", p->alpha);
1113 
1114  /* Check if there is transformation. Write if so. */
1115  if ((fabs(p->translate_x) > min_val)
1116  || (fabs(p->translate_y) > min_val)) {
1117  fprintf(fd, "\t(cons 'translate #(%f %f))\n",
1118  p->translate_x, p->translate_y);
1119  }
1120  if (fabs(p->rotation) > GERBV_PRECISION_ANGLE_RAD) {
1121  fprintf(fd, "\t(cons 'rotation #(%f))\n", p->rotation);
1122  }
1123  if ((fabs(p->scale_x - 1.0) > min_val)
1124  || (fabs(p->scale_y - 1.0) > min_val)) {
1125  fprintf(fd, "\t(cons 'scale #(%f %f))\n",
1126  p->scale_x, p->scale_y);
1127  }
1128  if (p->mirror_x || p->mirror_y) {
1129  fprintf(fd, "\t(cons 'mirror #(#%c #%c))\n",
1130  p->mirror_x? 't': 'f', p->mirror_y? 't': 'f');
1131  }
1132  }
1133  /* now write out the attribute list which specifies the
1134  * file format
1135  */
1136  if (p->layerno < 0) {
1137  attr_list = NULL;
1138  n_attr = 0;
1139  } else {
1140  attr_list = gerbvProject->file[p->layerno]->image->info->attr_list;
1141  n_attr = gerbvProject->file[p->layerno]->image->info->n_attr;
1142  }
1143 
1144  if (n_attr > 0) {
1145  fprintf(fd, "\t(cons 'attribs (list\n");
1146  }
1147  for (i = 0; i < n_attr ; i++) {
1148  switch (attr_list[i].type) {
1149  case HID_Label:
1150  fprintf(fd, "\t\t(list '%s 'Label \"%s\")\n", attr_list[i].name,
1151  attr_list[i].default_val.str_value);
1152  break;
1153 
1154  case HID_Integer:
1155  fprintf(fd, "\t\t(list '%s 'Integer %d)\n", attr_list[i].name,
1156  attr_list[i].default_val.int_value);
1157  break;
1158 
1159  case HID_Real:
1160  fprintf(fd, "\t\t(list '%s 'Real %g)\n", attr_list[i].name,
1161  attr_list[i].default_val.real_value);
1162  break;
1163 
1164  case HID_String:
1165  fprintf(fd, "\t\t(list '%s 'String \"%s\")\n", attr_list[i].name,
1166  attr_list[i].default_val.str_value);
1167  break;
1168 
1169  case HID_Boolean:
1170  fprintf(fd, "\t\t(list '%s 'Boolean %d)\n", attr_list[i].name,
1171  attr_list[i].default_val.int_value);
1172  break;
1173 
1174  case HID_Enum:
1175  fprintf(fd, "\t\t(list '%s 'Enum %d)\n", attr_list[i].name,
1176  attr_list[i].default_val.int_value);
1177  break;
1178 
1179  case HID_Mixed:
1180  DPRINTF("HID_Mixed\n");
1181  fprintf (stderr, _("%s(): WARNING: HID_Mixed is not yet supported.\n"),
1182  __FUNCTION__);
1183  break;
1184 
1185  case HID_Path:
1186  fprintf(fd, "\t\t(list '%s 'Path \"%s\")\n", attr_list[i].name,
1187  attr_list[i].default_val.str_value);
1188  break;
1189 
1190  default:
1191  fprintf (stderr, _("%s: unknown type of HID attribute (%d)\n"),
1192  __FUNCTION__, attr_list[i].type);
1193  break;
1194  }
1195  }
1196  if (n_attr > 0) {
1197  fprintf (fd, "\t))\n");
1198  }
1199 
1200  fprintf(fd, ")\n");
1201  p = p->next;
1202  }
1203 
1204  fprintf (fd, "(set-render-type! %d)\n", screenRenderInfo.renderType);
1205 
1206  setlocale(LC_NUMERIC, ""); /* Default locale */
1207 
1208  fclose(fd);
1209 
1210  return 0;
1211 } /* 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:568
project_list_t * read_project_file(char const *filename)
Reads the content of a project file.
Definition: project.c:944
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:906
Header info for loading and saving project files.
Header info for the rendering support functions for gerbv.
gerbv_image_t * image
Definition: gerbv.h:736
gerbv_image_info_t * info
Definition: gerbv.h:728
gerbv_fileinfo_t ** file
Definition: gerbv.h:752
gchar * execname
Definition: gerbv.h:760
gchar * execpath
Definition: gerbv.h:759
gerbv_render_types_t renderType
Definition: gerbv.h:779