1#include "global.hpp"
2
3#include <filesystem>
4#include <glob.h>
5#include <iostream>
6#include <ranges>
7
8static std::vector<std::string> ExpandGlob(const std::string &pattern)
9{
10 glob_t globobj;
11 glob(pattern: pattern.c_str(), flags: 0, errfunc: nullptr, pglob: &globobj);
12
13 std::vector<std::string> paths;
14 for (size_t i = 0; i < globobj.gl_pathc; ++i)
15 paths.push_back(x: globobj.gl_pathv[i]);
16
17 globfree(pglog: &globobj);
18 return paths;
19}
20
21static std::vector<std::string> ExpandIncludePaths(const toml::node_view<toml::node> &node)
22{
23 std::vector<std::string> includes;
24 if (node.is_array())
25 {
26 if (!node.is_homogeneous())
27 std::cerr << "non-string elements in include array, they will be ignored" << std::endl;
28
29 includes = *node.as_array() | //
30 std::views::filter([](const auto &v) { return v.is_string(); }) | //
31 std::views::transform([](const auto &v) { return **v.as_string(); }) | //
32 std::ranges::to<std::vector>();
33 }
34 else if (node.is_string())
35 {
36 includes.push_back(x: node.as_string()->get());
37 }
38 else
39 {
40 std::cerr << "bad include paths, expect string or array but got " << node.type() << std::endl;
41 }
42
43 return includes | std::views::transform(ExpandGlob) | std::views::join | std::ranges::to<std::vector>();
44}
45
46std::vector<toml::table> ReadAllConfig(const std::filesystem::path &config_path)
47{
48 std::vector<toml::table> tables;
49
50 auto mainTable = toml::parse_file(file_path: config_path.string());
51
52 const auto old_path = std::filesystem::current_path();
53 std::filesystem::current_path(p: config_path.parent_path());
54
55 const auto includes = ExpandIncludePaths(node: mainTable["include"]);
56 mainTable.erase(key: "include");
57
58 tables.push_back(x: std::move(mainTable));
59 for (const auto &inc : includes)
60 tables.push_back(x: toml::parse_file(file_path: inc));
61 std::filesystem::current_path(p: old_path);
62
63 return tables;
64}
65