I found a simple way to overload the load() function with the ability to keep duplicate sections. Duplicate keys are already created, so I'm working on the ability to stop that now.
I also created (and demonstrated in the test file of the new version) a new function to load (and reload) INI content from a variable instead of a file.
Code:
IniFile_load(IniFileObject, fromFile = "", duplicateSections = "", duplicateKeys = "") {
if (fromFile = "")
if !fromFile := IniFile_getFilePath(IniFileObject)
return false
if !FileExist(fromFile)
return false
if !sections := IniFile_getSections(IniFileObject)
return false
if (duplicateSections = "")
duplicateSections := IniFile_getDuplicateSections(IniFileObject)
if (duplicateKeys = "")
duplicateKeys := IniFile_getDuplicateKeys(IniFileObject)
Loop, Read, %fromFile%
{
line = %A_LoopReadLine%
; Check for section
if RegExMatch(line, "im)^\s*\[([^\]]+)\]\s*$", match) {
section := match1
addSection := false
if (duplicateSections) {
addSection := true
} else if !index := Vector_indexOf(sections, section, 1, "getTitle") {
addSection := true
} else sectionObj := Vector_get(sections, index)
if (addSection) {
sectionObj := IniSection_new(section)
Vector_add(sections, sectionObj)
}
continue
}
; Extract key, value, and comment from line, if available
if RegExMatch(line, "im)^\s*(([^=]+?)\s*=\s*""?(.*?)""?)?\s*(;\s?(.*))?$", match) {
field := IniField_new(match2, match3, match5)
IniSection_addField(sectionObj, field)
}
}
return true
}
Code:
iniFile_loadFromVar(IniFileObject, data = "", duplicateSections = "", duplicateKeys = "") {
if (data = "")
if !data := IniFile_getData(IniFileObject)
return false
if !sections := IniFile_getSections(IniFileObject)
return false
if (duplicateSections = "")
duplicateSections := IniFile_getDuplicateSections(IniFileObject)
if (duplicateKeys = "")
duplicateKeys := IniFile_getDuplicateKeys(IniFileObject)
Loop, Parse, data, `n
{
line = %A_LoopField%
; Check for section
if RegExMatch(line, "im)^\s*\[([^\]]+)\]\s*$", match) {
section := match1
addSection := false
if (duplicateSections) {
addSection := true
} else if !index := Vector_indexOf(sections, section, 1, "getTitle") {
addSection := true
} else sectionObj := Vector_get(sections, index)
if (addSection) {
sectionObj := IniSection_new(section)
Vector_add(sections, sectionObj)
}
continue
}
; Extract key, value, and comment from line, if available
if RegExMatch(line, "im)^\s*(([^=]+?)\s*=\s*""?(.*?)""?)?\s*(;\s?(.*))?$", match) {
field := IniField_new(match2, match3, match5)
IniSection_addField(sectionObj, field)
}
}
return true
}
Trying to figure out the best way to put a getComment and setComment function in IniFIle.
What I've come up with so far, is basing the comment off of a section or key, plus or minus a line offset.
For instance, to get the comment from the same line as Section1, Key1, you'd use:
IniFile_getComment(File, "Section1", "key1") ; The line comment
Or to get the comment on the line above it:
IniFile_getComment(File, "Section1", "key1", -1) ; Right above the key
Or to get the comment from a section offset:
IniFile_getComment(File, "Section1", "", 1) ; right below the section declaration
Is that simple enough, or can you think of a better way to access the comments (other than searching, which I might support also)?
Also, based on my work with the DOM, I think a null value (or "" in AHK's case) might be more logical than a 0 (false) when a function fails. Do you think I should change most of my return false lines to return "" so as not to be confused with an actual return value of 0?
I'm also implementing a headerFields Vector that stores everything before the first section in the INI file, and then saves it again with the INI file.
I'll make some new functions for working with header fields.