Introduce POLYGONHOLE_MODE for creating holes in polygons
[geda-pcb/gde.git] / src / file.c
bloba61d53f6e226b9c4efa1a30e2f9aa8c838c33cd8
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996,1997,1998,2005,2006 Thomas Nau
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., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
29 /* file save, load, merge ... routines
30 * getpid() needs a cast to (int) to get rid of compiler warnings
31 * on several architectures
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
38 #ifdef HAVE_SYS_PARAM_H
39 #include <sys/param.h>
40 #endif
42 #include "global.h"
44 #include <dirent.h>
45 #ifdef HAVE_PWD_H
46 #include <pwd.h>
47 #endif
48 #include <time.h>
50 #ifdef HAVE_SYS_SOCKET_H
51 #include <sys/socket.h>
52 #endif
54 #include <sys/stat.h>
56 #ifdef HAVE_NETINET_IN_H
57 #include <netinet/in.h>
58 #endif
60 #ifdef HAVE_NETDB_H
61 #include <netdb.h>
62 #endif
64 #include <stdio.h>
66 #ifdef HAVE_STDLIB_H
67 #include <stdlib.h>
68 #endif
70 #ifdef HAVE_STRING_H
71 #include <string.h>
72 #endif
74 #ifdef HAVE_UNISTD_H
75 #include <unistd.h>
76 #endif
79 #include "buffer.h"
80 #include "change.h"
81 #include "create.h"
82 #include "crosshair.h"
83 #include "data.h"
84 #include "edif_parse.h"
85 #include "error.h"
86 #include "file.h"
87 #include "hid.h"
88 #include "misc.h"
89 #include "move.h"
90 #include "mymem.h"
91 #include "parse_l.h"
92 #include "polygon.h"
93 #include "rats.h"
94 #include "remove.h"
95 #include "set.h"
96 #include "strflags.h"
98 #ifdef HAVE_LIBDMALLOC
99 #include <dmalloc.h>
100 #endif
102 RCSID ("$Id$");
104 #if !defined(HAS_ATEXIT) && !defined(HAS_ON_EXIT)
105 /* ---------------------------------------------------------------------------
106 * some local identifiers for OS without an atexit() or on_exit()
107 * call
109 static char TMPFilename[80];
110 #endif
112 /* ---------------------------------------------------------------------------
113 * some local prototypes
115 static void PrintQuotedString (FILE *, char *);
116 static void WritePCBInfoHeader (FILE *);
117 static void WritePCBDataHeader (FILE *);
118 static void WritePCBFontData (FILE *);
119 static void WriteViaData (FILE *, DataTypePtr);
120 static void WritePCBRatData (FILE *);
121 static void WriteElementData (FILE *, DataTypePtr);
122 static void WriteLayerData (FILE *, Cardinal, LayerTypePtr);
123 static int WritePCB (FILE *);
124 static int WritePCBFile (char *);
125 static int WritePipe (char *, bool);
126 static int ParseLibraryTree (void);
127 static int LoadNewlibFootprintsFromDir(char *path, char *toppath);
128 static char *pcb_basename (char *p);
130 /* ---------------------------------------------------------------------------
131 * Flag helper functions
134 #define F2S(OBJ, TYPE) flags_to_string ((OBJ)->Flags, TYPE)
136 /* --------------------------------------------------------------------------- */
138 static int
139 string_cmp (const char *a, const char *b)
141 while (*a && *b)
143 if (isdigit ((int) *a) && isdigit ((int) *b))
145 int ia = atoi (a);
146 int ib = atoi (b);
147 if (ia != ib)
148 return ia - ib;
149 while (isdigit ((int) *a) && *(a+1))
150 a++;
151 while (isdigit ((int) *b) && *(b+1))
152 b++;
154 else if (tolower ((int) *a) != tolower ((int) *b))
155 return tolower ((int) *a) - tolower ((int) *b);
156 a++;
157 b++;
159 if (*a)
160 return 1;
161 if (*b)
162 return -1;
163 return 0;
166 static int netlist_sort_offset = 0;
168 static int
169 netlist_sort (const void *va, const void *vb)
171 LibraryMenuType *am = (LibraryMenuType *) va;
172 LibraryMenuType *bm = (LibraryMenuType *) vb;
173 char *a = am->Name;
174 char *b = bm->Name;
175 if (*a == '~')
176 a++;
177 if (*b == '~')
178 b++;
179 return string_cmp (a, b);
182 static int
183 netnode_sort (const void *va, const void *vb)
185 LibraryEntryType *am = (LibraryEntryType *) va;
186 LibraryEntryType *bm = (LibraryEntryType *) vb;
187 char *a = am->ListEntry;
188 char *b = bm->ListEntry;
189 return string_cmp (a, b);
192 static void
193 sort_library (LibraryTypePtr lib)
195 int i;
196 qsort (lib->Menu, lib->MenuN, sizeof (lib->Menu[0]), netlist_sort);
197 for (i = 0; i < lib->MenuN; i++)
198 qsort (lib->Menu[i].Entry,
199 lib->Menu[i].EntryN, sizeof (lib->Menu[i].Entry[0]), netnode_sort);
202 void
203 sort_netlist ()
205 netlist_sort_offset = 2;
206 sort_library (&(PCB->NetlistLib));
207 netlist_sort_offset = 0;
210 /* ---------------------------------------------------------------------------
211 * opens a file and check if it exists
213 FILE *
214 CheckAndOpenFile (char *Filename, bool Confirm, bool AllButton,
215 bool * WasAllButton, bool * WasCancelButton)
217 FILE *fp = NULL;
218 struct stat buffer;
219 char message[MAXPATHLEN + 80];
220 int response;
222 if (Filename && *Filename)
224 if (!stat (Filename, &buffer) && Confirm)
226 sprintf (message, _("File '%s' exists, use anyway?"), Filename);
227 if (WasAllButton)
228 *WasAllButton = false;
229 if (WasCancelButton)
230 *WasCancelButton = false;
231 if (AllButton)
232 response =
233 gui->confirm_dialog (message, "Cancel", "Ok",
234 AllButton ? "Sequence OK" : 0);
235 else
236 response =
237 gui->confirm_dialog (message, "Cancel", "Ok", "Sequence OK");
239 switch (response)
241 case 2:
242 if (WasAllButton)
243 *WasAllButton = true;
244 break;
245 case 0:
246 if (WasCancelButton)
247 *WasCancelButton = true;
250 if ((fp = fopen (Filename, "w")) == NULL)
251 OpenErrorMessage (Filename);
253 return (fp);
256 /* ---------------------------------------------------------------------------
257 * opens a file for saving connection data
259 FILE *
260 OpenConnectionDataFile (void)
262 char *fname;
263 FILE *fp;
264 static char * default_file = NULL;
265 bool result; /* not used */
267 /* CheckAndOpenFile deals with the case where fname already exists */
268 fname = gui->fileselect (_("Save Connection Data As ..."),
269 _("Choose a file to save all connection data to."),
270 default_file, ".net", "connection_data",
272 if (fname == NULL)
273 return NULL;
275 if (default_file != NULL)
277 free (default_file);
278 default_file = NULL;
281 if (fname && *fname)
282 default_file = strdup (fname);
284 fp = CheckAndOpenFile (fname, true, false, &result, NULL);
285 free (fname);
287 return fp;
290 /* ---------------------------------------------------------------------------
291 * save elements in the current buffer
294 SaveBufferElements (char *Filename)
296 int result;
298 if (SWAP_IDENT)
299 SwapBuffers ();
300 result = WritePipe (Filename, false);
301 if (SWAP_IDENT)
302 SwapBuffers ();
303 return (result);
306 /* ---------------------------------------------------------------------------
307 * save PCB
310 SavePCB (char *Filename)
312 int retcode;
313 char *copy;
315 if (!(retcode = WritePipe (Filename, true)))
317 /* thanks to Nick Bailey for the bug-fix;
318 * first of all make a copy of the passed filename because
319 * it might be identical to 'PCB->Filename'
321 copy = MyStrdup (Filename, "SavePCB()");
322 SaveFree (PCB->Filename);
323 PCB->Filename = copy;
324 SetChangedFlag (false);
326 return (retcode);
329 /* ---------------------------------------------------------------------------
330 * set the route style to the first one, if the current one doesn't
331 * happen to match any. This way, "revert" won't change the route
332 * style.
334 static void
335 set_some_route_style ()
337 if (hid_get_flag ("style"))
338 return;
339 SetLineSize (PCB->RouteStyle[0].Thick);
340 SetViaSize (PCB->RouteStyle[0].Diameter, true);
341 SetViaDrillingHole (PCB->RouteStyle[0].Hole, true);
342 SetKeepawayWidth (PCB->RouteStyle[0].Keepaway);
345 /* ---------------------------------------------------------------------------
346 * load PCB
347 * parse the file with enabled 'PCB mode' (see parser)
348 * if successful, update some other stuff
351 LoadPCB (char *Filename)
353 PCBTypePtr newPCB = CreateNewPCB (false);
354 bool units_mm;
355 clock_t start, end;
356 double elapsed;
358 start = clock ();
360 /* new data isn't added to the undo list */
361 if (!ParsePCB (newPCB, Filename))
363 RemovePCB (PCB);
364 PCB = newPCB;
366 CreateNewPCBPost (PCB, 0);
367 ResetStackAndVisibility ();
369 /* update cursor location */
370 Crosshair.X = MAX (0, MIN (PCB->CursorX, (LocationType) PCB->MaxWidth));
371 Crosshair.Y =
372 MAX (0, MIN (PCB->CursorY, (LocationType) PCB->MaxHeight));
374 Xorig = Crosshair.X - TO_PCB (Output.Width / 2);
375 Yorig = Crosshair.Y - TO_PCB (Output.Height / 2);
377 /* update cursor confinement and output area (scrollbars) */
378 ChangePCBSize (PCB->MaxWidth, PCB->MaxHeight);
380 /* create default font if necessary */
381 if (!PCB->Font.Valid)
383 Message (_
384 ("File '%s' has no font information, using default font\n"),
385 Filename);
386 CreateDefaultFont ();
389 /* clear 'changed flag' */
390 SetChangedFlag (false);
391 PCB->Filename = MyStrdup (Filename, "LoadPCB()");
392 /* just in case a bad file saved file is loaded */
394 units_mm = (PCB->Grid != (int) PCB->Grid) ? true : false;
396 Settings.grid_units_mm = units_mm;
398 sort_netlist ();
400 set_some_route_style ();
402 hid_action ("PCBChanged");
404 end = clock ();
405 elapsed = ((double) (end - start)) / CLOCKS_PER_SEC;
406 gui->log ("Loading file %s took %f seconds of CPU time\n",
407 Filename, elapsed);
409 return (0);
411 hid_action ("PCBChanged");
413 /* release unused memory */
414 RemovePCB (newPCB);
415 return (1);
418 /* ---------------------------------------------------------------------------
419 * functions for loading elements-as-pcb
422 extern PCBTypePtr yyPCB;
423 extern DataTypePtr yyData;
424 extern FontTypePtr yyFont;
426 void
427 PreLoadElementPCB ()
430 if (!yyPCB)
431 return;
433 yyFont = &yyPCB->Font;
434 yyData = yyPCB->Data;
435 yyData->pcb = (void *)yyPCB;
436 yyData->LayerN = 0;
439 void
440 PostLoadElementPCB ()
442 PCBTypePtr pcb_save = PCB;
443 ElementTypePtr e;
445 if (!yyPCB)
446 return;
448 CreateNewPCBPost (yyPCB, 0);
449 ParseGroupString("1,c:2,s", &yyPCB->LayerGroups, yyData->LayerN);
450 e = yyPCB->Data->Element; /* we know there's only one */
451 PCB = yyPCB;
452 MoveElementLowLevel (yyPCB->Data,
453 e, -e->BoundingBox.X1, -e->BoundingBox.Y1);
454 PCB = pcb_save;
455 yyPCB->MaxWidth = e->BoundingBox.X2;
456 yyPCB->MaxHeight = e->BoundingBox.Y2;
459 /* ---------------------------------------------------------------------------
460 * writes the quoted string created by another subroutine
462 static void
463 PrintQuotedString (FILE * FP, char *S)
465 static DynamicStringType ds;
467 CreateQuotedString (&ds, S);
468 fputs (ds.Data, FP);
471 /* ---------------------------------------------------------------------------
472 * writes out an attribute list
474 static void
475 WriteAttributeList (FILE * FP, AttributeListTypePtr list, char *prefix)
477 int i;
479 for (i = 0; i < list->Number; i++)
480 fprintf (FP, "%sAttribute(\"%s\" \"%s\")\n",
481 prefix, list->List[i].name, list->List[i].value);
484 /* ---------------------------------------------------------------------------
485 * writes layout header information
486 * date, UID and name of user
488 static void
489 WritePCBInfoHeader (FILE * FP)
491 #ifdef HAVE_GETPWUID
492 struct passwd *pwentry;
493 #endif
495 #ifdef HAVE_GETHOSTNAME
496 static struct hostent *hostentry = NULL;
497 char hostname[256];
498 #endif
499 time_t currenttime;
501 /* write some useful comments */
502 currenttime = time (NULL);
503 fprintf (FP, "# release: %s " VERSION "\n", Progname);
504 fprintf (FP, "# date: %s", asctime (localtime (&currenttime)));
506 #ifdef HAVE_GETPWUID
507 pwentry = getpwuid (getuid ());
508 fprintf (FP, "# user: %s (%s)\n", pwentry->pw_name, pwentry->pw_gecos);
509 #else
510 fprintf (FP, "# user: Unknown\n");
511 #endif
513 #ifdef HAVE_GETHOSTNAME
514 if (gethostname (hostname, 255) != -1)
516 if (hostentry == NULL)
517 hostentry = gethostbyname (hostname);
518 fprintf (FP, "# host: %s\n",
519 hostentry ? hostentry->h_name : hostname);
521 #else
522 fprintf (FP, "# host: Unknown\n");
523 #endif
526 /* ---------------------------------------------------------------------------
527 * writes data header
528 * the name of the PCB, cursor location, zoom and grid
529 * layergroups and some flags
531 static void
532 WritePCBDataHeader (FILE * FP)
534 Cardinal group;
537 * ************************** README *******************
538 * ************************** README *******************
540 * If the file format is modified in any way, update
541 * PCB_FILE_VERSION in file.h
543 * ************************** README *******************
544 * ************************** README *******************
547 fprintf (FP, "\n# To read pcb files, the pcb version (or the git source date) must be >= the file version\n");
548 fprintf (FP, "FileVersion[%i]\n", PCB_FILE_VERSION);
550 fputs ("\nPCB[", FP);
551 PrintQuotedString (FP, EMPTY (PCB->Name));
552 fprintf (FP, " %i %i]\n\n", (int) PCB->MaxWidth, (int) PCB->MaxHeight);
553 fprintf (FP, "Grid[%s %i %i %i]\n",
554 c_dtostr (PCB->Grid), (int) PCB->GridOffsetX,
555 (int) PCB->GridOffsetY, (int) Settings.DrawGrid);
556 fprintf (FP, "Cursor[%i %i %s]\n", (int) TO_PCB_X (Output.Width / 2),
557 (int) TO_PCB_Y (Output.Height / 2), c_dtostr (PCB->Zoom));
558 fprintf (FP, "PolyArea[%s]\n", c_dtostr (PCB->IsleArea));
559 fprintf (FP, "Thermal[%s]\n", c_dtostr (PCB->ThermScale));
560 fprintf (FP, "DRC[%i %i %i %i %i %i]\n", PCB->Bloat, PCB->Shrink,
561 PCB->minWid, PCB->minSlk, PCB->minDrill, PCB->minRing);
562 fprintf (FP, "Flags(%s)\n", pcbflags_to_string(PCB->Flags));
563 fprintf (FP, "Groups(\"%s\")\n", LayerGroupsToString (&PCB->LayerGroups));
564 fputs ("Styles[\"", FP);
565 for (group = 0; group < NUM_STYLES - 1; group++)
566 fprintf (FP, "%s,%i,%i,%i,%i:", PCB->RouteStyle[group].Name,
567 PCB->RouteStyle[group].Thick,
568 PCB->RouteStyle[group].Diameter,
569 PCB->RouteStyle[group].Hole, PCB->RouteStyle[group].Keepaway);
570 fprintf (FP, "%s,%i,%i,%i,%i\"]\n\n", PCB->RouteStyle[group].Name,
571 PCB->RouteStyle[group].Thick,
572 PCB->RouteStyle[group].Diameter,
573 PCB->RouteStyle[group].Hole, PCB->RouteStyle[group].Keepaway);
576 /* ---------------------------------------------------------------------------
577 * writes font data of non empty symbols
579 static void
580 WritePCBFontData (FILE * FP)
582 Cardinal i, j;
583 LineTypePtr line;
584 FontTypePtr font;
586 for (font = &PCB->Font, i = 0; i <= MAX_FONTPOSITION; i++)
588 if (!font->Symbol[i].Valid)
589 continue;
591 if (isprint (i) && font->Symbol[i].Delta % 100 == 0)
592 fprintf (FP, "Symbol('%c' %i)\n(\n",
593 (char) i, (int) font->Symbol[i].Delta / 100);
594 else if (isprint (i))
595 fprintf (FP, "Symbol['%c' %i]\n(\n",
596 (char) i, (int) font->Symbol[i].Delta);
597 else
598 fprintf (FP, "Symbol[%i %i]\n(\n", i, (int) font->Symbol[i].Delta);
600 line = font->Symbol[i].Line;
601 for (j = font->Symbol[i].LineN; j; j--, line++)
603 if (line->Point1.X % 100 == 0
604 && line->Point1.Y % 100 == 0
605 && line->Point2.X % 100 == 0
606 && line->Point2.Y % 100 == 0 && line->Thickness % 100 == 0)
607 fprintf (FP, "\tSymbolLine(%i %i %i %i %i)\n",
608 line->Point1.X / 100, line->Point1.Y / 100,
609 line->Point2.X / 100, line->Point2.Y / 100,
610 line->Thickness / 100);
611 else
612 fprintf (FP, "\tSymbolLine[%i %i %i %i %i]\n",
613 line->Point1.X, line->Point1.Y,
614 line->Point2.X, line->Point2.Y, line->Thickness);
616 fputs (")\n", FP);
620 /* ---------------------------------------------------------------------------
621 * writes via data
623 static void
624 WriteViaData (FILE * FP, DataTypePtr Data)
626 int n;
627 /* write information about vias */
628 for (n = 0; n < Data->ViaN; n++)
630 PinTypePtr via = &Data->Via[n];
631 fprintf (FP, "Via[%i %i %i %i %i %i ",
632 via->X, via->Y,
633 via->Thickness, via->Clearance, via->Mask, via->DrillingHole);
634 PrintQuotedString (FP, EMPTY (via->Name));
635 fprintf (FP, " %s]\n", F2S (via, VIA_TYPE));
639 /* ---------------------------------------------------------------------------
640 * writes rat-line data
642 static void
643 WritePCBRatData (FILE * FP)
645 int n;
646 /* write information about rats */
647 for (n = 0; n < PCB->Data->RatN; n++)
649 RatTypePtr line = &PCB->Data->Rat[n];
650 fprintf (FP, "Rat[%i %i %i %i %i %i ",
651 (int) line->Point1.X, (int) line->Point1.Y,
652 (int) line->group1, (int) line->Point2.X,
653 (int) line->Point2.Y, (int) line->group2);
654 fprintf (FP, " %s]\n", F2S (line, RATLINE_TYPE));
658 /* ---------------------------------------------------------------------------
659 * writes netlist data
661 static void
662 WritePCBNetlistData (FILE * FP)
664 /* write out the netlist if it exists */
665 if (PCB->NetlistLib.MenuN)
667 int n, p;
668 fprintf (FP, "NetList()\n(\n");
670 for (n = 0; n < PCB->NetlistLib.MenuN; n++)
672 LibraryMenuTypePtr menu = &PCB->NetlistLib.Menu[n];
673 fprintf (FP, "\tNet(");
674 PrintQuotedString(FP, &menu->Name[2]);
675 fprintf (FP, " ");
676 PrintQuotedString(FP, UNKNOWN (menu->Style));
677 fprintf (FP, ")\n\t(\n");
678 for (p = 0; p < menu->EntryN; p++)
680 LibraryEntryTypePtr entry = &menu->Entry[p];
681 fprintf (FP, "\t\tConnect(");
682 PrintQuotedString (FP, entry->ListEntry);
683 fprintf (FP, ")\n");
685 fprintf (FP, "\t)\n");
687 fprintf (FP, ")\n");
691 /* ---------------------------------------------------------------------------
692 * writes element data
694 static void
695 WriteElementData (FILE * FP, DataTypePtr Data)
697 int n, p;
698 for (n = 0; n < Data->ElementN; n++)
700 ElementTypePtr element = &Data->Element[n];
701 /* only non empty elements */
702 if (!element->LineN && !element->PinN && !element->ArcN
703 && !element->PadN)
704 continue;
705 /* the coordinates and text-flags are the same for
706 * both names of an element
708 fprintf (FP, "\nElement[%s ", F2S (element, ELEMENT_TYPE));
709 PrintQuotedString (FP, EMPTY (DESCRIPTION_NAME (element)));
710 fputc (' ', FP);
711 PrintQuotedString (FP, EMPTY (NAMEONPCB_NAME (element)));
712 fputc (' ', FP);
713 PrintQuotedString (FP, EMPTY (VALUE_NAME (element)));
714 fprintf (FP, " %i %i %i %i %i %i %s]\n(\n",
715 (int) element->MarkX, (int) element->MarkY,
716 (int) (DESCRIPTION_TEXT (element).X -
717 element->MarkX),
718 (int) (DESCRIPTION_TEXT (element).Y -
719 element->MarkY),
720 (int) DESCRIPTION_TEXT (element).Direction,
721 (int) DESCRIPTION_TEXT (element).Scale,
722 F2S (&(DESCRIPTION_TEXT (element)), ELEMENTNAME_TYPE));
723 WriteAttributeList (FP, &element->Attributes, "\t");
724 for (p = 0; p < element->PinN; p++)
726 PinTypePtr pin = &element->Pin[p];
727 fprintf (FP, "\tPin[%i %i %i %i %i %i ",
728 (int) (pin->X - element->MarkX),
729 (int) (pin->Y - element->MarkY),
730 (int) pin->Thickness, (int) pin->Clearance,
731 (int) pin->Mask, (int) pin->DrillingHole);
732 PrintQuotedString (FP, EMPTY (pin->Name));
733 fprintf (FP, " ");
734 PrintQuotedString (FP, EMPTY (pin->Number));
735 fprintf (FP, " %s]\n", F2S (pin, PIN_TYPE));
737 for (p = 0; p < element->PadN; p++)
739 PadTypePtr pad = &element->Pad[p];
740 fprintf (FP, "\tPad[%i %i %i %i %i %i %i ",
741 (int) (pad->Point1.X - element->MarkX),
742 (int) (pad->Point1.Y - element->MarkY),
743 (int) (pad->Point2.X - element->MarkX),
744 (int) (pad->Point2.Y - element->MarkY),
745 (int) pad->Thickness, (int) pad->Clearance,
746 (int) pad->Mask);
747 PrintQuotedString (FP, EMPTY (pad->Name));
748 fprintf (FP, " ");
749 PrintQuotedString (FP, EMPTY (pad->Number));
750 fprintf (FP, " %s]\n", F2S (pad, PAD_TYPE));
752 for (p = 0; p < element->LineN; p++)
754 LineTypePtr line = &element->Line[p];
755 fprintf (FP,
756 "\tElementLine [%i %i %i %i %i]\n",
757 (int) (line->Point1.X -
758 element->MarkX),
759 (int) (line->Point1.Y -
760 element->MarkY),
761 (int) (line->Point2.X -
762 element->MarkX),
763 (int) (line->Point2.Y -
764 element->MarkY), (int) line->Thickness);
766 for (p = 0; p < element->ArcN; p++)
768 ArcTypePtr arc = &element->Arc[p];
769 fprintf (FP,
770 "\tElementArc [%i %i %i %i %i %i %i]\n",
771 (int) (arc->X - element->MarkX),
772 (int) (arc->Y - element->MarkY),
773 (int) arc->Width, (int) arc->Height,
774 (int) arc->StartAngle, (int) arc->Delta,
775 (int) arc->Thickness);
777 fputs ("\n\t)\n", FP);
781 /* ---------------------------------------------------------------------------
782 * writes layer data
784 static void
785 WriteLayerData (FILE * FP, Cardinal Number, LayerTypePtr layer)
787 int n;
788 /* write information about non empty layers */
789 if (layer->LineN || layer->ArcN || layer->TextN || layer->PolygonN ||
790 (layer->Name && *layer->Name))
792 fprintf (FP, "Layer(%i ", (int) Number + 1);
793 PrintQuotedString (FP, EMPTY (layer->Name));
794 fputs (")\n(\n", FP);
795 WriteAttributeList (FP, &layer->Attributes, "\t");
797 for (n = 0; n < layer->LineN; n++)
799 LineTypePtr line = &layer->Line[n];
800 fprintf (FP, "\tLine[%i %i %i %i %i %i %s]\n",
801 (int) line->Point1.X, (int) line->Point1.Y,
802 (int) line->Point2.X, (int) line->Point2.Y,
803 (int) line->Thickness, (int) line->Clearance,
804 F2S (line, LINE_TYPE));
806 for (n = 0; n < layer->ArcN; n++)
808 ArcTypePtr arc = &layer->Arc[n];
809 fprintf (FP, "\tArc[%i %i %i %i %i %i %i %i %s]\n",
810 (int) arc->X, (int) arc->Y, (int) arc->Width,
811 (int) arc->Height, (int) arc->Thickness,
812 (int) arc->Clearance, (int) arc->StartAngle,
813 (int) arc->Delta, F2S (arc, ARC_TYPE));
815 for (n = 0; n < layer->TextN; n++)
817 TextTypePtr text = &layer->Text[n];
818 fprintf (FP, "\tText[%i %i %i %i ",
819 (int) text->X, (int) text->Y,
820 (int) text->Direction, (int) text->Scale);
821 PrintQuotedString (FP, EMPTY (text->TextString));
822 fprintf (FP, " %s]\n", F2S (text, TEXT_TYPE));
824 for (n = 0; n < layer->PolygonN; n++)
826 PolygonTypePtr polygon = &layer->Polygon[n];
827 int p, i = 0;
828 Cardinal hole = 0;
829 fprintf (FP, "\tPolygon(%s)\n\t(", F2S (polygon, POLYGON_TYPE));
830 for (p = 0; p < polygon->PointN; p++)
832 PointTypePtr point = &polygon->Points[p];
834 if (hole < polygon->HoleIndexN &&
835 p == polygon->HoleIndex[hole])
837 if (hole > 0)
838 fputs ("\n\t\t)", FP);
839 fputs ("\n\t\tHole (", FP);
840 hole++;
841 i = 0;
844 if (i++ % 5 == 0)
846 fputs ("\n\t\t", FP);
847 if (hole)
848 fputs ("\t", FP);
850 fprintf (FP, "[%i %i] ", (int) point->X, (int) point->Y);
852 if (hole > 0)
853 fputs ("\n\t\t)", FP);
854 fputs ("\n\t)\n", FP);
856 fputs (")\n", FP);
860 /* ---------------------------------------------------------------------------
861 * writes just the elements in the buffer to file
863 static int
864 WriteBuffer (FILE * FP)
866 Cardinal i;
868 WriteViaData (FP, PASTEBUFFER->Data);
869 WriteElementData (FP, PASTEBUFFER->Data);
870 for (i = 0; i < max_layer + 2; i++)
871 WriteLayerData (FP, i, &(PASTEBUFFER->Data->Layer[i]));
872 return (STATUS_OK);
875 /* ---------------------------------------------------------------------------
876 * writes PCB to file
878 static int
879 WritePCB (FILE * FP)
881 Cardinal i;
883 WritePCBInfoHeader (FP);
884 WritePCBDataHeader (FP);
885 WritePCBFontData (FP);
886 WriteAttributeList (FP, &PCB->Attributes, "");
887 WriteViaData (FP, PCB->Data);
888 WriteElementData (FP, PCB->Data);
889 WritePCBRatData (FP);
890 for (i = 0; i < max_layer + 2; i++)
891 WriteLayerData (FP, i, &(PCB->Data->Layer[i]));
892 WritePCBNetlistData (FP);
894 return (STATUS_OK);
897 /* ---------------------------------------------------------------------------
898 * writes PCB to file
900 static int
901 WritePCBFile (char *Filename)
903 FILE *fp;
904 int result;
906 if ((fp = fopen (Filename, "w")) == NULL)
908 OpenErrorMessage (Filename);
909 return (STATUS_ERROR);
911 result = WritePCB (fp);
912 fclose (fp);
913 return (result);
916 /* ---------------------------------------------------------------------------
917 * writes to pipe using the command defined by Settings.SaveCommand
918 * %f are replaced by the passed filename
920 static int
921 WritePipe (char *Filename, bool thePcb)
923 FILE *fp;
924 int result;
925 char *p;
926 static DynamicStringType command;
927 int used_popen = 0;
929 if (EMPTY_STRING_P (Settings.SaveCommand))
931 fp = fopen (Filename, "w");
932 if (fp == 0)
934 Message ("Unable to write to file %s\n", Filename);
935 return STATUS_ERROR;
938 else
940 used_popen = 1;
941 /* setup commandline */
942 DSClearString (&command);
943 for (p = Settings.SaveCommand; *p; p++)
945 /* copy character if not special or add string to command */
946 if (!(*p == '%' && *(p + 1) == 'f'))
947 DSAddCharacter (&command, *p);
948 else
950 DSAddString (&command, Filename);
952 /* skip the character */
953 p++;
956 DSAddCharacter (&command, '\0');
957 printf ("write to pipe \"%s\"\n", command.Data);
958 if ((fp = popen (command.Data, "w")) == NULL)
960 PopenErrorMessage (command.Data);
961 return (STATUS_ERROR);
964 if (thePcb)
965 result = WritePCB (fp);
966 else
967 result = WriteBuffer (fp);
969 if (used_popen)
970 return (pclose (fp) ? STATUS_ERROR : result);
971 return (fclose (fp) ? STATUS_ERROR : result);
974 /* ---------------------------------------------------------------------------
975 * saves the layout in a temporary file
976 * this is used for fatal errors and does not call the program specified
977 * in 'saveCommand' for safety reasons
979 void
980 SaveInTMP (void)
982 char filename[80];
984 /* memory might have been released before this function is called */
985 if (PCB && PCB->Changed)
987 sprintf (filename, EMERGENCY_NAME, (int) getpid ());
988 Message (_("Trying to save your layout in '%s'\n"), filename);
989 WritePCBFile (filename);
993 /* ---------------------------------------------------------------------------
994 * front-end for 'SaveInTMP()'
995 * just makes sure that the routine is only called once
997 static bool dont_save_any_more = false;
998 void
999 EmergencySave (void)
1002 if (!dont_save_any_more)
1004 SaveInTMP ();
1005 dont_save_any_more = true;
1009 void
1010 DisableEmergencySave (void)
1012 dont_save_any_more = true;
1015 /* ----------------------------------------------------------------------
1016 * Callback for the autosave
1019 static hidval backup_timer;
1022 * If the backup interval is > 0 then set another timer. Otherwise
1023 * we do nothing and it is up to the GUI to call EnableAutosave()
1024 * after setting Settings.BackupInterval > 0 again.
1026 static void
1027 backup_cb (hidval data)
1029 backup_timer.ptr = NULL;
1030 Backup ();
1031 if (Settings.BackupInterval > 0 && gui->add_timer)
1032 backup_timer = gui->add_timer (backup_cb,
1033 1000 * Settings.BackupInterval, data);
1036 void
1037 EnableAutosave (void)
1039 hidval x;
1041 x.ptr = NULL;
1043 /* If we already have a timer going, then cancel it out */
1044 if (backup_timer.ptr != NULL && gui->stop_timer)
1045 gui->stop_timer (backup_timer);
1047 backup_timer.ptr = NULL;
1048 /* Start up a new timer */
1049 if (Settings.BackupInterval > 0 && gui->add_timer)
1050 backup_timer = gui->add_timer (backup_cb,
1051 1000 * Settings.BackupInterval,
1055 /* ---------------------------------------------------------------------------
1056 * creates backup file. The default is to use the pcb file name with
1057 * a "-" appended (like "foo.pcb-") and if we don't have a pcb file name
1058 * then use the template in BACKUP_NAME
1060 void
1061 Backup (void)
1063 char *filename = NULL;
1065 if( PCB && PCB->Filename )
1067 filename = (char *) malloc (sizeof (char) * (strlen (PCB->Filename) + 2));
1068 if (filename == NULL)
1070 fprintf (stderr, "Backup(): malloc failed\n");
1071 exit (1);
1073 sprintf (filename, "%s-", PCB->Filename);
1075 else
1077 /* BACKUP_NAME has %.8i which will be replaced by the process ID */
1078 filename = (char *) malloc (sizeof (char) * (strlen (BACKUP_NAME) + 8));
1079 if (filename == NULL)
1081 fprintf (stderr, "Backup(): malloc failed\n");
1082 exit (1);
1084 sprintf (filename, BACKUP_NAME, (int) getpid ());
1087 WritePCBFile (filename);
1088 free (filename);
1091 #if !defined(HAS_ATEXIT) && !defined(HAS_ON_EXIT)
1092 /* ---------------------------------------------------------------------------
1093 * makes a temporary copy of the data. This is useful for systems which
1094 * doesn't support calling functions on exit. We use this to save the data
1095 * before LEX and YACC functions are called because they are able to abort
1096 * the program.
1098 void
1099 SaveTMPData (void)
1101 sprintf (TMPFilename, EMERGENCY_NAME, (int) getpid ());
1102 WritePCBFile (TMPFilename);
1105 /* ---------------------------------------------------------------------------
1106 * removes the temporary copy of the data file
1108 void
1109 RemoveTMPData (void)
1111 unlink (TMPFilename);
1113 #endif
1115 /* ---------------------------------------------------------------------------
1116 * Parse the directory tree where newlib footprints are found
1119 /* Helper function for ParseLibraryTree */
1120 static char *
1121 pcb_basename (char *p)
1123 char *rv = strrchr (p, '/');
1124 if (rv)
1125 return rv + 1;
1126 return p;
1129 /* This is a helper function for ParseLibrary Tree. Given a char *path,
1130 * it finds all newlib footprints in that dir and sticks them into the
1131 * library menu structure named entry.
1133 static int
1134 LoadNewlibFootprintsFromDir(char *libpath, char *toppath)
1136 char olddir[MAXPATHLEN + 1]; /* The directory we start out in (cwd) */
1137 char subdir[MAXPATHLEN + 1]; /* The directory holding footprints to load */
1138 DIR *subdirobj; /* Interable object holding all subdir entries */
1139 struct dirent *subdirentry; /* Individual subdir entry */
1140 struct stat buffer; /* Buffer used in stat */
1141 LibraryMenuTypePtr menu = NULL; /* Pointer to PCB's library menu structure */
1142 LibraryEntryTypePtr entry; /* Pointer to individual menu entry */
1143 size_t l;
1144 size_t len;
1145 int n_footprints = 0; /* Running count of footprints found in this subdir */
1147 /* Cache old dir, then cd into subdir because stat is given relative file names. */
1148 memset (subdir, 0, sizeof subdir);
1149 memset (olddir, 0, sizeof olddir);
1150 GetWorkingDirectory(olddir);
1151 strcpy (subdir, libpath);
1152 chdir(subdir);
1153 GetWorkingDirectory(subdir); /* subdir is abs path */
1155 /* First try opening the directory specified by path */
1156 if ( (subdirobj = opendir (subdir)) == NULL )
1158 OpendirErrorMessage (subdir);
1159 return 0;
1162 /* Get pointer to memory holding menu */
1163 menu = GetLibraryMenuMemory (&Library);
1164 /* Populate menuname and path vars */
1165 menu->Name = MyStrdup (pcb_basename(subdir), "Newlib");
1166 menu->directory = strdup (pcb_basename(toppath));
1168 /* Now loop over files in this directory looking for files.
1169 * We ignore certain files which are not footprints.
1171 while ((subdirentry = readdir (subdirobj)) != NULL)
1173 #ifdef DEBUG
1174 /* printf("... Examining file %s ... \n", subdirentry->d_name); */
1175 #endif
1177 /* Ignore non-footprint files found in this directory
1178 * We're skipping .png and .html because those
1179 * may exist in a library tree to provide an html browsable
1180 * index of the library.
1182 l = strlen (subdirentry->d_name);
1183 if (!stat (subdirentry->d_name, &buffer) && S_ISREG (buffer.st_mode)
1184 && subdirentry->d_name[0] != '.'
1185 && NSTRCMP (subdirentry->d_name, "CVS") != 0
1186 && NSTRCMP (subdirentry->d_name, "Makefile") != 0
1187 && NSTRCMP (subdirentry->d_name, "Makefile.am") != 0
1188 && NSTRCMP (subdirentry->d_name, "Makefile.in") != 0
1189 && (l < 4 || NSTRCMP(subdirentry->d_name + (l - 4), ".png") != 0)
1190 && (l < 5 || NSTRCMP(subdirentry->d_name + (l - 5), ".html") != 0) )
1192 #ifdef DEBUG
1193 /* printf("... Found a footprint %s ... \n", subdirentry->d_name); */
1194 #endif
1195 n_footprints++;
1196 entry = GetLibraryEntryMemory (menu);
1199 * entry->AllocatedMemory points to abs path to the footprint.
1200 * entry->ListEntry points to fp name itself.
1202 len = strlen(subdir) + strlen("/") + strlen(subdirentry->d_name) + 1;
1203 entry->AllocatedMemory = MyCalloc (1, len, "ParseLibraryTree()");
1204 strcat (entry->AllocatedMemory, subdir);
1205 strcat (entry->AllocatedMemory, PCB_DIR_SEPARATOR_S);
1207 /* store pointer to start of footprint name */
1208 entry->ListEntry = entry->AllocatedMemory
1209 + strlen (entry->AllocatedMemory);
1211 /* Now place footprint name into AllocatedMemory */
1212 strcat (entry->AllocatedMemory, subdirentry->d_name);
1214 /* mark as directory tree (newlib) library */
1215 entry->Template = (char *) -1;
1218 /* Done. Clean up, cd back into old dir, and return */
1219 closedir (subdirobj);
1220 chdir(olddir);
1221 return n_footprints;
1225 /* This function loads the newlib footprints into the Library.
1226 * It examines all directories pointed to by Settings.LibraryTree.
1227 * In each directory specified there, it looks both in that directory,
1228 * as well as *one* level down. It calls the subfunction
1229 * LoadNewlibFootprintsFromDir to put the footprints into PCB's internal
1230 * datastructures.
1232 static int
1233 ParseLibraryTree (void)
1235 char toppath[MAXPATHLEN + 1]; /* String holding abs path to top level library dir */
1236 char working[MAXPATHLEN + 1]; /* String holding abs path to working dir */
1237 char *libpaths; /* String holding list of library paths to search */
1238 char *p; /* Helper string used in iteration */
1239 DIR *dirobj; /* Iterable directory object */
1240 struct dirent *direntry = NULL; /* Object holding individual directory entries */
1241 struct stat buffer; /* buffer used in stat */
1242 int n_footprints = 0; /* Running count of footprints found */
1244 /* Initialize path, working by writing 0 into every byte. */
1245 memset (toppath, 0, sizeof toppath);
1246 memset (working, 0, sizeof working);
1248 /* Save the current working directory as an absolute path.
1249 * This fcn writes the abs path into the memory pointed to by the input arg.
1251 GetWorkingDirectory (working);
1253 /* Additional loop to allow for multiple 'newlib' style library directories
1254 * called out in Settings.LibraryTree
1256 libpaths = MyStrdup (Settings.LibraryTree, "ParseLibraryTree");
1257 for (p = strtok (libpaths, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER))
1259 /* remove trailing path delimeter */
1260 strncpy (toppath, p, sizeof (toppath) - 1);
1262 /* start out in the working directory in case the path is a
1263 * relative path
1265 chdir (working);
1268 * Next change to the directory which is the top of the library tree
1269 * and extract its abs path.
1271 chdir (toppath);
1272 GetWorkingDirectory (toppath);
1274 #ifdef DEBUG
1275 printf("In ParseLibraryTree, looking for newlib footprints inside top level directory %s ... \n",
1276 toppath);
1277 #endif
1279 /* Next read in any footprints in the top level dir */
1280 n_footprints += LoadNewlibFootprintsFromDir("(local)", toppath);
1282 /* Then open this dir so we can loop over its contents. */
1283 if ((dirobj = opendir (toppath)) == NULL)
1285 OpendirErrorMessage (toppath);
1286 continue;
1289 /* Now loop over files in this directory looking for subdirs.
1290 * For each direntry which is a valid subdirectory,
1291 * try to load newlib footprints inside it.
1293 while ((direntry = readdir (dirobj)) != NULL)
1295 #ifdef DEBUG
1296 printf("In ParseLibraryTree loop examining 2nd level direntry %s ... \n", direntry->d_name);
1297 #endif
1298 /* Find subdirectories. Ignore entries beginning with "." and CVS
1299 * directories.
1301 if (!stat (direntry->d_name, &buffer)
1302 && S_ISDIR (buffer.st_mode)
1303 && direntry->d_name[0] != '.'
1304 && NSTRCMP (direntry->d_name, "CVS") != 0)
1306 /* Found a valid subdirectory. Try to load footprints from it.
1308 n_footprints += LoadNewlibFootprintsFromDir(direntry->d_name, toppath);
1311 closedir (dirobj);
1314 /* restore the original working directory */
1315 chdir (working);
1317 #ifdef DEBUG
1318 printf("Leaving ParseLibraryTree, found %d footprints.\n", n_footprints);
1319 #endif
1321 return n_footprints;
1324 /* ---------------------------------------------------------------------------
1325 * Read contents of the library description file (for M4)
1326 * and then read in M4 libs. Then call a fcn to read the newlib
1327 * footprints.
1330 ReadLibraryContents (void)
1332 static char *command = NULL;
1333 char inputline[MAX_LIBRARY_LINE_LENGTH + 1];
1334 FILE *resultFP = NULL;
1335 LibraryMenuTypePtr menu = NULL;
1336 LibraryEntryTypePtr entry;
1339 /* First load the M4 stuff. The variable Settings.LibraryPath
1340 * points to it.
1342 MYFREE (command);
1343 command = EvaluateFilename (Settings.LibraryContentsCommand,
1344 Settings.LibraryPath, Settings.LibraryFilename,
1345 NULL);
1347 #ifdef DEBUG
1348 printf("In ReadLibraryContents, about to execute command %s\n", command);
1349 #endif
1351 /* This uses a pipe to execute a shell script which provides the names of
1352 * all M4 libs and footprints. The results are placed in resultFP.
1354 if (command && *command && (resultFP = popen (command, "r")) == NULL)
1356 PopenErrorMessage (command);
1359 /* the M4 library contents are separated by colons;
1360 * template : package : name : description
1362 while (resultFP != NULL && fgets (inputline, MAX_LIBRARY_LINE_LENGTH, resultFP))
1364 size_t len = strlen (inputline);
1366 /* check for maximum linelength */
1367 if (len)
1369 len--;
1370 if (inputline[len] != '\n')
1371 Message
1372 ("linelength (%i) exceeded; following characters will be ignored\n",
1373 MAX_LIBRARY_LINE_LENGTH);
1374 else
1375 inputline[len] = '\0';
1378 /* if the line defines a menu */
1379 if (!strncmp (inputline, "TYPE=", 5))
1381 menu = GetLibraryMenuMemory (&Library);
1382 menu->Name = MyStrdup (UNKNOWN (&inputline[5]),
1383 "ReadLibraryDescription()");
1384 menu->directory = strdup (Settings.LibraryFilename);
1386 else
1388 /* allocate a new menu entry if not already done */
1389 if (!menu)
1391 menu = GetLibraryMenuMemory (&Library);
1392 menu->Name = MyStrdup (UNKNOWN ((char *) NULL),
1393 "ReadLibraryDescription()");
1394 menu->directory = strdup (Settings.LibraryFilename);
1396 entry = GetLibraryEntryMemory (menu);
1397 entry->AllocatedMemory = MyStrdup (inputline,
1398 "ReadLibraryDescription()");
1400 /* now break the line into pieces separated by colons */
1401 if ((entry->Template = strtok (entry->AllocatedMemory, ":")) !=
1402 NULL)
1403 if ((entry->Package = strtok (NULL, ":")) != NULL)
1404 if ((entry->Value = strtok (NULL, ":")) != NULL)
1405 entry->Description = strtok (NULL, ":");
1407 /* create the list entry */
1408 len = strlen (EMPTY (entry->Value)) +
1409 strlen (EMPTY (entry->Description)) + 4;
1410 entry->ListEntry = MyCalloc (len, sizeof (char),
1411 "ReadLibraryDescription()");
1412 sprintf (entry->ListEntry,
1413 "%s, %s", EMPTY (entry->Value),
1414 EMPTY (entry->Description));
1417 if (resultFP != NULL)
1418 pclose (resultFP);
1420 /* Now after reading in the M4 libs, call a function to
1421 * read the newlib footprint libraries. Then sort the whole
1422 * library.
1424 if (ParseLibraryTree () > 0 || resultFP != NULL)
1426 sort_library (&Library);
1427 return 0;
1430 return (1);
1433 #define BLANK(x) ((x) == ' ' || (x) == '\t' || (x) == '\n' \
1434 || (x) == '\0')
1436 /* ---------------------------------------------------------------------------
1437 * Read in a netlist and store it in the netlist menu
1441 ReadNetlist (char *filename)
1443 static char *command = NULL;
1444 char inputline[MAX_NETLIST_LINE_LENGTH + 1];
1445 char temp[MAX_NETLIST_LINE_LENGTH + 1];
1446 FILE *fp;
1447 LibraryMenuTypePtr menu = NULL;
1448 LibraryEntryTypePtr entry;
1449 int i, j, lines, kind;
1450 bool continued;
1451 int used_popen = 0;
1453 if (!filename)
1454 return (1); /* nothing to do */
1456 Message (_("Importing PCB netlist %s\n"), filename);
1458 if (EMPTY_STRING_P (Settings.RatCommand))
1460 fp = fopen (filename, "r");
1461 if (!fp)
1463 Message("Cannot open %s for reading", filename);
1464 return 1;
1467 else
1469 used_popen = 1;
1470 MYFREE (command);
1471 command = EvaluateFilename (Settings.RatCommand,
1472 Settings.RatPath, filename, NULL);
1474 /* open pipe to stdout of command */
1475 if (*command == '\0' || (fp = popen (command, "r")) == NULL)
1477 PopenErrorMessage (command);
1478 return (1);
1481 lines = 0;
1482 /* kind = 0 is net name
1483 * kind = 1 is route style name
1484 * kind = 2 is connection
1486 kind = 0;
1487 while (fgets (inputline, MAX_NETLIST_LINE_LENGTH, fp))
1489 size_t len = strlen (inputline);
1490 /* check for maximum length line */
1491 if (len)
1493 if (inputline[--len] != '\n')
1494 Message (_("Line length (%i) exceeded in netlist file.\n"
1495 "additional characters will be ignored.\n"),
1496 MAX_NETLIST_LINE_LENGTH);
1497 else
1498 inputline[len] = '\0';
1500 continued = (inputline[len - 1] == '\\') ? true : false;
1501 if (continued)
1502 inputline[len - 1] = '\0';
1503 lines++;
1504 i = 0;
1505 while (inputline[i] != '\0')
1507 j = 0;
1508 /* skip leading blanks */
1509 while (inputline[i] != '\0' && BLANK (inputline[i]))
1510 i++;
1511 if (kind == 0)
1513 /* add two spaces for included/unincluded */
1514 temp[j++] = ' ';
1515 temp[j++] = ' ';
1517 while (!BLANK (inputline[i]))
1518 temp[j++] = inputline[i++];
1519 temp[j] = '\0';
1520 while (inputline[i] != '\0' && BLANK (inputline[i]))
1521 i++;
1522 if (kind == 0)
1524 menu = GetLibraryMenuMemory (&PCB->NetlistLib);
1525 menu->Name = MyStrdup (temp, "ReadNetlist()");
1526 menu->flag = 1;
1527 kind++;
1529 else
1531 if (kind == 1 && strchr (temp, '-') == NULL)
1533 kind++;
1534 menu->Style = MyStrdup (temp, "ReadNetlist()");
1536 else
1538 entry = GetLibraryEntryMemory (menu);
1539 entry->ListEntry = MyStrdup (temp, "ReadNetlist()");
1543 if (!continued)
1544 kind = 0;
1546 if (!lines)
1548 Message (_("Empty netlist file!\n"));
1549 pclose (fp);
1550 return (1);
1552 if (used_popen)
1553 pclose (fp);
1554 else
1555 fclose (fp);
1556 sort_netlist ();
1557 return (0);
1560 static int ReadEdifNetlist (char *filename);
1562 int ImportNetlist (char *filename)
1564 FILE *fp;
1565 char buf[16];
1566 int i;
1567 char* p;
1570 if (!filename) return (1); /* nothing to do */
1571 fp = fopen (filename, "r");
1572 if (!fp) return (1); /* bad filename */
1573 i = fread (buf, 1, sizeof(buf)-1, fp);
1574 fclose(fp);
1575 buf[i] = '\0';
1576 p=buf;
1577 while ( *p )
1579 *p = tolower ((int) *p);
1580 p++;
1582 p = strstr (buf, "edif");
1583 if (!p) return ReadNetlist (filename);
1584 else return ReadEdifNetlist (filename);
1587 static int ReadEdifNetlist (char *filename)
1589 Message (_("Importing edif netlist %s\n"), filename);
1590 ParseEDIF(filename, NULL);
1592 return 0;