pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00036 #ifdef HAVE_CONFIG_H 00037 #include "config.h" 00038 #endif 00039 00040 #ifdef HAVE_SYS_PARAM_H 00041 #include <sys/param.h> 00042 #endif 00043 00044 #include "global.h" 00045 00046 #include <dirent.h> 00047 #ifdef HAVE_PWD_H 00048 #include <pwd.h> 00049 #endif 00050 #include <time.h> 00051 00052 #ifdef HAVE_SYS_SOCKET_H 00053 #include <sys/socket.h> 00054 #endif 00055 00056 #include <sys/stat.h> 00057 00058 #ifdef HAVE_NETINET_IN_H 00059 #include <netinet/in.h> 00060 #endif 00061 00062 #ifdef HAVE_NETDB_H 00063 #include <netdb.h> 00064 #endif 00065 00066 #include <stdio.h> 00067 00068 #ifdef HAVE_STDLIB_H 00069 #include <stdlib.h> 00070 #endif 00071 00072 #ifdef HAVE_STRING_H 00073 #include <string.h> 00074 #endif 00075 00076 #ifdef HAVE_UNISTD_H 00077 #include <unistd.h> 00078 #endif 00079 00080 00081 #include "buffer.h" 00082 #include "change.h" 00083 #include "create.h" 00084 #include "crosshair.h" 00085 #include "data.h" 00086 #include "edif_parse.h" 00087 #include "error.h" 00088 #include "file.h" 00089 #include "hid.h" 00090 #include "layerflags.h" 00091 #include "misc.h" 00092 #include "mymem.h" 00093 #include "parse_l.h" 00094 #include "pcb-printf.h" 00095 #include "polygon.h" 00096 #include "rats.h" 00097 #include "remove.h" 00098 #include "set.h" 00099 #include "strflags.h" 00100 00101 #ifdef HAVE_LIBDMALLOC 00102 #include <dmalloc.h> 00103 #endif 00104 00105 #if !defined(HAS_ATEXIT) && !defined(HAS_ON_EXIT) 00106 /* --------------------------------------------------------------------------- 00107 * some local identifiers for OS without an atexit() or on_exit() 00108 * call 00109 */ 00110 static char TMPFilename[80]; 00111 #endif 00112 00113 /* --------------------------------------------------------------------------- 00114 * some local prototypes 00115 */ 00116 static void PrintQuotedString (FILE *, char *); 00117 static void WritePCBInfoHeader (FILE *); 00118 static void WritePCBDataHeader (FILE *); 00119 static void WritePCBFontData (FILE *); 00120 static void WriteViaData (FILE *, DataType *); 00121 static void WritePCBRatData (FILE *); 00122 static void WriteElementData (FILE *, DataType *); 00123 static void WriteLayerData (FILE *, Cardinal, LayerType *); 00124 static int WritePCB (FILE *); 00125 static int WritePCBFile (char *); 00126 static int WritePipe (char *, bool); 00127 static int ParseLibraryTree (void); 00128 static int LoadNewlibFootprintsFromDir(char *path, char *toppath, bool recursive); 00129 00130 /* --------------------------------------------------------------------------- 00131 * Flag helper functions 00132 */ 00133 00134 #define F2S(OBJ, TYPE) flags_to_string ((OBJ)->Flags, TYPE) 00135 00136 /* --------------------------------------------------------------------------- */ 00137 00138 /* The idea here is to avoid gratuitously breaking backwards 00139 compatibility due to a new but rarely used feature. The first such 00140 case, for example, was the polygon Hole - if your design included 00141 polygon holes, you needed a newer PCB to read it, but if your 00142 design didn't include holes, PCB would produce a file that older 00143 PCBs could read, if only it had the correct version number in it. 00144 00145 If, however, you have to add or change a feature that really does 00146 require a new PCB version all the time, it's time to remove all the 00147 tests below and just always output the new version. 00148 00149 Note: Best practices here is to add support for a feature *first* 00150 (and bump PCB_FILE_VERSION in file.h), and note the version that 00151 added that support below, and *later* update the file format to 00152 need that version (which may then be older than PCB_FILE_VERSION). 00153 Hopefully, that allows for one release between adding support and 00154 needing it, which should minimize breakage. Of course, that's not 00155 *always* possible, practical, or desirable. 00156 00157 */ 00158 00159 00160 #define PCB_FILE_VERSION_BURIED_VIAS 20170218 00162 #define PCB_FILE_VERSION_HOLES 20100606 00164 #define PCB_FILE_VERSION_BASELINE 20091103 00166 int 00167 PCBFileVersionNeeded (void) 00168 { 00169 ALLPOLYGON_LOOP (PCB->Data); 00170 { 00171 if (polygon->HoleIndexN > 0) 00172 return PCB_FILE_VERSION_HOLES; 00173 } 00174 ENDALL_LOOP; 00175 00176 VIA_LOOP (PCB->Data); 00177 if ((via->BuriedFrom != 0) || (via->BuriedTo != 0)) 00178 return PCB_FILE_VERSION_BURIED_VIAS; 00179 END_LOOP; 00180 00181 return PCB_FILE_VERSION_BASELINE; 00182 } 00183 00184 /* --------------------------------------------------------------------------- */ 00185 00186 static int 00187 string_cmp (const char *a, const char *b) 00188 { 00189 while (*a && *b) 00190 { 00191 if (isdigit ((int) *a) && isdigit ((int) *b)) 00192 { 00193 int ia = atoi (a); 00194 int ib = atoi (b); 00195 if (ia != ib) 00196 return ia - ib; 00197 while (isdigit ((int) *a) && *(a+1)) 00198 a++; 00199 while (isdigit ((int) *b) && *(b+1)) 00200 b++; 00201 } 00202 else if (tolower ((int) *a) != tolower ((int) *b)) 00203 return tolower ((int) *a) - tolower ((int) *b); 00204 a++; 00205 b++; 00206 } 00207 if (*a) 00208 return 1; 00209 if (*b) 00210 return -1; 00211 return 0; 00212 } 00213 00214 static int netlist_sort_offset = 0; 00215 00216 static int 00217 netlist_sort (const void *va, const void *vb) 00218 { 00219 LibraryMenuType *am = (LibraryMenuType *) va; 00220 LibraryMenuType *bm = (LibraryMenuType *) vb; 00221 char *a = am->Name; 00222 char *b = bm->Name; 00223 if (*a == '~') 00224 a++; 00225 if (*b == '~') 00226 b++; 00227 return string_cmp (a, b); 00228 } 00229 00230 static int 00231 netnode_sort (const void *va, const void *vb) 00232 { 00233 LibraryEntryType *am = (LibraryEntryType *) va; 00234 LibraryEntryType *bm = (LibraryEntryType *) vb; 00235 char *a = am->ListEntry; 00236 char *b = bm->ListEntry; 00237 return string_cmp (a, b); 00238 } 00239 00240 static void 00241 sort_library (LibraryType *lib) 00242 { 00243 int i; 00244 qsort (lib->Menu, lib->MenuN, sizeof (lib->Menu[0]), netlist_sort); 00245 for (i = 0; i < lib->MenuN; i++) 00246 qsort (lib->Menu[i].Entry, 00247 lib->Menu[i].EntryN, sizeof (lib->Menu[i].Entry[0]), netnode_sort); 00248 } 00249 00250 void 00251 sort_netlist () 00252 { 00253 netlist_sort_offset = 2; 00254 sort_library (&(PCB->NetlistLib)); 00255 netlist_sort_offset = 0; 00256 } 00257 00261 FILE * 00262 CheckAndOpenFile (char *Filename, bool Confirm, bool AllButton, 00263 bool * WasAllButton, bool * WasCancelButton) 00264 { 00265 FILE *fp = NULL; 00266 struct stat buffer; 00267 char message[MAXPATHLEN + 80]; 00268 int response; 00269 00270 if (Filename && *Filename) 00271 { 00272 if (!stat (Filename, &buffer) && Confirm) 00273 { 00274 sprintf (message, _("File '%s' exists, use anyway?"), Filename); 00275 if (WasAllButton) 00276 *WasAllButton = false; 00277 if (WasCancelButton) 00278 *WasCancelButton = false; 00279 if (AllButton) 00280 response = 00281 gui->confirm_dialog (message, "Cancel", "Ok", 00282 AllButton ? "Sequence OK" : 0); 00283 else 00284 response = 00285 gui->confirm_dialog (message, "Cancel", "Ok", "Sequence OK"); 00286 00287 switch (response) 00288 { 00289 case 2: 00290 if (WasAllButton) 00291 *WasAllButton = true; 00292 break; 00293 case 0: 00294 if (WasCancelButton) 00295 *WasCancelButton = true; 00296 } 00297 } 00298 if ((fp = fopen (Filename, "w")) == NULL) 00299 OpenErrorMessage (Filename); 00300 } 00301 return (fp); 00302 } 00303 00307 FILE * 00308 OpenConnectionDataFile (void) 00309 { 00310 char *fname; 00311 FILE *fp; 00312 static char * default_file = NULL; 00313 bool result; /* not used */ 00314 00315 /* CheckAndOpenFile deals with the case where fname already exists */ 00316 fname = gui->fileselect (_("Save Connection Data As ..."), 00317 _("Choose a file to save all connection data to."), 00318 default_file, ".net", "connection_data", 00319 0); 00320 if (fname == NULL) 00321 return NULL; 00322 00323 if (default_file != NULL) 00324 { 00325 free (default_file); 00326 default_file = NULL; 00327 } 00328 00329 if (fname && *fname) 00330 default_file = strdup (fname); 00331 00332 fp = CheckAndOpenFile (fname, true, false, &result, NULL); 00333 free (fname); 00334 00335 return fp; 00336 } 00337 00341 int 00342 SaveBufferElements (char *Filename) 00343 { 00344 int result; 00345 00346 if (SWAP_IDENT) 00347 SwapBuffers (); 00348 result = WritePipe (Filename, false); 00349 if (SWAP_IDENT) 00350 SwapBuffers (); 00351 return (result); 00352 } 00353 00357 int 00358 SavePCB (char *file) 00359 { 00360 int retcode; 00361 00362 if (gui->notify_save_pcb == NULL) 00363 return WritePipe (file, true); 00364 00365 gui->notify_save_pcb (file, false); 00366 retcode = WritePipe (file, true); 00367 gui->notify_save_pcb (file, true); 00368 00369 return retcode; 00370 } 00371 00378 static void 00379 set_some_route_style () 00380 { 00381 if (hid_get_flag ("style")) 00382 return; 00383 SetLineSize (PCB->RouteStyle[0].Thick); 00384 SetViaSize (PCB->RouteStyle[0].Diameter, true); 00385 SetViaDrillingHole (PCB->RouteStyle[0].Hole, true); 00386 SetKeepawayWidth (PCB->RouteStyle[0].Keepaway); 00387 } 00388 00398 static int 00399 real_load_pcb (char *Filename, bool revert) 00400 { 00401 const char *unit_suffix, *grid_size; 00402 char *new_filename; 00403 PCBType *newPCB = CreateNewPCB (); 00404 PCBType *oldPCB; 00405 #ifdef DEBUG 00406 double elapsed; 00407 clock_t start, end; 00408 00409 start = clock (); 00410 #endif 00411 00412 new_filename = strdup (Filename); 00413 00414 oldPCB = PCB; 00415 PCB = newPCB; 00416 00417 /* mark the default font invalid to know if the file has one */ 00418 newPCB->Font.Valid = false; 00419 00420 /* new data isn't added to the undo list */ 00421 if (!ParsePCB (PCB, new_filename)) 00422 { 00423 RemovePCB (oldPCB); 00424 00425 CreateNewPCBPost (PCB, 0); 00426 ResetStackAndVisibility (); 00427 AssignDefaultLayerTypes(); 00428 00429 /* update cursor location */ 00430 Crosshair.X = CLAMP (PCB->CursorX, 0, PCB->MaxWidth); 00431 Crosshair.Y = CLAMP (PCB->CursorY, 0, PCB->MaxHeight); 00432 00433 /* update cursor confinement and output area (scrollbars) */ 00434 ChangePCBSize (PCB->MaxWidth, PCB->MaxHeight); 00435 00436 /* enable default font if necessary */ 00437 if (!PCB->Font.Valid) 00438 { 00439 Message (_ 00440 ("File '%s' has no font information, using default font\n"), 00441 new_filename); 00442 PCB->Font.Valid = true; 00443 } 00444 00445 /* clear 'changed flag' */ 00446 SetChangedFlag (false); 00447 PCB->Filename = new_filename; 00448 /* just in case a bad file saved file is loaded */ 00449 00450 /* Use attribute PCB::grid::unit as unit, if we can */ 00451 unit_suffix = AttributeGet (PCB, "PCB::grid::unit"); 00452 if (unit_suffix && *unit_suffix) 00453 { 00454 const Unit *new_unit = get_unit_struct (unit_suffix); 00455 if (new_unit) 00456 Settings.grid_unit = new_unit; 00457 } 00458 AttributePut (PCB, "PCB::grid::unit", Settings.grid_unit->suffix); 00459 Settings.increments = get_increments_struct (Settings.grid_unit->family); 00460 00461 /* Use attribute PCB::grid::size as size, if we can */ 00462 grid_size = AttributeGet (PCB, "PCB::grid::size"); 00463 if (grid_size) 00464 { 00465 PCB->Grid = GetValue (grid_size, NULL, NULL); 00466 } 00467 00468 sort_netlist (); 00469 00470 set_some_route_style (); 00471 00472 if (revert) 00473 hid_actionl ("PCBChanged", "revert", NULL); 00474 else 00475 hid_action ("PCBChanged"); 00476 00477 #ifdef DEBUG 00478 end = clock (); 00479 elapsed = ((double) (end - start)) / CLOCKS_PER_SEC; 00480 gui->log ("Loading file %s took %f seconds of CPU time\n", 00481 new_filename, elapsed); 00482 #endif 00483 00484 return (0); 00485 } 00486 PCB = oldPCB; 00487 hid_action ("PCBChanged"); 00488 00489 /* release unused memory */ 00490 RemovePCB (newPCB); 00491 return (1); 00492 } 00493 00497 int 00498 LoadPCB (char *file) 00499 { 00500 return real_load_pcb (file, false); 00501 } 00502 00506 int 00507 RevertPCB (void) 00508 { 00509 return real_load_pcb (PCB->Filename, true); 00510 } 00511 00515 static void 00516 PrintQuotedString (FILE * FP, char *S) 00517 { 00518 static DynamicStringType ds; 00519 00520 CreateQuotedString (&ds, S); 00521 fputs (ds.Data, FP); 00522 } 00523 00527 static void 00528 WriteAttributeList (FILE * FP, AttributeListType *list, char *prefix) 00529 { 00530 int i; 00531 00532 for (i = 0; i < list->Number; i++) 00533 { 00534 fprintf (FP, "%sAttribute(", prefix); 00535 PrintQuotedString(FP, list->List[i].name); 00536 fputs (" ", FP); 00537 PrintQuotedString(FP, list->List[i].value); 00538 fputs (")\n", FP); 00539 } 00540 } 00541 00545 static void 00546 WritePCBInfoHeader (FILE * FP) 00547 { 00548 /* write some useful comments */ 00549 fprintf (FP, "# release: %s " VERSION "\n", Progname); 00550 00551 /* avoid writing things like user name or date, as these cause merge 00552 * conflicts in collaborative environments using version control systems 00553 */ 00554 } 00555 00562 static void 00563 WritePCBDataHeader (FILE * FP) 00564 { 00565 Cardinal group; 00566 00567 /* 00568 * ************************** README ******************* 00569 * ************************** README ******************* 00570 * 00571 * If the file format is modified in any way, update 00572 * PCB_FILE_VERSION in file.h as well as PCBFileVersionNeeded() 00573 * at the top of this file. 00574 * 00575 * ************************** README ******************* 00576 * ************************** README ******************* 00577 */ 00578 00579 fprintf (FP, "\n# To read pcb files, the pcb version (or the git source date) must be >= the file version\n"); 00580 fprintf (FP, "FileVersion[%i]\n", PCBFileVersionNeeded ()); 00581 00582 fputs ("\nPCB[", FP); 00583 PrintQuotedString (FP, (char *)EMPTY (PCB->Name)); 00584 pcb_fprintf (FP, " %mr %mr]\n\n", PCB->MaxWidth, PCB->MaxHeight); 00585 pcb_fprintf (FP, "Grid[%mr %mr %mr %d]\n", PCB->Grid, 00586 PCB->GridOffsetX, PCB->GridOffsetY, Settings.DrawGrid); 00587 /* PolyArea should be output in square cmils, no suffix */ 00588 fprintf (FP, "PolyArea[%s]\n", c_dtostr (COORD_TO_MIL (COORD_TO_MIL (PCB->IsleArea) * 100) * 100)); 00589 pcb_fprintf (FP, "Thermal[%s]\n", c_dtostr (PCB->ThermScale)); 00590 pcb_fprintf (FP, "DRC[%mr %mr %mr %mr %mr %mr]\n", PCB->Bloat, PCB->Shrink, 00591 PCB->minWid, PCB->minSlk, PCB->minDrill, PCB->minRing); 00592 fprintf (FP, "Flags(%s)\n", pcbflags_to_string(PCB->Flags)); 00593 fprintf (FP, "Groups(\"%s\")\n", LayerGroupsToString (&PCB->LayerGroups)); 00594 fputs ("Styles[\"", FP); 00595 for (group = 0; group < NUM_STYLES - 1; group++) 00596 pcb_fprintf (FP, "%s,%mr,%mr,%mr,%mr:", PCB->RouteStyle[group].Name, 00597 PCB->RouteStyle[group].Thick, 00598 PCB->RouteStyle[group].Diameter, 00599 PCB->RouteStyle[group].Hole, PCB->RouteStyle[group].Keepaway); 00600 pcb_fprintf (FP, "%s,%mr,%mr,%mr,%mr\"]\n\n", PCB->RouteStyle[group].Name, 00601 PCB->RouteStyle[group].Thick, 00602 PCB->RouteStyle[group].Diameter, 00603 PCB->RouteStyle[group].Hole, PCB->RouteStyle[group].Keepaway); 00604 } 00605 00609 static void 00610 WritePCBFontData (FILE * FP) 00611 { 00612 Cardinal i, j; 00613 LineType *line; 00614 FontType *font; 00615 00616 for (font = &PCB->Font, i = 0; i <= MAX_FONTPOSITION; i++) 00617 { 00618 if (!font->Symbol[i].Valid) 00619 continue; 00620 00621 if (isprint (i)) 00622 pcb_fprintf (FP, "Symbol['%c' %mr]\n(\n", i, font->Symbol[i].Delta); 00623 else 00624 pcb_fprintf (FP, "Symbol[%i %mr]\n(\n", i, font->Symbol[i].Delta); 00625 00626 line = font->Symbol[i].Line; 00627 for (j = font->Symbol[i].LineN; j; j--, line++) 00628 pcb_fprintf (FP, "\tSymbolLine[%mr %mr %mr %mr %mr]\n", 00629 line->Point1.X, line->Point1.Y, 00630 line->Point2.X, line->Point2.Y, line->Thickness); 00631 fputs (")\n", FP); 00632 } 00633 } 00634 00638 static void 00639 WriteViaData (FILE * FP, DataType *Data) 00640 { 00641 GList *iter; 00642 /* write information about vias */ 00643 for (iter = Data->Via; iter != NULL; iter = g_list_next (iter)) 00644 { 00645 PinType *via = iter->data; 00646 pcb_fprintf (FP, "Via[%mr %mr %mr %mr %mr %mr ", via->X, via->Y, 00647 via->Thickness, via->Clearance, via->Mask, via->DrillingHole); 00648 if ((via->BuriedFrom != 0) || (via->BuriedTo != 0)) 00649 fprintf (FP, "%d %d ", via->BuriedFrom, via->BuriedTo); 00650 PrintQuotedString (FP, (char *)EMPTY (via->Name)); 00651 fprintf (FP, " %s]\n", F2S (via, VIA_TYPE)); 00652 } 00653 } 00654 00658 static void 00659 WritePCBRatData (FILE * FP) 00660 { 00661 GList *iter; 00662 /* write information about rats */ 00663 for (iter = PCB->Data->Rat; iter != NULL; iter = g_list_next (iter)) 00664 { 00665 RatType *line = iter->data; 00666 pcb_fprintf (FP, "Rat[%mr %mr %d %mr %mr %d ", 00667 line->Point1.X, line->Point1.Y, line->group1, 00668 line->Point2.X, line->Point2.Y, line->group2); 00669 fprintf (FP, " %s]\n", F2S (line, RATLINE_TYPE)); 00670 } 00671 } 00672 00676 static void 00677 WritePCBNetlistData (FILE * FP) 00678 { 00679 /* write out the netlist if it exists */ 00680 if (PCB->NetlistLib.MenuN) 00681 { 00682 int n, p; 00683 fprintf (FP, "NetList()\n(\n"); 00684 00685 for (n = 0; n < PCB->NetlistLib.MenuN; n++) 00686 { 00687 LibraryMenuType *menu = &PCB->NetlistLib.Menu[n]; 00688 fprintf (FP, "\tNet("); 00689 PrintQuotedString(FP, &menu->Name[2]); 00690 fprintf (FP, " "); 00691 PrintQuotedString(FP, (char *)UNKNOWN (menu->Style)); 00692 fprintf (FP, ")\n\t(\n"); 00693 for (p = 0; p < menu->EntryN; p++) 00694 { 00695 LibraryEntryType *entry = &menu->Entry[p]; 00696 fprintf (FP, "\t\tConnect("); 00697 PrintQuotedString (FP, entry->ListEntry); 00698 fprintf (FP, ")\n"); 00699 } 00700 fprintf (FP, "\t)\n"); 00701 } 00702 fprintf (FP, ")\n"); 00703 } 00704 } 00705 00709 static void 00710 WriteElementData (FILE * FP, DataType *Data) 00711 { 00712 GList *n, *p; 00713 for (n = Data->Element; n != NULL; n = g_list_next (n)) 00714 { 00715 ElementType *element = n->data; 00716 00717 /* only non empty elements */ 00718 if (!element->LineN && !element->PinN && !element->ArcN 00719 && !element->PadN) 00720 continue; 00721 /* the coordinates and text-flags are the same for 00722 * both names of an element 00723 */ 00724 fprintf (FP, "\nElement[%s ", F2S (element, ELEMENT_TYPE)); 00725 PrintQuotedString (FP, (char *)EMPTY (DESCRIPTION_NAME (element))); 00726 fputc (' ', FP); 00727 PrintQuotedString (FP, (char *)EMPTY (NAMEONPCB_NAME (element))); 00728 fputc (' ', FP); 00729 PrintQuotedString (FP, (char *)EMPTY (VALUE_NAME (element))); 00730 pcb_fprintf (FP, " %mr %mr %mr %mr %d %d %s]\n(\n", 00731 element->MarkX, element->MarkY, 00732 DESCRIPTION_TEXT (element).X - element->MarkX, 00733 DESCRIPTION_TEXT (element).Y - element->MarkY, 00734 DESCRIPTION_TEXT (element).Direction, 00735 DESCRIPTION_TEXT (element).Scale, 00736 F2S (&(DESCRIPTION_TEXT (element)), ELEMENTNAME_TYPE)); 00737 WriteAttributeList (FP, &element->Attributes, "\t"); 00738 for (p = element->Pin; p != NULL; p = g_list_next (p)) 00739 { 00740 PinType *pin = p->data; 00741 pcb_fprintf (FP, "\tPin[%mr %mr %mr %mr %mr %mr ", 00742 pin->X - element->MarkX, 00743 pin->Y - element->MarkY, 00744 pin->Thickness, pin->Clearance, 00745 pin->Mask, pin->DrillingHole); 00746 PrintQuotedString (FP, (char *)EMPTY (pin->Name)); 00747 fprintf (FP, " "); 00748 PrintQuotedString (FP, (char *)EMPTY (pin->Number)); 00749 fprintf (FP, " %s]\n", F2S (pin, PIN_TYPE)); 00750 } 00751 for (p = element->Pad; p != NULL; p = g_list_next (p)) 00752 { 00753 PadType *pad = p->data; 00754 pcb_fprintf (FP, "\tPad[%mr %mr %mr %mr %mr %mr %mr ", 00755 pad->Point1.X - element->MarkX, 00756 pad->Point1.Y - element->MarkY, 00757 pad->Point2.X - element->MarkX, 00758 pad->Point2.Y - element->MarkY, 00759 pad->Thickness, pad->Clearance, pad->Mask); 00760 PrintQuotedString (FP, (char *)EMPTY (pad->Name)); 00761 fprintf (FP, " "); 00762 PrintQuotedString (FP, (char *)EMPTY (pad->Number)); 00763 fprintf (FP, " %s]\n", F2S (pad, PAD_TYPE)); 00764 } 00765 for (p = element->Line; p != NULL; p = g_list_next (p)) 00766 { 00767 LineType *line = p->data; 00768 pcb_fprintf (FP, "\tElementLine [%mr %mr %mr %mr %mr]\n", 00769 line->Point1.X - element->MarkX, 00770 line->Point1.Y - element->MarkY, 00771 line->Point2.X - element->MarkX, 00772 line->Point2.Y - element->MarkY, 00773 line->Thickness); 00774 } 00775 for (p = element->Arc; p != NULL; p = g_list_next (p)) 00776 { 00777 ArcType *arc = p->data; 00778 pcb_fprintf (FP, "\tElementArc [%mr %mr %mr %mr %ma %ma %mr]\n", 00779 arc->X - element->MarkX, 00780 arc->Y - element->MarkY, 00781 arc->Width, arc->Height, 00782 arc->StartAngle, arc->Delta, 00783 arc->Thickness); 00784 } 00785 fputs ("\n\t)\n", FP); 00786 } 00787 } 00788 00792 static void 00793 WriteLayerData (FILE * FP, Cardinal Number, LayerType *layer) 00794 { 00795 GList *n; 00796 /* write information about non empty layers */ 00797 if (layer->LineN || layer->ArcN || layer->TextN || layer->PolygonN || 00798 (layer->Name && *layer->Name)) 00799 { 00800 fprintf (FP, "Layer(%i ", (int) Number + 1); 00801 PrintQuotedString (FP, (char *)EMPTY (layer->Name)); 00802 fprintf (FP, " \"%s\")\n(\n", layertype_to_string (layer->Type)); 00803 WriteAttributeList (FP, &layer->Attributes, "\t"); 00804 00805 for (n = layer->Line; n != NULL; n = g_list_next (n)) 00806 { 00807 LineType *line = n->data; 00808 pcb_fprintf (FP, "\tLine[%mr %mr %mr %mr %mr %mr %s]\n", 00809 line->Point1.X, line->Point1.Y, 00810 line->Point2.X, line->Point2.Y, 00811 line->Thickness, line->Clearance, 00812 F2S (line, LINE_TYPE)); 00813 } 00814 for (n = layer->Arc; n != NULL; n = g_list_next (n)) 00815 { 00816 ArcType *arc = n->data; 00817 pcb_fprintf (FP, "\tArc[%mr %mr %mr %mr %mr %mr %ma %ma %s]\n", 00818 arc->X, arc->Y, arc->Width, 00819 arc->Height, arc->Thickness, 00820 arc->Clearance, arc->StartAngle, 00821 arc->Delta, F2S (arc, ARC_TYPE)); 00822 } 00823 for (n = layer->Text; n != NULL; n = g_list_next (n)) 00824 { 00825 TextType *text = n->data; 00826 pcb_fprintf (FP, "\tText[%mr %mr %d %d ", 00827 text->X, text->Y, 00828 text->Direction, text->Scale); 00829 PrintQuotedString (FP, (char *)EMPTY (text->TextString)); 00830 fprintf (FP, " %s]\n", F2S (text, TEXT_TYPE)); 00831 } 00832 for (n = layer->Polygon; n != NULL; n = g_list_next (n)) 00833 { 00834 PolygonType *polygon = n->data; 00835 int p, i = 0; 00836 Cardinal hole = 0; 00837 fprintf (FP, "\tPolygon(%s)\n\t(", F2S (polygon, POLYGON_TYPE)); 00838 for (p = 0; p < polygon->PointN; p++) 00839 { 00840 PointType *point = &polygon->Points[p]; 00841 00842 if (hole < polygon->HoleIndexN && 00843 p == polygon->HoleIndex[hole]) 00844 { 00845 if (hole > 0) 00846 fputs ("\n\t\t)", FP); 00847 fputs ("\n\t\tHole (", FP); 00848 hole++; 00849 i = 0; 00850 } 00851 00852 if (i++ % 5 == 0) 00853 { 00854 fputs ("\n\t\t", FP); 00855 if (hole) 00856 fputs ("\t", FP); 00857 } 00858 pcb_fprintf (FP, "[%mr %mr] ", point->X, point->Y); 00859 } 00860 if (hole > 0) 00861 fputs ("\n\t\t)", FP); 00862 fputs ("\n\t)\n", FP); 00863 } 00864 fputs (")\n", FP); 00865 } 00866 } 00867 00871 static int 00872 WriteBuffer (FILE * FP) 00873 { 00874 Cardinal i; 00875 00876 WriteViaData (FP, PASTEBUFFER->Data); 00877 WriteElementData (FP, PASTEBUFFER->Data); 00878 for (i = 0; i < max_copper_layer + SILK_LAYER; i++) 00879 WriteLayerData (FP, i, &(PASTEBUFFER->Data->Layer[i])); 00880 return (STATUS_OK); 00881 } 00882 00886 static int 00887 WritePCB (FILE * FP) 00888 { 00889 Cardinal i; 00890 if (Settings.SaveMetricOnly) 00891 set_allow_readable (ALLOW_MM); 00892 else 00893 set_allow_readable (ALLOW_READABLE); 00894 00895 WritePCBInfoHeader (FP); 00896 WritePCBDataHeader (FP); 00897 WritePCBFontData (FP); 00898 WriteAttributeList (FP, &PCB->Attributes, ""); 00899 WriteViaData (FP, PCB->Data); 00900 WriteElementData (FP, PCB->Data); 00901 WritePCBRatData (FP); 00902 for (i = 0; i < max_copper_layer + SILK_LAYER; i++) 00903 WriteLayerData (FP, i, &(PCB->Data->Layer[i])); 00904 WritePCBNetlistData (FP); 00905 00906 return (STATUS_OK); 00907 } 00908 00912 static int 00913 WritePCBFile (char *Filename) 00914 { 00915 FILE *fp; 00916 int result; 00917 00918 if ((fp = fopen (Filename, "w")) == NULL) 00919 { 00920 OpenErrorMessage (Filename); 00921 return (STATUS_ERROR); 00922 } 00923 result = WritePCB (fp); 00924 fclose (fp); 00925 return (result); 00926 } 00927 00932 static int 00933 WritePipe (char *Filename, bool thePcb) 00934 { 00935 FILE *fp; 00936 int result; 00937 char *p; 00938 static DynamicStringType command; 00939 int used_popen = 0; 00940 00941 if (EMPTY_STRING_P (Settings.SaveCommand)) 00942 { 00943 fp = fopen (Filename, "w"); 00944 if (fp == 0) 00945 { 00946 Message ("Unable to write to file %s\n", Filename); 00947 return STATUS_ERROR; 00948 } 00949 } 00950 else 00951 { 00952 used_popen = 1; 00953 /* setup commandline */ 00954 DSClearString (&command); 00955 for (p = Settings.SaveCommand; *p; p++) 00956 { 00957 /* copy character if not special or add string to command */ 00958 if (!(*p == '%' && *(p + 1) == 'f')) 00959 DSAddCharacter (&command, *p); 00960 else 00961 { 00962 DSAddString (&command, Filename); 00963 00964 /* skip the character */ 00965 p++; 00966 } 00967 } 00968 DSAddCharacter (&command, '\0'); 00969 printf ("write to pipe \"%s\"\n", command.Data); 00970 if ((fp = popen (command.Data, "w")) == NULL) 00971 { 00972 PopenErrorMessage (command.Data); 00973 return (STATUS_ERROR); 00974 } 00975 } 00976 if (thePcb) 00977 { 00978 if (PCB->is_footprint) 00979 { 00980 WriteElementData (fp, PCB->Data); 00981 result = 0; 00982 } 00983 else 00984 result = WritePCB (fp); 00985 } 00986 else 00987 result = WriteBuffer (fp); 00988 00989 if (used_popen) 00990 return (pclose (fp) ? STATUS_ERROR : result); 00991 return (fclose (fp) ? STATUS_ERROR : result); 00992 } 00993 01000 void 01001 SaveInTMP (void) 01002 { 01003 char filename[80]; 01004 01005 /* memory might have been released before this function is called */ 01006 if (PCB && PCB->Changed) 01007 { 01008 sprintf (filename, EMERGENCY_NAME, (int) getpid ()); 01009 Message (_("Trying to save your layout in '%s'\n"), filename); 01010 WritePCBFile (filename); 01011 } 01012 } 01013 01019 static bool dont_save_any_more = false; 01020 void 01021 EmergencySave (void) 01022 { 01023 01024 if (!dont_save_any_more) 01025 { 01026 SaveInTMP (); 01027 dont_save_any_more = true; 01028 } 01029 } 01030 01031 void 01032 DisableEmergencySave (void) 01033 { 01034 dont_save_any_more = true; 01035 } 01036 01037 static hidval backup_timer; 01038 01047 static void 01048 backup_cb (hidval data) 01049 { 01050 backup_timer.ptr = NULL; 01051 Backup (); 01052 if (Settings.BackupInterval > 0 && gui->add_timer) 01053 backup_timer = gui->add_timer (backup_cb, 01054 1000 * Settings.BackupInterval, data); 01055 } 01056 01057 void 01058 EnableAutosave (void) 01059 { 01060 hidval x; 01061 01062 x.ptr = NULL; 01063 01064 /* If we already have a timer going, then cancel it out */ 01065 if (backup_timer.ptr != NULL && gui->stop_timer) 01066 gui->stop_timer (backup_timer); 01067 01068 backup_timer.ptr = NULL; 01069 /* Start up a new timer */ 01070 if (Settings.BackupInterval > 0 && gui->add_timer) 01071 backup_timer = gui->add_timer (backup_cb, 01072 1000 * Settings.BackupInterval, 01073 x); 01074 } 01075 01083 void 01084 Backup (void) 01085 { 01086 char *filename = NULL; 01087 01088 if( PCB && PCB->Filename ) 01089 { 01090 filename = (char *) malloc (sizeof (char) * (strlen (PCB->Filename) + 2)); 01091 if (filename == NULL) 01092 { 01093 fprintf (stderr, "Backup(): malloc failed\n"); 01094 exit (1); 01095 } 01096 sprintf (filename, "%s~", PCB->Filename); 01097 } 01098 else 01099 { 01100 /* BACKUP_NAME has %.8i which will be replaced by the process ID */ 01101 filename = (char *) malloc (sizeof (char) * (strlen (BACKUP_NAME) + 8)); 01102 if (filename == NULL) 01103 { 01104 fprintf (stderr, "Backup(): malloc failed\n"); 01105 exit (1); 01106 } 01107 sprintf (filename, BACKUP_NAME, (int) getpid ()); 01108 } 01109 01110 WritePCBFile (filename); 01111 free (filename); 01112 } 01113 01114 #if !defined(HAS_ATEXIT) && !defined(HAS_ON_EXIT) 01115 01123 void 01124 SaveTMPData (void) 01125 { 01126 sprintf (TMPFilename, EMERGENCY_NAME, (int) getpid ()); 01127 WritePCBFile (TMPFilename); 01128 } 01129 01133 void 01134 RemoveTMPData (void) 01135 { 01136 unlink (TMPFilename); 01137 } 01138 #endif 01139 01148 static int 01149 LoadNewlibFootprintsFromDir(char *libpath, char *toppath, bool recursive) 01150 { 01151 char olddir[MAXPATHLEN + 1]; /* The directory we start out in (cwd) */ 01152 char subdir[MAXPATHLEN + 1]; /* The directory holding footprints to load */ 01153 DIR *subdirobj; /* Interable object holding all subdir entries */ 01154 struct dirent *subdirentry; /* Individual subdir entry */ 01155 struct stat buffer; /* Buffer used in stat */ 01156 LibraryMenuType *menu = NULL; /* Pointer to PCB's library menu structure */ 01157 LibraryEntryType *entry; /* Pointer to individual menu entry */ 01158 size_t l; 01159 size_t len; 01160 int n_footprints = 0; /* Running count of footprints found in this subdir */ 01161 01162 /* Cache old dir, then cd into subdir because stat is given relative file names. */ 01163 memset (subdir, 0, sizeof subdir); 01164 memset (olddir, 0, sizeof olddir); 01165 if (GetWorkingDirectory (olddir) == NULL) 01166 { 01167 Message (_("LoadNewlibFootprintsFromDir: Could not determine initial working directory\n")); 01168 return 0; 01169 } 01170 01171 if (strcmp (libpath, "(local)") == 0) 01172 strcpy (subdir, "."); 01173 else 01174 strcpy (subdir, libpath); 01175 01176 if (chdir (subdir)) 01177 { 01178 ChdirErrorMessage (subdir); 01179 return 0; 01180 } 01181 01182 /* Determine subdir is abs path */ 01183 if (GetWorkingDirectory (subdir) == NULL) 01184 { 01185 Message (_("LoadNewlibFootprintsFromDir: Could not determine new working directory\n")); 01186 if (chdir (olddir)) 01187 ChdirErrorMessage (olddir); 01188 return 0; 01189 } 01190 01191 /* First try opening the directory specified by path */ 01192 if ( (subdirobj = opendir (subdir)) == NULL ) 01193 { 01194 OpendirErrorMessage (subdir); 01195 if (chdir (olddir)) 01196 ChdirErrorMessage (olddir); 01197 return 0; 01198 } 01199 01200 /* Get pointer to memory holding menu */ 01201 menu = GetLibraryMenuMemory (&Library); 01202 /* Populate menuname and path vars */ 01203 menu->Name = strdup (subdir); 01204 menu->directory = strdup (toppath); 01205 01206 /* Now loop over files in this directory looking for files. 01207 * We ignore certain files which are not footprints. 01208 */ 01209 while ((subdirentry = readdir (subdirobj)) != NULL) 01210 { 01211 #ifdef DEBUG 01212 /* printf("... Examining file %s ... \n", subdirentry->d_name); */ 01213 #endif 01214 01215 /* Ignore non-footprint files found in this directory 01216 * We're skipping .png and .html because those 01217 * may exist in a library tree to provide an html browsable 01218 * index of the library. 01219 */ 01220 l = strlen (subdirentry->d_name); 01221 if (!stat (subdirentry->d_name, &buffer) && S_ISREG (buffer.st_mode) 01222 && subdirentry->d_name[0] != '.' 01223 && NSTRCMP (subdirentry->d_name, "CVS") != 0 01224 && NSTRCMP (subdirentry->d_name, "Makefile") != 0 01225 && NSTRCMP (subdirentry->d_name, "Makefile.am") != 0 01226 && NSTRCMP (subdirentry->d_name, "Makefile.in") != 0 01227 && (l < 4 || NSTRCMP(subdirentry->d_name + (l - 4), ".png") != 0) 01228 && (l < 5 || NSTRCMP(subdirentry->d_name + (l - 5), ".html") != 0) 01229 && (l < 4 || NSTRCMP(subdirentry->d_name + (l - 4), ".pcb") != 0) ) 01230 { 01231 #ifdef DEBUG 01232 /* printf("... Found a footprint %s ... \n", subdirentry->d_name); */ 01233 #endif 01234 n_footprints++; 01235 entry = GetLibraryEntryMemory (menu); 01236 01237 /* 01238 * entry->AllocatedMemory points to abs path to the footprint. 01239 * entry->ListEntry points to fp name itself. 01240 */ 01241 len = strlen(subdir) + strlen("/") + strlen(subdirentry->d_name) + 1; 01242 entry->AllocatedMemory = (char *)calloc (1, len); 01243 strcat (entry->AllocatedMemory, subdir); 01244 strcat (entry->AllocatedMemory, PCB_DIR_SEPARATOR_S); 01245 01246 /* store pointer to start of footprint name */ 01247 entry->ListEntry = entry->AllocatedMemory 01248 + strlen (entry->AllocatedMemory); 01249 01250 /* Now place footprint name into AllocatedMemory */ 01251 strcat (entry->AllocatedMemory, subdirentry->d_name); 01252 01253 /* mark as directory tree (newlib) library */ 01254 entry->Template = (char *) -1; 01255 } 01256 } 01257 closedir (subdirobj); 01258 01259 /* Don't recurse into relatively-specified directories--we might be 01260 in the user's working directory, and the path might be "." */ 01261 if (!recursive) { 01262 if (chdir (olddir)) 01263 ChdirErrorMessage (olddir); 01264 return n_footprints; 01265 } 01266 01267 /* Then open this dir so we can loop over its contents. */ 01268 if ((subdirobj = opendir (subdir)) == NULL) 01269 { 01270 OpendirErrorMessage (subdir); 01271 if (chdir (olddir)) 01272 ChdirErrorMessage (olddir); 01273 return 0; 01274 } 01275 01276 /* Now loop over files in this directory looking for subdirs. 01277 * For each direntry which is a valid subdirectory, 01278 * try to load newlib footprints inside it. 01279 */ 01280 while ((subdirentry = readdir (subdirobj)) != NULL) 01281 { 01282 #ifdef DEBUG 01283 printf("In ParseLibraryTree loop examining 2nd level direntry %s ... \n", subdirentry->d_name); 01284 #endif 01285 /* Find subdirectories. Ignore entries beginning with "." and CVS 01286 * directories. 01287 */ 01288 if (!stat (subdirentry->d_name, &buffer) 01289 && S_ISDIR (buffer.st_mode) 01290 && subdirentry->d_name[0] != '.' 01291 && NSTRCMP (subdirentry->d_name, "CVS") != 0) 01292 { 01293 /* Found a valid subdirectory. Try to load footprints from it. 01294 */ 01295 char *subdir_path = (char *)calloc ( 01296 1, strlen(subdir) + strlen("/") + strlen(subdirentry->d_name) + 1); 01297 if (subdir_path == NULL) 01298 { 01299 fprintf (stderr, "LoadNewlibFootprintsFromDir(): " 01300 "malloc failed\n"); 01301 closedir (subdirobj); 01302 if (chdir (olddir)) 01303 ChdirErrorMessage (olddir); 01304 return n_footprints; 01305 } 01306 strcat (subdir_path, subdir); 01307 strcat (subdir_path, PCB_DIR_SEPARATOR_S); 01308 strcat (subdir_path, subdirentry->d_name); 01309 01310 n_footprints += LoadNewlibFootprintsFromDir(subdir_path, toppath, true); 01311 free(subdir_path); 01312 } 01313 } 01314 /* Done. Clean up, cd back into old dir, and return */ 01315 closedir (subdirobj); 01316 if (chdir (olddir)) 01317 ChdirErrorMessage (olddir); 01318 return n_footprints; 01319 } 01320 01321 01329 static int 01330 ParseLibraryTree (void) 01331 { 01332 char toppath[MAXPATHLEN + 1]; /* String holding abs path to top level library dir */ 01333 char working[MAXPATHLEN + 1]; /* String holding abs path to working dir */ 01334 char *libpaths; /* String holding list of library paths to search */ 01335 char *p; /* Helper string used in iteration */ 01336 int n_footprints = 0; /* Running count of footprints found */ 01337 bool is_abs = false; /* If we are processing an absolute path */ 01338 01339 /* Initialize path, working by writing 0 into every byte. */ 01340 memset (toppath, 0, sizeof toppath); 01341 memset (working, 0, sizeof working); 01342 01343 /* Save the current working directory as an absolute path. 01344 * This fcn writes the abs path into the memory pointed to by the input arg. 01345 */ 01346 if (GetWorkingDirectory (working) == NULL) 01347 { 01348 Message (_("ParseLibraryTree: Could not determine initial working directory\n")); 01349 return 0; 01350 } 01351 01352 /* Additional loop to allow for multiple 'newlib' style library directories 01353 * called out in Settings.LibraryTree 01354 */ 01355 libpaths = strdup (Settings.LibraryTree); 01356 for (p = strtok (libpaths, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER)) 01357 { 01358 /* remove trailing path delimeter */ 01359 strncpy (toppath, p, sizeof (toppath) - 1); 01360 01361 /* start out in the working directory in case the path is a 01362 * relative path 01363 */ 01364 if (chdir (working)) 01365 { 01366 ChdirErrorMessage (working); 01367 free (libpaths); 01368 return 0; 01369 } 01370 01371 /* 01372 * Next change to the directory which is the top of the library tree 01373 * and extract its abs path. 01374 */ 01375 if (chdir (toppath)) 01376 { 01377 ChdirErrorMessage (toppath); 01378 continue; 01379 } 01380 01381 if (GetWorkingDirectory (toppath) == NULL) 01382 { 01383 Message (_("ParseLibraryTree: Could not determine new working directory\n")); 01384 continue; 01385 } 01386 01387 /* figure out if this is an absolute path. Make sure it works on win32 as well. */ 01388 if (*p == PCB_DIR_SEPARATOR_C) 01389 { 01390 is_abs = true; 01391 } 01392 else if (strlen(p) > 3 && isalpha ((int) p[0]) && p[1] == ':' && p[2] == PCB_DIR_SEPARATOR_C) 01393 { 01394 is_abs = true; 01395 } 01396 01397 #ifdef DEBUG 01398 printf("In ParseLibraryTree, looking for newlib footprints inside top level directory %s ... \n", 01399 toppath); 01400 #endif 01401 01402 /* Next read in any footprints in the top level dir and below */ 01403 n_footprints += LoadNewlibFootprintsFromDir("(local)", toppath, is_abs); 01404 } 01405 01406 /* restore the original working directory */ 01407 if (chdir (working)) 01408 ChdirErrorMessage (working); 01409 01410 #ifdef DEBUG 01411 printf("Leaving ParseLibraryTree, found %d footprints.\n", n_footprints); 01412 #endif 01413 01414 free (libpaths); 01415 return n_footprints; 01416 } 01417 01424 int 01425 ReadLibraryContents (void) 01426 { 01427 static char *command = NULL; 01428 char inputline[MAX_LIBRARY_LINE_LENGTH + 1]; 01429 FILE *resultFP = NULL; 01430 LibraryMenuType *menu = NULL; 01431 LibraryEntryType *entry; 01432 01433 /* If we don't have a command to execute to find the library contents, 01434 * skip this. This is used by default on Windows builds (set in main.c), 01435 * as we can't normally run shell scripts or expect to have m4 present. 01436 */ 01437 if (Settings.LibraryContentsCommand != NULL && 01438 Settings.LibraryContentsCommand[0] != '\0') 01439 { 01440 /* First load the M4 stuff. The variable Settings.LibraryPath 01441 * points to it. 01442 */ 01443 free (command); 01444 command = EvaluateFilename (Settings.LibraryContentsCommand, 01445 Settings.LibraryPath, Settings.LibraryFilename, 01446 NULL); 01447 01448 #ifdef DEBUG 01449 printf("In ReadLibraryContents, about to execute command %s\n", command); 01450 #endif 01451 01452 /* This uses a pipe to execute a shell script which provides the names of 01453 * all M4 libs and footprints. The results are placed in resultFP. 01454 */ 01455 if (command && *command && (resultFP = popen (command, "r")) == NULL) 01456 { 01457 PopenErrorMessage (command); 01458 } 01459 01460 /* the M4 library contents are separated by colons; 01461 * template : package : name : description 01462 */ 01463 while (resultFP != NULL && fgets (inputline, MAX_LIBRARY_LINE_LENGTH, resultFP)) 01464 { 01465 size_t len = strlen (inputline); 01466 01467 /* check for maximum linelength */ 01468 if (len) 01469 { 01470 len--; 01471 if (inputline[len] != '\n') 01472 Message 01473 ("linelength (%i) exceeded; following characters will be ignored\n", 01474 MAX_LIBRARY_LINE_LENGTH); 01475 else 01476 inputline[len] = '\0'; 01477 } 01478 01479 /* if the line defines a menu */ 01480 if (!strncmp (inputline, "TYPE=", 5)) 01481 { 01482 menu = GetLibraryMenuMemory (&Library); 01483 menu->Name = strdup (UNKNOWN (&inputline[5])); 01484 menu->directory = strdup (Settings.LibraryFilename); 01485 } 01486 else 01487 { 01488 /* allocate a new menu entry if not already done */ 01489 if (!menu) 01490 { 01491 menu = GetLibraryMenuMemory (&Library); 01492 menu->Name = strdup (UNKNOWN ((char *) NULL)); 01493 menu->directory = strdup (Settings.LibraryFilename); 01494 } 01495 entry = GetLibraryEntryMemory (menu); 01496 entry->AllocatedMemory = strdup (inputline); 01497 01498 /* now break the line into pieces separated by colons */ 01499 if ((entry->Template = strtok (entry->AllocatedMemory, ":")) != 01500 NULL) 01501 if ((entry->Package = strtok (NULL, ":")) != NULL) 01502 if ((entry->Value = strtok (NULL, ":")) != NULL) 01503 entry->Description = strtok (NULL, ":"); 01504 01505 /* create the list entry */ 01506 len = strlen (EMPTY (entry->Value)) + 01507 strlen (EMPTY (entry->Description)) + 4; 01508 entry->ListEntry = (char *)calloc (len, sizeof (char)); 01509 sprintf (entry->ListEntry, 01510 "%s, %s", EMPTY (entry->Value), 01511 EMPTY (entry->Description)); 01512 } 01513 } 01514 if (resultFP != NULL) 01515 pclose (resultFP); 01516 } 01517 01518 /* Now after reading in the M4 libs, call a function to 01519 * read the newlib footprint libraries. Then sort the whole 01520 * library. 01521 */ 01522 if (ParseLibraryTree () > 0 || resultFP != NULL) 01523 { 01524 sort_library (&Library); 01525 return 0; 01526 } 01527 01528 return (1); 01529 } 01530 01531 #define BLANK(x) ((x) == ' ' || (x) == '\t' || (x) == '\n' \ 01532 || (x) == '\0') 01533 01537 int 01538 ReadNetlist (char *filename) 01539 { 01540 static char *command = NULL; 01541 char inputline[MAX_NETLIST_LINE_LENGTH + 1]; 01542 char temp[MAX_NETLIST_LINE_LENGTH + 1]; 01543 FILE *fp; 01544 LibraryMenuType *menu = NULL; 01545 LibraryEntryType *entry; 01546 int i, j, lines, kind; 01547 bool continued; 01548 bool used_popen = false; 01549 int retval = 0; 01550 01551 if (!filename) 01552 return 1; /* nothing to do */ 01553 01554 Message (_("Importing PCB netlist %s\n"), filename); 01555 01556 if (EMPTY_STRING_P (Settings.RatCommand)) 01557 { 01558 fp = fopen (filename, "r"); 01559 if (!fp) 01560 { 01561 Message("Cannot open %s for reading", filename); 01562 return 1; 01563 } 01564 } 01565 else 01566 { 01567 used_popen = true; 01568 free (command); 01569 command = EvaluateFilename (Settings.RatCommand, 01570 Settings.RatPath, filename, NULL); 01571 01572 /* open pipe to stdout of command */ 01573 if (*command == '\0' || (fp = popen (command, "r")) == NULL) 01574 { 01575 PopenErrorMessage (command); 01576 return 1; 01577 } 01578 } 01579 lines = 0; 01580 /* kind = 0 is net name 01581 * kind = 1 is route style name 01582 * kind = 2 is connection 01583 */ 01584 kind = 0; 01585 while (fgets (inputline, MAX_NETLIST_LINE_LENGTH, fp)) 01586 { 01587 size_t len = strlen (inputline); 01588 /* check for maximum length line */ 01589 if (len) 01590 { 01591 if (inputline[--len] != '\n') 01592 Message (_("Line length (%i) exceeded in netlist file.\n" 01593 "additional characters will be ignored.\n"), 01594 MAX_NETLIST_LINE_LENGTH); 01595 else 01596 inputline[len] = '\0'; 01597 } 01598 continued = (inputline[len - 1] == '\\') ? true : false; 01599 if (continued) 01600 inputline[len - 1] = '\0'; 01601 lines++; 01602 i = 0; 01603 while (inputline[i] != '\0') 01604 { 01605 j = 0; 01606 /* skip leading blanks */ 01607 while (inputline[i] != '\0' && BLANK (inputline[i])) 01608 i++; 01609 if (kind == 0) 01610 { 01611 /* add two spaces for included/unincluded */ 01612 temp[j++] = ' '; 01613 temp[j++] = ' '; 01614 } 01615 while (!BLANK (inputline[i])) 01616 temp[j++] = inputline[i++]; 01617 temp[j] = '\0'; 01618 while (inputline[i] != '\0' && BLANK (inputline[i])) 01619 i++; 01620 if (kind == 0) 01621 { 01622 menu = GetLibraryMenuMemory (&PCB->NetlistLib); 01623 menu->Name = strdup (temp); 01624 menu->flag = 1; 01625 kind++; 01626 } 01627 else 01628 { 01629 if (kind == 1 && strchr (temp, '-') == NULL) 01630 { 01631 kind++; 01632 menu->Style = strdup (temp); 01633 } 01634 else 01635 { 01636 entry = GetLibraryEntryMemory (menu); 01637 entry->ListEntry = strdup (temp); 01638 } 01639 } 01640 } 01641 if (!continued) 01642 kind = 0; 01643 } 01644 if (!lines) 01645 { 01646 Message (_("Empty netlist file!\n")); 01647 retval = 1; 01648 } 01649 if (used_popen) 01650 pclose (fp); 01651 else 01652 fclose (fp); 01653 sort_netlist (); 01654 return retval; 01655 } 01656 01657 static int ReadEdifNetlist (char *filename); 01658 01659 int ImportNetlist (char *filename) 01660 { 01661 FILE *fp; 01662 char buf[16]; 01663 int i; 01664 char* p; 01665 01666 01667 if (!filename) return (1); /* nothing to do */ 01668 fp = fopen (filename, "r"); 01669 if (!fp) return (1); /* bad filename */ 01670 i = fread (buf, 1, sizeof(buf)-1, fp); 01671 fclose(fp); 01672 buf[i] = '\0'; 01673 p=buf; 01674 while ( *p ) 01675 { 01676 *p = tolower ((int) *p); 01677 p++; 01678 } 01679 p = strstr (buf, "edif"); 01680 if (!p) return ReadNetlist (filename); 01681 else return ReadEdifNetlist (filename); 01682 } 01683 01684 static int ReadEdifNetlist (char *filename) 01685 { 01686 Message (_("Importing edif netlist %s\n"), filename); 01687 ParseEDIF(filename, NULL); 01688 01689 return 0; 01690 } 01691