/src/znc/include/znc/ZNCString.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2004-2025 ZNC, see the NOTICE file for details. |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #ifndef ZNCSTRING_H |
18 | | #define ZNCSTRING_H |
19 | | |
20 | | #include <znc/zncconfig.h> |
21 | | #include <map> |
22 | | #include <set> |
23 | | #include <string> |
24 | | #include <vector> |
25 | | #include <sstream> |
26 | | #include <sys/types.h> |
27 | | #include <initializer_list> |
28 | | |
29 | | #define _SQL(s) CString("'" + CString(s).Escape_n(CString::ESQL) + "'") |
30 | | #define _URL(s) CString(s).Escape_n(CString::EURL) |
31 | | #define _HTML(s) CString(s).Escape_n(CString::EHTML) |
32 | 0 | #define _NAMEDFMT(s) CString(s).Escape_n(CString::ENAMEDFMT) |
33 | | |
34 | | class CString; |
35 | | class MCString; |
36 | | |
37 | | typedef std::set<CString> SCString; |
38 | | typedef std::vector<CString> VCString; |
39 | | typedef std::vector<std::pair<CString, CString>> VPair; |
40 | | |
41 | | enum class CaseSensitivity { CaseInsensitive, CaseSensitive }; |
42 | | |
43 | | /** |
44 | | * @brief String class that is used inside ZNC. |
45 | | * |
46 | | * All strings that are used in ZNC and its modules should use instances of this |
47 | | * class. It provides helpful functions for parsing input like Token() and |
48 | | * Split(). |
49 | | */ |
50 | | class CString : public std::string { |
51 | | public: |
52 | | typedef enum { |
53 | | EASCII, |
54 | | EURL, |
55 | | EHTML, |
56 | | ESQL, |
57 | | ENAMEDFMT, |
58 | | EDEBUG, |
59 | | EMSGTAG, |
60 | | EHEXCOLON, |
61 | | } EEscape; |
62 | | |
63 | | static const CaseSensitivity CaseSensitive = CaseSensitivity::CaseSensitive; |
64 | | static const CaseSensitivity CaseInsensitive = |
65 | | CaseSensitivity::CaseInsensitive; |
66 | | |
67 | 0 | explicit CString(bool b) : std::string(b ? "true" : "false") {} |
68 | | explicit CString(char c); |
69 | | explicit CString(unsigned char c); |
70 | | explicit CString(short i); |
71 | | explicit CString(unsigned short i); |
72 | | explicit CString(int i); |
73 | | explicit CString(unsigned int i); |
74 | | explicit CString(long i); |
75 | | explicit CString(unsigned long i); |
76 | | explicit CString(long long i); |
77 | | explicit CString(unsigned long long i); |
78 | | explicit CString(double i, int precision = 2); |
79 | | explicit CString(float i, int precision = 2); |
80 | | |
81 | 3.19M | CString() : std::string() {} |
82 | 22.3k | CString(const char* c) : std::string(c) {} |
83 | 0 | CString(const char* c, size_t l) : std::string(c, l) {} |
84 | 9.13M | CString(const std::string& s) : std::string(s) {} |
85 | 0 | CString(size_t n, char c) : std::string(n, c) {} |
86 | 0 | CString(std::initializer_list<char> list) : std::string(list) {} |
87 | 0 | ~CString() {} |
88 | | |
89 | | /** |
90 | | * Casts a CString to another type. Implemented via std::stringstream, you use this |
91 | | * for any class that has an operator<<(std::ostream, YourClass). |
92 | | * @param target The object to cast into. If the cast fails, its state is unspecified. |
93 | | * @return True if the cast succeeds, and false if it fails. |
94 | | */ |
95 | | template <typename T> |
96 | | bool Convert(T* target) const { |
97 | | std::stringstream ss(*this); |
98 | | ss >> *target; |
99 | | return (bool)ss; // we don't care why it failed, only whether it failed |
100 | | } |
101 | | |
102 | | /** |
103 | | * Joins a collection of objects together, using 'this' as a delimiter. |
104 | | * You can pass either pointers to arrays, or iterators to collections. |
105 | | * @param i_begin An iterator pointing to the beginning of a group of objects. |
106 | | * @param i_end An iterator pointing past the end of a group of objects. |
107 | | * @return The joined string |
108 | | */ |
109 | | template <typename Iterator> |
110 | 0 | CString Join(Iterator i_start, const Iterator& i_end) const { |
111 | 0 | if (i_start == i_end) return CString(""); |
112 | 0 | std::ostringstream output; |
113 | 0 | output << *i_start; |
114 | 0 | while (true) { |
115 | 0 | ++i_start; |
116 | 0 | if (i_start == i_end) return CString(output.str()); |
117 | 0 | output << *this; |
118 | 0 | output << *i_start; |
119 | 0 | } |
120 | 0 | } Unexecuted instantiation: CString CString::Join<std::__1::__wrap_iter<CString*> >(std::__1::__wrap_iter<CString*>, std::__1::__wrap_iter<CString*> const&) const Unexecuted instantiation: CString CString::Join<std::__1::__tree_const_iterator<CString, std::__1::__tree_node<CString, void*>*, long> >(std::__1::__tree_const_iterator<CString, std::__1::__tree_node<CString, void*>*, long>, std::__1::__tree_const_iterator<CString, std::__1::__tree_node<CString, void*>*, long> const&) const Unexecuted instantiation: CString CString::Join<std::__1::__wrap_iter<CString const*> >(std::__1::__wrap_iter<CString const*>, std::__1::__wrap_iter<CString const*> const&) const |
121 | | |
122 | | /** |
123 | | * Compare this string caselessly to some other string. |
124 | | * @param s The string to compare to. |
125 | | * @param uLen The number of characters to compare. |
126 | | * @return An integer less than, equal to, or greater than zero if this |
127 | | * string smaller, equal.... to the given string. |
128 | | */ |
129 | | int CaseCmp(const CString& s, |
130 | | CString::size_type uLen = CString::npos) const; |
131 | | /** |
132 | | * Compare this string case sensitively to some other string. |
133 | | * @param s The string to compare to. |
134 | | * @param uLen The number of characters to compare. |
135 | | * @return An integer less than, equal to, or greater than zero if this |
136 | | * string smaller, equal.... to the given string. |
137 | | */ |
138 | | int StrCmp(const CString& s, CString::size_type uLen = CString::npos) const; |
139 | | /** |
140 | | * Check if this string is equal to some other string. |
141 | | * @param s The string to compare to. |
142 | | * @param cs CaseSensitive if you want the comparison to be case |
143 | | * sensitive, CaseInsensitive (default) otherwise. |
144 | | * @return True if the strings are equal. |
145 | | */ |
146 | | bool Equals(const CString& s, CaseSensitivity cs = CaseInsensitive) const; |
147 | | /** |
148 | | * @deprecated |
149 | | */ |
150 | | bool Equals(const CString& s, bool bCaseSensitive, |
151 | | CString::size_type uLen = CString::npos) const; |
152 | | /** |
153 | | * Do a wildcard comparison between two strings. |
154 | | * For example, the following returns true: |
155 | | * <code>WildCmp("*!?bar@foo", "I_am!~bar@foo");</code> |
156 | | * @param sWild The wildcards used for the comparison. |
157 | | * @param sString The string that is used for comparing. |
158 | | * @param cs CaseSensitive (default) if you want the comparison |
159 | | * to be case sensitive, CaseInsensitive otherwise. |
160 | | * @todo Make cs CaseInsensitive by default. |
161 | | * @return true if the wildcard matches. |
162 | | */ |
163 | | static bool WildCmp(const CString& sWild, const CString& sString, |
164 | | CaseSensitivity cs = CaseSensitive); |
165 | | /** |
166 | | * Do a wild compare on this string. |
167 | | * @param sWild The wildcards used to for the comparison. |
168 | | * @param cs CaseSensitive (default) if you want the comparison |
169 | | * to be case sensitive, CaseInsensitive otherwise. |
170 | | * @todo Make cs CaseInsensitive by default. |
171 | | * @return The result of <code>this->WildCmp(sWild, *this);</code>. |
172 | | */ |
173 | | bool WildCmp(const CString& sWild, |
174 | | CaseSensitivity cs = CaseSensitive) const; |
175 | | |
176 | | /** |
177 | | * Turn all characters in this string into their upper-case equivalent. |
178 | | * @returns A reference to *this. |
179 | | */ |
180 | | CString& MakeUpper(); |
181 | | /** |
182 | | * Turn all characters in this string into their lower-case equivalent. |
183 | | * @returns A reference to *this. |
184 | | */ |
185 | | CString& MakeLower(); |
186 | | /** |
187 | | * Return a copy of this string with all characters turned into |
188 | | * upper-case. |
189 | | * @return The new string. |
190 | | */ |
191 | | CString AsUpper() const; |
192 | | /** |
193 | | * Return a copy of this string with all characters turned into |
194 | | * lower-case. |
195 | | * @return The new string. |
196 | | */ |
197 | | CString AsLower() const; |
198 | | |
199 | | static EEscape ToEscape(const CString& sEsc); |
200 | | CString Escape_n(EEscape eFrom, EEscape eTo) const; |
201 | | CString Escape_n(EEscape eTo) const; |
202 | | CString& Escape(EEscape eFrom, EEscape eTo); |
203 | | CString& Escape(EEscape eTo); |
204 | | |
205 | | /** Replace all occurrences in a string. |
206 | | * |
207 | | * You can specify a "safe zone" via sLeft and sRight. Anything inside |
208 | | * of such a zone will not be replaced. This does not do recursion, so |
209 | | * e.g. with <code>Replace("(a()a)", "a", "b", "(", ")", true)</code> |
210 | | * you would get "a(b)" as result. The second opening brace and the |
211 | | * second closing brace would not be seen as a delimitered and thus |
212 | | * wouldn't be removed. The first a is inside a "safe zone" and thus is |
213 | | * left alone, too. |
214 | | * |
215 | | * @param sStr The string to do the replacing on. This will also contain |
216 | | * the result when this function returns. |
217 | | * @param sReplace The string that should be replaced. |
218 | | * @param sWith The replacement to use. |
219 | | * @param sLeft The string that marks the begin of the "safe zone". |
220 | | * @param sRight The string that marks the end of the "safe zone". |
221 | | * @param bRemoveDelims If this is true, all matches for sLeft and |
222 | | * sRight are removed. |
223 | | * @returns The number of replacements done. |
224 | | */ |
225 | | static unsigned int Replace(CString& sStr, const CString& sReplace, |
226 | | const CString& sWith, const CString& sLeft = "", |
227 | | const CString& sRight = "", |
228 | | bool bRemoveDelims = false); |
229 | | |
230 | | /** Replace all occurrences in the current string. |
231 | | * @see CString::Replace |
232 | | * @param sReplace The string to look for. |
233 | | * @param sWith The replacement to use. |
234 | | * @param sLeft The delimiter at the beginning of a safe zone. |
235 | | * @param sRight The delimiter at the end of a safe zone. |
236 | | * @param bRemoveDelims If true, all matching delimiters are removed. |
237 | | * @return The result of the replacing. The current string is left |
238 | | * unchanged. |
239 | | */ |
240 | | CString Replace_n(const CString& sReplace, const CString& sWith, |
241 | | const CString& sLeft = "", const CString& sRight = "", |
242 | | bool bRemoveDelims = false) const; |
243 | | /** Replace all occurrences in the current string. |
244 | | * @see CString::Replace |
245 | | * @param sReplace The string to look for. |
246 | | * @param sWith The replacement to use. |
247 | | * @param sLeft The delimiter at the beginning of a safe zone. |
248 | | * @param sRight The delimiter at the end of a safe zone. |
249 | | * @param bRemoveDelims If true, all matching delimiters are removed. |
250 | | * @returns The number of replacements done. |
251 | | */ |
252 | | unsigned int Replace(const CString& sReplace, const CString& sWith, |
253 | | const CString& sLeft = "", const CString& sRight = "", |
254 | | bool bRemoveDelims = false); |
255 | | /** Ellipsize the current string. |
256 | | * For example, ellipsizing "Hello, I'm Bob" to the length 9 would |
257 | | * result in "Hello,...". |
258 | | * @param uLen The length to ellipsize to. |
259 | | * @return The ellipsized string. |
260 | | */ |
261 | | CString Ellipsize(unsigned int uLen) const; |
262 | | /** Return the left part of the string. |
263 | | * @param uCount The number of characters to keep. |
264 | | * @return The resulting string. |
265 | | */ |
266 | | CString Left(size_type uCount) const; |
267 | | /** Return the right part of the string. |
268 | | * @param uCount The number of characters to keep. |
269 | | * @return The resulting string. |
270 | | */ |
271 | | CString Right(size_type uCount) const; |
272 | | |
273 | | /** Get the first line of this string. |
274 | | * @return The first line of text. |
275 | | */ |
276 | 0 | CString FirstLine() const { return Token(0, false, "\n"); } |
277 | | |
278 | | /** Get a token out of this string. For example in the string "a bc d e", |
279 | | * each of "a", "bc", "d" and "e" are tokens. |
280 | | * @param uPos The number of the token you are interested. The first |
281 | | * token has a position of 0. |
282 | | * @param bRest If false, only the token you asked for is returned. Else |
283 | | * you get the substring starting from the beginning of |
284 | | * your token. |
285 | | * @param sSep Seperator between tokens. |
286 | | * @param bAllowEmpty If this is true, empty tokens are allowed. In the |
287 | | * example from above this means that there is a |
288 | | * token "" before the "e" token. |
289 | | * @return The token you asked for and, if bRest is true, everything |
290 | | * after it. |
291 | | * @see Split() if you need a string split into all of its tokens. |
292 | | */ |
293 | | CString Token(size_t uPos, bool bRest = false, const CString& sSep = " ", |
294 | | bool bAllowEmpty = false) const; |
295 | | |
296 | | /** Get a token out of this string. This function behaves much like the |
297 | | * other Token() function in this class. The extra arguments are |
298 | | * handled similarly to Split(). |
299 | | */ |
300 | | CString Token(size_t uPos, bool bRest, const CString& sSep, |
301 | | bool bAllowEmpty, const CString& sLeft, const CString& sRight, |
302 | | bool bTrimQuotes = true) const; |
303 | | |
304 | | size_type URLSplit(MCString& msRet) const; |
305 | | size_type OptionSplit(MCString& msRet, bool bUpperKeys = false) const; |
306 | | size_type QuoteSplit(VCString& vsRet) const; |
307 | | |
308 | | /** Split up this string into tokens. |
309 | | * Via sLeft and sRight you can define "markers" like with Replace(). |
310 | | * Anything in such a marked section is treated as a single token. All |
311 | | * occurrences of sDelim in such a block are ignored. |
312 | | * @param sDelim Delimiter between tokens. |
313 | | * @param vsRet Vector for returning the result. |
314 | | * @param bAllowEmpty Do empty tokens count as a valid token? |
315 | | * @param sLeft Left delimiter like with Replace(). |
316 | | * @param sRight Right delimiter like with Replace(). |
317 | | * @param bTrimQuotes Should sLeft and sRight be removed from the token |
318 | | * they mark? |
319 | | * @param bTrimWhiteSpace If this is true, CString::Trim() is called on |
320 | | * each token. |
321 | | * @return The number of tokens found. |
322 | | */ |
323 | | size_type Split(const CString& sDelim, VCString& vsRet, |
324 | | bool bAllowEmpty = true, const CString& sLeft = "", |
325 | | const CString& sRight = "", bool bTrimQuotes = true, |
326 | | bool bTrimWhiteSpace = false) const; |
327 | | |
328 | | /** Split up this string into tokens. |
329 | | * This function is identical to the other CString::Split(), except that |
330 | | * the result is returned as a SCString instead of a VCString. |
331 | | */ |
332 | | size_type Split(const CString& sDelim, SCString& ssRet, |
333 | | bool bAllowEmpty = true, const CString& sLeft = "", |
334 | | const CString& sRight = "", bool bTrimQuotes = true, |
335 | | bool bTrimWhiteSpace = false) const; |
336 | | |
337 | | /** Build a string from a format string, replacing values from a map. |
338 | | * The format specification can contain simple named parameters that match |
339 | | * keys in the given map. For example in the string "a {b} c", the key "b" |
340 | | * is looked up in the map, and inserted for "{b}". |
341 | | * @param sFormat The format specification. |
342 | | * @param msValues A map of named parameters to their values. |
343 | | * @return The string with named parameters replaced. |
344 | | */ |
345 | | static CString NamedFormat(const CString& sFormat, |
346 | | const MCString& msValues); |
347 | | |
348 | | /** Produces a random string. |
349 | | * @param uLength The length of the resulting string. |
350 | | * @return A random string. |
351 | | */ |
352 | | static CString RandomString(unsigned int uLength); |
353 | | |
354 | | /** @return The MD5 hash of this string. */ |
355 | | CString MD5() const; |
356 | | /** @return The SHA256 hash of this string. */ |
357 | | CString SHA256() const; |
358 | | |
359 | | /** Treat this string as base64-encoded data and decode it. |
360 | | * @param sRet String to which the result of the decode is safed. |
361 | | * @return The length of the resulting string. |
362 | | */ |
363 | | unsigned long Base64Decode(CString& sRet) const; |
364 | | /** Treat this string as base64-encoded data and decode it. |
365 | | * The result is saved in this CString instance. |
366 | | * @return The length of the resulting string. |
367 | | */ |
368 | | unsigned long Base64Decode(); |
369 | | /** Treat this string as base64-encoded data and decode it. |
370 | | * @return The decoded string. |
371 | | */ |
372 | | CString Base64Decode_n() const; |
373 | | /** Base64-encode the current string. |
374 | | * @param sRet String where the result is saved. |
375 | | * @param uWrap A boolean(!?!) that decides if the result should be |
376 | | * wrapped after everywhere 57 characters. |
377 | | * @return true unless this code is buggy. |
378 | | * @todo WTF @ uWrap. |
379 | | * @todo This only returns false if some formula we use was wrong?! |
380 | | */ |
381 | | bool Base64Encode(CString& sRet, unsigned int uWrap = 0) const; |
382 | | /** Base64-encode the current string. |
383 | | * This string is overwritten with the result of the encode. |
384 | | * @todo return value and param are as with Base64Encode() from above. |
385 | | */ |
386 | | bool Base64Encode(unsigned int uWrap = 0); |
387 | | /** Base64-encode the current string |
388 | | * @todo uWrap is as broken as Base64Encode()'s uWrap. |
389 | | * @return The encoded string. |
390 | | */ |
391 | | CString Base64Encode_n(unsigned int uWrap = 0) const; |
392 | | |
393 | | #ifdef HAVE_LIBSSL |
394 | | CString Encrypt_n(const CString& sPass, const CString& sIvec = "") const; |
395 | | CString Decrypt_n(const CString& sPass, const CString& sIvec = "") const; |
396 | | void Encrypt(const CString& sPass, const CString& sIvec = ""); |
397 | | void Decrypt(const CString& sPass, const CString& sIvec = ""); |
398 | | void Crypt(const CString& sPass, bool bEncrypt, const CString& sIvec = ""); |
399 | | #endif |
400 | | |
401 | | /** Pretty-print a percent value. |
402 | | * @param d The percent value. This should be in range 0-100. |
403 | | * @return The "pretty" string. |
404 | | */ |
405 | | static CString ToPercent(double d); |
406 | | /** Pretty-print a number of bytes. |
407 | | * @param d The number of bytes. |
408 | | * @return A string describing the number of bytes. |
409 | | */ |
410 | | static CString ToByteStr(unsigned long long d); |
411 | | /** Pretty-print a time span. |
412 | | * @param s Number of seconds to print. |
413 | | * @return A string like "4w 6d 4h 3m 58s". |
414 | | */ |
415 | | static CString ToTimeStr(unsigned long s); |
416 | | |
417 | | /** @return True if this string is not "false". */ |
418 | | bool ToBool() const; |
419 | | /** @return The numerical value of this string similar to atoi(). */ |
420 | | short ToShort() const; |
421 | | /** @return The numerical value of this string similar to atoi(). */ |
422 | | unsigned short ToUShort() const; |
423 | | /** @return The numerical value of this string similar to atoi(). */ |
424 | | int ToInt() const; |
425 | | /** @return The numerical value of this string similar to atoi(). */ |
426 | | long ToLong() const; |
427 | | /** @return The numerical value of this string similar to atoi(). */ |
428 | | unsigned int ToUInt() const; |
429 | | /** @return The numerical value of this string similar to atoi(). */ |
430 | | unsigned long ToULong() const; |
431 | | /** @return The numerical value of this string similar to atoi(). */ |
432 | | unsigned long long ToULongLong() const; |
433 | | /** @return The numerical value of this string similar to atoi(). */ |
434 | | long long ToLongLong() const; |
435 | | /** @return The numerical value of this string similar to atoi(). */ |
436 | | double ToDouble() const; |
437 | | |
438 | | /** Trim this string. All leading/trailing occurrences of characters from |
439 | | * s are removed. |
440 | | * @param s A list of characters that should be trimmed. |
441 | | * @return true if this string was modified. |
442 | | */ |
443 | | bool Trim(const CString& s = " \t\r\n"); |
444 | | /** Trim this string. All leading occurrences of characters from s are |
445 | | * removed. |
446 | | * @param s A list of characters that should be trimmed. |
447 | | * @return true if this string was modified. |
448 | | */ |
449 | | bool TrimLeft(const CString& s = " \t\r\n"); |
450 | | /** Trim this string. All trailing occurrences of characters from s are |
451 | | * removed. |
452 | | * @param s A list of characters that should be trimmed. |
453 | | * @return true if this string was modified. |
454 | | */ |
455 | | bool TrimRight(const CString& s = " \t\r\n"); |
456 | | /** Trim this string. All leading/trailing occurrences of characters from |
457 | | * s are removed. This CString instance is not modified. |
458 | | * @param s A list of characters that should be trimmed. |
459 | | * @return The trimmed string. |
460 | | */ |
461 | | CString Trim_n(const CString& s = " \t\r\n") const; |
462 | | /** Trim this string. All leading occurrences of characters from s are |
463 | | * removed. This CString instance is not modified. |
464 | | * @param s A list of characters that should be trimmed. |
465 | | * @return The trimmed string. |
466 | | */ |
467 | | CString TrimLeft_n(const CString& s = " \t\r\n") const; |
468 | | /** Trim this string. All trailing occurrences of characters from s are |
469 | | * removed. This CString instance is not modified. |
470 | | * @param s A list of characters that should be trimmed. |
471 | | * @return The trimmed string. |
472 | | */ |
473 | | CString TrimRight_n(const CString& s = " \t\r\n") const; |
474 | | |
475 | | /** Trim a given prefix. |
476 | | * @param sPrefix The prefix that should be removed. |
477 | | * @return True if this string was modified. |
478 | | */ |
479 | | bool TrimPrefix(const CString& sPrefix = ":"); |
480 | | /** Trim a given suffix. |
481 | | * @param sSuffix The suffix that should be removed. |
482 | | * @return True if this string was modified. |
483 | | */ |
484 | | bool TrimSuffix(const CString& sSuffix); |
485 | | /** Trim a given prefix. |
486 | | * @param sPrefix The prefix that should be removed. |
487 | | * @return A copy of this string without the prefix. |
488 | | */ |
489 | | CString TrimPrefix_n(const CString& sPrefix = ":") const; |
490 | | /** Trim a given suffix. |
491 | | * @param sSuffix The suffix that should be removed. |
492 | | * @return A copy of this string without the prefix. |
493 | | */ |
494 | | CString TrimSuffix_n(const CString& sSuffix) const; |
495 | | |
496 | | /** Find the position of the given substring. |
497 | | * @param s The substring to search for. |
498 | | * @param cs CaseSensitive if you want the comparison to be case |
499 | | * sensitive, CaseInsensitive (default) otherwise. |
500 | | * @return The position of the substring if found, CString::npos otherwise. |
501 | | */ |
502 | | size_t Find(const CString& s, CaseSensitivity cs = CaseInsensitive) const; |
503 | | /** Check whether the string starts with a given prefix. |
504 | | * @param sPrefix The prefix. |
505 | | * @param cs CaseSensitive if you want the comparison to be case |
506 | | * sensitive, CaseInsensitive (default) otherwise. |
507 | | * @return True if the string starts with prefix, false otherwise. |
508 | | */ |
509 | | bool StartsWith(const CString& sPrefix, |
510 | | CaseSensitivity cs = CaseInsensitive) const; |
511 | | /** Check whether the string ends with a given suffix. |
512 | | * @param sSuffix The suffix. |
513 | | * @param cs CaseSensitive if you want the comparison to be case |
514 | | * sensitive, CaseInsensitive (default) otherwise. |
515 | | * @return True if the string ends with suffix, false otherwise. |
516 | | */ |
517 | | bool EndsWith(const CString& sSuffix, |
518 | | CaseSensitivity cs = CaseInsensitive) const; |
519 | | /** |
520 | | * Check whether the string contains a given string. |
521 | | * @param s The string to search. |
522 | | * @param bCaseSensitive Whether the search is case sensitive. |
523 | | * @return True if this string contains the other string, falser otherwise. |
524 | | */ |
525 | | bool Contains(const CString& s, CaseSensitivity cs = CaseInsensitive) const; |
526 | | |
527 | | /** Remove characters from the beginning of this string. |
528 | | * @param uLen The number of characters to remove. |
529 | | * @return true if this string was modified. |
530 | | */ |
531 | | bool LeftChomp(size_type uLen = 1); |
532 | | /** Remove characters from the end of this string. |
533 | | * @param uLen The number of characters to remove. |
534 | | * @return true if this string was modified. |
535 | | */ |
536 | | bool RightChomp(size_type uLen = 1); |
537 | | /** Remove characters from the beginning of this string. |
538 | | * This string object isn't modified. |
539 | | * @param uLen The number of characters to remove. |
540 | | * @return The result of the conversion. |
541 | | */ |
542 | | CString LeftChomp_n(size_type uLen = 1) const; |
543 | | /** Remove characters from the end of this string. |
544 | | * This string object isn't modified. |
545 | | * @param uLen The number of characters to remove. |
546 | | * @return The result of the conversion. |
547 | | */ |
548 | | CString RightChomp_n(size_type uLen = 1) const; |
549 | | /** Remove controls characters from this string. |
550 | | * Controls characters are color codes, and those in C0 set |
551 | | * See https://en.wikipedia.org/wiki/C0_and_C1_control_codes |
552 | | * @return The result of the conversion. |
553 | | */ |
554 | | CString& StripControls(); |
555 | | /** Remove controls characters from this string. |
556 | | * Controls characters are color codes, and those in C0 set |
557 | | * See https://en.wikipedia.org/wiki/C0_and_C1_control_codes |
558 | | * This string object isn't modified. |
559 | | * @return The result of the conversion. |
560 | | */ |
561 | | CString StripControls_n() const; |
562 | | |
563 | | private: |
564 | | protected: |
565 | | unsigned char* strnchr(const unsigned char* src, unsigned char c, |
566 | | unsigned int iMaxBytes, |
567 | | unsigned char* pFill = nullptr, |
568 | | unsigned int* piCount = nullptr) const; |
569 | | }; |
570 | | |
571 | | /** |
572 | | * @brief A dictionary for strings. |
573 | | * @todo Replace with "using MCString = std::map<CString, CString>;" in ZNC 2.0 |
574 | | * |
575 | | * This class maps strings to other strings. |
576 | | */ |
577 | | class MCString : public std::map<CString, CString> { |
578 | | public: |
579 | | /** Construct an empty MCString. */ |
580 | 2.14k | MCString() : std::map<CString, CString>() {} |
581 | | /** Construct a MCString using an initializer list eg. MCString m = { {"key1", "val1"}, {"key2", "val2"} }; */ |
582 | | MCString(std::initializer_list<std::pair<const CString, CString>> list) |
583 | 0 | : std::map<CString, CString>(list) {} |
584 | | /** Destruct this MCString. */ |
585 | 2.14k | virtual ~MCString() { clear(); } |
586 | | |
587 | | /** A static instance of an empty map. */ |
588 | | static const MCString EmptyMap; |
589 | | |
590 | | /** Status codes that can be returned by WriteToDisk() and |
591 | | * ReadFromDisk(). */ |
592 | | enum status_t { |
593 | | /// No errors. |
594 | | MCS_SUCCESS = 0, |
595 | | /// Opening the file failed. |
596 | | MCS_EOPEN = 1, |
597 | | /// Writing to the file failed. |
598 | | MCS_EWRITE = 2, |
599 | | /// WriteFilter() failed. |
600 | | MCS_EWRITEFIL = 3, |
601 | | /// ReadFilter() failed. |
602 | | MCS_EREADFIL = 4 |
603 | | }; |
604 | | |
605 | | /** Write this map to a file. |
606 | | * @param sPath The file name to write to. |
607 | | * @param iMode The mode for the file. |
608 | | * @return The result of the operation. |
609 | | * @see WriteFilter. |
610 | | */ |
611 | | enum status_t WriteToDisk(const CString& sPath, mode_t iMode = 0644) const; |
612 | | /** Read a map from a file. |
613 | | * @param sPath The file name to read from. |
614 | | * @return The result of the operation. |
615 | | * @see ReadFilter. |
616 | | */ |
617 | | enum status_t ReadFromDisk(const CString& sPath); |
618 | | |
619 | | /** Filter used while writing this map. This function is called by |
620 | | * WriteToDisk() for each pair that is going to be written. This |
621 | | * function has the chance to modify the data that will be written. |
622 | | * @param sKey The key that will be written. Can be modified. |
623 | | * @param sValue The value that will be written. Can be modified. |
624 | | * @return true unless WriteToDisk() should fail with MCS_EWRITEFIL. |
625 | | */ |
626 | 0 | virtual bool WriteFilter(CString& sKey, CString& sValue) const { |
627 | 0 | return true; |
628 | 0 | } |
629 | | /** Filter used while reading this map. This function is called by |
630 | | * ReadFromDisk() for each pair that is beging read. This function has |
631 | | * the chance to modify the data that is being read. |
632 | | * @param sKey The key that was read. Can be modified. |
633 | | * @param sValue The value that was read. Can be modified. |
634 | | * @return true unless ReadFromDisk() should fail with MCS_EWRITEFIL. |
635 | | */ |
636 | 0 | virtual bool ReadFilter(CString& sKey, CString& sValue) const { |
637 | 0 | return true; |
638 | 0 | } |
639 | | |
640 | | /** Encode a value so that it can safely be parsed by ReadFromDisk(). |
641 | | * This is an internal function. |
642 | | */ |
643 | | virtual CString& Encode(CString& sValue) const; |
644 | | /** Undo the effects of Encode(). This is an internal function. */ |
645 | | virtual CString& Decode(CString& sValue) const; |
646 | | }; |
647 | | |
648 | | namespace std { |
649 | | template <> |
650 | | struct hash<CString> : hash<std::string> {}; |
651 | | } |
652 | | |
653 | | // Make translateable messages easy to write: |
654 | | // t_f("Foo is {1}")(foo) |
655 | | class CInlineFormatMessage { |
656 | | public: |
657 | | explicit CInlineFormatMessage(const CString& sFormat) |
658 | 0 | : m_sFormat(sFormat) {} |
659 | | explicit CInlineFormatMessage(CString&& sFormat) |
660 | 0 | : m_sFormat(std::move(sFormat)) {} |
661 | | |
662 | | template <typename... Args> |
663 | 0 | CString operator()(const Args&... args) const { |
664 | 0 | MCString values; |
665 | 0 | apply(values, 1, args...); |
666 | 0 | return CString::NamedFormat(m_sFormat, values); |
667 | 0 | } Unexecuted instantiation: CString CInlineFormatMessage::operator()<CString>(CString const&) const Unexecuted instantiation: CString CInlineFormatMessage::operator()<CString, CString, CString, CString>(CString const&, CString const&, CString const&, CString const&) const Unexecuted instantiation: CString CInlineFormatMessage::operator()<double>(double const&) const Unexecuted instantiation: CString CInlineFormatMessage::operator()<CString, CString>(CString const&, CString const&) const Unexecuted instantiation: CString CInlineFormatMessage::operator()<unsigned long, CString>(unsigned long const&, CString const&) const Unexecuted instantiation: CString CInlineFormatMessage::operator()<unsigned int>(unsigned int const&) const Unexecuted instantiation: CString CInlineFormatMessage::operator()<CString, char [7], std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(CString const&, char const (&) [7], std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const Unexecuted instantiation: CString CInlineFormatMessage::operator()<CString, char [67], char const*>(CString const&, char const (&) [67], char const* const&) const Unexecuted instantiation: CString CInlineFormatMessage::operator()<CString, unsigned int>(CString const&, unsigned int const&) const Unexecuted instantiation: CString CInlineFormatMessage::operator()<unsigned long, unsigned int, unsigned int, unsigned int>(unsigned long const&, unsigned int const&, unsigned int const&, unsigned int const&) const Unexecuted instantiation: CString CInlineFormatMessage::operator()<CString, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, CString>(CString const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, CString const&) const Unexecuted instantiation: CString CInlineFormatMessage::operator()<unsigned int, CString>(unsigned int const&, CString const&) const Unexecuted instantiation: CString CInlineFormatMessage::operator()<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const |
668 | | |
669 | | private: |
670 | | template <typename Arg, typename... Rest> |
671 | | void apply(MCString& values, int index, const Arg& arg, |
672 | 0 | const Rest&... rest) const { |
673 | 0 | values[CString(index)] = CString(arg); |
674 | 0 | apply(values, index + 1, rest...); |
675 | 0 | } Unexecuted instantiation: void CInlineFormatMessage::apply<CString>(MCString&, int, CString const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<CString, CString, CString, CString>(MCString&, int, CString const&, CString const&, CString const&, CString const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<CString, CString, CString>(MCString&, int, CString const&, CString const&, CString const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<CString, CString>(MCString&, int, CString const&, CString const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<double>(MCString&, int, double const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<unsigned long, CString>(MCString&, int, unsigned long const&, CString const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<unsigned int>(MCString&, int, unsigned int const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<CString, char [7], std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(MCString&, int, CString const&, char const (&) [7], std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<char [7], std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(MCString&, int, char const (&) [7], std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >>(MCString&, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<CString, char [67], char const*>(MCString&, int, CString const&, char const (&) [67], char const* const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<char [67], char const*>(MCString&, int, char const (&) [67], char const* const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<char const*>(MCString&, int, char const* const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<CString, unsigned int>(MCString&, int, CString const&, unsigned int const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<unsigned long, unsigned int, unsigned int, unsigned int>(MCString&, int, unsigned long const&, unsigned int const&, unsigned int const&, unsigned int const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<unsigned int, unsigned int, unsigned int>(MCString&, int, unsigned int const&, unsigned int const&, unsigned int const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<unsigned int, unsigned int>(MCString&, int, unsigned int const&, unsigned int const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<CString, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, CString>(MCString&, int, CString const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, CString const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, CString>(MCString&, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, CString const&) const Unexecuted instantiation: void CInlineFormatMessage::apply<unsigned int, CString>(MCString&, int, unsigned int const&, CString const&) const |
676 | | |
677 | 0 | void apply(MCString& values, int index) const {} |
678 | | |
679 | | CString m_sFormat; |
680 | | }; |
681 | | |
682 | | // For gtest |
683 | | #ifdef GTEST_FAIL |
684 | | inline void PrintTo(const CString& s, std::ostream* os) { |
685 | | *os << '"' << s.Escape_n(CString::EDEBUG) << '"'; |
686 | | } |
687 | | #endif |
688 | | |
689 | | #endif // !ZNCSTRING_H |