pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00038 #ifdef HAVE_CONFIG_H 00039 #include "config.h" 00040 #endif 00041 00042 #include <math.h> 00043 00044 #include "report.h" 00045 #include "crosshair.h" 00046 #include "data.h" 00047 #include "drill.h" 00048 #include "error.h" 00049 #include "search.h" 00050 #include "misc.h" 00051 #include "mymem.h" 00052 #include "rats.h" 00053 #include "rtree.h" 00054 #include "strflags.h" 00055 #include "macro.h" 00056 #include "undo.h" 00057 #include "find.h" 00058 #include "draw.h" 00059 #include "pcb-printf.h" 00060 #ifdef HAVE_REGEX_H 00061 #include <regex.h> 00062 #endif 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 #define USER_UNITMASK (Settings.grid_unit->allow) 00077 00078 static int 00079 ReportDrills (int argc, char **argv, Coord x, Coord y) 00080 { 00081 DrillInfoType *AllDrills; 00082 Cardinal n; 00083 char *stringlist, *thestring; 00084 int total_drills = 0; 00085 size_t size_left; 00086 00087 AllDrills = GetDrillInfo (PCB->Data); 00088 00089 for (n = 0; n < AllDrills->DrillN; n++) 00090 { 00091 total_drills += AllDrills->Drill[n].PinCount; 00092 total_drills += AllDrills->Drill[n].ViaCount; 00093 } 00094 00095 size_left = 512L + AllDrills->DrillN * 64L; 00096 stringlist = (char *)malloc (size_left); 00097 00098 /* Use tabs for formatting since can't count on a fixed font anymore. 00099 | And even that probably isn't going to work in all cases. 00100 */ 00101 sprintf (stringlist, 00102 _("There are %d different drill sizes used in this layout, %d holes total\n\n" 00103 "Drill Diam. (%s)\t# of Pins\t# of Vias\t# of Elements\t# Unplated\n"), 00104 AllDrills->DrillN, total_drills, Settings.grid_unit->suffix); 00105 00106 thestring = stringlist; 00107 while (size_left > 0 && *thestring != '\0') 00108 { 00109 thestring++; 00110 size_left--; 00111 } 00112 00113 for (n = 0; n < AllDrills->DrillN; n++) 00114 { 00115 pcb_snprintf (thestring, size_left, 00116 _("%10m*\t\t%d\t\t%d\t\t%d\t\t%d\n"), 00117 Settings.grid_unit->suffix, 00118 AllDrills->Drill[n].DrillSize, 00119 AllDrills->Drill[n].PinCount, AllDrills->Drill[n].ViaCount, 00120 AllDrills->Drill[n].ElementN, 00121 AllDrills->Drill[n].UnplatedCount); 00122 while (size_left > 0 && *thestring != '\0') 00123 { 00124 thestring++; 00125 size_left--; 00126 } 00127 } 00128 FreeDrillInfo (AllDrills); 00129 /* create dialog box */ 00130 gui->report_dialog (_("Drill Report"), stringlist); 00131 00132 free (stringlist); 00133 return 0; 00134 } 00135 00136 00137 static const char reportdialog_syntax[] = N_("ReportDialog()"); 00138 00139 static const char reportdialog_help[] = 00140 N_("Report on the object under the crosshair"); 00141 00142 00143 static char* 00144 CreateBuriedViaDescription (int from, int to) 00145 { 00146 static char s[32]; 00147 00148 if ((from == 0) && (to == 0)) 00149 strcpy (s, "Through-hole"); 00150 else 00151 sprintf (s, "Buried (%d:%d)", from, to); 00152 00153 return s; 00154 } 00155 00156 /* %start-doc actions ReportDialog 00157 00158 This is a shortcut for @code{Report(Object)}. 00159 00160 %end-doc */ 00161 00162 static int 00163 ReportDialog (int argc, char **argv, Coord x, Coord y) 00164 { 00165 void *ptr1, *ptr2, *ptr3; 00166 int type; 00167 char report[2048]; 00168 00169 type = SearchScreen (x, y, REPORT_TYPES, &ptr1, &ptr2, &ptr3); 00170 if (type == NO_TYPE) 00171 type = 00172 SearchScreen (x, y, REPORT_TYPES | LOCKED_TYPE, &ptr1, &ptr2, &ptr3); 00173 00174 switch (type) 00175 { 00176 case VIA_TYPE: 00177 { 00178 PinType *via; 00179 #ifndef NDEBUG 00180 if (gui->shift_is_pressed ()) 00181 { 00182 __r_dump_tree (PCB->Data->via_tree->root, 0); 00183 return 0; 00184 } 00185 #endif 00186 via = (PinType *) ptr2; 00187 if (TEST_FLAG (HOLEFLAG, via)) 00188 pcb_snprintf (report, sizeof (report), _("%m+VIA ID# %ld; Flags:%s\n" 00189 "(X,Y) = %$mD.\n" 00190 "It is a pure hole of diameter %$mS.\n" 00191 "Name = \"%s\"." 00192 "%s"), USER_UNITMASK, via->ID, flags_to_string (via->Flags, VIA_TYPE), 00193 via->X, via->Y, via->DrillingHole, EMPTY (via->Name), 00194 TEST_FLAG (LOCKFLAG, via) ? _("It is LOCKED.\n") : ""); 00195 else 00196 pcb_snprintf (report, sizeof (report), _("%m+VIA ID# %ld; Flags:%s\n" 00197 "(X,Y) = %$mD.\n" 00198 "Copper width = %$mS. Drill width = %$mS.\n" 00199 "Clearance width in polygons = %$mS.\n" 00200 "Annulus = %$mS.\n" 00201 "Solder mask hole = %$mS (gap = %$mS).\n" 00202 "Type = %s.\n" 00203 "Name = \"%s\"." 00204 "%s"), USER_UNITMASK, via->ID, flags_to_string (via->Flags, VIA_TYPE), 00205 via->X, via->Y, 00206 via->Thickness, 00207 via->DrillingHole, 00208 via->Clearance / 2, 00209 (via->Thickness - via->DrillingHole) / 2, 00210 via->Mask, 00211 (via->Mask - via->Thickness) / 2, 00212 CreateBuriedViaDescription (via->BuriedFrom, via->BuriedTo), 00213 EMPTY (via->Name), TEST_FLAG (LOCKFLAG, via) ? 00214 _("It is LOCKED.\n") : ""); 00215 break; 00216 } 00217 case PIN_TYPE: 00218 { 00219 PinType *Pin; 00220 ElementType *element; 00221 #ifndef NDEBUG 00222 if (gui->shift_is_pressed ()) 00223 { 00224 __r_dump_tree (PCB->Data->pin_tree->root, 0); 00225 return 0; 00226 } 00227 #endif 00228 Pin = (PinType *) ptr2; 00229 element = (ElementType *) ptr1; 00230 00231 PIN_LOOP (element); 00232 { 00233 if (pin == Pin) 00234 break; 00235 } 00236 END_LOOP; 00237 if (TEST_FLAG (HOLEFLAG, Pin)) 00238 pcb_snprintf (report, sizeof (report), _("%m+PIN ID# %ld; Flags:%s\n" 00239 "(X,Y) = %$mD.\n" 00240 "It is a mounting hole. Drill width = %$mS.\n" 00241 "It is owned by element %$mS.\n" 00242 "%s"), USER_UNITMASK, Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE), 00243 Pin->X, Pin->Y, Pin->DrillingHole, 00244 EMPTY (element->Name[1].TextString), 00245 TEST_FLAG (LOCKFLAG, Pin) ? _("It is LOCKED.\n") : ""); 00246 else 00247 pcb_snprintf (report, sizeof (report), 00248 _("%m+PIN ID# %ld; Flags:%s\n" "(X,Y) = %$mD.\n" 00249 "Copper width = %$mS. Drill width = %$mS.\n" 00250 "Clearance width to Polygon = %$mS.\n" 00251 "Annulus = %$mS.\n" 00252 "Solder mask hole = %$mS (gap = %$mS).\n" 00253 "Name = \"%s\".\n" 00254 "It is owned by element %s\n as pin number %s.\n" 00255 "%s"), USER_UNITMASK, 00256 Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE), 00257 Pin->X, Pin->Y, Pin->Thickness, 00258 Pin->DrillingHole, 00259 Pin->Clearance / 2, 00260 (Pin->Thickness - Pin->DrillingHole) / 2, 00261 Pin->Mask, 00262 (Pin->Mask - Pin->Thickness) / 2, 00263 EMPTY (Pin->Name), 00264 EMPTY (element->Name[1].TextString), EMPTY (Pin->Number), 00265 TEST_FLAG (LOCKFLAG, Pin) ? _("It is LOCKED.\n") : ""); 00266 break; 00267 } 00268 case LINE_TYPE: 00269 { 00270 LineType *line; 00271 #ifndef NDEBUG 00272 if (gui->shift_is_pressed ()) 00273 { 00274 LayerType *layer = (LayerType *) ptr1; 00275 __r_dump_tree (layer->line_tree->root, 0); 00276 return 0; 00277 } 00278 #endif 00279 line = (LineType *) ptr2; 00280 pcb_snprintf (report, sizeof (report), _("%m+LINE ID# %ld; Flags:%s\n" 00281 "FirstPoint(X,Y) = %$mD, ID = %ld.\n" 00282 "SecondPoint(X,Y) = %$mD, ID = %ld.\n" 00283 "Width = %$mS.\nClearance width in polygons = %$mS.\n" 00284 "It is on layer %d\n" 00285 "and has name \"%s\".\n" 00286 "%s"), USER_UNITMASK, 00287 line->ID, flags_to_string (line->Flags, LINE_TYPE), 00288 line->Point1.X, line->Point1.Y, line->Point1.ID, 00289 line->Point2.X, line->Point2.Y, line->Point2.ID, 00290 line->Thickness, line->Clearance / 2, 00291 GetLayerNumber (PCB->Data, (LayerType *) ptr1), 00292 UNKNOWN (line->Number), 00293 TEST_FLAG (LOCKFLAG, line) ? _("It is LOCKED.\n") : ""); 00294 break; 00295 } 00296 case RATLINE_TYPE: 00297 { 00298 RatType *line; 00299 #ifndef NDEBUG 00300 if (gui->shift_is_pressed ()) 00301 { 00302 __r_dump_tree (PCB->Data->rat_tree->root, 0); 00303 return 0; 00304 } 00305 #endif 00306 line = (RatType *) ptr2; 00307 pcb_snprintf (report, sizeof (report), _("%m+RAT-LINE ID# %ld; Flags:%s\n" 00308 "FirstPoint(X,Y) = %$mD; ID = %ld; " 00309 "connects to layer group %d.\n" 00310 "SecondPoint(X,Y) = %$mD; ID = %ld; " 00311 "connects to layer group %d.\n"), 00312 USER_UNITMASK, line->ID, flags_to_string (line->Flags, LINE_TYPE), 00313 line->Point1.X, line->Point1.Y, 00314 line->Point1.ID, line->group1, 00315 line->Point2.X, line->Point2.Y, 00316 line->Point2.ID, line->group2); 00317 break; 00318 } 00319 case ARC_TYPE: 00320 { 00321 ArcType *Arc; 00322 BoxType *box; 00323 #ifndef NDEBUG 00324 if (gui->shift_is_pressed ()) 00325 { 00326 LayerType *layer = (LayerType *) ptr1; 00327 __r_dump_tree (layer->arc_tree->root, 0); 00328 return 0; 00329 } 00330 #endif 00331 Arc = (ArcType *) ptr2; 00332 box = GetArcEnds (Arc); 00333 00334 pcb_snprintf (report, sizeof (report), _("%m+ARC ID# %ld; Flags:%s\n" 00335 "CenterPoint(X,Y) = %$mD.\n" 00336 "Radius = %$mS, Thickness = %$mS.\n" 00337 "Clearance width in polygons = %$mS.\n" 00338 "StartAngle = %ma degrees, DeltaAngle = %ma degrees.\n" 00339 "Bounding Box is %$mD, %$mD.\n" 00340 "That makes the end points at %$mD and %$mD.\n" 00341 "It is on layer %d.\n" 00342 "%s"), USER_UNITMASK, Arc->ID, flags_to_string (Arc->Flags, ARC_TYPE), 00343 Arc->X, Arc->Y, 00344 Arc->Width, Arc->Thickness, 00345 Arc->Clearance / 2, Arc->StartAngle, Arc->Delta, 00346 Arc->BoundingBox.X1, Arc->BoundingBox.Y1, 00347 Arc->BoundingBox.X2, Arc->BoundingBox.Y2, 00348 box->X1, box->Y1, 00349 box->X2, box->Y2, 00350 GetLayerNumber (PCB->Data, (LayerType *) ptr1), 00351 TEST_FLAG (LOCKFLAG, Arc) ? _("It is LOCKED.\n") : ""); 00352 break; 00353 } 00354 case POLYGON_TYPE: 00355 { 00356 PolygonType *Polygon; 00357 #ifndef NDEBUG 00358 if (gui->shift_is_pressed ()) 00359 { 00360 LayerType *layer = (LayerType *) ptr1; 00361 __r_dump_tree (layer->polygon_tree->root, 0); 00362 return 0; 00363 } 00364 #endif 00365 Polygon = (PolygonType *) ptr2; 00366 00367 pcb_snprintf (report, sizeof (report), _("%m+POLYGON ID# %ld; Flags:%s\n" 00368 "Its bounding box is %$mD %$mD.\n" 00369 "It has %d points and could store %d more\n" 00370 " without using more memory.\n" 00371 "It has %d holes and resides on layer %d.\n" 00372 "%s"), USER_UNITMASK, Polygon->ID, 00373 flags_to_string (Polygon->Flags, POLYGON_TYPE), 00374 Polygon->BoundingBox.X1, Polygon->BoundingBox.Y1, 00375 Polygon->BoundingBox.X2, Polygon->BoundingBox.Y2, 00376 Polygon->PointN, Polygon->PointMax - Polygon->PointN, 00377 Polygon->HoleIndexN, 00378 GetLayerNumber (PCB->Data, (LayerType *) ptr1), 00379 TEST_FLAG (LOCKFLAG, Polygon) ? _("It is LOCKED.\n") : ""); 00380 break; 00381 } 00382 case PAD_TYPE: 00383 { 00384 Coord len; 00385 PadType *Pad; 00386 ElementType *element; 00387 #ifndef NDEBUG 00388 if (gui->shift_is_pressed ()) 00389 { 00390 __r_dump_tree (PCB->Data->pad_tree->root, 0); 00391 return 0; 00392 } 00393 #endif 00394 Pad = (PadType *) ptr2; 00395 element = (ElementType *) ptr1; 00396 00397 PAD_LOOP (element); 00398 { 00399 { 00400 if (pad == Pad) 00401 break; 00402 } 00403 } 00404 END_LOOP; 00405 len = Distance (Pad->Point1.X, Pad->Point1.Y, Pad->Point2.X, Pad->Point2.Y); 00406 pcb_snprintf (report, sizeof (report), _("%m+PAD ID# %ld; Flags:%s\n" 00407 "FirstPoint(X,Y) = %$mD; ID = %ld.\n" 00408 "SecondPoint(X,Y) = %$mD; ID = %ld.\n" 00409 "Width = %$mS. Length = %$mS.\n" 00410 "Clearance width in polygons = %$mS.\n" 00411 "Solder mask = %$mS x %$mS (gap = %$mS).\n" 00412 "Name = \"%s\".\n" 00413 "It is owned by SMD element %s\n" 00414 " as pin number %s and is on the %s\n" 00415 "side of the board.\n" 00416 "%s"), USER_UNITMASK, Pad->ID, 00417 flags_to_string (Pad->Flags, PAD_TYPE), 00418 Pad->Point1.X, Pad->Point1.Y, Pad->Point1.ID, 00419 Pad->Point2.X, Pad->Point2.Y, Pad->Point2.ID, 00420 Pad->Thickness, len + Pad->Thickness, 00421 Pad->Clearance / 2, 00422 Pad->Mask, len + Pad->Mask, 00423 (Pad->Mask - Pad->Thickness) / 2, 00424 EMPTY (Pad->Name), 00425 EMPTY (element->Name[1].TextString), 00426 EMPTY (Pad->Number), 00427 TEST_FLAG (ONSOLDERFLAG, 00428 Pad) ? _("solder (bottom)") : _("component"), 00429 TEST_FLAG (LOCKFLAG, Pad) ? _("It is LOCKED.\n") : ""); 00430 break; 00431 } 00432 case ELEMENT_TYPE: 00433 { 00434 ElementType *element; 00435 #ifndef NDEBUG 00436 if (gui->shift_is_pressed ()) 00437 { 00438 __r_dump_tree (PCB->Data->element_tree->root, 0); 00439 return 0; 00440 } 00441 #endif 00442 element = (ElementType *) ptr2; 00443 pcb_snprintf (report, sizeof (report), _("%m+ELEMENT ID# %ld; Flags:%s\n" 00444 "BoundingBox %$mD %$mD.\n" 00445 "Descriptive Name \"%s\".\n" 00446 "Name on board \"%s\".\n" 00447 "Part number name \"%s\".\n" 00448 "It is %$mS tall and is located at (X,Y) = %$mD %s.\n" 00449 "Mark located at point (X,Y) = %$mD.\n" 00450 "It is on the %s side of the board.\n" 00451 "%s"), USER_UNITMASK, 00452 element->ID, flags_to_string (element->Flags, ELEMENT_TYPE), 00453 element->BoundingBox.X1, element->BoundingBox.Y1, 00454 element->BoundingBox.X2, element->BoundingBox.Y2, 00455 EMPTY (element->Name[0].TextString), 00456 EMPTY (element->Name[1].TextString), 00457 EMPTY (element->Name[2].TextString), 00458 SCALE_TEXT (FONT_CAPHEIGHT, element->Name[1].Scale), 00459 element->Name[1].X, element->Name[1].Y, 00460 TEST_FLAG (HIDENAMEFLAG, element) ? _(",\n but it's hidden") : "", 00461 element->MarkX, element->MarkY, 00462 TEST_FLAG (ONSOLDERFLAG, element) ? _("solder (bottom)") : _("component"), 00463 TEST_FLAG (LOCKFLAG, element) ? _("It is LOCKED.\n") : ""); 00464 break; 00465 } 00466 case TEXT_TYPE: 00467 #ifndef NDEBUG 00468 if (gui->shift_is_pressed ()) 00469 { 00470 LayerType *layer = (LayerType *) ptr1; 00471 __r_dump_tree (layer->text_tree->root, 0); 00472 return 0; 00473 } 00474 #endif 00475 case ELEMENTNAME_TYPE: 00476 { 00477 char laynum[32]; 00478 TextType *text; 00479 #ifndef NDEBUG 00480 if (gui->shift_is_pressed ()) 00481 { 00482 __r_dump_tree (PCB->Data->name_tree[NAME_INDEX (PCB)]->root, 0); 00483 return 0; 00484 } 00485 #endif 00486 text = (TextType *) ptr2; 00487 00488 if (type == TEXT_TYPE) 00489 sprintf (laynum, _("It is on layer %d."), 00490 GetLayerNumber (PCB->Data, (LayerType *) ptr1)); 00491 pcb_snprintf (report, sizeof (report), _("%m+TEXT ID# %ld; Flags:%s\n" 00492 "Located at (X,Y) = %$mD.\n" 00493 "Characters are %$mS tall.\n" 00494 "Value is \"%s\".\n" 00495 "Direction is %d.\n" 00496 "The bounding box is %$mD %$mD.\n" 00497 "%s\n" 00498 "%s"), USER_UNITMASK, text->ID, flags_to_string (text->Flags, TEXT_TYPE), 00499 text->X, text->Y, SCALE_TEXT (FONT_CAPHEIGHT, text->Scale), 00500 text->TextString, text->Direction, 00501 text->BoundingBox.X1, text->BoundingBox.Y1, 00502 text->BoundingBox.X2, text->BoundingBox.Y2, 00503 (type == TEXT_TYPE) ? laynum : _("It is an element name."), 00504 TEST_FLAG (LOCKFLAG, text) ? _("It is LOCKED.\n") : ""); 00505 break; 00506 } 00507 case LINEPOINT_TYPE: 00508 case POLYGONPOINT_TYPE: 00509 { 00510 PointType *point = (PointType *) ptr2; 00511 pcb_snprintf (report, sizeof (report), _("%m+POINT ID# %ld.\n" 00512 "Located at (X,Y) = %$mD.\n" 00513 "It belongs to a %s on layer %d.\n"), USER_UNITMASK, point->ID, 00514 point->X, point->Y, 00515 (type == LINEPOINT_TYPE) ? 00516 C_("report", "line") : C_("report", "polygon"), 00517 GetLayerNumber (PCB->Data, (LayerType *) ptr1)); 00518 break; 00519 } 00520 case NO_TYPE: 00521 report[0] = '\0'; 00522 break; 00523 00524 default: 00525 sprintf (report, _("Unknown\n")); 00526 break; 00527 } 00528 00529 if (report[0] == '\0') 00530 { 00531 Message (_("Nothing found to report on\n")); 00532 return 1; 00533 } 00534 /* create dialog box */ 00535 gui->report_dialog (_("Report"), report); 00536 00537 return 0; 00538 } 00539 00540 static int 00541 ReportFoundPins (int argc, char **argv, Coord x, Coord y) 00542 { 00543 static DynamicStringType list; 00544 char temp[64]; 00545 int col = 0; 00546 00547 DSClearString (&list); 00548 DSAddString (&list, _("The following pins/pads are FOUND:\n")); 00549 ELEMENT_LOOP (PCB->Data); 00550 { 00551 PIN_LOOP (element); 00552 { 00553 if (TEST_FLAG (FOUNDFLAG, pin)) 00554 { 00555 sprintf (temp, _("%s-%s,%c"), 00556 NAMEONPCB_NAME (element), 00557 pin->Number, 00558 ((col++ % (COLUMNS + 1)) == COLUMNS) ? '\n' : ' '); 00559 DSAddString (&list, temp); 00560 } 00561 } 00562 END_LOOP; 00563 PAD_LOOP (element); 00564 { 00565 if (TEST_FLAG (FOUNDFLAG, pad)) 00566 { 00567 sprintf (temp, _("%s-%s,%c"), 00568 NAMEONPCB_NAME (element), pad->Number, 00569 ((col++ % (COLUMNS + 1)) == COLUMNS) ? '\n' : ' '); 00570 DSAddString (&list, temp); 00571 } 00572 } 00573 END_LOOP; 00574 } 00575 END_LOOP; 00576 00577 gui->report_dialog (_("Report"), list.Data); 00578 return 0; 00579 } 00580 00587 static double 00588 XYtoNetLength (Coord x, Coord y, int *found) 00589 { 00590 double length; 00591 00592 length = 0; 00593 *found = 0; 00594 00595 /* NB: The third argument here, 'false' ensures LookupConnection 00596 * does not add its changes to the undo system. 00597 */ 00598 LookupConnection (x, y, false, PCB->Grid, FOUNDFLAG, true); 00599 00600 ALLLINE_LOOP (PCB->Data); 00601 { 00602 if (TEST_FLAG (FOUNDFLAG, line)) 00603 { 00604 int dx, dy; 00605 dx = line->Point1.X - line->Point2.X; 00606 dy = line->Point1.Y - line->Point2.Y; 00607 length += hypot (dx, dy); 00608 *found = 1; 00609 } 00610 } 00611 ENDALL_LOOP; 00612 00613 ALLARC_LOOP (PCB->Data); 00614 { 00615 if (TEST_FLAG (FOUNDFLAG, arc)) 00616 { 00617 double l; 00618 /* FIXME: we assume width==height here */ 00619 l = M_PI * 2*arc->Width * abs(arc->Delta)/360.0; 00620 length += l; 00621 *found = 1; 00622 } 00623 } 00624 ENDALL_LOOP; 00625 00626 return length; 00627 } 00628 00629 static int 00630 ReportAllNetLengths (int argc, char **argv, Coord x, Coord y) 00631 { 00632 int ni; 00633 int found; 00634 00635 /* Reset all connection flags and save an undo-state to get back 00636 * to the state the board was in when we started this function. 00637 * 00638 * After this, we don't add any changes to the undo system, but 00639 * ensure we get back to a point where we can Undo() our changes 00640 * by resetting the connections with ClearFlagOnAllObjects() before 00641 * calling Undo() at the end of the procedure. 00642 */ 00643 ClearFlagOnAllObjects (true, FOUNDFLAG); 00644 IncrementUndoSerialNumber (); 00645 00646 for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++) 00647 { 00648 char *netname = PCB->NetlistLib.Menu[ni].Name + 2; 00649 char *ename = PCB->NetlistLib.Menu[ni].Entry[0].ListEntry; 00650 char *pname; 00651 bool got_one = 0; 00652 00653 ename = strdup (ename); 00654 pname = strchr (ename, '-'); 00655 if (! pname) 00656 { 00657 free (ename); 00658 continue; 00659 } 00660 *pname++ = 0; 00661 00662 ELEMENT_LOOP (PCB->Data); 00663 { 00664 char *es = element->Name[NAMEONPCB_INDEX].TextString; 00665 if (es && strcmp (es, ename) == 0) 00666 { 00667 PIN_LOOP (element); 00668 { 00669 if (strcmp (pin->Number, pname) == 0) 00670 { 00671 x = pin->X; 00672 y = pin->Y; 00673 got_one = 1; 00674 break; 00675 } 00676 } 00677 END_LOOP; 00678 PAD_LOOP (element); 00679 { 00680 if (strcmp (pad->Number, pname) == 0) 00681 { 00682 x = (pad->Point1.X + pad->Point2.X) / 2; 00683 y = (pad->Point1.Y + pad->Point2.Y) / 2; 00684 got_one = 1; 00685 break; 00686 } 00687 } 00688 END_LOOP; 00689 } 00690 } 00691 END_LOOP; 00692 00693 if (got_one) 00694 { 00695 char buf[50]; 00696 const char *units_name = argv[0]; 00697 Coord length; 00698 00699 if (argc < 1) 00700 units_name = Settings.grid_unit->suffix; 00701 00702 length = XYtoNetLength (x, y, &found); 00703 00704 /* Reset connectors for the next lookup */ 00705 ClearFlagOnAllObjects (false, FOUNDFLAG); 00706 00707 pcb_snprintf(buf, sizeof (buf), _("%$m*"), units_name, length); 00708 gui->log(_("Net \"%s\" length: %s\n"), netname, buf); 00709 } 00710 } 00711 00712 ClearFlagOnAllObjects (false, FOUNDFLAG); 00713 Undo (true); 00714 return 0; 00715 } 00716 00717 static int 00718 ReportNetLength (int argc, char **argv, Coord x, Coord y) 00719 { 00720 Coord length = 0; 00721 char *netname = 0; 00722 int found = 0; 00723 00724 gui->get_coords (_("Click on a connection"), &x, &y); 00725 00726 /* Reset all connection flags and save an undo-state to get back 00727 * to the state the board was in when we started this function. 00728 * 00729 * After this, we don't add any changes to the undo system, but 00730 * ensure we get back to a point where we can Undo() our changes 00731 * by resetting the connections with ClearFlagOnAllObjects() before 00732 * calling Undo() at the end of the procedure. 00733 */ 00734 ClearFlagOnAllObjects (true, FOUNDFLAG); 00735 IncrementUndoSerialNumber (); 00736 00737 length = XYtoNetLength (x, y, &found); 00738 00739 if (!found) 00740 { 00741 ClearFlagOnAllObjects (false, FOUNDFLAG); 00742 Undo (true); 00743 gui->log (_("No net under cursor.\n")); 00744 return 1; 00745 } 00746 00747 ELEMENT_LOOP (PCB->Data); 00748 { 00749 PIN_LOOP (element); 00750 { 00751 if (TEST_FLAG (FOUNDFLAG, pin)) 00752 { 00753 int ni, nei; 00754 char *ename = element->Name[NAMEONPCB_INDEX].TextString; 00755 char *pname = pin->Number; 00756 char *n; 00757 00758 if (ename && pname) 00759 { 00760 n = Concat (ename, _("-"), pname, NULL); 00761 for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++) 00762 for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++) 00763 { 00764 if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0) 00765 { 00766 netname = PCB->NetlistLib.Menu[ni].Name + 2; 00767 goto got_net_name; /* four for loops deep */ 00768 } 00769 } 00770 } 00771 } 00772 } 00773 END_LOOP; 00774 PAD_LOOP (element); 00775 { 00776 if (TEST_FLAG (FOUNDFLAG, pad)) 00777 { 00778 int ni, nei; 00779 char *ename = element->Name[NAMEONPCB_INDEX].TextString; 00780 char *pname = pad->Number; 00781 char *n; 00782 00783 if (ename && pname) 00784 { 00785 n = Concat (ename, _("-"), pname, NULL); 00786 for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++) 00787 for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++) 00788 { 00789 if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0) 00790 { 00791 netname = PCB->NetlistLib.Menu[ni].Name + 2; 00792 goto got_net_name; /* four for loops deep */ 00793 } 00794 } 00795 } 00796 } 00797 } 00798 END_LOOP; 00799 } 00800 END_LOOP; 00801 00802 got_net_name: 00803 ClearFlagOnAllObjects (false, FOUNDFLAG); 00804 Undo (true); 00805 00806 { 00807 char buf[50]; 00808 pcb_snprintf(buf, sizeof (buf), _("%$m*"), Settings.grid_unit->suffix, length); 00809 if (netname) 00810 gui->log (_("Net \"%s\" length: %s\n"), netname, buf); 00811 else 00812 gui->log (_("Net length: %s\n"), buf); 00813 } 00814 00815 return 0; 00816 } 00817 00818 static int 00819 ReportNetLengthByName (char *tofind, int x, int y) 00820 { 00821 int result; 00822 char *netname = 0; 00823 Coord length = 0; 00824 int found = 0; 00825 int i; 00826 LibraryMenuType *net; 00827 ConnectionType conn; 00828 int net_found = 0; 00829 #if defined(USE_RE) 00830 int use_re = 0; 00831 #endif 00832 #if defined(HAVE_REGCOMP) 00833 regex_t elt_pattern; 00834 regmatch_t match; 00835 #endif 00836 #if defined(HAVE_RE_COMP) 00837 char *elt_pattern; 00838 #endif 00839 00840 if (!PCB) 00841 return 1; 00842 00843 if (!tofind) 00844 return 1; 00845 00846 #if defined(USE_RE) 00847 use_re = 1; 00848 for (i = 0; i < PCB->NetlistLib.MenuN; i++) 00849 { 00850 net = PCB->NetlistLib.Menu + i; 00851 if (strcasecmp (tofind, net->Name + 2) == 0) 00852 use_re = 0; 00853 } 00854 if (use_re) 00855 { 00856 #if defined(HAVE_REGCOMP) 00857 result = 00858 regcomp (&elt_pattern, tofind, 00859 REG_EXTENDED | REG_ICASE | REG_NOSUB); 00860 if (result) 00861 { 00862 char errorstring[128]; 00863 00864 regerror (result, &elt_pattern, errorstring, 128); 00865 Message (_("regexp error: %s\n"), errorstring); 00866 regfree (&elt_pattern); 00867 return (1); 00868 } 00869 #endif 00870 #if defined(HAVE_RE_COMP) 00871 if ((elt_pattern = re_comp (tofind)) != NULL) 00872 { 00873 Message (_("re_comp error: %s\n"), elt_pattern); 00874 return (1); 00875 } 00876 #endif 00877 } 00878 #endif 00879 00880 for (i = 0; i < PCB->NetlistLib.MenuN; i++) 00881 { 00882 net = PCB->NetlistLib.Menu + i; 00883 00884 #if defined(USE_RE) 00885 if (use_re) 00886 { 00887 #if defined(HAVE_REGCOMP) 00888 if (regexec (&elt_pattern, net->Name + 2, 1, &match, 0) != 0) 00889 continue; 00890 #endif 00891 #if defined(HAVE_RE_COMP) 00892 if (re_exec (net->Name + 2) != 1) 00893 continue; 00894 #endif 00895 } 00896 else 00897 #endif 00898 if (strcasecmp (net->Name + 2, tofind)) 00899 continue; 00900 00901 if (SeekPad (net->Entry, &conn, false)) 00902 { 00903 switch (conn.type) 00904 { 00905 case PIN_TYPE: 00906 x = ((PinType *) (conn.ptr2))->X; 00907 y = ((PinType *) (conn.ptr2))->Y; 00908 net_found=1; 00909 break; 00910 case PAD_TYPE: 00911 x = ((PadType *) (conn.ptr2))->Point1.X; 00912 y = ((PadType *) (conn.ptr2))->Point1.Y; 00913 net_found=1; 00914 break; 00915 } 00916 if (net_found) 00917 break; 00918 } 00919 } 00920 00921 if (!net_found) 00922 { 00923 gui->log (_("No net named \"%s\"\n"), tofind); 00924 return 1; 00925 } 00926 00927 #ifdef HAVE_REGCOMP 00928 if (use_re) 00929 regfree (&elt_pattern); 00930 #endif 00931 00932 /* Reset all connection flags and save an undo-state to get back 00933 * to the state the board was in when we started. 00934 * 00935 * After this, we don't add any changes to the undo system, but 00936 * ensure we get back to a point where we can Undo() our changes 00937 * by resetting the connections with ClearFlagOnAllObjects() before 00938 * calling Undo() when we are finished. 00939 */ 00940 ClearFlagOnAllObjects (true, FOUNDFLAG); 00941 IncrementUndoSerialNumber (); 00942 00943 length = XYtoNetLength (x, y, &found); 00944 netname = net->Name + 2; 00945 00946 ClearFlagOnAllObjects (false, FOUNDFLAG); 00947 Undo (true); 00948 00949 if (!found) 00950 { 00951 if (net_found) 00952 gui->log (_("Net found, but no lines or arcs were flagged.\n")); 00953 else 00954 gui->log (_("Net not found.\n")); 00955 00956 return 1; 00957 } 00958 00959 { 00960 char buf[50]; 00961 pcb_snprintf(buf, 50, _("%$m*"), Settings.grid_unit->suffix, length); 00962 if (netname) 00963 gui->log (_("Net \"%s\" length: %s\n"), netname, buf); 00964 else 00965 gui->log (_("Net length: %s\n"), buf); 00966 } 00967 00968 return 0; 00969 } 00970 00971 static const char report_syntax[] = 00972 N_("Report(Object|DrillReport|FoundPins|NetLength|AllNetLengths|[,name])"); 00973 00974 static const char report_help[] = N_("Produce various report."); 00975 00976 /* %start-doc actions Report 00977 00978 @table @code 00979 00980 @item Object 00981 The object under the crosshair will be reported, describing various 00982 aspects of the object. 00983 00984 @item DrillReport 00985 A report summarizing the number of drill sizes used, and how many of 00986 each, will be produced. 00987 00988 @item FoundPins 00989 A report listing all pins and pads which are marked as ``found'' will 00990 be produced. 00991 00992 @item NetLength 00993 The name and length of the net under the crosshair will be reported to 00994 the message log. 00995 00996 @item AllNetLengths 00997 The name and length of the net under the crosshair will be reported to 00998 the message log. An optional parameter specifies mm, mil, pcb, or in 00999 units 01000 01001 @end table 01002 01003 %end-doc */ 01007 static int 01008 Report (int argc, char **argv, Coord x, Coord y) 01009 { 01010 if ((argc < 1) || (argc > 2)) 01011 AUSAGE (report); 01012 else if (strcasecmp (argv[0], "Object") == 0) 01013 { 01014 gui->get_coords (_("Click on an object"), &x, &y); 01015 return ReportDialog (argc - 1, argv + 1, x, y); 01016 } 01017 else if (strcasecmp (argv[0], "DrillReport") == 0) 01018 return ReportDrills (argc - 1, argv + 1, x, y); 01019 else if (strcasecmp (argv[0], "FoundPins") == 0) 01020 return ReportFoundPins (argc - 1, argv + 1, x, y); 01021 else if ((strcasecmp (argv[0], "NetLength") == 0) && (argc == 1)) 01022 return ReportNetLength (argc - 1, argv + 1, x, y); 01023 else if (strcasecmp (argv[0], "AllNetLengths") == 0) 01024 return ReportAllNetLengths (argc - 1, argv + 1, x, y); 01025 else if ((strcasecmp (argv[0], "NetLength") == 0) && (argc == 2)) 01026 return ReportNetLengthByName (argv[1], x, y); 01027 else if (argc == 2) 01028 AUSAGE (report); 01029 else 01030 AFAIL (report); 01031 return 1; 01032 } 01033 01034 HID_Action report_action_list[] = { 01035 {"ReportObject", N_("Click on an object"), ReportDialog, 01036 reportdialog_help, reportdialog_syntax} 01037 , 01038 {"Report", 0, Report, 01039 report_help, report_syntax} 01040 }; 01041 01042 REGISTER_ACTIONS (report_action_list)