mirror of
https://github.com/boostorg/program_options.git
synced 2026-01-30 20:12:31 +00:00
Added 'split_winmain' function.
[SVN r23550]
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
@@ -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
93
src/winmain.cpp
Normal 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
|
||||
@@ -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 ]
|
||||
|
||||
|
||||
;
|
||||
|
||||
@@ -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
63
test/winmain.cpp
Normal 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
|
||||
Reference in New Issue
Block a user