From 076d00674a5b1935abd67d471e8b1d09f36691dc Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 14 Nov 2000 04:13:37 +0000 Subject: [PATCH] *** empty log message *** --- dtool/src/dtoolutil/filename.cxx | 118 ++++++++++++++++++++++++++----- dtool/src/dtoolutil/filename.h | 2 + 2 files changed, 103 insertions(+), 17 deletions(-) diff --git a/dtool/src/dtoolutil/filename.cxx b/dtool/src/dtoolutil/filename.cxx index e9427f6295..9e566c89e2 100644 --- a/dtool/src/dtoolutil/filename.cxx +++ b/dtool/src/dtoolutil/filename.cxx @@ -517,6 +517,76 @@ make_absolute(const Filename &start_directory) { standardize(); } +//////////////////////////////////////////////////////////////////// +// Function: Filename::make_canonical +// Access: Public +// Description: Converts this filename to a canonical name by +// replacing the directory part with the fully-qualified +// directory part. This is done by changing to that +// directory and calling getcwd(). +// +// This has the effect of (a) converting relative paths +// to absolute paths (but see make_absolute() if this is +// the only effect you want), and (b) always resolving a +// given directory name to the same string, even if +// different symbolic links are traversed, and (c) +// changing nice symbolic-link paths like +// /fit/people/drose to ugly NFS automounter names like +// /hosts/dimbo/usr2/fit/people/drose. This can be +// troubling, but sometimes this is exactly what you +// want, particularly if you're about to call +// make_relative_to() between two filenames. +// +// The return value is true if successful, or false on +// failure (usually because the directory name does not +// exist or cannot be chdir'ed into). +//////////////////////////////////////////////////////////////////// +bool Filename:: +make_canonical() { + if (empty()) { + // An empty filename is a special case. This doesn't name + // anything. + return false; + } + + // Temporarily save the current working directory. + Filename cwd = ExecutionEnvironment::get_cwd(); + + if (is_directory()) { + // If the filename itself represents a directory and not a + // filename, cd to the named directory, not the one above it. + string dirname = get_fullpath(); + + if (chdir(dirname.c_str()) < 0) { + return false; + } + (*this) = ExecutionEnvironment::get_cwd(); + + } else { + // Otherwise, if the filename represents a regular file (or + // doesn't even exist), cd to the directory above. + string dirname = get_dirname(); + + if (dirname.empty()) { + // No dirname means the file is in this directory. + set_dirname(cwd); + return true; + } + + if (chdir(dirname.c_str()) < 0) { + return false; + } + set_dirname(ExecutionEnvironment::get_cwd().get_fullpath()); + } + + // Now restore the current working directory. + if (chdir(cwd.c_str()) < 0) { + cerr << "Error! Cannot change back to " << cwd << "\n"; + } + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: Filename::to_os_specific // Access: Public @@ -777,6 +847,10 @@ resolve_filename(const DSearchPath &searchpath, // begin with, and may or may not end with, a slash--a // terminating slash is ignored). // +// This only performs a string comparsion, so it may be +// wise to call make_canonical() on both filenames +// before calling make_relative_to(). +// // If allow_backups is false, the filename will only be // adjusted to be made relative if it is already // somewhere within or below the indicated directory. @@ -1061,32 +1135,42 @@ rename_to(const Filename &other) const { } //////////////////////////////////////////////////////////////////// -// Function: Filename::mkdir +// Function: Filename::make_dir // Access: Public // Description: Creates all the directories in the path to the file -// specified in the filename (useful for writing). +// specified in the filename, except for the basename +// itself. This assumes that the Filename contains the +// name of a file, not a directory name; it ensures that +// the directory containing the file exists. //////////////////////////////////////////////////////////////////// bool Filename:: make_dir() const { - size_t p = 0; - while (p < _filename.length()) { - size_t slash = _filename.find('/', p); - if (slash != string::npos) { - string component = _filename.substr(0, slash); - if (!(component == ".") || - !(component == "..")) { + Filename path = *this; + path.standardize(); + string dirname = path.get_dirname(); + + // First, make sure everything up to the last path is known. We + // don't care too much if any of these fail; maybe they failed + // because the directory was already there. + size_t slash = dirname.find('/'); + while (slash != string::npos) { + string component = dirname.substr(0, slash); #ifndef WIN32_VC - mkdir(component.c_str(), 0xffff); + mkdir(component.c_str(), 0777); #else - mkdir(component.c_str()); + mkdir(component.c_str()); #endif - } - } - p = slash; - while (p < _filename.length() && _filename[p] == '/') - p++; + slash = dirname.find('/', slash + 1); } - return true; + + // Now make the last one, and check the return value. +#ifndef WIN32_VC + int result = mkdir(dirname.c_str(), 0777); +#else + int result = mkdir(component.c_str()); +#endif + + return (result == 0); } diff --git a/dtool/src/dtoolutil/filename.h b/dtool/src/dtoolutil/filename.h index 345ce5c69b..a9565ef50a 100644 --- a/dtool/src/dtoolutil/filename.h +++ b/dtool/src/dtoolutil/filename.h @@ -119,6 +119,8 @@ public: void make_absolute(); void make_absolute(const Filename &start_directory); + bool make_canonical(); + string to_os_specific() const; bool exists() const;