1///////////////////////////////////////////////////////////////////////////// 2// Name: src/common/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: filefn.cpp 66990 2011-02-22 12:10:44Z JS $ 8// Copyright: (c) 1998 Julian Smart 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// ============================================================================ 13// declarations 14// ============================================================================ 15 16// ---------------------------------------------------------------------------- 17// headers 18// ---------------------------------------------------------------------------- 19 20// For compilers that support precompilation, includes "wx.h". 21#include "wx/wxprec.h" 22 23#ifdef __BORLANDC__ 24 #pragma hdrstop 25#endif 26 27#include "wx/filefn.h" 28 29#ifndef WX_PRECOMP 30 #include "wx/intl.h" 31 #include "wx/log.h" 32 #include "wx/utils.h" 33#endif 34 35#include "wx/file.h" 36#include "wx/filename.h" 37#include "wx/dir.h" 38 39#include "wx/tokenzr.h" 40 41// there are just too many of those... 42#ifdef __VISUALC__ 43 #pragma warning(disable:4706) // assignment within conditional expression 44#endif // VC++ 45 46#include <ctype.h> 47#include <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50#if !wxONLY_WATCOM_EARLIER_THAN(1,4) 51 #if !(defined(_MSC_VER) && (_MSC_VER > 800)) 52 #include <errno.h> 53 #endif 54#endif 55 56#if defined(__WXMAC__) 57 #include "wx/mac/private.h" // includes mac headers 58#endif 59 60#ifdef __WINDOWS__ 61 #include "wx/msw/private.h" 62 #include "wx/msw/mslu.h" 63 64 // sys/cygwin.h is needed for cygwin_conv_to_full_win32_path() 65 // 66 // note that it must be included after <windows.h> 67 #ifdef __GNUWIN32__ 68 #ifdef __CYGWIN__ 69 #include <sys/cygwin.h> 70 #endif 71 #endif // __GNUWIN32__ 72 73 // io.h is needed for _get_osfhandle() 74 // Already included by filefn.h for many Windows compilers 75 #if defined __MWERKS__ || defined __CYGWIN__ 76 #include <io.h> 77 #endif 78#endif // __WINDOWS__ 79 80#if defined(__VMS__) 81 #include <fab.h> 82#endif 83 84// TODO: Borland probably has _wgetcwd as well? 85#ifdef _MSC_VER 86 #define HAVE_WGETCWD 87#endif 88 89// ---------------------------------------------------------------------------- 90// constants 91// ---------------------------------------------------------------------------- 92 93#ifndef _MAXPATHLEN 94 #define _MAXPATHLEN 1024 95#endif 96 97#ifdef __WXMAC__ 98# include "MoreFilesX.h" 99#endif 100 101// ---------------------------------------------------------------------------- 102// private globals 103// ---------------------------------------------------------------------------- 104 105// MT-FIXME: get rid of this horror and all code using it 106static wxChar wxFileFunctionsBuffer[4*_MAXPATHLEN]; 107 108#if defined(__VISAGECPP__) && __IBMCPP__ >= 400 109// 110// VisualAge C++ V4.0 cannot have any external linkage const decs 111// in headers included by more than one primary source 112// 113const int wxInvalidOffset = -1; 114#endif 115 116// ---------------------------------------------------------------------------- 117// macros 118// ---------------------------------------------------------------------------- 119 120// translate the filenames before passing them to OS functions 121#define OS_FILENAME(s) (s.fn_str()) 122 123// ============================================================================ 124// implementation 125// ============================================================================ 126 127// ---------------------------------------------------------------------------- 128// wrappers around standard POSIX functions 129// ---------------------------------------------------------------------------- 130 131#ifdef wxNEED_WX_UNISTD_H 132 133WXDLLEXPORT int wxStat( const wxChar *file_name, wxStructStat *buf ) 134{ 135 return stat( wxConvFile.cWX2MB( file_name ), buf ); 136} 137 138WXDLLEXPORT int wxLstat( const wxChar *file_name, wxStructStat *buf ) 139{ 140 return lstat( wxConvFile.cWX2MB( file_name ), buf ); 141} 142 143WXDLLEXPORT int wxAccess( const wxChar *pathname, int mode ) 144{ 145 return access( wxConvFile.cWX2MB( pathname ), mode ); 146} 147 148WXDLLEXPORT int wxOpen( const wxChar *pathname, int flags, mode_t mode ) 149{ 150 return open( wxConvFile.cWX2MB( pathname ), flags, mode ); 151} 152 153#endif // wxNEED_WX_UNISTD_H 154 155#if wxUSE_UNICODE && defined __BORLANDC__ \ 156 && __BORLANDC__ >= 0x550 && __BORLANDC__ <= 0x551 157 158// BCC 5.5 and 5.5.1 have a bug in _wopen where files are created read only 159// regardless of the mode parameter. This hack works around the problem by 160// setting the mode with _wchmod. 161// 162int wxOpen(const wchar_t *pathname, int flags, mode_t mode) 163{ 164 int moreflags = 0; 165 166 // we only want to fix the mode when the file is actually created, so 167 // when creating first try doing it O_EXCL so we can tell if the file 168 // was already there. 169 if ((flags & O_CREAT) && !(flags & O_EXCL) && (mode & wxS_IWUSR) != 0) 170 moreflags = O_EXCL; 171 172 int fd = _wopen(pathname, flags | moreflags, mode); 173 174 // the file was actually created and needs fixing 175 if (fd != -1 && (flags & O_CREAT) != 0 && (mode & wxS_IWUSR) != 0) 176 { 177 close(fd); 178 _wchmod(pathname, mode); 179 fd = _wopen(pathname, flags & ~(O_EXCL | O_CREAT)); 180 } 181 // the open failed, but it may have been because the added O_EXCL stopped 182 // the opening of an existing file, so try again without. 183 else if (fd == -1 && moreflags != 0) 184 { 185 fd = _wopen(pathname, flags & ~O_CREAT); 186 } 187 188 return fd; 189} 190 191#endif 192 193// ---------------------------------------------------------------------------- 194// wxPathList 195// ---------------------------------------------------------------------------- 196 197bool wxPathList::Add(const wxString& path) 198{ 199 // add a path separator to force wxFileName to interpret it always as a directory 200 // (i.e. if we are called with '/home/user' we want to consider it a folder and 201 // not, as wxFileName would consider, a filename). 202 wxFileName fn(path + wxFileName::GetPathSeparator()); 203 204 // add only normalized relative/absolute paths 205 // NB: we won't do wxPATH_NORM_DOTS in order to avoid problems when trying to 206 // normalize paths which starts with ".." (which can be normalized only if 207 // we use also wxPATH_NORM_ABSOLUTE - which we don't want to use). 208 if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS)) 209 return false; 210 211 wxString toadd = fn.GetPath(); 212 if (Index(toadd) == wxNOT_FOUND) 213 wxArrayString::Add(toadd); // do not add duplicates 214 215 return true; 216} 217 218void wxPathList::Add(const wxArrayString &arr) 219{ 220 for (size_t j=0; j < arr.GetCount(); j++) 221 Add(arr[j]); 222} 223 224// Add paths e.g. from the PATH environment variable 225void wxPathList::AddEnvList (const wxString& WXUNUSED_IN_WINCE(envVariable)) 226{ 227 // No environment variables on WinCE 228#ifndef __WXWINCE__ 229 230 // The space has been removed from the tokenizers, otherwise a 231 // path such as "C:\Program Files" would be split into 2 paths: 232 // "C:\Program" and "Files"; this is true for both Windows and Unix. 233 234 static const wxChar PATH_TOKS[] = 235#if defined(__WINDOWS__) || defined(__OS2__) 236 wxT(";"); // Don't separate with colon in DOS (used for drive) 237#else 238 wxT(":;"); 239#endif 240 241 wxString val; 242 if ( wxGetEnv(envVariable, &val) ) 243 { 244 // split into an array of string the value of the env var 245 wxArrayString arr = wxStringTokenize(val, PATH_TOKS); 246 WX_APPEND_ARRAY(*this, arr); 247 } 248#endif // !__WXWINCE__ 249} 250 251// Given a full filename (with path), ensure that that file can 252// be accessed again USING FILENAME ONLY by adding the path 253// to the list if not already there. 254bool wxPathList::EnsureFileAccessible (const wxString& path) 255{ 256 return Add(wxPathOnly(path)); 257} 258 259#if WXWIN_COMPATIBILITY_2_6 260bool wxPathList::Member (const wxString& path) const 261{ 262 return Index(path) != wxNOT_FOUND; 263} 264#endif 265 266wxString wxPathList::FindValidPath (const wxString& file) const 267{ 268 // normalize the given string as it could be a path + a filename 269 // and not only a filename 270 wxFileName fn(file); 271 wxString strend; 272 273 // NB: normalize without making absolute otherwise calling this function with 274 // e.g. "b/c.txt" would result in removing the directory 'b' and the for loop 275 // below would only add to the paths of this list the 'c.txt' part when doing 276 // the existence checks... 277 // NB: we don't use wxPATH_NORM_DOTS here, too (see wxPathList::Add for more info) 278 if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS)) 279 return wxEmptyString; 280 281 wxASSERT_MSG(!fn.IsDir(), wxT("Cannot search for directories; only for files")); 282 if (fn.IsAbsolute()) 283 strend = fn.GetFullName(); // search for the file name and ignore the path part 284 else 285 strend = fn.GetFullPath(); 286 287 for (size_t i=0; i<GetCount(); i++) 288 { 289 wxString strstart = Item(i); 290 if (!strstart.IsEmpty() && strstart.Last() != wxFileName::GetPathSeparator()) 291 strstart += wxFileName::GetPathSeparator(); 292 293 if (wxFileExists(strstart + strend)) 294 return strstart + strend; // Found! 295 } 296 297 return wxEmptyString; // Not found 298} 299 300wxString wxPathList::FindAbsoluteValidPath (const wxString& file) const 301{ 302 wxString f = FindValidPath(file); 303 if ( f.empty() || wxIsAbsolutePath(f) ) 304 return f; 305 306 wxString buf = ::wxGetCwd(); 307 308 if ( !wxEndsWithPathSeparator(buf) ) 309 { 310 buf += wxFILE_SEP_PATH; 311 } 312 buf += f; 313 314 return buf; 315} 316 317// ---------------------------------------------------------------------------- 318// miscellaneous global functions (TOFIX!) 319// ---------------------------------------------------------------------------- 320 321static inline wxChar* MYcopystring(const wxString& s) 322{ 323 wxChar* copy = new wxChar[s.length() + 1]; 324 return wxStrcpy(copy, s.c_str()); 325} 326 327static inline wxChar* MYcopystring(const wxChar* s) 328{ 329 wxChar* copy = new wxChar[wxStrlen(s) + 1]; 330 return wxStrcpy(copy, s); 331} 332 333 334bool 335wxFileExists (const wxString& filename) 336{ 337#if defined(__WXPALMOS__) 338 return false; 339#elif defined(__WIN32__) && !defined(__WXMICROWIN__) 340 // we must use GetFileAttributes() instead of the ANSI C functions because 341 // it can cope with network (UNC) paths unlike them 342 DWORD ret = ::GetFileAttributes(filename); 343 344 return (ret != (DWORD)-1) && !(ret & FILE_ATTRIBUTE_DIRECTORY); 345#else // !__WIN32__ 346 #ifndef S_ISREG 347 #define S_ISREG(mode) ((mode) & S_IFREG) 348 #endif 349 wxStructStat st; 350#ifndef wxNEED_WX_UNISTD_H 351 return (wxStat( filename.fn_str() , &st) == 0 && S_ISREG(st.st_mode)) 352#ifdef __OS2__ 353 || (errno == EACCES) // if access is denied something with that name 354 // exists and is opened in exclusive mode. 355#endif 356 ; 357#else 358 return wxStat( filename , &st) == 0 && S_ISREG(st.st_mode); 359#endif 360#endif // __WIN32__/!__WIN32__ 361} 362 363bool 364wxIsAbsolutePath (const wxString& filename) 365{ 366 if (!filename.empty()) 367 { 368#if defined(__WXMAC__) && !defined(__DARWIN__) 369 // Classic or Carbon CodeWarrior like 370 // Carbon with Apple DevTools is Unix like 371 372 // This seems wrong to me, but there is no fix. since 373 // "MacOS:MyText.txt" is absolute whereas "MyDir:MyText.txt" 374 // is not. Or maybe ":MyDir:MyText.txt" has to be used? RR. 375 if (filename.Find(':') != wxNOT_FOUND && filename[0] != ':') 376 return true ; 377#else 378 // Unix like or Windows 379 if (filename[0] == wxT('/')) 380 return true; 381#endif 382#ifdef __VMS__ 383 if ((filename[0] == wxT('[') && filename[1] != wxT('.'))) 384 return true; 385#endif 386#if defined(__WINDOWS__) || defined(__OS2__) 387 // MSDOS like 388 if (filename[0] == wxT('\\') || (wxIsalpha (filename[0]) && filename[1] == wxT(':'))) 389 return true; 390#endif 391 } 392 return false ; 393} 394 395/* 396 * Strip off any extension (dot something) from end of file, 397 * IF one exists. Inserts zero into buffer. 398 * 399 */ 400 401void wxStripExtension(wxChar *buffer) 402{ 403 int len = wxStrlen(buffer); 404 int i = len-1; 405 while (i > 0) 406 { 407 if (buffer[i] == wxT('.')) 408 { 409 buffer[i] = 0; 410 break; 411 } 412 i --; 413 } 414} 415 416void wxStripExtension(wxString& buffer) 417{ 418 //RN: Be careful about the handling the case where 419 //buffer.length() == 0 420 for(size_t i = buffer.length() - 1; i != wxString::npos; --i) 421 { 422 if (buffer.GetChar(i) == wxT('.')) 423 { 424 buffer = buffer.Left(i); 425 break; 426 } 427 } 428} 429 430// Destructive removal of /./ and /../ stuff 431wxChar *wxRealPath (wxChar *path) 432{ 433#ifdef __WXMSW__ 434 static const wxChar SEP = wxT('\\'); 435 wxUnix2DosFilename(path); 436#else 437 static const wxChar SEP = wxT('/'); 438#endif 439 if (path[0] && path[1]) { 440 /* MATTHEW: special case "/./x" */ 441 wxChar *p; 442 if (path[2] == SEP && path[1] == wxT('.')) 443 p = &path[0]; 444 else 445 p = &path[2]; 446 for (; *p; p++) 447 { 448 if (*p == SEP) 449 { 450 if (p[1] == wxT('.') && p[2] == wxT('.') && (p[3] == SEP || p[3] == wxT('\0'))) 451 { 452 wxChar *q; 453 for (q = p - 1; q >= path && *q != SEP; q--) 454 { 455 // Empty 456 } 457 458 if (q[0] == SEP && (q[1] != wxT('.') || q[2] != wxT('.') || q[3] != SEP) 459 && (q - 1 <= path || q[-1] != SEP)) 460 { 461 wxStrcpy (q, p + 3); 462 if (path[0] == wxT('\0')) 463 { 464 path[0] = SEP; 465 path[1] = wxT('\0'); 466 } 467#if defined(__WXMSW__) || defined(__OS2__) 468 /* Check that path[2] is NULL! */ 469 else if (path[1] == wxT(':') && !path[2]) 470 { 471 path[2] = SEP; 472 path[3] = wxT('\0'); 473 } 474#endif 475 p = q - 1; 476 } 477 } 478 else if (p[1] == wxT('.') && (p[2] == SEP || p[2] == wxT('\0'))) 479 wxStrcpy (p, p + 2); 480 } 481 } 482 } 483 return path; 484} 485 486wxString wxRealPath(const wxString& path) 487{ 488 wxChar *buf1=MYcopystring(path); 489 wxChar *buf2=wxRealPath(buf1); 490 wxString buf(buf2); 491 delete [] buf1; 492 return buf; 493} 494 495 496// Must be destroyed 497wxChar *wxCopyAbsolutePath(const wxString& filename) 498{ 499 if (filename.empty()) 500 return (wxChar *) NULL; 501 502 if (! wxIsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer, filename))) 503 { 504 wxString buf = ::wxGetCwd(); 505 wxChar ch = buf.Last(); 506#ifdef __WXMSW__ 507 if (ch != wxT('\\') && ch != wxT('/')) 508 buf << wxT("\\"); 509#else 510 if (ch != wxT('/')) 511 buf << wxT("/"); 512#endif 513 buf << wxFileFunctionsBuffer; 514 buf = wxRealPath( buf ); 515 return MYcopystring( buf ); 516 } 517 return MYcopystring( wxFileFunctionsBuffer ); 518} 519 520/*- 521 Handles: 522 ~/ => home dir 523 ~user/ => user's home dir 524 If the environment variable a = "foo" and b = "bar" then: 525 Unix: 526 $a => foo 527 $a$b => foobar 528 $a.c => foo.c 529 xxx$a => xxxfoo 530 ${a}! => foo! 531 $(b)! => bar! 532 \$a => \$a 533 MSDOS: 534 $a ==> $a 535 $(a) ==> foo 536 $(a)$b ==> foo$b 537 $(a)$(b)==> foobar 538 test.$$ ==> test.$$ 539 */ 540 541/* input name in name, pathname output to buf. */ 542 543wxChar *wxExpandPath(wxChar *buf, const wxChar *name) 544{ 545 register wxChar *d, *s, *nm; 546 wxChar lnm[_MAXPATHLEN]; 547 int q; 548 549 // Some compilers don't like this line. 550// const wxChar trimchars[] = wxT("\n \t"); 551 552 wxChar trimchars[4]; 553 trimchars[0] = wxT('\n'); 554 trimchars[1] = wxT(' '); 555 trimchars[2] = wxT('\t'); 556 trimchars[3] = 0; 557 558#ifdef __WXMSW__ 559 const wxChar SEP = wxT('\\'); 560#else 561 const wxChar SEP = wxT('/'); 562#endif 563 buf[0] = wxT('\0'); 564 if (name == NULL || *name == wxT('\0')) 565 return buf; 566 nm = MYcopystring(name); // Make a scratch copy 567 wxChar *nm_tmp = nm; 568 569 /* Skip leading whitespace and cr */ 570 while (wxStrchr((wxChar *)trimchars, *nm) != NULL) 571 nm++; 572 /* And strip off trailing whitespace and cr */ 573 s = nm + (q = wxStrlen(nm)) - 1; 574 while (q-- && wxStrchr((wxChar *)trimchars, *s) != NULL) 575 *s = wxT('\0'); 576 577 s = nm; 578 d = lnm; 579#ifdef __WXMSW__ 580 q = FALSE; 581#else 582 q = nm[0] == wxT('\\') && nm[1] == wxT('~'); 583#endif 584 585 /* Expand inline environment variables */ 586#ifdef __VISAGECPP__ 587 while (*d) 588 { 589 *d++ = *s; 590 if(*s == wxT('\\')) 591 { 592 *(d - 1) = *++s; 593 if (*d) 594 { 595 s++; 596 continue; 597 } 598 else 599 break; 600 } 601 else 602#else 603 while ((*d++ = *s) != 0) { 604# ifndef __WXMSW__ 605 if (*s == wxT('\\')) { 606 if ((*(d - 1) = *++s)!=0) { 607 s++; 608 continue; 609 } else 610 break; 611 } else 612# endif 613#endif 614 // No env variables on WinCE 615#ifndef __WXWINCE__ 616#ifdef __WXMSW__ 617 if (*s++ == wxT('$') && (*s == wxT('{') || *s == wxT(')'))) 618#else 619 if (*s++ == wxT('$')) 620#endif 621 { 622 register wxChar *start = d; 623 register int braces = (*s == wxT('{') || *s == wxT('(')); 624 register wxChar *value; 625 while ((*d++ = *s) != 0) 626 if (braces ? (*s == wxT('}') || *s == wxT(')')) : !(wxIsalnum(*s) || *s == wxT('_')) ) 627 break; 628 else 629 s++; 630 *--d = 0; 631 value = wxGetenv(braces ? start + 1 : start); 632 if (value) { 633 for ((d = start - 1); (*d++ = *value++) != 0;) 634 { 635 // Empty 636 } 637 638 d--; 639 if (braces && *s) 640 s++; 641 } 642 } 643#endif 644 // __WXWINCE__ 645 } 646 647 /* Expand ~ and ~user */ 648 nm = lnm; 649 if (nm[0] == wxT('~') && !q) 650 { 651 /* prefix ~ */ 652 if (nm[1] == SEP || nm[1] == 0) 653 { /* ~/filename */ 654 // FIXME: wxGetUserHome could return temporary storage in Unicode mode 655 if ((s = WXSTRINGCAST wxGetUserHome(wxEmptyString)) != NULL) { 656 if (*++nm) 657 nm++; 658 } 659 } else 660 { /* ~user/filename */ 661 register wxChar *nnm; 662 register wxChar *home; 663 for (s = nm; *s && *s != SEP; s++) 664 { 665 // Empty 666 } 667 int was_sep; /* MATTHEW: Was there a separator, or NULL? */ 668 was_sep = (*s == SEP); 669 nnm = *s ? s + 1 : s; 670 *s = 0; 671 // FIXME: wxGetUserHome could return temporary storage in Unicode mode 672 if ((home = WXSTRINGCAST wxGetUserHome(wxString(nm + 1))) == NULL) 673 { 674 if (was_sep) /* replace only if it was there: */ 675 *s = SEP; 676 s = NULL; 677 } 678 else 679 { 680 nm = nnm; 681 s = home; 682 } 683 } 684 } 685 686 d = buf; 687 if (s && *s) { /* MATTHEW: s could be NULL if user '~' didn't exist */ 688 /* Copy home dir */ 689 while (wxT('\0') != (*d++ = *s++)) 690 /* loop */; 691 // Handle root home 692 if (d - 1 > buf && *(d - 2) != SEP) 693 *(d - 1) = SEP; 694 } 695 s = nm; 696 while ((*d++ = *s++) != 0) 697 { 698 // Empty 699 } 700 delete[] nm_tmp; // clean up alloc 701 /* Now clean up the buffer */ 702 return wxRealPath(buf); 703} 704 705/* Contract Paths to be build upon an environment variable 706 component: 707 708 example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib 709 710 The call wxExpandPath can convert these back! 711 */ 712wxChar * 713wxContractPath (const wxString& filename, 714 const wxString& WXUNUSED_IN_WINCE(envname), 715 const wxString& user) 716{ 717 static wxChar dest[_MAXPATHLEN]; 718 719 if (filename.empty()) 720 return (wxChar *) NULL; 721 722 wxStrcpy (dest, WXSTRINGCAST filename); 723#ifdef __WXMSW__ 724 wxUnix2DosFilename(dest); 725#endif 726 727 // Handle environment 728 const wxChar *val; 729#ifndef __WXWINCE__ 730 wxChar *tcp; 731 if (!envname.empty() && (val = wxGetenv (WXSTRINGCAST envname)) != NULL && 732 (tcp = wxStrstr (dest, val)) != NULL) 733 { 734 wxStrcpy (wxFileFunctionsBuffer, tcp + wxStrlen (val)); 735 *tcp++ = wxT('$'); 736 *tcp++ = wxT('{'); 737 wxStrcpy (tcp, WXSTRINGCAST envname); 738 wxStrcat (tcp, wxT("}")); 739 wxStrcat (tcp, wxFileFunctionsBuffer); 740 } 741#endif 742 743 // Handle User's home (ignore root homes!) 744 val = wxGetUserHome (user); 745 if (!val) 746 return dest; 747 748 const size_t len = wxStrlen(val); 749 if (len <= 2) 750 return dest; 751 752 if (wxStrncmp(dest, val, len) == 0) 753 { 754 wxStrcpy(wxFileFunctionsBuffer, wxT("~")); 755 if (!user.empty()) 756 wxStrcat(wxFileFunctionsBuffer, (const wxChar*) user); 757 wxStrcat(wxFileFunctionsBuffer, dest + len); 758 wxStrcpy (dest, wxFileFunctionsBuffer); 759 } 760 761 return dest; 762} 763 764// Return just the filename, not the path (basename) 765wxChar *wxFileNameFromPath (wxChar *path) 766{ 767 wxString p = path; 768 wxString n = wxFileNameFromPath(p); 769 770 return path + p.length() - n.length(); 771} 772 773wxString wxFileNameFromPath (const wxString& path) 774{ 775 wxString name, ext; 776 wxFileName::SplitPath(path, NULL, &name, &ext); 777 778 wxString fullname = name; 779 if ( !ext.empty() ) 780 { 781 fullname << wxFILE_SEP_EXT << ext; 782 } 783 784 return fullname; 785} 786 787// Return just the directory, or NULL if no directory 788wxChar * 789wxPathOnly (wxChar *path) 790{ 791 if (path && *path) 792 { 793 static wxChar buf[_MAXPATHLEN]; 794 795 // Local copy 796 wxStrcpy (buf, path); 797 798 int l = wxStrlen(path); 799 int i = l - 1; 800 801 // Search backward for a backward or forward slash 802 while (i > -1) 803 { 804#if defined(__WXMAC__) && !defined(__DARWIN__) 805 // Classic or Carbon CodeWarrior like 806 // Carbon with Apple DevTools is Unix like 807 if (path[i] == wxT(':') ) 808 { 809 buf[i] = 0; 810 return buf; 811 } 812#else 813 // Unix like or Windows 814 if (path[i] == wxT('/') || path[i] == wxT('\\')) 815 { 816 buf[i] = 0; 817 return buf; 818 } 819#endif 820#ifdef __VMS__ 821 if (path[i] == wxT(']')) 822 { 823 buf[i+1] = 0; 824 return buf; 825 } 826#endif 827 i --; 828 } 829 830#if defined(__WXMSW__) || defined(__OS2__) 831 // Try Drive specifier 832 if (wxIsalpha (buf[0]) && buf[1] == wxT(':')) 833 { 834 // A:junk --> A:. (since A:.\junk Not A:\junk) 835 buf[2] = wxT('.'); 836 buf[3] = wxT('\0'); 837 return buf; 838 } 839#endif 840 } 841 return (wxChar *) NULL; 842} 843 844// Return just the directory, or NULL if no directory 845wxString wxPathOnly (const wxString& path) 846{ 847 if (!path.empty()) 848 { 849 wxChar buf[_MAXPATHLEN]; 850 851 // Local copy 852 wxStrcpy (buf, WXSTRINGCAST path); 853 854 int l = path.length(); 855 int i = l - 1; 856 857 // Search backward for a backward or forward slash 858 while (i > -1) 859 { 860#if defined(__WXMAC__) && !defined(__DARWIN__) 861 // Classic or Carbon CodeWarrior like 862 // Carbon with Apple DevTools is Unix like 863 if (path[i] == wxT(':') ) 864 { 865 buf[i] = 0; 866 return wxString(buf); 867 } 868#else 869 // Unix like or Windows 870 if (path[i] == wxT('/') || path[i] == wxT('\\')) 871 { 872 // Don't return an empty string 873 if (i == 0) 874 i ++; 875 buf[i] = 0; 876 return wxString(buf); 877 } 878#endif 879#ifdef __VMS__ 880 if (path[i] == wxT(']')) 881 { 882 buf[i+1] = 0; 883 return wxString(buf); 884 } 885#endif 886 i --; 887 } 888 889#if defined(__WXMSW__) || defined(__OS2__) 890 // Try Drive specifier 891 if (wxIsalpha (buf[0]) && buf[1] == wxT(':')) 892 { 893 // A:junk --> A:. (since A:.\junk Not A:\junk) 894 buf[2] = wxT('.'); 895 buf[3] = wxT('\0'); 896 return wxString(buf); 897 } 898#endif 899 } 900 return wxEmptyString; 901} 902 903// Utility for converting delimiters in DOS filenames to UNIX style 904// and back again - or we get nasty problems with delimiters. 905// Also, convert to lower case, since case is significant in UNIX. 906 907#if defined(__WXMAC__) 908 909#if TARGET_API_MAC_OSX 910#define kDefaultPathStyle kCFURLPOSIXPathStyle 911#else 912#define kDefaultPathStyle kCFURLHFSPathStyle 913#endif 914 915wxString wxMacFSRefToPath( const FSRef *fsRef , CFStringRef additionalPathComponent ) 916{ 917 CFURLRef fullURLRef; 918 fullURLRef = CFURLCreateFromFSRef(NULL, fsRef); 919 if ( additionalPathComponent ) 920 { 921 CFURLRef parentURLRef = fullURLRef ; 922 fullURLRef = CFURLCreateCopyAppendingPathComponent(NULL, parentURLRef, 923 additionalPathComponent,false); 924 CFRelease( parentURLRef ) ; 925 } 926 CFStringRef cfString = CFURLCopyFileSystemPath(fullURLRef, kDefaultPathStyle); 927 CFRelease( fullURLRef ) ; 928 CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfString); 929 CFRelease( cfString ); 930 CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); 931 return wxMacCFStringHolder(cfMutableString).AsString(); 932} 933 934OSStatus wxMacPathToFSRef( const wxString&path , FSRef *fsRef ) 935{ 936 OSStatus err = noErr ; 937 CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, wxMacCFStringHolder(path)); 938 CFStringNormalize(cfMutableString,kCFStringNormalizationFormD); 939 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kDefaultPathStyle, false); 940 CFRelease( cfMutableString ); 941 if ( NULL != url ) 942 { 943 if ( CFURLGetFSRef(url, fsRef) == false ) 944 err = fnfErr ; 945 CFRelease( url ) ; 946 } 947 else 948 { 949 err = fnfErr ; 950 } 951 return err ; 952} 953 954wxString wxMacHFSUniStrToString( ConstHFSUniStr255Param uniname ) 955{ 956 CFStringRef cfname = CFStringCreateWithCharacters( kCFAllocatorDefault, 957 uniname->unicode, 958 uniname->length ); 959 CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfname); 960 CFRelease( cfname ); 961 CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); 962 return wxMacCFStringHolder(cfMutableString).AsString() ; 963} 964 965#ifndef __LP64__ 966 967wxString wxMacFSSpec2MacFilename( const FSSpec *spec ) 968{ 969 FSRef fsRef ; 970 if ( FSpMakeFSRef( spec , &fsRef) == noErr ) 971 { 972 return wxMacFSRefToPath( &fsRef ) ; 973 } 974 return wxEmptyString ; 975} 976 977void wxMacFilename2FSSpec( const wxString& path , FSSpec *spec ) 978{ 979 OSStatus err = noErr ; 980 FSRef fsRef ; 981 wxMacPathToFSRef( path , &fsRef ) ; 982 err = FSRefMakeFSSpec( &fsRef , spec ) ; 983} 984#endif 985 986#endif // __WXMAC__ 987 988void 989wxDos2UnixFilename (wxChar *s) 990{ 991 if (s) 992 while (*s) 993 { 994 if (*s == _T('\\')) 995 *s = _T('/'); 996#ifdef __WXMSW__ 997 else 998 *s = (wxChar)wxTolower (*s); // Case INDEPENDENT 999#endif 1000 s++; 1001 } 1002} 1003 1004void 1005#if defined(__WXMSW__) || defined(__OS2__) 1006wxUnix2DosFilename (wxChar *s) 1007#else 1008wxUnix2DosFilename (wxChar *WXUNUSED(s) ) 1009#endif 1010{ 1011// Yes, I really mean this to happen under DOS only! JACS 1012#if defined(__WXMSW__) || defined(__OS2__) 1013 if (s) 1014 while (*s) 1015 { 1016 if (*s == wxT('/')) 1017 *s = wxT('\\'); 1018 s++; 1019 } 1020#endif 1021} 1022 1023// Concatenate two files to form third 1024bool 1025wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& file3) 1026{ 1027#if wxUSE_FILE 1028 1029 wxFile in1(file1), in2(file2); 1030 wxTempFile out(file3); 1031 1032 if ( !in1.IsOpened() || !in2.IsOpened() || !out.IsOpened() ) 1033 return false; 1034 1035 ssize_t ofs; 1036 unsigned char buf[1024]; 1037 1038 for( int i=0; i<2; i++) 1039 { 1040 wxFile *in = i==0 ? &in1 : &in2; 1041 do{ 1042 if ( (ofs = in->Read(buf,WXSIZEOF(buf))) == wxInvalidOffset ) return false; 1043 if ( ofs > 0 ) 1044 if ( !out.Write(buf,ofs) ) 1045 return false; 1046 } while ( ofs == (ssize_t)WXSIZEOF(buf) ); 1047 } 1048 1049 return out.Commit(); 1050 1051#else 1052 1053 wxUnusedVar(file1); 1054 wxUnusedVar(file2); 1055 wxUnusedVar(file3); 1056 return false; 1057 1058#endif 1059} 1060 1061// Copy files 1062bool 1063wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite) 1064{ 1065#if defined(__WIN32__) && !defined(__WXMICROWIN__) 1066 // CopyFile() copies file attributes and modification time too, so use it 1067 // instead of our code if available 1068 // 1069 // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite 1070 if ( !::CopyFile(file1, file2, !overwrite) ) 1071 { 1072 wxLogSysError(_("Failed to copy the file '%s' to '%s'"), 1073 file1.c_str(), file2.c_str()); 1074 1075 return false; 1076 } 1077#elif defined(__OS2__) 1078 if ( ::DosCopy((PSZ)file1.c_str(), (PSZ)file2.c_str(), overwrite ? DCPY_EXISTING : 0) != 0 ) 1079 return false; 1080#elif defined(__PALMOS__) 1081 // TODO with http://www.palmos.com/dev/support/docs/protein_books/Memory_Databases_Files/ 1082 return false; 1083#elif wxUSE_FILE // !Win32 1084 1085 wxStructStat fbuf; 1086 // get permissions of file1 1087 if ( wxStat( file1.c_str(), &fbuf) != 0 ) 1088 { 1089 // the file probably doesn't exist or we haven't the rights to read 1090 // from it anyhow 1091 wxLogSysError(_("Impossible to get permissions for file '%s'"), 1092 file1.c_str()); 1093 return false; 1094 } 1095 1096 // open file1 for reading 1097 wxFile fileIn(file1, wxFile::read); 1098 if ( !fileIn.IsOpened() ) 1099 return false; 1100 1101 // remove file2, if it exists. This is needed for creating 1102 // file2 with the correct permissions in the next step 1103 if ( wxFileExists(file2) && (!overwrite || !wxRemoveFile(file2))) 1104 { 1105 wxLogSysError(_("Impossible to overwrite the file '%s'"), 1106 file2.c_str()); 1107 return false; 1108 } 1109 1110 // reset the umask as we want to create the file with exactly the same 1111 // permissions as the original one 1112 wxCHANGE_UMASK(0); 1113 1114 // create file2 with the same permissions than file1 and open it for 1115 // writing 1116 1117 wxFile fileOut; 1118 if ( !fileOut.Create(file2, overwrite, fbuf.st_mode & 0777) ) 1119 return false; 1120 1121 // copy contents of file1 to file2 1122 char buf[4096]; 1123 size_t count; 1124 for ( ;; ) 1125 { 1126 count = fileIn.Read(buf, WXSIZEOF(buf)); 1127 if ( fileIn.Error() ) 1128 return false; 1129 1130 // end of file? 1131 if ( !count ) 1132 break; 1133 1134 if ( fileOut.Write(buf, count) < count ) 1135 return false; 1136 } 1137 1138 // we can expect fileIn to be closed successfully, but we should ensure 1139 // that fileOut was closed as some write errors (disk full) might not be 1140 // detected before doing this 1141 if ( !fileIn.Close() || !fileOut.Close() ) 1142 return false; 1143 1144#if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__) 1145 // no chmod in VA. Should be some permission API for HPFS386 partitions 1146 // however 1147 if ( chmod(OS_FILENAME(file2), fbuf.st_mode) != 0 ) 1148 { 1149 wxLogSysError(_("Impossible to set permissions for the file '%s'"), 1150 file2.c_str()); 1151 return false; 1152 } 1153#endif // OS/2 || Mac 1154 1155#else // !Win32 && ! wxUSE_FILE 1156 1157 // impossible to simulate with wxWidgets API 1158 wxUnusedVar(file1); 1159 wxUnusedVar(file2); 1160 wxUnusedVar(overwrite); 1161 return false; 1162 1163#endif // __WXMSW__ && __WIN32__ 1164 1165 return true; 1166} 1167 1168bool 1169wxRenameFile(const wxString& file1, const wxString& file2, bool overwrite) 1170{ 1171 if ( !overwrite && wxFileExists(file2) ) 1172 { 1173 wxLogSysError 1174 ( 1175 _("Failed to rename the file '%s' to '%s' because the destination file already exists."), 1176 file1.c_str(), file2.c_str() 1177 ); 1178 1179 return false; 1180 } 1181 1182#if !defined(__WXWINCE__) && !defined(__WXPALMOS__) 1183 // Normal system call 1184 if ( wxRename (file1, file2) == 0 ) 1185 return true; 1186#endif 1187 1188 // Try to copy 1189 if (wxCopyFile(file1, file2, overwrite)) { 1190 wxRemoveFile(file1); 1191 return true; 1192 } 1193 // Give up 1194 return false; 1195} 1196 1197bool wxRemoveFile(const wxString& file) 1198{ 1199#if defined(__VISUALC__) \ 1200 || defined(__BORLANDC__) \ 1201 || defined(__WATCOMC__) \ 1202 || defined(__DMC__) \ 1203 || defined(__GNUWIN32__) \ 1204 || (defined(__MWERKS__) && defined(__MSL__)) 1205 int res = wxRemove(file); 1206#elif defined(__WXMAC__) 1207 int res = unlink(wxFNCONV(file)); 1208#elif defined(__WXPALMOS__) 1209 int res = 1; 1210 // TODO with VFSFileDelete() 1211#else 1212 int res = unlink(OS_FILENAME(file)); 1213#endif 1214 1215 return res == 0; 1216} 1217 1218bool wxMkdir(const wxString& dir, int perm) 1219{ 1220#if defined(__WXPALMOS__) 1221 return false; 1222#elif defined(__WXMAC__) && !defined(__UNIX__) 1223 return (mkdir( wxFNCONV(dir) , 0 ) == 0); 1224#else // !Mac 1225 const wxChar *dirname = dir.c_str(); 1226 1227 // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too 1228 // for the GNU compiler 1229#if (!(defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__))) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) || defined(__WINE__) || defined(__WXMICROWIN__) 1230 #if defined(MSVCRT) 1231 wxUnusedVar(perm); 1232 if ( mkdir(wxFNCONV(dirname)) != 0 ) 1233 #else 1234 if ( mkdir(wxFNCONV(dirname), perm) != 0 ) 1235 #endif 1236#elif defined(__OS2__) 1237 wxUnusedVar(perm); 1238 if (::DosCreateDir((PSZ)dirname, NULL) != 0) // enhance for EAB's?? 1239#elif defined(__DOS__) 1240 #if defined(__WATCOMC__) 1241 (void)perm; 1242 if ( wxMkDir(wxFNSTRINGCAST wxFNCONV(dirname)) != 0 ) 1243 #elif defined(__DJGPP__) 1244 if ( mkdir(wxFNCONV(dirname), perm) != 0 ) 1245 #else 1246 #error "Unsupported DOS compiler!" 1247 #endif 1248#else // !MSW, !DOS and !OS/2 VAC++ 1249 wxUnusedVar(perm); 1250#ifdef __WXWINCE__ 1251 if ( !CreateDirectory(dirname, NULL) ) 1252#else 1253 if ( wxMkDir(dir.fn_str()) != 0 ) 1254#endif 1255#endif // !MSW/MSW 1256 { 1257 wxLogSysError(_("Directory '%s' couldn't be created"), dirname); 1258 1259 return false; 1260 } 1261 1262 return true; 1263#endif // Mac/!Mac 1264} 1265 1266bool wxRmdir(const wxString& dir, int WXUNUSED(flags)) 1267{ 1268#if defined(__VMS__) 1269 return false; //to be changed since rmdir exists in VMS7.x 1270#elif defined(__OS2__) 1271 return (::DosDeleteDir((PSZ)dir.c_str()) == 0); 1272#elif defined(__WXWINCE__) 1273 return (RemoveDirectory(dir) != 0); 1274#elif defined(__WXPALMOS__) 1275 // TODO with VFSFileRename() 1276 return false; 1277#else 1278 return (wxRmDir(OS_FILENAME(dir)) == 0); 1279#endif 1280} 1281 1282// does the path exists? (may have or not '/' or '\\' at the end) 1283bool wxDirExists(const wxChar *pszPathName) 1284{ 1285 wxString strPath(pszPathName); 1286 1287#if defined(__WINDOWS__) || defined(__OS2__) 1288 // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, 1289 // so remove all trailing backslashes from the path - but don't do this for 1290 // the paths "d:\" (which are different from "d:") nor for just "\" 1291 while ( wxEndsWithPathSeparator(strPath) ) 1292 { 1293 size_t len = strPath.length(); 1294 if ( len == 1 || (len == 3 && strPath[len - 2] == _T(':')) ) 1295 break; 1296 1297 strPath.Truncate(len - 1); 1298 } 1299#endif // __WINDOWS__ 1300 1301#ifdef __OS2__ 1302 // OS/2 can't handle "d:", it wants either "d:\" or "d:." 1303 if (strPath.length() == 2 && strPath[1u] == _T(':')) 1304 strPath << _T('.'); 1305#endif 1306 1307#if defined(__WXPALMOS__) 1308 return false; 1309#elif defined(__WIN32__) && !defined(__WXMICROWIN__) 1310 // stat() can't cope with network paths 1311 DWORD ret = ::GetFileAttributes(strPath); 1312 1313 return (ret != (DWORD)-1) && (ret & FILE_ATTRIBUTE_DIRECTORY); 1314#elif defined(__OS2__) 1315 FILESTATUS3 Info = {{0}}; 1316 APIRET rc = ::DosQueryPathInfo((PSZ)(WXSTRINGCAST strPath), FIL_STANDARD, 1317 (void*) &Info, sizeof(FILESTATUS3)); 1318 1319 return ((rc == NO_ERROR) && (Info.attrFile & FILE_DIRECTORY)) || 1320 (rc == ERROR_SHARING_VIOLATION); 1321 // If we got a sharing violation, there must be something with this name. 1322#else // !__WIN32__ 1323 1324 wxStructStat st; 1325#ifndef __VISAGECPP__ 1326 return wxStat(strPath.c_str(), &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR); 1327#else 1328 // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only 1329 return wxStat(pszPathName, &st) == 0 && (st.st_mode == S_IFDIR); 1330#endif 1331 1332#endif // __WIN32__/!__WIN32__ 1333} 1334 1335// Get a temporary filename, opening and closing the file. 1336wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf) 1337{ 1338 wxString filename; 1339 if ( !wxGetTempFileName(prefix, filename) ) 1340 return NULL; 1341 1342 if ( buf ) 1343 wxStrcpy(buf, filename); 1344 else 1345 buf = MYcopystring(filename); 1346 1347 return buf; 1348} 1349 1350bool wxGetTempFileName(const wxString& prefix, wxString& buf) 1351{ 1352#if wxUSE_FILE 1353 buf = wxFileName::CreateTempFileName(prefix); 1354 1355 return !buf.empty(); 1356#else // !wxUSE_FILE 1357 wxUnusedVar(prefix); 1358 wxUnusedVar(buf); 1359 1360 return false; 1361#endif // wxUSE_FILE/!wxUSE_FILE 1362} 1363 1364// Get first file name matching given wild card. 1365 1366static wxDir *gs_dir = NULL; 1367static wxString gs_dirPath; 1368 1369wxString wxFindFirstFile(const wxChar *spec, int flags) 1370{ 1371 wxSplitPath(spec, &gs_dirPath, NULL, NULL); 1372 if ( gs_dirPath.empty() ) 1373 gs_dirPath = wxT("."); 1374 if ( !wxEndsWithPathSeparator(gs_dirPath ) ) 1375 gs_dirPath << wxFILE_SEP_PATH; 1376 1377 if (gs_dir) 1378 delete gs_dir; 1379 gs_dir = new wxDir(gs_dirPath); 1380 1381 if ( !gs_dir->IsOpened() ) 1382 { 1383 wxLogSysError(_("Can not enumerate files '%s'"), spec); 1384 return wxEmptyString; 1385 } 1386 1387 int dirFlags; 1388 switch (flags) 1389 { 1390 case wxDIR: dirFlags = wxDIR_DIRS; break; 1391 case wxFILE: dirFlags = wxDIR_FILES; break; 1392 default: dirFlags = wxDIR_DIRS | wxDIR_FILES; break; 1393 } 1394 1395 wxString result; 1396 gs_dir->GetFirst(&result, wxFileNameFromPath(wxString(spec)), dirFlags); 1397 if ( result.empty() ) 1398 { 1399 wxDELETE(gs_dir); 1400 return result; 1401 } 1402 1403 return gs_dirPath + result; 1404} 1405 1406wxString wxFindNextFile() 1407{ 1408 wxASSERT_MSG( gs_dir, wxT("You must call wxFindFirstFile before!") ); 1409 1410 wxString result; 1411 gs_dir->GetNext(&result); 1412 1413 if ( result.empty() ) 1414 { 1415 wxDELETE(gs_dir); 1416 return result; 1417 } 1418 1419 return gs_dirPath + result; 1420} 1421 1422 1423// Get current working directory. 1424// If buf is NULL, allocates space using new, else copies into buf. 1425// wxGetWorkingDirectory() is obsolete, use wxGetCwd() 1426// wxDoGetCwd() is their common core to be moved 1427// to wxGetCwd() once wxGetWorkingDirectory() will be removed. 1428// Do not expose wxDoGetCwd in headers! 1429 1430wxChar *wxDoGetCwd(wxChar *buf, int sz) 1431{ 1432#if defined(__WXPALMOS__) 1433 // TODO 1434 if(buf && sz>0) buf[0] = _T('\0'); 1435 return buf; 1436#elif defined(__WXWINCE__) 1437 // TODO 1438 if(buf && sz>0) buf[0] = _T('\0'); 1439 return buf; 1440#else 1441 if ( !buf ) 1442 { 1443 buf = new wxChar[sz + 1]; 1444 } 1445 1446 bool ok wxDUMMY_INITIALIZE(false); 1447 1448 // for the compilers which have Unicode version of _getcwd(), call it 1449 // directly, for the others call the ANSI version and do the translation 1450#if !wxUSE_UNICODE 1451 #define cbuf buf 1452#else // wxUSE_UNICODE 1453 bool needsANSI = true; 1454 1455 #if !defined(HAVE_WGETCWD) || wxUSE_UNICODE_MSLU 1456 char cbuf[_MAXPATHLEN]; 1457 #endif 1458 1459 #ifdef HAVE_WGETCWD 1460 #if wxUSE_UNICODE_MSLU 1461 if ( wxGetOsVersion() != wxOS_WINDOWS_9X ) 1462 #else 1463 char *cbuf = NULL; // never really used because needsANSI will always be false 1464 #endif 1465 { 1466 ok = _wgetcwd(buf, sz) != NULL; 1467 needsANSI = false; 1468 } 1469 #endif 1470 1471 if ( needsANSI ) 1472#endif // wxUSE_UNICODE 1473 { 1474 #if defined(_MSC_VER) || defined(__MINGW32__) 1475 ok = _getcwd(cbuf, sz) != NULL; 1476 #elif defined(__WXMAC__) && !defined(__DARWIN__) 1477 char lbuf[1024] ; 1478 if ( getcwd( lbuf , sizeof( lbuf ) ) ) 1479 { 1480 wxString res( lbuf , *wxConvCurrent ) ; 1481 wxStrcpy( buf , res ) ; 1482 ok = true; 1483 } 1484 else 1485 ok = false ; 1486 #elif defined(__OS2__) 1487 APIRET rc; 1488 ULONG ulDriveNum = 0; 1489 ULONG ulDriveMap = 0; 1490 rc = ::DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap); 1491 ok = rc == 0; 1492 if (ok) 1493 { 1494 sz -= 3; 1495 rc = ::DosQueryCurrentDir( 0 // current drive 1496 ,(PBYTE)cbuf + 3 1497 ,(PULONG)&sz 1498 ); 1499 cbuf[0] = char('A' + (ulDriveNum - 1)); 1500 cbuf[1] = ':'; 1501 cbuf[2] = '\\'; 1502 ok = rc == 0; 1503 } 1504 #else // !Win32/VC++ !Mac !OS2 1505 ok = getcwd(cbuf, sz) != NULL; 1506 #endif // platform 1507 1508 #if wxUSE_UNICODE && !(defined(__WXMAC__) && !defined(__DARWIN__)) 1509 // finally convert the result to Unicode if needed 1510 wxConvFile.MB2WC(buf, cbuf, sz); 1511 #endif // wxUSE_UNICODE 1512 } 1513 1514 if ( !ok ) 1515 { 1516 wxLogSysError(_("Failed to get the working directory")); 1517 1518 // VZ: the old code used to return "." on error which didn't make any 1519 // sense at all to me - empty string is a better error indicator 1520 // (NULL might be even better but I'm afraid this could lead to 1521 // problems with the old code assuming the return is never NULL) 1522 buf[0] = _T('\0'); 1523 } 1524 else // ok, but we might need to massage the path into the right format 1525 { 1526#ifdef __DJGPP__ 1527 // VS: DJGPP is a strange mix of DOS and UNIX API and returns paths 1528 // with / deliminers. We don't like that. 1529 for (wxChar *ch = buf; *ch; ch++) 1530 { 1531 if (*ch == wxT('/')) 1532 *ch = wxT('\\'); 1533 } 1534#endif // __DJGPP__ 1535 1536// MBN: we hope that in the case the user is compiling a GTK+/Motif app, 1537// he needs Unix as opposed to Win32 pathnames 1538#if defined( __CYGWIN__ ) && defined( __WINDOWS__ ) 1539 // another example of DOS/Unix mix (Cygwin) 1540 wxString pathUnix = buf; 1541#if wxUSE_UNICODE 1542 char bufA[_MAXPATHLEN]; 1543 cygwin_conv_to_full_win32_path(pathUnix.mb_str(wxConvFile), bufA); 1544 wxConvFile.MB2WC(buf, bufA, sz); 1545#else 1546 cygwin_conv_to_full_win32_path(pathUnix, buf); 1547#endif // wxUSE_UNICODE 1548#endif // __CYGWIN__ 1549 } 1550 1551 return buf; 1552 1553#if !wxUSE_UNICODE 1554 #undef cbuf 1555#endif 1556 1557#endif 1558 // __WXWINCE__ 1559} 1560 1561#if WXWIN_COMPATIBILITY_2_6 1562wxChar *wxGetWorkingDirectory(wxChar *buf, int sz) 1563{ 1564 return wxDoGetCwd(buf,sz); 1565} 1566#endif // WXWIN_COMPATIBILITY_2_6 1567 1568wxString wxGetCwd() 1569{ 1570 wxString str; 1571 wxDoGetCwd(wxStringBuffer(str, _MAXPATHLEN), _MAXPATHLEN); 1572 return str; 1573} 1574 1575bool wxSetWorkingDirectory(const wxString& d) 1576{ 1577#if defined(__OS2__) 1578 if (d[1] == ':') 1579 { 1580 ::DosSetDefaultDisk(1 + wxToupper(d[0]) - _T('A')); 1581 // do not call DosSetCurrentDir when just changing drive, 1582 // since it requires e.g. "d:." instead of "d:"! 1583 if (d.length() == 2) 1584 return true; 1585 } 1586 return (::DosSetCurrentDir((PSZ)d.c_str()) == 0); 1587#elif defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__) 1588 return (chdir(wxFNSTRINGCAST d.fn_str()) == 0); 1589#elif defined(__WINDOWS__) 1590 1591#ifdef __WIN32__ 1592#ifdef __WXWINCE__ 1593 // No equivalent in WinCE 1594 wxUnusedVar(d); 1595 return false; 1596#else 1597 return (bool)(SetCurrentDirectory(d) != 0); 1598#endif 1599#else 1600 // Must change drive, too. 1601 bool isDriveSpec = ((strlen(d) > 1) && (d[1] == ':')); 1602 if (isDriveSpec) 1603 { 1604 wxChar firstChar = d[0]; 1605 1606 // To upper case 1607 if (firstChar > 90) 1608 firstChar = firstChar - 32; 1609 1610 // To a drive number 1611 unsigned int driveNo = firstChar - 64; 1612 if (driveNo > 0) 1613 { 1614 unsigned int noDrives; 1615 _dos_setdrive(driveNo, &noDrives); 1616 } 1617 } 1618 bool success = (chdir(WXSTRINGCAST d) == 0); 1619 1620 return success; 1621#endif 1622 1623#endif 1624} 1625 1626// Get the OS directory if appropriate (such as the Windows directory). 1627// On non-Windows platform, probably just return the empty string. 1628wxString wxGetOSDirectory() 1629{ 1630#ifdef __WXWINCE__ 1631 return wxString(wxT("\\Windows")); 1632#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) 1633 wxChar buf[256]; 1634 GetWindowsDirectory(buf, 256); 1635 return wxString(buf); 1636#elif defined(__WXMAC__) 1637 return wxMacFindFolder(kOnSystemDisk, 'macs', false); 1638#else 1639 return wxEmptyString; 1640#endif 1641} 1642 1643bool wxEndsWithPathSeparator(const wxChar *pszFileName) 1644{ 1645 size_t len = wxStrlen(pszFileName); 1646 1647 return len && wxIsPathSeparator(pszFileName[len - 1]); 1648} 1649 1650// find a file in a list of directories, returns false if not found 1651bool wxFindFileInPath(wxString *pStr, const wxChar *pszPath, const wxChar *pszFile) 1652{ 1653 // we assume that it's not empty 1654 wxCHECK_MSG( !wxIsEmpty(pszFile), false, 1655 _T("empty file name in wxFindFileInPath")); 1656 1657 // skip path separator in the beginning of the file name if present 1658 if ( wxIsPathSeparator(*pszFile) ) 1659 pszFile++; 1660 1661 // copy the path (strtok will modify it) 1662 wxChar *szPath = new wxChar[wxStrlen(pszPath) + 1]; 1663 wxStrcpy(szPath, pszPath); 1664 1665 wxString strFile; 1666 wxChar *pc, *save_ptr; 1667 for ( pc = wxStrtok(szPath, wxPATH_SEP, &save_ptr); 1668 pc != NULL; 1669 pc = wxStrtok((wxChar *) NULL, wxPATH_SEP, &save_ptr) ) 1670 { 1671 // search for the file in this directory 1672 strFile = pc; 1673 if ( !wxEndsWithPathSeparator(pc) ) 1674 strFile += wxFILE_SEP_PATH; 1675 strFile += pszFile; 1676 1677 if ( wxFileExists(strFile) ) { 1678 *pStr = strFile; 1679 break; 1680 } 1681 } 1682 1683 // suppress warning about unused variable save_ptr when wxStrtok() is a 1684 // macro which throws away its third argument 1685 save_ptr = pc; 1686 1687 delete [] szPath; 1688 1689 return pc != NULL; // if true => we breaked from the loop 1690} 1691 1692void WXDLLEXPORT wxSplitPath(const wxChar *pszFileName, 1693 wxString *pstrPath, 1694 wxString *pstrName, 1695 wxString *pstrExt) 1696{ 1697 // it can be empty, but it shouldn't be NULL 1698 wxCHECK_RET( pszFileName, wxT("NULL file name in wxSplitPath") ); 1699 1700 wxFileName::SplitPath(pszFileName, pstrPath, pstrName, pstrExt); 1701} 1702 1703#if wxUSE_DATETIME 1704 1705time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename) 1706{ 1707 wxDateTime mtime; 1708 if ( !wxFileName(filename).GetTimes(NULL, &mtime, NULL) ) 1709 return (time_t)-1; 1710 1711 return mtime.GetTicks(); 1712} 1713 1714#endif // wxUSE_DATETIME 1715 1716 1717// Parses the filterStr, returning the number of filters. 1718// Returns 0 if none or if there's a problem. 1719// filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpeg" 1720 1721int WXDLLEXPORT wxParseCommonDialogsFilter(const wxString& filterStr, 1722 wxArrayString& descriptions, 1723 wxArrayString& filters) 1724{ 1725 descriptions.Clear(); 1726 filters.Clear(); 1727 1728 wxString str(filterStr); 1729 1730 wxString description, filter; 1731 int pos = 0; 1732 while( pos != wxNOT_FOUND ) 1733 { 1734 pos = str.Find(wxT('|')); 1735 if ( pos == wxNOT_FOUND ) 1736 { 1737 // if there are no '|'s at all in the string just take the entire 1738 // string as filter and make description empty for later autocompletion 1739 if ( filters.IsEmpty() ) 1740 { 1741 descriptions.Add(wxEmptyString); 1742 filters.Add(filterStr); 1743 } 1744 else 1745 { 1746 wxFAIL_MSG( _T("missing '|' in the wildcard string!") ); 1747 } 1748 1749 break; 1750 } 1751 1752 description = str.Left(pos); 1753 str = str.Mid(pos + 1); 1754 pos = str.Find(wxT('|')); 1755 if ( pos == wxNOT_FOUND ) 1756 { 1757 filter = str; 1758 } 1759 else 1760 { 1761 filter = str.Left(pos); 1762 str = str.Mid(pos + 1); 1763 } 1764 1765 descriptions.Add(description); 1766 filters.Add(filter); 1767 } 1768 1769#if defined(__WXMOTIF__) 1770 // split it so there is one wildcard per entry 1771 for( size_t i = 0 ; i < descriptions.GetCount() ; i++ ) 1772 { 1773 pos = filters[i].Find(wxT(';')); 1774 if (pos != wxNOT_FOUND) 1775 { 1776 // first split only filters 1777 descriptions.Insert(descriptions[i],i+1); 1778 filters.Insert(filters[i].Mid(pos+1),i+1); 1779 filters[i]=filters[i].Left(pos); 1780 1781 // autoreplace new filter in description with pattern: 1782 // C/C++ Files(*.cpp;*.c;*.h)|*.cpp;*.c;*.h 1783 // cause split into: 1784 // C/C++ Files(*.cpp)|*.cpp 1785 // C/C++ Files(*.c;*.h)|*.c;*.h 1786 // and next iteration cause another split into: 1787 // C/C++ Files(*.cpp)|*.cpp 1788 // C/C++ Files(*.c)|*.c 1789 // C/C++ Files(*.h)|*.h 1790 for ( size_t k=i;k<i+2;k++ ) 1791 { 1792 pos = descriptions[k].Find(filters[k]); 1793 if (pos != wxNOT_FOUND) 1794 { 1795 wxString before = descriptions[k].Left(pos); 1796 wxString after = descriptions[k].Mid(pos+filters[k].Len()); 1797 pos = before.Find(_T('('),true); 1798 if (pos>before.Find(_T(')'),true)) 1799 { 1800 before = before.Left(pos+1); 1801 before << filters[k]; 1802 pos = after.Find(_T(')')); 1803 int pos1 = after.Find(_T('(')); 1804 if (pos != wxNOT_FOUND && (pos<pos1 || pos1==wxNOT_FOUND)) 1805 { 1806 before << after.Mid(pos); 1807 descriptions[k] = before; 1808 } 1809 } 1810 } 1811 } 1812 } 1813 } 1814#endif 1815 1816 // autocompletion 1817 for( size_t j = 0 ; j < descriptions.GetCount() ; j++ ) 1818 { 1819 if ( descriptions[j].empty() && !filters[j].empty() ) 1820 { 1821 descriptions[j].Printf(_("Files (%s)"), filters[j].c_str()); 1822 } 1823 } 1824 1825 return filters.GetCount(); 1826} 1827 1828#if defined(__WINDOWS__) && !(defined(__UNIX__) || defined(__OS2__)) 1829 1830#ifndef INVALID_FILE_ATTRIBUTES 1831#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) 1832#endif 1833 1834static bool wxCheckWin32Permission(const wxString& path, DWORD access) 1835{ 1836 // quoting the MSDN: "To obtain a handle to a directory, call the 1837 // CreateFile function with the FILE_FLAG_BACKUP_SEMANTICS flag", but this 1838 // doesn't work under Win9x/ME but then it's not needed there anyhow 1839 const DWORD dwAttr = ::GetFileAttributes(path.fn_str()); 1840 if ( dwAttr == INVALID_FILE_ATTRIBUTES ) 1841 { 1842 // file probably doesn't exist at all 1843 return false; 1844 } 1845 1846 if ( wxGetOsVersion() == wxOS_WINDOWS_9X ) 1847 { 1848 // FAT directories always allow all access, even if they have the 1849 // readonly flag set, and FAT files can only be read-only 1850 return (dwAttr & FILE_ATTRIBUTE_DIRECTORY) || 1851 (access != GENERIC_WRITE || 1852 !(dwAttr & FILE_ATTRIBUTE_READONLY)); 1853 } 1854 1855 HANDLE h = ::CreateFile 1856 ( 1857 path.c_str(), 1858 access, 1859 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1860 NULL, 1861 OPEN_EXISTING, 1862 dwAttr & FILE_ATTRIBUTE_DIRECTORY 1863 ? FILE_FLAG_BACKUP_SEMANTICS 1864 : 0, 1865 NULL 1866 ); 1867 if ( h != INVALID_HANDLE_VALUE ) 1868 CloseHandle(h); 1869 1870 return h != INVALID_HANDLE_VALUE; 1871} 1872#endif // __WINDOWS__ 1873 1874bool wxIsWritable(const wxString &path) 1875{ 1876#if defined( __UNIX__ ) || defined(__OS2__) 1877 // access() will take in count also symbolic links 1878 return wxAccess(path.c_str(), W_OK) == 0; 1879#elif defined( __WINDOWS__ ) 1880 return wxCheckWin32Permission(path, GENERIC_WRITE); 1881#else 1882 wxUnusedVar(path); 1883 // TODO 1884 return false; 1885#endif 1886} 1887 1888bool wxIsReadable(const wxString &path) 1889{ 1890#if defined( __UNIX__ ) || defined(__OS2__) 1891 // access() will take in count also symbolic links 1892 return wxAccess(path.c_str(), R_OK) == 0; 1893#elif defined( __WINDOWS__ ) 1894 return wxCheckWin32Permission(path, GENERIC_READ); 1895#else 1896 wxUnusedVar(path); 1897 // TODO 1898 return false; 1899#endif 1900} 1901 1902bool wxIsExecutable(const wxString &path) 1903{ 1904#if defined( __UNIX__ ) || defined(__OS2__) 1905 // access() will take in count also symbolic links 1906 return wxAccess(path.c_str(), X_OK) == 0; 1907#elif defined( __WINDOWS__ ) 1908 return wxCheckWin32Permission(path, GENERIC_EXECUTE); 1909#else 1910 wxUnusedVar(path); 1911 // TODO 1912 return false; 1913#endif 1914} 1915 1916// Return the type of an open file 1917// 1918// Some file types on some platforms seem seekable but in fact are not. 1919// The main use of this function is to allow such cases to be detected 1920// (IsSeekable() is implemented as wxGetFileKind() == wxFILE_KIND_DISK). 1921// 1922// This is important for the archive streams, which benefit greatly from 1923// being able to seek on a stream, but which will produce corrupt archives 1924// if they unknowingly seek on a non-seekable stream. 1925// 1926// wxFILE_KIND_DISK is a good catch all return value, since other values 1927// disable features of the archive streams. Some other value must be returned 1928// for a file type that appears seekable but isn't. 1929// 1930// Known examples: 1931// * Pipes on Windows 1932// * Files on VMS with a record format other than StreamLF 1933// 1934wxFileKind wxGetFileKind(int fd) 1935{ 1936#if defined __WXMSW__ && !defined __WXWINCE__ && defined wxGetOSFHandle 1937 switch (::GetFileType(wxGetOSFHandle(fd)) & ~FILE_TYPE_REMOTE) 1938 { 1939 case FILE_TYPE_CHAR: 1940 return wxFILE_KIND_TERMINAL; 1941 case FILE_TYPE_DISK: 1942 return wxFILE_KIND_DISK; 1943 case FILE_TYPE_PIPE: 1944 return wxFILE_KIND_PIPE; 1945 } 1946 1947 return wxFILE_KIND_UNKNOWN; 1948 1949#elif defined(__UNIX__) 1950 if (isatty(fd)) 1951 return wxFILE_KIND_TERMINAL; 1952 1953 struct stat st; 1954 fstat(fd, &st); 1955 1956 if (S_ISFIFO(st.st_mode)) 1957 return wxFILE_KIND_PIPE; 1958 if (!S_ISREG(st.st_mode)) 1959 return wxFILE_KIND_UNKNOWN; 1960 1961 #if defined(__VMS__) 1962 if (st.st_fab_rfm != FAB$C_STMLF) 1963 return wxFILE_KIND_UNKNOWN; 1964 #endif 1965 1966 return wxFILE_KIND_DISK; 1967 1968#else 1969 #define wxFILEKIND_STUB 1970 (void)fd; 1971 return wxFILE_KIND_DISK; 1972#endif 1973} 1974 1975wxFileKind wxGetFileKind(FILE *fp) 1976{ 1977 // Note: The watcom rtl dll doesn't have fileno (the static lib does). 1978 // Should be fixed in version 1.4. 1979#if defined(wxFILEKIND_STUB) || wxONLY_WATCOM_EARLIER_THAN(1,4) 1980 (void)fp; 1981 return wxFILE_KIND_DISK; 1982#elif defined(__WINDOWS__) && !defined(__CYGWIN__) && !defined(__WATCOMC__) && !defined(__WINE__) 1983 return fp ? wxGetFileKind(_fileno(fp)) : wxFILE_KIND_UNKNOWN; 1984#else 1985 return fp ? wxGetFileKind(fileno(fp)) : wxFILE_KIND_UNKNOWN; 1986#endif 1987} 1988 1989 1990//------------------------------------------------------------------------ 1991// wild character routines 1992//------------------------------------------------------------------------ 1993 1994bool wxIsWild( const wxString& pattern ) 1995{ 1996 wxString tmp = pattern; 1997 wxChar *pat = WXSTRINGCAST(tmp); 1998 while (*pat) 1999 { 2000 switch (*pat++) 2001 { 2002 case wxT('?'): case wxT('*'): case wxT('['): case wxT('{'): 2003 return true; 2004 case wxT('\\'): 2005 if (!*pat++) 2006 return false; 2007 } 2008 } 2009 return false; 2010} 2011 2012/* 2013* Written By Douglas A. Lewis <dalewis@cs.Buffalo.EDU> 2014* 2015* The match procedure is public domain code (from ircII's reg.c) 2016* but modified to suit our tastes (RN: No "%" syntax I guess) 2017*/ 2018 2019bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special ) 2020{ 2021 if (text.empty()) 2022 { 2023 /* Match if both are empty. */ 2024 return pat.empty(); 2025 } 2026 2027 const wxChar *m = pat.c_str(), 2028 *n = text.c_str(), 2029 *ma = NULL, 2030 *na = NULL; 2031 int just = 0, 2032 acount = 0, 2033 count = 0; 2034 2035 if (dot_special && (*n == wxT('.'))) 2036 { 2037 /* Never match so that hidden Unix files 2038 * are never found. */ 2039 return false; 2040 } 2041 2042 for (;;) 2043 { 2044 if (*m == wxT('*')) 2045 { 2046 ma = ++m; 2047 na = n; 2048 just = 1; 2049 acount = count; 2050 } 2051 else if (*m == wxT('?')) 2052 { 2053 m++; 2054 if (!*n++) 2055 return false; 2056 } 2057 else 2058 { 2059 if (*m == wxT('\\')) 2060 { 2061 m++; 2062 /* Quoting "nothing" is a bad thing */ 2063 if (!*m) 2064 return false; 2065 } 2066 if (!*m) 2067 { 2068 /* 2069 * If we are out of both strings or we just 2070 * saw a wildcard, then we can say we have a 2071 * match 2072 */ 2073 if (!*n) 2074 return true; 2075 if (just) 2076 return true; 2077 just = 0; 2078 goto not_matched; 2079 } 2080 /* 2081 * We could check for *n == NULL at this point, but 2082 * since it's more common to have a character there, 2083 * check to see if they match first (m and n) and 2084 * then if they don't match, THEN we can check for 2085 * the NULL of n 2086 */ 2087 just = 0; 2088 if (*m == *n) 2089 { 2090 m++; 2091 count++; 2092 n++; 2093 } 2094 else 2095 { 2096 2097 not_matched: 2098 2099 /* 2100 * If there are no more characters in the 2101 * string, but we still need to find another 2102 * character (*m != NULL), then it will be 2103 * impossible to match it 2104 */ 2105 if (!*n) 2106 return false; 2107 2108 if (ma) 2109 { 2110 m = ma; 2111 n = ++na; 2112 count = acount; 2113 } 2114 else 2115 return false; 2116 } 2117 } 2118 } 2119} 2120 2121#ifdef __VISUALC__ 2122 #pragma warning(default:4706) // assignment within conditional expression 2123#endif // VC++ 2124