4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996,1997,1998,1999 Thomas Nau
7 * This module, report.c, was written and is Copyright (C) 1997 harry eaton
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
37 #include "crosshair.h"
51 #include "pcb-printf.h"
60 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
64 #ifdef HAVE_LIBDMALLOC
68 #define USER_UNITMASK (Settings.grid_unit->allow)
71 ReportDrills (int argc
, char **argv
, Coord x
, Coord y
)
73 DrillInfoTypePtr AllDrills
;
75 char *stringlist
, *thestring
;
78 AllDrills
= GetDrillInfo (PCB
->Data
);
79 RoundDrillInfo (AllDrills
, 100);
81 for (n
= 0; n
< AllDrills
->DrillN
; n
++)
83 total_drills
+= AllDrills
->Drill
[n
].PinCount
;
84 total_drills
+= AllDrills
->Drill
[n
].ViaCount
;
85 total_drills
+= AllDrills
->Drill
[n
].UnplatedCount
;
88 stringlist
= (char *)malloc (512L + AllDrills
->DrillN
* 64L);
90 /* Use tabs for formatting since can't count on a fixed font anymore.
91 | And even that probably isn't going to work in all cases.
94 "There are %d different drill sizes used in this layout, %d holes total\n\n"
95 "Drill Diam. (%s)\t# of Pins\t# of Vias\t# of Elements\t# Unplated\n",
96 AllDrills
->DrillN
, total_drills
, Settings
.grid_unit
->suffix
);
97 thestring
= stringlist
;
98 while (*thestring
!= '\0')
100 for (n
= 0; n
< AllDrills
->DrillN
; n
++)
102 pcb_sprintf (thestring
,
103 "%10m*\t\t%d\t\t%d\t\t%d\t\t%d\n",
104 Settings
.grid_unit
->suffix
,
105 AllDrills
->Drill
[n
].DrillSize
,
106 AllDrills
->Drill
[n
].PinCount
, AllDrills
->Drill
[n
].ViaCount
,
107 AllDrills
->Drill
[n
].ElementN
,
108 AllDrills
->Drill
[n
].UnplatedCount
);
109 while (*thestring
!= '\0')
112 FreeDrillInfo (AllDrills
);
113 /* create dialog box */
114 gui
->report_dialog ("Drill Report", stringlist
);
121 static const char reportdialog_syntax
[] = "ReportDialog()";
123 static const char reportdialog_help
[] =
124 "Report on the object under the crosshair";
126 /* %start-doc actions ReportDialog
128 This is a shortcut for @code{Report(Object)}.
133 ReportDialog (int argc
, char **argv
, Coord x
, Coord y
)
135 void *ptr1
, *ptr2
, *ptr3
;
139 type
= SearchScreen (x
, y
, REPORT_TYPES
, &ptr1
, &ptr2
, &ptr3
);
142 SearchScreen (x
, y
, REPORT_TYPES
| LOCKED_TYPE
, &ptr1
, &ptr2
, &ptr3
);
150 if (gui
->shift_is_pressed ())
152 __r_dump_tree (PCB
->Data
->via_tree
->root
, 0);
156 via
= (PinTypePtr
) ptr2
;
157 if (TEST_FLAG (HOLEFLAG
, via
))
158 pcb_sprintf (&report
[0], "%m+VIA ID# %ld; Flags:%s\n"
160 "It is a pure hole of diameter %$mS.\n"
162 "%s", USER_UNITMASK
, via
->ID
, flags_to_string (via
->Flags
, VIA_TYPE
),
163 via
->X
, via
->Y
, via
->DrillingHole
, EMPTY (via
->Name
),
164 TEST_FLAG (LOCKFLAG
, via
) ? "It is LOCKED.\n" : "");
166 pcb_sprintf (&report
[0], "%m+VIA ID# %ld; Flags:%s\n"
168 "Copper width = %$mS. Drill width = %$mS.\n"
169 "Clearance width in polygons = %$mS.\n"
171 "Solder mask hole = %$mS (gap = %$mS).\n"
173 "%s", USER_UNITMASK
, via
->ID
, flags_to_string (via
->Flags
, VIA_TYPE
),
178 (via
->Thickness
- via
->DrillingHole
) / 2,
180 (via
->Mask
- via
->Thickness
) / 2,
181 EMPTY (via
->Name
), TEST_FLAG (LOCKFLAG
, via
) ?
182 "It is LOCKED.\n" : "");
188 ElementTypePtr element
;
190 if (gui
->shift_is_pressed ())
192 __r_dump_tree (PCB
->Data
->pin_tree
->root
, 0);
196 Pin
= (PinTypePtr
) ptr2
;
197 element
= (ElementTypePtr
) ptr1
;
205 if (TEST_FLAG (HOLEFLAG
, Pin
))
206 pcb_sprintf (&report
[0], "%m+PIN ID# %ld; Flags:%s\n"
208 "It is a mounting hole. Drill width = %$mS.\n"
209 "It is owned by element %$mS.\n"
210 "%s", USER_UNITMASK
, Pin
->ID
, flags_to_string (Pin
->Flags
, PIN_TYPE
),
211 Pin
->X
, Pin
->Y
, Pin
->DrillingHole
,
212 EMPTY (element
->Name
[1].TextString
),
213 TEST_FLAG (LOCKFLAG
, Pin
) ? "It is LOCKED.\n" : "");
215 pcb_sprintf (&report
[0],
216 "%m+PIN ID# %ld; Flags:%s\n" "(X,Y) = %$mD.\n"
217 "Copper width = %$mS. Drill width = %$mS.\n"
218 "Clearance width to Polygon = %$mS.\n"
220 "Solder mask hole = %$mS (gap = %$mS).\n"
222 "It is owned by element %s\n as pin number %s.\n"
224 Pin
->ID
, flags_to_string (Pin
->Flags
, PIN_TYPE
),
225 Pin
->X
, Pin
->Y
, Pin
->Thickness
,
228 (Pin
->Thickness
- Pin
->DrillingHole
) / 2,
230 (Pin
->Mask
- Pin
->Thickness
) / 2,
232 EMPTY (element
->Name
[1].TextString
), EMPTY (Pin
->Number
),
233 TEST_FLAG (LOCKFLAG
, Pin
) ? "It is LOCKED.\n" : "");
240 if (gui
->shift_is_pressed ())
242 LayerTypePtr layer
= (LayerTypePtr
) ptr1
;
243 __r_dump_tree (layer
->line_tree
->root
, 0);
247 line
= (LineTypePtr
) ptr2
;
248 pcb_sprintf (&report
[0], "%m+LINE ID# %ld; Flags:%s\n"
249 "FirstPoint(X,Y) = %$mD, ID = %ld.\n"
250 "SecondPoint(X,Y) = %$mD, ID = %ld.\n"
251 "Width = %$mS.\nClearance width in polygons = %$mS.\n"
252 "It is on layer %d\n"
253 "and has name \"%s\".\n"
255 line
->ID
, flags_to_string (line
->Flags
, LINE_TYPE
),
256 line
->Point1
.X
, line
->Point1
.Y
, line
->Point1
.ID
,
257 line
->Point2
.X
, line
->Point2
.Y
, line
->Point2
.ID
,
258 line
->Thickness
, line
->Clearance
/ 2,
259 GetLayerNumber (PCB
->Data
, (LayerTypePtr
) ptr1
),
260 UNKNOWN (line
->Number
),
261 TEST_FLAG (LOCKFLAG
, line
) ? "It is LOCKED.\n" : "");
268 if (gui
->shift_is_pressed ())
270 __r_dump_tree (PCB
->Data
->rat_tree
->root
, 0);
274 line
= (RatTypePtr
) ptr2
;
275 pcb_sprintf (&report
[0], "%m+RAT-LINE ID# %ld; Flags:%s\n"
276 "FirstPoint(X,Y) = %$mD; ID = %ld; "
277 "connects to layer group %d.\n"
278 "SecondPoint(X,Y) = %$mD; ID = %ld; "
279 "connects to layer group %d.\n",
280 USER_UNITMASK
, line
->ID
, flags_to_string (line
->Flags
, LINE_TYPE
),
281 line
->Point1
.X
, line
->Point1
.Y
,
282 line
->Point1
.ID
, line
->group1
,
283 line
->Point2
.X
, line
->Point2
.Y
,
284 line
->Point2
.ID
, line
->group2
);
292 if (gui
->shift_is_pressed ())
294 LayerTypePtr layer
= (LayerTypePtr
) ptr1
;
295 __r_dump_tree (layer
->arc_tree
->root
, 0);
299 Arc
= (ArcTypePtr
) ptr2
;
300 box
= GetArcEnds (Arc
);
302 pcb_sprintf (&report
[0], "%m+ARC ID# %ld; Flags:%s\n"
303 "CenterPoint(X,Y) = %$mD.\n"
304 "Radius = %$mS, Thickness = %$mS.\n"
305 "Clearance width in polygons = %$mS.\n"
306 "StartAngle = %ma degrees, DeltaAngle = %ma degrees.\n"
307 "Bounding Box is %$mD, %$mD.\n"
308 "That makes the end points at %$mD and %$mD.\n"
309 "It is on layer %d.\n"
310 "%s", USER_UNITMASK
, Arc
->ID
, flags_to_string (Arc
->Flags
, ARC_TYPE
),
312 Arc
->Width
, Arc
->Thickness
,
313 Arc
->Clearance
/ 2, Arc
->StartAngle
, Arc
->Delta
,
314 Arc
->BoundingBox
.X1
, Arc
->BoundingBox
.Y1
,
315 Arc
->BoundingBox
.X2
, Arc
->BoundingBox
.Y2
,
318 GetLayerNumber (PCB
->Data
, (LayerTypePtr
) ptr1
),
319 TEST_FLAG (LOCKFLAG
, Arc
) ? "It is LOCKED.\n" : "");
324 PolygonTypePtr Polygon
;
326 if (gui
->shift_is_pressed ())
328 LayerTypePtr layer
= (LayerTypePtr
) ptr1
;
329 __r_dump_tree (layer
->polygon_tree
->root
, 0);
333 Polygon
= (PolygonTypePtr
) ptr2
;
335 pcb_sprintf (&report
[0], "%m+POLYGON ID# %ld; Flags:%s\n"
336 "Its bounding box is %$mD %$mD.\n"
337 "It has %d points and could store %d more\n"
338 " without using more memory.\n"
339 "It has %d holes and resides on layer %d.\n"
340 "%s", USER_UNITMASK
, Polygon
->ID
,
341 flags_to_string (Polygon
->Flags
, POLYGON_TYPE
),
342 Polygon
->BoundingBox
.X1
, Polygon
->BoundingBox
.Y1
,
343 Polygon
->BoundingBox
.X2
, Polygon
->BoundingBox
.Y2
,
344 Polygon
->PointN
, Polygon
->PointMax
- Polygon
->PointN
,
346 GetLayerNumber (PCB
->Data
, (LayerTypePtr
) ptr1
),
347 TEST_FLAG (LOCKFLAG
, Polygon
) ? "It is LOCKED.\n" : "");
354 ElementTypePtr element
;
356 if (gui
->shift_is_pressed ())
358 __r_dump_tree (PCB
->Data
->pad_tree
->root
, 0);
362 Pad
= (PadTypePtr
) ptr2
;
363 element
= (ElementTypePtr
) ptr1
;
373 len
= Distance (Pad
->Point1
.X
, Pad
->Point1
.Y
, Pad
->Point2
.X
, Pad
->Point2
.Y
);
374 pcb_sprintf (&report
[0], "%m+PAD ID# %ld; Flags:%s\n"
375 "FirstPoint(X,Y) = %$mD; ID = %ld.\n"
376 "SecondPoint(X,Y) = %$mD; ID = %ld.\n"
377 "Width = %$mS. Length = %$mS.\n"
378 "Clearance width in polygons = %$mS.\n"
379 "Solder mask = %$mS x %$mS (gap = %$mS).\n"
381 "It is owned by SMD element %s\n"
382 " as pin number %s and is on the %s\n"
383 "side of the board.\n"
384 "%s", USER_UNITMASK
, Pad
->ID
,
385 flags_to_string (Pad
->Flags
, PAD_TYPE
),
386 Pad
->Point1
.X
, Pad
->Point1
.Y
, Pad
->Point1
.ID
,
387 Pad
->Point2
.X
, Pad
->Point2
.Y
, Pad
->Point2
.ID
,
388 Pad
->Thickness
, len
+ Pad
->Thickness
,
390 Pad
->Mask
, len
+ Pad
->Mask
,
391 (Pad
->Mask
- Pad
->Thickness
) / 2,
393 EMPTY (element
->Name
[1].TextString
),
395 TEST_FLAG (ONSOLDERFLAG
,
396 Pad
) ? "solder (bottom)" : "component",
397 TEST_FLAG (LOCKFLAG
, Pad
) ? "It is LOCKED.\n" : "");
402 ElementTypePtr element
;
404 if (gui
->shift_is_pressed ())
406 __r_dump_tree (PCB
->Data
->element_tree
->root
, 0);
410 element
= (ElementTypePtr
) ptr2
;
411 pcb_sprintf (&report
[0], "%m+ELEMENT ID# %ld; Flags:%s\n"
412 "BoundingBox %$mD %$mD.\n"
413 "Descriptive Name \"%s\".\n"
414 "Name on board \"%s\".\n"
415 "Part number name \"%s\".\n"
416 "It is %$mS tall and is located at (X,Y) = %$mD %s.\n"
417 "Mark located at point (X,Y) = %$mD.\n"
418 "It is on the %s side of the board.\n"
420 element
->ID
, flags_to_string (element
->Flags
, ELEMENT_TYPE
),
421 element
->BoundingBox
.X1
, element
->BoundingBox
.Y1
,
422 element
->BoundingBox
.X2
, element
->BoundingBox
.Y2
,
423 EMPTY (element
->Name
[0].TextString
),
424 EMPTY (element
->Name
[1].TextString
),
425 EMPTY (element
->Name
[2].TextString
),
426 SCALE_TEXT (FONT_CAPHEIGHT
, element
->Name
[1].Scale
),
427 element
->Name
[1].X
, element
->Name
[1].Y
,
428 TEST_FLAG (HIDENAMEFLAG
, element
) ? ",\n but it's hidden" : "",
429 element
->MarkX
, element
->MarkY
,
430 TEST_FLAG (ONSOLDERFLAG
, element
) ? "solder (bottom)" : "component",
431 TEST_FLAG (LOCKFLAG
, element
) ? "It is LOCKED.\n" : "");
436 if (gui
->shift_is_pressed ())
438 LayerTypePtr layer
= (LayerTypePtr
) ptr1
;
439 __r_dump_tree (layer
->text_tree
->root
, 0);
443 case ELEMENTNAME_TYPE
:
448 if (gui
->shift_is_pressed ())
450 __r_dump_tree (PCB
->Data
->name_tree
[NAME_INDEX (PCB
)]->root
, 0);
454 text
= (TextTypePtr
) ptr2
;
456 if (type
== TEXT_TYPE
)
457 sprintf (laynum
, "It is on layer %d.",
458 GetLayerNumber (PCB
->Data
, (LayerTypePtr
) ptr1
));
459 pcb_sprintf (&report
[0], "%m+TEXT ID# %ld; Flags:%s\n"
460 "Located at (X,Y) = %$mD.\n"
461 "Characters are %$mS tall.\n"
464 "The bounding box is %$mD %$mD.\n"
466 "%s", USER_UNITMASK
, text
->ID
, flags_to_string (text
->Flags
, TEXT_TYPE
),
467 text
->X
, text
->Y
, SCALE_TEXT (FONT_CAPHEIGHT
, text
->Scale
),
468 text
->TextString
, text
->Direction
,
469 text
->BoundingBox
.X1
, text
->BoundingBox
.Y1
,
470 text
->BoundingBox
.X2
, text
->BoundingBox
.Y2
,
471 (type
== TEXT_TYPE
) ? laynum
: "It is an element name.",
472 TEST_FLAG (LOCKFLAG
, text
) ? "It is LOCKED.\n" : "");
476 case POLYGONPOINT_TYPE
:
478 PointTypePtr point
= (PointTypePtr
) ptr2
;
479 pcb_sprintf (&report
[0], "%m+POINT ID# %ld.\n"
480 "Located at (X,Y) = %$mD.\n"
481 "It belongs to a %s on layer %d.\n", USER_UNITMASK
, point
->ID
,
483 (type
== LINEPOINT_TYPE
) ? "line" : "polygon",
484 GetLayerNumber (PCB
->Data
, (LayerTypePtr
) ptr1
));
492 sprintf (&report
[0], "Unknown\n");
496 if (report
[0] == '\0')
498 Message (_("Nothing found to report on\n"));
501 /* create dialog box */
502 gui
->report_dialog ("Report", &report
[0]);
508 ReportFoundPins (int argc
, char **argv
, Coord x
, Coord y
)
510 static DynamicStringType list
;
514 DSClearString (&list
);
515 DSAddString (&list
, "The following pins/pads are FOUND:\n");
516 ELEMENT_LOOP (PCB
->Data
);
520 if (TEST_FLAG (FOUNDFLAG
, pin
))
522 sprintf (temp
, "%s-%s,%c",
523 NAMEONPCB_NAME (element
),
525 ((col
++ % (COLUMNS
+ 1)) == COLUMNS
) ? '\n' : ' ');
526 DSAddString (&list
, temp
);
532 if (TEST_FLAG (FOUNDFLAG
, pad
))
534 sprintf (temp
, "%s-%s,%c",
535 NAMEONPCB_NAME (element
), pad
->Number
,
536 ((col
++ % (COLUMNS
+ 1)) == COLUMNS
) ? '\n' : ' ');
537 DSAddString (&list
, temp
);
544 gui
->report_dialog ("Report", list
.Data
);
548 /* Assumes that we start with a blank connection state,
549 * e.g. ResetConnections() has been run.
550 * Does not add its own changes to the undo system
553 XYtoNetLength (Coord x
, Coord y
, int *found
)
560 /* NB: The third argument here, 'false' ensures LookupConnection
561 * does not add its changes to the undo system.
563 LookupConnection (x
, y
, false, PCB
->Grid
, FOUNDFLAG
);
565 ALLLINE_LOOP (PCB
->Data
);
567 if (TEST_FLAG (FOUNDFLAG
, line
))
571 dx
= line
->Point1
.X
- line
->Point2
.X
;
572 dy
= line
->Point1
.Y
- line
->Point2
.Y
;
573 l
= sqrt ((double)dx
*dx
+ (double)dy
*dy
);
580 ALLARC_LOOP (PCB
->Data
);
582 if (TEST_FLAG (FOUNDFLAG
, arc
))
585 /* FIXME: we assume width==height here */
586 l
= M_PI
* 2*arc
->Width
* abs(arc
->Delta
)/360.0;
597 ReportAllNetLengths (int argc
, char **argv
, Coord x
, Coord y
)
602 /* Reset all connection flags and save an undo-state to get back
603 * to the state the board was in when we started this function.
605 * After this, we don't add any changes to the undo system, but
606 * ensure we get back to a point where we can Undo() our changes
607 * by resetting the connections with ResetConnections() before
608 * calling Undo() at the end of the procedure.
610 ResetConnections (true);
611 IncrementUndoSerialNumber ();
613 for (ni
= 0; ni
< PCB
->NetlistLib
.MenuN
; ni
++)
615 char *netname
= PCB
->NetlistLib
.Menu
[ni
].Name
+ 2;
616 char *ename
= PCB
->NetlistLib
.Menu
[ni
].Entry
[0].ListEntry
;
620 ename
= strdup (ename
);
621 pname
= strchr (ename
, '-');
629 ELEMENT_LOOP (PCB
->Data
);
631 char *es
= element
->Name
[NAMEONPCB_INDEX
].TextString
;
632 if (es
&& strcmp (es
, ename
) == 0)
636 if (strcmp (pin
->Number
, pname
) == 0)
647 if (strcmp (pad
->Number
, pname
) == 0)
649 x
= (pad
->Point1
.X
+ pad
->Point2
.X
) / 2;
650 y
= (pad
->Point1
.Y
+ pad
->Point2
.Y
) / 2;
663 const char *units_name
= argv
[0];
667 units_name
= Settings
.grid_unit
->suffix
;
669 length
= XYtoNetLength (x
, y
, &found
);
671 /* Reset connectors for the next lookup */
672 ResetConnections (false);
674 pcb_sprintf(buf
, "%$m*", units_name
, length
);
675 gui
->log("Net %s length %s\n", netname
, buf
);
679 ResetConnections (false);
685 ReportNetLength (int argc
, char **argv
, Coord x
, Coord y
)
691 gui
->get_coords ("Click on a connection", &x
, &y
);
693 /* Reset all connection flags and save an undo-state to get back
694 * to the state the board was in when we started this function.
696 * After this, we don't add any changes to the undo system, but
697 * ensure we get back to a point where we can Undo() our changes
698 * by resetting the connections with ResetConnections() before
699 * calling Undo() at the end of the procedure.
701 ResetConnections (true);
702 IncrementUndoSerialNumber ();
704 length
= XYtoNetLength (x
, y
, &found
);
708 ResetConnections (false);
710 gui
->log ("No net under cursor.\n");
714 ELEMENT_LOOP (PCB
->Data
);
718 if (TEST_FLAG (FOUNDFLAG
, pin
))
721 char *ename
= element
->Name
[NAMEONPCB_INDEX
].TextString
;
722 char *pname
= pin
->Number
;
727 n
= Concat (ename
, "-", pname
, NULL
);
728 for (ni
= 0; ni
< PCB
->NetlistLib
.MenuN
; ni
++)
729 for (nei
= 0; nei
< PCB
->NetlistLib
.Menu
[ni
].EntryN
; nei
++)
731 if (strcmp (PCB
->NetlistLib
.Menu
[ni
].Entry
[nei
].ListEntry
, n
) == 0)
733 netname
= PCB
->NetlistLib
.Menu
[ni
].Name
+ 2;
734 goto got_net_name
; /* four for loops deep */
743 if (TEST_FLAG (FOUNDFLAG
, pad
))
746 char *ename
= element
->Name
[NAMEONPCB_INDEX
].TextString
;
747 char *pname
= pad
->Number
;
752 n
= Concat (ename
, "-", pname
, NULL
);
753 for (ni
= 0; ni
< PCB
->NetlistLib
.MenuN
; ni
++)
754 for (nei
= 0; nei
< PCB
->NetlistLib
.Menu
[ni
].EntryN
; nei
++)
756 if (strcmp (PCB
->NetlistLib
.Menu
[ni
].Entry
[nei
].ListEntry
, n
) == 0)
758 netname
= PCB
->NetlistLib
.Menu
[ni
].Name
+ 2;
759 goto got_net_name
; /* four for loops deep */
770 ResetConnections (false);
775 pcb_sprintf(buf
, "%$m*", Settings
.grid_unit
->suffix
, length
);
777 gui
->log ("Net \"%s\" length: %s\n", netname
, buf
);
779 gui
->log ("Net length: %s\n", buf
);
786 ReportNetLengthByName (char *tofind
, int x
, int y
)
793 LibraryMenuType
*net
;
799 #if defined(HAVE_REGCOMP)
803 #if defined(HAVE_RE_COMP)
815 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
817 net
= PCB
->NetlistLib
.Menu
+ i
;
818 if (strcasecmp (tofind
, net
->Name
+ 2) == 0)
823 #if defined(HAVE_REGCOMP)
825 regcomp (&elt_pattern
, tofind
,
826 REG_EXTENDED
| REG_ICASE
| REG_NOSUB
);
829 char errorstring
[128];
831 regerror (result
, &elt_pattern
, errorstring
, 128);
832 Message (_("regexp error: %s\n"), errorstring
);
833 regfree (&elt_pattern
);
837 #if defined(HAVE_RE_COMP)
838 if ((elt_pattern
= re_comp (tofind
)) != NULL
)
840 Message (_("re_comp error: %s\n"), elt_pattern
);
847 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
849 net
= PCB
->NetlistLib
.Menu
+ i
;
854 #if defined(HAVE_REGCOMP)
855 if (regexec (&elt_pattern
, net
->Name
+ 2, 1, &match
, 0) != 0)
858 #if defined(HAVE_RE_COMP)
859 if (re_exec (net
->Name
+ 2) != 1)
865 if (strcasecmp (net
->Name
+ 2, tofind
))
868 if (SeekPad (net
->Entry
, &conn
, false))
873 x
= ((PinType
*) (conn
.ptr2
))->X
;
874 y
= ((PinType
*) (conn
.ptr2
))->Y
;
878 x
= ((PadType
*) (conn
.ptr2
))->Point1
.X
;
879 y
= ((PadType
*) (conn
.ptr2
))->Point1
.Y
;
890 gui
->log ("No net named %s\n", tofind
);
896 regfree (&elt_pattern
);
899 /* Reset all connection flags and save an undo-state to get back
900 * to the state the board was in when we started.
902 * After this, we don't add any changes to the undo system, but
903 * ensure we get back to a point where we can Undo() our changes
904 * by resetting the connections with ResetConnections() before
905 * calling Undo() when we are finished.
907 ResetConnections (true);
908 IncrementUndoSerialNumber ();
910 length
= XYtoNetLength (x
, y
, &found
);
911 netname
= net
->Name
+ 2;
913 ResetConnections (false);
919 gui
->log ("Net found, but no lines or arcs were flagged.\n");
921 gui
->log ("Net not found.\n");
928 pcb_sprintf(buf
, "%$m*", Settings
.grid_unit
->suffix
, length
);
930 gui
->log ("Net \"%s\" length: %s\n", netname
, buf
);
932 gui
->log ("Net length: %s\n", buf
);
938 /* ---------------------------------------------------------------------------
939 * reports on an object
943 static const char report_syntax
[] = "Report(Object|DrillReport|FoundPins|NetLength|AllNetLengths|[,name])";
945 static const char report_help
[] = "Produce various report.";
947 /* %start-doc actions Report
952 The object under the crosshair will be reported, describing various
953 aspects of the object.
956 A report summarizing the number of drill sizes used, and how many of
957 each, will be produced.
960 A report listing all pins and pads which are marked as ``found'' will
964 The name and length of the net under the crosshair will be reported to
968 The name and length of the net under the crosshair will be reported to
969 the message log. An optional parameter specifies mm, mil, pcb, or in
977 Report (int argc
, char **argv
, Coord x
, Coord y
)
979 if ((argc
< 1) || (argc
> 2))
981 else if (strcasecmp (argv
[0], "Object") == 0)
983 gui
->get_coords ("Click on an object", &x
, &y
);
984 return ReportDialog (argc
- 1, argv
+ 1, x
, y
);
986 else if (strcasecmp (argv
[0], "DrillReport") == 0)
987 return ReportDrills (argc
- 1, argv
+ 1, x
, y
);
988 else if (strcasecmp (argv
[0], "FoundPins") == 0)
989 return ReportFoundPins (argc
- 1, argv
+ 1, x
, y
);
990 else if ((strcasecmp (argv
[0], "NetLength") == 0) && (argc
== 1))
991 return ReportNetLength (argc
- 1, argv
+ 1, x
, y
);
992 else if (strcasecmp (argv
[0], "AllNetLengths") == 0)
993 return ReportAllNetLengths (argc
- 1, argv
+ 1, x
, y
);
994 else if ((strcasecmp (argv
[0], "NetLength") == 0) && (argc
== 2))
995 return ReportNetLengthByName (argv
[1], x
, y
);
1003 HID_Action report_action_list
[] = {
1004 {"ReportObject", "Click on an object", ReportDialog
,
1005 reportdialog_help
, reportdialog_syntax
}
1007 {"Report", 0, Report
,
1008 report_help
, report_syntax
}
1011 REGISTER_ACTIONS (report_action_list
)