KiCad PCB EDA Suite
Loading...
Searching...
No Matches
filename_resolver.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2015-2020 Cirilo Bernardo <[email protected]>
5 * Copyright (C) 2015-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <fstream>
26#include <mutex>
27#include <sstream>
28
29#include <wx/log.h>
30#include <pgm_base.h>
31#include <trace_helpers.h>
32
33#include <common.h>
34#include <env_vars.h>
35#include <filename_resolver.h>
36#include <confirm.h>
37#include <wx_filename.h>
38
39// configuration file version
40#define CFGFILE_VERSION 1
41
42// flag bits used to track different one-off messages to users
43#define ERRFLG_ALIAS (1)
44#define ERRFLG_RELPATH (2)
45#define ERRFLG_ENVPATH (4)
46
47#define MASK_3D_RESOLVER "3D_RESOLVER"
48
49static std::mutex mutex_resolver;
50
51
53 m_pgm( nullptr ),
54 m_project( nullptr )
55{
56 m_errflags = 0;
57}
58
59
60bool FILENAME_RESOLVER::Set3DConfigDir( const wxString& aConfigDir )
61{
62 if( aConfigDir.empty() )
63 return false;
64
65 wxFileName cfgdir( ExpandEnvVarSubstitutions( aConfigDir, m_project ), "" );
66
67 cfgdir.Normalize( FN_NORMALIZE_FLAGS );
68
69 if( !cfgdir.DirExists() )
70 return false;
71
72 m_configDir = cfgdir.GetPath();
74
75 return true;
76}
77
78
79bool FILENAME_RESOLVER::SetProject( PROJECT* aProject, bool* flgChanged )
80{
81 m_project = aProject;
82
83 if( !aProject )
84 return false;
85
86 wxFileName projdir( ExpandEnvVarSubstitutions( aProject->GetProjectPath(), aProject ), "" );
87
88 projdir.Normalize( FN_NORMALIZE_FLAGS );
89
90 if( !projdir.DirExists() )
91 return false;
92
93 m_curProjDir = projdir.GetPath();
94
95 if( flgChanged )
96 *flgChanged = false;
97
98 if( m_paths.empty() )
99 {
100 SEARCH_PATH al;
101 al.m_Alias = wxS( "${KIPRJMOD}" );
102 al.m_Pathvar = wxS( "${KIPRJMOD}" );
104 m_paths.push_back( al );
105
106 if( flgChanged )
107 *flgChanged = true;
108 }
109 else
110 {
111 if( m_paths.front().m_Pathexp != m_curProjDir )
112 {
113 m_paths.front().m_Pathexp = m_curProjDir;
114
115 if( flgChanged )
116 *flgChanged = true;
117 }
118 else
119 {
120 return true;
121 }
122 }
123
124#ifdef DEBUG
125 {
126 std::ostringstream ostr;
127 ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
128 ostr << " * [INFO] changed project dir to ";
129 ostr << m_paths.front().m_Pathexp.ToUTF8();
130 wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
131 }
132#endif
133
134 return true;
135}
136
137
139{
140 return m_curProjDir;
141}
142
143
145{
146 m_pgm = aBase;
147
148 if( !m_pgm || m_paths.empty() )
149 return;
150
151 // recreate the path list
152 m_paths.clear();
154}
155
156
158{
159 if( !m_paths.empty() )
160 return true;
161
162 // add an entry for the default search path; at this point
163 // we cannot set a sensible default so we use an empty string.
164 // the user may change this later with a call to SetProjectDir()
165
166 SEARCH_PATH lpath;
167 lpath.m_Alias = wxS( "${KIPRJMOD}" );
168 lpath.m_Pathvar = wxS( "${KIPRJMOD}" );
169 lpath.m_Pathexp = m_curProjDir;
170 m_paths.push_back( lpath );
171 wxFileName fndummy;
172 wxUniChar psep = fndummy.GetPathSeparator();
173 std::list< wxString > epaths;
174
175 if( GetKicadPaths( epaths ) )
176 {
177 for( const wxString& currPath : epaths )
178 {
179 wxString currPathVarFormat = currPath;
180 currPathVarFormat.Prepend( wxS( "${" ) );
181 currPathVarFormat.Append( wxS( "}" ) );
182
183 wxString pathVal = ExpandEnvVarSubstitutions( currPathVarFormat, m_project );
184
185 if( pathVal.empty() )
186 {
187 lpath.m_Pathexp.clear();
188 }
189 else
190 {
191 fndummy.Assign( pathVal, "" );
192 fndummy.Normalize( FN_NORMALIZE_FLAGS );
193 lpath.m_Pathexp = fndummy.GetFullPath();
194 }
195
196 lpath.m_Alias = currPath;
197 lpath.m_Pathvar = currPath;
198
199 if( !lpath.m_Pathexp.empty() && psep == *lpath.m_Pathexp.rbegin() )
200 lpath.m_Pathexp.erase( --lpath.m_Pathexp.end() );
201
202 // we add it first with the alias set to the non-variable format
203 m_paths.push_back( lpath );
204
205 // now add it with the "new variable format ${VAR}"
206 lpath.m_Alias = currPathVarFormat;
207 m_paths.push_back( lpath );
208 }
209 }
210
211 if( m_paths.empty() )
212 return false;
213
214#ifdef DEBUG
215 wxLogTrace( MASK_3D_RESOLVER, wxS( " * [3D model] search paths:\n" ) );
216 std::list< SEARCH_PATH >::const_iterator sPL = m_paths.begin();
217
218 while( sPL != m_paths.end() )
219 {
220 wxLogTrace( MASK_3D_RESOLVER, wxS( " + %s : '%s'\n" ), (*sPL).m_Alias.GetData(),
221 (*sPL).m_Pathexp.GetData() );
222 ++sPL;
223 }
224#endif
225
226 return true;
227}
228
229
230bool FILENAME_RESOLVER::UpdatePathList( const std::vector< SEARCH_PATH >& aPathList )
231{
232 wxUniChar envMarker( '$' );
233
234 while( !m_paths.empty() && envMarker != *m_paths.back().m_Alias.rbegin() )
235 m_paths.pop_back();
236
237 for( const SEARCH_PATH& path : aPathList )
238 addPath( path );
239
240 return true;
241}
242
243
244wxString FILENAME_RESOLVER::ResolvePath( const wxString& aFileName, const wxString& aWorkingPath )
245{
246 std::lock_guard<std::mutex> lock( mutex_resolver );
247
248 if( aFileName.empty() )
249 return wxEmptyString;
250
251 if( m_paths.empty() )
253
254 // first attempt to use the name as specified:
255 wxString tname = aFileName;
256
257 // Note: variable expansion must preferably be performed via a threadsafe wrapper for the
258 // getenv() system call. If we allow the wxFileName::Normalize() routine to perform expansion
259 // then we will have a race condition since wxWidgets does not assure a threadsafe wrapper
260 // for getenv().
261 tname = ExpandEnvVarSubstitutions( tname, m_project );
262
263 wxFileName tmpFN( tname );
264
265 // this case covers full paths, leading expanded vars, and paths relative to the current
266 // working directory (which is not necessarily the current project directory)
267 if( tmpFN.FileExists() )
268 {
269 tmpFN.Normalize( FN_NORMALIZE_FLAGS );
270 tname = tmpFN.GetFullPath();
271
272 // special case: if a path begins with ${ENV_VAR} but is not in the resolver's path list
273 // then add it.
274 if( aFileName.StartsWith( wxS( "${" ) ) || aFileName.StartsWith( wxS( "$(" ) ) )
275 checkEnvVarPath( aFileName );
276
277 return tname;
278 }
279
280 // if a path begins with ${ENV_VAR}/$(ENV_VAR) and is not resolved then the file either does
281 // not exist or the ENV_VAR is not defined
282 if( aFileName.StartsWith( "${" ) || aFileName.StartsWith( "$(" ) )
283 {
284 if( !( m_errflags & ERRFLG_ENVPATH ) )
285 {
287 wxString errmsg = "[3D File Resolver] No such path; ensure the environment var is defined";
288 errmsg.append( "\n" );
289 errmsg.append( tname );
290 errmsg.append( "\n" );
291 wxLogTrace( tracePathsAndFiles, errmsg );
292 }
293
294 return wxEmptyString;
295 }
296
297 // at this point aFileName is:
298 // a. an aliased shortened name or
299 // b. cannot be determined
300
301 // check the path relative to the current project directory;
302 // NB: this is not necessarily the same as the current working directory, which has already
303 // been checked. This case accounts for partial paths which do not contain ${KIPRJMOD}.
304 // This check is performed before checking the path relative to ${KICAD7_3DMODEL_DIR} so that
305 // users can potentially override a model within ${KICAD7_3DMODEL_DIR}.
306 if( !m_paths.begin()->m_Pathexp.empty() && !tname.StartsWith( ":" ) )
307 {
308 tmpFN.Assign( m_paths.begin()->m_Pathexp, "" );
309 wxString fullPath = tmpFN.GetPathWithSep() + tname;
310
311 fullPath = ExpandEnvVarSubstitutions( fullPath, m_project );
312
313 if( wxFileName::FileExists( fullPath ) )
314 {
315 tmpFN.Assign( fullPath );
316 tmpFN.Normalize( FN_NORMALIZE_FLAGS );
317 tname = tmpFN.GetFullPath();
318 return tname;
319 }
320
321 }
322
323 // check path relative to search path
324 if( !aWorkingPath.IsEmpty() && !tname.StartsWith( ":" ) )
325 {
326 wxString tmp = aWorkingPath;
327 tmp.Append( tmpFN.GetPathSeparator() );
328 tmp.Append( tname );
329 tmpFN.Assign( tmp );
330
331 if( tmpFN.MakeAbsolute() && tmpFN.FileExists() )
332 {
333 tname = tmpFN.GetFullPath();
334 return tname;
335 }
336 }
337
338 // check the partial path relative to ${KICAD7_3DMODEL_DIR} (legacy behavior)
339 if( !tname.StartsWith( wxS( ":" ) ) )
340 {
341 wxFileName fpath;
342 wxString fullPath( wxString::Format( wxS( "${%s}" ),
343 ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ) ) );
344 fullPath.Append( fpath.GetPathSeparator() );
345 fullPath.Append( tname );
346 fullPath = ExpandEnvVarSubstitutions( fullPath, m_project );
347 fpath.Assign( fullPath );
348
349 if( fpath.Normalize( FN_NORMALIZE_FLAGS ) && fpath.FileExists() )
350 {
351 tname = fpath.GetFullPath();
352 return tname;
353 }
354
355 }
356
357 // at this point the filename must contain an alias or else it is invalid
358 wxString alias; // the alias portion of the short filename
359 wxString relpath; // the path relative to the alias
360
361 if( !SplitAlias( tname, alias, relpath ) )
362 {
363 if( !( m_errflags & ERRFLG_RELPATH ) )
364 {
365 // this can happen if the file was intended to be relative to ${KICAD7_3DMODEL_DIR}
366 // but ${KICAD7_3DMODEL_DIR} is not set or is incorrect.
368 wxString errmsg = "[3D File Resolver] No such path";
369 errmsg.append( wxS( "\n" ) );
370 errmsg.append( tname );
371 errmsg.append( wxS( "\n" ) );
372 wxLogTrace( tracePathsAndFiles, errmsg );
373 }
374
375 return wxEmptyString;
376 }
377
378 for( const SEARCH_PATH& path : m_paths )
379 {
380 // ${ENV_VAR} paths have already been checked; skip them
381 if( path.m_Alias.StartsWith( wxS( "${" ) ) || path.m_Alias.StartsWith( wxS( "$(" ) ) )
382 continue;
383
384 if( path.m_Alias == alias && !path.m_Pathexp.empty() )
385 {
386 wxFileName fpath( wxFileName::DirName( path.m_Pathexp ) );
387 wxString fullPath = fpath.GetPathWithSep() + relpath;
388
389 fullPath = ExpandEnvVarSubstitutions( fullPath, m_project );
390
391 if( wxFileName::FileExists( fullPath ) )
392 {
393 tname = fullPath;
394
395 wxFileName tmp( fullPath );
396
397 if( tmp.Normalize( FN_NORMALIZE_FLAGS ) )
398 tname = tmp.GetFullPath();
399
400 return tname;
401 }
402 }
403 }
404
405 if( !( m_errflags & ERRFLG_ALIAS ) )
406 {
408 wxString errmsg = "[3D File Resolver] No such path; ensure the path alias is defined";
409 errmsg.append( "\n" );
410 errmsg.append( tname.substr( 1 ) );
411 errmsg.append( "\n" );
412 wxLogTrace( tracePathsAndFiles, errmsg );
413 }
414
415 return wxEmptyString;
416}
417
418
420{
421 if( aPath.m_Alias.empty() || aPath.m_Pathvar.empty() )
422 return false;
423
424 std::lock_guard<std::mutex> lock( mutex_resolver );
425
426 SEARCH_PATH tpath = aPath;
427
428 #ifdef _WIN32
429 while( tpath.m_Pathvar.EndsWith( wxT( "\\" ) ) )
430 tpath.m_Pathvar.erase( tpath.m_Pathvar.length() - 1 );
431 #else
432 while( tpath.m_Pathvar.EndsWith( wxT( "/" ) ) && tpath.m_Pathvar.length() > 1 )
433 tpath.m_Pathvar.erase( tpath.m_Pathvar.length() - 1 );
434 #endif
435
436 wxFileName path( ExpandEnvVarSubstitutions( tpath.m_Pathvar, m_project ), "" );
437
438 path.Normalize( FN_NORMALIZE_FLAGS );
439
440 if( !path.DirExists() )
441 {
442 wxString versionedPath = wxString::Format( wxS( "${%s}" ),
443 ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ) );
444
445 if( aPath.m_Pathvar == versionedPath
446 || aPath.m_Pathvar == wxS( "${KIPRJMOD}" ) || aPath.m_Pathvar == wxS( "$(KIPRJMOD)" )
447 || aPath.m_Pathvar == wxS( "${KISYS3DMOD}" ) || aPath.m_Pathvar == wxS( "$(KISYS3DMOD)" ) )
448 {
449 // suppress the message if the missing pathvar is a system variable
450 }
451 else
452 {
453 wxString msg = _( "The given path does not exist" );
454 msg.append( wxT( "\n" ) );
455 msg.append( tpath.m_Pathvar );
456 DisplayErrorMessage( nullptr, msg );
457 }
458
459 tpath.m_Pathexp.clear();
460 }
461 else
462 {
463 tpath.m_Pathexp = path.GetFullPath();
464
465#ifdef _WIN32
466 while( tpath.m_Pathexp.EndsWith( wxT( "\\" ) ) )
467 tpath.m_Pathexp.erase( tpath.m_Pathexp.length() - 1 );
468#else
469 while( tpath.m_Pathexp.EndsWith( wxT( "/" ) ) && tpath.m_Pathexp.length() > 1 )
470 tpath.m_Pathexp.erase( tpath.m_Pathexp.length() - 1 );
471#endif
472 }
473
474 std::list< SEARCH_PATH >::iterator sPL = m_paths.begin();
475 std::list< SEARCH_PATH >::iterator ePL = m_paths.end();
476
477 while( sPL != ePL )
478 {
479 if( tpath.m_Alias == sPL->m_Alias )
480 {
481 wxString msg = _( "Alias: " );
482 msg.append( tpath.m_Alias );
483 msg.append( wxT( "\n" ) );
484 msg.append( _( "This path:" ) + wxS( " " ) );
485 msg.append( tpath.m_Pathvar );
486 msg.append( wxT( "\n" ) );
487 msg.append( _( "Existing path:" ) + wxS( " " ) );
488 msg.append( sPL->m_Pathvar );
489 DisplayErrorMessage( nullptr, _( "Bad alias (duplicate name)" ), msg );
490 return false;
491 }
492
493 ++sPL;
494 }
495
496 m_paths.push_back( tpath );
497 return true;
498}
499
500
501void FILENAME_RESOLVER::checkEnvVarPath( const wxString& aPath )
502{
503 bool useParen = false;
504
505 if( aPath.StartsWith( wxS( "$(" ) ) )
506 useParen = true;
507 else if( !aPath.StartsWith( wxS( "${" ) ) )
508 return;
509
510 size_t pEnd;
511
512 if( useParen )
513 pEnd = aPath.find( wxS( ")" ) );
514 else
515 pEnd = aPath.find( wxS( "}" ) );
516
517 if( pEnd == wxString::npos )
518 return;
519
520 wxString envar = aPath.substr( 0, pEnd + 1 );
521
522 // check if the alias exists; if not then add it to the end of the
523 // env var section of the path list
524 auto sPL = m_paths.begin();
525 auto ePL = m_paths.end();
526
527 while( sPL != ePL )
528 {
529 if( sPL->m_Alias == envar )
530 return;
531
532 if( !sPL->m_Alias.StartsWith( wxS( "${" ) ) )
533 break;
534
535 ++sPL;
536 }
537
538 SEARCH_PATH lpath;
539 lpath.m_Alias = envar;
540 lpath.m_Pathvar = lpath.m_Alias;
541 wxFileName tmpFN( ExpandEnvVarSubstitutions( lpath.m_Alias, m_project ), "" );
542
543 wxUniChar psep = tmpFN.GetPathSeparator();
544 tmpFN.Normalize( FN_NORMALIZE_FLAGS );
545
546 if( !tmpFN.DirExists() )
547 return;
548
549 lpath.m_Pathexp = tmpFN.GetFullPath();
550
551 if( !lpath.m_Pathexp.empty() && psep == *lpath.m_Pathexp.rbegin() )
552 lpath.m_Pathexp.erase( --lpath.m_Pathexp.end() );
553
554 if( lpath.m_Pathexp.empty() )
555 return;
556
557 m_paths.insert( sPL, lpath );
558}
559
560
561wxString FILENAME_RESOLVER::ShortenPath( const wxString& aFullPathName )
562{
563 wxString fname = aFullPathName;
564
565 if( m_paths.empty() )
567
568 std::lock_guard<std::mutex> lock( mutex_resolver );
569
570 std::list< SEARCH_PATH >::const_iterator sL = m_paths.begin();
571 size_t idx;
572
573 while( sL != m_paths.end() )
574 {
575 // undefined paths do not participate in the
576 // file name shortening procedure
577 if( sL->m_Pathexp.empty() )
578 {
579 ++sL;
580 continue;
581 }
582
583 wxFileName fpath;
584
585 // in the case of aliases, ensure that we use the most recent definition
586 if( sL->m_Alias.StartsWith( wxS( "${" ) ) || sL->m_Alias.StartsWith( wxS( "$(" ) ) )
587 {
588 wxString tpath = ExpandEnvVarSubstitutions( sL->m_Alias, m_project );
589
590 if( tpath.empty() )
591 {
592 ++sL;
593 continue;
594 }
595
596 fpath.Assign( tpath, wxT( "" ) );
597 }
598 else
599 {
600 fpath.Assign( sL->m_Pathexp, wxT( "" ) );
601 }
602
603 wxString fps = fpath.GetPathWithSep();
604 wxString tname;
605
606 idx = fname.find( fps );
607
608 if( idx == 0 )
609 {
610 fname = fname.substr( fps.size() );
611
612 #ifdef _WIN32
613 // ensure only the '/' separator is used in the internal name
614 fname.Replace( wxT( "\\" ), wxT( "/" ) );
615 #endif
616
617 if( sL->m_Alias.StartsWith( wxS( "${" ) ) || sL->m_Alias.StartsWith( wxS( "$(" ) ) )
618 {
619 // old style ENV_VAR
620 tname = sL->m_Alias;
621 tname.Append( wxS( "/" ) );
622 tname.append( fname );
623 }
624 else
625 {
626 // new style alias
627 tname = "${";
628 tname.append( sL->m_Alias );
629 tname.append( wxS( "}/" ) );
630 tname.append( fname );
631 }
632
633 return tname;
634 }
635
636 ++sL;
637 }
638
639#ifdef _WIN32
640 // it is strange to convert an MSWin full path to use the
641 // UNIX separator but this is done for consistency and can
642 // be helpful even when transferring project files from
643 // MSWin to *NIX.
644 fname.Replace( wxT( "\\" ), wxT( "/" ) );
645#endif
646
647 return fname;
648}
649
650
651
652const std::list< SEARCH_PATH >* FILENAME_RESOLVER::GetPaths() const
653{
654 return &m_paths;
655}
656
657
658bool FILENAME_RESOLVER::SplitAlias( const wxString& aFileName,
659 wxString& anAlias, wxString& aRelPath ) const
660{
661 anAlias.clear();
662 aRelPath.clear();
663
664 size_t searchStart = 0;
665
666 if( aFileName.StartsWith( wxT( ":" ) ) )
667 searchStart = 1;
668
669 size_t tagpos = aFileName.find( wxT( ":" ), searchStart );
670
671 if( tagpos == wxString::npos || tagpos == searchStart )
672 return false;
673
674 if( tagpos + 1 >= aFileName.length() )
675 return false;
676
677 anAlias = aFileName.substr( searchStart, tagpos - searchStart );
678 aRelPath = aFileName.substr( tagpos + 1 );
679
680 return true;
681}
682
683
684bool FILENAME_RESOLVER::ValidateFileName( const wxString& aFileName, bool& hasAlias ) const
685{
686 // Rules:
687 // 1. The generic form of an aliased 3D relative path is:
688 // ALIAS:relative/path
689 // 2. ALIAS is a UTF string excluding wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" )
690 // 3. The relative path must be a valid relative path for the platform
691 hasAlias = false;
692
693 if( aFileName.empty() )
694 return false;
695
696 wxString filename = aFileName;
697 wxString lpath;
698 size_t aliasStart = aFileName.StartsWith( ':' ) ? 1 : 0;
699 size_t aliasEnd = aFileName.find( ':', aliasStart );
700
701 // ensure that the file separators suit the current platform
702#ifdef __WINDOWS__
703 filename.Replace( wxT( "/" ), wxT( "\\" ) );
704
705 // if we see the :\ pattern then it must be a drive designator
706 if( aliasEnd != wxString::npos )
707 {
708 size_t pos1 = filename.find( wxT( ":\\" ) );
709
710 if( pos1 != wxString::npos && ( pos1 != aliasEnd || pos1 != 1 ) )
711 return false;
712
713 // if we have a drive designator then we have no alias
714 if( pos1 != wxString::npos )
715 aliasEnd = wxString::npos;
716 }
717#else
718 filename.Replace( wxT( "\\" ), wxT( "/" ) );
719#endif
720
721 // names may not end with ':'
722 if( aliasEnd == aFileName.length() -1 )
723 return false;
724
725 if( aliasEnd != wxString::npos )
726 {
727 // ensure the alias component is not empty
728 if( aliasEnd == aliasStart )
729 return false;
730
731 lpath = filename.substr( aliasStart, aliasEnd );
732
733 // check the alias for restricted characters
734 if( wxString::npos != lpath.find_first_of( wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" ) ) )
735 return false;
736
737 hasAlias = true;
738 lpath = aFileName.substr( aliasEnd + 1 );
739 }
740 else
741 {
742 lpath = aFileName;
743
744 // in the case of ${ENV_VAR}|$(ENV_VAR)/path, strip the
745 // environment string before testing
746 aliasEnd = wxString::npos;
747
748 if( aFileName.StartsWith( wxS( "${" ) ) )
749 aliasEnd = aFileName.find( '}' );
750 else if( aFileName.StartsWith( wxS( "$(" ) ) )
751 aliasEnd = aFileName.find( ')' );
752
753 if( aliasEnd != wxString::npos )
754 lpath = aFileName.substr( aliasEnd + 1 );
755
756 }
757
758 // Test for forbidden chars in filenames. Should be wxFileName::GetForbiddenChars()
759 // On MSW, the list returned by wxFileName::GetForbiddenChars() contains separators
760 // '\'and '/' used here because lpath can be a full path.
761 // So remove separators
762 wxString lpath_no_sep = lpath;
763#ifdef __WINDOWS__
764 lpath_no_sep.Replace( "/", " " );
765 lpath_no_sep.Replace( "\\", " " );
766
767 // A disk identifier is allowed, and therefore remove its separator
768 if( lpath_no_sep.Length() > 1 && lpath_no_sep[1] == ':' )
769 lpath_no_sep[1] = ' ';
770#endif
771
772 if( wxString::npos != lpath_no_sep.find_first_of( wxFileName::GetForbiddenChars() ) )
773 return false;
774
775 return true;
776}
777
778
779bool FILENAME_RESOLVER::GetKicadPaths( std::list< wxString >& paths ) const
780{
781 paths.clear();
782
783 if( !m_pgm )
784 return false;
785
786 bool hasKisys3D = false;
787
788
789 // iterate over the list of internally defined ENV VARs
790 // and add them to the paths list
793
794 while( mS != mE )
795 {
796 // filter out URLs, template directories, and known system paths
797 if( mS->first == wxS( "KICAD_PTEMPLATES" )
798 || mS->first.Matches( wxS( "KICAD*_FOOTPRINT_DIR") ) )
799 {
800 ++mS;
801 continue;
802 }
803
804 if( wxString::npos != mS->second.GetValue().find( wxS( "://" ) ) )
805 {
806 ++mS;
807 continue;
808 }
809
810 //also add the path without the ${} to act as legacy alias support for older files
811 paths.push_back( mS->first );
812
813 if( mS->first.Matches( wxS("KICAD*_3DMODEL_DIR") ) )
814 hasKisys3D = true;
815
816 ++mS;
817 }
818
819 if( !hasKisys3D )
820 paths.emplace_back( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ) );
821
822 return true;
823}
bool ValidateFileName(const wxString &aFileName, bool &hasAlias) const
Returns 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...
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
bool SetProject(PROJECT *aProject, bool *flgChanged=nullptr)
Set the current KiCad project directory as the first entry in the model path list.
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...
const std::list< SEARCH_PATH > * GetPaths() const
Return a pointer to the internal path list; the items in:load.
wxString ResolvePath(const wxString &aFileName, const wxString &aWorkingPath)
Determines the full path of the given file name.
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.
Definition: pgm_base.h:102
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition: pgm_base.cpp:923
Container for project specific data.
Definition: project.h:62
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:135
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:334
The common library.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:305
This file is part of the common library.
#define _(s)
Functions related to environment variables, including help functions.
#define ERRFLG_RELPATH
static std::mutex mutex_resolver
#define ERRFLG_ENVPATH
#define MASK_3D_RESOLVER
#define ERRFLG_ALIAS
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)
Constructs a versioned environment variable based on this KiCad major version.
Definition: env_vars.cpp:74
see class PGM_BASE
wxString m_Pathvar
wxString m_Pathexp
wxString m_Alias
wxLogTrace helper definitions.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition: wx_filename.h:39