]> git.saurik.com Git - wxWidgets.git/blame - src/common/filefn.cpp
*** empty log message ***
[wxWidgets.git] / src / common / filefn.cpp
CommitLineData
c801d85f
KB
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"
1a5a8367 29#include <wx/intl.h>
c801d85f
KB
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
aad5220b 44#ifdef __UNIX__
c801d85f
KB
45#include <unistd.h>
46#include <dirent.h>
aad5220b 47#endif
c801d85f 48
34138703 49#ifdef __WINDOWS__
c801d85f
KB
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
dfcb1ae0
KB
73#include "wx/setup.h"
74#ifdef HAVE_FNMATCH_H
75#include "fnmatch.h"
76#endif
77
34138703 78#ifdef __WINDOWS__
c801d85f
KB
79#include "windows.h"
80#endif
81
82#define _MAXPATHLEN 500
83
84#if !USE_SHARED_LIBRARY
85IMPLEMENT_DYNAMIC_CLASS(wxPathList, wxStringList)
86#endif
87
88extern char *wxBuffer;
89
90void 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
96void wxPathList::AddEnvList (const wxString& envVariable)
97{
98 static const char PATH_TOKS[] =
34138703 99#ifdef __WINDOWS__
c801d85f
KB
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 {
c67daf87 116 if ((token = strtok ((char *) NULL, PATH_TOKS)) != NULL)
c801d85f
KB
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.
127void 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
138bool 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 (
34138703 144#if defined(__WINDOWS__) || defined(__VMS__)
c801d85f
KB
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
157wxString 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);
34138703 175#ifdef __WINDOWS__
c801d85f
KB
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
187wxString 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 {
34138703 202#ifdef __WINDOWS__
c801d85f
KB
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
214bool
215wxFileExists (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?
227bool 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
236bool
237wxIsAbsolutePath (const wxString& filename)
238{
239 if (filename != "")
240 {
241 if (filename[0] == '/'
242#ifdef __VMS__
243 || (filename[0] == '[' && filename[1] != '.')
244#endif
34138703 245#ifdef __WINDOWS__
c801d85f
KB
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
261void 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
47fa7969
JS
276void 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
c801d85f
KB
291// Destructive removal of /./ and /../ stuff
292char *wxRealPath (char *path)
293{
2049ba38 294#ifdef __WXMSW__
c801d85f
KB
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 }
2049ba38 324#ifdef __WXMSW__
c801d85f
KB
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
344char *wxCopyAbsolutePath(const wxString& filename)
345{
346 if (filename == "")
c67daf87 347 return (char *) NULL;
c801d85f
KB
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];
2049ba38 354#ifdef __WXMSW__
c801d85f
KB
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
390char *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
2049ba38 405#ifdef __WXMSW__
c801d85f
KB
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;
2049ba38 426#ifdef __WXMSW__
c801d85f
KB
427 q = FALSE;
428#else
429 q = nm[0] == '\\' && nm[1] == '~';
430#endif
431
432 /* Expand inline environment variables */
433 while ((*d++ = *s)) {
2049ba38 434#ifndef __WXMSW__
c801d85f
KB
435 if (*s == '\\') {
436 if ((*(d - 1) = *++s)) {
437 s++;
438 continue;
439 } else
440 break;
441 } else
442#endif
2049ba38 443#ifdef __WXMSW__
c801d85f
KB
444 if (*s++ == '$' && (*s == '{' || *s == ')'))
445#else
446 if (*s++ == '$')
447#endif
448 {
449 register char *start = d;
c67daf87 450 register int braces = (*s == '{' || *s == '(');
c801d85f
KB
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 */
525char *
526wxContractPath (const wxString& filename, const wxString& envname, const wxString& user)
527{
528 static char dest[_MAXPATHLEN];
529
530 if (filename == "")
c67daf87 531 return (char *) NULL;
c801d85f
KB
532
533 strcpy (dest, WXSTRINGCAST filename);
2049ba38 534#ifdef __WXMSW__
c801d85f
KB
535 Unix2DosFilename(dest);
536#endif
537
538 // Handle environment
c67daf87
UR
539 char *val = (char *) NULL;
540 char *tcp = (char *) NULL;
541 if (envname != WXSTRINGCAST NULL && (val = getenv (WXSTRINGCAST envname)) != NULL &&
c801d85f
KB
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);
2049ba38 561#ifdef __WXMSW__
c801d85f
KB
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)
575char *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 */
2049ba38 592#ifdef __WXMSW__
c801d85f
KB
593 if (isalpha (*path) && *(path + 1) == ':')
594 return path + 2;
595#endif
596 }
597 return path;
598}
599
600wxString 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 */
2049ba38 619#ifdef __WXMSW__
c801d85f
KB
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
628char *
629wxPathOnly (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
2049ba38 661#ifdef __WXMSW__
c801d85f
KB
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
c67daf87 673 return (char *) NULL;
c801d85f
KB
674}
675
676// Return just the directory, or NULL if no directory
677wxString 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
2049ba38 709#ifdef __WXMSW__
c801d85f
KB
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
728void
729wxDos2UnixFilename (char *s)
730{
731 if (s)
732 while (*s)
733 {
734 if (*s == '\\')
735 *s = '/';
2049ba38 736#ifdef __WXMSW__
c801d85f
KB
737 else
738 *s = wxToLower (*s); // Case INDEPENDENT
739#endif
740 s++;
741 }
742}
743
744void
46dc76ba 745#ifdef __WXMSW__
aad5220b 746wxUnix2DosFilename (char *s)
46dc76ba
RR
747#else
748wxUnix2DosFilename (char *WXUNUSED(s))
749#endif
c801d85f
KB
750{
751// Yes, I really mean this to happen under DOS only! JACS
2049ba38 752#ifdef __WXMSW__
c801d85f
KB
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
764bool
765wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& file3)
766{
767 char *outfile = wxGetTempFileName("cat");
768
c67daf87
UR
769 FILE *fp1 = (FILE *) NULL;
770 FILE *fp2 = (FILE *) NULL;
771 FILE *fp3 = (FILE *) NULL;
c801d85f
KB
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
802bool
803wxCopyFile (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
825bool
826wxRenameFile (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
840bool 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
850bool wxMkdir(const wxString& dir)
851{
c856c750
JS
852#if defined(__WXSTUBS__)
853 return FALSE;
854#elif defined(__VMS__)
c801d85f 855 return FALSE;
2049ba38 856#elif (defined(__GNUWIN32__) && !defined(__MINGW32__)) || !defined(__WXMSW__)
c801d85f
KB
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
863bool 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
873bool wxDirExists(const wxString& dir)
874{
875#ifdef __VMS__
876 return FALSE;
2049ba38 877#elif !defined(__WXMSW__)
c801d85f
KB
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)
919bool 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.
932char *wxGetTempFileName(const wxString& prefix, char *buf)
933{
34138703 934#ifdef __WINDOWS__
c801d85f
KB
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 }
1a5a8367 971 cerr << _("wxWindows: error finding temporary file name.\n");
c801d85f 972 if (buf) buf[0] = 0;
c67daf87 973 return (char *) NULL;
c801d85f
KB
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__
c67daf87
UR
985static DIR *wxDirStream = (DIR *) NULL;
986static char *wxFileSpec = (char *) NULL;
c801d85f
KB
987static int wxFindFileFlags = 0;
988#endif
989
990char *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)
c67daf87 1014 return (char *) NULL;
c801d85f
KB
1015
1016 /* MATTHEW: [5] wxFindNextFile can do the rest of the work */
1017 return wxFindNextFile();
1018#endif
1019 // ifndef __VMS__
c67daf87 1020 return (char *) NULL;
c801d85f
KB
1021}
1022
1023char *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)
c67daf87 1030 return (char *) NULL;
c801d85f
KB
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);
c67daf87 1074 wxDirStream = (DIR *) NULL;
c801d85f
KB
1075#endif
1076 // ifndef __VMS__
1077
c67daf87 1078 return (char *) NULL;
c801d85f
KB
1079}
1080
2049ba38 1081#elif defined(__WXMSW__)
c801d85f
KB
1082
1083#ifdef __WIN32__
1084HANDLE wxFileStrucHandle = INVALID_HANDLE_VALUE;
1085WIN32_FIND_DATA wxFileStruc;
1086#else
1087#ifdef __BORLANDC__
1088static struct ffblk wxFileStruc;
1089#else
1090static struct _find_t wxFileStruc;
1091#endif
1092#endif
1093static wxString wxFileSpec = "";
1094static int wxFindFileFlags;
1095
1311c7a9 1096char *wxFindFirstFile(const char *spec, int flags)
c801d85f
KB
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
1172char *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
2049ba38 1246 // __WXMSW__
c801d85f
KB
1247
1248// Get current working directory.
1249// If buf is NULL, allocates space using new, else
1250// copies into buf.
1251char *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
1266bool wxSetWorkingDirectory(const wxString& d)
1267{
1268#ifdef __UNIX__
1269 return (chdir(d) == 0);
34138703 1270#elif defined(__WINDOWS__)
c801d85f
KB
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
1301bool 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
1311bool wxFindFileInPath(wxString *pStr, const char *pszPath, const char *pszFile)
1312{
1313 // we assume that it's not empty
1311c7a9 1314 wxCHECK_MSG( !IsEmpty(pszFile), FALSE,
1a5a8367 1315 _("empty file name in wxFindFileInPath"));
c801d85f
KB
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;
c67daf87 1327 for ( pc = strtok(szPath, PATH_SEP); pc; pc = strtok((char *) NULL, PATH_SEP) ) {
c801d85f
KB
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
3826db3e
VZ
1345void WXDLLEXPORT wxSplitPath(const char *pszFileName,
1346 wxString *pstrPath,
1347 wxString *pstrName,
1348 wxString *pstrExt)
1349{
1a5a8367 1350 wxCHECK_RET( pszFileName, _("NULL file name in wxSplitPath") );
3826db3e
VZ
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
c86f1403
VZ
1357 size_t nPosUnix = pSepUnix ? pSepUnix - pszFileName : 0;
1358 size_t nPosDos = pSepDos ? pSepDos - pszFileName : 0;
3826db3e
VZ
1359 if ( nPosDos > nPosUnix )
1360 nPosUnix = nPosDos;
c86f1403 1361// size_t nLen = Strlen(pszFileName);
3826db3e
VZ
1362
1363 if ( pstrPath )
1364 *pstrPath = wxString(pszFileName, nPosUnix);
1365 if ( pDot ) {
c86f1403 1366 size_t nPosDot = pDot - pszFileName;
3826db3e
VZ
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}
7f555861
JS
1379
1380//------------------------------------------------------------------------
1381// wild character routines
1382//------------------------------------------------------------------------
1383
1384bool 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
b112d152 1400bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special )
dfcb1ae0
KB
1401#ifdef HAVE_FNMATCH_H
1402{
b112d152
KB
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;
dfcb1ae0
KB
1407}
1408#else
1409
1410#pragma error Broken implementation of wxMatchWild() -- needs fixing!
1411 /*
1412 * WARNING: this code is broken!
1413 */
7f555861
JS
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};
dfcb1ae0 1547#endif
7f555861 1548