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