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

Go to the source code of this file.

Enumerations

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

Functions

int ProcessExecute (const wxString &aCommandLine, int aFlags, wxProcess *callback)
 Run a command in a child process. More...
 
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...
 
std::ostream & operator<< (std::ostream &out, const wxSize &size)
 Helper function to print the given wxSize to a stream. More...
 
std::ostream & operator<< (std::ostream &out, const wxPoint &pt)
 Helper function to print the given wxPoint to a stream. 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...
 

Enumeration Type Documentation

◆ Bracket

enum Bracket
Enumerator
Bracket_None 
Bracket_Normal 
Bracket_Curly 
Bracket_Max 

Definition at line 46 of file common.cpp.

47 {
49  Bracket_Normal = ')',
50  Bracket_Curly = '}',
51 #ifdef __WINDOWS__
52  Bracket_Windows = '%', // yeah, Windows people are a bit strange ;-)
53 #endif
55 };

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 297 of file common.cpp.

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

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 269 of file common.cpp.

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

References KIwxExpandEnvVars().

Referenced by FILENAME_RESOLVER::addPath(), FILENAME_RESOLVER::checkEnvVarPath(), S3D_PLUGIN_MANAGER::checkPluginName(), S3D_PLUGIN_MANAGER::checkPluginPath(), DIALOG_GEN_FOOTPRINT_POSITION::CreateGerberFiles(), FILENAME_RESOLVER::createPathList(), DIALOG_PLOT_SCHEMATIC::createPlotFileName(), DIALOG_EXPORT_SVG::ExportSVGFile(), DIALOG_GENDRILL::GenDrillAndMapFiles(), LIB_TABLE_ROW::GetFullURI(), DS_DATA_MODEL::MakeFullFileName(), TEXT_BUTTON_FILE_BROWSER::OnButtonClick(), PANEL_SYM_LIB_TABLE::onConvertLegacyLibraries(), DIALOG_GENDRILL::OnGenReportFile(), DIALOG_EXPORT_SVG::OnOutputDirectoryBrowseClicked(), DIALOG_PLOT::OnOutputDirectoryBrowseClicked(), DIALOG_GEN_FOOTPRINT_POSITION::OnOutputDirectoryBrowseClicked(), DIALOG_PLOT_SCHEMATIC::OnOutputDirectoryBrowseClicked(), DIALOG_GENDRILL::OnOutputDirectoryBrowseClicked(), DIALOG_PLOT::Plot(), FILENAME_RESOLVER::ResolvePath(), ResolveUriByEnvVars(), FILENAME_RESOLVER::Set3DConfigDir(), S3D_CACHE::Set3DConfigDir(), FILENAME_RESOLVER::SetProject(), FILENAME_RESOLVER::ShortenPath(), and ERC_TESTER::TestTextVars().

◆ ExpandTextVars() [1/2]

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

Definition at line 58 of file common.cpp.

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

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 64 of file common.cpp.

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

References PROJECT::TextVarResolver().

◆ KIwxExpandEnvVars()

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

Definition at line 122 of file common.cpp.

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

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.nosp@m.is@c.nosp@m.s.Buf.nosp@m.falo.nosp@m..EDU and ircII's reg.c.

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

Definition at line 407 of file common.cpp.

408 {
409  if( !*text )
410  {
411  /* Match if both are empty. */
412  return !*pat;
413  }
414 
415  const char *m = pat,
416  *n = text,
417  *ma = NULL,
418  *na = NULL;
419  int just = 0,
420  acount = 0,
421  count = 0;
422 
423  if( dot_special && (*n == '.') )
424  {
425  /* Never match so that hidden Unix files
426  * are never found. */
427  return false;
428  }
429 
430  for(;;)
431  {
432  if( *m == '*' )
433  {
434  ma = ++m;
435  na = n;
436  just = 1;
437  acount = count;
438  }
439  else if( *m == '?' )
440  {
441  m++;
442 
443  if( !*n++ )
444  return false;
445  }
446  else
447  {
448  if( *m == '\\' )
449  {
450  m++;
451 
452  /* Quoting "nothing" is a bad thing */
453  if( !*m )
454  return false;
455  }
456  if( !*m )
457  {
458  /*
459  * If we are out of both strings or we just
460  * saw a wildcard, then we can say we have a
461  * match
462  */
463  if( !*n )
464  return true;
465 
466  if( just )
467  return true;
468 
469  just = 0;
470  goto not_matched;
471  }
472 
473  /*
474  * We could check for *n == NULL at this point, but
475  * since it's more common to have a character there,
476  * check to see if they match first (m and n) and
477  * then if they don't match, THEN we can check for
478  * the NULL of n
479  */
480  just = 0;
481 
482  if( *m == *n )
483  {
484  m++;
485  count++;
486  n++;
487  }
488  else
489  {
490  not_matched:
491 
492  /*
493  * If there are no more characters in the
494  * string, but we still need to find another
495  * character (*m != NULL), then it will be
496  * impossible to match it
497  */
498  if( !*n )
499  return false;
500 
501  if( ma )
502  {
503  m = ma;
504  n = ++na;
505  count = acount;
506  }
507  else
508  return false;
509  }
510  }
511  }
512 }
#define NULL

References NULL.

Referenced by TimestampDir().

◆ operator<<() [1/2]

std::ostream& operator<< ( std::ostream &  out,
const wxSize &  size 
)

Helper function to print the given wxSize to a stream.

Used for debugging functions like EDA_ITEM::Show and also in unit testing fixtures.

Definition at line 379 of file common.cpp.

380 {
381  out << " width=\"" << size.GetWidth() << "\" height=\"" << size.GetHeight() << "\"";
382  return out;
383 }

◆ operator<<() [2/2]

std::ostream& operator<< ( std::ostream &  out,
const wxPoint &  pt 
)

Helper function to print the given wxPoint to a stream.

Used for debugging functions like EDA_ITEM::Show and also in unit testing fixtures.

Definition at line 386 of file common.cpp.

387 {
388  out << " x=\"" << pt.x << "\" y=\"" << pt.y << "\"";
389  return out;
390 }

◆ ProcessExecute()

int ProcessExecute ( const wxString &  aCommandLine,
int  aFlags = wxEXEC_ASYNC,
wxProcess *  callback = nullptr 
)

Run a command in a child process.

Parameters
aCommandLineThe process and any arguments to it all in a single string.
aFlagsThe same args as allowed for wxExecute()
callbackwxProcess implementing OnTerminate to be run when the child process finishes
Returns
pid of process, 0 in case of error (like return values of wxExecute()).

Definition at line 40 of file common.cpp.

41 {
42  return (int) wxExecute( aCommandLine, aFlags, callback );
43 }

Referenced by doPrintFile(), ExecuteFile(), GetAssociatedDocument(), OpenFile(), OpenPDF(), and SCH_EDIT_FRAME::WriteNetListFile().

◆ 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 282 of file common.cpp.

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

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.

TimestampDir

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

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

Definition at line 549 of file common.cpp.

550 {
551  long long timestamp = 0;
552 
553 #if defined( __WIN32__ )
554  // Win32 version.
555  // Save time by not searching for each path twice: once in wxDir.GetNext() and once in
556  // wxFileName.GetModificationTime(). Also cuts out wxWidgets' string-matching and case
557  // conversion by staying on the MSW side of things.
558  std::wstring filespec( aDirPath.t_str() );
559  filespec += '\\';
560  filespec += aFilespec.t_str();
561 
562  WIN32_FIND_DATA findData;
563  wxDateTime lastModDate;
564 
565  HANDLE fileHandle = ::FindFirstFile( filespec.data(), &findData );
566 
567  if( fileHandle != INVALID_HANDLE_VALUE )
568  {
569  do
570  {
571  ConvertFileTimeToWx( &lastModDate, findData.ftLastWriteTime );
572  timestamp += lastModDate.GetValue().GetValue();
573  timestamp += findData.nFileSizeLow; // Get the file size (partial) as well to check for sneaky changes
574  }
575  while ( FindNextFile( fileHandle, &findData ) != 0 );
576  }
577 
578  FindClose( fileHandle );
579 #else
580  // POSIX version.
581  // Save time by not converting between encodings -- do everything on the file-system side.
582  std::string filespec( aFilespec.fn_str() );
583  std::string dir_path( aDirPath.fn_str() );
584 
585  DIR* dir = opendir( dir_path.c_str() );
586 
587  if( dir )
588  {
589  for( dirent* dir_entry = readdir( dir ); dir_entry; dir_entry = readdir( dir ) )
590  {
591  if( !matchWild( filespec.c_str(), dir_entry->d_name, true ) )
592  continue;
593 
594  std::string entry_path = dir_path + '/' + dir_entry->d_name;
595  struct stat entry_stat;
596 
597  if( wxCRT_Lstat( entry_path.c_str(), &entry_stat ) == 0 )
598  {
599  // Timestamp the source file, not the symlink
600  if( S_ISLNK( entry_stat.st_mode ) ) // wxFILE_EXISTS_SYMLINK
601  {
602  char buffer[ PATH_MAX + 1 ];
603  ssize_t pathLen = readlink( entry_path.c_str(), buffer, PATH_MAX );
604 
605  if( pathLen > 0 )
606  {
607  struct stat linked_stat;
608  buffer[ pathLen ] = '\0';
609  entry_path = dir_path + buffer;
610 
611  if( wxCRT_Lstat( entry_path.c_str(), &linked_stat ) == 0 )
612  {
613  entry_stat = linked_stat;
614  }
615  else
616  {
617  // if we couldn't lstat the linked file we'll have to just use
618  // the symbolic link info
619  }
620  }
621  }
622 
623  if( S_ISREG( entry_stat.st_mode ) ) // wxFileExists()
624  {
625  timestamp += entry_stat.st_mtime * 1000;
626  timestamp += entry_stat.st_size; // Get the file size as well to check for sneaky changes
627  }
628  }
629  else
630  {
631  // if we couldn't lstat the file itself all we can do is use the name
632  timestamp += (signed) std::hash<std::string>{}( std::string( dir_entry->d_name ) );
633  }
634  }
635 
636  closedir( dir );
637  }
638 #endif
639 
640  return timestamp;
641 }
bool matchWild(const char *pat, const char *text, bool dot_special)
Performance enhancements to file and directory operations.
Definition: common.cpp:407

References matchWild().

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