28 #include <wx/filename.h> 30 #include <wx/msgdlg.h> 38 #define CFGFILE_VERSION 1 39 #define RESOLVER_CONFIG wxT( "3Dresolver.cfg" ) 42 #define ERRFLG_ALIAS (1) 43 #define ERRFLG_RELPATH (2) 44 #define ERRFLG_ENVPATH (4) 46 #define MASK_3D_RESOLVER "3D_RESOLVER" 50 static bool getHollerith(
const std::string& aString,
size_t& aIndex, wxString& aResult );
63 if( aConfigDir.empty() )
70 if( !cfgdir.DirExists() )
91 if( !projdir.DirExists() )
127 std::ostringstream ostr;
128 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
129 ostr <<
" * [INFO] changed project dir to ";
130 ostr <<
m_paths.front().m_Pathexp.ToUTF8();
175 wxUniChar psep = fndummy.GetPathSeparator();
176 std::list< wxString > epaths;
180 for(
const wxString& curr_path : epaths )
184 if( pathVal.empty() )
190 fndummy.Assign( pathVal,
"" );
213 std::list< SEARCH_PATH >::const_iterator sPL =
m_paths.begin();
218 (*sPL).m_Pathexp.GetData() );
229 wxUniChar envMarker(
'$' );
231 while( !
m_paths.empty() && envMarker != *
m_paths.back().m_Alias.rbegin() )
234 size_t nI = aPathList.size();
236 for(
size_t i = 0; i < nI; ++i )
247 if( aFileName.empty() )
248 return wxEmptyString;
254 wxString tname = aFileName;
258 tname.Replace( wxT(
"/" ), wxT(
"\\" ) );
268 wxFileName tmpFN( tname );
271 if( !aFileName.StartsWith(
"${" ) && !aFileName.StartsWith(
"$(" )
272 && !aFileName.StartsWith(
":" ) && tmpFN.IsAbsolute() )
276 if( tmpFN.FileExists() )
277 return tmpFN.GetFullPath();
279 return wxEmptyString;
285 if( tmpFN.FileExists() )
288 tname = tmpFN.GetFullPath();
292 if( aFileName.StartsWith(
"${" ) || aFileName.StartsWith(
"$(" ) )
300 if( aFileName.StartsWith(
"${" ) || aFileName.StartsWith(
"$(" ) )
305 wxString errmsg =
"[3D File Resolver] No such path; ensure the environment var is defined";
306 errmsg.append(
"\n" );
307 errmsg.append( tname );
308 errmsg.append(
"\n" );
312 return wxEmptyString;
319 std::list< SEARCH_PATH >::const_iterator sPL =
m_paths.begin();
320 std::list< SEARCH_PATH >::const_iterator ePL =
m_paths.end();
329 if( !sPL->m_Pathexp.empty() && !tname.StartsWith(
":" ) )
331 tmpFN.Assign( sPL->m_Pathexp,
"" );
332 wxString fullPath = tmpFN.GetPathWithSep() + tname;
336 if( wxFileName::FileExists( fullPath ) )
338 tmpFN.Assign( fullPath );
340 tname = tmpFN.GetFullPath();
347 if( !tname.StartsWith(
":" ) )
350 wxString fullPath(
"${KICAD6_3DMODEL_DIR}" );
351 fullPath.Append( fpath.GetPathSeparator() );
352 fullPath.Append( tname );
354 fpath.Assign( fullPath );
356 if( fpath.Normalize() && fpath.FileExists() )
358 tname = fpath.GetFullPath();
365 while( sPL != ePL && ( sPL->m_Alias.StartsWith(
"${" ) || sPL->m_Alias.StartsWith(
"$(" ) ) )
379 wxString errmsg =
"[3D File Resolver] No such path";
380 errmsg.append(
"\n" );
381 errmsg.append( tname );
382 errmsg.append(
"\n" );
386 return wxEmptyString;
391 if( !sPL->m_Alias.Cmp( alias ) && !sPL->m_Pathexp.empty() )
393 wxFileName fpath( wxFileName::DirName( sPL->m_Pathexp ) );
394 wxString fullPath = fpath.GetPathWithSep() + relpath;
398 if( wxFileName::FileExists( fullPath ) )
400 wxFileName tmp( fullPath );
402 if( tmp.Normalize() )
403 tname = tmp.GetFullPath();
415 wxString errmsg =
"[3D File Resolver] No such path; ensure the path alias is defined";
416 errmsg.append(
"\n" );
417 errmsg.append( tname.substr( 1 ) );
418 errmsg.append(
"\n" );
422 return wxEmptyString;
436 while( tpath.
m_Pathvar.EndsWith( wxT(
"\\" ) ) )
447 if( !path.DirExists() )
451 if( aPath.
m_Pathvar.compare( wxT(
"${KICAD6_3DMODEL_DIR}" ) ) )
453 wxString msg =
_(
"The given path does not exist" );
454 msg.append( wxT(
"\n" ) );
456 wxMessageBox( msg,
_(
"3D model search path" ) );
466 while( tpath.
m_Pathexp.EndsWith( wxT(
"\\" ) ) )
474 wxString pname = path.GetPath();
475 std::list< SEARCH_PATH >::iterator sPL =
m_paths.begin();
476 std::list< SEARCH_PATH >::iterator ePL =
m_paths.end();
480 if( !tpath.
m_Alias.Cmp( sPL->m_Alias ) )
482 wxString msg =
_(
"Alias: " );
484 msg.append( wxT(
"\n" ) );
485 msg.append(
_(
"This path:" ) + wxS(
" " ) );
487 msg.append( wxT(
"\n" ) );
488 msg.append(
_(
"Existing path:" ) + wxS(
" " ) );
489 msg.append( sPL->m_Pathvar );
490 wxMessageBox( msg,
_(
"Bad alias (duplicate name)" ) );
507 std::ostringstream ostr;
508 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
509 wxString errmsg =
"3D configuration directory is unknown";
510 ostr <<
" * " << errmsg.ToUTF8();
517 wxString cfgname = cfgpath.GetFullPath();
519 size_t nitems =
m_paths.size();
521 std::ifstream cfgFile;
524 if( !wxFileName::Exists( cfgname ) )
526 std::ostringstream ostr;
527 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
528 wxString errmsg =
"no 3D configuration file";
529 ostr <<
" * " << errmsg.ToUTF8() <<
" '";
530 ostr << cfgname.ToUTF8() <<
"'";
535 cfgFile.open( cfgname.ToUTF8() );
537 if( !cfgFile.is_open() )
539 std::ostringstream ostr;
540 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
541 wxString errmsg =
"Could not open configuration file";
542 ostr <<
" * " << errmsg.ToUTF8() <<
" '" << cfgname.ToUTF8() <<
"'";
552 while( cfgFile.good() )
555 std::getline( cfgFile, cfgLine );
558 if( cfgLine.empty() )
566 if( 1 == lineno && cfgLine.compare( 0, 2,
"#V" ) == 0 )
569 if( cfgLine.size() > 2 )
571 std::istringstream istr;
572 istr.str( cfgLine.substr( 2 ) );
585 if( !al.
m_Alias.Cmp( wxT(
"KICAD6_3DMODEL_DIR" ) ) )
602 return(
m_paths.size() != nitems );
610 std::ostringstream ostr;
611 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
612 wxString errmsg =
_(
"3D configuration directory is unknown" );
613 ostr <<
" * " << errmsg.ToUTF8();
615 wxMessageBox( errmsg,
_(
"Write 3D search path list" ) );
621 std::list< SEARCH_PATH >::const_iterator sPL =
m_paths.begin();
624 ( sPL->m_Alias.StartsWith(
"${" ) || sPL->m_Alias.StartsWith(
"$(" ) ) )
628 wxString cfgname = cfgpath.GetFullPath();
629 std::ofstream cfgFile;
631 cfgFile.open( cfgname.ToUTF8(), std::ios_base::trunc );
633 if( !cfgFile.is_open() )
635 std::ostringstream ostr;
636 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
637 wxString errmsg =
_(
"Could not open configuration file" );
638 ostr <<
" * " << errmsg.ToUTF8() <<
" '" << cfgname.ToUTF8() <<
"'";
640 wxMessageBox( errmsg,
_(
"Write 3D search path list" ) );
650 tstr = sPL->m_Alias.ToUTF8();
651 cfgFile <<
"\"" << tstr.size() <<
":" << tstr <<
"\",";
652 tstr = sPL->m_Pathvar.ToUTF8();
653 cfgFile <<
"\"" << tstr.size() <<
":" << tstr <<
"\",";
654 tstr = sPL->m_Description.ToUTF8();
655 cfgFile <<
"\"" << tstr.size() <<
":" << tstr <<
"\"\n";
659 bool bad = cfgFile.bad();
664 wxMessageBox(
_(
"Problems writing configuration file" ),
665 _(
"Write 3D search path list" ) );
676 bool useParen =
false;
678 if( aPath.StartsWith(
"$(" ) )
680 else if( !aPath.StartsWith(
"${" ) )
686 pEnd = aPath.find(
")" );
688 pEnd = aPath.find(
"}" );
690 if( pEnd == wxString::npos )
693 wxString envar = aPath.substr( 0, pEnd + 1 );
702 if( sPL->m_Alias == envar )
705 if( !sPL->m_Alias.StartsWith(
"${" ) )
716 wxUniChar psep = tmpFN.GetPathSeparator();
719 if( !tmpFN.DirExists() )
736 wxString fname = aFullPathName;
743 std::list< SEARCH_PATH >::const_iterator sL =
m_paths.begin();
750 if( sL->m_Pathexp.empty() )
759 if( sL->m_Alias.StartsWith(
"${" ) || sL->m_Alias.StartsWith(
"$(" ) )
769 fpath.Assign( tpath, wxT(
"" ) );
773 fpath.Assign( sL->m_Pathexp, wxT(
"" ) );
776 wxString fps = fpath.GetPathWithSep();
779 idx = fname.find( fps );
783 fname = fname.substr( fps.size() );
787 fname.Replace( wxT(
"\\" ), wxT(
"/" ) );
790 if( sL->m_Alias.StartsWith(
"${" ) || sL->m_Alias.StartsWith(
"$(" ) )
795 tname.append( fname );
801 tname.append( sL->m_Alias );
803 tname.append( fname );
817 fname.Replace( wxT(
"\\" ), wxT(
"/" ) );
832 wxString& anAlias, wxString& aRelPath )
837 if( !aFileName.StartsWith( wxT(
":" ) ) )
840 size_t tagpos = aFileName.find( wxT(
":" ), 1 );
842 if( wxString::npos == tagpos || 1 == tagpos )
845 if( tagpos + 1 >= aFileName.length() )
848 anAlias = aFileName.substr( 1, tagpos - 1 );
849 aRelPath = aFileName.substr( tagpos + 1 );
855 static bool getHollerith(
const std::string& aString,
size_t& aIndex, wxString& aResult )
859 if( aIndex >= aString.size() )
861 std::ostringstream ostr;
862 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
863 wxString errmsg =
"bad Hollerith string on line";
864 ostr <<
" * " << errmsg.ToUTF8() <<
"\n'" << aString <<
"'";
870 size_t i2 = aString.find(
'"', aIndex );
872 if( std::string::npos == i2 )
874 std::ostringstream ostr;
875 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
876 wxString errmsg =
"missing opening quote mark in config file";
877 ostr <<
" * " << errmsg.ToUTF8() <<
"\n'" << aString <<
"'";
885 if( i2 >= aString.size() )
887 std::ostringstream ostr;
888 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
889 wxString errmsg =
"invalid entry (unexpected end of line)";
890 ostr <<
" * " << errmsg.ToUTF8() <<
"\n'" << aString <<
"'";
898 while( aString[i2] >=
'0' && aString[i2] <=
'9' )
899 tnum.append( 1, aString[i2++] );
901 if( tnum.empty() || aString[i2++] !=
':' )
903 std::ostringstream ostr;
904 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
905 wxString errmsg =
"bad Hollerith string on line";
906 ostr <<
" * " << errmsg.ToUTF8() <<
"\n'" << aString <<
"'";
912 std::istringstream istr;
917 if( (i2 + nchars) >= aString.size() )
919 std::ostringstream ostr;
920 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
921 wxString errmsg =
"invalid entry (unexpected end of line)";
922 ostr <<
" * " << errmsg.ToUTF8() <<
"\n'" << aString <<
"'";
930 aResult = wxString::FromUTF8( aString.substr( i2, nchars ).c_str() );
934 if( i2 >= aString.size() || aString[i2] !=
'"' )
936 std::ostringstream ostr;
937 ostr << __FILE__ <<
": " << __FUNCTION__ <<
": " << __LINE__ <<
"\n";
938 wxString errmsg =
"missing closing quote mark in config file";
939 ostr <<
" * " << errmsg.ToUTF8() <<
"\n'" << aString <<
"'";
959 if( aFileName.empty() )
962 wxString filename = aFileName;
963 size_t pos0 = aFileName.find(
':' );
967 filename.Replace( wxT(
"/" ), wxT(
"\\" ) );
970 if( pos0 != wxString::npos )
972 size_t pos1 = filename.find( wxT(
":\\" ) );
974 if( pos1 != wxString::npos && ( pos1 != pos0 || pos1 != 1 ) )
978 if( pos1 != wxString::npos )
979 pos0 = wxString::npos;
982 filename.Replace( wxT(
"\\" ), wxT(
"/" ) );
986 if( pos0 == aFileName.length() -1 )
989 if( pos0 != wxString::npos )
995 wxString lpath = filename.substr( 0, pos0 );
998 if( wxString::npos != lpath.find_first_of( wxT(
"{}[]()%~<>\"='`;:.,&?/\\|$" ) ) )
1015 bool hasKisys3D =
false;
1026 if( mS->first == wxString(
"KICAD_PTEMPLATES" )
1027 || mS->first == wxString(
"KICAD6_FOOTPRINT_DIR" ) )
1033 if( wxString::npos != mS->second.GetValue().find( wxString(
"://" ) ) )
1039 wxString tmp(
"${" );
1040 tmp.Append( mS->first );
1042 paths.push_back( tmp );
1044 if( tmp ==
"${KICAD6_3DMODEL_DIR}" )
1051 paths.emplace_back(
"${KICAD6_3DMODEL_DIR}" );
std::list< SEARCH_PATH > m_paths
Container for project specific data.
bool readPathList(void)
Read a list of path names from a configuration file.
Container for data for KiCad programs.
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
bool writePathList(void)
Write the current path list to a configuration file.
bool createPathList(void)
Build the path list using available information such as KICAD6_3DMODEL_DIR and the 3d_path_list confi...
const std::list< SEARCH_PATH > * GetPaths(void)
Return a pointer to the internal path list; the items in:load.
virtual const ENV_VAR_MAP & GetLocalEnvVariables() const
static bool getHollerith(const std::string &aString, size_t &aIndex, wxString &aResult)
const wxString ExpandEnvVarSubstitutions(const wxString &aString, PROJECT *aProject)
Replace any environment variable & text variable references with their values.
virtual const wxString GetProjectPath() const
Return the full path of the project.
bool SplitAlias(const wxString &aFileName, wxString &anAlias, wxString &aRelPath)
Return true if the given name contains an alias and populates the string anAlias with the alias and a...
bool UpdatePathList(std::vector< SEARCH_PATH > &aPathList)
Clear the current path list and substitutes the given path list and update the path configuration fil...
bool addPath(const SEARCH_PATH &aPath)
Check that a path is valid and adds it to the search list.
wxString ShortenPath(const wxString &aFullPathName)
Produce a relative path based on the existing search directories or returns the same path if the path...
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER
bool GetKicadPaths(std::list< wxString > &paths)
Return a list of path environment variables local to KiCad.
wxString GetProjectDir(void)
wxLogTrace helper definitions.
wxString ResolvePath(const wxString &aFileName)
Determines the full path of the given file name.
static std::mutex mutex_resolver
bool SetProject(PROJECT *aProject, bool *flgChanged=nullptr)
Set the current KiCad project directory as the first entry in the model path list.
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 ...
void SetProgramBase(PGM_BASE *aBase)
Set a pointer to the application's PGM_BASE instance used to extract the local env vars.
bool ValidateFileName(const wxString &aFileName, bool &hasAlias)
Returns true if the given path is a valid aliased relative path.