42#define CFGFILE_VERSION 1
45#define ERRFLG_ALIAS (1)
46#define ERRFLG_RELPATH (2)
47#define ERRFLG_ENVPATH (4)
49#define MASK_3D_RESOLVER "3D_RESOLVER"
64 if( aConfigDir.empty() )
71 if( !cfgdir.DirExists() )
92 if( !projdir.DirExists() )
103 al.
m_Alias = wxS(
"${KIPRJMOD}" );
128 std::ostringstream ostr;
129 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
130 ostr <<
" * [INFO] changed project dir to ";
131 ostr <<
m_paths.front().m_Pathexp.ToUTF8();
169 lpath.
m_Alias = wxS(
"${KIPRJMOD}" );
174 wxUniChar psep = fndummy.GetPathSeparator();
175 std::list< wxString > epaths;
179 for(
const wxString& currPath : epaths )
181 wxString currPathVarFormat = currPath;
182 currPathVarFormat.Prepend( wxS(
"${" ) );
183 currPathVarFormat.Append( wxS(
"}" ) );
187 if( pathVal.empty() )
193 fndummy.Assign( pathVal,
"" );
208 lpath.
m_Alias = currPathVarFormat;
218 std::list< SEARCH_PATH >::const_iterator sPL =
m_paths.begin();
222 wxLogTrace(
MASK_3D_RESOLVER, wxS(
" + %s : '%s'\n" ), (*sPL).m_Alias.GetData(),
223 (*sPL).m_Pathexp.GetData() );
234 wxUniChar envMarker(
'$' );
236 while( !
m_paths.empty() && envMarker != *
m_paths.back().m_Alias.rbegin() )
247 std::vector<const EMBEDDED_FILES*> aEmbeddedFilesStack )
251 if( aFileName.empty() )
252 return wxEmptyString;
258 wxString tname = aFileName;
262 tname.Replace(
"\\",
"/" );
274 if( aEmbeddedFilesStack.empty() )
276 wxLogTrace( wxT(
"KICAD_EMBED" ),
277 wxT(
"No EMBEDDED_FILES object provided for kicad_embed URI" ) );
278 return wxEmptyString;
283 wxFileName temp_file = aEmbeddedFilesStack[0]->GetTemporaryFileName(
path );
286 while( !temp_file.IsOk() && ii < (
int) aEmbeddedFilesStack.size() )
287 temp_file = aEmbeddedFilesStack[ii++]->GetTemporaryFileName(
path );
289 if( !temp_file.IsOk() )
291 wxLogTrace( wxT(
"KICAD_EMBED" ),
292 wxT(
"Failed to get temp file '%s' for kicad_embed URI" ),
path );
293 return wxEmptyString;
296 wxLogTrace( wxT(
"KICAD_EMBED" ), wxT(
"Opening embedded file '%s' as '%s'" ),
297 tname, temp_file.GetFullPath() );
299 return temp_file.GetFullPath();
302 wxFileName tmpFN( tname );
306 if( tmpFN.FileExists() )
309 tname = tmpFN.GetFullPath();
313 if( aFileName.StartsWith( wxS(
"${" ) ) || aFileName.StartsWith( wxS(
"$(" ) ) )
322 if( aFileName.StartsWith(
"${" ) || aFileName.StartsWith(
"$(" ) )
326 if( tname == aFileName )
328 bool useBrace = aFileName.StartsWith(
"${" );
329 size_t aliasEnd = aFileName.find( useBrace ?
'}' :
')' );
331 if( aliasEnd != wxString::npos )
333 wxString alias = aFileName.substr( 2, aliasEnd - 2 );
334 wxString relpath = aFileName.substr( aliasEnd + 2 );
338 if(
path.m_Alias.StartsWith( wxS(
"${" ) ) ||
path.m_Alias.StartsWith( wxS(
"$(" ) ) )
341 if(
path.m_Alias == alias && !
path.m_Pathexp.empty() )
343 wxFileName fpath( wxFileName::DirName(
path.m_Pathexp ) );
344 wxString fullPath = fpath.GetPathWithSep() + relpath;
348 if( wxFileName::FileExists( fullPath ) )
350 wxFileName tmp( fullPath );
353 fullPath = tmp.GetFullPath();
365 wxString errmsg =
"[3D File Resolver] No such path; ensure the environment var is "
367 errmsg.append(
"\n" );
368 errmsg.append( tname );
369 errmsg.append(
"\n" );
373 return wxEmptyString;
385 if( !
m_paths.begin()->m_Pathexp.empty() && !tname.StartsWith(
":" ) )
387 tmpFN.Assign(
m_paths.begin()->m_Pathexp,
"" );
388 wxString fullPath = tmpFN.GetPathWithSep() + tname;
392 if( wxFileName::FileExists( fullPath ) )
394 tmpFN.Assign( fullPath );
396 tname = tmpFN.GetFullPath();
403 if( !aWorkingPath.IsEmpty() && !tname.StartsWith(
":" ) )
405 wxString tmp = aWorkingPath;
406 tmp.Append( tmpFN.GetPathSeparator() );
410 if( tmpFN.MakeAbsolute() && tmpFN.FileExists() )
412 tname = tmpFN.GetFullPath();
418 if( !tname.StartsWith( wxS(
":" ) ) )
421 wxString fullPath( wxString::Format( wxS(
"${%s}" ),
423 fullPath.Append( fpath.GetPathSeparator() );
424 fullPath.Append( tname );
426 fpath.Assign( fullPath );
430 tname = fpath.GetFullPath();
447 wxString errmsg =
"[3D File Resolver] No such path";
448 errmsg.append( wxS(
"\n" ) );
449 errmsg.append( tname );
450 errmsg.append( wxS(
"\n" ) );
454 return wxEmptyString;
460 if(
path.m_Alias.StartsWith( wxS(
"${" ) ) ||
path.m_Alias.StartsWith( wxS(
"$(" ) ) )
463 if(
path.m_Alias == alias && !
path.m_Pathexp.empty() )
465 wxFileName fpath( wxFileName::DirName(
path.m_Pathexp ) );
466 wxString fullPath = fpath.GetPathWithSep() + relpath;
470 if( wxFileName::FileExists( fullPath ) )
474 wxFileName tmp( fullPath );
477 tname = tmp.GetFullPath();
487 wxString errmsg =
"[3D File Resolver] No such path; ensure the path alias is defined";
488 errmsg.append(
"\n" );
489 errmsg.append( tname.substr( 1 ) );
490 errmsg.append(
"\n" );
494 return wxEmptyString;
508 while( tpath.
m_Pathvar.EndsWith( wxT(
"\\" ) ) )
519 if( !
path.DirExists() )
521 wxString versionedPath = wxString::Format( wxS(
"${%s}" ),
526 || aPath.
m_Pathvar == wxS(
"${KISYS3DMOD}" )
527 || aPath.
m_Pathvar == wxS(
"$(KISYS3DMOD)" ) )
533 wxString msg =
_(
"The given path does not exist" );
534 msg.append( wxT(
"\n" ) );
546 while( tpath.
m_Pathexp.EndsWith( wxT(
"\\" ) ) )
554 std::list< SEARCH_PATH >::iterator sPL =
m_paths.begin();
555 std::list< SEARCH_PATH >::iterator ePL =
m_paths.end();
559 if( tpath.
m_Alias == sPL->m_Alias )
561 wxString msg =
_(
"Alias: " );
563 msg.append( wxT(
"\n" ) );
564 msg.append(
_(
"This path:" ) + wxS(
" " ) );
566 msg.append( wxT(
"\n" ) );
567 msg.append(
_(
"Existing path:" ) + wxS(
" " ) );
568 msg.append( sPL->m_Pathvar );
583 bool useParen =
false;
585 if( aPath.StartsWith( wxS(
"$(" ) ) )
587 else if( !aPath.StartsWith( wxS(
"${" ) ) )
593 pEnd = aPath.find( wxS(
")" ) );
595 pEnd = aPath.find( wxS(
"}" ) );
597 if( pEnd == wxString::npos )
600 wxString envar = aPath.substr( 0, pEnd + 1 );
609 if( sPL->m_Alias == envar )
612 if( !sPL->m_Alias.StartsWith( wxS(
"${" ) ) )
623 wxUniChar psep = tmpFN.GetPathSeparator();
626 if( !tmpFN.DirExists() )
643 wxString fname = aFullPathName;
650 std::list< SEARCH_PATH >::const_iterator sL =
m_paths.begin();
657 if( sL->m_Pathexp.empty() )
666 if( sL->m_Alias.StartsWith( wxS(
"${" ) ) || sL->m_Alias.StartsWith( wxS(
"$(" ) ) )
676 fpath.Assign( tpath, wxT(
"" ) );
680 fpath.Assign( sL->m_Pathexp, wxT(
"" ) );
683 wxString fps = fpath.GetPathWithSep();
686 idx = fname.find( fps );
690 fname = fname.substr( fps.size() );
694 fname.Replace( wxT(
"\\" ), wxT(
"/" ) );
697 if( sL->m_Alias.StartsWith( wxS(
"${" ) ) || sL->m_Alias.StartsWith( wxS(
"$(" ) ) )
701 tname.Append( wxS(
"/" ) );
702 tname.append( fname );
708 tname.append( sL->m_Alias );
709 tname.append( wxS(
"}/" ) );
710 tname.append( fname );
724 fname.Replace( wxT(
"\\" ), wxT(
"/" ) );
738 wxString& anAlias, wxString& aRelPath )
const
743 size_t searchStart = 0;
745 if( aFileName.StartsWith( wxT(
":" ) ) )
748 size_t tagpos = aFileName.find( wxT(
":" ), searchStart );
750 if( tagpos == wxString::npos || tagpos == searchStart )
753 if( tagpos + 1 >= aFileName.length() )
756 anAlias = aFileName.substr( searchStart, tagpos - searchStart );
757 aRelPath = aFileName.substr( tagpos + 1 );
774 if( aFileName.empty() )
777 if( aFileName.StartsWith( wxT(
"file://" ) )
780 size_t prefixLength = aFileName.StartsWith( wxT(
"file://" ) ) ? 7 : 14;
781 if( aFileName.length() > prefixLength && aFileName[prefixLength] !=
'/' )
787 wxString filename = aFileName;
789 size_t aliasStart = aFileName.StartsWith(
':' ) ? 1 : 0;
790 size_t aliasEnd = aFileName.find(
':', aliasStart );
794 filename.Replace( wxT(
"/" ), wxT(
"\\" ) );
797 if( aliasEnd != wxString::npos )
799 size_t pos1 = filename.find( wxT(
":\\" ) );
801 if( pos1 != wxString::npos && ( pos1 != aliasEnd || pos1 != 1 ) )
805 if( pos1 != wxString::npos )
806 aliasEnd = wxString::npos;
809 filename.Replace( wxT(
"\\" ), wxT(
"/" ) );
813 if( aliasEnd == aFileName.length() -1 )
816 if( aliasEnd != wxString::npos )
819 if( aliasEnd == aliasStart )
822 lpath = filename.substr( aliasStart, aliasEnd );
825 if( wxString::npos != lpath.find_first_of( wxT(
"{}[]()%~<>\"='`;:.,&?/\\|$" ) ) )
829 lpath = aFileName.substr( aliasEnd + 1 );
837 aliasEnd = wxString::npos;
839 if( aFileName.StartsWith( wxS(
"${" ) ) )
840 aliasEnd = aFileName.find(
'}' );
841 else if( aFileName.StartsWith( wxS(
"$(" ) ) )
842 aliasEnd = aFileName.find(
')' );
844 if( aliasEnd != wxString::npos )
845 lpath = aFileName.substr( aliasEnd + 1 );
853 wxString lpath_no_sep = lpath;
856 lpath_no_sep.Replace(
"/",
" " );
857 lpath_no_sep.Replace(
"\\",
" " );
860 if( lpath_no_sep.Length() > 1 && lpath_no_sep[1] ==
':' )
861 lpath_no_sep[1] =
' ';
864 if( wxString::npos != lpath_no_sep.find_first_of( wxFileName::GetForbiddenChars() ) )
878 bool hasKisys3D =
false;
889 if( mS->first == wxS(
"KICAD_PTEMPLATES" )
890 || mS->first.Matches( wxS(
"KICAD*_FOOTPRINT_DIR") ) )
896 if( wxString::npos != mS->second.GetValue().find( wxS(
"://" ) ) )
903 paths.push_back( mS->first );
905 if( mS->first.Matches( wxS(
"KICAD*_3DMODEL_DIR") ) )
bool ValidateFileName(const wxString &aFileName, bool &hasAlias) const
Return true if the given path is a valid aliased relative path.
bool createPathList(void)
Build the path list using available information such as KICAD7_3DMODEL_DIR and the 3d_path_list confi...
wxString ResolvePath(const wxString &aFileName, const wxString &aWorkingPath, std::vector< const EMBEDDED_FILES * > aEmbeddedFilesStack)
Determine the full path of the given file name.
bool addPath(const SEARCH_PATH &aPath)
Check that a path is valid and adds it to the search list.
wxString GetProjectDir() const
bool GetKicadPaths(std::list< wxString > &paths) const
Return a list of path environment variables local to KiCad.
bool Set3DConfigDir(const wxString &aConfigDir)
Set the user's configuration directory for 3D models.
void checkEnvVarPath(const wxString &aPath)
Check the ${ENV_VAR} component of a path and adds it to the resolver's path list if it is not yet in ...
std::list< SEARCH_PATH > m_paths
List of base paths to search from.
void SetProgramBase(PGM_BASE *aBase)
Set a pointer to the application's PGM_BASE instance used to extract the local env vars.
bool SplitAlias(const wxString &aFileName, wxString &anAlias, wxString &aRelPath) const
Return true if the given name contains an alias and populates the string anAlias with the alias and a...
wxString m_configDir
3D configuration directory.
const std::list< SEARCH_PATH > * GetPaths() const
Return a pointer to the internal path list; the items in:load.
bool SetProject(const PROJECT *aProject, bool *flgChanged=nullptr)
Set the current KiCad project directory as the first entry in the model path list.
const PROJECT * m_project
bool UpdatePathList(const std::vector< SEARCH_PATH > &aPathList)
Clear the current path list and substitutes the given path list and update the path configuration fil...
wxString ShortenPath(const wxString &aFullPathName)
Produce a relative path based on the existing search directories or returns the same path if the path...
Container for data for KiCad programs.
Container for project specific data.
virtual const wxString GetProjectPath() const
Return the full path of the project.
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
This file is part of the common library.
Functions related to environment variables, including help functions.
static std::mutex mutex_resolver
static const std::string KiCadUriPrefix
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
wxString m_Pathvar
Base path as stored in the configuration file.
wxString m_Pathexp
Expanded base path.
wxString m_Alias
Alias to the base path.
wxLogTrace helper definitions.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().