src/puller.c: Converted plain comments into doxygen comments.
[geda-pcb/pcjc2.git] / src / netlist.c
blob241dbaa9c16e2d54424ddc0407055682988f4b83
1 /*!
2 * \file src/netlist.c
4 * \brief Generic netlist operations.
6 * <hr>
8 * <h1><b>Copyright.</b></h1>\n
10 * PCB, interactive printed circuit board design
12 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 * Contact addresses for paper mail and Email:
30 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
32 * Thomas.Nau@rz.uni-ulm.de
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
39 #include <stdlib.h>
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
43 #include <ctype.h>
44 #include <sys/types.h>
45 #ifdef HAVE_REGEX_H
46 #include <regex.h>
47 #endif
49 #include "global.h"
50 #include "action.h"
51 #include "buffer.h"
52 #include "data.h"
53 #include "djopt.h"
54 #include "error.h"
55 #include "file.h"
56 #include "find.h"
57 #include "mymem.h"
58 #include "misc.h"
59 #include "rats.h"
60 #include "set.h"
61 #include "vendor.h"
62 #include "create.h"
64 #ifdef HAVE_REGCOMP
65 #undef HAVE_RE_COMP
66 #endif
68 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
69 #define USE_RE
70 #endif
72 #ifdef HAVE_LIBDMALLOC
73 #include <dmalloc.h>
74 #endif
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 LibraryMenuType *
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 LibraryMenuType *
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, true);
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, true);
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);
200 * \brief The primary purpose of this action is to remove the netlist
201 * completely so that a new one can be loaded, usually via a gsch2pcb
202 * style script.
204 static void
205 netlist_clear (LibraryMenuType * net, LibraryEntryType * pin)
207 LibraryType *netlist = &PCB->NetlistLib;
208 int ni, pi;
210 if (net == 0)
212 /* Clear the entire netlist. */
213 FreeLibraryMemory (&PCB->NetlistLib);
215 else if (pin == 0)
217 /* Remove a net from the netlist. */
218 ni = net - netlist->Menu;
219 if (ni >= 0 && ni < netlist->MenuN)
221 /* if there is exactly one item, MenuN is 1 and ni is 0 */
222 if (netlist->MenuN - ni > 1)
223 memmove (net, net+1, (netlist->MenuN - ni - 1) * sizeof (*net));
224 netlist->MenuN --;
227 else
229 /* Remove a pin from the given net. Note that this may leave an
230 empty net, which is different than removing the net
231 (above). */
232 pi = pin - net->Entry;
233 if (pi >= 0 && pi < net->EntryN)
235 /* if there is exactly one item, MenuN is 1 and ni is 0 */
236 if (net->EntryN - pi > 1)
237 memmove (pin, pin+1, (net->EntryN - pi - 1) * sizeof (*pin));
238 net->EntryN --;
241 NetlistChanged (0);
244 static void
245 netlist_style (LibraryMenuType *net, const char *style)
247 free (net->Style);
248 net->Style = STRDUP ((char *)style);
252 * \brief The primary purpose of this action is to rebuild a netlist
253 * from a script, in conjunction with the clear action above.
255 static int
256 netlist_add (const char *netname, const char *pinname)
258 int ni, pi;
259 LibraryType *netlist = &PCB->NetlistLib;
260 LibraryMenuType *net = NULL;
261 LibraryEntryType *pin = NULL;
263 for (ni=0; ni<netlist->MenuN; ni++)
264 if (strcmp (netlist->Menu[ni].Name+2, netname) == 0)
266 net = & (netlist->Menu[ni]);
267 break;
269 if (net == NULL)
271 net = CreateNewNet (netlist, (char *)netname, NULL);
274 for (pi=0; pi<net->EntryN; pi++)
275 if (strcmp (net->Entry[pi].ListEntry, pinname) == 0)
277 pin = & (net->Entry[pi]);
278 break;
280 if (pin == NULL)
282 pin = CreateNewConnection (net, (char *)pinname);
285 NetlistChanged (0);
286 return 0;
289 static const char netlist_syntax[] =
290 "Net(find|select|rats|norats|clear[,net[,pin]])\n"
291 "Net(freeze|thaw|forcethaw)\n"
292 "Net(add,net,pin)";
294 static const char netlist_help[] = "Perform various actions on netlists.";
296 /* %start-doc actions Netlist
298 Each of these actions apply to a specified set of nets. @var{net} and
299 @var{pin} are patterns which match one or more nets or pins; these
300 patterns may be full names or regular expressions. If an exact match
301 is found, it is the only match; if no exact match is found,
302 @emph{then} the pattern is tried as a regular expression.
304 If neither @var{net} nor @var{pin} are specified, all nets apply. If
305 @var{net} is specified but not @var{pin}, all nets matching @var{net}
306 apply. If both are specified, nets which match @var{net} and contain
307 a pin matching @var{pin} apply.
309 @table @code
311 @item find
312 Nets which apply are marked @emph{found} and are drawn in the
313 @code{connected-color} color.
315 @item select
316 Nets which apply are selected.
318 @item rats
319 Nets which apply are marked as available for the rats nest.
321 @item norats
322 Nets which apply are marked as not available for the rats nest.
324 @item clear
325 Clears the netlist.
327 @item add
328 Add the given pin to the given netlist, creating either if needed.
330 @item sort
331 Called after a list of add's, this sorts the netlist.
333 @item freeze
334 @itemx thaw
335 @itemx forcethaw
336 Temporarily prevents changes to the netlist from being reflected in
337 the GUI. For example, if you need to make multiple changes, you
338 freeze the netlist, make the changes, then thaw it. Note that
339 freeze/thaw requests may nest, with the netlist being fully thawed
340 only when all pending freezes are thawed. You can bypass the nesting
341 by using forcethaw, which resets the freeze count and immediately
342 updates the GUI.
344 @end table
346 %end-doc */
348 #define ARG(n) (argc > (n) ? argv[n] : 0)
350 static int
351 Netlist (int argc, char **argv, Coord x, Coord y)
353 NFunc func;
354 int i, j;
355 LibraryMenuType *net;
356 LibraryEntryType *pin;
357 int net_found = 0;
358 int pin_found = 0;
359 #if defined(USE_RE)
360 int use_re = 0;
361 #endif
362 #if defined(HAVE_REGCOMP)
363 regex_t elt_pattern;
364 regmatch_t match;
365 #endif
366 #if defined(HAVE_RE_COMP)
367 char *elt_pattern;
368 #endif
370 if (!PCB)
371 return 1;
372 if (argc == 0)
374 Message (netlist_syntax);
375 return 1;
377 if (strcasecmp (argv[0], "find") == 0)
378 func = netlist_find;
379 else if (strcasecmp (argv[0], "select") == 0)
380 func = netlist_select;
381 else if (strcasecmp (argv[0], "rats") == 0)
382 func = netlist_rats;
383 else if (strcasecmp (argv[0], "norats") == 0)
384 func = netlist_norats;
385 else if (strcasecmp (argv[0], "clear") == 0)
387 func = netlist_clear;
388 if (argc == 1)
390 netlist_clear (NULL, NULL);
391 return 0;
394 else if (strcasecmp (argv[0], "style") == 0)
395 func = (NFunc)netlist_style;
396 else if (strcasecmp (argv[0], "add") == 0)
398 /* Add is different, because the net/pin won't already exist. */
399 return netlist_add (ARG(1), ARG(2));
401 else if (strcasecmp (argv[0], "sort") == 0)
403 sort_netlist ();
404 return 0;
406 else if (strcasecmp (argv[0], "freeze") == 0)
408 netlist_frozen ++;
409 return 0;
411 else if (strcasecmp (argv[0], "thaw") == 0)
413 if (netlist_frozen > 0)
415 netlist_frozen --;
416 if (netlist_needs_update)
417 NetlistChanged (0);
419 return 0;
421 else if (strcasecmp (argv[0], "forcethaw") == 0)
423 netlist_frozen = 0;
424 if (netlist_needs_update)
425 NetlistChanged (0);
426 return 0;
428 else
430 Message (netlist_syntax);
431 return 1;
434 #if defined(USE_RE)
435 if (argc > 1)
437 int result;
438 use_re = 1;
439 for (i = 0; i < PCB->NetlistLib.MenuN; i++)
441 net = PCB->NetlistLib.Menu + i;
442 if (strcasecmp (argv[1], net->Name + 2) == 0)
443 use_re = 0;
445 if (use_re)
447 #if defined(HAVE_REGCOMP)
448 result =
449 regcomp (&elt_pattern, argv[1],
450 REG_EXTENDED | REG_ICASE | REG_NOSUB);
451 if (result)
453 char errorstring[128];
455 regerror (result, &elt_pattern, errorstring, 128);
456 Message (_("regexp error: %s\n"), errorstring);
457 regfree (&elt_pattern);
458 return (1);
460 #endif
461 #if defined(HAVE_RE_COMP)
462 if ((elt_pattern = re_comp (argv[1])) != NULL)
464 Message (_("re_comp error: %s\n"), elt_pattern);
465 return (false);
467 #endif
470 #endif
472 for (i = PCB->NetlistLib.MenuN-1; i >= 0; i--)
474 net = PCB->NetlistLib.Menu + i;
476 if (argc > 1)
478 #if defined(USE_RE)
479 if (use_re)
481 #if defined(HAVE_REGCOMP)
482 if (regexec (&elt_pattern, net->Name + 2, 1, &match, 0) != 0)
483 continue;
484 #endif
485 #if defined(HAVE_RE_COMP)
486 if (re_exec (net->Name + 2) != 1)
487 continue;
488 #endif
490 else
491 #endif
492 if (strcasecmp (net->Name + 2, argv[1]))
493 continue;
495 net_found = 1;
497 pin = 0;
498 if (func == (void *)netlist_style)
500 netlist_style (net, ARG(2));
502 else if (argc > 2)
504 int l = strlen (argv[2]);
505 for (j = net->EntryN-1; j >= 0 ; j--)
506 if (strcasecmp (net->Entry[j].ListEntry, argv[2]) == 0
507 || (strncasecmp (net->Entry[j].ListEntry, argv[2], l) == 0
508 && net->Entry[j].ListEntry[l] == '-'))
510 pin = net->Entry + j;
511 pin_found = 1;
512 func (net, pin);
515 else
516 func (net, 0);
519 if (argc > 2 && !pin_found)
521 gui->log ("Net %s has no pin %s\n", argv[1], argv[2]);
522 return 1;
524 else if (!net_found)
526 gui->log ("No net named %s\n", argv[1]);
528 #ifdef HAVE_REGCOMP
529 if (use_re)
530 regfree (&elt_pattern);
531 #endif
533 return 0;
536 HID_Action netlist_action_list[] = {
537 {"net", 0, Netlist,
538 netlist_help, netlist_syntax}
540 {"netlist", 0, Netlist,
541 netlist_help, netlist_syntax}
544 REGISTER_ACTIONS (netlist_action_list)