' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
' Build with PBCC 6.0
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
#include "\basic\include\win32api.inc"
' %clockit = 0 ' uncomment to run timing.
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
FUNCTION PBmain as LONG
#REGISTER NONE
LOCAL src as DWORD
LOCAL lcnt as DWORD
LOCAL pMem as DWORD
LOCAL tcnt as DWORD
a$ = _
"Friends, Romans, countrymen, lend me your ears;"+chr$(13,10)+_
"I come to bury Caesar, not to praise him."+chr$(13,10)+_
"The evil that men do lives after them;"+chr$(13,10)+_
"The good is oft interred with their bones;"+chr$(13,10)
#IF %DEF(%clockit)
Open "lt.txt" for Binary as #1 ' VERY BIG file of your choice
Get$ #1, lof(1), a$
Close #1
tcnt = GetTickCount
#ENDIF
src = StrPtr(a$)
PREFIX "! "
push src
call lines_to_array ; call the tokenizer
mov pMem, eax ; returned array pointer address in variable
mov lcnt, ecx ; line count in variable
END PREFIX
#IF %DEF(%clockit)
tcnt = GetTickCount - tcnt
StdOut "Timing = "+format$(tcnt)+" milliseconds"
! jmp bye
#ENDIF
PREFIX "! "
mov esi, pMem ; load pointer array into ESI
mov edi, lcnt ; load the line count into EDI
lbl1:
push DWORD PTR [esi] ; write the line of text to the console
call puts ; make MSVCRT useful
add esi, 4 ; increment to next pointer
sub edi, 1 ; decrement the loop counter
jnz lbl1
END PREFIX
bye:
GlobalFree pMem ' release pointer memory here
waitkey$
End FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
FUNCTION lines_to_array(ByVal src as DWORD) as DWORD
' --------------------------------------------------------------------------
' in place tokenize a text file and return an array of pointers to the start
' of each line which is terminated at the ascii 13 location with an ascii 0
' IN address of source text
' OUT 1. array of pointers address in EAX
' 2. line count in ECX
' address of pointer array must be released in the scope of the caller
' using GlobalFree()
' --------------------------------------------------------------------------
#REGISTER NONE
LOCAL lcnt as DWORD
LOCAL pMem as DWORD
LOCAL alen as DWORD
PREFIX "! "
push src
call get_lcnt ; get the line count
mov lcnt, eax ; store line count in variable
lea eax, [eax*4] ; set pointer array length
mov alen, eax ; store the array size in alen
; --------------------------
; allocate the pointer array
; --------------------------
END PREFIX
pMem = GlobalAlloc(%GMEM_FIXED or %GMEM_ZEROINIT,alen)
PREFIX "! "
mov esi, src ; source address in ESI
mov ebx, pMem ; pointer array address in EBX
mov [ebx], esi ; load array address into 1st member of array
add ebx, 4
sub esi, 1
lbl1:
add esi, 1
movzx eax, BYTE PTR [esi]
test eax, eax ; test for zero
jz lbl2 ; exit loop on zero
cmp eax, 13 ; test for ascii 13
jne lbl1 ; short loop back if not 13
mov BYTE PTR [esi], 0 ; write terminator at ascii 13 location
add esi, 2 ; step over ascii 13 and 10
mov [ebx], esi ; write the next line start to pointer
add ebx, 4 ; increment to next pointer
jmp lbl1 ; long loop after writing pointer
lbl2:
mov ecx, lcnt ; return the line count in ECX
mov eax, pMem ; the array pointer in EAX
mov FUNCTION, eax
END PREFIX
End FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
FASTPROC get_lcnt
PREFIX "! "
; --------------------------------------
; count ascii 13 to determine line count
; --------------------------------------
mov edx, [esp+4] ; the source address
sub edx, 1
xor eax, eax
jmp lbl1
pre:
add eax, 1 ; increment the counter
lbl1:
; -----------
; unroll by 4
; -----------
add edx, 1
movzx ecx, BYTE PTR [edx]
cmp ecx, 13
je pre
test ecx, ecx
jz lbl2
add edx, 1
movzx ecx, BYTE PTR [edx]
cmp ecx, 13
je pre
test ecx, ecx
jz lbl2
add edx, 1
movzx ecx, BYTE PTR [edx]
cmp ecx, 13
je pre
test ecx, ecx
jz lbl2
add edx, 1
movzx ecx, BYTE PTR [edx]
cmp ecx, 13
je pre
test ecx, ecx
jnz lbl1
lbl2:
ret 4
END PREFIX
END FASTPROC
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
DECLARE FUNCTION vcputs CDECL LIB "MSVCRT.DLL" ALIAS "puts" (BYVAL ptxt AS DWORD) AS DWORD
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
SUB puts(BYVAL ptxt AS DWORD)
vcputs ptxt
End SUB
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤