Avoid hard-coding the number of extra layers in use (for 2x silkscreen)
[geda-pcb/pcjc2.git] / src / file.c
blob657efebfc9178d07a787bfcf1fe867b7db9042b1
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 ();
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[%mr %mr %mr %d]\n", PCB->Grid,
563 PCB->GridOffsetX, PCB->GridOffsetY, Settings.DrawGrid);
564 /* PolyArea should be output in square cmils, no suffix */
565 fprintf (FP, "PolyArea[%s]\n", c_dtostr (COORD_TO_MIL (COORD_TO_MIL (PCB->IsleArea) * 100) * 100));
566 pcb_fprintf (FP, "Thermal[%s]\n", c_dtostr (PCB->ThermScale));
567 pcb_fprintf (FP, "DRC[%mr %mr %mr %mr %mr %mr]\n", PCB->Bloat, PCB->Shrink,
568 PCB->minWid, PCB->minSlk, PCB->minDrill, PCB->minRing);
569 fprintf (FP, "Flags(%s)\n", pcbflags_to_string(PCB->Flags));
570 fprintf (FP, "Groups(\"%s\")\n", LayerGroupsToString (&PCB->LayerGroups));
571 fputs ("Styles[\"", FP);
572 for (group = 0; group < NUM_STYLES - 1; group++)
573 pcb_fprintf (FP, "%s,%mr,%mr,%mr,%mr:", PCB->RouteStyle[group].Name,
574 PCB->RouteStyle[group].Thick,
575 PCB->RouteStyle[group].Diameter,
576 PCB->RouteStyle[group].Hole, PCB->RouteStyle[group].Keepaway);
577 pcb_fprintf (FP, "%s,%mr,%mr,%mr,%mr\"]\n\n", PCB->RouteStyle[group].Name,
578 PCB->RouteStyle[group].Thick,
579 PCB->RouteStyle[group].Diameter,
580 PCB->RouteStyle[group].Hole, PCB->RouteStyle[group].Keepaway);
583 /* ---------------------------------------------------------------------------
584 * writes font data of non empty symbols
586 static void
587 WritePCBFontData (FILE * FP)
589 Cardinal i, j;
590 LineType *line;
591 FontType *font;
593 for (font = &PCB->Font, i = 0; i <= MAX_FONTPOSITION; i++)
595 if (!font->Symbol[i].Valid)
596 continue;
598 if (isprint (i))
599 pcb_fprintf (FP, "Symbol['%c' %mr]\n(\n", i, font->Symbol[i].Delta);
600 else
601 pcb_fprintf (FP, "Symbol[%i %mr]\n(\n", i, font->Symbol[i].Delta);
603 line = font->Symbol[i].Line;
604 for (j = font->Symbol[i].LineN; j; j--, line++)
605 pcb_fprintf (FP, "\tSymbolLine[%mr %mr %mr %mr %mr]\n",
606 line->Point1.X, line->Point1.Y,
607 line->Point2.X, line->Point2.Y, line->Thickness);
608 fputs (")\n", FP);
612 /* ---------------------------------------------------------------------------
613 * writes via data
615 static void
616 WriteViaData (FILE * FP, DataType *Data)
618 GList *iter;
619 /* write information about vias */
620 for (iter = Data->Via; iter != NULL; iter = g_list_next (iter))
622 PinType *via = iter->data;
623 pcb_fprintf (FP, "Via[%mr %mr %mr %mr %mr %mr ", via->X, via->Y,
624 via->Thickness, via->Clearance, via->Mask, via->DrillingHole);
625 PrintQuotedString (FP, (char *)EMPTY (via->Name));
626 fprintf (FP, " %s]\n", F2S (via, VIA_TYPE));
630 /* ---------------------------------------------------------------------------
631 * writes rat-line data
633 static void
634 WritePCBRatData (FILE * FP)
636 GList *iter;
637 /* write information about rats */
638 for (iter = PCB->Data->Rat; iter != NULL; iter = g_list_next (iter))
640 RatType *line = iter->data;
641 pcb_fprintf (FP, "Rat[%mr %mr %d %mr %mr %d ",
642 line->Point1.X, line->Point1.Y, line->group1,
643 line->Point2.X, line->Point2.Y, line->group2);
644 fprintf (FP, " %s]\n", F2S (line, RATLINE_TYPE));
648 /* ---------------------------------------------------------------------------
649 * writes netlist data
651 static void
652 WritePCBNetlistData (FILE * FP)
654 /* write out the netlist if it exists */
655 if (PCB->NetlistLib.MenuN)
657 int n, p;
658 fprintf (FP, "NetList()\n(\n");
660 for (n = 0; n < PCB->NetlistLib.MenuN; n++)
662 LibraryMenuType *menu = &PCB->NetlistLib.Menu[n];
663 fprintf (FP, "\tNet(");
664 PrintQuotedString(FP, &menu->Name[2]);
665 fprintf (FP, " ");
666 PrintQuotedString(FP, (char *)UNKNOWN (menu->Style));
667 fprintf (FP, ")\n\t(\n");
668 for (p = 0; p < menu->EntryN; p++)
670 LibraryEntryType *entry = &menu->Entry[p];
671 fprintf (FP, "\t\tConnect(");
672 PrintQuotedString (FP, entry->ListEntry);
673 fprintf (FP, ")\n");
675 fprintf (FP, "\t)\n");
677 fprintf (FP, ")\n");
681 /* ---------------------------------------------------------------------------
682 * writes element data
684 static void
685 WriteElementData (FILE * FP, DataType *Data)
687 GList *n, *p;
688 for (n = Data->Element; n != NULL; n = g_list_next (n))
690 ElementType *element = n->data;
692 /* only non empty elements */
693 if (!element->LineN && !element->PinN && !element->ArcN
694 && !element->PadN)
695 continue;
696 /* the coordinates and text-flags are the same for
697 * both names of an element
699 fprintf (FP, "\nElement[%s ", F2S (element, ELEMENT_TYPE));
700 PrintQuotedString (FP, (char *)EMPTY (DESCRIPTION_NAME (element)));
701 fputc (' ', FP);
702 PrintQuotedString (FP, (char *)EMPTY (NAMEONPCB_NAME (element)));
703 fputc (' ', FP);
704 PrintQuotedString (FP, (char *)EMPTY (VALUE_NAME (element)));
705 pcb_fprintf (FP, " %mr %mr %mr %mr %d %d %s]\n(\n",
706 element->MarkX, element->MarkY,
707 DESCRIPTION_TEXT (element).X - element->MarkX,
708 DESCRIPTION_TEXT (element).Y - element->MarkY,
709 DESCRIPTION_TEXT (element).Direction,
710 DESCRIPTION_TEXT (element).Scale,
711 F2S (&(DESCRIPTION_TEXT (element)), ELEMENTNAME_TYPE));
712 WriteAttributeList (FP, &element->Attributes, "\t");
713 for (p = element->Pin; p != NULL; p = g_list_next (p))
715 PinType *pin = p->data;
716 pcb_fprintf (FP, "\tPin[%mr %mr %mr %mr %mr %mr ",
717 pin->X - element->MarkX,
718 pin->Y - element->MarkY,
719 pin->Thickness, pin->Clearance,
720 pin->Mask, pin->DrillingHole);
721 PrintQuotedString (FP, (char *)EMPTY (pin->Name));
722 fprintf (FP, " ");
723 PrintQuotedString (FP, (char *)EMPTY (pin->Number));
724 fprintf (FP, " %s]\n", F2S (pin, PIN_TYPE));
726 for (p = element->Pad; p != NULL; p = g_list_next (p))
728 PadType *pad = p->data;
729 pcb_fprintf (FP, "\tPad[%mr %mr %mr %mr %mr %mr %mr ",
730 pad->Point1.X - element->MarkX,
731 pad->Point1.Y - element->MarkY,
732 pad->Point2.X - element->MarkX,
733 pad->Point2.Y - element->MarkY,
734 pad->Thickness, pad->Clearance, pad->Mask);
735 PrintQuotedString (FP, (char *)EMPTY (pad->Name));
736 fprintf (FP, " ");
737 PrintQuotedString (FP, (char *)EMPTY (pad->Number));
738 fprintf (FP, " %s]\n", F2S (pad, PAD_TYPE));
740 for (p = element->Line; p != NULL; p = g_list_next (p))
742 LineType *line = p->data;
743 pcb_fprintf (FP, "\tElementLine [%mr %mr %mr %mr %mr]\n",
744 line->Point1.X - element->MarkX,
745 line->Point1.Y - element->MarkY,
746 line->Point2.X - element->MarkX,
747 line->Point2.Y - element->MarkY,
748 line->Thickness);
750 for (p = element->Arc; p != NULL; p = g_list_next (p))
752 ArcType *arc = p->data;
753 pcb_fprintf (FP, "\tElementArc [%mr %mr %mr %mr %ma %ma %mr]\n",
754 arc->X - element->MarkX,
755 arc->Y - element->MarkY,
756 arc->Width, arc->Height,
757 arc->StartAngle, arc->Delta,
758 arc->Thickness);
760 fputs ("\n\t)\n", FP);
764 /* ---------------------------------------------------------------------------
765 * writes layer data
767 static void
768 WriteLayerData (FILE * FP, Cardinal Number, LayerType *layer)
770 GList *n;
771 /* write information about non empty layers */
772 if (layer->LineN || layer->ArcN || layer->TextN || layer->PolygonN ||
773 (layer->Name && *layer->Name))
775 fprintf (FP, "Layer(%i ", (int) Number + 1);
776 PrintQuotedString (FP, (char *)EMPTY (layer->Name));
777 fputs (")\n(\n", FP);
778 WriteAttributeList (FP, &layer->Attributes, "\t");
780 for (n = layer->Line; n != NULL; n = g_list_next (n))
782 LineType *line = n->data;
783 pcb_fprintf (FP, "\tLine[%mr %mr %mr %mr %mr %mr %s]\n",
784 line->Point1.X, line->Point1.Y,
785 line->Point2.X, line->Point2.Y,
786 line->Thickness, line->Clearance,
787 F2S (line, LINE_TYPE));
789 for (n = layer->Arc; n != NULL; n = g_list_next (n))
791 ArcType *arc = n->data;
792 pcb_fprintf (FP, "\tArc[%mr %mr %mr %mr %mr %mr %ma %ma %s]\n",
793 arc->X, arc->Y, arc->Width,
794 arc->Height, arc->Thickness,
795 arc->Clearance, arc->StartAngle,
796 arc->Delta, F2S (arc, ARC_TYPE));
798 for (n = layer->Text; n != NULL; n = g_list_next (n))
800 TextType *text = n->data;
801 pcb_fprintf (FP, "\tText[%mr %mr %d %d ",
802 text->X, text->Y,
803 text->Direction, text->Scale);
804 PrintQuotedString (FP, (char *)EMPTY (text->TextString));
805 fprintf (FP, " %s]\n", F2S (text, TEXT_TYPE));
807 for (n = layer->Polygon; n != NULL; n = g_list_next (n))
809 PolygonType *polygon = n->data;
810 int p, i = 0;
811 Cardinal hole = 0;
812 fprintf (FP, "\tPolygon(%s)\n\t(", F2S (polygon, POLYGON_TYPE));
813 for (p = 0; p < polygon->PointN; p++)
815 PointType *point = &polygon->Points[p];
817 if (hole < polygon->HoleIndexN &&
818 p == polygon->HoleIndex[hole])
820 if (hole > 0)
821 fputs ("\n\t\t)", FP);
822 fputs ("\n\t\tHole (", FP);
823 hole++;
824 i = 0;
827 if (i++ % 5 == 0)
829 fputs ("\n\t\t", FP);
830 if (hole)
831 fputs ("\t", FP);
833 pcb_fprintf (FP, "[%mr %mr] ", point->X, point->Y);
835 if (hole > 0)
836 fputs ("\n\t\t)", FP);
837 fputs ("\n\t)\n", FP);
839 fputs (")\n", FP);
843 /* ---------------------------------------------------------------------------
844 * writes just the elements in the buffer to file
846 static int
847 WriteBuffer (FILE * FP)
849 Cardinal i;
851 WriteViaData (FP, PASTEBUFFER->Data);
852 WriteElementData (FP, PASTEBUFFER->Data);
853 for (i = 0; i < max_copper_layer + EXTRA_LAYERS; i++)
854 WriteLayerData (FP, i, &(PASTEBUFFER->Data->Layer[i]));
855 return (STATUS_OK);
858 /* ---------------------------------------------------------------------------
859 * writes PCB to file
861 static int
862 WritePCB (FILE * FP)
864 Cardinal i;
865 if (Settings.SaveMetricOnly)
866 set_allow_readable (ALLOW_MM);
867 else
868 set_allow_readable (ALLOW_READABLE);
870 WritePCBInfoHeader (FP);
871 WritePCBDataHeader (FP);
872 WritePCBFontData (FP);
873 WriteAttributeList (FP, &PCB->Attributes, "");
874 WriteViaData (FP, PCB->Data);
875 WriteElementData (FP, PCB->Data);
876 WritePCBRatData (FP);
877 for (i = 0; i < max_copper_layer + EXTRA_LAYERS; i++)
878 WriteLayerData (FP, i, &(PCB->Data->Layer[i]));
879 WritePCBNetlistData (FP);
881 return (STATUS_OK);
884 /* ---------------------------------------------------------------------------
885 * writes PCB to file
887 static int
888 WritePCBFile (char *Filename)
890 FILE *fp;
891 int result;
893 if ((fp = fopen (Filename, "w")) == NULL)
895 OpenErrorMessage (Filename);
896 return (STATUS_ERROR);
898 result = WritePCB (fp);
899 fclose (fp);
900 return (result);
903 /* ---------------------------------------------------------------------------
904 * writes to pipe using the command defined by Settings.SaveCommand
905 * %f are replaced by the passed filename
907 static int
908 WritePipe (char *Filename, bool thePcb)
910 FILE *fp;
911 int result;
912 char *p;
913 static DynamicStringType command;
914 int used_popen = 0;
916 if (EMPTY_STRING_P (Settings.SaveCommand))
918 fp = fopen (Filename, "w");
919 if (fp == 0)
921 Message ("Unable to write to file %s\n", Filename);
922 return STATUS_ERROR;
925 else
927 used_popen = 1;
928 /* setup commandline */
929 DSClearString (&command);
930 for (p = Settings.SaveCommand; *p; p++)
932 /* copy character if not special or add string to command */
933 if (!(*p == '%' && *(p + 1) == 'f'))
934 DSAddCharacter (&command, *p);
935 else
937 DSAddString (&command, Filename);
939 /* skip the character */
940 p++;
943 DSAddCharacter (&command, '\0');
944 printf ("write to pipe \"%s\"\n", command.Data);
945 if ((fp = popen (command.Data, "w")) == NULL)
947 PopenErrorMessage (command.Data);
948 return (STATUS_ERROR);
951 if (thePcb)
953 if (PCB->is_footprint)
955 WriteElementData (fp, PCB->Data);
956 result = 0;
958 else
959 result = WritePCB (fp);
961 else
962 result = WriteBuffer (fp);
964 if (used_popen)
965 return (pclose (fp) ? STATUS_ERROR : result);
966 return (fclose (fp) ? STATUS_ERROR : result);
969 /* ---------------------------------------------------------------------------
970 * saves the layout in a temporary file
971 * this is used for fatal errors and does not call the program specified
972 * in 'saveCommand' for safety reasons
974 void
975 SaveInTMP (void)
977 char filename[80];
979 /* memory might have been released before this function is called */
980 if (PCB && PCB->Changed)
982 sprintf (filename, EMERGENCY_NAME, (int) getpid ());
983 Message (_("Trying to save your layout in '%s'\n"), filename);
984 WritePCBFile (filename);
988 /* ---------------------------------------------------------------------------
989 * front-end for 'SaveInTMP()'
990 * just makes sure that the routine is only called once
992 static bool dont_save_any_more = false;
993 void
994 EmergencySave (void)
997 if (!dont_save_any_more)
999 SaveInTMP ();
1000 dont_save_any_more = true;
1004 void
1005 DisableEmergencySave (void)
1007 dont_save_any_more = true;
1010 /* ----------------------------------------------------------------------
1011 * Callback for the autosave
1014 static hidval backup_timer;
1017 * If the backup interval is > 0 then set another timer. Otherwise
1018 * we do nothing and it is up to the GUI to call EnableAutosave()
1019 * after setting Settings.BackupInterval > 0 again.
1021 static void
1022 backup_cb (hidval data)
1024 backup_timer.ptr = NULL;
1025 Backup ();
1026 if (Settings.BackupInterval > 0 && gui->add_timer)
1027 backup_timer = gui->add_timer (backup_cb,
1028 1000 * Settings.BackupInterval, data);
1031 void
1032 EnableAutosave (void)
1034 hidval x;
1036 x.ptr = NULL;
1038 /* If we already have a timer going, then cancel it out */
1039 if (backup_timer.ptr != NULL && gui->stop_timer)
1040 gui->stop_timer (backup_timer);
1042 backup_timer.ptr = NULL;
1043 /* Start up a new timer */
1044 if (Settings.BackupInterval > 0 && gui->add_timer)
1045 backup_timer = gui->add_timer (backup_cb,
1046 1000 * Settings.BackupInterval,
1050 /* ---------------------------------------------------------------------------
1051 * creates backup file. The default is to use the pcb file name with
1052 * a "-" appended (like "foo.pcb-") and if we don't have a pcb file name
1053 * then use the template in BACKUP_NAME
1055 void
1056 Backup (void)
1058 char *filename = NULL;
1060 if( PCB && PCB->Filename )
1062 filename = (char *) malloc (sizeof (char) * (strlen (PCB->Filename) + 2));
1063 if (filename == NULL)
1065 fprintf (stderr, "Backup(): malloc failed\n");
1066 exit (1);
1068 sprintf (filename, "%s~", PCB->Filename);
1070 else
1072 /* BACKUP_NAME has %.8i which will be replaced by the process ID */
1073 filename = (char *) malloc (sizeof (char) * (strlen (BACKUP_NAME) + 8));
1074 if (filename == NULL)
1076 fprintf (stderr, "Backup(): malloc failed\n");
1077 exit (1);
1079 sprintf (filename, BACKUP_NAME, (int) getpid ());
1082 WritePCBFile (filename);
1083 free (filename);
1086 #if !defined(HAS_ATEXIT) && !defined(HAS_ON_EXIT)
1087 /* ---------------------------------------------------------------------------
1088 * makes a temporary copy of the data. This is useful for systems which
1089 * doesn't support calling functions on exit. We use this to save the data
1090 * before LEX and YACC functions are called because they are able to abort
1091 * the program.
1093 void
1094 SaveTMPData (void)
1096 sprintf (TMPFilename, EMERGENCY_NAME, (int) getpid ());
1097 WritePCBFile (TMPFilename);
1100 /* ---------------------------------------------------------------------------
1101 * removes the temporary copy of the data file
1103 void
1104 RemoveTMPData (void)
1106 unlink (TMPFilename);
1108 #endif
1110 /* ---------------------------------------------------------------------------
1111 * Parse the directory tree where newlib footprints are found
1114 /* This is a helper function for ParseLibrary Tree. Given a char *path,
1115 * it finds all newlib footprints in that dir, sticks them into the
1116 * library menu structure named entry, and recurses into subdirectories.
1118 static int
1119 LoadNewlibFootprintsFromDir(char *libpath, char *toppath, bool recursive)
1121 char olddir[MAXPATHLEN + 1]; /* The directory we start out in (cwd) */
1122 char subdir[MAXPATHLEN + 1]; /* The directory holding footprints to load */
1123 DIR *subdirobj; /* Interable object holding all subdir entries */
1124 struct dirent *subdirentry; /* Individual subdir entry */
1125 struct stat buffer; /* Buffer used in stat */
1126 LibraryMenuType *menu = NULL; /* Pointer to PCB's library menu structure */
1127 LibraryEntryType *entry; /* Pointer to individual menu entry */
1128 size_t l;
1129 size_t len;
1130 int n_footprints = 0; /* Running count of footprints found in this subdir */
1132 /* Cache old dir, then cd into subdir because stat is given relative file names. */
1133 memset (subdir, 0, sizeof subdir);
1134 memset (olddir, 0, sizeof olddir);
1135 if (GetWorkingDirectory (olddir) == NULL)
1137 Message (_("LoadNewlibFootprintsFromDir: Could not determine initial working directory\n"));
1138 return 0;
1141 if (strcmp (libpath, "(local)") == 0)
1142 strcpy (subdir, ".");
1143 else
1144 strcpy (subdir, libpath);
1146 if (chdir (subdir))
1148 ChdirErrorMessage (subdir);
1149 return 0;
1152 /* Determine subdir is abs path */
1153 if (GetWorkingDirectory (subdir) == NULL)
1155 Message (_("LoadNewlibFootprintsFromDir: Could not determine new working directory\n"));
1156 if (chdir (olddir))
1157 ChdirErrorMessage (olddir);
1158 return 0;
1161 /* First try opening the directory specified by path */
1162 if ( (subdirobj = opendir (subdir)) == NULL )
1164 OpendirErrorMessage (subdir);
1165 if (chdir (olddir))
1166 ChdirErrorMessage (olddir);
1167 return 0;
1170 /* Get pointer to memory holding menu */
1171 menu = GetLibraryMenuMemory (&Library);
1172 /* Populate menuname and path vars */
1173 menu->Name = strdup (subdir);
1174 menu->directory = strdup (toppath);
1176 /* Now loop over files in this directory looking for files.
1177 * We ignore certain files which are not footprints.
1179 while ((subdirentry = readdir (subdirobj)) != NULL)
1181 #ifdef DEBUG
1182 /* printf("... Examining file %s ... \n", subdirentry->d_name); */
1183 #endif
1185 /* Ignore non-footprint files found in this directory
1186 * We're skipping .png and .html because those
1187 * may exist in a library tree to provide an html browsable
1188 * index of the library.
1190 l = strlen (subdirentry->d_name);
1191 if (!stat (subdirentry->d_name, &buffer) && S_ISREG (buffer.st_mode)
1192 && subdirentry->d_name[0] != '.'
1193 && NSTRCMP (subdirentry->d_name, "CVS") != 0
1194 && NSTRCMP (subdirentry->d_name, "Makefile") != 0
1195 && NSTRCMP (subdirentry->d_name, "Makefile.am") != 0
1196 && NSTRCMP (subdirentry->d_name, "Makefile.in") != 0
1197 && (l < 4 || NSTRCMP(subdirentry->d_name + (l - 4), ".png") != 0)
1198 && (l < 5 || NSTRCMP(subdirentry->d_name + (l - 5), ".html") != 0)
1199 && (l < 4 || NSTRCMP(subdirentry->d_name + (l - 4), ".pcb") != 0) )
1201 #ifdef DEBUG
1202 /* printf("... Found a footprint %s ... \n", subdirentry->d_name); */
1203 #endif
1204 n_footprints++;
1205 entry = GetLibraryEntryMemory (menu);
1208 * entry->AllocatedMemory points to abs path to the footprint.
1209 * entry->ListEntry points to fp name itself.
1211 len = strlen(subdir) + strlen("/") + strlen(subdirentry->d_name) + 1;
1212 entry->AllocatedMemory = (char *)calloc (1, len);
1213 strcat (entry->AllocatedMemory, subdir);
1214 strcat (entry->AllocatedMemory, PCB_DIR_SEPARATOR_S);
1216 /* store pointer to start of footprint name */
1217 entry->ListEntry = entry->AllocatedMemory
1218 + strlen (entry->AllocatedMemory);
1220 /* Now place footprint name into AllocatedMemory */
1221 strcat (entry->AllocatedMemory, subdirentry->d_name);
1223 /* mark as directory tree (newlib) library */
1224 entry->Template = (char *) -1;
1227 closedir (subdirobj);
1229 /* Don't recurse into relatively-specified directories--we might be
1230 in the user's working directory, and the path might be "." */
1231 if (!recursive) {
1232 if (chdir (olddir))
1233 ChdirErrorMessage (olddir);
1234 return n_footprints;
1237 /* Then open this dir so we can loop over its contents. */
1238 if ((subdirobj = opendir (subdir)) == NULL)
1240 OpendirErrorMessage (subdir);
1241 if (chdir (olddir))
1242 ChdirErrorMessage (olddir);
1243 return 0;
1246 /* Now loop over files in this directory looking for subdirs.
1247 * For each direntry which is a valid subdirectory,
1248 * try to load newlib footprints inside it.
1250 while ((subdirentry = readdir (subdirobj)) != NULL)
1252 #ifdef DEBUG
1253 printf("In ParseLibraryTree loop examining 2nd level direntry %s ... \n", subdirentry->d_name);
1254 #endif
1255 /* Find subdirectories. Ignore entries beginning with "." and CVS
1256 * directories.
1258 if (!stat (subdirentry->d_name, &buffer)
1259 && S_ISDIR (buffer.st_mode)
1260 && subdirentry->d_name[0] != '.'
1261 && NSTRCMP (subdirentry->d_name, "CVS") != 0)
1263 /* Found a valid subdirectory. Try to load footprints from it.
1265 char *subdir_path = (char *)calloc (
1266 1, strlen(subdir) + strlen("/") + strlen(subdirentry->d_name) + 1);
1267 if (subdir_path == NULL)
1269 fprintf (stderr, "LoadNewlibFootprintsFromDir(): "
1270 "malloc failed\n");
1271 closedir (subdirobj);
1272 if (chdir (olddir))
1273 ChdirErrorMessage (olddir);
1274 return n_footprints;
1276 strcat (subdir_path, subdir);
1277 strcat (subdir_path, PCB_DIR_SEPARATOR_S);
1278 strcat (subdir_path, subdirentry->d_name);
1280 n_footprints += LoadNewlibFootprintsFromDir(subdir_path, toppath, true);
1281 free(subdir_path);
1284 /* Done. Clean up, cd back into old dir, and return */
1285 closedir (subdirobj);
1286 if (chdir (olddir))
1287 ChdirErrorMessage (olddir);
1288 return n_footprints;
1292 /* This function loads the newlib footprints into the Library.
1293 * It examines all directories pointed to by Settings.LibraryTree.
1294 * It calls the subfunction LoadNewlibFootprintsFromDir to put the
1295 * footprints into PCB's internal datastructures.
1297 static int
1298 ParseLibraryTree (void)
1300 char toppath[MAXPATHLEN + 1]; /* String holding abs path to top level library dir */
1301 char working[MAXPATHLEN + 1]; /* String holding abs path to working dir */
1302 char *libpaths; /* String holding list of library paths to search */
1303 char *p; /* Helper string used in iteration */
1304 int n_footprints = 0; /* Running count of footprints found */
1306 /* Initialize path, working by writing 0 into every byte. */
1307 memset (toppath, 0, sizeof toppath);
1308 memset (working, 0, sizeof working);
1310 /* Save the current working directory as an absolute path.
1311 * This fcn writes the abs path into the memory pointed to by the input arg.
1313 if (GetWorkingDirectory (working) == NULL)
1315 Message (_("ParseLibraryTree: Could not determine initial working directory\n"));
1316 return 0;
1319 /* Additional loop to allow for multiple 'newlib' style library directories
1320 * called out in Settings.LibraryTree
1322 libpaths = strdup (Settings.LibraryTree);
1323 for (p = strtok (libpaths, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER))
1325 /* remove trailing path delimeter */
1326 strncpy (toppath, p, sizeof (toppath) - 1);
1328 /* start out in the working directory in case the path is a
1329 * relative path
1331 if (chdir (working))
1333 ChdirErrorMessage (working);
1334 free (libpaths);
1335 return 0;
1339 * Next change to the directory which is the top of the library tree
1340 * and extract its abs path.
1342 if (chdir (toppath))
1344 ChdirErrorMessage (toppath);
1345 continue;
1348 if (GetWorkingDirectory (toppath) == NULL)
1350 Message (_("ParseLibraryTree: Could not determine new working directory\n"));
1351 continue;
1354 #ifdef DEBUG
1355 printf("In ParseLibraryTree, looking for newlib footprints inside top level directory %s ... \n",
1356 toppath);
1357 #endif
1359 /* Next read in any footprints in the top level dir and below */
1360 n_footprints += LoadNewlibFootprintsFromDir("(local)", toppath, *p == '/');
1363 /* restore the original working directory */
1364 if (chdir (working))
1365 ChdirErrorMessage (working);
1367 #ifdef DEBUG
1368 printf("Leaving ParseLibraryTree, found %d footprints.\n", n_footprints);
1369 #endif
1371 free (libpaths);
1372 return n_footprints;
1375 /* ---------------------------------------------------------------------------
1376 * Read contents of the library description file (for M4)
1377 * and then read in M4 libs. Then call a fcn to read the newlib
1378 * footprints.
1381 ReadLibraryContents (void)
1383 static char *command = NULL;
1384 char inputline[MAX_LIBRARY_LINE_LENGTH + 1];
1385 FILE *resultFP = NULL;
1386 LibraryMenuType *menu = NULL;
1387 LibraryEntryType *entry;
1389 /* If we don't have a command to execute to find the library contents,
1390 * skip this. This is used by default on Windows builds (set in main.c),
1391 * as we can't normally run shell scripts or expect to have m4 present.
1393 if (Settings.LibraryContentsCommand != NULL &&
1394 Settings.LibraryContentsCommand[0] != '\0')
1396 /* First load the M4 stuff. The variable Settings.LibraryPath
1397 * points to it.
1399 free (command);
1400 command = EvaluateFilename (Settings.LibraryContentsCommand,
1401 Settings.LibraryPath, Settings.LibraryFilename,
1402 NULL);
1404 #ifdef DEBUG
1405 printf("In ReadLibraryContents, about to execute command %s\n", command);
1406 #endif
1408 /* This uses a pipe to execute a shell script which provides the names of
1409 * all M4 libs and footprints. The results are placed in resultFP.
1411 if (command && *command && (resultFP = popen (command, "r")) == NULL)
1413 PopenErrorMessage (command);
1416 /* the M4 library contents are separated by colons;
1417 * template : package : name : description
1419 while (resultFP != NULL && fgets (inputline, MAX_LIBRARY_LINE_LENGTH, resultFP))
1421 size_t len = strlen (inputline);
1423 /* check for maximum linelength */
1424 if (len)
1426 len--;
1427 if (inputline[len] != '\n')
1428 Message
1429 ("linelength (%i) exceeded; following characters will be ignored\n",
1430 MAX_LIBRARY_LINE_LENGTH);
1431 else
1432 inputline[len] = '\0';
1435 /* if the line defines a menu */
1436 if (!strncmp (inputline, "TYPE=", 5))
1438 menu = GetLibraryMenuMemory (&Library);
1439 menu->Name = strdup (UNKNOWN (&inputline[5]));
1440 menu->directory = strdup (Settings.LibraryFilename);
1442 else
1444 /* allocate a new menu entry if not already done */
1445 if (!menu)
1447 menu = GetLibraryMenuMemory (&Library);
1448 menu->Name = strdup (UNKNOWN ((char *) NULL));
1449 menu->directory = strdup (Settings.LibraryFilename);
1451 entry = GetLibraryEntryMemory (menu);
1452 entry->AllocatedMemory = strdup (inputline);
1454 /* now break the line into pieces separated by colons */
1455 if ((entry->Template = strtok (entry->AllocatedMemory, ":")) !=
1456 NULL)
1457 if ((entry->Package = strtok (NULL, ":")) != NULL)
1458 if ((entry->Value = strtok (NULL, ":")) != NULL)
1459 entry->Description = strtok (NULL, ":");
1461 /* create the list entry */
1462 len = strlen (EMPTY (entry->Value)) +
1463 strlen (EMPTY (entry->Description)) + 4;
1464 entry->ListEntry = (char *)calloc (len, sizeof (char));
1465 sprintf (entry->ListEntry,
1466 "%s, %s", EMPTY (entry->Value),
1467 EMPTY (entry->Description));
1470 if (resultFP != NULL)
1471 pclose (resultFP);
1474 /* Now after reading in the M4 libs, call a function to
1475 * read the newlib footprint libraries. Then sort the whole
1476 * library.
1478 if (ParseLibraryTree () > 0 || resultFP != NULL)
1480 sort_library (&Library);
1481 return 0;
1484 return (1);
1487 #define BLANK(x) ((x) == ' ' || (x) == '\t' || (x) == '\n' \
1488 || (x) == '\0')
1490 /* ---------------------------------------------------------------------------
1491 * Read in a netlist and store it in the netlist menu
1495 ReadNetlist (char *filename)
1497 static char *command = NULL;
1498 char inputline[MAX_NETLIST_LINE_LENGTH + 1];
1499 char temp[MAX_NETLIST_LINE_LENGTH + 1];
1500 FILE *fp;
1501 LibraryMenuType *menu = NULL;
1502 LibraryEntryType *entry;
1503 int i, j, lines, kind;
1504 bool continued;
1505 bool used_popen = false;
1506 int retval = 0;
1508 if (!filename)
1509 return 1; /* nothing to do */
1511 Message (_("Importing PCB netlist %s\n"), filename);
1513 if (EMPTY_STRING_P (Settings.RatCommand))
1515 fp = fopen (filename, "r");
1516 if (!fp)
1518 Message("Cannot open %s for reading", filename);
1519 return 1;
1522 else
1524 used_popen = true;
1525 free (command);
1526 command = EvaluateFilename (Settings.RatCommand,
1527 Settings.RatPath, filename, NULL);
1529 /* open pipe to stdout of command */
1530 if (*command == '\0' || (fp = popen (command, "r")) == NULL)
1532 PopenErrorMessage (command);
1533 return 1;
1536 lines = 0;
1537 /* kind = 0 is net name
1538 * kind = 1 is route style name
1539 * kind = 2 is connection
1541 kind = 0;
1542 while (fgets (inputline, MAX_NETLIST_LINE_LENGTH, fp))
1544 size_t len = strlen (inputline);
1545 /* check for maximum length line */
1546 if (len)
1548 if (inputline[--len] != '\n')
1549 Message (_("Line length (%i) exceeded in netlist file.\n"
1550 "additional characters will be ignored.\n"),
1551 MAX_NETLIST_LINE_LENGTH);
1552 else
1553 inputline[len] = '\0';
1555 continued = (inputline[len - 1] == '\\') ? true : false;
1556 if (continued)
1557 inputline[len - 1] = '\0';
1558 lines++;
1559 i = 0;
1560 while (inputline[i] != '\0')
1562 j = 0;
1563 /* skip leading blanks */
1564 while (inputline[i] != '\0' && BLANK (inputline[i]))
1565 i++;
1566 if (kind == 0)
1568 /* add two spaces for included/unincluded */
1569 temp[j++] = ' ';
1570 temp[j++] = ' ';
1572 while (!BLANK (inputline[i]))
1573 temp[j++] = inputline[i++];
1574 temp[j] = '\0';
1575 while (inputline[i] != '\0' && BLANK (inputline[i]))
1576 i++;
1577 if (kind == 0)
1579 menu = GetLibraryMenuMemory (&PCB->NetlistLib);
1580 menu->Name = strdup (temp);
1581 menu->flag = 1;
1582 kind++;
1584 else
1586 if (kind == 1 && strchr (temp, '-') == NULL)
1588 kind++;
1589 menu->Style = strdup (temp);
1591 else
1593 entry = GetLibraryEntryMemory (menu);
1594 entry->ListEntry = strdup (temp);
1598 if (!continued)
1599 kind = 0;
1601 if (!lines)
1603 Message (_("Empty netlist file!\n"));
1604 retval = 1;
1606 if (used_popen)
1607 pclose (fp);
1608 else
1609 fclose (fp);
1610 sort_netlist ();
1611 return retval;
1614 static int ReadEdifNetlist (char *filename);
1616 int ImportNetlist (char *filename)
1618 FILE *fp;
1619 char buf[16];
1620 int i;
1621 char* p;
1624 if (!filename) return (1); /* nothing to do */
1625 fp = fopen (filename, "r");
1626 if (!fp) return (1); /* bad filename */
1627 i = fread (buf, 1, sizeof(buf)-1, fp);
1628 fclose(fp);
1629 buf[i] = '\0';
1630 p=buf;
1631 while ( *p )
1633 *p = tolower ((int) *p);
1634 p++;
1636 p = strstr (buf, "edif");
1637 if (!p) return ReadNetlist (filename);
1638 else return ReadEdifNetlist (filename);
1641 static int ReadEdifNetlist (char *filename)
1643 Message (_("Importing edif netlist %s\n"), filename);
1644 ParseEDIF(filename, NULL);
1646 return 0;