If you know your way around PowerBASIC you don't need this type of function all that often as the length of a string is stored 4 bytes below its start address but where you do, this is still an excellent very fast function. It comes with a duplicate guard. If you need the length of a basic dynamic string without scanning it, there is an algo below that will do it for you.
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
#IF NOT %DEF(%fn_StrLen)
%fn_StrLen = 1
' --------------------------------------------------------------------------------------------------
FUNCTION StrLen(ByVal item as DWORD) as DWORD
#REGISTER NONE
! mov eax, item ' get pointer to string
! lea edx, [eax+3] ' pointer+3 used in the end
! mov ebx, &H80808080
lbl0:
' --------------------
' manually unroll by 3
' --------------------
! mov edi, [eax] ' read first 4 bytes
! add eax, 4 ' increment pointer
! lea ecx, [edi-&H01010101] ' subtract 1 from each byte
! not edi ' invert all bytes
! and ecx, edi ' and these two
! and ecx, ebx
! jnz nxt
! mov edi, [eax] ' read first 4 bytes
! add eax, 4 ' increment pointer
! lea ecx, [edi-&H01010101] ' subtract 1 from each byte
! not edi ' invert all bytes
! and ecx, edi ' and these two
! and ecx, ebx
! jnz nxt
! mov edi, [eax] ' read first 4 bytes
! add eax, 4 ' increment pointer
! lea ecx, [edi-&H01010101] ' subtract 1 from each byte
! not edi ' invert all bytes
! and ecx, edi ' and these two
! and ecx, ebx
! jnz nxt
' --------------------
! mov edi, [eax] ' read first 4 bytes
! add eax, 4 ' 4 increment DWORD pointer
! lea ecx, [edi-&H01010101] ' subtract 1 from each byte
! not edi ' invert all bytes
! and ecx, edi ' and these two
! and ecx, ebx
! jz lbl0 ' no zero bytes, continue loop
nxt:
! test ecx, &H00008080 ' test first two bytes
! jnz lbl1
! shr ecx, 16 ' not in the first 2 bytes
! add eax, 2
lbl1:
! shl cl, 1 ' use carry flag to avoid branch
! sbb eax, edx ' compute length
! mov FUNCTION, eax
END FUNCTION
' --------------------------------------------------------------------------------------------------
#ENDIF
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Get dynamic string length without scanning it.
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
FUNCTION lnbstr(bstr$) as DWORD
' ----------------------------
' get the stored string length
' ----------------------------
#REGISTER NONE
LOCAL pstr as DWORD
pstr = StrPtr(bstr$) ' get the string address
! mov eax, pstr
! mov eax, [eax-4] ' get the stored buffer length
! mov FUNCTION, eax ' return it in EAX
End FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤