Move internationalization macros to one header
[geda-pcb/gde.git] / src / netlist.c
blobbe81e4e787d2438cd0e9ec926a1e16bc517f1c8c
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
29 /* generic netlist operations
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
36 #include <stdlib.h>
37 #ifdef HAVE_STRING_H
38 #include <string.h>
39 #endif
40 #include <ctype.h>
41 #include <sys/types.h>
42 #ifdef HAVE_REGEX_H
43 #include <regex.h>
44 #endif
46 #include "global.h"
47 #include "action.h"
48 #include "buffer.h"
49 #include "command.h"
50 #include "data.h"
51 #include "djopt.h"
52 #include "error.h"
53 #include "file.h"
54 #include "find.h"
55 #include "mymem.h"
56 #include "misc.h"
57 #include "rats.h"
58 #include "set.h"
59 #include "vendor.h"
60 #include "create.h"
62 #ifdef HAVE_REGCOMP
63 #undef HAVE_RE_COMP
64 #endif
66 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
67 #define USE_RE
68 #endif
70 #ifdef HAVE_LIBDMALLOC
71 #include <dmalloc.h>
72 #endif
74 RCSID ("$Id$");
77 int PCB->NetlistLib.MenuN
78 char * PCB->NetlistLib.Menu[i].Name
79 [0] == '*' (ok for rats) or ' ' (skip for rats)
80 [1] == unused
81 [2..] actual name
82 char * PCB->NetlistLib.Menu[i].Style
83 int PCB->NetlistLib.Menu[i].EntryN
84 char * PCB->NetlistLib.Menu[i].Entry[j].ListEntry
87 typedef void (*NFunc) (LibraryMenuType *, LibraryEntryType *);
89 int netlist_frozen = 0;
90 static int netlist_needs_update = 0;
92 void
93 NetlistChanged (int force_unfreeze)
95 if (force_unfreeze)
96 netlist_frozen = 0;
97 if (netlist_frozen)
98 netlist_needs_update = 1;
99 else
101 netlist_needs_update = 0;
102 hid_action ("NetlistChanged");
106 LibraryMenuTypePtr
107 netnode_to_netname (char *nodename)
109 int i, j;
110 /*printf("nodename [%s]\n", nodename);*/
111 for (i=0; i<PCB->NetlistLib.MenuN; i++)
113 for (j=0; j<PCB->NetlistLib.Menu[i].EntryN; j++)
115 if (strcmp (PCB->NetlistLib.Menu[i].Entry[j].ListEntry, nodename) == 0)
117 /*printf(" in [%s]\n", PCB->NetlistLib.Menu[i].Name);*/
118 return & (PCB->NetlistLib.Menu[i]);
122 return 0;
125 LibraryMenuTypePtr
126 netname_to_netname (char *netname)
128 int i;
130 if ((netname[0] == '*' || netname[0] == ' ') && netname[1] == ' ')
132 /* Looks like we were passed an internal netname, skip the prefix */
133 netname += 2;
135 for (i=0; i<PCB->NetlistLib.MenuN; i++)
137 if (strcmp (PCB->NetlistLib.Menu[i].Name + 2, netname) == 0)
139 return & (PCB->NetlistLib.Menu[i]);
142 return 0;
145 static int
146 pin_name_to_xy (LibraryEntryType * pin, int *x, int *y)
148 ConnectionType conn;
149 if (!SeekPad (pin, &conn, False))
150 return 1;
151 switch (conn.type)
153 case PIN_TYPE:
154 *x = ((PinType *) (conn.ptr2))->X;
155 *y = ((PinType *) (conn.ptr2))->Y;
156 return 0;
157 case PAD_TYPE:
158 *x = ((PadType *) (conn.ptr2))->Point1.X;
159 *y = ((PadType *) (conn.ptr2))->Point1.Y;
160 return 0;
162 return 1;
165 static void
166 netlist_find (LibraryMenuType * net, LibraryEntryType * pin)
168 int x, y;
169 if (pin_name_to_xy (net->Entry, &x, &y))
170 return;
171 LookupConnection (x, y, 1, 1, FOUNDFLAG);
174 static void
175 netlist_select (LibraryMenuType * net, LibraryEntryType * pin)
177 int x, y;
178 if (pin_name_to_xy (net->Entry, &x, &y))
179 return;
180 LookupConnection (x, y, 1, 1, SELECTEDFLAG);
183 static void
184 netlist_rats (LibraryMenuType * net, LibraryEntryType * pin)
186 net->Name[0] = ' ';
187 net->flag = 1;
188 NetlistChanged (0);
191 static void
192 netlist_norats (LibraryMenuType * net, LibraryEntryType * pin)
194 net->Name[0] = '*';
195 net->flag = 0;
196 NetlistChanged (0);
199 /* The primary purpose of this action is to remove the netlist
200 completely so that a new one can be loaded, usually via a gsch2pcb
201 style script. */
202 static void
203 netlist_clear (LibraryMenuType * net, LibraryEntryType * pin)
205 LibraryType *netlist = &PCB->NetlistLib;
206 int ni, pi;
208 if (net == 0)
210 /* Clear the entire netlist. */
211 FreeLibraryMemory (&PCB->NetlistLib);
213 else if (pin == 0)
215 /* Remove a net from the netlist. */
216 ni = net - netlist->Menu;
217 if (ni >= 0 && ni < netlist->MenuN)
219 /* if there is exactly one item, MenuN is 1 and ni is 0 */
220 if (netlist->MenuN - ni > 1)
221 memmove (net, net+1, (netlist->MenuN - ni - 1) * sizeof (*net));
222 netlist->MenuN --;
225 else
227 /* Remove a pin from the given net. Note that this may leave an
228 empty net, which is different than removing the net
229 (above). */
230 pi = pin - net->Entry;
231 if (pi >= 0 && pi < net->EntryN)
233 /* if there is exactly one item, MenuN is 1 and ni is 0 */
234 if (net->EntryN - pi > 1)
235 memmove (pin, pin+1, (net->EntryN - pi - 1) * sizeof (*pin));
236 net->EntryN --;
239 NetlistChanged (0);
242 static void
243 netlist_style (LibraryMenuType *net, const char *style)
245 if (net->Style)
246 MYFREE (net->Style);
247 if (style)
248 net->Style = MyStrdup ((char *)style, "Netlist(Style)");
251 /* The primary purpose of this action is to rebuild a netlist from a
252 script, in conjunction with the clear action above. */
253 static int
254 netlist_add (const char *netname, const char *pinname)
256 int ni, pi;
257 LibraryType *netlist = &PCB->NetlistLib;
258 LibraryMenuType *net = NULL;
259 LibraryEntryType *pin = NULL;
261 for (ni=0; ni<netlist->MenuN; ni++)
262 if (strcmp (netlist->Menu[ni].Name+2, netname) == 0)
264 net = & (netlist->Menu[ni]);
265 break;
267 if (net == NULL)
269 net = CreateNewNet (netlist, (char *)netname, NULL);
272 for (pi=0; pi<net->EntryN; pi++)
273 if (strcmp (net->Entry[pi].ListEntry, pinname) == 0)
275 pin = & (net->Entry[pi]);
276 break;
278 if (pin == NULL)
280 pin = CreateNewConnection (net, (char *)pinname);
283 NetlistChanged (0);
284 return 0;
287 static const char netlist_syntax[] =
288 "Net(find|select|rats|norats|clear[,net[,pin]])\n"
289 "Net(freeze|thaw|forcethaw)\n"
290 "Net(add,net,pin)";
292 static const char netlist_help[] = "Perform various actions on netlists.";
294 /* %start-doc actions Netlist
296 Each of these actions apply to a specified set of nets. @var{net} and
297 @var{pin} are patterns which match one or more nets or pins; these
298 patterns may be full names or regular expressions. If an exact match
299 is found, it is the only match; if no exact match is found,
300 @emph{then} the pattern is tried as a regular expression.
302 If neither @var{net} nor @var{pin} are specified, all nets apply. If
303 @var{net} is specified but not @var{pin}, all nets matching @var{net}
304 apply. If both are specified, nets which match @var{net} and contain
305 a pin matching @var{pin} apply.
307 @table @code
309 @item find
310 Nets which apply are marked @emph{found} and are drawn in the
311 @code{connected-color} color.
313 @item select
314 Nets which apply are selected.
316 @item rats
317 Nets which apply are marked as available for the rats nest.
319 @item norats
320 Nets which apply are marked as not available for the rats nest.
322 @item clear
323 Clears the netlist.
325 @item add
326 Add the given pin to the given netlist, creating either if needed.
328 @item sort
329 Called after a list of add's, this sorts the netlist.
331 @item freeze
332 @itemx thaw
333 @itemx forcethaw
334 Temporarily prevents changes to the netlist from being reflected in
335 the GUI. For example, if you need to make multiple changes, you
336 freeze the netlist, make the changes, then thaw it. Note that
337 freeze/thaw requests may nest, with the netlist being fully thawed
338 only when all pending freezes are thawed. You can bypass the nesting
339 by using forcethaw, which resets the freeze count and immediately
340 updates the GUI.
342 @end table
344 %end-doc */
346 #define ARG(n) (argc > (n) ? argv[n] : 0)
348 static int
349 Netlist (int argc, char **argv, int x, int y)
351 NFunc func;
352 int i, j;
353 LibraryMenuType *net;
354 LibraryEntryType *pin;
355 int net_found = 0;
356 int pin_found = 0;
357 #if defined(USE_RE)
358 int use_re = 0;
359 #endif
360 #if defined(HAVE_REGCOMP)
361 regex_t elt_pattern;
362 regmatch_t match;
363 #endif
364 #if defined(HAVE_RE_COMP)
365 char *elt_pattern;
366 #endif
368 if (!PCB)
369 return 1;
370 if (argc == 0)
372 Message (netlist_syntax);
373 return 1;
375 if (strcasecmp (argv[0], "find") == 0)
376 func = netlist_find;
377 else if (strcasecmp (argv[0], "select") == 0)
378 func = netlist_select;
379 else if (strcasecmp (argv[0], "rats") == 0)
380 func = netlist_rats;
381 else if (strcasecmp (argv[0], "norats") == 0)
382 func = netlist_norats;
383 else if (strcasecmp (argv[0], "clear") == 0)
385 func = netlist_clear;
386 if (argc == 1)
388 netlist_clear (NULL, NULL);
389 return 0;
392 else if (strcasecmp (argv[0], "style") == 0)
393 func = (void *)netlist_style;
394 else if (strcasecmp (argv[0], "add") == 0)
396 /* Add is different, because the net/pin won't already exist. */
397 return netlist_add (ARG(1), ARG(2));
399 else if (strcasecmp (argv[0], "sort") == 0)
401 sort_netlist ();
402 return 0;
404 else if (strcasecmp (argv[0], "freeze") == 0)
406 netlist_frozen ++;
407 return 0;
409 else if (strcasecmp (argv[0], "thaw") == 0)
411 if (netlist_frozen > 0)
413 netlist_frozen --;
414 if (netlist_needs_update)
415 NetlistChanged (0);
417 return 0;
419 else if (strcasecmp (argv[0], "forcethaw") == 0)
421 netlist_frozen = 0;
422 if (netlist_needs_update)
423 NetlistChanged (0);
424 return 0;
426 else
428 Message (netlist_syntax);
429 return 1;
432 #if defined(USE_RE)
433 if (argc > 1)
435 int result;
436 use_re = 1;
437 for (i = 0; i < PCB->NetlistLib.MenuN; i++)
439 net = PCB->NetlistLib.Menu + i;
440 if (strcasecmp (argv[1], net->Name + 2) == 0)
441 use_re = 0;
443 if (use_re)
445 #if defined(HAVE_REGCOMP)
446 result =
447 regcomp (&elt_pattern, argv[1],
448 REG_EXTENDED | REG_ICASE | REG_NOSUB);
449 if (result)
451 char errorstring[128];
453 regerror (result, &elt_pattern, errorstring, 128);
454 Message (_("regexp error: %s\n"), errorstring);
455 regfree (&elt_pattern);
456 return (1);
458 #endif
459 #if defined(HAVE_RE_COMP)
460 if ((elt_pattern = re_comp (argv[1])) != NULL)
462 Message (_("re_comp error: %s\n"), elt_pattern);
463 return (False);
465 #endif
468 #endif
470 for (i = PCB->NetlistLib.MenuN-1; i >= 0; i--)
472 net = PCB->NetlistLib.Menu + i;
474 if (argc > 1)
476 #if defined(USE_RE)
477 if (use_re)
479 #if defined(HAVE_REGCOMP)
480 if (regexec (&elt_pattern, net->Name + 2, 1, &match, 0) != 0)
481 continue;
482 #endif
483 #if defined(HAVE_RE_COMP)
484 if (re_exec (net->Name + 2) != 1)
485 continue;
486 #endif
488 else
489 #endif
490 if (strcasecmp (net->Name + 2, argv[1]))
491 continue;
493 net_found = 1;
495 pin = 0;
496 if (func == (void *)netlist_style)
498 netlist_style (net, ARG(2));
500 else if (argc > 2)
502 int l = strlen (argv[2]);
503 for (j = net->EntryN-1; j >= 0 ; j--)
504 if (strcasecmp (net->Entry[j].ListEntry, argv[2]) == 0
505 || (strncasecmp (net->Entry[j].ListEntry, argv[2], l) == 0
506 && net->Entry[j].ListEntry[l] == '-'))
508 pin = net->Entry + j;
509 pin_found = 1;
510 func (net, pin);
513 else
514 func (net, 0);
517 if (argc > 2 && !pin_found)
519 gui->log ("Net %s has no pin %s\n", argv[1], argv[2]);
520 return 1;
522 else if (!net_found)
524 gui->log ("No net named %s\n", argv[1]);
526 #ifdef HAVE_REGCOMP
527 if (use_re)
528 regfree (&elt_pattern);
529 #endif
531 return 0;
534 HID_Action netlist_action_list[] = {
535 {"net", 0, Netlist,
536 netlist_help, netlist_syntax}
538 {"netlist", 0, Netlist,
539 netlist_help, netlist_syntax}
542 REGISTER_ACTIONS (netlist_action_list)