KiCad PCB EDA Suite
common.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2014-2020 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
6  * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <fctsys.h>
27 #include <eda_base_frame.h>
28 #include <common.h>
29 #include <macros.h>
30 #include <reporter.h>
31 #include <mutex>
33 
34 #include <wx/process.h>
35 #include <wx/config.h>
36 #include <wx/utils.h>
37 #include <wx/stdpaths.h>
38 #include <wx/url.h>
39 #include <boost/uuid/uuid_generators.hpp>
40 #include <boost/uuid/uuid_io.hpp>
41 #include <boost/functional/hash.hpp>
42 
43 using KIGFX::COLOR4D;
44 
45 
46 // Create only once, as seeding is *very* expensive
47 static boost::uuids::random_generator randomGenerator;
48 
49 // These don't have the same performance penalty, but might as well be consistent
50 static boost::uuids::string_generator stringGenerator;
51 static boost::uuids::nil_generator nilGenerator;
52 
53 // Global nil reference
54 KIID niluuid( 0 );
55 
56 
58  m_uuid( randomGenerator() ),
59  m_cached_timestamp( 0 )
60 {
61 #if defined(EESCHEMA)
62  // JEY TODO: use legacy timestamps until new EEschema file format is in
63  static timestamp_t oldTimeStamp;
64  timestamp_t newTimeStamp = time( NULL );
65 
66  if( newTimeStamp <= oldTimeStamp )
67  newTimeStamp = oldTimeStamp + 1;
68 
69  oldTimeStamp = newTimeStamp;
70 
71  *this = KIID( wxString::Format( "%8.8X", newTimeStamp ) );
72 #endif
73 }
74 
75 
76 KIID::KIID( int null ) :
77  m_uuid( nilGenerator() ),
78  m_cached_timestamp( 0 )
79 {
80  wxASSERT( null == 0 );
81 }
82 
83 
84 KIID::KIID( const wxString& aString ) :
85  m_uuid(),
86  m_cached_timestamp( 0 )
87 {
88  if( aString.length() == 8 )
89  {
90  // A legacy-timestamp-based UUID has only the last 4 octets filled in.
91  // Convert them individually to avoid stepping in the little-endian/big-endian
92  // doo-doo.
93  for( int i = 0; i < 4; ++i )
94  {
95  wxString octet = aString.substr( i * 2, 2 );
96  m_uuid.data[ i + 12 ] = strtol( octet.data(), NULL, 16 );
97  }
98 
99  m_cached_timestamp = strtol( aString.c_str(), NULL, 16 );
100  }
101  else
102  {
103  try
104  {
105  m_uuid = stringGenerator( aString.wc_str() );
106 
107  if( IsLegacyTimestamp() )
108  m_cached_timestamp = strtol( aString.substr( 28 ).c_str(), NULL, 16 );
109  }
110  catch( ... )
111  {
112  // Failed to parse string representation; best we can do is assign a new
113  // random one.
115  }
116  }
117 }
118 
119 
120 KIID::KIID( timestamp_t aTimestamp )
121 {
122  m_cached_timestamp = aTimestamp;
123 
124  // A legacy-timestamp-based UUID has only the last 4 octets filled in.
125  // Convert them individually to avoid stepping in the little-endian/big-endian
126  // doo-doo.
127  wxString str = AsLegacyTimestampString();
128 
129  for( int i = 0; i < 4; ++i )
130  {
131  wxString octet = str.substr( i * 2, 2 );
132  m_uuid.data[ i + 12 ] = strtol( octet.data(), NULL, 16 );
133  }
134 }
135 
136 
138 {
139  return !m_uuid.data[8] && !m_uuid.data[9] && !m_uuid.data[10] && !m_uuid.data[11];
140 }
141 
142 
144 {
145  return m_cached_timestamp;
146 }
147 
148 
149 size_t KIID::Hash() const
150 {
151  size_t hash = 0;
152 
153  // Note: this is NOT little-endian/big-endian safe, but as long as it's just used
154  // at runtime it won't matter.
155 
156  for( int i = 0; i < 4; ++i )
157  boost::hash_combine( hash, reinterpret_cast<const uint32_t*>( m_uuid.data )[i] );
158 
159  return hash;
160 }
161 
162 
163 void KIID::Clone( const KIID& aUUID )
164 {
165  m_uuid = aUUID.m_uuid;
167 }
168 
169 
170 wxString KIID::AsString() const
171 {
172  return boost::uuids::to_string( m_uuid );
173 }
174 
175 
177 {
178  return wxString::Format( "%8.8lX", (unsigned long) AsLegacyTimestamp() );
179 }
180 
181 
190 // When reading/writing files, we need to swtich to setlocale( LC_NUMERIC, "C" ).
191 // Works fine to read/write files with floating point numbers.
192 // We can call setlocale( LC_NUMERIC, "C" ) of wxLocale( "C", "C", "C", false )
193 // wxWidgets discourage a direct call to setlocale
194 // However, for us, calling wxLocale( "C", "C", "C", false ) has a unwanted effect:
195 // The I18N translations are no longer active, because the English dixtionary is selected.
196 // To read files, this is not a major issues, but the resul can differ
197 // from using setlocale(xx, "C").
198 // Previouly, we called setlocale( LC_NUMERIC, "C" )
199 // The old code will be removed when calling wxLocale( "C", "C", "C", false )
200 // is fully tested, and all issues fixed
201 #define USE_WXLOCALE 1 /* 0 to call setlocale, 1 to call wxLocale */
202 
203 // On Windows, when using setlocale, a wx alert is generated
204 // in some cases (reading a bitmap for instance)
205 // So we disable alerts during the time a file is read or written
206 #if !USE_WXLOCALE
207 #if defined( _WIN32 ) && defined( DEBUG )
208 // a wxAssertHandler_t function to filter wxWidgets alert messages when reading/writing a file
209 // when switching the locale to LC_NUMERIC, "C"
210 // It is used in class LOCALE_IO to hide a useless (in kicad) wxWidgets alert message
211 void KiAssertFilter( const wxString &file, int line,
212  const wxString &func, const wxString &cond,
213  const wxString &msg)
214 {
215  if( !msg.Contains( "Decimal separator mismatch" ) )
216  wxTheApp->OnAssertFailure( file.c_str(), line, func.c_str(), cond.c_str(), msg.c_str() );
217 }
218 #endif
219 #endif
220 
221 std::atomic<unsigned int> LOCALE_IO::m_c_count( 0 );
222 LOCALE_IO::LOCALE_IO() : m_wxLocale( nullptr )
223 {
224  // use thread safe, atomic operation
225  if( m_c_count++ == 0 )
226  {
227 #if USE_WXLOCALE
228  m_wxLocale = new wxLocale( "C", "C", "C", false );
229 #else
230  // Store the user locale name, to restore this locale later, in dtor
231  m_user_locale = setlocale( LC_NUMERIC, nullptr );
232 #if defined( _WIN32 ) && defined( DEBUG )
233  // Disable wxWidgets alerts
234  wxSetAssertHandler( KiAssertFilter );
235 #endif
236  // Switch the locale to C locale, to read/write files with fp numbers
237  setlocale( LC_NUMERIC, "C" );
238 #endif
239  }
240 }
241 
242 
244 {
245  // use thread safe, atomic operation
246  if( --m_c_count == 0 )
247  {
248  // revert to the user locale
249 #if USE_WXLOCALE
250  delete m_wxLocale; // Deleting m_wxLocale restored previous locale
251  m_wxLocale = nullptr;
252 #else
253  setlocale( LC_NUMERIC, m_user_locale.c_str() );
254 #if defined( _WIN32 ) && defined( DEBUG )
255  // Enable wxWidgets alerts
256  wxSetDefaultAssertHandler();
257 #endif
258 #endif
259  }
260 }
261 
262 
263 wxSize GetTextSize( const wxString& aSingleLine, wxWindow* aWindow )
264 {
265  wxCoord width;
266  wxCoord height;
267 
268  {
269  wxClientDC dc( aWindow );
270  dc.SetFont( aWindow->GetFont() );
271  dc.GetTextExtent( aSingleLine, &width, &height );
272  }
273 
274  return wxSize( width, height );
275 }
276 
277 
278 bool EnsureTextCtrlWidth( wxTextCtrl* aCtrl, const wxString* aString )
279 {
280  wxWindow* window = aCtrl->GetParent();
281 
282  if( !window )
283  window = aCtrl;
284 
285  wxString ctrlText;
286 
287  if( !aString )
288  {
289  ctrlText = aCtrl->GetValue();
290  aString = &ctrlText;
291  }
292 
293  wxSize textz = GetTextSize( *aString, window );
294  wxSize ctrlz = aCtrl->GetSize();
295 
296  if( ctrlz.GetWidth() < textz.GetWidth() + 10 )
297  {
298  ctrlz.SetWidth( textz.GetWidth() + 10 );
299  aCtrl->SetSizeHints( ctrlz );
300  return true;
301  }
302 
303  return false;
304 }
305 
306 
307 void SelectReferenceNumber( wxTextEntry* aTextEntry )
308 {
309  wxString ref = aTextEntry->GetValue();
310 
311  if( ref.find_first_of( '?' ) != ref.npos )
312  {
313  aTextEntry->SetSelection( ref.find_first_of( '?' ), ref.find_last_of( '?' ) + 1 );
314  }
315  else
316  {
317  wxString num = ref;
318 
319  while( !num.IsEmpty() && ( !isdigit( num.Last() ) || !isdigit( num.GetChar( 0 ) ) ) )
320  {
321  if( !isdigit( num.Last() ) )
322  num.RemoveLast();
323 
324  if( !isdigit( num.GetChar ( 0 ) ) )
325  num = num.Right( num.Length() - 1);
326  }
327 
328  aTextEntry->SetSelection( ref.Find( num ), ref.Find( num ) + num.Length() );
329 
330  if( num.IsEmpty() )
331  aTextEntry->SetSelection( -1, -1 );
332  }
333 }
334 
335 
336 void wxStringSplit( const wxString& aText, wxArrayString& aStrings, wxChar aSplitter )
337 {
338  wxString tmp;
339 
340  for( unsigned ii = 0; ii < aText.Length(); ii++ )
341  {
342  if( aText[ii] == aSplitter )
343  {
344  aStrings.Add( tmp );
345  tmp.Clear();
346  }
347 
348  else
349  tmp << aText[ii];
350  }
351 
352  if( !tmp.IsEmpty() )
353  {
354  aStrings.Add( tmp );
355  }
356 }
357 
358 
359 int ProcessExecute( const wxString& aCommandLine, int aFlags, wxProcess *callback )
360 {
361  return wxExecute( aCommandLine, aFlags, callback );
362 }
363 
364 
366 {
367  static timestamp_t oldTimeStamp;
368  timestamp_t newTimeStamp;
369 
370  newTimeStamp = time( NULL );
371 
372  if( newTimeStamp <= oldTimeStamp )
373  newTimeStamp = oldTimeStamp + 1;
374 
375  oldTimeStamp = newTimeStamp;
376 
377  return newTimeStamp;
378 }
379 
380 
382 {
386 #ifdef __WINDOWS__
387  Bracket_Windows = '%', // yeah, Windows people are a bit strange ;-)
388 #endif
390 };
391 
392 
393 //
394 // Stolen from wxExpandEnvVars and then heavily optimized
395 //
396 wxString KIwxExpandEnvVars(const wxString& str)
397 {
398  size_t strlen = str.length();
399 
400  wxString strResult;
401  strResult.Alloc( strlen );
402 
403  for( size_t n = 0; n < strlen; n++ )
404  {
405  wxUniChar str_n = str[n];
406 
407  switch( str_n.GetValue() )
408  {
409 #ifdef __WINDOWS__
410  case wxT( '%' ):
411 #endif // __WINDOWS__
412  case wxT( '$' ):
413  {
414  Bracket bracket;
415 #ifdef __WINDOWS__
416  if( str_n == wxT( '%' ) )
417  bracket = Bracket_Windows;
418  else
419 #endif // __WINDOWS__
420  if( n == strlen - 1 )
421  {
422  bracket = Bracket_None;
423  }
424  else
425  {
426  switch( str[n + 1].GetValue() )
427  {
428  case wxT( '(' ):
429  bracket = Bracket_Normal;
430  str_n = str[++n]; // skip the bracket
431  break;
432 
433  case wxT( '{' ):
434  bracket = Bracket_Curly;
435  str_n = str[++n]; // skip the bracket
436  break;
437 
438  default:
439  bracket = Bracket_None;
440  }
441  }
442 
443  size_t m = n + 1;
444  wxUniChar str_m = str[m];
445 
446  while( m < strlen && ( wxIsalnum( str_m ) || str_m == wxT( '_' ) ) )
447  str_m = str[++m];
448 
449  wxString strVarName( str.c_str() + n + 1, m - n - 1 );
450 
451  // NB: use wxGetEnv instead of wxGetenv as otherwise variables
452  // set through wxSetEnv may not be read correctly!
453  bool expanded = false;
454  wxString tmp;
455 
456  if( wxGetEnv( strVarName, &tmp ) )
457  {
458  strResult += tmp;
459  expanded = true;
460  }
461  else
462  {
463  // variable doesn't exist => don't change anything
464 #ifdef __WINDOWS__
465  if ( bracket != Bracket_Windows )
466 #endif
467  if ( bracket != Bracket_None )
468  strResult << str[n - 1];
469 
470  strResult << str_n << strVarName;
471  }
472 
473  // check the closing bracket
474  if( bracket != Bracket_None )
475  {
476  if( m == strlen || str_m != (wxChar)bracket )
477  {
478  // under MSW it's common to have '%' characters in the registry
479  // and it's annoying to have warnings about them each time, so
480  // ignore them silently if they are not used for env vars
481  //
482  // under Unix, OTOH, this warning could be useful for the user to
483  // understand why isn't the variable expanded as intended
484 #ifndef __WINDOWS__
485  wxLogWarning( _( "Environment variables expansion failed: missing '%c' "
486  "at position %u in '%s'." ),
487  (char)bracket, (unsigned int) (m + 1), str.c_str() );
488 #endif // __WINDOWS__
489  }
490  else
491  {
492  // skip closing bracket unless the variables wasn't expanded
493  if( !expanded )
494  strResult << (wxChar)bracket;
495 
496  m++;
497  }
498  }
499 
500  n = m - 1; // skip variable name
501  str_n = str[n];
502  }
503  break;
504 
505  case wxT( '\\' ):
506  // backslash can be used to suppress special meaning of % and $
507  if( n != strlen - 1 && (str[n + 1] == wxT( '%' ) || str[n + 1] == wxT( '$' )) )
508  {
509  str_n = str[++n];
510  strResult += str_n;
511 
512  break;
513  }
514  // else fall through
515 
516  default:
517  strResult += str_n;
518  }
519  }
520 
521  return strResult;
522 }
523 
524 
525 const wxString ExpandEnvVarSubstitutions( const wxString& aString )
526 {
527  // wxGetenv( wchar_t* ) is not re-entrant on linux.
528  // Put a lock on multithreaded use of wxGetenv( wchar_t* ), called from wxEpandEnvVars(),
529  static std::mutex getenv_mutex;
530 
531  std::lock_guard<std::mutex> lock( getenv_mutex );
532 
533  // We reserve the right to do this another way, by providing our own member function.
534  return KIwxExpandEnvVars( aString );
535 }
536 
537 
538 const wxString ResolveUriByEnvVars( const wxString& aUri )
539 {
540  // URL-like URI: return as is.
541  wxURL url( aUri );
542 
543  if( url.GetError() == wxURL_NOERR )
544  return aUri;
545 
546  // Otherwise, the path points to a local file. Resolve environment
547  // variables if any.
548  return ExpandEnvVarSubstitutions( aUri );
549 }
550 
551 
552 bool EnsureFileDirectoryExists( wxFileName* aTargetFullFileName,
553  const wxString& aBaseFilename,
554  REPORTER* aReporter )
555 {
556  wxString msg;
557  wxString baseFilePath = wxFileName( aBaseFilename ).GetPath();
558 
559  // make aTargetFullFileName path, which is relative to aBaseFilename path (if it is not
560  // already an absolute path) absolute:
561  if( !aTargetFullFileName->MakeAbsolute( baseFilePath ) )
562  {
563  if( aReporter )
564  {
565  msg.Printf( _( "Cannot make path \"%s\" absolute with respect to \"%s\"." ),
566  aTargetFullFileName->GetPath(),
567  baseFilePath );
568  aReporter->Report( msg, RPT_SEVERITY_ERROR );
569  }
570 
571  return false;
572  }
573 
574  // Ensure the path of aTargetFullFileName exists, and create it if needed:
575  wxString outputPath( aTargetFullFileName->GetPath() );
576 
577  if( !wxFileName::DirExists( outputPath ) )
578  {
579  if( wxMkdir( outputPath ) )
580  {
581  if( aReporter )
582  {
583  msg.Printf( _( "Output directory \"%s\" created.\n" ), outputPath );
584  aReporter->Report( msg, RPT_SEVERITY_INFO );
585  return true;
586  }
587  }
588  else
589  {
590  if( aReporter )
591  {
592  msg.Printf( _( "Cannot create output directory \"%s\".\n" ), outputPath );
593  aReporter->Report( msg, RPT_SEVERITY_ERROR );
594  }
595 
596  return false;
597  }
598  }
599 
600  return true;
601 }
602 
603 
604 #ifdef __WXMAC__
605 wxString GetOSXKicadUserDataDir()
606 {
607  // According to wxWidgets documentation for GetUserDataDir:
608  // Mac: ~/Library/Application Support/appname
609  wxFileName udir( wxStandardPaths::Get().GetUserDataDir(), wxEmptyString );
610 
611  // Since appname is different if started via launcher or standalone binary
612  // map all to "kicad" here
613  udir.RemoveLastDir();
614  udir.AppendDir( "kicad" );
615 
616  return udir.GetPath();
617 }
618 
619 
620 wxString GetOSXKicadMachineDataDir()
621 {
622  return wxT( "/Library/Application Support/kicad" );
623 }
624 
625 
626 wxString GetOSXKicadDataDir()
627 {
628  // According to wxWidgets documentation for GetDataDir:
629  // Mac: appname.app/Contents/SharedSupport bundle subdirectory
630  wxFileName ddir( wxStandardPaths::Get().GetDataDir(), wxEmptyString );
631 
632  // This must be mapped to main bundle for everything but kicad.app
633  const wxArrayString dirs = ddir.GetDirs();
634  if( dirs[dirs.GetCount() - 3] != wxT( "kicad.app" ) )
635  {
636  // Bundle structure resp. current path is
637  // kicad.app/Contents/Applications/<standalone>.app/Contents/SharedSupport
638  // and will be mapped to
639  // kicad.app/Contents/SharedSupprt
640  ddir.RemoveLastDir();
641  ddir.RemoveLastDir();
642  ddir.RemoveLastDir();
643  ddir.RemoveLastDir();
644  ddir.AppendDir( wxT( "SharedSupport" ) );
645  }
646 
647  return ddir.GetPath();
648 }
649 #endif
650 
651 
652 // add this only if it is not in wxWidgets (for instance before 3.1.0)
653 #ifdef USE_KICAD_WXSTRING_HASH
654 size_t std::hash<wxString>::operator()( const wxString& s ) const
655 {
656  return std::hash<std::wstring>{}( s.ToStdWstring() );
657 }
658 #endif
659 
660 #ifdef USE_KICAD_WXPOINT_LESS_AND_HASH
661 size_t std::hash<wxPoint>::operator() ( const wxPoint& k ) const
662 {
663  auto xhash = std::hash<int>()( k.x );
664 
665  // 0x9e3779b9 is 2^33 / ( 1 + sqrt(5) )
666  // Adding this value ensures that consecutive bits of y will not be close to each other
667  // decreasing the likelihood of hash collision in similar values of x and y
668  return xhash ^ ( std::hash<int>()( k.y ) + 0x9e3779b9 + ( xhash << 6 ) + ( xhash >> 2 ) );
669 }
670 
671 bool std::less<wxPoint>::operator()( const wxPoint& aA, const wxPoint& aB ) const
672 {
673  if( aA.x == aB.x )
674  return aA.y < aB.y;
675 
676  return aA.x < aB.x;
677 }
678 #endif
679 
680 
681 std::ostream& operator<<( std::ostream& out, const wxSize& size )
682 {
683  out << " width=\"" << size.GetWidth() << "\" height=\"" << size.GetHeight() << "\"";
684  return out;
685 }
686 
687 
688 std::ostream& operator<<( std::ostream& out, const wxPoint& pt )
689 {
690  out << " x=\"" << pt.x << "\" y=\"" << pt.y << "\"";
691  return out;
692 }
693 
694 
710 WX_FILENAME::WX_FILENAME( const wxString& aPath, const wxString& aFilename ) :
711  m_fn( aPath, aFilename ),
712  m_path( aPath ),
713  m_fullName( aFilename )
714 { }
715 
716 
717 void WX_FILENAME::SetFullName( const wxString& aFileNameAndExtension )
718 {
719  m_fullName = aFileNameAndExtension;
720 }
721 
722 
723 wxString WX_FILENAME::GetName() const
724 {
725  size_t dot = m_fullName.find_last_of( wxT( '.' ) );
726  return m_fullName.substr( 0, dot );
727 }
728 
729 
730 wxString WX_FILENAME::GetFullName() const
731 {
732  return m_fullName;
733 }
734 
735 
736 wxString WX_FILENAME::GetPath() const
737 {
738  return m_path;
739 }
740 
741 
742 wxString WX_FILENAME::GetFullPath() const
743 {
744  return m_path + wxT( '/' ) + m_fullName;
745 }
746 
747 
748 // Write locally-cached values to the wxFileName. MUST be called before using m_fn.
750 {
751  size_t dot = m_fullName.find_last_of( wxT( '.' ) );
752  m_fn.SetName( m_fullName.substr( 0, dot ) );
753  m_fn.SetExt( m_fullName.substr( dot + 1 ) );
754 }
755 
756 
758 {
759  resolve();
760 
761  if( m_fn.FileExists() )
762  return m_fn.GetModificationTime().GetValue().GetValue();
763 
764  return 0;
765 }
766 
767 
774 bool matchWild( const char* pat, const char* text, bool dot_special )
775 {
776  if( !*text )
777  {
778  /* Match if both are empty. */
779  return !*pat;
780  }
781 
782  const char *m = pat,
783  *n = text,
784  *ma = NULL,
785  *na = NULL;
786  int just = 0,
787  acount = 0,
788  count = 0;
789 
790  if( dot_special && (*n == '.') )
791  {
792  /* Never match so that hidden Unix files
793  * are never found. */
794  return false;
795  }
796 
797  for(;;)
798  {
799  if( *m == '*' )
800  {
801  ma = ++m;
802  na = n;
803  just = 1;
804  acount = count;
805  }
806  else if( *m == '?' )
807  {
808  m++;
809 
810  if( !*n++ )
811  return false;
812  }
813  else
814  {
815  if( *m == '\\' )
816  {
817  m++;
818 
819  /* Quoting "nothing" is a bad thing */
820  if( !*m )
821  return false;
822  }
823  if( !*m )
824  {
825  /*
826  * If we are out of both strings or we just
827  * saw a wildcard, then we can say we have a
828  * match
829  */
830  if( !*n )
831  return true;
832 
833  if( just )
834  return true;
835 
836  just = 0;
837  goto not_matched;
838  }
839 
840  /*
841  * We could check for *n == NULL at this point, but
842  * since it's more common to have a character there,
843  * check to see if they match first (m and n) and
844  * then if they don't match, THEN we can check for
845  * the NULL of n
846  */
847  just = 0;
848 
849  if( *m == *n )
850  {
851  m++;
852  count++;
853  n++;
854  }
855  else
856  {
857  not_matched:
858 
859  /*
860  * If there are no more characters in the
861  * string, but we still need to find another
862  * character (*m != NULL), then it will be
863  * impossible to match it
864  */
865  if( !*n )
866  return false;
867 
868  if( ma )
869  {
870  m = ma;
871  n = ++na;
872  count = acount;
873  }
874  else
875  return false;
876  }
877  }
878  }
879 }
880 
881 
886 #if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__)
887 
888 // Convert between wxDateTime and FILETIME which is a 64-bit value representing
889 // the number of 100-nanosecond intervals since January 1, 1601 UTC.
890 //
891 // This is the offset between FILETIME epoch and the Unix/wxDateTime Epoch.
892 static wxInt64 EPOCH_OFFSET_IN_MSEC = wxLL(11644473600000);
893 
894 
895 static void ConvertFileTimeToWx( wxDateTime *dt, const FILETIME &ft )
896 {
897  wxLongLong t( ft.dwHighDateTime, ft.dwLowDateTime );
898  t /= 10000; // Convert hundreds of nanoseconds to milliseconds.
899  t -= EPOCH_OFFSET_IN_MSEC;
900 
901  *dt = wxDateTime( t );
902 }
903 
904 #endif // wxUSE_DATETIME && __WIN32__
905 
906 
916 long long TimestampDir( const wxString& aDirPath, const wxString& aFilespec )
917 {
918  long long timestamp = 0;
919 
920 #if defined( __WIN32__ )
921  // Win32 version.
922  // Save time by not searching for each path twice: once in wxDir.GetNext() and once in
923  // wxFileName.GetModificationTime(). Also cuts out wxWidgets' string-matching and case
924  // conversion by staying on the MSW side of things.
925  std::wstring filespec( aDirPath.t_str() );
926  filespec += '\\';
927  filespec += aFilespec.t_str();
928 
929  WIN32_FIND_DATA findData;
930  wxDateTime lastModDate;
931 
932  HANDLE fileHandle = ::FindFirstFile( filespec.data(), &findData );
933 
934  if( fileHandle != INVALID_HANDLE_VALUE )
935  {
936  do
937  {
938  ConvertFileTimeToWx( &lastModDate, findData.ftLastWriteTime );
939  timestamp += lastModDate.GetValue().GetValue();
940  }
941  while ( FindNextFile( fileHandle, &findData ) != 0 );
942  }
943 
944  FindClose( fileHandle );
945 #else
946  // POSIX version.
947  // Save time by not converting between encodings -- do everything on the file-system side.
948  std::string filespec( aFilespec.fn_str() );
949  std::string dir_path( aDirPath.fn_str() );
950 
951  DIR* dir = opendir( dir_path.c_str() );
952 
953  if( dir )
954  {
955  for( dirent* dir_entry = readdir( dir ); dir_entry; dir_entry = readdir( dir ) )
956  {
957  if( !matchWild( filespec.c_str(), dir_entry->d_name, true ) )
958  continue;
959 
960  std::string entry_path = dir_path + '/' + dir_entry->d_name;
961  struct stat entry_stat;
962 
963  if( wxCRT_Lstat( entry_path.c_str(), &entry_stat ) == 0 )
964  {
965  // Timestamp the source file, not the symlink
966  if( S_ISLNK( entry_stat.st_mode ) ) // wxFILE_EXISTS_SYMLINK
967  {
968  char buffer[ PATH_MAX + 1 ];
969  ssize_t pathLen = readlink( entry_path.c_str(), buffer, PATH_MAX );
970 
971  if( pathLen > 0 )
972  {
973  struct stat linked_stat;
974  buffer[ pathLen ] = '\0';
975  entry_path = dir_path + buffer;
976 
977  if( wxCRT_Lstat( entry_path.c_str(), &linked_stat ) == 0 )
978  {
979  entry_stat = linked_stat;
980  }
981  else
982  {
983  // if we couldn't lstat the linked file we'll have to just use
984  // the symbolic link info
985  }
986  }
987  }
988 
989  if( S_ISREG( entry_stat.st_mode ) ) // wxFileExists()
990  timestamp += entry_stat.st_mtime * 1000;
991  }
992  else
993  {
994  // if we couldn't lstat the file itself all we can do is use the name
995  timestamp += (signed) std::hash<std::string>{}( std::string( dir_entry->d_name ) );
996  }
997  }
998 
999  closedir( dir );
1000  }
1001 #endif
1002 
1003  return timestamp;
1004 }
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
Definition: common.cpp:336
WX_FILENAME(const wxString &aPath, const wxString &aFilename)
Performance enhancements to file and directory operations.
Definition: common.cpp:710
int ProcessExecute(const wxString &aCommandLine, int aFlags, wxProcess *callback)
Run a command in a child process.
Definition: common.cpp:359
~LOCALE_IO()
Definition: common.cpp:243
KIID()
Definition: common.cpp:57
const wxString ResolveUriByEnvVars(const wxString &aUri)
Replace any environment variables in file-path uris (leaving network-path URIs alone).
Definition: common.cpp:538
wxString KIwxExpandEnvVars(const wxString &str)
Definition: common.cpp:396
wxLocale * m_wxLocale
Definition: common.h:215
wxString GetName() const
Definition: common.cpp:723
static boost::uuids::string_generator stringGenerator
Definition: common.cpp:50
wxString AsString() const
Definition: common.cpp:170
wxString GetFullName() const
Definition: common.cpp:730
wxString m_path
Definition: common.h:411
boost::uuids::uuid m_uuid
Definition: common.h:99
size_t operator()(const wxPoint &k) const
Definition: common.cpp:661
REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:62
void SetFullName(const wxString &aFileNameAndExtension)
Definition: common.cpp:717
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
static boost::uuids::nil_generator nilGenerator
Definition: common.cpp:51
bool IsLegacyTimestamp() const
Definition: common.cpp:137
timestamp_t m_cached_timestamp
Definition: common.h:101
This file contains miscellaneous commonly used macros and functions.
wxSize GetTextSize(const wxString &aSingleLine, wxWindow *aWindow)
Return the size of aSingleLine of text when it is rendered in aWindow using whatever font is currentl...
Definition: common.cpp:263
wxFileName m_fn
Definition: common.h:410
static std::atomic< unsigned int > m_c_count
Definition: common.h:210
void SelectReferenceNumber(wxTextEntry *aTextEntry)
Select the number (or "?") in a reference for ease of editing.
Definition: common.cpp:307
Definition: common.h:65
long long GetTimestamp()
Definition: common.cpp:757
timestamp_t GetNewTimeStamp()
Definition: common.cpp:365
void resolve()
Definition: common.cpp:749
size_t Hash() const
Definition: common.cpp:149
bool EnsureTextCtrlWidth(wxTextCtrl *aCtrl, const wxString *aString)
Set the minimum pixel width on a text control in order to make a text string be fully visible within ...
Definition: common.cpp:278
#define NULL
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Replace any environment variable references with their values.
Definition: common.cpp:525
timestamp_t AsLegacyTimestamp() const
Definition: common.cpp:143
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.
Definition: common.cpp:552
Bracket
Definition: common.cpp:381
bool operator()(const wxPoint &aA, const wxPoint &aB) const
Definition: common.cpp:671
KIID niluuid(0)
static boost::uuids::random_generator randomGenerator
Definition: common.cpp:47
Base window classes and related definitions.
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/...
Definition: common.cpp:916
LOCALE_IO()
Definition: common.cpp:222
bool matchWild(const char *pat, const char *text, bool dot_special)
A copy of wxMatchWild(), which wxWidgets attributes to Douglas A.
Definition: common.cpp:774
wxString GetPath() const
Definition: common.cpp:736
void Clone(const KIID &aUUID)
Definition: common.cpp:163
wxString GetFullPath() const
Definition: common.cpp:742
wxString AsLegacyTimestampString() const
Definition: common.cpp:176
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
#define _(s)
Definition: 3d_actions.cpp:33
The common library.
uint32_t timestamp_t
timestamp_t is our type to represent unique IDs for all kinds of elements; historically simply the ti...
Definition: common.h:53
wxString m_fullName
Definition: common.h:412
std::string m_user_locale
Definition: common.h:214
std::ostream & operator<<(std::ostream &out, const wxSize &size)
Helper function to print the given wxSize to a stream.
Definition: common.cpp:681
size_t operator()(const wxString &s) const
Definition: common.cpp:654
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:40