KiCad PCB EDA Suite
FILENAME_RESOLVER Class Reference

#include <filename_resolver.h>

Public Member Functions

 FILENAME_RESOLVER ()
 
bool Set3DConfigDir (const wxString &aConfigDir)
 Function Set3DConfigDir sets the user's configuration directory for 3D models. More...
 
bool SetProjectDir (const wxString &aProjDir, bool *flgChanged=NULL)
 Function SetProjectDir sets the current KiCad project directory as the first entry in the model path list. More...
 
wxString GetProjectDir (void)
 
void SetProgramBase (PGM_BASE *aBase)
 Function SetProgramBase sets a pointer to the application's PGM_BASE instance; the pointer is used to extract the local env vars. More...
 
bool UpdatePathList (std::vector< SEARCH_PATH > &aPathList)
 Function UpdatePathList clears the current path list and substitutes the given path list, updating the path configuration file on success. More...
 
wxString ResolvePath (const wxString &aFileName)
 Function ResolvePath determines the full path of the given file name. More...
 
wxString ShortenPath (const wxString &aFullPathName)
 Function ShortenPath produces a relative path based on the existing search directories or returns the same path if the path is not a superset of an existing search path. More...
 
const std::list< SEARCH_PATH > * GetPaths (void)
 Function GetPaths returns a pointer to the internal path list; the items in:load. More...
 
bool SplitAlias (const wxString &aFileName, wxString &anAlias, wxString &aRelPath)
 Function SplitAlias returns true if the given name contains an alias and populates the string anAlias with the alias and aRelPath with the relative path. More...
 
bool ValidateFileName (const wxString &aFileName, bool &hasAlias)
 Function ValidateName returns true if the given path is a valid aliased relative path. More...
 
bool GetKicadPaths (std::list< wxString > &paths)
 Function GetKicadPaths returns a list of path environment variables local to Kicad; this list always includes KISYS3DMOD even if it is not defined locally. More...
 

Private Member Functions

bool createPathList (void)
 Function createPathList builds the path list using available information such as KISYS3DMOD and the 3d_path_list configuration file. More...
 
bool addPath (const SEARCH_PATH &aPath)
 Function addPath checks that a path is valid and adds it to the search list. More...
 
bool readPathList (void)
 Function readPathList reads a list of path names from a configuration file. More...
 
bool writePathList (void)
 Function writePathList writes the current path list to a configuration file. More...
 
void checkEnvVarPath (const wxString &aPath)
 Function checkEnvVarPath checks the ${ENV_VAR} component of a path and adds it to the resolver's path list if it is not yet in the list. More...
 

Private Attributes

wxString m_ConfigDir
 
std::list< SEARCH_PATHm_Paths
 
int m_errflags
 
PGM_BASEm_pgm
 
wxString m_curProjDir
 

Detailed Description

Definition at line 51 of file filename_resolver.h.

Constructor & Destructor Documentation

FILENAME_RESOLVER::FILENAME_RESOLVER ( )

Definition at line 52 of file filename_resolver.cpp.

References m_errflags, and m_pgm.

53 {
54  m_errflags = 0;
55  m_pgm = NULL;
56 }

Member Function Documentation

bool FILENAME_RESOLVER::addPath ( const SEARCH_PATH aPath)
private

Function addPath checks that a path is valid and adds it to the search list.

Parameters
aPathis the alias set to be checked and added
Returns
true if aPath is valid

Definition at line 438 of file filename_resolver.cpp.

References ExpandEnvVarSubstitutions(), lock_resolver, SEARCH_PATH::m_alias, SEARCH_PATH::m_pathexp, m_Paths, and SEARCH_PATH::m_pathvar.

Referenced by readPathList(), and UpdatePathList().

439 {
440  if( aPath.m_alias.empty() || aPath.m_pathvar.empty() )
441  return false;
442 
443  wxCriticalSectionLocker lock( lock_resolver );
444 
445  SEARCH_PATH tpath = aPath;
446 
447  #ifdef _WIN32
448  while( tpath.m_pathvar.EndsWith( wxT( "\\" ) ) )
449  tpath.m_pathvar.erase( tpath.m_pathvar.length() - 1 );
450  #else
451  while( tpath.m_pathvar.EndsWith( wxT( "/" ) ) && tpath.m_pathvar.length() > 1 )
452  tpath.m_pathvar.erase( tpath.m_pathvar.length() - 1 );
453  #endif
454 
455  wxFileName path;
456 
457  if( tpath.m_pathvar.StartsWith( "${" ) || tpath.m_pathvar.StartsWith( "$(" ) )
458  path.Assign( ExpandEnvVarSubstitutions( tpath.m_pathvar ), "" );
459  else
460  path.Assign( tpath.m_pathvar, "" );
461 
462  path.Normalize();
463 
464  if( !path.DirExists() )
465  {
466  // suppress the message if the missing pathvar is the
467  // legacy KISYS3DMOD variable
468  if( aPath.m_pathvar.compare( wxT( "${KISYS3DMOD}" ) ) )
469  {
470  wxString msg = _( "The given path does not exist" );
471  msg.append( wxT( "\n" ) );
472  msg.append( tpath.m_pathvar );
473  wxMessageBox( msg, _( "3D model search path" ) );
474  }
475 
476  tpath.m_pathexp.clear();
477  }
478  else
479  {
480  tpath.m_pathexp = path.GetFullPath();
481 
482  #ifdef _WIN32
483  while( tpath.m_pathexp.EndsWith( wxT( "\\" ) ) )
484  tpath.m_pathexp.erase( tpath.m_pathexp.length() - 1 );
485  #else
486  while( tpath.m_pathexp.EndsWith( wxT( "/" ) ) && tpath.m_pathexp.length() > 1 )
487  tpath.m_pathexp.erase( tpath.m_pathexp.length() - 1 );
488  #endif
489  }
490 
491  wxString pname = path.GetPath();
492  std::list< SEARCH_PATH >::iterator sPL = m_Paths.begin();
493  std::list< SEARCH_PATH >::iterator ePL = m_Paths.end();
494 
495  while( sPL != ePL )
496  {
497  if( !tpath.m_alias.Cmp( sPL->m_alias ) )
498  {
499  wxString msg = _( "Alias: " );
500  msg.append( tpath.m_alias );
501  msg.append( wxT( "\n" ) );
502  msg.append( _( "This path: " ) );
503  msg.append( tpath.m_pathvar );
504  msg.append( wxT( "\n" ) );
505  msg.append( _( "Existing path: " ) );
506  msg.append( sPL->m_pathvar );
507  wxMessageBox( msg, _( "Bad alias (duplicate name)" ) );
508 
509  return false;
510  }
511 
512  ++sPL;
513  }
514 
515  m_Paths.push_back( tpath );
516  return true;
517 }
wxString m_alias
std::list< SEARCH_PATH > m_Paths
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Replace any environment variable references with their values.
Definition: common.cpp:442
wxString m_pathexp
static wxCriticalSection lock_resolver
wxString m_pathvar
void FILENAME_RESOLVER::checkEnvVarPath ( const wxString &  aPath)
private

Function checkEnvVarPath checks the ${ENV_VAR} component of a path and adds it to the resolver's path list if it is not yet in the list.

Definition at line 691 of file filename_resolver.cpp.

References ExpandEnvVarSubstitutions(), SEARCH_PATH::m_alias, SEARCH_PATH::m_pathexp, m_Paths, and SEARCH_PATH::m_pathvar.

Referenced by ResolvePath().

692 {
693  bool useParen = false;
694 
695  if( aPath.StartsWith( "$(" ) )
696  useParen = true;
697  else if( !aPath.StartsWith( "${" ) )
698  return;
699 
700  size_t pEnd;
701 
702  if( useParen )
703  pEnd = aPath.find( ")" );
704  else
705  pEnd = aPath.find( "}" );
706 
707  if( pEnd == wxString::npos )
708  return;
709 
710  wxString envar = aPath.substr( 0, pEnd + 1 );
711 
712  // check if the alias exists; if not then add it to the end of the
713  // env var section of the path list
714  auto sPL = m_Paths.begin();
715  auto ePL = m_Paths.end();
716 
717  while( sPL != ePL )
718  {
719  if( sPL->m_alias == envar )
720  return;
721 
722  if( !sPL->m_alias.StartsWith( "${" ) )
723  break;
724 
725  ++sPL;
726  }
727 
728  SEARCH_PATH lpath;
729  lpath.m_alias = envar;
730  lpath.m_pathvar = lpath.m_alias;
731  wxFileName tmpFN;
732 
733  if( lpath.m_alias.StartsWith( "${" ) || lpath.m_alias.StartsWith( "$(" ) )
734  tmpFN.Assign( ExpandEnvVarSubstitutions( lpath.m_alias ), "" );
735  else
736  tmpFN.Assign( lpath.m_alias, "" );
737 
738  wxUniChar psep = tmpFN.GetPathSeparator();
739  tmpFN.Normalize();
740 
741  if( !tmpFN.DirExists() )
742  return;
743 
744  lpath.m_pathexp = tmpFN.GetFullPath();
745 
746  if( !lpath.m_pathexp.empty() && psep == *lpath.m_pathexp.rbegin() )
747  lpath.m_pathexp.erase( --lpath.m_pathexp.end() );
748 
749  if( lpath.m_pathexp.empty() )
750  return;
751 
752  m_Paths.insert( sPL, lpath );
753 }
wxString m_alias
std::list< SEARCH_PATH > m_Paths
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Replace any environment variable references with their values.
Definition: common.cpp:442
wxString m_pathexp
wxString m_pathvar
bool FILENAME_RESOLVER::createPathList ( void  )
private

Function createPathList builds the path list using available information such as KISYS3DMOD and the 3d_path_list configuration file.

Invalid paths are silently discarded and removed from the configuration file.

Returns
true if at least one valid path was found

Definition at line 166 of file filename_resolver.cpp.

References ExpandEnvVarSubstitutions(), GetKicadPaths(), i, SEARCH_PATH::m_alias, m_ConfigDir, m_curProjDir, SEARCH_PATH::m_pathexp, m_Paths, SEARCH_PATH::m_pathvar, MASK_3D_RESOLVER, and readPathList().

Referenced by ResolvePath(), Set3DConfigDir(), SetProgramBase(), and ShortenPath().

167 {
168  if( !m_Paths.empty() )
169  return true;
170 
171  wxString kmod;
172 
173  // add an entry for the default search path; at this point
174  // we cannot set a sensible default so we use an empty string.
175  // the user may change this later with a call to SetProjectDir()
176 
177  SEARCH_PATH lpath;
178  lpath.m_alias = "${KIPRJMOD}";
179  lpath.m_pathvar = "${KIPRJMOD}";
180  lpath.m_pathexp = m_curProjDir;
181  m_Paths.push_back( lpath );
182  wxFileName fndummy;
183  wxUniChar psep = fndummy.GetPathSeparator();
184  std::list< wxString > epaths;
185 
186  if( GetKicadPaths( epaths ) )
187  {
188  for( const auto& i : epaths )
189  {
190  wxString pathVal = ExpandEnvVarSubstitutions( i );
191 
192  if( pathVal.empty() )
193  {
194  lpath.m_pathexp.clear();
195  }
196  else
197  {
198  fndummy.Assign( pathVal, "" );
199  fndummy.Normalize();
200  lpath.m_pathexp = fndummy.GetFullPath();
201  }
202 
203  lpath.m_alias = i;
204  lpath.m_pathvar = i;
205 
206  if( !lpath.m_pathexp.empty() && psep == *lpath.m_pathexp.rbegin() )
207  lpath.m_pathexp.erase( --lpath.m_pathexp.end() );
208 
209  m_Paths.push_back( lpath );
210  }
211  }
212 
213  if( !m_ConfigDir.empty() )
214  readPathList();
215 
216  if( m_Paths.empty() )
217  return false;
218 
219 #ifdef DEBUG
220  wxLogTrace( MASK_3D_RESOLVER, " * [3D model] search paths:\n" );
221  std::list< SEARCH_PATH >::const_iterator sPL = m_Paths.begin();
222  std::list< SEARCH_PATH >::const_iterator ePL = m_Paths.end();
223 
224  while( sPL != ePL )
225  {
226  wxLogTrace( MASK_3D_RESOLVER, " + %s : '%s'\n", (*sPL).m_alias.GetData(),
227  (*sPL).m_pathexp.GetData() );
228  ++sPL;
229  }
230 #endif
231 
232  return true;
233 }
bool readPathList(void)
Function readPathList reads a list of path names from a configuration file.
wxString m_alias
std::list< SEARCH_PATH > m_Paths
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Replace any environment variable references with their values.
Definition: common.cpp:442
bool GetKicadPaths(std::list< wxString > &paths)
Function GetKicadPaths returns a list of path environment variables local to Kicad; this list always ...
wxString m_pathexp
wxString m_pathvar
size_t i
Definition: json11.cpp:597
#define MASK_3D_RESOLVER
bool FILENAME_RESOLVER::GetKicadPaths ( std::list< wxString > &  paths)

Function GetKicadPaths returns a list of path environment variables local to Kicad; this list always includes KISYS3DMOD even if it is not defined locally.

Definition at line 1030 of file filename_resolver.cpp.

References PGM_BASE::GetLocalEnvVariables(), and m_pgm.

Referenced by createPathList().

1031 {
1032  paths.clear();
1033 
1034  if( !m_pgm )
1035  return false;
1036 
1037  bool hasKisys3D = false;
1038 
1039 
1040  // iterate over the list of internally defined ENV VARs
1041  // and add them to the paths list
1044 
1045  while( mS != mE )
1046  {
1047  // filter out URLs, template directories, and known system paths
1048  if( mS->first == wxString( "KICAD_PTEMPLATES" )
1049  || mS->first == wxString( "KIGITHUB" )
1050  || mS->first == wxString( "KISYSMOD" ) )
1051  {
1052  ++mS;
1053  continue;
1054  }
1055 
1056  if( wxString::npos != mS->second.GetValue().find( wxString( "://" ) ) )
1057  {
1058  ++mS;
1059  continue;
1060  }
1061 
1062  wxString tmp( "${" );
1063  tmp.Append( mS->first );
1064  tmp.Append( "}" );
1065  paths.push_back( tmp );
1066 
1067  if( tmp == "${KISYS3DMOD}" )
1068  hasKisys3D = true;
1069 
1070  ++mS;
1071  }
1072 
1073  if( !hasKisys3D )
1074  paths.push_back( "${KISYS3DMOD}" );
1075 
1076  return true;
1077 }
VTBL_ENTRY const ENV_VAR_MAP & GetLocalEnvVariables() const
Definition: pgm_base.h:312
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER
Definition: pgm_base.h:131
const std::list< SEARCH_PATH > * FILENAME_RESOLVER::GetPaths ( void  )

Function GetPaths returns a pointer to the internal path list; the items in:load.

the list can be used to set up the list of search paths available to a 3D file browser.

Returns
pointer to the internal path list

Definition at line 847 of file filename_resolver.cpp.

References m_Paths.

Referenced by DIALOG_CONFIGURE_PATHS::TransferDataToWindow(), and DLG_SELECT_3DMODEL::updateDirChoiceList().

848 {
849  return &m_Paths;
850 }
std::list< SEARCH_PATH > m_Paths
wxString FILENAME_RESOLVER::GetProjectDir ( void  )

Definition at line 147 of file filename_resolver.cpp.

References m_curProjDir.

148 {
149  return m_curProjDir;
150 }
bool FILENAME_RESOLVER::readPathList ( void  )
private

Function readPathList reads a list of path names from a configuration file.

Returns
true if a file was found and contained at least one valid path

Definition at line 520 of file filename_resolver.cpp.

References addPath(), CFGFILE_VERSION, getHollerith(), SEARCH_PATH::m_alias, m_ConfigDir, SEARCH_PATH::m_description, m_Paths, SEARCH_PATH::m_pathvar, MASK_3D_RESOLVER, RESOLVER_CONFIG, and writePathList().

Referenced by createPathList().

521 {
522  if( m_ConfigDir.empty() )
523  {
524  std::ostringstream ostr;
525  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
526  wxString errmsg = "3D configuration directory is unknown";
527  ostr << " * " << errmsg.ToUTF8();
528  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
529  return false;
530  }
531 
532  wxFileName cfgpath( m_ConfigDir, RESOLVER_CONFIG );
533  cfgpath.Normalize();
534  wxString cfgname = cfgpath.GetFullPath();
535 
536  size_t nitems = m_Paths.size();
537 
538  std::ifstream cfgFile;
539  std::string cfgLine;
540 
541  if( !wxFileName::Exists( cfgname ) )
542  {
543  std::ostringstream ostr;
544  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
545  wxString errmsg = "no 3D configuration file";
546  ostr << " * " << errmsg.ToUTF8() << " '";
547  ostr << cfgname.ToUTF8() << "'";
548  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
549  return false;
550  }
551 
552  cfgFile.open( cfgname.ToUTF8() );
553 
554  if( !cfgFile.is_open() )
555  {
556  std::ostringstream ostr;
557  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
558  wxString errmsg = "Could not open configuration file";
559  ostr << " * " << errmsg.ToUTF8() << " '" << cfgname.ToUTF8() << "'";
560  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
561  return false;
562  }
563 
564  int lineno = 0;
565  SEARCH_PATH al;
566  size_t idx;
567  int vnum = 0; // version number
568 
569  while( cfgFile.good() )
570  {
571  cfgLine.clear();
572  std::getline( cfgFile, cfgLine );
573  ++lineno;
574 
575  if( cfgLine.empty() )
576  {
577  if( cfgFile.eof() )
578  break;
579 
580  continue;
581  }
582 
583  if( 1 == lineno && cfgLine.compare( 0, 2, "#V" ) == 0 )
584  {
585  // extract the version number and parse accordingly
586  if( cfgLine.size() > 2 )
587  {
588  std::istringstream istr;
589  istr.str( cfgLine.substr( 2 ) );
590  istr >> vnum;
591  }
592 
593  continue;
594  }
595 
596  idx = 0;
597 
598  if( !getHollerith( cfgLine, idx, al.m_alias ) )
599  continue;
600 
601  // never add on KISYS3DMOD from a config file
602  if( !al.m_alias.Cmp( wxT( "KISYS3DMOD" ) ) )
603  continue;
604 
605  if( !getHollerith( cfgLine, idx, al.m_pathvar ) )
606  continue;
607 
608  if( !getHollerith( cfgLine, idx, al.m_description ) )
609  continue;
610 
611  addPath( al );
612  }
613 
614  cfgFile.close();
615 
616  if( vnum < CFGFILE_VERSION )
617  writePathList();
618 
619  return( m_Paths.size() != nitems );
620 }
#define CFGFILE_VERSION
wxString m_alias
std::list< SEARCH_PATH > m_Paths
bool writePathList(void)
Function writePathList writes the current path list to a configuration file.
static bool getHollerith(const std::string &aString, size_t &aIndex, wxString &aResult)
bool addPath(const SEARCH_PATH &aPath)
Function addPath checks that a path is valid and adds it to the search list.
wxString m_description
#define RESOLVER_CONFIG
wxString m_pathvar
#define MASK_3D_RESOLVER
wxString FILENAME_RESOLVER::ResolvePath ( const wxString &  aFileName)

Function ResolvePath determines the full path of the given file name.

In the future remote files may be supported, in which case it is best to require a full URI in which case ResolvePath should check that the URI conforms to RFC-2396 and related documents and copies aFileName into aResolvedName if the URI is valid.

Definition at line 252 of file filename_resolver.cpp.

References checkEnvVarPath(), createPathList(), ERRFLG_ALIAS, ERRFLG_ENVPATH, ERRFLG_RELPATH, ExpandEnvVarSubstitutions(), lock_resolver, m_errflags, m_Paths, SplitAlias(), and tracePathsAndFiles.

Referenced by export_vrml_module(), and idf_export_module().

253 {
254  wxCriticalSectionLocker lock( lock_resolver );
255 
256  if( aFileName.empty() )
257  return wxEmptyString;
258 
259  if( m_Paths.empty() )
260  createPathList();
261 
262  // first attempt to use the name as specified:
263  wxString tname = aFileName;
264 
265  #ifdef _WIN32
266  // translate from KiCad's internal UNIX-like path to MSWin paths
267  tname.Replace( wxT( "/" ), wxT( "\\" ) );
268  #endif
269 
270  // Note: variable expansion must be performed using a threadsafe
271  // wrapper for the getenv() system call. If we allow the
272  // wxFileName::Normalize() routine to perform expansion then
273  // we will have a race condition since wxWidgets does not assure
274  // a threadsafe wrapper for getenv().
275  if( tname.StartsWith( "${" ) || tname.StartsWith( "$(" ) )
276  tname = ExpandEnvVarSubstitutions( tname );
277 
278  wxFileName tmpFN( tname );
279 
280  // in the case of absolute filenames we don't store a map item
281  if( !aFileName.StartsWith( "${" ) && !aFileName.StartsWith( "$(" )
282  && !aFileName.StartsWith( ":" ) && tmpFN.IsAbsolute() )
283  {
284  tmpFN.Normalize();
285 
286  if( tmpFN.FileExists() )
287  return tmpFN.GetFullPath();
288 
289  return wxEmptyString;
290  }
291 
292  // this case covers full paths, leading expanded vars, and paths
293  // relative to the current working directory (which is not necessarily
294  // the current project directory)
295  if( tmpFN.FileExists() )
296  {
297  tmpFN.Normalize();
298  tname = tmpFN.GetFullPath();
299 
300  // special case: if a path begins with ${ENV_VAR} but is not in the
301  // resolver's path list then add it.
302  if( aFileName.StartsWith( "${" ) || aFileName.StartsWith( "$(" ) )
303  checkEnvVarPath( aFileName );
304 
305  return tname;
306  }
307 
308  // if a path begins with ${ENV_VAR}/$(ENV_VAR) and is not resolved then the
309  // file either does not exist or the ENV_VAR is not defined
310  if( aFileName.StartsWith( "${" ) || aFileName.StartsWith( "$(" ) )
311  {
312  if( !( m_errflags & ERRFLG_ENVPATH ) )
313  {
315  wxString errmsg = "[3D File Resolver] No such path; ensure the environment var is defined";
316  errmsg.append( "\n" );
317  errmsg.append( tname );
318  errmsg.append( "\n" );
319  wxLogTrace( tracePathsAndFiles, errmsg );
320  }
321 
322  return wxEmptyString;
323  }
324 
325  // at this point aFileName is:
326  // a. an aliased shortened name or
327  // b. cannot be determined
328 
329  std::list< SEARCH_PATH >::const_iterator sPL = m_Paths.begin();
330  std::list< SEARCH_PATH >::const_iterator ePL = m_Paths.end();
331 
332  // check the path relative to the current project directory;
333  // note: this is not necessarily the same as the current working
334  // directory, which has already been checked. This case accounts
335  // for partial paths which do not contain ${KIPRJMOD}.
336  // This check is performed before checking the path relative to
337  // ${KISYS3DMOD} so that users can potentially override a model
338  // within ${KISYS3DMOD}
339  if( !sPL->m_pathexp.empty() && !tname.StartsWith( ":" ) )
340  {
341  tmpFN.Assign( sPL->m_pathexp, "" );
342  wxString fullPath = tmpFN.GetPathWithSep() + tname;
343 
344  if( fullPath.StartsWith( "${" ) || fullPath.StartsWith( "$(" ) )
345  fullPath = ExpandEnvVarSubstitutions( fullPath );
346 
347  if( wxFileName::FileExists( fullPath ) )
348  {
349  tmpFN.Assign( fullPath );
350  tmpFN.Normalize();
351  tname = tmpFN.GetFullPath();
352  return tname;
353  }
354 
355  }
356 
357  // check the partial path relative to ${KISYS3DMOD} (legacy behavior)
358  if( !tname.StartsWith( ":" ) )
359  {
360  wxFileName fpath;
361  wxString fullPath( "${KISYS3DMOD}" );
362  fullPath.Append( fpath.GetPathSeparator() );
363  fullPath.Append( tname );
364  fullPath = ExpandEnvVarSubstitutions( fullPath );
365  fpath.Assign( fullPath );
366 
367  if( fpath.Normalize() && fpath.FileExists() )
368  {
369  tname = fpath.GetFullPath();
370  return tname;
371  }
372 
373  }
374 
375  // ${ENV_VAR} paths have already been checked; skip them
376  while( sPL != ePL && ( sPL->m_alias.StartsWith( "${" ) || sPL->m_alias.StartsWith( "$(" ) ) )
377  ++sPL;
378 
379  // at this point the filename must contain an alias or else it is invalid
380  wxString alias; // the alias portion of the short filename
381  wxString relpath; // the path relative to the alias
382 
383  if( !SplitAlias( tname, alias, relpath ) )
384  {
385  if( !( m_errflags & ERRFLG_RELPATH ) )
386  {
387  // this can happen if the file was intended to be relative to
388  // ${KISYS3DMOD} but ${KISYS3DMOD} not set or incorrect.
390  wxString errmsg = "[3D File Resolver] No such path";
391  errmsg.append( "\n" );
392  errmsg.append( tname );
393  errmsg.append( "\n" );
394  wxLogTrace( tracePathsAndFiles, errmsg );
395  }
396 
397  return wxEmptyString;
398  }
399 
400  while( sPL != ePL )
401  {
402  if( !sPL->m_alias.Cmp( alias ) && !sPL->m_pathexp.empty() )
403  {
404  wxFileName fpath( wxFileName::DirName( sPL->m_pathexp ) );
405  wxString fullPath = fpath.GetPathWithSep() + relpath;
406 
407  if( fullPath.StartsWith( "${") || fullPath.StartsWith( "$(" ) )
408  fullPath = ExpandEnvVarSubstitutions( fullPath );
409 
410  if( wxFileName::FileExists( fullPath ) )
411  {
412  wxFileName tmp( fullPath );
413 
414  if( tmp.Normalize() )
415  tname = tmp.GetFullPath();
416 
417  return tname;
418  }
419  }
420 
421  ++sPL;
422  }
423 
424  if( !( m_errflags & ERRFLG_ALIAS ) )
425  {
427  wxString errmsg = "[3D File Resolver] No such path; ensure the path alias is defined";
428  errmsg.append( "\n" );
429  errmsg.append( tname.substr( 1 ) );
430  errmsg.append( "\n" );
431  wxLogTrace( tracePathsAndFiles, errmsg );
432  }
433 
434  return wxEmptyString;
435 }
#define ERRFLG_ENVPATH
std::list< SEARCH_PATH > m_Paths
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
bool createPathList(void)
Function createPathList builds the path list using available information such as KISYS3DMOD and the 3...
bool SplitAlias(const wxString &aFileName, wxString &anAlias, wxString &aRelPath)
Function SplitAlias returns true if the given name contains an alias and populates the string anAlias...
#define ERRFLG_ALIAS
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Replace any environment variable references with their values.
Definition: common.cpp:442
#define ERRFLG_RELPATH
static wxCriticalSection lock_resolver
void checkEnvVarPath(const wxString &aPath)
Function checkEnvVarPath checks the ${ENV_VAR} component of a path and adds it to the resolver&#39;s path...
bool FILENAME_RESOLVER::Set3DConfigDir ( const wxString &  aConfigDir)

Function Set3DConfigDir sets the user's configuration directory for 3D models.

Parameters
aConfigDir
Returns
true if the call succeeds (directory exists)

Definition at line 59 of file filename_resolver.cpp.

References createPathList(), ExpandEnvVarSubstitutions(), and m_ConfigDir.

60 {
61  if( aConfigDir.empty() )
62  return false;
63 
64  wxFileName cfgdir;
65 
66  if( aConfigDir.StartsWith( "${" ) || aConfigDir.StartsWith( "$(" ) )
67  cfgdir.Assign( ExpandEnvVarSubstitutions( aConfigDir ), "" );
68  else
69  cfgdir.Assign( aConfigDir, "" );
70 
71  cfgdir.Normalize();
72 
73  if( !cfgdir.DirExists() )
74  return false;
75 
76  m_ConfigDir = cfgdir.GetPath();
78 
79  return true;
80 }
bool createPathList(void)
Function createPathList builds the path list using available information such as KISYS3DMOD and the 3...
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Replace any environment variable references with their values.
Definition: common.cpp:442
void FILENAME_RESOLVER::SetProgramBase ( PGM_BASE aBase)

Function SetProgramBase sets a pointer to the application's PGM_BASE instance; the pointer is used to extract the local env vars.

Definition at line 153 of file filename_resolver.cpp.

References createPathList(), m_Paths, and m_pgm.

154 {
155  m_pgm = aBase;
156 
157  if( !m_pgm || m_Paths.empty() )
158  return;
159 
160  // recreate the path list
161  m_Paths.clear();
162  createPathList();
163 }
std::list< SEARCH_PATH > m_Paths
bool createPathList(void)
Function createPathList builds the path list using available information such as KISYS3DMOD and the 3...
bool FILENAME_RESOLVER::SetProjectDir ( const wxString &  aProjDir,
bool *  flgChanged = NULL 
)

Function SetProjectDir sets the current KiCad project directory as the first entry in the model path list.

Parameters
[in]aProjDircurrent project directory
[out]flgChangedoptional, set to true if directory was changed
Return values
truesuccess
falsefailure

Definition at line 83 of file filename_resolver.cpp.

References ExpandEnvVarSubstitutions(), SEARCH_PATH::m_alias, m_curProjDir, SEARCH_PATH::m_pathexp, m_Paths, SEARCH_PATH::m_pathvar, and MASK_3D_RESOLVER.

84 {
85  if( aProjDir.empty() )
86  return false;
87 
88  wxFileName projdir;
89 
90  if( aProjDir.StartsWith( "${" ) || aProjDir.StartsWith( "$(" ) )
91  projdir.Assign( ExpandEnvVarSubstitutions( aProjDir ), "" );
92  else
93  projdir.Assign( aProjDir, "" );
94 
95  projdir.Normalize();
96 
97  if( !projdir.DirExists() )
98  return false;
99 
100  m_curProjDir = projdir.GetPath();
101 
102  if( flgChanged )
103  *flgChanged = false;
104 
105  if( m_Paths.empty() )
106  {
107  SEARCH_PATH al;
108  al.m_alias = "${KIPRJMOD}";
109  al.m_pathvar = "${KIPRJMOD}";
110  al.m_pathexp = m_curProjDir;
111  m_Paths.push_back( al );
112 
113  if( flgChanged )
114  *flgChanged = true;
115 
116  }
117  else
118  {
119  if( m_Paths.front().m_pathexp.Cmp( m_curProjDir ) )
120  {
121  m_Paths.front().m_pathexp = m_curProjDir;
122 
123  if( flgChanged )
124  *flgChanged = true;
125 
126  }
127  else
128  {
129  return true;
130  }
131  }
132 
133 #ifdef DEBUG
134  do {
135  std::ostringstream ostr;
136  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
137  ostr << " * [INFO] changed project dir to ";
138  ostr << m_Paths.front().m_pathexp.ToUTF8();
139  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
140  } while( 0 );
141 #endif
142 
143  return true;
144 }
wxString m_alias
std::list< SEARCH_PATH > m_Paths
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Replace any environment variable references with their values.
Definition: common.cpp:442
wxString m_pathexp
wxString m_pathvar
#define MASK_3D_RESOLVER
wxString FILENAME_RESOLVER::ShortenPath ( const wxString &  aFullPathName)

Function ShortenPath produces a relative path based on the existing search directories or returns the same path if the path is not a superset of an existing search path.

Parameters
aFullPathNameis an absolute path to shorten
Returns
the shortened path or aFullPathName

Definition at line 756 of file filename_resolver.cpp.

References createPathList(), ExpandEnvVarSubstitutions(), lock_resolver, and m_Paths.

Referenced by DLG_SELECT_3DMODEL::TransferDataFromWindow().

757 {
758  wxString fname = aFullPathName;
759 
760  if( m_Paths.empty() )
761  createPathList();
762 
763  wxCriticalSectionLocker lock( lock_resolver );
764  std::list< SEARCH_PATH >::const_iterator sL = m_Paths.begin();
765  std::list< SEARCH_PATH >::const_iterator eL = m_Paths.end();
766  size_t idx;
767 
768  while( sL != eL )
769  {
770  // undefined paths do not participate in the
771  // file name shortening procedure
772  if( sL->m_pathexp.empty() )
773  {
774  ++sL;
775  continue;
776  }
777 
778  wxFileName fpath;
779 
780  // in the case of aliases, ensure that we use the most recent definition
781  if( sL->m_alias.StartsWith( "${" ) || sL->m_alias.StartsWith( "$(" ) )
782  {
783  wxString tpath = ExpandEnvVarSubstitutions( sL->m_alias );
784 
785  if( tpath.empty() )
786  {
787  ++sL;
788  continue;
789  }
790 
791  fpath.Assign( tpath, wxT( "" ) );
792  }
793  else
794  {
795  fpath.Assign( sL->m_pathexp, wxT( "" ) );
796  }
797 
798  wxString fps = fpath.GetPathWithSep();
799  wxString tname;
800 
801  idx = fname.find( fps );
802 
803  if( idx == 0 )
804  {
805  fname = fname.substr( fps.size() );
806 
807  #ifdef _WIN32
808  // ensure only the '/' separator is used in the internal name
809  fname.Replace( wxT( "\\" ), wxT( "/" ) );
810  #endif
811 
812  if( sL->m_alias.StartsWith( "${" ) || sL->m_alias.StartsWith( "$(" ) )
813  {
814  // old style ENV_VAR
815  tname = sL->m_alias;
816  tname.Append( "/" );
817  tname.append( fname );
818  }
819  else
820  {
821  // new style alias
822  tname = ":";
823  tname.append( sL->m_alias );
824  tname.append( ":" );
825  tname.append( fname );
826  }
827 
828  return tname;
829  }
830 
831  ++sL;
832  }
833 
834 #ifdef _WIN32
835  // it is strange to convert an MSWin full path to use the
836  // UNIX separator but this is done for consistency and can
837  // be helpful even when transferring project files from
838  // MSWin to *NIX.
839  fname.Replace( wxT( "\\" ), wxT( "/" ) );
840 #endif
841 
842  return fname;
843 }
std::list< SEARCH_PATH > m_Paths
bool createPathList(void)
Function createPathList builds the path list using available information such as KISYS3DMOD and the 3...
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Replace any environment variable references with their values.
Definition: common.cpp:442
static wxCriticalSection lock_resolver
bool FILENAME_RESOLVER::SplitAlias ( const wxString &  aFileName,
wxString &  anAlias,
wxString &  aRelPath 
)

Function SplitAlias returns true if the given name contains an alias and populates the string anAlias with the alias and aRelPath with the relative path.

Definition at line 853 of file filename_resolver.cpp.

Referenced by DIALOG_FOOTPRINT_FP_EDITOR::OnAdd3DModel(), DIALOG_FOOTPRINT_BOARD_EDITOR::OnAdd3DModel(), ResolvePath(), DIALOG_FOOTPRINT_FP_EDITOR::TransferDataToWindow(), and DIALOG_FOOTPRINT_BOARD_EDITOR::TransferDataToWindow().

855 {
856  anAlias.clear();
857  aRelPath.clear();
858 
859  if( !aFileName.StartsWith( wxT( ":" ) ) )
860  return false;
861 
862  size_t tagpos = aFileName.find( wxT( ":" ), 1 );
863 
864  if( wxString::npos == tagpos || 1 == tagpos )
865  return false;
866 
867  if( tagpos + 1 >= aFileName.length() )
868  return false;
869 
870  anAlias = aFileName.substr( 1, tagpos - 1 );
871  aRelPath = aFileName.substr( tagpos + 1 );
872 
873  return true;
874 }
bool FILENAME_RESOLVER::UpdatePathList ( std::vector< SEARCH_PATH > &  aPathList)

Function UpdatePathList clears the current path list and substitutes the given path list, updating the path configuration file on success.

Definition at line 236 of file filename_resolver.cpp.

References addPath(), i, m_Paths, and writePathList().

Referenced by DIALOG_CONFIGURE_PATHS::TransferDataFromWindow().

237 {
238  wxUniChar envMarker( '$' );
239 
240  while( !m_Paths.empty() && envMarker != *m_Paths.back().m_alias.rbegin() )
241  m_Paths.pop_back();
242 
243  size_t nI = aPathList.size();
244 
245  for( size_t i = 0; i < nI; ++i )
246  addPath( aPathList[i] );
247 
248  return writePathList();
249 }
std::list< SEARCH_PATH > m_Paths
bool writePathList(void)
Function writePathList writes the current path list to a configuration file.
bool addPath(const SEARCH_PATH &aPath)
Function addPath checks that a path is valid and adds it to the search list.
size_t i
Definition: json11.cpp:597
bool FILENAME_RESOLVER::ValidateFileName ( const wxString &  aFileName,
bool &  hasAlias 
)

Function ValidateName returns true if the given path is a valid aliased relative path.

If the path contains an alias then hasAlias is set true.

Definition at line 972 of file filename_resolver.cpp.

Referenced by DIALOG_FOOTPRINT_FP_EDITOR::On3DModelCellChanged(), and DIALOG_FOOTPRINT_BOARD_EDITOR::On3DModelCellChanged().

973 {
974  // Rules:
975  // 1. The generic form of an aliased 3D relative path is:
976  // ALIAS:relative/path
977  // 2. ALIAS is a UTF string excluding wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" )
978  // 3. The relative path must be a valid relative path for the platform
979  hasAlias = false;
980 
981  if( aFileName.empty() )
982  return false;
983 
984  wxString filename = aFileName;
985  size_t pos0 = aFileName.find( ':' );
986 
987  // ensure that the file separators suit the current platform
988  #ifdef __WINDOWS__
989  filename.Replace( wxT( "/" ), wxT( "\\" ) );
990 
991  // if we see the :\ pattern then it must be a drive designator
992  if( pos0 != wxString::npos )
993  {
994  size_t pos1 = filename.find( wxT( ":\\" ) );
995 
996  if( pos1 != wxString::npos && ( pos1 != pos0 || pos1 != 1 ) )
997  return false;
998 
999  // if we have a drive designator then we have no alias
1000  if( pos1 != wxString::npos )
1001  pos0 = wxString::npos;
1002  }
1003  #else
1004  filename.Replace( wxT( "\\" ), wxT( "/" ) );
1005  #endif
1006 
1007  // names may not end with ':'
1008  if( pos0 == aFileName.length() -1 )
1009  return false;
1010 
1011  if( pos0 != wxString::npos )
1012  {
1013  // ensure the alias component is not empty
1014  if( pos0 == 0 )
1015  return false;
1016 
1017  wxString lpath = filename.substr( 0, pos0 );
1018 
1019  // check the alias for restricted characters
1020  if( wxString::npos != lpath.find_first_of( wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" ) ) )
1021  return false;
1022 
1023  hasAlias = true;
1024  }
1025 
1026  return true;
1027 }
bool FILENAME_RESOLVER::writePathList ( void  )
private

Function writePathList writes the current path list to a configuration file.

Returns
true if the path list was not empty and was successfully written to the configuration file

Definition at line 623 of file filename_resolver.cpp.

References CFGFILE_VERSION, m_ConfigDir, m_Paths, MASK_3D_RESOLVER, and RESOLVER_CONFIG.

Referenced by readPathList(), and UpdatePathList().

624 {
625  if( m_ConfigDir.empty() )
626  {
627  std::ostringstream ostr;
628  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
629  wxString errmsg = _( "3D configuration directory is unknown" );
630  ostr << " * " << errmsg.ToUTF8();
631  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
632  wxMessageBox( errmsg, _( "Write 3D search path list" ) );
633 
634  return false;
635  }
636 
637  // skip all ${ENV_VAR} alias names
638  std::list< SEARCH_PATH >::const_iterator sPL = m_Paths.begin();
639  std::list< SEARCH_PATH >::const_iterator ePL = m_Paths.end();
640 
641  while( sPL != ePL && ( sPL->m_alias.StartsWith( "${" ) || sPL->m_alias.StartsWith( "$(" ) ) )
642  ++sPL;
643 
644  wxFileName cfgpath( m_ConfigDir, RESOLVER_CONFIG );
645  wxString cfgname = cfgpath.GetFullPath();
646  std::ofstream cfgFile;
647 
648  cfgFile.open( cfgname.ToUTF8(), std::ios_base::trunc );
649 
650  if( !cfgFile.is_open() )
651  {
652  std::ostringstream ostr;
653  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
654  wxString errmsg = _( "Could not open configuration file" );
655  ostr << " * " << errmsg.ToUTF8() << " '" << cfgname.ToUTF8() << "'";
656  wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
657  wxMessageBox( errmsg, _( "Write 3D search path list" ) );
658 
659  return false;
660  }
661 
662  cfgFile << "#V" << CFGFILE_VERSION << "\n";
663  std::string tstr;
664 
665  while( sPL != ePL )
666  {
667  tstr = sPL->m_alias.ToUTF8();
668  cfgFile << "\"" << tstr.size() << ":" << tstr << "\",";
669  tstr = sPL->m_pathvar.ToUTF8();
670  cfgFile << "\"" << tstr.size() << ":" << tstr << "\",";
671  tstr = sPL->m_description.ToUTF8();
672  cfgFile << "\"" << tstr.size() << ":" << tstr << "\"\n";
673  ++sPL;
674  }
675 
676  bool bad = cfgFile.bad();
677  cfgFile.close();
678 
679  if( bad )
680  {
681  wxMessageBox( _( "Problems writing configuration file" ),
682  _( "Write 3D search path list" ) );
683 
684  return false;
685  }
686 
687  return true;
688 }
#define CFGFILE_VERSION
std::list< SEARCH_PATH > m_Paths
#define RESOLVER_CONFIG
#define MASK_3D_RESOLVER

Member Data Documentation

wxString FILENAME_RESOLVER::m_ConfigDir
private

Definition at line 54 of file filename_resolver.h.

Referenced by createPathList(), readPathList(), Set3DConfigDir(), and writePathList().

wxString FILENAME_RESOLVER::m_curProjDir
private

Definition at line 58 of file filename_resolver.h.

Referenced by createPathList(), GetProjectDir(), and SetProjectDir().

int FILENAME_RESOLVER::m_errflags
private

Definition at line 56 of file filename_resolver.h.

Referenced by FILENAME_RESOLVER(), and ResolvePath().

PGM_BASE* FILENAME_RESOLVER::m_pgm
private

Definition at line 57 of file filename_resolver.h.

Referenced by FILENAME_RESOLVER(), GetKicadPaths(), and SetProgramBase().


The documentation for this class was generated from the following files: