mirror of
https://github.com/microsoft/MS-DOS.git
synced 2024-12-02 18:45:48 +00:00
2166 lines
63 KiB
NASM
2166 lines
63 KiB
NASM
; COMMAND version 1.17
|
||
;
|
||
; This version of COMMAND is divided into three distinct parts. First
|
||
; is the resident portion, which includes handlers for interrupts
|
||
; 22H (terminate), 23H (Cntrl-C), 24H (fatal error), and 27H (stay
|
||
; resident); it also has code to test and, if necessary, reload the
|
||
; transient portion. Following the resident is the init code, which is
|
||
; overwritten after use. Then comes the transient portion, which
|
||
; includes all command processing (whether internal or external).
|
||
; The transient portion loads at the end of physical memory, and it may
|
||
; be overlayed by programs that need as much memory as possible. When
|
||
; the resident portion of command regains control from a user program,
|
||
; a checksum is performed on the transient portion to see if it must be
|
||
; reloaded. Thus programs which do not need maximum memory will save
|
||
; the time required to reload COMMAND when they terminate.
|
||
|
||
;Use the following booleans to set assembly flags
|
||
FALSE EQU 0
|
||
TRUE EQU NOT FALSE
|
||
|
||
IBMVER EQU FALSE ;Switch to build IBM version of Command
|
||
MSVER EQU TRUE ;Switch to build MS-DOS version of Command
|
||
|
||
HIGHMEM EQU TRUE ;Run resident part above transient (high memory)
|
||
|
||
LINPERPAG EQU 23
|
||
NORMPERLIN EQU 1
|
||
WIDEPERLIN EQU 5
|
||
|
||
IF IBMVER
|
||
SYM EQU ">"
|
||
COMDRV EQU 1
|
||
ENDIF
|
||
|
||
IF MSVER
|
||
SYM EQU ":"
|
||
COMDRV EQU 0
|
||
ENDIF
|
||
|
||
FCB EQU 5CH
|
||
DSKRESET EQU 13
|
||
SETBASE EQU 38
|
||
SRCHFRST EQU 17
|
||
SRCHNXT EQU 18
|
||
RENAM EQU 23
|
||
INCHAR EQU 1
|
||
GETFAT EQU 27
|
||
OPEN EQU 15
|
||
CLOSE EQU 16
|
||
MAKE EQU 22
|
||
DELETE EQU 19
|
||
RDBLK EQU 39
|
||
WRBLK EQU 40
|
||
SETDMA EQU 26
|
||
SELDRV EQU 14
|
||
GETDRV EQU 25
|
||
PRINTBUF EQU 9
|
||
OUTCH EQU 2
|
||
INBUF EQU 10
|
||
GETDATE EQU 2AH
|
||
SETDATE EQU 2BH
|
||
GETTIME EQU 2CH
|
||
SETTIME EQU 2DH
|
||
RR EQU 33
|
||
RECLEN EQU 14
|
||
FILLEN EQU 16
|
||
OFFDATE EQU 20
|
||
|
||
|
||
;The following are all of the segments used in the load order
|
||
|
||
CODERES SEGMENT
|
||
CODERES ENDS
|
||
|
||
DATARES SEGMENT BYTE
|
||
DATARES ENDS
|
||
|
||
INIT SEGMENT BYTE
|
||
INIT ENDS
|
||
|
||
TAIL SEGMENT PARA
|
||
TAIL ENDS
|
||
|
||
TRANCODE SEGMENT PARA
|
||
TRANCODE ENDS
|
||
|
||
TRANDATA SEGMENT BYTE
|
||
TRANDATA ENDS
|
||
|
||
TRANSPACE SEGMENT BYTE
|
||
TRANSPACE ENDS
|
||
|
||
RESGROUP GROUP CODERES,DATARES,INIT,TAIL
|
||
TRANGROUP GROUP TRANCODE,TRANDATA,TRANSPACE
|
||
|
||
;Data for resident portion
|
||
|
||
DATARES SEGMENT BYTE
|
||
ORG 0
|
||
ZERO = $
|
||
MESBAS DW OFFSET RESGROUP:ERR0
|
||
DW OFFSET RESGROUP:ERR2
|
||
DW OFFSET RESGROUP:ERR4
|
||
DW OFFSET RESGROUP:ERR6
|
||
DW OFFSET RESGROUP:ERR8
|
||
DW OFFSET RESGROUP:ERR10
|
||
DW OFFSET RESGROUP:ERR12
|
||
ERR0 DB "Write protect$"
|
||
ERR2 DB "Not ready$"
|
||
ERR4 DB "Data$"
|
||
ERR6 DB "Seek$"
|
||
ERR8 DB "Sector not found$"
|
||
ERR10 DB "Write fault$"
|
||
ERR12 DB "Disk$"
|
||
READ DB "read$"
|
||
WRITE DB "writ$"
|
||
ERRMES DB " error "
|
||
IOTYP DB "writing"
|
||
DRVNUM DB " drive "
|
||
DRVLET DB "A"
|
||
NEWLIN DB 13,10,"$"
|
||
REQUEST DB "Abort, Retry, Ignore? $"
|
||
BADFAT DB 13,10,"File allocation table bad,$"
|
||
COMBAD DB 13,10,"Invalid COMMAND.COM"
|
||
NEEDCOM DB 13,10,"Insert DOS disk in "
|
||
IF IBMVER
|
||
DB "drive A"
|
||
ELSE
|
||
DB "default drive"
|
||
ENDIF
|
||
PROMPT DB 13,10,"and strike any key when ready",13,10,"$"
|
||
NEEDBAT DB 13,10,"Insert disk with batch file$"
|
||
ENDBATMES DB 13,10,"Terminate batch job (Y/N)? $"
|
||
LOADING DB 0
|
||
BATFCB DB 1,"AUTOEXECBAT"
|
||
DB 21 DUP(?)
|
||
DW 0
|
||
DW 0 ;Initialize RR field to zero
|
||
PARMTAB DW 10 DUP(-1) ;No parameters initially
|
||
BATCH DB 1 ;Assume batch mode initially
|
||
COMFCB DB COMDRV,"COMMAND COM"
|
||
DB 25 DUP(?)
|
||
TRANS DW OFFSET TRANGROUP:COMMAND
|
||
TRNSEG DW ?
|
||
BATBYT DB ?
|
||
MEMSIZ DW ?
|
||
SUM DW ?
|
||
INITADD DB 4 DUP(?)
|
||
RESDATASIZE EQU $-ZERO
|
||
DATARES ENDS
|
||
|
||
;Data for transient portion
|
||
|
||
TRANDATA SEGMENT BYTE
|
||
ORG 0
|
||
ZERO EQU $
|
||
BADNAM DB "Bad command or file name",13,10,"$"
|
||
MISNAM DB "Missing file name$"
|
||
RENERR DB "Duplicate file name or "
|
||
NOTFND DB "File not found$"
|
||
EXEBAD DB "Error in EXE file$"
|
||
NOSPACE DB "Insufficient disk space",13,10,"$"
|
||
FULDIR DB "File creation error",13,10,"$"
|
||
OVERWR DB "File cannot be copied onto itself",13,10,"$"
|
||
LOSTERR DB "Content of destination lost before copy",13,10,"$"
|
||
COPIED DB " File(s) copied$"
|
||
DIRMES DB " File(s)$"
|
||
TOOBIG DB "Program too big to fit in memory$"
|
||
BADDRV DB "Invalid drive specification$"
|
||
PAUSMES DB "Strike a key when ready . . . $"
|
||
BADSWT DB "Illegal switch",13,10,"$"
|
||
WEEKTAB DB "SunMonTueWedThuFriSat"
|
||
BADDAT DB 13,10,"Invalid date$"
|
||
CURDAT DB "Current date is $"
|
||
NEWDAT DB 13,10,"Enter new date: $"
|
||
BADTIM DB 13,10,"Invalid time$"
|
||
CURTIM DB "Current time is $"
|
||
NEWTIM DB 13,10,"Enter new time: $"
|
||
SUREMES DB "Are you sure (Y/N)? $"
|
||
|
||
COMTAB DB 4,"DIR",1
|
||
DW OFFSET TRANGROUP:CATALOG
|
||
DB 7,"RENAME",1
|
||
DW OFFSET TRANGROUP:RENAME
|
||
DB 4,"REN",1
|
||
DW OFFSET TRANGROUP:RENAME
|
||
DB 6,"ERASE",1
|
||
DW OFFSET TRANGROUP:ERASE
|
||
DB 4,"DEL",1
|
||
DW OFFSET TRANGROUP:ERASE
|
||
DB 5,"TYPE",1
|
||
DW OFFSET TRANGROUP:TYPEFIL
|
||
DB 4,"REM",1
|
||
DW OFFSET TRANGROUP:COMMAND
|
||
DB 5,"COPY",1
|
||
DW OFFSET TRANGROUP:COPY
|
||
DB 6,"PAUSE",1
|
||
DW OFFSET TRANGROUP:PAUSE
|
||
DB 5,"DATE",0
|
||
DW OFFSET TRANGROUP:DATE
|
||
DB 5,"TIME",0
|
||
DW OFFSET TRANGROUP:TIME
|
||
DB 0 ;Terminate command table
|
||
|
||
COMBUF DB 128,1,13
|
||
|
||
TRANDATASIZE EQU $-ZERO
|
||
TRANDATA ENDS
|
||
|
||
;Uninitialized transient data
|
||
TRANSPACE SEGMENT BYTE
|
||
ORG 0
|
||
ZERO = $
|
||
DB 128 DUP(?)
|
||
TPA DW 1 DUP(?)
|
||
RESSEG DW 1 DUP(?)
|
||
CHKDRV DB 1 DUP(?)
|
||
FILTYP DB 1 DUP(?)
|
||
CURDRV DB 1 DUP(?)
|
||
PARM1 DB 1 DUP(?)
|
||
PARM2 DB 1 DUP(?)
|
||
COMSW DW 1 DUP(?)
|
||
ARG1S DW 1 DUP(?)
|
||
ARG2S DW 1 DUP(?)
|
||
FLAGER DB 1 DUP(?)
|
||
CFLAG DB 1 DUP(?)
|
||
SPECDRV DB 1 DUP(?)
|
||
BYTCNT DW 1 DUP(?)
|
||
NXTADD DW 1 DUP(?)
|
||
LINCNT DB 1 DUP(?)
|
||
LINLEN DB 1 DUP(?)
|
||
FILECNT DW 1 DUP(?)
|
||
EXEFCB LABEL WORD
|
||
IDLEN DB 1 DUP(?)
|
||
ID DB 8 DUP(?)
|
||
COM DB 3 DUP(?)
|
||
DEST DB 37 DUP(?)
|
||
DESTNAME DB 11 DUP(?)
|
||
DIRBUF DB 37 DUP(?)
|
||
BITS DW 1 DUP(?)
|
||
FULLSCR DW 1 DUP(?)
|
||
EXEEND DW 1 DUP(?)
|
||
;Header variables for EXE file load
|
||
;These are overlapped with COPY variables, below
|
||
RUNVAR LABEL WORD
|
||
RELPT DW 1 DUP(?)
|
||
RELSEG DW 1 DUP(?)
|
||
PSIZE LABEL WORD
|
||
PAGES DW 1 DUP(?)
|
||
RELCNT DW 1 DUP(?)
|
||
HEADSIZ DW 1 DUP(?)
|
||
DW 1 DUP(?)
|
||
LOADLOW DW 1 DUP(?)
|
||
INITSS DW 1 DUP(?)
|
||
INITSP DW 1 DUP(?)
|
||
DW 1 DUP(?)
|
||
INITIP DW 1 DUP(?)
|
||
INITCS DW 1 DUP(?)
|
||
RELTAB DW 1 DUP(?)
|
||
RUNVARSIZ EQU $-RUNVAR
|
||
|
||
DB 80H DUP(?)
|
||
STACK LABEL WORD
|
||
|
||
PRETRLEN EQU $-ZERO ;Used later to compute TRNLEN
|
||
|
||
ORG RUNVAR-ZERO ;Overlaps EXE variables
|
||
|
||
SRCPT DW 1 DUP(?)
|
||
INEXACT DB 1 DUP(?)
|
||
APPEND DB 1 DUP(?)
|
||
NOWRITE DB 1 DUP(?)
|
||
ASCII DB 1 DUP(?)
|
||
PLUS DB 1 DUP(?)
|
||
SOURCE DB 11 DUP(?)
|
||
TRANSPACESIZE EQU $-ZERO
|
||
TRANSPACE ENDS
|
||
|
||
|
||
;START OF RESIDENT PORTION
|
||
|
||
CODERES SEGMENT
|
||
ASSUME CS:RESGROUP,DS:RESGROUP,ES:RESGROUP,SS:RESGROUP
|
||
ORG 0
|
||
ZERO = $
|
||
PARMBUF LABEL WORD
|
||
|
||
ORG 100H
|
||
|
||
RSTACK LABEL WORD
|
||
|
||
PROGSTART:
|
||
JMP CONPROC
|
||
|
||
LTPA DW 0 ;WILL STORE TPA SEGMENT HERE
|
||
MYSEG DW 0 ;Put our own segment here
|
||
|
||
CONTC:
|
||
MOV AX,CS
|
||
MOV DS,AX
|
||
MOV SS,AX
|
||
MOV SP,OFFSET RESGROUP:RSTACK
|
||
STI
|
||
CALL SETVECT
|
||
MOV AH,DSKRESET
|
||
INT 33 ;Reset disks in case files were open
|
||
TEST [BATCH],-1
|
||
JZ LODCOM
|
||
ASKEND:
|
||
MOV DX,OFFSET RESGROUP:ENDBATMES
|
||
MOV AH,PRINTBUF
|
||
INT 33
|
||
MOV AX,0C00H+INCHAR
|
||
INT 33
|
||
AND AL,5FH
|
||
CMP AL,"N"
|
||
JZ LODCOM
|
||
CMP AL,"Y"
|
||
JNZ ASKEND
|
||
MOV [BATCH],0
|
||
LODCOM:
|
||
MOV AX,CS
|
||
MOV SS,AX
|
||
MOV SP,OFFSET RESGROUP:RSTACK
|
||
MOV DS,AX
|
||
CALL SETVECT
|
||
CALL CHKSUM
|
||
CMP DX,[SUM]
|
||
JZ HAVCOM
|
||
MOV [LOADING],1
|
||
CALL LOADCOM
|
||
CHKSAME:
|
||
CALL CHKSUM
|
||
CMP DX,[SUM]
|
||
JZ HAVCOM
|
||
CALL WRONGCOM
|
||
JMP SHORT CHKSAME
|
||
HAVCOM:
|
||
MOV [LOADING],0
|
||
MOV SI,OFFSET RESGROUP:LTPA
|
||
MOV DI,OFFSET TRANGROUP:TPA
|
||
MOV ES,[TRNSEG]
|
||
CLD
|
||
MOVSW ;Move TPA segment to transient storage
|
||
MOVSW ;Move resident segment too
|
||
MOV AX,[MEMSIZ]
|
||
MOV WORD PTR ES:[2],AX
|
||
JMP DWORD PTR [TRANS]
|
||
|
||
RESIDENT:
|
||
ADD DX,15
|
||
MOV CL,4
|
||
SHR DX,CL ;Number of paragraphs of new addition
|
||
ADD CS:[LTPA],DX
|
||
XOR AX,AX
|
||
MOV DS,AX
|
||
JMP DWORD PTR DS:[80H] ;Pretend user executed INT 20H
|
||
|
||
DSKERR:
|
||
;******************************************************
|
||
; THIS IS THE DEFAULT DISK ERROR HANDLING CODE
|
||
; AVAILABLE TO ALL USERS IF THEY DO NOT TRY TO
|
||
; INTERCEPT INTERRUPT 24H.
|
||
;******************************************************
|
||
STI
|
||
PUSH DS
|
||
PUSH CS
|
||
POP DS ;Set up local data segment
|
||
PUSH DX
|
||
CALL CRLF
|
||
POP DX
|
||
ADD AL,"A" ;Compute drive letter
|
||
MOV [DRVLET],AL
|
||
TEST AH,80H ;Check if hard disk error
|
||
JNZ FATERR
|
||
MOV SI,OFFSET RESGROUP:READ
|
||
TEST AH,1
|
||
JZ SAVMES
|
||
MOV SI,OFFSET RESGROUP:WRITE
|
||
SAVMES:
|
||
LODSW
|
||
MOV WORD PTR [IOTYP],AX
|
||
LODSW
|
||
MOV WORD PTR [IOTYP+2],AX
|
||
AND DI,0FFH
|
||
CMP DI,12
|
||
JBE HAVCOD
|
||
MOV DI,12
|
||
HAVCOD:
|
||
MOV DI,WORD PTR [DI+MESBAS] ;Get pointer to error message
|
||
XCHG DI,DX ;May need DX later
|
||
MOV AH,PRINTBUF
|
||
INT 33 ;Print error type
|
||
MOV DX,OFFSET RESGROUP:ERRMES
|
||
INT 33
|
||
CMP [LOADING],0
|
||
JNZ GETCOMDSK
|
||
ASK:
|
||
MOV DX,OFFSET RESGROUP:REQUEST
|
||
MOV AH,PRINTBUF
|
||
INT 33
|
||
MOV AX,0C00H+INCHAR
|
||
INT 33 ;Get response
|
||
CALL CRLF
|
||
OR AL,20H ;Convert to lower case
|
||
MOV AH,0 ;Return code for ignore
|
||
CMP AL,"i" ;Ignore?
|
||
JZ EXIT
|
||
INC AH
|
||
CMP AL,"r" ;Retry?
|
||
JZ EXIT
|
||
INC AH
|
||
CMP AL,"a" ;Abort?
|
||
JNZ ASK
|
||
EXIT:
|
||
MOV AL,AH
|
||
MOV DX,DI
|
||
POP DS
|
||
IRET
|
||
|
||
FATERR:
|
||
MOV DX,OFFSET RESGROUP:BADFAT
|
||
MOV AH,PRINTBUF
|
||
INT 33
|
||
MOV DX,OFFSET RESGROUP:DRVNUM
|
||
INT 33
|
||
MOV AL,2 ;Abort
|
||
POP DS
|
||
IRET
|
||
|
||
GETCOMDSK:
|
||
MOV DX,OFFSET RESGROUP:NEEDCOM
|
||
MOV AH,PRINTBUF
|
||
INT 33
|
||
MOV AX,0C07H ;Get char without testing or echo
|
||
INT 33
|
||
JMP LODCOM
|
||
|
||
CRLF:
|
||
MOV DX,OFFSET RESGROUP:NEWLIN
|
||
PUSH AX
|
||
MOV AH,PRINTBUF
|
||
INT 33
|
||
POP AX
|
||
RET10: RET
|
||
|
||
LOADCOM:
|
||
PUSH DS
|
||
MOV DS,[TRNSEG]
|
||
MOV DX,100H
|
||
MOV AH,SETDMA
|
||
INT 33
|
||
POP DS
|
||
MOV DX,OFFSET RESGROUP:COMFCB
|
||
MOV AH,OPEN
|
||
INT 33 ;Open COMMAND.COM
|
||
OR AL,AL
|
||
JZ READCOM
|
||
MOV DX,OFFSET RESGROUP:NEEDCOM
|
||
PROMPTCOM:
|
||
MOV AH,PRINTBUF
|
||
INT 33
|
||
MOV AX,0C07H ;Get char without testing or echo
|
||
INT 33
|
||
JMP SHORT LOADCOM
|
||
READCOM:
|
||
MOV WORD PTR[COMFCB+RR],OFFSET RESGROUP:TRANSTART
|
||
XOR AX,AX
|
||
MOV WORD PTR[COMFCB+RR+2],AX
|
||
MOV [COMFCB],AL ;Use default drive
|
||
INC AX
|
||
MOV WORD PTR[COMFCB+RECLEN],AX
|
||
MOV CX,COMLEN
|
||
MOV DX,OFFSET RESGROUP:COMFCB
|
||
MOV AH,RDBLK
|
||
INT 33
|
||
OR AL,AL
|
||
JZ RET10
|
||
WRONGCOM:
|
||
MOV DX,OFFSET RESGROUP:COMBAD
|
||
JMP SHORT PROMPTCOM
|
||
|
||
CHKSUM:
|
||
CLD
|
||
PUSH DS
|
||
MOV DS,[TRNSEG]
|
||
MOV SI,100H
|
||
MOV CX,COMLEN
|
||
SHR CX,1
|
||
XOR DX,DX
|
||
CHK:
|
||
LODSW
|
||
ADD DX,AX
|
||
LOOP CHK
|
||
POP DS
|
||
RET
|
||
|
||
SETVECT:
|
||
MOV DX,OFFSET RESGROUP:LODCOM
|
||
MOV AX,2522H ;Set Terminate address
|
||
INT 21H
|
||
MOV DX,OFFSET RESGROUP:CONTC
|
||
MOV AX,2523H ;Set Ctrl-C address
|
||
INT 21H
|
||
MOV DX,OFFSET RESGROUP:DSKERR
|
||
MOV AX,2524H ;Set Hard Disk Error address
|
||
INT 33
|
||
MOV DX,OFFSET RESGROUP:RESIDENT
|
||
MOV AX,2527H ;Set Terminate and Stay Resident address
|
||
INT 33
|
||
RET
|
||
RESCODESIZE EQU $-ZERO
|
||
CODERES ENDS
|
||
|
||
;*******************************************************************
|
||
;START OF INIT PORTION
|
||
;This code is overlayed the first time the TPA is used.
|
||
|
||
INIT SEGMENT BYTE
|
||
|
||
ORG 0
|
||
ZERO = $
|
||
CONPROC:
|
||
MOV SP,OFFSET RESGROUP:RSTACK
|
||
|
||
IF HIGHMEM
|
||
MOV AX,WORD PTR DS:[2]
|
||
SUB AX,((RESCODESIZE+RESDATASIZE)+15)/16 ;Subtract size of resident
|
||
MOV WORD PTR DS:[2],AX
|
||
MOV ES,AX
|
||
MOV SI,100H
|
||
MOV DI,SI
|
||
MOV CX,((RESCODESIZE+RESDATASIZE)-100H+1)/2 ;Length of resident in words
|
||
REP MOVSW ;Move to end of memory
|
||
MOV DS,AX
|
||
MOV [LTPA],CS
|
||
ENDIF
|
||
|
||
IF NOT HIGHMEM
|
||
MOV AX,CS
|
||
ADD AX,((RESCODESIZE+RESDATASIZE)+15)/16 ;Compute segment of TPA
|
||
MOV [LTPA],AX
|
||
MOV AX,WORD PTR DS:[2]
|
||
ENDIF
|
||
|
||
MOV [MYSEG],DS
|
||
MOV [MEMSIZ],AX
|
||
SUB AX,TRNLEN ;Subtract size of transient
|
||
MOV [TRNSEG],AX
|
||
CALL SETVECT
|
||
CALL LOADCOM
|
||
CALL CHKSUM
|
||
MOV [SUM],DX
|
||
|
||
IF MSVER
|
||
IF HIGHMEM
|
||
PUSH DS
|
||
PUSH CS
|
||
POP DS
|
||
ENDIF
|
||
MOV DX,OFFSET RESGROUP:HEADER
|
||
MOV AH,PRINTBUF
|
||
INT 33
|
||
IF HIGHMEM
|
||
POP DS
|
||
ENDIF
|
||
ENDIF
|
||
|
||
MOV DX,OFFSET RESGROUP:BATFCB
|
||
MOV AH,OPEN
|
||
INT 33 ;See if AUTOEXEC.BAT exists
|
||
MOV WORD PTR[BATFCB+RECLEN],1 ;Set record length to 1
|
||
OR AL,AL ;Zero means file found
|
||
JZ DRV0
|
||
MOV [BATCH],0 ;Not found--turn off batch job
|
||
MOV AX,OFFSET TRANGROUP:DATINIT
|
||
MOV WORD PTR[INITADD],AX
|
||
MOV AX,[TRNSEG]
|
||
MOV WORD PTR[INITADD+2],AX
|
||
CALL DWORD PTR DS:[INITADD]
|
||
|
||
IF IBMVER
|
||
MOV DX,OFFSET RESGROUP:HEADER
|
||
MOV AH,PRINTBUF
|
||
INT 33
|
||
ENDIF
|
||
|
||
DRV0:
|
||
JMP HAVCOM
|
||
|
||
|
||
IF MSVER
|
||
HEADER DB 13,10,"Command v. 1.17"
|
||
IF HIGHMEM
|
||
DB "H"
|
||
ENDIF
|
||
DB 13,10,"$"
|
||
ENDIF
|
||
|
||
IF IBMVER
|
||
HEADER DB 13,10,13,10,"The IBM Personal Computer DOS",13,10
|
||
DB "Version 1.10 (C)Copyright IBM Corp 1981, 1982",13,10,"$"
|
||
DB "Licensed Material - Program Property of IBM"
|
||
ENDIF
|
||
|
||
INITSIZE EQU $-ZERO
|
||
INIT ENDS
|
||
|
||
;This TAIL segment is used to produce a PARA aligned label in the resident
|
||
; group which is the location where the transient segments will be loaded
|
||
; initialy.
|
||
|
||
TAIL SEGMENT PARA
|
||
ORG 0
|
||
TRANSTART LABEL WORD
|
||
TAIL ENDS
|
||
|
||
;********************************************************************
|
||
;START OF TRANSIENT PORTION
|
||
;This code is loaded at the end of memory and may be overwritten by
|
||
;memory-intensive user programs.
|
||
|
||
TRANCODE SEGMENT PARA
|
||
ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP,SS:TRANGROUP
|
||
|
||
WSWITCH EQU 1 ;Wide display during DIR
|
||
PSWITCH EQU 2 ;Pause (or Page) mode during DIR
|
||
VSWITCH EQU 4 ;Verify during COPY
|
||
ASWITCH EQU 8 ;ASCII mode during COPY
|
||
BSWITCH EQU 10H ;Binary mode during COPY
|
||
|
||
ORG 0
|
||
ZERO = $
|
||
|
||
ORG 100H ;Allow for 100H parameter area
|
||
|
||
SETDRV:
|
||
MOV AH,SELDRV
|
||
INT 21H
|
||
COMMAND:
|
||
CLD
|
||
MOV AX,CS
|
||
MOV SS,AX
|
||
MOV SP,OFFSET TRANGROUP:STACK
|
||
MOV ES,AX
|
||
MOV DS,AX
|
||
STI
|
||
MOV AX,46*100H
|
||
MOV DL,0
|
||
INT 33 ;Turn off verify after write
|
||
MOV AX,CS ;Get segment we're in
|
||
SUB AX,[TPA] ;AX=size ot TPA in paragraphs
|
||
MOV DX,16
|
||
MUL DX ;DX:AX=size of TPA in bytes
|
||
OR DX,DX ;See if over 64K
|
||
JZ SAVSIZ ;OK if not
|
||
MOV AX,-1 ;If so, limit to 65535 bytes
|
||
SAVSIZ:
|
||
MOV [BYTCNT],AX ;Max no. of bytes that can be buffered
|
||
CALL CRLF2
|
||
GETCOM:
|
||
MOV AH,GETDRV
|
||
INT 21H
|
||
MOV [CURDRV],AL
|
||
ADD AL,"A"
|
||
CALL OUT ;Print letter for default drive
|
||
MOV AL,SYM
|
||
CALL OUT
|
||
MOV DS,[RESSEG] ;All batch work must use resident seg.
|
||
ASSUME DS:RESGROUP
|
||
TEST [BATCH],-1
|
||
JNZ READBAT
|
||
PUSH CS
|
||
POP DS ;Need local segment to point to buffer
|
||
ASSUME DS:TRANGROUP
|
||
MOV DX,OFFSET TRANGROUP:COMBUF
|
||
MOV AH,INBUF
|
||
INT 21H ;Get a command
|
||
JMP DOCOM
|
||
|
||
;All batch proccessing has DS set to segment of resident portion
|
||
ASSUME DS:RESGROUP
|
||
NEEDPARM:
|
||
CALL GETBATBYT
|
||
CMP AL,"%" ;Check for two consecutive %
|
||
JZ SAVBATBYT
|
||
CMP AL,13 ;Check for end-of-line
|
||
JZ SAVBATBYT
|
||
SUB AL,"0"
|
||
JB RDBAT ;Ignore parameter reference if invalid
|
||
CMP AL,9
|
||
JA RDBAT
|
||
CBW
|
||
MOV SI,AX
|
||
SHL SI,1 ;Two bytes per entry
|
||
MOV SI,[SI+OFFSET RESGROUP:PARMTAB] ;Get pointer to corresponding parameter
|
||
CMP SI,-1 ;Check if parameter exists
|
||
JZ RDBAT ;Ignore if it doesn't
|
||
MOV AH,OUTCH
|
||
RDPARM:
|
||
LODSB ;From resident segment
|
||
CMP AL,0DH ;Check for end of parameter
|
||
JZ RDBAT
|
||
STOSB ;To transient segment
|
||
MOV DL,AL
|
||
INT 33 ;Display paramters too
|
||
JMP SHORT RDPARM
|
||
|
||
PROMPTBAT:
|
||
MOV AH,PRINTBUF
|
||
MOV DX,OFFSET RESGROUP:NEEDBAT
|
||
INT 33 ;Prompt for batch file
|
||
MOV AH,PRINTBUF
|
||
MOV DX,OFFSET RESGROUP:PROMPT
|
||
INT 33
|
||
MOV AX,0C00H+INCHAR
|
||
INT 33
|
||
JMP COMMAND
|
||
|
||
BADCOMJ1:JMP BADCOM
|
||
|
||
READBAT:
|
||
MOV DX,OFFSET RESGROUP:BATFCB
|
||
MOV AH,OPEN
|
||
INT 33 ;Make sure batch file still exists
|
||
OR AL,AL
|
||
JNZ PROMPTBAT ;If OPEN fails, prompt for disk
|
||
MOV WORD PTR [BATFCB+RECLEN],1
|
||
MOV DX,OFFSET RESGROUP:BATBYT
|
||
MOV AH,SETDMA
|
||
INT 33
|
||
MOV DI,OFFSET TRANGROUP:COMBUF+2
|
||
RDBAT:
|
||
CALL GETBATBYT
|
||
CMP AL,"%" ;Check for parameter
|
||
JZ NEEDPARM
|
||
SAVBATBYT:
|
||
STOSB
|
||
CALL OUT ;Display batched command line
|
||
CMP AL,0DH
|
||
JNZ RDBAT
|
||
SUB DI,OFFSET TRANGROUP:COMBUF+3
|
||
MOV AX,DI
|
||
MOV ES:[COMBUF+1],AL ;Set length of line
|
||
CALL GETBATBYT ;Eat linefeed
|
||
PUSH CS
|
||
POP DS ;Go back to local segment
|
||
ASSUME DS:TRANGROUP
|
||
DOCOM:
|
||
;All segments are local for command line processing
|
||
MOV AL,10
|
||
CALL OUT
|
||
MOV SI,OFFSET TRANGROUP:COMBUF+2
|
||
MOV DI,OFFSET TRANGROUP:IDLEN
|
||
MOV AX,2901H ;Make FCB with blank scan-off
|
||
INT 21H
|
||
CMP AL,1 ;Check for ambiguous command name
|
||
JZ BADCOMJ1 ;Ambiguous commands not allowed
|
||
CMP AL,-1
|
||
JNZ DRVGD
|
||
JMP DRVBAD
|
||
DRVGD:
|
||
MOV AL,[DI]
|
||
MOV [SPECDRV],AL
|
||
MOV AL," "
|
||
MOV CX,9
|
||
INC DI
|
||
REPNE SCASB ;Count no. of letters in command name
|
||
MOV AL,9
|
||
SUB AL,CL
|
||
MOV [IDLEN],AL
|
||
MOV DI,81H
|
||
MOV CX,0
|
||
PUSH SI
|
||
COMTAIL:
|
||
LODSB
|
||
STOSB ;Move command tail to 80H
|
||
CMP AL,13
|
||
LOOPNZ COMTAIL
|
||
NOT CL
|
||
MOV BYTE PTR DS:[80H],CL
|
||
POP SI
|
||
;If the command has 0 parameters must check here for
|
||
;any switches that might be present.
|
||
;SI -> first character after the command.
|
||
MOV [FLAGER],0 ;Set error flag before any calls to switch
|
||
CALL SWITCH ;Is the next character a "/"
|
||
MOV [COMSW],AX
|
||
MOV DI,FCB
|
||
MOV AX,2901H
|
||
INT 21H
|
||
MOV [PARM1],AL ;Save result of parse
|
||
CALL SWITCH
|
||
MOV [ARG1S],AX
|
||
MOV DI,FCB+10H
|
||
MOV AX,2901H
|
||
INT 21H ;Parse file name
|
||
MOV [PARM2],AL ;Save result
|
||
CALL SWITCH
|
||
MOV [ARG2S],AX
|
||
MOV AL,[IDLEN]
|
||
MOV DL,[SPECDRV]
|
||
OR DL,DL ;Check if drive was specified
|
||
JZ OK
|
||
JMP DRVCHK
|
||
OK: DEC AL ;Check for null command
|
||
JNZ FNDCOM
|
||
JMP GETCOM
|
||
|
||
RETSW:
|
||
XCHG AX,BX ;Put switches in AX
|
||
RET
|
||
|
||
SWITCH:
|
||
XOR BX,BX ;Initialize - no switches set
|
||
SWLOOP:
|
||
CALL SCANOFF ;Skip any delimiters
|
||
CMP AL,"/" ;Is it a switch specifier?
|
||
JNZ RETSW ;No -- we're finished
|
||
INC SI ;Skip over "/"
|
||
CALL SCANOFF
|
||
INC SI
|
||
;Convert lower case input to upper case
|
||
CMP AL,"a"
|
||
JB SAVCHR
|
||
CMP AL,"z"
|
||
JA SAVCHR
|
||
SUB AL,20H ;Lower-case changed to upper-case
|
||
SAVCHR:
|
||
MOV DI,OFFSET TRANGROUP:SWLIST
|
||
MOV CX,SWCOUNT
|
||
REPNE SCASB ;Look for matching switch
|
||
JNZ BADSW
|
||
MOV AX,1
|
||
SHL AX,CL ;Set a bit for the switch
|
||
OR BX,AX
|
||
JMP SHORT SWLOOP
|
||
|
||
BADSW:
|
||
MOV [FLAGER],1 ;Record error in switch
|
||
JMP SHORT SWLOOP
|
||
|
||
SWLIST DB "BAVPW"
|
||
SWCOUNT EQU $-SWLIST
|
||
|
||
DRVBAD:
|
||
MOV DX,OFFSET TRANGROUP:BADDRV
|
||
JMP ERROR
|
||
|
||
FNDCOM:
|
||
MOV SI,OFFSET TRANGROUP:COMTAB ;Prepare to search command table
|
||
MOV CH,0
|
||
FINDCOM:
|
||
MOV DI,OFFSET TRANGROUP:IDLEN
|
||
MOV CL,[SI]
|
||
JCXZ EXTERNAL
|
||
REPE CMPSB
|
||
LAHF
|
||
ADD SI,CX ;Bump to next position without affecting flags
|
||
SAHF
|
||
LODSB ;Get flag for drive check
|
||
MOV [CHKDRV],AL
|
||
LODSW ;Get address of command
|
||
JNZ FINDCOM
|
||
MOV DX,AX
|
||
CMP [CHKDRV],0
|
||
JZ NOCHECK
|
||
MOV AL,[PARM1]
|
||
OR AL,[PARM2] ;Check if either parm. had invalid drive
|
||
CMP AL,-1
|
||
JZ DRVBAD
|
||
NOCHECK:CALL DX
|
||
COMJMP: JMP COMMAND
|
||
|
||
BADCOMJ:JMP BADCOM
|
||
|
||
SETDRV1:
|
||
JMP SETDRV
|
||
|
||
DRVCHK:
|
||
DEC DL ;Adjust for correct drive number
|
||
DEC AL ;Check if anything else is on line
|
||
JZ SETDRV1
|
||
EXTERNAL:
|
||
MOV AL,[SPECDRV]
|
||
MOV [IDLEN],AL
|
||
MOV WORD PTR[COM],4F00H+"C" ;"CO"
|
||
MOV BYTE PTR[COM+2],"M"
|
||
MOV DX,OFFSET TRANGROUP:IDLEN
|
||
MOV AH,OPEN
|
||
INT 33 ;Check if command to be executed
|
||
MOV [FILTYP],AL ;0 for COM files, -1 for EXE files
|
||
OR AL,AL
|
||
JZ EXECUTE
|
||
MOV WORD PTR[COM],5800H+"E" ;"EX"
|
||
MOV BYTE PTR[COM+2],"E"
|
||
INT 33 ;Check for EXE file
|
||
OR AL,AL
|
||
JZ EXECUTE
|
||
MOV WORD PTR[COM],4100H+"B" ;"BA"
|
||
MOV BYTE PTR[COM+2],"T"
|
||
INT 33 ;Check if batch file to be executed
|
||
OR AL,AL
|
||
JNZ BADCOMJ
|
||
BATCOM:
|
||
;Batch parameters are read with ES set to segment of resident part
|
||
MOV ES,[RESSEG]
|
||
ASSUME ES:RESGROUP
|
||
MOV DI,OFFSET RESGROUP:PARMTAB
|
||
MOV AX,-1
|
||
MOV CX,10
|
||
REP STOSW ;Zero parameter pointer table
|
||
MOV SI,OFFSET TRANGROUP:COMBUF+2
|
||
MOV DI,OFFSET RESGROUP:PARMBUF
|
||
MOV BX,OFFSET RESGROUP:PARMTAB
|
||
EACHPARM:
|
||
CALL SCANOFF
|
||
CMP AL,0DH
|
||
JZ HAVPARM
|
||
MOV ES:[BX],DI ;Set pointer table to point to actual parameter
|
||
INC BX
|
||
INC BX
|
||
MOVPARM:
|
||
LODSB
|
||
CALL DELIM
|
||
JZ ENDPARM ;Check for end of parameter
|
||
STOSB
|
||
CMP AL,0DH
|
||
JZ HAVPARM
|
||
JMP SHORT MOVPARM
|
||
ENDPARM:
|
||
MOV AL,0DH
|
||
STOSB ;End-of-parameter marker
|
||
CMP BX,OFFSET RESGROUP:PARMTAB+20 ;Maximum number of parameters?
|
||
JB EACHPARM
|
||
HAVPARM:
|
||
MOV SI,OFFSET TRANGROUP:IDLEN
|
||
MOV DI,OFFSET RESGROUP:BATFCB
|
||
MOV CX,16
|
||
REP MOVSW ;Move into private batch FCB
|
||
XOR AX,AX
|
||
PUSH ES
|
||
POP DS ;Simply batch FCB setup
|
||
ASSUME DS:RESGROUP
|
||
MOV WORD PTR[BATFCB+RR],AX
|
||
MOV WORD PTR[BATFCB+RR+2],AX ;Zero RR field
|
||
INC AX
|
||
MOV WORD PTR[BATFCB+RECLEN],AX ;Set record length to 1 byte
|
||
MOV [BATCH],AL ;Flag batch job in progress
|
||
JMP COMMAND
|
||
ASSUME DS:TRANGROUP,ES:TRANGROUP
|
||
|
||
EXECUTE:
|
||
MOV AX,WORD PTR[IDLEN+16]
|
||
OR AX,WORD PTR[IDLEN+18] ;See if zero length
|
||
JZ BADCOM ;If so, error
|
||
XOR AX,AX
|
||
MOV WORD PTR[IDLEN+RR],AX
|
||
MOV WORD PTR[IDLEN+RR+2],AX ;Set RR field to zero
|
||
INC AX
|
||
MOV WORD PTR[IDLEN+RECLEN],AX ;Set record length field to 1
|
||
MOV DX,[TPA]
|
||
MOV BX,DX
|
||
MOV AH,SETBASE
|
||
INT 21H
|
||
TEST [FILTYP],-1 ;Check if file is COM or EXE
|
||
JZ COMLOAD
|
||
JMP EXELOAD
|
||
COMLOAD:PUSH DS
|
||
MOV DS,DX
|
||
MOV DX,100H
|
||
MOV AH,SETDMA
|
||
INT 21H
|
||
POP DS
|
||
MOV CX,[BYTCNT]
|
||
SUB CX,100H
|
||
MOV DX,OFFSET TRANGROUP:IDLEN
|
||
MOV AH,RDBLK
|
||
INT 21H
|
||
DEC AL
|
||
MOV DX,OFFSET TRANGROUP:TOOBIG
|
||
JNZ ERROR
|
||
;Set up exit conditions
|
||
MOV CX,[BYTCNT]
|
||
MOV DS,BX
|
||
MOV ES,BX
|
||
CLI
|
||
MOV SS,BX
|
||
MOV SP,CX
|
||
STI
|
||
SUB CX,100H ;Allow some stack space
|
||
XOR AX,AX
|
||
PUSH AX
|
||
MOV AX,100H
|
||
PUSH BX
|
||
PUSH AX
|
||
CALL SETUP
|
||
XXX PROC FAR
|
||
RET
|
||
XXX ENDP
|
||
BADCOM:
|
||
MOV DX,OFFSET TRANGROUP:BADNAM
|
||
ERROR:
|
||
MOV AH,PRINTBUF
|
||
INT 21H
|
||
JMP COMMAND
|
||
|
||
CHKCNT:
|
||
TEST [FILECNT],-1
|
||
JNZ ENDDIR
|
||
MOV DX,OFFSET TRANGROUP:NOTFND
|
||
JMP ERROR
|
||
|
||
ENDDIR:
|
||
;Make sure last line ends with CR/LF
|
||
MOV AL,[LINLEN]
|
||
CMP AL,[LINCNT] ;Will be equal if just had CR/LF
|
||
JZ MESSAGE
|
||
CALL CRLF2
|
||
MESSAGE:
|
||
MOV SI,[FILECNT]
|
||
XOR DI,DI
|
||
CALL DISP32BITS
|
||
MOV DX,OFFSET TRANGROUP:DIRMES
|
||
MOV AH,PRINTBUF
|
||
INT 21H
|
||
RET
|
||
|
||
CATALOG:
|
||
MOV AL,"?" ;*.* is default file spec.
|
||
MOV DI,5DH
|
||
MOV CX,11
|
||
REP STOSB
|
||
MOV SI,81H
|
||
CALL SWITCH
|
||
MOV DI,5CH
|
||
MOV AX,41*100H+0DH ;Parse with default name and extension
|
||
INT 33
|
||
|
||
;Begin by processing any switches that may have been specified.
|
||
;BITS will contain any information about switches that was
|
||
;found when the command line was parsed.
|
||
|
||
SETSWT:
|
||
MOV AX,[COMSW] ;Get switches from command
|
||
OR AX,[ARG1S] ;OR in switches from first parameter
|
||
MOV [BITS],AX
|
||
MOV BYTE PTR[FULLSCR],LINPERPAG
|
||
TEST AL,1 ;Look for /W
|
||
MOV AL,NORMPERLIN
|
||
JZ DIR
|
||
MOV AL,WIDEPERLIN
|
||
DIR:
|
||
MOV [LINLEN],AL ;Set number of entries per line
|
||
MOV [LINCNT],AL
|
||
MOV [FILECNT],0 ;Keep track of how many files found
|
||
MOV DX,OFFSET TRANGROUP:DIRBUF ;Set Disk transfer address
|
||
MOV AH,SETDMA
|
||
INT 21H
|
||
MOV AH,SRCHFRST
|
||
SHOWDIR:
|
||
MOV DX,5CH ;DX -> Unopened FCB
|
||
INT 21H ;Search for a file to match FCB
|
||
INC AL ;FF = file not found
|
||
JNZ AGAIN ;Either an error or we are finished
|
||
JMP CHKCNT
|
||
AGAIN:
|
||
INC [FILECNT] ;Keep track of how many we find
|
||
MOV SI,OFFSET TRANGROUP:DIRBUF+1 ;SI -> information returned by sys call
|
||
CALL SHONAME
|
||
TEST BYTE PTR[BITS],1 ;/W set?
|
||
JNZ NEXENT ;If so, no size, date, or time
|
||
CALL DISPSIZE ;Print size of file
|
||
CALL TWOSPC
|
||
MOV AX,WORD PTR[DIRBUF+25] ;Get date
|
||
OR AX,AX
|
||
JZ NEXENT ;Skip if no date
|
||
MOV DX,AX
|
||
MOV CL,5
|
||
SHR AX,CL ;Align month
|
||
AND AL,0FH
|
||
MOV BH,"0"-" " ;Enable zero suppression
|
||
CALL OUT2
|
||
MOV AL,"-"
|
||
CALL OUT
|
||
MOV AL,DL
|
||
AND AL,1FH ;Mask to day
|
||
CALL OUT2
|
||
MOV AL,"-"
|
||
CALL OUT
|
||
MOV AL,DH
|
||
SHR AL,1 ;Align year
|
||
ADD AX,80 ;Relative 1980
|
||
CMP AL,100
|
||
JB MILLENIUM
|
||
SUB AL,100
|
||
MILLENIUM:
|
||
CALL OUT2
|
||
MOV BX,WORD PTR[DIRBUF+23] ;Get time
|
||
OR BX,BX ;Time field present?
|
||
JZ NEXENT
|
||
CALL TWOSPC
|
||
SHR BX,1
|
||
SHR BX,1
|
||
SHR BX,1
|
||
SHR BL,1
|
||
SHR BL,1 ;Hours in BH, minutes in BL
|
||
MOV AL,BH
|
||
MOV DH,"a" ;Assume A.M.
|
||
CMP AL,12 ;In the afternoon?
|
||
JB MORN
|
||
MOV DH,"p"
|
||
JE MORN
|
||
SUB AL,12 ;Keep it to 12 hours or less
|
||
MORN:
|
||
OR AL,AL ;Before 1 am?
|
||
JNZ SHOHOURS
|
||
MOV AL,12
|
||
SHOHOURS:
|
||
MOV BH,"0"-" " ;Enable zero suppression
|
||
CALL OUT2
|
||
MOV AL,":"
|
||
CALL OUT
|
||
MOV AL,BL ;Output minutes
|
||
CALL OUT2
|
||
MOV AL,DH ;Get "a" or "p"
|
||
CALL OUT
|
||
NEXENT:
|
||
DEC [LINCNT]
|
||
JNZ SAMLIN
|
||
NEXLIN:
|
||
MOV AL,[LINLEN]
|
||
MOV [LINCNT],AL
|
||
CALL CRLF2
|
||
TEST BYTE PTR[BITS],2 ;/P switch present?
|
||
JZ SCROLL ;If not, just continue
|
||
DEC BYTE PTR[FULLSCR]
|
||
JNZ SCROLL
|
||
MOV BYTE PTR[FULLSCR],LINPERPAG
|
||
MOV AH,PRINTBUF
|
||
MOV DX,OFFSET TRANGROUP:PAUSMES
|
||
INT 33
|
||
MOV AX,0C08H ;Wait for any character to be typed
|
||
INT 21H
|
||
CALL CRLF2
|
||
SCROLL:
|
||
MOV AH,SRCHNXT
|
||
JMP SHOWDIR
|
||
|
||
SAMLIN:
|
||
MOV AL,9 ;Output a tab
|
||
CALL OUT
|
||
JMP SHORT SCROLL
|
||
|
||
SHONAME:
|
||
MOV CX,8
|
||
CALL OUTCNT
|
||
CALL ONESPC
|
||
MOV CX,3
|
||
OUTCNT:
|
||
LODSB
|
||
CALL OUT
|
||
LOOP OUTCNT
|
||
RET
|
||
|
||
TWOSPC:
|
||
CALL ONESPC
|
||
ONESPC:
|
||
MOV AL," "
|
||
JMP OUT
|
||
|
||
CRLF2:
|
||
MOV AL,13
|
||
CALL OUT
|
||
MOV AL,10
|
||
JMP OUT
|
||
|
||
DISPSIZE:
|
||
MOV SI,WORD PTR[DIRBUF+29]
|
||
MOV DI,WORD PTR[DIRBUF+31]
|
||
DISP32BITS:
|
||
;Prints the 32-bit number DI:SI on the console in decimal. Uses a total
|
||
;of 9 digit positions with leading blanks.
|
||
XOR AX,AX
|
||
MOV BX,AX
|
||
MOV BP,AX
|
||
MOV CX,32
|
||
CONVLP:
|
||
SHL SI,1
|
||
RCL DI,1
|
||
XCHG AX,BP
|
||
CALL CONVWRD
|
||
XCHG AX,BP
|
||
XCHG AX,BX
|
||
CALL CONVWRD
|
||
XCHG AX,BX
|
||
ADC AL,0
|
||
LOOP CONVLP
|
||
; Conversion complete. Print 9-digit number.
|
||
MOV CX,1810H ;Allow leading zero blanking for 8 digits
|
||
XCHG DX,AX
|
||
CALL DIGIT
|
||
XCHG AX,BX
|
||
CALL OUTWORD
|
||
XCHG AX,BP
|
||
OUTWORD:
|
||
PUSH AX
|
||
MOV DL,AH
|
||
CALL OUTBYTE
|
||
POP DX
|
||
OUTBYTE:
|
||
MOV DH,DL
|
||
SHR DL,1
|
||
SHR DL,1
|
||
SHR DL,1
|
||
SHR DL,1
|
||
CALL DIGIT
|
||
MOV DL,DH
|
||
DIGIT:
|
||
AND DL,0FH
|
||
JZ BLANKZER
|
||
MOV CL,0
|
||
BLANKZER:
|
||
DEC CH
|
||
AND CL,CH
|
||
OR DL,30H
|
||
SUB DL,CL
|
||
MOV AH,OUTCH
|
||
INT 21H
|
||
RET
|
||
|
||
CONVWRD:
|
||
ADC AL,AL
|
||
DAA
|
||
XCHG AL,AH
|
||
ADC AL,AL
|
||
DAA
|
||
XCHG AL,AH
|
||
RET20: RET
|
||
|
||
ERASE:
|
||
MOV CX,11
|
||
MOV SI,FCB+1
|
||
AMBSPEC:
|
||
LODSB
|
||
CMP AL,"?"
|
||
JNZ ALLFIL
|
||
LOOP AMBSPEC
|
||
ALLFIL:
|
||
CMP CX,0
|
||
JNZ NOPRMPT
|
||
ASKAGN:
|
||
MOV DX,OFFSET TRANGROUP:SUREMES ;"Are you sure (Y/N)?"
|
||
MOV AH,PRINTBUF
|
||
INT 21H
|
||
MOV AX,0C00H+INCHAR
|
||
INT 21H
|
||
AND AL,5FH
|
||
CMP AL,"N"
|
||
JZ RET20
|
||
CMP AL,"Y"
|
||
CALL CRLF2
|
||
JZ NOPRMPT
|
||
JMP SHORT ASKAGN
|
||
NOPRMPT:
|
||
MOV AH,DELETE
|
||
MOV BX,OFFSET TRANGROUP:NOTFND
|
||
CMP BYTE PTR DS:[FCB+1]," " ;Check if parameter exists
|
||
JMP SHORT OPFILE
|
||
RENAME:
|
||
MOV AH,RENAM
|
||
MOV BX,OFFSET TRANGROUP:RENERR
|
||
CMP BYTE PTR DS:[FCB+16+1]," " ;Check if parameter exists
|
||
OPFILE:
|
||
MOV DX,OFFSET TRANGROUP:MISNAM
|
||
JZ ERRJ ;Error if missing parameter
|
||
MOV DX,FCB
|
||
INT 21H
|
||
INC AL
|
||
JNZ RET20
|
||
MOV DX,BX
|
||
ERRJ: JMP ERROR
|
||
|
||
TYPEFIL:
|
||
MOV DS,[TPA]
|
||
XOR DX,DX
|
||
MOV AH,SETDMA
|
||
INT 21H
|
||
PUSH CS
|
||
POP DS
|
||
MOV DX,FCB
|
||
MOV AH,OPEN
|
||
INT 21H
|
||
OR AL,AL
|
||
MOV DX,OFFSET TRANGROUP:NOTFND
|
||
JNZ ERRJ
|
||
XOR AX,AX
|
||
MOV WORD PTR DS:[FCB+RR],AX ;Set RR field
|
||
MOV WORD PTR DS:[FCB+RR+2],AX
|
||
INC AX
|
||
MOV WORD PTR DS:[FCB+RECLEN],AX ;Set record length
|
||
MOV ES,[TPA]
|
||
TYPELP:
|
||
MOV DX,FCB
|
||
MOV CX,[BYTCNT]
|
||
MOV AH,RDBLK
|
||
INT 21H
|
||
JCXZ RET30
|
||
XOR SI,SI ;Start at 0 in TPA
|
||
OUTLP:
|
||
LODS BYTE PTR ES:[SI] ;In TPA segment
|
||
CMP AL,1AH
|
||
JZ RET30
|
||
MOV AH,OUTCH
|
||
MOV DL,AL
|
||
INT 21H
|
||
LOOP OUTLP
|
||
JMP SHORT TYPELP
|
||
|
||
RET30: RET ;Need a nearby RET
|
||
|
||
COPY:
|
||
XOR AX,AX
|
||
MOV [PLUS],AL ;Will keep track of "+"s
|
||
MOV [FILECNT],AX
|
||
MOV SI,81H ;Point to input line
|
||
CALL SWITCH ;Skip over switches on command
|
||
MOV BP,AX
|
||
MOV DI,FCB
|
||
CALL PARSNAM ;Scan first source
|
||
MOV [PARM1],DL ;Save ambiguous flag
|
||
MOV [SRCPT],SI ;Save pointer to command line
|
||
;Parse each name to find destination and check for /V switch
|
||
SCANNAM:
|
||
CALL PARSE
|
||
JNZ SCANNAM
|
||
GETDEST:
|
||
MOV DI,OFFSET TRANGROUP:DEST
|
||
MOV BX,BP ;Remeber switches so far
|
||
XOR BP,BP ;Must have dest. swtiches alone
|
||
CALL PARSNAM
|
||
MOV [ARG2S],BP ;Remember switches on destination
|
||
JNZ HAVDESTNAM ;File name present?
|
||
INC DI ;Point to file name spot
|
||
MOV AL,"?" ;Substitute *.*
|
||
MOV CX,11
|
||
REP STOSB
|
||
HAVDESTNAM:
|
||
OR BX,BP ;BX = all switches combined
|
||
AND BL,VSWITCH ;Verify requested?
|
||
JZ NOVER
|
||
MOV AX,46*100H+1 ;Set verify
|
||
MOV DL,0
|
||
INT 33
|
||
NOVER:
|
||
MOV DI,OFFSET TRANGROUP:DESTNAME
|
||
MOV SI,OFFSET TRANGROUP:DEST+1
|
||
MOV BX,FCB+1
|
||
CALL BUILDNAME ;See if we can make it unambiguous
|
||
MOV DI,OFFSET TRANGROUP:DESTNAME
|
||
MOV AL,"?"
|
||
MOV CX,11
|
||
REPNE SCASB ;Scan for "?" to see if ambiguous
|
||
MOV AL,1 ;Flag if ambig.
|
||
JZ AMBIG
|
||
DEC AX ;AL=0 if unambig.
|
||
AMBIG:
|
||
MOV DL,AL
|
||
MOV AH,[PLUS] ;1=found "+"
|
||
XOR AL,1 ;0=ambig, 1=unambig destination
|
||
AND AL,[PARM1] ;Source ambig. AND dest unambig.
|
||
OR AL,AH ;OR found "+" means concatenation
|
||
MOV [ASCII],AL ;Concatenation implies ASCII mode
|
||
MOV [INEXACT],AL ;ASCII implies inexact copy
|
||
SHL AL,1
|
||
OR AL,DL ;Combine multiple and concat flags
|
||
MOV [PARM2],AL
|
||
MOV AL,BYTE PTR[COMSW]
|
||
CALL SETASC ;Check /A,/B on command
|
||
MOV AL,BYTE PTR[ARG1S]
|
||
CALL SETASC ;Check for ASCII on first filename
|
||
MOV BYTE PTR[COMSW],AL ;Save starting switch values
|
||
MOV AH,SRCHFRST
|
||
CALL SEARCH ;Search for first source name
|
||
MULTDEST:
|
||
JZ FIRSTSRC ;Find a first source name?
|
||
TEST [PARM2],1 ;If multiple, we're done
|
||
JNZ ENDCOPY
|
||
XOR AX,AX
|
||
MOV [NXTADD],AX
|
||
MOV [CFLAG],AL ;Flag nothing read yet
|
||
NEXTSNG:
|
||
MOV DI,FCB
|
||
MOV SI,[SRCPT]
|
||
CALL PARSESRC ;Parse next file name into FCB
|
||
MOV [PARM1],DL ;Remember if it's ambiguous
|
||
MOV [SRCPT],SI
|
||
JZ SNGCLOS
|
||
MOV AH,SRCHFRST
|
||
CALL SEARCH ;Search for new file name
|
||
JNZ NEXTSNG ;If none, skip it and move to next name
|
||
READSNG:
|
||
CALL CHECKREAD
|
||
SNGLOOP:
|
||
CALL SEARCHNEXT ;See if any more of this name
|
||
JZ READSNG
|
||
JMP SHORT NEXTSNG
|
||
|
||
SNGCLOS:
|
||
CALL CLOSEFIL
|
||
ENDCOPY:
|
||
MOV SI,[FILECNT]
|
||
XOR DI,DI
|
||
CALL DISP32BITS
|
||
MOV DX,OFFSET TRANGROUP:COPIED
|
||
MOV AH,PRINTBUF
|
||
INT 21H
|
||
JMP COMMAND ;Stack could be messed up
|
||
|
||
FIRSTSRC:
|
||
MOV SI,OFFSET TRANGROUP:DIRBUF+1
|
||
MOV DI,OFFSET TRANGROUP:SOURCE
|
||
MOV CX,11
|
||
REP MOVSB ;Copy first source name to SOURCE
|
||
MOV SI,OFFSET TRANGROUP:DESTNAME
|
||
MOV DI,OFFSET TRANGROUP:DEST+1
|
||
MOV BX,OFFSET TRANGROUP:SOURCE
|
||
CALL BUILDNAME ;Build destination name
|
||
XOR AX,AX
|
||
MOV [NXTADD],AX
|
||
MOV [CFLAG],AL
|
||
MOV [APPEND],AL
|
||
MOV [NOWRITE],AL
|
||
TEST [PARM2],1 ;Multiple destinations?
|
||
JZ NOPRT
|
||
MOV SI,OFFSET TRANGROUP:DIRBUF+1
|
||
CALL SHONAME ;If so, show first source
|
||
CALL CRLF2
|
||
NOPRT:
|
||
CALL COMPNAME ;Source and dest. the same?
|
||
JNZ DOREAD ;If not, read source in
|
||
TEST [PARM2],2 ;Concatenation?
|
||
MOV DX,OFFSET TRANGROUP:OVERWR
|
||
JZ COPERRJ ;If not, overwrite error
|
||
MOV [APPEND],1 ;Set physical append
|
||
MOV AH,OPEN
|
||
MOV DX,OFFSET TRANGROUP:DEST
|
||
INT 33 ;Open (existing) destination
|
||
CMP [ASCII],0 ;ASCII flag set?
|
||
JZ BINARYAPP
|
||
;ASCII append. Must find logical EOF, then seek there with dest. FCB
|
||
MOV [NOWRITE],1
|
||
CALL READIN ;Find EOF
|
||
CALL FLSHFIL ;Seek there
|
||
MOV [NOWRITE],0
|
||
CALL FLSHFIL ;Truncate file
|
||
JMP SHORT SNGLCHK
|
||
|
||
SNGLOOPJ:JMP SNGLOOP
|
||
|
||
COPERRJ:JMP COPERR
|
||
|
||
BINARYAPP:
|
||
MOV WORD PTR[DEST+RECLEN],1 ;Set record length to 1
|
||
MOV SI,OFFSET TRANGROUP:DEST+16 ;Point to file size
|
||
MOV DI,OFFSET TRANGROUP:DEST+RR
|
||
MOVSW
|
||
MOVSW ;Seek to end of file
|
||
MOV [CFLAG],1
|
||
JMP SHORT SNGLCHK
|
||
DOREAD:
|
||
CALL READIN
|
||
SNGLCHK:
|
||
TEST [PARM2],1 ;Single or multiple destinations?
|
||
JZ SNGLOOPJ
|
||
MOV SI,[SRCPT]
|
||
MULTAPP:
|
||
CALL PARSE
|
||
JZ MULTCLOS
|
||
PUSH SI
|
||
MOV SI,OFFSET TRANGROUP:DIRBUF+1
|
||
MOV DI,SI
|
||
MOV BX,OFFSET TRANGROUP:SOURCE
|
||
CALL BUILDNAME
|
||
CALL CHECKREAD
|
||
POP SI
|
||
JMP SHORT MULTAPP
|
||
MULTCLOS:
|
||
CALL CLOSEFIL
|
||
MOV AL,BYTE PTR[COMSW]
|
||
MOV [ASCII],AL ;Restore ASCII flag
|
||
CALL SEARCHNEXT
|
||
JMP MULTDEST
|
||
|
||
PARSE:
|
||
MOV DI,OFFSET TRANGROUP:DIRBUF
|
||
PARSESRC:
|
||
CALL SCANOFF
|
||
CMP AL,"+"
|
||
JNZ RETZF
|
||
MOV [PLUS],1 ;Keep track of "+" signs
|
||
INC SI ;Skip over it
|
||
PARSNAM:
|
||
MOV AX,2901H
|
||
INT 33 ;Parse file name
|
||
CMP AL,-1 ;Illegal?
|
||
MOV DX,OFFSET TRANGROUP:BADDRV
|
||
JZ COPERRJ
|
||
XCHG AX,DX ;Save parse flag in DL
|
||
MOV AL,BYTE PTR[DI] ;Get drive number
|
||
OR AL,AL ;Is it default?
|
||
JNZ PARSW
|
||
MOV AL,[CURDRV] ;Substitute actual drive
|
||
INC AX
|
||
MOV BYTE PTR[DI],AL
|
||
PARSW:
|
||
PUSH BX
|
||
PUSH DI
|
||
CALL SWITCH ;Process switches
|
||
OR BP,AX ;Combine all switches
|
||
CALL SETASC ;Check for /A or /B
|
||
POP DI
|
||
POP BX
|
||
CMP BYTE PTR[DI+1]," " ;Did we even get a file name?
|
||
RET
|
||
|
||
RETZF:
|
||
XOR AX,AX
|
||
RET35: RET
|
||
|
||
SEARCHNEXT:
|
||
MOV AL,[PARM1] ;Is name ambiguous?
|
||
DEC AL
|
||
JNZ RET35 ;Don't perform search if not
|
||
MOV AH,SRCHNXT
|
||
SEARCH:
|
||
PUSH AX
|
||
MOV AH,SETDMA
|
||
MOV DX,OFFSET TRANGROUP:DIRBUF
|
||
INT 33 ;Put result of search in DIRBUF
|
||
POP AX ;Restore search first/next command
|
||
MOV DX,FCB
|
||
INT 33 ;Do the search
|
||
OR AL,AL
|
||
RET
|
||
|
||
SETASC:
|
||
;Given switch vector in AX,
|
||
; Set ASCII switch if /A is set
|
||
; Clear ASCII switch if /B is set
|
||
; Leave ASCII unchanged if neither or both are set
|
||
; Also sets INEXACT if ASCII is ever set. AL = ASCII on exit, flags set
|
||
AND AL,ASWITCH+BSWITCH
|
||
JPE LOADSW ;PE means both or neither are set
|
||
AND AL,ASWITCH
|
||
MOV [ASCII],AL
|
||
OR [INEXACT],AL
|
||
LOADSW:
|
||
MOV AL,[ASCII]
|
||
OR AL,AL
|
||
RET
|
||
|
||
BUILDNAME:
|
||
; [SI] = Ambiguous input file name
|
||
; [BX] = Source of replacement characters
|
||
; [DI] = Destination
|
||
; File name is copied from [SI] to [DI]. If "?"s are encountered,
|
||
; they are replaced with the character in the same position at [BX].
|
||
MOV CX,11
|
||
BUILDNAM:
|
||
LODSB
|
||
CMP AL,"?"
|
||
JNZ NOTAMBIG
|
||
MOV AL,BYTE PTR[BX]
|
||
NOTAMBIG:
|
||
STOSB
|
||
INC BX
|
||
LOOP BUILDNAM
|
||
RET
|
||
|
||
COMPNAME:
|
||
MOV SI,OFFSET TRANGROUP:DEST
|
||
MOV DI,OFFSET TRANGROUP:DIRBUF
|
||
MOV CX,6
|
||
REPE CMPSW
|
||
RET
|
||
|
||
CHECKREAD:
|
||
;Read file in (with READIN) if not identical to destination
|
||
CALL COMPNAME ;See if source and destination the same
|
||
JNZ READIN
|
||
CMP [APPEND],0 ;If physical append, it's OK
|
||
JNZ RET40
|
||
MOV DX,OFFSET TRANGROUP:LOSTERR ;Tell him he's not going to get it
|
||
MOV AH,PRINTBUF
|
||
INT 33
|
||
RET40: RET
|
||
|
||
READIN:
|
||
;Open source file and read it in. If memory fills up, flush it out to
|
||
;destination and keep reading. If /A switch set, chop file at first ^Z.
|
||
; Inputs/Outputs:
|
||
; [NXTADD] has current pointer in buffer
|
||
; [CFLAG] <>0 if destination has been created
|
||
|
||
MOV DX,OFFSET TRANGROUP:DIRBUF
|
||
MOV AH,OPEN
|
||
INT 21H
|
||
OR AL,AL ;Successful open?
|
||
JNZ RET40 ;If not, just ignore it
|
||
XOR AX,AX
|
||
MOV WORD PTR[DIRBUF+RR],AX
|
||
MOV WORD PTR[DIRBUF+RR+2],AX
|
||
INC AX
|
||
MOV WORD PTR[DIRBUF+RECLEN],AX
|
||
COPYLP:
|
||
MOV DX,[NXTADD]
|
||
MOV AH,SETDMA
|
||
PUSH DS
|
||
MOV DS,[TPA]
|
||
INT 33
|
||
POP DS
|
||
MOV CX,[BYTCNT]
|
||
SUB CX,DX ;Compute available space
|
||
MOV DX,OFFSET TRANGROUP:DIRBUF
|
||
MOV AH,RDBLK ;Read in source file
|
||
INT 21H
|
||
JCXZ RET40
|
||
CMP [ASCII],0
|
||
JZ BINREAD
|
||
MOV DX,CX
|
||
MOV DI,[NXTADD]
|
||
MOV AL,1AH
|
||
PUSH ES
|
||
MOV ES,[TPA]
|
||
REPNE SCASB ;Scan for EOF
|
||
POP ES
|
||
JNZ USEALL
|
||
INC CX
|
||
USEALL:
|
||
SUB DX,CX
|
||
MOV CX,DX
|
||
BINREAD:
|
||
ADD CX,[NXTADD]
|
||
MOV [NXTADD],CX
|
||
CMP CX,[BYTCNT] ;Is buffer full?
|
||
JB RET40 ;If not, we must have found EOF
|
||
CALL FLSHFIL
|
||
JMP SHORT COPYLP
|
||
|
||
CLOSEFIL:
|
||
MOV AX,[NXTADD]
|
||
MOV BX,AX
|
||
OR AL,AH ;See if any data is loaded
|
||
OR AL,[CFLAG] ; or file was created
|
||
JZ RET50 ;Don't close or count if not created
|
||
MOV AL,BYTE PTR[ARG2S]
|
||
CALL SETASC ;Check for /B or /A on destination
|
||
JZ BINCLOS
|
||
CMP BX,[BYTCNT] ;Is memory full?
|
||
JNZ PUTZ
|
||
CALL FLSHFIL ;Empty it to make room for 1 lousy byte
|
||
XOR BX,BX
|
||
PUTZ:
|
||
PUSH DS
|
||
MOV DS,[TPA]
|
||
MOV WORD PTR[BX],1AH ;Add End-of-file mark (Ctrl-Z)
|
||
POP DS
|
||
INC [NXTADD]
|
||
BINCLOS:
|
||
CALL FLSHFIL
|
||
CMP [INEXACT],0 ;Copy not exact?
|
||
JNZ NODATE ;If so, don't copy date & time
|
||
MOV SI,OFFSET TRANGROUP:DIRBUF+OFFDATE
|
||
MOV DI,OFFSET TRANGROUP:DEST+OFFDATE ;Make date & time same as original
|
||
MOVSW ;Copy date
|
||
MOVSW ;Copy time
|
||
NODATE:
|
||
MOV DX,OFFSET TRANGROUP:DEST
|
||
MOV AH,CLOSE
|
||
INT 21H
|
||
INC [FILECNT]
|
||
RET50: RET
|
||
|
||
FLSHFIL:
|
||
;Write out any data remaining in memory.
|
||
; Inputs:
|
||
; [NXTADD] = No. of bytes to write
|
||
; [CFLAG] <>0 if file has been created
|
||
; Outputs:
|
||
; [NXTADD] = 0
|
||
|
||
MOV AL,1
|
||
XCHG [CFLAG],AL
|
||
OR AL,AL
|
||
JNZ EXISTS
|
||
CMP [NOWRITE],0
|
||
JNZ SKPMAK ;Don't actually create if NOWRITE set
|
||
MOV DX,OFFSET TRANGROUP:DEST
|
||
MOV AH,MAKE
|
||
INT 21H
|
||
MOV DX,OFFSET TRANGROUP:FULDIR
|
||
OR AL,AL
|
||
JNZ COPERR
|
||
SKPMAK:
|
||
XOR AX,AX
|
||
MOV WORD PTR[DEST+RR],AX
|
||
MOV WORD PTR[DEST+RR+2],AX
|
||
INC AX
|
||
MOV WORD PTR[DEST+RECLEN],AX
|
||
EXISTS:
|
||
XOR CX,CX
|
||
XCHG CX,[NXTADD]
|
||
CMP [NOWRITE],0 ;If NOWRITE set, just seek CX bytes
|
||
JNZ SEEKEND
|
||
XOR DX,DX
|
||
PUSH DS
|
||
MOV DS,[TPA]
|
||
MOV AH,SETDMA
|
||
INT 33
|
||
POP DS
|
||
MOV DX,OFFSET TRANGROUP:DEST
|
||
MOV AH,WRBLK
|
||
INT 21H
|
||
OR AL,AL
|
||
JZ RET60
|
||
MOV DX,OFFSET TRANGROUP:DEST
|
||
MOV AH,CLOSE
|
||
INT 21H
|
||
MOV AH,DELETE
|
||
INT 33
|
||
MOV DX,OFFSET TRANGROUP:NOSPACE
|
||
COPERR:
|
||
MOV AH,9
|
||
INT 21H
|
||
JMP ENDCOPY
|
||
|
||
SEEKEND:
|
||
ADD WORD PTR[DEST+RR],CX
|
||
ADC WORD PTR[DEST+RR+2],0 ;Propagate carry
|
||
RET60: RET
|
||
|
||
GETBATBYT:
|
||
;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, CX, DX destroyed.
|
||
ASSUME DS:RESGROUP
|
||
MOV DX,OFFSET RESGROUP:BATFCB
|
||
MOV AH,RDBLK
|
||
MOV CX,1
|
||
INT 33 ;Get one more byte from batch file
|
||
JCXZ BATEOF
|
||
MOV AL,[BATBYT]
|
||
CMP AL,1AH
|
||
JNZ RET70
|
||
BATEOF:
|
||
MOV AL,0DH ;If end-of-file, then end of line
|
||
MOV [BATCH],0 ;And turn off batch mode
|
||
RET70: RET
|
||
ASSUME DS:TRANGROUP
|
||
|
||
SCANOFF:
|
||
LODSB
|
||
CALL DELIM
|
||
JZ SCANOFF
|
||
DEC SI ;Point to first non-delimiter
|
||
RET
|
||
|
||
DELIM:
|
||
CMP AL," "
|
||
JZ RET80
|
||
CMP AL,"="
|
||
JZ RET80
|
||
CMP AL,","
|
||
JZ RET80
|
||
CMP AL,9 ;Check for TAB character
|
||
RET80: RET
|
||
|
||
PAUSE:
|
||
MOV DX,OFFSET TRANGROUP:PAUSMES
|
||
MOV AH,PRINTBUF
|
||
INT 33
|
||
MOV AX,0C00H+INCHAR ;Get character with KB buffer flush
|
||
INT 33
|
||
RET90: RET
|
||
|
||
;Date and time are set during initialization and use
|
||
;this routines since they need to do a long return
|
||
|
||
DATINIT:
|
||
PUSH ES
|
||
PUSH DS ;Going to use the previous stack
|
||
MOV AX,CS ;Set up the appropriate segment registers
|
||
MOV ES,AX
|
||
MOV DS,AX
|
||
MOV WORD PTR DS:[81H],13 ;Want to prompt for date during initialization
|
||
CALL DATE
|
||
CALL TIME
|
||
POP DS
|
||
POP ES
|
||
YYY PROC FAR
|
||
RET
|
||
YYY ENDP
|
||
|
||
; DATE - Gets and sets the time
|
||
|
||
DATE:
|
||
MOV SI,81H ;Accepting argument for date inline
|
||
CALL SCANOFF
|
||
CMP AL,13
|
||
JZ PRMTDAT
|
||
MOV BX,2F00H+"-" ;"/-"
|
||
CALL INLINE
|
||
JMP COMDAT
|
||
|
||
PRMTDAT:
|
||
MOV DX,OFFSET TRANGROUP:CURDAT
|
||
MOV AH,PRINTBUF
|
||
INT 33 ;Print "Current date is "
|
||
MOV AH,GETDATE
|
||
INT 33 ;Get date in CX:DX
|
||
CBW
|
||
MOV SI,AX
|
||
SHL SI,1
|
||
ADD SI,AX ;SI=AX*3
|
||
ADD SI,OFFSET TRANGROUP:WEEKTAB
|
||
MOV BX,CX
|
||
MOV CX,3
|
||
CALL OUTCNT
|
||
MOV AL," "
|
||
CALL OUT
|
||
MOV AX,BX
|
||
MOV CX,DX
|
||
MOV DL,100
|
||
DIV DL
|
||
XCHG AL,AH
|
||
XCHG AX,DX
|
||
MOV BL,"-"
|
||
CALL SHOW
|
||
GETDAT:
|
||
MOV DX,OFFSET TRANGROUP:NEWDAT
|
||
MOV BX,2F00H+"-" ;"/-" in BX
|
||
CALL GETBUF
|
||
COMDAT: JZ RET90
|
||
JC DATERR
|
||
LODSB
|
||
CMP AL,BL
|
||
JZ SEPGD
|
||
CMP AL,BH
|
||
JNZ DATERR
|
||
SEPGD: CALL GETNUM
|
||
JC DATERR
|
||
MOV CX,1900
|
||
CMP BYTE PTR[SI],13
|
||
JZ BIAS
|
||
MOV AL,100
|
||
MUL AH
|
||
MOV CX,AX
|
||
CALL GETNUM
|
||
JC DATERR
|
||
BIAS:
|
||
MOV AL,AH
|
||
MOV AH,0
|
||
ADD CX,AX
|
||
LODSB
|
||
CMP AL,13
|
||
JNZ DATERR
|
||
MOV AH,SETDATE
|
||
INT 33
|
||
OR AL,AL
|
||
JNZ DATERR
|
||
JMP RET90
|
||
DATERR:
|
||
MOV DX,OFFSET TRANGROUP:BADDAT
|
||
MOV AH,PRINTBUF
|
||
INT 33
|
||
JMP GETDAT
|
||
|
||
; TIME gets and sets the time
|
||
|
||
TIME:
|
||
MOV SI,81H ;Accepting argument for time inline
|
||
CALL SCANOFF
|
||
CMP AL,13
|
||
JZ PRMTTIM
|
||
MOV BX,3A00H+":"
|
||
CALL INLINE
|
||
JMP COMTIM
|
||
|
||
PRMTTIM:
|
||
MOV DX,OFFSET TRANGROUP:CURTIM
|
||
MOV AH,PRINTBUF
|
||
INT 33 ;Print "Current time is "
|
||
MOV AH,GETTIME
|
||
INT 33 ;Get time in CX:DX
|
||
MOV BL,":"
|
||
CALL SHOW
|
||
GETTIM:
|
||
XOR CX,CX ;Initialize hours and minutes to zero
|
||
MOV DX,OFFSET TRANGROUP:NEWTIM
|
||
MOV BX,3A00H+":"
|
||
CALL GETBUF
|
||
COMTIM: JZ RET100 ;If no time present, don't change it
|
||
JC TIMERR
|
||
MOV CX,DX
|
||
XOR DX,DX
|
||
LODSB
|
||
CMP AL,13
|
||
JZ SAVTIM
|
||
CMP AL,BL
|
||
JNZ TIMERR
|
||
MOV BL,"."
|
||
CALL GETNUM
|
||
JC TIMERR
|
||
MOV DH,AH ;Position seconds
|
||
LODSB
|
||
CMP AL,13
|
||
JZ SAVTIM
|
||
CMP AL,BL
|
||
JNZ TIMERR
|
||
CALL GETNUM
|
||
JC TIMERR
|
||
MOV DL,AH
|
||
LODSB
|
||
CMP AL,13
|
||
JNZ TIMERR
|
||
SAVTIM:
|
||
MOV AH,SETTIME
|
||
INT 33
|
||
OR AL,AL
|
||
JZ RET100 ;Error in time?
|
||
TIMERR:
|
||
MOV DX,OFFSET TRANGROUP:BADTIM
|
||
MOV AH,PRINTBUF
|
||
INT 33 ;Print error message
|
||
JMP GETTIM ;Try again
|
||
|
||
GETBUF:
|
||
MOV AH,PRINTBUF
|
||
INT 33 ;Print "Enter new date: "
|
||
MOV AH,INBUF
|
||
MOV DX,OFFSET TRANGROUP:COMBUF
|
||
INT 33 ;Get input line
|
||
CALL CRLF2
|
||
MOV SI,OFFSET TRANGROUP:COMBUF+2
|
||
CMP BYTE PTR[SI],13 ;Check if new date entered
|
||
JZ RET100
|
||
INLINE:
|
||
CALL GETNUM ;Get one or two digit number
|
||
JC RET100
|
||
MOV DH,AH ;Put in position
|
||
LODSB
|
||
CMP AL,BL
|
||
JZ NEXT
|
||
CMP BL,":" ;Is it a date seperator?
|
||
JNZ DATESEP
|
||
DEC SI
|
||
MOV DL,0
|
||
RET100: RET ;Time may have only an hour specified
|
||
DATESEP:
|
||
CMP AL,BH
|
||
STC
|
||
JNZ RET100
|
||
NEXT: CALL GETNUM
|
||
MOV DL,AH ;Put in position
|
||
RET
|
||
|
||
GETNUM:
|
||
CALL INDIG
|
||
JC RET100
|
||
MOV AH,AL ;Save first digit
|
||
CALL INDIG ;Another digit?
|
||
JC OKRET
|
||
AAD ;Convert unpacked BCD to decimal
|
||
MOV AH,AL
|
||
OKRET:
|
||
OR AL,1
|
||
RET110: RET
|
||
|
||
INDIG:
|
||
MOV AL,BYTE PTR[SI]
|
||
SUB AL,"0"
|
||
JC RET110
|
||
CMP AL,10
|
||
CMC
|
||
JC RET110
|
||
INC SI
|
||
RET
|
||
|
||
SHOW:
|
||
MOV AL,CH
|
||
MOV BH,"0"-" " ;Enable leading zero suppression
|
||
CALL OUT2
|
||
MOV AL,BL
|
||
CALL OUT
|
||
MOV AL,CL
|
||
CALL OUT2
|
||
MOV AL,BL
|
||
CALL OUT
|
||
MOV AL,DH
|
||
CALL OUT2
|
||
CMP BL,":" ;Are we outputting time?
|
||
JNZ SKIPIT
|
||
MOV AL,"."
|
||
CALL OUT
|
||
SKIPIT: MOV AL,DL
|
||
OUT2: ;Output binary number as two ASCII digits
|
||
AAM ;Convert binary to unpacked BCD
|
||
XCHG AL,AH
|
||
OR AX,3030H ;Add "0" bias to both digits
|
||
CMP AL,"0" ;Is MSD zero?
|
||
JNZ NOSUP
|
||
SUB AL,BH ;Suppress leading zero if enabled
|
||
NOSUP:
|
||
MOV BH,0 ;Disable zero suppression
|
||
CALL OUT
|
||
MOV AL,AH
|
||
OUT:
|
||
;Print char in AL without affecting registers
|
||
XCHG AX,DX
|
||
PUSH AX
|
||
MOV AH,OUTCH
|
||
INT 33
|
||
POP AX
|
||
XCHG AX,DX
|
||
RET
|
||
|
||
EXELOAD:
|
||
MOV AX,CS
|
||
ADD AX,LOADSEG
|
||
MOV [EXEEND],AX ;Store in EXEEND
|
||
MOV DX,OFFSET TRANGROUP:RUNVAR ;Read header in here
|
||
MOV AH,SETDMA
|
||
INT 33
|
||
MOV CX,RUNVARSIZ ;Amount of header info we need
|
||
MOV DX,OFFSET TRANGROUP:EXEFCB
|
||
MOV AH,RDBLK
|
||
INT 33 ;Read in header
|
||
OR AL,AL
|
||
JNZ BADEXE ;Must not reach EOF
|
||
MOV AX,[HEADSIZ] ;Size of header in paragraphs
|
||
;Convert header size to 512-byte pages by multiplying by 32 & rounding up
|
||
ADD AX,31 ;Round up first
|
||
MOV CL,5
|
||
SHR AX,CL ;Multiply by 32
|
||
MOV [EXEFCB+RR],AX ;Position in file of program
|
||
MOV WORD PTR[EXEFCB+RECLEN],512 ;Set record size
|
||
ADD BX,10H ;First paragraph above parameter area
|
||
MOV DX,[PAGES] ;Total size of file in 512-byte pages
|
||
SUB DX,AX ;Size of program in pages
|
||
MOV [PSIZE],DX
|
||
SHL DX,CL ;Convert pages back to paragraphs
|
||
MOV AX,DX
|
||
ADD DX,BX ;Size + start = minimum memory (paragr.)
|
||
MOV CX,[EXEEND] ;Get memory size in paragraphs
|
||
CMP DX,CX ;Enough memory?
|
||
JA SHRTERR
|
||
MOV DX,[INITSP]
|
||
ADD DX,15
|
||
SHR DX,1
|
||
SHR DX,1
|
||
SHR DX,1
|
||
SHR DX,1
|
||
ADD DX,[INITSS]
|
||
ADD DX,BX ;Adjusted value of SP
|
||
CMP DX,CX ;Is it valid?
|
||
JA SHRTERR
|
||
CMP [LOADLOW],-1 ;Load low or high?
|
||
JZ LOAD ;If low, load at segment BX
|
||
SUB CX,AX ;Memory size - program size = load addr.
|
||
MOV BX,CX
|
||
LOAD:
|
||
MOV BP,BX ;Save load segment
|
||
LOAD1:
|
||
LOADSEG EQU (LOAD1-ZERO)/16
|
||
PUSH DS
|
||
MOV DS,BX
|
||
XOR DX,DX ;Address 0 in segment
|
||
MOV AH,SETDMA
|
||
INT 33 ;Set load address
|
||
POP DS
|
||
MOV CX,[PSIZE] ;Number of records to read
|
||
MOV DX,OFFSET TRANGROUP:EXEFCB
|
||
MOV AH,RDBLK
|
||
INT 33 ;Read in up to 64K
|
||
SUB [PSIZE],CX ;Decrement count by amount read
|
||
JZ HAVEXE ;Did we get it all?
|
||
TEST AL,1 ;Check return code if not
|
||
JNZ BADEXE ;Must be zero if more to come
|
||
ADD BX,1000H-20H ;Bump data segment 64K minus one record
|
||
JMP SHORT LOAD1 ;Get next 64K block
|
||
|
||
BADEXE:
|
||
MOV DX,OFFSET TRANGROUP:EXEBAD
|
||
JMP ERROR
|
||
|
||
SHRTERR:
|
||
MOV DX,OFFSET TRANGROUP:TOOBIG
|
||
JMP ERROR
|
||
|
||
HAVEXE:
|
||
MOV AX,[RELTAB] ;Get position of table
|
||
MOV [EXEFCB+RR],AX ;Set in random record field
|
||
MOV WORD PTR[EXEFCB+RECLEN],1 ;Set one-byte record
|
||
MOV DX,OFFSET TRANGROUP:RELPT ;4-byte buffer for relocation address
|
||
MOV AH,SETDMA
|
||
INT 33
|
||
CMP [RELCNT],0
|
||
JZ NOREL
|
||
RELOC:
|
||
MOV AH,RDBLK
|
||
MOV DX,OFFSET TRANGROUP:EXEFCB
|
||
MOV CX,4
|
||
INT 33 ;Read in one relocation pointer
|
||
OR AL,AL ;Check return code
|
||
JNZ BADEXE
|
||
MOV DI,[RELPT] ;Get offset of relocation pointer
|
||
MOV AX,[RELSEG] ;Get segment
|
||
ADD AX,BP ;Bias segment with actual load segment
|
||
MOV ES,AX
|
||
ADD WORD PTR ES:[DI],BP ;Relocate
|
||
DEC [RELCNT] ;Count off
|
||
JNZ RELOC
|
||
;Set up exit conditions
|
||
NOREL:
|
||
MOV AX,[INITSS]
|
||
ADD AX,BP
|
||
CLI
|
||
MOV SS,AX ;Initialize SS
|
||
MOV SP,[INITSP]
|
||
STI
|
||
ADD [INITCS],BP
|
||
MOV AX,[TPA] ;Get pointer to parameter area
|
||
MOV CX,[BYTCNT] ;Size of TPA segment
|
||
MOV ES,AX
|
||
MOV DS,AX ;Set segment registers to point to it
|
||
CALL SETUP
|
||
JMP DWORD PTR CS:[INITIP] ;Long jump to program
|
||
|
||
SETUP:
|
||
AND CL,0F0H ;Adjust to even paragraph boundary
|
||
MOV AX,WORD PTR DS:[6] ;Get current memory size
|
||
SUB AX,CX ;Find out how much we're changing it
|
||
MOV WORD PTR DS:[6],CX
|
||
MOV CL,4
|
||
SAR AX,CL ;Convert to a segment address
|
||
ADD WORD PTR DS:[8],AX ;Adjust long jump to go to same place
|
||
MOV DX,80H
|
||
MOV AH,SETDMA
|
||
INT 33 ;Set default disk transfer address
|
||
MOV AX,WORD PTR CS:[PARM1] ;Pass on info about FCBs
|
||
XOR CX,CX
|
||
MOV DX,CX ;Assume no batch file
|
||
ASSUME CS:RESGROUP
|
||
TEST CS:[BATCH],-1 ;Batch file in progress?
|
||
ASSUME CS:TRANGROUP
|
||
JZ RET120 ;If not, all set up
|
||
MOV CX,CS:[RESSEG]
|
||
MOV DX,OFFSET RESGROUP:BATFCB ;CX:DX points to batch FCB
|
||
RET120: RET
|
||
TRANCODESIZE EQU $-ZERO
|
||
TRANCODE ENDS
|
||
COMLEN EQU TRANDATASIZE+TRANCODESIZE-102H ;End of COMMAND load. ZERO Needed to make COMLEN absolute
|
||
TRNLEN EQU (PRETRLEN+TRANCODESIZE+TRANDATASIZE+15)/16 ;Length of transient in paragraphs
|
||
END PROGSTART
|
||
|