Fix typo converting request_debug_draw to return a HID_DRAW structure
[geda-pcb/pcjc2.git] / src / file.c
blob077213995238f189899965b89f151e9b9184ab0a
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996,1997,1998,2005,2006 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
27 /* file save, load, merge ... routines
28 * getpid() needs a cast to (int) to get rid of compiler warnings
29 * on several architectures
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
36 #ifdef HAVE_SYS_PARAM_H
37 #include <sys/param.h>
38 #endif
40 #include "global.h"
42 #include <dirent.h>
43 #ifdef HAVE_PWD_H
44 #include <pwd.h>
45 #endif
46 #include <time.h>
48 #ifdef HAVE_SYS_SOCKET_H
49 #include <sys/socket.h>
50 #endif
52 #include <sys/stat.h>
54 #ifdef HAVE_NETINET_IN_H
55 #include <netinet/in.h>
56 #endif
58 #ifdef HAVE_NETDB_H
59 #include <netdb.h>
60 #endif
62 #include <stdio.h>
64 #ifdef HAVE_STDLIB_H
65 #include <stdlib.h>
66 #endif
68 #ifdef HAVE_STRING_H
69 #include <string.h>
70 #endif
72 #ifdef HAVE_UNISTD_H
73 #include <unistd.h>
74 #endif
77 #include "buffer.h"
78 #include "change.h"
79 #include "create.h"
80 #include "crosshair.h"
81 #include "data.h"
82 #include "edif_parse.h"
83 #include "error.h"
84 #include "file.h"
85 #include "hid.h"
86 #include "misc.h"
87 #include "mymem.h"
88 #include "parse_l.h"
89 #include "pcb-printf.h"
90 #include "polygon.h"
91 #include "rats.h"
92 #include "remove.h"
93 #include "set.h"
94 #include "strflags.h"
96 #ifdef HAVE_LIBDMALLOC
97 #include <dmalloc.h>
98 #endif
100 #if !defined(HAS_ATEXIT) && !defined(HAS_ON_EXIT)
101 /* ---------------------------------------------------------------------------
102 * some local identifiers for OS without an atexit() or on_exit()
103 * call
105 static char TMPFilename[80];
106 #endif
108 /* ---------------------------------------------------------------------------
109 * some local prototypes
111 static void PrintQuotedString (FILE *, char *);
112 static void WritePCBInfoHeader (FILE *);
113 static void WritePCBDataHeader (FILE *);
114 static void WritePCBFontData (FILE *);
115 static void WriteViaData (FILE *, DataType *);
116 static void WritePCBRatData (FILE *);
117 static void WriteElementData (FILE *, DataType *);
118 static void WriteLayerData (FILE *, Cardinal, LayerType *);
119 static int WritePCB (FILE *);
120 static int WritePCBFile (char *);
121 static int WritePipe (char *, bool);
122 static int ParseLibraryTree (void);
123 static int LoadNewlibFootprintsFromDir(char *path, char *toppath, bool recursive);
125 /* ---------------------------------------------------------------------------
126 * Flag helper functions
129 #define F2S(OBJ, TYPE) flags_to_string ((OBJ)->Flags, TYPE)
131 /* --------------------------------------------------------------------------- */
133 /* The idea here is to avoid gratuitously breaking backwards
134 compatibility due to a new but rarely used feature. The first such
135 case, for example, was the polygon Hole - if your design included
136 polygon holes, you needed a newer PCB to read it, but if your
137 design didn't include holes, PCB would produce a file that older
138 PCBs could read, if only it had the correct version number in it.
140 If, however, you have to add or change a feature that really does
141 require a new PCB version all the time, it's time to remove all the
142 tests below and just always output the new version.
144 Note: Best practices here is to add support for a feature *first*
145 (and bump PCB_FILE_VERSION in file.h), and note the version that
146 added that support below, and *later* update the file format to
147 need that version (which may then be older than PCB_FILE_VERSION).
148 Hopefully, that allows for one release between adding support and
149 needing it, which should minimize breakage. Of course, that's not
150 *always* possible, practical, or desirable.
154 /* Hole[] in Polygon. */
155 #define PCB_FILE_VERSION_HOLES 20100606
156 /* First version ever saved. */
157 #define PCB_FILE_VERSION_BASELINE 20091103
160 PCBFileVersionNeeded (void)
162 ALLPOLYGON_LOOP (PCB->Data);
164 if (polygon->HoleIndexN > 0)
165 return PCB_FILE_VERSION_HOLES;
167 ENDALL_LOOP;
169 return PCB_FILE_VERSION_BASELINE;
172 /* --------------------------------------------------------------------------- */
174 static int
175 string_cmp (const char *a, const char *b)
177 while (*a && *b)
179 if (isdigit ((int) *a) && isdigit ((int) *b))
181 int ia = atoi (a);
182 int ib = atoi (b);
183 if (ia != ib)
184 return ia - ib;
185 while (isdigit ((int) *a) && *(a+1))
186 a++;
187 while (isdigit ((int) *b) && *(b+1))
188 b++;
190 else if (tolower ((int) *a) != tolower ((int) *b))
191 return tolower ((int) *a) - tolower ((int) *b);
192 a++;
193 b++;
195 if (*a)
196 return 1;
197 if (*b)
198 return -1;
199 return 0;
202 static int netlist_sort_offset = 0;
204 static int
205 netlist_sort (const void *va, const void *vb)
207 LibraryMenuType *am = (LibraryMenuType *) va;
208 LibraryMenuType *bm = (LibraryMenuType *) vb;
209 char *a = am->Name;
210 char *b = bm->Name;
211 if (*a == '~')
212 a++;
213 if (*b == '~')
214 b++;
215 return string_cmp (a, b);
218 static int
219 netnode_sort (const void *va, const void *vb)
221 LibraryEntryType *am = (LibraryEntryType *) va;
222 LibraryEntryType *bm = (LibraryEntryType *) vb;
223 char *a = am->ListEntry;
224 char *b = bm->ListEntry;
225 return string_cmp (a, b);
228 static void
229 sort_library (LibraryType *lib)
231 int i;
232 qsort (lib->Menu, lib->MenuN, sizeof (lib->Menu[0]), netlist_sort);
233 for (i = 0; i < lib->MenuN; i++)
234 qsort (lib->Menu[i].Entry,
235 lib->Menu[i].EntryN, sizeof (lib->Menu[i].Entry[0]), netnode_sort);
238 void
239 sort_netlist ()
241 netlist_sort_offset = 2;
242 sort_library (&(PCB->NetlistLib));
243 netlist_sort_offset = 0;
246 /* ---------------------------------------------------------------------------
247 * opens a file and check if it exists
249 FILE *
250 CheckAndOpenFile (char *Filename, bool Confirm, bool AllButton,
251 bool * WasAllButton, bool * WasCancelButton)
253 FILE *fp = NULL;
254 struct stat buffer;
255 char message[MAXPATHLEN + 80];
256 int response;
258 if (Filename && *Filename)
260 if (!stat (Filename, &buffer) && Confirm)
262 sprintf (message, _("File '%s' exists, use anyway?"), Filename);
263 if (WasAllButton)
264 *WasAllButton = false;
265 if (WasCancelButton)
266 *WasCancelButton = false;
267 if (AllButton)
268 response =
269 gui->confirm_dialog (message, "Cancel", "Ok",
270 AllButton ? "Sequence OK" : 0);
271 else
272 response =
273 gui->confirm_dialog (message, "Cancel", "Ok", "Sequence OK");
275 switch (response)
277 case 2:
278 if (WasAllButton)
279 *WasAllButton = true;
280 break;
281 case 0:
282 if (WasCancelButton)
283 *WasCancelButton = true;
286 if ((fp = fopen (Filename, "w")) == NULL)
287 OpenErrorMessage (Filename);
289 return (fp);
292 /* ---------------------------------------------------------------------------
293 * opens a file for saving connection data
295 FILE *
296 OpenConnectionDataFile (void)
298 char *fname;
299 FILE *fp;
300 static char * default_file = NULL;
301 bool result; /* not used */
303 /* CheckAndOpenFile deals with the case where fname already exists */
304 fname = gui->fileselect (_("Save Connection Data As ..."),
305 _("Choose a file to save all connection data to."),
306 default_file, ".net", "connection_data",
308 if (fname == NULL)
309 return NULL;
311 if (default_file != NULL)
313 free (default_file);
314 default_file = NULL;
317 if (fname && *fname)
318 default_file = strdup (fname);
320 fp = CheckAndOpenFile (fname, true, false, &result, NULL);
321 free (fname);
323 return fp;
326 /* ---------------------------------------------------------------------------
327 * save elements in the current buffer
330 SaveBufferElements (char *Filename)
332 int result;
334 if (SWAP_IDENT)
335 SwapBuffers ();
336 result = WritePipe (Filename, false);
337 if (SWAP_IDENT)
338 SwapBuffers ();
339 return (result);
342 /* ---------------------------------------------------------------------------
343 * save PCB
346 SavePCB (char *file)
348 int retcode;
350 if (gui->notify_save_pcb == NULL)
351 return WritePipe (file, true);
353 gui->notify_save_pcb (file, false);
354 retcode = WritePipe (file, true);
355 gui->notify_save_pcb (file, true);
357 return retcode;
360 /* ---------------------------------------------------------------------------
361 * set the route style to the first one, if the current one doesn't
362 * happen to match any. This way, "revert" won't change the route
363 * style.
365 static void
366 set_some_route_style ()
368 if (hid_get_flag ("style"))
369 return;
370 SetLineSize (PCB->RouteStyle[0].Thick);
371 SetViaSize (PCB->RouteStyle[0].Diameter, true);
372 SetViaDrillingHole (PCB->RouteStyle[0].Hole, true);
373 SetKeepawayWidth (PCB->RouteStyle[0].Keepaway);
376 /* ---------------------------------------------------------------------------
377 * load PCB
378 * parse the file with enabled 'PCB mode' (see parser)
379 * if successful, update some other stuff
381 * If revert is true, we pass "revert" as a parameter
382 * to the HID's PCBChanged action.
384 static int
385 real_load_pcb (char *Filename, bool revert)
387 const char *unit_suffix, *grid_size;
388 char *new_filename;
389 PCBType *newPCB = CreateNewPCB (false);
390 PCBType *oldPCB;
391 #ifdef DEBUG
392 double elapsed;
393 clock_t start, end;
395 start = clock ();
396 #endif
398 new_filename = strdup (Filename);
400 oldPCB = PCB;
401 PCB = newPCB;
403 /* mark the default font invalid to know if the file has one */
404 newPCB->Font.Valid = false;
406 /* new data isn't added to the undo list */
407 if (!ParsePCB (PCB, new_filename))
409 RemovePCB (oldPCB);
411 CreateNewPCBPost (PCB, 0);
412 ResetStackAndVisibility ();
414 /* update cursor location */
415 Crosshair.X = CLAMP (PCB->CursorX, 0, PCB->MaxWidth);
416 Crosshair.Y = CLAMP (PCB->CursorY, 0, PCB->MaxHeight);
418 /* update cursor confinement and output area (scrollbars) */
419 ChangePCBSize (PCB->MaxWidth, PCB->MaxHeight);
421 /* enable default font if necessary */
422 if (!PCB->Font.Valid)
424 Message (_
425 ("File '%s' has no font information, using default font\n"),
426 new_filename);
427 PCB->Font.Valid = true;
430 /* clear 'changed flag' */
431 SetChangedFlag (false);
432 PCB->Filename = new_filename;
433 /* just in case a bad file saved file is loaded */
435 /* Use attribute PCB::grid::unit as unit, if we can */
436 unit_suffix = AttributeGet (PCB, "PCB::grid::unit");
437 if (unit_suffix && *unit_suffix)
439 const Unit *new_unit = get_unit_struct (unit_suffix);
440 if (new_unit)
441 Settings.grid_unit = new_unit;
443 AttributePut (PCB, "PCB::grid::unit", Settings.grid_unit->suffix);
444 /* Use attribute PCB::grid::size as size, if we can */
445 grid_size = AttributeGet (PCB, "PCB::grid::size");
446 if (grid_size)
448 PCB->Grid = GetValue (grid_size, NULL, NULL);
451 sort_netlist ();
453 set_some_route_style ();
455 if (revert)
456 hid_actionl ("PCBChanged", "revert", NULL);
457 else
458 hid_action ("PCBChanged");
460 #ifdef DEBUG
461 end = clock ();
462 elapsed = ((double) (end - start)) / CLOCKS_PER_SEC;
463 gui->log ("Loading file %s took %f seconds of CPU time\n",
464 new_filename, elapsed);
465 #endif
467 return (0);
469 PCB = oldPCB;
470 hid_action ("PCBChanged");
472 /* release unused memory */
473 RemovePCB (newPCB);
474 return (1);
477 /* ---------------------------------------------------------------------------
478 * Load PCB
481 LoadPCB (char *file)
483 return real_load_pcb (file, false);
486 /* ---------------------------------------------------------------------------
487 * Revert PCB
490 RevertPCB (void)
492 return real_load_pcb (PCB->Filename, true);
495 /* ---------------------------------------------------------------------------
496 * writes the quoted string created by another subroutine
498 static void
499 PrintQuotedString (FILE * FP, char *S)
501 static DynamicStringType ds;
503 CreateQuotedString (&ds, S);
504 fputs (ds.Data, FP);
507 /* ---------------------------------------------------------------------------
508 * writes out an attribute list
510 static void
511 WriteAttributeList (FILE * FP, AttributeListType *list, char *prefix)
513 int i;
515 for (i = 0; i < list->Number; i++)
516 fprintf (FP, "%sAttribute(\"%s\" \"%s\")\n",
517 prefix, list->List[i].name, list->List[i].value);
520 /* ---------------------------------------------------------------------------
521 * writes layout header information
523 static void
524 WritePCBInfoHeader (FILE * FP)
526 /* write some useful comments */
527 fprintf (FP, "# release: %s " VERSION "\n", Progname);
529 /* avoid writing things like user name or date, as these cause merge
530 * conflicts in collaborative environments using version control systems
534 /* ---------------------------------------------------------------------------
535 * writes data header
536 * the name of the PCB, cursor location, zoom and grid
537 * layergroups and some flags
539 static void
540 WritePCBDataHeader (FILE * FP)
542 Cardinal group;
545 * ************************** README *******************
546 * ************************** README *******************
548 * If the file format is modified in any way, update
549 * PCB_FILE_VERSION in file.h as well as PCBFileVersionNeeded()
550 * at the top of this file.
552 * ************************** README *******************
553 * ************************** README *******************
556 fprintf (FP, "\n# To read pcb files, the pcb version (or the git source date) must be >= the file version\n");
557 fprintf (FP, "FileVersion[%i]\n", PCBFileVersionNeeded ());
559 fputs ("\nPCB[", FP);
560 PrintQuotedString (FP, (char *)EMPTY (PCB->Name));
561 pcb_fprintf (FP, " %mr %mr]\n\n", PCB->MaxWidth, PCB->MaxHeight);
562 pcb_fprintf (FP, "Grid[%s %mr %mr %d]\n", c_dtostr (COORD_TO_MIL (PCB->Grid) * 100), PCB->GridOffsetX, PCB->GridOffsetY, Settings.DrawGrid);
563 /* PolyArea should be output in square cmils, no suffix */
564 fprintf (FP, "PolyArea[%s]\n", c_dtostr (COORD_TO_MIL (COORD_TO_MIL (PCB->IsleArea) * 100) * 100));
565 pcb_fprintf (FP, "Thermal[%s]\n", c_dtostr (PCB->ThermScale));
566 pcb_fprintf (FP, "DRC[%mr %mr %mr %mr %mr %mr]\n", PCB->Bloat, PCB->Shrink,
567 PCB->minWid, PCB->minSlk, PCB->minDrill, PCB->minRing);
568 fprintf (FP, "Flags(%s)\n", pcbflags_to_string(PCB->Flags));
569 fprintf (FP, "Groups(\"%s\")\n", LayerGroupsToString (&PCB->LayerGroups));
570 fputs ("Styles[\"", FP);
571 for (group = 0; group < NUM_STYLES - 1; group++)
572 pcb_fprintf (FP, "%s,%mr,%mr,%mr,%mr:", PCB->RouteStyle[group].Name,
573 PCB->RouteStyle[group].Thick,
574 PCB->RouteStyle[group].Diameter,
575 PCB->RouteStyle[group].Hole, PCB->RouteStyle[group].Keepaway);
576 pcb_fprintf (FP, "%s,%mr,%mr,%mr,%mr\"]\n\n", PCB->RouteStyle[group].Name,
577 PCB->RouteStyle[group].Thick,
578 PCB->RouteStyle[group].Diameter,
579 PCB->RouteStyle[group].Hole, PCB->RouteStyle[group].Keepaway);
582 /* ---------------------------------------------------------------------------
583 * writes font data of non empty symbols
585 static void
586 WritePCBFontData (FILE * FP)
588 Cardinal i, j;
589 LineType *line;
590 FontType *font;
592 for (font = &PCB->Font, i = 0; i <= MAX_FONTPOSITION; i++)
594 if (!font->Symbol[i].Valid)
595 continue;
597 if (isprint (i))
598 pcb_fprintf (FP, "Symbol['%c' %mr]\n(\n", i, font->Symbol[i].Delta);
599 else
600 pcb_fprintf (FP, "Symbol[%i %mr]\n(\n", i, font->Symbol[i].Delta);
602 line = font->Symbol[i].Line;
603 for (j = font->Symbol[i].LineN; j; j--, line++)
604 pcb_fprintf (FP, "\tSymbolLine[%mr %mr %mr %mr %mr]\n",
605 line->Point1.X, line->Point1.Y,
606 line->Point2.X, line->Point2.Y, line->Thickness);
607 fputs (")\n", FP);
611 /* ---------------------------------------------------------------------------
612 * writes via data
614 static void
615 WriteViaData (FILE * FP, DataType *Data)
617 GList *iter;
618 /* write information about vias */
619 for (iter = Data->Via; iter != NULL; iter = g_list_next (iter))
621 PinType *via = iter->data;
622 pcb_fprintf (FP, "Via[%mr %mr %mr %mr %mr %mr ", via->X, via->Y,
623 via->Thickness, via->Clearance, via->Mask, via->DrillingHole);
624 PrintQuotedString (FP, (char *)EMPTY (via->Name));
625 fprintf (FP, " %s]\n", F2S (via, VIA_TYPE));
629 /* ---------------------------------------------------------------------------
630 * writes rat-line data
632 static void
633 WritePCBRatData (FILE * FP)
635 GList *iter;
636 /* write information about rats */
637 for (iter = PCB->Data->Rat; iter != NULL; iter = g_list_next (iter))
639 RatType *line = iter->data;
640 pcb_fprintf (FP, "Rat[%mr %mr %d %mr %mr %d ",
641 line->Point1.X, line->Point1.Y, line->group1,
642 line->Point2.X, line->Point2.Y, line->group2);
643 fprintf (FP, " %s]\n", F2S (line, RATLINE_TYPE));
647 /* ---------------------------------------------------------------------------
648 * writes netlist data
650 static void
651 WritePCBNetlistData (FILE * FP)
653 /* write out the netlist if it exists */
654 if (PCB->NetlistLib.MenuN)
656 int n, p;
657 fprintf (FP, "NetList()\n(\n");
659 for (n = 0; n < PCB->NetlistLib.MenuN; n++)
661 LibraryMenuType *menu = &PCB->NetlistLib.Menu[n];
662 fprintf (FP, "\tNet(");
663 PrintQuotedString(FP, &menu->Name[2]);
664 fprintf (FP, " ");
665 PrintQuotedString(FP, (char *)UNKNOWN (menu->Style));
666 fprintf (FP, ")\n\t(\n");
667 for (p = 0; p < menu->EntryN; p++)
669 LibraryEntryType *entry = &menu->Entry[p];
670 fprintf (FP, "\t\tConnect(");
671 PrintQuotedString (FP, entry->ListEntry);
672 fprintf (FP, ")\n");
674 fprintf (FP, "\t)\n");
676 fprintf (FP, ")\n");
680 /* ---------------------------------------------------------------------------
681 * writes element data
683 static void
684 WriteElementData (FILE * FP, DataType *Data)
686 GList *n, *p;
687 for (n = Data->Element; n != NULL; n = g_list_next (n))
689 ElementType *element = n->data;
691 /* only non empty elements */
692 if (!element->LineN && !element->PinN && !element->ArcN
693 && !element->PadN)
694 continue;
695 /* the coordinates and text-flags are the same for
696 * both names of an element
698 fprintf (FP, "\nElement[%s ", F2S (element, ELEMENT_TYPE));
699 PrintQuotedString (FP, (char *)EMPTY (DESCRIPTION_NAME (element)));
700 fputc (' ', FP);
701 PrintQuotedString (FP, (char *)EMPTY (NAMEONPCB_NAME (element)));
702 fputc (' ', FP);
703 PrintQuotedString (FP, (char *)EMPTY (VALUE_NAME (element)));
704 pcb_fprintf (FP, " %mr %mr %mr %mr %d %d %s]\n(\n",
705 element->MarkX, element->MarkY,
706 DESCRIPTION_TEXT (element).X - element->MarkX,
707 DESCRIPTION_TEXT (element).Y - element->MarkY,
708 DESCRIPTION_TEXT (element).Direction,
709 DESCRIPTION_TEXT (element).Scale,
710 F2S (&(DESCRIPTION_TEXT (element)), ELEMENTNAME_TYPE));
711 WriteAttributeList (FP, &element->Attributes, "\t");
712 for (p = element->Pin; p != NULL; p = g_list_next (p))
714 PinType *pin = p->data;
715 pcb_fprintf (FP, "\tPin[%mr %mr %mr %mr %mr %mr ",
716 pin->X - element->MarkX,
717 pin->Y - element->MarkY,
718 pin->Thickness, pin->Clearance,
719 pin->Mask, pin->DrillingHole);
720 PrintQuotedString (FP, (char *)EMPTY (pin->Name));
721 fprintf (FP, " ");
722 PrintQuotedString (FP, (char *)EMPTY (pin->Number));
723 fprintf (FP, " %s]\n", F2S (pin, PIN_TYPE));
725 for (p = element->Pad; p != NULL; p = g_list_next (p))
727 PadType *pad = p->data;
728 pcb_fprintf (FP, "\tPad[%mr %mr %mr %mr %mr %mr %mr ",
729 pad->Point1.X - element->MarkX,
730 pad->Point1.Y - element->MarkY,
731 pad->Point2.X - element->MarkX,
732 pad->Point2.Y - element->MarkY,
733 pad->Thickness, pad->Clearance, pad->Mask);
734 PrintQuotedString (FP, (char *)EMPTY (pad->Name));
735 fprintf (FP, " ");
736 PrintQuotedString (FP, (char *)EMPTY (pad->Number));
737 fprintf (FP, " %s]\n", F2S (pad, PAD_TYPE));
739 for (p = element->Line; p != NULL; p = g_list_next (p))
741 LineType *line = p->data;
742 pcb_fprintf (FP, "\tElementLine [%mr %mr %mr %mr %mr]\n",
743 line->Point1.X - element->MarkX,
744 line->Point1.Y - element->MarkY,
745 line->Point2.X - element->MarkX,
746 line->Point2.Y - element->MarkY,
747 line->Thickness);
749 for (p = element->Arc; p != NULL; p = g_list_next (p))
751 ArcType *arc = p->data;
752 pcb_fprintf (FP, "\tElementArc [%mr %mr %mr %mr %ma %ma %mr]\n",
753 arc->X - element->MarkX,
754 arc->Y - element->MarkY,
755 arc->Width, arc->Height,
756 arc->StartAngle, arc->Delta,
757 arc->Thickness);
759 fputs ("\n\t)\n", FP);
763 /* ---------------------------------------------------------------------------
764 * writes layer data
766 static void
767 WriteLayerData (FILE * FP, Cardinal Number, LayerType *layer)
769 GList *n;
770 /* write information about non empty layers */
771 if (layer->LineN || layer->ArcN || layer->TextN || layer->PolygonN ||
772 (layer->Name && *layer->Name))
774 fprintf (FP, "Layer(%i ", (int) Number + 1);
775 PrintQuotedString (FP, (char *)EMPTY (layer->Name));
776 fputs (")\n(\n", FP);
777 WriteAttributeList (FP, &layer->Attributes, "\t");
779 for (n = layer->Line; n != NULL; n = g_list_next (n))
781 LineType *line = n->data;
782 pcb_fprintf (FP, "\tLine[%mr %mr %mr %mr %mr %mr %s]\n",
783 line->Point1.X, line->Point1.Y,
784 line->Point2.X, line->Point2.Y,
785 line->Thickness, line->Clearance,
786 F2S (line, LINE_TYPE));
788 for (n = layer->Arc; n != NULL; n = g_list_next (n))
790 ArcType *arc = n->data;
791 pcb_fprintf (FP, "\tArc[%mr %mr %mr %mr %mr %mr %ma %ma %s]\n",
792 arc->X, arc->Y, arc->Width,
793 arc->Height, arc->Thickness,
794 arc->Clearance, arc->StartAngle,
795 arc->Delta, F2S (arc, ARC_TYPE));
797 for (n = layer->Text; n != NULL; n = g_list_next (n))
799 TextType *text = n->data;
800 pcb_fprintf (FP, "\tText[%mr %mr %d %d ",
801 text->X, text->Y,
802 text->Direction, text->Scale);
803 PrintQuotedString (FP, (char *)EMPTY (text->TextString));
804 fprintf (FP, " %s]\n", F2S (text, TEXT_TYPE));
806 for (n = layer->Polygon; n != NULL; n = g_list_next (n))
808 PolygonType *polygon = n->data;
809 int p, i = 0;
810 Cardinal hole = 0;
811 fprintf (FP, "\tPolygon(%s)\n\t(", F2S (polygon, POLYGON_TYPE));
812 for (p = 0; p < polygon->PointN; p++)
814 PointType *point = &polygon->Points[p];
816 if (hole < polygon->HoleIndexN &&
817 p == polygon->HoleIndex[hole])
819 if (hole > 0)
820 fputs ("\n\t\t)", FP);
821 fputs ("\n\t\tHole (", FP);
822 hole++;
823 i = 0;
826 if (i++ % 5 == 0)
828 fputs ("\n\t\t", FP);
829 if (hole)
830 fputs ("\t", FP);
832 pcb_fprintf (FP, "[%mr %mr] ", point->X, point->Y);
834 if (hole > 0)
835 fputs ("\n\t\t)", FP);
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_copper_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;
864 if (Settings.SaveMetricOnly)
865 set_allow_readable (ALLOW_MM);
866 else
867 set_allow_readable (ALLOW_READABLE);
869 WritePCBInfoHeader (FP);
870 WritePCBDataHeader (FP);
871 WritePCBFontData (FP);
872 WriteAttributeList (FP, &PCB->Attributes, "");
873 WriteViaData (FP, PCB->Data);
874 WriteElementData (FP, PCB->Data);
875 WritePCBRatData (FP);
876 for (i = 0; i < max_copper_layer + 2; i++)
877 WriteLayerData (FP, i, &(PCB->Data->Layer[i]));
878 WritePCBNetlistData (FP);
880 return (STATUS_OK);
883 /* ---------------------------------------------------------------------------
884 * writes PCB to file
886 static int
887 WritePCBFile (char *Filename)
889 FILE *fp;
890 int result;
892 if ((fp = fopen (Filename, "w")) == NULL)
894 OpenErrorMessage (Filename);
895 return (STATUS_ERROR);
897 result = WritePCB (fp);
898 fclose (fp);
899 return (result);
902 /* ---------------------------------------------------------------------------
903 * writes to pipe using the command defined by Settings.SaveCommand
904 * %f are replaced by the passed filename
906 static int
907 WritePipe (char *Filename, bool thePcb)
909 FILE *fp;
910 int result;
911 char *p;
912 static DynamicStringType command;
913 int used_popen = 0;
915 if (EMPTY_STRING_P (Settings.SaveCommand))
917 fp = fopen (Filename, "w");
918 if (fp == 0)
920 Message ("Unable to write to file %s\n", Filename);
921 return STATUS_ERROR;
924 else
926 used_popen = 1;
927 /* setup commandline */
928 DSClearString (&command);
929 for (p = Settings.SaveCommand; *p; p++)
931 /* copy character if not special or add string to command */
932 if (!(*p == '%' && *(p + 1) == 'f'))
933 DSAddCharacter (&command, *p);
934 else
936 DSAddString (&command, Filename);
938 /* skip the character */
939 p++;
942 DSAddCharacter (&command, '\0');
943 printf ("write to pipe \"%s\"\n", command.Data);
944 if ((fp = popen (command.Data, "w")) == NULL)
946 PopenErrorMessage (command.Data);
947 return (STATUS_ERROR);
950 if (thePcb)
952 if (PCB->is_footprint)
954 WriteElementData (fp, PCB->Data);
955 result = 0;
957 else
958 result = WritePCB (fp);
960 else
961 result = WriteBuffer (fp);
963 if (used_popen)
964 return (pclose (fp) ? STATUS_ERROR : result);
965 return (fclose (fp) ? STATUS_ERROR : result);
968 /* ---------------------------------------------------------------------------
969 * saves the layout in a temporary file
970 * this is used for fatal errors and does not call the program specified
971 * in 'saveCommand' for safety reasons
973 void
974 SaveInTMP (void)
976 char filename[80];
978 /* memory might have been released before this function is called */
979 if (PCB && PCB->Changed)
981 sprintf (filename, EMERGENCY_NAME, (int) getpid ());
982 Message (_("Trying to save your layout in '%s'\n"), filename);
983 WritePCBFile (filename);
987 /* ---------------------------------------------------------------------------
988 * front-end for 'SaveInTMP()'
989 * just makes sure that the routine is only called once
991 static bool dont_save_any_more = false;
992 void
993 EmergencySave (void)
996 if (!dont_save_any_more)
998 SaveInTMP ();
999 dont_save_any_more = true;
1003 void
1004 DisableEmergencySave (void)
1006 dont_save_any_more = true;
1009 /* ----------------------------------------------------------------------
1010 * Callback for the autosave
1013 static hidval backup_timer;
1016 * If the backup interval is > 0 then set another timer. Otherwise
1017 * we do nothing and it is up to the GUI to call EnableAutosave()
1018 * after setting Settings.BackupInterval > 0 again.
1020 static void
1021 backup_cb (hidval data)
1023 backup_timer.ptr = NULL;
1024 Backup ();
1025 if (Settings.BackupInterval > 0 && gui->add_timer)
1026 backup_timer = gui->add_timer (backup_cb,
1027 1000 * Settings.BackupInterval, data);
1030 void
1031 EnableAutosave (void)
1033 hidval x;
1035 x.ptr = NULL;
1037 /* If we already have a timer going, then cancel it out */
1038 if (backup_timer.ptr != NULL && gui->stop_timer)
1039 gui->stop_timer (backup_timer);
1041 backup_timer.ptr = NULL;
1042 /* Start up a new timer */
1043 if (Settings.BackupInterval > 0 && gui->add_timer)
1044 backup_timer = gui->add_timer (backup_cb,
1045 1000 * Settings.BackupInterval,
1049 /* ---------------------------------------------------------------------------
1050 * creates backup file. The default is to use the pcb file name with
1051 * a "-" appended (like "foo.pcb-") and if we don't have a pcb file name
1052 * then use the template in BACKUP_NAME
1054 void
1055 Backup (void)
1057 char *filename = NULL;
1059 if( PCB && PCB->Filename )
1061 filename = (char *) malloc (sizeof (char) * (strlen (PCB->Filename) + 2));
1062 if (filename == NULL)
1064 fprintf (stderr, "Backup(): malloc failed\n");
1065 exit (1);
1067 sprintf (filename, "%s~", PCB->Filename);
1069 else
1071 /* BACKUP_NAME has %.8i which will be replaced by the process ID */
1072 filename = (char *) malloc (sizeof (char) * (strlen (BACKUP_NAME) + 8));
1073 if (filename == NULL)
1075 fprintf (stderr, "Backup(): malloc failed\n");
1076 exit (1);
1078 sprintf (filename, BACKUP_NAME, (int) getpid ());
1081 WritePCBFile (filename);
1082 free (filename);
1085 #if !defined(HAS_ATEXIT) && !defined(HAS_ON_EXIT)
1086 /* ---------------------------------------------------------------------------
1087 * makes a temporary copy of the data. This is useful for systems which
1088 * doesn't support calling functions on exit. We use this to save the data
1089 * before LEX and YACC functions are called because they are able to abort
1090 * the program.
1092 void
1093 SaveTMPData (void)
1095 sprintf (TMPFilename, EMERGENCY_NAME, (int) getpid ());
1096 WritePCBFile (TMPFilename);
1099 /* ---------------------------------------------------------------------------
1100 * removes the temporary copy of the data file
1102 void
1103 RemoveTMPData (void)
1105 unlink (TMPFilename);
1107 #endif
1109 /* ---------------------------------------------------------------------------
1110 * Parse the directory tree where newlib footprints are found
1113 /* This is a helper function for ParseLibrary Tree. Given a char *path,
1114 * it finds all newlib footprints in that dir, sticks them into the
1115 * library menu structure named entry, and recurses into subdirectories.
1117 static int
1118 LoadNewlibFootprintsFromDir(char *libpath, char *toppath, bool recursive)
1120 char olddir[MAXPATHLEN + 1]; /* The directory we start out in (cwd) */
1121 char subdir[MAXPATHLEN + 1]; /* The directory holding footprints to load */
1122 DIR *subdirobj; /* Interable object holding all subdir entries */
1123 struct dirent *subdirentry; /* Individual subdir entry */
1124 struct stat buffer; /* Buffer used in stat */
1125 LibraryMenuType *menu = NULL; /* Pointer to PCB's library menu structure */
1126 LibraryEntryType *entry; /* Pointer to individual menu entry */
1127 size_t l;
1128 size_t len;
1129 int n_footprints = 0; /* Running count of footprints found in this subdir */
1131 /* Cache old dir, then cd into subdir because stat is given relative file names. */
1132 memset (subdir, 0, sizeof subdir);
1133 memset (olddir, 0, sizeof olddir);
1134 if (GetWorkingDirectory (olddir) == NULL)
1136 Message (_("LoadNewlibFootprintsFromDir: Could not determine initial working directory\n"));
1137 return 0;
1140 if (strcmp (libpath, "(local)") == 0)
1141 strcpy (subdir, ".");
1142 else
1143 strcpy (subdir, libpath);
1145 if (chdir (subdir))
1147 ChdirErrorMessage (subdir);
1148 return 0;
1151 /* Determine subdir is abs path */
1152 if (GetWorkingDirectory (subdir) == NULL)
1154 Message (_("LoadNewlibFootprintsFromDir: Could not determine new working directory\n"));
1155 if (chdir (olddir))
1156 ChdirErrorMessage (olddir);
1157 return 0;
1160 /* First try opening the directory specified by path */
1161 if ( (subdirobj = opendir (subdir)) == NULL )
1163 OpendirErrorMessage (subdir);
1164 if (chdir (olddir))
1165 ChdirErrorMessage (olddir);
1166 return 0;
1169 /* Get pointer to memory holding menu */
1170 menu = GetLibraryMenuMemory (&Library);
1171 /* Populate menuname and path vars */
1172 menu->Name = strdup (subdir);
1173 menu->directory = strdup (toppath);
1175 /* Now loop over files in this directory looking for files.
1176 * We ignore certain files which are not footprints.
1178 while ((subdirentry = readdir (subdirobj)) != NULL)
1180 #ifdef DEBUG
1181 /* printf("... Examining file %s ... \n", subdirentry->d_name); */
1182 #endif
1184 /* Ignore non-footprint files found in this directory
1185 * We're skipping .png and .html because those
1186 * may exist in a library tree to provide an html browsable
1187 * index of the library.
1189 l = strlen (subdirentry->d_name);
1190 if (!stat (subdirentry->d_name, &buffer) && S_ISREG (buffer.st_mode)
1191 && subdirentry->d_name[0] != '.'
1192 && NSTRCMP (subdirentry->d_name, "CVS") != 0
1193 && NSTRCMP (subdirentry->d_name, "Makefile") != 0
1194 && NSTRCMP (subdirentry->d_name, "Makefile.am") != 0
1195 && NSTRCMP (subdirentry->d_name, "Makefile.in") != 0
1196 && (l < 4 || NSTRCMP(subdirentry->d_name + (l - 4), ".png") != 0)
1197 && (l < 5 || NSTRCMP(subdirentry->d_name + (l - 5), ".html") != 0)
1198 && (l < 4 || NSTRCMP(subdirentry->d_name + (l - 4), ".pcb") != 0) )
1200 #ifdef DEBUG
1201 /* printf("... Found a footprint %s ... \n", subdirentry->d_name); */
1202 #endif
1203 n_footprints++;
1204 entry = GetLibraryEntryMemory (menu);
1207 * entry->AllocatedMemory points to abs path to the footprint.
1208 * entry->ListEntry points to fp name itself.
1210 len = strlen(subdir) + strlen("/") + strlen(subdirentry->d_name) + 1;
1211 entry->AllocatedMemory = (char *)calloc (1, len);
1212 strcat (entry->AllocatedMemory, subdir);
1213 strcat (entry->AllocatedMemory, PCB_DIR_SEPARATOR_S);
1215 /* store pointer to start of footprint name */
1216 entry->ListEntry = entry->AllocatedMemory
1217 + strlen (entry->AllocatedMemory);
1219 /* Now place footprint name into AllocatedMemory */
1220 strcat (entry->AllocatedMemory, subdirentry->d_name);
1222 /* mark as directory tree (newlib) library */
1223 entry->Template = (char *) -1;
1226 closedir (subdirobj);
1228 /* Don't recurse into relatively-specified directories--we might be
1229 in the user's working directory, and the path might be "." */
1230 if (!recursive) {
1231 if (chdir (olddir))
1232 ChdirErrorMessage (olddir);
1233 return n_footprints;
1236 /* Then open this dir so we can loop over its contents. */
1237 if ((subdirobj = opendir (subdir)) == NULL)
1239 OpendirErrorMessage (subdir);
1240 if (chdir (olddir))
1241 ChdirErrorMessage (olddir);
1242 return 0;
1245 /* Now loop over files in this directory looking for subdirs.
1246 * For each direntry which is a valid subdirectory,
1247 * try to load newlib footprints inside it.
1249 while ((subdirentry = readdir (subdirobj)) != NULL)
1251 #ifdef DEBUG
1252 printf("In ParseLibraryTree loop examining 2nd level direntry %s ... \n", subdirentry->d_name);
1253 #endif
1254 /* Find subdirectories. Ignore entries beginning with "." and CVS
1255 * directories.
1257 if (!stat (subdirentry->d_name, &buffer)
1258 && S_ISDIR (buffer.st_mode)
1259 && subdirentry->d_name[0] != '.'
1260 && NSTRCMP (subdirentry->d_name, "CVS") != 0)
1262 /* Found a valid subdirectory. Try to load footprints from it.
1264 char *subdir_path = (char *)calloc (
1265 1, strlen(subdir) + strlen("/") + strlen(subdirentry->d_name) + 1);
1266 if (subdir_path == NULL)
1268 fprintf (stderr, "LoadNewlibFootprintsFromDir(): "
1269 "malloc failed\n");
1270 closedir (subdirobj);
1271 if (chdir (olddir))
1272 ChdirErrorMessage (olddir);
1273 return n_footprints;
1275 strcat (subdir_path, subdir);
1276 strcat (subdir_path, PCB_DIR_SEPARATOR_S);
1277 strcat (subdir_path, subdirentry->d_name);
1279 n_footprints += LoadNewlibFootprintsFromDir(subdir_path, toppath, true);
1280 free(subdir_path);
1283 /* Done. Clean up, cd back into old dir, and return */
1284 closedir (subdirobj);
1285 if (chdir (olddir))
1286 ChdirErrorMessage (olddir);
1287 return n_footprints;
1291 /* This function loads the newlib footprints into the Library.
1292 * It examines all directories pointed to by Settings.LibraryTree.
1293 * It calls the subfunction LoadNewlibFootprintsFromDir to put the
1294 * footprints into PCB's internal datastructures.
1296 static int
1297 ParseLibraryTree (void)
1299 char toppath[MAXPATHLEN + 1]; /* String holding abs path to top level library dir */
1300 char working[MAXPATHLEN + 1]; /* String holding abs path to working dir */
1301 char *libpaths; /* String holding list of library paths to search */
1302 char *p; /* Helper string used in iteration */
1303 int n_footprints = 0; /* Running count of footprints found */
1305 /* Initialize path, working by writing 0 into every byte. */
1306 memset (toppath, 0, sizeof toppath);
1307 memset (working, 0, sizeof working);
1309 /* Save the current working directory as an absolute path.
1310 * This fcn writes the abs path into the memory pointed to by the input arg.
1312 if (GetWorkingDirectory (working) == NULL)
1314 Message (_("ParseLibraryTree: Could not determine initial working directory\n"));
1315 return 0;
1318 /* Additional loop to allow for multiple 'newlib' style library directories
1319 * called out in Settings.LibraryTree
1321 libpaths = strdup (Settings.LibraryTree);
1322 for (p = strtok (libpaths, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER))
1324 /* remove trailing path delimeter */
1325 strncpy (toppath, p, sizeof (toppath) - 1);
1327 /* start out in the working directory in case the path is a
1328 * relative path
1330 if (chdir (working))
1332 ChdirErrorMessage (working);
1333 free (libpaths);
1334 return 0;
1338 * Next change to the directory which is the top of the library tree
1339 * and extract its abs path.
1341 if (chdir (toppath))
1343 ChdirErrorMessage (toppath);
1344 continue;
1347 if (GetWorkingDirectory (toppath) == NULL)
1349 Message (_("ParseLibraryTree: Could not determine new working directory\n"));
1350 continue;
1353 #ifdef DEBUG
1354 printf("In ParseLibraryTree, looking for newlib footprints inside top level directory %s ... \n",
1355 toppath);
1356 #endif
1358 /* Next read in any footprints in the top level dir and below */
1359 n_footprints += LoadNewlibFootprintsFromDir("(local)", toppath, *p == '/');
1362 /* restore the original working directory */
1363 if (chdir (working))
1364 ChdirErrorMessage (working);
1366 #ifdef DEBUG
1367 printf("Leaving ParseLibraryTree, found %d footprints.\n", n_footprints);
1368 #endif
1370 free (libpaths);
1371 return n_footprints;
1374 /* ---------------------------------------------------------------------------
1375 * Read contents of the library description file (for M4)
1376 * and then read in M4 libs. Then call a fcn to read the newlib
1377 * footprints.
1380 ReadLibraryContents (void)
1382 static char *command = NULL;
1383 char inputline[MAX_LIBRARY_LINE_LENGTH + 1];
1384 FILE *resultFP = NULL;
1385 LibraryMenuType *menu = NULL;
1386 LibraryEntryType *entry;
1388 /* If we don't have a command to execute to find the library contents,
1389 * skip this. This is used by default on Windows builds (set in main.c),
1390 * as we can't normally run shell scripts or expect to have m4 present.
1392 if (Settings.LibraryContentsCommand != NULL &&
1393 Settings.LibraryContentsCommand[0] != '\0')
1395 /* First load the M4 stuff. The variable Settings.LibraryPath
1396 * points to it.
1398 free (command);
1399 command = EvaluateFilename (Settings.LibraryContentsCommand,
1400 Settings.LibraryPath, Settings.LibraryFilename,
1401 NULL);
1403 #ifdef DEBUG
1404 printf("In ReadLibraryContents, about to execute command %s\n", command);
1405 #endif
1407 /* This uses a pipe to execute a shell script which provides the names of
1408 * all M4 libs and footprints. The results are placed in resultFP.
1410 if (command && *command && (resultFP = popen (command, "r")) == NULL)
1412 PopenErrorMessage (command);
1415 /* the M4 library contents are separated by colons;
1416 * template : package : name : description
1418 while (resultFP != NULL && fgets (inputline, MAX_LIBRARY_LINE_LENGTH, resultFP))
1420 size_t len = strlen (inputline);
1422 /* check for maximum linelength */
1423 if (len)
1425 len--;
1426 if (inputline[len] != '\n')
1427 Message
1428 ("linelength (%i) exceeded; following characters will be ignored\n",
1429 MAX_LIBRARY_LINE_LENGTH);
1430 else
1431 inputline[len] = '\0';
1434 /* if the line defines a menu */
1435 if (!strncmp (inputline, "TYPE=", 5))
1437 menu = GetLibraryMenuMemory (&Library);
1438 menu->Name = strdup (UNKNOWN (&inputline[5]));
1439 menu->directory = strdup (Settings.LibraryFilename);
1441 else
1443 /* allocate a new menu entry if not already done */
1444 if (!menu)
1446 menu = GetLibraryMenuMemory (&Library);
1447 menu->Name = strdup (UNKNOWN ((char *) NULL));
1448 menu->directory = strdup (Settings.LibraryFilename);
1450 entry = GetLibraryEntryMemory (menu);
1451 entry->AllocatedMemory = strdup (inputline);
1453 /* now break the line into pieces separated by colons */
1454 if ((entry->Template = strtok (entry->AllocatedMemory, ":")) !=
1455 NULL)
1456 if ((entry->Package = strtok (NULL, ":")) != NULL)
1457 if ((entry->Value = strtok (NULL, ":")) != NULL)
1458 entry->Description = strtok (NULL, ":");
1460 /* create the list entry */
1461 len = strlen (EMPTY (entry->Value)) +
1462 strlen (EMPTY (entry->Description)) + 4;
1463 entry->ListEntry = (char *)calloc (len, sizeof (char));
1464 sprintf (entry->ListEntry,
1465 "%s, %s", EMPTY (entry->Value),
1466 EMPTY (entry->Description));
1469 if (resultFP != NULL)
1470 pclose (resultFP);
1473 /* Now after reading in the M4 libs, call a function to
1474 * read the newlib footprint libraries. Then sort the whole
1475 * library.
1477 if (ParseLibraryTree () > 0 || resultFP != NULL)
1479 sort_library (&Library);
1480 return 0;
1483 return (1);
1486 #define BLANK(x) ((x) == ' ' || (x) == '\t' || (x) == '\n' \
1487 || (x) == '\0')
1489 /* ---------------------------------------------------------------------------
1490 * Read in a netlist and store it in the netlist menu
1494 ReadNetlist (char *filename)
1496 static char *command = NULL;
1497 char inputline[MAX_NETLIST_LINE_LENGTH + 1];
1498 char temp[MAX_NETLIST_LINE_LENGTH + 1];
1499 FILE *fp;
1500 LibraryMenuType *menu = NULL;
1501 LibraryEntryType *entry;
1502 int i, j, lines, kind;
1503 bool continued;
1504 bool used_popen = false;
1505 int retval = 0;
1507 if (!filename)
1508 return 1; /* nothing to do */
1510 Message (_("Importing PCB netlist %s\n"), filename);
1512 if (EMPTY_STRING_P (Settings.RatCommand))
1514 fp = fopen (filename, "r");
1515 if (!fp)
1517 Message("Cannot open %s for reading", filename);
1518 return 1;
1521 else
1523 used_popen = true;
1524 free (command);
1525 command = EvaluateFilename (Settings.RatCommand,
1526 Settings.RatPath, filename, NULL);
1528 /* open pipe to stdout of command */
1529 if (*command == '\0' || (fp = popen (command, "r")) == NULL)
1531 PopenErrorMessage (command);
1532 return 1;
1535 lines = 0;
1536 /* kind = 0 is net name
1537 * kind = 1 is route style name
1538 * kind = 2 is connection
1540 kind = 0;
1541 while (fgets (inputline, MAX_NETLIST_LINE_LENGTH, fp))
1543 size_t len = strlen (inputline);
1544 /* check for maximum length line */
1545 if (len)
1547 if (inputline[--len] != '\n')
1548 Message (_("Line length (%i) exceeded in netlist file.\n"
1549 "additional characters will be ignored.\n"),
1550 MAX_NETLIST_LINE_LENGTH);
1551 else
1552 inputline[len] = '\0';
1554 continued = (inputline[len - 1] == '\\') ? true : false;
1555 if (continued)
1556 inputline[len - 1] = '\0';
1557 lines++;
1558 i = 0;
1559 while (inputline[i] != '\0')
1561 j = 0;
1562 /* skip leading blanks */
1563 while (inputline[i] != '\0' && BLANK (inputline[i]))
1564 i++;
1565 if (kind == 0)
1567 /* add two spaces for included/unincluded */
1568 temp[j++] = ' ';
1569 temp[j++] = ' ';
1571 while (!BLANK (inputline[i]))
1572 temp[j++] = inputline[i++];
1573 temp[j] = '\0';
1574 while (inputline[i] != '\0' && BLANK (inputline[i]))
1575 i++;
1576 if (kind == 0)
1578 menu = GetLibraryMenuMemory (&PCB->NetlistLib);
1579 menu->Name = strdup (temp);
1580 menu->flag = 1;
1581 kind++;
1583 else
1585 if (kind == 1 && strchr (temp, '-') == NULL)
1587 kind++;
1588 menu->Style = strdup (temp);
1590 else
1592 entry = GetLibraryEntryMemory (menu);
1593 entry->ListEntry = strdup (temp);
1597 if (!continued)
1598 kind = 0;
1600 if (!lines)
1602 Message (_("Empty netlist file!\n"));
1603 retval = 1;
1605 if (used_popen)
1606 pclose (fp);
1607 else
1608 fclose (fp);
1609 sort_netlist ();
1610 return retval;
1613 static int ReadEdifNetlist (char *filename);
1615 int ImportNetlist (char *filename)
1617 FILE *fp;
1618 char buf[16];
1619 int i;
1620 char* p;
1623 if (!filename) return (1); /* nothing to do */
1624 fp = fopen (filename, "r");
1625 if (!fp) return (1); /* bad filename */
1626 i = fread (buf, 1, sizeof(buf)-1, fp);
1627 fclose(fp);
1628 buf[i] = '\0';
1629 p=buf;
1630 while ( *p )
1632 *p = tolower ((int) *p);
1633 p++;
1635 p = strstr (buf, "edif");
1636 if (!p) return ReadNetlist (filename);
1637 else return ReadEdifNetlist (filename);
1640 static int ReadEdifNetlist (char *filename)
1642 Message (_("Importing edif netlist %s\n"), filename);
1643 ParseEDIF(filename, NULL);
1645 return 0;