Steve's Config File System
#1
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)

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.  Smile

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.  Smile[/quote]
Reply


Messages In This Thread
Steve's Config File System - by SMcNeill - 04-20-2022, 02:28 AM



Users browsing this thread: 2 Guest(s)