|
@@ -0,0 +1,349 @@
|
|
|
+/*******************************************************************************************
|
|
|
+*
|
|
|
+* rexm [raylib examples manager] - A simple command-line tool to manage raylib examples
|
|
|
+*
|
|
|
+* Supported processes:
|
|
|
+* - create <new_example_name>
|
|
|
+* - add <example_name>
|
|
|
+* - rename <old_examples_name> <new_example_name>
|
|
|
+* - remove <example_name>
|
|
|
+*
|
|
|
+* Files involved in the processes:
|
|
|
+* - raylib/examples/<category>/<category>_example_name.c
|
|
|
+* - raylib/examples/<category>/<category>_example_name.png
|
|
|
+* - raylib/examples/<category>/resources/..
|
|
|
+* - raylib/examples/Makefile
|
|
|
+* - raylib/examples/Makefile.Web
|
|
|
+* - raylib/examples/README.md
|
|
|
+* - raylib/projects/VS2022/examples/<category>_example_name.vcxproj
|
|
|
+* - raylib/projects/VS2022/raylib.sln
|
|
|
+* - raylib.com/common/examples.js
|
|
|
+* - raylib.com/examples/<category>/<category>_example_name.html
|
|
|
+* - raylib.com/examples/<category>/<category>_example_name.data
|
|
|
+* - raylib.com/examples/<category>/<category>_example_name.wasm
|
|
|
+* - raylib.com/examples/<category>/<category>_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 <stdlib.h>
|
|
|
+#include <stdio.h> // Required for: rename(), remove()
|
|
|
+#include <string.h> // 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 <new_example_name> : Creates an empty example, from internal template
|
|
|
+ // add <example_name> : Add existing example, category extracted from name
|
|
|
+ // rename <old_examples_name> <new_example_name> : Rename an existing example
|
|
|
+ // remove <example_name> : 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/<category>/<category>_example_name.c
|
|
|
+ // Create: raylib/examples/<category>/<category>_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/<category>/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/<category>_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/<category>/<category>_example_name.html
|
|
|
+ // Compile to: raylib.com/examples/<category>/<category>_example_name.data
|
|
|
+ // Compile to: raylib.com/examples/<category>/<category>_example_name.wasm
|
|
|
+ // Compile to: raylib.com/examples/<category>/<category>_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 <new_example_name> : Creates an empty example, from internal template
|
|
|
+ // add <example_name> : Add existing example, category extracted from name
|
|
|
+ // rename <old_examples_name> <new_example_name> : Rename an existing example
|
|
|
+ // remove <example_name> : 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 <example_name> [<example_rename>]\n");
|
|
|
+
|
|
|
+ printf("\nOPTIONS:\n\n");
|
|
|
+ printf(" help : Provides command-line usage information\n");
|
|
|
+ printf(" create <new_example_name> : Creates an empty example, from internal template\n");
|
|
|
+ printf(" add <example_name> : Add existing example, category extracted from name\n");
|
|
|
+ printf(" Supported categories: core, shapes, textures, text, models\n\n");
|
|
|
+ printf(" rename <old_examples_name> <new_example_name> : Rename an existing example\n");
|
|
|
+ printf(" remove <example_name> : 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 <core_basic_window> to <core_cool_window>\n\n");
|
|
|
+ printf(" > rem add shapes_custom_stars\n");
|
|
|
+ printf(" Add and updates new example provided <shapes_custom_stars>\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;
|
|
|
+}
|