]> git.saurik.com Git - wxWidgets.git/blob - src/common/filefn.cpp
84c0a65c36523760df4309d22dda2e8662a0fdcd
[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 #ifdef __GNUG__
13 #pragma implementation "filefn.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18 #include "wx/defs.h"
19
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23
24 #ifndef WX_PRECOMP
25 #include "wx/defs.h"
26 #endif
27
28 #include "wx/utils.h"
29 #include <wx/intl.h>
30
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #if !defined(__WATCOMC__)
36 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
37 #include <errno.h>
38 #endif
39 #endif
40 #include <time.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43
44 #ifdef __UNIX__
45 #include <unistd.h>
46 #include <dirent.h>
47 #endif
48
49 #ifdef __WINDOWS__
50 #ifndef __GNUWIN32__
51 #include <direct.h>
52 #include <dos.h>
53 #endif
54 #endif
55
56 #ifdef __GNUWIN32__
57 #include <sys/unistd.h>
58 #define stricmp strcasecmp
59 #endif
60
61 #ifdef __BORLANDC__ // Please someone tell me which version of Borland needs
62 // this (3.1 I believe) and how to test for it.
63 // If this works for Borland 4.0 as well, then no worries.
64 #include <dir.h>
65 #endif
66
67 #include "wx/setup.h"
68 #ifdef HAVE_FNMATCH_H
69 #include "fnmatch.h"
70 #endif
71
72 #ifdef __WINDOWS__
73 #include "windows.h"
74 #endif
75
76 #define _MAXPATHLEN 500
77
78 #if !USE_SHARED_LIBRARY
79 IMPLEMENT_DYNAMIC_CLASS(wxPathList, wxStringList)
80 #endif
81
82 extern char *wxBuffer;
83
84 void wxPathList::Add (const wxString& path)
85 {
86 wxStringList::Add ((char *)(const char *)path);
87 }
88
89 // Add paths e.g. from the PATH environment variable
90 void wxPathList::AddEnvList (const wxString& envVariable)
91 {
92 static const char PATH_TOKS[] =
93 #ifdef __WINDOWS__
94 " ;"; // Don't seperate with colon in DOS (used for drive)
95 #else
96 " :;";
97 #endif
98
99 char *val = getenv (WXSTRINGCAST envVariable);
100 if (val && *val)
101 {
102 char *s = copystring (val);
103 char *token = strtok (s, PATH_TOKS);
104
105 if (token)
106 {
107 Add (copystring (token));
108 while (token)
109 {
110 if ((token = strtok ((char *) NULL, PATH_TOKS)) != NULL)
111 Add (wxString(token));
112 }
113 }
114 delete[]s;
115 }
116 }
117
118 // Given a full filename (with path), ensure that that file can
119 // be accessed again USING FILENAME ONLY by adding the path
120 // to the list if not already there.
121 void wxPathList::EnsureFileAccessible (const wxString& path)
122 {
123 wxString path1(path);
124 char *path_only = wxPathOnly (WXSTRINGCAST path1);
125 if (path_only)
126 {
127 if (!Member (wxString(path_only)))
128 Add (wxString(path_only));
129 }
130 }
131
132 bool wxPathList::Member (const wxString& path)
133 {
134 for (wxNode * node = First (); node != NULL; node = node->Next ())
135 {
136 wxString path2((char *) node->Data ());
137 if (
138 #if defined(__WINDOWS__) || defined(__VMS__)
139 // Case INDEPENDENT
140 path.CompareTo (path2, wxString::ignoreCase) == 0
141 #else
142 // Case sensitive File System
143 path.CompareTo (path2) == 0
144 #endif
145 )
146 return TRUE;
147 }
148 return FALSE;
149 }
150
151 wxString wxPathList::FindValidPath (const wxString& file)
152 {
153 if (wxFileExists (wxExpandPath(wxBuffer, file)))
154 return wxString(wxBuffer);
155
156 char buf[_MAXPATHLEN];
157 strcpy(buf, wxBuffer);
158
159 char *filename = IsAbsolutePath (buf) ? wxFileNameFromPath (buf) : (char *)buf;
160
161 for (wxNode * node = First (); node; node = node->Next ())
162 {
163 char *path = (char *) node->Data ();
164 strcpy (wxBuffer, path);
165 char ch = wxBuffer[strlen(wxBuffer)-1];
166 if (ch != '\\' && ch != '/')
167 strcat (wxBuffer, "/");
168 strcat (wxBuffer, filename);
169 #ifdef __WINDOWS__
170 Unix2DosFilename (wxBuffer);
171 #endif
172 if (wxFileExists (wxBuffer))
173 {
174 return wxString(wxBuffer); // Found!
175 }
176 } // for()
177
178 return wxString(""); // Not found
179 }
180
181 wxString wxPathList::FindAbsoluteValidPath (const wxString& file)
182 {
183 wxString f = FindValidPath(file);
184 if (wxIsAbsolutePath(f))
185 return f;
186 else
187 {
188 char buf[500];
189 wxGetWorkingDirectory(buf, 499);
190 int len = (int)strlen(buf);
191 char lastCh = 0;
192 if (len > 0)
193 lastCh = buf[len-1];
194 if (lastCh != '/' && lastCh != '\\')
195 {
196 #ifdef __WINDOWS__
197 strcat(buf, "\\");
198 #else
199 strcat(buf, "/");
200 #endif
201 }
202 strcat(buf, (const char *)f);
203 strcpy(wxBuffer, buf);
204 return wxString(wxBuffer);
205 }
206 }
207
208 bool
209 wxFileExists (const wxString& filename)
210 {
211 #ifdef __GNUWIN32__ // (fix a B20 bug)
212 if (GetFileAttributes(filename) == 0xFFFFFFFF)
213 return FALSE;
214 else
215 return TRUE;
216 #else
217 struct stat stbuf;
218
219 if (filename && stat ((char *)(const char *)filename, &stbuf) == 0)
220 return TRUE;
221 return FALSE;
222 #endif
223 }
224
225 /* Vadim's alternative implementation
226
227 // does the file exist?
228 bool wxFileExists(const char *pszFileName)
229 {
230 struct stat st;
231 return !access(pszFileName, 0) &&
232 !stat(pszFileName, &st) &&
233 (st.st_mode & S_IFREG);
234 }
235 */
236
237 bool
238 wxIsAbsolutePath (const wxString& filename)
239 {
240 if (filename != "")
241 {
242 if (filename[0] == '/'
243 #ifdef __VMS__
244 || (filename[0] == '[' && filename[1] != '.')
245 #endif
246 #ifdef __WINDOWS__
247 /* MSDOS */
248 || filename[0] == '\\' || (isalpha (filename[0]) && filename[1] == ':')
249 #endif
250 )
251 return TRUE;
252 }
253 return FALSE;
254 }
255
256 /*
257 * Strip off any extension (dot something) from end of file,
258 * IF one exists. Inserts zero into buffer.
259 *
260 */
261
262 void wxStripExtension(char *buffer)
263 {
264 int len = strlen(buffer);
265 int i = len-1;
266 while (i > 0)
267 {
268 if (buffer[i] == '.')
269 {
270 buffer[i] = 0;
271 break;
272 }
273 i --;
274 }
275 }
276
277 void wxStripExtension(wxString& buffer)
278 {
279 size_t len = buffer.Length();
280 size_t i = len-1;
281 while (i > 0)
282 {
283 if (buffer.GetChar(i) == '.')
284 {
285 buffer = buffer.Left(i);
286 break;
287 }
288 i --;
289 }
290 }
291
292 // Destructive removal of /./ and /../ stuff
293 char *wxRealPath (char *path)
294 {
295 #ifdef __WXMSW__
296 static const char SEP = '\\';
297 Unix2DosFilename(path);
298 #else
299 static const char SEP = '/';
300 #endif
301 if (path[0] && path[1]) {
302 /* MATTHEW: special case "/./x" */
303 char *p;
304 if (path[2] == SEP && path[1] == '.')
305 p = &path[0];
306 else
307 p = &path[2];
308 for (; *p; p++)
309 {
310 if (*p == SEP)
311 {
312 if (p[1] == '.' && p[2] == '.' && (p[3] == SEP || p[3] == '\0'))
313 {
314 char *q;
315 for (q = p - 1; q >= path && *q != SEP; q--);
316 if (q[0] == SEP && (q[1] != '.' || q[2] != '.' || q[3] != SEP)
317 && (q - 1 <= path || q[-1] != SEP))
318 {
319 strcpy (q, p + 3);
320 if (path[0] == '\0')
321 {
322 path[0] = SEP;
323 path[1] = '\0';
324 }
325 #ifdef __WXMSW__
326 /* Check that path[2] is NULL! */
327 else if (path[1] == ':' && !path[2])
328 {
329 path[2] = SEP;
330 path[3] = '\0';
331 }
332 #endif
333 p = q - 1;
334 }
335 }
336 else if (p[1] == '.' && (p[2] == SEP || p[2] == '\0'))
337 strcpy (p, p + 2);
338 }
339 }
340 }
341 return path;
342 }
343
344 // Must be destroyed
345 char *wxCopyAbsolutePath(const wxString& filename)
346 {
347 if (filename == "")
348 return (char *) NULL;
349
350 if (! IsAbsolutePath(wxExpandPath(wxBuffer, filename))) {
351 char buf[_MAXPATHLEN];
352 buf[0] = '\0';
353 wxGetWorkingDirectory(buf, sizeof(buf)/sizeof(char));
354 char ch = buf[strlen(buf) - 1];
355 #ifdef __WXMSW__
356 if (ch != '\\' && ch != '/')
357 strcat(buf, "\\");
358 #else
359 if (ch != '/')
360 strcat(buf, "/");
361 #endif
362 strcat(buf, wxBuffer);
363 return copystring( wxRealPath(buf) );
364 }
365 return copystring( wxBuffer );
366 }
367
368 /*-
369 Handles:
370 ~/ => home dir
371 ~user/ => user's home dir
372 If the environment variable a = "foo" and b = "bar" then:
373 Unix:
374 $a => foo
375 $a$b => foobar
376 $a.c => foo.c
377 xxx$a => xxxfoo
378 ${a}! => foo!
379 $(b)! => bar!
380 \$a => \$a
381 MSDOS:
382 $a ==> $a
383 $(a) ==> foo
384 $(a)$b ==> foo$b
385 $(a)$(b)==> foobar
386 test.$$ ==> test.$$
387 */
388
389 /* input name in name, pathname output to buf. */
390
391 char *wxExpandPath(char *buf, const char *name)
392 {
393 register char *d, *s, *nm;
394 char lnm[_MAXPATHLEN];
395 int q;
396
397 // Some compilers don't like this line.
398 // const char trimchars[] = "\n \t";
399
400 char trimchars[4];
401 trimchars[0] = '\n';
402 trimchars[1] = ' ';
403 trimchars[2] = '\t';
404 trimchars[3] = 0;
405
406 #ifdef __WXMSW__
407 const char SEP = '\\';
408 #else
409 const char SEP = '/';
410 #endif
411 buf[0] = '\0';
412 if (name == NULL || *name == '\0')
413 return buf;
414 nm = copystring(name); // Make a scratch copy
415 char *nm_tmp = nm;
416
417 /* Skip leading whitespace and cr */
418 while (strchr((char *)trimchars, *nm) != NULL)
419 nm++;
420 /* And strip off trailing whitespace and cr */
421 s = nm + (q = strlen(nm)) - 1;
422 while (q-- && strchr((char *)trimchars, *s) != NULL)
423 *s = '\0';
424
425 s = nm;
426 d = lnm;
427 #ifdef __WXMSW__
428 q = FALSE;
429 #else
430 q = nm[0] == '\\' && nm[1] == '~';
431 #endif
432
433 /* Expand inline environment variables */
434 while ((*d++ = *s)) {
435 #ifndef __WXMSW__
436 if (*s == '\\') {
437 if ((*(d - 1) = *++s)) {
438 s++;
439 continue;
440 } else
441 break;
442 } else
443 #endif
444 #ifdef __WXMSW__
445 if (*s++ == '$' && (*s == '{' || *s == ')'))
446 #else
447 if (*s++ == '$')
448 #endif
449 {
450 register char *start = d;
451 register int braces = (*s == '{' || *s == '(');
452 register char *value;
453 while ((*d++ = *s))
454 if (braces ? (*s == '}' || *s == ')') : !(isalnum(*s) || *s == '_') )
455 break;
456 else
457 s++;
458 *--d = 0;
459 value = getenv(braces ? start + 1 : start);
460 if (value) {
461 for ((d = start - 1); (*d++ = *value++););
462 d--;
463 if (braces && *s)
464 s++;
465 }
466 }
467 }
468
469 /* Expand ~ and ~user */
470 nm = lnm;
471 s = "";
472 if (nm[0] == '~' && !q)
473 {
474 /* prefix ~ */
475 if (nm[1] == SEP || nm[1] == 0)
476 { /* ~/filename */
477 if ((s = wxGetUserHome("")) != NULL) {
478 if (*++nm)
479 nm++;
480 }
481 } else
482 { /* ~user/filename */
483 register char *nnm;
484 register char *home;
485 for (s = nm; *s && *s != SEP; s++);
486 int was_sep; /* MATTHEW: Was there a separator, or NULL? */
487 was_sep = (*s == SEP);
488 nnm = *s ? s + 1 : s;
489 *s = 0;
490 if ((home = wxGetUserHome(wxString(nm + 1))) == NULL) {
491 if (was_sep) /* replace only if it was there: */
492 *s = SEP;
493 s = "";
494 } else {
495 nm = nnm;
496 s = home;
497 }
498 }
499 }
500
501 d = buf;
502 if (s && *s) { /* MATTHEW: s could be NULL if user '~' didn't exist */
503 /* Copy home dir */
504 while ('\0' != (*d++ = *s++))
505 /* loop */;
506 // Handle root home
507 if (d - 1 > buf && *(d - 2) != SEP)
508 *(d - 1) = SEP;
509 }
510 s = nm;
511 while ((*d++ = *s++));
512
513 delete[] nm_tmp; // clean up alloc
514 /* Now clean up the buffer */
515 return wxRealPath(buf);
516 }
517
518
519 /* Contract Paths to be build upon an environment variable
520 component:
521
522 example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib
523
524 The call wxExpandPath can convert these back!
525 */
526 char *
527 wxContractPath (const wxString& filename, const wxString& envname, const wxString& user)
528 {
529 static char dest[_MAXPATHLEN];
530
531 if (filename == "")
532 return (char *) NULL;
533
534 strcpy (dest, WXSTRINGCAST filename);
535 #ifdef __WXMSW__
536 Unix2DosFilename(dest);
537 #endif
538
539 // Handle environment
540 char *val = (char *) NULL;
541 char *tcp = (char *) NULL;
542 if (envname != WXSTRINGCAST NULL && (val = getenv (WXSTRINGCAST envname)) != NULL &&
543 (tcp = strstr (dest, val)) != NULL)
544 {
545 strcpy (wxBuffer, tcp + strlen (val));
546 *tcp++ = '$';
547 *tcp++ = '{';
548 strcpy (tcp, WXSTRINGCAST envname);
549 strcat (tcp, "}");
550 strcat (tcp, wxBuffer);
551 }
552
553 // Handle User's home (ignore root homes!)
554 size_t len = 0;
555 if ((val = wxGetUserHome (user)) != NULL &&
556 (len = strlen(val)) > 2 &&
557 strncmp(dest, val, len) == 0)
558 {
559 strcpy(wxBuffer, "~");
560 if (user && *user)
561 strcat(wxBuffer, user);
562 #ifdef __WXMSW__
563 // strcat(wxBuffer, "\\");
564 #else
565 // strcat(wxBuffer, "/");
566 #endif
567 strcat(wxBuffer, dest + len);
568 strcpy (dest, wxBuffer);
569 }
570
571 return dest;
572 }
573
574 // Return just the filename, not the path
575 // (basename)
576 char *wxFileNameFromPath (char *path)
577 {
578 if (path)
579 {
580 register char *tcp;
581
582 tcp = path + strlen (path);
583 while (--tcp >= path)
584 {
585 if (*tcp == '/' || *tcp == '\\'
586 #ifdef __VMS__
587 || *tcp == ':' || *tcp == ']')
588 #else
589 )
590 #endif
591 return tcp + 1;
592 } /* while */
593 #ifdef __WXMSW__
594 if (isalpha (*path) && *(path + 1) == ':')
595 return path + 2;
596 #endif
597 }
598 return path;
599 }
600
601 wxString wxFileNameFromPath (const wxString& path1)
602 {
603 if (path1 != "")
604 {
605
606 char *path = WXSTRINGCAST path1 ;
607 register char *tcp;
608
609 tcp = path + strlen (path);
610 while (--tcp >= path)
611 {
612 if (*tcp == '/' || *tcp == '\\'
613 #ifdef __VMS__
614 || *tcp == ':' || *tcp == ']')
615 #else
616 )
617 #endif
618 return wxString(tcp + 1);
619 } /* while */
620 #ifdef __WXMSW__
621 if (isalpha (*path) && *(path + 1) == ':')
622 return wxString(path + 2);
623 #endif
624 }
625 return wxString("");
626 }
627
628 // Return just the directory, or NULL if no directory
629 char *
630 wxPathOnly (char *path)
631 {
632 if (path && *path)
633 {
634 static char buf[_MAXPATHLEN];
635
636 // Local copy
637 strcpy (buf, path);
638
639 int l = strlen(path);
640 bool done = FALSE;
641
642 int i = l - 1;
643
644 // Search backward for a backward or forward slash
645 while (!done && i > -1)
646 {
647 // ] is for VMS
648 if (path[i] == '/' || path[i] == '\\' || path[i] == ']')
649 {
650 done = TRUE;
651 #ifdef __VMS__
652 buf[i+1] = 0;
653 #else
654 buf[i] = 0;
655 #endif
656
657 return buf;
658 }
659 else i --;
660 }
661
662 #ifdef __WXMSW__
663 // Try Drive specifier
664 if (isalpha (buf[0]) && buf[1] == ':')
665 {
666 // A:junk --> A:. (since A:.\junk Not A:\junk)
667 buf[2] = '.';
668 buf[3] = '\0';
669 return buf;
670 }
671 #endif
672 }
673
674 return (char *) NULL;
675 }
676
677 // Return just the directory, or NULL if no directory
678 wxString wxPathOnly (const wxString& path)
679 {
680 if (path != "")
681 {
682 char buf[_MAXPATHLEN];
683
684 // Local copy
685 strcpy (buf, WXSTRINGCAST path);
686
687 int l = path.Length();
688 bool done = FALSE;
689
690 int i = l - 1;
691
692 // Search backward for a backward or forward slash
693 while (!done && i > -1)
694 {
695 // ] is for VMS
696 if (path[i] == '/' || path[i] == '\\' || path[i] == ']')
697 {
698 done = TRUE;
699 #ifdef __VMS__
700 buf[i+1] = 0;
701 #else
702 buf[i] = 0;
703 #endif
704
705 return wxString(buf);
706 }
707 else i --;
708 }
709
710 #ifdef __WXMSW__
711 // Try Drive specifier
712 if (isalpha (buf[0]) && buf[1] == ':')
713 {
714 // A:junk --> A:. (since A:.\junk Not A:\junk)
715 buf[2] = '.';
716 buf[3] = '\0';
717 return wxString(buf);
718 }
719 #endif
720 }
721
722 return wxString("");
723 }
724
725 // Utility for converting delimiters in DOS filenames to UNIX style
726 // and back again - or we get nasty problems with delimiters.
727 // Also, convert to lower case, since case is significant in UNIX.
728
729 void
730 wxDos2UnixFilename (char *s)
731 {
732 if (s)
733 while (*s)
734 {
735 if (*s == '\\')
736 *s = '/';
737 #ifdef __WXMSW__
738 else
739 *s = wxToLower (*s); // Case INDEPENDENT
740 #endif
741 s++;
742 }
743 }
744
745 void
746 #ifdef __WXMSW__
747 wxUnix2DosFilename (char *s)
748 #else
749 wxUnix2DosFilename (char *WXUNUSED(s))
750 #endif
751 {
752 // Yes, I really mean this to happen under DOS only! JACS
753 #ifdef __WXMSW__
754 if (s)
755 while (*s)
756 {
757 if (*s == '/')
758 *s = '\\';
759 s++;
760 }
761 #endif
762 }
763
764 // Concatenate two files to form third
765 bool
766 wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& file3)
767 {
768 char *outfile = wxGetTempFileName("cat");
769
770 FILE *fp1 = (FILE *) NULL;
771 FILE *fp2 = (FILE *) NULL;
772 FILE *fp3 = (FILE *) NULL;
773 // Open the inputs and outputs
774 if ((fp1 = fopen (WXSTRINGCAST file1, "rb")) == NULL ||
775 (fp2 = fopen (WXSTRINGCAST file2, "rb")) == NULL ||
776 (fp3 = fopen (outfile, "wb")) == NULL)
777 {
778 if (fp1)
779 fclose (fp1);
780 if (fp2)
781 fclose (fp2);
782 if (fp3)
783 fclose (fp3);
784 return FALSE;
785 }
786
787 int ch;
788 while ((ch = getc (fp1)) != EOF)
789 (void) putc (ch, fp3);
790 fclose (fp1);
791
792 while ((ch = getc (fp2)) != EOF)
793 (void) putc (ch, fp3);
794 fclose (fp2);
795
796 fclose (fp3);
797 bool result = wxRenameFile(outfile, file3);
798 delete[] outfile;
799 return result;
800 }
801
802 // Copy files
803 bool
804 wxCopyFile (const wxString& file1, const wxString& file2)
805 {
806 FILE *fd1;
807 FILE *fd2;
808 int ch;
809
810 if ((fd1 = fopen (WXSTRINGCAST file1, "rb")) == NULL)
811 return FALSE;
812 if ((fd2 = fopen (WXSTRINGCAST file2, "wb")) == NULL)
813 {
814 fclose (fd1);
815 return FALSE;
816 }
817
818 while ((ch = getc (fd1)) != EOF)
819 (void) putc (ch, fd2);
820
821 fclose (fd1);
822 fclose (fd2);
823 return TRUE;
824 }
825
826 bool
827 wxRenameFile (const wxString& file1, const wxString& file2)
828 {
829 // Normal system call
830 if (0 == rename (WXSTRINGCAST file1, WXSTRINGCAST file2))
831 return TRUE;
832 // Try to copy
833 if (wxCopyFile(file1, file2)) {
834 wxRemoveFile(file1);
835 return TRUE;
836 }
837 // Give up
838 return FALSE;
839 }
840
841 bool wxRemoveFile(const wxString& file)
842 {
843 #if defined(_MSC_VER) || defined(__BORLANDC__)
844 int flag = remove(WXSTRINGCAST file);
845 #else
846 int flag = unlink(WXSTRINGCAST file);
847 #endif
848 return (flag == 0) ;
849 }
850
851 bool wxMkdir(const wxString& dir)
852 {
853 #if defined(__WXSTUBS__)
854 return FALSE;
855 #elif defined(__VMS__)
856 return FALSE;
857 #elif (defined(__GNUWIN32__) && !defined(__MINGW32__)) || !defined(__WXMSW__)
858 return (mkdir (WXSTRINGCAST dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0);
859 #else
860 return (mkdir(WXSTRINGCAST dir) == 0);
861 #endif
862 }
863
864 bool wxRmdir(const wxString& dir, int WXUNUSED(flags))
865 {
866 #ifdef __VMS__
867 return FALSE;
868 #else
869 return (rmdir(WXSTRINGCAST dir) == 0);
870 #endif
871 }
872
873 #if 0
874 bool wxDirExists(const wxString& dir)
875 {
876 #ifdef __VMS__
877 return FALSE;
878 #elif !defined(__WXMSW__)
879 struct stat sbuf;
880 return (stat(dir, &sbuf) != -1) && S_ISDIR(sbuf.st_mode) ? TRUE : FALSE;
881 #else
882
883 /* MATTHEW: [6] Always use same code for Win32, call FindClose */
884 #if defined(__WIN32__)
885 WIN32_FIND_DATA fileInfo;
886 #else
887 #ifdef __BORLANDC__
888 struct ffblk fileInfo;
889 #else
890 struct find_t fileInfo;
891 #endif
892 #endif
893
894 #if defined(__WIN32__)
895 HANDLE h = FindFirstFile((LPTSTR) WXSTRINGCAST dir,(LPWIN32_FIND_DATA)&fileInfo);
896
897 if (h==INVALID_HANDLE_VALUE)
898 return FALSE;
899 else {
900 FindClose(h);
901 return ((fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
902 }
903 #else
904 // In Borland findfirst has a different argument
905 // ordering from _dos_findfirst. But _dos_findfirst
906 // _should_ be ok in both MS and Borland... why not?
907 #ifdef __BORLANDC__
908 return ((findfirst(WXSTRINGCAST dir, &fileInfo, _A_SUBDIR) == 0 && (fileInfo.ff_attrib & _A_SUBDIR) != 0));
909 #else
910 return (((_dos_findfirst(WXSTRINGCAST dir, _A_SUBDIR, &fileInfo) == 0) && (fileInfo.attrib & _A_SUBDIR)) != 0);
911 #endif
912 #endif
913
914 #endif
915 }
916
917 #endif
918
919 // does the path exists? (may have or not '/' or '\\' at the end)
920 bool wxPathExists(const char *pszPathName)
921 {
922 // Windows API returns -1 from stat for "c:\dir\" if "c:\dir" exists
923 // OTOH, we should change "d:" to "d:\" and leave "\" as is.
924 wxString strPath(pszPathName);
925 if ( wxEndsWithPathSeparator(pszPathName) && pszPathName[1] != '\0' )
926 strPath.Last() = '\0';
927
928 struct stat st;
929 return stat(strPath, &st) == 0 && (st.st_mode & S_IFDIR);
930 }
931
932 // Get a temporary filename, opening and closing the file.
933 char *wxGetTempFileName(const wxString& prefix, char *buf)
934 {
935 #ifdef __WINDOWS__
936
937 #ifndef __WIN32__
938 char tmp[144];
939 ::GetTempFileName(0, WXSTRINGCAST prefix, 0, tmp);
940 #else
941 char tmp[MAX_PATH];
942 char tmpPath[MAX_PATH];
943 ::GetTempPath(MAX_PATH, tmpPath);
944 ::GetTempFileName(tmpPath, WXSTRINGCAST prefix, 0, tmp);
945 #endif
946 if (buf) strcpy(buf, tmp);
947 else buf = copystring(tmp);
948 return buf;
949
950 #else
951 static short last_temp = 0; // cache last to speed things a bit
952 // At most 1000 temp files to a process! We use a ring count.
953 char tmp[100];
954
955 for (short suffix = last_temp + 1; suffix != last_temp; ++suffix %= 1000)
956 {
957 sprintf (tmp, "/tmp/%s%d.%03x", WXSTRINGCAST prefix, (int) getpid (), (int) suffix);
958 if (!wxFileExists( tmp ))
959 {
960 // Touch the file to create it (reserve name)
961 FILE *fd = fopen (tmp, "w");
962 if (fd)
963 fclose (fd);
964 last_temp = suffix;
965 if (buf)
966 strcpy( buf, tmp);
967 else
968 buf = copystring( tmp );
969 return buf;
970 }
971 }
972 cerr << _("wxWindows: error finding temporary file name.\n");
973 if (buf) buf[0] = 0;
974 return (char *) NULL;
975 #endif
976 }
977
978 // Get first file name matching given wild card.
979
980 #ifdef __UNIX__
981
982 // Get first file name matching given wild card.
983 // Flags are reserved for future use.
984
985 #ifndef __VMS__
986 static DIR *wxDirStream = (DIR *) NULL;
987 static char *wxFileSpec = (char *) NULL;
988 static int wxFindFileFlags = 0;
989 #endif
990
991 char *wxFindFirstFile(const char *spec, int flags)
992 {
993 #ifndef __VMS__
994 if (wxDirStream)
995 closedir(wxDirStream); // edz 941103: better housekeping
996
997 wxFindFileFlags = flags;
998
999 if (wxFileSpec)
1000 delete[] wxFileSpec;
1001 wxFileSpec = copystring(spec);
1002
1003 // Find path only so we can concatenate
1004 // found file onto path
1005 char *p = wxPathOnly(wxFileSpec);
1006
1007 /* MATTHEW: special case: path is really "/" */
1008 if (p && !*p && *wxFileSpec == '/')
1009 p = "/";
1010 /* MATTHEW: p is NULL => Local directory */
1011 if (!p)
1012 p = ".";
1013
1014 if ((wxDirStream=opendir(p))==NULL)
1015 return (char *) NULL;
1016
1017 /* MATTHEW: [5] wxFindNextFile can do the rest of the work */
1018 return wxFindNextFile();
1019 #endif
1020 // ifndef __VMS__
1021 return (char *) NULL;
1022 }
1023
1024 char *wxFindNextFile(void)
1025 {
1026 #ifndef __VMS__
1027 static char buf[400];
1028
1029 /* MATTHEW: [2] Don't crash if we read too many times */
1030 if (!wxDirStream)
1031 return (char *) NULL;
1032
1033 // Find path only so we can concatenate
1034 // found file onto path
1035 char *p = wxPathOnly(wxFileSpec);
1036 char *n = wxFileNameFromPath(wxFileSpec);
1037
1038 /* MATTHEW: special case: path is really "/" */
1039 if (p && !*p && *wxFileSpec == '/')
1040 p = "/";
1041
1042 // Do the reading
1043 struct dirent *nextDir;
1044 for (nextDir = readdir(wxDirStream); nextDir != NULL; nextDir = readdir(wxDirStream))
1045 {
1046
1047 /* MATTHEW: [5] Only return "." and ".." when they match, and only return
1048 directories when flags & wxDIR */
1049 if (wxMatchWild(n, nextDir->d_name)) {
1050 bool isdir;
1051
1052 buf[0] = 0;
1053 if (p && *p) {
1054 strcpy(buf, p);
1055 if (strcmp(p, "/") != 0)
1056 strcat(buf, "/");
1057 }
1058 strcat(buf, nextDir->d_name);
1059
1060 if ((strcmp(nextDir->d_name, ".") == 0) ||
1061 (strcmp(nextDir->d_name, "..") == 0)) {
1062 if (wxFindFileFlags && !(wxFindFileFlags & wxDIR))
1063 continue;
1064 isdir = TRUE;
1065 } else
1066 isdir = wxDirExists(buf);
1067
1068 if (!wxFindFileFlags
1069 || ((wxFindFileFlags & wxDIR) && isdir)
1070 || ((wxFindFileFlags & wxFILE) && !isdir))
1071 return buf;
1072 }
1073 }
1074 closedir(wxDirStream);
1075 wxDirStream = (DIR *) NULL;
1076 #endif
1077 // ifndef __VMS__
1078
1079 return (char *) NULL;
1080 }
1081
1082 #elif defined(__WXMSW__)
1083
1084 #ifdef __WIN32__
1085 HANDLE wxFileStrucHandle = INVALID_HANDLE_VALUE;
1086 WIN32_FIND_DATA wxFileStruc;
1087 #else
1088 #ifdef __BORLANDC__
1089 static struct ffblk wxFileStruc;
1090 #else
1091 static struct _find_t wxFileStruc;
1092 #endif
1093 #endif
1094 static wxString wxFileSpec = "";
1095 static int wxFindFileFlags;
1096
1097 char *wxFindFirstFile(const char *spec, int flags)
1098 {
1099 wxFileSpec = spec;
1100 wxFindFileFlags = flags; /* MATTHEW: [5] Remember flags */
1101
1102 // Find path only so we can concatenate
1103 // found file onto path
1104 wxString path1(wxFileSpec);
1105 char *p = wxPathOnly(WXSTRINGCAST path1);
1106 if (p && (strlen(p) > 0))
1107 strcpy(wxBuffer, p);
1108 else
1109 wxBuffer[0] = 0;
1110
1111 #ifdef __WIN32__
1112 if (wxFileStrucHandle != INVALID_HANDLE_VALUE)
1113 FindClose(wxFileStrucHandle);
1114
1115 wxFileStrucHandle = ::FindFirstFile(WXSTRINGCAST spec, &wxFileStruc);
1116
1117 if (wxFileStrucHandle == INVALID_HANDLE_VALUE)
1118 return NULL;
1119
1120 bool isdir = !!(wxFileStruc.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1121
1122 if (isdir && !(flags & wxDIR))
1123 return wxFindNextFile();
1124 else if (!isdir && flags && !(flags & wxFILE))
1125 return wxFindNextFile();
1126
1127 if (wxBuffer[0] != 0)
1128 strcat(wxBuffer, "\\");
1129 strcat(wxBuffer, wxFileStruc.cFileName);
1130 return wxBuffer;
1131 #else
1132
1133 int flag = _A_NORMAL;
1134 if (flags & wxDIR) /* MATTHEW: [5] Use & */
1135 flag = _A_SUBDIR;
1136
1137 #ifdef __BORLANDC__
1138 if (findfirst(WXSTRINGCAST spec, &wxFileStruc, flag) == 0)
1139 #else
1140 if (_dos_findfirst(WXSTRINGCAST spec, flag, &wxFileStruc) == 0)
1141 #endif
1142 {
1143 /* MATTHEW: [5] Check directory flag */
1144 char attrib;
1145
1146 #ifdef __BORLANDC__
1147 attrib = wxFileStruc.ff_attrib;
1148 #else
1149 attrib = wxFileStruc.attrib;
1150 #endif
1151
1152 if (attrib & _A_SUBDIR) {
1153 if (!(wxFindFileFlags & wxDIR))
1154 return wxFindNextFile();
1155 } else if (wxFindFileFlags && !(wxFindFileFlags & wxFILE))
1156 return wxFindNextFile();
1157
1158 if (wxBuffer[0] != 0)
1159 strcat(wxBuffer, "\\");
1160
1161 #ifdef __BORLANDC__
1162 strcat(wxBuffer, wxFileStruc.ff_name);
1163 #else
1164 strcat(wxBuffer, wxFileStruc.name);
1165 #endif
1166 return wxBuffer;
1167 }
1168 else
1169 return NULL;
1170 #endif // __WIN32__
1171 }
1172
1173 char *wxFindNextFile(void)
1174 {
1175 // Find path only so we can concatenate
1176 // found file onto path
1177 wxString p2(wxFileSpec);
1178 char *p = wxPathOnly(WXSTRINGCAST p2);
1179 if (p && (strlen(p) > 0))
1180 strcpy(wxBuffer, p);
1181 else
1182 wxBuffer[0] = 0;
1183
1184 try_again:
1185
1186 #ifdef __WIN32__
1187 if (wxFileStrucHandle == INVALID_HANDLE_VALUE)
1188 return NULL;
1189
1190 bool success = (FindNextFile(wxFileStrucHandle, &wxFileStruc) != 0);
1191 if (!success) {
1192 FindClose(wxFileStrucHandle);
1193 wxFileStrucHandle = INVALID_HANDLE_VALUE;
1194 return NULL;
1195 }
1196
1197 bool isdir = !!(wxFileStruc.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1198
1199 if (isdir && !(wxFindFileFlags & wxDIR))
1200 goto try_again;
1201 else if (!isdir && wxFindFileFlags && !(wxFindFileFlags & wxFILE))
1202 goto try_again;
1203
1204 if (wxBuffer[0] != 0)
1205 strcat(wxBuffer, "\\");
1206 strcat(wxBuffer, wxFileStruc.cFileName);
1207 return wxBuffer;
1208 #else
1209
1210 #ifdef __BORLANDC__
1211 if (findnext(&wxFileStruc) == 0)
1212 #else
1213 if (_dos_findnext(&wxFileStruc) == 0)
1214 #endif
1215 {
1216 /* MATTHEW: [5] Check directory flag */
1217 char attrib;
1218
1219 #ifdef __BORLANDC__
1220 attrib = wxFileStruc.ff_attrib;
1221 #else
1222 attrib = wxFileStruc.attrib;
1223 #endif
1224
1225 if (attrib & _A_SUBDIR) {
1226 if (!(wxFindFileFlags & wxDIR))
1227 goto try_again;
1228 } else if (wxFindFileFlags && !(wxFindFileFlags & wxFILE))
1229 goto try_again;
1230
1231
1232 if (wxBuffer[0] != 0)
1233 strcat(wxBuffer, "\\");
1234 #ifdef __BORLANDC__
1235 strcat(wxBuffer, wxFileStruc.ff_name);
1236 #else
1237 strcat(wxBuffer, wxFileStruc.name);
1238 #endif
1239 return wxBuffer;
1240 }
1241 else
1242 return NULL;
1243 #endif
1244 }
1245
1246 #endif
1247 // __WXMSW__
1248
1249 // Get current working directory.
1250 // If buf is NULL, allocates space using new, else
1251 // copies into buf.
1252 char *wxGetWorkingDirectory(char *buf, int sz)
1253 {
1254 if (!buf)
1255 buf = new char[sz+1];
1256 #ifdef _MSC_VER
1257 if (_getcwd(buf, sz) == NULL) {
1258 #else
1259 if (getcwd(buf, sz) == NULL) {
1260 #endif
1261 buf[0] = '.';
1262 buf[1] = '\0';
1263 }
1264 return buf;
1265 }
1266
1267 bool wxSetWorkingDirectory(const wxString& d)
1268 {
1269 #ifdef __UNIX__
1270 return (chdir(d) == 0);
1271 #elif defined(__WINDOWS__)
1272
1273 #ifdef __WIN32__
1274 return (bool)(SetCurrentDirectory(d) != 0);
1275 #else
1276 // Must change drive, too.
1277 bool isDriveSpec = ((strlen(d) > 1) && (d[1] == ':'));
1278 if (isDriveSpec)
1279 {
1280 char firstChar = d[0];
1281
1282 // To upper case
1283 if (firstChar > 90)
1284 firstChar = firstChar - 32;
1285
1286 // To a drive number
1287 unsigned int driveNo = firstChar - 64;
1288 if (driveNo > 0)
1289 {
1290 unsigned int noDrives;
1291 _dos_setdrive(driveNo, &noDrives);
1292 }
1293 }
1294 bool success = (chdir(WXSTRINGCAST d) == 0);
1295
1296 return success;
1297 #endif
1298
1299 #endif
1300 }
1301
1302 bool wxEndsWithPathSeparator(const char *pszFileName)
1303 {
1304 size_t len = Strlen(pszFileName);
1305 if ( len == 0 )
1306 return FALSE;
1307 else
1308 return wxIsPathSeparator(pszFileName[len - 1]);
1309 }
1310
1311 // find a file in a list of directories, returns false if not found
1312 bool wxFindFileInPath(wxString *pStr, const char *pszPath, const char *pszFile)
1313 {
1314 // we assume that it's not empty
1315 wxCHECK_MSG( !IsEmpty(pszFile), FALSE,
1316 _("empty file name in wxFindFileInPath"));
1317
1318 // skip path separator in the beginning of the file name if present
1319 if ( wxIsPathSeparator(*pszFile) )
1320 pszFile++;
1321
1322 // copy the path (strtok will modify it)
1323 char *szPath = new char[strlen(pszPath) + 1];
1324 strcpy(szPath, pszPath);
1325
1326 wxString strFile;
1327 char *pc;
1328 for ( pc = strtok(szPath, PATH_SEP); pc; pc = strtok((char *) NULL, PATH_SEP) ) {
1329 // search for the file in this directory
1330 strFile = pc;
1331 if ( !wxEndsWithPathSeparator(pc) )
1332 strFile += FILE_SEP_PATH;
1333 strFile += pszFile;
1334
1335 if ( FileExists(strFile) ) {
1336 *pStr = strFile;
1337 break;
1338 }
1339 }
1340
1341 delete [] szPath;
1342
1343 return pc != NULL; // if true => we breaked from the loop
1344 }
1345
1346 void WXDLLEXPORT wxSplitPath(const char *pszFileName,
1347 wxString *pstrPath,
1348 wxString *pstrName,
1349 wxString *pstrExt)
1350 {
1351 wxCHECK_RET( pszFileName, _("NULL file name in wxSplitPath") );
1352
1353 const char *pDot = strrchr(pszFileName, FILE_SEP_EXT);
1354 const char *pSepUnix = strrchr(pszFileName, FILE_SEP_PATH_UNIX);
1355 const char *pSepDos = strrchr(pszFileName, FILE_SEP_PATH_DOS);
1356
1357 // take the last of the two
1358 size_t nPosUnix = pSepUnix ? pSepUnix - pszFileName : 0;
1359 size_t nPosDos = pSepDos ? pSepDos - pszFileName : 0;
1360 if ( nPosDos > nPosUnix )
1361 nPosUnix = nPosDos;
1362 // size_t nLen = Strlen(pszFileName);
1363
1364 if ( pstrPath )
1365 *pstrPath = wxString(pszFileName, nPosUnix);
1366 if ( pDot ) {
1367 size_t nPosDot = pDot - pszFileName;
1368 if ( pstrName )
1369 *pstrName = wxString(pszFileName + nPosUnix + 1, nPosDot - nPosUnix);
1370 if ( pstrExt )
1371 *pstrExt = wxString(pszFileName + nPosDot + 1);
1372 }
1373 else {
1374 if ( pstrName )
1375 *pstrName = wxString(pszFileName + nPosUnix + 1);
1376 if ( pstrExt )
1377 pstrExt->Empty();
1378 }
1379 }
1380
1381 //------------------------------------------------------------------------
1382 // wild character routines
1383 //------------------------------------------------------------------------
1384
1385 bool wxIsWild( const wxString& pattern )
1386 {
1387 wxString tmp = pattern;
1388 char *pat = WXSTRINGCAST(tmp);
1389 while (*pat) {
1390 switch (*pat++) {
1391 case '?': case '*': case '[': case '{':
1392 return TRUE;
1393 case '\\':
1394 if (!*pat++)
1395 return FALSE;
1396 }
1397 }
1398 return FALSE;
1399 };
1400
1401 bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special )
1402 #ifdef HAVE_FNMATCH_H
1403 {
1404 if(dot_special)
1405 return fnmatch(pat.c_str(), text.c_str(), FNM_PERIOD) == 0;
1406 else
1407 return fnmatch(pat.c_str(), text.c_str(), 0) == 0;
1408 }
1409 #else
1410
1411 #pragma error Broken implementation of wxMatchWild() -- needs fixing!
1412 /*
1413 * WARNING: this code is broken!
1414 */
1415 {
1416 wxString tmp1 = pat;
1417 char *pattern = WXSTRINGCAST(tmp1);
1418 wxString tmp2 = text;
1419 char *str = WXSTRINGCAST(tmp2);
1420 char c;
1421 char *cp;
1422 bool done = FALSE, ret_code, ok;
1423 // Below is for vi fans
1424 const char OB = '{', CB = '}';
1425
1426 // dot_special means '.' only matches '.'
1427 if (dot_special && *str == '.' && *pattern != *str)
1428 return FALSE;
1429
1430 while ((*pattern != '\0') && (!done)
1431 && (((*str=='\0')&&((*pattern==OB)||(*pattern=='*')))||(*str!='\0'))) {
1432 switch (*pattern) {
1433 case '\\':
1434 pattern++;
1435 if (*pattern != '\0')
1436 pattern++;
1437 break;
1438 case '*':
1439 pattern++;
1440 ret_code = FALSE;
1441 while ((*str!='\0')
1442 && (!(ret_code=wxMatchWild(pattern, str++, FALSE))))
1443 /*loop*/;
1444 if (ret_code) {
1445 while (*str != '\0')
1446 str++;
1447 while (*pattern != '\0')
1448 pattern++;
1449 }
1450 break;
1451 case '[':
1452 pattern++;
1453 repeat:
1454 if ((*pattern == '\0') || (*pattern == ']')) {
1455 done = TRUE;
1456 break;
1457 }
1458 if (*pattern == '\\') {
1459 pattern++;
1460 if (*pattern == '\0') {
1461 done = TRUE;
1462 break;
1463 }
1464 }
1465 if (*(pattern + 1) == '-') {
1466 c = *pattern;
1467 pattern += 2;
1468 if (*pattern == ']') {
1469 done = TRUE;
1470 break;
1471 }
1472 if (*pattern == '\\') {
1473 pattern++;
1474 if (*pattern == '\0') {
1475 done = TRUE;
1476 break;
1477 }
1478 }
1479 if ((*str < c) || (*str > *pattern)) {
1480 pattern++;
1481 goto repeat;
1482 }
1483 } else if (*pattern != *str) {
1484 pattern++;
1485 goto repeat;
1486 }
1487 pattern++;
1488 while ((*pattern != ']') && (*pattern != '\0')) {
1489 if ((*pattern == '\\') && (*(pattern + 1) != '\0'))
1490 pattern++;
1491 pattern++;
1492 }
1493 if (*pattern != '\0') {
1494 pattern++, str++;
1495 }
1496 break;
1497 case '?':
1498 pattern++;
1499 str++;
1500 break;
1501 case OB:
1502 pattern++;
1503 while ((*pattern != CB) && (*pattern != '\0')) {
1504 cp = str;
1505 ok = TRUE;
1506 while (ok && (*cp != '\0') && (*pattern != '\0')
1507 && (*pattern != ',') && (*pattern != CB)) {
1508 if (*pattern == '\\')
1509 pattern++;
1510 ok = (*pattern++ == *cp++);
1511 }
1512 if (*pattern == '\0') {
1513 ok = FALSE;
1514 done = TRUE;
1515 break;
1516 } else if (ok) {
1517 str = cp;
1518 while ((*pattern != CB) && (*pattern != '\0')) {
1519 if (*++pattern == '\\') {
1520 if (*++pattern == CB)
1521 pattern++;
1522 }
1523 }
1524 } else {
1525 while (*pattern!=CB && *pattern!=',' && *pattern!='\0') {
1526 if (*++pattern == '\\') {
1527 if (*++pattern == CB || *pattern == ',')
1528 pattern++;
1529 }
1530 }
1531 }
1532 if (*pattern != '\0')
1533 pattern++;
1534 }
1535 break;
1536 default:
1537 if (*str == *pattern) {
1538 str++, pattern++;
1539 } else {
1540 done = TRUE;
1541 }
1542 }
1543 }
1544 while (*pattern == '*')
1545 pattern++;
1546 return ((*str == '\0') && (*pattern == '\0'));
1547 };
1548 #endif
1549