]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/filename.cpp
Fixed TablePrivileges() function (I HOPE!) so it will work with all supported databases
[wxWidgets.git] / src / common / filename.cpp
... / ...
CommitLineData
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#include "wx/msw/winundef.h"
49#endif
50
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
64// ============================================================================
65// implementation
66// ============================================================================
67
68// ----------------------------------------------------------------------------
69// wxFileName construction
70// ----------------------------------------------------------------------------
71
72void wxFileName::Assign( const wxFileName &filepath )
73{
74 m_ext = filepath.GetExt();
75 m_name = filepath.GetName();
76 m_dirs = filepath.GetDirs();
77}
78
79void wxFileName::Assign( const wxString& path,
80 const wxString& name,
81 const wxString& ext,
82 wxPathFormat format )
83{
84 wxStringTokenizer tn(path, GetPathSeparators(format),
85 wxTOKEN_RET_EMPTY_ALL);
86 bool first = TRUE;
87 m_dirs.Clear();
88 while ( tn.HasMoreTokens() )
89 {
90 wxString token = tn.GetNextToken();
91
92 // If the path starts with a slash, we need the first
93 // dir entry to be an empty for later reassembly.
94 if (first || !token.IsEmpty())
95 m_dirs.Add( token );
96
97 first = FALSE;
98 }
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;
108 SplitPath(fullpath, &path, &name, &ext, format);
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;
118 SplitPath(fullname, NULL /* no path */, &name, &ext, format);
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;
142}
143
144// ----------------------------------------------------------------------------
145// existence tests
146// ----------------------------------------------------------------------------
147
148bool wxFileName::FileExists()
149{
150 return wxFileName::FileExists( GetFullPath() );
151}
152
153bool wxFileName::FileExists( const wxString &file )
154{
155 return ::wxFileExists( file );
156}
157
158bool wxFileName::DirExists()
159{
160 return wxFileName::DirExists( GetFullPath() );
161}
162
163bool wxFileName::DirExists( const wxString &dir )
164{
165 return ::wxDirExists( dir );
166}
167
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
191// ----------------------------------------------------------------------------
192// CWD and HOME stuff
193// ----------------------------------------------------------------------------
194
195void wxFileName::AssignCwd()
196{
197 AssignDir(wxFileName::GetCwd());
198}
199
200/* static */
201wxString wxFileName::GetCwd()
202{
203 return ::wxGetCwd();
204}
205
206bool wxFileName::SetCwd()
207{
208 return wxFileName::SetCwd( GetFullPath() );
209}
210
211bool wxFileName::SetCwd( const wxString &cwd )
212{
213 return ::wxSetWorkingDirectory( cwd );
214}
215
216void wxFileName::AssignHomeDir()
217{
218 AssignDir(wxFileName::GetHomeDir());
219}
220
221wxString wxFileName::GetHomeDir()
222{
223 return ::wxGetHomeDir();
224}
225
226void wxFileName::AssignTempFileName( const wxString &prefix )
227{
228 wxString fullname;
229 if ( wxGetTempFileName(prefix, fullname) )
230 {
231 Assign(fullname);
232 }
233 else // error
234 {
235 Clear();
236 }
237}
238
239// ----------------------------------------------------------------------------
240// directory operations
241// ----------------------------------------------------------------------------
242
243bool wxFileName::Mkdir( int perm, bool full )
244{
245 return wxFileName::Mkdir( GetFullPath(), perm, full );
246}
247
248bool wxFileName::Mkdir( const wxString &dir, int perm, bool full )
249{
250 if (full)
251 {
252 wxFileName filename(dir);
253 wxArrayString dirs = filename.GetDirs();
254 dirs.Add(filename.GetName());
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 );
284}
285
286bool wxFileName::Rmdir()
287{
288 return wxFileName::Rmdir( GetFullPath() );
289}
290
291bool wxFileName::Rmdir( const wxString &dir )
292{
293 return ::wxRmdir( dir );
294}
295
296// ----------------------------------------------------------------------------
297// path normalization
298// ----------------------------------------------------------------------------
299
300bool wxFileName::Normalize(wxPathNormalize flags,
301 const wxString& cwd,
302 wxPathFormat format)
303{
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() )
314 {
315 if ( cwd.empty() )
316 curDir.AssignCwd();
317 else
318 curDir.AssignDir(cwd);
319 }
320
321 // handle ~ stuff under Unix only
322 if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) )
323 {
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
331 dirs.RemoveAt(0u);
332 }
333 }
334 }
335
336 if ( curDir.IsOk() )
337 {
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;
346 }
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++ )
352 {
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 )
378 {
379 dir = wxExpandEnvVars(dir);
380 }
381
382 if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
383 {
384 dir.MakeLower();
385 }
386
387 m_dirs.Add(dir);
388 }
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
398#if defined(__WXMSW__) && defined(__WIN32__)
399 if (flags & wxPATH_NORM_LONG)
400 {
401 Assign(GetLongPath());
402 }
403#endif
404
405 return TRUE;
406}
407
408// ----------------------------------------------------------------------------
409// filename kind tests
410// ----------------------------------------------------------------------------
411
412bool wxFileName::SameAs( const wxFileName &filepath, wxPathFormat format)
413{
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;
429}
430
431/* static */
432bool wxFileName::IsCaseSensitive( wxPathFormat format )
433{
434 // only DOS filenames are case-sensitive
435 return GetFormat(format) != wxPATH_DOS;
436}
437
438bool wxFileName::IsRelative( wxPathFormat format )
439{
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
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
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) ||
455 driveSep == _T(':') ||
456 (GetFormat(format) == wxPATH_UNIX && ch == _T('~') );
457}
458
459/* static */
460wxString wxFileName::GetPathSeparators(wxPathFormat format)
461{
462 wxString seps;
463 switch ( GetFormat(format) )
464 {
465 case wxPATH_DOS:
466 // accept both as native APIs do
467 seps << wxFILE_SEP_PATH_UNIX << wxFILE_SEP_PATH_DOS;
468 break;
469
470 default:
471 wxFAIL_MSG( _T("unknown wxPATH_XXX style") );
472 // fall through
473
474 case wxPATH_UNIX:
475 seps = wxFILE_SEP_PATH_UNIX;
476 break;
477
478 case wxPATH_MAC:
479 seps = wxFILE_SEP_PATH_MAC;
480 break;
481 }
482
483 return seps;
484}
485
486/* static */
487bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format)
488{
489 return GetPathSeparators(format).Find(ch) != wxNOT_FOUND;
490}
491
492bool wxFileName::IsWild( wxPathFormat format )
493{
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;
497}
498
499// ----------------------------------------------------------------------------
500// path components manipulation
501// ----------------------------------------------------------------------------
502
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
523// ----------------------------------------------------------------------------
524// accessors
525// ----------------------------------------------------------------------------
526
527void wxFileName::SetFullName(const wxString& fullname)
528{
529 SplitPath(fullname, NULL /* no path */, &m_name, &m_ext);
530}
531
532wxString wxFileName::GetFullName() const
533{
534 wxString fullname = m_name;
535 if ( !m_ext.empty() )
536 {
537 fullname << wxFILE_SEP_EXT << m_ext;
538 }
539
540 return fullname;
541}
542
543wxString wxFileName::GetPath( bool add_separator, wxPathFormat format ) const
544{
545 format = GetFormat( format );
546
547 wxString ret;
548 size_t count = m_dirs.GetCount();
549 for ( size_t i = 0; i < count; i++ )
550 {
551 ret += m_dirs[i];
552 if ( add_separator || (i < count) )
553 ret += wxFILE_SEP_PATH;
554 }
555
556 return ret;
557}
558
559wxString wxFileName::GetFullPath( wxPathFormat format ) const
560{
561 return GetPathWithSep() + GetFullName();
562}
563
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());
569 wxString pathOut;
570 DWORD sz = ::GetShortPathName(path, NULL, 0);
571 bool ok = sz != 0;
572 if ( ok )
573 {
574 ok = ::GetShortPathName
575 (
576 path,
577 pathOut.GetWriteBuf(sz),
578 sz
579 ) != 0;
580 pathOut.UngetWriteBuf();
581 }
582 if (ok)
583 return pathOut;
584 else
585 return path;
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());
596 wxString pathOut;
597 bool success = FALSE;
598
599#if wxUSE_DYNLIB_CLASS
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 )
606 {
607 s_triedToLoad = TRUE;
608
609 wxDllType dllKernel = wxDllLoader::LoadLibrary(_T("kernel32"));
610 if ( 0 ) // dllKernel )
611 {
612 // may succeed or fail depending on the Windows version
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
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 }
645 }
646 if (success)
647 return pathOut;
648#endif
649 // wxUSE_DYNLIB_CLASS
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
660 wxArrayString dirs = GetDirs();
661 dirs.Add(GetName());
662
663 size_t count = dirs.GetCount();
664 size_t i;
665 wxString tmpPath;
666
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
671 tmpPath = pathOut + dirs[i];
672
673 if (tmpPath.Last() == wxT(':'))
674 {
675 // Can't pass a drive and root dir to FindFirstFile,
676 // so continue to next dir
677 tmpPath += wxFILE_SEP_PATH;
678 pathOut = tmpPath;
679 continue;
680 }
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;
691 if ( (i < (count-1)) )
692 pathOut += wxFILE_SEP_PATH;
693
694 ::FindClose(hFind);
695 }
696 }
697 }
698 return pathOut;
699#else
700 return GetFullPath();
701#endif
702}
703
704wxPathFormat wxFileName::GetFormat( wxPathFormat format )
705{
706 if (format == wxPATH_NATIVE)
707 {
708#if defined(__WXMSW__) || defined(__WXPM__)
709 format = wxPATH_DOS;
710#elif defined(__WXMAC__)
711 format = wxPATH_UNIX; // that's the way the rest of wx' code works right now
712#else
713 format = wxPATH_UNIX;
714#endif
715 }
716 return format;
717}
718
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
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) )
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 {
773 // take all characters starting from the one after the last slash and
774 // up to, but excluding, the last dot
775 size_t nStart = posLastSlash == wxString::npos ? 0 : posLastSlash + 1;
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 }
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}