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.

1096 lines
28 KiB

  1. page ,132
  2. ; SCCSID = @(#)tbatch.asm 4.5 85/10/01
  3. ; SCCSID = @(#)tbatch.asm 4.5 85/10/01
  4. TITLE Batch processing routines
  5. ;/*
  6. ; * Microsoft Confidential
  7. ; * Copyright (C) Microsoft Corporation 1991
  8. ; * All Rights Reserved.
  9. ; */
  10. ;
  11. ; Revision History
  12. ; ================
  13. ;
  14. ; M006 SR 07/20/90 Changed BatCom to understand batch
  15. ; segments in UMBs. Check only for
  16. ; overlap.
  17. ; M017 MD 08/10/90 Eliminate extra DEC, to fix bug #1
  18. ;
  19. ; M037 SR 11/1/90 Bug #1745 & #3438 fixed. Fixed ReadBat
  20. ; to check if we have hit EOF on
  21. ; batchfile and if so, just clear everything
  22. ; and return finishing batch processing.
  23. ;
  24. .xlist
  25. .xcref
  26. include comsw.asm
  27. include dossym.inc
  28. include syscall.inc
  29. include comseg.asm
  30. include comequ.asm
  31. include doscntry.inc ;an000;
  32. include version.inc
  33. .list
  34. .cref
  35. DATARES SEGMENT PUBLIC BYTE ;AC000;
  36. EXTRN BATCH:WORD
  37. EXTRN Batch_Abort:byte
  38. EXTRN call_batch_flag:byte
  39. EXTRN ECHOFLAG:BYTE
  40. EXTRN forflag:byte
  41. EXTRN forptr:word
  42. EXTRN IFFlag:BYTE
  43. EXTRN In_Batch:byte
  44. EXTRN LTPA:WORD
  45. EXTRN Nest:word
  46. EXTRN next_batch:word
  47. EXTRN nullflag:byte
  48. EXTRN PIPEFLAG:BYTE
  49. EXTRN RES_TPA:WORD
  50. EXTRN SINGLECOM:WORD
  51. EXTRN SUPPRESS:BYTE ;AC000;
  52. DATARES ENDS
  53. TRANDATA SEGMENT PUBLIC BYTE ;AC000;
  54. EXTRN BADBAT_PTR:WORD
  55. EXTRN Extend_buf_ptr:word ;AC000;
  56. EXTRN Extend_buf_sub:byte ;AN022;
  57. EXTRN msg_disp_class:byte ;AC000;
  58. EXTRN NEEDBAT_PTR:WORD
  59. EXTRN pausemes_ptr:word ;AC000;
  60. TRANDATA ENDS
  61. TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
  62. EXTRN BatBufPos:WORD
  63. EXTRN BATHAND:WORD
  64. EXTRN bwdbuf:byte ;AN022;
  65. EXTRN BYTCNT:WORD
  66. EXTRN COMBUF:BYTE
  67. EXTRN EXECPATH:BYTE
  68. EXTRN ID:BYTE
  69. EXTRN RCH_ADDR:DWORD
  70. EXTRN RESSEG:WORD
  71. EXTRN string_ptr_2:word ;AC000;
  72. EXTRN TPA:WORD
  73. EXTRN TRAN_TPA:WORD
  74. extrn TranSpaceEnd:byte ; M006
  75. TRANSPACE ENDS
  76. TRANCODE SEGMENT PUBLIC BYTE
  77. ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
  78. EXTRN cerror:near
  79. EXTRN tcommand:near
  80. ;---------------
  81. TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
  82. extrn arg:byte ; the arg structure!
  83. transpace ends
  84. ;---------------
  85. Break <PromptBat - Open or wait for batch file>
  86. ;
  87. ; Open the batch file. If we cannot find the batch file. If the media is
  88. ; changeable, we prompt for the change. Otherwise, we terminate the batch
  89. ; file. Leave segment registers alone.
  90. ;
  91. Procedure PromptBat,NEAR
  92. ASSUME DS:ResGroup,ES:NOTHING
  93. invoke BATOPEN ; attempt to open batch file
  94. retnc
  95. cmp dx,error_file_not_found ;AN022; Ask for diskette if file not found
  96. jz Bat_Remcheck ;AN022;
  97. cmp dx,error_path_not_found ;AN022; Ask for diskette if path not found
  98. jz Bat_Remcheck ;AN022; Otherwise, issue message and exit
  99. invoke output_batch_name ;AN022; set up batch name in bwdbuf
  100. jmp short BatDie ;AN022;
  101. Bat_Remcheck: ;AN022; Go see if media is removable
  102. CALL [RCH_ADDR] ; DX has error number
  103. JZ AskForBat ; Media is removable
  104. ;
  105. ; The media is not changeable. Turn everything off.
  106. ;
  107. invoke ForOff
  108. invoke PipeOff
  109. MOV IfFlag,AL ; No If in progress.
  110. MOV DX,OFFSET TRANGROUP:BADBAT_ptr
  111. BatDie:
  112. call BatchOff
  113. PUSH CS
  114. POP DS
  115. ASSUME DS:TranGroup
  116. invoke std_eprintf ;AC022; display message
  117. ;
  118. ; TCOMMAND resets the stack. This is the equivalent of a non-local goto.
  119. ;
  120. JMP TCOMMAND ; he cleans off stack
  121. ;
  122. ; Ask the user to reinsert the batch file
  123. ;
  124. ASKFORBAT:
  125. ASSUME DS:ResGroup
  126. PUSH DS
  127. PUSH CS
  128. POP DS
  129. ASSUME DS:TranGroup
  130. MOV DX,OFFSET TRANGROUP:NEEDBAT_ptr ;AN022;
  131. invoke std_eprintf ;Prompt for batch file on stderr
  132. mov dx,offset trangroup:pausemes_ptr ;AN000; get second part of message
  133. invoke std_eprintf ;AN000; print it to stderr
  134. CALL GetKeystroke
  135. POP DS
  136. ASSUME DS:ResGroup
  137. jmp PromptBat
  138. EndProc PromptBat
  139. ;****************************************************************
  140. ;*
  141. ;* ROUTINE: Output_batch_name
  142. ;*
  143. ;* FUNCTION: Sets up batch name to be printed on extended error
  144. ;*
  145. ;* INPUT: DX - extended error number
  146. ;*
  147. ;* OUTPUT: Ready to call print routine
  148. ;*
  149. ;****************************************************************
  150. public output_batch_name ;AN022;
  151. Output_batch_name proc near ;AN022;
  152. push ds ;AN022; save resident segment
  153. mov ds,[batch] ;AN022; get batch file segment
  154. assume DS:nothing ;AN022;
  155. mov SI,BatFile ;AN022; get offset of batch file
  156. invoke dstrlen ;AN022; get length of string
  157. mov di,offset Trangroup:bwdbuf ;AN022; target for batch name
  158. rep movsb ;AN022; move the name
  159. push cs ;AN022; get local segment
  160. pop ds ;AN022;
  161. assume DS:trangroup ;AN022;
  162. mov extend_buf_ptr,dx ;AN022; put message number in block
  163. mov msg_disp_class,ext_msg_class ;AN022; set up extended error msg class
  164. mov dx,offset TranGroup:Extend_Buf_ptr ;AN022; get extended message pointer
  165. mov string_ptr_2,offset trangroup:bwdbuf ;AN022; point to substitution
  166. mov extend_buf_sub,one_subst ;AN022; set up for one subst
  167. pop ds ;AN022; restore data segment
  168. ret ;AN022; return
  169. Output_batch_name endp ;AN022;
  170. Break <GetKeystroke - get a keystroke and flush queue>
  171. ;
  172. ; read the next keystroke. Since there may be several characters in the queue
  173. ; after the one we ask for (function keys/Kanji), we need to flush the queue
  174. ; AFTER waiting.
  175. ;
  176. Procedure GetKeyStroke,NEAR
  177. ;
  178. ; read any character at any mode, interim mode or not.
  179. ;
  180. assume ds:trangroup
  181. PUSH DX ;AN000; 3/3/KK
  182. MOV AX,(ECS_call SHL 8) OR GetInterimMode ;AN000; 3/3/KK
  183. INT 21h ;AN000; 3/3/KK
  184. PUSH DX ;AN000; save interim state 3/3/KK
  185. MOV AX,(ECS_call SHL 8) OR SetInterimMode ;AN000; 3/3/KK
  186. MOV DL,InterimMode ;AN000; 3/3/KK
  187. INT 21h ;AN000; 3/3/KK
  188. MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR STD_CON_INPUT_no_echo
  189. INT 21h ; Get character with KB buffer flush
  190. MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0
  191. INT 21h
  192. MOV AX,(ECS_call SHL 8) OR SetInterimMode ;AN000; 3/3/KK
  193. POP DX ;AN000; restore interim state 3/3/KK
  194. INT 21h ;AN000; 3/3/KK
  195. POP DX ;AN000; 3/3/KK
  196. return
  197. EndProc GetKeyStroke
  198. Break <ReadBat - read 1 line from batch file>
  199. ;
  200. ; ReadBat - read a single line from the batch file. Perform all substitutions
  201. ; as appropriate
  202. ;
  203. Procedure ReadBat,NEAR
  204. ASSUME DS:ResGroup,ES:TranGroup
  205. mov suppress,yes_echo ;g initialize line suppress status
  206. test byte ptr [Batch_Abort],-1
  207. jnz Trying_To_Abort
  208. mov byte ptr [In_Batch],1 ; set flag to indicate batch job
  209. ;
  210. ;M037; Start of changes
  211. ; We check here if we have set the flag indicating that the batchfile is at
  212. ;EOF. In this case, we do not want to continue with the normal processing.
  213. ;We call GetBatByt once more so that the batch segment gets freed up, the
  214. ;batch file gets closed etc. and then return as if everything is done.
  215. ;
  216. push ds
  217. mov ds,Batch
  218. cmp ds:BatchEOF,0 ; are we at EOF in batchfile
  219. pop ds
  220. jz contbat ; no, continue normal processing
  221. invoke GetBatByt ; frees up batchseg
  222. mov es:ComBuf+2,al ; stuff CR into command buffer
  223. ; as a dummy command
  224. invoke CrLf2 ; print a CR-LF
  225. return ; done batch processing
  226. contbat:
  227. ;
  228. ;M037; End of changes
  229. ;
  230. CALL PromptBat
  231. Trying_To_Abort:
  232. MOV DI,OFFSET TRANGROUP:COMBUF+2
  233. ;
  234. ; Save position and try to scan for first non delimiter.
  235. ;
  236. TESTNOP:
  237. MOV AX,DS
  238. MOV DS,Batch
  239. ASSUME DS:NOTHING
  240. PUSH WORD PTR DS:[BatSeek]
  241. PUSH WORD PTR DS:[BatSeek+2] ; save current location.
  242. MOV DS,AX
  243. ASSUME DS:ResGroup
  244. invoke SkipDelim ; skip to first non-delim
  245. ;
  246. ; If the first non-delimiter is not a : (label), we reseek back to the
  247. ; beginning and read the line.
  248. ;
  249. CMP AL,':' ; is it a label?
  250. POP CX
  251. POP DX ; restore position in bat file
  252. JZ NopLine ; yes, resync everything.
  253. TEST [BATCH],-1 ; are we done with the batch file?
  254. JZ RdBat
  255. CMP AL, NO_ECHO_CHAR ;g see if user wants to suppress line
  256. JNZ SET_BAT_POS ;g no - go and set batch file position
  257. MOV SUPPRESS, NO_ECHO ;g yes set flag to indicate
  258. jmp short Rdbat ;g go read batch file
  259. SET_BAT_POS: ;g
  260. PUSH DS
  261. MOV DS,Batch
  262. ASSUME DS:NOTHING
  263. MOV WORD PTR DS:[BatSeek],DX ; reseek back to beginning
  264. MOV WORD PTR DS:[BatSeek+2],CX
  265. POP DS
  266. ASSUME DS:ResGroup
  267. MOV AX,(LSEEK SHL 8) + 0 ; seek back
  268. INT 21h
  269. MOV BatBufPos,-1 ; nuke batch buffer position
  270. xor cx,cx ; Initialize line length to zero
  271. JMP SHORT RdBat
  272. ;
  273. ; The first non-delimiter is a :. This line is not echoed and is ignored.
  274. ; We eat characters until a CR is seen.
  275. ;
  276. NOPLINE:
  277. CALL SkipToEOL
  278. invoke GetBatByt ; eat trailing LF
  279. TEST [BATCH],-1 ; are we done with the batch file?
  280. JNZ TESTNOP ; no, go get another line
  281. return ; Hit EOF
  282. ;
  283. ; Read a line into the buffer pointed to by ES:DI. If any %s are seen in the
  284. ; input, we are to consider two special cases:
  285. ;
  286. ; %0 to %9 These represent replaceable parameters from the batch segment
  287. ; %sym% This is a symbol from the environment
  288. ;
  289. RDBAT:
  290. invoke GetBatByt
  291. inc cx ; Inc the line length
  292. invoke testkanj ; MSKK04 07/14/89
  293. jz rdbat1 ;
  294. cmp cx, COMBUFLEN-1 ;
  295. jae TooLong ; can't start DBCS char at last pos'n
  296. stosb ;
  297. invoke GetBatByt ;
  298. inc cx ;
  299. jmp short SAVBATBYT ;
  300. rdbat1: ;
  301. cmp cx,COMBUFLEN ; Is it too long?
  302. jae TooLong ; Yes - handle it, handle it
  303. ;
  304. ; See if we have a parameter character.
  305. ;
  306. CMP AL,'%' ; Check for parameter
  307. JZ NEEDPARM
  308. ;
  309. ; no parameter character. Store it as usual and see if we are done.
  310. ;
  311. SAVBATBYT:
  312. STOSB
  313. CMP AL,0DH ; End of line found?
  314. JNZ RDBAT ; no, go for more
  315. ;
  316. ; We have read in an entire line. Decide whether we should echo the command
  317. ; line or not.
  318. ;
  319. Found_EOL:
  320. SUB DI,OFFSET TRANGROUP:COMBUF+3
  321. MOV AX,DI ; remember that we've not counted the CR
  322. MOV ES:[COMBUF+1],AL ; Set length of line
  323. invoke GetBatByt ; Eat linefeed
  324. invoke BATCLOSE
  325. CMP SUPPRESS, NO_ECHO ;G
  326. JZ Reset ;G
  327. test [echoflag],1 ; To echo or not to echo, that is the
  328. jnz try_nextflag
  329. Reset:
  330. PUSH CS ; question. (Profound, huh?)
  331. POP DS ; Go back to local segment
  332. retz ; no echoing here...
  333. ;
  334. ; Echo the command line with appropriate CRLF...
  335. ;
  336. try_nextflag:
  337. cmp nullflag,nullcommand ;G was there a command last time?
  338. jz No_crlf_print ;G no - don't print crlf
  339. invoke CRLF2 ;G Print out prompt
  340. no_crlf_print:
  341. invoke PRINT_PROMPT ;G
  342. PUSH CS ;G change data segment
  343. POP DS ;G
  344. ASSUME DS:TRANGROUP
  345. mov dx,OFFSET TRANGROUP:COMBUF+2 ; get command line for echoing
  346. invoke CRPRINT
  347. invoke CRLF2
  348. return
  349. ;
  350. ; The line was too long. Eat remainder of input text up until the CR
  351. ;
  352. TooLong:
  353. ASSUME DS:ResGroup
  354. cmp al,0dh ; Has the end of the line been reached?
  355. jz Ltlcont ; Yes, continue
  356. CALL SkipToEOL ; Eat remainder of line
  357. Ltlcont:
  358. stosb ; Terminate the command
  359. jmp Found_EOL ; Go process the valid part of the line
  360. ;
  361. ; We have found a parameter lead-in character. Check for the 0-9 case first
  362. ;
  363. NEEDPARM:
  364. invoke GetBatByt ; get next character
  365. CMP AL,'%' ; Check for two consecutive %
  366. JZ SAVBATBYT ; if so, replace with a single %
  367. CMP AL,0Dh ; Check for end-of-line
  368. JZ SAVBATBYT ; yes, treat it normally
  369. ;
  370. ; We have found %<something>. If the <something> is in the range 0-9, we
  371. ; retrieve the appropriate parameter from the batch segment. Otherwise we
  372. ; see if the <something> has a terminating % and then look up the contents
  373. ; in the environment
  374. ;
  375. PAROK:
  376. SUB AL,'0'
  377. JB NEEDENV ; look for parameter in the environment
  378. CMP AL,9
  379. JA NEEDENV
  380. ;
  381. ; We have found %<number>. This is taken from the parameters in the
  382. ; allocated batch area.
  383. ;
  384. CBW
  385. MOV BX,AX ; move index into AX
  386. SHL BX,1 ; convert word index into byte ptr
  387. SaveReg <ES>
  388. MOV ES,Batch
  389. ;
  390. ; The structure of the batch area is:
  391. ;
  392. ; BYTE type of segment
  393. ; DWORD offset for next line
  394. ; 10 WORD pointers to parameters. -1 is empty parameter
  395. ; ASCIZ file name (with . and ..)
  396. ; BYTES CR-terminated parameters
  397. ; BYTE 0 flag to indicate end of parameters
  398. ;
  399. ; Get pointer to BX'th argument
  400. ;
  401. MOV SI,ES:BatParm[BX]
  402. RestoreReg <ES>
  403. ;
  404. ; Is there a parameter here?
  405. ;
  406. CMP SI,-1 ; Check if parameter exists
  407. JNZ Yes_there_is ;G Yes go get it
  408. JMP RDBAT ; Ignore if it doesn't
  409. ;
  410. ; Copy in the found parameter from batch segment
  411. ;
  412. Yes_there_is:
  413. PUSH DS
  414. MOV DS,Batch
  415. ASSUME DS:NOTHING
  416. dec cx ; Don't count '%' in line length
  417. CopyParm:
  418. LODSB ; From resident segment
  419. CMP AL,0DH ; Check for end of parameter
  420. JZ EndParam
  421. inc cx ; Inc the line length
  422. cmp cx,COMBUFLEN ; Is it too long?
  423. jae LineTooL ; Yes - handle it, handle it
  424. STOSB
  425. JMP CopyParm
  426. ;
  427. ; We have copied up to the limit. Stop copying and eat remainder of batch
  428. ; line. We need to make sure that the tooLong code isn't fooled into
  429. ; believing that we are at EOL. Clobber AL too.
  430. ;
  431. LineTooL:
  432. XOR AL,AL
  433. POP DS
  434. ASSUME DS:RESGROUP
  435. JMP TooLong
  436. ;
  437. ; We have copied in an entire parameter. Go back for more
  438. ;
  439. EndParam:
  440. POP DS
  441. JMP RDBat
  442. ;
  443. ; We have found % followed by something other than 0-9. We presume that there
  444. ; will be a following % character. In between is an environment variable that
  445. ; we will fetch and replace in the batch line with its value.
  446. ;
  447. NEEDENV:
  448. dec cx ;AN070; Don't count "%"
  449. SaveReg <DS,DI>
  450. MOV DI,OFFSET TRANGROUP:ID ; temp spot for name
  451. ADD AL,'0' ; reconvert character
  452. STOSB ; store it in appropriate place
  453. ;
  454. ; loop getting characters until the next % is found or until EOL
  455. ;
  456. GETENV1:
  457. invoke GetBatByt ; get the byte
  458. STOSB ; store it
  459. CMP AL,0Dh ; EOL?
  460. JNZ GETENV15 ; no, see if it the term char
  461. ;
  462. ; The user entered a string with a % but no trailing %. We copy the string.
  463. ;
  464. mov byte ptr es:[di-1],0 ; nul terminate the string
  465. mov si,offset TranGroup:ID ; point to buffer
  466. pop di ; point to line buffer
  467. push cs
  468. pop ds
  469. call StrCpy
  470. jc LineTooL
  471. pop ds
  472. jmp SavBatByt
  473. GETENV15:
  474. CMP AL,'%' ; terminating %?
  475. JNZ GETENV1 ; no, go take out more characters
  476. ; M017 - following DEC is wrong, because we replace the % with a = here.
  477. ; This was the source of bug #1.
  478. ; dec cx ;AN070; Don't count "%"
  479. mov al,'=' ; terminate with =
  480. MOV ES:[DI-1],al
  481. ;
  482. ; ID now either has a =-terminated string which we are to find in the
  483. ; environment or a non =-terminated string which will not be found in the
  484. ; environment.
  485. ;
  486. GETENV2:
  487. MOV SI,OFFSET TRANGROUP:ID
  488. PUSH CS
  489. POP DS ; DS:SI POINTS TO NAME
  490. ASSUME DS:TRANGROUP
  491. PUSH CX
  492. INVOKE FIND_NAME_IN_environment
  493. ASSUME ES:RESGROUP
  494. POP CX
  495. PUSH ES
  496. POP DS
  497. assume ds:resgroup
  498. PUSH CS
  499. POP ES
  500. ASSUME ES:TRANGROUP
  501. MOV SI,DI
  502. POP DI ; get back pointer to command line
  503. ;
  504. ; If the parameter was not found, there is no need to perform any replacement.
  505. ; We merely pretend that we've copied the parameter.
  506. ;
  507. JC GETENV6
  508. ;
  509. ; ES:DI points to command line being built
  510. ; DS:SI points either to nul-terminated environment object AFTER =
  511. ;
  512. ASSUME ES:NOTHING
  513. call StrCpy ; (let RdBat handle overflow)
  514. GETENV6:
  515. pop ds
  516. JMP RDBAT ; no, go back to batch file
  517. EndProc ReadBat
  518. ;
  519. ; SkipToEOL - read from batch file until end of line
  520. ;
  521. Procedure SkipToEOL,NEAR
  522. ASSUME DS:ResGroup,ES:NOTHING
  523. TEST Batch,-1
  524. retz ; no batch file in effect
  525. invoke GetBatByt
  526. CMP AL,0Dh ; eol character?
  527. JNZ SkipToEOL ; no, go eat another
  528. return
  529. EndProc SkipToEOL
  530. Break <Allocate and deallocate the transient portion>
  531. ;
  532. ; Free Transient. Modify ES,AX,flags
  533. ;
  534. Procedure Free_TPA,NEAR
  535. ASSUME DS:TRANGROUP,ES:RESGROUP
  536. PUSH ES
  537. MOV ES,[RESSEG]
  538. MOV ES,[RES_TPA]
  539. MOV AH,DEALLOC
  540. INT 21h ; Make lots of free memory
  541. POP ES
  542. return
  543. EndProc Free_TPA
  544. ;
  545. ; Allocate transient. Modify AX,BX,DX,flags
  546. ;
  547. Procedure Alloc_TPA,NEAR
  548. ASSUME DS:TRANGROUP,ES:RESGROUP
  549. PUSH ES
  550. MOV ES,[RESSEG]
  551. MOV BX,0FFFFH ; Re-allocate the transient
  552. MOV AH,ALLOC
  553. INT 21h
  554. PUSH BX ; Save size of block
  555. MOV AH,ALLOC
  556. INT 21h
  557. ;
  558. ; Attempt to align TPA on 64K boundary
  559. ;
  560. POP BX ; Restore size of block
  561. MOV [RES_TPA], AX ; Save segment to beginning of block
  562. MOV [TRAN_TPA], AX
  563. ;
  564. ; Is the segment already aligned on a 64K boundary
  565. ;
  566. MOV DX, AX ; Save segment
  567. AND AX, 0FFFH ; Test if above boundary
  568. JNZ Calc_TPA
  569. MOV AX, DX
  570. AND AX, 0F000H ; Test if multiple of 64K
  571. JNZ NOROUND
  572. Calc_TPA:
  573. MOV AX, DX
  574. AND AX, 0F000H
  575. ADD AX, 01000H ; Round up to next 64K boundary
  576. JC NOROUND ; Memory wrap if carry set
  577. ;
  578. ; Make sure that new boundary is within allocated range
  579. ;
  580. MOV DX, [RES_TPA]
  581. ADD DX, BX ; Compute maximum address
  582. CMP DX, AX ; Is 64K address out of range?
  583. JB NOROUND
  584. ;
  585. ; Make sure that we won't overwrite the transient
  586. ;
  587. MOV BX, CS ; CS is beginning of transient
  588. CMP BX, AX
  589. JB NOROUND
  590. ;
  591. ; The area from the 64K boundary to the beginning of the transient must
  592. ; be at least 64K.
  593. ;
  594. SUB BX, AX
  595. CMP BX, 4096 ; Size greater than 64K?
  596. JAE ROUNDDONE
  597. NOROUND:
  598. MOV AX, [RES_TPA]
  599. ROUNDDONE:
  600. MOV [LTPA],AX ; Re-compute everything
  601. MOV [TPA],AX
  602. MOV BX,AX
  603. MOV AX,CS
  604. SUB AX,BX
  605. PUSH BX
  606. MOV BX,16
  607. MUL BX
  608. POP BX
  609. OR DX,DX
  610. JZ SAVSIZ2
  611. MOV AX,-1
  612. SAVSIZ2:
  613. ;
  614. ; AX is the number of bytes free in the buffer between the resident and the
  615. ; transient with a maximum of 64K-1. We round this down to a multiple of 512.
  616. ;
  617. CMP AX,512
  618. JBE GotSize
  619. AND AX,0FE00h ; NOT 511 = NOT 1FF
  620. GotSize:
  621. MOV [BYTCNT],AX
  622. POP ES
  623. return
  624. EndProc Alloc_TPA
  625. Break <BatCom - enter a batch file>
  626. ;
  627. ; The exec search has determined that the user has requested a batch file for
  628. ; execution. We parse the arguments, create the batch segment, and signal
  629. ; batch processing.
  630. ;
  631. Procedure BatCom,NEAR
  632. ASSUME DS:TRANGROUP, ES:NOTHING
  633. ;
  634. ; Batch parameters are read with ES set to segment of resident part
  635. ;
  636. MOV ES,[RESSEG]
  637. ASSUME ES:RESGROUP
  638. cmp es:[call_batch_flag],call_in_progress ;AN043; If in CALL,
  639. jz skip_ioset ;AN043; redirection was already set up
  640. invoke IOSET ; Set up any redirection
  641. skip_ioset: ;AN043;
  642. CALL FREE_TPA ; G
  643. cmp es:[call_batch_flag],call_in_progress ;G
  644. jz getecho ; G if we're in a call, don't execute
  645. ;
  646. ; Since BATCH has lower precedence than PIPE or FOR. If a new BATCH file is
  647. ; being started it MUST be true that no FOR or PIPE is currently in progress.
  648. ; Don't execute if in call
  649. ;
  650. invoke ForOff
  651. getecho:
  652. invoke PipeOff
  653. mov al,EchoFlag ; preserve echo state for chaining
  654. and al, 1 ; Save current echo state
  655. push ax
  656. xor ax,ax ;G
  657. test es:[batch],-1 ;G Are we in a batch file?
  658. jz leavebat ;G No, nothing to save
  659. mov ax,es:[batch] ;G get current batch segment
  660. cmp es:[call_batch_flag],call_in_progress ;G
  661. jz leavebat ;G
  662. ;
  663. ; We are in a chained batch file, save batlast from previous batch segment
  664. ; so that if we're in a CALL, we will return to the correct batch file.
  665. ;
  666. push es ;G
  667. mov es,ax ;G get current batch segment
  668. mov ax,es:[batlast] ;G get previous batch segment
  669. pop es ;G
  670. leavebat: ;G
  671. push ax ;G keep segment until new one created
  672. cmp es:[call_batch_flag],call_in_progress ;G are we in a CALL?
  673. jz startbat ;G Yes, keep current batch segment
  674. call BatchOff ;G No, deallocate old batch segment
  675. ;
  676. ; Find length of batch file
  677. ;
  678. startbat: ;G
  679. ASSUME ES:RESGROUP
  680. MOV es:[CALL_BATCH_FLAG], 0 ;G reset call flag
  681. mov SI, OFFSET TRANGROUP:EXECPATH
  682. mov ax,AppendTruename ;AN042; Get the real path where the batch file
  683. int 2fh ;AN042; was found with APPEND
  684. mov ah,Find_First ;AN042; The find_first will return it
  685. mov dx,si ;AN042; Get the string
  686. mov cx,search_attr ;AN042; filetypes to search for
  687. int 21h ;AN042;
  688. invoke DStrLen
  689. ;
  690. ; Allocate batch area:
  691. ; BYTE type of segment
  692. ; WORD segment of last batch file
  693. ; WORD segment for FOR command
  694. ; BYTE FOR flag state on entry to batch file
  695. ; DWORD offset for next line
  696. ; 10 WORD pointers to parameters. -1 is empty parameter
  697. ; ASCIZ file name (with . and ..)
  698. ; BYTES CR-terminated parameters
  699. ; BYTE 0 flag to indicate end of parameters
  700. ;
  701. ; We allocate the maximum size for the command line and use setblock to shrink
  702. ; later when we've squeezed out the extra
  703. ;
  704. MOV BX,CX ; length of file name.
  705. ADD BX,0Fh + (SIZE BatchSegment) + COMBUFLEN + 0Fh
  706. ; structure + max len + round up
  707. SaveReg <CX>
  708. MOV CL,4
  709. SHR BX,CL ; convert to paragraphs
  710. PUSH BX ;G save size of batch segment
  711. MOV AH,ALLOC
  712. INT 21h ; Allocate batch segment
  713. POP BX ;G get size of batch segment
  714. ;
  715. ; This should *NEVER* return an error. The transient is MUCH bigger than
  716. ; the batch segment. This may not be true, however, in a multitasking system.
  717. ; G This error will occur with nesting of batch files. We also need to
  718. ; G make sure that we don't overlay the transient.
  719. ;
  720. jc mem_error ;G not enough memory - exit
  721. push ax ;G save batch segment
  722. add ax,bx ;G get end of batch segment
  723. add ax,20h ;G add some tpa work area
  724. mov bx,cs ;G get the transient segment
  725. ;
  726. ; M006; We cant check just for above. If the batchseg goes into a UMB, the
  727. ; M006; batchseg is always above the transient. We need to change this code
  728. ; M006; to only check for an overlap
  729. ;
  730. mov dx,offset TRANGROUP:TranSpaceEnd ; M006
  731. add dx,15 ;round up para; M006
  732. shr dx,cl ;para size of transient; M006
  733. add dx,bx ;dx = top of transient; M006
  734. cmp ax,bx ; M006
  735. jb enough_mem ; Batchseg below transient
  736. ; enough memory ; M006
  737. cmp ax,dx ; M006
  738. ja enough_mem ; Batchseg above transient
  739. ; enough memory ; M006
  740. ;
  741. ; M006; Batchseg overlaps transient -- insufficient memory
  742. ;
  743. pop ax ; restore ax; M006
  744. ;M006; cmp ax,bx ;G do we end before the transient
  745. ;M006; pop ax ;G get batch segment back
  746. ;M006; jb enough_mem ;G we have enough memory - continue
  747. push es ;G no we're hitting the transient
  748. mov es,ax
  749. mov ax,DEALLOC SHL 8 ;G deallocate the batch segment
  750. int 21h
  751. pop es
  752. mem_error:
  753. jmp no_memory ;G Set up for message and exit
  754. enough_mem:
  755. pop ax ; restore ax; M006
  756. MOV [BATCH],AX
  757. CALL ALLOC_TPA
  758. ;
  759. ; Initialize batch segment
  760. ;
  761. RestoreReg <DX> ; length of name
  762. POP AX ;G get saved batch segment back
  763. inc es:nest ;G increment # batch files in progress
  764. PUSH ES
  765. MOV ES,[BATCH]
  766. ASSUME ES:NOTHING
  767. MOV ES:[BatType],BatchType ; signal batch file type
  768. MOV ES:[batlast],ax ;G save segment of last batch file
  769. push DS ;G
  770. mov DS,[resseg] ;G set to resident data
  771. ASSUME DS:RESGROUP
  772. xor ax,ax ;G
  773. mov bl,forflag ;G get the current FOR state
  774. mov ES:[batforflag],bl ;G save it in the batch segment
  775. test bl,-1 ;G are we in a FOR?
  776. jz for_not_on ;G no, for segment set to 0
  777. mov ax,forptr ;G yes, get current FOR segment
  778. mov forflag,0 ;G reset forflag
  779. for_not_on:
  780. mov ES:[batforptr],ax ;G save FOR segment in batch segment
  781. XOR AX,AX
  782. mov forptr,ax ;G make sure for segment is not active
  783. mov bl,echoflag ;G
  784. pop DS ;G
  785. mov byte ptr es:[Batechoflag],bl ;G save echo state of parent
  786. ;SR;
  787. ; Initialize the new BatchEOF flag we have added to 0
  788. ;
  789. mov es:BatchEOF,0
  790. MOV WORD PTR ES:[BatSeek],AX ; point to beginning of file
  791. MOV WORD PTR ES:[BatSeek+2],AX
  792. ;
  793. ; Initialize pointers
  794. ;
  795. DEC AX ; put -1 into AX
  796. MOV DI,BatParm ; point to parm area
  797. MOV BX,DI
  798. MOV CX,10
  799. REP STOSW ; Init to no parms
  800. ;
  801. ; Move in batch file name
  802. ;
  803. MOV CX,DX
  804. rep movsb ; including NUL.
  805. ;
  806. ; Now copy the command line into batch segment, parsing the arguments along
  807. ; the way. Segment will look like this:
  808. ;
  809. ; <arg0>CR<arg1>CR...<arg9>CR<arg10>CR...<ARGn>CR 0
  810. ;
  811. ; or, in the case of fewer arguments:
  812. ;
  813. ; <arg0>CR<arg1>CR...<arg6>CR CR CR ... CR 0
  814. ;
  815. MOV SI,OFFSET TRANGROUP:COMBUF+2
  816. MOV CX,10 ; at most 10 arguments
  817. ;
  818. ; Look for beginning of next argument
  819. ;
  820. EACHPARM:
  821. invoke SCANOFF ; skip to argument
  822. ;
  823. ; AL is first non-delimiter. DS:SI points to char = AL
  824. ;
  825. CMP AL,0DH ; end of road?
  826. JZ HAVPARM ; yes, no more arguments
  827. ;
  828. ; If CX = 0 then we have stored the most parm we can. Skip store
  829. ;
  830. JCXZ MOVPARM ; Only first 10 parms get pointers
  831. ;
  832. ; Go into allocated piece and stick in new argument pointer.
  833. ;
  834. MOV ES:[BX],DI ; store batch pointer
  835. ADD BX,2 ; advance arg counter
  836. ;
  837. ; Move the parameter into batch segment
  838. ;
  839. MOVPARM:
  840. LODSB ; get byte
  841. INVOKE DELIM ; if delimiter
  842. JZ ENDPARM ; then done with parm
  843. STOSB ; store byte
  844. CMP AL,0DH ; if CR then not delimiter
  845. JZ HAVPARM ; but end of parm list, finish
  846. JMP SHORT MOVPARM
  847. ;
  848. ; We have copied a parameter up until the first separator. Terminate it with
  849. ; CR
  850. ;
  851. ENDPARM:
  852. MOV AL,0DH
  853. STOSB
  854. JCXZ EACHPARM ; if no parameters, don't dec
  855. DEC CX ; remember that we've seen one.
  856. JMP SHORT EACHPARM
  857. ;
  858. ; We have parsed the entire line. Terminate the arg list
  859. ;
  860. HAVPARM:
  861. XOR AL,AL
  862. STOSB ; Nul terminate the parms
  863. ;
  864. ; Now we know EXACTLY how big the BATCH segment is. Round up size (from DI)
  865. ; into paragraphs and setblock to the appropriate size
  866. ;
  867. LEA BX,[DI+15]
  868. MOV CL,4
  869. SHR BX,CL
  870. MOV AH,SetBlock
  871. INT 21h
  872. POP ES
  873. ASSUME ES:RESGROUP
  874. PUSH ES
  875. POP DS ; Simply batch FCB setup
  876. ASSUME DS:RESGROUP
  877. CMP [SINGLECOM],-1
  878. JNZ NOBATSING
  879. MOV [SINGLECOM],0FFF0H ; Flag single command BATCH job
  880. NOBATSING:
  881. ;
  882. ; Enter the batch file with the current echo state
  883. ;
  884. pop ax ; Get original echo state
  885. mov echoflag,al ;g restore it
  886. JMP TCOMMAND
  887. ;
  888. ; The following is executed if there isn't enough memory for batch segment
  889. ;
  890. NO_MEMORY:
  891. assume ds:trangroup,es:resgroup
  892. pop dx ;g even up our stack
  893. pop ax ;g
  894. pop ax ;g
  895. call Alloc_tpa ;g reallocate memory
  896. mov msg_disp_class,ext_msg_class ;AN000; set up extended error msg class
  897. mov dx,offset TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer
  898. mov Extend_Buf_ptr,error_not_enough_memory ;AN000; get message number in control block
  899. jmp cerror ;g print error message and go...
  900. EndProc BatCom
  901. Procedure BatchOff
  902. ASSUME DS:NOTHING,ES:NOTHING
  903. SaveReg <AX,ES>
  904. PUSH DS ;G
  905. PUSH BX ;G
  906. MOV ES,ResSeg
  907. MOV DS,ResSeg ;G
  908. ASSUME ES:ResGroup,DS:Resgroup ;G
  909. MOV AX,Batch ; Free the batch segment
  910. OR AX,AX
  911. JZ nofree
  912. PUSH ES
  913. MOV ES,AX
  914. test [echoflag],1 ;G Is echo on?
  915. jnz echo_last_line ;G Yes - echo last line in file
  916. mov suppress,no_echo ;G no - don't echo last line in file
  917. echo_last_line:
  918. MOV BL,ES:[BATECHOFLAG] ;G Get echo state
  919. mov [echoflag],bl ;G and restore it
  920. MOV BX,ES:[BATFORPTR] ;G Get FOR segment
  921. MOV FORPTR,BX ;G and restore it
  922. MOV BL,ES:[BATFORFLAG] ;G Get FOR flag
  923. MOV FORFLAG,BL ;G and restore it
  924. MOV BX,es:[batlast] ;G get old batch segment
  925. MOV AH,DEALLOC
  926. INT 21h
  927. POP ES
  928. MOV Next_BATCH,BX ;G reset batch segment
  929. DEC es:NEST ;G
  930. XOR AX,AX
  931. MOV Batch,AX ; No batch in progress
  932. NoFree:
  933. POP BX ;G
  934. pop ds ;G
  935. RestoreReg <ES,AX>
  936. return
  937. EndProc BatchOff
  938. ; StrCpy - copy string, checking count in CX against COMBUFLEN
  939. ; Entry : DS:SI ==> source string
  940. ; ES:DI ==> destination string
  941. ; CX = current length of destination string
  942. ; Exit : string copied, CX updated, Carry set if length limit exceeded
  943. Procedure StrCpy,NEAR
  944. push ax
  945. ccycle:
  946. lodsb
  947. inc cx
  948. cmp cx,COMBUFLEN
  949. jb ccopy
  950. stc ; set carry to signal error
  951. jmp short ccend
  952. ccopy:
  953. stosb
  954. or al,al
  955. jnz ccycle
  956. ccend:
  957. dec cx ; discount extra byte
  958. dec di ; back up pointer
  959. pop ax
  960. return ; return carry clear
  961. EndProc StrCpy
  962. TRANCODE ENDS
  963. END
  964.