diff options
| author | Ray <[email protected]> | 2021-06-13 16:34:51 +0200 |
|---|---|---|
| committer | Ray <[email protected]> | 2021-06-13 16:34:51 +0200 |
| commit | d875891a3c2621ab40733ca3569eca9e054a6506 (patch) | |
| tree | d7568f28238e7ef38c75b7efc5a57a6face50eb6 /parser/raylib_parser.c | |
| parent | 3e68059556f628a172292ec99389fe2fbd820716 (diff) | |
| download | raylib-d875891a3c2621ab40733ca3569eca9e054a6506.tar.gz raylib-d875891a3c2621ab40733ca3569eca9e054a6506.zip | |
Improved raylib parser to export data as XML
- Improved command-line
- Added XML support
- Added sample outputs: DEFAULT, JSON, XML
- Reviewed LoadFileText() bug
- Removed trailing spaces
Diffstat (limited to 'parser/raylib_parser.c')
| -rw-r--r-- | parser/raylib_parser.c | 698 |
1 files changed, 440 insertions, 258 deletions
diff --git a/parser/raylib_parser.c b/parser/raylib_parser.c index f2f3109f..e38dde67 100644 --- a/parser/raylib_parser.c +++ b/parser/raylib_parser.c @@ -1,35 +1,35 @@ /********************************************************************************************** - raylib parser - raylib header parser + raylib API parser + + This parser scans raylib.h to get API information about structs, enums and functions. + All data is divided into pieces, usually as strings. The following types are used for data: - This parser scans raylib.h to get information about structs, enums and functions. - All data is separated into parts, usually as strings. The following types are used for data: - - struct FunctionInfo - struct StructInfo - struct EnumInfo - CONSTRAINTS: - - This parser is specifically designed to work with raylib.h, so, it has some constraints: - + CONSTRAINTS: + + This parser is specifically designed to work with raylib.h, so, it has some constraints: + - Functions are expected as a single line with the following structure: <retType> <name>(<paramType[0]> <paramName[0]>, <paramType[1]> <paramName[1]>); <desc> Be careful with functions broken into several lines, it breaks the process! - + - Structures are expected as several lines with the following form: - + <desc> typedef struct <name> { <fieldType[0]> <fieldName[0]>; <fieldDesc[0]> <fieldType[1]> <fieldName[1]>; <fieldDesc[1]> <fieldType[2]> <fieldName[2]>; <fieldDesc[2]> } <name>; - + - Enums are expected as several lines with the following form: - + <desc> typedef enum { <valueName[0]> = <valueInteger[0]>, <valueDesc[0]> @@ -37,14 +37,16 @@ <valueName[2]>, <valueDesc[2]> <valueName[3]> <valueDesc[3]> } <name>; - - NOTE: Multiple options are supported: + + NOTE: Multiple options are supported for enums: - If value is not provided, (<valueInteger[i -1]> + 1) is assigned - Value description can be provided or not - - 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. + + OTHER NOTES: + + - This parser could work with other C header files if mentioned constraints are followed. + + - This parser does not require <string.h> library, all data is parsed directly from char buffers. LICENSE: zlib/libpng @@ -55,6 +57,8 @@ **********************************************************************************************/ +#define _CRT_SECURE_NO_WARNINGS + #include <stdlib.h> // Required for: malloc(), calloc(), realloc(), free(), atoi(), strtol() #include <stdio.h> // Required for: printf(), fopen(), fseek(), ftell(), fread(), fclose() #include <stdbool.h> // Required for: bool @@ -66,8 +70,6 @@ #define MAX_LINE_LENGTH 512 // Maximum length of one line (including comments) #define MAX_STRUCT_LINE_LENGTH 2048 // Maximum length of one struct (multiple lines) -enum OutputFormat { PlainText, JSON }; // Which format the header information should be in - //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -79,6 +81,7 @@ typedef struct FunctionInfo { int paramCount; // Number of function parameters char paramType[12][32]; // Parameters type (max: 12 parameters) char paramName[12][32]; // Parameters name (max: 12 parameters) + char paramDesc[12][8]; // Parameters description (max: 12 parameters) } FunctionInfo; // Struct info data @@ -101,59 +104,70 @@ typedef struct EnumInfo { char valueDesc[128][64]; // Value description (max: 128 values) } EnumInfo; +// Output format for parsed data +typedef enum { DEFAULT = 0, JSON, XML } OutputFormat; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static int funcCount = 0; +static int structCount = 0; +static int enumCount = 0; +static FunctionInfo *funcs = NULL; +static StructInfo *structs = NULL; +static EnumInfo *enums = NULL; + +// Command line variables +static char inFileName[512] = { 0 }; // Input file name (required in case of provided through CLI) +static char outFileName[512] = { 0 }; // Output file name (required for file save/export) +static int outputFormat = DEFAULT; + //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- -char *LoadFileText(const char *fileName, int *length); -char **GetTextLines(const char *buffer, int length, int *linesCount); -void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name); -bool IsTextEqual(const char *text1, const char *text2, unsigned int count); -void MemoryCopy(void *dest, const void *src, unsigned int count); -char* CharReplace(char* text, char search, char replace); - -// Main entry point +static void ShowCommandLineInfo(void); // Show command line usage info +static void ProcessCommandLine(int argc, char *argv[]); // Process command line input + +static char *LoadFileText(const char *fileName, int *length); +static char **GetTextLines(const char *buffer, int length, int *linesCount); +static void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name); +static unsigned int TextLength(const char *text); // Get text length in bytes, check for \0 character +static bool IsTextEqual(const char *text1, const char *text2, unsigned int count); +static void MemoryCopy(void *dest, const void *src, unsigned int count); +static char* CharReplace(char* text, char search, char replace); + +static void ExportParsedData(const char *fileName, int format); // Export parsed data in desired format + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ int main(int argc, char* argv[]) { - // Help - if (argv[1] != NULL && IsTextEqual(argv[1], "--help", 6)) { - printf("Usage:\n"); - printf(" raylib_parser [--json]\n"); - return 0; - } + if (argc > 1) ProcessCommandLine(argc, argv); - // Allow changing the output format. - int outputFormat = 0; - if (argv[1] != NULL && IsTextEqual(argv[1], "--json", 6)) { - outputFormat = JSON; - } + if (inFileName[0] == '\0') MemoryCopy(inFileName, "../src/raylib.h\0", 16); int length = 0; - char *buffer = LoadFileText("../src/raylib.h", &length); - + char *buffer = LoadFileText(inFileName, &length); + // Preprocess buffer to get separate lines // NOTE: GetTextLines() also removes leading spaces/tabs int linesCount = 0; char **lines = GetTextLines(buffer, length, &linesCount); - - // Print buffer lines - //for (int i = 0; i < linesCount; i++) printf("_%s_\n", lines[i]); - + // Function lines pointers, selected from buffer "lines" - int funcCount = 0; char **funcLines = (char **)malloc(MAX_FUNCS_TO_PARSE*sizeof(char *)); // Structs data (multiple lines), selected from "buffer" - int structCount = 0; char **structLines = (char **)malloc(MAX_STRUCTS_TO_PARSE*sizeof(char *)); for (int i = 0; i < MAX_STRUCTS_TO_PARSE; i++) structLines[i] = (char *)calloc(MAX_STRUCT_LINE_LENGTH, sizeof(char)); - + // Enums lines pointers, selected from buffer "lines" - int enumCount = 0; int *enumLines = (int *)malloc(MAX_ENUMS_TO_PARSE*sizeof(int)); - + // Prepare required lines for parsing //-------------------------------------------------------------------------------------------------- - + // Read function lines for (int i = 0; i < linesCount; i++) { @@ -165,9 +179,6 @@ int main(int argc, char* argv[]) funcCount++; } } - - // Print function lines - //for (int i = 0; i < funcCount; i++) printf("%s\n", funcLines[i]); // Read structs data (multiple lines, read directly from buffer) // TODO: Parse structs data from "lines" instead of "buffer" -> Easier to get struct definition @@ -179,9 +190,9 @@ int main(int argc, char* argv[]) { int j = 0; bool validStruct = false; - - // WARNING: Typedefs between types: typedef Vector4 Quaternion; - + + // WARNING: Typedefs between types: typedef Vector4 Quaternion; + for (int c = 0; c < 128; c++) { if (buffer[i + c] == '{') @@ -191,13 +202,13 @@ int main(int argc, char* argv[]) } else if (buffer[i + c] == ';') { - // Not valid struct: + // Not valid struct: // i.e typedef struct rAudioBuffer rAudioBuffer; -> Typedef and forward declaration i += c; break; } } - + if (validStruct) { while (buffer[i + j] != '}') @@ -223,7 +234,7 @@ int main(int argc, char* argv[]) } } } - + // Read enum lines for (int i = 0; i < linesCount; i++) { @@ -236,17 +247,17 @@ int main(int argc, char* argv[]) enumCount++; } } - + // At this point we have all raylib structs, enums, functions lines data to start parsing - + free(buffer); // Unload text buffer // Parsing raylib data //-------------------------------------------------------------------------------------------------- // Structs info data - StructInfo *structs = (StructInfo *)calloc(MAX_STRUCTS_TO_PARSE, sizeof(StructInfo)); - + structs = (StructInfo *)calloc(MAX_STRUCTS_TO_PARSE, sizeof(StructInfo)); + for (int i = 0; i < structCount; i++) { int structLineOffset = 0; @@ -254,52 +265,52 @@ int main(int argc, char* argv[]) // Get struct name: typedef struct name { for (int c = 15; c < 64 + 15; c++) { - if (structLines[i][c] == '{') + if (structLines[i][c] == '{') { structLineOffset = c + 2; - + MemoryCopy(structs[i].name, &structLines[i][15], c - 15 - 1); break; } } - + // Get struct fields and count them -> fields finish with ; int j = 0; while (structLines[i][structLineOffset + j] != '}') { // WARNING: Some structs have empty spaces and comments -> OK, processed - + int fieldStart = 0; if ((structLines[i][structLineOffset + j] != ' ') && (structLines[i][structLineOffset + j] != '\n')) fieldStart = structLineOffset + j; - + if (fieldStart != 0) { // Scan one field line int c = 0; int fieldEndPos = 0; char fieldLine[256] = { 0 }; - + while (structLines[i][structLineOffset + j] != '\n') { if (structLines[i][structLineOffset + j] == ';') fieldEndPos = c; fieldLine[c] = structLines[i][structLineOffset + j]; c++; j++; } - + if (fieldLine[0] != '/') // Field line is not a comment { //printf("Struct field: %s_\n", fieldLine); // OK! - + // Get struct field type and name GetDataTypeAndName(fieldLine, fieldEndPos, structs[i].fieldType[structs[i].fieldCount], structs[i].fieldName[structs[i].fieldCount]); - + // Get the field description // We start skipping spaces in front of description comment int descStart = fieldEndPos; while ((fieldLine[descStart] != '/') && (fieldLine[descStart] != '\0')) descStart++; - + int k = 0; - while ((fieldLine[descStart + k] != '\0') && (fieldLine[descStart + k] != '\n')) + while ((fieldLine[descStart + k] != '\0') && (fieldLine[descStart + k] != '\n')) { structs[i].fieldDesc[structs[i].fieldCount][k] = fieldLine[descStart + k]; k++; @@ -313,17 +324,17 @@ int main(int argc, char* argv[]) } } - + for (int i = 0; i < MAX_STRUCTS_TO_PARSE; i++) free(structLines[i]); free(structLines); - + // Enum info data - EnumInfo *enums = (EnumInfo *)calloc(MAX_ENUMS_TO_PARSE, sizeof(EnumInfo)); - + enums = (EnumInfo *)calloc(MAX_ENUMS_TO_PARSE, sizeof(EnumInfo)); + for (int i = 0; i < enumCount; i++) { // TODO: Get enum description from lines[enumLines[i] - 1] - + for (int j = 1; j < 256; j++) // Maximum number of lines following enum first line { char *linePtr = lines[enumLines[i] + j]; @@ -336,20 +347,20 @@ int main(int argc, char* argv[]) //ENUM_VALUE_NAME = 99 //ENUM_VALUE_NAME = 99, //ENUM_VALUE_NAME = 0x00000040, // Value description - + // We start reading the value name int c = 0; - while ((linePtr[c] != ',') && - (linePtr[c] != ' ') && + while ((linePtr[c] != ',') && + (linePtr[c] != ' ') && (linePtr[c] != '=') && (linePtr[c] != '\0')) { enums[i].valueName[enums[i].valueCount][c] = linePtr[c]; c++; } - // After the name we can have: + // After the name we can have: // '=' -> value is provided // ',' -> value is equal to previous + 1, there could be a description if not '\0' // ' ' -> value is equal to previous + 1, there could be a description if not '\0' // '\0' -> value is equal to previous + 1 - + // Let's start checking if the line is not finished if ((linePtr[c] != ',') && (linePtr[c] != '\0')) { @@ -357,7 +368,7 @@ int main(int argc, char* argv[]) // '=' -> value is provided // ' ' -> value is equal to previous + 1, there could be a description if not '\0' bool foundValue = false; - while (linePtr[c] != '\0') + while (linePtr[c] != '\0') { if (linePtr[c] == '=') { foundValue = true; break; } c++; @@ -367,64 +378,64 @@ int main(int argc, char* argv[]) { if (linePtr[c + 1] == ' ') c += 2; else c++; - + // Parse integer value int n = 0; char integer[16] = { 0 }; - - while ((linePtr[c] != ',') && (linePtr[c] != ' ') && (linePtr[c] != '\0')) + + 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); - + // TODO: Parse value description if any } else enums[i].valueInteger[enums[i].valueCount] = (enums[i].valueInteger[enums[i].valueCount - 1] + 1); enums[i].valueCount++; } - else if (linePtr[0] == '}') + else if (linePtr[0] == '}') { // Get enum name from typedef int c = 0; while (linePtr[2 + c] != ';') { enums[i].name[c] = linePtr[2 + c]; c++; } - + break; // Enum ended, break for() loop } } } - + // Functions info data - FunctionInfo *funcs = (FunctionInfo *)calloc(MAX_FUNCS_TO_PARSE, sizeof(FunctionInfo)); - + funcs = (FunctionInfo *)calloc(MAX_FUNCS_TO_PARSE, sizeof(FunctionInfo)); + for (int i = 0; i < funcCount; i++) { int funcParamsStart = 0; int funcEnd = 0; - + // Get return type and function name from func line for (int c = 0; (c < MAX_LINE_LENGTH) && (funcLines[i][c] != '\n'); c++) { if (funcLines[i][c] == '(') // Starts function parameters { funcParamsStart = c + 1; - + // At this point we have function return type and function name char funcRetTypeName[128] = { 0 }; int funcRetTypeNameLen = c - 6; // Substract "RLAPI " MemoryCopy(funcRetTypeName, &funcLines[i][6], funcRetTypeNameLen); - + GetDataTypeAndName(funcRetTypeName, funcRetTypeNameLen, funcs[i].retType, funcs[i].name); break; } } - + // Get parameters from func line for (int c = funcParamsStart; c < MAX_LINE_LENGTH; c++) { @@ -434,9 +445,9 @@ int main(int argc, char* argv[]) char funcParamTypeName[128] = { 0 }; int funcParamTypeNameLen = c - funcParamsStart; MemoryCopy(funcParamTypeName, &funcLines[i][funcParamsStart], funcParamTypeNameLen); - + GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]); - + funcParamsStart = c + 1; if (funcLines[i][c + 1] == ' ') funcParamsStart += 1; funcs[i].paramCount++; // Move to next parameter @@ -444,170 +455,54 @@ int main(int argc, char* argv[]) else if (funcLines[i][c] == ')') { funcEnd = c + 2; - + // Check if previous word is void if ((funcLines[i][c - 4] == 'v') && (funcLines[i][c - 3] == 'o') && (funcLines[i][c - 2] == 'i') && (funcLines[i][c - 1] == 'd')) break; - + // Get parameter type + name, extract info char funcParamTypeName[128] = { 0 }; int funcParamTypeNameLen = c - funcParamsStart; MemoryCopy(funcParamTypeName, &funcLines[i][funcParamsStart], funcParamTypeNameLen); - + GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]); funcs[i].paramCount++; // Move to next parameter break; } } - + // Get function description for (int c = funcEnd; c < MAX_LINE_LENGTH; c++) { - if (funcLines[i][c] == '/') + if (funcLines[i][c] == '/') { MemoryCopy(funcs[i].desc, &funcLines[i][c], 127); // WARNING: Size could be too long for funcLines[i][c]? break; } } } - - for (int i = 0; i < linesCount; i++) free(lines[i]); + + //for (int i = 0; i < linesCount; i++) free(lines[i]); free(lines); free(funcLines); - + // At this point, all raylib data has been parsed! //----------------------------------------------------------------------------------------- // structs[] -> We have all the structs decomposed into pieces for further analysis // enums[] -> We have all the enums decomposed into pieces for further analysis // funcs[] -> We have all the functions decomposed into pieces for further analysis - - // Print structs info - switch (outputFormat) - { - case PlainText: { - printf("\nStructures found: %i\n\n", structCount); - for (int i = 0; i < structCount; i++) - { - printf("Struct %02i: %s (%i fields)\n", i + 1, structs[i].name, structs[i].fieldCount); - //printf("Description: %s\n", structs[i].desc); - for (int f = 0; f < structs[i].fieldCount; f++) printf(" Fields %i: %s %s %s\n", f + 1, structs[i].fieldType[f], structs[i].fieldName[f], structs[i].fieldDesc[f]); - } - // Print enums info - printf("\nEnums found: %i\n\n", enumCount); - for (int i = 0; i < enumCount; i++) - { - printf("Enum %02i: %s (%i values)\n", i + 1, enums[i].name, enums[i].valueCount); - //printf("Description: %s\n", enums[i].desc); - for (int e = 0; e < enums[i].valueCount; e++) printf(" Value %s: %i\n", enums[i].valueName[e], enums[i].valueInteger[e]); - } + // Process input file to output + if (outFileName[0] == '\0') MemoryCopy(outFileName, "raylib_api.txt\0", 15); - // Print function info - printf("\nFunctions found: %i\n\n", funcCount); - for (int i = 0; i < funcCount; i++) - { - printf("Function %03i: %s() (%i input parameters)\n", i + 1, funcs[i].name, funcs[i].paramCount); - printf(" Description: %s\n", funcs[i].desc); - printf(" Return type: %s\n", funcs[i].retType); - for (int p = 0; p < funcs[i].paramCount; p++) printf(" Param %i: %s (type: %s)\n", p + 1, funcs[i].paramName[p], funcs[i].paramType[p]); - if (funcs[i].paramCount == 0) printf(" No input parameters\n"); - } - } break; - case JSON: { - printf("{\n"); - printf(" \"structs\": [\n"); - for (int i = 0; i < structCount; i++) - { - printf(" {\n"); - printf(" \"name\": \"%s\",\n", structs[i].name); - printf(" \"description\": \"%s\",\n", structs[i].desc); - printf(" \"fields\": [\n"); - for (int f = 0; f < structs[i].fieldCount; f++) - { - printf(" {\n"); - printf(" \"name\": \"%s\",\n", structs[i].fieldName[f]), - printf(" \"type\": \"%s\",\n", structs[i].fieldType[f]), - printf(" \"description\": \"%s\"\n", structs[i].fieldDesc[f] + 3), - printf(" }"); - if (f < structs[i].fieldCount - 1) - printf(",\n"); - else - printf("\n"); - } - printf(" ]\n"); - printf(" }"); - if (i < structCount - 1) - printf(",\n"); - else - printf("\n"); - } - printf(" ],\n"); - - // Print enums info - printf(" \"enums\": [\n"); - for (int i = 0; i < enumCount; i++) - { - printf(" {\n"); - printf(" \"name\": \"%s\",\n", enums[i].name); - printf(" \"description\": \"%s\",\n", enums[i].desc + 3); - printf(" \"values\": [\n"); - for (int e = 0; e < enums[i].valueCount; e++) - { - printf(" {\n"); - printf(" \"name\": \"%s\",\n", enums[i].valueName[e]), - printf(" \"value\": %i,\n", enums[i].valueInteger[e]), - printf(" \"description\": \"%s\"\n", enums[i].valueDesc[e] + 3), - printf(" }"); - if (e < enums[i].valueCount - 1) - printf(",\n"); - else - printf("\n"); - } - printf(" ]\n"); - printf(" }"); - if (i < enumCount - 1) - printf(",\n"); - else - printf("\n"); - } - printf(" ],\n"); - - // Print function info - printf(" \"functions\": [\n"); - for (int i = 0; i < funcCount; i++) - { - printf(" {\n"); - printf(" \"name\": \"%s\",\n", funcs[i].name); - printf(" \"description\": \"%s\",\n", CharReplace(funcs[i].desc, '\\', ' ') + 3); - printf(" \"returnType\": \"%s\"", funcs[i].retType); + 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"); - if (funcs[i].paramCount == 0) - printf("\n"); - else - { - printf(",\n \"params\": {\n"); - for (int p = 0; p < funcs[i].paramCount; p++) - { - printf(" \"%s\": \"%s\"", funcs[i].paramName[p], funcs[i].paramType[p]); - if (p < funcs[i].paramCount - 1) - printf(",\n"); - else - printf("\n"); - } - printf(" }\n"); - } - printf(" }"); + ExportParsedData(outFileName, outputFormat); - if (i < funcCount - 1) - printf(",\n"); - else - printf("\n"); - } - printf(" ]\n"); - printf("}\n"); - } break; - } - free(funcs); free(structs); free(enums); @@ -616,10 +511,84 @@ int main(int argc, char* argv[]) //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- +// Show command line usage info +static void ShowCommandLineInfo(void) +{ + printf("\n//////////////////////////////////////////////////////////////////////////////////\n"); + printf("// //\n"); + printf("// raylib API parser //\n"); + printf("// //\n"); + printf("// more info and bugs-report: github.com/raysan5/raylib/parser //\n"); + printf("// //\n"); + printf("// Copyright (c) 2021 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, .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\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"); +} + +// 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(); + } + else if (IsTextEqual(argv[i], "-i", 2) || IsTextEqual(argv[i], "--input", 7)) + { + // Check for valid argument and valid file extension + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + MemoryCopy(inFileName, argv[i + 1], TextLength(argv[i + 1])); // Read input filename + i++; + } + else printf("WARNING: No input file provided\n"); + } + else if (IsTextEqual(argv[i], "-o", 2) || IsTextEqual(argv[i], "--output", 8)) + { + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + MemoryCopy(outFileName, argv[i + 1], TextLength(argv[i + 1])); // Read output filename + i++; + } + else printf("WARNING: No output file provided\n"); + } + else if (IsTextEqual(argv[i], "-f", 2) || IsTextEqual(argv[i], "--format", 8)) + { + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + if (IsTextEqual(argv[i + 1], "DEFAULT\0", 8)) outputFormat = DEFAULT; + else if (IsTextEqual(argv[i + 1], "JSON\0", 5)) outputFormat = JSON; + else if (IsTextEqual(argv[i + 1], "XML\0", 4)) outputFormat = XML; + } + else printf("WARNING: No format parameters provided\n"); + } + } +} // Load text data from file, returns a '\0' terminated string // NOTE: text chars array should be freed manually -char *LoadFileText(const char *fileName, int *length) +static char *LoadFileText(const char *fileName, int *length) { char *text = NULL; @@ -638,14 +607,17 @@ char *LoadFileText(const char *fileName, int *length) if (size > 0) { - *length = size; - text = (char *)calloc((size + 1), sizeof(char)); unsigned int count = (unsigned int)fread(text, sizeof(char), size, file); // WARNING: \r\n is converted to \n on reading, so, // read bytes count gets reduced by the number of lines - if (count < (unsigned int)size) text = realloc(text, count + 1); + if (count < (unsigned int)size) + { + text = realloc(text, count + 1); + *length = count; + } + else *length = size; // Zero-terminate the string text[count] = '\0'; @@ -659,47 +631,45 @@ char *LoadFileText(const char *fileName, int *length) } // Get all lines from a text buffer (expecting lines ending with '\n') -char **GetTextLines(const char *buffer, int length, int *linesCount) +static char **GetTextLines(const char *buffer, int length, int *linesCount) { - //#define MAX_LINE_LENGTH 512 - // Get the number of lines in the text int count = 0; for (int i = 0; i < length; i++) if (buffer[i] == '\n') count++; - //printf("Number of text lines in buffer: %i\n", count); - + printf("Number of text lines in buffer: %i\n", count); + // Allocate as many pointers as lines char **lines = (char **)malloc(count*sizeof(char **)); - + char *bufferPtr = (char *)buffer; - + for (int i = 0; (i < count) || (bufferPtr[0] != '\0'); i++) { lines[i] = (char *)calloc(MAX_LINE_LENGTH, sizeof(char)); - + // Remove line leading spaces // Find last index of space/tab character int index = 0; while ((bufferPtr[index] == ' ') || (bufferPtr[index] == '\t')) index++; int j = 0; - while (bufferPtr[index + j] != '\n') + while (bufferPtr[index + j] != '\n') { lines[i][j] = bufferPtr[index + j]; j++; } - + bufferPtr += (index + j + 1); } - + *linesCount = count; return lines; } // Get data type and name from a string containing both // NOTE: Useful to parse function parameters and struct fields -void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name) +static void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name) { for (int k = typeNameLen; k > 0; k--) { @@ -719,8 +689,18 @@ void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char } } +// 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; +} + // Custom memcpy() to avoid <string.h> -void MemoryCopy(void *dest, const void *src, unsigned int count) +static void MemoryCopy(void *dest, const void *src, unsigned int count) { char *srcPtr = (char *)src; char *destPtr = (char *)dest; @@ -729,13 +709,13 @@ void MemoryCopy(void *dest, const void *src, unsigned int count) } // Compare two text strings, requires number of characters to compare -bool IsTextEqual(const char *text1, const char *text2, unsigned int count) +static bool IsTextEqual(const char *text1, const char *text2, unsigned int count) { bool result = true; - - for (unsigned int i = 0; i < count; i++) + + for (unsigned int i = 0; i < count; i++) { - if (text1[i] != text2[i]) + if (text1[i] != text2[i]) { result = false; break; @@ -746,7 +726,7 @@ bool IsTextEqual(const char *text1, const char *text2, unsigned int count) } // Search and replace a character within a string. -char* CharReplace(char* text, char search, char replace) +static char* CharReplace(char* text, char search, char replace) { for (int i = 0; text[i] != '\0'; i++) if (text[i] == search) @@ -758,7 +738,7 @@ char* CharReplace(char* text, char search, char replace) // Replace text string // REQUIRES: strlen(), strstr(), strncpy(), strcpy() -> TODO: Replace by custom implementations! // WARNING: Returned buffer must be freed by the user (if return != NULL) -char *TextReplace(char *text, const char *replace, const char *by) +static char *TextReplace(char *text, const char *replace, const char *by) { // Sanity checks and initialization if (!text || !replace || !by) return NULL; @@ -804,4 +784,206 @@ char *TextReplace(char *text, const char *replace, const char *by) return result; } -*/
\ No newline at end of file +*/ + +// Export parsed data in desired format +static void ExportParsedData(const char *fileName, int format) +{ + FILE *outFile = fopen(fileName, "wt"); + + switch (format) + { + case DEFAULT: + { + // Print structs info + fprintf(outFile, "\nStructures found: %i\n\n", structCount); + for (int i = 0; i < structCount; i++) + { + fprintf(outFile, "Struct %02i: %s (%i fields)\n", i + 1, structs[i].name, structs[i].fieldCount); + fprintf(outFile, " Name: %s\n", structs[i].name); + fprintf(outFile, " Description: %s\n", structs[i].desc + 3); + for (int f = 0; f < structs[i].fieldCount; f++) fprintf(outFile, " Field[%i]: %s %s %s\n", f + 1, structs[i].fieldType[f], structs[i].fieldName[f], structs[i].fieldDesc[f]); + } + + // Print enums info + fprintf(outFile, "\nEnums found: %i\n\n", enumCount); + for (int i = 0; i < enumCount; i++) + { + fprintf(outFile, "Enum %02i: %s (%i values)\n", i + 1, enums[i].name, enums[i].valueCount); + fprintf(outFile, " Name: %s\n", enums[i].name); + fprintf(outFile, " Description: %s\n", enums[i].desc + 3); + for (int e = 0; e < enums[i].valueCount; e++) fprintf(outFile, " Value[%s]: %i\n", enums[i].valueName[e], enums[i].valueInteger[e]); + } + + // Print functions info + fprintf(outFile, "\nFunctions found: %i\n\n", funcCount); + for (int i = 0; i < funcCount; i++) + { + fprintf(outFile, "Function %03i: %s() (%i input parameters)\n", i + 1, funcs[i].name, funcs[i].paramCount); + fprintf(outFile, " Name: %s\n", funcs[i].name); + fprintf(outFile, " Return type: %s\n", funcs[i].retType); + fprintf(outFile, " Description: %s\n", funcs[i].desc + 3); + for (int p = 0; p < funcs[i].paramCount; p++) fprintf(outFile, " Param[%i]: %s (type: %s)\n", p + 1, funcs[i].paramName[p], funcs[i].paramType[p]); + if (funcs[i].paramCount == 0) fprintf(outFile, " No input parameters\n"); + } + } break; + case JSON: + { + fprintf(outFile, "{\n"); + + // Print 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", structs[i].desc); + fprintf(outFile, " \"fields\": [\n"); + for (int f = 0; f < structs[i].fieldCount; f++) + { + fprintf(outFile, " {\n"); + fprintf(outFile, " \"name\": \"%s\",\n", structs[i].fieldName[f]), + fprintf(outFile, " \"type\": \"%s\",\n", structs[i].fieldType[f]), + fprintf(outFile, " \"description\": \"%s\"\n", structs[i].fieldDesc[f] + 3), + 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 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", enums[i].desc + 3); + 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", enums[i].valueDesc[e] + 3), + fprintf(outFile, " }"); + if (e < enums[i].valueCount - 1) fprintf(outFile, ",\n"); + else fprintf(outFile, "\n"); + } + fprintf(outFile, " ]\n"); + fprintf(outFile, " }"); + if (i < enumCount - 1) fprintf(outFile, ",\n"); + else fprintf(outFile, "\n"); + } + fprintf(outFile, " ],\n"); + + // Print 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", CharReplace(funcs[i].desc, '\\', ' ') + 3); + 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, " \"%s\": \"%s\"", funcs[i].paramName[p], funcs[i].paramType[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 XML: + { + // XML format to export data: + /* + <?xml version="1.0" encoding="Windows-1252" ?> + <raylibAPI> + <Structs count=""> + <Struct name="" fieldCount="" desc=""> + <Field type="" name="" desc=""> + <Field type="" name="" desc=""> + </Struct> + <Structs> + <Enums count=""> + <Enum name="" valueCount="" desc=""> + <Value name="" integer="" desc=""> + <Value name="" integer="" desc=""> + </Enum> + </Enums> + <Functions count=""> + <Function name="" retType="" paramCount="" desc=""> + <Param type="" name="" desc="" /> + <Param type="" name="" desc="" /> + </Function> + </Functions> + </raylibAPI> + */ + + fprintf(outFile, "<?xml version=\"1.0\" encoding=\"Windows-1252\" ?>\n"); + fprintf(outFile, "<raylibAPI>\n"); + + // Print structs info + fprintf(outFile, " <Structs count=\"%i\">\n", structCount); + for (int i = 0; i < structCount; i++) + { + fprintf(outFile, " <Struct name=\"%s\" fieldCount=\"%i\" desc=\"%s\">\n", structs[i].name, structs[i].fieldCount, structs[i].desc + 3); + 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] + 3); + } + fprintf(outFile, " </Struct>\n"); + } + fprintf(outFile, " </Structs>\n"); + + // Print enums info + fprintf(outFile, " <Enums count=\"%i\">\n", enumCount); + for (int i = 0; i < enumCount; i++) + { + fprintf(outFile, " <Enum name=\"%s\" valueCount=\"%i\" desc=\"%s\">\n", enums[i].name, enums[i].valueCount, enums[i].desc + 3); + 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] + 3); + } + fprintf(outFile, " </Enum>\n"); + } + fprintf(outFile, " </Enums>\n"); + + // Print functions info + fprintf(outFile, " <Functions count=\"%i\">\n", funcCount); + for (int i = 0; i < funcCount; i++) + { + fprintf(outFile, " <Function name=\"%s\" retType=\"%s\" paramCount=\"%i\" desc=\"%s\">\n", funcs[i].name, funcs[i].retType, funcs[i].paramCount, funcs[i].desc + 3); + 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] + 3); + } + fprintf(outFile, " </Function>\n"); + } + fprintf(outFile, " </Functions>\n"); + + fprintf(outFile, "</raylibAPI>\n"); + + } break; + default: break; + } + + fclose(outFile); +} |
