Browse Source

get latest filename code, build on Irix

David Rose 23 years ago
parent
commit
adda410582

+ 75 - 0
ppremake/executionEnvironment.cxx

@@ -31,6 +31,81 @@
 #define getcwd _getcwd
 #endif
 
+////////////////////////////////////////////////////////////////////
+//     Function: ExecutionEnvironment::get_environment_variable
+//       Access: Public, Static
+//  Description: Returns the definition of the indicated environment
+//               variable, or the empty string if the variable is
+//               undefined.  The nonstatic implementation.
+////////////////////////////////////////////////////////////////////
+string ExecutionEnvironment::
+get_environment_variable(const string &var) {
+  const char *def = getenv(var.c_str());
+  if (def != (char *)NULL) {
+    return def;
+  }
+  return string();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ExecutionEnviroment::expand_string
+//       Access: Public, Static
+//  Description: Reads the string, looking for environment variable
+//               names marked by a $.  Expands all such variable
+//               names.  A repeated dollar sign ($$) is mapped to a
+//               single dollar sign.
+//
+//               Returns the expanded string.
+////////////////////////////////////////////////////////////////////
+string ExecutionEnvironment::
+expand_string(const string &str) {
+  string result;
+
+  size_t last = 0;
+  size_t dollar = str.find('$');
+  while (dollar != string::npos && dollar + 1 < str.length()) {
+    size_t start = dollar + 1;
+
+    if (str[start] == '$') {
+      // A double dollar sign maps to a single dollar sign.
+      result += str.substr(last, start - last);
+      last = start + 1;
+
+    } else {
+      string varname;
+      size_t end = start;
+
+      if (str[start] == '{') {
+        // Curly braces delimit the variable name explicitly.
+        end = str.find('}', start + 1);
+        if (end != string::npos) {
+          varname = str.substr(start + 1, end - (start + 1));
+          end++;
+        }
+      }
+
+      if (end == start) {
+        // Scan for the end of the variable name.
+        while (end < str.length() && (isalnum(str[end]) || str[end] == '_')) {
+          end++;
+        }
+        varname = str.substr(start, end - start);
+      }
+
+      string subst =
+      result += str.substr(last, dollar - last);
+      result += get_environment_variable(varname);
+      last = end;
+    }
+
+    dollar = str.find('$', last);
+  }
+
+  result += str.substr(last);
+
+  return result;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ExecutionEnviroment::get_cwd
 //       Access: Public, Static

+ 2 - 0
ppremake/executionEnvironment.h

@@ -30,6 +30,8 @@
 ////////////////////////////////////////////////////////////////////
 class ExecutionEnvironment {
 public:
+  static string get_environment_variable(const string &var);
+  static string expand_string(const string &str);
   static Filename get_cwd();
 };
 

+ 201 - 32
ppremake/filename.cxx

@@ -52,6 +52,12 @@
 #include <windows.h>
 #endif
 
+// The MSVC 6.0 Win32 SDK lacks the following definitions, so we define them
+// here for compatibility.
+#ifndef FILE_ATTRIBUTE_DEVICE
+#define FILE_ATTRIBUTE_DEVICE	0x00000040
+#endif
+
 // We might have been linked with the Cygwin dll.  This is ideal if it
 // is available, because it allows Panda to access all the Cygwin
 // mount definitions if they are in use.  If the Cygwin dll is not
@@ -99,7 +105,7 @@ get_panda_root() {
       panda_root = front_to_back_slash(envvar);
     }
 
-    if (!panda_root.empty() && panda_root[panda_root.length() - 1] != '\\') {
+    if (panda_root.empty() || panda_root[panda_root.length() - 1] != '\\') {
       panda_root += '\\';
     }
 
@@ -110,7 +116,7 @@ get_panda_root() {
 }
 
 static string
-convert_pathname(const string &unix_style_pathname) {
+convert_pathname(const string &unix_style_pathname, bool use_backslash) {
   if (unix_style_pathname.empty()) {
     return string();
   }
@@ -133,7 +139,11 @@ convert_pathname(const string &unix_style_pathname) {
     // It doesn't even start from the root, so we don't have to do
     // anything fancy--relative pathnames are the same in Windows as
     // in Unix, except for the direction of the slashes.
-    windows_pathname = front_to_back_slash(unix_style_pathname);
+    if (use_backslash) {
+      windows_pathname = front_to_back_slash(unix_style_pathname);
+    } else {
+      windows_pathname = unix_style_pathname;
+    }
 
   } else if (unix_style_pathname.length() > 3 &&
              isalpha(unix_style_pathname[1]) &&
@@ -145,9 +155,15 @@ convert_pathname(const string &unix_style_pathname) {
     // compilers (e.g. Cygwin's gcc 2.95.3) happy; so that they do not
     // confuse this string constructor with one that takes two
     // iterators.
-    windows_pathname =
-      string(1, (char)toupper(unix_style_pathname[1])) + ":" +
-      front_to_back_slash(unix_style_pathname.substr(2));
+    if (use_backslash) {
+      windows_pathname =
+	string(1, (char)toupper(unix_style_pathname[1])) + ":" +
+	front_to_back_slash(unix_style_pathname.substr(2));
+    } else {
+      windows_pathname =
+	string(1, (char)toupper(unix_style_pathname[1])) + ":" +
+	unix_style_pathname.substr(2);
+    }
 
   } else {
     // It starts with a slash, but the first part is not a single
@@ -157,29 +173,37 @@ convert_pathname(const string &unix_style_pathname) {
     // Use Cygwin to convert it if possible.
     char result[4096] = "";
     cygwin_conv_to_win32_path(unix_style_pathname.c_str(), result);
-    windows_pathname = result;
+    if (use_backslash) {
+      windows_pathname = result;
+    } else {
+      windows_pathname = back_to_front_slash(result);
+    }
 #else  // HAVE_CYGWIN
     // Without Cygwin, just prefix $PANDA_ROOT.
-    windows_pathname =
-      get_panda_root() + front_to_back_slash(unix_style_pathname.substr(1));
+    windows_pathname = get_panda_root();
+    if (use_backslash) {
+      windows_pathname += front_to_back_slash(unix_style_pathname.substr(1));
+    } else {
+      windows_pathname += unix_style_pathname.substr(1);
+    }
 #endif  // HAVE_CYGWIN
   }
 
   return windows_pathname;
 }
 
-string
-convert_dso_pathname(const string &unix_style_pathname) {
+static string
+convert_dso_pathname(const string &unix_style_pathname, bool use_backslash) {
   // If the extension is .so, change it to .dll.
   size_t dot = unix_style_pathname.rfind('.');
   if (dot == string::npos ||
       unix_style_pathname.find('/', dot) != string::npos) {
     // No filename extension.
-    return convert_pathname(unix_style_pathname);
+    return convert_pathname(unix_style_pathname, use_backslash);
   }
   if (unix_style_pathname.substr(dot) != ".so") {
     // Some other extension.
-    return convert_pathname(unix_style_pathname);
+    return convert_pathname(unix_style_pathname, use_backslash);
   }
 
   string dll_basename = unix_style_pathname.substr(0, dot);
@@ -196,27 +220,27 @@ convert_dso_pathname(const string &unix_style_pathname) {
   // somewhere on the LD_LIBRARY_PATH, or on PATH, or any of a number
   // of nutty places.
 
-  return convert_pathname(dll_basename + "_d.dll");
+  return convert_pathname(dll_basename + "_d.dll", use_backslash);
 #else
-  return convert_pathname(dll_basename + ".dll");
+  return convert_pathname(dll_basename + ".dll", use_backslash);
 #endif
 }
 
-string
-convert_executable_pathname(const string &unix_style_pathname) {
+static string
+convert_executable_pathname(const string &unix_style_pathname, bool use_backslash) {
   // If the extension is not .exe, append .exe.
   size_t dot = unix_style_pathname.rfind('.');
   if (dot == string::npos ||
       unix_style_pathname.find('/', dot) != string::npos) {
     // No filename extension.
-    return convert_pathname(unix_style_pathname + ".exe");
+    return convert_pathname(unix_style_pathname + ".exe", use_backslash);
   }
   if (unix_style_pathname.substr(dot) != ".exe") {
     // Some other extension.
-    return convert_pathname(unix_style_pathname + ".exe");
+    return convert_pathname(unix_style_pathname + ".exe", use_backslash);
   }
 
-  return convert_pathname(unix_style_pathname);
+  return convert_pathname(unix_style_pathname, use_backslash);
 }
 #endif //WIN32
 
@@ -313,6 +337,19 @@ from_os_specific(const string &os_specific, Filename::Type type) {
 #endif  // WIN32
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Filename::expand_from
+//       Access: Public, Static
+//  Description: Returns the same thing as from_os_specific(), but
+//               embedded environment variable references
+//               (e.g. "$DMODELS/foo.txt") are expanded out.
+////////////////////////////////////////////////////////////////////
+Filename Filename::
+expand_from(const string &os_specific, Filename::Type type) {
+  return from_os_specific(ExecutionEnvironment::expand_string(os_specific),
+                          type);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Filename::temporary
 //       Access: Public
@@ -505,6 +542,39 @@ set_extension(const string &s) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Filename::extract_components
+//       Access: Public
+//  Description: Extracts out the individual directory components of
+//               the path into a series of strings.  get_basename()
+//               will be the last component stored in the vector.
+//               Note that no distinction is made by this method
+//               between a leading slash and no leading slash, but you
+//               can call is_local() to differentiate the two cases.
+////////////////////////////////////////////////////////////////////
+void Filename::
+extract_components(vector_string &components) const {
+  components.clear();
+
+  size_t p = 0;
+  if (!_filename.empty() && _filename[0] == '/') {
+    // Skip the leading slash.
+    p = 1;
+  }
+  while (p < _filename.length()) {
+    size_t q = _filename.find('/', p);
+    if (q == string::npos) {
+      components.push_back(_filename.substr(p));
+      return;
+    }
+    components.push_back(_filename.substr(p, q - p));
+    p = q + 1;
+  }
+
+  // A trailing slash means we have an empty get_basename().
+  components.push_back(string());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Filename::standardize
 //       Access: Public
@@ -700,11 +770,48 @@ to_os_specific() const {
 #ifdef WIN32
   switch (get_type()) {
   case T_dso:
-    return convert_dso_pathname(standard.get_fullpath());
+    return convert_dso_pathname(standard.get_fullpath(), true);
   case T_executable:
-    return convert_executable_pathname(standard.get_fullpath());
+    return convert_executable_pathname(standard.get_fullpath(), true);
   default:
-    return convert_pathname(standard.get_fullpath());
+    return convert_pathname(standard.get_fullpath(), true);
+  }
+#else // WIN32
+  return standard;
+#endif // WIN32
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Filename::to_os_generic
+//       Access: Public
+//  Description: This is similar to to_os_specific(), but it is
+//               designed to generate a filename that can be
+//               understood on as many platforms as possible.  Since
+//               Windows can usually understand a
+//               forward-slash-delimited filename, this means it does
+//               the same thing as to_os_specific(), but it uses
+//               forward slashes instead of backslashes.
+//
+//               This method has a pretty limited use; it should
+//               generally be used for writing file references to a
+//               file that might be read on any operating system.
+////////////////////////////////////////////////////////////////////
+string Filename::
+to_os_generic() const {
+  if (empty()) {
+    return string();
+  }
+  Filename standard(*this);
+  standard.standardize();
+
+#ifdef WIN32
+  switch (get_type()) {
+  case T_dso:
+    return convert_dso_pathname(standard.get_fullpath(), false);
+  case T_executable:
+    return convert_executable_pathname(standard.get_fullpath(), false);
+  default:
+    return convert_pathname(standard.get_fullpath(), false);
   }
 #else // WIN32
   return standard;
@@ -1158,7 +1265,7 @@ bool Filename::
 open_read(ifstream &stream) const {
   assert(is_text() || is_binary());
 
-  ios::openmode open_mode = ios::in;
+  ios_openmode open_mode = ios::in;
 
 #ifdef HAVE_IOS_BINARY
   // For some reason, some systems (like Irix) don't define
@@ -1184,12 +1291,30 @@ open_read(ifstream &stream) const {
 //               appropriately as indicated; it is an error to call
 //               open_read() without first calling one of set_text()
 //               or set_binary().
+//
+//               If truncate is true, the file is truncated to zero
+//               length upon opening it, if it already exists.
+//               Otherwise, the file is kept at its original length.
 ////////////////////////////////////////////////////////////////////
 bool Filename::
-open_write(ofstream &stream) const {
+open_write(ofstream &stream, bool truncate) const {
   assert(is_text() || is_binary());
 
-  ios::openmode open_mode = ios::out;
+  ios_openmode open_mode = ios::out;
+
+  if (truncate) {
+    open_mode |= ios::trunc;
+
+  } else {
+    // Some systems insist on having ios::in set to prevent the file
+    // from being truncated when we open it.  Makes ios::trunc kind of
+    // pointless, doesn't it?  On the other hand, setting ios::in also
+    // seems to imply ios::nocreate (!), so we should only set this if
+    // the file already exists.
+    if (exists()) {
+      open_mode |= ios::in;
+    }
+  }
 
 #ifdef HAVE_IOS_BINARY
   // For some reason, some systems (like Irix) don't define
@@ -1225,7 +1350,7 @@ bool Filename::
 open_append(ofstream &stream) const {
   assert(is_text() || is_binary());
 
-  ios::openmode open_mode = ios::app;
+  ios_openmode open_mode = ios::app;
 
 #ifdef HAVE_IOS_BINARY
   // For some reason, some systems (like Irix) don't define
@@ -1261,7 +1386,7 @@ bool Filename::
 open_read_write(fstream &stream) const {
   assert(is_text() || is_binary());
 
-  ios::openmode open_mode = ios::in | ios::out;
+  ios_openmode open_mode = ios::in | ios::out;
 
 #ifdef HAVE_IOS_BINARY
   // For some reason, some systems (like Irix) don't define
@@ -1292,7 +1417,36 @@ open_read_write(fstream &stream) const {
 ////////////////////////////////////////////////////////////////////
 bool Filename::
 touch() const {
-#ifdef HAVE_UTIME_H
+#ifdef WIN32_VC
+  // In Windows, we have to use the Windows API to do this reliably.
+
+  // First, guarantee the file exists (and also get its handle).
+  string os_specific = to_os_specific();
+  HANDLE fhandle;
+  fhandle = CreateFile(os_specific.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE,
+                       NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+  if (fhandle == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+
+  // Now update the file time and date.
+  SYSTEMTIME sysnow;
+  FILETIME ftnow;
+  GetSystemTime(&sysnow);
+  if (!SystemTimeToFileTime(&sysnow, &ftnow)) {
+    CloseHandle(fhandle);
+    return false;
+  }
+  
+  if (!SetFileTime(fhandle, NULL, NULL, &ftnow)) {
+    CloseHandle(fhandle);
+    return false;
+  }
+
+  CloseHandle(fhandle);
+  return true;
+
+#elif defined(HAVE_UTIME_H)
   // Most Unix systems can do this explicitly.
 
   string os_specific = to_os_specific();
@@ -1325,14 +1479,14 @@ touch() const {
     return false;
   }
   return true;
-#else  // HAVE_UTIME_H
+#else  // WIN32, HAVE_UTIME_H
   // Other systems may not have an explicit control over the
   // modification time.  For these systems, we'll just temporarily
   // open the file in append mode, then close it again (it gets closed
   // when the ofstream goes out of scope).
   ofstream file;
   return open_append(file);
-#endif  // HAVE_UTIME_H
+#endif  // WIN32, HAVE_UTIME_H
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1374,12 +1528,27 @@ rename_to(const Filename &other) const {
 //               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.
+//
+//               However, if the filename ends in a slash, it assumes
+//               the Filename represents the name of a directory, and
+//               creates all the paths.
 ////////////////////////////////////////////////////////////////////
 bool Filename::
 make_dir() const {
+  if (empty()) {
+    return false;
+  }
   Filename path = *this;
   path.standardize();
-  string dirname = path.get_dirname();
+  string dirname;
+  if (_filename[_filename.length() - 1] == '/') {
+    // The Filename ends in a slash; it represents a directory.
+    dirname = path.get_fullpath();
+
+  } else {
+    // The Filename does not end in a slash; it represents a file.
+    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

+ 5 - 1
ppremake/filename.h

@@ -77,6 +77,8 @@ PUBLISHED:
 
   static Filename from_os_specific(const string &os_specific,
                                    Type type = T_general);
+  static Filename expand_from(const string &user_string, 
+                              Type type = T_general);
   static Filename temporary(const string &dirname, const string &prefix,
                             Type type = T_general);
 
@@ -120,6 +122,7 @@ PUBLISHED:
   INLINE void set_type(Type type);
   INLINE Type get_type() const;
 
+  void extract_components(vector_string &components) const;
   void standardize();
 
   // The following functions deal with the outside world.
@@ -132,6 +135,7 @@ PUBLISHED:
   bool make_canonical();
 
   string to_os_specific() const;
+  string to_os_generic() const;
 
   bool exists() const;
   bool is_regular_file() const;
@@ -148,7 +152,7 @@ PUBLISHED:
   bool scan_directory(vector_string &contents) const;
 
   bool open_read(ifstream &stream) const;
-  bool open_write(ofstream &stream) const;
+  bool open_write(ofstream &stream, bool truncate = true) const;
   bool open_append(ofstream &stream) const;
   bool open_read_write(fstream &stream) const;
 

+ 6 - 6
ppremake/ppScope.cxx

@@ -1911,34 +1911,34 @@ expand_makeguid(const string &params) {
   MD5Final(digest, &context);
 
   string guid;
-  int i = 0;
   char hex[2];
+  int i;
 
-  for (int i = 0; i < 4; i++) {
+  for (i = 0; i < 4; i++) {
     sprintf(hex, "%02x", digest[i]);
     guid.append(hex);
   }
   guid += "-";
 
-  for (int i = 4; i < 6; i++) {
+  for (i = 4; i < 6; i++) {
     sprintf(hex, "%02x", digest[i]);
     guid.append(hex);
   }
   guid += "-";
 
-  for (int i = 6; i < 8; i++) {
+  for (i = 6; i < 8; i++) {
     sprintf(hex, "%02x", digest[i]);
     guid.append(hex);
   }
   guid += "-";
 
-  for (int i = 8; i < 10; i++) {
+  for (i = 8; i < 10; i++) {
     sprintf(hex, "%02x", digest[i]);
     guid.append(hex);
   }
   guid += "-";
 
-  for (int i = 10; i < 16; i++) {
+  for (i = 10; i < 16; i++) {
     sprintf(hex, "%02x", digest[i]);
     guid.append(hex);
   }

+ 18 - 5
ppremake/ppremake.h

@@ -22,17 +22,30 @@
 #include <fstream>
 #ifdef HAVE_SSTREAM
 #include <sstream>
-#else  // HAVE_SSTREAM
+#else  /* HAVE_SSTREAM */
 #include <strstream>
-#endif  // HAVE_SSTREAM
-#else  // HAVE_IOSTREAM
+#endif  /* HAVE_SSTREAM */
+
+typedef std::ios::openmode ios_openmode;
+typedef std::ios::fmtflags ios_fmtflags;
+typedef std::ios::iostate ios_iostate;
+typedef std::ios::seekdir ios_seekdir;
+
+#else  /* HAVE_IOSTREAM */
 #include <iostream.h>
 #include <fstream.h>
 #include <strstream.h>
-#endif  // HAVE_IOSTREAM
+
+typedef int ios_openmode;
+typedef int ios_fmtflags;
+typedef int ios_iostate;
+/* Old iostream libraries used ios::seek_dir instead of ios::seekdir. */
+typedef ios::seek_dir ios_seekdir;
+
+#endif  /* HAVE_IOSTREAM */
 
 #if defined(HAVE_CYGWIN) || defined(WIN32_VC)
-// Either Cygwin or Visual C++ is a Win32 environment.
+/* Either Cygwin or Visual C++ is a Win32 environment. */
 #define WIN32
 #endif