Followed up on this question in a separate mail. Patch is attached. Please have a good look over it, if it's going to stable I don't want to be the only one who's had a look :)
On Sat, Apr 30, 2016 at 07:57:36PM -0400, Chris Pavlina wrote: > I'm very close to finished - I'll take some time to fully test and review the > patch to ensure it's ready for a commit to stable, though - will submit > tomorrow. > > I have a question. Currently, when loading a full library as opposed to a > single footprint, we silently ignore errors and just do not load footprints > that have syntax issues. This of course means that format versioning won't > really work for these. The user will never see the hint about their version > being old. > > Should I: > 1) Leave it as is. (please say no please say no please say no) > 2) Make an exception for the version-too-new case. > 3) Change this and *do* display these errors, in all cases. > > On Fri, Apr 29, 2016 at 09:24:19AM -0400, Wayne Stambaugh wrote: > > Thanks for the update. I've been holding off on releasing 4.0.3 for > > this. I apologize for my absence over the last week or so. I've been > > really busy at work and got sick on top of that so my motivation to > > spend what little free time I had working on KiCad was low. > > > > Cheers, > > > > Wayne > > > > On 4/28/2016 2:38 PM, Chris Pavlina wrote: > > > Just a quick ping to reassure y'all I'm still working on this - been > > > caught > > > up in other things a bit the last couple weeks. I've got a nearly working > > > implementation here. > > > > > > On Tue, Apr 12, 2016 at 12:22:48PM -0400, Wayne Stambaugh wrote: > > >> I doubt this going to be a big issue. Since the new board file format > > >> was implemented over fours years ago there have been a handful of > > >> changes. I think we're going to be OK with just the date code. > > >> > > >> On 4/12/2016 12:06 PM, Chris Pavlina wrote: > > >>> Let's just not do more than one format change in a single day... I > > >>> think that > > >>> would be a beneficial decision for project stability as well... > > >>> > > >>> On Tue, Apr 12, 2016 at 05:26:27PM +0200, Timofonic wrote: > > >>>> Despite my very limited knowledge, I like the simple approach. > > >>>> > > >>>> What about using letters if more than one format change is done? > > >>>> > > >>>> 20160412A, 20160412B, 20160412C... > > >>>> > > >>>> On April 12, 2016 2:30:23 PM CEST, Chris Pavlina > > >>>> <[email protected]> wrote: > > >>>>> Honestly I don't see the advantage to using Semantic Versioning for an > > >>>>> internal file format version... and using 2016.04.12 instead of > > >>>>> 20160412 > > >>>>> just seems like an exercise in making the parser more complicated. > > >>>>> Could > > >>>>> you explain *why* this would be a good thing? > > >>>>> On Apr 12, 2016 1:51 AM, "David Cary" <[email protected]> wrote: > > >>>>> > > >>>>>> Please at least consider Semantic Versioning ( http://semver.org/ ). > > >>>>>> And I recommend that if you figure out any way to improve on SemVer, > > >>>>>> please speak up so maybe the next version of SemVer can incorporate > > >>>>>> those improvements. > > >>>>>> > > >>>>>> I have enjoyed the discussion of new features and various ideas for > > >>>>>> versioning, and I encourage you to discuss them further. > > >>>>>> > > >>>>>> I am happy that the native KiCad file formats already avoid many > > >>>>>> problems mentioned in > > >>>>>> "Designing File Formats" http://www.fadden.com/tech/file-formats.html > > >>>>>> . > > >>>>>> Are there any remaining recommendations in that essay that maybe we > > >>>>>> should include in future versions of KiCad file formats? > > >>>>>> > > >>>>>> If hypothetically we did use Semantic Versioning, > > >>>>>> would it be better to do (a) or (b)?: > > >>>>>> (a) have a single KiCad version number that KiCad writes into every > > >>>>>> new file it creates, or > > >>>>>> (b) have a separate and independent version number for each part of > > >>>>>> KiCad -- the Eeschema version number written into new schematic > > >>>>> files, > > >>>>>> a separate Pcbnew version number written into new footprint and PCB > > >>>>>> layout files, etc. > > >>>>>> > > >>>>>> (How many independent version numbers could option (b) require?) > > >>>>>> > > >>>>>> On Thu, Apr 7, 2016 at 1:04 PM, Chris Pavlina > > >>>>> <[email protected]> > > >>>>>> wrote: > > >>>>>>> What about using the date the change was made as a "version > > >>>>> number"? Can > > >>>>>>> integerize it like 20160407 for example. This allows easy > > >>>>>> cross-referencing of > > >>>>>>> a format version with the revision that it was made in, and is > > >>>>>> guaranteed to > > >>>>>>> increase monotonically if you use a YMD format :) > > >>>>>> > > >>>>>> I agree with Wayne that it's more meaningful than most version > > >>>>> strings. > > >>>>>> > > >>>>>> My understanding is that "integerized date" without punctuation is > > >>>>>> more commonly known as the "ISO 8601 date basic format". > > >>>>>> > > >>>>>> Recently I've been putting a date like that on the silkscreen of my > > >>>>>> PCBs. (I use the "ISO 8601 date extended format" like 2016-04-07, the > > >>>>>> format produced by the KiCad "%D" format symbol). > > >>>>>> > > >>>>>> Is it possible to combine that with Semantic versioning, getting > > >>>>>> something like 2016.04.07 ? > > >>>>>> (This assumes we won't make a breaking change in the file format more > > >>>>>> than once a year -- optimistic? :-) > > >>>>>> > > >>>>>> -- > > >>>>>> David Cary > > >>>>>> +1(918)813-2279 > > >>>>>> http://OpenCircuits.com/ > > >>>>>> http://david.carybros.com/ > > >>>>>> > > >>>>> > > >>>>> > > >>>>> ------------------------------------------------------------------------ > > >>>>> > > >>>>> _______________________________________________ > > >>>>> Mailing list: https://launchpad.net/~kicad-developers > > >>>>> Post to : [email protected] > > >>>>> Unsubscribe : https://launchpad.net/~kicad-developers > > >>>>> More help : https://help.launchpad.net/ListHelp > > >>>> > > >>>> -- > > >>>> Enviado desde mi dispositivo Android con K-9 Mail. Por favor disculpa > > >>>> mi brevedad. > > >>> > > >>> _______________________________________________ > > >>> Mailing list: https://launchpad.net/~kicad-developers > > >>> Post to : [email protected] > > >>> Unsubscribe : https://launchpad.net/~kicad-developers > > >>> More help : https://help.launchpad.net/ListHelp > > >>> > > >> > > >> _______________________________________________ > > >> Mailing list: https://launchpad.net/~kicad-developers > > >> Post to : [email protected] > > >> Unsubscribe : https://launchpad.net/~kicad-developers > > >> More help : https://help.launchpad.net/ListHelp > >
>From 4a1c297eb639fc65fe5616540293a8310947b3c1 Mon Sep 17 00:00:00 2001 From: Chris Pavlina <[email protected]> Date: Sun, 1 May 2016 18:50:21 -0400 Subject: [PATCH] Add format version checking for PCB and footprints 1. Add a (version %d) entry to footprints matching that used in PCB files. 2. When a user loads a file and the version entry is encountered, store the version for later comparison. 3. If a syntax error is encountered, check whether a version was encountered. If the file is more recent than KiCad, explain to the user that they might be able to open the file if they upgrade KiCad. Also, update a few copyright lines that were in the general area where I was working. Relevant bug: https://bugs.launchpad.net/kicad/+bug/1416736 Users will still not see the error message when loading an entire library, as the library loading/caching system suppresses them. --- common/richio.cpp | 3 +- include/richio.h | 33 ++++- pcbnew/eagle_plugin.cpp | 3 +- pcbnew/eagle_plugin.h | 2 +- pcbnew/files.cpp | 2 +- pcbnew/github/github_plugin.cpp | 2 +- pcbnew/github/github_plugin.h | 2 +- pcbnew/gpcb_plugin.cpp | 3 +- pcbnew/gpcb_plugin.h | 2 +- pcbnew/io_mgr.cpp | 5 +- pcbnew/io_mgr.h | 4 +- pcbnew/kicad_plugin.cpp | 41 +++++- pcbnew/kicad_plugin.h | 3 +- pcbnew/legacy_plugin.cpp | 2 +- pcbnew/legacy_plugin.h | 5 +- pcbnew/librairi.cpp | 300 +++++++++++++++++++++++----------------- pcbnew/pcb_parser.cpp | 145 ++++++++++++++++--- pcbnew/pcb_parser.h | 43 +++++- pcbnew/plugin.cpp | 2 +- 19 files changed, 428 insertions(+), 174 deletions(-) diff --git a/common/richio.cpp b/common/richio.cpp index 339684e..37c138c 100644 --- a/common/richio.cpp +++ b/common/richio.cpp @@ -1,9 +1,8 @@ - /* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2007-2011 SoftPLC Corporation, Dick Hollenbeck <[email protected]> - * Copyright (C) 2015 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2015 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/include/richio.h b/include/richio.h index 78e95d3..3ab6d69 100644 --- a/include/richio.h +++ b/include/richio.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2007-2010 SoftPLC Corporation, Dick Hollenbeck <[email protected]> - * Copyright (C) 2007 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -193,6 +193,9 @@ struct PARSE_ERROR : public IO_ERROR int aLineNumber, int aByteIndex ); ~PARSE_ERROR() throw ( /*none*/ ){} + +protected: + PARSE_ERROR(): IO_ERROR() {} }; @@ -200,6 +203,34 @@ struct PARSE_ERROR : public IO_ERROR throw PARSE_ERROR( __FILE__, __LOC__, aMsg, aSource, aInputLine, aLineNumber, aByteIndex ) +/** + * Struct FUTURE_FORMAT_ERROR + * variant of PARSE_ERROR indicating that a syntax or related error was likely caused + * by a file generated by a newer version of KiCad than this. Can be used to generate + * more informative error messages. + */ +struct FUTURE_FORMAT_ERROR : public PARSE_ERROR +{ + wxString requiredVersion; ///< version or date of KiCad required to open file + + FUTURE_FORMAT_ERROR( const PARSE_ERROR& aParseError, const wxString& aRequiredVersion ) : + PARSE_ERROR(), requiredVersion( aRequiredVersion ) + { + errorText.Printf( _( + "KiCad was unable to open this file, as it was created with a more " + "recent version than the one you are running. To open it, you'll need " + "to upgrade KiCad to a newer version.\n\n" + "Date of KiCad version required (or newer): %s\n\n" + "Full error text:\n%s" ), + requiredVersion, aParseError.errorText ); + + lineNumber = aParseError.lineNumber; + byteIndex = aParseError.byteIndex; + inputLine = aParseError.inputLine; + } +}; + + /** @} exception_types */ diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index 6297da4..27d0d6c 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -3,8 +3,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]> - * Copyright (C) 2012-2015 KiCad Developers, see change_log.txt for contributors. - + * Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/pcbnew/eagle_plugin.h b/pcbnew/eagle_plugin.h index e9bde95..078bc8b 100644 --- a/pcbnew/eagle_plugin.h +++ b/pcbnew/eagle_plugin.h @@ -5,7 +5,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]> - * Copyright (C) 2012-2015 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index 379a1a2..650e7bd 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2011-2015 Wayne Stambaugh <[email protected]> - * Copyright (C) 2015 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/pcbnew/github/github_plugin.cpp b/pcbnew/github/github_plugin.cpp index 75d4e7b..e43c2fb 100644 --- a/pcbnew/github/github_plugin.cpp +++ b/pcbnew/github/github_plugin.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <[email protected]> - * Copyright (C) 2016 KiCad Developers, see CHANGELOG.TXT for contributors. + * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/pcbnew/github/github_plugin.h b/pcbnew/github/github_plugin.h index 3dc10a6..92f2c13 100644 --- a/pcbnew/github/github_plugin.h +++ b/pcbnew/github/github_plugin.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <[email protected]> - * Copyright (C) 2013 KiCad Developers, see CHANGELOG.TXT for contributors. + * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/pcbnew/gpcb_plugin.cpp b/pcbnew/gpcb_plugin.cpp index 16432fb..94815f0 100644 --- a/pcbnew/gpcb_plugin.cpp +++ b/pcbnew/gpcb_plugin.cpp @@ -2,8 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 Wayne Stambaugh <[email protected]> - * Copyright (C) 1992-2015 KiCad Developers, see change_log.txt for contributors. - * + * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/pcbnew/gpcb_plugin.h b/pcbnew/gpcb_plugin.h index 4ae6556..8fb1618 100644 --- a/pcbnew/gpcb_plugin.h +++ b/pcbnew/gpcb_plugin.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 Wayne Stambaugh <[email protected]> - * Copyright (C) 1992-2012 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/pcbnew/io_mgr.cpp b/pcbnew/io_mgr.cpp index c733d30..8d3981b 100644 --- a/pcbnew/io_mgr.cpp +++ b/pcbnew/io_mgr.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2011-2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]> - * Copyright (C) 2011 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -98,6 +98,9 @@ PLUGIN* IO_MGR::PluginFind( PCB_FILE_T aFileType ) #else THROW_IO_ERROR( "BUILD_GITHUB_PLUGIN not enabled in cmake build environment" ); #endif + + case FILE_TYPE_NONE: + return NULL; } return NULL; diff --git a/pcbnew/io_mgr.h b/pcbnew/io_mgr.h index e2b0135..80b4821 100644 --- a/pcbnew/io_mgr.h +++ b/pcbnew/io_mgr.h @@ -5,7 +5,7 @@ * This program source code file is part of KICAD, a free EDA CAD application. * * Copyright (C) 2011-2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]> - * Copyright (C) 2011 Kicad Developers, see change_log.txt for contributors. + * Copyright (C) 2016 Kicad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -83,6 +83,8 @@ public: // ALTIUM, // etc. + + FILE_TYPE_NONE }; /** diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index 09abbcd..c495e00 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -2,8 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 CERN - * Copyright (C) 1992-2011 KiCad Developers, see change_log.txt for contributors. - * + * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -418,7 +417,8 @@ void PCB_IO::Save( const wxString& aFileName, BOARD* aBoard, const PROPERTIES* a } -BOARD_ITEM* PCB_IO::Parse( const wxString& aClipboardSourceInput ) throw( PARSE_ERROR, IO_ERROR ) +BOARD_ITEM* PCB_IO::Parse( const wxString& aClipboardSourceInput ) + throw( FUTURE_FORMAT_ERROR, PARSE_ERROR, IO_ERROR ) { std::string input = TO_UTF8( aClipboardSourceInput ); @@ -426,7 +426,21 @@ BOARD_ITEM* PCB_IO::Parse( const wxString& aClipboardSourceInput ) throw( PARSE_ m_parser->SetLineReader( &reader ); - return m_parser->Parse(); + try + { + return m_parser->Parse(); + } + catch( const FUTURE_FORMAT_ERROR& err ) + { + throw; + } + catch( const PARSE_ERROR& err ) + { + if( m_parser->IsTooRecent() ) + throw FUTURE_FORMAT_ERROR( err, m_parser->GetRequiredVersion() ); + else + throw; + } } @@ -1721,7 +1735,24 @@ BOARD* PCB_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPER m_parser->SetLineReader( &reader ); m_parser->SetBoard( aAppendToMe ); - BOARD* board = dyn_cast<BOARD*>( m_parser->Parse() ); + BOARD* board = NULL; + + try + { + board = dynamic_cast<BOARD*>( m_parser->Parse() ); + } + catch( const FUTURE_FORMAT_ERROR& err ) + { + throw; + } + catch( const PARSE_ERROR& err ) + { + if( m_parser->IsTooRecent() ) + throw FUTURE_FORMAT_ERROR( err, m_parser->GetRequiredVersion() ); + else + throw; + } + wxASSERT( board ); // Give the filename to the board if it's new diff --git a/pcbnew/kicad_plugin.h b/pcbnew/kicad_plugin.h index 1655293..5b8f415 100644 --- a/pcbnew/kicad_plugin.h +++ b/pcbnew/kicad_plugin.h @@ -2,6 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 CERN. + * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -153,7 +154,7 @@ public: void SetOutputFormatter( OUTPUTFORMATTER* aFormatter ) { m_out = aFormatter; } BOARD_ITEM* Parse( const wxString& aClipboardSourceInput ) - throw( PARSE_ERROR, IO_ERROR ); + throw( FUTURE_FORMAT_ERROR, PARSE_ERROR, IO_ERROR ); protected: diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index c621c71..012800c 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -4,7 +4,7 @@ * * Copyright (C) 2007-2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]> * Copyright (C) 2004 Jean-Pierre Charras, [email protected] - * Copyright (C) 1992-2015 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/pcbnew/legacy_plugin.h b/pcbnew/legacy_plugin.h index 2216438..c604705 100644 --- a/pcbnew/legacy_plugin.h +++ b/pcbnew/legacy_plugin.h @@ -5,7 +5,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]> - * Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -30,6 +30,9 @@ #include <string> #include <layers_id_colors_and_visibility.h> +// FOOTPRINT_LIBRARY_HEADER_CNT gives the number of characters to compare to detect +// a footprint library. A few variants may have been used, and so we can only be +// sure that the header contains "PCBNEW-LibModule-V", not "PCBNEW-LibModule-V1". #define FOOTPRINT_LIBRARY_HEADER "PCBNEW-LibModule-V1" #define FOOTPRINT_LIBRARY_HEADER_CNT 18 diff --git a/pcbnew/librairi.cpp b/pcbnew/librairi.cpp index 86210c8..f0f6aba 100644 --- a/pcbnew/librairi.cpp +++ b/pcbnew/librairi.cpp @@ -1,8 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 1992-2015 KiCad Developers, see change_log.txt for contributors. - * + * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -99,180 +98,223 @@ static const wxString ModImportFileWildcard( _( "GPcb foot print files (*)|*" ) #define EXPORT_IMPORT_LASTPATH_KEY wxT( "import_last_path" ) -MODULE* FOOTPRINT_EDIT_FRAME::Import_Module() +/** + * Prompt the user for a module file to open. + * @param aParent - parent window for the dialog + * @param aLastPath - last opened path + */ +static wxFileName prompt_for_module( wxWindow* aParent, const wxString& aLastPath ) { - // use the clipboard for this in the future? - - // Some day it might be useful save the last library type selected along with the path. static int lastFilterIndex = 0; - - wxString lastOpenedPathForLoading = m_mruPath; - wxConfigBase* config = Kiface().KifaceSettings(); - - if( config ) - config->Read( EXPORT_IMPORT_LASTPATH_KEY, &lastOpenedPathForLoading ); - wxString wildCard; + wxFileName fn; wildCard << wxGetTranslation( KiCadFootprintLibFileWildcard ) << wxChar( '|' ) << wxGetTranslation( ModLegacyExportFileWildcard ) << wxChar( '|' ) << wxGetTranslation( ModImportFileWildcard ) << wxChar( '|' ) << wxGetTranslation( GedaPcbFootprintLibFileWildcard ); - wxFileDialog dlg( this, FMT_IMPORT_MODULE, - lastOpenedPathForLoading, wxEmptyString, - wildCard, wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + wxFileDialog dlg( aParent, FMT_IMPORT_MODULE, aLastPath, wxEmptyString, wildCard, + wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + dlg.SetFilterIndex( lastFilterIndex ); - if( dlg.ShowModal() == wxID_CANCEL ) - return NULL; + if( dlg.ShowModal() != wxID_CANCEL ) + { + lastFilterIndex = dlg.GetFilterIndex(); + fn = wxFileName( dlg.GetPath() ); + } + + return fn; +} - lastFilterIndex = dlg.GetFilterIndex(); - FILE* fp = wxFopen( dlg.GetPath(), wxT( "rt" ) ); +/** + * Read a file to detect the type. + * @param aFile - open file to be read. File pointer will be closed. + * @param aFileName - file name to be read + * @param aName - wxString to receive the module name iff type is LEGACY + */ +static IO_MGR::PCB_FILE_T detect_file_type( FILE* aFile, const wxFileName& aFileName, wxString* aName ) +{ + FILE_LINE_READER freader( aFile, aFileName.GetFullPath() ); + WHITESPACE_FILTER_READER reader( freader ); + IO_MGR::PCB_FILE_T file_type; - if( !fp ) + wxASSERT( aName ); + + reader.ReadLine(); + char* line = reader.Line(); + + if( !strnicmp( line, "(module", strlen( "(module" ) ) ) { - wxString msg = wxString::Format( FMT_FILE_NOT_FOUND, GetChars( dlg.GetPath() ) ); - DisplayError( this, msg ); - return NULL; + file_type = IO_MGR::KICAD; + *aName = aFileName.GetName(); } - - if( config ) // Save file path + else if( !strnicmp( line, FOOTPRINT_LIBRARY_HEADER, FOOTPRINT_LIBRARY_HEADER_CNT ) ) { - lastOpenedPathForLoading = wxPathOnly( dlg.GetPath() ); - config->Write( EXPORT_IMPORT_LASTPATH_KEY, lastOpenedPathForLoading ); + file_type = IO_MGR::LEGACY; + while( reader.ReadLine() ) + { + if( !strnicmp( line, "$MODULE", strlen( "$MODULE" ) ) ) + { + *aName = FROM_UTF8( StrPurge( line + strlen( "$MODULE" ) ) ); + break; + } + } + } + else if( !strnicmp( line, "Element", strlen( "Element" ) ) ) + { + file_type = IO_MGR::GEDA_PCB; + *aName = aFileName.GetName(); + } + else + { + file_type = IO_MGR::FILE_TYPE_NONE; } - wxString moduleName; + return file_type; +} - bool isGeda = false; - bool isLegacy = false; +/** + * Parse a footprint using a PLUGIN. + * @param aFileName - file name to parse + * @param aFileType - type of the file + * @param aName - name of the footprint + */ +static MODULE* parse_module_with_plugin( + const wxFileName& aFileName, IO_MGR::PCB_FILE_T aFileType, const wxString& aName ) +{ + wxString path; + + switch( aFileType ) { - FILE_LINE_READER freader( fp, dlg.GetPath() ); // I own fp, and will close it. - WHITESPACE_FILTER_READER reader( freader ); // skip blank lines + case IO_MGR::GEDA_PCB: + path = aFileName.GetPath(); + break; + case IO_MGR::LEGACY: + path = aFileName.GetFullPath(); + break; + default: + wxFAIL_MSG( wxT( "unexpected IO_MGR::PCB_FILE_T" ) ); + } - reader.ReadLine(); - char* line = reader.Line(); + PLUGIN::RELEASER pi( IO_MGR::PluginFind( aFileType ) ); - if( !strnicmp( line, "(module", 7 ) ) - { - // isKicad = true; - } - else if( !strnicmp( line, FOOTPRINT_LIBRARY_HEADER, FOOTPRINT_LIBRARY_HEADER_CNT ) ) - { - isLegacy = true; + return pi->FootprintLoad( path, aName ); +} - while( reader.ReadLine() ) - { - if( !strnicmp( line, "$MODULE", 7 ) ) - { - moduleName = FROM_UTF8( StrPurge( line + sizeof( "$MODULE" ) -1 ) ); - break; - } - } - } - else if( !strnicmp( line, "Element", 7 ) ) - { - isGeda = true; - } - else - { - DisplayError( this, FMT_NOT_MODULE ); - return NULL; - } - // fp is closed here by ~FILE_LINE_READER() +/** + * Parse a KICAD footprint. + * @param aFileName - file name to parse + */ +static MODULE* parse_module_kicad( const wxFileName& aFileName ) +{ + wxFFile f( aFileName.GetFullPath() ); + MODULE* mod = NULL; + + if( f.IsOpened() ) + { + PCB_IO pcb_io; + wxString fcontents; + + f.ReadAll( &fcontents ); + mod = dynamic_cast<MODULE*>( pcb_io.Parse( fcontents ) ); } - MODULE* module; + return mod; +} - if( isGeda ) - { - try - { - wxFileName fn = dlg.GetPath(); - PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::GEDA_PCB ) ); - moduleName = fn.GetName(); - module = pi->FootprintLoad( fn.GetPath(), moduleName ); +/** + * Try to load a footprint, returning NULL if the file couldn't be accessed. + * @param aFileName - file name to load + * @param aFileType - type of the file to load + * @param aName - footprint name + */ +MODULE* try_load_footprint( const wxFileName& aFileName, IO_MGR::PCB_FILE_T aFileType, + const wxString& aName ) +{ + MODULE* module = NULL; - if( !module ) - { - wxString msg = wxString::Format( - FMT_MOD_NOT_FOUND, GetChars( moduleName ), GetChars( fn.GetPath() ) ); + switch( aFileType ) + { + case IO_MGR::GEDA_PCB: + case IO_MGR::LEGACY: + module = parse_module_with_plugin( aFileName, aFileType, aName ); + break; - DisplayError( this, msg ); - return NULL; - } - } - catch( const IO_ERROR& ioe ) - { - DisplayError( this, ioe.errorText ); - return NULL; - } + case IO_MGR::KICAD: + module = parse_module_kicad( aFileName ); + break; + + default: + wxFAIL_MSG( wxT( "unexpected IO_MGR::PCB_FILE_T" ) ); } - else if( isLegacy ) - { - try - { - PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) ); - module = pi->FootprintLoad( dlg.GetPath(), moduleName ); + return module; +} - if( !module ) - { - wxString msg = wxString::Format( - FMT_MOD_NOT_FOUND, GetChars( moduleName ), GetChars( dlg.GetPath() ) ); - DisplayError( this, msg ); - return NULL; - } - } - catch( const IO_ERROR& ioe ) - { - DisplayError( this, ioe.errorText ); - return NULL; - } - } - else // if( isKicad ) - { - try - { - // This technique was chosen to create an example of how reading - // the s-expression format from clipboard could be done. +MODULE* FOOTPRINT_EDIT_FRAME::Import_Module() +{ + wxString lastOpenedPathForLoading = m_mruPath; + wxConfigBase* config = Kiface().KifaceSettings(); + + if( config ) + config->Read( EXPORT_IMPORT_LASTPATH_KEY, &lastOpenedPathForLoading ); - wxString fcontents; - PCB_IO pcb_io; - wxFFile f( dlg.GetPath() ); + wxFileName fn = prompt_for_module( this, lastOpenedPathForLoading ); - if( !f.IsOpened() ) - { - wxString msg = wxString::Format( FMT_BAD_PATH, GetChars( dlg.GetPath() ) ); + if( !fn.IsOk() ) + return NULL; - DisplayError( this, msg ); - return NULL; - } + FILE* fp = wxFopen( fn.GetFullPath(), wxT( "rt" ) ); - f.ReadAll( &fcontents ); + if( !fp ) + { + wxString msg = wxString::Format( FMT_FILE_NOT_FOUND, GetChars( fn.GetFullPath() ) ); + DisplayError( this, msg ); + return NULL; + } - module = dyn_cast<MODULE*>( pcb_io.Parse( fcontents ) ); + if( config ) // Save file path + { + lastOpenedPathForLoading = fn.GetPath(); + config->Write( EXPORT_IMPORT_LASTPATH_KEY, lastOpenedPathForLoading ); + } - if( !module ) - { - wxString msg = wxString::Format( FMT_BAD_PATH, GetChars( dlg.GetPath() ) ); + wxString moduleName; + IO_MGR::PCB_FILE_T fileType = detect_file_type( fp, fn.GetFullPath(), &moduleName ); - DisplayError( this, msg ); - return NULL; - } - } - catch( const IO_ERROR& ioe ) + if( fileType == IO_MGR::FILE_TYPE_NONE ) + { + DisplayError( this, FMT_NOT_MODULE ); + return NULL; + } + + MODULE* module; + wxString errMessage; + + try + { + module = try_load_footprint( fn, fileType, moduleName ); + + if( !module ) { - DisplayError( this, ioe.errorText ); + wxString msg = wxString::Format( + FMT_MOD_NOT_FOUND, GetChars( moduleName ), GetChars( fn.GetFullPath() ) ); + DisplayError( this, msg ); return NULL; } } + catch( const IO_ERROR& ioe ) + { + DisplayError( this, ioe.errorText ); + return NULL; + } // Insert footprint in list GetBoard()->Add( module ); diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index a6a373f..965bd61 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -2,8 +2,8 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 CERN - * Copyright (C) 2012-2015 KiCad Developers, see change_log.txt for contributors. - * @author Wayne Stambaugh <[email protected]> + * Copyright (C) 2013 Wayne Stambaugh <[email protected]> + * Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -60,6 +60,8 @@ using namespace PCB_KEYS_T; void PCB_PARSER::init() { + m_tooRecent = false; + m_requiredVersion = 0; m_layerIndices.clear(); m_layerMasks.clear(); @@ -169,6 +171,43 @@ bool PCB_PARSER::parseBool() throw( PARSE_ERROR ) } +int PCB_PARSER::parseVersion() throw( IO_ERROR, PARSE_ERROR ) +{ + if( NextTok() != T_version ) + Expecting( GetTokenText( T_version ) ); + + int pcb_version = parseInt( FromUTF8() ); + + NeedRIGHT(); + + return pcb_version; +} + + +wxString PCB_PARSER::GetRequiredVersion() +{ + int year, month, day; + + year = m_requiredVersion / 10000; + month = ( m_requiredVersion / 100 ) - ( year * 100 ); + day = m_requiredVersion - ( year * 10000 ) - ( month * 100 ); + + // wx throws an assertion, not a catchable exception, when the date is invalid. + // User input shouldn't give wx asserts, so check manually and throw a proper + // error instead + if( day <= 0 || month <= 0 || month > 12 || + day > wxDateTime::GetNumberOfDays( (wxDateTime::Month)( month - 1 ), year ) ) + { + wxString err; + err.Printf( _( "cannot interpret date code %d" ), m_requiredVersion ); + THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); + } + + wxDateTime date( day, (wxDateTime::Month)( month - 1 ), year, 0, 0, 0, 0 ); + return date.FormatDate(); +} + + wxPoint PCB_PARSER::parseXY() throw( PARSE_ERROR, IO_ERROR ) { if( CurTok() != T_LEFT ) @@ -411,7 +450,27 @@ BOARD_ITEM* PCB_PARSER::Parse() throw( IO_ERROR, PARSE_ERROR ) } -BOARD* PCB_PARSER::parseBOARD() throw( IO_ERROR, PARSE_ERROR ) +BOARD* PCB_PARSER::parseBOARD() throw( IO_ERROR, PARSE_ERROR, FUTURE_FORMAT_ERROR ) +{ + try + { + return parseBOARD_unchecked(); + } + catch( const FUTURE_FORMAT_ERROR& err ) + { + throw; + } + catch( const PARSE_ERROR& err ) + { + if( m_tooRecent ) + throw FUTURE_FORMAT_ERROR( err, GetRequiredVersion() ); + else + throw; + } +} + + +BOARD* PCB_PARSER::parseBOARD_unchecked() throw( IO_ERROR, PARSE_ERROR ) { T token; @@ -506,24 +565,34 @@ void PCB_PARSER::parseHeader() throw( IO_ERROR, PARSE_ERROR ) wxCHECK_RET( CurTok() == T_kicad_pcb, wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) ); - T token; - NeedLEFT(); - token = NextTok(); - if( token != T_version ) - Expecting( GetTokenText( T_version ) ); + T tok = NextTok(); + if( tok == T_version ) + { + m_requiredVersion = parseInt( FromUTF8() ); + m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION ); + NeedRIGHT(); - // Get the file version. - m_board->SetFileFormatVersionAtLoad( parseInt( GetTokenText( T_version ) ) ); + // Skip the host name and host build version information. + NeedLEFT(); + NeedSYMBOL(); + NeedSYMBOL(); + NeedSYMBOL(); + NeedRIGHT(); + } + else + { + m_requiredVersion = SEXPR_BOARD_FILE_VERSION; + m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION ); - // Skip the host name and host build version information. - NeedRIGHT(); - NeedLEFT(); - NeedSYMBOL(); - NeedSYMBOL(); - NeedSYMBOL(); - NeedRIGHT(); + // Skip the host name and host build version information. + NeedSYMBOL(); + NeedSYMBOL(); + NeedRIGHT(); + } + + m_board->SetFileFormatVersionAtLoad( m_requiredVersion ); } @@ -1651,7 +1720,29 @@ DIMENSION* PCB_PARSER::parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ) } -MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments ) throw( IO_ERROR, PARSE_ERROR ) +MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments ) + throw( IO_ERROR, PARSE_ERROR, FUTURE_FORMAT_ERROR ) +{ + try + { + return parseMODULE_unchecked( aInitialComments ); + } + catch( const FUTURE_FORMAT_ERROR& err ) + { + throw; + } + catch( const PARSE_ERROR& err ) + { + if( m_tooRecent ) + throw FUTURE_FORMAT_ERROR( err, GetRequiredVersion() ); + else + throw; + } +} + + +MODULE* PCB_PARSER::parseMODULE_unchecked( wxArrayString* aInitialComments ) + throw( IO_ERROR, PARSE_ERROR ) { wxCHECK_MSG( CurTok() == T_module, NULL, wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as MODULE." ) ); @@ -1665,7 +1756,11 @@ MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments ) throw( IO_ERR module->SetInitialComments( aInitialComments ); - NeedSYMBOLorNUMBER(); + token = NextTok(); + + if( !IsSymbol( token ) && token != T_NUMBER ) + Expecting( "symbol|number" ); + name = FromUTF8(); if( !name.IsEmpty() && fpid.Parse( FromUTF8() ) >= 0 ) @@ -1683,6 +1778,18 @@ MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments ) throw( IO_ERR switch( token ) { + case T_version: + { + // Theoretically a module nested in a PCB could declare its own version, though + // as of writing this comment we don't do that. Just in case, take the greater + // version. + int this_version = parseInt( FromUTF8() ); + NeedRIGHT(); + m_requiredVersion = std::max( m_requiredVersion, this_version ); + m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION ); + break; + } + case T_locked: module->SetLocked( true ); break; diff --git a/pcbnew/pcb_parser.h b/pcbnew/pcb_parser.h index 9350b4e..cd815ad 100644 --- a/pcbnew/pcb_parser.h +++ b/pcbnew/pcb_parser.h @@ -2,6 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 CERN + * Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -68,6 +69,8 @@ class PCB_PARSER : public PCB_LEXER LAYER_ID_MAP m_layerIndices; ///< map layer name to it's index LSET_MAP m_layerMasks; ///< map layer names to their masks std::vector<int> m_netCodes; ///< net codes mapping for boards being loaded + bool m_tooRecent; ///< true if version parses as later than supported + int m_requiredVersion; ///< set to the KiCad format version this board requires ///> Converts net code using the mapping table if available, ///> otherwise returns unchanged net code if < 0 or if is is out of range @@ -113,12 +116,20 @@ class PCB_PARSER : public PCB_LEXER DIMENSION* parseDIMENSION() throw( IO_ERROR, PARSE_ERROR ); /** - * Function parseModule + * Function parseMODULE * @param aInitialComments may be a pointer to a heap allocated initial comment block * or NULL. If not NULL, then caller has given ownership of a wxArrayString to * this function and care must be taken to delete it even on exception. */ - MODULE* parseMODULE( wxArrayString* aInitialComments = 0 ) throw( IO_ERROR, PARSE_ERROR ); + MODULE* parseMODULE( wxArrayString* aInitialComments = 0 ) + throw( IO_ERROR, PARSE_ERROR, FUTURE_FORMAT_ERROR ); + + /** + * Function parseMODULE_unchecked + * Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR automatically. + */ + MODULE* parseMODULE_unchecked( wxArrayString* aInitialComments = 0 ) + throw( IO_ERROR, PARSE_ERROR ); TEXTE_MODULE* parseTEXTE_MODULE() throw( IO_ERROR, PARSE_ERROR ); EDGE_MODULE* parseEDGE_MODULE() throw( IO_ERROR, PARSE_ERROR ); D_PAD* parseD_PAD( MODULE* aParent = NULL ) throw( IO_ERROR, PARSE_ERROR ); @@ -126,7 +137,13 @@ class PCB_PARSER : public PCB_LEXER VIA* parseVIA() throw( IO_ERROR, PARSE_ERROR ); ZONE_CONTAINER* parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ); PCB_TARGET* parsePCB_TARGET() throw( IO_ERROR, PARSE_ERROR ); - BOARD* parseBOARD() throw( IO_ERROR, PARSE_ERROR ); + BOARD* parseBOARD() throw( IO_ERROR, PARSE_ERROR, FUTURE_FORMAT_ERROR ); + + /** + * Function parseBOARD_unchecked + * Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR automatically. + */ + BOARD* parseBOARD_unchecked() throw( IO_ERROR, PARSE_ERROR ); /** @@ -252,6 +269,11 @@ class PCB_PARSER : public PCB_LEXER bool parseBool() throw( PARSE_ERROR ); + /** + * Parse a format version tag like (version 20160417) return the version. + * Expects to start on 'version', and eats the closing paren. + */ + int parseVersion() throw( IO_ERROR, PARSE_ERROR ); public: @@ -284,6 +306,21 @@ public: } BOARD_ITEM* Parse() throw( IO_ERROR, PARSE_ERROR ); + + /** + * Return whether a version number, if any was parsed, was too recent + */ + bool IsTooRecent() + { + return m_tooRecent; + } + + /** + * Return a string representing the version of kicad required to open this + * file. Not particularly meaningful if IsTooRecent() returns false. + */ + wxString GetRequiredVersion(); + }; diff --git a/pcbnew/plugin.cpp b/pcbnew/plugin.cpp index 22e060b..9b5f5ab 100644 --- a/pcbnew/plugin.cpp +++ b/pcbnew/plugin.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2011-2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]> - * Copyright (C) 2011 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License -- 2.7.4
_______________________________________________ Mailing list: https://launchpad.net/~kicad-developers Post to : [email protected] Unsubscribe : https://launchpad.net/~kicad-developers More help : https://help.launchpad.net/ListHelp

