summary refs log tree commit diff
path: root/src/String.h
diff options
context:
space:
mode:
authorWlodekM <[email protected]>2024-06-16 10:35:45 +0300
committerWlodekM <[email protected]>2024-06-16 10:35:45 +0300
commitabef6da56913f1c55528103e60a50451a39628b1 (patch)
treeb3c8092471ecbb73e568cd0d336efa0e7871ee8d /src/String.h
initial commit
Diffstat (limited to 'src/String.h')
-rw-r--r--src/String.h273
1 files changed, 273 insertions, 0 deletions
diff --git a/src/String.h b/src/String.h
new file mode 100644
index 0000000..ba09e84
--- /dev/null
+++ b/src/String.h
@@ -0,0 +1,273 @@
+#ifndef CC_STRING_H
+#define CC_STRING_H
+#include "Core.h"
+/* 
+Provides various string related operations
+   Also provides conversions betweens strings and numbers
+   Also provides converting code page 437 indices to/from unicode
+   Also provides wrapping a single line of text into multiple lines
+Copyright 2014-2023 ClassiCube | Licensed under BSD-3
+*/
+
+#define STRING_INT_CHARS 24
+/* Converts a character from A-Z to a-z, otherwise is left untouched. */
+#define Char_MakeLower(c) if ((c) >= 'A' && (c) <= 'Z') { (c) += ' '; }
+
+/* Constant string that points to NULL and has 0 length. */
+/* NOTE: Do NOT modify the contents of this string! */
+extern const cc_string String_Empty;
+/* Constructs a string from the given arguments. */
+static CC_INLINE cc_string String_Init(STRING_REF char* buffer, int length, int capacity) {
+	cc_string s; s.buffer = buffer; s.length = length; s.capacity = capacity; return s;
+}
+
+/* Counts number of characters until a '\0' is found, up to capacity. */
+CC_API int String_CalcLen(const char* raw, int capacity);
+/* Counts number of characters until a '\0' is found. */
+int String_Length(const char* raw);
+
+/* Constructs a string from a compile time string constant */
+#define String_FromConst(text) { (char*)(text), (sizeof(text) - 1), (sizeof(text) - 1)}
+/* Constructs a string from a compile time array */
+#define String_FromArray(buffer) { buffer, 0, sizeof(buffer)}
+
+/* Constructs a string from a (maybe null terminated) buffer. */
+CC_NOINLINE cc_string String_FromRaw(STRING_REF char* buffer, int capacity);
+/* Constructs a string from a null-terminated constant readonly buffer. */
+CC_API cc_string String_FromReadonly(STRING_REF const char* buffer);
+/* Constructs a string from a compile time array, that may have arbitary actual length of data at runtime */
+#define String_FromRawArray(buffer) String_FromRaw(buffer, sizeof(buffer))
+
+/* Constructs a string from a compile time array (leaving 1 byte of room for null terminator) */
+#define String_NT_Array(buffer) { buffer, 0, (sizeof(buffer) - 1)}
+/* Initialises a string from a compile time array. */
+#define String_InitArray(str, buffr) str.buffer = buffr; str.length = 0; str.capacity = sizeof(buffr);
+/* Initialises a string from a compile time array. (leaving 1 byte of room for null terminator) */
+#define String_InitArray_NT(str, buffr) str.buffer = buffr; str.length = 0; str.capacity = sizeof(buffr) - 1;
+
+/* Sets length of dst to 0, then appends all characters in src. */
+CC_API void String_Copy(cc_string* dst, const cc_string* src);
+/* Copies up to capacity characters from src into dst. Appends \0 after if src->length is < capacity. */
+/* NOTE: This means the buffer MAY NOT be null-terminated. Only use with String_FromRawArray. */
+CC_API void String_CopyToRaw(char* dst, int capacity, const cc_string* src);
+/* Calls String_CopyToRaw on a compile time array. */
+#define String_CopyToRawArray(buffer, src) String_CopyToRaw(buffer, sizeof(buffer), src)
+
+/* UNSAFE: Returns a substring of the given string. (sub.buffer is within str.buffer + str.length) */
+CC_API cc_string String_UNSAFE_Substring(STRING_REF const cc_string* str, int offset, int length);
+/* UNSAFE: Returns a substring of the given string. (sub.buffer is within str.buffer + str.length) */
+/* The substring returned is { str.buffer + offset, str.length - offset } */
+CC_API cc_string String_UNSAFE_SubstringAt(STRING_REF const cc_string* str, int offset);
+/* UNSAFE: Splits a string of the form [str1][c][str2][c][str3].. into substrings. */
+/* e.g., "abc:id:xyz" becomes "abc","id","xyz" */
+/* Returns the number of substrings found. (always <= maxSubs) */
+CC_API int String_UNSAFE_Split(STRING_REF const cc_string* str, char c, cc_string* subs, int maxSubs);
+/* UNSAFE: Splits a string of the form [part][c][rest], returning whether [c] was found or not. */
+/* NOTE: This is intended to be repeatedly called until str->length is 0. (unbounded String_UNSAFE_Split) */
+CC_API void String_UNSAFE_SplitBy(STRING_REF cc_string* str, char c, cc_string* part);
+/* UNSAFE: Splits a string of the form [key][c][value] into two substrings. */
+/* e.g., "allowed =true" becomes "allowed" and "true", and excludes the space. */
+/* If c is not found, sets key to str and value to String_Empty, returns false. */
+/* Otherwise if c is found, a non-zero value is returned. */
+CC_API int String_UNSAFE_Separate(STRING_REF const cc_string* str, char c, cc_string* key, cc_string* value);
+
+/* Returns non-zero if all characters of the strings are equal. */
+CC_API  int String_Equals(      const cc_string* a, const cc_string* b);
+typedef int (*FP_String_Equals)(const cc_string* a, const cc_string* b);
+/* Returns non-zero if all characters of the strings are case-insensitively equal. */
+CC_API  int String_CaselessEquals(      const cc_string* a, const cc_string* b);
+typedef int (*FP_String_CaselessEquals)(const cc_string* a, const cc_string* b);
+/* Returns non-zero if all characters of the strings are case-insensitively equal. */
+/* NOTE: Faster than String_CaselessEquals(a, String_FromReadonly(b)) */
+CC_API  int String_CaselessEqualsConst(      const cc_string* a, const char* b);
+typedef int (*FP_String_CaselessEqualsConst)(const cc_string* a, const char* b);
+/* Breaks down an integer into an array of digits, and returns number of digits. */
+/* NOTE: Digits are in reverse order, so e.g. '200' becomes '0','0','2' */
+int String_MakeUInt32(cc_uint32 num, char* digits);
+
+/* Attempts to append a character. */
+/* Does nothing if str->length == str->capcity. */
+CC_API void String_Append(cc_string* str, char c);
+/* Attempts to append "true" if value is non-zero, "false" otherwise. */
+CC_API void String_AppendBool(cc_string* str, cc_bool value);
+/* Attempts to append the digits of an integer (and -sign if negative). */
+CC_API void String_AppendInt(cc_string* str, int num);
+/* Attempts to append the digits of an unsigned 32 bit integer. */
+CC_API void String_AppendUInt32(cc_string* str, cc_uint32 num);
+/* Attempts to append the digits of an integer, padding left with 0. */
+CC_API void String_AppendPaddedInt(cc_string* str, int num, int minDigits);
+
+/* Attempts to append the digits of a float as a decimal. */
+/* NOTE: If the number is an integer, no decimal point is added. */
+/* Otherwise, fracDigits digits are added after a decimal point. */
+/*  e.g. 1.0f produces "1", 2.6745f produces "2.67" when fracDigits is 2 */
+CC_API void String_AppendFloat(cc_string* str, float num, int fracDigits); /* TODO: Need to account for , or . for decimal */
+/* Attempts to append characters. src MUST be null-terminated. */
+CC_API  void String_AppendConst(      cc_string* str, const char* src);
+typedef void (*FP_String_AppendConst)(cc_string* str, const char* src);
+/* Attempts to append characters. */
+void String_AppendAll(cc_string* str, const void* data, int len);
+/* Attempts to append characters of a string. */
+CC_API void String_AppendString(cc_string* str, const cc_string* src);
+/* Attempts to append characters of a string, skipping any colour codes. */
+CC_API void String_AppendColorless(cc_string* str, const cc_string* src);
+/* Attempts to append the two hex digits of a byte. */
+CC_API void String_AppendHex(cc_string* str, cc_uint8 value);
+
+/* Returns first index of the given character in the given string, -1 if not found. */
+#define String_IndexOf(str, c) String_IndexOfAt(str, 0, c)
+/* Returns first index of the given character in the given string, -1 if not found. */
+CC_API int String_IndexOfAt(const cc_string* str, int offset, char c);
+/* Returns last index of the given character in the given string, -1 if not found. */
+#define String_LastIndexOf(str, c) String_LastIndexOfAt(str, 0, c)
+/* Returns last index of the given character in the given string, -1 if not found. */
+CC_API int String_LastIndexOfAt(const cc_string* str, int offset, char c);
+/* Inserts the given character into the given string. Exits process if this fails. */
+/* e.g. inserting 'd' at offset '1' into "abc" produces "adbc" */
+CC_API void String_InsertAt(cc_string* str, int offset, char c);
+/* Deletes a character from the given string. Exits process if this fails. */
+/* e.g. deleting at offset '1' from "adbc" produces "abc" */
+CC_API void String_DeleteAt(cc_string* str, int offset);
+/* Trims leading spaces from the given string. */
+/* NOTE: Works by adjusting buffer/length, the characters in memory are not shifted. */
+CC_API void String_UNSAFE_TrimStart(cc_string* str);
+/* Trims trailing spaces from the given string. */
+/* NOTE: Works by adjusting buffer/length, the characters in memory are not shifted. */
+CC_API void String_UNSAFE_TrimEnd(cc_string* str);
+
+/* Returns first index of the given substring in the given string, -1 if not found. */
+/* e.g. index of "ab" within "cbabd" is 2 */
+CC_API int String_IndexOfConst(const cc_string* str, const char* sub);
+/* Returns non-zero if given substring is inside the given string. */
+#define String_ContainsConst(str, sub) (String_IndexOfConst(str, sub) >= 0)
+/* Returns non-zero if given substring is case-insensitively inside the given string. */
+CC_API  int String_CaselessContains(      const cc_string* str, const cc_string* sub);
+typedef int (*FP_String_CaselessContains)(const cc_string* str, const cc_string* sub);
+/* Returns non-zero if given substring is case-insensitively equal to the beginning of the given string. */
+CC_API  int String_CaselessStarts(      const cc_string* str, const cc_string* sub);
+typedef int (*FP_String_CaselessStarts)(const cc_string* str, const cc_string* sub);
+/* Returns non-zero if given substring is case-insensitively equal to the ending of the given string. */
+CC_API  int String_CaselessEnds(      const cc_string* str, const cc_string* sub);
+typedef int (*FP_String_CaselessEnds)(const cc_string* str, const cc_string* sub);
+/* Compares the length of the given strings, then compares the characters if same length. Returns: */
+/*  -X if a.length < b.length, X if a.length > b.length */
+/*  -X if a.buffer[i] < b.buffer[i], X if a.buffer[i] > b.buffer[i] */
+/*  else returns 0. NOTE: The return value is not just in -1,0,1! */
+CC_API int String_Compare(const cc_string* a, const cc_string* b);
+
+/* String_Format is provided for formatting strings (similiar to printf)
+Supported specifiers for string formatting:
+  TYPE  |  ARGUMENT |        EXAMPLE 
+%b      | cc_uint8  | format(%b, 46) = "46"
+%i      | int       | format(%i, -5) = "-5"
+%f[0-9] | float     | format(%f2, 321.3519) = "321.35"
+%p[0-9] | int       | format(%p3, 5) = "005"
+%t      | cc_bool   | format(%t, 1) = "true"
+%c      | char*     | format(%c, "ABCD") = "ABCD"
+%s      | cc_string | format(%s, {"ABCD", 2, 4}) = "AB"
+%r      | char      | format(%r, 47) = "\"
+%x      | cc_uintptr| format(%x, 31) = "000000000000002F"
+%h      | cc_uint32 | format(%h, 11) = "0000000B" 
+*/
+
+/* See String_Format4 */
+CC_API  void String_Format1(      cc_string* str, const char* format, const void* a1);
+typedef void (*FP_String_Format1)(cc_string* str, const char* format, const void* a1);
+/* See String_Format4 */
+CC_API  void String_Format2(      cc_string* str, const char* format, const void* a1, const void* a2);
+typedef void (*FP_String_Format2)(cc_string* str, const char* format, const void* a1, const void* a2);
+/* See String_Format4 */
+CC_API  void String_Format3(      cc_string* str, const char* format, const void* a1, const void* a2, const void* a3);
+typedef void (*FP_String_Format3)(cc_string* str, const char* format, const void* a1, const void* a2, const void* a3);
+/* Formats the arguments in a string, similiar to printf or C# String.Format
+NOTE: This is a low level API. Argument count and types are not checked at all. */
+CC_API  void String_Format4(      cc_string* str, const char* format, const void* a1, const void* a2, const void* a3, const void* a4);
+typedef void (*FP_String_Format4)(cc_string* str, const char* format, const void* a1, const void* a2, const void* a3, const void* a4);
+
+/* Converts a code page 437 character to its unicode equivalent. */
+cc_unichar Convert_CP437ToUnicode(char c);
+/* Converts a unicode codepoint to its code page 437 equivalent, or '?' if no match. */
+char Convert_CodepointToCP437(cc_codepoint cp);
+/* Attempts to convert a unicode codepoint to its code page 437 equivalent. */
+CC_API cc_bool Convert_TryCodepointToCP437(cc_codepoint cp, char* c);
+/* Decodes a unicode codepoint from UTF8, returning number of bytes read. */
+/* Returns 0 if not enough input data to read the character. */
+int Convert_Utf8ToCodepoint(cc_codepoint* cp, const cc_uint8* data, cc_uint32 len);
+/* Encodes a code page 437 character in UTF8, returning number of bytes written. */
+/* The number of bytes written is always either 1,2 or 3. */
+int Convert_CP437ToUtf8(char c, cc_uint8* data);
+
+/* Attempts to append all characters from UTF16 encoded data to the given string. */
+/* Characters not in code page 437 are omitted. */
+void String_AppendUtf16(cc_string* str, const void* data, int numBytes);
+/* Attempts to append all characters from UTF8 encoded data to the given string. */
+/* Characters not in code page 437 are omitted. */
+void String_AppendUtf8(cc_string* str, const void* data, int numBytes);
+/* Attempts to append all characters from CP-1252 encoded data to the given string. */
+/* Characters not in code page 437 are omitted. */
+void String_DecodeCP1252(cc_string* str, const void* data, int numBytes);
+/* Encodes a string in UTF8 format, also null terminating the string. */
+/* Returns the number of bytes written, excluding trailing NULL terminator. */
+int String_EncodeUtf8(void* data, const cc_string* src);
+
+/* Attempts to convert the given string into an unsigned 8 bit integer. */
+CC_API cc_bool Convert_ParseUInt8(const cc_string*  str, cc_uint8* value);
+/* Attempts to convert the given string into an unsigned 16 bit integer. */
+CC_API cc_bool Convert_ParseUInt16(const cc_string* str, cc_uint16* value);
+/* Attempts to convert the given string into an integer. */
+CC_API cc_bool Convert_ParseInt(const cc_string*    str, int* value);
+/* Attempts to convert the given string into an unsigned 64 bit integer. */
+CC_API cc_bool Convert_ParseUInt64(const cc_string* str, cc_uint64* value);
+/* Attempts to convert the given string into a floating point number. */
+CC_API cc_bool Convert_ParseFloat(const cc_string*  str, float* value);
+/* Attempts to convert the given string into a bool. */
+/* NOTE: String must case-insensitively equal "true" or "false" */
+CC_API cc_bool Convert_ParseBool(const cc_string*   str, cc_bool* value);
+
+#define STRINGSBUFFER_BUFFER_DEF_SIZE 4096
+#define STRINGSBUFFER_FLAGS_DEF_ELEMS 256
+#define STRINGSBUFFER_DEF_LEN_SHIFT 9
+#define STRINGSBUFFER_DEF_LEN_MASK  0x1FFUL
+
+struct StringsBuffer {
+	char*      textBuffer;  /* Raw characters of all entries */
+	cc_uint32*  flagsBuffer; /* Private flags for each entry */
+	int count, totalLength;
+	/* internal state */
+	int      _textCapacity, _flagsCapacity;
+	char     _defaultBuffer[STRINGSBUFFER_BUFFER_DEF_SIZE];
+	cc_uint32 _defaultFlags[STRINGSBUFFER_FLAGS_DEF_ELEMS];
+	/* Value to shift a flags value by to retrieve the offset */
+	int _lenShift;
+	/* Value to mask a flags value with to retrieve the length */
+	int _lenMask;
+};
+
+/* Resets counts to 0 and other state to default */
+void StringsBuffer_Init(struct StringsBuffer* buffer);
+/* Sets the number of bits in an entry's flags that are used to store its length */
+/*  (e.g. if bits is 9, then the maximum length of an entry is 2^9-1 = 511) */
+void StringsBuffer_SetLengthBits(struct StringsBuffer* buffer, int bits);
+/* Frees any allocated memory and then called StringsBuffer_Init */
+CC_NOINLINE void StringsBuffer_Clear(struct StringsBuffer* buffer);
+/* UNSAFE: Returns a direct pointer to the i'th string in the given buffer */
+/* You MUST NOT change the characters of this string. Copy to another string if necessary.*/
+CC_API STRING_REF cc_string StringsBuffer_UNSAFE_Get(struct StringsBuffer* buffer, int i);
+STRING_REF void StringsBuffer_UNSAFE_GetRaw(struct StringsBuffer* buffer, int i, cc_string* dst);
+/* Adds the given string to the end of the given buffer */
+CC_API void StringsBuffer_Add(struct StringsBuffer* buffer, const cc_string* str);
+/* Removes the i'th string from the given buffer, shifting following strings downwards */
+CC_API void StringsBuffer_Remove(struct StringsBuffer* buffer, int index);
+/* Sorts all the entries in the given buffer using String_Compare */
+void StringsBuffer_Sort(struct StringsBuffer* buffer);
+
+/* Performs line wrapping on the given string. */
+/* e.g. "some random tex|t* (| is lineLen) becomes "some random" "text" */
+void WordWrap_Do(STRING_REF cc_string* text, cc_string* lines, int numLines, int lineLen);
+/* Calculates the position of a raw index in the wrapped lines. */
+void WordWrap_GetCoords(int index, const cc_string* lines, int numLines, int* coordX, int* coordY);
+/* Returns number of characters from current character to end of previous word. */
+int  WordWrap_GetBackLength(const cc_string* text, int index);
+/* Returns number of characters from current character to start of next word. */
+int  WordWrap_GetForwardLength(const cc_string* text, int index);
+#endif