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