gerber.c: Tidy up use_gc() routine to avoid a static anlysis warning
[geda-pcb/pcjc2.git] / src / netlist.c
blob06f0e7739720da1a67cf325239c10f8d0de4bd19
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 free (net->Style);
246 net->Style = STRDUP ((char *)style);
249 /* The primary purpose of this action is to rebuild a netlist from a
250 script, in conjunction with the clear action above. */
251 static int
252 netlist_add (const char *netname, const char *pinname)
254 int ni, pi;
255 LibraryType *netlist = &PCB->NetlistLib;
256 LibraryMenuType *net = NULL;
257 LibraryEntryType *pin = NULL;
259 for (ni=0; ni<netlist->MenuN; ni++)
260 if (strcmp (netlist->Menu[ni].Name+2, netname) == 0)
262 net = & (netlist->Menu[ni]);
263 break;
265 if (net == NULL)
267 net = CreateNewNet (netlist, (char *)netname, NULL);
270 for (pi=0; pi<net->EntryN; pi++)
271 if (strcmp (net->Entry[pi].ListEntry, pinname) == 0)
273 pin = & (net->Entry[pi]);
274 break;
276 if (pin == NULL)
278 pin = CreateNewConnection (net, (char *)pinname);
281 NetlistChanged (0);
282 return 0;
285 static const char netlist_syntax[] =
286 "Net(find|select|rats|norats|clear[,net[,pin]])\n"
287 "Net(freeze|thaw|forcethaw)\n"
288 "Net(add,net,pin)";
290 static const char netlist_help[] = "Perform various actions on netlists.";
292 /* %start-doc actions Netlist
294 Each of these actions apply to a specified set of nets. @var{net} and
295 @var{pin} are patterns which match one or more nets or pins; these
296 patterns may be full names or regular expressions. If an exact match
297 is found, it is the only match; if no exact match is found,
298 @emph{then} the pattern is tried as a regular expression.
300 If neither @var{net} nor @var{pin} are specified, all nets apply. If
301 @var{net} is specified but not @var{pin}, all nets matching @var{net}
302 apply. If both are specified, nets which match @var{net} and contain
303 a pin matching @var{pin} apply.
305 @table @code
307 @item find
308 Nets which apply are marked @emph{found} and are drawn in the
309 @code{connected-color} color.
311 @item select
312 Nets which apply are selected.
314 @item rats
315 Nets which apply are marked as available for the rats nest.
317 @item norats
318 Nets which apply are marked as not available for the rats nest.
320 @item clear
321 Clears the netlist.
323 @item add
324 Add the given pin to the given netlist, creating either if needed.
326 @item sort
327 Called after a list of add's, this sorts the netlist.
329 @item freeze
330 @itemx thaw
331 @itemx forcethaw
332 Temporarily prevents changes to the netlist from being reflected in
333 the GUI. For example, if you need to make multiple changes, you
334 freeze the netlist, make the changes, then thaw it. Note that
335 freeze/thaw requests may nest, with the netlist being fully thawed
336 only when all pending freezes are thawed. You can bypass the nesting
337 by using forcethaw, which resets the freeze count and immediately
338 updates the GUI.
340 @end table
342 %end-doc */
344 #define ARG(n) (argc > (n) ? argv[n] : 0)
346 static int
347 Netlist (int argc, char **argv, Coord x, Coord y)
349 NFunc func;
350 int i, j;
351 LibraryMenuType *net;
352 LibraryEntryType *pin;
353 int net_found = 0;
354 int pin_found = 0;
355 #if defined(USE_RE)
356 int use_re = 0;
357 #endif
358 #if defined(HAVE_REGCOMP)
359 regex_t elt_pattern;
360 regmatch_t match;
361 #endif
362 #if defined(HAVE_RE_COMP)
363 char *elt_pattern;
364 #endif
366 if (!PCB)
367 return 1;
368 if (argc == 0)
370 Message (netlist_syntax);
371 return 1;
373 if (strcasecmp (argv[0], "find") == 0)
374 func = netlist_find;
375 else if (strcasecmp (argv[0], "select") == 0)
376 func = netlist_select;
377 else if (strcasecmp (argv[0], "rats") == 0)
378 func = netlist_rats;
379 else if (strcasecmp (argv[0], "norats") == 0)
380 func = netlist_norats;
381 else if (strcasecmp (argv[0], "clear") == 0)
383 func = netlist_clear;
384 if (argc == 1)
386 netlist_clear (NULL, NULL);
387 return 0;
390 else if (strcasecmp (argv[0], "style") == 0)
391 func = (NFunc)netlist_style;
392 else if (strcasecmp (argv[0], "add") == 0)
394 /* Add is different, because the net/pin won't already exist. */
395 return netlist_add (ARG(1), ARG(2));
397 else if (strcasecmp (argv[0], "sort") == 0)
399 sort_netlist ();
400 return 0;
402 else if (strcasecmp (argv[0], "freeze") == 0)
404 netlist_frozen ++;
405 return 0;
407 else if (strcasecmp (argv[0], "thaw") == 0)
409 if (netlist_frozen > 0)
411 netlist_frozen --;
412 if (netlist_needs_update)
413 NetlistChanged (0);
415 return 0;
417 else if (strcasecmp (argv[0], "forcethaw") == 0)
419 netlist_frozen = 0;
420 if (netlist_needs_update)
421 NetlistChanged (0);
422 return 0;
424 else
426 Message (netlist_syntax);
427 return 1;
430 #if defined(USE_RE)
431 if (argc > 1)
433 int result;
434 use_re = 1;
435 for (i = 0; i < PCB->NetlistLib.MenuN; i++)
437 net = PCB->NetlistLib.Menu + i;
438 if (strcasecmp (argv[1], net->Name + 2) == 0)
439 use_re = 0;
441 if (use_re)
443 #if defined(HAVE_REGCOMP)
444 result =
445 regcomp (&elt_pattern, argv[1],
446 REG_EXTENDED | REG_ICASE | REG_NOSUB);
447 if (result)
449 char errorstring[128];
451 regerror (result, &elt_pattern, errorstring, 128);
452 Message (_("regexp error: %s\n"), errorstring);
453 regfree (&elt_pattern);
454 return (1);
456 #endif
457 #if defined(HAVE_RE_COMP)
458 if ((elt_pattern = re_comp (argv[1])) != NULL)
460 Message (_("re_comp error: %s\n"), elt_pattern);
461 return (false);
463 #endif
466 #endif
468 for (i = PCB->NetlistLib.MenuN-1; i >= 0; i--)
470 net = PCB->NetlistLib.Menu + i;
472 if (argc > 1)
474 #if defined(USE_RE)
475 if (use_re)
477 #if defined(HAVE_REGCOMP)
478 if (regexec (&elt_pattern, net->Name + 2, 1, &match, 0) != 0)
479 continue;
480 #endif
481 #if defined(HAVE_RE_COMP)
482 if (re_exec (net->Name + 2) != 1)
483 continue;
484 #endif
486 else
487 #endif
488 if (strcasecmp (net->Name + 2, argv[1]))
489 continue;
491 net_found = 1;
493 pin = 0;
494 if (func == (void *)netlist_style)
496 netlist_style (net, ARG(2));
498 else if (argc > 2)
500 int l = strlen (argv[2]);
501 for (j = net->EntryN-1; j >= 0 ; j--)
502 if (strcasecmp (net->Entry[j].ListEntry, argv[2]) == 0
503 || (strncasecmp (net->Entry[j].ListEntry, argv[2], l) == 0
504 && net->Entry[j].ListEntry[l] == '-'))
506 pin = net->Entry + j;
507 pin_found = 1;
508 func (net, pin);
511 else
512 func (net, 0);
515 if (argc > 2 && !pin_found)
517 gui->log ("Net %s has no pin %s\n", argv[1], argv[2]);
518 return 1;
520 else if (!net_found)
522 gui->log ("No net named %s\n", argv[1]);
524 #ifdef HAVE_REGCOMP
525 if (use_re)
526 regfree (&elt_pattern);
527 #endif
529 return 0;
532 HID_Action netlist_action_list[] = {
533 {"net", 0, Netlist,
534 netlist_help, netlist_syntax}
536 {"netlist", 0, Netlist,
537 netlist_help, netlist_syntax}
540 REGISTER_ACTIONS (netlist_action_list)