Panda3D

filename.cxx

00001 // Filename: filename.cxx
00002 // Created by:  drose (18Jan99)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "filename.h"
00016 #include "filename_assist.h"
00017 #include "dSearchPath.h"
00018 #include "executionEnvironment.h"
00019 #include "vector_string.h"
00020 #include "atomicAdjust.h"
00021 
00022 #include <stdio.h>  // For rename() and tempnam()
00023 #include <time.h>   // for clock() and time()
00024 #include <sys/stat.h>
00025 #include <algorithm>
00026 
00027 #ifdef PHAVE_UTIME_H
00028 #include <utime.h>
00029 
00030 // We assume we have these too.
00031 #include <errno.h>
00032 #include <fcntl.h>
00033 #endif
00034 
00035 #ifdef PHAVE_GLOB_H
00036   #include <glob.h>
00037   #ifndef GLOB_NOMATCH
00038     #define GLOB_NOMATCH -3
00039   #endif
00040 #endif
00041 
00042 #ifdef PHAVE_DIRENT_H
00043 #include <dirent.h>
00044 #endif
00045 
00046 // It's true that dtoolbase.h includes this already, but we include
00047 // this again in case we are building this file within ppremake.
00048 #ifdef PHAVE_UNISTD_H
00049 #include <unistd.h>
00050 #endif
00051 
00052 TextEncoder::Encoding Filename::_filesystem_encoding = TextEncoder::E_utf8;
00053 
00054 TVOLATILE AtomicAdjust::Pointer Filename::_home_directory;
00055 TVOLATILE AtomicAdjust::Pointer Filename::_temp_directory;
00056 TVOLATILE AtomicAdjust::Pointer Filename::_user_appdata_directory;
00057 TVOLATILE AtomicAdjust::Pointer Filename::_common_appdata_directory;
00058 TypeHandle Filename::_type_handle;
00059 
00060 #ifdef WIN32
00061 /* begin Win32-specific code */
00062 
00063 #ifdef WIN32_VC
00064 #include <direct.h>
00065 #include <windows.h>
00066 #include <shlobj.h>
00067 #include <io.h>
00068 #endif
00069 
00070 // The MSVC 6.0 Win32 SDK lacks the following definitions, so we define them
00071 // here for compatibility.
00072 #ifndef FILE_ATTRIBUTE_DEVICE
00073 #define FILE_ATTRIBUTE_DEVICE 0x00000040
00074 #endif
00075 
00076 // We might have been linked with the Cygwin dll.  This is ideal if it
00077 // is available, because it allows Panda to access all the Cygwin
00078 // mount definitions if they are in use.  If the Cygwin dll is not
00079 // available, we fall back to our own convention for converting
00080 // pathnames.
00081 #ifdef HAVE_CYGWIN
00082 extern "C" void cygwin_conv_to_win32_path(const char *path, char *win32);
00083 extern "C" void cygwin_conv_to_posix_path(const char *path, char *posix);
00084 #endif
00085 
00086 // Windows uses the convention \\hostname\path\to\file to represent a
00087 // pathname to a file on another share.  This redefines a pathname to
00088 // be something more complicated than a sequence of directory names
00089 // separated by slashes.  The Unix convention to represent the same
00090 // thing is, like everything else, to graft the reference to the
00091 // remote hostname into the one global filesystem, with something like
00092 // /hosts/hostname/path/to/file.  We observe the Unix convention for
00093 // internal names used in Panda; this makes operations like
00094 // Filename::get_dirname() simpler and more internally consistent.
00095 
00096 // This string hard-defines the prefix that we use internally to
00097 // indicate that the next directory component name should be treated
00098 // as a hostname.  It might be nice to use a ConfigVariable for this,
00099 // except that we haven't defined ConfigVariable by this point (and
00100 // indeed we can't, since we need to have a Filename class already
00101 // created in order to read the first config file).  Windows purists
00102 // might be tempted to define this to a double slash so that internal
00103 // Panda filenames more closely resemble their Windows counterparts.
00104 // That might actually work, but it will cause problems with
00105 // Filename::standardize().
00106 
00107 // We use const char * instead of string to avoid static-init ordering
00108 // issues.
00109 static const char *hosts_prefix = "/hosts/";
00110 static size_t hosts_prefix_length = 7;
00111 
00112 static string
00113 front_to_back_slash(const string &str) {
00114   string result = str;
00115   string::iterator si;
00116   for (si = result.begin(); si != result.end(); ++si) {
00117     if ((*si) == '/') {
00118       (*si) = '\\';
00119     }
00120   }
00121 
00122   return result;
00123 }
00124 
00125 static string
00126 back_to_front_slash(const string &str) {
00127   string result = str;
00128   string::iterator si;
00129   for (si = result.begin(); si != result.end(); ++si) {
00130     if ((*si) == '\\') {
00131       (*si) = '/';
00132     }
00133   }
00134 
00135   return result;
00136 }
00137 
00138 static const string &
00139 get_panda_root() {
00140   static string *panda_root = NULL;
00141 
00142   if (panda_root == NULL) {
00143     panda_root = new string;
00144     const char *envvar = getenv("PANDA_ROOT");
00145     if (envvar != (const char *)NULL) {
00146       (*panda_root) = front_to_back_slash(envvar);
00147     }
00148 
00149     // Ensure the string ends in a backslash.  If PANDA_ROOT is empty
00150     // or undefined, this function must return a single backslash--not
00151     // an empty string--since this prefix is used to replace a leading
00152     // slash in Filename::to_os_specific().
00153     if ((*panda_root).empty() || (*panda_root)[(*panda_root).length() - 1] != '\\') {
00154       (*panda_root) += '\\';
00155     }
00156   }
00157 
00158   return (*panda_root);
00159 }
00160 
00161 static string
00162 convert_pathname(const string &unix_style_pathname) {
00163   if (unix_style_pathname.empty()) {
00164     return string();
00165   }
00166 
00167   // To convert from a Unix-style pathname to a Windows-style
00168   // pathname, we need to change all forward slashes to backslashes.
00169   // We might need to add a prefix as well, since Windows pathnames
00170   // typically begin with a drive letter.
00171 
00172   // By convention, if the top directory name consists of just one
00173   // letter, we treat that as a drive letter and map the rest of the
00174   // filename accordingly.  On the other hand, if the top directory
00175   // name consists of more than one letter, we assume this is a file
00176   // within some predefined tree whose root is given by the
00177   // environment variable "PANDA_ROOT", or if that is not defined,
00178   // "CYGWIN_ROOT" (for backward compatibility).
00179   string windows_pathname;
00180 
00181   if (unix_style_pathname[0] != '/') {
00182     // It doesn't even start from the root, so we don't have to do
00183     // anything fancy--relative pathnames are the same in Windows as
00184     // in Unix, except for the direction of the slashes.
00185     windows_pathname = front_to_back_slash(unix_style_pathname);
00186 
00187   } else if (unix_style_pathname.length() >= 2 &&
00188              isalpha(unix_style_pathname[1]) &&
00189              (unix_style_pathname.length() == 2 || unix_style_pathname[2] == '/')) {
00190     // This pathname begins with a slash and a single letter.  That
00191     // must be the drive letter.
00192 
00193     string remainder = unix_style_pathname.substr(2);
00194     if (remainder.empty()) {
00195       // There's a difference between "C:" and "C:/".
00196       remainder = "/";
00197     }
00198     remainder = front_to_back_slash(remainder);
00199 
00200     // We have to cast the result of toupper() to (char) to help some
00201     // compilers (e.g. Cygwin's gcc 2.95.3) happy; so that they do not
00202     // confuse this string constructor with one that takes two
00203     // iterators.
00204     windows_pathname =
00205       string(1, (char)toupper(unix_style_pathname[1])) + ":" + remainder;
00206 
00207   } else if (unix_style_pathname.length() > hosts_prefix_length &&
00208              unix_style_pathname.substr(0, hosts_prefix_length) == hosts_prefix) {
00209     // A filename like /hosts/fooby gets turned into \\fooby.
00210     windows_pathname = "\\\\" + front_to_back_slash(unix_style_pathname.substr(hosts_prefix_length));
00211     
00212   } else {
00213     // It starts with a slash, but the first part is not a single
00214     // letter.
00215 
00216 #ifdef HAVE_CYGWIN
00217     // Use Cygwin to convert it if possible.
00218     char result[4096] = "";
00219     cygwin_conv_to_win32_path(unix_style_pathname.c_str(), result);
00220     windows_pathname = result;
00221 
00222 #else  // HAVE_CYGWIN
00223     // Without Cygwin, just prefix $PANDA_ROOT.
00224     windows_pathname = get_panda_root();
00225     windows_pathname += front_to_back_slash(unix_style_pathname.substr(1));
00226 
00227 #endif  // HAVE_CYGWIN
00228   }
00229 
00230   return windows_pathname;
00231 }
00232 
00233 static string
00234 convert_dso_pathname(const string &unix_style_pathname) {
00235   // If the extension is .so, change it to .dll.
00236   size_t dot = unix_style_pathname.rfind('.');
00237   if (dot == string::npos ||
00238       unix_style_pathname.find('/', dot) != string::npos) {
00239     // No filename extension.
00240     return convert_pathname(unix_style_pathname);
00241   }
00242   if (unix_style_pathname.substr(dot) != ".so") {
00243     // Some other extension.
00244     return convert_pathname(unix_style_pathname);
00245   }
00246 
00247   string dll_basename = unix_style_pathname.substr(0, dot);
00248 
00249 #ifdef _DEBUG
00250   // If we're building a debug version, all the dso files we link in
00251   // must be named file_d.dll.  This does prohibit us from linking in
00252   // external dso files, generated outside of the Panda build system,
00253   // that don't follow this _d convention.  Maybe we need a separate
00254   // convert_system_dso_pathname() function.
00255 
00256   // We can't simply check to see if the file exists, because this
00257   // might not be a full path to the dso filename--it might be
00258   // somewhere on the LD_LIBRARY_PATH, or on PATH, or any of a number
00259   // of nutty places.
00260 
00261   return convert_pathname(dll_basename + "_d.dll");
00262 #else
00263   return convert_pathname(dll_basename + ".dll");
00264 #endif
00265 }
00266 
00267 static string
00268 convert_executable_pathname(const string &unix_style_pathname) {
00269   // If the extension is not .exe, append .exe.
00270   size_t dot = unix_style_pathname.rfind('.');
00271   if (dot == string::npos ||
00272       unix_style_pathname.find('/', dot) != string::npos) {
00273     // No filename extension.
00274     return convert_pathname(unix_style_pathname + ".exe");
00275   }
00276   if (unix_style_pathname.substr(dot) != ".exe") {
00277     // Some other extension.
00278     return convert_pathname(unix_style_pathname + ".exe");
00279   }
00280 
00281   return convert_pathname(unix_style_pathname);
00282 }
00283 #endif //WIN32
00284 
00285 ////////////////////////////////////////////////////////////////////
00286 //     Function: Filename::Constructor
00287 //       Access: Published
00288 //  Description: This constructor composes the filename out of a
00289 //               directory part and a basename part.  It will insert
00290 //               an intervening '/' if necessary.
00291 ////////////////////////////////////////////////////////////////////
00292 Filename::
00293 Filename(const Filename &dirname, const Filename &basename) {
00294   if (dirname.empty()) {
00295     (*this) = basename;
00296   } else {
00297     _flags = basename._flags;
00298     string dirpath = dirname.get_fullpath();
00299     if (dirpath[dirpath.length() - 1] == '/') {
00300       (*this) = dirpath + basename.get_fullpath();
00301     } else {
00302       (*this) = dirpath + "/" + basename.get_fullpath();
00303     }
00304   }
00305 }
00306 
00307 #ifdef HAVE_PYTHON
00308 ////////////////////////////////////////////////////////////////////
00309 //     Function: Filename::__reduce__
00310 //       Access: Published
00311 //  Description: This special Python method is implement to provide
00312 //               support for the pickle module.
00313 ////////////////////////////////////////////////////////////////////
00314 PyObject *Filename::
00315 __reduce__(PyObject *self) const {
00316   // We should return at least a 2-tuple, (Class, (args)): the
00317   // necessary class object whose constructor we should call
00318   // (e.g. this), and the arguments necessary to reconstruct this
00319   // object.
00320   PyObject *this_class = PyObject_Type(self);
00321   if (this_class == NULL) {
00322     return NULL;
00323   }
00324 
00325   PyObject *result = Py_BuildValue("(O(s))", this_class, c_str());
00326   Py_DECREF(this_class);
00327   return result;
00328 }
00329 #endif  // HAVE_PYTHON
00330 
00331 ////////////////////////////////////////////////////////////////////
00332 //     Function: Filename::from_os_specific
00333 //       Access: Published, Static
00334 //  Description: This named constructor returns a Panda-style filename
00335 //               (that is, using forward slashes, and no drive letter)
00336 //               based on the supplied filename string that describes
00337 //               a filename in the local system conventions (for
00338 //               instance, on Windows, it may use backslashes or begin
00339 //               with a drive letter and a colon).
00340 //
00341 //               Use this function to create a Filename from an
00342 //               externally-given filename string.  Use
00343 //               to_os_specific() again later to reconvert it back to
00344 //               the local operating system's conventions.
00345 //
00346 //               This function will do the right thing even if the
00347 //               filename is partially local conventions and partially
00348 //               Panda conventions; e.g. some backslashes and some
00349 //               forward slashes.
00350 ////////////////////////////////////////////////////////////////////
00351 Filename Filename::
00352 from_os_specific(const string &os_specific, Filename::Type type) {
00353 #ifdef WIN32
00354   string result = back_to_front_slash(os_specific);
00355   const string &panda_root = get_panda_root();
00356 
00357   // If the initial prefix is the same as panda_root, remove it.
00358   if (!panda_root.empty() && panda_root != string("\\") && 
00359       panda_root.length() < result.length()) {
00360     bool matches = true;
00361     size_t p;
00362     for (p = 0; p < panda_root.length() && matches; ++p) {
00363       char c = tolower(panda_root[p]);
00364       if (c == '\\') {
00365         c = '/';
00366       }
00367       matches = (c == tolower(result[p]));
00368     }
00369 
00370     if (matches) {
00371       // The initial prefix matches!  Replace the initial bit with a
00372       // leading slash.
00373       result = result.substr(panda_root.length());
00374       assert(!result.empty());
00375       if (result[0] != '/') {
00376         result = '/' + result;
00377       }
00378       Filename filename(result);
00379       filename.set_type(type);
00380       return filename;
00381     }
00382   }
00383 
00384   // All right, the initial prefix was not under panda_root.  But
00385   // maybe it begins with a drive letter.
00386   if (result.size() >= 3 && isalpha(result[0]) &&
00387       result[1] == ':' && result[2] == '/') {
00388     result[1] = tolower(result[0]);
00389     result[0] = '/';
00390 
00391     // If there's *just* a slash following the drive letter, go ahead
00392     // and trim it.
00393     if (result.size() == 3) {
00394       result = result.substr(0, 2);
00395     }
00396 
00397   } else if (result.substr(0, 2) == "//") {
00398     // If the initial prefix is a double slash, convert it to /hosts/.
00399     result = hosts_prefix + result.substr(2);
00400   }
00401 
00402   Filename filename(result);
00403   filename.set_type(type);
00404   return filename;
00405 #else  // WIN32
00406   // Generic Unix-style filenames--no conversion necessary.
00407   Filename filename(os_specific);
00408   filename.set_type(type);
00409   return filename;
00410 #endif  // WIN32
00411 }
00412 
00413 ////////////////////////////////////////////////////////////////////
00414 //     Function: Filename::from_os_specific_w
00415 //       Access: Published, Static
00416 //  Description: The wide-string variant of from_os_specific().
00417 //               Returns a new Filename, converted from an os-specific
00418 //               wide-character string.
00419 ////////////////////////////////////////////////////////////////////
00420 Filename Filename::
00421 from_os_specific_w(const wstring &os_specific, Filename::Type type) {
00422   TextEncoder encoder;
00423   encoder.set_encoding(get_filesystem_encoding());
00424   encoder.set_wtext(os_specific);
00425   return from_os_specific(encoder.get_text(), type);
00426 }
00427 
00428 ////////////////////////////////////////////////////////////////////
00429 //     Function: Filename::expand_from
00430 //       Access: Published, Static
00431 //  Description: Returns the same thing as from_os_specific(), but
00432 //               embedded environment variable references
00433 //               (e.g. "$DMODELS/foo.txt") are expanded out.  It also
00434 //               automatically elevates the file to its true case if
00435 //               needed.
00436 ////////////////////////////////////////////////////////////////////
00437 Filename Filename::
00438 expand_from(const string &os_specific, Filename::Type type) {
00439   Filename file = from_os_specific(ExecutionEnvironment::expand_string(os_specific),
00440                                    type);
00441   file.make_true_case();
00442   return file;
00443 }
00444 
00445 ////////////////////////////////////////////////////////////////////
00446 //     Function: Filename::temporary
00447 //       Access: Published, Static
00448 //  Description: Generates a temporary filename within the indicated
00449 //               directory, using the indicated prefix.  If the
00450 //               directory is empty, a system-defined directory is
00451 //               chosen instead.
00452 //
00453 //               The generated filename did not exist when the
00454 //               Filename checked, but since it does not specifically
00455 //               create the file, it is possible that another process
00456 //               could simultaneously create a file by the same name.
00457 ////////////////////////////////////////////////////////////////////
00458 Filename Filename::
00459 temporary(const string &dirname, const string &prefix, const string &suffix,
00460           Type type) {
00461   Filename fdirname = dirname;
00462 #ifdef WIN32
00463   // The Windows tempnam() function doesn't do a good job of choosing
00464   // a temporary directory.  Choose one ourselves.
00465   if (fdirname.empty()) {
00466     fdirname = Filename::get_temp_directory();
00467   }
00468 #endif
00469 
00470   if (fdirname.empty()) {
00471     // If we are not given a dirname, use the system tempnam()
00472     // function to create a system-defined temporary filename.
00473     char *name = tempnam(NULL, prefix.c_str());
00474     Filename result = Filename::from_os_specific(name);
00475     free(name);
00476     result.set_type(type);
00477     return result;
00478   }
00479 
00480   // If we *are* given a dirname, then use our own algorithm to make
00481   // up a filename within that dirname.  We do that because the system
00482   // tempnam() (for instance, under Windows) may ignore the dirname.
00483 
00484   Filename result;
00485   do {
00486     // We take the time of day and multiply it by the process time.
00487     // This will give us a very large number, of which we take the
00488     // bottom 24 bits and generate a 6-character hex code.
00489     int hash = (clock() * time(NULL)) & 0xffffff;
00490     char hex_code[10];
00491     sprintf(hex_code, "%06x", hash);
00492     result = Filename(fdirname, Filename(prefix + hex_code + suffix));
00493     result.set_type(type);
00494   } while (result.exists());
00495 
00496   return result;
00497 }
00498 
00499 ////////////////////////////////////////////////////////////////////
00500 //     Function: Filename::get_home_directory
00501 //       Access: Published
00502 //  Description: Returns a path to the user's home directory, if such
00503 //               a thing makes sense in the current OS, or to the
00504 //               nearest equivalent.  This may or may not be directly
00505 //               writable by the application.
00506 ////////////////////////////////////////////////////////////////////
00507 const Filename &Filename::
00508 get_home_directory() {
00509   if (AtomicAdjust::get_ptr(_home_directory) == NULL) {
00510     Filename home_directory;
00511 
00512     // In all environments, check $HOME first.
00513     char *home = getenv("HOME");
00514     if (home != (char *)NULL) {
00515       Filename dirname = from_os_specific(home);
00516       if (dirname.is_directory()) {
00517         if (dirname.make_canonical()) {
00518           home_directory = dirname;
00519         }
00520       }
00521     }
00522 
00523     if (home_directory.empty()) {
00524 #ifdef WIN32
00525       wchar_t buffer[MAX_PATH];
00526       
00527       // On Windows, fall back to the "My Documents" folder.
00528       if (SHGetSpecialFolderPathW(NULL, buffer, CSIDL_PERSONAL, true)) {
00529         Filename dirname = from_os_specific_w(buffer);
00530         if (dirname.is_directory()) {
00531           if (dirname.make_canonical()) {
00532             home_directory = dirname;
00533           }
00534         }
00535       }
00536 
00537 #elif defined(IS_OSX)
00538       home_directory = get_osx_home_directory();
00539       
00540 #else
00541       // Posix case: check /etc/passwd?
00542       
00543 #endif  // WIN32
00544     }
00545       
00546     if (home_directory.empty()) {
00547       // Fallback case.
00548       home_directory = ExecutionEnvironment::get_cwd();
00549     }
00550 
00551     Filename *newdir = new Filename(home_directory);
00552     if (AtomicAdjust::compare_and_exchange_ptr(_home_directory, NULL, newdir) != NULL) {
00553       // Didn't store it.  Must have been stored by someone else.
00554       assert(_home_directory != NULL);
00555       delete newdir;
00556     }
00557   }
00558   
00559   return (*(Filename *)_home_directory);
00560 }
00561 
00562 ////////////////////////////////////////////////////////////////////
00563 //     Function: Filename::get_temp_directory
00564 //       Access: Published
00565 //  Description: Returns a path to a system-defined temporary
00566 //               directory.
00567 ////////////////////////////////////////////////////////////////////
00568 const Filename &Filename::
00569 get_temp_directory() {
00570   if (AtomicAdjust::get_ptr(_temp_directory) == NULL) {
00571     Filename temp_directory;
00572 
00573 #ifdef WIN32
00574     static const size_t buffer_size = 4096;
00575     wchar_t buffer[buffer_size];
00576     if (GetTempPathW(buffer_size, buffer) != 0) {
00577       Filename dirname = from_os_specific_w(buffer);
00578       if (dirname.is_directory()) {
00579         if (dirname.make_canonical()) {
00580           temp_directory = dirname;
00581         }
00582       }
00583     }
00584 
00585 #elif defined(IS_OSX)
00586     temp_directory = get_osx_temp_directory();
00587 
00588 #else
00589     // Posix case.
00590     temp_directory = "/tmp";
00591 #endif  // WIN32
00592 
00593     if (temp_directory.empty()) {
00594       // Fallback case.
00595       temp_directory = ExecutionEnvironment::get_cwd();
00596     }
00597 
00598     Filename *newdir = new Filename(temp_directory);
00599     if (AtomicAdjust::compare_and_exchange_ptr(_temp_directory, NULL, newdir) != NULL) {
00600       // Didn't store it.  Must have been stored by someone else.
00601       assert(_temp_directory != NULL);
00602       delete newdir;
00603     }
00604   }
00605 
00606   return (*(Filename *)_temp_directory);
00607 }
00608 
00609 ////////////////////////////////////////////////////////////////////
00610 //     Function: Filename::get_user_appdata_directory
00611 //       Access: Published
00612 //  Description: Returns a path to a system-defined directory
00613 //               appropriate for creating a subdirectory for storing
00614 //               application-specific data, specific to the current
00615 //               user.
00616 ////////////////////////////////////////////////////////////////////
00617 const Filename &Filename::
00618 get_user_appdata_directory() {
00619   if (AtomicAdjust::get_ptr(_user_appdata_directory) == NULL) {
00620     Filename user_appdata_directory;
00621 
00622 #ifdef WIN32
00623     wchar_t buffer[MAX_PATH];
00624 
00625     if (SHGetSpecialFolderPathW(NULL, buffer, CSIDL_LOCAL_APPDATA, true)) {
00626       Filename dirname = from_os_specific_w(buffer);
00627       if (dirname.is_directory()) {
00628         if (dirname.make_canonical()) {
00629           user_appdata_directory = dirname;
00630         }
00631       }
00632     }
00633 
00634 #elif defined(IS_OSX)
00635     user_appdata_directory = get_osx_user_appdata_directory();
00636 
00637 #else
00638     // Posix case.
00639     user_appdata_directory = get_home_directory();
00640 
00641 #endif  // WIN32
00642 
00643     if (user_appdata_directory.empty()) {
00644       // Fallback case.
00645       user_appdata_directory = ExecutionEnvironment::get_cwd();
00646     }
00647 
00648     Filename *newdir = new Filename(user_appdata_directory);
00649     if (AtomicAdjust::compare_and_exchange_ptr(_user_appdata_directory, NULL, newdir) != NULL) {
00650       // Didn't store it.  Must have been stored by someone else.
00651       assert(_user_appdata_directory != NULL);
00652       delete newdir;
00653     }
00654   }
00655 
00656   return (*(Filename *)_user_appdata_directory);
00657 }
00658 
00659 ////////////////////////////////////////////////////////////////////
00660 //     Function: Filename::get_common_appdata_directory
00661 //       Access: Published
00662 //  Description: Returns a path to a system-defined directory
00663 //               appropriate for creating a subdirectory for storing
00664 //               application-specific data, common to all users.
00665 ////////////////////////////////////////////////////////////////////
00666 const Filename &Filename::
00667 get_common_appdata_directory() {
00668   if (AtomicAdjust::get_ptr(_common_appdata_directory) == NULL) {
00669     Filename common_appdata_directory;
00670 
00671 #ifdef WIN32
00672     wchar_t buffer[MAX_PATH];
00673 
00674     if (SHGetSpecialFolderPathW(NULL, buffer, CSIDL_COMMON_APPDATA, true)) {
00675       Filename dirname = from_os_specific_w(buffer);
00676       if (dirname.is_directory()) {
00677         if (dirname.make_canonical()) {
00678           common_appdata_directory = dirname;
00679         }
00680       }
00681     }
00682 
00683 #elif defined(IS_OSX)
00684     common_appdata_directory = get_osx_common_appdata_directory();
00685 
00686 #else
00687     // Posix case.
00688     common_appdata_directory = "/var";
00689 #endif  // WIN32
00690 
00691     if (common_appdata_directory.empty()) {
00692       // Fallback case.
00693       common_appdata_directory = ExecutionEnvironment::get_cwd();
00694     }
00695 
00696     Filename *newdir = new Filename(common_appdata_directory);
00697     if (AtomicAdjust::compare_and_exchange_ptr(_common_appdata_directory, NULL, newdir) != NULL) {
00698       // Didn't store it.  Must have been stored by someone else.
00699       assert(_common_appdata_directory != NULL);
00700       delete newdir;
00701     }
00702   }
00703 
00704   return (*(Filename *)_common_appdata_directory);
00705 }
00706 
00707 ////////////////////////////////////////////////////////////////////
00708 //     Function: Filename::set_fullpath
00709 //       Access: Published
00710 //  Description: Replaces the entire filename: directory, basename,
00711 //               extension.  This can also be achieved with the
00712 //               assignment operator.
00713 ////////////////////////////////////////////////////////////////////
00714 void Filename::
00715 set_fullpath(const string &s) {
00716   (*this) = s;
00717 }
00718 
00719 ////////////////////////////////////////////////////////////////////
00720 //     Function: Filename::set_dirname
00721 //       Access: Published
00722 //  Description: Replaces the directory part of the filename.  This is
00723 //               everything in the filename up to, but not including
00724 //               the rightmost slash.
00725 ////////////////////////////////////////////////////////////////////
00726 void Filename::
00727 set_dirname(const string &s) {
00728   if (s.empty()) {
00729     // Remove the directory prefix altogether.
00730     _filename.replace(0, _basename_start, "");
00731 
00732     int length_change = - ((int)_basename_start);
00733 
00734     _dirname_end = 0;
00735     _basename_start += length_change;
00736     _basename_end += length_change;
00737     _extension_start += length_change;
00738 
00739   } else {
00740     // Replace the existing directory prefix, or insert a new one.
00741 
00742     // We build the string ss to include the terminal slash.
00743     string ss;
00744     if (s[s.length()-1] == '/') {
00745       ss = s;
00746     } else {
00747       ss = s+'/';
00748     }
00749 
00750     int length_change = ss.length() - _basename_start;
00751 
00752     _filename.replace(0, _basename_start, ss);
00753 
00754     _dirname_end = ss.length() - 1;
00755 
00756     // An exception: if the dirname string was the single slash, the
00757     // dirname includes that slash.
00758     if (ss.length() == 1) {
00759       _dirname_end = 1;
00760     }
00761 
00762     _basename_start += length_change;
00763 
00764     if (_basename_end != string::npos) {
00765       _basename_end += length_change;
00766       _extension_start += length_change;
00767     }
00768   }
00769   locate_hash();
00770 }
00771 
00772 ////////////////////////////////////////////////////////////////////
00773 //     Function: Filename::set_basename
00774 //       Access: Published
00775 //  Description: Replaces the basename part of the filename.  This is
00776 //               everything in the filename after the rightmost slash,
00777 //               including any extensions.
00778 ////////////////////////////////////////////////////////////////////
00779 void Filename::
00780 set_basename(const string &s) {
00781   _filename.replace(_basename_start, string::npos, s);
00782   locate_extension();
00783   locate_hash();
00784 }
00785 
00786 
00787 ////////////////////////////////////////////////////////////////////
00788 //     Function: Filename::set_fullpath_wo_extension
00789 //       Access: Published
00790 //  Description: Replaces the full filename--directory and basename
00791 //               parts--except for the extension.
00792 ////////////////////////////////////////////////////////////////////
00793 void Filename::
00794 set_fullpath_wo_extension(const string &s) {
00795   int length_change = s.length() - _basename_end;
00796 
00797   _filename.replace(0, _basename_end, s);
00798 
00799   if (_basename_end != string::npos) {
00800     _basename_end += length_change;
00801     _extension_start += length_change;
00802   }
00803   locate_hash();
00804 }
00805 
00806 
00807 ////////////////////////////////////////////////////////////////////
00808 //     Function: Filename::set_basename_wo_extension
00809 //       Access: Published
00810 //  Description: Replaces the basename part of the filename, without
00811 //               the file extension.
00812 ////////////////////////////////////////////////////////////////////
00813 void Filename::
00814 set_basename_wo_extension(const string &s) {
00815   int length_change = s.length() - (_basename_end - _basename_start);
00816 
00817   if (_basename_end == string::npos) {
00818     _filename.replace(_basename_start, string::npos, s);
00819 
00820   } else {
00821     _filename.replace(_basename_start, _basename_end - _basename_start, s);
00822 
00823     _basename_end += length_change;
00824     _extension_start += length_change;
00825   }
00826   locate_hash();
00827 }
00828 
00829 
00830 ////////////////////////////////////////////////////////////////////
00831 //     Function: Filename::set_extension
00832 //       Access: Published
00833 //  Description: Replaces the file extension.  This is everything after
00834 //               the rightmost dot, if there is one, or the empty
00835 //               string if there is not.
00836 ////////////////////////////////////////////////////////////////////
00837 void Filename::
00838 set_extension(const string &s) {
00839   if (s.empty()) {
00840     // Remove the extension altogether.
00841     if (_basename_end != string::npos) {
00842       _filename.replace(_basename_end, string::npos, "");
00843       _basename_end = string::npos;
00844       _extension_start = string::npos;
00845     }
00846 
00847   } else if (_basename_end == string::npos) {
00848     // Insert an extension where there was none before.
00849     _basename_end = _filename.length();
00850     _extension_start = _filename.length() + 1;
00851     _filename += '.' + s;
00852 
00853   } else {
00854     // Replace an existing extension.
00855     _filename.replace(_extension_start, string::npos, s);
00856   }
00857   locate_hash();
00858 }
00859 
00860 ////////////////////////////////////////////////////////////////////
00861 //     Function: Filename::get_filename_index
00862 //       Access: Published
00863 //  Description: If the pattern flag is set for this Filename and the
00864 //               filename string actually includes a sequence of hash
00865 //               marks, then this returns a new Filename with the
00866 //               sequence of hash marks replaced by the indicated
00867 //               index number.
00868 //
00869 //               If the pattern flag is not set for this Filename or
00870 //               it does not contain a sequence of hash marks, this
00871 //               quietly returns the original filename.
00872 ////////////////////////////////////////////////////////////////////
00873 Filename Filename::
00874 get_filename_index(int index) const {
00875   Filename file(*this);
00876 
00877   if (_hash_end != _hash_start) {
00878     ostringstream strm;
00879     strm << _filename.substr(0, _hash_start) 
00880          << setw(_hash_end - _hash_start) << setfill('0') << index
00881          << _filename.substr(_hash_end);
00882     file.set_fullpath(strm.str());
00883   }
00884   file.set_pattern(false);
00885 
00886   return file;
00887 }
00888 
00889 ////////////////////////////////////////////////////////////////////
00890 //     Function: Filename::set_hash_to_end
00891 //       Access: Published
00892 //  Description: Replaces the part of the filename from the beginning
00893 //               of the hash sequence to the end of the filename.
00894 ////////////////////////////////////////////////////////////////////
00895 void Filename::
00896 set_hash_to_end(const string &s) {
00897   _filename.replace(_hash_start, string::npos, s);
00898 
00899   locate_basename();
00900   locate_extension();
00901   locate_hash();
00902 }
00903 
00904 ////////////////////////////////////////////////////////////////////
00905 //     Function: Filename::extract_components
00906 //       Access: Published
00907 //  Description: Extracts out the individual directory components of
00908 //               the path into a series of strings.  get_basename()
00909 //               will be the last component stored in the vector.
00910 //               Note that no distinction is made by this method
00911 //               between a leading slash and no leading slash, but you
00912 //               can call is_local() to differentiate the two cases.
00913 ////////////////////////////////////////////////////////////////////
00914 void Filename::
00915 extract_components(vector_string &components) const {
00916   components.clear();
00917 
00918   size_t p = 0;
00919   if (!_filename.empty() && _filename[0] == '/') {
00920     // Skip the leading slash.
00921     p = 1;
00922   }
00923   while (p < _filename.length()) {
00924     size_t q = _filename.find('/', p);
00925     if (q == string::npos) {
00926       components.push_back(_filename.substr(p));
00927       return;
00928     }
00929     components.push_back(_filename.substr(p, q - p));
00930     p = q + 1;
00931   }
00932 
00933   // A trailing slash means we have an empty get_basename().
00934   components.push_back(string());
00935 }
00936 
00937 ////////////////////////////////////////////////////////////////////
00938 //     Function: Filename::standardize
00939 //       Access: Published
00940 //  Description: Converts the filename to standard form by replacing
00941 //               consecutive slashes with a single slash, removing a
00942 //               trailing slash if present, and backing up over ../
00943 //               sequences within the filename where possible.
00944 ////////////////////////////////////////////////////////////////////
00945 void Filename::
00946 standardize() {
00947   assert(!_filename.empty());
00948   if (_filename == ".") {
00949     // Don't change a single dot; this refers to the current directory.
00950     return;
00951   }
00952 
00953   vector_string components;
00954 
00955   // Pull off the components of the filename one at a time.
00956   bool global = (_filename[0] == '/');
00957 
00958   size_t p = 0;
00959   while (p < _filename.length() && _filename[p] == '/') {
00960     p++;
00961   }
00962   while (p < _filename.length()) {
00963     size_t slash = _filename.find('/', p);
00964     string component = _filename.substr(p, slash - p);
00965     if (component == "." && p != 0) {
00966       // Ignore /./.
00967     } else if (component == ".." && !components.empty() &&
00968                !(components.back() == "..")) {
00969       if (components.back() == ".") {
00970         // To "back up" over a leading ./ means simply to remove the
00971         // leading ./
00972         components.pop_back();
00973         components.push_back(component);
00974       } else {
00975         // Back up normally.
00976         components.pop_back();
00977       }
00978     } else {
00979       components.push_back(component);
00980     }
00981 
00982     p = slash;
00983     while (p < _filename.length() && _filename[p] == '/') {
00984       p++;
00985     }
00986   }
00987 
00988   // Now reassemble the filename.
00989   string result;
00990   if (global) {
00991     result = "/";
00992   }
00993   if (!components.empty()) {
00994     result += components[0];
00995     for (int i = 1; i < (int)components.size(); i++) {
00996       result += "/" + components[i];
00997     }
00998   }
00999 
01000   (*this) = result;
01001 }
01002 
01003 ////////////////////////////////////////////////////////////////////
01004 //     Function: Filename::make_absolute
01005 //       Access: Published
01006 //  Description: Converts the filename to a fully-qualified pathname
01007 //               from the root (if it is a relative pathname), and
01008 //               then standardizes it (see standardize()).
01009 //
01010 //               This is sometimes a little problematic, since it may
01011 //               convert the file to its 'true' absolute pathname,
01012 //               which could be an ugly NFS-named file, irrespective
01013 //               of symbolic links
01014 //               (e.g. /.automount/dimbo/root/usr2/fit/people/drose
01015 //               instead of /fit/people/drose); besides being ugly,
01016 //               filenames like this may not be consistent across
01017 //               multiple different platforms.
01018 ////////////////////////////////////////////////////////////////////
01019 void Filename::
01020 make_absolute() {
01021   if (is_local()) {
01022     make_absolute(ExecutionEnvironment::get_cwd());
01023   } else {
01024     standardize();
01025   }
01026 }
01027 
01028 ////////////////////////////////////////////////////////////////////
01029 //     Function: Filename::make_absolute
01030 //       Access: Published
01031 //  Description: Converts the filename to a fully-qualified filename
01032 //               from the root (if it is a relative filename), and
01033 //               then standardizes it (see standardize()).  This
01034 //               flavor accepts a specific starting directory that the
01035 //               filename is known to be relative to.
01036 ////////////////////////////////////////////////////////////////////
01037 void Filename::
01038 make_absolute(const Filename &start_directory) {
01039   if (is_local()) {
01040     Filename new_filename(start_directory, _filename);
01041     new_filename._flags = _flags;
01042     (*this) = new_filename;
01043   }
01044 
01045   standardize();
01046 }
01047 
01048 ////////////////////////////////////////////////////////////////////
01049 //     Function: Filename::make_canonical
01050 //       Access: Published
01051 //  Description: Converts this filename to a canonical name by
01052 //               replacing the directory part with the fully-qualified
01053 //               directory part.  This is done by changing to that
01054 //               directory and calling getcwd().
01055 //
01056 //               This has the effect of (a) converting relative paths
01057 //               to absolute paths (but see make_absolute() if this is
01058 //               the only effect you want), and (b) always resolving a
01059 //               given directory name to the same string, even if
01060 //               different symbolic links are traversed, and (c)
01061 //               changing nice symbolic-link paths like
01062 //               /fit/people/drose to ugly NFS automounter names like
01063 //               /hosts/dimbo/usr2/fit/people/drose.  This can be
01064 //               troubling, but sometimes this is exactly what you
01065 //               want, particularly if you're about to call
01066 //               make_relative_to() between two filenames.
01067 //
01068 //               The return value is true if successful, or false on
01069 //               failure (usually because the directory name does not
01070 //               exist or cannot be chdir'ed into).
01071 ////////////////////////////////////////////////////////////////////
01072 bool Filename::
01073 make_canonical() {
01074   if (empty()) {
01075     // An empty filename is a special case.  This doesn't name
01076     // anything.
01077     return false;
01078   }
01079 
01080   if (get_fullpath() == "/") {
01081     // The root directory is a special case.
01082     return true;
01083   }
01084   
01085 #ifndef WIN32
01086   // Use realpath in order to resolve symlinks properly
01087   char newpath [PATH_MAX + 1];
01088   if (realpath(c_str(), newpath) != NULL) {
01089     Filename newpath_fn(newpath);
01090     newpath_fn._flags = _flags;
01091     (*this) = newpath_fn;
01092   }
01093 #endif
01094 
01095   Filename cwd = ExecutionEnvironment::get_cwd();
01096   if (!r_make_canonical(cwd)) {
01097     return false;
01098   }
01099 
01100   return make_true_case();
01101 }
01102 
01103 ////////////////////////////////////////////////////////////////////
01104 //     Function: Filename::make_true_case
01105 //       Access: Published
01106 //  Description: On a case-insensitive operating system
01107 //               (e.g. Windows), this method looks up the file in the
01108 //               file system and resets the Filename to represent the
01109 //               actual case of the file as it exists on the disk.
01110 //               The return value is true if the file exists and the
01111 //               conversion can be made, or false if there is some
01112 //               error.
01113 //
01114 //               On a case-sensitive operating system, this method
01115 //               does nothing and always returns true.
01116 //
01117 //               An empty filename is considered to exist in this
01118 //               case.
01119 ////////////////////////////////////////////////////////////////////
01120 bool Filename::
01121 make_true_case() {
01122   assert(!get_pattern());
01123 
01124   if (empty()) {
01125     return true;
01126   }
01127 
01128 #ifdef WIN32
01129   wstring os_specific = to_os_specific_w();
01130 
01131   // First, we have to convert it to its short name, then back to its
01132   // long name--that seems to be the trick to force Windows to throw
01133   // away the case we give it and get the actual file case.
01134   
01135   wchar_t short_name[MAX_PATH + 1];
01136   DWORD l = GetShortPathNameW(os_specific.c_str(), short_name, MAX_PATH + 1);
01137   if (l == 0) {
01138     // Couldn't query the path name for some reason.  Probably the
01139     // file didn't exist.
01140     return false;
01141   }
01142   // According to the Windows docs, l will return a value greater than
01143   // the specified length if the short_name length wasn't enough--but also
01144   // according to the Windows docs, MAX_PATH will always be enough.
01145   assert(l < MAX_PATH + 1);
01146   
01147   wchar_t long_name[MAX_PATH + 1];
01148   l = GetLongPathNameW(short_name, long_name, MAX_PATH + 1);
01149   if (l == 0) {
01150     // Couldn't query the path name for some reason.  Probably the
01151     // file didn't exist.
01152     return false;
01153   }
01154   assert(l < MAX_PATH + 1);
01155 
01156   Filename true_case = Filename::from_os_specific_w(long_name);
01157 
01158   // Now sanity-check the true-case filename.  If it's not the same as
01159   // the source file, except for case, reject it.
01160   wstring orig_filename = get_fullpath_w();
01161   wstring new_filename = true_case.get_fullpath_w();
01162   bool match = (orig_filename.length() == new_filename.length());
01163   for (size_t i = 0; i < orig_filename.length() && match; ++i) {
01164     match = (TextEncoder::unicode_tolower(orig_filename[i]) == TextEncoder::unicode_tolower(new_filename[i]));
01165   }
01166   if (!match) {
01167     // Something went wrong.  Keep the original filename, assume it
01168     // was the correct case after all.  We return true because the
01169     // filename is good.
01170     return true;
01171   }
01172 
01173   true_case._flags = _flags;
01174   (*this) = true_case;
01175   return true;
01176 
01177 #else  // WIN32
01178   return true;
01179 #endif  // WIN32
01180 }
01181 
01182 ////////////////////////////////////////////////////////////////////
01183 //     Function: Filename::to_os_specific
01184 //       Access: Published
01185 //  Description: Converts the filename from our generic Unix-like
01186 //               convention (forward slashes starting with the root at
01187 //               '/') to the corresponding filename in the local
01188 //               operating system (slashes in the appropriate
01189 //               direction, starting with the root at C:\, for
01190 //               instance).  Returns the string representing the
01191 //               converted filename, but does not change the Filename
01192 //               itself.
01193 //
01194 //               See also from_os_specific().
01195 ////////////////////////////////////////////////////////////////////
01196 string Filename::
01197 to_os_specific() const {
01198   assert(!get_pattern());
01199 
01200   if (empty()) {
01201     return string();
01202   }
01203   Filename standard(*this);
01204   standard.standardize();
01205 
01206 #ifdef IS_OSX 
01207   if (get_type() == T_dso) {
01208     std::string workname = standard.get_fullpath();
01209     size_t dot = workname.rfind('.');
01210     if (dot != string::npos) {
01211       if (workname.substr(dot) == ".so") {
01212         string dyLibBase = workname.substr(0, dot)+".dylib";
01213         return dyLibBase; 
01214       }
01215     }
01216   }
01217 #endif
01218 
01219 #ifdef WIN32
01220   switch (get_type()) {
01221   case T_dso:
01222     return convert_dso_pathname(standard.get_fullpath());
01223   case T_executable:
01224     return convert_executable_pathname(standard.get_fullpath());
01225   default:
01226     return convert_pathname(standard.get_fullpath());
01227   }
01228 #else // WIN32
01229   return standard.c_str();
01230 #endif // WIN32
01231 }
01232 
01233 ////////////////////////////////////////////////////////////////////
01234 //     Function: Filename::to_os_specific_w
01235 //       Access: Published
01236 //  Description: The wide-string variant on to_os_specific().
01237 ////////////////////////////////////////////////////////////////////
01238 wstring Filename::
01239 to_os_specific_w() const {
01240   TextEncoder encoder;
01241   encoder.set_encoding(get_filesystem_encoding());
01242   encoder.set_text(to_os_specific());
01243   return encoder.get_wtext();
01244 }
01245 
01246 ////////////////////////////////////////////////////////////////////
01247 //     Function: Filename::to_os_generic
01248 //       Access: Published
01249 //  Description: This is similar to to_os_specific(), but it is
01250 //               designed to generate a filename that can be
01251 //               understood on as many platforms as possible.  Since
01252 //               Windows can usually understand a
01253 //               forward-slash-delimited filename, this means it does
01254 //               the same thing as to_os_specific(), but it uses
01255 //               forward slashes instead of backslashes.
01256 //
01257 //               This method has a pretty limited use; it should
01258 //               generally be used for writing file references to a
01259 //               file that might be read on any operating system.
01260 ////////////////////////////////////////////////////////////////////
01261 string Filename::
01262 to_os_generic() const {
01263   assert(!get_pattern());
01264 
01265 #ifdef WIN32
01266   return back_to_front_slash(to_os_specific());
01267 #else // WIN32
01268   return to_os_specific();
01269 #endif // WIN32
01270 }
01271 
01272 ////////////////////////////////////////////////////////////////////
01273 //     Function: Filename::to_os_short_name
01274 //       Access: Published
01275 //  Description: This works like to_os_generic(), but it returns the
01276 //               "short name" version of the filename, if it exists,
01277 //               or the original filename otherwise.
01278 //
01279 //               On Windows platforms, this returns the 8.3 filename
01280 //               version of the given filename, if the file exists,
01281 //               and the same thing as to_os_specific() otherwise.  On
01282 //               non-Windows platforms, this always returns the same
01283 //               thing as to_os_specific().
01284 ////////////////////////////////////////////////////////////////////
01285 string Filename::
01286 to_os_short_name() const {
01287   assert(!get_pattern());
01288 
01289 #ifdef WIN32
01290   wstring os_specific = to_os_specific_w();
01291   
01292   wchar_t short_name[MAX_PATH + 1];
01293   DWORD l = GetShortPathNameW(os_specific.c_str(), short_name, MAX_PATH + 1);
01294   if (l == 0) {
01295     // Couldn't query the path name for some reason.  Probably the
01296     // file didn't exist.
01297     return to_os_specific();
01298   }
01299   // According to the Windows docs, l will return a value greater than
01300   // the specified length if the short_name length wasn't enough--but also
01301   // according to the Windows docs, MAX_PATH will always be enough.
01302   assert(l < MAX_PATH + 1);
01303 
01304   TextEncoder encoder;
01305   encoder.set_encoding(get_filesystem_encoding());
01306   encoder.set_wtext(short_name);
01307   return encoder.get_text();
01308 
01309 #else // WIN32
01310   return to_os_specific();
01311 #endif // WIN32
01312 }
01313 
01314 ////////////////////////////////////////////////////////////////////
01315 //     Function: Filename::to_os_long_name
01316 //       Access: Published
01317 //  Description: This is the opposite of to_os_short_name(): it
01318 //               returns the "long name" of the filename, if the
01319 //               filename exists.  On non-Windows platforms, this
01320 //               returns the same thing as to_os_specific().
01321 ////////////////////////////////////////////////////////////////////
01322 string Filename::
01323 to_os_long_name() const {
01324   assert(!get_pattern());
01325 
01326 #ifdef WIN32
01327   wstring os_specific = to_os_specific_w();
01328   
01329   wchar_t long_name[MAX_PATH + 1];
01330   DWORD l = GetLongPathNameW(os_specific.c_str(), long_name, MAX_PATH + 1);
01331   if (l == 0) {
01332     // Couldn't query the path name for some reason.  Probably the
01333     // file didn't exist.
01334     return to_os_specific();
01335   }
01336   assert(l < MAX_PATH + 1);
01337 
01338   TextEncoder encoder;
01339   encoder.set_encoding(get_filesystem_encoding());
01340   encoder.set_wtext(long_name);
01341   return encoder.get_text();
01342 
01343 #else // WIN32
01344   return to_os_specific();
01345 #endif // WIN32
01346 }
01347 
01348 ////////////////////////////////////////////////////////////////////
01349 //     Function: Filename::exists
01350 //       Access: Published
01351 //  Description: Returns true if the filename exists on the disk,
01352 //               false otherwise.  If the type is indicated to be
01353 //               executable, this also tests that the file has execute
01354 //               permission.
01355 ////////////////////////////////////////////////////////////////////
01356 bool Filename::
01357 exists() const {
01358 #ifdef WIN32_VC
01359   wstring os_specific = get_filename_index(0).to_os_specific_w();
01360 
01361   bool exists = false;
01362 
01363   DWORD results = GetFileAttributesW(os_specific.c_str());
01364   if (results != -1) {
01365     exists = true;
01366   }
01367 
01368 #else  // WIN32_VC
01369   string os_specific = get_filename_index(0).to_os_specific();
01370 
01371   struct stat this_buf;
01372   bool exists = false;
01373 
01374   if (stat(os_specific.c_str(), &this_buf) == 0) {
01375     exists = true;
01376   }
01377 #endif
01378 
01379   return exists;
01380 }
01381 
01382 ////////////////////////////////////////////////////////////////////
01383 //     Function: Filename::is_regular_file
01384 //       Access: Published
01385 //  Description: Returns true if the filename exists and is the
01386 //               name of a regular file (i.e. not a directory or
01387 //               device), false otherwise.
01388 ////////////////////////////////////////////////////////////////////
01389 bool Filename::
01390 is_regular_file() const {
01391 #ifdef WIN32_VC
01392   wstring os_specific = get_filename_index(0).to_os_specific_w();
01393 
01394   bool isreg = false;
01395 
01396   DWORD results = GetFileAttributesW(os_specific.c_str());
01397   if (results != -1) {
01398     isreg = ((results & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0);
01399   }
01400 
01401 #else  // WIN32_VC
01402   string os_specific = get_filename_index(0).to_os_specific();
01403 
01404   struct stat this_buf;
01405   bool isreg = false;
01406 
01407   if (stat(os_specific.c_str(), &this_buf) == 0) {
01408     isreg = S_ISREG(this_buf.st_mode);
01409   }
01410 #endif
01411 
01412   return isreg;
01413 }
01414 
01415 ////////////////////////////////////////////////////////////////////
01416 //     Function: Filename::is_writable
01417 //       Access: Published
01418 //  Description: Returns true if the filename exists and is either a
01419 //               directory or a regular file that can be written to,
01420 //               or false otherwise.
01421 ////////////////////////////////////////////////////////////////////
01422 bool Filename::
01423 is_writable() const {
01424   bool writable = false;
01425 
01426 #ifdef WIN32_VC
01427   wstring os_specific = get_filename_index(0).to_os_specific_w();
01428 
01429   DWORD results = GetFileAttributesW(os_specific.c_str());
01430   if (results != -1) {
01431     if ((results & FILE_ATTRIBUTE_DIRECTORY) != 0) {
01432       // Assume directories are writable.
01433       writable = true;
01434     } else if ((results & FILE_ATTRIBUTE_READONLY) == 0) {
01435       // Not read-only means writable.
01436       writable = true;
01437     }
01438   }
01439 #else  // WIN32_VC
01440   string os_specific = get_filename_index(0).to_os_specific();
01441 
01442   if (access(os_specific.c_str(), W_OK) == 0) {
01443     writable = true;
01444   }
01445 #endif
01446 
01447   return writable;
01448 }
01449 
01450 ////////////////////////////////////////////////////////////////////
01451 //     Function: Filename::is_directory
01452 //       Access: Published
01453 //  Description: Returns true if the filename exists and is a
01454 //               directory name, false otherwise.
01455 ////////////////////////////////////////////////////////////////////
01456 bool Filename::
01457 is_directory() const {
01458 #ifdef WIN32_VC
01459   wstring os_specific = get_filename_index(0).to_os_specific_w();
01460 
01461   bool isdir = false;
01462 
01463   DWORD results = GetFileAttributesW(os_specific.c_str());
01464   if (results != -1) {
01465     isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
01466   }
01467 #else  // WIN32_VC
01468   string os_specific = get_filename_index(0).to_os_specific();
01469 
01470   struct stat this_buf;
01471   bool isdir = false;
01472 
01473   if (stat(os_specific.c_str(), &this_buf) == 0) {
01474     isdir = S_ISDIR(this_buf.st_mode);
01475   }
01476 #endif
01477 
01478   return isdir;
01479 }
01480 
01481 ////////////////////////////////////////////////////////////////////
01482 //     Function: Filename::is_executable
01483 //       Access: Published
01484 //  Description: Returns true if the filename exists and is
01485 //               executable
01486 ////////////////////////////////////////////////////////////////////
01487 bool Filename::
01488 is_executable() const {
01489 #ifdef WIN32_VC
01490   // no access() in windows, but to our advantage executables can only
01491   // end in .exe or .com
01492   string extension = get_extension();
01493   if (extension == "exe" || extension == "com") {
01494     return exists();
01495   }
01496 
01497 #else /* WIN32_VC */
01498   string os_specific = get_filename_index(0).to_os_specific();
01499   if (access(os_specific.c_str(), X_OK) == 0) {
01500     return true;
01501   }
01502 #endif /* WIN32_VC */
01503 
01504   return false;
01505 }
01506 
01507 ////////////////////////////////////////////////////////////////////
01508 //     Function: Filename::compare_timestamps
01509 //       Access: Published
01510 //  Description: Returns a number less than zero if the file named by
01511 //               this object is older than the given file, zero if
01512 //               they have the same timestamp, or greater than zero if
01513 //               this one is newer.
01514 //
01515 //               If this_missing_is_old is true, it indicates that a
01516 //               missing file will be treated as if it were older than
01517 //               any other file; otherwise, a missing file will be
01518 //               treated as if it were newer than any other file.
01519 //               Similarly for other_missing_is_old.
01520 ////////////////////////////////////////////////////////////////////
01521 int Filename::
01522 compare_timestamps(const Filename &other,
01523                    bool this_missing_is_old,
01524                    bool other_missing_is_old) const {
01525 #ifdef WIN32_VC
01526   wstring os_specific = get_filename_index(0).to_os_specific_w();
01527   wstring other_os_specific = other.get_filename_index(0).to_os_specific_w();
01528 
01529   struct _stat this_buf;
01530   bool this_exists = false;
01531 
01532   if (_wstat(os_specific.c_str(), &this_buf) == 0) {
01533     this_exists = true;
01534   }
01535 
01536   struct _stat other_buf;
01537   bool other_exists = false;
01538 
01539   if (_wstat(other_os_specific.c_str(), &other_buf) == 0) {
01540     other_exists = true;
01541   }
01542 #else  // WIN32_VC
01543   string os_specific = get_filename_index(0).to_os_specific();
01544   string other_os_specific = other.get_filename_index(0).to_os_specific();
01545 
01546   struct stat this_buf;
01547   bool this_exists = false;
01548 
01549   if (stat(os_specific.c_str(), &this_buf) == 0) {
01550     this_exists = true;
01551   }
01552 
01553   struct stat other_buf;
01554   bool other_exists = false;
01555 
01556   if (stat(other_os_specific.c_str(), &other_buf) == 0) {
01557     other_exists = true;
01558   }
01559 #endif
01560 
01561   if (this_exists && other_exists) {
01562     // Both files exist, return the honest time comparison.
01563     return (int)this_buf.st_mtime - (int)other_buf.st_mtime;
01564 
01565   } else if (!this_exists && !other_exists) {
01566     // Neither file exists.
01567     if (this_missing_is_old == other_missing_is_old) {
01568       // Both files are either "very old" or "very new".
01569       return 0;
01570     }
01571     if (this_missing_is_old) {
01572       // This file is "very old", the other is "very new".
01573       return -1;
01574     } else {
01575       // This file is "very new", the other is "very old".
01576       return 1;
01577     }
01578 
01579   } else if (!this_exists) {
01580     // This file doesn't, the other one does.
01581     return this_missing_is_old ? -1 : 1;
01582 
01583   }
01584   // !other_exists
01585   assert(!other_exists);
01586   
01587   // This file exists, the other one doesn't.
01588   return other_missing_is_old ? 1 : -1;
01589 }
01590 
01591 ////////////////////////////////////////////////////////////////////
01592 //     Function: Filename::get_timestamp
01593 //       Access: Published
01594 //  Description: Returns a time_t value that represents the time the
01595 //               file was last modified, to within whatever precision
01596 //               the operating system records this information (on a
01597 //               Windows95 system, for instance, this may only be
01598 //               accurate to within 2 seconds).
01599 //
01600 //               If the timestamp cannot be determined, either because
01601 //               it is not supported by the operating system or
01602 //               because there is some error (such as file not found),
01603 //               returns 0.
01604 ////////////////////////////////////////////////////////////////////
01605 time_t Filename::
01606 get_timestamp() const {
01607 #ifdef WIN32_VC
01608   wstring os_specific = get_filename_index(0).to_os_specific_w();
01609 
01610   struct _stat this_buf;
01611 
01612   if (_wstat(os_specific.c_str(), &this_buf) == 0) {
01613     return this_buf.st_mtime;
01614   }
01615 #else  // WIN32_VC
01616   string os_specific = get_filename_index(0).to_os_specific();
01617 
01618   struct stat this_buf;
01619 
01620   if (stat(os_specific.c_str(), &this_buf) == 0) {
01621     return this_buf.st_mtime;
01622   }
01623 #endif
01624 
01625   return 0;
01626 }
01627 
01628 ////////////////////////////////////////////////////////////////////
01629 //     Function: Filename::get_access_timestamp
01630 //       Access: Published
01631 //  Description: Returns a time_t value that represents the time the
01632 //               file was last accessed, if this information is
01633 //               available.  See also get_timestamp(), which returns
01634 //               the last modification time.
01635 ////////////////////////////////////////////////////////////////////
01636 time_t Filename::
01637 get_access_timestamp() const {
01638 #ifdef WIN32_VC
01639   wstring os_specific = get_filename_index(0).to_os_specific_w();
01640 
01641   struct _stat this_buf;
01642 
01643   if (_wstat(os_specific.c_str(), &this_buf) == 0) {
01644     return this_buf.st_atime;
01645   }
01646 #else  // WIN32_VC
01647   string os_specific = get_filename_index(0).to_os_specific();
01648 
01649   struct stat this_buf;
01650 
01651   if (stat(os_specific.c_str(), &this_buf) == 0) {
01652     return this_buf.st_atime;
01653   }
01654 #endif
01655 
01656   return 0;
01657 }
01658 
01659 ////////////////////////////////////////////////////////////////////
01660 //     Function: Filename::get_file_size
01661 //       Access: Published
01662 //  Description: Returns the size of the file in bytes, or 0 if there
01663 //               is an error.
01664 ////////////////////////////////////////////////////////////////////
01665 off_t Filename::
01666 get_file_size() const {
01667 #ifdef WIN32_VC
01668   wstring os_specific = get_filename_index(0).to_os_specific_w();
01669 
01670   struct _stat this_buf;
01671 
01672   if (_wstat(os_specific.c_str(), &this_buf) == 0) {
01673     return this_buf.st_size;
01674   }
01675 #else  // WIN32_VC
01676   string os_specific = get_filename_index(0).to_os_specific();
01677 
01678   struct stat this_buf;
01679 
01680   if (stat(os_specific.c_str(), &this_buf) == 0) {
01681     return this_buf.st_size;
01682   }
01683 #endif
01684 
01685   return 0;
01686 }
01687 
01688 ////////////////////////////////////////////////////////////////////
01689 //     Function: Filename::resolve_filename
01690 //       Access: Published
01691 //  Description: Searches the given search path for the filename.  If
01692 //               it is found, updates the filename to the full
01693 //               pathname found and returns true; otherwise, returns
01694 //               false.
01695 ////////////////////////////////////////////////////////////////////
01696 bool Filename::
01697 resolve_filename(const DSearchPath &searchpath,
01698                  const string &default_extension) {
01699   Filename found;
01700 
01701   if (is_local()) {
01702     found = searchpath.find_file(*this);
01703 
01704     if (found.empty()) {
01705       // We didn't find it with the given extension; can we try the
01706       // default extension?
01707       if (get_extension().empty() && !default_extension.empty()) {
01708         Filename try_ext = *this;
01709         try_ext.set_extension(default_extension);
01710         found = searchpath.find_file(try_ext);
01711       }
01712     }
01713   } else {
01714     if (exists()) {
01715       // The full pathname exists.  Return true.
01716       return true;
01717     } else {
01718       // The full pathname doesn't exist with the given extension;
01719       // does it exist with the default extension?
01720       if (get_extension().empty() && !default_extension.empty()) {
01721         Filename try_ext = *this;
01722         try_ext.set_extension(default_extension);
01723         if (try_ext.exists()) {
01724           found = try_ext;
01725         }
01726       }
01727     }
01728   }
01729 
01730   if (!found.empty()) {
01731     (*this) = found;
01732     return true;
01733   }
01734 
01735   return false;
01736 }
01737 
01738 ////////////////////////////////////////////////////////////////////
01739 //     Function: Filename::make_relative_to
01740 //       Access: Published
01741 //  Description: Adjusts this filename, which must be a
01742 //               fully-specified pathname beginning with a slash, to
01743 //               make it a relative filename, relative to the
01744 //               fully-specified directory indicated (which must also
01745 //               begin with, and may or may not end with, a slash--a
01746 //               terminating slash is ignored).
01747 //
01748 //               This only performs a string comparsion, so it may be
01749 //               wise to call make_canonical() on both filenames
01750 //               before calling make_relative_to().
01751 //
01752 //               If allow_backups is false, the filename will only be
01753 //               adjusted to be made relative if it is already
01754 //               somewhere within or below the indicated directory.
01755 //               If allow_backups is true, it will be adjusted in all
01756 //               cases, even if this requires putting a series of ../
01757 //               characters before the filename--unless it would have
01758 //               to back all the way up to the root.
01759 //
01760 //               Returns true if the file was adjusted, false if it
01761 //               was not.
01762 ////////////////////////////////////////////////////////////////////
01763 bool Filename::
01764 make_relative_to(Filename directory, bool allow_backups) {
01765   if (_filename.empty() || directory.empty() ||
01766       _filename[0] != '/' || directory[0] != '/') {
01767     return false;
01768   }
01769 
01770   standardize();
01771   directory.standardize();
01772 
01773   if (directory == "/") {
01774     // Don't be silly.
01775     return false;
01776   }
01777 
01778   string rel_to_file = directory.get_fullpath() + "/.";
01779 
01780   size_t common = get_common_prefix(rel_to_file);
01781   if (common < 2) {
01782     // Oh, never mind.
01783     return false;
01784   }
01785 
01786   string result;
01787   int slashes = count_slashes(rel_to_file.substr(common));
01788   if (slashes > 0 && !allow_backups) {
01789     // Too bad; the file's not under the indicated directory.
01790     return false;
01791   }
01792 
01793   for (int i = 0; i < slashes; i++) {
01794     result += "../";
01795   }
01796   result += _filename.substr(common);
01797   (*this) = result;
01798 
01799   return true;
01800 }
01801 
01802 ////////////////////////////////////////////////////////////////////
01803 //     Function: Filename::find_on_searchpath
01804 //       Access: Published
01805 //  Description: Performs the reverse of the resolve_filename()
01806 //               operation: assuming that the current filename is
01807 //               fully-specified pathname (i.e. beginning with '/'),
01808 //               look on the indicated search path for a directory
01809 //               under which the file can be found.  When found,
01810 //               adjust the Filename to be relative to the indicated
01811 //               directory name.
01812 //
01813 //               Returns the index of the directory on the searchpath
01814 //               at which the file was found, or -1 if it was not
01815 //               found.
01816 ////////////////////////////////////////////////////////////////////
01817 int Filename::
01818 find_on_searchpath(const DSearchPath &searchpath) {
01819   if (_filename.empty() || _filename[0] != '/') {
01820     return -1;
01821   }
01822 
01823   int num_directories = searchpath.get_num_directories();
01824   for (int i = 0; i < num_directories; i++) {
01825     Filename directory = searchpath.get_directory(i);
01826     directory.make_absolute();
01827     if (make_relative_to(directory, false)) {
01828       return i;
01829     }
01830   }
01831 
01832   return -1;
01833 }
01834 
01835 ////////////////////////////////////////////////////////////////////
01836 //     Function: Filename::scan_directory
01837 //       Access: Published
01838 //  Description: Attempts to open the named filename as if it were a
01839 //               directory and looks for the non-hidden files within
01840 //               the directory.  Fills the given vector up with the
01841 //               sorted list of filenames that are local to this
01842 //               directory.
01843 //
01844 //               It is the user's responsibility to ensure that the
01845 //               contents vector is empty before making this call;
01846 //               otherwise, the new files will be appended to it.
01847 //
01848 //               Returns true on success, false if the directory could
01849 //               not be read for some reason.
01850 ////////////////////////////////////////////////////////////////////
01851 bool Filename::
01852 scan_directory(vector_string &contents) const {
01853   assert(!get_pattern());
01854 
01855 #if defined(WIN32_VC)
01856   // Use Windows' FindFirstFile() / FindNextFile() to walk through the
01857   // list of files in a directory.
01858   size_t orig_size = contents.size();
01859 
01860   wstring match;
01861   if (empty()) {
01862     match = L"*.*";
01863   } else {
01864     match = to_os_specific_w() + L"\\*.*";
01865   }
01866   WIN32_FIND_DATAW find_data;
01867 
01868   HANDLE handle = FindFirstFileW(match.c_str(), &find_data);
01869   if (handle == INVALID_HANDLE_VALUE) {
01870     if (GetLastError() == ERROR_NO_MORE_FILES) {
01871       // No matching files is not an error.
01872       return true;
01873     }
01874     return false;
01875   }
01876 
01877   TextEncoder encoder;
01878   encoder.set_encoding(get_filesystem_encoding());
01879   do {
01880     thread_consider_yield();
01881     wstring filename = find_data.cFileName;
01882     if (filename != L"." && filename != L"..") {
01883       encoder.set_wtext(filename);
01884       contents.push_back(encoder.get_text());
01885     }
01886   } while (FindNextFileW(handle, &find_data));
01887 
01888   bool scan_ok = (GetLastError() == ERROR_NO_MORE_FILES);
01889   FindClose(handle);
01890 
01891   sort(contents.begin() + orig_size, contents.end());
01892   return scan_ok;
01893 
01894 #elif defined(PHAVE_DIRENT_H)
01895   // Use Posix's opendir() / readdir() to walk through the list of
01896   // files in a directory.
01897   size_t orig_size = contents.size();
01898 
01899   string dirname;
01900   if (empty()) {
01901     dirname = ".";
01902   } else {
01903     dirname = _filename;
01904   }
01905   DIR *root = opendir(dirname.c_str());
01906   if (root == (DIR *)NULL) {
01907     if (errno != ENOTDIR) {
01908       perror(dirname.c_str());
01909     }
01910     return false;
01911   }
01912 
01913   struct dirent *d;
01914   d = readdir(root);
01915   while (d != (struct dirent *)NULL) {
01916     thread_consider_yield();
01917     if (d->d_name[0] != '.') {
01918       contents.push_back(d->d_name);
01919     }
01920     d = readdir(root);
01921   }
01922 
01923   // It turns out to be a mistake to check the value of errno after
01924   // calling readdir(), since it might have been set to non-zero
01925   // during some internal operation of readdir(), even though there
01926   // wasn't really a problem with scanning the directory itself.
01927   /*
01928   if (errno != 0 && errno != ENOENT && errno != ENOTDIR) {
01929     cerr << "Error occurred while scanning directory " << dirname << "\n";
01930     perror(dirname.c_str());
01931     closedir(root);
01932     return false;
01933   }
01934   */
01935   closedir(root);
01936 
01937   sort(contents.begin() + orig_size, contents.end());
01938   return true;
01939 
01940 #elif defined(PHAVE_GLOB_H)
01941   // It's hard to imagine a system that provides glob.h but does not
01942   // provide openddir() .. readdir(), but this code is leftover from a
01943   // time when there was an undetected bug in the above readdir()
01944   // loop, and it works, so we might as well keep it around for now.
01945   string dirname;
01946   if (empty()) {
01947     dirname = "*";
01948   } else if (_filename[_filename.length() - 1] == '/') {
01949     dirname = _filename + "*";
01950   } else {
01951     dirname = _filename + "/*";   /* comment to fix emacs syntax hilight */
01952   }
01953 
01954   glob_t globbuf;
01955 
01956   int r = glob(dirname.c_str(), GLOB_ERR, NULL, &globbuf);
01957 
01958   if (r != 0) {
01959     // Some error processing the match string.  If our version of
01960     // glob.h defines GLOB_NOMATCH, then we can differentiate an empty
01961     // return result from some other kind of error.
01962 #ifdef GLOB_NOMATCH
01963     if (r != GLOB_NOMATCH) {
01964       perror(dirname.c_str());
01965       return false;
01966     }
01967 #endif
01968 
01969     // Otherwise, all errors mean the same thing: no matches, but
01970     // otherwise no problem.
01971     return true;
01972   }
01973 
01974   size_t offset = dirname.size() - 1;
01975 
01976   for (int i = 0; globbuf.gl_pathv[i] != NULL; i++) {
01977     contents.push_back(globbuf.gl_pathv[i] + offset);
01978   }
01979   globfree(&globbuf);
01980 
01981   return true;
01982   
01983 #else
01984   // Don't know how to scan directories!
01985   return false;
01986 #endif
01987 }
01988 
01989 #ifdef HAVE_PYTHON
01990 ////////////////////////////////////////////////////////////////////
01991 //     Function: Filename::scan_directory
01992 //       Access: Published
01993 //  Description: This variant on scan_directory returns a Python list
01994 //               of strings on success, or None on failure.
01995 ////////////////////////////////////////////////////////////////////
01996 PyObject *Filename::
01997 scan_directory() const {
01998   vector_string contents;
01999   if (!scan_directory(contents)) {
02000     PyObject *result = Py_None;
02001     Py_INCREF(result);
02002     return result;
02003   }
02004 
02005   PyObject *result = PyList_New(contents.size());
02006   for (size_t i = 0; i < contents.size(); ++i) {
02007     const string &filename = contents[i];
02008     PyObject *str = PyString_FromStringAndSize(filename.data(), filename.size());
02009     PyList_SET_ITEM(result, i, str);
02010   }
02011 
02012   return result;
02013 }
02014 #endif  // HAVE_PYTHON
02015 
02016 ////////////////////////////////////////////////////////////////////
02017 //     Function: Filename::open_read
02018 //       Access: Published
02019 //  Description: Opens the indicated ifstream for reading the file, if
02020 //               possible.  Returns true if successful, false
02021 //               otherwise.  This requires the setting of the
02022 //               set_text()/set_binary() flags to open the file
02023 //               appropriately as indicated; it is an error to call
02024 //               open_read() without first calling one of set_text()
02025 //               or set_binary().
02026 ////////////////////////////////////////////////////////////////////
02027 bool Filename::
02028 open_read(ifstream &stream) const {
02029   assert(!get_pattern());
02030   assert(is_binary_or_text());
02031 
02032   ios_openmode open_mode = ios::in;
02033 
02034 #ifdef HAVE_IOS_BINARY
02035   // For some reason, some systems (like Irix) don't define
02036   // ios::binary.
02037   if (!is_text()) {
02038     open_mode |= ios::binary;
02039   }
02040 #endif
02041 
02042   stream.clear();
02043 #ifdef WIN32_VC
02044   wstring os_specific = to_os_specific_w();
02045   stream.open(os_specific.c_str(), open_mode);
02046 #else
02047   string os_specific = to_os_specific();
02048   stream.open(os_specific.c_str(), open_mode);
02049 #endif  // WIN32_VC
02050 
02051   return (!stream.fail());
02052 }
02053 
02054 ////////////////////////////////////////////////////////////////////
02055 //     Function: Filename::open_write
02056 //       Access: Published
02057 //  Description: Opens the indicated ifstream for writing the file, if
02058 //               possible.  Returns true if successful, false
02059 //               otherwise.  This requires the setting of the
02060 //               set_text()/set_binary() flags to open the file
02061 //               appropriately as indicated; it is an error to call
02062 //               open_read() without first calling one of set_text()
02063 //               or set_binary().
02064 //
02065 //               If truncate is true, the file is truncated to zero
02066 //               length upon opening it, if it already exists.
02067 //               Otherwise, the file is kept at its original length.
02068 ////////////////////////////////////////////////////////////////////
02069 bool Filename::
02070 open_write(ofstream &stream, bool truncate) const {
02071   assert(!get_pattern());
02072   assert(is_binary_or_text());
02073 
02074   ios_openmode open_mode = ios::out;
02075 
02076   if (truncate) {
02077     open_mode |= ios::trunc;
02078 
02079   } else {
02080     // Some systems insist on having ios::in set to prevent the file
02081     // from being truncated when we open it.  Makes ios::trunc kind of
02082     // pointless, doesn't it?  On the other hand, setting ios::in also
02083     // seems to imply ios::nocreate (!), so we should only set this if
02084     // the file already exists.
02085     if (exists()) {
02086       open_mode |= ios::in;
02087     }
02088   }
02089 
02090 #ifdef HAVE_IOS_BINARY
02091   // For some reason, some systems (like Irix) don't define
02092   // ios::binary.
02093   if (!is_text()) {
02094     open_mode |= ios::binary;
02095   }
02096 #endif
02097 
02098   stream.clear();
02099 #ifdef WIN32_VC
02100   wstring os_specific = to_os_specific_w();
02101   stream.open(os_specific.c_str(), open_mode);
02102 #else
02103   string os_specific = to_os_specific();
02104 #ifdef HAVE_OPEN_MASK
02105   stream.open(os_specific.c_str(), open_mode, 0666);
02106 #else
02107   stream.open(os_specific.c_str(), open_mode);
02108 #endif
02109 #endif  // WIN32_VC
02110 
02111   return (!stream.fail());
02112 }
02113 
02114 ////////////////////////////////////////////////////////////////////
02115 //     Function: Filename::open_append
02116 //       Access: Published
02117 //  Description: Opens the indicated ofstream for writing the file, if
02118 //               possible.  Returns true if successful, false
02119 //               otherwise.  This requires the setting of the
02120 //               set_text()/set_binary() flags to open the file
02121 //               appropriately as indicated; it is an error to call
02122 //               open_read() without first calling one of set_text()
02123 //               or set_binary().
02124 ////////////////////////////////////////////////////////////////////
02125 bool Filename::
02126 open_append(ofstream &stream) const {
02127   assert(!get_pattern());
02128   assert(is_binary_or_text());
02129 
02130   ios_openmode open_mode = ios::app;
02131 
02132 #ifdef HAVE_IOS_BINARY
02133   // For some reason, some systems (like Irix) don't define
02134   // ios::binary.
02135   if (!is_text()) {
02136     open_mode |= ios::binary;
02137   }
02138 #endif
02139 
02140   stream.clear();
02141 #ifdef WIN32_VC
02142   wstring os_specific = to_os_specific_w();
02143   stream.open(os_specific.c_str(), open_mode);
02144 #else
02145   string os_specific = to_os_specific();
02146 #ifdef HAVE_OPEN_MASK
02147   stream.open(os_specific.c_str(), open_mode, 0666);
02148 #else
02149   stream.open(os_specific.c_str(), open_mode);
02150 #endif
02151 #endif  // WIN32_VC
02152 
02153   return (!stream.fail());
02154 }
02155 
02156 ////////////////////////////////////////////////////////////////////
02157 //     Function: Filename::open_read_write
02158 //       Access: Published
02159 //  Description: Opens the indicated fstream for read/write access to
02160 //               the file, if possible.  Returns true if successful,
02161 //               false otherwise.  This requires the setting of the
02162 //               set_text()/set_binary() flags to open the file
02163 //               appropriately as indicated; it is an error to call
02164 //               open_read_write() without first calling one of
02165 //               set_text() or set_binary().
02166 ////////////////////////////////////////////////////////////////////
02167 bool Filename::
02168 open_read_write(fstream &stream, bool truncate) const {
02169   assert(!get_pattern());
02170   assert(is_binary_or_text());
02171 
02172   ios_openmode open_mode = ios::out | ios::in;
02173 
02174   if (truncate) {
02175     open_mode |= ios::trunc;
02176   }
02177 
02178   // Since ios::in also seems to imply ios::nocreate (!), we must
02179   // guarantee the file already exists before we try to open it.
02180   if (!exists()) {
02181     touch();
02182   }
02183 
02184 #ifdef HAVE_IOS_BINARY
02185   // For some reason, some systems (like Irix) don't define
02186   // ios::binary.
02187   if (!is_text()) {
02188     open_mode |= ios::binary;
02189   }
02190 #endif
02191 
02192   stream.clear();
02193 #ifdef WIN32_VC
02194   wstring os_specific = to_os_specific_w();
02195   stream.open(os_specific.c_str(), open_mode);
02196 #else
02197   string os_specific = to_os_specific();
02198 #ifdef HAVE_OPEN_MASK
02199   stream.open(os_specific.c_str(), open_mode, 0666);
02200 #else
02201   stream.open(os_specific.c_str(), open_mode);
02202 #endif
02203 #endif  // WIN32_VC
02204 
02205   return (!stream.fail());
02206 }
02207 
02208 ////////////////////////////////////////////////////////////////////
02209 //     Function: Filename::open_read_append
02210 //       Access: Published
02211 //  Description: Opens the indicated ifstream for reading and writing
02212 //               the file, if possible; writes are appended to the end
02213 //               of the file.  Returns true if successful, false
02214 //               otherwise.  This requires the setting of the
02215 //               set_text()/set_binary() flags to open the file
02216 //               appropriately as indicated; it is an error to call
02217 //               open_read() without first calling one of set_text()
02218 //               or set_binary().
02219 ////////////////////////////////////////////////////////////////////
02220 bool Filename::
02221 open_read_append(fstream &stream) const {
02222   assert(!get_pattern());
02223   assert(is_binary_or_text());
02224 
02225   ios_openmode open_mode = ios::app | ios::in;
02226 
02227 #ifdef HAVE_IOS_BINARY
02228   // For some reason, some systems (like Irix) don't define
02229   // ios::binary.
02230   if (!is_text()) {
02231     open_mode |= ios::binary;
02232   }
02233 #endif
02234 
02235   stream.clear();
02236 #ifdef WIN32_VC
02237   wstring os_specific = to_os_specific_w();
02238   stream.open(os_specific.c_str(), open_mode);
02239 #else
02240   string os_specific = to_os_specific();
02241 #ifdef HAVE_OPEN_MASK
02242   stream.open(os_specific.c_str(), open_mode, 0666);
02243 #else
02244   stream.open(os_specific.c_str(), open_mode);
02245 #endif
02246 #endif  // WIN32_VC
02247 
02248   return (!stream.fail());
02249 }
02250 
02251 #ifdef USE_PANDAFILESTREAM
02252 ////////////////////////////////////////////////////////////////////
02253 //     Function: Filename::open_read
02254 //       Access: Published
02255 //  Description: Opens the indicated pifstream for reading the file, if
02256 //               possible.  Returns true if successful, false
02257 //               otherwise.  This requires the setting of the
02258 //               set_text()/set_binary() flags to open the file
02259 //               appropriately as indicated; it is an error to call
02260 //               open_read() without first calling one of set_text()
02261 //               or set_binary().
02262 ////////////////////////////////////////////////////////////////////
02263 bool Filename::
02264 open_read(pifstream &stream) const {
02265   assert(!get_pattern());
02266   assert(is_binary_or_text());
02267 
02268   ios_openmode open_mode = ios::in;
02269 
02270 #ifdef HAVE_IOS_BINARY
02271   // For some reason, some systems (like Irix) don't define
02272   // ios::binary.
02273   if (!is_text()) {
02274     open_mode |= ios::binary;
02275   }
02276 #endif
02277 
02278   string os_specific = to_os_specific();
02279   stream.clear();
02280   stream.open(os_specific.c_str(), open_mode);
02281   return (!stream.fail());
02282 }
02283 #endif  // USE_PANDAFILESTREAM
02284 
02285 #ifdef USE_PANDAFILESTREAM
02286 ////////////////////////////////////////////////////////////////////
02287 //     Function: Filename::open_write
02288 //       Access: Published
02289 //  Description: Opens the indicated pifstream for writing the file, if
02290 //               possible.  Returns true if successful, false
02291 //               otherwise.  This requires the setting of the
02292 //               set_text()/set_binary() flags to open the file
02293 //               appropriately as indicated; it is an error to call
02294 //               open_read() without first calling one of set_text()
02295 //               or set_binary().
02296 //
02297 //               If truncate is true, the file is truncated to zero
02298 //               length upon opening it, if it already exists.
02299 //               Otherwise, the file is kept at its original length.
02300 ////////////////////////////////////////////////////////////////////
02301 bool Filename::
02302 open_write(pofstream &stream, bool truncate) const {
02303   assert(!get_pattern());
02304   assert(is_binary_or_text());
02305 
02306   ios_openmode open_mode = ios::out;
02307 
02308   if (truncate) {
02309     open_mode |= ios::trunc;
02310 
02311   } else {
02312     // Some systems insist on having ios::in set to prevent the file
02313     // from being truncated when we open it.  Makes ios::trunc kind of
02314     // pointless, doesn't it?  On the other hand, setting ios::in also
02315     // seems to imply ios::nocreate (!), so we should only set this if
02316     // the file already exists.
02317     if (exists()) {
02318       open_mode |= ios::in;
02319     }
02320   }
02321 
02322 #ifdef HAVE_IOS_BINARY
02323   // For some reason, some systems (like Irix) don't define
02324   // ios::binary.
02325   if (!is_text()) {
02326     open_mode |= ios::binary;
02327   }
02328 #endif
02329 
02330   stream.clear();
02331   string os_specific = to_os_specific();
02332 #ifdef HAVE_OPEN_MASK
02333   stream.open(os_specific.c_str(), open_mode, 0666);
02334 #else
02335   stream.open(os_specific.c_str(), open_mode);
02336 #endif
02337 
02338   return (!stream.fail());
02339 }
02340 #endif  // USE_PANDAFILESTREAM
02341 
02342 #ifdef USE_PANDAFILESTREAM
02343 ////////////////////////////////////////////////////////////////////
02344 //     Function: Filename::open_append
02345 //       Access: Published
02346 //  Description: Opens the indicated pifstream for writing the file, if
02347 //               possible.  Returns true if successful, false
02348 //               otherwise.  This requires the setting of the
02349 //               set_text()/set_binary() flags to open the file
02350 //               appropriately as indicated; it is an error to call
02351 //               open_read() without first calling one of set_text()
02352 //               or set_binary().
02353 ////////////////////////////////////////////////////////////////////
02354 bool Filename::
02355 open_append(pofstream &stream) const {
02356   assert(!get_pattern());
02357   assert(is_binary_or_text());
02358 
02359   ios_openmode open_mode = ios::app;
02360 
02361 #ifdef HAVE_IOS_BINARY
02362   // For some reason, some systems (like Irix) don't define
02363   // ios::binary.
02364   if (!is_text()) {
02365     open_mode |= ios::binary;
02366   }
02367 #endif
02368 
02369   stream.clear();
02370   string os_specific = to_os_specific();
02371 #ifdef HAVE_OPEN_MASK
02372   stream.open(os_specific.c_str(), open_mode, 0666);
02373 #else
02374   stream.open(os_specific.c_str(), open_mode);
02375 #endif
02376 
02377   return (!stream.fail());
02378 }
02379 #endif  // USE_PANDAFILESTREAM
02380 
02381 #ifdef USE_PANDAFILESTREAM
02382 ////////////////////////////////////////////////////////////////////
02383 //     Function: Filename::open_read_write
02384 //       Access: Published
02385 //  Description: Opens the indicated fstream for read/write access to
02386 //               the file, if possible.  Returns true if successful,
02387 //               false otherwise.  This requires the setting of the
02388 //               set_text()/set_binary() flags to open the file
02389 //               appropriately as indicated; it is an error to call
02390 //               open_read_write() without first calling one of
02391 //               set_text() or set_binary().
02392 ////////////////////////////////////////////////////////////////////
02393 bool Filename::
02394 open_read_write(pfstream &stream, bool truncate) const {
02395   assert(!get_pattern());
02396   assert(is_binary_or_text());
02397 
02398   ios_openmode open_mode = ios::out | ios::in;
02399 
02400   if (truncate) {
02401     open_mode |= ios::trunc;
02402   }
02403 
02404   // Since ios::in also seems to imply ios::nocreate (!), we must
02405   // guarantee the file already exists before we try to open it.
02406   if (!exists()) {
02407     touch();
02408   }
02409 
02410 #ifdef HAVE_IOS_BINARY
02411   // For some reason, some systems (like Irix) don't define
02412   // ios::binary.
02413   if (!is_text()) {
02414     open_mode |= ios::binary;
02415   }
02416 #endif
02417 
02418   stream.clear();
02419   string os_specific = to_os_specific();
02420 #ifdef HAVE_OPEN_MASK
02421   stream.open(os_specific.c_str(), open_mode, 0666);
02422 #else
02423   stream.open(os_specific.c_str(), open_mode);
02424 #endif
02425 
02426   return (!stream.fail());
02427 }
02428 #endif  // USE_PANDAFILESTREAM
02429 
02430 #ifdef USE_PANDAFILESTREAM
02431 ////////////////////////////////////////////////////////////////////
02432 //     Function: Filename::open_read_append
02433 //       Access: Published
02434 //  Description: Opens the indicated pfstream for reading and writing
02435 //               the file, if possible; writes are appended to the end
02436 //               of the file.  Returns true if successful, false
02437 //               otherwise.  This requires the setting of the
02438 //               set_text()/set_binary() flags to open the file
02439 //               appropriately as indicated; it is an error to call
02440 //               open_read() without first calling one of set_text()
02441 //               or set_binary().
02442 ////////////////////////////////////////////////////////////////////
02443 bool Filename::
02444 open_read_append(pfstream &stream) const {
02445   assert(!get_pattern());
02446   assert(is_binary_or_text());
02447 
02448   ios_openmode open_mode = ios::app | ios::in;
02449 
02450 #ifdef HAVE_IOS_BINARY
02451   // For some reason, some systems (like Irix) don't define
02452   // ios::binary.
02453   if (!is_text()) {
02454     open_mode |= ios::binary;
02455   }
02456 #endif
02457 
02458   stream.clear();
02459   string os_specific = to_os_specific();
02460 #ifdef HAVE_OPEN_MASK
02461   stream.open(os_specific.c_str(), open_mode, 0666);
02462 #else
02463   stream.open(os_specific.c_str(), open_mode);
02464 #endif
02465 
02466   return (!stream.fail());
02467 }
02468 #endif  // USE_PANDAFILESTREAM
02469 
02470 ////////////////////////////////////////////////////////////////////
02471 //     Function: Filename::touch
02472 //       Access: Published
02473 //  Description: Updates the modification time of the file to the
02474 //               current time.  If the file does not already exist, it
02475 //               will be created.  Returns true if successful, false
02476 //               if there is an error.
02477 ////////////////////////////////////////////////////////////////////
02478 bool Filename::
02479 touch() const {
02480   assert(!get_pattern());
02481 #ifdef WIN32_VC
02482   // In Windows, we have to use the Windows API to do this reliably.
02483 
02484   // First, guarantee the file exists (and also get its handle).
02485   wstring os_specific = to_os_specific_w();
02486   HANDLE fhandle;
02487   fhandle = CreateFileW(os_specific.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE,
02488                         NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
02489   if (fhandle == INVALID_HANDLE_VALUE) {
02490     return false;
02491   }
02492 
02493   // Now update the file time and date.
02494   SYSTEMTIME sysnow;
02495   FILETIME ftnow;
02496   GetSystemTime(&sysnow);
02497   if (!SystemTimeToFileTime(&sysnow, &ftnow)) {
02498     CloseHandle(fhandle);
02499     return false;
02500   }
02501   
02502   if (!SetFileTime(fhandle, NULL, NULL, &ftnow)) {
02503     CloseHandle(fhandle);
02504     return false;
02505   }
02506 
02507   CloseHandle(fhandle);
02508   return true;
02509 
02510 #elif defined(PHAVE_UTIME_H)
02511   // Most Unix systems can do this explicitly.
02512 
02513   string os_specific = to_os_specific();
02514 #ifdef HAVE_CYGWIN
02515   // In the Cygwin case, it seems we need to be sure to use the
02516   // Cygwin-style name; some broken utime() implementation.  That's
02517   // almost the same thing as the original Panda-style name, but not
02518   // exactly, so we first convert the Panda name to a Windows name,
02519   // then convert it back to Cygwin, to ensure we get it exactly right
02520   // by Cygwin rules.
02521   {
02522     char result[4096] = "";
02523     cygwin_conv_to_posix_path(os_specific.c_str(), result);
02524     os_specific = result;
02525   }
02526 #endif  // HAVE_CYGWIN
02527   int result = utime(os_specific.c_str(), NULL);
02528   if (result < 0) {
02529     if (errno == ENOENT) {
02530       // So the file doesn't already exist; create it.
02531       int fd = creat(os_specific.c_str(), 0666);
02532       if (fd < 0) {
02533         perror(os_specific.c_str());
02534         return false;
02535       }
02536       close(fd);
02537       return true;
02538     }
02539     perror(os_specific.c_str());
02540     return false;
02541   }
02542   return true;
02543 #else  // WIN32, PHAVE_UTIME_H
02544   // Other systems may not have an explicit control over the
02545   // modification time.  For these systems, we'll just temporarily
02546   // open the file in append mode, then close it again (it gets closed
02547   // when the pfstream goes out of scope).
02548   pfstream file;
02549   return open_append(file);
02550 #endif  // WIN32, PHAVE_UTIME_H
02551 }
02552 
02553 ////////////////////////////////////////////////////////////////////
02554 //     Function: Filename::chdir
02555 //       Access: Published
02556 //  Description: Changes directory to the specified location.
02557 //               Returns true if successful, false if failure.
02558 ////////////////////////////////////////////////////////////////////
02559 bool Filename::
02560 chdir() const {
02561 #ifdef WIN32_VC
02562   wstring os_specific = to_os_specific_w();
02563   return (_wchdir(os_specific.c_str()) >= 0);
02564 #else
02565   string os_specific = to_os_specific();
02566   return (::chdir(os_specific.c_str()) >= 0);
02567 #endif  // WIN32_VC
02568 }
02569 
02570 ////////////////////////////////////////////////////////////////////
02571 //     Function: Filename::unlink
02572 //       Access: Published
02573 //  Description: Permanently deletes the file associated with the
02574 //               filename, if possible.  Returns true if successful,
02575 //               false if failure (for instance, because the file did
02576 //               not exist, or because permissions were inadequate).
02577 ////////////////////////////////////////////////////////////////////
02578 bool Filename::
02579 unlink() const {
02580   assert(!get_pattern());
02581 #ifdef WIN32_VC
02582   // Windows can't delete a file if it's read-only.  Weird.
02583   wstring os_specific = to_os_specific_w();
02584   _wchmod(os_specific.c_str(), 0644);
02585   return (_wunlink(os_specific.c_str()) == 0);
02586 #else
02587   string os_specific = to_os_specific();
02588   return (::unlink(os_specific.c_str()) == 0);
02589 #endif  // WIN32_VC
02590 }
02591 
02592 
02593 ////////////////////////////////////////////////////////////////////
02594 //     Function: Filename::rename_to
02595 //       Access: Published
02596 //  Description: Renames the file to the indicated new filename.  If
02597 //               the new filename is in a different directory, this
02598 //               will perform a move.  Returns true if successful,
02599 //               false on failure.
02600 ////////////////////////////////////////////////////////////////////
02601 bool Filename::
02602 rename_to(const Filename &other) const {
02603   assert(!get_pattern());
02604 
02605   if (*this == other) {
02606     // Trivial success.
02607     return true;
02608   }
02609 
02610 #ifdef WIN32_VC
02611   wstring os_specific = to_os_specific_w();
02612   wstring other_os_specific = other.to_os_specific_w();
02613 
02614   if (_wrename(os_specific.c_str(),
02615                other_os_specific.c_str()) == 0) {
02616     // Successfully renamed.
02617     return true;
02618   }
02619 
02620   // The above might fail if we have tried to move a file to a
02621   // different filesystem.  In this case, copy the file into the same
02622   // directory first, and then rename it.
02623   string dirname = other.get_dirname();
02624   if (dirname.empty()) {
02625     dirname = ".";
02626   }
02627   Filename temp = Filename::temporary(dirname, "");
02628   temp.set_binary();
02629   if (!Filename::binary_filename(*this).copy_to(temp)) {
02630     return false;
02631   }
02632 
02633   wstring temp_os_specific = temp.to_os_specific_w();
02634   if (_wrename(temp_os_specific.c_str(),
02635                other_os_specific.c_str()) == 0) {
02636     // Successfully renamed.
02637     unlink();
02638     return true;
02639   }
02640 
02641   // Try unlinking the target first.
02642   other.unlink();
02643   if (_wrename(temp_os_specific.c_str(),
02644                other_os_specific.c_str()) == 0) {
02645     // Successfully renamed.
02646     unlink();
02647     return true;
02648   }
02649 #else  // WIN32_VC
02650   string os_specific = to_os_specific();
02651   string other_os_specific = other.to_os_specific();
02652 
02653   if (rename(os_specific.c_str(),
02654              other_os_specific.c_str()) == 0) {
02655     // Successfully renamed.
02656     return true;
02657   }
02658 
02659   // The above might fail if we have tried to move a file to a
02660   // different filesystem.  In this case, copy the file into the same
02661   // directory first, and then rename it.
02662   string dirname = other.get_dirname();
02663   if (dirname.empty()) {
02664     dirname = ".";
02665   }
02666   Filename temp = Filename::temporary(dirname, "");
02667   temp.set_binary();
02668   if (!Filename::binary_filename(*this).copy_to(temp)) {
02669     return false;
02670   }
02671 
02672   string temp_os_specific = temp.to_os_specific();
02673   if (rename(temp_os_specific.c_str(),
02674              other_os_specific.c_str()) == 0) {
02675     // Successfully renamed.
02676     unlink();
02677     return true;
02678   }
02679 
02680   // Try unlinking the target first.
02681   other.unlink();
02682   if (rename(temp_os_specific.c_str(),
02683              other_os_specific.c_str()) == 0) {
02684     // Successfully renamed.
02685     unlink();
02686     return true;
02687   }
02688 #endif  // WIN32_VC
02689 
02690   // Failed.
02691   temp.unlink();
02692   return false;
02693 }
02694 
02695 ////////////////////////////////////////////////////////////////////
02696 //     Function: Filename::copy_to
02697 //       Access: Published
02698 //  Description: Copies the file to the indicated new filename, by
02699 //               reading the contents and writing it to the new file.
02700 //               Returns true if successful, false on failure.  The
02701 //               copy is always binary, regardless of the filename
02702 //               settings.
02703 ////////////////////////////////////////////////////////////////////
02704 bool Filename::
02705 copy_to(const Filename &other) const {
02706   Filename this_filename = Filename::binary_filename(*this);
02707   pifstream in;
02708   if (!this_filename.open_read(in)) {
02709     return false;
02710   }
02711 
02712   Filename other_filename = Filename::binary_filename(other);
02713   pofstream out;
02714   if (!other_filename.open_write(out)) {
02715     return false;
02716   }
02717         
02718   static const size_t buffer_size = 4096;
02719   char buffer[buffer_size];
02720   
02721   in.read(buffer, buffer_size);
02722   size_t count = in.gcount();
02723   while (count != 0) {
02724     out.write(buffer, count);
02725     if (out.fail()) {
02726       other.unlink();
02727       return false;
02728     }
02729     in.read(buffer, buffer_size);
02730     count = in.gcount();
02731   }
02732 
02733   if (!in.eof()) {
02734     other.unlink();
02735     return false;
02736   }
02737 
02738   return true;
02739 }
02740 
02741 ////////////////////////////////////////////////////////////////////
02742 //     Function: Filename::make_dir
02743 //       Access: Published
02744 //  Description: Creates all the directories in the path to the file
02745 //               specified in the filename, except for the basename
02746 //               itself.  This assumes that the Filename contains the
02747 //               name of a file, not a directory name; it ensures that
02748 //               the directory containing the file exists.
02749 //
02750 //               However, if the filename ends in a slash, it assumes
02751 //               the Filename represents the name of a directory, and
02752 //               creates all the paths.
02753 ////////////////////////////////////////////////////////////////////
02754 bool Filename::
02755 make_dir() const {
02756   assert(!get_pattern());
02757   if (empty()) {
02758     return false;
02759   }
02760   Filename path;
02761   if (_filename[_filename.length() - 1] == '/') {
02762     // The Filename ends in a slash; it represents a directory.
02763     path = (*this);
02764 
02765   } else {
02766     // The Filename does not end in a slash; it represents a file.
02767     path = get_dirname();
02768   }
02769 
02770   if (path.empty()) {
02771     return false;
02772   }
02773   string dirname = path.get_fullpath();
02774 
02775   // First, make sure everything up to the last path is known.  We
02776   // don't care too much if any of these fail; maybe they failed
02777   // because the directory was already there.
02778   size_t slash = dirname.find('/');
02779   while (slash != string::npos) {
02780     Filename component(dirname.substr(0, slash));
02781 #ifdef WIN32_VC
02782     wstring os_specific = component.to_os_specific_w();
02783     _wmkdir(os_specific.c_str());
02784 #else
02785     string os_specific = component.to_os_specific();
02786     ::mkdir(os_specific.c_str(), 0777);
02787 #endif  // WIN32_VC
02788     slash = dirname.find('/', slash + 1);
02789   }
02790 
02791   // Now make the last one, and check the return value.
02792   Filename component(dirname);
02793 #ifdef WIN32_VC
02794   wstring os_specific = component.to_os_specific_w();
02795   int result = _wmkdir(os_specific.c_str());
02796 #else
02797   string os_specific = component.to_os_specific();
02798   int result = ::mkdir(os_specific.c_str(), 0777);
02799 #endif  // WIN32_VC
02800 
02801   return (result == 0);
02802 }
02803 
02804 ////////////////////////////////////////////////////////////////////
02805 //     Function: Filename::mkdir
02806 //       Access: Published
02807 //  Description: Creates the directory named by this filename.  Unlike
02808 //               make_dir(), this assumes that the Filename contains
02809 //               the directory name itself.  Also, parent directories
02810 //               are not automatically created; this function fails if
02811 //               any parent directory is missing.
02812 ////////////////////////////////////////////////////////////////////
02813 bool Filename::
02814 mkdir() const {
02815 #ifdef WIN32_VC
02816   wstring os_specific = to_os_specific_w();
02817   int result = _wmkdir(os_specific.c_str());
02818 #else
02819   string os_specific = to_os_specific();
02820   int result = ::mkdir(os_specific.c_str(), 0777);
02821 #endif  // WIN32_VC
02822 
02823   return (result == 0);
02824 }
02825 
02826 ////////////////////////////////////////////////////////////////////
02827 //     Function: Filename::rmdir
02828 //       Access: Published
02829 //  Description: The inverse of mkdir(): this removes the directory
02830 //               named by this Filename, if it is in fact a directory.
02831 ////////////////////////////////////////////////////////////////////
02832 bool Filename::
02833 rmdir() const {
02834 #ifdef WIN32_VC
02835   wstring os_specific = to_os_specific_w();
02836 
02837   int result = _wrmdir(os_specific.c_str());
02838   if (result != 0) {
02839     // Windows may require the directory to be writable before we can
02840     // remove it.
02841     _wchmod(os_specific.c_str(), 0777);
02842     result = _wrmdir(os_specific.c_str());
02843   }
02844 
02845 #else  // WIN32_VC
02846   string os_specific = to_os_specific();
02847   int result = ::rmdir(os_specific.c_str());
02848 #endif  // WIN32_VC
02849 
02850   return (result == 0);
02851 }
02852 
02853 ////////////////////////////////////////////////////////////////////
02854 //     Function: Filename::get_hash
02855 //       Access: Published
02856 //  Description: Returns a hash code that attempts to be mostly unique
02857 //               for different Filenames.
02858 ////////////////////////////////////////////////////////////////////
02859 int Filename::
02860 get_hash() const {
02861   static const int primes[] = {
02862       2,    3,    5,    7,   11,   13,   17,   19,   23,   29,
02863      31,   37,   41,   43,   47,   53,   59,   61,   67,   71,
02864      73,   79,   83,   89,   97,  101,  103,  107,  109,  113,
02865     127,  131,  137,  139,  149,  151,  157,  163,  167,  173,
02866     179,  181,  191,  193,  197,  199,  211,  223,  227,  229,
02867     233,  239,  241,  251,  257,  263,  269,  271,  277,  281,
02868     283,  293,  307,  311,  313,  317,  331,  337,  347,  349,
02869     353,  359,  367,  373,  379,  383,  389,  397,  401,  409,
02870     419,  421,  431,  433,  439,  443,  449,  457,  461,  463,
02871     467,  479,  487,  491,  499,  503,  509,  521,  523,  541,
02872     547,  557,  563,  569,  571,  577,  587,  593,  599,  601,
02873     607,  613,  617,  619,  631,  641,  643,  647,  653,  659,
02874     661,  673,  677,  683,  691,  701,  709,  719,  727,  733,
02875     739,  743,  751,  757,  761,  769,  773,  787,  797,  809,
02876     811,  821,  823,  827,  829,  839,  853,  857,  859,  863,
02877     877,  881,  883,  887,  907,  911,  919,  929,  937,  941,
02878     947,  953,  967,  971,  977,  983,  991,  997
02879   };
02880   static const size_t num_primes = sizeof(primes) / sizeof(int);
02881 
02882   int hash = 0;
02883   for (size_t i = 0; i < _filename.size(); ++i) {
02884     hash += (int)_filename[i] * primes[i % num_primes];
02885   }
02886 
02887   return hash;
02888 }
02889 
02890 
02891 ////////////////////////////////////////////////////////////////////
02892 //     Function: Filename::atomic_compare_and_exchange_contents
02893 //       Access: Public
02894 //  Description: Uses native file-locking mechanisms to atomically
02895 //               replace the contents of a (small) file with the
02896 //               specified contents, assuming it hasn't changed since
02897 //               the last time the file was read.
02898 //
02899 //               This is designed to be similar to
02900 //               AtomicAdjust::compare_and_exchange().  The method
02901 //               writes new_contents to the file, completely replacing
02902 //               the original contents; but only if the original
02903 //               contents exactly matched old_contents.  If the file
02904 //               was modified, returns true.  If, however, the
02905 //               original contents of the file did not exactly match
02906 //               old_contents, then the file is not modified, and
02907 //               false is returned.  In either case, orig_contents is
02908 //               filled with the original contents of the file.
02909 //
02910 //               If the file does not exist, it is implicitly created,
02911 //               and its original contents are empty.
02912 //
02913 //               If an I/O error occurs on write, some of the file may
02914 //               or may not have been written, and false is returned.
02915 //
02916 //               Expressed in pseudo-code, the logic is:
02917 //
02918 //                 orig_contents = file.read();
02919 //                 if (orig_contents == old_contents) {
02920 //                   file.write(new_contents);
02921 //                   return true;
02922 //                 }
02923 //                 return false;
02924 //
02925 //               The operation is guaranteed to be atomic only if the
02926 //               only operations that read and write to this file are
02927 //               atomic_compare_and_exchange_contents() and
02928 //               atomic_read_contents().
02929 ////////////////////////////////////////////////////////////////////
02930 bool Filename::
02931 atomic_compare_and_exchange_contents(string &orig_contents, 
02932                                      const string &old_contents, 
02933                                      const string &new_contents) const {
02934 #ifdef WIN32_VC
02935   wstring os_specific = to_os_specific_w();
02936   HANDLE hfile = CreateFileW(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE, 
02937                              0, NULL, OPEN_ALWAYS,
02938                              FILE_ATTRIBUTE_NORMAL, NULL);
02939   while (hfile == INVALID_HANDLE_VALUE) {
02940     DWORD error = GetLastError();
02941     if (error == ERROR_SHARING_VIOLATION) {
02942       // If the file is locked by another process, yield and try again.
02943       Sleep(0);
02944       hfile = CreateFileW(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE, 
02945                           0, NULL, OPEN_ALWAYS,
02946                           FILE_ATTRIBUTE_NORMAL, NULL);
02947     } else {
02948       cerr << "Couldn't open file: " << os_specific 
02949            << ", error " << error << "\n";
02950       return false;
02951     }
02952   }
02953 
02954   if (hfile == INVALID_HANDLE_VALUE) {
02955     cerr << "Couldn't open file: " << os_specific 
02956          << ", error " << GetLastError() << "\n";
02957     return false;
02958   }
02959 
02960   static const size_t buf_size = 512;
02961   char buf[buf_size];
02962 
02963   orig_contents = string();
02964 
02965   DWORD bytes_read;
02966   if (!ReadFile(hfile, buf, buf_size, &bytes_read, NULL)) {
02967     cerr << "Error reading file: " << os_specific 
02968          << ", error " << GetLastError() << "\n";
02969     CloseHandle(hfile);
02970     return false;
02971   }
02972   while (bytes_read > 0) {
02973     orig_contents += string(buf, bytes_read);
02974 
02975     if (!ReadFile(hfile, buf, buf_size, &bytes_read, NULL)) {
02976       cerr << "Error reading file: " << os_specific 
02977            << ", error " << GetLastError() << "\n";
02978       CloseHandle(hfile);
02979       return false;
02980     }
02981   }
02982 
02983   bool match = false;
02984   if (orig_contents == old_contents) {
02985     match = true;
02986     SetFilePointer(hfile, 0, 0, FILE_BEGIN);
02987     DWORD bytes_written;
02988     if (!WriteFile(hfile, new_contents.data(), new_contents.size(),
02989                    &bytes_written, NULL)) {
02990       cerr << "Error writing file: " << os_specific 
02991            << ", error " << GetLastError() << "\n";
02992       CloseHandle(hfile);
02993       return false;
02994     }
02995   }
02996 
02997   CloseHandle(hfile);
02998   return match;
02999 
03000 #else  // WIN32_VC
03001   string os_specific = to_os_specific();
03002   int fd = open(os_specific.c_str(), O_RDWR | O_CREAT, 0666);
03003   if (fd < 0) {
03004     perror(os_specific.c_str());
03005     return false;
03006   }
03007 
03008   static const size_t buf_size = 512;
03009   char buf[buf_size];
03010 
03011   orig_contents = string();
03012 
03013   if (lockf(fd, F_LOCK, 0) != 0) {
03014     perror(os_specific.c_str());
03015     close(fd);
03016     return false;
03017   }
03018     
03019   size_t bytes_read = read(fd, buf, buf_size);
03020   while (bytes_read > 0) {
03021     orig_contents += string(buf, bytes_read);
03022     bytes_read = read(fd, buf, buf_size);
03023   }
03024 
03025   if (bytes_read < 0) {
03026     perror(os_specific.c_str());
03027     close(fd);
03028     return false;
03029   }
03030 
03031   bool match = false;
03032   if (orig_contents == old_contents) {
03033     match = true;
03034     lseek(fd, 0, SEEK_SET);
03035     ssize_t bytes_written = write(fd, new_contents.data(), new_contents.size());
03036     if (bytes_written < 0) {
03037       perror(os_specific.c_str());
03038       close(fd);
03039       return false;
03040     }
03041   }
03042 
03043   if (close(fd) < 0) {
03044     perror(os_specific.c_str());
03045     return false;
03046   }
03047   
03048   return match;
03049 #endif  // WIN32_VC
03050 }
03051 
03052 ////////////////////////////////////////////////////////////////////
03053 //     Function: Filename::atomic_read_contents
03054 //       Access: Public
03055 //  Description: Uses native file-locking mechanisms to atomically
03056 //               read the contents of a (small) file.  This is the
03057 //               only way to read a file protected by
03058 //               atomic_compare_and_exchange_contents(), and be
03059 //               confident that the read operation is actually atomic
03060 //               with respect to that method.
03061 //
03062 //               If the file does not exist, it is implicitly created,
03063 //               and its contents are empty.
03064 //
03065 //               If the file is read successfully, fills its contents
03066 //               in the indicated string, and returns true.  If the
03067 //               file cannot be read, returns false.
03068 ////////////////////////////////////////////////////////////////////
03069 bool Filename::
03070 atomic_read_contents(string &contents) const {
03071 #ifdef WIN32_VC
03072   wstring os_specific = to_os_specific_w();
03073   HANDLE hfile = CreateFileW(os_specific.c_str(), GENERIC_READ, 
03074                              FILE_SHARE_READ, NULL, OPEN_ALWAYS,
03075                              FILE_ATTRIBUTE_NORMAL, NULL);
03076   while (hfile == INVALID_HANDLE_VALUE) {
03077     DWORD error = GetLastError();
03078     if (error == ERROR_SHARING_VIOLATION) {
03079       // If the file is locked by another process, yield and try again.
03080       Sleep(0);
03081       hfile = CreateFileW(os_specific.c_str(), GENERIC_READ, 
03082                           FILE_SHARE_READ, NULL, OPEN_ALWAYS,
03083                           FILE_ATTRIBUTE_NORMAL, NULL);      
03084     } else {
03085       cerr << "Couldn't open file: " << os_specific 
03086            << ", error " << error << "\n";
03087       return false;
03088     }
03089   }
03090 
03091   static const size_t buf_size = 512;
03092   char buf[buf_size];
03093 
03094   contents = string();
03095 
03096   DWORD bytes_read;
03097   if (!ReadFile(hfile, buf, buf_size, &bytes_read, NULL)) {
03098     cerr << "Error reading file: " << os_specific 
03099          << ", error " << GetLastError() << "\n";
03100     CloseHandle(hfile);
03101     return false;
03102   }
03103   while (bytes_read > 0) {
03104     contents += string(buf, bytes_read);
03105 
03106     if (!ReadFile(hfile, buf, buf_size, &bytes_read, NULL)) {
03107       cerr << "Error reading file: " << os_specific 
03108            << ", error " << GetLastError() << "\n";
03109       CloseHandle(hfile);
03110       return false;
03111     }
03112   }
03113 
03114   CloseHandle(hfile);
03115   return true;
03116 
03117 #else  // WIN32_VC
03118   string os_specific = to_os_specific();
03119   int fd = open(os_specific.c_str(), O_RDWR | O_CREAT, 0666);
03120   if (fd < 0) {
03121     perror(os_specific.c_str());
03122     return false;
03123   }
03124 
03125   static const size_t buf_size = 512;
03126   char buf[buf_size];
03127 
03128   contents = string();
03129 
03130   if (lockf(fd, F_LOCK, 0) != 0) {
03131     perror(os_specific.c_str());
03132     close(fd);
03133     return false;
03134   }
03135     
03136   size_t bytes_read = read(fd, buf, buf_size);
03137   while (bytes_read > 0) {
03138     contents += string(buf, bytes_read);
03139     bytes_read = read(fd, buf, buf_size);
03140   }
03141 
03142   if (bytes_read < 0) {
03143     perror(os_specific.c_str());
03144     close(fd);
03145     return false;
03146   }
03147 
03148   close(fd);
03149   return true;
03150 #endif  // WIN32_VC
03151 }
03152 
03153 ////////////////////////////////////////////////////////////////////
03154 //     Function: Filename::locate_basename
03155 //       Access: Protected
03156 //  Description: After the string has been reassigned, search for the
03157 //               slash marking the beginning of the basename, and set
03158 //               _dirname_end and _basename_start correctly.
03159 ////////////////////////////////////////////////////////////////////
03160 void Filename::
03161 locate_basename() {
03162   // Scan for the last slash, which marks the end of the directory
03163   // part.
03164   if (_filename.empty()) {
03165     _dirname_end = 0;
03166     _basename_start = 0;
03167 
03168   } else {
03169 
03170     string::size_type slash = _filename.rfind('/');
03171     if (slash != string::npos) {
03172       _basename_start = slash + 1;
03173       _dirname_end = _basename_start;
03174 
03175       // One exception: in case there are multiple slashes in a row,
03176       // we want to treat them as a single slash.  The directory
03177       // therefore actually ends at the first of these; back up a bit.
03178       while (_dirname_end > 0 && _filename[_dirname_end-1] == '/') {
03179         _dirname_end--;
03180       }
03181 
03182       // Another exception: if the dirname was nothing but slashes, it
03183       // was the root directory, or / itself.  In this case the dirname
03184       // does include the terminal slash (of course).
03185       if (_dirname_end == 0) {
03186         _dirname_end = 1;
03187       }
03188 
03189     } else {
03190       _dirname_end = 0;
03191       _basename_start = 0;
03192     }
03193   }
03194 
03195   // Now:
03196 
03197   // _dirname_end is the last slash character, or 0 if there are no
03198   // slash characters.
03199 
03200   // _basename_start is the character after the last slash character,
03201   // or 0 if there are no slash characters.
03202 }
03203 
03204 
03205 ////////////////////////////////////////////////////////////////////
03206 //     Function: Filename::locate_extension
03207 //       Access: Protected
03208 //  Description: Once the end of the directory prefix has been found,
03209 //               and _dirname_end and _basename_start are set
03210 //               correctly, search for the dot marking the beginning
03211 //               of the extension, and set _basename_end and
03212 //               _extension_start correctly.
03213 ////////////////////////////////////////////////////////////////////
03214 void Filename::
03215 locate_extension() {
03216   // Now scan for the last dot after that slash.
03217   if (_filename.empty()) {
03218     _basename_end = string::npos;
03219     _extension_start = string::npos;
03220 
03221   } else {
03222     string::size_type dot = _filename.length() - 1;
03223 
03224     while (dot+1 > _basename_start && _filename[dot] != '.') {
03225       --dot;
03226     }
03227 
03228     if (dot+1 > _basename_start) {
03229       _basename_end = dot;
03230       _extension_start = dot + 1;
03231     } else {
03232       _basename_end = string::npos;
03233       _extension_start = string::npos;
03234     }
03235   }
03236 
03237   // Now:
03238 
03239   // _basename_end is the last dot, or npos if there is no dot.
03240 
03241   // _extension_start is the character after the last dot, or npos if
03242   // there is no dot.
03243 }
03244 
03245 ////////////////////////////////////////////////////////////////////
03246 //     Function: Filename::locate_hash
03247 //       Access: Protected
03248 //  Description: Identifies the part of the filename that contains the
03249 //               sequence of hash marks, if any.
03250 ////////////////////////////////////////////////////////////////////
03251 void Filename::
03252 locate_hash() {
03253   if (!get_pattern()) {
03254     // If it's not a pattern-type filename, these are always set to
03255     // the end of the string.
03256     _hash_end = string::npos;
03257     _hash_start = string::npos;
03258 
03259   } else {
03260     // If it is a pattern-type filename, we must search for the hash
03261     // marks, which could be anywhere (but are usually toward the
03262     // end).
03263     _hash_end = _filename.rfind('#');
03264     if (_hash_end == string::npos) {
03265       _hash_end = string::npos;
03266       _hash_start = string::npos;
03267       
03268     } else {
03269       _hash_start = _hash_end;
03270       ++_hash_end;
03271       while (_hash_start > 0 && _filename[_hash_start - 1] == '#') {
03272         --_hash_start;
03273       }
03274     }
03275   }
03276 }
03277 
03278 
03279 ////////////////////////////////////////////////////////////////////
03280 //     Function: Filename::get_common_prefix
03281 //       Access: Protected
03282 //  Description: Returns the length of the longest common initial
03283 //               substring of this string and the other one that ends
03284 //               in a slash.  This is the lowest directory common to
03285 //               both filenames.
03286 ////////////////////////////////////////////////////////////////////
03287 size_t Filename::
03288 get_common_prefix(const string &other) const {
03289   size_t len = 0;
03290 
03291   // First, get the length of the common initial substring.
03292   while (len < length() && len < other.length() &&
03293          _filename[len] == other[len]) {
03294     len++;
03295   }
03296 
03297   // Now insist that it ends in a slash.
03298   while (len > 0 && _filename[len-1] != '/') {
03299     len--;
03300   }
03301 
03302   return len;
03303 }
03304 
03305 ////////////////////////////////////////////////////////////////////
03306 //     Function: Filename::count_slashes
03307 //       Access: Protected, Static
03308 //  Description: Returns the number of non-consecutive slashes in the
03309 //               indicated string, not counting a terminal slash.
03310 ////////////////////////////////////////////////////////////////////
03311 int Filename::
03312 count_slashes(const string &str) {
03313   int count = 0;
03314   string::const_iterator si;
03315   si = str.begin();
03316 
03317   while (si != str.end()) {
03318     if (*si == '/') {
03319       count++;
03320 
03321       // Skip consecutive slashes.
03322       ++si;
03323       while (*si == '/') {
03324         ++si;
03325       }
03326       if (si == str.end()) {
03327         // Oops, that was a terminal slash.  Don't count it.
03328         count--;
03329       }
03330 
03331     } else {
03332       ++si;
03333     }
03334   }
03335 
03336   return count;
03337 }
03338 
03339 
03340 ////////////////////////////////////////////////////////////////////
03341 //     Function: Filename::r_make_canonical
03342 //       Access: Protected
03343 //  Description: The recursive implementation of make_canonical().
03344 ////////////////////////////////////////////////////////////////////
03345 bool Filename::
03346 r_make_canonical(const Filename &cwd) {
03347   if (get_fullpath() == "/") {
03348     // If we reached the root, the whole path doesn't exist.  Report
03349     // failure.
03350     return false;
03351   }
03352 
03353 #ifdef WIN32_VC
03354   // First, try to cd to the filename directly.
03355   wstring os_specific = to_os_specific_w();
03356   if (_wchdir(os_specific.c_str()) >= 0) {
03357     // That worked, save the full path string.
03358     (*this) = ExecutionEnvironment::get_cwd();
03359 
03360     // And restore the current working directory.
03361     wstring osdir = cwd.to_os_specific_w();
03362     if (_wchdir(osdir.c_str()) < 0) {
03363       cerr << "Error!  Cannot change back to " << osdir << "\n";
03364     }
03365     return true;
03366   }
03367 #else  // WIN32_VC
03368   // First, try to cd to the filename directly.
03369   string os_specific = to_os_specific();
03370   if (::chdir(os_specific.c_str()) >= 0) {
03371     // That worked, save the full path string.
03372     (*this) = ExecutionEnvironment::get_cwd();
03373 
03374     // And restore the current working directory.
03375     string osdir = cwd.to_os_specific();
03376     if (::chdir(osdir.c_str()) < 0) {
03377       cerr << "Error!  Cannot change back to " << osdir << "\n";
03378     }
03379     return true;
03380   }
03381 #endif  // WIN32_VC
03382 
03383   // That didn't work; maybe it's not a directory.  Recursively go to
03384   // the directory above.
03385 
03386   Filename dir(get_dirname());
03387   
03388   if (dir.empty()) {
03389     // No dirname means the file is in this directory.
03390     set_dirname(cwd);
03391     return true;
03392   }
03393   
03394   if (!dir.r_make_canonical(cwd)) {
03395     return false;
03396   }
03397   set_dirname(dir);
03398   return true;
03399 }
03400 
 All Classes Functions Variables Enumerations