SHARE
TWEET

[Include] DOF2

losnato Jan 1st, 2012 16,699 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. */
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top