]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
9f95a23c | 2 | // vim: ts=8 sw=2 smarttab ft=cpp |
7c673cae | 3 | |
1e59de90 | 4 | #pragma once |
7c673cae | 5 | |
31f18b77 | 6 | #include <errno.h> |
7c673cae FG |
7 | #include <stdlib.h> |
8 | #include <limits.h> | |
f67539c2 | 9 | #include <string_view> |
20effc67 TL |
10 | #include <string> |
11 | #include <stdexcept> | |
7c673cae | 12 | |
31f18b77 | 13 | #include <boost/container/small_vector.hpp> |
31f18b77 | 14 | |
7c673cae FG |
15 | struct ltstr_nocase |
16 | { | |
31f18b77 | 17 | bool operator()(const std::string& s1, const std::string& s2) const |
7c673cae FG |
18 | { |
19 | return strcasecmp(s1.c_str(), s2.c_str()) < 0; | |
20 | } | |
21 | }; | |
22 | ||
31f18b77 | 23 | static inline int stringcasecmp(const std::string& s1, const std::string& s2) |
7c673cae FG |
24 | { |
25 | return strcasecmp(s1.c_str(), s2.c_str()); | |
26 | } | |
27 | ||
31f18b77 | 28 | static inline int stringcasecmp(const std::string& s1, const char *s2) |
7c673cae FG |
29 | { |
30 | return strcasecmp(s1.c_str(), s2); | |
31 | } | |
32 | ||
31f18b77 | 33 | static inline int stringcasecmp(const std::string& s1, int ofs, int size, const std::string& s2) |
7c673cae FG |
34 | { |
35 | return strncasecmp(s1.c_str() + ofs, s2.c_str(), size); | |
36 | } | |
37 | ||
31f18b77 | 38 | static inline int stringtoll(const std::string& s, int64_t *val) |
7c673cae FG |
39 | { |
40 | char *end; | |
41 | ||
42 | long long result = strtoll(s.c_str(), &end, 10); | |
43 | if (result == LLONG_MAX) | |
44 | return -EINVAL; | |
45 | ||
46 | if (*end) | |
47 | return -EINVAL; | |
48 | ||
49 | *val = (int64_t)result; | |
50 | ||
51 | return 0; | |
52 | } | |
53 | ||
31f18b77 | 54 | static inline int stringtoull(const std::string& s, uint64_t *val) |
7c673cae FG |
55 | { |
56 | char *end; | |
57 | ||
58 | unsigned long long result = strtoull(s.c_str(), &end, 10); | |
59 | if (result == ULLONG_MAX) | |
60 | return -EINVAL; | |
61 | ||
62 | if (*end) | |
63 | return -EINVAL; | |
64 | ||
65 | *val = (uint64_t)result; | |
66 | ||
67 | return 0; | |
68 | } | |
69 | ||
31f18b77 | 70 | static inline int stringtol(const std::string& s, int32_t *val) |
7c673cae FG |
71 | { |
72 | char *end; | |
73 | ||
74 | long result = strtol(s.c_str(), &end, 10); | |
75 | if (result == LONG_MAX) | |
76 | return -EINVAL; | |
77 | ||
78 | if (*end) | |
79 | return -EINVAL; | |
80 | ||
81 | *val = (int32_t)result; | |
82 | ||
83 | return 0; | |
84 | } | |
85 | ||
31f18b77 | 86 | static inline int stringtoul(const std::string& s, uint32_t *val) |
7c673cae FG |
87 | { |
88 | char *end; | |
89 | ||
90 | unsigned long result = strtoul(s.c_str(), &end, 10); | |
91 | if (result == ULONG_MAX) | |
92 | return -EINVAL; | |
93 | ||
94 | if (*end) | |
95 | return -EINVAL; | |
96 | ||
97 | *val = (uint32_t)result; | |
98 | ||
99 | return 0; | |
100 | } | |
101 | ||
f67539c2 | 102 | /* A converter between std::string_view and null-terminated C-strings. |
31f18b77 FG |
103 | * It copies memory while trying to utilize the local memory instead of |
104 | * issuing dynamic allocations. */ | |
105 | template<std::size_t N = 128> | |
106 | static inline boost::container::small_vector<char, N> | |
f67539c2 | 107 | sview2cstr(const std::string_view& sv) |
31f18b77 FG |
108 | { |
109 | boost::container::small_vector<char, N> cstr; | |
110 | cstr.reserve(sv.size() + sizeof('\0')); | |
111 | ||
112 | cstr.assign(std::begin(sv), std::end(sv)); | |
113 | cstr.push_back('\0'); | |
114 | ||
115 | return cstr; | |
116 | } | |
117 | ||
118 | /* std::strlen() isn't guaranteed to be computable at compile-time. Although | |
119 | * newer GCCs actually do that, Clang doesn't. Please be aware this function | |
120 | * IS NOT A DROP-IN REPLACEMENT FOR STRLEN -- it returns a different result | |
121 | * for strings having \0 in the middle. */ | |
122 | template<size_t N> | |
123 | static inline constexpr size_t sarrlen(const char (&arr)[N]) { | |
124 | return N - 1; | |
125 | } | |
126 | ||
127 | namespace detail { | |
128 | ||
129 | // variadic sum() to add up string lengths for reserve() | |
130 | static inline constexpr size_t sum() { return 0; } | |
131 | template <typename... Args> | |
132 | constexpr size_t sum(size_t v, Args... args) { return v + sum(args...); } | |
133 | ||
134 | // traits for string_size() | |
135 | template <typename T> | |
136 | struct string_traits { | |
137 | static constexpr size_t size(const T& s) { return s.size(); } | |
138 | }; | |
139 | // specializations for char*/const char* use strlen() | |
140 | template <> | |
141 | struct string_traits<const char*> { | |
142 | static size_t size(const char* s) { return std::strlen(s); } | |
143 | }; | |
144 | template <> | |
145 | struct string_traits<char*> : string_traits<const char*> {}; | |
146 | // constexpr specializations for char[]/const char[] | |
147 | template <std::size_t N> | |
148 | struct string_traits<const char[N]> { | |
149 | static constexpr size_t size_(const char* s, size_t i) { | |
150 | return i < N ? (*(s + i) == '\0' ? i : size_(s, i + 1)) | |
151 | : throw std::invalid_argument("Unterminated string constant."); | |
152 | } | |
153 | static constexpr size_t size(const char(&s)[N]) { return size_(s, 0); } | |
154 | }; | |
155 | template <std::size_t N> | |
156 | struct string_traits<char[N]> : string_traits<const char[N]> {}; | |
157 | ||
158 | // helpers for string_cat_reserve() | |
159 | static inline void append_to(std::string& s) {} | |
160 | template <typename... Args> | |
f67539c2 | 161 | void append_to(std::string& s, const std::string_view& v, const Args&... args) |
31f18b77 FG |
162 | { |
163 | s.append(v.begin(), v.end()); | |
164 | append_to(s, args...); | |
165 | } | |
166 | ||
167 | // helpers for string_join_reserve() | |
f67539c2 | 168 | static inline void join_next(std::string& s, const std::string_view& d) {} |
31f18b77 | 169 | template <typename... Args> |
f67539c2 TL |
170 | void join_next(std::string& s, const std::string_view& d, |
171 | const std::string_view& v, const Args&... args) | |
31f18b77 FG |
172 | { |
173 | s.append(d.begin(), d.end()); | |
174 | s.append(v.begin(), v.end()); | |
175 | join_next(s, d, args...); | |
176 | } | |
177 | ||
f67539c2 | 178 | static inline void join(std::string& s, const std::string_view& d) {} |
31f18b77 | 179 | template <typename... Args> |
f67539c2 TL |
180 | void join(std::string& s, const std::string_view& d, |
181 | const std::string_view& v, const Args&... args) | |
31f18b77 FG |
182 | { |
183 | s.append(v.begin(), v.end()); | |
184 | join_next(s, d, args...); | |
185 | } | |
186 | ||
187 | } // namespace detail | |
188 | ||
189 | /// return the length of a c string, string literal, or string type | |
190 | template <typename T> | |
191 | constexpr size_t string_size(const T& s) | |
192 | { | |
193 | return detail::string_traits<T>::size(s); | |
194 | } | |
195 | ||
196 | /// concatenates the given string arguments, returning as a std::string that | |
197 | /// gets preallocated with reserve() | |
198 | template <typename... Args> | |
199 | std::string string_cat_reserve(const Args&... args) | |
200 | { | |
201 | size_t total_size = detail::sum(string_size(args)...); | |
202 | std::string result; | |
203 | result.reserve(total_size); | |
204 | detail::append_to(result, args...); | |
205 | return result; | |
206 | } | |
207 | ||
208 | /// joins the given string arguments with a delimiter, returning as a | |
209 | /// std::string that gets preallocated with reserve() | |
210 | template <typename... Args> | |
f67539c2 | 211 | std::string string_join_reserve(const std::string_view& delim, |
31f18b77 FG |
212 | const Args&... args) |
213 | { | |
214 | size_t delim_size = delim.size() * std::max<ssize_t>(0, sizeof...(args) - 1); | |
215 | size_t total_size = detail::sum(string_size(args)...) + delim_size; | |
216 | std::string result; | |
217 | result.reserve(total_size); | |
218 | detail::join(result, delim, args...); | |
219 | return result; | |
220 | } | |
221 | template <typename... Args> | |
222 | std::string string_join_reserve(char delim, const Args&... args) | |
223 | { | |
f67539c2 | 224 | return string_join_reserve(std::string_view{&delim, 1}, args...); |
31f18b77 FG |
225 | } |
226 | ||
d2e6a577 FG |
227 | |
228 | /// use case-insensitive comparison in match_wildcards() | |
229 | static constexpr uint32_t MATCH_CASE_INSENSITIVE = 0x01; | |
230 | ||
231 | /// attempt to match the given input string with the pattern, which may contain | |
232 | /// the wildcard characters * and ? | |
f67539c2 TL |
233 | extern bool match_wildcards(std::string_view pattern, |
234 | std::string_view input, | |
d2e6a577 | 235 | uint32_t flags = 0); |