40#include <wx/stdpaths.h>
56 Bracket_Windows =
'%',
63 std::function<bool( wxString* )> projectResolver = [&]( wxString* token ) ->
bool
72wxString
ExpandTextVars(
const wxString& aSource,
const std::function<
bool( wxString* )>* aResolver,
int aFlags,
76 size_t sourceLen = aSource.length();
78 newbuf.Alloc( sourceLen );
83 for(
size_t i = 0; i < sourceLen; ++i )
87 if( i + 14 <= sourceLen && aSource.Mid( i, 14 ) == wxT(
"<<<ESC_DOLLAR:" ) )
90 newbuf.append( wxT(
"<<<ESC_DOLLAR:" ) );
95 while( i < sourceLen && braceCount > 0 )
97 if( aSource[i] ==
'{' )
99 else if( aSource[i] ==
'}' )
102 newbuf.append( aSource[i] );
108 else if( i + 10 <= sourceLen && aSource.Mid( i, 10 ) == wxT(
"<<<ESC_AT:" ) )
111 newbuf.append( wxT(
"<<<ESC_AT:" ) );
116 while( i < sourceLen && braceCount > 0 )
118 if( aSource[i] ==
'{' )
120 else if( aSource[i] ==
'}' )
123 newbuf.append( aSource[i] );
133 if( aSource[i] ==
'\\' && i + 1 < sourceLen )
135 if( ( aSource[i + 1] ==
'$' || aSource[i + 1] ==
'@' ) && i + 2 < sourceLen && aSource[i + 2] ==
'{' )
139 if( aSource[i + 1] ==
'$' )
140 newbuf.append( wxT(
"<<<ESC_DOLLAR:" ) );
142 newbuf.append( wxT(
"<<<ESC_AT:" ) );
147 for( i = i + 1; i < sourceLen && braceDepth > 0; ++i )
149 if( aSource[i] ==
'{' )
151 else if( aSource[i] ==
'}' )
154 newbuf.append( aSource[i] );
161 if( ( aSource[i] ==
'$' || aSource[i] ==
'@' ) && i + 1 < sourceLen && aSource[i + 1] ==
'{' )
163 bool isMathExpr = ( aSource[i] ==
'@' );
167 for( i = i + 2; i < sourceLen; ++i )
171 if( i + 14 <= sourceLen && aSource.Mid( i, 14 ) == wxT(
"<<<ESC_DOLLAR:" ) )
173 token.append( wxT(
"<<<ESC_DOLLAR:" ) );
177 int markerBraceCount = 1;
179 while( i < sourceLen && markerBraceCount > 0 )
181 if( aSource[i] ==
'{' )
183 else if( aSource[i] ==
'}' )
186 token.append( aSource[i] );
193 else if( i + 10 <= sourceLen && aSource.Mid( i, 10 ) == wxT(
"<<<ESC_AT:" ) )
195 token.append( wxT(
"<<<ESC_AT:" ) );
199 int markerBraceCount = 1;
201 while( i < sourceLen && markerBraceCount > 0 )
203 if( aSource[i] ==
'{' )
205 else if( aSource[i] ==
'}' )
208 token.append( aSource[i] );
216 if( aSource[i] ==
'{' )
219 token.append( aSource[i] );
221 else if( aSource[i] ==
'}' )
225 if( braceDepth == 0 )
228 token.append( aSource[i] );
232 token.append( aSource[i] );
236 if( token.IsEmpty() )
243 if( ( token.Contains( wxT(
"${" ) ) || token.Contains( wxT(
"@{" ) ) ) && aDepth < maxDepth )
250 newbuf.append( wxT(
"@{" ) + token + wxT(
"}" ) );
256 if( ( token.Contains( wxT(
"${" ) ) || token.Contains( wxT(
"@{" ) ) ) && aDepth < maxDepth )
261 if( token.Contains( wxT(
"@{" ) ) )
264 token = evaluator.
Evaluate( token );
269 && ( token.StartsWith( wxS(
"ERC_WARNING" ) ) || token.StartsWith( wxS(
"ERC_ERROR" ) )
270 || token.StartsWith( wxS(
"DRC_WARNING" ) ) || token.StartsWith( wxS(
"DRC_ERROR" ) ) ) )
274 else if( aResolver && ( *aResolver )( &token ) )
276 newbuf.append( token );
281 newbuf.append(
"${" + token +
"}" );
287 newbuf.append( aSource[i] );
295wxString
ResolveTextVars(
const wxString& aSource,
const std::function<
bool( wxString* )>* aResolver,
int& aDepth )
299 wxString
text = aSource;
304 while( (
text.Contains( wxT(
"${" ) ) ||
text.Contains( wxT(
"@{" ) ) ) && ++aDepth <= maxDepth )
309 if(
text.Contains( wxT(
"${" ) ) ||
text.Contains( wxT(
"@{" ) ) )
314 if(
text.Contains( wxT(
"@{" ) ) )
324 std::function<bool( wxString* )> tokenExtractor = [&]( wxString* token ) ->
bool
336 static wxRegEx expr( wxS(
"^\\$\\{\\w*\\}$" ) );
337 return expr.Matches( aSource );
344 return wxT(
"<i>" ) +
_(
"unannotated footprint" ) + wxT(
" </i>" );
362 size_t strlen = str.length();
365 strResult.Alloc( strlen );
367 auto getVersionedEnvVar = [](
const wxString& aMatch, wxString& aResult ) ->
bool
371 if( var.Matches( aMatch ) )
386 for(
size_t n = 0; n < strlen; n++ )
388 wxUniChar str_n = str[n];
390 switch( str_n.GetValue() )
399 if( str_n == wxT(
'%' ) )
401 bracket = Bracket_Windows;
405 if( n == strlen - 1 )
411 switch( str[n + 1].GetValue() )
432 wxUniChar str_m = str[m];
434 while( wxIsalnum( str_m ) || str_m == wxT(
'_' ) || str_m == wxT(
':' ) )
445 wxString strVarName( str.c_str() + n + 1, m - n - 1 );
449 bool expanded =
false;
450 wxString tmp = strVarName;
457 else if( wxGetEnv( strVarName, &tmp ) )
466 else if( strVarName.Contains(
"KISYS3DMOD" ) || strVarName.Matches(
"KICAD*_3DMODEL_DIR" ) )
468 if( getVersionedEnvVar(
"KICAD*_3DMODEL_DIR", strResult ) )
471 else if( strVarName.Matches(
"KICAD*_SYMBOL_DIR" ) )
473 if( getVersionedEnvVar(
"KICAD*_SYMBOL_DIR", strResult ) )
476 else if( strVarName.Matches(
"KICAD*_FOOTPRINT_DIR" ) )
478 if( getVersionedEnvVar(
"KICAD*_FOOTPRINT_DIR", strResult ) )
481 else if( strVarName.Matches(
"KICAD*_3RD_PARTY" ) )
483 if( getVersionedEnvVar(
"KICAD*_3RD_PARTY", strResult ) )
490 if( bracket != Bracket_Windows )
493 strResult << str[n - 1];
495 strResult << str_n << strVarName;
501 if( m == strlen || str_m != (wxChar) bracket )
510 wxLogWarning(
_(
"Environment variables expansion failed: missing '%c' "
511 "at position %u in '%s'." ),
512 (
char) bracket, (
unsigned int) ( m + 1 ), str.c_str() );
519 strResult << (wxChar) bracket;
532 if( n < strlen - 1 && ( str[n + 1] == wxT(
'%' ) || str[n + 1] == wxT(
'$' ) ) )
542 default: strResult += str_n;
546 std::set<wxString> loop_check;
547 auto first_pos = strResult.find_first_of( wxS(
"{(%" ) );
548 auto last_pos = strResult.find_last_of( wxS(
"})%" ) );
550 if( first_pos != strResult.npos && last_pos != strResult.npos && first_pos != last_pos )
561 static std::mutex getenv_mutex;
563 std::lock_guard<std::mutex> lock( getenv_mutex );
581 wxString baseFilePath = wxFileName( aBaseFilename ).GetPath();
585 if( !aTargetFullFileName->MakeAbsolute( baseFilePath ) )
589 msg.Printf(
_(
"Cannot make path '%s' absolute with respect to '%s'." ), aTargetFullFileName->GetPath(),
598 wxString outputPath( aTargetFullFileName->GetPath() );
600 if( !wxFileName::DirExists( outputPath ) )
603 if( wxFileName::Mkdir( outputPath, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
607 msg.Printf(
_(
"Output directory '%s' created." ), outputPath );
616 msg.Printf(
_(
"Cannot create output directory '%s'." ), outputPath );
630 wxString newFilename( aFilename );
635 if( newFilename.Lower().AfterLast(
'.' ) != aExtension )
637 if( !newFilename.EndsWith(
'.' ) )
638 newFilename.Append(
'.' );
640 newFilename.Append( aExtension );
651 for(
const std::string& ext : aExts )
653 if( !joined.empty() )
654 joined << wxS(
", " );
656 joined << wxS(
"*." ) << ext;
685 const char *m = pat, *n =
text, *ma =
nullptr, *na =
nullptr;
686 int just = 0, acount = 0, count = 0;
688 if( dot_special && ( *n ==
'.' ) )
785#if wxUSE_DATETIME && defined( __WIN32__ ) && !defined( __WXMICROWIN__ )
791static wxInt64 EPOCH_OFFSET_IN_MSEC = wxLL( 11644473600000 );
794static void ConvertFileTimeToWx( wxDateTime* dt,
const FILETIME& ft )
796 wxLongLong t( ft.dwHighDateTime, ft.dwLowDateTime );
798 t -= EPOCH_OFFSET_IN_MSEC;
800 *dt = wxDateTime( t );
814long long TimestampDir(
const wxString& aDirPath,
const wxString& aFilespec )
816 long long timestamp = 0;
818#if defined( __WIN32__ )
823 std::wstring filespec( aDirPath.t_str() );
825 filespec += aFilespec.t_str();
827 WIN32_FIND_DATA findData;
828 wxDateTime lastModDate;
830 HANDLE fileHandle = ::FindFirstFile( filespec.data(), &findData );
832 if( fileHandle != INVALID_HANDLE_VALUE )
836 ConvertFileTimeToWx( &lastModDate, findData.ftLastWriteTime );
837 timestamp += lastModDate.GetValue().GetValue();
840 timestamp += findData.nFileSizeLow;
841 }
while( FindNextFile( fileHandle, &findData ) != 0 );
844 FindClose( fileHandle );
848 std::string filespec( aFilespec.fn_str() );
849 std::string dir_path( aDirPath.fn_str() );
851 DIR* dir = opendir( dir_path.c_str() );
855 for( dirent* dir_entry = readdir( dir ); dir_entry; dir_entry = readdir( dir ) )
857 if( !
matchWild( filespec.c_str(), dir_entry->d_name,
true ) )
860 std::string entry_path = dir_path +
'/' + dir_entry->d_name;
861 struct stat entry_stat;
863 if( wxCRT_Lstat( entry_path.c_str(), &entry_stat ) == 0 )
866 if( S_ISLNK( entry_stat.st_mode ) )
868 char buffer[PATH_MAX + 1];
869 ssize_t pathLen = readlink( entry_path.c_str(), buffer, PATH_MAX );
873 struct stat linked_stat;
874 buffer[pathLen] =
'\0';
875 entry_path = dir_path + buffer;
877 if( wxCRT_Lstat( entry_path.c_str(), &linked_stat ) == 0 )
879 entry_stat = linked_stat;
889 if( S_ISREG( entry_stat.st_mode ) )
891 timestamp += entry_stat.st_mtime * 1000;
894 timestamp += entry_stat.st_size;
900 timestamp += (signed) std::hash<std::string>{}( std::string( dir_entry->d_name ) );
917 wxMessageDialog dialog(
nullptr,
918 _(
"This operating system is not supported "
919 "by KiCad and its dependencies." ),
920 _(
"Unsupported Operating System" ), wxOK | wxICON_EXCLAMATION );
922 dialog.SetExtendedMessage(
_(
"Any issues with KiCad on this system cannot "
923 "be reported to the official bugtracker." ) );
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
High-level wrapper for evaluating mathematical and string expressions in wxString format.
wxString Evaluate(const wxString &aInput)
Main evaluation function - processes input string and evaluates all} expressions.
Container for project specific data.
virtual bool TextVarResolver(wxString *aToken) const
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
wxString JoinExtensions(const std::vector< std::string > &aExts)
Join a list of file extensions for use in a file dialog.
wxString GetGeneratedFieldDisplayName(const wxString &aSource)
Returns any variables unexpanded, e.g.
const wxString ResolveUriByEnvVars(const wxString &aUri, const PROJECT *aProject)
Replace any environment and/or text variables in URIs.
wxString EnsureFileExtension(const wxString &aFilename, const wxString &aExtension)
It's annoying to throw up nag dialogs when the extension isn't right.
bool WarnUserIfOperatingSystemUnsupported()
Checks if the operating system is explicitly unsupported and displays a disclaimer message box.
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
bool matchWild(const char *pat, const char *text, bool dot_special)
Performance enhancements to file and directory operations.
bool EnsureFileDirectoryExists(wxFileName *aTargetFullFileName, const wxString &aBaseFilename, REPORTER *aReporter)
Make aTargetFullFileName absolute and create the path of this file if it doesn't yet exist.
wxString KIwxExpandEnvVars(const wxString &str, const PROJECT *aProject, std::set< wxString > *aSet=nullptr)
bool IsGeneratedField(const wxString &aSource)
Returns true if the string is generated, e.g contains a single text var reference.
wxString DescribeRef(const wxString &aRef)
Returns a user-visible HTML string describing a footprint reference designator.
wxString ResolveTextVars(const wxString &aSource, const std::function< bool(wxString *)> *aResolver, int &aDepth)
Multi-pass text variable expansion and math expression evaluation.
long long TimestampDir(const wxString &aDirPath, const wxString &aFilespec)
A copy of ConvertFileTimeToWx() because wxWidgets left it as a static function private to src/common/...
#define FOR_ERC_DRC
Expand '${var-name}' templates in text.
Base window classes and related definitions.
Functions related to environment variables, including help functions.
int m_ResolveTextRecursionDepth
The number of recursions to resolve text variables.
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
KICOMMON_API std::optional< VAL_TYPE > GetEnvVar(const wxString &aEnvVarName)
Get an environment variable as a specific type, if set correctly.
KICOMMON_API const std::vector< wxString > & GetPredefinedEnvVars()
Get the list of pre-defined environment variables.
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
wxString result
Test unit parsing edge cases and error handling.