Fix poly_ComputeInteriorPoint() to work correctly for holes
[geda-pcb/gde.git] / src / file.c
blob639c971886b42a487d4f9e98e6040c4688036fcd
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 *, Boolean);
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, Boolean Confirm, Boolean AllButton,
215 Boolean * WasAllButton, Boolean * 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 Boolean 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 Boolean 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 cvs 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 fprintf (FP, "\tPolygon(%s)\n\t(", F2S (polygon, POLYGON_TYPE));
829 for (p = 0; p < polygon->PointN; p++)
831 PointTypePtr point = &polygon->Points[p];
832 if (i++ % 5 == 0)
833 fputs ("\n\t\t", FP);
834 fprintf (FP, "[%i %i] ", (int) point->X, (int) point->Y);
836 fputs ("\n\t)\n", FP);
838 fputs (")\n", FP);
842 /* ---------------------------------------------------------------------------
843 * writes just the elements in the buffer to file
845 static int
846 WriteBuffer (FILE * FP)
848 Cardinal i;
850 WriteViaData (FP, PASTEBUFFER->Data);
851 WriteElementData (FP, PASTEBUFFER->Data);
852 for (i = 0; i < max_layer + 2; i++)
853 WriteLayerData (FP, i, &(PASTEBUFFER->Data->Layer[i]));
854 return (STATUS_OK);
857 /* ---------------------------------------------------------------------------
858 * writes PCB to file
860 static int
861 WritePCB (FILE * FP)
863 Cardinal i;
865 WritePCBInfoHeader (FP);
866 WritePCBDataHeader (FP);
867 WritePCBFontData (FP);
868 WriteAttributeList (FP, &PCB->Attributes, "");
869 WriteViaData (FP, PCB->Data);
870 WriteElementData (FP, PCB->Data);
871 WritePCBRatData (FP);
872 for (i = 0; i < max_layer + 2; i++)
873 WriteLayerData (FP, i, &(PCB->Data->Layer[i]));
874 WritePCBNetlistData (FP);
876 return (STATUS_OK);
879 /* ---------------------------------------------------------------------------
880 * writes PCB to file
882 static int
883 WritePCBFile (char *Filename)
885 FILE *fp;
886 int result;
888 if ((fp = fopen (Filename, "w")) == NULL)
890 OpenErrorMessage (Filename);
891 return (STATUS_ERROR);
893 result = WritePCB (fp);
894 fclose (fp);
895 return (result);
898 /* ---------------------------------------------------------------------------
899 * writes to pipe using the command defined by Settings.SaveCommand
900 * %f are replaced by the passed filename
902 static int
903 WritePipe (char *Filename, Boolean thePcb)
905 FILE *fp;
906 int result;
907 char *p;
908 static DynamicStringType command;
909 int used_popen = 0;
911 if (EMPTY_STRING_P (Settings.SaveCommand))
913 fp = fopen (Filename, "w");
914 if (fp == 0)
916 Message ("Unable to write to file %s\n", Filename);
917 return STATUS_ERROR;
920 else
922 used_popen = 1;
923 /* setup commandline */
924 DSClearString (&command);
925 for (p = Settings.SaveCommand; *p; p++)
927 /* copy character if not special or add string to command */
928 if (!(*p == '%' && *(p + 1) == 'f'))
929 DSAddCharacter (&command, *p);
930 else
932 DSAddString (&command, Filename);
934 /* skip the character */
935 p++;
938 DSAddCharacter (&command, '\0');
939 printf ("write to pipe \"%s\"\n", command.Data);
940 if ((fp = popen (command.Data, "w")) == NULL)
942 PopenErrorMessage (command.Data);
943 return (STATUS_ERROR);
946 if (thePcb)
947 result = WritePCB (fp);
948 else
949 result = WriteBuffer (fp);
951 if (used_popen)
952 return (pclose (fp) ? STATUS_ERROR : result);
953 return (fclose (fp) ? STATUS_ERROR : result);
956 /* ---------------------------------------------------------------------------
957 * saves the layout in a temporary file
958 * this is used for fatal errors and does not call the program specified
959 * in 'saveCommand' for safety reasons
961 void
962 SaveInTMP (void)
964 char filename[80];
966 /* memory might have been released before this function is called */
967 if (PCB && PCB->Changed)
969 sprintf (filename, EMERGENCY_NAME, (int) getpid ());
970 Message (_("Trying to save your layout in '%s'\n"), filename);
971 WritePCBFile (filename);
975 /* ---------------------------------------------------------------------------
976 * front-end for 'SaveInTMP()'
977 * just makes sure that the routine is only called once
979 static Boolean dont_save_any_more = False;
980 void
981 EmergencySave (void)
984 if (!dont_save_any_more)
986 SaveInTMP ();
987 dont_save_any_more = True;
991 void
992 DisableEmergencySave (void)
994 dont_save_any_more = True;
997 /* ----------------------------------------------------------------------
998 * Callback for the autosave
1001 static hidval backup_timer;
1004 * If the backup interval is > 0 then set another timer. Otherwise
1005 * we do nothing and it is up to the GUI to call EnableAutosave()
1006 * after setting Settings.BackupInterval > 0 again.
1008 static void
1009 backup_cb (hidval data)
1011 backup_timer.ptr = NULL;
1012 Backup ();
1013 if (Settings.BackupInterval > 0 && gui->add_timer)
1014 backup_timer = gui->add_timer (backup_cb,
1015 1000 * Settings.BackupInterval, data);
1018 void
1019 EnableAutosave (void)
1021 hidval x;
1023 x.ptr = NULL;
1025 /* If we already have a timer going, then cancel it out */
1026 if (backup_timer.ptr != NULL && gui->stop_timer)
1027 gui->stop_timer (backup_timer);
1029 backup_timer.ptr = NULL;
1030 /* Start up a new timer */
1031 if (Settings.BackupInterval > 0 && gui->add_timer)
1032 backup_timer = gui->add_timer (backup_cb,
1033 1000 * Settings.BackupInterval,
1037 /* ---------------------------------------------------------------------------
1038 * creates backup file. The default is to use the pcb file name with
1039 * a "-" appended (like "foo.pcb-") and if we don't have a pcb file name
1040 * then use the template in BACKUP_NAME
1042 void
1043 Backup (void)
1045 char *filename = NULL;
1047 if( PCB && PCB->Filename )
1049 filename = (char *) malloc (sizeof (char) * (strlen (PCB->Filename) + 2));
1050 if (filename == NULL)
1052 fprintf (stderr, "Backup(): malloc failed\n");
1053 exit (1);
1055 sprintf (filename, "%s-", PCB->Filename);
1057 else
1059 /* BACKUP_NAME has %.8i which will be replaced by the process ID */
1060 filename = (char *) malloc (sizeof (char) * (strlen (BACKUP_NAME) + 8));
1061 if (filename == NULL)
1063 fprintf (stderr, "Backup(): malloc failed\n");
1064 exit (1);
1066 sprintf (filename, BACKUP_NAME, (int) getpid ());
1069 WritePCBFile (filename);
1070 free (filename);
1073 #if !defined(HAS_ATEXIT) && !defined(HAS_ON_EXIT)
1074 /* ---------------------------------------------------------------------------
1075 * makes a temporary copy of the data. This is useful for systems which
1076 * doesn't support calling functions on exit. We use this to save the data
1077 * before LEX and YACC functions are called because they are able to abort
1078 * the program.
1080 void
1081 SaveTMPData (void)
1083 sprintf (TMPFilename, EMERGENCY_NAME, (int) getpid ());
1084 WritePCBFile (TMPFilename);
1087 /* ---------------------------------------------------------------------------
1088 * removes the temporary copy of the data file
1090 void
1091 RemoveTMPData (void)
1093 unlink (TMPFilename);
1095 #endif
1097 /* ---------------------------------------------------------------------------
1098 * Parse the directory tree where newlib footprints are found
1101 /* Helper function for ParseLibraryTree */
1102 static char *
1103 pcb_basename (char *p)
1105 char *rv = strrchr (p, '/');
1106 if (rv)
1107 return rv + 1;
1108 return p;
1111 /* This is a helper function for ParseLibrary Tree. Given a char *path,
1112 * it finds all newlib footprints in that dir and sticks them into the
1113 * library menu structure named entry.
1115 static int
1116 LoadNewlibFootprintsFromDir(char *libpath, char *toppath)
1118 char olddir[MAXPATHLEN + 1]; /* The directory we start out in (cwd) */
1119 char subdir[MAXPATHLEN + 1]; /* The directory holding footprints to load */
1120 DIR *subdirobj; /* Interable object holding all subdir entries */
1121 struct dirent *subdirentry; /* Individual subdir entry */
1122 struct stat buffer; /* Buffer used in stat */
1123 LibraryMenuTypePtr menu = NULL; /* Pointer to PCB's library menu structure */
1124 LibraryEntryTypePtr entry; /* Pointer to individual menu entry */
1125 size_t l;
1126 size_t len;
1127 int n_footprints = 0; /* Running count of footprints found in this subdir */
1129 /* Cache old dir, then cd into subdir because stat is given relative file names. */
1130 memset (subdir, 0, sizeof subdir);
1131 memset (olddir, 0, sizeof olddir);
1132 GetWorkingDirectory(olddir);
1133 strcpy (subdir, libpath);
1134 chdir(subdir);
1135 GetWorkingDirectory(subdir); /* subdir is abs path */
1137 /* First try opening the directory specified by path */
1138 if ( (subdirobj = opendir (subdir)) == NULL )
1140 OpendirErrorMessage (subdir);
1141 return 0;
1144 /* Get pointer to memory holding menu */
1145 menu = GetLibraryMenuMemory (&Library);
1146 /* Populate menuname and path vars */
1147 menu->Name = MyStrdup (pcb_basename(subdir), "Newlib");
1148 menu->directory = strdup (pcb_basename(toppath));
1150 /* Now loop over files in this directory looking for files.
1151 * We ignore certain files which are not footprints.
1153 while ((subdirentry = readdir (subdirobj)) != NULL)
1155 #ifdef DEBUG
1156 /* printf("... Examining file %s ... \n", subdirentry->d_name); */
1157 #endif
1159 /* Ignore non-footprint files found in this directory
1160 * We're skipping .png and .html because those
1161 * may exist in a library tree to provide an html browsable
1162 * index of the library.
1164 l = strlen (subdirentry->d_name);
1165 if (!stat (subdirentry->d_name, &buffer) && S_ISREG (buffer.st_mode)
1166 && subdirentry->d_name[0] != '.'
1167 && NSTRCMP (subdirentry->d_name, "CVS") != 0
1168 && NSTRCMP (subdirentry->d_name, "Makefile") != 0
1169 && NSTRCMP (subdirentry->d_name, "Makefile.am") != 0
1170 && NSTRCMP (subdirentry->d_name, "Makefile.in") != 0
1171 && (l < 4 || NSTRCMP(subdirentry->d_name + (l - 4), ".png") != 0)
1172 && (l < 5 || NSTRCMP(subdirentry->d_name + (l - 5), ".html") != 0) )
1174 #ifdef DEBUG
1175 /* printf("... Found a footprint %s ... \n", subdirentry->d_name); */
1176 #endif
1177 n_footprints++;
1178 entry = GetLibraryEntryMemory (menu);
1181 * entry->AllocatedMemory points to abs path to the footprint.
1182 * entry->ListEntry points to fp name itself.
1184 len = strlen(subdir) + strlen("/") + strlen(subdirentry->d_name) + 1;
1185 entry->AllocatedMemory = MyCalloc (1, len, "ParseLibraryTree()");
1186 strcat (entry->AllocatedMemory, subdir);
1187 strcat (entry->AllocatedMemory, PCB_DIR_SEPARATOR_S);
1189 /* store pointer to start of footprint name */
1190 entry->ListEntry = entry->AllocatedMemory
1191 + strlen (entry->AllocatedMemory);
1193 /* Now place footprint name into AllocatedMemory */
1194 strcat (entry->AllocatedMemory, subdirentry->d_name);
1196 /* mark as directory tree (newlib) library */
1197 entry->Template = (char *) -1;
1200 /* Done. Clean up, cd back into old dir, and return */
1201 closedir (subdirobj);
1202 chdir(olddir);
1203 return n_footprints;
1207 /* This function loads the newlib footprints into the Library.
1208 * It examines all directories pointed to by Settings.LibraryTree.
1209 * In each directory specified there, it looks both in that directory,
1210 * as well as *one* level down. It calls the subfunction
1211 * LoadNewlibFootprintsFromDir to put the footprints into PCB's internal
1212 * datastructures.
1214 static int
1215 ParseLibraryTree (void)
1217 char toppath[MAXPATHLEN + 1]; /* String holding abs path to top level library dir */
1218 char working[MAXPATHLEN + 1]; /* String holding abs path to working dir */
1219 char *libpaths; /* String holding list of library paths to search */
1220 char *p; /* Helper string used in iteration */
1221 DIR *dirobj; /* Iterable directory object */
1222 struct dirent *direntry = NULL; /* Object holding individual directory entries */
1223 struct stat buffer; /* buffer used in stat */
1224 int n_footprints = 0; /* Running count of footprints found */
1226 /* Initialize path, working by writing 0 into every byte. */
1227 memset (toppath, 0, sizeof toppath);
1228 memset (working, 0, sizeof working);
1230 /* Save the current working directory as an absolute path.
1231 * This fcn writes the abs path into the memory pointed to by the input arg.
1233 GetWorkingDirectory (working);
1235 /* Additional loop to allow for multiple 'newlib' style library directories
1236 * called out in Settings.LibraryTree
1238 libpaths = MyStrdup (Settings.LibraryTree, "ParseLibraryTree");
1239 for (p = strtok (libpaths, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER))
1241 /* remove trailing path delimeter */
1242 strncpy (toppath, p, sizeof (toppath) - 1);
1244 /* start out in the working directory in case the path is a
1245 * relative path
1247 chdir (working);
1250 * Next change to the directory which is the top of the library tree
1251 * and extract its abs path.
1253 chdir (toppath);
1254 GetWorkingDirectory (toppath);
1256 #ifdef DEBUG
1257 printf("In ParseLibraryTree, looking for newlib footprints inside top level directory %s ... \n",
1258 toppath);
1259 #endif
1261 /* Next read in any footprints in the top level dir */
1262 n_footprints += LoadNewlibFootprintsFromDir("(local)", toppath);
1264 /* Then open this dir so we can loop over its contents. */
1265 if ((dirobj = opendir (toppath)) == NULL)
1267 OpendirErrorMessage (toppath);
1268 continue;
1271 /* Now loop over files in this directory looking for subdirs.
1272 * For each direntry which is a valid subdirectory,
1273 * try to load newlib footprints inside it.
1275 while ((direntry = readdir (dirobj)) != NULL)
1277 #ifdef DEBUG
1278 printf("In ParseLibraryTree loop examining 2nd level direntry %s ... \n", direntry->d_name);
1279 #endif
1280 /* Find subdirectories. Ignore entries beginning with "." and CVS
1281 * directories.
1283 if (!stat (direntry->d_name, &buffer)
1284 && S_ISDIR (buffer.st_mode)
1285 && direntry->d_name[0] != '.'
1286 && NSTRCMP (direntry->d_name, "CVS") != 0)
1288 /* Found a valid subdirectory. Try to load footprints from it.
1290 n_footprints += LoadNewlibFootprintsFromDir(direntry->d_name, toppath);
1293 closedir (dirobj);
1296 /* restore the original working directory */
1297 chdir (working);
1299 #ifdef DEBUG
1300 printf("Leaving ParseLibraryTree, found %d footprints.\n", n_footprints);
1301 #endif
1303 return n_footprints;
1306 /* ---------------------------------------------------------------------------
1307 * Read contents of the library description file (for M4)
1308 * and then read in M4 libs. Then call a fcn to read the newlib
1309 * footprints.
1312 ReadLibraryContents (void)
1314 static char *command = NULL;
1315 char inputline[MAX_LIBRARY_LINE_LENGTH + 1];
1316 FILE *resultFP = NULL;
1317 LibraryMenuTypePtr menu = NULL;
1318 LibraryEntryTypePtr entry;
1321 /* First load the M4 stuff. The variable Settings.LibraryPath
1322 * points to it.
1324 MYFREE (command);
1325 command = EvaluateFilename (Settings.LibraryContentsCommand,
1326 Settings.LibraryPath, Settings.LibraryFilename,
1327 NULL);
1329 #ifdef DEBUG
1330 printf("In ReadLibraryContents, about to execute command %s\n", command);
1331 #endif
1333 /* This uses a pipe to execute a shell script which provides the names of
1334 * all M4 libs and footprints. The results are placed in resultFP.
1336 if (command && *command && (resultFP = popen (command, "r")) == NULL)
1338 PopenErrorMessage (command);
1341 /* the M4 library contents are separated by colons;
1342 * template : package : name : description
1344 while (resultFP != NULL && fgets (inputline, MAX_LIBRARY_LINE_LENGTH, resultFP))
1346 size_t len = strlen (inputline);
1348 /* check for maximum linelength */
1349 if (len)
1351 len--;
1352 if (inputline[len] != '\n')
1353 Message
1354 ("linelength (%i) exceeded; following characters will be ignored\n",
1355 MAX_LIBRARY_LINE_LENGTH);
1356 else
1357 inputline[len] = '\0';
1360 /* if the line defines a menu */
1361 if (!strncmp (inputline, "TYPE=", 5))
1363 menu = GetLibraryMenuMemory (&Library);
1364 menu->Name = MyStrdup (UNKNOWN (&inputline[5]),
1365 "ReadLibraryDescription()");
1366 menu->directory = strdup (Settings.LibraryFilename);
1368 else
1370 /* allocate a new menu entry if not already done */
1371 if (!menu)
1373 menu = GetLibraryMenuMemory (&Library);
1374 menu->Name = MyStrdup (UNKNOWN ((char *) NULL),
1375 "ReadLibraryDescription()");
1376 menu->directory = strdup (Settings.LibraryFilename);
1378 entry = GetLibraryEntryMemory (menu);
1379 entry->AllocatedMemory = MyStrdup (inputline,
1380 "ReadLibraryDescription()");
1382 /* now break the line into pieces separated by colons */
1383 if ((entry->Template = strtok (entry->AllocatedMemory, ":")) !=
1384 NULL)
1385 if ((entry->Package = strtok (NULL, ":")) != NULL)
1386 if ((entry->Value = strtok (NULL, ":")) != NULL)
1387 entry->Description = strtok (NULL, ":");
1389 /* create the list entry */
1390 len = strlen (EMPTY (entry->Value)) +
1391 strlen (EMPTY (entry->Description)) + 4;
1392 entry->ListEntry = MyCalloc (len, sizeof (char),
1393 "ReadLibraryDescription()");
1394 sprintf (entry->ListEntry,
1395 "%s, %s", EMPTY (entry->Value),
1396 EMPTY (entry->Description));
1399 if (resultFP != NULL)
1400 pclose (resultFP);
1402 /* Now after reading in the M4 libs, call a function to
1403 * read the newlib footprint libraries. Then sort the whole
1404 * library.
1406 if (ParseLibraryTree () > 0 || resultFP != NULL)
1408 sort_library (&Library);
1409 return 0;
1412 return (1);
1415 #define BLANK(x) ((x) == ' ' || (x) == '\t' || (x) == '\n' \
1416 || (x) == '\0')
1418 /* ---------------------------------------------------------------------------
1419 * Read in a netlist and store it in the netlist menu
1423 ReadNetlist (char *filename)
1425 static char *command = NULL;
1426 char inputline[MAX_NETLIST_LINE_LENGTH + 1];
1427 char temp[MAX_NETLIST_LINE_LENGTH + 1];
1428 FILE *fp;
1429 LibraryMenuTypePtr menu = NULL;
1430 LibraryEntryTypePtr entry;
1431 int i, j, lines, kind;
1432 Boolean continued;
1433 int used_popen = 0;
1435 if (!filename)
1436 return (1); /* nothing to do */
1438 Message (_("Importing PCB netlist %s\n"), filename);
1440 if (EMPTY_STRING_P (Settings.RatCommand))
1442 fp = fopen (filename, "r");
1443 if (!fp)
1445 Message("Cannot open %s for reading", filename);
1446 return 1;
1449 else
1451 used_popen = 1;
1452 MYFREE (command);
1453 command = EvaluateFilename (Settings.RatCommand,
1454 Settings.RatPath, filename, NULL);
1456 /* open pipe to stdout of command */
1457 if (*command == '\0' || (fp = popen (command, "r")) == NULL)
1459 PopenErrorMessage (command);
1460 return (1);
1463 lines = 0;
1464 /* kind = 0 is net name
1465 * kind = 1 is route style name
1466 * kind = 2 is connection
1468 kind = 0;
1469 while (fgets (inputline, MAX_NETLIST_LINE_LENGTH, fp))
1471 size_t len = strlen (inputline);
1472 /* check for maximum length line */
1473 if (len)
1475 if (inputline[--len] != '\n')
1476 Message (_("Line length (%i) exceeded in netlist file.\n"
1477 "additional characters will be ignored.\n"),
1478 MAX_NETLIST_LINE_LENGTH);
1479 else
1480 inputline[len] = '\0';
1482 continued = (inputline[len - 1] == '\\') ? True : False;
1483 if (continued)
1484 inputline[len - 1] = '\0';
1485 lines++;
1486 i = 0;
1487 while (inputline[i] != '\0')
1489 j = 0;
1490 /* skip leading blanks */
1491 while (inputline[i] != '\0' && BLANK (inputline[i]))
1492 i++;
1493 if (kind == 0)
1495 /* add two spaces for included/unincluded */
1496 temp[j++] = ' ';
1497 temp[j++] = ' ';
1499 while (!BLANK (inputline[i]))
1500 temp[j++] = inputline[i++];
1501 temp[j] = '\0';
1502 while (inputline[i] != '\0' && BLANK (inputline[i]))
1503 i++;
1504 if (kind == 0)
1506 menu = GetLibraryMenuMemory (&PCB->NetlistLib);
1507 menu->Name = MyStrdup (temp, "ReadNetlist()");
1508 menu->flag = 1;
1509 kind++;
1511 else
1513 if (kind == 1 && strchr (temp, '-') == NULL)
1515 kind++;
1516 menu->Style = MyStrdup (temp, "ReadNetlist()");
1518 else
1520 entry = GetLibraryEntryMemory (menu);
1521 entry->ListEntry = MyStrdup (temp, "ReadNetlist()");
1525 if (!continued)
1526 kind = 0;
1528 if (!lines)
1530 Message (_("Empty netlist file!\n"));
1531 pclose (fp);
1532 return (1);
1534 if (used_popen)
1535 pclose (fp);
1536 else
1537 fclose (fp);
1538 sort_netlist ();
1539 return (0);
1542 static int ReadEdifNetlist (char *filename);
1544 int ImportNetlist (char *filename)
1546 FILE *fp;
1547 char buf[16];
1548 int i;
1549 char* p;
1552 if (!filename) return (1); /* nothing to do */
1553 fp = fopen (filename, "r");
1554 if (!fp) return (1); /* bad filename */
1555 i = fread (buf, 1, sizeof(buf)-1, fp);
1556 fclose(fp);
1557 buf[i] = '\0';
1558 p=buf;
1559 while ( *p )
1561 *p = tolower ((int) *p);
1562 p++;
1564 p = strstr (buf, "edif");
1565 if (!p) return ReadNetlist (filename);
1566 else return ReadEdifNetlist (filename);
1569 static int ReadEdifNetlist (char *filename)
1571 Message (_("Importing edif netlist %s\n"), filename);
1572 ParseEDIF(filename, NULL);
1574 return 0;