' INI file parser: sections, keys, values, comments, lookup
#COMPILE EXE
#DIM ALL

FUNCTION TrimString(BYVAL s AS STRING) AS STRING
    LOCAL i  AS LONG
    LOCAL first  AS LONG
    LOCAL last  AS LONG
    first = 1
    last = LEN(s)
    DO WHILE first <= last AND MID$(s, first, 1) <= " "
        first = first + 1
    LOOP
    DO WHILE last >= first AND MID$(s, last, 1) <= " "
        last = last - 1
    LOOP
    IF first > last THEN FUNCTION = "" ELSE FUNCTION = MID$(s, first, last - first + 1)
END FUNCTION

SUB ParseINILine(BYVAL line AS STRING, section AS STRING, key AS STRING, value AS STRING)
    LOCAL eqPos AS LONG
    LOCAL trimmed AS STRING
    trimmed = TrimString(line)
    IF LEN(trimmed) = 0 THEN section = "": key = "": value = "": EXIT SUB
    IF LEFT$(trimmed, 1) = "[" THEN
        section = TrimString(MID$(trimmed, 2, LEN(trimmed) - 2))
        key = ""
        value = ""
    ELSEIF LEFT$(trimmed, 1) = ";" OR LEFT$(trimmed, 1) = "'" OR LEFT$(trimmed, 1) = "#" THEN
        section = ""
        key = ""
        value = ""
    ELSE
        eqPos = INSTR(trimmed, "=")
        IF eqPos > 0 THEN
            key = TrimString(LEFT$(trimmed, eqPos - 1))
            value = TrimString(MID$(trimmed, eqPos + 1))
            IF LEFT$(value, 1) = CHR$(34) AND RIGHT$(value, 1) = CHR$(34) THEN
                value = MID$(value, 2, LEN(value) - 2)
            END IF
            section = ""
        ELSE
            key = ""
            value = ""
        END IF
    END IF
END SUB

FUNCTION INIGet(BYVAL text AS STRING, BYVAL wantedSection AS STRING, BYVAL wantedKey AS STRING) AS STRING
    LOCAL i  AS LONG
    LOCAL pos  AS LONG
    LOCAL lineStart  AS LONG
    LOCAL lineEnd  AS LONG
    LOCAL line  AS STRING
    LOCAL section  AS STRING
    LOCAL key  AS STRING
    LOCAL value  AS STRING
    LOCAL inSection AS LONG
    inSection = 0
    pos = 1
    DO WHILE pos <= LEN(text)
        lineStart = pos
        pos = INSTR(pos, text, CHR$(10))
        IF pos = 0 THEN pos = LEN(text) + 1
        lineEnd = pos - 1
        IF MID$(text, lineEnd, 1) = CHR$(13) THEN lineEnd = lineEnd - 1
        line = MID$(text, lineStart, lineEnd - lineStart + 1)
        CALL ParseINILine(line, section, key, value)
        IF section <> "" THEN
            inSection = IFF(UCASE$(section) = UCASE$(wantedSection), 1, 0)
        ELSEIF inSection AND key <> "" THEN
            IF UCASE$(key) = UCASE$(wantedKey) THEN FUNCTION = value: EXIT FUNCTION
        END IF
        pos = pos + 1
    LOOP
    FUNCTION = ""
END FUNCTION

FUNCTION MakeSampleINI() AS STRING
    LOCAL r AS STRING
    r = "; Sample config" + CHR$(13) + CHR$(10)
    r = r + "[Database]" + CHR$(13) + CHR$(10)
    r = r + "host = localhost" + CHR$(13) + CHR$(10)
    r = r + "port = 5432" + CHR$(13) + CHR$(10)
    r = r + "name = pbxb64_db" + CHR$(13) + CHR$(10)
    r = r + "" + CHR$(13) + CHR$(10)
    r = r + "[Appearance]" + CHR$(13) + CHR$(10)
    r = r + "theme = dark" + CHR$(13) + CHR$(10)
    r = r + "font_size = 12" + CHR$(13) + CHR$(10)
    r = r + "" + CHR$(13) + CHR$(10)
    r = r + "[Window]" + CHR$(13) + CHR$(10)
    r = r + "# position" + CHR$(13) + CHR$(10)
    r = r + "x = 100" + CHR$(13) + CHR$(10)
    r = r + "y = 200" + CHR$(13) + CHR$(10)
    r = r + "width = 800" + CHR$(13) + CHR$(10)
    r = r + "height = 600" + CHR$(13) + CHR$(10)
    FUNCTION = r
END FUNCTION

FUNCTION PBMAIN() AS LONG
    LOCAL iniText AS STRING
    PRINT "=== INI Reader ==="
    PRINT
    iniText = MakeSampleINI()
    PRINT "INI content:"
    PRINT iniText
    PRINT
    PRINT "Lookups:"
    PRINT "  [Database].host = " + INIGet(iniText, "Database", "host")
    PRINT "  [Database].port = " + INIGet(iniText, "Database", "port")
    PRINT "  [Database].name = " + INIGet(iniText, "Database", "name")
    PRINT "  [Appearance].theme = " + INIGet(iniText, "Appearance", "theme")
    PRINT "  [Window].x = " + INIGet(iniText, "Window", "x")
    PRINT "  [Window].width = " + INIGet(iniText, "Window", "width")
    PRINT
    PRINT "Missing keys:"
    PRINT "  [Database].password = " + CHR$(34) + INIGet(iniText, "Database", "password") + CHR$(34)
    PRINT "  [Missing].key = " + CHR$(34) + INIGet(iniText, "Missing", "key") + CHR$(34)
    PRINT
    PRINT "INI reader tests complete."
    FUNCTION = 0
END FUNCTION
