1 /*!
2  * \file src/rats.c
3  *
4  * \brief Rats nest routines.
5  *
6  * <hr>
7  *
8  * <h1><b>Copyright.</b></h1>\n
9  *
10  * PCB, interactive printed circuit board design
11  *
12  * Copyright (C) 1994,1995,1996 Thomas Nau
13  *
14  * Copyright (C) 1997, harry eaton
15  *
16  * This module, rats.c, was written and is Copyright (C) 1997 by
17  * harry eaton.
18  *
19  * This module is also subject to the GNU GPL as described below.
20  *
21  * This program is free software; you can redistribute it and/or modify
22  * it under the terms of the GNU General Public License as published by
23  * the Free Software Foundation; either version 2 of the License, or
24  * (at your option) any later version.
25  *
26  * This program is distributed in the hope that it will be useful,
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29  * GNU General Public License for more details.
30  *
31  * You should have received a copy of the GNU General Public License along
32  * with this program; if not, write to the Free Software Foundation, Inc.,
33  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34  */
35 
36 /* Change History:
37  * Started 6/10/97
38  * Added support for minimum length rat lines 6/13/97
39  * rat lines to nearest line/via 8/29/98
40  * support for netlist window 10/24/98
41  */
42 
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46 
47 #include <math.h>
48 #include <stdio.h>
49 
50 #include "global.h"
51 
52 #include "create.h"
53 #include "data.h"
54 #include "draw.h"
55 #include "error.h"
56 #include "file.h"
57 #include "find.h"
58 #include "flags.h"
59 #include "misc.h"
60 #include "mymem.h"
61 #include "polygon.h"
62 #include "rats.h"
63 #include "search.h"
64 #include "set.h"
65 #include "undo.h"
66 
67 #ifdef HAVE_LIBDMALLOC
68 #include <dmalloc.h>
69 #endif
70 
71 #define TRIEDFIRST 0x1
72 #define BESTFOUND 0x2
73 
74 /* ---------------------------------------------------------------------------
75  * some forward declarations
76  */
77 static bool FindPad (char *, char *, ConnectionType *, bool);
78 static bool ParseConnection (char *, char *, char *);
79 static bool DrawShortestRats (NetListType *, void (*)(register ConnectionType *, register ConnectionType *, register RouteStyleType *));
80 static bool GatherSubnets (NetListType *, bool, bool);
81 static bool CheckShorts (LibraryMenuType *);
82 static void TransferNet (NetListType *, NetType *, NetType *);
83 
84 /* ---------------------------------------------------------------------------
85  * some local identifiers
86  */
87 static bool badnet = false;
88 static Cardinal top_group, bottom_group;	/* layer group holding top/bottom side */
89 
90 /*!
91  * \brief Parse a connection description from a string.
92  *
93  * Puts the element name in the string and the pin number in
94  * the number.
95  *
96  * \return If a valid connection is found, it returns the number of characters
97  * processed from the string, otherwise it returns 0.
98  */
99 static bool
ParseConnection(char * InString,char * ElementName,char * PinNum)100 ParseConnection (char *InString, char *ElementName, char *PinNum)
101 {
102   int i, j;
103 
104   /* copy element name portion */
105   for (j = 0; InString[j] != '\0' && InString[j] != '-'; j++)
106     ElementName[j] = InString[j];
107   if (InString[j] == '-')
108     {
109       for (i = j; i > 0 && ElementName[i - 1] >= 'a'; i--);
110       ElementName[i] = '\0';
111       for (i = 0, j++; InString[j] != '\0'; i++, j++)
112 	PinNum[i] = InString[j];
113       PinNum[i] = '\0';
114       return (false);
115     }
116   else
117     {
118       ElementName[j] = '\0';
119       Message (_("Bad net-list format encountered near: \"%s\"\n"),
120 	       ElementName);
121       return (true);
122     }
123 }
124 
125 /*!
126  * \brief Find a particular pad from an element name and pin number.
127  */
128 static bool
FindPad(char * ElementName,char * PinNum,ConnectionType * conn,bool Same)129 FindPad (char *ElementName, char *PinNum, ConnectionType * conn, bool Same)
130 {
131   ElementType *element;
132   GList *i;
133 
134   if ((element = SearchElementByName (PCB->Data, ElementName)) == NULL)
135     return false;
136 
137   for (i = element->Pad; i != NULL; i = g_list_next (i))
138     {
139       PadType *pad = i->data;
140 
141       if (NSTRCMP (PinNum, pad->Number) == 0 &&
142           (!Same || !TEST_FLAG (DRCFLAG, pad)))
143         {
144           conn->type = PAD_TYPE;
145           conn->ptr1 = element;
146           conn->ptr2 = pad;
147           conn->group = TEST_FLAG (ONSOLDERFLAG, pad) ? bottom_group : top_group;
148 
149           if (TEST_FLAG (EDGE2FLAG, pad))
150             {
151               conn->X = pad->Point2.X;
152               conn->Y = pad->Point2.Y;
153             }
154           else
155             {
156               conn->X = pad->Point1.X;
157               conn->Y = pad->Point1.Y;
158             }
159           return true;
160         }
161     }
162 
163   for (i = element->Pin; i != NULL; i = g_list_next (i))
164     {
165       PinType *pin = i->data;
166 
167       if (!TEST_FLAG (HOLEFLAG, pin) &&
168           pin->Number && NSTRCMP (PinNum, pin->Number) == 0 &&
169           (!Same || !TEST_FLAG (DRCFLAG, pin)))
170         {
171           conn->type = PIN_TYPE;
172           conn->ptr1 = element;
173           conn->ptr2 = pin;
174           conn->group = bottom_group;        /* any layer will do */
175           conn->X = pin->X;
176           conn->Y = pin->Y;
177           return true;
178         }
179     }
180 
181   return false;
182 }
183 
184 /*!
185  * \brief Parse a netlist menu entry and locate the corresponding pad.
186  *
187  * \return true if found, and fills in Connection information.
188  */
189 bool
SeekPad(LibraryEntryType * entry,ConnectionType * conn,bool Same)190 SeekPad (LibraryEntryType * entry, ConnectionType * conn, bool Same)
191 {
192   int j;
193   char ElementName[256];
194   char PinNum[256];
195 
196   if (ParseConnection (entry->ListEntry, ElementName, PinNum))
197     return (false);
198   for (j = 0; PinNum[j] != '\0'; j++);
199   if (j == 0)
200     {
201       Message (_("Error! Netlist file is missing pin!\n"
202 		 "white space after \"%s-\"\n"), ElementName);
203       badnet = true;
204     }
205   else
206     {
207       if (FindPad (ElementName, PinNum, conn, Same))
208 	return (true);
209       if (Same)
210 	return (false);
211       if (PinNum[j - 1] < '0' || PinNum[j - 1] > '9')
212 	{
213 	  Message ("WARNING! Pin number ending with '%c'"
214 		   " encountered in netlist file\n"
215 		   "Probably a bad netlist file format\n", PinNum[j - 1]);
216 	}
217     }
218   Message (_("Can't find %s pin %s called for in netlist.\n"),
219 	   ElementName, PinNum);
220   return (false);
221 }
222 
223 /*!
224  * \brief Read the library-netlist build a true Netlist structure.
225  */
226 NetListType *
ProcNetlist(LibraryType * net_menu)227 ProcNetlist (LibraryType *net_menu)
228 {
229   ConnectionType *connection;
230   ConnectionType LastPoint;
231   NetType *net;
232   static NetListType *Wantlist = NULL;
233 
234   if (!net_menu->MenuN)
235     return (NULL);
236   FreeNetListMemory (Wantlist);
237   free (Wantlist);
238   badnet = false;
239 
240   /* find layer groups of the component side and solder side */
241   bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
242   top_group = GetLayerGroupNumberBySide (TOP_SIDE);
243 
244   Wantlist = (NetListType *)calloc (1, sizeof (NetListType));
245   if (Wantlist)
246     {
247       ALLPIN_LOOP (PCB->Data);
248       {
249 	pin->Spare = NULL;
250 	CLEAR_FLAG (DRCFLAG, pin);
251       }
252       ENDALL_LOOP;
253       ALLPAD_LOOP (PCB->Data);
254       {
255 	pad->Spare = NULL;
256 	CLEAR_FLAG (DRCFLAG, pad);
257       }
258       ENDALL_LOOP;
259       MENU_LOOP (net_menu);
260       {
261 	if (menu->Name[0] == '*' || menu->flag == 0)
262 	  {
263 	    badnet = true;
264 	    continue;
265 	  }
266 	net = GetNetMemory (Wantlist);
267 	if (menu->Style)
268 	  {
269 	    STYLE_LOOP (PCB);
270 	    {
271 	      if (style->Name && !NSTRCMP (style->Name, menu->Style))
272 		{
273 		  net->Style = style;
274 		  break;
275 		}
276 	    }
277 	    END_LOOP;
278 	  }
279 	else			/* default to NULL if none found */
280 	  net->Style = NULL;
281 	ENTRY_LOOP (menu);
282 	{
283 	  if (SeekPad (entry, &LastPoint, false))
284 	    {
285 	      if (TEST_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2))
286 		Message (_
287 			 ("Error! Element %s pin %s appears multiple times in the netlist file.\n"),
288 			 NAMEONPCB_NAME ((ElementType *) LastPoint.ptr1),
289 			 (LastPoint.type ==
290 			  PIN_TYPE) ? ((PinType *) LastPoint.ptr2)->
291 			 Number : ((PadType *) LastPoint.ptr2)->Number);
292 	      else
293 		{
294 		  connection = GetConnectionMemory (net);
295 		  *connection = LastPoint;
296 		  /* indicate expect net */
297 		  connection->menu = menu;
298 		  /* mark as visited */
299 		  SET_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2);
300 		  if (LastPoint.type == PIN_TYPE)
301 		    ((PinType *) LastPoint.ptr2)->Spare = (void *) menu;
302 		  else
303 		    ((PadType *) LastPoint.ptr2)->Spare = (void *) menu;
304 		}
305 	    }
306 	  else
307 	    badnet = true;
308 	  /* check for more pins with the same number */
309 	  for (; SeekPad (entry, &LastPoint, true);)
310 	    {
311 	      connection = GetConnectionMemory (net);
312 	      *connection = LastPoint;
313 	      /* indicate expect net */
314 	      connection->menu = menu;
315 	      /* mark as visited */
316 	      SET_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2);
317 	      if (LastPoint.type == PIN_TYPE)
318 		((PinType *) LastPoint.ptr2)->Spare = (void *) menu;
319 	      else
320 		((PadType *) LastPoint.ptr2)->Spare = (void *) menu;
321 	    }
322 	}
323 	END_LOOP;
324       }
325       END_LOOP;
326     }
327   /* clear all visit marks */
328   ALLPIN_LOOP (PCB->Data);
329   {
330     CLEAR_FLAG (DRCFLAG, pin);
331   }
332   ENDALL_LOOP;
333   ALLPAD_LOOP (PCB->Data);
334   {
335     CLEAR_FLAG (DRCFLAG, pad);
336   }
337   ENDALL_LOOP;
338   return (Wantlist);
339 }
340 
341 /*!
342  * \brief Copy all connections from one net into another and then remove
343  * the first net from its netlist.
344  */
345 static void
TransferNet(NetListType * Netl,NetType * SourceNet,NetType * DestNet)346 TransferNet (NetListType *Netl, NetType *SourceNet, NetType *DestNet)
347 {
348   ConnectionType *conn;
349 
350   /* It would be worth checking if SourceNet is NULL here to avoid a segfault. Seb James. */
351   CONNECTION_LOOP (SourceNet);
352   {
353     conn = GetConnectionMemory (DestNet);
354     *conn = *connection;
355   }
356   END_LOOP;
357   DestNet->Style = SourceNet->Style;
358   /* free the connection memory */
359   FreeNetMemory (SourceNet);
360   /* remove SourceNet from its netlist */
361   *SourceNet = Netl->Net[--(Netl->NetN)];
362   /* zero out old garbage */
363   memset (&Netl->Net[Netl->NetN], 0, sizeof (NetType));
364 }
365 
366 static bool
CheckShorts(LibraryMenuType * theNet)367 CheckShorts (LibraryMenuType *theNet)
368 {
369   bool newone, warn = false;
370   PointerListType *generic = (PointerListType *)calloc (1, sizeof (PointerListType));
371   /* the first connection was starting point so
372    * the menu is always non-null
373    */
374   void **menu = GetPointerMemory (generic);
375 
376   *menu = theNet;
377   ALLPIN_LOOP (PCB->Data);
378   {
379     if (TEST_FLAG (DRCFLAG, pin))
380       {
381 	warn = true;
382 	if (!pin->Spare)
383 	  {
384 	    Message (_("Warning! Net \"%s\" is shorted to %s pin %s\n"),
385 		     &theNet->Name[2],
386 		     UNKNOWN (NAMEONPCB_NAME (element)),
387 		     UNKNOWN (pin->Number));
388 	    SET_FLAG (WARNFLAG, pin);
389 	    continue;
390 	  }
391 	newone = true;
392 	POINTER_LOOP (generic);
393 	{
394 	  if (*ptr == pin->Spare)
395 	    {
396 	      newone = false;
397 	      break;
398 	    }
399 	}
400 	END_LOOP;
401 	if (newone)
402 	  {
403 	    menu = GetPointerMemory (generic);
404 	    *menu = pin->Spare;
405 	    Message (_("Warning! Net \"%s\" is shorted to net \"%s\"\n"),
406 		     &theNet->Name[2],
407 		     &((LibraryMenuType *) (pin->Spare))->Name[2]);
408 	    SET_FLAG (WARNFLAG, pin);
409 	  }
410       }
411   }
412   ENDALL_LOOP;
413   ALLPAD_LOOP (PCB->Data);
414   {
415     if (TEST_FLAG (DRCFLAG, pad))
416       {
417 	warn = true;
418 	if (!pad->Spare)
419 	  {
420 	    Message (_("Warning! Net \"%s\" is shorted  to %s pad %s\n"),
421 		     &theNet->Name[2],
422 		     UNKNOWN (NAMEONPCB_NAME (element)),
423 		     UNKNOWN (pad->Number));
424 	    SET_FLAG (WARNFLAG, pad);
425 	    continue;
426 	  }
427 	newone = true;
428 	POINTER_LOOP (generic);
429 	{
430 	  if (*ptr == pad->Spare)
431 	    {
432 	      newone = false;
433 	      break;
434 	    }
435 	}
436 	END_LOOP;
437 	if (newone)
438 	  {
439 	    menu = GetPointerMemory (generic);
440 	    *menu = pad->Spare;
441 	    Message (_("Warning! Net \"%s\" is shorted to net \"%s\"\n"),
442 		     &theNet->Name[2],
443 		     &((LibraryMenuType *) (pad->Spare))->Name[2]);
444 	    SET_FLAG (WARNFLAG, pad);
445 	  }
446       }
447   }
448   ENDALL_LOOP;
449   FreePointerListMemory (generic);
450   free (generic);
451   return (warn);
452 }
453 
454 
455 /*!
456  * \brief Determine existing interconnections of the net and gather into
457  * sub-nets.
458  *
459  * Initially the netlist has each connection in its own individual net
460  * afterwards there can be many fewer nets with multiple connections
461  * each.
462  */
463 static bool
GatherSubnets(NetListType * Netl,bool NoWarn,bool AndRats)464 GatherSubnets (NetListType *Netl, bool NoWarn, bool AndRats)
465 {
466   NetType *a, *b;
467   ConnectionType *conn;
468   Cardinal m, n;
469   bool Warned = false;
470 
471   for (m = 0; Netl->NetN > 0 && m < Netl->NetN; m++)
472     {
473       a = &Netl->Net[m];
474       ClearFlagOnAllObjects (DRCFLAG, false);
475       RatFindHook (a->Connection[0].type, a->Connection[0].ptr1,
476                    a->Connection[0].ptr2, a->Connection[0].ptr2,
477                    false, DRCFLAG, AndRats);
478       /* now anybody connected to the first point has DRCFLAG set */
479       /* so move those to this subnet */
480       CLEAR_FLAG (DRCFLAG, (PinType *) a->Connection[0].ptr2);
481       for (n = m + 1; n < Netl->NetN; n++)
482 	{
483 	  b = &Netl->Net[n];
484 	  /* There can be only one connection in net b */
485 	  if (TEST_FLAG (DRCFLAG, (PinType *) b->Connection[0].ptr2))
486 	    {
487 	      CLEAR_FLAG (DRCFLAG, (PinType *) b->Connection[0].ptr2);
488 	      TransferNet (Netl, b, a);
489 	      /* back up since new subnet is now at old index */
490 	      n--;
491 	    }
492 	}
493       /* now add other possible attachment points to the subnet */
494       /* e.g. line end-points and vias */
495       /* don't add non-manhattan lines, the auto-router can't route to them */
496       ALLLINE_LOOP (PCB->Data);
497       {
498 	if (TEST_FLAG (DRCFLAG, line))
499 	  {
500 	    conn = GetConnectionMemory (a);
501 	    conn->X = line->Point1.X;
502 	    conn->Y = line->Point1.Y;
503 	    conn->type = LINE_TYPE;
504 	    conn->ptr1 = layer;
505 	    conn->ptr2 = line;
506 	    conn->group = GetLayerGroupNumberByPointer (layer);
507 	    conn->menu = NULL;	/* agnostic view of where it belongs */
508 	    conn = GetConnectionMemory (a);
509 	    conn->X = line->Point2.X;
510 	    conn->Y = line->Point2.Y;
511 	    conn->type = LINE_TYPE;
512 	    conn->ptr1 = layer;
513 	    conn->ptr2 = line;
514 	    conn->group = GetLayerGroupNumberByPointer (layer);
515 	    conn->menu = NULL;
516 	  }
517       }
518       ENDALL_LOOP;
519       /* add polygons so the auto-router can see them as targets */
520       ALLPOLYGON_LOOP (PCB->Data);
521       {
522 	if (TEST_FLAG (DRCFLAG, polygon))
523 	  {
524 	    conn = GetConnectionMemory (a);
525 	    /* make point on a vertex */
526 	    conn->X = polygon->Clipped->contours->head.point[0];
527 	    conn->Y = polygon->Clipped->contours->head.point[1];
528 	    conn->type = POLYGON_TYPE;
529 	    conn->ptr1 = layer;
530 	    conn->ptr2 = polygon;
531 	    conn->group = GetLayerGroupNumberByPointer (layer);
532 	    conn->menu = NULL;	/* agnostic view of where it belongs */
533 	  }
534       }
535       ENDALL_LOOP;
536       VIA_LOOP (PCB->Data);
537       {
538 	if (TEST_FLAG (DRCFLAG, via))
539 	  {
540 	    conn = GetConnectionMemory (a);
541 	    conn->X = via->X;
542 	    conn->Y = via->Y;
543 	    conn->type = VIA_TYPE;
544 	    conn->ptr1 = via;
545 	    conn->ptr2 = via;
546 	    conn->group = bottom_group;
547 	  }
548       }
549       END_LOOP;
550       if (!NoWarn)
551 	Warned |= CheckShorts (a->Connection[0].menu);
552     }
553   ClearFlagOnAllObjects (DRCFLAG, false);
554   return (Warned);
555 }
556 
557 /*!
558  * \brief Draw a rat net (tree) having the shortest lines.
559  *
560  * This also frees the subnet memory as they are consumed.
561  *
562  * \note The \c Netl we are passed is NOT the main netlist - it's the
563  * connectivity for ONE net.
564  * It represents the CURRENT connectivity state for the net, with each
565  * Netl->Net[N] representing one copper-connected subset of the net.
566  *
567  * Everything inside the NetList Netl should be connected together.
568  *
569  * Each Net in \c Netl is a group of Connections which are already
570  * connected together somehow, either by real wires or by rats we've
571  * already drawn.
572  *
573  * Each Connection is a vertex within that blob of connected items.
574  *
575  * This loop finds the closest vertex pairs between each blob and draws
576  * rats that merge the blobs until there's just one big blob.
577  *
578  * Just to clarify, with some examples:
579  *
580  * Each \c Netl is one full net from a netlist, like from gnetlist.
581  *
582  * Each Netl->Net[N] is a subset of that net that's already
583  * physically connected on the pcb.
584  *
585  * So a new design with no traces yet, would have a huge list of Net[N],
586  * each with one pin in it.
587  *
588  * A fully routed design would have one Net[N] with all the pins
589  * (for that net) in it.
590  */
591 static bool
DrawShortestRats(NetListType * Netl,void (* funcp)(register ConnectionType *,register ConnectionType *,register RouteStyleType *))592 DrawShortestRats (NetListType *Netl, void (*funcp) (register ConnectionType *, register ConnectionType *, register RouteStyleType *))
593 {
594   RatType *line;
595   register float distance, temp;
596   register ConnectionType *conn1, *conn2, *firstpoint, *secondpoint;
597   PolygonType *polygon;
598   bool changed = false;
599   bool havepoints;
600   Cardinal n, m, j;
601   NetType *next, *subnet, *theSubnet = NULL;
602 
603   /* This is just a sanity check, to make sure we're passed
604    * *something*.
605    */
606   if (!Netl || Netl->NetN < 1)
607     return false;
608 
609   /*
610    * We keep doing this do/while loop until everything's connected.
611    * I.e. once per rat we add.
612    */
613   distance = 0.0;
614   havepoints = true; /* so we run the loop at least once */
615   while (Netl->NetN > 1 && havepoints)
616     {
617       /* This is the top of the "find one rat" logic.  */
618       havepoints = false;
619       firstpoint = secondpoint = NULL;
620 
621       /* Test Net[0] vs Net[N] for N=1..max.  Find the shortest
622 	 distance between any two points in different blobs.  */
623       subnet = &Netl->Net[0];
624       for (j = 1; j < Netl->NetN; j++)
625 	{
626 	  /*
627 	   * Scan between Net[0] blob (subnet) and Net[N] blob (next).
628 	   * Note the shortest distance we find.
629 	   */
630 	  next = &Netl->Net[j];
631 	  for (n = subnet->ConnectionN - 1; n != -1; n--)
632 	    {
633 	      conn1 = &subnet->Connection[n];
634 	      for (m = next->ConnectionN - 1; m != -1; m--)
635 		{
636 		  conn2 = &next->Connection[m];
637 		  /*
638 		   * At this point, conn1 and conn2 are two pins in
639 		   * different blobs of the same net.  See how far
640 		   * apart they are, and if they're "closer" than what
641 		   * we already have.
642 		   */
643 
644 		  /*
645 		   * Prefer to connect Connections over polygons to the
646 		   * polygons (ie assume the user wants a via to a plane,
647 		   * not a daisy chain).  Further prefer to pick an existing
648 		   * via in the Net to make that connection.
649 		   */
650 		  if (conn1->type == POLYGON_TYPE &&
651 		      (polygon = (PolygonType *)conn1->ptr2) &&
652 		      !(distance == 0 &&
653 		        firstpoint && firstpoint->type == VIA_TYPE) &&
654 		      IsPointInPolygonIgnoreHoles (conn2->X, conn2->Y, polygon))
655 		    {
656 		      distance = 0;
657 		      firstpoint = conn2;
658 		      secondpoint = conn1;
659 		      theSubnet = next;
660 		      havepoints = true;
661 		    }
662 		  else if (conn2->type == POLYGON_TYPE &&
663 		      (polygon = (PolygonType *)conn2->ptr2) &&
664 		      !(distance == 0 &&
665 		        firstpoint && firstpoint->type == VIA_TYPE) &&
666 		      IsPointInPolygonIgnoreHoles (conn1->X, conn1->Y, polygon))
667 		    {
668 		      distance = 0;
669 		      firstpoint = conn1;
670 		      secondpoint = conn2;
671 		      theSubnet = next;
672 		      havepoints = true;
673 		    }
674 		  else if ((temp = SQUARE (conn1->X - conn2->X) +
675 		       SQUARE (conn1->Y - conn2->Y)) < distance || !firstpoint)
676 		    {
677 		      distance = temp;
678 		      firstpoint = conn1;
679 		      secondpoint = conn2;
680 		      theSubnet = next;
681 		      havepoints = true;
682 		    }
683 		}
684 	    }
685 	}
686 
687       /*
688        * If HAVEPOINTS is true, we've found a pair of points in two
689        * separate blobs of the net, and need to connect them together.
690        */
691       if (havepoints)
692 	{
693 	  if (funcp)
694 	    {
695 	      (*funcp) (firstpoint, secondpoint, subnet->Style);
696 	    }
697 	  else
698 	    {
699 	      /* found the shortest distance subnet, draw the rat */
700 	      if ((line = CreateNewRat (PCB->Data,
701 					firstpoint->X, firstpoint->Y,
702 					secondpoint->X, secondpoint->Y,
703 					firstpoint->group, secondpoint->group,
704 					Settings.RatThickness,
705 					NoFlags ())) != NULL)
706 		{
707 		  if (distance == 0)
708 		    SET_FLAG (VIAFLAG, line);
709 		  AddObjectToCreateUndoList (RATLINE_TYPE, line, line, line);
710 		  DrawRat (line);
711 		  changed = true;
712 		}
713 	    }
714 
715 	  /* copy theSubnet into the current subnet */
716 	  TransferNet (Netl, theSubnet, subnet);
717 	}
718     }
719 
720   /* presently nothing to do with the new subnet */
721   /* so we throw it away and free the space */
722   FreeNetMemory (&Netl->Net[--(Netl->NetN)]);
723   /* Sadly adding a rat line messes up the sorted arrays in connection finder */
724   /* hace: perhaps not necessarily now that they aren't stored in normal layers */
725   if (changed)
726     {
727       FreeConnectionLookupMemory ();
728       InitConnectionLookup ();
729     }
730   return (changed);
731 }
732 
733 
734 /*!
735  * \brief AddAllRats puts the rats nest into the layout from the loaded
736  * netlist.
737  *
738  * If SelectedOnly is true, it will only draw rats to selected pins and
739  * pads.
740  */
741 bool
AddAllRats(bool SelectedOnly,void (* funcp)(register ConnectionType *,register ConnectionType *,register RouteStyleType *))742 AddAllRats (bool SelectedOnly, void (*funcp) (register ConnectionType *, register ConnectionType *, register RouteStyleType *))
743 {
744   NetListType *Nets, *Wantlist;
745   NetType *lonesome;
746   ConnectionType *onepin;
747   bool changed, Warned = false;
748 
749   /* the netlist library has the text form
750    * ProcNetlist fills in the Netlist
751    * structure the way the final routing
752    * is supposed to look
753    */
754   Wantlist = ProcNetlist (&PCB->NetlistLib);
755   if (!Wantlist)
756     {
757       Message (_("Can't add rat lines because no netlist is loaded.\n"));
758       return (false);
759     }
760   changed = false;
761   /* initialize finding engine */
762   InitConnectionLookup ();
763   Nets = (NetListType *)calloc (1, sizeof (NetListType));
764   /* now we build another netlist (Nets) for each
765    * net in Wantlist that shows how it actually looks now,
766    * then fill in any missing connections with rat lines.
767    *
768    * we first assume each connection is separate
769    * (no routing), then gather them into groups
770    * if the net is all routed, the new netlist (Nets)
771    * will have only one net entry.
772    * Note that DrawShortestRats consumes all nets
773    * from Nets, so *Nets is empty after the
774    * DrawShortestRats call
775    */
776   NET_LOOP (Wantlist);
777   {
778     CONNECTION_LOOP (net);
779     {
780       if (!SelectedOnly
781 	  || TEST_FLAG (SELECTEDFLAG, (PinType *) connection->ptr2))
782 	{
783 	  lonesome = GetNetMemory (Nets);
784 	  onepin = GetConnectionMemory (lonesome);
785 	  *onepin = *connection;
786 	  lonesome->Style = net->Style;
787 	}
788     }
789     END_LOOP;
790     Warned |= GatherSubnets (Nets, SelectedOnly, true);
791     if (Nets->NetN > 0)
792       changed |= DrawShortestRats (Nets, funcp);
793   }
794   END_LOOP;
795   FreeNetListMemory (Nets);
796   free (Nets);
797   FreeConnectionLookupMemory ();
798   if (funcp)
799     return (true);
800 
801   if (Warned || changed)
802     Draw ();
803 
804   if (Warned)
805     Settings.RatWarn = true;
806 
807   if (changed)
808     {
809       IncrementUndoSerialNumber ();
810       if (PCB->Data->RatN > 0)
811 	{
812 	  Message ("%d rat line%s remaining\n", PCB->Data->RatN,
813 		   PCB->Data->RatN > 1 ? "s" : "");
814 	}
815       return (true);
816     }
817   if (!SelectedOnly && !Warned)
818     {
819       if (!PCB->Data->RatN && !badnet)
820 	Message (_("Congratulations!!\n"
821 		   "The layout is complete and has no shorted nets.\n"));
822       else
823 	Message (_("Nothing more to add, but there are\n"
824 		   "either rat-lines in the layout, disabled nets\n"
825 		   "in the net-list, or missing components\n"));
826     }
827   return (false);
828 }
829 
830 /*!
831  * \todo This is copied in large part from AddAllRats above; for
832  * maintainability, AddAllRats probably wants to be tweaked to use this
833  * version of the code so that we don't have duplication.
834  */
835 NetListListType
CollectSubnets(bool SelectedOnly)836 CollectSubnets (bool SelectedOnly)
837 {
838   NetListListType result = { 0, 0, NULL };
839   NetListType *Nets, *Wantlist;
840   NetType *lonesome;
841   ConnectionType *onepin;
842 
843   /* the netlist library has the text form
844    * ProcNetlist fills in the Netlist
845    * structure the way the final routing
846    * is supposed to look
847    */
848   Wantlist = ProcNetlist (&PCB->NetlistLib);
849   if (!Wantlist)
850     {
851       Message (_("Can't add rat lines because no netlist is loaded.\n"));
852       return result;
853     }
854   /* initialize finding engine */
855   InitConnectionLookup ();
856   /* now we build another netlist (Nets) for each
857    * net in Wantlist that shows how it actually looks now,
858    * then fill in any missing connections with rat lines.
859    *
860    * we first assume each connection is separate
861    * (no routing), then gather them into groups
862    * if the net is all routed, the new netlist (Nets)
863    * will have only one net entry.
864    * Note that DrawShortestRats consumes all nets
865    * from Nets, so *Nets is empty after the
866    * DrawShortestRats call
867    */
868   NET_LOOP (Wantlist);
869   {
870     Nets = GetNetListMemory (&result);
871     CONNECTION_LOOP (net);
872     {
873       if (!SelectedOnly
874 	  || TEST_FLAG (SELECTEDFLAG, (PinType *) connection->ptr2))
875 	{
876 	  lonesome = GetNetMemory (Nets);
877 	  onepin = GetConnectionMemory (lonesome);
878 	  *onepin = *connection;
879 	  lonesome->Style = net->Style;
880 	}
881     }
882     END_LOOP;
883     /* Note that AndRats is *FALSE* here! */
884     GatherSubnets (Nets, SelectedOnly, false);
885   }
886   END_LOOP;
887   FreeConnectionLookupMemory ();
888   return result;
889 }
890 
891 /*!
892  * \brief Check to see if a particular name is the name of an already
893  * existing rats line.
894  */
895 static int
rat_used(char * name)896 rat_used (char *name)
897 {
898   if (name == NULL)
899     return -1;
900 
901   MENU_LOOP (&PCB->NetlistLib);
902   {
903     if (menu->Name && (strcmp (menu->Name, name) == 0))
904       return 1;
905   }
906   END_LOOP;
907 
908   return 0;
909 }
910 
911 /*!
912  * \brief This function is moved from the original netlist.c as
913  * part of the gui code separation for the Gtk port.
914  */
915 RatType *
AddNet(void)916 AddNet (void)
917 {
918   static int ratDrawn = 0;
919   char name1[256], *name2;
920   Cardinal group1, group2;
921   char ratname[22];
922   int found;
923   void *ptr1, *ptr2, *ptr3;
924   LibraryMenuType *menu;
925   LibraryEntryType *entry;
926 
927   if (Crosshair.AttachedLine.Point1.X == Crosshair.AttachedLine.Point2.X
928       && Crosshair.AttachedLine.Point1.Y == Crosshair.AttachedLine.Point2.Y)
929     return (NULL);
930 
931   found = SearchObjectByLocation (PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3,
932 				  Crosshair.AttachedLine.Point1.X,
933 				  Crosshair.AttachedLine.Point1.Y, 5);
934   if (found == NO_TYPE)
935     {
936       Message (_("No pad/pin under rat line\n"));
937       return (NULL);
938     }
939   if (NAMEONPCB_NAME ((ElementType *) ptr1) == NULL
940       || *NAMEONPCB_NAME ((ElementType *) ptr1) == 0)
941     {
942       Message (_("You must name the starting element first\n"));
943       return (NULL);
944     }
945 
946   /* will work for pins to since the FLAG is common */
947   group1 = GetLayerGroupNumberBySide (
948             TEST_FLAG (ONSOLDERFLAG, (PadType *) ptr2) ? BOTTOM_SIDE : TOP_SIDE);
949   strcpy (name1, ConnectionName (found, ptr1, ptr2));
950   found = SearchObjectByLocation (PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3,
951 				  Crosshair.AttachedLine.Point2.X,
952 				  Crosshair.AttachedLine.Point2.Y, 5);
953   if (found == NO_TYPE)
954     {
955       Message (_("No pad/pin under rat line\n"));
956       return (NULL);
957     }
958   if (NAMEONPCB_NAME ((ElementType *) ptr1) == NULL
959       || *NAMEONPCB_NAME ((ElementType *) ptr1) == 0)
960     {
961       Message (_("You must name the ending element first\n"));
962       return (NULL);
963     }
964   group2 = GetLayerGroupNumberBySide (
965             TEST_FLAG (ONSOLDERFLAG, (PadType *) ptr2) ? BOTTOM_SIDE : TOP_SIDE);
966   name2 = ConnectionName (found, ptr1, ptr2);
967 
968   menu = netnode_to_netname (name1);
969   if (menu)
970     {
971       if (netnode_to_netname (name2))
972 	{
973 	  Message (_
974 		   ("Both connections already in netlist - cannot merge nets\n"));
975 	  return (NULL);
976 	}
977       entry = GetLibraryEntryMemory (menu);
978       entry->ListEntry = strdup (name2);
979       netnode_to_netname (name2);
980       goto ratIt;
981     }
982   /* ok, the first name did not belong to a net */
983   menu = netnode_to_netname (name2);
984   if (menu)
985     {
986       entry = GetLibraryEntryMemory (menu);
987       entry->ListEntry = strdup (name1);
988       netnode_to_netname (name1);
989       goto ratIt;
990     }
991 
992   /*
993    * neither belong to a net, so create a new one.
994    *
995    * before creating a new rats here, we need to search
996    * for a unique name.
997    */
998   sprintf (ratname, "  ratDrawn%i", ++ratDrawn);
999   while (rat_used (ratname))
1000     {
1001       sprintf (ratname, "  ratDrawn%i", ++ratDrawn);
1002     }
1003 
1004   menu = GetLibraryMenuMemory (&PCB->NetlistLib);
1005   menu->Name = strdup (ratname);
1006   entry = GetLibraryEntryMemory (menu);
1007   entry->ListEntry = strdup (name1);
1008   entry = GetLibraryEntryMemory (menu);
1009   entry->ListEntry = strdup (name2);
1010   menu->flag = 1;
1011 
1012 ratIt:
1013   NetlistChanged (0);
1014   return (CreateNewRat (PCB->Data, Crosshair.AttachedLine.Point1.X,
1015 			Crosshair.AttachedLine.Point1.Y,
1016 			Crosshair.AttachedLine.Point2.X,
1017 			Crosshair.AttachedLine.Point2.Y,
1018 			group1, group2, Settings.RatThickness, NoFlags ()));
1019 }
1020 
1021 /*!
1022  * \brief This function is moved from the original netlist.c as
1023  * part of the gui code separation for the Gtk port.
1024  */
1025 char *
ConnectionName(int type,void * ptr1,void * ptr2)1026 ConnectionName (int type, void *ptr1, void *ptr2)
1027 {
1028   static char name[256];
1029   char *num;
1030 
1031   switch (type)
1032     {
1033     case PIN_TYPE:
1034       num = ((PinType *) ptr2)->Number;
1035       break;
1036     case PAD_TYPE:
1037       num = ((PadType *) ptr2)->Number;
1038       break;
1039     default:
1040       return (NULL);
1041     }
1042   strcpy (name, UNKNOWN (NAMEONPCB_NAME ((ElementType *) ptr1)));
1043   strcat (name, "-");
1044   strcat (name, UNKNOWN (num));
1045   return (name);
1046 }
1047