From aa65b4266c0568bc02f6865acd557407e70ea970 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Thu, 4 Dec 2025 14:21:39 +0000 Subject: [PATCH] More flexible (and correct) version of CopySexprFile(), Fixes https://gitlab.com/kicad/code/kicad/-/issues/21738 (cherry picked from commit 666e7f5bc524e9f61a7ad61fad4167200360f348) --- common/gestfich.cpp | 34 +++++++++++-------------------- eeschema/eeschema.cpp | 47 ++++++++++++++++++++++++++++++++++--------- include/gestfich.h | 9 +++------ pcbnew/pcbnew.cpp | 33 ++++++++++++++++++++++++------ 4 files changed, 80 insertions(+), 43 deletions(-) diff --git a/common/gestfich.cpp b/common/gestfich.cpp index 44a559e6c5..572d4f5628 100644 --- a/common/gestfich.cpp +++ b/common/gestfich.cpp @@ -317,9 +317,8 @@ static void traverseSEXPR( SEXPR::SEXPR* aNode, const std::function& aPathTokenToExtensionMap, - const wxString& aSrcProjectBasePath, const wxString& aSrcProjectName, - const wxString& aNewProjectBasePath, const wxString& aNewProjectName, wxString& aErrors ) + std::function aCallback, + wxString& aErrors ) { bool success = false; @@ -333,27 +332,18 @@ void CopySexprFile( const wxString& aSrcPath, const wxString& aDestPath, { if( node->IsList() && node->GetNumberOfChildren() > 1 && node->GetChild( 0 )->IsSymbol() ) { - std::string token = node->GetChild( 0 )->GetSymbol(); + std::string token = node->GetChild( 0 )->GetSymbol(); + SEXPR::SEXPR_STRING* pathNode = dynamic_cast( node->GetChild( 1 ) ); + SEXPR::SEXPR_SYMBOL* symNode = dynamic_cast( node->GetChild( 1 ) ); + wxString path; - if( aPathTokenToExtensionMap.contains( token ) ) + if( pathNode ) + path = pathNode->m_value; + else if( symNode ) + path = symNode->m_value; + + if( aCallback( token, path ) ) { - const wxString& extension = aPathTokenToExtensionMap.at( token ); - SEXPR::SEXPR_STRING* pathNode = dynamic_cast( node->GetChild( 1 ) ); - SEXPR::SEXPR_SYMBOL* symNode = dynamic_cast( node->GetChild( 1 ) ); - wxString path; - - if( pathNode ) - path = pathNode->m_value; - else if( symNode ) - path = symNode->m_value; - - if( path == aSrcProjectName + extension ) - path = aNewProjectName + extension; - else if( path == aSrcProjectBasePath + "/" + aSrcProjectName + extension ) - path = aNewProjectBasePath + "/" + aNewProjectName + extension; - else if( path.StartsWith( aSrcProjectBasePath ) ) - path.Replace( aSrcProjectBasePath, aNewProjectBasePath, false ); - if( pathNode ) pathNode->m_value = path; else if( symNode ) diff --git a/eeschema/eeschema.cpp b/eeschema/eeschema.cpp index 0a2bd56ea3..d8ce89d952 100644 --- a/eeschema/eeschema.cpp +++ b/eeschema/eeschema.cpp @@ -563,11 +563,18 @@ void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aProje return; } - std::map aPathTokenToExtensionMap; - aPathTokenToExtensionMap["project"] = wxEmptyString; + CopySexprFile( aSrcFilePath, destFile.GetFullPath(), + [&]( const std::string& token, wxString& value ) -> bool + { + if( token == "project" && value == aProjectName ) + { + value = aNewProjectName; + return true; + } - CopySexprFile( aSrcFilePath, destFile.GetFullPath(), aPathTokenToExtensionMap, - aProjectBasePath, aProjectName, aNewProjectBasePath, aNewProjectName, aErrors ); + return false; + }, + aErrors ); } else if( ext == FILEEXT::SchematicSymbolFileExtension ) { @@ -591,12 +598,34 @@ void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aProje if( destFile.GetName() == aProjectName ) destFile.SetName( aNewProjectName ); - std::map aPathTokenToExtensionMap; - aPathTokenToExtensionMap["source"] = wxS( ".sch" ); - aPathTokenToExtensionMap["source"] = wxS( ".kicad_sch" ); + CopySexprFile( aSrcFilePath, destFile.GetFullPath(), + [&]( const std::string& token, wxString& value ) -> bool + { + if( token == "source" ) + { + for( const wxString& extension : { wxT( ".sch" ), wxT( ".kicad_sch" ) } ) + { + if( value == aProjectName + extension ) + { + value = aNewProjectName + extension; + return true; + } + else if( value == aProjectBasePath + "/" + aProjectName + extension ) + { + value = aNewProjectBasePath + "/" + aNewProjectName + extension; + return true; + } + else if( value.StartsWith( aProjectBasePath ) ) + { + value.Replace( aProjectBasePath, aNewProjectBasePath, false ); + return true; + } + } + } - CopySexprFile( aSrcFilePath, destFile.GetFullPath(), aPathTokenToExtensionMap, - aProjectBasePath, aProjectName, aNewProjectBasePath, aNewProjectName, aErrors ); + return false; + }, + aErrors ); } else if( destFile.GetName() == FILEEXT::SymbolLibraryTableFileName ) { diff --git a/include/gestfich.h b/include/gestfich.h index 7842c7a205..a1c77bc131 100644 --- a/include/gestfich.h +++ b/include/gestfich.h @@ -61,15 +61,12 @@ KICOMMON_API void KiCopyFile( const wxString& aSrcPath, const wxString& aDestPat /** * @param aSrcPath is the full filename of the source. * @param[in] aDestPath is the full filename of the target. - * @param[in] aPathTokenToExtensionMap a set of sexpr tokens which might be followed by a path to aSrcPath - * which needs to be updated to aDestPath. The value of the map is the - * extension any said path should have. + * @param[in] aCallback a facility to allow modification of the values of particular tokens. Normally used + * to update paths in the copied document. * @param[out] aErrors a wxString to *append* any errors to. */ KICOMMON_API void CopySexprFile( const wxString& aSrcPath, const wxString& aDestPath, - const std::map& aPathTokenToExtensionMap, - const wxString& aSrcProjectBasePath, const wxString& aSrcProjectName, - const wxString& aNewProjectBasePath, const wxString& aNewProjectName, + std::function aCallback, wxString& aErrors ); /** diff --git a/pcbnew/pcbnew.cpp b/pcbnew/pcbnew.cpp index 9c6c05ea31..93dded0254 100644 --- a/pcbnew/pcbnew.cpp +++ b/pcbnew/pcbnew.cpp @@ -520,13 +520,34 @@ void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aSrcPr if( destFile.GetName() == aSrcProjectName ) destFile.SetName( aNewProjectName ); - std::map aPathTokenToExtensionMap; - aPathTokenToExtensionMap["sheetfile"] = wxS( ".sch" ); - aPathTokenToExtensionMap["sheetfile"] = wxS( ".kicad_sch" ); + CopySexprFile( aSrcFilePath, destFile.GetFullPath(), + [&]( const std::string& token, wxString& value ) + { + if( token == "sheetfile" ) + { + for( const wxString& extension : { wxT( ".sch" ), wxT( ".kicad_sch" ) } ) + { + if( value == aSrcProjectName + extension ) + { + value = aNewProjectName + extension; + return true; + } + else if( value == aProjectBasePath + "/" + aSrcProjectName + extension ) + { + value = aNewProjectBasePath + "/" + aNewProjectName + extension; + return true; + } + else if( value.StartsWith( aProjectBasePath ) ) + { + value.Replace( aProjectBasePath, aNewProjectBasePath, false ); + return true; + } + } + } - CopySexprFile( aSrcFilePath, destFile.GetFullPath(), aPathTokenToExtensionMap, - aProjectBasePath, aSrcProjectName, - aNewProjectBasePath, aNewProjectName, aErrors ); + return false; + }, + aErrors ); } else if( ext == FILEEXT::LegacyPcbFileExtension ) {