udfArrayCompare
arr udfArrayCompare (arr, arr, str)
;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayCompare (arrA, arrB, strFilename)
arrErr = ArrDimension (7)
hdlFW = 0
If strFilename != ""
   intEMLast = ErrorMode (@OFF)
   LastError ()
   hdlFW = FileOpen (strFilename, "WRITE")
   intLastError = LastError ()
   ErrorMode (intEMLast)
   If intLastError > 0
      ArrInitialize (arrErr, "")
      arrErr[0] = 6
      arrErr[1] = intLastError
      Return arrErr ; Cannot create file.
   EndIf
EndIf

; Valid array?
ArrInitialize (arrErr, "")
blnInvalidA = !ArrInfo (arrA, -1)
blnInvalidB = !ArrInfo (arrB, -1)
arrErr[1] = blnInvalidA | blnInvalidB << 1
If arrErr[1]
   arrErr[0] = 1
   arrErr[2] = blnInvalidA
   arrErr[3] = blnInvalidB
   If hdlFW
      GoSub WriteFileHeader
      GoSub WriteFileLine
      GoSub WriteFileFooterAndClose
   EndIf
   Return arrErr ; Further comparing not possible.
EndIf

If hdlFW Then GoSub WriteFileHeader

; Same dimension?
ArrInitialize (arrErr, "")
intDimsA = ArrInfo (arrA, 0)
intDimsB = ArrInfo (arrB, 0)
arrErr[1] = (intDimsA > intDimsB) | (intDimsA < intDimsB) << 1
If arrErr[1]
   arrErr[0] = 2
   arrErr[2] = intDimsA
   arrErr[3] = intDimsB
   If hdlFW
      GoSub WriteFileLine
      GoSub WriteFileFooterAndClose
   EndIf
   Return arrErr ; Further comparing not possible.
EndIf

; Empty arrays? At this point the question could be also: Are they both dim-0 arrays?
ArrInitialize (arrErr, "")
intElemsA = ArrInfo (arrA, 6)
intElemsB = ArrInfo (arrB, 6)
If (intElemsA == 0) && (intElemsB == 0)
   arrErr[0] = 3 ; arrA and arrB have no elements.
   If hdlFW
      GoSub WriteFileLine
      GoSub WriteFileFooterAndClose
   EndIf
   Return arrErr ; Further comparing not possible.
EndIf

; If we reach here, then both arrays have the same dimension and the same number of elements.
; Now compare element VarType and value.

intErrCount = 0

strIndexFill = StrFill (",0", 2 * (5 - intDimsA))
arrD = ArrDimension (6)
arrE = ArrDimension (6)
For intD = 1 To 5
   arrE[intD] = Max (ArrInfo (arrA, intD) - 1, 0)
Next

; Compare elements.
For intD1 = 0 To arrE[1]
   arrD[1] = intD1
   For intD2 = 0 To arrE[2]
      arrD[2] = intD2
      For intD3 = 0 To arrE[3]
         arrD[3] = intD3
         For intD4 = 0 To arrE[4]
            arrD[4] = intD4
            For intD5 = 0 To arrE[5]
               arrD[5] = intD5
               strIdx = ""
               For intD = 1 To intDimsA
                  strIdx = ItemInsert (arrD[intD], -1, strIdx, ",")
               Next
               blnNEQVarType = VarType (arrA [%strIdx%]) != VarType (arrB [%strIdx%])
               blnNEQValue = arrA [%strIdx%] != arrB [%strIdx%]
               If blnNEQVarType || blnNEQValue
                  intErrCount = intErrCount + blnNEQVarType + blnNEQValue ; Count each difference.
                  arrErr[0] = 4
                  arrErr[1] = blnNEQVarType | blnNEQValue << 1
                  arrErr[2] = strIdx : strIndexFill
                  arrErr[3] = VarType (arrA [%strIdx%])
                  arrErr[4] = VarType (arrB [%strIdx%])
                  arrErr[5] = arrA [%strIdx%]
                  arrErr[6] = arrB [%strIdx%]
                  If hdlFW Then GoSub WriteFileLine
                     Else Return arrErr
               EndIf
            Next
         Next
      Next
   Next
Next

If hdlFW Then GoSub WriteFileFooterAndClose

ArrInitialize (arrErr, "")
arrErr[0] = 0
arrErr[1] = 0
If intErrCount
   arrErr[0] = 5
   arrErr[1] = intErrCount
EndIf
Return arrErr ; from udfArrayCompare.
;..........................................................................................................................................
:WriteFileHeader
arrArrInfo = ArrDimension (8)
arrArrInfo[0] = "ArrInfo;-1;{0};Validity of the array. 1=@TRUE valid, 0=@FALSE invalid."
arrArrInfo[1] = "ArrInfo;0;{1};Number of dimensions in the array."
arrArrInfo[2] = "ArrInfo;1;{2};Number of elements in dimension 1."
arrArrInfo[3] = "ArrInfo;2;{3};Number of elements in dimension 2."
arrArrInfo[4] = "ArrInfo;3;{4};Number of elements in dimension 3."
arrArrInfo[5] = "ArrInfo;4;{5};Number of elements in dimension 4."
arrArrInfo[6] = "ArrInfo;5;{6};Number of elements in dimension 5."
arrArrInfo[7] = "ArrInfo;6;{7};Number of elements in the entire array."

strBOM = "" ; BOM (EF BB BF) for Unicode UTF-8.
FileWrite (hdlFW, strBOM : '<?xml version="1.0" encoding="utf-8" standalone="yes"?>') ; XML declaration line with leading BOM (EF BB BF).
FileWrite (hdlFW, "<ARRAY_COMPARE>")         ; Open node "ARRAY_COMPARE".
FileWrite (hdlFW, "<ARRINFO_A><![CDATA[")    ; Open node "ARRINFO_A".
If arrErr[0] == 1 && arrErr[2] == 1
   FileWrite (hdlFW, StrReplace (arrArrInfo[0], "{0}", 0))
Else
   FileWrite (hdlFW, StrReplace (arrArrInfo[0], "{0}", 1))
   For intI = 1 To 7
      FileWrite (hdlFW, StrReplace (arrArrInfo[intI], "{" : intI : "}", ArrInfo (arrA, intI - 1)))
   Next
EndIf
FileWrite (hdlFW, "]]></ARRINFO_A>")         ; Close node "ARRINFO_A".
FileWrite (hdlFW, "<ARRINFO_B><![CDATA[")    ; Open node "ARRINFO_B".
If arrErr[0] == 1 && arrErr[3] == 1
   FileWrite (hdlFW, StrReplace (arrArrInfo[0], "{0}", 0))
Else
   FileWrite (hdlFW, StrReplace (arrArrInfo[0], "{0}", 1))
   For intI = 1 To 7
      FileWrite (hdlFW, StrReplace (arrArrInfo[intI], "{" : intI : "}", ArrInfo (arrB, intI - 1)))
   Next
EndIf
FileWrite (hdlFW, "]]></ARRINFO_B>")         ; Close node "ARRINFO_B".
FileWrite (hdlFW, "<COMPARE_RESULT><![CDATA[") ; Open node "COMPARE_DATA".
Drop (arrArrInfo)
Return ; from GoSub WriteFileHeader.
;..........................................................................................................................................
:WriteFileLine
strOut = ""
For intI = 0 To 6
   strOut = strOut : ";" : arrErr[intI]
Next
strOut = ChrStringToUnicode ("" : StrSub (strOut, 2, -1))
intPrevCodePage = ChrSetCodepage (65001)
FileWrite (hdlFW, strOut)
ChrSetCodepage (intPrevCodePage)
Return ; from GoSub WriteFileLine.
;..........................................................................................................................................
:WriteFileFooterAndClose
FileWrite (hdlFW, "]]></COMPARE_RESULT>")   ; Close node "ERRORDATA".
FileWrite (hdlFW, "</ARRAY_COMPARE>")     ; Close node "ARRAY_COMPARE".
hdlFW = FileClose (hdlFW)
Return ; from GoSub WriteFileFooterAndClose.
;..........................................................................................................................................
; This function "udfArrayCompare" compares two Winbatch arrays.
;
; Parameter:
; arrA .......... First array.
; arrB .......... Second array.
; strFilename ... Optional filename for writing out error data to XML file when comparing array elements.
;
; If the optional filename is left blank, then the function returns at the first encountered error.
;
; Return value:
; A dim-1 array of 7 elements. This error array is filled with data in relation to the error context.
; If the option "output to file" is used, then a XML file is created, which contains a list of all mismatched elements.
;
; Return codes stored in error array:
;
; E[0] Code         = 1  ... Array is not valid.
; E[1] Subcode      = 1  ... Array A is not valid.
; E[1] Subcode      = 2  ... Array B is not valid.
; E[1] Subcode      = 3  ... Both arrays A and B are not valid.
;
; E[0] Code         = 2  ... Array dimensions are different.
; E[1] Subcode      = 1  ... Array A has more dimensions than array B.
; E[1] Subcode      = 2  ... Array B has more dimensions than array A.
; E[2] Dimensions A ........ Number of dimensions in array A.
; E[3] Dimensions B ........ Number of dimensions in array B.
;
; E[0] Code         = 3  ... Both arrays A and B have no elements.
;
; E[0] Code         = 4  ... Array element mismatch.
; E[1] Subcode      = 1  ... VarType mismatch
; E[1] Subcode      = 2  ... Value mismatch.
; E[1] Subcode      = 3  ... Both VarType and Value mismatch.
; E[2] Index        ........ Element index in format "0,0,0,0,0".
; E[3] VarType A    ........ VarType of element in array A.
; E[4] VarType B    ........ VarType of element in array B.
; E[5] Value A      ........ Value of element in array A.
; E[6] Value B      ........ Value of element in array B.
;
; E[0] Code         = 5  ... Only set when option "output to file" is used.
; E[1] Error count  ........ Number of errors count.
;
; E[0] Code         = 6  ... Report file creation failed.
; E[1] Subcode      = 1  ... WinBatch error code.
;
;
; Detlev Dalitz.20110123.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayFromList (strList, strDelimiter)
If strList == "" Then Return ArrDimension (0) ; Return dim-0 array with no element.
If strDelimiter == "" Then Return ArrayFromStr (strList) ; Return dim-1 array with one character per array element.

arrD = ArrDimension (6)
ArrInitialize (arrD, "")

arrE = ArrDimension (6)
ArrInitialize (arrE, 0)

arrE [0] = Min (5, StrLen (strDelimiter))
arrD [1] = StrSub (strDelimiter, 1, 1)
arrE [1] = ItemCount (strList, arrD [1])
strItem = ItemExtract (1, strList, arrD [1])
For intI = 2 To arrE [0]
   arrD [intI] = StrSub (strDelimiter, intI, 1)
   arrE [IntI] = ItemCount (strItem, arrD [intI])
   strItem = ItemExtract (1, strItem, arrD [intI])
Next

arrArray = ArrDimension (arrE[1], arrE[2], arrE[3], arrE[4], arrE[5])

Switch arrE [0]
Case 1
   For intD1 = 1 To arrE [1]
      arrArray [intD1 - 1] = ItemExtract (intD1, strList, arrD [1])
   Next
   Break
Case 2
   For intD1 = 1 To arrE [1]
      strItem1 = ItemExtract (intD1, strList, arrD [1])
      For intD2 = 1 To arrE [2]
         arrArray [intD1 - 1, intD2 - 1] = ItemExtract (intD2, strItem1, arrD [2])
      Next
   Next
   Break
Case 3
   For intD1 = 1 To arrE [1]
      strItem1 = ItemExtract (intD1, strList, arrD [1])
      For intD2 = 1 To arrE [2]
         strItem2 = ItemExtract (intD2, strItem1, arrD [2])
         For intD3 = 1 To arrE [3]
            arrArray [intD1 - 1, intD2 - 1, intD3 - 1] = ItemExtract (intD3, strItem2, arrD [3])
         Next
      Next
   Next
   Break
Case 4
   For intD1 = 1 To arrE [1]
      strItem1 = ItemExtract (intD1, strList, arrD [1])
      For intD2 = 1 To arrE [2]
         strItem2 = ItemExtract (intD2, strItem1, arrD [2])
         For intD3 = 1 To arrE [3]
            strItem3 = ItemExtract (intD3, strItem2, arrD [3])
            For intD4 = 1 To arrE [4]
               arrArray [intD1 - 1, intD2 - 1, intD3 - 1, intD4 - 1] = ItemExtract (intD4, strItem3, arrD [4])
            Next
         Next
      Next
   Next
   Break
Case 5
   For intD1 = 1 To arrE [1]
      strItem1 = ItemExtract (intD1, strList, arrD [1])
      For intD2 = 1 To arrE [2]
         strItem2 = ItemExtract (intD2, strItem1, arrD [2])
         For intD3 = 1 To arrE [3]
            strItem3 = ItemExtract (intD3, strItem2, arrD [3])
            For intD4 = 1 To arrE [4]
               strItem4 = ItemExtract (intD4, strItem3, arrD [4])
               For intD5 = 1 To arrE [5]
                  arrArray [intD1 - 1, intD2 - 1, intD3 - 1, intD4 - 1, intD5 - 1] = ItemExtract (intD5, strItem4, arrD [5])
               Next
            Next
         Next
      Next
   Next
   Break
EndSwitch

Return arrArray
;..........................................................................................................................................
; This UDF "udfArrayFromList" returns a dim-1 .. dim-5 array, whose array elements are filled
; by iterative separating the given input string into chunks of substrings.
;
; The input string is a serialized string list representation of a dim-1 .. dim-5 array.
; The elements are delimited by 1 .. 5 delimiter string characters accordingly to their array dimension.
;
; If the given strList is empty, then the function returns a dim-0 array with no element.
;
; If the given strDelimiter is empty, then the function returns a dim-1 array with each element filled
; with one character of the given strList, which has been splitted into separate chars.
;
; Syntax:
; arr:Array = udfArrayFromList (str:String, str:Delimiter)
;
; Detlev Dalitz.20030225.20090520.20110123.
;..........................................................................................................................................
;
; Example 1:
;
;   ; Create dim-2 array.
;   ; One Element        = "o".
;   ; Dim2 = 2 x Element = "o+o" ; Delim "+".
;   ; Dim1 = 3 x Dim1    = "o+o=o+o=o+o" ; Delim "=".
;   ;
;   ;     | 0  1
;   ;   --+------
;   ;   0 | a  b
;   ;   1 | c  d
;   ;   2 | e  f
;
;   intElementsShouldBe = 3 * 2 ; 6.
;
;   strList = "o+o=o+o=o+o"
;   strDelimiter = "=+" ; Dimensions 1-2.
;
;   intElementsAre = StrLen (StrClean (strList, strDelimiter, "", @TRUE, 1)) ; 6.
;
;   arrA = udfArrayFromList (strList, strDelimiter)
;
;   arrB = ArrDimension (8)
;   arrB[0] = ArrInfo (arrA, -1) ; Validity of the array. 1=@TRUE valid, 0=@FALSE invalid.
;   arrB[1] = ArrInfo (arrA, 0)  ; Number of dimensions in the array.
;   arrB[2] = ArrInfo (arrA, 1)  ; Number of elements in dimension 1.
;   arrB[3] = ArrInfo (arrA, 2)  ; Number of elements in dimension 2.
;   arrB[4] = ArrInfo (arrA, 3)  ; Number of elements in dimension 3.
;   arrB[5] = ArrInfo (arrA, 4)  ; Number of elements in dimension 4.
;   arrB[6] = ArrInfo (arrA, 5)  ; Number of elements in dimension 5.
;   arrB[7] = ArrInfo (arrA, 6)  ; Number of elements in the entire array.
;
;   strListInfo = udfArrayToList (arrB, "|") ; 1|2|3|2|0|0|0|6.
;
;..........................................................................................................................................
;
; Example 2:
;
;   ; Create dim-5 array.
;   ; One Element        = "o".
;   ; Dim5 = 2 x Element = "o+o" ; Delim "+".
;   ; Dim4 = 4 x Dim5    = "o+o=o+o=o+o=o+o" ; Delim "=".
;   ; Dim3 = 3 x Dim4    = "o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o" ; Delim "/".
;   ; Dim2 = 2 x Dim3    = "o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o|o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o" ; Delim "|".
;   ; Dim1 = 2 x Dim2    = "o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o|o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o@o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o|o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o" ; Delim "@".
;
;   intElementsShouldBe = 2 * 2 * 3 * 4 * 2 ; 96.
;
;   strList = "o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o|o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o@o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o|o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o"
;   strDelimiter = "@|/=+" ; Dimensions 1-2-3-4-5.
;
;   intElementsAre = StrLen (StrClean (strList, strDelimiter, "", @TRUE, 1)) ; 96.
;
;   arrA = udfArrayFromList (strList, strDelimiter)
;
;   arrB = ArrDimension (8)
;   arrB[0] = ArrInfo (arrA, -1) ; Validity of the array. 1=@TRUE valid, 0=@FALSE invalid.
;   arrB[1] = ArrInfo (arrA, 0)  ; Number of dimensions in the array.
;   arrB[2] = ArrInfo (arrA, 1)  ; Number of elements in dimension 1.
;   arrB[3] = ArrInfo (arrA, 2)  ; Number of elements in dimension 2.
;   arrB[4] = ArrInfo (arrA, 3)  ; Number of elements in dimension 3.
;   arrB[5] = ArrInfo (arrA, 4)  ; Number of elements in dimension 4.
;   arrB[6] = ArrInfo (arrA, 5)  ; Number of elements in dimension 5.
;   arrB[7] = ArrInfo (arrA, 6)  ; Number of elements in the entire array.
;
;   strListInfo = udfArrayToList (arrB, "|") ; 1|5|2|2|3|4|2|96.
;
;..........................................................................................................................................
;
;   Previous code for ArrayFromString functionality (from version 20090520):
;
;   If strDelimiter == ""
;      strDelim = Num2Char (7) ; Surrogate char.
;      intSizeBB = StrLen (strList) << 1
;      hdlBB = BinaryAlloc (intSizeBB)
;      BinaryPokeStrW (hdlBB, 0, strList)
;      BinaryReplace (hdlBB, "", strDelim, @TRUE)
;      arrArray = Arrayize (BinaryPeekStr (hdlBB, 0, intSizeBB - 1), strDelim)
;      hdlBB = BinaryFree (hdlBB)
;      Return arrArray ; Return dim1 array with each element containing one char.
;   EndIf
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;----------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayToList (arrArray, strDelimiter)
If !ArrInfo (arrArray, -1) Then Return "" ; No array.
If !ArrInfo (arrArray, 6) Then Return "" ; No elements.

arrE = ArrDimension (6)
arrE [0] = ArrInfo (arrArray, 0)
For intI = 1 To 5
   arrE [intI] = Max (0, ArrInfo (arrArray, intI) - 1)
Next

arrD = ArrDimension (6)
ArrInitialize (arrD, "")
intLen = Min (arrE [0], StrLen (strDelimiter))
For intI = 1 To intLen
   arrD [intI] = StrSub (strDelimiter, intI, 1)
Next

Switch arrE [0]
Case 1
   strItemList1 = ""
   For intD1 = 0 To arrE [1]
      If !!VarType (arrArray [intD1])
         strItemList1 = strItemList1 : arrD [1] : arrArray [intD1]
      Else
         strItemList1 = strItemList1 : arrD [1]
      EndIf
   Next
   If arrD [1] != "" Then strItemList1 = StrSub (strItemList1, 2, -1)
   Break
Case 2
   strItemList1 = ""
   For intD1 = 0 To arrE [1]
      strItemList2 = ""
      For intD2 = 0 To arrE [2]
         If !!VarType (arrArray [intD1, intD2])
            strItemList2 = strItemList2 : arrD [2] : arrArray [intD1, intD2]
         Else
            strItemList2 = strItemList2 : arrD [2]
         EndIf
      Next
      If arrD [2] != "" Then strItemList2 = StrSub (strItemList2, 2, -1)
      strItemList1 = strItemList1 : arrD [1] : strItemList2
   Next
   If arrD [1] != "" Then strItemList1 = StrSub (strItemList1, 2, -1)
   Break
Case 3
   strItemList1 = ""
   For intD1 = 0 To arrE [1]
      strItemList2 = ""
      For intD2 = 0 To arrE [2]
         strItemList3 = ""
         For intD3 = 0 To arrE [3]
            If !!VarType (arrArray [intD1, intD2, intD3])
               strItemList3 = strItemList3 : arrD [3] : arrArray [intD1, intD2, intD3]
            Else
               strItemList3 = strItemList3 : arrD [3]
            EndIf
         Next
         If arrD [3] != "" Then strItemList3 = StrSub (strItemList3, 2, -1)
         strItemList2 = strItemList2 : arrD [2] : strItemList3
      Next
      If arrD [2] != "" Then strItemList2 = StrSub (strItemList2, 2, -1)
      strItemList1 = strItemList1 : arrD [1] : strItemList2
   Next
   If arrD [1] != "" Then strItemList1 = StrSub (strItemList1, 2, -1)
   Break
Case 4
   strItemList1 = ""
   For intD1 = 0 To arrE [1]
      strItemList2 = ""
      For intD2 = 0 To arrE [2]
         strItemList3 = ""
         For intD3 = 0 To arrE [3]
            strItemList4 = ""
            For intD4 = 0 To arrE [4]
               If !!VarType (arrArray [intD1, intD2, intD3, intD4])
                  strItemList4 = strItemList4 : arrD [4] : arrArray [intD1, intD2, intD3, intD4]
               Else
                  strItemList4 = strItemList4 : arrD [4]
               EndIf
            Next
            If arrD [4] != "" Then strItemList4 = StrSub (strItemList4, 2, -1)
            strItemList3 = strItemList3 : arrD [3] : strItemList4
         Next
         If arrD [3] != "" Then strItemList3 = StrSub (strItemList3, 2, -1)
         strItemList2 = strItemList2 : arrD [2] : strItemList3
      Next
      If arrD [2] != "" Then strItemList2 = StrSub (strItemList2, 2, -1)
      strItemList1 = strItemList1 : arrD [1] : strItemList2
   Next
   If arrD [1] != "" Then strItemList1 = StrSub (strItemList1, 2, -1)
   Break
Case 5
   strItemList1 = ""
   For intD1 = 0 To arrE [1]
      strItemList2 = ""
      For intD2 = 0 To arrE [2]
         strItemList3 = ""
         For intD3 = 0 To arrE [3]
            strItemList4 = ""
            For intD4 = 0 To arrE [4]
               strItemList5 = ""
               For intD5 = 0 To arrE [5]
                  If !!VarType (arrArray [intD1, intD2, intD3, intD4, intD5])
                     strItemList5 = strItemList5 : arrD [5] : arrArray [intD1, intD2, intD3, intD4, intD5]
                  Else
                     strItemList5 = strItemList5 : arrD [5]
                  EndIf
               Next
               If arrD [5] != "" Then strItemList5 = StrSub (strItemList5, 2, -1)
               strItemList4 = strItemList4 : arrD [4] : strItemList5
            Next
            If arrD [4] != "" Then strItemList4 = StrSub (strItemList4, 2, -1)
            strItemList3 = strItemList3 : arrD [3] : strItemList4
         Next
         If arrD [3] != "" Then strItemList3 = StrSub (strItemList3, 2, -1)
         strItemList2 = strItemList2 : arrD [2] : strItemList3
      Next
      If arrD [2] != "" Then strItemList2 = StrSub (strItemList2, 2, -1)
      strItemList1 = strItemList1 : arrD [1] : strItemList2
   Next
   If arrD [1] != "" Then strItemList1 = StrSub (strItemList1, 2, -1)
   Break
EndSwitch
Return strItemList1
;----------------------------------------------------------------------------------------------------------------------
; This UDF "udfArrayToList" converts a given array into a serialized itemlist
; with each item separated by the delimiter character accordingly to the current dimension.
;
; Example: strMyItemList = udfArrayToList (arrMyArray, @TAB)
; Creates an itemlist from array.
;
; Note:
; This UDF supports dim-1 to dim-5 array.
; An array element which is not initialized has a Vartype=0 (undefined).
; Therefore an empty item will be appended to target itemlist.
;
; Detlev Dalitz.20020718.20090519.20110923.
;----------------------------------------------------------------------------------------------------------------------
#EndFunction
;----------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayUnloadToFile (arrArray, strFilename)
If !ArrInfo (arrArray, -1) Then Return 0 ; No array.
If !ArrInfo (arrArray, 6) Then Return 0 ; No elements.

arrArrInfo = ArrDimension (8)
arrArrInfo[0] = "ArrInfo;-1;{0};Validity of the array. 1=@TRUE valid, 0=@FALSE invalid."
arrArrInfo[1] = "ArrInfo;0;{1};Number of dimensions in the array."
arrArrInfo[2] = "ArrInfo;1;{2};Number of elements in dimension 1."
arrArrInfo[3] = "ArrInfo;2;{3};Number of elements in dimension 2."
arrArrInfo[4] = "ArrInfo;3;{4};Number of elements in dimension 3."
arrArrInfo[5] = "ArrInfo;4;{5};Number of elements in dimension 4."
arrArrInfo[6] = "ArrInfo;5;{6};Number of elements in dimension 5."
arrArrInfo[7] = "ArrInfo;6;{7};Number of elements in the entire array."

intDims = ArrInfo (arrArray, 0)
strIndexFill = StrFill (",0", 2 * (5 - intDims))
arrD = ArrDimension (6)
arrE = ArrDimension (6)
For intD = 1 To 5
   arrE[intD] = Max (ArrInfo (arrArray, intD) - 1, 0)
Next

hdlFW = FileOpen (strFilename, "WRITE")

strBOM = "" ; BOM (EF BB BF) for Unicode UTF-8.
FileWrite (hdlFW, strBOM : '<?xml version="1.0" encoding="utf-8" standalone="yes"?>') ; XML declaration line with leading BOM (EF BB BF).
FileWrite (hdlFW, "<ARRAY>")            ; Open node "ARRAY".
FileWrite (hdlFW, "<ARRINFO><![CDATA[") ; Open node "ARRINFO".
; Write data.
For intI = 0 To 7
   FileWrite (hdlFW, StrReplace (arrArrInfo[intI], "{" : intI : "}", ArrInfo (arrArray, intI - 1)))
Next
FileWrite (hdlFW, "]]></ARRINFO>")      ; Close node "ARRINFO".
FileWrite (hdlFW, "<ARRDATA><![CDATA[") ; Open node "ARRDATA".
; Write data.
For intD1 = 0 To arrE[1]
   arrD[1] = intD1
   For intD2 = 0 To arrE[2]
      arrD[2] = intD2
      For intD3 = 0 To arrE[3]
         arrD[3] = intD3
         For intD4 = 0 To arrE[4]
            arrD[4] = intD4
            For intD5 = 0 To arrE[5]
               arrD[5] = intD5
               strIdx = ""
               For intD = 1 To intDims
                  strIdx = ItemInsert (arrD[intD], -1, strIdx, ",")
               Next
               strArrIndex = strIdx : strIndexFill
               intVarType = VarType (arrArray [%strIdx%])
               If intVarType
                  strOut = ChrStringToUnicode ("" : arrArray [%strIdx%])
                  intPrevCodePage = ChrSetCodepage (65001)
                  FileWrite (hdlFW, strArrIndex : ";" : intVarType : ";" : strOut)
                  ChrSetCodepage (intPrevCodePage)
               Else
                  FileWrite (hdlFW, strArrIndex : ";" : intVarType : ";")
               EndIf
            Next
         Next
      Next
   Next
Next
FileWrite (hdlFW, "]]></ARRDATA>") ; Close node "ARRDATA".
FileWrite (hdlFW, "</ARRAY>")      ; Close node "ARRAY".
hdlFW = FileClose (hdlFW)
Return FileSizeEx (strFilename)
;..........................................................................................................................................
; This function "udfArrayUnloadToFile" creates a specific array definition textfile (xml) from array,
; which can be used to load data back into an array by function "udfArrayLoadFromFile".
;
; Detlev Dalitz.20010731.20020828.20030222.20090528.20100122.20100125.20110123.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayLoadFromFile (strFilename)
intResult = 0
If !FileSizeEx (strFilename) Then Goto CANCEL

IntControl (65, 4096 * 256, 0, 0, 0) ; Enlarge fileread buffer for speedy access.

arrArrInfo = ArrDimension (8)
arrArrInfo[0] = "ArrInfo;-1;"
arrArrInfo[1] = "ArrInfo;0;"
arrArrInfo[2] = "ArrInfo;1;"
arrArrInfo[3] = "ArrInfo;2;"
arrArrInfo[4] = "ArrInfo;3;"
arrArrInfo[5] = "ArrInfo;4;"
arrArrInfo[6] = "ArrInfo;5;"
arrArrInfo[7] = "ArrInfo;6;"

hdlFR = FileOpen (strFilename, "READ")
If !hdlFR Then Goto CANCEL

While @TRUE
   strLine = FileRead (hdlFR)
   strLine = StrTrim (strLine)
   If strLine == "*EOF*" Then Goto CANCEL
   If strLine == "<ARRINFO><![CDATA[" Then Break
EndWhile

; Read header.
While @TRUE
   strLine = FileRead (hdlFR)
   strLine = StrTrim (strLine)
   If strLine == "*EOF*" Then Goto CANCEL
   If strLine == "]]></ARRINFO>" Then Break
   If strLine == "" Then Continue
   If 1 == StrIndex (strLine, arrArrInfo[0], 1, @FWDSCAN)
      arrArrInfo[0] = ItemExtract (3, strLine, ";")
      ElseIf 1 == StrIndex (strLine, arrArrInfo[1], 1, @FWDSCAN)
      arrArrInfo[1] = ItemExtract (3, strLine, ";")
      ElseIf 1 == StrIndex (strLine, arrArrInfo[2], 1, @FWDSCAN)
      arrArrInfo[2] = ItemExtract (3, strLine, ";")
      ElseIf 1 == StrIndex (strLine, arrArrInfo[3], 1, @FWDSCAN)
      arrArrInfo[3] = ItemExtract (3, strLine, ";")
      ElseIf 1 == StrIndex (strLine, arrArrInfo[4], 1, @FWDSCAN)
      arrArrInfo[4] = ItemExtract (3, strLine, ";")
      ElseIf 1 == StrIndex (strLine, arrArrInfo[5], 1, @FWDSCAN)
      arrArrInfo[5] = ItemExtract (3, strLine, ";")
      ElseIf 1 == StrIndex (strLine, arrArrInfo[6], 1, @FWDSCAN)
      arrArrInfo[6] = ItemExtract (3, strLine, ";")
      ElseIf 1 == StrIndex (strLine, arrArrInfo[7], 1, @FWDSCAN)
      arrArrInfo[7] = ItemExtract (3, strLine, ";")
   EndIf
EndWhile

While @TRUE
   strLine = FileRead (hdlFR)
   strLine = StrTrim (strLine)
   If strLine == "*EOF*" Then Goto CANCEL
   If strLine == "<ARRDATA><![CDATA[" Then Break
EndWhile

; Declare Array.
arrArray = ArrDimension (arrArrInfo[2], arrArrInfo[3], arrArrInfo[4], arrArrInfo[5], arrArrInfo[6])
intDimNext = ArrInfo (arrArray, 0) + 1

; Read data.
While @TRUE
   strLine = FileRead (hdlFR)
   strLine = StrTrim (strLine)
   If strLine == "*EOF*" Then Goto CANCEL
   If strLine == "]]></ARRDATA>" Then Break
   If strLine == "" Then Continue
   strArrIndex = ItemExtract (1, strLine, ";")
   intLen1 = StrLen (strArrIndex)
   intArrVarType = Int (ItemExtract (2, strLine, ";"))
   intLen2 = StrLen (intArrVarType)
   strArrData = StrSub (strLine, intLen1 + intLen2 + 3, -1)
   For intD = 5 To intDimNext By -1
      strArrIndex = ItemRemove (intD, strArrIndex, ",")
   Next
   Switch intArrVarType
   Case 2  ; VARTYPE_STRING
      intPrevCodePage = ChrSetCodepage (65001)
      strUnicode = ChrStringToUnicode (strArrData)
      ChrSetCodepage (intPrevCodePage)
      arrArray [%strArrIndex%] = ChrUnicodeToString (strUnicode)
      Break
   Case 32 ; VARTYPE_FLOATNUM
      arrArray [%strArrIndex%] = 1.0 * strArrData
      Break
      ;   Case 64   ; VARTYPE_BINARY
      ;   Case 128  ; VARTYPE_LPWSTR or "Unicode"
      ;   Case 256  ; VARTYPE_ARRAY
      ;   Case 512  ; VARTYPE_VARIANT
      ;   Case 1024 ; VARTYPE_COMOBJECT
      ;   Case 0    ; VARTYPE_UNDEFINED
      ;   Case -1   ; VARTYPE_RESWORD
      ;      Break
   Case intArrVarType
      If intArrVarType & 1 Then arrArray [%strArrIndex%] = 1 * strArrData
      ; 1=VARTYPE_INT; 65=VARTYPE_INT|VARTYPE_BINARY, 17=VARTYPE_INT|VARTYPE_OLEOBJECT, 5=VARTYPE_INT|VARTYPE_FILE, 1537=VARTYPE_INT|VARTYPE_VARIANT|VARTYPE_COMOBJECT
      Break
   EndSwitch
EndWhile
intResult = 1

:CANCEL
If IsDefined (hdlFR) Then hdlFR = FileClose (hdlFR)
If !intResult Then Return ArrDimension (0)
Return arrArray
;..........................................................................................................................................
; This function ""udfArrayLoadFromFile" creates an array from a specific array definition textfile (xml),
; which has been created previously by function "udfArrayUnloadToFile" resp. by other method.
;
; Detlev Dalitz.20010731.20020828.20030222.20090528.20100122.20100125.20110123.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------



; Test.

strMsgTitle = "Demo: udfArrayFromList / udfArrayToList / udfArrayUnloadToFile / udfArrayLoadFromFile / udfArrayCompare"

strDirScript = DirScript ()
strFilenameA = strDirScript : "ARRAY.A.txt.xml"
strFilenameB = strDirScript : "ARRAY.B.txt.xml"
strFileCompareResult = strDirScript : "ARRAY.Compare.txt.xml"

;----
;   ; Create dim-2 array.
;   ; One Element        = "o".
;   ; Dim2 = 2 x Element = "o+o" ; Delim "+".
;   ; Dim1 = 3 x Dim1    = "o+o=o+o=o+o" ; Delim "=".
;   ; Elements = 3*2 = 6.
;
;   strList = "ä+ö=ü+ß=é+è"
;   strDelimiter = "=+" ; Dimensions 1-2.
;   arrA = udfArrayFromList (strList, strDelimiter)
;----
;   ; Create dim-5 array.
;   ; One Element        = "o".
;   ; Dim5 = 2 x Element = "o+o" ; Delim "+".
;   ; Dim4 = 4 x Dim5    = "o+o=o+o=o+o=o+o" ; Delim "=".
;   ; Dim3 = 3 x Dim4    = "o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o" ; Delim "/".
;   ; Dim2 = 2 x Dim3    = "o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o|o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o" ; Delim "|".
;   ; Dim1 = 2 x Dim2    = "o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o|o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o@o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o|o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o" ; Delim "@".
;   ; Elements = 2*2*3*4*2 = 96.
;----

strList = "ä+ö=ü+ß=é+è=Ò+Ó/Ä+Ö=Ü+©=É+È=Ý+ÿ/o+o=o+o=o+o=o+o|o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o@o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o|o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o/o+o=o+o=o+o=o+o"
strDelimiter = "@|/=+" ; Dimensions 1-2-3-4-5.
arrA = udfArrayFromList (strList, strDelimiter)


; Unload array A to xml file.
intResult = udfArrayUnloadToFile (arrA, strFilenameA)

; Load array B from xml file.
arrB = udfArrayLoadFromFile (strFilenameA)

; Unload array B to xml file.
intResult = udfArrayUnloadToFile (arrB, strFilenameB)

; Compare xml files.
intResult = FileCompare (strFilenameA, strFilenameB) ; Should be 0 ==> Files content are identical.
If !!intResult Then Pause ("Error", "Files are different.")



; Test 1.
; Compare array A and B. No report file.

arrResult = udfArrayCompare (arrA, arrB, "") ; No report file.

strMsgTitle = "udfArrayCompare - Test 1"
strMsgText = "Error Code.Subcode = " : arrResult[0] : "." : arrResult[1]

If !!arrResult[0] Then Pause (strMsgTitle, strMsgText)
   Else Pause (strMsgTitle, "No Error.")



; Test 2.
; Compare array A and B. No report file.

; Change array B to get some error result.
arrB[0, 0, 0, 0, 0] = @PI

arrResult = udfArrayCompare (arrA, arrB, "") ; No report file.

strMsgTitle = "udfArrayCompare - Test 2"
strMsgText = "Error Code.Subcode = " : arrResult[0] : "." : arrResult[1]                 ; "4.3".
strMsgText = strMsgText : @LF : @LF : "Index = " : arrResult[2]                          ; "0,0,0,0,0".
strMsgText = strMsgText : @LF : @LF : "Vartype = " : arrResult[3] : " | " : arrResult[4] ; "2 | 32".
strMsgText = strMsgText : @LF : @LF : "Value = " : arrResult[5] : " | " : arrResult[6]   ; "ä | 3.14159265".

If !!arrResult[0] Then Pause (strMsgTitle, strMsgText)
   Else Pause (strMsgTitle, "No Error.")



; Test 3.
; Compare array A and B. Create report file.

; Change array B to get some error result.
arrB[0, 0, 0, 0, 0] = @PI
arrB[0, 0, 0, 1, 0] = "Test"
arrB[0, 0, 1, 0, 0] = 221
arrB[0, 0, 1, 1, 0] = ObjectType ("BOOL", @TRUE)

arrResult = udfArrayCompare (arrA, arrB, strFileCompareResult)

strMsgTitle = "udfArrayCompare - Test 3"
strMsgText = "Error Code.Subcode = " : arrResult[0] : "." : arrResult[1] ; "5.7". ==> Report file, 7 errors.

If !!arrResult[0] Then Pause (strMsgTitle, strMsgText)
   Else Pause (strMsgTitle, "No Error.")

; Report file.
; 4;3;0,0,0,0,0;2;32;ä;3.14159265  ==> two errors: VarType and Value.
; 4;2;0,0,0,1,0;2;2;ü;Test         ==> one error : Value.
; 4;3;0,0,1,0,0;2;1;Ä;221          ==> two errors: VarType and Value.
; 4;3;0,0,1,1,0;2;512;Ü;-1         ==> two errors: VarType and Value.

; Display Result.
blnResult = RunShell (strFilenameA, "", "", @ZOOMED, @NOWAIT)
TimeDelay (4)
blnResult = RunShell (strFilenameB, "", "", @ZOOMED, @NOWAIT)
TimeDelay (4)
blnResult = RunShell (strFileCompareResult, "", "", @ZOOMED, @NOWAIT)
TimeDelay (4)
blnResult = ShellExecute (strFileCompareResult, "", "", @ZOOMED, "")

:CANCEL
Exit