28/02/2024 23:41
Eu uso essa daqui e nunca tive problemas:
Código:
#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 Entry.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_RemoveTag (file [], tag []);
*/
// OnParseFile <Tag><Key>(extraid, value [])
// OnParseFile <><Key>(extraid, value [])
// OnDefaultParseFile (extraid, value [], key [], tag [], file [])
#define OnParseFile<%0><%1>(%2) \
forward _OnParseFile_%0_%1(%2); \
public _OnParseFile_%0_%1(%2)
#define OnDefaultParseFile(%0) \
forward _OnDefaultParseFile(%0); \
public _OnDefaultParseFile(%0)
#define DOF2_ParseBool() \
(strval (value) || (value [0] && !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 Tag. \
Tag_
#define Entry. \
Entry_
#define DOF2:: \
DOF2_
/*
#define MAX_TAG_SIZE (32)
#define MAX_LINE_SIZE (128)
#define MAX_TAGS (32)
#define MAX_ENTRIES (256)
#define MAX_FILE_SIZE (64)
#define USER_FILE_PATH "Users/%s.ini"
*/
#if !defined MAX_TAG_SIZE
#define MAX_TAG_SIZE (32)
#endif
#if !defined MAX_LINE_SIZE
#define MAX_LINE_SIZE (128)
#endif
#if !defined MAX_TAGS
#define MAX_TAGS (32)
#endif
#if !defined MAX_ENTRIES
#define MAX_ENTRIES (256)
#endif
#if !defined MAX_FILE_SIZE
#define MAX_FILE_SIZE (64)
#endif
#if !defined DUDB_CONVERT && 0 // Change to 1 to enable.
#define DUDB_CONVERT
#if !defined USER_FILE_PATH
#define USER_FILE_PATH "%s.dudb.sav"
#endif
#elseif !defined USER_FILE_PATH
#define USER_FILE_PATH "Users/%s.ini" // Create Users folder or redefine.
#endif
#if !defined DINI_CONVERT && 0 // Change to 1 to enable.
#define DINI_CONVERT
#endif
#if MAX_TAGS >= 256
#error MAX_TAGS must not be greater than 255.
#endif
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static stock
bool: UTF8 = true,
CurrentFile [MAX_FILE_SIZE],
bool: FileChanged,
Tag.Name [MAX_TAGS][MAX_TAG_SIZE char],
Tag.FirstEntry [MAX_TAGS] = {-1, ...},
Tag.LastEntry [MAX_TAGS] = {-1, ...},
Tag.Count,
Entry.Line [MAX_ENTRIES][MAX_LINE_SIZE char],
Entry.Tag [MAX_ENTRIES][MAX_TAG_SIZE char],
Entry.TagID [MAX_ENTRIES char],
Entry.NextEntry [MAX_ENTRIES] = {-1, ...},
Entry.PreviousEntry [MAX_ENTRIES] = {-1, ...},
Entry.Count,
SortedEntries [MAX_ENTRIES][2]; // Index 0: Hashcode, Index 1: EntryID
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
DOF2::Exit ()
DOF2::WriteFile ();
stock DOF2::SetUTF8 (bool: set)
UTF8 = set;
stock bool: DOF2::GetUTF8 ()
return UTF8;
stock DOF2::SetFile (file [])
{
CurrentFile [0] = '\0';
strcat (CurrentFile, file);
}
stock DOF2::GetFile ()
return CurrentFile;
stock DOF2::CreateFile (file [], password [] = "")
{
if (!DOF2::FileExists (file))
{
if (password [0])
#if defined DUDB_CONVERT
DOF2::SetInt (file, "password_hash", DOF2::num_hash (password));
#else
DOF2::SetInt (file, "password", DOF2::num_hash (password));
#endif
else
{
new File: f = fopen (file, io_append);
fclose (f);
}
return 1;
}
return 0;
}
stock DOF2::RenameFile (oldfile [], newfile [])
{
if (DOF2::FileExists (oldfile) && !DOF2::FileExists (newfile))
{
if (CurrentFile [0] && !strcmp (CurrentFile, oldfile) && FileChanged)
DOF2::WriteFile ();
else
DOF2::ParseFile (oldfile, -1, false);
DOF2::SetFile (newfile);
if (DOF2::WriteFile ())
{
fremove (oldfile);
return 1;
}
}
return 0;
}
stock DOF2::CopyFile (filetocopy [], newfile [])
{
if (DOF2::FileExists (filetocopy) && !DOF2::FileExists (newfile))
{
if (CurrentFile [0] && !strcmp (CurrentFile, filetocopy) && FileChanged)
DOF2::WriteFile ();
else
DOF2::ParseFile (filetocopy, -1, false);
DOF2::SetFile (newfile);
return DOF2::WriteFile ();
}
return 0;
}
stock DOF2::RemoveFile (file [])
{
if (file [0])
{
if (CurrentFile [0] && !strcmp (CurrentFile, file))
CurrentFile [0] = '\0';
fremove (file);
return 1;
}
return 0;
}
stock DOF2::MakeBackup (file [])
{
if (DOF2::FileExists (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);
}
return 0;
}
stock DOF2::RemoveTag (file [], tag [])
{
// Removes tag 'tag' with all it's entries.
if (file [0] && tag [0]) // You can't remove the empty tag.
{
if (CurrentFile [0] && !strcmp (CurrentFile, file) && FileChanged)
DOF2::WriteFile ();
else
DOF2::ParseFile (file, -1, false);
new
line [MAX_LINE_SIZE],
buf [MAX_TAG_SIZE],
tagid = -1,
currententry,
key [MAX_KEY_SIZE];
for (new i = 1; i < Tag.Count; ++i)
{
strunpack (buf, Tag.Name [i]);
if (!strcmp (buf, tag))
{
tagid = i;
break;
}
}
if (tagid != -1)
{
currententry = Tag.FirstEntry [tagid];
while (currententry != -1)
{
// Remove all entries under the current tag.
strunpack (line, Entry.Line [currententry]);
DOF2::ParseLine (line, key, buf);
DOF2::Unset (file, key, tag);
currententry = Entry.NextEntry [currententry];
}
// Move the last tag to the position of the current tag. Creates a little mess.
--Tag.Count;
Tag.Name [tagid] = Tag.Name [Tag.Count];
Tag.FirstEntry [tagid] = Tag.FirstEntry [Tag.Count];
Tag.LastEntry [tagid] = Tag.LastEntry [Tag.Count];
currententry = Tag.FirstEntry [tagid];
while (currententry != -1)
{
Entry.TagID {currententry} = tagid;
currententry = Entry.NextEntry [currententry];
}
FileChanged = true;
return 1;
}
}
return 0;
}
static stock DOF2::FindEntry (key [], tag [], keybuf [], valbuf [], &pos, keybufsize = sizeof (keybuf), valbufsize = sizeof (valbuf))
{
if (key [0])
{
new
entry = -1,
l,
m,
r,
h,
line [MAX_LINE_SIZE],
i;
h = DOF2::bernstein (key);
l = 0;
r = Entry.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 == SortedEntries [l][0])
{
m = l;
entry = SortedEntries [l][1];
}
else if (r > l && h == SortedEntries [r][0])
{
m = r;
entry = SortedEntries [r][1];
}
break;
}
else
{
m = l + (r - l) / 2;
if (h == SortedEntries [m][0])
{
entry = SortedEntries [m][1];
break;
}
else if (h > SortedEntries [m][0])
l = m + 1;
else
r = m - 1;
}
}
// Candidate found?
if (entry != -1)
{
strunpack (line, Entry.Line [entry]);
DOF2::ParseLine (line, keybuf, valbuf, keybufsize, valbufsize);
// Check if it's the entry we want.
if (!strcmp (keybuf, key) && ((!tag [0] && !Entry.Tag [entry][0]) || (tag [0] && Entry.Tag [entry][0] && !strcmp (tag, Entry.Tag [entry]))))
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 == SortedEntries [i][0]; --i)
{
entry = SortedEntries [i][1];
strunpack (line, Entry.Line [entry]);
DOF2::ParseLine (line, keybuf, valbuf, keybufsize, valbufsize);
if (!strcmp (keybuf, key) && ((!tag [0] && !Entry.Tag [entry][0]) || (tag [0] && Entry.Tag [entry][0] && !strcmp (tag, Entry.Tag [entry]))))
return (pos = i, entry);
}
for (i = m + 1; i < Entry.Count && h == SortedEntries [i][0]; ++i)
{
entry = SortedEntries [i][1];
strunpack (line, Entry.Line [entry]);
DOF2::ParseLine (line, keybuf, valbuf, keybufsize, valbufsize);
if (!strcmp (keybuf, key) && ((!tag [0] && !Entry.Tag [entry][0]) || (tag [0] && Entry.Tag [entry][0] && !strcmp (tag, Entry.Tag [entry]))))
return (pos = i, entry);
}
}
}
}
return -1;
}
stock DOF2::SetString (file [], key [], value [], tag [] = "")
{
if (file [0] && key [0])
{
new
entry,
pos,
tagid = -1,
buf [MAX_TAG_SIZE],
keybuf [MAX_LINE_SIZE],
valbuf [MAX_LINE_SIZE],
line [MAX_LINE_SIZE],
i;
if (!CurrentFile [0] || strcmp (CurrentFile, file))
DOF2::ParseFile (file, -1, false);
entry = DOF2::FindEntry (key, tag, keybuf, valbuf, pos);
// If the entry has been found, just change it's content.
if (entry != -1)
{
format (line, sizeof (line), "%s = %s", key, value);
FileChanged = true;
return strpack (Entry.Line [entry], line);
}
if (Entry.Count >= MAX_ENTRIES)
return 0;
// Search for the section where the entry belongs.
if (!tag [0])
tagid = 0;
else
{
for (i = 1; i < Tag.Count; ++i)
{
strunpack (buf, Tag.Name [i]);
if (buf [0] && !strcmp (tag, buf))
{
tagid = i;
break;
}
}
}
// Section we want does not exist, create new one if possible.
if (tagid == -1)
{
if (Tag.Count >= MAX_TAGS)
return 0;
tagid = Tag.Count;
strpack (Tag.Name [tagid], tag);
Tag.FirstEntry [tagid] = Tag.LastEntry [tagid] = -1;
++Tag.Count;
}
// Add the entry to the section. Section's content is defined by a linear two way list.
format (line, sizeof (line), "%s = %s", key, value);
strpack (Entry.Line [Entry.Count], line);
Entry.Tag [Entry.Count] = Tag.Name [tagid];
Entry.TagID {Entry.Count} = tagid;
Entry.NextEntry [Entry.Count] = -1;
// Add entry to sorted list of entries and move to right correct position in O(n) time.
SortedEntries [Entry.Count][0] = DOF2::bernstein (key);
SortedEntries [Entry.Count][1] = Entry.Count;
i = Entry.Count - 1;
while (i >= 0 && SortedEntries [i][0] > SortedEntries [i + 1][0])
{
DOF2::Swap (SortedEntries [i], SortedEntries [i + 1]);
--i;
}
if (Tag.LastEntry [tagid] == -1)
{
Tag.FirstEntry [tagid] = Tag.LastEntry [tagid] = Entry.Count;
Entry.PreviousEntry [Entry.Count] = -1;
}
else
{
new name [MAX_TAG_SIZE];
strunpack (name, Tag.Name [tagid]);
Entry.NextEntry [Tag.LastEntry [tagid]] = Entry.Count;
Entry.PreviousEntry [Entry.Count] = Tag.LastEntry [tagid];
Tag.LastEntry [tagid] = Entry.Count;
}
++Entry.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 [0] && key [0])
{
new
pos,
keybuf [MAX_LINE_SIZE];
if (!CurrentFile [0] || strcmp (CurrentFile, file))
DOF2::ParseFile (file, -1, false);
// Find entry and assign the result with it's value.
return (DOF2::FindEntry (key, tag, keybuf, result, pos, sizeof (keybuf), size) != -1);
}
return 0;
}
stock DOF2::Unset (file [], key [], tag [] = "")
{
if (file [0] && key [0])
{
new
entry,
pos,
keybuf [MAX_LINE_SIZE],
valbuf [MAX_LINE_SIZE];
if (!CurrentFile [0] || strcmp (CurrentFile, file))
DOF2::ParseFile (file, -1, false);
if ((entry = DOF2::FindEntry (key, tag, keybuf, valbuf, pos)) != -1)
{
// Remove entry from it's section.
if (Tag.FirstEntry [Entry.TagID {entry}] == entry)
{
Tag.FirstEntry [Entry.TagID {entry}] = Entry.NextEntry [entry];
if (Entry.NextEntry [entry] != -1)
Entry.PreviousEntry [Entry.NextEntry [entry]] = -1;
}
else
{
Entry.NextEntry [Entry.PreviousEntry [entry]] = Entry.NextEntry [entry];
if (Entry.NextEntry [entry] != -1)
Entry.PreviousEntry [Entry.NextEntry [entry]] = Entry.PreviousEntry [entry];
}
if (Tag.LastEntry [Entry.TagID {entry}] == entry)
{
Tag.LastEntry [Entry.TagID {entry}] = Entry.PreviousEntry [entry];
if (Entry.PreviousEntry [entry] != -1)
Entry.NextEntry [Entry.PreviousEntry [entry]] = -1;
}
else
{
Entry.PreviousEntry [Entry.NextEntry [entry]] = Entry.PreviousEntry [entry];
if (Entry.PreviousEntry [entry] != -1)
Entry.NextEntry [Entry.PreviousEntry [entry]] = Entry.NextEntry [entry];
}
// Move the entry to the end of the sorted list and decrement Entry.Count to forget about the unset entry.
while (pos < (Entry.Count - 1))
{
DOF2::Swap (SortedEntries [pos], SortedEntries [pos + 1]);
++pos;
}
--Entry.Count;
FileChanged = true;
return 1;
}
}
return 0;
}
stock DOF2::RenameKey (file [], oldkey [], newkey [], tag [] = "")
{
if (file [0] && oldkey [0])
{
new
entry,
pos,
keybuf [MAX_LINE_SIZE],
valbuf [MAX_LINE_SIZE],
line [MAX_LINE_SIZE];
if (!CurrentFile [0] || strcmp (CurrentFile, file))
DOF2::ParseFile (file, -1, false);
if ((entry = DOF2::FindEntry (oldkey, tag, keybuf, valbuf, pos)) != -1)
{
// Change content of entry.
format (line, sizeof (line), "%s = %s", newkey, valbuf);
strpack (Entry.Line [entry], line);
// Because the hashcode has been changed, the entry has to move in the list.
SortedEntries [pos][0] = DOF2::bernstein (newkey);
if (pos < (MAX_ENTRIES - 1) && SortedEntries [pos][0] > SortedEntries [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) && SortedEntries [pos][0] > SortedEntries [pos + 1][0])
{
DOF2::Swap (SortedEntries [pos], SortedEntries [pos + 1]);
++pos;
}
}
else if (pos > 0 && SortedEntries [pos][0] < SortedEntries [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 && SortedEntries [pos][0] < SortedEntries [pos - 1][0])
{
DOF2::Swap (SortedEntries [pos], SortedEntries [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 [0] || strcmp (CurrentFile, file))
DOF2::ParseFile (file, -1, false);
// Try to find the entry.
return (DOF2::FindEntry (key, tag, keybuf, valbuf, pos) != -1);
}
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 [0] && !strcmp (buf, "true", true)));
}
stock DOF2::SetBool (file [], key [], bool: value, tag [] = "")
{
if (value)
return DOF2::SetString (file, key, "true", tag);
else
return DOF2::SetString (file, key, "false", tag);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
stock DOF2::PrintFile (comment [] = "")
{
if (CurrentFile [0])
{
new
File: f = fopen (CurrentFile, io_write),
bool: firstline = true,
currententry,
buf [MAX_LINE_SIZE],
entries,
i;
if (f)
{
printf ("[DOF] Current file: %s", CurrentFile);
for ( ; i < Tag.Count; ++i)
{
if (i)
{
strunpack (buf, Tag.Name [i]);
format (buf, sizeof (buf), "[%s]", buf);
if (!firstline)
print (" ");
else
firstline = false;
print (buf);
}
currententry = Tag.FirstEntry [i];
while (currententry != -1)
{
strunpack (buf, Entry.Line [currententry]);
currententry = Entry.NextEntry [currententry];
firstline = false;
++entries;
print (buf);
}
}
printf ("* %d sections, %d entries", i, entries);
if (comment [0])
printf ("* Comment: %s", comment);
return fclose (f);
}
}
return 0;
}
stock DOF2::WriteFile ()
{
if (CurrentFile [0])
{
new
File: f = fopen (CurrentFile, io_write),
bool: firstline = true,
currententry;
if (f)
{
for (new i; i < Tag.Count; ++i)
{
if (Tag.FirstEntry [i] != -1) // Do not write when empty.
{
if (i)
{
if (!firstline)
{
fputchar (f, '\r', UTF8);
fputchar (f, '\n', UTF8);
}
else
firstline = false;
fputchar (f, '[', UTF8);
fwritechars (f, Tag.Name [i]);
fputchar (f, ']', UTF8);
fputchar (f, '\r', UTF8);
fputchar (f, '\n', UTF8);
}
currententry = Tag.FirstEntry [i];
while (currententry != -1)
{
fwritechars (f, Entry.Line [currententry]);
fputchar (f, '\r', UTF8);
fputchar (f, '\n', UTF8);
currententry = Entry.NextEntry [currententry];
firstline = false;
}
}
}
FileChanged = false;
return fclose (f);
}
}
return 0;
}
stock DOF2::ParseFile (file [], extraid, bool: callback = true)
{
if (file [0])
{
if (((CurrentFile [0] && strcmp (CurrentFile, file)) || callback) && FileChanged)
DOF2::WriteFile ();
new
File: f = fopen (file, io_readwrite),
line [MAX_LINE_SIZE char],
buf [MAX_LINE_SIZE],
key [MAX_LINE_SIZE],
value [MAX_LINE_SIZE],
tag [MAX_TAG_SIZE],
c,
pos;
if (f)
{
FileChanged = false;
DOF2::SetFile (file);
Tag.Count = 1;
Entry.Count = 0;
Tag.FirstEntry [0] = Tag.LastEntry [0] = -1;
for (new i, size = flength (f); i < size; ++i)
{
c = fgetchar (f, 0, UTF8);
if (pos == MAX_LINE_SIZE - 1 || c == '\n' || c == '\r')
c = '\0';
line {pos++} = c;
if (c == '\0')
{
// A new section found. Add the section to the list of sections.
if (line {0} == '[')
{
if (Tag.Count < MAX_TAGS)
{
pos = 1;
while (line {pos} && line {pos} != ']' && (pos - 1) < MAX_TAG_SIZE)
{
Tag.Name [Tag.Count]{pos - 1} = line {pos};
++pos;
}
Tag.Name [Tag.Count]{pos - 1} = '\0';
Tag.FirstEntry [Tag.Count] = Tag.LastEntry [Tag.Count] = -1;
++Tag.Count;
}
}
else
{
if (line {0})
{
strunpack (buf, line);
DOF2::ParseLine (buf, key, value);
strunpack (tag, Tag.Name [Tag.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, key, tag, file);
}
// Add entry to it's section and to the list which will be sorted.
Entry.Line [Entry.Count] = line;
Entry.Tag [Entry.Count] = Tag.Name [Tag.Count - 1];
Entry.TagID {Entry.Count} = Tag.Count - 1;
Entry.NextEntry [Entry.Count] = -1;
SortedEntries [Entry.Count][0] = DOF2::bernstein (key);
SortedEntries [Entry.Count][1] = Entry.Count;
if (Tag.LastEntry [Tag.Count - 1] == -1)
{
Tag.FirstEntry [Tag.Count - 1] = Tag.LastEntry [Tag.Count - 1] = Entry.Count;
Entry.PreviousEntry [Entry.Count] = -1;
}
else
{
Entry.NextEntry [Tag.LastEntry [Tag.Count - 1]] = Entry.Count;
Entry.PreviousEntry [Entry.Count] = Tag.LastEntry [Tag.Count - 1];
Tag.LastEntry [Tag.Count - 1] = Entry.Count;
}
++Entry.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::QuickSort (SortedEntries, 0, Entry.Count - 1, true);
return fclose (f);
}
}
return 0;
}
stock DOF2::ReparseFile (file [], extraid, bool: callback = true)
{
if (file [0] && CurrentFile [0] && !strcmp (file, CurrentFile))
{
CurrentFile [0] = '\0';
return DOF2::ParseFile (file, extraid, callback);
}
return 0;
}
static stock 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 [0] = '\0';
return 0;
}
return 1;
}
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 [0] && password [0] && DOF2::num_hash (password) == DOF2::GetInt (file, "password"));
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
stock DOF2::binstr (value, dest [], size = sizeof (dest))
format (dest, size, "0b%b", value);
stock DOF2::hexstr (value, dest [], size = sizeof (dest))
format (dest, size, "0x%x", value);
stock DOF2::strhex (string [])
{
new
i,
value;
if (string [0] == '0' && (string [1] == 'x' || string [1] == 'X'))
i = 2;
while (string [i])
{
value <<= 4;
switch (string [i])
{
case '0' .. '9':
value |= string [i] - '0';
case 'A' .. 'F':
value |= string [i] - 'A' + 10;
case 'a' .. 'f':
value |= string [i] - 'a' + 10;
default:
return 0;
}
++i;
}
return value;
}
stock DOF2::strbin (string [])
{
new
i,
value;
if (string [0] == '0' && (string [1] == 'b' || string [1] == 'B'))
i = 2;
while (string [i])
{
if (string [i] != '1' && string [i] != '0')
return 0;
value <<= 1;
value |= (string [i] - '0');
++i;
}
return value;
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static stock charfind (string [], c)
{
for (new i, len = strlen (string); i < len; ++i)
if (string [i] == c)
return i;
return -1;
}
static stock fwritechars (File: handle, c [])
{
new pos;
while (c {pos})
fputchar (handle, c {pos++}, UTF8);
}
static stock DOF2::QuickSort (array [][], l, r, bool: randomize = true)
{
if (r > l)
{
if (randomize)
{
new k = l + (random (32000) % (r - l + 1));
DOF2::Swap (array [k], array [r]);
}
new
i = l - 1,
j = r,
pivot = array [r][0];
while (i < j)
{
do
++i;
while (array [i][0] <= pivot && i < r);
do
--j;
while (array [j][0] >= pivot && j > l);
if (i < j)
DOF2::Swap (array [i], array [j]);
}
DOF2::Swap (array [i], array [r]);
DOF2::QuickSort (array, l, i - 1, randomize);
DOF2::QuickSort (array, i + 1, r, randomize);
}
}
static stock DOF2::Swap (a [], b [])
{
new c [2];
c [0] = a [0];
c [1] = a [1];
a [0] = b [0];
a [1] = b [1];
b [0] = c [0];
b [1] = c [1];
}
static stock DOF2::bernstein (string [])
{
new
h = -1,
i,
j;
while ((j = string [i++]))
h = h * 33 + j;
return h;
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
stock str_replace (newstr [], oldstr [], srcstr [], deststr [], bool: ignorecase = false, size = sizeof (deststr))
{
new
newlen = strlen (newstr),
oldlen = strlen (oldstr),
srclen = strlen (srcstr),
idx,
rep;
for (new i = 0; i < srclen; ++i)
{
if ((i + oldlen) <= srclen)
{
if (!strcmp (srcstr [i], oldstr, ignorecase, oldlen))
{
deststr [idx] = '\0';
strcat (deststr, newstr, size);
++rep;
idx += newlen;
i += oldlen - 1;
}
else
{
if (idx < (size - 1))
deststr [idx++] = srcstr [i];
else
return rep;
}
}
else
{
if (idx < (size - 1))
deststr [idx++] = srcstr [i];
else
return rep;
}
}
deststr [idx] = '\0';
return rep;
}
stock DOF2::udb_encode (nickname [])
{
new
buf [256],
result [256];
static const symbols [][2][] =
{
{"_", "_00"},
{";", "_01"},
{"!", "_02"},
{"/", "_03"},
{"\\", "_04"},
{"[", "_05"},
{"]", "_06"},
{"?", "_07"},
{".", "_08"},
{"*", "_09"},
{"<", "_10"},
{">", "_11"},
{"{", "_12"},
{"}", "_13"},
{" ", "_14"},
{"\"", "_15"},
{":", "_16"},
{"|", "_17"},
{"=", "_18"}
};
strcat (buf, nickname);
for (new i = 0; i < sizeof (symbols); ++i)
{
str_replace (symbols [i][1], symbols [i][0], buf, result);
buf [0] = '\0';
strcat (buf, result);
}
return result;
}
stock DOF2::udb_decode (nickname [])
{
new
buf [256],
result [256];
static const symbols [][2][] =
{
{"_", "_00"},
{";", "_01"},
{"!", "_02"},
{"/", "_03"},
{"\\", "_04"},
{"[", "_05"},
{"]", "_06"},
{"?", "_07"},
{".", "_08"},
{"*", "_09"},
{"<", "_10"},
{">", "_11"},
{"{", "_12"},
{"}", "_13"},
{" ", "_14"},
{"\"", "_15"},
{":", "_16"},
{"|", "_17"},
{"=", "_18"}
};
strcat (buf, nickname);
for (new i = 0; i < sizeof (symbols); ++i)
{
str_replace (symbols [i][0], symbols [i][1], buf, result);
buf [0] = '\0';
strcat (buf, result);
}
return result;
}
stock DOF2::num_hash (buf [])
{
new
length = strlen (buf),
s1 = 1,
s2 = 0,
n;
for (n = 0; n < length; n++)
{
s1 = (s1 + buf [n]) % 65521;
s2 = (s2 + s1) % 65521;
}
return (s2 << 16) + s1;
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#define DOF_ \
DOF2_
#if defined DUDB_CONVERT
#tryinclude <dutils>
#define dUser(%0).( DOF2_GetString(DOF2_File(%0),
#define dUserSet(%0).( DOF2_SetString(DOF2_File(%0),
#define dUserINT(%0).( DOF2_GetInt(DOF2_File(%0),
#define dUserSetINT(%0).( DOF2_SetInt(DOF2_File(%0),
#define dUserFLOAT(%0).( DOF2_GetFloat(DOF2_File(%0),
#define dUserSetFLOAT(%0).( DOF2_SetFloat(DOF2_File(%0),
#define udb_Create(%0,%1) DOF2_CreateFile(DOF2_File(%0),%1)
#define udb_RenameUser(%0,%1) DOF2_RenameFile(DOF2_File(%0),DOF2_File(%1))
#define udb_Exists(%0) DOF2_FileExists(DOF2_File(%0))
#define udb_Remove(%0) DOF2_RemoveFile(DOF2_File(%0))
#define udb_CheckLogin(%0,%1) DOF2_CheckLogin(DOF2_File(%0),%1)
#if !defined _dudb_included
#define _dudb_included
#endif
#endif
#if defined DINI_CONVERT
#define dini_Exists DOF2_FileExists
#define dini_Remove DOF2_RemoveFile
#define dini_Create DOF2_CreateFile
#define dini_Set DOF2_SetString
#define dini_Get DOF2_GetString
#define dini_IntSet DOF2_SetInt
#define dini_Int DOF2_GetInt
#define dini_BoolSet DOF2_SetBool
#define dini_Bool DOF2_GetBool
#define dini_FloatSet DOF2_SetFloat
#define dini_Float DOF2_GetFloat
#define dini_Unset DOF2_Unset
#define dini_Isset DOF2_IsSet
#if !defined _dini_included
#define _dini_included
#endif
#endif
#if defined DINI_CONVERT || defined DUDB_CONVERT
#define udb_hash DOF2_num_hash
#define num_hash DOF2_num_hash
#define udb_encode DOF2_udb_encode
#define udb_decode DOF2_udb_decode
#endif
Discente de Sistemas de Informação no Centro Federal de Ensino Tecnológico(CEFET/RJ)
Programador SA-MP desde 2012
Programador SA-MP desde 2012
Não envie dúvidas por inbox, crie um tópico. Sua dúvida pode ser a dúvida de outro alguém, e seu tópico ajudará outras pessoas no futuro.