Page 1 of 1

class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 09 Dec 2014, 16:42
by Verdlin
Download

(Originally posted here)

A big problem I have had will all other Ini libraries (including the old version of EasyIni) is that their syntax is too cumbersome. The point of this library is to make it as easy as possible to R/W inis; furthermore, I wanted to make the class itself easy to read and accessible to other developers. EasyIni is currently 389 LOC.

An unexpected positive consequence of this class is that it performs exponentially faster than IniWrite operations. I posted an example below where class_EasyIni is 1162% faster than IniWrite.

My design approach was, "How can I make this as easy as possible?" The result is, you can interface with ini's using class_EasyIni objects with great ease. Thanks to custom objects, this class allows you to use the familiar, native, Object syntax.

Code: Select all

; To create an ini object,
vIni := class_EasyIni("MyIni.ini")

; To interface with the object,
for section, aKeysAndVals in vIni
   for key, val in aKeysInVals
      vIni[Section][key] := 1

vIni[VariableWithSectionName][VariableWithKeyName] := val ; this is typically used when you are looping through sections and keys
vIni.NameOfSection.NameOfKey := val ; This syntax is the easiest, but you must know the literal section name and key name to do this.
   ; It is particularly useful for handling user-defined ini variables in your applications with relative ease.
vIni.NameOfSection[VariableWithKeyName] := val ; This is when you know the literal section name
vIni[VariableWithSectionName].key := val ; This is when you know the literal key name
This file is std lib compliant. Of course, you should make sure the file name is class_EasyIni.ahk in order for this to work.

Character limitations are mostly obvious:
  • You cannot use newlines in section names.
  • For any alphanumeric section, (i.e. "[A]") only one case is allowed. So if you tried to add section "[a]" AddSection() would fail. This is demonstrated in my 1500 sections example below.
  • During my tests, I noticed that SOH (chr(1)) and A_Space (chr(32)) were written to the same section [SOH]. I am not sure why this is the case, but I don't imagine this will be a problem for most people, if any.
  • I also noticed that quite a few odd character values were getting grouped together into the same sections. Whether this is a problem for anyone is doubtful, but I suspect it is possible for those who store BBCode in inis to have problems. Regardless, this class is just a fancy custom object. If there are certain problems with section names, this is likely a problem with AHK itself and not the class.
  • You cannot have a section or key that starts with the text, EasyIni_ReservedFor_. I can't imagine this being a big problem.
    "=" are not supported in keynames.
  • Do whatever you want with values ;)
A couple of notes about ini data:
  • Keys without values are supported
  • Although it is not recommended if you plan on using your inis with other applications that access the same ini, "]" in section names are supported.
  • EasyIni stores ini data in a custom object. Much credit for this custom object goes to Lexikos and Rbrtryn for their work with ordered arrays. For more information, see OrderedArray. Thanks to the pre-existing work with OrderedArrays, I was able to create an object that, without much trouble, enabled me to maintain the format of the ini file. If any comment or newline is removed from your file, or if any sections or keys are re-ordered in your file as a result of using class_EasyIni, then this is a bug and you should report it to me!
This rewrite of the library has increased the overall speed, as well. In fact, the Save() function is now as 3629% faster than the old EasyIni class!!

Below is a test where I add every possible character value (returned from chr()) to an ini. Writing to memory took < 1 second. Writing to a file took 17seconds (3629% faster than the old class).
Spoiler
This test shows what characters are readable by class_EasyIni. As I mentioned before, certain odd characters get grouped together into the same sections. If you care to know more about this, run the previous example first, and then run this example.
Spoiler
Adding 1500 sections, keys, and values takes < 1 sec total to write to memory and to an ini. This example shows how sections and keys are case-sensitive. It will produce errors for sections a-z because sections A-Z already existed in the ini.
Spoiler
Examples:
Creating an ini, adding and modifying sections, keys, and values, and saving.
Spoiler
Loading an ini from a string, and maintaining all formatting (including comments and newline) in an in file
Spoiler
IniWrite vs EasyIni:
Spoiler
I do appreciate any comments/input/criticism.

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Format

Posted: 09 Dec 2014, 20:11
by joedf
Very interesting... It makes me wonder if mcode would be faster.... :P

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Format

Posted: 20 Dec 2014, 00:36
by bobc119
This library is awesome! I've used it for a long time now. Thank you Verdlin.

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Format

Posted: 10 Mar 2015, 07:58
by Verdlin
joedf wrote:Very interesting... It makes me wonder if mcode would be faster.... :P
As a general rule of thumb, I think MCode is always going to be faster than interpreted code.
bobc119 wrote:This library is awesome! I've used it for a long time now. Thank you Verdlin.
You're welcome! Thanks for the support.

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 28 Sep 2015, 18:19
by highend
Great class, Verdlin!

Do you still support it?

My problem with it:

Let's say you have 3 entries like

Code: Select all

[20150927234336]
test=1

[20150927234337]
test=2

[20150927234338]
test=3
Try to use:

Code: Select all

vCfg.DeleteSection("20150927234337")
vCfg.Save()
and you'll notice that this section isn't deleted at all (but it's follower)...
Result:

Code: Select all

[20150927234336]
test=1

[20150927234337]
test=3
So the section is still there but the contents of the next following section is transferred into it.

So atm, it doesn't work with integer section names only. Can this be fixed?

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 29 Sep 2015, 08:49
by Verdlin
highend wrote:Great class, Verdlin!

Do you still support it?
...
So the section is still there but the contents of the next following section is transferred into it.

So atm, it doesn't work with integer section names only. Can this be fixed?
Thanks, Highend! This is a known bug. I've not been able to fix the bug because the code has been too complex for me to figure out.

I don't know if this is a good workaround for you, but you can add ".0" to the end of all your sections to get around this bug. Let me know if that's good enough. I could write a script for you to do this, but I think it's as simple as using Find/Replace in Notepad++ and replacing "]" with ".0]"

Long term I'd like to code a solution to this bug, but it's tricky. I have a few ideas a may try in the next week or so.

Code: Select all

{
	sIni:="
		(LTrim
			[20150927234336.0]
			test=1
 
			[20150927234337.0]
			test=2

			[20150927234338.0]
			test=3
		)"
 
	vIni := class_EasyIni("test.ini", sIni)
	for sec, aData in vIni
		for k, v in aData
			s .= s == "" ? "[" sec "]`n" k "=" v : "`n[" sec "]`n" k "=" v

	vIni.DeleteSection("20150927234337.0")
	s :=

	for sec, aData in vIni
		for k, v in aData
			s .= s == "" ? "[" sec "]`n" k "=" v : "`n[" sec "]`n" k "=" v

	Msgbox % s

	return
}
Output:
[20150927234336.0]
test=1
[20150927234338.0]
test=3

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 29 Sep 2015, 12:57
by highend
Hi Verdlin,
I don't know if this is a good workaround for you, but you can add ".0" to the end of all your sections to get around this bug. Let me know if that's good enough. I could write a script for you to do this, but I think it's as simple as using Find/Replace in Notepad++ and replacing "]" with ".0]"
That's just a simple regex replace in my editor. No script needed. I've switched to a different naming style for all sections in the meantime.
I'm just using an affixed "x" in front of the number. As long as a alphabetical character is used to make a string out of the integer, everything works fine.

Btw, using e.g. a "#" in front of it doesn't work as well. Wasn't able to find the reason for this behavior yet...

Let's see what you an achieve if you have some time for it next week :)

Regards and thanks for the fast answer!

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 29 Sep 2015, 21:53
by lexikos
To fix the bug, replace .Remove() with .Delete(). Remove() is commonly misused in this way, hence the split into RemoveAt() and Delete().

There is probably a similar bug for keys.

There is another bug related to the behaviour of integer keys in objects: integer section names are reformatted as pure decimal. For example, [0x1] and [001] become [1]. The workaround is the same as for the deletion bug.

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 30 Sep 2015, 15:02
by evilC
Nice work, although I have ditched INIs lately as they are only two levels deep. For situations where they are sufficient though, this is a nice, simple solution.

Lately have been using Coco's JSON parser and FileWrite - it seems to me that it may well be quite easy to apply your nice simple syntax to a system using that used JSON instead.

You could keep the syntax as
vIni[Section, key, you, can, keep, on, adding, levels...] := something

something could even be an object, not just a string :)

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 05 Jan 2016, 10:35
by hyaray
thanks for your class_EasyIni!!!
there's may be a bug below

Code: Select all

o := class_EasyIni("t.ini")
o.t.RemoveAt(2)
;o.t.Remove(2)
o.save()
Return

change of "t.ini"
[t]      [t]
1=1     1=1
2=2     2=3
3=3     3=4
4=4     4=
"4=" is the Bug? If I use Remove instead, "4=" disappeared.

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 12 Apr 2016, 10:35
by Verdlin
hyaray wrote:thanks for your class_EasyIni!!!
there's may be a bug below

Code: Select all

o := class_EasyIni("t.ini")
o.t.RemoveAt(2)
;o.t.Remove(2)
o.save()
Return

change of "t.ini"
[t]      [t]
1=1     1=1
2=2     2=3
3=3     3=4
4=4     4=
"4=" is the Bug? If I use Remove instead, "4=" disappeared.
Yes, this is a bug and it is documented in a few posts above (see post starting with, "Thanks, Highend! This is a known bug. I've not been able to fix the bug because the code has been too complex for me to figure out.").

Lexikos has given me a solution, but I've not been able to figure out how to implement it. Rbrtryn is the one who wrote the core code which contains the bug, and so I don't fully understand it and haven't taken adequate time to figure it out. If you can bug Rbrtryn, maybe he can fix it in his OrderedArray class... ;)

In the meanwhile, remember you can add ".0" to the end of all your sections to get around this bug.

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 24 Jul 2016, 23:08
by highend
Are there any license restrictions or could we use the class in a commercial project as well?

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 25 Jul 2016, 08:20
by Verdlin
highend wrote:Are there any license restrictions or could we use the class in a commercial project as well?
Thanks for asking! Feel free to use it. I haven't attached a license, and if I do, it would only be one which asked for attribution. So I'd just ask you to give me attribution in the same place you'll give attribution to anyone else :) .

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 25 Jul 2016, 08:33
by highend
Ok, thanks. So a link in the "About <application>" window would mention this class and provides a link to
a.) This thread
or
b.) Your user profile

What do you prefer, I guess a.)?

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 25 Jul 2016, 09:28
by Verdlin
A. is great, thanks!

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 25 Jul 2016, 09:51
by highend
Ok, I'll do that when the time comes :)

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 27 Aug 2016, 11:30
by YellowPeanuts
I really appreciate your great work.
I have a simply question.
When I use obj.save() then after saved data remove in obj.save()?
Sorry, I am not a navite speaker in english.

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 30 Aug 2016, 11:06
by Verdlin
YellowPeanuts wrote:I really appreciate your great work.
I have a simply question.
When I use obj.save() then after saved data remove in obj.save()?
Sorry, I am not a navite speaker in english.
Thank you, YellowPeanuts! Yes, our language barrier makes it a little difficult for me to understand your question, but I'll do my best to answer it.

obj.Save() will save it to a file. The data is not removed from the object itself. That will only happen when you invoke the destructor such as obj :=

Re: class_EasyIni:Native syntax-Ini.Section.Key:=val +Formatting

Posted: 06 Jun 2017, 08:00
by zcooler
Hello!

Im having difficulties how to utilize the "Default" option in IniRead within this EasyIni syntax. For example I have this IniRead command with ternary operators setting defaults (when keys and values does not exist yet) I would like to get working, but EasyIni does (as tested so far) not like expressions within its syntax when enumerating the array. Anyone have any ideas?

Code: Select all

For Each, Key In IniKeys {
IniRead, Value, %SettingsIni%, %IniSec%, %Key%, % (Key = "AllFiles" ? 1 : (Key = "SortFilter") ? "|" : 0)
 Value := vTestIni[IniSec][(Key = "AllFiles" ? 1 : (Key = "SortFilter") ? "|" : 0)] ;% (Key = "AllFiles" ? 1 : (Key = "SortFilter") ? "|" : 0)
   msgbox % IniSec "`n" Key "=" Value
}
IniRead, OutputVar, Filename, Section, Key [, Default]
Default
The value to store in OutputVar if the requested key is not found. If omitted, it defaults to the word ERROR. To store a blank value (empty string), specify %A_Space%.
[v1.0.90+]: This parameter is not used if Key is omitted.
EasyIni class:
Spoiler