]> git.saurik.com Git - wxWidgets.git/blame - src/common/filename.cpp
Fix/hack 1.
[wxWidgets.git] / src / common / filename.cpp
CommitLineData
df5ddbca 1/////////////////////////////////////////////////////////////////////////////
097ead30
VZ
2// Name: src/common/filename.cpp
3// Purpose: wxFileName - encapsulates a file path
844f90fb 4// Author: Robert Roebling, Vadim Zeitlin
df5ddbca
RR
5// Modified by:
6// Created: 28.12.2000
7// RCS-ID: $Id$
8// Copyright: (c) 2000 Robert Roebling
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
097ead30
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
df5ddbca
RR
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"
844f90fb 38#include "wx/config.h" // for wxExpandEnvVars
a35b27b1 39#include "wx/utils.h"
5d978d07
JS
40
41#if wxUSE_DYNLIB_CLASS
05e7001c 42#include "wx/dynlib.h"
5d978d07 43#endif
df5ddbca 44
9e9b65c1
JS
45// For GetShort/LongPathName
46#ifdef __WIN32__
47#include <windows.h>
48#include "wx/msw/winundef.h"
49#endif
50
ce16e5d7
RR
51// at least some of these are required for file mod time
52#ifdef __WXGTK__
53#include <sys/types.h>
54#include <sys/stat.h>
55#include <dirent.h>
56#include <pwd.h>
57#ifndef __VMS
58# include <grp.h>
59#endif
60# include <time.h>
61#include <unistd.h>
62#endif
63
097ead30
VZ
64// ============================================================================
65// implementation
66// ============================================================================
67
68// ----------------------------------------------------------------------------
844f90fb 69// wxFileName construction
097ead30 70// ----------------------------------------------------------------------------
df5ddbca 71
a35b27b1
RR
72void wxFileName::Assign( const wxFileName &filepath )
73{
a35b27b1
RR
74 m_ext = filepath.GetExt();
75 m_name = filepath.GetName();
844f90fb 76 m_dirs = filepath.GetDirs();
df5ddbca
RR
77}
78
844f90fb
VZ
79void wxFileName::Assign( const wxString& path,
80 const wxString& name,
81 const wxString& ext,
82 wxPathFormat format )
df5ddbca 83{
844f90fb
VZ
84 wxStringTokenizer tn(path, GetPathSeparators(format),
85 wxTOKEN_RET_EMPTY_ALL);
4fdfb558 86 bool first = TRUE;
844f90fb
VZ
87 m_dirs.Clear();
88 while ( tn.HasMoreTokens() )
df5ddbca 89 {
844f90fb
VZ
90 wxString token = tn.GetNextToken();
91
4fdfb558
RR
92 // If the path starts with a slash, we need the first
93 // dir entry to be an empty for later reassembly.
4fdfb558 94 if (first || !token.IsEmpty())
df5ddbca 95 m_dirs.Add( token );
844f90fb 96
4fdfb558 97 first = FALSE;
df5ddbca 98 }
844f90fb
VZ
99
100 m_ext = ext;
101 m_name = name;
102}
103
104void wxFileName::Assign(const wxString& fullpath,
105 wxPathFormat format)
106{
107 wxString path, name, ext;
9e8d8607 108 SplitPath(fullpath, &path, &name, &ext, format);
844f90fb
VZ
109
110 Assign(path, name, ext, format);
111}
112
113void wxFileName::Assign(const wxString& path,
114 const wxString& fullname,
115 wxPathFormat format)
116{
117 wxString name, ext;
9e8d8607 118 SplitPath(fullname, NULL /* no path */, &name, &ext, format);
844f90fb
VZ
119
120 Assign(path, name, ext, format);
121}
122
123void wxFileName::Clear()
124{
125 m_dirs.Clear();
126 m_name =
127 m_ext = wxEmptyString;
128}
129
130/* static */
131wxFileName wxFileName::FileName(const wxString& file)
132{
133 return wxFileName(file);
134}
135
136/* static */
137wxFileName wxFileName::DirName(const wxString& dir)
138{
139 wxFileName fn;
140 fn.AssignDir(dir);
141 return fn;
df5ddbca
RR
142}
143
844f90fb
VZ
144// ----------------------------------------------------------------------------
145// existence tests
146// ----------------------------------------------------------------------------
147
df5ddbca
RR
148bool wxFileName::FileExists()
149{
a35b27b1
RR
150 return wxFileName::FileExists( GetFullPath() );
151}
152
153bool wxFileName::FileExists( const wxString &file )
154{
155 return ::wxFileExists( file );
df5ddbca
RR
156}
157
158bool wxFileName::DirExists()
159{
a35b27b1
RR
160 return wxFileName::DirExists( GetFullPath() );
161}
162
163bool wxFileName::DirExists( const wxString &dir )
164{
165 return ::wxDirExists( dir );
df5ddbca
RR
166}
167
ce16e5d7
RR
168wxDateTime wxFileName::GetModificationTime()
169{
170#ifdef __WXGTK__
171 struct stat buff;
172 stat( GetFullName().fn_str(), &buff );
173
174#if !defined( __EMX__ ) && !defined(__VMS)
175 struct stat lbuff;
176 lstat( GetFullName().fn_str(), &lbuff );
177 struct tm *t = localtime( &lbuff.st_mtime );
178#else
179 struct tm *t = localtime( &buff.st_mtime );
180#endif
181
182 wxDateTime ret( t->tm_mday, (wxDateTime::Month)t->tm_mon, t->tm_year+1900, t->tm_hour, t->tm_min, t->tm_sec );
183#else
184
185 wxDateTime ret = wxDateTime::Now();
186
187#endif
188 return ret;
189}
190
844f90fb
VZ
191// ----------------------------------------------------------------------------
192// CWD and HOME stuff
193// ----------------------------------------------------------------------------
194
df5ddbca
RR
195void wxFileName::AssignCwd()
196{
844f90fb 197 AssignDir(wxFileName::GetCwd());
a35b27b1
RR
198}
199
844f90fb 200/* static */
a35b27b1
RR
201wxString wxFileName::GetCwd()
202{
203 return ::wxGetCwd();
204}
205
206bool wxFileName::SetCwd()
207{
208 return wxFileName::SetCwd( GetFullPath() );
df5ddbca
RR
209}
210
a35b27b1 211bool wxFileName::SetCwd( const wxString &cwd )
df5ddbca 212{
a35b27b1 213 return ::wxSetWorkingDirectory( cwd );
df5ddbca
RR
214}
215
a35b27b1
RR
216void wxFileName::AssignHomeDir()
217{
844f90fb 218 AssignDir(wxFileName::GetHomeDir());
a35b27b1 219}
844f90fb 220
a35b27b1
RR
221wxString wxFileName::GetHomeDir()
222{
223 return ::wxGetHomeDir();
224}
844f90fb 225
df5ddbca
RR
226void wxFileName::AssignTempFileName( const wxString &prefix )
227{
844f90fb
VZ
228 wxString fullname;
229 if ( wxGetTempFileName(prefix, fullname) )
230 {
231 Assign(fullname);
232 }
233 else // error
234 {
235 Clear();
236 }
df5ddbca
RR
237}
238
844f90fb
VZ
239// ----------------------------------------------------------------------------
240// directory operations
241// ----------------------------------------------------------------------------
242
f0ce3409 243bool wxFileName::Mkdir( int perm, bool full )
a35b27b1 244{
f0ce3409 245 return wxFileName::Mkdir( GetFullPath(), perm, full );
a35b27b1
RR
246}
247
f0ce3409 248bool wxFileName::Mkdir( const wxString &dir, int perm, bool full )
df5ddbca 249{
f0ce3409
JS
250 if (full)
251 {
252 wxFileName filename(dir);
253 wxArrayString dirs = filename.GetDirs();
77fe02a8 254 dirs.Add(filename.GetName());
f0ce3409
JS
255
256 size_t count = dirs.GetCount();
257 size_t i;
258 wxString currPath;
259 int noErrors = 0;
260 for ( i = 0; i < count; i++ )
261 {
262 currPath += dirs[i];
263
264 if (currPath.Last() == wxT(':'))
265 {
266 // Can't create a root directory so continue to next dir
267 currPath += wxFILE_SEP_PATH;
268 continue;
269 }
270
271 if (!DirExists(currPath))
272 if (!wxMkdir(currPath, perm))
273 noErrors ++;
274
275 if ( (i < (count-1)) )
276 currPath += wxFILE_SEP_PATH;
277 }
278
279 return (noErrors == 0);
280
281 }
282 else
283 return ::wxMkdir( dir, perm );
df5ddbca
RR
284}
285
a35b27b1 286bool wxFileName::Rmdir()
df5ddbca 287{
a35b27b1 288 return wxFileName::Rmdir( GetFullPath() );
df5ddbca
RR
289}
290
a35b27b1 291bool wxFileName::Rmdir( const wxString &dir )
df5ddbca 292{
a35b27b1 293 return ::wxRmdir( dir );
df5ddbca
RR
294}
295
844f90fb
VZ
296// ----------------------------------------------------------------------------
297// path normalization
298// ----------------------------------------------------------------------------
299
300bool wxFileName::Normalize(wxPathNormalize flags,
301 const wxString& cwd,
302 wxPathFormat format)
a35b27b1 303{
844f90fb
VZ
304 // the existing path components
305 wxArrayString dirs = GetDirs();
306
307 // the path to prepend in front to make the path absolute
308 wxFileName curDir;
309
310 format = GetFormat(format);
311
312 // make the path absolute
313 if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute() )
a35b27b1 314 {
844f90fb
VZ
315 if ( cwd.empty() )
316 curDir.AssignCwd();
a35b27b1 317 else
844f90fb 318 curDir.AssignDir(cwd);
a35b27b1 319 }
844f90fb
VZ
320
321 // handle ~ stuff under Unix only
322 if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) )
a35b27b1 323 {
844f90fb
VZ
324 if ( !dirs.IsEmpty() )
325 {
326 wxString dir = dirs[0u];
327 if ( !dir.empty() && dir[0u] == _T('~') )
328 {
329 curDir.AssignDir(wxGetUserHome(dir.c_str() + 1));
330
da2fd5ac 331 dirs.RemoveAt(0u);
844f90fb
VZ
332 }
333 }
a35b27b1 334 }
844f90fb
VZ
335
336 if ( curDir.IsOk() )
a35b27b1 337 {
844f90fb
VZ
338 wxArrayString dirsNew = curDir.GetDirs();
339 size_t count = dirs.GetCount();
340 for ( size_t n = 0; n < count; n++ )
341 {
342 dirsNew.Add(dirs[n]);
343 }
344
345 dirs = dirsNew;
a35b27b1 346 }
844f90fb
VZ
347
348 // now deal with ".", ".." and the rest
349 m_dirs.Empty();
350 size_t count = dirs.GetCount();
351 for ( size_t n = 0; n < count; n++ )
a35b27b1 352 {
844f90fb
VZ
353 wxString dir = dirs[n];
354
355 if ( flags && wxPATH_NORM_DOTS )
356 {
357 if ( dir == wxT(".") )
358 {
359 // just ignore
360 continue;
361 }
362
363 if ( dir == wxT("..") )
364 {
365 if ( m_dirs.IsEmpty() )
366 {
367 wxLogError(_("The path '%s' contains too many \"..\"!"),
368 GetFullPath().c_str());
369 return FALSE;
370 }
371
372 m_dirs.Remove(m_dirs.GetCount() - 1);
373 continue;
374 }
375 }
376
377 if ( flags & wxPATH_NORM_ENV_VARS )
a35b27b1 378 {
844f90fb 379 dir = wxExpandEnvVars(dir);
a35b27b1 380 }
844f90fb
VZ
381
382 if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
383 {
384 dir.MakeLower();
385 }
386
387 m_dirs.Add(dir);
a35b27b1 388 }
844f90fb
VZ
389
390 if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
391 {
392 // VZ: expand env vars here too?
393
394 m_name.MakeLower();
395 m_ext.MakeLower();
396 }
397
9e9b65c1
JS
398#if defined(__WXMSW__) && defined(__WIN32__)
399 if (flags & wxPATH_NORM_LONG)
400 {
401 Assign(GetLongPath());
402 }
403#endif
404
a35b27b1
RR
405 return TRUE;
406}
407
844f90fb
VZ
408// ----------------------------------------------------------------------------
409// filename kind tests
410// ----------------------------------------------------------------------------
411
412bool wxFileName::SameAs( const wxFileName &filepath, wxPathFormat format)
df5ddbca 413{
844f90fb
VZ
414 wxFileName fn1 = *this,
415 fn2 = filepath;
416
417 // get cwd only once - small time saving
418 wxString cwd = wxGetCwd();
419 fn1.Normalize(wxPATH_NORM_ALL, cwd, format);
420 fn2.Normalize(wxPATH_NORM_ALL, cwd, format);
421
422 if ( fn1.GetFullPath() == fn2.GetFullPath() )
423 return TRUE;
424
425 // TODO: compare inodes for Unix, this works even when filenames are
426 // different but files are the same (symlinks) (VZ)
427
428 return FALSE;
df5ddbca
RR
429}
430
844f90fb 431/* static */
df5ddbca
RR
432bool wxFileName::IsCaseSensitive( wxPathFormat format )
433{
844f90fb
VZ
434 // only DOS filenames are case-sensitive
435 return GetFormat(format) != wxPATH_DOS;
df5ddbca
RR
436}
437
438bool wxFileName::IsRelative( wxPathFormat format )
439{
844f90fb
VZ
440 return !IsAbsolute(format);
441}
442
443bool wxFileName::IsAbsolute( wxPathFormat format )
444{
445 wxChar ch = m_dirs.IsEmpty() ? _T('\0') : m_dirs[0u][0u];
446
9e9b65c1
JS
447 // Hack to cope with e.g. c:\thing - need something better
448 wxChar driveSep = _T('\0');
449 if (!m_dirs.IsEmpty() && m_dirs[0].Length() > 1)
450 driveSep = m_dirs[0u][1u];
451
844f90fb
VZ
452 // the path is absolute if it starts with a path separator or, only for
453 // Unix filenames, with "~" or "~user"
454 return IsPathSeparator(ch, format) ||
9e9b65c1 455 driveSep == _T(':') ||
844f90fb
VZ
456 (GetFormat(format) == wxPATH_UNIX && ch == _T('~') );
457}
458
459/* static */
460wxString wxFileName::GetPathSeparators(wxPathFormat format)
461{
462 wxString seps;
463 switch ( GetFormat(format) )
df5ddbca 464 {
844f90fb
VZ
465 case wxPATH_DOS:
466 // accept both as native APIs do
9e8d8607 467 seps << wxFILE_SEP_PATH_UNIX << wxFILE_SEP_PATH_DOS;
844f90fb
VZ
468 break;
469
470 default:
471 wxFAIL_MSG( _T("unknown wxPATH_XXX style") );
472 // fall through
473
474 case wxPATH_UNIX:
9e8d8607 475 seps = wxFILE_SEP_PATH_UNIX;
844f90fb
VZ
476 break;
477
478 case wxPATH_MAC:
9e8d8607 479 seps = wxFILE_SEP_PATH_MAC;
844f90fb 480 break;
df5ddbca
RR
481 }
482
844f90fb 483 return seps;
df5ddbca
RR
484}
485
844f90fb
VZ
486/* static */
487bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format)
df5ddbca 488{
844f90fb 489 return GetPathSeparators(format).Find(ch) != wxNOT_FOUND;
df5ddbca
RR
490}
491
492bool wxFileName::IsWild( wxPathFormat format )
493{
844f90fb
VZ
494 // FIXME: this is probably false for Mac and this is surely wrong for most
495 // of Unix shells (think about "[...]")
496 return m_name.find_first_of(_T("*?")) != wxString::npos;
df5ddbca
RR
497}
498
844f90fb
VZ
499// ----------------------------------------------------------------------------
500// path components manipulation
501// ----------------------------------------------------------------------------
502
df5ddbca
RR
503void wxFileName::AppendDir( const wxString &dir )
504{
505 m_dirs.Add( dir );
506}
507
508void wxFileName::PrependDir( const wxString &dir )
509{
510 m_dirs.Insert( dir, 0 );
511}
512
513void wxFileName::InsertDir( int before, const wxString &dir )
514{
515 m_dirs.Insert( dir, before );
516}
517
518void wxFileName::RemoveDir( int pos )
519{
520 m_dirs.Remove( (size_t)pos );
521}
522
844f90fb
VZ
523// ----------------------------------------------------------------------------
524// accessors
525// ----------------------------------------------------------------------------
526
7124df9b
VZ
527void wxFileName::SetFullName(const wxString& fullname)
528{
529 SplitPath(fullname, NULL /* no path */, &m_name, &m_ext);
530}
531
844f90fb 532wxString wxFileName::GetFullName() const
a35b27b1 533{
844f90fb
VZ
534 wxString fullname = m_name;
535 if ( !m_ext.empty() )
a35b27b1 536 {
9e8d8607 537 fullname << wxFILE_SEP_EXT << m_ext;
a35b27b1 538 }
a35b27b1 539
844f90fb 540 return fullname;
a35b27b1
RR
541}
542
543wxString wxFileName::GetPath( bool add_separator, wxPathFormat format ) const
df5ddbca
RR
544{
545 format = GetFormat( format );
844f90fb 546
df5ddbca 547 wxString ret;
844f90fb
VZ
548 size_t count = m_dirs.GetCount();
549 for ( size_t i = 0; i < count; i++ )
df5ddbca 550 {
844f90fb
VZ
551 ret += m_dirs[i];
552 if ( add_separator || (i < count) )
553 ret += wxFILE_SEP_PATH;
df5ddbca 554 }
844f90fb 555
df5ddbca
RR
556 return ret;
557}
558
559wxString wxFileName::GetFullPath( wxPathFormat format ) const
560{
844f90fb 561 return GetPathWithSep() + GetFullName();
df5ddbca
RR
562}
563
9e9b65c1
JS
564// Return the short form of the path (returns identity on non-Windows platforms)
565wxString wxFileName::GetShortPath() const
566{
567#if defined(__WXMSW__) && defined(__WIN32__)
568 wxString path(GetFullPath());
75ef5722
JS
569 wxString pathOut;
570 DWORD sz = ::GetShortPathName(path, NULL, 0);
571 bool ok = sz != 0;
572 if ( ok )
9e9b65c1 573 {
75ef5722
JS
574 ok = ::GetShortPathName
575 (
576 path,
577 pathOut.GetWriteBuf(sz),
578 sz
579 ) != 0;
580 pathOut.UngetWriteBuf();
9e9b65c1 581 }
75ef5722
JS
582 if (ok)
583 return pathOut;
9e9b65c1 584 else
75ef5722 585 return path;
9e9b65c1
JS
586#else
587 return GetFullPath();
588#endif
589}
590
591// Return the long form of the path (returns identity on non-Windows platforms)
592wxString wxFileName::GetLongPath() const
593{
594#if defined(__WXMSW__) && defined(__WIN32__)
595 wxString path(GetFullPath());
75ef5722 596 wxString pathOut;
05e7001c
JS
597 bool success = FALSE;
598
5d978d07 599#if wxUSE_DYNLIB_CLASS
05e7001c
JS
600 typedef DWORD (*GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD);
601
602 static bool s_triedToLoad = FALSE;
603 static GET_LONG_PATH_NAME s_pfnGetLongPathName = NULL;
604
605 if ( !s_triedToLoad )
9e9b65c1 606 {
05e7001c
JS
607 s_triedToLoad = TRUE;
608
609 wxDllType dllKernel = wxDllLoader::LoadLibrary(_T("kernel32"));
5d978d07 610 if ( 0 ) // dllKernel )
05e7001c
JS
611 {
612 // may succeed or fail depending on the Windows version
5d978d07
JS
613#ifdef _UNICODE
614 s_pfnGetLongPathName = (GET_LONG_PATH_NAME) wxDllLoader::GetSymbol(dllKernel, _T("GetLongPathNameW"));
615#else
616 s_pfnGetLongPathName = (GET_LONG_PATH_NAME) wxDllLoader::GetSymbol(dllKernel, _T("GetLongPathNameA"));
617#endif
05e7001c
JS
618
619 wxDllLoader::UnloadLibrary(dllKernel);
620
621 if ( s_pfnGetLongPathName )
622 {
623 DWORD dwSize = (*s_pfnGetLongPathName)(path, NULL, 0);
624 bool ok = dwSize > 0;
625
626 if ( ok )
627 {
628 DWORD sz = (*s_pfnGetLongPathName)(path, NULL, 0);
629 ok = sz != 0;
630 if ( ok )
631 {
632 ok = (*s_pfnGetLongPathName)
633 (
634 path,
635 pathOut.GetWriteBuf(sz),
636 sz
637 ) != 0;
638 pathOut.UngetWriteBuf();
639
640 success = TRUE;
641 }
642 }
643 }
644 }
9e9b65c1 645 }
05e7001c 646 if (success)
75ef5722 647 return pathOut;
5d978d07
JS
648#endif
649 // wxUSE_DYNLIB_CLASS
05e7001c
JS
650
651 if (!success)
652 {
653 // The OS didn't support GetLongPathName, or some other error.
654 // We need to call FindFirstFile on each component in turn.
655
656 WIN32_FIND_DATA findFileData;
657 HANDLE hFind;
658 pathOut = wxEmptyString;
659
77fe02a8
JS
660 wxArrayString dirs = GetDirs();
661 dirs.Add(GetName());
662
663 size_t count = dirs.GetCount();
05e7001c
JS
664 size_t i;
665 wxString tmpPath;
5d978d07 666
05e7001c
JS
667 for ( i = 0; i < count; i++ )
668 {
669 // We're using pathOut to collect the long-name path,
670 // but using a temporary for appending the last path component which may be short-name
77fe02a8 671 tmpPath = pathOut + dirs[i];
05e7001c
JS
672
673 if (tmpPath.Last() == wxT(':'))
5d978d07
JS
674 {
675 // Can't pass a drive and root dir to FindFirstFile,
676 // so continue to next dir
05e7001c 677 tmpPath += wxFILE_SEP_PATH;
5d978d07
JS
678 pathOut = tmpPath;
679 continue;
680 }
05e7001c
JS
681
682 hFind = ::FindFirstFile(tmpPath, &findFileData);
683 if (hFind == INVALID_HANDLE_VALUE)
684 {
685 // Error: return immediately with the original path
686 return path;
687 }
688 else
689 {
690 pathOut += findFileData.cFileName;
5d978d07 691 if ( (i < (count-1)) )
05e7001c
JS
692 pathOut += wxFILE_SEP_PATH;
693
694 ::FindClose(hFind);
695 }
696 }
697 }
698 return pathOut;
9e9b65c1
JS
699#else
700 return GetFullPath();
701#endif
702}
703
df5ddbca
RR
704wxPathFormat wxFileName::GetFormat( wxPathFormat format )
705{
706 if (format == wxPATH_NATIVE)
707 {
708#if defined(__WXMSW__) || defined(__WXPM__)
709 format = wxPATH_DOS;
844f90fb 710#elif defined(__WXMAC__)
2597135a 711 format = wxPATH_UNIX; // that's the way the rest of wx' code works right now
844f90fb 712#else
df5ddbca
RR
713 format = wxPATH_UNIX;
714#endif
715 }
716 return format;
717}
a35b27b1 718
9e8d8607
VZ
719// ----------------------------------------------------------------------------
720// path splitting function
721// ----------------------------------------------------------------------------
722
723void wxFileName::SplitPath(const wxString& fullpath,
724 wxString *pstrPath,
725 wxString *pstrName,
726 wxString *pstrExt,
727 wxPathFormat format)
728{
729 format = GetFormat(format);
730
731 // find the positions of the last dot and last path separator in the path
732 size_t posLastDot = fullpath.find_last_of(wxFILE_SEP_EXT);
733 size_t posLastSlash = fullpath.find_last_of(GetPathSeparators(format));
734
735 if ( (posLastDot != wxString::npos) && (format == wxPATH_UNIX) )
736 {
737 if ( (posLastDot == 0) ||
738 (fullpath[posLastDot - 1] == wxFILE_SEP_PATH_UNIX) )
739 {
740 // under Unix, dot may be (and commonly is) the first character of
741 // the filename, don't treat the entire filename as extension in
742 // this case
743 posLastDot = wxString::npos;
744 }
745 }
746
8e7dda21
VZ
747 // if we do have a dot and a slash, check that the dot is in the name part
748 if ( (posLastDot != wxString::npos) &&
749 (posLastSlash != wxString::npos) &&
750 (posLastDot < posLastSlash) )
9e8d8607
VZ
751 {
752 // the dot is part of the path, not the start of the extension
753 posLastDot = wxString::npos;
754 }
755
756 // now fill in the variables provided by user
757 if ( pstrPath )
758 {
759 if ( posLastSlash == wxString::npos )
760 {
761 // no path at all
762 pstrPath->Empty();
763 }
764 else
765 {
766 // take all until the separator
767 *pstrPath = fullpath.Left(posLastSlash);
768 }
769 }
770
771 if ( pstrName )
772 {
42b1f941
VZ
773 // take all characters starting from the one after the last slash and
774 // up to, but excluding, the last dot
9e8d8607 775 size_t nStart = posLastSlash == wxString::npos ? 0 : posLastSlash + 1;
8e7dda21
VZ
776 size_t count;
777 if ( posLastDot == wxString::npos )
778 {
779 // take all until the end
780 count = wxString::npos;
781 }
782 else if ( posLastSlash == wxString::npos )
783 {
784 count = posLastDot;
785 }
786 else // have both dot and slash
787 {
788 count = posLastDot - posLastSlash - 1;
789 }
9e8d8607
VZ
790
791 *pstrName = fullpath.Mid(nStart, count);
792 }
793
794 if ( pstrExt )
795 {
796 if ( posLastDot == wxString::npos )
797 {
798 // no extension
799 pstrExt->Empty();
800 }
801 else
802 {
803 // take everything after the dot
804 *pstrExt = fullpath.Mid(posLastDot + 1);
805 }
806 }
807}