|
|
@ -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: <category>_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) |
|
|
|
{ |
|
|
|
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, "<author_name>"); |
|
|
|
if (authorGitIndex > 0) |
|
|
|
for (int i = 0; i < 4; i++) |
|
|
|
{ |
|
|
|
int authorGitEndIndex = TextFindIndex(exText + authorGitIndex, ")"); |
|
|
|
if (authorGitEndIndex > 0) strncpy(exInfo.authorGitHub, exText + authorGitIndex + 2, authorGitEndIndex - (authorGitIndex + 2)); |
|
|
|
// 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, "<user_github>"); |
|
|
|
|
|
|
|
// TODO: Verify copyright line |
|
|
|
// Copyright (c) <year_created>-<year_updated> <user_name> (@<user_github>) |
|
|
|
|
|
|
|
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", |
|
|
|
exInfop">.category, exInfop">.name, starsText, verCreateText, verUpdateText, exInfo.author, exInfop">.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", |
|
|
|
exInfop">.category, exInfop">.name, starsText, verCreateText, verUpdateText, exInfo.author, exInfop">.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/<category>/<category>_example_name.c -> File exists? |
|
|
|
// Validate: raylib/examples/<category>/<category>_example_name.png -> File exists? |
|
|
|
// Validate: raylib/examples/<category>/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/<category>_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/<category>/<category>_example_name.html -> File exists? |
|
|
|
// Validate: raylib.com/examples/<category>/<category>_example_name.data -> File exists? |
|
|
|
// Validate: raylib.com/examples/<category>/<category>_example_name.wasm -> File exists? |
|
|
|
// Validate: raylib.com/examples/<category>/<category>_example_name.js -> File exists? |
|
|
|
|
|
|
|
// Additional validation elements |
|
|
|
// Validate: Example naming conventions: <category>/<category>_example_name |
|
|
|
// Validate: Duplicate entries in collection list |
|
|
|
// Validate: Example info (stars, author, github) missmatches with example content |
|
|
|
|
|
|
|
// After validation, update required files for consistency |
|
|
|
// Update files: Makefile, Makefile.Web, README.md, examples.js |
|
|
|
UpdateRequiredFiles(); |
|
|
|
/* |
|
|
|
// 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 |
|
|
|
*/ |
|
|
|
|
|
|
|
// Check all examples in collection [examples_list.txt] -> Source of truth! |
|
|
|
int exCollectionCount = 0; |
|
|
|
rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, "ALL", true, &exCollectionCount); |
|
|
|
|
|
|
|
// 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/<category>/<category>_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/<category>/<category>_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/<category>_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/<category>/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/<category>/<category>_example_name.html -> File exists? |
|
|
|
// Validate: raylib.com/examples/<category>/<category>_example_name.data -> File exists? |
|
|
|
// Validate: raylib.com/examples/<category>/<category>_example_name.wasm -> File exists? |
|
|
|
// Validate: raylib.com/examples/<category>/<category>_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: <category>/<category>_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/<category>_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/<category>/<category>_example_name.html |
|
|
|
// Review: Add/Remove: raylib.com/examples/<category>/<category>_example_name.data |
|
|
|
// Review: Add/Remove: raylib.com/examples/<category>/<category>_example_name.wasm |
|
|
|
// Review: Add/Remove: raylib.com/examples/<category>/<category>_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, "<author_name>"); |
|
|
|
if (authorGitIndex > 0) |
|
|
|
{ |
|
|
|
int authorGitEndIndex = TextFindIndex(exText + authorGitIndex, ")"); |
|
|
|
if (authorGitEndIndex > 0) strncpy(exInfo->authorGitHub, exText + authorGitIndex + 2, authorGitEndIndex - (authorGitIndex + 2)); |
|
|
|
} |
|
|
|
else strcpy(exInfo->authorGitHub, "<user_github>"); |
|
|
|
|
|
|
|
// TODO: Verify copyright line |
|
|
|
// Copyright (c) <year_created>-<year_updated> <user_name> (@<user_github>) |
|
|
|
|
|
|
|
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 = p">(int)(end - start); |
|
|
|
if ((len > 0) && (len < REXM_MAX_RESOURCE_PATH_LEN)) |
|
|
|
{ |
|
|
|
char buffer[REXM_MAX_RESOURCE_PATH_LEN] = { 0 }; |
|
|
|