pcb 4.1.1
An interactive printed circuit board layout editor.
|
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 */