Default STEP export to board only
[geda-pcb/pcjc2/v2.git] / src / netlist.c
blob1dd6d111db8833aca4da8fc5f4dd0d1cbfd0edea
1 /*!
2 * \file src/netlist.c
4 * \brief Generic netlist operations.
6 * <hr>
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
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
39 #include <stdlib.h>
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
43 #include <ctype.h>
44 #include <sys/types.h>
45 #ifdef HAVE_REGEX_H
46 #include <regex.h>
47 #endif
49 #include "global.h"
50 #include "action.h"
51 #include "buffer.h"
52 #include "data.h"
53 #include "djopt.h"
54 #include "error.h"
55 #include "file.h"
56 #include "find.h"
57 #include "mymem.h"
58 #include "misc.h"
59 #include "rats.h"
60 #include "set.h"
61 #include "vendor.h"
62 #include "create.h"
64 #ifdef HAVE_REGCOMP
65 #undef HAVE_RE_COMP
66 #endif
68 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
69 #define USE_RE
70 #endif
72 #ifdef HAVE_LIBDMALLOC
73 #include <dmalloc.h>
74 #endif
77 int PCB->NetlistLib.MenuN
78 char * PCB->NetlistLib.Menu[i].Name
79 [0] == '*' (ok for rats) or ' ' (skip for rats)
80 [1] == unused
81 [2..] actual name
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;
92 void
93 NetlistChanged (int force_unfreeze)
95 if (force_unfreeze)
96 netlist_frozen = 0;
97 if (netlist_frozen)
98 netlist_needs_update = 1;
99 else
101 netlist_needs_update = 0;
102 hid_action ("NetlistChanged");
106 LibraryMenuType *
107 netnode_to_netname (char *nodename)
109 int i, j;
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]);
122 return 0;
125 LibraryMenuType *
126 netname_to_netname (char *netname)
128 int i;
130 if ((netname[0] == '*' || netname[0] == ' ') && netname[1] == ' ')
132 /* Looks like we were passed an internal netname, skip the prefix */
133 netname += 2;
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]);
142 return 0;
145 static int
146 pin_name_to_xy (LibraryEntryType * pin, int *x, int *y)
148 ConnectionType conn;
149 if (!SeekPad (pin, &conn, false))
150 return 1;
151 switch (conn.type)
153 case PIN_TYPE:
154 *x = ((PinType *) (conn.ptr2))->X;
155 *y = ((PinType *) (conn.ptr2))->Y;
156 return 0;
157 case PAD_TYPE:
158 *x = ((PadType *) (conn.ptr2))->Point1.X;
159 *y = ((PadType *) (conn.ptr2))->Point1.Y;
160 return 0;
162 return 1;
165 static void
166 netlist_find (LibraryMenuType * net, LibraryEntryType * pin)
168 int x, y;
169 if (pin_name_to_xy (net->Entry, &x, &y))
170 return;
171 LookupConnection (x, y, 1, 1, FOUNDFLAG, true, true);
174 static void
175 netlist_select (LibraryMenuType * net, LibraryEntryType * pin)
177 int x, y;
178 if (pin_name_to_xy (net->Entry, &x, &y))
179 return;
180 LookupConnection (x, y, 1, 1, SELECTEDFLAG, true, true);
183 static void
184 netlist_rats (LibraryMenuType * net, LibraryEntryType * pin)
186 net->Name[0] = ' ';
187 net->flag = 1;
188 NetlistChanged (0);
191 static void
192 netlist_norats (LibraryMenuType * net, LibraryEntryType * pin)
194 net->Name[0] = '*';
195 net->flag = 0;
196 NetlistChanged (0);
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
202 * style script.
204 static void
205 netlist_clear (LibraryMenuType * net, LibraryEntryType * pin)
207 LibraryType *netlist = &PCB->NetlistLib;
208 int ni, pi;
210 if (net == 0)
212 /* Clear the entire netlist. */
213 FreeLibraryMemory (&PCB->NetlistLib);
215 else if (pin == 0)
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));
224 netlist->MenuN --;
227 else
229 /* Remove a pin from the given net. Note that this may leave an
230 empty net, which is different than removing the net
231 (above). */
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));
238 net->EntryN --;
241 NetlistChanged (0);
244 static void
245 netlist_style (LibraryMenuType *net, const char *style)
247 free (net->Style);
248 net->Style = STRDUP ((char *)style);
251 static void
252 netlist_netclass (LibraryMenuType *net, const char *netclass)
254 free (net->Netclass);
255 net->Netclass = STRDUP ((char *)netclass);
259 * \brief The primary purpose of this action is to rebuild a netlist
260 * from a script, in conjunction with the clear action above.
262 static int
263 netlist_add (const char *netname, const char *pinname)
265 int ni, pi;
266 LibraryType *netlist = &PCB->NetlistLib;
267 LibraryMenuType *net = NULL;
268 LibraryEntryType *pin = NULL;
270 for (ni=0; ni<netlist->MenuN; ni++)
271 if (strcmp (netlist->Menu[ni].Name+2, netname) == 0)
273 net = & (netlist->Menu[ni]);
274 break;
276 if (net == NULL)
278 net = CreateNewNet (netlist, (char *)netname, NULL, NULL);
281 for (pi=0; pi<net->EntryN; pi++)
282 if (strcmp (net->Entry[pi].ListEntry, pinname) == 0)
284 pin = & (net->Entry[pi]);
285 break;
287 if (pin == NULL)
289 pin = CreateNewConnection (net, (char *)pinname);
292 NetlistChanged (0);
293 return 0;
296 static const char netlist_syntax[] =
297 "Net(find|select|rats|norats|clear[,net[,pin]])\n"
298 "Net(freeze|thaw|forcethaw)\n"
299 "Net(add,net,pin)";
301 static const char netlist_help[] = "Perform various actions on netlists.";
303 /* %start-doc actions Netlist
305 Each of these actions apply to a specified set of nets. @var{net} and
306 @var{pin} are patterns which match one or more nets or pins; these
307 patterns may be full names or regular expressions. If an exact match
308 is found, it is the only match; if no exact match is found,
309 @emph{then} the pattern is tried as a regular expression.
311 If neither @var{net} nor @var{pin} are specified, all nets apply. If
312 @var{net} is specified but not @var{pin}, all nets matching @var{net}
313 apply. If both are specified, nets which match @var{net} and contain
314 a pin matching @var{pin} apply.
316 @table @code
318 @item find
319 Nets which apply are marked @emph{found} and are drawn in the
320 @code{connected-color} color.
322 @item select
323 Nets which apply are selected.
325 @item rats
326 Nets which apply are marked as available for the rats nest.
328 @item norats
329 Nets which apply are marked as not available for the rats nest.
331 @item clear
332 Clears the netlist.
334 @item add
335 Add the given pin to the given netlist, creating either if needed.
337 @item sort
338 Called after a list of add's, this sorts the netlist.
340 @item freeze
341 @itemx thaw
342 @itemx forcethaw
343 Temporarily prevents changes to the netlist from being reflected in
344 the GUI. For example, if you need to make multiple changes, you
345 freeze the netlist, make the changes, then thaw it. Note that
346 freeze/thaw requests may nest, with the netlist being fully thawed
347 only when all pending freezes are thawed. You can bypass the nesting
348 by using forcethaw, which resets the freeze count and immediately
349 updates the GUI.
351 @end table
353 %end-doc */
355 #define ARG(n) (argc > (n) ? argv[n] : 0)
357 static int
358 Netlist (int argc, char **argv, Coord x, Coord y)
360 NFunc func;
361 int i, j;
362 LibraryMenuType *net;
363 LibraryEntryType *pin;
364 int net_found = 0;
365 int pin_found = 0;
366 #if defined(USE_RE)
367 int use_re = 0;
368 #endif
369 #if defined(HAVE_REGCOMP)
370 regex_t elt_pattern;
371 regmatch_t match;
372 #endif
373 #if defined(HAVE_RE_COMP)
374 char *elt_pattern;
375 #endif
377 if (!PCB)
378 return 1;
379 if (argc == 0)
381 Message (netlist_syntax);
382 return 1;
384 if (strcasecmp (argv[0], "find") == 0)
385 func = netlist_find;
386 else if (strcasecmp (argv[0], "select") == 0)
387 func = netlist_select;
388 else if (strcasecmp (argv[0], "rats") == 0)
389 func = netlist_rats;
390 else if (strcasecmp (argv[0], "norats") == 0)
391 func = netlist_norats;
392 else if (strcasecmp (argv[0], "clear") == 0)
394 func = netlist_clear;
395 if (argc == 1)
397 netlist_clear (NULL, NULL);
398 return 0;
401 else if (strcasecmp (argv[0], "style") == 0)
402 func = (NFunc)netlist_style;
403 else if (strcasecmp (argv[0], "class") == 0)
404 func = (NFunc)netlist_netclass;
405 else if (strcasecmp (argv[0], "add") == 0)
407 /* Add is different, because the net/pin won't already exist. */
408 return netlist_add (ARG(1), ARG(2)); /* Net class? */
410 else if (strcasecmp (argv[0], "sort") == 0)
412 sort_netlist ();
413 return 0;
415 else if (strcasecmp (argv[0], "freeze") == 0)
417 netlist_frozen ++;
418 return 0;
420 else if (strcasecmp (argv[0], "thaw") == 0)
422 if (netlist_frozen > 0)
424 netlist_frozen --;
425 if (netlist_needs_update)
426 NetlistChanged (0);
428 return 0;
430 else if (strcasecmp (argv[0], "forcethaw") == 0)
432 netlist_frozen = 0;
433 if (netlist_needs_update)
434 NetlistChanged (0);
435 return 0;
437 else
439 Message (netlist_syntax);
440 return 1;
443 #if defined(USE_RE)
444 if (argc > 1)
446 int result;
447 use_re = 1;
448 for (i = 0; i < PCB->NetlistLib.MenuN; i++)
450 net = PCB->NetlistLib.Menu + i;
451 if (strcasecmp (argv[1], net->Name + 2) == 0)
452 use_re = 0;
454 if (use_re)
456 #if defined(HAVE_REGCOMP)
457 result =
458 regcomp (&elt_pattern, argv[1],
459 REG_EXTENDED | REG_ICASE | REG_NOSUB);
460 if (result)
462 char errorstring[128];
464 regerror (result, &elt_pattern, errorstring, 128);
465 Message (_("regexp error: %s\n"), errorstring);
466 regfree (&elt_pattern);
467 return (1);
469 #endif
470 #if defined(HAVE_RE_COMP)
471 if ((elt_pattern = re_comp (argv[1])) != NULL)
473 Message (_("re_comp error: %s\n"), elt_pattern);
474 return (false);
476 #endif
479 #endif
481 for (i = PCB->NetlistLib.MenuN-1; i >= 0; i--)
483 net = PCB->NetlistLib.Menu + i;
485 if (argc > 1)
487 #if defined(USE_RE)
488 if (use_re)
490 #if defined(HAVE_REGCOMP)
491 if (regexec (&elt_pattern, net->Name + 2, 1, &match, 0) != 0)
492 continue;
493 #endif
494 #if defined(HAVE_RE_COMP)
495 if (re_exec (net->Name + 2) != 1)
496 continue;
497 #endif
499 else
500 #endif
501 if (strcasecmp (net->Name + 2, argv[1]))
502 continue;
504 net_found = 1;
506 pin = 0;
507 if (func == (void *)netlist_style)
509 netlist_style (net, ARG(2));
511 else if (func == (void *)netlist_netclass)
513 netlist_netclass (net, ARG(2));
515 else if (argc > 2)
517 int l = strlen (argv[2]);
518 for (j = net->EntryN-1; j >= 0 ; j--)
519 if (strcasecmp (net->Entry[j].ListEntry, argv[2]) == 0
520 || (strncasecmp (net->Entry[j].ListEntry, argv[2], l) == 0
521 && net->Entry[j].ListEntry[l] == '-'))
523 pin = net->Entry + j;
524 pin_found = 1;
525 func (net, pin);
528 else
529 func (net, 0);
532 if (argc > 2 && !pin_found)
534 gui->log ("Net %s has no pin %s\n", argv[1], argv[2]);
535 return 1;
537 else if (!net_found)
539 gui->log ("No net named %s\n", argv[1]);
541 #ifdef HAVE_REGCOMP
542 if (use_re)
543 regfree (&elt_pattern);
544 #endif
546 return 0;
549 HID_Action netlist_action_list[] = {
550 {"net", 0, Netlist,
551 netlist_help, netlist_syntax}
553 {"netlist", 0, Netlist,
554 netlist_help, netlist_syntax}
557 REGISTER_ACTIONS (netlist_action_list)