Code archives/File Utilities/Read/Write INI File (BMX)
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
Simple INI file reader/writer | |||||
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
| ||
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 http://www.blitzbasic.com/codearcs/codearcs.php?code=1560 ' 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 |
| ||
nice :) I really should have implemented the loaded and saved properties... |
| ||
Another slight enhancement, to better handle empty values (lines like key= )' Code for handling INI files, taken from BlitzBasic forums, by Perturbatio ' http://www.blitzmax.com/codearcs/codearcs.php?code=1890 ' 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 http://www.blitzbasic.com/codearcs/codearcs.php?code=1560 ' 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 |
| ||
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 :) |
| ||
can someone plz convert to b3d? |
| ||
[quote]can someone plz convert to b3d?/quote] It may need some cleaning up, and it's only the reading, but the essentials are all there: http://www.blitzbasic.com/codearcs/codearcs.php?code=2621 |
Code Archives Forum