Subversion Repositories SvarDOS

Rev

Rev 1867 | Rev 1869 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
349 mateuszvis 1
;
537 mateuszvis 2
; rmod - resident module of the SvarCOM command interpreter (NASM code)
349 mateuszvis 3
;
1730 mateusz.vi 4
; Copyright (C) 2021-2024 Mateusz Viste
349 mateuszvis 5
; MIT license
6
;
7
; this is installed in memory by the transient part of SvarCOM. it has only
8
; two jobs: providing a resident buffer for command history, environment, etc
9
; and respawning COMMAND.COM whenever necessary.
10
 
11
CPU 8086
459 mateuszvis 12
org 0x100
349 mateuszvis 13
 
459 mateuszvis 14
PSP_ENVSEG equ 0x2C
15
 
349 mateuszvis 16
section .text    ; all goes into code segment
17
 
350 mateuszvis 18
                 ; offset
19
SIG1 dw 0x1983   ;  +0
20
SIG2 dw 0x1985   ;  +2
21
SIG3 dw 0x2017   ;  +4
983 mateusz.vi 22
SIG4 dw 0x2019   ;  +6  acts also as a guardval to detect severe stack overflows
349 mateuszvis 23
 
983 mateusz.vi 24
; Buffer used to remember previous command, when SvarCOM calls the buffered
25
; input service at INT 21h,AH=0x0A.
26
; This buffer is right before the stack, so in case of a stack overflow event
27
; (for example because of a "too ambitious" TSR) only this buffer is damaged,
987 mateusz.vi 28
; and can be invalidated without much harm. To detect such damage, SvarCOM's
29
; transient part is appending a signature at the end of the buffer.
30
INPUTBUF: times 132 db 0 ; 130 bytes for the input buffer + 2 for signature
983 mateusz.vi 31
 
490 mateuszvis 32
; DOS int 21h functions that I use require at least 40 bytes of stack under
33
; DOS-C (FreeDOS) kernel, so here I reserve 64 bytes juste to be sure
34
STACKBUF db "XXX  SVARCOM RMOD BY MATEUSZ VISTE  XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
35
STACKPTR dw 0
349 mateuszvis 36
 
366 mateuszvis 37
; offset of the COMSPEC variable in the environment block, 0 means "use
38
; boot drive". this value is patched by the transient part of COMMAND.COM
1178 mateusz.vi 39
COMSPECPTR dw 0  ; +CEh
349 mateuszvis 40
 
1849 mateusz.vi 41
; fallback COMSPEC string used if no COMSPEC is present in the environment.
42
; drive is patched by the transient part of COMMAND.COM
1178 mateusz.vi 43
COMSPECBOOT db "@:\COMMAND.COM", 0 ; +D0h
350 mateuszvis 44
 
529 mateuszvis 45
; exit code of last application
1178 mateusz.vi 46
LEXCODE  db 0    ; +DFh
529 mateuszvis 47
 
460 mateuszvis 48
; ExecParamRec used by INT 21h, AX=4b00 (load and execute program), 14 bytes:
49
;  offset  size  content
50
;     +0     2   segment of environment for child (0 = current)
51
;     +2     4   address of command line to place at PSP:0080
52
;     +6     4   address of an FCB to be placed at PSP:005c
53
;    +0Ah    4   address of an FCB to be placed at PSP:006c
1178 mateusz.vi 54
EXEC_PARAM_REC db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   ; +E0h
366 mateuszvis 55
 
548 mateuszvis 56
; Program to execute, preset by SvarCOM (128 bytes, ASCIIZ)
1178 mateusz.vi 57
EXECPROG: times 128 db 0                                     ; +EEh
460 mateuszvis 58
 
548 mateuszvis 59
; File where stdin and stdout should be redirected (0 = no redirection)
1178 mateusz.vi 60
REDIR_INFIL:     times 128 db 0     ; +16Eh
61
REDIR_OUTFIL:    times 128 db 0     ; +1EEh
62
REDIR_OUTAPPEND: dw 0               ; +26Eh
63
REDIR_DEL_STDIN: db 0               ; +270h  indicates that the stdin file
576 mateuszvis 64
                                    ;        should be deleted (pipes). This
65
                                    ;        MUST contain the 1st char of
66
                                    ;        REDIR_INFIL!
461 mateuszvis 67
 
1730 mateusz.vi 68
EXEC_LH: db 0                       ; +271h  EXECPROG to be loaded high?
69
ORIG_UMBLINKSTATE: db 0             ; +272h
70
ORIG_ALLOCSTRAT: db 0               ; +273h
1846 mateusz.vi 71
CTRLC_FLAG: db 0                    ; +274h  flag that says "aborted by CTRL+C"
1730 mateusz.vi 72
 
537 mateuszvis 73
; CTRL+BREAK (int 23h) handler
74
; According to the TechHelp! Manual: "If you want to abort (exit to the parent
75
; process), then set the carry flag and return via a FAR RET. This causes DOS
76
; to perform normal cleanup and exit to the parent." (otherwise use iret)
1846 mateusz.vi 77
BREAK_HANDLER:            ; +275h
78
mov [CTRLC_FLAG], byte 1  ; checked by SvarCOM to abort BAT files
537 mateuszvis 79
stc
80
retf
517 mateuszvis 81
 
1178 mateusz.vi 82
; INT 0x2E handler
83
INT2E:
84
xor ax, ax
85
iret
537 mateuszvis 86
 
1846 mateusz.vi 87
skipsig:                  ; +27Fh
537 mateuszvis 88
 
349 mateuszvis 89
; set up CS=DS=SS and point SP to my private stack buffer
90
mov ax, cs
91
mov ds, ax
92
mov es, ax
93
mov ss, ax
94
mov sp, STACKPTR
95
 
1178 mateusz.vi 96
; set up myself as break handler (int 0x23)
537 mateuszvis 97
mov ax, 0x2523  ; set int vector 23h
98
mov dx, BREAK_HANDLER
99
int 0x21
100
 
1863 mateusz.vi 101
; set up myself as criterr handler (int 0x24)
102
mov ax, 0x2524
103
mov dx, HANDLER_24H
104
int 0x21
105
 
1178 mateusz.vi 106
; set up myself as int 0x2E handler ("pass command to shell")
107
mov ax, 0x252E
108
mov dx, INT2E ; TODO do something meaningful instead of a no-op
109
int 0x21
110
 
517 mateuszvis 111
; revert stdin/stdout redirections (if any) to their initial state
112
call REVERT_REDIR_IF_ANY
113
 
576 mateuszvis 114
; redirect stdin and/or stdout if required
543 mateuszvis 115
call REDIR_INOUTFILE_IF_REQUIRED
517 mateuszvis 116
 
1593 mateusz.vi 117
; should I execute command.com or a pre-set application?
118
cmp [EXECPROG], byte 0
460 mateuszvis 119
jz EXEC_COMMAND_COM
120
 
461 mateuszvis 121
; TODO: perhaps I should call the DOS SetPSP function here? But if I do, the
122
;       int 21h, ah=50h call freezes...
123
;mov ah, 0x50           ; DOS 2+ -- Set PSP
124
;mov bx, cs
125
;int 0x21
460 mateuszvis 126
 
1730 mateusz.vi 127
 
128
; LOADHIGH?
129
cmp [EXEC_LH], byte 0
130
je NO_LOADHIGH
131
; SAVE CURRENT UMB LINK STATE
132
mov ax, 0x5802  ; GET UMB LINK STATE
133
int 0x21
134
mov [ORIG_UMBLINKSTATE], al
135
; SAVE CURRENT ALLOCATION STRATEGY
136
mov ax, 0x5800
137
int 0x21
138
mov [ORIG_ALLOCSTRAT], al
139
 
140
; LOADHIGH: link in the UMB memory chain for enabling high-memory allocation
141
;           (and save initial status on stack)
142
mov ax, 0x5803  ; SET UMB LINK STATE */
143
mov bx, 1
144
int 0x21
145
; set strategy to 'last fit, try high then low memory'
146
mov ax, 0x5801
147
mov bx, 0x0082
148
int 0x21
149
NO_LOADHIGH:
150
 
460 mateuszvis 151
; exec an application preset (by SvarCOM) in the ExecParamRec
152
mov ax, 0x4B00         ; DOS 2+ - load & execute program
461 mateuszvis 153
mov dx, EXECPROG       ; DS:DX  - ASCIZ program name (preset at PSP[already)
460 mateuszvis 154
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
155
int 0x21
465 mateuszvis 156
mov [cs:EXECPROG], byte 0 ; do not run app again (+DS might have been changed)
460 mateuszvis 157
 
1730 mateusz.vi 158
; go to start if nothing else to do (this will enforce valid ds/ss/etc)
159
cmp [cs:EXEC_LH], byte 0
160
je skipsig
463 mateuszvis 161
 
1730 mateusz.vi 162
; restore UMB link state and alloc strategy to original values (but make sure
163
; to base it on CS since DS might have been trashed by the program)
164
mov ax, 0x5803
165
xor bx, bx
166
mov bl, [cs:ORIG_UMBLINKSTATE]
167
int 0x21
168
; restore original memory allocation strategy
169
mov ax, 0x5801
170
mov bl, [cs:ORIG_ALLOCSTRAT]
171
int 0x21
172
; turn off the LH flag
173
mov [cs:EXEC_LH], byte 0
174
 
175
 
176
jmp skipsig      ; enforce valid ds/ss/etc (can be lost after int 21,4b)
177
 
460 mateuszvis 178
EXEC_COMMAND_COM:
179
 
353 mateuszvis 180
; collect the exit code of previous application
181
mov ah, 0x4D
182
int 0x21
529 mateuszvis 183
mov [LEXCODE], al
353 mateuszvis 184
 
460 mateuszvis 185
; zero out the exec param block (14 bytes)
186
mov al, 0              ; byte to write
187
mov cx, 14             ; how many times
188
mov di, EXEC_PARAM_REC ; ES:DI = destination
189
cld                    ; stosb must move forward
190
rep stosb              ; repeat cx times
191
 
1730 mateusz.vi 192
; zero out the LH flag
193
mov [EXEC_LH], byte 0
194
 
366 mateuszvis 195
; preset the default COMSPEC pointer to ES:DX (ES is already set to DS)
196
mov dx, COMSPECBOOT
197
 
198
; do I have a valid COMSPEC?
199
or [COMSPECPTR], word 0
200
jz USEDEFAULTCOMSPEC
459 mateuszvis 201
; set ES:DX to actual COMSPEC (in env segment)
202
mov es, [PSP_ENVSEG]
366 mateuszvis 203
mov dx, [COMSPECPTR]
204
USEDEFAULTCOMSPEC:
205
 
349 mateuszvis 206
; prepare the exec param block
459 mateuszvis 207
mov ax, [PSP_ENVSEG]
350 mateuszvis 208
mov [EXEC_PARAM_REC], ax
465 mateuszvis 209
mov [EXEC_PARAM_REC+2], word CMDTAIL
442 mateuszvis 210
mov [EXEC_PARAM_REC+4], cs
349 mateuszvis 211
 
212
; execute command.com
213
mov ax, 0x4B00         ; DOS 2+ - load & execute program
366 mateuszvis 214
push es                ;
215
pop ds                 ;
216
;mov dx, COMSPEC       ; DS:DX  - ASCIZ program name (preset already)
217
push cs
218
pop es
349 mateuszvis 219
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
220
int 0x21
221
 
222
; if all went well, jump back to start
223
jnc skipsig
224
 
1851 mateusz.vi 225
; save error code into cl
226
mov cl, al
227
 
228
; display program name (in DS:DX), but first replace its nul terminator by a $
229
mov si, dx
230
PARSENEXTBYTE:
231
lodsb ; load byte at DS:SI into AL and inc SI (direction flag is clear already)
232
test al, al  ; is zero yet?
233
jnz PARSENEXTBYTE
234
mov [si], byte '$'   ; replace the nul terminator by a $ and display it
235
mov ah, 0x09
236
int 0x21
237
mov [si], byte 0     ; revert the nul terminator back to its place
238
 
366 mateuszvis 239
; restore DS=CS
240
mov bx, cs
241
mov ds, bx
242
 
349 mateuszvis 243
; update error string so it contains the error number
1851 mateusz.vi 244
mov al, '0'
245
add al, cl    ; the exec error code
246
mov [ERRLOAD + 6], al
349 mateuszvis 247
 
366 mateuszvis 248
; display error message
349 mateuszvis 249
mov ah, 0x09
250
mov dx, ERRLOAD
251
int 0x21
252
 
253
; wait for keypress
1853 mateusz.vi 254
mov ah, 0x07    ; use INT 21h,AH=7 instead of AH=8 for CTRL+C immunity
349 mateuszvis 255
int 0x21
256
 
257
; back to program start
258
jmp skipsig
259
 
460 mateuszvis 260
; command.com tail arguments, in PSP format: length byte followed by args and
465 mateuszvis 261
; terminated with \r) - a single 0x0A byte is passed so SvarCOM knows it is
262
; called as respawn (as opposed to being invoked as a normal application)
263
; this allows multiple copies of SvarCOM to stack upon each other.
264
CMDTAIL db 0x01, 0x0A, 0x0D
442 mateuszvis 265
 
1851 mateusz.vi 266
ERRLOAD db ": ERR x, LOAD FAILED", 0x0A, 0x0D, '$'
517 mateuszvis 267
 
268
; variables used to revert stdin/stdout to their initial state
269
OLD_STDOUT dw 0xffff
270
OLD_STDIN  dw 0xffff
271
 
272
 
520 mateuszvis 273
; ****************************************************************************
517 mateuszvis 274
; *** ROUTINES ***************************************************************
520 mateuszvis 275
; ****************************************************************************
517 mateuszvis 276
 
520 mateuszvis 277
; ----------------------------------------------------------------------------
517 mateuszvis 278
; revert stdin/stdout redirections (if any) to their initial state
279
REVERT_REDIR_IF_ANY:
280
; is stdout redirected?
281
mov bx, [OLD_STDOUT]
282
cmp bx, 0xffff
283
je STDOUT_DONE
519 mateuszvis 284
; revert the stdout handle (dst in BX already)
517 mateuszvis 285
mov cx, 1        ; src handle (1=stdout)
286
mov ah, 0x46     ; redirect a handle
287
int 0x21
519 mateuszvis 288
; close the old handle (still in bx)
289
mov ah, 0x3e
290
int 0x21
517 mateuszvis 291
mov [OLD_STDOUT], word 0xffff ; mark stdout as "not redirected"
292
STDOUT_DONE:
543 mateuszvis 293
 
294
; is stdin redirected?
295
mov bx, [OLD_STDIN]
296
cmp bx, 0xffff
297
je STDIN_DONE
547 mateuszvis 298
; revert the stdin handle (dst in BX already)
543 mateuszvis 299
xor cx, cx       ; src handle (0=stdin)
300
mov ah, 0x46     ; redirect a handle
301
int 0x21
302
; close the old handle (still in bx)
303
mov ah, 0x3e
304
int 0x21
305
mov [OLD_STDIN], word 0xffff ; mark stdin as "not redirected"
576 mateuszvis 306
 
307
; delete stdin file if required
308
cmp [REDIR_DEL_STDIN], byte 0
309
je STDIN_DONE
310
; revert the original file and delete it
311
mov ah, [REDIR_DEL_STDIN]
312
mov [REDIR_INFIL], ah
313
mov ah, 0x41     ; DOS 2+ - delete file pointed at by DS:DX
314
mov dx, REDIR_INFIL
315
int 0x21
316
mov [REDIR_INFIL], byte 0
317
mov [REDIR_DEL_STDIN], byte 0
318
 
543 mateuszvis 319
STDIN_DONE:
320
 
517 mateuszvis 321
ret
520 mateuszvis 322
; ----------------------------------------------------------------------------
517 mateuszvis 323
 
324
 
520 mateuszvis 325
; ----------------------------------------------------------------------------
517 mateuszvis 326
; redirect stdout if REDIR_OUTFIL points to something
543 mateuszvis 327
REDIR_INOUTFILE_IF_REQUIRED:
548 mateuszvis 328
cmp [REDIR_OUTFIL], byte 0
517 mateuszvis 329
je NO_STDOUT_REDIR
548 mateuszvis 330
mov si, REDIR_OUTFIL   ; si = output file
517 mateuszvis 331
mov ax, 0x6c00         ; Extended Open/Create
332
mov bx, 1              ; access mode (0=read, 1=write, 2=r+w)
333
xor cx, cx             ; file attribs when(if) file is created (0=normal)
334
mov dx, [REDIR_OUTAPPEND] ; action if file exist (0x11=open, 0x12=truncate)
335
int 0x21               ; ax=handle on success (CF clear)
548 mateuszvis 336
mov [REDIR_OUTFIL], byte 0
517 mateuszvis 337
jc NO_STDOUT_REDIR     ; TODO: abort with an error message instead
520 mateuszvis 338
 
339
; jump to end of file if flag was 0x11 (required for >> redirections)
340
cmp [REDIR_OUTAPPEND], word 0x11
341
jne SKIP_JMPEOF
342
mov bx, ax
343
mov ax, 0x4202         ; jump to position EOF - CX:DX in handle BX
344
xor cx, cx
345
xor dx, dx
346
int 0x21
347
mov ax, bx             ; put my handle back in ax, as expected by later code
348
SKIP_JMPEOF:
349
 
517 mateuszvis 350
; duplicate current stdout so I can revert it later
351
push ax                ; save my file handle in stack
352
mov ah, 0x45           ; duplicate file handle BX
548 mateuszvis 353
mov bx, 1              ; 1 = stdout
517 mateuszvis 354
int 0x21               ; ax=new (duplicated) file handle
355
mov [OLD_STDOUT], ax   ; save the old handle in memory
520 mateuszvis 356
 
517 mateuszvis 357
; redirect stdout to my file
358
pop bx                 ; dst handle
359
mov cx, 1              ; src handle (1=stdout)
360
mov ah, 0x46           ; "redirect a handle"
361
int 0x21
520 mateuszvis 362
 
517 mateuszvis 363
; close the original file handle, I no longer need it
364
mov ah, 0x3e           ; close a file handle (handle in BX)
519 mateuszvis 365
int 0x21
517 mateuszvis 366
NO_STDOUT_REDIR:
543 mateuszvis 367
 
368
; *** redirect stdin if REDIR_INFIL points to something ***
548 mateuszvis 369
cmp [REDIR_INFIL], byte 0
543 mateuszvis 370
je NO_STDIN_REDIR
548 mateuszvis 371
mov dx, REDIR_INFIL    ; dx:dx = file
543 mateuszvis 372
mov ax, 0x3d00         ; open file for read
373
int 0x21               ; ax=handle on success (CF clear)
548 mateuszvis 374
mov [REDIR_INFIL], byte 0
543 mateuszvis 375
jc NO_STDIN_REDIR      ; TODO: abort with an error message instead
376
 
377
; duplicate current stdin so I can revert it later
378
push ax                ; save my file handle in stack
379
mov ah, 0x45           ; duplicate file handle BX
380
xor bx, bx             ; 0=stdin
381
int 0x21               ; ax=new (duplicated) file handle
382
mov [OLD_STDIN], ax    ; save the old handle in memory
383
 
384
; redirect stdout to my file
385
pop bx                 ; dst handle
386
xor cx, cx             ; src handle (0=stdin)
387
mov ah, 0x46           ; "redirect a handle"
388
int 0x21
389
 
390
; close the original file handle, I no longer need it
391
mov ah, 0x3e           ; close a file handle (handle in BX)
392
int 0x21
393
NO_STDIN_REDIR:
517 mateuszvis 394
ret
1863 mateusz.vi 395
 
396
 
397
; ****************************************************************************
398
; *                                                                          *
399
; * INT 24H HANDLER                                                          *
400
; *                                                                          *
401
; ****************************************************************************
402
;
403
; this is an executable image that can be set up as the critical error handler
1867 mateusz.vi 404
; interrupt (int 24h). It displays the usual "Abort, Retry, Fail..." prompt.
1863 mateusz.vi 405
;
406
; documentation:
407
; http://www.techhelpmanual.com/564-int_24h__critical_error_handler.html
408
;
409
; === CRIT HANDLER DETAILS ====================================================
410
;
411
; *** ON ENTRY ***
412
;
413
; upon entry to the INT 24h handler, the registers are as follows:
414
;  BP:SI = addr of a "device header" that identifies the failing device
415
;     DI = error code in lower 8 bits (only for non-disk errors)
416
;     AL = drive number, but only if AH bit 7 is reset
417
;     AH = error flags
418
;        0x80 = reset if device is a disk, set otherwise
419
;           all the following are valid ONLY for disks (0x80 reset):
420
;        0x20 = set if "ignore" action allowed
421
;        0x10 = set if "retry" action allowed
422
;        0x08 = set if "fail" action allowed
423
;        0x06 = disk area, 0=sys files, 1=fat, 10=directory, 11=data
424
;        0x01 = set if failure is a write, reset if read
425
;
426
; within the int 24h handler, only these DOS functions are allowed:
427
;   01H-0CH (DOS character I/O)
428
;   33H (all subfns are OK, including 3306H get DOS version)
429
;   50H (set PSP address)
430
;   51H and 62H (query PSP address)
431
;   59H (get extended error information)
432
;
433
; *** ON EXIT ***
434
;
435
; After handling the error, AL should be set with an action code and get back
436
; to DOS. Available actions are defined in AH at entry (see above). Possible
437
; values on exit are:
438
;   AL=0  ignore error (pretend nothing happened)
439
;   AL=1  retry operation
440
;   AL=2  abort (terminates the failed program via int 23h, like ctrl+break)
441
;   AL=3  return to application indicating a failure of the DOS function
442
;
443
; A very basic "always fail" handler would be as simple as this:
444
;   mov al, 3
445
;   iret
446
;
447
; *** DOS CALLS ***
448
;
449
; Warning! Be careful about using DOS fns in your Critical Error handler.
450
;          With DOS 5.0+, ONLY the following fns can be called safely:
451
;
452
;          01H-0CH (DOS character I/O)
453
;          33H (all subfns are OK, including 3306H get DOS version)
454
;          50H (set PSP address)
455
;          51H and 62H (query PSP address)
456
;          59H (get extended error information)
457
;
458
; =============================================================================
459
HANDLER_24H:    ; +46Ch
460
 
1868 mateusz.vi 461
; save registers so I can restore them later. AX does not require saving.
462
; Microsoft documentation says:
463
;  "When it is desired to ignore an error, the same registers must be preserved
464
;   as when it is desired to retry the operation (SS,SP,DS,BX,CX,DX)."
465
; source: INT24.DOC from MS-DOS 2.0
466
push bx
467
push cx
468
push dx
469
push ds
470
pushf
1863 mateusz.vi 471
 
472
; set DS to myself
473
push cs
474
pop ds
475
 
476
; is this a DISK error?
1864 mateusz.vi 477
test ah, 0x80
478
jz DISKERROR
1863 mateusz.vi 479
; non-disk error: output "CRITICAL ERROR #XXX SYSTEM HALTED" and freeze
480
; update the crit string so it contains the proper error code
1864 mateusz.vi 481
mov bx, CRITERRSYST+1
1863 mateusz.vi 482
mov ax, di
483
xor ah, ah
484
mov cl, 100
485
div cl ; AL = AX / cl     AH = remainder
486
add al, '0'
1864 mateusz.vi 487
mov [bx], al
488
inc bx
1863 mateusz.vi 489
 
490
mov al, ah
491
xor ah, ah
492
mov cl, 10
493
div cl
494
add al, '0'
495
add ah, '0'
1864 mateusz.vi 496
mov [bx], al
497
inc bx
498
mov [bx], ah
1863 mateusz.vi 499
 
500
; display the string
501
mov ah, 0x09
502
mov dx, CRITERR
503
int 0x21
1864 mateusz.vi 504
mov dx, CRITERRSYST
505
int 0x21
1863 mateusz.vi 506
; freeze the system
507
HALT:
508
sti
509
hlt;
510
jmp HALT
511
 
512
DISKERROR:
1864 mateusz.vi 513
; disk errors produce this message:
1866 mateusz.vi 514
; A: - READ|WRITE FAILURE
515
; (A)bort, (R)etry, (I)gnore, (F)ail
516
mov ch, ah      ; backup AH flags into CH
1864 mateusz.vi 517
add al, 'A'
1866 mateusz.vi 518
mov [CRITERRDISK], al
1864 mateusz.vi 519
mov ah, 0x09
520
mov dx, CRITERRDISK
521
int 0x21
522
; READ / WRITE (test flag 0x01, set = write, read otherwise)
523
mov dx, CRITERRDSK_WRITE
524
test ch, 1
525
jnz WRITE
526
mov dx, CRITERRDSK_READ
527
WRITE:
528
int 0x21
1866 mateusz.vi 529
mov dx, CRLF
1864 mateusz.vi 530
int 0x21
1866 mateusz.vi 531
; print available options (abort=always, 0x10=retry, 0x20=ignore, 0x08=fail)
532
CRITERR_ASKCHOICE:
533
mov dx, CRITERR_ABORT
534
int 0x21
535
; retry?
536
test ch, 0x10
537
jz NORETRY
538
mov dx, CRITERR_COMMA
539
int 0x21
540
mov dx, CRITERR_RETRY
541
int 0x21
542
NORETRY:
543
; ignore?
544
test ch, 0x20
545
jz NOIGNORE
546
mov dx, CRITERR_COMMA
547
int 0x21
548
mov dx, CRITERR_IGNOR
549
int 0x21
550
NOIGNORE:
551
; fail?
552
test ch, 0x08
553
jz NOFAIL
554
mov dx, CRITERR_COMMA
555
int 0x21
556
mov dx, CRITERR_FAIL
557
int 0x21
558
NOFAIL:
559
; output "? "
560
mov ah, 0x06
561
mov dl, '?'
562
int 0x21
563
mov dl, ' '
564
int 0x21
1863 mateusz.vi 565
 
1866 mateusz.vi 566
; wait for user key press and return (iret) with AL set accordingly:
567
;   AL=0  ignore
568
;   AL=1  retry
569
;   AL=2  abort
570
;   AL=3  fail
1863 mateusz.vi 571
 
1866 mateusz.vi 572
mov ah, 0x07  ; key input, no ctrl+c check
573
int 0x21
574
and al, 0xdf   ; switch AL to upper-case so key check is case-insensitive
575
mov cl, al     ; save pressed key in CL (AL is easily overwritten by DOS calls)
576
; print the pressed key
577
mov ah, 0x06
578
mov dl, cl
579
int 0x21
580
mov ah, 0x09
581
mov dx, CRLF
582
int 0x21
583
 
584
; was it abort?
585
cmp cl, [CRITERR_KEYS]
586
jne SKIP_ABORT
587
mov al, 2     ; AL=2 -> "abort"
1868 mateusz.vi 588
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 589
SKIP_ABORT:
590
; if retry is allowed - was it retry?
591
test ch, 0x10
592
jz SKIP_RETRY
593
cmp cl, [CRITERR_KEYS+1]
594
jne SKIP_RETRY
595
mov al, 1     ; AL=1 -> "retry"
1868 mateusz.vi 596
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 597
SKIP_RETRY:
598
; if ignore is allowed - was it ignore?
599
test ch, 0x20
600
jz SKIP_IGN
601
cmp cl, [CRITERR_KEYS+2]
602
jne SKIP_IGN
603
xor al, al    ; AL=0 -> "ignore"
1868 mateusz.vi 604
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 605
SKIP_IGN:
606
; if fail is allowed - was it fail?
607
test ch, 0x08
608
;jz SKIP_FAIL
609
cmp cl, [CRITERR_KEYS+3]
610
jne SKIP_FAIL
611
mov al, 3     ; AL=3 -> "fail"
1868 mateusz.vi 612
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 613
SKIP_FAIL:
1863 mateusz.vi 614
 
1866 mateusz.vi 615
jmp CRITERR_ASKCHOICE   ; invalid answer -> ask again
616
 
1868 mateusz.vi 617
QUIT_WITH_AL_SET:
618
 
1866 mateusz.vi 619
; restore registers and quit the handler
1868 mateusz.vi 620
popf
621
pop ds
622
pop dx
623
pop cx
624
pop bx
625
iret
1866 mateusz.vi 626
 
627
 
628
CRITERR db "CRITICAL ERROR $"
629
CRITERRSYST db "#XXX - SYSTEM HALTED$"
630
CRITERRDISK db "@: - $"
631
CRITERRDSK_READ db "READ FAILURE$"
632
CRITERRDSK_WRITE db "WRITE FAILURE$"
633
CRLF db 0x0A, 0x0D, "$"
634
CRITERR_ABORT db "(A)bort$"
635
CRITERR_RETRY db "(R)etry$"
636
CRITERR_IGNOR db "(I)gnore$"
637
CRITERR_FAIL  db "(F)ail$"
638
CRITERR_KEYS  db "ARIF"
639
CRITERR_COMMA db ", $"