''
'' FF_USING
'' Format one or more string or numeric expressions, based upon the contents
'' of the format mask string.
''
'' This function can format both numeric and string expressions, and can take
'' multiple arguments. Be careful to ensure that your number of expressions
'' match the number of format codes in the formatting mask.
''
'' Character
'' When the expression is a string, the following format codes apply within sMask:
''
'' ! The first character of the string is returned.
''
'' & The entire string is returned.
''
'' \\ The first two characters are returned.
''
'' \ \ If backslashes enclose n spaces, n + 2 characters of the string expression are returned.
''
'' _ Escape (underscore) character. The following character is interpreted as a literal
'' character instead of a mask format character.
''
'' Numeric
'' When expression is numeric, this function uses the same formatting codes as found in
'' FreeBASIC's Format function. Be aware of this because those codes differ somewhat from the
'' numeric formatting codes used in PowerBASIC's Using function.
''
'' IMPORTANT - When passing numeric values to this function you must always convert them
'' to Double format first, otherwise this function will not recognize it.
'' eg. st = FF_Using("This is \ \ my ##### mask", "Paul", CDbl(12345))
''
#Include Once "string.bi"
Function FF_Using CDECL ( ByRef sMask As String, ...) As String
Dim sBuffer As String = String(1024, 0) ' 1K buffer. This is what PowerBASIC uses.
Dim arg As Any Ptr = Va_first()
Dim pMask As UByte Ptr = Strptr(sMask)
Dim pBuffer As UByte Ptr = Strptr(sBuffer)
Dim nRemaining As Integer = Len(sMask)
Dim nPosBuf As Integer = 0 ' offset to write into sBuffer
Dim nPosMask As Integer = 0 ' offset to read from the mask
While (nRemaining > 0)
Dim char As Integer = pMask[nPosMask]
Dim sString As String = ""
Dim nFloat As Double = 0
Dim i As Integer = 0
nPosMask += 1
nRemaining -= 1
' Determine if this is possibly a format character
Select Case char
Case 95 ' Asc("_")
' Treat next character as a literal and put it in buffer
If (nRemaining <> 0) Then
pBuffer[nPosBuf] = pMask[nPosMask]
nPosBuf += 1
nRemaining -= 1
nPosMask += 1
End If
Case 33 ' Asc("!")
' First character of the expression is put in buffer
sString = *Va_arg(arg, ZString Ptr)
pBuffer[nPosBuf] = sString[0]
nPosBuf += 1
arg = Va_next(arg, ZString Ptr)
Case 92 ' Asc("\")
' This could be the start of a string literal sequence. Need
' to scan to find the ending back slash. If there is no ending
' backslash then we simply skip this expression.
Dim nNumChars As Integer = 1
' The characters can only be either a space or a backslash. Anything
' else is invalid and will cause us to bypass this expression.
For i = 1 To nRemaining
If pMask[nPosMask] = 32 Then ' space
nNumChars += 1
nRemaining -= 1
nPosMask += 1
ElseIf pMask[nPosMask] = 92 Then ' backslash
nNumChars += 1
nRemaining -= 1
nPosMask += 1
sString = Space(nNumChars)
Lset sString = *Va_arg(arg, ZString Ptr)
MemMove( @pBuffer[nPosBuf], Strptr(sString), Len(sString) )
nPosBuf += Len(sString)
arg = Va_next(arg, ZString Ptr)
Exit For
Else
' Error in the formatting of this mask expression so we must
' now abort processing the Mask and return buffer to caller.
Return Left(sBuffer, nPosBuf+1)
Exit For
End If
Next
Case 38 ' Asc("&")
' Whole string of the expression is put in buffer
sString = *Va_arg(arg, ZString Ptr)
MemMove( @pBuffer[nPosBuf], Strptr(sString), Len(sString) )
nPosBuf += Len(sString)
arg = Va_next(arg, ZString Ptr)
' Numeric formats
Case 35, 36, 43, 44, 45, 46, 48 ' Asc("#$+,-.0")
' Build the formatting mask
Dim sNumMask As String = Chr(char)
nFloat = Va_arg(arg, Double)
For i = 1 To nRemaining
char = pMask[nPosMask]
If (char=35) Or (char=36) Or (char=43) Or (char=44) Or _
(char=45) Or (char=46) Or (char=48) Then ' #$+,-.0
sNumMask += Chr(char)
nRemaining -= 1
nPosMask += 1
Else
' Process the number formatting and then iterate
' to process the waiting character.
sString = Format( nFloat, sNumMask )
MemMove( @pBuffer[nPosBuf], Strptr(sString), Len(sString) )
nPosBuf += Len(sString)
arg = Va_next(arg, Double)
Continue While
End If
Next
' If we get to here then we hit the end of the mask buffer but
' still need to process the formatting mask for the numeric expression.
sString = Format( nFloat, sNumMask )
MemMove( @pBuffer[nPosBuf], Strptr(sString), Len(sString) )
nPosBuf += Len(sString)
Case Else
' Ordinary character
pBuffer[nPosBuf] = char
nPosBuf += 1
End Select
Wend
Function = Left(sBuffer, nPosBuf+1)
End Function
I wrote this code tonight to help emulate PB's USING$ function. It is somewhat complicated but it does do a fair amount of what PB's USING function does.
Note: This function will not work on 64-bit Windows because of the way that FB handles variable number unspecified parameters. Use it on 32-bit only.