implement flag for Unix-like behaviour in wxCmdLineParser::ConverStringToArgs()

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@54648 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2008-07-16 00:49:25 +00:00
parent fec42c21ef
commit a4761b4c08
4 changed files with 138 additions and 32 deletions

View File

@ -19,6 +19,13 @@
#include "wx/arrstr.h"
#include "wx/cmdargs.h"
// determines ConvertStringToArgs() behaviour
enum wxCmdLineSplitType
{
wxCMD_LINE_SPLIT_DOS,
wxCMD_LINE_SPLIT_UNIX
};
#if wxUSE_CMDLINE_PARSER
class WXDLLIMPEXP_FWD_BASE wxDateTime;
@ -233,7 +240,9 @@ public:
void Reset();
// break down the command line in arguments
static wxArrayString ConvertStringToArgs(const wxString& cmdline);
static wxArrayString
ConvertStringToArgs(const wxString& cmdline,
wxCmdLineSplitType type = wxCMD_LINE_SPLIT_DOS);
private:
// common part of all ctors
@ -251,7 +260,9 @@ private:
class WXDLLIMPEXP_BASE wxCmdLineParser
{
public:
static wxArrayString ConvertStringToArgs(const wxString& cmdline);
static wxArrayString
ConvertStringToArgs(const wxString& cmdline,
wxCmdLineSplitType type = wxCMD_LINE_SPLIT_DOS);
};
#endif // wxUSE_CMDLINE_PARSER/!wxUSE_CMDLINE_PARSER

View File

@ -59,6 +59,15 @@ enum wxCmdLineEntryType
wxCMD_LINE_NONE ///< Use this to terminate the list.
};
/**
Flags determining ConvertStringToArgs() behaviour.
*/
enum wxCmdLineSplitType
{
wxCMD_LINE_SPLIT_DOS,
wxCMD_LINE_SPLIT_UNIX
};
/**
The structure wxCmdLineEntryDesc is used to describe the one command line
switch, option or parameter. An array of such structures should be passed
@ -301,12 +310,20 @@ public:
bool AreLongOptionsEnabled() const;
/**
Breaks down the string containing the full command line in words. The
words are separated by whitespace. The quotes can be used in the input
string to quote the white space and the back slashes can be used to
quote the quotes.
Breaks down the string containing the full command line in words.
Words are separated by whitespace and double quotes can be used to
preserve the spaces inside the words.
By default, this function uses Windows-like word splitting algorithm,
i.e. single quotes have no special meaning and backslash can't be used
to escape spaces neither. With @c wxCMD_LINE_SPLIT_UNIX flag Unix
semantics is used, i.e. both single and double quotes can be used and
backslash can be used to escape all the other special characters.
*/
static wxArrayString ConvertStringToArgs(const wxChar cmdline);
static wxArrayString
ConvertStringToArgs(const wxChar cmdline,
wxCmdLineSplitType flags = wxCMD_LINE_SPLIT_DOS);
/**
Identical to EnableLongOptions(@false).

View File

@ -1280,15 +1280,15 @@ static wxString GetLongOptionName(wxString::const_iterator p,
*/
/* static */
wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxString& cmdline)
wxArrayString
wxCmdLineParser::ConvertStringToArgs(const wxString& cmdline,
wxCmdLineSplitType type)
{
wxArrayString args;
wxString arg;
arg.reserve(1024);
bool isInsideQuotes = false;
const wxString::const_iterator end = cmdline.end();
wxString::const_iterator p = cmdline.begin();
@ -1303,31 +1303,76 @@ wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxString& cmdline)
break;
// parse this parameter
bool lastBS = false;
bool lastBS = false,
isInsideQuotes = false;
wxChar chDelim = '\0';
for ( arg.clear(); p != end; ++p )
{
const wxChar ch = *p;
if ( ch == '"' )
if ( type == wxCMD_LINE_SPLIT_DOS )
{
if ( ch == '"' )
{
if ( !lastBS )
{
isInsideQuotes = !isInsideQuotes;
// don't put quote in arg
continue;
}
//else: quote has no special meaning but the backslash
// still remains -- makes no sense but this is what
// Windows does
}
// note that backslash does *not* quote the space, only quotes do
else if ( !isInsideQuotes && (ch == ' ' || ch == '\t') )
{
++p; // skip this space anyhow
break;
}
lastBS = ch == '\\';
}
else // type == wxCMD_LINE_SPLIT_UNIX
{
if ( !lastBS )
{
isInsideQuotes = !isInsideQuotes;
if ( isInsideQuotes )
{
if ( ch == chDelim )
{
isInsideQuotes = false;
// don't put quote in arg
continue;
continue; // don't use the quote itself
}
}
else // not in quotes and not escaped
{
if ( ch == '\'' || ch == '"' )
{
isInsideQuotes = true;
chDelim = ch;
continue; // don't use the quote itself
}
if ( ch == ' ' || ch == '\t' )
{
++p; // skip this space anyhow
break;
}
}
lastBS = ch == '\\';
if ( lastBS )
continue;
}
else // escaped by backslash, just use as is
{
lastBS = false;
}
//else: quote has no special meaning but the backslash
// still remains -- makes no sense but this is what
// Windows does
}
// note that backslash does *not* quote the space, only quotes do
else if ( !isInsideQuotes && (ch == ' ' || ch == '\t') )
{
++p; // skip this space anyhow
break;
}
lastBS = ch == '\\';
arg += ch;
}

View File

@ -55,12 +55,26 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CmdLineTestCase, "CmdLineTestCase" );
void CmdLineTestCase::ConvertStringTestCase()
{
#define WX_ASSERT_ARGS_EQUAL(s, args) \
#define WX_ASSERT_DOS_ARGS_EQUAL(s, args) \
{ \
const wxArrayString a(wxCmdLineParser::ConvertStringToArgs(args));\
WX_ASSERT_STRARRAY_EQUAL(s, a); \
const wxArrayString \
argsDOS(wxCmdLineParser::ConvertStringToArgs(args, \
wxCMD_LINE_SPLIT_DOS)); \
WX_ASSERT_STRARRAY_EQUAL(s, argsDOS); \
}
#define WX_ASSERT_UNIX_ARGS_EQUAL(s, args) \
{ \
const wxArrayString \
argsUnix(wxCmdLineParser::ConvertStringToArgs(args, \
wxCMD_LINE_SPLIT_UNIX)); \
WX_ASSERT_STRARRAY_EQUAL(s, argsUnix); \
}
#define WX_ASSERT_ARGS_EQUAL(s, args) \
WX_ASSERT_DOS_ARGS_EQUAL(s, args) \
WX_ASSERT_UNIX_ARGS_EQUAL(s, args)
// normal cases
WX_ASSERT_ARGS_EQUAL( "foo", "foo" )
WX_ASSERT_ARGS_EQUAL( "foo bar", "\"foo bar\"" )
@ -74,12 +88,31 @@ void CmdLineTestCase::ConvertStringTestCase()
WX_ASSERT_ARGS_EQUAL( "foo", "foo \t " )
WX_ASSERT_ARGS_EQUAL( "foo|bar", "foo bar " )
WX_ASSERT_ARGS_EQUAL( "foo|bar|", "foo bar \"" )
WX_ASSERT_ARGS_EQUAL( "foo|bar|\\", "foo bar \\" )
WX_ASSERT_DOS_ARGS_EQUAL( "foo|bar|\\", "foo bar \\" )
WX_ASSERT_UNIX_ARGS_EQUAL( "foo|bar|", "foo bar \\" )
WX_ASSERT_ARGS_EQUAL( "12 34", "1\"2 3\"4" );
WX_ASSERT_ARGS_EQUAL( "1|2 34", "1 \"2 3\"4" );
WX_ASSERT_ARGS_EQUAL( "1|2 3|4", "1 \"2 3\" 4" );
// check for (broken) Windows semantics: backslash doesn't escape spaces
WX_ASSERT_ARGS_EQUAL( "foo|bar\\|baz", "foo bar\\ baz" );
WX_ASSERT_ARGS_EQUAL( "foo|bar\\\"baz", "foo \"bar\\\"baz\"" );
WX_ASSERT_DOS_ARGS_EQUAL( "foo|bar\\|baz", "foo bar\\ baz" );
WX_ASSERT_DOS_ARGS_EQUAL( "foo|bar\\\"baz", "foo \"bar\\\"baz\"" );
// check for more sane Unix semantics: backslash does escape spaces and
// quotes
WX_ASSERT_UNIX_ARGS_EQUAL( "foo|bar baz", "foo bar\\ baz" );
WX_ASSERT_UNIX_ARGS_EQUAL( "foo|bar\"baz", "foo \"bar\\\"baz\"" );
// check that single quotes work too with Unix semantics
WX_ASSERT_UNIX_ARGS_EQUAL( "foo bar", "'foo bar'" )
WX_ASSERT_UNIX_ARGS_EQUAL( "foo|bar baz", "foo 'bar baz'" )
WX_ASSERT_UNIX_ARGS_EQUAL( "foo|bar baz", "foo 'bar baz'" )
WX_ASSERT_UNIX_ARGS_EQUAL( "O'Henry", "\"O'Henry\"" )
WX_ASSERT_UNIX_ARGS_EQUAL( "O'Henry", "O\\'Henry" )
#undef WX_ASSERT_DOS_ARGS_EQUAL
#undef WX_ASSERT_UNIX_ARGS_EQUAL
#undef WX_ASSERT_ARGS_EQUAL
}