Subversion Repositories SvarDOS

Rev

Rev 987 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 987 Rev 1101
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. To detect such damage, SvarCOM's
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.
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
30
INPUTBUF: times 132 db 0 ; 130 bytes for the input buffer + 2 for signature
31
 
31
 
32
; 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
33
; 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
34
STACKBUF db "XXX  SVARCOM RMOD BY MATEUSZ VISTE  XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
34
STACKBUF db "XXX  SVARCOM RMOD BY MATEUSZ VISTE  XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
35
STACKPTR dw 0
35
STACKPTR dw 0
36
 
36
 
37
; 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
38
; 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
39
COMSPECPTR dw 0  ; +4Ah
39
COMSPECPTR dw 0  ; +4Ah
40
 
40
 
41
; 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
42
; drive. drive is patched by the transient part of COMMAND.COM
42
; drive. drive is patched by the transient part of COMMAND.COM
43
COMSPECBOOT db "@:\COMMAND.COM", 0 ; +4Ch
43
COMSPECBOOT db "@:\COMMAND.COM", 0 ; +4Ch
44
 
44
 
45
; exit code of last application
45
; exit code of last application
46
LEXCODE  db 0    ; +5Bh
46
LEXCODE  db 0    ; +5Bh
47
 
47
 
48
; 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:
49
;  offset  size  content
49
;  offset  size  content
50
;     +0     2   segment of environment for child (0 = current)
50
;     +0     2   segment of environment for child (0 = current)
51
;     +2     4   address of command line to place at PSP:0080
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
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
53
;    +0Ah    4   address of an FCB to be placed at PSP:006c
54
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
55
 
55
 
56
; Program to execute, preset by SvarCOM (128 bytes, ASCIIZ)
56
; Program to execute, preset by SvarCOM (128 bytes, ASCIIZ)
57
EXECPROG: times 128 db 0                                     ; +6Ah
57
EXECPROG: times 128 db 0                                     ; +6Ah
58
 
58
 
59
; File where stdin and stdout should be redirected (0 = no redirection)
59
; File where stdin and stdout should be redirected (0 = no redirection)
60
REDIR_INFIL:     times 128 db 0     ; +EAh
60
REDIR_INFIL:     times 128 db 0     ; +EAh
61
REDIR_OUTFIL:    times 128 db 0     ; +16Ah
61
REDIR_OUTFIL:    times 128 db 0     ; +16Ah
62
REDIR_OUTAPPEND: dw 0               ; +1EAh
62
REDIR_OUTAPPEND: dw 0               ; +1EAh
63
REDIR_DEL_STDIN: db 0               ; +1ECh  indicates that the stdin file
63
REDIR_DEL_STDIN: db 0               ; +1ECh  indicates that the stdin file
64
                                    ;        should be deleted (pipes). This
64
                                    ;        should be deleted (pipes). This
65
                                    ;        MUST contain the 1st char of
65
                                    ;        MUST contain the 1st char of
66
                                    ;        REDIR_INFIL!
66
                                    ;        REDIR_INFIL!
67
 
67
 
68
; CTRL+BREAK (int 23h) handler
68
; CTRL+BREAK (int 23h) handler
69
; 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
70
; 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
71
; 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)
72
BREAK_HANDLER:            ; +1EDh
72
BREAK_HANDLER:            ; +1EDh
73
stc
73
stc
74
retf
74
retf
75
 
75
 
76
 
76
 
77
skipsig:                  ; +1EFh
77
skipsig:                  ; +1EFh
78
 
78
 
79
; 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
80
mov ax, cs
80
mov ax, cs
81
mov ds, ax
81
mov ds, ax
82
mov es, ax
82
mov es, ax
83
mov ss, ax
83
mov ss, ax
84
mov sp, STACKPTR
84
mov sp, STACKPTR
85
 
85
 
86
; set up myself as break handler
86
; set up myself as break handler
87
mov ax, 0x2523  ; set int vector 23h
87
mov ax, 0x2523  ; set int vector 23h
88
mov dx, BREAK_HANDLER
88
mov dx, BREAK_HANDLER
89
int 0x21
89
int 0x21
90
 
90
 
91
; revert stdin/stdout redirections (if any) to their initial state
91
; revert stdin/stdout redirections (if any) to their initial state
92
call REVERT_REDIR_IF_ANY
92
call REVERT_REDIR_IF_ANY
93
 
93
 
94
; redirect stdin and/or stdout if required
94
; redirect stdin and/or stdout if required
95
call REDIR_INOUTFILE_IF_REQUIRED
95
call REDIR_INOUTFILE_IF_REQUIRED
96
 
96
 
97
; should I executed command.com or a pre-set application?
97
; should I executed command.com or a pre-set application?
98
or [EXECPROG], byte 0
98
or [EXECPROG], byte 0
99
jz EXEC_COMMAND_COM
99
jz EXEC_COMMAND_COM
100
 
100
 
101
; 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
102
;       int 21h, ah=50h call freezes...
102
;       int 21h, ah=50h call freezes...
103
;mov ah, 0x50           ; DOS 2+ -- Set PSP
103
;mov ah, 0x50           ; DOS 2+ -- Set PSP
104
;mov bx, cs
104
;mov bx, cs
105
;int 0x21
105
;int 0x21
106
 
106
 
107
; exec an application preset (by SvarCOM) in the ExecParamRec
107
; exec an application preset (by SvarCOM) in the ExecParamRec
108
mov ax, 0x4B00         ; DOS 2+ - load & execute program
108
mov ax, 0x4B00         ; DOS 2+ - load & execute program
109
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)
110
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
110
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
111
int 0x21
111
int 0x21
112
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)
113
 
113
 
114
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)
115
 
115
 
116
EXEC_COMMAND_COM:
116
EXEC_COMMAND_COM:
117
 
117
 
118
; collect the exit code of previous application
118
; collect the exit code of previous application
119
mov ah, 0x4D
119
mov ah, 0x4D
120
int 0x21
120
int 0x21
121
mov [LEXCODE], al
121
mov [LEXCODE], al
122
 
122
 
123
; zero out the exec param block (14 bytes)
123
; zero out the exec param block (14 bytes)
124
mov al, 0              ; byte to write
124
mov al, 0              ; byte to write
125
mov cx, 14             ; how many times
125
mov cx, 14             ; how many times
126
mov di, EXEC_PARAM_REC ; ES:DI = destination
126
mov di, EXEC_PARAM_REC ; ES:DI = destination
127
cld                    ; stosb must move forward
127
cld                    ; stosb must move forward
128
rep stosb              ; repeat cx times
128
rep stosb              ; repeat cx times
129
 
129
 
130
; 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)
131
mov dx, COMSPECBOOT
131
mov dx, COMSPECBOOT
132
 
132
 
133
; do I have a valid COMSPEC?
133
; do I have a valid COMSPEC?
134
or [COMSPECPTR], word 0
134
or [COMSPECPTR], word 0
135
jz USEDEFAULTCOMSPEC
135
jz USEDEFAULTCOMSPEC
136
; set ES:DX to actual COMSPEC (in env segment)
136
; set ES:DX to actual COMSPEC (in env segment)
137
mov es, [PSP_ENVSEG]
137
mov es, [PSP_ENVSEG]
138
mov dx, [COMSPECPTR]
138
mov dx, [COMSPECPTR]
139
USEDEFAULTCOMSPEC:
139
USEDEFAULTCOMSPEC:
140
 
140
 
141
; prepare the exec param block
141
; prepare the exec param block
142
mov ax, [PSP_ENVSEG]
142
mov ax, [PSP_ENVSEG]
143
mov [EXEC_PARAM_REC], ax
143
mov [EXEC_PARAM_REC], ax
144
mov [EXEC_PARAM_REC+2], word CMDTAIL
144
mov [EXEC_PARAM_REC+2], word CMDTAIL
145
mov [EXEC_PARAM_REC+4], cs
145
mov [EXEC_PARAM_REC+4], cs
146
 
146
 
147
; execute command.com
147
; execute command.com
148
mov ax, 0x4B00         ; DOS 2+ - load & execute program
148
mov ax, 0x4B00         ; DOS 2+ - load & execute program
149
push es                ;
149
push es                ;
150
pop ds                 ;
150
pop ds                 ;
151
;mov dx, COMSPEC       ; DS:DX  - ASCIZ program name (preset already)
151
;mov dx, COMSPEC       ; DS:DX  - ASCIZ program name (preset already)
152
push cs
152
push cs
153
pop es
153
pop es
154
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
154
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
155
int 0x21
155
int 0x21
156
 
156
 
157
; if all went well, jump back to start
157
; if all went well, jump back to start
158
jnc skipsig
158
jnc skipsig
159
 
159
 
160
; restore DS=CS
160
; restore DS=CS
161
mov bx, cs
161
mov bx, cs
162
mov ds, bx
162
mov ds, bx
163
 
163
 
164
; update error string so it contains the error number
164
; update error string so it contains the error number
165
add al, '0'
165
add al, '0'
166
mov [ERRLOAD + 4], al
166
mov [ERRLOAD + 4], al
167
 
167
 
168
; display error message
168
; display error message
169
mov ah, 0x09
169
mov ah, 0x09
170
mov dx, ERRLOAD
170
mov dx, ERRLOAD
171
int 0x21
171
int 0x21
172
 
172
 
173
; wait for keypress
173
; wait for keypress
174
mov ah, 0x08
174
mov ah, 0x08
175
int 0x21
175
int 0x21
176
 
176
 
177
; back to program start
177
; back to program start
178
jmp skipsig
178
jmp skipsig
179
 
179
 
180
; 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
181
; 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
182
; 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)
183
; this allows multiple copies of SvarCOM to stack upon each other.
183
; this allows multiple copies of SvarCOM to stack upon each other.
184
CMDTAIL db 0x01, 0x0A, 0x0D
184
CMDTAIL db 0x01, 0x0A, 0x0D
185
 
185
 
186
ERRLOAD db "ERR x, FAILED TO LOAD COMMAND.COM", 13, 10, '$'
186
ERRLOAD db "ERR x, FAILED TO LOAD COMMAND.COM", 13, 10, '$'
187
 
187
 
188
; variables used to revert stdin/stdout to their initial state
188
; variables used to revert stdin/stdout to their initial state
189
OLD_STDOUT dw 0xffff
189
OLD_STDOUT dw 0xffff
190
OLD_STDIN  dw 0xffff
190
OLD_STDIN  dw 0xffff
191
 
191
 
192
 
192
 
193
; ****************************************************************************
193
; ****************************************************************************
194
; *** ROUTINES ***************************************************************
194
; *** ROUTINES ***************************************************************
195
; ****************************************************************************
195
; ****************************************************************************
196
 
196
 
197
; ----------------------------------------------------------------------------
197
; ----------------------------------------------------------------------------
198
; revert stdin/stdout redirections (if any) to their initial state
198
; revert stdin/stdout redirections (if any) to their initial state
199
REVERT_REDIR_IF_ANY:
199
REVERT_REDIR_IF_ANY:
200
; is stdout redirected?
200
; is stdout redirected?
201
mov bx, [OLD_STDOUT]
201
mov bx, [OLD_STDOUT]
202
cmp bx, 0xffff
202
cmp bx, 0xffff
203
je STDOUT_DONE
203
je STDOUT_DONE
204
; revert the stdout handle (dst in BX already)
204
; revert the stdout handle (dst in BX already)
205
mov cx, 1        ; src handle (1=stdout)
205
mov cx, 1        ; src handle (1=stdout)
206
mov ah, 0x46     ; redirect a handle
206
mov ah, 0x46     ; redirect a handle
207
int 0x21
207
int 0x21
208
; close the old handle (still in bx)
208
; close the old handle (still in bx)
209
mov ah, 0x3e
209
mov ah, 0x3e
210
int 0x21
210
int 0x21
211
mov [OLD_STDOUT], word 0xffff ; mark stdout as "not redirected"
211
mov [OLD_STDOUT], word 0xffff ; mark stdout as "not redirected"
212
STDOUT_DONE:
212
STDOUT_DONE:
213
 
213
 
214
; is stdin redirected?
214
; is stdin redirected?
215
mov bx, [OLD_STDIN]
215
mov bx, [OLD_STDIN]
216
cmp bx, 0xffff
216
cmp bx, 0xffff
217
je STDIN_DONE
217
je STDIN_DONE
218
; revert the stdin handle (dst in BX already)
218
; revert the stdin handle (dst in BX already)
219
xor cx, cx       ; src handle (0=stdin)
219
xor cx, cx       ; src handle (0=stdin)
220
mov ah, 0x46     ; redirect a handle
220
mov ah, 0x46     ; redirect a handle
221
int 0x21
221
int 0x21
222
; close the old handle (still in bx)
222
; close the old handle (still in bx)
223
mov ah, 0x3e
223
mov ah, 0x3e
224
int 0x21
224
int 0x21
225
mov [OLD_STDIN], word 0xffff ; mark stdin as "not redirected"
225
mov [OLD_STDIN], word 0xffff ; mark stdin as "not redirected"
226
 
226
 
227
; delete stdin file if required
227
; delete stdin file if required
228
cmp [REDIR_DEL_STDIN], byte 0
228
cmp [REDIR_DEL_STDIN], byte 0
229
je STDIN_DONE
229
je STDIN_DONE
230
; revert the original file and delete it
230
; revert the original file and delete it
231
mov ah, [REDIR_DEL_STDIN]
231
mov ah, [REDIR_DEL_STDIN]
232
mov [REDIR_INFIL], ah
232
mov [REDIR_INFIL], ah
233
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
234
mov dx, REDIR_INFIL
234
mov dx, REDIR_INFIL
235
int 0x21
235
int 0x21
236
mov [REDIR_INFIL], byte 0
236
mov [REDIR_INFIL], byte 0
237
mov [REDIR_DEL_STDIN], byte 0
237
mov [REDIR_DEL_STDIN], byte 0
238
 
238
 
239
STDIN_DONE:
239
STDIN_DONE:
240
 
240
 
241
ret
241
ret
242
; ----------------------------------------------------------------------------
242
; ----------------------------------------------------------------------------
243
 
243
 
244
 
244
 
245
; ----------------------------------------------------------------------------
245
; ----------------------------------------------------------------------------
246
; redirect stdout if REDIR_OUTFIL points to something
246
; redirect stdout if REDIR_OUTFIL points to something
247
REDIR_INOUTFILE_IF_REQUIRED:
247
REDIR_INOUTFILE_IF_REQUIRED:
248
cmp [REDIR_OUTFIL], byte 0
248
cmp [REDIR_OUTFIL], byte 0
249
je NO_STDOUT_REDIR
249
je NO_STDOUT_REDIR
250
mov si, REDIR_OUTFIL   ; si = output file
250
mov si, REDIR_OUTFIL   ; si = output file
251
mov ax, 0x6c00         ; Extended Open/Create
251
mov ax, 0x6c00         ; Extended Open/Create
252
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)
253
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)
254
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)
255
int 0x21               ; ax=handle on success (CF clear)
255
int 0x21               ; ax=handle on success (CF clear)
256
mov [REDIR_OUTFIL], byte 0
256
mov [REDIR_OUTFIL], byte 0
257
jc NO_STDOUT_REDIR     ; TODO: abort with an error message instead
257
jc NO_STDOUT_REDIR     ; TODO: abort with an error message instead
258
 
258
 
259
; 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)
260
cmp [REDIR_OUTAPPEND], word 0x11
260
cmp [REDIR_OUTAPPEND], word 0x11
261
jne SKIP_JMPEOF
261
jne SKIP_JMPEOF
262
mov bx, ax
262
mov bx, ax
263
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
264
xor cx, cx
264
xor cx, cx
265
xor dx, dx
265
xor dx, dx
266
int 0x21
266
int 0x21
267
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
268
SKIP_JMPEOF:
268
SKIP_JMPEOF:
269
 
269
 
270
; duplicate current stdout so I can revert it later
270
; duplicate current stdout so I can revert it later
271
push ax                ; save my file handle in stack
271
push ax                ; save my file handle in stack
272
mov ah, 0x45           ; duplicate file handle BX
272
mov ah, 0x45           ; duplicate file handle BX
273
mov bx, 1              ; 1 = stdout
273
mov bx, 1              ; 1 = stdout
274
int 0x21               ; ax=new (duplicated) file handle
274
int 0x21               ; ax=new (duplicated) file handle
275
mov [OLD_STDOUT], ax   ; save the old handle in memory
275
mov [OLD_STDOUT], ax   ; save the old handle in memory
276
 
276
 
277
; redirect stdout to my file
277
; redirect stdout to my file
278
pop bx                 ; dst handle
278
pop bx                 ; dst handle
279
mov cx, 1              ; src handle (1=stdout)
279
mov cx, 1              ; src handle (1=stdout)
280
mov ah, 0x46           ; "redirect a handle"
280
mov ah, 0x46           ; "redirect a handle"
281
int 0x21
281
int 0x21
282
 
282
 
283
; close the original file handle, I no longer need it
283
; close the original file handle, I no longer need it
284
mov ah, 0x3e           ; close a file handle (handle in BX)
284
mov ah, 0x3e           ; close a file handle (handle in BX)
285
int 0x21
285
int 0x21
286
NO_STDOUT_REDIR:
286
NO_STDOUT_REDIR:
287
 
287
 
288
; *** redirect stdin if REDIR_INFIL points to something ***
288
; *** redirect stdin if REDIR_INFIL points to something ***
289
cmp [REDIR_INFIL], byte 0
289
cmp [REDIR_INFIL], byte 0
290
je NO_STDIN_REDIR
290
je NO_STDIN_REDIR
291
mov dx, REDIR_INFIL    ; dx:dx = file
291
mov dx, REDIR_INFIL    ; dx:dx = file
292
mov ax, 0x3d00         ; open file for read
292
mov ax, 0x3d00         ; open file for read
293
int 0x21               ; ax=handle on success (CF clear)
293
int 0x21               ; ax=handle on success (CF clear)
294
mov [REDIR_INFIL], byte 0
294
mov [REDIR_INFIL], byte 0
295
jc NO_STDIN_REDIR      ; TODO: abort with an error message instead
295
jc NO_STDIN_REDIR      ; TODO: abort with an error message instead
296
 
296
 
297
; duplicate current stdin so I can revert it later
297
; duplicate current stdin so I can revert it later
298
push ax                ; save my file handle in stack
298
push ax                ; save my file handle in stack
299
mov ah, 0x45           ; duplicate file handle BX
299
mov ah, 0x45           ; duplicate file handle BX
300
xor bx, bx             ; 0=stdin
300
xor bx, bx             ; 0=stdin
301
int 0x21               ; ax=new (duplicated) file handle
301
int 0x21               ; ax=new (duplicated) file handle
302
mov [OLD_STDIN], ax    ; save the old handle in memory
302
mov [OLD_STDIN], ax    ; save the old handle in memory
303
 
303
 
304
; redirect stdout to my file
304
; redirect stdout to my file
305
pop bx                 ; dst handle
305
pop bx                 ; dst handle
306
xor cx, cx             ; src handle (0=stdin)
306
xor cx, cx             ; src handle (0=stdin)
307
mov ah, 0x46           ; "redirect a handle"
307
mov ah, 0x46           ; "redirect a handle"
308
int 0x21
308
int 0x21
309
 
309
 
310
; close the original file handle, I no longer need it
310
; close the original file handle, I no longer need it
311
mov ah, 0x3e           ; close a file handle (handle in BX)
311
mov ah, 0x3e           ; close a file handle (handle in BX)
312
int 0x21
312
int 0x21
313
NO_STDIN_REDIR:
313
NO_STDIN_REDIR:
314
ret
314
ret
315
; ----------------------------------------------------------------------------
315
; ----------------------------------------------------------------------------
316
 
316