#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
#define MAX_DEFINES_TO_PARSE 2048
#define MAX_STRUCTS_TO_PARSE 64
#define MAX_ALIASES_TO_PARSE 64
#define MAX_ENUMS_TO_PARSE 64
#define MAX_CALLBACKS_TO_PARSE 64
#define MAX_FUNCS_TO_PARSE 1024
#define MAX_LINE_LENGTH 512
#define MAX_STRUCT_FIELDS 64
#define MAX_ENUM_VALUES 512
#define MAX_FUNCTION_PARAMETERS 12
typedef enum {
UNKNOWN = 0,
MACRO,
GUARD,
INT,
INT_MATH,
LONG,
LONG_MATH,
FLOAT,
FLOAT_MATH,
DOUBLE,
DOUBLE_MATH,
CHAR,
STRING,
COLOR
} DefineType;
typedef struct DefineInfo {
char name[64]; int type; char value[256]; char desc[128]; bool isHex; } DefineInfo;
typedef struct StructInfo {
char name[64]; char desc[128]; int fieldCount; char fieldType[MAX_STRUCT_FIELDS][64]; char fieldName[MAX_STRUCT_FIELDS][64]; char fieldDesc[MAX_STRUCT_FIELDS][128]; } StructInfo;
typedef struct AliasInfo {
char type[64]; char name[64]; char desc[128]; } AliasInfo;
typedef struct EnumInfo {
char name[64]; char desc[128]; int valueCount; char valueName[MAX_ENUM_VALUES][64]; int valueInteger[MAX_ENUM_VALUES]; char valueDesc[MAX_ENUM_VALUES][128]; } EnumInfo;
typedef struct FunctionInfo {
char name[64]; char desc[128]; char retType[32]; int paramCount; char paramType[MAX_FUNCTION_PARAMETERS][32]; char paramName[MAX_FUNCTION_PARAMETERS][32]; char paramDesc[MAX_FUNCTION_PARAMETERS][128]; } FunctionInfo;
typedef enum { DEFAULT = 0, JSON, XML, LUA, CODE } OutputFormat;
static int defineCount = 0;
static int structCount = 0;
static int aliasCount = 0;
static int enumCount = 0;
static int callbackCount = 0;
static int funcCount = 0;
static DefineInfo *defines = NULL;
static StructInfo *structs = NULL;
static AliasInfo *aliases = NULL;
static EnumInfo *enums = NULL;
static FunctionInfo *callbacks = NULL;
static FunctionInfo *funcs = NULL;
static char apiDefine[32] = { 0 }; static char truncAfter[32] = { 0 }; static char inFileName[512] = { 0 }; static char outFileName[512] = { 0 }; static int outputFormat = DEFAULT;
static void ShowCommandLineInfo(void); static void ProcessCommandLine(int argc, char *argv[]);
static char *LoadFileText(const char *fileName, int *length);
static char **GetTextLines(const char *buffer, int length, int *linesCount);
static void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name);
static void GetDescription(const char *source, char *description);
static void MoveArraySize(char *name, char *type); static unsigned int TextLength(const char *text); static bool IsTextEqual(const char *text1, const char *text2, unsigned int count);
static int TextFindIndex(const char *text, const char *find); static void MemoryCopy(void *dest, const void *src, unsigned int count);
static char *EscapeBackslashes(char *text); static const char *StrDefineType(DefineType type);
static void ExportParsedData(const char *fileName, int format);
int main(int argc, char* argv[])
{
if (argc > 1) ProcessCommandLine(argc, argv);
if (inFileName[0] == '\0') MemoryCopy(inFileName, "../src/raylib.h\0", 16);
if (outFileName[0] == '\0') MemoryCopy(outFileName, "raylib_api.txt\0", 15);
if (apiDefine[0] == '\0') MemoryCopy(apiDefine, "RLAPI\0", 6);
int length = 0;
char *buffer = LoadFileText(inFileName, &length);
if (buffer == NULL)
{
printf("Could not read input file: %s\n", inFileName);
return 1;
}
int linesCount = 0;
char **lines = GetTextLines(buffer, length, &linesCount);
if (truncAfter[0] != '\0')
{
int newCount = -1;
for (int i = 0; i < linesCount; i++)
{
if (newCount > -1) free(lines[i]);
else if (TextFindIndex(lines[i], truncAfter) > -1) newCount = i;
}
if (newCount > -1) linesCount = newCount;
printf("Number of truncated text lines: %i\n", linesCount);
}
int *defineLines = (int *)malloc(MAX_DEFINES_TO_PARSE*sizeof(int));
int *structLines = (int *)malloc(MAX_STRUCTS_TO_PARSE*sizeof(int));
int *aliasLines = (int *)malloc(MAX_ALIASES_TO_PARSE*sizeof(int));
int *enumLines = (int *)malloc(MAX_ENUMS_TO_PARSE*sizeof(int));
int *callbackLines = (int *)malloc(MAX_CALLBACKS_TO_PARSE*sizeof(int));
int *funcLines = (int *)malloc(MAX_FUNCS_TO_PARSE*sizeof(int));
for (int i = 0; i < linesCount; i++)
{
int j = 0;
while ((lines[i][j] == ' ') || (lines[i][j] == '\t')) j++; if (IsTextEqual(lines[i]+j, "#define ", 8))
{
defineLines[defineCount] = i;
defineCount++;
}
}
for (int i = 0; i < linesCount; i++)
{
if (IsTextEqual(lines[i], "typedef struct", 14))
{
bool validStruct = IsTextEqual(lines[i + 1], "struct", 6);
if (!validStruct)
{
for (int c = 0; c < MAX_LINE_LENGTH; c++)
{
char v = lines[i][c];
if (v == '{') validStruct = true;
if ((v == '{') || (v == ';') || (v == '\0')) break;
}
}
if (!validStruct) continue;
structLines[structCount] = i;
while (lines[i][0] != '}') i++;
while (lines[i][0] != '\0') i++;
structCount++;
}
}
for (int i = 0; i < linesCount; i++)
{
if (IsTextEqual(lines[i], "typedef", 7))
{
int spaceCount = 0;
bool validAlias = false;
for (int c = 0; c < MAX_LINE_LENGTH; c++)
{
char v = lines[i][c];
if (v == ' ') spaceCount++;
if ((v == ';') && (spaceCount == 2)) validAlias = true;
if ((v == ';') || (v == '(') || (v == '\0')) break;
}
if (!validAlias) continue;
aliasLines[aliasCount] = i;
aliasCount++;
}
}
for (int i = 0; i < linesCount; i++)
{
if (IsTextEqual(lines[i], "typedef enum {", 14) && (lines[i][TextLength(lines[i])-1] != ';')) {
enumLines[enumCount] = i;
enumCount++;
}
}
for (int i = 0; i < linesCount; i++)
{
if (IsTextEqual(lines[i], "typedef", 7))
{
bool hasBeginning = false;
bool hasMiddle = false;
bool hasEnd = false;
for (int c = 0; c < MAX_LINE_LENGTH; c++)
{
if ((lines[i][c] == '(') && (lines[i][c + 1] == '*')) hasBeginning = true;
if ((lines[i][c] == ')') && (lines[i][c + 1] == '(')) hasMiddle = true;
if ((lines[i][c] == ')') && (lines[i][c + 1] == ';')) hasEnd = true;
if (hasEnd) break;
}
if (hasBeginning && hasMiddle && hasEnd)
{
callbackLines[callbackCount] = i;
callbackCount++;
}
}
}
for (int i = 0; i < linesCount; i++)
{
if (IsTextEqual(lines[i], apiDefine, TextLength(apiDefine)))
{
funcLines[funcCount] = i;
funcCount++;
}
}
free(buffer);
defines = (DefineInfo *)calloc(MAX_DEFINES_TO_PARSE, sizeof(DefineInfo));
int defineIndex = 0;
for (int i = 0; i < defineCount; i++)
{
char *linePtr = lines[defineLines[i]];
int j = 0;
while ((linePtr[j] == ' ') || (linePtr[j] == '\t')) j++; j += 8; while ((linePtr[j] == ' ') || (linePtr[j] == '\t')) j++;
int defineNameStart = j;
int openBraces = 0;
while (linePtr[j] != '\0')
{
if (((linePtr[j] == ' ') || (linePtr[j] == '\t')) && (openBraces == 0)) break;
if (linePtr[j] == '(') openBraces++;
if (linePtr[j] == ')') openBraces--;
j++;
}
int defineNameEnd = j-1;
unsigned int nameLen = defineNameEnd - defineNameStart + 1;
bool isDuplicate = false;
for (int k = 0; k < defineIndex; k++)
{
if ((nameLen == TextLength(defines[k].name)) && IsTextEqual(defines[k].name, &linePtr[defineNameStart], nameLen))
{
isDuplicate = true;
break;
}
}
if (isDuplicate) continue;
MemoryCopy(defines[defineIndex].name, &linePtr[defineNameStart], nameLen);
if (linePtr[defineNameEnd] == ')') defines[defineIndex].type = MACRO;
while ((linePtr[j] == ' ') || (linePtr[j] == '\t')) j++;
int defineValueStart = j;
if ((linePtr[j] == '\0') || (linePtr[j] == '/')) defines[defineIndex].type = GUARD;
if (linePtr[j] == '"') defines[defineIndex].type = STRING;
else if (linePtr[j] == '\'') defines[defineIndex].type = CHAR;
else if (IsTextEqual(linePtr+j, "CLITERAL(Color)", 15)) defines[defineIndex].type = COLOR;
else if (isdigit(linePtr[j])) {
bool isFloat = false, isNumber = true, isHex = false;
while ((linePtr[j] != ' ') && (linePtr[j] != '\t') && (linePtr[j] != '\0'))
{
char ch = linePtr[j];
if (ch == '.') isFloat = true;
if (ch == 'x') isHex = true;
if (!(isdigit(ch) ||
((ch >= 'a') && (ch <= 'f')) ||
((ch >= 'A') && (ch <= 'F')) ||
(ch == 'x') ||
(ch == 'L') ||
(ch == '.') ||
(ch == '+') ||
(ch == '-'))) isNumber = false;
j++;
}
if (isNumber)
{
if (isFloat)
{
defines[defineIndex].type = linePtr[j-1] == 'f' ? FLOAT : DOUBLE;
}
else
{
defines[defineIndex].type = linePtr[j-1] == 'L' ? LONG : INT;
defines[defineIndex].isHex = isHex;
}
}
}
while ((linePtr[j] != '\\') && (linePtr[j] != '\0') && !((linePtr[j] == '/') && (linePtr[j+1] == '/'))) j++;
int defineValueEnd = j-1;
while ((linePtr[defineValueEnd] == ' ') || (linePtr[defineValueEnd] == '\t')) defineValueEnd--; if ((defines[defineIndex].type == LONG) || (defines[defineIndex].type == FLOAT)) defineValueEnd--; int valueLen = defineValueEnd - defineValueStart + 1;
if (valueLen > 255) valueLen = 255;
if (valueLen > 0) MemoryCopy(defines[defineIndex].value, &linePtr[defineValueStart], valueLen);
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);
}
if (defines[defineIndex].type == UNKNOWN)
{
int largestType = UNKNOWN;
bool isMath = true;
char *valuePtr = defines[defineIndex].value;
for (unsigned int c = 0; c < TextLength(valuePtr); c++)
{
char ch = valuePtr[c];
if ((ch == '(') ||
(ch == ')') ||
(ch == '+') ||
(ch == '-') ||
(ch == '*') ||
(ch == '/') ||
(ch == ' ') ||
(ch == '\t')) continue;
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)
{
int numberType;
if (isFloat) numberType = valuePtr[c - 1] == 'f' ? FLOAT_MATH : DOUBLE_MATH;
else numberType = valuePtr[c - 1] == 'L' ? LONG_MATH : INT_MATH;
if (numberType > largestType) largestType = numberType;
}
else
{
isMath = false;
break;
}
}
else {
int operandStart = c;
while (!((ch == '\0') ||
(ch == ' ') ||
(ch == '(') ||
(ch == ')') ||
(ch == '+') ||
(ch == '-') ||
(ch == '*') ||
(ch == '/')))
{
c++;
ch = valuePtr[c];
}
int operandEnd = c;
int operandLength = operandEnd - operandStart;
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))
{
if (defines[previousDefineIndex].type > largestType) largestType = defines[previousDefineIndex].type;
foundOperand = true;
}
break;
}
}
if (!foundOperand)
{
isMath = false;
break;
}
}
}
if (isMath)
{
if (largestType == INT) largestType = INT_MATH;
else if (largestType == LONG) largestType = LONG_MATH;
else if (largestType == FLOAT) largestType = FLOAT_MATH;
else if (largestType == DOUBLE) largestType = DOUBLE_MATH;
defines[defineIndex].type = largestType;
}
}
defineIndex++;
}
defineCount = defineIndex;
free(defineLines);
structs = (StructInfo *)calloc(MAX_STRUCTS_TO_PARSE, sizeof(StructInfo));
for (int i = 0; i < structCount; i++)
{
char **linesPtr = &lines[structLines[i]];
GetDescription(linesPtr[-1], structs[i].desc);
const int TDS_LEN = 15; 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;
}
}
int l = 1;
while (linesPtr[l][0] != '}')
{
if ((linesPtr[l][0] != ' ') && (linesPtr[l][0] != '\0'))
{
char *fieldLine = linesPtr[l];
int fieldEndPos = 0;
while (fieldLine[fieldEndPos] != ';') fieldEndPos++;
if ((fieldLine[0] != '/') && !IsTextEqual(fieldLine, "struct", 6)) {
GetDataTypeAndName(fieldLine, fieldEndPos, structs[i].fieldType[structs[i].fieldCount], structs[i].fieldName[structs[i].fieldCount]);
GetDescription(&fieldLine[fieldEndPos], structs[i].fieldDesc[structs[i].fieldCount]);
structs[i].fieldCount++;
int additionalFields = 0;
int originalIndex = structs[i].fieldCount - 1;
for (unsigned int c = 0; c < TextLength(structs[i].fieldName[originalIndex]); c++)
{
if (structs[i].fieldName[originalIndex][c] == ',') additionalFields++;
}
if (additionalFields > 0)
{
int originalLength = -1;
int lastStart;
for (unsigned int c = 0; c < TextLength(structs[i].fieldName[originalIndex]) + 1; c++)
{
char v = structs[i].fieldName[originalIndex][c];
bool isEndOfString = (v == '\0');
if ((v == ',') || isEndOfString)
{
if (originalLength == -1)
{
originalLength = c;
}
else
{
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)
{
c++;
while (structs[i].fieldName[originalIndex][c] == ' ') c++;
lastStart = c;
}
}
}
structs[i].fieldName[originalIndex][originalLength] = '\0';
}
additionalFields = 0;
originalIndex = structs[i].fieldCount - 1;
for (unsigned int c = 0; c < TextLength(structs[i].fieldType[originalIndex]); c++)
{
if (structs[i].fieldType[originalIndex][c] == ',') additionalFields++;
}
if (additionalFields > 0)
{
structs[i].fieldCount += additionalFields;
MemoryCopy(structs[i].fieldName[originalIndex + additionalFields], &structs[i].fieldName[originalIndex][0], TextLength(structs[i].fieldName[originalIndex]));
int fieldsRemaining = additionalFields;
int nameStart = -1;
int nameEnd = -1;
for (int k = TextLength(structs[i].fieldType[originalIndex]); k > 0; k--)
{
char v = structs[i].fieldType[originalIndex][k];
if ((v == '*') || (v == ' ') || (v == ','))
{
if (nameEnd != -1) {
if (fieldsRemaining != additionalFields)
{
nameStart = k + 1;
MemoryCopy(structs[i].fieldName[originalIndex + fieldsRemaining], &structs[i].fieldType[originalIndex][nameStart], nameEnd - nameStart + 1);
}
nameEnd = -1;
fieldsRemaining--;
}
}
else if (nameEnd == -1) nameEnd = k;
}
int fieldTypeLength = nameStart;
structs[i].fieldType[originalIndex][fieldTypeLength] = '\0';
for (int j = 1; j <= additionalFields; j++)
{
MemoryCopy(structs[i].fieldType[originalIndex + j], &structs[i].fieldType[originalIndex][0], fieldTypeLength);
MemoryCopy(structs[i].fieldDesc[originalIndex + j], &structs[i].fieldDesc[originalIndex][0], TextLength(structs[i].fieldDesc[originalIndex]));
}
}
}
}
l++;
}
for (int j = 0; j < structs[i].fieldCount; j++)
{
MoveArraySize(structs[i].fieldName[j], structs[i].fieldType[j]);
}
}
free(structLines);
aliases = (AliasInfo *)calloc(MAX_ALIASES_TO_PARSE, sizeof(AliasInfo));
for (int i = 0; i < aliasCount; i++)
{
GetDescription(lines[aliasLines[i] - 1], aliases[i].desc);
char *linePtr = lines[aliasLines[i]];
int c = 8;
int typeStart = c;
while(linePtr[c] != ' ') c++;
int typeLen = c - typeStart;
MemoryCopy(aliases[i].type, &linePtr[typeStart], typeLen);
c++;
int nameStart = c;
while(linePtr[c] != ';') c++;
int nameLen = c - nameStart;
MemoryCopy(aliases[i].name, &linePtr[nameStart], nameLen);
GetDescription(&linePtr[c], aliases[i].desc);
}
free(aliasLines);
enums = (EnumInfo *)calloc(MAX_ENUMS_TO_PARSE, sizeof(EnumInfo));
for (int i = 0; i < enumCount; i++)
{
for (int j = enumLines[i] - 1; j > 0; j--)
{
char *linePtr = lines[j];
if ((linePtr[0] != '/') || (linePtr[2] != ' '))
{
GetDescription(&lines[j + 1][0], enums[i].desc);
break;
}
}
for (int j = 1; j < MAX_ENUM_VALUES*2; j++) {
char *linePtr = lines[enumLines[i] + j];
if ((linePtr[0] >= 'A') && (linePtr[0] <= 'Z'))
{
int c = 0;
while ((linePtr[c] != ',') &&
(linePtr[c] != ' ') &&
(linePtr[c] != '=') &&
(linePtr[c] != '\0'))
{
enums[i].valueName[enums[i].valueCount][c] = linePtr[c];
c++;
}
if ((linePtr[c] != ',') && (linePtr[c] != '\0'))
{
bool foundValue = false;
while ((linePtr[c] != '\0') && (linePtr[c] != '/'))
{
if (linePtr[c] == '=')
{
foundValue = true;
break;
}
c++;
}
if (foundValue)
{
if (linePtr[c + 1] == ' ') c += 2;
else c++;
int n = 0;
char integer[16] = { 0 };
while ((linePtr[c] != ',') && (linePtr[c] != ' ') && (linePtr[c] != '\0'))
{
integer[n] = linePtr[c];
c++; n++;
}
if (integer[1] == 'x') enums[i].valueInteger[enums[i].valueCount] = (int)strtol(integer, NULL, 16);
else enums[i].valueInteger[enums[i].valueCount] = atoi(integer);
}
else enums[i].valueInteger[enums[i].valueCount] = (enums[i].valueInteger[enums[i].valueCount - 1] + 1);
}
else enums[i].valueInteger[enums[i].valueCount] = (enums[i].valueInteger[enums[i].valueCount - 1] + 1);
GetDescription(&linePtr[c], enums[i].valueDesc[enums[i].valueCount]);
enums[i].valueCount++;
}
else if (linePtr[0] == '}')
{
int c = 0;
while (linePtr[2 + c] != ';')
{
enums[i].name[c] = linePtr[2 + c];
c++;
}
break; }
}
}
free(enumLines);
callbacks = (FunctionInfo *)calloc(MAX_CALLBACKS_TO_PARSE, sizeof(FunctionInfo));
for (int i = 0; i < callbackCount; i++)
{
char *linePtr = lines[callbackLines[i]];
unsigned int c = 8;
int retTypeStart = c;
while(linePtr[c] != '(') c++;
int retTypeLen = c - retTypeStart;
while(linePtr[retTypeStart + retTypeLen - 1] == ' ') retTypeLen--;
MemoryCopy(callbacks[i].retType, &linePtr[retTypeStart], retTypeLen);
c += 2;
int nameStart = c;
while(linePtr[c] != ')') c++;
int nameLen = c - nameStart;
MemoryCopy(callbacks[i].name, &linePtr[nameStart], nameLen);
c += 2;
int paramStart = c;
for (; c < MAX_LINE_LENGTH; c++)
{
if ((linePtr[c] == ',') || (linePtr[c] == ')'))
{
int paramLen = c - paramStart;
GetDataTypeAndName(&linePtr[paramStart], paramLen, callbacks[i].paramType[callbacks[i].paramCount], callbacks[i].paramName[callbacks[i].paramCount]);
callbacks[i].paramCount++;
paramStart = c + 1;
while(linePtr[paramStart] == ' ') paramStart++;
}
if (linePtr[c] == ')') break;
}
GetDescription(&linePtr[c], callbacks[i].desc);
for (int j = 0; j < callbacks[i].paramCount; j++)
{
MoveArraySize(callbacks[i].paramName[j], callbacks[i].paramType[j]);
}
}
free(callbackLines);
funcs = (FunctionInfo *)calloc(MAX_FUNCS_TO_PARSE, sizeof(FunctionInfo));
for (int i = 0; i < funcCount; i++)
{
char *linePtr = lines[funcLines[i]];
int funcParamsStart = 0;
int funcEnd = 0;
for (int c = 0; (c < MAX_LINE_LENGTH) && (linePtr[c] != '\n'); c++)
{
if (linePtr[c] == '(') {
funcParamsStart = c + 1;
char funcRetTypeName[128] = { 0 };
int dc = TextLength(apiDefine) + 1;
int funcRetTypeNameLen = c - dc; MemoryCopy(funcRetTypeName, &linePtr[dc], funcRetTypeNameLen);
GetDataTypeAndName(funcRetTypeName, funcRetTypeNameLen, funcs[i].retType, funcs[i].name);
break;
}
}
for (int c = funcParamsStart; c < MAX_LINE_LENGTH; c++)
{
if (linePtr[c] == ',') {
char funcParamTypeName[128] = { 0 };
int funcParamTypeNameLen = c - funcParamsStart;
MemoryCopy(funcParamTypeName, &linePtr[funcParamsStart], funcParamTypeNameLen);
GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]);
funcParamsStart = c + 1;
if (linePtr[c + 1] == ' ') funcParamsStart += 1;
funcs[i].paramCount++; }
else if (linePtr[c] == ')')
{
funcEnd = c + 2;
if ((linePtr[c - 4] == 'v') && (linePtr[c - 3] == 'o') && (linePtr[c - 2] == 'i') && (linePtr[c - 1] == 'd')) break;
char funcParamTypeName[128] = { 0 };
int funcParamTypeNameLen = c - funcParamsStart;
MemoryCopy(funcParamTypeName, &linePtr[funcParamsStart], funcParamTypeNameLen);
GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]);
funcs[i].paramCount++; break;
}
}
GetDescription(&linePtr[funcEnd], funcs[i].desc);
for (int j = 0; j < funcs[i].paramCount; j++)
{
MoveArraySize(funcs[i].paramName[j], funcs[i].paramType[j]);
}
}
free(funcLines);
for (int i = 0; i < linesCount; i++) free(lines[i]);
free(lines);
printf("\nInput file: %s", inFileName);
printf("\nOutput file: %s", outFileName);
if (outputFormat == DEFAULT) printf("\nOutput format: DEFAULT\n\n");
else if (outputFormat == JSON) printf("\nOutput format: JSON\n\n");
else if (outputFormat == XML) printf("\nOutput format: XML\n\n");
else if (outputFormat == LUA) printf("\nOutput format: LUA\n\n");
else if (outputFormat == CODE) printf("\nOutput format: CODE\n\n");
ExportParsedData(outFileName, outputFormat);
free(defines);
free(structs);
free(aliases);
free(enums);
free(callbacks);
free(funcs);
}
static void ShowCommandLineInfo(void)
{
printf("\n//////////////////////////////////////////////////////////////////////////////////\n");
printf("// //\n");
printf("// raylib API parser //\n");
printf("// //\n");
printf("// more info and bugs-report: github.com/raysan5/raylib/parser //\n");
printf("// //\n");
printf("// Copyright (c) 2021-2023 Ramon Santamaria (@raysan5) //\n");
printf("// //\n");
printf("//////////////////////////////////////////////////////////////////////////////////\n\n");
printf("USAGE:\n\n");
printf(" > raylib_parser [--help] [--input <filename.h>] [--output <filename.ext>] [--format <type>]\n");
printf("\nOPTIONS:\n\n");
printf(" -h, --help : Show tool version and command line usage help\n\n");
printf(" -i, --input <filename.h> : Define input header file to parse.\n");
printf(" NOTE: If not specified, defaults to: raylib.h\n\n");
printf(" -o, --output <filename.ext> : Define output file and format.\n");
printf(" Supported extensions: .txt, .json, .xml, .lua, .h\n");
printf(" NOTE: If not specified, defaults to: raylib_api.txt\n\n");
printf(" -f, --format <type> : Define output format for parser data.\n");
printf(" Supported types: DEFAULT, JSON, XML, LUA, CODE\n\n");
printf(" -d, --define <DEF> : Define functions specifiers (i.e. RLAPI for raylib.h, RMDEF for raymath.h, etc.)\n");
printf(" NOTE: If no specifier defined, defaults to: RLAPI\n\n");
printf(" -t, --truncate <after> : Define string to truncate input after (i.e. \"RLGL IMPLEMENTATION\" for rlgl.h)\n");
printf(" NOTE: If not specified, the full input file is parsed.\n\n");
printf("\nEXAMPLES:\n\n");
printf(" > raylib_parser --input raylib.h --output api.json\n");
printf(" Process <raylib.h> to generate <api.json>\n\n");
printf(" > raylib_parser --output raylib_data.info --format XML\n");
printf(" Process <raylib.h> to generate <raylib_data.info> as XML text data\n\n");
printf(" > raylib_parser --input raymath.h --output raymath_data.info --format XML\n");
printf(" Process <raymath.h> to generate <raymath_data.info> as XML text data\n\n");
}
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))
{
ShowCommandLineInfo();
exit(0);
}
else if (IsTextEqual(argv[i], "-i", 2) || IsTextEqual(argv[i], "--input", 7))
{
if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
{
MemoryCopy(inFileName, argv[i + 1], TextLength(argv[i + 1])); 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])); i++;
}
else printf("WARNING: No output file provided\n");
}
else if (IsTextEqual(argv[i], "-f", 2) || IsTextEqual(argv[i], "--format", 8))
{
if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
{
if (IsTextEqual(argv[i + 1], "DEFAULT\0", 8)) outputFormat = DEFAULT;
else if (IsTextEqual(argv[i + 1], "JSON\0", 5)) outputFormat = JSON;
else if (IsTextEqual(argv[i + 1], "XML\0", 4)) outputFormat = XML;
else if (IsTextEqual(argv[i + 1], "LUA\0", 4)) outputFormat = LUA;
else if (IsTextEqual(argv[i + 1], "CODE\0", 4)) outputFormat = CODE;
}
else printf("WARNING: No format parameters provided\n");
}
else if (IsTextEqual(argv[i], "-d", 2) || IsTextEqual(argv[i], "--define", 8))
{
if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
{
MemoryCopy(apiDefine, argv[i + 1], TextLength(argv[i + 1])); apiDefine[TextLength(argv[i + 1])] = '\0';
i++;
}
else printf("WARNING: No define key provided\n");
}
else if (IsTextEqual(argv[i], "-t", 2) || IsTextEqual(argv[i], "--truncate", 10))
{
if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
{
MemoryCopy(truncAfter, argv[i + 1], TextLength(argv[i + 1])); truncAfter[TextLength(argv[i + 1])] = '\0';
i++;
}
}
}
}
static char *LoadFileText(const char *fileName, int *length)
{
char *text = NULL;
if (fileName != NULL)
{
FILE *file = fopen(fileName, "rt");
if (file != NULL)
{
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);
if (count < (unsigned int)size)
{
text = realloc(text, count + 1);
*length = count;
}
else *length = size;
text[count] = '\0';
}
fclose(file);
}
}
return text;
}
static char **GetTextLines(const char *buffer, int length, int *linesCount)
{
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);
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));
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;
}
static void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name)
{
for (int k = typeNameLen; k > 0; k--)
{
if ((typeName[k] == ' ') && (typeName[k - 1] != ','))
{
MemoryCopy(type, typeName, k);
MemoryCopy(name, typeName + k + 1, typeNameLen - k - 1);
break;
}
else if (typeName[k] == '*')
{
MemoryCopy(type, typeName, k + 1);
MemoryCopy(name, typeName + k + 1, typeNameLen - k - 1);
break;
}
else if ((typeName[k] == '.') && (typeNameLen == 3)) {
MemoryCopy(type, "...", 3);
MemoryCopy(name, "args", 4);
break;
}
}
}
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);
}
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';
}
}
}
}
static unsigned int TextLength(const char *text)
{
unsigned int length = 0;
if (text != NULL) while (*text++) length++;
return length;
}
static bool IsTextEqual(const char *text1, const char *text2, unsigned int count)
{
bool result = true;
for (unsigned int i = 0; i < count; i++)
{
if (text1[i] != text2[i])
{
result = false;
break;
}
}
return result;
}
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;
}
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];
}
static char *EscapeBackslashes(char *text)
{
static char buffer[256] = { 0 };
int count = 0;
for (int i = 0; (text[i] != '\0') && (i < 255); i++, count++)
{
buffer[count] = text[i];
if (text[i] == '\\')
{
buffer[count + 1] = '\\';
count++;
}
}
buffer[count] = '\0';
return buffer;
}
static const char *StrDefineType(DefineType type)
{
switch (type)
{
case UNKNOWN: return "UNKNOWN";
case GUARD: return "GUARD";
case MACRO: return "MACRO";
case INT: return "INT";
case INT_MATH: return "INT_MATH";
case LONG: return "LONG";
case LONG_MATH: return "LONG_MATH";
case FLOAT: return "FLOAT";
case FLOAT_MATH: return "FLOAT_MATH";
case DOUBLE: return "DOUBLE";
case DOUBLE_MATH: return "DOUBLE_MATH";
case CHAR: return "CHAR";
case STRING: return "STRING";
case COLOR: return "COLOR";
}
return "";
}
static void ExportParsedData(const char *fileName, int format)
{
FILE *outFile = fopen(fileName, "wt");
switch (format)
{
case DEFAULT:
{
fprintf(outFile, "\nDefines found: %i\n\n", defineCount);
for (int i = 0; i < defineCount; i++)
{
fprintf(outFile, "Define %03i: %s\n", i + 1, defines[i].name);
fprintf(outFile, " Name: %s\n", defines[i].name);
fprintf(outFile, " Type: %s\n", StrDefineType(defines[i].type));
fprintf(outFile, " Value: %s\n", defines[i].value);
fprintf(outFile, " Description: %s\n", defines[i].desc);
}
fprintf(outFile, "\nStructures found: %i\n\n", structCount);
for (int i = 0; i < structCount; i++)
{
fprintf(outFile, "Struct %02i: %s (%i fields)\n", i + 1, structs[i].name, structs[i].fieldCount);
fprintf(outFile, " Name: %s\n", structs[i].name);
fprintf(outFile, " Description: %s\n", structs[i].desc);
for (int f = 0; f < structs[i].fieldCount; f++)
{
fprintf(outFile, " Field[%i]: %s %s ", f + 1, structs[i].fieldType[f], structs[i].fieldName[f]);
if (structs[i].fieldDesc[f][0]) fprintf(outFile, "// %s\n", structs[i].fieldDesc[f]);
else fprintf(outFile, "\n");
}
}
fprintf(outFile, "\nAliases found: %i\n\n", aliasCount);
for (int i = 0; i < aliasCount; i++)
{
fprintf(outFile, "Alias %03i: %s\n", i + 1, aliases[i].name);
fprintf(outFile, " Type: %s\n", aliases[i].type);
fprintf(outFile, " Name: %s\n", aliases[i].name);
fprintf(outFile, " Description: %s\n", aliases[i].desc);
}
fprintf(outFile, "\nEnums found: %i\n\n", enumCount);
for (int i = 0; i < enumCount; i++)
{
fprintf(outFile, "Enum %02i: %s (%i values)\n", i + 1, enums[i].name, enums[i].valueCount);
fprintf(outFile, " Name: %s\n", enums[i].name);
fprintf(outFile, " Description: %s\n", enums[i].desc);
for (int e = 0; e < enums[i].valueCount; e++) fprintf(outFile, " Value[%s]: %i\n", enums[i].valueName[e], enums[i].valueInteger[e]);
}
fprintf(outFile, "\nCallbacks found: %i\n\n", callbackCount);
for (int i = 0; i < callbackCount; i++)
{
fprintf(outFile, "Callback %03i: %s() (%i input parameters)\n", i + 1, callbacks[i].name, callbacks[i].paramCount);
fprintf(outFile, " Name: %s\n", callbacks[i].name);
fprintf(outFile, " Return type: %s\n", callbacks[i].retType);
fprintf(outFile, " Description: %s\n", callbacks[i].desc);
for (int p = 0; p < callbacks[i].paramCount; p++) fprintf(outFile, " Param[%i]: %s (type: %s)\n", p + 1, callbacks[i].paramName[p], callbacks[i].paramType[p]);
if (callbacks[i].paramCount == 0) fprintf(outFile, " No input parameters\n");
}
fprintf(outFile, "\nFunctions found: %i\n\n", funcCount);
for (int i = 0; i < funcCount; i++)
{
fprintf(outFile, "Function %03i: %s() (%i input parameters)\n", i + 1, funcs[i].name, funcs[i].paramCount);
fprintf(outFile, " Name: %s\n", funcs[i].name);
fprintf(outFile, " Return type: %s\n", funcs[i].retType);
fprintf(outFile, " Description: %s\n", funcs[i].desc);
for (int p = 0; p < funcs[i].paramCount; p++) fprintf(outFile, " Param[%i]: %s (type: %s)\n", p + 1, funcs[i].paramName[p], funcs[i].paramType[p]);
if (funcs[i].paramCount == 0) fprintf(outFile, " No input parameters\n");
}
} break;
case JSON:
{
fprintf(outFile, "{\n");
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) {
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");
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");
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");
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");
fprintf(outFile, " \"callbacks\": [\n");
for (int i = 0; i < callbackCount; i++)
{
fprintf(outFile, " {\n");
fprintf(outFile, " \"name\": \"%s\",\n", callbacks[i].name);
fprintf(outFile, " \"description\": \"%s\",\n", EscapeBackslashes(callbacks[i].desc));
fprintf(outFile, " \"returnType\": \"%s\"", callbacks[i].retType);
if (callbacks[i].paramCount == 0) fprintf(outFile, "\n");
else
{
fprintf(outFile, ",\n \"params\": [\n");
for (int p = 0; p < callbacks[i].paramCount; p++)
{
fprintf(outFile, " {\n");
fprintf(outFile, " \"type\": \"%s\",\n", callbacks[i].paramType[p]);
fprintf(outFile, " \"name\": \"%s\"\n", callbacks[i].paramName[p]);
fprintf(outFile, " }");
if (p < callbacks[i].paramCount - 1) fprintf(outFile, ",\n");
else fprintf(outFile, "\n");
}
fprintf(outFile, " ]\n");
}
fprintf(outFile, " }");
if (i < callbackCount - 1) fprintf(outFile, ",\n");
else fprintf(outFile, "\n");
}
fprintf(outFile, " ],\n");
fprintf(outFile, " \"functions\": [\n");
for (int i = 0; i < funcCount; i++)
{
fprintf(outFile, " {\n");
fprintf(outFile, " \"name\": \"%s\",\n", funcs[i].name);
fprintf(outFile, " \"description\": \"%s\",\n", EscapeBackslashes(funcs[i].desc));
fprintf(outFile, " \"returnType\": \"%s\"", funcs[i].retType);
if (funcs[i].paramCount == 0) fprintf(outFile, "\n");
else
{
fprintf(outFile, ",\n \"params\": [\n");
for (int p = 0; p < funcs[i].paramCount; p++)
{
fprintf(outFile, " {\n");
fprintf(outFile, " \"type\": \"%s\",\n", funcs[i].paramType[p]);
fprintf(outFile, " \"name\": \"%s\"\n", funcs[i].paramName[p]);
fprintf(outFile, " }");
if (p < funcs[i].paramCount - 1) fprintf(outFile, ",\n");
else fprintf(outFile, "\n");
}
fprintf(outFile, " ]\n");
}
fprintf(outFile, " }");
if (i < funcCount - 1) fprintf(outFile, ",\n");
else fprintf(outFile, "\n");
}
fprintf(outFile, " ]\n");
fprintf(outFile, "}\n");
} break;
case XML:
{
fprintf(outFile, "<?xml version=\"1.0\" encoding=\"Windows-1252\" ?>\n");
fprintf(outFile, "<raylibAPI>\n");
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");
fprintf(outFile, " <Structs count=\"%i\">\n", structCount);
for (int i = 0; i < structCount; i++)
{
fprintf(outFile, " <Struct name=\"%s\" fieldCount=\"%i\" desc=\"%s\">\n", structs[i].name, structs[i].fieldCount, structs[i].desc);
for (int f = 0; f < structs[i].fieldCount; f++)
{
fprintf(outFile, " <Field type=\"%s\" name=\"%s\" desc=\"%s\" />\n", structs[i].fieldType[f], structs[i].fieldName[f], structs[i].fieldDesc[f]);
}
fprintf(outFile, " </Struct>\n");
}
fprintf(outFile, " </Structs>\n");
fprintf(outFile, " <Aliases count=\"%i\">\n", aliasCount);
for (int i = 0; i < aliasCount; i++)
{
fprintf(outFile, " <Alias type=\"%s\" name=\"%s\" desc=\"%s\" />\n", aliases[i].name, aliases[i].type, aliases[i].desc);
}
fprintf(outFile, " </Aliases>\n");
fprintf(outFile, " <Enums count=\"%i\">\n", enumCount);
for (int i = 0; i < enumCount; i++)
{
fprintf(outFile, " <Enum name=\"%s\" valueCount=\"%i\" desc=\"%s\">\n", enums[i].name, enums[i].valueCount, enums[i].desc);
for (int v = 0; v < enums[i].valueCount; v++)
{
fprintf(outFile, " <Value name=\"%s\" integer=\"%i\" desc=\"%s\" />\n", enums[i].valueName[v], enums[i].valueInteger[v], enums[i].valueDesc[v]);
}
fprintf(outFile, " </Enum>\n");
}
fprintf(outFile, " </Enums>\n");
fprintf(outFile, " <Callbacks count=\"%i\">\n", callbackCount);
for (int i = 0; i < callbackCount; i++)
{
fprintf(outFile, " <Callback name=\"%s\" retType=\"%s\" paramCount=\"%i\" desc=\"%s\">\n", callbacks[i].name, callbacks[i].retType, callbacks[i].paramCount, callbacks[i].desc);
for (int p = 0; p < callbacks[i].paramCount; p++)
{
fprintf(outFile, " <Param type=\"%s\" name=\"%s\" desc=\"%s\" />\n", callbacks[i].paramType[p], callbacks[i].paramName[p], callbacks[i].paramDesc[p]);
}
fprintf(outFile, " </Callback>\n");
}
fprintf(outFile, " </Callbacks>\n");
fprintf(outFile, " <Functions count=\"%i\">\n", funcCount);
for (int i = 0; i < funcCount; i++)
{
fprintf(outFile, " <Function name=\"%s\" retType=\"%s\" paramCount=\"%i\" desc=\"%s\">\n", funcs[i].name, funcs[i].retType, funcs[i].paramCount, funcs[i].desc);
for (int p = 0; p < funcs[i].paramCount; p++)
{
fprintf(outFile, " <Param type=\"%s\" name=\"%s\" desc=\"%s\" />\n", funcs[i].paramType[p], funcs[i].paramName[p], funcs[i].paramDesc[p]);
}
fprintf(outFile, " </Function>\n");
}
fprintf(outFile, " </Functions>\n");
fprintf(outFile, "</raylibAPI>\n");
} break;
case LUA:
{
fprintf(outFile, "return {\n");
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");
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");
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");
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");
fprintf(outFile, " callbacks = {\n");
for (int i = 0; i < callbackCount; i++)
{
fprintf(outFile, " {\n");
fprintf(outFile, " name = \"%s\",\n", callbacks[i].name);
fprintf(outFile, " description = \"%s\",\n", EscapeBackslashes(callbacks[i].desc));
fprintf(outFile, " returnType = \"%s\"", callbacks[i].retType);
if (callbacks[i].paramCount == 0) fprintf(outFile, "\n");
else
{
fprintf(outFile, ",\n params = {\n");
for (int p = 0; p < callbacks[i].paramCount; p++)
{
fprintf(outFile, " {type = \"%s\", name = \"%s\"}", callbacks[i].paramType[p], callbacks[i].paramName[p]);
if (p < callbacks[i].paramCount - 1) fprintf(outFile, ",\n");
else fprintf(outFile, "\n");
}
fprintf(outFile, " }\n");
}
fprintf(outFile, " }");
if (i < callbackCount - 1) fprintf(outFile, ",\n");
else fprintf(outFile, "\n");
}
fprintf(outFile, " },\n");
fprintf(outFile, " functions = {\n");
for (int i = 0; i < funcCount; i++)
{
fprintf(outFile, " {\n");
fprintf(outFile, " name = \"%s\",\n", funcs[i].name);
fprintf(outFile, " description = \"%s\",\n", EscapeBackslashes(funcs[i].desc));
fprintf(outFile, " returnType = \"%s\"", funcs[i].retType);
if (funcs[i].paramCount == 0) fprintf(outFile, "\n");
else
{
fprintf(outFile, ",\n params = {\n");
for (int p = 0; p < funcs[i].paramCount; p++)
{
fprintf(outFile, " {type = \"%s\", name = \"%s\"}", funcs[i].paramType[p], funcs[i].paramName[p]);
if (p < funcs[i].paramCount - 1) fprintf(outFile, ",\n");
else fprintf(outFile, "\n");
}
fprintf(outFile, " }\n");
}
fprintf(outFile, " }");
if (i < funcCount - 1) fprintf(outFile, ",\n");
else fprintf(outFile, "\n");
}
fprintf(outFile, " }\n");
fprintf(outFile, "}\n");
} break;
case CODE:
default: break;
}
fclose(outFile);
}