summaryrefslogtreecommitdiff
path: root/v4.0/src/CMD/COMMAND/TBATCH2.ASM
blob: 501c637c89e6774bc91afb50fdec5a7c74554d89 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
 page 80,132
;	SCCSID = @(#)tbatch2.asm	4.2 85/07/22
;	SCCSID = @(#)tbatch2.asm	4.2 85/07/22
TITLE	Batch processing routines part II

	INCLUDE comsw.asm

.xlist
.xcref
	INCLUDE DOSSYM.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
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
	jnz	BatEOF
	TEST	Batch,-1
	JZ	BatEOF
	PUSH	ES
	MOV	ES,Batch
	ASSUME	ES:NOTHING
	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	int_command			; 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
	jmp	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

BatEOFDS:
	ASSUME	DS:TranGroup
	MOV	DS,ResSeg
	ASSUME	DS:ResGroup

BATEOF:
	invoke	BatchOff
	CALL	BATCLOSE
	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	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>
assume	ds:trangroup,es:trangroup

;
; 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

	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
	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
	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
	CALL	BatClose

	return

Procedure   BatClose,NEAR

	MOV	BX,CS:[BATHAND]
	CMP	BX,5
	JB	CloseReturn
	MOV	AH,CLOSE
	INT	int_command

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	int_command			; 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	int_command
	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


TRANCODE    ENDS
	    END