fix windows globbing to support embedded quote marks

This commit is contained in:
David Rose 2011-11-21 21:13:30 +00:00
parent 75ac6c1bae
commit a9fc6e59ae
3 changed files with 50 additions and 51 deletions

View File

@ -37,17 +37,15 @@ preprocess_argv(int &argc, char **&argv) {
// Not Windows: do nothing.
#else // _WIN32
// Temporarily commenting out to fix build. Revisit shortly.
/*
static Win32ArgParser parser;
if (parser.is_cygwin_shell()) {
// Running within Cygwin: do nothing.
if (!parser.do_glob()) {
// No globbing required.
return;
}
// On Windows, and not within Cygwin. Process the args.
// Globbing is required. Process the args.
parser.set_system_command_line();
argc = parser.get_argc();
argv = parser.get_argv();
*/
#endif // _WIN32
}

View File

@ -81,11 +81,7 @@ set_command_line(const string &command_line) {
const char *p = command_line.c_str();
while (*p != '\0') {
if (*p == '"') {
parse_quoted_arg(p);
} else {
parse_unquoted_arg(p);
}
parse_unquoted_arg(p);
// Skip whitespace.
while (*p != '\0' && isspace(*p)) {
@ -159,17 +155,19 @@ get_argc() {
}
////////////////////////////////////////////////////////////////////
// Function: Win32ArgParser::is_cygwin_shell
// Function: Win32ArgParser::do_glob
// Access: Public, Static
// Description: Tries to determine if this program was launched from
// a Cygwin shell. Returns true if so, false otherwise.
// Description: Returns true if we should attempt to process (and
// apply glob matching) to the command line, or false if
// we should not (for instance, because it has already
// been done by the shell).
////////////////////////////////////////////////////////////////////
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");
do_glob() {
// First, we check for the PANDA_GLOB environment variable. If this
// is present, it overrides any other checks: "0" means not to do
// the glob, "1" means to do it.
string envvar = ExecutionEnvironment::get_environment_variable("PANDA_GLOB");
if (!envvar.empty()) {
istringstream strm(envvar);
int value;
@ -179,13 +177,16 @@ is_cygwin_shell() {
}
}
// Nothing explicit, so we have to determine Cygwin status
// implicitly.
// Nothing explicit, so the default is to perform globbing only if
// we were launched from the Windows default command shell, cmd.exe.
// Presumably if we were launched from something else, like Python,
// the caller won't expect globbing to be performed; and if we were
// launched from a Cygwin shell, it will already have been
// performed.
// 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.
// 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);
@ -221,30 +222,21 @@ is_cygwin_shell() {
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.
if (basename == "cmd.exe") {
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.
// Description: Parses the quoted argument beginning at p and returns
// it. Advances p to the first character following the
// close quote.
////////////////////////////////////////////////////////////////////
void Win32ArgParser::
string Win32ArgParser::
parse_quoted_arg(const char *&p) {
char quote = *p;
++p;
@ -273,8 +265,7 @@ parse_quoted_arg(const char *&p) {
// the closing quote and we're done.
if ((num_slashes & 1) == 0) {
++p;
save_arg(result);
return;
return result;
}
// But if there's an odd backslash, it simply escapes the
@ -303,7 +294,7 @@ parse_quoted_arg(const char *&p) {
++p;
}
save_arg(result);
return result;
}
////////////////////////////////////////////////////////////////////
@ -316,17 +307,25 @@ parse_quoted_arg(const char *&p) {
void Win32ArgParser::
parse_unquoted_arg(const char *&p) {
string result;
bool contains_quotes = false;
while (*p != '\0' && !isspace(*p)) {
result += *p;
++p;
if (*p == '"') {
// Begin a quoted sequence.
contains_quotes = true;
result += parse_quoted_arg(p);
} else {
// A regular character.
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.
if (!contains_quotes && glob.has_glob_characters()) {
// If the arg contains one or more glob characters (and no
// quotation marks), 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.
@ -342,7 +341,9 @@ parse_unquoted_arg(const char *&p) {
}
} else {
// No glob characters means we just store it directly.
// No glob characters means we just store it directly. Also, an
// embedded quoted string, anywhere within the arg, means we can't
// expand the glob characters.
save_arg(result);
}
}

View File

@ -48,10 +48,10 @@ public:
char **get_argv();
int get_argc();
static bool is_cygwin_shell();
static bool do_glob();
private:
void parse_quoted_arg(const char *&p);
string parse_quoted_arg(const char *&p);
void parse_unquoted_arg(const char *&p);
void save_arg(const string &arg);