Coverage Report

Created: 2025-11-09 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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