Subversion Repositories SvarDOS

Rev

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

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