6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
29 /* generic netlist operations
41 #include <sys/types.h>
66 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
70 #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
);
175 netlist_select (LibraryMenuType
* net
, LibraryEntryType
* pin
)
178 if (pin_name_to_xy (net
->Entry
, &x
, &y
))
180 LookupConnection (x
, y
, 1, 1, SELECTEDFLAG
);
184 netlist_rats (LibraryMenuType
* net
, LibraryEntryType
* pin
)
192 netlist_norats (LibraryMenuType
* net
, LibraryEntryType
* pin
)
199 /* The primary purpose of this action is to remove the netlist
200 completely so that a new one can be loaded, usually via a gsch2pcb
203 netlist_clear (LibraryMenuType
* net
, LibraryEntryType
* pin
)
205 LibraryType
*netlist
= &PCB
->NetlistLib
;
210 /* Clear the entire netlist. */
211 FreeLibraryMemory (&PCB
->NetlistLib
);
215 /* Remove a net from the netlist. */
216 ni
= net
- netlist
->Menu
;
217 if (ni
>= 0 && ni
< netlist
->MenuN
)
219 /* if there is exactly one item, MenuN is 1 and ni is 0 */
220 if (netlist
->MenuN
- ni
> 1)
221 memmove (net
, net
+1, (netlist
->MenuN
- ni
- 1) * sizeof (*net
));
227 /* Remove a pin from the given net. Note that this may leave an
228 empty net, which is different than removing the net
230 pi
= pin
- net
->Entry
;
231 if (pi
>= 0 && pi
< net
->EntryN
)
233 /* if there is exactly one item, MenuN is 1 and ni is 0 */
234 if (net
->EntryN
- pi
> 1)
235 memmove (pin
, pin
+1, (net
->EntryN
- pi
- 1) * sizeof (*pin
));
243 netlist_style (LibraryMenuType
*net
, const char *style
)
248 net
->Style
= MyStrdup ((char *)style
, "Netlist(Style)");
251 /* The primary purpose of this action is to rebuild a netlist from a
252 script, in conjunction with the clear action above. */
254 netlist_add (const char *netname
, const char *pinname
)
257 LibraryType
*netlist
= &PCB
->NetlistLib
;
258 LibraryMenuType
*net
= NULL
;
259 LibraryEntryType
*pin
= NULL
;
261 for (ni
=0; ni
<netlist
->MenuN
; ni
++)
262 if (strcmp (netlist
->Menu
[ni
].Name
+2, netname
) == 0)
264 net
= & (netlist
->Menu
[ni
]);
269 net
= CreateNewNet (netlist
, (char *)netname
, NULL
);
272 for (pi
=0; pi
<net
->EntryN
; pi
++)
273 if (strcmp (net
->Entry
[pi
].ListEntry
, pinname
) == 0)
275 pin
= & (net
->Entry
[pi
]);
280 pin
= CreateNewConnection (net
, (char *)pinname
);
287 static const char netlist_syntax
[] =
288 "Net(find|select|rats|norats|clear[,net[,pin]])\n"
289 "Net(freeze|thaw|forcethaw)\n"
292 static const char netlist_help
[] = "Perform various actions on netlists.";
294 /* %start-doc actions Netlist
296 Each of these actions apply to a specified set of nets. @var{net} and
297 @var{pin} are patterns which match one or more nets or pins; these
298 patterns may be full names or regular expressions. If an exact match
299 is found, it is the only match; if no exact match is found,
300 @emph{then} the pattern is tried as a regular expression.
302 If neither @var{net} nor @var{pin} are specified, all nets apply. If
303 @var{net} is specified but not @var{pin}, all nets matching @var{net}
304 apply. If both are specified, nets which match @var{net} and contain
305 a pin matching @var{pin} apply.
310 Nets which apply are marked @emph{found} and are drawn in the
311 @code{connected-color} color.
314 Nets which apply are selected.
317 Nets which apply are marked as available for the rats nest.
320 Nets which apply are marked as not available for the rats nest.
326 Add the given pin to the given netlist, creating either if needed.
329 Called after a list of add's, this sorts the netlist.
334 Temporarily prevents changes to the netlist from being reflected in
335 the GUI. For example, if you need to make multiple changes, you
336 freeze the netlist, make the changes, then thaw it. Note that
337 freeze/thaw requests may nest, with the netlist being fully thawed
338 only when all pending freezes are thawed. You can bypass the nesting
339 by using forcethaw, which resets the freeze count and immediately
346 #define ARG(n) (argc > (n) ? argv[n] : 0)
349 Netlist (int argc
, char **argv
, int x
, int y
)
353 LibraryMenuType
*net
;
354 LibraryEntryType
*pin
;
360 #if defined(HAVE_REGCOMP)
364 #if defined(HAVE_RE_COMP)
372 Message (netlist_syntax
);
375 if (strcasecmp (argv
[0], "find") == 0)
377 else if (strcasecmp (argv
[0], "select") == 0)
378 func
= netlist_select
;
379 else if (strcasecmp (argv
[0], "rats") == 0)
381 else if (strcasecmp (argv
[0], "norats") == 0)
382 func
= netlist_norats
;
383 else if (strcasecmp (argv
[0], "clear") == 0)
385 func
= netlist_clear
;
388 netlist_clear (NULL
, NULL
);
392 else if (strcasecmp (argv
[0], "style") == 0)
393 func
= (void *)netlist_style
;
394 else if (strcasecmp (argv
[0], "add") == 0)
396 /* Add is different, because the net/pin won't already exist. */
397 return netlist_add (ARG(1), ARG(2));
399 else if (strcasecmp (argv
[0], "sort") == 0)
404 else if (strcasecmp (argv
[0], "freeze") == 0)
409 else if (strcasecmp (argv
[0], "thaw") == 0)
411 if (netlist_frozen
> 0)
414 if (netlist_needs_update
)
419 else if (strcasecmp (argv
[0], "forcethaw") == 0)
422 if (netlist_needs_update
)
428 Message (netlist_syntax
);
437 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
439 net
= PCB
->NetlistLib
.Menu
+ i
;
440 if (strcasecmp (argv
[1], net
->Name
+ 2) == 0)
445 #if defined(HAVE_REGCOMP)
447 regcomp (&elt_pattern
, argv
[1],
448 REG_EXTENDED
| REG_ICASE
| REG_NOSUB
);
451 char errorstring
[128];
453 regerror (result
, &elt_pattern
, errorstring
, 128);
454 Message (_("regexp error: %s\n"), errorstring
);
455 regfree (&elt_pattern
);
459 #if defined(HAVE_RE_COMP)
460 if ((elt_pattern
= re_comp (argv
[1])) != NULL
)
462 Message (_("re_comp error: %s\n"), elt_pattern
);
470 for (i
= PCB
->NetlistLib
.MenuN
-1; i
>= 0; i
--)
472 net
= PCB
->NetlistLib
.Menu
+ i
;
479 #if defined(HAVE_REGCOMP)
480 if (regexec (&elt_pattern
, net
->Name
+ 2, 1, &match
, 0) != 0)
483 #if defined(HAVE_RE_COMP)
484 if (re_exec (net
->Name
+ 2) != 1)
490 if (strcasecmp (net
->Name
+ 2, argv
[1]))
496 if (func
== (void *)netlist_style
)
498 netlist_style (net
, ARG(2));
502 int l
= strlen (argv
[2]);
503 for (j
= net
->EntryN
-1; j
>= 0 ; j
--)
504 if (strcasecmp (net
->Entry
[j
].ListEntry
, argv
[2]) == 0
505 || (strncasecmp (net
->Entry
[j
].ListEntry
, argv
[2], l
) == 0
506 && net
->Entry
[j
].ListEntry
[l
] == '-'))
508 pin
= net
->Entry
+ j
;
517 if (argc
> 2 && !pin_found
)
519 gui
->log ("Net %s has no pin %s\n", argv
[1], argv
[2]);
524 gui
->log ("No net named %s\n", argv
[1]);
528 regfree (&elt_pattern
);
534 HID_Action netlist_action_list
[] = {
536 netlist_help
, netlist_syntax
}
538 {"netlist", 0, Netlist
,
539 netlist_help
, netlist_syntax
}
542 REGISTER_ACTIONS (netlist_action_list
)