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

Post your working scripts, libraries and tools for AHK v1.1 and older
Verdlin
Posts: 63
Joined: 04 Oct 2013, 08:55
Contact:

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

09 Dec 2014, 16:42

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.
Last edited by Verdlin on 10 Dec 2014, 07:23, edited 2 times in total.
User avatar
joedf
Posts: 8958
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

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

09 Dec 2014, 20:11

Very interesting... It makes me wonder if mcode would be faster.... :P
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]
bobc119
Posts: 23
Joined: 10 Jan 2014, 17:02

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

20 Dec 2014, 00:36

This library is awesome! I've used it for a long time now. Thank you Verdlin.
Verdlin
Posts: 63
Joined: 04 Oct 2013, 08:55
Contact:

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

10 Mar 2015, 07:58

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.
highend
Posts: 47
Joined: 24 Nov 2014, 16:57

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

28 Sep 2015, 18:19

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?
Verdlin
Posts: 63
Joined: 04 Oct 2013, 08:55
Contact:

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

29 Sep 2015, 08:49

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
highend
Posts: 47
Joined: 24 Nov 2014, 16:57

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

29 Sep 2015, 12:57

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!
lexikos
Posts: 9589
Joined: 30 Sep 2013, 04:07
Contact:

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

29 Sep 2015, 21:53

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.
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

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

30 Sep 2015, 15:02

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 :)
User avatar
hyaray
Posts: 85
Joined: 20 Jun 2015, 01:37
Contact:

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

05 Jan 2016, 10:35

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.
Verdlin
Posts: 63
Joined: 04 Oct 2013, 08:55
Contact:

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

12 Apr 2016, 10:35

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.
highend
Posts: 47
Joined: 24 Nov 2014, 16:57

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

24 Jul 2016, 23:08

Are there any license restrictions or could we use the class in a commercial project as well?
Verdlin
Posts: 63
Joined: 04 Oct 2013, 08:55
Contact:

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

25 Jul 2016, 08:20

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 :) .
highend
Posts: 47
Joined: 24 Nov 2014, 16:57

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

25 Jul 2016, 08:33

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.)?
highend
Posts: 47
Joined: 24 Nov 2014, 16:57

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

25 Jul 2016, 09:51

Ok, I'll do that when the time comes :)
YellowPeanuts

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

27 Aug 2016, 11:30

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.
Verdlin
Posts: 63
Joined: 04 Oct 2013, 08:55
Contact:

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

30 Aug 2016, 11:06

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 :=
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

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

06 Jun 2017, 08:00

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

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 179 guests