John Weiss wrote:
> I just ran a quick test.  Any Unix shell treats "--option='foo bar'"
> as a single element of "*argv[]".  The single-quotes protected the
> space from the shell.  (I tested with bash, ash, csh, tcsh, ksh, and
> bsh.)
> 
> For Windows, however I wouldn't be surprised if whitespace chars
> weren't escaped.  Just another one of those platform differences
> that'll need special handling.

I understand, really I do. See here for a sophisticated way of splitting a
string into an argv array:
http://www.devel.lyx.org/~leeming/libs/child/doc/html/parse_pseudo_command_line.html
Equivalent URL: http://tinyurl.com/4c4v9

I attach the code to recombine an argv array following the wsh quoting
rules.

-- 
Angus
/**
 * \file make_command_line.cpp
 * \author Angus Leeming
 */

#include "make_command_line.h"
#include "process_data.h"
#include <sstream>

using std::ostream;
using std::ostringstream;
using std::string;
using std::vector;


namespace child {

namespace {

string const protect_wsh_arg(string const & old_arg)
{
	if (old_arg.empty())
		return old_arg;

	ostringstream new_arg;

	string::const_iterator it = old_arg.begin();
	string::const_iterator const end = old_arg.end();

	// Inside a "-protected block, any " character must be escaped.
	// Note also that all adjacent \ characters in a block must be escaped
	// only if the next character following them is a " (which must
	// also be escaped).
	// Thus, using <...> to delimit the string,
	// <foo \ bar> becomes <"foo \ bar">,
	// <foo " bar> becomes <"foo \" bar"> and
	// <foo \\" bar> becomes <"foo \\\\\" bar">.
	// See http://article.gmane.org/gmane.comp.lib.boost.user/3005
	// or http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp

	new_arg << '"';

	for (; it != end; ++it) {
		char const c = *it;

		if (c == '"') {
			new_arg << "\\\"";

		} else if (c == '\\') {
			string::const_iterator it2 = it + 1;
			while (it2 != end && *it2 == '\\')
				++it2;

			string::size_type nbackslashes = std::distance(it, it2);
			if (it2 != end && *it2 == '"')
				nbackslashes *= 2;

			new_arg << string(nbackslashes, '\\');
			it = it2 - 1;

		} else {
			new_arg << c;
		}
	}

	new_arg << '"';

	return new_arg.str();
}


void build_wsh_command_line(ostream & os,
                            vector<string> const & argv)
{
	vector<string>::const_iterator it = argv.begin();
	vector<string>::const_iterator const end = argv.end();

	for (; it != end; ++it) {
		string const arg = protect_wsh_arg(*it);
		if (!arg.empty()) {
			if (os.tellp() > 0)
				os << ' ';
			os << arg;
		}
	}
}

} // namespace anon


string const make_wsh_command_line(process_data const & data)
{
	if (data.argv().empty())
		return string();

	ostringstream line;

	build_wsh_command_line(line, data.argv());
	// standard stream stuff to go here.

	return line.str();
}


string const make_wsh_command_line(vector<string> const & argv)
{
	if (argv.empty())
		return string();

	ostringstream line;

	build_wsh_command_line(line, argv);

	return line.str();
}

} // namespace child

Reply via email to