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>
64 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
68 #ifdef HAVE_LIBDMALLOC
73 int PCB->NetlistLib.MenuN
74 char * PCB->NetlistLib.Menu[i].Name
75 [0] == '*' (ok for rats) or ' ' (skip for rats)
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;
89 NetlistChanged (int force_unfreeze
)
94 netlist_needs_update
= 1;
97 netlist_needs_update
= 0;
98 hid_action ("NetlistChanged");
103 netnode_to_netname (char *nodename
)
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
]);
122 netname_to_netname (char *netname
)
126 if ((netname
[0] == '*' || netname
[0] == ' ') && netname
[1] == ' ')
128 /* Looks like we were passed an internal netname, skip the prefix */
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
]);
142 pin_name_to_xy (LibraryEntryType
* pin
, int *x
, int *y
)
145 if (!SeekPad (pin
, &conn
, false))
150 *x
= ((PinType
*) (conn
.ptr2
))->X
;
151 *y
= ((PinType
*) (conn
.ptr2
))->Y
;
154 *x
= ((PadType
*) (conn
.ptr2
))->Point1
.X
;
155 *y
= ((PadType
*) (conn
.ptr2
))->Point1
.Y
;
162 netlist_find (LibraryMenuType
* net
, LibraryEntryType
* pin
)
165 if (pin_name_to_xy (net
->Entry
, &x
, &y
))
167 LookupConnection (x
, y
, 1, 1, FOUNDFLAG
, true);
171 netlist_select (LibraryMenuType
* net
, LibraryEntryType
* pin
)
174 if (pin_name_to_xy (net
->Entry
, &x
, &y
))
176 LookupConnection (x
, y
, 1, 1, SELECTEDFLAG
, true);
180 netlist_rats (LibraryMenuType
* net
, LibraryEntryType
* pin
)
188 netlist_norats (LibraryMenuType
* net
, LibraryEntryType
* pin
)
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
199 netlist_clear (LibraryMenuType
* net
, LibraryEntryType
* pin
)
201 LibraryType
*netlist
= &PCB
->NetlistLib
;
206 /* Clear the entire netlist. */
207 FreeLibraryMemory (&PCB
->NetlistLib
);
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
));
223 /* Remove a pin from the given net. Note that this may leave an
224 empty net, which is different than removing the net
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
));
239 netlist_style (LibraryMenuType
*net
, const char *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. */
248 netlist_add (const char *netname
, const char *pinname
)
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
]);
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
]);
274 pin
= CreateNewConnection (net
, (char *)pinname
);
281 static const char netlist_syntax
[] =
282 "Net(find|select|rats|norats|clear[,net[,pin]])\n"
283 "Net(freeze|thaw|forcethaw)\n"
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.
304 Nets which apply are marked @emph{found} and are drawn in the
305 @code{connected-color} color.
308 Nets which apply are selected.
311 Nets which apply are marked as available for the rats nest.
314 Nets which apply are marked as not available for the rats nest.
320 Add the given pin to the given netlist, creating either if needed.
323 Called after a list of add's, this sorts the netlist.
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
340 #define ARG(n) (argc > (n) ? argv[n] : 0)
343 Netlist (int argc
, char **argv
, Coord x
, Coord y
)
347 LibraryMenuType
*net
;
348 LibraryEntryType
*pin
;
354 #if defined(HAVE_REGCOMP)
358 #if defined(HAVE_RE_COMP)
366 Message (netlist_syntax
);
369 if (strcasecmp (argv
[0], "find") == 0)
371 else if (strcasecmp (argv
[0], "select") == 0)
372 func
= netlist_select
;
373 else if (strcasecmp (argv
[0], "rats") == 0)
375 else if (strcasecmp (argv
[0], "norats") == 0)
376 func
= netlist_norats
;
377 else if (strcasecmp (argv
[0], "clear") == 0)
379 func
= netlist_clear
;
382 netlist_clear (NULL
, NULL
);
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)
398 else if (strcasecmp (argv
[0], "freeze") == 0)
403 else if (strcasecmp (argv
[0], "thaw") == 0)
405 if (netlist_frozen
> 0)
408 if (netlist_needs_update
)
413 else if (strcasecmp (argv
[0], "forcethaw") == 0)
416 if (netlist_needs_update
)
422 Message (netlist_syntax
);
431 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
433 net
= PCB
->NetlistLib
.Menu
+ i
;
434 if (strcasecmp (argv
[1], net
->Name
+ 2) == 0)
439 #if defined(HAVE_REGCOMP)
441 regcomp (&elt_pattern
, argv
[1],
442 REG_EXTENDED
| REG_ICASE
| REG_NOSUB
);
445 char errorstring
[128];
447 regerror (result
, &elt_pattern
, errorstring
, 128);
448 Message (_("regexp error: %s\n"), errorstring
);
449 regfree (&elt_pattern
);
453 #if defined(HAVE_RE_COMP)
454 if ((elt_pattern
= re_comp (argv
[1])) != NULL
)
456 Message (_("re_comp error: %s\n"), elt_pattern
);
464 for (i
= PCB
->NetlistLib
.MenuN
-1; i
>= 0; i
--)
466 net
= PCB
->NetlistLib
.Menu
+ i
;
473 #if defined(HAVE_REGCOMP)
474 if (regexec (&elt_pattern
, net
->Name
+ 2, 1, &match
, 0) != 0)
477 #if defined(HAVE_RE_COMP)
478 if (re_exec (net
->Name
+ 2) != 1)
484 if (strcasecmp (net
->Name
+ 2, argv
[1]))
490 if (func
== (void *)netlist_style
)
492 netlist_style (net
, ARG(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
;
511 if (argc
> 2 && !pin_found
)
513 gui
->log ("Net %s has no pin %s\n", argv
[1], argv
[2]);
518 gui
->log ("No net named %s\n", argv
[1]);
522 regfree (&elt_pattern
);
528 HID_Action netlist_action_list
[] = {
530 netlist_help
, netlist_syntax
}
532 {"netlist", 0, Netlist
,
533 netlist_help
, netlist_syntax
}
536 REGISTER_ACTIONS (netlist_action_list
)