// // wfunction.hpp // cpp_tests // // Created by jief on 15.03.20. // Copyright © 2020 Jief_Machak. All rights reserved. // /* * clang had poisoned identifier like wcslen. * It's not possible to define a function with that name, not even a macro... except on the command line. * So, for this to work, pass macro definition argument on command line : wcslen=wcslen_fixed wcscmp=__wcscmp_is_disabled__ wcsncmp=wcsncmp_fixed wcsstr=wcsstr_fixed */ /* * 2021, Mojave. * wcslen, wcsncmp seems fixed ! * wcsstr is NOT. * printf with %ls is not. * wprintf is not. */ #include #include #include #include #include #include #include #include //#include "../../../Include/Library/printf_lite.h" #include "../../../rEFIt_UEFI/Platform/BootLog.h" #include "xcode_utf_fixed.h" /* few tests for debug purpose */ extern "C" void xcode_utf_fixed_tests() { setlocale(LC_ALL, "en_US"); // to allow printf unicode char printf("sizeof(wchar_t)=%zu\n", sizeof(wchar_t)); printf("sizeof(size_t)=%zu\n", sizeof(size_t)); printf("sizeof(long)=%zu\n", sizeof(long)); printf("sizeof(long long)=%zu\n", sizeof(long long)); printf("sizeof(size_t)=%zu\n", sizeof(size_t)); #ifndef _MSC_VER //printf("%zu\n", (size_t)MAX_UINT64); //printf("%zd\n", (size_t)MAX_UINT64); #endif printf("%lc\n", L'Ľ'); #if PRINTF_LITE_REPLACE_STANDARD_FUNCTION == 1 printf("%ls\n", L"Hello world1"); char buf[50]; snprintf(buf, 50, "%ls", L"Hello world2"); printf("%s\n", buf); wprintf(L"%ls\n", L"Hello world൧楔"); #endif uint64_t uint64 = 1; printf("Hello world൧楔 %llu \n", uint64); DebugLog(2, "Hello world൧楔 %llu \n", uint64); size_t len1 = wcslen(L"Hell൧楔o world൧楔"); size_t len1f = wcslen_fixed(L"Hell൧楔o world൧楔"); printf("len1 = %zu, len1f = %zd\n", len1, len1f); int cmp1 = wcsncmp(L"12楔34", L"12楔35", 4); int cmp1f = wcsncmp_fixed(L"12楔34", L"12楔35", 4); printf("cmp1 = %d, cmp1f = %d\n", cmp1, cmp1f); { const wchar_t* str = L"12ク34"; const wchar_t* strstr1 = wcsstr(str, L"ク"); const wchar_t* strstr1f = wcsstr_fixed(str, L"ク"); printf("strstr1 = %ld, strstr1f = %ld\n", strstr1-str, strstr1f-str); } printf("\n\n\n"); // char32_t c32 = (int)-1; } #include "xcode_utf_fixed.h" #if __WCHAR_MAX__ < 0x10000 #undef wcslen extern "C" size_t wcslen(const wchar_t *); #undef wcscmp extern "C" int wcscmp(const wchar_t *s1, const wchar_t * s2); #undef wcsncmp extern "C" int wcsncmp(const wchar_t *, const wchar_t *, size_t); #undef wcsstr extern "C" wchar_t *wcsstr(const wchar_t *, const wchar_t *); static int is_surrogate(char16_t uc) { return (uc - 0xd800u) < 2048u; } static int is_high_surrogate(char16_t uc) { return (uc & 0xfffffc00) == 0xd800; } static int is_low_surrogate(char16_t uc) { return (uc & 0xfffffc00) == 0xdc00; } static char32_t surrogate_to_utf32(char16_t high, char16_t low) { return char32_t((high << 10) + low - 0x35fdc00); // Safe cast, it fits in 32 bits } static void convert_utf16_to_utf32(const char16_t* input, size_t input_size, std::vector* output) { const char16_t* const end = input + input_size; while (input < end && *input) { const char16_t uc = *input++; if (!is_surrogate(uc)) { (*output).push_back(uc); } else { if (is_high_surrogate(uc) && input < end && is_low_surrogate(*input)) (*output).push_back(surrogate_to_utf32(uc, *input++)); else { // ERROR } } } (*output).push_back(0); } std::string to_utf8(const char16_t* s) { std::wstring_convert, char16_t> conv; return conv.to_bytes(s); } #else std::string to_utf8(const char32_t* s) { std::wstring_convert, char32_t> conv; return conv.to_bytes(s); } #endif size_t wcslen_fixed(const wchar_t *s) { #if __WCHAR_MAX__ >= 0x10000 return wcslen(s); #else // wcslen seems not to work if sizeof(wchar_t) == 2 const wchar_t* p; for ( p = s ; *p ; p++ ); return (size_t)(p-s); #endif } int wcsncmp_fixed(const wchar_t *s1, const wchar_t * s2, size_t n) { #if __WCHAR_MAX__ >= 0x10000 return wcsncmp(s1, s2, n); #else // Looks like wcscmp doesn't work with Utf16, even if compiled with -fshort-wchar. // So conversion to Utf32 needed first. std::vector s1Utf32; std::vector s2Utf32; convert_utf16_to_utf32((const char16_t*)s1, n, &s1Utf32); convert_utf16_to_utf32((const char16_t*)s2, n, &s2Utf32); // we don't know the new value of n (x UTF16 chars is not x*2 UTF32 chars), so we can't call wcsncmp // but that's ok because we converted only n UTF16 chars in the call of convert_utf16_to_utf32 int ret = wcscmp((const wchar_t*)s1Utf32.data(), (const wchar_t*)s2Utf32.data()); return ret; #endif } #ifdef _LIBCPP_WCHAR_H wchar_t* wcsstr_fixed(const wchar_t* haystack, const wchar_t* needle) #else wchar_t* wcsstr_fixed(const wchar_t* haystack, const wchar_t* needle) #endif { #if __WCHAR_MAX__ >= 0x10000 return (wchar_t*)wcsstr(haystack, needle); #else // Looks like wcscmp doesn't work with Utf16, even if compiled with -fshort-wchar. // So conversion to Utf32 needed first. const wchar_t *a = haystack, *b = needle; for (;;) if (!*b) return (wchar_t*)(a - wcslen_fixed(needle)); else if (!*a) return NULL; else if (*a++ != *b++) { a = ++haystack; b = needle;} #endif } /* * macOS 10.15 define vsnprintf as a macro that calls __vsnprintf_chk */ extern "C" int __vsnprintf_chk (char* buf, size_t len, int check, size_t size, const char* format, va_list va) { (void)check; (void)size; return PRINTF_FUNCTION_NAME(PRINTF_CFUNCTION_PREFIX, vsnprint, PRINTF_CFUNCTION_SUFFIX)(buf, len, format, va); } #if PRINTF_LITE_REPLACE_STANDARD_FUNCTION == 1 extern "C" int printf(const char* format, ...) { int ret; #if __WCHAR_MAX__ <= 0xFFFF va_list va; va_start(va, format); char buf[4095]; ret = PRINTF_FUNCTION_NAME(PRINTF_CFUNCTION_PREFIX, vsnprint, PRINTF_CFUNCTION_SUFFIX)(buf, sizeof(buf)-1, format, va); write(1, buf, strlen(buf)); va_end(va); #else va_list va; va_start(va, format); ret = vprintf(format, va); va_end(va); #endif return ret; } #if __WCHAR_MAX__ <= 0xFFFF extern "C" int vprintf(const char* format, va_list va) { int ret; char buf[4095]; ret = PRINTF_FUNCTION_NAME(PRINTF_CFUNCTION_PREFIX, vsnprint, PRINTF_CFUNCTION_SUFFIX)(buf, sizeof(buf)-1, format, va); write(1, buf, strlen(buf)); return ret; } #endif #endif //extern "C" int snprintf(char * __restrict buf, size_t len, const char * __restrict format, ...) //{ // int ret = PRINTF_FUNCTION_NAME(PRINTF_CFUNCTION_PREFIX, snprint, PRINTF_CFUNCTION_SUFFIX)(buf, sizeof(buf)-1, format); // return ret; //} int wprintf(const wchar_t* wformat, ...) { int ret; #if __WCHAR_MAX__ <= 0xFFFF std::string format = to_utf8((char16_t*)wformat); wchar_t wbuf[4095]; va_list va; va_start(va, wformat); ret = PRINTF_FUNCTION_NAME(PRINTF_CFUNCTION_PREFIX, vsnwprint, PRINTF_CFUNCTION_SUFFIX)(wbuf, sizeof(wbuf)-1, format.c_str(), va); va_end(va); std::string buf = to_utf8((char16_t*)wbuf); write(1, buf.c_str(), buf.length()); #else std::string format = to_utf8((char32_t*)wformat); wchar_t wbuf[4095]; va_list va; va_start(va, wformat); ret = PRINTF_FUNCTION_NAME(PRINTF_CFUNCTION_PREFIX, vsnwprint, PRINTF_CFUNCTION_SUFFIX)(wbuf, sizeof(wbuf)-1, format.c_str(), va); va_end(va); std::string buf = to_utf8((char32_t*)wbuf); write(1, buf.c_str(), buf.length()); #endif return ret; }