Shiny 3D eye-candy
[geda-pcb/pcjc2.git] / src / netlist.c
blobf420fac05c0dfa092ac4e1aed6ac8ceaf65da517
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
27 /* generic netlist operations
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
34 #include <stdlib.h>
35 #ifdef HAVE_STRING_H
36 #include <string.h>
37 #endif
38 #include <ctype.h>
39 #include <sys/types.h>
40 #ifdef HAVE_REGEX_H
41 #include <regex.h>
42 #endif
44 #include "global.h"
45 #include "action.h"
46 #include "buffer.h"
47 #include "data.h"
48 #include "djopt.h"
49 #include "error.h"
50 #include "file.h"
51 #include "find.h"
52 #include "mymem.h"
53 #include "misc.h"
54 #include "rats.h"
55 #include "set.h"
56 #include "vendor.h"
57 #include "create.h"
59 #ifdef HAVE_REGCOMP
60 #undef HAVE_RE_COMP
61 #endif
63 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
64 #define USE_RE
65 #endif
67 #ifdef HAVE_LIBDMALLOC
68 #include <dmalloc.h>
69 #endif
72 int PCB->NetlistLib.MenuN
73 char * PCB->NetlistLib.Menu[i].Name
74 [0] == '*' (ok for rats) or ' ' (skip for rats)
75 [1] == unused
76 [2..] actual name
77 char * PCB->NetlistLib.Menu[i].Style
78 int PCB->NetlistLib.Menu[i].EntryN
79 char * PCB->NetlistLib.Menu[i].Entry[j].ListEntry
82 typedef void (*NFunc) (LibraryMenuType *, LibraryEntryType *);
84 int netlist_frozen = 0;
85 static int netlist_needs_update = 0;
87 void
88 NetlistChanged (int force_unfreeze)
90 if (force_unfreeze)
91 netlist_frozen = 0;
92 if (netlist_frozen)
93 netlist_needs_update = 1;
94 else
96 netlist_needs_update = 0;
97 hid_action ("NetlistChanged");
101 LibraryMenuType *
102 netnode_to_netname (char *nodename)
104 int i, j;
105 /*printf("nodename [%s]\n", nodename);*/
106 for (i=0; i<PCB->NetlistLib.MenuN; i++)
108 for (j=0; j<PCB->NetlistLib.Menu[i].EntryN; j++)
110 if (strcmp (PCB->NetlistLib.Menu[i].Entry[j].ListEntry, nodename) == 0)
112 /*printf(" in [%s]\n", PCB->NetlistLib.Menu[i].Name);*/
113 return & (PCB->NetlistLib.Menu[i]);
117 return 0;
120 LibraryMenuType *
121 netname_to_netname (char *netname)
123 int i;
125 if ((netname[0] == '*' || netname[0] == ' ') && netname[1] == ' ')
127 /* Looks like we were passed an internal netname, skip the prefix */
128 netname += 2;
130 for (i=0; i<PCB->NetlistLib.MenuN; i++)
132 if (strcmp (PCB->NetlistLib.Menu[i].Name + 2, netname) == 0)
134 return & (PCB->NetlistLib.Menu[i]);
137 return 0;
140 static int
141 pin_name_to_xy (LibraryEntryType * pin, int *x, int *y)
143 ConnectionType conn;
144 if (!SeekPad (pin, &conn, false))
145 return 1;
146 switch (conn.type)
148 case PIN_TYPE:
149 *x = ((PinType *) (conn.ptr2))->X;
150 *y = ((PinType *) (conn.ptr2))->Y;
151 return 0;
152 case PAD_TYPE:
153 *x = ((PadType *) (conn.ptr2))->Point1.X;
154 *y = ((PadType *) (conn.ptr2))->Point1.Y;
155 return 0;
157 return 1;
160 static void
161 netlist_find (LibraryMenuType * net, LibraryEntryType * pin)
163 int x, y;
164 if (pin_name_to_xy (net->Entry, &x, &y))
165 return;
166 LookupConnection (x, y, 1, 1, FOUNDFLAG, true);
169 static void
170 netlist_select (LibraryMenuType * net, LibraryEntryType * pin)
172 int x, y;
173 if (pin_name_to_xy (net->Entry, &x, &y))
174 return;
175 LookupConnection (x, y, 1, 1, SELECTEDFLAG, true);
178 static void
179 netlist_rats (LibraryMenuType * net, LibraryEntryType * pin)
181 net->Name[0] = ' ';
182 net->flag = 1;
183 NetlistChanged (0);
186 static void
187 netlist_norats (LibraryMenuType * net, LibraryEntryType * pin)
189 net->Name[0] = '*';
190 net->flag = 0;
191 NetlistChanged (0);
194 /* The primary purpose of this action is to remove the netlist
195 completely so that a new one can be loaded, usually via a gsch2pcb
196 style script. */
197 static void
198 netlist_clear (LibraryMenuType * net, LibraryEntryType * pin)
200 LibraryType *netlist = &PCB->NetlistLib;
201 int ni, pi;
203 if (net == 0)
205 /* Clear the entire netlist. */
206 FreeLibraryMemory (&PCB->NetlistLib);
208 else if (pin == 0)
210 /* Remove a net from the netlist. */
211 ni = net - netlist->Menu;
212 if (ni >= 0 && ni < netlist->MenuN)
214 /* if there is exactly one item, MenuN is 1 and ni is 0 */
215 if (netlist->MenuN - ni > 1)
216 memmove (net, net+1, (netlist->MenuN - ni - 1) * sizeof (*net));
217 netlist->MenuN --;
220 else
222 /* Remove a pin from the given net. Note that this may leave an
223 empty net, which is different than removing the net
224 (above). */
225 pi = pin - net->Entry;
226 if (pi >= 0 && pi < net->EntryN)
228 /* if there is exactly one item, MenuN is 1 and ni is 0 */
229 if (net->EntryN - pi > 1)
230 memmove (pin, pin+1, (net->EntryN - pi - 1) * sizeof (*pin));
231 net->EntryN --;
234 NetlistChanged (0);
237 static void
238 netlist_style (LibraryMenuType *net, const char *style)
240 free (net->Style);
241 net->Style = STRDUP ((char *)style);
244 /* The primary purpose of this action is to rebuild a netlist from a
245 script, in conjunction with the clear action above. */
246 static int
247 netlist_add (const char *netname, const char *pinname)
249 int ni, pi;
250 LibraryType *netlist = &PCB->NetlistLib;
251 LibraryMenuType *net = NULL;
252 LibraryEntryType *pin = NULL;
254 for (ni=0; ni<netlist->MenuN; ni++)
255 if (strcmp (netlist->Menu[ni].Name+2, netname) == 0)
257 net = & (netlist->Menu[ni]);
258 break;
260 if (net == NULL)
262 net = CreateNewNet (netlist, (char *)netname, NULL);
265 for (pi=0; pi<net->EntryN; pi++)
266 if (strcmp (net->Entry[pi].ListEntry, pinname) == 0)
268 pin = & (net->Entry[pi]);
269 break;
271 if (pin == NULL)
273 pin = CreateNewConnection (net, (char *)pinname);
276 NetlistChanged (0);
277 return 0;
280 static const char netlist_syntax[] =
281 "Net(find|select|rats|norats|clear[,net[,pin]])\n"
282 "Net(freeze|thaw|forcethaw)\n"
283 "Net(add,net,pin)";
285 static const char netlist_help[] = "Perform various actions on netlists.";
287 /* %start-doc actions Netlist
289 Each of these actions apply to a specified set of nets. @var{net} and
290 @var{pin} are patterns which match one or more nets or pins; these
291 patterns may be full names or regular expressions. If an exact match
292 is found, it is the only match; if no exact match is found,
293 @emph{then} the pattern is tried as a regular expression.
295 If neither @var{net} nor @var{pin} are specified, all nets apply. If
296 @var{net} is specified but not @var{pin}, all nets matching @var{net}
297 apply. If both are specified, nets which match @var{net} and contain
298 a pin matching @var{pin} apply.
300 @table @code
302 @item find
303 Nets which apply are marked @emph{found} and are drawn in the
304 @code{connected-color} color.
306 @item select
307 Nets which apply are selected.
309 @item rats
310 Nets which apply are marked as available for the rats nest.
312 @item norats
313 Nets which apply are marked as not available for the rats nest.
315 @item clear
316 Clears the netlist.
318 @item add
319 Add the given pin to the given netlist, creating either if needed.
321 @item sort
322 Called after a list of add's, this sorts the netlist.
324 @item freeze
325 @itemx thaw
326 @itemx forcethaw
327 Temporarily prevents changes to the netlist from being reflected in
328 the GUI. For example, if you need to make multiple changes, you
329 freeze the netlist, make the changes, then thaw it. Note that
330 freeze/thaw requests may nest, with the netlist being fully thawed
331 only when all pending freezes are thawed. You can bypass the nesting
332 by using forcethaw, which resets the freeze count and immediately
333 updates the GUI.
335 @end table
337 %end-doc */
339 #define ARG(n) (argc > (n) ? argv[n] : 0)
341 static int
342 Netlist (int argc, char **argv, Coord x, Coord y)
344 NFunc func;
345 int i, j;
346 LibraryMenuType *net;
347 LibraryEntryType *pin;
348 int net_found = 0;
349 int pin_found = 0;
350 #if defined(USE_RE)
351 int use_re = 0;
352 #endif
353 #if defined(HAVE_REGCOMP)
354 regex_t elt_pattern;
355 regmatch_t match;
356 #endif
357 #if defined(HAVE_RE_COMP)
358 char *elt_pattern;
359 #endif
361 if (!PCB)
362 return 1;
363 if (argc == 0)
365 Message (netlist_syntax);
366 return 1;
368 if (strcasecmp (argv[0], "find") == 0)
369 func = netlist_find;
370 else if (strcasecmp (argv[0], "select") == 0)
371 func = netlist_select;
372 else if (strcasecmp (argv[0], "rats") == 0)
373 func = netlist_rats;
374 else if (strcasecmp (argv[0], "norats") == 0)
375 func = netlist_norats;
376 else if (strcasecmp (argv[0], "clear") == 0)
378 func = netlist_clear;
379 if (argc == 1)
381 netlist_clear (NULL, NULL);
382 return 0;
385 else if (strcasecmp (argv[0], "style") == 0)
386 func = (NFunc)netlist_style;
387 else if (strcasecmp (argv[0], "add") == 0)
389 /* Add is different, because the net/pin won't already exist. */
390 return netlist_add (ARG(1), ARG(2));
392 else if (strcasecmp (argv[0], "sort") == 0)
394 sort_netlist ();
395 return 0;
397 else if (strcasecmp (argv[0], "freeze") == 0)
399 netlist_frozen ++;
400 return 0;
402 else if (strcasecmp (argv[0], "thaw") == 0)
404 if (netlist_frozen > 0)
406 netlist_frozen --;
407 if (netlist_needs_update)
408 NetlistChanged (0);
410 return 0;
412 else if (strcasecmp (argv[0], "forcethaw") == 0)
414 netlist_frozen = 0;
415 if (netlist_needs_update)
416 NetlistChanged (0);
417 return 0;
419 else
421 Message (netlist_syntax);
422 return 1;
425 #if defined(USE_RE)
426 if (argc > 1)
428 int result;
429 use_re = 1;
430 for (i = 0; i < PCB->NetlistLib.MenuN; i++)
432 net = PCB->NetlistLib.Menu + i;
433 if (strcasecmp (argv[1], net->Name + 2) == 0)
434 use_re = 0;
436 if (use_re)
438 #if defined(HAVE_REGCOMP)
439 result =
440 regcomp (&elt_pattern, argv[1],
441 REG_EXTENDED | REG_ICASE | REG_NOSUB);
442 if (result)
444 char errorstring[128];
446 regerror (result, &elt_pattern, errorstring, 128);
447 Message (_("regexp error: %s\n"), errorstring);
448 regfree (&elt_pattern);
449 return (1);
451 #endif
452 #if defined(HAVE_RE_COMP)
453 if ((elt_pattern = re_comp (argv[1])) != NULL)
455 Message (_("re_comp error: %s\n"), elt_pattern);
456 return (false);
458 #endif
461 #endif
463 for (i = PCB->NetlistLib.MenuN-1; i >= 0; i--)
465 net = PCB->NetlistLib.Menu + i;
467 if (argc > 1)
469 #if defined(USE_RE)
470 if (use_re)
472 #if defined(HAVE_REGCOMP)
473 if (regexec (&elt_pattern, net->Name + 2, 1, &match, 0) != 0)
474 continue;
475 #endif
476 #if defined(HAVE_RE_COMP)
477 if (re_exec (net->Name + 2) != 1)
478 continue;
479 #endif
481 else
482 #endif
483 if (strcasecmp (net->Name + 2, argv[1]))
484 continue;
486 net_found = 1;
488 pin = 0;
489 if (func == (void *)netlist_style)
491 netlist_style (net, ARG(2));
493 else if (argc > 2)
495 int l = strlen (argv[2]);
496 for (j = net->EntryN-1; j >= 0 ; j--)
497 if (strcasecmp (net->Entry[j].ListEntry, argv[2]) == 0
498 || (strncasecmp (net->Entry[j].ListEntry, argv[2], l) == 0
499 && net->Entry[j].ListEntry[l] == '-'))
501 pin = net->Entry + j;
502 pin_found = 1;
503 func (net, pin);
506 else
507 func (net, 0);
510 if (argc > 2 && !pin_found)
512 gui->log ("Net %s has no pin %s\n", argv[1], argv[2]);
513 return 1;
515 else if (!net_found)
517 gui->log ("No net named %s\n", argv[1]);
519 #ifdef HAVE_REGCOMP
520 if (use_re)
521 regfree (&elt_pattern);
522 #endif
524 return 0;
527 HID_Action netlist_action_list[] = {
528 {"net", 0, Netlist,
529 netlist_help, netlist_syntax}
531 {"netlist", 0, Netlist,
532 netlist_help, netlist_syntax}
535 REGISTER_ACTIONS (netlist_action_list)