diff options
author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2021-12-27 00:00:00 +0000 |
---|---|---|
committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2022-03-18 15:35:13 +0500 |
commit | f19f813537c7aea1c20749c914e756b54a9c3cf5 (patch) | |
tree | 816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /CPP/Common/MyString.h | |
parent | 98e06a519b63b81986abe76d28887f6984a7732b (diff) | |
download | 7zip-21.07.tar.gz 7zip-21.07.tar.bz2 7zip-21.07.zip |
'21.07'21.07
Diffstat (limited to 'CPP/Common/MyString.h')
-rw-r--r-- | CPP/Common/MyString.h | 1012 |
1 files changed, 1012 insertions, 0 deletions
diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h new file mode 100644 index 0000000..aa3c301 --- /dev/null +++ b/CPP/Common/MyString.h | |||
@@ -0,0 +1,1012 @@ | |||
1 | // Common/MyString.h | ||
2 | |||
3 | #ifndef __COMMON_MY_STRING_H | ||
4 | #define __COMMON_MY_STRING_H | ||
5 | |||
6 | #include <string.h> | ||
7 | |||
8 | #ifndef _WIN32 | ||
9 | #include <wctype.h> | ||
10 | #include <wchar.h> | ||
11 | #endif | ||
12 | |||
13 | #include "MyWindows.h" | ||
14 | #include "MyTypes.h" | ||
15 | #include "MyVector.h" | ||
16 | |||
17 | |||
18 | /* if (DEBUG_FSTRING_INHERITS_ASTRING is defined), then | ||
19 | FString inherits from AString, so we can find bugs related to FString at compile time. | ||
20 | DON'T define DEBUG_FSTRING_INHERITS_ASTRING in release code */ | ||
21 | |||
22 | // #define DEBUG_FSTRING_INHERITS_ASTRING | ||
23 | |||
24 | #ifdef DEBUG_FSTRING_INHERITS_ASTRING | ||
25 | class FString; | ||
26 | #endif | ||
27 | |||
28 | |||
29 | #ifdef _MSC_VER | ||
30 | #ifdef _NATIVE_WCHAR_T_DEFINED | ||
31 | #define MY_NATIVE_WCHAR_T_DEFINED | ||
32 | #endif | ||
33 | #else | ||
34 | #define MY_NATIVE_WCHAR_T_DEFINED | ||
35 | #endif | ||
36 | |||
37 | /* | ||
38 | native support for wchar_t: | ||
39 | _MSC_VER == 1600 : /Zc:wchar_t is not supported | ||
40 | _MSC_VER == 1310 (VS2003) | ||
41 | ? _MSC_VER == 1400 (VS2005) : wchar_t <- unsigned short | ||
42 | /Zc:wchar_t : wchar_t <- __wchar_t, _WCHAR_T_DEFINED and _NATIVE_WCHAR_T_DEFINED | ||
43 | _MSC_VER > 1400 (VS2008+) | ||
44 | /Zc:wchar_t[-] | ||
45 | /Zc:wchar_t is on by default | ||
46 | */ | ||
47 | |||
48 | #ifdef _WIN32 | ||
49 | #define IS_PATH_SEPAR(c) ((c) == '\\' || (c) == '/') | ||
50 | #else | ||
51 | #define IS_PATH_SEPAR(c) ((c) == CHAR_PATH_SEPARATOR) | ||
52 | #endif | ||
53 | |||
54 | inline bool IsPathSepar(char c) { return IS_PATH_SEPAR(c); } | ||
55 | inline bool IsPathSepar(wchar_t c) { return IS_PATH_SEPAR(c); } | ||
56 | |||
57 | inline unsigned MyStringLen(const char *s) | ||
58 | { | ||
59 | unsigned i; | ||
60 | for (i = 0; s[i] != 0; i++); | ||
61 | return i; | ||
62 | } | ||
63 | |||
64 | inline void MyStringCopy(char *dest, const char *src) | ||
65 | { | ||
66 | while ((*dest++ = *src++) != 0); | ||
67 | } | ||
68 | |||
69 | inline char *MyStpCpy(char *dest, const char *src) | ||
70 | { | ||
71 | for (;;) | ||
72 | { | ||
73 | char c = *src; | ||
74 | *dest = c; | ||
75 | if (c == 0) | ||
76 | return dest; | ||
77 | src++; | ||
78 | dest++; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | inline unsigned MyStringLen(const wchar_t *s) | ||
83 | { | ||
84 | unsigned i; | ||
85 | for (i = 0; s[i] != 0; i++); | ||
86 | return i; | ||
87 | } | ||
88 | |||
89 | inline void MyStringCopy(wchar_t *dest, const wchar_t *src) | ||
90 | { | ||
91 | while ((*dest++ = *src++) != 0); | ||
92 | } | ||
93 | |||
94 | inline void MyStringCat(wchar_t *dest, const wchar_t *src) | ||
95 | { | ||
96 | MyStringCopy(dest + MyStringLen(dest), src); | ||
97 | } | ||
98 | |||
99 | |||
100 | /* | ||
101 | inline wchar_t *MyWcpCpy(wchar_t *dest, const wchar_t *src) | ||
102 | { | ||
103 | for (;;) | ||
104 | { | ||
105 | wchar_t c = *src; | ||
106 | *dest = c; | ||
107 | if (c == 0) | ||
108 | return dest; | ||
109 | src++; | ||
110 | dest++; | ||
111 | } | ||
112 | } | ||
113 | */ | ||
114 | |||
115 | int FindCharPosInString(const char *s, char c) throw(); | ||
116 | int FindCharPosInString(const wchar_t *s, wchar_t c) throw(); | ||
117 | |||
118 | #ifdef _WIN32 | ||
119 | #ifndef _UNICODE | ||
120 | #define STRING_UNICODE_THROW | ||
121 | #endif | ||
122 | #endif | ||
123 | |||
124 | #ifndef STRING_UNICODE_THROW | ||
125 | #define STRING_UNICODE_THROW throw() | ||
126 | #endif | ||
127 | |||
128 | |||
129 | inline char MyCharUpper_Ascii(char c) | ||
130 | { | ||
131 | if (c >= 'a' && c <= 'z') | ||
132 | return (char)((unsigned char)c - 0x20); | ||
133 | return c; | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | inline wchar_t MyCharUpper_Ascii(wchar_t c) | ||
138 | { | ||
139 | if (c >= 'a' && c <= 'z') | ||
140 | return (wchar_t)(c - 0x20); | ||
141 | return c; | ||
142 | } | ||
143 | */ | ||
144 | |||
145 | inline char MyCharLower_Ascii(char c) | ||
146 | { | ||
147 | if (c >= 'A' && c <= 'Z') | ||
148 | return (char)((unsigned char)c + 0x20); | ||
149 | return c; | ||
150 | } | ||
151 | |||
152 | inline wchar_t MyCharLower_Ascii(wchar_t c) | ||
153 | { | ||
154 | if (c >= 'A' && c <= 'Z') | ||
155 | return (wchar_t)(c + 0x20); | ||
156 | return c; | ||
157 | } | ||
158 | |||
159 | wchar_t MyCharUpper_WIN(wchar_t c) throw(); | ||
160 | |||
161 | inline wchar_t MyCharUpper(wchar_t c) throw() | ||
162 | { | ||
163 | if (c < 'a') return c; | ||
164 | if (c <= 'z') return (wchar_t)(c - 0x20); | ||
165 | if (c <= 0x7F) return c; | ||
166 | #ifdef _WIN32 | ||
167 | #ifdef _UNICODE | ||
168 | return (wchar_t)(unsigned)(UINT_PTR)CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c); | ||
169 | #else | ||
170 | return (wchar_t)MyCharUpper_WIN(c); | ||
171 | #endif | ||
172 | #else | ||
173 | return (wchar_t)towupper((wint_t)c); | ||
174 | #endif | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | wchar_t MyCharLower_WIN(wchar_t c) throw(); | ||
179 | |||
180 | inline wchar_t MyCharLower(wchar_t c) throw() | ||
181 | { | ||
182 | if (c < 'A') return c; | ||
183 | if (c <= 'Z') return (wchar_t)(c + 0x20); | ||
184 | if (c <= 0x7F) return c; | ||
185 | #ifdef _WIN32 | ||
186 | #ifdef _UNICODE | ||
187 | return (wchar_t)(unsigned)(UINT_PTR)CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c); | ||
188 | #else | ||
189 | return (wchar_t)MyCharLower_WIN(c); | ||
190 | #endif | ||
191 | #else | ||
192 | return (wchar_t)tolower(c); | ||
193 | #endif | ||
194 | } | ||
195 | */ | ||
196 | |||
197 | // char *MyStringUpper(char *s) throw(); | ||
198 | // char *MyStringLower(char *s) throw(); | ||
199 | |||
200 | // void MyStringUpper_Ascii(char *s) throw(); | ||
201 | // void MyStringUpper_Ascii(wchar_t *s) throw(); | ||
202 | void MyStringLower_Ascii(char *s) throw(); | ||
203 | void MyStringLower_Ascii(wchar_t *s) throw(); | ||
204 | // wchar_t *MyStringUpper(wchar_t *s) STRING_UNICODE_THROW; | ||
205 | // wchar_t *MyStringLower(wchar_t *s) STRING_UNICODE_THROW; | ||
206 | |||
207 | bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw(); | ||
208 | |||
209 | bool IsString1PrefixedByString2(const char *s1, const char *s2) throw(); | ||
210 | bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw(); | ||
211 | bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw(); | ||
212 | bool IsString1PrefixedByString2_NoCase_Ascii(const char *s1, const char *s2) throw(); | ||
213 | bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *u, const char *a) throw(); | ||
214 | bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw(); | ||
215 | |||
216 | #define MyStringCompare(s1, s2) wcscmp(s1, s2) | ||
217 | int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw(); | ||
218 | // int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw(); | ||
219 | |||
220 | // ---------- ASCII ---------- | ||
221 | // char values in ASCII strings must be less then 128 | ||
222 | bool StringsAreEqual_Ascii(const char *u, const char *a) throw(); | ||
223 | bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw(); | ||
224 | bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw(); | ||
225 | bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw(); | ||
226 | bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw(); | ||
227 | |||
228 | #define MY_STRING_DELETE(_p_) delete []_p_; | ||
229 | // #define MY_STRING_DELETE(_p_) my_delete(_p_); | ||
230 | |||
231 | |||
232 | #define FORBID_STRING_OPS_2(cls, t) \ | ||
233 | void Find(t) const; \ | ||
234 | void Find(t, unsigned startIndex) const; \ | ||
235 | void ReverseFind(t) const; \ | ||
236 | void InsertAtFront(t); \ | ||
237 | void RemoveChar(t); \ | ||
238 | void Replace(t, t); \ | ||
239 | |||
240 | #define FORBID_STRING_OPS(cls, t) \ | ||
241 | explicit cls(t); \ | ||
242 | explicit cls(const t *); \ | ||
243 | cls &operator=(t); \ | ||
244 | cls &operator=(const t *); \ | ||
245 | cls &operator+=(t); \ | ||
246 | cls &operator+=(const t *); \ | ||
247 | FORBID_STRING_OPS_2(cls, t) \ | ||
248 | |||
249 | /* | ||
250 | cls &operator+(t); \ | ||
251 | cls &operator+(const t *); \ | ||
252 | */ | ||
253 | |||
254 | #define FORBID_STRING_OPS_AString(t) FORBID_STRING_OPS(AString, t) | ||
255 | #define FORBID_STRING_OPS_UString(t) FORBID_STRING_OPS(UString, t) | ||
256 | #define FORBID_STRING_OPS_UString2(t) FORBID_STRING_OPS(UString2, t) | ||
257 | |||
258 | class AString | ||
259 | { | ||
260 | char *_chars; | ||
261 | unsigned _len; | ||
262 | unsigned _limit; | ||
263 | |||
264 | void MoveItems(unsigned dest, unsigned src) | ||
265 | { | ||
266 | memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(char)); | ||
267 | } | ||
268 | |||
269 | void InsertSpace(unsigned &index, unsigned size); | ||
270 | |||
271 | void ReAlloc(unsigned newLimit); | ||
272 | void ReAlloc2(unsigned newLimit); | ||
273 | void SetStartLen(unsigned len); | ||
274 | void Grow_1(); | ||
275 | void Grow(unsigned n); | ||
276 | |||
277 | AString(unsigned num, const char *s); | ||
278 | AString(unsigned num, const AString &s); | ||
279 | AString(const AString &s, char c); // it's for String + char | ||
280 | AString(const char *s1, unsigned num1, const char *s2, unsigned num2); | ||
281 | |||
282 | friend AString operator+(const AString &s, char c) { return AString(s, c); } | ||
283 | // friend AString operator+(char c, const AString &s); // is not supported | ||
284 | |||
285 | friend AString operator+(const AString &s1, const AString &s2); | ||
286 | friend AString operator+(const AString &s1, const char *s2); | ||
287 | friend AString operator+(const char *s1, const AString &s2); | ||
288 | |||
289 | // ---------- forbidden functions ---------- | ||
290 | |||
291 | #ifdef MY_NATIVE_WCHAR_T_DEFINED | ||
292 | FORBID_STRING_OPS_AString(wchar_t) | ||
293 | #endif | ||
294 | |||
295 | FORBID_STRING_OPS_AString(signed char) | ||
296 | FORBID_STRING_OPS_AString(unsigned char) | ||
297 | FORBID_STRING_OPS_AString(short) | ||
298 | FORBID_STRING_OPS_AString(unsigned short) | ||
299 | FORBID_STRING_OPS_AString(int) | ||
300 | FORBID_STRING_OPS_AString(unsigned) | ||
301 | FORBID_STRING_OPS_AString(long) | ||
302 | FORBID_STRING_OPS_AString(unsigned long) | ||
303 | |||
304 | #ifdef DEBUG_FSTRING_INHERITS_ASTRING | ||
305 | AString(const FString &s); | ||
306 | AString &operator=(const FString &s); | ||
307 | AString &operator+=(const FString &s); | ||
308 | #endif | ||
309 | |||
310 | public: | ||
311 | explicit AString(); | ||
312 | explicit AString(char c); | ||
313 | explicit AString(const char *s); | ||
314 | AString(const AString &s); | ||
315 | ~AString() { MY_STRING_DELETE(_chars); } | ||
316 | |||
317 | unsigned Len() const { return _len; } | ||
318 | bool IsEmpty() const { return _len == 0; } | ||
319 | void Empty() { _len = 0; _chars[0] = 0; } | ||
320 | |||
321 | operator const char *() const { return _chars; } | ||
322 | char *Ptr_non_const() const { return _chars; } | ||
323 | const char *Ptr() const { return _chars; } | ||
324 | const char *Ptr(unsigned pos) const { return _chars + pos; } | ||
325 | const char *RightPtr(unsigned num) const { return _chars + _len - num; } | ||
326 | char Back() const { return _chars[(size_t)_len - 1]; } | ||
327 | |||
328 | void ReplaceOneCharAtPos(unsigned pos, char c) { _chars[pos] = c; } | ||
329 | |||
330 | char *GetBuf() { return _chars; } | ||
331 | /* GetBuf(minLen): provides the buffer that can store | ||
332 | at least (minLen) characters and additional null terminator. | ||
333 | 9.35: GetBuf doesn't preserve old characters and terminator */ | ||
334 | char *GetBuf(unsigned minLen) | ||
335 | { | ||
336 | if (minLen > _limit) | ||
337 | ReAlloc2(minLen); | ||
338 | return _chars; | ||
339 | } | ||
340 | char *GetBuf_SetEnd(unsigned minLen) | ||
341 | { | ||
342 | if (minLen > _limit) | ||
343 | ReAlloc2(minLen); | ||
344 | char *chars = _chars; | ||
345 | chars[minLen] = 0; | ||
346 | _len = minLen; | ||
347 | return chars; | ||
348 | } | ||
349 | |||
350 | void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; } | ||
351 | void ReleaseBuf_SetEnd(unsigned newLen) { _len = newLen; _chars[newLen] = 0; } | ||
352 | void ReleaseBuf_CalcLen(unsigned maxLen) | ||
353 | { | ||
354 | char *chars = _chars; | ||
355 | chars[maxLen] = 0; | ||
356 | _len = MyStringLen(chars); | ||
357 | } | ||
358 | |||
359 | AString &operator=(char c); | ||
360 | AString &operator=(const char *s); | ||
361 | AString &operator=(const AString &s); | ||
362 | void SetFromWStr_if_Ascii(const wchar_t *s); | ||
363 | // void SetFromBstr_if_Ascii(BSTR s); | ||
364 | |||
365 | AString &operator+=(char c) | ||
366 | { | ||
367 | if (_limit == _len) | ||
368 | Grow_1(); | ||
369 | unsigned len = _len; | ||
370 | char *chars = _chars; | ||
371 | chars[len++] = c; | ||
372 | chars[len] = 0; | ||
373 | _len = len; | ||
374 | return *this; | ||
375 | } | ||
376 | |||
377 | void Add_Space(); | ||
378 | void Add_Space_if_NotEmpty(); | ||
379 | void Add_OptSpaced(const char *s); | ||
380 | void Add_LF(); | ||
381 | void Add_PathSepar() { operator+=(CHAR_PATH_SEPARATOR); } | ||
382 | |||
383 | AString &operator+=(const char *s); | ||
384 | AString &operator+=(const AString &s); | ||
385 | |||
386 | void Add_UInt32(UInt32 v); | ||
387 | void Add_UInt64(UInt64 v); | ||
388 | |||
389 | void SetFrom(const char *s, unsigned len); // no check | ||
390 | void SetFrom_CalcLen(const char *s, unsigned len); | ||
391 | |||
392 | AString Mid(unsigned startIndex, unsigned count) const { return AString(count, _chars + startIndex); } | ||
393 | AString Left(unsigned count) const { return AString(count, *this); } | ||
394 | |||
395 | // void MakeUpper() { MyStringUpper(_chars); } | ||
396 | // void MakeLower() { MyStringLower(_chars); } | ||
397 | void MakeLower_Ascii() { MyStringLower_Ascii(_chars); } | ||
398 | |||
399 | |||
400 | bool IsEqualTo(const char *s) const { return strcmp(_chars, s) == 0; } | ||
401 | bool IsEqualTo_Ascii_NoCase(const char *s) const { return StringsAreEqualNoCase_Ascii(_chars, s); } | ||
402 | // int Compare(const char *s) const { return MyStringCompare(_chars, s); } | ||
403 | // int Compare(const AString &s) const { return MyStringCompare(_chars, s._chars); } | ||
404 | // int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); } | ||
405 | // int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); } | ||
406 | bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); } | ||
407 | bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); | ||
408 | |||
409 | bool IsAscii() const | ||
410 | { | ||
411 | unsigned len = Len(); | ||
412 | const char *s = _chars; | ||
413 | for (unsigned i = 0; i < len; i++) | ||
414 | if ((unsigned char)s[i] >= 0x80) | ||
415 | return false; | ||
416 | return true; | ||
417 | } | ||
418 | int Find(char c) const { return FindCharPosInString(_chars, c); } | ||
419 | int Find(char c, unsigned startIndex) const | ||
420 | { | ||
421 | int pos = FindCharPosInString(_chars + startIndex, c); | ||
422 | return pos < 0 ? -1 : (int)startIndex + pos; | ||
423 | } | ||
424 | |||
425 | int ReverseFind(char c) const throw(); | ||
426 | int ReverseFind_Dot() const throw() { return ReverseFind('.'); } | ||
427 | int ReverseFind_PathSepar() const throw(); | ||
428 | |||
429 | int Find(const char *s) const { return Find(s, 0); } | ||
430 | int Find(const char *s, unsigned startIndex) const throw(); | ||
431 | |||
432 | void TrimLeft() throw(); | ||
433 | void TrimRight() throw(); | ||
434 | void Trim() | ||
435 | { | ||
436 | TrimRight(); | ||
437 | TrimLeft(); | ||
438 | } | ||
439 | |||
440 | void InsertAtFront(char c); | ||
441 | // void Insert(unsigned index, char c); | ||
442 | void Insert(unsigned index, const char *s); | ||
443 | void Insert(unsigned index, const AString &s); | ||
444 | |||
445 | void RemoveChar(char ch) throw(); | ||
446 | |||
447 | void Replace(char oldChar, char newChar) throw(); | ||
448 | void Replace(const AString &oldString, const AString &newString); | ||
449 | |||
450 | void Delete(unsigned index) throw(); | ||
451 | void Delete(unsigned index, unsigned count) throw(); | ||
452 | void DeleteFrontal(unsigned num) throw(); | ||
453 | void DeleteBack() { _chars[--_len] = 0; } | ||
454 | void DeleteFrom(unsigned index) | ||
455 | { | ||
456 | if (index < _len) | ||
457 | { | ||
458 | _len = index; | ||
459 | _chars[index] = 0; | ||
460 | } | ||
461 | } | ||
462 | |||
463 | void Wipe_and_Empty() | ||
464 | { | ||
465 | if (_chars) | ||
466 | { | ||
467 | memset(_chars, 0, (_limit + 1) * sizeof(*_chars)); | ||
468 | _len = 0; | ||
469 | } | ||
470 | } | ||
471 | }; | ||
472 | |||
473 | |||
474 | class AString_Wipe: public AString | ||
475 | { | ||
476 | CLASS_NO_COPY(AString_Wipe) | ||
477 | public: | ||
478 | AString_Wipe(): AString() {} | ||
479 | // AString_Wipe(const AString &s): AString(s) {} | ||
480 | // AString_Wipe &operator=(const AString &s) { AString::operator=(s); return *this; } | ||
481 | // AString_Wipe &operator=(const char *s) { AString::operator=(s); return *this; } | ||
482 | ~AString_Wipe() { Wipe_and_Empty(); } | ||
483 | }; | ||
484 | |||
485 | |||
486 | bool operator<(const AString &s1, const AString &s2); | ||
487 | bool operator>(const AString &s1, const AString &s2); | ||
488 | |||
489 | /* | ||
490 | bool operator==(const AString &s1, const AString &s2); | ||
491 | bool operator==(const AString &s1, const char *s2); | ||
492 | bool operator==(const char *s1, const AString &s2); | ||
493 | |||
494 | bool operator!=(const AString &s1, const AString &s2); | ||
495 | bool operator!=(const AString &s1, const char *s2); | ||
496 | bool operator!=(const char *s1, const AString &s2); | ||
497 | */ | ||
498 | |||
499 | inline bool operator==(const AString &s1, const AString &s2) { return s1.Len() == s2.Len() && strcmp(s1, s2) == 0; } | ||
500 | inline bool operator==(const AString &s1, const char *s2) { return strcmp(s1, s2) == 0; } | ||
501 | inline bool operator==(const char *s1, const AString &s2) { return strcmp(s1, s2) == 0; } | ||
502 | |||
503 | inline bool operator!=(const AString &s1, const AString &s2) { return s1.Len() != s2.Len() || strcmp(s1, s2) != 0; } | ||
504 | inline bool operator!=(const AString &s1, const char *s2) { return strcmp(s1, s2) != 0; } | ||
505 | inline bool operator!=(const char *s1, const AString &s2) { return strcmp(s1, s2) != 0; } | ||
506 | |||
507 | // ---------- forbidden functions ---------- | ||
508 | |||
509 | void operator==(char c1, const AString &s2); | ||
510 | void operator==(const AString &s1, char c2); | ||
511 | |||
512 | void operator+(char c, const AString &s); // this function can be OK, but we don't use it | ||
513 | |||
514 | void operator+(const AString &s, int c); | ||
515 | void operator+(const AString &s, unsigned c); | ||
516 | void operator+(int c, const AString &s); | ||
517 | void operator+(unsigned c, const AString &s); | ||
518 | void operator-(const AString &s, int c); | ||
519 | void operator-(const AString &s, unsigned c); | ||
520 | |||
521 | |||
522 | class UString | ||
523 | { | ||
524 | wchar_t *_chars; | ||
525 | unsigned _len; | ||
526 | unsigned _limit; | ||
527 | |||
528 | void MoveItems(unsigned dest, unsigned src) | ||
529 | { | ||
530 | memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(wchar_t)); | ||
531 | } | ||
532 | |||
533 | void InsertSpace(unsigned index, unsigned size); | ||
534 | |||
535 | void ReAlloc(unsigned newLimit); | ||
536 | void ReAlloc2(unsigned newLimit); | ||
537 | void SetStartLen(unsigned len); | ||
538 | void Grow_1(); | ||
539 | void Grow(unsigned n); | ||
540 | |||
541 | UString(unsigned num, const wchar_t *s); // for Mid | ||
542 | UString(unsigned num, const UString &s); // for Left | ||
543 | UString(const UString &s, wchar_t c); // it's for String + char | ||
544 | UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2); | ||
545 | |||
546 | friend UString operator+(const UString &s, wchar_t c) { return UString(s, c); } | ||
547 | // friend UString operator+(wchar_t c, const UString &s); // is not supported | ||
548 | |||
549 | friend UString operator+(const UString &s1, const UString &s2); | ||
550 | friend UString operator+(const UString &s1, const wchar_t *s2); | ||
551 | friend UString operator+(const wchar_t *s1, const UString &s2); | ||
552 | |||
553 | // ---------- forbidden functions ---------- | ||
554 | |||
555 | FORBID_STRING_OPS_UString(signed char) | ||
556 | FORBID_STRING_OPS_UString(unsigned char) | ||
557 | FORBID_STRING_OPS_UString(short) | ||
558 | |||
559 | #ifdef MY_NATIVE_WCHAR_T_DEFINED | ||
560 | FORBID_STRING_OPS_UString(unsigned short) | ||
561 | #endif | ||
562 | |||
563 | FORBID_STRING_OPS_UString(int) | ||
564 | FORBID_STRING_OPS_UString(unsigned) | ||
565 | FORBID_STRING_OPS_UString(long) | ||
566 | FORBID_STRING_OPS_UString(unsigned long) | ||
567 | |||
568 | FORBID_STRING_OPS_2(UString, char) | ||
569 | |||
570 | #ifdef DEBUG_FSTRING_INHERITS_ASTRING | ||
571 | UString(const FString &s); | ||
572 | UString &operator=(const FString &s); | ||
573 | UString &operator+=(const FString &s); | ||
574 | #endif | ||
575 | |||
576 | public: | ||
577 | UString(); | ||
578 | explicit UString(wchar_t c); | ||
579 | explicit UString(char c); | ||
580 | explicit UString(const char *s); | ||
581 | explicit UString(const AString &s); | ||
582 | UString(const wchar_t *s); | ||
583 | UString(const UString &s); | ||
584 | ~UString() { MY_STRING_DELETE(_chars); } | ||
585 | |||
586 | unsigned Len() const { return _len; } | ||
587 | bool IsEmpty() const { return _len == 0; } | ||
588 | void Empty() { _len = 0; _chars[0] = 0; } | ||
589 | |||
590 | operator const wchar_t *() const { return _chars; } | ||
591 | wchar_t *Ptr_non_const() const { return _chars; } | ||
592 | const wchar_t *Ptr() const { return _chars; } | ||
593 | const wchar_t *Ptr(unsigned pos) const { return _chars + pos; } | ||
594 | const wchar_t *RightPtr(unsigned num) const { return _chars + _len - num; } | ||
595 | wchar_t Back() const { return _chars[(size_t)_len - 1]; } | ||
596 | |||
597 | void ReplaceOneCharAtPos(unsigned pos, wchar_t c) { _chars[pos] = c; } | ||
598 | |||
599 | wchar_t *GetBuf() { return _chars; } | ||
600 | |||
601 | wchar_t *GetBuf(unsigned minLen) | ||
602 | { | ||
603 | if (minLen > _limit) | ||
604 | ReAlloc2(minLen); | ||
605 | return _chars; | ||
606 | } | ||
607 | wchar_t *GetBuf_SetEnd(unsigned minLen) | ||
608 | { | ||
609 | if (minLen > _limit) | ||
610 | ReAlloc2(minLen); | ||
611 | wchar_t *chars = _chars; | ||
612 | chars[minLen] = 0; | ||
613 | _len = minLen; | ||
614 | return chars; | ||
615 | } | ||
616 | |||
617 | void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; } | ||
618 | void ReleaseBuf_SetEnd(unsigned newLen) { _len = newLen; _chars[newLen] = 0; } | ||
619 | void ReleaseBuf_CalcLen(unsigned maxLen) | ||
620 | { | ||
621 | wchar_t *chars = _chars; | ||
622 | chars[maxLen] = 0; | ||
623 | _len = MyStringLen(chars); | ||
624 | } | ||
625 | |||
626 | UString &operator=(wchar_t c); | ||
627 | UString &operator=(char c) { return (*this)=((wchar_t)(unsigned char)c); } | ||
628 | UString &operator=(const wchar_t *s); | ||
629 | UString &operator=(const UString &s); | ||
630 | void SetFrom(const wchar_t *s, unsigned len); // no check | ||
631 | void SetFromBstr(LPCOLESTR s); | ||
632 | UString &operator=(const char *s); | ||
633 | UString &operator=(const AString &s) { return operator=(s.Ptr()); } | ||
634 | |||
635 | UString &operator+=(wchar_t c) | ||
636 | { | ||
637 | if (_limit == _len) | ||
638 | Grow_1(); | ||
639 | unsigned len = _len; | ||
640 | wchar_t *chars = _chars; | ||
641 | chars[len++] = c; | ||
642 | chars[len] = 0; | ||
643 | _len = len; | ||
644 | return *this; | ||
645 | } | ||
646 | |||
647 | UString &operator+=(char c) { return (*this)+=((wchar_t)(unsigned char)c); } | ||
648 | |||
649 | void Add_Space(); | ||
650 | void Add_Space_if_NotEmpty(); | ||
651 | void Add_LF(); | ||
652 | void Add_PathSepar() { operator+=(WCHAR_PATH_SEPARATOR); } | ||
653 | |||
654 | UString &operator+=(const wchar_t *s); | ||
655 | UString &operator+=(const UString &s); | ||
656 | UString &operator+=(const char *s); | ||
657 | UString &operator+=(const AString &s) { return operator+=(s.Ptr()); } | ||
658 | |||
659 | void Add_UInt32(UInt32 v); | ||
660 | void Add_UInt64(UInt64 v); | ||
661 | |||
662 | UString Mid(unsigned startIndex, unsigned count) const { return UString(count, _chars + startIndex); } | ||
663 | UString Left(unsigned count) const { return UString(count, *this); } | ||
664 | |||
665 | // void MakeUpper() { MyStringUpper(_chars); } | ||
666 | // void MakeUpper() { MyStringUpper_Ascii(_chars); } | ||
667 | // void MakeUpper_Ascii() { MyStringUpper_Ascii(_chars); } | ||
668 | void MakeLower_Ascii() { MyStringLower_Ascii(_chars); } | ||
669 | |||
670 | bool IsEqualTo(const char *s) const { return StringsAreEqual_Ascii(_chars, s); } | ||
671 | bool IsEqualTo_NoCase(const wchar_t *s) const { return StringsAreEqualNoCase(_chars, s); } | ||
672 | bool IsEqualTo_Ascii_NoCase(const char *s) const { return StringsAreEqualNoCase_Ascii(_chars, s); } | ||
673 | int Compare(const wchar_t *s) const { return wcscmp(_chars, s); } | ||
674 | // int Compare(const UString &s) const { return MyStringCompare(_chars, s._chars); } | ||
675 | // int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); } | ||
676 | // int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); } | ||
677 | bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); } | ||
678 | bool IsPrefixedBy_NoCase(const wchar_t *s) const { return IsString1PrefixedByString2_NoCase(_chars, s); } | ||
679 | bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); | ||
680 | |||
681 | bool IsAscii() const | ||
682 | { | ||
683 | unsigned len = Len(); | ||
684 | const wchar_t *s = _chars; | ||
685 | for (unsigned i = 0; i < len; i++) | ||
686 | if (s[i] >= 0x80) | ||
687 | return false; | ||
688 | return true; | ||
689 | } | ||
690 | int Find(wchar_t c) const { return FindCharPosInString(_chars, c); } | ||
691 | int Find(wchar_t c, unsigned startIndex) const | ||
692 | { | ||
693 | int pos = FindCharPosInString(_chars + startIndex, c); | ||
694 | return pos < 0 ? -1 : (int)startIndex + pos; | ||
695 | } | ||
696 | |||
697 | int ReverseFind(wchar_t c) const throw(); | ||
698 | int ReverseFind_Dot() const throw() { return ReverseFind(L'.'); } | ||
699 | int ReverseFind_PathSepar() const throw(); | ||
700 | |||
701 | int Find(const wchar_t *s) const { return Find(s, 0); } | ||
702 | int Find(const wchar_t *s, unsigned startIndex) const throw(); | ||
703 | |||
704 | void TrimLeft() throw(); | ||
705 | void TrimRight() throw(); | ||
706 | void Trim() | ||
707 | { | ||
708 | TrimRight(); | ||
709 | TrimLeft(); | ||
710 | } | ||
711 | |||
712 | void InsertAtFront(wchar_t c); | ||
713 | // void Insert_wchar_t(unsigned index, wchar_t c); | ||
714 | void Insert(unsigned index, const wchar_t *s); | ||
715 | void Insert(unsigned index, const UString &s); | ||
716 | |||
717 | void RemoveChar(wchar_t ch) throw(); | ||
718 | |||
719 | void Replace(wchar_t oldChar, wchar_t newChar) throw(); | ||
720 | void Replace(const UString &oldString, const UString &newString); | ||
721 | |||
722 | void Delete(unsigned index) throw(); | ||
723 | void Delete(unsigned index, unsigned count) throw(); | ||
724 | void DeleteFrontal(unsigned num) throw(); | ||
725 | void DeleteBack() { _chars[--_len] = 0; } | ||
726 | void DeleteFrom(unsigned index) | ||
727 | { | ||
728 | if (index < _len) | ||
729 | { | ||
730 | _len = index; | ||
731 | _chars[index] = 0; | ||
732 | } | ||
733 | } | ||
734 | |||
735 | void Wipe_and_Empty() | ||
736 | { | ||
737 | if (_chars) | ||
738 | { | ||
739 | memset(_chars, 0, (_limit + 1) * sizeof(*_chars)); | ||
740 | _len = 0; | ||
741 | } | ||
742 | } | ||
743 | }; | ||
744 | |||
745 | |||
746 | class UString_Wipe: public UString | ||
747 | { | ||
748 | CLASS_NO_COPY(UString_Wipe) | ||
749 | public: | ||
750 | UString_Wipe(): UString() {} | ||
751 | // UString_Wipe(const UString &s): UString(s) {} | ||
752 | // UString_Wipe &operator=(const UString &s) { UString::operator=(s); return *this; } | ||
753 | // UString_Wipe &operator=(const wchar_t *s) { UString::operator=(s); return *this; } | ||
754 | ~UString_Wipe() { Wipe_and_Empty(); } | ||
755 | }; | ||
756 | |||
757 | |||
758 | bool operator<(const UString &s1, const UString &s2); | ||
759 | bool operator>(const UString &s1, const UString &s2); | ||
760 | |||
761 | inline bool operator==(const UString &s1, const UString &s2) { return s1.Len() == s2.Len() && wcscmp(s1, s2) == 0; } | ||
762 | inline bool operator==(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) == 0; } | ||
763 | inline bool operator==(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) == 0; } | ||
764 | |||
765 | inline bool operator!=(const UString &s1, const UString &s2) { return s1.Len() != s2.Len() || wcscmp(s1, s2) != 0; } | ||
766 | inline bool operator!=(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) != 0; } | ||
767 | inline bool operator!=(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) != 0; } | ||
768 | |||
769 | |||
770 | // ---------- forbidden functions ---------- | ||
771 | |||
772 | void operator==(wchar_t c1, const UString &s2); | ||
773 | void operator==(const UString &s1, wchar_t c2); | ||
774 | |||
775 | void operator+(wchar_t c, const UString &s); // this function can be OK, but we don't use it | ||
776 | |||
777 | void operator+(const AString &s1, const UString &s2); | ||
778 | void operator+(const UString &s1, const AString &s2); | ||
779 | |||
780 | void operator+(const UString &s1, const char *s2); | ||
781 | void operator+(const char *s1, const UString &s2); | ||
782 | |||
783 | void operator+(const UString &s, char c); | ||
784 | void operator+(const UString &s, unsigned char c); | ||
785 | void operator+(char c, const UString &s); | ||
786 | void operator+(unsigned char c, const UString &s); | ||
787 | void operator-(const UString &s1, wchar_t c); | ||
788 | |||
789 | #ifdef _WIN32 | ||
790 | // can we forbid these functions, if wchar_t is 32-bit ? | ||
791 | void operator+(const UString &s, int c); | ||
792 | void operator+(const UString &s, unsigned c); | ||
793 | void operator+(int c, const UString &s); | ||
794 | void operator+(unsigned c, const UString &s); | ||
795 | void operator-(const UString &s1, int c); | ||
796 | void operator-(const UString &s1, unsigned c); | ||
797 | #endif | ||
798 | |||
799 | |||
800 | |||
801 | |||
802 | |||
803 | |||
804 | |||
805 | class UString2 | ||
806 | { | ||
807 | wchar_t *_chars; | ||
808 | unsigned _len; | ||
809 | |||
810 | void ReAlloc2(unsigned newLimit); | ||
811 | void SetStartLen(unsigned len); | ||
812 | |||
813 | // ---------- forbidden functions ---------- | ||
814 | |||
815 | FORBID_STRING_OPS_UString2(char) | ||
816 | FORBID_STRING_OPS_UString2(signed char) | ||
817 | FORBID_STRING_OPS_UString2(unsigned char) | ||
818 | FORBID_STRING_OPS_UString2(short) | ||
819 | |||
820 | UString2 &operator=(wchar_t c); | ||
821 | |||
822 | UString2(const AString &s); | ||
823 | UString2 &operator=(const AString &s); | ||
824 | UString2 &operator+=(const AString &s); | ||
825 | |||
826 | #ifdef DEBUG_FSTRING_INHERITS_ASTRING | ||
827 | UString2(const FString &s); | ||
828 | UString2 &operator=(const FString &s); | ||
829 | UString2 &operator+=(const FString &s); | ||
830 | #endif | ||
831 | |||
832 | public: | ||
833 | UString2(): _chars(NULL), _len(0) {} | ||
834 | UString2(const wchar_t *s); | ||
835 | UString2(const UString2 &s); | ||
836 | ~UString2() { if (_chars) MY_STRING_DELETE(_chars); } | ||
837 | |||
838 | unsigned Len() const { return _len; } | ||
839 | bool IsEmpty() const { return _len == 0; } | ||
840 | // void Empty() { _len = 0; _chars[0] = 0; } | ||
841 | |||
842 | // operator const wchar_t *() const { return _chars; } | ||
843 | const wchar_t *GetRawPtr() const { return _chars; } | ||
844 | |||
845 | int Compare(const wchar_t *s) const { return wcscmp(_chars, s); } | ||
846 | |||
847 | wchar_t *GetBuf(unsigned minLen) | ||
848 | { | ||
849 | if (!_chars || minLen > _len) | ||
850 | ReAlloc2(minLen); | ||
851 | return _chars; | ||
852 | } | ||
853 | void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; } | ||
854 | |||
855 | UString2 &operator=(const wchar_t *s); | ||
856 | UString2 &operator=(const UString2 &s); | ||
857 | void SetFromAscii(const char *s); | ||
858 | }; | ||
859 | |||
860 | bool operator==(const UString2 &s1, const UString2 &s2); | ||
861 | bool operator==(const UString2 &s1, const wchar_t *s2); | ||
862 | bool operator==(const wchar_t *s1, const UString2 &s2); | ||
863 | |||
864 | inline bool operator!=(const UString2 &s1, const UString2 &s2) { return !(s1 == s2); } | ||
865 | inline bool operator!=(const UString2 &s1, const wchar_t *s2) { return !(s1 == s2); } | ||
866 | inline bool operator!=(const wchar_t *s1, const UString2 &s2) { return !(s1 == s2); } | ||
867 | |||
868 | |||
869 | // ---------- forbidden functions ---------- | ||
870 | |||
871 | void operator==(wchar_t c1, const UString2 &s2); | ||
872 | void operator==(const UString2 &s1, wchar_t c2); | ||
873 | bool operator<(const UString2 &s1, const UString2 &s2); | ||
874 | bool operator>(const UString2 &s1, const UString2 &s2); | ||
875 | |||
876 | void operator+(const UString2 &s1, const UString2 &s2); | ||
877 | void operator+(const UString2 &s1, const wchar_t *s2); | ||
878 | void operator+(const wchar_t *s1, const UString2 &s2); | ||
879 | void operator+(wchar_t c, const UString2 &s); | ||
880 | void operator+(const UString2 &s, wchar_t c); | ||
881 | void operator+(const UString2 &s, char c); | ||
882 | void operator+(const UString2 &s, unsigned char c); | ||
883 | void operator+(char c, const UString2 &s); | ||
884 | void operator+(unsigned char c, const UString2 &s); | ||
885 | void operator-(const UString2 &s1, wchar_t c); | ||
886 | |||
887 | |||
888 | |||
889 | |||
890 | |||
891 | |||
892 | typedef CObjectVector<AString> AStringVector; | ||
893 | typedef CObjectVector<UString> UStringVector; | ||
894 | |||
895 | #ifdef _UNICODE | ||
896 | typedef UString CSysString; | ||
897 | #else | ||
898 | typedef AString CSysString; | ||
899 | #endif | ||
900 | |||
901 | typedef CObjectVector<CSysString> CSysStringVector; | ||
902 | |||
903 | |||
904 | // ---------- FString ---------- | ||
905 | |||
906 | #ifndef DEBUG_FSTRING_INHERITS_ASTRING | ||
907 | #ifdef _WIN32 | ||
908 | #define USE_UNICODE_FSTRING | ||
909 | #endif | ||
910 | #endif | ||
911 | |||
912 | #ifdef USE_UNICODE_FSTRING | ||
913 | |||
914 | #define __FTEXT(quote) L##quote | ||
915 | |||
916 | typedef wchar_t FChar; | ||
917 | typedef UString FString; | ||
918 | |||
919 | #define fs2us(_x_) (_x_) | ||
920 | #define us2fs(_x_) (_x_) | ||
921 | FString fas2fs(const char *s); | ||
922 | FString fas2fs(const AString &s); | ||
923 | AString fs2fas(const FChar *s); | ||
924 | |||
925 | #else | ||
926 | |||
927 | #define __FTEXT(quote) quote | ||
928 | |||
929 | typedef char FChar; | ||
930 | |||
931 | #ifdef DEBUG_FSTRING_INHERITS_ASTRING | ||
932 | |||
933 | class FString: public AString | ||
934 | { | ||
935 | // FString &operator=(const char *s); | ||
936 | FString &operator=(const AString &s); | ||
937 | // FString &operator+=(const AString &s); | ||
938 | public: | ||
939 | FString(const AString &s): AString(s.Ptr()) {} | ||
940 | FString(const FString &s): AString(s.Ptr()) {} | ||
941 | FString(const char *s): AString(s) {} | ||
942 | FString() {} | ||
943 | FString &operator=(const FString &s) { AString::operator=((const AString &)s); return *this; } | ||
944 | FString &operator=(char c) { AString::operator=(c); return *this; } | ||
945 | FString &operator+=(char c) { AString::operator+=(c); return *this; } | ||
946 | FString &operator+=(const FString &s) { AString::operator+=((const AString &)s); return *this; } | ||
947 | FString Left(unsigned count) const { return FString(AString::Left(count)); } | ||
948 | }; | ||
949 | void operator+(const AString &s1, const FString &s2); | ||
950 | void operator+(const FString &s1, const AString &s2); | ||
951 | |||
952 | inline FString operator+(const FString &s1, const FString &s2) | ||
953 | { | ||
954 | AString s =(const AString &)s1 + (const AString &)s2; | ||
955 | return FString(s.Ptr()); | ||
956 | // return FString((const AString &)s1 + (const AString &)s2); | ||
957 | } | ||
958 | inline FString operator+(const FString &s1, const FChar *s2) | ||
959 | { | ||
960 | return s1 + (FString)s2; | ||
961 | } | ||
962 | /* | ||
963 | inline FString operator+(const FChar *s1, const FString &s2) | ||
964 | { | ||
965 | return (FString)s1 + s2; | ||
966 | } | ||
967 | */ | ||
968 | |||
969 | inline FString fas2fs(const char *s) { return FString(s); } | ||
970 | |||
971 | #else // DEBUG_FSTRING_INHERITS_ASTRING | ||
972 | typedef AString FString; | ||
973 | #define fas2fs(_x_) (_x_) | ||
974 | #endif // DEBUG_FSTRING_INHERITS_ASTRING | ||
975 | |||
976 | UString fs2us(const FChar *s); | ||
977 | UString fs2us(const FString &s); | ||
978 | FString us2fs(const wchar_t *s); | ||
979 | #define fs2fas(_x_) (_x_) | ||
980 | |||
981 | #endif | ||
982 | |||
983 | #define FTEXT(quote) __FTEXT(quote) | ||
984 | |||
985 | #define FCHAR_PATH_SEPARATOR FTEXT(CHAR_PATH_SEPARATOR) | ||
986 | #define FSTRING_PATH_SEPARATOR FTEXT(STRING_PATH_SEPARATOR) | ||
987 | |||
988 | // #define FCHAR_ANY_MASK FTEXT('*') | ||
989 | // #define FSTRING_ANY_MASK FTEXT("*") | ||
990 | |||
991 | typedef const FChar *CFSTR; | ||
992 | |||
993 | typedef CObjectVector<FString> FStringVector; | ||
994 | |||
995 | #endif | ||
996 | |||
997 | |||
998 | |||
999 | #if defined(_WIN32) | ||
1000 | // #include <wchar.h> | ||
1001 | // WCHAR_MAX is defined as ((wchar_t)-1) | ||
1002 | #define _WCHART_IS_16BIT 1 | ||
1003 | #elif (defined(WCHAR_MAX) && (WCHAR_MAX <= 0xffff)) \ | ||
1004 | || (defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ == 2)) | ||
1005 | #define _WCHART_IS_16BIT 1 | ||
1006 | #endif | ||
1007 | |||
1008 | #if WCHAR_PATH_SEPARATOR == L'\\' | ||
1009 | // WSL scheme | ||
1010 | #define WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT ((wchar_t)((unsigned)(0xF000) + (unsigned)'\\')) | ||
1011 | // #define WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT '_' | ||
1012 | #endif | ||