; Description:      4 C style string compare routines in ASM:
;                     case sensitive full string compare
;                     case sensitive "n" characters compare
;                     case insensitive full string compare
;                     case insensitive "n" characters compare
;
; Type:             System
;
; Last updated:     12th January 2000 - Minor optimisations
;                                     - Added two "n" compare functions
;
; Author:           David McMinn (dave@satanicdreams.com)
;
; In all functions, you pass the address of two strings you want
; to compare. In the two "n" functions, you also pass the number of characters
; from the string you want to compare (although the code will not run past the end
; of a string). The returned value will be:
;
; <0 if s1 < s2
; =0 if s1 = s2
; >0 if s1 > s2
;
; BN: These functions do not handle non-English characters, such as those
; with accents etc


; Case sensitive compare
Function.w ASM_strcmp{*s1.b, *s2.b}
.ASM_strcmp:
        MOVEA.l d0,a0       ; put pointers to strings into addres registers
        MOVEA.l d1,a1

'fetch: MOVE.b  (a1)+,d1    ; get next character from s2 string
        MOVE.b  (a0)+,d0    ; get next character from s1 string

        BEQ     'exit       ; check if letter is null terminator

        CMP.b   d0,d1       ; check if letters are same
        BEQ     'fetch      ; if they are, move onto next kletter

'exit:  MOVEQ.l #0,d2       ; clear d2
        NOT.b   d2          ; put mask of $00FF into d2
        AND.w   d2,d0       ; make sure only bye is in d0
        AND.w   d2,d1       ; make sure only byte is in d1
        SUB.w   d1,d0       ; get return result
        AsmExit
End Function


; Case sensitive compare with length
Function.w ASM_strncmp{*s1.b, *s2.b, n.l}
.ASM_strncmp:
        MOVEA.l d0,a0       ; put pointers to strings into addres registers
        MOVEA.l d1,a1

'fetch: TST.l   d2          ; check to see if n=0
        BEQ     'exit       ; if it is, we exit
        SUBQ.l  #1,d2       ; subtract 1 from n

        MOVE.b  (a1)+,d1    ; get next character from s2 string
        MOVE.b  (a0)+,d0    ; get next character from s1 string

        BEQ     'retchr     ; check if letter is null terminator

        CMP.b   d0,d1       ; check if letters are same
        BEQ     'fetch      ; if they are, move onto next kletter

'retchr:MOVEQ.l #0,d2       ; clear d2
        NOT.b   d2          ; put mask of $00FF into d2
        AND.w   d2,d0       ; make sure only bye is in d0
        AND.w   d2,d1       ; make sure only byte is in d1
        SUB.w   d1,d0       ; get return result
        AsmExit

'exit:  MOVE.l  d2,d0       ; put 0 into d0, as strings are the same
        AsmExit
End Function


; Case insensitive compare
Function.w ASM_strcmpi{*s1.b, *s2.b}
.ASM_strcmpi:
        MOVEA.l d0,a0       ; put pointers to strings in address registers
        MOVEA.l d1,a1

        MOVEQ.l #96,d2      ; one less than the ASCII code of the first lower case character
        MOVEQ.l #123,d3     ; the last ASCII lower case character code
        MOVEQ.l #-33,d4     ; mask for subtracting 32 from the lower case to convert to upper case

'fetch: MOVE.b  (a1)+,d1    ; get next character from s2 string
        MOVE.b  (a0)+,d0    ; get next character from s1 string

        BEQ     'exit       ; check if letter is null terminator

        CMP.b   d2,d0       ; compare character to 96
        BLS     'noup1      ; if lower or same, this is not a lower case char, so branch
        CMP.b   d3,d0       ; compare character to 123
        BCC     'noup1      ; if higher, this is not a lower case char, so branch
        AND.b   d4,d0       ; if it was a lower case character, convert to upper case

'noup1: CMP.b   d2,d1       ; compare character to 96
        BLS     'noup2      ; if lower or same, this is not a lower case char, so branch
        CMP.b   d3,d1       ; compare character to 123
        BHI     'noup2      ; if higher, this is not a lower case char, so branch
        AND.b   d4,d1       ; if it was a lower case character, convert to upper case

'noup2: CMP.b   d0,d1       ; check if letters are same
        BEQ     'fetch      ; if they are, move onto next kletter

'exit:  MOVEQ.l #0,d2       ; clear d2
        NOT.b   d2          ; put mask of $00FF into d2
        AND.w   d2,d0       ; make sure only bye is in d0
        AND.w   d2,d1       ; make sure only byte is in d1
        SUB.w   d1,d0       ; get return result
        AsmExit
End Function


; Case insensitive compare with length
Function.w ASM_strncmpi{*s1.b, *s2.b, n.l}
.ASM_strncmpi:
        MOVEA.l d0,a0       ; put pointers to strings into addres registers
        MOVEA.l d1,a1

        MOVEQ.l #96,d5      ; one less than the ASCII code of the first lower case character
        MOVEQ.l #123,d3     ; the last ASCII lower case character code
        MOVEQ.l #-33,d4     ; mask for subtracting 32 from the lower case to convert to upper case

'fetch: TST.l   d2          ; check to see if n=0
        BEQ     'exit       ; if it is, we exit
        SUBQ.l  #1,d2       ; subtract 1 from n

        MOVE.b  (a1)+,d1    ; get next character from s2 string
        MOVE.b  (a0)+,d0    ; get next character from s1 string

        BEQ     'retchr     ; check if letter is null terminator

        CMP.b   d5,d0       ; compare character to 96
        BLS     'noup1      ; if lower or same, this is not a lower case char, so branch
        CMP.b   d3,d0       ; compare character to 123
        BCC     'noup1      ; if higher, this is not a lower case char, so branch
        AND.b   d4,d0       ; if it was a lower case character, convert to upper case

'noup1: CMP.b   d5,d1       ; compare character to 96
        BLS     'noup2      ; if lower or same, this is not a lower case char, so branch
        CMP.b   d3,d1       ; compare character to 123
        BHI     'noup2      ; if higher, this is not a lower case char, so branch
        AND.b   d4,d1       ; if it was a lower case character, convert to upper case

'noup2: CMP.b   d0,d1       ; check if letters are same
        BEQ     'fetch      ; if they are, move onto next kletter

'retchr:MOVEQ.l #0,d2       ; clear d2
        NOT.b   d2          ; put mask of $00FF into d2
        AND.w   d2,d0       ; make sure only bye is in d0
        AND.w   d2,d1       ; make sure only byte is in d1
        SUB.w   d1,d0       ; get return result
        AsmExit

'exit:  MOVE.l  d2,d0       ; put 0 into d0, as strings are the same
        AsmExit
End Function


; Small demo

a$ = "abcd"
b$ = "aBcd"
c$ = "aBcdE"

NPrint "Comparing with case sensitivity"
result.w = ASM_strcmp{&a$,&b$}
If result<0 Then NPrint "a$ < b$"
If result=0 Then NPrint "a$ = b$"
If result>0 Then NPrint "a$ > b$"

NPrint "Comparing with case insensitivity"
result.w = ASM_strcmpi{&a$,&b$}
If result<0 Then NPrint "a$ < b$"
If result=0 Then NPrint "a$ = b$"
If result>0 Then NPrint "a$ > b$"

NPrint "Comparing 4 characters with case sensitivity"
result.w = ASM_strncmp{&a$,&c$,4}
If result<0 Then NPrint "a$ < c$"
If result=0 Then NPrint "a$ = c$"
If result>0 Then NPrint "a$ > c$"

NPrint "Comparing 4 characters with case insensitivity"
result.w = ASM_strncmpi{&a$,&c$,0}
If result<0 Then NPrint "a$ < c$"
If result=0 Then NPrint "a$ = c$"
If result>0 Then NPrint "a$ > c$"

NPrint "Press mouse button to quit"
ClickMouse
End

