Subversion Repositories SvarDOS

Rev

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

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