blob: 13305d9ff0d22cff863ff274db544a826a760357 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include "lib/cmdline.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <zircon/assert.h>
Cmdline gCmdline;
void Cmdline::Append(const char* str) {
if (str == nullptr || *str == 0) {
return;
}
bool found_equal = false;
for (;;) {
unsigned c = *str++;
if (c == 0) {
// Finish an in-progress argument.
if (length_ > 0 && data_[length_ - 1] != 0) {
if (!found_equal) {
AddOrAbort('=');
}
// Terminate the string.
AddOrAbort(0);
}
break;
}
if (c == '=') {
found_equal = true;
} else if ((c < ' ') || (c > 127)) {
// It's a special character of some kind.
if ((c == '\n') || (c == '\r') || (c == '\t')) {
c = ' ';
} else {
c = '.';
}
}
if (c == ' ') {
// Spaces become \0's, but do not double up.
if (length_ == 0 || (data_[length_ - 1] == 0)) {
// No need to add another terminator, so loop back to the start.
continue;
}
if (!found_equal) {
AddOrAbort('=');
} else {
found_equal = false;
}
// Add the terminator.
AddOrAbort(0);
continue;
}
AddOrAbort(static_cast<char>(c));
}
}
const char* Cmdline::GetString(const char* key) const {
if (!key) {
return data_;
}
const size_t sz = strlen(key);
if (sz == 0) {
return nullptr;
}
if (length_ == 0) {
return nullptr;
}
// Start at the end and work backwards so that repeated values appended later
// to the command line override earlier settings.
const char* ptr = data_ + length_;
for (;;) {
// At the top of the loop, we're always at the first character of the item
// *after* the one we're going to search next. This is, pointing at the
// character one beyond the \0 of the string to be considered next. On the
// first time through the loop, we'll be pointing at the extra \0 that
// terminates the whole buffer.
--ptr; // Step back to the \0 of the previous item.
--ptr; // Step back to the last character of the previous item.
if (ptr < data_) {
// If beyond the beginning of the data, the key was not found.
return nullptr;
}
// Walk backwards either to the terminator of the item preceding the one
// we're on, or to the beginning of the buffer.
while (ptr > data_ && *ptr != 0) {
--ptr;
}
// If not at the first character of the buffer, then increment back past the
// terminator of the previous item to the first character of the string.
if (ptr != data_) {
++ptr;
}
if (!strncmp(ptr, key, sz) && ptr[sz] == '=') {
break;
}
}
ptr += sz;
ptr++; // Increment past the '='.
return ptr;
}
bool Cmdline::GetBool(const char* key, bool default_value) const {
const char* value = GetString(key);
if (value == nullptr) {
return default_value;
}
if ((strcmp(value, "0") == 0) || (strcmp(value, "false") == 0) || (strcmp(value, "off") == 0)) {
return false;
}
return true;
}
uint64_t Cmdline::GetUInt64(const char* key, uint64_t default_value) const {
const char* value_str = GetString(key);
if (value_str == nullptr || *value_str == '\0') {
return default_value;
}
char* end;
static_assert(sizeof(unsigned long int) == sizeof(uint64_t));
uint64_t value = strtol(value_str, &end, 0);
if (*end != '\0') {
return default_value;
}
return value;
}
uint32_t Cmdline::GetUInt32(const char* key, uint32_t default_value) const {
return static_cast<uint32_t>(Cmdline::GetUInt64(key, default_value));
}
size_t Cmdline::size() const {
return length_ + 1;
}
void Cmdline::AddOrAbort(char c) {
if (length_ < kCmdlineMax - 1) {
data_[length_++] = c;
} else {
ZX_PANIC("cmdline overflow");
}
}