blob: 759bc53534c42a043c26d7ac0210b14506d59654 [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cmdline.h"
#include <ctype.h>
#include <algorithm>
#include <iterator>
namespace gigaboot {
bool Commandline::Add(const std::string_view key, const std::string_view val) {
if (key.size() > kCmdlineMaxArgSize || val.size() > kCmdlineMaxArgSize) {
return false;
}
auto entry = std::find_if(valid_entries_.begin(), valid_entries_.end(),
[&key](auto& e) { return e.key == key; });
if (entry != valid_entries_.end()) {
entry->val = val;
return true;
}
if (valid_entries_.size() == entries_.size()) {
// Entries array is full, can't append.
return false;
}
valid_entries_ = {entries_.begin(), valid_entries_.size() + 1};
valid_entries_.back() = {key, val};
return true;
}
const std::string_view Commandline::Get(const std::string_view key,
const std::string_view _default) {
auto entry = std::find_if(valid_entries_.begin(), valid_entries_.end(),
[&key](auto& e) { return e.key == key; });
return (entry == valid_entries_.end()) ? _default : entry->val;
}
bool Commandline::AppendItems(std::string_view cmdline) {
auto end = cmdline.cend();
auto pos = std::find_if_not(cmdline.cbegin(), end, isspace);
while (pos != end) {
auto key_end = std::find_if(pos, end, [](auto& c) { return c == '=' || isspace(c); });
std::string_view key(&(*pos), key_end - pos);
pos = key_end + 1;
bool res;
if (*key_end == '=') {
auto val_end = std::find_if(pos, end, isspace);
std::string_view val(&(*pos), val_end - pos);
pos = val_end;
res = Add(key, val);
} else {
res = Add(key);
}
if (!res) {
return res;
}
pos = std::find_if_not(pos, end, isspace);
}
return true;
}
zx::result<size_t> Commandline::ToString(cpp20::span<char> cmdline) {
auto pos = cmdline.begin();
for (const auto& entry : valid_entries_) {
// One char for a space, one for an =, one for a null terminator
if (pos + entry.key.size() + entry.val.size() + 1 + 1 + 1 > cmdline.end()) {
return zx::error(ZX_ERR_BUFFER_TOO_SMALL);
}
pos += entry.key.copy(&(*pos), entry.key.size());
if (!entry.val.empty()) {
*pos++ = '=';
pos += entry.val.copy(&(*pos), entry.val.size());
}
*pos++ = ' ';
}
// Remove the trailing space
if (pos != cmdline.begin()) {
--pos;
}
*pos = '\0';
return zx::ok(pos - cmdline.begin());
}
} // namespace gigaboot