You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
5.9 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2017 Wayne Stambaugh <stambaughw@verizon.net>
  5. * Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
  6. * Copyright (C) 2017 CERN
  7. * @author Maciej Suminski <maciej.suminski@cern.ch>
  8. *
  9. * This program is free software: you can redistribute it and/or modify it
  10. * under the terms of the GNU General Public License as published by the
  11. * Free Software Foundation, either version 3 of the License, or (at your
  12. * option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License along
  20. * with this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. #include <env_paths.h>
  23. static bool normalizeAbsolutePaths( const wxFileName& aPathA,
  24. const wxFileName& aPathB,
  25. wxString* aResultPath )
  26. {
  27. wxCHECK_MSG( aPathA.IsAbsolute(), false, aPathA.GetPath() + " is not an absolute path." );
  28. wxCHECK_MSG( aPathB.IsAbsolute(), false, aPathB.GetPath() + " is not an absolute path." );
  29. if( aPathA.GetPath() == aPathB.GetPath() )
  30. return true;
  31. if( ( aPathA.GetDirCount() > aPathB.GetDirCount() )
  32. || ( aPathA.HasVolume() && !aPathB.HasVolume() )
  33. || ( !aPathA.HasVolume() && aPathB.HasVolume() )
  34. || ( ( aPathA.HasVolume() && aPathB.HasVolume() )
  35. && ( aPathA.GetVolume() != aPathB.GetVolume() ) ) )
  36. return false;
  37. wxArrayString aDirs = aPathA.GetDirs();
  38. wxArrayString bDirs = aPathB.GetDirs();
  39. size_t i = 0;
  40. while( i < aDirs.GetCount() )
  41. {
  42. if( aDirs[i] != bDirs[i] )
  43. return false;
  44. i++;
  45. }
  46. if( aResultPath )
  47. {
  48. while( i < bDirs.GetCount() )
  49. {
  50. *aResultPath += bDirs[i] + wxT( "/" );
  51. i++;
  52. }
  53. }
  54. return true;
  55. }
  56. wxString NormalizePath( const wxFileName& aFilePath, const ENV_VAR_MAP* aEnvVars,
  57. const wxString& aProjectPath )
  58. {
  59. wxFileName envPath;
  60. wxString varName;
  61. wxString remainingPath;
  62. wxString normalizedFullPath;
  63. int pathDepth = 0;
  64. if( aEnvVars )
  65. {
  66. for( auto& entry : *aEnvVars )
  67. {
  68. // Don't bother normalizing paths that don't exist or the user cannot read.
  69. if( !wxFileName::DirExists( entry.second.GetValue() )
  70. || !wxFileName::IsDirReadable( entry.second.GetValue() ) )
  71. continue;
  72. envPath.SetPath( entry.second.GetValue() );
  73. wxString tmp;
  74. if( normalizeAbsolutePaths( envPath, aFilePath, &tmp ) )
  75. {
  76. int newDepth = envPath.GetDirs().GetCount();
  77. // Only use the variable if it removes more directories than the previous ones
  78. if( newDepth > pathDepth )
  79. {
  80. pathDepth = newDepth;
  81. varName = entry.first;
  82. remainingPath = tmp;
  83. }
  84. }
  85. }
  86. }
  87. if( varName.IsEmpty() && !aProjectPath.IsEmpty()
  88. && wxFileName( aProjectPath ).IsAbsolute() && wxFileName( aFilePath ).IsAbsolute() )
  89. {
  90. envPath.SetPath( aProjectPath );
  91. if( normalizeAbsolutePaths( envPath, aFilePath, &remainingPath ) )
  92. varName = PROJECT_VAR_NAME;
  93. }
  94. if( !varName.IsEmpty() )
  95. {
  96. normalizedFullPath = wxString::Format( "${%s}/", varName );
  97. if( !remainingPath.IsEmpty() )
  98. normalizedFullPath += remainingPath;
  99. normalizedFullPath += aFilePath.GetFullName();
  100. }
  101. return normalizedFullPath;
  102. }
  103. wxString NormalizePath( const wxFileName& aFilePath, const ENV_VAR_MAP* aEnvVars,
  104. const PROJECT* aProject )
  105. {
  106. if( aProject )
  107. return NormalizePath( aFilePath, aEnvVars, aProject->GetProjectPath() );
  108. else
  109. return NormalizePath( aFilePath, aEnvVars, "" );
  110. }
  111. // Create file path by appending path and file name. This approach allows the filename
  112. // to contain a relative path, whereas wxFileName::SetPath() would replace the
  113. // relative path
  114. static wxString createFilePath( const wxString& aPath, const wxString& aFileName )
  115. {
  116. wxString path( aPath );
  117. if( !path.EndsWith( wxFileName::GetPathSeparator() ) )
  118. path.Append( wxFileName::GetPathSeparator() );
  119. return path + aFileName;
  120. }
  121. wxString ResolveFile( const wxString& aFileName, const ENV_VAR_MAP* aEnvVars,
  122. const PROJECT* aProject )
  123. {
  124. wxFileName full( aFileName );
  125. if( full.IsAbsolute() )
  126. return full.GetFullPath();
  127. if( aProject )
  128. {
  129. wxFileName fn( createFilePath( aProject->GetProjectPath(), aFileName ) );
  130. if( fn.Exists() )
  131. return fn.GetFullPath();
  132. }
  133. if( aEnvVars )
  134. {
  135. for( auto& entry : *aEnvVars )
  136. {
  137. wxFileName fn( createFilePath( entry.second.GetValue(), aFileName ) );
  138. if( fn.Exists() )
  139. return fn.GetFullPath();
  140. }
  141. }
  142. return wxEmptyString;
  143. }
  144. bool PathIsInsideProject( const wxString& aFileName, const PROJECT* aProject, wxFileName* aSubPath )
  145. {
  146. wxFileName fn( aFileName );
  147. wxFileName prj( aProject->GetProjectPath() );
  148. wxArrayString pdirs = prj.GetDirs();
  149. wxArrayString fdirs = fn.GetDirs();
  150. if( fdirs.size() < pdirs.size() )
  151. return false;
  152. for( size_t i = 0; i < pdirs.size(); i++ )
  153. {
  154. if( fdirs[i] != pdirs[i] )
  155. return false;
  156. }
  157. // Now we know that fn is inside prj
  158. if( aSubPath )
  159. {
  160. aSubPath->Clear();
  161. for( size_t i = pdirs.size(); i < fdirs.size(); i++ )
  162. aSubPath->AppendDir( fdirs[i] );
  163. }
  164. return true;
  165. }