Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

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


  • Please log in to reply
39 replies to this topic
Verdlin
  • Members
  • 256 posts
  • Last active: Apr 29 2016 06:46 PM
  • Joined: 21 Dec 2012

Be my guest... that's the purpose of this forum!!!  Help and be helped!  You inspired me, I shared some of the concepts I use, and I'll probably learn something from your improved version!  I love it.

 

Relayer

 

1 month later and I have successfully rewritten the class ;).

 

This is much, much better then the old version. I am going to rewrite the main post to outline new features, changes, and amazing speed improvements.


Scripts are written and tested using AHK_H 64w (unless otherwise specified).

CFlyout. EasyIni. Dynamic Label Execution (No Reload). Word Lookup.


Larctic
  • Members
  • 303 posts
  • Last active: May 10 2016 04:56 PM
  • Joined: 21 Jul 2012
Thanks. The fifth example is exactly what I was looking for.
 
This is my slightly modified version. 
1, automatic call functions without having to use "# Include"
2, support INI built-in variables.
3, reads null key.
[Automatic]
Aid
Clip  

[Thread library]
Configuration
Sidebar menu
 
vIni := class_EasyIni("Test.ini")

     return


class_EasyIni(a,b="",c="")
	{
	return new EasyIni(a,b,c)
	}

class EasyIni
{
	__New(sFile="", sLoadFromStr="",c="") ; Loads ths file into memory.
	{
	……
			FileRead, sIni, %sFile%
	(c?sIni:=EasyIni_inl(sIni):"")
	……
​
	(x:=InStr(sTrimmedLine, "=")) ? (this[sCurSec, SubStr(sTrimmedLine, 1, x - 1)] := SubStr(sTrimmedLine, x + 1)) : (this[sCurSec, sTrimmedLine] := "")

	}
}

EasyIni_inl(v){
	If InStr(v, "`%a_workingdir`%")
		stringreplace,v,v,`%a_workingdir`%,%a_workingdir%,all
	If InStr(v, "`%A_ScriptDir`%")
		stringreplace,v,v,`%A_ScriptDir`%,%A_ScriptDir%,all
	……
	}


Verdlin
  • Members
  • 256 posts
  • Last active: Apr 29 2016 06:46 PM
  • Joined: 21 Dec 2012

 

Thanks. The fifth example is exactly what I was looking for.
 
This is my slightly modified version. 
1, automatic call functions without having to use "# Include"
2, support INI built-in variables.
3, reads null key.

 

 

You're welcome, and thank you, Larctic! Those are great suggestion. I have implemented all of them and sync'd with GitHub.

 

Here is a working example:

Spoiler

Scripts are written and tested using AHK_H 64w (unless otherwise specified).

CFlyout. EasyIni. Dynamic Label Execution (No Reload). Word Lookup.


Verdlin
  • Members
  • 256 posts
  • Last active: Apr 29 2016 06:46 PM
  • Joined: 21 Dec 2012

Hmm, I just realized my implementation of A_ScriptDir and A_WorkingDir makes no sense. Were you wanting support for those variables in Inis? i.e.

 

Spoiler

Scripts are written and tested using AHK_H 64w (unless otherwise specified).

CFlyout. EasyIni. Dynamic Label Execution (No Reload). Word Lookup.


Larctic
  • Members
  • 303 posts
  • Last active: May 10 2016 04:56 PM
  • Joined: 21 Jul 2012

Yes, I need to do this. Because I use the H version, all the scripts, the contents of these variables is the same.



Verdlin
  • Members
  • 256 posts
  • Last active: Apr 29 2016 06:46 PM
  • Joined: 21 Dec 2012

Yes, I need to do this. Because I use the H version, all the scripts, the contents of these variables is the same.

 

Ah, yes, I forgot about that -- I am an _H user, too.

 

Here's an interesting question: should the literal text "A_ScriptDir" and "A_WorkingDir" be resolved to it's value when called and then saved with the actual value, or should the class translate this for you and keep retain the literal variable text under-the-hood.

 

For example:

[Section]
Path=A_ScriptDir\Exe.exe

; ini object
Msgbox % vIni.Section.Path ; outputs something like, "C:\Users\Larctic\Exe.exe"
vIni.Save()

[Section]
Path=C:\Users\Larctic\Exe.exe

OR

[Section]
Path=A_ScriptDir\Exe.exe

; ini object
Msgbox % vIni.Section.Path ; outputs something like, "C:\Users\Larctic\Exe.exe"
vIni.Save() ; Ini stays the same

[Section]
Path=A_ScriptDir\Exe.exe

Scripts are written and tested using AHK_H 64w (unless otherwise specified).

CFlyout. EasyIni. Dynamic Label Execution (No Reload). Word Lookup.


Larctic
  • Members
  • 303 posts
  • Last active: May 10 2016 04:56 PM
  • Joined: 21 Jul 2012
Save, you can use the same means.
But I did not do so, probably because there is no demand in this respect.
 
StringReplace,A ,A , %A_ScriptDir%, A_ScriptDir, All
In addition, there are some suggestions.
 
"InStr" is a relatively time-consuming command. The following code, the first time you run, you've got the required value, why is it performed twice in the back?
 
if (InStr(sTrimmedLine, "="))
{
    sPrevKeyForThisSec := SubStr(sTrimmedLine, 1, InStr(sTrimmedLine, "=") - 1)
    this[sCurSec, sPrevKeyForThisSec] := SubStr(sTrimmedLine, InStr(sTrimmedLine, "=") + 1)
}


Verdlin
  • Members
  • 256 posts
  • Last active: Apr 29 2016 06:46 PM
  • Joined: 21 Dec 2012
StringReplace,A ,A , %A_ScriptDir%, A_ScriptDir, All

 

So values within an ini will be resolved from the literal path of A_ScriptDir into the name, "A_ScriptDir" (i.e. "C:\Program Files\Autohotkey" gets translated to, "A_ScriptDir")? I am not certain this is such a good idea. If the ini is also used by some other application or script, then A_ScriptDir will be read by those applications as, "A_ScriptDir" instead of the path. Granted, I think that this is a rare or non-existent scenario, I just don't see a compelling argument for either way.

 

Thanks for the suggestions! I went ahead and reduced InStr calls from 3 to 1. I had simply forgot that this was a slow(ish) function.

 

Updated. New version simply translates %A_ScriptDir% to actual path whenever this is encountered in a value. i.e.

sIni:="
(LTrim
[Section]
Path=%A_ScriptDir%
)"

vIni := class_EasyIni("test.ini", sIni)
Msgbox % "Path=" vIni.Section.Path ; for me, outputs Path=C:\Program Files\AutoHotkey
vIni.Save()
return

Scripts are written and tested using AHK_H 64w (unless otherwise specified).

CFlyout. EasyIni. Dynamic Label Execution (No Reload). Word Lookup.


Larctic
  • Members
  • 303 posts
  • Last active: May 10 2016 04:56 PM
  • Joined: 21 Jul 2012
INI built-in variables, this requirement is not common, so I do not recommend class_EasyIni promotion.
 
 
This is my common functions, because I need a lot to read INI files, so I pursuit of performance:
 
Z_ini(h,p=""){
	FileRead, h, %h%
	If (ErrorLevel = 0) and h
		{
		j:=[], (p?h:=Z_inl(h):"")
		Loop, Parse, h, `n, `r `t
			{
			(!A_LoopField  or ((r:=SubStr((z:=A_LoopField), 1, 1)) = ";"))
				? "" : ((r = "[")
				? (x:=SubStr(z, 2, InStr(z, "]", false, 0) - 2)) : ((p:=InStr(z, "=")) 
				? (j[x, Trim(SubStr(z, 1, p - 1))] := Trim(SubStr(z, p + 1))) : (j[x, z] := "")))
			}
		return j
		}
	}


Larctic
  • Members
  • 303 posts
  • Last active: May 10 2016 04:56 PM
  • Joined: 21 Jul 2012
repeat

Verdlin
  • Members
  • 256 posts
  • Last active: Apr 29 2016 06:46 PM
  • Joined: 21 Dec 2012

I appreciate your contributions! Although this code will perform faster, it is very important to me that my script stay readable. That is just one determinant that makes this class, "Easy."

 

Although, at this point, readability may not be as important because this class is pretty stable, I would be shooting myself in the foot if I use the above format. Myself, and doubtless many others, will find it troublesome to read and parse out so much cryptic, compressed script on so few lines.


Scripts are written and tested using AHK_H 64w (unless otherwise specified).

CFlyout. EasyIni. Dynamic Label Execution (No Reload). Word Lookup.


Verdlin
  • Members
  • 256 posts
  • Last active: Apr 29 2016 06:46 PM
  • Joined: 21 Dec 2012

Updated.

* Fixing formatting bugs when saving file.
* Fixed bug where AddKey() would return true when it actually failed.
This would happen if an ini that had a section with no keys was loaded,
and then later AddKey was called.

Scripts are written and tested using AHK_H 64w (unless otherwise specified).

CFlyout. EasyIni. Dynamic Label Execution (No Reload). Word Lookup.


Larctic
  • Members
  • 303 posts
  • Last active: May 10 2016 04:56 PM
  • Joined: 21 Jul 2012
Yes, as a public library, it is necessary to maintain legibility. I agree with your point of view.
Thank update.happy.png


Verdlin
  • Members
  • 256 posts
  • Last active: Apr 29 2016 06:46 PM
  • Joined: 21 Dec 2012

A pleasure! Thanks for contributing ;)


Scripts are written and tested using AHK_H 64w (unless otherwise specified).

CFlyout. EasyIni. Dynamic Label Execution (No Reload). Word Lookup.


Verdlin
  • Members
  • 256 posts
  • Last active: Apr 29 2016 06:46 PM
  • Joined: 21 Dec 2012

Update:

* Fixing a bug where comments before the first section were not saved
* Fixing a bug where an additional newline was saved to the end of an
ini file whose last line was a newline
* Fixing bug where keys starting with "[" were read in as sections
* Fixing bug where AddKey would return true, but fail to add a key/val
to a Section that was loaded from __New with no keys
* Adding support for .Copy
* Support delimiter in GetSections/Keys/Vals
* Improving Merge, although it still does not merge formatting
* Minor refactoring to improve speed and readability

Scripts are written and tested using AHK_H 64w (unless otherwise specified).

CFlyout. EasyIni. Dynamic Label Execution (No Reload). Word Lookup.