Add our implementation for wcscoll() and wcsxfrm().

* add Wcscoll() and Wcsxfrm() ICU locale backend
* provide implementations of wcscoll() and wcsxfrm() that are using
  the respective methods of the locale backend
This commit is contained in:
Oliver Tappe
2012-01-07 21:47:31 +01:00
parent 1b93a2e630
commit bd55dcbefb
8 changed files with 165 additions and 6 deletions
@@ -29,6 +29,10 @@ public:
status_t Strcoll(const char* a, const char* b, int& out); status_t Strcoll(const char* a, const char* b, int& out);
status_t Strxfrm(char* out, const char* in, size_t size, status_t Strxfrm(char* out, const char* in, size_t size,
size_t& outSize); size_t& outSize);
status_t Wcscoll(const wchar_t* a, const wchar_t* b,
int& out);
status_t Wcsxfrm(wchar_t* out, const wchar_t* in,
size_t size, size_t& outSize);
private: private:
status_t _ToUnicodeString(const char* in, status_t _ToUnicodeString(const char* in,
@@ -61,6 +61,10 @@ public:
virtual status_t Strcoll(const char* a, const char* b, int& out); virtual status_t Strcoll(const char* a, const char* b, int& out);
virtual status_t Strxfrm(char* out, const char* in, size_t size, virtual status_t Strxfrm(char* out, const char* in, size_t size,
size_t& outSize); size_t& outSize);
virtual status_t Wcscoll(const wchar_t* a, const wchar_t* b,
int& out);
virtual status_t Wcsxfrm(wchar_t* out, const wchar_t* in,
size_t size, size_t& outSize);
virtual status_t TZSet(const char* timeZoneID, const char* tz); virtual status_t TZSet(const char* timeZoneID, const char* tz);
virtual status_t Localtime(const time_t* inTime, virtual status_t Localtime(const time_t* inTime,
@@ -144,6 +144,10 @@ public:
int& out) = 0; int& out) = 0;
virtual status_t Strxfrm(char* out, const char* in, size_t size, virtual status_t Strxfrm(char* out, const char* in, size_t size,
size_t& outSize) = 0; size_t& outSize) = 0;
virtual status_t Wcscoll(const wchar_t* a, const wchar_t* b,
int& out) = 0;
virtual status_t Wcsxfrm(wchar_t* out, const wchar_t* in,
size_t size, size_t& outSize) = 0;
virtual status_t TZSet(const char* timeZoneID, virtual status_t TZSet(const char* timeZoneID,
const char* tz) = 0; const char* tz) = 0;
@@ -7,9 +7,12 @@
#include "ICUCollateData.h" #include "ICUCollateData.h"
#include <string.h> #include <string.h>
#include <wchar.h>
#include <unicode/unistr.h> #include <unicode/unistr.h>
#include <AutoDeleter.h>
namespace BPrivate { namespace BPrivate {
namespace Libroot { namespace Libroot {
@@ -63,7 +66,7 @@ ICUCollateData::SetToPosix()
status_t status_t
ICUCollateData::Strcoll(const char* a, const char* b, int& result) ICUCollateData::Strcoll(const char* a, const char* b, int& result)
{ {
if (strcmp(fPosixLocaleName, "POSIX") == 0) { if (fCollator == NULL || strcmp(fPosixLocaleName, "POSIX") == 0) {
// handle POSIX here as the collator ICU uses for that (english) is // handle POSIX here as the collator ICU uses for that (english) is
// incompatible in too many ways // incompatible in too many ways
result = strcmp(a, b); result = strcmp(a, b);
@@ -109,7 +112,7 @@ ICUCollateData::Strcoll(const char* a, const char* b, int& result)
status_t status_t
ICUCollateData::Strxfrm(char* out, const char* in, size_t size, size_t& outSize) ICUCollateData::Strxfrm(char* out, const char* in, size_t size, size_t& outSize)
{ {
if (strcmp(fPosixLocaleName, "POSIX") == 0) { if (fCollator == NULL || strcmp(fPosixLocaleName, "POSIX") == 0) {
// handle POSIX here as the collator ICU uses for that (english) is // handle POSIX here as the collator ICU uses for that (english) is
// incompatible in too many ways // incompatible in too many ways
outSize = strlcpy(out, in, size); outSize = strlcpy(out, in, size);
@@ -125,13 +128,40 @@ ICUCollateData::Strxfrm(char* out, const char* in, size_t size, size_t& outSize)
return B_OK; return B_OK;
} }
UErrorCode icuStatus = U_ZERO_ERROR;
UnicodeString unicodeIn; UnicodeString unicodeIn;
if (_ToUnicodeString(in, unicodeIn) != B_OK) if (_ToUnicodeString(in, unicodeIn) != B_OK)
return B_BAD_VALUE; return B_BAD_VALUE;
outSize = fCollator->getSortKey(unicodeIn, (uint8_t*)out, size); outSize = fCollator->getSortKey(unicodeIn, (uint8_t*)out, size);
return B_OK;
}
status_t
ICUCollateData::Wcscoll(const wchar_t* a, const wchar_t* b, int& result)
{
if (fCollator == NULL || strcmp(fPosixLocaleName, "POSIX") == 0) {
// handle POSIX here as the collator ICU uses for that (english) is
// incompatible in too many ways
result = wcscmp(a, b);
for (const wchar_t* aIter = a; *aIter != 0; ++aIter) {
if (*aIter > 127)
return B_BAD_VALUE;
}
for (const wchar_t* bIter = b; *bIter != 0; ++bIter) {
if (*bIter > 127)
return B_BAD_VALUE;
}
return B_OK;
}
UnicodeString unicodeA = UnicodeString::fromUTF32((UChar32*)a, -1);
UnicodeString unicodeB = UnicodeString::fromUTF32((UChar32*)b, -1);
UErrorCode icuStatus = U_ZERO_ERROR;
result = fCollator->compare(unicodeA, unicodeB, icuStatus);
if (!U_SUCCESS(icuStatus)) if (!U_SUCCESS(icuStatus))
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -139,6 +169,40 @@ ICUCollateData::Strxfrm(char* out, const char* in, size_t size, size_t& outSize)
} }
status_t
ICUCollateData::Wcsxfrm(wchar_t* out, const wchar_t* in, size_t size,
size_t& outSize)
{
if (in == NULL) {
outSize = 0;
return B_OK;
}
if (fCollator == NULL || strcmp(fPosixLocaleName, "POSIX") == 0) {
// handle POSIX here as the collator ICU uses for that (english) is
// incompatible in too many ways
outSize = wcslcpy(out, in, size);
for (const wchar_t* inIter = in; *inIter != 0; ++inIter) {
if (*inIter > 127)
return B_BAD_VALUE;
}
return B_OK;
}
UnicodeString unicodeIn = UnicodeString::fromUTF32((UChar32*)in, -1);
size_t requiredSize = fCollator->getSortKey(unicodeIn, NULL, 0);
uint8_t* buffer = (uint8_t*)out;
outSize = fCollator->getSortKey(unicodeIn, buffer, requiredSize);
// convert 1-byte characters to 4-byte wide characters:
for (size_t i = 0; i < outSize; ++i)
out[outSize - 1 - i] = buffer[outSize - 1 - i];
return B_OK;
}
status_t status_t
ICUCollateData::_ToUnicodeString(const char* in, UnicodeString& out) ICUCollateData::_ToUnicodeString(const char* in, UnicodeString& out)
{ {
@@ -294,6 +294,25 @@ ICULocaleBackend::Strxfrm(char* out, const char* in, size_t size,
} }
status_t
ICULocaleBackend::Wcscoll(const wchar_t* a, const wchar_t* b, int& result)
{
ErrnoMaintainer errnoMaintainer;
return fCollateData.Wcscoll(a, b, result);
}
status_t
ICULocaleBackend::Wcsxfrm(wchar_t* out, const wchar_t* in, size_t size,
size_t& outSize)
{
ErrnoMaintainer errnoMaintainer;
return fCollateData.Wcsxfrm(out, in, size, outSize);
}
status_t status_t
ICULocaleBackend::TZSet(const char* timeZoneID, const char* tz) ICULocaleBackend::TZSet(const char* timeZoneID, const char* tz)
{ {
@@ -11,8 +11,6 @@
#include <unicode/gregocal.h> #include <unicode/gregocal.h>
#include <AutoDeleter.h>
namespace BPrivate { namespace BPrivate {
namespace Libroot { namespace Libroot {
@@ -0,0 +1,32 @@
/*
** Copyright 2011, Oliver Tappe, [email protected]. All rights reserved.
** Distributed under the terms of the Haiku License.
*/
#include <errno_private.h>
#include <LocaleBackend.h>
#include <wchar_private.h>
using BPrivate::Libroot::gLocaleBackend;
extern "C" int
__wcscoll(const wchar_t* wcs1, const wchar_t* wcs2)
{
if (gLocaleBackend != NULL) {
int result = 0;
status_t status = gLocaleBackend->Wcscoll(wcs1, wcs2, result);
if (status != B_OK)
__set_errno(EINVAL);
return result;
}
return wcscmp(wcs1, wcs2);
}
extern "C"
B_DEFINE_WEAK_ALIAS(__wcscoll, wcscoll);
@@ -0,0 +1,34 @@
/*
* Copyright 2011, Oliver Tappe, [email protected].
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include <errno.h>
#include <errno_private.h>
#include <LocaleBackend.h>
#include <wchar_private.h>
using BPrivate::Libroot::gLocaleBackend;
extern "C" size_t
__wcsxfrm(wchar_t* dest, const wchar_t* src, size_t destSize)
{
if (gLocaleBackend != NULL) {
size_t outSize = 0;
status_t status = gLocaleBackend->Wcsxfrm(dest, src, destSize, outSize);
if (status != B_OK)
__set_errno(EINVAL);
return outSize;
}
return wcslcpy(dest, src, destSize);
}
extern "C"
B_DEFINE_WEAK_ALIAS(__wcsxfrm, wcsxfrm);