-
Notifications
You must be signed in to change notification settings - Fork 0
/
lab5.asm
464 lines (369 loc) · 9.55 KB
/
lab5.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
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
.186
.stack 200h
;Lab 5, var 19 (for 7 and 8 - vars 4 and 9)
;Task - take file, delete all words that match provided word.
;Subtasks:
;-Parameters(including path) are passed through command line
;-Don't load entire file into buffer
;-Word can have spaces and tabulation on both ends(cut that off). Max size is 50 symbols
;Notes:
;-Useful interrupts:
; -21h/3Dh - open existing file
; -21h/3Eh - close file
; -21h/3Fh - read bytes from file
; -21h/40h - write bytes to file
; -21h/42h - SEEK
; -To truncate - use write with 0 length
;-Console arguments - through PSP(from 80h to 100h). Maybe need to separate arguments or smth
;-Offsets of buffers(inp;outp): 0731:000A , 0741:000A ; 0752:000E
.data
pspSegm dw ? ;console args are located in this at offset 80h
argsLen db ?
path db db 129 DUP(0) ;path string. Must be ASCIIZ, so fill with zeroes
fileHandle dw ?
searchWordSize db 50 ;length of string
searchWordStr db 51 DUP(0) ;letters
offsetIn dw 2 DUP(0)
;endLength dw 513
bufferInLow db 256 DUP(0)
bufferInHigh db 256 DUP(0)
offsetOut dw 2 DUP(0)
bufferOut db 512 DUP(?)
bufferOutEnd: db 0 ;just a label to detect end of buffer
infoArgsErr db "Invalid arguments!", '$'
infoOpenErr db "Can't open file. Code:", '$'
infoRWErr db "Can't read/write to file. Code:", '$'
.code
;------------------------MACROS------------------------
;Transfer 32-bit file offset between registers and memory.
;Both macros are used with a SEEK interrupt to store the offset
loadOffset MACRO dwVar
mov cx, WORD PTR dwVar[0]
mov dx, WORD PTR dwVar[2]
ENDM
storeOffset MACRO dwVar
mov WORD PTR dwVar[0], dx ;seek returns into different
mov WORD PTR dwVar[2], ax ;pair of registers for some reason
ENDM
;-------------------------CODE-------------------------
start:
push ds
mov bx, @data
mov ds, bx
pop bx
mov es, bx
mov pspSegm, bx
;(check AL for disk letter error?(0FFh if wrong, otherwise 00h))
call readArgs
cmp searchWordSize, 0
jne noErrorArgs
;Couldn't load arguments
lea dx, infoArgsErr
mov ah, 09h
int 21h
jmp main_finish
noErrorArgs:
;Got the arguments. Now open file
mov ah, 3Dh
mov al, 02h ;mode - shared read/write
mov dx, offset path
int 21h
jnc noOpenError
;Couldn't open file
lea dx, infoOpenErr
mov ah, 09h
int 21h
;display error code
mov dl, al
add dl, '0'
mov ah, 2
int 21h
jmp main_finish
noOpenError:
mov fileHandle, ax
;restore segments to usual
mov si, ds
mov es, si
;(test read/write)
;reading one byte
mov bx, fileHandle
mov dx, offset bufferInLow
mov cx, 1
mov ah, 3Fh
int 21h
jc fileIOError
;moving back to pos 0
mov al, 0
xor cx, cx
xor dx, dx
mov ah, 42h
int 21h
;writing the same byte back
mov cx, 1
mov dx, offset bufferInLow
mov ah, 40h
int 21h
jc fileIOError
jmp noFileIOError
fileIOError:
;Coudn't read to file
lea dx, infoRWErr
mov ah, 09h
int 21h
jmp main_finish
noFileIOError:
;Now, start the process
lea si, bufferInLow
lea di, bufferOut
xor cx, cx
;load initial buffer
CALL readHalf
CALL copyToLow
CALL readHalf
CALL checkWord ;words can start right away
mov ch, 0Fh ;CH=0Fh is used as "prev char is space" flag
mainLoop:
cmp [si], 0
je mainLoopEnd ;reached end of file. Leave
;find if need to check for word
cmp [si], '0'
jl startWordCmp
cmp [si], '9'
jle noWordCmp
cmp [si], 'A'
jl startWordCmp
cmp [si], 'Z'
jle noWordCmp
cmp [si], 'a'
jl startWordCmp
cmp [si], 'z'
jle noWordCmp
startWordCmp: ;start of next word, maybe it's the one
mov cl, 0Fh ;CL=0Fh is used as a "beginning of word" flag
noWordCmp: ;regular letter, not a part of word
cmp si, offset bufferInHigh
jle mainLoop_noShift ;don't need to load new data yet
;attach next part of file to array
CALL copyToLow
sub si, 256
CALL readHalf
mainLoop_noShift:
cmp [si], ' ' ;Check if current char is space
jne spaceRem_noSpace
cmp ch, 0Fh ;If multiple spaces in row, skip all except 1st. Means can skip all write-related code
mov ch, 0Fh ;curr char is space. Must set flag
je mainLoop_noFlush
jmp spaceRem_noClear
spaceRem_noSpace:
xor ch, ch ;clear "prev char is space" flag
spaceRem_noClear:
;move symbol into output buffer
mov ah, [si]
mov [di], ah
inc di
cmp di, offset bufferOutEnd
jne mainLoop_noFlush
;output buffer is full. Write it back to file, reset iterator
CALL writeBuf
lea di, bufferOut
mainLoop_noFlush:
inc si
cmp cl, 0Fh ;Check "beginning of word" flag. If true,
jne wordNoCmp ;start compare routine from its first letter
CALL checkWord
wordNoCmp:
mov cl, 02h ;to keep loop going
loop mainLoop
mainLoopEnd:
;Processed all data, but still have some in output buffer. Write it to file
CALL writeBuf
;Truncate file
mov di, offset bufferOut ;put di on beginning of its array
CALL writeBuf ;(writing zero bytes truncates file to current pos)
main_finish:
;Close file
mov bx, fileHandle
mov ah, 3Eh
int 21h
;idk, should be it.
;Return control to system.
mov ah, 4Ch
int 21h
;=====================================FUNCTIONS=====================================
;Reads console arguments - path and word to search.
;On error, searchWordSize = 0
PROC readArgs
pusha
;read length of args
mov di, 80h
mov al, es:[di]
mov argsLen, al
inc di
;search 1st parameter(path)
mov cx, 128 ;max amount of skipped spaces
mov al, ' '
repe scasb ;skip spaces
dec di ;to end up on 1st letter
;actual reading
mov bx, offset path
xor cx, cx ;size unknown, no point in limiting
arg1Loop: ;copy path to variable
mov al, es:[di]
cmp al, ' '
je arg1LoopEnd
cmp al, 009 ;tabulation
je arg1LoopEnd
cmp al, 0Dh ;end of args
je argFail ;don't have 2nd argument - that's an error
mov [bx], al ;store char in path string
inc di
inc bx
loop arg1Loop
arg1LoopEnd:
;Reading arg 2
;Skip initial spaces and tabs
arg2PreLoop:
mov al, es:[di]
inc di
cmp al, ' '
je arg2PreLoop
cmp al, 009 ;tab
je arg2PreLoop
dec di
;Found beginning of arg 2. Read it
xor bx, bx
xor cx, cx
mov cl, searchWordSize ;If cx runs out, word is too large - error
inc cl
arg2Loop:
mov al, es:[di]
inc di
cmp al, ' '
je arg2LoopEnd
cmp al, 009 ;tab
je arg2LoopEnd
cmp al, 0Dh ;end of args
je arg2LoopEnd
arg2LoopWrite:
mov searchWordStr[bx], al
inc bx
loop arg2Loop
arg2LoopEnd:
cmp cx, 0
je argFail
mov searchWordSize, bl
popa
ret
argFail: ;incorrect arguments
mov searchWordSize, 0
popa
ret
ENDP readArgs
;Reads 256 bytes from file into top half of input buffer.
;Includes SEEK. On EOF, string gets capped off by NULL-symbol.
PROC readHalf
pusha
;first, seek pos
mov bx, fileHandle
loadOffset offsetIn
mov al, 0
mov ah, 42h
int 21h
;got pos, now read data
xor dx, dx
lea dx, bufferInHigh
mov cx, 256
mov ah, 3Fh
int 21h
cmp ax, cx
je noEOF
;End of file. Put null-character as last symbol
lea di, bufferInHigh
add di, ax
mov [di], 0
noEOF:
;get and store new file offset
mov al, 1
xor cx, cx
xor dx, dx
mov ah, 42h
int 21h
storeOffset offsetIn ;update offset variable
popa
ret
ENDP readHalf
;Copies bufferInHigh into bufferInLow. That's it!
;(doesn't transfer pointer though, need to do that separately)
PROC copyToLow
pusha
mov si, offset bufferInHigh
mov di, offset bufferInLow
mov cx, 256
rep movsb
popa
ret
ENDP copyToLow
;Writes bytes from bufferOut to DI into file.
PROC writeBuf
pusha
push di
;seek pos
mov bx, fileHandle
loadOffset offsetOut ;(macro)
mov al, 0
mov ah, 42h
int 21h
;write data
mov dx, offset bufferOut
pop cx
sub cx, dx ;length from DI
mov ah, 40h
int 21h
;get and store new file offset
mov al, 1
xor cx, cx
xor dx, dx
mov ah, 42h
int 21h
storeOffset offsetOut ;update offset variable
popa
ret
ENDP writeBuf
;Function to compare word with target word, and skip on match.
;Needs SI to point at first letter of suspect word.
;If word matched and has ' ' right after it, skips it.
PROC checkWord
push cx
push di
push si
mov di, offset searchWordStr
xor cx, cx
mov cl, searchWordSize
repe cmpsb
cmp cx, 0
jne cw_fail
;Check if word ended right after that
cmp [si], '0'
jl cw_match
cmp [si], '9'
jle cw_fail
cmp [si], 'A'
jl cw_match
cmp [si], 'Z'
jle cw_fail
cmp [si], 'a'
jl cw_match
cmp [si], 'z'
jle cw_fail
cw_match:
pop di ;don't restore si, but keep stack intact
pop di
pop cx
ret
cw_fail:
pop si
pop di
pop cx
ret
ENDP checkWord
end start