More flexible (and correct) version of CopySexprFile(),

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21738

(cherry picked from commit 666e7f5bc5)
This commit is contained in:
Jeff Young
2026-01-02 12:04:11 +00:00
parent 08fd4630e9
commit aa65b4266c
4 changed files with 80 additions and 43 deletions
+12 -22
View File
@@ -317,9 +317,8 @@ static void traverseSEXPR( SEXPR::SEXPR* aNode, const std::function<void( SEXPR:
void CopySexprFile( const wxString& aSrcPath, const wxString& aDestPath,
const std::map<std::string, wxString>& aPathTokenToExtensionMap,
const wxString& aSrcProjectBasePath, const wxString& aSrcProjectName,
const wxString& aNewProjectBasePath, const wxString& aNewProjectName, wxString& aErrors )
std::function<bool( const std::string& token, wxString& value )> 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<SEXPR::SEXPR_STRING*>( node->GetChild( 1 ) );
SEXPR::SEXPR_SYMBOL* symNode = dynamic_cast<SEXPR::SEXPR_SYMBOL*>( 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<SEXPR::SEXPR_STRING*>( node->GetChild( 1 ) );
SEXPR::SEXPR_SYMBOL* symNode = dynamic_cast<SEXPR::SEXPR_SYMBOL*>( 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 )
+38 -9
View File
@@ -563,11 +563,18 @@ void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aProje
return;
}
std::map<std::string, wxString> 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<std::string, wxString> 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 )
{
+3 -6
View File
@@ -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<std::string, wxString>& aPathTokenToExtensionMap,
const wxString& aSrcProjectBasePath, const wxString& aSrcProjectName,
const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
std::function<bool( const std::string& token, wxString& value )> aCallback,
wxString& aErrors );
/**
+27 -6
View File
@@ -520,13 +520,34 @@ void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aSrcPr
if( destFile.GetName() == aSrcProjectName )
destFile.SetName( aNewProjectName );
std::map<std::string, wxString> 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 )
{