Data.cxx 4.18 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2021 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "Data.hxx"
21 22
#include "Parser.hxx"
#include "fs/AllocatedPath.hxx"
23
#include "util/RuntimeError.hxx"
24
#include "util/StringAPI.hxx"
25

26 27
#include <stdlib.h>

28 29 30
void
ConfigData::Clear()
{
31 32
	for (auto &i : params)
		i.clear();
33

34 35
	for (auto &i : blocks)
		i.clear();
36
}
37

38 39 40 41
template<typename T>
gcc_pure
static auto
FindLast(const std::forward_list<T> &list)
42
{
43 44 45 46 47
	auto i = list.before_begin();
	while (std::next(i) != list.end())
		++i;
	return i;
}
48

49 50 51 52
template<typename T>
static auto
Append(std::forward_list<T> &list, T &&src)
{
53
	return list.emplace_after(FindLast(list), std::forward<T>(src));
54 55 56 57
}

void
ConfigData::AddParam(ConfigOption option,
58
		     ConfigParam &&param) noexcept
59
{
60
	Append(GetParamList(option), std::move(param));
61 62
}

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
const char *
ConfigData::GetString(ConfigOption option,
		      const char *default_value) const noexcept
{
	const auto *param = GetParam(option);
	if (param == nullptr)
		return default_value;

	return param->value.c_str();
}

AllocatedPath
ConfigData::GetPath(ConfigOption option) const
{
	const auto *param = GetParam(option);
	if (param == nullptr)
		return nullptr;

	return param->GetPath();
}

unsigned
ConfigData::GetUnsigned(ConfigOption option, unsigned default_value) const
{
87 88 89 90 91
	return With(option, [default_value](const char *s){
		return s != nullptr
			? ParseUnsigned(s)
			: default_value;
	});
92 93 94 95 96
}

unsigned
ConfigData::GetPositive(ConfigOption option, unsigned default_value) const
{
97 98 99 100 101
	return With(option, [default_value](const char *s){
		return s != nullptr
			? ParsePositive(s)
			: default_value;
	});
102 103
}

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
std::chrono::steady_clock::duration
ConfigData::GetUnsigned(ConfigOption option,
			std::chrono::steady_clock::duration default_value) const
{
	return With(option, [default_value](const char *s){
		if (s == nullptr)
			return default_value;

		auto value = ParseDuration(s);
		if (value < std::chrono::steady_clock::duration{})
			throw std::runtime_error("Value must not be negative");

		return value;
	});
}

std::chrono::steady_clock::duration
ConfigData::GetPositive(ConfigOption option,
			std::chrono::steady_clock::duration default_value) const
{
	return With(option, [default_value](const char *s){
		if (s == nullptr)
			return default_value;

		auto value = ParseDuration(s);
		if (value <= std::chrono::steady_clock::duration{})
			throw std::runtime_error("Value must be positive");

		return value;
	});
}

136 137 138
bool
ConfigData::GetBool(ConfigOption option, bool default_value) const
{
139 140 141 142 143
	return With(option, [default_value](const char *s){
		return s != nullptr
			? ParseBool(s)
			: default_value;
	});
144 145
}

146
ConfigBlock &
147
ConfigData::AddBlock(ConfigBlockOption option,
148
		     ConfigBlock &&block) noexcept
149
{
150
	return *Append(GetBlockList(option), std::move(block));
151 152
}

153 154
const ConfigBlock *
ConfigData::FindBlock(ConfigBlockOption option,
155
		      const char *key, const char *value) const
156
{
157 158
	for (const auto &block : GetBlockList(option)) {
		const char *value2 = block.GetBlockValue(key);
159
		if (value2 == nullptr)
160
			throw FormatRuntimeError("block without '%s' in line %d",
161
						 key, block.line);
162 163

		if (StringIsEqual(value2, value))
164
			return &block;
165 166 167 168
	}

	return nullptr;
}
169 170 171 172 173 174 175

ConfigBlock &
ConfigData::MakeBlock(ConfigBlockOption option,
		      const char *key, const char *value)
{
	auto *block = const_cast<ConfigBlock *>(FindBlock(option, key, value));
	if (block == nullptr) {
176 177
		ConfigBlock new_block;
		new_block.AddBlockParam(key, value);
178
		block = &AddBlock(option, std::move(new_block));
179 180 181 182
	}

	return *block;
}