Subversion Repositories SvarDOS

Rev

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

Rev 987 Rev 1178
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  ; +CEh
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 ; +D0h
44
 
44
 
45
; exit code of last application
45
; exit code of last application
46
LEXCODE  db 0    ; +5Bh
46
LEXCODE  db 0    ; +DFh
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   ; +E0h
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                                     ; +EEh
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     ; +16Eh
61
REDIR_OUTFIL:    times 128 db 0     ; +16Ah
61
REDIR_OUTFIL:    times 128 db 0     ; +1EEh
62
REDIR_OUTAPPEND: dw 0               ; +1EAh
62
REDIR_OUTAPPEND: dw 0               ; +26Eh
63
REDIR_DEL_STDIN: db 0               ; +1ECh  indicates that the stdin file
63
REDIR_DEL_STDIN: db 0               ; +270h  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:            ; +271h
73
stc
73
stc
74
retf
74
retf
75
 
75
 
-
 
76
; INT 0x2E handler
-
 
77
INT2E:
-
 
78
xor ax, ax
-
 
79
iret
76
 
80
 
77
skipsig:                  ; +1EFh
81
skipsig:                  ; +276h
78
 
82
 
79
; set up CS=DS=SS and point SP to my private stack buffer
83
; set up CS=DS=SS and point SP to my private stack buffer
80
mov ax, cs
84
mov ax, cs
81
mov ds, ax
85
mov ds, ax
82
mov es, ax
86
mov es, ax
83
mov ss, ax
87
mov ss, ax
84
mov sp, STACKPTR
88
mov sp, STACKPTR
85
 
89
 
86
; set up myself as break handler
90
; set up myself as break handler (int 0x23)
87
mov ax, 0x2523  ; set int vector 23h
91
mov ax, 0x2523  ; set int vector 23h
88
mov dx, BREAK_HANDLER
92
mov dx, BREAK_HANDLER
89
int 0x21
93
int 0x21
-
 
94
 
-
 
95
; set up myself as int 0x2E handler ("pass command to shell")
-
 
96
mov ax, 0x252E
-
 
97
mov dx, INT2E ; TODO do something meaningful instead of a no-op
-
 
98
int 0x21
90
 
99
 
91
; revert stdin/stdout redirections (if any) to their initial state
100
; revert stdin/stdout redirections (if any) to their initial state
92
call REVERT_REDIR_IF_ANY
101
call REVERT_REDIR_IF_ANY
93
 
102
 
94
; redirect stdin and/or stdout if required
103
; redirect stdin and/or stdout if required
95
call REDIR_INOUTFILE_IF_REQUIRED
104
call REDIR_INOUTFILE_IF_REQUIRED
96
 
105
 
97
; should I executed command.com or a pre-set application?
106
; should I executed command.com or a pre-set application?
98
or [EXECPROG], byte 0
107
or [EXECPROG], byte 0
99
jz EXEC_COMMAND_COM
108
jz EXEC_COMMAND_COM
100
 
109
 
101
; TODO: perhaps I should call the DOS SetPSP function here? But if I do, the
110
; TODO: perhaps I should call the DOS SetPSP function here? But if I do, the
102
;       int 21h, ah=50h call freezes...
111
;       int 21h, ah=50h call freezes...
103
;mov ah, 0x50           ; DOS 2+ -- Set PSP
112
;mov ah, 0x50           ; DOS 2+ -- Set PSP
104
;mov bx, cs
113
;mov bx, cs
105
;int 0x21
114
;int 0x21
106
 
115
 
107
; exec an application preset (by SvarCOM) in the ExecParamRec
116
; exec an application preset (by SvarCOM) in the ExecParamRec
108
mov ax, 0x4B00         ; DOS 2+ - load & execute program
117
mov ax, 0x4B00         ; DOS 2+ - load & execute program
109
mov dx, EXECPROG       ; DS:DX  - ASCIZ program name (preset at PSP[already)
118
mov dx, EXECPROG       ; DS:DX  - ASCIZ program name (preset at PSP[already)
110
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
119
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
111
int 0x21
120
int 0x21
112
mov [cs:EXECPROG], byte 0 ; do not run app again (+DS might have been changed)
121
mov [cs:EXECPROG], byte 0 ; do not run app again (+DS might have been changed)
113
 
122
 
114
jmp short skipsig      ; enforce valid ds/ss/etc (can be lost after int 21,4b)
123
jmp short skipsig      ; enforce valid ds/ss/etc (can be lost after int 21,4b)
115
 
124
 
116
EXEC_COMMAND_COM:
125
EXEC_COMMAND_COM:
117
 
126
 
118
; collect the exit code of previous application
127
; collect the exit code of previous application
119
mov ah, 0x4D
128
mov ah, 0x4D
120
int 0x21
129
int 0x21
121
mov [LEXCODE], al
130
mov [LEXCODE], al
122
 
131
 
123
; zero out the exec param block (14 bytes)
132
; zero out the exec param block (14 bytes)
124
mov al, 0              ; byte to write
133
mov al, 0              ; byte to write
125
mov cx, 14             ; how many times
134
mov cx, 14             ; how many times
126
mov di, EXEC_PARAM_REC ; ES:DI = destination
135
mov di, EXEC_PARAM_REC ; ES:DI = destination
127
cld                    ; stosb must move forward
136
cld                    ; stosb must move forward
128
rep stosb              ; repeat cx times
137
rep stosb              ; repeat cx times
129
 
138
 
130
; preset the default COMSPEC pointer to ES:DX (ES is already set to DS)
139
; preset the default COMSPEC pointer to ES:DX (ES is already set to DS)
131
mov dx, COMSPECBOOT
140
mov dx, COMSPECBOOT
132
 
141
 
133
; do I have a valid COMSPEC?
142
; do I have a valid COMSPEC?
134
or [COMSPECPTR], word 0
143
or [COMSPECPTR], word 0
135
jz USEDEFAULTCOMSPEC
144
jz USEDEFAULTCOMSPEC
136
; set ES:DX to actual COMSPEC (in env segment)
145
; set ES:DX to actual COMSPEC (in env segment)
137
mov es, [PSP_ENVSEG]
146
mov es, [PSP_ENVSEG]
138
mov dx, [COMSPECPTR]
147
mov dx, [COMSPECPTR]
139
USEDEFAULTCOMSPEC:
148
USEDEFAULTCOMSPEC:
140
 
149
 
141
; prepare the exec param block
150
; prepare the exec param block
142
mov ax, [PSP_ENVSEG]
151
mov ax, [PSP_ENVSEG]
143
mov [EXEC_PARAM_REC], ax
152
mov [EXEC_PARAM_REC], ax
144
mov [EXEC_PARAM_REC+2], word CMDTAIL
153
mov [EXEC_PARAM_REC+2], word CMDTAIL
145
mov [EXEC_PARAM_REC+4], cs
154
mov [EXEC_PARAM_REC+4], cs
146
 
155
 
147
; execute command.com
156
; execute command.com
148
mov ax, 0x4B00         ; DOS 2+ - load & execute program
157
mov ax, 0x4B00         ; DOS 2+ - load & execute program
149
push es                ;
158
push es                ;
150
pop ds                 ;
159
pop ds                 ;
151
;mov dx, COMSPEC       ; DS:DX  - ASCIZ program name (preset already)
160
;mov dx, COMSPEC       ; DS:DX  - ASCIZ program name (preset already)
152
push cs
161
push cs
153
pop es
162
pop es
154
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
163
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
155
int 0x21
164
int 0x21
156
 
165
 
157
; if all went well, jump back to start
166
; if all went well, jump back to start
158
jnc skipsig
167
jnc skipsig
159
 
168
 
160
; restore DS=CS
169
; restore DS=CS
161
mov bx, cs
170
mov bx, cs
162
mov ds, bx
171
mov ds, bx
163
 
172
 
164
; update error string so it contains the error number
173
; update error string so it contains the error number
165
add al, '0'
174
add al, '0'
166
mov [ERRLOAD + 4], al
175
mov [ERRLOAD + 4], al
167
 
176
 
168
; display error message
177
; display error message
169
mov ah, 0x09
178
mov ah, 0x09
170
mov dx, ERRLOAD
179
mov dx, ERRLOAD
171
int 0x21
180
int 0x21
172
 
181
 
173
; wait for keypress
182
; wait for keypress
174
mov ah, 0x08
183
mov ah, 0x08
175
int 0x21
184
int 0x21
176
 
185
 
177
; back to program start
186
; back to program start
178
jmp skipsig
187
jmp skipsig
179
 
188
 
180
; command.com tail arguments, in PSP format: length byte followed by args and
189
; 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
190
; 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)
191
; called as respawn (as opposed to being invoked as a normal application)
183
; this allows multiple copies of SvarCOM to stack upon each other.
192
; this allows multiple copies of SvarCOM to stack upon each other.
184
CMDTAIL db 0x01, 0x0A, 0x0D
193
CMDTAIL db 0x01, 0x0A, 0x0D
185
 
194
 
186
ERRLOAD db "ERR x, FAILED TO LOAD COMMAND.COM", 13, 10, '$'
195
ERRLOAD db "ERR x, FAILED TO LOAD COMMAND.COM", 13, 10, '$'
187
 
196
 
188
; variables used to revert stdin/stdout to their initial state
197
; variables used to revert stdin/stdout to their initial state
189
OLD_STDOUT dw 0xffff
198
OLD_STDOUT dw 0xffff
190
OLD_STDIN  dw 0xffff
199
OLD_STDIN  dw 0xffff
191
 
200
 
192
 
201
 
193
; ****************************************************************************
202
; ****************************************************************************
194
; *** ROUTINES ***************************************************************
203
; *** ROUTINES ***************************************************************
195
; ****************************************************************************
204
; ****************************************************************************
196
 
205
 
197
; ----------------------------------------------------------------------------
206
; ----------------------------------------------------------------------------
198
; revert stdin/stdout redirections (if any) to their initial state
207
; revert stdin/stdout redirections (if any) to their initial state
199
REVERT_REDIR_IF_ANY:
208
REVERT_REDIR_IF_ANY:
200
; is stdout redirected?
209
; is stdout redirected?
201
mov bx, [OLD_STDOUT]
210
mov bx, [OLD_STDOUT]
202
cmp bx, 0xffff
211
cmp bx, 0xffff
203
je STDOUT_DONE
212
je STDOUT_DONE
204
; revert the stdout handle (dst in BX already)
213
; revert the stdout handle (dst in BX already)
205
mov cx, 1        ; src handle (1=stdout)
214
mov cx, 1        ; src handle (1=stdout)
206
mov ah, 0x46     ; redirect a handle
215
mov ah, 0x46     ; redirect a handle
207
int 0x21
216
int 0x21
208
; close the old handle (still in bx)
217
; close the old handle (still in bx)
209
mov ah, 0x3e
218
mov ah, 0x3e
210
int 0x21
219
int 0x21
211
mov [OLD_STDOUT], word 0xffff ; mark stdout as "not redirected"
220
mov [OLD_STDOUT], word 0xffff ; mark stdout as "not redirected"
212
STDOUT_DONE:
221
STDOUT_DONE:
213
 
222
 
214
; is stdin redirected?
223
; is stdin redirected?
215
mov bx, [OLD_STDIN]
224
mov bx, [OLD_STDIN]
216
cmp bx, 0xffff
225
cmp bx, 0xffff
217
je STDIN_DONE
226
je STDIN_DONE
218
; revert the stdin handle (dst in BX already)
227
; revert the stdin handle (dst in BX already)
219
xor cx, cx       ; src handle (0=stdin)
228
xor cx, cx       ; src handle (0=stdin)
220
mov ah, 0x46     ; redirect a handle
229
mov ah, 0x46     ; redirect a handle
221
int 0x21
230
int 0x21
222
; close the old handle (still in bx)
231
; close the old handle (still in bx)
223
mov ah, 0x3e
232
mov ah, 0x3e
224
int 0x21
233
int 0x21
225
mov [OLD_STDIN], word 0xffff ; mark stdin as "not redirected"
234
mov [OLD_STDIN], word 0xffff ; mark stdin as "not redirected"
226
 
235
 
227
; delete stdin file if required
236
; delete stdin file if required
228
cmp [REDIR_DEL_STDIN], byte 0
237
cmp [REDIR_DEL_STDIN], byte 0
229
je STDIN_DONE
238
je STDIN_DONE
230
; revert the original file and delete it
239
; revert the original file and delete it
231
mov ah, [REDIR_DEL_STDIN]
240
mov ah, [REDIR_DEL_STDIN]
232
mov [REDIR_INFIL], ah
241
mov [REDIR_INFIL], ah
233
mov ah, 0x41     ; DOS 2+ - delete file pointed at by DS:DX
242
mov ah, 0x41     ; DOS 2+ - delete file pointed at by DS:DX
234
mov dx, REDIR_INFIL
243
mov dx, REDIR_INFIL
235
int 0x21
244
int 0x21
236
mov [REDIR_INFIL], byte 0
245
mov [REDIR_INFIL], byte 0
237
mov [REDIR_DEL_STDIN], byte 0
246
mov [REDIR_DEL_STDIN], byte 0
238
 
247
 
239
STDIN_DONE:
248
STDIN_DONE:
240
 
249
 
241
ret
250
ret
242
; ----------------------------------------------------------------------------
251
; ----------------------------------------------------------------------------
243
 
252
 
244
 
253
 
245
; ----------------------------------------------------------------------------
254
; ----------------------------------------------------------------------------
246
; redirect stdout if REDIR_OUTFIL points to something
255
; redirect stdout if REDIR_OUTFIL points to something
247
REDIR_INOUTFILE_IF_REQUIRED:
256
REDIR_INOUTFILE_IF_REQUIRED:
248
cmp [REDIR_OUTFIL], byte 0
257
cmp [REDIR_OUTFIL], byte 0
249
je NO_STDOUT_REDIR
258
je NO_STDOUT_REDIR
250
mov si, REDIR_OUTFIL   ; si = output file
259
mov si, REDIR_OUTFIL   ; si = output file
251
mov ax, 0x6c00         ; Extended Open/Create
260
mov ax, 0x6c00         ; Extended Open/Create
252
mov bx, 1              ; access mode (0=read, 1=write, 2=r+w)
261
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)
262
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)
263
mov dx, [REDIR_OUTAPPEND] ; action if file exist (0x11=open, 0x12=truncate)
255
int 0x21               ; ax=handle on success (CF clear)
264
int 0x21               ; ax=handle on success (CF clear)
256
mov [REDIR_OUTFIL], byte 0
265
mov [REDIR_OUTFIL], byte 0
257
jc NO_STDOUT_REDIR     ; TODO: abort with an error message instead
266
jc NO_STDOUT_REDIR     ; TODO: abort with an error message instead
258
 
267
 
259
; jump to end of file if flag was 0x11 (required for >> redirections)
268
; jump to end of file if flag was 0x11 (required for >> redirections)
260
cmp [REDIR_OUTAPPEND], word 0x11
269
cmp [REDIR_OUTAPPEND], word 0x11
261
jne SKIP_JMPEOF
270
jne SKIP_JMPEOF
262
mov bx, ax
271
mov bx, ax
263
mov ax, 0x4202         ; jump to position EOF - CX:DX in handle BX
272
mov ax, 0x4202         ; jump to position EOF - CX:DX in handle BX
264
xor cx, cx
273
xor cx, cx
265
xor dx, dx
274
xor dx, dx
266
int 0x21
275
int 0x21
267
mov ax, bx             ; put my handle back in ax, as expected by later code
276
mov ax, bx             ; put my handle back in ax, as expected by later code
268
SKIP_JMPEOF:
277
SKIP_JMPEOF:
269
 
278
 
270
; duplicate current stdout so I can revert it later
279
; duplicate current stdout so I can revert it later
271
push ax                ; save my file handle in stack
280
push ax                ; save my file handle in stack
272
mov ah, 0x45           ; duplicate file handle BX
281
mov ah, 0x45           ; duplicate file handle BX
273
mov bx, 1              ; 1 = stdout
282
mov bx, 1              ; 1 = stdout
274
int 0x21               ; ax=new (duplicated) file handle
283
int 0x21               ; ax=new (duplicated) file handle
275
mov [OLD_STDOUT], ax   ; save the old handle in memory
284
mov [OLD_STDOUT], ax   ; save the old handle in memory
276
 
285
 
277
; redirect stdout to my file
286
; redirect stdout to my file
278
pop bx                 ; dst handle
287
pop bx                 ; dst handle
279
mov cx, 1              ; src handle (1=stdout)
288
mov cx, 1              ; src handle (1=stdout)
280
mov ah, 0x46           ; "redirect a handle"
289
mov ah, 0x46           ; "redirect a handle"
281
int 0x21
290
int 0x21
282
 
291
 
283
; close the original file handle, I no longer need it
292
; close the original file handle, I no longer need it
284
mov ah, 0x3e           ; close a file handle (handle in BX)
293
mov ah, 0x3e           ; close a file handle (handle in BX)
285
int 0x21
294
int 0x21
286
NO_STDOUT_REDIR:
295
NO_STDOUT_REDIR:
287
 
296
 
288
; *** redirect stdin if REDIR_INFIL points to something ***
297
; *** redirect stdin if REDIR_INFIL points to something ***
289
cmp [REDIR_INFIL], byte 0
298
cmp [REDIR_INFIL], byte 0
290
je NO_STDIN_REDIR
299
je NO_STDIN_REDIR
291
mov dx, REDIR_INFIL    ; dx:dx = file
300
mov dx, REDIR_INFIL    ; dx:dx = file
292
mov ax, 0x3d00         ; open file for read
301
mov ax, 0x3d00         ; open file for read
293
int 0x21               ; ax=handle on success (CF clear)
302
int 0x21               ; ax=handle on success (CF clear)
294
mov [REDIR_INFIL], byte 0
303
mov [REDIR_INFIL], byte 0
295
jc NO_STDIN_REDIR      ; TODO: abort with an error message instead
304
jc NO_STDIN_REDIR      ; TODO: abort with an error message instead
296
 
305
 
297
; duplicate current stdin so I can revert it later
306
; duplicate current stdin so I can revert it later
298
push ax                ; save my file handle in stack
307
push ax                ; save my file handle in stack
299
mov ah, 0x45           ; duplicate file handle BX
308
mov ah, 0x45           ; duplicate file handle BX
300
xor bx, bx             ; 0=stdin
309
xor bx, bx             ; 0=stdin
301
int 0x21               ; ax=new (duplicated) file handle
310
int 0x21               ; ax=new (duplicated) file handle
302
mov [OLD_STDIN], ax    ; save the old handle in memory
311
mov [OLD_STDIN], ax    ; save the old handle in memory
303
 
312
 
304
; redirect stdout to my file
313
; redirect stdout to my file
305
pop bx                 ; dst handle
314
pop bx                 ; dst handle
306
xor cx, cx             ; src handle (0=stdin)
315
xor cx, cx             ; src handle (0=stdin)
307
mov ah, 0x46           ; "redirect a handle"
316
mov ah, 0x46           ; "redirect a handle"
308
int 0x21
317
int 0x21
309
 
318
 
310
; close the original file handle, I no longer need it
319
; close the original file handle, I no longer need it
311
mov ah, 0x3e           ; close a file handle (handle in BX)
320
mov ah, 0x3e           ; close a file handle (handle in BX)
312
int 0x21
321
int 0x21
313
NO_STDIN_REDIR:
322
NO_STDIN_REDIR:
314
ret
323
ret
315
; ----------------------------------------------------------------------------
324
; ----------------------------------------------------------------------------
316
 
325