master
h 224 lines 7.42 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft Corporation. All rights reserved
4
5 Parses .gitconfig-style properties files.
6
7 --*/
8
9 #pragma once
10
11 #include <stdio.h>
12 #include <string>
13 #include <functional>
14 #include <map>
15 #include <optional>
16 #include <vector>
17 #include "stringshared.h"
18 #include "Localization.h"
19
20 #ifdef WIN32
21
22 #include <filesystem>
23 #include "wslservice.h"
24 #include "ExecutionContext.h"
25
26 #endif
27
28 struct MemoryString
29 {
30 MemoryString(uint64_t& value) : m_value(value) {};
31 uint64_t& m_value;
32 };
33
34 enum class ConfigKeyPresence
35 {
36 Absent,
37 Present
38 };
39
40 class ConfigKey
41 {
42 public:
43 using TParseMethod = std::function<void(const char*, const char*, const wchar_t*, unsigned long)>;
44 using TGetValueMethod = std::function<std::wstring()>;
45
46 template <typename TType>
47 inline ConfigKey(std::vector<const char*>&& names, TType& outValue, ConfigKeyPresence* presence = nullptr) :
48 m_names(std::move(names))
49 {
50 m_parse = [presence = presence, &outValue](const char* name, const char* value, const wchar_t* filename, unsigned long line) {
51 if (ParseImpl(name, value, filename, line, outValue) && presence != nullptr)
52 {
53 *presence = ConfigKeyPresence::Present;
54 }
55 };
56
57 m_getValue = [&outValue]() { return GetValueImpl(outValue); };
58 }
59
60 template <typename TType>
61 inline ConfigKey(const char* name, TType& value, ConfigKeyPresence* presence = nullptr) :
62 ConfigKey(std::vector<const char*>{name}, value, presence)
63 {
64 }
65
66 inline ConfigKey(const char* name, MemoryString outValue, ConfigKeyPresence* presence = nullptr) :
67 m_names(std::vector<const char*>{name})
68 {
69 m_parse = [presence = presence, outValue = outValue](const char* name, const char* value, const wchar_t* filename, unsigned long line) {
70 if (ParseImpl(name, value, filename, line, outValue) && presence != nullptr)
71 {
72 *presence = ConfigKeyPresence::Present;
73 }
74 };
75
76 m_getValue = [outValue = outValue]() { return GetValueImpl(outValue); };
77 }
78
79 inline ConfigKey(const char* name, TParseMethod&& parse) : m_names({name}), m_parse(std::move(parse))
80 {
81 }
82
83 template <typename TEnum>
84 inline ConfigKey(
85 std::vector<const char*>&& names,
86 const std::map<std::string, TEnum, wsl::shared::string::CaseInsensitiveCompare>& values,
87 TEnum& outValue,
88 ConfigKeyPresence* presence = nullptr) :
89 m_names(std::move(names))
90 {
91 m_parse = [presence = presence, values = values, &outValue](
92 const char* name, const char* value, const wchar_t* filename, unsigned long line) {
93 auto result = ParseEnumString(values, value, name, filename, line);
94 if (result.has_value())
95 {
96 outValue = result.value();
97 if (presence != nullptr)
98 {
99 *presence = ConfigKeyPresence::Present;
100 }
101 }
102 };
103
104 m_getValue = [&values, &outValue]() { return GetEnumString(values, outValue); };
105 }
106
107 template <typename TEnum>
108 inline ConfigKey(
109 const char* name,
110 const std::map<std::string, TEnum, wsl::shared::string::CaseInsensitiveCompare>& values,
111 TEnum& outValue,
112 ConfigKeyPresence* presence = nullptr) :
113 ConfigKey(std::vector<const char*>{name}, values, outValue, presence)
114 {
115 }
116
117 bool Matches(const char* name) const;
118 bool Matches(const char* name, size_t length) const;
119 void Parse(const char* name, const char* value, const wchar_t* fileName, unsigned long line);
120 const std::vector<const char*>& GetNames() const;
121 std::wstring GetValue() const;
122
123 template <typename TEnum>
124 static inline std::optional<TEnum> ParseEnumString(
125 const std::map<std::string, TEnum, wsl::shared::string::CaseInsensitiveCompare>& mappings,
126 const char* value,
127 const char* name,
128 const wchar_t* fileName,
129 unsigned long line)
130 {
131 auto it = mappings.find(value);
132 if (it == mappings.end())
133 {
134 std::stringstream validValues;
135 bool first = true;
136 for (const auto& e : mappings)
137 {
138 if (!first)
139 {
140 validValues << ", ";
141 }
142
143 first = false;
144 validValues << e.first;
145 }
146
147 EMIT_USER_WARNING(wsl::shared::Localization::MessageConfigInvalidEnum(value, name, fileName, line, validValues.str().c_str()));
148 return {};
149 }
150
151 return it->second;
152 }
153
154 template <typename TEnum>
155 static std::wstring GetEnumString(const std::map<std::string, TEnum, wsl::shared::string::CaseInsensitiveCompare>& mappings, TEnum& value)
156 {
157 auto it = mappings.begin();
158 for (; it != mappings.end(); ++it)
159 {
160 if (it->second == value)
161 {
162 break;
163 }
164 }
165
166 return it == mappings.end() ? L"" : wsl::shared::string::MultiByteToWide(it->first);
167 }
168
169 private:
170 static bool ParseImpl(const char* name, const char* value, const wchar_t* filePath, unsigned long fileLine, bool& result);
171 static bool ParseImpl(const char* name, const char* value, const wchar_t* filePath, unsigned long fileLine, int& result);
172 static bool ParseImpl(const char* name, const char* value, const wchar_t* filePath, unsigned long fileLine, std::string& result);
173 static bool ParseImpl(const char* name, const char* value, const wchar_t* filePath, unsigned long fileLine, MemoryString result);
174 static bool ParseImpl(const char* name, const char* value, const wchar_t* filePath, unsigned long fileLine, std::wstring& result);
175 static bool ParseImpl(const char* name, const char* value, const wchar_t* filePath, unsigned long fileLine, std::filesystem::path& result);
176
177 static std::wstring GetValueImpl(bool result);
178 static std::wstring GetValueImpl(int result);
179 static std::wstring GetValueImpl(const std::string& result);
180 static std::wstring GetValueImpl(const std::optional<std::string>& result);
181 static std::wstring GetValueImpl(const MemoryString& result);
182 static std::wstring GetValueImpl(const std::wstring& result);
183
184 #ifdef WIN32
185 static bool ParseImpl(const char* name, const char* value, const wchar_t* filePath, unsigned long fileLine, wsl::shared::string::MacAddress& result);
186 static std::wstring GetValueImpl(const wsl::shared::string::MacAddress& result);
187 #endif
188
189 template <typename T>
190 static inline bool ParseImpl(const char* name, const char* value, const wchar_t* filePath, unsigned long fileLine, std::optional<T>& result)
191 {
192 T storage{};
193
194 if (ParseImpl(name, value, filePath, fileLine, storage))
195 {
196 result.emplace(std::move(storage));
197 return true;
198 }
199
200 return false;
201 }
202
203 std::vector<const char*> m_names;
204 TParseMethod m_parse;
205 TGetValueMethod m_getValue;
206 std::optional<std::pair<std::string, unsigned long>> m_parseResult;
207 };
208
209 enum
210 {
211 CFG_SKIP_INVALID_LINES = 0x1,
212 CFG_SKIP_UNKNOWN_VALUES = 0x2,
213 CFG_DEBUG = 0x80000000,
214 };
215
216 int ParseConfigFile(std::vector<ConfigKey>& keys, FILE* file, int flags, const wchar_t* filePath);
217 int ParseConfigFile(
218 std::vector<ConfigKey>& keys,
219 FILE* file,
220 int flags,
221 const wchar_t* filePath,
222 std::wstring& configFileOutput,
223 std::optional<ConfigKey> outputKey = std::nullopt,
224 bool removeKey = false);