Added 'split_winmain' function.

[SVN r23550]
This commit is contained in:
Vladimir Prus
2004-07-14 15:57:02 +00:00
parent 6dcf98d974
commit 9133a2e903
7 changed files with 176 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ subproject libs/program_options/build ;
SOURCES = cmdline config_file options_description parsers variables_map
value_semantic positional_options utf8_codecvt_facet convert
winmain
;
lib boost_program_options

View File

@@ -5,7 +5,7 @@ project boost/program_options
SOURCES = cmdline config_file options_description parsers variables_map
value_semantic positional_options utf8_codecvt_facet
convert
convert winmain
;
import os ;

View File

@@ -173,6 +173,21 @@ namespace boost { namespace program_options {
BOOST_PROGRAM_OPTIONS_DECL parsed_options
parse_environment(const options_description&, const char* prefix);
#ifdef _WIN32
/** Parses the char* string which is passed to WinMain function on
windows. This function is provided for convenience, and because it's
not clear how to portably access split command line string from
runtime library and if it always exists.
This function is available only on Windows.
*/
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::string>
split_winmain(const std::string& cmdline);
/** @overload */
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::wstring>
split_winmain(const std::wstring& cmdline);
#endif
}}
#undef DECL

93
src/winmain.cpp Normal file
View File

@@ -0,0 +1,93 @@
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/parsers.hpp>
#ifdef _WIN32
namespace boost { namespace program_options {
using namespace std;
// The rules for windows command line are pretty funny, see
// http://article.gmane.org/gmane.comp.lib.boost.user/3005
// http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp
BOOST_PROGRAM_OPTIONS_DECL
std::vector<std::string> split_winmain(const std::string& input)
{
std::vector<std::string> result;
string::const_iterator i = input.begin(), e = input.end();
for(;i != e; ++i)
if (!std::isspace(*i))
break;
if (i != e) {
std::string current;
bool inside_quoted = false;
int backslash_count = 0;
for(; i != e; ++i) {
if (*i == '"') {
// '"' preceded by even number (n) of backslashes generates
// n/2 backslashes and is a quoted block delimiter
if (backslash_count % 2 == 0) {
current.append(backslash_count / 2, '\\');
inside_quoted = !inside_quoted;
// '"' preceded by odd number (n) of backslashes generates
// (n-1)/2 backslashes and is literal quote.
} else {
current.append(backslash_count / 2, '\\');
current.push_back('"');
}
backslash_count = 0;
} else if (*i == '\\') {
++backslash_count;
} else {
// Not quote or backslash. All accumulated backslashes should be
// added
if (backslash_count) {
current.append(backslash_count, '\\');
backslash_count = 0;
}
if (isspace(*i) && !inside_quoted) {
// Space outside quoted section terminate the current argument
result.push_back(current);
current.resize(0);
for(;i != e && isspace(*i); ++i)
;
--i;
} else {
current.push_back(*i);
}
}
}
// If we have trailing backslashes, add them
if (backslash_count)
current.append(backslash_count, '\\');
// If we have non-empty 'current' or we're still in quoted
// section (even if 'current' is empty), add the last token.
if (!current.empty() || inside_quoted)
result.push_back(current);
}
return result;
}
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::wstring>
split_winmain(const std::wstring& cmdline)
{
vector<wstring> result;
vector<string> aux = split_winmain(to_internal(cmdline));
for (unsigned i = 0, e = result.size(); i < e; ++i)
result.push_back(from_utf8(aux[i]));
return result;
}
}}
#endif

View File

@@ -33,12 +33,14 @@ test-suite program_options :
[ program-options-test cmdline_test ]
[ program-options-test positional_options_test ]
[ program-options-test unicode_test ]
[ program-options-test winmain ]
[ program-options-dll-test options_description_test ]
[ program-options-dll-test parsers_test ]
[ program-options-dll-test variable_map_test ]
[ program-options-dll-test cmdline_test ]
[ program-options-dll-test positional_options_test ]
[ program-options-dll-test unicode_test ]
[ program-options-dll-test winmain ]
;

View File

@@ -14,6 +14,7 @@ test-suite program_options :
[ run cmdline_test.cpp ]
[ run positional_options_test.cpp ]
[ run unicode_test.cpp ]
[ run winmain.cpp ]
;
exe test_convert : test_convert.cpp ../build//program_options ;

63
test/winmain.cpp Normal file
View File

@@ -0,0 +1,63 @@
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef _WIN32
#include <string>
#include <vector>
#include <cctype>
#include <boost/program_options/parsers.hpp>
using namespace boost::program_options;
#include <boost/test/test_tools.hpp>
#include <boost/preprocessor/cat.hpp>
template<class T, unsigned N>
unsigned size(const T (&t)[N])
{
return N;
}
void test_winmain()
{
using namespace std;
#define C ,
#define TEST(input, expected) \
char* BOOST_PP_CAT(e, __LINE__)[] = expected;\
vector<string> BOOST_PP_CAT(v, __LINE__) = split_winmain(input);\
BOOST_REQUIRE(BOOST_PP_CAT(v, __LINE__).size() == size(BOOST_PP_CAT(e, __LINE__)));\
BOOST_CHECK_EQUAL_COLLECTIONS(BOOST_PP_CAT(v, __LINE__).begin(),\
BOOST_PP_CAT(v, __LINE__).end(),\
BOOST_PP_CAT(e, __LINE__));
// The following expectations were obtained in Win2000 shell:
TEST("1 ", {"1"});
TEST("1\"2\" ", {"12"});
TEST("1\"2 ", {"12 "});
TEST("1\"\\\"2\" ", {"1\"2"});
TEST("\"1\" \"2\" ", {"1" C "2"});
TEST("1\\\" ", {"1\""});
TEST("1\\\\\" ", {"1\\ "});
TEST("1\\\\\\\" ", {"1\\\""});
TEST("1\\\\\\\\\" ", {"1\\\\ "});
TEST("1\" 1 ", {"1 1 "});
TEST("1\\\" 1 ", {"1\"" C "1"});
TEST("1\\1 ", {"1\\1"});
TEST("1\\\\1 ", {"1\\\\1"});
}
int test_main(int, char*[])
{
test_winmain();
return 0;
}
#else
int test_main(int, char*[])
{
return 0;
}
#endif