Add support for filling / thindrawing raw polygons to the HID interface
[geda-pcb/gde.git] / src / hid / common / hidinit.c
blob9581d32cd0e04f2165a56ced969fa04a478fac14
1 /* $Id$ */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
11 #ifdef HAVE_DLFCN_H
12 #include <dlfcn.h>
13 #endif
15 #include <dirent.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <unistd.h>
20 #if defined(WIN32) && defined(HAVE_WINDOWS_H)
21 #include <windows.h>
22 #endif
24 #include "global.h"
25 #include "hid.h"
26 #include "../hidint.h"
28 /* for dlopen() and friends on windows */
29 #include "compat.h"
31 #include "error.h"
32 #include "global.h"
33 #include "misc.h"
35 #ifdef HAVE_LIBDMALLOC
36 #include <dmalloc.h>
37 #endif
39 RCSID ("$Id$");
41 #define HID_DEF(x) extern void hid_ ## x ## _init(void);
42 #include "hid/common/hidlist.h"
43 #undef HID_DEF
45 HID **hid_list = 0;
46 int hid_num_hids = 0;
48 extern HID hid_nogui;
50 HID *gui = &hid_nogui;
51 HID *exporter = NULL;
53 int pixel_slop = 1;
55 static void
56 hid_load_dir (char *dirname)
58 DIR *dir;
59 struct dirent *de;
61 dir = opendir (dirname);
62 if (!dir)
64 free (dirname);
65 return;
67 while ((de = readdir (dir)) != NULL)
69 void *sym;
70 void (*symv)();
71 void *so;
72 char *basename, *path, *symname;
73 struct stat st;
75 basename = strdup (de->d_name);
76 if (strlen (basename) > 3
77 && strcasecmp (basename+strlen(basename)-3, ".so") == 0)
78 basename[strlen(basename)-3] = 0;
79 else if (strlen (basename) > 4
80 && strcasecmp (basename+strlen(basename)-4, ".dll") == 0)
81 basename[strlen(basename)-4] = 0;
82 path = Concat (dirname, PCB_DIR_SEPARATOR_S, de->d_name, NULL);
84 if (stat (path, &st) == 0
85 && (
86 /* mingw and win32 do not support S_IXGRP or S_IXOTH */
87 #if defined(S_IXGRP)
88 (st.st_mode & S_IXGRP) ||
89 #endif
90 #if defined(S_IXOTH)
91 (st.st_mode & S_IXOTH) ||
92 #endif
93 (st.st_mode & S_IXUSR) )
94 && S_ISREG (st.st_mode))
96 if ((so = dlopen (path, RTLD_NOW | RTLD_GLOBAL)) == NULL)
98 fprintf(stderr, "dl_error: %s\n", dlerror ());
100 else
102 symname = Concat ("hid_", basename, "_init", NULL);
103 if ((sym = dlsym (so, symname)) != NULL)
105 symv = (void (*)()) sym;
106 symv();
108 else if ((sym = dlsym (so, "pcb_plugin_init")) != NULL)
110 symv = (void (*)()) sym;
111 symv();
113 free (symname);
116 free (basename);
117 free (path);
119 free (dirname);
122 void
123 hid_init ()
126 gui = &hid_nogui;
127 #define HID_DEF(x) hid_ ## x ## _init();
128 #include "hid/common/hidlist.h"
129 #undef HID_DEF
131 hid_load_dir (Concat (exec_prefix, PCB_DIR_SEPARATOR_S, "lib",
132 PCB_DIR_SEPARATOR_S, "pcb",
133 PCB_DIR_SEPARATOR_S, "plugins",
134 PCB_DIR_SEPARATOR_S, HOST, NULL));
135 hid_load_dir (Concat (exec_prefix, PCB_DIR_SEPARATOR_S, "lib",
136 PCB_DIR_SEPARATOR_S, "pcb",
137 PCB_DIR_SEPARATOR_S, "plugins", NULL));
139 /* homedir is set by the core immediately on startup */
140 if (homedir != NULL)
142 hid_load_dir (Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb",
143 PCB_DIR_SEPARATOR_S, "plugins",
144 PCB_DIR_SEPARATOR_S, HOST, NULL));
145 hid_load_dir (Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb",
146 PCB_DIR_SEPARATOR_S, "plugins", NULL));
148 hid_load_dir (Concat ("plugins", PCB_DIR_SEPARATOR_S, HOST, NULL));
149 hid_load_dir (Concat ("plugins", NULL));
152 void
153 hid_register_hid (HID * hid)
155 int i;
156 int sz = (hid_num_hids + 2) * sizeof (HID *);
158 if (hid->struct_size != sizeof (HID))
160 fprintf (stderr, "Warning: hid \"%s\" has an incompatible ABI.\n",
161 hid->name);
162 return;
165 for (i=0; i<hid_num_hids; i++)
166 if (hid == hid_list[i])
167 return;
169 hid_num_hids++;
170 if (hid_list)
171 hid_list = (HID **) realloc (hid_list, sz);
172 else
173 hid_list = (HID **) malloc (sz);
175 hid_list[hid_num_hids - 1] = hid;
176 hid_list[hid_num_hids] = 0;
179 static void (*gui_start) (int *, char ***) = 0;
180 static HID *default_gui = 0;
182 void
183 hid_register_gui (HID * Pgui, void (*func) (int *, char ***))
185 if (gui_start)
186 return;
188 default_gui = Pgui;
189 gui_start = func;
193 HID *
194 hid_find_gui ()
196 int i;
198 for (i = 0; i < hid_num_hids; i++)
199 if (!hid_list[i]->printer && !hid_list[i]->exporter)
200 return hid_list[i];
202 fprintf (stderr, "Error: No GUI available.\n");
203 exit (1);
206 HID *
207 hid_find_printer ()
209 int i;
211 for (i = 0; i < hid_num_hids; i++)
212 if (hid_list[i]->printer)
213 return hid_list[i];
215 return 0;
218 HID *
219 hid_find_exporter (const char *which)
221 int i;
223 for (i = 0; i < hid_num_hids; i++)
224 if (hid_list[i]->exporter && strcmp (which, hid_list[i]->name) == 0)
225 return hid_list[i];
227 fprintf (stderr, "Invalid exporter %s, available ones:", which);
228 for (i = 0; i < hid_num_hids; i++)
229 if (hid_list[i]->exporter)
230 fprintf (stderr, " %s", hid_list[i]->name);
231 fprintf (stderr, "\n");
233 return 0;
236 HID **
237 hid_enumerate ()
239 return hid_list;
242 HID_AttrNode *hid_attr_nodes = 0;
244 void
245 hid_register_attributes (HID_Attribute * a, int n)
247 HID_AttrNode *ha;
249 /* printf("%d attributes registered\n", n); */
250 ha = (HID_AttrNode *) malloc (sizeof (HID_AttrNode));
251 ha->next = hid_attr_nodes;
252 hid_attr_nodes = ha;
253 ha->attributes = a;
254 ha->n = n;
257 void
258 hid_parse_command_line (int *argc, char ***argv)
260 HID_AttrNode *ha;
261 int i, e, ok;
263 (*argc)--;
264 (*argv)++;
266 for (ha = hid_attr_nodes; ha; ha = ha->next)
267 for (i = 0; i < ha->n; i++)
269 HID_Attribute *a = ha->attributes + i;
270 switch (a->type)
272 case HID_Label:
273 break;
274 case HID_Integer:
275 if (a->value)
276 *(int *) a->value = a->default_val.int_value;
277 break;
278 case HID_Boolean:
279 if (a->value)
280 *(char *) a->value = a->default_val.int_value;
281 break;
282 case HID_Real:
283 if (a->value)
284 *(double *) a->value = a->default_val.real_value;
285 break;
286 case HID_String:
287 if (a->value)
288 *(char **) a->value = a->default_val.str_value;
289 break;
290 case HID_Enum:
291 if (a->value)
292 *(int *) a->value = a->default_val.int_value;
293 break;
294 default:
295 abort ();
299 while (*argc && (*argv)[0][0] == '-' && (*argv)[0][1] == '-')
301 int bool_val;
302 int arg_ofs;
304 bool_val = 1;
305 arg_ofs = 2;
306 try_no_arg:
307 for (ha = hid_attr_nodes; ha; ha = ha->next)
308 for (i = 0; i < ha->n; i++)
309 if (strcmp ((*argv)[0] + arg_ofs, ha->attributes[i].name) == 0)
311 HID_Attribute *a = ha->attributes + i;
312 char *ep;
313 switch (ha->attributes[i].type)
315 case HID_Label:
316 break;
317 case HID_Integer:
318 if (a->value)
319 *(int *) a->value = strtol ((*argv)[1], 0, 0);
320 else
321 a->default_val.int_value = strtol ((*argv)[1], 0, 0);
322 (*argc)--;
323 (*argv)++;
324 break;
325 case HID_Real:
326 if (a->value)
327 *(double *) a->value = strtod ((*argv)[1], 0);
328 else
329 a->default_val.real_value = strtod ((*argv)[1], 0);
330 (*argc)--;
331 (*argv)++;
332 break;
333 case HID_String:
334 if (a->value)
335 *(char **) a->value = (*argv)[1];
336 else
337 a->default_val.str_value = (*argv)[1];
338 (*argc)--;
339 (*argv)++;
340 break;
341 case HID_Boolean:
342 if (a->value)
343 *(char *) a->value = bool_val;
344 else
345 a->default_val.int_value = bool_val;
346 break;
347 case HID_Mixed:
348 abort ();
349 a->default_val.real_value = strtod ((*argv)[1], &ep);
350 goto do_enum;
351 case HID_Enum:
352 ep = (*argv)[1];
353 do_enum:
354 ok = 0;
355 for (e = 0; a->enumerations[e]; e++)
356 if (strcmp (a->enumerations[e], (*argv)[1]) == 0)
358 ok = 1;
359 a->default_val.int_value = e;
360 a->default_val.str_value = ep;
361 break;
363 if (!ok)
365 fprintf (stderr,
366 "ERROR: \"%s\" is an unknown value for the --%s option\n",
367 (*argv)[1], a->name);
368 exit (1);
370 (*argc)--;
371 (*argv)++;
372 break;
373 case HID_Path:
374 abort ();
375 a->default_val.str_value = (*argv)[1];
376 (*argc)--;
377 (*argv)++;
378 break;
380 (*argc)--;
381 (*argv)++;
382 ha = 0;
383 goto got_match;
385 if (bool_val == 1 && strncmp ((*argv)[0], "--no-", 5) == 0)
387 bool_val = 0;
388 arg_ofs = 5;
389 goto try_no_arg;
391 fprintf (stderr, "unrecognized option: %s\n", (*argv)[0]);
392 exit (1);
393 got_match:;
396 (*argc)++;
397 (*argv)--;
400 static int
401 attr_hash (HID_Attribute *a)
403 unsigned char *cp = (unsigned char *)a;
404 int i, rv=0;
405 for (i=0; i<(int)((char *)&(a->hash) - (char *)a); i++)
406 rv = (rv * 13) ^ (rv >> 16) ^ cp[i];
407 return rv;
410 void
411 hid_save_settings (int locally)
413 char *fname;
414 struct stat st;
415 FILE *f;
416 HID_AttrNode *ha;
417 int i;
419 if (locally)
421 fname = Concat ("pcb.settings", NULL);
423 else
425 if (homedir == NULL)
426 return;
427 fname = Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb", NULL);
429 if (stat (fname, &st))
430 #ifdef WIN32
431 if (mkdir (fname))
432 #else
433 if (mkdir (fname, 0777))
434 #endif
436 free (fname);
437 return;
439 free (fname);
441 fname = Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb",
442 PCB_DIR_SEPARATOR_S, "settings", NULL);
445 f = fopen (fname, "w");
446 if (!f)
448 Message ("Can't open %s", fname);
449 free (fname);
450 return;
453 for (ha = hid_attr_nodes; ha; ha = ha->next)
455 for (i = 0; i < ha->n; i++)
457 char *str;
458 HID_Attribute *a = ha->attributes + i;
460 if (a->hash == attr_hash (a))
461 fprintf (f, "# ");
462 switch (a->type)
464 case HID_Label:
465 break;
466 case HID_Integer:
467 fprintf (f, "%s = %d\n",
468 a->name,
469 a->value ? *(int *)a->value : a->default_val.int_value);
470 break;
471 case HID_Boolean:
472 fprintf (f, "%s = %d\n",
473 a->name,
474 a->value ? *(char *)a->value : a->default_val.int_value);
475 break;
476 case HID_Real:
477 fprintf (f, "%s = %f\n",
478 a->name,
479 a->value ? *(double *)a->value : a->default_val.real_value);
480 break;
481 case HID_String:
482 case HID_Path:
483 str = a->value ? *(char **)a->value : a->default_val.str_value;
484 fprintf (f, "%s = %s\n",
485 a->name,
486 str ? str : "");
487 break;
488 case HID_Enum:
489 fprintf (f, "%s = %s\n",
490 a->name,
491 a->enumerations[a->value ? *(int *)a->value : a->default_val.int_value]);
492 break;
493 case HID_Mixed:
494 abort ();
495 break;
498 fprintf (f, "\n");
500 fclose (f);
501 free (fname);
504 static void
505 hid_set_attribute (char *name, char *value)
507 HID_AttrNode *ha;
508 int i, e, ok;
510 for (ha = hid_attr_nodes; ha; ha = ha->next)
511 for (i = 0; i < ha->n; i++)
512 if (strcmp (name, ha->attributes[i].name) == 0)
514 HID_Attribute *a = ha->attributes + i;
515 switch (ha->attributes[i].type)
517 case HID_Label:
518 break;
519 case HID_Integer:
520 a->default_val.int_value = strtol (value, 0, 0);
521 break;
522 case HID_Real:
523 a->default_val.real_value = strtod (value, 0);
524 break;
525 case HID_String:
526 a->default_val.str_value = strdup (value);
527 break;
528 case HID_Boolean:
529 a->default_val.int_value = 1;
530 break;
531 case HID_Mixed:
532 abort ();
533 a->default_val.real_value = strtod (value, &value);
534 /* fall through */
535 case HID_Enum:
536 ok = 0;
537 for (e = 0; a->enumerations[e]; e++)
538 if (strcmp (a->enumerations[e], value) == 0)
540 ok = 1;
541 a->default_val.int_value = e;
542 a->default_val.str_value = value;
543 break;
545 if (!ok)
547 fprintf (stderr,
548 "ERROR: \"%s\" is an unknown value for the %s option\n",
549 value, a->name);
550 exit (1);
552 break;
553 case HID_Path:
554 a->default_val.str_value = value;
555 break;
560 static void
561 hid_load_settings_1 (char *fname)
563 char line[1024], *namep, *valp, *cp;
564 FILE *f;
566 f = fopen (fname, "r");
567 if (!f)
569 free (fname);
570 return;
573 free (fname);
574 while (fgets (line, sizeof(line), f) != NULL)
576 for (namep=line; *namep && isspace ((int) *namep); namep++)
578 if (*namep == '#')
579 continue;
580 for (valp=namep; *valp && !isspace((int) *valp); valp++)
582 if (! *valp)
583 continue;
584 *valp++ = 0;
585 while (*valp && (isspace ((int) *valp) || *valp == '='))
586 valp ++;
587 if (! *valp)
588 continue;
589 cp = valp + strlen(valp) - 1;
590 while (cp >= valp && isspace ((int) *cp))
591 *cp-- = 0;
592 hid_set_attribute (namep, valp);
595 fclose (f);
598 void
599 hid_load_settings ()
601 HID_AttrNode *ha;
602 int i;
604 for (ha = hid_attr_nodes; ha; ha = ha->next)
605 for (i = 0; i < ha->n; i++)
606 ha->attributes[i].hash = attr_hash (ha->attributes+i);
608 hid_load_settings_1 (Concat (pcblibdir, PCB_DIR_SEPARATOR_S, "settings", NULL));
609 if (homedir != NULL)
610 hid_load_settings_1 (Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb",
611 PCB_DIR_SEPARATOR_S, "settings", NULL));
612 hid_load_settings_1 (Concat ("pcb.settings", NULL));
615 #define HASH_SIZE 31
617 typedef struct ecache
619 struct ecache *next;
620 const char *name;
621 hidval val;
622 } ecache;
624 typedef struct ccache
626 ecache *colors[HASH_SIZE];
627 ecache *lru;
628 } ccache;
630 static void
631 copy_color (int set, hidval * cval, hidval * aval)
633 if (set)
634 memcpy (cval, aval, sizeof (hidval));
635 else
636 memcpy (aval, cval, sizeof (hidval));
640 hid_cache_color (int set, const char *name, hidval * val, void **vcache)
642 unsigned long hash;
643 const char *cp;
644 ccache *cache;
645 ecache *e;
647 cache = (ccache *) * vcache;
648 if (cache == 0)
649 cache = *vcache = (void *) calloc (sizeof (ccache), 1);
651 if (cache->lru && strcmp (cache->lru->name, name) == 0)
653 copy_color (set, &(cache->lru->val), val);
654 return 1;
657 /* djb2: this algorithm (k=33) was first reported by dan bernstein many
658 * years ago in comp.lang.c. another version of this algorithm (now favored
659 * by bernstein) uses xor: hash(i) = hash(i - 1) * 33 ^ str[i]; the magic
660 * of number 33 (why it works better than many other constants, prime or
661 * not) has never been adequately explained.
663 hash = 5381;
664 for (cp = name, hash = 0; *cp; cp++)
665 hash = ((hash << 5) + hash) + (*cp & 0xff); /* hash * 33 + c */
666 hash %= HASH_SIZE;
668 for (e = cache->colors[hash]; e; e = e->next)
669 if (strcmp (e->name, name) == 0)
671 copy_color (set, &(e->val), val);
672 cache->lru = e;
673 return 1;
675 if (!set)
676 return 0;
678 e = (ecache *) malloc (sizeof (ecache));
679 e->next = cache->colors[hash];
680 cache->colors[hash] = e;
681 e->name = strdup (name);
682 memcpy (&(e->val), val, sizeof (hidval));
683 cache->lru = e;
685 return 1;
688 /* otherwise homeless function, refactored out of the five export HIDs */
689 void
690 derive_default_filename(const char *pcbfile, HID_Attribute *filename_attrib, const char *suffix, char **memory)
692 char *buf;
693 char *pf;
695 if (pcbfile == NULL)
696 pf = strdup ("unknown.pcb");
697 else
698 pf = strdup (pcbfile);
700 if (!pf || (memory && filename_attrib->default_val.str_value != *memory)) return;
702 buf = malloc (strlen (pf) + strlen(suffix) + 1);
703 if (memory) *memory = buf;
704 if (buf) {
705 size_t bl;
706 strcpy (buf, pf);
707 bl = strlen(buf);
708 if (bl > 4 && strcmp (buf + bl - 4, ".pcb") == 0)
709 buf[bl - 4] = 0;
710 strcat(buf, suffix);
711 if (filename_attrib->default_val.str_value)
712 free(filename_attrib->default_val.str_value);
713 filename_attrib->default_val.str_value = buf;
716 free (pf);