Unverified Commit 5d4f8645 authored by Joseph Noir's avatar Joseph Noir Committed by GitHub

Merge pull request #890

Fix handling of CLI string arguments
parents e01e9eca 208d78b4
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <cstring>
#include <iterator> #include <iterator>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
...@@ -102,16 +103,33 @@ void parse(parse_state& ps, std::string& x); ...@@ -102,16 +103,33 @@ void parse(parse_state& ps, std::string& x);
// -- container types ---------------------------------------------------------- // -- container types ----------------------------------------------------------
template <class First, class Second> void parse_element(parse_state& ps, std::string& x, const char* char_blacklist);
void parse(parse_state& ps, std::pair<First, Second>& kvp) {
parse(ps, kvp.first); template <class T>
enable_if_t<!is_pair<T>::value> parse_element(parse_state& ps, T& x,
const char*) {
parse(ps, x);
}
template <class First, class Second, size_t N>
void parse_element(parse_state& ps, std::pair<First, Second>& kvp,
const char (&char_blacklist)[N]) {
static_assert(N > 0, "empty array");
// TODO: consider to guard the blacklist computation with
// `if constexpr (is_same_v<First, string>)` when switching to C++17.
char key_blacklist[N + 1];
if (N > 1)
memcpy(key_blacklist, char_blacklist, N - 1);
key_blacklist[N - 1] = '=';
key_blacklist[N] = '\0';
parse_element(ps, kvp.first, key_blacklist);
if (ps.code > pec::trailing_character) if (ps.code > pec::trailing_character)
return; return;
if (!ps.consume('=')) { if (!ps.consume('=')) {
ps.code = pec::unexpected_character; ps.code = pec::unexpected_character;
return; return;
} }
parse(ps, kvp.second); parse_element(ps, kvp.second, char_blacklist);
} }
template <class T> template <class T>
...@@ -123,6 +141,7 @@ enable_if_tt<is_iterable<T>> parse(parse_state& ps, T& xs) { ...@@ -123,6 +141,7 @@ enable_if_tt<is_iterable<T>> parse(parse_state& ps, T& xs) {
auto out = std::inserter(xs, xs.end()); auto out = std::inserter(xs, xs.end());
// List/map using [] or {} notation. // List/map using [] or {} notation.
if (ps.consume(opening_char)) { if (ps.consume(opening_char)) {
char char_blacklist[] = {closing_char, ',', '\0'};
do { do {
if (ps.consume(closing_char)) { if (ps.consume(closing_char)) {
ps.skip_whitespaces(); ps.skip_whitespaces();
...@@ -130,7 +149,7 @@ enable_if_tt<is_iterable<T>> parse(parse_state& ps, T& xs) { ...@@ -130,7 +149,7 @@ enable_if_tt<is_iterable<T>> parse(parse_state& ps, T& xs) {
return; return;
} }
value_type tmp; value_type tmp;
parse(ps, tmp); parse_element(ps, tmp, char_blacklist);
if (ps.code > pec::trailing_character) if (ps.code > pec::trailing_character)
return; return;
*out++ = std::move(tmp); *out++ = std::move(tmp);
...@@ -148,8 +167,9 @@ enable_if_tt<is_iterable<T>> parse(parse_state& ps, T& xs) { ...@@ -148,8 +167,9 @@ enable_if_tt<is_iterable<T>> parse(parse_state& ps, T& xs) {
return; return;
// List/map without [] or {}. // List/map without [] or {}.
do { do {
char char_blacklist[] = {',', '\0'};
value_type tmp; value_type tmp;
parse(ps, tmp); parse_element(ps, tmp, char_blacklist);
if (ps.code > pec::trailing_character) if (ps.code > pec::trailing_character)
return; return;
*out++ = std::move(tmp); *out++ = std::move(tmp);
......
...@@ -206,11 +206,25 @@ void parse(parse_state& ps, std::string& x) { ...@@ -206,11 +206,25 @@ void parse(parse_state& ps, std::string& x) {
parser::read_string(ps, make_consumer(x)); parser::read_string(ps, make_consumer(x));
return; return;
} }
auto c = ps.current(); for (auto c = ps.current(); c != '\0'; c = ps.next())
while (c != '\0' && (isalnum(c) || isspace(c))) {
x += c; x += c;
c = ps.next(); while (!x.empty() && isspace(x.back()))
x.pop_back();
ps.code = pec::success;
}
void parse_element(parse_state& ps, std::string& x,
const char* char_blacklist) {
ps.skip_whitespaces();
if (ps.current() == '"') {
parser::read_string(ps, make_consumer(x));
return;
} }
auto is_legal = [=](char c) {
return c != '\0' && strchr(char_blacklist, c) == nullptr;
};
for (auto c = ps.current(); is_legal(c); c = ps.next())
x += c;
while (!x.empty() && isspace(x.back())) while (!x.empty() && isspace(x.back()))
x.pop_back(); x.pop_back();
ps.code = ps.at_end() ? pec::success : pec::trailing_character; ps.code = ps.at_end() ? pec::success : pec::trailing_character;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment