Browse Source

perform shell-style filename globbing on Win32 too

David Rose 14 years ago
parent
commit
c0b7ca96b8

+ 20 - 7
dtool/src/dtoolutil/Sources.pp

@@ -12,50 +12,63 @@
   #define SOURCES \
     checkPandaVersion.h \
     config_dtoolutil.h \
+    dSearchPath.I dSearchPath.h \
     executionEnvironment.I executionEnvironment.h filename.I  \
     filename.h \
     $[if $[IS_OSX],filename_assist.mm filename_assist.h,] \
-    load_dso.h dSearchPath.I dSearchPath.h \
+    globPattern.I globPattern.h \
+    load_dso.h \
     pandaFileStream.h pandaFileStream.I \
     pandaFileStreamBuf.h \
     pandaSystem.h pandaVersion.h \
     panda_getopt.h panda_getopt_long.h panda_getopt_impl.h \
     pfstream.h pfstream.I pfstreamBuf.h \
+    preprocess_argv.h \
     stringDecoder.h stringDecoder.I \
     textEncoder.h textEncoder.I \
     unicodeLatinMap.h \
     vector_string.h \
-    vector_src.h 
+    vector_src.h \
+    win32ArgParser.h
 
   #define INCLUDED_SOURCES \
     checkPandaVersion.cxx \
     config_dtoolutil.cxx \
-    executionEnvironment.cxx filename.cxx load_dso.cxx  \
     dSearchPath.cxx \
+    executionEnvironment.cxx filename.cxx \
+    globPattern.cxx \
+    load_dso.cxx  \
     pandaFileStream.cxx pandaFileStreamBuf.cxx \
     pandaSystem.cxx \
     panda_getopt_impl.cxx \
     pfstreamBuf.cxx pfstream.cxx \
+    preprocess_argv.cxx \
     stringDecoder.cxx \
     textEncoder.cxx \
     unicodeLatinMap.cxx \
-    vector_string.cxx
+    vector_string.cxx \
+    win32ArgParser.cxx
 
   #define INSTALL_HEADERS \
     checkPandaVersion.h \
     config_dtoolutil.h \
-    executionEnvironment.I executionEnvironment.h filename.I    \
-    filename.h load_dso.h dSearchPath.I dSearchPath.h   \
+    dSearchPath.I dSearchPath.h \
+    executionEnvironment.I executionEnvironment.h filename.I \
+    filename.h \
+    globPattern.I globPattern.h \
+    load_dso.h \
     pandaFileStream.h pandaFileStream.I \
     pandaFileStreamBuf.h \
     pandaSystem.h pandaVersion.h \
     panda_getopt.h panda_getopt_long.h panda_getopt_impl.h \
     pfstream.h pfstream.I pfstreamBuf.h \
+    preprocess_argv.h \
     stringDecoder.h stringDecoder.I \
     textEncoder.h textEncoder.I \
     unicodeLatinMap.h \
     vector_string.h \
-    vector_src.cxx vector_src.h
+    vector_src.cxx vector_src.h \
+    win32ArgParser.h
 #end lib_target
 
 #begin test_bin_target

+ 4 - 2
dtool/src/dtoolutil/dtoolutil_composite1.cxx

@@ -1,8 +1,10 @@
+#include "checkPandaVersion.cxx"
 #include "config_dtoolutil.cxx"
+#include "dSearchPath.cxx"
+#include "executionEnvironment.cxx"
 #include "filename.cxx"
+#include "globPattern.cxx"
 #include "load_dso.cxx"
-#include "dSearchPath.cxx"
 #include "pandaSystem.cxx"
-#include "checkPandaVersion.cxx"
 
 

+ 2 - 2
dtool/src/dtoolutil/dtoolutil_composite2.cxx

@@ -1,11 +1,11 @@
 #include "pandaFileStream.cxx"
 #include "pandaFileStreamBuf.cxx"
 #include "panda_getopt_impl.cxx"
-#include "executionEnvironment.cxx"
 #include "pfstream.cxx"
 #include "pfstreamBuf.cxx"
+#include "preprocess_argv.cxx"
 #include "stringDecoder.cxx"
 #include "textEncoder.cxx"
 #include "unicodeLatinMap.cxx"
 #include "vector_string.cxx"
-
+#include "win32ArgParser.cxx"

+ 0 - 0
dtool/src/prc/globPattern.I → dtool/src/dtoolutil/globPattern.I


+ 0 - 0
dtool/src/prc/globPattern.cxx → dtool/src/dtoolutil/globPattern.cxx


+ 1 - 1
dtool/src/prc/globPattern.h → dtool/src/dtoolutil/globPattern.h

@@ -34,7 +34,7 @@
 //               example, to scan a directory for all files matching a
 //               particular pattern.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_DTOOLCONFIG GlobPattern {
+class EXPCL_DTOOL GlobPattern {
 PUBLISHED:
   INLINE GlobPattern(const string &pattern = string());
   INLINE GlobPattern(const GlobPattern &copy);

+ 50 - 0
dtool/src/dtoolutil/preprocess_argv.cxx

@@ -0,0 +1,50 @@
+// Filename: preprocess_argv.cxx
+// Created by:  drose (08Nov11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "preprocess_argv.h"
+#include "win32ArgParser.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: preprocess_argv
+//  Description: Processes the argc, argv pair as needed before
+//               passing it to getopt().  If this program is running
+//               on Windows, but not within Cygwin, this ignores the
+//               incoming argv, argv values, replacing them from the
+//               GetCommandLine() string, and expanding glob patterns
+//               like *.egg to a list of all matching egg files.  On
+//               other platforms, this function does nothing and
+//               returns argc, argv unchanged.
+//
+//               The argc and argv values are modified by this
+//               function, if necessary, to point to
+//               statically-allocated memory that will be valid until
+//               the next call to preprocess_argv().
+////////////////////////////////////////////////////////////////////
+void
+preprocess_argv(int &argc, char **&argv) {
+#ifndef _WIN32
+  // Not Windows: do nothing.
+#else  // _WIN32
+  static Win32ArgParser parser;
+  if (parser.is_cygwin_shell()) {
+    // Running within Cygwin: do nothing.
+    return;
+  }
+
+  // On Windows, and not within Cygwin.  Process the args.
+  parser.set_system_command_line();
+  argc = parser.get_argc();
+  argv = parser.get_argv();
+#endif  // _WIN32
+}

+ 24 - 0
dtool/src/dtoolutil/preprocess_argv.h

@@ -0,0 +1,24 @@
+// Filename: preprocess_argv.h
+// Created by:  drose (08Nov11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PREPROCESS_ARGV_H
+#define PREPROCESS_ARGV_H
+
+#include "dtoolbase.h"
+
+extern EXPCL_DTOOL void
+preprocess_argv(int &argc, char **&argv);
+
+#endif
+

+ 361 - 0
dtool/src/dtoolutil/win32ArgParser.cxx

@@ -0,0 +1,361 @@
+// Filename: win32ArgParser.cxx
+// Created by:  drose (08Nov11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "win32ArgParser.h"
+
+#ifdef _WIN32
+
+#include "memoryBase.h"
+#include "textEncoder.h"
+#include "globPattern.h"
+#include "filename.h"
+#include "executionEnvironment.h"
+
+#include <windows.h>
+#include <Tlhelp32.h>
+
+////////////////////////////////////////////////////////////////////
+//     Function: Win32ArgParser::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+Win32ArgParser::
+Win32ArgParser() :
+  _argv(NULL),
+  _argc(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Win32ArgParser::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+Win32ArgParser::
+~Win32ArgParser() {
+  clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Win32ArgParser::clear
+//       Access: Public
+//  Description: Resets the parser to empty command line and
+//               deallocates the internal argv array.
+////////////////////////////////////////////////////////////////////
+void Win32ArgParser::
+clear() {
+  assert(_argc == (int)_args.size());
+
+  if (_argv != NULL) {
+    for (int i = 0; i < _argc; ++i) {
+      PANDA_FREE_ARRAY(_argv[i]);
+    }
+    PANDA_FREE_ARRAY(_argv);
+    _argv = NULL;
+  }
+
+  _argc = 0;
+  _args.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Win32ArgParser::set_command_line
+//       Access: Public
+//  Description: Sets the string that indicates the full Win32 command
+//               line, and starts parsing this into argc, argv.
+////////////////////////////////////////////////////////////////////
+void Win32ArgParser::
+set_command_line(const string &command_line) {
+  clear();
+  
+  const char *p = command_line.c_str();
+  while (*p != '\0') {
+    if (*p == '"') {
+      parse_quoted_arg(p);
+    } else {
+      parse_unquoted_arg(p);
+    }
+
+    // Skip whitespace.
+    while (*p != '\0' && isspace(*p)) {
+      ++p;
+    }
+  }
+
+  assert(_argc == 0 && _argv == NULL);
+  _argc = (int)_args.size();
+  _argv = (char **)PANDA_MALLOC_ARRAY(_argc * sizeof(char *));
+  for (int i = 0; i < _argc; ++i) {
+    const string &arg = _args[i];
+    char *astr = (char *)PANDA_MALLOC_ARRAY(arg.size() + 1);
+    memcpy(astr, arg.data(), arg.size());
+    astr[arg.size()] = '\0';
+    _argv[i] = astr;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Win32ArgParser::set_command_line
+//       Access: Public
+//  Description: Sets the Unicode string that indicates the full Win32
+//               command line, and starts parsing this into argc,
+//               argv.
+////////////////////////////////////////////////////////////////////
+void Win32ArgParser::
+set_command_line(const wstring &command_line) {
+  TextEncoder encoder;
+  encoder.set_encoding(Filename::get_filesystem_encoding());
+  encoder.set_wtext(command_line);
+  set_command_line(encoder.get_text());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Win32ArgParser::set_system_command_line
+//       Access: Public
+//  Description: Tells the parser to call GetCommandLine() to query
+//               the system command line string, and parse it into
+//               argc, argv.
+////////////////////////////////////////////////////////////////////
+void Win32ArgParser::
+set_system_command_line() {
+  LPWSTR command_line = GetCommandLineW();
+  set_command_line(command_line);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Win32ArgParser::get_argv
+//       Access: Public
+//  Description: Returns the argv array as computed by
+//               set_command_line() or set_system_command_line().
+//               This array indexes directly into data allocated
+//               within the Win32ArgParser object; it will remain
+//               valid until set_command_line() or clear() is again
+//               called, or until the parser object destructs.
+////////////////////////////////////////////////////////////////////
+char **Win32ArgParser::
+get_argv() {
+  return _argv;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Win32ArgParser::get_argc
+//       Access: Public
+//  Description: Returns the number of elements in the argv array.
+////////////////////////////////////////////////////////////////////
+int Win32ArgParser::
+get_argc() {
+  return _argc;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Win32ArgParser::is_cygwin_shell
+//       Access: Public, Static
+//  Description: Tries to determine if this program was launched from
+//               a Cygwin shell.  Returns true if so, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool Win32ArgParser::
+is_cygwin_shell() {
+  // First, we check for the PANDA_CYGWIN environment variable.  If
+  // this is present, it overrides any other checks: "0" means not
+  // Cygwin, "1" means Cygwin.
+  string envvar = ExecutionEnvironment::get_environment_variable("PANDA_CYGWIN");
+  if (!envvar.empty()) {
+    istringstream strm(envvar);
+    int value;
+    strm >> value;
+    if (!strm.fail()) {
+      return (value != 0);
+    }
+  }
+
+  // Nothing explicit, so we have to determine Cygwin status
+  // implicitly.
+
+  // Our strategy is to check the parent process name for one of the
+  // known Cygwin shells.  Unfortunately, it is surprisingly difficult
+  // to determine the parent process in Windows.  We have to enumerate
+  // all of the processes to find it.
+
+  HANDLE toolhelp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+
+  PROCESSENTRY32 entry;
+  memset(&entry, 0, sizeof(entry));
+  entry.dwSize = sizeof(entry);
+
+  DWORD current_id = GetCurrentProcessId();
+  DWORD parent_id = -1;
+
+  if (Process32First(toolhelp, &entry)) {
+    do {
+      if (entry.th32ProcessID == current_id) {
+        parent_id = entry.th32ParentProcessID;
+        break;
+      }
+    } while (Process32Next(toolhelp, &entry));
+  }
+
+  Filename parent_exe;
+  if (parent_id != -1) {
+    // Now we've got the parent process ID, go back through the list
+    // to get its process name.
+    if (Process32First(toolhelp, &entry)) {
+      do {
+        if (entry.th32ProcessID == parent_id) {
+          parent_exe = Filename::from_os_specific(entry.szExeFile);
+          break;
+        }
+      } while (Process32Next(toolhelp, &entry));
+    }
+  }
+
+  CloseHandle(toolhelp);
+  string basename = parent_exe.get_basename();
+  if (basename == "sh.exe" || basename == "bash.exe" ||
+      basename == "csh.exe" || basename == "tcsh.exe" || 
+      basename == "zsh.exe" || basename == "ash.exe") {
+    // These are the standard Unix shell names.  Assume one of these
+    // as the parent process name means we were launched from a Cygwin
+    // shell.  Even if it's from something other than the Cygwin
+    // implementation, these filenames suggests a smart shell that
+    // will have already pre-processed the command line.
+    return true;
+  }
+
+  // Something else means a standard Windows shell that doesn't
+  // process the command line.
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Win32ArgParser::parse_quoted_arg
+//       Access: Private
+//  Description: Parses the quoted argument beginning at p and saves
+//               it in _char_args.  Advances p to the first character
+//               following the close quote.
+////////////////////////////////////////////////////////////////////
+void Win32ArgParser::
+parse_quoted_arg(const char *&p) {
+  char quote = *p;
+  ++p;
+  string result;
+
+  while (*p != '\0' && *p != quote) {
+    // TODO: handle caret?  What does it mean?
+
+    if (*p == '\\') {
+      // A backslash is an escape character only when it precedes a
+      // quote mark, or a series of backslashes precede a quote mark.
+      int num_slashes = 1;
+      ++p;
+      while (*p == '\\') {
+        ++p;
+        ++num_slashes;
+      }
+      if (*p == quote) {
+        // A series of backslashes precede a quote mark.  This means
+        // something special.  First, each pair of backslashes means a
+        // single backslash.
+        for (int i = 0; i < num_slashes; i += 2) {
+          result += '\\';
+        }
+        // And if there's no odd backslashes left over, we've reached
+        // the closing quote and we're done.
+        if ((num_slashes & 1) == 0) {
+          ++p;
+          save_arg(result);
+          return;
+        }
+        
+        // But if there's an odd backslash, it simply escapes the
+        // quote mark.
+        result += quote;
+        ++p;
+
+      } else {
+        // A series of backslashes not followed by a quote mark is
+        // interpreted literally, not even counting them by twos, per
+        // Win32's weird rules.
+        for (int i = 0; i < num_slashes; ++i) {
+          result += '\\';
+        }
+      }
+
+    } else {
+      // Neither a backslash nor a quote mark, so just interpret it
+      // literally.
+      result += *p;
+      ++p;
+    }
+  }
+
+  if (*p == quote) {
+    ++p;
+  }
+
+  save_arg(result);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Win32ArgParser::parse_unquoted_arg
+//       Access: Private
+//  Description: Parses the unquoted argument beginning at p and saves
+//               it in _char_args.  Advances p to the first whitespace
+//               following the argument.
+////////////////////////////////////////////////////////////////////
+void Win32ArgParser::
+parse_unquoted_arg(const char *&p) {
+  string result;
+  while (*p != '\0' && !isspace(*p)) {
+    result += *p;
+    ++p;
+  }
+
+  Filename filename = Filename::from_os_specific(result);
+  GlobPattern glob(filename);
+  if (glob.has_glob_characters()) {
+    // If the arg contains one or more glob characters, we attempt to
+    // expand the files.  This means we interpret it as a
+    // Windows-specific filename.
+    vector_string expand;
+    if (glob.match_files(expand) != 0) {
+      // The files matched.  Add the expansions.
+      vector_string::const_iterator ei;
+      for (ei = expand.begin(); ei != expand.end(); ++ei) {
+        Filename filename(*ei);
+        save_arg(filename.to_os_specific());
+      }
+    } else {
+      // There wasn't a match.  Just add the original, unexpanded
+      // string, like bash does.
+      save_arg(result);
+    }
+
+  } else {
+    // No glob characters means we just store it directly.
+    save_arg(result);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Win32ArgParser::save_arg
+//       Access: Private
+//  Description: Stores the indicated string as the next argument in
+//               _args.
+////////////////////////////////////////////////////////////////////
+void Win32ArgParser::
+save_arg(const string &arg) {
+  _args.push_back(arg);
+}
+
+#endif  // _WIN32

+ 67 - 0
dtool/src/dtoolutil/win32ArgParser.h

@@ -0,0 +1,67 @@
+// Filename: win32ArgParser.h
+// Created by:  drose (08Nov11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef WIN32ARGPARSER_H
+#define WIN32ARGPARSER_H
+
+#include "dtoolbase.h"
+
+#ifdef _WIN32
+
+#include "vector_string.h"
+#include "pvector.h"
+
+#include <assert.h>
+
+////////////////////////////////////////////////////////////////////
+//       Class : Win32ArgParser
+// Description : This class is used to parse the single command-line
+//               string provided by Windows into the standard argc,
+//               argv array of strings.  In this way it duplicates the
+//               functionality of Windows' own CommandLineToArgv()
+//               function, but it is also supports automatic expansion
+//               of glob filenames, e.g. *.egg is turned into an
+//               explicit list of egg files in the directory.
+////////////////////////////////////////////////////////////////////
+class EXPCL_DTOOL Win32ArgParser {
+public:
+  Win32ArgParser();
+  ~Win32ArgParser();
+
+  void clear();
+
+  void set_command_line(const string &command_line);
+  void set_command_line(const wstring &command_line);
+  void set_system_command_line();
+
+  char **get_argv();
+  int get_argc();
+
+  static bool is_cygwin_shell();
+
+private:
+  void parse_quoted_arg(const char *&p);
+  void parse_unquoted_arg(const char *&p);
+  void save_arg(const string &arg);
+
+  typedef vector_string Args;
+  Args _args;
+
+  char **_argv;
+  int _argc;
+};
+
+#endif  // _WIN32
+
+#endif

+ 3 - 1
dtool/src/interrogate/interrogate.cxx

@@ -19,6 +19,7 @@
 #include "cppGlobals.h"
 #include "pnotify.h"
 #include "panda_getopt_long.h"
+#include "preprocess_argv.h"
 #include <time.h>
 
 CPPParser parser;
@@ -302,7 +303,8 @@ predefine_macro(CPPParser& parser, const string& inoption) {
 }
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
+  preprocess_argv(argc, argv);
   string command_line;
   int i;
   for (i = 0; i < argc; i++) {

+ 2 - 0
dtool/src/interrogate/interrogate_module.cxx

@@ -23,6 +23,7 @@
 #include "pystub.h"
 #include "pnotify.h"
 #include "panda_getopt_long.h"
+#include "preprocess_argv.h"
 #include "pset.h"
 
 Filename output_code_filename;
@@ -237,6 +238,7 @@ int main(int argc, char *argv[]) {
   extern int optind;
   int flag;
 
+  preprocess_argv(argc, argv);
   flag = getopt_long_only(argc, argv, short_options, long_options, NULL);
   while (flag != EOF) {
     switch (flag) {

+ 3 - 1
dtool/src/interrogate/parse_file.cxx

@@ -22,6 +22,7 @@
 #include "cppType.h"
 #include "cppGlobals.h"
 #include "panda_getopt_long.h"
+#include "preprocess_argv.h"
 #include <stdlib.h>
 
 CPPParser parser;
@@ -192,10 +193,11 @@ show_typedefs(const string &str) {
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
   extern char *optarg;
   extern int optind;
   const char *optstr = "I:S:D:o:l:vp";
+  preprocess_argv(argc, argv);
 
   parser.set_verbose(2);
   bool prompt = false;

+ 0 - 3
dtool/src/prc/Sources.pp

@@ -27,7 +27,6 @@
     configVariableSearchPath.I configVariableSearchPath.h \
     configVariableString.I configVariableString.h \
     encryptStreamBuf.h encryptStreamBuf.I encryptStream.h encryptStream.I \
-    globPattern.I globPattern.h \
     littleEndian.h \
     nativeNumericData.I nativeNumericData.h \
     pnotify.I pnotify.h \
@@ -63,7 +62,6 @@
     configVariableSearchPath.cxx \
     configVariableString.cxx \
     encryptStreamBuf.cxx encryptStream.cxx \
-    globPattern.cxx \
     nativeNumericData.cxx \
     notify.cxx \
     notifyCategory.cxx \
@@ -93,7 +91,6 @@
     configVariableSearchPath.I configVariableSearchPath.h \
     configVariableString.I configVariableString.h \
     encryptStreamBuf.h encryptStreamBuf.I encryptStream.h encryptStream.I \
-    globPattern.I globPattern.h \
     littleEndian.h \
     nativeNumericData.I nativeNumericData.h \
     pnotify.I pnotify.h \

+ 0 - 1
dtool/src/prc/prc_composite2.cxx

@@ -3,7 +3,6 @@
 #include "configVariableString.cxx"
 #include "encryptStreamBuf.cxx"
 #include "encryptStream.cxx"
-#include "globPattern.cxx"
 #include "nativeNumericData.cxx"
 #include "notify.cxx"
 #include "notifyCategory.cxx"

+ 3 - 1
dtool/src/prckeys/makePrcKey.cxx

@@ -17,6 +17,7 @@
 #include "filename.h"
 #include "pvector.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 #include <stdio.h>
 
 // Pick up the public key definitions.
@@ -317,7 +318,7 @@ usage() {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
   extern char *optarg;
   extern int optind;
   const char *optstr = "a:b:p:h";
@@ -329,6 +330,7 @@ main(int argc, char *argv[]) {
   string pass_phrase;
   bool got_pass_phrase = false;
 
+  preprocess_argv(argc, argv);
   int flag = getopt(argc, argv, optstr);
 
   while (flag != EOF) {

+ 3 - 1
dtool/src/prckeys/signPrcFile_src.cxx

@@ -21,6 +21,7 @@
 #include "filename.h"
 #include "executionEnvironment.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 
 #include <time.h>
 
@@ -285,7 +286,8 @@ usage() {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
+  preprocess_argv(argc, argv);
   if (argv[0] != NULL && *argv[0]) {
     // Get the program name from the command-line arguments, if the OS
     // provides it.

+ 3 - 1
dtool/src/test_interrogate/test_interrogate.cxx

@@ -20,6 +20,7 @@
 #include "filename.h"
 #include "pystub.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 
 #include <stdlib.h>
 
@@ -516,7 +517,7 @@ usage() {
 }
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
   extern char *optarg;
   extern int optind;
   const char *optstr = "p:ftqh";
@@ -524,6 +525,7 @@ main(int argc, char *argv[]) {
   bool all_functions = false;
   bool all_types = false;
   bool quick_load = false;
+  preprocess_argv(argc, argv);
   int flag = getopt(argc, argv, optstr);
 
   while (flag != EOF) {

+ 4 - 1
panda/src/downloadertools/apply_patch.cxx

@@ -14,11 +14,14 @@
 
 #include "pandabase.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 #include "patchfile.h"
 #include "filename.h"
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
+  preprocess_argv(argc, argv);
+
   if (argc < 3) {
     cerr << "Usage: apply_patch <patch_file> <old_file>" << endl;
     cerr << "Will overwrite old_file" << endl;

+ 3 - 1
panda/src/downloadertools/build_patch.cxx

@@ -14,6 +14,7 @@
 
 #include "pandabase.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 #include "patchfile.h"
 #include "filename.h"
 
@@ -51,7 +52,7 @@ help() {
 }
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
   Filename patch_file;
   bool complete_file = false;
   int footprint_length = 0;
@@ -59,6 +60,7 @@ main(int argc, char *argv[]) {
   //  extern char *optarg;
   extern int optind;
   static const char *optflags = "o:cf:h";
+  preprocess_argv(argc, argv);
   int flag = getopt(argc, argv, optflags);
   Filename rel_path;
   while (flag != EOF) {

+ 3 - 1
panda/src/downloadertools/check_md5.cxx

@@ -16,6 +16,7 @@
 #include "hashVal.h"
 #include "filename.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 
 bool output_decimal = false;
 bool suppress_filename = false;
@@ -65,7 +66,7 @@ output_hash(const string &filename, const HashVal &hash) {
   
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
   extern char *optarg;
   extern int optind;
   const char *optstr = "i:db:qh";
@@ -74,6 +75,7 @@ main(int argc, char *argv[]) {
   string input_string;
   Filename binary_output_filename;
 
+  preprocess_argv(argc, argv);
   int flag = getopt(argc, argv, optstr);
 
   while (flag != EOF) {

+ 3 - 1
panda/src/downloadertools/multify.cxx

@@ -14,6 +14,7 @@
 
 #include "pandabase.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 #include "multifile.h"
 #include "pointerTo.h"
 #include "filename.h"
@@ -747,7 +748,8 @@ tokenize_extensions(const string &str, pset<string> &extensions) {
 }
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
+  preprocess_argv(argc, argv);
   if (argc < 2) {
     usage();
     return 1;

+ 3 - 1
panda/src/downloadertools/pdecrypt.cxx

@@ -16,6 +16,7 @@
 #include "encrypt_string.h"
 #include "pnotify.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 
 string password;
 bool got_password = false;
@@ -44,7 +45,7 @@ usage() {
 }
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
   extern char *optarg;
   extern int optind;
   const char *optstr = "o:p:h";
@@ -52,6 +53,7 @@ main(int argc, char *argv[]) {
   Filename dest_filename;
   bool got_dest_filename = false;
 
+  preprocess_argv(argc, argv);
   int flag = getopt(argc, argv, optstr);
 
   while (flag != EOF) {

+ 3 - 1
panda/src/downloadertools/pencrypt.cxx

@@ -16,6 +16,7 @@
 #include "encrypt_string.h"
 #include "pnotify.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 
 string password;
 bool got_password = false;
@@ -82,7 +83,7 @@ usage() {
 }
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
   extern char *optarg;
   extern int optind;
   const char *optstr = "o:p:ta:k:i:h";
@@ -91,6 +92,7 @@ main(int argc, char *argv[]) {
   bool got_dest_filename = false;
   bool text_file = false;
 
+  preprocess_argv(argc, argv);
   int flag = getopt(argc, argv, optstr);
 
   while (flag != EOF) {

+ 3 - 1
panda/src/downloadertools/punzip.cxx

@@ -16,6 +16,7 @@
 #include "compress_string.h"
 #include "pnotify.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 
 void
 usage() {
@@ -31,7 +32,7 @@ usage() {
 }
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
   extern char *optarg;
   extern int optind;
   const char *optstr = "o:ch";
@@ -40,6 +41,7 @@ main(int argc, char *argv[]) {
   bool got_dest_filename = false;
   bool use_stdout = false;
 
+  preprocess_argv(argc, argv);
   int flag = getopt(argc, argv, optstr);
 
   while (flag != EOF) {

+ 3 - 1
panda/src/downloadertools/pzip.cxx

@@ -16,6 +16,7 @@
 #include "compress_string.h"
 #include "pnotify.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 
 void
 usage() {
@@ -55,7 +56,7 @@ usage() {
 }
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
   extern char *optarg;
   extern int optind;
   const char *optstr = "o:c123456789h";
@@ -65,6 +66,7 @@ main(int argc, char *argv[]) {
   bool use_stdout = false;
   int compression_level = 6;
 
+  preprocess_argv(argc, argv);
   int flag = getopt(argc, argv, optstr);
 
   while (flag != EOF) {

+ 3 - 2
panda/src/testbed/pgrid.cxx

@@ -19,6 +19,7 @@
 #include "string_utils.h"
 #include "pvector.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 
 #define RANDFRAC (rand()/(PN_stdfloat)(RAND_MAX))
 
@@ -382,9 +383,9 @@ load_gridded_models(WindowFramework *window,
 }
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
+  preprocess_argv(argc, argv);
   PandaFramework framework;
-  vector_string args;
   framework.open_framework(argc, argv);
   framework.set_window_title("Gridded Object Viewer");
 

+ 3 - 1
panda/src/testbed/pview.cxx

@@ -24,6 +24,7 @@
 #include "bamCache.h"
 #include "virtualFileSystem.h"
 #include "panda_getopt.h"
+#include "preprocess_argv.h"
 
 // By including checkPandaVersion.h, we guarantee that runtime
 // attempts to run pview will fail if it inadvertently links with the
@@ -223,7 +224,8 @@ report_version() {
 }
 
 int
-main(int argc, char *argv[]) {
+main(int argc, char **argv) {
+  preprocess_argv(argc, argv);
   framework.open_framework(argc, argv);
   framework.set_window_title("Panda Viewer");
 

+ 3 - 2
pandatool/src/progbase/programBase.cxx

@@ -26,6 +26,7 @@
 #include "configVariableInt.h"
 #include "configVariableBool.h"
 #include "panda_getopt_long.h"
+#include "preprocess_argv.h"
 
 #include <stdlib.h>
 #include <algorithm>
@@ -198,8 +199,8 @@ show_text(const string &prefix, int indent_width, string text) {
 //               exit(1).
 ////////////////////////////////////////////////////////////////////
 void ProgramBase::
-parse_command_line(int argc, char *argv[]) {
-
+parse_command_line(int argc, char **argv) {
+  preprocess_argv(argc, argv);
 
   // Setting this variable to zero reinitializes the options parser
   // This is only necessary for processing multiple command lines in

+ 1 - 1
pandatool/src/progbase/programBase.h

@@ -46,7 +46,7 @@ public:
   INLINE void show_text(const string &text);
   void show_text(const string &prefix, int indent_width, string text);
 
-  virtual void parse_command_line(int argc, char *argv[]);
+  virtual void parse_command_line(int argc, char **argv);
 
   string get_exec_command() const;