Browse Source

*** empty log message ***

David Rose 25 years ago
parent
commit
f836633fd5

+ 22 - 18
dtool/pptempl/Global.msvc.pp

@@ -36,36 +36,40 @@
 
 #defun decygwin frompat,topath,path
   #foreach file $[path]
-    #if $[eq $[substr 1,1,$[file]],/]
-      $[patsubst $[frompat],$[topath],$[shell cygpath -w $[file]]]
+    #if $[isfullpath $[file]]
+      $[patsubst $[frompat],$[topath],$[cygpath_w $[file]]]
     #else
-      $[patsubst $[frompat],$[topath],$[file]]
+      $[patsubst $[frompat],$[topath],$[osfilename $[file]]]
     #endif
   #end file
 #end decygwin
 
 // Define this if we want to make .sbr files.
-#defer BROWSEINFO_FLAG -Fr$[target:%.obj=%.sbr]
+#defer BROWSEINFO_FLAG /Fr"$[osfilename $[target:%.obj=%.sbr]]"
+#defer CFLAGS_SHARED
 
-#defer CFLAGS_OPT1 -MDd -GZ -Zi $[BROWSEINFO_FLAG] -Fd$[target:%.obj=%.pdb] -D_DEBUG
-#defer CFLAGS_OPT2 -MDd -Zi -Fd$[target:%.obj=%.pdb] -D_DEBUG -O2 -Ob1 -Ogity -G6
-#defer CFLAGS_OPT3 -MD -DOPTIMIZE -O2 -Ob1 -Ogity -G6 -Gi-
-#defer CFLAGS_OPT4 -MD -DOPTIMIZE -DNDEBUG -O2 -Ob1 -Ogity -G6 -Gi-
+#defer CFLAGS_OPT1 /MDd /GZ /Zi $[BROWSEINFO_FLAG] /Fd"$[osfilename $[target:%.obj=%.pdb]]" /D_DEBUG
+#defer CFLAGS_OPT2 /MDd /Zi /Fd"$[osfilename $[target:%.obj=%.pdb]]" /D_DEBUG /O2 /Ob1 /Ogity /G6
+#defer CFLAGS_OPT3 /MD /DOPTIMIZE /O2 /Ob1 /Ogity /G6 /Gi-
+#defer CFLAGS_OPT4 /MD /DOPTIMIZE /DNDEBUG /O2 /Ob1 /Ogity /G6 /Gi-
 
-#defer LFLAGS_OPT1 -debug -incremental:no
-#defer LFLAGS_OPT2 -debug -incremental:no
-#defer LFLAGS_OPT3 -fixed:no
-#defer LFLAGS_OPT4 -fixed:no
+#defer LFLAGS_OPT1 /debug /incremental:no
+#defer LFLAGS_OPT2 /debug /incremental:no
+#defer LFLAGS_OPT3 /fixed:no
+#defer LFLAGS_OPT4 /fixed:no
 
-#defer extra_cflags -nologo -W3 -EHsc -Zm250 -D_WINDOWS -DWIN32 -D_WINDLL -DSTRICT -DPENV_WIN32 -DWIN32_VC
-#defer extra_so_lflags -DLL -NOLOGO
-#defer extra_bin_lflags -NOLOGO
+#defer interrogate_ipath $[decygwin %,-I"%",$[target_ipath]]
+#defer interrogate_spath $[decygwin %,-S"%",$[install_parser_inc_dir]]
 
-#defer COMPILE_C cl -c -Fo$[target] $[decygwin %,-I"%",$[ipath]] $[flags] $[extra_cflags] $[source]
+#defer extra_cflags /nologo /W3 /EHsc /Zm250 /D_WINDOWS /DWIN32 /D_WINDLL /DSTRICT /DPENV_WIN32 /DWIN32_VC
+#defer extra_so_lflags /DLL /NOLOGO
+#defer extra_bin_lflags /NOLOGO
+
+#defer COMPILE_C cl /c /Fo"$[osfilename $[target]]" $[decygwin %,/I"%",$[ipath]] $[flags] $[extra_cflags] $[source]
 #defer COMPILE_C++ $[COMPILE_C]
 
-#defer SHARED_LIB_C link $[LFLAGS_OPT$[OPTIMIZE]] $[extra_so_lflags] $[sources] $[decygwin %,-LIBPATH:"%",$[lpath]] $[patsubst %.lib,%.lib,%,lib%.lib,$[libs]] -OUT:$[target]
+#defer SHARED_LIB_C link $[LFLAGS_OPT$[OPTIMIZE]] $[extra_so_lflags] $[sources] $[decygwin %,-LIBPATH:"%",$[lpath]] $[patsubst %.lib,%.lib,%,lib%.lib,$[libs]] /OUT:"$[osfilename $[target]]"
 #defer SHARED_LIB_C++ $[SHARED_LIB_C]
 
-#defer LINK_BIN_C link $[LFLAGS_OPT$[OPTIMIZE]] $[extra_bin_lflags] $[sources] $[decygwin %,-LIBPATH:"%",$[lpath]] $[patsubst %.lib,%.lib,%,lib%.lib,$[libs]] -OUT:$[target]
+#defer LINK_BIN_C link $[LFLAGS_OPT$[OPTIMIZE]] $[extra_bin_lflags] $[sources] $[decygwin %,-LIBPATH:"%",$[lpath]] $[patsubst %.lib,%.lib,%,lib%.lib,$[libs]] /OUT:"$[osfilename $[target]]"
 #defer LINK_BIN_C++ $[LINK_BIN_C]

+ 10 - 1
dtool/pptempl/Global.pp

@@ -221,6 +221,13 @@
   $[if $[and $[run_interrogate],$[IGATESCAN]], \
     lib$[TARGET].in]
 
+// This variable returns the name of the interrogate code file
+// that will be generated for a particular target, or empty string if
+// the target is not to be interrogated.
+#defer get_igateoutput \
+  $[if $[and $[run_interrogate],$[IGATESCAN]], \
+    lib$[TARGET]_igate.cxx]
+
 // This variable returns the name of the interrogate module, if the
 // current metalib target should include one, or empty string if it
 // should not.
@@ -493,9 +500,11 @@ Warning: Variable $[upcase $[tree]]_INSTALL is not set!
 
 
 // Set up the correct interrogate options.
+#defer interrogate_ipath $[target_ipath:%=-I%]
+#defer interrogate_spath $[install_parser_inc_dir:%=-S%]
 #defer interrogate_options \
     -DCPPPARSER -D__cplusplus $[SYSTEM_IGATE_FLAGS] \
-    -S$[install_parser_inc_dir] $[target_ipath:%=-I%] \
+    $[interrogate_spath] $[interrogate_ipath] \
     $[filter -D%,$[get_cflags] $[C++FLAGS]] \
     $[INTERROGATE_OPTIONS] \
     $[if $[INTERROGATE_PYTHON_INTERFACE],-python] \

+ 27 - 18
dtool/pptempl/Template.msvc.pp

@@ -42,7 +42,8 @@
   #else
     // This library is on a metalib, so we can't build it, but we
     // should build all the obj's that go into it.
-    #set deferred_objs $[deferred_objs] $[patsubst %.c %.cxx %.yxx %.lxx,$[so_dir]/%.obj,%,,$[SOURCES]]
+    #set deferred_objs $[deferred_objs] \
+      $[patsubst %.c %.cxx %.yxx %.lxx,$[so_dir]/%.obj,%,,$[get_sources] $[get_igateoutput]]
   #endif
 #end lib_target
 
@@ -145,7 +146,7 @@
 #defer lpath $[other_trees:%=%/lib] $[sort $[complete_lpath]] $[get_lpath]
 
 // And $[libs] is the set of libraries we will link with.
-#defer libs $[unique $[actual_local_libs] $[patsubst %:m,,%:c %,%,$[OTHER_LIBS]] $[get_libs]]
+#defer libs $[unique $[actual_local_libs] $[patsubst %:c,,%:m %,%,$[OTHER_LIBS]] $[get_libs]]
 
 // Okay, we're ready.  Start outputting the Makefile now.
 #output Makefile
@@ -210,8 +211,7 @@ cleanall : clean
        $[if $[install_config],$[install_config_dir]] \
        $[if $[install_igatedb],$[install_igatedb_dir]] \
      ] \
-     $[TARGET(metalib_target static_lib_target):%=install-lib%] \
-     $[real_lib_targets:%=install-lib%] \
+     $[TARGET(metalib_target lib_target static_lib_target):%=install-lib%] \
      $[TARGET(bin_target):%=install-%] \
      $[installed_files]
 install : all $[install_targets]
@@ -253,6 +253,11 @@ $[directory] :
 
 #forscopes metalib_target lib_target
 
+// In Windows, we don't actually build all the libraries.  In
+// particular, we don't build any libraries that are listed on a
+// metalib.  Is this one such library?
+#define build_it $[eq $[module $[TARGET],$[TARGET]],]
+
 // We might need to define a BUILDING_ symbol for win32.  We use the
 // BUILDING_DLL variable name, defined typically in the metalib, for
 // this; but in some cases, where the library isn't part of a metalib,
@@ -266,7 +271,7 @@ $[directory] :
 // generated .in file that interrogate will produce (and which should
 // be installed into the /etc directory).
 #define igatescan $[get_igatescan]
-#define igateoutput $[if $[igatescan],lib$[TARGET]_igate.cxx]
+#define igateoutput $[get_igateoutput]
 #define igatedb $[get_igatedb]
 
 // If this is a metalib, it may have a number of components that
@@ -283,26 +288,30 @@ $[directory] :
 #define igatemscan $[components $[get_igatedb:%=$[RELDIR]/$[so_dir]/%],$[active_component_libs]]
 #define igatemout $[if $[igatemscan],lib$[TARGET]_module.cxx]
 
-// Now output the rule to actually link the library from all of its
-// various .obj files.
-#define sources \
- $[unique $[patsubst %.cxx %.c %.yxx %.lxx,$[so_dir]/%.obj,%,,$[get_sources] $[igateoutput] $[igatemout]]] \
- $[components $[unique $[patsubst %.cxx %.c %.yxx %.lxx,$[RELDIR]/$[so_dir]/%.obj,%,,$[get_sources] $[igateoutput] $[igatemout]]],$[COMPONENT_LIBS]]
+#if $[build_it]
+  // Now output the rule to actually link the library from all of its
+  // various .obj files.
+  #define sources \
+   $[unique $[patsubst %.cxx %.c %.yxx %.lxx,$[so_dir]/%.obj,%,,$[get_sources] $[igateoutput] $[igatemout]]] \
+   $[components $[unique $[patsubst %.cxx %.c %.yxx %.lxx,$[RELDIR]/$[so_dir]/%.obj,%,,$[get_sources] $[get_igateoutput]]],$[active_component_libs]]
 lib_$[TARGET]_so = $[sources]
-#define target $[so_dir]/lib$[TARGET].dll
-#define sources $(lib_$[TARGET]_so)
+  #define target $[so_dir]/lib$[TARGET].dll
+  #define sources $(lib_$[TARGET]_so)
 $[target] : $[sources]
-#if $[filter %.cxx %.yxx %.lxx,$[get_sources]]
+  #if $[filter %.cxx %.yxx %.lxx,$[get_sources]]
 	$[SHARED_LIB_C++]
-#else
+  #else
 	$[SHARED_LIB_C]
+  #endif
 #endif
 
 // Here are the rules to install and uninstall the library and
 // everything that goes along with it.
 #define installed_files \
-    $[install_lib_dir]/lib$[TARGET].dll \
-    $[install_lib_dir]/lib$[TARGET].lib \
+    $[if $[build_it], \
+      $[install_lib_dir]/lib$[TARGET].dll \
+      $[install_lib_dir]/lib$[TARGET].lib \
+    ] \
     $[INSTALL_SCRIPTS:%=$[install_bin_dir]/%] \
     $[INSTALL_HEADERS:%=$[install_headers_dir]/%] \
     $[INSTALL_DATA:%=$[install_data_dir]/%] \
@@ -351,7 +360,7 @@ $[so_dir]/$[igatedb] $[so_dir]/$[igateoutput] : $[filter-out .c .cxx,$[igatescan
 #define target $[igateoutput:%.cxx=$[so_dir]/%.obj]
 #define source $[so_dir]/$[igateoutput]
 #define ipath . $[target_ipath]
-#define flags $[get_cflags] $[C++FLAGS] $[CFLAGS_OPT$[OPTIMIZE]] $[CFLAGS_SHARED] $[all_sources $[building_var:%=-D%],$[file]]
+#define flags $[get_cflags] $[C++FLAGS] $[CFLAGS_OPT$[OPTIMIZE]] $[CFLAGS_SHARED] $[building_var:%=-D%]
 $[target] : $[source]
 	$[COMPILE_C++]
 #endif  // $[igatescan]
@@ -373,7 +382,7 @@ $[target] : $[sources]
 #define target $[igatemout:%.cxx=$[so_dir]/%.obj]
 #define source $[so_dir]/$[igatemout]
 #define ipath . $[target_ipath]
-#define flags $[get_cflags] $[C++FLAGS] $[CFLAGS_OPT$[OPTIMIZE]] $[CFLAGS_SHARED] $[all_sources $[building_var:%=-D%],$[file]]
+#define flags $[get_cflags] $[C++FLAGS] $[CFLAGS_OPT$[OPTIMIZE]] $[CFLAGS_SHARED] $[building_var:%=-D%]
 $[target] : $[source]
 	$[COMPILE_C++]
 #endif  // $[igatescan]

+ 1 - 1
dtool/pptempl/Template.unix.pp

@@ -243,7 +243,7 @@ $[directory] :
 // generated .in file that interrogate will produce (and which should
 // be installed into the /etc directory).
 #define igatescan $[get_igatescan]
-#define igateoutput $[if $[igatescan],lib$[TARGET]_igate.cxx]
+#define igateoutput $[get_igateoutput]
 #define igatedb $[get_igatedb]
 
 // If this is a metalib, it may have a number of components that

+ 2 - 2
ppremake/Makefile.am

@@ -1,8 +1,8 @@
 bin_PROGRAMS = ppremake
 
 ppremake_SOURCES =						\
-    check_include.cxx check_include.h find_searchpath.cxx	\
-    find_searchpath.h						\
+    check_include.cxx check_include.h filename.cxx filename.h	\
+    find_searchpath.cxx find_searchpath.h			\
     gnu_getopt.c gnu_getopt.h					\
     ppCommandFile.cxx ppCommandFile.h ppDependableFile.cxx	\
     ppDependableFile.h ppDirectory.cxx				\

+ 78 - 0
ppremake/filename.cxx

@@ -0,0 +1,78 @@
+// Filename: filename.cxx
+// Created by:  drose (19Oct00)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "filename.h"
+#include <ctype.h>
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPScope::is_fullpath
+//  Description: Returns true if the given pathname appears to be a
+//               fully-specified pathname.  This means it begins with
+//               a slash for unix_platform, and it begins with a slash
+//               or backslash, with an optional drive leterr, for
+//               windows_platform.
+////////////////////////////////////////////////////////////////////
+bool
+is_fullpath(const string &pathname) {
+  if (pathname.empty()) {
+    return false;
+  }
+
+  if (pathname[0] == '/') {
+    return true;
+  }
+
+  if (windows_platform) {
+    if (pathname.length() > 2 && 
+	isalpha(pathname[0]) && pathname[1] == ':') {
+      // A drive-letter prefix.
+      return (pathname[2] == '/' || pathname[2] == '\\');
+    }
+    // No drive-letter prefix.
+    return (pathname[0] == '\\');
+  }
+
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPScope::to_os_filename
+//  Description: Changes forward slashes to backslashes, but only if
+//               windows_platform is set.  Otherwise returns the
+//               string unchanged.
+////////////////////////////////////////////////////////////////////
+string
+to_os_filename(string pathname) {
+  if (windows_platform) {
+    string::iterator si;
+    for (si = pathname.begin(); si != pathname.end(); ++si) {
+      if ((*si) == '/') {
+	(*si) = '\\';
+      }
+    }
+  }
+
+  return pathname;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPScope::to_unix_filename
+//  Description: Changes backslashes to forward slashes, but only if
+//               windows_platform is set.  Otherwise returns the
+//               string unchanged.
+////////////////////////////////////////////////////////////////////
+string
+to_unix_filename(string pathname) {
+  if (windows_platform) {
+    string::iterator si;
+    for (si = pathname.begin(); si != pathname.end(); ++si) {
+      if ((*si) == '\\') {
+	(*si) = '/';
+      }
+    }
+  }
+
+  return pathname;
+}

+ 19 - 0
ppremake/filename.h

@@ -0,0 +1,19 @@
+// Filename: filename.h
+// Created by:  drose (19Oct00)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef FILENAME_H
+#define FILENAME_H
+
+#include "ppremake.h"
+
+// This header file defines a few functions handy for dealing with
+// filenames in a cross-platform world.
+
+bool is_fullpath(const string &pathname);
+string to_os_filename(string pathname);
+string to_unix_filename(string pathname);
+
+#endif
+

+ 8 - 0
ppremake/ppCommandFile.cxx

@@ -289,6 +289,14 @@ read_line(string line) {
   // If the comment was at the beginning of the line, ignore the whole
   // line, including its whitespace.
   if (comment != 0) {
+    // We also strip off whitespace at the end of the line, since this
+    // is generally invisible and almost always just leads to trouble.
+    size_t eol = line.length();
+    while (eol > 0 && (isspace(line[eol - 1]) || line[eol - 1] == '\r')) {
+      eol--;
+    }
+    line = line.substr(0, eol);
+
     if (_in_for) {
       // Save up the lines for later execution if we're within a #forscopes.
       _saved_lines.push_back(line);

+ 42 - 46
ppremake/ppDirectory.cxx

@@ -346,30 +346,12 @@ report_depends() const {
     // Get the complete set of directories we depend on.
     Depends dep;
     get_complete_i_depend_on(dep);
-
-    // Copy the set into a vector, so we can sort it into a nice order
-    // for the user's pleasure.
-    vector<PPDirectory *> dirs;
-    copy(dep.begin(), dep.end(),
-	 back_insert_iterator<vector<PPDirectory *> >(dirs));
-    
-    sort(dirs.begin(), dirs.end(), SortDirectoriesByDependencyAndName());
     
-    cerr << _dirname << " depends on the following directories:";
-    static const int max_col = 72;
-    int col = max_col;
-    vector<PPDirectory *>::const_iterator di;
-    for (di = dirs.begin(); di != dirs.end(); ++di) {
-      const string &dirname = (*di)->_dirname;
-      col += dirname.length() + 1;
-      if (col >= max_col) {
-	col = dirname.length() + 2;
-	cerr << "\n  " << dirname;
-      } else {
-	cerr << " " << dirname;
-      }
-    }
-    cerr << "\n";
+    cerr << _dirname << " depends directly on the following directories:";
+    show_directories(_i_depend_on);
+
+    cerr << "and directly or indirectly on the following directories:";
+    show_directories(dep);
   }
 }
 
@@ -389,29 +371,11 @@ report_needs() const {
     Depends dep;
     get_complete_depends_on_me(dep);
 
-    // Copy the set into a vector, so we can sort it into a nice order
-    // for the user's pleasure.
-    vector<PPDirectory *> dirs;
-    copy(dep.begin(), dep.end(),
-	 back_insert_iterator<vector<PPDirectory *> >(dirs));
-    
-    sort(dirs.begin(), dirs.end(), SortDirectoriesByDependencyAndName());
-    
-    cerr << _dirname << " is needed by the following directories:";
-    static const int max_col = 72;
-    int col = max_col;
-    vector<PPDirectory *>::const_iterator di;
-    for (di = dirs.begin(); di != dirs.end(); ++di) {
-      const string &dirname = (*di)->_dirname;
-      col += dirname.length() + 1;
-      if (col >= max_col) {
-	col = dirname.length() + 2;
-	cerr << "\n  " << dirname;
-      } else {
-	cerr << " " << dirname;
-      }
-    }
-    cerr << "\n";
+    cerr << _dirname << " is needed directly by the following directories:";
+    show_directories(_depends_on_me);
+
+    cerr << "and directly or indirectly by the following directories:";
+    show_directories(dep);
   }
 }
 
@@ -777,3 +741,35 @@ get_complete_depends_on_me(Depends &dep) const {
     }
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPDirectory::show_directories
+//       Access: Private
+//  Description: Writes a set of dependency directory names to
+//               standard error.  The output begins with a newline.
+////////////////////////////////////////////////////////////////////
+void PPDirectory::
+show_directories(const PPDirectory::Depends &dep) const {
+  // Copy the set into a vector, so we can sort it into a nice order
+  // for the user's pleasure.
+  vector<PPDirectory *> dirs;
+  copy(dep.begin(), dep.end(),
+       back_insert_iterator<vector<PPDirectory *> >(dirs));
+  
+  sort(dirs.begin(), dirs.end(), SortDirectoriesByDependencyAndName());
+  
+  static const int max_col = 72;
+  int col = max_col;
+  vector<PPDirectory *>::const_iterator di;
+  for (di = dirs.begin(); di != dirs.end(); ++di) {
+    const string &dirname = (*di)->_dirname;
+    col += dirname.length() + 1;
+    if (col >= max_col) {
+      col = dirname.length() + 2;
+      cerr << "\n  " << dirname;
+    } else {
+      cerr << " " << dirname;
+    }
+  }
+  cerr << "\n";
+}

+ 1 - 0
ppremake/ppDirectory.h

@@ -67,6 +67,7 @@ private:
 
   void get_complete_i_depend_on(Depends &dep) const;
   void get_complete_depends_on_me(Depends &dep) const;
+  void show_directories(const Depends &dep) const;
 
   string _dirname;
   PPScope *_scope;

+ 10 - 0
ppremake/ppMain.cxx

@@ -7,6 +7,7 @@
 #include "ppScope.h"
 #include "ppCommandFile.h"
 #include "ppDirectory.h"
+#include "tokenize.h"
 
 #include <unistd.h>
 #include <assert.h>
@@ -92,6 +93,15 @@ read_source(const string &root) {
     return false;
   }
 
+  // Now check the *_PLATFORM variables that System.pp was supposed to
+  // set.
+  if (!trim_blanks(_def_scope->expand_string("$[UNIX_PLATFORM]")).empty()) {
+    unix_platform = true;
+  }
+  if (!trim_blanks(_def_scope->expand_string("$[WINDOWS_PLATFORM]")).empty()) {
+    windows_platform = true;
+  }
+
   PPScope::push_scope(_def_scope);
 
   if (!_tree.scan_source(&_named_scopes)) {

+ 16 - 4
ppremake/ppNamedScopes.cxx

@@ -153,9 +153,21 @@ void PPNamedScopes::
 p_get_scopes(const PPNamedScopes::Named &named, const string &name,
 	     Scopes &scopes) const {
   Named::const_iterator ni;
-  ni = named.find(name);
-  if (ni != named.end()) {
-    const Scopes &s = (*ni).second;
-    scopes.insert(scopes.end(), s.begin(), s.end());
+  if (name == "*") {
+    // Scope name "*" means all nested scopes in this directory,
+    // except for the empty-name scope (which is the outer scope).
+    for (ni = named.begin(); ni != named.end(); ++ni) {
+      if (!(*ni).first.empty()) {
+	const Scopes &s = (*ni).second;
+	scopes.insert(scopes.end(), s.begin(), s.end());
+      }
+    }
+
+  } else {
+    ni = named.find(name);
+    if (ni != named.end()) {
+      const Scopes &s = (*ni).second;
+      scopes.insert(scopes.end(), s.begin(), s.end());
+    }
   }
 }

+ 150 - 4
ppremake/ppScope.cxx

@@ -12,6 +12,7 @@
 #include "ppDependableFile.h"
 #include "tokenize.h"
 #include "find_searchpath.h"
+#include "filename.h"
 
 #include <stdlib.h>
 #include <algorithm>
@@ -32,6 +33,11 @@ PPScope::MapVariableDefinition PPScope::_null_map_def;
 
 PPScope::ScopeStack PPScope::_scope_stack;
 
+#ifdef __CYGWIN__
+extern "C" void cygwin_conv_to_win32_path(const char *path, char *win32);
+extern "C" void cygwin_conv_to_posix_path(const char *path, char *posix);
+#endif
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PPScope::Constructor
 //       Access: Public
@@ -803,7 +809,17 @@ r_expand_variable(const string &str, size_t &vp,
     }      
 
     // Is it a built-in function?
-    if (funcname == "wildcard") {
+    if (funcname == "isfullpath") {
+      return expand_isfullpath(params);
+    } else if (funcname == "osfilename") {
+      return expand_osfilename(params);
+    } else if (funcname == "unixfilename") {
+      return expand_unixfilename(params);
+    } else if (funcname == "cygpath_w") {
+      return expand_cygpath_w(params);
+    } else if (funcname == "cygpath_p") {
+      return expand_cygpath_p(params);
+    } else if (funcname == "wildcard") {
       return expand_wildcard(params);
     } else if (funcname == "isdir") {
       return expand_isdir(params);
@@ -1020,6 +1036,133 @@ expand_variable_nested(const string &varname,
   return result;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPScope::expand_isfullpath
+//       Access: Private
+//  Description: Expands the "isfullpath" function variable.  This
+//               returns true (actually, the same as its input) if the
+//               input parameter is a fully-specified path name,
+//               meaning it begins with a slash for unix_platform, and
+//               it begins with a slash or backslash, with an optional
+//               drive leterr, for windows_platform.
+////////////////////////////////////////////////////////////////////
+string PPScope::
+expand_isfullpath(const string &params) const {
+  string filename = trim_blanks(expand_string(params));
+
+  string result;
+  if (is_fullpath(filename)) {
+    result = filename;
+  }
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPScope::expand_osfilename
+//       Access: Private
+//  Description: Expands the "osfilename" function variable.  This
+//               converts the filename from a Unix-style filename
+//               (e.g. with slash separators) to a platform-specific
+//               filename.  Currently, this only has an effect when
+//               generating code for a Windows platform: it simply
+//               converts forward slashes to backslashes.  On other
+//               platforms it has no effect.
+//
+//               This is different from cygpath_w in that (a) it works
+//               regardless of whether we are actually running under
+//               Cygwin, and (b) it does nothing more intelligent than
+//               reverse slashes.
+////////////////////////////////////////////////////////////////////
+string PPScope::
+expand_osfilename(const string &params) const {
+  // Split the parameter into tokens based on the spaces.
+  vector<string> words;
+  tokenize_whitespace(expand_string(params), words);
+
+  vector<string>::iterator wi;
+  for (wi = words.begin(); wi != words.end(); ++wi) {
+    (*wi) = to_os_filename(*wi);
+  }
+
+  string result = repaste(words, " ");
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPScope::expand_unixfilename
+//       Access: Private
+//  Description: Expands the "unixfilename" function variable.  This
+//               converts the filename from a platform-specific
+//               filename to a Unix-style filename (e.g. with slash
+//               separators).  Currently, this only has an effect when
+//               generating code for a Windows platform: it simply
+//               converts backslashes to forward slashes.  On other
+//               platforms it has no effect.
+//
+//               This is different from cygpath_p in that (a) it works
+//               regardless of whether we are actually running under
+//               Cygwin, and (b) it does nothing more intelligent than
+//               reverse slashes.
+////////////////////////////////////////////////////////////////////
+string PPScope::
+expand_unixfilename(const string &params) const {
+  // Split the parameter into tokens based on the spaces.
+  vector<string> words;
+  tokenize_whitespace(expand_string(params), words);
+
+  vector<string>::iterator wi;
+  for (wi = words.begin(); wi != words.end(); ++wi) {
+    (*wi) = to_unix_filename(*wi);
+  }
+
+  string result = repaste(words, " ");
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPScope::expand_cygpath_w
+//       Access: Private
+//  Description: Expands the "cygpath_w" function variable.  This is
+//               equivalent to $[shell cygpath -w ...] when running
+//               under Cygwin, and returns the parameter itself when
+//               not running under Cygwin.
+////////////////////////////////////////////////////////////////////
+string PPScope::
+expand_cygpath_w(const string &params) const {
+  string filename = trim_blanks(expand_string(params));
+
+#ifdef __CYGWIN__
+  char result[4096];
+
+  cygwin_conv_to_win32_path(filename.c_str(), result);
+  filename = result;
+#endif
+
+  return filename;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPScope::expand_cygpath_p
+//       Access: Private
+//  Description: Expands the "cygpath_p" function variable.  This is
+//               equivalent to $[shell cygpath -p ...] when running
+//               under Cygwin, and returns the parameter itself when
+//               not running under Cygwin.
+////////////////////////////////////////////////////////////////////
+string PPScope::
+expand_cygpath_p(const string &params) const {
+  string filename = trim_blanks(expand_string(params));
+
+#ifdef __CYGWIN__
+  char result[4096];
+
+  cygwin_conv_to_posix_path(filename.c_str(), result);
+  filename = result;
+#endif
+
+  return filename;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PPScope::expand_wildcard
 //       Access: Private
@@ -1291,6 +1434,7 @@ expand_shell(const string &params) const {
     
   if (pid == 0) {
     // Child.
+    close(pd[0]);
     dup2(pd[1], STDOUT_FILENO);
     char *argv[4];
     argv[0] = "sh";
@@ -1355,7 +1499,7 @@ expand_shell(const string &params) const {
 ////////////////////////////////////////////////////////////////////
 string PPScope::
 expand_standardize(const string &params) const {
-  string filename = expand_string(params);
+  string filename = trim_blanks(expand_string(params));
   if (filename.empty()) {
     return string();
   }
@@ -1411,8 +1555,10 @@ expand_standardize(const string &params) const {
 ////////////////////////////////////////////////////////////////////
 string PPScope::
 expand_length(const string &params) const {
+  string word = trim_blanks(expand_string(params));
+
   char buffer[32];
-  sprintf(buffer, "%d", params.length());
+  sprintf(buffer, "%d", word.length());
   string result = buffer;
   return result;
 }  
@@ -1432,7 +1578,7 @@ expand_substr(const string &params) const {
   tokenize_params(params, tokens, true);
 
   if (tokens.size() != 3) {
-    cerr << "wordlist requires three parameters.\n";
+    cerr << "substr requires three parameters.\n";
     return string();
   }
 

+ 5 - 0
ppremake/ppScope.h

@@ -80,6 +80,11 @@ private:
   string expand_variable_nested(const string &varname, 
 				const string &scope_names) const;
 
+  string expand_isfullpath(const string &params) const;
+  string expand_osfilename(const string &params) const;
+  string expand_unixfilename(const string &params) const;
+  string expand_cygpath_w(const string &params) const;
+  string expand_cygpath_p(const string &params) const;
   string expand_wildcard(const string &params) const;
   string expand_isdir(const string &params) const;
   string expand_isfile(const string &params) const;

+ 5 - 1
ppremake/ppremake.cxx

@@ -21,6 +21,9 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+bool unix_platform = false;
+bool windows_platform = false;
+
 static void
 usage() {
   cerr <<
@@ -268,13 +271,14 @@ main(int argc, char *argv[]) {
     }
 
     for (int i = 1; i < argc; i++) {
+      cerr << "\n";
       if (report_depends) {
 	ppmain.report_depends(argv[i]);
       }
+      cerr << "\n";
       if (report_needs) {
 	ppmain.report_needs(argv[i]);
       }
-      cerr << "\n";
     }
 
   } else {

+ 7 - 0
ppremake/ppremake.h

@@ -49,4 +49,11 @@ using namespace std;
 #define SCOPE_DIRNAME_WILDCARD "*"
 #define SCOPE_DIRNAME_CURRENT "."
 
+/* These are set from the similarly-named variables defined in
+   System.pp. */
+#ifdef __cplusplus
+extern bool unix_platform;
+extern bool windows_platform;
+#endif
+
 #endif