-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathutil.h
221 lines (186 loc) · 5.69 KB
/
util.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
// Copyright (c) 2022, Eugene Gershnik
// SPDX-License-Identifier: BSD-3-Clause
#ifndef HEADER_UTIL_H_INCLUDED
#define HEADER_UTIL_H_INCLUDED
/*
Portable utilities
*/
enum AllowedAddressFamily {
BothIPv4AndIPv6,
IPv4Only,
IPv6Only
};
struct WindowsDomain {
template<class... Args>
WindowsDomain(Args && ...args): name(std::forward<Args>(args)...) {}
sys_string name;
};
struct WindowsWorkgroup {
template<class... Args>
WindowsWorkgroup(Args && ...args): name(std::forward<Args>(args)...) {}
sys_string name;
};
using MemberOf = std::variant<WindowsWorkgroup, WindowsDomain>;
enum class DaemonType {
Unix
#if HAVE_SYSTEMD
, Systemd
#endif
#if HAVE_LAUNCHD
, Launchd
#endif
};
struct NetworkInterface {
NetworkInterface(int idx, const char * first, const char * last):
name(first, last),
index(idx) {
}
NetworkInterface(int idx, const sys_string & n):
name(n),
index(idx) {
}
friend auto operator<=>(const NetworkInterface & lhs, const NetworkInterface & rhs) -> std::strong_ordering {
if (auto res = lhs.name <=> rhs.name; res != 0)
return res;
return lhs.index <=> rhs.index;
}
friend auto operator==(const NetworkInterface & lhs, const NetworkInterface & rhs) -> bool {
return lhs.name == rhs.name && lhs.index == rhs.index;
}
friend auto operator!=(const NetworkInterface & lhs, const NetworkInterface & rhs) -> bool {
return !(lhs == rhs);
}
sys_string name;
int index;
};
template <> struct fmt::formatter<NetworkInterface> {
constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin(), end = ctx.end();
if (it != end && *it != '}') throw format_error("invalid format");
return it;
}
template <typename FormatContext>
auto format(const NetworkInterface & iface, FormatContext & ctx) const -> decltype(ctx.out()) {
return fmt::format_to(ctx.out(), "{}(idx: {})", iface.name, iface.index);
}
};
template<class T>
class RefCountedContainerBuffer{
public:
RefCountedContainerBuffer(T && data):
m_dataPtr(refcnt_attach(new ref_counted_adapter<T>(std::move(data)))),
m_buffer(m_dataPtr->data(), m_dataPtr->size()) {
}
using value_type = asio::const_buffer;
using const_iterator = const asio::const_buffer *;
auto begin() const -> const_iterator { return &m_buffer; }
auto end() const -> const_iterator { return &m_buffer + 1; }
private:
refcnt_ptr<ref_counted_adapter<T>> m_dataPtr;
asio::const_buffer m_buffer;
};
class StdIoFileBase {
public:
FILE * get() const noexcept {
return m_fp;
}
operator bool() const noexcept {
return m_fp != nullptr;
}
protected:
StdIoFileBase(FILE * fp) : m_fp(fp) {}
StdIoFileBase(StdIoFileBase && src) noexcept {
m_fp = src.m_fp;
src.m_fp = nullptr;
}
StdIoFileBase(const StdIoFileBase &) = delete;
StdIoFileBase & operator=(const StdIoFileBase &) = delete;
StdIoFileBase & operator=(StdIoFileBase &&) = delete;
~StdIoFileBase() noexcept {}
FILE * m_fp;
};
class StdIoFile : public StdIoFileBase {
public:
StdIoFile(const char * path, const char * mode, std::error_code & ec) noexcept:
StdIoFileBase(fopen(path, mode)) {
if (!m_fp) {
int err = errno;
ec = std::make_error_code(static_cast<std::errc>(err));
}
}
StdIoFile(StdIoFile && src) noexcept = default;
auto operator=(StdIoFile && src) noexcept -> StdIoFile & {
this->~StdIoFile();
new (this) StdIoFile(std::move(src));
return *this;
}
~StdIoFile() noexcept {
if (m_fp)
fclose(m_fp);
}
};
class StdIoPipe : public StdIoFileBase {
public:
StdIoPipe(const char * command, const char * mode, std::error_code & ec):
StdIoFileBase(popen(command, mode)) {
if (!m_fp) {
int err = errno;
ec = std::make_error_code(static_cast<std::errc>(err));
}
}
StdIoPipe(StdIoPipe && src) noexcept = default;
auto operator=(StdIoPipe && src) noexcept -> StdIoPipe & {
this->~StdIoPipe();
new (this) StdIoPipe(std::move(src));
return *this;
}
~StdIoPipe() noexcept {
if (m_fp)
pclose(m_fp);
}
};
template<class Sink>
auto readLine(const StdIoFileBase & file, Sink sink) -> outcome::result<bool> {
for ( ; ; ) {
int res = fgetc(file.get());
if (res == EOF) {
if (ferror(file.get()))
return std::make_error_code(static_cast<std::errc>(errno));
return false;
}
auto c = char(res);
if (c == '\n')
break;
sink(c);
}
return true;
}
template<class Sink>
auto readAll(const StdIoFileBase & file, Sink sink) -> outcome::result<void> {
for ( ; ; ) {
int res = fgetc(file.get());
if (res == EOF) {
if (ferror(file.get()))
return std::make_error_code(static_cast<std::errc>(errno));
return outcome::success();
}
sink(char(res));
}
return outcome::success();
}
inline auto makeHttpUrl(const ip::tcp::endpoint & endp) -> sys_string {
auto addr = endp.address();
if (addr.is_v4()) {
return fmt::format("http://{0}:{1}", addr.to_string(), endp.port());
} else {
auto addr6 = addr.to_v6();
addr6.scope_id(0);
return fmt::format("http://[{0}]:{1}", addr6.to_string(), endp.port());
}
}
template<class T, class Arg>
constexpr decltype(auto) makeDependentOn(Arg && arg) {
return std::forward<Arg>(arg);
}
extern std::mt19937 g_Random;
#endif