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