Since we can use the Free Basic intrinsic array procedures to work with arrays of CWSTR strings, I have added some helper functions to CWSTR.inc.
' ########################################################################################
' *** HELPER FUNCTIONS ***
' ########################################################################################
' ========================================================================================
' qsort CWstr comparison function
' ========================================================================================
PRIVATE FUNCTION AfxCWstrArrayCompare CDECL (BYVAL a AS CWSTR PTR, BYVAL b AS CWSTR PTR) AS LONG
FUNCTION = wcscmp(cast(WSTRING PTR, a->m_pBuffer), cast(WSTRING PTR, b->m_pBuffer))
END FUNCTION
' ========================================================================================
' ========================================================================================
' Reverse qsort CWstr comparison function
' ========================================================================================
PRIVATE FUNCTION AfxCWStrArrayReverseCompare CDECL (BYVAL a AS CWSTR PTR, BYVAL b AS CWSTR PTR) AS LONG
DIM r AS LONG = wcscmp(cast(WSTRING PTR, a->m_pBuffer), cast(WSTRING PTR, b->m_pBuffer))
IF r = 1 THEN r = -1 ELSE IF r = -1 THEN r = 1
RETURN r
END FUNCTION
' ========================================================================================
' ========================================================================================
' Sorts a one-dimensional CWSTR array calling the C qsort function.
' Parameters:
' - rgwstr : Start of target array.
' - numElm : Number of elements in the array.
' - bAscend: TRUE for sorting in ascending order; FALSE for sorting in descending order.
' Example:
' DIM rg(1 TO 10) AS CWSTR
' FOR i AS LONG = 1 TO 10
' rg(i) = "string " & i
' NEXT
' FOR i AS LONG = 1 TO 10
' print rg(i)
' NEXT
' print "---- after sorting ----"
' AfxCWstrSort @rg(1), 10, TRUE
' FOR i AS LONG = 1 TO 10
' print rg(i)
' NEXT
' ========================================================================================
PRIVATE SUB AfxCWstrSort (BYREF rgwstr AS ANY PTR, BYVAL numElm AS LONG, BYVAL bAscend AS BOOLEAN = TRUE)
IF rgwstr = NULL OR numElm < 2 THEN EXIT SUB
IF bAscend THEN
qsort rgwstr, numElm, SIZEOF(CWSTR), CPTR(ANY PTR, @AfxCWstrArrayCompare)
ELSE
qsort rgwstr, numElm, SIZEOF(CWSTR) , CPTR(ANY PTR, @AfxCWStrArrayReverseCompare)
END IF
END SUB
' ========================================================================================
' ========================================================================================
PRIVATE SUB AfxCWstrArraySort (rgwstr() AS CWSTR, BYVAL bAscend AS BOOLEAN = TRUE)
DIM numElm AS LONG = UBOUND(rgwstr) - LBOUND(rgwstr) + 1
AfxCWstrSort @rgwstr(LBOUND(rgwstr)), numElm, bAscend
END SUB
' ========================================================================================
' ========================================================================================
' Appends a CWSTR at the end of a one-dimensional CWSTR array.
' Parameters:
' - rgwstr(): The CWSTR array
' - cws: The CWSTR to append
' Return value:
' TRUE or FALSE
' Example:
' #INCLUDE ONCE "Afx/CWSTR.inc"
' USING Afx
' REDIM rg(1 TO 10) AS CWSTR
' FOR i AS LONG = 1 TO 10
' rg(i) = "string " & i
' NEXT
' AfxCwstrArrayAppend(rg(), "string 11")
' FOR i AS LONG = LBOUND(rg) TO UBOUND(rg)
' print rg(i)
' NEXT
' Note: REDIM PRESERVE cannot be used on fixed-size arrays - i.e. arrays with constant bounds
' made with DIM. If after calling REDIM PRESERVE the upper bound has not changed, it means
' that it is a fixed string.
' ========================================================================================
PRIVATE FUNCTION AfxCWstrArrayAppend (rgwstr() AS CWSTR, BYREF cws AS CWSTR) AS BOOLEAN
DIM upperBound AS LONG = UBOUND(rgwstr)
REDIM PRESERVE rgwstr(LBOUND(rgwstr) TO upperBound + 1) AS CWSTR
IF UBOUND(rgwstr) > upperBound THEN rgwstr(UBOUND(rgwstr)) = cws : RETURN TRUE
RETURN FALSE
END FUNCTION
' ========================================================================================
' ========================================================================================
' Inserts a new CWSTR element before the specified position in a one-dimensional CWSTR array.
' Parameters:
' - rgwstr(): The CWSTR array
' - nPos: The position in the array where the new element will be added.
' This position is relative to the lower bound of the array.
' - cws: The CWSTR to append
' Return value:
' TRUE or FALSE
' Example:
' #INCLUDE ONCE "Afx/CWSTR.inc"
' USING Afx
' REDIM rg(1 TO 10) AS CWSTR
' FOR i AS LONG = 1 TO 10
' rg(i) = "string " & i
' NEXT
' AfxCwstrArrayInsert(rg(), 3, "Inserted element")
' FOR i AS LONG = LBOUND(rg) TO UBOUND(rg)
' print rg(i)
' NEXT
' Note: REDIM PRESERVE cannot be used on fixed-size arrays - i.e. arrays with constant bounds
' made with DIM. If after calling REDIM PRESERVE the upper bound has not changed, it means
' that it is a fixed string.
' ========================================================================================
PRIVATE FUNCTION AfxCWstrArrayInsert (rgwstr() AS CWSTR, BYVAL nPos AS LONG, BYREF cws AS CWSTR) AS BOOLEAN
DIM lowerBound AS LONG = LBOUND(rgwstr)
DIM upperBound AS LONG = UBOUND(rgwstr)
nPos = nPos - 1 + lowerBound
IF nPos < lowerBound OR nPos > upperBound THEN RETURN FALSE
REDIM PRESERVE rgwstr(lowerBound TO upperBound + 1) AS CWSTR
IF UBOUND(rgwstr) = upperBound THEN RETURN FALSE
' // Move all the elements down
FOR i AS LONG = UBOUND(rgwstr) TO nPos + 1 STEP - 1
rgwstr(i) = rgwstr(i - 1)
NEXT
rgwstr(nPos) = cws
RETURN TRUE
END FUNCTION
' ========================================================================================
' ========================================================================================
' Removes the specified element of a one-dimensional CWSTR array.
' Parameters:
' - rgwstr(): The CWSTR array
' - nPos: The position in the array of the element to remove.
' This position is relative to the lower bound of the array.
' - cws: The CWSTR to append
' Return value:
' TRUE or FALSE
' Example:
' #INCLUDE ONCE "Afx/CWSTR.inc"
' USING Afx
' REDIM rg(1 TO 10) AS CWSTR
' FOR i AS LONG = 1 TO 10
' rg(i) = "string " & i
' NEXT
' AfxCwstrArrayRemove(rg(), 3)
' FOR i AS LONG = LBOUND(rg) TO UBOUND(rg)
' print rg(i)
' NEXT
' Note: REDIM PRESERVE cannot be used on fixed-size arrays - i.e. arrays with constant bounds
' made with DIM. If after calling REDIM PRESERVE the upper bound has not changed, it means
' that it is a fixed string.
' ========================================================================================
PRIVATE FUNCTION AfxCWstrArrayRemove (rgwstr() AS CWSTR, BYVAL nPos AS LONG) AS BOOLEAN
DIM lowerBound AS LONG = LBOUND(rgwstr)
DIM upperBound AS LONG = UBOUND(rgwstr)
nPos = nPos - 1 + lowerBound
IF nPos < lowerBound OR nPos > upperBound THEN RETURN FALSE
FOR i AS LONG = nPos TO upperBound - 1
rgwstr(i) = rgwstr(i + 1)
NEXT
REDIM PRESERVE rgwstr(lowerBound TO upperBound - 1) AS CWSTR
IF UBOUND(rgwstr) = upperBound THEN RETURN FALSE
RETURN TRUE
END FUNCTION
' ========================================================================================
' ========================================================================================
' Removes the first element of a one-dimensional CWSTR array.
' ========================================================================================
PRIVATE FUNCTION AfxCWstrArrayRemoveFirst (rgwstr() AS CWSTR) AS BOOLEAN
DIM lowerBound AS LONG = LBOUND(rgwstr)
DIM upperBound AS LONG = UBOUND(rgwstr)
DIM nPos AS LONG = lowerBound
FOR i AS LONG = nPos TO upperBound - 1
rgwstr(i) = rgwstr(i + 1)
NEXT
REDIM PRESERVE rgwstr(lowerBound TO upperBound - 1) AS CWSTR
IF UBOUND(rgwstr) = upperBound THEN RETURN FALSE
RETURN TRUE
END FUNCTION
' ========================================================================================
' ========================================================================================
' Removes the last element of a one-dimensional CWSTR array.
' ========================================================================================
PRIVATE FUNCTION AfxCWstrArrayRemoveLast (rgwstr() AS CWSTR) AS BOOLEAN
DIM lowerBound AS LONG = LBOUND(rgwstr)
DIM upperBound AS LONG = UBOUND(rgwstr)
REDIM PRESERVE rgwstr(lowerBound TO upperBound - 1) AS CWSTR
IF UBOUND(rgwstr) = upperBound THEN RETURN FALSE
RETURN TRUE
END FUNCTION
' ========================================================================================
I wonder if there is a way to detect if an array is fixed other that checking if REDIM PRESERVE has failed.