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