[Include] eXtended INI Processor - Fast & Feature Rich INI Processor
#1

eXtended INI Processor
Fast,simple,unique,feature rich,user friendly INI Reader/Writer
Latest Version: 1.1 - 2/9/2015

eXtended INI Processor, eINI in short, is an amazing INI Processor include which comes with lot of new features,innumerable configurable options and lot more without compromising speed and efficiency of the server.This system works by caching the whole INI File and storing each and every single line in the memory where all manipulations are done.This means that the file is opened twice, once for parsing and once for saving.eINI stores sections,keys,lines in data structures which are commonly knows as linked lists where each node(i.e:line or key) stores the id of the next as well as the previous key which makes deleting,inserting operations easier and efficient.

There are many INI Processor Includes around but this one is a whole lot different from other.This is exclusively made for those who don't use YSI and who need some of the features which are not available in y_ini but comes with eINI.

Contents:
  • Features
  • INI Specifications
  • Getting Started & Configuration
  • Reading
  • Escape Characters & Replacements
  • Writing
  • Miscellaneous Functions
  • Benchmarks
  • Issues & Notes
  • Change Log
  • Download
  • Credits
Features:
  • Very fast and efficient
  • Supports Comments(inline as well line comments)
  • Read/Write Arrays,Enums
  • Read/Write Multiple Keys
  • Replacement Feature
  • Custom Replacements
  • Allows use of different INI Standards
  • Highly Customizable
  • Well Documented
  • Multiple File Support
  • Supports Section Tags
  • Saves the file the way it was(i.e:doesn't delete comments or blank lines)
How is eINI different from other INI Readers?
Firstly, eINI is way much faster than dini(as ****** says, though very popular it is insanely slow),SII and similar INI Readers.When compared with y_ini, eINI writes values much faster than y_ini but y_ini is slightly faster while reading smaller ini files.Given the fact that eINI parser is more careful and does more work, eINI working slower was expected but surprisingly eINI is faster than y_ini when large files are used.

Secondly, eINI provides some exiting features such as Replacements and different mods of parsing which has never been implemented in any other INI Processors.

Thirdly, easy to use and well documented.

List of functions:
  • INI::CreateINI
  • INI::OpenINI
  • INI::IsValidHandle
  • INI::CloseINI
  • INI::WriteBuffer
  • INI::ParseINI
  • INI::ReadString, INI::ReadBool, INI::ReadInteger, INI::ReadFloat, INI::ReadHex, INI::ReadBinary, INI::ReadArray, INI::ReadEnum, INI::ReadFormat
  • INI::WriteString, INI::WriteBool,INI::WriteInteger, INI::WriteFloat, INI::WriteHex, INI::WriteBinary, INI::WriteArray, INI::WriteEnum, INI::WriteFormat
  • INI::Replace,INI::SetReplacementText
  • INI::DeleteSection,INI::DeleteKey
  • INI::GetSectionID,INI::GetKeyID
  • INI::GetSectionName,INI::GetKeyName
  • INI::DumpINI
INI Specifications
INI files are simple text files usually with .ini extension which are composed of sections,keys and their values.There have been different standards for ini files over many years.eINI supports many INI Standards with a variety of options which can be toggled as per ones needs.One must follow these rules while manually creating or editing INI files so that the file makes sense to the eINI Parser.

Keys(properties)
The basic element contained in an INI File is a key(also known as property). Each key consists of a name and a value which is delimited by a '=' or an ':' sign depending on your settings('=' by default).
Code:
name=value

myinteger=123
myfloat=12.3
mystring=this is a string


By default, eINI treats all of the keys that are given below as equivalent.The leading spaces and the ending spaces of a key name are insignificant.The leading spaces are insignificant for a key value but terminal spaces are significant.These examples must make this clear.
Code:
example=123
example    =123
     example                =                    123
example = 123;
example = 123#Comments can be indicated by either using a '#' or a ';'
example = 123;Anything after a ';' or a '#' will be considered as a comment line
example = 123;Comments will not contribute to the value of the key

example = 123 ;
example = 123; These two keys are not equivalent since the previous key has a terminal space and this one doesn't


The name must be made up of alphanumeric characters.An underscore may be used.Spaces in the name aren't allowed by default but they can be enabled by defining INI_ENABLE_WHITESPACE before including this script.You can use almost any character(characters which cause ambiguity are not allowed such as '=') in the key name if you are running the processor in LIBERAL mode.

The following are invalid key definitions.
Code:
e$x%ample = 123 ;The key name has $ and % which are invalid characters until you are in LIBERAL mode
example key = 123 ;This key name has a space in it which isn't allowed by default
Sections
Keys can(but not compulsory) be grouped into arbitrarily named sections.The beginning of each section is indicated by enclosing the section name within square brackets.The keys that do not belong to any section(the keys that are defined before any section is defined) are termed as Global Keys.Global Keys belong to the global section.There is no explicit delimiter that indicates end of a section;the sections end at the declaration of the next section.

Code:
key1 = 123124 ;This is a global key
[SECTION_NAME]
key1= 123
key2 = 145 ;Section ends here
[ANOTHER_SECTION]
key1 = 234
key2 = 134
key3= 454
Here too, the leading and ending spaces in the section name are not significant.The following section declarations are identical
Code:
[SECTION]
[  SECTION  ]
[ SECTION] ;You can also have comments here too
Every section name must be made up of alphanumeric characters.An underscore can be used.Spaces aren't allowed by default but they can be enabled by defining INI_ENABLE_WHITESPACE before including this script.Any character(characters which cause ambiguity are not allowed such as ']') can be used in the section names if you are running the processor in LIBERAL mode.The following section declarations are invalid.
Code:
[SECT ION] ;The space isn't supposed to be there
[$ection] ; $ is not an alphanumeric character nor an underscore - allowed if you are in LIBERAL mode
[Section ;This is invalid because ']' character is missing;this can be disabled
[] ; Empty or Null Sections are not allowed
Comments
Comments can take their own line or can be used in key/section declarations as depicted in the above examples.Comment lines are indicated by beginning the line with a ';' or a '#'. Comment lines are ignored by the parser.

Code:
; this is a comment line - can write any gibberish crap here like asdasdas bdku asgdbasdb
#Hey! I am a comment line to!!
          ;The leading spaces don't matter
Blank Lines
You can have blank lines in the file.These lines will be ignored by the parser.These lines can be used to format the file and make it more readable to the human eye.

Code:
[Section1]
key1=23

[Section2] ;The previous line was a blank line and will be ignored
thekey=12324
Random Lines
Random Lines are the lines which make no sense to the parser.Such lines are not allowed until you are in LIBERAL mode where random lines are treated as comment lines.

Code:
$512341Dasd ;Parser says "WTF is this"
1238912y 39p8
1230 hihd asld.
Duplicate Names
Only one key with a particular name can exist within a section.Duplicate keys which are found later will give rise to a warning and will be ignored while reading(the first key with that name will be considered). This implies for section names also.

Case Sensitivity
Both case sensitive and non-case-sensitive parsing are supported.They can be toggled by defining INI_DISABLE_CASE_SENSITIVITY before including this script.

Escape Characters & Replacements
Escape Characters can be used in the key values.These are necessary because using a ; or # or any other special character in the value would cause problems.For example using ';' would indicate a comment and the rest of the value will be ignored.So to add a ';' in the value of a key, you must use '\;' which the parser will count as a character that is a part of the value.

There is a topic dedicated to Escape Characters & Replacements and everything will be discussed in detail in that section.

Getting Started & Configuration
To use eINI, you simply need to include header after defining all the configurable options.All the options or settings must be defined before including.Stating the options after including the header has no effect and the option will assume default value.

Code:
#define INI_ENABLE_WHITESPACE

#include <eINI>

#define INI_DISABLE_CASE_SENSITIVITY //Case Sensitivity won't be disabled since this line comes after the include
Here is a list of options or settings which eINI provides
INI_USE_LOG_FILE
SettingDefaultDescription
INI_USE_LOG_FILEBy default errors/warnings/notices are printed directly into the server consoleDefining will enable
INI_ENABLE_WHITESPACEBy default white-spaces are not allowedDefining will enable white-spaces in key and section names
INI_DISABLE_CASE_SENSITIVITYBy default names are case sensitiveDefining will disable case sensitivity
INI_DISABLE_WARNINGSAll warnings are printed in the server window by defaultDefining will disable all warning messages
INI_DISABLE_ERRORSAll errors are printed in the server window by defaultDefining will disable all error messages
INI_DISABLE_NOTICESAll notice messages are printed in the server window by defaultDefining will disable all notice messages
INI_LIBERAL_MODEDisabled by defaultDefining will enable LIBERAL mode
INI_ASSUME_FORMATTED_INIAssumes the worst case(poorly formatted) by defaultDefining will tell the parser to assume the ini to be formatted
INI_CAREFUL_MODEBy default the mistakes that are made by the programmer are taken care such as passing an invalid handleDefining will tell eINI that the programmer is perfect and won't make mistakes
INI_MAX_MULTI_FILESBy default it is set to 2Number of files that can be operated simultaneously
INI_MAX_LINESBy default it will be set to 128The maximum number of lines that an INI file can have
INI_MAX_SECTIONSBy default it will be set to 32Maximum number of sections that are allowed in an INI File
INI_MAX_KEYSBy default it will be set to the value of INI_MAX_LINESMaximum number of keys allowed in an INI File
INI_NAME_VALUE_DELIMITER'=' to by defaultKey Name-Value Delimiter(must be '=' or ':')
INI_ESCAPE_CHARACTER By default '\' will be the escape character starterYou don't get any option here, it has to be '\'
INI_MAX_LINE_LENGTHBy default it will be 256Maximum number of characters allowed per line
INI_MAX_FILE_NAME_LENGTH32 by defaultMaximum length of a file location
INI_MAX_SECTION_NAME_LENGTH32 by defaultMaximum number of characters allowed in a section name
INI_MAX_SECTION_NAME_LENGTH32 by defaultMaximum number of characters allowed in a section name
INI_MAX_KEY_NAME_LENGTH64 by defaultMaximum number of characters allowed in a key name
INI_MAX_KEY_VALUE_LENGTHINI_MAX_LINE_LENGTH by defaultMaximum number of characters allowed in a key value
INI_MAX_REPLACEMENT_TAG24 by defaultMaximum number of characters allowed in a replacement tag
INI_MAX_REPLACEMENT_TEXT(INI_MAX_KEY_VALUE_LENGTH-3) by defaultMaximum number of characters that are allowed in ReplacementText
INI_FLOATING_POINT_PRECISION16 by defaultMaximum number of characters required to store the largest and most precise float + 1
INI_INTEGER_DIGITS10 by defaultMaximum number of characters required to store the largest integer + 1
INI_HEX_DIGITS8 by defaultMaximum number of characters required to store the largest hexadecimal number + 1
INI_BIN_DIGITS33 by defaultMaximum number of characters required to store the longest binary number + 1
INI_MAX_FUNCTION_NAME_LENGTH32 by defaultLength of PAWN function identifiers(can be lesser than the maximum limit)
INI_WRITE_FALSE_VALUE"flase" by defaultString to be used in WriteBool as well as ReadBool for false
INI_WRITE_FALSE_VALUE_SIZE6 by defaultSize of INI_WRITE_FALSE_VALUE string
INI_WRITE_TRUE_VALUE32 by defaultString to be used in WriteBool as well as ReadBool for true
INI_WRITE_TRUE_VALUE_SIZE"true" by defaultSize of INI_WRITE_TRUE_VALUE string
To change a default setting just define it with value of your choice before including eINI.

Liberal Mode:
This mode liberalizes the INI standard allowing bad INI files to be parsed without issuing any errors.Enabling this mode only affects the parser.It will slightly improve the performance of the parser.

List of changes from default mode:
  • If white-spaces are not enabled then any section or key name containing space will be ignored instead of giving an error and halting the parser.You can enable whitespace along with LIBERAL Mode.
    Code:
    [SECTION ONE] ;This section declaration will be ignored and treated as if it wasn't there
    key on‌e = 123123 ; This line will be ignored
  • Empty sections, invalid sections, invalid keys, invalid lines will be ignored
    [code][] ;This line will be ignored
    $$$ ;This line will be ignored
  • Section or key names can now contain symbols such as $,%,&,etc.They can be made up of anything even non graphical characters.
    The following lines are valid:
    Code:
    [$ection]
    k$ey=123123
    a!b@c#d$e%f^g&h*i(j)k-l+=123123 ;The '=' will mean end of the key name
Assume Formatted Mode:
Tells the parser that the file is neatly formatted and it needn't do format checks.This will improve the efficiency of the parser by 30%-40% but decreases the versatility of the INI files.

In this mode the parser makes the following assumptions:
  • The INI File follows the INI Standard mentioned in INI Specificiations
  • No leading spaces before a section name
  • No whitespace are found in section or key names until its enabled
  • No terminal spaces in section or key names
  • Terminated Section Tags
  • Section and key names are valid
  • No random lines(i.e: a line which is not a key or a section or a comment or a blank line)
  • No warning will be given for empty keys

Example of a formatted INI:

Code:
key1=123123 ;No leading spaces
[SECTION] ;no leading spaces here too
key34=45356
key345=2342634
;Comment lines are still allowed

;Blank lines are also allowed
If INI files are not in the expected format when this mode is enabled then the parser will show some kind of undefined behavior.

Careful Mode:
This mode assumes that programmer is very careful.Tells the script to assume that no invalid handles or any such careless mistake will not happen.This will make negligible difference in performance of the script in this version.Just a useless feature right now in this version.

I strongly recommend this mode to be turned off since it is has negligible impact on the performance in the current release and humans are stupid and can never be perfect.

Opening/Closing Files & INI Handles
Just like a File Handle(File:file), eINI uses INI Handles(INI:ini).This is similar to the INI: tag used in y_ini.This is basically used to identify an INI File and also to distinguish between INI Handles,File Handles and normal variables.

To learn more about tags in PAWN, visit Scripting:tags

Creating an INI Handle is as simple as declaring a variable:
Code:
new INI:handle;
Every function that belongs to eINI needs to be prefixed with INI:: before calling.This work just like C++ Namespaces.

These are the basic functions:
Function Description
CreateINI Creates an INI file for writing
OpenINI Opens an INI File for reading or writing or both depending on the mode argument passed
CloseINI Saves the INI file and invalidates the INI Handle
IsValidHandle Returns true if the handle is valid else false
CreateINI
Definition:INI::CreateINI(const fname)
Parameters:fname takes the location along with the filename that is to be created
Returns:INI Handle (with INI:) for the newly created file or an error code
Remarks:The file is not physically created until CloseINI is called

Exceptions:
INI_ERR_FILE_ALREADY_EXISTS - The file already exists
INI_ERR_MAX_FILE_LIMIT - Maximum simultaneously operable files limit has been reached

Code:
new INI:handle = INI::CreateINI("config \\mysql.ini");
OpenINI
Definition:INI::OpenINI(const fname,mode=INI_READ_WRITE)
Parameters:
  • fname takes the location along with the filename that is to be opened
  • mode can take INI_READ_WRITE/INI_READ/INI_WRITE
Returns:INI Handle (with INI:) for the opened file or an error code
Remarks:Use the mode parameter to enhance performance

Exceptions:
INI_ERR_FILE_DOES_NOT_EXIST - The file doesn't exist
INI_ERR_MAX_FILE_LIMIT - Maximum simultaneously operable files limit has been reached

Code:
new INI:handle = INI::OpenINI("config \\mysql.ini");
Why use mode parameter?
Suppose you are only writing to the file then do you think the parser needs to store the value of every key?
The answer is no because we won't need the values.So by setting the mode to INI_WRITE we tell the parser that we are only writing so parse only key and section names.Will improve performance to a great extent for large files.

Suppose you are only reading the file then do you think it is necessary to save the file?
The answer is no because you won't be making any changes to the file.

CloseINI
Definition:INI::CloseINI(INI:filehandle,bool:savebuffer=true)
Parameters:
  • filehandle takes the INI handle which is to be closed
  • savebuffer should be set to false if you do not want CloseINI to save the buffer to the file
Returns:0 for normal execution or an error code
Remarks:The file won't be saved and you will lose an INI Handle if CloseINI is not called

Exceptions:
INI_ERR_INVALID_HANDLE - An invalid handle was passed to CloseINI
INI_ERR_PARSING_FAILED - The file couldn't be parsed.This would only happen if the file was opened, not used and there is a syntax error in the file.

Code:
INI::CloseINI(handle); 
INI::CloseINI(handle,false);
IsValidHandle
Definition:INI::IsValidHandle(INI:handle)
Parameters:INI Handle that has to be checked for validity
Returns:True if the given INI Handle is valid else false
Remarks:Primarily used to check if OpenINI or CreateINI was successful

[code]new INI:handle = INI::OpenINI("sql.ini");
if(INI::IsValidHandle(handle))
{
//Safe to use the handle
}
else print("Couldn't load sql configuration");
[/code

eINI Log File
By default, eINI prints all warnings/errors/notices directly into the server console. You can enable logging using file by defining INI_USE_LOG_FILE before including eINI.

The log file is named as "eini_log.txt". You can find the log file in scriptfiles folder.

How the parser works(Advanced & Optional)
The parser checks each and every line and stores the information regarding the line in an user-defined enumerator array.It uses linked lists to the store the lines.Once the parser identifies the type of the line, it creates a key or a section element in an user-defined enumerator array of keys or sections respectively.The keys are also stored in linked lists.Each section and key is given an id based on the segment-offset method.

Segment-Offset Method:
A segment is an index or an address which indicates the start of a region of memory and offset is also an index or an address which tells how far the variable from the segment is situated in the memory.

If you have had a glimpse through the include, you would have probably noticed these
Code:
static stock INI_Line[INI_MAX_MULTI_FILES*INI_MAX_LINES][E_INI_LINE];
static stock INI_Section[INI_MAX_MULTI_FILES*INI_MAX_SECTIONS][E_INI_SECTION];
static stock INI_Key[INI_MAX_MULTI_FILES*INI_MAX_KEYS][E_INI_KEY];
Let's investigate INI_Key.The number of elements with INI_Key is INI_MAX_MULTI_FILES*INI_MAX_KEYS.This variable 'INI_Key' stores the Keys for all the keys of different files.Each file gets its segment and each key gets an offset.The indexes that belong to the first file would be from 0 to INI_MAX_KEYS and of the second file would be INI_MAX_KEYS to INI_MAX_KEYS*2 and so on...

For nth file, INI_MAX_KEYS*(n-1) to INI_MAX_KEYS*n belongs to the nth INI Handle.

Now to access a key of the file, we would need an offset.The offset indicates how far away from the segment the key is.

Lets take an example:
Code:
[SECTION1]
key1=123
key2=4534
[SECTION2]
key3=23423
.
.
.
Lets assume that this was the second file that was opened and has been assigned the INI Handle 2.So this handle would own the keys with index starting from INI_MAX_KEYS to INI_MAX_KEYS*2.So its starting index of the segment would be INI_MAX_LINES.The key one(i.e:"key1") gets its absolute index as INI_MAX_KEYS and offset as 0, the second key(i.e:"key2") gets an absolute index as INI_MAX_KEYSS+1, an offset of 1, third key(i.e:"key3") gets an absolute index as INI_MAX_KEYS+2 and offset as 2 and so on.All of these keys have the segment index as INI_MAX_KEYS.

This is how eINI assigns key ids.

Now to get the name of the key of key 'n' of this file, we use the following formula
Code:
INI_Key[segment + offset][E_INI_KEY_name];
INI_Key[INI_MAX_KEYS + n][E_INI_KEY_name]

INI_Key[INI_MAX_KEYS + 2][E_INI_KEY_name] //Gets the name of key3
I hope that now you have a fair idea about how indexing(giving ids) in eINI works.

So we would come across two terms while using eINI namely relative keyid/sectionid and absolute keyid/sectionid.
This is exactly same as segment and offset.

The parser assigns IDs linearly.The first key of the file gets offset 0,second gets offset 1 and so on.Similarly the first section gets an offset of 1, second gets an offset of 2 and so on.Where did the offset 0 go?Its reserved for global section irrespective if there is any global key or not(global keys could be added later).

Why do we need to know this?
You can exploit the way the parser assigns IDs linearly to improve the performance of the script.Instead of asking eINI to search and find the section or the key, you could directly tell the Read or Write functions the keyids and sectionids knowing the file already which would improve the performance to a large extent(we would avoid so many strcmps for finding sections and keys). We'll see more examples later in the Reading and Writing Sections.

Example:
Code:
key1=asd
[SEC1]
key1=asdasd
key2=34234
[SEC2]
a=123
b=234 ;some gibberish..asdasd.sd.ad.as.da.sd.sad
c=345
[SEC3]
[SEC4]
note=the previous section was empty ;random comment
Relative Key ID Assignments:
key1 = 0 (Global Key, therefore has a sectionid 0)
key1 = 1(key1 of SEC1)
key2 = 2
a = 3
b= 4
c = 5

Relative Section ID Assignments:
Global Section = 0 (irrespective of if there is any element or not)
SEC1 = 1
SEC2 = 2
SEC3 = 3
SEC4 = 4

Reading
eINI supports reading by calling reading functions individually as well as dynamic reading/loading(which is similar to y_ini).We will look into both of them separately.

Static Loading
eINI provides functions to read strings,integers,floats,hexadecimal numbers,binary numbers,arrays,enumerators.It also provides lazy programmers with a function which can be used to read multiple keys simultaneously at the cost efficiency.

These are the functions that can be used to obtain values of the keys.
Function Description
ReadString Gets the value of a key as a string
ReadBool Used to read keys with Boolean values
ReadInteger Gets the value of a key as an integer
ReadFloat Gets the value of a key has a floating point number
ReadHex Reads a value in hexadecimal format and gets an integer equivalent for it
ReadBinary Reads a value in binary format and gets an integer equivalent for it
ReadArray Reads an array
ReadEnum Reads an enum(fills the whole enum with data)
ReadFormat For lazy programmers who want to read multiple keys in one go
ReadString
Gets the value of a key as a string.

Definition:INI::ReadString(INI:filehandle,result[],const key[],const section[]="",keyid=-1,sectionid=-1,result_size=sizeof(result),section_size=sizeof(s ection),key_size=sizeof(key))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • result is the array where the read string has to be stored
  • key is the name of the key
  • section is the name of the section where the key has to be searched
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • result_size is the size of the result parameter
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or an error code
Remarks:Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.

Exceptions:
INI_KEY_NOT_FOUND - The key whose value was requested was not found in the file
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_ERR_PARSING_FAILED - The parsing of the file failed

Code:
new password[64];
INI::ReadString(handle,password,"pass","login_cred"); //Searches for pass in login_cred
INI::ReadString(handle,password,"pass"); //Searches for pass in the global section
INI::ReadString(handle,password,"pass","",-1,sectionid); //Searches for pass in section with id sectionid
INI::ReadString(handle,password,"","",1); //Gets the value of key with keyid 1
ReadBool
This function interprets the value of the given key and tells the Boolean value associated with it.If the value is equal to '1' or 'true' then the variable parameter will be set to true.If the value is equal to '0' or 'false' then the variable parameter is set to false.

Definition:INI::ReadBool(INI:filehandle,&bool:variable,const key[]="",const section[]="",keyid=-1,sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • variable is the boolean variable where the result has to be stored
  • key is the name of the key
  • section is the name of the section where the key has to be searched
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or an error code
Remarks:Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.

Exceptions:
INI_KEY_NOT_FOUND - The key whose value was requested was not found in the file
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_ERR_PARSING_FAILED - The parsing of the file failed
INI_ERR_INVALID_BOOL - The value cannot be interpreted (value is not acceptable)

Code:
new bool:rcon_password_enabled;
INI::ReadBool(handle,rcon_password_enabled,"ispass","login_cred"); //Searches for ispass in login_cred
INI::ReadBool(handle,rcon_password_enabled,"ispass"); //Searches for ispass in the global section
INI::ReadBool(handle,rcon_password_enabled,"ispass","",-1,sectionid); //Searches for ispass in section with id sectionid
INI::ReadBool(handle,rcon_password_enabled,"","",1); //Gets the value of key with keyid 1
Example:
Assume that we are working on this file
Code:
[SECTION1]
key1=true
key2=false
key3=1
key4=0
key5=not a bool
If we use ReadBool on all the keys, these will be the results:
ReadBool will set variable to true when key1 is read
ReadBool will set variable to false when key2 is read
ReadBool will set variable to true when key3 is read
ReadBool will set variable to false when key4 is read
ReadBool will not touch the variable and will return that it is an invalid bool

ReadInteger
Gets the integral value of a key

Definition:INI::ReadInteger(INI:filehandle,&variable,const key[]="",const section[]="",keyid=-1,sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • variable is the variable where the result has to be stored
  • key is the name of the key
  • section is the name of the section where the key has to be searched
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or an error code
Remarks:
  • Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.
  • variable will be set to zero if the value associated with the key is not numeric
Exceptions:
INI_KEY_NOT_FOUND - The key whose value was requested was not found in the file
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_ERR_PARSING_FAILED - The parsing of the file failed

Code:
new var;
INI::ReadInteger(handle,var,"int","nums"); //Searches for int in nums
INI::ReadInteger(handle,var,"int"); //Searches for int in the global section
INI::ReadInteger(handle,var,"int","",-1,sectionid); //Searches for int in section with id sectionid
INI::ReadInteger(handle,var,"","",1); //Gets the value of key with keyid 1
ReadFloat
Gets a floating point number from the key

Definition:INI::ReadFloat(INI:filehandle,&Float:variable,cons t key[]="",const section[]="",keyid=-1,sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • variable is the variable where the result has to be stored
  • key is the name of the key
  • section is the name of the section where the key has to be searched
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or an error code
Remarks:
  • Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.
  • Some precision will be lost while the key value which is read as string is converted to a float
Exceptions:
INI_KEY_NOT_FOUND - The key whose value was requested was not found in the file
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_ERR_PARSING_FAILED - The parsing of the file failed

Code:
new var;
INI::ReadFloat(handle,var,"float","nums"); //Searches for float in nums
INI::ReadFloat(handle,var,"float"); //Searches for float in the global section
INI::ReadFloat(handle,var,"float","",-1,sectionid); //Searches for float in section with id sectionid
INI::ReadFloat(handle,var,"","",1); //Gets the value of key with keyid 1
ReadHex
Gets the integral value of a key where the value is expressed in hexadecimal notation

Definition:INI::ReadHex(INI:filehandle,&variable,const key[]="",const section[]="",keyid=-1,sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • variable is the variable where the result has to be stored
  • key is the name of the key
  • section is the name of the section where the key has to be searched
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or an error code
Remarks:
  • Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.
  • variable will be set to the integral value of the hex value until an unknown hex digit is encountered or end of the value
Exceptions:
INI_KEY_NOT_FOUND - The key whose value was requested was not found in the file
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_ERR_PARSING_FAILED - The parsing of the file failed

Code:
new var;
INI::ReadHex(handle,var,"inth","nums"); //Searches for inth in nums
INI::ReadHex(handle,var,"int"); //Searches for inth in the global section
INI::ReadHex(handle,var,"int","",-1,sectionid); //Searches for inth in section with id sectionid
INI::ReadHex(handle,var,"","",1); //Gets the value of key with keyid 1
ReadBinary
Gets the integral value of a key where the value is expressed in binary notation

Definition:INI::ReadBinary(INI:filehandle,&variable,const key[]="",const section[]="",keyid=-1,sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • variable is the variable where the result has to be stored
  • key is the name of the key
  • section is the name of the section where the key has to be searched
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or an error code
Remarks:
  • Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.
  • variable will be set to the integral value of the hex value until an unknown binary digit is encountered or end of the value
Exceptions:
INI_KEY_NOT_FOUND - The key whose value was requested was not found in the file
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_ERR_PARSING_FAILED - The parsing of the file failed

Code:
new var;
INI::ReadBinary(handle,var,"intb","nums"); //Searches for intb in nums
INI::ReadBinary(handle,var,"intb"); //Searches for intb in the global section
INI::ReadBinary(handle,var,"intb","",-1,sectionid); //Searches for intb in section with id sectionid
INI::ReadBinary(handle,var,"","",1); //Gets the value of key with keyid 1
ReadArray
Parses an array key and fills the given array with the correct values.

Definition:INI::ReadArray(INI:filehandle,array[],const key[]="",const section[]="",keyid=-1,sectionid=-1,array_size=sizeof(array),section_size=sizeof(sec tion),key_size=sizeof(key))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • array where the value has to be stored
  • key is the name of the key
  • section is the name of the section where the key has to be searched
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • array_size is the size of the section parameter
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or an error code
Remarks:
  • Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.
  • Filling of the array will stop if an exception occurs
Exceptions:
INI_KEY_NOT_FOUND - The key whose value was requested was not found in the file
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_ERR_PARSING_FAILED - The parsing of the file failed

Code:
new var[5];
INI::ReadArray(handle,var,"arr","nums"); //Searches for arr in nums
INI::ReadArray(handle,var,"arr"); //Searches for arr in the global section
INI::ReadArray(handle,var,"arr","",-1,sectionid); //Searches for arr in section with id sectionid
INI::ReadArray(handle,var,"","",1); //Gets the value of key with keyid 1
ReadEnum
Parses an enum key and loads an enum array.

Definition:INI::ReadEnum(INI:filehandle,enum_array[],enum_unit_size,const key[]="",const section[]="",keyid=-1,sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • array where the value has to be stored
  • enum_unit_size is the size of the enum
  • key is the name of the key
  • section is the name of the section where the key has to be searched
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or an error code
Remarks:
  • Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.
  • Filling of the array will stop if an exception occurs
Exceptions:
INI_KEY_NOT_FOUND - The key whose value was requested was not found in the file
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_ERR_PARSING_FAILED - The parsing of the file failed

Code:
new var[5][ENUM];
INI::ReadEnum(handle,var[0],sizeof(var[]),"arr","nums"); //Searches for arr in nums
INI::ReadEnum(handle,var[1],sizeof(var[]),"arr"); //Searches for arr in the global section
INI::ReadEnum(handle,var[2],sizeof(var[]),"arr","",-1,sectionid); //Searches for arr in section with id sectionid
INI::ReadEnum(handle,var[3],sizeof(var[]),"","",1); //Gets the value of key with keyid 1
ReadFormat
Read multiple keys in one line at the cost of efficiency.

Definition:INI::ReadFormat(INI:filehandle,sectionid,const format[],{Float,_}:...)
Parameters:
  • filehandle takes the INI Handle on which to operate
  • sectionid takes the relative section id
  • format must give the type of data of the section in key order
  • key1,result1,key2,result2....
Returns: 0 always
Remarks:
  • This function is very slow, so try to avoid using this function
List of valid specifiers:
SpecifierSymbolData Type
Integer Data Typed or iCalls ReadInteger to get the integral value
String Data TypesCalls ReadString directly
Float Data TypefCalls ReadFloat to get the value of the key
Binary Data TypebCalls ReadBinary to parse the key
Hexadecimal Data TypeX or xCalls ReadHex to parse the key
Boolean Data TypeT or FCalls ReadBool to parse the key
NOTE:Using an invalid specifier will stop the reading process.

Code:
;Example INI
[SECTION1]
a=5.4
b=str
c=0xFF
d=234234
Code:
new var1[10],Float:var2,var3,var4;
INI::ReadFormat(handle,1,"fsxi","a",var2,"b",var1,"c",var3,"d",var4);
Dynamic Loading using ParseINI

Dynamic Loading is the other method to read keys.This system is similar to y_ini.The parser calls a function each time a key is parsed. There are different ways of dynamic loading which will be explained in this section. Dynamic Loading also provides an option to broadcast data across all scripts which means you can share the contents of the INI file with different scripts without having to parse the file again in that script.

ParseINI
Parses the INI File and caches keys and sections

Definition:INI::ParseINI(INI:filehandle,const LoadFunction[] = "",bool:dynamic=false,extra=0,bool:pass_extra=fals e,bool:func_with_key=false);
Parameters:
  • filehandle is the INI Handle which should be parsed
  • LoadFunction is the function name which should be called for dynamic loading
  • dynamic should be set to true for Dynamic Loading else false for just parsing
  • extra is the extra information that has to be passed to the Load Function
  • pass_extra tells if the extra parameter is used
  • func_with_key If false,first occurrence of %s in LoadFunction will be replaced with section name only
    If true,the first two occurrences of %s in LoadFunction will be replaced with section
    name followed by key name respectively
  • tradition_func If true the section name and key name will be passed as arguments to the LoadFunction. The LoadFunction will be called as it is without any modifications. (false by default)
  • broadcast If true the data will be sent to all running scripts.If set to false, only the local script
    callbacks will be called. (false by deafult)
Returns:
Returns 0 for normal execution
It also returns 0 if file was not meant to be parsed(in case of a new file)
Or an error code

Exceptions:
INI_ERR_INVALID_HANDLE - Invalid File Handle
INI_ERR_SYNTAX - The INI file does not meet the required format

Code:
INI::ParseINI(myhandle); //Normal Parsing
INI::ParseINI(myhandle,"Load_%s",true); //Parsing with dynamic loading.The %s will be replaced with the section name
INI::ParseINI(myhandle,"Load_%s",true,playerid,true); //Parsing with dynamic loading with extra parameter
INI::ParseINI(myhandle,"Load_%s_%s",true,random_number,false,true); //Parsing with dynamic loading.The %s will be replaced with section and key name
INI::ParseINI(myhandle,"Load_%s_%s",true,playerid,true,true); //Parsing with dynamic loading with extra paramter
INI::ParseINI(myhandle,"LoadFunction",true,playerid,true,false,true); //Parsing with traditional dynamic loading with extra paramter
INI::ParseINI(myhandle,"LoadFunction",true,playerid,true,false,true,true); //Parsing with traditional dynamic loading and broadcast across all scripts
Load Function must be passed with a '%s' specifier where you want the parser to add the Section Name before calling, i.e: if Load Function is "Load_func_%s" will be changed to "Load_func_SECTION_NAME" during parsing.The keys in the global section will call the callback with ""(i.e:Nothing will be substituted) as section name.

To understand better, lets take an example.Let the text given below be our example INI File.
Code:
key=234567
[SECTION1]
asd=23
eqwe=123
eqwaxe=88
[SECTION2]
asd=2
iii=66
Lets assume that the "MyFunc_%s" is passed to ParseINI as LoadFunction parameter.
The Load Function will be called 6 times as there are 6 keys.

To read all the keys, we would need a total of 3 functions.
Code:
//If you are not using the extra parameter
public MyFunc_(const key[],const value[]) //For global keys
{
       if(!strcmp(key,"key"))
             MyVar=strval(value);
}
public MyFunc_SECTION1(const key[],const value[]) //Called three times 
{
      if(!strcmp(key,"asd"))
             MyVar=strval(value);
}
public MyFunc_SECTION2(const key[],const value[]) //Called two times
{
     //Do whatever you want with the key
} 

//If you are using the extra parameter
public MyFunc_(const key[],const value[],extra); //For global keys
public MyFunc_SECTION1(const key[],const value[],extra); //Called for asd,eqwe,eqwaxe
public MyFunc_SECTION2(const key[],const value[],extra); //Called for asd,iii
The returns from the Load Function are not handled by the parser.The key and value will have the name of the key and its value respectively.

If you are using func_with_key then the second occurrence of '%s' will be replaced with the key name.For example, if "MyFunc_%s_%s" was passed to ParseINI as Argument then "MyFunc_SECTION_KEY" will be called for each key.

Traditional way of dynamic reading passes the key and the section name as arguments to the Load Function.

Code:
public LoadFunction(const key[],const section[],const value[]);
By default the information read from the INI is not broadcasted across all scripts. You can enable broadcasting by setting the broadcast parameter to true. By enabling broadcast, the LoadFunction will be called in every running script.

Escape Characters & Replacements
The escape characters present in a string in an ini file are not replaced when it is read by the server.So you'll have to do it manually.But eINI makes your work easier by providing ready-made functions which will do the replacement of escape characters for you.

Lets look at an example to understand what I mean:
Code:
[SAMP]
samp=This is SA-MP\\0.3.7\nDownload at sa-mp.com
If you read this string and then print it in your server console, you'll see this
"This is SA-MP\\0.3.7\nDownload at sa-mp.com"

You won't get the expected output, i.e:
"This is SA-MP\0.3.7
Download at sa-mp.com"

You won't get that output because '\n' or any other escape sequences are not replaced with their appropriate ASCII Value.

This can be easily fixed with the help of Replace Function provided by eINI.

Replace
Replaces escape characters with their real ASCII Value.

Definition:INI::Replace(const src[],dest[],const ReplacementFunction[]="",extra=0,bool:pass_extra=false,sz=sizeof(src),s z_dest=sizeof(dest),sz_rf=sizeof(ReplacementFuncti on))
Parameters:
  • src takes the source string
  • dest is the array where the result has to be stored
  • ReplacementFunction is the function name
  • extra is the extra information that has to be passed to the replacement function
  • pass_extra tells if the extra parameter is used
  • sz is the size of the source string
  • sz_dest is the size of the destination string
  • sz_rf is the size of the replacement function string
Returns:Returns 0 always

You cannot directly use ';' or '#' or characters that are sensitive to the parser directly.Instead you must use the appropriate escape character.

List of valid escape characters:
NameEscape CharacterData Type
Backward Slash\\Replaces '\\' with a single slash
Null\0Adds a null character when '\0' is encountered
Tab\tAdds a tab space
Carriage Return\rAdds a carriage reuturn
New Line\nAdds a new line character
Semi-colon\;Replaces '\;' with ';'
Hash\#Replaces '\#' with '#'Square Brackets\[ or \]Replaces '\[' or '\]' with '[' and ']' respectively
Code:
new res[128];
INI::Replace("This a \n TEST LINE slash \\ SEMI \;",res);
Custom Replacements:
Replace has another amazing feature that allows to have your own escape strings.All custom escape sequences must be enclosed within [THE ESCAPE SEQUENCE NAME]. The function will parse the line and call your Replacement Function where you'll decide what to substitute(the string set using SetReplacementText) in place of that escape sequence.

Lets take an example to understand better:

Code:
str = "Password must have [MAX] to [MIN] characters"
Replace(str,dest,"MyFunc");

public MyFunc(const text[])
{
    if(!strcmp(text,"MAX"))
    { 
         new str[] = "32";
         INI::SetReplacementText(str); 
         return 1;
    }
    if(!strcmp(text,"MIN"))
    { 
         new str[] = "5";
         INI::SetReplacementText(str);
         return 1;
    }
    return 0;
}
Now the array dest will have
"Password must have 20 to 5 characters"

What you return in the ReplacementFunction matters.The replacement will be carried out only if your Replacement Function returns a non-zero integer.Returning 0 means that eINI won't carry out the replacement and will replace it with "[]".

SetReplacementText
Will set the replacement text

Definition:INI::SetReplacementText(const str[])
Parameters:
  • str takes the string
Returns: true on success,false on failure

Code:
new str[] = "replace text";
INI::SetReplacementText(str);
INI::SetReplacementText("text"); //This is not allowed
Extra Parameter:
The extra parameter is passed to the replacement function and it optional.
Code:
public MyFunc(extra,const text[])
To use this extra parameter you must enable the extra parameter and pass the extra value to the Replace Function which will in turn pass it to the Replacement Function.

Code:
Replace(str,dest,"MyFunc",playerid,true);
Writing
eINI provides lots of different methods to write keys to files efficiently.It stores all the new values in a buffer and writes them all at once instead of having to open a file every time to write something.

These are the functions that eINI provides for writing data to files.
Function Description
WriteString Writes a string to the file
WriteBool Writes a boolean value
WriteInteger Writes an integer value
WriteFloat Writes a floating point number value
WriteHex Writes an integer in hexadecimal notation
WriteBinary Writes an integer in binary notation
WriteArray Writes an array
WriteEnum Writs an enum unit
WriteFormat For lazy programmers who want to write multiple keys in one go
WriteString
Writes a string

Definition:INI::WriteString(INI:filehandle,const data[],const key[],const section[],keyid=-1,sectionid=-1,data_size=sizeof(data),section_size=sizeof(secti on),key_size=sizeof(key))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • data is the string that is to be saved
  • key is the name of the key
  • section is the name of the section where the key resides.
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • data_size is the size of the result parameter
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or the keyid of the newly created key or an error code
Remarks:Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.

Exceptions:
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_KEY_NOT_FOUND - Key with the given keyid doesn't exist
INI_ERR_PARSING_FAILED - Parsing failed

Code:
INI::WriteString(handle,"this is not my password","pass","login_cred"); //Searches for pass in login_cred,if not found it will be created 
INI::WriteString(handle,"this is not my password","pass"); //Searches for pass in the global section if not found,it will be created
INI::WriteString(handle,"this is not my password","pass","",-1,sectionid); //Searches for pass in section with id sectionid, if not found it will be created
INI::WriteString(handle,"this is not my password","","",1); //Writes the data to the key with keyid 1
WriteBool
Checks for falsity of the boolean variable passed and writes its equivalent to the key.

Definition:INI::WriteBool(INI:filehandle,bool:variable,const key[],const section[],keyid=-1,sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • variable is the boolean variable
  • key is the name of the key
  • section is the name of the section where the key resides
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or the keyid of the newly created key or an error code
Remarks:Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.

Exceptions:
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_KEY_NOT_FOUND - Key with the given keyid doesn't exist
INI_ERR_PARSING_FAILED - Parsing failed

Code:
INI::WriteBool(handle,rcon_password_enabled,"ispass","login_cred"); //Searches for ispass in login_cred, will create the key if not found
INI::WriteBool(handle,rcon_password_enabled,"ispass"); //Searches for ispass in the global section,will create the key if not found
INI::WriteBool(handle,rcon_password_enabled,"ispass","",-1,sectionid); //Searches for ispass in section with id sectionid,will create the key if not found
INI::WriteBool(handle,rcon_password_enabled,"","",1); //Write the value to the key with id keyid
WriteInteger
Writes an integer
Definition:INI::WriteInteger(INI:filehandle,variable,const key[],const section[],keyid=-1,sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • variable is the integer that has to be saved
  • key is the name of the key
  • section is the name of the section where the key resides
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or the keyid of the newly created key or an error code
Remarks:Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.

Exceptions:
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_KEY_NOT_FOUND - Key with the given keyid doesn't exist
INI_ERR_PARSING_FAILED - Parsing failed

Code:
INI::WriteInteger(handle,var,"int","nums"); //Searches for int in nums, will create the key if it doesn't exist
INI::WriteInteger(handle,var,"int"); //Searches for int in the global section, will create the key if it doesn't exist
INI::WriteInteger(handle,var,"int","",-1,sectionid); //Searches for int in section with id sectionid, will create the key if it doesn't exist
INI::WriteInteger(handle,var,"","",1); //Writes the value to the key with keyid 1
WriteFloat
Writs a float to the key

Definition:INI::WriteFloat(INI:filehandle,Float:variable,cons t key[],const section[],keyid=-1,sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • variable is the where the float to be saved is stored
  • key is the name of the key
  • section is the name of the section where the key resides
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or the keyid of the newly created key or an error code
Remarks:Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.

Exceptions:
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_KEY_NOT_FOUND - Key with the given keyid doesn't exist
INI_ERR_PARSING_FAILED - Parsing failed
Code:
INI::WriteFloat(handle,var,"float","nums"); //Searches for float in nums, will create the key if it doesn't exist
INI::WriteFloat(handle,var,"float"); //Searches for float in the global section, will create the key if it doesn't exist
INI::WriteFloat(handle,var,"float","",-1,sectionid); //Searches for float in section with id sectionid, will create the key if it doesn't exist
INI::WriteFloat(handle,var,"","",1); //Writes the value to the key with keyid 1
WriteHex
Writs an integer in hexadecimal notation

Definition:INI::WriteHex(INI:filehandle,variable,const key[],const section[],keyid=-1,sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ));
Parameters:
  • filehandle takes the INI Handle on which to operate
  • variable is the integer that has to be saved in hexadecimal notation
  • key is the name of the key
  • section is the name of the section where the key resides
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or the keyid of the newly created key or an error code
Remarks:Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.

Exceptions:
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_KEY_NOT_FOUND - Key with the given keyid doesn't exist
INI_ERR_PARSING_FAILED - Parsing failed

Code:
new var = 123213;
INI::WriteHex(handle,var,"inth","nums"); //Searches for inth in nums, will create the key if it doesn't exist
INI::WriteHex(handle,var,"int"); //Searches for inth in the global section, will create the key if it doesn't exist
INI::WriteHex(handle,var,"int","",-1,sectionid); //Searches for inth in section with id sectionid, will create the key if it doesn't exist
INI::WriteHex(handle,var,"","",1); //Writes the value to the key with keyid 1
WriteBinary
Writes an integer value to a key in binary form

Definition:INI::WriteBinary(INI:filehandle,variable,const key[],const section[],keyid=-1,sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • variable is the integer that has to be saved in binary form
  • key is the name of the key
  • section is the name of the section where the key resides
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or the keyid of the newly created key or an error code
Remarks:Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.

Exceptions:
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_KEY_NOT_FOUND - Key with the given keyid doesn't exist
INI_ERR_PARSING_FAILED - Parsing failed

Code:
new var = 123123;
INI::WriteBinary(handle,var,"intb","nums"); //Searches for intb in nums, will create the key if it doesn't exist
INI::WriteBinary(handle,var,"intb"); //Searches for intb in the global section, will create the key if it doesn't exist
INI::WriteBinary(handle,var,"intb","",-1,sectionid); //Searches for intb in section with id sectionid, will create the key if it doesn't exist
INI::WriteBinary(handle,var,"","",1); //Writes the value to the key with keyid 1
WritesArray
Writes an array

Definition:INI::WriteArray(INI:filehandle,array[],const key[]="",const section[]="",keyid=-1,sectionid=-1,array_size=sizeof(array),section_size=sizeof(sec tion),key_size=sizeof(key))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • array is the array which will be saved
  • key is the name of the key
  • section is the name of the section where the key resides
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • array_size is the size of the section parameter
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or the keyid of the newly created key or an error code
Remarks:Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.

Exceptions:
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_KEY_NOT_FOUND - Key with the given keyid doesn't exist
INI_ERR_PARSING_FAILED - Parsing failed

Code:
new var[5] = {1,2,3,4,5};
INI::WriteArray(handle,var,"arr","nums"); //Searches for arr in nums, will create the key if it doesn't exist
INI::WriteArray(handle,var,"arr"); //Searches for arr in the global section, will create the key if it doesn't exist
INI::WriteArray(handle,var,"arr","",-1,sectionid); //Searches for arr in section with id sectionid, will create the key if it doesn't exist
INI::ReadArray(handle,var,"","",1); //Writes the value to the key with keyid 1
WriteEnum
Writes an enum element to the file

Definition:INI::WriteEnum(INI:filehandle,enum_array[],enum_unit_size,const key[]="",const section[]="",keyid=-1,sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • enum_array whose data has to be saved
  • enum_unit_size is the size of the enum
  • key is the name of the key
  • section is the name of the section where the key resides
  • keyid is the relative key id if it is known
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns keyid(relative) if the key is found or the keyid of the newly created key or an error code
Remarks:Use keyid parameter when ever possible or at least sectionid parameter if known to improve performance.

Exceptions:
INI_ERR_INVALID_HANDLE - The INI Handle passed is invalid
INI_KEY_NOT_FOUND - Key with the given keyid doesn't exist
INI_ERR_PARSING_FAILED - Parsing failed

Code:
//new var[MAX_PLAYERS][P_ENUM];
INI::WriteEnum(handle,var[0],sizeof(var[]),"arr","nums"); //Searches for arr in nums, will create the key if it doesn't exist
INI::WriteEnum(handle,var[1],sizeof(var[]),"arr"); //Searches for arr in the global section, will create the key if it doesn't exist
INI::WriteEnum(handle,var[2],sizeof(var[]),"arr","",-1,sectionid); //Searches for arr in section with id sectionid, will create the key if it doesn't exist
INI::WriteEnum(handle,var[3],sizeof(var[]),"","",1); //Gets the value of key with keyid 1
WriteFormat
Write multiple keys in one line at the cost of efficiency.

Definition:INI::WriteFormat(INI:filehandle,sectionid,const format[],{Float,_}:...)
Parameters:
  • filehandle takes the INI Handle on which to operate
  • sectionid takes the relative section id
  • format must give the type of data of the section in key order
  • data1,key1,data2,key2,....
Returns: 0 always
Remarks:
  • This function is very slow, so try to avoid using this function
List of valid specifiers:
SpecifierSymbolData Type
Integer Data Typed or iCalls WriteInteger to save
String Data TypesCalls WriteString to save
Float Data TypefCalls WriteFloat to save
Binary Data TypebCalls WriteBinary to save the key
Hexadecimal Data TypeX or xCalls WriteHex to save the key
Boolean Data TypeT or FCalls WriteBool to save the key
NOTE:Using an invalid specifier will stop the writing process.

Code:
;Example INI
[SECTION1]
a=5.4
b=str
c=0xFF
Code:
INI::WriteFormat(handle,1,"fsxi",2.5,"a","Awesome","b",15,"c",23123,"d");
Code:
;Resultant INI
[SECTION1]
a=2.5
b=Awesome
c=0xF
d=23123 ;created this just now
Miscellaneous Functions
eINI has some more functions which will be discussed here.

List of Miscellaneous Functions:
Function Description
DeleteSection Delete an entire section
DeleteKey Delete a key
GetSectionID Get relative section ID from section name
GetKeyID Get relative key ID from key name
GetSectionName Get Section Name from relative section id
GetKeyName Get Key Name from relative key id
WriteBuffer Saves the buffer to the file
DumpINI Dumps the contents of a file in the Server Window
DeleteSection
Delete an entire section

Definition:INI::DeleteSection(INI:filehandle,const section[]="",sectionid=-1,section_size=sizeof(section))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • section is the name of the section that should be deleted
  • sectionid is the relative section id if it is known
  • section_size is the size of the section parameter
Returns:Returns 0 on success or an error code

Exceptions:
INI_ERR_INVALID_HANDLE - Invalid INI Handle was passed to the function
INI_SECTION_NOT_FOUND - Section does not exist
INI_ERR_INVALID_ID - Invalid Section ID

Code:
new var = 123123;
INI::DeleteSection(handle,"DELETEME"); //Delete DELETEME
INI::DeleteSection(INI:filehandle,"",2); //Delete Section with section id 2
DeleteKey
Deletes a key

Definition:INI::DeleteKey(INI:filehandle,const key[],const section[]="",keyid=-1,sectionid=-1,key_size=sizeof(key),section_size=sizeof(section ));
Parameters:
  • filehandle takes the INI Handle on which to operate
  • key is the name of the key that has to be deleted
  • section is the name of the section where the key resides
  • keyid is the relative key id if it is know
  • sectionid is the relative section id if it is known
  • key_size is the size of the key parameter
  • section_size is the size of the section parameter
Returns:Returns 0 on success or an error code

Exceptions:
INI_ERR_INVALID_HANDLE - Invalid INI Handle was passed to the function
INI_KEY_NOT_FOUND - Key does not exist
INI_ERR_INVALID_ID - Invalid Section ID

Code:
INI::DeleteKey(handle,"DELKEY","SEC");
INI::DeleteKey(handle,"DELKEY","",-1,2);
INI::DeleteKey(handle,"","",2);
INI::DeleteKey(handle,"DELKEY","");
GetSectionID
Get relative section id from section name

Definition:INI::GetSectionID(INI:filehandle,const section[],section_size=sizeof(section))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • section is the name of the section
  • section_size is the size of the section parameter
Returns:Returns the relative section id or an error code

Exceptions:
INI_ERR_INVALID_HANDLE - Invalid INI Handle was passed to the function
INI_SECTION_NOT_FOUND - Section does not exist

Code:
INI::GetSectionID(handle,"SECTION");
GetKeyID
Get relative key id from key name

Definition:INI::GetKeyID(INI:filehandle,const key[],const section[]="",sectionid=-1,section_size=sizeof(section),key_size=sizeof(key ))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • key is the name of the key
  • section is the name of the section
  • sectionid is the relative section id if known
  • section_size is the size of the section parameter
  • key_size is the size of the key parameter
Returns:Returns the relative key id or an error code

Exceptions:
INI_ERR_INVALID_HANDLE - Invalid INI Handle was passed to the function
INI_KEY_NOT_FOUND - Key does not exist

Code:
INI::GetKeyID(handle,"KEY","SECTION");
INI::GetKeyID(handle,"KEY","",1);
INI::GetKeyID(handle,"KEY","");
GetSectionName
Get section name from section id

Definition:INI::GetSectionName(INI:filehandle,result[],sectionid,result_size=sizeof(result))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • result is the array where the section name has to be stored
  • sectionid is the relative section id
  • result_size is the size of result
Returns:Returns 0 on success or an error code

Exceptions:
INI_ERR_INVALID_HANDLE - Invalid INI Handle was passed to the function
INI_ERR_INVALID_ID - Invalid Section ID

Code:
new res[32];
INI::GetSectionName(handle,res,1);
GetKeyName
Get key name from key id

Definition:INI::GetKeyName(INI:filehandle,result[],keyid,result_size=sizeof(result))
Parameters:
  • filehandle takes the INI Handle on which to operate
  • result is the array where the section name has to be stored
  • keyid is the relative section id
  • result_size is the size of result
Returns:Returns 0 on success or an error code

Exceptions:
INI_ERR_INVALID_HANDLE - Invalid INI Handle was passed to the function
INI_ERR_INVALID_ID - Invalid Key ID

Code:
new res[32];
INI::GetKeyName(handle,res,1);
WriteBuffer
Writes the buffer to the file

Definition:INI::WriteBuffer(INI:filehandle)
Parameters:
  • filehandle takes the INI Handle which has to be saved
Returns:Returns 0 on success or an error code

Exceptions:
INI_ERR_INVALID_HANDLE - Invalid INI Handle was passed to the function
INI_ERR_FILE_CREATION_FAILED - Could not create a new file
INI_ERR_PARSING_FAILED - Parsing of the file failed
INI_ERR_FAILED_TO_OPEN - Could not open the file
Code:
INI::WriteBuffer(handle);
DumpINI
Dumps the contents of an INI File on to the Server Window

Definition:INI::DumpINI(INI:filehandle)
Parameters:
  • filehandle takes the INI Handle on which to operate
Returns:Returns 0 on success or an error code

Exceptions:
INI_ERR_INVALID_HANDLE - Invalid INI Handle was passed to the function

Code:
new res[32];
INI::DumpINI(handle);
Benchmarks

Writing Speed Test
NOTE:These speed tests are outdated. New speed tests haven't been conducted for the latest version.
eINI is faster at all times while writing when compared with y_ini.

TST1.txt and TST2.txt have the same contents.I made two different files so that any changes made by y_ini won't affect eINI.

Code:
    new a = GetTickCount();
    new INI:ini = INI_Open("TST1.txt");
    for(new i = 0;i < 100000;i++)
    {
       	INI_SetTag(ini, "XXXX");
       	INI_WriteString(ini,"k","1234");
       	INI_WriteString(ini,"k2","1234");
       	INI_WriteString(ini,"k3","1234");
       	INI_WriteString(ini,"k4","1234");
       	INI_WriteString(ini,"k5","1234");
       	INI_SetTag(ini, "XXXX2");
       	INI_WriteString(ini,"k","1234");
       	INI_WriteString(ini,"k2","1234");
       	INI_WriteString(ini,"k3","1234");
       	INI_WriteString(ini,"k4","1234");
       	INI_WriteString(ini,"k5","1234");
    }
    INI_Close(ini);
    new b = GetTickCount();
    new INI:handle = INI::OpenINI("TST2.txt",INI_WRITE);
   
    for(new i = 0;i < 100000;i++)
    {
        new id = INI::GetSectionID(handle,"XXXX");
        INI::WriteString(handle,"1234","k","",-1,id);
        INI::WriteString(handle,"1234","k2","",-1,id);
        INI::WriteString(handle,"1234","k3","",-1,id);
        INI::WriteString(handle,"1234","k4","",-1,id);
        INI::WriteString(handle,"1234","k5","",-1,id);
        id = INI::GetSectionID(handle,"XXXX2");
        INI::WriteString(handle,"1234","k","",-1,id);
        INI::WriteString(handle,"1234","k2","",-1,id);
        INI::WriteString(handle,"1234","k3","",-1,id);
        INI::WriteString(handle,"1234","k4","",-1,id);
        INI::WriteString(handle,"1234","k5","",-1,id);
	}
    INI::CloseINI(handle);
    new c = GetTickCount();
	printf("SPEED TEST YSI:%d eINI:%d",b-a,c-b);
Results:
SPEED TEST YSI:1685 eINI:1203
SPEED TEST YSI:1667 eINI:1175
SPEED TEST YSI:1666 eINI:1283

Reading Speed Test
y_ini wins when the file is small and eINI wins where the file is large.
Code:
main()
{
    new a = GetTickCount();
    
    for(new i = 0;i < 100000;i++)
    {
        INI_ParseFile("TEST.txt", "Load1");
    }
    
    new b = GetTickCount();
    
   
    for(new i = 0;i < 100000;i++)
    {
        new INI:handle = INI::OpenINI("TEST.txt",INI_READ);
        INI::ParseINI(handle,"Load2",true);
        INI::CloseINI(handle);
	}
    
    new c = GetTickCount();
	printf("SPEED TEST YSI:%d eINI:%d",b-a,c-b);
}
forward Load1(tag[],key[],value[]);
public Load1(tag[],key[],value[])
{

}
forward Load2(key[],value[]);
public Load2(key[],value[])
{

}
Results:
SPEED TEST YSI:6141 eINI:6839 - Small File - 7 Lines
SPEED TEST YSI:6099 eINI:6686 - Small File - 6 Lines
SPEED TEST YSI:7664 eINI:7665- Small File - 10 Lines
SPEED TEST YSI:12614 eINI:10490 - Large File - 20 Lines
SPEED TEST YSI:19184 eINI:14487 - Very Large File - 36 lines

Issues & Notes
I had written this include in 2013 for my personal use.I have heavily modified the include this year(2015).I have added LIBERAL Mode so that any INI format/standard can be used or else I would be forcing people to use the style I like.

I am expecting bugs because its very old and moreover I have done lot of edits to the code to improve it.I have tested though and fixed all the bugs I could find.There could be some more.

Report bugs via PM or Create an issue at github
Report Typos this thread via PM

Change Log
Version 1.0:
(7/5/2015)

First Release

Version 1.0.3:
(10/5/2015)
  • Added SetReplacementText
  • Added new setting - INI_MAX_REPLACEMENT_TEXT
  • Minor Fixes
Version 1.0.4:
(10/6/2015)
  • Bug Fix
Version 1.0.5:
(19/8/2015)
  • Improved ReadString
  • Fixed a bug which created duplicate sections when WriteString was used.
Version 1.1:
(2/9/2015)
  • New Parameter for ParseINI where you can specify if you would want eINI to broadcast the loaded data across all scripts
  • New Parameter for ParseINI which adds a new way of dynamic loading where key and section name will be passed as arguments to LoadFunctions
  • Overall improvement in Speed
  • Bug Fixes
  • New Log System (tracks eINI events)
Download
GitHub
Example Filterscript


Credits
Yashas
******,Dracoblue,Slick,Neufox and everyone else for their INI Readers which helped me a lot
Slice,****** and many others who used to amaze me every time

Special Thanks to:
****** a.k.a Alex "******" Cole
Kye/Kalcor & the whole SA-MP Team
Thiadmer for PAWN
Reply
#2

Why did you made INI that complicated.

Personally i don't use INI anymore cause its slower, old method and slower! I would be much better if you try SQLITE or MYSQL.

And i will give you Rep because you wrote so much!
Reply
#3

Quote:
Originally Posted by Gammix
View Post
Why did you made INI that complicated.

Personally i don't use INI anymore cause its slower, old method and slower! I would be much better if you try SQLITE or MYSQL.

And i will give you Rep because you wrote so much!
It isn't complicated.This thread looks huge which makes it look as if its complicated.
Please tell me which part was complicated?

Languages
Even I personally use MySQL to store information.I use INI only to load language files.This include is from 2013.
Reply
#4

Good job i look forward to work with this.
Reply
#5

Well done and nice to see effort in your thread.
Reply
#6

Looks like edited version of y_ini, dini and sii.
Reply
#7

Awesome work. Omg thats a huge thread lol
Reply
#8

Quote:
Originally Posted by Gammix
View Post
Why did you made INI that complicated.

Personally i don't use INI anymore cause its slower, old method and slower! I would be much better if you try SQLITE or MYSQL.

And i will give you Rep because you wrote so much!
Me too I prefer Sqlite, and I think if anyone really requires to use some of the features in this they would be using a plugin just feels like this tries to re-invent the wheel which is fine but was it really worth the effort? Probably for some.
Reply
#9

Quote:
Originally Posted by Amrev
View Post
Looks like edited version of y_ini, dini and sii.
eINI is not even close to any of them INI Processors you mentioned.
Every single line of eINI was written by me.

The only thing in common with y_ini and eINI is they both use Linked Lists which by far is the best way to store INI Data.

dini,sii and eINI are at two different ends.eINI is 40x faster than dini.

dini,sii both do not support sections/tags whereas eINI supports.
y_ini has half the features which eINI provides.

Performance of all these INI Processor when compared with eINI differ significantly except for y_ini.

Quote:
Originally Posted by NGEN123
View Post
Awesome work. Omg thats a huge thread lol
I was wondering if I need to break this thread up and make two separate tutorials, one for reading and one for writing in the tutorial section.

Quote:
Originally Posted by Pottus
View Post
Me too I prefer Sqlite, and I think if anyone really requires to use some of the features in this they would be using a plugin just feels like this tries to re-invent the wheel which is fine but was it really worth the effort?
This is from 2013, I just spent around 10-12 hours on updating this.

This is anyway the fastest INI Processor I believe if my speeds tests are valid.

Do you use SQLite even for storing languages?I use INI to store languages with tags like [en],[fr]...
Reply
#10

I only support English but I would definitely use y_languages. I am not sure what purpose that is for since you did not explain but if you were using databases you could just make one of the rows languages. But I am sure there is some useful stuff for guys who like INI.
Reply
#11

What about benchmarking with dFile? Because I'm using it now and it's faster than Y_ini too!
Reply
#12

I checked it but I couldn't find the plugin(download links are invalid)

You may be right.dFile can be faster than y_ini or eINI since it is a plugin.

If you make your own strlen and benchmark it with native strlen then the native would be like 2x to 2.5 x faster than your code though both do the same.

native ~ plugin

Quote:
Originally Posted by Yashas
I am wondering if native functions are faster than the ones I make.

Код:
 for(new i = 400000;i;i--)
  strcmp(x1,x2);
 new b = GetTickCount();
 printf("SD TST:%d",b-a);

 a = GetTickCount();
 for(new i = 400000;i;i--)
 {
    new j =0;
    while(1)
    {
        if(x1[j] != x2[j++])
            break;
    }
 }
For PAWN it seems that native is twice as fast as mine!

My version had to be faster because it cannot be optimized further ,in fact it doesn't even function like strcmp and does less work than strcmp.

I had made my own parser which actually checks every character,does all the copying,all comparing,... - So is this bad?I thought I would avoid the function overhead by doing it but....

Thanks
Quote:
Originally Posted by ******
No, natives are WAY faster than PAWN code! If you found it was twice as fast I would suggest you retest as I would suspect it is far more than that.
Reply
#13

Quote:
Originally Posted by Yashas
Посмотреть сообщение
I checked it but I couldn't find the plugin(download links are invalid)

You may be right.dFile can be faster than y_ini or eINI since it is a plugin.

If you make your own strlen and benchmark it with native strlen then the native would be like 2x to 2.5 x faster than your code though both do the same.

native ~ plugin
dFile is using FileManager plugin for directories only, not for file writing and reading. It's an include. You can download it without using plugin.
Reply
#14

So it is faster than the SA:MP natives?

If so then I will try adding a new setting "USE_FILE_MANAGER_PLUGIN" option in the next release.
Reply
#15

Quote:
Originally Posted by Yashas
Посмотреть сообщение
So it is faster than the SA:MP natives?

If so then I will try adding a new setting "USE_FILE_MANAGER_PLUGIN" option in the next release.
Sorry, I was using dFile without a plugin
Reply
#16

Holy shit that documentation! Good job, really.

p.s. better way to benchmark code: https://sampforum.blast.hk/showthread.php?tid=218491
Reply
#17

The speed test results which I've posted are average of 3 or 4.I run the code multiple times and plug those number into my calculator and find the average.

There are lot of features and it is highly customizable.Therefore a good documentation is a must.
Reply
#18

Hm i wonder how hard it would be to convert from mxINI... I really really need the sections feature, and the read/write modes really interests me
Reply
#19

Good job, using it now to load languages.
Reply
#20

Quote:
Originally Posted by liquor
Посмотреть сообщение
Hm i wonder how hard it would be to convert from mxINI... I really really need the sections feature, and the read/write modes really interests me
It should be hard because you now want to use sections and your mxINI never supported sections. So that means lot of work. But you can save time by mapping eINI functions to mxINI functions using defines.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)