18 string::iterator f = s.begin();
19 string::iterator t = s.begin();
21 for (; f != s.end(); ++f, ++t) {
52 neu.reserve(s.length()*2+1);
54 for (string::iterator p = s.begin(); p != s.end(); ++p) {
55 if (*p ==
'\\' || strchr(to_escape, *p)) {
58 else if (*p ==
'\n') { neu = neu+
"\\n"; }
59 else if (*p ==
'\r') { neu = neu+
"\\r"; }
60 else if (*p ==
'\t') { neu = neu+
"\\t"; }
61 else { neu = neu+*p; }
75 while (!parse_error) {
76 size_t equal = configString.find(
'=', pos);
77 if (equal == string::npos)
break;
79 const char lookingAt = configString[equal+1];
80 if (lookingAt !=
'\'') {
81 parse_error =
GBS_global_string(
"expected quote \"'\" after \"=\", found \"%c\"", lookingAt);
84 size_t start = equal+2;
85 size_t end = configString.find(
'\'', start);
86 while (end != string::npos) {
87 if (configString[end-1] !=
'\\')
break;
88 if (configString[end-2] ==
'\\') {
91 while (bwd>=start && configString[bwd] ==
'\\') {
95 if ((escCount%2) == 0)
break;
98 end = configString.find(
'\'', end+1);
100 if (end == string::npos) {
101 parse_error =
"could not find matching quote \"'\"";
105 string config_name = configString.substr(pos, equal-pos);
106 string value = configString.substr(start, end-start);
108 parse_error = decode_escapes(value);
110 set_entry(config_name, value);
126 #define TEST_ESCAPE_ENCODING(plain,expected) do{ \
127 string encoded = plain; \
128 ConfigMapping::encode_escapes(encoded, "'"); \
129 TEST_EXPECT_EQUAL(encoded, expected); \
130 string decoded = encoded; \
131 TEST_EXPECT_NO_ERROR(ConfigMapping::decode_escapes(decoded)); \
132 TEST_EXPECT_EQUAL(decoded, plain); \
135 void TEST_configValueEscaping() {
136 TEST_ESCAPE_ENCODING(
"hello",
"hello");
138 TEST_ESCAPE_ENCODING(
"'hello'",
"\\'hello\\'");
139 TEST_ESCAPE_ENCODING(
"\"hello\"",
"\"hello\"");
142 TEST_ESCAPE_ENCODING(
"LINE\nNEXT",
"LINE\\nNEXT");
143 TEST_ESCAPE_ENCODING(
"1\t2\r3",
"1\\t2\\r3");
146 TEST_ESCAPE_ENCODING(
"hel\\lo",
"hel\\\\lo");
147 TEST_ESCAPE_ENCODING(
"\\hello",
"\\\\hello");
148 TEST_ESCAPE_ENCODING(
"hello\\",
"hello\\\\");
150 TEST_ESCAPE_ENCODING(
"hello\\'",
"hello\\\\\\'");
151 TEST_ESCAPE_ENCODING(
"\\'hello\\'",
"\\\\\\'hello\\\\\\'");
153 string invalidEncoding =
"xyz\\";
157 struct TestedConfig {
158 const char *configString;
160 const char *entryList;
162 struct ReinterpretedConfig {
163 const char *configString;
164 const char *reinterpreted;
166 struct FailingConfig {
167 const char *configString;
171 static TestedConfig testedCfg[] = {
173 {
"tag='value'", 1,
"tag" },
174 {
"321='1st';abc='2nd'", 2,
"321/abc" },
175 {
"t-ha t='2';t;hi/s='1'", 2,
"t-ha t,t;hi/s" },
176 {
"t'ag'='value'", 1,
"t'ag'" },
178 static FailingConfig failedCfg[] = {
179 {
"nix=;was='ia'",
"expected quote \"'\"" },
180 {
"tag=value",
"expected quote \"'\"" },
181 {
"hasto='match",
"could not find matching quote" },
183 static ReinterpretedConfig reinterpretCfg[] = {
185 {
"this='1';that='2'",
"that='2';this='1'" },
188 inline bool anyStringContains(
const CharPtrArray& strings,
char c) {
189 for (
int i = 0; strings[i]; ++i) {
190 if (strchr(strings[i], c)) {
196 static char autodetectSeparator(
const CharPtrArray& strings) {
197 const char *sep =
"/;,:|#*";
198 for (
int i = 0; sep[i]; ++i) {
199 if (!anyStringContains(strings, sep[i])) {
207 void TEST_ConfigMapping() {
208 for (
size_t c = 0; c<
ARRAY_ELEMS(testedCfg); ++c) {
209 const TestedConfig& CFG = testedCfg[c];
210 TEST_ANNOTATE(CFG.configString);
223 TEST_EXPECT_EQUAL_STRINGCOPY__NOERROREXPORTED(
GBT_join_strings(entries, autodetectSeparator(entries)), CFG.entryList);
229 const char *stored =
"tag='val';'qtag'='\\'qval\\''";
239 const char *storedAsValue =
"stored='tag=\\'val\\';\\'qtag\\'=\\'\\\\\\'qval\\\\\\'\\''";
250 unwrapped.delete_entry(
"stored");
259 const char *SLASHED =
"slashed\\";
274 for (
size_t c = 0; c<
ARRAY_ELEMS(reinterpretCfg); ++c) {
275 const ReinterpretedConfig& CFG = reinterpretCfg[c];
276 TEST_ANNOTATE(CFG.configString);
285 for (
size_t c = 0; c<
ARRAY_ELEMS(failedCfg); ++c) {
286 const FailingConfig& CFG = failedCfg[c];
287 TEST_ANNOTATE(CFG.configString);
void delete_entry(const char *entry)
return string(buffer, length)
const char * GBS_global_string(const char *templat,...)
#define ARRAY_ELEMS(array)
bool has_entry(const char *entry) const
static HelixNrInfo * start
std::string config_string() const
#define TEST_EXPECT(cond)
void get_entries(class ConstStrArray &to_array)
static void encode_escapes(std::string &s, const char *to_escape)
#define TEST_REJECT(cond)
static void error(const char *msg)
static GB_ERROR decode_escapes(std::string &s)
void set_entry(const std::string &entry, const std::string &value)
char * GBT_join_strings(const CharPtrArray &strings, char separator)
GB_ERROR parseFrom(const std::string &configString)
const char * get_entry(const char *entry) const
#define TEST_EXPECT_NO_ERROR(call)
#define TEST_EXPECT_ERROR_CONTAINS(call, part)
#define TEST_EXPECT_EQUAL(expr, want)
GB_write_int const char s