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
39 #include <sys/types.h>
63 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
67 #ifdef HAVE_LIBDMALLOC
72 int PCB->NetlistLib.MenuN
73 char * PCB->NetlistLib.Menu[i].Name
74 [0] == '*' (ok for rats) or ' ' (skip for rats)
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;
88 NetlistChanged (int force_unfreeze
)
93 netlist_needs_update
= 1;
96 netlist_needs_update
= 0;
97 hid_action ("NetlistChanged");
102 netnode_to_netname (char *nodename
)
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
]);
121 netname_to_netname (char *netname
)
125 if ((netname
[0] == '*' || netname
[0] == ' ') && netname
[1] == ' ')
127 /* Looks like we were passed an internal netname, skip the prefix */
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
]);
141 pin_name_to_xy (LibraryEntryType
* pin
, int *x
, int *y
)
144 if (!SeekPad (pin
, &conn
, false))
149 *x
= ((PinType
*) (conn
.ptr2
))->X
;
150 *y
= ((PinType
*) (conn
.ptr2
))->Y
;
153 *x
= ((PadType
*) (conn
.ptr2
))->Point1
.X
;
154 *y
= ((PadType
*) (conn
.ptr2
))->Point1
.Y
;
161 netlist_find (LibraryMenuType
* net
, LibraryEntryType
* pin
)
164 if (pin_name_to_xy (net
->Entry
, &x
, &y
))
166 LookupConnection (x
, y
, 1, 1, FOUNDFLAG
, true);
170 netlist_select (LibraryMenuType
* net
, LibraryEntryType
* pin
)
173 if (pin_name_to_xy (net
->Entry
, &x
, &y
))
175 LookupConnection (x
, y
, 1, 1, SELECTEDFLAG
, true);
179 netlist_rats (LibraryMenuType
* net
, LibraryEntryType
* pin
)
187 netlist_norats (LibraryMenuType
* net
, LibraryEntryType
* pin
)
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
198 netlist_clear (LibraryMenuType
* net
, LibraryEntryType
* pin
)
200 LibraryType
*netlist
= &PCB
->NetlistLib
;
205 /* Clear the entire netlist. */
206 FreeLibraryMemory (&PCB
->NetlistLib
);
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
));
222 /* Remove a pin from the given net. Note that this may leave an
223 empty net, which is different than removing the net
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
));
238 netlist_style (LibraryMenuType
*net
, const char *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. */
247 netlist_add (const char *netname
, const char *pinname
)
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
]);
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
]);
273 pin
= CreateNewConnection (net
, (char *)pinname
);
280 static const char netlist_syntax
[] =
281 "Net(find|select|rats|norats|clear[,net[,pin]])\n"
282 "Net(freeze|thaw|forcethaw)\n"
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.
303 Nets which apply are marked @emph{found} and are drawn in the
304 @code{connected-color} color.
307 Nets which apply are selected.
310 Nets which apply are marked as available for the rats nest.
313 Nets which apply are marked as not available for the rats nest.
319 Add the given pin to the given netlist, creating either if needed.
322 Called after a list of add's, this sorts the netlist.
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
339 #define ARG(n) (argc > (n) ? argv[n] : 0)
342 Netlist (int argc
, char **argv
, Coord x
, Coord y
)
346 LibraryMenuType
*net
;
347 LibraryEntryType
*pin
;
353 #if defined(HAVE_REGCOMP)
357 #if defined(HAVE_RE_COMP)
365 Message (netlist_syntax
);
368 if (strcasecmp (argv
[0], "find") == 0)
370 else if (strcasecmp (argv
[0], "select") == 0)
371 func
= netlist_select
;
372 else if (strcasecmp (argv
[0], "rats") == 0)
374 else if (strcasecmp (argv
[0], "norats") == 0)
375 func
= netlist_norats
;
376 else if (strcasecmp (argv
[0], "clear") == 0)
378 func
= netlist_clear
;
381 netlist_clear (NULL
, NULL
);
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)
397 else if (strcasecmp (argv
[0], "freeze") == 0)
402 else if (strcasecmp (argv
[0], "thaw") == 0)
404 if (netlist_frozen
> 0)
407 if (netlist_needs_update
)
412 else if (strcasecmp (argv
[0], "forcethaw") == 0)
415 if (netlist_needs_update
)
421 Message (netlist_syntax
);
430 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
432 net
= PCB
->NetlistLib
.Menu
+ i
;
433 if (strcasecmp (argv
[1], net
->Name
+ 2) == 0)
438 #if defined(HAVE_REGCOMP)
440 regcomp (&elt_pattern
, argv
[1],
441 REG_EXTENDED
| REG_ICASE
| REG_NOSUB
);
444 char errorstring
[128];
446 regerror (result
, &elt_pattern
, errorstring
, 128);
447 Message (_("regexp error: %s\n"), errorstring
);
448 regfree (&elt_pattern
);
452 #if defined(HAVE_RE_COMP)
453 if ((elt_pattern
= re_comp (argv
[1])) != NULL
)
455 Message (_("re_comp error: %s\n"), elt_pattern
);
463 for (i
= PCB
->NetlistLib
.MenuN
-1; i
>= 0; i
--)
465 net
= PCB
->NetlistLib
.Menu
+ i
;
472 #if defined(HAVE_REGCOMP)
473 if (regexec (&elt_pattern
, net
->Name
+ 2, 1, &match
, 0) != 0)
476 #if defined(HAVE_RE_COMP)
477 if (re_exec (net
->Name
+ 2) != 1)
483 if (strcasecmp (net
->Name
+ 2, argv
[1]))
489 if (func
== (void *)netlist_style
)
491 netlist_style (net
, ARG(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
;
510 if (argc
> 2 && !pin_found
)
512 gui
->log ("Net %s has no pin %s\n", argv
[1], argv
[2]);
517 gui
->log ("No net named %s\n", argv
[1]);
521 regfree (&elt_pattern
);
527 HID_Action netlist_action_list
[] = {
529 netlist_help
, netlist_syntax
}
531 {"netlist", 0, Netlist
,
532 netlist_help
, netlist_syntax
}
535 REGISTER_ACTIONS (netlist_action_list
)