/**********************************************************************************************
							 | 
						|
								
							 | 
						|
								    raylib API parser
							 | 
						|
								
							 | 
						|
								    This parser scans raylib.h to get API information about defines, structs, aliases, enums, callbacks and functions.
							 | 
						|
								    All data is divided into pieces, usually as strings. The following types are used for data:
							 | 
						|
								
							 | 
						|
								     - struct DefineInfo
							 | 
						|
								     - struct StructInfo
							 | 
						|
								     - struct AliasInfo
							 | 
						|
								     - struct EnumInfo
							 | 
						|
								     - struct FunctionInfo
							 | 
						|
								
							 | 
						|
								    CONSTRAINTS:
							 | 
						|
								
							 | 
						|
								    This parser is specifically designed to work with raylib.h, so, it has some constraints:
							 | 
						|
								
							 | 
						|
								     - Functions are expected as a single line with the following structure:
							 | 
						|
								
							 | 
						|
								       <retType> <name>(<paramType[0]> <paramName[0]>, <paramType[1]> <paramName[1]>);  <desc>
							 | 
						|
								
							 | 
						|
								       Be careful with functions broken into several lines, it breaks the process!
							 | 
						|
								
							 | 
						|
								     - Structures are expected as several lines with the following form:
							 | 
						|
								
							 | 
						|
								       <desc>
							 | 
						|
								       typedef struct <name> {
							 | 
						|
								           <fieldType[0]> <fieldName[0]>;  <fieldDesc[0]>
							 | 
						|
								           <fieldType[1]> <fieldName[1]>;  <fieldDesc[1]>
							 | 
						|
								           <fieldType[2]> <fieldName[2]>;  <fieldDesc[2]>
							 | 
						|
								       } <name>;
							 | 
						|
								
							 | 
						|
								     - Enums are expected as several lines with the following form:
							 | 
						|
								
							 | 
						|
								       <desc>
							 | 
						|
								       typedef enum {
							 | 
						|
								           <valueName[0]> = <valueInteger[0]>, <valueDesc[0]>
							 | 
						|
								           <valueName[1]>,
							 | 
						|
								           <valueName[2]>, <valueDesc[2]>
							 | 
						|
								           <valueName[3]>  <valueDesc[3]>
							 | 
						|
								       } <name>;
							 | 
						|
								
							 | 
						|
								       NOTE: Multiple options are supported for enums:
							 | 
						|
								          - If value is not provided, (<valueInteger[i -1]> + 1) is assigned
							 | 
						|
								          - Value description can be provided or not
							 | 
						|
								
							 | 
						|
								    OTHER NOTES:
							 | 
						|
								
							 | 
						|
								     - This parser could work with other C header files if mentioned constraints are followed.
							 | 
						|
								     - This parser does not require <string.h> library, all data is parsed directly from char buffers.
							 | 
						|
								
							 | 
						|
								    LICENSE: zlib/libpng
							 | 
						|
								
							 | 
						|
								    raylib-parser is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
							 | 
						|
								    BSD-like license that allows static linking with closed source software:
							 | 
						|
								
							 | 
						|
								    Copyright (c) 2021-2025 Ramon Santamaria (@raysan5)
							 | 
						|
								
							 | 
						|
								**********************************************************************************************/
							 | 
						|
								
							 | 
						|
								#define _CRT_SECURE_NO_WARNINGS
							 | 
						|
								
							 | 
						|
								#include <stdlib.h>             // Required for: malloc(), calloc(), realloc(), free(), atoi(), strtol()
							 | 
						|
								#include <stdio.h>              // Required for: printf(), fopen(), fseek(), ftell(), fread(), fclose()
							 | 
						|
								#include <stdbool.h>            // Required for: bool
							 | 
						|
								#include <ctype.h>              // Required for: isdigit()
							 | 
						|
								
							 | 
						|
								#define MAX_DEFINES_TO_PARSE    2048    // Maximum number of defines to parse
							 | 
						|
								#define MAX_STRUCTS_TO_PARSE      64    // Maximum number of structures to parse
							 | 
						|
								#define MAX_ALIASES_TO_PARSE      64    // Maximum number of aliases to parse
							 | 
						|
								#define MAX_ENUMS_TO_PARSE        64    // Maximum number of enums to parse
							 | 
						|
								#define MAX_CALLBACKS_TO_PARSE    64    // Maximum number of callbacks to parse
							 | 
						|
								#define MAX_FUNCS_TO_PARSE      1024    // Maximum number of functions to parse
							 | 
						|
								
							 | 
						|
								#define MAX_LINE_LENGTH         1024    // Maximum length of one line (including comments)
							 | 
						|
								
							 | 
						|
								#define MAX_STRUCT_FIELDS         64    // Maximum number of struct fields
							 | 
						|
								#define MAX_ENUM_VALUES          512    // Maximum number of enum values
							 | 
						|
								#define MAX_FUNCTION_PARAMETERS   12    // Maximum number of function parameters
							 | 
						|
								
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								// Types and Structures Definition
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								// Type of parsed define
							 | 
						|
								typedef enum {
							 | 
						|
								    UNKNOWN = 0,
							 | 
						|
								    MACRO,
							 | 
						|
								    GUARD,
							 | 
						|
								    INT,
							 | 
						|
								    INT_MATH,
							 | 
						|
								    LONG,
							 | 
						|
								    LONG_MATH,
							 | 
						|
								    FLOAT,
							 | 
						|
								    FLOAT_MATH,
							 | 
						|
								    DOUBLE,
							 | 
						|
								    DOUBLE_MATH,
							 | 
						|
								    CHAR,
							 | 
						|
								    STRING,
							 | 
						|
								    COLOR
							 | 
						|
								} DefineType;
							 | 
						|
								
							 | 
						|
								// Define info data
							 | 
						|
								typedef struct DefineInfo {
							 | 
						|
								    char name[64];              // Define name
							 | 
						|
								    int type;                   // Define type
							 | 
						|
								    char value[256];            // Define value
							 | 
						|
								    char desc[128];             // Define description
							 | 
						|
								    bool isHex;                 // Define is hex number (for types INT, LONG)
							 | 
						|
								} DefineInfo;
							 | 
						|
								
							 | 
						|
								// Struct info data
							 | 
						|
								typedef struct StructInfo {
							 | 
						|
								    char name[64];              // Struct name
							 | 
						|
								    char desc[128];             // Struct type description
							 | 
						|
								    int fieldCount;             // Number of fields in the struct
							 | 
						|
								    char fieldType[MAX_STRUCT_FIELDS][64];     // Field type
							 | 
						|
								    char fieldName[MAX_STRUCT_FIELDS][64];     // Field name
							 | 
						|
								    char fieldDesc[MAX_STRUCT_FIELDS][128];    // Field description
							 | 
						|
								} StructInfo;
							 | 
						|
								
							 | 
						|
								// Alias info data
							 | 
						|
								typedef struct AliasInfo {
							 | 
						|
								    char type[64];              // Alias type
							 | 
						|
								    char name[64];              // Alias name
							 | 
						|
								    char desc[128];             // Alias description
							 | 
						|
								} AliasInfo;
							 | 
						|
								
							 | 
						|
								// Enum info data
							 | 
						|
								typedef struct EnumInfo {
							 | 
						|
								    char name[64];              // Enum name
							 | 
						|
								    char desc[128];             // Enum description
							 | 
						|
								    int valueCount;             // Number of values in enumerator
							 | 
						|
								    char valueName[MAX_ENUM_VALUES][64];    // Value name definition
							 | 
						|
								    int valueInteger[MAX_ENUM_VALUES];      // Value integer
							 | 
						|
								    char valueDesc[MAX_ENUM_VALUES][128];   // Value description
							 | 
						|
								} EnumInfo;
							 | 
						|
								
							 | 
						|
								// Function info data
							 | 
						|
								typedef struct FunctionInfo {
							 | 
						|
								    char name[64];              // Function name
							 | 
						|
								    char desc[512];             // Function description (comment at the end)
							 | 
						|
								    char retType[32];           // Return value type
							 | 
						|
								    int paramCount;             // Number of function parameters
							 | 
						|
								    char paramType[MAX_FUNCTION_PARAMETERS][32];   // Parameters type
							 | 
						|
								    char paramName[MAX_FUNCTION_PARAMETERS][32];   // Parameters name
							 | 
						|
								    char paramDesc[MAX_FUNCTION_PARAMETERS][128];  // Parameters description
							 | 
						|
								} FunctionInfo;
							 | 
						|
								
							 | 
						|
								// Output format for parsed data
							 | 
						|
								typedef enum { DEFAULT = 0, JSON, XML, LUA, CODE } OutputFormat;
							 | 
						|
								
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								// Global Variables Definition
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								static int defineCount = 0;
							 | 
						|
								static int structCount = 0;
							 | 
						|
								static int aliasCount = 0;
							 | 
						|
								static int enumCount = 0;
							 | 
						|
								static int callbackCount = 0;
							 | 
						|
								static int funcCount = 0;
							 | 
						|
								static DefineInfo *defines = NULL;
							 | 
						|
								static StructInfo *structs = NULL;
							 | 
						|
								static AliasInfo *aliases = NULL;
							 | 
						|
								static EnumInfo *enums = NULL;
							 | 
						|
								static FunctionInfo *callbacks = NULL;
							 | 
						|
								static FunctionInfo *funcs = NULL;
							 | 
						|
								
							 | 
						|
								// Command line variables
							 | 
						|
								static char apiDefine[32] = { 0 };         // Functions define (i.e. RLAPI for raylib.h, RMDEF for raymath.h, etc.)
							 | 
						|
								static char truncAfter[32] = { 0 };        // Truncate marker (i.e. "RLGL IMPLEMENTATION" for rlgl.h)
							 | 
						|
								static int outputFormat = DEFAULT;
							 | 
						|
								
							 | 
						|
								// NOTE: Max length depends on OS, in Windows MAX_PATH = 256
							 | 
						|
								static char inFileName[512] = { 0 };        // Input file name (required in case of drag & drop over executable)
							 | 
						|
								static char outFileName[512] = { 0 };       // Output file name (required for file save/export)
							 | 
						|
								
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								// Module Functions Declaration
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								static void ShowCommandLineInfo(void);                      // Show command line usage info
							 | 
						|
								static void ProcessCommandLine(int argc, char *argv[]);     // Process command line input
							 | 
						|
								
							 | 
						|
								static char *LoadFileText(const char *fileName, int *length);
							 | 
						|
								static char **GetTextLines(const char *buffer, int length, int *linesCount);
							 | 
						|
								static void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name);
							 | 
						|
								static void GetDescription(const char *source, char *description);
							 | 
						|
								static void MoveArraySize(char *name, char *type);          // Move array size from name to type
							 | 
						|
								static unsigned int TextLength(const char *text);           // Get text length in bytes, check for \0 character
							 | 
						|
								static bool IsTextEqual(const char *text1, const char *text2, unsigned int count);
							 | 
						|
								static int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string
							 | 
						|
								static void MemoryCopy(void *dest, const void *src, unsigned int count);
							 | 
						|
								static char *EscapeBackslashes(char *text);                 // Replace '\' by "\\" when exporting to JSON and XML
							 | 
						|
								static const char *StrDefineType(DefineType type);          // Get string of define type
							 | 
						|
								
							 | 
						|
								static void ExportParsedData(const char *fileName, int format); // Export parsed data in desired format
							 | 
						|
								
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								// Program main entry point
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								int main(int argc, char* argv[])
							 | 
						|
								{
							 | 
						|
								    if (argc > 1) ProcessCommandLine(argc, argv);
							 | 
						|
								
							 | 
						|
								    const char *raylibhPath = "../src/raylib.h\0";
							 | 
						|
								    const char *raylibapiPath = "raylib_api.txt\0";
							 | 
						|
								    const char *rlapiPath = "RLAPI\0";
							 | 
						|
								    if (inFileName[0] == '\0') MemoryCopy(inFileName, raylibhPath, TextLength(raylibhPath) + 1);
							 | 
						|
								    if (outFileName[0] == '\0') MemoryCopy(outFileName, raylibapiPath, TextLength(raylibapiPath) + 1);
							 | 
						|
								    if (apiDefine[0] == '\0') MemoryCopy(apiDefine, rlapiPath, TextLength(rlapiPath) + 1);
							 | 
						|
								
							 | 
						|
								    int length = 0;
							 | 
						|
								    char *buffer = LoadFileText(inFileName, &length);
							 | 
						|
								
							 | 
						|
								    if (buffer == NULL)
							 | 
						|
								    {
							 | 
						|
								        printf("Could not read input file: %s\n", inFileName);
							 | 
						|
								        return 1;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Preprocess buffer to get separate lines
							 | 
						|
								    // NOTE: GetTextLines() also removes leading spaces/tabs
							 | 
						|
								    int linesCount = 0;
							 | 
						|
								    char **lines = GetTextLines(buffer, length, &linesCount);
							 | 
						|
								
							 | 
						|
								    // Truncate lines
							 | 
						|
								    if (truncAfter[0] != '\0')
							 | 
						|
								    {
							 | 
						|
								        int newCount = -1;
							 | 
						|
								        for (int i = 0; i < linesCount; i++)
							 | 
						|
								        {
							 | 
						|
								            if (newCount > -1) free(lines[i]);
							 | 
						|
								            else if (TextFindIndex(lines[i], truncAfter) > -1) newCount = i;
							 | 
						|
								        }
							 | 
						|
								        if (newCount > -1) linesCount = newCount;
							 | 
						|
								        printf("Number of truncated text lines: %i\n", linesCount);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Defines line indices
							 | 
						|
								    int *defineLines = (int *)malloc(MAX_DEFINES_TO_PARSE*sizeof(int));
							 | 
						|
								
							 | 
						|
								    // Structs line indices
							 | 
						|
								    int *structLines = (int *)malloc(MAX_STRUCTS_TO_PARSE*sizeof(int));
							 | 
						|
								
							 | 
						|
								    // Aliases line indices
							 | 
						|
								    int *aliasLines = (int *)malloc(MAX_ALIASES_TO_PARSE*sizeof(int));
							 | 
						|
								
							 | 
						|
								    // Enums line indices
							 | 
						|
								    int *enumLines = (int *)malloc(MAX_ENUMS_TO_PARSE*sizeof(int));
							 | 
						|
								
							 | 
						|
								    // Callbacks line indices
							 | 
						|
								    int *callbackLines = (int *)malloc(MAX_CALLBACKS_TO_PARSE*sizeof(int));
							 | 
						|
								
							 | 
						|
								    // Function line indices
							 | 
						|
								    int *funcLines = (int *)malloc(MAX_FUNCS_TO_PARSE*sizeof(int));
							 | 
						|
								
							 | 
						|
								    // Prepare required lines for parsing
							 | 
						|
								    //----------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								    // Read define lines
							 | 
						|
								    for (int i = 0; i < linesCount; i++)
							 | 
						|
								    {
							 | 
						|
								        int j = 0;
							 | 
						|
								        while ((lines[i][j] == ' ') || (lines[i][j] == '\t')) j++; // skip spaces and tabs in the begining
							 | 
						|
								        // Read define line
							 | 
						|
								        if (IsTextEqual(lines[i]+j, "#define ", 8))
							 | 
						|
								        {
							 | 
						|
								            // Keep the line position in the array of lines,
							 | 
						|
								            // so, we can scan that position and following lines
							 | 
						|
								            defineLines[defineCount] = i;
							 | 
						|
								            defineCount++;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Read struct lines
							 | 
						|
								    for (int i = 0; i < linesCount; i++)
							 | 
						|
								    {
							 | 
						|
								        // Find structs
							 | 
						|
								        // starting with "typedef struct ... {" or "typedef struct ... ; \n struct ... {"
							 | 
						|
								        // ending with "} ... ;"
							 | 
						|
								        // i.e. excluding "typedef struct rAudioBuffer rAudioBuffer;" -> Typedef and forward declaration only
							 | 
						|
								        if (IsTextEqual(lines[i], "typedef struct", 14))
							 | 
						|
								        {
							 | 
						|
								            bool validStruct = IsTextEqual(lines[i + 1], "struct", 6);
							 | 
						|
								            if (!validStruct)
							 | 
						|
								            {
							 | 
						|
								                for (int c = 0; c < MAX_LINE_LENGTH; c++)
							 | 
						|
								                {
							 | 
						|
								                    char v = lines[i][c];
							 | 
						|
								                    if (v == '{') validStruct = true;
							 | 
						|
								                    if ((v == '{') || (v == ';') || (v == '\0')) break;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            if (!validStruct) continue;
							 | 
						|
								            structLines[structCount] = i;
							 | 
						|
								            while (lines[i][0] != '}') i++;
							 | 
						|
								            while (lines[i][0] != '\0') i++;
							 | 
						|
								            structCount++;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Read alias lines
							 | 
						|
								    for (int i = 0; i < linesCount; i++)
							 | 
						|
								    {
							 | 
						|
								        // Find aliases (lines with "typedef ... ...;")
							 | 
						|
								        if (IsTextEqual(lines[i], "typedef", 7))
							 | 
						|
								        {
							 | 
						|
								            int spaceCount = 0;
							 | 
						|
								            bool validAlias = false;
							 | 
						|
								
							 | 
						|
								            for (int c = 0; c < MAX_LINE_LENGTH; c++)
							 | 
						|
								            {
							 | 
						|
								                char v = lines[i][c];
							 | 
						|
								                if (v == ' ') spaceCount++;
							 | 
						|
								                if ((v == ';') && (spaceCount == 2)) validAlias = true;
							 | 
						|
								                if ((v == ';') || (v == '(') || (v == '\0')) break;
							 | 
						|
								            }
							 | 
						|
								            if (!validAlias) continue;
							 | 
						|
								            aliasLines[aliasCount] = i;
							 | 
						|
								            aliasCount++;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Read enum lines
							 | 
						|
								    for (int i = 0; i < linesCount; i++)
							 | 
						|
								    {
							 | 
						|
								        // Read enum line
							 | 
						|
								        if (IsTextEqual(lines[i], "typedef enum {", 14) && (lines[i][TextLength(lines[i])-1] != ';')) // ignore inline enums
							 | 
						|
								        {
							 | 
						|
								            // Keep the line position in the array of lines,
							 | 
						|
								            // so, we can scan that position and following lines
							 | 
						|
								            enumLines[enumCount] = i;
							 | 
						|
								            enumCount++;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Read callback lines
							 | 
						|
								    for (int i = 0; i < linesCount; i++)
							 | 
						|
								    {
							 | 
						|
								        // Find callbacks (lines with "typedef ... (* ... )( ... );")
							 | 
						|
								        if (IsTextEqual(lines[i], "typedef", 7))
							 | 
						|
								        {
							 | 
						|
								            bool hasBeginning = false;
							 | 
						|
								            bool hasMiddle = false;
							 | 
						|
								            bool hasEnd = false;
							 | 
						|
								
							 | 
						|
								            for (int c = 0; c < MAX_LINE_LENGTH; c++)
							 | 
						|
								            {
							 | 
						|
								                if ((lines[i][c] == '(') && (lines[i][c + 1] == '*')) hasBeginning = true;
							 | 
						|
								                if ((lines[i][c] == ')') && (lines[i][c + 1] == '(')) hasMiddle = true;
							 | 
						|
								                if ((lines[i][c] == ')') && (lines[i][c + 1] == ';')) hasEnd = true;
							 | 
						|
								                if (hasEnd) break;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            if (hasBeginning && hasMiddle && hasEnd)
							 | 
						|
								            {
							 | 
						|
								                callbackLines[callbackCount] = i;
							 | 
						|
								                callbackCount++;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Read function lines
							 | 
						|
								    for (int i = 0; i < linesCount; i++)
							 | 
						|
								    {
							 | 
						|
								        // Read function line (starting with `define`, i.e. for raylib.h "RLAPI")
							 | 
						|
								        if (IsTextEqual(lines[i], apiDefine, TextLength(apiDefine)))
							 | 
						|
								        {
							 | 
						|
								            funcLines[funcCount] = i;
							 | 
						|
								            funcCount++;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // At this point we have all raylib defines, structs, aliases, enums, callbacks, functions lines data to start parsing
							 | 
						|
								
							 | 
						|
								    free(buffer);       // Unload text buffer
							 | 
						|
								
							 | 
						|
								    // Parsing raylib data
							 | 
						|
								    //----------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								    // Define info data
							 | 
						|
								    defines = (DefineInfo *)calloc(MAX_DEFINES_TO_PARSE, sizeof(DefineInfo));
							 | 
						|
								    int defineIndex = 0;
							 | 
						|
								
							 | 
						|
								    for (int i = 0; i < defineCount; i++)
							 | 
						|
								    {
							 | 
						|
								        char *linePtr = lines[defineLines[i]];
							 | 
						|
								        int j = 0;
							 | 
						|
								
							 | 
						|
								        while ((linePtr[j] == ' ') || (linePtr[j] == '\t')) j++; // Skip spaces and tabs in the begining
							 | 
						|
								        j += 8;                                                  // Skip "#define "
							 | 
						|
								        while ((linePtr[j] == ' ') || (linePtr[j] == '\t')) j++; // Skip spaces and tabs after "#define "
							 | 
						|
								
							 | 
						|
								        // Extract name
							 | 
						|
								        int defineNameStart = j;
							 | 
						|
								        int openBraces = 0;
							 | 
						|
								        while (linePtr[j] != '\0')
							 | 
						|
								        {
							 | 
						|
								            if (((linePtr[j] == ' ') || (linePtr[j] == '\t')) && (openBraces == 0)) break;
							 | 
						|
								            if (linePtr[j] == '(') openBraces++;
							 | 
						|
								            if (linePtr[j] == ')') openBraces--;
							 | 
						|
								            j++;
							 | 
						|
								        }
							 | 
						|
								        int defineNameEnd = j-1;
							 | 
						|
								
							 | 
						|
								        // Skip duplicates
							 | 
						|
								        unsigned int nameLen = defineNameEnd - defineNameStart + 1;
							 | 
						|
								        bool isDuplicate = false;
							 | 
						|
								        for (int k = 0; k < defineIndex; k++)
							 | 
						|
								        {
							 | 
						|
								            if ((nameLen == TextLength(defines[k].name)) && IsTextEqual(defines[k].name, &linePtr[defineNameStart], nameLen))
							 | 
						|
								            {
							 | 
						|
								                isDuplicate = true;
							 | 
						|
								                break;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								        if (isDuplicate) continue;
							 | 
						|
								
							 | 
						|
								        MemoryCopy(defines[defineIndex].name, &linePtr[defineNameStart], nameLen);
							 | 
						|
								
							 | 
						|
								        // Determine type
							 | 
						|
								        if (linePtr[defineNameEnd] == ')') defines[defineIndex].type = MACRO;
							 | 
						|
								
							 | 
						|
								        while ((linePtr[j] == ' ') || (linePtr[j] == '\t')) j++; // Skip spaces and tabs after name
							 | 
						|
								
							 | 
						|
								        int defineValueStart = j;
							 | 
						|
								        if ((linePtr[j] == '\0') || (linePtr[j] == '/')) defines[defineIndex].type = GUARD;
							 | 
						|
								        if (linePtr[j] == '"') defines[defineIndex].type = STRING;
							 | 
						|
								        else if (linePtr[j] == '\'') defines[defineIndex].type = CHAR;
							 | 
						|
								        else if (IsTextEqual(linePtr+j, "CLITERAL(Color)", 15)) defines[defineIndex].type = COLOR;
							 | 
						|
								        else if (isdigit(linePtr[j])) // Parsing numbers
							 | 
						|
								        {
							 | 
						|
								            bool isFloat = false, isNumber = true, isHex = false;
							 | 
						|
								            while ((linePtr[j] != ' ') && (linePtr[j] != '\t') && (linePtr[j] != '\0'))
							 | 
						|
								            {
							 | 
						|
								                char ch = linePtr[j];
							 | 
						|
								                if (ch == '.') isFloat = true;
							 | 
						|
								                if (ch == 'x') isHex = true;
							 | 
						|
								                if (!(isdigit(ch) ||
							 | 
						|
								                      ((ch >= 'a') && (ch <= 'f')) ||
							 | 
						|
								                      ((ch >= 'A') && (ch <= 'F')) ||
							 | 
						|
								                      (ch == 'x') ||
							 | 
						|
								                      (ch == 'L') ||
							 | 
						|
								                      (ch == '.') ||
							 | 
						|
								                      (ch == '+') ||
							 | 
						|
								                      (ch == '-'))) isNumber = false;
							 | 
						|
								                j++;
							 | 
						|
								            }
							 | 
						|
								            if (isNumber)
							 | 
						|
								            {
							 | 
						|
								                if (isFloat)
							 | 
						|
								                {
							 | 
						|
								                    defines[defineIndex].type = (linePtr[j-1] == 'f')? FLOAT : DOUBLE;
							 | 
						|
								                }
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    defines[defineIndex].type = (linePtr[j-1] == 'L')? LONG : INT;
							 | 
						|
								                    defines[defineIndex].isHex = isHex;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Extracting value
							 | 
						|
								        while ((linePtr[j] != '\\') && (linePtr[j] != '\0') && !((linePtr[j] == '/') && (linePtr[j+1] == '/'))) j++;
							 | 
						|
								        int defineValueEnd = j-1;
							 | 
						|
								        while ((linePtr[defineValueEnd] == ' ') || (linePtr[defineValueEnd] == '\t')) defineValueEnd--; // Remove trailing spaces and tabs
							 | 
						|
								        if ((defines[defineIndex].type == LONG) || (defines[defineIndex].type == FLOAT)) defineValueEnd--; // Remove number postfix
							 | 
						|
								        int valueLen = defineValueEnd - defineValueStart + 1;
							 | 
						|
								        if (valueLen > 255) valueLen = 255;
							 | 
						|
								
							 | 
						|
								        if (valueLen > 0) MemoryCopy(defines[defineIndex].value, &linePtr[defineValueStart], valueLen);
							 | 
						|
								
							 | 
						|
								        // Extracting description
							 | 
						|
								        if ((linePtr[j] == '/') && linePtr[j + 1] == '/')
							 | 
						|
								        {
							 | 
						|
								            j += 2;
							 | 
						|
								            while (linePtr[j] == ' ') j++;
							 | 
						|
								            int commentStart = j;
							 | 
						|
								            while ((linePtr[j] != '\\') && (linePtr[j] != '\0')) j++;
							 | 
						|
								            int commentEnd = j-1;
							 | 
						|
								            int commentLen = commentEnd - commentStart + 1;
							 | 
						|
								            if (commentLen > 127) commentLen = 127;
							 | 
						|
								
							 | 
						|
								            MemoryCopy(defines[defineIndex].desc, &linePtr[commentStart], commentLen);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Parse defines of type UNKNOWN to find calculated numbers
							 | 
						|
								        if (defines[defineIndex].type == UNKNOWN)
							 | 
						|
								        {
							 | 
						|
								            int largestType = UNKNOWN;
							 | 
						|
								            bool isMath = true;
							 | 
						|
								            char *valuePtr = defines[defineIndex].value;
							 | 
						|
								
							 | 
						|
								            for (unsigned int c = 0; c < TextLength(valuePtr); c++)
							 | 
						|
								            {
							 | 
						|
								                char ch = valuePtr[c];
							 | 
						|
								
							 | 
						|
								                // Skip operators and whitespace
							 | 
						|
								                if ((ch == '(') ||
							 | 
						|
								                    (ch == ')') ||
							 | 
						|
								                    (ch == '+') ||
							 | 
						|
								                    (ch == '-') ||
							 | 
						|
								                    (ch == '*') ||
							 | 
						|
								                    (ch == '/') ||
							 | 
						|
								                    (ch == ' ') ||
							 | 
						|
								                    (ch == '\t')) continue;
							 | 
						|
								
							 | 
						|
								                // Read number operand
							 | 
						|
								                else if (isdigit(ch))
							 | 
						|
								                {
							 | 
						|
								                    bool isNumber = true, isFloat = false;
							 | 
						|
								                    while (!((ch == '(') ||
							 | 
						|
								                             (ch == ')') ||
							 | 
						|
								                             (ch == '*') ||
							 | 
						|
								                             (ch == '/') ||
							 | 
						|
								                             (ch == ' ') ||
							 | 
						|
								                             (ch == '\t') ||
							 | 
						|
								                             (ch == '\0')))
							 | 
						|
								                    {
							 | 
						|
								                        if (ch == '.') isFloat = true;
							 | 
						|
								                        if (!(isdigit(ch) ||
							 | 
						|
								                            ((ch >= 'a') && (ch <= 'f')) ||
							 | 
						|
								                            ((ch >= 'A') && (ch <= 'F')) ||
							 | 
						|
								                            (ch == 'x') ||
							 | 
						|
								                            (ch == 'L') ||
							 | 
						|
								                            (ch == '.') ||
							 | 
						|
								                            (ch == '+') ||
							 | 
						|
								                            (ch == '-')))
							 | 
						|
								                        {
							 | 
						|
								                            isNumber = false;
							 | 
						|
								                            break;
							 | 
						|
								                        }
							 | 
						|
								                        c++;
							 | 
						|
								                        ch = valuePtr[c];
							 | 
						|
								                    }
							 | 
						|
								                    if (isNumber)
							 | 
						|
								                    {
							 | 
						|
								                        // Found a valid number -> update largestType
							 | 
						|
								                        int numberType;
							 | 
						|
								                        if (isFloat) numberType = (valuePtr[c - 1] == 'f')? FLOAT_MATH : DOUBLE_MATH;
							 | 
						|
								                        else numberType = (valuePtr[c - 1] == 'L')? LONG_MATH : INT_MATH;
							 | 
						|
								
							 | 
						|
								                        if (numberType > largestType) largestType = numberType;
							 | 
						|
								                    }
							 | 
						|
								                    else
							 | 
						|
								                    {
							 | 
						|
								                        isMath = false;
							 | 
						|
								                        break;
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								                else    // Read string operand
							 | 
						|
								                {
							 | 
						|
								                    int operandStart = c;
							 | 
						|
								                    while (!((ch == '\0') ||
							 | 
						|
								                             (ch == ' ') ||
							 | 
						|
								                             (ch == '(') ||
							 | 
						|
								                             (ch == ')') ||
							 | 
						|
								                             (ch == '+') ||
							 | 
						|
								                             (ch == '-') ||
							 | 
						|
								                             (ch == '*') ||
							 | 
						|
								                             (ch == '/')))
							 | 
						|
								                    {
							 | 
						|
								                        c++;
							 | 
						|
								                        ch = valuePtr[c];
							 | 
						|
								                    }
							 | 
						|
								                    int operandEnd = c;
							 | 
						|
								                    int operandLength = operandEnd - operandStart;
							 | 
						|
								
							 | 
						|
								                    // Search previous defines for operand
							 | 
						|
								                    bool foundOperand = false;
							 | 
						|
								                    for (int previousDefineIndex = 0; previousDefineIndex < defineIndex; previousDefineIndex++)
							 | 
						|
								                    {
							 | 
						|
								                        if (IsTextEqual(defines[previousDefineIndex].name, &valuePtr[operandStart], operandLength))
							 | 
						|
								                        {
							 | 
						|
								                            if ((defines[previousDefineIndex].type >= INT) && (defines[previousDefineIndex].type <= DOUBLE_MATH))
							 | 
						|
								                            {
							 | 
						|
								                                // Found operand and it's a number -> update largestType
							 | 
						|
								                                if (defines[previousDefineIndex].type > largestType) largestType = defines[previousDefineIndex].type;
							 | 
						|
								                                foundOperand = true;
							 | 
						|
								                            }
							 | 
						|
								                            break;
							 | 
						|
								                        }
							 | 
						|
								                    }
							 | 
						|
								                    if (!foundOperand)
							 | 
						|
								                    {
							 | 
						|
								                        isMath = false;
							 | 
						|
								                        break;
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            if (isMath)
							 | 
						|
								            {
							 | 
						|
								                // Define is a calculated number -> update type
							 | 
						|
								                if (largestType == INT) largestType = INT_MATH;
							 | 
						|
								                else if (largestType == LONG) largestType = LONG_MATH;
							 | 
						|
								                else if (largestType == FLOAT) largestType = FLOAT_MATH;
							 | 
						|
								                else if (largestType == DOUBLE) largestType = DOUBLE_MATH;
							 | 
						|
								                defines[defineIndex].type = largestType;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        defineIndex++;
							 | 
						|
								    }
							 | 
						|
								    defineCount = defineIndex;
							 | 
						|
								    free(defineLines);
							 | 
						|
								
							 | 
						|
								    // Structs info data
							 | 
						|
								    structs = (StructInfo *)calloc(MAX_STRUCTS_TO_PARSE, sizeof(StructInfo));
							 | 
						|
								
							 | 
						|
								    for (int i = 0; i < structCount; i++)
							 | 
						|
								    {
							 | 
						|
								        char **linesPtr = &lines[structLines[i]];
							 | 
						|
								
							 | 
						|
								        // Parse struct description
							 | 
						|
								        GetDescription(linesPtr[-1], structs[i].desc);
							 | 
						|
								
							 | 
						|
								        // Get struct name: typedef struct name {
							 | 
						|
								        const int TDS_LEN = 15; // length of "typedef struct "
							 | 
						|
								        for (int c = TDS_LEN; c < 64 + TDS_LEN; c++)
							 | 
						|
								        {
							 | 
						|
								            if ((linesPtr[0][c] == '{') || (linesPtr[0][c] == ' '))
							 | 
						|
								            {
							 | 
						|
								                int nameLen = c - TDS_LEN;
							 | 
						|
								                while (linesPtr[0][TDS_LEN + nameLen - 1] == ' ') nameLen--;
							 | 
						|
								                MemoryCopy(structs[i].name, &linesPtr[0][TDS_LEN], nameLen);
							 | 
						|
								                break;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Get struct fields and count them -> fields finish with ;
							 | 
						|
								        int l = 1;
							 | 
						|
								        while (linesPtr[l][0] != '}')
							 | 
						|
								        {
							 | 
						|
								            // WARNING: Some structs have empty spaces and comments -> OK, processed
							 | 
						|
								            if ((linesPtr[l][0] != ' ') && (linesPtr[l][0] != '\0'))
							 | 
						|
								            {
							 | 
						|
								                // Scan one field line
							 | 
						|
								                char *fieldLine = linesPtr[l];
							 | 
						|
								                int fieldEndPos = 0;
							 | 
						|
								                while (fieldLine[fieldEndPos] != ';') fieldEndPos++;
							 | 
						|
								
							 | 
						|
								                if ((fieldLine[0] != '/') && !IsTextEqual(fieldLine, "struct", 6)) // Field line is not a comment and not a struct declaration
							 | 
						|
								                {
							 | 
						|
								                    //printf("Struct field: %s_\n", fieldLine);     // OK!
							 | 
						|
								
							 | 
						|
								                    // Get struct field type and name
							 | 
						|
								                    GetDataTypeAndName(fieldLine, fieldEndPos, structs[i].fieldType[structs[i].fieldCount], structs[i].fieldName[structs[i].fieldCount]);
							 | 
						|
								
							 | 
						|
								                    // Get the field description
							 | 
						|
								                    GetDescription(&fieldLine[fieldEndPos], structs[i].fieldDesc[structs[i].fieldCount]);
							 | 
						|
								
							 | 
						|
								                    structs[i].fieldCount++;
							 | 
						|
								
							 | 
						|
								                    // Split field names containing multiple fields (like Matrix)
							 | 
						|
								                    int additionalFields = 0;
							 | 
						|
								                    int originalIndex = structs[i].fieldCount - 1;
							 | 
						|
								                    for (unsigned int c = 0; c < TextLength(structs[i].fieldName[originalIndex]); c++)
							 | 
						|
								                    {
							 | 
						|
								                        if (structs[i].fieldName[originalIndex][c] == ',') additionalFields++;
							 | 
						|
								                    }
							 | 
						|
								
							 | 
						|
								                    if (additionalFields > 0)
							 | 
						|
								                    {
							 | 
						|
								                        int originalLength = -1;
							 | 
						|
								                        int lastStart;
							 | 
						|
								                        for (unsigned int c = 0; c < TextLength(structs[i].fieldName[originalIndex]) + 1; c++)
							 | 
						|
								                        {
							 | 
						|
								                            char v = structs[i].fieldName[originalIndex][c];
							 | 
						|
								                            bool isEndOfString = (v == '\0');
							 | 
						|
								                            if ((v == ',') || isEndOfString)
							 | 
						|
								                            {
							 | 
						|
								                                if (originalLength == -1)
							 | 
						|
								                                {
							 | 
						|
								                                    // Save length of original field name
							 | 
						|
								                                    // Don't truncate yet, still needed for copying
							 | 
						|
								                                    originalLength = c;
							 | 
						|
								                                }
							 | 
						|
								                                else
							 | 
						|
								                                {
							 | 
						|
								                                    // Copy field data from original field
							 | 
						|
								                                    int nameLength = c - lastStart;
							 | 
						|
								                                    MemoryCopy(structs[i].fieldName[structs[i].fieldCount], &structs[i].fieldName[originalIndex][lastStart], nameLength);
							 | 
						|
								                                    MemoryCopy(structs[i].fieldType[structs[i].fieldCount], &structs[i].fieldType[originalIndex][0], TextLength(structs[i].fieldType[originalIndex]));
							 | 
						|
								                                    MemoryCopy(structs[i].fieldDesc[structs[i].fieldCount], &structs[i].fieldDesc[originalIndex][0], TextLength(structs[i].fieldDesc[originalIndex]));
							 | 
						|
								                                    structs[i].fieldCount++;
							 | 
						|
								                                }
							 | 
						|
								                                if (!isEndOfString)
							 | 
						|
								                                {
							 | 
						|
								                                    // Skip comma and spaces
							 | 
						|
								                                    c++;
							 | 
						|
								                                    while (structs[i].fieldName[originalIndex][c] == ' ') c++;
							 | 
						|
								
							 | 
						|
								                                    // Save position for next field
							 | 
						|
								                                    lastStart = c;
							 | 
						|
								                                }
							 | 
						|
								                            }
							 | 
						|
								                        }
							 | 
						|
								                        // Set length of original field to truncate the first field name
							 | 
						|
								                        structs[i].fieldName[originalIndex][originalLength] = '\0';
							 | 
						|
								                    }
							 | 
						|
								
							 | 
						|
								                    // Split field types containing multiple fields (like MemNode)
							 | 
						|
								                    additionalFields = 0;
							 | 
						|
								                    originalIndex = structs[i].fieldCount - 1;
							 | 
						|
								                    for (unsigned int c = 0; c < TextLength(structs[i].fieldType[originalIndex]); c++)
							 | 
						|
								                    {
							 | 
						|
								                        if (structs[i].fieldType[originalIndex][c] == ',') additionalFields++;
							 | 
						|
								                    }
							 | 
						|
								
							 | 
						|
								                    if (additionalFields > 0)
							 | 
						|
								                    {
							 | 
						|
								                        // Copy original name to last additional field
							 | 
						|
								                        structs[i].fieldCount += additionalFields;
							 | 
						|
								                        MemoryCopy(structs[i].fieldName[originalIndex + additionalFields], &structs[i].fieldName[originalIndex][0], TextLength(structs[i].fieldName[originalIndex]));
							 | 
						|
								
							 | 
						|
								                        // Copy names from type to additional fields
							 | 
						|
								                        int fieldsRemaining = additionalFields;
							 | 
						|
								                        int nameStart = -1;
							 | 
						|
								                        int nameEnd = -1;
							 | 
						|
								                        for (int k = TextLength(structs[i].fieldType[originalIndex]); k > 0; k--)
							 | 
						|
								                        {
							 | 
						|
								                            char v = structs[i].fieldType[originalIndex][k];
							 | 
						|
								                            if ((v == '*') || (v == ' ') || (v == ','))
							 | 
						|
								                            {
							 | 
						|
								                                if (nameEnd != -1) {
							 | 
						|
								                                    // Don't copy to last additional field
							 | 
						|
								                                    if (fieldsRemaining != additionalFields)
							 | 
						|
								                                    {
							 | 
						|
								                                        nameStart = k + 1;
							 | 
						|
								                                        MemoryCopy(structs[i].fieldName[originalIndex + fieldsRemaining], &structs[i].fieldType[originalIndex][nameStart], nameEnd - nameStart + 1);
							 | 
						|
								                                    }
							 | 
						|
								                                    nameEnd = -1;
							 | 
						|
								                                    fieldsRemaining--;
							 | 
						|
								                                }
							 | 
						|
								                            }
							 | 
						|
								                            else if (nameEnd == -1) nameEnd = k;
							 | 
						|
								                        }
							 | 
						|
								
							 | 
						|
								                        // Truncate original field type
							 | 
						|
								                        int fieldTypeLength = nameStart;
							 | 
						|
								                        structs[i].fieldType[originalIndex][fieldTypeLength] = '\0';
							 | 
						|
								
							 | 
						|
								                        // Set field type and description of additional fields
							 | 
						|
								                        for (int j = 1; j <= additionalFields; j++)
							 | 
						|
								                        {
							 | 
						|
								                            MemoryCopy(structs[i].fieldType[originalIndex + j], &structs[i].fieldType[originalIndex][0], fieldTypeLength);
							 | 
						|
								                            MemoryCopy(structs[i].fieldDesc[originalIndex + j], &structs[i].fieldDesc[originalIndex][0], TextLength(structs[i].fieldDesc[originalIndex]));
							 | 
						|
								                        }
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            l++;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Move array sizes from name to type
							 | 
						|
								        for (int j = 0; j < structs[i].fieldCount; j++)
							 | 
						|
								        {
							 | 
						|
								            MoveArraySize(structs[i].fieldName[j], structs[i].fieldType[j]);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    free(structLines);
							 | 
						|
								
							 | 
						|
								    // Alias info data
							 | 
						|
								    aliases = (AliasInfo *)calloc(MAX_ALIASES_TO_PARSE, sizeof(AliasInfo));
							 | 
						|
								
							 | 
						|
								    for (int i = 0; i < aliasCount; i++)
							 | 
						|
								    {
							 | 
						|
								        // Description from previous line
							 | 
						|
								        GetDescription(lines[aliasLines[i] - 1], aliases[i].desc);
							 | 
						|
								
							 | 
						|
								        char *linePtr = lines[aliasLines[i]];
							 | 
						|
								
							 | 
						|
								        // Skip "typedef "
							 | 
						|
								        int c = 8;
							 | 
						|
								
							 | 
						|
								        // Type
							 | 
						|
								        int typeStart = c;
							 | 
						|
								        while(linePtr[c] != ' ') c++;
							 | 
						|
								        int typeLen = c - typeStart;
							 | 
						|
								        MemoryCopy(aliases[i].type, &linePtr[typeStart], typeLen);
							 | 
						|
								
							 | 
						|
								        // Skip space
							 | 
						|
								        c++;
							 | 
						|
								
							 | 
						|
								        // Name
							 | 
						|
								        int nameStart = c;
							 | 
						|
								        while(linePtr[c] != ';') c++;
							 | 
						|
								        int nameLen = c - nameStart;
							 | 
						|
								        MemoryCopy(aliases[i].name, &linePtr[nameStart], nameLen);
							 | 
						|
								
							 | 
						|
								        // Description
							 | 
						|
								        GetDescription(&linePtr[c], aliases[i].desc);
							 | 
						|
								    }
							 | 
						|
								    free(aliasLines);
							 | 
						|
								
							 | 
						|
								    // Enum info data
							 | 
						|
								    enums = (EnumInfo *)calloc(MAX_ENUMS_TO_PARSE, sizeof(EnumInfo));
							 | 
						|
								
							 | 
						|
								    for (int i = 0; i < enumCount; i++)
							 | 
						|
								    {
							 | 
						|
								
							 | 
						|
								        // Parse enum description
							 | 
						|
								        // NOTE: This is not necessarily from the line immediately before,
							 | 
						|
								        // some of the enums have extra lines between the "description"
							 | 
						|
								        // and the typedef enum
							 | 
						|
								        for (int j = enumLines[i] - 1; j > 0; j--)
							 | 
						|
								        {
							 | 
						|
								            char *linePtr = lines[j];
							 | 
						|
								            if ((linePtr[0] != '/') || (linePtr[2] != ' '))
							 | 
						|
								            {
							 | 
						|
								                GetDescription(&lines[j + 1][0], enums[i].desc);
							 | 
						|
								                break;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        for (int j = 1; j < MAX_ENUM_VALUES*2; j++)   // Maximum number of lines following enum first line
							 | 
						|
								        {
							 | 
						|
								            char *linePtr = lines[enumLines[i] + j];
							 | 
						|
								
							 | 
						|
								            if ((linePtr[0] >= 'A') && (linePtr[0] <= 'Z'))
							 | 
						|
								            {
							 | 
						|
								                // Parse enum value line, possible options:
							 | 
						|
								                //ENUM_VALUE_NAME,
							 | 
						|
								                //ENUM_VALUE_NAME
							 | 
						|
								                //ENUM_VALUE_NAME     = 99
							 | 
						|
								                //ENUM_VALUE_NAME     = 99,
							 | 
						|
								                //ENUM_VALUE_NAME     = 0x00000040,   // Value description
							 | 
						|
								
							 | 
						|
								                // We start reading the value name
							 | 
						|
								                int c = 0;
							 | 
						|
								                while ((linePtr[c] != ',') &&
							 | 
						|
								                       (linePtr[c] != ' ') &&
							 | 
						|
								                       (linePtr[c] != '=') &&
							 | 
						|
								                       (linePtr[c] != '\0'))
							 | 
						|
								                {
							 | 
						|
								                    enums[i].valueName[enums[i].valueCount][c] = linePtr[c];
							 | 
						|
								                    c++;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // After the name we can have:
							 | 
						|
								                //  '='  -> value is provided
							 | 
						|
								                //  ','  -> value is equal to previous + 1, there could be a description if not '\0'
							 | 
						|
								                //  ' '  -> value is equal to previous + 1, there could be a description if not '\0'
							 | 
						|
								                //  '\0' -> value is equal to previous + 1
							 | 
						|
								
							 | 
						|
								                // Let's start checking if the line is not finished
							 | 
						|
								                if ((linePtr[c] != ',') && (linePtr[c] != '\0'))
							 | 
						|
								                {
							 | 
						|
								                    // Two options:
							 | 
						|
								                    //  '='  -> value is provided
							 | 
						|
								                    //  ' '  -> value is equal to previous + 1, there could be a description if not '\0'
							 | 
						|
								                    bool foundValue = false;
							 | 
						|
								                    while ((linePtr[c] != '\0') && (linePtr[c] != '/'))
							 | 
						|
								                    {
							 | 
						|
								                        if (linePtr[c] == '=')
							 | 
						|
								                        {
							 | 
						|
								                            foundValue = true;
							 | 
						|
								                            break;
							 | 
						|
								                        }
							 | 
						|
								                        c++;
							 | 
						|
								                    }
							 | 
						|
								
							 | 
						|
								                    if (foundValue)
							 | 
						|
								                    {
							 | 
						|
								                        if (linePtr[c + 1] == ' ') c += 2;
							 | 
						|
								                        else c++;
							 | 
						|
								
							 | 
						|
								                        // Parse integer value
							 | 
						|
								                        int n = 0;
							 | 
						|
								                        char integer[16] = { 0 };
							 | 
						|
								
							 | 
						|
								                        while ((linePtr[c] != ',') && (linePtr[c] != ' ') && (linePtr[c] != '\0'))
							 | 
						|
								                        {
							 | 
						|
								                            integer[n] = linePtr[c];
							 | 
						|
								                            c++; n++;
							 | 
						|
								                        }
							 | 
						|
								
							 | 
						|
								                        if (integer[1] == 'x') enums[i].valueInteger[enums[i].valueCount] = (int)strtol(integer, NULL, 16);
							 | 
						|
								                        else enums[i].valueInteger[enums[i].valueCount] = atoi(integer);
							 | 
						|
								                    }
							 | 
						|
								                    else enums[i].valueInteger[enums[i].valueCount] = (enums[i].valueInteger[enums[i].valueCount - 1] + 1);
							 | 
						|
								                }
							 | 
						|
								                else enums[i].valueInteger[enums[i].valueCount] = (enums[i].valueInteger[enums[i].valueCount - 1] + 1);
							 | 
						|
								
							 | 
						|
								                // Parse value description
							 | 
						|
								                GetDescription(&linePtr[c], enums[i].valueDesc[enums[i].valueCount]);
							 | 
						|
								
							 | 
						|
								                enums[i].valueCount++;
							 | 
						|
								            }
							 | 
						|
								            else if (linePtr[0] == '}')
							 | 
						|
								            {
							 | 
						|
								                // Get enum name from typedef
							 | 
						|
								                int c = 0;
							 | 
						|
								                while (linePtr[2 + c] != ';')
							 | 
						|
								                {
							 | 
						|
								                    enums[i].name[c] = linePtr[2 + c];
							 | 
						|
								                    c++;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                break;  // Enum ended, break for() loop
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    free(enumLines);
							 | 
						|
								
							 | 
						|
								    // Callback info data
							 | 
						|
								    callbacks = (FunctionInfo *)calloc(MAX_CALLBACKS_TO_PARSE, sizeof(FunctionInfo));
							 | 
						|
								
							 | 
						|
								    for (int i = 0; i < callbackCount; i++)
							 | 
						|
								    {
							 | 
						|
								        char *linePtr = lines[callbackLines[i]];
							 | 
						|
								
							 | 
						|
								        // Skip "typedef "
							 | 
						|
								        unsigned int c = 8;
							 | 
						|
								
							 | 
						|
								        // Return type
							 | 
						|
								        int retTypeStart = c;
							 | 
						|
								        while(linePtr[c] != '(') c++;
							 | 
						|
								        int retTypeLen = c - retTypeStart;
							 | 
						|
								        while(linePtr[retTypeStart + retTypeLen - 1] == ' ') retTypeLen--;
							 | 
						|
								        MemoryCopy(callbacks[i].retType, &linePtr[retTypeStart], retTypeLen);
							 | 
						|
								
							 | 
						|
								        // Skip "(*"
							 | 
						|
								        c += 2;
							 | 
						|
								
							 | 
						|
								        // Name
							 | 
						|
								        int nameStart = c;
							 | 
						|
								        while(linePtr[c] != ')') c++;
							 | 
						|
								        int nameLen = c - nameStart;
							 | 
						|
								        MemoryCopy(callbacks[i].name, &linePtr[nameStart], nameLen);
							 | 
						|
								
							 | 
						|
								        // Skip ")("
							 | 
						|
								        c += 2;
							 | 
						|
								
							 | 
						|
								        // Params
							 | 
						|
								        int paramStart = c;
							 | 
						|
								        for (; c < MAX_LINE_LENGTH; c++)
							 | 
						|
								        {
							 | 
						|
								            if ((linePtr[c] == ',') || (linePtr[c] == ')'))
							 | 
						|
								            {
							 | 
						|
								                // Get parameter type + name, extract info
							 | 
						|
								                int paramLen = c - paramStart;
							 | 
						|
								                GetDataTypeAndName(&linePtr[paramStart], paramLen, callbacks[i].paramType[callbacks[i].paramCount], callbacks[i].paramName[callbacks[i].paramCount]);
							 | 
						|
								                callbacks[i].paramCount++;
							 | 
						|
								                paramStart = c + 1;
							 | 
						|
								                while(linePtr[paramStart] == ' ') paramStart++;
							 | 
						|
								            }
							 | 
						|
								            if (linePtr[c] == ')') break;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Description
							 | 
						|
								        GetDescription(&linePtr[c], callbacks[i].desc);
							 | 
						|
								
							 | 
						|
								        // Move array sizes from name to type
							 | 
						|
								        for (int j = 0; j < callbacks[i].paramCount; j++)
							 | 
						|
								        {
							 | 
						|
								            MoveArraySize(callbacks[i].paramName[j], callbacks[i].paramType[j]);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    free(callbackLines);
							 | 
						|
								
							 | 
						|
								    // Functions info data
							 | 
						|
								    funcs = (FunctionInfo *)calloc(MAX_FUNCS_TO_PARSE, sizeof(FunctionInfo));
							 | 
						|
								
							 | 
						|
								    for (int i = 0; i < funcCount; i++)
							 | 
						|
								    {
							 | 
						|
								        char *linePtr = lines[funcLines[i]];
							 | 
						|
								
							 | 
						|
								        int funcParamsStart = 0;
							 | 
						|
								        int funcEnd = 0;
							 | 
						|
								
							 | 
						|
								        // Get return type and function name from func line
							 | 
						|
								        for (int c = 0; (c < MAX_LINE_LENGTH) && (linePtr[c] != '\n'); c++)
							 | 
						|
								        {
							 | 
						|
								            if (linePtr[c] == '(')     // Starts function parameters
							 | 
						|
								            {
							 | 
						|
								                funcParamsStart = c + 1;
							 | 
						|
								
							 | 
						|
								                // At this point we have function return type and function name
							 | 
						|
								                char funcRetTypeName[128] = { 0 };
							 | 
						|
								                int dc = TextLength(apiDefine) + 1;
							 | 
						|
								                int funcRetTypeNameLen = c - dc;     // Substract `define` ("RLAPI " for raylib.h)
							 | 
						|
								                MemoryCopy(funcRetTypeName, &linePtr[dc], funcRetTypeNameLen);
							 | 
						|
								
							 | 
						|
								                GetDataTypeAndName(funcRetTypeName, funcRetTypeNameLen, funcs[i].retType, funcs[i].name);
							 | 
						|
								                break;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Get parameters from func line
							 | 
						|
								        for (int c = funcParamsStart; c < MAX_LINE_LENGTH; c++)
							 | 
						|
								        {
							 | 
						|
								            if (linePtr[c] == ',')     // Starts function parameters
							 | 
						|
								            {
							 | 
						|
								                // Get parameter type + name, extract info
							 | 
						|
								                char funcParamTypeName[128] = { 0 };
							 | 
						|
								                int funcParamTypeNameLen = c - funcParamsStart;
							 | 
						|
								                MemoryCopy(funcParamTypeName, &linePtr[funcParamsStart], funcParamTypeNameLen);
							 | 
						|
								
							 | 
						|
								                GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]);
							 | 
						|
								
							 | 
						|
								                funcParamsStart = c + 1;
							 | 
						|
								                if (linePtr[c + 1] == ' ') funcParamsStart += 1;
							 | 
						|
								                funcs[i].paramCount++;      // Move to next parameter
							 | 
						|
								            }
							 | 
						|
								            else if (linePtr[c] == ')')
							 | 
						|
								            {
							 | 
						|
								                funcEnd = c + 2;
							 | 
						|
								
							 | 
						|
								                // Check if there are no parameters
							 | 
						|
								                if ((funcEnd - funcParamsStart == 2) ||
							 | 
						|
								                    ((linePtr[c - 4] == 'v') &&
							 | 
						|
								                     (linePtr[c - 3] == 'o') &&
							 | 
						|
								                     (linePtr[c - 2] == 'i') &&
							 | 
						|
								                     (linePtr[c - 1] == 'd'))) {
							 | 
						|
								                  break;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Get parameter type + name, extract info
							 | 
						|
								                char funcParamTypeName[128] = { 0 };
							 | 
						|
								                int funcParamTypeNameLen = c - funcParamsStart;
							 | 
						|
								                MemoryCopy(funcParamTypeName, &linePtr[funcParamsStart], funcParamTypeNameLen);
							 | 
						|
								
							 | 
						|
								                GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]);
							 | 
						|
								
							 | 
						|
								                funcs[i].paramCount++;      // Move to next parameter
							 | 
						|
								                break;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Get function description
							 | 
						|
								        GetDescription(&linePtr[funcEnd], funcs[i].desc);
							 | 
						|
								
							 | 
						|
								        // Move array sizes from name to type
							 | 
						|
								        for (int j = 0; j < funcs[i].paramCount; j++)
							 | 
						|
								        {
							 | 
						|
								            MoveArraySize(funcs[i].paramName[j], funcs[i].paramType[j]);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    free(funcLines);
							 | 
						|
								
							 | 
						|
								    for (int i = 0; i < linesCount; i++) free(lines[i]);
							 | 
						|
								    free(lines);
							 | 
						|
								
							 | 
						|
								    // At this point, all raylib data has been parsed!
							 | 
						|
								    //----------------------------------------------------------------------------------
							 | 
						|
								    // defines[]   -> We have all the defines decomposed into pieces for further analysis
							 | 
						|
								    // structs[]   -> We have all the structs decomposed into pieces for further analysis
							 | 
						|
								    // aliases[]   -> We have all the aliases decomposed into pieces for further analysis
							 | 
						|
								    // enums[]     -> We have all the enums decomposed into pieces for further analysis
							 | 
						|
								    // callbacks[] -> We have all the callbacks decomposed into pieces for further analysis
							 | 
						|
								    // funcs[]     -> We have all the functions decomposed into pieces for further analysis
							 | 
						|
								
							 | 
						|
								    printf("\nInput file:       %s", inFileName);
							 | 
						|
								    printf("\nOutput file:      %s", outFileName);
							 | 
						|
								    if (outputFormat == DEFAULT) printf("\nOutput format:    DEFAULT\n\n");
							 | 
						|
								    else if (outputFormat == JSON) printf("\nOutput format:    JSON\n\n");
							 | 
						|
								    else if (outputFormat == XML) printf("\nOutput format:    XML\n\n");
							 | 
						|
								    else if (outputFormat == LUA) printf("\nOutput format:    LUA\n\n");
							 | 
						|
								    else if (outputFormat == CODE) printf("\nOutput format:    CODE\n\n");
							 | 
						|
								
							 | 
						|
								    ExportParsedData(outFileName, outputFormat);
							 | 
						|
								
							 | 
						|
								    free(defines);
							 | 
						|
								    free(structs);
							 | 
						|
								    free(aliases);
							 | 
						|
								    free(enums);
							 | 
						|
								    free(callbacks);
							 | 
						|
								    free(funcs);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								// Module Functions Definition
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								// Show command line usage info
							 | 
						|
								static void ShowCommandLineInfo(void)
							 | 
						|
								{
							 | 
						|
								    printf("\n//////////////////////////////////////////////////////////////////////////////////\n");
							 | 
						|
								    printf("//                                                                              //\n");
							 | 
						|
								    printf("// raylib API parser                                                            //\n");
							 | 
						|
								    printf("//                                                                              //\n");
							 | 
						|
								    printf("// more info and bugs-report: github.com/raysan5/raylib/parser                  //\n");
							 | 
						|
								    printf("//                                                                              //\n");
							 | 
						|
								    printf("// Copyright (c) 2021-2025 Ramon Santamaria (@raysan5)                          //\n");
							 | 
						|
								    printf("//                                                                              //\n");
							 | 
						|
								    printf("//////////////////////////////////////////////////////////////////////////////////\n\n");
							 | 
						|
								
							 | 
						|
								    printf("USAGE:\n\n");
							 | 
						|
								    printf("    > raylib_parser [--help] [--input <filename.h>] [--output <filename.ext>] [--format <type>]\n");
							 | 
						|
								
							 | 
						|
								    printf("\nOPTIONS:\n\n");
							 | 
						|
								    printf("    -h, --help                      : Show tool version and command line usage help\n\n");
							 | 
						|
								    printf("    -i, --input <filename.h>        : Define input header file to parse.\n");
							 | 
						|
								    printf("                                      NOTE: If not specified, defaults to: raylib.h\n\n");
							 | 
						|
								    printf("    -o, --output <filename.ext>     : Define output file and format.\n");
							 | 
						|
								    printf("                                      Supported extensions: .txt, .json, .xml, .lua, .h\n");
							 | 
						|
								    printf("                                      NOTE: If not specified, defaults to: raylib_api.txt\n\n");
							 | 
						|
								    printf("    -f, --format <type>             : Define output format for parser data.\n");
							 | 
						|
								    printf("                                      Supported types: DEFAULT, JSON, XML, LUA, CODE\n\n");
							 | 
						|
								    printf("    -d, --define <DEF>              : Define functions specifiers (i.e. RLAPI for raylib.h, RMAPI for raymath.h, etc.)\n");
							 | 
						|
								    printf("                                      NOTE: If no specifier defined, defaults to: RLAPI\n\n");
							 | 
						|
								    printf("    -t, --truncate <after>          : Define string to truncate input after (i.e. \"RLGL IMPLEMENTATION\" for rlgl.h)\n");
							 | 
						|
								    printf("                                      NOTE: If not specified, the full input file is parsed.\n\n");
							 | 
						|
								
							 | 
						|
								    printf("\nEXAMPLES:\n\n");
							 | 
						|
								    printf("    > raylib_parser --input raylib.h --output api.json\n");
							 | 
						|
								    printf("        Process <raylib.h> to generate <api.json>\n\n");
							 | 
						|
								    printf("    > raylib_parser --output raylib_data.info --format XML\n");
							 | 
						|
								    printf("        Process <raylib.h> to generate <raylib_data.info> as XML text data\n\n");
							 | 
						|
								    printf("    > raylib_parser --input raymath.h --output raymath_data.info --format XML --define RMAPI\n");
							 | 
						|
								    printf("        Process <raymath.h> to generate <raymath_data.info> as XML text data\n\n");
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Process command line arguments
							 | 
						|
								static void ProcessCommandLine(int argc, char *argv[])
							 | 
						|
								{
							 | 
						|
								    for (int i = 1; i < argc; i++)
							 | 
						|
								    {
							 | 
						|
								        if (IsTextEqual(argv[i], "-h", 2) || IsTextEqual(argv[i], "--help", 6))
							 | 
						|
								        {
							 | 
						|
								            // Show info
							 | 
						|
								            ShowCommandLineInfo();
							 | 
						|
								            exit(0);
							 | 
						|
								        }
							 | 
						|
								        else if (IsTextEqual(argv[i], "-i", 2) || IsTextEqual(argv[i], "--input", 7))
							 | 
						|
								        {
							 | 
						|
								            // Check for valid argument and valid file extension
							 | 
						|
								            if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
							 | 
						|
								            {
							 | 
						|
								                MemoryCopy(inFileName, argv[i + 1], TextLength(argv[i + 1])); // Read input filename
							 | 
						|
								                i++;
							 | 
						|
								            }
							 | 
						|
								            else printf("WARNING: No input file provided\n");
							 | 
						|
								        }
							 | 
						|
								        else if (IsTextEqual(argv[i], "-o", 2) || IsTextEqual(argv[i], "--output", 8))
							 | 
						|
								        {
							 | 
						|
								            if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
							 | 
						|
								            {
							 | 
						|
								                MemoryCopy(outFileName, argv[i + 1], TextLength(argv[i + 1])); // Read output filename
							 | 
						|
								                i++;
							 | 
						|
								            }
							 | 
						|
								            else printf("WARNING: No output file provided\n");
							 | 
						|
								        }
							 | 
						|
								        else if (IsTextEqual(argv[i], "-f", 2) || IsTextEqual(argv[i], "--format", 8))
							 | 
						|
								        {
							 | 
						|
								            if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
							 | 
						|
								            {
							 | 
						|
								                if (IsTextEqual(argv[i + 1], "DEFAULT\0", 8)) outputFormat = DEFAULT;
							 | 
						|
								                else if (IsTextEqual(argv[i + 1], "JSON\0", 5)) outputFormat = JSON;
							 | 
						|
								                else if (IsTextEqual(argv[i + 1], "XML\0", 4)) outputFormat = XML;
							 | 
						|
								                else if (IsTextEqual(argv[i + 1], "LUA\0", 4)) outputFormat = LUA;
							 | 
						|
								                else if (IsTextEqual(argv[i + 1], "CODE\0", 4)) outputFormat = CODE;
							 | 
						|
								            }
							 | 
						|
								            else printf("WARNING: No format parameters provided\n");
							 | 
						|
								        }
							 | 
						|
								        else if (IsTextEqual(argv[i], "-d", 2) || IsTextEqual(argv[i], "--define", 8))
							 | 
						|
								        {
							 | 
						|
								            if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
							 | 
						|
								            {
							 | 
						|
								                MemoryCopy(apiDefine, argv[i + 1], TextLength(argv[i + 1])); // Read functions define
							 | 
						|
								                apiDefine[TextLength(argv[i + 1])] = '\0';
							 | 
						|
								                i++;
							 | 
						|
								            }
							 | 
						|
								            else printf("WARNING: No define key provided\n");
							 | 
						|
								        }
							 | 
						|
								        else if (IsTextEqual(argv[i], "-t", 2) || IsTextEqual(argv[i], "--truncate", 10))
							 | 
						|
								        {
							 | 
						|
								            if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
							 | 
						|
								            {
							 | 
						|
								                MemoryCopy(truncAfter, argv[i + 1], TextLength(argv[i + 1])); // Read truncate marker
							 | 
						|
								                truncAfter[TextLength(argv[i + 1])] = '\0';
							 | 
						|
								                i++;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Load text data from file, returns a '\0' terminated string
							 | 
						|
								// NOTE: text chars array should be freed manually
							 | 
						|
								static char *LoadFileText(const char *fileName, int *length)
							 | 
						|
								{
							 | 
						|
								    char *text = NULL;
							 | 
						|
								
							 | 
						|
								    if (fileName != NULL)
							 | 
						|
								    {
							 | 
						|
								        FILE *file = fopen(fileName, "rt");
							 | 
						|
								
							 | 
						|
								        if (file != NULL)
							 | 
						|
								        {
							 | 
						|
								            // WARNING: When reading a file as 'text' file,
							 | 
						|
								            // text mode causes carriage return-linefeed translation...
							 | 
						|
								            // ...but using fseek() should return correct byte-offset
							 | 
						|
								            fseek(file, 0, SEEK_END);
							 | 
						|
								            int size = ftell(file);
							 | 
						|
								            fseek(file, 0, SEEK_SET);
							 | 
						|
								
							 | 
						|
								            if (size > 0)
							 | 
						|
								            {
							 | 
						|
								                text = (char *)calloc((size + 1), sizeof(char));
							 | 
						|
								                unsigned int count = (unsigned int)fread(text, sizeof(char), size, file);
							 | 
						|
								
							 | 
						|
								                // WARNING: \r\n is converted to \n on reading, so,
							 | 
						|
								                // read bytes count gets reduced by the number of lines
							 | 
						|
								                if (count < (unsigned int)size)
							 | 
						|
								                {
							 | 
						|
								                    text = realloc(text, count + 1);
							 | 
						|
								                    *length = count;
							 | 
						|
								                }
							 | 
						|
								                else *length = size;
							 | 
						|
								
							 | 
						|
								                // Zero-terminate the string
							 | 
						|
								                text[count] = '\0';
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            fclose(file);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return text;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Get all lines from a text buffer (expecting lines ending with '\n')
							 | 
						|
								static char **GetTextLines(const char *buffer, int length, int *linesCount)
							 | 
						|
								{
							 | 
						|
								    // Get the number of lines in the text
							 | 
						|
								    int count = 0;
							 | 
						|
								    for (int i = 0; i < length; i++) if (buffer[i] == '\n') count++;
							 | 
						|
								
							 | 
						|
								    printf("Number of text lines in buffer: %i\n", count);
							 | 
						|
								
							 | 
						|
								    // Allocate as many pointers as lines
							 | 
						|
								    char **lines = (char **)malloc(count*sizeof(char **));
							 | 
						|
								
							 | 
						|
								    char *bufferPtr = (char *)buffer;
							 | 
						|
								
							 | 
						|
								    for (int i = 0; (i < count) || (bufferPtr[0] != '\0'); i++)
							 | 
						|
								    {
							 | 
						|
								        lines[i] = (char *)calloc(MAX_LINE_LENGTH, sizeof(char));
							 | 
						|
								
							 | 
						|
								        // Remove line leading spaces
							 | 
						|
								        // Find last index of space/tab character
							 | 
						|
								        int index = 0;
							 | 
						|
								        while ((bufferPtr[index] == ' ') || (bufferPtr[index] == '\t')) index++;
							 | 
						|
								
							 | 
						|
								        int j = 0;
							 | 
						|
								        while (bufferPtr[index + j] != '\n' && bufferPtr[index + j] != '\0')
							 | 
						|
								        {
							 | 
						|
								            lines[i][j] = bufferPtr[index + j];
							 | 
						|
								            j++;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        bufferPtr += (index + j + 1);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    *linesCount = count;
							 | 
						|
								    return lines;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Get data type and name from a string containing both
							 | 
						|
								// NOTE: Useful to parse function parameters and struct fields
							 | 
						|
								static void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name)
							 | 
						|
								{
							 | 
						|
								    for (int k = typeNameLen; k > 0; k--)
							 | 
						|
								    {
							 | 
						|
								        if ((typeName[k] == ' ') && (typeName[k - 1] != ','))
							 | 
						|
								        {
							 | 
						|
								            // Function name starts at this point (and ret type finishes at this point)
							 | 
						|
								            MemoryCopy(type, typeName, k);
							 | 
						|
								            MemoryCopy(name, typeName + k + 1, typeNameLen - k - 1);
							 | 
						|
								            break;
							 | 
						|
								        }
							 | 
						|
								        else if (typeName[k] == '*')
							 | 
						|
								        {
							 | 
						|
								            MemoryCopy(type, typeName, k + 1);
							 | 
						|
								            MemoryCopy(name, typeName + k + 1, typeNameLen - k - 1);
							 | 
						|
								            break;
							 | 
						|
								        }
							 | 
						|
								        else if ((typeName[k] == '.') && (typeNameLen == 3)) // Handle varargs ...);
							 | 
						|
								        {
							 | 
						|
									    const char *varargsDots = "...";
							 | 
						|
									    const char *varargsArg = "args";
							 | 
						|
								            MemoryCopy(type, varargsDots, TextLength(varargsDots));
							 | 
						|
								            MemoryCopy(name, varargsArg, TextLength(varargsArg));
							 | 
						|
								            break;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Get comment from a line, do nothing if no comment in line
							 | 
						|
								static void GetDescription(const char *line, char *description)
							 | 
						|
								{
							 | 
						|
								    int c = 0;
							 | 
						|
								    int descStart = -1;
							 | 
						|
								    int lastSlash = -2;
							 | 
						|
								    bool isValid = false;
							 | 
						|
								    while (line[c] != '\0')
							 | 
						|
								    {
							 | 
						|
								        if (isValid && (descStart == -1) && (line[c] != ' ')) descStart = c;
							 | 
						|
								        else if (line[c] == '/')
							 | 
						|
								        {
							 | 
						|
								            if (lastSlash == c - 1) isValid = true;
							 | 
						|
								            lastSlash = c;
							 | 
						|
								        }
							 | 
						|
								        c++;
							 | 
						|
								    }
							 | 
						|
								    if (descStart != -1) MemoryCopy(description, &line[descStart], c - descStart);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Move array size from name to type
							 | 
						|
								static void MoveArraySize(char *name, char *type)
							 | 
						|
								{
							 | 
						|
								    int nameLength = TextLength(name);
							 | 
						|
								    if (name[nameLength - 1] == ']')
							 | 
						|
								    {
							 | 
						|
								        for (int k = nameLength; k > 0; k--)
							 | 
						|
								        {
							 | 
						|
								            if (name[k] == '[')
							 | 
						|
								            {
							 | 
						|
								                int sizeLength = nameLength - k;
							 | 
						|
								                MemoryCopy(&type[TextLength(type)], &name[k], sizeLength);
							 | 
						|
								                name[k] = '\0';
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Get text length in bytes, check for \0 character
							 | 
						|
								static unsigned int TextLength(const char *text)
							 | 
						|
								{
							 | 
						|
								    unsigned int length = 0;
							 | 
						|
								
							 | 
						|
								    if (text != NULL) while (*text++) length++;
							 | 
						|
								
							 | 
						|
								    return length;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Compare two text strings, requires number of characters to compare
							 | 
						|
								static bool IsTextEqual(const char *text1, const char *text2, unsigned int count)
							 | 
						|
								{
							 | 
						|
								    bool result = true;
							 | 
						|
								
							 | 
						|
								    for (unsigned int i = 0; i < count; i++)
							 | 
						|
								    {
							 | 
						|
								        if (text1[i] != text2[i])
							 | 
						|
								        {
							 | 
						|
								            result = false;
							 | 
						|
								            break;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return result;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Find first text occurrence within a string
							 | 
						|
								int TextFindIndex(const char *text, const char *find)
							 | 
						|
								{
							 | 
						|
								    int textLen = TextLength(text);
							 | 
						|
								    int findLen = TextLength(find);
							 | 
						|
								
							 | 
						|
								    for (int i = 0; i <= textLen - findLen; i++)
							 | 
						|
								    {
							 | 
						|
								        if (IsTextEqual(&text[i], find, findLen)) return i;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return -1;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Custom memcpy() to avoid <string.h>
							 | 
						|
								static void MemoryCopy(void *dest, const void *src, unsigned int count)
							 | 
						|
								{
							 | 
						|
								    char *srcPtr = (char *)src;
							 | 
						|
								    char *destPtr = (char *)dest;
							 | 
						|
								
							 | 
						|
								    for (unsigned int i = 0; i < count; i++) destPtr[i] = srcPtr[i];
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Escape backslashes in a string, writing the escaped string into a static buffer
							 | 
						|
								static char *EscapeBackslashes(char *text)
							 | 
						|
								{
							 | 
						|
								    static char buffer[256] = { 0 };
							 | 
						|
								
							 | 
						|
								    int count = 0;
							 | 
						|
								
							 | 
						|
								    for (int i = 0; (text[i] != '\0') && (i < 255); i++, count++)
							 | 
						|
								    {
							 | 
						|
								        buffer[count] = text[i];
							 | 
						|
								
							 | 
						|
								        if (text[i] == '\\')
							 | 
						|
								        {
							 | 
						|
								            buffer[count + 1] = '\\';
							 | 
						|
								            count++;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    buffer[count] = '\0';
							 | 
						|
								
							 | 
						|
								    return buffer;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Get string of define type
							 | 
						|
								static const char *StrDefineType(DefineType type)
							 | 
						|
								{
							 | 
						|
								    switch (type)
							 | 
						|
								    {
							 | 
						|
								        case UNKNOWN:     return "UNKNOWN";
							 | 
						|
								        case GUARD:       return "GUARD";
							 | 
						|
								        case MACRO:       return "MACRO";
							 | 
						|
								        case INT:         return "INT";
							 | 
						|
								        case INT_MATH:    return "INT_MATH";
							 | 
						|
								        case LONG:        return "LONG";
							 | 
						|
								        case LONG_MATH:   return "LONG_MATH";
							 | 
						|
								        case FLOAT:       return "FLOAT";
							 | 
						|
								        case FLOAT_MATH:  return "FLOAT_MATH";
							 | 
						|
								        case DOUBLE:      return "DOUBLE";
							 | 
						|
								        case DOUBLE_MATH: return "DOUBLE_MATH";
							 | 
						|
								        case CHAR:        return "CHAR";
							 | 
						|
								        case STRING:      return "STRING";
							 | 
						|
								        case COLOR:       return "COLOR";
							 | 
						|
								    }
							 | 
						|
								    return "";
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/*
							 | 
						|
								// Replace text string
							 | 
						|
								// REQUIRES: strlen(), strstr(), strncpy(), strcpy() -> TODO: Replace by custom implementations!
							 | 
						|
								// WARNING: Returned buffer must be freed by the user (if return != NULL)
							 | 
						|
								static char *TextReplace(char *text, const char *replace, const char *by)
							 | 
						|
								{
							 | 
						|
								    // Sanity checks and initialization
							 | 
						|
								    if (!text || !replace || !by) return NULL;
							 | 
						|
								
							 | 
						|
								    char *result;
							 | 
						|
								
							 | 
						|
								    char *insertPoint;      // Next insert point
							 | 
						|
								    char *temp;             // Temp pointer
							 | 
						|
								    int replaceLen;         // Replace string length of (the string to remove)
							 | 
						|
								    int byLen;              // Replacement length (the string to replace replace by)
							 | 
						|
								    int lastReplacePos;     // Distance between replace and end of last replace
							 | 
						|
								    int count;              // Number of replacements
							 | 
						|
								
							 | 
						|
								    replaceLen = strlen(replace);
							 | 
						|
								    if (replaceLen == 0) return NULL;  // Empty replace causes infinite loop during count
							 | 
						|
								
							 | 
						|
								    byLen = strlen(by);
							 | 
						|
								
							 | 
						|
								    // Count the number of replacements needed
							 | 
						|
								    insertPoint = text;
							 | 
						|
								    for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
							 | 
						|
								
							 | 
						|
								    // Allocate returning string and point temp to it
							 | 
						|
								    temp = result = (char *)malloc(strlen(text) + (byLen - replaceLen)*count + 1);
							 | 
						|
								
							 | 
						|
								    if (!result) return NULL;   // Memory could not be allocated
							 | 
						|
								
							 | 
						|
								    // First time through the loop, all the variable are set correctly from here on,
							 | 
						|
								    //  - 'temp' points to the end of the result string
							 | 
						|
								    //  - 'insertPoint' points to the next occurrence of replace in text
							 | 
						|
								    //  - 'text' points to the remainder of text after "end of replace"
							 | 
						|
								    while (count--)
							 | 
						|
								    {
							 | 
						|
								        insertPoint = strstr(text, replace);
							 | 
						|
								        lastReplacePos = (int)(insertPoint - text);
							 | 
						|
								        temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
							 | 
						|
								        temp = strcpy(temp, by) + byLen;
							 | 
						|
								        text += lastReplacePos + replaceLen; // Move to next "end of replace"
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Copy remaind text part after replacement to result (pointed by moving temp)
							 | 
						|
								    strcpy(temp, text);
							 | 
						|
								
							 | 
						|
								    return result;
							 | 
						|
								}
							 | 
						|
								*/
							 | 
						|
								
							 | 
						|
								// Export parsed data in desired format
							 | 
						|
								static void ExportParsedData(const char *fileName, int format)
							 | 
						|
								{
							 | 
						|
								    FILE *outFile = fopen(fileName, "wt");
							 | 
						|
								
							 | 
						|
								    switch (format)
							 | 
						|
								    {
							 | 
						|
								        case DEFAULT:
							 | 
						|
								        {
							 | 
						|
								            // Print defines info
							 | 
						|
								            fprintf(outFile, "\nDefines found: %i\n\n", defineCount);
							 | 
						|
								            for (int i = 0; i < defineCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "Define %03i: %s\n", i + 1, defines[i].name);
							 | 
						|
								                fprintf(outFile, "  Name: %s\n", defines[i].name);
							 | 
						|
								                fprintf(outFile, "  Type: %s\n", StrDefineType(defines[i].type));
							 | 
						|
								                fprintf(outFile, "  Value: %s\n", defines[i].value);
							 | 
						|
								                fprintf(outFile, "  Description: %s\n", defines[i].desc);
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Print structs info
							 | 
						|
								            fprintf(outFile, "\nStructures found: %i\n\n", structCount);
							 | 
						|
								            for (int i = 0; i < structCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "Struct %02i: %s (%i fields)\n", i + 1, structs[i].name, structs[i].fieldCount);
							 | 
						|
								                fprintf(outFile, "  Name: %s\n", structs[i].name);
							 | 
						|
								                fprintf(outFile, "  Description: %s\n", structs[i].desc);
							 | 
						|
								                for (int f = 0; f < structs[i].fieldCount; f++)
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "  Field[%i]: %s %s ", f + 1, structs[i].fieldType[f], structs[i].fieldName[f]);
							 | 
						|
								                    if (structs[i].fieldDesc[f][0]) fprintf(outFile, "// %s\n", structs[i].fieldDesc[f]);
							 | 
						|
								                    else fprintf(outFile, "\n");
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Print aliases info
							 | 
						|
								            fprintf(outFile, "\nAliases found: %i\n\n", aliasCount);
							 | 
						|
								            for (int i = 0; i < aliasCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "Alias %03i: %s\n", i + 1, aliases[i].name);
							 | 
						|
								                fprintf(outFile, "  Type: %s\n", aliases[i].type);
							 | 
						|
								                fprintf(outFile, "  Name: %s\n", aliases[i].name);
							 | 
						|
								                fprintf(outFile, "  Description: %s\n", aliases[i].desc);
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Print enums info
							 | 
						|
								            fprintf(outFile, "\nEnums found: %i\n\n", enumCount);
							 | 
						|
								            for (int i = 0; i < enumCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "Enum %02i: %s (%i values)\n", i + 1, enums[i].name, enums[i].valueCount);
							 | 
						|
								                fprintf(outFile, "  Name: %s\n", enums[i].name);
							 | 
						|
								                fprintf(outFile, "  Description: %s\n", enums[i].desc);
							 | 
						|
								                for (int e = 0; e < enums[i].valueCount; e++) fprintf(outFile, "  Value[%s]: %i\n", enums[i].valueName[e], enums[i].valueInteger[e]);
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Print callbacks info
							 | 
						|
								            fprintf(outFile, "\nCallbacks found: %i\n\n", callbackCount);
							 | 
						|
								            for (int i = 0; i < callbackCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "Callback %03i: %s() (%i input parameters)\n", i + 1, callbacks[i].name, callbacks[i].paramCount);
							 | 
						|
								                fprintf(outFile, "  Name: %s\n", callbacks[i].name);
							 | 
						|
								                fprintf(outFile, "  Return type: %s\n", callbacks[i].retType);
							 | 
						|
								                fprintf(outFile, "  Description: %s\n", callbacks[i].desc);
							 | 
						|
								                for (int p = 0; p < callbacks[i].paramCount; p++) fprintf(outFile, "  Param[%i]: %s (type: %s)\n", p + 1, callbacks[i].paramName[p], callbacks[i].paramType[p]);
							 | 
						|
								                if (callbacks[i].paramCount == 0) fprintf(outFile, "  No input parameters\n");
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Print functions info
							 | 
						|
								            fprintf(outFile, "\nFunctions found: %i\n\n", funcCount);
							 | 
						|
								            for (int i = 0; i < funcCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "Function %03i: %s() (%i input parameters)\n", i + 1, funcs[i].name, funcs[i].paramCount);
							 | 
						|
								                fprintf(outFile, "  Name: %s\n", funcs[i].name);
							 | 
						|
								                fprintf(outFile, "  Return type: %s\n", funcs[i].retType);
							 | 
						|
								                fprintf(outFile, "  Description: %s\n", funcs[i].desc);
							 | 
						|
								                for (int p = 0; p < funcs[i].paramCount; p++) fprintf(outFile, "  Param[%i]: %s (type: %s)\n", p + 1, funcs[i].paramName[p], funcs[i].paramType[p]);
							 | 
						|
								                if (funcs[i].paramCount == 0) fprintf(outFile, "  No input parameters\n");
							 | 
						|
								            }
							 | 
						|
								        } break;
							 | 
						|
								        case JSON:
							 | 
						|
								        {
							 | 
						|
								            fprintf(outFile, "{\n");
							 | 
						|
								
							 | 
						|
								            // Print defines info
							 | 
						|
								            fprintf(outFile, "  \"defines\": [\n");
							 | 
						|
								            for (int i = 0; i < defineCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "    {\n");
							 | 
						|
								                fprintf(outFile, "      \"name\": \"%s\",\n", defines[i].name);
							 | 
						|
								                fprintf(outFile, "      \"type\": \"%s\",\n", StrDefineType(defines[i].type));
							 | 
						|
								                if (defines[i].isHex) // INT or LONG
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "      \"value\": %ld,\n", strtol(defines[i].value, NULL, 16));
							 | 
						|
								                }
							 | 
						|
								                else if ((defines[i].type == INT) ||
							 | 
						|
								                         (defines[i].type == LONG) ||
							 | 
						|
								                         (defines[i].type == FLOAT) ||
							 | 
						|
								                         (defines[i].type == DOUBLE) ||
							 | 
						|
								                         (defines[i].type == STRING))
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "      \"value\": %s,\n", defines[i].value);
							 | 
						|
								                }
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "      \"value\": \"%s\",\n", defines[i].value);
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "      \"description\": \"%s\"\n", defines[i].desc);
							 | 
						|
								                fprintf(outFile, "    }");
							 | 
						|
								
							 | 
						|
								                if (i < defineCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                else fprintf(outFile, "\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "  ],\n");
							 | 
						|
								
							 | 
						|
								            // Print structs info
							 | 
						|
								            fprintf(outFile, "  \"structs\": [\n");
							 | 
						|
								            for (int i = 0; i < structCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "    {\n");
							 | 
						|
								                fprintf(outFile, "      \"name\": \"%s\",\n", structs[i].name);
							 | 
						|
								                fprintf(outFile, "      \"description\": \"%s\",\n", EscapeBackslashes(structs[i].desc));
							 | 
						|
								                fprintf(outFile, "      \"fields\": [\n");
							 | 
						|
								                for (int f = 0; f < structs[i].fieldCount; f++)
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "        {\n");
							 | 
						|
								                    fprintf(outFile, "          \"type\": \"%s\",\n", structs[i].fieldType[f]);
							 | 
						|
								                    fprintf(outFile, "          \"name\": \"%s\",\n", structs[i].fieldName[f]);
							 | 
						|
								                    fprintf(outFile, "          \"description\": \"%s\"\n", EscapeBackslashes(structs[i].fieldDesc[f]));
							 | 
						|
								                    fprintf(outFile, "        }");
							 | 
						|
								                    if (f < structs[i].fieldCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                    else fprintf(outFile, "\n");
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "      ]\n");
							 | 
						|
								                fprintf(outFile, "    }");
							 | 
						|
								                if (i < structCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                else fprintf(outFile, "\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "  ],\n");
							 | 
						|
								
							 | 
						|
								            // Print aliases info
							 | 
						|
								            fprintf(outFile, "  \"aliases\": [\n");
							 | 
						|
								            for (int i = 0; i < aliasCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "    {\n");
							 | 
						|
								                fprintf(outFile, "      \"type\": \"%s\",\n", aliases[i].type);
							 | 
						|
								                fprintf(outFile, "      \"name\": \"%s\",\n", aliases[i].name);
							 | 
						|
								                fprintf(outFile, "      \"description\": \"%s\"\n", aliases[i].desc);
							 | 
						|
								                fprintf(outFile, "    }");
							 | 
						|
								
							 | 
						|
								                if (i < aliasCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                else fprintf(outFile, "\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "  ],\n");
							 | 
						|
								
							 | 
						|
								            // Print enums info
							 | 
						|
								            fprintf(outFile, "  \"enums\": [\n");
							 | 
						|
								            for (int i = 0; i < enumCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "    {\n");
							 | 
						|
								                fprintf(outFile, "      \"name\": \"%s\",\n", enums[i].name);
							 | 
						|
								                fprintf(outFile, "      \"description\": \"%s\",\n", EscapeBackslashes(enums[i].desc));
							 | 
						|
								                fprintf(outFile, "      \"values\": [\n");
							 | 
						|
								                for (int e = 0; e < enums[i].valueCount; e++)
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "        {\n");
							 | 
						|
								                    fprintf(outFile, "          \"name\": \"%s\",\n", enums[i].valueName[e]);
							 | 
						|
								                    fprintf(outFile, "          \"value\": %i,\n", enums[i].valueInteger[e]);
							 | 
						|
								                    fprintf(outFile, "          \"description\": \"%s\"\n", EscapeBackslashes(enums[i].valueDesc[e]));
							 | 
						|
								                    fprintf(outFile, "        }");
							 | 
						|
								                    if (e < enums[i].valueCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                    else fprintf(outFile, "\n");
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "      ]\n");
							 | 
						|
								                fprintf(outFile, "    }");
							 | 
						|
								                if (i < enumCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                else fprintf(outFile, "\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "  ],\n");
							 | 
						|
								
							 | 
						|
								            // Print callbacks info
							 | 
						|
								            fprintf(outFile, "  \"callbacks\": [\n");
							 | 
						|
								            for (int i = 0; i < callbackCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "    {\n");
							 | 
						|
								                fprintf(outFile, "      \"name\": \"%s\",\n", callbacks[i].name);
							 | 
						|
								                fprintf(outFile, "      \"description\": \"%s\",\n", EscapeBackslashes(callbacks[i].desc));
							 | 
						|
								                fprintf(outFile, "      \"returnType\": \"%s\"", callbacks[i].retType);
							 | 
						|
								
							 | 
						|
								                if (callbacks[i].paramCount == 0) fprintf(outFile, "\n");
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, ",\n      \"params\": [\n");
							 | 
						|
								                    for (int p = 0; p < callbacks[i].paramCount; p++)
							 | 
						|
								                    {
							 | 
						|
								                        fprintf(outFile, "        {\n");
							 | 
						|
								                        fprintf(outFile, "          \"type\": \"%s\",\n", callbacks[i].paramType[p]);
							 | 
						|
								                        fprintf(outFile, "          \"name\": \"%s\"\n", callbacks[i].paramName[p]);
							 | 
						|
								                        fprintf(outFile, "        }");
							 | 
						|
								                        if (p < callbacks[i].paramCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                        else fprintf(outFile, "\n");
							 | 
						|
								                    }
							 | 
						|
								                    fprintf(outFile, "      ]\n");
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "    }");
							 | 
						|
								
							 | 
						|
								                if (i < callbackCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                else fprintf(outFile, "\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "  ],\n");
							 | 
						|
								
							 | 
						|
								            // Print functions info
							 | 
						|
								            fprintf(outFile, "  \"functions\": [\n");
							 | 
						|
								            for (int i = 0; i < funcCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "    {\n");
							 | 
						|
								                fprintf(outFile, "      \"name\": \"%s\",\n", funcs[i].name);
							 | 
						|
								                fprintf(outFile, "      \"description\": \"%s\",\n", EscapeBackslashes(funcs[i].desc));
							 | 
						|
								                fprintf(outFile, "      \"returnType\": \"%s\"", funcs[i].retType);
							 | 
						|
								
							 | 
						|
								                if (funcs[i].paramCount == 0) fprintf(outFile, "\n");
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, ",\n      \"params\": [\n");
							 | 
						|
								                    for (int p = 0; p < funcs[i].paramCount; p++)
							 | 
						|
								                    {
							 | 
						|
								                        fprintf(outFile, "        {\n");
							 | 
						|
								                        fprintf(outFile, "          \"type\": \"%s\",\n", funcs[i].paramType[p]);
							 | 
						|
								                        fprintf(outFile, "          \"name\": \"%s\"\n", funcs[i].paramName[p]);
							 | 
						|
								                        fprintf(outFile, "        }");
							 | 
						|
								                        if (p < funcs[i].paramCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                        else fprintf(outFile, "\n");
							 | 
						|
								                    }
							 | 
						|
								                    fprintf(outFile, "      ]\n");
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "    }");
							 | 
						|
								
							 | 
						|
								                if (i < funcCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                else fprintf(outFile, "\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "  ]\n");
							 | 
						|
								            fprintf(outFile, "}\n");
							 | 
						|
								        } break;
							 | 
						|
								        case XML:
							 | 
						|
								        {
							 | 
						|
								            // XML format to export data:
							 | 
						|
								            /*
							 | 
						|
								            <?xml version="1.0" encoding="Windows-1252" ?>
							 | 
						|
								            <raylibAPI>
							 | 
						|
								                <Defines count="">
							 | 
						|
								                    <Define name="" type="" value="" desc="" />
							 | 
						|
								                </Defines>
							 | 
						|
								                <Structs count="">
							 | 
						|
								                    <Struct name="" fieldCount="" desc="">
							 | 
						|
								                        <Field type="" name="" desc="" />
							 | 
						|
								                        <Field type="" name="" desc="" />
							 | 
						|
								                    </Struct>
							 | 
						|
								                <Structs>
							 | 
						|
								                <Aliases count="">
							 | 
						|
								                    <Alias type="" name="" desc="" />
							 | 
						|
								                </Aliases>
							 | 
						|
								                <Enums count="">
							 | 
						|
								                    <Enum name="" valueCount="" desc="">
							 | 
						|
								                        <Value name="" integer="" desc="" />
							 | 
						|
								                        <Value name="" integer="" desc="" />
							 | 
						|
								                    </Enum>
							 | 
						|
								                </Enums>
							 | 
						|
								                <Callbacks count="">
							 | 
						|
								                    <Callback name="" retType="" paramCount="" desc="">
							 | 
						|
								                        <Param type="" name="" desc="" />
							 | 
						|
								                        <Param type="" name="" desc="" />
							 | 
						|
								                    </Callback>
							 | 
						|
								                </Callbacks>
							 | 
						|
								                <Functions count="">
							 | 
						|
								                    <Function name="" retType="" paramCount="" desc="">
							 | 
						|
								                        <Param type="" name="" desc="" />
							 | 
						|
								                        <Param type="" name="" desc="" />
							 | 
						|
								                    </Function>
							 | 
						|
								                </Functions>
							 | 
						|
								            </raylibAPI>
							 | 
						|
								            */
							 | 
						|
								
							 | 
						|
								            fprintf(outFile, "<?xml version=\"1.0\" encoding=\"Windows-1252\" ?>\n");
							 | 
						|
								            fprintf(outFile, "<raylibAPI>\n");
							 | 
						|
								
							 | 
						|
								            // Print defines info
							 | 
						|
								            fprintf(outFile, "    <Defines count=\"%i\">\n", defineCount);
							 | 
						|
								            for (int i = 0; i < defineCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "        <Define name=\"%s\" type=\"%s\" ", defines[i].name, StrDefineType(defines[i].type));
							 | 
						|
								                if (defines[i].type == STRING)
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "value=%s", defines[i].value);
							 | 
						|
								                }
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "value=\"%s\"", defines[i].value);
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, " desc=\"%s\" />\n", defines[i].desc);
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "    </Defines>\n");
							 | 
						|
								
							 | 
						|
								            // Print structs info
							 | 
						|
								            fprintf(outFile, "    <Structs count=\"%i\">\n", structCount);
							 | 
						|
								            for (int i = 0; i < structCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "        <Struct name=\"%s\" fieldCount=\"%i\" desc=\"%s\">\n", structs[i].name, structs[i].fieldCount, structs[i].desc);
							 | 
						|
								                for (int f = 0; f < structs[i].fieldCount; f++)
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "            <Field type=\"%s\" name=\"%s\" desc=\"%s\" />\n", structs[i].fieldType[f], structs[i].fieldName[f], structs[i].fieldDesc[f]);
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "        </Struct>\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "    </Structs>\n");
							 | 
						|
								
							 | 
						|
								            // Print aliases info
							 | 
						|
								            fprintf(outFile, "    <Aliases count=\"%i\">\n", aliasCount);
							 | 
						|
								            for (int i = 0; i < aliasCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "        <Alias type=\"%s\" name=\"%s\" desc=\"%s\" />\n", aliases[i].name, aliases[i].type, aliases[i].desc);
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "    </Aliases>\n");
							 | 
						|
								
							 | 
						|
								            // Print enums info
							 | 
						|
								            fprintf(outFile, "    <Enums count=\"%i\">\n", enumCount);
							 | 
						|
								            for (int i = 0; i < enumCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "        <Enum name=\"%s\" valueCount=\"%i\" desc=\"%s\">\n", enums[i].name, enums[i].valueCount, enums[i].desc);
							 | 
						|
								                for (int v = 0; v < enums[i].valueCount; v++)
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "            <Value name=\"%s\" integer=\"%i\" desc=\"%s\" />\n", enums[i].valueName[v], enums[i].valueInteger[v], enums[i].valueDesc[v]);
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "        </Enum>\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "    </Enums>\n");
							 | 
						|
								
							 | 
						|
								            // Print callbacks info
							 | 
						|
								            fprintf(outFile, "    <Callbacks count=\"%i\">\n", callbackCount);
							 | 
						|
								            for (int i = 0; i < callbackCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "        <Callback name=\"%s\" retType=\"%s\" paramCount=\"%i\" desc=\"%s\">\n", callbacks[i].name, callbacks[i].retType, callbacks[i].paramCount, callbacks[i].desc);
							 | 
						|
								                for (int p = 0; p < callbacks[i].paramCount; p++)
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "            <Param type=\"%s\" name=\"%s\" desc=\"%s\" />\n", callbacks[i].paramType[p], callbacks[i].paramName[p], callbacks[i].paramDesc[p]);
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "        </Callback>\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "    </Callbacks>\n");
							 | 
						|
								
							 | 
						|
								            // Print functions info
							 | 
						|
								            fprintf(outFile, "    <Functions count=\"%i\">\n", funcCount);
							 | 
						|
								            for (int i = 0; i < funcCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "        <Function name=\"%s\" retType=\"%s\" paramCount=\"%i\" desc=\"%s\">\n", funcs[i].name, funcs[i].retType, funcs[i].paramCount, funcs[i].desc);
							 | 
						|
								                for (int p = 0; p < funcs[i].paramCount; p++)
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "            <Param type=\"%s\" name=\"%s\" desc=\"%s\" />\n", funcs[i].paramType[p], funcs[i].paramName[p], funcs[i].paramDesc[p]);
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "        </Function>\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "    </Functions>\n");
							 | 
						|
								
							 | 
						|
								            fprintf(outFile, "</raylibAPI>\n");
							 | 
						|
								
							 | 
						|
								        } break;
							 | 
						|
								        case LUA:
							 | 
						|
								        {
							 | 
						|
								            fprintf(outFile, "return {\n");
							 | 
						|
								
							 | 
						|
								            // Print defines info
							 | 
						|
								            fprintf(outFile, "  defines = {\n");
							 | 
						|
								            for (int i = 0; i < defineCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "    {\n");
							 | 
						|
								                fprintf(outFile, "      name = \"%s\",\n", defines[i].name);
							 | 
						|
								                fprintf(outFile, "      type = \"%s\",\n", StrDefineType(defines[i].type));
							 | 
						|
								                if ((defines[i].type == INT) ||
							 | 
						|
								                    (defines[i].type == LONG) ||
							 | 
						|
								                    (defines[i].type == FLOAT) ||
							 | 
						|
								                    (defines[i].type == DOUBLE) ||
							 | 
						|
								                    (defines[i].type == STRING))
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "      value = %s,\n", defines[i].value);
							 | 
						|
								                }
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "      value = \"%s\",\n", defines[i].value);
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "      description = \"%s\"\n", defines[i].desc);
							 | 
						|
								                fprintf(outFile, "    }");
							 | 
						|
								
							 | 
						|
								                if (i < defineCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                else fprintf(outFile, "\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "  },\n");
							 | 
						|
								
							 | 
						|
								            // Print structs info
							 | 
						|
								            fprintf(outFile, "  structs = {\n");
							 | 
						|
								            for (int i = 0; i < structCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "    {\n");
							 | 
						|
								                fprintf(outFile, "      name = \"%s\",\n", structs[i].name);
							 | 
						|
								                fprintf(outFile, "      description = \"%s\",\n", EscapeBackslashes(structs[i].desc));
							 | 
						|
								                fprintf(outFile, "      fields = {\n");
							 | 
						|
								                for (int f = 0; f < structs[i].fieldCount; f++)
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "        {\n");
							 | 
						|
								                    fprintf(outFile, "          type = \"%s\",\n", structs[i].fieldType[f]);
							 | 
						|
								                    fprintf(outFile, "          name = \"%s\",\n", structs[i].fieldName[f]);
							 | 
						|
								                    fprintf(outFile, "          description = \"%s\"\n", EscapeBackslashes(structs[i].fieldDesc[f]));
							 | 
						|
								                    fprintf(outFile, "        }");
							 | 
						|
								                    if (f < structs[i].fieldCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                    else fprintf(outFile, "\n");
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "      }\n");
							 | 
						|
								                fprintf(outFile, "    }");
							 | 
						|
								                if (i < structCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                else fprintf(outFile, "\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "  },\n");
							 | 
						|
								
							 | 
						|
								            // Print aliases info
							 | 
						|
								            fprintf(outFile, "  aliases = {\n");
							 | 
						|
								            for (int i = 0; i < aliasCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "    {\n");
							 | 
						|
								                fprintf(outFile, "      type = \"%s\",\n", aliases[i].type);
							 | 
						|
								                fprintf(outFile, "      name = \"%s\",\n", aliases[i].name);
							 | 
						|
								                fprintf(outFile, "      description = \"%s\"\n", aliases[i].desc);
							 | 
						|
								                fprintf(outFile, "    }");
							 | 
						|
								
							 | 
						|
								                if (i < aliasCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                else fprintf(outFile, "\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "  },\n");
							 | 
						|
								
							 | 
						|
								            // Print enums info
							 | 
						|
								            fprintf(outFile, "  enums = {\n");
							 | 
						|
								            for (int i = 0; i < enumCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "    {\n");
							 | 
						|
								                fprintf(outFile, "      name = \"%s\",\n", enums[i].name);
							 | 
						|
								                fprintf(outFile, "      description = \"%s\",\n", EscapeBackslashes(enums[i].desc));
							 | 
						|
								                fprintf(outFile, "      values = {\n");
							 | 
						|
								                for (int e = 0; e < enums[i].valueCount; e++)
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, "        {\n");
							 | 
						|
								                    fprintf(outFile, "          name = \"%s\",\n", enums[i].valueName[e]);
							 | 
						|
								                    fprintf(outFile, "          value = %i,\n", enums[i].valueInteger[e]);
							 | 
						|
								                    fprintf(outFile, "          description = \"%s\"\n", EscapeBackslashes(enums[i].valueDesc[e]));
							 | 
						|
								                    fprintf(outFile, "        }");
							 | 
						|
								                    if (e < enums[i].valueCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                    else fprintf(outFile, "\n");
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "      }\n");
							 | 
						|
								                fprintf(outFile, "    }");
							 | 
						|
								                if (i < enumCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                else fprintf(outFile, "\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "  },\n");
							 | 
						|
								
							 | 
						|
								            // Print callbacks info
							 | 
						|
								            fprintf(outFile, "  callbacks = {\n");
							 | 
						|
								            for (int i = 0; i < callbackCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "    {\n");
							 | 
						|
								                fprintf(outFile, "      name = \"%s\",\n", callbacks[i].name);
							 | 
						|
								                fprintf(outFile, "      description = \"%s\",\n", EscapeBackslashes(callbacks[i].desc));
							 | 
						|
								                fprintf(outFile, "      returnType = \"%s\"", callbacks[i].retType);
							 | 
						|
								
							 | 
						|
								                if (callbacks[i].paramCount == 0) fprintf(outFile, "\n");
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, ",\n      params = {\n");
							 | 
						|
								                    for (int p = 0; p < callbacks[i].paramCount; p++)
							 | 
						|
								                    {
							 | 
						|
								                        fprintf(outFile, "        {type = \"%s\", name = \"%s\"}", callbacks[i].paramType[p], callbacks[i].paramName[p]);
							 | 
						|
								                        if (p < callbacks[i].paramCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                        else fprintf(outFile, "\n");
							 | 
						|
								                    }
							 | 
						|
								                    fprintf(outFile, "      }\n");
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "    }");
							 | 
						|
								
							 | 
						|
								                if (i < callbackCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                else fprintf(outFile, "\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "  },\n");
							 | 
						|
								
							 | 
						|
								            // Print functions info
							 | 
						|
								            fprintf(outFile, "  functions = {\n");
							 | 
						|
								            for (int i = 0; i < funcCount; i++)
							 | 
						|
								            {
							 | 
						|
								                fprintf(outFile, "    {\n");
							 | 
						|
								                fprintf(outFile, "      name = \"%s\",\n", funcs[i].name);
							 | 
						|
								                fprintf(outFile, "      description = \"%s\",\n", EscapeBackslashes(funcs[i].desc));
							 | 
						|
								                fprintf(outFile, "      returnType = \"%s\"", funcs[i].retType);
							 | 
						|
								
							 | 
						|
								                if (funcs[i].paramCount == 0) fprintf(outFile, "\n");
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    fprintf(outFile, ",\n      params = {\n");
							 | 
						|
								                    for (int p = 0; p < funcs[i].paramCount; p++)
							 | 
						|
								                    {
							 | 
						|
								                        fprintf(outFile, "        {type = \"%s\", name = \"%s\"}", funcs[i].paramType[p], funcs[i].paramName[p]);
							 | 
						|
								                        if (p < funcs[i].paramCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                        else fprintf(outFile, "\n");
							 | 
						|
								                    }
							 | 
						|
								                    fprintf(outFile, "      }\n");
							 | 
						|
								                }
							 | 
						|
								                fprintf(outFile, "    }");
							 | 
						|
								
							 | 
						|
								                if (i < funcCount - 1) fprintf(outFile, ",\n");
							 | 
						|
								                else fprintf(outFile, "\n");
							 | 
						|
								            }
							 | 
						|
								            fprintf(outFile, "  }\n");
							 | 
						|
								            fprintf(outFile, "}\n");
							 | 
						|
								        } break;
							 | 
						|
								        case CODE:
							 | 
						|
								        default: break;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    fclose(outFile);
							 | 
						|
								}
							 |