Move internationalization macros to one header
[geda-pcb/gde.git] / src / rats.c
blobc174cc9ab6f8128aebd337cae4cef8f4e343cd2d
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
8 *
9 * This module, rats.c, was written and is Copyright (C) 1997 by harry eaton
10 * this module is also subject to the GNU GPL as described below
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 /* Change History:
29 * Started 6/10/97
30 * Added support for minimum length rat lines 6/13/97
31 * rat lines to nearest line/via 8/29/98
32 * support for netlist window 10/24/98
35 /* rats nest routines
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
41 #include <math.h>
42 #include <stdio.h>
44 #include "global.h"
46 #include "create.h"
47 #include "data.h"
48 #include "draw.h"
49 #include "error.h"
50 #include "file.h"
51 #include "find.h"
52 #include "misc.h"
53 #include "mymem.h"
54 #include "polygon.h"
55 #include "rats.h"
56 #include "search.h"
57 #include "set.h"
58 #include "undo.h"
60 #ifdef HAVE_LIBDMALLOC
61 #include <dmalloc.h>
62 #endif
64 RCSID ("$Id$");
67 #define TRIEDFIRST 0x1
68 #define BESTFOUND 0x2
70 /* ---------------------------------------------------------------------------
71 * some forward declarations
73 static Boolean FindPad (char *, char *, ConnectionType *, Boolean);
74 static Boolean ParseConnection (char *, char *, char *);
75 static Boolean DrawShortestRats (NetListTypePtr, void (*)());
76 static Boolean GatherSubnets (NetListTypePtr, Boolean, Boolean);
77 static Boolean CheckShorts (LibraryMenuTypePtr);
78 static void TransferNet (NetListTypePtr, NetTypePtr, NetTypePtr);
80 /* ---------------------------------------------------------------------------
81 * some local identifiers
83 static Boolean badnet = False;
84 static Cardinal SLayer, CLayer; /* layer group holding solder/component side */
86 /* ---------------------------------------------------------------------------
87 * parse a connection description from a string
88 * puts the element name in the string and the pin number in
89 * the number. If a valid connection is found, it returns the
90 * number of characters processed from the string, otherwise
91 * it returns 0
93 static Boolean
94 ParseConnection (char *InString, char *ElementName, char *PinNum)
96 int i, j;
98 /* copy element name portion */
99 for (j = 0; InString[j] != '\0' && InString[j] != '-'; j++)
100 ElementName[j] = InString[j];
101 if (InString[j] == '-')
103 for (i = j; i > 0 && ElementName[i - 1] >= 'a'; i--);
104 ElementName[i] = '\0';
105 for (i = 0, j++; InString[j] != '\0'; i++, j++)
106 PinNum[i] = InString[j];
107 PinNum[i] = '\0';
108 return (False);
110 else
112 ElementName[j] = '\0';
113 Message (_("Bad net-list format encountered near: \"%s\"\n"),
114 ElementName);
115 return (True);
119 /* ---------------------------------------------------------------------------
120 * Find a particular pad from an element name and pin number
122 static Boolean
123 FindPad (char *ElementName, char *PinNum, ConnectionType * conn, Boolean Same)
125 ElementTypePtr element;
126 Cardinal i;
128 if ((element = SearchElementByName (PCB->Data, ElementName)) != NULL)
130 for (i = 0; i < element->PadN; i++)
131 if (NSTRCMP (PinNum, element->Pad[i].Number) == 0 && (!Same
133 !TEST_FLAG
134 (DRCFLAG,
135 &element->
136 Pad[i])))
138 conn->type = PAD_TYPE;
139 conn->ptr2 = &element->Pad[i];
140 conn->group =
141 TEST_FLAG (ONSOLDERFLAG, &element->Pad[i]) ? SLayer : CLayer;
142 if (TEST_FLAG (EDGE2FLAG, &element->Pad[i]))
144 conn->X = element->Pad[i].Point2.X;
145 conn->Y = element->Pad[i].Point2.Y;
147 else
149 conn->X = element->Pad[i].Point1.X;
150 conn->Y = element->Pad[i].Point1.Y;
152 break;
154 if (i == element->PadN)
156 for (i = 0; i < element->PinN; i++)
157 if (!TEST_FLAG (HOLEFLAG, &element->Pin[i]) &&
158 element->Pin[i].Number &&
159 NSTRCMP (PinNum, element->Pin[i].Number) == 0 &&
160 (!Same || !TEST_FLAG (DRCFLAG, &element->Pin[i])))
162 conn->type = PIN_TYPE;
163 conn->ptr2 = &element->Pin[i];
164 conn->group = SLayer; /* any layer will do */
165 conn->X = element->Pin[i].X;
166 conn->Y = element->Pin[i].Y;
167 break;
169 if (i == element->PinN)
170 return (False);
172 conn->ptr1 = element;
173 return (True);
175 return (False);
178 /*--------------------------------------------------------------------------
179 * parse a netlist menu entry and locate the corresponding pad
180 * returns True if found, and fills in Connection information
182 Boolean
183 SeekPad (LibraryEntryType * entry, ConnectionType * conn, Boolean Same)
185 int j;
186 char ElementName[256];
187 char PinNum[256];
189 if (ParseConnection (entry->ListEntry, ElementName, PinNum))
190 return (False);
191 for (j = 0; PinNum[j] != '\0'; j++);
192 if (j == 0)
194 Message (_("Error! Netlist file is missing pin!\n"
195 "white space after \"%s-\"\n"), ElementName);
196 badnet = True;
198 else
200 if (FindPad (ElementName, PinNum, conn, Same))
201 return (True);
202 if (Same)
203 return (False);
204 if (PinNum[j - 1] < '0' || PinNum[j - 1] > '9')
206 Message ("WARNING! Pin number ending with '%c'"
207 " encountered in netlist file\n"
208 "Probably a bad netlist file format\n", PinNum[j - 1]);
211 Message (_("Can't find %s pin %s called for in netlist.\n"),
212 ElementName, PinNum);
213 return (False);
216 /* ---------------------------------------------------------------------------
217 * Read the library-netlist build a true Netlist structure
220 NetListTypePtr
221 ProcNetlist (LibraryTypePtr net_menu)
223 ConnectionTypePtr connection;
224 ConnectionType LastPoint;
225 NetTypePtr net;
226 static NetListTypePtr Wantlist = NULL;
228 if (!net_menu->MenuN)
229 return (NULL);
230 FreeNetListMemory (Wantlist);
231 SaveFree (Wantlist);
232 /* MYFREE (Wantlist); *//* awkward */
233 badnet = False;
235 /* find layer groups of the component side and solder side */
236 SLayer = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
237 CLayer = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
239 Wantlist = MyCalloc (1, sizeof (NetListType), "ProcNetlist()");
240 if (Wantlist)
242 ALLPIN_LOOP (PCB->Data);
244 pin->Spare = NULL;
245 CLEAR_FLAG (DRCFLAG, pin);
247 ENDALL_LOOP;
248 ALLPAD_LOOP (PCB->Data);
250 pad->Spare = NULL;
251 CLEAR_FLAG (DRCFLAG, pad);
253 ENDALL_LOOP;
254 MENU_LOOP (net_menu);
256 if (menu->Name[0] == '*' || menu->flag == 0)
258 badnet = True;
259 continue;
261 net = GetNetMemory (Wantlist);
262 if (menu->Style)
264 STYLE_LOOP (PCB);
266 if (style->Name && !NSTRCMP (style->Name, menu->Style))
268 net->Style = style;
269 break;
272 END_LOOP;
274 else /* default to NULL if none found */
275 net->Style = NULL;
276 ENTRY_LOOP (menu);
278 if (SeekPad (entry, &LastPoint, False))
280 if (TEST_FLAG (DRCFLAG, (PinTypePtr) LastPoint.ptr2))
281 Message (_
282 ("Error! Element %s pin %s appears multiple times in the netlist file.\n"),
283 NAMEONPCB_NAME ((ElementTypePtr) LastPoint.ptr1),
284 (LastPoint.type ==
285 PIN_TYPE) ? ((PinTypePtr) LastPoint.ptr2)->
286 Number : ((PadTypePtr) LastPoint.ptr2)->Number);
287 else
289 connection = GetConnectionMemory (net);
290 *connection = LastPoint;
291 /* indicate expect net */
292 connection->menu = menu;
293 /* mark as visited */
294 SET_FLAG (DRCFLAG, (PinTypePtr) LastPoint.ptr2);
295 if (LastPoint.type == PIN_TYPE)
296 ((PinTypePtr) LastPoint.ptr2)->Spare = (void *) menu;
297 else
298 ((PadTypePtr) LastPoint.ptr2)->Spare = (void *) menu;
301 else
302 badnet = True;
303 /* check for more pins with the same number */
304 for (; SeekPad (entry, &LastPoint, True);)
306 connection = GetConnectionMemory (net);
307 *connection = LastPoint;
308 /* indicate expect net */
309 connection->menu = menu;
310 /* mark as visited */
311 SET_FLAG (DRCFLAG, (PinTypePtr) LastPoint.ptr2);
312 if (LastPoint.type == PIN_TYPE)
313 ((PinTypePtr) LastPoint.ptr2)->Spare = (void *) menu;
314 else
315 ((PadTypePtr) LastPoint.ptr2)->Spare = (void *) menu;
318 END_LOOP;
320 END_LOOP;
322 /* clear all visit marks */
323 ALLPIN_LOOP (PCB->Data);
325 CLEAR_FLAG (DRCFLAG, pin);
327 ENDALL_LOOP;
328 ALLPAD_LOOP (PCB->Data);
330 CLEAR_FLAG (DRCFLAG, pad);
332 ENDALL_LOOP;
333 return (Wantlist);
337 * copy all connections from one net into another
338 * and then remove the first net from its netlist
340 static void
341 TransferNet (NetListTypePtr Netl, NetTypePtr SourceNet, NetTypePtr DestNet)
343 ConnectionTypePtr conn;
345 CONNECTION_LOOP (SourceNet);
347 conn = GetConnectionMemory (DestNet);
348 *conn = *connection;
350 END_LOOP;
351 DestNet->Style = SourceNet->Style;
352 /* free the connection memory */
353 FreeNetMemory (SourceNet);
354 /* remove SourceNet from its netlist */
355 *SourceNet = Netl->Net[--(Netl->NetN)];
356 /* zero out old garbage */
357 memset (&Netl->Net[Netl->NetN], 0, sizeof (NetType));
360 static Boolean
361 CheckShorts (LibraryMenuTypePtr theNet)
363 Boolean new, warn = False;
364 PointerListTypePtr generic = MyCalloc (1, sizeof (PointerListType),
365 "CheckShorts");
366 /* the first connection was starting point so
367 * the menu is always non-null
369 void **menu = GetPointerMemory (generic);
371 *menu = theNet;
372 ALLPIN_LOOP (PCB->Data);
374 if (TEST_FLAG (DRCFLAG, pin))
376 warn = True;
377 if (!pin->Spare)
379 Message (_("Warning! Net \"%s\" is shorted to %s pin %s\n"),
380 &theNet->Name[2],
381 UNKNOWN (NAMEONPCB_NAME (element)),
382 UNKNOWN (pin->Number));
383 SET_FLAG (WARNFLAG, pin);
384 continue;
386 new = True;
387 POINTER_LOOP (generic);
389 if (*ptr == pin->Spare)
391 new = False;
392 break;
395 END_LOOP;
396 if (new)
398 menu = GetPointerMemory (generic);
399 *menu = pin->Spare;
400 Message (_("Warning! net \"%s\" is shorted to net \"%s\"\n"),
401 &theNet->Name[2],
402 &((LibraryMenuTypePtr) (pin->Spare))->Name[2]);
403 SET_FLAG (WARNFLAG, pin);
407 ENDALL_LOOP;
408 ALLPAD_LOOP (PCB->Data);
410 if (TEST_FLAG (DRCFLAG, pad))
412 warn = True;
413 if (!pad->Spare)
415 Message (_("Warning! Net \"%s\" is shorted to %s pad %s\n"),
416 &theNet->Name[2],
417 UNKNOWN (NAMEONPCB_NAME (element)),
418 UNKNOWN (pad->Number));
419 SET_FLAG (WARNFLAG, pad);
420 continue;
422 new = True;
423 POINTER_LOOP (generic);
425 if (*ptr == pad->Spare)
427 new = False;
428 break;
431 END_LOOP;
432 if (new)
434 menu = GetPointerMemory (generic);
435 *menu = pad->Spare;
436 Message (_("Warning! Net \"%s\" is shorted to net \"%s\"\n"),
437 &theNet->Name[2],
438 &((LibraryMenuTypePtr) (pad->Spare))->Name[2]);
439 SET_FLAG (WARNFLAG, pad);
443 ENDALL_LOOP;
444 FreePointerListMemory (generic);
445 SaveFree (generic);
446 return (warn);
450 /* ---------------------------------------------------------------------------
451 * Determine existing interconnections of the net and gather into sub-nets
453 * initially the netlist has each connection in its own individual net
454 * afterwards there can be many fewer nets with multiple connections each
456 static Boolean
457 GatherSubnets (NetListTypePtr Netl, Boolean NoWarn, Boolean AndRats)
459 NetTypePtr a, b;
460 ConnectionTypePtr conn;
461 Cardinal m, n;
462 Boolean Warned = False;
464 for (m = 0; Netl->NetN > 0 && m < Netl->NetN; m++)
466 a = &Netl->Net[m];
467 ResetFoundPinsViasAndPads (False);
468 ResetFoundLinesAndPolygons (False);
469 RatFindHook (a->Connection[0].type, a->Connection[0].ptr1,
470 a->Connection[0].ptr2, a->Connection[0].ptr2, False,
471 AndRats);
472 /* now anybody connected to the first point has DRCFLAG set */
473 /* so move those to this subnet */
474 CLEAR_FLAG (DRCFLAG, (PinTypePtr) a->Connection[0].ptr2);
475 for (n = m + 1; n < Netl->NetN; n++)
477 b = &Netl->Net[n];
478 /* There can be only one connection in net b */
479 if (TEST_FLAG (DRCFLAG, (PinTypePtr) b->Connection[0].ptr2))
481 CLEAR_FLAG (DRCFLAG, (PinTypePtr) b->Connection[0].ptr2);
482 TransferNet (Netl, b, a);
483 /* back up since new subnet is now at old index */
484 n--;
487 /* now add other possible attachment points to the subnet */
488 /* e.g. line end-points and vias */
489 /* don't add non-manhattan lines, the auto-router can't route to them */
490 ALLLINE_LOOP (PCB->Data);
492 if (TEST_FLAG (DRCFLAG, line)
493 && ((line->Point1.X == line->Point2.X)
494 || (line->Point1.Y == line->Point2.Y)))
496 conn = GetConnectionMemory (a);
497 conn->X = line->Point1.X;
498 conn->Y = line->Point1.Y;
499 conn->type = LINE_TYPE;
500 conn->ptr1 = layer;
501 conn->ptr2 = line;
502 conn->group = GetLayerGroupNumberByPointer (layer);
503 conn->menu = NULL; /* agnostic view of where it belongs */
504 conn = GetConnectionMemory (a);
505 conn->X = line->Point2.X;
506 conn->Y = line->Point2.Y;
507 conn->type = LINE_TYPE;
508 conn->ptr1 = layer;
509 conn->ptr2 = line;
510 conn->group = GetLayerGroupNumberByPointer (layer);
511 conn->menu = NULL;
514 ENDALL_LOOP;
515 /* add polygons so the auto-router can see them as targets */
516 ALLPOLYGON_LOOP (PCB->Data);
518 if (TEST_FLAG (DRCFLAG, polygon))
520 conn = GetConnectionMemory (a);
521 /* make point on a vertex */
522 conn->X = polygon->Clipped->contours->head.point[0];
523 conn->Y = polygon->Clipped->contours->head.point[1];
524 conn->type = POLYGON_TYPE;
525 conn->ptr1 = layer;
526 conn->ptr2 = polygon;
527 conn->group = GetLayerGroupNumberByPointer (layer);
528 conn->menu = NULL; /* agnostic view of where it belongs */
531 ENDALL_LOOP;
532 VIA_LOOP (PCB->Data);
534 if (TEST_FLAG (DRCFLAG, via))
536 conn = GetConnectionMemory (a);
537 conn->X = via->X;
538 conn->Y = via->Y;
539 conn->type = VIA_TYPE;
540 conn->ptr1 = via;
541 conn->ptr2 = via;
542 conn->group = SLayer;
545 END_LOOP;
546 if (!NoWarn)
547 Warned |= CheckShorts (a->Connection[0].menu);
549 ResetFoundPinsViasAndPads (False);
550 ResetFoundLinesAndPolygons (False);
551 return (Warned);
554 /* ---------------------------------------------------------------------------
555 * Draw a rat net (tree) having the shortest lines
556 * this also frees the subnet memory as they are consumed
559 static Boolean
560 DrawShortestRats (NetListTypePtr Netl, void (*funcp) ())
562 RatTypePtr line;
563 register float distance, temp;
564 register ConnectionTypePtr conn1, conn2, firstpoint, secondpoint;
565 PolygonTypePtr polygon;
566 Boolean changed = False;
567 Cardinal n, m, j;
568 NetTypePtr next, subnet, theSubnet = NULL;
571 * Everything inside the NetList Netl should be connected together.
572 * Each Net in Netl is a group of Connections which are already
573 * connected together somehow, either by real wires or by rats we've
574 * already drawn. Each Connection is a vertex within that blob of
575 * connected items. This loop finds the closest vertex pairs between
576 * each blob and draws rats that merge the blobs until there's just
577 * one big blob.
579 distance = 0.0;
580 while (Netl->NetN > 1)
582 firstpoint = secondpoint = NULL;
583 subnet = &Netl->Net[0];
584 for (j = 1; j < Netl->NetN; j++)
586 next = &Netl->Net[j];
587 for (n = subnet->ConnectionN - 1; n != -1; n--)
589 conn1 = &subnet->Connection[n];
590 for (m = next->ConnectionN - 1; m != -1; m--)
592 conn2 = &next->Connection[m];
594 * Prefer to connect Connections over polygons to the
595 * polygons (ie assume the user wants a via to a plane,
596 * not a daisy chain). Further prefer to pick an existing
597 * via in the Net to make that connection.
599 if (conn1->type == POLYGON_TYPE &&
600 (polygon = (PolygonTypePtr)conn1->ptr2) &&
601 !(distance == 0 &&
602 firstpoint && firstpoint->type == VIA_TYPE) &&
603 IsPointInPolygonIgnoreHoles (conn2->X, conn2->Y, polygon))
605 distance = 0;
606 firstpoint = conn2;
607 secondpoint = conn1;
608 theSubnet = next;
610 else if (conn2->type == POLYGON_TYPE &&
611 (polygon = (PolygonTypePtr)conn2->ptr2) &&
612 !(distance == 0 &&
613 firstpoint && firstpoint->type == VIA_TYPE) &&
614 IsPointInPolygonIgnoreHoles (conn1->X, conn1->Y, polygon))
616 distance = 0;
617 firstpoint = conn1;
618 secondpoint = conn2;
619 theSubnet = next;
621 else if ((temp = SQUARE (conn1->X - conn2->X) +
622 SQUARE (conn1->Y - conn2->Y)) < distance || !firstpoint)
624 distance = temp;
625 firstpoint = conn1;
626 secondpoint = conn2;
627 theSubnet = next;
632 if (funcp)
634 (*funcp) (firstpoint, secondpoint, subnet->Style);
636 else
638 /* found the shortest distance subnet, draw the rat */
639 if ((line = CreateNewRat (PCB->Data,
640 firstpoint->X, firstpoint->Y,
641 secondpoint->X, secondpoint->Y,
642 firstpoint->group, secondpoint->group,
643 Settings.RatThickness,
644 NoFlags ())) != NULL)
646 if (distance == 0)
647 SET_FLAG (VIAFLAG, line);
648 AddObjectToCreateUndoList (RATLINE_TYPE, line, line, line);
649 DrawRat (line, 0);
650 changed = True;
654 /* copy theSubnet into the current subnet */
655 TransferNet (Netl, theSubnet, subnet);
657 /* presently nothing to do with the new subnet */
658 /* so we throw it away and free the space */
659 FreeNetMemory (&Netl->Net[--(Netl->NetN)]);
660 /* Sadly adding a rat line messes up the sorted arrays in connection finder */
661 /* hace: perhaps not necessarily now that they aren't stored in normal layers */
662 if (changed)
664 FreeConnectionLookupMemory ();
665 InitConnectionLookup ();
667 return (changed);
671 /* ---------------------------------------------------------------------------
672 * AddAllRats puts the rats nest into the layout from the loaded netlist
673 * if SelectedOnly is true, it will only draw rats to selected pins and pads
675 Boolean
676 AddAllRats (Boolean SelectedOnly, void (*funcp) ())
678 NetListTypePtr Nets, Wantlist;
679 NetTypePtr lonesome;
680 ConnectionTypePtr onepin;
681 Boolean changed, Warned = False;
683 /* the netlist library has the text form
684 * ProcNetlist fills in the Netlist
685 * structure the way the final routing
686 * is supposed to look
688 Wantlist = ProcNetlist (&PCB->NetlistLib);
689 if (!Wantlist)
691 Message (_("Can't add rat lines because no netlist is loaded.\n"));
692 return (False);
694 changed = False;
695 /* initialize finding engine */
696 InitConnectionLookup ();
697 SaveFindFlag (DRCFLAG);
698 Nets = MyCalloc (1, sizeof (NetListType), "AddAllRats()");
699 /* now we build another netlist (Nets) for each
700 * net in Wantlist that shows how it actually looks now,
701 * then fill in any missing connections with rat lines.
703 * we first assume each connection is separate
704 * (no routing), then gather them into groups
705 * if the net is all routed, the new netlist (Nets)
706 * will have only one net entry.
707 * Note that DrawShortestRats consumes all nets
708 * from Nets, so *Nets is empty after the
709 * DrawShortestRats call
711 NET_LOOP (Wantlist);
713 CONNECTION_LOOP (net);
715 if (!SelectedOnly
716 || TEST_FLAG (SELECTEDFLAG, (PinTypePtr) connection->ptr2))
718 lonesome = GetNetMemory (Nets);
719 onepin = GetConnectionMemory (lonesome);
720 *onepin = *connection;
721 lonesome->Style = net->Style;
724 END_LOOP;
725 Warned |= GatherSubnets (Nets, SelectedOnly, True);
726 if (Nets->NetN > 0)
727 changed |= DrawShortestRats (Nets, funcp);
729 END_LOOP;
730 FreeNetListMemory (Nets);
731 MYFREE (Nets);
732 FreeConnectionLookupMemory ();
733 RestoreFindFlag ();
734 if (funcp)
735 return (True);
737 if (Warned || changed)
738 Draw ();
740 if (Warned)
741 Settings.RatWarn = True;
743 if (changed)
745 IncrementUndoSerialNumber ();
746 if (PCB->Data->RatN > 0)
748 Message ("%d rat line%s remaining\n", PCB->Data->RatN,
749 PCB->Data->RatN > 1 ? "s" : "");
751 return (True);
753 if (!SelectedOnly && !Warned)
755 if (!PCB->Data->RatN && !badnet)
756 Message (_("Congratulations!!\n"
757 "The layout is complete and has no shorted nets.\n"));
758 else
759 Message (_("Nothing more to add, but there are\n"
760 "either rat-lines in the layout, disabled nets\n"
761 "in the net-list, or missing components\n"));
763 return (False);
766 /* XXX: This is copied in large part from AddAllRats above; for
767 * maintainability, AddAllRats probably wants to be tweaked to use this
768 * version of the code so that we don't have duplication. */
769 NetListListType
770 CollectSubnets (Boolean SelectedOnly)
772 NetListListType result = { 0, 0, NULL };
773 NetListTypePtr Nets, Wantlist;
774 NetTypePtr lonesome;
775 ConnectionTypePtr onepin;
777 /* the netlist library has the text form
778 * ProcNetlist fills in the Netlist
779 * structure the way the final routing
780 * is supposed to look
782 Wantlist = ProcNetlist (&PCB->NetlistLib);
783 if (!Wantlist)
785 Message (_("Can't add rat lines because no netlist is loaded.\n"));
786 return result;
788 /* initialize finding engine */
789 InitConnectionLookup ();
790 SaveFindFlag (DRCFLAG);
791 /* now we build another netlist (Nets) for each
792 * net in Wantlist that shows how it actually looks now,
793 * then fill in any missing connections with rat lines.
795 * we first assume each connection is separate
796 * (no routing), then gather them into groups
797 * if the net is all routed, the new netlist (Nets)
798 * will have only one net entry.
799 * Note that DrawShortestRats consumes all nets
800 * from Nets, so *Nets is empty after the
801 * DrawShortestRats call
803 NET_LOOP (Wantlist);
805 Nets = GetNetListMemory (&result);
806 CONNECTION_LOOP (net);
808 if (!SelectedOnly
809 || TEST_FLAG (SELECTEDFLAG, (PinTypePtr) connection->ptr2))
811 lonesome = GetNetMemory (Nets);
812 onepin = GetConnectionMemory (lonesome);
813 *onepin = *connection;
814 lonesome->Style = net->Style;
817 END_LOOP;
818 /* Note that AndRats is *FALSE* here! */
819 GatherSubnets (Nets, SelectedOnly, False);
821 END_LOOP;
822 FreeConnectionLookupMemory ();
823 RestoreFindFlag ();
824 return result;
828 * Check to see if a particular name is the name of an already existing rats
829 * line
831 static int
832 rat_used (char *name)
834 if (name == NULL)
835 return -1;
837 MENU_LOOP (&PCB->NetlistLib);
839 if (menu->Name && (strcmp (menu->Name, name) == 0))
840 return 1;
842 END_LOOP;
844 return 0;
847 /* These next two functions moved from the original netlist.c as part of the
848 | gui code separation for the Gtk port.
850 RatTypePtr
851 AddNet (void)
853 static int ratDrawn = 0;
854 char name1[256], *name2;
855 Cardinal group1, group2;
856 char ratname[20];
857 int found;
858 void *ptr1, *ptr2, *ptr3;
859 LibraryMenuTypePtr menu;
860 LibraryEntryTypePtr entry;
862 if (Crosshair.AttachedLine.Point1.X == Crosshair.AttachedLine.Point2.X
863 && Crosshair.AttachedLine.Point1.Y == Crosshair.AttachedLine.Point2.Y)
864 return (NULL);
866 found = SearchObjectByLocation (PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3,
867 Crosshair.AttachedLine.Point1.X,
868 Crosshair.AttachedLine.Point1.Y, 5);
869 if (found == NO_TYPE)
871 Message (_("No pad/pin under rat line\n"));
872 return (NULL);
874 if (NAMEONPCB_NAME ((ElementTypePtr) ptr1) == NULL
875 || *NAMEONPCB_NAME ((ElementTypePtr) ptr1) == 0)
877 Message (_("You must name the starting element first\n"));
878 return (NULL);
881 /* will work for pins to since the FLAG is common */
882 group1 = (TEST_FLAG (ONSOLDERFLAG, (PadTypePtr) ptr2) ?
883 GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER) :
884 GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER));
885 strcpy (name1, ConnectionName (found, ptr1, ptr2));
886 found = SearchObjectByLocation (PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3,
887 Crosshair.AttachedLine.Point2.X,
888 Crosshair.AttachedLine.Point2.Y, 5);
889 if (found == NO_TYPE)
891 Message (_("No pad/pin under rat line\n"));
892 return (NULL);
894 if (NAMEONPCB_NAME ((ElementTypePtr) ptr1) == NULL
895 || *NAMEONPCB_NAME ((ElementTypePtr) ptr1) == 0)
897 Message (_("You must name the ending element first\n"));
898 return (NULL);
900 group2 = (TEST_FLAG (ONSOLDERFLAG, (PadTypePtr) ptr2) ?
901 GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER) :
902 GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER));
903 name2 = ConnectionName (found, ptr1, ptr2);
905 menu = netnode_to_netname (name1);
906 if (menu)
908 if (netnode_to_netname (name2))
910 Message (_
911 ("Both connections already in netlist - cannot merge nets\n"));
912 return (NULL);
914 entry = GetLibraryEntryMemory (menu);
915 entry->ListEntry = MyStrdup (name2, "AddNet");
916 netnode_to_netname (name2);
917 goto ratIt;
919 /* ok, the first name did not belong to a net */
920 menu = netnode_to_netname (name2);
921 if (menu)
923 entry = GetLibraryEntryMemory (menu);
924 entry->ListEntry = MyStrdup (name1, "AddNet");
925 netnode_to_netname (name1);
926 goto ratIt;
930 * neither belong to a net, so create a new one.
932 * before creating a new rats here, we need to search
933 * for a unique name.
935 sprintf (ratname, " ratDrawn%i", ++ratDrawn);
936 while (rat_used (ratname))
938 sprintf (ratname, " ratDrawn%i", ++ratDrawn);
941 menu = GetLibraryMenuMemory (&PCB->NetlistLib);
942 menu->Name = MyStrdup (ratname, "AddNet");
943 entry = GetLibraryEntryMemory (menu);
944 entry->ListEntry = MyStrdup (name1, "AddNet");
945 entry = GetLibraryEntryMemory (menu);
946 entry->ListEntry = MyStrdup (name2, "AddNet");
947 menu->flag = 1;
949 ratIt:
950 NetlistChanged (0);
951 return (CreateNewRat (PCB->Data, Crosshair.AttachedLine.Point1.X,
952 Crosshair.AttachedLine.Point1.Y,
953 Crosshair.AttachedLine.Point2.X,
954 Crosshair.AttachedLine.Point2.Y,
955 group1, group2, Settings.RatThickness, NoFlags ()));
959 char *
960 ConnectionName (int type, void *ptr1, void *ptr2)
962 static char name[256];
963 char *num;
965 switch (type)
967 case PIN_TYPE:
968 num = ((PinTypePtr) ptr2)->Number;
969 break;
970 case PAD_TYPE:
971 num = ((PadTypePtr) ptr2)->Number;
972 break;
973 default:
974 return (NULL);
976 strcpy (name, UNKNOWN (NAMEONPCB_NAME ((ElementTypePtr) ptr1)));
977 strcat (name, "-");
978 strcat (name, UNKNOWN (num));
979 return (name);