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