Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

962 lines
21 KiB

page ,132
; SCCSID = @(#)tbatch2.asm 4.2 85/07/22
; SCCSID = @(#)tbatch2.asm 4.2 85/07/22
TITLE Batch processing routines part II
;/*
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1991
; * All Rights Reserved.
; */
;
; Revision History
; ================
;
; M020 SR 08/20/89 Changed GetBatByt to check if we
; already reached EOF before trying
; to read from batchfile. Also fixed
; old bug of ds not being setup on an
; error while reading the batchfile.
;
; M037 SR 11/1/90 Bug #1745 & #3438 fixed. On a GOTO, we
; reseek to the beginning of the
; batchfile. Clear the BatchEOF flag
; to indicate that we are no longer at
; EOF.
;
.xlist
.xcref
include comsw.asm
include dossym.inc
include syscall.inc
include comseg.asm
include comequ.asm
.list
.cref
DATARES SEGMENT PUBLIC BYTE ;AC000;
EXTRN BATCH:WORD
EXTRN Batch_Abort:byte
EXTRN call_batch_flag:byte
EXTRN call_flag:byte
EXTRN IFFlag:BYTE
EXTRN In_Batch:byte
EXTRN Nest:word
EXTRN PIPEFILES:BYTE
EXTRN RETCODE:WORD
EXTRN SINGLECOM:WORD
;;; extrn BatchEOF:byte
extrn EchoFlag:byte
extrn Next_Batch:word
DATARES ENDS
TRANDATA SEGMENT PUBLIC BYTE ;AC000;
EXTRN BADLAB_PTR:WORD
EXTRN BatBufLen:WORD
EXTRN IFTAB:BYTE
EXTRN SYNTMES_PTR:WORD
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
EXTRN arg:byte ; the arg structure!
EXTRN BatBuf:BYTE
EXTRN BatBufEnd:WORD
EXTRN BatBufPos:WORD
EXTRN BATHAND:WORD
EXTRN COMBUF:BYTE
EXTRN DIRBUF:BYTE
EXTRN GOTOLEN:WORD
EXTRN if_not_count:word
EXTRN IFNOTFLAG:BYTE
EXTRN RESSEG:WORD
TRANSPACE ENDS
TRANCODE SEGMENT PUBLIC BYTE
ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
EXTRN cerror:near
EXTRN docom1:near
EXTRN tcommand:near
public $if,iferlev,goto,shift,ifexists,ifnot,forerror,$call
Break <GetBatByt - retrieve a byte from the batch file>
; Get one byte from the batch file and return it in AL. End-of-file returns
; <CR> and ends batch mode. DS must be set to resident segment.
; AH, DX destroyed.
Procedure GETBATBYT,NEAR
ASSUME DS:RESGROUP
SaveReg <BX,CX,DS>
test byte ptr [Batch_Abort],-1
jz @f
jmp BatEOF
@@:
TEST Batch,-1
JnZ @f
jmp BatEOF
@@:
PUSH ES
MOV ES,Batch
ASSUME ES:NOTHING
;M020;
;Check if we have already reached EOF (BatchEOF flag set. Then, we do not
;try to read from the batchfile again.
;
cmp es:BatchEOF,0 ;already reached EOF? ;M020
jz not_eof ;no, read batch file ;M020
jmp At_EOF ;yes, no more reads ;M020
not_eof: ;M020
ADD WORD PTR ES:[BatSeek],1
ADC WORD PTR ES:[BatSeek+2],0
POP ES
;
; See if we have bytes buffered...
;
MOV AX,CS
MOV DS,AX
ASSUME DS:TranGroup
MOV BX,BatBufPos
CMP BX,-1
JNZ UnBuf
;
; There are no bytes in the buffer. Let's try to fill it up.
;
MOV DX,OFFSET TranGROUP:BatBuf
MOV CX,BatBufLen ; max to read.
MOV BX,BatHand
MOV AH,READ
INT 21h ; Get one more byte from batch file
jnc bat_read_ok ;AN022; if no error - continue
invoke get_ext_error_number ;AN022; get the error
push ds ;AN022; save local segment
mov ds,[resseg] ;AN022; get resident segment
assume ds:resgroup ;AN022;
mov dx,ax ;AN022; put error in DX
invoke output_batch_name ;AN022; set up to print the error
pop ds ;AN022;
assume ds:trangroup ;AN022;
invoke std_eprintf ;AN022; print out the error
mov byte ptr combuf+2,end_of_line_in;AN022; terminate the batch line for parsing
mov byte ptr combuf+3,end_of_line_out ;AN022; terminate the batch line for output
;M020;
;Old bug! We jump to BatEof from here without ds=RESGROUP. Probably, this
;error is never hit (and it shouldn't be)
;
mov ds,ResSeg ; ds = RESGROUP ; M020
jmp short bateof ;AN022; terminate the batch file
bat_read_ok: ;AN022;
MOV CX,AX
JCXZ BATEOFDS
MOV BatBufEnd,CX
XOR BX,BX
MOV BatBufPos,BX
;
; Buffered bytes!
;
UnBuf:
MOV AL,BatBuf[BX] ; get next byte
INC BX
CMP BX,BatBufEnd ; beyond end of buffer?
JB SetBufPos
MOV BX,-1
SetBufPos:
MOV BatBufPos,BX
CMP AL,1AH ; ^Z for termination?
jnz GetByteDone
;
;We get here only when we hit an EOF
;
BatEOFDS:
;SR;
; HACK!!! A massive hack being put in here to get batch processing to work
;properly on EOF. Previously, a CR was returned and batch processing turned
;off the moment we hit an EOF. Unfortunately, if the last line had no CR-LF,
;batch processing is turned off before the last line is processed and so
;this line would never be executed.
; To fix this, a new flag BatchEOF has been introduced. This flag is
;set to 4 if there is no CR-LF before the EOF -- this is determined by looking
;at the buffer contents. If there is no LF ( we assume that presence of LF
;indicated a CR-LF combination), then we set BatchEOF to 4 and return a
;fake CR to the caller. This decrements BatchEOF. On the next call to this
;routine, BatchEOF is decremented to 2 and a fake lF is returned. On the
;third call, BatchEOF becomes zero and batch processing is turned off,
;now that the last line has been processed. If the EOF is the first char read into the buffer
;during this call, and there was a CR-LF previously, we are going to fake
;another redundant CR-LF. There is no work-around I can think of.
; I would love to restructure this entire routine and its caller to
;make the flow really easy to understand but I guess this will have to wait.
;
push es
mov es,ResSeg
;SR;
; If we had already set the BatchEOF flag on a previous call (BatchEOF == 2
;or BatchEOF == 1 now), then do not do the LF check.
;
mov es,es:Batch
cmp es:BatchEOF,0
jnz crpresent
inc es:BatchEOF ;match the dec following
mov bx,BatBufEnd
cmp BatBuf[bx-1],0ah ;was a LF present?
je crpresent ;yes, no need to fake it
add es:BatchEOF,3 ;BatchEOF == 4 to fake CR-LF
crpresent:
;;; pop es
ASSUME DS:TranGroup
MOV DS,ResSeg
ASSUME DS:ResGroup
;SR;
; The shift operation is done here to replace the decrement. This is because
;we can jump to this label directly from above when bogus calls are made to
;this routine even after batch processing is turned off. The shift ensures
;maintains the following invariance : 4 -> 2; 2 -> 1 ; 1 -> 0; 0 -> 0. Thus,
;it is used as a decrement and also as a NOP to just fall through on bogus
;calls.
; We turn batch processing off if BatchEOF == 1 or BatchEOF == 0.
;BatchEOF == 1 when we fall through from BatEOFDS and BatchEOF == 0 on a
;direct jump to BATEOF. If BatchEOF == 4, we return a fake CR-LF without
;turning batch processing off.
;
At_EOF: ;new label added ;M020
shr es:BatchEOF,1 ;decrement the flag
jz turn_off ;zero,turn batch off
cmp es:BatchEOF,1
jz ret_lf ;BatchEOF was 2, return LF
;
;BatchEOF == 4, indicates return fake CR now and fake LF next.
;
mov al,0dh ;return fake CR.
pop es
jmp short GetByteDone
ret_lf:
mov al,0ah ;return fake LF
pop es
jmp short GetByteDone
turn_off:
pop es
BATEOF:
invoke BatchOff ;turn batch processing off
CALL BATCLOSE
;;; mov BatchEOF,0 ;make sure BatchEOF = 0
;SR; BugBug
; There is a good reason why this carriage return is being returned here.
;This was part of the old code. Because,
;of the way the caller is structured, a fake CR has to be returned again on
;EOF to ensure the termination of the caller's loop. If echo is on, this
;results in an extra linefeed after the batchfile is run if the last line of
;the batchfile already had a CR-LF.
;NB: Do not confuse this with the faked CR. The fake CR-LF was to mark
;the end-of-line. This CR is to mark the end-of-file.
;
MOV AL,0dH ; If end-of-file, then end of line
test byte ptr [Batch_Abort],-1
mov byte ptr [Batch_Abort],0
jz Cont_Get_Byt
mov di,offset TRANGROUP:COMBUF+2 ; reset pointer to beginning of buffer
xor cx,cx ; zero line length
jmp short GetByteDone
Cont_Get_Byt:
CMP [SINGLECOM],0FFF0H ; See if we need to set SINGLECOM
JNZ GetByteDone
CMP NEST,0 ;G See if we have nested batch files
JNZ GETBYTEDONE ;G Yes - don't exit just yet
MOV [SINGLECOM],-1 ; Cause termination
GetByteDone:
RestoreReg <DS,CX,BX>
return
EndProc GetBatByt
break <$If - conditional execution>
assume ds:trangroup,es:trangroup
IFERRORP:
POP AX
IFERROR:
FORERROR:
MOV DX,OFFSET TRANGROUP:SYNTMES_ptr
JMP CERROR
$IF:
;
; Turn off any pipes in progress.
;
push ds ;AN004; save local DS
mov ds,[resseg] ;AN004; get resident segment
assume ds:resgroup ;AN004;
cmp [PIPEFILES],0 ;AN004; Only turn off if present.
jz IFNoPipe ;AN004; no pipe - continue
invoke PipeDel ;AN004; turn off piping
IFNoPipe: ;AN004;
pop ds ;AN004; get local DS back
assume ds:trangroup ;AN004;
MOV [IFNOTFLAG],0
mov [if_not_count], 0
MOV SI,81H
IFREENT:
invoke SCANOFF
CMP AL,0DH
JZ IFERROR
MOV BP,SI
MOV DI,OFFSET TRANGROUP:IFTAB ; Prepare to search if table
MOV CH,0
IFINDCOM:
MOV SI,BP
MOV CL,[DI]
INC DI
JCXZ IFSTRING
JMP SHORT FIRSTCOMP
IFCOMP:
JNZ IF_DIF ;AC000;
FIRSTCOMP:
LODSB
MOV AH,ES:[DI]
INC DI
CMP AL,AH
JZ IFLP
OR AH,20H ; Try lower case
CMP AL,AH
IFLP:
LOOP IFCOMP
IF_DIF: ;AC000;
LAHF
ADD DI,CX ; Bump to next position without affecting flags
MOV BX,[DI] ; Get handler address
INC DI
INC DI
SAHF
JNZ IFINDCOM
LODSB
CMP AL,0DH
IFERRORJ:
JZ IFERROR
invoke DELIM
JNZ IFINDCOM
invoke SCANOFF
JMP BX
IFNOT:
NOT [IFNOTFLAG]
inc [if_not_count]
JMP IFREENT
;
; We are comparing two strings for equality. First, find the end of the
; first string.
;
IFSTRING:
PUSH SI ; save away pointer for later compare
XOR CX,CX ; count of chars in first string
FIRST_STRING:
LODSB ; get character
CMP AL,0DH ; end of line?
JZ IFERRORP ; yes => error
invoke DELIM ; is it a delimiter?
JZ EQUAL_CHECK ; yes, go find equal sign
INC CX ; remember 1 byte for the length
JMP FIRST_STRING ; go back for more
;
; We have found the end of the first string. Unfortunately, we CANNOT use
; scanoff to find the next token; = is a valid separator and will be skipped
; over.
;
EQUAL_CHECK:
CMP AL,'=' ; is char we have an = sign?
JZ EQUAL_CHECK2 ; yes, go find second one.
CMP AL,0DH ; end of line?
JZ IFERRORPj ;AC004; yes, syntax error
LODSB ; get next char
JMP EQUAL_CHECK
;
; The first = has been found. The next char had better be an = too.
;
EQUAL_CHECK2:
LODSB ; get potential = char
CMP AL,'=' ; is it good?
jnz iferrorpj ; no, error
;
; Find beginning of second string.
;
invoke SCANOFF
CMP AL,0DH
jz iferrorpj
POP DI
;
; DS:SI points to second string
; CX has number of chars in first string
; ES:DI points to first string
;
; Perform compare to elicit match
;
REPE CMPSB
JZ MATCH ; match found!
;
; No match. Let's find out what was wrong. The character that did not match
; has been advanced over. Let's back up to it.
;
DEC SI
;
; If it is EOL, then syntax error
;
CMP BYTE PTR [SI],0DH
JZ IFERRORJ
;
; Advance pointer over remainder of unmatched text to next delimiter
;
SKIPSTRINGEND:
LODSB
NOTMATCH:
CMP AL,0DH
IFERRORJ2:
JZ IFERRORJ
invoke DELIM
JNZ SKIPSTRINGEND
;
; Signal that we did NOT have a match
;
MOV AL,-1
JMP SHORT IFRET
iferrorpj:
jmp iferrorp
;
; The compare succeeded. Was the second string longer than the first? We
; do this by seeing if the next char is a delimiter.
;
MATCH:
LODSB
invoke DELIM
JNZ NOTMATCH ; not same.
XOR AL,AL
JMP SHORT IFRET
IFEXISTS:
ifexist_attr EQU attr_hidden+attr_system
moredelim:
lodsb ; move command line pointer over
invoke delim ; pathname -- have to do it ourselves
jnz moredelim ; 'cause parse_file_descriptor is dumb
mov DX, OFFSET TRANGROUP:dirbuf
trap set_dma
mov BX, 2 ; if(0) [|not](|1) exist[1|2] file(2|3)
add BX, [if_not_count]
mov AX, OFFSET TRANGROUP:arg.argv
invoke argv_calc ; convert arg index to pointer
mov DX, [BX].argpointer ; get pointer to supposed filename
mov CX, ifexist_attr ; filetypes to search for
trap Find_First ; request first match, if any
jc if_ex_c ; carry is how to determine error
xor AL, AL
jmp short ifret
if_ex_c:
mov AL, -1 ; false 'n' fall through...
IFRET:
TEST [IFNOTFLAG],-1
JZ REALTEST
NOT AL
REALTEST:
OR AL,AL
JZ IFTRUE
JMP TCOMMAND
IFTRUE:
invoke SCANOFF
MOV CX,SI
SUB CX,81H
SUB DS:[80H],CL
MOV CL,DS:[80H]
MOV [COMBUF+1],CL
MOV DI,OFFSET TRANGROUP:COMBUF+2
CLD
REP MOVSB
MOV AL,0DH
STOSB
;
; Signal that an IF was done. This prevents the redirections from getting
; lost.
;
PUSH DS
MOV DS,ResSeg
ASSUME DS:RESGROUP
MOV IFFlag,-1
POP DS
ASSUME DS:TRANGROUP
;
; Go do the command
;
JMP DOCOM1
iferrorj3:
jmp iferrorj2
IFERLEV:
MOV BH,10
XOR BL,BL
GETNUMLP:
LODSB
CMP AL,0DH
jz iferrorj3
invoke DELIM
JZ GOTNUM
SUB AL,'0'
XCHG AL,BL
MUL BH
ADD AL,BL
XCHG AL,BL
JMP SHORT GETNUMLP
GOTNUM:
PUSH DS
MOV DS,[RESSEG]
ASSUME DS:RESGROUP
MOV AH,BYTE PTR [RETCODE]
POP DS
ASSUME DS:TRANGROUP
XOR AL,AL
CMP AH,BL
JAE IFRET
DEC AL
JMP SHORT IFRET
break <Shift - advance arguments>
;
; Shift the parameters in the batch structure by 1 and set up the new argument.
; This is a NOP if no batch in progress.
;
Procedure Shift,NEAR
assume ds:trangroup,es:trangroup
MOV DS,[RESSEG]
ASSUME DS:RESGROUP
MOV AX,[BATCH] ; get batch pointer
OR AX,AX ; in batch mode?
retz ; no, done.
MOV ES,AX ; operate in batch segment
MOV DS,AX
ASSUME DS:NOTHING,ES:NOTHING
;
; Now move the batch args down by 1 word
;
MOV DI,BatParm ; point to parm table
LEA SI,[DI+2] ; make source = dest + 2
MOV CX,9 ; move 9 parameters
REP MOVSW ; SHIFT down
;
; If the last parameter (the one not moved) is empty (= -1) then we are done.
; We have copied it into the previous position
;
CMP WORD PTR [DI],-1 ; if last one was not in use then
retz ; No new parm
;
; This last pointer is NOT nul. Get it and scan to find the next argument.
; Assume, first, that there is no next argument
;
MOV SI,[DI]
MOV WORD PTR [DI],-1 ; Assume no parm
;
; The parameters are CR separated. Scan for end of this parm
;
SKIPCRLP:
LODSB
CMP AL,0DH
JNZ SKIPCRLP
;
; We are now pointing at next arg. If it is 0 (end of original line) then we
; are finished. There ARE no more parms and the pointer has been previously
; initialized to indicate it.
;
CMP BYTE PTR [SI],0
retz ; End of parms
MOV [DI],SI ; Pointer to next parm as %9
return
EndProc Shift
;
; Skip delim reads bytes from the batch file until a non-delimiter is seen.
; returns char in AL, carry set -> eof
;
Procedure SkipDelim,NEAR
ASSUME DS:ResGroup,ES:NOTHING
TEST Batch,-1
JZ SkipErr ; batch file empty. OOPS!
CALL GetBatByt ; get a char
invoke Delim ; check for ignoreable chars
JZ SkipDelim ; ignore this char.
clc
return
SkipErr:
stc
return
EndProc SkipDelim
break $Call
; CALL is an internal command that transfers control to a .bat, .exe, or
; .com file. This routine strips the CALL off the command line, sets
; the CALL_FLAG to indicate a call in progress, and returns control to
; DOCOM1 in TCODE to reprocess the command line and execute the file
; being CALLed.
$CALL:
; strip off CALL from command line
ASSUME DS:trangroup,ES:trangroup
push si
push di
push ax
push cx
mov si,offset trangroup:combuf+2
invoke scanoff ;get to first non-delimeter
add si,length_call ;point to char past CALL
mov di,offset trangroup:combuf+2
mov cx,combuflen-length_call ;get length of buffer
rep movsb ;move it
pop cx
pop ax
pop di
pop si
; set call flag to indicate call in progress
push ds
mov ds,[resseg]
ASSUME DS:resgroup,ES:resgroup
mov call_flag, call_in_progress
mov call_batch_flag, call_in_progress
;
; Turn off any pipes in progress.
;
cmp [PIPEFILES],0 ; Only turn off if present.
jz NoPipe
invoke PipeDel
NoPipe:
pop ds
ret
break Goto
GOTO:
assume ds:trangroup,es:trangroup
MOV DS,[RESSEG]
assume ds:resgroup
TEST [BATCH],-1
retz ; If not in batch mode, a nop
XOR DX,DX
PUSH DS
MOV DS,Batch
MOV WORD PTR DS:[BatSeek],DX ; Back to start
MOV WORD PTR DS:[BatSeek+2],DX ; Back to start
;M037
; Clear EOF indicator because we have reseeked to the beginning of the file.
;
mov ds:BatchEOF,0 ; clear eof indicator ;M037
POP DS
GotoOpen:
invoke promptBat
MOV DI,FCB+1 ; Get the label
MOV CX,11
MOV AL,' '
REPNE SCASB
JNZ NOINC
INC CX
NOINC:
SUB CX,11
NEG CX
MOV [GOTOLEN],CX
;
; At beginning of file. Skip to first non-delimiter char
;
CALL SkipDelim
JC BadGoto
CMP AL,':'
JZ CHKLABEL
LABLKLP: ; Look for the label
CALL GETBATBYT
CMP AL,0AH
JNZ LABLKTST
;
; At beginning of line. Skip to first non-delimiter char
;
CALL SkipDelim
JC BadGoto
CMP AL,':'
JZ CHKLABEL
LABLKTST:
TEST [BATCH],-1
JNZ LABLKLP
BadGoto:
CALL BATCLOSE
;SR;
; At this point we are terminating without freeing up any nested batch
;segments i.e if the error occurred within a called batch file. This routine
;will traverse the linked list of batch segments and free all of them.
;
call free_batch ;free up nested batch segments
PUSH CS
POP DS
MOV DX,OFFSET TRANGROUP:BADLAB_ptr
JMP CERROR
;
; Found the :. Skip to first non-delimiter char
;
CHKLABEL:
CALL SkipDelim
JC BadGoto
MOV DI,FCB+1
MOV CX,[GOTOLEN]
JMP SHORT GotByte
NEXTCHRLP:
PUSH CX
CALL GETBATBYT
POP CX
GotByte:
INVOKE TESTKANJ ;AN000; 3/3/KK
JZ NOTKANJ1 ;AN000; 3/3/KK
CMP AL, ES:[DI] ;AN000; 3/3/KK
JNZ LABLKTST ;AN000; 3/3/KK
INC DI ;AN000; 3/3/KK
DEC CX ;AN000; 3/3/KK
JCXZ LABLKTST ;AN000; 3/3/KK
PUSH CX ;AN000; 3/3/KK
CALL GETBATBYT ;AN000; 3/3/KK
POP CX ;AN000; 3/3/KK
CMP AL, ES:[DI] ;AN000; 3/3/KK
JMP SHORT KNEXTLABCHR ;AN000; 3/3/KK
NOTKANJ1: ;AN000; 3/3/KK
OR AL,20H
CMP AL,ES:[DI]
JNZ TRYUPPER
JMP SHORT NEXTLABCHR
TRYUPPER:
SUB AL,20H
CMP AL,ES:[DI]
KNEXTLABCHR: ;AN000; 3/3/KK
JNZ LABLKTST
NEXTLABCHR:
INC DI
LOOP NEXTCHRLP
CALL GETBATBYT
cmp [GOTOLEN],8 ; Is the label atleast 8 chars long?
jge gotocont ; Yes, then the next char doesn't matter
CMP AL,' '
JA LABLKTST
gotocont:
CMP AL,0DH
JZ SKIPLFEED
TONEXTBATLIN:
CALL GETBATBYT
CMP AL,0DH
JNZ TONEXTBATLIN
SKIPLFEED:
CALL GETBATBYT
;SR;
; The BatchEOF flag is set in GetBatByt to indicate that we are faking a
;CR-LF for the last line. On a goto, this flag has to be cleared, because
;BatchEOF == 1 now, after returning a CR-LF. The next call to GetBatByt
;to get the EOF has not been made yet because we encountered the Goto. On
;all other cases, EOF will be hit while trying to read the next line and
;we are fine.
;
push es
mov es,Batch
mov es:BatchEOF,0 ;invalidate fake CR-LF flag
pop es
CALL BatClose
return
Procedure BatClose,NEAR
assume ds:resgroup
MOV BX,CS:[BATHAND]
CMP BX,5
JB CloseReturn
MOV AH,CLOSE
INT 21h
CloseReturn:
mov byte ptr [In_Batch],0 ; reset flag
return
EndProc BatClose
;
; Open the BATCH file, If open fails, AL is drive of batch file (A=1)
; Also, fills internal batch buffer. If access denied, then AX = -1
;
Procedure BatOpen,NEAR
ASSUME DS:RESGROUP,ES:TRANGROUP
PUSH DS
MOV DS,[BATCH]
ASSUME DS:NOTHING
MOV DX,BatFile
MOV AX,OPEN SHL 8
INT 21h ; Open the batch file
JC SETERRDL
MOV DX,WORD PTR DS:[BatSeek]
MOV CX,WORD PTR DS:[BatSeek+2]
POP DS
ASSUME DS:RESGROUP
MOV [BATHAND],AX
MOV BX,AX
MOV AX,LSEEK SHL 8 ; Go to the right spot
INT 21h
MOV BatBufPos,-1 ; nuke batch buffer position
return
SETERRDL:
MOV BX,DX
invoke get_ext_error_number ;AN022; get the extended error
mov dx,ax ;AN022; save extended error in DX
MOV AL,[BX] ; Get drive spec
SUB AL,'@' ; A = 1
POP DS
STC ; SUB mucked over carry
return
EndProc BatOpen
;
;Free_batch : This routine traverses the linked batch segments freeing all
;the batch and FOR segments until all of them are freed. It also restores
;the old state of the EchoFlag.
;
; ENTRY: ds = RESGROUP
;
; EXIT: All batch & FOR segments freed.
; EchoFlag restored to old state before batch process.
;
; REGISTERS AFFECTED: bx, cx
free_batch proc near
assume ds:RESGROUP,es:nothing
push es
mov bx,Next_Batch
or bx,bx
jz fb_ret
ClearBatch:
mov es,bx ; get batch segment
mov bx,es:BatForPtr ; get old FOR segment
cmp bx,0 ; is a FOR in progress
je no_bat_for ; no - don't deallocate
push es ;
mov es,bx ; yes - free it up...
mov ah,DEALLOC ;
int 21h ;
pop es ; restore to batch segment
No_Bat_For:
mov cl,es:BatEchoFlag ; get old echo flag
mov bx,es:BatLast ; get old batch segment
mov ah,DEALLOC ; free it up...
int 21h
mov Batch,bx ; get ready to deallocate next batch
dec nest ; is there another batch file?
jnz ClearBatch ; keep going until no batch file
mov EchoFlag,cl ;restore echo status
mov Batch,0 ;no batch process in progress
fb_ret:
pop es
ret
free_batch endp
TRANCODE ENDS
END