summaryrefslogtreecommitdiff
path: root/string.asm
blob: ea197d2e853280fb6b6e8111b8270db96b4134f3 (plain) (blame)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
%ifndef _STRING_ASM
%define _STRING_ASM

; stack direction
; ---------------
; + = external
; - = local
;
; ^ must be getting old D:
;

; calling conventions
;	push COUNT
;	push SOURCE
;	push DESTINATION
;	call FUNCTION
;	add sp, 6 (^ in the case of three WORDS)
;
; In C, for instance, this translate to:
; FUNCTION (DESTINATION, SOURCE, COUNT);

memset:
	; Set memory with byte value
	push bp			; setup stack frame
	mov bp, sp		; ...
	push si
	push di
	push cx

	mov di, [bp + 4]	; destination address
	mov ax, [bp + 6]	; requested byte value
	mov cx, [bp + 8]	; count

	cld			; will decrement address ES:DI
	rep stosb		; while cx > 0
				; store byte AL in ES:DI

	pop cx
	pop di
	pop si
	mov sp, bp
	pop bp
	ret


memcpy:
	push bp			; setup stack frame
	mov bp, sp		; ...

	mov di, [bp + 4]	; destination buffer
	mov si, [bp + 6]	; source buffer
	mov cx, [bp + 8]	; count of characters to move

	cld
	rep movsb

	mov sp, bp
	pop bp
	ret


strlen:
	; Determine length of null terminated string
	; NOTE: 64k limit imposed
	push bp			; setup stack frame
	mov bp, sp		; ...
	push cx
	push si

	xor cx, cx		; cx is counter
	xor ax, ax		; ax is return value
	mov si, [bp + 2]	; string address
.loop:
	lodsb			; load byte from ES:SI into AL
	cmp al, 0		; zero?
	je .return		; if so, we're done
	inc cx			; if not, keep going
	jc .crash		; if we roll over CX the carry flag will be set (that's bad)

	jmp .loop

.crash:
	stc			; force carry flag on failure

.return:
	clc
	mov ax, cx
	pop si
	pop cx
	mov sp, bp
	pop bp
	ret


strnchr:
	; Find first occurence of character in a string
	push bp			; setup stack frame
	mov bp, sp		; ...
	push cx
	push dx
	push si

	xor ax, ax		; ax is return value
	mov si, [bp + 4]	; string address
	mov dx, [bp + 6]	; needle character
	mov cx, [bp + 8]	; counter
.loop:
	lodsb			; load byte at si
	cmp al, dl		; same as needle?
	je .return		; if true: return

	dec cx			; decrement counter
	jne .loop		; counter zero?

.return:
	mov ax, cx		; return index of character
	pop si
	pop dx
	pop cx
	mov sp, bp
	pop bp
	ret


strncmp:
	; Determine difference between two strings
	push bp			; setup stack frame
	mov bp, sp		; ...
	push bx			; save registers
	push dx
	push si
	push di

	mov di, [bp + 4]	; string2 address
	mov si, [bp + 6]	; string1 address
	mov cx, [bp + 8]	; limit to compare

.loop:
	mov bx, [si]		; string1
	mov dx, [di]		; string2
	inc si			; next address, string1
	inc di			; next address, string2
	dec cx			; decrease byte counter

	cmp bx, dx		; compare bytes
	jne .diff		; Just die if not-equal

	cmp cx, 0		; If equal, check for null termination
	jne .loop

.diff:
	cmp bx, dx
	jg .s1_larger
	jl .s1_smaller
	je .return

.s1_smaller:
	mov ax, -1
	jmp .return

.s1_larger:
	mov ax, cx

.return:
	pop di			; cleanup stack
	pop si
	pop dx
	pop bx
	mov sp, bp
	pop bp
	ret


strtok:
        push bp
        mov bp, sp
        push bx
        push cx
        push dx
        push di
        push si

	xor ax, ax                      ; clear AX for delimter
	xor bx, bx
	xor cx, cx			; initialize string length counter
	xor dx, dx			; initialize record counter
	xor si, si
	xor di, di

	sub sp, 2			; reserve stack variable
	mov word [bp - 2], 0		;	final_pass = [bp - 2]

        mov di, [bp + 4]                ; arg1 - null terminated string
        mov si, [bp + 6]                ; arg2 - address of results array
        mov al, [bp + 8]                ; arg3 - delimiter value
        cld                             ; clear direction flag (0)

        jmp .strtok_scan		; begin scan

        .strtok_record_token:
		inc dx			; increase record count
                mov bx, di		; store address of delimiter
                sub bx, cx		; subtract length from address
					; to get start of string

                mov [si], bx		; store start of word
                mov [si+2], cx		; store length of word

                add si, 4               ; increment array pointer
                xor cx, cx		; reset counter
                cmp word [bp - 2], 0	; is this the final pass?
                jne .strtok_return	; if so, return
					; else, fall through
        .strtok_scan:
		inc cx
                scasb			; scan for delimiter in AL
                je .strtok_record_token	; if ZF=1, store pointer
                cmp byte [di], 0	; if null terminated, exit loop
                jne .strtok_scan	; else continue

                mov word [bp - 2], 1	; indicate final pass in progress
                dec bx			; adjust final address for null termination
                jmp .strtok_record_token ; process final address

.strtok_return:
	mov ax, dx	; return record count
	pop si
	pop di
	pop dx
	pop cx
	pop bx

        mov sp, bp
        pop bp
	ret

%endif	; _STRING_ASM