Files
Pegasys-RomWBW/Source/ZCPR/zcpr.asm
2014-09-08 04:11:55 +00:00

2044 lines
50 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
TITLE 'ZCPR Version 1.0'
;
; CP/M Z80 Command Processor Replacement (CPR) Version 1.0
; CCPZ CREATED AND CUSTOMIZED FOR ARIES-II BY RLC
; FURTHER MODIFIED BY RGF AS V2.0
; FURTHER MODIFIED BY RLC AS V2.1
; FURTHER MODIFIED BY KBP AS V2.2
; FURTHER MODIFIED BY RLC AS V2.4 (V2.3 skipped)
; FURTHER MODIFIED BY RLC AS V2.5
; FURTHER MODIFIED BY RLC AS V2.6
; FURTHUR MODIFIED BY SBB AS V2.7
; FURTHER MODIFIED BY RLC AS V2.8
; FURTHER MODIFIED BY RLC AS V2.9
; FURTHER MODIFIED BY RLC AS V3.0
; FURTHER MODIFIED BY RLC AS V3.1
; FURTHER MODIFIED BY RLC AS V4.0
; ZCPR VERSION 1.0 CREATED FROM CCPZ VERSION 4.0 BY RLC IN
; A COORDINATED EFFORT WITH CCP-GROUP
;
; ZCPR is a group effort by CCP-GROUP, whose active membership involved
; in this project consists of the following:
; RLC - Richard Conn
; RGF - Ron Fowler
; KBP - Keith Peterson
; FJW - Frank Wancho
; The following individual also provided a contribution:
; SBB - Steve Bogolub
;
;
;******** Structure Notes ********
;
; This CPR is divided into a number of major sections. The following
; is an outline of these sections and the names of the major routines
; located therein.
;
; Section Function/Routines
; ------- -----------------
;
; -- Opening Comments, Equates, and Macro Definitions
;
; 0 JMP Table into CPR
;
; 1 Buffers
;
; 2 CPR Starting Modules
; CPR1 CPR RESTRT RSTCPR RCPRNL
; PRNNF
;
; 3 Utilities
; CRLF CONOUT CONIN LCOUT LSTOUT
; READF READ BDOSB PRINTC PRINT
; GETDRV DEFDMA DMASET RESET BDOSJP
; LOGIN OPENF OPEN GRBDOS CLOSE
; SEARF SEAR1 SEARN SUBKIL DELETE
; RESETUSR GETUSR SETUSR
;
; 4 CPR Utilities
; SETUD SETU0D UCASE REDBUF CNVBUF
; BREAK USRNUM ERROR SDELM ADVAN
; SBLANK ADDAH NUMBER NUMERR HEXNUM
; DIRPTR SLOGIN DLOGIN COMLOG SCANER
; CMDSER
;
; 5 CPR-Resident Commands and Functions
; 5A DIR DIRPR FILLQ
; 5B ERA
; 5C LIST
; 5D TYPE PAGER
; 5E SAVE
; 5F REN
; 5G USER
; 5H DFU
; 5I JUMP
; 5J GO
; 5K COM CALLPROG ERRLOG ERRJMP
; 5L GET MEMLOAD PRNLE
;
;
FALSE EQU 0
TRUE EQU NOT FALSE
;
; CUSTOMIZATION EQUATES
;
; The following equates may be used to customize this CPR for the user's
; system and integration technique. The following constants are provided:
;
; REL - TRUE if integration is to be done via MOVCPM
; - FALSE if integration is to be done via DDT and SYSGEN
;
; BASE - Base Address of user's CP/M system (normally 0 for DR version)
; This equate allows easy modification by non-standard CP/M (eg,H89)
;
; CPRLOC - Base Page Address of CPR; this value can be obtained by running
; the BDOSLOC program on your system, or by setting the
; MSIZE and BIOSEX equates to the system memory size in
; K-bytes and the "extra" memory required by your BIOS
; in K-bytes. BIOSEX is zero if your BIOS is normal size,
; and can be negative if your BIOS is in PROM or in
; non-contiguous memory.
;
; RAS - Remote-Access System; setting this equate to TRUE disables
; certain CPR commands that are considered harmful in a Remote-
; Access environment; use under Remote-Access Systems (RBBS) for
; security purposes
;
REL EQU FALSE ;SET TO TRUE FOR MOVCPM INTEGRATION
;
BASE EQU 0 ;BASE OF CP/M SYSTEM (SET FOR STANDARD CP/M)
;
IF REL
CPRLOC EQU 0 ;MOVCPM IMAGE
ELSE
;
; If REL is FALSE, the value of CPRLOC may be set in one
; of two ways. The first way is to set MSIZE and BIOSEX
; as described above using the following three lines:
;
;MSIZE EQU 56 ;SIZE OF MEM IN K-BYTES
;BIOSEX EQU 0 ;EXTRA # K-BYTES IN BIOS
;CPRLOC EQU 3400H+(MSIZE-20-BIOSEX)*1024 ;CPR ORIGIN
;
; The second way is to obtain the origin of your current
; CPR using BDSLOC or its equivalent, then merely set CPRLOC
; to that value as as in the following line:
;
;CPRLOC EQU 0BD00H ;FILL IN WITH BDOSLOC SUPPLIED VALUE
CPRLOC EQU 0D000H ;WW - CUSTOMIZED FOR ROMWBW
;
; Note that you should only use one method or the other.
; Do NOT define CPRLOC twice!
;
; The following gives the required offset to load the CPR into the
; CP/M SYSGEN Image through DDT (the Roffset command); Note that this
; value conforms with the standard value presented in the CP/M reference
; manuals, but it may not necessarily conform with the location of the
; CPR in YOUR CP/M system; several systems (Morrow Designs, P&T, Heath
; Org-0 to name a few) have the CPR located at a non-standard address in
; the SYSGEN Image
;
;CPRR EQU 0980H-CPRLOC ;DDT LOAD OFFSET
CPRR EQU 1100H-CPRLOC ;DDT LOAD OFFSET FOR MORROW DESIGNS
ENDIF
;
RAS EQU FALSE ;SET TO TRUE IF CPR IS FOR A REMOTE-ACCESS SYSTEM
;
; The following is presented as an option, but is not generally user-customiz-
; able. A basic design choice had to be made in the design of ZCPR concerning
; the execution of SUBMIT files. The original CCP had a problem in this sense
; in that it ALWAYS looked for the SUBMIT file from drive A: and the SUBMIT
; program itself (SUBMIT.COM) would place the $$$.SUB file on the currently
; logged-in drive, so when the user was logged into B: and he issued a SUBMIT
; command, the $$$.SUB was placed on B: and did not execute because the CCP
; looked for it on A: and never found it.
; After much debate it was decided to have ZCPR perform the same type of
; function as CCP (look for the $$$.SUB file on A:), but the problem with
; SUBMIT.COM still exists. Hence, RGF designed SuperSUB and RLC took his
; SuperSUB and designed SUB from it; both programs are set up to allow the
; selection at assembly time of creating the $$$.SUB on the logged-in drive
; or on drive A:.
; A final definition of the Indirect Command File ($$$.SUB or SUBMIT
; File) is presented as follows:
; "An Indirect Command File is one which contains
; a series of commands exactly as they would be
; entered from a CP/M Console. The SUBMIT Command
; (or SUB Command) reads this files and transforms
; it for processing by the ZCPR (the $$$.SUB File).
; ZCPR will then execute the commands indicated
; EXACTLY as if they were typed at the Console."
; Hence, to permit this to happen, the $$$.SUB file must always
; be present on a specific drive, and A: is the choice for said drive.
; With this facility engaged as such, Indirect Command Files like:
; DIR
; A:
; DIR
; can be executed, even though the currently logged-in drive is changed
; during execution. If the $$$.SUB file was present on the currently
; logged-in drive, the above series of commands would not work since the
; ZCPR would be looking for $$$.SUB on the logged-in drive, and switching
; logged-in drives without moving the $$$.SUB file as well would cause
; processing to abort.
;
SUBA equ TRUE ; Set to TRUE to have $$$.SUB always on A:
; Set to FALSE to have $$$.SUB on the logged-in drive
;
; The following flag enables extended processing for user-program supplied
; command lines. This is for Command Level 3 of ZCPR. Under the CCPZ Version
; 4.0 philosophy, three command levels exist:
; (1) that command issued by the user from his console at the '>' prompt
; (2) that command issued by a $$$.SUB file at the '$' prompt
; (3) that command issued by a user program by placing the command into
; CIBUFF and setting the character count in CBUFF
; Setting CLEVEL3 to TRUE enables extended processing of the third level of
; ZCPR command. All the user program need do is to store the command line and
; set the character count; ZCPR will initialize the pointers properly, store
; the ending zero properly, and capitalize the command line for processing.
; Once the command line is properly stored, the user executes the command line
; by reentering the ZCPR through CPRLOC [NOTE: The C register MUST contain
; a valid User/Disk Flag (see location 4) at this time.]
;
CLEVEL3 equ TRUE ;ENABLE COMMAND LEVEL 3 PROCESSING
;
;
;*** TERMINAL AND 'TYPE' CUSTOMIZATION EQUATES
;
NLINES EQU 24 ;NUMBER OF LINES ON CRT SCREEN
WIDE EQU TRUE ;TRUE IF WIDE DIR DISPLAY
FENCE EQU '|' ;SEP CHAR BETWEEN DIR FILES
;
PGDFLT EQU TRUE ;SET TO FALSE TO DISABLE PAGING BY DEFAULT
PGDFLG EQU 'P' ;FOR TYPE COMMAND: PAGE OR NOT (DEP ON PGDFLT)
; THIS FLAG REVERSES THE DEFAULT EFFECT
;
MAXUSR EQU 15 ;MAXIMUM USER NUMBER ACCESSABLE
;
SYSFLG EQU 'A' ;FOR DIR COMMAND: LIST $SYS AND $DIR
;
SOFLG EQU 'S' ;FOR DIR COMMAND: LIST $SYS FILES ONLY
;
SUPRES EQU TRUE ;SUPRESSES USER # REPORT FOR USER 0
;
DEFUSR EQU 0 ;DEFAULT USER NUMBER FOR COM FILES
;
SPRMPT EQU '$' ;CPR PROMPT INDICATING SUBMIT COMMAND
CPRMPT EQU '>' ;CPR PROMPT INDICATING USER COMMAND
;
NUMBASE EQU 'H' ;CHARACTER USED TO SWITCH FROM DEFAULT
; NUMBER BASE
;
SECTFLG EQU 'S' ;OPTION CHAR FOR SAVE COMMAND TO SAVE SECTORS
;
; END OF CUSTOMIZATION SECTION
;
CR EQU 0DH
LF EQU 0AH
TAB EQU 09H
;
WBOOT EQU BASE+0000H ;CP/M WARM BOOT ADDRESS
UDFLAG EQU BASE+0004H ;USER NUM IN HIGH NYBBLE, DISK IN LOW
BDOS EQU BASE+0005H ;BDOS FUNCTION CALL ENTRY PT
TFCB EQU BASE+005CH ;DEFAULT FCB BUFFER
TBUFF EQU BASE+0080H ;DEFAULT DISK I/O BUFFER
TPA EQU BASE+0100H ;BASE OF TPA
;
;
; MACROS TO PROVIDE Z80 EXTENSIONS
; MACROS INCLUDE:
;
$-MACRO ;FIRST TURN OFF THE EXPANSIONS
;
; JR - JUMP RELATIVE
; JRC - JUMP RELATIVE IF CARRY
; JRNC - JUMP RELATIVE IF NO CARRY
; JRZ - JUMP RELATIVE IF ZERO
; JRNZ - JUMP RELATIVE IF NO ZERO
; DJNZ - DECREMENT B AND JUMP RELATIVE IF NO ZERO
; LDIR - MOV @HL TO @DE FOR COUNT IN BC
; LXXD - LOAD DOUBLE REG DIRECT
; SXXD - STORE DOUBLE REG DIRECT
;
;
;
; @GENDD MACRO USED FOR CHECKING AND GENERATING
; 8-BIT JUMP RELATIVE DISPLACEMENTS
;
@GENDD MACRO ?DD ;;USED FOR CHECKING RANGE OF 8-BIT DISPLACEMENTS
IF (?DD GT 7FH) AND (?DD LT 0FF80H)
DB 100H ;Displacement Range Error on Jump Relative
ELSE
DB ?DD
ENDIF
ENDM
;
;
; Z80 MACRO EXTENSIONS
;
JR MACRO ?N ;;JUMP RELATIVE
DB 18H
@GENDD ?N-$-1
ENDM
;
JRC MACRO ?N ;;JUMP RELATIVE ON CARRY
DB 38H
@GENDD ?N-$-1
ENDM
;
JRNC MACRO ?N ;;JUMP RELATIVE ON NO CARRY
DB 30H
@GENDD ?N-$-1
ENDM
;
JRZ MACRO ?N ;;JUMP RELATIVE ON ZERO
DB 28H
@GENDD ?N-$-1
ENDM
;
JRNZ MACRO ?N ;;JUMP RELATIVE ON NO ZERO
DB 20H
@GENDD ?N-$-1
ENDM
;
DJNZ MACRO ?N ;;DECREMENT B AND JUMP RELATIVE ON NO ZERO
DB 10H
@GENDD ?N-$-1
ENDM
;
LDIR MACRO ;;LDIR
DB 0EDH,0B0H
ENDM
;
LDED MACRO ?N ;;LOAD DE DIRECT
DB 0EDH,05BH
DW ?N
ENDM
;
LBCD MACRO ?N ;;LOAD BC DIRECT
DB 0EDH,4BH
DW ?N
ENDM
;
SDED MACRO ?N ;;STORE DE DIRECT
DB 0EDH,53H
DW ?N
ENDM
;
SBCD MACRO ?N ;;STORE BC DIRECT
DB 0EDH,43H
DW ?N
ENDM
;
; END OF Z80 MACRO EXTENSIONS
;
;
;**** Section 0 ****
;
ORG CPRLOC
;
; ENTRY POINTS INTO ZCPR
; If the ZCPR is entered at location CPRLOC (at the JMP to CPR), then
; the default command in CIBUFF will be processed. If the ZCPR is entered
; at location CPRLOC+3 (at the JMP to CPR1), then the default command in
; CIBUFF will NOT be processed.
; NOTE: Entry into ZCPR in this way is permitted under ZCPR Version 4.0,
; but in order for this to work, CIBUFF and CBUFF MUST be initialized properly
; AND the C register MUST contain a valid User/Disk Flag (see Location 4: the
; most significant nybble contains the User Number and the least significant
; nybble contains the Disk Number).
; Some user programs (such as SYNONYM3) attempt to use the default
; command facility. Under the original CPR, it was necessary to initialize
; the pointer after the reserved space for the command buffer to point to
; the first byte of the command buffer. Under Version 4.x of ZCPR, this is
; no longer the case. The CIBPTR (Command Input Buffer PoinTeR) is located
; to be compatable with such programs (provided they determine the buffer
; length from the byte at MBUFF [CPRLOC + 6]), but under Version 4.x of ZCPR
; this is no longer necessary. ZCPR Version 4.x automatically initializes
; this buffer pointer in all cases.
;
ENTRY:
JMP CPR ; Process potential default command
JMP CPR1 ; Do NOT process potential default command
;
;**** Section 1 ****
; BUFFERS ET AL
;
; INPUT COMMAND LINE AND DEFAULT COMMAND
; The command line to be executed is stored here. This command line
; is generated in one of three ways:
; (1) by the user entering it through the BDOS READLN function at
; the du> prompt [user input from keyboard]
; (2) by the SUBMIT File Facility placing it there from a $$$.SUB
; file
; (3) by an external program or user placing the required command
; into this buffer
; In all cases, the command line is placed into the buffer starting at
; CIBUFF. This command line is terminated by the last character (NOT Carriage
; Return), and a character count of all characters in the command line
; up to and including the last character is placed into location CBUFF
; (immediately before the command line at CIBUFF). The placed command line
; is then parsed, interpreted, and the indicated command is executed.
; If CLEVEL3 is permitted, a terminating zero is placed after the command
; (otherwise the user program has to place this zero) and the CIBPTR is
; properly initialized (otherwise the user program has to init this ptr).
; If the command is placed by a user program, entering at CPRLOC is enough
; to have the command processed. Again, under CCPZ Version 4.0, it is not
; necessary to store the pointer to CIBUFF in CIBPTR; ZCPR will do this for
; the calling program if CLEVEL3 is made TRUE.
; WARNING: The command line must NOT exceed BUFLEN characters in length.
; For user programs which load this command, the value of BUFLEN can be
; obtained by examining the byte at MBUFF (CPRLOC + 6).
;
BUFLEN EQU 80 ;MAXIMUM BUFFER LENGTH
MBUFF:
DB BUFLEN ;MAXIMUM BUFFER LENGTH
CBUFF:
DB 0 ;NUMBER OF VALID CHARS IN COMMAND LINE
CIBUFF:
DB ' ' ;DEFAULT (COLD BOOT) COMMAND
CIBUF:
DB 0 ;COMMAND STRING TERMINATOR
DS BUFLEN-($-CIBUFF)+1 ;TOTAL IS 'BUFLEN' BYTES
;
CIBPTR:
DW CIBUFF ;POINTER TO COMMAND INPUT BUFFER
CIPTR:
DW CIBUF ;CURRENT POINTER
;
DS 26 ;STACK AREA
STACK EQU $ ;TOP OF STACK
;
; FILE TYPE FOR COMMAND
;
COMMSG:
DB 'COM'
;
; SUBMIT FILE CONTROL BLOCK
;
SUBFCB:
IF SUBA ;IF $$$.SUB ON A:
DB 1 ;DISK NAME SET TO DEFAULT TO DRIVE A:
ENDIF
;
IF NOT SUBA ;IF $$$.SUB ON CURRENT DRIVE
DB 0 ;DISK NAME SET TO DEFAULT TO CURRENT DRIVE
ENDIF
;
DB '$$$' ;FILE NAME
DB ' '
DB 'SUB' ;FILE TYPE
DB 0 ;EXTENT NUMBER
DB 0 ;S1
SUBFS2:
DS 1 ;S2
SUBFRC:
DS 1 ;RECORD COUNT
DS 16 ;DISK GROUP MAP
SUBFCR:
DS 1 ;CURRENT RECORD NUMBER
;
; COMMAND FILE CONTROL BLOCK
;
FCBDN:
DS 1 ;DISK NAME
FCBFN:
DS 8 ;FILE NAME
FCBFT:
DS 3 ;FILE TYPE
DS 1 ;EXTENT NUMBER
DS 2 ;S1 AND S2
DS 1 ;RECORD COUNT
FCBDM:
DS 16 ;DISK GROUP MAP
FCBCR:
DS 1 ;CURRENT RECORD NUMBER
;
; OTHER BUFFERS
;
PAGCNT:
DB NLINES-2 ;LINES LEFT ON PAGE
CHRCNT:
DB 0 ;CHAR COUNT FOR TYPE
QMCNT:
DB 0 ;QUESTION MARK COUNT FOR FCB TOKEN SCANNER
;
; CPR BUILT-IN COMMAND TABLE
;
NCHARS EQU 4 ;NUMBER OF CHARS/COMMAND
;
; CPR COMMAND NAME TABLE
; EACH TABLE ENTRY IS COMPOSED OF THE 4-BYTE COMMAND AND 2-BYTE ADDRESS
;
CMDTBL:
DB 'DIR '
DW DIR
DB 'LIST'
DW LIST
DB 'TYPE'
DW TYPE
DB 'USER'
DW USER
DB 'DFU '
DW DFU
;
IF NOT RAS ;FOR NON-RAS
DB 'GO '
DW GO
DB 'ERA '
DW ERA
DB 'SAVE'
DW SAVE
DB 'REN '
DW REN
DB 'GET '
DW GET
DB 'JUMP'
DW JUMP
ENDIF
;
NCMNDS EQU ($-CMDTBL)/(NCHARS+2)
;
;
;**** Section 2 ****
; CPR STARTING POINTS
;
; START CPR AND DON'T PROCESS DEFAULT COMMAND STORED
;
CPR1:
XRA A ;SET NO DEFAULT COMMAND
STA CBUFF
;
; START CPR AND POSSIBLY PROCESS DEFAULT COMMAND
;
; NOTE ON MODIFICATION BY RGF: BDOS RETURNS 0FFH IN
; ACCUMULATOR WHENEVER IT LOGS IN A DIRECTORY, IF ANY
; FILE NAME CONTAINS A '$' IN IT. THIS IS NOW USED AS
; A CLUE TO DETERMINE WHETHER OR NOT TO DO A SEARCH
; FOR SUBMIT FILE, IN ORDER TO ELIMINATE WASTEFUL SEARCHES.
;
CPR:
LXI SP,STACK ;RESET STACK
PUSH B
MOV A,C ;C=USER/DISK NUMBER (SEE LOC 4)
RAR ;EXTRACT USER NUMBER
RAR
RAR
RAR
ANI 0FH
MOV E,A ;SET USER NUMBER
CALL SETUSR
CALL RESET ;RESET DISK SYSTEM
STA RNGSUB ;SAVE SUBMIT CLUE FROM DRIVE A:
POP B
MOV A,C ;C=USER/DISK NUMBER (SEE LOC 4)
ANI 0FH ;EXTRACT DEFAULT DISK DRIVE
STA TDRIVE ;SET IT
JRZ NOLOG ;SKIP IF 0...ALREADY LOGGED
CALL LOGIN ;LOG IN DEFAULT DISK
;
IF NOT SUBA ;IF $$$.SUB IS ON CURRENT DRIVE
STA RNGSUB ;BDOS '$' CLUE
ENDIF
;
NOLOG:
LXI D,SUBFCB ;CHECK FOR $$$.SUB ON CURRENT DISK
RNGSUB EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION
MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS THE RNGSUB FLAG
ORA A ;SET FLAGS ON CLUE
CMA ;PREPARE FOR COMING 'CMA'
CNZ SEAR1
CMA ;0FFH IS RETURNED IF NO $$$.SUB, SO COMPLEMENT
STA RNGSUB ;SET FLAG (0=NO $$$.SUB)
LDA CBUFF ;EXECUTE DEFAULT COMMAND?
ORA A ;0=NO
JRNZ RS1
;
; PROMPT USER AND INPUT COMMAND LINE FROM HIM
;
RESTRT:
LXI SP,STACK ;RESET STACK
;
; PRINT PROMPT (DU>)
;
CALL CRLF ;PRINT PROMPT
CALL GETDRV ;CURRENT DRIVE IS PART OF PROMPT
ADI 'A' ;CONVERT TO ASCII A-P
CALL CONOUT
CALL GETUSR ;GET USER NUMBER
;
IF SUPRES ;IF SUPPRESSING USR # REPORT FOR USR 0
ORA A
JRZ RS000
ENDIF
;
CPI 10 ;USER < 10?
JRC RS00
SUI 10 ;SUBTRACT 10 FROM IT
PUSH PSW ;SAVE IT
MVI A,'1' ;OUTPUT 10'S DIGIT
CALL CONOUT
POP PSW
RS00:
ADI '0' ;OUTPUT 1'S DIGIT (CONVERT TO ASCII)
CALL CONOUT
;
; READ INPUT LINE FROM USER OR $$$.SUB
;
RS000:
CALL REDBUF ;INPUT COMMAND LINE FROM USER (OR $$$.SUB)
;
; PROCESS INPUT LINE
;
RS1:
;
IF CLEVEL3 ;IF THIRD COMMAND LEVEL IS PERMITTED
CALL CNVBUF ;CAPITALIZE COMMAND LINE, PLACE ENDING 0,
; AND SET CIBPTR VALUE
ENDIF
;
CALL DEFDMA ;SET TBUFF TO DMA ADDRESS
CALL GETDRV ;GET DEFAULT DRIVE NUMBER
STA TDRIVE ;SET IT
CALL SCANER ;PARSE COMMAND NAME FROM COMMAND LINE
CNZ ERROR ;ERROR IF COMMAND NAME CONTAINS A '?'
LXI D,RSTCPR ;PUT RETURN ADDRESS OF COMMAND
PUSH D ;ON THE STACK
LDA TEMPDR ;IS COMMAND OF FORM 'D:COMMAND'?
ORA A ;NZ=YES
JNZ COM ; IMMEDIATELY
CALL CMDSER ;SCAN FOR CPR-RESIDENT COMMAND
JNZ COM ;NOT CPR-RESIDENT
MOV A,M ;FOUND IT: GET LOW-ORDER PART
INX H ;GET HIGH-ORDER PART
MOV H,M ;STORE HIGH
MOV L,A ;STORE LOW
PCHL ;EXECUTE CPR ROUTINE
;
; ENTRY POINT FOR RESTARTING CPR AND LOGGING IN DEFAULT DRIVE
;
RSTCPR:
CALL DLOGIN ;LOG IN DEFAULT DRIVE
;
; ENTRY POINT FOR RESTARTING CPR WITHOUT LOGGING IN DEFAULT DRIVE
;
RCPRNL:
CALL SCANER ;EXTRACT NEXT TOKEN FROM COMMAND LINE
LDA FCBFN ;GET FIRST CHAR OF TOKEN
SUI ' ' ;ANY CHAR?
LXI H,TEMPDR
ORA M
JNZ ERROR
JR RESTRT
;
; No File Error Message
;
PRNNF:
CALL PRINTC ;NO FILE MESSAGE
DB 'No Fil','e'+80H
RET
;
;**** Section 3 ****
; I/O UTILITIES
;
; OUTPUT CHAR IN REG A TO CONSOLE AND DON'T CHANGE BC
;
;
; OUTPUT <CRLF>
;
CRLF:
MVI A,CR
CALL CONOUT
MVI A,LF ;FALL THRU TO CONOUT
;
CONOUT:
PUSH B
MVI C,02H
OUTPUT:
MOV E,A
PUSH H
CALL BDOS
POP H
POP B
RET
;
CONIN:
MVI C,01H ;GET CHAR FROM CON: WITH ECHO
CALL BDOSB
JMP UCASE ;CAPITALIZE
;
LCOUT:
PUSH PSW ;OUTPUT CHAR TO CON: OR LST: DEP ON PRFLG
PRFLG EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION
MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS THE PRINT FLAG
ORA A ;0=TYPE
JRZ LC1
POP PSW ;GET CHAR
;
; OUTPUT CHAR IN REG A TO LIST DEVICE
;
LSTOUT:
PUSH B
MVI C,05H
JR OUTPUT
LC1:
POP PSW ;GET CHAR
PUSH PSW
CALL CONOUT ;OUTPUT TO CON:
POP PSW
CPI LF ;CHECK FOR PAGING
JZ PAGER
RET
;
READF:
LXI D,FCBDN ;FALL THRU TO READ
READ:
MVI C,14H ;FALL THRU TO BDOSB
;
; CALL BDOS AND SAVE BC
;
BDOSB:
PUSH B
CALL BDOS
POP B
ORA A
RET
;
; PRINT STRING (ENDING IN 0) PTED TO BY RET ADR;START WITH <CRLF>
;
PRINTC:
PUSH PSW ;SAVE FLAGS
CALL CRLF ;NEW LINE
POP PSW
;
PRINT:
XTHL ;GET PTR TO STRING
PUSH PSW ;SAVE FLAGS
CALL PRIN1 ;PRINT STRING
POP PSW ;GET FLAGS
XTHL ;RESTORE HL AND RET ADR
RET
;
; PRINT STRING (ENDING IN 0) PTED TO BY HL
;
PRIN1:
MOV A,M ;GET NEXT BYTE
ORA A ;WW - SET FLAGS
RZ ;WW - DONE IF ZERO
ANI 7FH ;WW - CLEAR HIGH BIT
CALL CONOUT ;PRINT CHAR
MOV A,M ;GET NEXT BYTE AGAIN FOR TEST
INX H ;PT TO NEXT BYTE
ORA A ;SET FLAGS
RM ;DONE IF MSB SET
JR PRIN1
;
; BDOS FUNCTION ROUTINES
;
;
; RETURN NUMBER OF CURRENT DISK IN A
;
GETDRV:
MVI C,19H
JR BDOSJP
;
; SET 80H AS DMA ADDRESS
;
DEFDMA:
LXI D,TBUFF ;80H=TBUFF
DMASET:
MVI C,1AH
JR BDOSJP
;
RESET:
MVI C,0DH
BDOSJP:
JMP BDOS
;
LOGIN:
MOV E,A
MVI C,0EH
JR BDOSJP ;SAVE SOME CODE SPACE
;
OPENF:
XRA A
STA FCBCR
LXI D,FCBDN ;FALL THRU TO OPEN
;
OPEN:
MVI C,0FH ;FALL THRU TO GRBDOS
;
GRBDOS:
CALL BDOS
INR A ;SET ZERO FLAG FOR ERROR RETURN
RET
;
CLOSE:
MVI C,10H
JR GRBDOS
;
SEARF:
LXI D,FCBDN ;SPECIFY FCB
SEAR1:
MVI C,11H
JR GRBDOS
;
SEARN:
MVI C,12H
JR GRBDOS
;
; CHECK FOR SUBMIT FILE IN EXECUTION AND ABORT IT IF SO
;
SUBKIL:
LXI H,RNGSUB ;CHECK FOR SUBMIT FILE IN EXECUTION
MOV A,M
ORA A ;0=NO
RZ
MVI M,0 ;ABORT SUBMIT FILE
LXI D,SUBFCB ;DELETE $$$.SUB
;
DELETE:
MVI C,13H
JR BDOSJP ;SAVE MORE SPACE
;
; RESET USER NUMBER IF CHANGED
;
RESETUSR:
TMPUSR EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION
MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS TMPUSR
MOV E,A ;PLACE IN E
JR SETUSR ;THEN GO SET USER
GETUSR:
MVI E,0FFH ;GET CURRENT USER NUMBER
SETUSR:
MVI C,20H ;SET USER NUMBER TO VALUE IN E (GET IF E=FFH)
JR BDOSJP ;MORE SPACE SAVING
;
; END OF BDOS FUNCTIONS
;
;
;**** Section 4 ****
; CPR UTILITIES
;
; SET USER/DISK FLAG TO CURRENT USER AND DEFAULT DISK
;
SETUD:
CALL GETUSR ;GET NUMBER OF CURRENT USER
ADD A ;PLACE IT IN HIGH NYBBLE
ADD A
ADD A
ADD A
LXI H,TDRIVE ;MASK IN DEFAULT DRIVE NUMBER (LOW NYBBLE)
ORA M ;MASK IN
STA UDFLAG ;SET USER/DISK NUMBER
RET
;
; SET USER/DISK FLAG TO USER 0 AND DEFAULT DISK
;
SETU0D:
TDRIVE EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION
MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS TDRIVE
STA UDFLAG ;SET USER/DISK NUMBER
RET
;
; CONVERT CHAR IN A TO UPPER CASE
;
UCASE:
CPI 61H ;LOWER-CASE A
RC
CPI 7BH ;GREATER THAN LOWER-CASE Z?
RNC
ANI 5FH ;CAPITALIZE
RET
;
; INPUT NEXT COMMAND TO CPR
; This routine determines if a SUBMIT file is being processed
; and extracts the command line from it if so or from the user's console
;
REDBUF:
LDA RNGSUB ;SUBMIT FILE CURRENTLY IN EXECUTION?
ORA A ;0=NO
JRZ RB1 ;GET LINE FROM CONSOLE IF NOT
LXI D,SUBFCB ;OPEN $$$.SUB
PUSH D ;SAVE DE
CALL OPEN
POP D ;RESTORE DE
JRZ RB1 ;ERASE $$$.SUB IF END OF FILE AND GET CMND
LDA SUBFRC ;GET VALUE OF LAST RECORD IN FILE
DCR A ;PT TO NEXT TO LAST RECORD
STA SUBFCR ;SAVE NEW VALUE OF LAST RECORD IN $$$.SUB
CALL READ ;DE=SUBFCB
JRNZ RB1 ;ABORT $$$.SUB IF ERROR IN READING LAST REC
LXI D,CBUFF ;COPY LAST RECORD (NEXT SUBMIT CMND) TO CBUFF
LXI H,TBUFF ; FROM TBUFF
LXI B,BUFLEN ;NUMBER OF BYTES
LDIR
LXI H,SUBFS2 ;PT TO S2 OF $$$.SUB FCB
MVI M,0 ;SET S2 TO ZERO
INX H ;PT TO RECORD COUNT
DCR M ;DECREMENT RECORD COUNT OF $$$.SUB
LXI D,SUBFCB ;CLOSE $$$.SUB
CALL CLOSE
JRZ RB1 ;ABORT $$$.SUB IF ERROR
MVI A,SPRMPT ;PRINT SUBMIT PROMPT
CALL CONOUT
LXI H,CIBUFF ;PRINT COMMAND LINE FROM $$$.SUB
CALL PRIN1
CALL BREAK ;CHECK FOR ABORT (ANY CHAR)
;
IF CLEVEL3 ;IF THIRD COMMAND LEVEL IS PERMITTED
RZ ;IF <NULL> (NO ABORT), RETURN TO CALLER AND RUN
ENDIF
;
IF NOT CLEVEL3 ;IF THIRD COMMAND LEVEL IS NOT PERMITTED
JRZ CNVBUF ;IF <NULL> (NO ABORT), CAPITALIZE COMMAND
ENDIF
;
CALL SUBKIL ;KILL $$$.SUB IF ABORT
JMP RESTRT ;RESTART CPR
;
; INPUT COMMAND LINE FROM USER CONSOLE
;
RB1:
CALL SUBKIL ;ERASE $$$.SUB IF PRESENT
CALL SETUD ;SET USER AND DISK
MVI A,CPRMPT ;PRINT PROMPT
CALL CONOUT
MVI C,0AH ;READ COMMAND LINE FROM USER
LXI D,MBUFF
CALL BDOS
;
IF CLEVEL3 ;IF THIRD COMMAND LEVEL IS PERMITTED
JMP SETU0D ;SET CURRENT DISK NUMBER IN LOWER PARAMS
ENDIF
;
IF NOT CLEVEL3 ;IF THIRD COMMAND LEVEL IS NOT PERMITTED
CALL SETU0D ;SET CURRENT DISK NUMBER IF LOWER PARAMS
; AND FALL THRU TO CNVBUF
ENDIF
;
; CAPITALIZE STRING (ENDING IN 0) IN CBUFF AND SET PTR FOR PARSING
;
CNVBUF:
LXI H,CBUFF ;PT TO USER'S COMMAND
MOV B,M ;CHAR COUNT IN B
INR B ;ADD 1 IN CASE OF ZERO
CB1:
INX H ;PT TO 1ST VALID CHAR
MOV A,M ;CAPITALIZE COMMAND CHAR
CALL UCASE
MOV M,A
DJNZ CB1 ;CONTINUE TO END OF COMMAND LINE
CB2:
MVI M,0 ;STORE ENDING <NULL>
LXI H,CIBUFF ;SET COMMAND LINE PTR TO 1ST CHAR
SHLD CIBPTR
RET
;
; CHECK FOR ANY CHAR FROM USER CONSOLE;RET W/ZERO SET IF NONE
;
BREAK:
PUSH D ;SAVE DE
MVI C,11 ;CSTS CHECK
CALL BDOSB
CNZ CONIN ;GET INPUT CHAR
BRKBK:
POP D
RET
;
; GET THE REQUESTED USER NUMBER FROM THE COMMAND LINE AND VALIDATE IT.
;
USRNUM:
CALL NUMBER
CPI MAXUSR+1
RC
;
; INVALID COMMAND -- PRINT IT
;
ERROR:
CALL CRLF ;NEW LINE
LHLD CIPTR ;PT TO BEGINNING OF COMMAND LINE
ERR2:
MOV A,M ;GET CHAR
CPI ' '+1 ;SIMPLE '?' IF <SP> OR LESS
JRC ERR1
PUSH H ;SAVE PTR TO ERROR COMMAND CHAR
CALL CONOUT ;PRINT COMMAND CHAR
POP H ;GET PTR
INX H ;PT TO NEXT
JR ERR2 ;CONTINUE
ERR1:
CALL PRINT ;PRINT '?'
DB '?'+80H
CALL SUBKIL ;TERMINATE ACTIVE $$$.SUB IF ANY
JMP RESTRT ;RESTART CPR
;
; CHECK TO SEE IF DE PTS TO DELIMITER; IF SO, RET W/ZERO FLAG SET
;
SDELM:
LDAX D
ORA A ;0=DELIMITER
RZ
CPI ' ' ;ERROR IF < <SP>
JRC ERROR
RZ ;<SP>=DELIMITER
CPI '=' ;'='=DELIMITER
RZ
CPI 5FH ;UNDERSCORE=DELIMITER
RZ
CPI '.' ;'.'=DELIMITER
RZ
CPI ':' ;':'=DELIMITER
RZ
CPI ';' ;';'=DELIMITER
RZ
CPI '<' ;'<'=DELIMITER
RZ
CPI '>' ;'>'=DELIMITER
RET
;
; ADVANCE INPUT PTR TO FIRST NON-BLANK AND FALL THROUGH TO SBLANK
;
ADVAN:
LDED CIBPTR
;
; SKIP STRING PTED TO BY DE (STRING ENDS IN 0) UNTIL END OF STRING
; OR NON-BLANK ENCOUNTERED (BEGINNING OF TOKEN)
;
SBLANK:
LDAX D
ORA A
RZ
CPI ' '
RNZ
INX D
JR SBLANK
;
; ADD A TO HL (HL=HL+A)
;
ADDAH:
ADD L
MOV L,A
RNC
INR H
RET
;
; EXTRACT DECIMAL NUMBER FROM COMMAND LINE
; RETURN WITH VALUE IN REG A;ALL REGISTERS MAY BE AFFECTED
;
NUMBER:
CALL SCANER ;PARSE NUMBER AND PLACE IN FCBFN
LXI H,FCBFN+10 ;PT TO END OF TOKEN FOR CONVERSION
MVI B,11 ;11 CHARS MAX
;
; CHECK FOR SUFFIX FOR HEXADECIMAL NUMBER
;
NUMS:
MOV A,M ;GET CHARS FROM END, SEARCHING FOR SUFFIX
DCX H ;BACK UP
CPI ' ' ;SPACE?
JRNZ NUMS1 ;CHECK FOR SUFFIX
DJNZ NUMS ;COUNT DOWN
JR NUM0 ;BY DEFAULT, PROCESS
NUMS1:
CPI NUMBASE ;CHECK AGAINST BASE SWITCH FLAG
JRZ HNUM0
;
; PROCESS DECIMAL NUMBER
;
NUM0:
LXI H,FCBFN ;PT TO BEGINNING OF TOKEN
LXI B,1100H ;C=ACCUMULATED VALUE, B=CHAR COUNT
; (C=0, B=11)
NUM1:
MOV A,M ;GET CHAR
CPI ' ' ;DONE IF <SP>
JRZ NUM2
INX H ;PT TO NEXT CHAR
SUI '0' ;CONVERT TO BINARY (ASCII 0-9 TO BINARY)
CPI 10 ;ERROR IF >= 10
JRNC NUMERR
MOV D,A ;DIGIT IN D
MOV A,C ;NEW VALUE = OLD VALUE * 10
RLC
RLC
RLC
ADD C ;CHECK FOR RANGE ERROR
JRC NUMERR
ADD C ;CHECK FOR RANGE ERROR
JRC NUMERR
ADD D ;NEW VALUE = OLD VALUE * 10 + DIGIT
JRC NUMERR ;CHECK FOR RANGE ERROR
MOV C,A ;SET NEW VALUE
DJNZ NUM1 ;COUNT DOWN
;
; RETURN FROM NUMBER
;
NUM2:
MOV A,C ;GET ACCUMULATED VALUE
RET
;
; NUMBER ERROR ROUTINE FOR SPACE CONSERVATION
;
NUMERR:
JMP ERROR ;USE ERROR ROUTINE - THIS IS RELATIVE PT
;
; EXTRACT HEXADECIMAL NUMBER FROM COMMAND LINE
; RETURN WITH VALUE IN REG A; ALL REGISTERS MAY BE AFFECTED
;
HEXNUM:
CALL SCANER ;PARSE NUMBER AND PLACE IN FCBFN
HNUM0:
LXI H,FCBFN ;PT TO TOKEN FOR CONVERSION
LXI D,0 ;DE=ACCUMULATED VALUE
MVI B,11 ;B=CHAR COUNT
HNUM1:
MOV A,M ;GET CHAR
CPI ' ' ;DONE?
JRZ HNUM3 ;RETURN IF SO
CPI NUMBASE ;DONE IF NUMBASE SUFFIX
JRZ HNUM3
SUI '0' ;CONVERT TO BINARY
JRC NUMERR ;RETURN AND DONE IF ERROR
CPI 10 ;0-9?
JRC HNUM2
SUI 7 ;A-F?
CPI 10H ;ERROR?
JRNC NUMERR
HNUM2:
INX H ;PT TO NEXT CHAR
MOV C,A ;DIGIT IN C
MOV A,D ;GET ACCUMULATED VALUE
RLC ;EXCHANGE NYBBLES
RLC
RLC
RLC
ANI 0F0H ;MASK OUT LOW NYBBLE
MOV D,A
MOV A,E ;SWITCH LOW-ORDER NYBBLES
RLC
RLC
RLC
RLC
MOV E,A ;HIGH NYBBLE OF E=NEW HIGH OF E,
; LOW NYBBLE OF E=NEW LOW OF D
ANI 0FH ;GET NEW LOW OF D
ORA D ;MASK IN HIGH OF D
MOV D,A ;NEW HIGH BYTE IN D
MOV A,E
ANI 0F0H ;MASK OUT LOW OF E
ORA C ;MASK IN NEW LOW
MOV E,A ;NEW LOW BYTE IN E
DJNZ HNUM1 ;COUNT DOWN
;
; RETURN FROM HEXNUM
;
HNUM3:
XCHG ;RETURNED VALUE IN HL
MOV A,L ;LOW-ORDER BYTE IN A
RET
;
; PT TO DIRECTORY ENTRY IN TBUFF WHOSE OFFSET IS SPECIFIED BY A AND C
;
DIRPTR:
LXI H,TBUFF ;PT TO TEMP BUFFER
ADD C ;PT TO 1ST BYTE OF DIR ENTRY
CALL ADDAH ;PT TO DESIRED BYTE IN DIR ENTRY
MOV A,M ;GET DESIRED BYTE
RET
;
; CHECK FOR SPECIFIED DRIVE AND LOG IT IN IF NOT DEFAULT
;
SLOGIN:
XRA A ;SET FCBDN FOR DEFAULT DRIVE
STA FCBDN
CALL COMLOG ;CHECK DRIVE
RZ
JR DLOG5 ;DO LOGIN OTHERWISE
;
; CHECK FOR SPECIFIED DRIVE AND LOG IN DEFAULT DRIVE IF SPECIFIED<>DEFAULT
;
DLOGIN:
CALL COMLOG ;CHECK DRIVE
RZ ;ABORT IF SAME
LDA TDRIVE ;LOG IN DEFAULT DRIVE
;
DLOG5: JMP LOGIN
;
; ROUTINE COMMON TO BOTH LOGIN ROUTINES; ON EXIT, Z SET MEANS ABORT
;
COMLOG:
TEMPDR EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION
MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS TEMPDR
ORA A ;0=NO
RZ
DCR A ;COMPARE IT AGAINST DEFAULT
LXI H,TDRIVE
CMP M
RET ;ABORT IF SAME
;
; EXTRACT TOKEN FROM COMMAND LINE AND PLACE IT INTO FCBDN;
; FORMAT FCBDN FCB IF TOKEN RESEMBLES FILE NAME AND TYPE (FILENAME.TYP);
; ON INPUT, CIBPTR PTS TO CHAR AT WHICH TO START SCAN;
; ON OUTPUT, CIBPTR PTS TO CHAR AT WHICH TO CONTINUE AND ZERO FLAG IS RESET
; IF '?' IS IN TOKEN
;
; ENTRY POINTS:
; SCANER - LOAD TOKEN INTO FIRST FCB
; SCANX - LOAD TOKEN INTO FCB PTED TO BY HL
;
SCANER:
LXI H,FCBDN ;POINT TO FCBDN
SCANX:
XRA A ;SET TEMPORARY DRIVE NUMBER TO DEFAULT
STA TEMPDR
CALL ADVAN ;SKIP TO NON-BLANK OR END OF LINE
SDED CIPTR ;SET PTR TO NON-BLANK OR END OF LINE
LDAX D ;END OF LINE?
ORA A ;0=YES
JRZ SCAN2
SBI 'A'-1 ;CONVERT POSSIBLE DRIVE SPEC TO NUMBER
MOV B,A ;STORE NUMBER (A:=0, B:=1, ETC) IN B
INX D ;PT TO NEXT CHAR
LDAX D ;SEE IF IT IS A COLON (:)
CPI ':'
JRZ SCAN3 ;YES, WE HAVE A DRIVE SPEC
DCX D ;NO, BACK UP PTR TO FIRST NON-BLANK CHAR
SCAN2:
LDA TDRIVE ;SET 1ST BYTE OF FCBDN AS DEFAULT DRIVE
MOV M,A
JR SCAN4
SCAN3:
MOV A,B ;WE HAVE A DRIVE SPEC
STA TEMPDR ;SET TEMPORARY DRIVE
MOV M,B ;SET 1ST BYTE OF FCBDN AS SPECIFIED DRIVE
INX D ;PT TO BYTE AFTER ':'
;
; EXTRACT FILENAME FROM POSSIBLE FILENAME.TYP
;
SCAN4:
XRA A ;A=0
STA QMCNT ;INIT COUNT OF NUMBER OF QUESTION MARKS IN FCB
MVI B,8 ;MAX OF 8 CHARS IN FILE NAME
CALL SCANF ;FILL FCB FILE NAME
;
; EXTRACT FILE TYPE FROM POSSIBLE FILENAME.TYP
;
MVI B,3 ;PREPARE TO EXTRACT TYPE
CPI '.' ;IF (DE) DELIMITER IS A '.', WE HAVE A TYPE
JRNZ SCAN15 ;FILL FILE TYPE BYTES WITH <SP>
INX D ;PT TO CHAR IN COMMAND LINE AFTER '.'
CALL SCANF ;FILL FCB FILE TYPE
JR SCAN16 ;SKIP TO NEXT PROCESSING
SCAN15:
CALL SCANF4 ;SPACE FILL
;
; FILL IN EX, S1, S2, AND RC WITH ZEROES
;
SCAN16:
MVI B,4 ;4 BYTES
SCAN17:
INX H ;PT TO NEXT BYTE IN FCBDN
MVI M,0
DJNZ SCAN17
;
; SCAN COMPLETE -- DE PTS TO DELIMITER BYTE AFTER TOKEN
;
SDED CIBPTR
;
; SET ZERO FLAG TO INDICATE PRESENCE OF '?' IN FILENAME.TYP
;
LDA QMCNT ;GET NUMBER OF QUESTION MARKS
ORA A ;SET ZERO FLAG TO INDICATE ANY '?'
RET
;
; SCANF -- SCAN TOKEN PTED TO BY DE FOR A MAX OF B BYTES; PLACE IT INTO
; FILE NAME FIELD PTED TO BY HL; EXPAND AND INTERPRET WILD CARDS OF
; '*' AND '?'; ON EXIT, DE PTS TO TERMINATING DELIMITER
;
SCANF:
CALL SDELM ;DONE IF DELIMITER ENCOUNTERED - <SP> FILL
JRZ SCANF4
INX H ;PT TO NEXT BYTE IN FCBDN
CPI '*' ;IS (DE) A WILD CARD?
JRNZ SCANF1 ;CONTINUE IF NOT
MVI M,'?' ;PLACE '?' IN FCBDN AND DON'T ADVANCE DE IF SO
CALL SCQ ;SCANNER COUNT QUESTION MARKS
JR SCANF2
SCANF1:
MOV M,A ;STORE FILENAME CHAR IN FCBDN
INX D ;PT TO NEXT CHAR IN COMMAND LINE
CPI '?' ;CHECK FOR QUESTION MARK (WILD)
CZ SCQ ;SCANNER COUNT QUESTION MARKS
SCANF2:
DJNZ SCANF ;DECREMENT CHAR COUNT UNTIL 8 ELAPSED
SCANF3:
CALL SDELM ;8 CHARS OR MORE - SKIP UNTIL DELIMITER
RZ ;ZERO FLAG SET IF DELIMITER FOUND
INX D ;PT TO NEXT CHAR IN COMMAND LINE
JR SCANF3
;
; FILL MEMORY POINTED TO BY HL WITH SPACES FOR B BYTES
;
SCANF4:
INX H ;PT TO NEXT BYTE IN FCBDN
MVI M,' ' ;FILL FILENAME PART WITH <SP>
DJNZ SCANF4
RET
;
; INCREMENT QUESTION MARK COUNT FOR SCANNER
; THIS ROUTINE INCREMENTS THE COUNT OF THE NUMBER OF QUESTION MARKS IN
; THE CURRENT FCB ENTRY
;
SCQ:
LDA QMCNT ;GET COUNT
INR A ;INCREMENT
STA QMCNT ;PUT COUNT
RET
;
; CMDTBL (COMMAND TABLE) SCANNER
; ON RETURN, HL PTS TO ADDRESS OF COMMAND IF CPR-RESIDENT
; ON RETURN, ZERO FLAG SET MEANS CPR-RESIDENT COMMAND
;
CMDSER:
LXI H,CMDTBL ;PT TO COMMAND TABLE
MVI C,NCMNDS ;SET COMMAND COUNTER
CMS1:
LXI D,FCBFN ;PT TO STORED COMMAND NAME
MVI B,NCHARS ;NUMBER OF CHARS/COMMAND (8 MAX)
CMS2:
LDAX D ;COMPARE AGAINST TABLE ENTRY
CMP M
JRNZ CMS3 ;NO MATCH
INX D ;PT TO NEXT CHAR
INX H
DJNZ CMS2 ;COUNT DOWN
LDAX D ;NEXT CHAR IN INPUT COMMAND MUST BE <SP>
CPI ' '
JRNZ CMS4
RET ;COMMAND IS CPR-RESIDENT (ZERO FLAG SET)
CMS3:
INX H ;SKIP TO NEXT COMMAND TABLE ENTRY
DJNZ CMS3
CMS4:
INX H ;SKIP ADDRESS
INX H
DCR C ;DECREMENT TABLE ENTRY NUMBER
JRNZ CMS1
INR C ;CLEAR ZERO FLAG
RET ;COMMAND IS DISK-RESIDENT (ZERO FLAG CLEAR)
;
;**** Section 5 ****
; CPR-Resident Commands
;
;
;Section 5A
;Command: DIR
;Function: To display a directory of the files on disk
;Forms:
; DIR <afn> Displays the DIR files
; DIR <afn> S Displays the SYS files
; DIR <afn> A Display both DIR and SYS files
;
DIR:
MVI A,80H ;SET SYSTEM BIT EXAMINATION
PUSH PSW
CALL SCANER ;EXTRACT POSSIBLE D:FILENAME.TYP TOKEN
CALL SLOGIN ;LOG IN DRIVE IF NECESSARY
LXI H,FCBFN ;MAKE FCB WILD (ALL '?') IF NO FILENAME.TYP
MOV A,M ;GET FIRST CHAR OF FILENAME.TYP
CPI ' ' ;IF <SP>, ALL WILD
CZ FILLQ
CALL ADVAN ;LOOK AT NEXT INPUT CHAR
MVI B,0 ;SYS TOKEN DEFAULT
JRZ DIR2 ;JUMP; THERE ISN'T ONE
CPI SYSFLG ;SYSTEM FLAG SPECIFIER?
JRZ GOTSYS ;GOT SYSTEM SPECIFIER
CPI SOFLG ;SYS ONLY?
JRNZ DIR2
MVI B,80H ;FLAG SYS ONLY
GOTSYS:
INX D
SDED CIBPTR
CPI SOFLG ;SYS ONLY SPEC?
JRZ DIR2 ;THEN LEAVE BIT SPEC UNCHAGNED
POP PSW ;GET FLAG
XRA A ;SET NO SYSTEM BIT EXAMINATION
PUSH PSW
DIR2:
POP PSW ;GET FLAG
DIR2A:
;DROP INTO DIRPR TO PRINT DIRECTORY
; THEN RESTART CPR
;
; DIRECTORY PRINT ROUTINE; ON ENTRY, MSB OF A IS 1 (80H) IF SYSTEM FILES EXCL
;
DIRPR:
MOV D,A ;STORE SYSTEM FLAG IN D
MVI E,0 ;SET COLUMN COUNTER TO ZERO
PUSH D ;SAVE COLUMN COUNTER (E) AND SYSTEM FLAG (D)
MOV A,B ;SYS ONLY SPECIFIER
STA SYSTST
CALL SEARF ;SEARCH FOR SPECIFIED FILE (FIRST OCCURRANCE)
CZ PRNNF ;PRINT NO FILE MSG;REG A NOT CHANGED
;
; ENTRY SELECTION LOOP; ON ENTRY, A=OFFSET FROM SEARF OR SEARN
;
DIR3:
JRZ DIR11 ;DONE IF ZERO FLAG SET
DCR A ;ADJUST TO RETURNED VALUE
RRC ;CONVERT NUMBER TO OFFSET INTO TBUFF
RRC
RRC
ANI 60H
MOV C,A ;OFFSET INTO TBUFF IN C (C=OFFSET TO ENTRY)
MVI A,10 ;ADD 10 TO PT TO SYSTEM FILE ATTRIBUTE BIT
CALL DIRPTR
POP D ;GET SYSTEM BIT MASK FROM D
PUSH D
ANA D ;MASK FOR SYSTEM BIT
SYSTST EQU $+1 ;POINTER TO IN-THE-CODE BUFFER SYSTST
CPI 0
JRNZ DIR10
POP D ;GET ENTRY COUNT (=<CR> COUNTER)
MOV A,E ;ADD 1 TO IT
INR E
PUSH D ;SAVE IT
ANI 03H ;OUTPUT <CRLF> IF 4 ENTRIES PRINTED IN LINE
PUSH PSW
JRNZ DIR4
CALL CRLF ;NEW LINE
JR DIR5
DIR4:
CALL PRINT
;
IF WIDE
DB ' ' ;2 SPACES
DB FENCE ;THEN FENCE CHAR
DB ' ',' '+80H ;THEN 2 MORE SPACES
ENDIF
;
IF NOT WIDE
DB ' ' ;SPACE
DB FENCE ;THEN FENCE CHAR
DB ' '+80H ;THEN SPACE
ENDIF
;
DIR5:
MVI B,01H ;PT TO 1ST BYTE OF FILE NAME
DIR6:
MOV A,B ;A=OFFSET
CALL DIRPTR ;HL NOW PTS TO 1ST BYTE OF FILE NAME
ANI 7FH ;MASK OUT MSB
CPI ' ' ;NO FILE NAME?
JRNZ DIR8 ;PRINT FILE NAME IF PRESENT
POP PSW
PUSH PSW
CPI 03H
JRNZ DIR7
MVI A,09H ;PT TO 1ST BYTE OF FILE TYPE
CALL DIRPTR ;HL NOW PTS TO 1ST BYTE OF FILE TYPE
ANI 7FH ;MASK OUT MSB
CPI ' ' ;NO FILE TYPE?
JRZ DIR9 ;CONTINUE IF SO
DIR7:
MVI A,' ' ;OUTPUT <SP>
DIR8:
CALL CONOUT ;PRINT CHAR
INR B ;INCR CHAR COUNT
MOV A,B
CPI 12 ;END OF FILENAME.TYP?
JRNC DIR9 ;CONTINUE IF SO
CPI 09H ;END IF FILENAME ONLY?
JRNZ DIR6 ;PRINT TYP IF SO
MVI A,'.' ;PRINT DOT BETWEEN FILE NAME AND TYPE
CALL CONOUT
JR DIR6
DIR9:
POP PSW
DIR10:
CALL BREAK ;CHECK FOR ABORT
JRNZ DIR11
CALL SEARN ;SEARCH FOR NEXT FILE
JR DIR3 ;CONTINUE
DIR11:
POP D ;RESTORE STACK
RET
;
; FILL FCB @HL WITH '?'
;
FILLQ:
MVI B,11 ;NUMBER OF CHARS IN FN & FT
FQLP:
MVI M,'?' ;STORE '?'
INX H
DJNZ FQLP
RET
;
;Section 5B
;Command: ERA
;Function: Erase files
;Forms:
; ERA <afn> Erase Specified files and print their names
;
IF NOT RAS ;NOT FOR REMOTE-ACCESS SYSTEM
;
ERA:
CALL SCANER ;PARSE FILE SPECIFICATION
CPI 11 ;ALL WILD (ALL FILES = 11 '?')?
JRNZ ERA1 ;IF NOT, THEN DO ERASES
CALL PRINTC
DB 'All','?'+80H
CALL CONIN ;GET REPLY
CPI 'Y' ;YES?
JNZ RESTRT ;RESTART CPR IF NOT
CALL CRLF ;NEW LINE
ERA1:
CALL SLOGIN ;LOG IN SELECTED DISK IF ANY
XRA A ;PRINT ALL FILES (EXAMINE SYSTEM BIT)
MOV B,A ;NO SYS-ONLY OPT TO DIRPR
CALL DIRPR ;PRINT DIRECTORY OF ERASED FILES
LXI D,FCBDN ;DELETE FILE SPECIFIED
CALL DELETE
RET ;REENTER CPR
;
ENDIF ;RAS
;
;Section 5C
;Command: LIST
;Function: Print out specified file on the LST: Device
;Forms:
; LIST <ufn> Print file (NO Paging)
;
LIST:
MVI A,0FFH ;TURN ON PRINTER FLAG
JR TYPE0
;
;Section 5D
;Command: TYPE
;Function: Print out specified file on the CON: Device
;Forms:
; TYPE <ufn> Print file
; TYPE <ufn> P Print file with paging flag
;
TYPE:
XRA A ;TURN OFF PRINTER FLAG
;
; ENTRY POINT FOR CPR LIST FUNCTION (LIST)
;
TYPE0:
STA PRFLG ;SET FLAG
CALL SCANER ;EXTRACT FILENAME.TYP TOKEN
JNZ ERROR ;ERROR IF ANY QUESTION MARKS
CALL ADVAN ;GET PGDFLG IF IT'S THERE
STA PGFLG ;SAVE IT AS A FLAG
JRZ NOSLAS ;JUMP IF INPUT ENDED
INX D ;PUT NEW BUF POINTER
XCHG
SHLD CIBPTR
NOSLAS:
CALL SLOGIN ;LOG IN SELECTED DISK IF ANY
CALL OPENF ;OPEN SELECTED FILE
JZ TYPE4 ;ABORT IF ERROR
CALL CRLF ;NEW LINE
MVI A,NLINES-1 ;SET LINE COUNT
STA PAGCNT
LXI H,CHRCNT ;SET CHAR POSITION/COUNT
MVI M,0FFH ;EMPTY LINE
MVI B,0 ;SET TAB CHAR COUNTER
TYPE1:
LXI H,CHRCNT ;PT TO CHAR POSITION/COUNT
MOV A,M ;END OF BUFFER?
CPI 80H
JRC TYPE2
PUSH H ;READ NEXT BLOCK
CALL READF
POP H
JRNZ TYPE3 ;ERROR?
XRA A ;RESET COUNT
MOV M,A
TYPE2:
INR M ;INCREMENT CHAR COUNT
LXI H,TBUFF ;PT TO BUFFER
CALL ADDAH ;COMPUTE ADDRESS OF NEXT CHAR FROM OFFSET
MOV A,M ;GET NEXT CHAR
ANI 7FH ;MASK OUT MSB
CPI 1AH ;END OF FILE (^Z)?
RZ ;RESTART CPR IF SO
;
; OUTPUT CHAR TO CON: OR LST: DEVICE WITH TABULATION
;
CPI CR ;RESET TAB COUNT?
JRZ TABRST
CPI LF ;RESET TAB COUNT?
JRZ TABRST
CPI TAB ;TAB?
JRZ LTAB
CALL LCOUT ;OUTPUT CHAR
INR B ;INCREMENT CHAR COUNT
JR TYPE2L
TABRST:
CALL LCOUT ;OUTPUT <CR> OR <LF>
MVI B,0 ;RESET TAB COUNTER
JR TYPE2L
LTAB:
MVI A,' ' ;<SP>
CALL LCOUT
INR B ;INCR POS COUNT
MOV A,B
ANI 7
JRNZ LTAB
;
; CONTINUE PROCESSING
;
TYPE2L:
CALL BREAK ;CHECK FOR ABORT
JRZ TYPE1 ;CONTINUE IF NO CHAR
CPI 'C'-'@' ;^C?
RZ ;RESTART IF SO
JR TYPE1
TYPE3:
DCR A ;NO ERROR?
RZ ;RESTART CPR
TYPE4:
JMP ERRLOG
;
; PAGING ROUTINES
; PAGER COUNTS DOWN LINES AND PAUSES FOR INPUT (DIRECT) IF COUNT EXPIRES
; PAGSET SETS LINES/PAGE COUNT
;
PAGER:
PUSH H
LXI H,PAGCNT ;COUNT DOWN
DCR M
JRNZ PGBAK ;JUMP IF NOT END OF PAGE
MVI M,NLINES-2 ;REFILL COUNTER
;
PGFLG EQU $+1 ;POINTER TO IN-THE-CODE BUFFER PGFLG
MVI A,0 ;0 MAY BE CHANGED BY PGFLG EQUATE
CPI PGDFLG ;PAGE DEFAULT OVERRIDE OPTION WANTED?
;
IF PGDFLT ;IF PAGING IS DEFAULT
JRZ PGBAK ; PGDFLG MEANS NO PAGING, PLEASE
ELSE ;IF PAGING NOT DEFAULT
JRNZ PGBAK ; PGDFLG MEANS PLEASE PAGINATE
ENDIF
;
CALL CONIN ;GET CHAR TO CONTINUE
CPI 'C'-'@' ;^C
JZ RSTCPR ;RESTART CPR
PGBAK:
POP H ;RESTORE HL
RET
;
;Section 5E
;Command: SAVE
;Function: To save the contents of the TPA onto disk as a file
;Forms:
; SAVE <Number of Pages> <ufn>
; Save specified number of pages (start at 100H)
; from TPA into specified file; <Number of
; Pages> is in DEC
; SAVE <Number of Sectors> <ufn> S
; Like SAVE above, but numeric argument specifies
; number of sectors rather than pages
;
IF NOT RAS ;NOT FOR REMOTE-ACCESS SYSTEM
;
SAVE:
CALL NUMBER ;EXTRACT NUMBER FROM COMMAND LINE
MOV L,A ;HL=PAGE COUNT
MVI H,0
PUSH H ;SAVE PAGE COUNT
CALL EXTEST ;TEST FOR EXISTENCE OF FILE AND ABORT IF SO
MVI C,16H ;BDOS MAKE FILE
CALL GRBDOS
POP H ;GET PAGE COUNT
JRZ SAVE3 ;ERROR?
XRA A ;SET RECORD COUNT FIELD OF NEW FILE'S FCB
STA FCBCR
CALL ADVAN ;LOOK FOR 'S' FOR SECTOR OPTION
INX D ;PT TO AFTER 'S' TOKEN
CPI SECTFLG
JRZ SAVE0
DCX D ;NO 'S' TOKEN, SO BACK UP
DAD H ;DOUBLE IT FOR HL=SECTOR (128 BYTES) COUNT
SAVE0:
SDED CIBPTR ;SET PTR TO BAD TOKEN OR AFTER GOOD TOKEN
LXI D,TPA ;PT TO START OF SAVE AREA (TPA)
SAVE1:
MOV A,H ;DONE WITH SAVE?
ORA L ;HL=0 IF SO
JRZ SAVE2
DCX H ;COUNT DOWN ON SECTORS
PUSH H ;SAVE PTR TO BLOCK TO SAVE
LXI H,128 ;128 BYTES PER SECTOR
DAD D ;PT TO NEXT SECTOR
PUSH H ;SAVE ON STACK
CALL DMASET ;SET DMA ADDRESS FOR WRITE (ADDRESS IN DE)
LXI D,FCBDN ;WRITE SECTOR
MVI C,15H ;BDOS WRITE SECTOR
CALL BDOSB ;SAVE BC
POP D ;GET PTR TO NEXT SECTOR IN DE
POP H ;GET SECTOR COUNT
JRNZ SAVE3 ;WRITE ERROR?
JR SAVE1 ;CONTINUE
SAVE2:
LXI D,FCBDN ;CLOSE SAVED FILE
CALL CLOSE
INR A ;ERROR?
JRNZ SAVE4
SAVE3:
CALL PRNLE ;PRINT 'NO SPACE' ERROR
SAVE4:
CALL DEFDMA ;SET DMA TO 0080
RET ;RESTART CPR
;
; Test File in FCB for existence, ask user to delete if so, and abort if he
; choses not to
;
EXTEST:
CALL SCANER ;EXTRACT FILE NAME
JNZ ERROR ;'?' IS NOT PERMITTED
CALL SLOGIN ;LOG IN SELECTED DISK
CALL SEARF ;LOOK FOR SPECIFIED FILE
LXI D,FCBDN ;PT TO FILE FCB
RZ ;OK IF NOT FOUND
PUSH D ;SAVE PTR TO FCB
CALL PRINTC
DB 'Delete File','?'+80H
CALL CONIN ;GET RESPONSE
POP D ;GET PTR TO FCB
CPI 'Y' ;KEY ON YES
JNZ RSTCPR ;RESTART IF NO
PUSH D ;SAVE PTR TO FCB
CALL DELETE ;DELETE FILE
POP D ;GET PTR TO FCB
RET
;
ENDIF ;RAS
;
;Section 5F
;Command: REN
;Function: To change the name of an existing file
;Forms:
; REN <New ufn>=<Old ufn> Perform function
;
IF NOT RAS ;NOT FOR REMOTE-ACCESS SYSTEM
;
REN:
CALL EXTEST ;TEST FOR FILE EXISTENCE AND RETURN
; IF FILE DOESN'T EXIST; ABORT IF IT DOES
LDA TEMPDR ;SAVE CURRENT DEFAULT DISK
PUSH PSW ;SAVE ON STACK
REN0:
LXI H,FCBDN ;SAVE NEW FILE NAME
LXI D,FCBDM
LXI B,16 ;16 BYTES
LDIR
CALL ADVAN ;ADVANCE CIBPTR
CPI '=' ;'=' OK
JRNZ REN4
REN1:
XCHG ;PT TO CHAR AFTER '=' IN HL
INX H
SHLD CIBPTR ;SAVE PTR TO OLD FILE NAME
CALL SCANER ;EXTRACT FILENAME.TYP TOKEN
JRNZ REN4 ;ERROR IF ANY '?'
POP PSW ;GET OLD DEFAULT DRIVE
MOV B,A ;SAVE IT
LXI H,TEMPDR ;COMPARE IT AGAINST CURRENT DEFAULT DRIVE
MOV A,M ;MATCH?
ORA A
JRZ REN2
CMP B ;CHECK FOR DRIVE ERROR
MOV M,B
JRNZ REN4
REN2:
MOV M,B
XRA A
STA FCBDN ;SET DEFAULT DRIVE
LXI D,FCBDN ;RENAME FILE
MVI C,17H ;BDOS RENAME FCT
CALL GRBDOS
RNZ
REN3:
CALL PRNNF ;PRINT NO FILE MSG
REN4:
JMP ERRLOG
;
ENDIF ;RAS
;
;Section 5G
;Command: USER
;Function: Change current USER number
;Forms:
; USER <unum> Select specified user number;<unum> is in DEC
;
USER:
CALL USRNUM ;EXTRACT USER NUMBER FROM COMMAND LINE
MOV E,A ;PLACE USER NUMBER IN E
CALL SETUSR ;SET SPECIFIED USER
RSTJMP:
JMP RCPRNL ;RESTART CPR
;
;Section 5H
;Command: DFU
;Function: Set the Default User Number for the command/file scanner
; (MEMLOAD)
;Forms:
; DFU <unum> Select Default User Number;<unum> is in DEC
;
DFU:
CALL USRNUM ;GET USER NUMBER
STA DFUSR ;PUT IT AWAY
JR RSTJMP ;RESTART CPR (NO DEFAULT LOGIN)
;
;Section 5I
;Command: JUMP
;Function: To Call the program (subroutine) at the specified address
; without loading from disk
;Forms:
; JUMP <adr> Call at <adr>;<adr> is in HEX
;
IF NOT RAS ;NOT FOR REMOTE-ACCESS SYSTEM
;
JUMP:
CALL HEXNUM ;GET LOAD ADDRESS IN HL
JR CALLPROG ;PERFORM CALL
;
ENDIF ;RAS
;
;Section 5J
;Command: GO
;Function: To Call the program in the TPA without loading
; loading from disk. Same as JUMP 100H, but much
; more convenient, especially when used with
; parameters for programs like STAT. Also can be
; allowed on remote-access systems with no problems.
;
;Form:
; GO <parameters like for COMMAND>
;
IF NOT RAS ;ONLY IF RAS
;
GO: LXI H,TPA ;Always to TPA
JR CALLPROG ;Perform call
;
ENDIF ;END OF GO FOR RAS
;
;Section 5K
;Command: COM file processing
;Function: To load the specified COM file from disk and execute it
;Forms:
; <command>
;
COM:
LDA FCBFN ;ANY COMMAND?
CPI ' ' ;' ' MEANS COMMAND WAS 'D:' TO SWITCH
JRNZ COM1 ;NOT <SP>, SO MUST BE TRANSIENT OR ERROR
LDA TEMPDR ;LOOK FOR DRIVE SPEC
ORA A ;IF ZERO, JUST BLANK
JZ RCPRNL
DCR A ;ADJUST FOR LOG IN
STA TDRIVE ;SET DEFAULT DRIVE
CALL SETU0D ;SET DRIVE WITH USER 0
CALL LOGIN ;LOG IN DRIVE
JMP RCPRNL ;RESTART CPR
COM1:
LDA FCBFT ;FILE TYPE MUST BE BLANK
CPI ' '
JNZ ERROR
LXI H,COMMSG ;PLACE DEFAULT FILE TYPE (COM) INTO FCB
LXI D,FCBFT ;COPY INTO FILE TYPE
LXI B,3 ;3 BYTES
LDIR
LXI H,TPA ;SET EXECUTION/LOAD ADDRESS
PUSH H ;SAVE FOR EXECUTION
CALL MEMLOAD ;LOAD MEMORY WITH FILE SPECIFIED IN CMD LINE
POP H ;GET EXECUTION ADDRESS
RNZ ;RETURN (ABORT) IF LOAD ERROR
;
; CALLPROG IS THE ENTRY POINT FOR THE EXECUTION OF THE LOADED
; PROGRAM;ON ENTRY TO THIS ROUTINE, HL MUST CONTAIN THE EXECUTION
; ADDRESS OF THE PROGRAM (SUBROUTINE) TO EXECUTE
;
CALLPROG:
SHLD EXECADR ;PERFORM IN-LINE CODE MODIFICATION
CALL DLOGIN ;LOG IN DEFAULT DRIVE
CALL SCANER ;SEARCH COMMAND LINE FOR NEXT TOKEN
LXI H,TEMPDR ;SAVE PTR TO DRIVE SPEC
PUSH H
MOV A,M ;SET DRIVE SPEC
STA FCBDN
LXI H,FCBDN+10H ;PT TO 2ND FILE NAME
CALL SCANX ;SCAN FOR IT AND LOAD IT INTO FCBDN+16
POP H ;SET UP DRIVE SPECS
MOV A,M
STA FCBDM
XRA A
STA FCBCR
LXI D,TFCB ;COPY TO DEFAULT FCB
LXI H,FCBDN ;FROM FCBDN
LXI B,33 ;SET UP DEFAULT FCB
LDIR
LXI H,CIBUFF
COM4:
MOV A,M ;SKIP TO END OF 2ND FILE NAME
ORA A ;END OF LINE?
JRZ COM5
CPI ' ' ;END OF TOKEN?
JRZ COM5
INX H
JR COM4
;
; LOAD COMMAND LINE INTO TBUFF
;
COM5:
MVI B,0 ;SET CHAR COUNT
LXI D,TBUFF+1 ;PT TO CHAR POS
COM6:
MOV A,M ;COPY COMMAND LINE TO TBUFF
STAX D
ORA A ;DONE IF ZERO
JRZ COM7
INR B ;INCR CHAR COUNT
INX H ;PT TO NEXT
INX D
JR COM6
;
; RUN LOADED TRANSIENT PROGRAM
;
COM7:
MOV A,B ;SAVE CHAR COUNT
STA TBUFF
CALL CRLF ;NEW LINE
CALL DEFDMA ;SET DMA TO 0080
CALL SETUD ;SET USER/DISK
;
; EXECUTION (CALL) OF PROGRAM (SUBROUTINE) OCCURS HERE
;
EXECADR EQU $+1 ;CHANGE ADDRESS FOR IN-LINE CODE MODIFICATION
CALL TPA ;CALL TRANSIENT
CALL DEFDMA ;SET DMA TO 0080, IN CASE
;PROG CHANGED IT ON US
CALL SETU0D ;SET USER 0/DISK
CALL LOGIN ;LOGIN DISK
JMP RESTRT ;RESTART CPR
;
; TRANSIENT LOAD ERROR
;
COM8:
POP H ;CLEAR RETURN ADDRESS
CALL RESETUSR ;RESET CURRENT USER NUMBER
; RESET MUST BE DONE BEFORE LOGIN
ERRLOG:
CALL DLOGIN ;LOG IN DEFAULT DISK
ERRJMP:
JMP ERROR
;
;Section 5L
;Command: GET
;Function: To load the specified file from disk to the specified address
;Forms:
; GET <adr> <ufn> Load the specified file at the specified page;
; <adr> is in HEX
;
IF NOT RAS ;NOT FOR REMOTE-ACCESS SYSTEM
;
GET:
CALL HEXNUM ;GET LOAD ADDRESS IN HL
PUSH H ;SAVE ADDRESS
CALL SCANER ;GET FILE NAME
POP H ;RESTORE ADDRESS
JRNZ ERRJMP ;MUST BE UNAMBIGUOUS
;
; FALL THRU TO MEMLOAD
;
ENDIF ;RAS
;
; LOAD MEMORY WITH THE FILE WHOSE NAME IS SPECIFIED IN THE COMMAND LINE
; ON INPUT, HL CONTAINS STARTING ADDRESS TO LOAD
;
MEMLOAD:
CALL MLOAD ;USER MEMORY LOAD SUBROUTINE
PUSH PSW ;SAVE RETURN STATUS
CALL RESETUSR ;RESET USER NUMBER
POP PSW ;GET RETURN STATUS
RET
;
; MEMORY LOAD SUBROUTINE
; EXIT POINTS ARE A SIMPLE RETURN WITH THE ZERO FLAG SET IF NO ERROR,
; A SIMPLE RETURN WITH THE ZERO FLAG RESET (NZ) IF MEMORY FULL, OR A JMP TO
; COM8 IF COM FILE NOT FOUND
;
MLOAD:
SHLD LOADADR ;SET LOAD ADDRESS
CALL GETUSR ;GET CURRENT USER NUMBER
STA TMPUSR ;SAVE IT FOR LATER
STA TSELUSR ;TEMP USER TO SELECT
;
; MLA is a reentry point for a non-standard CP/M Modification
; This is the return point for when the .COM (or GET) file is not found the
; first time, Drive A: is selected for a second attempt
;
MLA:
CALL SLOGIN ;LOG IN SPECIFIED DRIVE IF ANY
CALL OPENF ;OPEN COMMAND.COM FILE
JRNZ MLA1 ;FILE FOUND - LOAD IT
;
; ERROR ROUTINE TO SELECT USER 0 IF ALL ELSE FAILS
;
DFUSR EQU $+1 ;MARK IN-THE-CODE VARIABLE
MVI A,DEFUSR ;GET DEFAULT USER
TSELUSR EQU $+1 ;MARK IN-THE-CODE VARIABLE
CPI DEFUSR ;SAME?
JRZ MLA0 ;JUMP IF
STA TSELUSR ;ELSE PUT DOWN NEW ONE
MOV E,A
CALL SETUSR ;GO SET NEW USER NUMBER
JR MLA ;AND TRY AGAIN
;
; ERROR ROUTINE TO SELECT DRIVE A: IF DEFAULT WAS ORIGINALLY SELECTED
;
MLA0:
LXI H,TEMPDR ;GET DRIVE FROM CURRENT COMMAND
XRA A ;A=0
ORA M
JNZ COM8 ;ERROR IF ALREADY DISK A:
MVI M,1 ;SELECT DRIVE A:
JR MLA
;
; FILE FOUND -- PROCEED WITH LOAD
;
MLA1:
LOADADR EQU $+1 ;MEMORY LOAD ADDRESS (IN-LINE CODE MOD)
LXI H,TPA ;SET START ADDRESS OF MEMORY LOAD
ML2:
MVI A,ENTRY/256-1 ;GET HIGH-ORDER ADR OF JUST BELOW CPR
CMP H ;ARE WE GOING TO OVERWRITE THE CPR?
JRC PRNLE ;ERROR IF SO
PUSH H ;SAVE ADDRESS OF NEXT SECTOR
XCHG ;... IN DE
CALL DMASET ;SET DMA ADDRESS FOR LOAD
LXI D,FCBDN ;READ NEXT SECTOR
CALL READ
POP H ;GET ADDRESS OF NEXT SECTOR
JRNZ ML3 ;READ ERROR OR EOF?
LXI D,128 ;MOVE 128 BYTES PER SECTOR
DAD D ;PT TO NEXT SECTOR IN HL
JR ML2
;
ML3:
DCR A ;LOAD COMPLETE
RZ ;OK IF ZERO, ELSE FALL THRU TO PRNLE
;
; LOAD ERROR
;
PRNLE:
CALL PRINTC
DB 'Ful','l'+80H
MVI A,1 ;SET NON-ZERO TO INDICATE ERROR
ORA A ;SET FLAG
RET
;
END