]> git.saurik.com Git - wxWidgets.git/blob - src/common/filename.cpp
Restored wxFileName::GetModificationTime() under Classic.
[wxWidgets.git] / src / common / filename.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/filename.cpp
3 // Purpose: wxFileName - encapsulates a file path
4 // Author: Robert Roebling, Vadim Zeitlin
5 // Modified by:
6 // Created: 28.12.2000
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000 Robert Roebling
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "filename.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/intl.h"
33 #include "wx/log.h"
34 #endif
35
36 #include "wx/filename.h"
37 #include "wx/tokenzr.h"
38 #include "wx/config.h" // for wxExpandEnvVars
39 #include "wx/utils.h"
40
41 #if wxUSE_DYNLIB_CLASS
42 #include "wx/dynlib.h"
43 #endif
44
45 // For GetShort/LongPathName
46 #ifdef __WIN32__
47 #include <windows.h>
48
49 #include "wx/msw/winundef.h"
50 #endif
51
52 // utime() is POSIX so should normally be available on all Unices
53 #ifdef __UNIX_LIKE__
54 #include <sys/types.h>
55 #include <utime.h>
56 #include <sys/stat.h>
57 #include <unistd.h>
58 #endif
59
60 #ifdef __MWERKS__
61 #include <stat.h>
62 #include <unistd.h>
63 #include <unix.h>
64 #endif
65
66 // ----------------------------------------------------------------------------
67 // private classes
68 // ----------------------------------------------------------------------------
69
70 // small helper class which opens and closes the file - we use it just to get
71 // a file handle for the given file name to pass it to some Win32 API function
72 #ifdef __WIN32__
73
74 class wxFileHandle
75 {
76 public:
77 wxFileHandle(const wxString& filename)
78 {
79 m_hFile = ::CreateFile
80 (
81 filename, // name
82 GENERIC_READ, // access mask
83 0, // no sharing
84 NULL, // no secutity attr
85 OPEN_EXISTING, // creation disposition
86 0, // no flags
87 NULL // no template file
88 );
89
90 if ( m_hFile == INVALID_HANDLE_VALUE )
91 {
92 wxLogSysError(_("Failed to open '%s' for reading"),
93 filename.c_str());
94 }
95 }
96
97 ~wxFileHandle()
98 {
99 if ( m_hFile != INVALID_HANDLE_VALUE )
100 {
101 if ( !::CloseHandle(m_hFile) )
102 {
103 wxLogSysError(_("Failed to close file handle"));
104 }
105 }
106 }
107
108 // return TRUE only if the file could be opened successfully
109 bool IsOk() const { return m_hFile != INVALID_HANDLE_VALUE; }
110
111 // get the handle
112 operator HANDLE() const { return m_hFile; }
113
114 private:
115 HANDLE m_hFile;
116 };
117
118 #endif // __WIN32__
119
120 // ----------------------------------------------------------------------------
121 // private functions
122 // ----------------------------------------------------------------------------
123
124 #ifdef __WIN32__
125
126 // convert between wxDateTime and FILETIME which is a 64-bit value representing
127 // the number of 100-nanosecond intervals since January 1, 1601.
128
129 // the number of milliseconds between the Unix Epoch (January 1, 1970) and the
130 // FILETIME reference point (January 1, 1601)
131 static const wxLongLong FILETIME_EPOCH_OFFSET = wxLongLong(0xa97, 0x30b66800);
132
133 static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft)
134 {
135 wxLongLong ll(ft.dwHighDateTime, ft.dwLowDateTime);
136
137 // convert 100ns to ms
138 ll /= 10000;
139
140 // move it to our Epoch
141 ll -= FILETIME_EPOCH_OFFSET;
142
143 *dt = wxDateTime(ll);
144 }
145
146 static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt)
147 {
148 // do the reverse of ConvertFileTimeToWx()
149 wxLongLong ll = dt.GetValue();
150 ll *= 10000;
151 ll += FILETIME_EPOCH_OFFSET;
152
153 ft->dwHighDateTime = ll.GetHi();
154 ft->dwLowDateTime = ll.GetLo();
155 }
156
157 #endif // __WIN32__
158
159 // ============================================================================
160 // implementation
161 // ============================================================================
162
163 // ----------------------------------------------------------------------------
164 // wxFileName construction
165 // ----------------------------------------------------------------------------
166
167 void wxFileName::Assign( const wxFileName &filepath )
168 {
169 m_ext = filepath.GetExt();
170 m_name = filepath.GetName();
171 m_dirs = filepath.GetDirs();
172 }
173
174 void wxFileName::Assign( const wxString& path,
175 const wxString& name,
176 const wxString& ext,
177 wxPathFormat format )
178 {
179 wxStringTokenizer tn(path, GetPathSeparators(format),
180 wxTOKEN_RET_EMPTY_ALL);
181 int i = 0;
182 m_dirs.Clear();
183 while ( tn.HasMoreTokens() )
184 {
185 wxString token = tn.GetNextToken();
186
187 // If the path starts with a slash (or two for a network path),
188 // we need the first dir entry to be an empty for later reassembly.
189 if ((i < 2) || !token.IsEmpty())
190 m_dirs.Add( token );
191
192 i ++;
193 }
194
195 m_ext = ext;
196 m_name = name;
197 }
198
199 void wxFileName::Assign(const wxString& fullpath,
200 wxPathFormat format)
201 {
202 wxString path, name, ext;
203 SplitPath(fullpath, &path, &name, &ext, format);
204
205 Assign(path, name, ext, format);
206 }
207
208 void wxFileName::Assign(const wxString& path,
209 const wxString& fullname,
210 wxPathFormat format)
211 {
212 wxString name, ext;
213 SplitPath(fullname, NULL /* no path */, &name, &ext, format);
214
215 Assign(path, name, ext, format);
216 }
217
218 void wxFileName::Clear()
219 {
220 m_dirs.Clear();
221 m_name =
222 m_ext = wxEmptyString;
223 }
224
225 /* static */
226 wxFileName wxFileName::FileName(const wxString& file)
227 {
228 return wxFileName(file);
229 }
230
231 /* static */
232 wxFileName wxFileName::DirName(const wxString& dir)
233 {
234 wxFileName fn;
235 fn.AssignDir(dir);
236 return fn;
237 }
238
239 // ----------------------------------------------------------------------------
240 // existence tests
241 // ----------------------------------------------------------------------------
242
243 bool wxFileName::FileExists()
244 {
245 return wxFileName::FileExists( GetFullPath() );
246 }
247
248 bool wxFileName::FileExists( const wxString &file )
249 {
250 return ::wxFileExists( file );
251 }
252
253 bool wxFileName::DirExists()
254 {
255 return wxFileName::DirExists( GetFullPath() );
256 }
257
258 bool wxFileName::DirExists( const wxString &dir )
259 {
260 return ::wxDirExists( dir );
261 }
262
263 // ----------------------------------------------------------------------------
264 // CWD and HOME stuff
265 // ----------------------------------------------------------------------------
266
267 void wxFileName::AssignCwd()
268 {
269 AssignDir(wxFileName::GetCwd());
270 }
271
272 /* static */
273 wxString wxFileName::GetCwd()
274 {
275 return ::wxGetCwd();
276 }
277
278 bool wxFileName::SetCwd()
279 {
280 return wxFileName::SetCwd( GetFullPath() );
281 }
282
283 bool wxFileName::SetCwd( const wxString &cwd )
284 {
285 return ::wxSetWorkingDirectory( cwd );
286 }
287
288 void wxFileName::AssignHomeDir()
289 {
290 AssignDir(wxFileName::GetHomeDir());
291 }
292
293 wxString wxFileName::GetHomeDir()
294 {
295 return ::wxGetHomeDir();
296 }
297
298 void wxFileName::AssignTempFileName( const wxString &prefix )
299 {
300 wxString fullname;
301 if ( wxGetTempFileName(prefix, fullname) )
302 {
303 Assign(fullname);
304 }
305 else // error
306 {
307 Clear();
308 }
309 }
310
311 // ----------------------------------------------------------------------------
312 // directory operations
313 // ----------------------------------------------------------------------------
314
315 bool wxFileName::Mkdir( int perm, bool full )
316 {
317 return wxFileName::Mkdir( GetFullPath(), perm, full );
318 }
319
320 bool wxFileName::Mkdir( const wxString &dir, int perm, bool full )
321 {
322 if (full)
323 {
324 wxFileName filename(dir);
325 wxArrayString dirs = filename.GetDirs();
326 dirs.Add(filename.GetName());
327
328 size_t count = dirs.GetCount();
329 size_t i;
330 wxString currPath;
331 int noErrors = 0;
332 for ( i = 0; i < count; i++ )
333 {
334 currPath += dirs[i];
335
336 if (currPath.Last() == wxT(':'))
337 {
338 // Can't create a root directory so continue to next dir
339 currPath += wxFILE_SEP_PATH;
340 continue;
341 }
342
343 if (!DirExists(currPath))
344 if (!wxMkdir(currPath, perm))
345 noErrors ++;
346
347 if ( (i < (count-1)) )
348 currPath += wxFILE_SEP_PATH;
349 }
350
351 return (noErrors == 0);
352
353 }
354 else
355 return ::wxMkdir( dir, perm );
356 }
357
358 bool wxFileName::Rmdir()
359 {
360 return wxFileName::Rmdir( GetFullPath() );
361 }
362
363 bool wxFileName::Rmdir( const wxString &dir )
364 {
365 return ::wxRmdir( dir );
366 }
367
368 // ----------------------------------------------------------------------------
369 // path normalization
370 // ----------------------------------------------------------------------------
371
372 bool wxFileName::Normalize(wxPathNormalize flags,
373 const wxString& cwd,
374 wxPathFormat format)
375 {
376 // the existing path components
377 wxArrayString dirs = GetDirs();
378
379 // the path to prepend in front to make the path absolute
380 wxFileName curDir;
381
382 format = GetFormat(format);
383
384 // make the path absolute
385 if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute() )
386 {
387 if ( cwd.empty() )
388 curDir.AssignCwd();
389 else
390 curDir.AssignDir(cwd);
391 }
392
393 // handle ~ stuff under Unix only
394 if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) )
395 {
396 if ( !dirs.IsEmpty() )
397 {
398 wxString dir = dirs[0u];
399 if ( !dir.empty() && dir[0u] == _T('~') )
400 {
401 curDir.AssignDir(wxGetUserHome(dir.c_str() + 1));
402
403 dirs.RemoveAt(0u);
404 }
405 }
406 }
407
408 if ( curDir.IsOk() )
409 {
410 wxArrayString dirsNew = curDir.GetDirs();
411 size_t count = dirs.GetCount();
412 for ( size_t n = 0; n < count; n++ )
413 {
414 dirsNew.Add(dirs[n]);
415 }
416
417 dirs = dirsNew;
418 }
419
420 // now deal with ".", ".." and the rest
421 m_dirs.Empty();
422 size_t count = dirs.GetCount();
423 for ( size_t n = 0; n < count; n++ )
424 {
425 wxString dir = dirs[n];
426
427 if ( flags && wxPATH_NORM_DOTS )
428 {
429 if ( dir == wxT(".") )
430 {
431 // just ignore
432 continue;
433 }
434
435 if ( dir == wxT("..") )
436 {
437 if ( m_dirs.IsEmpty() )
438 {
439 wxLogError(_("The path '%s' contains too many \"..\"!"),
440 GetFullPath().c_str());
441 return FALSE;
442 }
443
444 m_dirs.Remove(m_dirs.GetCount() - 1);
445 continue;
446 }
447 }
448
449 if ( flags & wxPATH_NORM_ENV_VARS )
450 {
451 dir = wxExpandEnvVars(dir);
452 }
453
454 if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
455 {
456 dir.MakeLower();
457 }
458
459 m_dirs.Add(dir);
460 }
461
462 if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
463 {
464 // VZ: expand env vars here too?
465
466 m_name.MakeLower();
467 m_ext.MakeLower();
468 }
469
470 #if defined(__WXMSW__) && defined(__WIN32__)
471 if (flags & wxPATH_NORM_LONG)
472 {
473 Assign(GetLongPath());
474 }
475 #endif
476
477 return TRUE;
478 }
479
480 // ----------------------------------------------------------------------------
481 // filename kind tests
482 // ----------------------------------------------------------------------------
483
484 bool wxFileName::SameAs( const wxFileName &filepath, wxPathFormat format)
485 {
486 wxFileName fn1 = *this,
487 fn2 = filepath;
488
489 // get cwd only once - small time saving
490 wxString cwd = wxGetCwd();
491 fn1.Normalize(wxPATH_NORM_ALL, cwd, format);
492 fn2.Normalize(wxPATH_NORM_ALL, cwd, format);
493
494 if ( fn1.GetFullPath() == fn2.GetFullPath() )
495 return TRUE;
496
497 // TODO: compare inodes for Unix, this works even when filenames are
498 // different but files are the same (symlinks) (VZ)
499
500 return FALSE;
501 }
502
503 /* static */
504 bool wxFileName::IsCaseSensitive( wxPathFormat format )
505 {
506 // only DOS and OpenVMS filenames are case-sensitive
507 return ( GetFormat(format) != wxPATH_DOS &
508 GetFormat(format) != wxPATH_VMS );
509 }
510
511 bool wxFileName::IsRelative( wxPathFormat format )
512 {
513 return !IsAbsolute(format);
514 }
515
516 bool wxFileName::IsAbsolute( wxPathFormat format )
517 {
518 wxChar ch = m_dirs.IsEmpty() ? _T('\0') : m_dirs[0u][0u];
519
520 // Hack to cope with e.g. c:\thing - need something better
521 wxChar driveSep = _T('\0');
522 if (!m_dirs.IsEmpty() && m_dirs[0].Length() > 1)
523 driveSep = m_dirs[0u][1u];
524
525 // the path is absolute if it starts with a path separator or, only for
526 // Unix filenames, with "~" or "~user"
527 return IsPathSeparator(ch, format) ||
528 driveSep == _T(':') ||
529 (GetFormat(format) == wxPATH_UNIX && ch == _T('~') );
530 }
531
532 /* static */
533 wxString wxFileName::GetPathSeparators(wxPathFormat format)
534 {
535 wxString seps;
536 switch ( GetFormat(format) )
537 {
538 case wxPATH_DOS:
539 // accept both as native APIs do
540 seps << wxFILE_SEP_PATH_UNIX << wxFILE_SEP_PATH_DOS;
541 break;
542
543 default:
544 wxFAIL_MSG( _T("unknown wxPATH_XXX style") );
545 // fall through
546
547 case wxPATH_UNIX:
548 seps = wxFILE_SEP_PATH_UNIX;
549 break;
550
551 case wxPATH_MAC:
552 seps = wxFILE_SEP_PATH_MAC;
553 break;
554
555 case wxPATH_VMS:
556 seps = wxFILE_SEP_PATH_VMS;
557 break;
558 }
559
560 return seps;
561 }
562
563 /* static */
564 bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format)
565 {
566 return GetPathSeparators(format).Find(ch) != wxNOT_FOUND;
567 }
568
569 bool wxFileName::IsWild( wxPathFormat format )
570 {
571 // FIXME: this is probably false for Mac and this is surely wrong for most
572 // of Unix shells (think about "[...]")
573 (void)format;
574 return m_name.find_first_of(_T("*?")) != wxString::npos;
575 }
576
577 // ----------------------------------------------------------------------------
578 // path components manipulation
579 // ----------------------------------------------------------------------------
580
581 void wxFileName::AppendDir( const wxString &dir )
582 {
583 m_dirs.Add( dir );
584 }
585
586 void wxFileName::PrependDir( const wxString &dir )
587 {
588 m_dirs.Insert( dir, 0 );
589 }
590
591 void wxFileName::InsertDir( int before, const wxString &dir )
592 {
593 m_dirs.Insert( dir, before );
594 }
595
596 void wxFileName::RemoveDir( int pos )
597 {
598 m_dirs.Remove( (size_t)pos );
599 }
600
601 // ----------------------------------------------------------------------------
602 // accessors
603 // ----------------------------------------------------------------------------
604
605 void wxFileName::SetFullName(const wxString& fullname)
606 {
607 SplitPath(fullname, NULL /* no path */, &m_name, &m_ext);
608 }
609
610 wxString wxFileName::GetFullName() const
611 {
612 wxString fullname = m_name;
613 if ( !m_ext.empty() )
614 {
615 fullname << wxFILE_SEP_EXT << m_ext;
616 }
617
618 return fullname;
619 }
620
621 wxString wxFileName::GetPath( bool add_separator, wxPathFormat format ) const
622 {
623 format = GetFormat( format );
624
625 wxString ret;
626 size_t count = m_dirs.GetCount();
627 for ( size_t i = 0; i < count; i++ )
628 {
629 ret += m_dirs[i];
630 if ( add_separator || (i < count) )
631 ret += wxFILE_SEP_PATH;
632 }
633
634 return ret;
635 }
636
637 wxString wxFileName::GetFullPath( wxPathFormat format ) const
638 {
639 format = GetFormat( format );
640
641 wxString ret;
642 if (format == wxPATH_DOS)
643 {
644 for (size_t i = 0; i < m_dirs.GetCount(); i++)
645 {
646 ret += m_dirs[i];
647 ret += '\\';
648 }
649 }
650 else
651 if (format == wxPATH_UNIX)
652 {
653 for (size_t i = 0; i < m_dirs.GetCount(); i++)
654 {
655 ret += m_dirs[i];
656 ret += '/';
657 }
658 }
659 else
660 if (format == wxPATH_VMS)
661 {
662 ret += '[';
663 for (size_t i = 0; i < m_dirs.GetCount(); i++)
664 {
665 ret += '.';
666 ret += m_dirs[i];
667 }
668 ret += ']';
669 }
670 else
671 {
672 for (size_t i = 0; i < m_dirs.GetCount(); i++)
673 {
674 ret += m_dirs[i];
675 ret += ':';
676 }
677 }
678
679 ret += m_name;
680
681 if (!m_ext.IsEmpty())
682 {
683 ret += '.';
684 ret += m_ext;
685 }
686
687 return ret;
688 }
689
690 // Return the short form of the path (returns identity on non-Windows platforms)
691 wxString wxFileName::GetShortPath() const
692 {
693 #if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__)
694 wxString path(GetFullPath());
695 wxString pathOut;
696 DWORD sz = ::GetShortPathName(path, NULL, 0);
697 bool ok = sz != 0;
698 if ( ok )
699 {
700 ok = ::GetShortPathName
701 (
702 path,
703 pathOut.GetWriteBuf(sz),
704 sz
705 ) != 0;
706 pathOut.UngetWriteBuf();
707 }
708 if (ok)
709 return pathOut;
710
711 return path;
712 #else
713 return GetFullPath();
714 #endif
715 }
716
717 // Return the long form of the path (returns identity on non-Windows platforms)
718 wxString wxFileName::GetLongPath() const
719 {
720 #if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__)
721 wxString path(GetFullPath());
722 wxString pathOut;
723 bool success = FALSE;
724
725 // VZ: this code was disabled, why?
726 #if 0 // wxUSE_DYNLIB_CLASS
727 typedef DWORD (*GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD);
728
729 static bool s_triedToLoad = FALSE;
730
731 if ( !s_triedToLoad )
732 {
733 s_triedToLoad = TRUE;
734 wxDllType dllKernel = wxDllLoader::LoadLibrary(_T("kernel32"));
735 if ( dllKernel )
736 {
737 // may succeed or fail depending on the Windows version
738 static GET_LONG_PATH_NAME s_pfnGetLongPathName = NULL;
739 #ifdef _UNICODE
740 s_pfnGetLongPathName = (GET_LONG_PATH_NAME) wxDllLoader::GetSymbol(dllKernel, _T("GetLongPathNameW"));
741 #else
742 s_pfnGetLongPathName = (GET_LONG_PATH_NAME) wxDllLoader::GetSymbol(dllKernel, _T("GetLongPathNameA"));
743 #endif
744
745 wxDllLoader::UnloadLibrary(dllKernel);
746
747 if ( s_pfnGetLongPathName )
748 {
749 DWORD dwSize = (*s_pfnGetLongPathName)(path, NULL, 0);
750 bool ok = dwSize > 0;
751
752 if ( ok )
753 {
754 DWORD sz = (*s_pfnGetLongPathName)(path, NULL, 0);
755 ok = sz != 0;
756 if ( ok )
757 {
758 ok = (*s_pfnGetLongPathName)
759 (
760 path,
761 pathOut.GetWriteBuf(sz),
762 sz
763 ) != 0;
764 pathOut.UngetWriteBuf();
765
766 success = TRUE;
767 }
768 }
769 }
770 }
771 }
772 if (success)
773 return pathOut;
774 #endif // wxUSE_DYNLIB_CLASS
775
776 if (!success)
777 {
778 // The OS didn't support GetLongPathName, or some other error.
779 // We need to call FindFirstFile on each component in turn.
780
781 WIN32_FIND_DATA findFileData;
782 HANDLE hFind;
783 pathOut = wxEmptyString;
784
785 wxArrayString dirs = GetDirs();
786 dirs.Add(GetFullName());
787
788 size_t count = dirs.GetCount();
789 size_t i;
790 wxString tmpPath;
791
792 for ( i = 0; i < count; i++ )
793 {
794 // We're using pathOut to collect the long-name path,
795 // but using a temporary for appending the last path component which may be short-name
796 tmpPath = pathOut + dirs[i];
797
798 if (tmpPath.Last() == wxT(':'))
799 {
800 // Can't pass a drive and root dir to FindFirstFile,
801 // so continue to next dir
802 tmpPath += wxFILE_SEP_PATH;
803 pathOut = tmpPath;
804 continue;
805 }
806
807 hFind = ::FindFirstFile(tmpPath, &findFileData);
808 if (hFind == INVALID_HANDLE_VALUE)
809 {
810 // Error: return immediately with the original path
811 return path;
812 }
813 else
814 {
815 pathOut += findFileData.cFileName;
816 if ( (i < (count-1)) )
817 pathOut += wxFILE_SEP_PATH;
818
819 ::FindClose(hFind);
820 }
821 }
822 }
823
824 return pathOut;
825 #else
826 return GetFullPath();
827 #endif
828 }
829
830 wxPathFormat wxFileName::GetFormat( wxPathFormat format )
831 {
832 if (format == wxPATH_NATIVE)
833 {
834 #if defined(__WXMSW__) || defined(__WXPM__)
835 format = wxPATH_DOS;
836 #elif defined(__WXMAC__) && !defined(__DARWIN__)
837 format = wxPATH_MAC;
838 #elif defined(__VMS)
839 format = wxPATH_VMS;
840 #else
841 format = wxPATH_UNIX;
842 #endif
843 }
844 return format;
845 }
846
847 // ----------------------------------------------------------------------------
848 // path splitting function
849 // ----------------------------------------------------------------------------
850
851 void wxFileName::SplitPath(const wxString& fullpath,
852 wxString *pstrPath,
853 wxString *pstrName,
854 wxString *pstrExt,
855 wxPathFormat format)
856 {
857 format = GetFormat(format);
858
859 // find the positions of the last dot and last path separator in the path
860 size_t posLastDot = fullpath.find_last_of(wxFILE_SEP_EXT);
861 size_t posLastSlash = fullpath.find_last_of(GetPathSeparators(format));
862
863 if ( (posLastDot != wxString::npos) && (format == wxPATH_UNIX) )
864 {
865 if ( (posLastDot == 0) ||
866 (fullpath[posLastDot - 1] == wxFILE_SEP_PATH_UNIX) )
867 {
868 // under Unix, dot may be (and commonly is) the first character of
869 // the filename, don't treat the entire filename as extension in
870 // this case
871 posLastDot = wxString::npos;
872 }
873 }
874 else
875 if ( (posLastDot != wxString::npos) && (format == wxPATH_VMS) )
876 {
877 if ( (posLastDot == 0) ||
878 (fullpath[posLastDot - 1] == ']' ) )
879 {
880 // under OpenVMS, dot may be (and commonly is) the first character of
881 // the filename, don't treat the entire filename as extension in
882 // this case
883 posLastDot = wxString::npos;
884 }
885 }
886
887 // if we do have a dot and a slash, check that the dot is in the name part
888 if ( (posLastDot != wxString::npos) &&
889 (posLastSlash != wxString::npos) &&
890 (posLastDot < posLastSlash) )
891 {
892 // the dot is part of the path, not the start of the extension
893 posLastDot = wxString::npos;
894 }
895
896 // now fill in the variables provided by user
897 if ( pstrPath )
898 {
899 if ( posLastSlash == wxString::npos )
900 {
901 // no path at all
902 pstrPath->Empty();
903 }
904 else
905 {
906 // take all until the separator
907 *pstrPath = fullpath.Left(posLastSlash);
908 }
909 }
910
911 if ( pstrName )
912 {
913 // take all characters starting from the one after the last slash and
914 // up to, but excluding, the last dot
915 size_t nStart = posLastSlash == wxString::npos ? 0 : posLastSlash + 1;
916 size_t count;
917 if ( posLastDot == wxString::npos )
918 {
919 // take all until the end
920 count = wxString::npos;
921 }
922 else if ( posLastSlash == wxString::npos )
923 {
924 count = posLastDot;
925 }
926 else // have both dot and slash
927 {
928 count = posLastDot - posLastSlash - 1;
929 }
930
931 *pstrName = fullpath.Mid(nStart, count);
932 }
933
934 if ( pstrExt )
935 {
936 if ( posLastDot == wxString::npos )
937 {
938 // no extension
939 pstrExt->Empty();
940 }
941 else
942 {
943 // take everything after the dot
944 *pstrExt = fullpath.Mid(posLastDot + 1);
945 }
946 }
947 }
948
949 // ----------------------------------------------------------------------------
950 // time functions
951 // ----------------------------------------------------------------------------
952
953 bool wxFileName::SetTimes(const wxDateTime *dtCreate,
954 const wxDateTime *dtAccess,
955 const wxDateTime *dtMod)
956 {
957 #if defined(__UNIX_LIKE__)
958 if ( !dtAccess && !dtMod )
959 {
960 // can't modify the creation time anyhow, don't try
961 return TRUE;
962 }
963
964 // if dtAccess or dtMod is not specified, use the other one (which must be
965 // non NULL because of the test above) for both times
966 utimbuf utm;
967 utm.actime = dtAccess ? dtAccess->GetTicks() : dtMod->GetTicks();
968 utm.modtime = dtMod ? dtMod->GetTicks() : dtAccess->GetTicks();
969 if ( utime(GetFullPath(), &utm) == 0 )
970 {
971 return TRUE;
972 }
973 #elif defined(__WIN32__)
974 wxFileHandle fh(GetFullPath());
975 if ( fh.IsOk() )
976 {
977 FILETIME ftAccess, ftCreate, ftWrite;
978
979 if ( dtCreate )
980 ConvertWxToFileTime(&ftCreate, *dtCreate);
981 if ( dtAccess )
982 ConvertWxToFileTime(&ftAccess, *dtAccess);
983 if ( dtMod )
984 ConvertWxToFileTime(&ftWrite, *dtMod);
985
986 if ( ::SetFileTime(fh,
987 dtCreate ? &ftCreate : NULL,
988 dtAccess ? &ftAccess : NULL,
989 dtMod ? &ftWrite : NULL) )
990 {
991 return TRUE;
992 }
993 }
994 #else // other platform
995 #endif // platforms
996
997 wxLogSysError(_("Failed to modify file times for '%s'"),
998 GetFullPath().c_str());
999
1000 return FALSE;
1001 }
1002
1003 bool wxFileName::Touch()
1004 {
1005 #if defined(__UNIX_LIKE__)
1006 // under Unix touching file is simple: just pass NULL to utime()
1007 if ( utime(GetFullPath(), NULL) == 0 )
1008 {
1009 return TRUE;
1010 }
1011
1012 wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str());
1013
1014 return FALSE;
1015 #else // other platform
1016 wxDateTime dtNow = wxDateTime::Now();
1017
1018 return SetTimes(NULL /* don't change create time */, &dtNow, &dtNow);
1019 #endif // platforms
1020 }
1021
1022 bool wxFileName::GetTimes(wxDateTime *dtAccess,
1023 wxDateTime *dtMod,
1024 wxDateTime *dtChange) const
1025 {
1026 #if defined(__UNIX_LIKE__)
1027 wxStructStat stBuf;
1028 if ( wxStat(GetFullPath(), &stBuf) == 0 )
1029 {
1030 if ( dtAccess )
1031 dtAccess->Set(stBuf.st_atime);
1032 if ( dtMod )
1033 dtMod->Set(stBuf.st_mtime);
1034 if ( dtChange )
1035 dtChange->Set(stBuf.st_ctime);
1036
1037 return TRUE;
1038 }
1039 #elif defined(__WXMAC__)
1040 wxStructStat stBuf;
1041 if ( wxStat(GetFullPath(), &stBuf) == 0 )
1042 {
1043 if ( dtAccess )
1044 dtAccess->Set(stBuf.st_atime);
1045 if ( dtMod )
1046 dtMod->Set(stBuf.st_mtime);
1047 if ( dtChange )
1048 dtChange->Set(stBuf.st_ctime);
1049
1050 return TRUE;
1051 }
1052 #elif defined(__WIN32__)
1053 wxFileHandle fh(GetFullPath());
1054 if ( fh.IsOk() )
1055 {
1056 FILETIME ftAccess, ftCreate, ftWrite;
1057
1058 if ( ::GetFileTime(fh,
1059 dtMod ? &ftCreate : NULL,
1060 dtAccess ? &ftAccess : NULL,
1061 dtChange ? &ftWrite : NULL) )
1062 {
1063 if ( dtMod )
1064 ConvertFileTimeToWx(dtMod, ftCreate);
1065 if ( dtAccess )
1066 ConvertFileTimeToWx(dtAccess, ftAccess);
1067 if ( dtChange )
1068 ConvertFileTimeToWx(dtChange, ftWrite);
1069
1070 return TRUE;
1071 }
1072 }
1073 #else // other platform
1074 #endif // platforms
1075
1076 wxLogSysError(_("Failed to retrieve file times for '%s'"),
1077 GetFullPath().c_str());
1078
1079 return FALSE;
1080 }
1081