raylib_parser.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  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. //----------------------------------------------------------------------------------
  47. // Types and Structures Definition
  48. //----------------------------------------------------------------------------------
  49. // Function info data
  50. typedef struct FunctionInfo {
  51. char name[64]; // Function name
  52. char desc[128]; // Function description (comment at the end)
  53. char retType[32]; // Return value type
  54. int paramCount; // Number of function parameters
  55. char paramType[12][32]; // Parameters type (max: 12 parameters)
  56. char paramName[12][32]; // Parameters name (max: 12 parameters)
  57. } FunctionInfo;
  58. // Struct info data
  59. typedef struct StructInfo {
  60. char name[64]; // Struct name
  61. char desc[64]; // Struct type description
  62. int fieldCount; // Number of fields in the struct
  63. char fieldType[16][32]; // Field type (max: 16 fields)
  64. char fieldName[16][32]; // Field name (max: 16 fields)
  65. char fieldDesc[16][128]; // Field description (max: 16 fields)
  66. } StructInfo;
  67. // Enum info data
  68. typedef struct EnumInfo {
  69. char name[64]; // Enum name
  70. char desc[64]; // Enum description
  71. int valueCount; // Number of values in enumerator
  72. char valueName[128][64]; // Value name definition (max: 128 values)
  73. int valueInteger[128]; // Value integer (max: 128 values)
  74. char valueDesc[128][64]; // Value description (max: 128 values)
  75. } EnumInfo;
  76. //----------------------------------------------------------------------------------
  77. // Module Functions Declaration
  78. //----------------------------------------------------------------------------------
  79. char *LoadFileText(const char *fileName, int *length);
  80. char **GetTextLines(const char *buffer, int length, int *linesCount);
  81. void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name);
  82. bool IsTextEqual(const char *text1, const char *text2, unsigned int count);
  83. void MemoryCopy(void *dest, const void *src, unsigned int count);
  84. // Main entry point
  85. int main()
  86. {
  87. int length = 0;
  88. char *buffer = LoadFileText("../src/raylib.h", &length);
  89. // Preprocess buffer to get separate lines
  90. // NOTE: GetTextLines() also removes leading spaces/tabs
  91. int linesCount = 0;
  92. char **lines = GetTextLines(buffer, length, &linesCount);
  93. // Print buffer lines
  94. //for (int i = 0; i < linesCount; i++) printf("_%s_\n", lines[i]);
  95. // Function lines pointers, selected from buffer "lines"
  96. int funcCount = 0;
  97. char **funcLines = (char **)malloc(MAX_FUNCS_TO_PARSE*sizeof(char *));
  98. // Structs data (multiple lines), selected from "buffer"
  99. int structCount = 0;
  100. char **structLines = (char **)malloc(MAX_STRUCTS_TO_PARSE*sizeof(char *));
  101. for (int i = 0; i < MAX_STRUCTS_TO_PARSE; i++) structLines[i] = (char *)calloc(MAX_STRUCT_LINE_LENGTH, sizeof(char));
  102. // Enums lines pointers, selected from buffer "lines"
  103. int enumCount = 0;
  104. int *enumLines = (int *)malloc(MAX_ENUMS_TO_PARSE*sizeof(int));
  105. // Prepare required lines for parsing
  106. //--------------------------------------------------------------------------------------------------
  107. // Read function lines
  108. for (int i = 0; i < linesCount; i++)
  109. {
  110. // Read function line (starting with "RLAPI")
  111. if (IsTextEqual(lines[i], "RLAPI", 5))
  112. {
  113. // Keep a pointer to the function line
  114. funcLines[funcCount] = lines[i];
  115. funcCount++;
  116. }
  117. }
  118. // Print function lines
  119. //for (int i = 0; i < funcCount; i++) printf("%s\n", funcLines[i]);
  120. // Read structs data (multiple lines, read directly from buffer)
  121. // TODO: Parse structs data from "lines" instead of "buffer" -> Easier to get struct definition
  122. for (int i = 0; i < length; i++)
  123. {
  124. // Read struct data (starting with "typedef struct", ending with '} ... ;')
  125. // NOTE: We read it directly from buffer
  126. if (IsTextEqual(buffer + i, "typedef struct", 14))
  127. {
  128. int j = 0;
  129. bool validStruct = false;
  130. // WARNING: Typedefs between types: typedef Vector4 Quaternion;
  131. for (int c = 0; c < 128; c++)
  132. {
  133. if (buffer[i + c] == '{')
  134. {
  135. validStruct = true;
  136. break;
  137. }
  138. else if (buffer[i + j] == ';')
  139. {
  140. // Not valid struct:
  141. // i.e typedef struct rAudioBuffer rAudioBuffer; -> Typedef and forward declaration
  142. i += c;
  143. break;
  144. }
  145. }
  146. if (validStruct)
  147. {
  148. while (buffer[i + j] != '}')
  149. {
  150. structLines[structCount][j] = buffer[i + j];
  151. j++;
  152. }
  153. while (buffer[i + j] != '}')
  154. {
  155. structLines[structCount][j] = buffer[i + j];
  156. j++;
  157. }
  158. while (buffer[i + j] != '\n')
  159. {
  160. structLines[structCount][j] = buffer[i + j];
  161. j++;
  162. }
  163. i += j;
  164. structCount++;
  165. }
  166. }
  167. }
  168. // Read enum lines
  169. for (int i = 0; i < linesCount; i++)
  170. {
  171. // Read function line (starting with "RLAPI")
  172. if (IsTextEqual(lines[i], "typedef enum {", 14))
  173. {
  174. // Keep the line position in the array of lines,
  175. // so, we can scan that position and following lines
  176. enumLines[enumCount] = i;
  177. enumCount++;
  178. }
  179. }
  180. // At this point we have all raylib structs, enums, functions lines data to start parsing
  181. free(buffer); // Unload text buffer
  182. // Parsing raylib data
  183. //--------------------------------------------------------------------------------------------------
  184. // Structs info data
  185. StructInfo *structs = (StructInfo *)calloc(MAX_STRUCTS_TO_PARSE, sizeof(StructInfo));
  186. for (int i = 0; i < structCount; i++)
  187. {
  188. int structLineOffset = 0;
  189. // Get struct name: typedef struct name {
  190. for (int c = 15; c < 64 + 15; c++)
  191. {
  192. if (structLines[i][c] == '{')
  193. {
  194. structLineOffset = c + 2;
  195. MemoryCopy(structs[i].name, &structLines[i][15], c - 15 - 1);
  196. break;
  197. }
  198. }
  199. // Get struct fields and count them -> fields finish with ;
  200. int j = 0;
  201. while (structLines[i][structLineOffset + j] != '}')
  202. {
  203. // WARNING: Some structs have empty spaces and comments -> OK, processed
  204. int fieldStart = 0;
  205. if ((structLines[i][structLineOffset + j] != ' ') && (structLines[i][structLineOffset + j] != '\n')) fieldStart = structLineOffset + j;
  206. if (fieldStart != 0)
  207. {
  208. // Scan one field line
  209. int c = 0;
  210. int fieldEndPos = 0;
  211. char fieldLine[256] = { 0 };
  212. while (structLines[i][structLineOffset + j] != '\n')
  213. {
  214. if (structLines[i][structLineOffset + j] == ';') fieldEndPos = c;
  215. fieldLine[c] = structLines[i][structLineOffset + j];
  216. c++; j++;
  217. }
  218. if (fieldLine[0] != '/') // Field line is not a comment
  219. {
  220. //printf("Struct field: %s_\n", fieldLine); // OK!
  221. // Get struct field type and name
  222. GetDataTypeAndName(fieldLine, fieldEndPos, structs[i].fieldType[structs[i].fieldCount], structs[i].fieldName[structs[i].fieldCount]);
  223. // Get the field description
  224. // We start skipping spaces in front of description comment
  225. int descStart = fieldEndPos;
  226. while ((fieldLine[descStart] != '/') && (fieldLine[descStart] != '\0')) descStart++;
  227. int k = 0;
  228. while ((fieldLine[descStart + k] != '\0') && (fieldLine[descStart + k] != '\n'))
  229. {
  230. structs[i].fieldDesc[structs[i].fieldCount][k] = fieldLine[descStart + k];
  231. k++;
  232. }
  233. structs[i].fieldCount++;
  234. }
  235. }
  236. j++;
  237. }
  238. }
  239. for (int i = 0; i < MAX_STRUCTS_TO_PARSE; i++) free(structLines[i]);
  240. free(structLines);
  241. // Enum info data
  242. EnumInfo *enums = (EnumInfo *)calloc(MAX_ENUMS_TO_PARSE, sizeof(EnumInfo));
  243. for (int i = 0; i < enumCount; i++)
  244. {
  245. // TODO: Get enum description from lines[enumLines[i] - 1]
  246. for (int j = 1; j < 256; j++) // Maximum number of lines following enum first line
  247. {
  248. char *linePtr = lines[enumLines[i] + j];
  249. if ((linePtr[0] >= 'A') && (linePtr[0] <= 'Z'))
  250. {
  251. // Parse enum value line, possible options:
  252. //ENUM_VALUE_NAME,
  253. //ENUM_VALUE_NAME
  254. //ENUM_VALUE_NAME = 99
  255. //ENUM_VALUE_NAME = 99,
  256. //ENUM_VALUE_NAME = 0x00000040, // Value description
  257. // We start reading the value name
  258. int c = 0;
  259. while ((linePtr[c] != ',') &&
  260. (linePtr[c] != ' ') &&
  261. (linePtr[c] != '=') &&
  262. (linePtr[c] != '\0')) { enums[i].valueName[enums[i].valueCount][c] = linePtr[c]; c++; }
  263. // After the name we can have:
  264. // '=' -> value is provided
  265. // ',' -> value is equal to previous + 1, there could be a description if not '\0'
  266. // ' ' -> value is equal to previous + 1, there could be a description if not '\0'
  267. // '\0' -> value is equal to previous + 1
  268. // Let's start checking if the line is not finished
  269. if ((linePtr[c] != ',') && (linePtr[c] != '\0'))
  270. {
  271. // Two options:
  272. // '=' -> value is provided
  273. // ' ' -> value is equal to previous + 1, there could be a description if not '\0'
  274. bool foundValue = false;
  275. while (linePtr[c] != '\0')
  276. {
  277. if (linePtr[c] == '=') { foundValue = true; break; }
  278. c++;
  279. }
  280. if (foundValue)
  281. {
  282. if (linePtr[c + 1] == ' ') c += 2;
  283. else c++;
  284. // Parse integer value
  285. int n = 0;
  286. char integer[16] = { 0 };
  287. while ((linePtr[c] != ',') && (linePtr[c] != ' ') && (linePtr[c] != '\0'))
  288. {
  289. integer[n] = linePtr[c];
  290. c++; n++;
  291. }
  292. if (integer[1] == 'x') enums[i].valueInteger[enums[i].valueCount] = (int)strtol(integer, NULL, 16);
  293. else enums[i].valueInteger[enums[i].valueCount] = atoi(integer);
  294. }
  295. else enums[i].valueInteger[enums[i].valueCount] = (enums[i].valueInteger[enums[i].valueCount - 1] + 1);
  296. // TODO: Parse value description if any
  297. }
  298. else enums[i].valueInteger[enums[i].valueCount] = (enums[i].valueInteger[enums[i].valueCount - 1] + 1);
  299. enums[i].valueCount++;
  300. }
  301. else if (linePtr[0] == '}')
  302. {
  303. // Get enum name from typedef
  304. int c = 0;
  305. while (linePtr[2 + c] != ';') { enums[i].name[c] = linePtr[2 + c]; c++; }
  306. break; // Enum ended, break for() loop
  307. }
  308. }
  309. }
  310. // Functions info data
  311. FunctionInfo *funcs = (FunctionInfo *)calloc(MAX_FUNCS_TO_PARSE, sizeof(FunctionInfo));
  312. for (int i = 0; i < funcCount; i++)
  313. {
  314. int funcParamsStart = 0;
  315. int funcEnd = 0;
  316. // Get return type and function name from func line
  317. for (int c = 0; (c < MAX_LINE_LENGTH) && (funcLines[i][c] != '\n'); c++)
  318. {
  319. if (funcLines[i][c] == '(') // Starts function parameters
  320. {
  321. funcParamsStart = c + 1;
  322. // At this point we have function return type and function name
  323. char funcRetTypeName[128] = { 0 };
  324. int funcRetTypeNameLen = c - 6; // Substract "RLAPI "
  325. MemoryCopy(funcRetTypeName, &funcLines[i][6], funcRetTypeNameLen);
  326. GetDataTypeAndName(funcRetTypeName, funcRetTypeNameLen, funcs[i].retType, funcs[i].name);
  327. break;
  328. }
  329. }
  330. // Get parameters from func line
  331. for (int c = funcParamsStart; c < MAX_LINE_LENGTH; c++)
  332. {
  333. if (funcLines[i][c] == ',') // Starts function parameters
  334. {
  335. // Get parameter type + name, extract info
  336. char funcParamTypeName[128] = { 0 };
  337. int funcParamTypeNameLen = c - funcParamsStart;
  338. MemoryCopy(funcParamTypeName, &funcLines[i][funcParamsStart], funcParamTypeNameLen);
  339. GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]);
  340. funcParamsStart = c + 1;
  341. if (funcLines[i][c + 1] == ' ') funcParamsStart += 1;
  342. funcs[i].paramCount++; // Move to next parameter
  343. }
  344. else if (funcLines[i][c] == ')')
  345. {
  346. funcEnd = c + 2;
  347. // Check if previous word is void
  348. if ((funcLines[i][c - 4] == 'v') && (funcLines[i][c - 3] == 'o') && (funcLines[i][c - 2] == 'i') && (funcLines[i][c - 1] == 'd')) break;
  349. // Get parameter type + name, extract info
  350. char funcParamTypeName[128] = { 0 };
  351. int funcParamTypeNameLen = c - funcParamsStart;
  352. MemoryCopy(funcParamTypeName, &funcLines[i][funcParamsStart], funcParamTypeNameLen);
  353. GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]);
  354. funcs[i].paramCount++; // Move to next parameter
  355. break;
  356. }
  357. }
  358. // Get function description
  359. for (int c = funcEnd; c < MAX_LINE_LENGTH; c++)
  360. {
  361. if (funcLines[i][c] == '/')
  362. {
  363. MemoryCopy(funcs[i].desc, &funcLines[i][c], 127); // WARNING: Size could be too long for funcLines[i][c]?
  364. break;
  365. }
  366. }
  367. }
  368. for (int i = 0; i < linesCount; i++) free(lines[i]);
  369. free(lines);
  370. free(funcLines);
  371. // At this point, all raylib data has been parsed!
  372. //-----------------------------------------------------------------------------------------
  373. // structs[] -> We have all the structs decomposed into pieces for further analysis
  374. // enums[] -> We have all the enums decomposed into pieces for further analysis
  375. // funcs[] -> We have all the functions decomposed into pieces for further analysis
  376. // Print structs info
  377. printf("\nStructures found: %i\n\n", structCount);
  378. for (int i = 0; i < structCount; i++)
  379. {
  380. printf("Struct %02i: %s (%i fields)\n", i + 1, structs[i].name, structs[i].fieldCount);
  381. //printf("Description: %s\n", structs[i].desc);
  382. 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]);
  383. }
  384. // Print enums info
  385. printf("\nEnums found: %i\n\n", enumCount);
  386. for (int i = 0; i < enumCount; i++)
  387. {
  388. printf("Enum %02i: %s (%i values)\n", i + 1, enums[i].name, enums[i].valueCount);
  389. //printf("Description: %s\n", enums[i].desc);
  390. for (int e = 0; e < enums[i].valueCount; e++) printf(" Value %s: %i\n", enums[i].valueName[e], enums[i].valueInteger[e]);
  391. }
  392. // Print function info
  393. printf("\nFunctions found: %i\n\n", funcCount);
  394. for (int i = 0; i < funcCount; i++)
  395. {
  396. printf("Function %03i: %s() (%i input parameters)\n", i + 1, funcs[i].name, funcs[i].paramCount);
  397. printf(" Description: %s\n", funcs[i].desc);
  398. printf(" Return type: %s\n", funcs[i].retType);
  399. 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]);
  400. if (funcs[i].paramCount == 0) printf(" No input parameters\n");
  401. }
  402. free(funcs);
  403. free(structs);
  404. free(enums);
  405. }
  406. //----------------------------------------------------------------------------------
  407. // Module Functions Definition
  408. //----------------------------------------------------------------------------------
  409. // Load text data from file, returns a '\0' terminated string
  410. // NOTE: text chars array should be freed manually
  411. char *LoadFileText(const char *fileName, int *length)
  412. {
  413. char *text = NULL;
  414. if (fileName != NULL)
  415. {
  416. FILE *file = fopen(fileName, "rt");
  417. if (file != NULL)
  418. {
  419. // WARNING: When reading a file as 'text' file,
  420. // text mode causes carriage return-linefeed translation...
  421. // ...but using fseek() should return correct byte-offset
  422. fseek(file, 0, SEEK_END);
  423. int size = ftell(file);
  424. fseek(file, 0, SEEK_SET);
  425. if (size > 0)
  426. {
  427. *length = size;
  428. text = (char *)calloc((size + 1), sizeof(char));
  429. unsigned int count = (unsigned int)fread(text, sizeof(char), size, file);
  430. // WARNING: \r\n is converted to \n on reading, so,
  431. // read bytes count gets reduced by the number of lines
  432. if (count < (unsigned int)size) text = realloc(text, count + 1);
  433. // Zero-terminate the string
  434. text[count] = '\0';
  435. }
  436. fclose(file);
  437. }
  438. }
  439. return text;
  440. }
  441. // Get all lines from a text buffer (expecting lines ending with '\n')
  442. char **GetTextLines(const char *buffer, int length, int *linesCount)
  443. {
  444. //#define MAX_LINE_LENGTH 512
  445. // Get the number of lines in the text
  446. int count = 0;
  447. for (int i = 0; i < length; i++) if (buffer[i] == '\n') count++;
  448. //printf("Number of text lines in buffer: %i\n", count);
  449. // Allocate as many pointers as lines
  450. char **lines = (char **)malloc(count*sizeof(char **));
  451. char *bufferPtr = (char *)buffer;
  452. for (int i = 0; (i < count) || (bufferPtr[0] != '\0'); i++)
  453. {
  454. lines[i] = (char *)calloc(MAX_LINE_LENGTH, sizeof(char));
  455. // Remove line leading spaces
  456. // Find last index of space/tab character
  457. int index = 0;
  458. while ((bufferPtr[index] == ' ') || (bufferPtr[index] == '\t')) index++;
  459. int j = 0;
  460. while (bufferPtr[index + j] != '\n')
  461. {
  462. lines[i][j] = bufferPtr[index + j];
  463. j++;
  464. }
  465. bufferPtr += (index + j + 1);
  466. }
  467. *linesCount = count;
  468. return lines;
  469. }
  470. // Get data type and name from a string containing both
  471. // NOTE: Useful to parse function parameters and struct fields
  472. void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name)
  473. {
  474. for (int k = typeNameLen; k > 0; k--)
  475. {
  476. if (typeName[k] == ' ')
  477. {
  478. // Function name starts at this point (and ret type finishes at this point)
  479. MemoryCopy(type, typeName, k);
  480. MemoryCopy(name, typeName + k + 1, typeNameLen - k - 1);
  481. break;
  482. }
  483. else if (typeName[k] == '*')
  484. {
  485. MemoryCopy(type, typeName, k + 1);
  486. MemoryCopy(name, typeName + k + 1, typeNameLen - k - 1);
  487. break;
  488. }
  489. }
  490. }
  491. // Custom memcpy() to avoid <string.h>
  492. void MemoryCopy(void *dest, const void *src, unsigned int count)
  493. {
  494. char *srcPtr = (char *)src;
  495. char *destPtr = (char *)dest;
  496. for (unsigned int i = 0; i < count; i++) destPtr[i] = srcPtr[i];
  497. }
  498. // Compare two text strings, requires number of characters to compare
  499. bool IsTextEqual(const char *text1, const char *text2, unsigned int count)
  500. {
  501. bool result = true;
  502. for (unsigned int i = 0; i < count; i++)
  503. {
  504. if (text1[i] != text2[i])
  505. {
  506. result = false;
  507. break;
  508. }
  509. }
  510. return result;
  511. }
  512. /*
  513. // Replace text string
  514. // REQUIRES: strlen(), strstr(), strncpy(), strcpy() -> TODO: Replace by custom implementations!
  515. // WARNING: Returned buffer must be freed by the user (if return != NULL)
  516. char *TextReplace(char *text, const char *replace, const char *by)
  517. {
  518. // Sanity checks and initialization
  519. if (!text || !replace || !by) return NULL;
  520. char *result;
  521. char *insertPoint; // Next insert point
  522. char *temp; // Temp pointer
  523. int replaceLen; // Replace string length of (the string to remove)
  524. int byLen; // Replacement length (the string to replace replace by)
  525. int lastReplacePos; // Distance between replace and end of last replace
  526. int count; // Number of replacements
  527. replaceLen = strlen(replace);
  528. if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count
  529. byLen = strlen(by);
  530. // Count the number of replacements needed
  531. insertPoint = text;
  532. for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
  533. // Allocate returning string and point temp to it
  534. temp = result = (char *)malloc(strlen(text) + (byLen - replaceLen)*count + 1);
  535. if (!result) return NULL; // Memory could not be allocated
  536. // First time through the loop, all the variable are set correctly from here on,
  537. // - 'temp' points to the end of the result string
  538. // - 'insertPoint' points to the next occurrence of replace in text
  539. // - 'text' points to the remainder of text after "end of replace"
  540. while (count--)
  541. {
  542. insertPoint = strstr(text, replace);
  543. lastReplacePos = (int)(insertPoint - text);
  544. temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
  545. temp = strcpy(temp, by) + byLen;
  546. text += lastReplacePos + replaceLen; // Move to next "end of replace"
  547. }
  548. // Copy remaind text part after replacement to result (pointed by moving temp)
  549. strcpy(temp, text);
  550. return result;
  551. }
  552. */