Skip to content

Commit 890fe69

Browse files
committed
Implement escape character support in OptionStringContainer::from_string
The parsing logic in `from_string` has been rewritten to handle the escape character (`\`).
1 parent d7e1192 commit 890fe69

File tree

1 file changed

+44
-20
lines changed

1 file changed

+44
-20
lines changed

libdnf5/conf/option_string_list.cpp

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <map>
2727
#include <optional>
2828
#include <regex>
29+
#include <string_view>
2930

3031
namespace libdnf5 {
3132

@@ -197,32 +198,55 @@ void OptionStringContainer<T, IsAppend>::test(const ValueType & value) const {
197198
}
198199
}
199200

200-
// Since strtok_r modifies its str input we copy `value` param
201201
template <typename T, bool IsAppend>
202202
T OptionStringContainer<T, IsAppend>::from_string(std::string value) const {
203203
ValueType tmp;
204-
char * str = nullptr;
205-
char * token = nullptr;
206-
char * saveptr = nullptr;
207-
208-
// If the first token in the string is empty (we start with a delimiter) it's
209-
// a special case, it can be used to clear existing content of the option.
210-
auto start = value.find_first_not_of(' ');
211-
if (start != std::string::npos && strchr(get_delimiters(), value[start]) != nullptr) {
212-
tmp.insert(tmp.end(), "");
213-
}
214204

215-
for (str = value.data();; str = nullptr) {
216-
token = strtok_r(str, get_delimiters(), &saveptr);
217-
if (token == nullptr) {
218-
break;
205+
const std::string_view delimiters{get_delimiters()};
206+
bool first_item_empty = true; // Flag to handle the case of an empty first item (string starts with a delimiter)
207+
bool escape = false;
208+
const auto end_it = value.end();
209+
std::string item;
210+
for (auto it = value.begin(); it != end_it; ++it) {
211+
if (escape) {
212+
escape = false;
213+
item += *it;
214+
if (*it != ' ') {
215+
first_item_empty = false;
216+
}
217+
continue;
218+
}
219+
if (*it == '\\') {
220+
escape = true;
221+
continue;
222+
}
223+
if (delimiters.find(*it) == delimiters.npos) {
224+
item += *it;
225+
if (*it != ' ') {
226+
first_item_empty = false;
227+
}
228+
continue;
219229
}
220-
std::string token_str(token);
221-
// Since deliemeters don't have to include space, we have to trim the token
222-
utils::string::trim(token_str);
223-
if (!token_str.empty()) {
224-
tmp.insert(tmp.end(), std::move(token_str));
230+
231+
utils::string::trim(item);
232+
if (item.empty()) {
233+
if (first_item_empty && *it != ' ') {
234+
first_item_empty = false;
235+
// If the first item in the string is empty (we start with a delimiter) it's
236+
// a special case, it can be used to clear existing content of the option.
237+
tmp.insert(tmp.end(), "");
238+
}
239+
continue;
225240
}
241+
tmp.insert(tmp.end(), item);
242+
243+
item.clear();
244+
}
245+
246+
// If the final token is not empty, insert it into the container.
247+
utils::string::trim(item);
248+
if (!item.empty()) {
249+
tmp.insert(tmp.end(), item);
226250
}
227251

228252
return tmp;

0 commit comments

Comments
 (0)