Martin
Well-known member
CX Code Contributor
3rd Party Module Dev
Tutorial Author
3rd Party Tool Dev
- Joined
- Jun 19, 2017
- Messages
- 338
I know there is some basic ini file handling but the solutions from ignition and pyro lack sections so I came up with my own, works for all targets where filestreams are supported so no HTML5.
This is just a start and currently it can only read but not write, but I hope it will be useful for someone:
Example ini file:
Please note for those ini files: you can have comments everywhere but for a string value comments are currently ignored. Might add some quotes "" to mark the string.
Example usage:
Please let me know if you would like have anything added.
This is just a start and currently it can only read but not write, but I hope it will be useful for someone:
Code:
Strict
Import brl.filestream
Class KeyValuePair
Public
Field _isValid:Bool
Field _key:String
Field _value:String
End Class
Class IniHandler
Private
Field _sections:StringMap<StringMap<String>>
Field _modified:StringMap<StringMap<String>>
Field _iniString:String
Public
Method New()
_sections = New StringMap<StringMap<String>>()
_modified = New StringMap<StringMap<String>>()
End Method
Method open:Void(path:String)
Local file:FileStream = FileStream.Open("cerberus://data/" + path, "r")
If file
_iniString = file.ReadString()
file.Close()
Else
Print "File '" + path + "' not found!"
EndIf
refresh()
file.Close()
End Method
Method doesSectionExist:Bool(sectionName:String)
Return _sections.Contains(sectionName)
End Method
Method doesKeyExist:Bool(sectionName:String, key:String)
Local section:StringMap<String>
' check if the section exists
If _sections.Contains(sectionName)
section = _sections.Get(sectionName)
Return section.Contains(key)
Else
Return False
EndIf
End Method
Method readValue:String(sectionName:String, key:String, defaultValue:String)
If Not _sections.Contains(sectionName)
Return defaultValue
EndIf
Local section:StringMap<String>
section = _sections.Get(sectionName)
If Not section.Contains(key)
Return defaultValue
EndIf
Return section.Get(key)
End Method
Method readValue:Int(sectionName:String, key:String, defaultValue:Int)
Local str:String = readValue(sectionName, key, String(defaultValue))
str = splitComment(str)
Return Int(str)
End Method
Method readValue:Float(sectionName:String, key:String, defaultValue:Float)
Local str:String = readValue(sectionName, key, String(defaultValue))
str = splitComment(str)
Return Float(str)
End Method
Method readValue:Bool(sectionName:String, key:String, defaultValue:Bool)
Local defaultStr:String = "False"
If defaultValue Then defaultStr = "True"
Local str:String = readValue(sectionName, key, defaultStr)
str = splitComment(str)
If str.ToLower() = "true"
Return True
Else
Return False
EndIf
End Method
Method readArray:Int[](sectionName:String, key:String, defaultValue:Int[])
Local defaultStr:String
For Local i:Int = 0 Until defaultValue.Length
defaultStr += String(defaultValue[i])
If i < defaultValue.Length - 1
defaultStr += ","
EndIf
Next
Local str:String = readValue(sectionName, key, defaultStr)
str = splitComment(str)
Local val:String[] = str.Split(",")
' convert to int
Local valFinal:Int[] = New Int[val.Length]
For Local i:Int = 0 Until val.Length
valFinal[i] = Int(val[i])
Next
Return valFinal
End Method
Method readArray:Float[](sectionName:String, key:String, defaultValue:Float[])
Local defaultStr:String
For Local i:Int = 0 Until defaultValue.Length
defaultStr += String(defaultValue[i])
If i < defaultValue.Length - 1
defaultStr += ","
EndIf
Next
Local str:String = readValue(sectionName, key, defaultStr)
str = splitComment(str)
Local val:String[] = str.Split(",")
' convert to float
Local valFinal:Float[] = New Float[val.Length]
For Local i:Int = 0 Until val.Length
valFinal[i] = Float(val[i])
Next
Return valFinal
End Method
Method readArray:Bool[](sectionName:String, key:String, defaultValue:Bool[])
Local defaultStr:String
For Local i:Int = 0 Until defaultValue.Length
If defaultValue[i]
defaultStr += "True"
Else
defaultStr += "False"
EndIf
If i < defaultValue.Length - 1
defaultStr += ","
EndIf
Next
Local str:String = readValue(sectionName, key, defaultStr)
str = splitComment(str)
Local val:String[] = str.Split(",")
' convert to bool
Local valFinal:Bool[] = New Bool[val.Length]
For Local i:Int = 0 Until val.Length
If val[i].ToLower() = "true"
valFinal[i] = True
Else
valFinal[i] = False
EndIf
Next
Return valFinal
End Method
Private
Method refresh:Void()
' clear local cache
_sections.Clear()
_modified.Clear()
Local currentSection:StringMap<String> = Null
Local sectionName:String
Local lines:String[] = _iniString.Trim().Split("~n")
For Local str:String = EachIn lines
' remove possible "carriage return"
If str.EndsWith("~r")
str = str[..str.Length-1]
EndIf
' check for section names
sectionName = parseSectionName(str)
If sectionName.Length > 0
' only the first occurrence of a section is loaded
If _sections.Contains(sectionName)
currentSection = Null
Else
currentSection = New StringMap<String>()
_sections.Add(sectionName, currentSection)
EndIf
ElseIf currentSection <> Null
' check for key+value pair
Local keyValuePair:KeyValuePair = parseKeyValuePair(str)
If keyValuePair._isValid
' only the first occurrence of a key is loaded
If Not currentSection.Contains(keyValuePair._key)
currentSection.Add(keyValuePair._key, keyValuePair._value)
EndIf
EndIf
EndIf
Next
End Method
Method splitComment:String(str:String)
Local retStr:String[]
If str.Contains("//")
retStr = str.Split("//")
ElseIf str.Contains("#")
retStr = str.Split("#")
ElseIf str.Contains(";")
retStr = str.Split(";")
Else
retStr = New String[1]
retStr[0] = str
EndIf
Return retStr[0].Trim()
End Method
Method parseSectionName:String(s:String)
If s.StartsWith("//") Or s.StartsWith("#") Or s.StartsWith(";") ' comment
Return ""
EndIf
If Not s.StartsWith("[")
Return ""
EndIf
If Not s.EndsWith("]")
Return ""
EndIf
If s.Length < 3
Return ""
EndIf
Return s[1..s.Length-1]
End Method
Method parseKeyValuePair:KeyValuePair(s:String)
Local keyValuePair:KeyValuePair = New KeyValuePair()
If s.StartsWith("//") Or s.StartsWith("#") Or s.StartsWith(";") ' comment
keyValuePair._isValid = False
Return keyValuePair
EndIf
Local i:Int = s.Find("=")
If i = 0
keyValuePair._isValid = False
Return keyValuePair
EndIf
keyValuePair._key = s[0..i].Trim()
If keyValuePair._key.Length = 0
keyValuePair._isValid = False
Return keyValuePair
EndIf
Local j:Int = s.Length - i - 1
If j > 0
keyValuePair._value = s[i+1..].Trim()
Else
keyValuePair._value = ""
EndIf
keyValuePair._isValid = True
Return keyValuePair
End Method
End Class
Example ini file:
Code:
// This is a comment
# This too!
; another comment
[General]
StringVal = Hello World
FloatVal = 123.45 // some comment behind
IntVal = 123
BoolVal = false
IntArr = 1, 2, 3
FloatArr = 1.2, 3.4, 5.6
BoolArr = true, false, true
Please note for those ini files: you can have comments everywhere but for a string value comments are currently ignored. Might add some quotes "" to mark the string.
Example usage:
Code:
Local ini:IniHandler = New IniHandler()
Local file:FileStream = ini.open("config.ini")
Local sval:String = ini.readValue("General", "StringVal", "NOT SET")
Local ival:Int = ini.readValue("General", "IntVal", 0)
Local fval:Float = ini.readValue("General", "FloatVal", 0.0)
Local bval:Bool = ini.readValue("General", "BoolVal", False)
Local iarr:Int[] = ini.readArray("General", "IntArr", [1, 2, 3])
Local farr:Float[] = ini.readArray("General", "FloatArr", [1.0, 2.0, 3.0])
Local barr:Bool[] = ini.readArray("General", "BoolArr", [True, False, True])
Please let me know if you would like have anything added.
Last edited: