aboutsummaryrefslogtreecommitdiff
path: root/src/streq.s
blob: d063a35fd48bcdb44e1495476e7c961cfdce54dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

 .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.