GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/utils/stringutils.cpp Lines: 602 615 97.9 %
Date: 2017-11-29 Branches: 435 530 82.1 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2007-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2017  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "utils/stringutils.h"
24
25
#include "const/utils/utf8.h"
26
27
#ifdef DYECMD
28
#include "utils/cast.h"
29
#else  // DYECMD
30
#include "resources/iteminfo.h"
31
#include "resources/db/itemdb.h"
32
#endif  // DYECMD
33
34
#include "utils/gettext.h"
35
#include "utils/foreach.h"
36
37
#include <algorithm>
38
#include <sstream>
39
40
#ifdef WIN32
41
#include <sys/time.h>
42
#endif  // WIN32
43
44
#include "debug.h"
45
46
11015
std::string &trim(std::string &str)
47
{
48
10847
    size_t pos = str.find_last_not_of(' ');
49
10847
    if (pos != std::string::npos)
50
    {
51
10841
        str.erase(pos + 1);
52
10841
        pos = str.find_first_not_of(' ');
53
54
10841
        if (pos != std::string::npos)
55
10841
            str.erase(0, pos);
56
    }
57
    else
58
    {
59
        // There is nothing else but whitespace in the string
60
        str.clear();
61
    }
62
11015
    return str;
63
}
64
65
179
std::string &toLower(std::string &str)
66
{
67
2908
    std::transform(str.begin(), str.end(), str.begin(), &tolower);
68
179
    return str;
69
}
70
71
8
std::string &toUpper(std::string &str)
72
{
73
32
    std::transform(str.begin(), str.end(), str.begin(), &toupper);
74
8
    return str;
75
}
76
77
15636
unsigned int atox(const std::string &str)
78
{
79
15636
    unsigned int value = 0;
80
15636
    if (sscanf(str.c_str(), "0x%06x", &value) != 0)
81
15634
        return value;
82
    return 0;
83
}
84
85
4
const char *ipToString(const uint32_t address)
86
{
87
    static char asciiIP[18];
88
89
16
    snprintf(asciiIP, sizeof(asciiIP), "%i.%i.%i.%i",
90
            CAST_U8(address),
91
4
            CAST_U8(address >> 8),
92
4
            CAST_U8(address >> 16),
93
4
            CAST_U8(address >> 24));
94
4
    asciiIP[17] = 0;
95
96
4
    return asciiIP;
97
}
98
99
168230
std::string strprintf(const char *const format, ...)
100
{
101
    char buf[257];
102
    va_list args;
103
168230
    va_start(args, format);
104
168230
    size_t nb = vsnprintf(buf, 256, format, args);
105
168230
    buf[256] = 0;
106
168230
    va_end(args);
107
168230
    if (nb < 256)
108
504684
        return buf;
109
110
    // The static size was not big enough, try again with a dynamic allocation.
111
2
    ++nb;
112
2
    char *buf2 = new char[nb];
113
2
    va_start(args, format);
114
2
    vsnprintf(buf2, nb, format, args);
115
2
    va_end(args);
116
6
    std::string res(buf2);
117
2
    delete [] buf2;
118
2
    return res;
119
}
120
121
20
std::string removeColors(std::string msg)
122
{
123

44
    for (unsigned int f = 0; f < msg.length() - 2 && msg.length() > 2; f++)
124
    {
125
82
        while (msg.length() > f + 2 && msg.at(f) == '#'
126

62
               && msg.at(f + 1) == '#')
127
        {
128
10
            msg = msg.erase(f, 3);
129
        }
130
    }
131
20
    return msg;
132
}
133
134
36938686
int compareStrI(const std::string &a, const std::string &b)
135
{
136
36938686
    std::string::const_iterator itA = a.begin();
137
36938686
    const std::string::const_iterator endA = a.end();
138
36938686
    std::string::const_iterator itB = b.begin();
139
36938686
    const std::string::const_iterator endB = b.end();
140
141

109176546
    for (; itA < endA && itB < endB; ++itA, ++itB)
142
    {
143
48242338
        const int comp = tolower(*itA) - tolower(*itB);
144
48242338
        if (comp != 0)
145
            return comp;
146
    }
147
148
    // Check string lengths
149

865158
    if (itA == endA && itB == endB)
150
        return 0;
151
269144
    else if (itA == endA)
152
        return -1;
153
    else
154
261530
        return 1;
155
}
156
157
158
14
bool isWordSeparator(const signed char chr)
159
{
160
28
    return chr == ' ' ||
161
14
        chr == ',' ||
162

24
        chr == '.' ||
163
24
        chr == '"';
164
}
165
166
8
const std::string findSameSubstring(const std::string &restrict str1,
167
                                    const std::string &restrict str2)
168
{
169
8
    const int minLength = str1.length() > str2.length()
170
8
        ? CAST_S32(str2.length()) : CAST_S32(str1.length());
171
40
    for (int f = 0; f < minLength; f ++)
172
    {
173
102
        if (str1.at(f) != str2.at(f))
174
2
            return str1.substr(0, f);
175
    }
176
6
    return str1.substr(0, minLength);
177
}
178
179
10
const std::string findSameSubstringI(const std::string &restrict s1,
180
                                     const std::string &restrict s2)
181
{
182
20
    std::string str1 = s1;
183
20
    std::string str2 = s2;
184
10
    toLower(str1);
185
10
    toLower(str2);
186
187
10
    const size_t minLength = str1.length() > str2.length()
188
10
        ? str2.length() : str1.length();
189
56
    for (size_t f = 0; f < minLength; f ++)
190
    {
191
96
        if (str1.at(f) != str2.at(f))
192
2
            return s1.substr(0, f);
193
    }
194
8
    return s1.substr(0, minLength);
195
}
196
197
10
size_t findI(std::string str, std::string subStr)
198
{
199
20
    str = toLower(str);
200
20
    subStr = toLower(subStr);
201
10
    return str.find(subStr);
202
}
203
204
10
size_t findI(std::string text, const StringVect &list)
205
{
206
10
    toLower(text);
207
54
    FOR_EACH (StringVectCIter, i, list)
208
    {
209
54
        std::string subStr = *i;
210
40
        subStr = toLower(subStr);
211
20
        const size_t idx = text.find(subStr);
212
20
        if (idx != std::string::npos)
213
12
            return idx;
214
    }
215
    return std::string::npos;
216
}
217
218
274
size_t findAny(const std::string &restrict text,
219
               const std::string &restrict chars,
220
               const size_t pos)
221
{
222
274
    size_t idx = std::string::npos;
223
274
    const size_t sz = chars.size();
224
556
    for (size_t f = 0; f < sz; f ++)
225
    {
226
282
        const size_t idx2 = text.find(chars[f], pos);
227
282
        if (idx2 != std::string::npos && idx2 < idx)
228
214
            idx = idx2;
229
    }
230
274
    return idx;
231
}
232
233
namespace
234
{
235
    unsigned int base = 94;
236
    unsigned int start = 33;
237
}  // namespace
238
239
8
const std::string encodeStr(unsigned int value, const unsigned int size)
240
{
241
    std::string buf;
242
243
    do
244
    {
245
24
        buf += CAST_S8(value % base + start);
246
12
        value /= base;
247
    }
248
12
    while (value != 0u);
249
250
16
    while (buf.length() < size)
251
8
        buf += CAST_S8(start);
252
8
    return buf;
253
}
254
255
256
10
unsigned int decodeStr(const std::string &str)
257
{
258
10
    if (str.empty())
259
        return 0;
260
261
8
    int res = str[0] - start;
262
8
    int mult = 1;
263
20
    for (unsigned int f = 1; f < str.length(); f ++)
264
    {
265
12
        mult *= base;
266
24
        res = res + (str[f] - start) * mult;
267
    }
268
8
    return res;
269
}
270
271
14
std::string extractNameFromSprite(std::string str)
272
{
273
12
    const size_t pos1 = str.rfind('.');
274
12
    if (pos1 != std::string::npos)
275
    {
276
10
        size_t pos2 = str.rfind('/');
277
10
        const size_t pos3 = str.rfind('\\');
278
10
        if (pos3 != std::string::npos)
279
        {
280
6
            if (pos2 == std::string::npos || pos3 > pos2)
281
4
                pos2 = pos3;
282
        }
283
10
        if (pos2 == std::string::npos)
284
2
            pos2 = CAST_SIZE(-1);
285
286
10
        const int size = CAST_S32(pos1) - CAST_S32(pos2) - 1;
287
10
        if (size > 0)
288
20
            str = str.substr(pos2 + 1, size);
289
    }
290
14
    return str;
291
}
292
293
14
std::string removeSpriteIndex(std::string str)
294
{
295
12
    const size_t pos1 = str.rfind('[');
296
297
12
    if (pos1 != std::string::npos)
298
    {
299
10
        size_t pos2 = str.rfind('/');
300
10
        const size_t pos3 = str.rfind('\\');
301
10
        if (pos3 != std::string::npos)
302
        {
303
6
            if (pos2 == std::string::npos || pos3 > pos2)
304
4
                pos2 = pos3;
305
        }
306
10
        if (pos2 == std::string::npos)
307
2
            pos2 = CAST_SIZE(-1);
308
309
10
        const int size = CAST_S32(pos1) - CAST_S32(pos2) - 1;
310
10
        if (size > 0)
311
20
            str = str.substr(pos2 + 1, size);
312
    }
313
14
    return str;
314
}
315
316
6
const char* getSafeUtf8String(const std::string &text)
317
{
318
6
    const size_t sz = text.size();
319
6
    const size_t size = sz + UTF8_MAX_SIZE;
320
6
    char *const buf = new char[size];
321
12
    memcpy(buf, text.c_str(), sz);
322
12
    memset(buf + sz, 0, UTF8_MAX_SIZE);
323
6
    return buf;
324
}
325
326
18788
void getSafeUtf8String(std::string text, char *const buf)
327
{
328
18788
    if (buf == nullptr)
329
        return;
330
18786
    const size_t sz = text.size();
331
18786
    const size_t size = sz + UTF8_MAX_SIZE;
332
18786
    if (size > 65500)
333
    {
334
4
        text = text.substr(0, 65500);
335
2
        const size_t sz1 = text.size();
336
4
        memcpy(buf, text.c_str(), sz1);
337
2
        memset(buf + sz1, 0, UTF8_MAX_SIZE);
338
    }
339
    else
340
    {
341
37568
        memcpy(buf, text.c_str(), sz);
342
18784
        memset(buf + sz, 0, UTF8_MAX_SIZE);
343
    }
344
}
345
346
44
std::string getFileName(const std::string &path)
347
{
348
44
    size_t pos1 = path.rfind('/');
349
44
    const size_t pos2 = path.rfind('\\');
350
44
    if (pos1 == std::string::npos)
351
        pos1 = pos2;
352
40
    else if (pos2 != std::string::npos && pos2 > pos1)
353
2
        pos1 = pos2;
354
355
44
    if (pos1 == std::string::npos)
356
        return path;
357
40
    return path.substr(pos1 + 1);
358
}
359
360
962
std::string getFileDir(const std::string &path)
361
{
362
962
    size_t pos1 = path.rfind('/');
363
962
    const size_t pos2 = path.rfind('\\');
364
962
    if (pos1 == std::string::npos)
365
        pos1 = pos2;
366
720
    else if (pos2 != std::string::npos && pos2 > pos1)
367
2
        pos1 = pos2;
368
369
962
    if (pos1 == std::string::npos)
370
        return path;
371
720
    return path.substr(0, pos1);
372
}
373
374
43186
std::string& replaceAll(std::string& context,
375
                        const std::string &restrict from,
376
                        const std::string &restrict to)
377
{
378
43186
    if (from.empty())
379
        return context;
380
43180
    size_t lookHere = 0;
381
    size_t foundHere;
382
43180
    const size_t fromSize = from.size();
383
43180
    const size_t toSize = to.size();
384
44004
    while ((foundHere = context.find(from, lookHere)) != std::string::npos)
385
    {
386
412
        context.replace(foundHere, fromSize, to);
387
412
        lookHere = foundHere + toSize;
388
    }
389
    return context;
390
}
391
392
53310
void replaceRecursiveAll(std::string& context,
393
                         const std::string &restrict from,
394
                         const char to)
395
{
396
53310
    size_t lookHere = 0;
397
    size_t foundHere;
398
53310
    const size_t fromSize = from.size();
399
54270
    while ((foundHere = context.find(from, lookHere)) != std::string::npos)
400
    {
401
480
        context.replace(foundHere, fromSize, 1, to);
402
480
        lookHere = foundHere;
403
    }
404
53310
}
405
406
77
bool getBoolFromString(const std::string &text)
407
{
408
154
    std::string txt = text;
409
77
    toLower(trim(txt));
410


272
    if (txt == "true" || txt == "yes" || txt == "on" || txt == "1")
411
        return true;
412


152
    else if (txt == "false" || txt == "no" || txt == "off" || txt == "0")
413
        return false;
414
    else
415
28
        return static_cast<bool>(atoi(txt.c_str()));
416
}
417
418
22
void replaceSpecialChars(std::string &text)
419
{
420
22
    size_t pos1 = text.find('&');
421
54
    while (pos1 != std::string::npos)
422
    {
423
20
        const size_t idx = pos1 + 1;
424
20
        const size_t sz = text.size();
425
20
        if (idx >= sz)
426
            break;
427
428
        size_t f;
429
76
        for (f = idx; f < sz; f ++)
430
        {
431

84
            if (text[f] < '0' || text[f] > '9')
432
                break;
433
        }
434

30
        if (idx + 1 < f && text[f] == ';')
435
        {
436
40
            std::string str(" ");
437
50
            str[0] = CAST_S8(atoi(text.substr(
438
                idx, f - idx).c_str()));
439

60
            text = text.substr(0, pos1).append(str).append(text.substr(f + 1));
440
10
            pos1 += 1;
441
        }
442
        else
443
        {
444
6
            pos1 = f + 1;
445
        }
446
447
16
        pos1 = text.find('&', pos1);
448
    }
449
22
}
450
451
508
std::string normalize(const std::string &name)
452
{
453
1016
    std::string normalized = name;
454
2032
    return toLower(trim(normalized));
455
}
456
457
12
void splitToIntSet(std::set<int> &tokens,
458
                   const std::string &text,
459
                   const char separator)
460
{
461
24
    std::stringstream ss(text);
462
12
    std::string item;
463

108
    while (std::getline(ss, item, separator))
464
84
        tokens.insert(atoi(item.c_str()));
465
12
}
466
467
12
std::list<int> splitToIntList(const std::string &text,
468
                              const char separator)
469
{
470
12
    std::list<int> tokens;
471
24
    std::stringstream ss(text);
472
12
    std::string item;
473

108
    while (std::getline(ss, item, separator))
474
84
        tokens.push_back(atoi(item.c_str()));
475
476
12
    return tokens;
477
}
478
479
66
std::list<std::string> splitToStringList(const std::string &text,
480
                                         const char separator)
481
{
482
66
    std::list<std::string> tokens;
483
132
    std::stringstream ss(text);
484
66
    std::string item;
485

180
    while (std::getline(ss, item, separator))
486
24
        tokens.push_back(item);
487
488
66
    return tokens;
489
}
490
491
6526
void splitToStringVector(StringVect &tokens,
492
                         const std::string &text,
493
                         const char separator)
494
{
495
13052
    std::stringstream ss(text);
496
6526
    std::string item;
497

33164
    while (std::getline(ss, item, separator))
498
    {
499
20112
        item = trim(item);
500
10056
        if (!item.empty())
501
10024
            tokens.push_back(item);
502
    }
503
6526
}
504
505
14
void splitToStringSet(std::set<std::string> &tokens,
506
                      const std::string &text,
507
                      const char separator)
508
{
509
28
    std::stringstream ss(text);
510
14
    std::string item;
511

96
    while (std::getline(ss, item, separator))
512
    {
513
68
        item = trim(item);
514
34
        if (!item.empty())
515
            tokens.insert(item);
516
    }
517
14
}
518
519
14
void splitToIntVector(STD_VECTOR<int> &tokens,
520
                      const std::string &text,
521
                      const char separator)
522
{
523
28
    std::stringstream ss(text);
524
14
    std::string item;
525

96
    while (std::getline(ss, item, separator))
526
    {
527
68
        item = trim(item);
528
34
        if (!item.empty())
529
96
            tokens.push_back(atoi(item.c_str()));
530
    }
531
14
}
532
533
14
std::string combineDye(std::string file,
534
                       const std::string &dye)
535
{
536
14
    if (dye.empty())
537
        return file;
538
8
    const size_t pos = file.find_last_of('|');
539
8
    if (pos != std::string::npos)
540
24
        return file.substr(0, pos).append("|").append(dye);
541
8
    return file.append("|").append(dye);
542
}
543
544
20
std::string combineDye2(std::string file,
545
                        const std::string &dye)
546
{
547
20
    if (dye.empty())
548
        return file;
549
550
8
    const size_t pos = file.find_last_of('|');
551
8
    if (pos != std::string::npos)
552
    {
553
8
        const std::string dye1 = file.substr(pos + 1);
554
8
        std::string str;
555
8
        file = file.substr(0, pos);
556
8
        const std::list<std::string> list1 = splitToStringList(dye1, ';');
557
8
        const std::list<std::string> list2 = splitToStringList(dye, ';');
558
14
        for (std::list<std::string>::const_iterator it1 = list1.begin(),
559
16
             it2 = list2.begin(), it1_end = list1.end(), it2_end = list2.end();
560

10
             it1 != it1_end && it2 != it2_end; ++it1, ++it2)
561
        {
562

24
            str.append(*it1).append(":").append(*it2).append(";");
563
        }
564
16
        return file.append("|").append(str);
565
    }
566
    return file;
567
}
568
569
14
std::string combineDye3(std::string file,
570
                        const std::string &dye)
571
{
572
14
    if (dye.empty())
573
        return file;
574
575
6
    const size_t pos = file.find_last_of('|');
576
6
    if (pos != std::string::npos)
577
    {
578
8
        const std::string dye1 = file.substr(pos + 1);
579
8
        std::string str;
580
8
        file = file.substr(0, pos);
581
8
        const std::list<std::string> list1 = splitToStringList(dye1, ';');
582
8
        const std::list<std::string> list2 = splitToStringList(dye, ';');
583
14
        for (std::list<std::string>::const_iterator it1 = list1.begin(),
584
16
             it2 = list2.begin(), it1_end = list1.end(), it2_end = list2.end();
585

10
             it1 != it1_end && it2 != it2_end; ++it1, ++it2)
586
        {
587

24
            str.append(*it1).append(":").append(*it2).append(";");
588
        }
589
16
        return file.append("|").append(str);
590
    }
591
8
    if (dye.empty() || file.empty())
592
        return file;
593
4
    return file.append("|").append(dye);
594
}
595
596
62
std::string packList(const std::list<std::string> &list)
597
{
598
124
    std::list<std::string>::const_iterator i = list.begin();
599
    std::string str;
600
100
    while (i != list.end())
601
    {
602
76
        str.append(*i).append("|");
603
        ++ i;
604
    }
605
62
    const size_t sz = str.size();
606
62
    if (sz > 1)
607
16
        str = str.substr(0, sz - 1);
608
62
    return str;
609
}
610
611
50
std::list<std::string> unpackList(const std::string &str)
612
{
613
50
    return splitToStringList(str, '|');
614
}
615
616
10
std::string stringToHexPath(const std::string &str)
617
{
618
10
    if (str.empty())
619
6
        return "";
620
621
8
    std::string hex = strprintf("%%%2x/", CAST_U32(str[0]));
622
20
    for (unsigned f = 1, fsz = CAST_U32(str.size());
623
20
         f < fsz; f ++)
624
    {
625
48
        hex.append(strprintf("%%%2x", CAST_U32(str[f])));
626
    }
627
8
    return hex;
628
}
629
630
8
void deleteCharLeft(std::string &str,
631
                    unsigned *const pos)
632
{
633
8
    if (pos == nullptr)
634
        return;
635
636
8
    while (*pos > 0)
637
    {
638
8
        (*pos)--;
639
16
        const int v = str[*pos];
640
8
        str.erase(*pos, 1);
641
8
        if ((v & 192) != 128)
642
            break;
643
    }
644
}
645
646
197368
bool findLast(const std::string &restrict str1,
647
              const std::string &restrict str2)
648
{
649
197368
    const size_t s1 = str1.size();
650
197368
    const size_t s2 = str2.size();
651
197368
    if (s1 < s2)
652
        return false;
653
412176
    if (str1.substr(s1 - s2) == str2)
654
        return true;
655
81934
    return false;
656
}
657
658
8
bool findFirst(const std::string &restrict str1,
659
               const std::string &restrict str2)
660
{
661
8
    const size_t s1 = str1.size();
662
8
    const size_t s2 = str2.size();
663
8
    if (s1 < s2)
664
        return false;
665
18
    if (str1.substr(0, s2) == str2)
666
        return true;
667
2
    return false;
668
}
669
670
100
bool findCutLast(std::string &restrict str1,
671
                 const std::string &restrict str2)
672
{
673
100
    const size_t s1 = str1.size();
674
100
    const size_t s2 = str2.size();
675
100
    if (s1 < s2)
676
        return false;
677
294
    if (str1.substr(s1 - s2) == str2)
678
    {
679
160
        str1 = str1.substr(0, s1 - s2);
680
80
        return true;
681
    }
682
    return false;
683
}
684
685
8
void cutLast(std::string &restrict str1,
686
             const std::string &restrict str2)
687
{
688
8
    const size_t s1 = str1.size();
689
8
    const size_t s2 = str2.size();
690
8
    if (s1 < s2)
691
        return;
692
18
    if (str1.substr(s1 - s2) == str2)
693
8
        str1 = str1.substr(0, s1 - s2);
694
}
695
696
394
bool findCutFirst(std::string &restrict str1,
697
                  const std::string &restrict str2)
698
{
699
394
    const size_t s1 = str1.size();
700
394
    const size_t s2 = str2.size();
701
394
    if (s1 < s2)
702
        return false;
703
1176
    if (str1.substr(0, s2) == str2)
704
    {
705
304
        str1 = str1.substr(s2);
706
152
        return true;
707
    }
708
    return false;
709
}
710
711
8
void cutFirst(std::string &restrict str1,
712
              const std::string &restrict str2)
713
{
714
8
    const size_t s1 = str1.size();
715
8
    const size_t s2 = str2.size();
716
8
    if (s1 < s2)
717
        return;
718
18
    if (str1.substr(0, s2) == str2)
719
8
        str1 = str1.substr(s2);
720
}
721
722
8
std::string &removeProtocol(std::string &url)
723
{
724
8
    const size_t i = url.find("://");
725
8
    if (i != std::string::npos)
726
8
        url = url.substr(i + 3);
727
8
    return url;
728
}
729
730
74058
bool strStartWith(const std::string &restrict str1,
731
                  const std::string &restrict str2)
732
{
733
74058
    const size_t sz2 = str2.size();
734
74058
    if (str1.size() < sz2)
735
        return false;
736
192750
    return str1.substr(0, sz2) == str2;
737
}
738
739
5
std::string getDateString()
740
{
741
    char buffer[80];
742
    time_t rawtime;
743
5
    time(&rawtime);
744
5
    const tm *const timeinfo = localtime(&rawtime);
745
746
5
    strftime(buffer, 79, "%Y-%m-%d", timeinfo);
747
15
    return std::string(buffer);
748
}
749
750
std::string getDateTimeString()
751
{
752
    char buffer[80];
753
    time_t rawtime;
754
    time(&rawtime);
755
    const tm *const timeinfo = localtime(&rawtime);
756
757
    strftime(buffer, 79, "%Y-%m-%d %H:%M:%S", timeinfo);
758
    return std::string(buffer);
759
}
760
761
58
signed char parseBoolean(const std::string &value)
762
{
763
116
    std::string txt = value;
764
58
    toLower(trim(txt));
765


196
    if (txt == "true" || txt == "yes" || txt == "on" || txt == "1")
766
        return 1;
767


108
    else if (txt == "false" || txt == "no" || txt == "off" || txt == "0")
768
        return 0;
769
    else
770
        return -1;
771
}
772
773
12
std::string encodeLinkText(std::string data)
774
{
775

96
    return replaceAll(data, "|", "\342\235\230");
776
}
777
778
2
std::string decodeLinkText(std::string data)
779
{
780

16
    return replaceAll(data, "\342\235\230", "|");
781
}
782
783
6
std::string toStringPrint(const unsigned int val)
784
{
785
    static char str[100];
786
6
    snprintf(str, sizeof(str), "%u 0x%x", val, val);
787
6
    str[99] = 0;
788
18
    return str;
789
}
790
791
1586
std::string toString(uint32_t num)
792
{
793
    char buf[30];
794
1586
    buf[29] = '\0';
795
1586
    size_t idx = 28;
796
    do
797
3064
        buf[idx--] = CAST_8((num % 10) + '0');
798
3064
    while ((num /= 10) != 0);
799
4758
    return buf + idx + 1;
800
}
801
802
14
std::string toString(uint64_t num)
803
{
804
    char buf[100];
805
14
    buf[99] = '\0';
806
14
    size_t idx = 98;
807
    do
808
14
        buf[idx--] = CAST_8((num % 10) + '0');
809
14
    while ((num /= 10) != 0);
810
42
    return buf + idx + 1;
811
}
812
813
4
std::string toString(uint16_t num)
814
{
815
    char buf[10];
816
4
    buf[9] = '\0';
817
4
    size_t idx = 8;
818
    do
819
16
        buf[idx--] = CAST_8((num % 10) + '0');
820
16
    while ((num /= 10) != 0);
821
12
    return buf + idx + 1;
822
}
823
824
2
std::string toString(unsigned char num)
825
{
826
    char buf[5];
827
2
    buf[4] = '\0';
828
2
    size_t idx = 3;
829
    do
830
6
        buf[idx--] = CAST_8((num % 10) + '0');
831
6
    while ((num /= 10) != 0);
832
6
    return buf + idx + 1;
833
}
834
835
250482
std::string toString(int32_t num)
836
{
837
    char buf[30];
838
250482
    bool useSign(false);
839
250482
    buf[29] = '\0';
840
250482
    size_t idx = 28;
841
842
250482
    if (num < 0)
843
    {
844
3204
        useSign = true;
845
3204
        num = -num;
846
    }
847
    do
848
1277936
        buf[idx--] = CAST_8((num % 10) + '0');
849
1277936
    while ((num /= 10) != 0);
850
250482
    if (useSign)
851
3204
        buf[idx--] = '-';
852
751446
    return buf + idx + 1;
853
}
854
855
560
std::string toString(const float num)
856
{
857
560
    return strprintf("%f", num);
858
}
859
860
10
std::string toString(const double num)
861
{
862
10
    return strprintf("%f", static_cast<float>(num));
863
}
864
865
14
bool isDigit(const std::string &str)
866
{
867
14
    if (str.empty())
868
        return false;
869
    const size_t sz = str.size();
870
40
    for (size_t f = 0; f < sz; f ++)
871
    {
872
22
        const char &chr = str[f];
873
22
        if (chr < '0' || chr > '9')
874
            return false;
875
    }
876
    return true;
877
}
878
879
12
void secureChatCommand(std::string &str)
880
{
881

30
    if (str[0] == '/' || str[0] == '@' || str[0] == '#')
882
12
        str = "_" + str;
883
12
}
884
885
10
bool parse2Int(const std::string &args,
886
               int &x,
887
               int &y)
888
{
889
10
    bool isValid = false;
890
10
    size_t pos = args.find(' ');
891
10
    if (pos == std::string::npos)
892
6
        pos = args.find(',');
893
10
    if (pos != std::string::npos)
894
    {
895
8
        if (pos + 1 < args.length())
896
        {
897
24
            x = atoi(args.substr(0, pos).c_str());
898
24
            y = atoi(args.substr(pos + 1, args.length()).c_str());
899
6
            isValid = true;
900
        }
901
    }
902
10
    return isValid;
903
}
904
905
8
bool parse2Str(const std::string &args,
906
               std::string &str1,
907
               std::string &str2)
908
{
909
8
    bool isValid = false;
910
8
    size_t pos = args.find(' ');
911
8
    if (pos == std::string::npos)
912
6
        pos = args.find(',');
913
8
    if (pos != std::string::npos)
914
    {
915
6
        if (pos + 1 < args.length())
916
        {
917
8
            str1 = args.substr(0, pos);
918
8
            str2 = args.substr(pos + 1, args.length());
919
4
            isValid = true;
920
        }
921
    }
922
8
    return isValid;
923
}
924
925
12
uint32_t parseNumber(const std::string &str)
926
{
927
12
    uint32_t i = 0;
928
12
    int idx = 0;
929

48
    if (strStartWith(str, "0x"))
930
        idx = 2;
931

14
    else if (str[0] == 'h' || str[0] == 'x')
932
        idx = 1;
933
    if (idx > 0)
934
24
        sscanf(str.substr(idx).c_str(), "%10x", &i);
935
    else
936
8
        i = atoi(str.c_str());
937
12
    return i;
938
}
939
940
12
std::string removeToken(std::string &str,
941
                        const std::string &token)
942
{
943
12
    const size_t idx = str.find(token);
944
12
    if (idx > 0 && idx != std::string::npos)
945
8
        str = str.substr(idx + 1);
946
    else
947
        str.clear();
948
12
    return str;
949
}
950
951
std::string timeToStr(const uint32_t time)
952
{
953
    char buf[101];
954
    const time_t tempTime = time;
955
    tm *const timeInfo = localtime(&tempTime);
956
    if (strftime(&buf[0], 100, "%Y-%m-%d_%H-%M-%S", timeInfo) != 0u)
957
        return std::string(buf);
958
    return "unknown";
959
}
960
961
20
std::string timeDiffToString(int timeDiff)
962
{
963
20
    std::string str;
964
965
20
    const int weeks = timeDiff / 60 / 60 / 24 / 7;
966
20
    if (weeks > 0)
967
    {
968
        // TRANSLATORS: uptime command
969
20
        str = strprintf(ngettext(N_("%d week"), N_("%d weeks"),
970
            weeks), weeks);
971
10
        timeDiff -= weeks * 60 * 60 * 24 * 7;
972
    }
973
974
20
    const int days = timeDiff / 60 / 60 / 24;
975
20
    if (days > 0)
976
    {
977
10
        if (!str.empty())
978
8
            str.append(", ");
979
        // TRANSLATORS: uptime command
980
30
        str.append(strprintf(ngettext(N_("%d day"), N_("%d days"),
981
            days), days));
982
10
        timeDiff -= days * 60 * 60 * 24;
983
    }
984
20
    const int hours = timeDiff / 60 / 60;
985
20
    if (hours > 0)
986
    {
987
8
        if (!str.empty())
988
6
            str.append(", ");
989
        // TRANSLATORS: uptime command
990
24
        str.append(strprintf(ngettext(N_("%d hour"), N_("%d hours"),
991
            hours), hours));
992
8
        timeDiff -= hours * 60 * 60;
993
    }
994
20
    const int min = timeDiff / 60;
995
20
    if (min > 0)
996
    {
997
6
        if (!str.empty())
998
4
            str.append(", ");
999
        // TRANSLATORS: uptime command
1000
18
        str.append(strprintf(ngettext(N_("%d minute"), N_("%d minutes"),
1001
            min), min));
1002
6
        timeDiff -= min * 60;
1003
    }
1004
1005
20
    if (timeDiff > 0)
1006
    {
1007
4
        if (!str.empty())
1008
2
            str.append(", ");
1009
        // TRANSLATORS: uptime command
1010
12
        str.append(strprintf(ngettext(N_("%d second"), N_("%d seconds"),
1011
            timeDiff), timeDiff));
1012
    }
1013
    if (str.empty())
1014
    {
1015
        // TRANSLATORS: uptime command
1016
6
        str.append(strprintf(ngettext(N_("%d second"), N_("%d seconds"),
1017
            0), 0));
1018
    }
1019
20
    return str;
1020
}
1021
1022
20
std::string escapeString(std::string str)
1023
{
1024

140
    replaceAll(str, "\"", "\\\"");
1025
40
    return "\"" + str + "\"";
1026
}
1027
1028
26642
void sanitizePath(std::string &path)
1029
{
1030
#ifdef WIN32
1031
    const char sepStr = '\\';
1032
    const std::string sep2Str = "\\\\";
1033
    const std::string sepWrongStr = "/";
1034
#else
1035
26642
    const char sepStr = '/';
1036
106568
    const std::string sep2Str = "//";
1037
106568
    const std::string sepWrongStr = "\\";
1038
#endif
1039
26642
    replaceRecursiveAll(path, sepWrongStr, sepStr);
1040
26642
    replaceRecursiveAll(path, sep2Str, sepStr);
1041
26642
}
1042
1043
17378
std::string pathJoin(std::string str1,
1044
                     const std::string &str2)
1045
{
1046
#ifdef WIN32
1047
    const char sep = '\\';
1048
    std::string sepStr = "\\";
1049
#else
1050
17378
    const char sep = '/';
1051
69512
    std::string sepStr = "/";
1052
#endif
1053
1054
17378
    if (str1.empty())
1055
    {
1056
18
        if (str2[0] == sep)
1057
            return str2;
1058
12
        return sepStr.append(str2);
1059
    }
1060
17360
    const size_t sz1 = str1.size();
1061
17360
    if (str2.empty())
1062
    {
1063
12
        if (str1[sz1 - 1] == sep)
1064
            return str1;
1065
        return str1.append(sepStr);
1066
    }
1067
34708
    if (str1[sz1 - 1] == sep)
1068
    {
1069
4801
        if (str2[0] == sep)
1070
72
            return str1.append(str2.substr(1));
1071
4783
        return str1.append(str2);
1072
    }
1073
    else
1074
    {
1075
12553
        if (str2[0] == sep)
1076
4
            return str1.append(str2);
1077
25098
        return str1.append(sepStr).append(str2);
1078
    }
1079
}
1080
1081
628
std::string pathJoin(std::string str1,
1082
                     const std::string &str2,
1083
                     const std::string &str3)
1084
{
1085
#ifdef WIN32
1086
    const char sep = '\\';
1087
    std::string sepStr = "\\";
1088
#else
1089
628
    const char sep = '/';
1090
2512
    std::string sepStr = "/";
1091
#endif
1092
1093
628
    if (str1.empty())
1094
    {
1095
16
        return pathJoin(str2, str3);
1096
    }
1097
620
    size_t sz1 = str1.size();
1098
620
    if (str2.empty())
1099
    {
1100
8
        return pathJoin(str1, str3);
1101
    }
1102
616
    if (str3.empty())
1103
    {
1104
4
        return pathJoin(str1, str2);
1105
    }
1106
1228
    if (str1[sz1 - 1] == sep)
1107
    {
1108
586
        if (str2[0] == sep)
1109
36
            str1.append(str2.substr(1));
1110
        else
1111
            str1.append(str2);
1112
    }
1113
    else
1114
    {
1115
28
        if (str2[0] == sep)
1116
            str1.append(str2);
1117
        else
1118
24
            str1.append(sepStr).append(str2);
1119
    }
1120
1121
614
    sz1 = str1.size();
1122
1228
    if (str1[sz1 - 1] == sep)
1123
    {
1124
12
        if (str3[0] == sep)
1125
16
            return str1.append(str3.substr(1));
1126
8
        return str1.append(str3);
1127
    }
1128
    else
1129
    {
1130
602
        if (str3[0] == sep)
1131
10
            return str1.append(str3);
1132
1184
        return str1.append(sepStr).append(str3);
1133
    }
1134
}
1135
1136
26
std::string urlJoin(std::string str1,
1137
                    const std::string &str2)
1138
{
1139
26
    const char sep = '/';
1140
104
    std::string sepStr = "/";
1141
1142
26
    if (str1.empty())
1143
    {
1144
6
        if (str2[0] == sep)
1145
            return str2;
1146
4
        return sepStr.append(str2);
1147
    }
1148
20
    const size_t sz1 = str1.size();
1149
20
    if (str2.empty())
1150
    {
1151
4
        if (str1[sz1 - 1] == sep)
1152
            return str1;
1153
        return str1.append(sepStr);
1154
    }
1155
36
    if (str1[sz1 - 1] == sep)
1156
    {
1157
8
        if (str2[0] == sep)
1158
16
            return str1.append(str2.substr(1));
1159
4
        return str1.append(str2);
1160
    }
1161
    else
1162
    {
1163
10
        if (str2[0] == sep)
1164
4
            return str1.append(str2);
1165
12
        return str1.append(sepStr).append(str2);
1166
    }
1167
}
1168
1169
#ifndef DYECMD
1170
86
void replaceItemLinks(std::string &msg)
1171
{
1172
    // Check for item link
1173
86
    size_t start2 = msg.find('[');
1174
86
    size_t sz = msg.size();
1175
376
    while (start2 + 1 < sz &&
1176

238
           start2 != std::string::npos &&
1177
156
           msg[start2 + 1] != '@')
1178
    {
1179
78
        const size_t end = msg.find(']', start2);
1180

78
        if (start2 + 1 != end &&
1181
            end != std::string::npos)
1182
        {
1183
            // Catch multiple embeds and ignore them
1184
            // so it doesn't crash the client.
1185

80
            while ((msg.find('[', start2 + 1) != std::string::npos) &&
1186
                   (msg.find('[', start2 + 1) < end))
1187
            {
1188
                start2 = msg.find('[', start2 + 1);
1189
            }
1190
1191

50
            if (start2 + 1 < sz &&
1192
50
                end < sz &&
1193
                end > start2 + 1)
1194
            {
1195
72
                std::string itemStr = msg.substr(start2 + 1, end - start2 - 1);
1196
1197
72
                StringVect parts;
1198
38
                splitToStringVector(parts, itemStr, ',');
1199
38
                if (parts.empty())
1200
4
                    return;
1201
1202
34
                const ItemInfo &itemInfo = ItemDB::get(parts[0]);
1203
34
                const int itemId = itemInfo.getId();
1204
34
                if (itemId != 0)
1205
                {
1206
68
                    std::string temp = strprintf("@@%d", itemId);
1207
102
                    std::string name = parts[0];
1208
34
                    msg.erase(start2 + 1, end - start2 - 1);
1209
102
                    parts.erase(parts.begin());
1210
34
                    if (!parts.empty())
1211
                        name.clear();
1212
1213
174
                    FOR_EACH (StringVectCIter, it, parts)
1214
                    {
1215
12
                        std:: string str = *it;
1216
4
                        trim(str);
1217
4
                        const ItemInfo &itemInfo2 = ItemDB::get(str);
1218
4
                        const int cardId = itemInfo2.getId();
1219
4
                        if (cardId != 0)
1220
12
                            temp.append(strprintf(",%d", cardId));
1221
                    }
1222
34
                    temp.append("|");
1223
34
                    temp.append(name);
1224
34
                    temp.append("@@");
1225
68
                    msg.insert(start2 + 1, temp);
1226
34
                    sz = msg.size();
1227
                }
1228
            }
1229
        }
1230
74
        start2 = msg.find('[', start2 + 1);
1231
    }
1232
}
1233
#else  // DYECMD
1234
1235
void replaceItemLinks(std::string &msg A_UNUSED)
1236
{
1237
}
1238
#endif  // DYECMD