y_bini.inc 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*
  2. y_bin - Binary file storage.
  3. */
  4. /*
  5. Binary file format:
  6. 4 bytes - Number of chunks in the file.
  7. Chunk header:
  8. These are not garbage collected, and memory is allocated for a huge number.
  9. Actually, I'm not sure of the best way to do this well... The original idea was
  10. to just have fixed blocks, I don't know if that is still the best method.
  11. Actually, maybe the best method is separate files created and destroyed as
  12. required, that would be a LOT less coding!
  13. */
  14. stock INI_WriteArray(const INI:f, const string:name[], const arr[], const len = sizeof (arr))
  15. {
  16. // First things first, determine the filename for the data. This is done as:
  17. //
  18. // <f path>\<f name>.INI[<tag>]<name>=
  19. //
  20. // Also, unlike all other INI data, this data is not buffered - doing so is
  21. // not only hard, but pointless because we are writing to a different file.
  22. new
  23. fname[64];
  24. format(fname, sizeof (fname), "%s[%s]%s=.bin", YSI_g_sINIWriteFile[f], YSI_g_sINITagBuffer[YSI_g_sINICurrentTag[f]][E_INI_TAGS_NAME], name);
  25. new
  26. File:b = fopen(fname, io_write);
  27. if (b)
  28. {
  29. fblockwrite(b, arr, len);
  30. INI_WriteString(f, name, fname),
  31. fclose(b);
  32. }
  33. }
  34. stock INI_ReadArray(const string:fname[], dest[], len = sizeof (dest))
  35. {
  36. new
  37. File:b = fopen(fname, io_read);
  38. if (b)
  39. {
  40. new
  41. l2 = flength(b);
  42. if (l2 > len) P:W("%s buffer has shrunk since writing.", fname);
  43. else if (l2 < len) P:W("%s buffer has grown since writing.", fname);
  44. return
  45. fblockread(b, arr, len);
  46. fclose(b),
  47. 1;
  48. }
  49. else
  50. {
  51. // Do something special to detect old style arrays. Sadly, we can't
  52. // upgrade them as they may not be writing (actually, why can't we?)
  53. }
  54. return 0;
  55. }
  56. #define INI_Array(%1,%2) \
  57. if (!strcmp((%1), name, true)) return INI_ReadArray(value, %2)
  58. /*
  59. BIN_WriteChunk(const BIN:f, const pos, const arr[], const len = sizeof (arr), buffer = sizeof (arr))
  60. {
  61. if (buffer < len)
  62. {
  63. // Blank the file location, return the new location. Can NEVER garbage
  64. // collect the wasted storage. Actually, why can't we? Use double
  65. // indirection!
  66. }
  67. else if (buffer > len)
  68. {
  69. // Pad the data.
  70. }
  71. }
  72. */
  73. /**--------------------------------------------------------------------------**\
  74. <summary>INI_TryGetValue</summary>
  75. <param name="start">Start position of the possibly current key.</param>
  76. <param name="end">End position of the found key.</param>
  77. <returns>
  78. -
  79. </returns>
  80. <remarks>
  81. The INI system uses basic string functions to find candidate keys. They
  82. always start searching from the known start of the current tag, and check
  83. that the found key is before the start of the next known tag. If both those
  84. conditions are true, this function is called to further verify the found
  85. text - it could be a substring in a larger key, it could be a value, or it
  86. could be commented out. This function therefore checks that the found
  87. position in the stored string is the first item on a line, and is followed
  88. only by either nothing or an equals sign.
  89. If this IS the key we are searching for, then we return a later position
  90. corresponding to the start of the value (or cellmax if there is no value).
  91. If this isn't a valid key, we return -1.
  92. </remarks>
  93. \**--------------------------------------------------------------------------**/
  94. static stock bool:INI_TryGetValue(start, end)
  95. {
  96. // Check everything before this position is whitespace only.
  97. new
  98. cur = start;
  99. for ( ; ; )
  100. {
  101. switch (YSI_gMallocMemory[--cur])
  102. {
  103. case '\0', '\r', '\n': break;
  104. case ' ', '\t': {}
  105. default: return -1;
  106. }
  107. }
  108. cur = end;
  109. for ( ; ; )
  110. {
  111. switch (YSI_gMallocMemory[cur++])
  112. {
  113. // Has no value, just a key.
  114. case '\0', '\r', '\n': return cellmax;
  115. // Has a value, find the start.
  116. case '=':
  117. {
  118. // "cur" has already been incremented by this point.
  119. for ( ; ; )
  120. {
  121. switch (YSI_gMallocMemory[cur])
  122. {
  123. case '\0', '\r', '\n': return cellmax;
  124. case ' ', '\t': ++cur;
  125. default: return cur;
  126. }
  127. }
  128. }
  129. case ' ', '\t': {}
  130. default: break;
  131. }
  132. }
  133. return -1;
  134. }