Simple Ini Reader

BlitzMax Forums/BlitzMax Module Tweaks/Simple Ini Reader

Vertex(Posted 2006) [#1]
Here is a simple Ini Reader wich accept only this quasi standard:

Ini     = {(Section{Key | ({blank} \n)})
          |({blank} \n)
          |Comment}.
Section = "[" Ident "]" [blank {blank} Comment] \n.
Key     = {blank} Ident {blank} "=" {blank} {character} [blank {blank} Comment] \n.
Comment = ";" {character} \n.
Ident   = Letter {Letter | Digit}.
Letter  = "A" | .. | "Z" | "a" | .. | "z".
Digit   = "0" | "1" | .. | "9".


(Ok, ok, identifier are not only constructed with letters and digits)

SuperStrict

Module PUB.IniReader

ModuleInfo "Version: 1.1"
ModuleInfo "Author: Oliver Skawronek"
ModuleInfo "License: Public Domain"

Import BRL.FileSystem
Import BRL.LinkedList

Type TIniReader
	Field Sections : TList

	Method New()
		Self.Sections = New TList
	End Method

	Method GetValue:String(Section:String, Key:String)
		Local Found:Int, Section2:TSection, Key2:TKey

		Section = Section.ToLower()
		Key     = Key.ToLower()
		For Section2 = EachIn Self.Sections
			If Section2.Name.ToLower() = Section Then
				Found = True
				Exit
			EndIf
		Next
		If Not Found Then Return ""

		For Key2 = EachIn Section2.Keys
			If Key2.Name.ToLower() = Key Then Return Key2.Value
		Next

		Return ""
	End Method

	Function Load:TIniReader(URL:Object)
		Local Stream:TStream, Reader:TIniReader, Section:TSection
		Local Key:TKey, Line:String, Position:Int, Found:Int

		Stream = ReadStream(URL)
		If Not Stream Then Return Null

		Reader = New TIniReader

		While Not Stream.EoF()
			Line = Stream.ReadLine()

			' Check for white spaces at the beginning
			If Line[0] = 9 Or Line[0] = 32 Then
				Found = 0
				For Position = 1 Until Line.Length
					If Line[Position] <> 9 And Line[Position] <> 32 Then
						Found = Position
						Exit
					EndIf
				Next

				' Trim white spaces
				Line = Line[Found..]

				' Only comments and keys can begin with white spaces
				If Line[0] = 91 Then
					Stream.Close()
					Throw "Sections can't begin with white spaces."
					Return Null
				EndIf
			EndIf

			' Check for a comment
			Found = Line.Find(";")
			If Found => 0 Then
				If Found > 0 And (Not (Line[Found - 1] = 9 Or ..
				                       Line[Found - 1] = 32)) Then
					Stream.Close()
					Throw "Expected spacing character before ';'."
					Return Null
				EndIf
				
				Line = Line[..Found]
			EndIf

			' Check for empty line
			If Line.Length = 0 Then Continue

			' Check for a section
			If Line[0] = 91 Then
				Found = 0
				For Position = 1 Until Line.Length
					If Line[Position] = 9 Or Line[Position] = 32 Then
						Stream.Close()
						Throw "Sectionnames can't contain white spaces."
						Return Null
					EndIf

					If Line[Position] = 93 Then
						Found = Position
						Exit
					EndIf
				Next

				If Not Found Then
					Stream.Close()
					Throw "Expected ']'."
					Return Null
				EndIf

				Section = New TSection
				Section.Name = Line[1..Found]

				Reader.Sections.AddLast(Section)
				Continue
			EndIf

			' Check if a section exists
			If Not Section
				Stream.Close()
				Throw "Expected '[Section]' before."
				Return Null
			EndIf

			' Check for a key
			Found = Line.Find("=")
			If Not Found Then
				Stream.Close()
				Throw "Expected '='."
				Return Null
			EndIf

			Found = 0
			For Position = 0 Until Line.Length
				If Found = 0 And (Line[Position] = 9 Or Line[Position] = 32) Then
					Found = Position
				ElseIf Found > 0 And Line[Position] <> 61 Then
					Stream.Close()
					Throw "Keynames can't contain white spaces."
					Return Null
				ElseIf Line[Position] = 61 Then
					Found = Position
					Exit
				EndIf
			Next

			Key = New TKey
			Key.Name  = Line[..Found].Replace(" ", "").Replace("	", "")
			Key.Value = Line[Found + 1..].Replace(" ", "").Replace("	", "")
			Section.Keys.AddLast(Key)
		Wend

		Stream.Close()
		Return Reader
	End Function
End Type

Type TSection
	Field Name : String
	Field Keys : TList

	Method New()
		Self.Keys = New TList
	End Method
End Type

Type TKey
	Field Name  : String
	Field Value : String
End Type


Example:
SuperStrict

Framework PUB.IniReader
Import BRL.StandardIO
Import BRL.PolledInput

Global Reader:TIniReader

Try
	Reader = TIniReader.Load("config.ini")
Catch Error:String
	Print "Ini Error:"
	Print Error
	WaitKey
	End
End Try

Print "Screen Height = "+Reader.GetValue("Screen", "Height")

WaitKey
End


config.ini
[Screen]
; Only 640*480, 800*600 and 1024*768
width=800
height=600
depth=32
fullscreen=False
VSync=False

[Music]
musicEnabled=False
musicVolume=100 ; 0 to 100 
sfxEnabled=True
sfxVolume=100


cu olli