1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <ctype.h>
9 
10 #include "global.h"
11 #include "data.h"
12 #include "error.h"
13 
14 #include "hid.h"
15 #include "../hidint.h"
16 
17 #ifdef HAVE_LIBDMALLOC
18 #include <dmalloc.h>
19 #endif
20 
21 static HID_Action **all_actions = 0;
22 static int all_actions_sorted = 0;
23 static int n_actions = 0;
24 
25 HID_Action *current_action = NULL;
26 
27 static const char *
check_action_name(const char * s)28 check_action_name (const char *s)
29 {
30   while (*s)
31     if (isspace ((int) *s++) || *s == '(')
32       return (s-1);
33   return NULL;
34 }
35 
36 void
hid_register_actions(HID_Action * a,int n)37 hid_register_actions (HID_Action * a, int n)
38 {
39   int i, count = 0;
40 
41   all_actions = (HID_Action **)realloc (all_actions,
42                          (n_actions + n) * sizeof (HID_Action*));
43   for (i = 0; i < n; i++)
44     {
45       if (check_action_name (a[i].name))
46         {
47           Message (_("ERROR! Invalid action name, "
48                      "action \"%s\" not registered.\n"), a[i].name);
49           continue;
50         }
51       all_actions[n_actions + count++] = a + i;
52     }
53   n_actions += count;
54   all_actions_sorted = 0;
55 }
56 
57 void
hid_register_action(HID_Action * a)58 hid_register_action (HID_Action * a)
59 {
60   hid_register_actions (a, 1);
61 }
62 
63 static int
action_sort_compar(const void * va,const void * vb)64 action_sort_compar (const void *va, const void *vb)
65 {
66   HID_Action *a = *(HID_Action **) va;
67   HID_Action *b = *(HID_Action **) vb;
68   return strcmp (a->name, b->name);
69 }
70 
71 static void
sort_actions()72 sort_actions ()
73 {
74   qsort (all_actions, n_actions, sizeof (HID_Action*), action_sort_compar);
75   all_actions_sorted = 1;
76 }
77 
78 static int
action_search_compar(const void * va,const void * vb)79 action_search_compar (const void *va, const void *vb)
80 {
81   char *name = (char*)va;
82   HID_Action *action = *(HID_Action**)vb;
83   return strcmp (name, action->name);
84 }
85 
86 HID_Action *
hid_find_action(const char * name)87 hid_find_action (const char *name)
88 {
89   HID_Action **action;
90   int i;
91 
92   if (name == NULL)
93     return 0;
94 
95   if (!all_actions_sorted)
96     sort_actions ();
97 
98   action = (HID_Action **)bsearch (name, all_actions, n_actions, sizeof (HID_Action*),
99                     action_search_compar);
100   if (action)
101     return *action;
102 
103   for (i = 0; i < n_actions; i++)
104     if (strcasecmp (all_actions[i]->name, name) == 0)
105       return all_actions[i];
106 
107   printf ("unknown action `%s'\n", name);
108   return 0;
109 }
110 
111 void
print_actions()112 print_actions ()
113 {
114   int i;
115 
116   if (!all_actions_sorted)
117     sort_actions ();
118 
119   fprintf (stderr, "Registered Actions:\n");
120   for (i = 0; i < n_actions; i++)
121     {
122       if (all_actions[i]->description)
123 	fprintf (stderr, "  %s - %s\n", all_actions[i]->name,
124 		 all_actions[i]->description);
125       else
126 	fprintf (stderr, "  %s\n", all_actions[i]->name);
127       if (all_actions[i]->syntax)
128 	{
129 	  const char *bb, *eb;
130 	  bb = eb = all_actions[i]->syntax;
131 	  while (1)
132 	    {
133 	      for (eb = bb; *eb && *eb != '\n'; eb++)
134 		;
135 	      fwrite ("    ", 4, 1, stderr);
136 	      fwrite (bb, eb - bb, 1, stderr);
137 	      fputc ('\n', stderr);
138 	      if (*eb == 0)
139 		break;
140 	      bb = eb + 1;
141 	    }
142 	}
143     }
144 }
145 
146 static void
dump_string(char prefix,const char * str)147 dump_string (char prefix, const char *str)
148 {
149   int eol = 1;
150   while (*str)
151     {
152       if (eol)
153 	{
154 	  putchar (prefix);
155 	  eol = 0;
156 	}
157       putchar (*str);
158       if (*str == '\n')
159 	eol = 1;
160       str ++;
161     }
162   if (!eol)
163     putchar ('\n');
164 }
165 
166 void
dump_actions()167 dump_actions ()
168 {
169   int i;
170 
171   if (!all_actions_sorted)
172     sort_actions ();
173 
174   for (i = 0; i < n_actions; i++)
175     {
176       const char *desc = all_actions[i]->description;
177       const char *synt = all_actions[i]->syntax;
178 
179       desc = desc ? desc : "";
180       synt = synt ? synt : "";
181 
182       printf ("A%s\n", all_actions[i]->name);
183       dump_string ('D', desc);
184       dump_string ('S', synt);
185     }
186 }
187 
188 int
hid_action(const char * name)189 hid_action (const char *name)
190 {
191   return hid_actionv (name, 0, 0);
192 }
193 
194 int
hid_actionl(const char * name,...)195 hid_actionl (const char *name, ...)
196 {
197   char *argv[20];
198   int argc = 0;
199   va_list ap;
200   char *arg;
201 
202   va_start (ap, name);
203   while ((arg = va_arg (ap, char *)) != 0)
204       argv[argc++] = arg;
205   va_end (ap);
206   return hid_actionv (name, argc, argv);
207 }
208 
209 int
hid_actionv(const char * name,int argc,char ** argv)210 hid_actionv (const char *name, int argc, char **argv)
211 {
212   Coord x = 0, y = 0;
213   int i, ret;
214   HID_Action *a, *old_action;
215 
216   if (!name)
217     return 1;
218 
219   a = hid_find_action (name);
220   if (!a)
221     {
222       int i;
223       Message (_("no action %s("), name);
224       for (i = 0; i < argc; i++)
225         Message ("%s%s", i ? ", " : "", argv[i]);
226       Message (")\n");
227       return 1;
228     }
229 
230   if (a->need_coord_msg)
231     gui->get_coords (_(a->need_coord_msg), &x, &y);
232 
233   if (Settings.verbose)
234     {
235       printf ("Action: \033[34m%s(", name);
236       for (i = 0; i < argc; i++)
237 	printf ("%s%s", i ? "," : "", argv[i]);
238       printf (")\033[0m\n");
239     }
240 
241   old_action     = current_action;
242   current_action = a;
243   ret = current_action->trigger_cb (argc, argv, x, y);
244   current_action = old_action;
245 
246   return ret;
247 }
248 
249 static int
hid_parse_actionstring(const char * rstr,char require_parens)250 hid_parse_actionstring (const char *rstr, char require_parens)
251 {
252   char **list = NULL;
253   int max = 0;
254   int num;
255   char *str = NULL;
256   const char *sp;
257   char *cp, *aname, *cp2;
258   int maybe_empty = 0;
259   char in_quotes = 0;
260   char parens = 0;
261   int retcode = 0;
262 
263   /*fprintf(stderr, "invoke: `%s'\n", rstr);*/
264 
265   sp = rstr;
266   str = (char *)malloc(strlen(rstr)+1);
267 
268 another:
269   num = 0;
270   cp = str;
271 
272   /* eat leading spaces and tabs */
273   while (*sp && isspace ((int) *sp))
274     sp++;
275 
276   if (!*sp)
277     {
278       retcode = 0;
279       goto cleanup;
280     }
281 
282   aname = cp;
283 
284   /* copy the action name, assumes name does not have a space or '('
285    * in its name */
286   while (*sp && !isspace ((int) *sp) && *sp != '(')
287     *cp++ = *sp++;
288   *cp++ = 0;
289 
290   /* skip whitespace */
291   while (*sp && isspace ((int) *sp))
292     sp++;
293 
294   /*
295    * we only have an action name, so invoke the action
296    * with no parameters or event.
297    */
298   if (!*sp)
299     {
300       retcode = hid_actionv (aname, 0, 0);
301       goto cleanup;
302     }
303 
304   /* are we using parenthesis? */
305   if (*sp == '(')
306     {
307       parens = 1;
308       sp++;
309     }
310   else if (require_parens)
311     {
312       Message (_("Syntax error: %s\n"), rstr);
313       Message (_("    expected: Action(arg1, arg2)"));
314       retcode = 1;
315       goto cleanup;
316     }
317 
318   /* get the parameters to pass to the action */
319   while (1)
320     {
321       /*
322        * maybe_empty == 0 means that the last char examined was not a
323        * ","
324        */
325       if (!maybe_empty && ((parens && *sp == ')') || (!parens && !*sp)))
326 	{
327           retcode = hid_actionv (aname, num, list);
328           if (retcode)
329             goto cleanup;
330 
331           /* strip any white space or ';' following the action */
332           if (parens)
333             sp++;
334           while (*sp && (isspace ((int) *sp) || *sp == ';'))
335             sp++;
336 	  goto another;
337 	}
338       else if (*sp == 0 && !maybe_empty)
339 	break;
340       else
341         {
342 	  maybe_empty = 0;
343 	  in_quotes = 0;
344 	  /*
345 	   * if we have more parameters than memory in our array of
346 	   * pointers, then either allocate some or grow the array
347 	   */
348 	  if (num >= max)
349 	    {
350 	      max += 10;
351 	      if (list)
352 		list = (char **) realloc (list, max * sizeof (char *));
353 	      else
354 		list = (char **) malloc (max * sizeof (char *));
355 	    }
356 	  /* Strip leading whitespace.  */
357 	  while (*sp && isspace ((int) *sp))
358 	    sp++;
359 	  list[num++] = cp;
360 
361 	  /* search for the end of the argument, we want to keep going
362            * if we are in quotes or the char is not a delimiter
363            */
364 	  while (*sp && (in_quotes || ((*sp != ',')
365                                        && (!parens || *sp != ')')
366                                        && (parens || !isspace ((int) *sp)))))
367 	    {
368 	      /*
369 	       * single quotes give literal value inside, including '\'.
370 	       * you can't have a single inside single quotes.
371 	       * doubles quotes gives literal value inside, but allows escape.
372 	       */
373 	      if ((*sp == '"' || *sp == '\'') && (!in_quotes || *sp == in_quotes))
374 	        {
375 	          in_quotes = in_quotes ? 0 : *sp;
376 	          sp++;
377 	          continue;
378 	        }
379 	      /* unless within single quotes, \<char> will just be <char> */
380 	      else if (*sp == '\\' && in_quotes != '\'')
381 	        sp++;
382 	      *cp++ = *sp++;
383 	    }
384 	  cp2 = cp - 1;
385 	  *cp++ = 0;
386 	  if (*sp == ',' || (!parens && isspace ((int) *sp)))
387 	    {
388 	      maybe_empty = 1;
389 	      sp++;
390 	    }
391 	  /* Strip trailing whitespace.  */
392 	  for (; isspace ((int) *cp2) && cp2 >= list[num - 1]; cp2--)
393 	    *cp2 = 0;
394 	}
395     }
396 
397  cleanup:
398 
399   if (list != NULL)
400     free(list);
401 
402   if (str != NULL)
403     free (str);
404 
405   return retcode;
406 }
407 
hid_parse_command(const char * str_)408 int hid_parse_command (const char *str_)
409 {
410   return hid_parse_actionstring (str_, FALSE);
411 }
412 
hid_parse_actions(const char * str_)413 int hid_parse_actions (const char *str_)
414 {
415   return hid_parse_actionstring (str_, TRUE);
416 }
417 
418 /* trick for the doc extractor */
419 #define static
420 
421 /* %start-doc actions 00macros
422 
423 @macro hidaction
424 
425 This is one of a number of actions which are part of the HID
426 interface.  The core functions use these actions to tell the current
427 GUI when to change the presented information in response to changes
428 that the GUI may not know about.  The user normally does not invoke
429 these directly.
430 
431 @end macro
432 
433 %end-doc */
434 
435 
436 static const char pcbchanged_syntax[] =
437   "PCBChanged([revert])";
438 static const char pcbchanged_help[] =
439   "Tells the GUI that the whole PCB has changed. The optional \"revert\""
440   "parameter can be used as a hint to the GUI that the same design is being"
441   "reloaded, and that it might keep some viewport settings";
442 
443 /* %start-doc actions PCBChanged
444 
445 @hidaction
446 
447 %end-doc */
448 
449 static const char routestyleschanged_syntax[] =
450   "RouteStylesChanged()";
451 static const char routestyleschanged_help[] =
452   "Tells the GUI that the routing styles have changed.";
453 
454 /* %start-doc actions RouteStylesChanged
455 
456 @hidaction
457 
458 %end-doc */
459 
460 static const char netlistchanged_syntax[] =
461   "NetlistChanged()";
462 static const char netlistchanged_help[] =
463   "Tells the GUI that the netlist has changed.";
464 
465 /* %start-doc actions NetlistChanged
466 
467 @hidaction
468 
469 %end-doc */
470 
471 static const char layerschanged_syntax[] =
472   "LayersChanged()";
473 static const char layerschanged_help[] =
474   "Tells the GUI that the layers have changed.";
475 
476 /* %start-doc actions LayersChanged
477 
478 This includes layer names, colors, stacking order, visibility, etc.
479 
480 @hidaction
481 
482 %end-doc */
483 
484 static const char librarychanged_syntax[] =
485   "LibraryChanged()";
486 static const char librarychanged_help[] =
487   "Tells the GUI that the libraries have changed.";
488 
489 /* %start-doc actions LibraryChanged
490 
491 @hidaction
492 
493 %end-doc */
494