Files
pip/src_main/core/pichar.cpp

396 lines
8.0 KiB
C++

/*! \file pichar.h
* \brief Unicode char
*/
/*
PIP - Platform Independent Primitives
Unicode char
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piincludes_p.h"
#include "pibytearray.h"
#ifdef PIP_ICU
# define U_NOEXCEPT
# include "unicode/ucnv.h"
# include "unicode/ustring.h"
#endif
#ifdef WINDOWS
# include <stringapiset.h>
# include <winnls.h>
#endif
char * __syslocname__ = 0;
char * __sysoemname__ = 0;
char * __utf8name__ = 0;
#ifdef BLACKBERRY
# include <ctype.h>
#endif
#include <wchar.h>
#ifdef ANDROID
# if __ANDROID_API__ < 21
# define wctomb(s, wc) wcrtomb(s, wc, NULL)
# define mbtowc(pwc, s, n) mbrtowc(pwc, s, n, NULL)
# endif
#endif
/*! \class PIChar
* \brief Unicode char
* \details This class is wrapper around \c "uint".
* There are many contructors and information functions
*/
ushort charFromCodepage(const char * c, int size, const char * codepage, int * taken = 0) {
if (!c || size <= 0) return 0;
if (uchar(c[0]) < 0x80) return c[0];
int ret;
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(codepage, &e);
if (cc) {
UChar uc(0);
e = (UErrorCode)0;
ret = ucnv_toUChars(cc, &uc, 1, c, size, &e);
//printf("PIChar %d -> %d\n", c[0], uc);
if (taken) *taken = ret;
ucnv_close(cc);
return ushort(uc);
}
#else
# ifdef WINDOWS
wchar_t buffer;
ret = MultiByteToWideChar((uint)(uintptr_t)codepage, MB_ERR_INVALID_CHARS, c, size, &buffer, 1);
if (ret <= 0) return 0;
if (taken) *taken = ret;
return buffer;
//printf("request %d\n", sz);
# else
wchar_t wc(0);
mbtowc(0, 0, 0); // reset mbtowc
ret = mbtowc(&wc, c, size);
//printf("mbtowc = %d\n", ret);
if (ret < 1) return 0;
return ushort(int(wc));
# endif
#endif
return ushort(c[0]);
}
int charCompare(const PIChar & f, const PIChar & s) {
return
#ifdef PIP_ICU
u_strCompare((const UChar*)f.toWCharPtr(), 1, (const UChar*)s.toWCharPtr(), 1, FALSE);
#else
# ifdef WINDOWS
CompareStringW(LOCALE_USER_DEFAULT, 0, (PCNZWCH)f.toWCharPtr(), 1, (PCNZWCH)s.toWCharPtr(), 1) - 2;
# else
wcsncmp((const wchar_t *)f.toWCharPtr(), (const wchar_t *)s.toWCharPtr(), 1);
# endif
#endif
}
bool winIsCharType(const ushort * ch, int type) {
#ifdef WINDOWS
WORD attr = 0;
if (GetStringTypeW(CT_CTYPE1, (LPCWCH)ch, 1, &attr) == 0) return false;
return ((attr & type) == type);
#endif
return false;
}
PIChar::PIChar(const char * c, int * bytes) {
ch = charFromCodepage(c, 4, __syslocname__, bytes);
}
PIChar PIChar::fromConsole(char c) {
PIChar ret;
ret.ch = charFromCodepage(&c, 1, __sysoemname__);
return ret;
}
PIChar PIChar::fromSystem(char c) {
PIChar ret;
ret.ch = charFromCodepage(&c, 1, __syslocname__);
return ret;
}
PIChar PIChar::fromUTF8(const char * c) {
PIChar ret;
int l = 0;
while (c[l] != '\0') ++l;
ret.ch = charFromCodepage(c, l, __utf8name__);
return ret;
}
bool PIChar::operator ==(const PIChar & o) const {
return ch == o.ch;
}
bool PIChar::operator >(const PIChar & o) const {
return charCompare(*this, o) > 0;
}
bool PIChar::operator <(const PIChar & o) const {
return charCompare(*this, o) < 0;
}
bool PIChar::operator >=(const PIChar & o) const {
return charCompare(*this, o) >= 0;
}
bool PIChar::operator <=(const PIChar & o) const {
return charCompare(*this, o) <= 0;
}
bool PIChar::isDigit() const {
if (isAscii()) return isdigit(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_DIGIT);
#else
return iswdigit(ch) != 0;
#endif
}
bool PIChar::isHex() const {
if (isAscii()) return isxdigit(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_XDIGIT);
#else
return iswxdigit(ch) != 0;
#endif
}
bool PIChar::isGraphical() const {
if (isAscii()) return isgraph(ch) != 0;
#ifdef WINDOWS
return !winIsCharType(&ch, C1_CNTRL);
#else
return iswgraph(ch) != 0;
#endif
}
bool PIChar::isControl() const {
if (isAscii()) return iscntrl(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_CNTRL);
#else
return iswcntrl(ch) != 0;
#endif
}
bool PIChar::isLower() const {
if (isAscii()) return islower(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_LOWER);
#else
return iswlower(ch) != 0;
#endif
}
bool PIChar::isUpper() const {
if (isAscii()) return isupper(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_UPPER);
#else
return iswupper(ch) != 0;
#endif
}
bool PIChar::isPrint() const {
if (isAscii()) return isprint(ch) != 0;
#ifdef WINDOWS
return !winIsCharType(&ch, C1_CNTRL);
#else
return iswprint(ch) != 0;
#endif
}
bool PIChar::isSpace() const {
if (isAscii()) return isspace(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_SPACE);
#else
return iswspace(ch) != 0;
#endif
}
bool PIChar::isAlpha() const {
if (isAscii()) return isalpha(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_ALPHA);
#else
return iswalpha(ch) != 0;
#endif
}
bool PIChar::isAscii() const {
return isascii(ch) != 0;
}
const wchar_t * PIChar::toWCharPtr() const {
return reinterpret_cast<const wchar_t * >(&ch);
}
const char * PIChar::toCharPtr() const {
return reinterpret_cast<const char * >(&ch);
}
wchar_t PIChar::toWChar() const {
return wchar_t(ch);
}
char PIChar::toConsole1Byte() const {
if (ch < 0x80) return ch;
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(__sysoemname__, &e);
if (cc) {
char uc[8];
e = (UErrorCode)0;
ucnv_fromUChars(cc, uc, 8, (const UChar*)(&ch), 1, &e);
ucnv_close(cc);
return uc[0];
}
#endif
#ifdef WINDOWS
char ret[4] = {0,0,0,0};
WideCharToMultiByte(CP_OEMCP, 0, (LPCWCH)&ch, 1, ret, 4, NULL, NULL);
return ret[0];
#endif
return toAscii();
}
char PIChar::toSystem() const {
if (ch < 0x80) return ch;
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(__syslocname__, &e);
if (cc) {
char uc[8];
e = (UErrorCode)0;
ucnv_fromUChars(cc, uc, 8, (const UChar*)(&ch), 1, &e);
ucnv_close(cc);
return uc[0];
}
#endif
#ifdef WINDOWS
char ret[4] = {0,0,0,0};
WideCharToMultiByte(CP_ACP, 0, (LPCWCH)&ch, 1, ret, 4, NULL, NULL);
return ret[0];
#endif
return toAscii();
}
PIChar PIChar::toUpper() const {
if (isAscii()) return PIChar(toupper(ch));
#ifdef PIP_ICU
UChar c(0);
UErrorCode e((UErrorCode)0);
u_strToUpper(&c, 1, (const UChar*)(&ch), 1, 0, &e);
return PIChar(c);
#else
# ifdef WINDOWS
ushort wc = 0;
if (LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, (LPCWSTR)&ch, 1, (LPWSTR)&wc, 1) == 1)
return PIChar(wc);
# endif
#endif
return PIChar(towupper(ch));
}
PIChar PIChar::toLower() const {
if (isAscii()) return PIChar(tolower(ch));
#ifdef PIP_ICU
UChar c(0);
UErrorCode e((UErrorCode)0);
u_strToLower(&c, 1, (const UChar*)(&ch), 1, 0, &e);
return PIChar(c);
#else
# ifdef WINDOWS
ushort wc = 0;
if (LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, (LPCWSTR)&ch, 1, (LPWSTR)&wc, 1) == 1)
return PIChar(wc);
# endif
#endif
return PIChar(towlower(ch));
}
PICout operator <<(PICout s, const PIChar & v) {
s.space();
s.setControl(0, true);
if (v.isAscii()) s << char(v.ch);
else {
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(__syslocname__, &e);
if (cc) {
char uc[8];
memset(uc, 0, 8);
e = (UErrorCode)0;
ucnv_fromUChars(cc, uc, 8, (const UChar*)(&v.ch), 1, &e);
ucnv_close(cc);
s << uc;
} else
#endif
#ifdef WINDOWS
//if (PICout::isBufferActive())
s << v.toSystem();
//else
// s << v.toConsole1Byte();
#else
{
char tc[8];
wctomb(0, 0);
int sz = wctomb(tc, v.ch);
for (int b = 0; b < sz; ++b)
s << tc[b];
}
#endif
}
s.restoreControl();
return s;
}