]> git.saurik.com Git - wxWidgets.git/blob - src/common/filefn.cpp
corrected wxGetWorkingDirectory for mac (stripping last char off)
[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 #elif defined(__WXPM__)
1023 if (::DosCopy(file2, file2, overwrite ? DCPY_EXISTING : 0) == 0)
1024 return TRUE;
1025 else
1026 return FALSE;
1027 #else // !Win32
1028 wxStructStat fbuf;
1029
1030 // get permissions of file1
1031 if ( wxStat(OS_FILENAME(file1), &fbuf) != 0 )
1032 {
1033 // the file probably doesn't exist or we haven't the rights to read
1034 // from it anyhow
1035 wxLogSysError(_("Impossible to get permissions for file '%s'"),
1036 file1.c_str());
1037 return FALSE;
1038 }
1039
1040 // open file1 for reading
1041 wxFile fileIn(file1, wxFile::read);
1042 if ( !fileIn.IsOpened() )
1043 return FALSE;
1044
1045 // remove file2, if it exists. This is needed for creating
1046 // file2 with the correct permissions in the next step
1047 if ( wxFileExists(file2) && (!overwrite || !wxRemoveFile(file2)))
1048 {
1049 wxLogSysError(_("Impossible to overwrite the file '%s'"),
1050 file2.c_str());
1051 return FALSE;
1052 }
1053
1054 #ifdef __UNIX__
1055 // reset the umask as we want to create the file with exactly the same
1056 // permissions as the original one
1057 mode_t oldUmask = umask( 0 );
1058 #endif // __UNIX__
1059
1060 // create file2 with the same permissions than file1 and open it for
1061 // writing
1062 wxFile fileOut;
1063 if ( !fileOut.Create(file2, overwrite, fbuf.st_mode & 0777) )
1064 return FALSE;
1065
1066 #ifdef __UNIX__
1067 /// restore the old umask
1068 umask(oldUmask);
1069 #endif // __UNIX__
1070
1071 // copy contents of file1 to file2
1072 char buf[4096];
1073 size_t count;
1074 for ( ;; )
1075 {
1076 count = fileIn.Read(buf, WXSIZEOF(buf));
1077 if ( fileIn.Error() )
1078 return FALSE;
1079
1080 // end of file?
1081 if ( !count )
1082 break;
1083
1084 if ( fileOut.Write(buf, count) < count )
1085 return FALSE;
1086 }
1087
1088 // we can expect fileIn to be closed successfully, but we should ensure
1089 // that fileOut was closed as some write errors (disk full) might not be
1090 // detected before doing this
1091 if ( !fileIn.Close() || !fileOut.Close() )
1092 return FALSE;
1093
1094 #if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__)
1095 // no chmod in VA. Should be some permission API for HPFS386 partitions
1096 // however
1097 if ( chmod(OS_FILENAME(file2), fbuf.st_mode) != 0 )
1098 {
1099 wxLogSysError(_("Impossible to set permissions for the file '%s'"),
1100 file2.c_str());
1101 return FALSE;
1102 }
1103 #endif // OS/2 || Mac
1104
1105 return TRUE;
1106 #endif // __WXMSW__ && __WIN32__
1107 }
1108
1109 bool
1110 wxRenameFile (const wxString& file1, const wxString& file2)
1111 {
1112 // Normal system call
1113 if ( wxRename (file1, file2) == 0 )
1114 return TRUE;
1115
1116 // Try to copy
1117 if (wxCopyFile(file1, file2)) {
1118 wxRemoveFile(file1);
1119 return TRUE;
1120 }
1121 // Give up
1122 return FALSE;
1123 }
1124
1125 bool wxRemoveFile(const wxString& file)
1126 {
1127 #if defined(__VISUALC__) \
1128 || defined(__BORLANDC__) \
1129 || defined(__WATCOMC__) \
1130 || defined(__GNUWIN32__)
1131 int res = wxRemove(file);
1132 #else
1133 int res = unlink(OS_FILENAME(file));
1134 #endif
1135
1136 return res == 0;
1137 }
1138
1139 bool wxMkdir(const wxString& dir, int perm)
1140 {
1141 #if defined(__WXMAC__) && !defined(__UNIX__)
1142 return (mkdir( dir , 0 ) == 0);
1143 #else // !Mac
1144 const wxChar *dirname = dir.c_str();
1145
1146 // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too
1147 // for the GNU compiler
1148 #if (!(defined(__WXMSW__) || defined(__WXPM__))) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) || defined(__WXWINE__) || defined(__WXMICROWIN__)
1149 if ( mkdir(wxFNCONV(dirname), perm) != 0 )
1150 #elif defined(__WXPM__)
1151 if (::DosCreateDir((PSZ)dirname, NULL) != 0) // enhance for EAB's??
1152 #else // !MSW and !OS/2 VAC++
1153 (void)perm;
1154 if ( wxMkDir(wxFNSTRINGCAST wxFNCONV(dirname)) != 0 )
1155 #endif // !MSW/MSW
1156 {
1157 wxLogSysError(_("Directory '%s' couldn't be created"), dirname);
1158
1159 return FALSE;
1160 }
1161
1162 return TRUE;
1163 #endif // Mac/!Mac
1164 }
1165
1166 bool wxRmdir(const wxString& dir, int WXUNUSED(flags))
1167 {
1168 #ifdef __VMS__
1169 return FALSE; //to be changed since rmdir exists in VMS7.x
1170 #elif defined(__WXPM__)
1171 return (::DosDeleteDir((PSZ)dir.c_str()) == 0);
1172 #else
1173
1174 #ifdef __SALFORDC__
1175 return FALSE; // What to do?
1176 #else
1177 return (wxRmDir(OS_FILENAME(dir)) == 0);
1178 #endif
1179
1180 #endif
1181 }
1182
1183 // does the path exists? (may have or not '/' or '\\' at the end)
1184 bool wxPathExists(const wxChar *pszPathName)
1185 {
1186 wxString strPath(pszPathName);
1187 #ifdef __WINDOWS__
1188 // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists,
1189 // so remove all trailing backslashes from the path - but don't do this for
1190 // the pathes "d:\" (which are different from "d:") nor for just "\"
1191 while ( wxEndsWithPathSeparator(strPath) )
1192 {
1193 size_t len = strPath.length();
1194 if ( len == 1 || (len == 3 && strPath[len - 2] == _T(':')) )
1195 break;
1196
1197 strPath.Truncate(len - 1);
1198 }
1199 #endif // __WINDOWS__
1200
1201 #ifdef __WINDOWS__
1202 // Stat can't cope with network paths
1203 DWORD ret = GetFileAttributes(strPath.c_str());
1204 DWORD isDir = (ret & FILE_ATTRIBUTE_DIRECTORY);
1205 return ((ret != 0xffffffff) && (isDir != 0));
1206 #else
1207
1208 wxStructStat st;
1209 #ifndef __VISAGECPP__
1210 return wxStat(wxFNSTRINGCAST strPath.fn_str(), &st) == 0 &&
1211 ((st.st_mode & S_IFMT) == S_IFDIR);
1212 #else
1213 // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only
1214 return wxStat(wxFNSTRINGCAST strPath.fn_str(), &st) == 0 &&
1215 (st.st_mode == S_IFDIR);
1216 #endif
1217
1218 #endif
1219 }
1220
1221 // Get a temporary filename, opening and closing the file.
1222 wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf)
1223 {
1224 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
1225
1226 #ifndef __WIN32__
1227 wxChar tmp[144];
1228 ::GetTempFileName(0, WXSTRINGCAST prefix, 0, tmp);
1229 #else
1230 wxChar tmp[MAX_PATH];
1231 wxChar tmpPath[MAX_PATH];
1232 ::GetTempPath(MAX_PATH, tmpPath);
1233 ::GetTempFileName(tmpPath, WXSTRINGCAST prefix, 0, tmp);
1234 #endif
1235 if (buf) wxStrcpy(buf, tmp);
1236 else buf = copystring(tmp);
1237 return buf;
1238
1239 #else
1240 static short last_temp = 0; // cache last to speed things a bit
1241 // At most 1000 temp files to a process! We use a ring count.
1242 wxChar tmp[100]; // FIXME static buffer
1243
1244 for (short suffix = last_temp + 1; suffix != last_temp; ++suffix %= 1000)
1245 {
1246 wxSprintf (tmp, wxT("/tmp/%s%d.%03x"), WXSTRINGCAST prefix, (int) getpid (), (int) suffix);
1247 if (!wxFileExists( tmp ))
1248 {
1249 // Touch the file to create it (reserve name)
1250 FILE *fd = fopen (wxFNCONV(tmp), "w");
1251 if (fd)
1252 fclose (fd);
1253 last_temp = suffix;
1254 if (buf)
1255 wxStrcpy( buf, tmp);
1256 else
1257 buf = copystring( tmp );
1258 return buf;
1259 }
1260 }
1261 wxLogError( _("wxWindows: error finding temporary file name.\n") );
1262 if (buf) buf[0] = 0;
1263 return (wxChar *) NULL;
1264 #endif
1265 }
1266
1267 bool wxGetTempFileName(const wxString& prefix, wxString& buf)
1268 {
1269 wxChar buf2[512];
1270 if (wxGetTempFileName(prefix, buf2) != (wxChar*) NULL)
1271 {
1272 buf = buf2;
1273 return TRUE;
1274 }
1275 else
1276 return FALSE;
1277 }
1278
1279 // Get first file name matching given wild card.
1280
1281 #ifdef __UNIX__
1282
1283 // Get first file name matching given wild card.
1284 // Flags are reserved for future use.
1285
1286 #if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 )
1287 static DIR *gs_dirStream = (DIR *) NULL;
1288 static wxString gs_strFileSpec;
1289 static int gs_findFlags = 0;
1290 #endif
1291
1292 wxString wxFindFirstFile(const wxChar *spec, int flags)
1293 {
1294 wxString result;
1295 #ifdef __VMS
1296 wxChar *specvms = NULL;
1297 #endif
1298
1299 #if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 )
1300 if (gs_dirStream)
1301 closedir(gs_dirStream); // edz 941103: better housekeping
1302
1303 gs_findFlags = flags;
1304
1305 gs_strFileSpec = spec;
1306
1307 // Find path only so we can concatenate
1308 // found file onto path
1309 wxString path(wxPathOnly(gs_strFileSpec));
1310
1311 // special case: path is really "/"
1312 if ( !path && gs_strFileSpec[0u] == wxT('/') )
1313 #ifdef __VMS
1314 {
1315 wxStrcpy( specvms , wxT( "[000000]" ) );
1316 gs_strFileSpec = specvms;
1317 wxString path_vms(wxPathOnly(gs_strFileSpec));
1318 path = path_vms;
1319 }
1320 #else
1321 path = wxT('/');
1322 #endif
1323 // path is empty => Local directory
1324 if ( !path )
1325 #ifdef __VMS
1326 {
1327 wxStrcpy( specvms , wxT( "[]" ) );
1328 gs_strFileSpec = specvms;
1329 wxString path_vms1(wxPathOnly(gs_strFileSpec));
1330 path = path_vms1;
1331 }
1332 #else
1333 path = wxT('.');
1334 #endif
1335
1336 gs_dirStream = opendir(path.fn_str());
1337 if ( !gs_dirStream )
1338 {
1339 wxLogSysError(_("Can not enumerate files in directory '%s'"),
1340 path.c_str());
1341 }
1342 else
1343 {
1344 result = wxFindNextFile();
1345 }
1346 #endif // !VMS6.x or earlier
1347
1348 return result;
1349 }
1350
1351 wxString wxFindNextFile()
1352 {
1353 wxString result;
1354
1355 #if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 )
1356 wxCHECK_MSG( gs_dirStream, result, wxT("must call wxFindFirstFile first") );
1357
1358 // Find path only so we can concatenate
1359 // found file onto path
1360 wxString path(wxPathOnly(gs_strFileSpec));
1361 wxString name(wxFileNameFromPath(gs_strFileSpec));
1362
1363 /* MATTHEW: special case: path is really "/" */
1364 if ( !path && gs_strFileSpec[0u] == wxT('/'))
1365 path = wxT('/');
1366
1367 // Do the reading
1368 struct dirent *nextDir;
1369 for ( nextDir = readdir(gs_dirStream);
1370 nextDir != NULL;
1371 nextDir = readdir(gs_dirStream) )
1372 {
1373 if (wxMatchWild(name, nextDir->d_name, FALSE) && // RR: added FALSE to find hidden files
1374 strcmp(nextDir->d_name, ".") &&
1375 strcmp(nextDir->d_name, "..") )
1376 {
1377 result.Empty();
1378 if ( !path.IsEmpty() )
1379 {
1380 result = path;
1381 if ( path != wxT('/') )
1382 result += wxT('/');
1383 }
1384
1385 result += nextDir->d_name;
1386
1387 // Only return "." and ".." when they match
1388 bool isdir;
1389 if ( (strcmp(nextDir->d_name, ".") == 0) ||
1390 (strcmp(nextDir->d_name, "..") == 0))
1391 {
1392 if ( (gs_findFlags & wxDIR) != 0 )
1393 isdir = TRUE;
1394 else
1395 continue;
1396 }
1397 else
1398 isdir = wxDirExists(result);
1399
1400 // and only return directories when flags & wxDIR
1401 if ( !gs_findFlags ||
1402 ((gs_findFlags & wxDIR) && isdir) ||
1403 ((gs_findFlags & wxFILE) && !isdir) )
1404 {
1405 return result;
1406 }
1407 }
1408 }
1409
1410 result.Empty(); // not found
1411
1412 closedir(gs_dirStream);
1413 gs_dirStream = (DIR *) NULL;
1414 #endif // !VMS6.2 or earlier
1415
1416 return result;
1417 }
1418
1419 #elif defined(__WXMAC__)
1420
1421 struct MacDirectoryIterator
1422 {
1423 CInfoPBRec m_CPB ;
1424 wxInt16 m_index ;
1425 long m_dirId ;
1426 Str255 m_name ;
1427 } ;
1428
1429 static int g_iter_flags ;
1430
1431 static MacDirectoryIterator g_iter ;
1432
1433 wxString wxFindFirstFile(const wxChar *spec, int flags)
1434 {
1435 wxString result;
1436
1437 g_iter_flags = flags; /* MATTHEW: [5] Remember flags */
1438
1439 // Find path only so we can concatenate found file onto path
1440 wxString path(wxPathOnly(spec));
1441 if ( !path.IsEmpty() )
1442 result << path << wxT('\\');
1443
1444 FSSpec fsspec ;
1445
1446 wxMacFilename2FSSpec( result , &fsspec ) ;
1447 g_iter.m_CPB.hFileInfo.ioVRefNum = fsspec.vRefNum ;
1448 g_iter.m_CPB.hFileInfo.ioNamePtr = g_iter.m_name ;
1449 g_iter.m_index = 0 ;
1450
1451 Boolean isDir ;
1452 FSpGetDirectoryID( &fsspec , &g_iter.m_dirId , &isDir ) ;
1453 if ( !isDir )
1454 return wxEmptyString ;
1455
1456 return wxFindNextFile( ) ;
1457 }
1458
1459 wxString wxFindNextFile()
1460 {
1461 wxString result;
1462
1463 short err = noErr ;
1464
1465 while ( err == noErr )
1466 {
1467 g_iter.m_index++ ;
1468 g_iter.m_CPB.dirInfo.ioFDirIndex = g_iter.m_index;
1469 g_iter.m_CPB.dirInfo.ioDrDirID = g_iter.m_dirId; /* we need to do this every time */
1470 err = PBGetCatInfoSync((CInfoPBPtr)&g_iter.m_CPB);
1471 if ( err != noErr )
1472 break ;
1473
1474 if ( ( g_iter.m_CPB.dirInfo.ioFlAttrib & ioDirMask) != 0 && (g_iter_flags & wxDIR) ) // we have a directory
1475 break ;
1476
1477 if ( ( g_iter.m_CPB.dirInfo.ioFlAttrib & ioDirMask) == 0 && !(g_iter_flags & wxFILE ) )
1478 continue ;
1479
1480 // hit !
1481 break ;
1482 }
1483 if ( err != noErr )
1484 {
1485 return wxEmptyString ;
1486 }
1487 FSSpec spec ;
1488
1489 FSMakeFSSpecCompat(g_iter.m_CPB.hFileInfo.ioVRefNum,
1490 g_iter.m_dirId,
1491 g_iter.m_name,
1492 &spec) ;
1493
1494 return wxMacFSSpec2MacFilename( &spec ) ;
1495 }
1496
1497 #elif defined(__WXMSW__)
1498
1499 #ifdef __WIN32__
1500 static HANDLE gs_hFileStruct = INVALID_HANDLE_VALUE;
1501 static WIN32_FIND_DATA gs_findDataStruct;
1502 #else // Win16
1503 #ifdef __BORLANDC__
1504 static struct ffblk gs_findDataStruct;
1505 #else
1506 static struct _find_t gs_findDataStruct;
1507 #endif // Borland
1508 #endif // Win32/16
1509
1510 static wxString gs_strFileSpec;
1511 static int gs_findFlags = 0;
1512
1513 wxString wxFindFirstFile(const wxChar *spec, int flags)
1514 {
1515 wxString result;
1516
1517 gs_strFileSpec = spec;
1518 gs_findFlags = flags; /* MATTHEW: [5] Remember flags */
1519
1520 // Find path only so we can concatenate found file onto path
1521 wxString path(wxPathOnly(gs_strFileSpec));
1522 if ( !path.IsEmpty() )
1523 result << path << wxT('\\');
1524
1525 #ifdef __WIN32__
1526 if ( gs_hFileStruct != INVALID_HANDLE_VALUE )
1527 FindClose(gs_hFileStruct);
1528
1529 gs_hFileStruct = ::FindFirstFile(WXSTRINGCAST spec, &gs_findDataStruct);
1530
1531 if ( gs_hFileStruct == INVALID_HANDLE_VALUE )
1532 {
1533 result.Empty();
1534
1535 return result;
1536 }
1537
1538 bool isdir = !!(gs_findDataStruct.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1539
1540 if (isdir && !(flags & wxDIR))
1541 return wxFindNextFile();
1542 else if (!isdir && flags && !(flags & wxFILE))
1543 return wxFindNextFile();
1544
1545 result += gs_findDataStruct.cFileName;
1546
1547 return result;
1548 #else // !Win32
1549 int flag = _A_NORMAL;
1550 if (flags & wxDIR)
1551 flag = _A_SUBDIR;
1552
1553 #ifdef __BORLANDC__
1554 if (findfirst(WXSTRINGCAST spec, &gs_findDataStruct, flag) == 0)
1555 #else
1556 if (_dos_findfirst(WXSTRINGCAST spec, flag, &gs_findDataStruct) == 0)
1557 #endif
1558 {
1559 char attrib;
1560
1561 #ifdef __BORLANDC__
1562 attrib = gs_findDataStruct.ff_attrib;
1563 #else
1564 attrib = gs_findDataStruct.attrib;
1565 #endif
1566
1567 if (attrib & _A_SUBDIR) {
1568 if (!(gs_findFlags & wxDIR))
1569 return wxFindNextFile();
1570 } else if (gs_findFlags && !(gs_findFlags & wxFILE))
1571 return wxFindNextFile();
1572
1573 result +=
1574 #ifdef __BORLANDC__
1575 gs_findDataStruct.ff_name
1576 #else
1577 gs_findDataStruct.name
1578 #endif
1579 ;
1580 }
1581
1582 return result;
1583 #endif // __WIN32__
1584 }
1585
1586
1587 wxString wxFindNextFile()
1588 {
1589 wxString result;
1590
1591 // Find path only so we can concatenate found file onto path
1592 wxString path(wxPathOnly(gs_strFileSpec));
1593
1594 try_again:
1595
1596 #ifdef __WIN32__
1597 if (gs_hFileStruct == INVALID_HANDLE_VALUE)
1598 return result;
1599
1600 bool success = (FindNextFile(gs_hFileStruct, &gs_findDataStruct) != 0);
1601 if (!success)
1602 {
1603 FindClose(gs_hFileStruct);
1604 gs_hFileStruct = INVALID_HANDLE_VALUE;
1605 }
1606 else
1607 {
1608 bool isdir = !!(gs_findDataStruct.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1609
1610 if (isdir && !(gs_findFlags & wxDIR))
1611 goto try_again;
1612 else if (!isdir && gs_findFlags && !(gs_findFlags & wxFILE))
1613 goto try_again;
1614
1615 if ( !path.IsEmpty() )
1616 result << path << wxT('\\');
1617 result << gs_findDataStruct.cFileName;
1618 }
1619
1620 return result;
1621 #else // Win16
1622
1623 #ifdef __BORLANDC__
1624 if (findnext(&gs_findDataStruct) == 0)
1625 #else
1626 if (_dos_findnext(&gs_findDataStruct) == 0)
1627 #endif
1628 {
1629 /* MATTHEW: [5] Check directory flag */
1630 char attrib;
1631
1632 #ifdef __BORLANDC__
1633 attrib = gs_findDataStruct.ff_attrib;
1634 #else
1635 attrib = gs_findDataStruct.attrib;
1636 #endif
1637
1638 if (attrib & _A_SUBDIR) {
1639 if (!(gs_findFlags & wxDIR))
1640 goto try_again;
1641 } else if (gs_findFlags && !(gs_findFlags & wxFILE))
1642 goto try_again;
1643
1644
1645 result +=
1646 #ifdef __BORLANDC__
1647 gs_findDataStruct.ff_name
1648 #else
1649 gs_findDataStruct.name
1650 #endif
1651 ;
1652 }
1653
1654 return result;
1655 #endif // Win32/16
1656 }
1657
1658 #elif defined(__WXPM__)
1659
1660 wxString wxFindFirstFile(const wxChar *spec, int flags)
1661 {
1662 wxString result;
1663
1664 /*
1665 // TODO: figure something out here for OS/2
1666 gs_strFileSpec = spec;
1667 gs_findFlags = flags;
1668
1669 // Find path only so we can concatenate found file onto path
1670 wxString path(wxPathOnly(gs_strFileSpec));
1671 if ( !path.IsEmpty() )
1672 result << path << wxT('\\');
1673
1674 int flag = _A_NORMAL;
1675 if (flags & wxDIR)
1676 flag = _A_SUBDIR;
1677
1678 if (_dos_findfirst(WXSTRINGCAST spec, flag, &gs_findDataStruct) == 0)
1679 {
1680 char attrib;
1681 attrib = gs_findDataStruct.attrib;
1682
1683 if (attrib & _A_SUBDIR) {
1684 if (!(gs_findFlags & wxDIR))
1685 return wxFindNextFile();
1686 } else if (gs_findFlags && !(gs_findFlags & wxFILE))
1687 return wxFindNextFile();
1688
1689 result += gs_findDataStruct.name;
1690 }
1691 */
1692 return result;
1693 }
1694
1695 wxString wxFindNextFile()
1696 {
1697 wxString result;
1698 // TODO:
1699 return result;
1700 }
1701
1702 #endif // Unix/Windows/OS/2
1703
1704 // Get current working directory.
1705 // If buf is NULL, allocates space using new, else
1706 // copies into buf.
1707 wxChar *wxGetWorkingDirectory(wxChar *buf, int sz)
1708 {
1709 if (!buf)
1710 buf = new wxChar[sz+1];
1711 #if wxUSE_UNICODE
1712 char *cbuf = new char[sz+1];
1713 #ifdef _MSC_VER
1714 if (_getcwd(cbuf, sz) == NULL) {
1715 #elif defined(__WXMAC__)
1716 enum
1717 {
1718 SFSaveDisk = 0x214, CurDirStore = 0x398
1719 };
1720 FSSpec cwdSpec ;
1721
1722 FSMakeFSSpec( - *(short *) SFSaveDisk , *(long *) CurDirStore , NULL , &cwdSpec ) ;
1723 wxString res = wxMacFSSpec2UnixFilename( &cwdSpec ) ;
1724 strcpy( buf , res ) ;
1725 if (0) {
1726 #else
1727 if (getcwd(cbuf, sz) == NULL) {
1728 #endif
1729 delete [] cbuf;
1730 #else // wxUnicode
1731 #ifdef _MSC_VER
1732 if (_getcwd(buf, sz) == NULL) {
1733 #elif defined(__WXMAC__) && !defined(__UNIX__)
1734 FSSpec cwdSpec ;
1735 FCBPBRec pb;
1736 OSErr error;
1737 Str255 fileName ;
1738 pb.ioNamePtr = (StringPtr) &fileName;
1739 pb.ioVRefNum = 0;
1740 pb.ioRefNum = LMGetCurApRefNum();
1741 pb.ioFCBIndx = 0;
1742 error = PBGetFCBInfoSync(&pb);
1743 if ( error == noErr )
1744 {
1745 cwdSpec.vRefNum = pb.ioFCBVRefNum;
1746 cwdSpec.parID = pb.ioFCBParID;
1747 cwdSpec.name[0] = 0 ;
1748 wxString res = wxMacFSSpec2MacFilename( &cwdSpec ) ;
1749
1750 strcpy( buf , res ) ;
1751 buf[res.length()]=0 ;
1752 }
1753 else
1754 buf[0] = 0 ;
1755 /*
1756 this version will not always give back the application directory on mac
1757 enum
1758 {
1759 SFSaveDisk = 0x214, CurDirStore = 0x398
1760 };
1761 FSSpec cwdSpec ;
1762
1763 FSMakeFSSpec( - *(short *) SFSaveDisk , *(long *) CurDirStore , NULL , &cwdSpec ) ;
1764 wxString res = wxMacFSSpec2UnixFilename( &cwdSpec ) ;
1765 strcpy( buf , res ) ;
1766 */
1767 if (0) {
1768 #elif defined(__VISAGECPP__) || (defined (__OS2__) && defined (__WATCOMC__))
1769 APIRET rc;
1770 rc = ::DosQueryCurrentDir( 0 // current drive
1771 ,buf
1772 ,(PULONG)&sz
1773 );
1774 if (rc != 0) {
1775 #else
1776 if (getcwd(buf, sz) == NULL) {
1777 #endif
1778 #endif
1779 buf[0] = wxT('.');
1780 buf[1] = wxT('\0');
1781 }
1782 #if wxUSE_UNICODE
1783 else {
1784 wxConvFile.MB2WC(buf, cbuf, sz);
1785 delete [] cbuf;
1786 }
1787 #endif
1788 return buf;
1789 }
1790
1791 wxString wxGetCwd()
1792 {
1793 static const size_t maxPathLen = 1024;
1794
1795 wxString str;
1796 wxGetWorkingDirectory(str.GetWriteBuf(maxPathLen), maxPathLen);
1797 str.UngetWriteBuf();
1798
1799 return str;
1800 }
1801
1802 bool wxSetWorkingDirectory(const wxString& d)
1803 {
1804 #if defined( __UNIX__ ) || defined( __WXMAC__ )
1805 return (chdir(wxFNSTRINGCAST d.fn_str()) == 0);
1806 #elif defined(__WXPM__)
1807 return (::DosSetCurrentDir((PSZ)d.c_str()) == 0);
1808 #elif defined(__WINDOWS__)
1809
1810 #ifdef __WIN32__
1811 return (bool)(SetCurrentDirectory(d) != 0);
1812 #else
1813 // Must change drive, too.
1814 bool isDriveSpec = ((strlen(d) > 1) && (d[1] == ':'));
1815 if (isDriveSpec)
1816 {
1817 wxChar firstChar = d[0];
1818
1819 // To upper case
1820 if (firstChar > 90)
1821 firstChar = firstChar - 32;
1822
1823 // To a drive number
1824 unsigned int driveNo = firstChar - 64;
1825 if (driveNo > 0)
1826 {
1827 unsigned int noDrives;
1828 _dos_setdrive(driveNo, &noDrives);
1829 }
1830 }
1831 bool success = (chdir(WXSTRINGCAST d) == 0);
1832
1833 return success;
1834 #endif
1835
1836 #endif
1837 }
1838
1839 // Get the OS directory if appropriate (such as the Windows directory).
1840 // On non-Windows platform, probably just return the empty string.
1841 wxString wxGetOSDirectory()
1842 {
1843 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
1844 wxChar buf[256];
1845 GetWindowsDirectory(buf, 256);
1846 return wxString(buf);
1847 #else
1848 return wxEmptyString;
1849 #endif
1850 }
1851
1852 bool wxEndsWithPathSeparator(const wxChar *pszFileName)
1853 {
1854 size_t len = wxStrlen(pszFileName);
1855 if ( len == 0 )
1856 return FALSE;
1857 else
1858 return wxIsPathSeparator(pszFileName[len - 1]);
1859 }
1860
1861 // find a file in a list of directories, returns false if not found
1862 bool wxFindFileInPath(wxString *pStr, const wxChar *pszPath, const wxChar *pszFile)
1863 {
1864 // we assume that it's not empty
1865 wxCHECK_MSG( !wxIsEmpty(pszFile), FALSE,
1866 _T("empty file name in wxFindFileInPath"));
1867
1868 // skip path separator in the beginning of the file name if present
1869 if ( wxIsPathSeparator(*pszFile) )
1870 pszFile++;
1871
1872 // copy the path (strtok will modify it)
1873 wxChar *szPath = new wxChar[wxStrlen(pszPath) + 1];
1874 wxStrcpy(szPath, pszPath);
1875
1876 wxString strFile;
1877 wxChar *pc, *save_ptr;
1878 for ( pc = wxStrtok(szPath, wxPATH_SEP, &save_ptr);
1879 pc != NULL;
1880 pc = wxStrtok((wxChar *) NULL, wxPATH_SEP, &save_ptr) )
1881 {
1882 // search for the file in this directory
1883 strFile = pc;
1884 if ( !wxEndsWithPathSeparator(pc) )
1885 strFile += wxFILE_SEP_PATH;
1886 strFile += pszFile;
1887
1888 if ( FileExists(strFile) ) {
1889 *pStr = strFile;
1890 break;
1891 }
1892 }
1893
1894 // suppress warning about unused variable save_ptr when wxStrtok() is a
1895 // macro which throws away its third argument
1896 save_ptr = pc;
1897
1898 delete [] szPath;
1899
1900 return pc != NULL; // if true => we breaked from the loop
1901 }
1902
1903 void WXDLLEXPORT wxSplitPath(const wxChar *pszFileName,
1904 wxString *pstrPath,
1905 wxString *pstrName,
1906 wxString *pstrExt)
1907 {
1908 // it can be empty, but it shouldn't be NULL
1909 wxCHECK_RET( pszFileName, wxT("NULL file name in wxSplitPath") );
1910
1911 wxFileName::SplitPath(pszFileName, pstrPath, pstrName, pstrExt);
1912 }
1913
1914 time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename)
1915 {
1916 wxStructStat buf;
1917
1918 wxStat(filename.fn_str(), &buf);
1919 return buf.st_mtime;
1920 }
1921
1922
1923 //------------------------------------------------------------------------
1924 // wild character routines
1925 //------------------------------------------------------------------------
1926
1927 bool wxIsWild( const wxString& pattern )
1928 {
1929 wxString tmp = pattern;
1930 wxChar *pat = WXSTRINGCAST(tmp);
1931 while (*pat) {
1932 switch (*pat++) {
1933 case wxT('?'): case wxT('*'): case wxT('['): case wxT('{'):
1934 return TRUE;
1935 case wxT('\\'):
1936 if (!*pat++)
1937 return FALSE;
1938 }
1939 }
1940 return FALSE;
1941 };
1942
1943 bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special )
1944
1945 #if defined(HAVE_FNMATCH_H)
1946 {
1947 // this probably won't work well for multibyte chars in Unicode mode?
1948 if(dot_special)
1949 return fnmatch(pat.fn_str(), text.fn_str(), FNM_PERIOD) == 0;
1950 else
1951 return fnmatch(pat.fn_str(), text.fn_str(), 0) == 0;
1952 }
1953 #else
1954
1955 // #pragma error Broken implementation of wxMatchWild() -- needs fixing!
1956
1957 /*
1958 * WARNING: this code is broken!
1959 */
1960 {
1961 wxString tmp1 = pat;
1962 wxChar *pattern = WXSTRINGCAST(tmp1);
1963 wxString tmp2 = text;
1964 wxChar *str = WXSTRINGCAST(tmp2);
1965 wxChar c;
1966 wxChar *cp;
1967 bool done = FALSE, ret_code, ok;
1968 // Below is for vi fans
1969 const wxChar OB = wxT('{'), CB = wxT('}');
1970
1971 // dot_special means '.' only matches '.'
1972 if (dot_special && *str == wxT('.') && *pattern != *str)
1973 return FALSE;
1974
1975 while ((*pattern != wxT('\0')) && (!done)
1976 && (((*str==wxT('\0'))&&((*pattern==OB)||(*pattern==wxT('*'))))||(*str!=wxT('\0')))) {
1977 switch (*pattern) {
1978 case wxT('\\'):
1979 pattern++;
1980 if (*pattern != wxT('\0'))
1981 pattern++;
1982 break;
1983 case wxT('*'):
1984 pattern++;
1985 ret_code = FALSE;
1986 while ((*str!=wxT('\0'))
1987 && ((ret_code=wxMatchWild(pattern, str++, FALSE)) == 0))
1988 /*loop*/;
1989 if (ret_code) {
1990 while (*str != wxT('\0'))
1991 str++;
1992 while (*pattern != wxT('\0'))
1993 pattern++;
1994 }
1995 break;
1996 case wxT('['):
1997 pattern++;
1998 repeat:
1999 if ((*pattern == wxT('\0')) || (*pattern == wxT(']'))) {
2000 done = TRUE;
2001 break;
2002 }
2003 if (*pattern == wxT('\\')) {
2004 pattern++;
2005 if (*pattern == wxT('\0')) {
2006 done = TRUE;
2007 break;
2008 }
2009 }
2010 if (*(pattern + 1) == wxT('-')) {
2011 c = *pattern;
2012 pattern += 2;
2013 if (*pattern == wxT(']')) {
2014 done = TRUE;
2015 break;
2016 }
2017 if (*pattern == wxT('\\')) {
2018 pattern++;
2019 if (*pattern == wxT('\0')) {
2020 done = TRUE;
2021 break;
2022 }
2023 }
2024 if ((*str < c) || (*str > *pattern)) {
2025 pattern++;
2026 goto repeat;
2027 }
2028 } else if (*pattern != *str) {
2029 pattern++;
2030 goto repeat;
2031 }
2032 pattern++;
2033 while ((*pattern != wxT(']')) && (*pattern != wxT('\0'))) {
2034 if ((*pattern == wxT('\\')) && (*(pattern + 1) != wxT('\0')))
2035 pattern++;
2036 pattern++;
2037 }
2038 if (*pattern != wxT('\0')) {
2039 pattern++, str++;
2040 }
2041 break;
2042 case wxT('?'):
2043 pattern++;
2044 str++;
2045 break;
2046 case OB:
2047 pattern++;
2048 while ((*pattern != CB) && (*pattern != wxT('\0'))) {
2049 cp = str;
2050 ok = TRUE;
2051 while (ok && (*cp != wxT('\0')) && (*pattern != wxT('\0'))
2052 && (*pattern != wxT(',')) && (*pattern != CB)) {
2053 if (*pattern == wxT('\\'))
2054 pattern++;
2055 ok = (*pattern++ == *cp++);
2056 }
2057 if (*pattern == wxT('\0')) {
2058 ok = FALSE;
2059 done = TRUE;
2060 break;
2061 } else if (ok) {
2062 str = cp;
2063 while ((*pattern != CB) && (*pattern != wxT('\0'))) {
2064 if (*++pattern == wxT('\\')) {
2065 if (*++pattern == CB)
2066 pattern++;
2067 }
2068 }
2069 } else {
2070 while (*pattern!=CB && *pattern!=wxT(',') && *pattern!=wxT('\0')) {
2071 if (*++pattern == wxT('\\')) {
2072 if (*++pattern == CB || *pattern == wxT(','))
2073 pattern++;
2074 }
2075 }
2076 }
2077 if (*pattern != wxT('\0'))
2078 pattern++;
2079 }
2080 break;
2081 default:
2082 if (*str == *pattern) {
2083 str++, pattern++;
2084 } else {
2085 done = TRUE;
2086 }
2087 }
2088 }
2089 while (*pattern == wxT('*'))
2090 pattern++;
2091 return ((*str == wxT('\0')) && (*pattern == wxT('\0')));
2092 };
2093
2094 #endif
2095
2096 #ifdef __VISUALC__
2097 #pragma warning(default:4706) // assignment within conditional expression
2098 #endif // VC++