(no commit message)
[geda-pcb/pcjc2.git] / src / netlist.c
blob4a17eece4e9daaf7604d7f8498911027e647665f
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 "command.h"
48 #include "data.h"
49 #include "djopt.h"
50 #include "error.h"
51 #include "file.h"
52 #include "find.h"
53 #include "mymem.h"
54 #include "misc.h"
55 #include "rats.h"
56 #include "set.h"
57 #include "vendor.h"
58 #include "create.h"
60 #ifdef HAVE_REGCOMP
61 #undef HAVE_RE_COMP
62 #endif
64 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
65 #define USE_RE
66 #endif
68 #ifdef HAVE_LIBDMALLOC
69 #include <dmalloc.h>
70 #endif
73 int PCB->NetlistLib.MenuN
74 char * PCB->NetlistLib.Menu[i].Name
75 [0] == '*' (ok for rats) or ' ' (skip for rats)
76 [1] == unused
77 [2..] actual name
78 char * PCB->NetlistLib.Menu[i].Style
79 int PCB->NetlistLib.Menu[i].EntryN
80 char * PCB->NetlistLib.Menu[i].Entry[j].ListEntry
83 typedef void (*NFunc) (LibraryMenuType *, LibraryEntryType *);
85 int netlist_frozen = 0;
86 static int netlist_needs_update = 0;
88 void
89 NetlistChanged (int force_unfreeze)
91 if (force_unfreeze)
92 netlist_frozen = 0;
93 if (netlist_frozen)
94 netlist_needs_update = 1;
95 else
97 netlist_needs_update = 0;
98 hid_action ("NetlistChanged");
102 LibraryMenuType *
103 netnode_to_netname (char *nodename)
105 int i, j;
106 /*printf("nodename [%s]\n", nodename);*/
107 for (i=0; i<PCB->NetlistLib.MenuN; i++)
109 for (j=0; j<PCB->NetlistLib.Menu[i].EntryN; j++)
111 if (strcmp (PCB->NetlistLib.Menu[i].Entry[j].ListEntry, nodename) == 0)
113 /*printf(" in [%s]\n", PCB->NetlistLib.Menu[i].Name);*/
114 return & (PCB->NetlistLib.Menu[i]);
118 return 0;
121 LibraryMenuType *
122 netname_to_netname (char *netname)
124 int i;
126 if ((netname[0] == '*' || netname[0] == ' ') && netname[1] == ' ')
128 /* Looks like we were passed an internal netname, skip the prefix */
129 netname += 2;
131 for (i=0; i<PCB->NetlistLib.MenuN; i++)
133 if (strcmp (PCB->NetlistLib.Menu[i].Name + 2, netname) == 0)
135 return & (PCB->NetlistLib.Menu[i]);
138 return 0;
141 static int
142 pin_name_to_xy (LibraryEntryType * pin, int *x, int *y)
144 ConnectionType conn;
145 if (!SeekPad (pin, &conn, false))
146 return 1;
147 switch (conn.type)
149 case PIN_TYPE:
150 *x = ((PinType *) (conn.ptr2))->X;
151 *y = ((PinType *) (conn.ptr2))->Y;
152 return 0;
153 case PAD_TYPE:
154 *x = ((PadType *) (conn.ptr2))->Point1.X;
155 *y = ((PadType *) (conn.ptr2))->Point1.Y;
156 return 0;
158 return 1;
161 static void
162 netlist_find (LibraryMenuType * net, LibraryEntryType * pin)
164 int x, y;
165 if (pin_name_to_xy (net->Entry, &x, &y))
166 return;
167 LookupConnection (x, y, 1, 1, FOUNDFLAG, true);
170 static void
171 netlist_select (LibraryMenuType * net, LibraryEntryType * pin)
173 int x, y;
174 if (pin_name_to_xy (net->Entry, &x, &y))
175 return;
176 LookupConnection (x, y, 1, 1, SELECTEDFLAG, true);
179 static void
180 netlist_rats (LibraryMenuType * net, LibraryEntryType * pin)
182 net->Name[0] = ' ';
183 net->flag = 1;
184 NetlistChanged (0);
187 static void
188 netlist_norats (LibraryMenuType * net, LibraryEntryType * pin)
190 net->Name[0] = '*';
191 net->flag = 0;
192 NetlistChanged (0);
195 /* The primary purpose of this action is to remove the netlist
196 completely so that a new one can be loaded, usually via a gsch2pcb
197 style script. */
198 static void
199 netlist_clear (LibraryMenuType * net, LibraryEntryType * pin)
201 LibraryType *netlist = &PCB->NetlistLib;
202 int ni, pi;
204 if (net == 0)
206 /* Clear the entire netlist. */
207 FreeLibraryMemory (&PCB->NetlistLib);
209 else if (pin == 0)
211 /* Remove a net from the netlist. */
212 ni = net - netlist->Menu;
213 if (ni >= 0 && ni < netlist->MenuN)
215 /* if there is exactly one item, MenuN is 1 and ni is 0 */
216 if (netlist->MenuN - ni > 1)
217 memmove (net, net+1, (netlist->MenuN - ni - 1) * sizeof (*net));
218 netlist->MenuN --;
221 else
223 /* Remove a pin from the given net. Note that this may leave an
224 empty net, which is different than removing the net
225 (above). */
226 pi = pin - net->Entry;
227 if (pi >= 0 && pi < net->EntryN)
229 /* if there is exactly one item, MenuN is 1 and ni is 0 */
230 if (net->EntryN - pi > 1)
231 memmove (pin, pin+1, (net->EntryN - pi - 1) * sizeof (*pin));
232 net->EntryN --;
235 NetlistChanged (0);
238 static void
239 netlist_style (LibraryMenuType *net, const char *style)
241 free (net->Style);
242 net->Style = STRDUP ((char *)style);
245 /* The primary purpose of this action is to rebuild a netlist from a
246 script, in conjunction with the clear action above. */
247 static int
248 netlist_add (const char *netname, const char *pinname)
250 int ni, pi;
251 LibraryType *netlist = &PCB->NetlistLib;
252 LibraryMenuType *net = NULL;
253 LibraryEntryType *pin = NULL;
255 for (ni=0; ni<netlist->MenuN; ni++)
256 if (strcmp (netlist->Menu[ni].Name+2, netname) == 0)
258 net = & (netlist->Menu[ni]);
259 break;
261 if (net == NULL)
263 net = CreateNewNet (netlist, (char *)netname, NULL);
266 for (pi=0; pi<net->EntryN; pi++)
267 if (strcmp (net->Entry[pi].ListEntry, pinname) == 0)
269 pin = & (net->Entry[pi]);
270 break;
272 if (pin == NULL)
274 pin = CreateNewConnection (net, (char *)pinname);
277 NetlistChanged (0);
278 return 0;
281 static const char netlist_syntax[] =
282 "Net(find|select|rats|norats|clear[,net[,pin]])\n"
283 "Net(freeze|thaw|forcethaw)\n"
284 "Net(add,net,pin)";
286 static const char netlist_help[] = "Perform various actions on netlists.";
288 /* %start-doc actions Netlist
290 Each of these actions apply to a specified set of nets. @var{net} and
291 @var{pin} are patterns which match one or more nets or pins; these
292 patterns may be full names or regular expressions. If an exact match
293 is found, it is the only match; if no exact match is found,
294 @emph{then} the pattern is tried as a regular expression.
296 If neither @var{net} nor @var{pin} are specified, all nets apply. If
297 @var{net} is specified but not @var{pin}, all nets matching @var{net}
298 apply. If both are specified, nets which match @var{net} and contain
299 a pin matching @var{pin} apply.
301 @table @code
303 @item find
304 Nets which apply are marked @emph{found} and are drawn in the
305 @code{connected-color} color.
307 @item select
308 Nets which apply are selected.
310 @item rats
311 Nets which apply are marked as available for the rats nest.
313 @item norats
314 Nets which apply are marked as not available for the rats nest.
316 @item clear
317 Clears the netlist.
319 @item add
320 Add the given pin to the given netlist, creating either if needed.
322 @item sort
323 Called after a list of add's, this sorts the netlist.
325 @item freeze
326 @itemx thaw
327 @itemx forcethaw
328 Temporarily prevents changes to the netlist from being reflected in
329 the GUI. For example, if you need to make multiple changes, you
330 freeze the netlist, make the changes, then thaw it. Note that
331 freeze/thaw requests may nest, with the netlist being fully thawed
332 only when all pending freezes are thawed. You can bypass the nesting
333 by using forcethaw, which resets the freeze count and immediately
334 updates the GUI.
336 @end table
338 %end-doc */
340 #define ARG(n) (argc > (n) ? argv[n] : 0)
342 static int
343 Netlist (int argc, char **argv, Coord x, Coord y)
345 NFunc func;
346 int i, j;
347 LibraryMenuType *net;
348 LibraryEntryType *pin;
349 int net_found = 0;
350 int pin_found = 0;
351 #if defined(USE_RE)
352 int use_re = 0;
353 #endif
354 #if defined(HAVE_REGCOMP)
355 regex_t elt_pattern;
356 regmatch_t match;
357 #endif
358 #if defined(HAVE_RE_COMP)
359 char *elt_pattern;
360 #endif
362 if (!PCB)
363 return 1;
364 if (argc == 0)
366 Message (netlist_syntax);
367 return 1;
369 if (strcasecmp (argv[0], "find") == 0)
370 func = netlist_find;
371 else if (strcasecmp (argv[0], "select") == 0)
372 func = netlist_select;
373 else if (strcasecmp (argv[0], "rats") == 0)
374 func = netlist_rats;
375 else if (strcasecmp (argv[0], "norats") == 0)
376 func = netlist_norats;
377 else if (strcasecmp (argv[0], "clear") == 0)
379 func = netlist_clear;
380 if (argc == 1)
382 netlist_clear (NULL, NULL);
383 return 0;
386 else if (strcasecmp (argv[0], "style") == 0)
387 func = (NFunc)netlist_style;
388 else if (strcasecmp (argv[0], "add") == 0)
390 /* Add is different, because the net/pin won't already exist. */
391 return netlist_add (ARG(1), ARG(2));
393 else if (strcasecmp (argv[0], "sort") == 0)
395 sort_netlist ();
396 return 0;
398 else if (strcasecmp (argv[0], "freeze") == 0)
400 netlist_frozen ++;
401 return 0;
403 else if (strcasecmp (argv[0], "thaw") == 0)
405 if (netlist_frozen > 0)
407 netlist_frozen --;
408 if (netlist_needs_update)
409 NetlistChanged (0);
411 return 0;
413 else if (strcasecmp (argv[0], "forcethaw") == 0)
415 netlist_frozen = 0;
416 if (netlist_needs_update)
417 NetlistChanged (0);
418 return 0;
420 else
422 Message (netlist_syntax);
423 return 1;
426 #if defined(USE_RE)
427 if (argc > 1)
429 int result;
430 use_re = 1;
431 for (i = 0; i < PCB->NetlistLib.MenuN; i++)
433 net = PCB->NetlistLib.Menu + i;
434 if (strcasecmp (argv[1], net->Name + 2) == 0)
435 use_re = 0;
437 if (use_re)
439 #if defined(HAVE_REGCOMP)
440 result =
441 regcomp (&elt_pattern, argv[1],
442 REG_EXTENDED | REG_ICASE | REG_NOSUB);
443 if (result)
445 char errorstring[128];
447 regerror (result, &elt_pattern, errorstring, 128);
448 Message (_("regexp error: %s\n"), errorstring);
449 regfree (&elt_pattern);
450 return (1);
452 #endif
453 #if defined(HAVE_RE_COMP)
454 if ((elt_pattern = re_comp (argv[1])) != NULL)
456 Message (_("re_comp error: %s\n"), elt_pattern);
457 return (false);
459 #endif
462 #endif
464 for (i = PCB->NetlistLib.MenuN-1; i >= 0; i--)
466 net = PCB->NetlistLib.Menu + i;
468 if (argc > 1)
470 #if defined(USE_RE)
471 if (use_re)
473 #if defined(HAVE_REGCOMP)
474 if (regexec (&elt_pattern, net->Name + 2, 1, &match, 0) != 0)
475 continue;
476 #endif
477 #if defined(HAVE_RE_COMP)
478 if (re_exec (net->Name + 2) != 1)
479 continue;
480 #endif
482 else
483 #endif
484 if (strcasecmp (net->Name + 2, argv[1]))
485 continue;
487 net_found = 1;
489 pin = 0;
490 if (func == (void *)netlist_style)
492 netlist_style (net, ARG(2));
494 else if (argc > 2)
496 int l = strlen (argv[2]);
497 for (j = net->EntryN-1; j >= 0 ; j--)
498 if (strcasecmp (net->Entry[j].ListEntry, argv[2]) == 0
499 || (strncasecmp (net->Entry[j].ListEntry, argv[2], l) == 0
500 && net->Entry[j].ListEntry[l] == '-'))
502 pin = net->Entry + j;
503 pin_found = 1;
504 func (net, pin);
507 else
508 func (net, 0);
511 if (argc > 2 && !pin_found)
513 gui->log ("Net %s has no pin %s\n", argv[1], argv[2]);
514 return 1;
516 else if (!net_found)
518 gui->log ("No net named %s\n", argv[1]);
520 #ifdef HAVE_REGCOMP
521 if (use_re)
522 regfree (&elt_pattern);
523 #endif
525 return 0;
528 HID_Action netlist_action_list[] = {
529 {"net", 0, Netlist,
530 netlist_help, netlist_syntax}
532 {"netlist", 0, Netlist,
533 netlist_help, netlist_syntax}
536 REGISTER_ACTIONS (netlist_action_list)