1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
// *****************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
// *****************************************************************************
#ifndef ZSTRING_H_73425873425789
#define ZSTRING_H_73425873425789
#include "string_base.h"
using Zchar = char;
#define Zstr(x) x
const Zchar FILE_NAME_SEPARATOR = '/';
//"The reason for all the fuss above" - Loki/SmartPtr
//a high-performance string for interfacing with native OS APIs in multithreaded contexts
using Zstring = zen::Zbase<Zchar>;
//for special UI-contexts: guaranteed exponential growth + ref-counting
using Zstringw = zen::Zbase<wchar_t>;
//Caveat: don't expect input/output string sizes to match:
// - different UTF-8 encoding length of upper-case chars
// - different number of upper case chars (e.g. "ß" => "SS" on macOS)
// - output is Unicode-normalized
Zstring makeUpperCopy(const Zstring& str);
//Windows, Linux: precomposed
//macOS: decomposed
Zstring getUnicodeNormalForm(const Zstring& str);
// "In fact, Unicode declares that there is an equivalence relationship between decomposed and composed sequences,
// and conformant software should not treat canonically equivalent sequences, whether composed or decomposed or something in between, as different."
// http://www.win.tue.nl/~aeb/linux/uc/nfc_vs_nfd.html
struct LessUnicodeNormal { bool operator()(const Zstring& lhs, const Zstring& rhs) const { return getUnicodeNormalForm(lhs) < getUnicodeNormalForm(rhs);} };
Zstring replaceCpyAsciiNoCase(const Zstring& str, const Zstring& oldTerm, const Zstring& newTerm);
//------------------------------------------------------------------------------------------
inline bool equalNoCase(const Zstring& lhs, const Zstring& rhs) { return makeUpperCopy(lhs) == makeUpperCopy(rhs); }
struct ZstringNoCase //use as STL container key: avoid needless upper-case conversions during std::map<>::find()
{
ZstringNoCase(const Zstring& str) : upperCase(makeUpperCopy(str)) {}
Zstring upperCase;
};
inline bool operator<(const ZstringNoCase& lhs, const ZstringNoCase& rhs) { return lhs.upperCase < rhs.upperCase; }
//------------------------------------------------------------------------------------------
//Compare *local* file paths:
// Windows: igore case
// Linux: byte-wise comparison
// macOS: ignore case + Unicode normalization forms
int compareNativePath(const Zstring& lhs, const Zstring& rhs);
inline bool equalNativePath(const Zstring& lhs, const Zstring& rhs) { return compareNativePath(lhs, rhs) == 0; }
struct LessNativePath { bool operator()(const Zstring& lhs, const Zstring& rhs) const { return compareNativePath(lhs, rhs) < 0; } };
//------------------------------------------------------------------------------------------
int compareNatural(const Zstring& lhs, const Zstring& rhs);
struct LessNaturalSort { bool operator()(const Zstring& lhs, const Zstring& rhs) const { return compareNatural(lhs, rhs) < 0; } };
//------------------------------------------------------------------------------------------
inline
Zstring appendSeparator(Zstring path) //support rvalue references!
{
if (!zen::endsWith(path, FILE_NAME_SEPARATOR))
path += FILE_NAME_SEPARATOR;
return path; //returning a by-value parameter => RVO if possible, r-value otherwise!
}
inline
Zstring appendPaths(const Zstring& basePath, const Zstring& relPath, Zchar pathSep)
{
using namespace zen;
assert(!startsWith(relPath, pathSep) && !endsWith(relPath, pathSep));
if (relPath.empty())
return basePath;
if (basePath.empty())
return relPath;
if (startsWith(relPath, pathSep))
{
if (relPath.size() == 1)
return basePath;
if (endsWith(basePath, pathSep))
return basePath + (relPath.c_str() + 1);
}
else if (!endsWith(basePath, pathSep))
{
Zstring output = basePath;
output.reserve(basePath.size() + 1 + relPath.size()); //append all three strings using a single memory allocation
return std::move(output) + pathSep + relPath; //
}
return basePath + relPath;
}
inline Zstring nativeAppendPaths(const Zstring& basePath, const Zstring& relPath) { return appendPaths(basePath, relPath, FILE_NAME_SEPARATOR); }
inline
Zstring getFileExtension(const Zstring& filePath)
{
//const Zstring fileName = afterLast(filePath, FILE_NAME_SEPARATOR, zen::IF_MISSING_RETURN_ALL);
//return afterLast(fileName, Zstr('.'), zen::IF_MISSING_RETURN_NONE);
auto it = zen::findLast(filePath.begin(), filePath.end(), FILE_NAME_SEPARATOR);
if (it == filePath.end())
it = filePath.begin();
else
++it;
auto it2 = zen::findLast(it, filePath.end(), Zstr('.'));
if (it2 != filePath.end())
++it2;
return Zstring(it2, filePath.end());
}
//common unicode characters
const wchar_t EM_DASH = L'\u2014';
const wchar_t EN_DASH = L'\u2013';
const wchar_t* const SPACED_DASH = L" \u2013 "; //using 'EN DASH'
const wchar_t LTR_MARK = L'\u200E'; //UTF-8: E2 80 8E
const wchar_t RTL_MARK = L'\u200F'; //UTF-8: E2 80 8F
const wchar_t ELLIPSIS = L'\u2026'; //"..."
const wchar_t MULT_SIGN = L'\u00D7'; //fancy "x"
//const wchar_t NOBREAK_SPACE = L'\u00A0';
//---------------------------------------------------------------------------
//ZEN macro consistency checks:
#if defined ZEN_WIN_PRE_VISTA || defined ZEN_WIN_VISTA_AND_LATER
#error these macros are obsolete!
#endif
#endif //ZSTRING_H_73425873425789
|