pcb 4.1.1
An interactive printed circuit board layout editor.

actions.c

Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <string.h>
00008 #include <ctype.h>
00009 
00010 #include "global.h"
00011 #include "data.h"
00012 #include "error.h"
00013 
00014 #include "hid.h"
00015 #include "../hidint.h"
00016 
00017 #ifdef HAVE_LIBDMALLOC
00018 #include <dmalloc.h>
00019 #endif
00020 
00021 static HID_Action **all_actions = 0;
00022 static int all_actions_sorted = 0;
00023 static int n_actions = 0;
00024 
00025 HID_Action *current_action = NULL;
00026 
00027 static const char *
00028 check_action_name (const char *s)
00029 {
00030   while (*s)
00031     if (isspace ((int) *s++) || *s == '(')
00032       return (s-1);
00033   return NULL;
00034 }
00035 
00036 void
00037 hid_register_actions (HID_Action * a, int n)
00038 {
00039   int i, count = 0;
00040   
00041   all_actions = (HID_Action **)realloc (all_actions,
00042                          (n_actions + n) * sizeof (HID_Action*));
00043   for (i = 0; i < n; i++)
00044     {
00045       if (check_action_name (a[i].name))
00046         {
00047           Message (_("ERROR! Invalid action name, "
00048                      "action \"%s\" not registered.\n"), a[i].name);
00049           continue;
00050         }
00051       all_actions[n_actions + count++] = a + i;
00052     }
00053   n_actions += count;
00054   all_actions_sorted = 0;
00055 }
00056 
00057 void
00058 hid_register_action (HID_Action * a)
00059 {
00060   hid_register_actions (a, 1);
00061 }
00062 
00063 static int
00064 action_sort_compar (const void *va, const void *vb)
00065 {
00066   HID_Action *a = *(HID_Action **) va;
00067   HID_Action *b = *(HID_Action **) vb;
00068   return strcmp (a->name, b->name);
00069 }
00070 
00071 static void
00072 sort_actions ()
00073 {
00074   qsort (all_actions, n_actions, sizeof (HID_Action*), action_sort_compar);
00075   all_actions_sorted = 1;
00076 }
00077 
00078 static int
00079 action_search_compar (const void *va, const void *vb)
00080 {
00081   char *name = (char*)va;
00082   HID_Action *action = *(HID_Action**)vb;
00083   return strcmp (name, action->name);
00084 }
00085 
00086 HID_Action *
00087 hid_find_action (const char *name)
00088 {
00089   HID_Action **action;
00090   int i;
00091   
00092   if (name == NULL)
00093     return 0;
00094 
00095   if (!all_actions_sorted)
00096     sort_actions ();
00097 
00098   action = (HID_Action **)bsearch (name, all_actions, n_actions, sizeof (HID_Action*),
00099                     action_search_compar);
00100   if (action)
00101     return *action;
00102 
00103   for (i = 0; i < n_actions; i++)
00104     if (strcasecmp (all_actions[i]->name, name) == 0)
00105       return all_actions[i];
00106 
00107   printf ("unknown action `%s'\n", name);
00108   return 0;
00109 }
00110 
00111 void
00112 print_actions ()
00113 {
00114   int i;
00115 
00116   if (!all_actions_sorted)
00117     sort_actions ();
00118   
00119   fprintf (stderr, "Registered Actions:\n");
00120   for (i = 0; i < n_actions; i++)
00121     {
00122       if (all_actions[i]->description)
00123         fprintf (stderr, "  %s - %s\n", all_actions[i]->name,
00124                  all_actions[i]->description);
00125       else
00126         fprintf (stderr, "  %s\n", all_actions[i]->name);
00127       if (all_actions[i]->syntax)
00128         {
00129           const char *bb, *eb;
00130           bb = eb = all_actions[i]->syntax;
00131           while (1)
00132             {
00133               for (eb = bb; *eb && *eb != '\n'; eb++)
00134                 ;
00135               fwrite ("    ", 4, 1, stderr);
00136               fwrite (bb, eb - bb, 1, stderr);
00137               fputc ('\n', stderr);
00138               if (*eb == 0)
00139                 break;
00140               bb = eb + 1;
00141             }
00142         }
00143     }
00144 }
00145 
00146 static void
00147 dump_string (char prefix, const char *str)
00148 {
00149   int eol = 1;
00150   while (*str)
00151     {
00152       if (eol)
00153         {
00154           putchar (prefix);
00155           eol = 0;
00156         }
00157       putchar (*str);
00158       if (*str == '\n')
00159         eol = 1;
00160       str ++;
00161     }
00162   if (!eol)
00163     putchar ('\n');
00164 }
00165 
00166 void
00167 dump_actions ()
00168 {
00169   int i;
00170 
00171   if (!all_actions_sorted)
00172     sort_actions ();
00173 
00174   for (i = 0; i < n_actions; i++)
00175     {
00176       const char *desc = all_actions[i]->description;
00177       const char *synt = all_actions[i]->syntax;
00178 
00179       desc = desc ? desc : "";
00180       synt = synt ? synt : "";
00181 
00182       printf ("A%s\n", all_actions[i]->name);
00183       dump_string ('D', desc);
00184       dump_string ('S', synt);
00185     }
00186 }
00187 
00188 int
00189 hid_action (const char *name)
00190 {
00191   return hid_actionv (name, 0, 0);
00192 }
00193 
00194 int
00195 hid_actionl (const char *name, ...)
00196 {
00197   char *argv[20];
00198   int argc = 0;
00199   va_list ap;
00200   char *arg;
00201 
00202   va_start (ap, name);
00203   while ((arg = va_arg (ap, char *)) != 0)
00204       argv[argc++] = arg;
00205   va_end (ap);
00206   return hid_actionv (name, argc, argv);
00207 }
00208 
00209 int
00210 hid_actionv (const char *name, int argc, char **argv)
00211 {
00212   Coord x = 0, y = 0;
00213   int i, ret;
00214   HID_Action *a, *old_action;
00215 
00216   if (!name)
00217     return 1;
00218 
00219   a = hid_find_action (name);
00220   if (!a)
00221     {
00222       int i;
00223       Message (_("no action %s("), name);
00224       for (i = 0; i < argc; i++)
00225         Message ("%s%s", i ? ", " : "", argv[i]);
00226       Message (")\n");
00227       return 1;
00228     }
00229 
00230   if (a->need_coord_msg)
00231     gui->get_coords (_(a->need_coord_msg), &x, &y);
00232 
00233   if (Settings.verbose)
00234     {
00235       printf ("Action: \033[34m%s(", name);
00236       for (i = 0; i < argc; i++)
00237         printf ("%s%s", i ? "," : "", argv[i]);
00238       printf (")\033[0m\n");
00239     }
00240   
00241   old_action     = current_action;
00242   current_action = a;
00243   ret = current_action->trigger_cb (argc, argv, x, y);
00244   current_action = old_action;
00245   
00246   return ret;
00247 }
00248 
00249 static int
00250 hid_parse_actionstring (const char *rstr, char require_parens)
00251 {
00252   char **list = NULL;
00253   int max = 0;
00254   int num;
00255   char *str = NULL;
00256   const char *sp;
00257   char *cp, *aname, *cp2;
00258   int maybe_empty = 0;
00259   char in_quotes = 0;
00260   char parens = 0;
00261   int retcode = 0;
00262 
00263   /*fprintf(stderr, "invoke: `%s'\n", rstr);*/
00264 
00265   sp = rstr;
00266   str = (char *)malloc(strlen(rstr)+1);
00267 
00268 another:
00269   num = 0;
00270   cp = str;
00271 
00272   /* eat leading spaces and tabs */
00273   while (*sp && isspace ((int) *sp))
00274     sp++;
00275   
00276   if (!*sp)
00277     {
00278       retcode = 0;
00279       goto cleanup;
00280     }
00281   
00282   aname = cp;
00283 
00284   /* copy the action name, assumes name does not have a space or '('
00285    * in its name */
00286   while (*sp && !isspace ((int) *sp) && *sp != '(')
00287     *cp++ = *sp++;
00288   *cp++ = 0;
00289 
00290   /* skip whitespace */
00291   while (*sp && isspace ((int) *sp))
00292     sp++;
00293 
00294   /*
00295    * we only have an action name, so invoke the action
00296    * with no parameters or event.
00297    */
00298   if (!*sp)
00299     {
00300       retcode = hid_actionv (aname, 0, 0);
00301       goto cleanup;
00302     }
00303 
00304   /* are we using parenthesis? */
00305   if (*sp == '(')
00306     {
00307       parens = 1;
00308       sp++;
00309     }
00310   else if (require_parens)
00311     {
00312       Message (_("Syntax error: %s\n"), rstr);
00313       Message (_("    expected: Action(arg1, arg2)"));
00314       retcode = 1;
00315       goto cleanup;
00316     }
00317   
00318   /* get the parameters to pass to the action */
00319   while (1)
00320     {
00321       /* 
00322        * maybe_empty == 0 means that the last char examined was not a
00323        * ","
00324        */
00325       if (!maybe_empty && ((parens && *sp == ')') || (!parens && !*sp)))
00326         {
00327           retcode = hid_actionv (aname, num, list);
00328           if (retcode)
00329             goto cleanup;
00330 
00331           /* strip any white space or ';' following the action */
00332           if (parens)
00333             sp++;
00334           while (*sp && (isspace ((int) *sp) || *sp == ';'))
00335             sp++;
00336           goto another;
00337         }
00338       else if (*sp == 0 && !maybe_empty)
00339         break;
00340       else
00341         {
00342           maybe_empty = 0;
00343           in_quotes = 0;
00344           /* 
00345            * if we have more parameters than memory in our array of
00346            * pointers, then either allocate some or grow the array
00347            */
00348           if (num >= max)
00349             {
00350               max += 10;
00351               if (list)
00352                 list = (char **) realloc (list, max * sizeof (char *));
00353               else
00354                 list = (char **) malloc (max * sizeof (char *));
00355             }
00356           /* Strip leading whitespace.  */
00357           while (*sp && isspace ((int) *sp))
00358             sp++;
00359           list[num++] = cp;
00360           
00361           /* search for the end of the argument, we want to keep going
00362            * if we are in quotes or the char is not a delimiter
00363            */
00364           while (*sp && (in_quotes || ((*sp != ',')
00365                                        && (!parens || *sp != ')')
00366                                        && (parens || !isspace ((int) *sp)))))
00367             {
00368               /*
00369                * single quotes give literal value inside, including '\'. 
00370                * you can't have a single inside single quotes.
00371                * doubles quotes gives literal value inside, but allows escape.
00372                */
00373               if ((*sp == '"' || *sp == '\'') && (!in_quotes || *sp == in_quotes))
00374                 {
00375                   in_quotes = in_quotes ? 0 : *sp;
00376                   sp++;
00377                   continue;
00378                 }
00379               /* unless within single quotes, <char> will just be <char> */
00380               else if (*sp == '\\' && in_quotes != '\'')
00381                 sp++;
00382               *cp++ = *sp++;
00383             }
00384           cp2 = cp - 1;
00385           *cp++ = 0;
00386           if (*sp == ',' || (!parens && isspace ((int) *sp)))
00387             {
00388               maybe_empty = 1;
00389               sp++;
00390             }
00391           /* Strip trailing whitespace.  */
00392           for (; isspace ((int) *cp2) && cp2 >= list[num - 1]; cp2--)
00393             *cp2 = 0;
00394         }
00395     }
00396   
00397  cleanup:
00398   
00399   if (list != NULL)
00400     free(list);
00401   
00402   if (str != NULL)
00403     free (str);
00404   
00405   return retcode;
00406 }
00407 
00408 int hid_parse_command (const char *str_)
00409 {
00410   return hid_parse_actionstring (str_, FALSE);
00411 }
00412 
00413 int hid_parse_actions (const char *str_)
00414 {
00415   return hid_parse_actionstring (str_, TRUE);
00416 }
00417 
00418 /* trick for the doc extractor */
00419 #define static
00420 
00421 /* %start-doc actions 00macros
00422 
00423 @macro hidaction
00424 
00425 This is one of a number of actions which are part of the HID
00426 interface.  The core functions use these actions to tell the current
00427 GUI when to change the presented information in response to changes
00428 that the GUI may not know about.  The user normally does not invoke
00429 these directly.
00430 
00431 @end macro
00432 
00433 %end-doc */
00434 
00435 
00436 static const char pcbchanged_syntax[] =
00437   "PCBChanged([revert])";
00438 static const char pcbchanged_help[] =
00439   "Tells the GUI that the whole PCB has changed. The optional \"revert\""
00440   "parameter can be used as a hint to the GUI that the same design is being"
00441   "reloaded, and that it might keep some viewport settings";
00442 
00443 /* %start-doc actions PCBChanged
00444 
00445 @hidaction
00446 
00447 %end-doc */
00448 
00449 static const char routestyleschanged_syntax[] = 
00450   "RouteStylesChanged()";
00451 static const char routestyleschanged_help[] = 
00452   "Tells the GUI that the routing styles have changed.";
00453 
00454 /* %start-doc actions RouteStylesChanged
00455 
00456 @hidaction
00457 
00458 %end-doc */
00459 
00460 static const char netlistchanged_syntax[] = 
00461   "NetlistChanged()";
00462 static const char netlistchanged_help[] = 
00463   "Tells the GUI that the netlist has changed.";
00464 
00465 /* %start-doc actions NetlistChanged
00466 
00467 @hidaction
00468 
00469 %end-doc */
00470 
00471 static const char layerschanged_syntax[] = 
00472   "LayersChanged()";
00473 static const char layerschanged_help[] = 
00474   "Tells the GUI that the layers have changed.";
00475 
00476 /* %start-doc actions LayersChanged
00477 
00478 This includes layer names, colors, stacking order, visibility, etc.
00479 
00480 @hidaction
00481 
00482 %end-doc */
00483 
00484 static const char librarychanged_syntax[] = 
00485   "LibraryChanged()";
00486 static const char librarychanged_help[] = 
00487   "Tells the GUI that the libraries have changed.";
00488 
00489 /* %start-doc actions LibraryChanged
00490 
00491 @hidaction
00492 
00493 %end-doc */