Advertisement
White_Blue

Untitled

Feb 29th, 2024
1,859
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 51.64 KB | None | 0 0
  1. #if defined _dof2_included
  2.     #endinput
  3. #endif
  4. #define _dof2_included
  5.  
  6. #include <a_samp>
  7.  
  8. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  9.  
  10. /*
  11.  * This is a new version of the INI script Double-O-Files.
  12.  * However, it's has completely been rewritten and has now a much better performance.
  13.  * There is also the support for sections in the INI file. (But there is no support for comments.)
  14.  * Double-O-Files 2 is compatible with DUDB, DINI, Double-O-Files and possibly y_ini since it
  15.  * can handle sections and entry of the format "key = value", not only "key=value".
  16.  * The number of spaces between the equal sign and key and value can actually be arbitrary.
  17.  * I've added some comments below. You may see that I've mentioned the big-O-notation,
  18.  * 'n' always Entries.Count.
  19.  * Double-O-Files 2 should also be useful for Russian letter because I'm using
  20.  * the functions fgetchar and fputchar to write and read the files.
  21.  *
  22.  * There is another new feature which has been inspired by ZCMD and y_ini:
  23.  * The OnParseFile callbacks. To learn more about it, read the description in
  24.  * the SA-MP forums if you haven't already.
  25.  * THE END
  26.  */
  27.  
  28. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  29.  
  30. /*
  31. native DOF2_SetFile(file[]);
  32. native DOF2_LoadFile();
  33. native DOF2_SaveFile();
  34. native DOF2_ParseFile(file[],extraid,bool:callback=true);
  35. native DOF2_ReparseFile(file[],extraid,bool:callback=true);
  36. native DOF2_WriteFile();
  37. native DOF2_PrintFile(comment[]="");
  38. native DOF2_GetString(file[],key[],tag[]="");
  39. native DOF2_GetStringEx(file[],key[],result[],size,tag[]="");
  40. native Float:DOF2_GetFloat(file[],key[]);
  41. native DOF2_GetInt(file[],key[],tag[]="");
  42. native DOF2_GetHex(file[],key[],tag[]="");
  43. native DOF2_GetBin(file[],key[],tag[]="");
  44. native bool:DOF2_GetBool(file[],key[],tag[]="");
  45. native DOF2_SetString(file[],key[],value[],tag[]="");
  46. native DOF2_SetFloat(file[],key[],Float:value);
  47. native DOF2_SetInt(file[],key[],value,tag[]="");
  48. native DOF2_SetHex(file[],key[],value,tag[]="");
  49. native DOF2_SetBin(file[],key[],value,tag[]="");
  50. native DOF2_SetBool(file[],key[],bool:value,tag[]="");
  51. native DOF2_IsSet(file[],key[],tag[]="");
  52. native DOF2_Unset(file[],key[],tag[]="");
  53. native DOF2_FileExists(file[]);
  54. native DOF2_RemoveFile(file[]);
  55. native DOF2_CreateFile(file[],password[]="");
  56. native DOF2_RenameFile(oldfile[],newfile[]);
  57. native DOF2_RenameKey(file[],oldkey[],newkey[],tag[]="");
  58. native DOF2_CopyFile(filetocopy[],newfile[]);
  59. native DOF2_CheckLogin(file[],password[]);
  60. native DOF2_File(user[]);
  61. native DOF2_ParseInt();
  62. native DOF2_ParseFloat();
  63. native DOF2_ParseBool();
  64. native DOF2_ParseBin();
  65. native DOF2_ParseHex();
  66. native DOF2_SetUTF8(bool:set);
  67. native bool:DOF2_GetUTF8();
  68. native DOF2_GetFile();
  69. native DOF2_MakeBackup(file[]);
  70. native DOF2_RemoveSection (file [], tag []);
  71. native DOF2_SectionExists (file [], tag []);
  72. native DOF2_SortSection (file [], tag [], bool: ignorecase = true, bool: ascending = true);
  73. native DOF2_SortAllSections (file [], bool: ignorecase = true, bool: ascending = true);
  74. native DOF2_SetCaseSensitivity (bool: set);
  75. native DOF2_GetCaseSensitivity ();
  76. */
  77.  
  78. #define DOF2_TagExists  DOF2_SectionExists
  79. #define DOF2_RemoveTag  DOF2_RemoveSection
  80.  
  81. // OnParseFile <Tag><Key>(extraid, value [])
  82. // OnParseFile <><Key>(extraid, value [])
  83. // OnDefaultParseFile (extraid, value [], key [], tag [], file [])
  84.  
  85. // The arguments of your OnParseFile functions may have arbitrary names but must be an integer followed by a string.
  86. // Function must return a value.
  87. #define OnParseFile<%0><%1>(%2) \
  88.     forward _OnParseFile_%0_%1 (extraid, value []); \
  89.     public _OnParseFile_%0_%1 (extraid, value []) \
  90.         return __OnParseFile_%0_%1 (extraid, (value [0] == '\1' && value [1] == '\0') ? ("") : value); \
  91.     stock __OnParseFile_%0_%1 (%2)
  92.  
  93. // Also here: The argument names may be arbitrary but must be an integer followed by 4 strings.
  94. // Function must return a value.
  95. #define OnDefaultParseFile(%0) \
  96.     forward _OnDefaultParseFile (extraid, value [], key [], tag [], file []); \
  97.     public _OnDefaultParseFile (extraid, value [], key [], tag [], file []) \
  98.         return __OnDefaultParseFile (extraid, (value [0] == '\1' && value [1] == '\0') ? ("") : value, key, (tag [0] == '\1' && tag [1] == '\0') ? ("") : tag, file); \
  99.     stock __OnDefaultParseFile (%0)
  100.  
  101. #define DOF2_ParseBool() \
  102.     (strval (value) || (value [0] && !strcmp (value, "true", true)))
  103.  
  104. #define DOF2_ParseInt() \
  105.     (strval (value))
  106.  
  107. #define DOF2_ParseFloat() \
  108.     (floatstr (value))
  109.  
  110. #define DOF2_ParseBin() \
  111.     (DOF2_strbin (value))
  112.  
  113. #define DOF2_ParseHex() \
  114.     (DOF2_strhex (value))
  115.  
  116. #define DOF2_LoadFile() \
  117.     DOF2_ParseFile (CurrentFile, -1, false)
  118.  
  119. #define DOF2_SaveFile \
  120.     DOF2_WriteFile
  121.  
  122. #define DOF2_FileExists \
  123.     fexist
  124.  
  125. #define Sections. \
  126.     Sections_
  127.  
  128. #define Entries. \
  129.     Entries_
  130.  
  131. #define DOF2:: \
  132.     DOF2_
  133.    
  134. #if !defined private
  135.     #define private         static stock
  136. #endif
  137.    
  138. #pragma dynamic 65536
  139.  
  140. /*
  141. #define MAX_SECTION_TAG        (32)
  142. #define MAX_LINE_SIZE       (128)
  143. #define MAX_SECTIONS            (32)
  144. #define MAX_ENTRIES         (256)
  145. #define MAX_FILE_SIZE       (64)
  146.  
  147. #define USER_FILE_PATH      "Users/%s.ini"
  148. */
  149.  
  150. // The maximum length of the name of a tag.
  151. #if !defined MAX_SECTION_TAG
  152.     #define MAX_SECTION_TAG     (32)
  153. #endif
  154.  
  155. // The maximum length of a line (including key and value).
  156. #if !defined MAX_LINE_SIZE
  157.     #define MAX_LINE_SIZE       (150)
  158. #endif
  159.  
  160. // The maximum number of sections which can be handled. Be careful: MUST NOT be higher than 255.
  161. #if !defined MAX_SECTIONS
  162.     #define MAX_SECTIONS        (32)
  163. #endif
  164.  
  165. // The maximum number of entries which can be loaded into the cache.
  166. #if !defined MAX_ENTRIES
  167.     #define MAX_ENTRIES         (256)
  168. #endif
  169.  
  170. // The maximum length of the name of a file.
  171. #if !defined MAX_FILE_SIZE
  172.     #define MAX_FILE_SIZE       (64)
  173. #endif
  174.  
  175. /*
  176. If PACK_CONTENT == true tag names and lines (key + value) will get stored in cache as packed strings.
  177. The result is less memory usage. However, you won't be able to use special characters like russian or chinese ones.
  178. */
  179. #if !defined PACK_CONTENT
  180.     #define PACK_CONTENT        (false)
  181. #endif
  182.  
  183. #define INVALID_ENTRY           (-1)
  184. #define INVALID_SECTION         (-1)
  185.  
  186. // Do you want to emulate DUDB?
  187. #if !defined DUDB_CONVERT && 0 // Change to 1 to enable.
  188.     #define DUDB_CONVERT
  189. #endif
  190.  
  191. #if !defined USER_FILE_PATH
  192.     #if defined DUDB_CONVERT
  193.         #define USER_FILE_PATH  "%s.dudb.sav"
  194.     #else
  195.         #define USER_FILE_PATH  "%s.ini"
  196.     #endif
  197. #endif
  198.  
  199. #if !defined USER_PW_HASH_KEY
  200.     #if defined DUDB_CONVERT
  201.         #define USER_PW_HASH_KEY "password_hash"
  202.     #else
  203.         #define USER_PW_HASH_KEY "password"
  204.     #endif
  205. #endif
  206.    
  207.  
  208. // Do you want to emulate DINI?
  209. #if !defined DINI_CONVERT && 1 // Change to 1 to enable.
  210.     #define DINI_CONVERT
  211. #endif
  212.  
  213. /*
  214. #if MAX_SECTIONS >= 256
  215.     #error MAX_SECTIONS must not be greater than 255.
  216. #endif
  217. */
  218.  
  219. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  220.  
  221. private
  222.     bool: UseUTF8 = PACK_CONTENT,
  223.     bool: CaseSensitive = false,
  224.     CurrentFile [MAX_FILE_SIZE],
  225.     bool: FileChanged,
  226.     Sections.FirstEntry [MAX_SECTIONS] = {INVALID_ENTRY, ...},
  227.     Sections.LastEntry [MAX_SECTIONS] = {INVALID_ENTRY, ...},
  228.     Sections.Count,
  229. #if PACK_CONTENT == true
  230.     Sections.Tag [MAX_SECTIONS][MAX_SECTION_TAG char],
  231.     Entries.Line [MAX_ENTRIES][MAX_LINE_SIZE char],
  232.     Entries.Tag [MAX_ENTRIES][MAX_SECTION_TAG char],
  233. #else
  234.     Sections.Tag [MAX_SECTIONS][MAX_SECTION_TAG],
  235.     Entries.Line [MAX_ENTRIES][MAX_LINE_SIZE],
  236.     Entries.Tag [MAX_ENTRIES][MAX_SECTION_TAG],
  237. #endif
  238. #if MAX_SECTIONS >= 256
  239.     Entries.Section [MAX_ENTRIES],
  240. #else
  241.     Entries.Section [MAX_ENTRIES char],
  242. #endif
  243.     Entries.NextEntry [MAX_ENTRIES] = {INVALID_ENTRY, ...},
  244.     Entries.PreviousEntry [MAX_ENTRIES] = {INVALID_ENTRY, ...},
  245.     Entries.Count,
  246.     SortedEntryList [MAX_ENTRIES][2]; // Index 0: Hashcode, Index 1: EntryID
  247.  
  248. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  249.  
  250. DOF2::Exit ()
  251.     DOF2::WriteFile ();
  252.  
  253. stock DOF2::SetUTF8 (bool: set)
  254.     UseUTF8 = set;
  255.  
  256. stock bool: DOF2::GetUTF8 ()
  257.     return UseUTF8;
  258.  
  259. stock bool: DOF2::SetCaseSensitivity (bool: set)
  260.     CaseSensitive = set;
  261.    
  262. stock bool: DOF2::GetCaseSensitivity ()
  263.     return CaseSensitive;
  264.  
  265. stock DOF2::SetFile (const file [])
  266.     DOF2::strcpy (CurrentFile, file);
  267.  
  268. stock DOF2::GetFile ()
  269.     return CurrentFile;
  270.  
  271. stock DOF2::CreateFile (const file [], const password [] = "")
  272. {
  273.     if (!DOF2::FileExists (file))
  274.     {
  275.         new File: f = fopen (file, io_append);
  276.        
  277.         if (fclose (f))
  278.         {
  279.             if (password [0])
  280.                 return DOF2::SetInt (file, USER_PW_HASH_KEY, DOF2::num_hash (password));
  281.             return 1;
  282.         }
  283.     }
  284.     return 0;
  285. }
  286.  
  287. stock DOF2::RenameFile (oldfile [], newfile [])
  288. {
  289.     if (!DOF2::FileExists (newfile))
  290.     {
  291.         // If 'CurrentFile' is 'oldfile', write it if it has been changed.
  292.         if (CurrentFile [0] && !strcmp (CurrentFile, oldfile) && FileChanged)
  293.             DOF2::WriteFile ();
  294.         else if (!DOF2::ParseFile (oldfile, -1, false)) // Otherwise parse 'oldfile'.
  295.             return 0;
  296.            
  297.         DOF2::SetFile (newfile);
  298.         if (DOF2::WriteFile ())
  299.             return fremove (oldfile);
  300.     }
  301.     return 0;
  302. }
  303.  
  304. stock DOF2::CopyFile (filetocopy [], newfile [])
  305. {
  306.     if (!DOF2::FileExists (newfile))
  307.     {
  308.         if (CurrentFile [0] && !strcmp (CurrentFile, filetocopy) && FileChanged)
  309.             DOF2::WriteFile ();
  310.         else if(!DOF2::ParseFile (filetocopy, -1, false))
  311.             return 0;
  312.            
  313.         DOF2::SetFile (newfile);
  314.         return DOF2::WriteFile ();
  315.     }
  316.     return 0;
  317. }
  318.  
  319. stock DOF2::RemoveFile (const file [])
  320. {
  321.     if (file [0])
  322.     {
  323.         if (CurrentFile [0] && !strcmp (CurrentFile, file))
  324.             CurrentFile [0] = '\0';
  325.         return fremove (file);
  326.     }
  327.     return 0;
  328. }
  329.  
  330. stock DOF2::MakeBackup (file [])
  331. {
  332.     new
  333.         year,
  334.         month,
  335.         day,
  336.         hour,
  337.         minute,
  338.         second,
  339.         backupfile [MAX_FILE_SIZE];
  340.  
  341.     getdate (year, month, day);
  342.     gettime (hour, minute, second);
  343.     format (backupfile, sizeof (backupfile), "%s.%02d_%02d_%02d.%02d_%02d_%02d_%02d.bak", CurrentFile, month, day, year, hour, minute, second, GetTickCount ());
  344.     return DOF2::CopyFile (CurrentFile, backupfile);
  345. }
  346.  
  347. stock bool: DOF2::SectionExists (file [], tag [])
  348. {
  349.     if (file [0]) // You can't remove the empty Sections.
  350.     {
  351.         if (!tag [0])
  352.             return true; // Emptry section always exists. In every file.
  353.  
  354.         if (!CurrentFile [0] || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.
  355.             if (!DOF2::ParseFile (file, -1, false))
  356.                 return false;
  357.  
  358.     #if PACK_CONTENT == true
  359.         new buf [MAX_SECTION_TAG];
  360.     #endif
  361.    
  362.         for (new i = 1; i < Sections.Count; ++i)
  363.         {
  364.         #if PACK_CONTENT == true
  365.             strunpack (buf, Sections.Tag [i]);
  366.             if (!strcmp (buf, tag, !CaseSensitive))
  367.                 return true;
  368.         #else
  369.             if (!strcmp (Sections.Tag [i], tag, !CaseSensitive))
  370.                 return true;
  371.         #endif
  372.         }
  373.     }
  374.     return false;
  375. }
  376.  
  377. stock DOF2::RemoveSection (file [], tag [])
  378. {
  379.     // Removes tag 'tag' with all it's entries.
  380.     if (file [0] && tag [0]) // You can't remove the empty Sections.
  381.     {
  382.         if (!CurrentFile [0] || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.
  383.             if (!DOF2::ParseFile (file, -1, false))
  384.                 return 0;
  385.  
  386.         new
  387.         #if PACK_CONTENT == true
  388.             line [MAX_LINE_SIZE],
  389.             buf [MAX_SECTION_TAG],
  390.         #endif
  391.             section = INVALID_SECTION,
  392.             entry,
  393.             key [MAX_KEY_SIZE];
  394.  
  395.         for (new i = 1; i < Sections.Count; ++i)
  396.         {
  397.         #if PACK_CONTENT == true
  398.             strunpack (buf, Sections.Tag [i]);
  399.             if (!strcmp (buf, tag, !CaseSensitive))
  400.             {
  401.                 section = i;
  402.                 break;
  403.             }
  404.         #else
  405.             if (!strcmp (Sections.Tag [i], tag, !CaseSensitive))
  406.             {
  407.                 section = i;
  408.                 break;
  409.             }
  410.         #endif
  411.         }
  412.  
  413.         if (section != INVALID_SECTION)
  414.         {
  415.             entry = Sections.FirstEntry [section];
  416.             while (entry != INVALID_ENTRY)
  417.             {
  418.                 // Remove all entries under the current Sections.
  419.             #if PACK_CONTENT == true
  420.                 strunpack (line, Entries.Line [entry]);
  421.                 DOF2::ParseLine (line, key, buf);
  422.             #else
  423.                 DOF2::ParseLine (Entries.Line [entry], key, buf);
  424.             #endif
  425.                 DOF2::Unset (file, key, tag);
  426.                 entry = Entries.NextEntry [entry];
  427.             }
  428.  
  429.             // Move the last tag to the position of the current tag. Creates a little mess.
  430.             --Sections.Count;
  431.             Sections.Tag [section] = Sections.Tag [Sections.Count];
  432.             Sections.FirstEntry [section] = Sections.FirstEntry [Sections.Count];
  433.             Sections.LastEntry [section] = Sections.LastEntry [Sections.Count];
  434.  
  435.             // Adjust the tag IDs of the entries.
  436.             entry = Sections.FirstEntry [section];
  437.             while (entry != INVALID_ENTRY)
  438.             {
  439.             #if MAX_SECTIONS >= 256
  440.                 Entries.Section [entry] = section;
  441.             #else
  442.                 Entries.Section {entry} = section;
  443.             #endif
  444.                 entry = Entries.NextEntry [entry];
  445.             }
  446.             FileChanged = true;
  447.             return 1;
  448.         }
  449.     }
  450.     return 0;
  451. }
  452.  
  453. private DOF2::SearchEntry (const key [], const tag [], keybuf [], valbuf [], &pos, keybufsize = sizeof (keybuf), valbufsize = sizeof (valbuf))
  454. {
  455.     if (key [0] && Entries.Count)
  456.     {
  457.         new
  458.             entry = INVALID_ENTRY,
  459.             l,
  460.             m,
  461.             r,
  462.             h,
  463.         #if PACK_CONTENT == true
  464.             line [MAX_LINE_SIZE],
  465.             buf [MAX_SECTION_TAG],
  466.         #endif
  467.             i;
  468.  
  469.         h = DOF2::HashKey (key);
  470.         l = 0;
  471.         r = Entries.Count - 1;
  472.  
  473.         /*
  474.          * Binary search in a sorted list of entries in O(log n) time. This algorithm makes for example with 256 elements a maximum of ~8 steps until the entry is found if it exists.
  475.          * A sequential search would take up to 256 steps. That was the case in the first Double-O-Files script.
  476.          */
  477.         while (l <= r)
  478.         {
  479.             if ((r - l) < 2)
  480.             {
  481.                 if (h == SortedEntryList [l][0])
  482.                 {
  483.                     m = l;
  484.                     entry = SortedEntryList [l][1];
  485.                 }
  486.                 else if (r > l && h == SortedEntryList [r][0])
  487.                 {
  488.                     m = r;
  489.                     entry = SortedEntryList [r][1];
  490.                 }
  491.                 break;
  492.             }
  493.             else
  494.             {
  495.                 m = l + (r - l) / 2;
  496.                 if (h == SortedEntryList [m][0])
  497.                 {
  498.                     entry = SortedEntryList [m][1];
  499.                     break;
  500.                 }
  501.                 else if (h > SortedEntryList [m][0])
  502.                     l = m + 1;
  503.                 else
  504.                     r = m - 1;
  505.             }
  506.         }
  507.  
  508.         // Candidate found?
  509.         if (entry != INVALID_ENTRY)
  510.         {
  511.             // Check if it's the entry we want.
  512.         #if PACK_CONTENT == true
  513.             strunpack (line, Entries.Line [entry]);
  514.             DOF2::ParseLine (line, keybuf, valbuf, keybufsize, valbufsize);
  515.             strunpack (buf, Entries.Tag [entry]);
  516.             if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag [0] && !buf [0]) || (tag [0] && buf [0] && !strcmp (tag, buf, !CaseSensitive))))
  517.         #else
  518.             DOF2::ParseLine (Entries.Line [entry], keybuf, valbuf, keybufsize, valbufsize);
  519.             if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag [0] && !Entries.Tag [entry][0]) || (tag [0] && Entries.Tag [entry][0] && !strcmp (tag, Entries.Tag [entry], !CaseSensitive))))
  520.         #endif
  521.                 return (pos = m, entry);
  522.             else
  523.             {
  524.                 // If not, look left and right in the list for entries with the same hash code. This can be collisions or entries with the same key from another section.
  525.                 for (i = m - 1; i >= 0 && h == SortedEntryList [i][0]; --i)
  526.                 {
  527.                     entry = SortedEntryList [i][1];
  528.                 #if PACK_CONTENT == true
  529.                     strunpack (line, Entries.Line [entry]);
  530.                     DOF2::ParseLine (line, keybuf, valbuf, keybufsize, valbufsize);
  531.                     strunpack (buf, Entries.Tag [entry]);
  532.                     if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag [0] && !buf [0]) || (tag [0] && buf [0] && !strcmp (tag, buf, !CaseSensitive))))
  533.                 #else
  534.                     DOF2::ParseLine (Entries.Line [entry], keybuf, valbuf, keybufsize, valbufsize);
  535.                     if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag [0] && !Entries.Tag [entry][0]) || (tag [0] && Entries.Tag [entry][0] && !strcmp (tag, Entries.Tag [entry], !CaseSensitive))))
  536.                 #endif
  537.                         return (pos = i, entry);
  538.                 }
  539.  
  540.                 for (i = m + 1; i < Entries.Count && h == SortedEntryList [i][0]; ++i)
  541.                 {
  542.                     entry = SortedEntryList [i][1];
  543.                 #if PACK_CONTENT == true
  544.                     strunpack (line, Entries.Line [entry]);
  545.                     DOF2::ParseLine (line, keybuf, valbuf, keybufsize, valbufsize);
  546.                     strunpack (buf, Entries.Tag [entry]);
  547.                     if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag [0] && !buf [0]) || (tag [0] && buf [0] && !strcmp (tag, buf, !CaseSensitive))))
  548.                 #else
  549.                     DOF2::ParseLine (Entries.Line [entry], keybuf, valbuf, keybufsize, valbufsize);
  550.                     if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag [0] && !Entries.Tag [entry][0]) || (tag [0] && Entries.Tag [entry][0] && !strcmp (tag, Entries.Tag [entry], !CaseSensitive))))
  551.                 #endif
  552.                         return (pos = i, entry);
  553.                 }
  554.             }
  555.         }
  556.     }
  557.    
  558.     keybuf [0] = valbuf [0] = '\0';
  559.     return INVALID_ENTRY;
  560. }
  561.  
  562. stock DOF2::SetString (const file [], const key [], const value [], const tag [] = "")
  563. {
  564.     if (file [0] && key [0])
  565.     {
  566.         new
  567.             entry,
  568.             pos,
  569.             section = INVALID_SECTION,
  570.             keybuf [MAX_LINE_SIZE],
  571.             valbuf [MAX_LINE_SIZE],
  572.         #if PACK_CONTENT == true
  573.             buf [MAX_SECTION_TAG],
  574.             line [MAX_LINE_SIZE],
  575.         #endif
  576.             i;
  577.  
  578.         if (!CurrentFile [0] || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.
  579.             if (!DOF2::ParseFile (file, -1, false))
  580.                 return 0;
  581.  
  582.         entry = DOF2::SearchEntry (key, tag, keybuf, valbuf, pos);
  583.  
  584.         // If the entry has been found, just change it's content.
  585.         if (entry != INVALID_ENTRY)
  586.         {
  587.             FileChanged = true;
  588.         #if PACK_CONTENT == true
  589.             format (line, sizeof (line), "%s = %s", key, value [0] ? value : ("(null)"));
  590.             return strpack (Entries.Line [entry], line);
  591.         #else
  592.             format (Entries.Line [entry], sizeof (Entries.Line []), "%s = %s", key, value [0] ? value : ("(null)"));
  593.             return 1;
  594.         #endif
  595.         }
  596.  
  597.         if (Entries.Count >= MAX_ENTRIES)
  598.             return 0;
  599.  
  600.         // Search for the section where the entry belongs.
  601.         if (!tag [0])
  602.             section = 0;
  603.         else
  604.         {
  605.             for (i = 1; i < Sections.Count; ++i)
  606.             {
  607.             #if PACK_CONTENT == true
  608.                 strunpack (buf, Sections.Tag [i]);
  609.                 if (buf [0] && !strcmp (tag, buf, !CaseSensitive))
  610.                 {
  611.                     section = i;
  612.                     break;
  613.                 }
  614.             #else
  615.                 if (Sections.Tag [i][0] && !strcmp (tag, Sections.Tag [i], !CaseSensitive))
  616.                 {
  617.                     section = i;
  618.                     break;
  619.                 }
  620.             #endif
  621.             }
  622.         }
  623.  
  624.         // Section we want does not exist, create new one if possible.
  625.         if (section == INVALID_SECTION)
  626.         {
  627.             if (Sections.Count >= MAX_SECTIONS)
  628.                 return 0;
  629.  
  630.             section = Sections.Count++;
  631.         #if PACK_CONTENT == true
  632.             strpack (Sections.Tag [section], tag);
  633.         #else
  634.             DOF2::strcpy (Sections.Tag [section], tag);
  635.         #endif
  636.             Sections.FirstEntry [section] = Sections.LastEntry [section] = INVALID_ENTRY;
  637.         }
  638.  
  639.         // Add the entry to the section. Section's content is defined by a linear two way list.
  640.     #if PACK_CONTENT == true
  641.         format (line, sizeof (line), "%s = %s", key, value [0] ? value : ("(null)"));
  642.         strpack (Entries.Line [Entries.Count], line);
  643.     #else
  644.         format (Entries.Line [Entries.Count], sizeof (Entries.Line []), "%s = %s", key, value [0] ? value : ("(null)"));
  645.     #endif
  646.         Entries.Tag [Entries.Count] = Sections.Tag [section];
  647.     #if MAX_SECTIONS >= 256
  648.         Entries.Section [Entries.Count] = section;
  649.     #else
  650.         Entries.Section {Entries.Count} = section;
  651.     #endif
  652.         Entries.NextEntry [Entries.Count] = INVALID_ENTRY;
  653.  
  654.         // Add entry to sorted list of entries and move to right correct position in O(n) time.
  655.         SortedEntryList [Entries.Count][0] = DOF2::HashKey (key);
  656.         SortedEntryList [Entries.Count][1] = Entries.Count;
  657.         i = Entries.Count - 1;
  658.         while (i >= 0 && SortedEntryList [i][0] > SortedEntryList [i + 1][0])
  659.         {
  660.             DOF2::SwapSortedEntries (SortedEntryList [i], SortedEntryList [i + 1]);
  661.             --i;
  662.         }
  663.  
  664.         if (Sections.LastEntry [section] == INVALID_ENTRY) // No entry in this section.
  665.         {
  666.             Sections.FirstEntry [section] = Sections.LastEntry [section] = Entries.Count;
  667.             Entries.PreviousEntry [Entries.Count] = INVALID_ENTRY;
  668.         }
  669.         else
  670.         {
  671.             Entries.NextEntry [Sections.LastEntry [section]] = Entries.Count;
  672.             Entries.PreviousEntry [Entries.Count] = Sections.LastEntry [section];
  673.             Sections.LastEntry [section] = Entries.Count;
  674.         }
  675.         ++Entries.Count;
  676.         FileChanged = true;
  677.     }
  678.     DOF2_SaveFile();
  679.     return 1;
  680. }
  681.  
  682. stock DOF2::GetString (const file [], const key [], const tag [] = "")
  683. {
  684.     new buf [MAX_LINE_SIZE];
  685.     DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
  686.     return buf;
  687. }
  688.  
  689. stock DOF2::GetStringEx (const file [], const key [], result [], size, const tag [] = "")
  690. {
  691.     if (file [0] && key [0])
  692.     {
  693.         new
  694.             pos,
  695.             keybuf [MAX_LINE_SIZE];
  696.  
  697.         if (!CurrentFile [0] || strcmp (CurrentFile, file))
  698.         {
  699.             if (!DOF2::ParseFile (file, -1, false))
  700.             {
  701.                 result [0] = '\0';
  702.                 return 0;
  703.             }
  704.         }
  705.  
  706.         // Find entry and assign the result with it's value.
  707.         return (DOF2::SearchEntry (key, tag, keybuf, result, pos, sizeof (keybuf), size) != INVALID_ENTRY);
  708.     }
  709.     return 0;
  710. }
  711.  
  712. stock DOF2::Unset (file [], key [], tag [] = "")
  713. {
  714.     if (file [0] && key [0])
  715.     {
  716.         new
  717.             entry,
  718.             pos,
  719.             keybuf [MAX_LINE_SIZE],
  720.             valbuf [MAX_LINE_SIZE];
  721.  
  722.         if (!CurrentFile [0] || strcmp (CurrentFile, file))
  723.             if (!DOF2::ParseFile (file, -1, false))
  724.                 return 0;
  725.  
  726.         if ((entry = DOF2::SearchEntry (key, tag, keybuf, valbuf, pos)) != INVALID_ENTRY)
  727.         {
  728.             // Remove entry from it's section.
  729.         #if MAX_SECTIONS >= 256
  730.             if (Sections.FirstEntry [Entries.Section [entry]] == entry) // Is the entry the first entry in the section? Make it's next entry the first entry.
  731.         #else
  732.             if (Sections.FirstEntry [Entries.Section {entry}] == entry)
  733.         #endif
  734.             {
  735.             #if MAX_SECTIONS >= 256
  736.                 Sections.FirstEntry [Entries.Section [entry]] = Entries.NextEntry [entry];
  737.             #else
  738.                 Sections.FirstEntry [Entries.Section {entry}] = Entries.NextEntry [entry];
  739.             #endif
  740.                 if (Entries.NextEntry [entry] != INVALID_ENTRY)
  741.                     Entries.PreviousEntry [Entries.NextEntry [entry]] = INVALID_ENTRY;
  742.             }
  743.             else
  744.             {
  745.                 Entries.NextEntry [Entries.PreviousEntry [entry]] = Entries.NextEntry [entry];
  746.                 if (Entries.NextEntry [entry] != INVALID_ENTRY)
  747.                     Entries.PreviousEntry [Entries.NextEntry [entry]] = Entries.PreviousEntry [entry];
  748.             }
  749.  
  750.         #if MAX_SECTIONS >= 256
  751.             if (Sections.LastEntry [Entries.Section [entry]] == entry)
  752.         #else
  753.             if (Sections.LastEntry [Entries.Section {entry}] == entry)
  754.         #endif
  755.             {
  756.             #if MAX_SECTIONS >= 256
  757.                 Sections.LastEntry [Entries.Section [entry]] = Entries.PreviousEntry [entry];
  758.             #else
  759.                 Sections.LastEntry [Entries.Section {entry}] = Entries.PreviousEntry [entry];
  760.             #endif
  761.                 if (Entries.PreviousEntry [entry] != INVALID_ENTRY)
  762.                     Entries.NextEntry [Entries.PreviousEntry [entry]] = INVALID_ENTRY;
  763.             }
  764.             else
  765.             {
  766.                 Entries.PreviousEntry [Entries.NextEntry [entry]] = Entries.PreviousEntry [entry];
  767.                 if (Entries.PreviousEntry [entry] != INVALID_ENTRY)
  768.                     Entries.NextEntry [Entries.PreviousEntry [entry]] = Entries.NextEntry [entry];
  769.             }
  770.  
  771.             // Move the entry to the end of the sorted list and decrement Entries.Count to forget about the unset Entries.
  772.             while (pos < (Entries.Count - 1))
  773.             {
  774.                 DOF2::SwapSortedEntries (SortedEntryList [pos], SortedEntryList [pos + 1]);
  775.                 ++pos;
  776.             }
  777.             --Entries.Count;
  778.             FileChanged = true;
  779.             return 1;
  780.         }
  781.     }
  782.     return 0;
  783. }
  784.  
  785. stock DOF2::RenameKey (file [], oldkey [], newkey [], tag [] = "")
  786. {
  787.     if (file [0] && oldkey [0])
  788.     {
  789.         new
  790.             entry,
  791.             pos,
  792.         #if PACK_CONTENT == true
  793.             line [MAX_LINE_SIZE],
  794.         #endif
  795.             keybuf [MAX_LINE_SIZE],
  796.             valbuf [MAX_LINE_SIZE];
  797.  
  798.         if (!CurrentFile [0] || strcmp (CurrentFile, file))
  799.             if (!DOF2::ParseFile (file, -1, false))
  800.                 return 0;
  801.  
  802.         if ((entry = DOF2::SearchEntry (oldkey, tag, keybuf, valbuf, pos)) != INVALID_ENTRY)
  803.         {
  804.             // Change content of Entries.
  805.         #if PACK_CONTENT == true
  806.             format (line, sizeof (line), "%s = %s", newkey, valbuf [0] ? valbuf : ("(null)"));
  807.             strpack (Entries.Line [entry], line);
  808.         #else
  809.             format (Entries.Line [entry], sizeof (Entries.Line []), "%s = %s", newkey, valbuf [0] ? valbuf : ("(null)"));
  810.         #endif
  811.  
  812.             // Because the hashcode has been changed, the entry has to move in the list.
  813.             SortedEntryList [pos][0] = DOF2::HashKey (newkey);
  814.             if (pos < (MAX_ENTRIES - 1) && SortedEntryList [pos][0] > SortedEntryList [pos + 1][0])
  815.             {
  816.                 // Hash value of key is greater than the hash value of it's right neighbor, move to the right by swapping the 2 entries.
  817.                 while (pos < (MAX_ENTRIES - 1) && SortedEntryList [pos][0] > SortedEntryList [pos + 1][0])
  818.                 {
  819.                     DOF2::SwapSortedEntries (SortedEntryList [pos], SortedEntryList [pos + 1]);
  820.                     ++pos;
  821.                 }
  822.             }
  823.             else if (pos > 0 && SortedEntryList [pos][0] < SortedEntryList [pos + 1][0])
  824.             {
  825.                 // Hash value of key is smaller than the hash value of it' left neighbor, move to the left by swapping the 2 entries.
  826.                 while (pos > 0 && SortedEntryList [pos][0] < SortedEntryList [pos - 1][0])
  827.                 {
  828.                     DOF2::SwapSortedEntries (SortedEntryList [pos], SortedEntryList [pos - 1]);
  829.                     --pos;
  830.                 }
  831.             }
  832.  
  833.             FileChanged = true;
  834.             return 1;
  835.         }
  836.     }
  837.     return 0;
  838. }
  839.  
  840. stock bool: DOF2::IsSet (file [], key [], tag [] = "")
  841. {
  842.     new
  843.         pos,
  844.         keybuf [MAX_LINE_SIZE],
  845.         valbuf [MAX_LINE_SIZE];
  846.  
  847.     if (!CurrentFile [0] || strcmp (CurrentFile, file))
  848.         if (!DOF2::ParseFile (file, -1, false))
  849.             return false;
  850.  
  851.     // Try to find the Entries.
  852.     return (DOF2::SearchEntry (key, tag, keybuf, valbuf, pos) != INVALID_ENTRY);
  853. }
  854.  
  855. stock DOF2::SetInt (const file [], const key [], value, const tag [] = "")
  856. {
  857.     new buf [16];
  858.     format (buf, sizeof (buf), "%d", value);
  859.     return DOF2::SetString (file, key, buf, tag);
  860. }
  861.  
  862. stock DOF2::GetInt (const file [], const key [], const tag [] = "")
  863. {
  864.     new buf [16];
  865.     DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
  866.     return strval (buf);
  867. }
  868.  
  869. stock DOF2::SetHex (file [], key [], value, tag [] = "")
  870. {
  871.     new buf [16];
  872.     DOF2::hexstr (value, buf);
  873.     return DOF2::SetString (file, key, buf, tag);
  874. }
  875.  
  876. stock DOF2::GetHex (file [], key [], tag [] = "")
  877. {
  878.     new buf [16];
  879.     DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
  880.     return DOF2::strhex (buf);
  881. }
  882.  
  883. stock DOF2::SetBin (file [], key [], value, tag [] = "")
  884. {
  885.     new buf [35];
  886.     DOF2::binstr (value, buf);
  887.     return DOF2::SetString (file, key, buf, tag);
  888. }
  889.  
  890. stock DOF2::GetBin (file [], key [], tag [] = "")
  891. {
  892.     new buf [35];
  893.     DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
  894.     return DOF2::strbin (buf);
  895. }
  896.  
  897. stock DOF2::SetFloat (const file [], const key [], Float: value, const tag [] = "")
  898. {
  899.     new buf [32];
  900.     format (buf, sizeof (buf), "%.8f", value);
  901.     return DOF2::SetString (file, key, buf, tag);
  902. }
  903.  
  904. stock Float: DOF2::GetFloat (const file [], const key [], const tag [] = "")
  905. {
  906.     new buf [32];
  907.     DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
  908.     return floatstr (buf);
  909. }
  910.  
  911. stock bool: DOF2::GetBool (const file [], const key [], const tag [] = "")
  912. {
  913.     new buf [16];
  914.     DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
  915.     return (strval (buf) || (buf [0] && !strcmp (buf, "true", true)));
  916. }
  917.  
  918. stock DOF2::SetBool (const file [], const key [], bool: value, const tag [] = "")
  919.     return DOF2::SetString (file, key, value ? ("true") : ("false"), tag);
  920.    
  921. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  922.  
  923. stock DOF2::PrintFile (comment [] = "")
  924. {
  925.     if (CurrentFile [0])
  926.     {
  927.         new
  928.             bool: firstline = true,
  929.             entry,
  930.         #if PACK_CONTENT == true
  931.             buf [MAX_LINE_SIZE],
  932.         #endif
  933.             entries,
  934.             i;
  935.  
  936.         printf ("[DOF] Current file: %s", CurrentFile);
  937.         for ( ; i < Sections.Count; ++i)
  938.         {
  939.             if (i)
  940.             {
  941.                 if (!firstline)
  942.                     print (" ");
  943.                 else
  944.                     firstline = false;
  945.             #if PACK_CONTENT == true
  946.                 strunpack (buf, Sections.Tag [i]);
  947.                 printf ("[%s]", buf);
  948.             #else
  949.                 printf ("[%s]", Sections.Tag [i]);
  950.             #endif
  951.             }
  952.             entry = Sections.FirstEntry [i];
  953.             while (entry != INVALID_ENTRY)
  954.             {
  955.             #if PACK_CONTENT == true
  956.                 strunpack (buf, Entries.Line [entry]);
  957.                 print (buf);
  958.             #else
  959.                 print (Entries.Line [entry]);
  960.             #endif
  961.                 entry = Entries.NextEntry [entry];
  962.                 firstline = false;
  963.                 ++entries;
  964.             }
  965.         }
  966.         printf ("* %d sections, %d entries", i, entries);
  967.         if (comment [0])
  968.             printf ("* Comment: %s", comment);
  969.         return 1;
  970.     }
  971.     return 0;
  972. }
  973.  
  974. stock DOF2::WriteFile ()
  975. {
  976.     if (CurrentFile [0])
  977.     {
  978.         new
  979.             File: f = fopen (CurrentFile, io_write),
  980.             bool: firstline = true,
  981.             entry;
  982.  
  983.         if (f)
  984.         {
  985.             for (new i; i < Sections.Count; ++i)
  986.             {
  987.                 if (Sections.FirstEntry [i] != INVALID_ENTRY) // Do not write when empty.
  988.                 {
  989.                     if (i)
  990.                     {
  991.                         if (!firstline)
  992.                         {
  993.                             fputchar (f, '\r', UseUTF8);
  994.                             fputchar (f, '\n', UseUTF8);
  995.                         }
  996.                         else
  997.                             firstline = false;
  998.                         fputchar (f, '[', UseUTF8);
  999.                         fwritechars (f, Sections.Tag [i]);
  1000.                         fputchar (f, ']', UseUTF8);
  1001.                         fputchar (f, '\r', UseUTF8);
  1002.                         fputchar (f, '\n', UseUTF8);
  1003.                     }
  1004.  
  1005.                     entry = Sections.FirstEntry [i];
  1006.                     while (entry != INVALID_ENTRY)
  1007.                     {
  1008.                         fwritechars (f, Entries.Line [entry]);
  1009.                         fputchar (f, '\r', UseUTF8);
  1010.                         fputchar (f, '\n', UseUTF8);
  1011.                         entry = Entries.NextEntry [entry];
  1012.                         firstline = false;
  1013.                     }
  1014.                 }
  1015.             }
  1016.             FileChanged = false;
  1017.             return fclose (f);
  1018.         }
  1019.     }
  1020.     return 0;
  1021. }
  1022.  
  1023. stock DOF2::ParseFile (const file [], extraid = -1, bool: callback = false)
  1024. {
  1025.     if (file [0] && DOF2::FileExists (file))
  1026.     {
  1027.         /*
  1028.         Write the file in the buffer when:
  1029.         - There is actually a file in the buffer
  1030.         - The file in the buffer is not the file you want to parse and this file has been changed.
  1031.         - Or the current file is the file you want to and has been changed.
  1032.         */
  1033.         //if (CurrentFile [0] && ((strcmp (CurrentFile, file) && FileChanged) || FileChanged))
  1034.         if (CurrentFile [0] && FileChanged) // Equal to the query above but shorter.
  1035.             DOF2::WriteFile ();
  1036.  
  1037.         new
  1038.             File: f = fopen (file, io_readwrite),
  1039.             buf [MAX_LINE_SIZE],
  1040.         #if PACK_CONTENT == true
  1041.             line [MAX_LINE_SIZE char],
  1042.             tag [MAX_SECTION_TAG],
  1043.         #else
  1044.             line [MAX_LINE_SIZE],
  1045.         #endif
  1046.             key [MAX_LINE_SIZE],
  1047.             value [MAX_LINE_SIZE],
  1048.             c,
  1049.             pos;
  1050.  
  1051.         if (f)
  1052.         {
  1053.             FileChanged = false;
  1054.             DOF2::SetFile (file);
  1055.  
  1056.             Sections.Count = 1;
  1057.             Entries.Count = 0;
  1058.             Sections.FirstEntry [0] = Sections.LastEntry [0] = INVALID_ENTRY;
  1059.  
  1060.             for (new i, size = flength (f); i < size; ++i)
  1061.             {
  1062.                 c = fgetchar (f, false);
  1063.                 //c = fgetchar (f, 0, UseUTF8);
  1064.                 if (pos == MAX_LINE_SIZE - 1 || c == '\n' || c == '\r')
  1065.                     c = '\0';
  1066.             #if PACK_CONTENT == true
  1067.                 line {pos++} = c;
  1068.             #else
  1069.                 line [pos++] = c;
  1070.             #endif
  1071.  
  1072.                 if (c == '\0')
  1073.                 {
  1074.                     // A new section found. Add the section to the list of sections.
  1075.                 #if PACK_CONTENT == true
  1076.                     if (line {0} == '[')
  1077.                 #else
  1078.                     if (line [0] == '[')
  1079.                 #endif
  1080.                     {
  1081.                         if (Sections.Count < MAX_SECTIONS)
  1082.                         {
  1083.                             pos = 1;
  1084.                         #if PACK_CONTENT == true
  1085.                             while (line {pos} && line {pos} != ']' && (pos - 1) < MAX_SECTION_TAG)
  1086.                             {
  1087.                                 Sections.Tag [Sections.Count]{pos - 1} = line {pos};
  1088.                                 ++pos;
  1089.                             }
  1090.                             Sections.Tag [Sections.Count]{pos - 1} = '\0';
  1091.                         #else
  1092.                             while (line [pos] && line [pos] != ']' && (pos - 1) < MAX_SECTION_TAG)
  1093.                             {
  1094.                                 Sections.Tag [Sections.Count][pos - 1] = line [pos];
  1095.                                 ++pos;
  1096.                             }
  1097.                             Sections.Tag [Sections.Count][pos - 1] = '\0';
  1098.                         #endif
  1099.                             Sections.FirstEntry [Sections.Count] = Sections.LastEntry [Sections.Count] = INVALID_ENTRY;
  1100.                             ++Sections.Count;
  1101.                         }
  1102.                     }
  1103.                     else
  1104.                     {
  1105.                     #if PACK_CONTENT == true
  1106.                         if (line {0})
  1107.                     #else
  1108.                         if (line [0])
  1109.                     #endif
  1110.                         {
  1111.                         #if PACK_CONTENT == true
  1112.                             strunpack (buf, line);
  1113.                             DOF2::ParseLine (buf, key, value);
  1114.                             strunpack (tag, Sections.Tag [Sections.Count - 1]);
  1115.  
  1116.                             // Call a specific function for a specific entry - ZCMD-style!
  1117.                             if (callback)
  1118.                             {
  1119.                                 format (buf, sizeof (buf), "_OnParseFile_%s_%s", tag, key);
  1120.                                 if (!CallRemoteFunction (buf, "is", extraid, value))
  1121.                                     CallRemoteFunction ("_OnDefaultParseFile", "issss", extraid, value [0] ? value : ("\1"), key, Sections.Tag [Sections.Count - 1][0] ? Sections.Tag [Sections.Count - 1] : ("\1"), file);
  1122.                             }
  1123.                         #else
  1124.                             DOF2::ParseLine (line, key, value);
  1125.  
  1126.                             // Call a specific function for a specific entry - ZCMD-style!
  1127.                             if (callback)
  1128.                             {
  1129.                                 format (buf, sizeof (buf), "_OnParseFile_%s_%s", Sections.Tag [Sections.Count - 1], key);
  1130.                                 if (!CallRemoteFunction (buf, "is", extraid, value))
  1131.                                     CallRemoteFunction ("_OnDefaultParseFile", "issss", extraid, value [0] ? value : ("\1"), key, Sections.Tag [Sections.Count - 1][0] ? Sections.Tag [Sections.Count - 1] : ("\1"), file);
  1132.                             }
  1133.                         #endif
  1134.  
  1135.                             // Add entry to it's section and to the list which will be sorted.
  1136.                             Entries.Line [Entries.Count] = line;
  1137.                             Entries.Tag [Entries.Count] = Sections.Tag [Sections.Count - 1];
  1138.                         #if MAX_SECTIONS >= 256
  1139.                             Entries.Section [Entries.Count] = Sections.Count - 1;
  1140.                         #else
  1141.                             Entries.Section {Entries.Count} = Sections.Count - 1;
  1142.                         #endif
  1143.                             Entries.NextEntry [Entries.Count] = INVALID_ENTRY;
  1144.  
  1145.                             SortedEntryList [Entries.Count][0] = DOF2::HashKey (key);
  1146.                             SortedEntryList [Entries.Count][1] = Entries.Count;
  1147.  
  1148.                             if (Sections.LastEntry [Sections.Count - 1] == INVALID_ENTRY)
  1149.                             {
  1150.                                 Sections.FirstEntry [Sections.Count - 1] = Sections.LastEntry [Sections.Count - 1] = Entries.Count;
  1151.                                 Entries.PreviousEntry [Entries.Count] = INVALID_ENTRY;
  1152.                             }
  1153.                             else
  1154.                             {
  1155.                                 Entries.NextEntry [Sections.LastEntry [Sections.Count - 1]] = Entries.Count;
  1156.                                 Entries.PreviousEntry [Entries.Count] = Sections.LastEntry [Sections.Count - 1];
  1157.                                 Sections.LastEntry [Sections.Count - 1] = Entries.Count;
  1158.                             }
  1159.                             ++Entries.Count;
  1160.                         }
  1161.                     }
  1162.                     pos = 0;
  1163.                 }
  1164.             }
  1165.             /*
  1166.              * Sort list of entries by it's hashcodes in O(n * log n) time.
  1167.              * (Worst case is actually O(n * n), however, this QuickSort implementation chooses a randomized pivot
  1168.              * to minimize the chance for the worst case.)
  1169.              */
  1170.             DOF2::SortEntries (SortedEntryList, 0, Entries.Count - 1, true);
  1171.             return fclose (f);
  1172.         }
  1173.     }
  1174.     return 0;
  1175. }
  1176.  
  1177. // Rather useless.
  1178. stock DOF2::ReparseFile (file [], extraid, bool: callback = true)
  1179. {
  1180.     if (file [0] && CurrentFile [0] && !strcmp (file, CurrentFile))
  1181.     {
  1182.         CurrentFile [0] = '\0';
  1183.         return DOF2::ParseFile (file, extraid, callback);
  1184.     }
  1185.     return 0;
  1186. }
  1187.  
  1188. private DOF2::ParseLine (const line [], key [], value [], keysize = sizeof (key), valuesize = sizeof (value))
  1189. {
  1190.     new
  1191.         pos,
  1192.         readpos;
  1193.  
  1194.     if ((pos = charfind (line, '=')) != -1)
  1195.     {
  1196.         // Read key and value.
  1197.         readpos = pos - 1;
  1198.         while (readpos >= 0 && line [readpos] == ' ')
  1199.             --readpos;
  1200.  
  1201.         if (readpos >= 0 && keysize > (readpos + 1))
  1202.         {
  1203.             key [readpos + 1] = '\0';
  1204.             while (readpos >= 0)
  1205.             {
  1206.                 key [readpos] = line [readpos];
  1207.                 --readpos;
  1208.             }
  1209.         }
  1210.         else
  1211.             return 0;
  1212.  
  1213.         readpos = pos + 1;
  1214.         ++pos;
  1215.         while (line [readpos] == ' ')
  1216.         {
  1217.             ++pos;
  1218.             ++readpos;
  1219.         }
  1220.  
  1221.         if (line [readpos])
  1222.         {
  1223.             while (readpos >= 0 && line [readpos] && valuesize > (readpos - pos + 1))
  1224.             {
  1225.                 value [readpos - pos] = line [readpos];
  1226.                 ++readpos;
  1227.             }
  1228.             value [readpos - pos] = '\0';
  1229.         }
  1230.         else
  1231.         {
  1232.             key [0] = value [0] = '\0';
  1233.             return 0;
  1234.         }
  1235.        
  1236.         if (!strcmp (value, "(null)", true))
  1237.             value [0] = '\0';
  1238.         return 1;
  1239.     }
  1240.     key [0] = value [0] = '\0';
  1241.     return 0;
  1242. }
  1243.  
  1244. stock DOF2::File (user [])
  1245. {
  1246.     new newfile [MAX_FILE_SIZE];
  1247.     format (newfile, sizeof (newfile), USER_FILE_PATH, DOF2::udb_encode (user));
  1248.     return newfile;
  1249. }
  1250.  
  1251. stock bool: DOF2::CheckLogin (file [], password [])
  1252.     return (file [0] && password [0] && DOF2::num_hash (password) == DOF2::GetInt (file, USER_PW_HASH_KEY));
  1253.  
  1254. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  1255.  
  1256. stock DOF2::binstr (value, dest [], size = sizeof (dest))
  1257. {
  1258.     new buf [32 + 3] = "0b";
  1259.     for (new i = 0; i < 32; ++i)
  1260.         buf [i + 2] = '0' + ((value >>> (31 - i)) & 1);
  1261.  
  1262.     DOF2::strcpy (dest, buf, size);
  1263. }
  1264.     //format (dest, size, "0b%b", value);
  1265.  
  1266. stock DOF2::hexstr (value, dest [], size = sizeof (dest))
  1267. {
  1268.     static const characters [] =
  1269.     {
  1270.         '0', '1', '2', '3',
  1271.         '4', '5', '6', '7',
  1272.         '8', '9', 'A', 'B',
  1273.         'C', 'D', 'E', 'F'
  1274.     };
  1275.    
  1276.     new buf [8 + 3] = "0x";
  1277.    
  1278.     for (new i = 0; i < 8; ++i)
  1279.         buf [2 + i] = characters [(value >>> ((7 - i) << 2)) & 0x0F];
  1280.  
  1281.     DOF2::strcpy (dest, buf, size);
  1282. }
  1283.     //format (dest, size, "0x%x", value);
  1284.  
  1285. stock DOF2::strhex (string [])
  1286. {
  1287.     new
  1288.         i,
  1289.         value;
  1290.        
  1291.     if (string [0] == '0' && (string [1] == 'x' || string [1] == 'X'))
  1292.         i = 2;
  1293.  
  1294.     while (string [i])
  1295.     {
  1296.         value <<= 4;
  1297.         switch (string [i])
  1298.         {
  1299.             case '0' .. '9':
  1300.                 value |= string [i] - '0';
  1301.  
  1302.             case 'A' .. 'F':
  1303.                 value |= string [i] - 'A' + 10;
  1304.  
  1305.             case 'a' .. 'f':
  1306.                 value |= string [i] - 'a' + 10;
  1307.  
  1308.             default:
  1309.                 return 0;
  1310.         }
  1311.         ++i;
  1312.     }
  1313.     return value;
  1314. }
  1315.  
  1316. stock DOF2::strbin (string [])
  1317. {
  1318.     new
  1319.         i,
  1320.         value;
  1321.  
  1322.     if (string [0] == '0' && (string [1] == 'b' || string [1] == 'B'))
  1323.         i = 2;
  1324.  
  1325.     while (string [i])
  1326.     {
  1327.         if (string [i] != '1' && string [i] != '0')
  1328.             return 0;
  1329.  
  1330.         value <<= 1;
  1331.         value |= (string [i] - '0');
  1332.         ++i;
  1333.     }
  1334.     return value;
  1335. }
  1336.  
  1337. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  1338.  
  1339. private charfind (const string [], c)
  1340. {
  1341.     for (new i, len = strlen (string); i < len; ++i)
  1342.         if (string [i] == c)
  1343.             return i;
  1344.     return -1;
  1345. }
  1346.  
  1347. private fwritechars (File: handle, const c [])
  1348. {
  1349.     new pos;
  1350. #if PACK_CONTENT == true
  1351.     while (c {pos})
  1352.         fputchar (handle, c {pos++}, UseUTF8);
  1353. #else
  1354.     while (c [pos])
  1355.         fputchar (handle, c [pos++], UseUTF8);
  1356. #endif
  1357. }
  1358.  
  1359. private DOF2::SortEntries (entries [][2], l, r, bool: randomize = true)
  1360. {
  1361.     if (r > l)
  1362.     {
  1363.         if (randomize)
  1364.         {
  1365.             new k = l + (random (65535) % (r - l + 1));
  1366.             DOF2::SwapSortedEntries (entries [k], entries [r]);
  1367.         }
  1368.  
  1369.         new
  1370.             i = l - 1,
  1371.             j = r,
  1372.             pivot = entries [r][0];
  1373.  
  1374.         while (i < j)
  1375.         {
  1376.             do
  1377.                 ++i;
  1378.             while (entries [i][0] <= pivot && i < r);
  1379.  
  1380.             do
  1381.                 --j;
  1382.             while (entries [j][0] >= pivot && j > l);
  1383.  
  1384.             if (i < j)
  1385.                 DOF2::SwapSortedEntries (entries [i], entries [j]);
  1386.         }
  1387.         DOF2::SwapSortedEntries (entries [i], entries [r]);
  1388.         DOF2::SortEntries (entries, l, i - 1, randomize);
  1389.         DOF2::SortEntries (entries, i + 1, r, randomize);
  1390.     }
  1391. }
  1392.  
  1393. private DOF2::SwapSortedEntries (a [2], b [2])
  1394. {
  1395.     new c [2];
  1396.     c [0] = a [0];
  1397.     c [1] = a [1];
  1398.     a [0] = b [0];
  1399.     a [1] = b [1];
  1400.     b [0] = c [0];
  1401.     b [1] = c [1];
  1402. }
  1403.  
  1404. stock DOF2::SortAllSections (file [], bool: ignorecase = true, bool: ascending = true)
  1405. {
  1406.     if (file [0])
  1407.     {
  1408.         if (!CurrentFile [0] || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.
  1409.             if (!DOF2::ParseFile (file, -1, false))
  1410.                 return 0;
  1411.  
  1412.         new
  1413.             entries [MAX_ENTRIES],
  1414.             keys [MAX_ENTRIES][MAX_LINE_SIZE],
  1415.             key [MAX_LINE_SIZE],
  1416.             value [MAX_LINE_SIZE],
  1417.         #if PACK_CONTENT == true
  1418.             line [MAX_LINE_SIZE],
  1419.         #endif
  1420.             entry,
  1421.             i;
  1422.  
  1423.         for (new section = 0; section < Sections.Count; ++section)
  1424.         {
  1425.             i = 0;
  1426.             entry = Sections.FirstEntry [section];
  1427.             while (entry != INVALID_ENTRY)
  1428.             {
  1429.             #if PACK_CONTENT == true
  1430.                 strunpack (line, Entries.Line [entry]);
  1431.                 DOF2::ParseLine (line, key, value);
  1432.             #else
  1433.                 DOF2::ParseLine (Entries.Line [entry], key, value);
  1434.             #endif
  1435.                 keys [i][0] = '\0';
  1436.                 strcat (keys [i], key);
  1437.                 entries [i] = entry;
  1438.                 entry = Entries.NextEntry [entry];
  1439.                 ++i;
  1440.             }
  1441.  
  1442.             if (i > 0)
  1443.                 DOF2::SortSection_Internal (section, entries, keys, 0, i - 1, ignorecase, ascending);
  1444.         }
  1445.         return 1;
  1446.     }
  1447.     return 0;
  1448. }
  1449.  
  1450. stock DOF2::SortSection (file [], tag [], bool: ignorecase = true, bool: ascending = true)
  1451. {
  1452.     if (file [0])
  1453.     {
  1454.         if (!CurrentFile [0] || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.
  1455.             if (!DOF2::ParseFile (file, -1, false))
  1456.                 return 0;
  1457.  
  1458.         new
  1459.             section = INVALID_SECTION,
  1460.             entries [MAX_ENTRIES],
  1461.             keys [MAX_ENTRIES][MAX_LINE_SIZE],
  1462.             key [MAX_LINE_SIZE],
  1463.             buf [MAX_LINE_SIZE],
  1464.         #if PACK_CONTENT == true
  1465.             line [MAX_LINE_SIZE],
  1466.         #endif
  1467.             entry,
  1468.             i;
  1469.  
  1470.         if (!tag [0])
  1471.             section = 0;
  1472.         else
  1473.         {
  1474.             for (i = 1; i < Sections.Count; ++i)
  1475.             {
  1476.             #if PACK_CONTENT == true
  1477.                 strunpack (buf, Sections.Tag [i]);
  1478.                 if (buf [0] && !strcmp (tag, buf, !CaseSensitive))
  1479.                 {
  1480.                     section = i;
  1481.                     break;
  1482.                 }
  1483.             #else
  1484.                 if (Sections.Tag [i][0] && !strcmp (tag, Sections.Tag [i], !CaseSensitive))
  1485.                 {
  1486.                     section = i;
  1487.                     break;
  1488.                 }
  1489.             #endif
  1490.             }
  1491.         }
  1492.  
  1493.         if (section != INVALID_SECTION)
  1494.         {
  1495.             i = 0;
  1496.             entry = Sections.FirstEntry [section];
  1497.             while (entry != INVALID_ENTRY)
  1498.             {
  1499.             #if PACK_CONTENT == true
  1500.                 strunpack (line, Entries.Line [entry]);
  1501.                 DOF2::ParseLine (line, key, buf);
  1502.             #else
  1503.                 DOF2::ParseLine (Entries.Line [entry], key, buf);
  1504.             #endif
  1505.                 keys [i][0] = '\0';
  1506.                 strcat (keys [i], key);
  1507.                 entries [i] = entry;
  1508.                 entry = Entries.NextEntry [entry];
  1509.                 ++i;
  1510.             }
  1511.  
  1512.             if (i > 0)
  1513.             {
  1514.                 DOF2::SortSection_Internal (section, entries, keys, 0, i - 1, ignorecase, ascending);
  1515.                 return 1;
  1516.             }
  1517.         }
  1518.     }
  1519.     return 0;
  1520. }
  1521.  
  1522. private DOF2::SortSection_Internal (section, entries [], keys [][], l, r, bool: ignorecase = true, bool: ascending = true)
  1523. {
  1524.     // Entries must be stored into an array...
  1525.     if (0 <= section < Sections.Count && r > l)
  1526.     {
  1527.         new
  1528.             i = l - 1,
  1529.             j = r,
  1530.             buf [MAX_LINE_SIZE];
  1531.  
  1532.         static
  1533.             pivot [MAX_LINE_SIZE]; // Must be static, otherwise too much memory usage during recursion ==> Script will crash!
  1534.  
  1535.         pivot [0] = '\0';
  1536.         strcat (pivot, keys [r]);
  1537.  
  1538.         while (i < j)
  1539.         {
  1540.             if (ascending)
  1541.             {
  1542.                 do
  1543.                     ++i;
  1544.                 while (strcmp (keys [i], pivot,  ignorecase) <= 0 && i < r);
  1545.  
  1546.                 do
  1547.                     --j;
  1548.                 while (strcmp (keys [j], pivot, ignorecase) >= 0 && j > l);
  1549.             }
  1550.             else
  1551.             {
  1552.                 do
  1553.                     ++i;
  1554.                 while (strcmp (keys [i], pivot,  ignorecase) >= 0 && i < r);
  1555.  
  1556.                 do
  1557.                     --j;
  1558.                 while (strcmp (keys [j], pivot, ignorecase) <= 0 && j > l);
  1559.             }
  1560.  
  1561.             if (i < j)
  1562.             {
  1563.                 DOF2::SwapEntries (section, entries [i], entries [j]);
  1564.  
  1565.                 DOF2::strcpy (buf, keys [i]);
  1566.                 DOF2::strcpy (keys [i], keys [j], MAX_LINE_SIZE);
  1567.                 DOF2::strcpy (keys [j], buf, MAX_LINE_SIZE);
  1568.  
  1569.                 entries [i] ^= entries [j];
  1570.                 entries [j] ^= entries [i];
  1571.                 entries [i] ^= entries [j];
  1572.             }
  1573.         }
  1574.  
  1575.         if (i != r)
  1576.         {
  1577.             DOF2::SwapEntries (section, entries [i], entries [r]);
  1578.  
  1579.             DOF2::strcpy (buf, keys [i]);
  1580.             DOF2::strcpy (keys [i], keys [r], MAX_LINE_SIZE);
  1581.             DOF2::strcpy (keys [r], buf, MAX_LINE_SIZE);
  1582.  
  1583.             entries [i] ^= entries [r];
  1584.             entries [r] ^= entries [i];
  1585.             entries [i] ^= entries [r];
  1586.         }
  1587.  
  1588.         DOF2::SortSection_Internal (section, entries, keys, l, i - 1, ignorecase, ascending);
  1589.         DOF2::SortSection_Internal (section, entries, keys, i + 1, r, ignorecase, ascending);
  1590.     }
  1591. }
  1592.  
  1593. private DOF2::SwapEntries (section, entry1, entry2)
  1594. {
  1595.     // This swaps two entries in the entry list of a section. (Pointers are swapped)
  1596.     if (0 <= section < Sections.Count && 0 <= entry1 <= Entries.Count && 0 <= entry2 <= Entries.Count)
  1597.     {
  1598.         if (entry1 == Sections.FirstEntry [section])
  1599.             Sections.FirstEntry [section] = entry2;
  1600.         else if (entry2 == Sections.FirstEntry [section])
  1601.             Sections.FirstEntry [section] = entry1;
  1602.  
  1603.         if (entry1 == Sections.LastEntry [section])
  1604.             Sections.LastEntry [section] = entry2;
  1605.         else if (entry2 == Sections.LastEntry [section])
  1606.             Sections.LastEntry [section] = entry1;
  1607.  
  1608.         if (Entries.NextEntry [entry1] == entry2)
  1609.         {
  1610.             Entries.NextEntry [entry1] = Entries.NextEntry [entry2];
  1611.             Entries.PreviousEntry [entry2] = Entries.PreviousEntry [entry1];
  1612.  
  1613.             if (Entries.PreviousEntry [entry1] != INVALID_ENTRY)
  1614.                 Entries.NextEntry [Entries.PreviousEntry [entry1]] = entry2;
  1615.  
  1616.             if (Entries.NextEntry [entry2] != INVALID_ENTRY)
  1617.                 Entries.PreviousEntry [Entries.NextEntry [entry2]] = entry1;
  1618.  
  1619.             Entries.NextEntry [entry2] = entry1;
  1620.             Entries.PreviousEntry [entry1] = entry2;
  1621.         }
  1622.         else if (Entries.NextEntry [entry2] == entry1)
  1623.         {
  1624.             Entries.NextEntry [entry2] = Entries.NextEntry [entry1];
  1625.             Entries.PreviousEntry [entry1] = Entries.PreviousEntry [entry2];
  1626.  
  1627.             if (Entries.PreviousEntry [entry2] != INVALID_ENTRY)
  1628.                 Entries.NextEntry [Entries.PreviousEntry [entry2]] = entry1;
  1629.  
  1630.             if (Entries.NextEntry [entry1] != INVALID_ENTRY)
  1631.                 Entries.PreviousEntry [Entries.NextEntry [entry1]] = entry2;
  1632.  
  1633.             Entries.NextEntry [entry1] = entry2;
  1634.             Entries.PreviousEntry [entry2] = entry1;
  1635.         }
  1636.         else
  1637.         {
  1638.             new pointer;
  1639.  
  1640.             if (Entries.PreviousEntry [entry1] != INVALID_ENTRY)
  1641.                 Entries.NextEntry [Entries.PreviousEntry [entry1]] = entry2;
  1642.  
  1643.             if (Entries.NextEntry [entry1] != INVALID_ENTRY)
  1644.                 Entries.PreviousEntry [Entries.NextEntry [entry1]] = entry2;
  1645.  
  1646.             if (Entries.PreviousEntry [entry2] != INVALID_ENTRY)
  1647.                 Entries.NextEntry [Entries.PreviousEntry [entry2]] = entry1;
  1648.  
  1649.             if (Entries.NextEntry [entry2] != INVALID_ENTRY)
  1650.                 Entries.PreviousEntry [Entries.NextEntry [entry2]] = entry1;
  1651.  
  1652.             pointer = Entries.NextEntry [entry1];
  1653.             Entries.NextEntry [entry1] = Entries.NextEntry [entry2];
  1654.             Entries.NextEntry [entry2] = pointer;
  1655.  
  1656.             pointer = Entries.PreviousEntry [entry1];
  1657.             Entries.PreviousEntry [entry1] = Entries.PreviousEntry [entry2];
  1658.             Entries.PreviousEntry [entry2] = pointer;
  1659.         }
  1660.         return 1;
  1661.     }
  1662.     return 0;
  1663. }
  1664.  
  1665. private DOF2::HashKey (const key [])
  1666. {
  1667.     new
  1668.         h = -1,
  1669.         i,
  1670.         j;
  1671.  
  1672.     if (CaseSensitive)
  1673.     {
  1674.         while ((j = key [i++]))
  1675.             h = h * 33 + j;
  1676.     }
  1677.     else
  1678.     {
  1679.         while ((j = tolower (key [i++])))
  1680.             h = h * 33 + j;
  1681.     }
  1682.     return h;
  1683. }
  1684.  
  1685. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  1686.  
  1687. stock DOF2::strcpy (dest [], const src [], size = sizeof (dest))
  1688. {
  1689.     dest [0] = '\0';
  1690.     strcat (dest, src, size);
  1691. }
  1692.  
  1693. // Replace [oldstr] with [newstr] in [srcstr] and copy write the new string to 'deststr'.
  1694.  
  1695. stock DOF2::strreplace (const newstr [], const oldstr [], const srcstr [], deststr [], bool: ignorecase = false, size = sizeof (deststr))
  1696. {
  1697.     new
  1698.         newlen = strlen (newstr),
  1699.         oldlen = strlen (oldstr),
  1700.         srclen = strlen (srcstr),
  1701.         idx,
  1702.         rep;
  1703.  
  1704.     for (new i = 0; i < srclen; ++i)
  1705.     {
  1706.         if (idx < (size - 1))
  1707.         {
  1708.             if ((i + oldlen) <= srclen)
  1709.             {
  1710.                 if (!strcmp (srcstr [i], oldstr, ignorecase, oldlen))
  1711.                 {
  1712.                     deststr [idx] = '\0';
  1713.                     strcat (deststr, newstr, size);
  1714.                     ++rep;
  1715.                     idx += newlen;
  1716.                     i += oldlen - 1;
  1717.                 }
  1718.                 else
  1719.                     deststr [idx++] = srcstr [i];
  1720.             }
  1721.             else
  1722.                 deststr [idx++] = srcstr [i];
  1723.         }
  1724.         else
  1725.             return rep;
  1726.     }
  1727.     deststr [idx] = '\0';
  1728.     return rep;
  1729. }
  1730.  
  1731. stock DOF2::udb_encode (nickname [])
  1732. {
  1733.     new
  1734.         buf [256],
  1735.         result [256];
  1736.  
  1737.     static const symbols [][2][] =
  1738.     {
  1739.         {"_", "_00"},
  1740.         {";", "_01"},
  1741.         {"!", "_02"},
  1742.         {"/", "_03"},
  1743.         {"\\", "_04"},
  1744.         {"[", "_05"},
  1745.         {"]", "_06"},
  1746.         {"?", "_07"},
  1747.         {".", "_08"},
  1748.         {"*", "_09"},
  1749.         {"<", "_10"},
  1750.         {">", "_11"},
  1751.         {"{", "_12"},
  1752.         {"}", "_13"},
  1753.         {" ", "_14"},
  1754.         {"\"", "_15"},
  1755.         {":", "_16"},
  1756.         {"|", "_17"},
  1757.         {"=", "_18"}
  1758.     };
  1759.  
  1760.     strcat (buf, nickname);
  1761.     for (new i = 0; i < sizeof (symbols); ++i)
  1762.     {
  1763.         DOF2::strreplace (symbols [i][1], symbols [i][0], buf, result);
  1764.         DOF2::strcpy (buf, result);
  1765.     }
  1766.     return result;
  1767. }
  1768.  
  1769. stock DOF2::udb_decode (nickname [])
  1770. {
  1771.     new
  1772.         buf [256],
  1773.         result [256];
  1774.  
  1775.     static const symbols [][2][] =
  1776.     {
  1777.         {"_", "_00"},
  1778.         {";", "_01"},
  1779.         {"!", "_02"},
  1780.         {"/", "_03"},
  1781.         {"\\", "_04"},
  1782.         {"[", "_05"},
  1783.         {"]", "_06"},
  1784.         {"?", "_07"},
  1785.         {".", "_08"},
  1786.         {"*", "_09"},
  1787.         {"<", "_10"},
  1788.         {">", "_11"},
  1789.         {"{", "_12"},
  1790.         {"}", "_13"},
  1791.         {" ", "_14"},
  1792.         {"\"", "_15"},
  1793.         {":", "_16"},
  1794.         {"|", "_17"},
  1795.         {"=", "_18"}
  1796.     };
  1797.  
  1798.     strcat (buf, nickname);
  1799.     for (new i = 0; i < sizeof (symbols); ++i)
  1800.     {
  1801.         DOF2::strreplace (symbols [i][0], symbols [i][1], buf, result);
  1802.         DOF2::strcpy (buf, result);
  1803.     }
  1804.     return result;
  1805. }
  1806.  
  1807. stock DOF2::num_hash (const buf [])
  1808. {
  1809.     new
  1810.         length = strlen (buf),
  1811.         s1 = 1,
  1812.         s2 = 0,
  1813.         n;
  1814.  
  1815.     for (n = 0; n < length; n++)
  1816.     {
  1817.        s1 = (s1 + buf [n]) % 65521;
  1818.        s2 = (s2 + s1) % 65521;
  1819.     }
  1820.     return (s2 << 16) + s1;
  1821. }
  1822.  
  1823. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  1824.  
  1825. #if defined DUDB_CONVERT
  1826.  
  1827.     #tryinclude <dutils>
  1828.  
  1829.     #define dUser(%0).(             DOF2_GetString(DOF2_File(%0),
  1830.     #define dUserSet(%0).(          DOF2_SetString(DOF2_File(%0),
  1831.     #define dUserINT(%0).(          DOF2_GetInt(DOF2_File(%0),
  1832.     #define dUserSetINT(%0).(       DOF2_SetInt(DOF2_File(%0),
  1833.     #define dUserFLOAT(%0).(        DOF2_GetFloat(DOF2_File(%0),
  1834.     #define dUserSetFLOAT(%0).(     DOF2_SetFloat(DOF2_File(%0),
  1835.     #define udb_Create(%0,%1)       DOF2_CreateFile(DOF2_File(%0),%1)
  1836.     #define udb_RenameUser(%0,%1)   DOF2_RenameFile(DOF2_File(%0),DOF2_File(%1))
  1837.     #define udb_Exists(%0)          DOF2_FileExists(DOF2_File(%0))
  1838.     #define udb_Remove(%0)          DOF2_RemoveFile(DOF2_File(%0))
  1839.     #define udb_CheckLogin(%0,%1)   DOF2_CheckLogin(DOF2_File(%0),%1)
  1840.  
  1841.     #if !defined _dudb_included
  1842.         #define _dudb_included
  1843.     #endif
  1844.  
  1845. #endif
  1846.  
  1847. #if defined DINI_CONVERT
  1848.  
  1849.     #define dini_Exists             DOF2_FileExists
  1850.     #define dini_Remove             DOF2_RemoveFile
  1851.     #define dini_Create             DOF2_CreateFile
  1852.     #define dini_Set                DOF2_SetString
  1853.     #define dini_Get                DOF2_GetString
  1854.     #define dini_IntSet             DOF2_SetInt
  1855.     #define dini_Int                DOF2_GetInt
  1856.     #define dini_BoolSet            DOF2_SetBool
  1857.     #define dini_Bool               DOF2_GetBool
  1858.     #define dini_FloatSet           DOF2_SetFloat
  1859.     #define dini_Float              DOF2_GetFloat
  1860.     #define dini_Unset              DOF2_Unset
  1861.     #define dini_Isset              DOF2_IsSet
  1862.  
  1863.     #if !defined _dini_included
  1864.         #define _dini_included
  1865.     #endif
  1866.  
  1867. #endif
  1868.  
  1869. /*
  1870. #if defined DINI_CONVERT || defined DUDB_CONVERT
  1871.  
  1872.     #define udb_hash                DOF2_num_hash
  1873.     #define num_hash                DOF2_num_hash
  1874.     #define udb_encode              DOF2_udb_encode
  1875.     #define udb_decode              DOF2_udb_decode
  1876.  
  1877. #endif
  1878. */
  1879.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement