
 .importzp sreg, ptr1, ptr2
 .import popptr1, popax
 .import _msg_text
 .export _streq, _streq_i, _strneq_i, _lcase, _find_nick

 ; extern __fastcall__ char lcase(char c);
 ; extern __fastcall__ char streq(char *s1, char *s2);
 ; extern __fastcall__ char streq_i(char *s1, char *s2);
 ; extern __fastcall__ char strneq_i(char *s1, char *s2, char len);
 ; extern __fastcall__ char find_nick(void);

 ; these are fast and small replacements for standard C library functions.
 ; lcase() is a drop-in replacement for tolower().
 ; streq() is basically strcmp() except it returns true for equality,
 ; false for inequality (so you can't e.g. use it for sorting).
 ; also, it only supports strings up to 256 bytes long.
 ; streq_i() is the case-insensitive verson of streq().
 ; strneq_i() is case-insensitive and stops after 'len' characters.
 ; find_nick() does a case-insensitive search of msg_text for
 ; config.nick. returns 1 if found, 0 if not. NOTE: only searches the
 ; first 256 bytes of msg_text! this is a minor infelicity, but people
 ; rarely type that much text in one message...

 limit = sreg+3 ; number of characters to compare (0 = 256)
 insens = sreg  ; bit 7 set = case insensitive, otherwise not
 temp = sreg+1  ; nothing to see here, move along :)
 temp2 = sreg+2

 NICK = $0480 ; aka config.nick

_lcase:
 cmp #'Z'+1
 bcs lcret
 cmp #'A'
 bcc lcret
 ora #$20
lcret:
 rts

_strneq_i:
 sta limit
 jsr popax
 ldy #$80
 sty insens
 jmp doit

_streq_i:
 ldy #$80
 .byte $2c ; BIT abs, skip next
_streq:
 ldy #0
 sty insens
 ldy #0
 sty limit

doit:
 sta ptr2
 stx ptr2+1
 jsr popptr1 ; returns with Y=0

cmploop:
 lda (ptr2),y
 bit insens
 bpl no_case_1
 jsr _lcase

no_case_1:
 sta temp
 lda (ptr1),y
 tax
 bit insens
 bpl no_case_2
 jsr _lcase

no_case_2:
 sec
 sbc temp
 bne ret0
 txa
 beq ret1

 iny
 cpy limit
 bne cmploop

ret1:
 lda #1
 .byte $2c
ret0:
 lda #0
 tax
 rts

_find_nick:
 lda _msg_text
 sta ptr1
 lda _msg_text+1
 sta ptr1+1
 ldy #0
 ; loop over _msg_text, looking for the first character of NICK,
 ; but convert both to lowercase before comparing.
@l:
 lda (ptr1),y
 beq ret0 ; if we hit the end of _msg_text, we're done, no match.
 jsr _lcase
 sta temp ; temp = lcase(A)
 lda NICK ; compare to lcase(NICK[0])
 jsr _lcase
 cmp temp
 beq @found1 ; found a match for the first char, see if the rest matches.
@next:
 iny
 bne @l
 beq ret0
@found1: ; found a case-insensitive match for the first char of NICL...
 sty temp2 ; save Y so we can pick back up in the @l loop if this isn't a match.
 iny    ; start with _msg_text char after the initial match.
 ldx #1 ; start with 2nd char of NICK
@l2:
 lda (ptr1),y
 jsr _lcase
 sta temp
 lda NICK,x
 beq ret1 ; if we hit the null terminator of NICK, we have a successful match!
 jsr _lcase
 cmp temp
 bne @nope ; no match, get out of @l2
 iny
 inx
 bne @l2 ; matched a char, look at the next
@nope:
 ldy temp2 ; restore Y
 jmp @next ; jump to the bottom of the @l loop.
