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