|
|
@ -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; |
|
|
|
} |
|
|
|
*/ |