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