summaryrefslogtreecommitdiff
path: root/string.asm
blob: bf8f958f753b23690f0d2024a0dc640e65daeda5 (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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
%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
	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 + 4]        ; 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
	jmp .loop

.return:
	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:
	%define .token_count [bp - 2]
	push bp
	mov bp, sp

	sub sp, 2			; use: .token_count

	push bx				; save GPRs
	push dx
	push di
	push si

	xor ax, ax			; use: hold delimiter (LSB of AX)
	xor bx, bx			; use: effective address calculations
	xor cx, cx			; use: input string length counter
	xor dx, dx			; use: temp for string comparison
	xor si, si			; use: token array address
	xor di, di			; use: input string address

	mov di, [bp + 4]		; arg1 - input string (null terminated)
	mov si, [bp + 6]		; arg2 - address of token array
	mov al, [bp + 8]		; arg3 - delimter value

	cld				; clear direction flag

	.find_first:
		mov dl, byte [di]	; Load byte from input string
		cmp dl, al		; is it the delimiter?
		jne .calculate_length	; if not, calculate length of string at this address
		inc di			; else, scan next byte
		jmp .find_first

	.calculate_length:
		push ax			; save delimiter
		push di			; get length of null terminated string
		call strlen
		add sp, 2
		mov cx, ax		; count is return value
		pop ax			; restore delimiter

		lea bx, [di]		; load initial address for _no_adjust
		jmp .strtok_record_no_adjust


	.strtok_record_eos:
		mov byte [di], 0	; Null terminate token

	.strtok_record:
		lea bx, [di + 1]	; The address following the null terminated token
					; points to our new token address

	.strtok_record_no_adjust:
		inc word .token_count
		mov [si], bx		; store address in results array
		add si, 2		; increment results array by one WORD
		inc di			; increment input string
		dec cx			; decrement input string length counter

	.strtok_scan:
		mov dl, byte [di]	; load byte from input string
		cmp dl, 0		; is it the end of the string?
		je .strtok_return

		cmp dl, al		; is this the delimiter?
		je .strtok_record_eos	; if yes, record the address

		dec cx			; decrement input string length counter
		inc di			; increment input string
		jmp .strtok_scan	; loop until scanning is done

	cmp cx, 0			; if the counter is not zero there's more to parse
	jne .strtok_record		; loop until token parsing is done


.strtok_return:
	mov ax, [bp + 6]		; return token array
	mov cx, .token_count		; return token count

	pop si				; restore GPRs
	pop di
	pop dx
	pop bx

	add sp, 2
	mov sp, bp
	pop bp
	ret

%endif	; _STRING_ASM