summaryrefslogtreecommitdiff
path: root/v1.25/source/COMMAND.ASM
diff options
context:
space:
mode:
Diffstat (limited to 'v1.25/source/COMMAND.ASM')
-rw-r--r--v1.25/source/COMMAND.ASM2166
1 files changed, 2166 insertions, 0 deletions
diff --git a/v1.25/source/COMMAND.ASM b/v1.25/source/COMMAND.ASM
new file mode 100644
index 0000000..830bf73
--- /dev/null
+++ b/v1.25/source/COMMAND.ASM
@@ -0,0 +1,2166 @@
1; COMMAND version 1.17
2;
3; This version of COMMAND is divided into three distinct parts. First
4; is the resident portion, which includes handlers for interrupts
5; 22H (terminate), 23H (Cntrl-C), 24H (fatal error), and 27H (stay
6; resident); it also has code to test and, if necessary, reload the
7; transient portion. Following the resident is the init code, which is
8; overwritten after use. Then comes the transient portion, which
9; includes all command processing (whether internal or external).
10; The transient portion loads at the end of physical memory, and it may
11; be overlayed by programs that need as much memory as possible. When
12; the resident portion of command regains control from a user program,
13; a checksum is performed on the transient portion to see if it must be
14; reloaded. Thus programs which do not need maximum memory will save
15; the time required to reload COMMAND when they terminate.
16
17;Use the following booleans to set assembly flags
18FALSE EQU 0
19TRUE EQU NOT FALSE
20
21IBMVER EQU FALSE ;Switch to build IBM version of Command
22MSVER EQU TRUE ;Switch to build MS-DOS version of Command
23
24HIGHMEM EQU TRUE ;Run resident part above transient (high memory)
25
26LINPERPAG EQU 23
27NORMPERLIN EQU 1
28WIDEPERLIN EQU 5
29
30 IF IBMVER
31SYM EQU ">"
32COMDRV EQU 1
33 ENDIF
34
35 IF MSVER
36SYM EQU ":"
37COMDRV EQU 0
38 ENDIF
39
40FCB EQU 5CH
41DSKRESET EQU 13
42SETBASE EQU 38
43SRCHFRST EQU 17
44SRCHNXT EQU 18
45RENAM EQU 23
46INCHAR EQU 1
47GETFAT EQU 27
48OPEN EQU 15
49CLOSE EQU 16
50MAKE EQU 22
51DELETE EQU 19
52RDBLK EQU 39
53WRBLK EQU 40
54SETDMA EQU 26
55SELDRV EQU 14
56GETDRV EQU 25
57PRINTBUF EQU 9
58OUTCH EQU 2
59INBUF EQU 10
60GETDATE EQU 2AH
61SETDATE EQU 2BH
62GETTIME EQU 2CH
63SETTIME EQU 2DH
64RR EQU 33
65RECLEN EQU 14
66FILLEN EQU 16
67OFFDATE EQU 20
68
69
70;The following are all of the segments used in the load order
71
72CODERES SEGMENT
73CODERES ENDS
74
75DATARES SEGMENT BYTE
76DATARES ENDS
77
78INIT SEGMENT BYTE
79INIT ENDS
80
81TAIL SEGMENT PARA
82TAIL ENDS
83
84TRANCODE SEGMENT PARA
85TRANCODE ENDS
86
87TRANDATA SEGMENT BYTE
88TRANDATA ENDS
89
90TRANSPACE SEGMENT BYTE
91TRANSPACE ENDS
92
93RESGROUP GROUP CODERES,DATARES,INIT,TAIL
94TRANGROUP GROUP TRANCODE,TRANDATA,TRANSPACE
95
96;Data for resident portion
97
98DATARES SEGMENT BYTE
99 ORG 0
100ZERO = $
101MESBAS DW OFFSET RESGROUP:ERR0
102 DW OFFSET RESGROUP:ERR2
103 DW OFFSET RESGROUP:ERR4
104 DW OFFSET RESGROUP:ERR6
105 DW OFFSET RESGROUP:ERR8
106 DW OFFSET RESGROUP:ERR10
107 DW OFFSET RESGROUP:ERR12
108ERR0 DB "Write protect$"
109ERR2 DB "Not ready$"
110ERR4 DB "Data$"
111ERR6 DB "Seek$"
112ERR8 DB "Sector not found$"
113ERR10 DB "Write fault$"
114ERR12 DB "Disk$"
115READ DB "read$"
116WRITE DB "writ$"
117ERRMES DB " error "
118IOTYP DB "writing"
119DRVNUM DB " drive "
120DRVLET DB "A"
121NEWLIN DB 13,10,"$"
122REQUEST DB "Abort, Retry, Ignore? $"
123BADFAT DB 13,10,"File allocation table bad,$"
124COMBAD DB 13,10,"Invalid COMMAND.COM"
125NEEDCOM DB 13,10,"Insert DOS disk in "
126 IF IBMVER
127 DB "drive A"
128 ELSE
129 DB "default drive"
130 ENDIF
131PROMPT DB 13,10,"and strike any key when ready",13,10,"$"
132NEEDBAT DB 13,10,"Insert disk with batch file$"
133ENDBATMES DB 13,10,"Terminate batch job (Y/N)? $"
134LOADING DB 0
135BATFCB DB 1,"AUTOEXECBAT"
136 DB 21 DUP(?)
137 DW 0
138 DW 0 ;Initialize RR field to zero
139PARMTAB DW 10 DUP(-1) ;No parameters initially
140BATCH DB 1 ;Assume batch mode initially
141COMFCB DB COMDRV,"COMMAND COM"
142 DB 25 DUP(?)
143TRANS DW OFFSET TRANGROUP:COMMAND
144TRNSEG DW ?
145BATBYT DB ?
146MEMSIZ DW ?
147SUM DW ?
148INITADD DB 4 DUP(?)
149RESDATASIZE EQU $-ZERO
150DATARES ENDS
151
152;Data for transient portion
153
154TRANDATA SEGMENT BYTE
155 ORG 0
156ZERO EQU $
157BADNAM DB "Bad command or file name",13,10,"$"
158MISNAM DB "Missing file name$"
159RENERR DB "Duplicate file name or "
160NOTFND DB "File not found$"
161EXEBAD DB "Error in EXE file$"
162NOSPACE DB "Insufficient disk space",13,10,"$"
163FULDIR DB "File creation error",13,10,"$"
164OVERWR DB "File cannot be copied onto itself",13,10,"$"
165LOSTERR DB "Content of destination lost before copy",13,10,"$"
166COPIED DB " File(s) copied$"
167DIRMES DB " File(s)$"
168TOOBIG DB "Program too big to fit in memory$"
169BADDRV DB "Invalid drive specification$"
170PAUSMES DB "Strike a key when ready . . . $"
171BADSWT DB "Illegal switch",13,10,"$"
172WEEKTAB DB "SunMonTueWedThuFriSat"
173BADDAT DB 13,10,"Invalid date$"
174CURDAT DB "Current date is $"
175NEWDAT DB 13,10,"Enter new date: $"
176BADTIM DB 13,10,"Invalid time$"
177CURTIM DB "Current time is $"
178NEWTIM DB 13,10,"Enter new time: $"
179SUREMES DB "Are you sure (Y/N)? $"
180
181COMTAB DB 4,"DIR",1
182 DW OFFSET TRANGROUP:CATALOG
183 DB 7,"RENAME",1
184 DW OFFSET TRANGROUP:RENAME
185 DB 4,"REN",1
186 DW OFFSET TRANGROUP:RENAME
187 DB 6,"ERASE",1
188 DW OFFSET TRANGROUP:ERASE
189 DB 4,"DEL",1
190 DW OFFSET TRANGROUP:ERASE
191 DB 5,"TYPE",1
192 DW OFFSET TRANGROUP:TYPEFIL
193 DB 4,"REM",1
194 DW OFFSET TRANGROUP:COMMAND
195 DB 5,"COPY",1
196 DW OFFSET TRANGROUP:COPY
197 DB 6,"PAUSE",1
198 DW OFFSET TRANGROUP:PAUSE
199 DB 5,"DATE",0
200 DW OFFSET TRANGROUP:DATE
201 DB 5,"TIME",0
202 DW OFFSET TRANGROUP:TIME
203 DB 0 ;Terminate command table
204
205COMBUF DB 128,1,13
206
207TRANDATASIZE EQU $-ZERO
208TRANDATA ENDS
209
210;Uninitialized transient data
211TRANSPACE SEGMENT BYTE
212 ORG 0
213ZERO = $
214 DB 128 DUP(?)
215TPA DW 1 DUP(?)
216RESSEG DW 1 DUP(?)
217CHKDRV DB 1 DUP(?)
218FILTYP DB 1 DUP(?)
219CURDRV DB 1 DUP(?)
220PARM1 DB 1 DUP(?)
221PARM2 DB 1 DUP(?)
222COMSW DW 1 DUP(?)
223ARG1S DW 1 DUP(?)
224ARG2S DW 1 DUP(?)
225FLAGER DB 1 DUP(?)
226CFLAG DB 1 DUP(?)
227SPECDRV DB 1 DUP(?)
228BYTCNT DW 1 DUP(?)
229NXTADD DW 1 DUP(?)
230LINCNT DB 1 DUP(?)
231LINLEN DB 1 DUP(?)
232FILECNT DW 1 DUP(?)
233EXEFCB LABEL WORD
234IDLEN DB 1 DUP(?)
235ID DB 8 DUP(?)
236COM DB 3 DUP(?)
237DEST DB 37 DUP(?)
238DESTNAME DB 11 DUP(?)
239DIRBUF DB 37 DUP(?)
240BITS DW 1 DUP(?)
241FULLSCR DW 1 DUP(?)
242EXEEND DW 1 DUP(?)
243;Header variables for EXE file load
244;These are overlapped with COPY variables, below
245RUNVAR LABEL WORD
246RELPT DW 1 DUP(?)
247RELSEG DW 1 DUP(?)
248PSIZE LABEL WORD
249PAGES DW 1 DUP(?)
250RELCNT DW 1 DUP(?)
251HEADSIZ DW 1 DUP(?)
252 DW 1 DUP(?)
253LOADLOW DW 1 DUP(?)
254INITSS DW 1 DUP(?)
255INITSP DW 1 DUP(?)
256 DW 1 DUP(?)
257INITIP DW 1 DUP(?)
258INITCS DW 1 DUP(?)
259RELTAB DW 1 DUP(?)
260RUNVARSIZ EQU $-RUNVAR
261
262 DB 80H DUP(?)
263STACK LABEL WORD
264
265PRETRLEN EQU $-ZERO ;Used later to compute TRNLEN
266
267 ORG RUNVAR-ZERO ;Overlaps EXE variables
268
269SRCPT DW 1 DUP(?)
270INEXACT DB 1 DUP(?)
271APPEND DB 1 DUP(?)
272NOWRITE DB 1 DUP(?)
273ASCII DB 1 DUP(?)
274PLUS DB 1 DUP(?)
275SOURCE DB 11 DUP(?)
276TRANSPACESIZE EQU $-ZERO
277TRANSPACE ENDS
278
279
280;START OF RESIDENT PORTION
281
282CODERES SEGMENT
283ASSUME CS:RESGROUP,DS:RESGROUP,ES:RESGROUP,SS:RESGROUP
284 ORG 0
285ZERO = $
286PARMBUF LABEL WORD
287
288 ORG 100H
289
290RSTACK LABEL WORD
291
292PROGSTART:
293 JMP CONPROC
294
295LTPA DW 0 ;WILL STORE TPA SEGMENT HERE
296MYSEG DW 0 ;Put our own segment here
297
298CONTC:
299 MOV AX,CS
300 MOV DS,AX
301 MOV SS,AX
302 MOV SP,OFFSET RESGROUP:RSTACK
303 STI
304 CALL SETVECT
305 MOV AH,DSKRESET
306 INT 33 ;Reset disks in case files were open
307 TEST [BATCH],-1
308 JZ LODCOM
309ASKEND:
310 MOV DX,OFFSET RESGROUP:ENDBATMES
311 MOV AH,PRINTBUF
312 INT 33
313 MOV AX,0C00H+INCHAR
314 INT 33
315 AND AL,5FH
316 CMP AL,"N"
317 JZ LODCOM
318 CMP AL,"Y"
319 JNZ ASKEND
320 MOV [BATCH],0
321LODCOM:
322 MOV AX,CS
323 MOV SS,AX
324 MOV SP,OFFSET RESGROUP:RSTACK
325 MOV DS,AX
326 CALL SETVECT
327 CALL CHKSUM
328 CMP DX,[SUM]
329 JZ HAVCOM
330 MOV [LOADING],1
331 CALL LOADCOM
332CHKSAME:
333 CALL CHKSUM
334 CMP DX,[SUM]
335 JZ HAVCOM
336 CALL WRONGCOM
337 JMP SHORT CHKSAME
338HAVCOM:
339 MOV [LOADING],0
340 MOV SI,OFFSET RESGROUP:LTPA
341 MOV DI,OFFSET TRANGROUP:TPA
342 MOV ES,[TRNSEG]
343 CLD
344 MOVSW ;Move TPA segment to transient storage
345 MOVSW ;Move resident segment too
346 MOV AX,[MEMSIZ]
347 MOV WORD PTR ES:[2],AX
348 JMP DWORD PTR [TRANS]
349
350RESIDENT:
351 ADD DX,15
352 MOV CL,4
353 SHR DX,CL ;Number of paragraphs of new addition
354 ADD CS:[LTPA],DX
355 XOR AX,AX
356 MOV DS,AX
357 JMP DWORD PTR DS:[80H] ;Pretend user executed INT 20H
358
359DSKERR:
360 ;******************************************************
361 ; THIS IS THE DEFAULT DISK ERROR HANDLING CODE
362 ; AVAILABLE TO ALL USERS IF THEY DO NOT TRY TO
363 ; INTERCEPT INTERRUPT 24H.
364 ;******************************************************
365 STI
366 PUSH DS
367 PUSH CS
368 POP DS ;Set up local data segment
369 PUSH DX
370 CALL CRLF
371 POP DX
372 ADD AL,"A" ;Compute drive letter
373 MOV [DRVLET],AL
374 TEST AH,80H ;Check if hard disk error
375 JNZ FATERR
376 MOV SI,OFFSET RESGROUP:READ
377 TEST AH,1
378 JZ SAVMES
379 MOV SI,OFFSET RESGROUP:WRITE
380SAVMES:
381 LODSW
382 MOV WORD PTR [IOTYP],AX
383 LODSW
384 MOV WORD PTR [IOTYP+2],AX
385 AND DI,0FFH
386 CMP DI,12
387 JBE HAVCOD
388 MOV DI,12
389HAVCOD:
390 MOV DI,WORD PTR [DI+MESBAS] ;Get pointer to error message
391 XCHG DI,DX ;May need DX later
392 MOV AH,PRINTBUF
393 INT 33 ;Print error type
394 MOV DX,OFFSET RESGROUP:ERRMES
395 INT 33
396 CMP [LOADING],0
397 JNZ GETCOMDSK
398ASK:
399 MOV DX,OFFSET RESGROUP:REQUEST
400 MOV AH,PRINTBUF
401 INT 33
402 MOV AX,0C00H+INCHAR
403 INT 33 ;Get response
404 CALL CRLF
405 OR AL,20H ;Convert to lower case
406 MOV AH,0 ;Return code for ignore
407 CMP AL,"i" ;Ignore?
408 JZ EXIT
409 INC AH
410 CMP AL,"r" ;Retry?
411 JZ EXIT
412 INC AH
413 CMP AL,"a" ;Abort?
414 JNZ ASK
415EXIT:
416 MOV AL,AH
417 MOV DX,DI
418 POP DS
419 IRET
420
421FATERR:
422 MOV DX,OFFSET RESGROUP:BADFAT
423 MOV AH,PRINTBUF
424 INT 33
425 MOV DX,OFFSET RESGROUP:DRVNUM
426 INT 33
427 MOV AL,2 ;Abort
428 POP DS
429 IRET
430
431GETCOMDSK:
432 MOV DX,OFFSET RESGROUP:NEEDCOM
433 MOV AH,PRINTBUF
434 INT 33
435 MOV AX,0C07H ;Get char without testing or echo
436 INT 33
437 JMP LODCOM
438
439CRLF:
440 MOV DX,OFFSET RESGROUP:NEWLIN
441 PUSH AX
442 MOV AH,PRINTBUF
443 INT 33
444 POP AX
445RET10: RET
446
447LOADCOM:
448 PUSH DS
449 MOV DS,[TRNSEG]
450 MOV DX,100H
451 MOV AH,SETDMA
452 INT 33
453 POP DS
454 MOV DX,OFFSET RESGROUP:COMFCB
455 MOV AH,OPEN
456 INT 33 ;Open COMMAND.COM
457 OR AL,AL
458 JZ READCOM
459 MOV DX,OFFSET RESGROUP:NEEDCOM
460PROMPTCOM:
461 MOV AH,PRINTBUF
462 INT 33
463 MOV AX,0C07H ;Get char without testing or echo
464 INT 33
465 JMP SHORT LOADCOM
466READCOM:
467 MOV WORD PTR[COMFCB+RR],OFFSET RESGROUP:TRANSTART
468 XOR AX,AX
469 MOV WORD PTR[COMFCB+RR+2],AX
470 MOV [COMFCB],AL ;Use default drive
471 INC AX
472 MOV WORD PTR[COMFCB+RECLEN],AX
473 MOV CX,COMLEN
474 MOV DX,OFFSET RESGROUP:COMFCB
475 MOV AH,RDBLK
476 INT 33
477 OR AL,AL
478 JZ RET10
479WRONGCOM:
480 MOV DX,OFFSET RESGROUP:COMBAD
481 JMP SHORT PROMPTCOM
482
483CHKSUM:
484 CLD
485 PUSH DS
486 MOV DS,[TRNSEG]
487 MOV SI,100H
488 MOV CX,COMLEN
489 SHR CX,1
490 XOR DX,DX
491CHK:
492 LODSW
493 ADD DX,AX
494 LOOP CHK
495 POP DS
496 RET
497
498SETVECT:
499 MOV DX,OFFSET RESGROUP:LODCOM
500 MOV AX,2522H ;Set Terminate address
501 INT 21H
502 MOV DX,OFFSET RESGROUP:CONTC
503 MOV AX,2523H ;Set Ctrl-C address
504 INT 21H
505 MOV DX,OFFSET RESGROUP:DSKERR
506 MOV AX,2524H ;Set Hard Disk Error address
507 INT 33
508 MOV DX,OFFSET RESGROUP:RESIDENT
509 MOV AX,2527H ;Set Terminate and Stay Resident address
510 INT 33
511 RET
512RESCODESIZE EQU $-ZERO
513CODERES ENDS
514
515;*******************************************************************
516;START OF INIT PORTION
517;This code is overlayed the first time the TPA is used.
518
519INIT SEGMENT BYTE
520
521 ORG 0
522ZERO = $
523CONPROC:
524 MOV SP,OFFSET RESGROUP:RSTACK
525
526 IF HIGHMEM
527 MOV AX,WORD PTR DS:[2]
528 SUB AX,((RESCODESIZE+RESDATASIZE)+15)/16 ;Subtract size of resident
529 MOV WORD PTR DS:[2],AX
530 MOV ES,AX
531 MOV SI,100H
532 MOV DI,SI
533 MOV CX,((RESCODESIZE+RESDATASIZE)-100H+1)/2 ;Length of resident in words
534 REP MOVSW ;Move to end of memory
535 MOV DS,AX
536 MOV [LTPA],CS
537 ENDIF
538
539 IF NOT HIGHMEM
540 MOV AX,CS
541 ADD AX,((RESCODESIZE+RESDATASIZE)+15)/16 ;Compute segment of TPA
542 MOV [LTPA],AX
543 MOV AX,WORD PTR DS:[2]
544 ENDIF
545
546 MOV [MYSEG],DS
547 MOV [MEMSIZ],AX
548 SUB AX,TRNLEN ;Subtract size of transient
549 MOV [TRNSEG],AX
550 CALL SETVECT
551 CALL LOADCOM
552 CALL CHKSUM
553 MOV [SUM],DX
554
555 IF MSVER
556 IF HIGHMEM
557 PUSH DS
558 PUSH CS
559 POP DS
560 ENDIF
561 MOV DX,OFFSET RESGROUP:HEADER
562 MOV AH,PRINTBUF
563 INT 33
564 IF HIGHMEM
565 POP DS
566 ENDIF
567 ENDIF
568
569 MOV DX,OFFSET RESGROUP:BATFCB
570 MOV AH,OPEN
571 INT 33 ;See if AUTOEXEC.BAT exists
572 MOV WORD PTR[BATFCB+RECLEN],1 ;Set record length to 1
573 OR AL,AL ;Zero means file found
574 JZ DRV0
575 MOV [BATCH],0 ;Not found--turn off batch job
576 MOV AX,OFFSET TRANGROUP:DATINIT
577 MOV WORD PTR[INITADD],AX
578 MOV AX,[TRNSEG]
579 MOV WORD PTR[INITADD+2],AX
580 CALL DWORD PTR DS:[INITADD]
581
582 IF IBMVER
583 MOV DX,OFFSET RESGROUP:HEADER
584 MOV AH,PRINTBUF
585 INT 33
586 ENDIF
587
588DRV0:
589 JMP HAVCOM
590
591
592 IF MSVER
593HEADER DB 13,10,"Command v. 1.17"
594 IF HIGHMEM
595 DB "H"
596 ENDIF
597 DB 13,10,"$"
598 ENDIF
599
600 IF IBMVER
601HEADER DB 13,10,13,10,"The IBM Personal Computer DOS",13,10
602 DB "Version 1.10 (C)Copyright IBM Corp 1981, 1982",13,10,"$"
603 DB "Licensed Material - Program Property of IBM"
604 ENDIF
605
606INITSIZE EQU $-ZERO
607INIT ENDS
608
609;This TAIL segment is used to produce a PARA aligned label in the resident
610; group which is the location where the transient segments will be loaded
611; initialy.
612
613TAIL SEGMENT PARA
614 ORG 0
615TRANSTART LABEL WORD
616TAIL ENDS
617
618;********************************************************************
619;START OF TRANSIENT PORTION
620;This code is loaded at the end of memory and may be overwritten by
621;memory-intensive user programs.
622
623TRANCODE SEGMENT PARA
624ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP,SS:TRANGROUP
625
626WSWITCH EQU 1 ;Wide display during DIR
627PSWITCH EQU 2 ;Pause (or Page) mode during DIR
628VSWITCH EQU 4 ;Verify during COPY
629ASWITCH EQU 8 ;ASCII mode during COPY
630BSWITCH EQU 10H ;Binary mode during COPY
631
632 ORG 0
633ZERO = $
634
635 ORG 100H ;Allow for 100H parameter area
636
637SETDRV:
638 MOV AH,SELDRV
639 INT 21H
640COMMAND:
641 CLD
642 MOV AX,CS
643 MOV SS,AX
644 MOV SP,OFFSET TRANGROUP:STACK
645 MOV ES,AX
646 MOV DS,AX
647 STI
648 MOV AX,46*100H
649 MOV DL,0
650 INT 33 ;Turn off verify after write
651 MOV AX,CS ;Get segment we're in
652 SUB AX,[TPA] ;AX=size ot TPA in paragraphs
653 MOV DX,16
654 MUL DX ;DX:AX=size of TPA in bytes
655 OR DX,DX ;See if over 64K
656 JZ SAVSIZ ;OK if not
657 MOV AX,-1 ;If so, limit to 65535 bytes
658SAVSIZ:
659 MOV [BYTCNT],AX ;Max no. of bytes that can be buffered
660 CALL CRLF2
661GETCOM:
662 MOV AH,GETDRV
663 INT 21H
664 MOV [CURDRV],AL
665 ADD AL,"A"
666 CALL OUT ;Print letter for default drive
667 MOV AL,SYM
668 CALL OUT
669 MOV DS,[RESSEG] ;All batch work must use resident seg.
670ASSUME DS:RESGROUP
671 TEST [BATCH],-1
672 JNZ READBAT
673 PUSH CS
674 POP DS ;Need local segment to point to buffer
675ASSUME DS:TRANGROUP
676 MOV DX,OFFSET TRANGROUP:COMBUF
677 MOV AH,INBUF
678 INT 21H ;Get a command
679 JMP DOCOM
680
681;All batch proccessing has DS set to segment of resident portion
682ASSUME DS:RESGROUP
683NEEDPARM:
684 CALL GETBATBYT
685 CMP AL,"%" ;Check for two consecutive %
686 JZ SAVBATBYT
687 CMP AL,13 ;Check for end-of-line
688 JZ SAVBATBYT
689 SUB AL,"0"
690 JB RDBAT ;Ignore parameter reference if invalid
691 CMP AL,9
692 JA RDBAT
693 CBW
694 MOV SI,AX
695 SHL SI,1 ;Two bytes per entry
696 MOV SI,[SI+OFFSET RESGROUP:PARMTAB] ;Get pointer to corresponding parameter
697 CMP SI,-1 ;Check if parameter exists
698 JZ RDBAT ;Ignore if it doesn't
699 MOV AH,OUTCH
700RDPARM:
701 LODSB ;From resident segment
702 CMP AL,0DH ;Check for end of parameter
703 JZ RDBAT
704 STOSB ;To transient segment
705 MOV DL,AL
706 INT 33 ;Display paramters too
707 JMP SHORT RDPARM
708
709PROMPTBAT:
710 MOV AH,PRINTBUF
711 MOV DX,OFFSET RESGROUP:NEEDBAT
712 INT 33 ;Prompt for batch file
713 MOV AH,PRINTBUF
714 MOV DX,OFFSET RESGROUP:PROMPT
715 INT 33
716 MOV AX,0C00H+INCHAR
717 INT 33
718 JMP COMMAND
719
720BADCOMJ1:JMP BADCOM
721
722READBAT:
723 MOV DX,OFFSET RESGROUP:BATFCB
724 MOV AH,OPEN
725 INT 33 ;Make sure batch file still exists
726 OR AL,AL
727 JNZ PROMPTBAT ;If OPEN fails, prompt for disk
728 MOV WORD PTR [BATFCB+RECLEN],1
729 MOV DX,OFFSET RESGROUP:BATBYT
730 MOV AH,SETDMA
731 INT 33
732 MOV DI,OFFSET TRANGROUP:COMBUF+2
733RDBAT:
734 CALL GETBATBYT
735 CMP AL,"%" ;Check for parameter
736 JZ NEEDPARM
737SAVBATBYT:
738 STOSB
739 CALL OUT ;Display batched command line
740 CMP AL,0DH
741 JNZ RDBAT
742 SUB DI,OFFSET TRANGROUP:COMBUF+3
743 MOV AX,DI
744 MOV ES:[COMBUF+1],AL ;Set length of line
745 CALL GETBATBYT ;Eat linefeed
746 PUSH CS
747 POP DS ;Go back to local segment
748ASSUME DS:TRANGROUP
749DOCOM:
750;All segments are local for command line processing
751 MOV AL,10
752 CALL OUT
753 MOV SI,OFFSET TRANGROUP:COMBUF+2
754 MOV DI,OFFSET TRANGROUP:IDLEN
755 MOV AX,2901H ;Make FCB with blank scan-off
756 INT 21H
757 CMP AL,1 ;Check for ambiguous command name
758 JZ BADCOMJ1 ;Ambiguous commands not allowed
759 CMP AL,-1
760 JNZ DRVGD
761 JMP DRVBAD
762DRVGD:
763 MOV AL,[DI]
764 MOV [SPECDRV],AL
765 MOV AL," "
766 MOV CX,9
767 INC DI
768 REPNE SCASB ;Count no. of letters in command name
769 MOV AL,9
770 SUB AL,CL
771 MOV [IDLEN],AL
772 MOV DI,81H
773 MOV CX,0
774 PUSH SI
775COMTAIL:
776 LODSB
777 STOSB ;Move command tail to 80H
778 CMP AL,13
779 LOOPNZ COMTAIL
780 NOT CL
781 MOV BYTE PTR DS:[80H],CL
782 POP SI
783;If the command has 0 parameters must check here for
784;any switches that might be present.
785;SI -> first character after the command.
786 MOV [FLAGER],0 ;Set error flag before any calls to switch
787 CALL SWITCH ;Is the next character a "/"
788 MOV [COMSW],AX
789 MOV DI,FCB
790 MOV AX,2901H
791 INT 21H
792 MOV [PARM1],AL ;Save result of parse
793 CALL SWITCH
794 MOV [ARG1S],AX
795 MOV DI,FCB+10H
796 MOV AX,2901H
797 INT 21H ;Parse file name
798 MOV [PARM2],AL ;Save result
799 CALL SWITCH
800 MOV [ARG2S],AX
801 MOV AL,[IDLEN]
802 MOV DL,[SPECDRV]
803 OR DL,DL ;Check if drive was specified
804 JZ OK
805 JMP DRVCHK
806OK: DEC AL ;Check for null command
807 JNZ FNDCOM
808 JMP GETCOM
809
810RETSW:
811 XCHG AX,BX ;Put switches in AX
812 RET
813
814SWITCH:
815 XOR BX,BX ;Initialize - no switches set
816SWLOOP:
817 CALL SCANOFF ;Skip any delimiters
818 CMP AL,"/" ;Is it a switch specifier?
819 JNZ RETSW ;No -- we're finished
820 INC SI ;Skip over "/"
821 CALL SCANOFF
822 INC SI
823;Convert lower case input to upper case
824 CMP AL,"a"
825 JB SAVCHR
826 CMP AL,"z"
827 JA SAVCHR
828 SUB AL,20H ;Lower-case changed to upper-case
829SAVCHR:
830 MOV DI,OFFSET TRANGROUP:SWLIST
831 MOV CX,SWCOUNT
832 REPNE SCASB ;Look for matching switch
833 JNZ BADSW
834 MOV AX,1
835 SHL AX,CL ;Set a bit for the switch
836 OR BX,AX
837 JMP SHORT SWLOOP
838
839BADSW:
840 MOV [FLAGER],1 ;Record error in switch
841 JMP SHORT SWLOOP
842
843SWLIST DB "BAVPW"
844SWCOUNT EQU $-SWLIST
845
846DRVBAD:
847 MOV DX,OFFSET TRANGROUP:BADDRV
848 JMP ERROR
849
850FNDCOM:
851 MOV SI,OFFSET TRANGROUP:COMTAB ;Prepare to search command table
852 MOV CH,0
853FINDCOM:
854 MOV DI,OFFSET TRANGROUP:IDLEN
855 MOV CL,[SI]
856 JCXZ EXTERNAL
857 REPE CMPSB
858 LAHF
859 ADD SI,CX ;Bump to next position without affecting flags
860 SAHF
861 LODSB ;Get flag for drive check
862 MOV [CHKDRV],AL
863 LODSW ;Get address of command
864 JNZ FINDCOM
865 MOV DX,AX
866 CMP [CHKDRV],0
867 JZ NOCHECK
868 MOV AL,[PARM1]
869 OR AL,[PARM2] ;Check if either parm. had invalid drive
870 CMP AL,-1
871 JZ DRVBAD
872NOCHECK:CALL DX
873COMJMP: JMP COMMAND
874
875BADCOMJ:JMP BADCOM
876
877SETDRV1:
878 JMP SETDRV
879
880DRVCHK:
881 DEC DL ;Adjust for correct drive number
882 DEC AL ;Check if anything else is on line
883 JZ SETDRV1
884EXTERNAL:
885 MOV AL,[SPECDRV]
886 MOV [IDLEN],AL
887 MOV WORD PTR[COM],4F00H+"C" ;"CO"
888 MOV BYTE PTR[COM+2],"M"
889 MOV DX,OFFSET TRANGROUP:IDLEN
890 MOV AH,OPEN
891 INT 33 ;Check if command to be executed
892 MOV [FILTYP],AL ;0 for COM files, -1 for EXE files
893 OR AL,AL
894 JZ EXECUTE
895 MOV WORD PTR[COM],5800H+"E" ;"EX"
896 MOV BYTE PTR[COM+2],"E"
897 INT 33 ;Check for EXE file
898 OR AL,AL
899 JZ EXECUTE
900 MOV WORD PTR[COM],4100H+"B" ;"BA"
901 MOV BYTE PTR[COM+2],"T"
902 INT 33 ;Check if batch file to be executed
903 OR AL,AL
904 JNZ BADCOMJ
905BATCOM:
906;Batch parameters are read with ES set to segment of resident part
907 MOV ES,[RESSEG]
908ASSUME ES:RESGROUP
909 MOV DI,OFFSET RESGROUP:PARMTAB
910 MOV AX,-1
911 MOV CX,10
912 REP STOSW ;Zero parameter pointer table
913 MOV SI,OFFSET TRANGROUP:COMBUF+2
914 MOV DI,OFFSET RESGROUP:PARMBUF
915 MOV BX,OFFSET RESGROUP:PARMTAB
916EACHPARM:
917 CALL SCANOFF
918 CMP AL,0DH
919 JZ HAVPARM
920 MOV ES:[BX],DI ;Set pointer table to point to actual parameter
921 INC BX
922 INC BX
923MOVPARM:
924 LODSB
925 CALL DELIM
926 JZ ENDPARM ;Check for end of parameter
927 STOSB
928 CMP AL,0DH
929 JZ HAVPARM
930 JMP SHORT MOVPARM
931ENDPARM:
932 MOV AL,0DH
933 STOSB ;End-of-parameter marker
934 CMP BX,OFFSET RESGROUP:PARMTAB+20 ;Maximum number of parameters?
935 JB EACHPARM
936HAVPARM:
937 MOV SI,OFFSET TRANGROUP:IDLEN
938 MOV DI,OFFSET RESGROUP:BATFCB
939 MOV CX,16
940 REP MOVSW ;Move into private batch FCB
941 XOR AX,AX
942 PUSH ES
943 POP DS ;Simply batch FCB setup
944ASSUME DS:RESGROUP
945 MOV WORD PTR[BATFCB+RR],AX
946 MOV WORD PTR[BATFCB+RR+2],AX ;Zero RR field
947 INC AX
948 MOV WORD PTR[BATFCB+RECLEN],AX ;Set record length to 1 byte
949 MOV [BATCH],AL ;Flag batch job in progress
950 JMP COMMAND
951ASSUME DS:TRANGROUP,ES:TRANGROUP
952
953EXECUTE:
954 MOV AX,WORD PTR[IDLEN+16]
955 OR AX,WORD PTR[IDLEN+18] ;See if zero length
956 JZ BADCOM ;If so, error
957 XOR AX,AX
958 MOV WORD PTR[IDLEN+RR],AX
959 MOV WORD PTR[IDLEN+RR+2],AX ;Set RR field to zero
960 INC AX
961 MOV WORD PTR[IDLEN+RECLEN],AX ;Set record length field to 1
962 MOV DX,[TPA]
963 MOV BX,DX
964 MOV AH,SETBASE
965 INT 21H
966 TEST [FILTYP],-1 ;Check if file is COM or EXE
967 JZ COMLOAD
968 JMP EXELOAD
969COMLOAD:PUSH DS
970 MOV DS,DX
971 MOV DX,100H
972 MOV AH,SETDMA
973 INT 21H
974 POP DS
975 MOV CX,[BYTCNT]
976 SUB CX,100H
977 MOV DX,OFFSET TRANGROUP:IDLEN
978 MOV AH,RDBLK
979 INT 21H
980 DEC AL
981 MOV DX,OFFSET TRANGROUP:TOOBIG
982 JNZ ERROR
983;Set up exit conditions
984 MOV CX,[BYTCNT]
985 MOV DS,BX
986 MOV ES,BX
987 CLI
988 MOV SS,BX
989 MOV SP,CX
990 STI
991 SUB CX,100H ;Allow some stack space
992 XOR AX,AX
993 PUSH AX
994 MOV AX,100H
995 PUSH BX
996 PUSH AX
997 CALL SETUP
998XXX PROC FAR
999 RET
1000XXX ENDP
1001BADCOM:
1002 MOV DX,OFFSET TRANGROUP:BADNAM
1003ERROR:
1004 MOV AH,PRINTBUF
1005 INT 21H
1006 JMP COMMAND
1007
1008CHKCNT:
1009 TEST [FILECNT],-1
1010 JNZ ENDDIR
1011 MOV DX,OFFSET TRANGROUP:NOTFND
1012 JMP ERROR
1013
1014ENDDIR:
1015;Make sure last line ends with CR/LF
1016 MOV AL,[LINLEN]
1017 CMP AL,[LINCNT] ;Will be equal if just had CR/LF
1018 JZ MESSAGE
1019 CALL CRLF2
1020MESSAGE:
1021 MOV SI,[FILECNT]
1022 XOR DI,DI
1023 CALL DISP32BITS
1024 MOV DX,OFFSET TRANGROUP:DIRMES
1025 MOV AH,PRINTBUF
1026 INT 21H
1027 RET
1028
1029CATALOG:
1030 MOV AL,"?" ;*.* is default file spec.
1031 MOV DI,5DH
1032 MOV CX,11
1033 REP STOSB
1034 MOV SI,81H
1035 CALL SWITCH
1036 MOV DI,5CH
1037 MOV AX,41*100H+0DH ;Parse with default name and extension
1038 INT 33
1039
1040;Begin by processing any switches that may have been specified.
1041;BITS will contain any information about switches that was
1042;found when the command line was parsed.
1043
1044SETSWT:
1045 MOV AX,[COMSW] ;Get switches from command
1046 OR AX,[ARG1S] ;OR in switches from first parameter
1047 MOV [BITS],AX
1048 MOV BYTE PTR[FULLSCR],LINPERPAG
1049 TEST AL,1 ;Look for /W
1050 MOV AL,NORMPERLIN
1051 JZ DIR
1052 MOV AL,WIDEPERLIN
1053DIR:
1054 MOV [LINLEN],AL ;Set number of entries per line
1055 MOV [LINCNT],AL
1056 MOV [FILECNT],0 ;Keep track of how many files found
1057 MOV DX,OFFSET TRANGROUP:DIRBUF ;Set Disk transfer address
1058 MOV AH,SETDMA
1059 INT 21H
1060 MOV AH,SRCHFRST
1061SHOWDIR:
1062 MOV DX,5CH ;DX -> Unopened FCB
1063 INT 21H ;Search for a file to match FCB
1064 INC AL ;FF = file not found
1065 JNZ AGAIN ;Either an error or we are finished
1066 JMP CHKCNT
1067AGAIN:
1068 INC [FILECNT] ;Keep track of how many we find
1069 MOV SI,OFFSET TRANGROUP:DIRBUF+1 ;SI -> information returned by sys call
1070 CALL SHONAME
1071 TEST BYTE PTR[BITS],1 ;/W set?
1072 JNZ NEXENT ;If so, no size, date, or time
1073 CALL DISPSIZE ;Print size of file
1074 CALL TWOSPC
1075 MOV AX,WORD PTR[DIRBUF+25] ;Get date
1076 OR AX,AX
1077 JZ NEXENT ;Skip if no date
1078 MOV DX,AX
1079 MOV CL,5
1080 SHR AX,CL ;Align month
1081 AND AL,0FH
1082 MOV BH,"0"-" " ;Enable zero suppression
1083 CALL OUT2
1084 MOV AL,"-"
1085 CALL OUT
1086 MOV AL,DL
1087 AND AL,1FH ;Mask to day
1088 CALL OUT2
1089 MOV AL,"-"
1090 CALL OUT
1091 MOV AL,DH
1092 SHR AL,1 ;Align year
1093 ADD AX,80 ;Relative 1980
1094 CMP AL,100
1095 JB MILLENIUM
1096 SUB AL,100
1097MILLENIUM:
1098 CALL OUT2
1099 MOV BX,WORD PTR[DIRBUF+23] ;Get time
1100 OR BX,BX ;Time field present?
1101 JZ NEXENT
1102 CALL TWOSPC
1103 SHR BX,1
1104 SHR BX,1
1105 SHR BX,1
1106 SHR BL,1
1107 SHR BL,1 ;Hours in BH, minutes in BL
1108 MOV AL,BH
1109 MOV DH,"a" ;Assume A.M.
1110 CMP AL,12 ;In the afternoon?
1111 JB MORN
1112 MOV DH,"p"
1113 JE MORN
1114 SUB AL,12 ;Keep it to 12 hours or less
1115MORN:
1116 OR AL,AL ;Before 1 am?
1117 JNZ SHOHOURS
1118 MOV AL,12
1119SHOHOURS:
1120 MOV BH,"0"-" " ;Enable zero suppression
1121 CALL OUT2
1122 MOV AL,":"
1123 CALL OUT
1124 MOV AL,BL ;Output minutes
1125 CALL OUT2
1126 MOV AL,DH ;Get "a" or "p"
1127 CALL OUT
1128NEXENT:
1129 DEC [LINCNT]
1130 JNZ SAMLIN
1131NEXLIN:
1132 MOV AL,[LINLEN]
1133 MOV [LINCNT],AL
1134 CALL CRLF2
1135 TEST BYTE PTR[BITS],2 ;/P switch present?
1136 JZ SCROLL ;If not, just continue
1137 DEC BYTE PTR[FULLSCR]
1138 JNZ SCROLL
1139 MOV BYTE PTR[FULLSCR],LINPERPAG
1140 MOV AH,PRINTBUF
1141 MOV DX,OFFSET TRANGROUP:PAUSMES
1142 INT 33
1143 MOV AX,0C08H ;Wait for any character to be typed
1144 INT 21H
1145 CALL CRLF2
1146SCROLL:
1147 MOV AH,SRCHNXT
1148 JMP SHOWDIR
1149
1150SAMLIN:
1151 MOV AL,9 ;Output a tab
1152 CALL OUT
1153 JMP SHORT SCROLL
1154
1155SHONAME:
1156 MOV CX,8
1157 CALL OUTCNT
1158 CALL ONESPC
1159 MOV CX,3
1160OUTCNT:
1161 LODSB
1162 CALL OUT
1163 LOOP OUTCNT
1164 RET
1165
1166TWOSPC:
1167 CALL ONESPC
1168ONESPC:
1169 MOV AL," "
1170 JMP OUT
1171
1172CRLF2:
1173 MOV AL,13
1174 CALL OUT
1175 MOV AL,10
1176 JMP OUT
1177
1178DISPSIZE:
1179 MOV SI,WORD PTR[DIRBUF+29]
1180 MOV DI,WORD PTR[DIRBUF+31]
1181DISP32BITS:
1182;Prints the 32-bit number DI:SI on the console in decimal. Uses a total
1183;of 9 digit positions with leading blanks.
1184 XOR AX,AX
1185 MOV BX,AX
1186 MOV BP,AX
1187 MOV CX,32
1188CONVLP:
1189 SHL SI,1
1190 RCL DI,1
1191 XCHG AX,BP
1192 CALL CONVWRD
1193 XCHG AX,BP
1194 XCHG AX,BX
1195 CALL CONVWRD
1196 XCHG AX,BX
1197 ADC AL,0
1198 LOOP CONVLP
1199; Conversion complete. Print 9-digit number.
1200 MOV CX,1810H ;Allow leading zero blanking for 8 digits
1201 XCHG DX,AX
1202 CALL DIGIT
1203 XCHG AX,BX
1204 CALL OUTWORD
1205 XCHG AX,BP
1206OUTWORD:
1207 PUSH AX
1208 MOV DL,AH
1209 CALL OUTBYTE
1210 POP DX
1211OUTBYTE:
1212 MOV DH,DL
1213 SHR DL,1
1214 SHR DL,1
1215 SHR DL,1
1216 SHR DL,1
1217 CALL DIGIT
1218 MOV DL,DH
1219DIGIT:
1220 AND DL,0FH
1221 JZ BLANKZER
1222 MOV CL,0
1223BLANKZER:
1224 DEC CH
1225 AND CL,CH
1226 OR DL,30H
1227 SUB DL,CL
1228 MOV AH,OUTCH
1229 INT 21H
1230 RET
1231
1232CONVWRD:
1233 ADC AL,AL
1234 DAA
1235 XCHG AL,AH
1236 ADC AL,AL
1237 DAA
1238 XCHG AL,AH
1239RET20: RET
1240
1241ERASE:
1242 MOV CX,11
1243 MOV SI,FCB+1
1244AMBSPEC:
1245 LODSB
1246 CMP AL,"?"
1247 JNZ ALLFIL
1248 LOOP AMBSPEC
1249ALLFIL:
1250 CMP CX,0
1251 JNZ NOPRMPT
1252ASKAGN:
1253 MOV DX,OFFSET TRANGROUP:SUREMES ;"Are you sure (Y/N)?"
1254 MOV AH,PRINTBUF
1255 INT 21H
1256 MOV AX,0C00H+INCHAR
1257 INT 21H
1258 AND AL,5FH
1259 CMP AL,"N"
1260 JZ RET20
1261 CMP AL,"Y"
1262 CALL CRLF2
1263 JZ NOPRMPT
1264 JMP SHORT ASKAGN
1265NOPRMPT:
1266 MOV AH,DELETE
1267 MOV BX,OFFSET TRANGROUP:NOTFND
1268 CMP BYTE PTR DS:[FCB+1]," " ;Check if parameter exists
1269 JMP SHORT OPFILE
1270RENAME:
1271 MOV AH,RENAM
1272 MOV BX,OFFSET TRANGROUP:RENERR
1273 CMP BYTE PTR DS:[FCB+16+1]," " ;Check if parameter exists
1274OPFILE:
1275 MOV DX,OFFSET TRANGROUP:MISNAM
1276 JZ ERRJ ;Error if missing parameter
1277 MOV DX,FCB
1278 INT 21H
1279 INC AL
1280 JNZ RET20
1281 MOV DX,BX
1282ERRJ: JMP ERROR
1283
1284TYPEFIL:
1285 MOV DS,[TPA]
1286 XOR DX,DX
1287 MOV AH,SETDMA
1288 INT 21H
1289 PUSH CS
1290 POP DS
1291 MOV DX,FCB
1292 MOV AH,OPEN
1293 INT 21H
1294 OR AL,AL
1295 MOV DX,OFFSET TRANGROUP:NOTFND
1296 JNZ ERRJ
1297 XOR AX,AX
1298 MOV WORD PTR DS:[FCB+RR],AX ;Set RR field
1299 MOV WORD PTR DS:[FCB+RR+2],AX
1300 INC AX
1301 MOV WORD PTR DS:[FCB+RECLEN],AX ;Set record length
1302 MOV ES,[TPA]
1303TYPELP:
1304 MOV DX,FCB
1305 MOV CX,[BYTCNT]
1306 MOV AH,RDBLK
1307 INT 21H
1308 JCXZ RET30
1309 XOR SI,SI ;Start at 0 in TPA
1310OUTLP:
1311 LODS BYTE PTR ES:[SI] ;In TPA segment
1312 CMP AL,1AH
1313 JZ RET30
1314 MOV AH,OUTCH
1315 MOV DL,AL
1316 INT 21H
1317 LOOP OUTLP
1318 JMP SHORT TYPELP
1319
1320RET30: RET ;Need a nearby RET
1321
1322COPY:
1323 XOR AX,AX
1324 MOV [PLUS],AL ;Will keep track of "+"s
1325 MOV [FILECNT],AX
1326 MOV SI,81H ;Point to input line
1327 CALL SWITCH ;Skip over switches on command
1328 MOV BP,AX
1329 MOV DI,FCB
1330 CALL PARSNAM ;Scan first source
1331 MOV [PARM1],DL ;Save ambiguous flag
1332 MOV [SRCPT],SI ;Save pointer to command line
1333;Parse each name to find destination and check for /V switch
1334SCANNAM:
1335 CALL PARSE
1336 JNZ SCANNAM
1337GETDEST:
1338 MOV DI,OFFSET TRANGROUP:DEST
1339 MOV BX,BP ;Remeber switches so far
1340 XOR BP,BP ;Must have dest. swtiches alone
1341 CALL PARSNAM
1342 MOV [ARG2S],BP ;Remember switches on destination
1343 JNZ HAVDESTNAM ;File name present?
1344 INC DI ;Point to file name spot
1345 MOV AL,"?" ;Substitute *.*
1346 MOV CX,11
1347 REP STOSB
1348HAVDESTNAM:
1349 OR BX,BP ;BX = all switches combined
1350 AND BL,VSWITCH ;Verify requested?
1351 JZ NOVER
1352 MOV AX,46*100H+1 ;Set verify
1353 MOV DL,0
1354 INT 33
1355NOVER:
1356 MOV DI,OFFSET TRANGROUP:DESTNAME
1357 MOV SI,OFFSET TRANGROUP:DEST+1
1358 MOV BX,FCB+1
1359 CALL BUILDNAME ;See if we can make it unambiguous
1360 MOV DI,OFFSET TRANGROUP:DESTNAME
1361 MOV AL,"?"
1362 MOV CX,11
1363 REPNE SCASB ;Scan for "?" to see if ambiguous
1364 MOV AL,1 ;Flag if ambig.
1365 JZ AMBIG
1366 DEC AX ;AL=0 if unambig.
1367AMBIG:
1368 MOV DL,AL
1369 MOV AH,[PLUS] ;1=found "+"
1370 XOR AL,1 ;0=ambig, 1=unambig destination
1371 AND AL,[PARM1] ;Source ambig. AND dest unambig.
1372 OR AL,AH ;OR found "+" means concatenation
1373 MOV [ASCII],AL ;Concatenation implies ASCII mode
1374 MOV [INEXACT],AL ;ASCII implies inexact copy
1375 SHL AL,1
1376 OR AL,DL ;Combine multiple and concat flags
1377 MOV [PARM2],AL
1378 MOV AL,BYTE PTR[COMSW]
1379 CALL SETASC ;Check /A,/B on command
1380 MOV AL,BYTE PTR[ARG1S]
1381 CALL SETASC ;Check for ASCII on first filename
1382 MOV BYTE PTR[COMSW],AL ;Save starting switch values
1383 MOV AH,SRCHFRST
1384 CALL SEARCH ;Search for first source name
1385MULTDEST:
1386 JZ FIRSTSRC ;Find a first source name?
1387 TEST [PARM2],1 ;If multiple, we're done
1388 JNZ ENDCOPY
1389 XOR AX,AX
1390 MOV [NXTADD],AX
1391 MOV [CFLAG],AL ;Flag nothing read yet
1392NEXTSNG:
1393 MOV DI,FCB
1394 MOV SI,[SRCPT]
1395 CALL PARSESRC ;Parse next file name into FCB
1396 MOV [PARM1],DL ;Remember if it's ambiguous
1397 MOV [SRCPT],SI
1398 JZ SNGCLOS
1399 MOV AH,SRCHFRST
1400 CALL SEARCH ;Search for new file name
1401 JNZ NEXTSNG ;If none, skip it and move to next name
1402READSNG:
1403 CALL CHECKREAD
1404SNGLOOP:
1405 CALL SEARCHNEXT ;See if any more of this name
1406 JZ READSNG
1407 JMP SHORT NEXTSNG
1408
1409SNGCLOS:
1410 CALL CLOSEFIL
1411ENDCOPY:
1412 MOV SI,[FILECNT]
1413 XOR DI,DI
1414 CALL DISP32BITS
1415 MOV DX,OFFSET TRANGROUP:COPIED
1416 MOV AH,PRINTBUF
1417 INT 21H
1418 JMP COMMAND ;Stack could be messed up
1419
1420FIRSTSRC:
1421 MOV SI,OFFSET TRANGROUP:DIRBUF+1
1422 MOV DI,OFFSET TRANGROUP:SOURCE
1423 MOV CX,11
1424 REP MOVSB ;Copy first source name to SOURCE
1425 MOV SI,OFFSET TRANGROUP:DESTNAME
1426 MOV DI,OFFSET TRANGROUP:DEST+1
1427 MOV BX,OFFSET TRANGROUP:SOURCE
1428 CALL BUILDNAME ;Build destination name
1429 XOR AX,AX
1430 MOV [NXTADD],AX
1431 MOV [CFLAG],AL
1432 MOV [APPEND],AL
1433 MOV [NOWRITE],AL
1434 TEST [PARM2],1 ;Multiple destinations?
1435 JZ NOPRT
1436 MOV SI,OFFSET TRANGROUP:DIRBUF+1
1437 CALL SHONAME ;If so, show first source
1438 CALL CRLF2
1439NOPRT:
1440 CALL COMPNAME ;Source and dest. the same?
1441 JNZ DOREAD ;If not, read source in
1442 TEST [PARM2],2 ;Concatenation?
1443 MOV DX,OFFSET TRANGROUP:OVERWR
1444 JZ COPERRJ ;If not, overwrite error
1445 MOV [APPEND],1 ;Set physical append
1446 MOV AH,OPEN
1447 MOV DX,OFFSET TRANGROUP:DEST
1448 INT 33 ;Open (existing) destination
1449 CMP [ASCII],0 ;ASCII flag set?
1450 JZ BINARYAPP
1451;ASCII append. Must find logical EOF, then seek there with dest. FCB
1452 MOV [NOWRITE],1
1453 CALL READIN ;Find EOF
1454 CALL FLSHFIL ;Seek there
1455 MOV [NOWRITE],0
1456 CALL FLSHFIL ;Truncate file
1457 JMP SHORT SNGLCHK
1458
1459SNGLOOPJ:JMP SNGLOOP
1460
1461COPERRJ:JMP COPERR
1462
1463BINARYAPP:
1464 MOV WORD PTR[DEST+RECLEN],1 ;Set record length to 1
1465 MOV SI,OFFSET TRANGROUP:DEST+16 ;Point to file size
1466 MOV DI,OFFSET TRANGROUP:DEST+RR
1467 MOVSW
1468 MOVSW ;Seek to end of file
1469 MOV [CFLAG],1
1470 JMP SHORT SNGLCHK
1471DOREAD:
1472 CALL READIN
1473SNGLCHK:
1474 TEST [PARM2],1 ;Single or multiple destinations?
1475 JZ SNGLOOPJ
1476 MOV SI,[SRCPT]
1477MULTAPP:
1478 CALL PARSE
1479 JZ MULTCLOS
1480 PUSH SI
1481 MOV SI,OFFSET TRANGROUP:DIRBUF+1
1482 MOV DI,SI
1483 MOV BX,OFFSET TRANGROUP:SOURCE
1484 CALL BUILDNAME
1485 CALL CHECKREAD
1486 POP SI
1487 JMP SHORT MULTAPP
1488MULTCLOS:
1489 CALL CLOSEFIL
1490 MOV AL,BYTE PTR[COMSW]
1491 MOV [ASCII],AL ;Restore ASCII flag
1492 CALL SEARCHNEXT
1493 JMP MULTDEST
1494
1495PARSE:
1496 MOV DI,OFFSET TRANGROUP:DIRBUF
1497PARSESRC:
1498 CALL SCANOFF
1499 CMP AL,"+"
1500 JNZ RETZF
1501 MOV [PLUS],1 ;Keep track of "+" signs
1502 INC SI ;Skip over it
1503PARSNAM:
1504 MOV AX,2901H
1505 INT 33 ;Parse file name
1506 CMP AL,-1 ;Illegal?
1507 MOV DX,OFFSET TRANGROUP:BADDRV
1508 JZ COPERRJ
1509 XCHG AX,DX ;Save parse flag in DL
1510 MOV AL,BYTE PTR[DI] ;Get drive number
1511 OR AL,AL ;Is it default?
1512 JNZ PARSW
1513 MOV AL,[CURDRV] ;Substitute actual drive
1514 INC AX
1515 MOV BYTE PTR[DI],AL
1516PARSW:
1517 PUSH BX
1518 PUSH DI
1519 CALL SWITCH ;Process switches
1520 OR BP,AX ;Combine all switches
1521 CALL SETASC ;Check for /A or /B
1522 POP DI
1523 POP BX
1524 CMP BYTE PTR[DI+1]," " ;Did we even get a file name?
1525 RET
1526
1527RETZF:
1528 XOR AX,AX
1529RET35: RET
1530
1531SEARCHNEXT:
1532 MOV AL,[PARM1] ;Is name ambiguous?
1533 DEC AL
1534 JNZ RET35 ;Don't perform search if not
1535 MOV AH,SRCHNXT
1536SEARCH:
1537 PUSH AX
1538 MOV AH,SETDMA
1539 MOV DX,OFFSET TRANGROUP:DIRBUF
1540 INT 33 ;Put result of search in DIRBUF
1541 POP AX ;Restore search first/next command
1542 MOV DX,FCB
1543 INT 33 ;Do the search
1544 OR AL,AL
1545 RET
1546
1547SETASC:
1548;Given switch vector in AX,
1549; Set ASCII switch if /A is set
1550; Clear ASCII switch if /B is set
1551; Leave ASCII unchanged if neither or both are set
1552; Also sets INEXACT if ASCII is ever set. AL = ASCII on exit, flags set
1553 AND AL,ASWITCH+BSWITCH
1554 JPE LOADSW ;PE means both or neither are set
1555 AND AL,ASWITCH
1556 MOV [ASCII],AL
1557 OR [INEXACT],AL
1558LOADSW:
1559 MOV AL,[ASCII]
1560 OR AL,AL
1561 RET
1562
1563BUILDNAME:
1564; [SI] = Ambiguous input file name
1565; [BX] = Source of replacement characters
1566; [DI] = Destination
1567; File name is copied from [SI] to [DI]. If "?"s are encountered,
1568; they are replaced with the character in the same position at [BX].
1569 MOV CX,11
1570BUILDNAM:
1571 LODSB
1572 CMP AL,"?"
1573 JNZ NOTAMBIG
1574 MOV AL,BYTE PTR[BX]
1575NOTAMBIG:
1576 STOSB
1577 INC BX
1578 LOOP BUILDNAM
1579 RET
1580
1581COMPNAME:
1582 MOV SI,OFFSET TRANGROUP:DEST
1583 MOV DI,OFFSET TRANGROUP:DIRBUF
1584 MOV CX,6
1585 REPE CMPSW
1586 RET
1587
1588CHECKREAD:
1589;Read file in (with READIN) if not identical to destination
1590 CALL COMPNAME ;See if source and destination the same
1591 JNZ READIN
1592 CMP [APPEND],0 ;If physical append, it's OK
1593 JNZ RET40
1594 MOV DX,OFFSET TRANGROUP:LOSTERR ;Tell him he's not going to get it
1595 MOV AH,PRINTBUF
1596 INT 33
1597RET40: RET
1598
1599READIN:
1600;Open source file and read it in. If memory fills up, flush it out to
1601;destination and keep reading. If /A switch set, chop file at first ^Z.
1602; Inputs/Outputs:
1603; [NXTADD] has current pointer in buffer
1604; [CFLAG] <>0 if destination has been created
1605
1606 MOV DX,OFFSET TRANGROUP:DIRBUF
1607 MOV AH,OPEN
1608 INT 21H
1609 OR AL,AL ;Successful open?
1610 JNZ RET40 ;If not, just ignore it
1611 XOR AX,AX
1612 MOV WORD PTR[DIRBUF+RR],AX
1613 MOV WORD PTR[DIRBUF+RR+2],AX
1614 INC AX
1615 MOV WORD PTR[DIRBUF+RECLEN],AX
1616COPYLP:
1617 MOV DX,[NXTADD]
1618 MOV AH,SETDMA
1619 PUSH DS
1620 MOV DS,[TPA]
1621 INT 33
1622 POP DS
1623 MOV CX,[BYTCNT]
1624 SUB CX,DX ;Compute available space
1625 MOV DX,OFFSET TRANGROUP:DIRBUF
1626 MOV AH,RDBLK ;Read in source file
1627 INT 21H
1628 JCXZ RET40
1629 CMP [ASCII],0
1630 JZ BINREAD
1631 MOV DX,CX
1632 MOV DI,[NXTADD]
1633 MOV AL,1AH
1634 PUSH ES
1635 MOV ES,[TPA]
1636 REPNE SCASB ;Scan for EOF
1637 POP ES
1638 JNZ USEALL
1639 INC CX
1640USEALL:
1641 SUB DX,CX
1642 MOV CX,DX
1643BINREAD:
1644 ADD CX,[NXTADD]
1645 MOV [NXTADD],CX
1646 CMP CX,[BYTCNT] ;Is buffer full?
1647 JB RET40 ;If not, we must have found EOF
1648 CALL FLSHFIL
1649 JMP SHORT COPYLP
1650
1651CLOSEFIL:
1652 MOV AX,[NXTADD]
1653 MOV BX,AX
1654 OR AL,AH ;See if any data is loaded
1655 OR AL,[CFLAG] ; or file was created
1656 JZ RET50 ;Don't close or count if not created
1657 MOV AL,BYTE PTR[ARG2S]
1658 CALL SETASC ;Check for /B or /A on destination
1659 JZ BINCLOS
1660 CMP BX,[BYTCNT] ;Is memory full?
1661 JNZ PUTZ
1662 CALL FLSHFIL ;Empty it to make room for 1 lousy byte
1663 XOR BX,BX
1664PUTZ:
1665 PUSH DS
1666 MOV DS,[TPA]
1667 MOV WORD PTR[BX],1AH ;Add End-of-file mark (Ctrl-Z)
1668 POP DS
1669 INC [NXTADD]
1670BINCLOS:
1671 CALL FLSHFIL
1672 CMP [INEXACT],0 ;Copy not exact?
1673 JNZ NODATE ;If so, don't copy date & time
1674 MOV SI,OFFSET TRANGROUP:DIRBUF+OFFDATE
1675 MOV DI,OFFSET TRANGROUP:DEST+OFFDATE ;Make date & time same as original
1676 MOVSW ;Copy date
1677 MOVSW ;Copy time
1678NODATE:
1679 MOV DX,OFFSET TRANGROUP:DEST
1680 MOV AH,CLOSE
1681 INT 21H
1682 INC [FILECNT]
1683RET50: RET
1684
1685FLSHFIL:
1686;Write out any data remaining in memory.
1687; Inputs:
1688; [NXTADD] = No. of bytes to write
1689; [CFLAG] <>0 if file has been created
1690; Outputs:
1691; [NXTADD] = 0
1692
1693 MOV AL,1
1694 XCHG [CFLAG],AL
1695 OR AL,AL
1696 JNZ EXISTS
1697 CMP [NOWRITE],0
1698 JNZ SKPMAK ;Don't actually create if NOWRITE set
1699 MOV DX,OFFSET TRANGROUP:DEST
1700 MOV AH,MAKE
1701 INT 21H
1702 MOV DX,OFFSET TRANGROUP:FULDIR
1703 OR AL,AL
1704 JNZ COPERR
1705SKPMAK:
1706 XOR AX,AX
1707 MOV WORD PTR[DEST+RR],AX
1708 MOV WORD PTR[DEST+RR+2],AX
1709 INC AX
1710 MOV WORD PTR[DEST+RECLEN],AX
1711EXISTS:
1712 XOR CX,CX
1713 XCHG CX,[NXTADD]
1714 CMP [NOWRITE],0 ;If NOWRITE set, just seek CX bytes
1715 JNZ SEEKEND
1716 XOR DX,DX
1717 PUSH DS
1718 MOV DS,[TPA]
1719 MOV AH,SETDMA
1720 INT 33
1721 POP DS
1722 MOV DX,OFFSET TRANGROUP:DEST
1723 MOV AH,WRBLK
1724 INT 21H
1725 OR AL,AL
1726 JZ RET60
1727 MOV DX,OFFSET TRANGROUP:DEST
1728 MOV AH,CLOSE
1729 INT 21H
1730 MOV AH,DELETE
1731 INT 33
1732 MOV DX,OFFSET TRANGROUP:NOSPACE
1733COPERR:
1734 MOV AH,9
1735 INT 21H
1736 JMP ENDCOPY
1737
1738SEEKEND:
1739 ADD WORD PTR[DEST+RR],CX
1740 ADC WORD PTR[DEST+RR+2],0 ;Propagate carry
1741RET60: RET
1742
1743GETBATBYT:
1744;Get one byte from the batch file and return it in AL. End-of-file
1745;returns <CR> and ends batch mode. DS must be set to resident segment.
1746;AH, CX, DX destroyed.
1747ASSUME DS:RESGROUP
1748 MOV DX,OFFSET RESGROUP:BATFCB
1749 MOV AH,RDBLK
1750 MOV CX,1
1751 INT 33 ;Get one more byte from batch file
1752 JCXZ BATEOF
1753 MOV AL,[BATBYT]
1754 CMP AL,1AH
1755 JNZ RET70
1756BATEOF:
1757 MOV AL,0DH ;If end-of-file, then end of line
1758 MOV [BATCH],0 ;And turn off batch mode
1759RET70: RET
1760ASSUME DS:TRANGROUP
1761
1762SCANOFF:
1763 LODSB
1764 CALL DELIM
1765 JZ SCANOFF
1766 DEC SI ;Point to first non-delimiter
1767 RET
1768
1769DELIM:
1770 CMP AL," "
1771 JZ RET80
1772 CMP AL,"="
1773 JZ RET80
1774 CMP AL,","
1775 JZ RET80
1776 CMP AL,9 ;Check for TAB character
1777RET80: RET
1778
1779PAUSE:
1780 MOV DX,OFFSET TRANGROUP:PAUSMES
1781 MOV AH,PRINTBUF
1782 INT 33
1783 MOV AX,0C00H+INCHAR ;Get character with KB buffer flush
1784 INT 33
1785RET90: RET
1786
1787;Date and time are set during initialization and use
1788;this routines since they need to do a long return
1789
1790DATINIT:
1791 PUSH ES
1792 PUSH DS ;Going to use the previous stack
1793 MOV AX,CS ;Set up the appropriate segment registers
1794 MOV ES,AX
1795 MOV DS,AX
1796 MOV WORD PTR DS:[81H],13 ;Want to prompt for date during initialization
1797 CALL DATE
1798 CALL TIME
1799 POP DS
1800 POP ES
1801YYY PROC FAR
1802 RET
1803YYY ENDP
1804
1805; DATE - Gets and sets the time
1806
1807DATE:
1808 MOV SI,81H ;Accepting argument for date inline
1809 CALL SCANOFF
1810 CMP AL,13
1811 JZ PRMTDAT
1812 MOV BX,2F00H+"-" ;"/-"
1813 CALL INLINE
1814 JMP COMDAT
1815
1816PRMTDAT:
1817 MOV DX,OFFSET TRANGROUP:CURDAT
1818 MOV AH,PRINTBUF
1819 INT 33 ;Print "Current date is "
1820 MOV AH,GETDATE
1821 INT 33 ;Get date in CX:DX
1822 CBW
1823 MOV SI,AX
1824 SHL SI,1
1825 ADD SI,AX ;SI=AX*3
1826 ADD SI,OFFSET TRANGROUP:WEEKTAB
1827 MOV BX,CX
1828 MOV CX,3
1829 CALL OUTCNT
1830 MOV AL," "
1831 CALL OUT
1832 MOV AX,BX
1833 MOV CX,DX
1834 MOV DL,100
1835 DIV DL
1836 XCHG AL,AH
1837 XCHG AX,DX
1838 MOV BL,"-"
1839 CALL SHOW
1840GETDAT:
1841 MOV DX,OFFSET TRANGROUP:NEWDAT
1842 MOV BX,2F00H+"-" ;"/-" in BX
1843 CALL GETBUF
1844COMDAT: JZ RET90
1845 JC DATERR
1846 LODSB
1847 CMP AL,BL
1848 JZ SEPGD
1849 CMP AL,BH
1850 JNZ DATERR
1851SEPGD: CALL GETNUM
1852 JC DATERR
1853 MOV CX,1900
1854 CMP BYTE PTR[SI],13
1855 JZ BIAS
1856 MOV AL,100
1857 MUL AH
1858 MOV CX,AX
1859 CALL GETNUM
1860 JC DATERR
1861BIAS:
1862 MOV AL,AH
1863 MOV AH,0
1864 ADD CX,AX
1865 LODSB
1866 CMP AL,13
1867 JNZ DATERR
1868 MOV AH,SETDATE
1869 INT 33
1870 OR AL,AL
1871 JNZ DATERR
1872 JMP RET90
1873DATERR:
1874 MOV DX,OFFSET TRANGROUP:BADDAT
1875 MOV AH,PRINTBUF
1876 INT 33
1877 JMP GETDAT
1878
1879; TIME gets and sets the time
1880
1881TIME:
1882 MOV SI,81H ;Accepting argument for time inline
1883 CALL SCANOFF
1884 CMP AL,13
1885 JZ PRMTTIM
1886 MOV BX,3A00H+":"
1887 CALL INLINE
1888 JMP COMTIM
1889
1890PRMTTIM:
1891 MOV DX,OFFSET TRANGROUP:CURTIM
1892 MOV AH,PRINTBUF
1893 INT 33 ;Print "Current time is "
1894 MOV AH,GETTIME
1895 INT 33 ;Get time in CX:DX
1896 MOV BL,":"
1897 CALL SHOW
1898GETTIM:
1899 XOR CX,CX ;Initialize hours and minutes to zero
1900 MOV DX,OFFSET TRANGROUP:NEWTIM
1901 MOV BX,3A00H+":"
1902 CALL GETBUF
1903COMTIM: JZ RET100 ;If no time present, don't change it
1904 JC TIMERR
1905 MOV CX,DX
1906 XOR DX,DX
1907 LODSB
1908 CMP AL,13
1909 JZ SAVTIM
1910 CMP AL,BL
1911 JNZ TIMERR
1912 MOV BL,"."
1913 CALL GETNUM
1914 JC TIMERR
1915 MOV DH,AH ;Position seconds
1916 LODSB
1917 CMP AL,13
1918 JZ SAVTIM
1919 CMP AL,BL
1920 JNZ TIMERR
1921 CALL GETNUM
1922 JC TIMERR
1923 MOV DL,AH
1924 LODSB
1925 CMP AL,13
1926 JNZ TIMERR
1927SAVTIM:
1928 MOV AH,SETTIME
1929 INT 33
1930 OR AL,AL
1931 JZ RET100 ;Error in time?
1932TIMERR:
1933 MOV DX,OFFSET TRANGROUP:BADTIM
1934 MOV AH,PRINTBUF
1935 INT 33 ;Print error message
1936 JMP GETTIM ;Try again
1937
1938GETBUF:
1939 MOV AH,PRINTBUF
1940 INT 33 ;Print "Enter new date: "
1941 MOV AH,INBUF
1942 MOV DX,OFFSET TRANGROUP:COMBUF
1943 INT 33 ;Get input line
1944 CALL CRLF2
1945 MOV SI,OFFSET TRANGROUP:COMBUF+2
1946 CMP BYTE PTR[SI],13 ;Check if new date entered
1947 JZ RET100
1948INLINE:
1949 CALL GETNUM ;Get one or two digit number
1950 JC RET100
1951 MOV DH,AH ;Put in position
1952 LODSB
1953 CMP AL,BL
1954 JZ NEXT
1955 CMP BL,":" ;Is it a date seperator?
1956 JNZ DATESEP
1957 DEC SI
1958 MOV DL,0
1959RET100: RET ;Time may have only an hour specified
1960DATESEP:
1961 CMP AL,BH
1962 STC
1963 JNZ RET100
1964NEXT: CALL GETNUM
1965 MOV DL,AH ;Put in position
1966 RET
1967
1968GETNUM:
1969 CALL INDIG
1970 JC RET100
1971 MOV AH,AL ;Save first digit
1972 CALL INDIG ;Another digit?
1973 JC OKRET
1974 AAD ;Convert unpacked BCD to decimal
1975 MOV AH,AL
1976OKRET:
1977 OR AL,1
1978RET110: RET
1979
1980INDIG:
1981 MOV AL,BYTE PTR[SI]
1982 SUB AL,"0"
1983 JC RET110
1984 CMP AL,10
1985 CMC
1986 JC RET110
1987 INC SI
1988 RET
1989
1990SHOW:
1991 MOV AL,CH
1992 MOV BH,"0"-" " ;Enable leading zero suppression
1993 CALL OUT2
1994 MOV AL,BL
1995 CALL OUT
1996 MOV AL,CL
1997 CALL OUT2
1998 MOV AL,BL
1999 CALL OUT
2000 MOV AL,DH
2001 CALL OUT2
2002 CMP BL,":" ;Are we outputting time?
2003 JNZ SKIPIT
2004 MOV AL,"."
2005 CALL OUT
2006SKIPIT: MOV AL,DL
2007OUT2: ;Output binary number as two ASCII digits
2008 AAM ;Convert binary to unpacked BCD
2009 XCHG AL,AH
2010 OR AX,3030H ;Add "0" bias to both digits
2011 CMP AL,"0" ;Is MSD zero?
2012 JNZ NOSUP
2013 SUB AL,BH ;Suppress leading zero if enabled
2014NOSUP:
2015 MOV BH,0 ;Disable zero suppression
2016 CALL OUT
2017 MOV AL,AH
2018OUT:
2019;Print char in AL without affecting registers
2020 XCHG AX,DX
2021 PUSH AX
2022 MOV AH,OUTCH
2023 INT 33
2024 POP AX
2025 XCHG AX,DX
2026 RET
2027
2028EXELOAD:
2029 MOV AX,CS
2030 ADD AX,LOADSEG
2031 MOV [EXEEND],AX ;Store in EXEEND
2032 MOV DX,OFFSET TRANGROUP:RUNVAR ;Read header in here
2033 MOV AH,SETDMA
2034 INT 33
2035 MOV CX,RUNVARSIZ ;Amount of header info we need
2036 MOV DX,OFFSET TRANGROUP:EXEFCB
2037 MOV AH,RDBLK
2038 INT 33 ;Read in header
2039 OR AL,AL
2040 JNZ BADEXE ;Must not reach EOF
2041 MOV AX,[HEADSIZ] ;Size of header in paragraphs
2042;Convert header size to 512-byte pages by multiplying by 32 & rounding up
2043 ADD AX,31 ;Round up first
2044 MOV CL,5
2045 SHR AX,CL ;Multiply by 32
2046 MOV [EXEFCB+RR],AX ;Position in file of program
2047 MOV WORD PTR[EXEFCB+RECLEN],512 ;Set record size
2048 ADD BX,10H ;First paragraph above parameter area
2049 MOV DX,[PAGES] ;Total size of file in 512-byte pages
2050 SUB DX,AX ;Size of program in pages
2051 MOV [PSIZE],DX
2052 SHL DX,CL ;Convert pages back to paragraphs
2053 MOV AX,DX
2054 ADD DX,BX ;Size + start = minimum memory (paragr.)
2055 MOV CX,[EXEEND] ;Get memory size in paragraphs
2056 CMP DX,CX ;Enough memory?
2057 JA SHRTERR
2058 MOV DX,[INITSP]
2059 ADD DX,15
2060 SHR DX,1
2061 SHR DX,1
2062 SHR DX,1
2063 SHR DX,1
2064 ADD DX,[INITSS]
2065 ADD DX,BX ;Adjusted value of SP
2066 CMP DX,CX ;Is it valid?
2067 JA SHRTERR
2068 CMP [LOADLOW],-1 ;Load low or high?
2069 JZ LOAD ;If low, load at segment BX
2070 SUB CX,AX ;Memory size - program size = load addr.
2071 MOV BX,CX
2072LOAD:
2073 MOV BP,BX ;Save load segment
2074LOAD1:
2075LOADSEG EQU (LOAD1-ZERO)/16
2076 PUSH DS
2077 MOV DS,BX
2078 XOR DX,DX ;Address 0 in segment
2079 MOV AH,SETDMA
2080 INT 33 ;Set load address
2081 POP DS
2082 MOV CX,[PSIZE] ;Number of records to read
2083 MOV DX,OFFSET TRANGROUP:EXEFCB
2084 MOV AH,RDBLK
2085 INT 33 ;Read in up to 64K
2086 SUB [PSIZE],CX ;Decrement count by amount read
2087 JZ HAVEXE ;Did we get it all?
2088 TEST AL,1 ;Check return code if not
2089 JNZ BADEXE ;Must be zero if more to come
2090 ADD BX,1000H-20H ;Bump data segment 64K minus one record
2091 JMP SHORT LOAD1 ;Get next 64K block
2092
2093BADEXE:
2094 MOV DX,OFFSET TRANGROUP:EXEBAD
2095 JMP ERROR
2096
2097SHRTERR:
2098 MOV DX,OFFSET TRANGROUP:TOOBIG
2099 JMP ERROR
2100
2101HAVEXE:
2102 MOV AX,[RELTAB] ;Get position of table
2103 MOV [EXEFCB+RR],AX ;Set in random record field
2104 MOV WORD PTR[EXEFCB+RECLEN],1 ;Set one-byte record
2105 MOV DX,OFFSET TRANGROUP:RELPT ;4-byte buffer for relocation address
2106 MOV AH,SETDMA
2107 INT 33
2108 CMP [RELCNT],0
2109 JZ NOREL
2110RELOC:
2111 MOV AH,RDBLK
2112 MOV DX,OFFSET TRANGROUP:EXEFCB
2113 MOV CX,4
2114 INT 33 ;Read in one relocation pointer
2115 OR AL,AL ;Check return code
2116 JNZ BADEXE
2117 MOV DI,[RELPT] ;Get offset of relocation pointer
2118 MOV AX,[RELSEG] ;Get segment
2119 ADD AX,BP ;Bias segment with actual load segment
2120 MOV ES,AX
2121 ADD WORD PTR ES:[DI],BP ;Relocate
2122 DEC [RELCNT] ;Count off
2123 JNZ RELOC
2124;Set up exit conditions
2125NOREL:
2126 MOV AX,[INITSS]
2127 ADD AX,BP
2128 CLI
2129 MOV SS,AX ;Initialize SS
2130 MOV SP,[INITSP]
2131 STI
2132 ADD [INITCS],BP
2133 MOV AX,[TPA] ;Get pointer to parameter area
2134 MOV CX,[BYTCNT] ;Size of TPA segment
2135 MOV ES,AX
2136 MOV DS,AX ;Set segment registers to point to it
2137 CALL SETUP
2138 JMP DWORD PTR CS:[INITIP] ;Long jump to program
2139
2140SETUP:
2141 AND CL,0F0H ;Adjust to even paragraph boundary
2142 MOV AX,WORD PTR DS:[6] ;Get current memory size
2143 SUB AX,CX ;Find out how much we're changing it
2144 MOV WORD PTR DS:[6],CX
2145 MOV CL,4
2146 SAR AX,CL ;Convert to a segment address
2147 ADD WORD PTR DS:[8],AX ;Adjust long jump to go to same place
2148 MOV DX,80H
2149 MOV AH,SETDMA
2150 INT 33 ;Set default disk transfer address
2151 MOV AX,WORD PTR CS:[PARM1] ;Pass on info about FCBs
2152 XOR CX,CX
2153 MOV DX,CX ;Assume no batch file
2154ASSUME CS:RESGROUP
2155 TEST CS:[BATCH],-1 ;Batch file in progress?
2156ASSUME CS:TRANGROUP
2157 JZ RET120 ;If not, all set up
2158 MOV CX,CS:[RESSEG]
2159 MOV DX,OFFSET RESGROUP:BATFCB ;CX:DX points to batch FCB
2160RET120: RET
2161TRANCODESIZE EQU $-ZERO
2162TRANCODE ENDS
2163COMLEN EQU TRANDATASIZE+TRANCODESIZE-102H ;End of COMMAND load. ZERO Needed to make COMLEN absolute
2164TRNLEN EQU (PRETRLEN+TRANCODESIZE+TRANDATASIZE+15)/16 ;Length of transient in paragraphs
2165 END PROGSTART
2166 \ No newline at end of file