1 /*!
2  * \file src/vendor.c
3  *
4  * \brief .
5  *
6  * <hr>
7  *
8  * <h1><b>Copyright.</b></h1>\n
9  *
10  * PCB, interactive printed circuit board design
11  *
12  * Copyright (C) 2004, 2007 Dan McMahill
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <ctype.h>
34 #include <math.h>
35 #include <stdio.h>
36 
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
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_REGEX_H
50 #include <regex.h>
51 #else
52 #ifdef HAVE_UNISTD_H
53 #include <unistd.h>
54 #endif
55 #endif
56 
57 #include "change.h"
58 #include "data.h"
59 #include "draw.h"
60 #include "error.h"
61 #include "global.h"
62 #include "resource.h"
63 #include "set.h"
64 #include "undo.h"
65 #include "vendor.h"
66 
67 #ifdef HAVE_LIBDMALLOC
68 #include <dmalloc.h>
69 #endif
70 
71 static void add_to_drills (char *);
72 static void apply_vendor_map (void);
73 static void process_skips (Resource *);
74 static bool rematch (const char *, const char *);
75 
76 /* list of vendor drills and a count of them */
77 static int *vendor_drills = NULL;
78 static int n_vendor_drills = 0;
79 
80 static int cached_drill = -1;
81 static int cached_map = -1;
82 
83 /* lists of elements to ignore */
84 static char **ignore_refdes = NULL;
85 static int n_refdes = 0;
86 static char **ignore_value = NULL;
87 static int n_value = 0;
88 static char **ignore_descr = NULL;
89 static int n_descr = 0;
90 
91 /*!
92  * \brief Vendor name.
93  */
94 static char *vendor_name = NULL;
95 
96 /*!
97  * \brief Resource file to PCB units scale factor.
98  */
99 static double sf;
100 
101 
102 /*!
103  * \brief Enable/disable mapping.
104  */
105 static bool vendorMapEnable = false;
106 
107 /* type of drill mapping */
108 #define CLOSEST 1
109 #define ROUND_UP 0
110 static int rounding_method = ROUND_UP;
111 
112 #define FREE(x) if((x) != NULL) { free (x) ; (x) = NULL; }
113 
114 /* ************************************************************ */
115 
116 static const char apply_vendor_syntax[] = N_("ApplyVendor()");
117 
118 static const char apply_vendor_help[] =
119   N_("Applies the currently loaded vendor drill table to the current design.");
120 
121 /* %start-doc actions ApplyVendor
122 @cindex vendor map
123 @cindex vendor drill table
124 @findex ApplyVendor()
125 
126 This will modify all of your drill holes to match the list of allowed
127 sizes for your vendor.
128 %end-doc */
129 
130 int
ActionApplyVendor(int argc,char ** argv,Coord x,Coord y)131 ActionApplyVendor (int argc, char **argv, Coord x, Coord y)
132 {
133   hid_action ("Busy");
134   apply_vendor_map ();
135   return 0;
136 }
137 
138 /* ************************************************************ */
139 
140 static const char toggle_vendor_syntax[] = N_("ToggleVendor()");
141 
142 static const char toggle_vendor_help[] =
143   N_("Toggles the state of automatic drill size mapping.");
144 
145 /* %start-doc actions ToggleVendor
146 
147 @cindex vendor map
148 @cindex vendor drill table
149 @findex ToggleVendor()
150 
151 When drill mapping is enabled, new instances of pins and vias will
152 have their drill holes mapped to one of the allowed drill sizes
153 specified in the currently loaded vendor drill table.  To enable drill
154 mapping, a vendor resource file containing a drill table must be
155 loaded first.
156 
157 %end-doc */
158 
159 int
ActionToggleVendor(int argc,char ** argv,Coord x,Coord y)160 ActionToggleVendor (int argc, char **argv, Coord x, Coord y)
161 {
162   if (vendorMapEnable)
163     vendorMapEnable = false;
164   else
165     vendorMapEnable = true;
166   return 0;
167 }
168 
169 /* ************************************************************ */
170 
171 static const char enable_vendor_syntax[] = N_("EnableVendor()");
172 
173 static const char enable_vendor_help[] =
174   N_("Enables automatic drill size mapping.");
175 
176 /* %start-doc actions EnableVendor
177 
178 @cindex vendor map
179 @cindex vendor drill table
180 @findex EnableVendor()
181 
182 When drill mapping is enabled, new instances of pins and vias will
183 have their drill holes mapped to one of the allowed drill sizes
184 specified in the currently loaded vendor drill table.  To enable drill
185 mapping, a vendor resource file containing a drill table must be
186 loaded first.
187 
188 %end-doc */
189 
190 int
ActionEnableVendor(int argc,char ** argv,Coord x,Coord y)191 ActionEnableVendor (int argc, char **argv, Coord x, Coord y)
192 {
193   vendorMapEnable = true;
194   return 0;
195 }
196 
197 /* ************************************************************ */
198 
199 static const char disable_vendor_syntax[] = N_("DisableVendor()");
200 
201 static const char disable_vendor_help[] =
202   N_("Disables automatic drill size mapping.");
203 
204 /* %start-doc actions DisableVendor
205 
206 @cindex vendor map
207 @cindex vendor drill table
208 @findex DisableVendor()
209 
210 When drill mapping is enabled, new instances of pins and vias will
211 have their drill holes mapped to one of the allowed drill sizes
212 specified in the currently loaded vendor drill table.
213 
214 %end-doc */
215 
216 int
ActionDisableVendor(int argc,char ** argv,Coord x,Coord y)217 ActionDisableVendor (int argc, char **argv, Coord x, Coord y)
218 {
219   vendorMapEnable = false;
220   return 0;
221 }
222 
223 /* ************************************************************ */
224 
225 static const char unload_vendor_syntax[] = N_("UnloadVendor()");
226 
227 static const char unload_vendor_help[] =
228   N_("Unloads the current vendor drill mapping table.");
229 
230 /* %start-doc actions UnloadVendor
231 
232 @cindex vendor map
233 @cindex vendor drill table
234 @findex UnloadVendor()
235 
236 %end-doc */
237 
238 int
ActionUnloadVendor(int argc,char ** argv,Coord x,Coord y)239 ActionUnloadVendor (int argc, char **argv, Coord x, Coord y)
240 {
241   cached_drill = -1;
242 
243   /* Unload any vendor table we may have had */
244   n_vendor_drills = 0;
245   n_refdes = 0;
246   n_value = 0;
247   n_descr = 0;
248   FREE (vendor_drills);
249   FREE (ignore_refdes);
250   FREE (ignore_value);
251   FREE (ignore_descr);
252   return 0;
253 }
254 
255 /* ************************************************************ */
256 
257 static const char load_vendor_syntax[] = N_("LoadVendorFrom(filename)");
258 
259 static const char load_vendor_help[] =
260   N_("Loads the specified vendor resource file.");
261 
262 /* %start-doc actions LoadVendorFrom
263 
264 @cindex vendor map
265 @cindex vendor drill table
266 @findex LoadVendorFrom()
267 
268 @table @var
269 @item filename
270 Name of the vendor resource file.  If not specified, the user will
271 be prompted to enter one.
272 @end table
273 
274 %end-doc */
275 
276 int
ActionLoadVendorFrom(int argc,char ** argv,Coord x,Coord y)277 ActionLoadVendorFrom (int argc, char **argv, Coord x, Coord y)
278 {
279   int i;
280   char *fname = NULL;
281   static char *default_file = NULL;
282   char *sval;
283   Resource *res, *drcres, *drlres;
284   int type;
285   bool free_fname = false;
286 
287   cached_drill = -1;
288 
289   fname = argc ? argv[0] : 0;
290 
291   if (!fname || !*fname)
292     {
293       fname = gui->fileselect (_("Load Vendor Resource File..."),
294 			       _("Picks a vendor resource file to load.\n"
295 				 "This file can contain drc settings for a\n"
296 				 "particular vendor as well as a list of\n"
297 				 "predefined drills which are allowed."),
298 			       default_file, ".res", "vendor",
299 			       HID_FILESELECT_READ);
300       if (fname == NULL)
301 	AFAIL (load_vendor);
302 
303       free_fname = true;
304 
305       free (default_file);
306       default_file = NULL;
307 
308       if (fname && *fname)
309 	default_file = strdup (fname);
310     }
311 
312   /* Unload any vendor table we may have had */
313   n_vendor_drills = 0;
314   n_refdes = 0;
315   n_value = 0;
316   n_descr = 0;
317   FREE (vendor_drills);
318   FREE (ignore_refdes);
319   FREE (ignore_value);
320   FREE (ignore_descr);
321 
322 
323   /* load the resource file */
324   res = resource_parse (fname, NULL);
325   if (res == NULL)
326     {
327       Message (_("Could not load vendor resource file \"%s\"\n"), fname);
328       return 1;
329     }
330 
331   /* figure out the vendor name, if specified */
332   vendor_name = (char *)UNKNOWN (resource_value (res, "vendor"));
333 
334   /* figure out the units, if specified */
335   sval = resource_value (res, "units");
336   if (sval == NULL)
337     {
338       sf = MIL_TO_COORD(1);
339     }
340   else if ((NSTRCMP (sval, "mil") == 0) || (NSTRCMP (sval, "mils") == 0))
341     {
342       sf = MIL_TO_COORD(1);
343     }
344   else if ((NSTRCMP (sval, "inch") == 0) || (NSTRCMP (sval, "inches") == 0))
345     {
346       sf = INCH_TO_COORD(1);
347     }
348   else if (NSTRCMP (sval, "mm") == 0)
349     {
350       sf = MM_TO_COORD(1);
351     }
352   else
353     {
354       Message (_("\"%s\" is not a supported units.  Defaulting to inch\n"),
355 	       sval);
356       sf = INCH_TO_COORD(1);
357     }
358 
359 
360   /* default to ROUND_UP */
361   rounding_method = ROUND_UP;
362 
363   /* extract the drillmap resource */
364   drlres = resource_subres (res, "drillmap");
365   if (drlres == NULL)
366     {
367       Message (_("No drillmap resource found\n"));
368     }
369   else
370     {
371       sval = resource_value (drlres, "round");
372       if (sval != NULL)
373 	{
374 	  if (NSTRCMP (sval, "up") == 0)
375 	    {
376 	      rounding_method = ROUND_UP;
377 	    }
378 	  else if (NSTRCMP (sval, "nearest") == 0)
379 	    {
380 	      rounding_method = CLOSEST;
381 	    }
382 	  else
383 	    {
384 	      Message (_("\"%s\" is not a valid rounding type. "
385 		    "Defaulting to up\n"),
386 		       sval);
387 	      rounding_method = ROUND_UP;
388 	    }
389 	}
390 
391       process_skips (resource_subres (drlres, "skips"));
392 
393       for (i = 0; i < drlres->c; i++)
394 	{
395 	  type = resource_type (drlres->v[i]);
396 	  switch (type)
397 	    {
398 	    case 10:
399 	      /* just a number */
400 	      add_to_drills (drlres->v[i].value);
401 	      break;
402 
403 	    default:
404 	      break;
405 	    }
406 	}
407     }
408 
409   /* Extract the DRC resource */
410   drcres = resource_subres (res, "drc");
411 
412   sval = resource_value (drcres, "copper_space");
413   if (sval != NULL)
414     {
415       PCB->Bloat = floor (sf * atof (sval) + 0.5);
416       Message (_("Set DRC minimum copper spacing to %.2f mils\n"),
417 	       0.01 * PCB->Bloat);
418     }
419 
420   sval = resource_value (drcres, "copper_overlap");
421   if (sval != NULL)
422     {
423       PCB->Shrink = floor (sf * atof (sval) + 0.5);
424       Message (_("Set DRC minimum copper overlap to %.2f mils\n"),
425 	       0.01 * PCB->Shrink);
426     }
427 
428   sval = resource_value (drcres, "copper_width");
429   if (sval != NULL)
430     {
431       PCB->minWid = floor (sf * atof (sval) + 0.5);
432       Message (_("Set DRC minimum copper spacing to %.2f mils\n"),
433 	       0.01 * PCB->minWid);
434     }
435 
436   sval = resource_value (drcres, "silk_width");
437   if (sval != NULL)
438     {
439       PCB->minSlk = floor (sf * atof (sval) + 0.5);
440       Message (_("Set DRC minimum silk width to %.2f mils\n"),
441 	       0.01 * PCB->minSlk);
442     }
443 
444   sval = resource_value (drcres, "min_drill");
445   if (sval != NULL)
446     {
447       PCB->minDrill = floor (sf * atof (sval) + 0.5);
448       Message (_("Set DRC minimum drill diameter to %.2f mils\n"),
449 	       0.01 * PCB->minDrill);
450     }
451 
452   sval = resource_value (drcres, "min_ring");
453   if (sval != NULL)
454     {
455       PCB->minRing = floor (sf * atof (sval) + 0.5);
456       Message (_("Set DRC minimum annular ring to %.2f mils\n"),
457 	       0.01 * PCB->minRing);
458     }
459 
460   Message (_("Loaded %d vendor drills from %s\n"), n_vendor_drills, fname);
461   Message (_("Loaded %d RefDes skips, %d Value skips, %d Descr skips\n"),
462 	   n_refdes, n_value, n_descr);
463 
464   vendorMapEnable = true;
465   apply_vendor_map ();
466   if (free_fname)
467     free (fname);
468   return 0;
469 }
470 
471 static void
apply_vendor_map(void)472 apply_vendor_map (void)
473 {
474   int i;
475   int changed, tot;
476   bool state;
477 
478   state = vendorMapEnable;
479 
480   /* enable mapping */
481   vendorMapEnable = true;
482 
483   /* reset our counts */
484   changed = 0;
485   tot = 0;
486 
487   /* If we have loaded vendor drills, then apply them to the design */
488   if (n_vendor_drills > 0)
489     {
490 
491       /* first all the vias */
492       VIA_LOOP (PCB->Data);
493       {
494 	tot++;
495 	if (via->DrillingHole != vendorDrillMap (via->DrillingHole))
496 	  {
497 	    /* only change unlocked vias */
498 	    if (!TEST_FLAG (LOCKFLAG, via))
499 	      {
500 		if (ChangeObject2ndSize (VIA_TYPE, via, NULL, NULL,
501 					 vendorDrillMap (via->DrillingHole),
502 					 true, false))
503 		  changed++;
504 		else
505 		  {
506 		    Message (_("Via at %.2f, %.2f not changed. "
507 			  "Possible reasons:\n"
508 			  "\t- pad size too small\n"
509 			  "\t- new size would be too large or too small\n"),
510 			0.01 * via->X, 0.01 * via->Y);
511 		  }
512 	      }
513 	    else
514 	      {
515 		Message (_("Locked via at %.2f, %.2f not changed.\n"),
516 			 0.01 * via->X, 0.01 * via->Y);
517 	      }
518 	  }
519       }
520       END_LOOP;
521 
522       /* and now the pins */
523       ELEMENT_LOOP (PCB->Data);
524       {
525 	/*
526 	 * first figure out if this element should be skipped for some
527 	 * reason
528 	 */
529 	if (vendorIsElementMappable (element))
530 	  {
531 	    /* the element is ok to modify, so iterate over its pins */
532 	    PIN_LOOP (element);
533 	    {
534 	      tot++;
535 	      if (pin->DrillingHole != vendorDrillMap (pin->DrillingHole))
536 		{
537 		  if (!TEST_FLAG (LOCKFLAG, pin))
538 		    {
539 		      if (ChangeObject2ndSize (PIN_TYPE, element, pin, NULL,
540 					       vendorDrillMap (pin->
541 							       DrillingHole),
542 					       true, false))
543 			changed++;
544 		      else
545 			{
546 			  Message (_("Pin %s (%s) at %.2f, %.2f "
547 				"(element %s, %s, %s) not changed.\n"
548 				"\tPossible reasons:\n"
549 				"\t- pad size too small\n"
550 				"\t- new size would be too large or too small\n"),
551 				   UNKNOWN (pin->Number), UNKNOWN (pin->Name),
552 				   0.01 * pin->X, 0.01 * pin->Y,
553 				   UNKNOWN (NAMEONPCB_NAME (element)),
554 				   UNKNOWN (VALUE_NAME (element)),
555 				   UNKNOWN (DESCRIPTION_NAME (element)));
556 			}
557 		    }
558 		  else
559 		    {
560 		      Message (_("Locked pin at %-6.2f, %-6.2f not changed.\n"),
561 			       0.01 * pin->X, 0.01 * pin->Y);
562 		    }
563 		}
564 	    }
565 	    END_LOOP;
566 	  }
567       }
568       END_LOOP;
569 
570       Message (_("Updated %d drill sizes out of %d total\n"), changed, tot);
571 
572       /* Update the current Via */
573       if (Settings.ViaDrillingHole !=
574 	  vendorDrillMap (Settings.ViaDrillingHole))
575 	{
576 	  changed++;
577 	  Settings.ViaDrillingHole =
578 	    vendorDrillMap (Settings.ViaDrillingHole);
579 	  Message (_("Adjusted active via hole size to be %6.2f mils\n"),
580 		   0.01 * Settings.ViaDrillingHole);
581 	}
582 
583       /* and update the vias for the various routing styles */
584       for (i = 0; i < NUM_STYLES; i++)
585 	{
586 	  if (PCB->RouteStyle[i].Hole !=
587 	      vendorDrillMap (PCB->RouteStyle[i].Hole))
588 	    {
589 	      changed++;
590 	      PCB->RouteStyle[i].Hole =
591 		vendorDrillMap (PCB->RouteStyle[i].Hole);
592 	      Message (_("Adjusted %s routing style via hole size to be "
593 		    "%6.2f mils\n"),
594 		       PCB->RouteStyle[i].Name,
595 		       0.01 * PCB->RouteStyle[i].Hole);
596 	      if (PCB->RouteStyle[i].Diameter < PCB->RouteStyle[i].Hole)
597 		{
598 		  PCB->RouteStyle[i].Diameter = PCB->RouteStyle[i].Hole;
599 		  Message (_("Increased %s routing style via diameter to "
600 			"%6.2f mils\n"),
601 			   PCB->RouteStyle[i].Name,
602 			   0.01 * PCB->RouteStyle[i].Diameter);
603 		}
604 	    }
605 	}
606 
607       /*
608        * if we've changed anything, indicate that we need to save the
609        * file, redraw things, and make sure we can undo.
610        */
611       if (changed)
612 	{
613 	  SetChangedFlag (true);
614 	  Redraw ();
615 	  IncrementUndoSerialNumber ();
616 	}
617     }
618 
619   /* restore mapping on/off */
620   vendorMapEnable = state;
621 }
622 
623 /*!
624  * \brief For a given drill size, find the closest vendor drill size.
625  */
626 int
vendorDrillMap(int in)627 vendorDrillMap (int in)
628 {
629   int i, min, max;
630 
631   if (in == cached_drill)
632     return cached_map;
633   cached_drill = in;
634 
635   /* skip the mapping if we don't have a vendor drill table */
636   if ((n_vendor_drills == 0) || (vendor_drills == NULL)
637       || (vendorMapEnable == false))
638     {
639       cached_map = in;
640       return in;
641     }
642 
643   /* are we smaller than the smallest drill? */
644   if (in <= vendor_drills[0])
645     {
646       cached_map = vendor_drills[0];
647       return vendor_drills[0];
648     }
649 
650   /* are we larger than the largest drill? */
651   if (in > vendor_drills[n_vendor_drills - 1])
652     {
653       Message (_("Vendor drill list does not contain a drill >= %6.2f mil\n"
654 		 "Using %6.2f mil instead.\n"),
655 	       0.01 * in, 0.01 * vendor_drills[n_vendor_drills - 1]);
656       cached_map = vendor_drills[n_vendor_drills - 1];
657       return vendor_drills[n_vendor_drills - 1];
658     }
659 
660   /* figure out which 2 drills are closest in size */
661   min = 0;
662   max = n_vendor_drills - 1;
663   while (max - min > 1)
664     {
665       i = (max+min) / 2;
666       if (in > vendor_drills[i])
667 	min = i;
668       else
669 	max = i;
670     }
671   i = max;
672 
673   /* now round per the rounding mode */
674   if (rounding_method == CLOSEST)
675     {
676       /* find the closest drill size */
677       if ((in - vendor_drills[i - 1]) > (vendor_drills[i] - in))
678 	{
679 	  cached_map = vendor_drills[i];
680 	  return vendor_drills[i];
681 	}
682       else
683 	{
684 	  cached_map = vendor_drills[i - 1];
685 	  return vendor_drills[i - 1];
686 	}
687     }
688   else
689     {
690       /* always round up */
691       cached_map = vendor_drills[i];
692       return vendor_drills[i];
693     }
694 
695 }
696 
697 /*!
698  * \brief Add a drill size to the vendor drill list.
699  */
700 static void
add_to_drills(char * sval)701 add_to_drills (char *sval)
702 {
703   double tmpd;
704   int val;
705   int k, j;
706 
707   /* increment the count and make sure we have memory */
708   n_vendor_drills++;
709   if ((vendor_drills = (int *)realloc (vendor_drills,
710 				n_vendor_drills * sizeof (int))) == NULL)
711     {
712       fprintf (stderr, _("realloc() failed to allocate %ld bytes\n"),
713 	       (unsigned long) n_vendor_drills * sizeof (int));
714       return;
715     }
716 
717   /* string to a value with the units scale factor in place */
718   tmpd = atof (sval);
719   val = floor (sf * tmpd + 0.5);
720 
721   /*
722    * We keep the array of vendor drills sorted to make it easier to
723    * do the rounding later.  The algorithm used here is not so efficient,
724    * but we're not dealing with much in the way of data.
725    */
726 
727   /* figure out where to insert the value to keep the array sorted.  */
728   k = 0;
729   while ((k < n_vendor_drills - 1) && (vendor_drills[k] < val))
730     k++;
731 
732   if (k == n_vendor_drills - 1)
733     {
734       vendor_drills[n_vendor_drills - 1] = val;
735     }
736   else
737     {
738       /* move up the existing drills to make room */
739       for (j = n_vendor_drills - 1; j > k; j--)
740 	{
741 	  vendor_drills[j] = vendor_drills[j - 1];
742 	}
743 
744       vendor_drills[k] = val;
745     }
746 }
747 
748 /*!
749  * \brief Deal with the "skip" subresource.
750  */
751 static void
process_skips(Resource * res)752 process_skips (Resource * res)
753 {
754   int type;
755   int i, k;
756   char *sval;
757   int *cnt;
758   char ***lst = NULL;
759 
760   if (res == NULL)
761     return;
762 
763   for (i = 0; i < res->c; i++)
764     {
765       type = resource_type (res->v[i]);
766       switch (type)
767 	{
768 	case 1:
769 	  /*
770 	   * an unnamed sub resource.  This is something like
771 	   * {refdes "J3"}
772 	   */
773 	  sval = res->v[i].subres->v[0].value;
774 	  if (sval == NULL)
775 	    {
776 	      Message (_("Error:  null skip value\n"));
777 	    }
778 	  else
779 	    {
780 	      if (NSTRCMP (sval, "refdes") == 0)
781 		{
782 		  cnt = &n_refdes;
783 		  lst = &ignore_refdes;
784 		}
785 	      else if (NSTRCMP (sval, "value") == 0)
786 		{
787 		  cnt = &n_value;
788 		  lst = &ignore_value;
789 		}
790 	      else if (NSTRCMP (sval, "descr") == 0)
791 		{
792 		  cnt = &n_descr;
793 		  lst = &ignore_descr;
794 		}
795 	      else
796 		{
797 		  cnt = NULL;
798 		}
799 
800 	      /* add the entry to the appropriate list */
801 	      if (cnt != NULL)
802 		{
803 		  for (k = 1; k < res->v[i].subres->c; k++)
804 		    {
805 		      sval = res->v[i].subres->v[k].value;
806 		      (*cnt)++;
807 		      if ((*lst =
808 			   (char **) realloc (*lst,
809 					      (*cnt) * sizeof (char *))) ==
810 			  NULL)
811 			{
812 			  fprintf (stderr, _("realloc() failed\n"));
813 			  exit (-1);
814 			}
815 		      (*lst)[*cnt - 1] = strdup (sval);
816 		    }
817 		}
818 	    }
819 	  break;
820 
821 	default:
822 	  Message (_("Ignored resource type = %d in skips= section\n"), type);
823 	}
824     }
825 
826 }
827 
828 bool
vendorIsElementMappable(ElementType * element)829 vendorIsElementMappable (ElementType *element)
830 {
831   int i;
832   int noskip;
833 
834   if (vendorMapEnable == false)
835     return false;
836 
837   noskip = 1;
838   for (i = 0; i < n_refdes; i++)
839     {
840       if ((NSTRCMP (UNKNOWN (NAMEONPCB_NAME (element)), ignore_refdes[i]) ==
841 	   0)
842 	  || rematch (ignore_refdes[i], UNKNOWN (NAMEONPCB_NAME (element))))
843 	{
844 	  Message (_("Vendor mapping skipped because "
845 		"refdes = %s matches %s\n"),
846 		   UNKNOWN (NAMEONPCB_NAME (element)), ignore_refdes[i]);
847 	  noskip = 0;
848 	}
849     }
850   if (noskip)
851     for (i = 0; i < n_value; i++)
852       {
853 	if ((NSTRCMP (UNKNOWN (VALUE_NAME (element)), ignore_value[i]) == 0)
854 	    || rematch (ignore_value[i], UNKNOWN (VALUE_NAME (element))))
855 	  {
856 	    Message (_("Vendor mapping skipped because "
857 		  "value = %s matches %s\n"),
858 		     UNKNOWN (VALUE_NAME (element)), ignore_value[i]);
859 	    noskip = 0;
860 	  }
861       }
862 
863   if (noskip)
864     for (i = 0; i < n_descr; i++)
865       {
866 	if ((NSTRCMP (UNKNOWN (DESCRIPTION_NAME (element)), ignore_descr[i])
867 	     == 0)
868 	    || rematch (ignore_descr[i],
869 			UNKNOWN (DESCRIPTION_NAME (element))))
870 	  {
871 	    Message (_("Vendor mapping skipped because "
872 		  "descr = %s matches %s\n"),
873 		     UNKNOWN (DESCRIPTION_NAME (element)), ignore_descr[i]);
874 	    noskip = 0;
875 	  }
876       }
877 
878   if (noskip && TEST_FLAG (LOCKFLAG, element))
879     {
880       Message (_("Vendor mapping skipped because element %s is locked\n"),
881 	       UNKNOWN (NAMEONPCB_NAME (element)));
882       noskip = 0;
883     }
884 
885   if (noskip)
886     return true;
887   else
888     return false;
889 }
890 
891 static bool
rematch(const char * re,const char * s)892 rematch (const char *re, const char *s)
893 {
894   /*
895    * If this system has regular expression capability, then
896    * add support for regular expressions in the skip lists.
897    */
898 
899 #if defined(HAVE_REGCOMP)
900 
901   int result;
902   regmatch_t match;
903   regex_t compiled;
904 
905   /* compile the regular expression */
906   result = regcomp (&compiled, re, REG_EXTENDED | REG_ICASE | REG_NOSUB);
907   if (result)
908     {
909       char errorstring[128];
910 
911       regerror (result, &compiled, errorstring, sizeof (errorstring));
912       Message (_("regexp error: %s\n"), errorstring);
913       regfree (&compiled);
914       return (false);
915     }
916 
917   result = regexec (&compiled, s, 1, &match, 0);
918   regfree (&compiled);
919 
920   if (result == 0)
921     return (true);
922   else
923     return (false);
924 
925 #elif defined(HAVE_RE_COMP)
926   int m;
927   char *rslt;
928 
929   /* compile the regular expression */
930   if ((rslt = re_comp (re)) != NULL)
931     {
932       Message (_("re_comp error: %s\n"), rslt);
933       return (false);
934     }
935 
936   m = re_exec (s);
937 
938   switch m
939     {
940     case 1:
941       return (true);
942       break;
943 
944     case 0:
945       return (false);
946       break;
947 
948     default:
949       Message (_("re_exec error\n"));
950       break;
951     }
952 
953 #else
954   return (false);
955 #endif
956 
957 }
958 
959 HID_Action vendor_action_list[] = {
960   {"ApplyVendor", 0, ActionApplyVendor,
961    apply_vendor_help, apply_vendor_syntax}
962   ,
963   {"ToggleVendor", 0, ActionToggleVendor,
964    toggle_vendor_help, toggle_vendor_syntax}
965   ,
966   {"EnableVendor", 0, ActionEnableVendor,
967    enable_vendor_help, enable_vendor_syntax}
968   ,
969   {"DisableVendor", 0, ActionDisableVendor,
970    disable_vendor_help, disable_vendor_syntax}
971   ,
972   {"UnloadVendor", 0, ActionUnloadVendor,
973    unload_vendor_help, unload_vendor_syntax}
974   ,
975   {"LoadVendorFrom", 0, ActionLoadVendorFrom,
976    load_vendor_help, load_vendor_syntax}
977 };
978 
REGISTER_ACTIONS(vendor_action_list)979 REGISTER_ACTIONS (vendor_action_list)
980 
981 static int vendor_get_enabled (void *data)
982 {
983   return vendorMapEnable;
984 }
985 
986 HID_Flag vendor_flag_list[] = {
987   {"VendorMapOn", vendor_get_enabled, NULL}
988 };
989 
990 REGISTER_FLAGS (vendor_flag_list)
991