]> git.saurik.com Git - wxWidgets.git/blob - src/common/filefn.cpp
oops, forgot to commit yesterday changes related to wxStatusBarBase
[wxWidgets.git] / src / common / filefn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: filefn.cpp
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
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "filefn.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26 #include "wx/defs.h"
27
28 #ifdef __BORLANDC__
29 #pragma hdrstop
30 #endif
31
32 #include "wx/utils.h"
33 #include "wx/intl.h"
34 #include "wx/file.h"
35 #include "wx/filename.h"
36
37 // there are just too many of those...
38 #ifdef __VISUALC__
39 #pragma warning(disable:4706) // assignment within conditional expression
40 #endif // VC++
41
42 #include <ctype.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #if !defined(__WATCOMC__)
47 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
48 #include <errno.h>
49 #endif
50 #endif
51
52 #include <time.h>
53
54 #ifndef __MWERKS__
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #else
58 #include <stat.h>
59 #include <unistd.h>
60 #include <unix.h>
61 #endif
62
63 #ifdef __UNIX__
64 #include <unistd.h>
65 #include <dirent.h>
66 #endif
67
68 #ifdef __WXPM__
69 #include <process.h>
70 #include "wx/os2/private.h"
71 #endif
72 #ifdef __WINDOWS__
73 #if !defined( __GNUWIN32__ ) && !defined( __MWERKS__ ) && !defined(__SALFORDC__)
74 #include <direct.h>
75 #include <dos.h>
76 #include <io.h>
77 #endif // __WINDOWS__
78 #endif // native Win compiler
79
80 #ifdef __GNUWIN32__
81 #include <wchar.h>
82 #ifndef __TWIN32__
83 #include <sys/unistd.h>
84 #endif
85 #endif
86
87 #ifdef __BORLANDC__ // Please someone tell me which version of Borland needs
88 // this (3.1 I believe) and how to test for it.
89 // If this works for Borland 4.0 as well, then no worries.
90 #include <dir.h>
91 #endif
92
93 #ifdef __SALFORDC__
94 #include <dir.h>
95 #include <unix.h>
96 #endif
97
98 #include "wx/setup.h"
99 #include "wx/log.h"
100
101 // No, Cygwin doesn't appear to have fnmatch.h after all.
102 #if defined(HAVE_FNMATCH_H)
103 #include "fnmatch.h"
104 #endif
105
106 #ifdef __WINDOWS__
107 #include <windows.h>
108 #endif
109
110 // ----------------------------------------------------------------------------
111 // constants
112 // ----------------------------------------------------------------------------
113
114 #define _MAXPATHLEN 500
115
116 extern wxChar *wxBuffer;
117
118 #ifdef __WXMAC__
119 # include "MoreFiles.h"
120 # include "MoreFilesExtras.h"
121 # include "FullPath.h"
122 # include "FSpCompat.h"
123 #endif
124
125 IMPLEMENT_DYNAMIC_CLASS(wxPathList, wxStringList)
126
127 // ----------------------------------------------------------------------------
128 // private globals
129 // ----------------------------------------------------------------------------
130
131 static wxChar wxFileFunctionsBuffer[4*_MAXPATHLEN];
132
133 #if defined(__VISAGECPP__) && __IBMCPP__ >= 400
134 //
135 // VisualAge C++ V4.0 cannot have any external linkage const decs
136 // in headers included by more than one primary source
137 //
138 const off_t wxInvalidOffset = (off_t)-1;
139 #endif
140
141 // ----------------------------------------------------------------------------
142 // macros
143 // ----------------------------------------------------------------------------
144
145 // we need to translate Mac filenames before passing them to OS functions
146 #if defined(__WXMAC__) && defined(__DARWIN__)
147 #define OS_FILENAME(s) wxMac2UnixFilename(s.fn_str())
148 #else
149 #define OS_FILENAME(s) (s.fn_str())
150 #endif
151
152 // ============================================================================
153 // implementation
154 // ============================================================================
155
156 void wxPathList::Add (const wxString& path)
157 {
158 wxStringList::Add (WXSTRINGCAST path);
159 }
160
161 // Add paths e.g. from the PATH environment variable
162 void wxPathList::AddEnvList (const wxString& envVariable)
163 {
164 static const wxChar PATH_TOKS[] =
165 #ifdef __WINDOWS__
166 wxT(" ;"); // Don't seperate with colon in DOS (used for drive)
167 #else
168 wxT(" :;");
169 #endif
170
171 wxChar *val = wxGetenv (WXSTRINGCAST envVariable);
172 if (val && *val)
173 {
174 wxChar *s = copystring (val);
175 wxChar *save_ptr, *token = wxStrtok (s, PATH_TOKS, &save_ptr);
176
177 if (token)
178 {
179 Add (copystring (token));
180 while (token)
181 {
182 if ((token = wxStrtok ((wxChar *) NULL, PATH_TOKS, &save_ptr)) != NULL)
183 Add (wxString(token));
184 }
185 }
186
187 // suppress warning about unused variable save_ptr when wxStrtok() is a
188 // macro which throws away its third argument
189 save_ptr = token;
190
191 delete [] s;
192 }
193 }
194
195 // Given a full filename (with path), ensure that that file can
196 // be accessed again USING FILENAME ONLY by adding the path
197 // to the list if not already there.
198 void wxPathList::EnsureFileAccessible (const wxString& path)
199 {
200 wxString path_only(wxPathOnly(path));
201 if ( !path_only.IsEmpty() )
202 {
203 if ( !Member(path_only) )
204 Add(path_only);
205 }
206 }
207
208 bool wxPathList::Member (const wxString& path)
209 {
210 for (wxNode * node = First (); node != NULL; node = node->Next ())
211 {
212 wxString path2((wxChar *) node->Data ());
213 if (
214 #if defined(__WINDOWS__) || defined(__VMS__) || defined (__WXMAC__)
215 // Case INDEPENDENT
216 path.CompareTo (path2, wxString::ignoreCase) == 0
217 #else
218 // Case sensitive File System
219 path.CompareTo (path2) == 0
220 #endif
221 )
222 return TRUE;
223 }
224 return FALSE;
225 }
226
227 wxString wxPathList::FindValidPath (const wxString& file)
228 {
229 if (wxFileExists (wxExpandPath(wxFileFunctionsBuffer, file)))
230 return wxString(wxFileFunctionsBuffer);
231
232 wxChar buf[_MAXPATHLEN];
233 wxStrcpy(buf, wxFileFunctionsBuffer);
234
235 wxChar *filename = (wxChar*) NULL; /* shut up buggy egcs warning */
236 filename = IsAbsolutePath (buf) ? wxFileNameFromPath (buf) : (wxChar *)buf;
237
238 for (wxNode * node = First (); node; node = node->Next ())
239 {
240 wxChar *path = (wxChar *) node->Data ();
241 wxStrcpy (wxFileFunctionsBuffer, path);
242 wxChar ch = wxFileFunctionsBuffer[wxStrlen(wxFileFunctionsBuffer)-1];
243 if (ch != wxT('\\') && ch != wxT('/'))
244 wxStrcat (wxFileFunctionsBuffer, wxT("/"));
245 wxStrcat (wxFileFunctionsBuffer, filename);
246 #ifdef __WINDOWS__
247 Unix2DosFilename (wxFileFunctionsBuffer);
248 #endif
249 if (wxFileExists (wxFileFunctionsBuffer))
250 {
251 return wxString(wxFileFunctionsBuffer); // Found!
252 }
253 } // for()
254
255 return wxString(wxT("")); // Not found
256 }
257
258 wxString wxPathList::FindAbsoluteValidPath (const wxString& file)
259 {
260 wxString f = FindValidPath(file);
261 if ( wxIsAbsolutePath(f) )
262 return f;
263
264 wxString buf;
265 wxGetWorkingDirectory(buf.GetWriteBuf(_MAXPATHLEN), _MAXPATHLEN - 1);
266 buf.UngetWriteBuf();
267 if ( !wxEndsWithPathSeparator(buf) )
268 {
269 buf += wxFILE_SEP_PATH;
270 }
271 buf += f;
272
273 return buf;
274 }
275
276 bool
277 wxFileExists (const wxString& filename)
278 {
279 #ifdef __WINDOWS__
280 // GetFileAttributes can copy with network paths
281 DWORD ret = GetFileAttributes(filename);
282 DWORD isDir = (ret & FILE_ATTRIBUTE_DIRECTORY);
283 return ((ret != 0xffffffff) && (isDir == 0));
284 #else
285 wxStructStat stbuf;
286 if ( !filename.empty() && wxStat (OS_FILENAME(filename), &stbuf) == 0 )
287 return TRUE;
288
289 return FALSE;
290 #endif
291 }
292
293 bool
294 wxIsAbsolutePath (const wxString& filename)
295 {
296 #ifdef __WXMAC__
297 if (filename != wxT(""))
298 {
299 // This seems wrong to me, but there is no fix. since
300 // "MacOS:MyText.txt" is absolute whereas "MyDir:MyText.txt"
301 // is not. Or maybe ":MyDir:MyText.txt" has to be used? RR.
302
303 if (filename.Find(':') != wxNOT_FOUND && filename[0] != ':')
304 return TRUE ;
305 }
306 return FALSE ;
307 #else
308 if (filename != wxT(""))
309 {
310 if (filename[0] == wxT('/')
311 #ifdef __VMS__
312 || (filename[0] == wxT('[') && filename[1] != wxT('.'))
313 #endif
314 #ifdef __WINDOWS__
315 /* MSDOS */
316 || filename[0] == wxT('\\') || (wxIsalpha (filename[0]) && filename[1] == wxT(':'))
317 #endif
318 )
319 return TRUE;
320 }
321 return FALSE;
322 #endif
323 }
324
325 /*
326 * Strip off any extension (dot something) from end of file,
327 * IF one exists. Inserts zero into buffer.
328 *
329 */
330
331 void wxStripExtension(wxChar *buffer)
332 {
333 int len = wxStrlen(buffer);
334 int i = len-1;
335 while (i > 0)
336 {
337 if (buffer[i] == wxT('.'))
338 {
339 buffer[i] = 0;
340 break;
341 }
342 i --;
343 }
344 }
345
346 void wxStripExtension(wxString& buffer)
347 {
348 size_t len = buffer.Length();
349 size_t i = len-1;
350 while (i > 0)
351 {
352 if (buffer.GetChar(i) == wxT('.'))
353 {
354 buffer = buffer.Left(i);
355 break;
356 }
357 i --;
358 }
359 }
360
361 // Destructive removal of /./ and /../ stuff
362 wxChar *wxRealPath (wxChar *path)
363 {
364 #ifdef __WXMSW__
365 static const wxChar SEP = wxT('\\');
366 Unix2DosFilename(path);
367 #else
368 static const wxChar SEP = wxT('/');
369 #endif
370 if (path[0] && path[1]) {
371 /* MATTHEW: special case "/./x" */
372 wxChar *p;
373 if (path[2] == SEP && path[1] == wxT('.'))
374 p = &path[0];
375 else
376 p = &path[2];
377 for (; *p; p++)
378 {
379 if (*p == SEP)
380 {
381 if (p[1] == wxT('.') && p[2] == wxT('.') && (p[3] == SEP || p[3] == wxT('\0')))
382 {
383 wxChar *q;
384 for (q = p - 1; q >= path && *q != SEP; q--);
385 if (q[0] == SEP && (q[1] != wxT('.') || q[2] != wxT('.') || q[3] != SEP)
386 && (q - 1 <= path || q[-1] != SEP))
387 {
388 wxStrcpy (q, p + 3);
389 if (path[0] == wxT('\0'))
390 {
391 path[0] = SEP;
392 path[1] = wxT('\0');
393 }
394 #ifdef __WXMSW__
395 /* Check that path[2] is NULL! */
396 else if (path[1] == wxT(':') && !path[2])
397 {
398 path[2] = SEP;
399 path[3] = wxT('\0');
400 }
401 #endif
402 p = q - 1;
403 }
404 }
405 else if (p[1] == wxT('.') && (p[2] == SEP || p[2] == wxT('\0')))
406 wxStrcpy (p, p + 2);
407 }
408 }
409 }
410 return path;
411 }
412
413 // Must be destroyed
414 wxChar *wxCopyAbsolutePath(const wxString& filename)
415 {
416 if (filename == wxT(""))
417 return (wxChar *) NULL;
418
419 if (! IsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer, filename))) {
420 wxChar buf[_MAXPATHLEN];
421 buf[0] = wxT('\0');
422 wxGetWorkingDirectory(buf, WXSIZEOF(buf));
423 wxChar ch = buf[wxStrlen(buf) - 1];
424 #ifdef __WXMSW__
425 if (ch != wxT('\\') && ch != wxT('/'))
426 wxStrcat(buf, wxT("\\"));
427 #else
428 if (ch != wxT('/'))
429 wxStrcat(buf, wxT("/"));
430 #endif
431 wxStrcat(buf, wxFileFunctionsBuffer);
432 return copystring( wxRealPath(buf) );
433 }
434 return copystring( wxFileFunctionsBuffer );
435 }
436
437 /*-
438 Handles:
439 ~/ => home dir
440 ~user/ => user's home dir
441 If the environment variable a = "foo" and b = "bar" then:
442 Unix:
443 $a => foo
444 $a$b => foobar
445 $a.c => foo.c
446 xxx$a => xxxfoo
447 ${a}! => foo!
448 $(b)! => bar!
449 \$a => \$a
450 MSDOS:
451 $a ==> $a
452 $(a) ==> foo
453 $(a)$b ==> foo$b
454 $(a)$(b)==> foobar
455 test.$$ ==> test.$$
456 */
457
458 /* input name in name, pathname output to buf. */
459
460 wxChar *wxExpandPath(wxChar *buf, const wxChar *name)
461 {
462 register wxChar *d, *s, *nm;
463 wxChar lnm[_MAXPATHLEN];
464 int q;
465
466 // Some compilers don't like this line.
467 // const wxChar trimchars[] = wxT("\n \t");
468
469 wxChar trimchars[4];
470 trimchars[0] = wxT('\n');
471 trimchars[1] = wxT(' ');
472 trimchars[2] = wxT('\t');
473 trimchars[3] = 0;
474
475 #ifdef __WXMSW__
476 const wxChar SEP = wxT('\\');
477 #else
478 const wxChar SEP = wxT('/');
479 #endif
480 buf[0] = wxT('\0');
481 if (name == NULL || *name == wxT('\0'))
482 return buf;
483 nm = copystring(name); // Make a scratch copy
484 wxChar *nm_tmp = nm;
485
486 /* Skip leading whitespace and cr */
487 while (wxStrchr((wxChar *)trimchars, *nm) != NULL)
488 nm++;
489 /* And strip off trailing whitespace and cr */
490 s = nm + (q = wxStrlen(nm)) - 1;
491 while (q-- && wxStrchr((wxChar *)trimchars, *s) != NULL)
492 *s = wxT('\0');
493
494 s = nm;
495 d = lnm;
496 #ifdef __WXMSW__
497 q = FALSE;
498 #else
499 q = nm[0] == wxT('\\') && nm[1] == wxT('~');
500 #endif
501
502 /* Expand inline environment variables */
503 #ifdef __VISAGECPP__
504 while (*d)
505 {
506 *d++ = *s;
507 if(*s == wxT('\\'))
508 {
509 *(d - 1) = *++s;
510 if (*d)
511 {
512 s++;
513 continue;
514 }
515 else
516 break;
517 }
518 else
519 #else
520 while ((*d++ = *s) != 0) {
521 # ifndef __WXMSW__
522 if (*s == wxT('\\')) {
523 if ((*(d - 1) = *++s)) {
524 s++;
525 continue;
526 } else
527 break;
528 } else
529 # endif
530 #endif
531 #ifdef __WXMSW__
532 if (*s++ == wxT('$') && (*s == wxT('{') || *s == wxT(')')))
533 #else
534 if (*s++ == wxT('$'))
535 #endif
536 {
537 register wxChar *start = d;
538 register int braces = (*s == wxT('{') || *s == wxT('('));
539 register wxChar *value;
540 while ((*d++ = *s) != 0)
541 if (braces ? (*s == wxT('}') || *s == wxT(')')) : !(wxIsalnum(*s) || *s == wxT('_')) )
542 break;
543 else
544 s++;
545 *--d = 0;
546 value = wxGetenv(braces ? start + 1 : start);
547 if (value) {
548 for ((d = start - 1); (*d++ = *value++) != 0;);
549 d--;
550 if (braces && *s)
551 s++;
552 }
553 }
554 }
555
556 /* Expand ~ and ~user */
557 nm = lnm;
558 s = wxT("");
559 if (nm[0] == wxT('~') && !q)
560 {
561 /* prefix ~ */
562 if (nm[1] == SEP || nm[1] == 0)
563 { /* ~/filename */
564 // FIXME: wxGetUserHome could return temporary storage in Unicode mode
565 if ((s = WXSTRINGCAST wxGetUserHome(wxT(""))) != NULL) {
566 if (*++nm)
567 nm++;
568 }
569 } else
570 { /* ~user/filename */
571 register wxChar *nnm;
572 register wxChar *home;
573 for (s = nm; *s && *s != SEP; s++);
574 int was_sep; /* MATTHEW: Was there a separator, or NULL? */
575 was_sep = (*s == SEP);
576 nnm = *s ? s + 1 : s;
577 *s = 0;
578 // FIXME: wxGetUserHome could return temporary storage in Unicode mode
579 if ((home = WXSTRINGCAST wxGetUserHome(wxString(nm + 1))) == NULL) {
580 if (was_sep) /* replace only if it was there: */
581 *s = SEP;
582 s = wxT("");
583 } else {
584 nm = nnm;
585 s = home;
586 }
587 }
588 }
589
590 d = buf;
591 if (s && *s) { /* MATTHEW: s could be NULL if user '~' didn't exist */
592 /* Copy home dir */
593 while (wxT('\0') != (*d++ = *s++))
594 /* loop */;
595 // Handle root home
596 if (d - 1 > buf && *(d - 2) != SEP)
597 *(d - 1) = SEP;
598 }
599 s = nm;
600 while ((*d++ = *s++) != 0);
601 delete[] nm_tmp; // clean up alloc
602 /* Now clean up the buffer */
603 return wxRealPath(buf);
604 }
605
606 /* Contract Paths to be build upon an environment variable
607 component:
608
609 example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib
610
611 The call wxExpandPath can convert these back!
612 */
613 wxChar *
614 wxContractPath (const wxString& filename, const wxString& envname, const wxString& user)
615 {
616 static wxChar dest[_MAXPATHLEN];
617
618 if (filename == wxT(""))
619 return (wxChar *) NULL;
620
621 wxStrcpy (dest, WXSTRINGCAST filename);
622 #ifdef __WXMSW__
623 Unix2DosFilename(dest);
624 #endif
625
626 // Handle environment
627 const wxChar *val = (const wxChar *) NULL;
628 wxChar *tcp = (wxChar *) NULL;
629 if (envname != WXSTRINGCAST NULL && (val = wxGetenv (WXSTRINGCAST envname)) != NULL &&
630 (tcp = wxStrstr (dest, val)) != NULL)
631 {
632 wxStrcpy (wxFileFunctionsBuffer, tcp + wxStrlen (val));
633 *tcp++ = wxT('$');
634 *tcp++ = wxT('{');
635 wxStrcpy (tcp, WXSTRINGCAST envname);
636 wxStrcat (tcp, wxT("}"));
637 wxStrcat (tcp, wxFileFunctionsBuffer);
638 }
639
640 // Handle User's home (ignore root homes!)
641 size_t len = 0;
642 if ((val = wxGetUserHome (user)) != NULL &&
643 (len = wxStrlen(val)) > 2 &&
644 wxStrncmp(dest, val, len) == 0)
645 {
646 wxStrcpy(wxFileFunctionsBuffer, wxT("~"));
647 if (user != wxT(""))
648 wxStrcat(wxFileFunctionsBuffer, (const wxChar*) user);
649 #ifdef __WXMSW__
650 // strcat(wxFileFunctionsBuffer, "\\");
651 #else
652 // strcat(wxFileFunctionsBuffer, "/");
653 #endif
654 wxStrcat(wxFileFunctionsBuffer, dest + len);
655 wxStrcpy (dest, wxFileFunctionsBuffer);
656 }
657
658 return dest;
659 }
660
661 // Return just the filename, not the path
662 // (basename)
663 wxChar *wxFileNameFromPath (wxChar *path)
664 {
665 if (path)
666 {
667 register wxChar *tcp;
668
669 tcp = path + wxStrlen (path);
670 while (--tcp >= path)
671 {
672 #ifdef __WXMAC__
673 if (*tcp == wxT(':') )
674 #else
675 if (*tcp == wxT('/') || *tcp == wxT('\\')
676 #ifdef __VMS__
677 || *tcp == wxT(':') || *tcp == wxT(']'))
678 #else
679 )
680 #endif
681 #endif
682 return tcp + 1;
683 } /* while */
684 #if defined(__WXMSW__) || defined(__WXPM__)
685 if (wxIsalpha (*path) && *(path + 1) == wxT(':'))
686 return path + 2;
687 #endif
688 }
689 return path;
690 }
691
692 wxString wxFileNameFromPath (const wxString& path1)
693 {
694 if (path1 != wxT(""))
695 {
696
697 wxChar *path = WXSTRINGCAST path1 ;
698 register wxChar *tcp;
699
700 tcp = path + wxStrlen (path);
701 while (--tcp >= path)
702 {
703 #ifdef __WXMAC__
704 if (*tcp == wxT(':') )
705 #else
706 if (*tcp == wxT('/') || *tcp == wxT('\\')
707 #ifdef __VMS__
708 || *tcp == wxT(':') || *tcp == wxT(']'))
709 #else
710 )
711 #endif
712 #endif
713 return wxString(tcp + 1);
714 } /* while */
715 #if defined(__WXMSW__) || defined(__WXPM__)
716 if (wxIsalpha (*path) && *(path + 1) == wxT(':'))
717 return wxString(path + 2);
718 #endif
719 }
720 // Yes, this should return the path, not an empty string, otherwise
721 // we get "thing.txt" -> "".
722 return path1;
723 }
724
725 // Return just the directory, or NULL if no directory
726 wxChar *
727 wxPathOnly (wxChar *path)
728 {
729 if (path && *path)
730 {
731 static wxChar buf[_MAXPATHLEN];
732
733 // Local copy
734 wxStrcpy (buf, path);
735
736 int l = wxStrlen(path);
737 bool done = FALSE;
738
739 int i = l - 1;
740
741 // Search backward for a backward or forward slash
742 while (!done && i > -1)
743 {
744 // ] is for VMS
745 #ifdef __WXMAC__
746 if (path[i] == wxT(':') )
747 #else
748 if (path[i] == wxT('/') || path[i] == wxT('\\') || path[i] == wxT(']'))
749 #endif
750 {
751 done = TRUE;
752 #ifdef __VMS__
753 if ( path[i] == wxT(']') )
754 buf[i+1] = 0;
755 else
756 #endif
757 buf[i] = 0;
758
759 return buf;
760 }
761 else i --;
762 }
763
764 #if defined(__WXMSW__) || defined(__WXPM__)
765 // Try Drive specifier
766 if (wxIsalpha (buf[0]) && buf[1] == wxT(':'))
767 {
768 // A:junk --> A:. (since A:.\junk Not A:\junk)
769 buf[2] = wxT('.');
770 buf[3] = wxT('\0');
771 return buf;
772 }
773 #endif
774 }
775
776 return (wxChar *) NULL;
777 }
778
779 // Return just the directory, or NULL if no directory
780 wxString wxPathOnly (const wxString& path)
781 {
782 if (path != wxT(""))
783 {
784 wxChar buf[_MAXPATHLEN];
785
786 // Local copy
787 wxStrcpy (buf, WXSTRINGCAST path);
788
789 int l = path.Length();
790 bool done = FALSE;
791
792 int i = l - 1;
793
794 // Search backward for a backward or forward slash
795 while (!done && i > -1)
796 {
797 // ] is for VMS
798 #ifdef __WXMAC__
799 if (path[i] == wxT(':') )
800 #else
801 if (path[i] == wxT('/') || path[i] == wxT('\\') || path[i] == wxT(']'))
802 #endif
803 {
804 done = TRUE;
805 #ifdef __VMS__
806 if ( path[i] == wxT(']') )
807 buf[i+1] = 0;
808 else
809 #endif
810 buf[i] = 0;
811
812 return wxString(buf);
813 }
814 else i --;
815 }
816
817 #if defined(__WXMSW__) || defined(__WXPM__)
818 // Try Drive specifier
819 if (wxIsalpha (buf[0]) && buf[1] == wxT(':'))
820 {
821 // A:junk --> A:. (since A:.\junk Not A:\junk)
822 buf[2] = wxT('.');
823 buf[3] = wxT('\0');
824 return wxString(buf);
825 }
826 #endif
827 }
828
829 return wxString(wxT(""));
830 }
831
832 // Utility for converting delimiters in DOS filenames to UNIX style
833 // and back again - or we get nasty problems with delimiters.
834 // Also, convert to lower case, since case is significant in UNIX.
835
836 #if defined(__WXMAC__)
837 wxString wxMacFSSpec2MacFilename( const FSSpec *spec )
838 {
839 Handle myPath ;
840 short length ;
841
842 FSpGetFullPath( spec , &length , &myPath ) ;
843 ::SetHandleSize( myPath , length + 1 ) ;
844 ::HLock( myPath ) ;
845 (*myPath)[length] = 0 ;
846 if ( length > 0 && (*myPath)[length-1] ==':' )
847 (*myPath)[length-1] = 0 ;
848
849 wxString result( (char*) *myPath ) ;
850 ::HUnlock( myPath ) ;
851 ::DisposeHandle( myPath ) ;
852 return result ;
853 }
854
855 void wxMacFilename2FSSpec( const char *path , FSSpec *spec )
856 {
857 FSpLocationFromFullPath( strlen(path ) , path , spec ) ;
858 }
859
860 static char sMacFileNameConversion[ 1000 ] ;
861
862 wxString wxMac2UnixFilename (const char *str)
863 {
864 char *s = sMacFileNameConversion ;
865 strcpy( s , str ) ;
866 if (s)
867 {
868 memmove( s+1 , s ,strlen( s ) + 1) ;
869 if ( *s == ':' )
870 *s = '.' ;
871 else
872 *s = '/' ;
873
874 while (*s)
875 {
876 if (*s == ':')
877 *s = '/';
878 else
879 *s = wxTolower (*s); // Case INDEPENDENT
880 s++;
881 }
882 }
883 return wxString (sMacFileNameConversion) ;
884 }
885
886 wxString wxUnix2MacFilename (const char *str)
887 {
888 char *s = sMacFileNameConversion ;
889 strcpy( s , str ) ;
890 if (s)
891 {
892 if ( *s == '.' )
893 {
894 // relative path , since it goes on with slash which is translated to a :
895 memmove( s , s+1 ,strlen( s ) ) ;
896 }
897 else if ( *s == '/' )
898 {
899 // absolute path -> on mac just start with the drive name
900 memmove( s , s+1 ,strlen( s ) ) ;
901 }
902 else
903 {
904 wxASSERT_MSG( 1 , "unkown path beginning" ) ;
905 }
906 while (*s)
907 {
908 if (*s == '/' || *s == '\\')
909 {
910 // convert any back-directory situations
911 if ( *(s+1) == '.' && *(s+2) == '.' && ( (*(s+3) == '/' || *(s+3) == '\\') ) )
912 {
913 *s = ':';
914 memmove( s+1 , s+3 ,strlen( s+3 ) + 1 ) ;
915 }
916 else
917 *s = ':';
918 }
919
920 s++ ;
921 }
922 }
923 return wxString (sMacFileNameConversion) ;
924 }
925
926 wxString wxMacFSSpec2UnixFilename( const FSSpec *spec )
927 {
928 return wxMac2UnixFilename( wxMacFSSpec2MacFilename( spec) ) ;
929 }
930
931 void wxUnixFilename2FSSpec( const char *path , FSSpec *spec )
932 {
933 wxString var = wxUnix2MacFilename( path ) ;
934 wxMacFilename2FSSpec( var , spec ) ;
935 }
936
937 #endif
938 void
939 wxDos2UnixFilename (char *s)
940 {
941 if (s)
942 while (*s)
943 {
944 if (*s == '\\')
945 *s = '/';
946 #ifdef __WXMSW__
947 else
948 *s = wxTolower (*s); // Case INDEPENDENT
949 #endif
950 s++;
951 }
952 }
953
954 void
955 #if defined(__WXMSW__) || defined(__WXPM__)
956 wxUnix2DosFilename (wxChar *s)
957 #else
958 wxUnix2DosFilename (wxChar *WXUNUSED(s) )
959 #endif
960 {
961 // Yes, I really mean this to happen under DOS only! JACS
962 #if defined(__WXMSW__) || defined(__WXPM__)
963 if (s)
964 while (*s)
965 {
966 if (*s == wxT('/'))
967 *s = wxT('\\');
968 s++;
969 }
970 #endif
971 }
972
973 // Concatenate two files to form third
974 bool
975 wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& file3)
976 {
977 wxString outfile;
978 if ( !wxGetTempFileName("cat", outfile) )
979 return FALSE;
980
981 FILE *fp1 = (FILE *) NULL;
982 FILE *fp2 = (FILE *) NULL;
983 FILE *fp3 = (FILE *) NULL;
984 // Open the inputs and outputs
985 if ((fp1 = wxFopen (OS_FILENAME( file1 ), wxT("rb"))) == NULL ||
986 (fp2 = wxFopen (OS_FILENAME( file2 ), wxT("rb"))) == NULL ||
987 (fp3 = wxFopen (OS_FILENAME( outfile ), wxT("wb"))) == NULL)
988 {
989 if (fp1)
990 fclose (fp1);
991 if (fp2)
992 fclose (fp2);
993 if (fp3)
994 fclose (fp3);
995 return FALSE;
996 }
997
998 int ch;
999 while ((ch = getc (fp1)) != EOF)
1000 (void) putc (ch, fp3);
1001 fclose (fp1);
1002
1003 while ((ch = getc (fp2)) != EOF)
1004 (void) putc (ch, fp3);
1005 fclose (fp2);
1006
1007 fclose (fp3);
1008 bool result = wxRenameFile(outfile, file3);
1009 return result;
1010 }
1011
1012 // Copy files
1013 bool
1014 wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite)
1015 {
1016 #if defined(__WIN32__) && !defined(__WXMICROWIN__)
1017 // CopyFile() copies file attributes and modification time too, so use it
1018 // instead of our code if available
1019 //
1020 // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite
1021 return ::CopyFile(file1, file2, !overwrite) != 0;
1022 #else // !Win32
1023 wxStructStat fbuf;
1024
1025 // get permissions of file1
1026 if ( wxStat(OS_FILENAME(file1), &fbuf) != 0 )
1027 {
1028 // the file probably doesn't exist or we haven't the rights to read
1029 // from it anyhow
1030 wxLogSysError(_("Impossible to get permissions for file '%s'"),
1031 file1.c_str());
1032 return FALSE;
1033 }
1034
1035 // open file1 for reading
1036 wxFile fileIn(file1, wxFile::read);
1037 if ( !fileIn.IsOpened() )
1038 return FALSE;
1039
1040 // remove file2, if it exists. This is needed for creating
1041 // file2 with the correct permissions in the next step
1042 if ( wxFileExists(file2) && (!overwrite || !wxRemoveFile(file2)))
1043 {
1044 wxLogSysError(_("Impossible to overwrite the file '%s'"),
1045 file2.c_str());
1046 return FALSE;
1047 }
1048
1049 #ifdef __UNIX__
1050 // reset the umask as we want to create the file with exactly the same
1051 // permissions as the original one
1052 mode_t oldUmask = umask( 0 );
1053 #endif // __UNIX__
1054
1055 // create file2 with the same permissions than file1 and open it for
1056 // writing
1057 wxFile fileOut;
1058 if ( !fileOut.Create(file2, overwrite, fbuf.st_mode & 0777) )
1059 return FALSE;
1060
1061 #ifdef __UNIX__
1062 /// restore the old umask
1063 umask(oldUmask);
1064 #endif // __UNIX__
1065
1066 // copy contents of file1 to file2
1067 char buf[4096];
1068 size_t count;
1069 for ( ;; )
1070 {
1071 count = fileIn.Read(buf, WXSIZEOF(buf));
1072 if ( fileIn.Error() )
1073 return FALSE;
1074
1075 // end of file?
1076 if ( !count )
1077 break;
1078
1079 if ( fileOut.Write(buf, count) < count )
1080 return FALSE;
1081 }
1082
1083 // we can expect fileIn to be closed successfully, but we should ensure
1084 // that fileOut was closed as some write errors (disk full) might not be
1085 // detected before doing this
1086 if ( !fileIn.Close() || !fileOut.Close() )
1087 return FALSE;
1088
1089 #if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__)
1090 // no chmod in VA. Should be some permission API for HPFS386 partitions
1091 // however
1092 if ( chmod(OS_FILENAME(file2), fbuf.st_mode) != 0 )
1093 {
1094 wxLogSysError(_("Impossible to set permissions for the file '%s'"),
1095 file2.c_str());
1096 return FALSE;
1097 }
1098 #endif // OS/2 || Mac
1099
1100 return TRUE;
1101 #endif // __WXMSW__ && __WIN32__
1102 }
1103
1104 bool
1105 wxRenameFile (const wxString& file1, const wxString& file2)
1106 {
1107 // Normal system call
1108 if ( wxRename (file1, file2) == 0 )
1109 return TRUE;
1110
1111 // Try to copy
1112 if (wxCopyFile(file1, file2)) {
1113 wxRemoveFile(file1);
1114 return TRUE;
1115 }
1116 // Give up
1117 return FALSE;
1118 }
1119
1120 bool wxRemoveFile(const wxString& file)
1121 {
1122 #if defined(__VISUALC__) \
1123 || defined(__BORLANDC__) \
1124 || defined(__WATCOMC__) \
1125 || defined(__GNUWIN32__)
1126 int res = wxRemove(file);
1127 #else
1128 int res = unlink(OS_FILENAME(file));
1129 #endif
1130
1131 return res == 0;
1132 }
1133
1134 bool wxMkdir(const wxString& dir, int perm)
1135 {
1136 #if defined(__WXMAC__) && !defined(__UNIX__)
1137 return (mkdir( dir , 0 ) == 0);
1138 #else // !Mac
1139 const wxChar *dirname = dir.c_str();
1140
1141 // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too
1142 // for the GNU compiler
1143 #if (!(defined(__WXMSW__) || defined(__WXPM__))) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) || defined(__WXWINE__) || defined(__WXMICROWIN__)
1144 if ( mkdir(wxFNCONV(dirname), perm) != 0 )
1145 #elif defined(__WXPM__)
1146 if (::DosCreateDir((PSZ)dirname, NULL) != 0) // enhance for EAB's??
1147 #else // !MSW and !OS/2 VAC++
1148 (void)perm;
1149 if ( wxMkDir(wxFNSTRINGCAST wxFNCONV(dirname)) != 0 )
1150 #endif // !MSW/MSW
1151 {
1152 wxLogSysError(_("Directory '%s' couldn't be created"), dirname);
1153
1154 return FALSE;
1155 }
1156
1157 return TRUE;
1158 #endif // Mac/!Mac
1159 }
1160
1161 bool wxRmdir(const wxString& dir, int WXUNUSED(flags))
1162 {
1163 #ifdef __VMS__
1164 return FALSE; //to be changed since rmdir exists in VMS7.x
1165 #elif defined(__WXPM__)
1166 return (::DosDeleteDir((PSZ)dir.c_str()) == 0);
1167 #else
1168
1169 #ifdef __SALFORDC__
1170 return FALSE; // What to do?
1171 #else
1172 return (wxRmDir(OS_FILENAME(dir)) == 0);
1173 #endif
1174
1175 #endif
1176 }
1177
1178 // does the path exists? (may have or not '/' or '\\' at the end)
1179 bool wxPathExists(const wxChar *pszPathName)
1180 {
1181 wxString strPath(pszPathName);
1182 #ifdef __WINDOWS__
1183 // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists,
1184 // so remove all trailing backslashes from the path - but don't do this for
1185 // the pathes "d:\" (which are different from "d:") nor for just "\"
1186 while ( wxEndsWithPathSeparator(strPath) )
1187 {
1188 size_t len = strPath.length();
1189 if ( len == 1 || (len == 3 && strPath[len - 2] == _T(':')) )
1190 break;
1191
1192 strPath.Truncate(len - 1);
1193 }
1194 #endif // __WINDOWS__
1195
1196 #ifdef __WINDOWS__
1197 // Stat can't cope with network paths
1198 DWORD ret = GetFileAttributes(strPath.c_str());
1199 DWORD isDir = (ret & FILE_ATTRIBUTE_DIRECTORY);
1200 return ((ret != 0xffffffff) && (isDir != 0));
1201 #else
1202
1203 wxStructStat st;
1204 #ifndef __VISAGECPP__
1205 return wxStat(wxFNSTRINGCAST strPath.fn_str(), &st) == 0 &&
1206 ((st.st_mode & S_IFMT) == S_IFDIR);
1207 #else
1208 // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only
1209 return wxStat(wxFNSTRINGCAST strPath.fn_str(), &st) == 0 &&
1210 (st.st_mode == S_IFDIR);
1211 #endif
1212
1213 #endif
1214 }
1215
1216 // Get a temporary filename, opening and closing the file.
1217 wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf)
1218 {
1219 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
1220
1221 #ifndef __WIN32__
1222 wxChar tmp[144];
1223 ::GetTempFileName(0, WXSTRINGCAST prefix, 0, tmp);
1224 #else
1225 wxChar tmp[MAX_PATH];
1226 wxChar tmpPath[MAX_PATH];
1227 ::GetTempPath(MAX_PATH, tmpPath);
1228 ::GetTempFileName(tmpPath, WXSTRINGCAST prefix, 0, tmp);
1229 #endif
1230 if (buf) wxStrcpy(buf, tmp);
1231 else buf = copystring(tmp);
1232 return buf;
1233
1234 #else
1235 static short last_temp = 0; // cache last to speed things a bit
1236 // At most 1000 temp files to a process! We use a ring count.
1237 wxChar tmp[100]; // FIXME static buffer
1238
1239 for (short suffix = last_temp + 1; suffix != last_temp; ++suffix %= 1000)
1240 {
1241 wxSprintf (tmp, wxT("/tmp/%s%d.%03x"), WXSTRINGCAST prefix, (int) getpid (), (int) suffix);
1242 if (!wxFileExists( tmp ))
1243 {
1244 // Touch the file to create it (reserve name)
1245 FILE *fd = fopen (wxFNCONV(tmp), "w");
1246 if (fd)
1247 fclose (fd);
1248 last_temp = suffix;
1249 if (buf)
1250 wxStrcpy( buf, tmp);
1251 else
1252 buf = copystring( tmp );
1253 return buf;
1254 }
1255 }
1256 wxLogError( _("wxWindows: error finding temporary file name.\n") );
1257 if (buf) buf[0] = 0;
1258 return (wxChar *) NULL;
1259 #endif
1260 }
1261
1262 bool wxGetTempFileName(const wxString& prefix, wxString& buf)
1263 {
1264 wxChar buf2[512];
1265 if (wxGetTempFileName(prefix, buf2) != (wxChar*) NULL)
1266 {
1267 buf = buf2;
1268 return TRUE;
1269 }
1270 else
1271 return FALSE;
1272 }
1273
1274 // Get first file name matching given wild card.
1275
1276 #ifdef __UNIX__
1277
1278 // Get first file name matching given wild card.
1279 // Flags are reserved for future use.
1280
1281 #if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 )
1282 static DIR *gs_dirStream = (DIR *) NULL;
1283 static wxString gs_strFileSpec;
1284 static int gs_findFlags = 0;
1285 #endif
1286
1287 wxString wxFindFirstFile(const wxChar *spec, int flags)
1288 {
1289 wxString result;
1290 #ifdef __VMS
1291 wxChar *specvms = NULL;
1292 #endif
1293
1294 #if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 )
1295 if (gs_dirStream)
1296 closedir(gs_dirStream); // edz 941103: better housekeping
1297
1298 gs_findFlags = flags;
1299
1300 gs_strFileSpec = spec;
1301
1302 // Find path only so we can concatenate
1303 // found file onto path
1304 wxString path(wxPathOnly(gs_strFileSpec));
1305
1306 // special case: path is really "/"
1307 if ( !path && gs_strFileSpec[0u] == wxT('/') )
1308 #ifdef __VMS
1309 {
1310 wxStrcpy( specvms , wxT( "[000000]" ) );
1311 gs_strFileSpec = specvms;
1312 wxString path_vms(wxPathOnly(gs_strFileSpec));
1313 path = path_vms;
1314 }
1315 #else
1316 path = wxT('/');
1317 #endif
1318 // path is empty => Local directory
1319 if ( !path )
1320 #ifdef __VMS
1321 {
1322 wxStrcpy( specvms , wxT( "[]" ) );
1323 gs_strFileSpec = specvms;
1324 wxString path_vms1(wxPathOnly(gs_strFileSpec));
1325 path = path_vms1;
1326 }
1327 #else
1328 path = wxT('.');
1329 #endif
1330
1331 gs_dirStream = opendir(path.fn_str());
1332 if ( !gs_dirStream )
1333 {
1334 wxLogSysError(_("Can not enumerate files in directory '%s'"),
1335 path.c_str());
1336 }
1337 else
1338 {
1339 result = wxFindNextFile();
1340 }
1341 #endif // !VMS6.x or earlier
1342
1343 return result;
1344 }
1345
1346 wxString wxFindNextFile()
1347 {
1348 wxString result;
1349
1350 #if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 )
1351 wxCHECK_MSG( gs_dirStream, result, wxT("must call wxFindFirstFile first") );
1352
1353 // Find path only so we can concatenate
1354 // found file onto path
1355 wxString path(wxPathOnly(gs_strFileSpec));
1356 wxString name(wxFileNameFromPath(gs_strFileSpec));
1357
1358 /* MATTHEW: special case: path is really "/" */
1359 if ( !path && gs_strFileSpec[0u] == wxT('/'))
1360 path = wxT('/');
1361
1362 // Do the reading
1363 struct dirent *nextDir;
1364 for ( nextDir = readdir(gs_dirStream);
1365 nextDir != NULL;
1366 nextDir = readdir(gs_dirStream) )
1367 {
1368 if (wxMatchWild(name, nextDir->d_name, FALSE) && // RR: added FALSE to find hidden files
1369 strcmp(nextDir->d_name, ".") &&
1370 strcmp(nextDir->d_name, "..") )
1371 {
1372 result.Empty();
1373 if ( !path.IsEmpty() )
1374 {
1375 result = path;
1376 if ( path != wxT('/') )
1377 result += wxT('/');
1378 }
1379
1380 result += nextDir->d_name;
1381
1382 // Only return "." and ".." when they match
1383 bool isdir;
1384 if ( (strcmp(nextDir->d_name, ".") == 0) ||
1385 (strcmp(nextDir->d_name, "..") == 0))
1386 {
1387 if ( (gs_findFlags & wxDIR) != 0 )
1388 isdir = TRUE;
1389 else
1390 continue;
1391 }
1392 else
1393 isdir = wxDirExists(result);
1394
1395 // and only return directories when flags & wxDIR
1396 if ( !gs_findFlags ||
1397 ((gs_findFlags & wxDIR) && isdir) ||
1398 ((gs_findFlags & wxFILE) && !isdir) )
1399 {
1400 return result;
1401 }
1402 }
1403 }
1404
1405 result.Empty(); // not found
1406
1407 closedir(gs_dirStream);
1408 gs_dirStream = (DIR *) NULL;
1409 #endif // !VMS6.2 or earlier
1410
1411 return result;
1412 }
1413
1414 #elif defined(__WXMAC__)
1415
1416 struct MacDirectoryIterator
1417 {
1418 CInfoPBRec m_CPB ;
1419 wxInt16 m_index ;
1420 long m_dirId ;
1421 Str255 m_name ;
1422 } ;
1423
1424 static int g_iter_flags ;
1425
1426 static MacDirectoryIterator g_iter ;
1427
1428 wxString wxFindFirstFile(const wxChar *spec, int flags)
1429 {
1430 wxString result;
1431
1432 g_iter_flags = flags; /* MATTHEW: [5] Remember flags */
1433
1434 // Find path only so we can concatenate found file onto path
1435 wxString path(wxPathOnly(spec));
1436 if ( !path.IsEmpty() )
1437 result << path << wxT('\\');
1438
1439 FSSpec fsspec ;
1440
1441 wxMacFilename2FSSpec( result , &fsspec ) ;
1442 g_iter.m_CPB.hFileInfo.ioVRefNum = fsspec.vRefNum ;
1443 g_iter.m_CPB.hFileInfo.ioNamePtr = g_iter.m_name ;
1444 g_iter.m_index = 0 ;
1445
1446 Boolean isDir ;
1447 FSpGetDirectoryID( &fsspec , &g_iter.m_dirId , &isDir ) ;
1448 if ( !isDir )
1449 return wxEmptyString ;
1450
1451 return wxFindNextFile( ) ;
1452 }
1453
1454 wxString wxFindNextFile()
1455 {
1456 wxString result;
1457
1458 short err = noErr ;
1459
1460 while ( err == noErr )
1461 {
1462 g_iter.m_index++ ;
1463 g_iter.m_CPB.dirInfo.ioFDirIndex = g_iter.m_index;
1464 g_iter.m_CPB.dirInfo.ioDrDirID = g_iter.m_dirId; /* we need to do this every time */
1465 err = PBGetCatInfoSync((CInfoPBPtr)&g_iter.m_CPB);
1466 if ( err != noErr )
1467 break ;
1468
1469 if ( ( g_iter.m_CPB.dirInfo.ioFlAttrib & ioDirMask) != 0 && (g_iter_flags & wxDIR) ) // we have a directory
1470 break ;
1471
1472 if ( ( g_iter.m_CPB.dirInfo.ioFlAttrib & ioDirMask) == 0 && !(g_iter_flags & wxFILE ) )
1473 continue ;
1474
1475 // hit !
1476 break ;
1477 }
1478 if ( err != noErr )
1479 {
1480 return wxEmptyString ;
1481 }
1482 FSSpec spec ;
1483
1484 FSMakeFSSpecCompat(g_iter.m_CPB.hFileInfo.ioVRefNum,
1485 g_iter.m_dirId,
1486 g_iter.m_name,
1487 &spec) ;
1488
1489 return wxMacFSSpec2MacFilename( &spec ) ;
1490 }
1491
1492 #elif defined(__WXMSW__)
1493
1494 #ifdef __WIN32__
1495 static HANDLE gs_hFileStruct = INVALID_HANDLE_VALUE;
1496 static WIN32_FIND_DATA gs_findDataStruct;
1497 #else // Win16
1498 #ifdef __BORLANDC__
1499 static struct ffblk gs_findDataStruct;
1500 #else
1501 static struct _find_t gs_findDataStruct;
1502 #endif // Borland
1503 #endif // Win32/16
1504
1505 static wxString gs_strFileSpec;
1506 static int gs_findFlags = 0;
1507
1508 wxString wxFindFirstFile(const wxChar *spec, int flags)
1509 {
1510 wxString result;
1511
1512 gs_strFileSpec = spec;
1513 gs_findFlags = flags; /* MATTHEW: [5] Remember flags */
1514
1515 // Find path only so we can concatenate found file onto path
1516 wxString path(wxPathOnly(gs_strFileSpec));
1517 if ( !path.IsEmpty() )
1518 result << path << wxT('\\');
1519
1520 #ifdef __WIN32__
1521 if ( gs_hFileStruct != INVALID_HANDLE_VALUE )
1522 FindClose(gs_hFileStruct);
1523
1524 gs_hFileStruct = ::FindFirstFile(WXSTRINGCAST spec, &gs_findDataStruct);
1525
1526 if ( gs_hFileStruct == INVALID_HANDLE_VALUE )
1527 {
1528 result.Empty();
1529
1530 return result;
1531 }
1532
1533 bool isdir = !!(gs_findDataStruct.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1534
1535 if (isdir && !(flags & wxDIR))
1536 return wxFindNextFile();
1537 else if (!isdir && flags && !(flags & wxFILE))
1538 return wxFindNextFile();
1539
1540 result += gs_findDataStruct.cFileName;
1541
1542 return result;
1543 #else // !Win32
1544 int flag = _A_NORMAL;
1545 if (flags & wxDIR)
1546 flag = _A_SUBDIR;
1547
1548 #ifdef __BORLANDC__
1549 if (findfirst(WXSTRINGCAST spec, &gs_findDataStruct, flag) == 0)
1550 #else
1551 if (_dos_findfirst(WXSTRINGCAST spec, flag, &gs_findDataStruct) == 0)
1552 #endif
1553 {
1554 char attrib;
1555
1556 #ifdef __BORLANDC__
1557 attrib = gs_findDataStruct.ff_attrib;
1558 #else
1559 attrib = gs_findDataStruct.attrib;
1560 #endif
1561
1562 if (attrib & _A_SUBDIR) {
1563 if (!(gs_findFlags & wxDIR))
1564 return wxFindNextFile();
1565 } else if (gs_findFlags && !(gs_findFlags & wxFILE))
1566 return wxFindNextFile();
1567
1568 result +=
1569 #ifdef __BORLANDC__
1570 gs_findDataStruct.ff_name
1571 #else
1572 gs_findDataStruct.name
1573 #endif
1574 ;
1575 }
1576
1577 return result;
1578 #endif // __WIN32__
1579 }
1580
1581
1582 wxString wxFindNextFile()
1583 {
1584 wxString result;
1585
1586 // Find path only so we can concatenate found file onto path
1587 wxString path(wxPathOnly(gs_strFileSpec));
1588
1589 try_again:
1590
1591 #ifdef __WIN32__
1592 if (gs_hFileStruct == INVALID_HANDLE_VALUE)
1593 return result;
1594
1595 bool success = (FindNextFile(gs_hFileStruct, &gs_findDataStruct) != 0);
1596 if (!success)
1597 {
1598 FindClose(gs_hFileStruct);
1599 gs_hFileStruct = INVALID_HANDLE_VALUE;
1600 }
1601 else
1602 {
1603 bool isdir = !!(gs_findDataStruct.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1604
1605 if (isdir && !(gs_findFlags & wxDIR))
1606 goto try_again;
1607 else if (!isdir && gs_findFlags && !(gs_findFlags & wxFILE))
1608 goto try_again;
1609
1610 if ( !path.IsEmpty() )
1611 result << path << wxT('\\');
1612 result << gs_findDataStruct.cFileName;
1613 }
1614
1615 return result;
1616 #else // Win16
1617
1618 #ifdef __BORLANDC__
1619 if (findnext(&gs_findDataStruct) == 0)
1620 #else
1621 if (_dos_findnext(&gs_findDataStruct) == 0)
1622 #endif
1623 {
1624 /* MATTHEW: [5] Check directory flag */
1625 char attrib;
1626
1627 #ifdef __BORLANDC__
1628 attrib = gs_findDataStruct.ff_attrib;
1629 #else
1630 attrib = gs_findDataStruct.attrib;
1631 #endif
1632
1633 if (attrib & _A_SUBDIR) {
1634 if (!(gs_findFlags & wxDIR))
1635 goto try_again;
1636 } else if (gs_findFlags && !(gs_findFlags & wxFILE))
1637 goto try_again;
1638
1639
1640 result +=
1641 #ifdef __BORLANDC__
1642 gs_findDataStruct.ff_name
1643 #else
1644 gs_findDataStruct.name
1645 #endif
1646 ;
1647 }
1648
1649 return result;
1650 #endif // Win32/16
1651 }
1652
1653 #elif defined(__WXPM__)
1654
1655 wxString wxFindFirstFile(const wxChar *spec, int flags)
1656 {
1657 wxString result;
1658
1659 /*
1660 // TODO: figure something out here for OS/2
1661 gs_strFileSpec = spec;
1662 gs_findFlags = flags;
1663
1664 // Find path only so we can concatenate found file onto path
1665 wxString path(wxPathOnly(gs_strFileSpec));
1666 if ( !path.IsEmpty() )
1667 result << path << wxT('\\');
1668
1669 int flag = _A_NORMAL;
1670 if (flags & wxDIR)
1671 flag = _A_SUBDIR;
1672
1673 if (_dos_findfirst(WXSTRINGCAST spec, flag, &gs_findDataStruct) == 0)
1674 {
1675 char attrib;
1676 attrib = gs_findDataStruct.attrib;
1677
1678 if (attrib & _A_SUBDIR) {
1679 if (!(gs_findFlags & wxDIR))
1680 return wxFindNextFile();
1681 } else if (gs_findFlags && !(gs_findFlags & wxFILE))
1682 return wxFindNextFile();
1683
1684 result += gs_findDataStruct.name;
1685 }
1686 */
1687 return result;
1688 }
1689
1690 wxString wxFindNextFile()
1691 {
1692 wxString result;
1693 // TODO:
1694 return result;
1695 }
1696
1697 #endif // Unix/Windows/OS/2
1698
1699 // Get current working directory.
1700 // If buf is NULL, allocates space using new, else
1701 // copies into buf.
1702 wxChar *wxGetWorkingDirectory(wxChar *buf, int sz)
1703 {
1704 if (!buf)
1705 buf = new wxChar[sz+1];
1706 #if wxUSE_UNICODE
1707 char *cbuf = new char[sz+1];
1708 #ifdef _MSC_VER
1709 if (_getcwd(cbuf, sz) == NULL) {
1710 #elif defined(__WXMAC__)
1711 enum
1712 {
1713 SFSaveDisk = 0x214, CurDirStore = 0x398
1714 };
1715 FSSpec cwdSpec ;
1716
1717 FSMakeFSSpec( - *(short *) SFSaveDisk , *(long *) CurDirStore , NULL , &cwdSpec ) ;
1718 wxString res = wxMacFSSpec2UnixFilename( &cwdSpec ) ;
1719 strcpy( buf , res ) ;
1720 if (0) {
1721 #else
1722 if (getcwd(cbuf, sz) == NULL) {
1723 #endif
1724 delete [] cbuf;
1725 #else // wxUnicode
1726 #ifdef _MSC_VER
1727 if (_getcwd(buf, sz) == NULL) {
1728 #elif defined(__WXMAC__) && !defined(__UNIX__)
1729 FSSpec cwdSpec ;
1730 FCBPBRec pb;
1731 OSErr error;
1732 Str255 fileName ;
1733 pb.ioNamePtr = (StringPtr) &fileName;
1734 pb.ioVRefNum = 0;
1735 pb.ioRefNum = LMGetCurApRefNum();
1736 pb.ioFCBIndx = 0;
1737 error = PBGetFCBInfoSync(&pb);
1738 if ( error == noErr )
1739 {
1740 cwdSpec.vRefNum = pb.ioFCBVRefNum;
1741 cwdSpec.parID = pb.ioFCBParID;
1742 cwdSpec.name[0] = 0 ;
1743 wxString res = wxMacFSSpec2MacFilename( &cwdSpec ) ;
1744
1745 strcpy( buf , res ) ;
1746 buf[res.length()-1]=0 ;
1747 }
1748 else
1749 buf[0] = 0 ;
1750 /*
1751 this version will not always give back the application directory on mac
1752 enum
1753 {
1754 SFSaveDisk = 0x214, CurDirStore = 0x398
1755 };
1756 FSSpec cwdSpec ;
1757
1758 FSMakeFSSpec( - *(short *) SFSaveDisk , *(long *) CurDirStore , NULL , &cwdSpec ) ;
1759 wxString res = wxMacFSSpec2UnixFilename( &cwdSpec ) ;
1760 strcpy( buf , res ) ;
1761 */
1762 if (0) {
1763 #elif(__VISAGECPP__)
1764 APIRET rc;
1765 rc = ::DosQueryCurrentDir( 0 // current drive
1766 ,buf
1767 ,(PULONG)&sz
1768 );
1769 if (rc != 0) {
1770 #else
1771 if (getcwd(buf, sz) == NULL) {
1772 #endif
1773 #endif
1774 buf[0] = wxT('.');
1775 buf[1] = wxT('\0');
1776 }
1777 #if wxUSE_UNICODE
1778 else {
1779 wxConvFile.MB2WC(buf, cbuf, sz);
1780 delete [] cbuf;
1781 }
1782 #endif
1783 return buf;
1784 }
1785
1786 wxString wxGetCwd()
1787 {
1788 static const size_t maxPathLen = 1024;
1789
1790 wxString str;
1791 wxGetWorkingDirectory(str.GetWriteBuf(maxPathLen), maxPathLen);
1792 str.UngetWriteBuf();
1793
1794 return str;
1795 }
1796
1797 bool wxSetWorkingDirectory(const wxString& d)
1798 {
1799 #if defined( __UNIX__ ) || defined( __WXMAC__ )
1800 return (chdir(wxFNSTRINGCAST d.fn_str()) == 0);
1801 #elif defined(__WXPM__)
1802 return (::DosSetCurrentDir((PSZ)d.c_str()) == 0);
1803 #elif defined(__WINDOWS__)
1804
1805 #ifdef __WIN32__
1806 return (bool)(SetCurrentDirectory(d) != 0);
1807 #else
1808 // Must change drive, too.
1809 bool isDriveSpec = ((strlen(d) > 1) && (d[1] == ':'));
1810 if (isDriveSpec)
1811 {
1812 wxChar firstChar = d[0];
1813
1814 // To upper case
1815 if (firstChar > 90)
1816 firstChar = firstChar - 32;
1817
1818 // To a drive number
1819 unsigned int driveNo = firstChar - 64;
1820 if (driveNo > 0)
1821 {
1822 unsigned int noDrives;
1823 _dos_setdrive(driveNo, &noDrives);
1824 }
1825 }
1826 bool success = (chdir(WXSTRINGCAST d) == 0);
1827
1828 return success;
1829 #endif
1830
1831 #endif
1832 }
1833
1834 // Get the OS directory if appropriate (such as the Windows directory).
1835 // On non-Windows platform, probably just return the empty string.
1836 wxString wxGetOSDirectory()
1837 {
1838 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
1839 wxChar buf[256];
1840 GetWindowsDirectory(buf, 256);
1841 return wxString(buf);
1842 #else
1843 return wxEmptyString;
1844 #endif
1845 }
1846
1847 bool wxEndsWithPathSeparator(const wxChar *pszFileName)
1848 {
1849 size_t len = wxStrlen(pszFileName);
1850 if ( len == 0 )
1851 return FALSE;
1852 else
1853 return wxIsPathSeparator(pszFileName[len - 1]);
1854 }
1855
1856 // find a file in a list of directories, returns false if not found
1857 bool wxFindFileInPath(wxString *pStr, const wxChar *pszPath, const wxChar *pszFile)
1858 {
1859 // we assume that it's not empty
1860 wxCHECK_MSG( !wxIsEmpty(pszFile), FALSE,
1861 _T("empty file name in wxFindFileInPath"));
1862
1863 // skip path separator in the beginning of the file name if present
1864 if ( wxIsPathSeparator(*pszFile) )
1865 pszFile++;
1866
1867 // copy the path (strtok will modify it)
1868 wxChar *szPath = new wxChar[wxStrlen(pszPath) + 1];
1869 wxStrcpy(szPath, pszPath);
1870
1871 wxString strFile;
1872 wxChar *pc, *save_ptr;
1873 for ( pc = wxStrtok(szPath, wxPATH_SEP, &save_ptr);
1874 pc != NULL;
1875 pc = wxStrtok((wxChar *) NULL, wxPATH_SEP, &save_ptr) )
1876 {
1877 // search for the file in this directory
1878 strFile = pc;
1879 if ( !wxEndsWithPathSeparator(pc) )
1880 strFile += wxFILE_SEP_PATH;
1881 strFile += pszFile;
1882
1883 if ( FileExists(strFile) ) {
1884 *pStr = strFile;
1885 break;
1886 }
1887 }
1888
1889 // suppress warning about unused variable save_ptr when wxStrtok() is a
1890 // macro which throws away its third argument
1891 save_ptr = pc;
1892
1893 delete [] szPath;
1894
1895 return pc != NULL; // if true => we breaked from the loop
1896 }
1897
1898 void WXDLLEXPORT wxSplitPath(const wxChar *pszFileName,
1899 wxString *pstrPath,
1900 wxString *pstrName,
1901 wxString *pstrExt)
1902 {
1903 // it can be empty, but it shouldn't be NULL
1904 wxCHECK_RET( pszFileName, wxT("NULL file name in wxSplitPath") );
1905
1906 wxFileName::SplitPath(pszFileName, pstrPath, pstrName, pstrExt);
1907 }
1908
1909 time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename)
1910 {
1911 wxStructStat buf;
1912
1913 wxStat(filename.fn_str(), &buf);
1914 return buf.st_mtime;
1915 }
1916
1917
1918 //------------------------------------------------------------------------
1919 // wild character routines
1920 //------------------------------------------------------------------------
1921
1922 bool wxIsWild( const wxString& pattern )
1923 {
1924 wxString tmp = pattern;
1925 wxChar *pat = WXSTRINGCAST(tmp);
1926 while (*pat) {
1927 switch (*pat++) {
1928 case wxT('?'): case wxT('*'): case wxT('['): case wxT('{'):
1929 return TRUE;
1930 case wxT('\\'):
1931 if (!*pat++)
1932 return FALSE;
1933 }
1934 }
1935 return FALSE;
1936 };
1937
1938 bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special )
1939
1940 #if defined(HAVE_FNMATCH_H)
1941 {
1942 // this probably won't work well for multibyte chars in Unicode mode?
1943 if(dot_special)
1944 return fnmatch(pat.fn_str(), text.fn_str(), FNM_PERIOD) == 0;
1945 else
1946 return fnmatch(pat.fn_str(), text.fn_str(), 0) == 0;
1947 }
1948 #else
1949
1950 // #pragma error Broken implementation of wxMatchWild() -- needs fixing!
1951
1952 /*
1953 * WARNING: this code is broken!
1954 */
1955 {
1956 wxString tmp1 = pat;
1957 wxChar *pattern = WXSTRINGCAST(tmp1);
1958 wxString tmp2 = text;
1959 wxChar *str = WXSTRINGCAST(tmp2);
1960 wxChar c;
1961 wxChar *cp;
1962 bool done = FALSE, ret_code, ok;
1963 // Below is for vi fans
1964 const wxChar OB = wxT('{'), CB = wxT('}');
1965
1966 // dot_special means '.' only matches '.'
1967 if (dot_special && *str == wxT('.') && *pattern != *str)
1968 return FALSE;
1969
1970 while ((*pattern != wxT('\0')) && (!done)
1971 && (((*str==wxT('\0'))&&((*pattern==OB)||(*pattern==wxT('*'))))||(*str!=wxT('\0')))) {
1972 switch (*pattern) {
1973 case wxT('\\'):
1974 pattern++;
1975 if (*pattern != wxT('\0'))
1976 pattern++;
1977 break;
1978 case wxT('*'):
1979 pattern++;
1980 ret_code = FALSE;
1981 while ((*str!=wxT('\0'))
1982 && ((ret_code=wxMatchWild(pattern, str++, FALSE)) == 0))
1983 /*loop*/;
1984 if (ret_code) {
1985 while (*str != wxT('\0'))
1986 str++;
1987 while (*pattern != wxT('\0'))
1988 pattern++;
1989 }
1990 break;
1991 case wxT('['):
1992 pattern++;
1993 repeat:
1994 if ((*pattern == wxT('\0')) || (*pattern == wxT(']'))) {
1995 done = TRUE;
1996 break;
1997 }
1998 if (*pattern == wxT('\\')) {
1999 pattern++;
2000 if (*pattern == wxT('\0')) {
2001 done = TRUE;
2002 break;
2003 }
2004 }
2005 if (*(pattern + 1) == wxT('-')) {
2006 c = *pattern;
2007 pattern += 2;
2008 if (*pattern == wxT(']')) {
2009 done = TRUE;
2010 break;
2011 }
2012 if (*pattern == wxT('\\')) {
2013 pattern++;
2014 if (*pattern == wxT('\0')) {
2015 done = TRUE;
2016 break;
2017 }
2018 }
2019 if ((*str < c) || (*str > *pattern)) {
2020 pattern++;
2021 goto repeat;
2022 }
2023 } else if (*pattern != *str) {
2024 pattern++;
2025 goto repeat;
2026 }
2027 pattern++;
2028 while ((*pattern != wxT(']')) && (*pattern != wxT('\0'))) {
2029 if ((*pattern == wxT('\\')) && (*(pattern + 1) != wxT('\0')))
2030 pattern++;
2031 pattern++;
2032 }
2033 if (*pattern != wxT('\0')) {
2034 pattern++, str++;
2035 }
2036 break;
2037 case wxT('?'):
2038 pattern++;
2039 str++;
2040 break;
2041 case OB:
2042 pattern++;
2043 while ((*pattern != CB) && (*pattern != wxT('\0'))) {
2044 cp = str;
2045 ok = TRUE;
2046 while (ok && (*cp != wxT('\0')) && (*pattern != wxT('\0'))
2047 && (*pattern != wxT(',')) && (*pattern != CB)) {
2048 if (*pattern == wxT('\\'))
2049 pattern++;
2050 ok = (*pattern++ == *cp++);
2051 }
2052 if (*pattern == wxT('\0')) {
2053 ok = FALSE;
2054 done = TRUE;
2055 break;
2056 } else if (ok) {
2057 str = cp;
2058 while ((*pattern != CB) && (*pattern != wxT('\0'))) {
2059 if (*++pattern == wxT('\\')) {
2060 if (*++pattern == CB)
2061 pattern++;
2062 }
2063 }
2064 } else {
2065 while (*pattern!=CB && *pattern!=wxT(',') && *pattern!=wxT('\0')) {
2066 if (*++pattern == wxT('\\')) {
2067 if (*++pattern == CB || *pattern == wxT(','))
2068 pattern++;
2069 }
2070 }
2071 }
2072 if (*pattern != wxT('\0'))
2073 pattern++;
2074 }
2075 break;
2076 default:
2077 if (*str == *pattern) {
2078 str++, pattern++;
2079 } else {
2080 done = TRUE;
2081 }
2082 }
2083 }
2084 while (*pattern == wxT('*'))
2085 pattern++;
2086 return ((*str == wxT('\0')) && (*pattern == wxT('\0')));
2087 };
2088
2089 #endif
2090
2091 #ifdef __VISUALC__
2092 #pragma warning(default:4706) // assignment within conditional expression
2093 #endif // VC++