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.
 
 
 
 
 
 

1097 lines
28 KiB

page ,132
; SCCSID = @(#)tbatch.asm 4.5 85/10/01
; SCCSID = @(#)tbatch.asm 4.5 85/10/01
TITLE Batch processing routines
;/*
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1991
; * All Rights Reserved.
; */
;
; Revision History
; ================
;
; M006 SR 07/20/90 Changed BatCom to understand batch
; segments in UMBs. Check only for
; overlap.
; M017 MD 08/10/90 Eliminate extra DEC, to fix bug #1
;
; M037 SR 11/1/90 Bug #1745 & #3438 fixed. Fixed ReadBat
; to check if we have hit EOF on
; batchfile and if so, just clear everything
; and return finishing batch processing.
;
.xlist
.xcref
include comsw.asm
include dossym.inc
include syscall.inc
include comseg.asm
include comequ.asm
include doscntry.inc ;an000;
include version.inc
.list
.cref
DATARES SEGMENT PUBLIC BYTE ;AC000;
EXTRN BATCH:WORD
EXTRN Batch_Abort:byte
EXTRN call_batch_flag:byte
EXTRN ECHOFLAG:BYTE
EXTRN forflag:byte
EXTRN forptr:word
EXTRN IFFlag:BYTE
EXTRN In_Batch:byte
EXTRN LTPA:WORD
EXTRN Nest:word
EXTRN next_batch:word
EXTRN nullflag:byte
EXTRN PIPEFLAG:BYTE
EXTRN RES_TPA:WORD
EXTRN SINGLECOM:WORD
EXTRN SUPPRESS:BYTE ;AC000;
DATARES ENDS
TRANDATA SEGMENT PUBLIC BYTE ;AC000;
EXTRN BADBAT_PTR:WORD
EXTRN Extend_buf_ptr:word ;AC000;
EXTRN Extend_buf_sub:byte ;AN022;
EXTRN msg_disp_class:byte ;AC000;
EXTRN NEEDBAT_PTR:WORD
EXTRN pausemes_ptr:word ;AC000;
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
EXTRN BatBufPos:WORD
EXTRN BATHAND:WORD
EXTRN bwdbuf:byte ;AN022;
EXTRN BYTCNT:WORD
EXTRN COMBUF:BYTE
EXTRN EXECPATH:BYTE
EXTRN ID:BYTE
EXTRN RCH_ADDR:DWORD
EXTRN RESSEG:WORD
EXTRN string_ptr_2:word ;AC000;
EXTRN TPA:WORD
EXTRN TRAN_TPA:WORD
extrn TranSpaceEnd:byte ; M006
TRANSPACE ENDS
TRANCODE SEGMENT PUBLIC BYTE
ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
EXTRN cerror:near
EXTRN tcommand:near
;---------------
TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
extrn arg:byte ; the arg structure!
transpace ends
;---------------
Break <PromptBat - Open or wait for batch file>
;
; Open the batch file. If we cannot find the batch file. If the media is
; changeable, we prompt for the change. Otherwise, we terminate the batch
; file. Leave segment registers alone.
;
Procedure PromptBat,NEAR
ASSUME DS:ResGroup,ES:NOTHING
invoke BATOPEN ; attempt to open batch file
retnc
cmp dx,error_file_not_found ;AN022; Ask for diskette if file not found
jz Bat_Remcheck ;AN022;
cmp dx,error_path_not_found ;AN022; Ask for diskette if path not found
jz Bat_Remcheck ;AN022; Otherwise, issue message and exit
invoke output_batch_name ;AN022; set up batch name in bwdbuf
jmp short BatDie ;AN022;
Bat_Remcheck: ;AN022; Go see if media is removable
CALL [RCH_ADDR] ; DX has error number
JZ AskForBat ; Media is removable
;
; The media is not changeable. Turn everything off.
;
invoke ForOff
invoke PipeOff
MOV IfFlag,AL ; No If in progress.
MOV DX,OFFSET TRANGROUP:BADBAT_ptr
BatDie:
call BatchOff
PUSH CS
POP DS
ASSUME DS:TranGroup
invoke std_eprintf ;AC022; display message
;
; TCOMMAND resets the stack. This is the equivalent of a non-local goto.
;
JMP TCOMMAND ; he cleans off stack
;
; Ask the user to reinsert the batch file
;
ASKFORBAT:
ASSUME DS:ResGroup
PUSH DS
PUSH CS
POP DS
ASSUME DS:TranGroup
MOV DX,OFFSET TRANGROUP:NEEDBAT_ptr ;AN022;
invoke std_eprintf ;Prompt for batch file on stderr
mov dx,offset trangroup:pausemes_ptr ;AN000; get second part of message
invoke std_eprintf ;AN000; print it to stderr
CALL GetKeystroke
POP DS
ASSUME DS:ResGroup
jmp PromptBat
EndProc PromptBat
;****************************************************************
;*
;* ROUTINE: Output_batch_name
;*
;* FUNCTION: Sets up batch name to be printed on extended error
;*
;* INPUT: DX - extended error number
;*
;* OUTPUT: Ready to call print routine
;*
;****************************************************************
public output_batch_name ;AN022;
Output_batch_name proc near ;AN022;
push ds ;AN022; save resident segment
mov ds,[batch] ;AN022; get batch file segment
assume DS:nothing ;AN022;
mov SI,BatFile ;AN022; get offset of batch file
invoke dstrlen ;AN022; get length of string
mov di,offset Trangroup:bwdbuf ;AN022; target for batch name
rep movsb ;AN022; move the name
push cs ;AN022; get local segment
pop ds ;AN022;
assume DS:trangroup ;AN022;
mov extend_buf_ptr,dx ;AN022; put message number in block
mov msg_disp_class,ext_msg_class ;AN022; set up extended error msg class
mov dx,offset TranGroup:Extend_Buf_ptr ;AN022; get extended message pointer
mov string_ptr_2,offset trangroup:bwdbuf ;AN022; point to substitution
mov extend_buf_sub,one_subst ;AN022; set up for one subst
pop ds ;AN022; restore data segment
ret ;AN022; return
Output_batch_name endp ;AN022;
Break <GetKeystroke - get a keystroke and flush queue>
;
; read the next keystroke. Since there may be several characters in the queue
; after the one we ask for (function keys/Kanji), we need to flush the queue
; AFTER waiting.
;
Procedure GetKeyStroke,NEAR
;
; read any character at any mode, interim mode or not.
;
assume ds:trangroup
PUSH DX ;AN000; 3/3/KK
MOV AX,(ECS_call SHL 8) OR GetInterimMode ;AN000; 3/3/KK
INT 21h ;AN000; 3/3/KK
PUSH DX ;AN000; save interim state 3/3/KK
MOV AX,(ECS_call SHL 8) OR SetInterimMode ;AN000; 3/3/KK
MOV DL,InterimMode ;AN000; 3/3/KK
INT 21h ;AN000; 3/3/KK
MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR STD_CON_INPUT_no_echo
INT 21h ; Get character with KB buffer flush
MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0
INT 21h
MOV AX,(ECS_call SHL 8) OR SetInterimMode ;AN000; 3/3/KK
POP DX ;AN000; restore interim state 3/3/KK
INT 21h ;AN000; 3/3/KK
POP DX ;AN000; 3/3/KK
return
EndProc GetKeyStroke
Break <ReadBat - read 1 line from batch file>
;
; ReadBat - read a single line from the batch file. Perform all substitutions
; as appropriate
;
Procedure ReadBat,NEAR
ASSUME DS:ResGroup,ES:TranGroup
mov suppress,yes_echo ;g initialize line suppress status
test byte ptr [Batch_Abort],-1
jnz Trying_To_Abort
mov byte ptr [In_Batch],1 ; set flag to indicate batch job
;
;M037; Start of changes
; We check here if we have set the flag indicating that the batchfile is at
;EOF. In this case, we do not want to continue with the normal processing.
;We call GetBatByt once more so that the batch segment gets freed up, the
;batch file gets closed etc. and then return as if everything is done.
;
push ds
mov ds,Batch
cmp ds:BatchEOF,0 ; are we at EOF in batchfile
pop ds
jz contbat ; no, continue normal processing
invoke GetBatByt ; frees up batchseg
mov es:ComBuf+2,al ; stuff CR into command buffer
; as a dummy command
invoke CrLf2 ; print a CR-LF
return ; done batch processing
contbat:
;
;M037; End of changes
;
CALL PromptBat
Trying_To_Abort:
MOV DI,OFFSET TRANGROUP:COMBUF+2
;
; Save position and try to scan for first non delimiter.
;
TESTNOP:
MOV AX,DS
MOV DS,Batch
ASSUME DS:NOTHING
PUSH WORD PTR DS:[BatSeek]
PUSH WORD PTR DS:[BatSeek+2] ; save current location.
MOV DS,AX
ASSUME DS:ResGroup
invoke SkipDelim ; skip to first non-delim
;
; If the first non-delimiter is not a : (label), we reseek back to the
; beginning and read the line.
;
CMP AL,':' ; is it a label?
POP CX
POP DX ; restore position in bat file
JZ NopLine ; yes, resync everything.
TEST [BATCH],-1 ; are we done with the batch file?
JZ RdBat
CMP AL, NO_ECHO_CHAR ;g see if user wants to suppress line
JNZ SET_BAT_POS ;g no - go and set batch file position
MOV SUPPRESS, NO_ECHO ;g yes set flag to indicate
jmp short Rdbat ;g go read batch file
SET_BAT_POS: ;g
PUSH DS
MOV DS,Batch
ASSUME DS:NOTHING
MOV WORD PTR DS:[BatSeek],DX ; reseek back to beginning
MOV WORD PTR DS:[BatSeek+2],CX
POP DS
ASSUME DS:ResGroup
MOV AX,(LSEEK SHL 8) + 0 ; seek back
INT 21h
MOV BatBufPos,-1 ; nuke batch buffer position
xor cx,cx ; Initialize line length to zero
JMP SHORT RdBat
;
; The first non-delimiter is a :. This line is not echoed and is ignored.
; We eat characters until a CR is seen.
;
NOPLINE:
CALL SkipToEOL
invoke GetBatByt ; eat trailing LF
TEST [BATCH],-1 ; are we done with the batch file?
JNZ TESTNOP ; no, go get another line
return ; Hit EOF
;
; Read a line into the buffer pointed to by ES:DI. If any %s are seen in the
; input, we are to consider two special cases:
;
; %0 to %9 These represent replaceable parameters from the batch segment
; %sym% This is a symbol from the environment
;
RDBAT:
invoke GetBatByt
inc cx ; Inc the line length
invoke testkanj ; MSKK04 07/14/89
jz rdbat1 ;
cmp cx, COMBUFLEN-1 ;
jae TooLong ; can't start DBCS char at last pos'n
stosb ;
invoke GetBatByt ;
inc cx ;
jmp short SAVBATBYT ;
rdbat1: ;
cmp cx,COMBUFLEN ; Is it too long?
jae TooLong ; Yes - handle it, handle it
;
; See if we have a parameter character.
;
CMP AL,'%' ; Check for parameter
JZ NEEDPARM
;
; no parameter character. Store it as usual and see if we are done.
;
SAVBATBYT:
STOSB
CMP AL,0DH ; End of line found?
JNZ RDBAT ; no, go for more
;
; We have read in an entire line. Decide whether we should echo the command
; line or not.
;
Found_EOL:
SUB DI,OFFSET TRANGROUP:COMBUF+3
MOV AX,DI ; remember that we've not counted the CR
MOV ES:[COMBUF+1],AL ; Set length of line
invoke GetBatByt ; Eat linefeed
invoke BATCLOSE
CMP SUPPRESS, NO_ECHO ;G
JZ Reset ;G
test [echoflag],1 ; To echo or not to echo, that is the
jnz try_nextflag
Reset:
PUSH CS ; question. (Profound, huh?)
POP DS ; Go back to local segment
retz ; no echoing here...
;
; Echo the command line with appropriate CRLF...
;
try_nextflag:
cmp nullflag,nullcommand ;G was there a command last time?
jz No_crlf_print ;G no - don't print crlf
invoke CRLF2 ;G Print out prompt
no_crlf_print:
invoke PRINT_PROMPT ;G
PUSH CS ;G change data segment
POP DS ;G
ASSUME DS:TRANGROUP
mov dx,OFFSET TRANGROUP:COMBUF+2 ; get command line for echoing
invoke CRPRINT
invoke CRLF2
return
;
; The line was too long. Eat remainder of input text up until the CR
;
TooLong:
ASSUME DS:ResGroup
cmp al,0dh ; Has the end of the line been reached?
jz Ltlcont ; Yes, continue
CALL SkipToEOL ; Eat remainder of line
Ltlcont:
stosb ; Terminate the command
jmp Found_EOL ; Go process the valid part of the line
;
; We have found a parameter lead-in character. Check for the 0-9 case first
;
NEEDPARM:
invoke GetBatByt ; get next character
CMP AL,'%' ; Check for two consecutive %
JZ SAVBATBYT ; if so, replace with a single %
CMP AL,0Dh ; Check for end-of-line
JZ SAVBATBYT ; yes, treat it normally
;
; We have found %<something>. If the <something> is in the range 0-9, we
; retrieve the appropriate parameter from the batch segment. Otherwise we
; see if the <something> has a terminating % and then look up the contents
; in the environment
;
PAROK:
SUB AL,'0'
JB NEEDENV ; look for parameter in the environment
CMP AL,9
JA NEEDENV
;
; We have found %<number>. This is taken from the parameters in the
; allocated batch area.
;
CBW
MOV BX,AX ; move index into AX
SHL BX,1 ; convert word index into byte ptr
SaveReg <ES>
MOV ES,Batch
;
; The structure of the batch area is:
;
; BYTE type of segment
; DWORD offset for next line
; 10 WORD pointers to parameters. -1 is empty parameter
; ASCIZ file name (with . and ..)
; BYTES CR-terminated parameters
; BYTE 0 flag to indicate end of parameters
;
; Get pointer to BX'th argument
;
MOV SI,ES:BatParm[BX]
RestoreReg <ES>
;
; Is there a parameter here?
;
CMP SI,-1 ; Check if parameter exists
JNZ Yes_there_is ;G Yes go get it
JMP RDBAT ; Ignore if it doesn't
;
; Copy in the found parameter from batch segment
;
Yes_there_is:
PUSH DS
MOV DS,Batch
ASSUME DS:NOTHING
dec cx ; Don't count '%' in line length
CopyParm:
LODSB ; From resident segment
CMP AL,0DH ; Check for end of parameter
JZ EndParam
inc cx ; Inc the line length
cmp cx,COMBUFLEN ; Is it too long?
jae LineTooL ; Yes - handle it, handle it
STOSB
JMP CopyParm
;
; We have copied up to the limit. Stop copying and eat remainder of batch
; line. We need to make sure that the tooLong code isn't fooled into
; believing that we are at EOL. Clobber AL too.
;
LineTooL:
XOR AL,AL
POP DS
ASSUME DS:RESGROUP
JMP TooLong
;
; We have copied in an entire parameter. Go back for more
;
EndParam:
POP DS
JMP RDBat
;
; We have found % followed by something other than 0-9. We presume that there
; will be a following % character. In between is an environment variable that
; we will fetch and replace in the batch line with its value.
;
NEEDENV:
dec cx ;AN070; Don't count "%"
SaveReg <DS,DI>
MOV DI,OFFSET TRANGROUP:ID ; temp spot for name
ADD AL,'0' ; reconvert character
STOSB ; store it in appropriate place
;
; loop getting characters until the next % is found or until EOL
;
GETENV1:
invoke GetBatByt ; get the byte
STOSB ; store it
CMP AL,0Dh ; EOL?
JNZ GETENV15 ; no, see if it the term char
;
; The user entered a string with a % but no trailing %. We copy the string.
;
mov byte ptr es:[di-1],0 ; nul terminate the string
mov si,offset TranGroup:ID ; point to buffer
pop di ; point to line buffer
push cs
pop ds
call StrCpy
jc LineTooL
pop ds
jmp SavBatByt
GETENV15:
CMP AL,'%' ; terminating %?
JNZ GETENV1 ; no, go take out more characters
; M017 - following DEC is wrong, because we replace the % with a = here.
; This was the source of bug #1.
; dec cx ;AN070; Don't count "%"
mov al,'=' ; terminate with =
MOV ES:[DI-1],al
;
; ID now either has a =-terminated string which we are to find in the
; environment or a non =-terminated string which will not be found in the
; environment.
;
GETENV2:
MOV SI,OFFSET TRANGROUP:ID
PUSH CS
POP DS ; DS:SI POINTS TO NAME
ASSUME DS:TRANGROUP
PUSH CX
INVOKE FIND_NAME_IN_environment
ASSUME ES:RESGROUP
POP CX
PUSH ES
POP DS
assume ds:resgroup
PUSH CS
POP ES
ASSUME ES:TRANGROUP
MOV SI,DI
POP DI ; get back pointer to command line
;
; If the parameter was not found, there is no need to perform any replacement.
; We merely pretend that we've copied the parameter.
;
JC GETENV6
;
; ES:DI points to command line being built
; DS:SI points either to nul-terminated environment object AFTER =
;
ASSUME ES:NOTHING
call StrCpy ; (let RdBat handle overflow)
GETENV6:
pop ds
JMP RDBAT ; no, go back to batch file
EndProc ReadBat
;
; SkipToEOL - read from batch file until end of line
;
Procedure SkipToEOL,NEAR
ASSUME DS:ResGroup,ES:NOTHING
TEST Batch,-1
retz ; no batch file in effect
invoke GetBatByt
CMP AL,0Dh ; eol character?
JNZ SkipToEOL ; no, go eat another
return
EndProc SkipToEOL
Break <Allocate and deallocate the transient portion>
;
; Free Transient. Modify ES,AX,flags
;
Procedure Free_TPA,NEAR
ASSUME DS:TRANGROUP,ES:RESGROUP
PUSH ES
MOV ES,[RESSEG]
MOV ES,[RES_TPA]
MOV AH,DEALLOC
INT 21h ; Make lots of free memory
POP ES
return
EndProc Free_TPA
;
; Allocate transient. Modify AX,BX,DX,flags
;
Procedure Alloc_TPA,NEAR
ASSUME DS:TRANGROUP,ES:RESGROUP
PUSH ES
MOV ES,[RESSEG]
MOV BX,0FFFFH ; Re-allocate the transient
MOV AH,ALLOC
INT 21h
PUSH BX ; Save size of block
MOV AH,ALLOC
INT 21h
;
; Attempt to align TPA on 64K boundary
;
POP BX ; Restore size of block
MOV [RES_TPA], AX ; Save segment to beginning of block
MOV [TRAN_TPA], AX
;
; Is the segment already aligned on a 64K boundary
;
MOV DX, AX ; Save segment
AND AX, 0FFFH ; Test if above boundary
JNZ Calc_TPA
MOV AX, DX
AND AX, 0F000H ; Test if multiple of 64K
JNZ NOROUND
Calc_TPA:
MOV AX, DX
AND AX, 0F000H
ADD AX, 01000H ; Round up to next 64K boundary
JC NOROUND ; Memory wrap if carry set
;
; Make sure that new boundary is within allocated range
;
MOV DX, [RES_TPA]
ADD DX, BX ; Compute maximum address
CMP DX, AX ; Is 64K address out of range?
JB NOROUND
;
; Make sure that we won't overwrite the transient
;
MOV BX, CS ; CS is beginning of transient
CMP BX, AX
JB NOROUND
;
; The area from the 64K boundary to the beginning of the transient must
; be at least 64K.
;
SUB BX, AX
CMP BX, 4096 ; Size greater than 64K?
JAE ROUNDDONE
NOROUND:
MOV AX, [RES_TPA]
ROUNDDONE:
MOV [LTPA],AX ; Re-compute everything
MOV [TPA],AX
MOV BX,AX
MOV AX,CS
SUB AX,BX
PUSH BX
MOV BX,16
MUL BX
POP BX
OR DX,DX
JZ SAVSIZ2
MOV AX,-1
SAVSIZ2:
;
; AX is the number of bytes free in the buffer between the resident and the
; transient with a maximum of 64K-1. We round this down to a multiple of 512.
;
CMP AX,512
JBE GotSize
AND AX,0FE00h ; NOT 511 = NOT 1FF
GotSize:
MOV [BYTCNT],AX
POP ES
return
EndProc Alloc_TPA
Break <BatCom - enter a batch file>
;
; The exec search has determined that the user has requested a batch file for
; execution. We parse the arguments, create the batch segment, and signal
; batch processing.
;
Procedure BatCom,NEAR
ASSUME DS:TRANGROUP, ES:NOTHING
;
; Batch parameters are read with ES set to segment of resident part
;
MOV ES,[RESSEG]
ASSUME ES:RESGROUP
cmp es:[call_batch_flag],call_in_progress ;AN043; If in CALL,
jz skip_ioset ;AN043; redirection was already set up
invoke IOSET ; Set up any redirection
skip_ioset: ;AN043;
CALL FREE_TPA ; G
cmp es:[call_batch_flag],call_in_progress ;G
jz getecho ; G if we're in a call, don't execute
;
; Since BATCH has lower precedence than PIPE or FOR. If a new BATCH file is
; being started it MUST be true that no FOR or PIPE is currently in progress.
; Don't execute if in call
;
invoke ForOff
getecho:
invoke PipeOff
mov al,EchoFlag ; preserve echo state for chaining
and al, 1 ; Save current echo state
push ax
xor ax,ax ;G
test es:[batch],-1 ;G Are we in a batch file?
jz leavebat ;G No, nothing to save
mov ax,es:[batch] ;G get current batch segment
cmp es:[call_batch_flag],call_in_progress ;G
jz leavebat ;G
;
; We are in a chained batch file, save batlast from previous batch segment
; so that if we're in a CALL, we will return to the correct batch file.
;
push es ;G
mov es,ax ;G get current batch segment
mov ax,es:[batlast] ;G get previous batch segment
pop es ;G
leavebat: ;G
push ax ;G keep segment until new one created
cmp es:[call_batch_flag],call_in_progress ;G are we in a CALL?
jz startbat ;G Yes, keep current batch segment
call BatchOff ;G No, deallocate old batch segment
;
; Find length of batch file
;
startbat: ;G
ASSUME ES:RESGROUP
MOV es:[CALL_BATCH_FLAG], 0 ;G reset call flag
mov SI, OFFSET TRANGROUP:EXECPATH
mov ax,AppendTruename ;AN042; Get the real path where the batch file
int 2fh ;AN042; was found with APPEND
mov ah,Find_First ;AN042; The find_first will return it
mov dx,si ;AN042; Get the string
mov cx,search_attr ;AN042; filetypes to search for
int 21h ;AN042;
invoke DStrLen
;
; Allocate batch area:
; BYTE type of segment
; WORD segment of last batch file
; WORD segment for FOR command
; BYTE FOR flag state on entry to batch file
; DWORD offset for next line
; 10 WORD pointers to parameters. -1 is empty parameter
; ASCIZ file name (with . and ..)
; BYTES CR-terminated parameters
; BYTE 0 flag to indicate end of parameters
;
; We allocate the maximum size for the command line and use setblock to shrink
; later when we've squeezed out the extra
;
MOV BX,CX ; length of file name.
ADD BX,0Fh + (SIZE BatchSegment) + COMBUFLEN + 0Fh
; structure + max len + round up
SaveReg <CX>
MOV CL,4
SHR BX,CL ; convert to paragraphs
PUSH BX ;G save size of batch segment
MOV AH,ALLOC
INT 21h ; Allocate batch segment
POP BX ;G get size of batch segment
;
; This should *NEVER* return an error. The transient is MUCH bigger than
; the batch segment. This may not be true, however, in a multitasking system.
; G This error will occur with nesting of batch files. We also need to
; G make sure that we don't overlay the transient.
;
jc mem_error ;G not enough memory - exit
push ax ;G save batch segment
add ax,bx ;G get end of batch segment
add ax,20h ;G add some tpa work area
mov bx,cs ;G get the transient segment
;
; M006; We cant check just for above. If the batchseg goes into a UMB, the
; M006; batchseg is always above the transient. We need to change this code
; M006; to only check for an overlap
;
mov dx,offset TRANGROUP:TranSpaceEnd ; M006
add dx,15 ;round up para; M006
shr dx,cl ;para size of transient; M006
add dx,bx ;dx = top of transient; M006
cmp ax,bx ; M006
jb enough_mem ; Batchseg below transient
; enough memory ; M006
cmp ax,dx ; M006
ja enough_mem ; Batchseg above transient
; enough memory ; M006
;
; M006; Batchseg overlaps transient -- insufficient memory
;
pop ax ; restore ax; M006
;M006; cmp ax,bx ;G do we end before the transient
;M006; pop ax ;G get batch segment back
;M006; jb enough_mem ;G we have enough memory - continue
push es ;G no we're hitting the transient
mov es,ax
mov ax,DEALLOC SHL 8 ;G deallocate the batch segment
int 21h
pop es
mem_error:
jmp no_memory ;G Set up for message and exit
enough_mem:
pop ax ; restore ax; M006
MOV [BATCH],AX
CALL ALLOC_TPA
;
; Initialize batch segment
;
RestoreReg <DX> ; length of name
POP AX ;G get saved batch segment back
inc es:nest ;G increment # batch files in progress
PUSH ES
MOV ES,[BATCH]
ASSUME ES:NOTHING
MOV ES:[BatType],BatchType ; signal batch file type
MOV ES:[batlast],ax ;G save segment of last batch file
push DS ;G
mov DS,[resseg] ;G set to resident data
ASSUME DS:RESGROUP
xor ax,ax ;G
mov bl,forflag ;G get the current FOR state
mov ES:[batforflag],bl ;G save it in the batch segment
test bl,-1 ;G are we in a FOR?
jz for_not_on ;G no, for segment set to 0
mov ax,forptr ;G yes, get current FOR segment
mov forflag,0 ;G reset forflag
for_not_on:
mov ES:[batforptr],ax ;G save FOR segment in batch segment
XOR AX,AX
mov forptr,ax ;G make sure for segment is not active
mov bl,echoflag ;G
pop DS ;G
mov byte ptr es:[Batechoflag],bl ;G save echo state of parent
;SR;
; Initialize the new BatchEOF flag we have added to 0
;
mov es:BatchEOF,0
MOV WORD PTR ES:[BatSeek],AX ; point to beginning of file
MOV WORD PTR ES:[BatSeek+2],AX
;
; Initialize pointers
;
DEC AX ; put -1 into AX
MOV DI,BatParm ; point to parm area
MOV BX,DI
MOV CX,10
REP STOSW ; Init to no parms
;
; Move in batch file name
;
MOV CX,DX
rep movsb ; including NUL.
;
; Now copy the command line into batch segment, parsing the arguments along
; the way. Segment will look like this:
;
; <arg0>CR<arg1>CR...<arg9>CR<arg10>CR...<ARGn>CR 0
;
; or, in the case of fewer arguments:
;
; <arg0>CR<arg1>CR...<arg6>CR CR CR ... CR 0
;
MOV SI,OFFSET TRANGROUP:COMBUF+2
MOV CX,10 ; at most 10 arguments
;
; Look for beginning of next argument
;
EACHPARM:
invoke SCANOFF ; skip to argument
;
; AL is first non-delimiter. DS:SI points to char = AL
;
CMP AL,0DH ; end of road?
JZ HAVPARM ; yes, no more arguments
;
; If CX = 0 then we have stored the most parm we can. Skip store
;
JCXZ MOVPARM ; Only first 10 parms get pointers
;
; Go into allocated piece and stick in new argument pointer.
;
MOV ES:[BX],DI ; store batch pointer
ADD BX,2 ; advance arg counter
;
; Move the parameter into batch segment
;
MOVPARM:
LODSB ; get byte
INVOKE DELIM ; if delimiter
JZ ENDPARM ; then done with parm
STOSB ; store byte
CMP AL,0DH ; if CR then not delimiter
JZ HAVPARM ; but end of parm list, finish
JMP SHORT MOVPARM
;
; We have copied a parameter up until the first separator. Terminate it with
; CR
;
ENDPARM:
MOV AL,0DH
STOSB
JCXZ EACHPARM ; if no parameters, don't dec
DEC CX ; remember that we've seen one.
JMP SHORT EACHPARM
;
; We have parsed the entire line. Terminate the arg list
;
HAVPARM:
XOR AL,AL
STOSB ; Nul terminate the parms
;
; Now we know EXACTLY how big the BATCH segment is. Round up size (from DI)
; into paragraphs and setblock to the appropriate size
;
LEA BX,[DI+15]
MOV CL,4
SHR BX,CL
MOV AH,SetBlock
INT 21h
POP ES
ASSUME ES:RESGROUP
PUSH ES
POP DS ; Simply batch FCB setup
ASSUME DS:RESGROUP
CMP [SINGLECOM],-1
JNZ NOBATSING
MOV [SINGLECOM],0FFF0H ; Flag single command BATCH job
NOBATSING:
;
; Enter the batch file with the current echo state
;
pop ax ; Get original echo state
mov echoflag,al ;g restore it
JMP TCOMMAND
;
; The following is executed if there isn't enough memory for batch segment
;
NO_MEMORY:
assume ds:trangroup,es:resgroup
pop dx ;g even up our stack
pop ax ;g
pop ax ;g
call Alloc_tpa ;g reallocate memory
mov msg_disp_class,ext_msg_class ;AN000; set up extended error msg class
mov dx,offset TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer
mov Extend_Buf_ptr,error_not_enough_memory ;AN000; get message number in control block
jmp cerror ;g print error message and go...
EndProc BatCom
Procedure BatchOff
ASSUME DS:NOTHING,ES:NOTHING
SaveReg <AX,ES>
PUSH DS ;G
PUSH BX ;G
MOV ES,ResSeg
MOV DS,ResSeg ;G
ASSUME ES:ResGroup,DS:Resgroup ;G
MOV AX,Batch ; Free the batch segment
OR AX,AX
JZ nofree
PUSH ES
MOV ES,AX
test [echoflag],1 ;G Is echo on?
jnz echo_last_line ;G Yes - echo last line in file
mov suppress,no_echo ;G no - don't echo last line in file
echo_last_line:
MOV BL,ES:[BATECHOFLAG] ;G Get echo state
mov [echoflag],bl ;G and restore it
MOV BX,ES:[BATFORPTR] ;G Get FOR segment
MOV FORPTR,BX ;G and restore it
MOV BL,ES:[BATFORFLAG] ;G Get FOR flag
MOV FORFLAG,BL ;G and restore it
MOV BX,es:[batlast] ;G get old batch segment
MOV AH,DEALLOC
INT 21h
POP ES
MOV Next_BATCH,BX ;G reset batch segment
DEC es:NEST ;G
XOR AX,AX
MOV Batch,AX ; No batch in progress
NoFree:
POP BX ;G
pop ds ;G
RestoreReg <ES,AX>
return
EndProc BatchOff
; StrCpy - copy string, checking count in CX against COMBUFLEN
; Entry : DS:SI ==> source string
; ES:DI ==> destination string
; CX = current length of destination string
; Exit : string copied, CX updated, Carry set if length limit exceeded
Procedure StrCpy,NEAR
push ax
ccycle:
lodsb
inc cx
cmp cx,COMBUFLEN
jb ccopy
stc ; set carry to signal error
jmp short ccend
ccopy:
stosb
or al,al
jnz ccycle
ccend:
dec cx ; discount extra byte
dec di ; back up pointer
pop ax
return ; return carry clear
EndProc StrCpy
TRANCODE ENDS
END