1733 lines
32 KiB
C++
1733 lines
32 KiB
C++
// Common/MyString.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#ifdef _WIN32
|
|
#include <wchar.h>
|
|
#else
|
|
#include <ctype.h>
|
|
#endif
|
|
|
|
#if !defined(_UNICODE) || !defined(USE_UNICODE_FSTRING)
|
|
#include "StringConvert.h"
|
|
#endif
|
|
|
|
#include "MyString.h"
|
|
|
|
#define MY_STRING_NEW(_T_, _size_) new _T_[_size_]
|
|
// #define MY_STRING_NEW(_T_, _size_) ((_T_ *)my_new((size_t)(_size_) * sizeof(_T_)))
|
|
|
|
/*
|
|
inline const char* MyStringGetNextCharPointer(const char *p) throw()
|
|
{
|
|
#if defined(_WIN32) && !defined(UNDER_CE)
|
|
return CharNextA(p);
|
|
#else
|
|
return p + 1;
|
|
#endif
|
|
}
|
|
*/
|
|
|
|
int FindCharPosInString(const char *s, char c) throw()
|
|
{
|
|
for (const char *p = s;; p++)
|
|
{
|
|
if (*p == c)
|
|
return (int)(p - s);
|
|
if (*p == 0)
|
|
return -1;
|
|
// MyStringGetNextCharPointer(p);
|
|
}
|
|
}
|
|
|
|
int FindCharPosInString(const wchar_t *s, wchar_t c) throw()
|
|
{
|
|
for (const wchar_t *p = s;; p++)
|
|
{
|
|
if (*p == c)
|
|
return (int)(p - s);
|
|
if (*p == 0)
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
void MyStringUpper_Ascii(wchar_t *s)
|
|
{
|
|
for (;;)
|
|
{
|
|
wchar_t c = *s;
|
|
if (c == 0)
|
|
return;
|
|
*s++ = MyCharUpper_Ascii(c);
|
|
}
|
|
}
|
|
*/
|
|
|
|
void MyStringLower_Ascii(char *s) throw()
|
|
{
|
|
for (;;)
|
|
{
|
|
char c = *s;
|
|
if (c == 0)
|
|
return;
|
|
*s++ = MyCharLower_Ascii(c);
|
|
}
|
|
}
|
|
|
|
void MyStringLower_Ascii(wchar_t *s) throw()
|
|
{
|
|
for (;;)
|
|
{
|
|
wchar_t c = *s;
|
|
if (c == 0)
|
|
return;
|
|
*s++ = MyCharLower_Ascii(c);
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
|
|
#ifdef _UNICODE
|
|
|
|
// wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); }
|
|
// wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); }
|
|
// for WinCE - FString - char
|
|
// const char *MyStringGetPrevCharPointer(const char * /* base */, const char *p) { return p - 1; }
|
|
|
|
#else
|
|
|
|
// const char * MyStringGetPrevCharPointer(const char *base, const char *p) throw() { return CharPrevA(base, p); }
|
|
// char * MyStringUpper(char *s) { return CharUpperA(s); }
|
|
// char * MyStringLower(char *s) { return CharLowerA(s); }
|
|
|
|
wchar_t MyCharUpper_WIN(wchar_t c) throw()
|
|
{
|
|
wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c);
|
|
if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
|
|
return (wchar_t)(unsigned)(UINT_PTR)res;
|
|
const int kBufSize = 4;
|
|
char s[kBufSize + 1];
|
|
int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0);
|
|
if (numChars == 0 || numChars > kBufSize)
|
|
return c;
|
|
s[numChars] = 0;
|
|
::CharUpperA(s);
|
|
::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
|
|
return c;
|
|
}
|
|
|
|
/*
|
|
wchar_t MyCharLower_WIN(wchar_t c)
|
|
{
|
|
wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c);
|
|
if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
|
|
return (wchar_t)(unsigned)(UINT_PTR)res;
|
|
const int kBufSize = 4;
|
|
char s[kBufSize + 1];
|
|
int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0);
|
|
if (numChars == 0 || numChars > kBufSize)
|
|
return c;
|
|
s[numChars] = 0;
|
|
::CharLowerA(s);
|
|
::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
|
|
return c;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
wchar_t * MyStringUpper(wchar_t *s)
|
|
{
|
|
if (s == 0)
|
|
return 0;
|
|
wchar_t *res = CharUpperW(s);
|
|
if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
|
|
return res;
|
|
AString a = UnicodeStringToMultiByte(s);
|
|
a.MakeUpper();
|
|
MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
|
|
return s;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
wchar_t * MyStringLower(wchar_t *s)
|
|
{
|
|
if (s == 0)
|
|
return 0;
|
|
wchar_t *res = CharLowerW(s);
|
|
if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
|
|
return res;
|
|
AString a = UnicodeStringToMultiByte(s);
|
|
a.MakeLower();
|
|
MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
|
|
return s;
|
|
}
|
|
*/
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
bool IsString1PrefixedByString2(const char *s1, const char *s2) throw()
|
|
{
|
|
for (;;)
|
|
{
|
|
unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true;
|
|
unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false;
|
|
}
|
|
}
|
|
|
|
bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw()
|
|
{
|
|
for (;;)
|
|
{
|
|
wchar_t c1 = *s1++;
|
|
wchar_t c2 = *s2++;
|
|
if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false;
|
|
if (c1 == 0) return true;
|
|
}
|
|
}
|
|
|
|
// ---------- ASCII ----------
|
|
|
|
bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
|
|
{
|
|
const char *s1 = _chars;
|
|
for (;;)
|
|
{
|
|
char c2 = *s++;
|
|
if (c2 == 0)
|
|
return true;
|
|
char c1 = *s1++;
|
|
if (MyCharLower_Ascii(c1) !=
|
|
MyCharLower_Ascii(c2))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
|
|
{
|
|
const wchar_t *s1 = _chars;
|
|
for (;;)
|
|
{
|
|
char c2 = *s++;
|
|
if (c2 == 0)
|
|
return true;
|
|
wchar_t c1 = *s1++;
|
|
if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw()
|
|
{
|
|
for (;;)
|
|
{
|
|
unsigned char c = *a;
|
|
if (c != *u)
|
|
return false;
|
|
if (c == 0)
|
|
return true;
|
|
a++;
|
|
u++;
|
|
}
|
|
}
|
|
|
|
bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw()
|
|
{
|
|
for (;;)
|
|
{
|
|
char c1 = *s1++;
|
|
char c2 = *s2++;
|
|
if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
|
|
return false;
|
|
if (c1 == 0)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw()
|
|
{
|
|
for (;;)
|
|
{
|
|
wchar_t c1 = *s1++;
|
|
wchar_t c2 = *s2++;
|
|
if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
|
|
return false;
|
|
if (c1 == 0)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw()
|
|
{
|
|
for (;;)
|
|
{
|
|
wchar_t c1 = *s1++;
|
|
char c2 = *s2++;
|
|
if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)))
|
|
return false;
|
|
if (c1 == 0)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw()
|
|
{
|
|
for (;;)
|
|
{
|
|
wchar_t c2 = *s2++; if (c2 == 0) return true;
|
|
wchar_t c1 = *s1++; if (c1 != c2) return false;
|
|
}
|
|
}
|
|
|
|
bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw()
|
|
{
|
|
for (;;)
|
|
{
|
|
wchar_t c2 = *s2++; if (c2 == 0) return true;
|
|
wchar_t c1 = *s1++;
|
|
if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// NTFS order: uses upper case
|
|
int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw()
|
|
{
|
|
for (;;)
|
|
{
|
|
wchar_t c1 = *s1++;
|
|
wchar_t c2 = *s2++;
|
|
if (c1 != c2)
|
|
{
|
|
wchar_t u1 = MyCharUpper(c1);
|
|
wchar_t u2 = MyCharUpper(c2);
|
|
if (u1 < u2) return -1;
|
|
if (u1 > u2) return 1;
|
|
}
|
|
if (c1 == 0) return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num)
|
|
{
|
|
for (; num != 0; num--)
|
|
{
|
|
wchar_t c1 = *s1++;
|
|
wchar_t c2 = *s2++;
|
|
if (c1 != c2)
|
|
{
|
|
wchar_t u1 = MyCharUpper(c1);
|
|
wchar_t u2 = MyCharUpper(c2);
|
|
if (u1 < u2) return -1;
|
|
if (u1 > u2) return 1;
|
|
}
|
|
if (c1 == 0) return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
*/
|
|
|
|
// ---------- AString ----------
|
|
|
|
void AString::InsertSpace(unsigned &index, unsigned size)
|
|
{
|
|
Grow(size);
|
|
MoveItems(index + size, index);
|
|
}
|
|
|
|
#define k_Alloc_Len_Limit 0x40000000
|
|
|
|
void AString::ReAlloc(unsigned newLimit)
|
|
{
|
|
if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130220;
|
|
// MY_STRING_REALLOC(_chars, char, newLimit + 1, _len + 1);
|
|
char *newBuf = MY_STRING_NEW(char, newLimit + 1);
|
|
memcpy(newBuf, _chars, (size_t)(_len + 1)); \
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = newLimit;
|
|
}
|
|
|
|
void AString::ReAlloc2(unsigned newLimit)
|
|
{
|
|
if (newLimit >= k_Alloc_Len_Limit) throw 20130220;
|
|
// MY_STRING_REALLOC(_chars, char, newLimit + 1, 0);
|
|
char *newBuf = MY_STRING_NEW(char, newLimit + 1);
|
|
newBuf[0] = 0;
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = newLimit;
|
|
}
|
|
|
|
void AString::SetStartLen(unsigned len)
|
|
{
|
|
_chars = 0;
|
|
_chars = MY_STRING_NEW(char, len + 1);
|
|
_len = len;
|
|
_limit = len;
|
|
}
|
|
|
|
void AString::Grow_1()
|
|
{
|
|
unsigned next = _len;
|
|
next += next / 2;
|
|
next += 16;
|
|
next &= ~(unsigned)15;
|
|
ReAlloc(next - 1);
|
|
}
|
|
|
|
void AString::Grow(unsigned n)
|
|
{
|
|
unsigned freeSize = _limit - _len;
|
|
if (n <= freeSize)
|
|
return;
|
|
|
|
unsigned next = _len + n;
|
|
next += next / 2;
|
|
next += 16;
|
|
next &= ~(unsigned)15;
|
|
ReAlloc(next - 1);
|
|
}
|
|
|
|
/*
|
|
AString::AString(unsigned num, const char *s)
|
|
{
|
|
unsigned len = MyStringLen(s);
|
|
if (num > len)
|
|
num = len;
|
|
SetStartLen(num);
|
|
memcpy(_chars, s, num);
|
|
_chars[num] = 0;
|
|
}
|
|
*/
|
|
|
|
AString::AString(unsigned num, const AString &s)
|
|
{
|
|
if (num > s._len)
|
|
num = s._len;
|
|
SetStartLen(num);
|
|
memcpy(_chars, s._chars, num);
|
|
_chars[num] = 0;
|
|
}
|
|
|
|
AString::AString(const AString &s, char c)
|
|
{
|
|
SetStartLen(s.Len() + 1);
|
|
char *chars = _chars;
|
|
unsigned len = s.Len();
|
|
memcpy(chars, s, len);
|
|
chars[len] = c;
|
|
chars[len + 1] = 0;
|
|
}
|
|
|
|
AString::AString(const char *s1, unsigned num1, const char *s2, unsigned num2)
|
|
{
|
|
SetStartLen(num1 + num2);
|
|
char *chars = _chars;
|
|
memcpy(chars, s1, num1);
|
|
memcpy(chars + num1, s2, num2 + 1);
|
|
}
|
|
|
|
AString operator+(const AString &s1, const AString &s2) { return AString(s1, s1.Len(), s2, s2.Len()); }
|
|
AString operator+(const AString &s1, const char *s2) { return AString(s1, s1.Len(), s2, MyStringLen(s2)); }
|
|
AString operator+(const char *s1, const AString &s2) { return AString(s1, MyStringLen(s1), s2, s2.Len()); }
|
|
|
|
AString::AString()
|
|
{
|
|
_chars = 0;
|
|
_chars = MY_STRING_NEW(char, 4);
|
|
_len = 0;
|
|
_limit = 4 - 1;
|
|
_chars[0] = 0;
|
|
}
|
|
|
|
AString::AString(char c)
|
|
{
|
|
SetStartLen(1);
|
|
_chars[0] = c;
|
|
_chars[1] = 0;
|
|
}
|
|
|
|
AString::AString(const char *s)
|
|
{
|
|
SetStartLen(MyStringLen(s));
|
|
MyStringCopy(_chars, s);
|
|
}
|
|
|
|
AString::AString(const AString &s)
|
|
{
|
|
SetStartLen(s._len);
|
|
MyStringCopy(_chars, s._chars);
|
|
}
|
|
|
|
AString &AString::operator=(char c)
|
|
{
|
|
if (1 > _limit)
|
|
{
|
|
char *newBuf = MY_STRING_NEW(char, 1 + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = 1;
|
|
}
|
|
_len = 1;
|
|
_chars[0] = c;
|
|
_chars[1] = 0;
|
|
return *this;
|
|
}
|
|
|
|
AString &AString::operator=(const char *s)
|
|
{
|
|
unsigned len = MyStringLen(s);
|
|
if (len > _limit)
|
|
{
|
|
char *newBuf = MY_STRING_NEW(char, len + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = len;
|
|
}
|
|
_len = len;
|
|
MyStringCopy(_chars, s);
|
|
return *this;
|
|
}
|
|
|
|
AString &AString::operator=(const AString &s)
|
|
{
|
|
if (&s == this)
|
|
return *this;
|
|
unsigned len = s._len;
|
|
if (len > _limit)
|
|
{
|
|
char *newBuf = MY_STRING_NEW(char, len + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = len;
|
|
}
|
|
_len = len;
|
|
MyStringCopy(_chars, s._chars);
|
|
return *this;
|
|
}
|
|
|
|
void AString::SetFromWStr_if_Ascii(const wchar_t *s)
|
|
{
|
|
unsigned len = 0;
|
|
{
|
|
for (;; len++)
|
|
{
|
|
wchar_t c = s[len];
|
|
if (c == 0)
|
|
break;
|
|
if (c >= 0x80)
|
|
return;
|
|
}
|
|
}
|
|
if (len > _limit)
|
|
{
|
|
char *newBuf = MY_STRING_NEW(char, len + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = len;
|
|
}
|
|
_len = len;
|
|
char *dest = _chars;
|
|
unsigned i;
|
|
for (i = 0; i < len; i++)
|
|
dest[i] = (char)s[i];
|
|
dest[i] = 0;
|
|
}
|
|
|
|
/*
|
|
void AString::SetFromBstr_if_Ascii(BSTR s)
|
|
{
|
|
unsigned len = ::SysStringLen(s);
|
|
{
|
|
for (unsigned i = 0; i < len; i++)
|
|
if (s[i] <= 0 || s[i] >= 0x80)
|
|
return;
|
|
}
|
|
if (len > _limit)
|
|
{
|
|
char *newBuf = MY_STRING_NEW(char, len + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = len;
|
|
}
|
|
_len = len;
|
|
char *dest = _chars;
|
|
unsigned i;
|
|
for (i = 0; i < len; i++)
|
|
dest[i] = (char)s[i];
|
|
dest[i] = 0;
|
|
}
|
|
*/
|
|
|
|
void AString::Add_Space() { operator+=(' '); }
|
|
void AString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); }
|
|
void AString::Add_LF() { operator+=('\n'); }
|
|
|
|
AString &AString::operator+=(const char *s)
|
|
{
|
|
unsigned len = MyStringLen(s);
|
|
Grow(len);
|
|
MyStringCopy(_chars + _len, s);
|
|
_len += len;
|
|
return *this;
|
|
}
|
|
|
|
AString &AString::operator+=(const AString &s)
|
|
{
|
|
Grow(s._len);
|
|
MyStringCopy(_chars + _len, s._chars);
|
|
_len += s._len;
|
|
return *this;
|
|
}
|
|
|
|
void AString::SetFrom(const char *s, unsigned len) // no check
|
|
{
|
|
if (len > _limit)
|
|
{
|
|
char *newBuf = MY_STRING_NEW(char, len + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = len;
|
|
}
|
|
if (len != 0)
|
|
memcpy(_chars, s, len);
|
|
_chars[len] = 0;
|
|
_len = len;
|
|
}
|
|
|
|
void AString::SetFrom_CalcLen(const char *s, unsigned len) // no check
|
|
{
|
|
unsigned i;
|
|
for (i = 0; i < len; i++)
|
|
if (s[i] == 0)
|
|
break;
|
|
SetFrom(s, i);
|
|
}
|
|
|
|
int AString::Find(const char *s, unsigned startIndex) const throw()
|
|
{
|
|
const char *fs = strstr(_chars + startIndex, s);
|
|
if (!fs)
|
|
return -1;
|
|
return (int)(fs - _chars);
|
|
|
|
/*
|
|
if (s[0] == 0)
|
|
return startIndex;
|
|
unsigned len = MyStringLen(s);
|
|
const char *p = _chars + startIndex;
|
|
for (;; p++)
|
|
{
|
|
const char c = *p;
|
|
if (c != s[0])
|
|
{
|
|
if (c == 0)
|
|
return -1;
|
|
continue;
|
|
}
|
|
unsigned i;
|
|
for (i = 1; i < len; i++)
|
|
if (p[i] != s[i])
|
|
break;
|
|
if (i == len)
|
|
return (int)(p - _chars);
|
|
}
|
|
*/
|
|
}
|
|
|
|
int AString::ReverseFind(char c) const throw()
|
|
{
|
|
if (_len == 0)
|
|
return -1;
|
|
const char *p = _chars + _len - 1;
|
|
for (;;)
|
|
{
|
|
if (*p == c)
|
|
return (int)(p - _chars);
|
|
if (p == _chars)
|
|
return -1;
|
|
p--; // p = GetPrevCharPointer(_chars, p);
|
|
}
|
|
}
|
|
|
|
int AString::ReverseFind_PathSepar() const throw()
|
|
{
|
|
if (_len == 0)
|
|
return -1;
|
|
const char *p = _chars + _len - 1;
|
|
for (;;)
|
|
{
|
|
char c = *p;
|
|
if (IS_PATH_SEPAR(c))
|
|
return (int)(p - _chars);
|
|
if (p == _chars)
|
|
return -1;
|
|
p--;
|
|
}
|
|
}
|
|
|
|
void AString::TrimLeft() throw()
|
|
{
|
|
const char *p = _chars;
|
|
for (;; p++)
|
|
{
|
|
char c = *p;
|
|
if (c != ' ' && c != '\n' && c != '\t')
|
|
break;
|
|
}
|
|
unsigned pos = (unsigned)(p - _chars);
|
|
if (pos != 0)
|
|
{
|
|
MoveItems(0, pos);
|
|
_len -= pos;
|
|
}
|
|
}
|
|
|
|
void AString::TrimRight() throw()
|
|
{
|
|
const char *p = _chars;
|
|
unsigned i;
|
|
for (i = _len; i != 0; i--)
|
|
{
|
|
char c = p[i - 1];
|
|
if (c != ' ' && c != '\n' && c != '\t')
|
|
break;
|
|
}
|
|
if (i != _len)
|
|
{
|
|
_chars[i] = 0;
|
|
_len = i;
|
|
}
|
|
}
|
|
|
|
void AString::InsertAtFront(char c)
|
|
{
|
|
if (_limit == _len)
|
|
Grow_1();
|
|
MoveItems(1, 0);
|
|
_chars[0] = c;
|
|
_len++;
|
|
}
|
|
|
|
/*
|
|
void AString::Insert(unsigned index, char c)
|
|
{
|
|
InsertSpace(index, 1);
|
|
_chars[index] = c;
|
|
_len++;
|
|
}
|
|
*/
|
|
|
|
void AString::Insert(unsigned index, const char *s)
|
|
{
|
|
unsigned num = MyStringLen(s);
|
|
if (num != 0)
|
|
{
|
|
InsertSpace(index, num);
|
|
memcpy(_chars + index, s, num);
|
|
_len += num;
|
|
}
|
|
}
|
|
|
|
void AString::Insert(unsigned index, const AString &s)
|
|
{
|
|
unsigned num = s.Len();
|
|
if (num != 0)
|
|
{
|
|
InsertSpace(index, num);
|
|
memcpy(_chars + index, s, num);
|
|
_len += num;
|
|
}
|
|
}
|
|
|
|
void AString::RemoveChar(char ch) throw()
|
|
{
|
|
char *src = _chars;
|
|
|
|
for (;;)
|
|
{
|
|
char c = *src++;
|
|
if (c == 0)
|
|
return;
|
|
if (c == ch)
|
|
break;
|
|
}
|
|
|
|
char *dest = src - 1;
|
|
|
|
for (;;)
|
|
{
|
|
char c = *src++;
|
|
if (c == 0)
|
|
break;
|
|
if (c != ch)
|
|
*dest++ = c;
|
|
}
|
|
|
|
*dest = 0;
|
|
_len = (unsigned)(dest - _chars);
|
|
}
|
|
|
|
// !!!!!!!!!!!!!!! test it if newChar = '\0'
|
|
void AString::Replace(char oldChar, char newChar) throw()
|
|
{
|
|
if (oldChar == newChar)
|
|
return; // 0;
|
|
// unsigned number = 0;
|
|
int pos = 0;
|
|
while ((unsigned)pos < _len)
|
|
{
|
|
pos = Find(oldChar, pos);
|
|
if (pos < 0)
|
|
break;
|
|
_chars[(unsigned)pos] = newChar;
|
|
pos++;
|
|
// number++;
|
|
}
|
|
return; // number;
|
|
}
|
|
|
|
void AString::Replace(const AString &oldString, const AString &newString)
|
|
{
|
|
if (oldString.IsEmpty())
|
|
return; // 0;
|
|
if (oldString == newString)
|
|
return; // 0;
|
|
unsigned oldLen = oldString.Len();
|
|
unsigned newLen = newString.Len();
|
|
// unsigned number = 0;
|
|
int pos = 0;
|
|
while ((unsigned)pos < _len)
|
|
{
|
|
pos = Find(oldString, pos);
|
|
if (pos < 0)
|
|
break;
|
|
Delete(pos, oldLen);
|
|
Insert(pos, newString);
|
|
pos += newLen;
|
|
// number++;
|
|
}
|
|
// return number;
|
|
}
|
|
|
|
void AString::Delete(unsigned index) throw()
|
|
{
|
|
MoveItems(index, index + 1);
|
|
_len--;
|
|
}
|
|
|
|
void AString::Delete(unsigned index, unsigned count) throw()
|
|
{
|
|
if (index + count > _len)
|
|
count = _len - index;
|
|
if (count > 0)
|
|
{
|
|
MoveItems(index, index + count);
|
|
_len -= count;
|
|
}
|
|
}
|
|
|
|
void AString::DeleteFrontal(unsigned num) throw()
|
|
{
|
|
if (num != 0)
|
|
{
|
|
MoveItems(0, num);
|
|
_len -= num;
|
|
}
|
|
}
|
|
|
|
/*
|
|
AString operator+(const AString &s1, const AString &s2)
|
|
{
|
|
AString result(s1);
|
|
result += s2;
|
|
return result;
|
|
}
|
|
|
|
AString operator+(const AString &s, const char *chars)
|
|
{
|
|
AString result(s);
|
|
result += chars;
|
|
return result;
|
|
}
|
|
|
|
AString operator+(const char *chars, const AString &s)
|
|
{
|
|
AString result(chars);
|
|
result += s;
|
|
return result;
|
|
}
|
|
|
|
AString operator+(const AString &s, char c)
|
|
{
|
|
AString result(s);
|
|
result += c;
|
|
return result;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
AString operator+(char c, const AString &s)
|
|
{
|
|
AString result(c);
|
|
result += s;
|
|
return result;
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
|
|
// ---------- UString ----------
|
|
|
|
void UString::InsertSpace(unsigned index, unsigned size)
|
|
{
|
|
Grow(size);
|
|
MoveItems(index + size, index);
|
|
}
|
|
|
|
void UString::ReAlloc(unsigned newLimit)
|
|
{
|
|
if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130221;
|
|
// MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, _len + 1);
|
|
wchar_t *newBuf = MY_STRING_NEW(wchar_t, newLimit + 1);
|
|
wmemcpy(newBuf, _chars, _len + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = newLimit;
|
|
}
|
|
|
|
void UString::ReAlloc2(unsigned newLimit)
|
|
{
|
|
if (newLimit >= k_Alloc_Len_Limit) throw 20130221;
|
|
// MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0);
|
|
wchar_t *newBuf = MY_STRING_NEW(wchar_t, newLimit + 1);
|
|
newBuf[0] = 0;
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = newLimit;
|
|
}
|
|
|
|
void UString::SetStartLen(unsigned len)
|
|
{
|
|
_chars = 0;
|
|
_chars = MY_STRING_NEW(wchar_t, len + 1);
|
|
_len = len;
|
|
_limit = len;
|
|
}
|
|
|
|
void UString::Grow_1()
|
|
{
|
|
unsigned next = _len;
|
|
next += next / 2;
|
|
next += 16;
|
|
next &= ~(unsigned)15;
|
|
ReAlloc(next - 1);
|
|
}
|
|
|
|
void UString::Grow(unsigned n)
|
|
{
|
|
unsigned freeSize = _limit - _len;
|
|
if (n <= freeSize)
|
|
return;
|
|
|
|
unsigned next = _len + n;
|
|
next += next / 2;
|
|
next += 16;
|
|
next &= ~(unsigned)15;
|
|
ReAlloc(next - 1);
|
|
}
|
|
|
|
|
|
UString::UString(unsigned num, const wchar_t *s)
|
|
{
|
|
unsigned len = MyStringLen(s);
|
|
if (num > len)
|
|
num = len;
|
|
SetStartLen(num);
|
|
wmemcpy(_chars, s, num);
|
|
_chars[num] = 0;
|
|
}
|
|
|
|
|
|
UString::UString(unsigned num, const UString &s)
|
|
{
|
|
if (num > s._len)
|
|
num = s._len;
|
|
SetStartLen(num);
|
|
wmemcpy(_chars, s._chars, num);
|
|
_chars[num] = 0;
|
|
}
|
|
|
|
UString::UString(const UString &s, wchar_t c)
|
|
{
|
|
SetStartLen(s.Len() + 1);
|
|
wchar_t *chars = _chars;
|
|
unsigned len = s.Len();
|
|
wmemcpy(chars, s, len);
|
|
chars[len] = c;
|
|
chars[len + 1] = 0;
|
|
}
|
|
|
|
UString::UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2)
|
|
{
|
|
SetStartLen(num1 + num2);
|
|
wchar_t *chars = _chars;
|
|
wmemcpy(chars, s1, num1);
|
|
wmemcpy(chars + num1, s2, num2 + 1);
|
|
}
|
|
|
|
UString operator+(const UString &s1, const UString &s2) { return UString(s1, s1.Len(), s2, s2.Len()); }
|
|
UString operator+(const UString &s1, const wchar_t *s2) { return UString(s1, s1.Len(), s2, MyStringLen(s2)); }
|
|
UString operator+(const wchar_t *s1, const UString &s2) { return UString(s1, MyStringLen(s1), s2, s2.Len()); }
|
|
|
|
UString::UString()
|
|
{
|
|
_chars = 0;
|
|
_chars = MY_STRING_NEW(wchar_t, 4);
|
|
_len = 0;
|
|
_limit = 4 - 1;
|
|
_chars[0] = 0;
|
|
}
|
|
|
|
UString::UString(wchar_t c)
|
|
{
|
|
SetStartLen(1);
|
|
_chars[0] = c;
|
|
_chars[1] = 0;
|
|
}
|
|
|
|
UString::UString(const wchar_t *s)
|
|
{
|
|
unsigned len = MyStringLen(s);
|
|
SetStartLen(len);
|
|
wmemcpy(_chars, s, len + 1);
|
|
}
|
|
|
|
UString::UString(const UString &s)
|
|
{
|
|
SetStartLen(s._len);
|
|
wmemcpy(_chars, s._chars, s._len + 1);
|
|
}
|
|
|
|
UString &UString::operator=(wchar_t c)
|
|
{
|
|
if (1 > _limit)
|
|
{
|
|
wchar_t *newBuf = MY_STRING_NEW(wchar_t, 1 + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = 1;
|
|
}
|
|
_len = 1;
|
|
_chars[0] = c;
|
|
_chars[1] = 0;
|
|
return *this;
|
|
}
|
|
|
|
UString &UString::operator=(const wchar_t *s)
|
|
{
|
|
unsigned len = MyStringLen(s);
|
|
if (len > _limit)
|
|
{
|
|
wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = len;
|
|
}
|
|
_len = len;
|
|
wmemcpy(_chars, s, len + 1);
|
|
return *this;
|
|
}
|
|
|
|
UString &UString::operator=(const UString &s)
|
|
{
|
|
if (&s == this)
|
|
return *this;
|
|
unsigned len = s._len;
|
|
if (len > _limit)
|
|
{
|
|
wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = len;
|
|
}
|
|
_len = len;
|
|
wmemcpy(_chars, s._chars, len + 1);
|
|
return *this;
|
|
}
|
|
|
|
void UString::SetFromBstr(BSTR s)
|
|
{
|
|
unsigned len = ::SysStringLen(s);
|
|
if (len > _limit)
|
|
{
|
|
wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = len;
|
|
}
|
|
_len = len;
|
|
// if (s)
|
|
wmemcpy(_chars, s, len + 1);
|
|
}
|
|
|
|
void UString::Add_Space() { operator+=(L' '); }
|
|
void UString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); }
|
|
|
|
void UString::Add_LF()
|
|
{
|
|
if (_limit == _len)
|
|
Grow_1();
|
|
unsigned len = _len;
|
|
wchar_t *chars = _chars;
|
|
chars[len++] = L'\n';
|
|
chars[len] = 0;
|
|
_len = len;
|
|
}
|
|
|
|
UString &UString::operator+=(const wchar_t *s)
|
|
{
|
|
unsigned len = MyStringLen(s);
|
|
Grow(len);
|
|
wmemcpy(_chars + _len, s, len + 1);
|
|
_len += len;
|
|
return *this;
|
|
}
|
|
|
|
UString &UString::operator+=(const UString &s)
|
|
{
|
|
Grow(s._len);
|
|
wmemcpy(_chars + _len, s._chars, s._len + 1);
|
|
_len += s._len;
|
|
return *this;
|
|
}
|
|
|
|
void UString::SetFrom(const wchar_t *s, unsigned len) // no check
|
|
{
|
|
if (len > _limit)
|
|
{
|
|
wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = len;
|
|
}
|
|
if (len != 0)
|
|
wmemcpy(_chars, s, len);
|
|
_chars[len] = 0;
|
|
_len = len;
|
|
}
|
|
|
|
void UString::SetFromAscii(const char *s)
|
|
{
|
|
unsigned len = MyStringLen(s);
|
|
if (len > _limit)
|
|
{
|
|
wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
_limit = len;
|
|
}
|
|
wchar_t *chars = _chars;
|
|
for (unsigned i = 0; i < len; i++)
|
|
chars[i] = (unsigned char)s[i];
|
|
chars[len] = 0;
|
|
_len = len;
|
|
}
|
|
|
|
void UString::AddAscii(const char *s)
|
|
{
|
|
unsigned len = MyStringLen(s);
|
|
Grow(len);
|
|
wchar_t *chars = _chars + _len;
|
|
for (unsigned i = 0; i < len; i++)
|
|
chars[i] = (unsigned char)s[i];
|
|
chars[len] = 0;
|
|
_len += len;
|
|
}
|
|
|
|
|
|
|
|
int UString::Find(const wchar_t *s, unsigned startIndex) const throw()
|
|
{
|
|
const wchar_t *fs = wcsstr(_chars + startIndex, s);
|
|
if (!fs)
|
|
return -1;
|
|
return (int)(fs - _chars);
|
|
|
|
/*
|
|
if (s[0] == 0)
|
|
return startIndex;
|
|
unsigned len = MyStringLen(s);
|
|
const wchar_t *p = _chars + startIndex;
|
|
for (;; p++)
|
|
{
|
|
const wchar_t c = *p;
|
|
if (c != s[0])
|
|
{
|
|
if (c == 0)
|
|
return -1;
|
|
continue;
|
|
}
|
|
unsigned i;
|
|
for (i = 1; i < len; i++)
|
|
if (p[i] != s[i])
|
|
break;
|
|
if (i == len)
|
|
return (int)(p - _chars);
|
|
}
|
|
*/
|
|
}
|
|
|
|
int UString::ReverseFind(wchar_t c) const throw()
|
|
{
|
|
if (_len == 0)
|
|
return -1;
|
|
const wchar_t *p = _chars + _len - 1;
|
|
for (;;)
|
|
{
|
|
if (*p == c)
|
|
return (int)(p - _chars);
|
|
if (p == _chars)
|
|
return -1;
|
|
p--;
|
|
}
|
|
}
|
|
|
|
int UString::ReverseFind_PathSepar() const throw()
|
|
{
|
|
if (_len == 0)
|
|
return -1;
|
|
const wchar_t *p = _chars + _len - 1;
|
|
for (;;)
|
|
{
|
|
wchar_t c = *p;
|
|
if (IS_PATH_SEPAR(c))
|
|
return (int)(p - _chars);
|
|
if (p == _chars)
|
|
return -1;
|
|
p--;
|
|
}
|
|
}
|
|
|
|
void UString::TrimLeft() throw()
|
|
{
|
|
const wchar_t *p = _chars;
|
|
for (;; p++)
|
|
{
|
|
wchar_t c = *p;
|
|
if (c != ' ' && c != '\n' && c != '\t')
|
|
break;
|
|
}
|
|
unsigned pos = (unsigned)(p - _chars);
|
|
if (pos != 0)
|
|
{
|
|
MoveItems(0, pos);
|
|
_len -= pos;
|
|
}
|
|
}
|
|
|
|
void UString::TrimRight() throw()
|
|
{
|
|
const wchar_t *p = _chars;
|
|
unsigned i;
|
|
for (i = _len; i != 0; i--)
|
|
{
|
|
wchar_t c = p[i - 1];
|
|
if (c != ' ' && c != '\n' && c != '\t')
|
|
break;
|
|
}
|
|
if (i != _len)
|
|
{
|
|
_chars[i] = 0;
|
|
_len = i;
|
|
}
|
|
}
|
|
|
|
void UString::InsertAtFront(wchar_t c)
|
|
{
|
|
if (_limit == _len)
|
|
Grow_1();
|
|
MoveItems(1, 0);
|
|
_chars[0] = c;
|
|
_len++;
|
|
}
|
|
|
|
/*
|
|
void UString::Insert(unsigned index, wchar_t c)
|
|
{
|
|
InsertSpace(index, 1);
|
|
_chars[index] = c;
|
|
_len++;
|
|
}
|
|
*/
|
|
|
|
void UString::Insert(unsigned index, const wchar_t *s)
|
|
{
|
|
unsigned num = MyStringLen(s);
|
|
if (num != 0)
|
|
{
|
|
InsertSpace(index, num);
|
|
wmemcpy(_chars + index, s, num);
|
|
_len += num;
|
|
}
|
|
}
|
|
|
|
void UString::Insert(unsigned index, const UString &s)
|
|
{
|
|
unsigned num = s.Len();
|
|
if (num != 0)
|
|
{
|
|
InsertSpace(index, num);
|
|
wmemcpy(_chars + index, s, num);
|
|
_len += num;
|
|
}
|
|
}
|
|
|
|
void UString::RemoveChar(wchar_t ch) throw()
|
|
{
|
|
wchar_t *src = _chars;
|
|
|
|
for (;;)
|
|
{
|
|
wchar_t c = *src++;
|
|
if (c == 0)
|
|
return;
|
|
if (c == ch)
|
|
break;
|
|
}
|
|
|
|
wchar_t *dest = src - 1;
|
|
|
|
for (;;)
|
|
{
|
|
wchar_t c = *src++;
|
|
if (c == 0)
|
|
break;
|
|
if (c != ch)
|
|
*dest++ = c;
|
|
}
|
|
|
|
*dest = 0;
|
|
_len = (unsigned)(dest - _chars);
|
|
}
|
|
|
|
// !!!!!!!!!!!!!!! test it if newChar = '\0'
|
|
void UString::Replace(wchar_t oldChar, wchar_t newChar) throw()
|
|
{
|
|
if (oldChar == newChar)
|
|
return; // 0;
|
|
// unsigned number = 0;
|
|
int pos = 0;
|
|
while ((unsigned)pos < _len)
|
|
{
|
|
pos = Find(oldChar, pos);
|
|
if (pos < 0)
|
|
break;
|
|
_chars[(unsigned)pos] = newChar;
|
|
pos++;
|
|
// number++;
|
|
}
|
|
return; // number;
|
|
}
|
|
|
|
void UString::Replace(const UString &oldString, const UString &newString)
|
|
{
|
|
if (oldString.IsEmpty())
|
|
return; // 0;
|
|
if (oldString == newString)
|
|
return; // 0;
|
|
unsigned oldLen = oldString.Len();
|
|
unsigned newLen = newString.Len();
|
|
// unsigned number = 0;
|
|
int pos = 0;
|
|
while ((unsigned)pos < _len)
|
|
{
|
|
pos = Find(oldString, pos);
|
|
if (pos < 0)
|
|
break;
|
|
Delete(pos, oldLen);
|
|
Insert(pos, newString);
|
|
pos += newLen;
|
|
// number++;
|
|
}
|
|
// return number;
|
|
}
|
|
|
|
void UString::Delete(unsigned index) throw()
|
|
{
|
|
MoveItems(index, index + 1);
|
|
_len--;
|
|
}
|
|
|
|
void UString::Delete(unsigned index, unsigned count) throw()
|
|
{
|
|
if (index + count > _len)
|
|
count = _len - index;
|
|
if (count > 0)
|
|
{
|
|
MoveItems(index, index + count);
|
|
_len -= count;
|
|
}
|
|
}
|
|
|
|
void UString::DeleteFrontal(unsigned num) throw()
|
|
{
|
|
if (num != 0)
|
|
{
|
|
MoveItems(0, num);
|
|
_len -= num;
|
|
}
|
|
}
|
|
|
|
|
|
// ---------- UString2 ----------
|
|
|
|
void UString2::ReAlloc2(unsigned newLimit)
|
|
{
|
|
if (newLimit >= k_Alloc_Len_Limit) throw 20130221;
|
|
// MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0);
|
|
_chars = MY_STRING_NEW(wchar_t, newLimit + 1);
|
|
}
|
|
|
|
void UString2::SetStartLen(unsigned len)
|
|
{
|
|
_chars = 0;
|
|
_chars = MY_STRING_NEW(wchar_t, len + 1);
|
|
_len = len;
|
|
}
|
|
|
|
|
|
/*
|
|
UString2::UString2(wchar_t c)
|
|
{
|
|
SetStartLen(1);
|
|
_chars[0] = c;
|
|
_chars[1] = 0;
|
|
}
|
|
*/
|
|
|
|
UString2::UString2(const wchar_t *s)
|
|
{
|
|
unsigned len = MyStringLen(s);
|
|
SetStartLen(len);
|
|
wmemcpy(_chars, s, len + 1);
|
|
}
|
|
|
|
UString2::UString2(const UString2 &s): _chars(NULL), _len(0)
|
|
{
|
|
if (s._chars)
|
|
{
|
|
SetStartLen(s._len);
|
|
wmemcpy(_chars, s._chars, s._len + 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
UString2 &UString2::operator=(wchar_t c)
|
|
{
|
|
if (1 > _len)
|
|
{
|
|
wchar_t *newBuf = MY_STRING_NEW(wchar_t, 1 + 1);
|
|
if (_chars)
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
}
|
|
_len = 1;
|
|
_chars[0] = c;
|
|
_chars[1] = 0;
|
|
return *this;
|
|
}
|
|
*/
|
|
|
|
UString2 &UString2::operator=(const wchar_t *s)
|
|
{
|
|
unsigned len = MyStringLen(s);
|
|
if (len > _len)
|
|
{
|
|
wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
|
|
if (_chars)
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
}
|
|
_len = len;
|
|
MyStringCopy(_chars, s);
|
|
return *this;
|
|
}
|
|
|
|
void UString2::SetFromAscii(const char *s)
|
|
{
|
|
unsigned len = MyStringLen(s);
|
|
if (len > _len)
|
|
{
|
|
wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
|
|
if (_chars)
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
}
|
|
wchar_t *chars = _chars;
|
|
for (unsigned i = 0; i < len; i++)
|
|
chars[i] = (unsigned char)s[i];
|
|
chars[len] = 0;
|
|
_len = len;
|
|
}
|
|
|
|
UString2 &UString2::operator=(const UString2 &s)
|
|
{
|
|
if (&s == this)
|
|
return *this;
|
|
unsigned len = s._len;
|
|
if (len > _len)
|
|
{
|
|
wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
|
|
if (_chars)
|
|
MY_STRING_DELETE(_chars);
|
|
_chars = newBuf;
|
|
}
|
|
_len = len;
|
|
MyStringCopy(_chars, s._chars);
|
|
return *this;
|
|
}
|
|
|
|
bool operator==(const UString2 &s1, const UString2 &s2)
|
|
{
|
|
return s1.Len() == s2.Len() && (s1.IsEmpty() || wcscmp(s1.GetRawPtr(), s2.GetRawPtr()) == 0);
|
|
}
|
|
|
|
bool operator==(const UString2 &s1, const wchar_t *s2)
|
|
{
|
|
if (s1.IsEmpty())
|
|
return (*s2 == 0);
|
|
return wcscmp(s1.GetRawPtr(), s2) == 0;
|
|
}
|
|
|
|
bool operator==(const wchar_t *s1, const UString2 &s2)
|
|
{
|
|
if (s2.IsEmpty())
|
|
return (*s1 == 0);
|
|
return wcscmp(s1, s2.GetRawPtr()) == 0;
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------
|
|
|
|
/*
|
|
int MyStringCompareNoCase(const char *s1, const char *s2)
|
|
{
|
|
return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2));
|
|
}
|
|
*/
|
|
|
|
static inline UINT GetCurrentCodePage()
|
|
{
|
|
#if defined(UNDER_CE) || !defined(_WIN32)
|
|
return CP_ACP;
|
|
#else
|
|
return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP;
|
|
#endif
|
|
}
|
|
|
|
#ifdef USE_UNICODE_FSTRING
|
|
|
|
#ifndef _UNICODE
|
|
|
|
AString fs2fas(CFSTR s)
|
|
{
|
|
return UnicodeStringToMultiByte(s, GetCurrentCodePage());
|
|
}
|
|
|
|
FString fas2fs(const AString &s)
|
|
{
|
|
return MultiByteToUnicodeString(s, GetCurrentCodePage());
|
|
}
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
UString fs2us(const FString &s)
|
|
{
|
|
return MultiByteToUnicodeString((AString)s, GetCurrentCodePage());
|
|
}
|
|
|
|
FString us2fs(const wchar_t *s)
|
|
{
|
|
return UnicodeStringToMultiByte(s, GetCurrentCodePage());
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef ENV_HAVE_WCTYPE_H
|
|
// FIXME
|
|
|
|
wchar_t *wmemcpy(wchar_t * d, const wchar_t * s, size_t n)
|
|
{
|
|
wchar_t *a = d;
|
|
while (n--) *d++ = *s++;
|
|
return a;
|
|
}
|
|
|
|
int wmemcmp(const wchar_t *l, const wchar_t *r, size_t n)
|
|
{
|
|
for (; n && *l==*r; n--, l++, r++);
|
|
return n ? (*l-*r) : 0;
|
|
}
|
|
|
|
wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t n)
|
|
{
|
|
for (; n && *s != c; n--, s++);
|
|
return n ? (wchar_t *)s : 0;
|
|
}
|
|
|
|
int wcscmp(const wchar_t *l, const wchar_t *r)
|
|
{
|
|
for (; *l==*r && *l && *r; l++, r++);
|
|
return *l - *r;
|
|
}
|
|
|
|
size_t wcslen(const wchar_t *s)
|
|
{
|
|
const wchar_t *a;
|
|
for (a=s; *s; s++);
|
|
return s-a;
|
|
}
|
|
|
|
wchar_t *wcschr(const wchar_t *s, wchar_t c)
|
|
{
|
|
if (!c) return (wchar_t *)s + wcslen(s);
|
|
for (; *s && *s != c; s++);
|
|
return *s ? (wchar_t *)s : 0;
|
|
}
|
|
|
|
#undef MAX
|
|
#define MAX(a,b) ((a)>(b)?(a):(b))
|
|
#undef MIN
|
|
#define MIN(a,b) ((a)<(b)?(a):(b))
|
|
|
|
static wchar_t *twoway_wcsstr(const wchar_t *h, const wchar_t *n)
|
|
{
|
|
const wchar_t *z;
|
|
size_t l, ip, jp, k, p, ms, p0, mem, mem0;
|
|
|
|
/* Computing length of needle */
|
|
for (l=0; n[l] && h[l]; l++);
|
|
if (n[l]) return 0; /* hit the end of h */
|
|
|
|
/* Compute maximal suffix */
|
|
ip = -1; jp = 0; k = p = 1;
|
|
while (jp+k<l) {
|
|
if (n[ip+k] == n[jp+k]) {
|
|
if (k == p) {
|
|
jp += p;
|
|
k = 1;
|
|
} else k++;
|
|
} else if (n[ip+k] > n[jp+k]) {
|
|
jp += k;
|
|
k = 1;
|
|
p = jp - ip;
|
|
} else {
|
|
ip = jp++;
|
|
k = p = 1;
|
|
}
|
|
}
|
|
ms = ip;
|
|
p0 = p;
|
|
|
|
/* And with the opposite comparison */
|
|
ip = -1; jp = 0; k = p = 1;
|
|
while (jp+k<l) {
|
|
if (n[ip+k] == n[jp+k]) {
|
|
if (k == p) {
|
|
jp += p;
|
|
k = 1;
|
|
} else k++;
|
|
} else if (n[ip+k] < n[jp+k]) {
|
|
jp += k;
|
|
k = 1;
|
|
p = jp - ip;
|
|
} else {
|
|
ip = jp++;
|
|
k = p = 1;
|
|
}
|
|
}
|
|
if (ip+1 > ms+1) ms = ip;
|
|
else p = p0;
|
|
|
|
/* Periodic needle? */
|
|
if (wmemcmp(n, n+p, ms+1)) {
|
|
mem0 = 0;
|
|
p = MAX(ms, l-ms-1) + 1;
|
|
} else mem0 = l-p;
|
|
mem = 0;
|
|
|
|
/* Initialize incremental end-of-haystack pointer */
|
|
z = h;
|
|
|
|
/* Search loop */
|
|
for (;;) {
|
|
/* Update incremental end-of-haystack pointer */
|
|
if (z-h < l) {
|
|
/* Fast estimate for MIN(l,63) */
|
|
size_t grow = l | 63;
|
|
const wchar_t *z2 = wmemchr(z, 0, grow);
|
|
if (z2) {
|
|
z = z2;
|
|
if (z-h < l) return 0;
|
|
} else z += grow;
|
|
}
|
|
|
|
/* Compare right half */
|
|
for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++);
|
|
if (n[k]) {
|
|
h += k-ms;
|
|
mem = 0;
|
|
continue;
|
|
}
|
|
/* Compare left half */
|
|
for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
|
|
if (k <= mem) return (wchar_t *)h;
|
|
h += p;
|
|
mem = mem0;
|
|
}
|
|
}
|
|
|
|
wchar_t *wcsstr(const wchar_t * h, const wchar_t * n)
|
|
{
|
|
/* Return immediately on empty needle or haystack */
|
|
if (!n[0]) return (wchar_t *)h;
|
|
if (!h[0]) return 0;
|
|
|
|
/* Use faster algorithms for short needles */
|
|
h = wcschr(h, *n);
|
|
if (!h || !n[1]) return (wchar_t *)h;
|
|
if (!h[1]) return 0;
|
|
|
|
return twoway_wcsstr(h, n);
|
|
}
|
|
|
|
#if defined(__DJGPP__)
|
|
wchar_t *wcscpy(wchar_t * d, const wchar_t * s)
|
|
{
|
|
wchar_t *a = d;
|
|
while ((*d++ = *s++));
|
|
return a;
|
|
}
|
|
|
|
wchar_t *wcscat(wchar_t *dest, const wchar_t * src)
|
|
{
|
|
wcscpy(dest + wcslen(dest), src);
|
|
return dest;
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|