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