|
|
|
@ -67,7 +67,7 @@ |
|
|
|
|
|
|
|
#include <stdlib.h> // Required for: malloc(), free() |
|
|
|
#include <stdio.h> // Required for: vsprintf() |
|
|
|
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()] |
|
|
|
#include <string.h> // Required for: strcmp(), strstr(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()] |
|
|
|
#include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()] |
|
|
|
#include <ctype.h> // Required for: toupper(), tolower() [Used in TextToUpper(), TextToLower()] |
|
|
|
|
|
|
|
@ -164,9 +164,8 @@ extern void LoadFontDefault(void) |
|
|
|
{ |
|
|
|
#define BIT_CHECK(a,b) ((a) & (1u << (b))) |
|
|
|
|
|
|
|
// check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return |
|
|
|
if (defaultFont.glyphs != NULL && !isGpuReady) |
|
|
|
return; |
|
|
|
// Check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return |
|
|
|
if ((defaultFont.glyphs != NULL) && !isGpuReady) return; |
|
|
|
|
|
|
|
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement |
|
|
|
// Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl |
|
|
|
@ -1453,29 +1452,31 @@ Rectangle GetGlyphAtlasRec(Font font, int codepoint) |
|
|
|
char **LoadTextLines(const char *text, int *count) |
|
|
|
{ |
|
|
|
char **lines = NULL; |
|
|
|
int lineCount = 0; |
|
|
|
|
|
|
|
if (text == NULL) { *count = 0; return lines; } |
|
|
|
|
|
|
|
int lineCount = 1; |
|
|
|
int textSize = (int)strlen(text); |
|
|
|
|
|
|
|
// First text scan pass to get required line count |
|
|
|
for (int i = 0; i < textSize; i++) |
|
|
|
if (text != NULL) |
|
|
|
{ |
|
|
|
">if (text[i] == '\n') lineCount++; |
|
|
|
} |
|
|
|
int textSize = TextLength(text); |
|
|
|
lineCount = 1; |
|
|
|
|
|
|
|
lines = (char **)RL_CALLOC(lineCount, sizeof(char *)); |
|
|
|
for (int i = 0, l = 0, lineLen = 0; i <= textSize; i++) |
|
|
|
{ |
|
|
|
if ((text[i] == '\n') || (text[i] == '\0')) |
|
|
|
// First text scan pass to get required line count |
|
|
|
for (int i = 0; i < textSize; i++) |
|
|
|
{ |
|
|
|
if (text[i] == '\n') lineCount++; |
|
|
|
} |
|
|
|
|
|
|
|
lines = (char **)RL_CALLOC(lineCount, sizeof(char *)); |
|
|
|
for (int i = 0, l = 0, lineLen = 0; i <= textSize; i++) |
|
|
|
{ |
|
|
|
lines[l] = (char *)RL_CALLOC(lineLen + 1, 1); |
|
|
|
strncpy(lines[l], &text[i - lineLen], lineLen); |
|
|
|
lineLen = 0; |
|
|
|
l++; |
|
|
|
if ((text[i] == '\n') || (text[i] == '\0')) |
|
|
|
{ |
|
|
|
lines[l] = (char *)RL_CALLOC(lineLen + 1, 1); |
|
|
|
strncpy(lines[l], &text[i - lineLen], lineLen); |
|
|
|
lineLen = 0; |
|
|
|
l++; |
|
|
|
} |
|
|
|
else lineLen++; |
|
|
|
} |
|
|
|
else lineLen++; |
|
|
|
} |
|
|
|
|
|
|
|
*count = lineCount; |
|
|
|
@ -1517,24 +1518,27 @@ const char *TextFormat(const char *text, ...) |
|
|
|
static int index = 0; |
|
|
|
|
|
|
|
char *currentBuffer = buffers[index]; |
|
|
|
memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using |
|
|
|
memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using |
|
|
|
|
|
|
|
if (text != NULL) |
|
|
|
{ |
|
|
|
va_list args; |
|
|
|
va_start(args, text); |
|
|
|
int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args); |
|
|
|
va_end(args); |
|
|
|
|
|
|
|
va_list args; |
|
|
|
va_start(args, text); |
|
|
|
int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args); |
|
|
|
va_end(args); |
|
|
|
// If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occurred |
|
|
|
if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH) |
|
|
|
{ |
|
|
|
// Inserting "..." at the end of the string to mark as truncated |
|
|
|
char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0" |
|
|
|
snprintf(truncBuffer, 4, "..."); |
|
|
|
} |
|
|
|
|
|
|
|
// If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occurred |
|
|
|
if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH) |
|
|
|
{ |
|
|
|
// Inserting "..." at the end of the string to mark as truncated |
|
|
|
char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0" |
|
|
|
snprintf(truncBuffer, 4, "..."); |
|
|
|
index += 1; // Move to next buffer for next function call |
|
|
|
if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0; |
|
|
|
} |
|
|
|
|
|
|
|
index += 1; // Move to next buffer for next function call |
|
|
|
if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0; |
|
|
|
|
|
|
|
return currentBuffer; |
|
|
|
} |
|
|
|
|
|
|
|
@ -1545,13 +1549,16 @@ int TextToInteger(const char *text) |
|
|
|
int value = 0; |
|
|
|
int sign = 1; |
|
|
|
|
|
|
|
if (p">(text[0] == '+') || (text[0] == '-')) |
|
|
|
if (n">text != NULL) |
|
|
|
{ |
|
|
|
if (text[0] == '-') sign = -1; |
|
|
|
text++; |
|
|
|
} |
|
|
|
if ((text[0] == '+') || (text[0] == '-')) |
|
|
|
{ |
|
|
|
if (text[0] == '-') sign = -1; |
|
|
|
text++; |
|
|
|
} |
|
|
|
|
|
|
|
for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0'); |
|
|
|
for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0'); |
|
|
|
} |
|
|
|
|
|
|
|
return value*sign; |
|
|
|
} |
|
|
|
@ -1564,22 +1571,25 @@ float TextToFloat(const char *text) |
|
|
|
float value = 0.0f; |
|
|
|
float sign = 1.0f; |
|
|
|
|
|
|
|
if (p">(text[0] == '+') || (text[0] == '-')) |
|
|
|
if (n">text != NULL) |
|
|
|
{ |
|
|
|
if (text[0] == '-') sign = -1.0f; |
|
|
|
text++; |
|
|
|
} |
|
|
|
if ((text[0] == '+') || (text[0] == '-')) |
|
|
|
{ |
|
|
|
if (text[0] == '-') sign = -1.0f; |
|
|
|
text++; |
|
|
|
} |
|
|
|
|
|
|
|
int i = 0; |
|
|
|
for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0'); |
|
|
|
int i = 0; |
|
|
|
for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0'); |
|
|
|
|
|
|
|
if (text[i++] == '.') |
|
|
|
{ |
|
|
|
float divisor = 10.0f; |
|
|
|
for (; ((text[i] >= '0') && (text[i] <= '9')); i++) |
|
|
|
if (text[i++] == '.') |
|
|
|
{ |
|
|
|
value += ((float)(text[i] - '0'))/divisor; |
|
|
|
divisor = divisor*10.0f; |
|
|
|
float divisor = 10.0f; |
|
|
|
for (; ((text[i] >= '0') && (text[i] <= '9')); i++) |
|
|
|
{ |
|
|
|
value += ((float)(text[i] - '0'))/divisor; |
|
|
|
divisor = divisor*10.0f; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -1631,25 +1641,22 @@ const char *TextSubtext(const char *text, int position, int length) |
|
|
|
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; |
|
|
|
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); |
|
|
|
|
|
|
|
int textLength = TextLength(text); |
|
|
|
|
|
|
|
if (position >= textLength) |
|
|
|
if (text != NULL) |
|
|
|
{ |
|
|
|
return buffer; //First char is already '\0' by memset |
|
|
|
} |
|
|
|
int textLength = TextLength(text); |
|
|
|
|
|
|
|
int maxLength = textLength - position; |
|
|
|
if (length > maxLength) length = maxLength; |
|
|
|
if (length >= MAX_TEXT_BUFFER_LENGTH) length = MAX_TEXT_BUFFER_LENGTH - 1; |
|
|
|
if (position >= textLength) return buffer; // First char is already '\0' by memset |
|
|
|
|
|
|
|
// NOTE: Alternative: memcpy(buffer, text + position, length) |
|
|
|
int maxLength = textLength - position; |
|
|
|
if (length > maxLength) length = maxLength; |
|
|
|
if (length >= MAX_TEXT_BUFFER_LENGTH) length = MAX_TEXT_BUFFER_LENGTH - 1; |
|
|
|
|
|
|
|
for (int c = 0 ; c < length ; c++) |
|
|
|
{ |
|
|
|
buffer[c] = text[position + c]; |
|
|
|
} |
|
|
|
// NOTE: Alternative: memcpy(buffer, text + position, length) |
|
|
|
|
|
|
|
for (int c = 0; c < length; c++) buffer[c] = text[position + c]; |
|
|
|
|
|
|
|
buffer[length] = '\0'; |
|
|
|
buffer[length] = '\0'; |
|
|
|
} |
|
|
|
|
|
|
|
return buffer; |
|
|
|
} |
|
|
|
@ -1684,7 +1691,7 @@ char *GetTextBetween(const char *text, const char *begin, const char *end) |
|
|
|
|
|
|
|
if (beginIndex > -1) |
|
|
|
{ |
|
|
|
int beginLen = p">(int)strlen(begin); |
|
|
|
int beginLen = n">TextLength(begin); |
|
|
|
int endIndex = TextFindIndex(text + beginIndex + beginLen, end); |
|
|
|
|
|
|
|
if (endIndex > -1) |
|
|
|
@ -1700,84 +1707,86 @@ char *GetTextBetween(const char *text, const char *begin, const char *end) |
|
|
|
} |
|
|
|
|
|
|
|
// Replace text string |
|
|
|
// REQUIRES: strstr(), strncpy(), strcpy() |
|
|
|
// REQUIRES: strstr(), strncpy() |
|
|
|
// TODO: If (replacement == "") remove "search" text |
|
|
|
// WARNING: Allocated memory must be manually freed |
|
|
|
char *TextReplace(const char *text, const char *search, const char *replacement) |
|
|
|
{ |
|
|
|
char *result = NULL; |
|
|
|
|
|
|
|
if (!text || !search) return NULL; // Sanity check |
|
|
|
if ((text != NULL) && (search != NULL)) |
|
|
|
{ |
|
|
|
char *insertPoint = NULL; // Next insert point |
|
|
|
char *temp = NULL; // Temp pointer |
|
|
|
int searchLen = 0; // Search string length of (the string to remove) |
|
|
|
int replaceLen = 0; // Replacement length (the string to replace by) |
|
|
|
int lastReplacePos = 0; // Distance between next search and end of last replace |
|
|
|
int count = 0; // Number of replacements |
|
|
|
|
|
|
|
char *insertPoint = NULL; // Next insert point |
|
|
|
char *temp = NULL; // Temp pointer |
|
|
|
int searchLen = 0; // Search string length of (the string to remove) |
|
|
|
int replaceLen = 0; // Replacement length (the string to replace by) |
|
|
|
int lastReplacePos = 0; // Distance between next search and end of last replace |
|
|
|
int count = 0; // Number of replacements |
|
|
|
searchLen = TextLength(search); |
|
|
|
if (searchLen == 0) return NULL; // Empty search causes infinite loop during count |
|
|
|
|
|
|
|
searchLen = TextLength(search); |
|
|
|
if (searchLen == 0) return NULL; // Empty search causes infinite loop during count |
|
|
|
replaceLen = TextLength(replacement); |
|
|
|
|
|
|
|
replaceLen = TextLength(replacement); |
|
|
|
// Count the number of replacements needed |
|
|
|
insertPoint = (char *)text; |
|
|
|
for (count = 0; (temp = strstr(insertPoint, search)); count++) insertPoint = temp + searchLen; |
|
|
|
|
|
|
|
// Count the number of replacements needed |
|
|
|
insertPoint = (char *)text; |
|
|
|
for (count = 0; (temp = strstr(insertPoint, search)); count++) insertPoint = temp + searchLen; |
|
|
|
// Allocate returning string and point temp to it |
|
|
|
temp = result = (char *)RL_MALLOC(TextLength(text) + (replaceLen - searchLen)*count + 1); |
|
|
|
|
|
|
|
// Allocate returning string and point temp to it |
|
|
|
temp = result = (char *)RL_MALLOC(TextLength(text) + (replaceLen - searchLen)*count + 1); |
|
|
|
if (!result) return NULL; // Memory could not be allocated |
|
|
|
|
|
|
|
if (!result) return NULL; // Memory could not be allocated |
|
|
|
// First time through the loop, all the variable are set correctly from here on, |
|
|
|
// - 'temp' points to the end of the result string |
|
|
|
// - 'insertPoint' points to the next occurrence of replace in text |
|
|
|
// - 'text' points to the remainder of text after "end of replace" |
|
|
|
while (count--) |
|
|
|
{ |
|
|
|
insertPoint = (char *)strstr(text, search); |
|
|
|
lastReplacePos = (int)(insertPoint - text); |
|
|
|
temp = strncpy(temp, text, lastReplacePos) + lastReplacePos; |
|
|
|
temp = strcpy(temp, replacement) + replaceLen; |
|
|
|
text += lastReplacePos + searchLen; // Move to next "end of replace" |
|
|
|
} |
|
|
|
|
|
|
|
// First time through the loop, all the variable are set correctly from here on, |
|
|
|
// - 'temp' points to the end of the result string |
|
|
|
// - 'insertPoint' points to the next occurrence of replace in text |
|
|
|
// - 'text' points to the remainder of text after "end of replace" |
|
|
|
while (count--) |
|
|
|
{ |
|
|
|
insertPoint = (char *)strstr(text, search); |
|
|
|
lastReplacePos = (int)(insertPoint - text); |
|
|
|
temp = strncpy(temp, text, lastReplacePos) + lastReplacePos; |
|
|
|
temp = strcpy(temp, replacement) + replaceLen; |
|
|
|
text += lastReplacePos + searchLen; // Move to next "end of replace" |
|
|
|
// Copy remaind text part after replacement to result (pointed by moving temp) |
|
|
|
strcpy(temp, text); |
|
|
|
} |
|
|
|
|
|
|
|
// Copy remaind text part after replacement to result (pointed by moving temp) |
|
|
|
strcpy(temp, text); |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
// Replace text between two specific strings |
|
|
|
// REQUIRES: strlen(), strncpy() |
|
|
|
// REQUIRES: strncpy() |
|
|
|
// NOTE: If (replacement == NULL) remove "begin"[ ]"end" text |
|
|
|
// WARNING: Returned string must be freed by user |
|
|
|
char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement) |
|
|
|
{ |
|
|
|
char *result = NULL; |
|
|
|
|
|
|
|
if (!text || !begin || !end) return NULL; // Sanity check |
|
|
|
|
|
|
|
int beginIndex = TextFindIndex(text, begin); |
|
|
|
|
|
|
|
if (beginIndex > -1) |
|
|
|
if ((text != NULL) && (begin != NULL) && (end != NULL)) |
|
|
|
{ |
|
|
|
int beginLen = (int)strlen(begin); |
|
|
|
int endIndex = TextFindIndex(text + beginIndex + beginLen, end); |
|
|
|
int beginIndex = TextFindIndex(text, begin); |
|
|
|
|
|
|
|
if (endIndex > -1) |
|
|
|
if (beginIndex > -1) |
|
|
|
{ |
|
|
|
endIndex += (beginIndex + beginLen); |
|
|
|
int beginLen = TextLength(begin); |
|
|
|
int endIndex = TextFindIndex(text + beginIndex + beginLen, end); |
|
|
|
|
|
|
|
if (endIndex > -1) |
|
|
|
{ |
|
|
|
endIndex += (beginIndex + beginLen); |
|
|
|
|
|
|
|
int textLen = (int)strlen(text); |
|
|
|
int replaceLen = (replacement == NULL)? 0 : (int)strlen(replacement); |
|
|
|
int toreplaceLen = endIndex - beginIndex - beginLen; |
|
|
|
result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char)); |
|
|
|
int textLen = n">TextLength(text); |
|
|
|
int replaceLen = (replacement == NULL)? 0 : n">TextLength(replacement); |
|
|
|
int toreplaceLen = endIndex - beginIndex - beginLen; |
|
|
|
result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char)); |
|
|
|
|
|
|
|
strncpy(result, text, beginIndex + beginLen); // Copy first text part |
|
|
|
if (replacement != NULL) strncpy(result + beginIndex + beginLen, replacement, replaceLen); // Copy replacement (if provided) |
|
|
|
strncpy(result + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part |
|
|
|
strncpy(result, text, beginIndex + beginLen); // Copy first text part |
|
|
|
if (replacement != NULL) strncpy(result + beginIndex + beginLen, replacement, replaceLen); // Copy replacement (if provided) |
|
|
|
strncpy(result + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -1788,16 +1797,21 @@ char *TextReplaceBetween(const char *text, const char *begin, const char *end, c |
|
|
|
// WARNING: Allocated memory must be manually freed |
|
|
|
char *TextInsert(const char *text, const char *insert, int position) |
|
|
|
{ |
|
|
|
int textLen = TextLength(text); |
|
|
|
int insertLen = TextLength(insert); |
|
|
|
char *result = NULL; |
|
|
|
|
|
|
|
char *result = (char *)RL_MALLOC(textLen + insertLen + 1); |
|
|
|
if ((text != NULL) && (insert != NULL)) |
|
|
|
{ |
|
|
|
int textLen = TextLength(text); |
|
|
|
int insertLen = TextLength(insert); |
|
|
|
|
|
|
|
result = (char *)RL_MALLOC(textLen + insertLen + 1); |
|
|
|
|
|
|
|
for (int i = 0; i < position; i++) result[i] = text[i]; |
|
|
|
for (int i = position; i < insertLen + position; i++) result[i] = insert[i]; |
|
|
|
for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i]; |
|
|
|
for (int i = 0; i < position; i++) result[i] = text[i]; |
|
|
|
for (int i = position; i < insertLen + position; i++) result[i] = insert[i]; |
|
|
|
for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i]; |
|
|
|
|
|
|
|
result[textLen + insertLen] = '\0'; // Make sure text string is valid! |
|
|
|
result[textLen + insertLen] = '\0'; // Add EOL |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
@ -1879,11 +1893,13 @@ char **TextSplit(const char *text, char delimiter, int *count) |
|
|
|
|
|
|
|
// Append text at specific position and move cursor |
|
|
|
// WARNING: It's up to the user to make sure appended text does not overflow the buffer! |
|
|
|
// REQUIRES: strcpy() |
|
|
|
void TextAppend(char *text, const char *append, int *position) |
|
|
|
{ |
|
|
|
strcpy(text + *position, append); |
|
|
|
*position += TextLength(append); |
|
|
|
if ((text != NULL) && (append != NULL)) |
|
|
|
{ |
|
|
|
TextCopy(text + *position, append); |
|
|
|
*position += TextLength(append); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Find first text occurrence within a string |
|
|
|
@ -1891,11 +1907,13 @@ void TextAppend(char *text, const char *append, int *position) |
|
|
|
int TextFindIndex(const char *text, const char *search) |
|
|
|
{ |
|
|
|
int position = -1; |
|
|
|
if (text == NULL) return position; |
|
|
|
|
|
|
|
char *ptr = (char *)strstr(text, search); |
|
|
|
if (text != NULL) |
|
|
|
{ |
|
|
|
char *ptr = (char *)strstr(text, search); |
|
|
|
|
|
|
|
if (ptr != NULL) position = (int)(ptr - text); |
|
|
|
if (ptr != NULL) position = (int)(ptr - text); |
|
|
|
} |
|
|
|
|
|
|
|
return position; |
|
|
|
} |
|
|
|
@ -2029,24 +2047,29 @@ char *TextToCamel(const char *text) |
|
|
|
// WARNING: Allocated memory must be manually freed |
|
|
|
char *LoadUTF8(const int *codepoints, int length) |
|
|
|
{ |
|
|
|
// We allocate enough memory to fit all possible codepoints |
|
|
|
// NOTE: 5 bytes for every codepoint should be enough |
|
|
|
char *text = (char *)RL_CALLOC(length*5, 1); |
|
|
|
const char *utf8 = NULL; |
|
|
|
int size = 0; |
|
|
|
|
|
|
|
for (int i = 0, bytes = 0; i < length; i++) |
|
|
|
char *text = NULL; |
|
|
|
|
|
|
|
if ((codepoints != NULL) && (length > 0)) |
|
|
|
{ |
|
|
|
utf8 = CodepointToUTF8(codepoints[i], &bytes); |
|
|
|
memcpy(text + size, utf8, bytes); |
|
|
|
size += bytes; |
|
|
|
} |
|
|
|
// We allocate enough memory to fit all possible codepoints |
|
|
|
// NOTE: 5 bytes for every codepoint should be enough |
|
|
|
text = (char *)RL_CALLOC(length*5, 1); |
|
|
|
const char *utf8 = NULL; |
|
|
|
int size = 0; |
|
|
|
|
|
|
|
// Create second buffer and copy data manually to it |
|
|
|
char *temp = (char *)RL_CALLOC(size + 1, 1); |
|
|
|
memcpy(temp, text, size); |
|
|
|
RL_FREE(text); |
|
|
|
text = temp; |
|
|
|
for (int i = 0, bytes = 0; i < length; i++) |
|
|
|
{ |
|
|
|
utf8 = CodepointToUTF8(codepoints[i], &bytes); |
|
|
|
memcpy(text + size, utf8, bytes); |
|
|
|
size += bytes; |
|
|
|
} |
|
|
|
|
|
|
|
// Create second buffer and copy data manually to it |
|
|
|
char *temp = (char *)RL_CALLOC(size + 1, 1); |
|
|
|
memcpy(temp, text, size); |
|
|
|
RL_FREE(text); |
|
|
|
text = temp; |
|
|
|
} |
|
|
|
|
|
|
|
return text; |
|
|
|
} |
|
|
|
@ -2060,28 +2083,31 @@ void UnloadUTF8(char *text) |
|
|
|
// Load all codepoints from a UTF-8 text string, codepoints count returned by parameter |
|
|
|
int *LoadCodepoints(const char *text, int *count) |
|
|
|
{ |
|
|
|
int textLength = TextLength(text); |
|
|
|
|
|
|
|
int codepointSize = 0; |
|
|
|
int *codepoints = NULL; |
|
|
|
int codepointCount = 0; |
|
|
|
|
|
|
|
if (text != NULL) |
|
|
|
{ |
|
|
|
int textLength = TextLength(text); |
|
|
|
|
|
|
|
// Allocate a big enough buffer to store as many codepoints as text bytes |
|
|
|
int *codepoints = (int *)RL_CALLOC(textLength, sizeof(int)); |
|
|
|
// Allocate a big enough buffer to store as many codepoints as text bytes |
|
|
|
int *codepoints = (int *)RL_CALLOC(textLength, sizeof(int)); |
|
|
|
|
|
|
|
for (int i = 0; i < textLength; codepointCount++) |
|
|
|
{ |
|
|
|
codepoints[codepointCount] = GetCodepointNext(text + i, &codepointSize); |
|
|
|
i += codepointSize; |
|
|
|
} |
|
|
|
int codepointSize = 0; |
|
|
|
for (int i = 0; i < textLength; codepointCount++) |
|
|
|
{ |
|
|
|
codepoints[codepointCount] = GetCodepointNext(text + i, &codepointSize); |
|
|
|
i += codepointSize; |
|
|
|
} |
|
|
|
|
|
|
|
// Create second buffer and copy data manually to it |
|
|
|
int *temp = (int *)RL_CALLOC(codepointCount, sizeof(int)); |
|
|
|
for (int i = 0; i < codepointCount; i++) temp[i] = codepoints[i]; |
|
|
|
RL_FREE(codepoints); |
|
|
|
codepoints = temp; |
|
|
|
// Create second buffer and copy data manually to it |
|
|
|
int *temp = (int *)RL_CALLOC(codepointCount, sizeof(int)); |
|
|
|
for (int i = 0; i < codepointCount; i++) temp[i] = codepoints[i]; |
|
|
|
RL_FREE(codepoints); |
|
|
|
codepoints = temp; |
|
|
|
} |
|
|
|
|
|
|
|
*count = codepointCount; |
|
|
|
|
|
|
|
return codepoints; |
|
|
|
} |
|
|
|
|
|
|
|
@ -2098,14 +2124,15 @@ int GetCodepointCount(const char *text) |
|
|
|
unsigned int length = 0; |
|
|
|
const char *ptr = text; |
|
|
|
|
|
|
|
while (*ptr != '\0') |
|
|
|
if (ptr != NULL) |
|
|
|
{ |
|
|
|
int next = 0; |
|
|
|
GetCodepointNext(ptr, &next); |
|
|
|
|
|
|
|
ptr += next; |
|
|
|
|
|
|
|
length++; |
|
|
|
while (*ptr != '\0') |
|
|
|
{ |
|
|
|
int next = 0; |
|
|
|
GetCodepointNext(ptr, &next); |
|
|
|
ptr += next; |
|
|
|
length++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return length; |
|
|
|
@ -2170,11 +2197,14 @@ int GetCodepoint(const char *text, int *codepointSize) |
|
|
|
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
|
|
|
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
|
|
|
*/ |
|
|
|
// NOTE: on decode errors we return as soon as possible |
|
|
|
|
|
|
|
|
|
|
|
int codepoint = 0x3f; // Codepoint (defaults to '?') |
|
|
|
int octet = (unsigned char)(text[0]); // The first UTF8 octet |
|
|
|
*codepointSize = 1; |
|
|
|
if (text == NULL) return codepoint; |
|
|
|
|
|
|
|
// NOTE: on decode errors we return as soon as possible |
|
|
|
int octet = (unsigned char)(text[0]); // The first UTF8 octet |
|
|
|
|
|
|
|
if (octet <= 0x7f) |
|
|
|
{ |
|
|
|
@ -2266,6 +2296,7 @@ int GetCodepointNext(const char *text, int *codepointSize) |
|
|
|
const char *ptr = text; |
|
|
|
int codepoint = 0x3f; // Codepoint (defaults to '?') |
|
|
|
*codepointSize = 1; |
|
|
|
if (text == NULL) return codepoint; |
|
|
|
|
|
|
|
// Get current codepoint and bytes processed |
|
|
|
if (0xf0 == (0xf8 & ptr[0])) |
|
|
|
@ -2304,15 +2335,15 @@ int GetCodepointPrevious(const char *text, int *codepointSize) |
|
|
|
{ |
|
|
|
const char *ptr = text; |
|
|
|
int codepoint = 0x3f; // Codepoint (defaults to '?') |
|
|
|
kt">int cpSize = 0; |
|
|
|
o">*codepointSize = 0; |
|
|
|
o">*codepointSize = 1; |
|
|
|
k">if (text == NULL) return codepoint; |
|
|
|
|
|
|
|
// Move to previous codepoint |
|
|
|
do ptr--; |
|
|
|
while (((0x80 & ptr[0]) != 0) && ((0xc0 & ptr[0]) == 0x80)); |
|
|
|
|
|
|
|
int cpSize = 0; |
|
|
|
codepoint = GetCodepointNext(ptr, &cpSize); |
|
|
|
|
|
|
|
if (codepoint != 0) *codepointSize = cpSize; |
|
|
|
|
|
|
|
return codepoint; |
|
|
|
|