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
)
246 net
->Style
= STRDUP ((char *)style
);
249 /* The primary purpose of this action is to rebuild a netlist from a
250 script, in conjunction with the clear action above. */
252 netlist_add (const char *netname
, const char *pinname
)
255 LibraryType
*netlist
= &PCB
->NetlistLib
;
256 LibraryMenuType
*net
= NULL
;
257 LibraryEntryType
*pin
= NULL
;
259 for (ni
=0; ni
<netlist
->MenuN
; ni
++)
260 if (strcmp (netlist
->Menu
[ni
].Name
+2, netname
) == 0)
262 net
= & (netlist
->Menu
[ni
]);
267 net
= CreateNewNet (netlist
, (char *)netname
, NULL
);
270 for (pi
=0; pi
<net
->EntryN
; pi
++)
271 if (strcmp (net
->Entry
[pi
].ListEntry
, pinname
) == 0)
273 pin
= & (net
->Entry
[pi
]);
278 pin
= CreateNewConnection (net
, (char *)pinname
);
285 static const char netlist_syntax
[] =
286 "Net(find|select|rats|norats|clear[,net[,pin]])\n"
287 "Net(freeze|thaw|forcethaw)\n"
290 static const char netlist_help
[] = "Perform various actions on netlists.";
292 /* %start-doc actions Netlist
294 Each of these actions apply to a specified set of nets. @var{net} and
295 @var{pin} are patterns which match one or more nets or pins; these
296 patterns may be full names or regular expressions. If an exact match
297 is found, it is the only match; if no exact match is found,
298 @emph{then} the pattern is tried as a regular expression.
300 If neither @var{net} nor @var{pin} are specified, all nets apply. If
301 @var{net} is specified but not @var{pin}, all nets matching @var{net}
302 apply. If both are specified, nets which match @var{net} and contain
303 a pin matching @var{pin} apply.
308 Nets which apply are marked @emph{found} and are drawn in the
309 @code{connected-color} color.
312 Nets which apply are selected.
315 Nets which apply are marked as available for the rats nest.
318 Nets which apply are marked as not available for the rats nest.
324 Add the given pin to the given netlist, creating either if needed.
327 Called after a list of add's, this sorts the netlist.
332 Temporarily prevents changes to the netlist from being reflected in
333 the GUI. For example, if you need to make multiple changes, you
334 freeze the netlist, make the changes, then thaw it. Note that
335 freeze/thaw requests may nest, with the netlist being fully thawed
336 only when all pending freezes are thawed. You can bypass the nesting
337 by using forcethaw, which resets the freeze count and immediately
344 #define ARG(n) (argc > (n) ? argv[n] : 0)
347 Netlist (int argc
, char **argv
, int x
, int y
)
351 LibraryMenuType
*net
;
352 LibraryEntryType
*pin
;
358 #if defined(HAVE_REGCOMP)
362 #if defined(HAVE_RE_COMP)
370 Message (netlist_syntax
);
373 if (strcasecmp (argv
[0], "find") == 0)
375 else if (strcasecmp (argv
[0], "select") == 0)
376 func
= netlist_select
;
377 else if (strcasecmp (argv
[0], "rats") == 0)
379 else if (strcasecmp (argv
[0], "norats") == 0)
380 func
= netlist_norats
;
381 else if (strcasecmp (argv
[0], "clear") == 0)
383 func
= netlist_clear
;
386 netlist_clear (NULL
, NULL
);
390 else if (strcasecmp (argv
[0], "style") == 0)
391 func
= (void *)netlist_style
;
392 else if (strcasecmp (argv
[0], "add") == 0)
394 /* Add is different, because the net/pin won't already exist. */
395 return netlist_add (ARG(1), ARG(2));
397 else if (strcasecmp (argv
[0], "sort") == 0)
402 else if (strcasecmp (argv
[0], "freeze") == 0)
407 else if (strcasecmp (argv
[0], "thaw") == 0)
409 if (netlist_frozen
> 0)
412 if (netlist_needs_update
)
417 else if (strcasecmp (argv
[0], "forcethaw") == 0)
420 if (netlist_needs_update
)
426 Message (netlist_syntax
);
435 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
437 net
= PCB
->NetlistLib
.Menu
+ i
;
438 if (strcasecmp (argv
[1], net
->Name
+ 2) == 0)
443 #if defined(HAVE_REGCOMP)
445 regcomp (&elt_pattern
, argv
[1],
446 REG_EXTENDED
| REG_ICASE
| REG_NOSUB
);
449 char errorstring
[128];
451 regerror (result
, &elt_pattern
, errorstring
, 128);
452 Message (_("regexp error: %s\n"), errorstring
);
453 regfree (&elt_pattern
);
457 #if defined(HAVE_RE_COMP)
458 if ((elt_pattern
= re_comp (argv
[1])) != NULL
)
460 Message (_("re_comp error: %s\n"), elt_pattern
);
468 for (i
= PCB
->NetlistLib
.MenuN
-1; i
>= 0; i
--)
470 net
= PCB
->NetlistLib
.Menu
+ i
;
477 #if defined(HAVE_REGCOMP)
478 if (regexec (&elt_pattern
, net
->Name
+ 2, 1, &match
, 0) != 0)
481 #if defined(HAVE_RE_COMP)
482 if (re_exec (net
->Name
+ 2) != 1)
488 if (strcasecmp (net
->Name
+ 2, argv
[1]))
494 if (func
== (void *)netlist_style
)
496 netlist_style (net
, ARG(2));
500 int l
= strlen (argv
[2]);
501 for (j
= net
->EntryN
-1; j
>= 0 ; j
--)
502 if (strcasecmp (net
->Entry
[j
].ListEntry
, argv
[2]) == 0
503 || (strncasecmp (net
->Entry
[j
].ListEntry
, argv
[2], l
) == 0
504 && net
->Entry
[j
].ListEntry
[l
] == '-'))
506 pin
= net
->Entry
+ j
;
515 if (argc
> 2 && !pin_found
)
517 gui
->log ("Net %s has no pin %s\n", argv
[1], argv
[2]);
522 gui
->log ("No net named %s\n", argv
[1]);
526 regfree (&elt_pattern
);
532 HID_Action netlist_action_list
[] = {
534 netlist_help
, netlist_syntax
}
536 {"netlist", 0, Netlist
,
537 netlist_help
, netlist_syntax
}
540 REGISTER_ACTIONS (netlist_action_list
)