From 68a1190bf2cb1754ee0050ad363ce2a833303858 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 6 Aug 2025 00:56:29 +0200 Subject: [PATCH] REXM: ADDED: Examples validation --- tools/rexm/rexm.c | 403 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 315 insertions(+), 88 deletions(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 296ffc552..d5f7f02ca 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -71,15 +71,36 @@ //---------------------------------------------------------------------------------- // raylib example info struct typedef struct { - char category[16]; - char name[128]; - char stars; - float verCreated; - float verUpdated; - char author[64]; - char authorGitHub[64]; + char category[16]; // Example category: core, shapes, textures, text, models, shaders, audio, others + char name[128]; // Example name: _name_part + int stars; // Example stars count: ★☆☆☆ + float verCreated; // Example raylib creation version + float verUpdated; // Example raylib last update version + char author[64]; // Example author + char authorGitHub[64]; // Example author, GitHub user name + int resCount; // Example resources counter + int status; // Example validation status info } rlExampleInfo; +// Validation status for a single example +typedef enum { + VALID_OK = 0, // All required files and entries are present + VALID_MISSING_C = 1 << 0, // Missing .c source file + VALID_MISSING_PNG = 1 << 1, // Missing screenshot .png + VALID_INVALID_PNG = 1 << 2, // Invalid screenshot .png (using template one) + VALID_MISSING_RESOURCES = 1 << 3, // Missing resources listed in the code + VALID_MISSING_VCXPROJ = 1 << 4, // Missing Visual Studio .vcxproj file + VALID_NOT_IN_VCXSOL = 1 << 5, // Project not included in solution file + VALID_NOT_IN_MAKEFILE = 1 << 6, // Not listed in Makefile + VALID_NOT_IN_MAKEFILE_WEB = 1 << 7, // Not listed in Makefile.Web + VALID_NOT_IN_README = 1 << 8, // Not listed in README.md + VALID_NOT_IN_JS = 1 << 9, // Not listed in examples.js + VALID_INCONSISTENT_INFO = 1 << 10, // Inconsistent info between collection and example header (stars, author...) + VALID_MISSING_WEB_OUTPUT = 1 << 11, // Missing .html/.data/.wasm/.js + VALID_INVALID_CATEGORY = 1 << 12, // Not a recognized category + VALID_UNKNOWN_ERROR = 1 << 13 // Unknown failure case (fallback) +} rlExampleValidationStatus; + // Example management operations typedef enum { OP_NONE = 0, // No process to do @@ -107,11 +128,12 @@ static const char *exCollectionFilePath = "C:/GitHub/raylib/examples/examples_li //---------------------------------------------------------------------------------- // Module specific functions declaration //---------------------------------------------------------------------------------- +static int FileTextFind(const char *fileName, const char *find); static int FileTextReplace(const char *fileName, const char *textLookUp, const char *textReplace); static int FileCopy(const char *srcPath, const char *dstPath); static int FileRename(const char *fileName, const char *fileRename); -static int FileRemove(const char *fileName); static int FileMove(const char *srcPath, const char *dstPath); +static int FileRemove(const char *fileName); // Update required files from examples collection // UPDATES: Makefile, Makefile.Web, README.md, examples.js @@ -128,6 +150,9 @@ static void UnloadExamplesData(rlExampleInfo *exInfo); static char **LoadTextLines(const char *text, int *count); static void UnloadTextLines(char **text); +// Get example info from file header +static rlExampleInfo *GetExampleInfo(const char *exFileName); + // raylib example line info parser // Parses following line format: core/core_basic_window;⭐️☆☆☆;1.0;1.0;"Ray"/@raysan5 static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry); @@ -406,76 +431,36 @@ int main(int argc, char *argv[]) // Get required example info from example file header (if provided) // NOTE: If no example info is provided (other than category/name), just using some default values - char *exText = LoadFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName)); - - rlExampleInfo exInfo = { 0 }; - strcpy(exInfo.category, exCategory); - strcpy(exInfo.name, exName); + rlExampleInfo *exInfo = GetExampleInfo(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName)); // Get example difficulty stars char starsText[16] = { 0 }; - int starsIndex = TextFindIndex(exText, "★"); - if (starsIndex > 0) strncpy(starsText, exText + starsIndex, 3*4); // NOTE: Every UTF-8 star are 3 bytes - else strcpy(starsText, "★☆☆☆"); - - // Get example create with raylib version - char verCreateText[4] = { 0 }; - int verCreateIndex = TextFindIndex(exText, "created with raylib "); // Version = index + 20 - if (verCreateIndex > 0) strncpy(verCreateText, exText + verCreateIndex + 20, 3); - else strncpy(verCreateText, RAYLIB_VERSION, 3); // Only pick MAJOR.MINOR - - // Get example update with raylib version - char verUpdateText[4] = { 0 }; - int verUpdateIndex = TextFindIndex(exText, "updated with raylib "); // Version = index + 20 - if (verUpdateIndex > 0) strncpy(verUpdateText, exText + verUpdateIndex + 20, 3); - else strncpy(verUpdateText, RAYLIB_VERSION, 3); // Only pick MAJOR.MINOR - - // Get example creator and github user - int authorIndex = TextFindIndex(exText, "Example contributed by "); // Author = index + 23 - int authorGitIndex = TextFindIndex(exText, "(@"); // Author GitHub user = index + 2 - if (authorIndex > 0) + for (int i = 0; i < 4; i++) { - int authorNameLen = 0; - if (authorGitIndex > 0) authorNameLen = (authorGitIndex - 1) - (authorIndex + 23); - else - { - int authorNameEndIndex = TextFindIndex(exText + authorIndex, " and reviewed by Ramon Santamaria"); - if (authorNameEndIndex == -1) authorNameEndIndex = TextFindIndex(exText + authorIndex, "\n"); - - authorNameLen = authorNameEndIndex - (authorIndex + 23); - } - strncpy(exInfo.author, exText + authorIndex + 23, authorNameLen); + // NOTE: Every UTF-8 star are 3 bytes + if (i < exInfo->stars) strncpy(starsText + 3*i, "★", 3); + else strncpy(starsText + 3*i, "☆", 3); } - else strcpy(exInfo.author, ""); - if (authorGitIndex > 0) - { - int authorGitEndIndex = TextFindIndex(exText + authorGitIndex, ")"); - if (authorGitEndIndex > 0) strncpy(exInfo.authorGitHub, exText + authorGitIndex + 2, authorGitEndIndex - (authorGitIndex + 2)); - } - else strcpy(exInfo.author, ""); - - // TODO: Verify copyright line - // Copyright (c) - (@) - UnloadFileText(exText); - if (nextCategoryIndex == -1) { // Add example to collection at the EOF int endIndex = (int)strlen(exCollectionList); memcpy(exCollectionListUpdated, exCollectionList, endIndex); - sprintf(exCollectionListUpdated + endIndex, TextFormat("%s;%s;%s;%s;%s;\"%s\";@%s\n", - exInfo.category, exInfo.name, starsText, verCreateText, verUpdateText, exInfo.author, exInfo.authorGitHub)); + sprintf(exCollectionListUpdated + endIndex, TextFormat("%s;%s;%s;%.2f;%.2f;\"%s\";@%s\n", + exInfo->category, exInfo->name, starsText, exInfo->verCreated, exInfo->verUpdated, exInfo->author, exInfo->authorGitHub)); } else { // Add example to collection, at the end of the category list int categoryIndex = TextFindIndex(exCollectionList, exCategories[nextCategoryIndex]); memcpy(exCollectionListUpdated, exCollectionList, categoryIndex); - int textWritenSize = sprintf(exCollectionListUpdated + categoryIndex, TextFormat("%s;%s;%s;%s;%s;\"%s\";@%s\n", - exInfo.category, exInfo.name, starsText, verCreateText, verUpdateText, exInfo.author, exInfo.authorGitHub)); + int textWritenSize = sprintf(exCollectionListUpdated + categoryIndex, TextFormat("%s;%s;%s;%.2f;%.2f;\"%s\";@%s\n", + exInfo->category, exInfo->name, starsText, exInfo->verCreated, exInfo->verUpdated, exInfo->author, exInfo->authorGitHub)); memcpy(exCollectionListUpdated + categoryIndex + textWritenSize, exCollectionList + categoryIndex, strlen(exCollectionList) - categoryIndex); } + + RL_FREE(exInfo); SaveFileText(exCollectionFilePath, exCollectionListUpdated); RL_FREE(exCollectionListUpdated); @@ -703,29 +688,178 @@ int main(int argc, char *argv[]) case OP_VALIDATE: // Validate: report and actions case OP_UPDATE: { - // TODO: Validate examples in collection list [examples_list.txt] -> Source of truth! - // Validate: raylib/examples//_example_name.c -> File exists? - // Validate: raylib/examples//_example_name.png -> File exists? - // Validate: raylib/examples//resources/.. -> Example resources available? - // Validate: raylib/examples/Makefile -> Example listed? - // Validate: raylib/examples/Makefile.Web -> Example listed? - // Validate: raylib/examples/README.md -> Example listed? - // Validate: raylib/projects/VS2022/examples/_example_name.vcxproj -> File exists? - // Validate: raylib/projects/VS2022/raylib.sln -> Example listed? - // Validate: raylib.com/common/examples.js -> Example listed? - // Validate: raylib.com/examples//_example_name.html -> File exists? - // Validate: raylib.com/examples//_example_name.data -> File exists? - // Validate: raylib.com/examples//_example_name.wasm -> File exists? - // Validate: raylib.com/examples//_example_name.js -> File exists? + /* + // Validation flags available: + VALID_MISSING_C + VALID_MISSING_PNG + VALID_INVALID_PNG + VALID_MISSING_RESOURCES + VALID_MISSING_VCXPROJ + VALID_NOT_IN_VCXSOL + VALID_NOT_IN_MAKEFILE + VALID_NOT_IN_MAKEFILE_WEB + VALID_NOT_IN_README + VALID_NOT_IN_JS + VALID_INCONSISTENT_INFO + VALID_MISSING_WEB_OUTPUT + VALID_INVALID_CATEGORY + */ - // Additional validation elements - // Validate: Example naming conventions: /_example_name - // Validate: Duplicate entries in collection list - // Validate: Example info (stars, author, github) missmatches with example content + // Check all examples in collection [examples_list.txt] -> Source of truth! + int exCollectionCount = 0; + rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, "ALL", true, &exCollectionCount); - // After validation, update required files for consistency - // Update files: Makefile, Makefile.Web, README.md, examples.js - UpdateRequiredFiles(); + // TODO: Validate: Duplicate entries in collection list? + + // Get status information for all examples, using "status" field in the struct + for (int i = 0; i < exCollectionCount; i++) + { + rlExampleInfo *exInfo = &exCollection[i]; + exInfo->status = 0; + + // Validate: raylib/examples//_example_name.c -> File exists? + if (!FileExists(TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name))) exInfo->status |= VALID_MISSING_C; + + // Validate: raylib/examples//_example_name.png -> File exists? + if (!FileExists(TextFormat("%s/%s/%s.png", exBasePath, exInfo->category, exInfo->name))) exInfo->status |= VALID_MISSING_PNG; + + // Validate: example screenshot is not the template default one + Image imScreenshot = LoadImage(TextFormat("%s/%s/%s.png", exBasePath, exInfo->category, exInfo->name)); + Image imTemplate = LoadImage(TextFormat("%s/examples_template.png", exBasePath)); + if (memcmp(imScreenshot.data, imTemplate.data, GetPixelDataSize(imScreenshot.width, imScreenshot.height, imScreenshot.format)) != 0) exInfo->status |= VALID_INVALID_PNG; + UnloadImage(imTemplate); + UnloadImage(imScreenshot); + + // Validate: raylib/examples/Makefile -> Example listed? + if (FileTextFind(TextFormat("%s/Makefile", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_MAKEFILE; + + // Validate: raylib/examples/Makefile.Web -> Example listed? + if (FileTextFind(TextFormat("%s/Makefile.Web", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_MAKEFILE_WEB; + + // Validate: raylib/examples/README.md -> Example listed? + if (FileTextFind(TextFormat("%s/README.md", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_JS; + + // Validate: raylib.com/common/examples.js -> Example listed? + if (FileTextFind(TextFormat("%s/common/examples.js", exWebPath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_README; + + // Validate: raylib/projects/VS2022/examples/_example_name.vcxproj -> File exists? + if (!FileExists(TextFormat("%s/../projects/VS2022/examples/%s.png", exBasePath, exInfo->name))) exInfo->status |= VALID_MISSING_VCXPROJ; + + // Validate: raylib/projects/VS2022/raylib.sln -> Example listed? + if (FileTextFind(TextFormat("%s/../projects/VS2022/raylib.sln", exBasePath), exInfo->name) == -1) exInfo->status |= VALID_NOT_IN_VCXSOL; + + // Validate: raylib/examples//resources/.. -> Example resources available? + // Scan resources used in example to check for missing resource files + char **resPaths = ScanExampleResources(TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name), &exInfo->resCount); + if (exInfo->resCount > 0) + { + for (int r = 0; r < exInfo->resCount; r++) + { + // WARNING: Special case to consider: shaders, resource paths could use conditions: "glsl%i" + // In this case, multiple resources are required: glsl100, glsl120, glsl330 + if (TextFindIndex(resPaths[r], "glsl%i") > -1) + { + int glslVer[3] = { 100, 120, 330 }; + + for (int v = 0; v < 3; v++) + { + char *resPathUpdated = TextReplace(resPaths[r], "glsl%i", TextFormat("glsl%i", glslVer[v])); + if (!FileExists(TextFormat("%s/%s/%s", exBasePath, exInfo->category, resPathUpdated))) exInfo->status |= VALID_MISSING_RESOURCES; + RL_FREE(resPathUpdated); + } + } + else + { + if (!FileExists(TextFormat("%s/%s/%s", exBasePath, exInfo->category, resPaths[r]))) exInfo->status |= VALID_MISSING_RESOURCES; + } + } + } + ClearExampleResources(resPaths); + + // Validate: raylib.com/examples//_example_name.html -> File exists? + // Validate: raylib.com/examples//_example_name.data -> File exists? + // Validate: raylib.com/examples//_example_name.wasm -> File exists? + // Validate: raylib.com/examples//_example_name.js -> File exists? + if ((!FileExists(TextFormat("%s/examples/%s/%s.html", exWebPath, exInfo->category, exInfo->name))) || + ((exInfo->resCount > 0) && !FileExists(TextFormat("%s/examples/%s/%s.data", exWebPath, exInfo->category, exInfo->name))) || + (!FileExists(TextFormat("%s/examples/%s/%s.wasm", exWebPath, exInfo->category, exInfo->name))) || + (!FileExists(TextFormat("%s/examples/%s/%s.js", exWebPath, exInfo->category, exInfo->name)))) exInfo->status |= VALID_MISSING_WEB_OUTPUT; + + // NOTE: Additional validation elements + // Validate: Example naming conventions: /_example_name, valid category + if ((TextFindIndex(exInfo->name, exInfo->category) == -1) || + (!TextIsEqual(exInfo->category, "core") || !TextIsEqual(exInfo->category, "shapes") || + !TextIsEqual(exInfo->category, "textures") || !TextIsEqual(exInfo->category, "text") || + !TextIsEqual(exInfo->category, "models") || !TextIsEqual(exInfo->category, "shaders") || + !TextIsEqual(exInfo->category, "audio") || !TextIsEqual(exInfo->category, "others"))) exInfo->status |= VALID_INVALID_CATEGORY; + + // Validate: Example info (stars, author, github) missmatches with example header content + rlExampleInfo *exInfoHeader = GetExampleInfo(TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name)); + + if ((strcmp(exInfo->name, exInfoHeader->name) != 0) || // NOTE: Get it from example, not file + (strcmp(exInfo->category, exInfoHeader->category) != 0) || + (strcmp(exInfo->author, exInfoHeader->author) != 0) || + (strcmp(exInfo->authorGitHub, exInfoHeader->authorGitHub) != 0) || + (exInfo->stars != exInfoHeader->stars) || + (exInfo->verCreated != exInfoHeader->verCreated) || + (exInfo->verUpdated != exInfoHeader->verUpdated)) exInfo->status |= VALID_INCONSISTENT_INFO; + + RL_FREE(exInfoHeader); + + // TODO: Generate validation report/table with results (.md) + /* + //Status Description + //OK Everything found + //MISSING One or more files are missing, some can be solved automatically + //ERROR Serious inconsistencies + + Columns: + [C] VALID_MISSING_C // Missing .c source file + [PNG] VALID_MISSING_PNG // Missing screenshot .png + [WPNG] VALID_INVALID_PNG // Invalid png screenshot (using template one) + [RES] VALID_MISSING_RESOURCES // Missing resources listed in the code + [VCX] VALID_MISSING_VCXPROJ // Missing Visual Studio .vcxproj file + [SOL] VALID_NOT_IN_VCXSOL // Project not included in solution file + [MK] VALID_NOT_IN_MAKEFILE // Not listed in Makefile + [MKWEB] VALID_NOT_IN_MAKEFILE_WEB // Not listed in Makefile.Web + [RDME] VALID_NOT_IN_README // Not listed in README.md + [JS] VALID_NOT_IN_JS // Not listed in examples.js + [WOUT] VALID_MISSING_WEB_OUTPUT // Missing .html/.data/.wasm/.js + [INFO] VALID_INCONSISTENT_INFO // Inconsistent info between collection and example header (stars, author...) + [CAT] VALID_INVALID_CATEGORY // Not a recognized category + + [STATUS] [CATEGORY] [NAME] [C] [PNG] [WPNG] [RES] [VCX] [SOL] [MK] [MKWEB] [RDME] [JS] [WOUT] [INFO] [CAT] + ----------------------------------------------------------------------------------------------------------------------- + OK core basic_window ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ + MISSING shapes colorful_lines ✘ ✔ ✘ ✔ ✘ ✔ ✔ ✘ ✔ ✔ ✔ ✔ ✔ + ERROR text broken_shader ✘ ✘ ✘ ✘ ✘ ✘ ✘ ✘ ✔ ✘ ✔ ✔ ✔ + */ + } + + UnloadExamplesData(exCollection); + //------------------------------------------------------------------------------------------------ + + if (opCode == OP_UPDATE) + { + // Actions to be performed to fix/review anything possible + //------------------------------------------------------------------------------------------------ + + // TODO: Process validation results and take actions to + // correct everything possible to make collection consistent + + // Review: Add/Remove: raylib/projects/VS2022/examples/_example_name.vcxproj + // Review: Add/remove: raylib/projects/VS2022/raylib.sln + + // Update files: Makefile, Makefile.Web, README.md, examples.js + UpdateRequiredFiles(); + + // Review examples + // Review: Add/Remove: raylib.com/examples//_example_name.html + // Review: Add/Remove: raylib.com/examples//_example_name.data + // Review: Add/Remove: raylib.com/examples//_example_name.wasm + // Review: Add/Remove: raylib.com/examples//_example_name.js + //------------------------------------------------------------------------------------------------ + } } break; default: // Help @@ -1156,6 +1290,21 @@ static void UnloadExamplesData(rlExampleInfo *exInfo) RL_FREE(exInfo); } +// Find text in existing file +static int FileTextFind(const char *fileName, const char *find) +{ + int result = -1; + + if (FileExists(fileName)) + { + char *fileText = LoadFileText(fileName); + result = TextFindIndex(fileText, find); + UnloadFileText(fileText); + } + + return result; +} + // Replace text in an existing file static int FileTextReplace(const char *fileName, const char *textLookUp, const char *textReplace) { @@ -1264,6 +1413,84 @@ static void UnloadTextLines(char **lines) RL_FREE(lines); } +// Get example info from file header +rlExampleInfo *GetExampleInfo(const char *exFileName) +{ + rlExampleInfo *exInfo = (rlExampleInfo *)RL_CALLOC(1, sizeof(rlExampleInfo)); + + if (IsFileExtension(exFileName, ".c")) + { + strcpy(exInfo->name, GetFileNameWithoutExt(exFileName)); + strncpy(exInfo->category, exInfo->name, TextFindIndex(exInfo->name, "_")); + + char *exText = LoadFileText(exFileName); + + // Get example difficulty stars + // NOTE: Counting the unicode char occurrences: ⭐️ + int starsIndex = TextFindIndex(exText, "★"); + if (starsIndex > 0) + { + const char *starPtr = exText + starsIndex; + while (*starPtr) + { + if (((unsigned char)starPtr[0] == 0xe2) && + ((unsigned char)starPtr[1] == 0xad) && + ((unsigned char)starPtr[2] == 0x90)) + { + exInfo->stars++; + starPtr += 3; // Advance past multibyte character + } + else starPtr++; + } + } + + // Get example create with raylib version + char verCreateText[4] = { 0 }; + int verCreateIndex = TextFindIndex(exText, "created with raylib "); // Version = index + 20 + if (verCreateIndex > 0) strncpy(verCreateText, exText + verCreateIndex + 20, 3); + else strncpy(verCreateText, RAYLIB_VERSION, 3); // Only pick MAJOR.MINOR + exInfo->verCreated = TextToFloat(verCreateText); + + // Get example update with raylib version + char verUpdateText[4] = { 0 }; + int verUpdateIndex = TextFindIndex(exText, "updated with raylib "); // Version = index + 20 + if (verUpdateIndex > 0) strncpy(verUpdateText, exText + verUpdateIndex + 20, 3); + else strncpy(verUpdateText, RAYLIB_VERSION, 3); // Only pick MAJOR.MINOR + exInfo->verUpdated = TextToFloat(verUpdateText); + + // Get example creator and github user + int authorIndex = TextFindIndex(exText, "Example contributed by "); // Author = index + 23 + int authorGitIndex = TextFindIndex(exText, "(@"); // Author GitHub user = index + 2 + if (authorIndex > 0) + { + int authorNameLen = 0; + if (authorGitIndex > 0) authorNameLen = (authorGitIndex - 1) - (authorIndex + 23); + else + { + int authorNameEndIndex = TextFindIndex(exText + authorIndex, " and reviewed by Ramon Santamaria"); + if (authorNameEndIndex == -1) authorNameEndIndex = TextFindIndex(exText + authorIndex, "\n"); + + authorNameLen = authorNameEndIndex - (authorIndex + 23); + } + strncpy(exInfo->author, exText + authorIndex + 23, authorNameLen); + } + else strcpy(exInfo->author, ""); + if (authorGitIndex > 0) + { + int authorGitEndIndex = TextFindIndex(exText + authorGitIndex, ")"); + if (authorGitEndIndex > 0) strncpy(exInfo->authorGitHub, exText + authorGitIndex + 2, authorGitEndIndex - (authorGitIndex + 2)); + } + else strcpy(exInfo->authorGitHub, ""); + + // TODO: Verify copyright line + // Copyright (c) - (@) + + UnloadFileText(exText); + } + + return exInfo; +} + // raylib example line info parser // Parses following line format: core;core_basic_window;⭐️☆☆☆;1.0;1.0;"Ray";@raysan5 static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry) @@ -1283,17 +1510,17 @@ static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry) // Parsing stars // NOTE: Counting the unicode char occurrences: ⭐️ - const char *ptr = tokens[2]; - while (*ptr) + const char *starPtr = tokens[2]; + while (*starPtr) { - if (((unsigned char)ptr[0] == 0xE2) && - ((unsigned char)ptr[1] == 0xAD) && - ((unsigned char)ptr[2] == 0x90)) + if (((unsigned char)starPtr[0] == 0xe2) && + ((unsigned char)starPtr[1] == 0xad) && + ((unsigned char)starPtr[2] == 0x90)) { entry->stars++; - ptr += 3; // Advance past multibyte character + starPtr += 3; // Advance past multibyte character } - else ptr++; + else starPtr++; } // Get raylib creation/update versions @@ -1352,7 +1579,7 @@ static char **ScanExampleResources(const char *filePath, int *resPathCount) char *end = strchr(start, '"'); if (!end) break; - int len = end - start; + int len = (int)(end - start); if ((len > 0) && (len < REXM_MAX_RESOURCE_PATH_LEN)) { char buffer[REXM_MAX_RESOURCE_PATH_LEN] = { 0 };