4 * \brief Generic netlist operations.
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
44 #include <sys/types.h>
68 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
72 #ifdef HAVE_LIBDMALLOC
77 int PCB->NetlistLib.MenuN
78 char * PCB->NetlistLib.Menu[i].Name
79 [0] == '*' (ok for rats) or ' ' (skip for rats)
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;
93 NetlistChanged (int force_unfreeze
)
98 netlist_needs_update
= 1;
101 netlist_needs_update
= 0;
102 hid_action ("NetlistChanged");
107 netnode_to_netname (char *nodename
)
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
]);
126 netname_to_netname (char *netname
)
130 if ((netname
[0] == '*' || netname
[0] == ' ') && netname
[1] == ' ')
132 /* Looks like we were passed an internal netname, skip the prefix */
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
]);
146 pin_name_to_xy (LibraryEntryType
* pin
, int *x
, int *y
)
149 if (!SeekPad (pin
, &conn
, false))
154 *x
= ((PinType
*) (conn
.ptr2
))->X
;
155 *y
= ((PinType
*) (conn
.ptr2
))->Y
;
158 *x
= ((PadType
*) (conn
.ptr2
))->Point1
.X
;
159 *y
= ((PadType
*) (conn
.ptr2
))->Point1
.Y
;
166 netlist_find (LibraryMenuType
* net
, LibraryEntryType
* pin
)
169 if (pin_name_to_xy (net
->Entry
, &x
, &y
))
171 LookupConnection (x
, y
, 1, 1, FOUNDFLAG
, true);
175 netlist_select (LibraryMenuType
* net
, LibraryEntryType
* pin
)
178 if (pin_name_to_xy (net
->Entry
, &x
, &y
))
180 LookupConnection (x
, y
, 1, 1, SELECTEDFLAG
, true);
184 netlist_rats (LibraryMenuType
* net
, LibraryEntryType
* pin
)
192 netlist_norats (LibraryMenuType
* net
, LibraryEntryType
* pin
)
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
205 netlist_clear (LibraryMenuType
* net
, LibraryEntryType
* pin
)
207 LibraryType
*netlist
= &PCB
->NetlistLib
;
212 /* Clear the entire netlist. */
213 FreeLibraryMemory (&PCB
->NetlistLib
);
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
));
229 /* Remove a pin from the given net. Note that this may leave an
230 empty net, which is different than removing the net
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
));
245 netlist_style (LibraryMenuType
*net
, const char *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.
256 netlist_add (const char *netname
, const char *pinname
)
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
]);
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
]);
282 pin
= CreateNewConnection (net
, (char *)pinname
);
289 static const char netlist_syntax
[] =
290 "Net(find|select|rats|norats|clear[,net[,pin]])\n"
291 "Net(freeze|thaw|forcethaw)\n"
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.
312 Nets which apply are marked @emph{found} and are drawn in the
313 @code{connected-color} color.
316 Nets which apply are selected.
319 Nets which apply are marked as available for the rats nest.
322 Nets which apply are marked as not available for the rats nest.
328 Add the given pin to the given netlist, creating either if needed.
331 Called after a list of add's, this sorts the netlist.
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
348 #define ARG(n) (argc > (n) ? argv[n] : 0)
351 Netlist (int argc
, char **argv
, Coord x
, Coord y
)
355 LibraryMenuType
*net
;
356 LibraryEntryType
*pin
;
362 #if defined(HAVE_REGCOMP)
366 #if defined(HAVE_RE_COMP)
374 Message (netlist_syntax
);
377 if (strcasecmp (argv
[0], "find") == 0)
379 else if (strcasecmp (argv
[0], "select") == 0)
380 func
= netlist_select
;
381 else if (strcasecmp (argv
[0], "rats") == 0)
383 else if (strcasecmp (argv
[0], "norats") == 0)
384 func
= netlist_norats
;
385 else if (strcasecmp (argv
[0], "clear") == 0)
387 func
= netlist_clear
;
390 netlist_clear (NULL
, NULL
);
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)
406 else if (strcasecmp (argv
[0], "freeze") == 0)
411 else if (strcasecmp (argv
[0], "thaw") == 0)
413 if (netlist_frozen
> 0)
416 if (netlist_needs_update
)
421 else if (strcasecmp (argv
[0], "forcethaw") == 0)
424 if (netlist_needs_update
)
430 Message (netlist_syntax
);
439 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
441 net
= PCB
->NetlistLib
.Menu
+ i
;
442 if (strcasecmp (argv
[1], net
->Name
+ 2) == 0)
447 #if defined(HAVE_REGCOMP)
449 regcomp (&elt_pattern
, argv
[1],
450 REG_EXTENDED
| REG_ICASE
| REG_NOSUB
);
453 char errorstring
[128];
455 regerror (result
, &elt_pattern
, errorstring
, 128);
456 Message (_("regexp error: %s\n"), errorstring
);
457 regfree (&elt_pattern
);
461 #if defined(HAVE_RE_COMP)
462 if ((elt_pattern
= re_comp (argv
[1])) != NULL
)
464 Message (_("re_comp error: %s\n"), elt_pattern
);
472 for (i
= PCB
->NetlistLib
.MenuN
-1; i
>= 0; i
--)
474 net
= PCB
->NetlistLib
.Menu
+ i
;
481 #if defined(HAVE_REGCOMP)
482 if (regexec (&elt_pattern
, net
->Name
+ 2, 1, &match
, 0) != 0)
485 #if defined(HAVE_RE_COMP)
486 if (re_exec (net
->Name
+ 2) != 1)
492 if (strcasecmp (net
->Name
+ 2, argv
[1]))
498 if (func
== (void *)netlist_style
)
500 netlist_style (net
, ARG(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
;
519 if (argc
> 2 && !pin_found
)
521 gui
->log ("Net %s has no pin %s\n", argv
[1], argv
[2]);
526 gui
->log ("No net named %s\n", argv
[1]);
530 regfree (&elt_pattern
);
536 HID_Action netlist_action_list
[] = {
538 netlist_help
, netlist_syntax
}
540 {"netlist", 0, Netlist
,
541 netlist_help
, netlist_syntax
}
544 REGISTER_ACTIONS (netlist_action_list
)