| // 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 |