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/process.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

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

53 {
55  Bracket_Normal = ')',
56  Bracket_Curly = '}',
57 #ifdef __WINDOWS__
58  Bracket_Windows = '%', // yeah, Windows people are a bit strange ;-)
59 #endif
61 };

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

310 {
311  wxString msg;
312  wxString baseFilePath = wxFileName( aBaseFilename ).GetPath();
313 
314  // make aTargetFullFileName path, which is relative to aBaseFilename path (if it is not
315  // already an absolute path) absolute:
316  if( !aTargetFullFileName->MakeAbsolute( baseFilePath ) )
317  {
318  if( aReporter )
319  {
320  msg.Printf( _( "Cannot make path '%s' absolute with respect to '%s'." ),
321  aTargetFullFileName->GetPath(),
322  baseFilePath );
323  aReporter->Report( msg, RPT_SEVERITY_ERROR );
324  }
325 
326  return false;
327  }
328 
329  // Ensure the path of aTargetFullFileName exists, and create it if needed:
330  wxString outputPath( aTargetFullFileName->GetPath() );
331 
332  if( !wxFileName::DirExists( outputPath ) )
333  {
334  // Make every directory provided when the provided path doesn't exist
335  if( wxFileName::Mkdir( outputPath, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
336  {
337  if( aReporter )
338  {
339  msg.Printf( _( "Output directory '%s' created." ), outputPath );
340  aReporter->Report( msg, RPT_SEVERITY_INFO );
341  return true;
342  }
343  }
344  else
345  {
346  if( aReporter )
347  {
348  msg.Printf( _( "Cannot create output directory '%s'." ), outputPath );
349  aReporter->Report( msg, RPT_SEVERITY_ERROR );
350  }
351 
352  return false;
353  }
354  }
355 
356  return true;
357 }
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 279 of file common.cpp.

280 {
281  // wxGetenv( wchar_t* ) is not re-entrant on linux.
282  // Put a lock on multithreaded use of wxGetenv( wchar_t* ), called from wxEpandEnvVars(),
283  static std::mutex getenv_mutex;
284 
285  std::lock_guard<std::mutex> lock( getenv_mutex );
286 
287  // We reserve the right to do this another way, by providing our own member function.
288  return KIwxExpandEnvVars( aString, aProject );
289 }
wxString KIwxExpandEnvVars(const wxString &str, const PROJECT *aProject)
Definition: common.cpp:128

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(), DS_DATA_MODEL::MakeFullFileName(), 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(), 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 64 of file common.cpp.

65 {
66  return ExpandTextVars( aSource, nullptr, nullptr, aProject );
67 }
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject)
Definition: common.cpp:64

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

74 {
75  wxString newbuf;
76  size_t sourceLen = aSource.length();
77 
78  newbuf.Alloc( sourceLen ); // best guess (improves performance)
79 
80  for( size_t i = 0; i < sourceLen; ++i )
81  {
82  if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i+1] == '{' )
83  {
84  wxString token;
85 
86  for( i = i + 2; i < sourceLen; ++i )
87  {
88  if( aSource[i] == '}' )
89  break;
90  else
91  token.append( aSource[i] );
92  }
93 
94  if( token.IsEmpty() )
95  continue;
96 
97  if( aLocalResolver && (*aLocalResolver)( &token ) )
98  {
99  newbuf.append( token );
100  }
101  else if( aProject && aProject->TextVarResolver( &token ) )
102  {
103  newbuf.append( token );
104  }
105  else if( aFallbackResolver && (*aFallbackResolver)( &token ) )
106  {
107  newbuf.append( token );
108  }
109  else
110  {
111  // Token not resolved: leave the reference unchanged
112  newbuf.append( "${" + token + "}" );
113  }
114  }
115  else
116  {
117  newbuf.append( aSource[i] );
118  }
119  }
120 
121  return newbuf;
122 }
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 128 of file common.cpp.

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

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

References text.

Referenced by TimestampDir().

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

47 {
48  return (int) wxExecute( aCommandLine, aFlags, callback );
49 }

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

293 {
294  wxString uri = ExpandTextVars( aUri, aProject );
295 
296  // URL-like URI: return as is.
297  wxURL url( uri );
298 
299  if( url.GetError() == wxURL_NOERR )
300  return uri;
301 
302  // Otherwise, the path points to a local file. Resolve environment variables if any.
303  return ExpandEnvVarSubstitutions( aUri, aProject );
304 }
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject)
Definition: common.cpp:64
const wxString ExpandEnvVarSubstitutions(const wxString &aString, PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:279

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

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

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

616 {
618  return false;
619 
620  wxMessageDialog dialog( nullptr, _( "This operating system is not supported "
621  "by KiCad and its dependencies." ),
622  _( "Unsupported Operating System" ),
623  wxOK | wxICON_EXCLAMATION );
624 
625  dialog.SetExtendedMessage( _( "Any issues with KiCad on this system cannot "
626  "be reported to the official bugtracker." ) );
627  dialog.ShowModal();
628 
629  return true;
630 }
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().