[bmx] Read/Write INI File (BMX) by Perturbatio [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:43

Previous topic - Next topic

BlitzBot

Title : Read/Write INI File (BMX)
Author : Perturbatio
Posted : 1+ years ago

Description : Simple INI file reader/writer

Code :
Code (blitzmax) Select
SuperStrict

Function SplitString:TList(inString:String, Delim:String)
Local tempList : TList = New TList
Local currentChar : String = ""
Local count : Int = 0
Local TokenStart : Int = 0

If Len(Delim)<1 Then Return Null

inString = Trim(inString)

For count = 0 Until Len(inString)
If inString[count..count+1] = delim Then
tempList.AddLast(inString[TokenStart..Count])
TokenStart = count + 1
End If
Next
tempList.AddLast(inString[TokenStart..Count])
Return tempList
End Function


Type TIniSection
Field Name:String
Field Values:TMap


Method SetValue(key:String, value:Object)
Values.Insert(Key, Value)
End Method


Method GetValue:String(Key:String)
Return String(Values.ValueForKey(Key))
End Method


Method DeleteValue(Key:String)
Values.Remove(Key)
End Method


Method GetSectionText:String()
Local result:String = "["+Name+"]~r~n"

For Local s:Object = EachIn Values.keys()
result = result + String(s) + "=" + String(Values.ValueForKey(s)) + "~r~n"
Next

Return result+"~r~n"
End Method


Function Create:TIniSection(name:String)
Local tempSection:TIniSection = New TIniSection
tempSection.name = name
tempSection.Values = New TMap
Return tempSection
End Function

End Type



Type TSectionList
Field _Sections:TIniSection[]

Method GetSection:TIniSection(sectionName:String)

For Local section:TIniSection = EachIn _Sections
If section.Name = sectionName Then Return section
Next

Return Null

End Method


Method AddSection:TIniSection(sectionName:String)
Local currentLength:Int = Len(_Sections)

_Sections = _Sections[..currentLength+1]
_Sections[currentLength] = TIniSection.Create(sectionName)

Return _Sections[currentLength]
End Method


Method RemoveSection:Int(sectionName:String)
Local currentLength:Int = Len(_Sections)

For Local i:Int = 0 To currentLength-1
If _Sections[i].Name = sectionName Then
If i < currentLength-1 Then
For Local x:Int = i To currentLength-2
_Sections[x] = _Sections[x+1]
Next
EndIf
_Sections = _Sections[..currentLength-1]

Return True

EndIf
Next

Return False
End Method


Function Create:TSectionList()
Local tempSectionList:TSectionList = New TSectionList

Return tempSectionList
End Function

End Type



Type TPertIni
Field Filename:String
Field Loaded:Int
Field Saved:Int
Field Sections:TSectionList


Method Load:Int()
Local file:TStream
Local line:String
Local tempList:TList
Local tempArray:Object[]
Local currentSection:String = ""
Local error:String


If FileType(Filename) = 1 Then

file:TStream = ReadStream(FileName)

While Not Eof(file)

line = Trim(ReadLine(file))



If Not (Line[..1] = ";") Then

If Line[..1] = "[" And Line[Len(Line)-1..] = "]" Then
currentSection = Line[1..Len(Line)-1]

AddSection(currentSection)
Else
If Len(currentSection) > 0 And Len(line) > 0 Then
tempList = SplitString(Line, "=")
If tempList Then
tempArray = tempList.ToArray();
SetSectionValue(currentSection, String(tempArray[0]), String(tempArray[1]))
EndIf
Else If Len(Line) > 0 Then
Return False 'no section header found'
EndIf
EndIf
EndIf
Wend

CloseStream(file)

EndIf

Return False
End Method


Method Save:Int(Overwrite:Int = False)
Local file:TStream
Local ft:Int = FileType(Filename)

If ft = 0  Or (ft = 1 And Overwrite = True) Then
file:TStream = WriteStream(FileName)
WriteString(file, GetIniText())
CloseStream(file)
Else
Return False
EndIf

End Method


Method AddSection:TIniSection(sectionName:String)
Return Sections.AddSection(sectionName)
End Method


Method GetSection:TIniSection(sectionName:String)
Return Sections.GetSection(sectionName)
End Method


Method SetSectionValue(sectionName:String, key:String, value:String)
For Local i:Int = 0 To Len(Sections._Sections) -1
If Sections._Sections[i].name = sectionName Then
Sections._Sections[i].SetValue(key, value)
Return
EndIf
Next
End Method


Method DeleteSectionValue(sectionName:String, key:String)
For Local i:Int = 0 To Len(Sections._Sections) -1
If Sections._Sections[i].name = sectionName Then
Sections._Sections[i].DeleteValue(key)
Return
EndIf
Next
End Method


Method GetSectionValue:String(sectionName:String, key:String)
For Local i:Int = 0 To Len(Sections._Sections) -1
If Sections._Sections[i].name = sectionName Then
Return Sections._Sections[i].GetValue(key)
EndIf
Next
End Method


Method GetIniText:String()
Local result:String
For Local section:TIniSection = EachIn Sections._Sections
result:+section.GetSectionText()
Next
Return result
End Method


Function Create:TPertIni(filename:String)
Local tempIni:TPertIni = New TPertIni
tempIni.Filename = filename
tempIni.Sections:TSectionList = TSectionList.Create()
Return tempIni
End Function
End Type


Local ini:TPertIni = TPertIni.Create("test.ini")
'ini.AddSection("testSection")

'ini.SetSectionValue("testSection", "testValue", "1200")
'ini.SetSectionValue("testSection", "testValue2", "1300")
'ini.SetSectionValue("testSection", "testValue3", "1500")
'ini.SetSectionValue("testSection", "testValue5=4", "1700")

ini.Load()
Print ini.GetIniText()
Print "value:  " + ini.getSectionValue("testSection", "testValue2")
Print "value2: " + ini.getSectionValue("testSection2", "testValue2")
'ini.DeleteSectionValue("testSection", "testValue2")
'ini.Save(True)


Comments :


watusimoto(Posted 1+ years ago)

 Here's an improved version that handles comments and whitespace in the INI better...  Note that the code use is identical -- all changes made are internal and transparent to the developer.

Function SplitString:TList(inString:String, Delim:String)
Local tempList : TList = New TList
Local currentChar : String = ""
Local count : Int = 0
Local TokenStart : Int = 0

If Len(Delim)<1 Then Return Null

inString = Trim(inString)

For count = 0 Until Len(inString)
If inString[count..count+1] = delim Then
tempList.AddLast(inString[TokenStart..Count])
TokenStart = count + 1
End If
Next
tempList.AddLast(inString[TokenStart..Count])
Return tempList
End Function


Type TIniSection
Field Name:String
Field Values:TMap


Method SetValue(key:String, value:Object)
Values.Insert(Key, Value)
End Method


Method GetValue:String(Key:String)
Return String(Values.ValueForKey(Key))
End Method


Method DeleteValue(Key:String)
Values.Remove(Key)
End Method


Method GetSectionText:String()
Local result:String = "["+Name+"]~r~n"

For Local s:Object = EachIn Values.keys()
result = result + String(s) + "=" + String(Values.ValueForKey(s)) + "~r~n"
Next

Return result+"~r~n"
End Method


Function Create:TIniSection(name:String)
Local tempSection:TIniSection = New TIniSection
tempSection.name = name
tempSection.Values = New TMap
Return tempSection
End Function

End Type



Type TSectionList
Field _Sections:TIniSection[]

Method GetSection:TIniSection(sectionName:String)

For Local section:TIniSection = EachIn _Sections
If section.Name = sectionName Then Return section
Next

Return Null

End Method


Method AddSection:TIniSection(sectionName:String)
Local currentLength:Int = Len(_Sections)

_Sections = _Sections[..currentLength+1]
_Sections[currentLength] = TIniSection.Create(sectionName)

Return _Sections[currentLength]
End Method


Method RemoveSection:Int(sectionName:String)
Local currentLength:Int = Len(_Sections)

For Local i:Int = 0 To currentLength-1
If _Sections[i].Name = sectionName Then
If i < currentLength-1 Then
For Local x:Int = i To currentLength-2
_Sections[x] = _Sections[x+1]
Next
EndIf
_Sections = _Sections[..currentLength-1]

Return True

EndIf
Next

Return False
End Method


Function Create:TSectionList()
Local tempSectionList:TSectionList = New TSectionList

Return tempSectionList
End Function

End Type



Type TPertIni
Field Filename:String
Field Loaded:Int
Field Saved:Int
Field Sections:TSectionList


Method Load:Int()
Local file:TStream
Local line:String
Local tempList:TList
Local tempArray:Object[]
Local currentSection:String = ""
Local error:String


If FileType(Filename) = 1 Then

file:TStream = ReadStream(FileName)

While Not Eof(file)

line = cleanVal(ReadLine(file))


If Not (Line[..1] = ";") Then

If Line[..1] = "[" And Line[Len(Line)-1..] = "]" Then
currentSection = Line[1..Len(Line)-1]

AddSection(currentSection)
Else
If Len(currentSection) > 0 And Len(line) > 0 Then
tempArray = smartSplit(Line, "=")
If tempArray <> NULL
SetSectionValue(currentSection, String(tempArray[0]).trim(), String(tempArray[1]).trim())
EndIf
Else If Len(Line) > 0 Then
Return False 'no section header found'
EndIf
EndIf
EndIf
Wend

CloseStream(file)

EndIf

Return False
End Method


Method Save:Int(Overwrite:Int = False)
Local file:TStream
Local ft:Int = FileType(Filename)

If ft = 0  Or (ft = 1 And Overwrite = True) Then
file:TStream = WriteStream(FileName)
WriteString(file, GetIniText())
CloseStream(file)
Else
Return False
EndIf

End Method


Method AddSection:TIniSection(sectionName:String)
Return Sections.AddSection(sectionName)
End Method


Method GetSection:TIniSection(sectionName:String)
Return Sections.GetSection(sectionName)
End Method


Method SetSectionValue(sectionName:String, key:String, value:String)
For Local i:Int = 0 To Len(Sections._Sections) -1
If Sections._Sections[i].name = sectionName Then
Sections._Sections[i].SetValue(key, value)
Return
EndIf
Next
End Method


Method DeleteSectionValue(sectionName:String, key:String)
For Local i:Int = 0 To Len(Sections._Sections) -1
If Sections._Sections[i].name = sectionName Then
Sections._Sections[i].DeleteValue(key)
Return
EndIf
Next
End Method


Method GetSectionValue:String(sectionName:String, key:String)
For Local i:Int = 0 To Len(Sections._Sections) -1
If Sections._Sections[i].name = sectionName Then
Return Sections._Sections[i].GetValue(key)
EndIf
Next
End Method


Method GetIniText:String()
Local result:String
For Local section:TIniSection = EachIn Sections._Sections
result:+section.GetSectionText()
Next
Return result
End Method


Function Create:TPertIni(filename:String)
Local tempIni:TPertIni = New TPertIni
tempIni.Filename = filename
tempIni.Sections:TSectionList = TSectionList.Create()
Return tempIni
End Function
End Type





'###############################################################################
' Trim any whitespace or comments from value

function cleanVal:string(s:string)

if s then return smartSplit(s.trim(),";")[0] else return null

end function

'###############################################################################
' Split a string into substrings
' From <a href="codearcs5798.html?code=1560" target="_blank">http://www.blitzbasic.com/codearcs/codearcs.php?code=1560</a>
' by CoderLaureate, bug fix by Chris Eykamp
' This code has been declared by its author to be Public Domain code.

Function SmartSplit:String[](str:String, dels:String, text_qual:String = "~q")
Local Parms:String[] = New String[1]
Local pPtr:Int = 0
Local chPtr:Int = 0
Local delPtr:Int = 0
Local qt:Int = False
Local str2:String = ""

Repeat
Local del:String = Chr(dels[delPtr])
Local ch:String = Chr(str[chPtr])
If ch = text_qual Then
If qt = False Then
qt = True
Else
qt = False
End If
End If
If ch = del Then
If qt = True Then str2:+ ch
Else
str2:+ ch
End If
If ch = del Or chPtr = str.Length - 1 Then
If qt = False Then
Parms[pPtr] = str2.Trim()
str2 = ""
pPtr:+ 1
Parms = Parms[..pPtr + 1]
If dels.length > 1 And delPtr < dels.length Then delPtr:+ 1
End If
End If
chPtr:+ 1
If chPtr >= str.Length Then Exit
Forever
If Parms.Length > 1 Then Parms = Parms[..Parms.Length - 1]
Return Parms

End Function



Perturbatio(Posted 1+ years ago)

 nice :)I really should have implemented the loaded and saved properties...


watusimoto(Posted 1+ years ago)

 Another slight enhancement, to better handle empty values (lines like key= )' Code for handling INI files, taken from BlitzBasic forums, by Perturbatio
' <a href="http://www.blitzmax.com/codearcs/codearcs.php?code=1890" target="_blank">http://www.blitzmax.com/codearcs/codearcs.php?code=1890</a>
' Modified by Chris Eykamp to make it more flexible
' Code in this section is public domain

' CE   Apr-2007 Better support for comments and whitespace in INI file
' CE 26-Apr-2007 Fixed problem with empty values (lines that look like key =)

Function SplitString:TList(inString:String, Delim:String)
Local tempList : TList = New TList
Local currentChar : String = ""
Local count : Int = 0
Local TokenStart : Int = 0

If Len(Delim)<1 Then Return Null

inString = Trim(inString)

For count = 0 Until Len(inString)
If inString[count..count+1] = delim Then
tempList.AddLast(inString[TokenStart..Count])
TokenStart = count + 1
End If
Next
tempList.AddLast(inString[TokenStart..Count])
Return tempList
End Function


Type TIniSection
Field Name:String
Field Values:TMap


Method SetValue(key:String, value:Object)
Values.Insert(Key, Value)
End Method


Method GetValue:String(Key:String)
Return String(Values.ValueForKey(Key))
End Method


Method DeleteValue(Key:String)
Values.Remove(Key)
End Method


Method GetSectionText:String()
Local result:String = "["+Name+"]~r~n"

For Local s:Object = EachIn Values.keys()
result = result + String(s) + "=" + String(Values.ValueForKey(s)) + "~r~n"
Next

Return result+"~r~n"
End Method


Function Create:TIniSection(name:String)
Local tempSection:TIniSection = New TIniSection
tempSection.name = name
tempSection.Values = New TMap
Return tempSection
End Function

End Type



Type TSectionList
Field _Sections:TIniSection[]

Method GetSection:TIniSection(sectionName:String)

For Local section:TIniSection = EachIn _Sections
If section.Name = sectionName Then Return section
Next

Return Null

End Method


Method AddSection:TIniSection(sectionName:String)
Local currentLength:Int = Len(_Sections)

_Sections = _Sections[..currentLength+1]
_Sections[currentLength] = TIniSection.Create(sectionName)

Return _Sections[currentLength]
End Method


Method RemoveSection:Int(sectionName:String)
Local currentLength:Int = Len(_Sections)

For Local i:Int = 0 To currentLength-1
If _Sections[i].Name = sectionName Then
If i < currentLength-1 Then
For Local x:Int = i To currentLength-2
_Sections[x] = _Sections[x+1]
Next
EndIf
_Sections = _Sections[..currentLength-1]

Return True

EndIf
Next

Return False
End Method


Function Create:TSectionList()
Local tempSectionList:TSectionList = New TSectionList

Return tempSectionList
End Function

End Type



Type TPertIni
Field Filename:String
Field Loaded:Int
Field Saved:Int
Field Sections:TSectionList


Method Load:Int()
Local file:TStream
Local line:String
Local tempList:TList
Local tempArray:Object[]
Local currentSection:String = ""
Local error:String
local v:string


If FileType(Filename) = 1 Then

file:TStream = ReadStream(FileName)

While Not Eof(file)

line = cleanVal(ReadLine(file))


If Not (Line[..1] = ";") Then ' Skip lines that are just comments

If Line[..1] = "[" And Line[Len(Line)-1..] = "]" Then
currentSection = Line[1..Len(Line)-1]

AddSection(currentSection)
Else
If Len(currentSection) > 0 And Len(line) > 0 Then
tempArray = smartSplit(Line, "=")
If tempArray <> NULL

if tempArray.length > 1 then
v = String(tempArray[1]).trim()
else
v = ""
endif

SetSectionValue(currentSection, String(tempArray[0]).trim(), v)
EndIf
Else If Len(Line) > 0 Then
Return False 'no section header found'
EndIf
EndIf
EndIf
Wend

CloseStream(file)

EndIf

Return False
End Method


Method Save:Int(Overwrite:Int = False)
Local file:TStream
Local ft:Int = FileType(Filename)

If ft = 0  Or (ft = 1 And Overwrite = True) Then
file:TStream = WriteStream(FileName)
WriteString(file, GetIniText())
CloseStream(file)
Else
Return False
EndIf

End Method


Method AddSection:TIniSection(sectionName:String)
Return Sections.AddSection(sectionName)
End Method


Method GetSection:TIniSection(sectionName:String)
Return Sections.GetSection(sectionName)
End Method


Method SetSectionValue(sectionName:String, key:String, value:String)
For Local i:Int = 0 To Len(Sections._Sections) -1
If Sections._Sections[i].name = sectionName Then
Sections._Sections[i].SetValue(key, value)
Return
EndIf
Next
End Method


Method DeleteSectionValue(sectionName:String, key:String)
For Local i:Int = 0 To Len(Sections._Sections) -1
If Sections._Sections[i].name = sectionName Then
Sections._Sections[i].DeleteValue(key)
Return
EndIf
Next
End Method


Method GetSectionValue:String(sectionName:String, key:String)
For Local i:Int = 0 To Len(Sections._Sections) -1
If Sections._Sections[i].name = sectionName Then
Return Sections._Sections[i].GetValue(key)
EndIf
Next
End Method


Method GetIniText:String()
Local result:String
For Local section:TIniSection = EachIn Sections._Sections
result:+section.GetSectionText()
Next
Return result
End Method


Function Create:TPertIni(filename:String)
Local tempIni:TPertIni = New TPertIni
tempIni.Filename = filename
tempIni.Sections:TSectionList = TSectionList.Create()
Return tempIni
End Function
End Type





'###############################################################################
' Trim any whitespace or comments from value

function cleanVal:string(s:string)

if s then return smartSplit(s.trim(),";")[0] else return null

end function

'###############################################################################
' Split a string into substrings
' From <a href="codearcs5798.html?code=1560" target="_blank">http://www.blitzbasic.com/codearcs/codearcs.php?code=1560</a>
' by CoderLaureate, bug fix by Chris Eykamp
' This code has been declared by its author to be Public Domain code.

Function SmartSplit:String[](str:String, dels:String, text_qual:String = "~q")
Local Parms:String[] = New String[1]
Local pPtr:Int = 0
Local chPtr:Int = 0
Local delPtr:Int = 0
Local qt:Int = False
Local str2:String = ""

Repeat
Local del:String = Chr(dels[delPtr])
Local ch:String = Chr(str[chPtr])
If ch = text_qual Then
If qt = False Then
qt = True
Else
qt = False
End If
End If
If ch = del Then
If qt = True Then str2:+ ch
Else
str2:+ ch
End If
If ch = del Or chPtr = str.Length - 1 Then
If qt = False Then
Parms[pPtr] = str2.Trim()
str2 = ""
pPtr:+ 1
Parms = Parms[..pPtr + 1]
If dels.length > 1 And delPtr < dels.length Then delPtr:+ 1
End If
End If
chPtr:+ 1
If chPtr >= str.Length Then Exit
Forever
If Parms.Length > 1 Then Parms = Parms[..Parms.Length - 1]
Return Parms

End Function



Crovean(Posted 1+ years ago)

 I'm quite new to BlitzMax so could you please post an example how to use this? I would like to use INI files with the applications I make... Thanks in advance :)


Guy Fawkes(Posted 1+ years ago)

 can someone plz convert to b3d?


_PJ_(Posted 1+ years ago)

 
Quotecan someone plz convert to b3d?/quote]It may need some cleaning up, and it's only the reading, but the essentials are all there:<a href="codearcs6870.html?code=2621" target="_blank">http://www.blitzbasic.com/codearcs/codearcs.php?code=2621</a> [/i]