KiCad PCB EDA Suite
common.cpp File Reference
#include <eda_base_frame.h>
#include <kiplatform/app.h>
#include <project.h>
#include <common.h>
#include <reporter.h>
#include <macros.h>
#include <mutex>
#include <wx/config.h>
#include <wx/log.h>
#include <wx/msgdlg.h>
#include <wx/stdpaths.h>
#include <wx/url.h>
#include <wx/utils.h>

Go to the source code of this file.

Enumerations

enum  Bracket { Bracket_None , Bracket_Normal = ')' , Bracket_Curly = '}' , Bracket_Max }
 

Functions

wxString ExpandTextVars (const wxString &aSource, const PROJECT *aProject)
 
wxString ExpandTextVars (const wxString &aSource, const std::function< bool(wxString *)> *aLocalResolver, const std::function< bool(wxString *)> *aFallbackResolver, const PROJECT *aProject)
 Expand '${var-name}' templates in text. More...
 
wxString KIwxExpandEnvVars (const wxString &str, const PROJECT *aProject)
 
const wxString ExpandEnvVarSubstitutions (const wxString &aString, const PROJECT *aProject)
 Replace any environment variable & text variable references with their values. More...
 
const wxString ResolveUriByEnvVars (const wxString &aUri, PROJECT *aProject)
 Replace any environment and/or text variables in file-path uris (leaving network-path URIs alone). More...
 
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. More...
 
bool matchWild (const char *pat, const char *text, bool dot_special)
 Performance enhancements to file and directory operations. More...
 
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/filename.cpp. More...
 
bool WarnUserIfOperatingSystemUnsupported ()
 Checks if the operating system is explicitly unsupported and displays a disclaimer message box. More...
 

Enumeration Type Documentation

◆ Bracket

enum Bracket
Enumerator
Bracket_None 
Bracket_Normal 
Bracket_Curly 
Bracket_Max 

Definition at line 45 of file common.cpp.

46{
48 Bracket_Normal = ')',
49 Bracket_Curly = '}',
50#ifdef __WINDOWS__
51 Bracket_Windows = '%', // yeah, Windows people are a bit strange ;-)
52#endif
54};
@ Bracket_Max
Definition: common.cpp:53
@ Bracket_None
Definition: common.cpp:47
@ Bracket_Normal
Definition: common.cpp:48
@ Bracket_Curly
Definition: common.cpp:49

Function Documentation

◆ EnsureFileDirectoryExists()

bool EnsureFileDirectoryExists ( wxFileName *  aTargetFullFileName,
const wxString &  aBaseFilename,
REPORTER aReporter = nullptr 
)

Make aTargetFullFileName absolute and create the path of this file if it doesn't yet exist.

Parameters
aTargetFullFileNamethe wxFileName containing the full path and file name to modify. The path may be absolute or relative to aBaseFilename .
aBaseFilenamea full filename. Only its path is used to set the aTargetFullFileName path.
aReportera point to a REPORTER object use to show messages (can be NULL)
Returns
true if aOutputDir already exists or was successfully created.

Definition at line 295 of file common.cpp.

298{
299 wxString msg;
300 wxString baseFilePath = wxFileName( aBaseFilename ).GetPath();
301
302 // make aTargetFullFileName path, which is relative to aBaseFilename path (if it is not
303 // already an absolute path) absolute:
304 if( !aTargetFullFileName->MakeAbsolute( baseFilePath ) )
305 {
306 if( aReporter )
307 {
308 msg.Printf( _( "Cannot make path '%s' absolute with respect to '%s'." ),
309 aTargetFullFileName->GetPath(),
310 baseFilePath );
311 aReporter->Report( msg, RPT_SEVERITY_ERROR );
312 }
313
314 return false;
315 }
316
317 // Ensure the path of aTargetFullFileName exists, and create it if needed:
318 wxString outputPath( aTargetFullFileName->GetPath() );
319
320 if( !wxFileName::DirExists( outputPath ) )
321 {
322 // Make every directory provided when the provided path doesn't exist
323 if( wxFileName::Mkdir( outputPath, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
324 {
325 if( aReporter )
326 {
327 msg.Printf( _( "Output directory '%s' created." ), outputPath );
328 aReporter->Report( msg, RPT_SEVERITY_INFO );
329 return true;
330 }
331 }
332 else
333 {
334 if( aReporter )
335 {
336 msg.Printf( _( "Cannot create output directory '%s'." ), outputPath );
337 aReporter->Report( msg, RPT_SEVERITY_ERROR );
338 }
339
340 return false;
341 }
342 }
343
344 return true;
345}
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
#define _(s)
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO

References _, REPORTER::Report(), RPT_SEVERITY_ERROR, and RPT_SEVERITY_INFO.

Referenced by DIALOG_GEN_FOOTPRINT_POSITION::CreateAsciiFiles(), DIALOG_GEN_FOOTPRINT_POSITION::CreateGerberFiles(), SCH_PLOTTER::createPlotFileName(), DIALOG_EXPORT_SVG::ExportSVGFile(), DIALOG_GENDRILL::GenDrillAndMapFiles(), PLOT_CONTROLLER::OpenPlotfile(), and DIALOG_PLOT::Plot().

◆ ExpandEnvVarSubstitutions()

const wxString ExpandEnvVarSubstitutions ( const wxString &  aString,
const PROJECT aProject 
)

Replace any environment variable & text variable references with their values.

Parameters
aStringa string containing (perhaps) references to env var
Returns
the expanded environment variable.

Definition at line 267 of file common.cpp.

268{
269 // wxGetenv( wchar_t* ) is not re-entrant on linux.
270 // Put a lock on multithreaded use of wxGetenv( wchar_t* ), called from wxEpandEnvVars(),
271 static std::mutex getenv_mutex;
272
273 std::lock_guard<std::mutex> lock( getenv_mutex );
274
275 // We reserve the right to do this another way, by providing our own member function.
276 return KIwxExpandEnvVars( aString, aProject );
277}
wxString KIwxExpandEnvVars(const wxString &str, const PROJECT *aProject)
Definition: common.cpp:121

References KIwxExpandEnvVars().

Referenced by FILENAME_RESOLVER::addPath(), FILENAME_RESOLVER::checkEnvVarPath(), S3D_PLUGIN_MANAGER::checkPluginName(), DIALOG_GEN_FOOTPRINT_POSITION::CreateAsciiFiles(), DIALOG_GEN_FOOTPRINT_POSITION::CreateGerberFiles(), SIM_LIB_MGR::CreateLibrary(), SIM_LIB_MGR::CreateModel(), FILENAME_RESOLVER::createPathList(), DIALOG_EXPORT_SVG::ExportSVGFile(), DIALOG_GENDRILL::GenDrillAndMapFiles(), LIB_TABLE_ROW::GetFullURI(), DIALOG_PLOT_SCHEMATIC::getOutputPath(), SPICE_GENERATOR_KIBIS::IbisDevice(), TEXT_BUTTON_FILE_BROWSER::OnButtonClick(), PANEL_SYM_LIB_TABLE::onConvertLegacyLibraries(), DIALOG_GENDRILL::OnGenReportFile(), DIALOG_PLOT_SCHEMATIC::OnOutputDirectoryBrowseClicked(), DIALOG_EXPORT_SVG::OnOutputDirectoryBrowseClicked(), DIALOG_GEN_FOOTPRINT_POSITION::OnOutputDirectoryBrowseClicked(), DIALOG_GENDRILL::OnOutputDirectoryBrowseClicked(), DIALOG_PLOT::OnOutputDirectoryBrowseClicked(), DIALOG_PAGES_SETTINGS::OnWksFileSelection(), PLOT_CONTROLLER::OpenPlotfile(), DIALOG_PLOT::Plot(), FILENAME_RESOLVER::ResolvePath(), DS_DATA_MODEL::ResolvePath(), ResolveUriByEnvVars(), S3D_CACHE::Set3DConfigDir(), FILENAME_RESOLVER::Set3DConfigDir(), FILENAME_RESOLVER::SetProject(), FILENAME_RESOLVER::ShortenPath(), ERC_TESTER::TestTextVars(), and NETLIST_EXPORTER_SPICE::writeInclude().

◆ ExpandTextVars() [1/2]

◆ ExpandTextVars() [2/2]

wxString ExpandTextVars ( const wxString &  aSource,
const std::function< bool(wxString *)> *  aLocalResolver,
const std::function< bool(wxString *)> *  aFallbackResolver,
const PROJECT aProject 
)

Expand '${var-name}' templates in text.

The LocalResolver is given first crack at it, after which the PROJECT's resolver is called.

Definition at line 63 of file common.cpp.

67{
68 wxString newbuf;
69 size_t sourceLen = aSource.length();
70
71 newbuf.Alloc( sourceLen ); // best guess (improves performance)
72
73 for( size_t i = 0; i < sourceLen; ++i )
74 {
75 if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i+1] == '{' )
76 {
77 wxString token;
78
79 for( i = i + 2; i < sourceLen; ++i )
80 {
81 if( aSource[i] == '}' )
82 break;
83 else
84 token.append( aSource[i] );
85 }
86
87 if( token.IsEmpty() )
88 continue;
89
90 if( aLocalResolver && (*aLocalResolver)( &token ) )
91 {
92 newbuf.append( token );
93 }
94 else if( aProject && aProject->TextVarResolver( &token ) )
95 {
96 newbuf.append( token );
97 }
98 else if( aFallbackResolver && (*aFallbackResolver)( &token ) )
99 {
100 newbuf.append( token );
101 }
102 else
103 {
104 // Token not resolved: leave the reference unchanged
105 newbuf.append( "${" + token + "}" );
106 }
107 }
108 else
109 {
110 newbuf.append( aSource[i] );
111 }
112 }
113
114 return newbuf;
115}
virtual bool TextVarResolver(wxString *aToken) const
Definition: project.cpp:70

References PROJECT::TextVarResolver().

◆ KIwxExpandEnvVars()

wxString KIwxExpandEnvVars ( const wxString &  str,
const PROJECT aProject 
)

Definition at line 121 of file common.cpp.

122{
123 size_t strlen = str.length();
124
125 wxString strResult;
126 strResult.Alloc( strlen ); // best guess (improves performance)
127
128 for( size_t n = 0; n < strlen; n++ )
129 {
130 wxUniChar str_n = str[n];
131
132 switch( str_n.GetValue() )
133 {
134#ifdef __WINDOWS__
135 case wxT( '%' ):
136#endif // __WINDOWS__
137 case wxT( '$' ):
138 {
139 Bracket bracket;
140#ifdef __WINDOWS__
141 if( str_n == wxT( '%' ) )
142 bracket = Bracket_Windows;
143 else
144#endif // __WINDOWS__
145 if( n == strlen - 1 )
146 {
147 bracket = Bracket_None;
148 }
149 else
150 {
151 switch( str[n + 1].GetValue() )
152 {
153 case wxT( '(' ):
154 bracket = Bracket_Normal;
155 str_n = str[++n]; // skip the bracket
156 break;
157
158 case wxT( '{' ):
159 bracket = Bracket_Curly;
160 str_n = str[++n]; // skip the bracket
161 break;
162
163 default:
164 bracket = Bracket_None;
165 }
166 }
167
168 size_t m = n + 1;
169
170 if( m >= strlen )
171 break;
172
173 wxUniChar str_m = str[m];
174
175 while( wxIsalnum( str_m ) || str_m == wxT( '_' ) || str_m == wxT( ':' ) )
176 {
177 if( ++m == strlen )
178 {
179 str_m = 0;
180 break;
181 }
182
183 str_m = str[m];
184 }
185
186 wxString strVarName( str.c_str() + n + 1, m - n - 1 );
187
188 // NB: use wxGetEnv instead of wxGetenv as otherwise variables
189 // set through wxSetEnv may not be read correctly!
190 bool expanded = false;
191 wxString tmp = strVarName;
192
193 if( aProject && aProject->TextVarResolver( &tmp ) )
194 {
195 strResult += tmp;
196 expanded = true;
197 }
198 else if( wxGetEnv( strVarName, &tmp ) )
199 {
200 strResult += tmp;
201 expanded = true;
202 }
203 else
204 {
205 // variable doesn't exist => don't change anything
206#ifdef __WINDOWS__
207 if ( bracket != Bracket_Windows )
208#endif
209 if ( bracket != Bracket_None )
210 strResult << str[n - 1];
211
212 strResult << str_n << strVarName;
213 }
214
215 // check the closing bracket
216 if( bracket != Bracket_None )
217 {
218 if( m == strlen || str_m != (wxChar)bracket )
219 {
220 // under MSW it's common to have '%' characters in the registry
221 // and it's annoying to have warnings about them each time, so
222 // ignore them silently if they are not used for env vars
223 //
224 // under Unix, OTOH, this warning could be useful for the user to
225 // understand why isn't the variable expanded as intended
226#ifndef __WINDOWS__
227 wxLogWarning( _( "Environment variables expansion failed: missing '%c' "
228 "at position %u in '%s'." ),
229 (char)bracket, (unsigned int) (m + 1), str.c_str() );
230#endif // __WINDOWS__
231 }
232 else
233 {
234 // skip closing bracket unless the variables wasn't expanded
235 if( !expanded )
236 strResult << (wxChar)bracket;
237
238 m++;
239 }
240 }
241
242 n = m - 1; // skip variable name
243 str_n = str[n];
244 }
245 break;
246
247 case wxT( '\\' ):
248 // backslash can be used to suppress special meaning of % and $
249 if( n < strlen - 1 && (str[n + 1] == wxT( '%' ) || str[n + 1] == wxT( '$' )) )
250 {
251 str_n = str[++n];
252 strResult += str_n;
253
254 break;
255 }
257
258 default:
259 strResult += str_n;
260 }
261 }
262
263 return strResult;
264}
Bracket
Definition: common.cpp:46
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83

References _, Bracket_Curly, Bracket_None, Bracket_Normal, KI_FALLTHROUGH, and PROJECT::TextVarResolver().

Referenced by ExpandEnvVarSubstitutions().

◆ matchWild()

bool matchWild ( const char *  pat,
const char *  text,
bool  dot_special 
)

Performance enhancements to file and directory operations.

Note: while it's annoying to have to make copies of wxWidgets stuff and then add platform-specific performance optimizations, the following routines offer SIGNIFICANT performance benefits. A copy of wxMatchWild(), which wxWidgets attributes to Douglas A. Lewis dalew[email protected][email protected][email protected]s.Buf[email protected]falo[email protected].EDU and ircII's reg.c.

This version is modified to skip any encoding conversions (for performance).

Definition at line 362 of file common.cpp.

363{
364 if( !*text )
365 {
366 /* Match if both are empty. */
367 return !*pat;
368 }
369
370 const char *m = pat,
371 *n = text,
372 *ma = nullptr,
373 *na = nullptr;
374 int just = 0,
375 acount = 0,
376 count = 0;
377
378 if( dot_special && (*n == '.') )
379 {
380 /* Never match so that hidden Unix files
381 * are never found. */
382 return false;
383 }
384
385 for(;;)
386 {
387 if( *m == '*' )
388 {
389 ma = ++m;
390 na = n;
391 just = 1;
392 acount = count;
393 }
394 else if( *m == '?' )
395 {
396 m++;
397
398 if( !*n++ )
399 return false;
400 }
401 else
402 {
403 if( *m == '\\' )
404 {
405 m++;
406
407 /* Quoting "nothing" is a bad thing */
408 if( !*m )
409 return false;
410 }
411
412 if( !*m )
413 {
414 /*
415 * If we are out of both strings or we just
416 * saw a wildcard, then we can say we have a
417 * match
418 */
419 if( !*n )
420 return true;
421
422 if( just )
423 return true;
424
425 just = 0;
426 goto not_matched;
427 }
428
429 /*
430 * We could check for *n == NULL at this point, but
431 * since it's more common to have a character there,
432 * check to see if they match first (m and n) and
433 * then if they don't match, THEN we can check for
434 * the NULL of n
435 */
436 just = 0;
437
438 if( *m == *n )
439 {
440 m++;
441 count++;
442 n++;
443 }
444 else
445 {
446 not_matched:
447
448 /*
449 * If there are no more characters in the
450 * string, but we still need to find another
451 * character (*m != NULL), then it will be
452 * impossible to match it
453 */
454 if( !*n )
455 return false;
456
457 if( ma )
458 {
459 m = ma;
460 n = ++na;
461 count = acount;
462 }
463 else
464 return false;
465 }
466 }
467 }
468}

References text.

Referenced by TimestampDir().

◆ ResolveUriByEnvVars()

const wxString ResolveUriByEnvVars ( const wxString &  aUri,
PROJECT aProject 
)

Replace any environment and/or text variables in file-path uris (leaving network-path URIs alone).

Definition at line 280 of file common.cpp.

281{
282 wxString uri = ExpandTextVars( aUri, aProject );
283
284 // URL-like URI: return as is.
285 wxURL url( uri );
286
287 if( url.GetError() == wxURL_NOERR )
288 return uri;
289
290 // Otherwise, the path points to a local file. Resolve environment variables if any.
291 return ExpandEnvVarSubstitutions( aUri, aProject );
292}
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:267

References ExpandEnvVarSubstitutions(), and ExpandTextVars().

Referenced by GetAssociatedDocument().

◆ TimestampDir()

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/filename.cpp.

This routine offers SIGNIFICANT performance benefits over using wxWidgets to gather timestamps from matching files in a directory.

Parameters
aDirPathis the directory to search.
aFilespecis a (wildcarded) file spec to match against.
Returns
a hash of the last-mod-dates of all matching files in the directory.

Definition at line 504 of file common.cpp.

505{
506 long long timestamp = 0;
507
508#if defined( __WIN32__ )
509 // Win32 version.
510 // Save time by not searching for each path twice: once in wxDir.GetNext() and once in
511 // wxFileName.GetModificationTime(). Also cuts out wxWidgets' string-matching and case
512 // conversion by staying on the MSW side of things.
513 std::wstring filespec( aDirPath.t_str() );
514 filespec += '\\';
515 filespec += aFilespec.t_str();
516
517 WIN32_FIND_DATA findData;
518 wxDateTime lastModDate;
519
520 HANDLE fileHandle = ::FindFirstFile( filespec.data(), &findData );
521
522 if( fileHandle != INVALID_HANDLE_VALUE )
523 {
524 do
525 {
526 ConvertFileTimeToWx( &lastModDate, findData.ftLastWriteTime );
527 timestamp += lastModDate.GetValue().GetValue();
528
529 // Get the file size (partial) as well to check for sneaky changes.
530 timestamp += findData.nFileSizeLow;
531 }
532 while ( FindNextFile( fileHandle, &findData ) != 0 );
533 }
534
535 FindClose( fileHandle );
536#else
537 // POSIX version.
538 // Save time by not converting between encodings -- do everything on the file-system side.
539 std::string filespec( aFilespec.fn_str() );
540 std::string dir_path( aDirPath.fn_str() );
541
542 DIR* dir = opendir( dir_path.c_str() );
543
544 if( dir )
545 {
546 for( dirent* dir_entry = readdir( dir ); dir_entry; dir_entry = readdir( dir ) )
547 {
548 if( !matchWild( filespec.c_str(), dir_entry->d_name, true ) )
549 continue;
550
551 std::string entry_path = dir_path + '/' + dir_entry->d_name;
552 struct stat entry_stat;
553
554 if( wxCRT_Lstat( entry_path.c_str(), &entry_stat ) == 0 )
555 {
556 // Timestamp the source file, not the symlink
557 if( S_ISLNK( entry_stat.st_mode ) ) // wxFILE_EXISTS_SYMLINK
558 {
559 char buffer[ PATH_MAX + 1 ];
560 ssize_t pathLen = readlink( entry_path.c_str(), buffer, PATH_MAX );
561
562 if( pathLen > 0 )
563 {
564 struct stat linked_stat;
565 buffer[ pathLen ] = '\0';
566 entry_path = dir_path + buffer;
567
568 if( wxCRT_Lstat( entry_path.c_str(), &linked_stat ) == 0 )
569 {
570 entry_stat = linked_stat;
571 }
572 else
573 {
574 // if we couldn't lstat the linked file we'll have to just use
575 // the symbolic link info
576 }
577 }
578 }
579
580 if( S_ISREG( entry_stat.st_mode ) ) // wxFileExists()
581 {
582 timestamp += entry_stat.st_mtime * 1000;
583
584 // Get the file size as well to check for sneaky changes.
585 timestamp += entry_stat.st_size;
586 }
587 }
588 else
589 {
590 // if we couldn't lstat the file itself all we can do is use the name
591 timestamp += (signed) std::hash<std::string>{}( std::string( dir_entry->d_name ) );
592 }
593 }
594
595 closedir( dir );
596 }
597#endif
598
599 return timestamp;
600}
bool matchWild(const char *pat, const char *text, bool dot_special)
Performance enhancements to file and directory operations.
Definition: common.cpp:362

References matchWild().

Referenced by GPCB_FPL_CACHE::GetTimestamp(), and FP_CACHE::GetTimestamp().

◆ WarnUserIfOperatingSystemUnsupported()

bool WarnUserIfOperatingSystemUnsupported ( )

Checks if the operating system is explicitly unsupported and displays a disclaimer message box.

Returns
true if the operating system is unsupported

Definition at line 603 of file common.cpp.

604{
606 return false;
607
608 wxMessageDialog dialog( nullptr, _( "This operating system is not supported "
609 "by KiCad and its dependencies." ),
610 _( "Unsupported Operating System" ),
611 wxOK | wxICON_EXCLAMATION );
612
613 dialog.SetExtendedMessage( _( "Any issues with KiCad on this system cannot "
614 "be reported to the official bugtracker." ) );
615 dialog.ShowModal();
616
617 return true;
618}
bool IsOperatingSystemUnsupported()
Checks if the Operating System is explicitly unsupported and we want to prevent users from sending bu...
Definition: gtk/app.cpp:51

References _, and KIPLATFORM::APP::IsOperatingSystemUnsupported().

Referenced by PGM_BASE::InitPgm(), and COMMON_CONTROL::ReportBug().