]> git.saurik.com Git - wxWidgets.git/blame - src/common/filefn.cpp
fix typo; wrap lines; add some clarifications
[wxWidgets.git] / src / common / filefn.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
6d3d756a 2// Name: src/common/filefn.cpp
c801d85f
KB
3// Purpose: File- and directory-related functions
4// Author: Julian Smart
5// Modified by:
6// Created: 29/01/98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Julian Smart
65571936 9// Licence: wxWindows licence
c801d85f
KB
10/////////////////////////////////////////////////////////////////////////////
11
e90c1d2a
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
c801d85f
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
c801d85f
KB
22
23#ifdef __BORLANDC__
7af89395 24 #pragma hdrstop
c801d85f
KB
25#endif
26
94268cae
WS
27#include "wx/filefn.h"
28
8898456d
WS
29#ifndef WX_PRECOMP
30 #include "wx/intl.h"
e4db172a 31 #include "wx/log.h"
de6185e2 32 #include "wx/utils.h"
0bf751e7 33 #include "wx/crt.h"
8898456d
WS
34#endif
35
7bcc9eb9 36#include "wx/dynarray.h"
94268cae 37#include "wx/file.h"
9e8d8607 38#include "wx/filename.h"
8ff12342 39#include "wx/dir.h"
c801d85f 40
8daf3c36
VZ
41#include "wx/tokenzr.h"
42
fd3f686c 43// there are just too many of those...
3f4a0c5b 44#ifdef __VISUALC__
fd3f686c
VZ
45 #pragma warning(disable:4706) // assignment within conditional expression
46#endif // VC++
47
c801d85f
KB
48#include <ctype.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
13ff2485 52#if !wxONLY_WATCOM_EARLIER_THAN(1,4)
3f4a0c5b
VZ
53 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
54 #include <errno.h>
55 #endif
c801d85f 56#endif
3f4a0c5b 57
76a5e5d2 58#if defined(__WXMAC__)
c933e267 59 #include "wx/osx/private.h" // includes mac headers
76a5e5d2
SC
60#endif
61
34138703 62#ifdef __WINDOWS__
18a1516c 63 #include "wx/msw/private.h"
3d5231db 64 #include "wx/msw/mslu.h"
b0091f58 65
3ffbc733
VZ
66 // sys/cygwin.h is needed for cygwin_conv_to_full_win32_path()
67 //
68 // note that it must be included after <windows.h>
69 #ifdef __GNUWIN32__
e02e8816
MB
70 #ifdef __CYGWIN__
71 #include <sys/cygwin.h>
72 #endif
3ffbc733 73 #endif // __GNUWIN32__
18a1516c
MW
74
75 // io.h is needed for _get_osfhandle()
76 // Already included by filefn.h for many Windows compilers
77 #if defined __MWERKS__ || defined __CYGWIN__
78 #include <io.h>
79 #endif
3ffbc733 80#endif // __WINDOWS__
c801d85f 81
68351053 82#if defined(__VMS__)
3c70014d
MW
83 #include <fab.h>
84#endif
85
13b1f8a7
VZ
86// TODO: Borland probably has _wgetcwd as well?
87#ifdef _MSC_VER
88 #define HAVE_WGETCWD
89#endif
90
e90c1d2a
VZ
91// ----------------------------------------------------------------------------
92// constants
93// ----------------------------------------------------------------------------
94
13b1f8a7
VZ
95#ifndef _MAXPATHLEN
96 #define _MAXPATHLEN 1024
97#endif
c801d85f 98
834c8ade
VZ
99#ifndef INVALID_FILE_ATTRIBUTES
100 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
101#endif
102
e90c1d2a
VZ
103// ----------------------------------------------------------------------------
104// private globals
105// ----------------------------------------------------------------------------
106
47d281e6 107#if WXWIN_COMPATIBILITY_2_8
e90c1d2a 108static wxChar wxFileFunctionsBuffer[4*_MAXPATHLEN];
47d281e6 109#endif
e90c1d2a 110
5d33ed2c
DW
111#if defined(__VISAGECPP__) && __IBMCPP__ >= 400
112//
32e768ae 113// VisualAge C++ V4.0 cannot have any external linkage const decs
5d33ed2c
DW
114// in headers included by more than one primary source
115//
30984dea 116const int wxInvalidOffset = -1;
5d33ed2c
DW
117#endif
118
e90c1d2a
VZ
119// ============================================================================
120// implementation
121// ============================================================================
122
56614e51
VZ
123// ----------------------------------------------------------------------------
124// wrappers around standard POSIX functions
125// ----------------------------------------------------------------------------
126
311b0403
MW
127#if wxUSE_UNICODE && defined __BORLANDC__ \
128 && __BORLANDC__ >= 0x550 && __BORLANDC__ <= 0x551
129
130// BCC 5.5 and 5.5.1 have a bug in _wopen where files are created read only
131// regardless of the mode parameter. This hack works around the problem by
132// setting the mode with _wchmod.
0597e7f9 133//
52de37c7 134int wxCRT_Open(const wchar_t *pathname, int flags, mode_t mode)
311b0403
MW
135{
136 int moreflags = 0;
137
138 // we only want to fix the mode when the file is actually created, so
139 // when creating first try doing it O_EXCL so we can tell if the file
140 // was already there.
141 if ((flags & O_CREAT) && !(flags & O_EXCL) && (mode & wxS_IWUSR) != 0)
142 moreflags = O_EXCL;
143
144 int fd = _wopen(pathname, flags | moreflags, mode);
145
146 // the file was actually created and needs fixing
147 if (fd != -1 && (flags & O_CREAT) != 0 && (mode & wxS_IWUSR) != 0)
148 {
149 close(fd);
150 _wchmod(pathname, mode);
151 fd = _wopen(pathname, flags & ~(O_EXCL | O_CREAT));
152 }
153 // the open failed, but it may have been because the added O_EXCL stopped
154 // the opening of an existing file, so try again without.
155 else if (fd == -1 && moreflags != 0)
156 {
157 fd = _wopen(pathname, flags & ~O_CREAT);
158 }
159
160 return fd;
161}
162
163#endif
164
92980e90
RR
165// ----------------------------------------------------------------------------
166// wxPathList
167// ----------------------------------------------------------------------------
168
34e2d943 169bool wxPathList::Add(const wxString& path)
f526f752 170{
31a8bf3f
RR
171 // add a path separator to force wxFileName to interpret it always as a directory
172 // (i.e. if we are called with '/home/user' we want to consider it a folder and
173 // not, as wxFileName would consider, a filename).
8daf3c36 174 wxFileName fn(path + wxFileName::GetPathSeparator());
31a8bf3f
RR
175
176 // add only normalized relative/absolute paths
34e2d943
RR
177 // NB: we won't do wxPATH_NORM_DOTS in order to avoid problems when trying to
178 // normalize paths which starts with ".." (which can be normalized only if
179 // we use also wxPATH_NORM_ABSOLUTE - which we don't want to use).
180 if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS))
181 return false;
f526f752 182
8daf3c36
VZ
183 wxString toadd = fn.GetPath();
184 if (Index(toadd) == wxNOT_FOUND)
185 wxArrayString::Add(toadd); // do not add duplicates
34e2d943
RR
186
187 return true;
f526f752
MB
188}
189
8daf3c36 190void wxPathList::Add(const wxArrayString &arr)
c801d85f 191{
8daf3c36
VZ
192 for (size_t j=0; j < arr.GetCount(); j++)
193 Add(arr[j]);
c801d85f
KB
194}
195
196// Add paths e.g. from the PATH environment variable
7bea7b91 197void wxPathList::AddEnvList (const wxString& WXUNUSED_IN_WINCE(envVariable))
c801d85f 198{
1c193821
JS
199 // No environment variables on WinCE
200#ifndef __WXWINCE__
8daf3c36
VZ
201
202 // The space has been removed from the tokenizers, otherwise a
203 // path such as "C:\Program Files" would be split into 2 paths:
204 // "C:\Program" and "Files"; this is true for both Windows and Unix.
205
db4444f0 206 static const wxChar PATH_TOKS[] =
5a3912f2 207#if defined(__WINDOWS__) || defined(__OS2__)
3103e8a9 208 wxT(";"); // Don't separate with colon in DOS (used for drive)
c801d85f 209#else
8daf3c36 210 wxT(":;");
c801d85f
KB
211#endif
212
8daf3c36
VZ
213 wxString val;
214 if ( wxGetEnv(envVariable, &val) )
c801d85f 215 {
8daf3c36
VZ
216 // split into an array of string the value of the env var
217 wxArrayString arr = wxStringTokenize(val, PATH_TOKS);
218 WX_APPEND_ARRAY(*this, arr);
c801d85f 219 }
7bea7b91 220#endif // !__WXWINCE__
c801d85f
KB
221}
222
223// Given a full filename (with path), ensure that that file can
224// be accessed again USING FILENAME ONLY by adding the path
225// to the list if not already there.
34e2d943 226bool wxPathList::EnsureFileAccessible (const wxString& path)
c801d85f 227{
34e2d943 228 return Add(wxPathOnly(path));
c801d85f
KB
229}
230
2587df2c
VS
231#if WXWIN_COMPATIBILITY_2_6
232bool wxPathList::Member (const wxString& path) const
233{
234 return Index(path) != wxNOT_FOUND;
235}
236#endif
237
8daf3c36 238wxString wxPathList::FindValidPath (const wxString& file) const
c801d85f 239{
31a8bf3f
RR
240 // normalize the given string as it could be a path + a filename
241 // and not only a filename
8daf3c36
VZ
242 wxFileName fn(file);
243 wxString strend;
c801d85f 244
34e2d943
RR
245 // NB: normalize without making absolute otherwise calling this function with
246 // e.g. "b/c.txt" would result in removing the directory 'b' and the for loop
247 // below would only add to the paths of this list the 'c.txt' part when doing
248 // the existence checks...
249 // NB: we don't use wxPATH_NORM_DOTS here, too (see wxPathList::Add for more info)
250 if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS))
251 return wxEmptyString;
31a8bf3f
RR
252
253 wxASSERT_MSG(!fn.IsDir(), wxT("Cannot search for directories; only for files"));
8daf3c36 254 if (fn.IsAbsolute())
31a8bf3f 255 strend = fn.GetFullName(); // search for the file name and ignore the path part
8daf3c36
VZ
256 else
257 strend = fn.GetFullPath();
c801d85f 258
8daf3c36 259 for (size_t i=0; i<GetCount(); i++)
c801d85f 260 {
8daf3c36
VZ
261 wxString strstart = Item(i);
262 if (!strstart.IsEmpty() && strstart.Last() != wxFileName::GetPathSeparator())
263 strstart += wxFileName::GetPathSeparator();
c801d85f 264
8daf3c36
VZ
265 if (wxFileExists(strstart + strend))
266 return strstart + strend; // Found!
267 }
268
269 return wxEmptyString; // Not found
c801d85f
KB
270}
271
8daf3c36 272wxString wxPathList::FindAbsoluteValidPath (const wxString& file) const
c801d85f 273{
e90c1d2a 274 wxString f = FindValidPath(file);
fc447c7f 275 if ( f.empty() || wxIsAbsolutePath(f) )
e90c1d2a
VZ
276 return f;
277
ce045aed 278 wxString buf = ::wxGetCwd();
13b1f8a7 279
e90c1d2a 280 if ( !wxEndsWithPathSeparator(buf) )
c801d85f 281 {
e90c1d2a 282 buf += wxFILE_SEP_PATH;
c801d85f 283 }
e90c1d2a
VZ
284 buf += f;
285
286 return buf;
c801d85f
KB
287}
288
8daf3c36 289// ----------------------------------------------------------------------------
939fdcf6 290// miscellaneous global functions
8daf3c36
VZ
291// ----------------------------------------------------------------------------
292
939fdcf6 293#if WXWIN_COMPATIBILITY_2_8
8daf3c36
VZ
294static inline wxChar* MYcopystring(const wxString& s)
295{
296 wxChar* copy = new wxChar[s.length() + 1];
297 return wxStrcpy(copy, s.c_str());
298}
299
52de37c7
VS
300template<typename CharType>
301static inline CharType* MYcopystring(const CharType* s)
8daf3c36 302{
52de37c7 303 CharType* copy = new CharType[wxStrlen(s) + 1];
8daf3c36
VZ
304 return wxStrcpy(copy, s);
305}
939fdcf6 306#endif
8daf3c36
VZ
307
308
3f4a0c5b 309bool
c801d85f
KB
310wxFileExists (const wxString& filename)
311{
68351053
WS
312#if defined(__WXPALMOS__)
313 return false;
314#elif defined(__WIN32__) && !defined(__WXMICROWIN__)
4ea2c29f
VZ
315 // we must use GetFileAttributes() instead of the ANSI C functions because
316 // it can cope with network (UNC) paths unlike them
e0a050e3 317 DWORD ret = ::GetFileAttributes(filename.fn_str());
2db300c6 318
834c8ade 319 return (ret != INVALID_FILE_ATTRIBUTES) && !(ret & FILE_ATTRIBUTE_DIRECTORY);
4ea2c29f 320#else // !__WIN32__
27d98837
MW
321 #ifndef S_ISREG
322 #define S_ISREG(mode) ((mode) & S_IFREG)
323 #endif
4ea2c29f 324 wxStructStat st;
f3660dcb 325#ifndef wxNEED_WX_UNISTD_H
27d98837 326 return (wxStat( filename.fn_str() , &st) == 0 && S_ISREG(st.st_mode))
bf58daba
SN
327#ifdef __OS2__
328 || (errno == EACCES) // if access is denied something with that name
329 // exists and is opened in exclusive mode.
330#endif
331 ;
f3660dcb 332#else
27d98837 333 return wxStat( filename , &st) == 0 && S_ISREG(st.st_mode);
f3660dcb 334#endif
4ea2c29f 335#endif // __WIN32__/!__WIN32__
c801d85f
KB
336}
337
3f4a0c5b 338bool
c801d85f
KB
339wxIsAbsolutePath (const wxString& filename)
340{
b494c48b 341 if (!filename.empty())
2985ad5d 342 {
e8e1d09e
GD
343 // Unix like or Windows
344 if (filename[0] == wxT('/'))
79e162f5 345 return true;
c801d85f 346#ifdef __VMS__
e8e1d09e 347 if ((filename[0] == wxT('[') && filename[1] != wxT('.')))
79e162f5 348 return true;
c801d85f 349#endif
5a3912f2 350#if defined(__WINDOWS__) || defined(__OS2__)
e8e1d09e
GD
351 // MSDOS like
352 if (filename[0] == wxT('\\') || (wxIsalpha (filename[0]) && filename[1] == wxT(':')))
79e162f5 353 return true;
c801d85f 354#endif
c801d85f 355 }
79e162f5 356 return false ;
c801d85f
KB
357}
358
47d281e6 359#if WXWIN_COMPATIBILITY_2_8
c801d85f
KB
360/*
361 * Strip off any extension (dot something) from end of file,
362 * IF one exists. Inserts zero into buffer.
363 *
364 */
3f4a0c5b 365
52de37c7
VS
366template<typename T>
367static void wxDoStripExtension(T *buffer)
c801d85f 368{
b0c5cd0f
WS
369 int len = wxStrlen(buffer);
370 int i = len-1;
371 while (i > 0)
c801d85f 372 {
b0c5cd0f
WS
373 if (buffer[i] == wxT('.'))
374 {
375 buffer[i] = 0;
376 break;
377 }
378 i --;
c801d85f 379 }
c801d85f
KB
380}
381
52de37c7
VS
382void wxStripExtension(char *buffer) { wxDoStripExtension(buffer); }
383void wxStripExtension(wchar_t *buffer) { wxDoStripExtension(buffer); }
384
47fa7969
JS
385void wxStripExtension(wxString& buffer)
386{
a6f4dbbd 387 //RN: Be careful about the handling the case where
ce045aed
WS
388 //buffer.length() == 0
389 for(size_t i = buffer.length() - 1; i != wxString::npos; --i)
47fa7969 390 {
2cbfa061
RN
391 if (buffer.GetChar(i) == wxT('.'))
392 {
393 buffer = buffer.Left(i);
394 break;
395 }
47fa7969 396 }
47fa7969
JS
397}
398
c801d85f 399// Destructive removal of /./ and /../ stuff
52de37c7
VS
400template<typename CharType>
401static CharType *wxDoRealPath (CharType *path)
c801d85f 402{
e2fc40b4 403 static const CharType SEP = wxFILE_SEP_PATH;
2049ba38 404#ifdef __WXMSW__
2b5f62a0 405 wxUnix2DosFilename(path);
c801d85f
KB
406#endif
407 if (path[0] && path[1]) {
408 /* MATTHEW: special case "/./x" */
52de37c7 409 CharType *p;
223d09f6 410 if (path[2] == SEP && path[1] == wxT('.'))
c801d85f
KB
411 p = &path[0];
412 else
413 p = &path[2];
414 for (; *p; p++)
415 {
3f4a0c5b
VZ
416 if (*p == SEP)
417 {
223d09f6 418 if (p[1] == wxT('.') && p[2] == wxT('.') && (p[3] == SEP || p[3] == wxT('\0')))
3f4a0c5b 419 {
52de37c7 420 CharType *q;
f0e1c343
JS
421 for (q = p - 1; q >= path && *q != SEP; q--)
422 {
423 // Empty
424 }
425
223d09f6 426 if (q[0] == SEP && (q[1] != wxT('.') || q[2] != wxT('.') || q[3] != SEP)
3f4a0c5b
VZ
427 && (q - 1 <= path || q[-1] != SEP))
428 {
50920146 429 wxStrcpy (q, p + 3);
223d09f6 430 if (path[0] == wxT('\0'))
3f4a0c5b
VZ
431 {
432 path[0] = SEP;
223d09f6 433 path[1] = wxT('\0');
3f4a0c5b 434 }
5a3912f2 435#if defined(__WXMSW__) || defined(__OS2__)
3f4a0c5b 436 /* Check that path[2] is NULL! */
223d09f6 437 else if (path[1] == wxT(':') && !path[2])
3f4a0c5b
VZ
438 {
439 path[2] = SEP;
223d09f6 440 path[3] = wxT('\0');
3f4a0c5b
VZ
441 }
442#endif
443 p = q - 1;
444 }
445 }
223d09f6 446 else if (p[1] == wxT('.') && (p[2] == SEP || p[2] == wxT('\0')))
50920146 447 wxStrcpy (p, p + 2);
3f4a0c5b 448 }
c801d85f
KB
449 }
450 }
451 return path;
452}
453
52de37c7
VS
454char *wxRealPath(char *path)
455{
456 return wxDoRealPath(path);
457}
458
459wchar_t *wxRealPath(wchar_t *path)
460{
461 return wxDoRealPath(path);
462}
463
ce045aed
WS
464wxString wxRealPath(const wxString& path)
465{
466 wxChar *buf1=MYcopystring(path);
467 wxChar *buf2=wxRealPath(buf1);
468 wxString buf(buf2);
469 delete [] buf1;
470 return buf;
471}
472
473
c801d85f 474// Must be destroyed
50920146 475wxChar *wxCopyAbsolutePath(const wxString& filename)
c801d85f 476{
ce045aed 477 if (filename.empty())
d3b9f782 478 return NULL;
c801d85f 479
ce045aed
WS
480 if (! wxIsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer, filename)))
481 {
482 wxString buf = ::wxGetCwd();
483 wxChar ch = buf.Last();
2049ba38 484#ifdef __WXMSW__
ce045aed
WS
485 if (ch != wxT('\\') && ch != wxT('/'))
486 buf << wxT("\\");
c801d85f 487#else
ce045aed
WS
488 if (ch != wxT('/'))
489 buf << wxT("/");
c801d85f 490#endif
ce045aed
WS
491 buf << wxFileFunctionsBuffer;
492 buf = wxRealPath( buf );
493 return MYcopystring( buf );
494 }
495 return MYcopystring( wxFileFunctionsBuffer );
c801d85f
KB
496}
497
498/*-
499 Handles:
500 ~/ => home dir
501 ~user/ => user's home dir
502 If the environment variable a = "foo" and b = "bar" then:
503 Unix:
3f4a0c5b
VZ
504 $a => foo
505 $a$b => foobar
506 $a.c => foo.c
507 xxx$a => xxxfoo
508 ${a}! => foo!
509 $(b)! => bar!
510 \$a => \$a
c801d85f 511 MSDOS:
3f4a0c5b
VZ
512 $a ==> $a
513 $(a) ==> foo
514 $(a)$b ==> foo$b
515 $(a)$(b)==> foobar
516 test.$$ ==> test.$$
c801d85f
KB
517 */
518
519/* input name in name, pathname output to buf. */
520
52de37c7
VS
521template<typename CharType>
522static CharType *wxDoExpandPath(CharType *buf, const wxString& name)
c801d85f 523{
52de37c7
VS
524 register CharType *d, *s, *nm;
525 CharType lnm[_MAXPATHLEN];
33ac7e6f 526 int q;
c801d85f
KB
527
528 // Some compilers don't like this line.
52de37c7 529// const CharType trimchars[] = wxT("\n \t");
c801d85f 530
52de37c7 531 CharType trimchars[4];
223d09f6
KB
532 trimchars[0] = wxT('\n');
533 trimchars[1] = wxT(' ');
534 trimchars[2] = wxT('\t');
c801d85f
KB
535 trimchars[3] = 0;
536
e2fc40b4 537 static const CharType SEP = wxFILE_SEP_PATH;
2049ba38 538#ifdef __WXMSW__
e2fc40b4 539 //wxUnix2DosFilename(path);
c801d85f 540#endif
e2fc40b4 541
223d09f6 542 buf[0] = wxT('\0');
52de37c7 543 if (name.empty())
3f4a0c5b 544 return buf;
8fd7108e 545 nm = ::MYcopystring(static_cast<const CharType*>(name.c_str())); // Make a scratch copy
52de37c7 546 CharType *nm_tmp = nm;
c801d85f
KB
547
548 /* Skip leading whitespace and cr */
52de37c7 549 while (wxStrchr(trimchars, *nm) != NULL)
3f4a0c5b 550 nm++;
c801d85f 551 /* And strip off trailing whitespace and cr */
50920146 552 s = nm + (q = wxStrlen(nm)) - 1;
52de37c7 553 while (q-- && wxStrchr(trimchars, *s) != NULL)
223d09f6 554 *s = wxT('\0');
c801d85f
KB
555
556 s = nm;
557 d = lnm;
2049ba38 558#ifdef __WXMSW__
dc259b79 559 q = FALSE;
c801d85f 560#else
223d09f6 561 q = nm[0] == wxT('\\') && nm[1] == wxT('~');
c801d85f
KB
562#endif
563
564 /* Expand inline environment variables */
c2ff79b1
DW
565#ifdef __VISAGECPP__
566 while (*d)
567 {
568 *d++ = *s;
223d09f6 569 if(*s == wxT('\\'))
c2ff79b1
DW
570 {
571 *(d - 1) = *++s;
572 if (*d)
573 {
574 s++;
575 continue;
576 }
577 else
578 break;
579 }
580 else
581#else
22394d24 582 while ((*d++ = *s) != 0) {
c2ff79b1 583# ifndef __WXMSW__
223d09f6 584 if (*s == wxT('\\')) {
c40158e4 585 if ((*(d - 1) = *++s)!=0) {
3f4a0c5b
VZ
586 s++;
587 continue;
588 } else
589 break;
590 } else
c2ff79b1 591# endif
c801d85f 592#endif
1c193821
JS
593 // No env variables on WinCE
594#ifndef __WXWINCE__
2049ba38 595#ifdef __WXMSW__
223d09f6 596 if (*s++ == wxT('$') && (*s == wxT('{') || *s == wxT(')')))
c801d85f 597#else
223d09f6 598 if (*s++ == wxT('$'))
3f4a0c5b
VZ
599#endif
600 {
52de37c7 601 register CharType *start = d;
223d09f6 602 register int braces = (*s == wxT('{') || *s == wxT('('));
52de37c7 603 register CharType *value;
22394d24 604 while ((*d++ = *s) != 0)
223d09f6 605 if (braces ? (*s == wxT('}') || *s == wxT(')')) : !(wxIsalnum(*s) || *s == wxT('_')) )
3f4a0c5b
VZ
606 break;
607 else
608 s++;
609 *--d = 0;
50920146 610 value = wxGetenv(braces ? start + 1 : start);
3f4a0c5b 611 if (value) {
f0e1c343
JS
612 for ((d = start - 1); (*d++ = *value++) != 0;)
613 {
614 // Empty
615 }
616
3f4a0c5b
VZ
617 d--;
618 if (braces && *s)
619 s++;
620 }
621 }
1c193821
JS
622#endif
623 // __WXWINCE__
c801d85f
KB
624 }
625
626 /* Expand ~ and ~user */
52de37c7 627 wxString homepath;
c801d85f 628 nm = lnm;
223d09f6 629 if (nm[0] == wxT('~') && !q)
c801d85f 630 {
3f4a0c5b
VZ
631 /* prefix ~ */
632 if (nm[1] == SEP || nm[1] == 0)
633 { /* ~/filename */
52de37c7
VS
634 homepath = wxGetUserHome(wxEmptyString);
635 if (!homepath.empty()) {
636 s = (CharType*)(const CharType*)homepath.c_str();
3f4a0c5b
VZ
637 if (*++nm)
638 nm++;
639 }
c801d85f 640 } else
3f4a0c5b 641 { /* ~user/filename */
52de37c7 642 register CharType *nnm;
f0e1c343
JS
643 for (s = nm; *s && *s != SEP; s++)
644 {
645 // Empty
646 }
3f4a0c5b 647 int was_sep; /* MATTHEW: Was there a separator, or NULL? */
c801d85f 648 was_sep = (*s == SEP);
3f4a0c5b
VZ
649 nnm = *s ? s + 1 : s;
650 *s = 0;
52de37c7
VS
651 homepath = wxGetUserHome(wxString(nm + 1));
652 if (homepath.empty())
7448de8d
WS
653 {
654 if (was_sep) /* replace only if it was there: */
655 *s = SEP;
295272bd 656 s = NULL;
7448de8d
WS
657 }
658 else
659 {
3f4a0c5b 660 nm = nnm;
52de37c7 661 s = (CharType*)(const CharType*)homepath.c_str();
3f4a0c5b
VZ
662 }
663 }
c801d85f
KB
664 }
665
666 d = buf;
667 if (s && *s) { /* MATTHEW: s could be NULL if user '~' didn't exist */
3f4a0c5b 668 /* Copy home dir */
223d09f6 669 while (wxT('\0') != (*d++ = *s++))
3f4a0c5b
VZ
670 /* loop */;
671 // Handle root home
672 if (d - 1 > buf && *(d - 2) != SEP)
673 *(d - 1) = SEP;
c801d85f
KB
674 }
675 s = nm;
f0e1c343
JS
676 while ((*d++ = *s++) != 0)
677 {
678 // Empty
679 }
c801d85f
KB
680 delete[] nm_tmp; // clean up alloc
681 /* Now clean up the buffer */
682 return wxRealPath(buf);
683}
684
52de37c7
VS
685char *wxExpandPath(char *buf, const wxString& name)
686{
687 return wxDoExpandPath(buf, name);
688}
689
690wchar_t *wxExpandPath(wchar_t *buf, const wxString& name)
691{
692 return wxDoExpandPath(buf, name);
693}
694
695
c801d85f
KB
696/* Contract Paths to be build upon an environment variable
697 component:
698
699 example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib
700
701 The call wxExpandPath can convert these back!
702 */
50920146 703wxChar *
7bea7b91
WS
704wxContractPath (const wxString& filename,
705 const wxString& WXUNUSED_IN_WINCE(envname),
706 const wxString& user)
c801d85f 707{
50920146 708 static wxChar dest[_MAXPATHLEN];
c801d85f 709
b494c48b 710 if (filename.empty())
d3b9f782 711 return NULL;
c801d85f 712
52de37c7 713 wxStrcpy (dest, filename);
2049ba38 714#ifdef __WXMSW__
2b5f62a0 715 wxUnix2DosFilename(dest);
c801d85f
KB
716#endif
717
718 // Handle environment
52de37c7 719 wxString val;
1c193821 720#ifndef __WXWINCE__
999836aa 721 wxChar *tcp;
52de37c7 722 if (!envname.empty() && !(val = wxGetenv (envname)).empty() &&
50920146 723 (tcp = wxStrstr (dest, val)) != NULL)
c801d85f 724 {
52de37c7 725 wxStrcpy (wxFileFunctionsBuffer, tcp + val.length());
223d09f6
KB
726 *tcp++ = wxT('$');
727 *tcp++ = wxT('{');
52de37c7 728 wxStrcpy (tcp, envname);
223d09f6 729 wxStrcat (tcp, wxT("}"));
e90c1d2a 730 wxStrcat (tcp, wxFileFunctionsBuffer);
c801d85f 731 }
1c193821 732#endif
c801d85f
KB
733
734 // Handle User's home (ignore root homes!)
844ca096 735 val = wxGetUserHome (user);
52de37c7 736 if (val.empty())
844ca096
VZ
737 return dest;
738
52de37c7 739 const size_t len = val.length();
844ca096
VZ
740 if (len <= 2)
741 return dest;
742
743 if (wxStrncmp(dest, val, len) == 0)
744 {
745 wxStrcpy(wxFileFunctionsBuffer, wxT("~"));
b494c48b 746 if (!user.empty())
52de37c7 747 wxStrcat(wxFileFunctionsBuffer, user);
844ca096
VZ
748 wxStrcat(wxFileFunctionsBuffer, dest + len);
749 wxStrcpy (dest, wxFileFunctionsBuffer);
750 }
c801d85f
KB
751
752 return dest;
753}
754
47d281e6
FM
755#endif // #if WXWIN_COMPATIBILITY_2_8
756
1f1070e2 757// Return just the filename, not the path (basename)
50920146 758wxChar *wxFileNameFromPath (wxChar *path)
c801d85f 759{
1f1070e2
VZ
760 wxString p = path;
761 wxString n = wxFileNameFromPath(p);
2db300c6 762
1f1070e2 763 return path + p.length() - n.length();
c801d85f
KB
764}
765
1f1070e2 766wxString wxFileNameFromPath (const wxString& path)
c801d85f 767{
1f1070e2
VZ
768 wxString name, ext;
769 wxFileName::SplitPath(path, NULL, &name, &ext);
2db300c6 770
1f1070e2
VZ
771 wxString fullname = name;
772 if ( !ext.empty() )
773 {
774 fullname << wxFILE_SEP_EXT << ext;
c801d85f 775 }
1f1070e2
VZ
776
777 return fullname;
c801d85f
KB
778}
779
780// Return just the directory, or NULL if no directory
50920146
OK
781wxChar *
782wxPathOnly (wxChar *path)
c801d85f 783{
e8e1d09e 784 if (path && *path)
c801d85f 785 {
e8e1d09e 786 static wxChar buf[_MAXPATHLEN];
2db300c6 787
e8e1d09e
GD
788 // Local copy
789 wxStrcpy (buf, path);
2db300c6 790
e8e1d09e
GD
791 int l = wxStrlen(path);
792 int i = l - 1;
2db300c6 793
e8e1d09e
GD
794 // Search backward for a backward or forward slash
795 while (i > -1)
796 {
e8e1d09e
GD
797 // Unix like or Windows
798 if (path[i] == wxT('/') || path[i] == wxT('\\'))
799 {
800 buf[i] = 0;
801 return buf;
802 }
c801d85f 803#ifdef __VMS__
e8e1d09e
GD
804 if (path[i] == wxT(']'))
805 {
806 buf[i+1] = 0;
807 return buf;
808 }
a339970a 809#endif
e8e1d09e 810 i --;
c801d85f 811 }
2db300c6 812
5a3912f2 813#if defined(__WXMSW__) || defined(__OS2__)
e8e1d09e
GD
814 // Try Drive specifier
815 if (wxIsalpha (buf[0]) && buf[1] == wxT(':'))
3f4a0c5b 816 {
e8e1d09e
GD
817 // A:junk --> A:. (since A:.\junk Not A:\junk)
818 buf[2] = wxT('.');
819 buf[3] = wxT('\0');
820 return buf;
3f4a0c5b 821 }
c801d85f
KB
822#endif
823 }
d3b9f782 824 return NULL;
c801d85f
KB
825}
826
827// Return just the directory, or NULL if no directory
828wxString wxPathOnly (const wxString& path)
829{
b494c48b 830 if (!path.empty())
c801d85f 831 {
e8e1d09e 832 wxChar buf[_MAXPATHLEN];
2db300c6 833
e8e1d09e 834 // Local copy
52de37c7 835 wxStrcpy(buf, path);
2db300c6 836
ce045aed 837 int l = path.length();
e8e1d09e
GD
838 int i = l - 1;
839
840 // Search backward for a backward or forward slash
841 while (i > -1)
842 {
e8e1d09e
GD
843 // Unix like or Windows
844 if (path[i] == wxT('/') || path[i] == wxT('\\'))
845 {
5c760b84
JS
846 // Don't return an empty string
847 if (i == 0)
848 i ++;
e8e1d09e
GD
849 buf[i] = 0;
850 return wxString(buf);
851 }
c801d85f 852#ifdef __VMS__
e8e1d09e
GD
853 if (path[i] == wxT(']'))
854 {
855 buf[i+1] = 0;
856 return wxString(buf);
857 }
a339970a 858#endif
e8e1d09e 859 i --;
c801d85f 860 }
2db300c6 861
5a3912f2 862#if defined(__WXMSW__) || defined(__OS2__)
e8e1d09e
GD
863 // Try Drive specifier
864 if (wxIsalpha (buf[0]) && buf[1] == wxT(':'))
3f4a0c5b 865 {
e8e1d09e
GD
866 // A:junk --> A:. (since A:.\junk Not A:\junk)
867 buf[2] = wxT('.');
868 buf[3] = wxT('\0');
869 return wxString(buf);
3f4a0c5b 870 }
c801d85f
KB
871#endif
872 }
b494c48b 873 return wxEmptyString;
c801d85f
KB
874}
875
876// Utility for converting delimiters in DOS filenames to UNIX style
877// and back again - or we get nasty problems with delimiters.
878// Also, convert to lower case, since case is significant in UNIX.
879
c933e267 880#if defined(__WXMAC__) && !defined(__WXOSX_IPHONE__)
b0091f58 881
a2b77260 882#define kDefaultPathStyle kCFURLPOSIXPathStyle
a1c34a78 883
a62848fd 884wxString wxMacFSRefToPath( const FSRef *fsRef , CFStringRef additionalPathComponent )
a2b77260 885{
a62848fd 886 CFURLRef fullURLRef;
a2b77260
SC
887 fullURLRef = CFURLCreateFromFSRef(NULL, fsRef);
888 if ( additionalPathComponent )
889 {
890 CFURLRef parentURLRef = fullURLRef ;
891 fullURLRef = CFURLCreateCopyAppendingPathComponent(NULL, parentURLRef,
892 additionalPathComponent,false);
893 CFRelease( parentURLRef ) ;
894 }
a62848fd
WS
895 CFStringRef cfString = CFURLCopyFileSystemPath(fullURLRef, kDefaultPathStyle);
896 CFRelease( fullURLRef ) ;
739cb14a
SC
897 CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfString);
898 CFRelease( cfString );
a8d69700 899 CFStringNormalize(cfMutableString,kCFStringNormalizationFormC);
80539f04 900 return wxCFStringRef(cfMutableString).AsString();
bedaf53e 901}
e7549107 902
a62848fd 903OSStatus wxMacPathToFSRef( const wxString&path , FSRef *fsRef )
bedaf53e 904{
b1d4dd7a 905 OSStatus err = noErr ;
80539f04 906 CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, wxCFStringRef(path));
a8d69700 907 CFStringNormalize(cfMutableString,kCFStringNormalizationFormD);
739cb14a
SC
908 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kDefaultPathStyle, false);
909 CFRelease( cfMutableString );
a62848fd
WS
910 if ( NULL != url )
911 {
912 if ( CFURLGetFSRef(url, fsRef) == false )
913 err = fnfErr ;
a2b77260 914 CFRelease( url ) ;
bfc2bf62
SC
915 }
916 else
917 {
a2b77260 918 err = fnfErr ;
bfc2bf62 919 }
a2b77260 920 return err ;
bedaf53e
SC
921}
922
a62848fd 923wxString wxMacHFSUniStrToString( ConstHFSUniStr255Param uniname )
c4e41ce3 924{
a2b77260
SC
925 CFStringRef cfname = CFStringCreateWithCharacters( kCFAllocatorDefault,
926 uniname->unicode,
927 uniname->length );
739cb14a
SC
928 CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfname);
929 CFRelease( cfname );
a8d69700 930 CFStringNormalize(cfMutableString,kCFStringNormalizationFormC);
80539f04 931 return wxCFStringRef(cfMutableString).AsString() ;
c4e41ce3 932}
e7549107 933
fb743cab
SC
934#ifndef __LP64__
935
a2b77260 936wxString wxMacFSSpec2MacFilename( const FSSpec *spec )
17dff81c 937{
a2b77260
SC
938 FSRef fsRef ;
939 if ( FSpMakeFSRef( spec , &fsRef) == noErr )
e7549107 940 {
a2b77260 941 return wxMacFSRefToPath( &fsRef ) ;
e7549107 942 }
a2b77260 943 return wxEmptyString ;
17dff81c 944}
e7549107 945
a2b77260 946void wxMacFilename2FSSpec( const wxString& path , FSSpec *spec )
e7549107 947{
0ad76eea
SC
948 OSStatus err = noErr;
949 FSRef fsRef;
950 wxMacPathToFSRef( path , &fsRef );
47d281e6 951 err = FSGetCatalogInfo(&fsRef, kFSCatInfoNone, NULL, NULL, spec, NULL);
0ad76eea 952 verify_noerr( err );
e7549107 953}
fb743cab 954#endif
12d67f8a 955
e8e1d09e
GD
956#endif // __WXMAC__
957
47d281e6
FM
958
959#if WXWIN_COMPATIBILITY_2_8
960
52de37c7
VS
961template<typename T>
962static void wxDoDos2UnixFilename(T *s)
c801d85f
KB
963{
964 if (s)
965 while (*s)
966 {
4603b4f9
JS
967 if (*s == _T('\\'))
968 *s = _T('/');
e7549107 969#ifdef __WXMSW__
3f4a0c5b 970 else
52de37c7 971 *s = wxTolower(*s); // Case INDEPENDENT
c801d85f 972#endif
3f4a0c5b 973 s++;
c801d85f
KB
974 }
975}
976
52de37c7
VS
977void wxDos2UnixFilename(char *s) { wxDoDos2UnixFilename(s); }
978void wxDos2UnixFilename(wchar_t *s) { wxDoDos2UnixFilename(s); }
979
980template<typename T>
981static void
5a3912f2 982#if defined(__WXMSW__) || defined(__OS2__)
52de37c7 983wxDoUnix2DosFilename(T *s)
46dc76ba 984#else
52de37c7 985wxDoUnix2DosFilename(T *WXUNUSED(s) )
46dc76ba 986#endif
c801d85f
KB
987{
988// Yes, I really mean this to happen under DOS only! JACS
5a3912f2 989#if defined(__WXMSW__) || defined(__OS2__)
c801d85f
KB
990 if (s)
991 while (*s)
992 {
223d09f6
KB
993 if (*s == wxT('/'))
994 *s = wxT('\\');
3f4a0c5b 995 s++;
c801d85f
KB
996 }
997#endif
998}
999
52de37c7
VS
1000void wxUnix2DosFilename(char *s) { wxDoUnix2DosFilename(s); }
1001void wxUnix2DosFilename(wchar_t *s) { wxDoUnix2DosFilename(s); }
1002
47d281e6
FM
1003#endif // #if WXWIN_COMPATIBILITY_2_8
1004
c801d85f 1005// Concatenate two files to form third
3f4a0c5b 1006bool
c801d85f
KB
1007wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& file3)
1008{
b0c5cd0f
WS
1009#if wxUSE_FILE
1010
1011 wxFile in1(file1), in2(file2);
1012 wxTempFile out(file3);
1013
1014 if ( !in1.IsOpened() || !in2.IsOpened() || !out.IsOpened() )
1015 return false;
1016
1017 ssize_t ofs;
1018 unsigned char buf[1024];
1019
1020 for( int i=0; i<2; i++)
c801d85f 1021 {
b0c5cd0f
WS
1022 wxFile *in = i==0 ? &in1 : &in2;
1023 do{
1024 if ( (ofs = in->Read(buf,WXSIZEOF(buf))) == wxInvalidOffset ) return false;
1025 if ( ofs > 0 )
1026 if ( !out.Write(buf,ofs) )
1027 return false;
1028 } while ( ofs == (ssize_t)WXSIZEOF(buf) );
c801d85f
KB
1029 }
1030
b0c5cd0f
WS
1031 return out.Commit();
1032
1033#else
c801d85f 1034
b0c5cd0f
WS
1035 wxUnusedVar(file1);
1036 wxUnusedVar(file2);
1037 wxUnusedVar(file3);
1038 return false;
c801d85f 1039
b0c5cd0f 1040#endif
c801d85f
KB
1041}
1042
0597e7f9
VZ
1043// helper of generic implementation of wxCopyFile()
1044#if !(defined(__WIN32__) || defined(__OS2__) || defined(__PALMOS__)) && \
1045 wxUSE_FILE
1046
1047static bool
1048wxDoCopyFile(wxFile& fileIn,
1049 const wxStructStat& fbuf,
1050 const wxString& filenameDst,
1051 bool overwrite)
1052{
1053 // reset the umask as we want to create the file with exactly the same
1054 // permissions as the original one
1055 wxCHANGE_UMASK(0);
1056
1057 // create file2 with the same permissions than file1 and open it for
1058 // writing
1059
1060 wxFile fileOut;
1061 if ( !fileOut.Create(filenameDst, overwrite, fbuf.st_mode & 0777) )
1062 return false;
1063
1064 // copy contents of file1 to file2
1065 char buf[4096];
1066 for ( ;; )
1067 {
1068 ssize_t count = fileIn.Read(buf, WXSIZEOF(buf));
1069 if ( count == wxInvalidOffset )
1070 return false;
1071
1072 // end of file?
1073 if ( !count )
1074 break;
1075
1076 if ( fileOut.Write(buf, count) < (size_t)count )
1077 return false;
1078 }
1079
1080 // we can expect fileIn to be closed successfully, but we should ensure
1081 // that fileOut was closed as some write errors (disk full) might not be
1082 // detected before doing this
1083 return fileIn.Close() && fileOut.Close();
1084}
1085
1086#endif // generic implementation of wxCopyFile
1087
c801d85f 1088// Copy files
3f4a0c5b 1089bool
4658c44e 1090wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite)
c801d85f 1091{
04ef50df 1092#if defined(__WIN32__) && !defined(__WXMICROWIN__)
4658c44e
VZ
1093 // CopyFile() copies file attributes and modification time too, so use it
1094 // instead of our code if available
1095 //
1096 // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite
e0a050e3 1097 if ( !::CopyFile(file1.fn_str(), file2.fn_str(), !overwrite) )
564225a1
VZ
1098 {
1099 wxLogSysError(_("Failed to copy the file '%s' to '%s'"),
1100 file1.c_str(), file2.c_str());
1101
79e162f5 1102 return false;
564225a1 1103 }
5a3912f2 1104#elif defined(__OS2__)
1f3d9911 1105 if ( ::DosCopy(file1.c_str(), file2.c_str(), overwrite ? DCPY_EXISTING : 0) != 0 )
79e162f5 1106 return false;
68351053
WS
1107#elif defined(__PALMOS__)
1108 // TODO with http://www.palmos.com/dev/support/docs/protein_books/Memory_Databases_Files/
1109 return false;
98438730 1110#elif wxUSE_FILE // !Win32
32f31043 1111
b1ac3b56 1112 wxStructStat fbuf;
32f31043 1113 // get permissions of file1
b1ac3b56 1114 if ( wxStat( file1.c_str(), &fbuf) != 0 )
32f31043
VZ
1115 {
1116 // the file probably doesn't exist or we haven't the rights to read
1117 // from it anyhow
1118 wxLogSysError(_("Impossible to get permissions for file '%s'"),
1119 file1.c_str());
79e162f5 1120 return false;
32f31043
VZ
1121 }
1122
1123 // open file1 for reading
1124 wxFile fileIn(file1, wxFile::read);
a339970a 1125 if ( !fileIn.IsOpened() )
79e162f5 1126 return false;
c801d85f 1127
32f31043
VZ
1128 // remove file2, if it exists. This is needed for creating
1129 // file2 with the correct permissions in the next step
4658c44e 1130 if ( wxFileExists(file2) && (!overwrite || !wxRemoveFile(file2)))
32f31043
VZ
1131 {
1132 wxLogSysError(_("Impossible to overwrite the file '%s'"),
1133 file2.c_str());
79e162f5 1134 return false;
32f31043
VZ
1135 }
1136
0597e7f9 1137 wxDoCopyFile(fileIn, fbuf, file2, overwrite);
32f31043 1138
0597e7f9
VZ
1139#if defined(__WXMAC__) || defined(__WXCOCOA__)
1140 // copy the resource fork of the file too if it's present
1141 wxString pathRsrcOut;
1142 wxFile fileRsrcIn;
c801d85f 1143
c7386783 1144 {
0597e7f9
VZ
1145 // suppress error messages from this block as resource forks don't have
1146 // to exist
1147 wxLogNull noLog;
1148
1149 // it's not enough to check for file existence: it always does on HFS
1150 // but is empty for files without resources
1151 if ( fileRsrcIn.Open(file1 + wxT("/..namedfork/rsrc")) &&
1152 fileRsrcIn.Length() > 0 )
1153 {
1154 // we must be using HFS or another filesystem with resource fork
1155 // support, suppose that destination file system also is HFS[-like]
1156 pathRsrcOut = file2 + wxT("/..namedfork/rsrc");
1157 }
1158 else // check if we have resource fork in separate file (non-HFS case)
1159 {
1160 wxFileName fnRsrc(file1);
1161 fnRsrc.SetName(wxT("._") + fnRsrc.GetName());
a339970a 1162
0597e7f9
VZ
1163 fileRsrcIn.Close();
1164 if ( fileRsrcIn.Open( fnRsrc.GetFullPath() ) )
1165 {
1166 fnRsrc = file2;
1167 fnRsrc.SetName(wxT("._") + fnRsrc.GetName());
a339970a 1168
0597e7f9
VZ
1169 pathRsrcOut = fnRsrc.GetFullPath();
1170 }
1171 }
c7386783 1172 }
c801d85f 1173
0597e7f9
VZ
1174 if ( !pathRsrcOut.empty() )
1175 {
1176 if ( !wxDoCopyFile(fileRsrcIn, fbuf, pathRsrcOut, overwrite) )
1177 return false;
1178 }
1179#endif // wxMac || wxCocoa
abb74e97 1180
5fde6fcc 1181#if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__)
abb74e97
VZ
1182 // no chmod in VA. Should be some permission API for HPFS386 partitions
1183 // however
4a3c54bf 1184 if ( chmod(file2.fn_str(), fbuf.st_mode) != 0 )
32f31043
VZ
1185 {
1186 wxLogSysError(_("Impossible to set permissions for the file '%s'"),
1187 file2.c_str());
79e162f5 1188 return false;
32f31043 1189 }
4658c44e 1190#endif // OS/2 || Mac
98438730
WS
1191
1192#else // !Win32 && ! wxUSE_FILE
1193
1194 // impossible to simulate with wxWidgets API
1195 wxUnusedVar(file1);
1196 wxUnusedVar(file2);
1197 wxUnusedVar(overwrite);
1198 return false;
1199
564225a1 1200#endif // __WXMSW__ && __WIN32__
4658c44e 1201
79e162f5 1202 return true;
c801d85f
KB
1203}
1204
3f4a0c5b 1205bool
57e988b8 1206wxRenameFile(const wxString& file1, const wxString& file2, bool overwrite)
c801d85f 1207{
57e988b8
VZ
1208 if ( !overwrite && wxFileExists(file2) )
1209 {
1210 wxLogSysError
1211 (
1212 _("Failed to rename the file '%s' to '%s' because the destination file already exists."),
1213 file1.c_str(), file2.c_str()
1214 );
1215
1216 return false;
1217 }
1218
68351053 1219#if !defined(__WXWINCE__) && !defined(__WXPALMOS__)
1c193821 1220 // Normal system call
c3396917 1221 if ( wxRename (file1, file2) == 0 )
79e162f5 1222 return true;
1c193821 1223#endif
a339970a 1224
c801d85f 1225 // Try to copy
57e988b8 1226 if (wxCopyFile(file1, file2, overwrite)) {
c801d85f 1227 wxRemoveFile(file1);
79e162f5 1228 return true;
c801d85f
KB
1229 }
1230 // Give up
79e162f5 1231 return false;
c801d85f
KB
1232}
1233
1234bool wxRemoveFile(const wxString& file)
1235{
161f4f73
VZ
1236#if defined(__VISUALC__) \
1237 || defined(__BORLANDC__) \
1238 || defined(__WATCOMC__) \
ba1e9d6c 1239 || defined(__DMC__) \
e874f867
SC
1240 || defined(__GNUWIN32__) \
1241 || (defined(__MWERKS__) && defined(__MSL__))
68351053 1242 int res = wxRemove(file);
c4e41ce3 1243#elif defined(__WXMAC__)
e0a050e3 1244 int res = unlink(file.fn_str());
68351053
WS
1245#elif defined(__WXPALMOS__)
1246 int res = 1;
1247 // TODO with VFSFileDelete()
c801d85f 1248#else
4a3c54bf 1249 int res = unlink(file.fn_str());
c801d85f 1250#endif
a339970a 1251
68351053 1252 return res == 0;
c801d85f
KB
1253}
1254
1a33c3ba 1255bool wxMkdir(const wxString& dir, int perm)
c801d85f 1256{
68351053
WS
1257#if defined(__WXPALMOS__)
1258 return false;
4a3c54bf
VZ
1259#else
1260#if defined(__WXMAC__) && !defined(__UNIX__)
1261 if ( mkdir(dir.fn_str(), 0) != 0 )
1a33c3ba 1262
c2ff79b1 1263 // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too
7708abe9 1264 // for the GNU compiler
4a3c54bf
VZ
1265#elif (!(defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__))) || \
1266 (defined(__GNUWIN32__) && !defined(__MINGW32__)) || \
1267 defined(__WINE__) || defined(__WXMICROWIN__)
1268 const wxChar *dirname = dir.c_str();
9c8cd106 1269 #if defined(MSVCRT)
79e162f5 1270 wxUnusedVar(perm);
2e38557f 1271 if ( mkdir(wxFNCONV(dirname)) != 0 )
9c8cd106
WS
1272 #else
1273 if ( mkdir(wxFNCONV(dirname), perm) != 0 )
2e38557f 1274 #endif
5a3912f2 1275#elif defined(__OS2__)
7a893a31 1276 wxUnusedVar(perm);
4a3c54bf 1277 if (::DosCreateDir(dir.c_str(), NULL) != 0) // enhance for EAB's??
b916f809 1278#elif defined(__DOS__)
4a3c54bf 1279 const wxChar *dirname = dir.c_str();
b916f809
VS
1280 #if defined(__WATCOMC__)
1281 (void)perm;
1282 if ( wxMkDir(wxFNSTRINGCAST wxFNCONV(dirname)) != 0 )
1283 #elif defined(__DJGPP__)
1284 if ( mkdir(wxFNCONV(dirname), perm) != 0 )
1285 #else
1286 #error "Unsupported DOS compiler!"
1287 #endif
1288#else // !MSW, !DOS and !OS/2 VAC++
a6f4dbbd 1289 wxUnusedVar(perm);
4a3c54bf
VZ
1290 #ifdef __WXWINCE__
1291 if ( CreateDirectory(dir, NULL) == 0 )
1292 #else
a6f4dbbd 1293 if ( wxMkDir(dir.fn_str()) != 0 )
4a3c54bf 1294 #endif
7708abe9 1295#endif // !MSW/MSW
1a33c3ba 1296 {
4a3c54bf 1297 wxLogSysError(_("Directory '%s' couldn't be created"), dir);
79e162f5 1298 return false;
1a33c3ba
VZ
1299 }
1300
79e162f5 1301 return true;
4a3c54bf 1302#endif // PALMOS/!PALMOS
c801d85f
KB
1303}
1304
1305bool wxRmdir(const wxString& dir, int WXUNUSED(flags))
1306{
68351053 1307#if defined(__VMS__)
79e162f5 1308 return false; //to be changed since rmdir exists in VMS7.x
68351053
WS
1309#elif defined(__WXPALMOS__)
1310 // TODO with VFSFileRename()
1311 return false;
a3ef5bf5 1312#else
4a3c54bf
VZ
1313 #if defined(__OS2__)
1314 if ( ::DosDeleteDir(dir.c_str()) != 0 )
1315 #elif defined(__WXWINCE__)
1316 if ( RemoveDirectory(dir) == 0 )
1317 #else
1318 if ( wxRmDir(dir.fn_str()) != 0 )
1319 #endif
1320 {
1321 wxLogSysError(_("Directory '%s' couldn't be deleted"), dir);
1322 return false;
1323 }
1324
1325 return true;
1326#endif // PALMOS/!PALMOS
c801d85f
KB
1327}
1328
c801d85f 1329// does the path exists? (may have or not '/' or '\\' at the end)
e960c20e 1330bool wxDirExists(const wxString& pathName)
c801d85f 1331{
e960c20e 1332 wxString strPath(pathName);
e32d659d 1333
5a3912f2 1334#if defined(__WINDOWS__) || defined(__OS2__)
f6bcfd97
BP
1335 // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists,
1336 // so remove all trailing backslashes from the path - but don't do this for
56614e51 1337 // the paths "d:\" (which are different from "d:") nor for just "\"
f6bcfd97
BP
1338 while ( wxEndsWithPathSeparator(strPath) )
1339 {
1340 size_t len = strPath.length();
cc4a1ce1 1341 if ( len == 1 || (len == 3 && strPath[len - 2] == _T(':')) )
f6bcfd97 1342 break;
c801d85f 1343
f6bcfd97
BP
1344 strPath.Truncate(len - 1);
1345 }
1346#endif // __WINDOWS__
1347
5a3912f2
SN
1348#ifdef __OS2__
1349 // OS/2 can't handle "d:", it wants either "d:\" or "d:."
1d4f9cb7 1350 if (strPath.length() == 2 && strPath[1u] == _T(':'))
5a3912f2
SN
1351 strPath << _T('.');
1352#endif
1353
68351053
WS
1354#if defined(__WXPALMOS__)
1355 return false;
1356#elif defined(__WIN32__) && !defined(__WXMICROWIN__)
e32d659d 1357 // stat() can't cope with network paths
e0a050e3 1358 DWORD ret = ::GetFileAttributes(strPath.fn_str());
2db300c6 1359
834c8ade 1360 return (ret != INVALID_FILE_ATTRIBUTES) && (ret & FILE_ATTRIBUTE_DIRECTORY);
27b2dd53 1361#elif defined(__OS2__)
fe1f34f8
SN
1362 FILESTATUS3 Info = {{0}};
1363 APIRET rc = ::DosQueryPathInfo((PSZ)(WXSTRINGCAST strPath), FIL_STANDARD,
1364 (void*) &Info, sizeof(FILESTATUS3));
1365
1366 return ((rc == NO_ERROR) && (Info.attrFile & FILE_DIRECTORY)) ||
1367 (rc == ERROR_SHARING_VIOLATION);
1368 // If we got a sharing violation, there must be something with this name.
e32d659d 1369#else // !__WIN32__
4c97e024 1370
f6bcfd97 1371 wxStructStat st;
71c97a89 1372#ifndef __VISAGECPP__
5a3912f2 1373 return wxStat(strPath.c_str(), &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR);
71c97a89
DW
1374#else
1375 // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only
e960c20e 1376 return wxStat(strPath.c_str(), &st) == 0 && (st.st_mode == S_IFDIR);
71c97a89
DW
1377#endif
1378
e32d659d 1379#endif // __WIN32__/!__WIN32__
c801d85f
KB
1380}
1381
47d281e6
FM
1382#if WXWIN_COMPATIBILITY_2_8
1383
c801d85f 1384// Get a temporary filename, opening and closing the file.
50920146 1385wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf)
c801d85f 1386{
e44d5a58
VZ
1387 wxString filename;
1388 if ( !wxGetTempFileName(prefix, filename) )
ade35f11 1389 return NULL;
c801d85f 1390
ade35f11 1391 if ( buf )
fcb9fb91
VZ
1392#ifdef _PACC_VER
1393 // work around the PalmOS pacc compiler bug
1394 wxStrcpy(buf, filename.data());
1395#else
ade35f11 1396 wxStrcpy(buf, filename);
fcb9fb91 1397#endif
ade35f11 1398 else
f526f752 1399 buf = MYcopystring(filename);
c801d85f 1400
ade35f11 1401 return buf;
c801d85f
KB
1402}
1403
c0ab6adf
JS
1404bool wxGetTempFileName(const wxString& prefix, wxString& buf)
1405{
e44d5a58 1406#if wxUSE_FILE
522d32e5 1407 buf = wxFileName::CreateTempFileName(prefix);
ade35f11
VZ
1408
1409 return !buf.empty();
e44d5a58
VZ
1410#else // !wxUSE_FILE
1411 wxUnusedVar(prefix);
1412 wxUnusedVar(buf);
1413
1414 return false;
1415#endif // wxUSE_FILE/!wxUSE_FILE
c0ab6adf
JS
1416}
1417
47d281e6
FM
1418#endif // #if WXWIN_COMPATIBILITY_2_8
1419
c801d85f
KB
1420// Get first file name matching given wild card.
1421
8ff12342
VS
1422static wxDir *gs_dir = NULL;
1423static wxString gs_dirPath;
1424
52de37c7 1425wxString wxFindFirstFile(const wxString& spec, int flags)
8ff12342 1426{
47d281e6 1427 wxFileName::SplitPath(spec, &gs_dirPath, NULL, NULL);
a6f4dbbd 1428 if ( gs_dirPath.empty() )
8ff12342 1429 gs_dirPath = wxT(".");
083f7497 1430 if ( !wxEndsWithPathSeparator(gs_dirPath ) )
8ff12342
VS
1431 gs_dirPath << wxFILE_SEP_PATH;
1432
31004b74 1433 delete gs_dir; // can be NULL, this is ok
8ff12342 1434 gs_dir = new wxDir(gs_dirPath);
2db300c6 1435
8ff12342
VS
1436 if ( !gs_dir->IsOpened() )
1437 {
1438 wxLogSysError(_("Can not enumerate files '%s'"), spec);
1439 return wxEmptyString;
1440 }
2db300c6 1441
999836aa 1442 int dirFlags;
8ff12342
VS
1443 switch (flags)
1444 {
1445 case wxDIR: dirFlags = wxDIR_DIRS; break;
1446 case wxFILE: dirFlags = wxDIR_FILES; break;
1447 default: dirFlags = wxDIR_DIRS | wxDIR_FILES; break;
1448 }
2db300c6 1449
8ff12342 1450 wxString result;
52de37c7 1451 gs_dir->GetFirst(&result, wxFileNameFromPath(spec), dirFlags);
a6f4dbbd 1452 if ( result.empty() )
e168b6ac 1453 {
8ff12342 1454 wxDELETE(gs_dir);
e168b6ac
VS
1455 return result;
1456 }
8ff12342
VS
1457
1458 return gs_dirPath + result;
1459}
1460
1461wxString wxFindNextFile()
1462{
31004b74 1463 wxCHECK_MSG( gs_dir, "", "You must call wxFindFirstFile before!" );
8ff12342
VS
1464
1465 wxString result;
1466 gs_dir->GetNext(&result);
2db300c6 1467
a6f4dbbd 1468 if ( result.empty() )
e168b6ac 1469 {
8ff12342 1470 wxDELETE(gs_dir);
e168b6ac
VS
1471 return result;
1472 }
2db300c6 1473
8ff12342
VS
1474 return gs_dirPath + result;
1475}
1476
c801d85f
KB
1477
1478// Get current working directory.
ce045aed
WS
1479// If buf is NULL, allocates space using new, else copies into buf.
1480// wxGetWorkingDirectory() is obsolete, use wxGetCwd()
1481// wxDoGetCwd() is their common core to be moved
1482// to wxGetCwd() once wxGetWorkingDirectory() will be removed.
1483// Do not expose wxDoGetCwd in headers!
1484
1485wxChar *wxDoGetCwd(wxChar *buf, int sz)
c801d85f 1486{
68351053 1487#if defined(__WXPALMOS__)
ce045aed
WS
1488 // TODO
1489 if(buf && sz>0) buf[0] = _T('\0');
cdc05919 1490 return buf;
68351053 1491#elif defined(__WXWINCE__)
abf912c5 1492 // TODO
ce045aed 1493 if(buf && sz>0) buf[0] = _T('\0');
cdc05919 1494 return buf;
1c193821 1495#else
13b1f8a7 1496 if ( !buf )
f6bcfd97 1497 {
13b1f8a7
VZ
1498 buf = new wxChar[sz + 1];
1499 }
1500
79e162f5 1501 bool ok wxDUMMY_INITIALIZE(false);
13b1f8a7
VZ
1502
1503 // for the compilers which have Unicode version of _getcwd(), call it
1504 // directly, for the others call the ANSI version and do the translation
dbc38199 1505#if !wxUSE_UNICODE
247f8a77 1506 #define cbuf buf
dbc38199 1507#else // wxUSE_UNICODE
79e162f5 1508 bool needsANSI = true;
dbc38199 1509
247f8a77 1510 #if !defined(HAVE_WGETCWD) || wxUSE_UNICODE_MSLU
c35c94f6 1511 char cbuf[_MAXPATHLEN];
247f8a77 1512 #endif
dbc38199 1513
13b1f8a7 1514 #ifdef HAVE_WGETCWD
247f8a77 1515 #if wxUSE_UNICODE_MSLU
406d283a 1516 if ( wxGetOsVersion() != wxOS_WINDOWS_9X )
f5c0e657 1517 #else
79e162f5 1518 char *cbuf = NULL; // never really used because needsANSI will always be false
247f8a77
VS
1519 #endif
1520 {
1521 ok = _wgetcwd(buf, sz) != NULL;
79e162f5 1522 needsANSI = false;
247f8a77 1523 }
13b1f8a7 1524 #endif
13b1f8a7 1525
247f8a77 1526 if ( needsANSI )
dbc38199 1527#endif // wxUSE_UNICODE
247f8a77 1528 {
29d0a26e 1529 #if defined(_MSC_VER) || defined(__MINGW32__)
dbc38199 1530 ok = _getcwd(cbuf, sz) != NULL;
5a3912f2 1531 #elif defined(__OS2__)
13b1f8a7 1532 APIRET rc;
5a3912f2
SN
1533 ULONG ulDriveNum = 0;
1534 ULONG ulDriveMap = 0;
a62848fd 1535 rc = ::DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap);
5a3912f2 1536 ok = rc == 0;
a62848fd
WS
1537 if (ok)
1538 {
1539 sz -= 3;
1540 rc = ::DosQueryCurrentDir( 0 // current drive
089e9521 1541 ,(PBYTE)cbuf + 3
5a3912f2
SN
1542 ,(PULONG)&sz
1543 );
7a893a31 1544 cbuf[0] = char('A' + (ulDriveNum - 1));
5a3912f2
SN
1545 cbuf[1] = ':';
1546 cbuf[2] = '\\';
1547 ok = rc == 0;
1548 }
13b1f8a7 1549 #else // !Win32/VC++ !Mac !OS2
dbc38199 1550 ok = getcwd(cbuf, sz) != NULL;
13b1f8a7 1551 #endif // platform
247f8a77 1552
0ad76eea 1553 #if wxUSE_UNICODE
247f8a77
VS
1554 // finally convert the result to Unicode if needed
1555 wxConvFile.MB2WC(buf, cbuf, sz);
1556 #endif // wxUSE_UNICODE
1557 }
13b1f8a7
VZ
1558
1559 if ( !ok )
19193a2c 1560 {
13b1f8a7 1561 wxLogSysError(_("Failed to get the working directory"));
19193a2c 1562
13b1f8a7
VZ
1563 // VZ: the old code used to return "." on error which didn't make any
1564 // sense at all to me - empty string is a better error indicator
1565 // (NULL might be even better but I'm afraid this could lead to
1566 // problems with the old code assuming the return is never NULL)
1567 buf[0] = _T('\0');
19193a2c 1568 }
13b1f8a7 1569 else // ok, but we might need to massage the path into the right format
19193a2c 1570 {
4b00a538 1571#ifdef __DJGPP__
13b1f8a7
VZ
1572 // VS: DJGPP is a strange mix of DOS and UNIX API and returns paths
1573 // with / deliminers. We don't like that.
1574 for (wxChar *ch = buf; *ch; ch++)
1575 {
1576 if (*ch == wxT('/'))
1577 *ch = wxT('\\');
1578 }
1579#endif // __DJGPP__
1580
17234b26
MB
1581// MBN: we hope that in the case the user is compiling a GTK+/Motif app,
1582// he needs Unix as opposed to Win32 pathnames
1583#if defined( __CYGWIN__ ) && defined( __WINDOWS__ )
3ffbc733 1584 // another example of DOS/Unix mix (Cygwin)
13b1f8a7 1585 wxString pathUnix = buf;
7682e22e
VZ
1586#if wxUSE_UNICODE
1587 char bufA[_MAXPATHLEN];
1588 cygwin_conv_to_full_win32_path(pathUnix.mb_str(wxConvFile), bufA);
1589 wxConvFile.MB2WC(buf, bufA, sz);
1590#else
13b1f8a7 1591 cygwin_conv_to_full_win32_path(pathUnix, buf);
7682e22e 1592#endif // wxUSE_UNICODE
e02e8816 1593#endif // __CYGWIN__
13b1f8a7 1594 }
4b00a538 1595
13b1f8a7 1596 return buf;
dbc38199
VS
1597
1598#if !wxUSE_UNICODE
247f8a77 1599 #undef cbuf
dbc38199 1600#endif
1c193821
JS
1601
1602#endif
1603 // __WXWINCE__
c801d85f
KB
1604}
1605
2587df2c
VS
1606#if WXWIN_COMPATIBILITY_2_6
1607wxChar *wxGetWorkingDirectory(wxChar *buf, int sz)
1608{
1609 return wxDoGetCwd(buf,sz);
1610}
1611#endif // WXWIN_COMPATIBILITY_2_6
1612
ce045aed
WS
1613wxString wxGetCwd()
1614{
1615 wxString str;
1616 wxDoGetCwd(wxStringBuffer(str, _MAXPATHLEN), _MAXPATHLEN);
eac2aeb0 1617 return str;
7af89395
VZ
1618}
1619
c801d85f
KB
1620bool wxSetWorkingDirectory(const wxString& d)
1621{
5a3912f2 1622#if defined(__OS2__)
43c97407
SN
1623 if (d[1] == ':')
1624 {
5a1e0e91 1625 ::DosSetDefaultDisk(wxToupper(d[0]) - _T('A') + 1);
2b2883a5
JS
1626 // do not call DosSetCurrentDir when just changing drive,
1627 // since it requires e.g. "d:." instead of "d:"!
1628 if (d.length() == 2)
1629 return true;
43c97407 1630 }
1f3d9911 1631 return (::DosSetCurrentDir(d.c_str()) == 0);
5a3912f2
SN
1632#elif defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__)
1633 return (chdir(wxFNSTRINGCAST d.fn_str()) == 0);
34138703 1634#elif defined(__WINDOWS__)
a62848fd 1635
c801d85f 1636#ifdef __WIN32__
1c193821
JS
1637#ifdef __WXWINCE__
1638 // No equivalent in WinCE
abf912c5 1639 wxUnusedVar(d);
79e162f5 1640 return false;
c801d85f 1641#else
e0a050e3 1642 return (bool)(SetCurrentDirectory(d.fn_str()) != 0);
1c193821
JS
1643#endif
1644#else
1645 // Must change drive, too.
1646 bool isDriveSpec = ((strlen(d) > 1) && (d[1] == ':'));
1647 if (isDriveSpec)
c801d85f 1648 {
1c193821 1649 wxChar firstChar = d[0];
a62848fd 1650
1c193821
JS
1651 // To upper case
1652 if (firstChar > 90)
1653 firstChar = firstChar - 32;
a62848fd 1654
1c193821
JS
1655 // To a drive number
1656 unsigned int driveNo = firstChar - 64;
1657 if (driveNo > 0)
1658 {
1659 unsigned int noDrives;
1660 _dos_setdrive(driveNo, &noDrives);
1661 }
c801d85f 1662 }
1c193821 1663 bool success = (chdir(WXSTRINGCAST d) == 0);
a62848fd 1664
1c193821 1665 return success;
c801d85f 1666#endif
a62848fd 1667
c801d85f
KB
1668#endif
1669}
1670
631f1bfe
JS
1671// Get the OS directory if appropriate (such as the Windows directory).
1672// On non-Windows platform, probably just return the empty string.
1673wxString wxGetOSDirectory()
1674{
1c193821
JS
1675#ifdef __WXWINCE__
1676 return wxString(wxT("\\Windows"));
1677#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__)
50920146 1678 wxChar buf[256];
631f1bfe
JS
1679 GetWindowsDirectory(buf, 256);
1680 return wxString(buf);
26eef304 1681#elif defined(__WXMAC__) && wxOSX_USE_CARBON
2d3441d7 1682 return wxMacFindFolder(kOnSystemDisk, 'macs', false);
631f1bfe
JS
1683#else
1684 return wxEmptyString;
1685#endif
1686}
1687
52de37c7 1688bool wxEndsWithPathSeparator(const wxString& filename)
c801d85f 1689{
52de37c7 1690 return !filename.empty() && wxIsPathSeparator(filename.Last());
c801d85f
KB
1691}
1692
79e162f5 1693// find a file in a list of directories, returns false if not found
52de37c7 1694bool wxFindFileInPath(wxString *pStr, const wxString& szPath, const wxString& szFile)
c801d85f 1695{
a17e237f 1696 // we assume that it's not empty
52de37c7 1697 wxCHECK_MSG( !szFile.empty(), false,
f6bcfd97 1698 _T("empty file name in wxFindFileInPath"));
a17e237f
VZ
1699
1700 // skip path separator in the beginning of the file name if present
52de37c7
VS
1701 wxString szFile2;
1702 if ( wxIsPathSeparator(szFile[0u]) )
1703 szFile2 = szFile.Mid(1);
1704 else
1705 szFile2 = szFile;
1706
1707 wxStringTokenizer tkn(szPath, wxPATH_SEP);
1708
1709 while ( tkn.HasMoreTokens() )
a17e237f 1710 {
52de37c7
VS
1711 wxString strFile = tkn.GetNextToken();
1712 if ( !wxEndsWithPathSeparator(strFile) )
a17e237f 1713 strFile += wxFILE_SEP_PATH;
52de37c7 1714 strFile += szFile2;
a17e237f 1715
52de37c7
VS
1716 if ( wxFileExists(strFile) )
1717 {
a17e237f 1718 *pStr = strFile;
52de37c7 1719 return true;
a17e237f 1720 }
c801d85f 1721 }
c801d85f 1722
52de37c7 1723 return false;
c801d85f
KB
1724}
1725
47d281e6 1726#if WXWIN_COMPATIBILITY_2_8
163b3ad7 1727void WXDLLIMPEXP_BASE wxSplitPath(const wxString& fileName,
3826db3e
VZ
1728 wxString *pstrPath,
1729 wxString *pstrName,
1730 wxString *pstrExt)
1731{
52de37c7 1732 wxFileName::SplitPath(fileName, pstrPath, pstrName, pstrExt);
3826db3e 1733}
47d281e6 1734#endif // #if WXWIN_COMPATIBILITY_2_8
7f555861 1735
2c5e5cbd
VS
1736#if wxUSE_DATETIME
1737
163b3ad7 1738time_t WXDLLIMPEXP_BASE wxFileModificationTime(const wxString& filename)
a47ce4a7 1739{
2936a6b1
VZ
1740 wxDateTime mtime;
1741 if ( !wxFileName(filename).GetTimes(NULL, &mtime, NULL) )
1742 return (time_t)-1;
a62848fd 1743
2936a6b1 1744 return mtime.GetTicks();
a47ce4a7
VS
1745}
1746
2c5e5cbd
VS
1747#endif // wxUSE_DATETIME
1748
a47ce4a7 1749
9e152a55
WS
1750// Parses the filterStr, returning the number of filters.
1751// Returns 0 if none or if there's a problem.
daf32463 1752// filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpeg"
9e152a55 1753
163b3ad7 1754int WXDLLIMPEXP_BASE wxParseCommonDialogsFilter(const wxString& filterStr,
7bea7b91
WS
1755 wxArrayString& descriptions,
1756 wxArrayString& filters)
9e152a55
WS
1757{
1758 descriptions.Clear();
1759 filters.Clear();
1760
1761 wxString str(filterStr);
1762
1763 wxString description, filter;
1764 int pos = 0;
1765 while( pos != wxNOT_FOUND )
1766 {
1767 pos = str.Find(wxT('|'));
1768 if ( pos == wxNOT_FOUND )
1769 {
1770 // if there are no '|'s at all in the string just take the entire
daf32463 1771 // string as filter and make description empty for later autocompletion
9e152a55
WS
1772 if ( filters.IsEmpty() )
1773 {
daf32463 1774 descriptions.Add(wxEmptyString);
9e152a55
WS
1775 filters.Add(filterStr);
1776 }
1777 else
1778 {
1779 wxFAIL_MSG( _T("missing '|' in the wildcard string!") );
1780 }
1781
1782 break;
1783 }
1784
1785 description = str.Left(pos);
1786 str = str.Mid(pos + 1);
1787 pos = str.Find(wxT('|'));
1788 if ( pos == wxNOT_FOUND )
1789 {
1790 filter = str;
1791 }
1792 else
1793 {
1794 filter = str.Left(pos);
1795 str = str.Mid(pos + 1);
1796 }
1797
1798 descriptions.Add(description);
1799 filters.Add(filter);
1800 }
1801
daf32463
WS
1802#if defined(__WXMOTIF__)
1803 // split it so there is one wildcard per entry
1804 for( size_t i = 0 ; i < descriptions.GetCount() ; i++ )
1805 {
1806 pos = filters[i].Find(wxT(';'));
1807 if (pos != wxNOT_FOUND)
1808 {
1809 // first split only filters
1810 descriptions.Insert(descriptions[i],i+1);
1811 filters.Insert(filters[i].Mid(pos+1),i+1);
1812 filters[i]=filters[i].Left(pos);
1813
1814 // autoreplace new filter in description with pattern:
1815 // C/C++ Files(*.cpp;*.c;*.h)|*.cpp;*.c;*.h
1816 // cause split into:
1817 // C/C++ Files(*.cpp)|*.cpp
1818 // C/C++ Files(*.c;*.h)|*.c;*.h
1819 // and next iteration cause another split into:
1820 // C/C++ Files(*.cpp)|*.cpp
1821 // C/C++ Files(*.c)|*.c
1822 // C/C++ Files(*.h)|*.h
1823 for ( size_t k=i;k<i+2;k++ )
1824 {
1825 pos = descriptions[k].Find(filters[k]);
1826 if (pos != wxNOT_FOUND)
1827 {
1828 wxString before = descriptions[k].Left(pos);
1829 wxString after = descriptions[k].Mid(pos+filters[k].Len());
1830 pos = before.Find(_T('('),true);
1831 if (pos>before.Find(_T(')'),true))
1832 {
1833 before = before.Left(pos+1);
1834 before << filters[k];
1835 pos = after.Find(_T(')'));
1836 int pos1 = after.Find(_T('('));
1837 if (pos != wxNOT_FOUND && (pos<pos1 || pos1==wxNOT_FOUND))
1838 {
1839 before << after.Mid(pos);
1840 descriptions[k] = before;
1841 }
1842 }
1843 }
1844 }
1845 }
1846 }
1847#endif
1848
1849 // autocompletion
1850 for( size_t j = 0 ; j < descriptions.GetCount() ; j++ )
1851 {
489f6cf7 1852 if ( descriptions[j].empty() && !filters[j].empty() )
daf32463
WS
1853 {
1854 descriptions[j].Printf(_("Files (%s)"), filters[j].c_str());
1855 }
1856 }
1857
9e152a55
WS
1858 return filters.GetCount();
1859}
1860
968956aa 1861#if defined(__WINDOWS__) && !(defined(__UNIX__) || defined(__OS2__))
f2346d3f 1862static bool wxCheckWin32Permission(const wxString& path, DWORD access)
3ff07edb
RR
1863{
1864 // quoting the MSDN: "To obtain a handle to a directory, call the
f2346d3f
VZ
1865 // CreateFile function with the FILE_FLAG_BACKUP_SEMANTICS flag", but this
1866 // doesn't work under Win9x/ME but then it's not needed there anyhow
c9c023dd
VZ
1867 const DWORD dwAttr = ::GetFileAttributes(path.fn_str());
1868 if ( dwAttr == INVALID_FILE_ATTRIBUTES )
1869 {
1870 // file probably doesn't exist at all
1871 return false;
1872 }
1873
1874 if ( wxGetOsVersion() == wxOS_WINDOWS_9X )
3ff07edb 1875 {
f2346d3f 1876 // FAT directories always allow all access, even if they have the
c9c023dd
VZ
1877 // readonly flag set, and FAT files can only be read-only
1878 return (dwAttr & FILE_ATTRIBUTE_DIRECTORY) ||
1879 (access != GENERIC_WRITE ||
1880 !(dwAttr & FILE_ATTRIBUTE_READONLY));
3ff07edb 1881 }
3ff07edb 1882
f2346d3f
VZ
1883 HANDLE h = ::CreateFile
1884 (
6ad68ad8 1885 path.t_str(),
f2346d3f
VZ
1886 access,
1887 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1888 NULL,
1889 OPEN_EXISTING,
c9c023dd
VZ
1890 dwAttr & FILE_ATTRIBUTE_DIRECTORY
1891 ? FILE_FLAG_BACKUP_SEMANTICS
1892 : 0,
f2346d3f
VZ
1893 NULL
1894 );
1895 if ( h != INVALID_HANDLE_VALUE )
1896 CloseHandle(h);
1897
1898 return h != INVALID_HANDLE_VALUE;
3ff07edb 1899}
f2346d3f 1900#endif // __WINDOWS__
3ff07edb
RR
1901
1902bool wxIsWritable(const wxString &path)
1903{
2203a185 1904#if defined( __UNIX__ ) || defined(__OS2__)
3ff07edb 1905 // access() will take in count also symbolic links
0d4ba4ef 1906 return wxAccess(path.c_str(), W_OK) == 0;
3ff07edb 1907#elif defined( __WINDOWS__ )
f2346d3f 1908 return wxCheckWin32Permission(path, GENERIC_WRITE);
3ff07edb 1909#else
a8b6a1b1 1910 wxUnusedVar(path);
3ff07edb
RR
1911 // TODO
1912 return false;
1913#endif
1914}
1915
1916bool wxIsReadable(const wxString &path)
1917{
2203a185 1918#if defined( __UNIX__ ) || defined(__OS2__)
3ff07edb 1919 // access() will take in count also symbolic links
0d4ba4ef 1920 return wxAccess(path.c_str(), R_OK) == 0;
3ff07edb 1921#elif defined( __WINDOWS__ )
f2346d3f 1922 return wxCheckWin32Permission(path, GENERIC_READ);
3ff07edb 1923#else
a8b6a1b1 1924 wxUnusedVar(path);
3ff07edb
RR
1925 // TODO
1926 return false;
1927#endif
1928}
1929
1930bool wxIsExecutable(const wxString &path)
1931{
2203a185 1932#if defined( __UNIX__ ) || defined(__OS2__)
3ff07edb 1933 // access() will take in count also symbolic links
0d4ba4ef 1934 return wxAccess(path.c_str(), X_OK) == 0;
3ff07edb 1935#elif defined( __WINDOWS__ )
f2346d3f 1936 return wxCheckWin32Permission(path, GENERIC_EXECUTE);
3ff07edb 1937#else
a8b6a1b1 1938 wxUnusedVar(path);
3ff07edb
RR
1939 // TODO
1940 return false;
1941#endif
1942}
1943
693b31be
MW
1944// Return the type of an open file
1945//
1946// Some file types on some platforms seem seekable but in fact are not.
1947// The main use of this function is to allow such cases to be detected
1948// (IsSeekable() is implemented as wxGetFileKind() == wxFILE_KIND_DISK).
1949//
1950// This is important for the archive streams, which benefit greatly from
1951// being able to seek on a stream, but which will produce corrupt archives
1952// if they unknowingly seek on a non-seekable stream.
1953//
1954// wxFILE_KIND_DISK is a good catch all return value, since other values
1955// disable features of the archive streams. Some other value must be returned
1956// for a file type that appears seekable but isn't.
1957//
1958// Known examples:
1959// * Pipes on Windows
1960// * Files on VMS with a record format other than StreamLF
1961//
1962wxFileKind wxGetFileKind(int fd)
1963{
1964#if defined __WXMSW__ && !defined __WXWINCE__ && defined wxGetOSFHandle
1965 switch (::GetFileType(wxGetOSFHandle(fd)) & ~FILE_TYPE_REMOTE)
1966 {
1967 case FILE_TYPE_CHAR:
1968 return wxFILE_KIND_TERMINAL;
1969 case FILE_TYPE_DISK:
1970 return wxFILE_KIND_DISK;
1971 case FILE_TYPE_PIPE:
1972 return wxFILE_KIND_PIPE;
1973 }
1974
1975 return wxFILE_KIND_UNKNOWN;
1976
1977#elif defined(__UNIX__)
1978 if (isatty(fd))
1979 return wxFILE_KIND_TERMINAL;
1980
1981 struct stat st;
1982 fstat(fd, &st);
1983
1984 if (S_ISFIFO(st.st_mode))
1985 return wxFILE_KIND_PIPE;
1986 if (!S_ISREG(st.st_mode))
1987 return wxFILE_KIND_UNKNOWN;
1988
1989 #if defined(__VMS__)
1990 if (st.st_fab_rfm != FAB$C_STMLF)
1991 return wxFILE_KIND_UNKNOWN;
1992 #endif
1993
1994 return wxFILE_KIND_DISK;
1995
1996#else
1997 #define wxFILEKIND_STUB
1998 (void)fd;
1999 return wxFILE_KIND_DISK;
2000#endif
2001}
2002
2003wxFileKind wxGetFileKind(FILE *fp)
2004{
2005 // Note: The watcom rtl dll doesn't have fileno (the static lib does).
2006 // Should be fixed in version 1.4.
2007#if defined(wxFILEKIND_STUB) || wxONLY_WATCOM_EARLIER_THAN(1,4)
2008 (void)fp;
2009 return wxFILE_KIND_DISK;
bade0251 2010#elif defined(__WINDOWS__) && !defined(__CYGWIN__) && !defined(__WATCOMC__) && !defined(__WINE__)
693b31be
MW
2011 return fp ? wxGetFileKind(_fileno(fp)) : wxFILE_KIND_UNKNOWN;
2012#else
2013 return fp ? wxGetFileKind(fileno(fp)) : wxFILE_KIND_UNKNOWN;
2014#endif
2015}
2016
9e152a55 2017
7f555861
JS
2018//------------------------------------------------------------------------
2019// wild character routines
2020//------------------------------------------------------------------------
2021
2022bool wxIsWild( const wxString& pattern )
2023{
52de37c7 2024 for ( wxString::const_iterator p = pattern.begin(); p != pattern.end(); ++p )
2b5f62a0 2025 {
52de37c7 2026 switch ( (*p).GetValue() )
2b5f62a0 2027 {
52de37c7
VS
2028 case wxT('?'):
2029 case wxT('*'):
2030 case wxT('['):
2031 case wxT('{'):
2032 return true;
2033
2034 case wxT('\\'):
2035 if ( ++p == pattern.end() )
2036 return false;
3f4a0c5b 2037 }
7f555861 2038 }
79e162f5 2039 return false;
dfcb1ae0 2040}
dfcb1ae0 2041
2b5f62a0
VZ
2042/*
2043* Written By Douglas A. Lewis <dalewis@cs.Buffalo.EDU>
2044*
2045* The match procedure is public domain code (from ircII's reg.c)
b931e275 2046* but modified to suit our tastes (RN: No "%" syntax I guess)
2b5f62a0 2047*/
7be1f0d9 2048
2b5f62a0 2049bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special )
7f555861 2050{
7448de8d
WS
2051 if (text.empty())
2052 {
2053 /* Match if both are empty. */
2054 return pat.empty();
2055 }
2056
2057 const wxChar *m = pat.c_str(),
2058 *n = text.c_str(),
2059 *ma = NULL,
b931e275 2060 *na = NULL;
7448de8d 2061 int just = 0,
7448de8d
WS
2062 acount = 0,
2063 count = 0;
2064
2065 if (dot_special && (*n == wxT('.')))
2066 {
2067 /* Never match so that hidden Unix files
2068 * are never found. */
2069 return false;
2070 }
2071
2072 for (;;)
2073 {
2074 if (*m == wxT('*'))
2b5f62a0 2075 {
7448de8d
WS
2076 ma = ++m;
2077 na = n;
2078 just = 1;
7448de8d 2079 acount = count;
2b5f62a0 2080 }
7448de8d 2081 else if (*m == wxT('?'))
2b5f62a0 2082 {
7448de8d
WS
2083 m++;
2084 if (!*n++)
79e162f5 2085 return false;
2b5f62a0 2086 }
7448de8d 2087 else
2b5f62a0 2088 {
7448de8d
WS
2089 if (*m == wxT('\\'))
2090 {
2091 m++;
2092 /* Quoting "nothing" is a bad thing */
2093 if (!*m)
2094 return false;
2095 }
2096 if (!*m)
2097 {
2098 /*
2099 * If we are out of both strings or we just
2100 * saw a wildcard, then we can say we have a
2101 * match
2102 */
2103 if (!*n)
2104 return true;
2105 if (just)
2106 return true;
2107 just = 0;
2108 goto not_matched;
2109 }
2110 /*
2111 * We could check for *n == NULL at this point, but
2112 * since it's more common to have a character there,
2113 * check to see if they match first (m and n) and
2114 * then if they don't match, THEN we can check for
2115 * the NULL of n
2116 */
2117 just = 0;
2118 if (*m == *n)
2119 {
2120 m++;
7448de8d
WS
2121 count++;
2122 n++;
2123 }
2124 else
2125 {
2126
2127 not_matched:
2128
2129 /*
2130 * If there are no more characters in the
2131 * string, but we still need to find another
2132 * character (*m != NULL), then it will be
2133 * impossible to match it
2134 */
2135 if (!*n)
2136 return false;
2b5f62a0 2137
7448de8d
WS
2138 if (ma)
2139 {
2140 m = ma;
2141 n = ++na;
2142 count = acount;
3f4a0c5b 2143 }
7448de8d
WS
2144 else
2145 return false;
2146 }
3f4a0c5b 2147 }
7448de8d 2148 }
2b5f62a0 2149}
fd3f686c 2150
3f4a0c5b 2151#ifdef __VISUALC__
fd3f686c 2152 #pragma warning(default:4706) // assignment within conditional expression
53c6e7cc 2153#endif // VC++