Advertisement
losnato

[Include] DOF2

Jan 1st, 2012
24,667
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 51.36 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       (128)
  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 && 0 // 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 (file [])
  266.     DOF2::strcpy (CurrentFile, file);
  267.  
  268. stock DOF2::GetFile ()
  269.     return CurrentFile;
  270.  
  271. stock DOF2::CreateFile (file [], 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 (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 (key [], 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 (file [], key [], value [], 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.     return 1;
  679. }
  680.  
  681. stock DOF2::GetString (file [], key [], tag [] = "")
  682. {
  683.     new buf [MAX_LINE_SIZE];
  684.     DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
  685.     return buf;
  686. }
  687.  
  688. stock DOF2::GetStringEx (file [], key [], result [], size, tag [] = "")
  689. {
  690.     if (file [0] && key [0])
  691.     {
  692.         new
  693.             pos,
  694.             keybuf [MAX_LINE_SIZE];
  695.  
  696.         if (!CurrentFile [0] || strcmp (CurrentFile, file))
  697.         {
  698.             if (!DOF2::ParseFile (file, -1, false))
  699.             {
  700.                 result [0] = '\0';
  701.                 return 0;
  702.             }
  703.         }
  704.  
  705.         // Find entry and assign the result with it's value.
  706.         return (DOF2::SearchEntry (key, tag, keybuf, result, pos, sizeof (keybuf), size) != INVALID_ENTRY);
  707.     }
  708.     return 0;
  709. }
  710.  
  711. stock DOF2::Unset (file [], key [], tag [] = "")
  712. {
  713.     if (file [0] && key [0])
  714.     {
  715.         new
  716.             entry,
  717.             pos,
  718.             keybuf [MAX_LINE_SIZE],
  719.             valbuf [MAX_LINE_SIZE];
  720.  
  721.         if (!CurrentFile [0] || strcmp (CurrentFile, file))
  722.             if (!DOF2::ParseFile (file, -1, false))
  723.                 return 0;
  724.  
  725.         if ((entry = DOF2::SearchEntry (key, tag, keybuf, valbuf, pos)) != INVALID_ENTRY)
  726.         {
  727.             // Remove entry from it's section.
  728.         #if MAX_SECTIONS >= 256
  729.             if (Sections.FirstEntry [Entries.Section [entry]] == entry) // Is the entry the first entry in the section? Make it's next entry the first entry.
  730.         #else
  731.             if (Sections.FirstEntry [Entries.Section {entry}] == entry)
  732.         #endif
  733.             {
  734.             #if MAX_SECTIONS >= 256
  735.                 Sections.FirstEntry [Entries.Section [entry]] = Entries.NextEntry [entry];
  736.             #else
  737.                 Sections.FirstEntry [Entries.Section {entry}] = Entries.NextEntry [entry];
  738.             #endif
  739.                 if (Entries.NextEntry [entry] != INVALID_ENTRY)
  740.                     Entries.PreviousEntry [Entries.NextEntry [entry]] = INVALID_ENTRY;
  741.             }
  742.             else
  743.             {
  744.                 Entries.NextEntry [Entries.PreviousEntry [entry]] = Entries.NextEntry [entry];
  745.                 if (Entries.NextEntry [entry] != INVALID_ENTRY)
  746.                     Entries.PreviousEntry [Entries.NextEntry [entry]] = Entries.PreviousEntry [entry];
  747.             }
  748.  
  749.         #if MAX_SECTIONS >= 256
  750.             if (Sections.LastEntry [Entries.Section [entry]] == entry)
  751.         #else
  752.             if (Sections.LastEntry [Entries.Section {entry}] == entry)
  753.         #endif
  754.             {
  755.             #if MAX_SECTIONS >= 256
  756.                 Sections.LastEntry [Entries.Section [entry]] = Entries.PreviousEntry [entry];
  757.             #else
  758.                 Sections.LastEntry [Entries.Section {entry}] = Entries.PreviousEntry [entry];
  759.             #endif
  760.                 if (Entries.PreviousEntry [entry] != INVALID_ENTRY)
  761.                     Entries.NextEntry [Entries.PreviousEntry [entry]] = INVALID_ENTRY;
  762.             }
  763.             else
  764.             {
  765.                 Entries.PreviousEntry [Entries.NextEntry [entry]] = Entries.PreviousEntry [entry];
  766.                 if (Entries.PreviousEntry [entry] != INVALID_ENTRY)
  767.                     Entries.NextEntry [Entries.PreviousEntry [entry]] = Entries.NextEntry [entry];
  768.             }
  769.  
  770.             // Move the entry to the end of the sorted list and decrement Entries.Count to forget about the unset Entries.
  771.             while (pos < (Entries.Count - 1))
  772.             {
  773.                 DOF2::SwapSortedEntries (SortedEntryList [pos], SortedEntryList [pos + 1]);
  774.                 ++pos;
  775.             }
  776.             --Entries.Count;
  777.             FileChanged = true;
  778.             return 1;
  779.         }
  780.     }
  781.     return 0;
  782. }
  783.  
  784. stock DOF2::RenameKey (file [], oldkey [], newkey [], tag [] = "")
  785. {
  786.     if (file [0] && oldkey [0])
  787.     {
  788.         new
  789.             entry,
  790.             pos,
  791.         #if PACK_CONTENT == true
  792.             line [MAX_LINE_SIZE],
  793.         #endif
  794.             keybuf [MAX_LINE_SIZE],
  795.             valbuf [MAX_LINE_SIZE];
  796.  
  797.         if (!CurrentFile [0] || strcmp (CurrentFile, file))
  798.             if (!DOF2::ParseFile (file, -1, false))
  799.                 return 0;
  800.  
  801.         if ((entry = DOF2::SearchEntry (oldkey, tag, keybuf, valbuf, pos)) != INVALID_ENTRY)
  802.         {
  803.             // Change content of Entries.
  804.         #if PACK_CONTENT == true
  805.             format (line, sizeof (line), "%s = %s", newkey, valbuf [0] ? valbuf : ("(null)"));
  806.             strpack (Entries.Line [entry], line);
  807.         #else
  808.             format (Entries.Line [entry], sizeof (Entries.Line []), "%s = %s", newkey, valbuf [0] ? valbuf : ("(null)"));
  809.         #endif
  810.  
  811.             // Because the hashcode has been changed, the entry has to move in the list.
  812.             SortedEntryList [pos][0] = DOF2::HashKey (newkey);
  813.             if (pos < (MAX_ENTRIES - 1) && SortedEntryList [pos][0] > SortedEntryList [pos + 1][0])
  814.             {
  815.                 // Hash value of key is greater than the hash value of it's right neighbor, move to the right by swapping the 2 entries.
  816.                 while (pos < (MAX_ENTRIES - 1) && SortedEntryList [pos][0] > SortedEntryList [pos + 1][0])
  817.                 {
  818.                     DOF2::SwapSortedEntries (SortedEntryList [pos], SortedEntryList [pos + 1]);
  819.                     ++pos;
  820.                 }
  821.             }
  822.             else if (pos > 0 && SortedEntryList [pos][0] < SortedEntryList [pos + 1][0])
  823.             {
  824.                 // Hash value of key is smaller than the hash value of it' left neighbor, move to the left by swapping the 2 entries.
  825.                 while (pos > 0 && SortedEntryList [pos][0] < SortedEntryList [pos - 1][0])
  826.                 {
  827.                     DOF2::SwapSortedEntries (SortedEntryList [pos], SortedEntryList [pos - 1]);
  828.                     --pos;
  829.                 }
  830.             }
  831.  
  832.             FileChanged = true;
  833.             return 1;
  834.         }
  835.     }
  836.     return 0;
  837. }
  838.  
  839. stock bool: DOF2::IsSet (file [], key [], tag [] = "")
  840. {
  841.     new
  842.         pos,
  843.         keybuf [MAX_LINE_SIZE],
  844.         valbuf [MAX_LINE_SIZE];
  845.  
  846.     if (!CurrentFile [0] || strcmp (CurrentFile, file))
  847.         if (!DOF2::ParseFile (file, -1, false))
  848.             return false;
  849.  
  850.     // Try to find the Entries.
  851.     return (DOF2::SearchEntry (key, tag, keybuf, valbuf, pos) != INVALID_ENTRY);
  852. }
  853.  
  854. stock DOF2::SetInt (file [], key [], value, tag [] = "")
  855. {
  856.     new buf [16];
  857.     format (buf, sizeof (buf), "%d", value);
  858.     return DOF2::SetString (file, key, buf, tag);
  859. }
  860.  
  861. stock DOF2::GetInt (file [], key [], tag [] = "")
  862. {
  863.     new buf [16];
  864.     DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
  865.     return strval (buf);
  866. }
  867.  
  868. stock DOF2::SetHex (file [], key [], value, tag [] = "")
  869. {
  870.     new buf [16];
  871.     DOF2::hexstr (value, buf);
  872.     return DOF2::SetString (file, key, buf, tag);
  873. }
  874.  
  875. stock DOF2::GetHex (file [], key [], tag [] = "")
  876. {
  877.     new buf [16];
  878.     DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
  879.     return DOF2::strhex (buf);
  880. }
  881.  
  882. stock DOF2::SetBin (file [], key [], value, tag [] = "")
  883. {
  884.     new buf [35];
  885.     DOF2::binstr (value, buf);
  886.     return DOF2::SetString (file, key, buf, tag);
  887. }
  888.  
  889. stock DOF2::GetBin (file [], key [], tag [] = "")
  890. {
  891.     new buf [35];
  892.     DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
  893.     return DOF2::strbin (buf);
  894. }
  895.  
  896. stock DOF2::SetFloat (file [], key [], Float: value, tag [] = "")
  897. {
  898.     new buf [32];
  899.     format (buf, sizeof (buf), "%.8f", value);
  900.     return DOF2::SetString (file, key, buf, tag);
  901. }
  902.  
  903. stock Float: DOF2::GetFloat (file [], key [], tag [] = "")
  904. {
  905.     new buf [32];
  906.     DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
  907.     return floatstr (buf);
  908. }
  909.  
  910. stock bool: DOF2::GetBool (file [], key [], tag [] = "")
  911. {
  912.     new buf [16];
  913.     DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
  914.     return (strval (buf) || (buf [0] && !strcmp (buf, "true", true)));
  915. }
  916.  
  917. stock DOF2::SetBool (file [], key [], bool: value, tag [] = "")
  918.     return DOF2::SetString (file, key, value ? ("true") : ("false"), tag);
  919.    
  920. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  921.  
  922. stock DOF2::PrintFile (comment [] = "")
  923. {
  924.     if (CurrentFile [0])
  925.     {
  926.         new
  927.             bool: firstline = true,
  928.             entry,
  929.         #if PACK_CONTENT == true
  930.             buf [MAX_LINE_SIZE],
  931.         #endif
  932.             entries,
  933.             i;
  934.  
  935.         printf ("[DOF] Current file: %s", CurrentFile);
  936.         for ( ; i < Sections.Count; ++i)
  937.         {
  938.             if (i)
  939.             {
  940.                 if (!firstline)
  941.                     print (" ");
  942.                 else
  943.                     firstline = false;
  944.             #if PACK_CONTENT == true
  945.                 strunpack (buf, Sections.Tag [i]);
  946.                 printf ("[%s]", buf);
  947.             #else
  948.                 printf ("[%s]", Sections.Tag [i]);
  949.             #endif
  950.             }
  951.             entry = Sections.FirstEntry [i];
  952.             while (entry != INVALID_ENTRY)
  953.             {
  954.             #if PACK_CONTENT == true
  955.                 strunpack (buf, Entries.Line [entry]);
  956.                 print (buf);
  957.             #else
  958.                 print (Entries.Line [entry]);
  959.             #endif
  960.                 entry = Entries.NextEntry [entry];
  961.                 firstline = false;
  962.                 ++entries;
  963.             }
  964.         }
  965.         printf ("* %d sections, %d entries", i, entries);
  966.         if (comment [0])
  967.             printf ("* Comment: %s", comment);
  968.         return 1;
  969.     }
  970.     return 0;
  971. }
  972.  
  973. stock DOF2::WriteFile ()
  974. {
  975.     if (CurrentFile [0])
  976.     {
  977.         new
  978.             File: f = fopen (CurrentFile, io_write),
  979.             bool: firstline = true,
  980.             entry;
  981.  
  982.         if (f)
  983.         {
  984.             for (new i; i < Sections.Count; ++i)
  985.             {
  986.                 if (Sections.FirstEntry [i] != INVALID_ENTRY) // Do not write when empty.
  987.                 {
  988.                     if (i)
  989.                     {
  990.                         if (!firstline)
  991.                         {
  992.                             fputchar (f, '\r', UseUTF8);
  993.                             fputchar (f, '\n', UseUTF8);
  994.                         }
  995.                         else
  996.                             firstline = false;
  997.                         fputchar (f, '[', UseUTF8);
  998.                         fwritechars (f, Sections.Tag [i]);
  999.                         fputchar (f, ']', UseUTF8);
  1000.                         fputchar (f, '\r', UseUTF8);
  1001.                         fputchar (f, '\n', UseUTF8);
  1002.                     }
  1003.  
  1004.                     entry = Sections.FirstEntry [i];
  1005.                     while (entry != INVALID_ENTRY)
  1006.                     {
  1007.                         fwritechars (f, Entries.Line [entry]);
  1008.                         fputchar (f, '\r', UseUTF8);
  1009.                         fputchar (f, '\n', UseUTF8);
  1010.                         entry = Entries.NextEntry [entry];
  1011.                         firstline = false;
  1012.                     }
  1013.                 }
  1014.             }
  1015.             FileChanged = false;
  1016.             return fclose (f);
  1017.         }
  1018.     }
  1019.     return 0;
  1020. }
  1021.  
  1022. stock DOF2::ParseFile (file [], extraid = -1, bool: callback = false)
  1023. {
  1024.     if (file [0] && DOF2::FileExists (file))
  1025.     {
  1026.         /*
  1027.         Write the file in the buffer when:
  1028.         - There is actually a file in the buffer
  1029.         - The file in the buffer is not the file you want to parse and this file has been changed.
  1030.         - Or the current file is the file you want to and has been changed.
  1031.         */
  1032.         //if (CurrentFile [0] && ((strcmp (CurrentFile, file) && FileChanged) || FileChanged))
  1033.         if (CurrentFile [0] && FileChanged) // Equal to the query above but shorter.
  1034.             DOF2::WriteFile ();
  1035.  
  1036.         new
  1037.             File: f = fopen (file, io_readwrite),
  1038.             buf [MAX_LINE_SIZE],
  1039.         #if PACK_CONTENT == true
  1040.             line [MAX_LINE_SIZE char],
  1041.             tag [MAX_SECTION_TAG],
  1042.         #else
  1043.             line [MAX_LINE_SIZE],
  1044.         #endif
  1045.             key [MAX_LINE_SIZE],
  1046.             value [MAX_LINE_SIZE],
  1047.             c,
  1048.             pos;
  1049.  
  1050.         if (f)
  1051.         {
  1052.             FileChanged = false;
  1053.             DOF2::SetFile (file);
  1054.  
  1055.             Sections.Count = 1;
  1056.             Entries.Count = 0;
  1057.             Sections.FirstEntry [0] = Sections.LastEntry [0] = INVALID_ENTRY;
  1058.  
  1059.             for (new i, size = flength (f); i < size; ++i)
  1060.             {
  1061.                 c = fgetchar (f, 0, UseUTF8);
  1062.                 if (pos == MAX_LINE_SIZE - 1 || c == '\n' || c == '\r')
  1063.                     c = '\0';
  1064.             #if PACK_CONTENT == true
  1065.                 line {pos++} = c;
  1066.             #else
  1067.                 line [pos++] = c;
  1068.             #endif
  1069.  
  1070.                 if (c == '\0')
  1071.                 {
  1072.                     // A new section found. Add the section to the list of sections.
  1073.                 #if PACK_CONTENT == true
  1074.                     if (line {0} == '[')
  1075.                 #else
  1076.                     if (line [0] == '[')
  1077.                 #endif
  1078.                     {
  1079.                         if (Sections.Count < MAX_SECTIONS)
  1080.                         {
  1081.                             pos = 1;
  1082.                         #if PACK_CONTENT == true
  1083.                             while (line {pos} && line {pos} != ']' && (pos - 1) < MAX_SECTION_TAG)
  1084.                             {
  1085.                                 Sections.Tag [Sections.Count]{pos - 1} = line {pos};
  1086.                                 ++pos;
  1087.                             }
  1088.                             Sections.Tag [Sections.Count]{pos - 1} = '\0';
  1089.                         #else
  1090.                             while (line [pos] && line [pos] != ']' && (pos - 1) < MAX_SECTION_TAG)
  1091.                             {
  1092.                                 Sections.Tag [Sections.Count][pos - 1] = line [pos];
  1093.                                 ++pos;
  1094.                             }
  1095.                             Sections.Tag [Sections.Count][pos - 1] = '\0';
  1096.                         #endif
  1097.                             Sections.FirstEntry [Sections.Count] = Sections.LastEntry [Sections.Count] = INVALID_ENTRY;
  1098.                             ++Sections.Count;
  1099.                         }
  1100.                     }
  1101.                     else
  1102.                     {
  1103.                     #if PACK_CONTENT == true
  1104.                         if (line {0})
  1105.                     #else
  1106.                         if (line [0])
  1107.                     #endif
  1108.                         {
  1109.                         #if PACK_CONTENT == true
  1110.                             strunpack (buf, line);
  1111.                             DOF2::ParseLine (buf, key, value);
  1112.                             strunpack (tag, Sections.Tag [Sections.Count - 1]);
  1113.  
  1114.                             // Call a specific function for a specific entry - ZCMD-style!
  1115.                             if (callback)
  1116.                             {
  1117.                                 format (buf, sizeof (buf), "_OnParseFile_%s_%s", tag, key);
  1118.                                 if (!CallRemoteFunction (buf, "is", extraid, value))
  1119.                                     CallRemoteFunction ("_OnDefaultParseFile", "issss", extraid, value [0] ? value : ("\1"), key, Sections.Tag [Sections.Count - 1][0] ? Sections.Tag [Sections.Count - 1] : ("\1"), file);
  1120.                             }
  1121.                         #else
  1122.                             DOF2::ParseLine (line, key, value);
  1123.  
  1124.                             // Call a specific function for a specific entry - ZCMD-style!
  1125.                             if (callback)
  1126.                             {
  1127.                                 format (buf, sizeof (buf), "_OnParseFile_%s_%s", Sections.Tag [Sections.Count - 1], key);
  1128.                                 if (!CallRemoteFunction (buf, "is", extraid, value))
  1129.                                     CallRemoteFunction ("_OnDefaultParseFile", "issss", extraid, value [0] ? value : ("\1"), key, Sections.Tag [Sections.Count - 1][0] ? Sections.Tag [Sections.Count - 1] : ("\1"), file);
  1130.                             }
  1131.                         #endif
  1132.  
  1133.                             // Add entry to it's section and to the list which will be sorted.
  1134.                             Entries.Line [Entries.Count] = line;
  1135.                             Entries.Tag [Entries.Count] = Sections.Tag [Sections.Count - 1];
  1136.                         #if MAX_SECTIONS >= 256
  1137.                             Entries.Section [Entries.Count] = Sections.Count - 1;
  1138.                         #else
  1139.                             Entries.Section {Entries.Count} = Sections.Count - 1;
  1140.                         #endif
  1141.                             Entries.NextEntry [Entries.Count] = INVALID_ENTRY;
  1142.  
  1143.                             SortedEntryList [Entries.Count][0] = DOF2::HashKey (key);
  1144.                             SortedEntryList [Entries.Count][1] = Entries.Count;
  1145.  
  1146.                             if (Sections.LastEntry [Sections.Count - 1] == INVALID_ENTRY)
  1147.                             {
  1148.                                 Sections.FirstEntry [Sections.Count - 1] = Sections.LastEntry [Sections.Count - 1] = Entries.Count;
  1149.                                 Entries.PreviousEntry [Entries.Count] = INVALID_ENTRY;
  1150.                             }
  1151.                             else
  1152.                             {
  1153.                                 Entries.NextEntry [Sections.LastEntry [Sections.Count - 1]] = Entries.Count;
  1154.                                 Entries.PreviousEntry [Entries.Count] = Sections.LastEntry [Sections.Count - 1];
  1155.                                 Sections.LastEntry [Sections.Count - 1] = Entries.Count;
  1156.                             }
  1157.                             ++Entries.Count;
  1158.                         }
  1159.                     }
  1160.                     pos = 0;
  1161.                 }
  1162.             }
  1163.             /*
  1164.              * Sort list of entries by it's hashcodes in O(n * log n) time.
  1165.              * (Worst case is actually O(n * n), however, this QuickSort implementation chooses a randomized pivot
  1166.              * to minimize the chance for the worst case.)
  1167.              */
  1168.             DOF2::SortEntries (SortedEntryList, 0, Entries.Count - 1, true);
  1169.             return fclose (f);
  1170.         }
  1171.     }
  1172.     return 0;
  1173. }
  1174.  
  1175. // Rather useless.
  1176. stock DOF2::ReparseFile (file [], extraid, bool: callback = true)
  1177. {
  1178.     if (file [0] && CurrentFile [0] && !strcmp (file, CurrentFile))
  1179.     {
  1180.         CurrentFile [0] = '\0';
  1181.         return DOF2::ParseFile (file, extraid, callback);
  1182.     }
  1183.     return 0;
  1184. }
  1185.  
  1186. private DOF2::ParseLine (line [], key [], value [], keysize = sizeof (key), valuesize = sizeof (value))
  1187. {
  1188.     new
  1189.         pos,
  1190.         readpos;
  1191.  
  1192.     if ((pos = charfind (line, '=')) != -1)
  1193.     {
  1194.         // Read key and value.
  1195.         readpos = pos - 1;
  1196.         while (readpos >= 0 && line [readpos] == ' ')
  1197.             --readpos;
  1198.  
  1199.         if (readpos >= 0 && keysize > (readpos + 1))
  1200.         {
  1201.             key [readpos + 1] = '\0';
  1202.             while (readpos >= 0)
  1203.             {
  1204.                 key [readpos] = line [readpos];
  1205.                 --readpos;
  1206.             }
  1207.         }
  1208.         else
  1209.             return 0;
  1210.  
  1211.         readpos = pos + 1;
  1212.         ++pos;
  1213.         while (line [readpos] == ' ')
  1214.         {
  1215.             ++pos;
  1216.             ++readpos;
  1217.         }
  1218.  
  1219.         if (line [readpos])
  1220.         {
  1221.             while (readpos >= 0 && line [readpos] && valuesize > (readpos - pos + 1))
  1222.             {
  1223.                 value [readpos - pos] = line [readpos];
  1224.                 ++readpos;
  1225.             }
  1226.             value [readpos - pos] = '\0';
  1227.         }
  1228.         else
  1229.         {
  1230.             key [0] = value [0] = '\0';
  1231.             return 0;
  1232.         }
  1233.        
  1234.         if (!strcmp (value, "(null)", true))
  1235.             value [0] = '\0';
  1236.         return 1;
  1237.     }
  1238.     key [0] = value [0] = '\0';
  1239.     return 0;
  1240. }
  1241.  
  1242. stock DOF2::File (user [])
  1243. {
  1244.     new newfile [MAX_FILE_SIZE];
  1245.     format (newfile, sizeof (newfile), USER_FILE_PATH, DOF2::udb_encode (user));
  1246.     return newfile;
  1247. }
  1248.  
  1249. stock bool: DOF2::CheckLogin (file [], password [])
  1250.     return (file [0] && password [0] && DOF2::num_hash (password) == DOF2::GetInt (file, USER_PW_HASH_KEY));
  1251.  
  1252. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  1253.  
  1254. stock DOF2::binstr (value, dest [], size = sizeof (dest))
  1255. {
  1256.     new buf [32 + 3] = "0b";
  1257.     for (new i = 0; i < 32; ++i)
  1258.         buf [i + 2] = '0' + ((value >>> (31 - i)) & 1);
  1259.  
  1260.     DOF2::strcpy (dest, buf, size);
  1261. }
  1262.     //format (dest, size, "0b%b", value);
  1263.  
  1264. stock DOF2::hexstr (value, dest [], size = sizeof (dest))
  1265. {
  1266.     static const characters [] =
  1267.     {
  1268.         '0', '1', '2', '3',
  1269.         '4', '5', '6', '7',
  1270.         '8', '9', 'A', 'B',
  1271.         'C', 'D', 'E', 'F'
  1272.     };
  1273.    
  1274.     new buf [8 + 3] = "0x";
  1275.    
  1276.     for (new i = 0; i < 8; ++i)
  1277.         buf [2 + i] = characters [(value >>> ((7 - i) << 2)) & 0x0F];
  1278.  
  1279.     DOF2::strcpy (dest, buf, size);
  1280. }
  1281.     //format (dest, size, "0x%x", value);
  1282.  
  1283. stock DOF2::strhex (string [])
  1284. {
  1285.     new
  1286.         i,
  1287.         value;
  1288.        
  1289.     if (string [0] == '0' && (string [1] == 'x' || string [1] == 'X'))
  1290.         i = 2;
  1291.  
  1292.     while (string [i])
  1293.     {
  1294.         value <<= 4;
  1295.         switch (string [i])
  1296.         {
  1297.             case '0' .. '9':
  1298.                 value |= string [i] - '0';
  1299.  
  1300.             case 'A' .. 'F':
  1301.                 value |= string [i] - 'A' + 10;
  1302.  
  1303.             case 'a' .. 'f':
  1304.                 value |= string [i] - 'a' + 10;
  1305.  
  1306.             default:
  1307.                 return 0;
  1308.         }
  1309.         ++i;
  1310.     }
  1311.     return value;
  1312. }
  1313.  
  1314. stock DOF2::strbin (string [])
  1315. {
  1316.     new
  1317.         i,
  1318.         value;
  1319.  
  1320.     if (string [0] == '0' && (string [1] == 'b' || string [1] == 'B'))
  1321.         i = 2;
  1322.  
  1323.     while (string [i])
  1324.     {
  1325.         if (string [i] != '1' && string [i] != '0')
  1326.             return 0;
  1327.  
  1328.         value <<= 1;
  1329.         value |= (string [i] - '0');
  1330.         ++i;
  1331.     }
  1332.     return value;
  1333. }
  1334.  
  1335. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  1336.  
  1337. private charfind (string [], c)
  1338. {
  1339.     for (new i, len = strlen (string); i < len; ++i)
  1340.         if (string [i] == c)
  1341.             return i;
  1342.     return -1;
  1343. }
  1344.  
  1345. private fwritechars (File: handle, c [])
  1346. {
  1347.     new pos;
  1348. #if PACK_CONTENT == true
  1349.     while (c {pos})
  1350.         fputchar (handle, c {pos++}, UseUTF8);
  1351. #else
  1352.     while (c [pos])
  1353.         fputchar (handle, c [pos++], UseUTF8);
  1354. #endif
  1355. }
  1356.  
  1357. private DOF2::SortEntries (entries [][2], l, r, bool: randomize = true)
  1358. {
  1359.     if (r > l)
  1360.     {
  1361.         if (randomize)
  1362.         {
  1363.             new k = l + (random (65535) % (r - l + 1));
  1364.             DOF2::SwapSortedEntries (entries [k], entries [r]);
  1365.         }
  1366.  
  1367.         new
  1368.             i = l - 1,
  1369.             j = r,
  1370.             pivot = entries [r][0];
  1371.  
  1372.         while (i < j)
  1373.         {
  1374.             do
  1375.                 ++i;
  1376.             while (entries [i][0] <= pivot && i < r);
  1377.  
  1378.             do
  1379.                 --j;
  1380.             while (entries [j][0] >= pivot && j > l);
  1381.  
  1382.             if (i < j)
  1383.                 DOF2::SwapSortedEntries (entries [i], entries [j]);
  1384.         }
  1385.         DOF2::SwapSortedEntries (entries [i], entries [r]);
  1386.         DOF2::SortEntries (entries, l, i - 1, randomize);
  1387.         DOF2::SortEntries (entries, i + 1, r, randomize);
  1388.     }
  1389. }
  1390.  
  1391. private DOF2::SwapSortedEntries (a [2], b [2])
  1392. {
  1393.     new c [2];
  1394.     c [0] = a [0];
  1395.     c [1] = a [1];
  1396.     a [0] = b [0];
  1397.     a [1] = b [1];
  1398.     b [0] = c [0];
  1399.     b [1] = c [1];
  1400. }
  1401.  
  1402. stock DOF2::SortAllSections (file [], bool: ignorecase = true, bool: ascending = true)
  1403. {
  1404.     if (file [0])
  1405.     {
  1406.         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.
  1407.             if (!DOF2::ParseFile (file, -1, false))
  1408.                 return 0;
  1409.  
  1410.         new
  1411.             entries [MAX_ENTRIES],
  1412.             keys [MAX_ENTRIES][MAX_LINE_SIZE],
  1413.             key [MAX_LINE_SIZE],
  1414.             value [MAX_LINE_SIZE],
  1415.         #if PACK_CONTENT == true
  1416.             line [MAX_LINE_SIZE],
  1417.         #endif
  1418.             entry,
  1419.             i;
  1420.  
  1421.         for (new section = 0; section < Sections.Count; ++section)
  1422.         {
  1423.             i = 0;
  1424.             entry = Sections.FirstEntry [section];
  1425.             while (entry != INVALID_ENTRY)
  1426.             {
  1427.             #if PACK_CONTENT == true
  1428.                 strunpack (line, Entries.Line [entry]);
  1429.                 DOF2::ParseLine (line, key, value);
  1430.             #else
  1431.                 DOF2::ParseLine (Entries.Line [entry], key, value);
  1432.             #endif
  1433.                 keys [i][0] = '\0';
  1434.                 strcat (keys [i], key);
  1435.                 entries [i] = entry;
  1436.                 entry = Entries.NextEntry [entry];
  1437.                 ++i;
  1438.             }
  1439.  
  1440.             if (i > 0)
  1441.                 DOF2::SortSection_Internal (section, entries, keys, 0, i - 1, ignorecase, ascending);
  1442.         }
  1443.         return 1;
  1444.     }
  1445.     return 0;
  1446. }
  1447.  
  1448. stock DOF2::SortSection (file [], tag [], bool: ignorecase = true, bool: ascending = true)
  1449. {
  1450.     if (file [0])
  1451.     {
  1452.         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.
  1453.             if (!DOF2::ParseFile (file, -1, false))
  1454.                 return 0;
  1455.  
  1456.         new
  1457.             section = INVALID_SECTION,
  1458.             entries [MAX_ENTRIES],
  1459.             keys [MAX_ENTRIES][MAX_LINE_SIZE],
  1460.             key [MAX_LINE_SIZE],
  1461.             buf [MAX_LINE_SIZE],
  1462.         #if PACK_CONTENT == true
  1463.             line [MAX_LINE_SIZE],
  1464.         #endif
  1465.             entry,
  1466.             i;
  1467.  
  1468.         if (!tag [0])
  1469.             section = 0;
  1470.         else
  1471.         {
  1472.             for (i = 1; i < Sections.Count; ++i)
  1473.             {
  1474.             #if PACK_CONTENT == true
  1475.                 strunpack (buf, Sections.Tag [i]);
  1476.                 if (buf [0] && !strcmp (tag, buf, !CaseSensitive))
  1477.                 {
  1478.                     section = i;
  1479.                     break;
  1480.                 }
  1481.             #else
  1482.                 if (Sections.Tag [i][0] && !strcmp (tag, Sections.Tag [i], !CaseSensitive))
  1483.                 {
  1484.                     section = i;
  1485.                     break;
  1486.                 }
  1487.             #endif
  1488.             }
  1489.         }
  1490.  
  1491.         if (section != INVALID_SECTION)
  1492.         {
  1493.             i = 0;
  1494.             entry = Sections.FirstEntry [section];
  1495.             while (entry != INVALID_ENTRY)
  1496.             {
  1497.             #if PACK_CONTENT == true
  1498.                 strunpack (line, Entries.Line [entry]);
  1499.                 DOF2::ParseLine (line, key, buf);
  1500.             #else
  1501.                 DOF2::ParseLine (Entries.Line [entry], key, buf);
  1502.             #endif
  1503.                 keys [i][0] = '\0';
  1504.                 strcat (keys [i], key);
  1505.                 entries [i] = entry;
  1506.                 entry = Entries.NextEntry [entry];
  1507.                 ++i;
  1508.             }
  1509.  
  1510.             if (i > 0)
  1511.             {
  1512.                 DOF2::SortSection_Internal (section, entries, keys, 0, i - 1, ignorecase, ascending);
  1513.                 return 1;
  1514.             }
  1515.         }
  1516.     }
  1517.     return 0;
  1518. }
  1519.  
  1520. private DOF2::SortSection_Internal (section, entries [], keys [][], l, r, bool: ignorecase = true, bool: ascending = true)
  1521. {
  1522.     // Entries must be stored into an array...
  1523.     if (0 <= section < Sections.Count && r > l)
  1524.     {
  1525.         new
  1526.             i = l - 1,
  1527.             j = r,
  1528.             buf [MAX_LINE_SIZE];
  1529.  
  1530.         static
  1531.             pivot [MAX_LINE_SIZE]; // Must be static, otherwise too much memory usage during recursion ==> Script will crash!
  1532.  
  1533.         pivot [0] = '\0';
  1534.         strcat (pivot, keys [r]);
  1535.  
  1536.         while (i < j)
  1537.         {
  1538.             if (ascending)
  1539.             {
  1540.                 do
  1541.                     ++i;
  1542.                 while (strcmp (keys [i], pivot,  ignorecase) <= 0 && i < r);
  1543.  
  1544.                 do
  1545.                     --j;
  1546.                 while (strcmp (keys [j], pivot, ignorecase) >= 0 && j > l);
  1547.             }
  1548.             else
  1549.             {
  1550.                 do
  1551.                     ++i;
  1552.                 while (strcmp (keys [i], pivot,  ignorecase) >= 0 && i < r);
  1553.  
  1554.                 do
  1555.                     --j;
  1556.                 while (strcmp (keys [j], pivot, ignorecase) <= 0 && j > l);
  1557.             }
  1558.  
  1559.             if (i < j)
  1560.             {
  1561.                 DOF2::SwapEntries (section, entries [i], entries [j]);
  1562.  
  1563.                 DOF2::strcpy (buf, keys [i]);
  1564.                 DOF2::strcpy (keys [i], keys [j], MAX_LINE_SIZE);
  1565.                 DOF2::strcpy (keys [j], buf, MAX_LINE_SIZE);
  1566.  
  1567.                 entries [i] ^= entries [j];
  1568.                 entries [j] ^= entries [i];
  1569.                 entries [i] ^= entries [j];
  1570.             }
  1571.         }
  1572.  
  1573.         if (i != r)
  1574.         {
  1575.             DOF2::SwapEntries (section, entries [i], entries [r]);
  1576.  
  1577.             DOF2::strcpy (buf, keys [i]);
  1578.             DOF2::strcpy (keys [i], keys [r], MAX_LINE_SIZE);
  1579.             DOF2::strcpy (keys [r], buf, MAX_LINE_SIZE);
  1580.  
  1581.             entries [i] ^= entries [r];
  1582.             entries [r] ^= entries [i];
  1583.             entries [i] ^= entries [r];
  1584.         }
  1585.  
  1586.         DOF2::SortSection_Internal (section, entries, keys, l, i - 1, ignorecase, ascending);
  1587.         DOF2::SortSection_Internal (section, entries, keys, i + 1, r, ignorecase, ascending);
  1588.     }
  1589. }
  1590.  
  1591. private DOF2::SwapEntries (section, entry1, entry2)
  1592. {
  1593.     // This swaps two entries in the entry list of a section. (Pointers are swapped)
  1594.     if (0 <= section < Sections.Count && 0 <= entry1 <= Entries.Count && 0 <= entry2 <= Entries.Count)
  1595.     {
  1596.         if (entry1 == Sections.FirstEntry [section])
  1597.             Sections.FirstEntry [section] = entry2;
  1598.         else if (entry2 == Sections.FirstEntry [section])
  1599.             Sections.FirstEntry [section] = entry1;
  1600.  
  1601.         if (entry1 == Sections.LastEntry [section])
  1602.             Sections.LastEntry [section] = entry2;
  1603.         else if (entry2 == Sections.LastEntry [section])
  1604.             Sections.LastEntry [section] = entry1;
  1605.  
  1606.         if (Entries.NextEntry [entry1] == entry2)
  1607.         {
  1608.             Entries.NextEntry [entry1] = Entries.NextEntry [entry2];
  1609.             Entries.PreviousEntry [entry2] = Entries.PreviousEntry [entry1];
  1610.  
  1611.             if (Entries.PreviousEntry [entry1] != INVALID_ENTRY)
  1612.                 Entries.NextEntry [Entries.PreviousEntry [entry1]] = entry2;
  1613.  
  1614.             if (Entries.NextEntry [entry2] != INVALID_ENTRY)
  1615.                 Entries.PreviousEntry [Entries.NextEntry [entry2]] = entry1;
  1616.  
  1617.             Entries.NextEntry [entry2] = entry1;
  1618.             Entries.PreviousEntry [entry1] = entry2;
  1619.         }
  1620.         else if (Entries.NextEntry [entry2] == entry1)
  1621.         {
  1622.             Entries.NextEntry [entry2] = Entries.NextEntry [entry1];
  1623.             Entries.PreviousEntry [entry1] = Entries.PreviousEntry [entry2];
  1624.  
  1625.             if (Entries.PreviousEntry [entry2] != INVALID_ENTRY)
  1626.                 Entries.NextEntry [Entries.PreviousEntry [entry2]] = entry1;
  1627.  
  1628.             if (Entries.NextEntry [entry1] != INVALID_ENTRY)
  1629.                 Entries.PreviousEntry [Entries.NextEntry [entry1]] = entry2;
  1630.  
  1631.             Entries.NextEntry [entry1] = entry2;
  1632.             Entries.PreviousEntry [entry2] = entry1;
  1633.         }
  1634.         else
  1635.         {
  1636.             new pointer;
  1637.  
  1638.             if (Entries.PreviousEntry [entry1] != INVALID_ENTRY)
  1639.                 Entries.NextEntry [Entries.PreviousEntry [entry1]] = entry2;
  1640.  
  1641.             if (Entries.NextEntry [entry1] != INVALID_ENTRY)
  1642.                 Entries.PreviousEntry [Entries.NextEntry [entry1]] = entry2;
  1643.  
  1644.             if (Entries.PreviousEntry [entry2] != INVALID_ENTRY)
  1645.                 Entries.NextEntry [Entries.PreviousEntry [entry2]] = entry1;
  1646.  
  1647.             if (Entries.NextEntry [entry2] != INVALID_ENTRY)
  1648.                 Entries.PreviousEntry [Entries.NextEntry [entry2]] = entry1;
  1649.  
  1650.             pointer = Entries.NextEntry [entry1];
  1651.             Entries.NextEntry [entry1] = Entries.NextEntry [entry2];
  1652.             Entries.NextEntry [entry2] = pointer;
  1653.  
  1654.             pointer = Entries.PreviousEntry [entry1];
  1655.             Entries.PreviousEntry [entry1] = Entries.PreviousEntry [entry2];
  1656.             Entries.PreviousEntry [entry2] = pointer;
  1657.         }
  1658.         return 1;
  1659.     }
  1660.     return 0;
  1661. }
  1662.  
  1663. private DOF2::HashKey (key [])
  1664. {
  1665.     new
  1666.         h = -1,
  1667.         i,
  1668.         j;
  1669.  
  1670.     if (CaseSensitive)
  1671.     {
  1672.         while ((j = key [i++]))
  1673.             h = h * 33 + j;
  1674.     }
  1675.     else
  1676.     {
  1677.         while ((j = tolower (key [i++])))
  1678.             h = h * 33 + j;
  1679.     }
  1680.     return h;
  1681. }
  1682.  
  1683. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  1684.  
  1685. stock DOF2::strcpy (dest [], const src [], size = sizeof (dest))
  1686. {
  1687.     dest [0] = '\0';
  1688.     strcat (dest, src, size);
  1689. }
  1690.  
  1691. // Replace [oldstr] with [newstr] in [srcstr] and copy write the new string to 'deststr'.
  1692.  
  1693. stock DOF2::strreplace (const newstr [], const oldstr [], const srcstr [], deststr [], bool: ignorecase = false, size = sizeof (deststr))
  1694. {
  1695.     new
  1696.         newlen = strlen (newstr),
  1697.         oldlen = strlen (oldstr),
  1698.         srclen = strlen (srcstr),
  1699.         idx,
  1700.         rep;
  1701.  
  1702.     for (new i = 0; i < srclen; ++i)
  1703.     {
  1704.         if (idx < (size - 1))
  1705.         {
  1706.             if ((i + oldlen) <= srclen)
  1707.             {
  1708.                 if (!strcmp (srcstr [i], oldstr, ignorecase, oldlen))
  1709.                 {
  1710.                     deststr [idx] = '\0';
  1711.                     strcat (deststr, newstr, size);
  1712.                     ++rep;
  1713.                     idx += newlen;
  1714.                     i += oldlen - 1;
  1715.                 }
  1716.                 else
  1717.                     deststr [idx++] = srcstr [i];
  1718.             }
  1719.             else
  1720.                 deststr [idx++] = srcstr [i];
  1721.         }
  1722.         else
  1723.             return rep;
  1724.     }
  1725.     deststr [idx] = '\0';
  1726.     return rep;
  1727. }
  1728.  
  1729. stock DOF2::udb_encode (nickname [])
  1730. {
  1731.     new
  1732.         buf [256],
  1733.         result [256];
  1734.  
  1735.     static const symbols [][2][] =
  1736.     {
  1737.         {"_", "_00"},
  1738.         {";", "_01"},
  1739.         {"!", "_02"},
  1740.         {"/", "_03"},
  1741.         {"\\", "_04"},
  1742.         {"[", "_05"},
  1743.         {"]", "_06"},
  1744.         {"?", "_07"},
  1745.         {".", "_08"},
  1746.         {"*", "_09"},
  1747.         {"<", "_10"},
  1748.         {">", "_11"},
  1749.         {"{", "_12"},
  1750.         {"}", "_13"},
  1751.         {" ", "_14"},
  1752.         {"\"", "_15"},
  1753.         {":", "_16"},
  1754.         {"|", "_17"},
  1755.         {"=", "_18"}
  1756.     };
  1757.  
  1758.     strcat (buf, nickname);
  1759.     for (new i = 0; i < sizeof (symbols); ++i)
  1760.     {
  1761.         DOF2::strreplace (symbols [i][1], symbols [i][0], buf, result);
  1762.         DOF2::strcpy (buf, result);
  1763.     }
  1764.     return result;
  1765. }
  1766.  
  1767. stock DOF2::udb_decode (nickname [])
  1768. {
  1769.     new
  1770.         buf [256],
  1771.         result [256];
  1772.  
  1773.     static const symbols [][2][] =
  1774.     {
  1775.         {"_", "_00"},
  1776.         {";", "_01"},
  1777.         {"!", "_02"},
  1778.         {"/", "_03"},
  1779.         {"\\", "_04"},
  1780.         {"[", "_05"},
  1781.         {"]", "_06"},
  1782.         {"?", "_07"},
  1783.         {".", "_08"},
  1784.         {"*", "_09"},
  1785.         {"<", "_10"},
  1786.         {">", "_11"},
  1787.         {"{", "_12"},
  1788.         {"}", "_13"},
  1789.         {" ", "_14"},
  1790.         {"\"", "_15"},
  1791.         {":", "_16"},
  1792.         {"|", "_17"},
  1793.         {"=", "_18"}
  1794.     };
  1795.  
  1796.     strcat (buf, nickname);
  1797.     for (new i = 0; i < sizeof (symbols); ++i)
  1798.     {
  1799.         DOF2::strreplace (symbols [i][0], symbols [i][1], buf, result);
  1800.         DOF2::strcpy (buf, result);
  1801.     }
  1802.     return result;
  1803. }
  1804.  
  1805. stock DOF2::num_hash (buf [])
  1806. {
  1807.     new
  1808.         length = strlen (buf),
  1809.         s1 = 1,
  1810.         s2 = 0,
  1811.         n;
  1812.  
  1813.     for (n = 0; n < length; n++)
  1814.     {
  1815.        s1 = (s1 + buf [n]) % 65521;
  1816.        s2 = (s2 + s1) % 65521;
  1817.     }
  1818.     return (s2 << 16) + s1;
  1819. }
  1820.  
  1821. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  1822.  
  1823. #if defined DUDB_CONVERT
  1824.  
  1825.     #tryinclude <dutils>
  1826.  
  1827.     #define dUser(%0).(             DOF2_GetString(DOF2_File(%0),
  1828.     #define dUserSet(%0).(          DOF2_SetString(DOF2_File(%0),
  1829.     #define dUserINT(%0).(          DOF2_GetInt(DOF2_File(%0),
  1830.     #define dUserSetINT(%0).(       DOF2_SetInt(DOF2_File(%0),
  1831.     #define dUserFLOAT(%0).(        DOF2_GetFloat(DOF2_File(%0),
  1832.     #define dUserSetFLOAT(%0).(     DOF2_SetFloat(DOF2_File(%0),
  1833.     #define udb_Create(%0,%1)       DOF2_CreateFile(DOF2_File(%0),%1)
  1834.     #define udb_RenameUser(%0,%1)   DOF2_RenameFile(DOF2_File(%0),DOF2_File(%1))
  1835.     #define udb_Exists(%0)          DOF2_FileExists(DOF2_File(%0))
  1836.     #define udb_Remove(%0)          DOF2_RemoveFile(DOF2_File(%0))
  1837.     #define udb_CheckLogin(%0,%1)   DOF2_CheckLogin(DOF2_File(%0),%1)
  1838.  
  1839.     #if !defined _dudb_included
  1840.         #define _dudb_included
  1841.     #endif
  1842.  
  1843. #endif
  1844.  
  1845. #if defined DINI_CONVERT
  1846.  
  1847.     #define dini_Exists             DOF2_FileExists
  1848.     #define dini_Remove             DOF2_RemoveFile
  1849.     #define dini_Create             DOF2_CreateFile
  1850.     #define dini_Set                DOF2_SetString
  1851.     #define dini_Get                DOF2_GetString
  1852.     #define dini_IntSet             DOF2_SetInt
  1853.     #define dini_Int                DOF2_GetInt
  1854.     #define dini_BoolSet            DOF2_SetBool
  1855.     #define dini_Bool               DOF2_GetBool
  1856.     #define dini_FloatSet           DOF2_SetFloat
  1857.     #define dini_Float              DOF2_GetFloat
  1858.     #define dini_Unset              DOF2_Unset
  1859.     #define dini_Isset              DOF2_IsSet
  1860.  
  1861.     #if !defined _dini_included
  1862.         #define _dini_included
  1863.     #endif
  1864.  
  1865. #endif
  1866.  
  1867. /*
  1868. #if defined DINI_CONVERT || defined DUDB_CONVERT
  1869.  
  1870.     #define udb_hash                DOF2_num_hash
  1871.     #define num_hash                DOF2_num_hash
  1872.     #define udb_encode              DOF2_udb_encode
  1873.     #define udb_decode              DOF2_udb_decode
  1874.  
  1875. #endif
  1876. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement