2021-05-30 11:51:15 +02:00
/**********************************************************************************************
2025-10-04 19:39:25 +02:00
rlparser - raylib header API parser , extracts API information as separate tokens
2021-06-13 16:34:51 +02:00
2022-05-04 13:44:55 +02:00
This parser scans raylib . h to get API information about defines , structs , aliases , enums , callbacks and functions .
2021-06-13 16:34:51 +02:00
All data is divided into pieces , usually as strings . The following types are used for data :
2022-05-04 13:44:55 +02:00
- struct DefineInfo
2021-05-30 11:51:15 +02:00
- struct StructInfo
2022-05-01 12:34:15 +02:00
- struct AliasInfo
2021-05-30 11:51:15 +02:00
- struct EnumInfo
2022-05-04 13:44:55 +02:00
- struct FunctionInfo
2025-10-04 19:39:25 +02:00
WARNING : This parser is specifically designed to work with raylib . h , and has some contraints
in that regards . Still , it can also work with other header files that follow same file structure
conventions as raylib . h : rlgl . h , raymath . h , raygui . h , reasings . h
2021-05-30 11:51:15 +02:00
2021-06-13 16:34:51 +02:00
CONSTRAINTS :
This parser is specifically designed to work with raylib . h , so , it has some constraints :
2021-05-30 11:51:15 +02:00
- Functions are expected as a single line with the following structure :
< retType > < name > ( < paramType [ 0 ] > < paramName [ 0 ] > , < paramType [ 1 ] > < paramName [ 1 ] > ) ; < desc >
2025-10-04 19:39:25 +02:00
WARNING : Be careful with functions broken into several lines , it breaks the process !
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
- 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 > ;
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
- Enums are expected as several lines with the following form :
< desc >
typedef enum {
2021-05-31 12:37:03 +02:00
< valueName [ 0 ] > = < valueInteger [ 0 ] > , < valueDesc [ 0 ] >
2021-05-30 11:51:15 +02:00
< valueName [ 1 ] > ,
< valueName [ 2 ] > , < valueDesc [ 2 ] >
< valueName [ 3 ] > < valueDesc [ 3 ] >
} < name > ;
2021-06-13 16:34:51 +02:00
NOTE : Multiple options are supported for enums :
2021-05-31 12:37:03 +02:00
- If value is not provided , ( < valueInteger [ i - 1 ] > + 1 ) is assigned
2021-05-30 11:51:15 +02:00
- Value description can be provided or not
2021-06-13 16:34:51 +02:00
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 .
2021-05-30 11:51:15 +02:00
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 :
2026-01-02 13:40:15 +01:00
Copyright ( c ) 2021 - 2026 Ramon Santamaria ( @ raysan5 )
2021-05-30 11:51:15 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-06-13 16:34:51 +02:00
# define _CRT_SECURE_NO_WARNINGS
2021-05-30 11:51:15 +02:00
# 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
2022-02-03 16:56:00 +03:00
# include <ctype.h> // Required for: isdigit()
2021-05-30 11:51:15 +02:00
2022-05-04 13:44:55 +02:00
# define MAX_DEFINES_TO_PARSE 2048 // Maximum number of defines to parse
2021-05-30 11:51:15 +02:00
# define MAX_STRUCTS_TO_PARSE 64 // Maximum number of structures to parse
2022-05-01 12:34:15 +02:00
# define MAX_ALIASES_TO_PARSE 64 // Maximum number of aliases to parse
2021-05-30 11:51:15 +02:00
# define MAX_ENUMS_TO_PARSE 64 // Maximum number of enums to parse
2022-05-04 13:44:55 +02:00
# define MAX_CALLBACKS_TO_PARSE 64 // Maximum number of callbacks to parse
2023-01-28 00:33:15 +02:00
# define MAX_FUNCS_TO_PARSE 1024 // Maximum number of functions to parse
2021-05-30 11:51:15 +02:00
2024-09-17 10:30:26 +02:00
# define MAX_LINE_LENGTH 1024 // Maximum length of one line (including comments)
2021-05-30 11:51:15 +02:00
2022-05-04 11:06:01 +02:00
# define MAX_STRUCT_FIELDS 64 // Maximum number of struct fields
2021-07-29 21:37:44 +03:00
# define MAX_ENUM_VALUES 512 // Maximum number of enum values
2022-05-04 13:44:55 +02:00
# define MAX_FUNCTION_PARAMETERS 12 // Maximum number of function parameters
2021-07-29 21:37:44 +03:00
2021-05-30 11:51:15 +02:00
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
2022-05-04 13:44:55 +02:00
2025-10-04 20:07:39 +02:00
// Define value type
2022-05-06 20:23:07 +02:00
typedef enum {
UNKNOWN = 0 ,
MACRO ,
GUARD ,
INT ,
INT_MATH ,
LONG ,
LONG_MATH ,
FLOAT ,
FLOAT_MATH ,
DOUBLE ,
DOUBLE_MATH ,
CHAR ,
STRING ,
COLOR
} DefineType ;
2022-05-04 13:44:55 +02:00
// Define info data
typedef struct DefineInfo {
2022-08-02 21:05:31 +02:00
char name [ 64 ] ; // Define name
2025-10-04 20:07:39 +02:00
int type ; // Define type: enum DefineType
2022-08-02 21:05:31 +02:00
char value [ 256 ] ; // Define value
char desc [ 128 ] ; // Define description
bool isHex ; // Define is hex number (for types INT, LONG)
2022-05-04 13:44:55 +02:00
} DefineInfo ;
2021-05-30 11:51:15 +02:00
// Struct info data
typedef struct StructInfo {
char name [ 64 ] ; // Struct name
2021-12-16 15:34:55 +00:00
char desc [ 128 ] ; // Struct type description
2021-05-30 11:51:15 +02:00
int fieldCount ; // Number of fields in the struct
2021-07-29 21:37:44 +03:00
char fieldType [ MAX_STRUCT_FIELDS ] [ 64 ] ; // Field type
char fieldName [ MAX_STRUCT_FIELDS ] [ 64 ] ; // Field name
char fieldDesc [ MAX_STRUCT_FIELDS ] [ 128 ] ; // Field description
2021-05-30 11:51:15 +02:00
} StructInfo ;
2022-05-01 12:34:15 +02:00
// Alias info data
typedef struct AliasInfo {
char type [ 64 ] ; // Alias type
char name [ 64 ] ; // Alias name
char desc [ 128 ] ; // Alias description
} AliasInfo ;
2021-05-30 11:51:15 +02:00
// Enum info data
typedef struct EnumInfo {
char name [ 64 ] ; // Enum name
2021-12-16 15:34:55 +00:00
char desc [ 128 ] ; // Enum description
2021-05-30 11:51:15 +02:00
int valueCount ; // Number of values in enumerator
2021-07-29 21:37:44 +03:00
char valueName [ MAX_ENUM_VALUES ] [ 64 ] ; // Value name definition
int valueInteger [ MAX_ENUM_VALUES ] ; // Value integer
2022-01-05 21:35:01 +01:00
char valueDesc [ MAX_ENUM_VALUES ] [ 128 ] ; // Value description
2021-05-30 11:51:15 +02:00
} EnumInfo ;
2022-05-04 13:44:55 +02:00
// Function info data
typedef struct FunctionInfo {
char name [ 64 ] ; // Function name
2024-09-17 10:30:26 +02:00
char desc [ 512 ] ; // Function description (comment at the end)
2022-05-04 13:44:55 +02:00
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 ;
2022-02-03 16:56:00 +03:00
2021-06-13 16:34:51 +02:00
// Output format for parsed data
2022-08-14 12:56:55 +02:00
typedef enum { DEFAULT = 0 , JSON , XML , LUA , CODE } OutputFormat ;
2021-06-13 16:34:51 +02:00
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
2022-05-04 13:44:55 +02:00
static int defineCount = 0 ;
2021-06-13 16:34:51 +02:00
static int structCount = 0 ;
2022-05-01 12:34:15 +02:00
static int aliasCount = 0 ;
2021-06-13 16:34:51 +02:00
static int enumCount = 0 ;
2022-05-04 13:44:55 +02:00
static int callbackCount = 0 ;
static int funcCount = 0 ;
static DefineInfo * defines = NULL ;
2021-06-13 16:34:51 +02:00
static StructInfo * structs = NULL ;
2022-05-01 12:34:15 +02:00
static AliasInfo * aliases = NULL ;
2021-06-13 16:34:51 +02:00
static EnumInfo * enums = NULL ;
2022-05-04 13:44:55 +02:00
static FunctionInfo * callbacks = NULL ;
static FunctionInfo * funcs = NULL ;
2021-06-13 16:34:51 +02:00
// Command line variables
2022-05-04 13:44:55 +02:00
static char apiDefine [ 32 ] = { 0 } ; // Functions define (i.e. RLAPI for raylib.h, RMDEF for raymath.h, etc.)
2022-05-06 20:18:39 +02:00
static char truncAfter [ 32 ] = { 0 } ; // Truncate marker (i.e. "RLGL IMPLEMENTATION" for rlgl.h)
2021-06-13 16:34:51 +02:00
static int outputFormat = DEFAULT ;
2025-10-04 20:07:39 +02:00
// NOTE: Filename max length depends on OS, in Windows MAX_PATH = 256
2023-09-29 00:28:03 +02:00
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)
2021-05-30 11:51:15 +02:00
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
2021-06-13 16:34:51 +02:00
static void ShowCommandLineInfo ( void ) ; // Show command line usage info
static void ProcessCommandLine ( int argc , char * argv [ ] ) ; // Process command line input
2025-10-04 20:07:39 +02:00
static char * LoadFileText ( const char * fileName , int * length ) ; // Load text file - UnloadFileText() required!
static void UnloadFileText ( char * text ) ; // Unload text data
static char * * LoadTextLines ( const char * buffer , int length , int * lineCount ) ; // Load all lines from a text buffer (expecting lines ending with '\n') - UnloadTextLines() required
static void UnloadTextLines ( char * * lines , int lineCount ) ; // Unload text lines data
static void GetDataTypeAndName ( const char * typeName , int typeNameLen , char * type , char * name ) ; // Get data type and name from a string containing both (i.e function param and struct fields)
static void GetDescription ( const char * source , char * description ) ; // Get description comment from a line, do nothing if no comment in line
2022-05-04 13:44:55 +02:00
static void MoveArraySize ( char * name , char * type ) ; // Move array size from name to type
2021-06-13 16:34:51 +02:00
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 ) ;
2022-05-06 20:18:39 +02:00
static int TextFindIndex ( const char * text , const char * find ) ; // Find first text occurrence within a string
2025-10-04 20:07:39 +02:00
static void MemoryCopy ( void * dest , const void * src , unsigned int count ) ; // Memory copy, memcpy() replacement to avoid <string.h>
2021-12-16 14:59:40 +01:00
static char * EscapeBackslashes ( char * text ) ; // Replace '\' by "\\" when exporting to JSON and XML
2022-02-03 16:56:00 +03:00
static const char * StrDefineType ( DefineType type ) ; // Get string of define type
2022-05-04 13:44:55 +02:00
static void ExportParsedData ( const char * fileName , int format ) ; // Export parsed data in desired format
2022-05-04 11:06:01 +02:00
2022-05-04 13:44:55 +02:00
//----------------------------------------------------------------------------------
2021-06-13 16:34:51 +02:00
// Program main entry point
2022-05-04 13:44:55 +02:00
//----------------------------------------------------------------------------------
2021-06-06 04:21:56 -04:00
int main ( int argc , char * argv [ ] )
2021-05-30 11:51:15 +02:00
{
2021-06-13 16:34:51 +02:00
if ( argc > 1 ) ProcessCommandLine ( argc , argv ) ;
2021-06-06 04:21:56 -04:00
2024-05-29 15:00:28 +05:30
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 ) ;
2021-06-06 04:21:56 -04:00
2021-05-30 11:51:15 +02:00
int length = 0 ;
2021-06-13 16:34:51 +02:00
char * buffer = LoadFileText ( inFileName , & length ) ;
Review parser Makefile (#2765)
* parser: Fail gracefully if a nonexistent file is passed on the command line
Before, if a nonexistent file was passed to LoadFileText(), it would
return NULL, and the parser would happily dereference it.
* parser: Refactor Makefile and update the path to easings.h (now reasings.h)
Before, the `make all` target would simply segfault, see 0a679d79
Now, if a file in the `make all` target doesn't exist, make will write
an error.
Individual API files can be generated likeso, provided the header file
the target depends on exists:
FORMAT=JSON EXTENSION=json make raygui_api.json
In order for the `make all` target to succeed, raygui.h, physac.h and
rmem.h need to be added to the correct directory.
2022-10-20 16:29:03 +01:00
if ( buffer = = NULL )
{
2023-02-15 17:36:31 +01:00
printf ( " Could not read input file: %s \n " , inFileName ) ;
return 1 ;
Review parser Makefile (#2765)
* parser: Fail gracefully if a nonexistent file is passed on the command line
Before, if a nonexistent file was passed to LoadFileText(), it would
return NULL, and the parser would happily dereference it.
* parser: Refactor Makefile and update the path to easings.h (now reasings.h)
Before, the `make all` target would simply segfault, see 0a679d79
Now, if a file in the `make all` target doesn't exist, make will write
an error.
Individual API files can be generated likeso, provided the header file
the target depends on exists:
FORMAT=JSON EXTENSION=json make raygui_api.json
In order for the `make all` target to succeed, raygui.h, physac.h and
rmem.h need to be added to the correct directory.
2022-10-20 16:29:03 +01:00
}
2021-05-30 11:51:15 +02:00
// Preprocess buffer to get separate lines
2025-10-04 20:07:39 +02:00
// NOTE: LoadTextLines() also removes leading spaces/tabs
int lineCount = 0 ;
char * * lines = LoadTextLines ( buffer , length , & lineCount ) ;
2021-06-13 16:34:51 +02:00
2025-10-04 20:07:39 +02:00
// Truncate lines (if required)
2022-05-06 20:18:39 +02:00
if ( truncAfter [ 0 ] ! = ' \0 ' )
{
int newCount = - 1 ;
2025-10-04 20:07:39 +02:00
for ( int i = 0 ; i < lineCount ; i + + )
2022-05-06 20:18:39 +02:00
{
if ( newCount > - 1 ) free ( lines [ i ] ) ;
else if ( TextFindIndex ( lines [ i ] , truncAfter ) > - 1 ) newCount = i ;
}
2025-10-04 20:07:39 +02:00
if ( newCount > - 1 ) lineCount = newCount ;
printf ( " Number of truncated text lines: %i \n " , lineCount ) ;
2022-05-06 20:18:39 +02:00
}
2022-05-04 13:44:55 +02:00
// Defines line indices
int * defineLines = ( int * ) malloc ( MAX_DEFINES_TO_PARSE * sizeof ( int ) ) ;
2021-05-30 11:51:15 +02:00
2022-05-04 11:06:01 +02:00
// Structs line indices
2021-12-16 15:34:55 +00:00
int * structLines = ( int * ) malloc ( MAX_STRUCTS_TO_PARSE * sizeof ( int ) ) ;
2021-06-13 16:34:51 +02:00
2022-05-04 11:06:01 +02:00
// Aliases line indices
2022-05-01 12:34:15 +02:00
int * aliasLines = ( int * ) malloc ( MAX_ALIASES_TO_PARSE * sizeof ( int ) ) ;
2022-05-04 11:06:01 +02:00
// Enums line indices
2021-05-30 11:51:15 +02:00
int * enumLines = ( int * ) malloc ( MAX_ENUMS_TO_PARSE * sizeof ( int ) ) ;
2021-06-13 16:34:51 +02:00
2022-05-04 13:44:55 +02:00
// Callbacks line indices
int * callbackLines = ( int * ) malloc ( MAX_CALLBACKS_TO_PARSE * sizeof ( int ) ) ;
2022-02-03 16:56:00 +03:00
2022-05-04 13:44:55 +02:00
// Function line indices
int * funcLines = ( int * ) malloc ( MAX_FUNCS_TO_PARSE * sizeof ( int ) ) ;
2021-06-13 16:34:51 +02:00
2022-05-04 13:44:55 +02:00
// Prepare required lines for parsing
//----------------------------------------------------------------------------------
// Read define lines
2025-10-04 20:07:39 +02:00
for ( int i = 0 ; i < lineCount ; i + + )
2021-05-30 11:51:15 +02:00
{
2022-05-04 13:44:55 +02:00
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 ) )
2021-05-30 11:51:15 +02:00
{
2022-05-04 13:44:55 +02:00
// Keep the line position in the array of lines,
// so, we can scan that position and following lines
defineLines [ defineCount ] = i ;
defineCount + + ;
2022-05-04 11:06:01 +02:00
}
}
// Read struct lines
2025-10-04 20:07:39 +02:00
for ( int i = 0 ; i < lineCount ; i + + )
2022-05-04 11:06:01 +02:00
{
// 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 + + )
2021-05-30 11:51:15 +02:00
{
2022-05-04 11:06:01 +02:00
char v = lines [ i ] [ c ] ;
if ( v = = ' { ' ) validStruct = true ;
if ( ( v = = ' { ' ) | | ( v = = ' ; ' ) | | ( v = = ' \0 ' ) ) break ;
2021-05-30 11:51:15 +02:00
}
}
2021-12-16 15:34:55 +00:00
if ( ! validStruct ) continue ;
structLines [ structCount ] = i ;
while ( lines [ i ] [ 0 ] ! = ' } ' ) i + + ;
while ( lines [ i ] [ 0 ] ! = ' \0 ' ) i + + ;
structCount + + ;
2021-05-30 11:51:15 +02:00
}
}
2021-06-13 16:34:51 +02:00
2022-05-01 12:34:15 +02:00
// Read alias lines
2025-10-04 20:07:39 +02:00
for ( int i = 0 ; i < lineCount ; i + + )
2022-05-01 12:34:15 +02:00
{
// 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 + + ;
2022-05-04 11:06:01 +02:00
if ( ( v = = ' ; ' ) & & ( spaceCount = = 2 ) ) validAlias = true ;
if ( ( v = = ' ; ' ) | | ( v = = ' ( ' ) | | ( v = = ' \0 ' ) ) break ;
2022-05-01 12:34:15 +02:00
}
if ( ! validAlias ) continue ;
aliasLines [ aliasCount ] = i ;
aliasCount + + ;
}
}
2021-05-30 11:51:15 +02:00
// Read enum lines
2025-10-04 20:07:39 +02:00
for ( int i = 0 ; i < lineCount ; i + + )
2021-05-30 11:51:15 +02:00
{
2021-07-29 21:37:44 +03:00
// Read enum line
2022-05-04 11:06:01 +02:00
if ( IsTextEqual ( lines [ i ] , " typedef enum { " , 14 ) & & ( lines [ i ] [ TextLength ( lines [ i ] ) - 1 ] ! = ' ; ' ) ) // ignore inline enums
2021-05-30 11:51:15 +02:00
{
// Keep the line position in the array of lines,
// so, we can scan that position and following lines
enumLines [ enumCount ] = i ;
enumCount + + ;
}
}
2021-06-13 16:34:51 +02:00
2022-05-04 13:44:55 +02:00
// Read callback lines
2025-10-04 20:07:39 +02:00
for ( int i = 0 ; i < lineCount ; i + + )
2022-02-03 16:56:00 +03:00
{
2022-05-04 13:44:55 +02:00
// Find callbacks (lines with "typedef ... (* ... )( ... );")
if ( IsTextEqual ( lines [ i ] , " typedef " , 7 ) )
2022-02-03 16:56:00 +03:00
{
2022-05-04 13:44:55 +02:00
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
2025-10-04 20:07:39 +02:00
for ( int i = 0 ; i < lineCount ; i + + )
2022-05-04 13:44:55 +02:00
{
// Read function line (starting with `define`, i.e. for raylib.h "RLAPI")
if ( IsTextEqual ( lines [ i ] , apiDefine , TextLength ( apiDefine ) ) )
{
funcLines [ funcCount ] = i ;
funcCount + + ;
2022-02-03 16:56:00 +03:00
}
}
2022-05-04 13:44:55 +02:00
// At this point we have all raylib defines, structs, aliases, enums, callbacks, functions lines data to start parsing
2021-06-13 16:34:51 +02:00
2025-10-04 20:07:39 +02:00
UnloadFileText ( buffer ) ; // Unload text buffer
2021-05-30 11:51:15 +02:00
// Parsing raylib data
2022-05-04 13:44:55 +02:00
//----------------------------------------------------------------------------------
// Define info data
int defineIndex = 0 ;
2025-10-04 20:07:39 +02:00
defines = ( DefineInfo * ) calloc ( MAX_DEFINES_TO_PARSE , sizeof ( DefineInfo ) ) ;
2021-06-13 16:34:51 +02:00
2022-05-04 13:44:55 +02:00
for ( int i = 0 ; i < defineCount ; i + + )
2021-05-30 11:51:15 +02:00
{
2022-05-04 13:44:55 +02:00
char * linePtr = lines [ defineLines [ i ] ] ;
int j = 0 ;
2021-05-30 11:51:15 +02:00
2022-05-04 13:44:55 +02:00
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 "
2021-12-16 13:49:17 +00:00
2022-05-04 13:44:55 +02:00
// Extract name
int defineNameStart = j ;
int openBraces = 0 ;
while ( linePtr [ j ] ! = ' \0 ' )
2021-05-30 11:51:15 +02:00
{
2022-05-04 13:44:55 +02:00
if ( ( ( linePtr [ j ] = = ' ' ) | | ( linePtr [ j ] = = ' \t ' ) ) & & ( openBraces = = 0 ) ) break ;
if ( linePtr [ j ] = = ' ( ' ) openBraces + + ;
if ( linePtr [ j ] = = ' ) ' ) openBraces - - ;
j + + ;
2021-05-30 11:51:15 +02:00
}
2022-05-04 13:44:55 +02:00
int defineNameEnd = j - 1 ;
2021-06-13 16:34:51 +02:00
2022-05-04 13:44:55 +02:00
// Skip duplicates
2022-08-02 21:17:19 +02:00
unsigned int nameLen = defineNameEnd - defineNameStart + 1 ;
2022-05-04 13:44:55 +02:00
bool isDuplicate = false ;
for ( int k = 0 ; k < defineIndex ; k + + )
2021-05-30 11:51:15 +02:00
{
2022-05-04 13:44:55 +02:00
if ( ( nameLen = = TextLength ( defines [ k ] . name ) ) & & IsTextEqual ( defines [ k ] . name , & linePtr [ defineNameStart ] , nameLen ) )
2021-05-30 11:51:15 +02:00
{
2022-05-04 13:44:55 +02:00
isDuplicate = true ;
break ;
}
}
if ( isDuplicate ) continue ;
2021-06-13 16:34:51 +02:00
2022-05-04 13:44:55 +02:00
MemoryCopy ( defines [ defineIndex ] . name , & linePtr [ defineNameStart ] , nameLen ) ;
2021-06-13 16:34:51 +02:00
2022-05-04 13:44:55 +02:00
// Determine type
if ( linePtr [ defineNameEnd ] = = ' ) ' ) defines [ defineIndex ] . type = MACRO ;
2021-05-30 11:51:15 +02:00
2022-05-04 13:44:55 +02:00
while ( ( linePtr [ j ] = = ' ' ) | | ( linePtr [ j ] = = ' \t ' ) ) j + + ; // Skip spaces and tabs after name
2022-05-01 12:34:15 +02:00
2022-05-04 13:44:55 +02:00
int defineValueStart = j ;
2022-08-02 21:17:19 +02:00
if ( ( linePtr [ j ] = = ' \0 ' ) | | ( linePtr [ j ] = = ' / ' ) ) defines [ defineIndex ] . type = GUARD ;
2022-05-04 13:44:55 +02:00
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 )
{
2023-10-08 18:10:05 +02:00
defines [ defineIndex ] . type = ( linePtr [ j - 1 ] = = ' f ' ) ? FLOAT : DOUBLE ;
2022-05-04 13:44:55 +02:00
}
else
{
2023-10-08 18:10:05 +02:00
defines [ defineIndex ] . type = ( linePtr [ j - 1 ] = = ' L ' ) ? LONG : INT ;
2022-05-04 13:44:55 +02:00
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 ) ;
}
2022-05-06 20:23:07 +02:00
// Parse defines of type UNKNOWN to find calculated numbers
if ( defines [ defineIndex ] . type = = UNKNOWN )
{
2022-08-02 21:17:19 +02:00
int largestType = UNKNOWN ;
2022-05-06 20:23:07 +02:00
bool isMath = true ;
char * valuePtr = defines [ defineIndex ] . value ;
2022-08-02 21:17:19 +02:00
for ( unsigned int c = 0 ; c < TextLength ( valuePtr ) ; c + + )
2022-05-06 20:23:07 +02:00
{
char ch = valuePtr [ c ] ;
// Skip operators and whitespace
if ( ( ch = = ' ( ' ) | |
( ch = = ' ) ' ) | |
( ch = = ' + ' ) | |
( ch = = ' - ' ) | |
( ch = = ' * ' ) | |
( ch = = ' / ' ) | |
( ch = = ' ' ) | |
( ch = = ' \t ' ) ) continue ;
2023-09-29 00:28:03 +02:00
2022-05-06 20:23:07 +02:00
// 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
2022-08-02 21:17:19 +02:00
int numberType ;
2023-10-08 18:11:55 +02:00
if ( isFloat ) numberType = ( valuePtr [ c - 1 ] = = ' f ' ) ? FLOAT_MATH : DOUBLE_MATH ;
else numberType = ( valuePtr [ c - 1 ] = = ' L ' ) ? LONG_MATH : INT_MATH ;
2023-09-29 00:28:03 +02:00
2022-05-06 20:23:07 +02:00
if ( numberType > largestType ) largestType = numberType ;
}
else
{
isMath = false ;
break ;
}
}
2022-08-02 21:17:19 +02:00
else // Read string operand
2022-05-06 20:23:07 +02:00
{
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 ;
}
}
2022-05-04 13:44:55 +02:00
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 ;
2022-08-02 21:17:19 +02:00
for ( unsigned int c = 0 ; c < TextLength ( structs [ i ] . fieldName [ originalIndex ] ) ; c + + )
2022-05-04 13:44:55 +02:00
{
if ( structs [ i ] . fieldName [ originalIndex ] [ c ] = = ' , ' ) additionalFields + + ;
}
2023-09-29 00:28:03 +02:00
2022-05-04 13:44:55 +02:00
if ( additionalFields > 0 )
{
int originalLength = - 1 ;
int lastStart ;
2022-08-02 21:17:19 +02:00
for ( unsigned int c = 0 ; c < TextLength ( structs [ i ] . fieldName [ originalIndex ] ) + 1 ; c + + )
2022-05-04 13:44:55 +02:00
{
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
2022-05-04 11:06:01 +02:00
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 ;
}
2022-05-01 12:34:15 +02:00
}
2022-05-04 11:06:01 +02:00
}
// 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 ;
2022-08-02 21:17:19 +02:00
for ( unsigned int c = 0 ; c < TextLength ( structs [ i ] . fieldType [ originalIndex ] ) ; c + + )
2022-05-04 11:06:01 +02:00
{
if ( structs [ i ] . fieldType [ originalIndex ] [ c ] = = ' , ' ) additionalFields + + ;
}
2023-09-29 00:28:03 +02:00
2022-08-02 21:17:19 +02:00
if ( additionalFields > 0 )
{
2022-05-04 11:06:01 +02:00
// 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 = = ' , ' ) )
2022-05-01 12:34:15 +02:00
{
2022-05-04 11:06:01 +02:00
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 - - ;
}
2022-05-01 12:34:15 +02:00
}
2022-05-04 11:06:01 +02:00
else if ( nameEnd = = - 1 ) nameEnd = k ;
}
2022-05-01 12:34:15 +02:00
2022-05-04 11:06:01 +02:00
// 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 ] ) ) ;
2022-05-01 12:34:15 +02:00
}
}
2021-05-30 11:51:15 +02:00
}
}
2021-12-16 15:34:55 +00:00
l + + ;
2021-05-30 11:51:15 +02:00
}
2022-05-04 11:06:01 +02:00
// 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 ] ) ;
}
2021-05-30 11:51:15 +02:00
}
free ( structLines ) ;
2021-06-13 16:34:51 +02:00
2022-05-01 12:34:15 +02:00
// Alias info data
aliases = ( AliasInfo * ) calloc ( MAX_ALIASES_TO_PARSE , sizeof ( AliasInfo ) ) ;
for ( int i = 0 ; i < aliasCount ; i + + )
{
// Description from previous line
2022-05-04 11:06:01 +02:00
GetDescription ( lines [ aliasLines [ i ] - 1 ] , aliases [ i ] . desc ) ;
2022-05-01 12:34:15 +02:00
char * linePtr = lines [ aliasLines [ i ] ] ;
// Skip "typedef "
int c = 8 ;
// Type
int typeStart = c ;
while ( linePtr [ c ] ! = ' ' ) c + + ;
int typeLen = c - typeStart ;
2022-05-04 11:06:01 +02:00
MemoryCopy ( aliases [ i ] . type , & linePtr [ typeStart ] , typeLen ) ;
2022-05-01 12:34:15 +02:00
// Skip space
c + + ;
// Name
int nameStart = c ;
while ( linePtr [ c ] ! = ' ; ' ) c + + ;
int nameLen = c - nameStart ;
2022-05-04 11:06:01 +02:00
MemoryCopy ( aliases [ i ] . name , & linePtr [ nameStart ] , nameLen ) ;
2022-05-01 12:34:15 +02:00
// Description
2022-05-04 11:06:01 +02:00
GetDescription ( & linePtr [ c ] , aliases [ i ] . desc ) ;
2022-05-01 12:34:15 +02:00
}
free ( aliasLines ) ;
2021-05-30 11:51:15 +02:00
// Enum info data
2021-06-13 16:34:51 +02:00
enums = ( EnumInfo * ) calloc ( MAX_ENUMS_TO_PARSE , sizeof ( EnumInfo ) ) ;
2021-05-30 11:51:15 +02:00
for ( int i = 0 ; i < enumCount ; i + + )
{
2021-12-16 13:49:17 +00:00
// 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 ] ! = ' ' ) )
{
2022-05-04 11:06:01 +02:00
GetDescription ( & lines [ j + 1 ] [ 0 ] , enums [ i ] . desc ) ;
2021-12-16 13:49:17 +00:00
break ;
}
}
2021-06-13 16:34:51 +02:00
2021-07-29 21:37:44 +03:00
for ( int j = 1 ; j < MAX_ENUM_VALUES * 2 ; j + + ) // Maximum number of lines following enum first line
2021-05-30 11:51:15 +02:00
{
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
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
// We start reading the value name
int c = 0 ;
2021-06-13 16:34:51 +02:00
while ( ( linePtr [ c ] ! = ' , ' ) & &
( linePtr [ c ] ! = ' ' ) & &
2021-05-30 11:51:15 +02:00
( linePtr [ c ] ! = ' = ' ) & &
2022-05-01 12:34:15 +02:00
( linePtr [ c ] ! = ' \0 ' ) )
{
enums [ i ] . valueName [ enums [ i ] . valueCount ] [ c ] = linePtr [ c ] ;
c + + ;
}
2021-05-30 11:51:15 +02:00
2021-06-13 16:34:51 +02:00
// After the name we can have:
2021-05-30 11:51:15 +02:00
// '=' -> 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
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
// 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 ;
2021-12-16 13:49:17 +00:00
while ( ( linePtr [ c ] ! = ' \0 ' ) & & ( linePtr [ c ] ! = ' / ' ) )
2021-05-30 11:51:15 +02:00
{
2022-05-01 12:34:15 +02:00
if ( linePtr [ c ] = = ' = ' )
{
foundValue = true ;
break ;
}
2021-05-30 11:51:15 +02:00
c + + ;
}
if ( foundValue )
{
if ( linePtr [ c + 1 ] = = ' ' ) c + = 2 ;
else c + + ;
2022-03-17 10:52:13 +00:00
2021-05-30 11:51:15 +02:00
// Parse integer value
int n = 0 ;
char integer [ 16 ] = { 0 } ;
2022-03-17 10:52:13 +00:00
2021-06-13 16:34:51 +02:00
while ( ( linePtr [ c ] ! = ' , ' ) & & ( linePtr [ c ] ! = ' ' ) & & ( linePtr [ c ] ! = ' \0 ' ) )
2021-05-30 11:51:15 +02:00
{
integer [ n ] = linePtr [ c ] ;
c + + ; n + + ;
}
2022-03-17 10:52:13 +00:00
2021-05-31 12:37:03 +02:00
if ( integer [ 1 ] = = ' x ' ) enums [ i ] . valueInteger [ enums [ i ] . valueCount ] = ( int ) strtol ( integer , NULL , 16 ) ;
else enums [ i ] . valueInteger [ enums [ i ] . valueCount ] = atoi ( integer ) ;
2021-05-30 11:51:15 +02:00
}
2021-05-31 12:37:03 +02:00
else enums [ i ] . valueInteger [ enums [ i ] . valueCount ] = ( enums [ i ] . valueInteger [ enums [ i ] . valueCount - 1 ] + 1 ) ;
2021-05-30 11:51:15 +02:00
}
2021-05-31 12:37:03 +02:00
else enums [ i ] . valueInteger [ enums [ i ] . valueCount ] = ( enums [ i ] . valueInteger [ enums [ i ] . valueCount - 1 ] + 1 ) ;
2021-05-30 11:51:15 +02:00
2022-05-04 11:06:01 +02:00
// Parse value description
GetDescription ( & linePtr [ c ] , enums [ i ] . valueDesc [ enums [ i ] . valueCount ] ) ;
2021-12-16 13:49:17 +00:00
2021-05-30 11:51:15 +02:00
enums [ i ] . valueCount + + ;
}
2021-06-13 16:34:51 +02:00
else if ( linePtr [ 0 ] = = ' } ' )
2021-05-30 11:51:15 +02:00
{
// Get enum name from typedef
int c = 0 ;
2022-05-01 12:34:15 +02:00
while ( linePtr [ 2 + c ] ! = ' ; ' )
{
enums [ i ] . name [ c ] = linePtr [ 2 + c ] ;
c + + ;
}
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
break ; // Enum ended, break for() loop
}
}
}
2021-11-13 09:40:35 -08:00
free ( enumLines ) ;
2022-05-04 13:44:55 +02:00
// Callback info data
callbacks = ( FunctionInfo * ) calloc ( MAX_CALLBACKS_TO_PARSE , sizeof ( FunctionInfo ) ) ;
2022-02-03 16:56:00 +03:00
2022-05-04 13:44:55 +02:00
for ( int i = 0 ; i < callbackCount ; i + + )
2022-02-03 16:56:00 +03:00
{
2022-05-04 13:44:55 +02:00
char * linePtr = lines [ callbackLines [ i ] ] ;
2022-02-03 16:56:00 +03:00
2022-05-04 13:44:55 +02:00
// Skip "typedef "
2022-08-02 21:17:19 +02:00
unsigned int c = 8 ;
2022-02-03 16:56:00 +03:00
2022-05-04 13:44:55 +02:00
// 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 ) ;
2022-02-03 16:56:00 +03:00
2022-05-04 13:44:55 +02:00
// Skip "(*"
c + = 2 ;
2022-02-03 16:56:00 +03:00
2022-05-04 13:44:55 +02:00
// Name
int nameStart = c ;
while ( linePtr [ c ] ! = ' ) ' ) c + + ;
int nameLen = c - nameStart ;
MemoryCopy ( callbacks [ i ] . name , & linePtr [ nameStart ] , nameLen ) ;
2022-02-03 16:56:00 +03:00
2022-05-04 13:44:55 +02:00
// Skip ")("
c + = 2 ;
2022-02-03 16:56:00 +03:00
2022-05-04 13:44:55 +02:00
// Params
int paramStart = c ;
2022-08-02 21:17:19 +02:00
for ( ; c < MAX_LINE_LENGTH ; c + + )
2022-05-01 12:34:15 +02:00
{
2022-05-04 13:44:55 +02:00
if ( ( linePtr [ c ] = = ' , ' ) | | ( linePtr [ c ] = = ' ) ' ) )
2022-05-01 12:34:15 +02:00
{
2022-05-04 13:44:55 +02:00
// 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 + + ;
2022-02-03 16:56:00 +03:00
}
2022-05-04 13:44:55 +02:00
if ( linePtr [ c ] = = ' ) ' ) break ;
2022-02-03 16:56:00 +03:00
}
2022-05-04 13:44:55 +02:00
// Description
GetDescription ( & linePtr [ c ] , callbacks [ i ] . desc ) ;
2022-02-03 16:56:00 +03:00
2022-05-04 13:44:55 +02:00
// Move array sizes from name to type
for ( int j = 0 ; j < callbacks [ i ] . paramCount ; j + + )
2022-05-01 12:34:15 +02:00
{
2022-05-04 13:44:55 +02:00
MoveArraySize ( callbacks [ i ] . paramName [ j ] , callbacks [ i ] . paramType [ j ] ) ;
2022-02-03 16:56:00 +03:00
}
}
2022-05-04 13:44:55 +02:00
free ( callbackLines ) ;
2022-02-03 16:56:00 +03:00
2021-05-30 11:51:15 +02:00
// Functions info data
2021-06-13 16:34:51 +02:00
funcs = ( FunctionInfo * ) calloc ( MAX_FUNCS_TO_PARSE , sizeof ( FunctionInfo ) ) ;
2021-05-30 11:51:15 +02:00
for ( int i = 0 ; i < funcCount ; i + + )
{
2022-05-04 11:06:01 +02:00
char * linePtr = lines [ funcLines [ i ] ] ;
2021-05-30 11:51:15 +02:00
int funcParamsStart = 0 ;
int funcEnd = 0 ;
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
// Get return type and function name from func line
2022-05-04 11:06:01 +02:00
for ( int c = 0 ; ( c < MAX_LINE_LENGTH ) & & ( linePtr [ c ] ! = ' \n ' ) ; c + + )
2021-05-30 11:51:15 +02:00
{
2022-05-04 11:06:01 +02:00
if ( linePtr [ c ] = = ' ( ' ) // Starts function parameters
2021-05-30 11:51:15 +02:00
{
funcParamsStart = c + 1 ;
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
// At this point we have function return type and function name
char funcRetTypeName [ 128 ] = { 0 } ;
2021-07-29 21:37:44 +03:00
int dc = TextLength ( apiDefine ) + 1 ;
int funcRetTypeNameLen = c - dc ; // Substract `define` ("RLAPI " for raylib.h)
2022-05-04 11:06:01 +02:00
MemoryCopy ( funcRetTypeName , & linePtr [ dc ] , funcRetTypeNameLen ) ;
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
GetDataTypeAndName ( funcRetTypeName , funcRetTypeNameLen , funcs [ i ] . retType , funcs [ i ] . name ) ;
break ;
}
}
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
// Get parameters from func line
for ( int c = funcParamsStart ; c < MAX_LINE_LENGTH ; c + + )
{
2022-05-04 11:06:01 +02:00
if ( linePtr [ c ] = = ' , ' ) // Starts function parameters
2021-05-30 11:51:15 +02:00
{
// Get parameter type + name, extract info
char funcParamTypeName [ 128 ] = { 0 } ;
int funcParamTypeNameLen = c - funcParamsStart ;
2022-05-04 11:06:01 +02:00
MemoryCopy ( funcParamTypeName , & linePtr [ funcParamsStart ] , funcParamTypeNameLen ) ;
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
GetDataTypeAndName ( funcParamTypeName , funcParamTypeNameLen , funcs [ i ] . paramType [ funcs [ i ] . paramCount ] , funcs [ i ] . paramName [ funcs [ i ] . paramCount ] ) ;
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
funcParamsStart = c + 1 ;
2022-05-04 11:06:01 +02:00
if ( linePtr [ c + 1 ] = = ' ' ) funcParamsStart + = 1 ;
2021-05-30 11:51:15 +02:00
funcs [ i ] . paramCount + + ; // Move to next parameter
}
2022-05-04 11:06:01 +02:00
else if ( linePtr [ c ] = = ' ) ' )
2021-05-30 11:51:15 +02:00
{
funcEnd = c + 2 ;
2021-06-13 16:34:51 +02:00
2024-05-13 03:33:09 +05:00
// 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 ;
}
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
// Get parameter type + name, extract info
char funcParamTypeName [ 128 ] = { 0 } ;
int funcParamTypeNameLen = c - funcParamsStart ;
2022-05-04 11:06:01 +02:00
MemoryCopy ( funcParamTypeName , & linePtr [ funcParamsStart ] , funcParamTypeNameLen ) ;
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
GetDataTypeAndName ( funcParamTypeName , funcParamTypeNameLen , funcs [ i ] . paramType [ funcs [ i ] . paramCount ] , funcs [ i ] . paramName [ funcs [ i ] . paramCount ] ) ;
funcs [ i ] . paramCount + + ; // Move to next parameter
break ;
}
}
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
// Get function description
2022-05-04 11:06:01 +02:00
GetDescription ( & linePtr [ funcEnd ] , funcs [ i ] . desc ) ;
// Move array sizes from name to type
for ( int j = 0 ; j < funcs [ i ] . paramCount ; j + + )
2021-05-30 11:51:15 +02:00
{
2022-05-04 11:06:01 +02:00
MoveArraySize ( funcs [ i ] . paramName [ j ] , funcs [ i ] . paramType [ j ] ) ;
2021-05-30 11:51:15 +02:00
}
}
2022-05-04 11:06:01 +02:00
free ( funcLines ) ;
2021-06-13 16:34:51 +02:00
2025-10-04 20:07:39 +02:00
UnloadTextLines ( lines , lineCount ) ;
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
// At this point, all raylib data has been parsed!
2022-05-04 13:44:55 +02:00
//----------------------------------------------------------------------------------
// defines[] -> We have all the defines decomposed into pieces for further analysis
2022-05-04 11:06:01 +02:00
// 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
2022-05-04 13:44:55 +02:00
// funcs[] -> We have all the functions decomposed into pieces for further analysis
2021-06-06 04:21:56 -04:00
2025-10-04 20:16:16 +02:00
// Export data as required
// NOTE: We are exporting data in several common formats (JSON, XML, LUA...) for convenience
// but this data can be directly used to create bindings for other languages modifying this
// small parser for every binding need, there is no need to use (and re-parse) the
// generated files... despite it seems that's the usual approach...
2021-06-13 16:34:51 +02:00
printf ( " \n Input file: %s " , inFileName ) ;
printf ( " \n Output file: %s " , outFileName ) ;
if ( outputFormat = = DEFAULT ) printf ( " \n Output format: DEFAULT \n \n " ) ;
else if ( outputFormat = = JSON ) printf ( " \n Output format: JSON \n \n " ) ;
else if ( outputFormat = = XML ) printf ( " \n Output format: XML \n \n " ) ;
2021-11-11 20:12:30 +03:00
else if ( outputFormat = = LUA ) printf ( " \n Output format: LUA \n \n " ) ;
2022-08-05 20:00:58 +02:00
else if ( outputFormat = = CODE ) printf ( " \n Output format: CODE \n \n " ) ;
2021-06-06 04:21:56 -04:00
2021-06-13 16:34:51 +02:00
ExportParsedData ( outFileName , outputFormat ) ;
2021-06-06 04:21:56 -04:00
2022-05-04 13:44:55 +02:00
free ( defines ) ;
2021-05-30 11:51:15 +02:00
free ( structs ) ;
2022-05-01 12:34:15 +02:00
free ( aliases ) ;
2021-05-30 11:51:15 +02:00
free ( enums ) ;
2022-05-04 13:44:55 +02:00
free ( callbacks ) ;
free ( funcs ) ;
2021-05-30 11:51:15 +02:00
}
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
2021-06-13 16:34:51 +02:00
// Show command line usage info
static void ShowCommandLineInfo ( void )
{
printf ( " \n ////////////////////////////////////////////////////////////////////////////////// \n " ) ;
printf ( " // // \n " ) ;
2025-10-04 20:16:16 +02:00
printf ( " // rlparser - raylib header API parser // \n " ) ;
2021-06-13 16:34:51 +02:00
printf ( " // // \n " ) ;
2025-10-04 20:16:16 +02:00
printf ( " // more info and bugs-report: github.com/raysan5/raylib/tools/rlparser // \n " ) ;
2021-06-13 16:34:51 +02:00
printf ( " // // \n " ) ;
2026-01-02 13:40:15 +01:00
printf ( " // Copyright (c) 2021-2026 Ramon Santamaria (@raysan5) // \n " ) ;
2021-06-13 16:34:51 +02:00
printf ( " // // \n " ) ;
printf ( " ////////////////////////////////////////////////////////////////////////////////// \n \n " ) ;
printf ( " USAGE: \n \n " ) ;
2025-10-04 20:16:16 +02:00
printf ( " > rlparser [--help] [--input <filename.h>] [--output <filename.ext>] [--format <type>] \n " ) ;
2021-06-13 16:34:51 +02:00
printf ( " \n OPTIONS: \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 " ) ;
2022-08-05 20:00:58 +02:00
printf ( " Supported extensions: .txt, .json, .xml, .lua, .h \n " ) ;
2021-06-13 16:34:51 +02:00
printf ( " NOTE: If not specified, defaults to: raylib_api.txt \n \n " ) ;
printf ( " -f, --format <type> : Define output format for parser data. \n " ) ;
2022-08-05 20:00:58 +02:00
printf ( " Supported types: DEFAULT, JSON, XML, LUA, CODE \n \n " ) ;
2024-06-22 18:16:36 +01:00
printf ( " -d, --define <DEF> : Define functions specifiers (i.e. RLAPI for raylib.h, RMAPI for raymath.h, etc.) \n " ) ;
2022-08-02 21:10:35 +02:00
printf ( " NOTE: If no specifier defined, defaults to: RLAPI \n \n " ) ;
2022-05-06 20:18:39 +02:00
printf ( " -t, --truncate <after> : Define string to truncate input after (i.e. \" RLGL IMPLEMENTATION \" for rlgl.h) \n " ) ;
2022-08-02 21:10:35 +02:00
printf ( " NOTE: If not specified, the full input file is parsed. \n \n " ) ;
2021-06-13 16:34:51 +02:00
printf ( " \n EXAMPLES: \n \n " ) ;
2025-10-04 20:16:16 +02:00
printf ( " > rlparser --input raylib.h --output api.json \n " ) ;
2021-06-13 16:34:51 +02:00
printf ( " Process <raylib.h> to generate <api.json> \n \n " ) ;
2025-10-04 20:16:16 +02:00
printf ( " > rlparser --output raylib_data.info --format XML \n " ) ;
2021-06-13 16:34:51 +02:00
printf ( " Process <raylib.h> to generate <raylib_data.info> as XML text data \n \n " ) ;
2025-10-04 20:16:16 +02:00
printf ( " > rlparser --input raymath.h --output raymath_data.info --format XML --define RMAPI \n " ) ;
2021-07-29 21:37:44 +03:00
printf ( " Process <raymath.h> to generate <raymath_data.info> as XML text data \n \n " ) ;
2021-06-13 16:34:51 +02:00
}
// 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 ( ) ;
2022-05-04 13:44:55 +02:00
exit ( 0 ) ;
2021-06-13 16:34:51 +02:00
}
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 ;
2021-11-11 20:12:30 +03:00
else if ( IsTextEqual ( argv [ i + 1 ] , " LUA \0 " , 4 ) ) outputFormat = LUA ;
2022-08-05 20:00:58 +02:00
else if ( IsTextEqual ( argv [ i + 1 ] , " CODE \0 " , 4 ) ) outputFormat = CODE ;
2021-06-13 16:34:51 +02:00
}
else printf ( " WARNING: No format parameters provided \n " ) ;
}
2021-07-29 21:37:44 +03:00
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 " ) ;
}
2022-05-06 20:18:39 +02:00
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 + + ;
}
}
2021-06-13 16:34:51 +02:00
}
}
2021-05-30 11:51:15 +02:00
// Load text data from file, returns a '\0' terminated string
// NOTE: text chars array should be freed manually
2021-06-13 16:34:51 +02:00
static char * LoadFileText ( const char * fileName , int * length )
2021-05-30 11:51:15 +02:00
{
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
2021-06-13 16:34:51 +02:00
if ( count < ( unsigned int ) size )
{
text = realloc ( text , count + 1 ) ;
* length = count ;
}
else * length = size ;
2021-05-30 11:51:15 +02:00
// Zero-terminate the string
text [ count ] = ' \0 ' ;
}
fclose ( file ) ;
}
}
return text ;
}
2025-10-04 20:07:39 +02:00
// Unload text data
static void UnloadFileText ( char * text )
{
free ( text ) ;
}
2021-05-30 11:51:15 +02:00
// Get all lines from a text buffer (expecting lines ending with '\n')
2025-10-04 20:07:39 +02:00
static char * * LoadTextLines ( const char * buffer , int length , int * lineCount )
2021-05-30 11:51:15 +02:00
{
// Get the number of lines in the text
int count = 0 ;
for ( int i = 0 ; i < length ; i + + ) if ( buffer [ i ] = = ' \n ' ) count + + ;
2021-06-13 16:34:51 +02:00
printf ( " Number of text lines in buffer: %i \n " , count ) ;
2021-05-30 11:51:15 +02:00
// Allocate as many pointers as lines
char * * lines = ( char * * ) malloc ( count * sizeof ( char * * ) ) ;
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
char * bufferPtr = ( char * ) buffer ;
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
for ( int i = 0 ; ( i < count ) | | ( bufferPtr [ 0 ] ! = ' \0 ' ) ; i + + )
{
2025-10-04 20:07:39 +02:00
lines [ i ] = ( char * ) calloc ( MAX_LINE_LENGTH , sizeof ( char ) ) ; // MAX_LINE_LENGTH=1024
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
// Remove line leading spaces
// Find last index of space/tab character
int index = 0 ;
while ( ( bufferPtr [ index ] = = ' ' ) | | ( bufferPtr [ index ] = = ' \t ' ) ) index + + ;
int j = 0 ;
2024-05-15 07:16:45 -07:00
while ( bufferPtr [ index + j ] ! = ' \n ' & & bufferPtr [ index + j ] ! = ' \0 ' )
2021-05-30 11:51:15 +02:00
{
lines [ i ] [ j ] = bufferPtr [ index + j ] ;
j + + ;
}
2021-06-13 16:34:51 +02:00
2021-05-30 11:51:15 +02:00
bufferPtr + = ( index + j + 1 ) ;
}
2021-06-13 16:34:51 +02:00
2025-10-04 20:07:39 +02:00
* lineCount = count ;
2021-05-30 11:51:15 +02:00
return lines ;
}
2025-10-04 20:07:39 +02:00
// Unload text lines data
static void UnloadTextLines ( char * * lines , int lineCount )
{
for ( int i = 0 ; i < lineCount ; i + + ) free ( lines [ i ] ) ;
free ( lines ) ;
}
2021-05-30 11:51:15 +02:00
// Get data type and name from a string containing both
// NOTE: Useful to parse function parameters and struct fields
2021-06-13 16:34:51 +02:00
static void GetDataTypeAndName ( const char * typeName , int typeNameLen , char * type , char * name )
2021-05-30 11:51:15 +02:00
{
for ( int k = typeNameLen ; k > 0 ; k - - )
{
2022-05-01 12:34:15 +02:00
if ( ( typeName [ k ] = = ' ' ) & & ( typeName [ k - 1 ] ! = ' , ' ) )
2021-05-30 11:51:15 +02:00
{
// 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 ;
}
2022-05-01 12:34:15 +02:00
else if ( ( typeName [ k ] = = ' . ' ) & & ( typeNameLen = = 3 ) ) / / Handle varargs . . . ) ;
2022-03-08 19:00:09 +00:00
{
2024-05-29 15:00:28 +05:30
const char * varargsDots = " ... " ;
const char * varargsArg = " args " ;
MemoryCopy ( type , varargsDots , TextLength ( varargsDots ) ) ;
MemoryCopy ( name , varargsArg , TextLength ( varargsArg ) ) ;
2022-05-01 12:34:15 +02:00
break ;
2022-03-08 19:00:09 +00:00
}
2021-05-30 11:51:15 +02:00
}
}
2022-05-04 11:06:01 +02:00
// 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 ) ;
}
2022-05-04 13:44:55 +02:00
// 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 ' ;
}
}
}
}
2021-06-13 16:34:51 +02:00
// 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 ;
}
2021-05-30 11:51:15 +02:00
// Compare two text strings, requires number of characters to compare
2021-06-13 16:34:51 +02:00
static bool IsTextEqual ( const char * text1 , const char * text2 , unsigned int count )
2021-05-30 11:51:15 +02:00
{
bool result = true ;
2021-06-13 16:34:51 +02:00
for ( unsigned int i = 0 ; i < count ; i + + )
2021-05-30 11:51:15 +02:00
{
2021-06-13 16:34:51 +02:00
if ( text1 [ i ] ! = text2 [ i ] )
2021-05-30 11:51:15 +02:00
{
result = false ;
break ;
}
}
return result ;
}
2022-05-06 20:18:39 +02:00
// 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 ;
}
2022-05-04 13:44:55 +02:00
// 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 ] ;
}
2021-12-16 13:49:17 +00:00
// Escape backslashes in a string, writing the escaped string into a static buffer
2021-12-16 14:59:40 +01:00
static char * EscapeBackslashes ( char * text )
2021-06-06 04:21:56 -04:00
{
2021-12-16 14:59:40 +01:00
static char buffer [ 256 ] = { 0 } ;
2022-03-17 10:52:13 +00:00
2021-12-16 14:59:40 +01:00
int count = 0 ;
2022-03-17 10:52:13 +00:00
2021-12-16 14:59:40 +01:00
for ( int i = 0 ; ( text [ i ] ! = ' \0 ' ) & & ( i < 255 ) ; i + + , count + + )
2021-12-16 13:49:17 +00:00
{
2021-12-16 14:59:40 +01:00
buffer [ count ] = text [ i ] ;
2022-03-17 10:52:13 +00:00
if ( text [ i ] = = ' \\ ' )
2021-12-16 14:59:40 +01:00
{
buffer [ count + 1 ] = ' \\ ' ;
count + + ;
}
2021-12-16 13:49:17 +00:00
}
2022-03-17 10:52:13 +00:00
2021-12-16 14:59:40 +01:00
buffer [ count ] = ' \0 ' ;
2022-03-17 10:52:13 +00:00
2021-12-16 14:59:40 +01:00
return buffer ;
2021-06-06 04:21:56 -04:00
}
2022-02-03 16:56:00 +03:00
// Get string of define type
static const char * StrDefineType ( DefineType type )
{
switch ( type )
{
2022-05-06 20:23:07 +02:00
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 " ;
2022-02-03 16:56:00 +03:00
}
return " " ;
}
2021-05-30 11:51:15 +02:00
/*
// 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)
2021-06-13 16:34:51 +02:00
static char * TextReplace ( char * text , const char * replace , const char * by )
2021-05-30 11:51:15 +02:00
{
// 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 ;
}
2021-06-13 16:34:51 +02:00
*/
// Export parsed data in desired format
static void ExportParsedData ( const char * fileName , int format )
{
FILE * outFile = fopen ( fileName , " wt " ) ;
switch ( format )
{
case DEFAULT :
{
2022-05-04 13:44:55 +02:00
// Print defines info
fprintf ( outFile , " \n Defines 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 ) ;
}
2021-06-13 16:34:51 +02:00
// Print structs info
fprintf ( outFile , " \n Structures 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 ) ;
2022-05-04 11:06:01 +02:00
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 " ) ;
}
2021-06-13 16:34:51 +02:00
}
2022-05-01 12:34:15 +02:00
// Print aliases info
fprintf ( outFile , " \n Aliases 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 ) ;
2022-05-04 11:06:01 +02:00
fprintf ( outFile , " Description: %s \n " , aliases [ i ] . desc ) ;
2022-05-01 12:34:15 +02:00
}
2021-06-13 16:34:51 +02:00
// Print enums info
fprintf ( outFile , " \n Enums 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 ) ;
2022-05-04 11:06:01 +02:00
fprintf ( outFile , " Description: %s \n " , enums [ i ] . desc ) ;
2021-06-13 16:34:51 +02:00
for ( int e = 0 ; e < enums [ i ] . valueCount ; e + + ) fprintf ( outFile , " Value[%s]: %i \n " , enums [ i ] . valueName [ e ] , enums [ i ] . valueInteger [ e ] ) ;
}
2022-05-04 11:06:01 +02:00
// Print callbacks info
fprintf ( outFile , " \n Callbacks 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 " ) ;
}
2022-05-04 13:44:55 +02:00
// Print functions info
fprintf ( outFile , " \n Functions found: %i \n \n " , funcCount ) ;
for ( int i = 0 ; i < funcCount ; i + + )
2022-02-03 16:56:00 +03:00
{
2022-05-04 13:44:55 +02:00
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 " ) ;
2022-02-03 16:56:00 +03:00
}
2021-06-13 16:34:51 +02:00
} break ;
2022-05-04 13:44:55 +02:00
case JSON :
2021-11-11 20:12:30 +03:00
{
2022-05-04 13:44:55 +02:00
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 " ) ;
2021-11-11 20:12:30 +03:00
// Print structs info
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " \" structs \" : [ \n " ) ;
2021-11-11 20:12:30 +03:00
for ( int i = 0 ; i < structCount ; i + + )
{
fprintf ( outFile , " { \n " ) ;
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " \" name \" : \" %s \" , \n " , structs [ i ] . name ) ;
fprintf ( outFile , " \" description \" : \" %s \" , \n " , EscapeBackslashes ( structs [ i ] . desc ) ) ;
fprintf ( outFile , " \" fields \" : [ \n " ) ;
2021-11-11 20:12:30 +03:00
for ( int f = 0 ; f < structs [ i ] . fieldCount ; f + + )
{
fprintf ( outFile , " { \n " ) ;
2022-05-04 13:44:55 +02:00
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 ] ) ) ;
2021-11-11 20:12:30 +03:00
fprintf ( outFile , " } " ) ;
if ( f < structs [ i ] . fieldCount - 1 ) fprintf ( outFile , " , \n " ) ;
else fprintf ( outFile , " \n " ) ;
}
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " ] \n " ) ;
2021-11-11 20:12:30 +03:00
fprintf ( outFile , " } " ) ;
if ( i < structCount - 1 ) fprintf ( outFile , " , \n " ) ;
else fprintf ( outFile , " \n " ) ;
}
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " ], \n " ) ;
2021-11-11 20:12:30 +03:00
2022-05-01 12:34:15 +02:00
// Print aliases info
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " \" aliases \" : [ \n " ) ;
2022-05-01 12:34:15 +02:00
for ( int i = 0 ; i < aliasCount ; i + + )
{
fprintf ( outFile , " { \n " ) ;
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " \" type \" : \" %s \" , \n " , aliases [ i ] . type ) ;
fprintf ( outFile , " \" name \" : \" %s \" , \n " , aliases [ i ] . name ) ;
fprintf ( outFile , " \" description \" : \" %s \" \n " , aliases [ i ] . desc ) ;
2022-05-01 12:34:15 +02:00
fprintf ( outFile , " } " ) ;
if ( i < aliasCount - 1 ) fprintf ( outFile , " , \n " ) ;
else fprintf ( outFile , " \n " ) ;
}
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " ], \n " ) ;
2022-05-01 12:34:15 +02:00
2021-11-11 20:12:30 +03:00
// Print enums info
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " \" enums \" : [ \n " ) ;
2021-11-11 20:12:30 +03:00
for ( int i = 0 ; i < enumCount ; i + + )
{
fprintf ( outFile , " { \n " ) ;
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " \" name \" : \" %s \" , \n " , enums [ i ] . name ) ;
fprintf ( outFile , " \" description \" : \" %s \" , \n " , EscapeBackslashes ( enums [ i ] . desc ) ) ;
fprintf ( outFile , " \" values \" : [ \n " ) ;
2021-11-11 20:12:30 +03:00
for ( int e = 0 ; e < enums [ i ] . valueCount ; e + + )
{
fprintf ( outFile , " { \n " ) ;
2022-05-04 13:44:55 +02:00
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 ] ) ) ;
2021-11-11 20:12:30 +03:00
fprintf ( outFile , " } " ) ;
if ( e < enums [ i ] . valueCount - 1 ) fprintf ( outFile , " , \n " ) ;
else fprintf ( outFile , " \n " ) ;
}
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " ] \n " ) ;
2021-11-11 20:12:30 +03:00
fprintf ( outFile , " } " ) ;
if ( i < enumCount - 1 ) fprintf ( outFile , " , \n " ) ;
else fprintf ( outFile , " \n " ) ;
}
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " ], \n " ) ;
2022-05-04 11:06:01 +02:00
// Print callbacks info
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " \" callbacks \" : [ \n " ) ;
2022-05-04 11:06:01 +02:00
for ( int i = 0 ; i < callbackCount ; i + + )
{
fprintf ( outFile , " { \n " ) ;
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " \" name \" : \" %s \" , \n " , callbacks [ i ] . name ) ;
fprintf ( outFile , " \" description \" : \" %s \" , \n " , EscapeBackslashes ( callbacks [ i ] . desc ) ) ;
fprintf ( outFile , " \" returnType \" : \" %s \" " , callbacks [ i ] . retType ) ;
2022-05-04 11:06:01 +02:00
if ( callbacks [ i ] . paramCount = = 0 ) fprintf ( outFile , " \n " ) ;
else
{
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " , \n \" params \" : [ \n " ) ;
2022-05-04 11:06:01 +02:00
for ( int p = 0 ; p < callbacks [ i ] . paramCount ; p + + )
{
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " { \n " ) ;
fprintf ( outFile , " \" type \" : \" %s \" , \n " , callbacks [ i ] . paramType [ p ] ) ;
fprintf ( outFile , " \" name \" : \" %s \" \n " , callbacks [ i ] . paramName [ p ] ) ;
fprintf ( outFile , " } " ) ;
2022-05-04 11:06:01 +02:00
if ( p < callbacks [ i ] . paramCount - 1 ) fprintf ( outFile , " , \n " ) ;
else fprintf ( outFile , " \n " ) ;
}
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " ] \n " ) ;
2022-05-04 11:06:01 +02:00
}
fprintf ( outFile , " } " ) ;
if ( i < callbackCount - 1 ) fprintf ( outFile , " , \n " ) ;
else fprintf ( outFile , " \n " ) ;
}
2022-02-03 16:56:00 +03:00
fprintf ( outFile , " ], \n " ) ;
2021-06-13 16:34:51 +02:00
// 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 ) ;
2022-05-04 11:06:01 +02:00
fprintf ( outFile , " \" description \" : \" %s \" , \n " , EscapeBackslashes ( funcs [ i ] . desc ) ) ;
2021-06-13 16:34:51 +02:00
fprintf ( outFile , " \" returnType \" : \" %s \" " , funcs [ i ] . retType ) ;
if ( funcs [ i ] . paramCount = = 0 ) fprintf ( outFile , " \n " ) ;
else
{
2022-01-04 15:06:10 +02:00
fprintf ( outFile , " , \n \" params \" : [ \n " ) ;
2021-06-13 16:34:51 +02:00
for ( int p = 0 ; p < funcs [ i ] . paramCount ; p + + )
{
2022-01-04 15:06:10 +02:00
fprintf ( outFile , " { \n " ) ;
fprintf ( outFile , " \" type \" : \" %s \" , \n " , funcs [ i ] . paramType [ p ] ) ;
fprintf ( outFile , " \" name \" : \" %s \" \n " , funcs [ i ] . paramName [ p ] ) ;
fprintf ( outFile , " } " ) ;
2021-06-13 16:34:51 +02:00
if ( p < funcs [ i ] . paramCount - 1 ) fprintf ( outFile , " , \n " ) ;
else fprintf ( outFile , " \n " ) ;
}
2022-01-04 15:06:10 +02:00
fprintf ( outFile , " ] \n " ) ;
2021-06-13 16:34:51 +02:00
}
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 >
2022-05-04 13:44:55 +02:00
< Defines count = " " >
< Define name = " " type = " " value = " " desc = " " / >
< / Defines >
2021-06-13 16:34:51 +02:00
< Structs count = " " >
< Struct name = " " fieldCount = " " desc = " " >
2022-05-01 12:34:15 +02:00
< Field type = " " name = " " desc = " " / >
< Field type = " " name = " " desc = " " / >
2021-06-13 16:34:51 +02:00
< / Struct >
< Structs >
2022-05-01 12:34:15 +02:00
< Aliases count = " " >
< Alias type = " " name = " " desc = " " / >
< / Aliases >
2021-06-13 16:34:51 +02:00
< Enums count = " " >
< Enum name = " " valueCount = " " desc = " " >
2022-05-01 12:34:15 +02:00
< Value name = " " integer = " " desc = " " / >
< Value name = " " integer = " " desc = " " / >
2021-06-13 16:34:51 +02:00
< / Enum >
< / Enums >
2022-05-04 11:06:01 +02:00
< Callbacks count = " " >
< Callback name = " " retType = " " paramCount = " " desc = " " >
< Param type = " " name = " " desc = " " / >
< Param type = " " name = " " desc = " " / >
< / Callback >
< / Callbacks >
2022-05-04 13:44:55 +02:00
< Functions count = " " >
< Function name = " " retType = " " paramCount = " " desc = " " >
< Param type = " " name = " " desc = " " / >
< Param type = " " name = " " desc = " " / >
< / Function >
< / Functions >
2021-06-13 16:34:51 +02:00
< / raylibAPI >
*/
fprintf ( outFile , " <?xml version= \" 1.0 \" encoding= \" Windows-1252 \" ?> \n " ) ;
fprintf ( outFile , " <raylibAPI> \n " ) ;
2022-05-04 13:44:55 +02:00
// 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 " ) ;
2021-06-13 16:34:51 +02:00
// Print structs info
fprintf ( outFile , " <Structs count= \" %i \" > \n " , structCount ) ;
for ( int i = 0 ; i < structCount ; i + + )
{
2022-05-04 11:06:01 +02:00
fprintf ( outFile , " <Struct name= \" %s \" fieldCount= \" %i \" desc= \" %s \" > \n " , structs [ i ] . name , structs [ i ] . fieldCount , structs [ i ] . desc ) ;
2021-06-13 16:34:51 +02:00
for ( int f = 0 ; f < structs [ i ] . fieldCount ; f + + )
{
2022-05-04 11:06:01 +02:00
fprintf ( outFile , " <Field type= \" %s \" name= \" %s \" desc= \" %s \" /> \n " , structs [ i ] . fieldType [ f ] , structs [ i ] . fieldName [ f ] , structs [ i ] . fieldDesc [ f ] ) ;
2021-06-13 16:34:51 +02:00
}
fprintf ( outFile , " </Struct> \n " ) ;
}
fprintf ( outFile , " </Structs> \n " ) ;
2022-05-01 12:34:15 +02:00
// Print aliases info
fprintf ( outFile , " <Aliases count= \" %i \" > \n " , aliasCount ) ;
for ( int i = 0 ; i < aliasCount ; i + + )
{
2022-05-04 11:06:01 +02:00
fprintf ( outFile , " <Alias type= \" %s \" name= \" %s \" desc= \" %s \" /> \n " , aliases [ i ] . name , aliases [ i ] . type , aliases [ i ] . desc ) ;
2022-05-01 12:34:15 +02:00
}
fprintf ( outFile , " </Aliases> \n " ) ;
2021-06-13 16:34:51 +02:00
// Print enums info
fprintf ( outFile , " <Enums count= \" %i \" > \n " , enumCount ) ;
for ( int i = 0 ; i < enumCount ; i + + )
{
2022-05-04 11:06:01 +02:00
fprintf ( outFile , " <Enum name= \" %s \" valueCount= \" %i \" desc= \" %s \" > \n " , enums [ i ] . name , enums [ i ] . valueCount , enums [ i ] . desc ) ;
2021-06-13 16:34:51 +02:00
for ( int v = 0 ; v < enums [ i ] . valueCount ; v + + )
{
2022-05-04 11:06:01 +02:00
fprintf ( outFile , " <Value name= \" %s \" integer= \" %i \" desc= \" %s \" /> \n " , enums [ i ] . valueName [ v ] , enums [ i ] . valueInteger [ v ] , enums [ i ] . valueDesc [ v ] ) ;
2021-06-13 16:34:51 +02:00
}
fprintf ( outFile , " </Enum> \n " ) ;
}
fprintf ( outFile , " </Enums> \n " ) ;
2022-05-04 13:44:55 +02:00
// Print callbacks info
fprintf ( outFile , " <Callbacks count= \" %i \" > \n " , callbackCount ) ;
for ( int i = 0 ; i < callbackCount ; i + + )
2022-02-03 16:56:00 +03:00
{
2022-05-04 13:44:55 +02:00
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 + + )
2022-04-05 00:00:41 +02:00
{
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " <Param type= \" %s \" name= \" %s \" desc= \" %s \" /> \n " , callbacks [ i ] . paramType [ p ] , callbacks [ i ] . paramName [ p ] , callbacks [ i ] . paramDesc [ p ] ) ;
2022-04-05 00:00:41 +02:00
}
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " </Callback> \n " ) ;
2022-02-03 16:56:00 +03:00
}
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " </Callbacks> \n " ) ;
2022-02-03 16:56:00 +03:00
2021-06-13 16:34:51 +02:00
// Print functions info
fprintf ( outFile , " <Functions count= \" %i \" > \n " , funcCount ) ;
for ( int i = 0 ; i < funcCount ; i + + )
{
2022-05-04 11:06:01 +02:00
fprintf ( outFile , " <Function name= \" %s \" retType= \" %s \" paramCount= \" %i \" desc= \" %s \" > \n " , funcs [ i ] . name , funcs [ i ] . retType , funcs [ i ] . paramCount , funcs [ i ] . desc ) ;
2021-06-13 16:34:51 +02:00
for ( int p = 0 ; p < funcs [ i ] . paramCount ; p + + )
{
2022-05-04 11:06:01 +02:00
fprintf ( outFile , " <Param type= \" %s \" name= \" %s \" desc= \" %s \" /> \n " , funcs [ i ] . paramType [ p ] , funcs [ i ] . paramName [ p ] , funcs [ i ] . paramDesc [ p ] ) ;
2021-06-13 16:34:51 +02:00
}
fprintf ( outFile , " </Function> \n " ) ;
}
fprintf ( outFile , " </Functions> \n " ) ;
2022-05-04 13:44:55 +02:00
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 " ) ;
2022-05-04 11:06:01 +02:00
// Print callbacks info
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " callbacks = { \n " ) ;
2022-05-04 11:06:01 +02:00
for ( int i = 0 ; i < callbackCount ; i + + )
{
2022-05-04 13:44:55 +02:00
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
2022-05-04 11:06:01 +02:00
{
2022-05-04 13:44:55 +02:00
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 " ) ;
2022-05-04 11:06:01 +02:00
}
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " } " ) ;
if ( i < callbackCount - 1 ) fprintf ( outFile , " , \n " ) ;
else fprintf ( outFile , " \n " ) ;
2022-05-04 11:06:01 +02:00
}
2022-05-04 13:44:55 +02:00
fprintf ( outFile , " }, \n " ) ;
2022-05-04 11:06:01 +02:00
2022-05-04 13:44:55 +02:00
// 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 ) ;
2021-06-13 16:34:51 +02:00
2022-05-04 13:44:55 +02:00
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 " ) ;
2021-06-13 16:34:51 +02:00
} break ;
2022-08-05 20:00:58 +02:00
case CODE :
2021-06-13 16:34:51 +02:00
default : break ;
}
fclose ( outFile ) ;
}