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