From d88f27f08d160edaae89a04828aee6cc3650fa04 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 1 Aug 2025 00:30:01 +0200 Subject: [PATCH] NEW: ADDED: `rexm` - A simple command-line tool to manage raylib examples -WIP- --- examples/rexm.c | 349 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 349 insertions(+) create mode 100644 examples/rexm.c diff --git a/examples/rexm.c b/examples/rexm.c new file mode 100644 index 000000000..d40c2ce1c --- /dev/null +++ b/examples/rexm.c @@ -0,0 +1,349 @@ +/******************************************************************************************* +* +* rexm [raylib examples manager] - A simple command-line tool to manage raylib examples +* +* Supported processes: +* - create +* - add +* - rename +* - remove +* +* Files involved in the processes: +* - raylib/examples//_example_name.c +* - raylib/examples//_example_name.png +* - raylib/examples//resources/.. +* - raylib/examples/Makefile +* - raylib/examples/Makefile.Web +* - raylib/examples/README.md +* - raylib/projects/VS2022/examples/_example_name.vcxproj +* - raylib/projects/VS2022/raylib.sln +* - raylib.com/common/examples.js +* - raylib.com/examples//_example_name.html +* - raylib.com/examples//_example_name.data +* - raylib.com/examples//_example_name.wasm +* - raylib.com/examples//_example_name.js +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2025 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" + +#include +#include // Required for: rename(), remove() +#include // Required for: strcmp(), strcpy() + +#define SUPPORT_LOG_INFO +#if defined(SUPPORT_LOG_INFO) && defined(_DEBUG) + #define LOG(...) printf(__VA_ARGS__) +#else + #define LOG(...) +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// Example management operations +typedef enum { + OP_NONE = 0, + OP_CREATE = 1, + OP_ADD = 2, + OP_RENAME = 3, + OP_REMOVE = 4 +} ExampleOperation; + +//---------------------------------------------------------------------------------- +// Module specific functions declaration +//---------------------------------------------------------------------------------- +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); // TODO: Implement, make sure to deal with paths moving +static int FileRemove(const char *fileName); // TODO: Implement + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(int argc, char *argv[]) +{ + // Examples path for building + // TODO: Avoid hardcoding path values... + char *exBasePath = "C:/GitHub/raylib/examples"; + char *exWebPath = "C:/GitHub/raylib.com/examples"; + char *exTemplateFilePath = "C:/GitHub/raylib/examples/examples_template.c"; + + char inFileName[1024] = { 0 }; // Example input filename + + char exName[1024] = { 0 }; // Example name, without extension: core_basic_window + char exCategory[32] = { 0 }; // Example category: core + char exRename[1024] = { 0 }; // Example re-name, without extension + char exPath[1024] = { 0 }; // Example path -NOT USED- + char exFullPath[1024] = { 0 }; // Example full path -NOT USED- + + int opCode = OP_NONE; // Operation code: 0-None(Help), 1-Create, 2-Add, 3-Rename, 4-Remove + + // Command-line usage mode + //-------------------------------------------------------------------------------------- + if (argc > 1) + { + // Supported commands: + // help : Provides command-line usage information (default) + // create : Creates an empty example, from internal template + // add : Add existing example, category extracted from name + // rename : Rename an existing example + // remove : Remove an existing example + if (strcmp(argv[1], "create") == 0) + { + // Check for valid upcoming argument + if (argc == 2) LOG("WARNING: No filename provided to create\n"); + else if (argc > 3) LOG("WARNING: Too many arguments provided\n"); + else + { + // TODO: Additional security checks for file name? + + strcpy(inFileName, argv[2]); // Register filename for creation + opCode = 1; + } + } + else if (strcmp(argv[1], "add") == 0) + { + // Check for valid upcoming argument + if (argc == 2) LOG("WARNING: No filename provided to create\n"); + else if (argc > 3) LOG("WARNING: Too many arguments provided\n"); + else + { + if (IsFileExtension(argv[2], ".c")) // Check for valid file extension: input + { + // TODO: Parse category name from filename provided! + + strcpy(inFileName, argv[2]); // Register filename for creation + opCode = 2; + } + else LOG("WARNING: Input file extension not recognized (.c)\n"); + } + } + else if (strcmp(argv[1], "rename") == 0) + { + if (argc == 2) LOG("WARNING: No filename provided to create\n"); + else if (argc == 3) LOG("WARNING: No enough arguments provided\n"); + else if (argc > 4) LOG("WARNING: Too many arguments provided\n"); + else + { + // TODO: Register exName, exCategory and exRename + + opCode = 3; + } + } + else if (strcmp(argv[1], "remove") == 0) + { + // Check for valid upcoming argument + if (argc == 2) LOG("WARNING: No filename provided to create\n"); + else if (argc > 3) LOG("WARNING: Too many arguments provided\n"); + else + { + strcpy(inFileName, argv[2]); // Register filename for removal + opCode = 4; + } + } + } + + switch (opCode) + { + case 1: // Create: New example from template + { + // Copy template file as new example + FileCopy(exTemplateFilePath, TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName)); + } + case 2: // Add: Example from command-line input filename + { + if ((opCode != 1) && FileExists(inFileName)) + { + FileCopy(inFileName, TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName)); + } + + // Generate all required files + //-------------------------------------------------------------------------------- + // Create: raylib/examples//_example_name.c + // Create: raylib/examples//_example_name.png + FileCopy("C:/GitHub/raylib/examples/examples_template.png", + TextFormat("%s/%s/%s.png", exBasePath, exCategory, exName)); // To be updated manually! + + // Copy: raylib/examples//resources/*.* ---> To be updated manually! + + // TODO: Update the required files to add new example in the required position (ordered by category and name), + // it could require some logic to make it possible... + + // Edit: raylib/examples/Makefile --> Add new example + // Edit: raylib/examples/Makefile.Web --> Add new example + // Edit: raylib/examples/README.md --> Add new example + + // Create: raylib/projects/VS2022/examples/_example_name.vcxproj + // Edit: raylib/projects/VS2022/raylib.sln --> Add new example + // Edit: raylib.com/common/examples.js --> Add new example + + // Compile to: raylib.com/examples//_example_name.html + // Compile to: raylib.com/examples//_example_name.data + // Compile to: raylib.com/examples//_example_name.wasm + // Compile to: raylib.com/examples//_example_name.js + + // Recompile example (on raylib side) + // NOTE: Tools requirements: emscripten, w64devkit + system(TextFormat("%s/../build_example_web.bat %s\%s", exBasePath, exCategory, exName)); + + // Copy results to web side + FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName), + TextFormat("%s/%s/%s.html", exWebPath, exCategory, exName)); + FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exCategory, exName), + TextFormat("%s/%s/%s.data", exWebPath, exCategory, exName)); + FileCopy(TextFormat("%s/%s/%s.wasm", exBasePath, exCategory, exName), + TextFormat("%s/%s/%s.wasm", exWebPath, exCategory, exName)); + FileCopy(TextFormat("%s/%s/%s.js", exBasePath, exCategory, exName), + TextFormat("%s/%s/%s.js", exWebPath, exCategory, exName)); + } break; + case 3: // Rename + { + // Rename all required files + rename(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName), + TextFormat("%s/%s/%s.c", exBasePath, exCategory, exRename)); + rename(TextFormat("%s/%s/%s.png", exBasePath, exCategory, exName), + TextFormat("%s/%s/%s.png", exBasePath, exCategory, exRename)); + + FileTextReplace(TextFormat("%s/Makefile", exBasePath), exName, exRename); + FileTextReplace(TextFormat("%s/Makefile.Web", exBasePath), exName, exRename); + FileTextReplace(TextFormat("%s/README.md", exBasePath), exName, exRename); + + rename(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName), + TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exRename)); + FileTextReplace(TextFormat("%s/../projects/VS2022/raylib.sln", exBasePath), exName, exRename); + + // Remove old web compilation + FileTextReplace(TextFormat("%s/../common/examples.js", exWebPath), exName, exRename); + remove(TextFormat("%s/%s/%s.html", exWebPath, exCategory, exName)); + remove(TextFormat("%s/%s/%s.data", exWebPath, exCategory, exName)); + remove(TextFormat("%s/%s/%s.wasm", exWebPath, exCategory, exName)); + remove(TextFormat("%s/%s/%s.js", exWebPath, exCategory, exName)); + + // Recompile example (on raylib side) + // NOTE: Tools requirements: emscripten, w64devkit + system(TextFormat("%s/../build_example_web.bat %s\%s", exBasePath, exCategory, exName)); + + // Copy results to web side + FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName), + TextFormat("%s/%s/%s.html", exWebPath, exCategory, exName)); + FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exCategory, exName), + TextFormat("%s/%s/%s.data", exWebPath, exCategory, exName)); + FileCopy(TextFormat("%s/%s/%s.wasm", exBasePath, exCategory, exName), + TextFormat("%s/%s/%s.wasm", exWebPath, exCategory, exName)); + FileCopy(TextFormat("%s/%s/%s.js", exBasePath, exCategory, exName), + TextFormat("%s/%s/%s.js", exWebPath, exCategory, exName)); + } break; + case 4: // Remove + { + // TODO: Remove and update all required files... + + } break; + default: // Help + { + // Supported commands: + // help : Provides command-line usage information + // create : Creates an empty example, from internal template + // add : Add existing example, category extracted from name + // rename : Rename an existing example + // remove : Remove an existing example + + printf("\n////////////////////////////////////////////////////////////////////////////////////////////\n"); + printf("// //\n"); + printf("// rem [raylib examples manager] - A simple command-line tool to manage raylib examples //\n"); + printf("// powered by raylib v5.6-dev //\n"); + printf("// //\n"); + printf("// Copyright (c) 2025 Ramon Santamaria (@raysan5) //\n"); + printf("// //\n"); + printf("////////////////////////////////////////////////////////////////////////////////////////////\n\n"); + + printf("USAGE:\n\n"); + printf(" > rem help|create|add|rename|remove []\n"); + + printf("\nOPTIONS:\n\n"); + printf(" help : Provides command-line usage information\n"); + printf(" create : Creates an empty example, from internal template\n"); + printf(" add : Add existing example, category extracted from name\n"); + printf(" Supported categories: core, shapes, textures, text, models\n\n"); + printf(" rename : Rename an existing example\n"); + printf(" remove : Remove an existing example\n\n"); + printf("\nEXAMPLES:\n\n"); + printf(" > rem rename core_basic_window core_cool_window\n"); + printf(" Renames and updates example to \n\n"); + printf(" > rem add shapes_custom_stars\n"); + printf(" Add and updates new example provided \n\n"); + } break; + } + + return 0; +} + +//---------------------------------------------------------------------------------- +// Module specific functions definition +//---------------------------------------------------------------------------------- +static int FileTextReplace(const char *fileName, const char *textLookUp, const char *textReplace) +{ + int result = 0; + char *fileText = NULL; + char *fileTextUpdated = { 0 }; + + fileText = LoadFileText(fileName); + fileTextUpdated = TextReplace(fileText, textLookUp, textReplace); + result = SaveFileText(fileName, fileTextUpdated); + MemFree(fileTextUpdated); + UnloadFileText(fileText); + + return result; +} + +static int FileCopy(const char *srcPath, const char *dstPath) +{ + int result = 0; + int srcDataSize = 0; + unsigned char *srcFileData = LoadFileData(srcPath, &srcDataSize); + + if ((srcFileData != NULL) && (srcDataSize > 0)) result = SaveFileData(dstPath, srcFileData, srcDataSize); + + UnloadFileData(srcFileData); + + return result; +} + +static int FileRename(const char *fileName, const char *fileRename) +{ + int result = 0; + + // TODO: Make sure to deal with paths properly for file moving if required + + if (FileExists(fileName)) rename(fileName, TextFormat("%s/%s", GetDirectoryPath(fileName), fileRename)); + + return result; +} + +static int FileRemove(const char *fileName) +{ + int result = 0; + + if (FileExists(fileName)) remove(fileName); + + return result; +}