-
Notifications
You must be signed in to change notification settings - Fork 0
/
UTIL.ASM
executable file
·340 lines (295 loc) · 6.33 KB
/
UTIL.ASM
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
uppercase
bits 16
cpu 8086
; Include support for fortified DOS system calls:
%include "dossyscl.inc"
segment dseg public class=data
ecode_start_str db " (error code ", 0
ecode_end_str db ").", 0Dh, 0Ah, 0
segment cseg public class=code align=16
; Write a zero-terminated string into a file:
;
; Inputs:
;
; BX - File handle.
; DS:DX - Location of the first character of the string.
;
; Outputs:
;
; Carry flag - Set on error conditions, clear on success.
;
; AX - If CF is set: Error code.
; - If CF is not set: Number of bytes written to the file.
;
; All other GPRs are preserved.
;
global write_str_zterm
write_str_zterm:
push cx
push bx
xor cx, cx
mov bx, dx
.count_loop: mov al, [bx]
test al, al
jz .count_done
inc bx
inc cx
jmp .count_loop
.count_done: pop bx
call near dos_syscl_hwrite
pop cx
retn
; Write an error message for a dos system call error code:
;
;
; This routine is meant to provide a convenient way of printing error messages
; upon the failure of DOS system calls, writing both a descriptive message
; (if the error code is known) and the value of the code itself, terminating
; the output with a dot and a CR LF pair.
;
;
; Inputs:
;
; AX - Error code
; BX - File handle
;
;
; Outputs:
;
; Carry flag - Set on error conditions, clear on success.
;
; AX - If CF is set: Error code.
; - If CF is not set: Number of bytes written to the file.
;
; All other GPRs are preserved.
;
;
; NOTE: This routine uses data within this module's and dossyscl.asm's
; data segment (the text of the messages to be printed), and thus it
; must be ensured that the data segment of these two modules gets
; merged (this is the job of the linker) and that the DS register is
; configured to access it prior to calling this routine.
;
global write_dossyscl_error
write_dossyscl_error:
push cx
push dx
xor cx, cx
push ax
call near dos_syscl_strerror
call near write_str_zterm
jc .write_failed_pop
add cx, ax
mov dx, ecode_start_str
call near write_str_zterm
jc .write_failed_pop
add cx, ax
pop ax
call near write_u16
jc .write_failed
add cx, ax
mov dx, ecode_end_str
call near write_str_zterm
jc .write_failed
add cx, ax
mov ax, cx
pop dx
pop cx
clc
retn
.write_failed_pop:
add sp, 2 ; No need for the old AX value, AX now
; holds a new error code.
.write_failed: pop dx
pop cx
stc
retn
; Write an unsigned 16-bit number into a file:
;
; Inputs:
;
; AX - The number to print.
; BX - File handle.
;
; Outputs:
;
; Carry flag - Set on error conditions, clear on success.
;
; AX - If CF is set: Error code.
; - If CF is not set: Number of bytes written to the file.
;
; All other GPRs are preserved.
;
global write_u16
write_u16: push bp
mov bp, sp
; Allocate space on the stack for the number string (6 bytes
; instead of 5, since sp needs to be even).
sub sp, 6 ; [bp-1]..[bp-6]
push cx
push dx
push di
mov cx, 10
mov di, -1
; Generate a decimal form of the number:
.divide_loop: xor dx, dx
div cx
mov [bp+di], dl
add byte [bp+di], '0'
dec di
test ax, ax
jnz .divide_loop
; Prepare the string far pointer:
mov ax, ds
push ax
mov ax, ss
mov ds, ax
inc di
lea dx, [bp+di]
; Prepare the length:
mov cx, di
neg cx
; Perform the syscall:
call near dos_syscl_hwrite
pop dx
mov ds, dx
pop di
pop dx
pop cx
mov sp, bp
pop bp
retn
; Write a signed 16-bit number into a file:
;
; Inputs:
;
; AX - The number to print.
; BX - File handle.
;
; Outputs:
;
; Carry flag - Set on error conditions, clear on success.
;
; AX - If CF is set: Error code.
; - If CF is not set: Number of bytes written to the file.
;
; All other GPRs are preserved.
;
global write_s16
write_s16: push bp
mov bp, sp
; Allocate space on the stack for the number string:
sub sp, 6 ; [bp-1]..[bp-6]
push cx
push dx
push di
push bx
mov cx, 10
mov di, -1
; Check for the sign:
mov bx, ax
and bx, 8000h
jz .divide_loop
neg ax
; Generate a decimal form of the number:
.divide_loop: xor dx, dx
div cx
mov [bp+di], dl
add byte [bp+di], '0'
dec di
test ax, ax
jnz .divide_loop
; Generate a sign if needed:
test bx, bx
jz .no_sign
mov byte [bp+di], '-'
dec di
.no_sign: pop bx
; Prepare the string far pointer:
mov ax, ds
push ax
mov ax, ss
mov ds, ax
inc di
lea dx, [bp+di]
; Prepare the length:
mov cx, di
neg cx
; Perform the syscall:
call near dos_syscl_hwrite
pop dx
mov ds, dx
pop di
pop dx
pop cx
mov sp, bp
pop bp
retn
; Check whether two zero-terminated strings are equal:
;
; Inputs:
;
; ES:BX - Start of the first string.
; DS:DX - Start of the second string.
;
; Outputs:
;
; The carry flag is unset if the two strings are equal, set otherwise.
;
; The values of all GPRs are preserved.
;
global str_identity_check
str_identity_check:
push ax
push bx
push dx
.check_loop: mov al, [es:bx]
xchg bx, dx
mov ah, [bx]
xchg bx, dx
cmp al, ah
jnz .not_equal
test al, al
jz .are_equal
inc bx
inc dx
jmp .check_loop
.not_equal: stc
jmp .epilogue
.are_equal: clc
.epilogue: pop dx
pop bx
pop ax
retn
; Check whether the given character is a space:
;
; A space, in the context of this routine, is one of the following ASCII codes:
; TAB, VT, CR, LF, FF, 20h
;
; Inputs:
;
; AL - The byte to check
;
; Outputs:
;
; The carry flag is set if the given byte is not a space, and unset if it is.
;
; The values of all GPRs are preserved.
;
global char_is_space
char_is_space: cmp al, 09h ; TAB
jz .is_space
cmp al, 0Bh ; VT
jz .is_space
cmp al, 0Dh ; CR
jz .is_space
cmp al, 0Ah ; LF
jz .is_space
cmp al, 0Ch ; FF
jz .is_space
cmp al, 20h ; Literal space character
jz .is_space
.not_space: stc
retn
.is_space: clc
retn