* 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 Displays the DIR files ; DIR S Displays the SYS files ; DIR 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 , 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 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 Erase Specified files and print their names ; ERA 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 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 Print file ; TYPE 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 OR AND RESET TAB COUNT ; TYPE4: CALL LCOUT ;OUTPUT OR JZ TYPEX ;SKIP MVI B,0 ;RESET TAB COUNTER JR TYPE6 ; ; TABULATE ; TYPE5: MVI A,' ' ; 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 = 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