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