|
@@ -0,0 +1,683 @@
|
|
|
+/**********************************************************************************************
|
|
|
+
|
|
|
+ raylib parser - raylib header parser
|
|
|
+
|
|
|
+ This parser scans raylib.h to get information about structs, enums and functions.
|
|
|
+ All data is separated into parts, usually as strings. The following types are used for data:
|
|
|
+
|
|
|
+ - struct FunctionInfo
|
|
|
+ - struct StructInfo
|
|
|
+ - struct EnumInfo
|
|
|
+
|
|
|
+ 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]> = <valueInt[0]>, <valueDesc[0]>
|
|
|
+ <valueName[1]>,
|
|
|
+ <valueName[2]>, <valueDesc[2]>
|
|
|
+ <valueName[3]> <valueDesc[3]>
|
|
|
+ } <name>;
|
|
|
+
|
|
|
+ NOTE: Multiple options are supported:
|
|
|
+ - If value is not provided, (<valueInt[i -1]> + 1) is assigned
|
|
|
+ - Value description can be provided or not
|
|
|
+
|
|
|
+ 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 Ramon Santamaria (@raysan5)
|
|
|
+
|
|
|
+**********************************************************************************************/
|
|
|
+
|
|
|
+#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
|
|
|
+
|
|
|
+#define MAX_FUNCS_TO_PARSE 512 // Maximum number of functions to parse
|
|
|
+#define MAX_STRUCTS_TO_PARSE 64 // Maximum number of structures to parse
|
|
|
+#define MAX_ENUMS_TO_PARSE 64 // Maximum number of enums to parse
|
|
|
+
|
|
|
+#define MAX_LINE_LENGTH 512 // Maximum length of one line (including comments)
|
|
|
+#define MAX_STRUCT_LINE_LENGTH 2048 // Maximum length of one struct (multiple lines)
|
|
|
+
|
|
|
+//----------------------------------------------------------------------------------
|
|
|
+// Types and Structures Definition
|
|
|
+//----------------------------------------------------------------------------------
|
|
|
+// Function info data
|
|
|
+typedef struct FunctionInfo {
|
|
|
+ char name[64]; // Function name
|
|
|
+ char retType[32]; // Return value type
|
|
|
+ int paramCount; // Number of function parameters
|
|
|
+ char paramType[12][32]; // Parameters type (max: 12 parameters)
|
|
|
+ char paramName[12][32]; // Parameters name (max: 12 parameters)
|
|
|
+ char desc[128]; // Function description (comment at the end)
|
|
|
+} FunctionInfo;
|
|
|
+
|
|
|
+// Struct info data
|
|
|
+typedef struct StructInfo {
|
|
|
+ char name[64]; // Struct name
|
|
|
+ char desc[64]; // Struct type description
|
|
|
+ int fieldCount; // Number of fields in the struct
|
|
|
+ char fieldType[16][32]; // Field type (max: 16 fields)
|
|
|
+ char fieldName[16][32]; // Field name (max: 16 fields)
|
|
|
+ char fieldDesc[16][128]; // Field description (max: 16 fields)
|
|
|
+} StructInfo;
|
|
|
+
|
|
|
+// Enum info data
|
|
|
+typedef struct EnumInfo {
|
|
|
+ char name[64]; // Enum name
|
|
|
+ char desc[64]; // Enum description
|
|
|
+ int valueCount; // Number of values in enumerator
|
|
|
+ char valueName[128][64]; // Value name definition (max: 128 values)
|
|
|
+ int valueInt[128]; // Value integer (max: 128 values)
|
|
|
+} EnumInfo;
|
|
|
+
|
|
|
+//----------------------------------------------------------------------------------
|
|
|
+// Module Functions Declaration
|
|
|
+//----------------------------------------------------------------------------------
|
|
|
+char *LoadFileText(const char *fileName, int *length);
|
|
|
+char **GetTextLines(const char *buffer, int length, int *linesCount);
|
|
|
+void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name);
|
|
|
+bool IsTextEqual(const char *text1, const char *text2, unsigned int count);
|
|
|
+void MemoryCopy(void *dest, const void *src, unsigned int count);
|
|
|
+
|
|
|
+// Main entry point
|
|
|
+int main()
|
|
|
+{
|
|
|
+ int length = 0;
|
|
|
+ char *buffer = LoadFileText("../src/raylib.h", &length);
|
|
|
+
|
|
|
+ // Preprocess buffer to get separate lines
|
|
|
+ // NOTE: GetTextLines() also removes leading spaces/tabs
|
|
|
+ int linesCount = 0;
|
|
|
+ char **lines = GetTextLines(buffer, length, &linesCount);
|
|
|
+
|
|
|
+ // Print buffer lines
|
|
|
+ //for (int i = 0; i < linesCount; i++) printf("_%s_\n", lines[i]);
|
|
|
+
|
|
|
+ // Function lines pointers, selected from buffer "lines"
|
|
|
+ int funcCount = 0;
|
|
|
+ char **funcLines = (char **)malloc(MAX_FUNCS_TO_PARSE*sizeof(char *));
|
|
|
+
|
|
|
+ // Structs data (multiple lines), selected from "buffer"
|
|
|
+ int structCount = 0;
|
|
|
+ char **structLines = (char **)malloc(MAX_STRUCTS_TO_PARSE*sizeof(char *));
|
|
|
+ for (int i = 0; i < MAX_STRUCTS_TO_PARSE; i++) structLines[i] = (char *)calloc(MAX_STRUCT_LINE_LENGTH, sizeof(char));
|
|
|
+
|
|
|
+ // Enums lines pointers, selected from buffer "lines"
|
|
|
+ int enumCount = 0;
|
|
|
+ int *enumLines = (int *)malloc(MAX_ENUMS_TO_PARSE*sizeof(int));
|
|
|
+
|
|
|
+ // Prepare required lines for parsing
|
|
|
+ //--------------------------------------------------------------------------------------------------
|
|
|
+
|
|
|
+ // Read function lines
|
|
|
+ for (int i = 0; i < linesCount; i++)
|
|
|
+ {
|
|
|
+ // Read function line (starting with "RLAPI")
|
|
|
+ if (IsTextEqual(lines[i], "RLAPI", 5))
|
|
|
+ {
|
|
|
+ // Keep a pointer to the function line
|
|
|
+ funcLines[funcCount] = lines[i];
|
|
|
+ funcCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Print function lines
|
|
|
+ //for (int i = 0; i < funcCount; i++) printf("%s\n", funcLines[i]);
|
|
|
+
|
|
|
+ // Read structs data (multiple lines, read directly from buffer)
|
|
|
+ // TODO: Parse structs data from "lines" instead of "buffer" -> Easier to get struct definition
|
|
|
+ for (int i = 0; i < length; i++)
|
|
|
+ {
|
|
|
+ // Read struct data (starting with "typedef struct", ending with '} ... ;')
|
|
|
+ // NOTE: We read it directly from buffer
|
|
|
+ if (IsTextEqual(buffer + i, "typedef struct", 14))
|
|
|
+ {
|
|
|
+ int j = 0;
|
|
|
+ bool validStruct = false;
|
|
|
+
|
|
|
+ // WARNING: Typedefs between types: typedef Vector4 Quaternion;
|
|
|
+
|
|
|
+ for (int c = 0; c < 128; c++)
|
|
|
+ {
|
|
|
+ if (buffer[i + c] == '{')
|
|
|
+ {
|
|
|
+ validStruct = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ else if (buffer[i + j] == ';')
|
|
|
+ {
|
|
|
+ // Not valid struct:
|
|
|
+ // i.e typedef struct rAudioBuffer rAudioBuffer; -> Typedef and forward declaration
|
|
|
+ i += c;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (validStruct)
|
|
|
+ {
|
|
|
+ while (buffer[i + j] != '}')
|
|
|
+ {
|
|
|
+ structLines[structCount][j] = buffer[i + j];
|
|
|
+ j++;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (buffer[i + j] != '}')
|
|
|
+ {
|
|
|
+ structLines[structCount][j] = buffer[i + j];
|
|
|
+ j++;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (buffer[i + j] != '\n')
|
|
|
+ {
|
|
|
+ structLines[structCount][j] = buffer[i + j];
|
|
|
+ j++;
|
|
|
+ }
|
|
|
+
|
|
|
+ i += j;
|
|
|
+ structCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Read enum lines
|
|
|
+ for (int i = 0; i < linesCount; i++)
|
|
|
+ {
|
|
|
+ // Read function line (starting with "RLAPI")
|
|
|
+ if (IsTextEqual(lines[i], "typedef enum {", 14))
|
|
|
+ {
|
|
|
+ // Keep the line position in the array of lines,
|
|
|
+ // so, we can scan that position and following lines
|
|
|
+ enumLines[enumCount] = i;
|
|
|
+ enumCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // At this point we have all raylib structs, enums, functions lines data to start parsing
|
|
|
+
|
|
|
+ free(buffer); // Unload text buffer
|
|
|
+
|
|
|
+ // Parsing raylib data
|
|
|
+ //--------------------------------------------------------------------------------------------------
|
|
|
+
|
|
|
+ // Structs info data
|
|
|
+ StructInfo *structs = (StructInfo *)calloc(MAX_STRUCTS_TO_PARSE, sizeof(StructInfo));
|
|
|
+
|
|
|
+ for (int i = 0; i < structCount; i++)
|
|
|
+ {
|
|
|
+ int structLineOffset = 0;
|
|
|
+
|
|
|
+ // Get struct name: typedef struct name {
|
|
|
+ for (int c = 15; c < 64 + 15; c++)
|
|
|
+ {
|
|
|
+ if (structLines[i][c] == '{')
|
|
|
+ {
|
|
|
+ structLineOffset = c + 2;
|
|
|
+
|
|
|
+ MemoryCopy(structs[i].name, &structLines[i][15], c - 15 - 1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get struct fields and count them -> fields finish with ;
|
|
|
+ int j = 0;
|
|
|
+ while (structLines[i][structLineOffset + j] != '}')
|
|
|
+ {
|
|
|
+ // WARNING: Some structs have empty spaces and comments -> OK, processed
|
|
|
+
|
|
|
+ int fieldStart = 0;
|
|
|
+ if ((structLines[i][structLineOffset + j] != ' ') && (structLines[i][structLineOffset + j] != '\n')) fieldStart = structLineOffset + j;
|
|
|
+
|
|
|
+ if (fieldStart != 0)
|
|
|
+ {
|
|
|
+ // Scan one field line
|
|
|
+ int c = 0;
|
|
|
+ int fieldEndPos = 0;
|
|
|
+ char fieldLine[256] = { 0 };
|
|
|
+
|
|
|
+ while (structLines[i][structLineOffset + j] != '\n')
|
|
|
+ {
|
|
|
+ if (structLines[i][structLineOffset + j] == ';') fieldEndPos = c;
|
|
|
+ fieldLine[c] = structLines[i][structLineOffset + j];
|
|
|
+ c++; j++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fieldLine[0] != '/') // Field line is not a comment
|
|
|
+ {
|
|
|
+ //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
|
|
|
+ // We start skipping spaces in front of description comment
|
|
|
+ int descStart = fieldEndPos;
|
|
|
+ while ((fieldLine[descStart] != '/') && (fieldLine[descStart] != '\0')) descStart++;
|
|
|
+
|
|
|
+ int k = 0;
|
|
|
+ while ((fieldLine[descStart + k] != '\0') && (fieldLine[descStart + k] != '\n'))
|
|
|
+ {
|
|
|
+ structs[i].fieldDesc[structs[i].fieldCount][k] = fieldLine[descStart + k];
|
|
|
+ k++;
|
|
|
+ }
|
|
|
+
|
|
|
+ structs[i].fieldCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ j++;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < MAX_STRUCTS_TO_PARSE; i++) free(structLines[i]);
|
|
|
+ free(structLines);
|
|
|
+
|
|
|
+ // Enum info data
|
|
|
+ EnumInfo *enums = (EnumInfo *)calloc(MAX_ENUMS_TO_PARSE, sizeof(EnumInfo));
|
|
|
+
|
|
|
+ for (int i = 0; i < enumCount; i++)
|
|
|
+ {
|
|
|
+ // TODO: Get enum description from lines[enumLines[i] - 1]
|
|
|
+
|
|
|
+ for (int j = 1; j < 256; 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')
|
|
|
+ {
|
|
|
+ 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].valueInt[enums[i].valueCount] = (int)strtol(integer, NULL, 16);
|
|
|
+ else enums[i].valueInt[enums[i].valueCount] = atoi(integer);
|
|
|
+ }
|
|
|
+ else enums[i].valueInt[enums[i].valueCount] = (enums[i].valueInt[enums[i].valueCount - 1] + 1);
|
|
|
+
|
|
|
+ // TODO: Parse value description if any
|
|
|
+ }
|
|
|
+ else enums[i].valueInt[enums[i].valueCount] = (enums[i].valueInt[enums[i].valueCount - 1] + 1);
|
|
|
+
|
|
|
+ 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
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Functions info data
|
|
|
+ FunctionInfo *funcs = (FunctionInfo *)calloc(MAX_FUNCS_TO_PARSE, sizeof(FunctionInfo));
|
|
|
+
|
|
|
+ for (int i = 0; i < funcCount; i++)
|
|
|
+ {
|
|
|
+ int funcParamsStart = 0;
|
|
|
+ int funcEnd = 0;
|
|
|
+
|
|
|
+ // Get return type and function name from func line
|
|
|
+ for (int c = 0; (c < MAX_LINE_LENGTH) && (funcLines[i][c] != '\n'); c++)
|
|
|
+ {
|
|
|
+ if (funcLines[i][c] == '(') // Starts function parameters
|
|
|
+ {
|
|
|
+ funcParamsStart = c + 1;
|
|
|
+
|
|
|
+ // At this point we have function return type and function name
|
|
|
+ char funcRetTypeName[128] = { 0 };
|
|
|
+ int funcRetTypeNameLen = c - 6; // Substract "RLAPI "
|
|
|
+ MemoryCopy(funcRetTypeName, &funcLines[i][6], 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 (funcLines[i][c] == ',') // Starts function parameters
|
|
|
+ {
|
|
|
+ // Get parameter type + name, extract info
|
|
|
+ char funcParamTypeName[128] = { 0 };
|
|
|
+ int funcParamTypeNameLen = c - funcParamsStart;
|
|
|
+ MemoryCopy(funcParamTypeName, &funcLines[i][funcParamsStart], funcParamTypeNameLen);
|
|
|
+
|
|
|
+ GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]);
|
|
|
+
|
|
|
+ funcParamsStart = c + 1;
|
|
|
+ if (funcLines[i][c + 1] == ' ') funcParamsStart += 1;
|
|
|
+ funcs[i].paramCount++; // Move to next parameter
|
|
|
+ }
|
|
|
+ else if (funcLines[i][c] == ')')
|
|
|
+ {
|
|
|
+ funcEnd = c + 2;
|
|
|
+
|
|
|
+ // Check if previous word is void
|
|
|
+ if ((funcLines[i][c - 4] == 'v') && (funcLines[i][c - 3] == 'o') && (funcLines[i][c - 2] == 'i') && (funcLines[i][c - 1] == 'd')) break;
|
|
|
+
|
|
|
+ // Get parameter type + name, extract info
|
|
|
+ char funcParamTypeName[128] = { 0 };
|
|
|
+ int funcParamTypeNameLen = c - funcParamsStart;
|
|
|
+ MemoryCopy(funcParamTypeName, &funcLines[i][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
|
|
|
+ for (int c = funcEnd; c < MAX_LINE_LENGTH; c++)
|
|
|
+ {
|
|
|
+ if (funcLines[i][c] == '/')
|
|
|
+ {
|
|
|
+ MemoryCopy(funcs[i].desc, &funcLines[i][c], 127); // WARNING: Size could be too long for funcLines[i][c]?
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < linesCount; i++) free(lines[i]);
|
|
|
+ free(lines);
|
|
|
+ free(funcLines);
|
|
|
+
|
|
|
+ // At this point, all raylib data has been parsed!
|
|
|
+ //-----------------------------------------------------------------------------------------
|
|
|
+ // structs[] -> We have all the structs decomposed into pieces for further analysis
|
|
|
+ // enums[] -> We have all the enums decomposed into pieces for further analysis
|
|
|
+ // funcs[] -> We have all the functions decomposed into pieces for further analysis
|
|
|
+
|
|
|
+ // Print structs info
|
|
|
+ printf("\nStructures found: %i\n\n", structCount);
|
|
|
+ for (int i = 0; i < structCount; i++)
|
|
|
+ {
|
|
|
+ printf("Struct %02i: %s (%i fields)\n", i + 1, structs[i].name, structs[i].fieldCount);
|
|
|
+ //printf("Description: %s\n", structs[i].desc);
|
|
|
+ for (int f = 0; f < structs[i].fieldCount; f++) printf(" Fields %i: %s %s %s\n", f + 1, structs[i].fieldType[f], structs[i].fieldName[f], structs[i].fieldDesc[f]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Print enums info
|
|
|
+ printf("\nEnums found: %i\n\n", enumCount);
|
|
|
+ for (int i = 0; i < enumCount; i++)
|
|
|
+ {
|
|
|
+ printf("Enum %02i: %s (%i values)\n", i + 1, enums[i].name, enums[i].valueCount);
|
|
|
+ //printf("Description: %s\n", enums[i].desc);
|
|
|
+ for (int e = 0; e < enums[i].valueCount; e++) printf(" Value %s: %i\n", enums[i].valueName[e], enums[i].valueInt[e]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Print function info
|
|
|
+ printf("\nFunctions found: %i\n\n", funcCount);
|
|
|
+ for (int i = 0; i < funcCount; i++)
|
|
|
+ {
|
|
|
+ printf("Function %03i: %s() (%i input parameters)\n", i + 1, funcs[i].name, funcs[i].paramCount);
|
|
|
+ printf(" Description: %s\n", funcs[i].desc);
|
|
|
+ printf(" Return type: %s\n", funcs[i].retType);
|
|
|
+ for (int p = 0; p < funcs[i].paramCount; p++) printf(" Param %i: %s (type: %s)\n", p + 1, funcs[i].paramName[p], funcs[i].paramType[p]);
|
|
|
+ if (funcs[i].paramCount == 0) printf(" No input parameters\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ free(funcs);
|
|
|
+ free(structs);
|
|
|
+ free(enums);
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------------------
|
|
|
+// Module Functions Definition
|
|
|
+//----------------------------------------------------------------------------------
|
|
|
+
|
|
|
+// Load text data from file, returns a '\0' terminated string
|
|
|
+// NOTE: text chars array should be freed manually
|
|
|
+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)
|
|
|
+ {
|
|
|
+ *length = size;
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ // Zero-terminate the string
|
|
|
+ text[count] = '\0';
|
|
|
+ }
|
|
|
+
|
|
|
+ fclose(file);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return text;
|
|
|
+}
|
|
|
+
|
|
|
+// Get all lines from a text buffer (expecting lines ending with '\n')
|
|
|
+char **GetTextLines(const char *buffer, int length, int *linesCount)
|
|
|
+{
|
|
|
+ //#define MAX_LINE_LENGTH 512
|
|
|
+
|
|
|
+ // 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')
|
|
|
+ {
|
|
|
+ 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
|
|
|
+void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name)
|
|
|
+{
|
|
|
+ for (int k = typeNameLen; k > 0; k--)
|
|
|
+ {
|
|
|
+ if (typeName[k] == ' ')
|
|
|
+ {
|
|
|
+ // 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Custom memcpy() to avoid <string.h>
|
|
|
+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];
|
|
|
+}
|
|
|
+
|
|
|
+// Compare two text strings, requires number of characters to compare
|
|
|
+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;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+// 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)
|
|
|
+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;
|
|
|
+}
|
|
|
+*/
|