]> git.saurik.com Git - wxWidgets.git/blob - src/common/filename.cpp
implemented wxFileName::SplitPath(), wxSplitPath() now just calls it
[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 // ============================================================================
42 // implementation
43 // ============================================================================
44
45 // ----------------------------------------------------------------------------
46 // wxFileName construction
47 // ----------------------------------------------------------------------------
48
49 void wxFileName::Assign( const wxFileName &filepath )
50 {
51 m_ext = filepath.GetExt();
52 m_name = filepath.GetName();
53 m_dirs = filepath.GetDirs();
54 }
55
56 void wxFileName::Assign( const wxString& path,
57 const wxString& name,
58 const wxString& ext,
59 wxPathFormat format )
60 {
61 wxStringTokenizer tn(path, GetPathSeparators(format),
62 wxTOKEN_RET_EMPTY_ALL);
63 bool first = TRUE;
64 m_dirs.Clear();
65 while ( tn.HasMoreTokens() )
66 {
67 wxString token = tn.GetNextToken();
68
69 // If the path starts with a slash, we need the first
70 // dir entry to be an empty for later reassembly.
71 if (first || !token.IsEmpty())
72 m_dirs.Add( token );
73
74 first = FALSE;
75 }
76
77 m_ext = ext;
78 m_name = name;
79 }
80
81 void wxFileName::Assign(const wxString& fullpath,
82 wxPathFormat format)
83 {
84 wxString path, name, ext;
85 SplitPath(fullpath, &path, &name, &ext, format);
86
87 Assign(path, name, ext, format);
88 }
89
90 void wxFileName::Assign(const wxString& path,
91 const wxString& fullname,
92 wxPathFormat format)
93 {
94 wxString name, ext;
95 SplitPath(fullname, NULL /* no path */, &name, &ext, format);
96
97 Assign(path, name, ext, format);
98 }
99
100 void wxFileName::Clear()
101 {
102 m_dirs.Clear();
103 m_name =
104 m_ext = wxEmptyString;
105 }
106
107 /* static */
108 wxFileName wxFileName::FileName(const wxString& file)
109 {
110 return wxFileName(file);
111 }
112
113 /* static */
114 wxFileName wxFileName::DirName(const wxString& dir)
115 {
116 wxFileName fn;
117 fn.AssignDir(dir);
118 return fn;
119 }
120
121 // ----------------------------------------------------------------------------
122 // existence tests
123 // ----------------------------------------------------------------------------
124
125 bool wxFileName::FileExists()
126 {
127 return wxFileName::FileExists( GetFullPath() );
128 }
129
130 bool wxFileName::FileExists( const wxString &file )
131 {
132 return ::wxFileExists( file );
133 }
134
135 bool wxFileName::DirExists()
136 {
137 return wxFileName::DirExists( GetFullPath() );
138 }
139
140 bool wxFileName::DirExists( const wxString &dir )
141 {
142 return ::wxDirExists( dir );
143 }
144
145 // ----------------------------------------------------------------------------
146 // CWD and HOME stuff
147 // ----------------------------------------------------------------------------
148
149 void wxFileName::AssignCwd()
150 {
151 AssignDir(wxFileName::GetCwd());
152 }
153
154 /* static */
155 wxString wxFileName::GetCwd()
156 {
157 return ::wxGetCwd();
158 }
159
160 bool wxFileName::SetCwd()
161 {
162 return wxFileName::SetCwd( GetFullPath() );
163 }
164
165 bool wxFileName::SetCwd( const wxString &cwd )
166 {
167 return ::wxSetWorkingDirectory( cwd );
168 }
169
170 void wxFileName::AssignHomeDir()
171 {
172 AssignDir(wxFileName::GetHomeDir());
173 }
174
175 wxString wxFileName::GetHomeDir()
176 {
177 return ::wxGetHomeDir();
178 }
179
180 void wxFileName::AssignTempFileName( const wxString &prefix )
181 {
182 wxString fullname;
183 if ( wxGetTempFileName(prefix, fullname) )
184 {
185 Assign(fullname);
186 }
187 else // error
188 {
189 Clear();
190 }
191 }
192
193 // ----------------------------------------------------------------------------
194 // directory operations
195 // ----------------------------------------------------------------------------
196
197 bool wxFileName::Mkdir( int perm )
198 {
199 return wxFileName::Mkdir( GetFullPath(), perm );
200 }
201
202 bool wxFileName::Mkdir( const wxString &dir, int perm )
203 {
204 return ::wxMkdir( dir, perm );
205 }
206
207 bool wxFileName::Rmdir()
208 {
209 return wxFileName::Rmdir( GetFullPath() );
210 }
211
212 bool wxFileName::Rmdir( const wxString &dir )
213 {
214 return ::wxRmdir( dir );
215 }
216
217 // ----------------------------------------------------------------------------
218 // path normalization
219 // ----------------------------------------------------------------------------
220
221 bool wxFileName::Normalize(wxPathNormalize flags,
222 const wxString& cwd,
223 wxPathFormat format)
224 {
225 // the existing path components
226 wxArrayString dirs = GetDirs();
227
228 // the path to prepend in front to make the path absolute
229 wxFileName curDir;
230
231 format = GetFormat(format);
232
233 // make the path absolute
234 if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute() )
235 {
236 if ( cwd.empty() )
237 curDir.AssignCwd();
238 else
239 curDir.AssignDir(cwd);
240 }
241
242 // handle ~ stuff under Unix only
243 if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) )
244 {
245 if ( !dirs.IsEmpty() )
246 {
247 wxString dir = dirs[0u];
248 if ( !dir.empty() && dir[0u] == _T('~') )
249 {
250 curDir.AssignDir(wxGetUserHome(dir.c_str() + 1));
251
252 dirs.Remove(0u);
253 }
254 }
255 }
256
257 if ( curDir.IsOk() )
258 {
259 wxArrayString dirsNew = curDir.GetDirs();
260 size_t count = dirs.GetCount();
261 for ( size_t n = 0; n < count; n++ )
262 {
263 dirsNew.Add(dirs[n]);
264 }
265
266 dirs = dirsNew;
267 }
268
269 // now deal with ".", ".." and the rest
270 m_dirs.Empty();
271 size_t count = dirs.GetCount();
272 for ( size_t n = 0; n < count; n++ )
273 {
274 wxString dir = dirs[n];
275
276 if ( flags && wxPATH_NORM_DOTS )
277 {
278 if ( dir == wxT(".") )
279 {
280 // just ignore
281 continue;
282 }
283
284 if ( dir == wxT("..") )
285 {
286 if ( m_dirs.IsEmpty() )
287 {
288 wxLogError(_("The path '%s' contains too many \"..\"!"),
289 GetFullPath().c_str());
290 return FALSE;
291 }
292
293 m_dirs.Remove(m_dirs.GetCount() - 1);
294 continue;
295 }
296 }
297
298 if ( flags & wxPATH_NORM_ENV_VARS )
299 {
300 dir = wxExpandEnvVars(dir);
301 }
302
303 if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
304 {
305 dir.MakeLower();
306 }
307
308 m_dirs.Add(dir);
309 }
310
311 if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
312 {
313 // VZ: expand env vars here too?
314
315 m_name.MakeLower();
316 m_ext.MakeLower();
317 }
318
319 return TRUE;
320 }
321
322 // ----------------------------------------------------------------------------
323 // filename kind tests
324 // ----------------------------------------------------------------------------
325
326 bool wxFileName::SameAs( const wxFileName &filepath, wxPathFormat format)
327 {
328 wxFileName fn1 = *this,
329 fn2 = filepath;
330
331 // get cwd only once - small time saving
332 wxString cwd = wxGetCwd();
333 fn1.Normalize(wxPATH_NORM_ALL, cwd, format);
334 fn2.Normalize(wxPATH_NORM_ALL, cwd, format);
335
336 if ( fn1.GetFullPath() == fn2.GetFullPath() )
337 return TRUE;
338
339 // TODO: compare inodes for Unix, this works even when filenames are
340 // different but files are the same (symlinks) (VZ)
341
342 return FALSE;
343 }
344
345 /* static */
346 bool wxFileName::IsCaseSensitive( wxPathFormat format )
347 {
348 // only DOS filenames are case-sensitive
349 return GetFormat(format) != wxPATH_DOS;
350 }
351
352 bool wxFileName::IsRelative( wxPathFormat format )
353 {
354 return !IsAbsolute(format);
355 }
356
357 bool wxFileName::IsAbsolute( wxPathFormat format )
358 {
359 wxChar ch = m_dirs.IsEmpty() ? _T('\0') : m_dirs[0u][0u];
360
361 // the path is absolute if it starts with a path separator or, only for
362 // Unix filenames, with "~" or "~user"
363 return IsPathSeparator(ch, format) ||
364 (GetFormat(format) == wxPATH_UNIX && ch == _T('~') );
365 }
366
367 /* static */
368 wxString wxFileName::GetPathSeparators(wxPathFormat format)
369 {
370 wxString seps;
371 switch ( GetFormat(format) )
372 {
373 case wxPATH_DOS:
374 // accept both as native APIs do
375 seps << wxFILE_SEP_PATH_UNIX << wxFILE_SEP_PATH_DOS;
376 break;
377
378 default:
379 wxFAIL_MSG( _T("unknown wxPATH_XXX style") );
380 // fall through
381
382 case wxPATH_UNIX:
383 seps = wxFILE_SEP_PATH_UNIX;
384 break;
385
386 case wxPATH_MAC:
387 seps = wxFILE_SEP_PATH_MAC;
388 break;
389 }
390
391 return seps;
392 }
393
394 /* static */
395 bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format)
396 {
397 return GetPathSeparators(format).Find(ch) != wxNOT_FOUND;
398 }
399
400 bool wxFileName::IsWild( wxPathFormat format )
401 {
402 // FIXME: this is probably false for Mac and this is surely wrong for most
403 // of Unix shells (think about "[...]")
404 return m_name.find_first_of(_T("*?")) != wxString::npos;
405 }
406
407 // ----------------------------------------------------------------------------
408 // path components manipulation
409 // ----------------------------------------------------------------------------
410
411 void wxFileName::AppendDir( const wxString &dir )
412 {
413 m_dirs.Add( dir );
414 }
415
416 void wxFileName::PrependDir( const wxString &dir )
417 {
418 m_dirs.Insert( dir, 0 );
419 }
420
421 void wxFileName::InsertDir( int before, const wxString &dir )
422 {
423 m_dirs.Insert( dir, before );
424 }
425
426 void wxFileName::RemoveDir( int pos )
427 {
428 m_dirs.Remove( (size_t)pos );
429 }
430
431 // ----------------------------------------------------------------------------
432 // accessors
433 // ----------------------------------------------------------------------------
434
435 wxString wxFileName::GetFullName() const
436 {
437 wxString fullname = m_name;
438 if ( !m_ext.empty() )
439 {
440 fullname << wxFILE_SEP_EXT << m_ext;
441 }
442
443 return fullname;
444 }
445
446 wxString wxFileName::GetPath( bool add_separator, wxPathFormat format ) const
447 {
448 format = GetFormat( format );
449
450 wxString ret;
451 size_t count = m_dirs.GetCount();
452 for ( size_t i = 0; i < count; i++ )
453 {
454 ret += m_dirs[i];
455 if ( add_separator || (i < count) )
456 ret += wxFILE_SEP_PATH;
457 }
458
459 return ret;
460 }
461
462 wxString wxFileName::GetFullPath( wxPathFormat format ) const
463 {
464 return GetPathWithSep() + GetFullName();
465 }
466
467 wxPathFormat wxFileName::GetFormat( wxPathFormat format )
468 {
469 if (format == wxPATH_NATIVE)
470 {
471 #if defined(__WXMSW__) || defined(__WXPM__)
472 format = wxPATH_DOS;
473 #elif defined(__WXMAC__)
474 format = wxPATH_MAC;
475 #else
476 format = wxPATH_UNIX;
477 #endif
478 }
479 return format;
480 }
481
482 // ----------------------------------------------------------------------------
483 // path splitting function
484 // ----------------------------------------------------------------------------
485
486 void wxFileName::SplitPath(const wxString& fullpath,
487 wxString *pstrPath,
488 wxString *pstrName,
489 wxString *pstrExt,
490 wxPathFormat format)
491 {
492 format = GetFormat(format);
493
494 // find the positions of the last dot and last path separator in the path
495 size_t posLastDot = fullpath.find_last_of(wxFILE_SEP_EXT);
496 size_t posLastSlash = fullpath.find_last_of(GetPathSeparators(format));
497
498 if ( (posLastDot != wxString::npos) && (format == wxPATH_UNIX) )
499 {
500 if ( (posLastDot == 0) ||
501 (fullpath[posLastDot - 1] == wxFILE_SEP_PATH_UNIX) )
502 {
503 // under Unix, dot may be (and commonly is) the first character of
504 // the filename, don't treat the entire filename as extension in
505 // this case
506 posLastDot = wxString::npos;
507 }
508 }
509
510 if ( (posLastDot != wxString::npos) && (posLastDot < posLastSlash) )
511 {
512 // the dot is part of the path, not the start of the extension
513 posLastDot = wxString::npos;
514 }
515
516 // now fill in the variables provided by user
517 if ( pstrPath )
518 {
519 if ( posLastSlash == wxString::npos )
520 {
521 // no path at all
522 pstrPath->Empty();
523 }
524 else
525 {
526 // take all until the separator
527 *pstrPath = fullpath.Left(posLastSlash);
528 }
529 }
530
531 if ( pstrName )
532 {
533 size_t nStart = posLastSlash == wxString::npos ? 0 : posLastSlash + 1;
534 size_t count = posLastDot == wxString::npos ? wxString::npos
535 : posLastDot - posLastSlash;
536
537 *pstrName = fullpath.Mid(nStart, count);
538 }
539
540 if ( pstrExt )
541 {
542 if ( posLastDot == wxString::npos )
543 {
544 // no extension
545 pstrExt->Empty();
546 }
547 else
548 {
549 // take everything after the dot
550 *pstrExt = fullpath.Mid(posLastDot + 1);
551 }
552 }
553 }