|
|
/*
* This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2017 Wayne Stambaugh <stambaughw@gmail.com> * Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2017 CERN * @author Maciej Suminski <maciej.suminski@cern.ch> * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <env_paths.h>
#include <project.h>
#include <wx/filename.h>
static bool normalizeAbsolutePaths( const wxFileName& aPathA, const wxFileName& aPathB, wxString* aResultPath ){ wxCHECK_MSG( aPathA.IsAbsolute(), false, aPathA.GetPath() + wxS( " is not an absolute path." ) ); wxCHECK_MSG( aPathB.IsAbsolute(), false, aPathB.GetPath() + wxS( " is not an absolute path." ) );
if( aPathA.GetPath() == aPathB.GetPath() ) return true;
// Not sure all of volume checks are necessary since wxFileName::GetVolume() returns
// an empty string if the path has no volume.
if( ( aPathA.GetDirCount() > aPathB.GetDirCount() ) || ( aPathA.HasVolume() && !aPathB.HasVolume() ) || ( !aPathA.HasVolume() && aPathB.HasVolume() ) || ( ( aPathA.HasVolume() && aPathB.HasVolume() ) && ( aPathA.GetVolume().CmpNoCase( aPathB.GetVolume() ) != 0 ) ) ) return false;
wxArrayString aDirs = aPathA.GetDirs(); wxArrayString bDirs = aPathB.GetDirs();
size_t i = 0;
while( i < aDirs.GetCount() ) { if( aDirs[i] != bDirs[i] ) return false;
i++; }
if( aResultPath ) { while( i < bDirs.GetCount() ) { *aResultPath += bDirs[i] + wxT( "/" ); i++; } }
return true;}
wxString NormalizePath( const wxFileName& aFilePath, const ENV_VAR_MAP* aEnvVars, const wxString& aProjectPath ){ wxFileName envPath; wxString varName; wxString remainingPath; wxString normalizedFullPath; int pathDepth = 0;
if( aEnvVars ) { for( const std::pair<const wxString, ENV_VAR_ITEM>& entry : *aEnvVars ) { // Don't bother normalizing paths that don't exist or the user cannot read.
if( !wxFileName::DirExists( entry.second.GetValue() ) || !wxFileName::IsDirReadable( entry.second.GetValue() ) ) { continue; }
envPath.SetPath( entry.second.GetValue() );
wxString tmp;
if( normalizeAbsolutePaths( envPath, aFilePath, &tmp ) ) { int newDepth = envPath.GetDirs().GetCount();
// Only use the variable if it removes more directories than the previous ones
if( newDepth > pathDepth ) { pathDepth = newDepth; varName = entry.first; remainingPath = tmp; }
// @fixme Shouldn't we break here if an environment variable path is found or try
// at least try to pick the best match?
} } }
if( varName.IsEmpty() && !aProjectPath.IsEmpty() && wxFileName( aProjectPath ).IsAbsolute() && wxFileName( aFilePath ).IsAbsolute() ) { envPath.SetPath( aProjectPath );
if( normalizeAbsolutePaths( envPath, aFilePath, &remainingPath ) ) varName = PROJECT_VAR_NAME; }
if( varName.IsEmpty() ) { normalizedFullPath = aFilePath.GetFullPath(); } else { normalizedFullPath = wxString::Format( "${%s}/", varName );
if( !remainingPath.IsEmpty() ) normalizedFullPath += remainingPath;
normalizedFullPath += aFilePath.GetFullName(); }
return normalizedFullPath;}
wxString NormalizePath( const wxFileName& aFilePath, const ENV_VAR_MAP* aEnvVars, const PROJECT* aProject ){ if( aProject ) return NormalizePath( aFilePath, aEnvVars, aProject->GetProjectPath() ); else return NormalizePath( aFilePath, aEnvVars, "" );}
// Create file path by appending path and file name. This approach allows the filename
// to contain a relative path, whereas wxFileName::SetPath() would replace the
// relative path
static wxString createFilePath( const wxString& aPath, const wxString& aFileName ){ wxString path( aPath );
if( !path.EndsWith( wxFileName::GetPathSeparator() ) ) path.Append( wxFileName::GetPathSeparator() );
return path + aFileName;}
wxString ResolveFile( const wxString& aFileName, const ENV_VAR_MAP* aEnvVars, const PROJECT* aProject ){ wxFileName full( aFileName );
if( full.IsAbsolute() ) return full.GetFullPath();
if( aProject ) { wxFileName fn( createFilePath( aProject->GetProjectPath(), aFileName ) );
if( fn.Exists() ) return fn.GetFullPath(); }
if( aEnvVars ) { for( const std::pair<const wxString, ENV_VAR_ITEM>& entry : *aEnvVars ) { wxFileName fn( createFilePath( entry.second.GetValue(), aFileName ) );
if( fn.Exists() ) return fn.GetFullPath(); } }
return wxEmptyString;}
bool PathIsInsideProject( const wxString& aFileName, const PROJECT* aProject, wxFileName* aSubPath ){ wxFileName fn( aFileName ); wxFileName prj( aProject->GetProjectPath() );
wxArrayString pdirs = prj.GetDirs(); wxArrayString fdirs = fn.GetDirs();
if( fdirs.size() < pdirs.size() ) return false;
for( size_t i = 0; i < pdirs.size(); i++ ) { if( fdirs[i] != pdirs[i] ) return false; }
// Now we know that fn is inside prj
if( aSubPath ) { aSubPath->Clear();
for( size_t i = pdirs.size(); i < fdirs.size(); i++ ) aSubPath->AppendDir( fdirs[i] ); }
return true;}
|