Browse Source

allow make_canonical() to work for paths that don't completely exist

David Rose 22 years ago
parent
commit
224463894e
2 changed files with 54 additions and 36 deletions
  1. 53 36
      dtool/src/dtoolutil/filename.cxx
  2. 1 0
      dtool/src/dtoolutil/filename.h

+ 53 - 36
dtool/src/dtoolutil/filename.cxx

@@ -705,44 +705,14 @@ make_canonical() {
     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 = to_os_specific();
-
-    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.
-    Filename dir(get_dirname());
-
-    if (dir.empty()) {
-      // No dirname means the file is in this directory.
-      set_dirname(cwd);
-      return true;
-    }
-
-    string dirname = dir.to_os_specific();
-    if (chdir(dirname.c_str()) < 0) {
-      return false;
-    }
-    set_dirname(ExecutionEnvironment::get_cwd().get_fullpath());
-  }
-
-  // Now restore the current working directory.
-  string osdir = cwd.to_os_specific();
-  if (chdir(osdir.c_str()) < 0) {
-    cerr << "Error!  Cannot change back to " << cwd << "\n";
+  if (get_fullpath() == "/") {
+    // The root directory is a special case.
+    return true;
   }
 
-  return true;
+  // Temporarily save the current working directory.
+  Filename cwd = ExecutionEnvironment::get_cwd();
+  return r_make_canonical(cwd);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1731,3 +1701,50 @@ count_slashes(const string &str) {
   return count;
 }
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: Filename::r_make_canonical
+//       Access: Private
+//  Description: The recursive implementation of make_canonical().
+////////////////////////////////////////////////////////////////////
+bool Filename::
+r_make_canonical(const Filename &cwd) {
+  if (get_fullpath() == "/") {
+    // If we reached the root, the whole path doesn't exist.  Report
+    // failure.
+    return false;
+  }
+
+  // First, try to cd to the filename directly.
+  string os_specific = to_os_specific();
+
+  if (chdir(os_specific.c_str()) >= 0) {
+    // That worked, save the full path string.
+    (*this) = ExecutionEnvironment::get_cwd();
+
+    // And restore the current working directory.
+    string osdir = cwd.to_os_specific();
+    if (chdir(osdir.c_str()) < 0) {
+      cerr << "Error!  Cannot change back to " << cwd << "\n";
+    }
+    return true;
+  }
+
+  // That didn't work; maybe it's not a directory.  Recursively go to
+  // the directory above.
+
+  Filename dir(get_dirname());
+  
+  if (dir.empty()) {
+    // No dirname means the file is in this directory.
+    set_dirname(cwd);
+    return true;
+  }
+  
+  if (!dir.r_make_canonical(cwd)) {
+    return false;
+  }
+  set_dirname(dir);
+  return true;
+}
+

+ 1 - 0
dtool/src/dtoolutil/filename.h

@@ -175,6 +175,7 @@ private:
   void locate_extension();
   size_t get_common_prefix(const string &other) const;
   static int count_slashes(const string &str);
+  bool r_make_canonical(const Filename &cwd);
 
   string _filename;
   // We'll make these size_t instead of string::size_type to help out