Browse Source

*** empty log message ***

David Rose 25 năm trước cách đây
mục cha
commit
076d00674a
2 tập tin đã thay đổi với 103 bổ sung17 xóa
  1. 101 17
      dtool/src/dtoolutil/filename.cxx
  2. 2 0
      dtool/src/dtoolutil/filename.h

+ 101 - 17
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);
 }
 
 

+ 2 - 0
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;