Simplify altering default builtin colours, and loading options representing colours

Also improve String_Append to deliberately crash the game when attempting to append to an uninitialised string in MSVC debug builds
This commit is contained in:
UnknownShadow200 2023-11-20 19:30:36 +11:00
parent 7bbfd61f63
commit 39b09a9202
7 changed files with 95 additions and 39 deletions

View File

@ -20,6 +20,29 @@ Some general guidelines to keep in mind when it comes to `cc_string` strings:
- Strings are not garbage collected or reference counted<br> - Strings are not garbage collected or reference counted<br>
(i.e. you are responsible for managing the lifetime of strings) (i.e. you are responsible for managing the lifetime of strings)
## Usage examples
Initialisating a string from readonly text:
```C
cc_string str = String_FromConst("ABC");
```
Initialising a string from temporary memory on the stack:
```C
// str will be able to store at most 200 characters in it
char strBuffer[200];
cc_string str = String_FromArray(strBuffer);
```
Initialising a string from persistent memory on the heap:
```C
// str will be able to store at most 200 characters in it
char* str = Mem_Alloc(1, 200, "String buffer");
cc_string str = String_Init(str, 0, 200);
```
# Converting to/from other string representations
## C String conversion ## C String conversion
### C string -> cc_string ### C string -> cc_string
@ -88,7 +111,7 @@ void SetWorkingDir(cc_string* title) {
Platform_EncodeUtf16(&str, title); Platform_EncodeUtf16(&str, title);
SetCurrentDirectoryW(str.uni); SetCurrentDirectoryW(str.uni);
// it's recommended that you DON'T use the ansi format whenever possible // it's recommended that you DON'T use the ansi format whenever possible
//SetCurrentDirectoryA(str.ansi); //SetCurrentDirectoryA(str.ansi);
} }
``` ```
@ -106,13 +129,15 @@ void SetWorkingDir(cc_string* title) {
} }
``` ```
## API # API
I'm lazy so I will just link to [String.h](/src/String.h) I'm lazy so I will just link to [String.h](/src/String.h)
If you'd rather I provided a more detailed reference here, please let me know. If you'd rather I provided a more detailed reference here, please let me know.
# Extra details TODO
# Comparisons to other string implementations
## C comparison ## C comparison
@ -202,10 +227,7 @@ string::compare -> String_Compare
std::sprintf -> String_Format1/2/3/4 std::sprintf -> String_Format1/2/3/4
``` ```
# Detailed lifetime examples
## Lifetime examples
Managing the lifetime of strings is important, as not properly managing them can cause issues. Managing the lifetime of strings is important, as not properly managing them can cause issues.

View File

@ -415,19 +415,18 @@ static struct ChatCommand GpuInfoCommand = {
}; };
static void RenderTypeCommand_Execute(const cc_string* args, int argsCount) { static void RenderTypeCommand_Execute(const cc_string* args, int argsCount) {
int flags; char strBuffer[256];
if (!argsCount) { cc_string safeStr = String_FromArray(strBuffer);
Chat_AddRaw("&e/client: &cYou didn't specify a new render type."); return; cc_string unsafeStr;
}
flags = EnvRenderer_CalcFlags(args); Options_SetInt("xyz", 123456);
if (flags >= 0) { Options_Get("xyz", &safeStr, "");
EnvRenderer_SetMode(flags); Options_UNSAFE_Get("xyz", &unsafeStr);
Options_Set(OPT_RENDER_TYPE, args);
Chat_Add1("&e/client: &fRender type is now %s.", args); Options_Reload();
} else {
Chat_Add1("&e/client: &cUnrecognised render type &f\"%s\"&c.", args); Chat_Add1("Safe: %s", &safeStr);
} Chat_Add1("Unsafe: %s", &unsafeStr);
} }
static struct ChatCommand RenderTypeCommand = { static struct ChatCommand RenderTypeCommand = {

View File

@ -633,26 +633,39 @@ static void DefaultPngProcess(struct Stream* stream, const cc_string* name) {
static struct TextureEntry default_entry = { "default.png", DefaultPngProcess }; static struct TextureEntry default_entry = { "default.png", DefaultPngProcess };
static void InitHexEncodedColor(int i, int hex, cc_uint8 lo, cc_uint8 hi) { /* The default 16 colours are the CGA 16 color palette (without special brown colour) */
Drawer2D.Colors[i] = BitmapColor_RGB( /* See https://en.wikipedia.org/wiki/Color_Graphics_Adapter#With_an_RGBI_monitor for reference */
lo * ((hex >> 2) & 1) + hi * (hex >> 3), /* The 16 hex colours below were produced from the following formula: */
lo * ((hex >> 1) & 1) + hi * (hex >> 3), /* R = 191 * ((hex >> 2) & 1) + 64 * (hex >> 3) */
lo * ((hex >> 0) & 1) + hi * (hex >> 3)); /* G = 191 * ((hex >> 1) & 1) + 64 * (hex >> 3) */
} /* B = 191 * ((hex >> 0) & 1) + 64 * (hex >> 3) */
static const BitmapCol defaults_0_9[] = {
BitmapColor_RGB( 0, 0, 0), /* 0 */
BitmapColor_RGB( 0, 0, 191), /* 1 */
BitmapColor_RGB( 0, 191, 0), /* 2 */
BitmapColor_RGB( 0, 191, 191), /* 3 */
BitmapColor_RGB(191, 0, 0), /* 4 */
BitmapColor_RGB(191, 0, 191), /* 5 */
BitmapColor_RGB(191, 191, 0), /* 6 */
BitmapColor_RGB(191, 191, 191), /* 7 */
BitmapColor_RGB( 64, 64, 64), /* 8 */
BitmapColor_RGB( 64, 64, 255) /* 9 */
};
static const BitmapCol defaults_a_f[] = {
BitmapColor_RGB( 64, 255, 64), /* A */
BitmapColor_RGB( 64, 255, 255), /* B */
BitmapColor_RGB(255, 64, 64), /* C */
BitmapColor_RGB(255, 64, 255), /* D */
BitmapColor_RGB(255, 255, 64), /* E */
BitmapColor_RGB(255, 255, 255), /* F */
};
static void OnReset(void) { static void OnReset(void) {
int i; Mem_Set(Drawer2D.Colors, 0, sizeof(Drawer2D.Colors));
for (i = 0; i < DRAWER2D_MAX_COLORS; i++) {
Drawer2D.Colors[i] = 0;
}
for (i = 0; i <= 9; i++) { Mem_Copy(&Drawer2D.Colors['0'], defaults_0_9, sizeof(defaults_0_9));
InitHexEncodedColor('0' + i, i, 191, 64); Mem_Copy(&Drawer2D.Colors['a'], defaults_a_f, sizeof(defaults_a_f));
} Mem_Copy(&Drawer2D.Colors['A'], defaults_a_f, sizeof(defaults_a_f));
for (i = 10; i <= 15; i++) {
InitHexEncodedColor('a' + (i - 10), i, 191, 64);
InitHexEncodedColor('A' + (i - 10), i, 191, 64);
}
} }
static void OnInit(void) { static void OnInit(void) {

View File

@ -328,9 +328,7 @@ const struct LauncherTheme Launcher_NordicTheme = {
CC_NOINLINE static void ParseColor(const char* key, BitmapCol* color) { CC_NOINLINE static void ParseColor(const char* key, BitmapCol* color) {
cc_uint8 rgb[3]; cc_uint8 rgb[3];
cc_string value; if (!Options_GetColor(key, rgb)) return;
if (!Options_UNSAFE_Get(key, &value)) return;
if (!PackedCol_TryParseHex(&value, rgb)) return;
*color = BitmapColor_RGB(rgb[0], rgb[1], rgb[2]); *color = BitmapColor_RGB(rgb[0], rgb[1], rgb[2]);
} }

View File

@ -6,6 +6,7 @@
#include "Errors.h" #include "Errors.h"
#include "Utils.h" #include "Utils.h"
#include "Logger.h" #include "Logger.h"
#include "PackedCol.h"
struct StringsBuffer Options; struct StringsBuffer Options;
static struct StringsBuffer changedOpts; static struct StringsBuffer changedOpts;
@ -137,6 +138,19 @@ int Options_GetEnum(const char* key, int defValue, const char* const* names, int
return Utils_ParseEnum(&str, defValue, names, namesCount); return Utils_ParseEnum(&str, defValue, names, namesCount);
} }
cc_bool Options_GetColor(const char* key, cc_uint8* rgb) {
cc_string value, parts[3];
if (!Options_UNSAFE_Get(key, &value)) return false;
if (PackedCol_TryParseHex(&value, rgb)) return true;
/* Try parsing as R,G,B instead */
return String_UNSAFE_Split(&value, ',', parts, 3)
&& Convert_ParseUInt8(&parts[0], &rgb[0])
&& Convert_ParseUInt8(&parts[1], &rgb[1])
&& Convert_ParseUInt8(&parts[2], &rgb[2]);
}
void Options_SetBool(const char* keyRaw, cc_bool value) { void Options_SetBool(const char* keyRaw, cc_bool value) {
static const cc_string str_true = String_FromConst("True"); static const cc_string str_true = String_FromConst("True");
static const cc_string str_false = String_FromConst("False"); static const cc_string str_false = String_FromConst("False");

View File

@ -123,6 +123,9 @@ CC_API float Options_GetFloat(const char* key, float min, float max, float defV
/* Returns value of given option as an integer, or defalt value if could not be converted. */ /* Returns value of given option as an integer, or defalt value if could not be converted. */
/* NOTE: Conversion is done by going through all elements of names, returning index of a match. */ /* NOTE: Conversion is done by going through all elements of names, returning index of a match. */
CC_API int Options_GetEnum(const char* key, int defValue, const char* const* names, int namesCount); CC_API int Options_GetEnum(const char* key, int defValue, const char* const* names, int namesCount);
/* Attempts to parse the value of the given option into an RGB (3 byte) colour. */
/* Returns whether the option was actually found and could be parsed into a colour. */
cc_bool Options_GetColor(const char* key, cc_uint8* rgb);
/* Sets value of given option to either "true" or "false". */ /* Sets value of given option to either "true" or "false". */
CC_API void Options_SetBool(const char* keyRaw, cc_bool value); CC_API void Options_SetBool(const char* keyRaw, cc_bool value);

View File

@ -146,6 +146,13 @@ int String_CaselessEqualsConst(const cc_string* a, const char* b) {
void String_Append(cc_string* str, char c) { void String_Append(cc_string* str, char c) {
/* MSVC in debug mode will initialise all variables on the stack with 0xCC by default */
/* So if a string is being passed with CC in all its fields, then it's probably invalid */
#if _MSC_VER && _DEBUG
if (str->length == 0xCCCC && str->capacity == 0xCCCC)
Logger_Abort("String must be initialised before calling String_Append");
#endif
if (str->length == str->capacity) return; if (str->length == str->capacity) return;
str->buffer[str->length++] = c; str->buffer[str->length++] = c;
} }