raylib_parser.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. /**********************************************************************************************
  2. raylib parser - raylib header parser
  3. This parser scans raylib.h to get information about structs, enums and functions.
  4. All data is separated into parts, usually as strings. The following types are used for data:
  5. - struct FunctionInfo
  6. - struct StructInfo
  7. - struct EnumInfo
  8. CONSTRAINTS:
  9. This parser is specifically designed to work with raylib.h, so, it has some constraints:
  10. - Functions are expected as a single line with the following structure:
  11. <retType> <name>(<paramType[0]> <paramName[0]>, <paramType[1]> <paramName[1]>); <desc>
  12. Be careful with functions broken into several lines, it breaks the process!
  13. - Structures are expected as several lines with the following form:
  14. <desc>
  15. typedef struct <name> {
  16. <fieldType[0]> <fieldName[0]>; <fieldDesc[0]>
  17. <fieldType[1]> <fieldName[1]>; <fieldDesc[1]>
  18. <fieldType[2]> <fieldName[2]>; <fieldDesc[2]>
  19. } <name>;
  20. - Enums are expected as several lines with the following form:
  21. <desc>
  22. typedef enum {
  23. <valueName[0]> = <valueInteger[0]>, <valueDesc[0]>
  24. <valueName[1]>,
  25. <valueName[2]>, <valueDesc[2]>
  26. <valueName[3]> <valueDesc[3]>
  27. } <name>;
  28. NOTE: Multiple options are supported:
  29. - If value is not provided, (<valueInteger[i -1]> + 1) is assigned
  30. - Value description can be provided or not
  31. This parser could work with other C header files if mentioned constraints are followed.
  32. This parser does not require <string.h> library, all data is parsed directly from char buffers.
  33. LICENSE: zlib/libpng
  34. raylib-parser is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  35. BSD-like license that allows static linking with closed source software:
  36. Copyright (c) 2021 Ramon Santamaria (@raysan5)
  37. **********************************************************************************************/
  38. #include <stdlib.h> // Required for: malloc(), calloc(), realloc(), free(), atoi(), strtol()
  39. #include <stdio.h> // Required for: printf(), fopen(), fseek(), ftell(), fread(), fclose()
  40. #include <stdbool.h> // Required for: bool
  41. #define MAX_FUNCS_TO_PARSE 512 // Maximum number of functions to parse
  42. #define MAX_STRUCTS_TO_PARSE 64 // Maximum number of structures to parse
  43. #define MAX_ENUMS_TO_PARSE 64 // Maximum number of enums to parse
  44. #define MAX_LINE_LENGTH 512 // Maximum length of one line (including comments)
  45. #define MAX_STRUCT_LINE_LENGTH 2048 // Maximum length of one struct (multiple lines)
  46. enum OutputFormat { PlainText, JSON }; // Which format the header information should be in
  47. //----------------------------------------------------------------------------------
  48. // Types and Structures Definition
  49. //----------------------------------------------------------------------------------
  50. // Function info data
  51. typedef struct FunctionInfo {
  52. char name[64]; // Function name
  53. char desc[128]; // Function description (comment at the end)
  54. char retType[32]; // Return value type
  55. int paramCount; // Number of function parameters
  56. char paramType[12][32]; // Parameters type (max: 12 parameters)
  57. char paramName[12][32]; // Parameters name (max: 12 parameters)
  58. } FunctionInfo;
  59. // Struct info data
  60. typedef struct StructInfo {
  61. char name[64]; // Struct name
  62. char desc[64]; // Struct type description
  63. int fieldCount; // Number of fields in the struct
  64. char fieldType[16][32]; // Field type (max: 16 fields)
  65. char fieldName[16][32]; // Field name (max: 16 fields)
  66. char fieldDesc[16][128]; // Field description (max: 16 fields)
  67. } StructInfo;
  68. // Enum info data
  69. typedef struct EnumInfo {
  70. char name[64]; // Enum name
  71. char desc[64]; // Enum description
  72. int valueCount; // Number of values in enumerator
  73. char valueName[128][64]; // Value name definition (max: 128 values)
  74. int valueInteger[128]; // Value integer (max: 128 values)
  75. char valueDesc[128][64]; // Value description (max: 128 values)
  76. } EnumInfo;
  77. //----------------------------------------------------------------------------------
  78. // Module Functions Declaration
  79. //----------------------------------------------------------------------------------
  80. char *LoadFileText(const char *fileName, int *length);
  81. char **GetTextLines(const char *buffer, int length, int *linesCount);
  82. void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name);
  83. bool IsTextEqual(const char *text1, const char *text2, unsigned int count);
  84. void MemoryCopy(void *dest, const void *src, unsigned int count);
  85. char* CharReplace(char* text, char search, char replace);
  86. // Main entry point
  87. int main(int argc, char* argv[])
  88. {
  89. // Help
  90. if (IsTextEqual(argv[1], "--help", 6)) {
  91. printf("Usage:\n");
  92. printf(" raylib_parser [--json]\n");
  93. return 0;
  94. }
  95. // Allow changing the output format.
  96. int outputFormat = 0;
  97. if (IsTextEqual(argv[1], "--json", 6)) {
  98. outputFormat = JSON;
  99. }
  100. int length = 0;
  101. char *buffer = LoadFileText("../src/raylib.h", &length);
  102. // Preprocess buffer to get separate lines
  103. // NOTE: GetTextLines() also removes leading spaces/tabs
  104. int linesCount = 0;
  105. char **lines = GetTextLines(buffer, length, &linesCount);
  106. // Print buffer lines
  107. //for (int i = 0; i < linesCount; i++) printf("_%s_\n", lines[i]);
  108. // Function lines pointers, selected from buffer "lines"
  109. int funcCount = 0;
  110. char **funcLines = (char **)malloc(MAX_FUNCS_TO_PARSE*sizeof(char *));
  111. // Structs data (multiple lines), selected from "buffer"
  112. int structCount = 0;
  113. char **structLines = (char **)malloc(MAX_STRUCTS_TO_PARSE*sizeof(char *));
  114. for (int i = 0; i < MAX_STRUCTS_TO_PARSE; i++) structLines[i] = (char *)calloc(MAX_STRUCT_LINE_LENGTH, sizeof(char));
  115. // Enums lines pointers, selected from buffer "lines"
  116. int enumCount = 0;
  117. int *enumLines = (int *)malloc(MAX_ENUMS_TO_PARSE*sizeof(int));
  118. // Prepare required lines for parsing
  119. //--------------------------------------------------------------------------------------------------
  120. // Read function lines
  121. for (int i = 0; i < linesCount; i++)
  122. {
  123. // Read function line (starting with "RLAPI")
  124. if (IsTextEqual(lines[i], "RLAPI", 5))
  125. {
  126. // Keep a pointer to the function line
  127. funcLines[funcCount] = lines[i];
  128. funcCount++;
  129. }
  130. }
  131. // Print function lines
  132. //for (int i = 0; i < funcCount; i++) printf("%s\n", funcLines[i]);
  133. // Read structs data (multiple lines, read directly from buffer)
  134. // TODO: Parse structs data from "lines" instead of "buffer" -> Easier to get struct definition
  135. for (int i = 0; i < length; i++)
  136. {
  137. // Read struct data (starting with "typedef struct", ending with '} ... ;')
  138. // NOTE: We read it directly from buffer
  139. if (IsTextEqual(buffer + i, "typedef struct", 14))
  140. {
  141. int j = 0;
  142. bool validStruct = false;
  143. // WARNING: Typedefs between types: typedef Vector4 Quaternion;
  144. for (int c = 0; c < 128; c++)
  145. {
  146. if (buffer[i + c] == '{')
  147. {
  148. validStruct = true;
  149. break;
  150. }
  151. else if (buffer[i + c] == ';')
  152. {
  153. // Not valid struct:
  154. // i.e typedef struct rAudioBuffer rAudioBuffer; -> Typedef and forward declaration
  155. i += c;
  156. break;
  157. }
  158. }
  159. if (validStruct)
  160. {
  161. while (buffer[i + j] != '}')
  162. {
  163. structLines[structCount][j] = buffer[i + j];
  164. j++;
  165. }
  166. while (buffer[i + j] != '}')
  167. {
  168. structLines[structCount][j] = buffer[i + j];
  169. j++;
  170. }
  171. while (buffer[i + j] != '\n')
  172. {
  173. structLines[structCount][j] = buffer[i + j];
  174. j++;
  175. }
  176. i += j;
  177. structCount++;
  178. }
  179. }
  180. }
  181. // Read enum lines
  182. for (int i = 0; i < linesCount; i++)
  183. {
  184. // Read function line (starting with "RLAPI")
  185. if (IsTextEqual(lines[i], "typedef enum {", 14))
  186. {
  187. // Keep the line position in the array of lines,
  188. // so, we can scan that position and following lines
  189. enumLines[enumCount] = i;
  190. enumCount++;
  191. }
  192. }
  193. // At this point we have all raylib structs, enums, functions lines data to start parsing
  194. free(buffer); // Unload text buffer
  195. // Parsing raylib data
  196. //--------------------------------------------------------------------------------------------------
  197. // Structs info data
  198. StructInfo *structs = (StructInfo *)calloc(MAX_STRUCTS_TO_PARSE, sizeof(StructInfo));
  199. for (int i = 0; i < structCount; i++)
  200. {
  201. int structLineOffset = 0;
  202. // Get struct name: typedef struct name {
  203. for (int c = 15; c < 64 + 15; c++)
  204. {
  205. if (structLines[i][c] == '{')
  206. {
  207. structLineOffset = c + 2;
  208. MemoryCopy(structs[i].name, &structLines[i][15], c - 15 - 1);
  209. break;
  210. }
  211. }
  212. // Get struct fields and count them -> fields finish with ;
  213. int j = 0;
  214. while (structLines[i][structLineOffset + j] != '}')
  215. {
  216. // WARNING: Some structs have empty spaces and comments -> OK, processed
  217. int fieldStart = 0;
  218. if ((structLines[i][structLineOffset + j] != ' ') && (structLines[i][structLineOffset + j] != '\n')) fieldStart = structLineOffset + j;
  219. if (fieldStart != 0)
  220. {
  221. // Scan one field line
  222. int c = 0;
  223. int fieldEndPos = 0;
  224. char fieldLine[256] = { 0 };
  225. while (structLines[i][structLineOffset + j] != '\n')
  226. {
  227. if (structLines[i][structLineOffset + j] == ';') fieldEndPos = c;
  228. fieldLine[c] = structLines[i][structLineOffset + j];
  229. c++; j++;
  230. }
  231. if (fieldLine[0] != '/') // Field line is not a comment
  232. {
  233. //printf("Struct field: %s_\n", fieldLine); // OK!
  234. // Get struct field type and name
  235. GetDataTypeAndName(fieldLine, fieldEndPos, structs[i].fieldType[structs[i].fieldCount], structs[i].fieldName[structs[i].fieldCount]);
  236. // Get the field description
  237. // We start skipping spaces in front of description comment
  238. int descStart = fieldEndPos;
  239. while ((fieldLine[descStart] != '/') && (fieldLine[descStart] != '\0')) descStart++;
  240. int k = 0;
  241. while ((fieldLine[descStart + k] != '\0') && (fieldLine[descStart + k] != '\n'))
  242. {
  243. structs[i].fieldDesc[structs[i].fieldCount][k] = fieldLine[descStart + k];
  244. k++;
  245. }
  246. structs[i].fieldCount++;
  247. }
  248. }
  249. j++;
  250. }
  251. }
  252. for (int i = 0; i < MAX_STRUCTS_TO_PARSE; i++) free(structLines[i]);
  253. free(structLines);
  254. // Enum info data
  255. EnumInfo *enums = (EnumInfo *)calloc(MAX_ENUMS_TO_PARSE, sizeof(EnumInfo));
  256. for (int i = 0; i < enumCount; i++)
  257. {
  258. // TODO: Get enum description from lines[enumLines[i] - 1]
  259. for (int j = 1; j < 256; j++) // Maximum number of lines following enum first line
  260. {
  261. char *linePtr = lines[enumLines[i] + j];
  262. if ((linePtr[0] >= 'A') && (linePtr[0] <= 'Z'))
  263. {
  264. // Parse enum value line, possible options:
  265. //ENUM_VALUE_NAME,
  266. //ENUM_VALUE_NAME
  267. //ENUM_VALUE_NAME = 99
  268. //ENUM_VALUE_NAME = 99,
  269. //ENUM_VALUE_NAME = 0x00000040, // Value description
  270. // We start reading the value name
  271. int c = 0;
  272. while ((linePtr[c] != ',') &&
  273. (linePtr[c] != ' ') &&
  274. (linePtr[c] != '=') &&
  275. (linePtr[c] != '\0')) { enums[i].valueName[enums[i].valueCount][c] = linePtr[c]; c++; }
  276. // After the name we can have:
  277. // '=' -> value is provided
  278. // ',' -> value is equal to previous + 1, there could be a description if not '\0'
  279. // ' ' -> value is equal to previous + 1, there could be a description if not '\0'
  280. // '\0' -> value is equal to previous + 1
  281. // Let's start checking if the line is not finished
  282. if ((linePtr[c] != ',') && (linePtr[c] != '\0'))
  283. {
  284. // Two options:
  285. // '=' -> value is provided
  286. // ' ' -> value is equal to previous + 1, there could be a description if not '\0'
  287. bool foundValue = false;
  288. while (linePtr[c] != '\0')
  289. {
  290. if (linePtr[c] == '=') { foundValue = true; break; }
  291. c++;
  292. }
  293. if (foundValue)
  294. {
  295. if (linePtr[c + 1] == ' ') c += 2;
  296. else c++;
  297. // Parse integer value
  298. int n = 0;
  299. char integer[16] = { 0 };
  300. while ((linePtr[c] != ',') && (linePtr[c] != ' ') && (linePtr[c] != '\0'))
  301. {
  302. integer[n] = linePtr[c];
  303. c++; n++;
  304. }
  305. if (integer[1] == 'x') enums[i].valueInteger[enums[i].valueCount] = (int)strtol(integer, NULL, 16);
  306. else enums[i].valueInteger[enums[i].valueCount] = atoi(integer);
  307. }
  308. else enums[i].valueInteger[enums[i].valueCount] = (enums[i].valueInteger[enums[i].valueCount - 1] + 1);
  309. // TODO: Parse value description if any
  310. }
  311. else enums[i].valueInteger[enums[i].valueCount] = (enums[i].valueInteger[enums[i].valueCount - 1] + 1);
  312. enums[i].valueCount++;
  313. }
  314. else if (linePtr[0] == '}')
  315. {
  316. // Get enum name from typedef
  317. int c = 0;
  318. while (linePtr[2 + c] != ';') { enums[i].name[c] = linePtr[2 + c]; c++; }
  319. break; // Enum ended, break for() loop
  320. }
  321. }
  322. }
  323. // Functions info data
  324. FunctionInfo *funcs = (FunctionInfo *)calloc(MAX_FUNCS_TO_PARSE, sizeof(FunctionInfo));
  325. for (int i = 0; i < funcCount; i++)
  326. {
  327. int funcParamsStart = 0;
  328. int funcEnd = 0;
  329. // Get return type and function name from func line
  330. for (int c = 0; (c < MAX_LINE_LENGTH) && (funcLines[i][c] != '\n'); c++)
  331. {
  332. if (funcLines[i][c] == '(') // Starts function parameters
  333. {
  334. funcParamsStart = c + 1;
  335. // At this point we have function return type and function name
  336. char funcRetTypeName[128] = { 0 };
  337. int funcRetTypeNameLen = c - 6; // Substract "RLAPI "
  338. MemoryCopy(funcRetTypeName, &funcLines[i][6], funcRetTypeNameLen);
  339. GetDataTypeAndName(funcRetTypeName, funcRetTypeNameLen, funcs[i].retType, funcs[i].name);
  340. break;
  341. }
  342. }
  343. // Get parameters from func line
  344. for (int c = funcParamsStart; c < MAX_LINE_LENGTH; c++)
  345. {
  346. if (funcLines[i][c] == ',') // Starts function parameters
  347. {
  348. // Get parameter type + name, extract info
  349. char funcParamTypeName[128] = { 0 };
  350. int funcParamTypeNameLen = c - funcParamsStart;
  351. MemoryCopy(funcParamTypeName, &funcLines[i][funcParamsStart], funcParamTypeNameLen);
  352. GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]);
  353. funcParamsStart = c + 1;
  354. if (funcLines[i][c + 1] == ' ') funcParamsStart += 1;
  355. funcs[i].paramCount++; // Move to next parameter
  356. }
  357. else if (funcLines[i][c] == ')')
  358. {
  359. funcEnd = c + 2;
  360. // Check if previous word is void
  361. if ((funcLines[i][c - 4] == 'v') && (funcLines[i][c - 3] == 'o') && (funcLines[i][c - 2] == 'i') && (funcLines[i][c - 1] == 'd')) break;
  362. // Get parameter type + name, extract info
  363. char funcParamTypeName[128] = { 0 };
  364. int funcParamTypeNameLen = c - funcParamsStart;
  365. MemoryCopy(funcParamTypeName, &funcLines[i][funcParamsStart], funcParamTypeNameLen);
  366. GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]);
  367. funcs[i].paramCount++; // Move to next parameter
  368. break;
  369. }
  370. }
  371. // Get function description
  372. for (int c = funcEnd; c < MAX_LINE_LENGTH; c++)
  373. {
  374. if (funcLines[i][c] == '/')
  375. {
  376. MemoryCopy(funcs[i].desc, &funcLines[i][c], 127); // WARNING: Size could be too long for funcLines[i][c]?
  377. break;
  378. }
  379. }
  380. }
  381. for (int i = 0; i < linesCount; i++) free(lines[i]);
  382. free(lines);
  383. free(funcLines);
  384. // At this point, all raylib data has been parsed!
  385. //-----------------------------------------------------------------------------------------
  386. // structs[] -> We have all the structs decomposed into pieces for further analysis
  387. // enums[] -> We have all the enums decomposed into pieces for further analysis
  388. // funcs[] -> We have all the functions decomposed into pieces for further analysis
  389. // Print structs info
  390. switch (outputFormat)
  391. {
  392. case PlainText: {
  393. printf("\nStructures found: %i\n\n", structCount);
  394. for (int i = 0; i < structCount; i++)
  395. {
  396. printf("Struct %02i: %s (%i fields)\n", i + 1, structs[i].name, structs[i].fieldCount);
  397. //printf("Description: %s\n", structs[i].desc);
  398. 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]);
  399. }
  400. // Print enums info
  401. printf("\nEnums found: %i\n\n", enumCount);
  402. for (int i = 0; i < enumCount; i++)
  403. {
  404. printf("Enum %02i: %s (%i values)\n", i + 1, enums[i].name, enums[i].valueCount);
  405. //printf("Description: %s\n", enums[i].desc);
  406. for (int e = 0; e < enums[i].valueCount; e++) printf(" Value %s: %i\n", enums[i].valueName[e], enums[i].valueInteger[e]);
  407. }
  408. // Print function info
  409. printf("\nFunctions found: %i\n\n", funcCount);
  410. for (int i = 0; i < funcCount; i++)
  411. {
  412. printf("Function %03i: %s() (%i input parameters)\n", i + 1, funcs[i].name, funcs[i].paramCount);
  413. printf(" Description: %s\n", funcs[i].desc);
  414. printf(" Return type: %s\n", funcs[i].retType);
  415. 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]);
  416. if (funcs[i].paramCount == 0) printf(" No input parameters\n");
  417. }
  418. } break;
  419. case JSON: {
  420. printf("{\n");
  421. printf(" \"structs\": [\n");
  422. for (int i = 0; i < structCount; i++)
  423. {
  424. printf(" {\n");
  425. printf(" \"name\": \"%s\",\n", structs[i].name);
  426. printf(" \"description\": \"%s\",\n", structs[i].desc);
  427. printf(" \"fields\": [\n");
  428. for (int f = 0; f < structs[i].fieldCount; f++)
  429. {
  430. printf(" {\n");
  431. printf(" \"name\": \"%s\",\n", structs[i].fieldName[f]),
  432. printf(" \"type\": \"%s\",\n", structs[i].fieldType[f]),
  433. printf(" \"description\": \"%s\"\n", structs[i].fieldDesc[f] + 3),
  434. printf(" }");
  435. if (f < structs[i].fieldCount - 1)
  436. printf(",\n");
  437. else
  438. printf("\n");
  439. }
  440. printf(" ]\n");
  441. printf(" }");
  442. if (i < structCount - 1)
  443. printf(",\n");
  444. else
  445. printf("\n");
  446. }
  447. printf(" ],\n");
  448. // Print enums info
  449. printf(" \"enums\": [\n");
  450. for (int i = 0; i < enumCount; i++)
  451. {
  452. printf(" {\n");
  453. printf(" \"name\": \"%s\",\n", enums[i].name);
  454. printf(" \"description\": \"%s\",\n", enums[i].desc + 3);
  455. printf(" \"values\": [\n");
  456. for (int e = 0; e < enums[i].valueCount; e++)
  457. {
  458. printf(" {\n");
  459. printf(" \"name\": \"%s\",\n", enums[i].valueName[e]),
  460. printf(" \"value\": %i,\n", enums[i].valueInteger[e]),
  461. printf(" \"description\": \"%s\"\n", enums[i].valueDesc[e] + 3),
  462. printf(" }");
  463. if (e < enums[i].valueCount - 1)
  464. printf(",\n");
  465. else
  466. printf("\n");
  467. }
  468. printf(" ]\n");
  469. printf(" }");
  470. if (i < enumCount - 1)
  471. printf(",\n");
  472. else
  473. printf("\n");
  474. }
  475. printf(" ],\n");
  476. // Print function info
  477. printf(" \"functions\": [\n");
  478. for (int i = 0; i < funcCount; i++)
  479. {
  480. printf(" {\n");
  481. printf(" \"name\": \"%s\",\n", funcs[i].name);
  482. printf(" \"description\": \"%s\",\n", CharReplace(funcs[i].desc, '\\', ' ') + 3);
  483. printf(" \"returnType\": \"%s\"", funcs[i].retType);
  484. if (funcs[i].paramCount == 0)
  485. printf("\n");
  486. else
  487. {
  488. printf(",\n \"params\": {\n");
  489. for (int p = 0; p < funcs[i].paramCount; p++)
  490. {
  491. printf(" \"%s\": \"%s\"", funcs[i].paramName[p], funcs[i].paramType[p]);
  492. if (p < funcs[i].paramCount - 1)
  493. printf(",\n");
  494. else
  495. printf("\n");
  496. }
  497. printf(" }\n");
  498. }
  499. printf(" }");
  500. if (i < funcCount - 1)
  501. printf(",\n");
  502. else
  503. printf("\n");
  504. }
  505. printf(" ]\n");
  506. printf("}\n");
  507. } break;
  508. }
  509. free(funcs);
  510. free(structs);
  511. free(enums);
  512. }
  513. //----------------------------------------------------------------------------------
  514. // Module Functions Definition
  515. //----------------------------------------------------------------------------------
  516. // Load text data from file, returns a '\0' terminated string
  517. // NOTE: text chars array should be freed manually
  518. char *LoadFileText(const char *fileName, int *length)
  519. {
  520. char *text = NULL;
  521. if (fileName != NULL)
  522. {
  523. FILE *file = fopen(fileName, "rt");
  524. if (file != NULL)
  525. {
  526. // WARNING: When reading a file as 'text' file,
  527. // text mode causes carriage return-linefeed translation...
  528. // ...but using fseek() should return correct byte-offset
  529. fseek(file, 0, SEEK_END);
  530. int size = ftell(file);
  531. fseek(file, 0, SEEK_SET);
  532. if (size > 0)
  533. {
  534. *length = size;
  535. text = (char *)calloc((size + 1), sizeof(char));
  536. unsigned int count = (unsigned int)fread(text, sizeof(char), size, file);
  537. // WARNING: \r\n is converted to \n on reading, so,
  538. // read bytes count gets reduced by the number of lines
  539. if (count < (unsigned int)size) text = realloc(text, count + 1);
  540. // Zero-terminate the string
  541. text[count] = '\0';
  542. }
  543. fclose(file);
  544. }
  545. }
  546. return text;
  547. }
  548. // Get all lines from a text buffer (expecting lines ending with '\n')
  549. char **GetTextLines(const char *buffer, int length, int *linesCount)
  550. {
  551. //#define MAX_LINE_LENGTH 512
  552. // Get the number of lines in the text
  553. int count = 0;
  554. for (int i = 0; i < length; i++) if (buffer[i] == '\n') count++;
  555. //printf("Number of text lines in buffer: %i\n", count);
  556. // Allocate as many pointers as lines
  557. char **lines = (char **)malloc(count*sizeof(char **));
  558. char *bufferPtr = (char *)buffer;
  559. for (int i = 0; (i < count) || (bufferPtr[0] != '\0'); i++)
  560. {
  561. lines[i] = (char *)calloc(MAX_LINE_LENGTH, sizeof(char));
  562. // Remove line leading spaces
  563. // Find last index of space/tab character
  564. int index = 0;
  565. while ((bufferPtr[index] == ' ') || (bufferPtr[index] == '\t')) index++;
  566. int j = 0;
  567. while (bufferPtr[index + j] != '\n')
  568. {
  569. lines[i][j] = bufferPtr[index + j];
  570. j++;
  571. }
  572. bufferPtr += (index + j + 1);
  573. }
  574. *linesCount = count;
  575. return lines;
  576. }
  577. // Get data type and name from a string containing both
  578. // NOTE: Useful to parse function parameters and struct fields
  579. void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name)
  580. {
  581. for (int k = typeNameLen; k > 0; k--)
  582. {
  583. if (typeName[k] == ' ' && typeName[k - 1] != ',')
  584. {
  585. // Function name starts at this point (and ret type finishes at this point)
  586. MemoryCopy(type, typeName, k);
  587. MemoryCopy(name, typeName + k + 1, typeNameLen - k - 1);
  588. break;
  589. }
  590. else if (typeName[k] == '*')
  591. {
  592. MemoryCopy(type, typeName, k + 1);
  593. MemoryCopy(name, typeName + k + 1, typeNameLen - k - 1);
  594. break;
  595. }
  596. }
  597. }
  598. // Custom memcpy() to avoid <string.h>
  599. void MemoryCopy(void *dest, const void *src, unsigned int count)
  600. {
  601. char *srcPtr = (char *)src;
  602. char *destPtr = (char *)dest;
  603. for (unsigned int i = 0; i < count; i++) destPtr[i] = srcPtr[i];
  604. }
  605. // Compare two text strings, requires number of characters to compare
  606. bool IsTextEqual(const char *text1, const char *text2, unsigned int count)
  607. {
  608. bool result = true;
  609. for (unsigned int i = 0; i < count; i++)
  610. {
  611. if (text1[i] != text2[i])
  612. {
  613. result = false;
  614. break;
  615. }
  616. }
  617. return result;
  618. }
  619. // Search and replace a character within a string.
  620. char* CharReplace(char* text, char search, char replace)
  621. {
  622. for (int i = 0; text[i] != '\0'; i++)
  623. if (text[i] == search)
  624. text[i] = replace;
  625. return text;
  626. }
  627. /*
  628. // Replace text string
  629. // REQUIRES: strlen(), strstr(), strncpy(), strcpy() -> TODO: Replace by custom implementations!
  630. // WARNING: Returned buffer must be freed by the user (if return != NULL)
  631. char *TextReplace(char *text, const char *replace, const char *by)
  632. {
  633. // Sanity checks and initialization
  634. if (!text || !replace || !by) return NULL;
  635. char *result;
  636. char *insertPoint; // Next insert point
  637. char *temp; // Temp pointer
  638. int replaceLen; // Replace string length of (the string to remove)
  639. int byLen; // Replacement length (the string to replace replace by)
  640. int lastReplacePos; // Distance between replace and end of last replace
  641. int count; // Number of replacements
  642. replaceLen = strlen(replace);
  643. if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count
  644. byLen = strlen(by);
  645. // Count the number of replacements needed
  646. insertPoint = text;
  647. for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
  648. // Allocate returning string and point temp to it
  649. temp = result = (char *)malloc(strlen(text) + (byLen - replaceLen)*count + 1);
  650. if (!result) return NULL; // Memory could not be allocated
  651. // First time through the loop, all the variable are set correctly from here on,
  652. // - 'temp' points to the end of the result string
  653. // - 'insertPoint' points to the next occurrence of replace in text
  654. // - 'text' points to the remainder of text after "end of replace"
  655. while (count--)
  656. {
  657. insertPoint = strstr(text, replace);
  658. lastReplacePos = (int)(insertPoint - text);
  659. temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
  660. temp = strcpy(temp, by) + byLen;
  661. text += lastReplacePos + replaceLen; // Move to next "end of replace"
  662. }
  663. // Copy remaind text part after replacement to result (pointed by moving temp)
  664. strcpy(temp, text);
  665. return result;
  666. }
  667. */