10 UNICODE string functions written with no stack frame for PBWIN10/PBCC6

Started by hutch--, May 17, 2011, 01:14:39 AM

Previous topic - Next topic

hutch--

With the new syntax for PB compilers I can write code in MASM and port it directly to PB as long as it is low level mnemonic code with no change apart from things like masm's anonymous labels and hex notation.


' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

' -------------------
' build with PBWIN 10
' -------------------

FUNCTION PBmain as LONG

    LOCAL rval as DWORD
    LOCAL wszStr as WSTRINGZ * 64

    wszStr = "1234567890"
    ! lea eax, wszStr
    ! push eax
    ! call uc_len
    ! mov rval, eax

    msgbox format$(rval)

    wszStr = "1234567890"
    ! push 6
    ! lea eax, wszStr
    ! push eax
    ! call uc_left

    msgbox wszStr

    wszStr = "1234567890"
    ! push 6
    ! lea eax, wszStr
    ! push eax
    ! call uc_right

    msgbox wszStr

    wszStr = "1234567890"
    ! lea eax, wszStr
    ! push eax
    ! call uc_reverse

    msgbox wszStr

    wszStr = " 1234567890"
    ! lea eax, wszStr
    ! push eax
    ! call uc_ltrim

    msgbox wszStr

    wszStr = "1234567890 "
    ! lea eax, wszStr
    ! push eax
    ! call uc_rtrim

    msgbox wszStr

    wszStr = " 1234567890 "
    ! lea eax, wszStr
    ! push eax
    ! call uc_trim

    msgbox wszStr

    LOCAL txt1 as WSTRINGZ * 32
    LOCAL txt2 as WSTRINGZ * 32
    LOCAL txt3 as WSTRINGZ * 32
    LOCAL trv  as DWORD

    txt1 = "text one"
    txt2 = "text two"

    ! lea eax, txt2
    ! push eax
    ! lea eax, txt1
    ! push eax
    ! call uc_cmp
    ! mov trv, eax

    msgbox format$(trv)

    ! lea eax, txt1
    ! push eax
    ! lea eax, txt1
    ! push eax
    ! call uc_cmp
    ! mov trv, eax

    msgbox format$(trv)

    wszStr = "Original String"
    txt1 = " Next String "
    txt2 = " Last String"

    ! lea eax, txt1
    ! push eax
    ! lea eax, wszStr
    ! push eax
    ! call uc_cat

    msgbox wszStr

    ! lea eax, txt2
    ! push eax
    ! lea eax, wszStr
    ! push eax
    ! call uc_cat

    msgbox wszStr

    LOCAL esp_ as DWORD

    wszStr = ""

    txt1 = "Original String"
    txt2 = " Next String"
    txt3 = " Last String"

    ! lea eax, txt3
    ! push eax
    ! lea eax, txt2
    ! push eax
    ! lea eax, txt1
    ! push eax
    ! lea eax, wszStr
    ! push eax
    ! push 3
    ! call uc_multicat
    ! add esp, 20

    msgbox wszStr

End FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FASTPROC uc_len

    PREFIX "! "

    mov eax, [esp+4]            ; load the string address
    sub eax, 2                  ; set up the address for loop entry
  lbl0:
    add eax, 2                  ; increment up to the next WORD sized character
    cmp WORD PTR [eax], 0       ; test if UNICODE character is terminator
    jne lbl0                    ; loop back if not

    sub eax, [esp+4]            ; sub the start address from EAX
    shr eax, 1                  ; half the result for UNICODE length
    ret 4                       ; return while balancing the stack

    END PREFIX

END FASTPROC

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FASTPROC uc_left

    PREFIX "! "

    mov eax, [esp+4]            ; string address
    mov ecx, [esp+8]            ; char count
    sub eax, 2                  ; set up the address for loop entry

  lbl0:
    add eax, 2
    cmp WORD PTR [eax], 0       ; exit if zero is found before required length
    je lblout
    sub ecx, 1
    jns lbl0

    mov WORD PTR [eax], 0       ; else truncate the string

  lblout:
    ret 8

    END PREFIX

END FASTPROC

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FASTPROC uc_right

    PREFIX "! "

    mov eax, [esp+4]            ; load address into EAX
    push eax                    ; push it onto the stack
    call uc_len                 ; get the string length

    cmp eax, [esp+8]            ; compare it against required length
    ja lbl0                     ; if its greater that required, proceed.
    ret 8                       ; else exit with no change

  lbl0:
    sub eax, [esp+8]            ; calculate the OFFSET for the 1st required character
    add eax, eax                ; double it for 2 byte UNICODE character

    mov ecx, [esp+4]            ; load the string address in both source and destination registers
    mov edx, [esp+4]
    add ecx, eax                ; add the 1st character OFFSET to the source register

  lbl1:
    movzx eax, WORD PTR [ecx]   ; load each UNICODE character into EBX
    mov WORD PTR [edx], ax      ; copy it to the destination register
    add ecx, 2                  ; add 2 for next UNICODE character location
    add edx, 2
    test eax, eax               ; test if last written character is zero.
    jnz lbl1                    ; loop back if not

    ret 8                       ; balance the stack and return

    END PREFIX

END FASTPROC

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FASTPROC uc_reverse

    PREFIX "! "

    push ebx
    push esi

    mov eax, [esp+12]           ; load src address into EAX ([esp+4] plus 8 {2 pushes})
    push eax
    call uc_len

    mov esi, eax                ; write char count to ESI
    shr esi, 1                  ; int divide it by 2

    add eax, eax                ; double UNICODE length to get offset of end

    mov ecx, [esp+12]
    mov edx, [esp+12]
    add edx, eax                ; add the OFFSET to get end character
    sub edx, 2

  ; read 1st and last chars then swap them then read
  ; next inner pair until middle of string is reached

  lbl0:
    movzx eax, WORD PTR [ecx]
    movzx ebx, WORD PTR [edx]
    mov [ecx], bx
    mov [edx], ax
    add ecx, 2
    sub edx, 2
    sub esi, 1
    jnz lbl0

    pop esi
    pop ebx

    ret 4                       ; balance the stack and return

    END PREFIX

END FASTPROC

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FASTPROC uc_ltrim

    PREFIX "! "

    mov eax, [esp+4]            ; load the stack variable into EAX
    mov ecx, [esp+4]            ; load the stack variable into ECX
    sub eax, 2

  lbl0:
    add eax, 2
    cmp WORD PTR [eax], 32      ; strip space
    je lbl0
    cmp WORD PTR [eax], 9       ; strip tab
    je lbl0

  ; ------------------------------------------
  ; copy the rest back to string start address
  ; ------------------------------------------
  lbl1:
    movzx edx, WORD PTR [eax]   ; zero extend WORD into EDX
    mov WORD PTR [ecx], dx      ; write it back to same buffer
    add eax, 2
    add ecx, 2
    test edx, edx               ; test for zero after it is written
    jnz lbl1                    ; loop back if not zero

    ret 4                       ; balance the stack and return

    END PREFIX

END FASTPROC

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FASTPROC uc_rtrim

    PREFIX "! "

    mov ecx, [esp+4]            ; load string address in ECX
    xor edx, edx                ; zero EDX
    sub ecx, 2

  lbl0:
    add ecx, 2
    cmp WORD PTR [ecx], 0       ; exit loop on zero
    je lbl2
    cmp WORD PTR [ecx], 32      ; loop back on space
    je lbl0
    cmp WORD PTR [ecx], 9       ; loop back on tab
    je lbl0
  lbl1:
    mov edx, ecx                ; else write last char address to EDX
    jmp lbl0

  lbl2:
    test edx, edx               ; test if EDX has been modified
    jz lbl3
    mov WORD PTR [edx+2], 0     ; if it has, write terminator 1 char after
  lbl3:                         ' last non space/tab char
    ret 4                       ; balance the stack and return

    END PREFIX

END FASTPROC

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FASTPROC uc_trim

    PREFIX "! "

    mov eax, [esp+4]
    push eax
    call uc_ltrim

    mov eax, [esp+4]
    push eax
    call uc_rtrim

    ret 4                       ; balance the stack and return

    END PREFIX

END FASTPROC

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FASTPROC uc_cmp

    PREFIX "! "

    push edi

    mov edx, [esp+8]
    mov edi, [esp+12]
    mov eax, -2
    xor ecx, ecx

  lbl0:
    add eax, 2
    movzx ecx, WORD PTR [edx+eax]   ; load each char
    cmp cx, [edi+eax]               ; compare it to char in other string
    jne mismatch
    test ecx, ecx
    jnz lbl0

    shr eax, 1                  ; half for character count on match
    jmp match

  mismatch:
    xor eax, eax                ; zero for mismatch

  match:
    pop edi

    ret 8                       ; balance the stack and return

    END PREFIX

END FASTPROC

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FASTPROC uc_cat

    PREFIX "! "

    mov edx, [esp+4]
    sub edx, 2
    mov ecx, [esp+8]
    xor eax, eax

  lbl0:
    add edx, 2
    cmp WORD PTR [edx], 0       ; find the end
    jne lbl0

  lbl1:
    mov ax, [ecx]               ; append 2nd string
    mov [edx], ax
    add ecx, 2
    add edx, 2
    test ax, ax
    jnz lbl1

    ret 8

    END PREFIX

END FASTPROC

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

' ucMultiCat proc C pcount:DWORD,lpBuffer:DWORD,args:VARARG

FASTPROC uc_multicat

    PREFIX "! "

    push esi
    push edi

    xor eax, eax                ; clear EAX for following partial reads and writes
    mov edi, [esp+8][8]         ; lpBuffer
    xor ecx, ecx                ; clear arg counter
    lea edx, [esp+12][8]        ; args
    sub edi, 2
  lbl0:
    add edi, 2
    mov ax, [edi]
    test ax, ax
    jne lbl0
  newstr:
    sub edi, 2
    mov esi, [edx+ecx*4]
  lbl1:
    add edi, 2
    mov ax, [esi]
    mov [edi], ax
    add esi, 2
    test ax, ax
    jne lbl1
    add ecx, 1
    cmp ecx, [esp+4][8]         ; pcount
    jne newstr

    mov eax, [esp+8][8]         ; lpBuffer

    pop edi
    pop esi

    ret                         ; stack must be corrected by caller

    END PREFIX

END FASTPROC

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php