mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-06 19:40:10 +02:00
49e696e42f
Happy new year!
161 lines
6.9 KiB
C++
161 lines
6.9 KiB
C++
// yabridge: a Wine plugin bridge
|
|
// Copyright (C) 2020-2024 Robbert van der Helm
|
|
//
|
|
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
|
|
|
#include "configuration.h"
|
|
|
|
#include <fnmatch.h>
|
|
#include <fstream>
|
|
|
|
#include "toml++.h"
|
|
#include "utils.h"
|
|
|
|
namespace fs = ghc::filesystem;
|
|
|
|
Configuration::Configuration() noexcept {}
|
|
|
|
Configuration::Configuration(const fs::path& config_path,
|
|
const fs::path& yabridge_path)
|
|
: Configuration() {
|
|
// Will throw a `toml::parse_error` if the file cannot be parsed. Better
|
|
// to throw here rather than failing silently since syntax errors would
|
|
// otherwise be impossible to spot. We'll also have to sort all tables by
|
|
// the location in the file since tomlplusplus internally uses ordered maps
|
|
// so otherwise we'll get the tables sorted by key instead.
|
|
toml::table table = toml::parse_file(config_path.string());
|
|
|
|
// This table stores its children in an ordered map and it will thus be
|
|
// sorted lexicographically. For our uses we want sections from the start of
|
|
// the file to have precedence over later sections, so we need to sort the
|
|
// tables by source location first.
|
|
std::vector<std::tuple<toml::key, toml::table>> sorted_tables{};
|
|
for (auto [pattern, node] : table) {
|
|
if (const toml::table* config = node.as_table()) {
|
|
sorted_tables.push_back(std::make_tuple(pattern, *config));
|
|
}
|
|
}
|
|
std::sort(sorted_tables.begin(), sorted_tables.end(),
|
|
[](const auto& a, const auto& b) {
|
|
const auto& [a_pattern, a_table] = a;
|
|
const auto& [b_pattern, b_table] = b;
|
|
|
|
return a_pattern.source().begin.line <
|
|
b_pattern.source().begin.line;
|
|
});
|
|
|
|
// This is the path of the current .so file relative to this `yabridge.toml`
|
|
// file
|
|
const fs::path relative_path =
|
|
yabridge_path.lexically_relative(config_path.parent_path());
|
|
for (const auto& [pattern, table] : sorted_tables) {
|
|
// First try to match the glob pattern, allow matching an entire
|
|
// directory for ease of use. If none of the patterns in the file match
|
|
// the plugin path then everything will be left at the defaults.
|
|
const std::string key(pattern.str());
|
|
if (fnmatch(key.c_str(), relative_path.c_str(),
|
|
FNM_PATHNAME | FNM_LEADING_DIR) != 0) {
|
|
continue;
|
|
}
|
|
|
|
matched_file = config_path;
|
|
matched_pattern = pattern;
|
|
|
|
// If the table is missing some fields then they will simply be left at
|
|
// their defaults. At this point I'd really wish C++ could do pattern
|
|
// matching.
|
|
for (const auto& [key, value] : table) {
|
|
if (key == "group") {
|
|
if (const auto parsed_value = value.as_string()) {
|
|
group = parsed_value->get();
|
|
} else {
|
|
invalid_options.emplace_back(key);
|
|
}
|
|
} else if (key == "disable_pipes") {
|
|
// This option can be either enabled or disable with a boolean,
|
|
// or it can be set to an absolute path
|
|
if (const auto parsed_value = value.as_boolean()) {
|
|
if (*parsed_value) {
|
|
disable_pipes = get_temporary_directory() /
|
|
"yabridge-plugin-output.log";
|
|
} else {
|
|
disable_pipes = std::nullopt;
|
|
}
|
|
} else if (const auto parsed_value = value.as_string()) {
|
|
disable_pipes = parsed_value->get();
|
|
} else {
|
|
invalid_options.emplace_back(key);
|
|
}
|
|
} else if (key == "editor_coordinate_hack") {
|
|
if (const auto parsed_value = value.as_boolean()) {
|
|
editor_coordinate_hack = parsed_value->get();
|
|
} else {
|
|
invalid_options.emplace_back(key);
|
|
}
|
|
} else if (key == "editor_disable_host_scaling") {
|
|
if (const auto parsed_value = value.as_boolean()) {
|
|
editor_disable_host_scaling = parsed_value->get();
|
|
} else {
|
|
invalid_options.emplace_back(key);
|
|
}
|
|
} else if (key == "editor_force_dnd") {
|
|
if (const auto parsed_value = value.as_boolean()) {
|
|
editor_force_dnd = parsed_value->get();
|
|
} else {
|
|
invalid_options.emplace_back(key);
|
|
}
|
|
} else if (key == "editor_xembed") {
|
|
if (const auto parsed_value = value.as_boolean()) {
|
|
editor_xembed = parsed_value->get();
|
|
} else {
|
|
invalid_options.emplace_back(key);
|
|
}
|
|
} else if (key == "frame_rate") {
|
|
if (const auto parsed_value = value.as_floating_point()) {
|
|
frame_rate = parsed_value->get();
|
|
} else if (const auto parsed_value = value.as_integer()) {
|
|
// For usability's sake we want to be a bit more lax than a
|
|
// normal TOML file would be and accept both floating point
|
|
// values and integers here
|
|
frame_rate = parsed_value->get();
|
|
} else {
|
|
invalid_options.emplace_back(key);
|
|
}
|
|
} else if (key == "hide_daw") {
|
|
if (const auto parsed_value = value.as_boolean()) {
|
|
hide_daw = parsed_value->get();
|
|
} else {
|
|
invalid_options.emplace_back(key);
|
|
}
|
|
} else if (key == "vst3_prefer_32bit") {
|
|
if (const auto parsed_value = value.as_boolean()) {
|
|
vst3_prefer_32bit = parsed_value->get();
|
|
} else {
|
|
invalid_options.emplace_back(key);
|
|
}
|
|
} else {
|
|
unknown_options.emplace_back(key);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::chrono::steady_clock::duration Configuration::event_loop_interval()
|
|
const noexcept {
|
|
return std::chrono::duration_cast<std::chrono::steady_clock::duration>(
|
|
std::chrono::milliseconds(1000) / frame_rate.value_or(60.0));
|
|
}
|