Subversion Repositories SvarDOS

Rev

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

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