You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2306 lines
44 KiB

* SYSTEM SEGMENT: SYS.RCP
* SYSTEM: ARIES-1
* CUSTOMIZED BY: RICHARD CONN
*
* PROGRAM: SYSRCP.ASM
* AUTHOR: RICHARD CONN
* VERSION: 1.0
* DATE: 3 FEB 84
* PREVIOUS VERSIONS: NONE
*
VERSION EQU 10
*
* SYSRCP is a resident command processor for ZCPR3. As with
* all resident command processors, SYSRCP performs the following functions:
*
* 1. Assuming that the EXTFCB contains the name of the
* command, SYSRCP looks to see if the first character
* of the file name field in the EXTFCB is a question
* mark; if so, it returns with the Zero Flag Set and
* HL pointing to the internal routine which prints
* its list of commands
* 2. The resident command list in SYSRCP is scanned for
* the entry contained in the file name field of
* EXTFCB; if found, SYSRCP returns with the Zero Flag
* Set and HL pointing to the internal routine which
* implements the function; if not found, SYSRCP returns
* with the Zero Flag Reset (NZ)
*
*
* Global Library which Defines Addresses for SYSRCP
*
MACLIB Z3BASE ; USE BASE ADDRESSES
MACLIB SYSRCP ; USE SYSRCP HEADER
;
CTRLC EQU 'C'-'@'
TAB EQU 09H
LF EQU 0AH
FF EQU 0CH
CR EQU 0DH
CTRLX EQU 'X'-'@'
;
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
FCB1 EQU TFCB ;1st and 2nd FCBs
FCB2 EQU TFCB+16
TBUFF EQU BASE+0080H ;DEFAULT DISK I/O BUFFER
TPA EQU BASE+0100H ;BASE OF TPA
DIRBUF EQU BASE+4000H ;DIR BUFFER (MANY ENTRIES PERMITTED)
PAGCNT EQU DIRBUF-100H ;PAGE COUNT BUFFER
OLDFCB EQU PAGCNT+1 ;OLD FCB BUFFER
CPBLOCKS EQU 32 ;USE 4K FOR BUFFERING OF COPY
;
$-MACRO ;FIRST TURN OFF THE EXPANSIONS
;
; MACROS TO PROVIDE Z80 EXTENSIONS
; MACROS INCLUDE:
;
; 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
;
; @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,?DD ;Displacement Range Error on Jump Relative
ELSE
DB ?DD
ENDIF ;;RANGE ERROR
ENDM
;
;
; Z80 MACRO EXTENSIONS
;
JR MACRO ?N ;;JUMP RELATIVE
IF I8080 ;;8080/8085
JMP ?N
ELSE ;;Z80
DB 18H
@GENDD ?N-$-1
ENDIF ;;I8080
ENDM
;
JRC MACRO ?N ;;JUMP RELATIVE ON CARRY
IF I8080 ;;8080/8085
JC ?N
ELSE ;;Z80
DB 38H
@GENDD ?N-$-1
ENDIF ;;I8080
ENDM
;
JRNC MACRO ?N ;;JUMP RELATIVE ON NO CARRY
IF I8080 ;;8080/8085
JNC ?N
ELSE ;;Z80
DB 30H
@GENDD ?N-$-1
ENDIF ;;I8080
ENDM
;
JRZ MACRO ?N ;;JUMP RELATIVE ON ZERO
IF I8080 ;;8080/8085
JZ ?N
ELSE ;;Z80
DB 28H
@GENDD ?N-$-1
ENDIF ;;I8080
ENDM
;
JRNZ MACRO ?N ;;JUMP RELATIVE ON NO ZERO
IF I8080 ;;8080/8085
JNZ ?N
ELSE ;;Z80
DB 20H
@GENDD ?N-$-1
ENDIF ;;I8080
ENDM
;
DJNZ MACRO ?N ;;DECREMENT B AND JUMP RELATIVE ON NO ZERO
IF I8080 ;;8080/8085
DCR B
JNZ ?N
ELSE ;;Z80
DB 10H
@GENDD ?N-$-1
ENDIF ;;I8080
ENDM
*
* SYSTEM Entry Point
*
org rcp ; passed for Z3BASE
db 'Z3RCP' ; Flag for Package Loader
*
* **** Command Table for RCP ****
* This table is RCP-dependent!
*
* The command name table is structured as follows:
*
* ctable:
* DB 'CMNDNAME' ; Table Record Structure is
* DW cmndaddress ; 8 Chars for Name and 2 Bytes for Adr
* ...
* DB 0 ; End of Table
*
cnsize equ 4 ; NUMBER OF CHARS IN COMMAND NAME
db cnsize ; size of text entries
ctab:
db 'H ' ; Help for RCP
dw clist
ctab1:
;
IF CPON
db 'CP ' ; Copy
dw copy
ENDIF ;CPON
;
IF DIRON
db 'DIR ' ; Directory
dw dir
ENDIF ;DIRON
;
IF ECHOON
db 'ECHO' ; Echo
dw echo
ENDIF
;
IF ERAON
db 'ERA ' ; Erase
dw era
ENDIF ;ERAON
;
IF LTON AND LISTON
db 'LIST' ; List
dw list
ENDIF ;LTON AND LISTON
;
IF NOTEON
db 'NOTE' ; Note-Comment-NOP Command
dw note
ENDIF
;
IF PEEKON
db 'P ' ; Peek into Memory
dw peek
ENDIF ;PEEKON
;
IF POKEON
db 'POKE' ; Poke Values into Memory
dw poke
ENDIF ;POKEON
;
IF PROTON
db 'PROT' ; Protection Codes
dw att
ENDIF ;PROTON
;
IF REGON
db 'REG ' ; Register Command
dw regcmd
ENDIF ;RSETON
;
IF RENON
db 'REN ' ; Rename
dw ren
ENDIF ;RENON
;
IF LTON
db 'TYPE' ; Type
dw type
ENDIF ;LTON
;
IF WHLON
db 'WHL ' ; Wheel
dw whl
db 'WHLQ' ; Wheel Query
dw whlmsg
ENDIF ;WHLON
;
db 0
*
* BANNER NAME OF RCP
*
rcp$name:
db 'SYS '
db (version/10)+'0','.',(version mod 10)+'0'
db RCPID
db 0
*
* Command List Routine
*
clist:
lxi h,rcp$name ; print RCP Name
call print1
lxi h,ctab1 ; print table entries
mvi c,1 ; set count for new line
clist1:
mov a,m ; done?
ora a
rz
dcr c ; count down
jrnz clist1a
call crlf ; new line
mvi c,4 ; set count
clist1a:
lxi d,entryname ; copy command name into message buffer
mvi b,cnsize ; number of chars
clist2:
mov a,m ; copy
stax d
inx h ; pt to next
inx d
dcr b
jnz clist2
inx h ; skip to next entry
inx h
push h ; save ptr
lxi h,entrymsg ; print message
call print1
pop h ; get ptr
jmp clist1
*
* Console Output Routine
*
conout:
push h ; save regs
push d
push b
push psw
ani 7fh ; mask MSB
mov e,a ; char in E
mvi c,2 ; output
call bdos
pop psw ; get regs
pop b
pop d
pop h
;
; This simple return doubles for the NOTE Command (NOP) and CONOUT Exit
; NOTE Command: NOTE any text
;
NOTE:
ret
*
* Print String (terminated in 0 or MSB Set) at Return Address
*
print:
xthl ; get address
call print1
xthl ; put address
ret
*
* Print String (terminated in 0 or MSB Set) pted to by HL
*
print1:
mov a,m ; done?
inx h ; pt to next
ora a ; 0 terminator
rz
call conout ; print char
rm ; MSB terminator
jmp print1
*
* CLIST Messages
*
entrymsg:
db ' ' ; command name prefix
entryname:
ds cnsize ; command name
db 0 ; terminator
*
* **** RCP Routines ****
* All code from here on is RCP-dependent!
*
;
;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
;Notes:
; The flag SYSFLG defines the letter used to display both DIR and
; SYS files (A in the above Forms section)
; The flag SOFLG defines the letter used to display only the SYS
; files (S in the above Forms section)
; The flag WIDE determines if the file names are spaced further
; apart (WIDE=TRUE) for 80-col screens
; The flag FENCE defines the character used to separate the file
; names
;
IF DIRON
DIR:
;
; CHECK FOR WHEEL APPROVAL IF OPTION ENABLED
;
IF WDIR
CALL WHLTST
ENDIF ;WHEEL APPROVAL
;
CALL RETSAVE ;SAVE RET ADDRESS AND SET STACK
LXI H,FCB1+1 ;MAKE FCB WILD (ALL '?') IF NO FILENAME.TYP
MOV A,M ;GET FIRST CHAR OF FILENAME.TYP
CPI ' ' ;IF <SP>, ALL WILD
CZ FILLQ
LDA FCB2+1 ;GET FIRST CHAR OF 2ND FILE NAME
MVI B,80H ;PREPARE FOR DIR-ONLY SELECTION
CPI ' ' ;ANY FLAG?
JRZ DIRPR ;THERE IS NO FLAG, SO DIR ONLY
MVI B,1 ;SET FOR BOTH DIR AND SYS FILES
CPI SYSFLG ;SYSTEM AND DIR FLAG SPECIFIER?
JRZ DIRPR ;GOT SYSTEM SPECIFIER
CPI SOFLG ;SYS ONLY?
JRNZ DIRPR
DCR B ;B=0 FOR SYS FILES ONLY
;
ENDIF ;DIRON
;
; DIRECTORY PRINT ROUTINE; ON ENTRY, B REG IS SET AS FOLLOWS:
; 0 FOR ONLY SYSTEM FILES, 80H FOR ONLY DIR FILES, 1 FOR BOTH
;
IF DIRON OR ERAON OR LTON OR PROTON OR CPON OR RENON
DIRPR:
MOV A,B ;GET SYSTST FLAG
CALL GETDIR ;LOAD AND SORT DIRECTORY
JZ PRFNF ;PRINT NO FILE MESSAGE
MVI E,4 ;COUNT DOWN TO 0
;
; ENTRY PRINT LOOP; ON ENTRY, HL PTS TO FILES SELECTED (TERMINATED BY 0)
; AND E IS ENTRY COUNTER
;
DIR3:
MOV A,M ;CHECK FOR DONE
ORA A
JZ EXIT ;EXIT IF DONE
MOV A,E ;GET ENTRY COUNTER
ORA A ;OUTPUT <CRLF> IF 4 ENTRIES PRINTED IN LINE
CZ DIRCRLF ;NEW LINE
MOV A,E ;GET ENTRY COUNT
CPI 4 ;FIRST ENTRY?
JRZ DIR4
CALL PRINT
;
IF WIDE
;
DB ' ' ;2 SPACES
DB FENCE ;THEN FENCE CHAR
DB ' '+80H ;THEN 1 MORE SPACE
;
ELSE
;
DB ' ' ;SPACE
DB FENCE+80H ;THEN FENCE CHAR
;
ENDIF ;WIDE
;
DIR4:
CALL PRFN ;PRINT FILE NAME
CALL BREAK ;CHECK FOR ABORT
DCR E ;DECREMENT ENTRY COUNTER
JR DIR3
;
; CRLF FOR DIR ROUTINE
;
DIRCRLF:
PUSH PSW ;DON'T AFFECT PSW
CALL CRLF ;NEW LINE
POP PSW
MVI E,4 ;RESET ENTRY COUNTER
RET
;
; AFTER A SEARCH, RETURN NZ SET IF DESIRED TYPE OF FILE FOUND, Z IF NOT
; THIS ALGORITHM LOOKS AT THE SYSTEM BIT OF THE LOCATED FILE; THIS
; BIT IS SET TO 1 IF THE FILE IS A SYSTEM FILE AND 0 IF NOT A SYSTEM
; FILE. THE FOLLOWING EXCLUSIVE OR MASKS ARE APPLIED TO RETURN Z OR NZ
; AS REQUIRED BY THE CALLING PROGRAM:
;
; SYSTEM BYTE: X 0 0 0 0 0 0 0 (AFTER 80H MASK, X=1 IF SYS, 0 IF DIR)
;
; SYS-ONLY : 0 0 0 0 0 0 0 0 (XOR 0 = 0 if X=0, = 80H if X=1)
; DIR-ONLY : 1 0 0 0 0 0 0 0 (XOR 80H = 80h if X=0, = 0 if X=1)
; BOTH : 0 0 0 0 0 0 0 1 (XOR 1 = 81H or 1H, NZ in both cases)
;
GETSBIT:
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)
LXI D,TBUFF ;PT TO BUFFER
MOV A,E ;BASE ADDRESS IN A
ADD C ;ADD IN ENTRY OFFSET
MOV E,A ;RESULT IN E
PUSH D ;SAVE PTR IN DE
ADI 10 ;ADD OFFSET OF 10 TO PT TO SYSTEM BYTE
MOV E,A ;SET ADDRESS
LDAX D ;GET BYTE
POP D ;GET PTR IN DE
ANI 80H ;LOOK AT ONLY SYSTEM BIT
SYSTST EQU $+1 ;IN-THE-CODE VARIABLE
XRI 0 ; IF SYSTST=0, SYS ONLY; IF SYSTST=80H, DIR
; ONLY; IF SYSTST=1, BOTH SYS AND DIR
RET ;NZ IF OK, Z IF NOT OK
;
; FILL FCB @HL WITH '?'
;
FILLQ:
MVI B,11 ;NUMBER OF CHARS IN FN & FT
MVI A,'?' ;STORE '?'
FILLP:
MOV M,A ;STORE BYTE
INX H ;PT TO NEXT
DJNZ FILLP ;COUNT DOWN
RET
;
; LOAD DIRECTORY AND SORT IT
; ON INPUT, A=SYSTST FLAG (0=SYS, 1=DIR, 80H=BOTH)
; DIRECTORY IS LOADED INTO DIRBUF
; RETURN WITH ZERO SET IF NO MATCH AND HL PTS TO 1ST ENTRY IF MATCH
;
GETDIR:
STA SYSTST ; SET SYSTEM TEST FLAG
CALL LOGUSR ; LOG INTO USER AREA OF FCB1
LXI H,DIRBUF ; PT TO DIR BUFFER
MVI M,0 ; SET EMPTY
LXI B,0 ; SET COUNTER
CALL SEARF ; LOOK FOR MATCH
RZ ; RETURN IF NOT FOUND
;
; STEP 1: LOAD DIRECTORY
;
GD1:
PUSH B ; SAVE COUNTER
CALL GETSBIT ; CHECK FOR SYSTEM OK
POP B
JRZ GD2 ; NOT OK, SO SKIP
PUSH B ; SAVE COUNTER
INX D ; PT TO FILE NAME
XCHG ; HL PTS TO FILE NAME, DE PTS TO BUFFER
MVI B,11 ; COPY 11 BYTES
CALL LDIR ; DO COPY
XCHG ; HL PTS TO NEXT BUFFER LOCATION
POP B ; GET COUNTER
INX B ; INCREMENT COUNTER
GD2:
CALL SEARN ; LOOK FOR NEXT
JRNZ GD1
MVI M,0 ; STORE ENDING 0
LXI H,DIRBUF ; PT TO DIR BUFFER
MOV A,M ; CHECK FOR EMPTY
ORA A
RZ
;
; STEP 2: SORT DIRECTORY
;
PUSH H ; SAVE PTR TO DIRBUF FOR RETURN
CALL DIRALPHA ; SORT
POP H
XRA A ; SET NZ FLAG FOR OK
DCR A
RET
;*
;* DIRALPHA -- ALPHABETIZES DIRECTORY IN DIRBUF; BC CONTAINS
;* THE NUMBER OF FILES IN THE DIRECTORY
;*
DIRALPHA:
MOV A,B ; ANY FILES?
ORA C
RZ
MOV H,B ; HL=BC=FILE COUNT
MOV L,C
SHLD N ; SET "N"
;*
;* SHELL SORT --
;* THIS SORT ROUTINE IS ADAPTED FROM "SOFTWARE TOOLS"
;* BY KERNIGAN AND PLAUGHER, PAGE 106. COPYRIGHT, 1976, ADDISON-WESLEY.
;* ON ENTRY, BC=NUMBER OF ENTRIES
;*
N EQU $+1 ; POINTER FOR IN-THE-CODE MODIFICATION
LXI H,0 ; NUMBER OF ITEMS TO SORT
SHLD GAP ; SET INITIAL GAP TO N FOR FIRST DIVISION BY 2
;* FOR (GAP = N/2; GAP > 0; GAP = GAP/2)
SRTL0:
ORA A ; CLEAR CARRY
GAP EQU $+1 ; POINTER FOR IN-THE-CODE MODIFICATION
LXI H,0 ; GET PREVIOUS GAP
MOV A,H ; ROTATE RIGHT TO DIVIDE BY 2
RAR
MOV H,A
MOV A,L
RAR
MOV L,A
;* TEST FOR ZERO
ORA H
RZ ; DONE WITH SORT IF GAP = 0
SHLD GAP ; SET VALUE OF GAP
SHLD I ; SET I=GAP FOR FOLLOWING LOOP
;* FOR (I = GAP + 1; I <= N; I = I + 1)
SRTL1:
I EQU $+1 ; POINTER FOR IN-THE-CODE MODIFICATION
LXI H,0 ; ADD 1 TO I
INX H
SHLD I
;* TEST FOR I <= N
XCHG ; I IS IN DE
LHLD N ; GET N
MOV A,L ; COMPARE BY SUBTRACTION
SUB E
MOV A,H
SBB D ; CARRY SET MEANS I > N
JRC SRTL0 ; DON'T DO FOR LOOP IF I > N
LHLD I ; SET J = I INITIALLY FOR FIRST SUBTRACTION OF GAP
SHLD J
;* FOR (J = I - GAP; J > 0; J = J - GAP)
SRTL2:
LHLD GAP ; GET GAP
XCHG ; ... IN DE
J EQU $+1 ; POINTER FOR IN-THE-CODE MODIFICATION
LXI H,0 ; GET J
MOV A,L ; COMPUTE J - GAP
SUB E
MOV L,A
MOV A,H
SBB D
MOV H,A
SHLD J ; J = J - GAP
JRC SRTL1 ; IF CARRY FROM SUBTRACTIONS, J < 0 AND ABORT
MOV A,H ; J=0?
ORA L
JRZ SRTL1 ; IF ZERO, J=0 AND ABORT
;* SET JG = J + GAP
XCHG ; J IN DE
LHLD GAP ; GET GAP
DAD D ; J + GAP
SHLD JG ; JG = J + GAP
;* IF (V(J) <= V(JG))
CALL ICOMPARE ; J IN DE, JG IN HL
;* ... THEN BREAK
JRC SRTL1
;* ... ELSE EXCHANGE
LHLD J ; SWAP J, JG
XCHG
JG EQU $+1 ; POINTER FOR IN-THE-CODE MODIFICATION
LXI H,0
CALL ISWAP ; J IN DE, JG IN HL
;* END OF INNER-MOST FOR LOOP
JR SRTL2
;*
;* SWAP (Exchange) the elements whose indexes are in HL and DE
;*
ISWAP:
CALL IPOS ; COMPUTE POSITION FROM INDEX
XCHG
CALL IPOS ; COMPUTE 2ND ELEMENT POSITION FROM INDEX
MVI B,11 ; 11 BYTES TO FLIP
ISWAP1:
LDAX D ; GET BYTES
MOV C,M
MOV M,A ; PUT BYTES
MOV A,C
STAX D
INX H ; PT TO NEXT
INX D
DJNZ ISWAP1
RET
;*
;* ICOMPARE compares the entry pointed to by the pointer pointed to by HL
;* with that pointed to by DE (1st level indirect addressing); on entry,
;* HL and DE contain the numbers of the elements to compare (1, 2, ...);
;* on exit, Carry Set means ((DE)) < ((HL)), Zero Set means ((HL)) = ((DE)),
;* and Non-Zero and No-Carry means ((DE)) > ((HL))
;*
ICOMPARE:
CALL IPOS ; GET POSITION OF FIRST ELEMENT
XCHG
CALL IPOS ; GET POSITION OF 2ND ELEMENT
XCHG
;*
;* COMPARE DIR ENTRY PTED TO BY HL WITH THAT PTED TO BY DE;
;* NO NET EFFECT ON HL, DE; RET W/CARRY SET MEANS DE<HL
;* RET W/ZERO SET MEANS DE=HL
;*
IF NOT SORTNT ; TYPE AND NAME?
;*
;* COMPARE BY FILE TYPE AND FILE NAME
;*
PUSH H
PUSH D
LXI B,8 ; PT TO FT (8 BYTES)
DAD B
XCHG
DAD B
XCHG ; DE, HL NOW PT TO THEIR FT'S
MVI B,3 ; 3 BYTES
CALL COMP ; COMPARE FT'S
POP D
POP H
RNZ ; CONTINUE IF COMPLETE MATCH
MVI B,8 ; 8 BYTES
JR COMP ; COMPARE FN'S
;
ELSE ; NAME AND TYPE
;*
;* COMPARE BY FILE NAME AND FILE TYPE
;*
MVI B,11 ; COMPARE FN, FT AND FALL THRU TO COMP
;*
;* COMP COMPARES DE W/HL FOR B BYTES; RET W/CARRY IF DE<HL
;* MSB IS DISREGARDED
;*
COMP:
MOV A,M ; GET (HL)
ANI 7FH ; MASK MSB
MOV C,A ; ... IN C
LDAX D ; COMPARE
ANI 7FH ; MASK MSB
CMP C
RNZ
INX H ; PT TO NEXT
INX D
DJNZ COMP ; COUNT DOWN
RET
;
ENDIF ; NOT SORTNT
;*
;* Compute physical position of element whose index is in HL; on exit, HL
;* is the physical address of this element; Indexes are 1..N
;*
IPOS:
DCX H ; HL=(HL-1)*11+DIRBUF
MOV B,H ; BC=HL
MOV C,L
DAD H ; HL=HL*2
DAD H ; HL=HL*4
DAD B ; HL=HL*5
DAD H ; HL=HL*10
DAD B ; HL=HL*11
LXI B,DIRBUF ; ADD IN DIRBUF
DAD B
RET
;
ENDIF ;DIRON OR ERAON OR LTON OR PROTON OR CPON OR RENON
;
;Section 5B
;Command: ERA
;Function: Erase files
;Forms:
; ERA <afn> Erase Specified files and print their names
; ERA <afn> I Erase Specified files and print their names, but ask
; for verification before Erase is done
;
IF ERAON
ERA:
;
; CHECK FOR WHEEL APPROVAL IF OPTION ENABLED
;
IF WERA
CALL WHLTST
ENDIF ;WHEEL APPROVAL
;
CALL RETSAVE
LDA FCB2+1 ;GET ERAFLG IF IT'S THERE
STA ERAFLG ;SAVE IT AS A FLAG
MVI A,1 ;DIR FILES ONLY
CALL GETDIR ;LOAD DIRECTORY OF FILES
JZ PRFNF ;ABORT IF NO FILES
;
; MAIN ERASE LOOP
;
ERA1:
PUSH H ;SAVE PTR TO FILE
CALL PRFN ;PRINT ITS NAME
SHLD NXTFILE ;SAVE PTR TO NEXT FILE
POP H ;GET PTR TO THIS FILE
CALL ROTEST ;TEST FILE PTED TO BY HL FOR R/O
JRNZ ERA3
ERAFLG EQU $+1 ;ADDRESS OF FLAG
MVI A,0 ;2ND BYTE IS FLAG
CPI 'I' ;IS IT AN INSPECT OPTION?
JRNZ ERA2 ;SKIP PROMPT IF IT IS NOT
CALL ERAQ ;ERASE?
JRNZ ERA3 ;SKIP IF NOT
ERA2:
LXI D,FCB1+1 ;COPY INTO FCB1
MVI B,11 ;11 BYTES
CALL LDIR
CALL INITFCB1 ;INIT FCB
MVI C,19 ;DELETE FILE
CALL BDOS
ERA3:
LHLD NXTFILE ;HL PTS TO NEXT FILE
MOV A,M ;GET CHAR
ORA A ;DONE?
JZ EXIT
CALL CRLF ;NEW LINE
JR ERA1
;
ENDIF ;ERAON
;
;Section 5C
;Command: LIST
;Function: Print out specified file on the LST: Device
;Forms:
; LIST <afn> Print file (NO Paging)
;Notes:
; The flags which apply to TYPE do not take effect with LIST
;
IF LTON
LIST:
;
; CHECK FOR WHEEL APPROVAL IF OPTION ENABLED
;
IF WLIST
CALL WHLTST
ENDIF ;WHEEL APPROVAL
;
CALL RETSAVE
MVI A,0FFH ;TURN ON PRINTER FLAG
JR TYPE0
;
;Section 5D
;Command: TYPE
;Function: Print out specified file on the CON: Device
;Forms:
; TYPE <afn> Print file
; TYPE <afn> P Print file with paging flag
;Notes:
; The flag PGDFLG defines the letter which toggles the paging
; facility (P in the forms section above)
; The flag PGDFLT determines if TYPE is to page by default
; (PGDFLT=TRUE if TYPE pages by default); combined with
; PGDFLG, the following events occur --
; If PGDFLT = TRUE, PGDFLG turns OFF paging
; If PGDFLT = FALSE, PGDFLG turns ON paging
;
TYPE:
;
; CHECK FOR WHEEL APPROVAL IF OPTION ENABLED
;
IF WTYPE
CALL WHLTST
ENDIF ;WHEEL APPROVAL
;
CALL RETSAVE
XRA A ;TURN OFF PRINTER FLAG
;
; ENTRY POINT FOR CPR LIST FUNCTION (LIST)
;
TYPE0:
STA PRFLG ;SET FLAG
LDA FCB2+1 ;GET PAGE FLAG
STA PGFLG ;SAVE IT AS A FLAG
MVI A,1 ;SELECT DIR FILES
CALL GETDIR ;ALLOW AMBIGUOUS FILES
JZ PRFNF ;NO FILES
SHLD NXTFILE ;SET PTR TO NEXT FILE
JR TYPEX2
TYPEX:
LHLD NXTFILE ;GET PTR TO NEXT FILE
MOV A,M ;ANY FILES?
ORA A
JZ EXIT
LDA PRFLG ;CHECK FOR LIST OUTPUT
ORA A ;0=TYPE
JRZ TYPEX1
MVI A,CR ;BOL ON PRINTER
CALL LCOUT
MVI A,FF ;FORM FEED THE PRINTER
CALL LCOUT
JR TYPEX2
TYPEX1:
CALL PAGEBREAK ;PAGE BREAK MESSAGE
TYPEX2:
LXI D,FCB1+1 ;COPY INTO FCB1
MVI B,11 ;11 BYTES
CALL LDIR
SHLD NXTFILE ;SET PTR TO NEXT FILE
CALL INITFCB1 ;INIT FCB1
MVI C,15 ;OPEN FILE
CALL BDOS
INR A ;SET ERROR FLAG
JZ PRFNF ;ABORT IF ERROR
MVI A,NLINES-2 ;SET LINE COUNT
STA PAGCNT
MVI A,CR ;NEW LINE
CALL LCOUT
MVI A,LF
CALL LCOUT
LXI B,080H ;SET CHAR POSITION AND TAB COUNT
; (B=0=TAB, C=080H=CHAR POSITION)
;
; MAIN LOOP FOR LOADING NEXT BLOCK
;
TYPE2:
MOV A,C ;GET CHAR COUNT
CPI 80H
JRC TYPE3
PUSH H ;READ NEXT BLOCK
PUSH B
LXI D,FCB1 ;PT TO FCB
MVI C,20 ;READ RECORD
CALL BDOS
ORA A ;SET FLAGS
POP B
POP H
JRNZ TYPE7 ;END OF FILE?
MVI C,0 ;SET CHAR COUNT
LXI H,TBUFF ;PT TO FIRST CHAR
;
; MAIN LOOP FOR PRINTING CHARS IN TBUFF
;
TYPE3:
MOV A,M ;GET NEXT CHAR
ANI 7FH ;MASK OUT MSB
CPI 1AH ;END OF FILE (^Z)?
JRZ TYPE7 ;NEXT FILE IF SO
;
; OUTPUT CHAR TO CON: OR LST: DEVICE WITH TABULATION
;
CPI CR ;RESET TAB COUNT?
JRZ TYPE4
CPI LF ;RESET TAB COUNT?
JRZ TYPE4
CPI TAB ;TAB?
JRZ TYPE5
;
; OUTPUT CHAR AND INCREMENT CHAR COUNT
;
CALL LCOUT ;OUTPUT CHAR
JZ TYPEX ;SKIP
INR B ;INCREMENT TAB COUNT
JR TYPE6
;
; OUTPUT <CR> OR <LF> AND RESET TAB COUNT
;
TYPE4:
CALL LCOUT ;OUTPUT <CR> OR <LF>
JZ TYPEX ;SKIP
MVI B,0 ;RESET TAB COUNTER
JR TYPE6
;
; TABULATE
;
TYPE5:
MVI A,' ' ;<SP>
CALL LCOUT
JZ TYPEX ;SKIP
INR B ;INCR POS COUNT
MOV A,B
ANI 7
JRNZ TYPE5
;
; CONTINUE PROCESSING
;
TYPE6:
INR C ;INCREMENT CHAR COUNT
INX H ;PT TO NEXT CHAR
CALL BREAK ;CHECK FOR ABORT
JZ TYPEX ;SKIP
JR TYPE2
TYPE7:
LXI D,FCB1 ;CLOSE FILE
MVI C,16 ;BDOS FUNCTION
CALL BDOS
JMP TYPEX
;
; SEND OUTPUT TO LST: OR CON:, AS PER THE FLAG
; RETURN WITH Z IF ABORT
;
LCOUT:
PUSH H ;SAVE REGS
PUSH D
PUSH B
MOV E,A ;CHAR IN E
MVI C,2 ;OUTPUT TO CON:
PRFLG EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION
MVI A,0 ;2ND BYTE IS THE PRINT FLAG
ORA A ;0=TYPE
JRZ LC1
MVI C,5 ;OUTPUT TO LST:
LC1:
PUSH D ;SAVE CHAR
CALL BDOS ;OUTPUT CHAR IN E
POP D ;GET CHAR
MOV A,E
CPI LF
JRNZ LC2
LDA PRFLG ;OUTPUT TO LST:?
ORA A ;NZ = YES
JRNZ LC2
;
; CHECK FOR PAGING
;
LXI H,PAGCNT ;COUNT DOWN
DCR M
JRNZ LC2 ;JUMP IF NOT END OF PAUSE
MVI M,NLINES-2 ;REFILL COUNTER
PGFLG EQU $+1 ;POINTER TO IN-THE-CODE BUFFER
MVI A,0 ;2ND BYTE IS THE PAGING FLAG
CPI PGDFLG ;PAGE DEFAULT OVERRIDE OPTION WANTED?
;
IF PGDFLT ;IF PAGING IS DEFAULT
;
JRZ LC2 ;PGDFLG MEANS NO PAGING
;
ELSE
;
JRNZ LC2 ;PGDFLG MEANS PAGE
;
ENDIF ;PGDFLT
;
CALL PAGEBREAK ;PRINT PAGE BREAK MESSAGE
JR LC3 ;Z TO SKIP
LC2:
XRA A ;SET OK
DCR A ;NZ=OK
LC3:
POP B ;RESTORE REGS
POP D
POP H
RET
;
; PRINT PAGE BREAK MESSAGE AND GET USER INPUT
; ABORT IF ^C, RZ IF ^X
;
PAGEBREAK:
PUSH H ;SAVE HL
CALL PRINT
DB cr,lf,' Typing',' '+80H
LXI H,FCB1+1 ;PRINT FILE NAME
CALL PRFN
CALL DASH ;PRINT DASH
CALL CONIN ;GET INPUT
POP H ;RESTORE HL
PUSH PSW
CALL CRLF ;NEW LINE
POP PSW
CPI CTRLC ;^C
JZ EXIT
CPI CTRLX ;SKIP?
RET
;
ENDIF ;LTON
;
;Section 5E
;Command: REN
;Function: To change the name of an existing file
;Forms:
; REN <New ufn>=<Old ufn> Perform function
;
IF RENON
REN:
;
; CHECK FOR WHEEL APPROVAL IF OPTION ENABLED
;
IF WREN
CALL WHLTST
ENDIF ;WHEEL APPROVAL
;
CALL RETSAVE
;
;
; STEP 1: CHECK FOR FILE 2 BEING AMBIGUOUS
;
LXI H,FCB2+1 ;CAN'T BE AMBIGUOUS
CALL AMBCHK1
;
; STEP 2: LOG INTO USER AREA
;
CALL LOGUSR ;LOG INTO USER AREA OF FCB1
;
; STEP 3: SEE IF NEW FILE ALREADY EXISTS
; EXTEST PERFORMS A NUMBER OF CHECKS:
; 1) AMBIGUITY
; 2) R/O
; 3) IF FILE EXISTS AND NOT R/O, PERMISSION TO DELETE
;
CALL EXTEST
JZ EXIT ;R/O OR NO PERMISSION
;
; STEP 4: EXCHANGE FILE NAME FIELDS FOR RENAME
;
LXI H,FCB1 ;EXCHANGE NAMES ONLY
PUSH H ;SAVE PTR
INX H
LXI D,FCB2+1
MVI B,11 ;11 BYTES
REN1:
LDAX D ;GET OLD
MOV C,A
MOV A,M
STAX D ;PUT NEW
MOV M,C
INX H ;PT TO NEXT
INX D
DJNZ REN1
;
; STEP 5: SEE IF OLD FILE IS R/O
;
CALL SEARF ;LOOK FOR FILE
JZ PRFNF
CALL GETSBIT ;GET PTR TO ENTRY IN TBUFF
XCHG ;HL PTS TO ENTRY
INX H ;PT TO FN
CALL ROTEST ;SEE IF FILE IS R/O
JNZ EXIT
;
; STEP 6: RENAME THE FILE
;
POP D ;GET PTR TO FCB
MVI C,23 ;RENAME
CALL BDOS
INR A ;SET ZERO FLAG IF ERROR
JZ PRFNF ;PRINT NO SOURCE FILE MESSAGE
JMP EXIT
;
ENDIF ;RENON
;
;Section 5F
;Command: PROT
;Function: To set the attributes of a file (R/O and SYS)
;
;Form:
; PROT afn RSI
;If either R or S are omitted, the file is made R/W or DIR, resp;
;R and S may be in any order. If I is present, Inspection is enabled.
;
IF PROTON
ATT:
;
; CHECK FOR WHEEL APPROVAL IF OPTION ENABLED
;
IF WPROT
CALL WHLTST
ENDIF ;WHEEL APPROVAL
;
CALL RETSAVE
XRA A ;SET NO INSPECT
STA INSPECT
LXI H,0 ;SET R/O AND SYS ATTRIBUTES OFF
LXI D,FCB2+1 ;PT TO ATTRIBUTES
MVI B,3 ;3 CHARS MAX
ATT1:
LDAX D ;GET CHAR
INX D ;PT TO NEXT
CPI 'I' ;INSPECT?
JRZ ATTI
CPI 'R' ;SET R/O?
JRZ ATTR
CPI 'S' ;SET SYS?
JRZ ATTS
ATT2:
DJNZ ATT1
JR ATT3
ATTI:
STA INSPECT ;SET FLAG
JR ATT2
ATTR:
MVI H,80H ;SET R/O BIT
JR ATT2
ATTS:
MVI L,80H ;SET SYS BIT
JR ATT2
ATT3:
SHLD FATT ;SAVE FILE ATTRIBUTES
MVI A,1 ;SELECT DIR AND SYS FILES
CALL GETDIR ;LOAD DIRECTORY
JZ PRFNF ;NO FILE ERROR
SHLD NXTFILE ;PT TO NEXT FILE
JR ATT5
ATT4:
LHLD NXTFILE ;PT TO NEXT FILE
MOV A,M ;END OF LIST?
ORA A
JZ EXIT
CALL CRLF ;NEW LINE
ATT5:
PUSH H ;SAVE PTR TO CURRENT FILE
CALL PRFN ;PRINT ITS NAME
SHLD NXTFILE ;SAVE PTR TO NEXT FILE
CALL PRINT
DB ' Set to R','/'+80H
LHLD FATT ;GET ATTRIBUTES
MVI C,'W' ;ASSUME R/W
MOV A,H ;GET R/O BIT
ORA A
JRZ ATT6
MVI C,'O' ;SET R/O
ATT6:
MOV A,C ;GET CHAR
CALL CONOUT
MOV A,L ;GET SYS FLAG
ORA A ;SET FLAG
JRZ ATT7
CALL PRINT
DB ' and SY','S'+80H
ATT7:
INSPECT EQU $+1 ;PTR FOR IN-THE-CODE MODIFICATION
MVI A,0 ;GET INSPECT FLAG
ORA A ;Z=NO
POP H ;GET PTR TO CURRENT FILE
JRZ ATT8
CALL ERAQ1 ;ASK FOR Y/N
JRNZ ATT4 ;ADVANCE TO NEXT FILE IF NOT Y
ATT8:
LXI D,FCB1+1 ;COPY INTO FCB1
MVI B,11 ;11 BYTES
CALL LDIR
FATT EQU $+1 ;PTR FOR IN-THE-CODE MODIFICATION
LXI H,0 ;GET ATTRIBUTES
DCX D ;PT TO SYS BYTE
DCX D
MOV A,L ;GET SYS FLAG
CALL ATTSET ;SET ATTRIBUTE CORRECTLY
DCX D ;PT TO R/O BYTE
MOV A,H ;GET R/O FLAG
CALL ATTSET
LXI D,FCB1 ;PT TO FCB
MVI C,30 ;SET ATTRIBUTES
CALL BDOS
JR ATT4
ATTSET:
ORA A ;0=CLEAR ATTRIBUTE
JRZ ATTST1
LDAX D ;GET BYTE
ORI 80H ;SET ATTRIBUTE
STAX D
RET
ATTST1:
LDAX D ;GET BYTE
ANI 7FH ;CLEAR ATTRIBUTE
STAX D
RET
;
ENDIF ;PROTON
;
;Section 5G
;Command: CP
;Function: To copy a file from one place to another
;
;Form:
; CP new=old
;
IF CPON
COPY:
;
; CHECK FOR WHEEL APPROVAL IF OPTION ENABLED
;
IF WCP
CALL WHLTST
ENDIF ;WHEEL APPROVAL
;
CALL RETSAVE
;
; STEP 0: IF NEW IS BLANK, MAKE IT THE SAME NAME AND TYPE AS OLD
;
LXI D,FCB1+1 ;PT TO NEW FILE NAME
LDAX D ;GET FIRST CHAR
CPI ' ' ;NO NAME?
JRNZ COPY0
LXI H,FCB2+1 ;MAKE SAME AS OLD
MVI B,11 ;11 BYTES
CALL LDIR
;
; STEP 1: SEE IF NEW=OLD AND ABORT IF SO
;
COPY0:
LXI H,FCB1 ;PT TO NEXT
LXI D,FCB2 ;PT TO OLD
PUSH H ;SAVE PTRS
PUSH D
INX H ;PT TO FILE NAME
INX D
MVI B,13 ;COMPARE 13 BYTES
COPY1:
LDAX D ;GET OLD
CMP M ;COMPARE TO NEW
JRNZ COPY2
INX H ;PT TO NEXT
INX D
DJNZ COPY1
MVI C,25 ;GET CURRENT DISK
CALL BDOS
INR A ;MAKE 1..P
MOV B,A ;CURRENT DISK IN B
POP D ;GET PTR TO DN
POP H
LDAX D ;GET DISK
MOV C,A ;... IN C
ORA A ;CURRENT?
JRNZ COPY1A
MOV C,B ;MAKE C CURRENT
COPY1A:
MOV A,M ;GET DISK
ORA A ;CURRENT?
JRNZ COPY1B
MOV A,B ;MAKE A CURRENT
COPY1B:
CMP C ;SAME DISK ALSO?
JRNZ COPY3 ;CONTINUE WITH OPERATION
JR CPERR
COPY2:
POP D ;GET PTRS
POP H
;
; STEP 2: SET USER NUMBERS
;
COPY3:
LDA FCB1+13 ;GET NEW USER
STA USRNEW
LDA FCB2+13 ;GET OLD USER
STA USROLD
;
; STEP 3: SEE IF OLD FILE EXISTS
;
LXI H,OLDFCB ;COPY OLD INTO 2ND FCB
PUSH H ;SAVE PTR TO 2ND FCB
XCHG
MVI B,14 ;14 BYTES
CALL LDIR
CALL LOGOLD ;LOG IN USER NUMBER OF OLD FCB
POP H ;GET PTR TO 2ND FCB
CALL INITFCB2 ;INIT FCB
MVI C,17 ;LOOK FOR FILE
CALL BDOS
INR A ;CHECK FOR ERROR
JZ PRFNF ;FILE NOT FOUND
;
; STEP 4: SEE IF NEW EXISTS
;
CALL LOGNEW ;LOG INTO NEW'S USER AREA
CALL EXTEST ;TEST
JZ EXIT ;ERROR EXIT
;
; STEP 5: CREATE NEW
;
LXI D,FCB1 ;PT TO FCB
MVI C,22 ;MAKE FILE
CALL BDOS
INR A ;ERROR?
JRNZ COPY4
;
; COPY ERROR
;
CPERR:
CALL PRINT
DB ' Copy','?'+80H
JMP EXIT
;
; STEP 6: OPEN OLD
;
COPY4:
CALL LOGOLD ;GET USER
LXI H,OLDFCB ;PT TO FCB
CALL INITFCB2 ;INIT FCB
MVI C,15 ;OPEN FILE
CALL BDOS
;
; STEP 7: COPY OLD TO NEW WITH BUFFERING
;
COPY5:
CALL LOGOLD ;GET USER
MVI B,0 ;SET COUNTER
LXI H,TPA ;SET NEXT ADDRESS TO COPY INTO
COPY5A:
PUSH H ;SAVE ADDRESS AND COUNTER
PUSH B
LXI D,OLDFCB ;READ BLOCK FROM FILE
MVI C,20
CALL BDOS
POP B ;GET COUNTER AND ADDRESS
POP D
ORA A ;OK?
JRNZ COPY5B
PUSH B ;SAVE COUNTER
LXI H,TBUFF ;COPY FROM BUFFER
MVI B,128 ;128 BYTES
CALL LDIR
XCHG ;HL PTS TO NEXT
POP B ;GET COUNTER
INR B ;INCREMENT IT
MOV A,B ;DONE?
CPI CPBLOCKS ;DONE IF CPBLOCKS LOADED
JRNZ COPY5A
COPY5B:
MOV A,B ;GET COUNT
ORA A
JRZ COPY6 ;DONE IF NOTHING LOADED
PUSH B ;SAVE COUNT
CALL LOGNEW ;GET USER
LXI H,TPA ;PT TO TPA
COPY5C:
LXI D,TBUFF ;COPY INTO TBUFF
MVI B,128 ;128 BYTES
CALL LDIR
PUSH H ;SAVE PTR TO NEXT
LXI D,FCB1 ;PT TO FCB
MVI C,21 ;WRITE BLOCK
CALL BDOS
ORA A
JRNZ CPERR ;COPY ERROR
POP H ;GET PTR TO NEXT BLOCK
POP B ;GET COUNT
DCR B ;COUNT DOWN
JRZ COPY5 ;GET NEXT
PUSH B ;SAVE COUNT
JR COPY5C
;
; STEP 8: CLOSE FILES
;
COPY6:
CALL LOGOLD ;GET USER
LXI D,OLDFCB ;PT TO FCB
MVI C,16 ;CLOSE FILE
CALL BDOS
CALL LOGNEW ;GET USER
LXI D,FCB1 ;PT TO FCB
MVI C,16 ;CLOSE FILE
CALL BDOS
CALL PRINT
DB ' Don','e'+80H
JMP EXIT
;
; LOG INTO USER NUMBER OF OLD FILE
;
LOGOLD:
USROLD EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION
MVI A,0 ;GET NUMBER
JMP SETUSR
;
; LOG INTO USER NUMBER OF NEW FILE
;
LOGNEW:
USRNEW EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION
MVI A,0 ;GET NUMBER
JMP SETUSR
;
ENDIF ;CPON
;
;Section 5H
;Command: PEEK
;Function: Display memory
;
;Form:
; PEEK startadr - 256 bytes displayed
; PEEK startadr endadr - range of bytes displayed
;
IF PEEKON
PEEK:
;
; CHECK FOR WHEEL APPROVAL IF OPTION ENABLED
;
IF WPEEK
CALL WHLTST
ENDIF ;WHEEL APPROVAL
;
CALL RETSAVE
LXI H,TBUFF+1 ;FIND FIRST NUMBER
NXTPEEK EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION
LXI D,0 ;DEFAULT PEEK ADDRESS IF NONE
CALL SKSP ;SKIP TO NON-BLANK
CNZ HEXNUM ;GET START ADDRESS IF ANY (ELSE DEFAULT)
CALL PRINT
DB ' Pee','k'+80H
CALL ADRAT ;PRINT ADDRESS MESSAGE
PUSH D ;SAVE IT
LXI B,256 ;COMPUTE END ADDRESS
XCHG
DAD B
XCHG ;END ADDRESS IN DE
CALL SKSP ;SKIP TO NON-BLANK
JRZ PEEK1 ;PROCESS
CALL HEXNUM ;GET 2ND NUMBER IN DE
PEEK1:
POP H ;HL IS START ADDRESS, DE IS END ADDRESS
CALL PEEK2 ;DO PEEK
SHLD NXTPEEK ;SET CONTINUED PEEK ADDRESS
JMP EXIT
;
; DISPLAY LOOP
;
PEEK2:
MOV A,D ;SEE IF DE<=HL
CMP H
RC ;OUT OF BOUNDS
JRNZ PEEK2A ;HL > DE
MOV A,E
CMP L
RZ
RC
PEEK2A:
CALL CRLF ;NEW LINE
MOV A,H ;PRINT ADDRESS
CALL PASHC
MOV A,L
CALL PAHC
CALL DASH ;PRINT LEADER
MVI B,16 ;16 BYTES TO DISPLAY
PUSH H ;SAVE START ADDRESS
PEEK3:
MOV A,M ;GET NEXT BYTE
CALL PASHC ;PRINT WITH LEADING SPACE
INX H ;PT TO NEXT
DJNZ PEEK3
POP H ;PT TO FIRST
MVI B,16 ;16 BYTES
MVI A,' ' ;SPACE AND FENCE
CALL CONOUT
CALL PRINT
DB FENCE+80H
PEEK4:
MOV A,M ;GET NEXT BYTE
MVI C,'.' ;ASSUME DOT
ANI 7FH ;MASK IT
CPI ' ' ;DOT IF LESS THAN SPACE
JRC PEEK5
CPI 7FH ;DON'T PRINT DEL
JRZ PEEK5
MOV C,A ;CHAR IN C
PEEK5:
MOV A,C ;GET CHAR
CALL CONOUT ;SEND IT
INX H ;PT TO NEXT
DJNZ PEEK4
CALL PRINT ;CLOSING FENCE
DB FENCE+80H
CALL BREAK ;ALLOW ABORT
JR PEEK2
;
ENDIF ;PEEKON
;
; PRINT A AS 2 HEX CHARS
; PASHC - LEADING SPACE
;
IF PEEKON OR POKEON
PASHC:
PUSH PSW ;SAVE A
CALL PRINT
DB ' '+80H
POP PSW
PAHC:
PUSH B ;SAVE BC
MOV C,A ;BYTE IN C
RRC ;EXCHANGE NYBBLES
RRC
RRC
RRC
CALL PAH ;PRINT HEX CHAR
MOV A,C ;GET LOW
POP B ;RESTORE BC AND FALL THRU TO PAH
PAH:
ANI 0FH ;MASK
ADI '0' ;CONVERT TO ASCII
CPI '9'+1 ;LETTER?
JRC PAH1
ADI 7 ;ADJUST TO LETTER
PAH1:
JMP CONOUT
;
ENDIF ;PEEKON OR POKEON
;
;Section 5I
;Command: POKE
;Function: Place Values into Memory
;
;Form:
; POKE startadr val1 val2 ...
;
IF POKEON
POKE:
;
; CHECK FOR WHEEL APPROVAL IF OPTION ENABLED
;
IF WPOKE
CALL WHLTST
ENDIF ;WHEEL APPROVAL
;
CALL RETSAVE
LXI H,TBUFF+1 ;PT TO FIRST CHAR
CALL SKSP ;SKIP TO NON-BLANK
JRZ NOARGS ;ARG ERROR
CALL HEXNUM ;CONVERT TO NUMBER
CALL PRINT
DB ' Pok','e'+80H
CALL ADRAT ;PRINT AT MESSAGE
;
; LOOP FOR STORING HEX VALUES SEQUENTIALLY VIA POKE
;
POKE1:
PUSH D ;SAVE ADDRESS
CALL SKSP ;SKIP TO NON-BLANK
JZ EXIT ;DONE
CPI '"' ;QUOTED TEXT?
JRZ POKE2
CALL HEXNUM ;GET NUMBER
MOV A,E ;GET LOW
POP D ;GET ADDRESS
STAX D ;STORE NUMBER
INX D ;PT TO NEXT
JR POKE1
;
; STORE ASCII CHARS
;
POKE2:
POP D ;GET NEXT ADDRESS
INX H ;PT TO NEXT CHAR
POKE3:
MOV A,M ;GET NEXT CHAR
ORA A ;DONE?
JZ EXIT
STAX D ;PUT CHAR
INX H ;PT TO NEXT
INX D
JR POKE3
;
; No Argument Error
;
NOARGS:
CALL PRINT
DB ' Arg','?'+80H
JMP EXIT
;
ENDIF ;POKEON
;
;Section 5J
;Command: REG
;Function: Manipulate Memory Registers
;
;Forms:
; REG D or REG <-- Display Register Value
; REG Mreg <-- Decrement Register Value
; REG Preg <-- Increment Register Value
; REG Sreg value <-- Set Register Value
;
IF REGON
REGCMD:
LXI H,FCB1+1 ;PT TO FIRST ARG
MOV A,M ;GET FIRST CHAR
PUSH PSW ;SAVE CHAR
CPI 'A' ;ASSUME DIGIT IF LESS THAN 'A'
JRC REGC1
INX H ;PT TO DIGIT
REGC1:
MOV A,M ;GET DIGIT
CALL REGPTR ;PT TO REGISTER
POP PSW ;GET CHAR
CPI 'S' ;SET?
JRZ RSET
CPI 'P' ;PLUS?
JRZ RINC
CPI 'M' ;MINUS?
JRZ RDEC
;
; SHOW REGISTER VALUES
;
RSHOW:
XRA A ;SELECT REGISTER 0
MOV B,A ;COUNTER SET TO 0 IN B
CALL REGP2 ;HL PTS TO REGISTER 0
RSHOW1:
MOV A,B ;GET COUNTER VALUE
CPI 10
JZ CRLF ;NEW LINE AND EXIT IF DONE
CALL PRINT
DB ' Reg',' '+80H
MOV A,B ;PRINT REGISTER NUMBER
ADI '0'
CALL CONOUT
CALL PRINT
DB ' ','='+80H
PUSH B ;SAVE COUNTER
CALL REGOUT ;PRINT REGISTER VALUE
POP B ;GET COUNTER
INR B ;INCREMENT COUNTER
MOV A,B ;CHECK FOR NEW LINE
ANI 3
CZ CRLF
INX H ;PT TO NEXT REGISTER
JR RSHOW1
;
; INCREMENT REGISTER VALUE
; HL PTS TO MEMORY REGISTER ON INPUT
;
RINC:
INR M ;INCREMENT IT
JR REGOUT ;PRINT RESULT
;
; DECREMENT REGISTER VALUE
; HL PTS TO MEMORY REGISTER ON INPUT
;
RDEC:
DCR M ;DECREMENT VALUE
JR REGOUT ;PRINT RESULT
;
; SET REGISTER VALUE
; HL PTS TO REGISTER ON INPUT
;
RSET:
LXI D,FCB2+1 ;PT TO VALUE
MVI B,0 ;INIT VALUE TO ZERO
RSET1:
LDAX D ;GET NEXT DIGIT
INX D ;PT TO NEXT
SUI '0' ;CONVERT TO BINARY
JRC RSET2
CPI 10 ;RANGE?
JRNC RSET2
MOV C,A ;DIGIT IN C
MOV A,B ;MULTIPLY OLD BY 10
ADD A ;*2
ADD A ;*4
ADD B ;*5
ADD A ;*10
ADD C ;ADD IN NEW DIGIT
MOV B,A ;RESULT IN B
JR RSET1
RSET2:
MOV M,B ;SET VALUE
REGOUT:
CALL PRINT ;PRINT LEADING SPACE
DB ' '+80H
MOV A,M ;GET REGISTER VALUE
MVI B,100 ;PRINT 100'S
MVI C,0 ;SET LEADING SPACE FLAG
CALL DECB ;PRINT 100'S
MVI B,10 ;PRINT 10'S
CALL DECB ;PRINT 10'S
ADI '0' ;PRINT 1'S
JMP CONOUT
;
; SUBTRACT B FROM A UNTIL CARRY, THEN PRINT DIGIT COUNT
;
DECB:
MVI D,'0' ;SET DIGIT
DECB1:
SUB B ;SUBTRACT
JRC DECB2
INR D ;ADD 1 TO DIGIT CHAR
JR DECB1
DECB2:
ADD B ;ADD BACK IN
MOV E,A ;SAVE A IN E
MOV A,D ;GET DIGIT CHAR
CPI '0' ;LEADING ZERO CHECK
JRNZ DECB3
MOV A,C ;ANY LEADING DIGIT YET?
ORA A
JRZ DECB4
DECB3:
MOV A,D ;GET DIGIT CHAR
CALL CONOUT ;PRINT IT
INR C ;SET C<>0 FOR LEADING DIGIT CHECK
DECB4:
MOV A,E ;RESTORE A FOR NEXT ROUND
RET
;
; SET HL TO POINT TO MEMORY REGISTER WHOSE INDEX IS PTED TO BY HL
; ON INPUT, A CONTAINS REGISTER CHAR
; ON OUTPUT, HL = ADDRESS OF MEMORY REGISTER (REG 0 ASSUMED IF ERROR)
;
REGPTR:
MVI B,0 ;INIT TO ZERO
SUI '0' ;CONVERT
JRC REGP1
CPI 10 ;RANGE
JRNC REGP1
MOV B,A ;VALUE IN B
REGP1:
MOV A,B ;VALUE IN A
REGP2:
LXI H,Z3MSG+30H ;PT TO MEMORY REGISTERS
ADD L ;PT TO PROPER REGISTER
MOV L,A
MOV A,H
ACI 0
MOV H,A ;HL PTS TO REGISTER
RET
;
ENDIF ;REGON
;
;Section 5K
;Command: WHL/WHLQ
;Function: Set the Wheel Byte on or off
;
;Form:
; WHL -- turn Wheel Byte OFF
; WHL password -- turn Wheel Byte ON if password is correct
; WHLQ -- find out status of Wheel Byte
;
IF WHLON
WHL:
LXI H,FCB1+1 ;PT TO FIRST CHAR
MOV A,M ;GET IT
CPI ' ' ;TURN BYTE OFF IF NO PASSWORD
JRZ WHLOFF
LXI D,WHLPASS
MVI B,8 ;CHECK 8 CHARS
WHL1:
LDAX D ;GET CHAR
CMP M ;COMPARE
JRNZ WHLMSG
INX H ;PT TO NEXT
INX D
DJNZ WHL1
;
; TURN ON WHEEL BYTE
;
MVI A,0FFH ;TURN ON WHEEL BYTE
JR WHLSET
;
; TURN OFF WHEEL BYTE
;
WHLOFF:
XRA A ;TURN OFF WHEEL BYTE
WHLSET:
STA Z3WHL ;SET WHEEL BYTE AND PRINT MESSAGE
;
; PRINT WHEEL BYTE MESSAGE
;
WHLMSG:
CALL PRINT
DB ' Wheel Byte',' '+80H
LDA Z3WHL ;GET WHEEL BYTE
ORA A ;ZERO IS OFF
JRZ OFFM
CALL PRINT
DB 'O','N'+80H
RET
OFFM:
CALL PRINT
DB 'OF','F'+80H
RET
;
; WHEEL PASSWORD DEFINED FROM SYSRCP.LIB FILE
;
DB 'Z'-'@' ;LEADING ^Z IN CASE OF TYPE
WHLPASS:
WPASS ;USE MACRO
;
ENDIF ;WHLON
;
;Section 5L
;Command: ECHO
;Function: Echo Text without Interpretation to Console or Printer
;
;Form:
; ECHO text <-- echo text to console
; ECHO $text <-- echo text to printer
;
; Additionally, if a form feed character is encountered in the
; output string, no further output will be done, a new line will be
; issued, and this will be followed by a form feed character. That is:
;
; ECHO $text^L
;
; will cause "text" to be printed on the printer followed by CR, LF, FF.
;
ECHO:
LXI H,TBUFF+1 ;PT TO FIRST CHAR
ECHO1:
MOV A,M ;SKIP LEADING SPACES
INX H ;PT TO NEXT
CPI ' '
JRZ ECHO1
;
IF ECHOLST
MOV B,A ;CHAR IN B
CPI '$' ;PRINT FLAG?
JRZ ECHO2
ENDIF ;ECHOLST
;
DCX H ;PT TO CHAR
;
; LOOP TO ECHO CHARS
;
ECHO2:
MOV A,M ;GET CHAR
ORA A ;EOL?
JRZ ECHO4
;
IF ECHOLST
CPI FF ;FORM FEED?
JRZ ECHO3
ENDIF ;ECHOLST
;
ECHO2C:
CALL ECHOUT ;SEND CHAR
INX H ;PT TO NEXT
JR ECHO2
;
; FORM FEED - SEND NEW LINE FOLLOWED BY FORM FEED IF PRINTER OUTPUT
;
IF ECHOLST
ECHO3:
MOV A,B ;CHECK FOR PRINTER OUTPUT
CPI '$'
JRNZ ECHOFF ;SEND FORM FEED NORMALLY IF NOT PRINTER
CALL ECHONL ;SEND NEW LINE
MVI A,FF ;SEND FORM FEED
JR ECHOUT
;
; SEND FORM FEED CHAR TO CONSOLE
;
ECHOFF:
MVI A,FF ;GET CHAR
JR ECHO2C
ENDIF ;ECHOLST
;
; END OF PRINT LOOP - CHECK FOR PRINTER TERMINATION
;
ECHO4:
IF NOT ECHOLST
;
RET
;
ELSE
;
MOV A,B ;CHECK FOR PRINTER OUTPUT
CPI '$'
RNZ ;DONE IF NO PRINTER OUTPUT
;
; OUTPUT A NEW LINE
;
ECHONL:
MVI A,CR ;OUTPUT NEW LINE ON PRINTER
CALL ECHOUT
MVI A,LF ;FALL THRU TO ECHOUT
;
ENDIF ;NOT ECHOLST
;
; OUTPUT CHAR TO PRINTER OR CONSOLE
;
ECHOUT:
MOV C,A ;CHAR IN C
PUSH H ;SAVE HL
PUSH B ;SAVE BC
LXI D,0CH-3 ;OFFSET FOR CONSOLE OUTPUT
;
IF ECHOLST
MOV A,B ;CHECK FOR PRINTER
CPI '$'
JRNZ ECHOUT1
INX D ;ADD 3 FOR PRINTER OFFSET
INX D
INX D
;
ENDIF ;ECHOLST
;
; OUTPUT CHAR IN C WITH BIOS OFFSET IN DE
;
ECHOUT1:
CALL BIOUT ;BIOS OUTPUT
POP B ;RESTORE BC,HL
POP H
RET
;
; OUTPUT CHAR IN C TO BIOS WITH OFFSET IN DE
;
BIOUT:
LHLD WBOOT+1 ;GET ADDRESS OF WARM BOOT
DAD D ;PT TO ROUTINE
PCHL ;JUMP TO IT
;
; ** SUPPORT UTILITIES **
;
;
; CHECK FOR USER INPUT; IF ^C, RETURN WITH Z
;
BREAK:
PUSH H ;SAVE REGS
PUSH D
PUSH B
MVI E,0FFH ;GET CHAR IF ANY
MVI C,6 ;CONSOLE STATUS CHECK
CALL BDOS
POP B ;RESTORE REGS
POP D
POP H
CPI CTRLC ;CHECK FOR ABORT
JZ EXIT ;EXIT
CPI CTRLX ;SKIP?
RET
;
; COPY HL TO DE FOR B BYTES
;
LDIR:
MOV A,M ;GET
STAX D ;PUT
INX H ;PT TO NEXT
INX D
DJNZ LDIR ;LOOP
RET
;
; PRINT FILE NOT FOUND MESSAGE
;
PRFNF:
CALL PRINT
DB ' No File','s'+80H
JMP EXIT
;
; OUTPUT NEW LINE TO CON:
;
CRLF:
MVI A,CR
CALL CONOUT
MVI A,LF
JMP CONOUT
;
; SEARCH FOR FIRST AND NEXT
;
SEARF:
PUSH B ; SAVE COUNTER
PUSH H ; SAVE HL
MVI C,17 ; SEARCH FOR FIRST FUNCTION
SEARF1:
LXI D,FCB1 ; PT TO FCB
CALL BDOS
INR A ; SET ZERO FLAG FOR ERROR RETURN
POP H ; GET HL
POP B ; GET COUNTER
RET
SEARN:
PUSH B ; SAVE COUNTER
PUSH H ; SAVE HL
MVI C,18 ; SEARCH FOR NEXT FUNCTION
JR SEARF1
;
; CONSOLE INPUT
;
CONIN:
PUSH H ; SAVE REGS
PUSH D
PUSH B
MVI C,1 ; INPUT
CALL BDOS
POP B ; GET REGS
POP D
POP H
ANI 7FH ; MASK MSB
CPI 61H
RC
ANI 5FH ; TO UPPER CASE
RET
;
; LOG INTO USER AREA CONTAINED IN FCB1
;
LOGUSR:
LDA FCB1+13 ;GET USER NUMBER
SETUSR:
MOV E,A
MVI C,32 ;USE BDOS FCT
JMP BDOS
;
; PRINT FILE NAME PTED TO BY HL
;
PRFN:
CALL PRINT ;LEADING SPACE
DB ' '+80H
MVI B,8 ;8 CHARS
CALL PRFN1
MVI A,'.' ;DOT
CALL CONOUT
MVI B,3 ;3 CHARS
PRFN1:
MOV A,M ; GET CHAR
INX H ; PT TO NEXT
CALL CONOUT ; PRINT CHAR
DJNZ PRFN1 ; COUNT DOWN
RET
;
; SAVE RETURN ADDRESS
;
RETSAVE:
POP D ; GET RETURN ADDRESS
POP H ; GET RETURN ADDRESS TO ZCPR3
SHLD Z3RET ; SAVE IT
PUSH H ; PUT RETURN ADDRESS TO ZCPR3 BACK
PUSH D ; PUT RETURN ADDRESS BACK
RET
;
; EXIT TO ZCPR3
;
EXIT:
Z3RET EQU $+1 ; POINTER TO IN-THE-CODE MODIFICATION
LXI H,0 ; RETURN ADDRESS
PCHL ; GOTO ZCPR3
;
; TEST WHEEL BYTE FOR APPROVAL
; IF WHEEL BYTE IS 0 (OFF), ABORT WITH A MESSAGE (FLUSH RET ADR AND EXIT)
;
IF WHEEL ;IF ANY WHEEL OPTION IS RUNNING
WHLTST:
LDA Z3WHL ;GET WHEEL BYTE
ORA A ;ZERO?
RNZ
POP PSW ;CLEAR STACK
CALL PRINT
DB ' No Whee','l'+80H
RET
ENDIF ;WHEEL
;
; PRINT A DASH
;
IF LTON OR PEEKON
DASH:
CALL PRINT
DB ' -',' '+80H
RET
;
ENDIF ;LTON OR PEEKON
;
; PRINT ADDRESS MESSAGE
; PRINT ADDRESS IN DE
;
IF PEEKON OR POKEON
ADRAT:
CALL PRINT
DB ' at',' '+80H
MOV A,D ;PRINT HIGH
CALL PAHC
MOV A,E ;PRINT LOW
JMP PAHC
;
; EXTRACT HEXADECIMAL NUMBER FROM LINE PTED TO BY HL
; RETURN WITH VALUE IN DE AND HL PTING TO OFFENDING CHAR
;
HEXNUM:
LXI D,0 ;DE=ACCUMULATED VALUE
MVI B,5 ;B=CHAR COUNT
HNUM1:
MOV A,M ;GET CHAR
CPI ' '+1 ;DONE?
RC ;RETURN IF SPACE OR LESS
INX H ;PT TO NEXT
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:
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
RET
;
; NUMBER ERROR
;
NUMERR:
CALL PRINT
DB ' Num','?'+80H
JMP EXIT
;
; SKIP TO NEXT NON-BLANK
;
SKSP:
MOV A,M ;GET CHAR
INX H ;PT TO NEXT
CPI ' ' ;SKIP SPACES
JRZ SKSP
DCX H ;PT TO GOOD CHAR
ORA A ;SET EOL FLAG
RET
;
ENDIF ;PEEKON OR POKEON
;
; Test File in FCB for unambiguity and existence, ask user to delete if so
; Return with Z flag set if R/O or no permission to delete
;
IF RENON OR CPON
EXTEST:
CALL AMBCHK ;AMBIGUOUS FILE NAMES NOT ALLOWED
CALL SEARF ;LOOK FOR SPECIFIED FILE
JRZ EXOK ;OK IF NOT FOUND
CALL GETSBIT ;POSITION INTO DIR
INX D ;PT TO FILE NAME
XCHG ;HL PTS TO FILE NAME
PUSH H ;SAVE PTR TO FILE NAME
CALL PRFN ;PRINT FILE NAME
POP H
CALL ROTEST ;CHECK FOR R/O
JRNZ EXER
CALL ERAQ ;ERASE?
JRNZ EXER ;RESTART AS ERROR IF NO
LXI D,FCB1 ;PT TO FCB1
MVI C,19 ;DELETE FILE
CALL BDOS
EXOK:
XRA A
DCR A ;NZ = OK
RET
EXER:
XRA A ;ERROR FLAG - FILE IS R/O OR NO PERMISSION
RET
;
; CHECK FOR AMBIGUOUS FILE NAME IN FCB1
; RETURN Z IF SO
;
AMBCHK:
LXI H,FCB1+1 ;PT TO FCB
;
; CHECK FOR AMBIGUOUS FILE NAME PTED TO BY HL
;
AMBCHK1:
PUSH H
MVI B,11 ;11 BYTES
AMB1:
MOV A,M ;GET CHAR
ANI 7FH ;MASK
CPI '?'
JRZ AMB2
INX H ;PT TO NEXT
DJNZ AMB1
DCR B ;SET NZ FLAG
POP D
RET
AMB2:
POP H ;PT TO FILE NAME
CALL PRFN
CALL PRINT
DB ' is AF','N'+80H
JMP EXIT
;
ENDIF ;RENON OR CPON
;
; CHECK USER TO SEE IF HE APPROVES ERASE OF FILE
; RETURN WITH Z IF YES
;
IF RENON OR CPON OR ERAON OR PROTON
ERAQ:
CALL PRINT
DB ' - Eras','e'+80H
ERAQ1:
CALL PRINT
DB ' (Y/N)?',' '+80H
CALL CONIN ;GET RESPONSE
CPI 'Y' ;KEY ON YES
RET
;
ENDIF ;RENON OR CPON OR ERAON OR PROTON
;
; TEST FILE PTED TO BY HL FOR R/O
; NZ IF R/O
;
IF RENON OR ERAON OR CPON
ROTEST:
PUSH H ;ADVANCE TO R/O BYTE
LXI B,8 ;PT TO 9TH BYTE
DAD B
MOV A,M ;GET IT
ANI 80H ;MASK BIT
PUSH PSW
LXI H,ROMSG
CNZ PRINT1 ;PRINT IF NZ
POP PSW ;GET FLAG
POP H ;GET PTR
RET
ROMSG:
DB ' is R/','O'+80H
;
ENDIF ;RENON OR ERAON OR CPON
;
; INIT FCB1, RETURN WITH DE PTING TO FCB1
;
IF ERAON OR LTON OR CPON
INITFCB1:
LXI H,FCB1 ;PT TO FCB
INITFCB2:
PUSH H ;SAVE PTR
LXI B,12 ;PT TO FIRST BYTE
DAD B
MVI B,24 ;ZERO 24 BYTES
XRA A ;ZERO FILL
CALL FILLP ;FILL MEMORY
POP D ;PT TO FCB
RET
;
ENDIF ;ERAON OR LTON OR CPON
;
; BUFFERS
;
NXTFILE:
DS 2 ;PTR TO NEXT FILE IN LIST
;
; SIZE ERROR TEST
;
IF ($ GT (RCP + RCPS*128))
SIZERR EQU NOVALUE ;RCP IS TOO LARGE FOR BUFFER
ENDIF
;
; END OF SYS.RCP
;
END