Inifile Managing
;==========================================================================================================================================
; Inifile Managing.
;
; Detlev Dalitz.20021127.20030727.20030802.20090428.
;==========================================================================================================================================
; udfIniSectionCreate  (strSection, strIniFile)
; udfIniSectionDelete  (strSection, strIniFile)
;
; udfIniSectionRename  (strSectionOld, strSectionNew, strIniFile) ; The FileGet version.
; udfIniSectionRenameV2 (strSectionOld, strSectionNew, strIniFile) ; The Binary Buffer version (old).
;
; udfIniSectionCopy    (strSection, strIniFileFrom, strIniFileTo)
; udfIniSectionMove    (strSection, strIniFileFrom, strIniFileTo)
; udfIniSectionMerge   (strSection, strIniFile1, strIniFile2, strIniFileMerge)
;
; udfIniSectionSort    (strSection, strIniFile)
;
; udfIniSectionAdjust  (strIniFile) ; The FileGet version.
; udfIniSectionAdjustV2 (strIniFile) ; The Binary Buffer version (old).
;==========================================================================================================================================

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfIniSectionCreate (strSection, strIniFile)
IniWritePvt (strSection, "", "", strIniFile)
IniDeletePvt (strSection, "", strIniFile)
IniWritePvt ("", "", "", strIniFile)
Return FileExist (strIniFile)
;..........................................................................................................................................
; This UDF "udfIniSectionCreate" creates a section header in inifile.
; If the section already exists nothing will be changed.
;
; Detlev Dalitz.20021127.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfIniSectionDelete (strSection, strIniFile)
IniWritePvt ("", "", "", strIniFile) ; For sure force flushing cache to disk.
TimeDelay (1)
IniDeletePvt (strSection, @WHOLESECTION, strIniFile)
IniWritePvt ("", "", "", strIniFile)
Return FileExist (strIniFile)
;..........................................................................................................................................
; This UDF "udfIniSectionDelete" deletes an entire section in inifile without permission.
;
; Detlev Dalitz.20021127.20030727.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfIniSectionRename (strSectionOld, strSectionNew, strIniFile) ; The FileGet version.
intFilesize = FileSize (strIniFile)
If !intFilesize Then Return @FALSE ; File may exist empty, but there is nothing to do.

IniWritePvt ("", "", "", strIniFile) ; Force flushing cache to disk.
TimeDelay (1)

strIni = StrCat (@LF, FileGet (strIniFile))

; Left adjust all lines.
strReplaceOld = StrCat (@LF, " ")
strReplaceNew = @LF
While StrIndex (strIni, strReplaceOld, 0, @FWDSCAN)
   strIni = StrReplace (strIni, strReplaceOld, strReplaceNew)
EndWhile

; Rename section header.
strIni = StrReplace (strIni, StrCat (@LF, "[", strSectionOld, "]"), StrCat (@LF, "[", strSectionNew, "]"))

; Write inifile to disk.
FilePut (strIniFile, StrSub (strIni, 2, -1))

Return FileExist (strIniFile)
;..........................................................................................................................................
; This UDF "udfIniSectionRename" renames a given section header in inifile.
; This function requires, that all lines within an inifile are delimited with @CRLF as EOL marker.
;
; Detlev Dalitz.20030802.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfIniSectionRenameV2 (strSectionOld, strSectionNew, strIniFile) ; The binary buffer version.
intFilesize = FileSize (strIniFile)
If !intFilesize Then Return @FALSE ; File may exist empty, but there is nothing to do.

IniWritePvt ("", "", "", strIniFile) ; Force flushing cache to disk.
TimeDelay (1)

intBBsize = intFilesize + 2 + Max (0, (StrLen (strSectionNew) - StrLen (strSectionOld)))
hdlBB = BinaryAlloc (intBBsize)
BinaryPokeStr (hdlBB, 0, @CRLF) ; Add a little helper, will be removed later.
If intFilesize != BinaryReadEx (hdlBB, 2, strIniFile, 0, intFilesize) Then Return @FALSE ; Quick way out.

; Left adjust all lines.
strReplaceOld = StrCat (@CRLF, " ")
strReplaceNew = @CRLF
While BinaryReplace (hdlBB, strReplaceOld, strReplaceNew, @TRUE)
EndWhile

strBBTag = BinaryTagInit (hdlBB, StrCat (@LF, "[", strSectionOld), "]") ; Init section header to search.
strBBTag = BinaryTagFind (strBBTag) ; Find the section header.
blnDone = @FALSE
If strBBTag != ""
   strBBTag = BinaryTagRepl (strBBTag, StrCat (@LF, "[", strSectionNew, "]")) ; Rename section header.
   BinaryWriteEx (hdlBB, 0, strIniFile, 0, -1)
   blnDone = 0 < BinaryWriteEx (hdlBB, 2, strIniFile, 0, BinaryEodGet (hdlBB)-2) ; Overwrite inifile.
EndIf
hdlBB = BinaryFree (hdlBB)
Return blnDone && FileExist (strIniFile)
;..........................................................................................................................................
; This UDF "udfIniSectionRename" renames a given section header in inifile.
; This function requires, that all lines within an inifile are delimited with @CRLF as EOL marker.
;
; Detlev Dalitz.20021127.20030727.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfIniSectionCopy (strSection, strIniFileFrom, strIniFileTo)
IniWritePvt ("", "", "", strIniFileFrom) ; Force flushing cache to disk.
TimeDelay (1)
strKeyList = IniItemizePvt (strSection, strIniFileFrom)
intKeyCount = ItemCount (strKeyList, @TAB)
For intKey = 1 To intKeyCount
   strKey = ItemExtract (intKey, strKeyList, @TAB)
   strData = IniReadPvt (strSection, strKey, "", strIniFileFrom)
   IniWritePvt (strSection, strKey, strData, strIniFileTo)
Next
IniWritePvt ("", "", "", strIniFileTo)
Return FileExist (strIniFileTo)
;..........................................................................................................................................
; This UDF "udfIniSectionCopy" copies a whole section from one inifile to another inifile.
; The receiving inifile will be created automatically.
;
; Caution:
; If the target inifile "strIniFileTo" already contains a section with the same name,
; this function works like an overwriting merger function!
;
; Detlev Dalitz.20021127.20030727.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfIniSectionMove (strSection, strIniFileFrom, strIniFileTo)
If udfIniSectionCopy (strSection, strIniFileFrom, strIniFileTo)
   udfIniSectionDelete (strSection, strIniFileFrom)
   Return FileExist (strIniFileTo)
EndIf
Return @FALSE
;..........................................................................................................................................
; This UDF "udfIniSectionMove" moves a whole section from one inifile to another inifile.
; The receiving inifile will be created automatically.
; After copying the whole section from first inifile to second inifile,
; the whole section will be deleted from the first inifile.
;
; Caution:
; If the target inifile "strIniFileTo" already contains a section with the same name,
; this function works like an overwriting merger function!
;
; Detlev Dalitz.20021127.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfIniSectionMerge (strSection, strIniFile1, strIniFile2, strIniFileMerge)
udfIniSectionCopy (strSection, strIniFile1, strIniFileMerge)
udfIniSectionCopy (strSection, strIniFile2, strIniFileMerge)
Return FileExist (strIniFileMerge)
;..........................................................................................................................................
; This UDF "udfIniSectionMerge" merges equally named sections of two inifiles
; together into a third target inifile.
; The target inifile will be created automatically.
; The input inifiles remain untouched.
;
; Merging is done by simple copying sections from inifiles to target mergefile.
; The position of the inifiles in the function's parameter list determines,
; which inifile will get higher priority for overwrite pre-existing data:
; Data from second inifile "strIniFile2" overwrites data from first inifile "strIniFile1".
;
; Detlev Dalitz.20021127.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfIniSectionSort (strSection, strIniFile)
intFilesize = FileSize (strIniFile)
If !intFilesize Then Return @FALSE ; File may exist empty, but there is nothing to do.

IniWritePvt ("", "", "", strIniFile) ; Force flushing cache to disk.
TimeDelay (1)

strKeyList = IniItemizePvt (strSection, strIniFile)
strKeyList = ItemSort (strKeyList, @TAB)
intKeyCount = ItemCount (strKeyList, @TAB)

; Create a temporary section with unique name.
strSectionTemp = StrCat (strSection, GetTickCount ())
For intKey = 1 To intKeyCount
   strKey = ItemExtract (intKey, strKeyList, @TAB)
   strData = IniReadPvt (strSection, strKey, "", strIniFile)
   IniWritePvt (strSectionTemp, strKey, strData, strIniFile)
Next
IniWritePvt ("", "", "", strIniFile) ; Flush the inifile to disk.

; Delete original section.
IniDeletePvt (strSection, @WHOLESECTION, strIniFile)
IniWritePvt ("", "", "", strIniFile) ; Flush the inifile to disk.

; Rename temporary section.
blnDone = udfIniSectionRename (strSectionTemp, strSection, strIniFile)

Return blnDone && FileExist (strIniFile)
;..........................................................................................................................................
; This UDF "udfIniSectionSort" sorts keywords from a section in ascending order
; for better human readability.
;
; Note: In Win9x operating systems the maximum size of an inifile is limited to 64kB.
; Make sure that the above function can work successful within this limit.
;
; Detlev Dalitz.20021127.20030727.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfIniSectionAdjust (strIniFile) ; The FileGet version.
intFilesize = FileSize (strIniFile)
If !intFilesize Then Return @FALSE ; File may exist empty, but there is nothing to do.

IniWritePvt ("", "", "", strIniFile) ; Force flushing cache to disk.
TimeDelay (1)

strSectionList = IniItemizePvt ("", strIniFile)
strSectionCount = ItemCount (strSectionList, @TAB)

strIni = StrCat (@LF, FileGet (strIniFile)) ; Add a little helper.

; Left adjust all lines.
strReplaceOld = StrCat (@LF, " ")
strReplaceNew = @LF
While StrIndex (strIni, strReplaceOld, 0, @FWDSCAN)
   strIni = StrReplace (strIni, strReplaceOld, strReplaceNew)
EndWhile

; Insert blank line before section headers.
strReplaceOld = StrCat (@CRLF, "[")
strReplaceNew = StrCat (@CRLF, @CRLF, "[")
strIni = StrReplace (strIni, strReplaceOld, strReplaceNew)

; Force adjust to one blank line.
strReplaceOld = StrCat (@CRLF, @CRLF, @CRLF, "[")
strReplaceNew = StrCat (@CRLF, @CRLF, "[")
While StrIndex (strIni, strReplaceOld, 0, @FWDSCAN)
   strIni = StrReplace (strIni, strReplaceOld, strReplaceNew)
EndWhile

; Write inifile to disk.
FilePut (strIniFile, StrSub (strIni, 2, -1)) ; Cut little helper.

Return FileExist (strIniFile)
;..........................................................................................................................................
; This UDF "udfIniSectionAdjust" adjusts the space between sections
; to a single blank line for better human readability.
; This function requires, that all lines within an inifile are delimited with @CRLF as EOL marker.
;
; Detlev Dalitz.20030802.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfIniSectionAdjustV2 (strIniFile) ; The binary buffer version.
intFilesize = FileSize (strIniFile)
If !intFilesize Then Return @FALSE ; File may exist empty, but there is nothing to do.

IniWritePvt ("", "", "", strIniFile) ; Force flushing cache to disk.
TimeDelay (1)

strSectionList = IniItemizePvt ("", strIniFile)
strSectionCount = ItemCount (strSectionList, @TAB)

intBBsize = intFilesize + 2 + 2 * strSectionCount
hdlBB = BinaryAlloc (intBBsize)
BinaryPokeStr (hdlBB, 0, @CRLF) ; Add little helper.
If intFilesize != BinaryReadEx (hdlBB, 2, strIniFile, 0, intFilesize) Then Return @FALSE ; Quick way out.

; Left adjust all lines.
strReplaceOld = StrCat (@CRLF, " ")
strReplaceNew = @CRLF
While BinaryReplace (hdlBB, strReplaceOld, strReplaceNew, @TRUE)
EndWhile

; Insert blank line before section headers.
strReplaceOld = StrCat (@CRLF, "[")
strReplaceNew = StrCat (@CRLF, @CRLF, "[")
BinaryReplace (hdlBB, strReplaceOld, strReplaceNew, @TRUE)

; Force adjust to one blank line (including cut little helper).
strReplaceOld = StrCat (@CRLF, @CRLF, @CRLF, "[")
strReplaceNew = StrCat (@CRLF, @CRLF, "[")
While BinaryReplace (hdlBB, strReplaceOld, strReplaceNew, @TRUE)
EndWhile

; Overwrite inifile.
BinaryWriteEx (hdlBB, 0, strIniFile, 0, -1)
blnDone = 0 < BinaryWriteEx (hdlBB, 4, strIniFile, 0, BinaryEodGet (hdlBB)-4)

hdlBB = BinaryFree (hdlBB)
Return blnDone && FileExist (strIniFile)
;..........................................................................................................................................
; This UDF "udfIniSectionAdjust" adjusts the space between sections
; to a single blank line for better human readability.
; This function requires, that all lines within an inifile are delimited with @CRLF as EOL marker.
;
; Detlev Dalitz.20021127.20030727.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


; Test.
strBrowser = StrCat (DirHome (), "browser.exe")

strFileTemp = FileCreateTemp ("TMP")
strFolderTemp = FilePath (strFileTemp)
blnResult = FileDelete (strFileTemp)


:Test1
strIniFile = StrCat (strFolderTemp, "TestA.ini")
strSection = "test"

Message ("Test 1", "Create section.")
blnResult = udfIniSectionCreate (strSection, strIniFile)
RunWait (strBrowser, strIniFile)

Message ("Test 1", "Delete section.")
blnResult = udfIniSectionDelete (strSection, strIniFile)
RunWait (strBrowser, strIniFile)

Message ("Test 1", "Create section.")
blnResult = udfIniSectionCreate (strSection, strIniFile)
RunWait (strBrowser, strIniFile)

Message ("Test 1", "Rename section.")
strSectionOld = "test"
strSectionNew = "renamed"
blnResult = udfIniSectionRename (strSectionOld, strSectionNew, strIniFile)
RunWait (strBrowser, strIniFile)

Message ("Test 1", "Rename section.")
strSectionOld = "renamed"
strSectionNew = "test"
blnResult = udfIniSectionRename (strSectionOld, strSectionNew, strIniFile)
RunWait (strBrowser, strIniFile)


:Test2
strIniFileFrom = StrCat (strFolderTemp, "TestA.ini")
strIniFileTo   = StrCat (strFolderTemp, "TestB.ini")
strSection = "test"

Message ("Test 2", "Create two sections with data.")
FileDelete (strIniFileFrom)
IniWritePvt ("A", "key", "data", strIniFileFrom)
IniWritePvt (strSection, "key1", "data1", strIniFileFrom)
IniWritePvt (strSection, "key2", "data2", strIniFileFrom)
IniWritePvt (strSection, "key3", "data3", strIniFileFrom)
IniWritePvt ("", "", "", strIniFileFrom)
RunWait (strBrowser, strIniFileFrom)

Message ("Test 2", "Copy second section into other inifile.")
FileDelete (strIniFileTo)
blnResult = udfIniSectionCopy (strSection, strIniFileFrom, strIniFileTo)
Run (strBrowser, strIniFileFrom)
RunWait (strBrowser, strIniFileTo)

Message ("Test 2", "Move second section into other inifile.")
FileDelete (strIniFileTo)
blnResult = udfIniSectionMove (strSection, strIniFileFrom, strIniFileTo)
Run (strBrowser, strIniFileFrom)
RunWait (strBrowser, strIniFileTo)


:Test3
strIniFileA = StrCat (strFolderTemp, "TestA.ini")
strIniFileB = StrCat (strFolderTemp, "TestB.ini")
strIniFileMerge = StrCat (strFolderTemp, "TestC.ini")
strSection = "test"

Message ("Test 3", "Create two sections with data in inifile A.")
FileDelete (strIniFileA)
IniWritePvt ("A", "key", "data", strIniFileA)
IniWritePvt (strSection, "key11", "data1", strIniFileA)
IniWritePvt (strSection, "key22", "data2", strIniFileA)
IniWritePvt (strSection, "key33", "data3", strIniFileA)
IniWritePvt ("", "", "", strIniFileA)
RunWait (strBrowser, strIniFileA)

Message ("Test 3", "Create two sections with data in inifile B.")
FileDelete (strIniFileB)
IniWritePvt ("B", "key", "data", strIniFileB)
IniWritePvt (strSection, "key11", "data11", strIniFileB)
IniWritePvt (strSection, "key99", "data99", strIniFileB)
IniWritePvt (strSection, "key88", "data88", strIniFileB)
IniWritePvt ("", "", "", strIniFileB)
RunWait (strBrowser, strIniFileB)

Message ("Test 3", "Merge one section, B over A into inifile C.")
FileDelete (strIniFileMerge)
blnResult = udfIniSectionMerge (strSection, strIniFileA, strIniFileB, strIniFileMerge)
Run (strBrowser, strIniFileA)
Run (strBrowser, strIniFileB)
RunWait (strBrowser, strIniFileMerge)

Message ("Test 3", "Merge one section, A over B into inifile C.")
FileDelete (strIniFileMerge)
blnResult = udfIniSectionMerge (strSection, strIniFileB, strIniFileA, strIniFileMerge)
Run (strBrowser, strIniFileA)
Run (strBrowser, strIniFileB)
RunWait (strBrowser, strIniFileMerge)


:Test4
strIniFile = StrCat (strFolderTemp, "TestA.ini")
strSection = "test"

Message ("Test 4", "Create two sections with data.")
FileDelete (strIniFile)
IniWritePvt ("A", "key", "data", strIniFile)
IniWritePvt (strSection, "key1", "data1", strIniFile)
IniWritePvt (strSection, "key2", "data2", strIniFile)
IniWritePvt (strSection, "key3", "data3", strIniFile)
IniWritePvt ("", "", "", strIniFile)
RunWait (strBrowser, strIniFile)

Message ("Test 4", "Adjust all sections by a blank line.")
blnResult = udfIniSectionAdjust (strIniFile)
RunWait (strBrowser, strIniFile)


:Test5
strIniFile = StrCat (strFolderTemp, "TestA.ini")
strSection = "test"

Message ("Test 5", "Create two sections with data.")
FileDelete (strIniFile)
IniWritePvt ("A", "key3", "data3", strIniFile)
IniWritePvt ("A", "key2", "data2", strIniFile)
IniWritePvt ("A", "key1", "data1", strIniFile)
IniWritePvt (strSection, "key33", "data3", strIniFile)
IniWritePvt (strSection, "key11", "data1", strIniFile)
IniWritePvt (strSection, "key22", "data2", strIniFile)
IniWritePvt ("", "", "", strIniFile)
RunWait (strBrowser, strIniFile)

Message ("Test 5", "Sort one section.")
blnResult = udfIniSectionSort (strSection, strIniFile)
RunWait (strBrowser, strIniFile)

FileDelete (StrCat (strFolderTemp, "Test*.ini"))
Exit
;==========================================================================================================================================