INI-Reader

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

 

n-Halbleiter

Betreff: INI-Reader

BeitragDi, März 30, 2010 3:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Guten Morgen BBP!

Ja, ich weiß, noch ein INI-Reader. Aber dieser ist leicht verschieden zu anderen. Es beginnt schon beim Aufgabenfeld: Er ist nur für das Auslesen aus einer INI in Types gedacht. Zusätzlich wurde er darauf konzipiert, dass er mit Templates arbeitet, sodass er nützlich ist, um beispielsweise Baupläne (also im Allgemeinen gesagt: Gleiche Informationen in der INI) zu Laden. Er besitzt ferner keine Schreibfunktionen, sondern ist nur zum Auslesen gedacht.

Es muss eine Datei importiert werden, nämlich "INILoader.bmx" (oder wie ihr sie nennen mögt). Nachdem dies geschehen ist, können Templates erstellt und Sequenzen und Schlüssel registriert werden. Die Handhabung dürfte aus dem Beispiel klar werden.

Zuerst die Import-Datei "INILoader.bmx". BlitzMax: [AUSKLAPPEN]
SuperStrict

Import BRL.Blitz
Import BRL.Retro
Import BRL.Map
Import BRL.FileSystem
Import BRL.Reflection

Type TINI

Field _Template:TINITemplate
Field _File:TStream
Field _chComment:String
Field _CurrentSequence:TSequence
Field _Strict:Byte

'Constructors & Destructor
Rem
The constructor. It needs a TINITemplate, the filename of the INI you want to become read, the mode of reading (Strict/Nonstrict) and the comment signing character.
End Rem

Function Create:TINI(Template:TINITemplate,rgchFile:String,StrictMode:Byte=True,chComment:String="#")
Local INI:TINI=New TINI
INI.Init(Template,rgchFile,StrictMode,chComment)
Return INI
End Function

Method Init(Template:TINITemplate,rgchFile:String,StrictMode:Byte,chComment:String)
Self._Template=Template
Self._CurrentSequence=Self._Template._NullSequence
Self._Strict=StrictMode
Self._chComment=Chr(chComment[0])
If FileType(rgchFile)<>FILETYPE_FILE
DebugLog "TINI.Create(): Ini "+rgchFile+" has not been found. This instance of TINI is useless."
Else
Self._File=ReadFile(rgchFile)
End If
End Method

Method Delete()
Self._File.Close()
Self._Template:TINITemplate=Null
End Method

'Actions
Rem
Reopens the INIFile with a different file.
End Rem

Method ReOpen(rgchName:String)
Self._File.Close()
Self.Init(Self._Template,rgchName,Self._Strict,Self._chComment)
End Method

Rem
The method of an TINI-object to read the whole INI-File into the specified object (Parameter).
End Rem

Method Read:Byte(Obj:Object)
Local rgch:String,Args:String[]
While Not Eof(Self._File)
rgch=Self._File.ReadLine()
rgch=BeforeFirst(rgch,Self.chComment())
If rgch<>""
Select rgch[0]
Case 91'Section
'Strip Parentheses
rgch=rgch[1..rgch.length-1]
If Self._Template.HasSequence(Lower(rgch))
Self._CurrentSequence=Self._Template.SequenceLookUp(Lower(rgch))
Else
DebugLog "TINI.Read(): Sequence '"+rgch+"' not found.~n Template: "+Self._Template._rgchName
If Self._Strict Then Return False
End If
Default'Regular processed line
Args=rgch.Split("=")
Args[0]=Args[0].Trim()
Args[1]=Args[1].Trim()
If Self._CurrentSequence.HasKey(Lower(Args[0]))
Self._CurrentSequence.KeyLookUp(Lower(Args[0])).SetValue(Obj,Args[1])
Else
DebugLog "TINI.Read(): Key '"+rgch+"' not found in sequence '"+Self._CurrentSequence.Name()+"'~n Template: "+Self._Template._rgchName
If Self._Strict Then Return False
End If
End Select
End If
Wend
Return True
End Method

'Getters & Setters
Rem
This Getter returns the comment signing character
End Rem

Method chComment:String()
Return Self._chComment
End Method

End Type

Type TINITemplate

Field _NullSequence:TSequence'=TSequence.Create("")
Field _rgchName:String
Field _rgSequence:TMap
Field _CurrentSequence:TSequence

'Constructors & Destructor
Rem
The constructor. It takes the name of the INITemplate as a parameter
End Rem

Function Create:TINITemplate(rgchName:String)
Local Template:TINITemplate=New TINITemplate
Template.Init(rgchName)
Return Template
End Function

Method Init(rgchName:String)
Self._rgSequence=CreateMap()
Self._NullSequence=TSequence.Create("")
Self._rgSequence.Insert("",Self._NullSequence)
Self._rgchName=rgchName
End Method

Method Delete()
Self._rgSequence=Null
End Method

'Registration functions
Rem
This method adds a sequence (or section) to the template. The string parameter is the name of the sequence
End Rem

Method AddSequence(rgchName:String)
Local Sequence:TSequence=TSequence.Create(rgchName)
Self._CurrentSequence=Sequence
End Method

Rem
Registrates the current sequence (created with "AddSequence") in the map of sequences and sets the current sequence to Null.
End Rem

Method FinishSequence()
If Self.HasSequence(Self._CurrentSequence.Name())=False Then Self._rgSequence.Insert(Lower(Self._CurrentSequence.Name()),Self._CurrentSequence)
Self._CurrentSequence=Self._NullSequence
End Method

Rem
Restores the sequence with the specified name and sets it as current sequence.
End Rem

Method RestoreSequence(rgchName:String)
Self._CurrentSequence=Self.SequenceLookUp(rgchName)
End Method

Rem
Adds a key to the current sequence.
End Rem

Method AddKey(rgchName:String,Action:Object)
Self.CurrentSequence().AddKey(rgchName,Action)
End Method

'Interfacing
Rem
Returns whether the specified sequence is in the map of registrated sequences
End Rem

Method HasSequence:Byte(rgch:String)
If rgch<>""
Return Self._rgSequence.Contains(rgch)
Else
Return True
End If
End Method

Rem
Returns the sequence object with the specified name. It is possible to recieve the NullSequence (named "").
End Rem

Method SequenceLookUp:TSequence(rgch:String)
If rgch<>""
Return TSequence(Self._rgSequence.ValueForKey(rgch))
Else
Return Self._NullSequence
End If
End Method

'Getters & Setters
Rem
Returns the current sequence
End Rem

Method CurrentSequence:TSequence()
Return Self._CurrentSequence
End Method

End Type

Type TSequence

Field _rgchName:String
Field _rgKey:TMap

'Constructors & Destructor
Rem
The Constructor. It recieves the name of the sequence as a parameter.
End Rem

Function Create:TSequence(rgchName:String)
Local Sequence:TSequence=New TSequence
Sequence.Init(rgchName)
Return Sequence
End Function

Method Init(rgchName:String)
Self._rgchName=rgchName
Self._rgKey=CreateMap()
End Method

Method Delete()
Self._rgKey=Null
End Method

'Interfacing
Rem
Returns whether the sequence conains the specified key.
End Rem

Method HasKey:Byte(rgch:String)
Return Self._rgKey.Contains(rgch)
End Method

Rem
Returns the key with the specified name.
End Rem

Method KeyLookUp:TKey(rgch:String)
Return TKey(Self._rgKey.ValueForKey(rgch))
End Method

'Registration functions
Rem
Adds a key to the pool of keys with the specified name.
End Rem

Method AddKey(rgchName:String,Action:Object)
Local Key:TKey=TKey.Create(rgchName)
If TField(Action) Or TMethod(Action)
Key._Content=TMember(Action)
End If
Self._rgKey.Insert(Lower(Key.Name()),Key)
End Method

'Getters & Setters
Rem
Returns the Name of the key
End Rem

Method Name:String()
Return Self._rgchName
End Method

End Type

Type TKey

Field _rgchName:String
Field _Content:TMember

'Constructors & Destructor
Rem
The constructor. It takes the name of the key as an argument.
End Rem

Function Create:TKey(rgchName:String)
Local Key:TKey=New TKey
Key.Init(rgchName)
Return Key
End Function

Method Init(rgchName:String)
Self._rgchName=rgchName
End Method

Method Delete()
Self._rgchName=Null
Self._Content=Null
End Method

'Setters & Getters
Rem
Returns the name of the key.
End Rem

Method Name:String()
Return Self._rgchName
End Method

Rem
Executes the action of the key to the specified object (CurrentObj) with the specified parameters (Value).
End Rem

Method SetValue(CurrentObj:Object,Value:Object)
If TField(Self._Content)
TField(Self._Content).Set(CurrentObj,Value)
Else If TMethod(Self._Content)
TMethod(Self._Content).Invoke(CurrentObj,[Value])
End If
End Method

End Type

'Helper function
Function BeforeFirst:String(rgch:String,ch:String)
Local ich:Int=Instr(rgch,ch)
If ich<>0
Return rgch[..ich-1]
Else
Return rgch
End If
End Function


Das Beispiel. BlitzMax: [AUSKLAPPEN]
SuperStrict

Framework BRL.Blitz

Import BRL.Reflection 'Das ist nötig, damit man auf Member von Types zugreifen kann. Daran denken, wenn man ein Framework benutzt, ansonsten kann man es weglassen.
Import "INILoader.bmx"

Type TTest

Field Name:String,Example:String
Field Size:Int[2],Depth:Int

'Methoden, die als Aktionen dienen können.
Method Width(rgch:String)
Self.Size[0]=Int(rgch)
End Method

Method Height(rgch:String)
Self.Size[1]=Int(rgch)
End Method

Method SetDepth(rgch:String)
Self.Depth=Int(rgch)/20
End Method

End Type

Local TypeID:TTypeId=TTypeId.ForName("TTest")'Für die grundsätzliche Verwendung von Reflection bitte in die Doku schauen.

Local Template:TINITemplate=TINITemplate.Create("Settings")

Template.AddSequence("Settings")

Template.AddKey("Width",TypeID.FindMethod("Width"))'Klappt mit Methoden
Template.AddKey("Height",TypeID.FindMethod("Height"))
Template.AddKey("Depth",TypeID.FindMethod("SetDepth"))

Template.FinishSequence()'Die NullSequence ist nun die aktuelle Sequenz

Template.AddKey("Name",TypeID.FindField("Name"))'Und klappt auch mit Fields.
Template.AddKey("Example",TypeID.FindField("Example"))

'Hiermit wäre das INITemplate fertig präpariert.

'Mit diesem Aufruf wird die INI-Datei geöffnet und zum Laden vorbereitet. Spielt mal mit dem dritten Parameter herum, er ändert das Verhalten im Fehlerfall (in der INI ist ein solcher schon "eingebaut").
Local INI:TINI=TINI.Create(Template,"settings.ini",True)
'Der letzte, optionale Parameter bestimmt das Kommentarzeichen, also das Zeichen, mit dem ein Kommentar eingeläutet wird.

Local Test:TTest=New TTest'Wir benötigen eine Instanz von TTest.

INI.Read(Test)'Und lesen die Inhalte der INI in unsere Instanz hinein.

'Nun zum überprüfen, dass alle Werte korrekt gesetzt wurden.
Print Test.Name
Print Test.Example
Print Test.Size[0]+","+Test.Size[1]
Print Test.Depth


Und als letztes noch die verwendete INI-Datei "settings.ini".Code: [AUSKLAPPEN]
#Comment

Name=hgea #Comment
Example=hfu3
[Settings]#Comment
Width=1234
Depth=60
Height=123
[Example]
thing=error


Im Test nicht genutzte Funktionalitäten:
Arrow ReOpen des Types TINI: Diese Methode öffnet eine neue INI-Datei mit ansonsten gleichen Parametern.
Arrow RestoreSequence des Types TINITemplate: Diese Methode setzt eine vorher erstellte und fertiggestellte Sequenz als aktuelle Sequenz.

Anmerkung an diejenigen, die den Code in "INILoader.bmx" verstehen wollen: Es ist z.T. ungarische Notation und sämtliche Fields eines Types beginnen mit einem Unterstrich. Auch könnte die Angewohnheit von mir, einmal die Function "Create" und die Methode "Init" zu verwenden, suspekt vorkommen.
mfg, Calvin
Maschine: Intel Core2 Duo E6750, 4GB DDR2-Ram, ATI Radeon HD4850, Win 7 x64 und Ubuntu 12.04 64-Bit
Ploing!
Blog

"Die Seele einer jeden Ordnung ist ein großer Papierkorb." - Kurt Tucholsky (09.01.1890 - 21.12.1935)

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group