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, 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 };

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)

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

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

◆ ExpandEnvVarSubstitutions()

const wxString ExpandEnvVarSubstitutions ( const wxString &  aString,
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(), S3D_PLUGIN_MANAGER::checkPluginPath(), DIALOG_GEN_FOOTPRINT_POSITION::CreateAsciiFiles(), DIALOG_GEN_FOOTPRINT_POSITION::CreateGerberFiles(), FILENAME_RESOLVER::createPathList(), DIALOG_EXPORT_SVG::ExportSVGFile(), NETLIST_EXPORTER_PSPICE::Format(), DIALOG_GENDRILL::GenDrillAndMapFiles(), LIB_TABLE_ROW::GetFullURI(), DIALOG_PLOT_SCHEMATIC::getOutputPath(), DIALOG_SPICE_MODEL::loadLibrary(), TEXT_BUTTON_FILE_BROWSER::OnButtonClick(), PANEL_SYM_LIB_TABLE::onConvertLegacyLibraries(), DIALOG_GENDRILL::OnGenReportFile(), DIALOG_PLOT::OnOutputDirectoryBrowseClicked(), DIALOG_EXPORT_SVG::OnOutputDirectoryBrowseClicked(), DIALOG_GENDRILL::OnOutputDirectoryBrowseClicked(), DIALOG_GEN_FOOTPRINT_POSITION::OnOutputDirectoryBrowseClicked(), DIALOG_PLOT_SCHEMATIC::OnOutputDirectoryBrowseClicked(), DIALOG_SPICE_MODEL::onSelectLibrary(), DIALOG_PLOT::Plot(), FILENAME_RESOLVER::ResolvePath(), DS_DATA_MODEL::ResolvePath(), ResolveUriByEnvVars(), FILENAME_RESOLVER::Set3DConfigDir(), S3D_CACHE::Set3DConfigDir(), FILENAME_RESOLVER::SetProject(), FILENAME_RESOLVER::ShortenPath(), ERC_TESTER::TestTextVars(), and FILENAME_RESOLVER::WritePathList().

◆ ExpandTextVars() [1/2]

wxString ExpandTextVars ( const wxString &  aSource,
const PROJECT aProject 
)

Definition at line 57 of file common.cpp.

58 {
59  return ExpandTextVars( aSource, nullptr, nullptr, aProject );
60 }
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject)
Definition: common.cpp:57

References ExpandTextVars().

Referenced by AddGerberX2Header(), DS_DRAW_ITEM_LIST::BuildFullText(), ExpandTextVars(), PCB_TEXT::GetShownText(), SCH_FIELD::GetShownText(), SCH_TEXT::GetShownText(), FP_TEXT::GetShownText(), NETLIST_EXPORTER_XML::makeDesignHeader(), ResolveUriByEnvVars(), and TITLE_BLOCK::TextVarResolver().

◆ 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:66

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 }
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
Bracket
Definition: common.cpp:45
virtual bool TextVarResolver(wxString *aToken) const
Definition: project.cpp:66
#define _(s)

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 }
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject)
Definition: common.cpp:57
const wxString ExpandEnvVarSubstitutions(const wxString &aString, 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 FP_CACHE::GetTimestamp(), and GPCB_FPL_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
#define _(s)

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

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