Szerző Téma: DOF2 Használata(Double-O-Files_2)  (Megtekintve 3636 alkalommal)

Nem elérhető ZyZu.

  • Globális moderátor
  • 8939
  • my turbo diesel forum
  • Discord: ZyZu.
    • Profil megtekintése
DOF2 Használata(Double-O-Files_2)
« Dátum: 2013. Február 07. - 17:11:48 »
+2
Üdv! Szóval nehány hónapja találtam meg az interneten ezt a jó kis includet és nekem nagyon bejött amit lehet benne csinálni.. hasonló a dini fálj kezelõjéhez is csak más változó névvel és már funkciók is található benne, ahogyan én észrevettem sokkal jobb mint a dini mivel ott több mindent kell csinálni ami szerintem ebben egyszerûbb. Szóval egy kisebb leírás errõl az egész DOF2(Double-O-Files_2) -ról/rõl.
Használata szerintem nagyon egyszerû a kezelése hasonló a dini függvénykönyvtárhoz! Több leírás a dini használatáról ami hasonló ehez képest példák: http://sampforum.hu/index.php?topic=3075
 

native DOF2_SetFile(file[]);
native DOF2_LoadFile();
native DOF2_SaveFile();
native DOF2_ParseFile(file[],extraid,bool:callback=true);
native DOF2_ReparseFile(file[],extraid,bool:callback=true);
native DOF2_WriteFile();
native DOF2_PrintFile(comment[]=\"\");
native DOF2_GetString(file[],key[],tag[]=\"\");
native DOF2_GetStringEx(file[],key[],result[],size,tag[]=\"\");
native Float:DOF2_GetFloat(file[],key[]);
native DOF2_GetInt(file[],key[],tag[]=\"\");
native DOF2_GetHex(file[],key[],tag[]=\"\");
native DOF2_GetBin(file[],key[],tag[]=\"\");
native bool:DOF2_GetBool(file[],key[],tag[]=\"\");
native DOF2_SetString(file[],key[],value[],tag[]=\"\");
native DOF2_SetFloat(file[],key[],Float:value);
native DOF2_SetInt(file[],key[],value,tag[]=\"\");
native DOF2_SetHex(file[],key[],value,tag[]=\"\");
native DOF2_SetBin(file[],key[],value,tag[]=\"\");
native DOF2_SetBool(file[],key[],bool:value,tag[]=\"\");
native DOF2_IsSet(file[],key[],tag[]=\"\");
native DOF2_Unset(file[],key[],tag[]=\"\");
native DOF2_FileExists(file[]);
native DOF2_RemoveFile(file[]);
native DOF2_CreateFile(file[],password[]=\"\");
native DOF2_RenameFile(oldfile[],newfile[]);
native DOF2_RenameKey(file[],oldkey[],newkey[],tag[]=\"\");
native DOF2_CopyFile(filetocopy[],newfile[]);
native DOF2_CheckLogin(file[],password[]);
native DOF2_File(user[]);
native DOF2_ParseInt();
native DOF2_ParseFloat();
native DOF2_ParseBool();
native DOF2_ParseBin();
native DOF2_ParseHex();
native DOF2_SetUTF8(bool:set);
native bool:DOF2_GetUTF8();
native DOF2_GetFile();
native DOF2_MakeBackup(file[]);
native DOF2_RemoveSection (file [], tag []);
native DOF2_SectionExists (file [], tag []);
native DOF2_SortSection (file [], tag [], bool: ignorecase = true, bool: ascending = true);
native DOF2_SortAllSections (file [], bool: ignorecase = true, bool: ascending = true);
native DOF2_SetCaseSensitivity (bool: set);
native DOF2_GetCaseSensitivity ();

 
A fálj létrehozása:
 
DOF2_CreateFile(\" Fálj neve . ini \");

 
Regisztráláskor az adatok létrehozása.. fálj nevét tudjuk létrehozni és lenullázuk a játékos adatait, hogy mindeki aki kezdi a játékot akkor 0 -tól kezdje..
 
DOF2_SetString( karakterlánc ,\" Fálj \", amit bele szeretnénk írni a fáljba );

 
Példa:
 
DOF2_SetInt( karakterlánc ,\" Neve amit létrehozzon a mappában \",  0);

 
Adatok mentése más játékosnak
 
DOF2_SaveFile();

 
Ha a fálj létezik akkor nem hozza megint létre az adott mappát.. vagyis lekérdezi a fálj nevét.
 
DOF2_FileExists

 
Ezzel be tudjuk tölteni az adatokat a szerveren egy adott fáljból mappából.
 
DOF2_GetInt( karakterlánc , \" Amit be szeretnénk tölteni..\" );

 
Egy adott fálj nevét tudjuk modosítani
 
DOF2_WriteFile();

 
Nagyon sok kód, függvény található benne én leírtam a legfontosabb függvényt amire szûkség is lehet a mentésre.. bemásoltam a native táblát, hogy lássátok milyen kódok találhatóak az include bemásolva code tagokba! A leírás frissítése hamarosan!

Egy hasznos és egy jó példa amibõl tudunk tanúlni a mentésrõl és köszönjük szépen Ty$oN -nak/nek a kisebb regisztrációs rendszert ebbõl sokat lehet tanulni:




/*      Double-O-Files_2 Register/Login system by Ty$oN
DOF2 Tutorial By SmiT
Double-O-Seven for Double-O-Files_2 (DOF2)*/
#include <a_samp>
#include <Double-O-Files_2>
#define DIALOG_REGISTER 1
#define DIALOG_LOGIN 2
#define WHITE \"{FFFFFF}\"
#define RED \"{F81414}\"
#define GREEN \"{00FF22}\"
enum P_ENUM
{
    pMoney,
    pAdmin,
    pKills,
    pDeaths
}
new P_DATA[ MAX_PLAYERS ][ P_ENUM ];
stock USER_FILE(playerid)
{
    new
                STR[ 128 ],
                P_NAME[ MAX_PLAYER_NAME ];
    GetPlayerName( playerid, P_NAME,  sizeof ( P_NAME ) );
    format( STR, sizeof ( STR ), USER_FILE_PATH, P_NAME);
    return
                STR;
}
stock Load_Player_Stats(playerid)
{
        P_DATA[ playerid ][ pKills ] = DOF2_GetInt( USER_FILE( playerid ),\"Olesek\");
    P_DATA[ playerid ][ pDeaths ] = DOF2_GetInt( USER_FILE( playerid ),\"Halalok\");
    P_DATA[ playerid ][ pMoney ] = DOF2_GetInt( USER_FILE( playerid ),\"Penz\");
        P_DATA[ playerid ][ pAdmin ] = DOF2_GetInt( USER_FILE( playerid ),\"AdminSzint\");
        GivePlayerMoney(playerid, P_DATA[ playerid ][ pMoney ]);
}
public OnFilterScriptInit()
{
        return 1;
}
public OnFilterScriptExit()
{
        DOF2_Exit();
        return 1;
}
public OnPlayerRequestClass(playerid, classid)
{
        return 1;
}
public OnPlayerConnect(playerid)
{
    if( DOF2_FileExists ( USER_FILE ( playerid ) ) )
    {
        ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_INPUT,\"\"WHITE\"Belépés\",\"\"WHITE\"Üdvözöllek!\\n\"RED\"%s\\n\"WHITE\"Te már regisztrálva vagy!\\nLépj be!\",\"Belépés\",\"Kilépés\");
        }
    else
    {
        ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_INPUT,\"\"WHITE\"Regisztráció\",\"\"WHITE\"Üdvözöllek!\\n\"RED\"%s\\n\"WHITE\"Te még nem vagy regisztrálva!\\nLépj be!\",\"Belépés\",\"Kilépés\");
        }
        return 1;
}
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
        new name[MAX_PLAYER_NAME];
        GetPlayerName(playerid,name,MAX_PLAYER_NAME);
    switch( dialogid )
    {
        case DIALOG_REGISTER:
        {
            if ( !response ) return Kick( playerid );
            if( response )
            {
                if( !strlen ( inputtext ) ) return ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_INPUT,\"\"WHITE\"Belépés\",\"\"WHITE\"Üdvözöllek!\\n\"RED\"%s\\n\"WHITE\"Te már regisztrálva vagy!\\nLépj be!\",\"Belépés\",\"Kilépés\");
                                DOF2_CreateFile( USER_FILE ( playerid ), inputtext );
                                DOF2_SetInt( USER_FILE ( playerid ), \"Olesek\", 0);
                DOF2_SetInt( USER_FILE ( playerid ), \"Halalok\", 0);
                DOF2_SetInt( USER_FILE ( playerid ), \"Penz\", 1000);
                DOF2_SetInt( USER_FILE ( playerid ), \"AdminSzint\", 0);
                DOF2_SaveFile();
                                SetSpawnInfo( playerid, 0, 0, 1958.33, 1343.12, 15.36, 269.15, 0, 0, 0, 0, 0, 0 );
                                SpawnPlayer( playerid );
                                GivePlayerMoney(playerid, 1000);
            }
        }
        case DIALOG_LOGIN:
        {
            if ( !response ) return Kick( playerid );
            if( response )
            {
                if( DOF2_CheckLogin( USER_FILE( playerid ), inputtext ) )
                                {
                    Load_Player_Stats(playerid);
                                }
                else
                                {
                    ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_INPUT,\"\"WHITE\"Elfelejtett jelszó\",\"\"WHITE\"Rossz jelszót adtál meg!\\n\"RED\"%s\\n\"WHITE\"Írd be a jelszavadat!\",\"Belépés\",\"Kilépés\");
                                }
                                return 1;
            }
        }
    }
    return 1;
}
public OnPlayerDisconnect(playerid, reason)
{
        DOF2_SetInt( USER_FILE ( playerid ), \"Olesek\", P_DATA[ playerid ][ pKills ] );
    DOF2_SetInt( USER_FILE ( playerid ), \"Halalok\", P_DATA[ playerid ][ pDeaths ] );
    DOF2_SetInt( USER_FILE ( playerid ), \"Penz\", GetPlayerMoney( playerid ) );
    DOF2_SetInt( USER_FILE ( playerid ), \"AdminSzint\", P_DATA[ playerid ][ pAdmin ] );
        DOF2_SaveFile();
        return 1;
}
public OnPlayerDeath(playerid, killerid, reason)
{
        if( killerid != INVALID_PLAYER_ID )
        {
                P_DATA[ playerid ][ pKills ] ++;
        }
        P_DATA[ playerid ][ pDeaths ] ++;
    return 1;
}

 
Include fálj code tagokban!
 

#if defined _dof2_included
#endinput
#endif
#define _dof2_included
#include <a_samp>
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* This is a new version of the INI script Double-O-Files.
* However, it\'s has completely been rewritten and has now a much better performance.
* There is also the support for sections in the INI file. (But there is no support for comments.)
* Double-O-Files 2 is compatible with DUDB, DINI, Double-O-Files and possibly y_ini since it
* can handle sections and entry of the format \"key = value\", not only \"key=value\".
* The number of spaces between the equal sign and key and value can actually be arbitrary.
* I\'ve added some comments below. You may see that I\'ve mentioned the big-O-notation,
* \'n\' always Entries.Count.
* Double-O-Files 2 should also be useful for Russian letter because I\'m using
* the functions fgetchar and fputchar to write and read the files.
*
* There is another new feature which has been inspired by ZCMD and y_ini:
* The OnParseFile callbacks. To learn more about it, read the description in
* the SA-MP forums if you haven\'t already.
* THE END
*/
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
native DOF2_SetFile(file[]);
native DOF2_LoadFile();
native DOF2_SaveFile();
native DOF2_ParseFile(file[],extraid,bool:callback=true);
native DOF2_ReparseFile(file[],extraid,bool:callback=true);
native DOF2_WriteFile();
native DOF2_PrintFile(comment[]=\"\");
native DOF2_GetString(file[],key[],tag[]=\"\");
native DOF2_GetStringEx(file[],key[],result[],size,tag[]=\"\");
native Float:DOF2_GetFloat(file[],key[]);
native DOF2_GetInt(file[],key[],tag[]=\"\");
native DOF2_GetHex(file[],key[],tag[]=\"\");
native DOF2_GetBin(file[],key[],tag[]=\"\");
native bool:DOF2_GetBool(file[],key[],tag[]=\"\");
native DOF2_SetString(file[],key[],value[],tag[]=\"\");
native DOF2_SetFloat(file[],key[],Float:value);
native DOF2_SetInt(file[],key[],value,tag[]=\"\");
native DOF2_SetHex(file[],key[],value,tag[]=\"\");
native DOF2_SetBin(file[],key[],value,tag[]=\"\");
native DOF2_SetBool(file[],key[],bool:value,tag[]=\"\");
native DOF2_IsSet(file[],key[],tag[]=\"\");
native DOF2_Unset(file[],key[],tag[]=\"\");
native DOF2_FileExists(file[]);
native DOF2_RemoveFile(file[]);
native DOF2_CreateFile(file[],password[]=\"\");
native DOF2_RenameFile(oldfile[],newfile[]);
native DOF2_RenameKey(file[],oldkey[],newkey[],tag[]=\"\");
native DOF2_CopyFile(filetocopy[],newfile[]);
native DOF2_CheckLogin(file[],password[]);
native DOF2_File(user[]);
native DOF2_ParseInt();
native DOF2_ParseFloat();
native DOF2_ParseBool();
native DOF2_ParseBin();
native DOF2_ParseHex();
native DOF2_SetUTF8(bool:set);
native bool:DOF2_GetUTF8();
native DOF2_GetFile();
native DOF2_MakeBackup(file[]);
native DOF2_RemoveSection (file [], tag []);
native DOF2_SectionExists (file [], tag []);
native DOF2_SortSection (file [], tag [], bool: ignorecase = true, bool: ascending = true);
native DOF2_SortAllSections (file [], bool: ignorecase = true, bool: ascending = true);
native DOF2_SetCaseSensitivity (bool: set);
native DOF2_GetCaseSensitivity ();
*/
#define DOF2_TagExists  DOF2_SectionExists
#define DOF2_RemoveTag  DOF2_RemoveSection
// OnParseFile <Tag><Key>(extraid, value [])
// OnParseFile <><Key>(extraid, value [])
// OnDefaultParseFile (extraid, value [], key [], tag [], file [])
// The arguments of your OnParseFile functions may have arbitrary names but must be an integer followed by a string.
// Function must return a value.
#define OnParseFile<%0><%1>(%2) \\
forward _OnParseFile_%0_%1 (extraid, value []); \\
public _OnParseFile_%0_%1 (extraid, value []) \\
    return __OnParseFile_%0_%1 (extraid, (value
  • == \'\\1\' && value [1] == \'\\0\') ? (\"\") : value); \\

stock __OnParseFile_%0_%1 (%2)
// Also here: The argument names may be arbitrary but must be an integer followed by 4 strings.
// Function must return a value.
#define OnDefaultParseFile(%0) \\
forward _OnDefaultParseFile (extraid, value [], key [], tag [], file []); \\
public _OnDefaultParseFile (extraid, value [], key [], tag [], file []) \\
    return __OnDefaultParseFile (extraid, (value
  • == \'\\1\' && value [1] == \'\\0\') ? (\"\") : value, key, (tag
  • == \'\\1\' && tag [1] == \'\\0\') ? (\"\") : tag, file); \\

stock __OnDefaultParseFile (%0)
#define DOF2_ParseBool() \\
(strval (value) || (value
  • && !strcmp (value, \"true\", true)))

#define DOF2_ParseInt() \\
(strval (value))
#define DOF2_ParseFloat() \\
(floatstr (value))
#define DOF2_ParseBin() \\
(DOF2_strbin (value))
#define DOF2_ParseHex() \\
(DOF2_strhex (value))
#define DOF2_LoadFile() \\
DOF2_ParseFile (CurrentFile, -1, false)
#define DOF2_SaveFile \\
DOF2_WriteFile
#define DOF2_FileExists \\
fexist
#define Sections. \\
Sections_
#define Entries. \\
Entries_
#define DOF2:: \\
DOF2_
#if !defined private
#define private       static stock
#endif
#pragma dynamic 65536
/*
#define MAX_SECTION_TAG        (32)
#define MAX_LINE_SIZE       (128)
#define MAX_SECTIONS            (32)
#define MAX_ENTRIES         (256)
#define MAX_FILE_SIZE       (64)
#define USER_FILE_PATH       \"Users/%s.ini\"
*/
// The maximum length of the name of a tag.
#if !defined MAX_SECTION_TAG
#define MAX_SECTION_TAG       (32)
#endif
// The maximum length of a line (including key and value).
#if !defined MAX_LINE_SIZE
#define MAX_LINE_SIZE       (128)
#endif
// The maximum number of sections which can be handled. Be careful: MUST NOT be higher than 255.
#if !defined MAX_SECTIONS
#define MAX_SECTIONS          (32)
#endif
// The maximum number of entries which can be loaded into the cache.
#if !defined MAX_ENTRIES
#define MAX_ENTRIES         (256)
#endif
// The maximum length of the name of a file.
#if !defined MAX_FILE_SIZE
#define MAX_FILE_SIZE       (64)
#endif
/*
If PACK_CONTENT == true tag names and lines (key + value) will get stored in cache as packed strings.
The result is less memory usage. However, you won\'t be able to use special characters like russian or chinese ones.
*/
#if !defined PACK_CONTENT
#define PACK_CONTENT        (false)
#endif
#define INVALID_ENTRY           (-1)
#define INVALID_SECTION         (-1)
// Do you want to emulate DUDB?
#if !defined DUDB_CONVERT && 0 // Change to 1 to enable.
#define DUDB_CONVERT
#endif
#if !defined USER_FILE_PATH
#if defined DUDB_CONVERT
#define USER_FILE_PATH    \"%s.dudb.sav\"
#else
    #define USER_FILE_PATH    \"%s.ini\"
#endif
#endif
#if !defined USER_PW_HASH_KEY
    #if defined DUDB_CONVERT
#define USER_PW_HASH_KEY \"password_hash\"
#else
    #define USER_PW_HASH_KEY \"password\"
#endif
#endif
 
// Do you want to emulate DINI?
#if !defined DINI_CONVERT && 0 // Change to 1 to enable.
#define DINI_CONVERT
#endif
/*
#if MAX_SECTIONS >= 256
#error MAX_SECTIONS must not be greater than 255.
#endif
*/
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
private
bool: UseUTF8 = PACK_CONTENT,
bool: CaseSensitive = false,
CurrentFile [MAX_FILE_SIZE],
bool: FileChanged,
Sections.FirstEntry [MAX_SECTIONS] = {INVALID_ENTRY, ...},
Sections.LastEntry [MAX_SECTIONS] = {INVALID_ENTRY, ...},
Sections.Count,
#if PACK_CONTENT == true
Sections.Tag [MAX_SECTIONS][MAX_SECTION_TAG char],
Entries.Line [MAX_ENTRIES][MAX_LINE_SIZE char],
Entries.Tag [MAX_ENTRIES][MAX_SECTION_TAG char],
#else
Sections.Tag [MAX_SECTIONS][MAX_SECTION_TAG],
    Entries.Line [MAX_ENTRIES][MAX_LINE_SIZE],
Entries.Tag [MAX_ENTRIES][MAX_SECTION_TAG],
#endif
#if MAX_SECTIONS >= 256
Entries.Section [MAX_ENTRIES],
#else
Entries.Section [MAX_ENTRIES char],
#endif
Entries.NextEntry [MAX_ENTRIES] = {INVALID_ENTRY, ...},
Entries.PreviousEntry [MAX_ENTRIES] = {INVALID_ENTRY, ...},
Entries.Count,
SortedEntryList [MAX_ENTRIES][2]; // Index 0: Hashcode, Index 1: EntryID
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
DOF2::Exit ()
DOF2::WriteFile ();
stock DOF2::SetUTF8 (bool: set)
UseUTF8 = set;
stock bool: DOF2::GetUTF8 ()
return UseUTF8;
stock bool: DOF2::SetCaseSensitivity (bool: set)
CaseSensitive = set;
stock bool: DOF2::GetCaseSensitivity ()
return CaseSensitive;
stock DOF2::SetFile (file [])
DOF2::strcpy (CurrentFile, file);
stock DOF2::GetFile ()
return CurrentFile;
stock DOF2::CreateFile (file [], password [] = \"\")
{
if (!DOF2::FileExists (file))
{
        new File: f = fopen (file, io_append);
       
if (fclose (f))
{
   if (password
  • )

       return DOF2::SetInt (file, USER_PW_HASH_KEY, DOF2::num_hash (password));
   return 1;
}
}
return 0;
}
stock DOF2::RenameFile (oldfile [], newfile [])
{
if (!DOF2::FileExists (newfile))
{
    // If \'CurrentFile\' is \'oldfile\', write it if it has been changed.
if (CurrentFile
  • && !strcmp (CurrentFile, oldfile) && FileChanged)

   DOF2::WriteFile ();
else if (!DOF2::ParseFile (oldfile, -1, false)) // Otherwise parse \'oldfile\'.
    return 0;
   
DOF2::SetFile (newfile);
if (DOF2::WriteFile ())
    return fremove (oldfile);
}
return 0;
}
stock DOF2::CopyFile (filetocopy [], newfile [])
{
    if (!DOF2::FileExists (newfile))
{
    if (CurrentFile
  • && !strcmp (CurrentFile, filetocopy) && FileChanged)

   DOF2::WriteFile ();
else if(!DOF2::ParseFile (filetocopy, -1, false))
    return 0;
   
DOF2::SetFile (newfile);
return DOF2::WriteFile ();
}
return 0;
}
stock DOF2::RemoveFile (file [])
{
if (file
  • )

{
    if (CurrentFile
  • && !strcmp (CurrentFile, file))

        CurrentFile
  • = \'\\0\';

return fremove (file);
}
return 0;
}
stock DOF2::MakeBackup (file [])
{
    new
        year,
month,
day,
hour,
minute,
second,
backupfile [MAX_FILE_SIZE];
    getdate (year, month, day);
    gettime (hour, minute, second);
    format (backupfile, sizeof (backupfile), \"%s.%02d_%02d_%02d.%02d_%02d_%02d_%02d.bak\", CurrentFile, month, day, year, hour, minute, second, GetTickCount ());
    return DOF2::CopyFile (CurrentFile, backupfile);
}
stock bool: DOF2::SectionExists (file [], tag [])
{
    if (file
  • ) // You can\'t remove the empty Sections.

{
    if (!tag
  • )

        return true; // Emptry section always exists. In every file.
        if (!CurrentFile
  • || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.

       if (!DOF2::ParseFile (file, -1, false))
           return false;
#if PACK_CONTENT == true
new buf [MAX_SECTION_TAG];
#endif
       for (new i = 1; i < Sections.Count; ++i)
       {
       #if PACK_CONTENT == true
           strunpack (buf, Sections.Tag );
        if (!strcmp (buf, tag, !CaseSensitive))
        return true;
#else
    if (!strcmp (Sections.Tag , tag, !CaseSensitive))
        return true;
#endif
       }
}
return false;
}
stock DOF2::RemoveSection (file [], tag [])
{
// Removes tag \'tag\' with all it\'s entries.
if (file
  • && tag
  • ) // You can\'t remove the empty Sections.

{
       if (!CurrentFile
  • || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.

       if (!DOF2::ParseFile (file, -1, false))
           return 0;
new
#if PACK_CONTENT == true
    line [MAX_LINE_SIZE],
    buf [MAX_SECTION_TAG],
#endif
   section = INVALID_SECTION,
   entry,
   key [MAX_KEY_SIZE];
    for (new i = 1; i < Sections.Count; ++i)
    {
#if PACK_CONTENT == true
        strunpack (buf, Sections.Tag );
        if (!strcmp (buf, tag, !CaseSensitive))
        {
            section = i;
            break;
        }
#else
    if (!strcmp (Sections.Tag , tag, !CaseSensitive))
        {
            section = i;
            break;
        }
#endif
    }
if (section != INVALID_SECTION)
{
   entry = Sections.FirstEntry [section];
   while (entry != INVALID_ENTRY)
   {
       // Remove all entries under the current Sections.
    #if PACK_CONTENT == true
       strunpack (line, Entries.Line [entry]);
       DOF2::ParseLine (line, key, buf);
   #else
       DOF2::ParseLine (Entries.Line [entry], key, buf);
   #endif
       DOF2::Unset (file, key, tag);
      entry = Entries.NextEntry [entry];
   }
    // Move the last tag to the position of the current tag. Creates a little mess.
    --Sections.Count;
    Sections.Tag [section] = Sections.Tag [sections.Count];
    Sections.FirstEntry [section] = Sections.FirstEntry [sections.Count];
    Sections.LastEntry [section] = Sections.LastEntry [sections.Count];
   // Adjust the tag IDs of the entries.
    entry = Sections.FirstEntry [section];
    while (entry != INVALID_ENTRY)
    {
   #if MAX_SECTIONS >= 256
      Entries.Section [entry] = section;
   #else
        Entries.Section {entry} = section;
   #endif
        entry = Entries.NextEntry [entry];
    }
    FileChanged = true;
    return 1;
}
}
return 0;
}
private DOF2::SearchEntry (key [], tag [], keybuf [], valbuf [], &pos, keybufsize = sizeof (keybuf), valbufsize = sizeof (valbuf))
{
if (key
  • && Entries.Count)

{
    new
        entry = INVALID_ENTRY,
        l,
        m,
        r,
        h,
#if PACK_CONTENT == true
        line [MAX_LINE_SIZE],
        buf [MAX_SECTION_TAG],
#endif
        i;
        h = DOF2::HashKey (key);
l = 0;
r = Entries.Count - 1;
/*
 * 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.
 * A sequential search would take up to 256 steps. That was the case in the first Double-O-Files script.
 */
while (l <= r)
{
    if ((r - l) < 2)
    {
        if (h == SortedEntryList [l][0])
        {
            m = l;
           entry = SortedEntryList [l][1];
      }
      else if (r > l && h == SortedEntryList [r][0])
      {
          m = r;
          entry = SortedEntryList [r][1];
      }
        break;
    }
    else
    {
        m = l + (r - l) / 2;
       if (h == SortedEntryList [m][0])
       {
           entry = SortedEntryList [m][1];
           break;
       }
       else if (h > SortedEntryList [m][0])
         l = m + 1;
      else
          r = m - 1;
   }
}
// Candidate found?
if (entry != INVALID_ENTRY)
{
   // Check if it\'s the entry we want.
        #if PACK_CONTENT == true
   strunpack (line, Entries.Line [entry]);
   DOF2::ParseLine (line, keybuf, valbuf, keybufsize, valbufsize);
    strunpack (buf, Entries.Tag [entry]);
   if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag
  • && !buf
  • ) || (tag
  • && buf
  • && !strcmp (tag, buf, !CaseSensitive))))

#else
   DOF2::ParseLine (Entries.Line [entry], keybuf, valbuf, keybufsize, valbufsize);
    if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag
  • && !Entries.Tag [entry][0]) || (tag
  • && Entries.Tag [entry][0] && !strcmp (tag, Entries.Tag [entry], !CaseSensitive))))

#endif
       return (pos = m, entry);
   else
   {
       // 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.
       for (i = m - 1; i >= 0 && h == SortedEntryList [0]; --i)
       {
           entry = SortedEntryList [1];
       #if PACK_CONTENT == true
         strunpack (line, Entries.Line [entry]);
         DOF2::ParseLine (line, keybuf, valbuf, keybufsize, valbufsize);
          strunpack (buf, Entries.Tag [entry]);
         if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag
  • && !buf
  • ) || (tag
  • && buf
  • && !strcmp (tag, buf, !CaseSensitive))))

      #else
         DOF2::ParseLine (Entries.Line [entry], keybuf, valbuf, keybufsize, valbufsize);
          if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag
  • && !Entries.Tag [entry][0]) || (tag
  • && Entries.Tag [entry][0] && !strcmp (tag, Entries.Tag [entry], !CaseSensitive))))

      #endif
             return (pos = i, entry);
       }
       for (i = m + 1; i < Entries.Count && h == SortedEntryList [0]; ++i)
       {
           entry = SortedEntryList [1];
       #if PACK_CONTENT == true
         strunpack (line, Entries.Line [entry]);
         DOF2::ParseLine (line, keybuf, valbuf, keybufsize, valbufsize);
          strunpack (buf, Entries.Tag [entry]);
         if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag
  • && !buf
  • ) || (tag
  • && buf
  • && !strcmp (tag, buf, !CaseSensitive))))

      #else
         DOF2::ParseLine (Entries.Line [entry], keybuf, valbuf, keybufsize, valbufsize);
          if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag
  • && !Entries.Tag [entry][0]) || (tag
  • && Entries.Tag [entry][0] && !strcmp (tag, Entries.Tag [entry], !CaseSensitive))))

      #endif
             return (pos = i, entry);
       }
   }
}
}
keybuf
  • = valbuf
  • = \'\\0\';

return INVALID_ENTRY;
}
stock DOF2::SetString (file [], key [], value [], tag [] = \"\")
{
    if (file
  • && key
  • )

{
    new
        entry,
        pos,
        section = INVALID_SECTION,
        keybuf [MAX_LINE_SIZE],
        valbuf [MAX_LINE_SIZE],
#if PACK_CONTENT == true
        buf [MAX_SECTION_TAG],
        line [MAX_LINE_SIZE],
#endif
   i;
        if (!CurrentFile
  • || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.

       if (!DOF2::ParseFile (file, -1, false))
           return 0;
        entry = DOF2::SearchEntry (key, tag, keybuf, valbuf, pos);
        // If the entry has been found, just change it\'s content.
        if (entry != INVALID_ENTRY)
{
    FileChanged = true;
#if PACK_CONTENT == true
   format (line, sizeof (line), \"%s = %s\", key, value
  • ? value : (\"(null)\"));

    return strpack (Entries.Line [entry], line);
#else
   format (Entries.Line [entry], sizeof (Entries.Line []), \"%s = %s\", key, value
  • ? value : (\"(null)\"));

   return 1;
#endif
        }
if (Entries.Count >= MAX_ENTRIES)
    return 0;
// Search for the section where the entry belongs.
if (!tag
  • )

    section = 0;
else
{
   for (i = 1; i < Sections.Count; ++i)
   {
   #if PACK_CONTENT == true
       strunpack (buf, Sections.Tag );
       if (buf
  • && !strcmp (tag, buf, !CaseSensitive))

       {
           section = i;
           break;
       }
   #else
       if (Sections.Tag [0] && !strcmp (tag, Sections.Tag , !CaseSensitive))
       {
           section = i;
           break;
       }
   #endif
   }
}
// Section we want does not exist, create new one if possible.
if (section == INVALID_SECTION)
{
    if (Sections.Count >= MAX_SECTIONS)
        return 0;
    section = Sections.Count++;
    #if PACK_CONTENT == true
   strpack (Sections.Tag [section], tag);
#else
    DOF2::strcpy (Sections.Tag [section], tag);
#endif
   Sections.FirstEntry [section] = Sections.LastEntry [section] = INVALID_ENTRY;
}
// Add the entry to the section. Section\'s content is defined by a linear two way list.
#if PACK_CONTENT == true
format (line, sizeof (line), \"%s = %s\", key, value
  • ? value : (\"(null)\"));

strpack (Entries.Line [Entries.Count], line);
#else
    format (Entries.Line [Entries.Count], sizeof (Entries.Line []), \"%s = %s\", key, value
  • ? value : (\"(null)\"));

#endif
Entries.Tag [Entries.Count] = Sections.Tag [section];
    #if MAX_SECTIONS >= 256
Entries.Section [Entries.Count] = section;
#else
    Entries.Section {Entries.Count} = section;
#endif
Entries.NextEntry [Entries.Count] = INVALID_ENTRY;
// Add entry to sorted list of entries and move to right correct position in O(n) time.
SortedEntryList [Entries.Count][0] = DOF2::HashKey (key);
SortedEntryList [Entries.Count][1] = Entries.Count;
i = Entries.Count - 1;
while (i >= 0 && SortedEntryList [0] > SortedEntryList [i + 1][0])
{
    DOF2::SwapSortedEntries (SortedEntryList , SortedEntryList [i + 1]);
    --i;
}
if (Sections.LastEntry [section] == INVALID_ENTRY) // No entry in this section.
{
    Sections.FirstEntry [section] = Sections.LastEntry [section] = Entries.Count;
    Entries.PreviousEntry [Entries.Count] = INVALID_ENTRY;
}
else
{
   Entries.NextEntry [sections.LastEntry [section]] = Entries.Count;
   Entries.PreviousEntry [Entries.Count] = Sections.LastEntry [section];
   Sections.LastEntry [section] = Entries.Count;
}
++Entries.Count;
FileChanged = true;
}
return 1;
}
stock DOF2::GetString (file [], key [], tag [] = \"\")
{
new buf [MAX_LINE_SIZE];
DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
return buf;
}
stock DOF2::GetStringEx (file [], key [], result [], size, tag [] = \"\")
{
if (file
  • && key
  • )

{
    new
        pos,
   keybuf [MAX_LINE_SIZE];
        if (!CurrentFile
  • || strcmp (CurrentFile, file))

        {
       if (!DOF2::ParseFile (file, -1, false))
       {
           result
  • = \'\\0\';

           return 0;
   }
}
// Find entry and assign the result with it\'s value.
return (DOF2::SearchEntry (key, tag, keybuf, result, pos, sizeof (keybuf), size) != INVALID_ENTRY);
}
return 0;
}
stock DOF2::Unset (file [], key [], tag [] = \"\")
{
if (file
  • && key
  • )

{
    new
        entry,
        pos,
   keybuf [MAX_LINE_SIZE],
   valbuf [MAX_LINE_SIZE];
if (!CurrentFile
  • || strcmp (CurrentFile, file))

       if (!DOF2::ParseFile (file, -1, false))
           return 0;
if ((entry = DOF2::SearchEntry (key, tag, keybuf, valbuf, pos)) != INVALID_ENTRY)
{
    // Remove entry from it\'s section.
        #if MAX_SECTIONS >= 256
    if (Sections.FirstEntry [Entries.Section [entry]] == entry) // Is the entry the first entry in the section? Make it\'s next entry the first entry.
#else
    if (Sections.FirstEntry [Entries.Section {entry}] == entry)
#endif
   {
   #if MAX_SECTIONS >= 256
        Sections.FirstEntry [Entries.Section [entry]] = Entries.NextEntry [entry];
   #else
       Sections.FirstEntry [Entries.Section {entry}] = Entries.NextEntry [entry];
   #endif
        if (Entries.NextEntry [entry] != INVALID_ENTRY)
         Entries.PreviousEntry [Entries.NextEntry [entry]] = INVALID_ENTRY;
   }
   else
   {
       Entries.NextEntry [Entries.PreviousEntry [entry]] = Entries.NextEntry [entry];
       if (Entries.NextEntry [entry] != INVALID_ENTRY)
         Entries.PreviousEntry [Entries.NextEntry [entry]] = Entries.PreviousEntry [entry];
   }
        #if MAX_SECTIONS >= 256
            if (Sections.LastEntry [Entries.Section [entry]] == entry)
        #else
   if (Sections.LastEntry [Entries.Section {entry}] == entry)
#endif
   {
   #if MAX_SECTIONS >= 256
       Sections.LastEntry [Entries.Section [entry]] = Entries.PreviousEntry [entry];
   #else
       Sections.LastEntry [Entries.Section {entry}] = Entries.PreviousEntry [entry];
   #endif
       if (Entries.PreviousEntry [entry] != INVALID_ENTRY)
           Entries.NextEntry [Entries.PreviousEntry [entry]] = INVALID_ENTRY;
   }
   else
   {
       Entries.PreviousEntry [Entries.NextEntry [entry]] = Entries.PreviousEntry [entry];
       if (Entries.PreviousEntry [entry] != INVALID_ENTRY)
           Entries.NextEntry [Entries.PreviousEntry [entry]] = Entries.NextEntry [entry];
   }
   // Move the entry to the end of the sorted list and decrement Entries.Count to forget about the unset Entries.
   while (pos < (Entries.Count - 1))
   {
       DOF2::SwapSortedEntries (SortedEntryList [pos], SortedEntryList [pos + 1]);
       ++pos;
   }
   --Entries.Count;
   FileChanged = true;
    return 1;
}
}
return 0;
}
stock DOF2::RenameKey (file [], oldkey [], newkey [], tag [] = \"\")
{
if (file
  • && oldkey
  • )

{
    new
        entry,
        pos,
#if PACK_CONTENT == true
   line [MAX_LINE_SIZE],
#endif
   keybuf [MAX_LINE_SIZE],
   valbuf [MAX_LINE_SIZE];
if (!CurrentFile
  • || strcmp (CurrentFile, file))

       if (!DOF2::ParseFile (file, -1, false))
           return 0;
if ((entry = DOF2::SearchEntry (oldkey, tag, keybuf, valbuf, pos)) != INVALID_ENTRY)
{
    // Change content of Entries.
#if PACK_CONTENT == true
            format (line, sizeof (line), \"%s = %s\", newkey, valbuf
  • ? valbuf : (\"(null)\"));

    strpack (Entries.Line [entry], line);
#else
            format (Entries.Line [entry], sizeof (Entries.Line []), \"%s = %s\", newkey, valbuf
  • ? valbuf : (\"(null)\"));

#endif
    // Because the hashcode has been changed, the entry has to move in the list.
    SortedEntryList [pos][0] = DOF2::HashKey (newkey);
    if (pos < (MAX_ENTRIES - 1) && SortedEntryList [pos][0] > SortedEntryList [pos + 1][0])
    {
      // Hash value of key is greater than the hash value of it\'s right neighbor, move to the right by swapping the 2 entries.
      while (pos < (MAX_ENTRIES - 1) && SortedEntryList [pos][0] > SortedEntryList [pos + 1][0])
      {
          DOF2::SwapSortedEntries (SortedEntryList [pos], SortedEntryList [pos + 1]);
          ++pos;
      }
    }
    else if (pos > 0 && SortedEntryList [pos][0] < SortedEntryList [pos + 1][0])
    {
        // Hash value of key is smaller than the hash value of it\' left neighbor, move to the left by swapping the 2 entries.
        while (pos > 0 && SortedEntryList [pos][0] < SortedEntryList [pos - 1][0])
        {
            DOF2::SwapSortedEntries (SortedEntryList [pos], SortedEntryList [pos - 1]);
            --pos;
        }
    }
   FileChanged = true;
    return 1;
}
}
return 0;
}
stock bool: DOF2::IsSet (file [], key [], tag [] = \"\")
{
new
    pos,
keybuf [MAX_LINE_SIZE],
valbuf [MAX_LINE_SIZE];
if (!CurrentFile
  • || strcmp (CurrentFile, file))

if (!DOF2::ParseFile (file, -1, false))
    return false;
// Try to find the Entries.
return (DOF2::SearchEntry (key, tag, keybuf, valbuf, pos) != INVALID_ENTRY);
}
stock DOF2::SetInt (file [], key [], value, tag [] = \"\")
{
new buf [16];
format (buf, sizeof (buf), \"%d\", value);
return DOF2::SetString (file, key, buf, tag);
}
stock DOF2::GetInt (file [], key [], tag [] = \"\")
{
new buf [16];
DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
return strval (buf);
}
stock DOF2::SetHex (file [], key [], value, tag [] = \"\")
{
new buf [16];
DOF2::hexstr (value, buf);
return DOF2::SetString (file, key, buf, tag);
}
stock DOF2::GetHex (file [], key [], tag [] = \"\")
{
new buf [16];
DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
return DOF2::strhex (buf);
}
stock DOF2::SetBin (file [], key [], value, tag [] = \"\")
{
new buf [35];
DOF2::binstr (value, buf);
return DOF2::SetString (file, key, buf, tag);
}
stock DOF2::GetBin (file [], key [], tag [] = \"\")
{
new buf [35];
DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
return DOF2::strbin (buf);
}
stock DOF2::SetFloat (file [], key [], Float: value, tag [] = \"\")
{
new buf [32];
format (buf, sizeof (buf), \"%.8f\", value);
return DOF2::SetString (file, key, buf, tag);
}
stock Float: DOF2::GetFloat (file [], key [], tag [] = \"\")
{
new buf [32];
DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
return floatstr (buf);
}
stock bool: DOF2::GetBool (file [], key [], tag [] = \"\")
{
new buf [16];
DOF2::GetStringEx (file, key, buf, sizeof (buf), tag);
return (strval (buf) || (buf
  • && !strcmp (buf, \"true\", true)));

}
stock DOF2::SetBool (file [], key [], bool: value, tag [] = \"\")
return DOF2::SetString (file, key, value ? (\"true\") : (\"false\"), tag);
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
stock DOF2::PrintFile (comment [] = \"\")
{
    if (CurrentFile
  • )

{
new
   bool: firstline = true,
   entry,
#if PACK_CONTENT == true
   buf [MAX_LINE_SIZE],
#endif
   entries,
   i;
    printf (\"[DOF] Current file: %s\", CurrentFile);
for ( ; i < Sections.Count; ++i)
{
    if (i)
   {
       if (!firstline)
         print (\" \");
      else
          firstline = false;
   #if PACK_CONTENT == true
      strunpack (buf, Sections.Tag );
      printf (\"[%s]\", buf);
   #else
       printf (\"[%s]\", Sections.Tag );
   #endif
   }
   entry = Sections.FirstEntry ;
   while (entry != INVALID_ENTRY)
   {
   #if PACK_CONTENT == true
      strunpack (buf, Entries.Line [entry]);
      print (buf);
   #else
       print (Entries.Line [entry]);
   #endif
       entry = Entries.NextEntry [entry];
       firstline = false;
       ++entries;
   }
}
printf (\"* %d sections, %d entries\", i, entries);
if (comment
  • )

   printf (\"* Comment: %s\", comment);
return 1;
}
return 0;
}
stock DOF2::WriteFile ()
{
if (CurrentFile
  • )

{
new
   File: f = fopen (CurrentFile, io_write),
   bool: firstline = true,
   entry;
if (f)
{
   for (new i; i < Sections.Count; ++i)
   {
       if (Sections.FirstEntry != INVALID_ENTRY) // Do not write when empty.
       {
          if (i)
         {
             if (!firstline)
            {
               fputchar (f, \'\\r\', UseUTF8);
               fputchar (f, \'\\n\', UseUTF8);
            }
            else
                firstline = false;
            fputchar (f, \'[\', UseUTF8);
            fwritechars (f, Sections.Tag );
            fputchar (f, \']\', UseUTF8);
            fputchar (f, \'\\r\', UseUTF8);
            fputchar (f, \'\\n\', UseUTF8);
         }
         entry = Sections.FirstEntry ;
         while (entry != INVALID_ENTRY)
         {
             fwritechars (f, Entries.Line [entry]);
             fputchar (f, \'\\r\', UseUTF8);
             fputchar (f, \'\\n\', UseUTF8);
             entry = Entries.NextEntry [entry];
             firstline = false;
         }
      }
   }
   FileChanged = false;
   return fclose (f);
}
}
return 0;
}
stock DOF2::ParseFile (file [], extraid = -1, bool: callback = false)
{
    if (file
  • && DOF2::FileExists (file))

{
    /*
    Write the file in the buffer when:
    - There is actually a file in the buffer
    - The file in the buffer is not the file you want to parse and this file has been changed.
    - Or the current file is the file you want to and has been changed.
    */
    //if (CurrentFile
  • && ((strcmp (CurrentFile, file) && FileChanged) || FileChanged))

    if (CurrentFile
  • && FileChanged) // Equal to the query above but shorter.

       DOF2::WriteFile ();
new
   File: f = fopen (file, io_readwrite),
    buf [MAX_LINE_SIZE],
#if PACK_CONTENT == true
    line [MAX_LINE_SIZE char],
    tag [MAX_SECTION_TAG],
#else
    line [MAX_LINE_SIZE],
#endif
    key [MAX_LINE_SIZE],
    value [MAX_LINE_SIZE],
   c,
   pos;
if (f)
{
   FileChanged = false;
            DOF2::SetFile (file);
   Sections.Count = 1;
   Entries.Count = 0;
   Sections.FirstEntry
  • = Sections.LastEntry
  • = INVALID_ENTRY;

   for (new i, size = flength (f); i < size; ++i)
   {
       c = fgetchar (f, 0, UseUTF8);
      if (pos == MAX_LINE_SIZE - 1 || c == \'\\n\' || c == \'\\r\')
          c = \'\\0\';
   #if PACK_CONTENT == true
      line {pos++} = c;
   #else
       line [pos++] = c;
   #endif
      if (c == \'\\0\')
      {
          // A new section found. Add the section to the list of sections.
      #if PACK_CONTENT == true
          if (line {0} == \'[\')
      #else
                   if (line
  • == \'[\')

      #endif
          {
              if (Sections.Count < MAX_SECTIONS)
              {
               pos = 1;
            #if PACK_CONTENT == true
               while (line {pos} && line {pos} != \']\' && (pos - 1) < MAX_SECTION_TAG)
               {
                  Sections.Tag [sections.Count]{pos - 1} = line {pos};
                  ++pos;
               }
               Sections.Tag [sections.Count]{pos - 1} = \'\\0\';
            #else
                while (line [pos] && line [pos] != \']\' && (pos - 1) < MAX_SECTION_TAG)
               {
                  Sections.Tag [sections.Count][pos - 1] = line [pos];
                  ++pos;
               }
               Sections.Tag [sections.Count][pos - 1] = \'\\0\';
            #endif
               Sections.FirstEntry [sections.Count] = Sections.LastEntry [sections.Count] = INVALID_ENTRY;
               ++Sections.Count;
             }
          }
          else
          {
         #if PACK_CONTENT == true
              if (line {0})
         #else
             if (line
  • )

         #endif
              {
              #if PACK_CONTENT == true
               strunpack (buf, line);
                 DOF2::ParseLine (buf, key, value);
                 strunpack (tag, Sections.Tag [sections.Count - 1]);
               // Call a specific function for a specific entry - ZCMD-style!
                 if (callback)
                 {
                    format (buf, sizeof (buf), \"_OnParseFile_%s_%s\", tag, key);
                    if (!CallRemoteFunction (buf, \"is\", extraid, value))
                     CallRemoteFunction (\"_OnDefaultParseFile\", \"issss\", extraid, value
  • ? value : (\"\\1\"), key, Sections.Tag [sections.Count - 1][0] ? Sections.Tag [sections.Count - 1] : (\"\\1\"), file);

               }
            #else
                 DOF2::ParseLine (line, key, value);
               // Call a specific function for a specific entry - ZCMD-style!
                 if (callback)
                 {
                    format (buf, sizeof (buf), \"_OnParseFile_%s_%s\", Sections.Tag [sections.Count - 1], key);
                    if (!CallRemoteFunction (buf, \"is\", extraid, value))
                     CallRemoteFunction (\"_OnDefaultParseFile\", \"issss\", extraid, value
  • ? value : (\"\\1\"), key, Sections.Tag [sections.Count - 1][0] ? Sections.Tag [sections.Count - 1] : (\"\\1\"), file);

               }
            #endif
               // Add entry to it\'s section and to the list which will be sorted.
               Entries.Line [Entries.Count] = line;
               Entries.Tag [Entries.Count] = Sections.Tag [sections.Count - 1];
                        #if MAX_SECTIONS >= 256
               Entries.Section [Entries.Count] = Sections.Count - 1;
            #else
               Entries.Section {Entries.Count} = Sections.Count - 1;
            #endif
               Entries.NextEntry [Entries.Count] = INVALID_ENTRY;
               SortedEntryList [Entries.Count][0] = DOF2::HashKey (key);
               SortedEntryList [Entries.Count][1] = Entries.Count;
               if (Sections.LastEntry [sections.Count - 1] == INVALID_ENTRY)
               {
                   Sections.FirstEntry [sections.Count - 1] = Sections.LastEntry [sections.Count - 1] = Entries.Count;
                   Entries.PreviousEntry [Entries.Count] = INVALID_ENTRY;
               }
               else
               {
                  Entries.NextEntry [sections.LastEntry [sections.Count - 1]] = Entries.Count;
                  Entries.PreviousEntry [Entries.Count] = Sections.LastEntry [sections.Count - 1];
                  Sections.LastEntry [sections.Count - 1] = Entries.Count;
               }
               ++Entries.Count;
            }
          }
          pos = 0;
      }
   }
   /*
    * Sort list of entries by it\'s hashcodes in O(n * log n) time.
    * (Worst case is actually O(n * n), however, this QuickSort implementation chooses a randomized pivot
    * to minimize the chance for the worst case.)
    */
   DOF2::SortEntries (SortedEntryList, 0, Entries.Count - 1, true);
   return fclose (f);
}
}
return 0;
}
// Rather useless.
stock DOF2::ReparseFile (file [], extraid, bool: callback = true)
{
if (file
  • && CurrentFile
  • && !strcmp (file, CurrentFile))

{
    CurrentFile
  • = \'\\0\';

return DOF2::ParseFile (file, extraid, callback);
}
return 0;
}
private DOF2::ParseLine (line [], key [], value [], keysize = sizeof (key), valuesize = sizeof (value))
{
new
pos,
readpos;
if ((pos = charfind (line, \'=\')) != -1)
{
    // Read key and value.
    readpos = pos - 1;
while (readpos >= 0 && line [readpos] == \' \')
    --readpos;
if (readpos >= 0 && keysize > (readpos + 1))
{
   key [readpos + 1] = \'\\0\';
   while (readpos >= 0)
   {
      key [readpos] = line [readpos];
      --readpos;
   }
}
else
    return 0;
readpos = pos + 1;
++pos;
while (line [readpos] == \' \')
{
   ++pos;
    ++readpos;
}
        if (line [readpos])
{
    while (readpos >= 0 && line [readpos] && valuesize > (readpos - pos + 1))
   {
      value [readpos - pos] = line [readpos];
      ++readpos;
   }
   value [readpos - pos] = \'\\0\';
}
else
{
    key
  • = value
  • = \'\\0\';

    return 0;
}
if (!strcmp (value, \"(null)\", true))
    value
  • = \'\\0\';

return 1;
}
key
  • = value
  • = \'\\0\';

return 0;
}
stock DOF2::File (user [])
{
new newfile [MAX_FILE_SIZE];
format (newfile, sizeof (newfile), USER_FILE_PATH, DOF2::udb_encode (user));
return newfile;
}
stock bool: DOF2::CheckLogin (file [], password [])
return (file
  • && password
  • && DOF2::num_hash (password) == DOF2::GetInt (file, USER_PW_HASH_KEY));

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
stock DOF2::binstr (value, dest [], size = sizeof (dest))
{
new buf [32 + 3] = \"0b\";
for (new i = 0; i < 32; ++i)
    buf [i + 2] = \'0\' + ((value >>> (31 - i)) & 1);
DOF2::strcpy (dest, buf, size);
}
//format (dest, size, \"0b%b\", value);
stock DOF2::hexstr (value, dest [], size = sizeof (dest))
{
static const characters [] =
{
    \'0\', \'1\', \'2\', \'3\',
    \'4\', \'5\', \'6\', \'7\',
    \'8\', \'9\', \'A\', \'B\',
    \'C\', \'D\', \'E\', \'F\'
};
new buf [8 + 3] = \"0x\";
for (new i = 0; i < 8; ++i)
buf [2 + i] = characters [(value >>> ((7 - i) << 2)) & 0x0F];
DOF2::strcpy (dest, buf, size);
}
//format (dest, size, \"0x%x\", value);
stock DOF2::strhex (string [])
{
new
i,
value;
if (string
  • == \'0\' && (string [1] == \'x\' || string [1] == \'X\'))

i = 2;
    while (string )
    {
value <<= 4;
switch (string )
{
    case \'0\' .. \'9\':
        value |= string - \'0\';
   case \'A\' .. \'F\':
       value |= string - \'A\' + 10;
            case \'a\' .. \'f\':
       value |= string - \'a\' + 10;
   default:
       return 0;
}
++i;
    }
    return value;
}
stock DOF2::strbin (string [])
{
new
    i,
    value;
if (string
  • == \'0\' && (string [1] == \'b\' || string [1] == \'B\'))

    i = 2;
while (string )
{
    if (string != \'1\' && string != \'0\')
        return 0;
value <<= 1;
value |= (string - \'0\');
++i;
}
return value;
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
private charfind (string [], c)
{
for (new i, len = strlen (string); i < len; ++i)
if (string == c)
    return i;
return -1;
}
private fwritechars (File: handle, c [])
{
    new pos;
#if PACK_CONTENT == true
while (c {pos})
    fputchar (handle, c {pos++}, UseUTF8);
#else
    while (c [pos])
    fputchar (handle, c [pos++], UseUTF8);
#endif
}
private DOF2::SortEntries (entries [][2], l, r, bool: randomize = true)
{
if (r > l)
{
if (randomize)
{
   new k = l + (random (65535) % (r - l + 1));
     DOF2::SwapSortedEntries (entries [k], entries [r]);
}
new
   i = l - 1,
   j = r,
   pivot = entries [r][0];
while (i < j)
{
   do
      ++i;
   while (entries [0] <= pivot && i < r);
   do
       --j;
   while (entries [j][0] >= pivot && j > l);
   if (i < j)
       DOF2::SwapSortedEntries (entries , entries [j]);
}
DOF2::SwapSortedEntries (entries , entries [r]);
DOF2::SortEntries (entries, l, i - 1, randomize);
DOF2::SortEntries (entries, i + 1, r, randomize);
}
}
private DOF2::SwapSortedEntries (a [2], b [2])
{
new c [2];
c
  • = a
  • ;

c [1] = a [1];
a
  • = b
  • ;

a [1] = b [1];
b
  • = c
  • ;

b [1] = c [1];
}
stock DOF2::SortAllSections (file [], bool: ignorecase = true, bool: ascending = true)
{
    if (file
  • )

{
    if (!CurrentFile
  • || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.

       if (!DOF2::ParseFile (file, -1, false))
           return 0;
new
   entries [MAX_ENTRIES],
   keys [MAX_ENTRIES][MAX_LINE_SIZE],
   key [MAX_LINE_SIZE],
   value [MAX_LINE_SIZE],
    #if PACK_CONTENT == true
   line [MAX_LINE_SIZE],
#endif
   entry,
   i;
for (new section = 0; section < Sections.Count; ++section)
{
    i = 0;
   entry = Sections.FirstEntry [section];
   while (entry != INVALID_ENTRY)
   {
        #if PACK_CONTENT == true
       strunpack (line, Entries.Line [entry]);
       DOF2::ParseLine (line, key, value);
   #else
       DOF2::ParseLine (Entries.Line [entry], key, value);
   #endif
       keys [0] = \'\\0\';
       strcat (keys , key);
       entries = entry;
       entry = Entries.NextEntry [entry];
       ++i;
   }
   if (i > 0)
      DOF2::SortSection_Internal (section, entries, keys, 0, i - 1, ignorecase, ascending);
}
return 1;
}
return 0;
}
stock DOF2::SortSection (file [], tag [], bool: ignorecase = true, bool: ascending = true)
{
if (file
  • )

{
    if (!CurrentFile
  • || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.

       if (!DOF2::ParseFile (file, -1, false))
           return 0;
new
    section = INVALID_SECTION,
   entries [MAX_ENTRIES],
   keys [MAX_ENTRIES][MAX_LINE_SIZE],
   key [MAX_LINE_SIZE],
   buf [MAX_LINE_SIZE],
    #if PACK_CONTENT == true
   line [MAX_LINE_SIZE],
#endif
   entry,
   i;
if (!tag
  • )

   section = 0;
else
{
   for (i = 1; i < Sections.Count; ++i)
   {
   #if PACK_CONTENT == true
       strunpack (buf, Sections.Tag );
       if (buf
  • && !strcmp (tag, buf, !CaseSensitive))

       {
           section = i;
           break;
       }
   #else
       if (Sections.Tag [0] && !strcmp (tag, Sections.Tag , !CaseSensitive))
       {
           section = i;
           break;
       }
   #endif
   }
}
if (section != INVALID_SECTION)
{
    i = 0;
   entry = Sections.FirstEntry [section];
   while (entry != INVALID_ENTRY)
   {
        #if PACK_CONTENT == true
       strunpack (line, Entries.Line [entry]);
       DOF2::ParseLine (line, key, buf);
   #else
       DOF2::ParseLine (Entries.Line [entry], key, buf);
   #endif
       keys [0] = \'\\0\';
       strcat (keys , key);
       entries = entry;
       entry = Entries.NextEntry [entry];
       ++i;
   }
   if (i > 0)
   {
      DOF2::SortSection_Internal (section, entries, keys, 0, i - 1, ignorecase, ascending);
       return 1;
   }
}
}
return 0;
}
private DOF2::SortSection_Internal (section, entries [], keys [][], l, r, bool: ignorecase = true, bool: ascending = true)
{
// Entries must be stored into an array...
    if (0 <= section < Sections.Count && r > l)
    {
        new
            i = l - 1,
            j = r,
   buf [MAX_LINE_SIZE];
        static
            pivot [MAX_LINE_SIZE]; // Must be static, otherwise too much memory usage during recursion ==> Script will crash!
        pivot
  • = \'\\0\';

        strcat (pivot, keys [r]);
        while (i < j)
        {
            if (ascending)
            {
                do
                    ++i;
                while (strcmp (keys , pivot,  ignorecase) <= 0 && i < r);
                do
                    --j;
                while (strcmp (keys [j], pivot, ignorecase) >= 0 && j > l);
            }
            else
            {
                do
                    ++i;
                while (strcmp (keys , pivot,  ignorecase) >= 0 && i < r);
                do
                    --j;
                while (strcmp (keys [j], pivot, ignorecase) <= 0 && j > l);
            }
            if (i < j)
            {
                DOF2::SwapEntries (section, entries , entries [j]);
      DOF2::strcpy (buf, keys );
      DOF2::strcpy (keys , keys [j], MAX_LINE_SIZE);
      DOF2::strcpy (keys [j], buf, MAX_LINE_SIZE);
      entries ^= entries [j];
                entries [j] ^= entries ;
          &nb

 
Frissítve: 2013.02.07
« Utoljára szerkesztve: 2013. Szeptember 02. - 14:50:40 írta Benceee »

Nem elérhető Sramm

  • 596
    • Profil megtekintése
DOF2 Használata(Double-O-Files_2)
« Válasz #1 Dátum: 2013. Február 07. - 18:19:00 »
+1
Frissítve: 2012.02.07[/quote]
2013-at írunk.  ;D

Nem elérhető ZyZu.

  • Globális moderátor
  • 8939
  • my turbo diesel forum
  • Discord: ZyZu.
    • Profil megtekintése
DOF2 Használata(Double-O-Files_2)
« Válasz #2 Dátum: 2013. Február 07. - 20:27:50 »
0
Javítva! :D Köszönöm, hogy szóltál!  ;)

Nem elérhető Rupert

  • 2301
    • Profil megtekintése
DOF2 Használata(Double-O-Files_2)
« Válasz #3 Dátum: 2013. Február 07. - 20:59:51 »
+1
Áthelyezve, szép, igényes leírás.

Nem elérhető ZyZu.

  • Globális moderátor
  • 8939
  • my turbo diesel forum
  • Discord: ZyZu.
    • Profil megtekintése
DOF2 Használata(Double-O-Files_2)
« Válasz #4 Dátum: 2013. Február 07. - 21:24:45 »
0
Köszönöm!  ;) Leírást bõvitem!  :)

DOF2 Használata(Double-O-Files_2)
« Válasz #5 Dátum: 2013. Március 05. - 21:14:42 »
0
Hasznos

 

SimplePortal 2.3.7 © 2008-2024, SimplePortal