04-20-2022, 02:28 AM
Two little routines which can be used to read and write to a config file. (If you guys want to see an example of what an actual config file would look like using this, look at the config.txt in your QB64/internal folder. This is the exact same config routines which we imported into QB64. :-X)
The concept behind the routines here is rather simple:
First, most config files have headings to help make finding and organizing things easier for the user to find if they ever open the file in a simple text editor. This supports those as a purely organizational type object, but they actually don't hold any value except to make things easier for the user in they alter things manually.
For example, a config file might look like the following:
'[COLORS]
RED = 1
BLUE = 2
'[JOYSTICK]
EnableJoystick = FALSE
Now that's easy enough to read and alter in a text editor, but what if the user edits it so that it looks something more like the following:
'[COLORS]
RED = 1
'[JOYSTICK]
EnableJoystick = FALSE
BLUE = 2
That BLUE isn't in the right heading!
So the choice here is: Do we ignore it since it's not in the expected place? Or read it as long as it's anywhere in the file?? I chose to read it no matter where it appears in the config file.
The only drawback to this is that we can't have two different settings called BLUE under different headings, but that I don't see that as being an issue for us so much just for the simple fact that QB64 really isn't going to have that many settings to use that we can't give them all an unique name.
So honestly, all we're really dealing with here is the item$ which is the setting we're looking for, and the value$ that we want to assign to it, with the heading$ only being there to help with making it all look pretty...
Other point to note:
ReadConfigSetting is a FUNCTION.
It returns a 0 to us if it fails to find a setting, and a -1 if it found it successfully.
the value$ is passed back to us via the 2nd parameter in the FUNCTION.
work = ReadConfigSetting("TextColor", value$)
Now if we have a setting for TextColor, work will be -1 and value$ will be whatever that setting is
If there's no TextColor in the config file, work will be 0 and value$ might be anything....
I'd suggest to ALWAYS check to see if the return value of that function is true or not, before I'd accept the value that it gave us.
work = ReadConfigSetting("TextColor", value$)
IF work THEN
PRINT "Textcolor value found. It's: "; value$
ELSE
PRINT "No textcolor found"
END IF
All in all, I find it easier to use than I do to explain the use. LOL - try out the demo and you'll see how it works for yourself easily enough.
WriteConfigSetting (heading$, item$, value$) writes the headings (just for prettification), item, and value to the proper place in your config file. It searches to see if the setting is already in the file, and if not it adds it to the proper area automatically for you.
ReadConfigSetting (item$, value$) returns a 0 or -1 through the function to tell us if things worked as we expected, and returns our value to use through the second parameter if it can.
It really is basically that simple to use. [/quote]
Code: (Select All)
ConfigFile$ = "config.txt"
ConfigBak$ = "config.bak"
WriteConfigSetting "'[COLOR SETTING]", "Background", "_RGB32(255,0,255)"
DisplayConfigFile
WriteConfigSetting "'[COLOR SETTING]", "TextColor", "_RGB32(255,0,0)"
DisplayConfigFile
WriteConfigSetting "'[COLOR SETTING]", "Background", "_RGB32(255,0,0) 'REDONE"
DisplayConfigFile
WriteConfigSetting "'[COLOR SETTING]", "TextColor", "_RGB32(255,0,255) 'REDONE ALSO"
DisplayConfigFile
PRINT
PRINT "============================================="
PRINT
work = ReadConfigSetting("TextColor", value$)
IF work THEN
PRINT "Textcolor value found. It's: "; value$
ELSE
PRINT "No textcolor found"
END IF
SUB DisplayConfigFile
SHARED ConfigFile$
InFile = FREEFILE: OPEN ConfigFile$ FOR BINARY AS #InFile
IF LOF(InFile) THEN
DO UNTIL EOF(InFile)
LINE INPUT #InFile, junk$
PRINT junk$
LOOP
ELSE
KILL "config.txt" 'remove the blank file from the drive
PRINT "No config file found."
END IF
CLOSE InFile
END SUB
SUB WriteConfigSetting (heading$, item$, value$)
SHARED ConfigFile$, ConfigBak$
DIM CRLF AS STRING
IF INSTR(_OS$, "WIN") THEN CRLF = CHR$(13) + CHR$(10) ELSE CRLF = CHR$(10)
_TITLE STR$(LEN(CRLF))
InFile = FREEFILE: OPEN ConfigFile$ FOR BINARY AS #InFile
OutFile = FREEFILE: OPEN ConfigBak$ FOR OUTPUT AS #OutFile
placed = 0
IF LOF(InFile) THEN
DO UNTIL EOF(InFile)
LINE INPUT #InFile, junk$
'we really don't care about heading$ here; it's only used to make things easier for the user to locate in the config file
junk$ = LTRIM$(RTRIM$(junk$))
IF _STRICMP(LEFT$(junk$, LEN(item$)), item$) = 0 THEN
PRINT #OutFile, item$; " = "; value$
placed = -1
ELSE
PRINT #OutFile, junk$
END IF
LOOP
END IF
CLOSE #InFile, #OutFile
IF NOT placed THEN 'we didn't find the proper setting already in the file somewhere.
'Either the file was corrupted, or the user deleted this particulat setting sometime in the past.
'Now we look to see if the heading exists in the file or not.
'If it does, then we place the new setting under that heading.
'If not then we write that heading to the end of the file to make it easier for the user to locate in the future
'and then we write it below there.
OPEN ConfigBak$ FOR BINARY AS #InFile
l = LOF(InFile)
out$ = item$ + " = " + value$ + CRLF
temp$ = SPACE$(l)
GET #InFile, 1, temp$
l1 = INSTR(temp$, heading$)
IF l1 THEN
l1 = l1 + LEN(heading$) + LEN(CRLF)
PUT #InFile, l1, out$
r$ = MID$(temp$, l1)
PUT #InFile, , r$
placed = -1
END IF
IF NOT placed THEN
PUT #InFile, l + 1, CRLF
PUT #InFile, , heading$
PUT #InFile, , CRLF
PUT #InFile, , out$
PUT #InFile, , CRLF
END IF
CLOSE InFile
END IF
KILL ConfigFile$
NAME ConfigBak$ AS ConfigFile$
END SUB
FUNCTION ReadConfigSetting (item$, value$)
SHARED ConfigFile$
value$ = "" 'We start by blanking the value$ as a default return state
InFile = FREEFILE: OPEN ConfigFile$ FOR BINARY AS #InFile
IF LOF(InFile) THEN
found = 0
DO UNTIL EOF(InFile)
LINE INPUT #InFile, temp$
temp$ = LTRIM$(RTRIM$(temp$))
IF LEFT$(UCASE$(temp$), LEN(item$)) = UCASE$(item$) THEN found = -1: EXIT DO
LOOP
CLOSE InFile
IF found THEN 'we found what we're looking for
l = INSTR(temp$, "=") 'return the value after the = sign
IF l THEN
value$ = MID$(temp$, l + 1)
l = INSTR(value$, CHR$(13)) 'we only want what's before a CR
IF l THEN value$ = LEFT$(value$, l)
l = INSTR(value$, CHR$(10)) 'or a LineFeed
'These are basic text files; they shouldn't have stray CHR$(10) or CHR$(13) characters in them!
IF l THEN value$ = LEFT$(value$, l)
value$ = LTRIM$(RTRIM$(value$))
ReadConfigSetting = -1
EXIT FUNCTION
END IF
END IF
END IF
ReadConfigSetting = 0 'failed to find the setting
END FUNCTION
The concept behind the routines here is rather simple:
First, most config files have headings to help make finding and organizing things easier for the user to find if they ever open the file in a simple text editor. This supports those as a purely organizational type object, but they actually don't hold any value except to make things easier for the user in they alter things manually.
For example, a config file might look like the following:
'[COLORS]
RED = 1
BLUE = 2
'[JOYSTICK]
EnableJoystick = FALSE
Now that's easy enough to read and alter in a text editor, but what if the user edits it so that it looks something more like the following:
'[COLORS]
RED = 1
'[JOYSTICK]
EnableJoystick = FALSE
BLUE = 2
That BLUE isn't in the right heading!
So the choice here is: Do we ignore it since it's not in the expected place? Or read it as long as it's anywhere in the file?? I chose to read it no matter where it appears in the config file.
The only drawback to this is that we can't have two different settings called BLUE under different headings, but that I don't see that as being an issue for us so much just for the simple fact that QB64 really isn't going to have that many settings to use that we can't give them all an unique name.
So honestly, all we're really dealing with here is the item$ which is the setting we're looking for, and the value$ that we want to assign to it, with the heading$ only being there to help with making it all look pretty...
Other point to note:
ReadConfigSetting is a FUNCTION.
It returns a 0 to us if it fails to find a setting, and a -1 if it found it successfully.
the value$ is passed back to us via the 2nd parameter in the FUNCTION.
work = ReadConfigSetting("TextColor", value$)
Now if we have a setting for TextColor, work will be -1 and value$ will be whatever that setting is
If there's no TextColor in the config file, work will be 0 and value$ might be anything....
I'd suggest to ALWAYS check to see if the return value of that function is true or not, before I'd accept the value that it gave us.
work = ReadConfigSetting("TextColor", value$)
IF work THEN
PRINT "Textcolor value found. It's: "; value$
ELSE
PRINT "No textcolor found"
END IF
All in all, I find it easier to use than I do to explain the use. LOL - try out the demo and you'll see how it works for yourself easily enough.
WriteConfigSetting (heading$, item$, value$) writes the headings (just for prettification), item, and value to the proper place in your config file. It searches to see if the setting is already in the file, and if not it adds it to the proper area automatically for you.
ReadConfigSetting (item$, value$) returns a 0 or -1 through the function to tell us if things worked as we expected, and returns our value to use through the second parameter if it can.
It really is basically that simple to use. [/quote]