Code archives/File Utilities/INI-format data files
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| INI is a simple file format for storing data (usually configuration settings, but potentially anything) in a format that is easy for humans to read and edit as text files (Wikipedia). The format is very simple. Data is held in properties, which are a key/value pair where a name key is associated with a value using the = operator. Properties can be grouped in sections, where a name key in square brackets marks that the following properties belong to the section of that name. And like in Blitz3D, any text following a semicolon is a comment and is ignored by the loader. The main thing of note is that unlike some other serialization formats (such as XML), sections do not "nest", and the file is completely flat. This means less stuff on screen (at the cost of some structural expression), making them easier to use when you want the end user to be able to edit the file (e.g. to play with settings). Details: In this implementation, name keys (for both section and property names) may use any of the letters A-Z, a-z (case sensitive), 0-9, and the characters \ : . and _. Value strings (the part of a property to the right of the = operator) may consist of any characters, but will end at the newline or a semicolon marking a comment. Between double-quotes, the semicolon may appear (and quotes themselves may be escaped with a backslash) without starting a comment. If an open-brace appears, the text following will be treated as part of the value string until the matching close-brace appears (each open-brace within the string must be matched by a close-brace before the quoted string ends), which allows the string to include newlines and span many lines of text. Everything (whitespace, semicolons) within a braced or quoted section of string is preserved, but if the string is completely enclosed in quotes or braces, the outermost quote/brace characters are removed. Unquoted whitespace is stripped from the ends of the value. Use: Despite requiring a flat structure, the INI format can store any kind of structured data that can be represented in string form; instead of nesting objects, another section can represent the nested structure, and its "owner" can store a string key, simply listing its section name. It is also possible to store another INI structure within a braced block value, although the result string will have to be parsed separately. Levels, game settings, game rules (such as weapon stats) or even 3D models can be stored easily with this file format. INI structures can be either created empty, or loaded from a file or string (useful for sub-structures), with the provided constructor and loader functions. Sections and properties may be both added and removed, and the values of properties both read and assigned. Once the structure has been suitably edited, it can be saved back to a file, or a single string (if the structure was created rather than loaded, the library will attempt to format it slightly for readability as well; otherwise it will preserve the original formatting). Properties may be accessed either as a member of a section, or without specifying the section, in which case the first matching property in the entire structure is returned (using sections is wholly optional). It is also possible to delete a section but leave its properties in place. Any duplicate names (either of sections or properties) are not in error, but instead only the first matching name will be "found" and the second and others will be hidden until the first is deleted (properties of the same name in different sections may be accessed by specifying the section). In the event of any error, the function "LogError" is called with details, and the function where an error occurred will try to return gracefully with a null value. This means that nonexistent names are not a program-breaking error. "LogError" itself is not provided and should be linked to an appropriate error logging function for your program (since the errors will reflect user-edited data, this probably shouldn't be DebugLog). Details of the specific functions making up the API are given in the file itself. Examples: Here's a simple example of an INI file being created from scratch: A simple structure is created with five sections with two properties each, plus a sectionless final property. A couple of properties and sections are removed, and some values are read. (This example uses DebugLog to print out the whole structure because it can handle multi-line strings, unlike Print). Here's a more complex example - a simple level definition: In this, the number of NPCs and a list of their names are given in the first section; the names can then be used to access the sections with the data for each relevant section. Note that not every NPC has every data field; if a field is absent, the empty string is returned (making something of this is up to whoever tried to access the value). The NPCs also have scripts attached to control their AI - three different ways of representing this are shown. The first NPC simply stores the whole script fragment in a braced multi-line value. The second NPC stores the name of another section; in this case, it's taking advantage of the fact that names can contain the backslash character to make it look like a namespaced identifier. That section then contains the script as a braced value again. The third NPC stores an INI sub-structure in a braced block, which can be loaded with INI_LoadString and read in the same way as the containing file. It's true that INI isn't as powerful or safe as XML or other formats, and it probably shouldn't be recommended for particularly large, fragile structures such as 3D models. But I prefer the simplicity where it's appropriate. | |||||
; INI file read/write library
;=============================
; Public API:
;
; - INI_Create: Create a new, empty INI structure from scratch with an optional comment
; Structures created in this way will attempt to auto-format themselves
;
; - INI_Load: Load an INI structure from a file
; Structures created in this way will not apply any auto-formatting
;
; - INI_LoadString: Load an INI structure from a string
; This is otherwise identical to INI_Load
;
; - INI_Write: Write an INI structure out to a text file
;
; - INI_WriteString: Write an INI structure out to a string
; As far as possible this is identical to INI_Write
;
; - INI_Free: Free an INI structure and all of its elements
;
; - INI_AddSection: Add a new, empty section to an INI structure
; No check is performed to see if a section with that name already exists
;
; - INI_RemoveSection: Remove a section (and optionally all of its properties) from an INI structure
; In the case of duplicate sections, only the first is removed
; If the section does not exist, an error is logged and no action is taken
;
; - INI_AddProperty: Add a property to an INI structure (optionally in a given section)
; No check is performed to see if a property with that name already exists
;
; - INI_GetValue: Retrieve a value from a given property (optionally in a given section)
; If the property does not exist, the empty string is returned and an error logged
;
; - INI_SetValue: Set the value of a given property (optionally in a given section)
; If the property does not exist, an error is logged and no action is taken
;
; - INI_GetComment: Retrieve a comment from a given property (optionally in a given section)
; If the property does not exist, the empty string is returned and an error logged
;
; - INI_SetComment: Set the comment of a given property (optionally in a given section)
; If the property does not exist, an error is logged and no action is taken
;
; - INI_RemoveProperty: Remove a property from an INI structure (optionally in a given section)
; If the property does not exist, an error is logged and no action is taken
;
;
; All the remaining functions, whose names begin with INI_private_, are part of the internal
; implementation and should not be called directly.
;
; The LogError function, called when an error is encountered, is not provided in this library.
; Instead, link it to a suitable logging function for your application.
;
Type INI_File
Field imported, comment$
Field sCount, sList.INI_Section
Field pCount, pList.INI_Property
End Type
Type INI_Stream
Field sPtr, sData
Field source$
End Type
Type INI_Section
Field name$, comment$
Field pCount, start.INI_Property
Field pv.INI_Section, nx.INI_Section
End Type
Type INI_Property
Field hasValue
Field key$, value$, comment$
Field pv.INI_Property, nx.INI_Property
End Type
; Create a new, empty INI structure
Function INI_Create.INI_File(comment$ = "")
Local i.INI_File = New INI_File
If comment <> ""
i\comment = comment
i\pList = INI_private_CreateProperty(i, Null, False, "", "", "", Null) ;Spacer line
Local c.INI_Property = INI_private_CreateProperty(i, Null, False, "", "", comment, i\pList)
INI_private_CreateProperty(i, Null, False, "", "", "", c) ;Another spacer
EndIf
Return i
End Function
; Load an INI structure from a file
Function INI_Load.INI_File(filename$)
Local s.INI_Stream, i.INI_File
If FileType(filename) <> 1 ;Replace with appropriate error function for your program
LogError "Could not open "+Chr(34)+filename+Chr(34)+": file not found"
Return Null
EndIf
s = INI_private_LoadINIFileStream(filename)
i = INI_private_ReadStream(s)
INI_private_FreeINIFileStream s
Return i
End Function
; Load an INI structure from a string
Function INI_LoadString.INI_File(val$)
Local s.INI_Stream, i.INI_File
s = INI_private_ReadINIFileSTream(val)
i = INI_private_ReadStream(s)
INI_private_FreeINIFileStream s
Return i
End Function
; Write an INI structure out to a text file
Function INI_Write(ini.INI_File, filename$)
Local f = WriteFile(filename), p.INI_Property, outL$
If f = 0
LogError "Unable to write to file "+Chr(34)+filename+Chr(34)
Return
EndIf
p = ini\pList
While p <> Null
If p\hasValue
outL = p\key + " = " + p\value
If p\comment <> "" Then outL = outL + " ;" + p\comment
Else
If p\value = ""
If p\comment <> "" Then outL = ";" + p\comment : Else outL = ""
Else
outL = "[ " + p\value + " ]"
If p\comment <> "" Then outL = outL + " ;" + p\comment
EndIf
EndIf
WriteLine f, outL
p = p\nx
Wend
If Not ini\imported Then WriteLine f, ""
CloseFile f
End Function
; Write an INI structure out to a string
Function INI_WriteString$(ini.INI_File)
Local outS$, p.INI_Property, outL$
p = ini\pList
While p <> Null
If p\hasValue
outL = p\key + " = " + p\value
If p\comment <> "" Then outL = outL + " ;" + p\comment
Else
If p\value = ""
If p\comment <> "" Then outL = ";" + p\comment : Else outL = ""
Else
outL = "[ " + p\value + " ]"
If p\comment <> "" Then outL = outL + " ;" + p\comment
EndIf
EndIf
outS = outS + outL + Chr(13) + Chr(10)
p = p\nx
Wend
If Not ini\imported Then outS = outS + Chr(13) + Chr(10)
Return outS
End Function
; Free an INI structure and all of its elements
Function INI_Free(ini.INI_File)
Local p.INI_Property, op.INI_Property
p = ini\pList
While p <> Null
op = p
p = p\nx
Delete op
Wend
Local s.INI_Section, os.INI_Section
s = ini\sList
While s <> Null
os = s
s = s\nx
Delete os
Wend
Delete ini
End Function
; Add a new, empty section to an INI structure
Function INI_AddSection(ini.INI_File, name$, comment$)
Local s.INI_Section, os.INI_Section
s = ini\sList
While s <> Null
os = s
s = s\nx
Wend
Local p.INI_Property, op.INI_Property
p = ini\pList
While p <> Null
op = p
p = p\nx
Wend
INI_private_CreateSection ini, name, comment, os, op
End Function
; Remove a section (and optionally all of its properties) from an INI structure
Function INI_RemoveSection(ini.INI_File, name$, freeProperties = True)
Local s.INI_Section, s_pv.INI_Section, s_nx.INI_Section
s = ini\sList
While s <> Null
If s\name = name Then Exit
s = s\nx
Wend
If s = Null
LogError "Could not find section "+Chr(34)+name+Chr(34)+" to remove"
Return
EndIf
If freeProperties
Local p.INI_Property, p_pv.INI_Property, p_nx.INI_Property, i
p_pv = s\start\pv
p = s\start
p_nx = p\nx
For i = 0 To s\pCount ;Not an error - we're also processing the zero element
p_nx = p\nx
Delete p
p = p_nx
Next
If p_pv <> Null Then p_pv\nx = p_nx
If p_nx <> Null Then p_nx\pv = p_pv
EndIf
If s\pv <> Null Then s\pv\nx = s\nx
If s\nx <> Null Then s\nx\pv = s\pv
Delete s
End Function
; Add a property to an INI structure (optionally in a given section)
Function INI_AddProperty(ini.INI_File, sec$, key$, value$, comment$ = "")
Local s.INI_Section = Null, i, p.INI_Property, n.INI_Property
If sec <> ""
s = ini\sList
While s <> Null
If s\name = sec Then Exit
s = s\nx
Wend
If s = Null
LogError "Could not find section "+Chr(34)+sec+Chr(34)+"; property not added"
Return
EndIf
p = s\start
For i = 1 To s\pCount
p = p\nx
Next
Else
n = ini\pList
While n <> Null
p = n
n = n\nx
Wend
EndIf
;Note that we did NOT check for duplicate names - this is not an error
INI_private_CreateProperty(ini, s, True, key, value, comment, p)
End Function
; Retrieve a value from a given property (optionally in a given section)
Function INI_GetValue$(ini.INI_File, sec$, key$)
Local p.INI_Property[0], s.INI_Section[0]
INI_private_GetProperty ini, sec, key, p, s ;Use out parameters
If p[0] <> Null Then Return p[0]\value : Else Return ""
End Function
; Set the value of a given property (optionally in a given section)
Function INI_SetValue(ini.INI_File, sec$, key$, val$)
Local p.INI_Property[0], s.INI_Section[0]
INI_private_GetProperty ini, sec, key, p, s ;Use out parameters
If p[0] <> Null Then p[0]\value = val
End Function
; Retrieve a comment from a given property (optionally in a given section)
Function INI_GetComment$(ini.INI_File, sec$, key$)
Local p.INI_Property[0], s.INI_Section[0]
INI_private_GetProperty ini, sec, key, p, s ;Use out parameters
If p[0] <> Null Then Return p[0]\comment : Else Return ""
End Function
; Set the comment of a given property (optionally in a given section)
Function INI_SetComment(ini.INI_File, sec$, key$, cmmt$)
Local p.INI_Property[0], s.INI_Section[0]
INI_private_GetProperty ini, sec, key, p, s ;Use out parameters
If p[0] <> Null Then p[0]\comment = cmmt
End Function
; Remove a property from an INI structure (optionally in a given section)
Function INI_RemoveProperty(ini.INI_File, sec$, key$)
Local p.INI_Property[0], s.INI_Section[0], s2.INI_Section, p2.INI_Property, i
INI_private_GetProperty ini, sec, key, p, s ;Use out parameters
If sec = "" ;Make sure that if the property belongs to a section, it gets removed properly
s2 = ini\sList
While s2 <> Null
p2 = s2\start
For i = 1 To s2\pCount
p2 = p2\nx
If p2\hasValue
If p2\key = key Then Exit ;The list is ordered, so break on the first match
EndIf
Next
If i <= s2\pCount Then Exit
s2 = s2\nx
Wend
If s2 <> Null
If p2 = p[0] Then s[0] = s2
EndIf
EndIf
If p[0] <> Null
If s[0] <> Null Then s[0]\pCount = s[0]\pCount - 1
If p[0]\pv <> Null Then p[0]\pv\nx = p[0]\nx
If p[0]\nx <> Null Then p[0]\nx\pv = p[0]\pv
Delete p[0]
EndIf
End Function
; Internal function: load an INI structure from a bank stream
Function INI_private_ReadStream.INI_File(s.INI_Stream)
Local i.INI_File = INI_Create(), error, ls.INI_Section, lp.INI_Property
i\imported = True
While s\sPtr < BankSize(s\sData) - 2
INI_private_SkipWhitespace s
Local c = PeekByte(s\sData, s\sPtr)
If c = 59 ;Semicolon
lp = INI_private_ReadCommentLine(s, i, ls, lp) ;Doesn't raise any errors
ElseIf c = 91 ;[ (open bracket)
ls = INI_private_ReadSectionDef(s, i, ls, lp)
If ls = Null Then error = True : Else lp = ls\start
ElseIf INI_private_IsValidNameChar(c) ;Key name
lp = INI_private_ReadPropertyDef(s, i, ls, lp)
If lp = Null Then error = True
ElseIf INI_private_CheckNewline(s) ;Try to swallow a newline
lp = INI_private_CreateProperty(i, ls, False, "", "", "", lp)
Else
error = True
EndIf
If error ;In the event of error, break off (should we try to continue instead?)
Local lineNo[0], lineVal$[0]
INI_private_GetCurrentLine s, lineNo, lineVal
LogError "Error reading data from "+s\source+": line "+lineNo[0]+" ( "+lineVal[0]+" ) is not a valid property or section definition"
INI_Free i
Return Null
EndIf
Wend
Return i
End Function
; Internal function: read a comment line into the INI structure for preservation
Function INI_private_ReadCommentLine.INI_Property(s.INI_Stream, i.INI_File, ls.INI_Section, lp.INI_Property)
Local cmmt$
s\sPtr = s\sPtr + 1
While Not INI_private_CheckNewline(s)
cmmt = cmmt + Chr(PeekByte(s\sData, s\sPtr))
s\sPtr = s\sPtr + 1
Wend
Return INI_private_CreateProperty(i, ls, False, "", "", cmmt, lp)
End Function
; Internal function: read a section definition into the INI structure
Function INI_private_ReadSectionDef.INI_Section(s.INI_Stream, i.INI_File, ls.INI_Section, lp.INI_Property)
Local name$, c, cmmt$
s\sPtr = s\sPtr + 1
INI_private_SkipWhitespace s
c = PeekByte(s\sData, s\sPtr)
While INI_private_IsValidNameChar(c)
name = name + Chr(c)
s\sPtr = s\sPtr + 1
c = PeekByte(s\sData, s\sPtr)
Wend
INI_private_SkipWhitespace s
; If there was no closing bracket, or there is an invalid character, return Null as error
If PeekByte(s\sData, s\sPtr) <> 93 Or name = "" Then Return Null
s\sPtr = s\sPtr + 1
INI_private_SkipWhitespace s
If PeekByte(s\sData, s\sPtr) = 59 ;Semicolon - comment
s\sPtr = s\sPtr + 1
While Not INI_private_CheckNewline(s)
cmmt = cmmt + Chr(PeekByte(s\sData, s\sPtr))
s\sPtr = s\sPtr + 1
Wend
ElseIf Not INI_private_CheckNewline(s) ;Newline or comments only; otherwise, return Null as error
Return Null
EndIf
Return INI_private_CreateSection(i, name, cmmt, ls, lp)
End Function
; Internal function: read a property definition into the INI structure
Function INI_private_ReadPropertyDef.INI_Property(s.INI_Stream, i.INI_File, ls.INI_Section, lp.INI_Property)
Local name$, val$, cmmt$, c, inQuotes, inBraces, esc
INI_private_SkipWhitespace s
c = PeekByte(s\sData, s\sPtr)
While INI_private_IsValidNameChar(c)
name = name + Chr(c)
s\sPtr = s\sPtr + 1
c = PeekByte(s\sData, s\sPtr)
Wend
INI_private_SkipWhitespace s
; If there is no equal sign, or there is an invalid character, return Null as error
If PeekByte(s\sData, s\sPtr) <> 61 Or name = "" Then Return Null
s\sPtr = s\sPtr + 1
INI_private_SkipWhitespace s
Repeat
c = PeekByte(s\sData, s\sPtr)
If Not inBraces
If INI_private_CheckNewline(s) Then Exit ;Braces can contain newlines
If (Not inQuotes) And (c = 59) Then Exit ;Semicolon
If c = 92 Then esc = True ;Backslash (escape character)
If c = 34 And esc = False Then inQuotes = Not inQuotes : Else esc = -1
If c <> 92 Then esc = False
EndIf
If Not inQuotes
If c = 123 Then inBraces = inBraces + 1 ;Opening brace
If c = 125 And inBraces > 0 Then inBraces = inBraces - 1 ;Closing brace
EndIf
If esc = -1 Then val = Left(val, Len(val) - 1) : esc = False
val = val + Chr(c)
s\sPtr = s\sPtr + 1
If s\sPtr = BankSize(s\sData) ;Unmatched brace could lead to hitting the EOF
LogError "Unmatched braces in peoperty value"
Return Null
EndIf
Forever
If val = "" Then Return Null ;If there is no value, return Null as an error
val = Trim(val) ;Remove trailing unquoted whitespace
;If the whole of val is quoted or braced, remove the outer layer of quoting
If (Left(val, 1) = Chr(34) And Right(val, 1) = Chr(34)) Or (Left(val, 1) = "{" And Right(val, 1) = "}")
val = Mid(val, 2, Len(val) - 2)
EndIf
If c = 59 ;Semicolon - comment
s\sPtr = s\sPtr + 1
While Not INI_private_CheckNewline(s)
cmmt = cmmt + Chr(PeekByte(s\sData, s\sPtr))
s\sPtr = s\sPtr + 1
Wend
EndIf
Return INI_private_CreateProperty(i, ls, True, name, val, cmmt, lp)
End Function
; Internal function: create a property object
Function INI_private_CreateProperty.INI_Property(i.INI_File, s.INI_Section, hasVal, key$, val$, cmmt$, pv.INI_Property)
Local p.INI_Property = New INI_Property
p\hasValue = hasVal
p\key = key
p\value = val
p\comment = cmmt
p\pv = pv
i\pCount = i\pCount + 1
If i\pList = Null Then i\pList = p
If s <> Null Then s\pCount = s\pCount + 1
If pv <> Null
p\nx = pv\nx
pv\nx = p
If p\nx <> Null Then p\nx\pv = p
EndIf
Return p
End Function
; Internal function: create a section object
Function INI_private_CreateSection.INI_Section(i.INI_File, name$, cmmt$, pv.INI_Section, pp.INI_Property)
Local s.INI_Section = New INI_Section
s\name = name
s\comment = cmmt
s\pv = pv
If Not i\imported ;If this is being created ex nihilo, apply basic formatting here
pp = INI_private_CreateProperty(i, Null, False, "", "", "", pp)
pp = INI_private_CreateProperty(i, Null, False, "", "", "", pp) ;Two spacers?
pp = INI_private_CreateProperty(i, Null, False, "", "", cmmt, pp) ;Comment
s\start = INI_private_CreateProperty(i, s, False, "", name, "", pp) ;And the start line
INI_private_CreateProperty i, Null, False, "", "", "", s\start ;Final spacer
Else
s\start = INI_private_CreateProperty(i, s, False, "", name, cmmt, pp) ;Otherwise, don't adjust the formatting
EndIf
s\pCount = 0 ;Reset after adding s\start
i\sCount = i\sCount + 1
If i\sList = Null Then i\sList = s
If pv <> Null Then pv\nx = s
Return s
End Function
; Internal function: retrieve a property object by key, optionally in a given section
Function INI_private_GetProperty.INI_Property(ini.INI_File, sec$, key$, p_out.INI_Property[0], s_out.INI_Section[0])
Local p.INI_Property, s.INI_Section, i
If sec = "" ;No section, check all properties in order
p = ini\pList
While p <> Null
If p\hasValue
If p\key = key Then Exit
EndIf
p = p\nx
Wend
If p = Null Then LogError "Could not find property "+Chr(34)+key+Chr(34)
Else
s = ini\sList
While s <> Null
If s\name = sec Then Exit
s = s\nx
Wend
If s = Null
LogError "Could not find section "+Chr(34)+sec+Chr(34)+" to retrieve property"
Return Null
EndIf
p = s\start ;Start itself is a placeholder
For i = 1 To s\pCount
p = p\nx
If p\hasValue
If p\key = key Then Exit
EndIf
Next
If i > s\pCount
LogError "Could not find property "+Chr(34)+key+Chr(34)+" in section "+Chr(34)+sec+Chr(34)
Return Null
EndIf
EndIf
; Use out parameters to return multiple values
p_out[0] = p
s_out[0] = s
End Function
; Internal function: create a new bank stream object
Function INI_private_CreateINIFileStream.INI_Stream(source$, size)
Local s.INI_Stream = New INI_Stream
s = New INI_Stream
s\sData = CreateBank(size + 2)
PokeShort s\sData, size, $0A ;Append a final line-ending to simplify checking
s\sPtr = 0
s\source = source
Return s
End Function
; Internal function: load a bank stream from a file
Function INI_private_LoadINIFileStream.INI_Stream(filename$)
Local size, s.INI_Stream, f
If FileType(filename) <> 1 ;Replace with appropriate error function for your program
LogError "Could not open "+Chr(34)+filename+Chr(34)+": file not found"
Return Null
EndIf
size = FileSize(filename)
s = INI_private_CreateINIFileStream(filename, size)
f = ReadFile(filename)
ReadBytes s\sData, f, 0, size
CloseFile f
Return s
End Function
; Internal function: create a bank stream from a string
Function INI_private_ReadINIFileSTream.INI_Stream(val$)
Local c, s.INI_Stream, i, l = Len(val)
s = INI_private_CreateINIFileStream("string", l)
For i = 1 To l
PokeByte s\sData, i - 1, Asc(Mid(val, i, 1))
Next
Return s
End Function
; Internal function: free a bank stream
Function INI_private_FreeINIFileStream(s.INI_Stream)
FreeBank s\sData
Delete s
End Function
; Internal function: skip tabs and spaces in a bank stream
Function INI_private_SkipWhitespace(s.INI_Stream)
Local c = PeekByte(s\sData, s\sPtr)
While c = 9 Or c = 32
s\sPtr = s\sPtr + 1
c = PeekByte(s\sData, s\sPtr)
Wend
End Function
; Internal function: test if a character is valid for use in a property or section name
Function INI_private_IsValidNameChar(c)
If c >= 48 And c <= 57 Then Return True ;Digit 0-9
If c >= 65 And c <= 90 Then Return True ;Letter A-Z
If c >= 97 And c <= 122 Then Return True ;Letter a-z
If c = 92 Or c = 58 Or c = 95 Or c = 46 Then Return True ;Colon, backslash, underscore, dot
Return False
End Function
; Internal function: test for a newline (and swallow it if present)
Function INI_private_CheckNewline(s.INI_Stream)
If PeekShort(s\sData, s\sPtr) = $A0D
s\sPtr = s\sPtr + 2
Return True
ElseIf PeekByte(s\sData, s\sPtr) = 10 Or PeekByte(s\sData, s\sPtr) = 13
s\sPtr = s\sPtr + 1
Return True
Else
Return False
EndIf
End Function
; Internal function: Get the current line contents and number (for error messages) - uses out-parameters
Function INI_private_GetCurrentLine(s.INI_Stream, lineNo[0], lineVal$[0])
Local i, lIndex, lNo = 1 ;Start at 1
For i = 0 To s\sPtr
If PeekShort(s\sData, i) = $A0D
lNo = lNo + 1
lIndex = i + 2
i = i + 1
ElseIf PeekByte(s\sData, i) = 10 Or PeekByte(s\sData, i) = 13
lNo = lNo + 1
lIndex = i + 1
EndIf
Next
lineNo[0] = lNo
lineVal[0] = ""
While PeekByte(s\sData, lIndex) <> 10 And PeekByte(s\sData, lIndex) <> 13
lineVal[0] = lineVal[0] + Chr(PeekByte(s\sData, lIndex))
lIndex = lIndex + 1
Wend
End Function
;~IDEal Editor Parameters:
;~F#3A#40#45#4C#55#63#73#7E#9D#B7#CF#E4#10A#12A#133#13C#145#14E#170#198
;~F#1A3#1C6#20A#222#23E#26C#279#28C#299#29F#2A8#2B1#2BE
;~C#Blitz3D |
Comments
| ||
| I LOVE U MAN! XD NO HOMO :P |
| ||
| Haha, yeah your questions about writing strings and so on made me think you might be interested in this. It was in fact that that gave me the idea to tidy up the comments and put it in the archive. |
| ||
| I'm glad I've inspired you! :) |
| ||
| Question, sorry for my ignorance, as not to step debuglog content if not a file (config.ini) |
| ||
| Sorry Yue, your question didn't translate properly. Can you rephrase it? |
| ||
| Hello, thank you for your patience. I can not find the way to move to a txt file so in the example above appears in the debuglog. Now I do not want to appear in the debuglog, if not in a file that can be txt, dat, img etc, which will store game settings. Greetings. Edit: |
| ||
You mean like this:Local i.INI_File = ... ; INI_Write i, "config.ini" INI_Free i ...? INI_Write always outputs to a text file. The examples use INI_WriteString, which creates an internal B3D string of the whole contents of the INI, but doesn't save anything. The use of DebugLog was just to easily display this string, and isn't necessary for normal use of the library. |
| ||
![]() Yes! Ok, thanks for the help. Now I have another question, and it is related to the following: In INI files, I can get game-related settings, but I worry that such data can be changed by the end user, for example could change the health kits, or the amount of points you have. Is there any way to make the data encrypted? Or in this case would have to resort to putting words strange that only I understand the comments and keys? Greetings. |
| ||
| In INI files, I can get game-related settings, but I worry that such data can be changed by the end user, for example could change the health kits, or the amount of points you have. Is there any way to make the data encrypted? Or in this case would have to resort to putting words strange that only I understand the comments and keys? Yeah, INI is really intended to make it easier for the end user to modify the data. You could: -- as you suggest, have keys that aren't obvious (also, just don't bother with comments, if you don't want to make things clear) -- also have values that aren't obvious, where possible -- use INI_WriteString to generate a string, use a generic string-encryptor (maybe there's a suitable one in the archives?) to encrypt the whole thing, and write that encrypted string to a file (reverse the process to read data) |
| ||
| Thank you very much for your work, is increasingly less and given me a lot to learn I have noticed that the title of programmer left me even further. A last question, where I can find a generic support Blitz3D encryptor to encrypt strings. Greetings. Edit: Ok, no problem, save file .dll y data file: - = 100 ; true data healt + = 20 ; False data W = 50 ; False data 34= 100 ; true data Score. Thanks Yasha |
Code Archives Forum
