pcb 4.1.1
An interactive printed circuit board layout editor.

netlist.c

Go to the documentation of this file.
00001 
00035 #ifdef HAVE_CONFIG_H
00036 #include "config.h"
00037 #endif
00038 
00039 #include <stdlib.h>
00040 #ifdef HAVE_STRING_H
00041 #include <string.h>
00042 #endif
00043 #include <ctype.h>
00044 #include <sys/types.h>
00045 #ifdef HAVE_REGEX_H
00046 #include <regex.h>
00047 #endif
00048 
00049 #include "global.h"
00050 #include "action.h"
00051 #include "buffer.h"
00052 #include "data.h"
00053 #include "djopt.h"
00054 #include "error.h"
00055 #include "file.h"
00056 #include "find.h"
00057 #include "mymem.h"
00058 #include "misc.h"
00059 #include "rats.h"
00060 #include "set.h"
00061 #include "vendor.h"
00062 #include "create.h"
00063 
00064 #ifdef HAVE_REGCOMP
00065 #undef HAVE_RE_COMP
00066 #endif
00067 
00068 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
00069 #define USE_RE
00070 #endif
00071 
00072 #ifdef HAVE_LIBDMALLOC
00073 #include <dmalloc.h>
00074 #endif
00075 
00076 /*
00077   int    PCB->NetlistLib.MenuN
00078   char * PCB->NetlistLib.Menu[i].Name
00079      [0] == '*' (ok for rats) or ' ' (skip for rats)
00080      [1] == unused
00081      [2..] actual name
00082   char * PCB->NetlistLib.Menu[i].Style
00083   int    PCB->NetlistLib.Menu[i].EntryN
00084   char * PCB->NetlistLib.Menu[i].Entry[j].ListEntry
00085 */
00086 
00087 typedef void (*NFunc) (LibraryMenuType *, LibraryEntryType *);
00088 
00089 int netlist_frozen = 0;
00090 static int netlist_needs_update = 0;
00091 
00092 void
00093 NetlistChanged (int force_unfreeze)
00094 {
00095   if (force_unfreeze)
00096     netlist_frozen = 0;
00097   if (netlist_frozen)
00098     netlist_needs_update = 1;
00099   else
00100     {
00101       netlist_needs_update = 0;
00102       hid_action ("NetlistChanged");
00103     }
00104 }
00105 
00106 LibraryMenuType *
00107 netnode_to_netname (char *nodename)
00108 {
00109   int i, j;
00110   /*printf("nodename [%s]\n", nodename);*/
00111   for (i=0; i<PCB->NetlistLib.MenuN; i++)
00112     {
00113       for (j=0; j<PCB->NetlistLib.Menu[i].EntryN; j++)
00114         {
00115           if (strcmp (PCB->NetlistLib.Menu[i].Entry[j].ListEntry, nodename) == 0)
00116             {
00117               /*printf(" in [%s]\n", PCB->NetlistLib.Menu[i].Name);*/
00118               return & (PCB->NetlistLib.Menu[i]);
00119             }
00120         }
00121     }
00122   return 0;
00123 }
00124 
00125 LibraryMenuType *
00126 netname_to_netname (char *netname)
00127 {
00128   int i;
00129 
00130   if ((netname[0] == '*' || netname[0] == ' ') && netname[1] == ' ')
00131     {
00132       /* Looks like we were passed an internal netname, skip the prefix */
00133       netname += 2;
00134     }
00135   for (i=0; i<PCB->NetlistLib.MenuN; i++)
00136     {
00137       if (strcmp (PCB->NetlistLib.Menu[i].Name + 2, netname) == 0)
00138         {
00139           return & (PCB->NetlistLib.Menu[i]);
00140         }
00141     }
00142   return 0;
00143 }
00144 
00145 static int
00146 pin_name_to_xy (LibraryEntryType * pin, int *x, int *y)
00147 {
00148   ConnectionType conn;
00149   if (!SeekPad (pin, &conn, false))
00150     return 1;
00151   switch (conn.type)
00152     {
00153     case PIN_TYPE:
00154       *x = ((PinType *) (conn.ptr2))->X;
00155       *y = ((PinType *) (conn.ptr2))->Y;
00156       return 0;
00157     case PAD_TYPE:
00158       *x = ((PadType *) (conn.ptr2))->Point1.X;
00159       *y = ((PadType *) (conn.ptr2))->Point1.Y;
00160       return 0;
00161     }
00162   return 1;
00163 }
00164 
00165 static void
00166 netlist_find (LibraryMenuType * net, LibraryEntryType * pin)
00167 {
00168   int x, y;
00169   if (pin_name_to_xy (net->Entry, &x, &y))
00170     return;
00171   LookupConnection (x, y, 1, 1, FOUNDFLAG, true);
00172 }
00173 
00174 static void
00175 netlist_select (LibraryMenuType * net, LibraryEntryType * pin)
00176 {
00177   int x, y;
00178   if (pin_name_to_xy (net->Entry, &x, &y))
00179     return;
00180   LookupConnection (x, y, 1, 1, SELECTEDFLAG, true);
00181 }
00182 
00183 static void
00184 netlist_rats (LibraryMenuType * net, LibraryEntryType * pin)
00185 {
00186   net->Name[0] = ' ';
00187   net->flag = 1;
00188   NetlistChanged (0);
00189 }
00190 
00191 static void
00192 netlist_norats (LibraryMenuType * net, LibraryEntryType * pin)
00193 {
00194   net->Name[0] = '*';
00195   net->flag = 0;
00196   NetlistChanged (0);
00197 }
00198 
00204 static void
00205 netlist_clear (LibraryMenuType * net, LibraryEntryType * pin)
00206 {
00207   LibraryType *netlist = &PCB->NetlistLib;
00208   int ni, pi;
00209 
00210   if (net == 0)
00211     {
00212       /* Clear the entire netlist. */
00213       FreeLibraryMemory (&PCB->NetlistLib);
00214     }
00215   else if (pin == 0)
00216     {
00217       /* Remove a net from the netlist. */
00218       ni = net - netlist->Menu;
00219       if (ni >= 0 && ni < netlist->MenuN)
00220         {
00221           /* if there is exactly one item, MenuN is 1 and ni is 0 */
00222           if (netlist->MenuN - ni > 1)
00223             memmove (net, net+1, (netlist->MenuN - ni - 1) * sizeof (*net));
00224           netlist->MenuN --;
00225         }
00226     }
00227   else
00228     {
00229       /* Remove a pin from the given net.  Note that this may leave an
00230          empty net, which is different than removing the net
00231          (above).  */
00232       pi = pin - net->Entry;
00233       if (pi >= 0 && pi < net->EntryN)
00234         {
00235           /* if there is exactly one item, MenuN is 1 and ni is 0 */
00236           if (net->EntryN - pi > 1)
00237             memmove (pin, pin+1, (net->EntryN - pi - 1) * sizeof (*pin));
00238           net->EntryN --;
00239         }
00240     }
00241   NetlistChanged (0);
00242 }
00243 
00244 static void
00245 netlist_style (LibraryMenuType *net, const char *style)
00246 {
00247   free (net->Style);
00248   net->Style = STRDUP ((char *)style);
00249 }
00250 
00255 static int
00256 netlist_add (const char *netname, const char *pinname)
00257 {
00258   int ni, pi;
00259   LibraryType *netlist = &PCB->NetlistLib;
00260   LibraryMenuType *net = NULL;
00261   LibraryEntryType *pin = NULL;
00262 
00263   for (ni=0; ni<netlist->MenuN; ni++)
00264     if (strcmp (netlist->Menu[ni].Name+2, netname) == 0)
00265       {
00266         net = & (netlist->Menu[ni]);
00267         break;
00268       }
00269   if (net == NULL)
00270     {
00271       net = CreateNewNet (netlist, (char *)netname, NULL);
00272     }
00273 
00274   for (pi=0; pi<net->EntryN; pi++)
00275     if (strcmp (net->Entry[pi].ListEntry, pinname) == 0)
00276       {
00277         pin = & (net->Entry[pi]);
00278         break;
00279       }
00280   if (pin == NULL)
00281     {
00282       pin = CreateNewConnection (net, (char *)pinname);
00283     }
00284 
00285   NetlistChanged (0);
00286   return 0;
00287 }
00288 
00289 static const char netlist_syntax[] =
00290   "Net(find|select|rats|norats|clear[,net[,pin]])\n"
00291   "Net(freeze|thaw|forcethaw)\n"
00292   "Net(add,net,pin)";
00293 
00294 static const char netlist_help[] = "Perform various actions on netlists.";
00295 
00296 /* %start-doc actions Netlist
00297 
00298 Each of these actions apply to a specified set of nets.  @var{net} and
00299 @var{pin} are patterns which match one or more nets or pins; these
00300 patterns may be full names or regular expressions.  If an exact match
00301 is found, it is the only match; if no exact match is found,
00302 @emph{then} the pattern is tried as a regular expression.
00303 
00304 If neither @var{net} nor @var{pin} are specified, all nets apply.  If
00305 @var{net} is specified but not @var{pin}, all nets matching @var{net}
00306 apply.  If both are specified, nets which match @var{net} and contain
00307 a pin matching @var{pin} apply.
00308 
00309 @table @code
00310 
00311 @item find
00312 Nets which apply are marked @emph{found} and are drawn in the
00313 @code{connected-color} color.
00314 
00315 @item select
00316 Nets which apply are selected.
00317 
00318 @item rats
00319 Nets which apply are marked as available for the rats nest.
00320 
00321 @item norats
00322 Nets which apply are marked as not available for the rats nest.
00323 
00324 @item clear
00325 Clears the netlist.
00326 
00327 @item add
00328 Add the given pin to the given netlist, creating either if needed.
00329 
00330 @item sort
00331 Called after a list of add's, this sorts the netlist.
00332 
00333 @item freeze
00334 @itemx thaw
00335 @itemx forcethaw
00336 Temporarily prevents changes to the netlist from being reflected in
00337 the GUI.  For example, if you need to make multiple changes, you
00338 freeze the netlist, make the changes, then thaw it.  Note that
00339 freeze/thaw requests may nest, with the netlist being fully thawed
00340 only when all pending freezes are thawed.  You can bypass the nesting
00341 by using forcethaw, which resets the freeze count and immediately
00342 updates the GUI.
00343 
00344 @end table
00345 
00346 %end-doc */
00347 
00348 #define ARG(n) (argc > (n) ? argv[n] : 0)
00349 
00350 static int
00351 Netlist (int argc, char **argv, Coord x, Coord y)
00352 {
00353   NFunc func;
00354   int i, j;
00355   LibraryMenuType *net;
00356   LibraryEntryType *pin;
00357   int net_found = 0;
00358   int pin_found = 0;
00359 #if defined(USE_RE)
00360   int use_re = 0;
00361 #endif
00362 #if defined(HAVE_REGCOMP)
00363   regex_t elt_pattern;
00364   regmatch_t match;
00365 #endif
00366 #if defined(HAVE_RE_COMP)
00367   char *elt_pattern;
00368 #endif
00369 
00370   if (!PCB)
00371     return 1;
00372   if (argc == 0)
00373     {
00374       Message (netlist_syntax);
00375       return 1;
00376     }
00377   if (strcasecmp (argv[0], "find") == 0)
00378     func = netlist_find;
00379   else if (strcasecmp (argv[0], "select") == 0)
00380     func = netlist_select;
00381   else if (strcasecmp (argv[0], "rats") == 0)
00382     func = netlist_rats;
00383   else if (strcasecmp (argv[0], "norats") == 0)
00384     func = netlist_norats;
00385   else if (strcasecmp (argv[0], "clear") == 0)
00386     {
00387       func = netlist_clear;
00388       if (argc == 1)
00389         {
00390           netlist_clear (NULL, NULL);
00391           return 0;
00392         }
00393     }
00394   else if (strcasecmp (argv[0], "style") == 0)
00395     func = (NFunc)netlist_style;
00396   else if (strcasecmp (argv[0], "add") == 0)
00397     {
00398       /* Add is different, because the net/pin won't already exist.  */
00399       return netlist_add (ARG(1), ARG(2));
00400     }
00401   else if (strcasecmp (argv[0], "sort") == 0)
00402     {
00403       sort_netlist ();
00404       return 0;
00405     }
00406   else if (strcasecmp (argv[0], "freeze") == 0)
00407     {
00408       netlist_frozen ++;
00409       return 0;
00410     }
00411   else if (strcasecmp (argv[0], "thaw") == 0)
00412     {
00413       if (netlist_frozen > 0)
00414         {
00415           netlist_frozen --;
00416           if (netlist_needs_update)
00417             NetlistChanged (0);
00418         }
00419       return 0;
00420     }
00421   else if (strcasecmp (argv[0], "forcethaw") == 0)
00422     {
00423       netlist_frozen = 0;
00424       if (netlist_needs_update)
00425         NetlistChanged (0);
00426       return 0;
00427     }
00428   else
00429     {
00430       Message (netlist_syntax);
00431       return 1;
00432     }
00433 
00434 #if defined(USE_RE)
00435   if (argc > 1)
00436     {
00437       int result;
00438       use_re = 1;
00439       for (i = 0; i < PCB->NetlistLib.MenuN; i++)
00440         {
00441           net = PCB->NetlistLib.Menu + i;
00442           if (strcasecmp (argv[1], net->Name + 2) == 0)
00443             use_re = 0;
00444         }
00445       if (use_re)
00446         {
00447 #if defined(HAVE_REGCOMP)
00448           result =
00449             regcomp (&elt_pattern, argv[1],
00450                      REG_EXTENDED | REG_ICASE | REG_NOSUB);
00451           if (result)
00452             {
00453               char errorstring[128];
00454 
00455               regerror (result, &elt_pattern, errorstring, 128);
00456               Message (_("regexp error: %s\n"), errorstring);
00457               regfree (&elt_pattern);
00458               return (1);
00459             }
00460 #endif
00461 #if defined(HAVE_RE_COMP)
00462           if ((elt_pattern = re_comp (argv[1])) != NULL)
00463             {
00464               Message (_("re_comp error: %s\n"), elt_pattern);
00465               return (false);
00466             }
00467 #endif
00468         }
00469     }
00470 #endif
00471 
00472   for (i = PCB->NetlistLib.MenuN-1; i >= 0; i--)
00473     {
00474       net = PCB->NetlistLib.Menu + i;
00475 
00476       if (argc > 1)
00477         {
00478 #if defined(USE_RE)
00479           if (use_re)
00480             {
00481 #if defined(HAVE_REGCOMP)
00482               if (regexec (&elt_pattern, net->Name + 2, 1, &match, 0) != 0)
00483                 continue;
00484 #endif
00485 #if defined(HAVE_RE_COMP)
00486               if (re_exec (net->Name + 2) != 1)
00487                 continue;
00488 #endif
00489             }
00490           else
00491 #endif
00492           if (strcasecmp (net->Name + 2, argv[1]))
00493             continue;
00494         }
00495       net_found = 1;
00496 
00497       pin = 0;
00498       if (func == (void *)netlist_style)
00499         {
00500           netlist_style (net, ARG(2));
00501         }
00502       else if (argc > 2)
00503         {
00504           int l = strlen (argv[2]);
00505           for (j = net->EntryN-1; j >= 0 ; j--)
00506             if (strcasecmp (net->Entry[j].ListEntry, argv[2]) == 0
00507                 || (strncasecmp (net->Entry[j].ListEntry, argv[2], l) == 0
00508                     && net->Entry[j].ListEntry[l] == '-'))
00509               {
00510                 pin = net->Entry + j;
00511                 pin_found = 1;
00512                 func (net, pin);
00513               }
00514         }
00515       else
00516         func (net, 0);
00517     }
00518 
00519   if (argc > 2 && !pin_found)
00520     {
00521       gui->log ("Net %s has no pin %s\n", argv[1], argv[2]);
00522       return 1;
00523     }
00524   else if (!net_found)
00525     {
00526       gui->log ("No net named %s\n", argv[1]);
00527     }
00528 #ifdef HAVE_REGCOMP
00529   if (use_re)
00530     regfree (&elt_pattern);
00531 #endif
00532 
00533   return 0;
00534 }
00535 
00536 HID_Action netlist_action_list[] = {
00537   {"net", 0, Netlist,
00538    netlist_help, netlist_syntax}
00539   ,
00540   {"netlist", 0, Netlist,
00541    netlist_help, netlist_syntax}
00542 };
00543 
00544 REGISTER_ACTIONS (netlist_action_list)