Subversion Repositories SvarDOS

Rev

Rev 983 | Rev 1593 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 983 Rev 987
1
;
1
;
2
; rmod - resident module of the SvarCOM command interpreter (NASM code)
2
; rmod - resident module of the SvarCOM command interpreter (NASM code)
3
;
3
;
4
; Copyright (C) 2021-2022 Mateusz Viste
4
; Copyright (C) 2021-2022 Mateusz Viste
5
; MIT license
5
; MIT license
6
;
6
;
7
; this is installed in memory by the transient part of SvarCOM. it has only
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
8
; two jobs: providing a resident buffer for command history, environment, etc
9
; and respawning COMMAND.COM whenever necessary.
9
; and respawning COMMAND.COM whenever necessary.
10
 
10
 
11
CPU 8086
11
CPU 8086
12
org 0x100
12
org 0x100
13
 
13
 
14
PSP_ENVSEG equ 0x2C
14
PSP_ENVSEG equ 0x2C
15
 
15
 
16
section .text    ; all goes into code segment
16
section .text    ; all goes into code segment
17
 
17
 
18
                 ; offset
18
                 ; offset
19
SIG1 dw 0x1983   ;  +0
19
SIG1 dw 0x1983   ;  +0
20
SIG2 dw 0x1985   ;  +2
20
SIG2 dw 0x1985   ;  +2
21
SIG3 dw 0x2017   ;  +4
21
SIG3 dw 0x2017   ;  +4
22
SIG4 dw 0x2019   ;  +6  acts also as a guardval to detect severe stack overflows
22
SIG4 dw 0x2019   ;  +6  acts also as a guardval to detect severe stack overflows
23
 
23
 
24
; Buffer used to remember previous command, when SvarCOM calls the buffered
24
; Buffer used to remember previous command, when SvarCOM calls the buffered
25
; input service at INT 21h,AH=0x0A.
25
; input service at INT 21h,AH=0x0A.
26
; This buffer is right before the stack, so in case of a stack overflow event
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,
27
; (for example because of a "too ambitious" TSR) only this buffer is damaged,
28
; and can be invalidated without much harm.
28
; and can be invalidated without much harm. To detect such damage, SvarCOM's
29
INPUTBUF: times 130 db 0
-
 
30
 
-
 
31
; This stack sig is a guardian value that is checked by the transient part of
29
; transient part is appending a signature at the end of the buffer.
32
; SvarCOM to detect possible stack overflows. If a stack overflow occurs, then
-
 
33
; the INPUTBUFF area above is invalidated and stack signature reverted.
30
INPUTBUF: times 132 db 0 ; 130 bytes for the input buffer + 2 for signature
34
STACKSIG dw 0xCAFE
-
 
35
 
31
 
36
; DOS int 21h functions that I use require at least 40 bytes of stack under
32
; DOS int 21h functions that I use require at least 40 bytes of stack under
37
; DOS-C (FreeDOS) kernel, so here I reserve 64 bytes juste to be sure
33
; DOS-C (FreeDOS) kernel, so here I reserve 64 bytes juste to be sure
38
STACKBUF db "XXX  SVARCOM RMOD BY MATEUSZ VISTE  XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
34
STACKBUF db "XXX  SVARCOM RMOD BY MATEUSZ VISTE  XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
39
STACKPTR dw 0
35
STACKPTR dw 0
40
 
36
 
41
; offset of the COMSPEC variable in the environment block, 0 means "use
37
; offset of the COMSPEC variable in the environment block, 0 means "use
42
; boot drive". this value is patched by the transient part of COMMAND.COM
38
; boot drive". this value is patched by the transient part of COMMAND.COM
43
COMSPECPTR dw 0  ; +4Ah
39
COMSPECPTR dw 0  ; +4Ah
44
 
40
 
45
; fallback COMSPEC string used if no COMPSEC is present in the environment
41
; fallback COMSPEC string used if no COMPSEC is present in the environment
46
; drive. drive is patched by the transient part of COMMAND.COM
42
; drive. drive is patched by the transient part of COMMAND.COM
47
COMSPECBOOT db "@:\COMMAND.COM", 0 ; +4Ch
43
COMSPECBOOT db "@:\COMMAND.COM", 0 ; +4Ch
48
 
44
 
49
; exit code of last application
45
; exit code of last application
50
LEXCODE  db 0    ; +5Bh
46
LEXCODE  db 0    ; +5Bh
51
 
47
 
52
; ExecParamRec used by INT 21h, AX=4b00 (load and execute program), 14 bytes:
48
; ExecParamRec used by INT 21h, AX=4b00 (load and execute program), 14 bytes:
53
;  offset  size  content
49
;  offset  size  content
54
;     +0     2   segment of environment for child (0 = current)
50
;     +0     2   segment of environment for child (0 = current)
55
;     +2     4   address of command line to place at PSP:0080
51
;     +2     4   address of command line to place at PSP:0080
56
;     +6     4   address of an FCB to be placed at PSP:005c
52
;     +6     4   address of an FCB to be placed at PSP:005c
57
;    +0Ah    4   address of an FCB to be placed at PSP:006c
53
;    +0Ah    4   address of an FCB to be placed at PSP:006c
58
EXEC_PARAM_REC db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   ; +5Ch
54
EXEC_PARAM_REC db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   ; +5Ch
59
 
55
 
60
; Program to execute, preset by SvarCOM (128 bytes, ASCIIZ)
56
; Program to execute, preset by SvarCOM (128 bytes, ASCIIZ)
61
EXECPROG: times 128 db 0                                     ; +6Ah
57
EXECPROG: times 128 db 0                                     ; +6Ah
62
 
58
 
63
; File where stdin and stdout should be redirected (0 = no redirection)
59
; File where stdin and stdout should be redirected (0 = no redirection)
64
REDIR_INFIL:     times 128 db 0     ; +EAh
60
REDIR_INFIL:     times 128 db 0     ; +EAh
65
REDIR_OUTFIL:    times 128 db 0     ; +16Ah
61
REDIR_OUTFIL:    times 128 db 0     ; +16Ah
66
REDIR_OUTAPPEND: dw 0               ; +1EAh
62
REDIR_OUTAPPEND: dw 0               ; +1EAh
67
REDIR_DEL_STDIN: db 0               ; +1ECh  indicates that the stdin file
63
REDIR_DEL_STDIN: db 0               ; +1ECh  indicates that the stdin file
68
                                    ;        should be deleted (pipes). This
64
                                    ;        should be deleted (pipes). This
69
                                    ;        MUST contain the 1st char of
65
                                    ;        MUST contain the 1st char of
70
                                    ;        REDIR_INFIL!
66
                                    ;        REDIR_INFIL!
71
 
67
 
72
; CTRL+BREAK (int 23h) handler
68
; CTRL+BREAK (int 23h) handler
73
; According to the TechHelp! Manual: "If you want to abort (exit to the parent
69
; According to the TechHelp! Manual: "If you want to abort (exit to the parent
74
; process), then set the carry flag and return via a FAR RET. This causes DOS
70
; process), then set the carry flag and return via a FAR RET. This causes DOS
75
; to perform normal cleanup and exit to the parent." (otherwise use iret)
71
; to perform normal cleanup and exit to the parent." (otherwise use iret)
76
BREAK_HANDLER:            ; +1EDh
72
BREAK_HANDLER:            ; +1EDh
77
stc
73
stc
78
retf
74
retf
79
 
75
 
80
 
76
 
81
skipsig:                  ; +1EFh
77
skipsig:                  ; +1EFh
82
 
78
 
83
; set up CS=DS=SS and point SP to my private stack buffer
79
; set up CS=DS=SS and point SP to my private stack buffer
84
mov ax, cs
80
mov ax, cs
85
mov ds, ax
81
mov ds, ax
86
mov es, ax
82
mov es, ax
87
mov ss, ax
83
mov ss, ax
88
mov sp, STACKPTR
84
mov sp, STACKPTR
89
 
85
 
90
; set up myself as break handler
86
; set up myself as break handler
91
mov ax, 0x2523  ; set int vector 23h
87
mov ax, 0x2523  ; set int vector 23h
92
mov dx, BREAK_HANDLER
88
mov dx, BREAK_HANDLER
93
int 0x21
89
int 0x21
94
 
90
 
95
; revert stdin/stdout redirections (if any) to their initial state
91
; revert stdin/stdout redirections (if any) to their initial state
96
call REVERT_REDIR_IF_ANY
92
call REVERT_REDIR_IF_ANY
97
 
93
 
98
; redirect stdin and/or stdout if required
94
; redirect stdin and/or stdout if required
99
call REDIR_INOUTFILE_IF_REQUIRED
95
call REDIR_INOUTFILE_IF_REQUIRED
100
 
96
 
101
; should I executed command.com or a pre-set application?
97
; should I executed command.com or a pre-set application?
102
or [EXECPROG], byte 0
98
or [EXECPROG], byte 0
103
jz EXEC_COMMAND_COM
99
jz EXEC_COMMAND_COM
104
 
100
 
105
; TODO: perhaps I should call the DOS SetPSP function here? But if I do, the
101
; TODO: perhaps I should call the DOS SetPSP function here? But if I do, the
106
;       int 21h, ah=50h call freezes...
102
;       int 21h, ah=50h call freezes...
107
;mov ah, 0x50           ; DOS 2+ -- Set PSP
103
;mov ah, 0x50           ; DOS 2+ -- Set PSP
108
;mov bx, cs
104
;mov bx, cs
109
;int 0x21
105
;int 0x21
110
 
106
 
111
; exec an application preset (by SvarCOM) in the ExecParamRec
107
; exec an application preset (by SvarCOM) in the ExecParamRec
112
mov ax, 0x4B00         ; DOS 2+ - load & execute program
108
mov ax, 0x4B00         ; DOS 2+ - load & execute program
113
mov dx, EXECPROG       ; DS:DX  - ASCIZ program name (preset at PSP[already)
109
mov dx, EXECPROG       ; DS:DX  - ASCIZ program name (preset at PSP[already)
114
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
110
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
115
int 0x21
111
int 0x21
116
mov [cs:EXECPROG], byte 0 ; do not run app again (+DS might have been changed)
112
mov [cs:EXECPROG], byte 0 ; do not run app again (+DS might have been changed)
117
 
113
 
118
jmp short skipsig      ; enforce valid ds/ss/etc (can be lost after int 21,4b)
114
jmp short skipsig      ; enforce valid ds/ss/etc (can be lost after int 21,4b)
119
 
115
 
120
EXEC_COMMAND_COM:
116
EXEC_COMMAND_COM:
121
 
117
 
122
; collect the exit code of previous application
118
; collect the exit code of previous application
123
mov ah, 0x4D
119
mov ah, 0x4D
124
int 0x21
120
int 0x21
125
mov [LEXCODE], al
121
mov [LEXCODE], al
126
 
122
 
127
; zero out the exec param block (14 bytes)
123
; zero out the exec param block (14 bytes)
128
mov al, 0              ; byte to write
124
mov al, 0              ; byte to write
129
mov cx, 14             ; how many times
125
mov cx, 14             ; how many times
130
mov di, EXEC_PARAM_REC ; ES:DI = destination
126
mov di, EXEC_PARAM_REC ; ES:DI = destination
131
cld                    ; stosb must move forward
127
cld                    ; stosb must move forward
132
rep stosb              ; repeat cx times
128
rep stosb              ; repeat cx times
133
 
129
 
134
; preset the default COMSPEC pointer to ES:DX (ES is already set to DS)
130
; preset the default COMSPEC pointer to ES:DX (ES is already set to DS)
135
mov dx, COMSPECBOOT
131
mov dx, COMSPECBOOT
136
 
132
 
137
; do I have a valid COMSPEC?
133
; do I have a valid COMSPEC?
138
or [COMSPECPTR], word 0
134
or [COMSPECPTR], word 0
139
jz USEDEFAULTCOMSPEC
135
jz USEDEFAULTCOMSPEC
140
; set ES:DX to actual COMSPEC (in env segment)
136
; set ES:DX to actual COMSPEC (in env segment)
141
mov es, [PSP_ENVSEG]
137
mov es, [PSP_ENVSEG]
142
mov dx, [COMSPECPTR]
138
mov dx, [COMSPECPTR]
143
USEDEFAULTCOMSPEC:
139
USEDEFAULTCOMSPEC:
144
 
140
 
145
; prepare the exec param block
141
; prepare the exec param block
146
mov ax, [PSP_ENVSEG]
142
mov ax, [PSP_ENVSEG]
147
mov [EXEC_PARAM_REC], ax
143
mov [EXEC_PARAM_REC], ax
148
mov [EXEC_PARAM_REC+2], word CMDTAIL
144
mov [EXEC_PARAM_REC+2], word CMDTAIL
149
mov [EXEC_PARAM_REC+4], cs
145
mov [EXEC_PARAM_REC+4], cs
150
 
146
 
151
; execute command.com
147
; execute command.com
152
mov ax, 0x4B00         ; DOS 2+ - load & execute program
148
mov ax, 0x4B00         ; DOS 2+ - load & execute program
153
push es                ;
149
push es                ;
154
pop ds                 ;
150
pop ds                 ;
155
;mov dx, COMSPEC       ; DS:DX  - ASCIZ program name (preset already)
151
;mov dx, COMSPEC       ; DS:DX  - ASCIZ program name (preset already)
156
push cs
152
push cs
157
pop es
153
pop es
158
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
154
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
159
int 0x21
155
int 0x21
160
 
156
 
161
; if all went well, jump back to start
157
; if all went well, jump back to start
162
jnc skipsig
158
jnc skipsig
163
 
159
 
164
; restore DS=CS
160
; restore DS=CS
165
mov bx, cs
161
mov bx, cs
166
mov ds, bx
162
mov ds, bx
167
 
163
 
168
; update error string so it contains the error number
164
; update error string so it contains the error number
169
add al, '0'
165
add al, '0'
170
mov [ERRLOAD + 4], al
166
mov [ERRLOAD + 4], al
171
 
167
 
172
; display error message
168
; display error message
173
mov ah, 0x09
169
mov ah, 0x09
174
mov dx, ERRLOAD
170
mov dx, ERRLOAD
175
int 0x21
171
int 0x21
176
 
172
 
177
; wait for keypress
173
; wait for keypress
178
mov ah, 0x08
174
mov ah, 0x08
179
int 0x21
175
int 0x21
180
 
176
 
181
; back to program start
177
; back to program start
182
jmp skipsig
178
jmp skipsig
183
 
179
 
184
; command.com tail arguments, in PSP format: length byte followed by args and
180
; command.com tail arguments, in PSP format: length byte followed by args and
185
; terminated with \r) - a single 0x0A byte is passed so SvarCOM knows it is
181
; terminated with \r) - a single 0x0A byte is passed so SvarCOM knows it is
186
; called as respawn (as opposed to being invoked as a normal application)
182
; called as respawn (as opposed to being invoked as a normal application)
187
; this allows multiple copies of SvarCOM to stack upon each other.
183
; this allows multiple copies of SvarCOM to stack upon each other.
188
CMDTAIL db 0x01, 0x0A, 0x0D
184
CMDTAIL db 0x01, 0x0A, 0x0D
189
 
185
 
190
ERRLOAD db "ERR x, FAILED TO LOAD COMMAND.COM", 13, 10, '$'
186
ERRLOAD db "ERR x, FAILED TO LOAD COMMAND.COM", 13, 10, '$'
191
 
187
 
192
; variables used to revert stdin/stdout to their initial state
188
; variables used to revert stdin/stdout to their initial state
193
OLD_STDOUT dw 0xffff
189
OLD_STDOUT dw 0xffff
194
OLD_STDIN  dw 0xffff
190
OLD_STDIN  dw 0xffff
195
 
191
 
196
 
192
 
197
; ****************************************************************************
193
; ****************************************************************************
198
; *** ROUTINES ***************************************************************
194
; *** ROUTINES ***************************************************************
199
; ****************************************************************************
195
; ****************************************************************************
200
 
196
 
201
; ----------------------------------------------------------------------------
197
; ----------------------------------------------------------------------------
202
; revert stdin/stdout redirections (if any) to their initial state
198
; revert stdin/stdout redirections (if any) to their initial state
203
REVERT_REDIR_IF_ANY:
199
REVERT_REDIR_IF_ANY:
204
; is stdout redirected?
200
; is stdout redirected?
205
mov bx, [OLD_STDOUT]
201
mov bx, [OLD_STDOUT]
206
cmp bx, 0xffff
202
cmp bx, 0xffff
207
je STDOUT_DONE
203
je STDOUT_DONE
208
; revert the stdout handle (dst in BX already)
204
; revert the stdout handle (dst in BX already)
209
mov cx, 1        ; src handle (1=stdout)
205
mov cx, 1        ; src handle (1=stdout)
210
mov ah, 0x46     ; redirect a handle
206
mov ah, 0x46     ; redirect a handle
211
int 0x21
207
int 0x21
212
; close the old handle (still in bx)
208
; close the old handle (still in bx)
213
mov ah, 0x3e
209
mov ah, 0x3e
214
int 0x21
210
int 0x21
215
mov [OLD_STDOUT], word 0xffff ; mark stdout as "not redirected"
211
mov [OLD_STDOUT], word 0xffff ; mark stdout as "not redirected"
216
STDOUT_DONE:
212
STDOUT_DONE:
217
 
213
 
218
; is stdin redirected?
214
; is stdin redirected?
219
mov bx, [OLD_STDIN]
215
mov bx, [OLD_STDIN]
220
cmp bx, 0xffff
216
cmp bx, 0xffff
221
je STDIN_DONE
217
je STDIN_DONE
222
; revert the stdin handle (dst in BX already)
218
; revert the stdin handle (dst in BX already)
223
xor cx, cx       ; src handle (0=stdin)
219
xor cx, cx       ; src handle (0=stdin)
224
mov ah, 0x46     ; redirect a handle
220
mov ah, 0x46     ; redirect a handle
225
int 0x21
221
int 0x21
226
; close the old handle (still in bx)
222
; close the old handle (still in bx)
227
mov ah, 0x3e
223
mov ah, 0x3e
228
int 0x21
224
int 0x21
229
mov [OLD_STDIN], word 0xffff ; mark stdin as "not redirected"
225
mov [OLD_STDIN], word 0xffff ; mark stdin as "not redirected"
230
 
226
 
231
; delete stdin file if required
227
; delete stdin file if required
232
cmp [REDIR_DEL_STDIN], byte 0
228
cmp [REDIR_DEL_STDIN], byte 0
233
je STDIN_DONE
229
je STDIN_DONE
234
; revert the original file and delete it
230
; revert the original file and delete it
235
mov ah, [REDIR_DEL_STDIN]
231
mov ah, [REDIR_DEL_STDIN]
236
mov [REDIR_INFIL], ah
232
mov [REDIR_INFIL], ah
237
mov ah, 0x41     ; DOS 2+ - delete file pointed at by DS:DX
233
mov ah, 0x41     ; DOS 2+ - delete file pointed at by DS:DX
238
mov dx, REDIR_INFIL
234
mov dx, REDIR_INFIL
239
int 0x21
235
int 0x21
240
mov [REDIR_INFIL], byte 0
236
mov [REDIR_INFIL], byte 0
241
mov [REDIR_DEL_STDIN], byte 0
237
mov [REDIR_DEL_STDIN], byte 0
242
 
238
 
243
STDIN_DONE:
239
STDIN_DONE:
244
 
240
 
245
ret
241
ret
246
; ----------------------------------------------------------------------------
242
; ----------------------------------------------------------------------------
247
 
243
 
248
 
244
 
249
; ----------------------------------------------------------------------------
245
; ----------------------------------------------------------------------------
250
; redirect stdout if REDIR_OUTFIL points to something
246
; redirect stdout if REDIR_OUTFIL points to something
251
REDIR_INOUTFILE_IF_REQUIRED:
247
REDIR_INOUTFILE_IF_REQUIRED:
252
cmp [REDIR_OUTFIL], byte 0
248
cmp [REDIR_OUTFIL], byte 0
253
je NO_STDOUT_REDIR
249
je NO_STDOUT_REDIR
254
mov si, REDIR_OUTFIL   ; si = output file
250
mov si, REDIR_OUTFIL   ; si = output file
255
mov ax, 0x6c00         ; Extended Open/Create
251
mov ax, 0x6c00         ; Extended Open/Create
256
mov bx, 1              ; access mode (0=read, 1=write, 2=r+w)
252
mov bx, 1              ; access mode (0=read, 1=write, 2=r+w)
257
xor cx, cx             ; file attribs when(if) file is created (0=normal)
253
xor cx, cx             ; file attribs when(if) file is created (0=normal)
258
mov dx, [REDIR_OUTAPPEND] ; action if file exist (0x11=open, 0x12=truncate)
254
mov dx, [REDIR_OUTAPPEND] ; action if file exist (0x11=open, 0x12=truncate)
259
int 0x21               ; ax=handle on success (CF clear)
255
int 0x21               ; ax=handle on success (CF clear)
260
mov [REDIR_OUTFIL], byte 0
256
mov [REDIR_OUTFIL], byte 0
261
jc NO_STDOUT_REDIR     ; TODO: abort with an error message instead
257
jc NO_STDOUT_REDIR     ; TODO: abort with an error message instead
262
 
258
 
263
; jump to end of file if flag was 0x11 (required for >> redirections)
259
; jump to end of file if flag was 0x11 (required for >> redirections)
264
cmp [REDIR_OUTAPPEND], word 0x11
260
cmp [REDIR_OUTAPPEND], word 0x11
265
jne SKIP_JMPEOF
261
jne SKIP_JMPEOF
266
mov bx, ax
262
mov bx, ax
267
mov ax, 0x4202         ; jump to position EOF - CX:DX in handle BX
263
mov ax, 0x4202         ; jump to position EOF - CX:DX in handle BX
268
xor cx, cx
264
xor cx, cx
269
xor dx, dx
265
xor dx, dx
270
int 0x21
266
int 0x21
271
mov ax, bx             ; put my handle back in ax, as expected by later code
267
mov ax, bx             ; put my handle back in ax, as expected by later code
272
SKIP_JMPEOF:
268
SKIP_JMPEOF:
273
 
269
 
274
; duplicate current stdout so I can revert it later
270
; duplicate current stdout so I can revert it later
275
push ax                ; save my file handle in stack
271
push ax                ; save my file handle in stack
276
mov ah, 0x45           ; duplicate file handle BX
272
mov ah, 0x45           ; duplicate file handle BX
277
mov bx, 1              ; 1 = stdout
273
mov bx, 1              ; 1 = stdout
278
int 0x21               ; ax=new (duplicated) file handle
274
int 0x21               ; ax=new (duplicated) file handle
279
mov [OLD_STDOUT], ax   ; save the old handle in memory
275
mov [OLD_STDOUT], ax   ; save the old handle in memory
280
 
276
 
281
; redirect stdout to my file
277
; redirect stdout to my file
282
pop bx                 ; dst handle
278
pop bx                 ; dst handle
283
mov cx, 1              ; src handle (1=stdout)
279
mov cx, 1              ; src handle (1=stdout)
284
mov ah, 0x46           ; "redirect a handle"
280
mov ah, 0x46           ; "redirect a handle"
285
int 0x21
281
int 0x21
286
 
282
 
287
; close the original file handle, I no longer need it
283
; close the original file handle, I no longer need it
288
mov ah, 0x3e           ; close a file handle (handle in BX)
284
mov ah, 0x3e           ; close a file handle (handle in BX)
289
int 0x21
285
int 0x21
290
NO_STDOUT_REDIR:
286
NO_STDOUT_REDIR:
291
 
287
 
292
; *** redirect stdin if REDIR_INFIL points to something ***
288
; *** redirect stdin if REDIR_INFIL points to something ***
293
cmp [REDIR_INFIL], byte 0
289
cmp [REDIR_INFIL], byte 0
294
je NO_STDIN_REDIR
290
je NO_STDIN_REDIR
295
mov dx, REDIR_INFIL    ; dx:dx = file
291
mov dx, REDIR_INFIL    ; dx:dx = file
296
mov ax, 0x3d00         ; open file for read
292
mov ax, 0x3d00         ; open file for read
297
int 0x21               ; ax=handle on success (CF clear)
293
int 0x21               ; ax=handle on success (CF clear)
298
mov [REDIR_INFIL], byte 0
294
mov [REDIR_INFIL], byte 0
299
jc NO_STDIN_REDIR      ; TODO: abort with an error message instead
295
jc NO_STDIN_REDIR      ; TODO: abort with an error message instead
300
 
296
 
301
; duplicate current stdin so I can revert it later
297
; duplicate current stdin so I can revert it later
302
push ax                ; save my file handle in stack
298
push ax                ; save my file handle in stack
303
mov ah, 0x45           ; duplicate file handle BX
299
mov ah, 0x45           ; duplicate file handle BX
304
xor bx, bx             ; 0=stdin
300
xor bx, bx             ; 0=stdin
305
int 0x21               ; ax=new (duplicated) file handle
301
int 0x21               ; ax=new (duplicated) file handle
306
mov [OLD_STDIN], ax    ; save the old handle in memory
302
mov [OLD_STDIN], ax    ; save the old handle in memory
307
 
303
 
308
; redirect stdout to my file
304
; redirect stdout to my file
309
pop bx                 ; dst handle
305
pop bx                 ; dst handle
310
xor cx, cx             ; src handle (0=stdin)
306
xor cx, cx             ; src handle (0=stdin)
311
mov ah, 0x46           ; "redirect a handle"
307
mov ah, 0x46           ; "redirect a handle"
312
int 0x21
308
int 0x21
313
 
309
 
314
; close the original file handle, I no longer need it
310
; close the original file handle, I no longer need it
315
mov ah, 0x3e           ; close a file handle (handle in BX)
311
mov ah, 0x3e           ; close a file handle (handle in BX)
316
int 0x21
312
int 0x21
317
NO_STDIN_REDIR:
313
NO_STDIN_REDIR:
318
ret
314
ret
319
; ----------------------------------------------------------------------------
315
; ----------------------------------------------------------------------------
320
 
316