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] [EINKLAPPEN] 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
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
Method ReOpen(rgchName:String) Self._File.Close() Self.Init(Self._Template,rgchName,Self._Strict,Self._chComment) End Method
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 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 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
Method chComment:String() Return Self._chComment End Method End Type
Type TINITemplate Field _NullSequence:TSequence Field _rgchName:String Field _rgSequence:TMap Field _CurrentSequence:TSequence
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
Method AddSequence(rgchName:String) Local Sequence:TSequence=TSequence.Create(rgchName) Self._CurrentSequence=Sequence End Method
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
Method RestoreSequence(rgchName:String) Self._CurrentSequence=Self.SequenceLookUp(rgchName) End Method
Method AddKey(rgchName:String,Action:Object) Self.CurrentSequence().AddKey(rgchName,Action) End Method
Method HasSequence:Byte(rgch:String) If rgch<>"" Return Self._rgSequence.Contains(rgch) Else Return True End If End Method
Method SequenceLookUp:TSequence(rgch:String) If rgch<>"" Return TSequence(Self._rgSequence.ValueForKey(rgch)) Else Return Self._NullSequence End If End Method
Method CurrentSequence:TSequence() Return Self._CurrentSequence End Method End Type
Type TSequence Field _rgchName:String Field _rgKey:TMap
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
Method HasKey:Byte(rgch:String) Return Self._rgKey.Contains(rgch) End Method
Method KeyLookUp:TKey(rgch:String) Return TKey(Self._rgKey.ValueForKey(rgch)) End Method
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
Method Name:String() Return Self._rgchName End Method End Type
Type TKey Field _rgchName:String Field _Content:TMember
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
Method Name:String() Return Self._rgchName End Method
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
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] [EINKLAPPEN] SuperStrict
Framework BRL.Blitz
Import BRL.Reflection Import "INILoader.bmx"
Type TTest Field Name:String,Example:String Field Size:Int[2],Depth:Int 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")
Local Template:TINITemplate=TINITemplate.Create("Settings")
Template.AddSequence("Settings")
Template.AddKey("Width",TypeID.FindMethod("Width")) Template.AddKey("Height",TypeID.FindMethod("Height")) Template.AddKey("Depth",TypeID.FindMethod("SetDepth"))
Template.FinishSequence()
Template.AddKey("Name",TypeID.FindField("Name")) Template.AddKey("Example",TypeID.FindField("Example"))
Local INI:TINI=TINI.Create(Template,"settings.ini",True)
Local Test:TTest=New TTest
INI.Read(Test)
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] [EINKLAPPEN] #Comment
Name=hgea #Comment
Example=hfu3
[Settings]#Comment
Width=1234
Depth=60
Height=123
[Example]
thing=error
Im Test nicht genutzte Funktionalitäten:
ReOpen des Types TINI: Diese Methode öffnet eine neue INI-Datei mit ansonsten gleichen Parametern.
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.
|