;************************************************************************* ;* * ;* Z C P R 3 -- Z80-Based Command Processor Replacement, Version 3.0 * ;* * ;* Copyright (c) 1984 by Richard Conn * ;* Copyright US Government * ;* All Rights Reserved * ;* * ;* ZCPR3 was written by Richard Conn, who assumes no responsibility * ;* or liability for its use. ZCPR3 is released to the CP/M user * ;* community for non-commercial use only. * ;* * ;* All registered users of CP/M are encouraged to freely copy and use * ;* ZCPR3 and its associated utilities on their registered systems for * ;* non-commercial purposes. * ;* * ;* Any commercial use of ZCPR3 is prohibited unless approved by the * ;* author, Richard Conn, or his authorized agent, Echelon, Inc, in * ;* writing. * ;* * ;* This is the RELEASE VERSION of ZCPR3. Dated: 21 Apr 84 * ;* * ;************************************************************************* ; ; ZCPR3 -- CP/M Z80 Command Processor Replacement (ZCPR) Version 3.0 ; ; ZCPR3 is based upon ZCPR2 ; ;******** Structure Notes ******** ; ; ZCPR3 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 ZCPR3 ; ENTRY ; ; 1 Buffers ; 1. Input Command Line and Default Command ; 2. File Type of COM File ; 3. SUBMIT File Control Block ; 4. Command File Control Block ; 5. Line Count Buffer ; 6. Resident Command Table ; ; 2 CPR Starting Modules ; CPR1 CPR RESTRT RS0 RS1 ; RS2 PARSER SCANNER DUSCAN DIRSCAN ; PASSCK SKSP TSTEOL INITFCB IFCB ; FILL PRNNF ; ; 3 Utilities ; CONIN CRLF CONOUT LCOUT LSTOUT ; PAGER READF READ BDOSB NOTE ; PRINTC PRINT PRIN1 GETDRV DEFDMA ; DMASET RESET BDOSJP LOGIN OPENF ; OPEN GRBDOS CLOSE SEARF SEAR1 ; SEARN SUBKIL DELETE GETUSR SETUSR ; ; 4 CPR Utilities ; SETUD UCASE PROMPT READBUF BREAK ; SDELM ADDAH LDIR NUMBER NUMERR ; HEXNUM FCBLOG SLOGIN WHLCHK CMDSER ; ; 5 CPR-Resident Commands and Functions ; 5A DIR DIRPR PRFN DIRPTR GETSBIT ; 5B ERA ; 5C LIST ; 5D TYPE ; 5E SAVE AMBCHK EXTEST ; 5F REN ; 5G JUMP ; 5H GO ; 5I COMDIR COM CALLPROG ; 5J GET MLOAD DLOGIN PRNLE PATH ; MPATH STACK PWLIN ; ; ; The following MACLIB statements load all the user-selected equates ; which are used to customize ZCPR3 for the user's working environment. ; MACLIB Z3BASE MACLIB Z3HDR ; CTRLC EQU 03H TAB EQU 09H LF EQU 0AH CR EQU 0DH ; 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 TFCB2 EQU TFCB+16 ;2ND FCB TBUFF EQU BASE+0080H ;DEFAULT DISK I/O BUFFER TPA EQU BASE+0100H ;BASE OF TPA BIOS EQU CCP+0800H+0E00H ;BIOS Location ; ;$-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 ; PUTRG - SAVE REGISTERS ; GETRG - RESTORE REGISTERS ; ; @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 ELSE DB ?DD ENDIF ;;RANGE ERROR ENDM ; ; ; Z80 MACRO EXTENSIONS ; JR MACRO ?N ;;JUMP RELATIVE IF I8080 ;;8080/8085 JP ?N ELSE ;;Z80 DB 18H @GENDD ?N-$-1 ENDIF ;;I8080 ENDM ; JRC MACRO ?N ;;JUMP RELATIVE ON CARRY IF I8080 ;;8080/8085 JP C,?N ELSE ;;Z80 DB 38H @GENDD ?N-$-1 ENDIF ;;I8080 ENDM ; JRNC MACRO ?N ;;JUMP RELATIVE ON NO CARRY IF I8080 ;;8080/8085 JP NC,?N ELSE ;;Z80 DB 30H @GENDD ?N-$-1 ENDIF ;;I8080 ENDM ; JRZ MACRO ?N ;;JUMP RELATIVE ON ZERO IF I8080 ;;8080/8085 JP Z,?N ELSE ;;Z80 DB 28H @GENDD ?N-$-1 ENDIF ;;I8080 ENDM ; JRNZ MACRO ?N ;;JUMP RELATIVE ON NO ZERO IF I8080 ;;8080/8085 JP NZ,?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 DEC B JP NZ,?N ELSE ;;Z80 DB 10H @GENDD ?N-$-1 ENDIF ;;I8080 ENDM ; PUTRG MACRO PUSH HL ;;SAVE REGISTERS IN ORDER PUSH DE PUSH BC ENDM ; GETRG MACRO POP BC ;;RESTORE REGISTERS IN ORDER POP DE POP HL ENDM ; ; END OF Z80 MACRO EXTENSIONS ; ; ;**** Section 0 **** ; ORG CPRLOC ; ; ENTRY POINTS INTO ZCPR3 ; ; IF MULTCMD (MULTIPLE COMMANDS ON ONE LINE) is FALSE: ; If ZCPR3 is entered at location CPRLOC (at the JMP to CPR), then ; the default command in CMDLIN will be processed. If ZCPR3 is entered ; at location CPRLOC+3 (at the JMP to CPR1), then the default command in ; CMDLIN will NOT be processed. ; NOTE: Entry into ZCPR3 at CPRLOC is permitted, but in order for this ; to work, CMDLIN MUST be initialized to contain the command line (ending in 0) ; and the C register MUST contain a valid User/Disk Flag ; (the most significant nybble contains the User Number and the least ; significant nybble contains the Disk Number). ; ; IF MULTCMD is TRUE: ; Entry at CPR or CPR1 has the same effect. Multiple command processing ; will still continue. ; ; If MULTCMD is FALSE, a user program need only load the buffer ; CMDLIN with the desired command line, terminated by a zero, in order to ; have this command line executed. If MULTCMD is TRUE, a user program must ; load this buffer as before, but he must also set the NXTCHR pointer to ; point to the first character of the command line. ; ; NOTE: ***** (BIG STAR) ***** Programs such as SYNONYM3 will fail if ; multiple commands are enabled, but this feature is so very useful that I ; feel it is worth the sacrifice. Some ZCPR3 utilities, like ALIAS and MENU, ; require multiple commands, and this feature also permits simple chaining ; of programs to be possible under the ZCPR3 environment. ; ; Enjoy using ZCPR3! ; Richard Conn ; ENTRY: JP CPR ; Process potential default command JP CPR1 ; Do NOT process potential default command ; ;**** Section 1 **** ; BUFFERS ET AL ; ; **** 1. INPUT COMMAND LINE AND DEFAULT COMMAND ; IF MULTCMD ;MULTIPLE COMMANDS ALLOWED? ; ; For Multiple Commands, the command line buffer (CMDLIN) is located external ; to ZCPR3 so that it is not overlayed during Warm Boots; the same is true ; for NXTCHR, the 2nd key buffer. BUFSIZ and CHRCNT are not important and ; are provided so the BDOS READLN function can load CMDLIN directly and ; a user program can see how much space is available in CMDLIN for its text. ; NXTCHR EQU Z3CL ;NXTCHR STORED EXTERNALLY (2 bytes) BUFSIZ EQU NXTCHR+2 ;BUFSIZ STORED EXTERNALLY (1 byte) CHRCNT EQU BUFSIZ+1 ;CHRCNT STORED EXTERNALLY (1 byte) CMDLIN EQU CHRCNT+1 ;CMDLIN STORED EXTERNALLY (long) BUFLEN EQU Z3CLS ;LENGTH OF BUFFER ; ELSE ; ; If no multiple commands are permitted, these buffers are left internal ; to ZCPR3 so that the original CCP command line facility (as used by ; programs like SYNONYM3) can be left intact. ; BUFLEN EQU 80 ;MAXIMUM BUFFER LENGTH BUFSIZ: DB BUFLEN ;MAXIMUM BUFFER LENGTH CHRCNT: DB 0 ;NUMBER OF VALID CHARS IN COMMAND LINE CMDLIN: DB ' ' ;DEFAULT (COLD BOOT) COMMAND DB 0 ;COMMAND STRING TERMINATOR DS BUFLEN-[$-CMDLIN]+1 ;TOTAL IS 'BUFLEN' BYTES ; NXTCHR: DW CMDLIN ;POINTER TO COMMAND INPUT BUFFER ; ENDIF ;MULTCMD ; ; ; **** 2. FILE TYPE FOR COMMAND ; COMMSG: COMTYP ;USE MACRO FROM Z3HDR.LIB ; IF SUBON ;IF SUBMIT FACILITY ENABLED ... ; ; **** 3. SUBMIT FILE CONTROL BLOCK ; SUBFCB: DB 1 ;DISK NAME SET TO DEFAULT TO DRIVE A: DB '$$$' ;FILE NAME DB ' ' SUBTYP ;USE MACRO FROM Z3HDR.LIB 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 ; ENDIF ;SUBON ; ; **** 4. COMMAND FILE CONTROL BLOCK ; IF EXTFCB NE 0 ;MAY BE PLACED EXTERNAL TO ZCPR3 ; FCBDN EQU EXTFCB ;DISK NAME FCBFN EQU FCBDN+1 ;FILE NAME FCBFT EQU FCBFN+8 ;FILE TYPE FCBDM EQU FCBFT+7 ;DISK GROUP MAP FCBCR EQU FCBDM+16 ;CURRENT RECORD NUMBER ; ELSE ;OR INTERNAL TO ZCPR3 ; 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 ; ENDIF ;EXTFCB ; ; ; **** 5. LINE COUNT BUFFER ; IF LTON PAGCNT: DB NLINES-2 ;LINES LEFT ON PAGE ENDIF ;LTON ; ; **** 6. RESIDENT COMMAND TABLE ; EACH TABLE ENTRY IS STRUCTURED AS FOLLOWS: ; DB 'NAME' ;NCHARS LONG ; DW ADDRESS ;ADDRESS OF COMMAND ; CMDTBL: DB NCHARS ;SIZE OF TEXT IN COMMAND TABLE CTABLE ;DEFINE COMMAND TABLE VIA MACRO IN Z3HDR FILE DB 0 ;END OF TABLE ; ; ;**** Section 2 **** ; ZCPR3 STARTING POINTS ; ; START ZCPR3 AND DON'T PROCESS DEFAULT COMMAND STORED IF MULTIPLE COMMANDS ; ARE NOT ALLOWED ; CPR1: ; IF NOT MULTCMD ;IF MULTIPLE COMMANDS NOT ALLOWED ; XOR A ;SET END OF COMMAND LINE SO NO DEFAULT COMMAND LD (CMDLIN),A ;FIRST CHAR OF BUFFER ; ENDIF ;NOT MULTCMD ; ; START ZCPR3 AND POSSIBLY PROCESS DEFAULT COMMAND ; ; NOTE ON MODIFICATION BY Ron Fowler: 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: LD SP,STACK ;RESET STACK ; IF NOT MULTCMD ;ONLY ONE COMMAND PERMITTED LD HL,CMDLIN ;SET PTR TO BEGINNING OF COMMAND LINE LD (NXTCHR),HL ENDIF ;NOT MULTCMD ; PUSH BC LD A,C ;C=USER/DISK NUMBER (SEE LOC 4) RRA ;EXTRACT USER NUMBER RRA RRA RRA AND 0FH LD (CURUSR),A ;SET USER CALL SETUSR ;SET USER NUMBER CALL RESET ;RESET DISK SYSTEM ; IF SUBON ;IF SUBMIT FACILITY ENABLED ; LD (RNGSUB),A ;SAVE SUBMIT CLUE FROM DRIVE A: ; ENDIF ;SUBON ; POP BC LD A,C ;C=USER/DISK NUMBER (SEE LOC 4) AND 0FH ;EXTRACT CURRENT DISK DRIVE LD (CURDR),A ;SET IT CALL NZ,LOGIN ;LOG IN DEFAULT DISK IF NOT ALREADY LOGGED IN CALL SETUD ;SET USER/DISK FLAG CALL DEFDMA ;SET DEFAULT DMA ADDRESS ; IF SUBON ;CHECK FOR $$$.SUB IF SUBMIT FACILITY IS ON ; LD DE,SUBFCB ;CHECK FOR $$$.SUB ON CURRENT DISK RNGSUB EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION LD A,0 ;2ND BYTE (IMMEDIATE ARG) IS THE RNGSUB FLAG OR A ;SET FLAGS ON CLUE CALL NZ,SEAR1 LD (RNGSUB),A ;SET FLAG (0=NO $$$.SUB) ; ENDIF ;SUBON ; JR RS1 ;CHECK COMMAND LINE FOR CONTENT ; ; PROMPT USER AND INPUT COMMAND LINE FROM HIM ; RESTRT: LD SP,STACK ;RESET STACK ; ; READ INPUT LINE FROM USER OR $$$.SUB ; RS0: ; IF Z3MSG NE 0 XOR A ;SET NO OUTPUT MESSAGE LD (Z3MSG+3),A ;ZCPR3 COMMAND STATUS INC A ;SET ZCPR3 INPUT PROMPT LD (Z3MSG+7),A ;ZEX MESSAGE BYTE ENDIF ;Z3MSG NE 0 ; LD HL,CMDLIN ;SET POINTER TO FIRST CHAR IN COMMAND LINE LD (NXTCHR),HL ;POINTER TO NEXT CHARACTER TO PROCESS LD (HL),0 ;ZERO OUT COMMAND LINE IN CASE OF WARM BOOT PUSH HL ;SAVE PTR CALL READBUF ;INPUT COMMAND LINE FROM USER (OR $$$.SUB) ; IF Z3MSG NE 0 XOR A ;NORMAL PROCESSING RESUMED LD (Z3MSG+7),A ;ZEX MESSAGE BYTE ENDIF ; POP HL ;GET PTR LD A,(HL) ;CHECK FOR COMMENT LINE CP COMMENT ;BEGINS WITH COMMENT CHAR? JR Z,RS0 ;INPUT ANOTHER LINE IF SO ; ; PROCESS INPUT LINE; NXTCHR PTS TO FIRST LETTER OF COMMAND ; RS1: LD SP,STACK ;RESET STACK ; ; RETURN TO CURRENT DIRECTORY AND POINT TO NEXT CHAR IN COMMAND LINE ; CALL DLOGIN ;RETURN TO CURRENT DIRECTORY LD HL,(NXTCHR) ;PT TO FIRST CHAR OF NEXT COMMAND PUSH HL ;SAVE PTR ; ; CAPITALIZE COMMAND LINE ; CAPBUF: LD A,(HL) ;CAPITALIZE COMMAND CHAR CALL UCASE LD (HL),A INC HL ;PT TO NEXT CHAR OR A ;EOL? JR NZ,CAPBUF POP HL ;GET PTR TO FIRST CHAR IN LINE ; ; SET POINTER FOR MULTIPLE COMMAND LINE PROCESSING TO FIRST CHAR OF NEW CMND ; RS2: CALL SKSP ;SKIP OVER SPACES OR A ;END OF LINE? JR Z,RESTRT CP CTRLC ;ABORT CHAR? JR Z,RESTRT ; IF MULTCMD ;MULTIPLE COMMANDS ALLOWED? LD A,(HL) ;GET FIRST CHAR OF COMMAND CP CMDSEP ;IS IT A COMMAND SEPARATOR? JR NZ,RS3 INC HL ;SKIP IT IF IT IS JR RS2 ENDIF ;MULTCMD ; RS3: LD (NXTCHR),HL ;SET PTR TO FIRST CHAR OF NEW COMMAND LINE LD (CURCMD),HL ;SAVE PTR TO COMMAND LINE FOR ERROR RETURN ; ; PARSE COMMAND LINE PTED TO BY HL ; CALL PARSER ;PARSE ENTIRE COMMAND LINE ; ; CHECK FOR SHELL INVOCATION AND RUN IT IF SO ; IF Z3MSG NE 0 LD A,(Z3MSG+3) ;GET COMMAND STATUS CP 1 ;SHELL? JP Z,RS4 ENDIF ;Z3MSG NE 0 ; ; IF IFON AND FCP AVAILABLE, TRY TO RUN FROM FCP ; IF IFON AND [FCP NE 0] LD HL,FCP+5 ;PT TO COMMAND TABLE CALL CMDSCAN ;SCAN TABLE JP Z,CALLP ;RUN IF FOUND (NO LEADING CRLF) ENDIF ;IFON AND (FCP NE 0) ; ; IF IFON, THEN CHECK FOR RUNNING IF AND FLUSH COMMAND LINE IF ENABLED ; IF IFON LD HL,Z3MSG+1 ;PT TO IF BYTE LD A,(HL) ;GET IT OR A ;SEE IF ANY IF JR Z,RS4 ;CONTINUE IF NOT INC HL ;PT TO IF ACTIVE BYTE AND (HL) ;SEE IF CURRENT IF IS ACTIVE JR Z,RS1 ;SKIP IF NOT ENDIF ;IFON RS4: ; ; IF DIR: PREFIX, HANDLE AS COM FILE ; COLON EQU $+1 ;FLAG FOR IN-THE-CODE MODIFICATION LD A,0 ;COMMAND OF THE FORM 'DIR:COMMAND'? OR A ;0=NO JP NZ,COMDIR ;PROCESS AS COM FILE IF DIR: FORM ; ; CHECK FOR RESIDENT COMMAND ; CALL CMDSER ;SCAN FOR CPR-RESIDENT COMMAND JP Z,CALLP ;RUN CPR-RESIDENT COMMAND WITH NO LEADING CRLF ; ; CHECK FOR RESIDENT COMMAND PACKAGE ; IF RCP NE 0 LD HL,RCP+5 ;PT TO RCP COMMAND TABLE CALL CMDSCAN ;CHECK FOR RCP JP Z,CALLPROG ENDIF ; ; PROCESS AS COM FILE ; JP COM ;PROCESS COM FILE ; ; ERROR PROCESSOR ; ERROR: ; IF SUBON ;IF SUBMIT FACILITY IS ON ; CALL SUBKIL ;TERMINATE ACTIVE $$$.SUB IF ANY ; ENDIF ;SUBON ; CALL CRLF ;NEW LINE ; IF Z3MSG NE 0 ;MESSAGES ENABLED? ; LD A,(Z3MSG+3) ;WAS ERROR CAUSED BY NO SHELL? AND 1 ;BIT 0 SAYS ZCPR3 TRIED TO RUN A SHELL JR NZ,ERRSH ;ABORT SHELL LD A,(Z3MSG) ;GET ERROR HANDLER MESSAGE LD B,A ;... IN B OR A ;FLUSH AND RESUME? JR Z,ERR0 LD A,2 ;SET ERROR FLAG LD (Z3MSG+3),A ;IN SHELL STATUS BUFFER LD HL,(CURCMD) ;PT TO BEGINNING OF ERROR LD (Z3MSG+4),HL ;SAVE IN MESSAGE LD HL,Z3MSG+10H ;PT TO COMMAND LINE LD (NXTCHR),HL ;NEXT CHARACTER TO EXECUTE JP RS1 ;RUN CONTENTS OF BUFFER ; ; CLEAR SHELL STACK AND RESTART COMMAND PROCESSING ; ERRSH: ; IF SHSTK NE 0 ;IF SHELL STACK AVAILABLE XOR A ;CLEAR SHELL STACK LD (SHSTK),A ENDIF ; JP RESTRT ;RESTART PROCESSING ERR0: ; ENDIF ;Z3MSG NE 0 ; CURCMD EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION LD HL,0 ;PT TO BEGINNING OF COMMAND LINE ERR1: LD A,(HL) ;GET CHAR OR A ;END OF LINE? JR Z,ERR2 CALL CONOUT ;PRINT COMMAND CHAR INC HL ;PT TO NEXT CHAR JR ERR1 ;CONTINUE ERR2: CALL PRINT ;PRINT '?' DB '?'+80H ERR3: JP RESTRT ;RESTART CPR ; ; PARSE COMMAND LINE PTED TO BY HL ; RETURN WITH NZ IF ERROR IN COMMAND NAME ; PARSER: ; ; INITIALIZE THE COMMAND AND TOKEN FCBS ; LD DE,FCBDN ;PT TO COMMAND FCB CALL INITFCB ;INIT IT LD DE,TFCB ;PT TO TOKEN FCB CALL INITFCB ;INIT IT ; ; EXTRACT COMMAND NAME ; LD DE,FCBDN ;PLACE COMMAND NAME INTO COMMAND FCB CALL SCANNER ;EXTRACT COMMAND NAME JR NZ,ERROR ;ERROR RETURN ; ; CHECK FOR ERROR IN COMMAND NAME (FILE TYPE GIVEN) ; LD DE,FCBFT ;PT TO FILE TYPE LD A,(DE) ;GET FIRST CHAR OF FILE TYPE CP ' ' ;MUST BE BLANK, OR ERROR JR NZ,ERROR ;ERROR RETURN ; ; SET TYPE OF COMMAND ; PUSH HL ;SAVE PTR TO NEXT BYTE LD HL,COMMSG ;PLACE DEFAULT FILE TYPE (COM) INTO FCB LD B,3 ;3 BYTES CALL LDIR POP HL ;GET PTR TO NEXT BYTE ; ; SET DIR: PREFIX FLAG ; MYCOLON EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION LD A,0 ;PREVIOUS TOKEN CONTAINED A COLON? LD (COLON),A ; ; SAVE POINTER TO COMMAND TAIL FOR LATER COPY INTO TBUFF AND FIND END OF ; COMMAND LINE; THIS IS ALSO THE ENTRY POINT FOR CMDRUN FACILITY TO ; PARSE THE ENTIRE COMMAND LINE AS A TAIL ; PARSET: LD (TAILSV),HL ;SAVE PTR TO COMMAND TAIL PUSH HL ;SAVE PTR CTAIL: LD A,(HL) ;GET CHAR CALL TSTEOL ;AT EOL? JR Z,CTAIL1 INC HL ;PT TO NEXT JR CTAIL CTAIL1: LD (NXTCHR),HL ;SAVE PTR TO NEXT LINE POP HL ;GET PTR TO COMMAND TAIL ; ; EXTRACT FIRST TOKEN ; CALL SKSP ;SKIP OVER SPACES RET Z ;DONE IF EOL OR END OF COMMAND LD DE,TFCB ;STORE FIRST TOKEN IN TFCB CALL SCANNER ;EXTRACT TOKEN ; ; EXTRACT SECOND TOKEN ; CALL SKSP ;SKIP OVER SPACES RET Z ;DONE IF EOL OR END OF COMMAND LD DE,TFCB+16 ;PT TO 2ND FCB AND FALL THRU TO SCANNER ; ; EXTRACT TOKEN FROM COMMAND LINE AND PLACE IT INTO FCB PTED TO BY DE ; FORMAT FCBDN FCB IF TOKEN RESEMBLES FILE NAME AND TYPE (FILENAME.TYP) ; ON INPUT, HL PTS TO NEXT CHAR AND DE PTS TO FCB ; ON OUTPUT, HL PTS TO DELIMITER AFTER TOKEN AND ZERO FLAG IS RESET ; IF '?' IS IN TOKEN ; ; ENTRY POINTS: ; SCANNER - LOAD TOKEN INTO FCB PTED TO BY DE ; SCANNER: XOR A ;A=0 LD (DE),A ;SET DEFAULT DRIVE LD (MYCOLON),A ;SET NO COLON LD (TEMPDR),A ;SET TEMPORARY DRIVE NUMBER TO DEFAULT LD (QMCNT),A ;ZERO QUESTION MARK COUNTER LD A,(CURUSR) ;GET CURRENT USER LD (TEMPUSR),A ;SET TEMPUSR PUSH DE ;SAVE PTR TO FIRST BYTE OF FCB LD B,8 ;8 CHARS MAX CALL SCANF ;PLACE FIRST TOKEN INTO FILE NAME FIELD POP DE ;GET PTR TO FIRST BYTE OF FCB LD A,(HL) ;GET TERMINATING CHAR LD (ENDCHAR),A ;SET ENDING CHAR CP ':' ;COLON? JR NZ,SCAN1 ;NO, WE HAVE A FILE NAME LD (MYCOLON),A ;SET COLON INC HL ;PT TO CHAR AFTER COLON ; ; SCAN TOKEN FOR DIR: FORM, WHICH MEANS WE HAVE A USER/DISK SPECIFICATION ; HL PTS TO CHAR AFTER COLON ; IF [Z3NDIR NE 0] AND NDINCP ;NAMED DIRS AVAILABLE ; IF DUFIRST ;DU: BEFORE DIR: ; ; CHECK FOR DU: FORM ; IF ACCPTDU ;PERMIT DU: FORM PUSH DE ;SAVE PTR TO FCB DN PUSH HL ;SAVE PTR TO NEXT CHAR IN LINE CALL DUSCAN ;CHECK FOR DU: FORM POP HL ;GET PTR TO NEXT CHAR POP DE ;GET PTR TO FCB JR Z,SUD1 ;GOT IT ENDIF ;ACCPTDU ; ; CHECK FOR DIR: FORM ; IF ACCPTND ;PERMIT DIR: FORM PUSH DE ;SAVE PTR TO FCB PUSH HL ;SAVE PTR TO NEXT CHAR CALL DIRSCAN ;CHECK FOR DIR: FORM POP HL ;GET PTR TO NEXT CHAR POP DE ;GET PTR TO FCB JR NZ,SCAN1 ;ERROR IN PREFIX ENDIF ;ACCPTND SUD1: ; ELSE ;DIR: BEFORE DU: ; ; CHECK FOR DIR: FORM ; IF ACCPTND ;PERMIT DIR: FORM PUSH DE ;SAVE PTR TO FCB PUSH HL ;SAVE PTR TO NEXT CHAR CALL DIRSCAN ;CHECK FOR DIR: FORM POP HL ;GET PTR TO NEXT CHAR POP DE ;GET PTR TO FCB JR Z,SUD1 ;GOT IT ENDIF ;ACCPTND ; ; CHECK FOR DU: FORM ; IF ACCPTDU ;PERMIT DU: FORM PUSH DE ;SAVE PTR TO FCB DN PUSH HL ;SAVE PTR TO NEXT CHAR IN LINE CALL DUSCAN ;CHECK FOR DU: FORM POP HL ;GET PTR TO NEXT CHAR POP DE ;GET PTR TO FCB JR NZ,SCAN1 ;ERROR IN PREFIX ENDIF ;ACCPTDU SUD1: ; ENDIF ;DUFIRST ; ELSE ;DU ONLY ; ; CHECK FOR DU: FORM ; IF ACCPTDU ;ALLOW DU: FORM PUSH DE ;SAVE PTR TO FCB DN PUSH HL ;SAVE PTR TO NEXT CHAR IN LINE CALL DUSCAN ;CHECK FOR DU: FORM POP HL ;GET PTR TO NEXT CHAR POP DE ;GET PTR TO FCB JR NZ,SCAN1 ;ERROR IN PREFIX ENDIF ;ACCPTDU ; ENDIF ;(Z3NDIR NE 0) AND NDINCP ; ; SET DRIVE REFERENCED ; LD A,(TEMPDR) ;SET DRIVE LD (DE),A ;... IN FCB ; ; REINIT FCB PTED TO BY DE ; PUSH DE ;SAVE PTR INC DE ;PT TO FN FIELD CALL IFCB ;ONLY PARTIAL INIT (17 BYTES TOTAL) POP DE ; ; EXTRACT FILENAME FIELD ; XOR A LD (QMCNT),A ;ZERO QUESTION MARK COUNTER PUSH DE ;SAVE PTR TO FIRST BYTE OF FCB LD B,8 ;8 CHARS MAX CALL SCANF ;STORE FILE NAME POP DE ;GET PTR TO FIRST BYTE OF FCB LD A,(HL) ;GET OFFENDING CHAR LD (ENDCHAR),A ;SET ENDING CHAR ; ; SKIP TO FILE TYPE FIELD ; HL PTS TO NEXT CHAR, DE PTS TO DN FIELD OF FCB ; SCAN1: ENDCHAR EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION LD A,0 ;GET ENDING CHAR EX DE,HL LD BC,8 ;PT TO BEFORE FILE TYPE FIELD OF FCB ADD HL,BC EX DE,HL ; ; EXTRACT FILETYPE FIELD ; LD B,3 ;PREPARE TO EXTRACT FILE TYPE CP '.' ;IF '.', WE HAVE A TYPE JR NZ,SCAN2 INC HL ;PT TO CHAR AFTER '.' PUSH DE CALL SCANF ;GET FCB FILE TYPE POP DE SCAN2: ; ; SET USER NUMBER REFERENCED ; HL PTS TO NEXT CHAR, DE PTS TO BEFORE FCB FT ; EX DE,HL LD BC,5 ;PT TO S1 FIELD ADD HL,BC EX DE,HL LD A,(TEMPUSR) ;STORE USER NUMBER HERE LD (DE),A ; ; SKIP TO SPACE, CHAR AFTER =, OR EOL ; HL PTS TO NEXT CHAR IN LINE ; SCAN3: LD A,(HL) ;GET NEXT CHAR CP ' '+1 ;DONE IF LESS THAN SPACE JR C,SCAN4 CALL TSTEOL ;EOL? JR Z,SCAN4 INC HL ;PT TO NEXT CP '=' ;EQUATE? JR NZ,SCAN3 SCAN4: ; ; SET ZERO FLAG TO INDICATE PRESENCE OF '?' IN DIR:FILENAME.TYP ; QMCNT EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION LD A,0 ;NUMBER OF QUESTION MARKS OR A ;SET ZERO FLAG RET ; ; SCANF -- SCAN TOKEN PTED TO BY HL FOR A MAX OF B BYTES; PLACE IT INTO ; FILE NAME FIELD PTED TO BY DE; EXPAND AND INTERPRET WILD CARDS OF ; '*' AND '?'; ON EXIT, DE PTS TO TERMINATING DELIMITER ; SCANF: CALL SDELM ;DONE IF DELIMITER ENCOUNTERED RET Z INC DE ;PT TO NEXT BYTE IN FCB CP '*' ;IS (DE) A WILD CARD? JR NZ,SCANF1 ;CONTINUE IF NOT LD A,'?' ;PLACE '?' IN FCB AND DON'T ADVANCE HL IF SO LD (DE),A CALL SCQ ;SCANNER COUNT QUESTION MARKS JR SCANF2 SCANF1: LD (DE),A ;STORE FILENAME CHAR IN FCB INC HL ;PT TO NEXT CHAR IN COMMAND LINE CP '?' ;CHECK FOR QUESTION MARK (WILD) CALL Z,SCQ ;SCANNER COUNT QUESTION MARKS SCANF2: DJNZ SCANF ;DECREMENT CHAR COUNT UNTIL 8 ELAPSED SCANF3: CALL SDELM ;8 CHARS OR MORE - SKIP UNTIL DELIMITER RET Z ;ZERO FLAG SET IF DELIMITER FOUND INC HL ;PT TO NEXT CHAR IN COMMAND LINE JR SCANF3 ; ; INCREMENT QUESTION MARK COUNT FOR SCANNER ; THIS ROUTINE INCREMENTS THE COUNT OF THE NUMBER OF QUESTION MARKS IN ; THE CURRENT FCB ENTRY ; SCQ: PUSH HL ;SAVE HL LD HL,QMCNT ;GET COUNT INC (HL) ;INCREMENT POP HL ;GET HL RET ; ; SCAN FOR AND EXTRACT DISK/USER INFO ASSUMING DU: FORM ; ON ENTRY, DE PTS TO FIRST BYTE OF FCB CONTAINING POSSIBLE DU FORM ; ON EXIT, ZERO FLAG SET MEAN OK AND TEMPDR AND TEMPUSR SET ; IF ACCPTDU ;ALLOW DU: FORM DUSCAN: EX DE,HL ;PTR IN HL INC HL ;PT TO FIRST BYTE OF FN LD A,(HL) ;GET FIRST CHAR CP 'A' ;CONVERT POSSIBLE DRIVE SPEC TO NUMBER JR C,DUS1 ;IF LESS THAN 'A', MUST BE DIGIT ; ; SET DISK NUMBER (A=1) ; SUB 'A'-1 ;CONVERT DRIVE NUMBER TO 1-16 CP MAXDISK+1 ;WITHIN RANGE? JR NC,DUSE1 ;INVALID DISK NUMBER LD (TEMPDR),A ;SET TEMPORARY DRIVE NUMBER INC HL ;PT TO NEXT CHAR LD A,(HL) ;SEE IF IT IS A SPACE CP ' ' RET Z CALL DIGCK ;CHECK FOR DIGIT RET C ; ; SET USER NUMBER ; DUS1: PUSH HL ;SAVE PTR TO DIGITS LD B,2 ;UP TO 2 DIGITS DUS1A: LD A,(HL) ;CHECK FOR DIGIT OR SPACE CP ' ' ;IF SPACE, THEN NO DIGIT JR Z,DUS2 CALL DIGCK ;CHECK FOR DIGIT JR C,DUSE INC HL DJNZ DUS1A ;COUNT DOWN LD A,(HL) ;3RD CHAR CP ' ' ;MUST BE SPACE JR NZ,DUSE DUS2: POP HL CALL NUM0A ;GET NUMBER CP MAXUSR+1 ;WITHIN LIMIT? JR NC,DUSE1 LD (TEMPUSR),A ;SAVE USER NUMBER XOR A ;SET OK RET DUSE: POP HL ;CLEAR STACK DUSE1: XOR A DEC A RET ; ENDIF ;ACCPTDU ; IF [Z3NDIR NE 0] AND NDINCP AND ACCPTND ; ; SCAN FOR DIR FORM ; ON ENTRY, DE PTS TO FCB CONTAINING NAME TO CHECK FOR ; ON EXIT, IF FOUND, Z AND TEMPUSR AND TEMPDR SET ; DIRSCAN: EX DE,HL ;PTR IN HL INC HL ;PT TO FN LD DE,Z3NDIR ;PT TO FIRST ENTRY IN MEMORY-BASED DIR DIRS1: LD A,(DE) ;GET NEXT CHAR OR A ;ZERO IF END OF DIR JR Z,DIRSERR INC DE ;PT TO DIR NAME INC DE PUSH HL ;SAVE PTR TO FILE NAME PUSH DE ;SAVE PTR TO DIR ENTRY LD B,8 ;MATCH? DIRS2: LD A,(DE) ;GET BYTE CP (HL) ;COMPARE JR NZ,DIRS3 INC HL ;PT TO NEXT INC DE DJNZ DIRS2 ;COUNT DOWN DIRS3: POP DE ;RESTORE REGS POP HL JR Z,DIRS4 EX DE,HL ;ADVANCE TO NEXT ENTRY LD BC,16 ;8 BYTES FOR NAME + 8 BYTES FOR PASSWORD ADD HL,BC EX DE,HL JR DIRS1 ; ; NO DIR match ; DIRSERR: XOR A ;RETURN NZ DEC A RET ; ; DIR match ; DIRS4: ; IF PWCHECK PUSH DE ;SAVE PTR TO DE LD BC,8 ;PT TO PW EX DE,HL ;HL PTS TO ENTRY ADD HL,BC CALL PASSCK ;CHECK FOR PW POP DE ;GET PTR JP NZ,DIRSERR ENDIF ;PWCHECK ; DEC DE ;PT TO USER LD A,(DE) ;GET USER LD (TEMPUSR),A DEC DE ;PT TO DISK LD A,(DE) ;GET IT LD (TEMPDR),A ;A=1 XOR A ;SET Z RET ; ENDIF ;(Z3NDIR NE 0) AND NDINCP AND ACCPTND ; IF PWCHECK ; ; CHECK FOR PASSWORD PTED TO BY HL ; RETURN WITH ZERO FLAG SET IF MATCH ; PASSCK: LD A,(HL) ;CHECK FOR NO PW CP ' ' RET Z PUSH HL ;SAVE PTR CALL PRINT DB CR,LF,'PW?',' '+80H LD DE,PWLIN LD A,9 ;SET CHAR COUNT LD (DE),A LD C,10 ;BDOS READLN PUSH DE CALL BDOS POP HL ;GET PTR TO BUFFER INC HL ;PT TO CHAR COUNT LD A,(HL) ;GET CHAR COUNT INC HL ;PT TO FIRST CHAR PUSH HL ;SAVE PTR CALL ADDAH ;HL PTS TO AFTER LAST CHAR LD (HL),' ' ;PLACE SPACE POP DE ;PT TO USER INPUT POP HL ;PT TO PASSWORD LD B,8 ;8 CHARS MAX PWCK: LD A,(DE) ;GET NEXT CHAR CALL UCASE ;CAPITALIZE USER INPUT CP (HL) ;COMPARE FOR MATCH RET NZ ;NO MATCH CP ' ' ;DONE? RET Z INC HL ;PT TO NEXT INC DE DJNZ PWCK XOR A ;SET ZERO FLAG RET ; ENDIF ;PWCHECK ; ; SKIP OVER SPACES PTED TO BY HL ; ON RETURN, ZERO FLAG SET MEANS WE HIT EOL OR CMDSEP ; SKSP: LD A,(HL) ;GET NEXT CHAR INC HL ;PT TO NEXT CP ' ' ;SPACE? JR Z,SKSP DEC HL ;PT TO NON-SPACE ; ; CHECK TO SEE IF CHAR IN A IS EOL OR CMDSEP ; TSTEOL: OR A ;EOL? ; IF MULTCMD ;MULTIPLE COMMANDS SUPPORTED? RET Z ;RETURN WITH FLAG CP CMDSEP ;COMMAND SEPARATOR? ENDIF ;MULTCMD ; RET ; ; INIT FCB PTED TO BY DE ; INITFCB: XOR A LD (DE),A ;SET DEFAULT DISK (DN BYTE IS 0) INC DE ;PT TO FILE NAME FIELD CALL IFCB ;FILL 1ST PART OF FCB; FALL THRU TO IFCB TO RUN AGAIN ; ; FILL FN, FT, EX, S1, S2, RC, AND FOLLOWING CR (OR DN) FIELDS ; IFCB: LD B,11 ;STORE 11 SPACES LD A,' ' CALL FILL XOR A LD (DE),A ;SET EX TO ZERO INC DE LD A,(CURUSR) LD (DE),A ;SET S1 TO CURRENT USER INC DE LD B,3 ;STORE 3 ZEROES XOR A ;FALL THRU TO FILL ; ; FILL MEMORY POINTED TO BY DE WITH CHAR IN A FOR B BYTES ; FILL: LD (DE),A ;FILL WITH BYTE IN A INC DE ;PT TO NEXT DJNZ FILL RET ; ; 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 ; CONIN: LD C,1 ;INPUT CHAR CALL BDOS ;GET INPUT CHAR WITH ^S PROCESSING AND ECHO JP UCASE ;CAPITALIZE ; ; OUTPUT ; CRLF: LD A,CR CALL CONOUT LD A,LF ;FALL THRU TO CONOUT ; CONOUT: PUTRG ;SAVE REGS LD C,2 OUTPUT: LD E,A CALL BDOS GETRG ;GET REGS RET ; LCOUT: PUSH AF ;OUTPUT CHAR TO CON: OR LST: DEP ON PRFLG PRFLG EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION LD A,0 ;2ND BYTE (IMMEDIATE ARG) IS THE PRINT FLAG OR A ;0=TYPE JR Z,LC1 POP AF ;GET CHAR ; ; OUTPUT CHAR IN REG A TO LIST DEVICE ; LSTOUT: PUTRG ;SAVE REGISTERS LD C,5 JR OUTPUT LC1: POP AF ;GET CHAR PUSH AF CALL CONOUT ;OUTPUT TO CON: POP AF ; IF LTON CP LF ;CHECK FOR PAGING RET NZ ; ; PAGING ROUTINES ; PAGER COUNTS DOWN LINES AND PAUSES FOR INPUT (DIRECT) IF COUNT EXPIRES ; PAGSET SETS LINES/PAGE COUNT ; PAGER: PUSH HL LD HL,PAGCNT ;COUNT DOWN DEC (HL) JR NZ,PAGER1 ;JUMP IF NOT END OF PAGE LD (HL),NLINES-2 ;REFILL COUNTER ; PGFLG EQU $+1 ;POINTER TO IN-THE-CODE BUFFER PGFLG LD A,0 ;0 MAY BE CHANGED BY PGFLG EQUATE CP PGDFLG ;PAGE DEFAULT OVERRIDE OPTION WANTED? ; IF PGDFLT ;IF PAGING IS DEFAULT JR Z,PAGER1 ; PGDFLG MEANS NO PAGING ELSE ;IF PAGING NOT DEFAULT JR NZ,PAGER1 ; PGDFLG MEANS PLEASE PAGINATE ; ENDIF ;PGDFLG ; PUSH BC ;SAVE REG CALL BIOS+9 ;BIOS CONSOLE INPUT ROUTINE POP BC ;GET REG CP 'C'-'@' ;^C JP Z,RS1 ;RESTART CPR PAGER1: POP HL ;RESTORE HL ENDIF ;LTON ; RET ;RETURN FOR LC1 IF NOT LTON ; ; READ FILE BLOCK FUNCTION ; READF: LD DE,TFCB ;FALL THRU TO READ READ: LD C,14H ;FALL THRU TO BDOSB ; ; CALL BDOS AND SAVE BC ; BDOSB: PUSH BC CALL BDOS POP BC OR A ; ; THIS RETURN IS FOR BDOSB AND FOR THE NULL FUNCTION CALLED NOTE ; NOTE: RET ; ; PRINT STRING (ENDING IN CHAR WITH MSB SET) PTED TO BY RET ADR ; START WITH ; PRINTC: CALL CRLF ;NEW LINE ; PRINT: EX (SP),HL ;GET PTR TO STRING CALL PRIN1 ;PRINT STRING EX (SP),HL ;RESTORE HL AND RET ADR RET ; ; PRINT STRING (ENDING IN 0 OR BYTE WITH MSB SET) PTED TO BY HL ; PRIN1: LD A,(HL) ;GET NEXT BYTE INC HL ;PT TO NEXT BYTE OR A ;END OF STRING? RET Z ;STRING TERMINATED BY BINARY 0 PUSH AF ;SAVE FLAGS AND 7FH ;MASK OUT MSB CALL CONOUT ;PRINT CHAR POP AF ;GET FLAGS RET M ;STRING TERMINATED BY MSB SET JR PRIN1 ; ; BDOS FUNCTION ROUTINES ; ; ; RETURN NUMBER OF CURRENT DISK IN A ; GETDRV: LD C,19H JR BDOSJP ; ; SET 80H AS DMA ADDRESS ; DEFDMA: LD DE,TBUFF ;80H=TBUFF DMASET: LD C,1AH JR BDOSJP ; RESET: LD C,0DH BDOSJP: JP BDOS ; LOGIN: LD E,A LD C,0EH JR BDOSJP ;SAVE SOME CODE SPACE ; OPENF: XOR A LD (FCBCR),A LD DE,FCBDN ;FALL THRU TO OPEN ; OPEN: LD C,0FH ;FALL THRU TO GRBDOS ; GRBDOS: CALL BDOS INC A ;SET ZERO FLAG FOR ERROR RETURN RET ; CLOSE: LD C,10H JR GRBDOS ; SEARF: LD DE,TFCB ;SPECIFY FCB SEAR1: LD C,11H JR GRBDOS ; SEARN: LD C,12H JR GRBDOS ; ; CHECK FOR SUBMIT FILE IN EXECUTION AND ABORT IT IF SO ; IF SUBON ;ENABLE ONLY IF SUBMIT FACILITY IS ENABLED ; SUBKIL: LD HL,RNGSUB ;CHECK FOR SUBMIT FILE IN EXECUTION LD A,(HL) OR A ;0=NO RET Z LD (HL),0 ;ABORT SUBMIT FILE LD DE,SUBFCB ;DELETE $$$.SUB ; ENDIF ;SUBON ; DELETE: LD C,13H JR BDOSJP ;SAVE MORE SPACE ; ; GET/SET USER NUMBER ; GETUSR: LD A,0FFH ;GET CURRENT USER NUMBER SETUSR: LD E,A ;USER NUMBER IN E LD C,20H ;SET USER NUMBER TO VALUE IN E (GET IF E=FFH) JR BDOSJP ;MORE SPACE SAVING ; ; END OF BDOS FUNCTIONS ; ; ;**** Section 4 **** ; ZCPR3 UTILITIES ; ; SET USER/DISK FLAG TO CURRENT USER AND DEFAULT DISK ; SETUD: CALL GETUSR ;GET NUMBER OF CURRENT USER AND 0FH ;MASK SURE 4 BITS ADD A,A ;PLACE IT IN HIGH NYBBLE ADD A,A ADD A,A ADD A,A LD HL,CURDR ;MASK IN CURRENT DRIVE NUMBER (LOW NYBBLE) OR (HL) ;MASK IN LD (UDFLAG),A ;SET USER/DISK NUMBER RET ; ; CONVERT CHAR IN A TO UPPER CASE ; UCASE: AND 7FH ;MASK OUT MSB CP 61H ;LOWER-CASE A RET C CP 7BH ;GREATER THAN LOWER-CASE Z? RET NC AND 5FH ;CAPITALIZE RET ; ; PRINT DU (DIR) PROMPT ; PROMPT: ; ; PRINT PROMPT (DU>) ; CALL CRLF ;PRINT PROMPT ; IF INCLDU ;IF DRIVE IN PROMPT LD A,(CURDR) ;CURRENT DRIVE IS PART OF PROMPT ADD 'A' ;CONVERT TO ASCII A-P CALL CONOUT LD A,(CURUSR) ;GET USER NUMBER ; IF SUPRES ;IF SUPPRESSING USR # REPORT FOR USR 0 OR A JR Z,PRMPT2 ENDIF ;SUPRES ; CP 10 ;USER < 10? JR C,PRMPT1 SUB 10 ;SUBTRACT 10 FROM IT PUSH AF ;SAVE IT LD A,'1' ;OUTPUT 10'S DIGIT CALL CONOUT POP AF PRMPT1: ADD '0' ;OUTPUT 1'S DIGIT (CONVERT TO ASCII) CALL CONOUT PRMPT2: ENDIF ;INCLDU ; ; PRINT NDIR ENTRY IF ANY ; IF INCLNDR AND [Z3NDIR NE 0] ; LD A,(CURDR) ;GET CURRENT DU IN BC INC A LD B,A LD A,(CURUSR) LD C,A LD HL,Z3NDIR ;SCAN DIRECTORY FOR MATCH ; ; MAIN LOOP FOR SCANNING NDR FOR DU IN BC ; PRMPT3: LD A,(HL) ;END OF NDR? OR A RET Z INC HL ;PT TO USER CP B ;COMPARE DISK JR NZ,PRMPT5 LD A,(HL) ;COMPARE USER CP C JR NZ,PRMPT5 ; ; MATCH OF DU ; IF INCLDU ;SEPARATE DU AND NDR WITH COLON LD A,':' ;PRINT SEPARATOR CALL CONOUT ENDIF ;INCLDU ; LD B,8 ;8 CHARS MAX PRMPT4: INC HL ;PT TO NEXT CHAR LD A,(HL) ;GET NEXT CHAR CP ' ' ;DONE IF SPACE RET Z CALL CONOUT ;PRINT CHAR DJNZ PRMPT4 ;COUNT DOWN RET ; ; ADVANCE TO NEXT DU ; PRMPT5: LD DE,16+1 ;SKIP USER (1 BYTE) AND NAME/PW (16 BYTES) ADD HL,DE JR PRMPT3 ;CONTINUE SCAN ; ENDIF ;INCLNDR AND (Z3NDIR NE 0) ; 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 ; READBUF: ; IF SUBON ;IF SUBMIT FACILITY IS ENABLED, CHECK FOR IT ; LD A,(RNGSUB) ;SUBMIT FILE CURRENTLY IN EXECUTION? OR A ;0=NO JR Z,RB1 ;GET LINE FROM CONSOLE IF NOT LD DE,SUBFCB ;OPEN $$$.SUB PUSH DE ;SAVE DE CALL OPEN POP DE ;RESTORE DE JR Z,RB1 ;ERASE $$$.SUB IF END OF FILE AND GET CMND LD A,(SUBFRC) ;GET VALUE OF LAST RECORD IN FILE DEC A ;PT TO NEXT TO LAST RECORD LD (SUBFCR),A ;SAVE NEW VALUE OF LAST RECORD IN $$$.SUB CALL READ ;DE=SUBFCB JR NZ,RB1 ;ABORT $$$.SUB IF ERROR IN READING LAST REC LD DE,CHRCNT ;COPY LAST RECORD (NEXT SUBMIT CMND) TO CHRCNT LD HL,TBUFF ; FROM TBUFF LD B,BUFLEN ;NUMBER OF BYTES CALL LDIR LD HL,SUBFS2 ;PT TO S2 OF $$$.SUB FCB LD (HL),0 ;SET S2 TO ZERO INC HL ;PT TO RECORD COUNT DEC (HL) ;DECREMENT RECORD COUNT OF $$$.SUB LD DE,SUBFCB ;CLOSE $$$.SUB CALL CLOSE JR Z,RB1 ;ABORT $$$.SUB IF ERROR CALL PROMPT ;PRINT PROMPT LD A,SPRMPT ;PRINT SUBMIT PROMPT TRAILER CALL CONOUT LD HL,CMDLIN ;PRINT COMMAND LINE FROM $$$.SUB CALL PRIN1 CALL BREAK ;CHECK FOR ABORT (ANY CHAR) RET NZ ;IF NO ^C, RETURN TO CALLER AND RUN CALL SUBKIL ;KILL $$$.SUB IF ABORT JP RESTRT ;RESTART CPR ; ; INPUT COMMAND LINE FROM USER CONSOLE ; RB1: CALL SUBKIL ;ERASE $$$.SUB IF PRESENT ; ENDIF ;SUBON ; ; IF SHELL STACKS ARE IMPLEMENTED, CHECK FOR CONTENT AT THIS TIME ; IF SHSTK NE 0 ; LD HL,SHSTK ;PT TO STACK LD A,(HL) ;CHECK FIRST BYTE CP ' '+1 ;SEE IF ANY ENTRY JR C,RB2 ;GET USER INPUT IF NONE ; ENDIF ;SHSTK NE 0 ; IF [SHSTK NE 0] OR [Z3MSG NE 0] ; RUNBUF: LD DE,CMDLIN ;PT TO FIRST CHAR OF COMMAND LINE LD B,SHSIZE ;COPY SHELL LINE INTO COMMAND LINE BUFFER CALL LDIR ;DO COPY EX DE,HL ;HL PTS TO END OF LINE LD A,1 ;SAY SHELL WAS INVOKED LD (Z3MSG+3),A ;Z3 OUTPUT MESSAGE JR RB3 ;STORE ENDING ZERO AND EXIT RB2: ; ENDIF ;(SHSTK NE 0) OR (Z3MSG NE 0) ; CALL PROMPT ;PRINT PROMPT LD A,CPRMPT ;PRINT PROMPT TRAILER CALL CONOUT LD C,0AH ;READ COMMAND LINE FROM USER LD DE,BUFSIZ ;PT TO BUFFER SIZE BYTE OF COMMAND LINE CALL BDOS ; ; STORE ZERO AT END OF COMMAND LINE ; LD HL,CHRCNT ;PT TO CHAR COUNT LD A,(HL) ;GET CHAR COUNT INC HL ;PT TO FIRST CHAR OF COMMAND LINE CALL ADDAH ;PT TO AFTER LAST CHAR OF COMMAND LINE RB3: LD (HL),0 ;STORE ENDING ZERO RET ; ; CHECK FOR ANY CHAR FROM USER CONSOLE; RET W/ZERO SET IF NONE ; BREAK: PUTRG ;SAVE REGISTERS CALL BIOS+6 ;CONSOLE STATUS CHECK OR A ;SET FLAGS CALL NZ,BIOS+9 ;GET INPUT CHAR WITH ^S PROCESSING CP 'S'-'@' ;PAUSE IF ^S CALL Z,BIOS+9 ;GET NEXT CHAR GETRG ;RESTORE REGISTERS CP 'C'-'@' ;CHECK FOR ABORT RET ; ; CHECK TO SEE IF HL PTS TO DELIMITER; IF SO, RET W/ZERO FLAG SET ; SDELM: LD A,(HL) ;GET NEXT CHAR FROM LINE CP ' '+1 ;DELIM IF <= JR C,ZERO CP '=' ;'='=DELIMITER RET Z CP 5FH ;UNDERSCORE=DELIMITER RET Z CP '.' ;'.'=DELIMITER RET Z CP ':' ;':'=DELIMITER RET Z CP ',' ;','=DELIMITER RET Z ; IF CMDSEP NE ';' CP ';' ;';'=DELIMITER RET Z ENDIF ; CP '<' ;'<'=DELIMITER RET Z CP '>' ;'>'=DELIMITER RET Z JP TSTEOL ;CHECK FOR EOL ZERO: XOR A ;SET ZERO FLAG RET ; ; ADD A TO HL (HL=HL+A) ; ADDAH: ADD A,L LD L,A RET NC INC H RET ; ; COPY FROM HL TO DE FOR B BYTES ; LDIR: LD A,(HL) ;GET BYTE LD (DE),A ;PUT BYTE INC HL ;PT TO NEXT INC DE DJNZ LDIR RET ; ; EXTRACT DECIMAL NUMBER FROM COMMAND LINE ; RETURN WITH VALUE IN REG A; ALL REGISTERS MAY BE AFFECTED ; NUMBER: LD HL,TFCB+8 ;PT TO END OF TOKEN FOR CONVERSION LD B,8 ;8 CHARS MAX ; ; CHECK FOR SUFFIX FOR HEXADECIMAL NUMBER ; NUMS: LD A,(HL) ;GET CHARS FROM END, SEARCHING FOR SUFFIX DEC HL ;BACK UP CP ' ' ;SPACE? JR NZ,NUMS1 ;CHECK FOR SUFFIX DJNZ NUMS ;COUNT DOWN JR NUM0 ;BY DEFAULT, PROCESS NUMS1: CP NUMBASE ;CHECK AGAINST BASE SWITCH FLAG JR Z,HEXNUM ; ; PROCESS DECIMAL NUMBER ; NUM0: LD HL,TFCB+1 ;PT TO BEGINNING OF TOKEN NUM0A: LD BC,1100H ;C=ACCUMULATED VALUE, B=CHAR COUNT ; (C=0, B=11) NUM1: LD A,(HL) ;GET CHAR CALL SDELM ;DONE IF DELIMITER JR Z,NUM2 INC HL ;PT TO NEXT CHAR CALL DIGCK ;CHECK FOR DIGIT IN A JR C,NUMERR LD D,A ;DIGIT IN D LD A,C ;NEW VALUE = OLD VALUE * 10 RLCA ;*2 JR C,NUMERR RLCA ;*4 JR C,NUMERR ADD A,C ;*5 JR C,NUMERR RLCA ;*10 JR C,NUMERR ADD A,D ;NEW VALUE = OLD VALUE * 10 + DIGIT JR C,NUMERR ;CHECK FOR RANGE ERROR LD C,A ;SET NEW VALUE DJNZ NUM1 ;COUNT DOWN ; ; RETURN FROM NUMBER ; NUM2: LD A,C ;GET ACCUMULATED VALUE RET ; ; NUMBER ERROR ROUTINE FOR SPACE CONSERVATION ; NUMERR: JP ERROR ;USE ERROR ROUTINE - THIS IS RELATIVE PT ; ; CHECK TO SEE IF A IS A DIGIT ; IF SO, RETURN ITS VALUE ; IF NOT, RETURN WITH CARRY SET ; DIGCK: SUB '0' ;DIGIT? RET C ;ERROR CP 10 ;RANGE? JR NC,DIGCK1 CCF ;FLIP CARRY RET DIGCK1: SCF ;SET CARRY RET ; ; EXTRACT HEXADECIMAL NUMBER FROM COMMAND LINE ; RETURN WITH VALUE IN REG A; ALL REGISTERS MAY BE AFFECTED ; HEXNUM: LD HL,TFCB+1 ;PT TO TOKEN FOR CONVERSION LD DE,0 ;DE=ACCUMULATED VALUE LD B,11 ;B=CHAR COUNT HNUM1: LD A,(HL) ;GET CHAR CP ' ' ;DONE? JR Z,HNUM3 ;RETURN IF SO CP NUMBASE ;DONE IF NUMBASE SUFFIX JR Z,HNUM3 SUB '0' ;CONVERT TO BINARY JR C,NUMERR ;RETURN AND DONE IF ERROR CP 10 ;0-9? JR C,HNUM2 SUB 7 ;A-F? CP 10H ;ERROR? JR NC,NUMERR HNUM2: INC HL ;PT TO NEXT CHAR LD C,A ;DIGIT IN C LD A,D ;GET ACCUMULATED VALUE RLCA ;EXCHANGE NYBBLES RLCA RLCA RLCA AND 0F0H ;MASK OUT LOW NYBBLE LD D,A LD A,E ;SWITCH LOW-ORDER NYBBLES RLCA RLCA RLCA RLCA LD E,A ;HIGH NYBBLE OF E=NEW HIGH OF E, ; LOW NYBBLE OF E=NEW LOW OF D AND 0FH ;GET NEW LOW OF D OR D ;MASK IN HIGH OF D LD D,A ;NEW HIGH BYTE IN D LD A,E AND 0F0H ;MASK OUT LOW OF E OR C ;MASK IN NEW LOW LD E,A ;NEW LOW BYTE IN E DJNZ HNUM1 ;COUNT DOWN ; ; RETURN FROM HEXNUM ; HNUM3: EX DE,HL ;RETURNED VALUE IN HL LD A,L ;LOW-ORDER BYTE IN A RET ; ; LOG INTO DU CONTAINED IN FCB PTED TO BY DE ; FCBLOG: PUSH DE ;SAVE PTR TO FCB EX DE,HL LD A,(HL) ;GET DRIVE LD (TEMPDR),A ;SET TEMP DRIVE LD BC,13 ;PT TO S1 FIELD ADD HL,BC LD A,(HL) ;GET USER LD (TEMPUSR),A ;SET TEMP USER CALL SLOGIN ;LOG IN POP DE ;GET PTR TO FCB RET ; ; CHECK FOR SPECIFIED DRIVE AND LOG IT IN ; SLOGIN: TEMPDR EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION LD A,0 ;2ND BYTE (IMMEDIATE ARG) IS TEMPDR OR A ;0=CURRENT DRIVE JR NZ,SLOG1 LD A,(CURDR) ;LOG IN CURRENT DRIVE INC A ;ADD 1 FOR NEXT DCR SLOG1: DEC A ;ADJUST FOR PROPER DISK NUMBER (A=0) CALL LOGIN ;LOG IN NEW DRIVE TEMPUSR EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION LD A,0 ;2ND BYTE IS USER TO BE SELECTED JP SETUSR ;LOG IN NEW USER ; ; ROUTINE TO CHECK FOR A WHEEL BYTE AS NON-ZERO ; IF WHEEL BYTE IS ZERO, THEN ABORT (POP STACK AND RETURN) ; ; IF WHEEL ;WHEEL FACILITY? WHLCHK: LD A,(Z3WHL) ;GET WHEEL BYTE OR A ;ZERO? RET NZ ;OK IF NOT JP ERROR ;PROCESS AS ERROR ENDIF ;WHEEL ; ; ; CMDTBL (COMMAND TABLE) SCANNER ; ON RETURN, HL CONTAINS ADDRESS OF COMMAND IF CPR-RESIDENT ; ON RETURN, ZERO FLAG SET MEANS CPR-RESIDENT COMMAND ; CMDSER: LD HL,CMDTBL ;PT TO COMMAND TABLE ; ; ENTRY POINT TO PERMIT RCP TABLE TO BE SCANNED ; CMDSCAN: LD B,(HL) ;GET SIZE OF COMMAND TEXT INC HL ;PT TO FIRST COMMAND CMS1: LD A,(HL) ;CHECK FOR END OF TABLE OR A JR Z,CMS5 LD DE,FCBFN ;PT TO STORED COMMAND NAME PUSH BC ;SAVE SIZE OF COMMAND TEXT CMS2: LD A,(DE) ;COMPARE AGAINST TABLE ENTRY CP (HL) JR NZ,CMS3 ;NO MATCH INC DE ;PT TO NEXT CHAR INC HL DJNZ CMS2 ;COUNT DOWN LD A,(DE) ;NEXT CHAR IN INPUT COMMAND MUST BE CP ' ' JR NZ,CMS4 POP BC ;CLEAR STACK LD A,(HL) ;GET ADDRESS FROM TABLE INTO HL INC HL LD H,(HL) LD L,A ;HL CONTAINS ADDRESS XOR A ;ZERO FLAG SET FOR COMMAND FOUND RET ;COMMAND IS RESIDENT (ZERO FLAG SET) CMS3: INC HL ;SKIP TO NEXT COMMAND TABLE ENTRY DJNZ CMS3 CMS4: POP BC ;GET SIZE OF COMMAND TEXT INC HL ;SKIP ADDRESS INC HL JR CMS1 CMS5: XOR A ;SET NZ DEC A ;COMMAND NOT FOUND IF NZ RET ; ;**** Section 5 **** ; CPR-Resident Commands ; ; ;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 ENABLED ; DIR: LD DE,TFCB ;PT TO TARGET FCB PUSH DE ;SAVE PTR INC DE ;PT TO FILE NAME LD A,(DE) ;GET FIRST CHAR CP ' ' ;IF , MAKE ALL WILD JR NZ,DIR1 LD B,11 ;11 BYTES LD A,'?' ;WILD CALL FILL DIR1: POP DE ;GET PTR TO FCB LD DE,TFCB ;PT TO TARGET FCB CALL FCBLOG ;LOG IN TEMP DISK/USER LD A,(TFCB2+1) ;LOOK AT NEXT INPUT CHAR LD B,80H ;PREPARE FOR DIR-ONLY SELECTION CP ' ' JR Z,DIRPR ;THERE IS NO FLAG, SO DIR ONLY LD B,1 ;SET FOR BOTH DIR AND SYS FILES CP SYSFLG ;SYSTEM AND DIR FLAG SPECIFIER? JR Z,DIRPR ;GOT SYSTEM SPECIFIER CP SOFLG ;SYS ONLY? JR NZ,DIRPR DEC B ;B=0 FOR SYS FILES ONLY ;DROP INTO DIRPR TO PRINT DIRECTORY ; THEN RESTART CPR ; 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 ; DIRPR: LD A,B ;GET FLAG LD (SYSTST),A ;SET SYSTEM TEST FLAG LD E,0 ;SET COLUMN COUNTER TO ZERO PUSH DE ;SAVE COLUMN COUNTER (E) CALL SEARF ;SEARCH FOR SPECIFIED FILE (FIRST OCCURRENCE) JR NZ,DIR3 CALL PRNNF ;PRINT NO FILE MSG; REG A NOT CHANGED XOR A ;SET ZERO FLAG IN CASE CALLED BY ERA POP DE ;RESTORE DE RET ; ; ENTRY SELECTION LOOP; ON ENTRY, A=OFFSET FROM SEARF OR SEARN ; DIR3: CALL GETSBIT ;GET AND TEST FOR TYPE OF FILES JR Z,DIR6 POP DE ;GET ENTRY COUNT (= COUNTER) LD A,E ;GET ENTRY COUNTER INC E ;INCREMENT ENTRY COUNTER PUSH DE ;SAVE IT AND 03H ;OUTPUT IF 4 ENTRIES PRINTED IN LINE JR NZ,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 ; ELSE ; DB ' ' ;SPACE DB FENCE ;THEN FENCE CHAR DB ' '+80H ;THEN SPACE ; ENDIF ;WIDE ; DIR5: ; MVI B,01H ;PT TO 1ST BYTE OF FILE NAME ; MOV A,B ;A=OFFSET LD A,1 ;PT TO 1ST BYTE OF FILE NAME CALL DIRPTR ;HL NOW PTS TO 1ST BYTE OF FILE NAME CALL PRFN ;PRINT FILE NAME DIR6: CALL BREAK ;CHECK FOR ABORT JR Z,DIR7 CALL SEARN ;SEARCH FOR NEXT FILE JR NZ,DIR3 ;CONTINUE IF FILE FOUND DIR7: POP DE ;RESTORE STACK LD A,0FFH ;SET NZ FLAG OR A RET ; ENDIF ;DIRON OR ERAON ; ; PRINT FILE NAME PTED TO BY HL ; PRFN: LD B,8 ;8 CHARS CALL PRFN1 LD A,'.' ;DOT CALL CONOUT LD B,3 ;3 CHARS PRFN1: LD A,(HL) ; GET CHAR INC HL ; PT TO NEXT CALL CONOUT ; PRINT CHAR DEC B ; COUNT DOWN JR NZ,PRFN1 RET ; ; PT TO DIRECTORY ENTRY IN TBUFF WHOSE OFFSET IS SPECIFIED BY A AND C ; DIRPTR: LD HL,TBUFF ;PT TO TEMP BUFFER ADD A,C ;PT TO 1ST BYTE OF DIR ENTRY CALL ADDAH ;PT TO DESIRED BYTE IN DIR ENTRY LD A,(HL) ;GET DESIRED BYTE 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: DEC A ;ADJUST TO RETURNED VALUE RRCA ;CONVERT NUMBER TO OFFSET INTO TBUFF RRCA RRCA AND 60H LD C,A ;OFFSET INTO TBUFF IN C (C=OFFSET TO ENTRY) LD A,10 ;ADD 10 TO PT TO SYSTEM FILE ATTRIBUTE BIT CALL DIRPTR ;A=SYSTEM BYTE AND 80H ;LOOK AT ONLY SYSTEM BIT SYSTST EQU $+1 ;IN-THE-CODE VARIABLE XOR 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 ; ;Section 5B ;Command: ERA ;Function: Erase files ;Forms: ; ERA Erase Specified files and print their names ; ERA V Erase Specified files and print their names, but ask ; for verification before Erase is done ;Notes: ; Several Key Flags affect this command: ; ERAV - If TRUE, the V option is enabled, and the character ; which turns it on (the V) is defined by ERDFLG ; ERAOK - If TRUE, the OK? prompt is enabled ; If ERAOK is FALSE, the verification feature is disabled regardless ; of what value ERAV has ; If ERAOK is TRUE, then: ; If ERAV is TRUE, verification is requested only if the V ; flag (actual letter defined by ERDFLG) is in the ; command line ; If ERAV is FALSE, verification is always requested, and a ; V flag in the command line will cause an error ; message to be printed (V?) after the ERA is completed ; IF ERAON ;ERA ENABLED? ; ERA: ; IF WERA ;WHEEL FACILITY ENABLED? CALL WHLCHK ;CHECK FOR IT ENDIF ;WERA ; IF ERAV AND ERAOK ;V FLAG AND OK? ENABLED? LD A,(TFCB2+1) ;GET ERAFLG IF IT'S THERE LD (ERAFLG),A ;SAVE IT AS A FLAG ENDIF ;ERAV ; LD DE,TFCB ;PT TO TARGET FCB CALL FCBLOG ;LOG INTO DU IN FCB LD B,1 ;DISPLAY ALL MATCHING FILES CALL DIRPR ;PRINT DIRECTORY OF ERASED FILES RET Z ;ABORT IF NO FILES ; IF ERAOK ;PRINT PROMPT ; IF ERAV ;TEST VERIFY FLAG ; ERAFLG EQU $+1 ;ADDRESS OF FLAG LD A,0 ;2ND BYTE IS FLAG CP ERDFLG ;IS IT A VERIFY OPTION? JR NZ,ERA2 ;SKIP PROMPT IF IT IS NOT ; ENDIF ;ERAV ; CALL PRINTC DB 'OK to Erase','?'+80H CALL CONIN ;GET REPLY CP 'Y' ;YES? RET NZ ;ABORT IF NOT ; ENDIF ;ERAOK ; ERA2: LD DE,TFCB ;DELETE FILE SPECIFIED JP DELETE ;DELETE FILE AND REENTER CCP ; 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 AND TYPE ENABLED? ; LIST: LD 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: XOR A ;TURN OFF PRINTER FLAG ; ; ENTRY POINT FOR CPR LIST FUNCTION (LIST) ; TYPE0: LD (PRFLG),A ;SET FLAG ; IF WLT ;WHEEL ON? CALL WHLCHK ;CHECK WHEEL BYTE ENDIF ;WLT ; LD A,(TFCB2+1) ;GET PGDFLG IF IT'S THERE LD (PGFLG),A ;SAVE IT AS A FLAG LD DE,TFCB ;PT TO TARGET FILE FCB CALL AMBCHK ;CHECK FOR QUESTION MARKS IN TFCB RET Z ;ERROR IF ANY QUESTION MARKS CALL FCBLOG ;LOG INTO DU IN FCB LD DE,TFCB ;PT TO SELECT FILE CALL OPEN ;OPEN SELECTED FILE JP Z,PRNNF ;ABORT IF ERROR CALL CRLF ;NEW LINE LD A,NLINES-1 ;SET LINE COUNT LD (PAGCNT),A LD BC,080H ;SET CHAR POSITION AND TAB COUNT ; (B=0=TAB, C=080H=CHAR POSITION) ; ; MAIN LOOP FOR LOADING NEXT BLOCK ; TYPE2: LD A,C ;GET CHAR COUNT CP 80H JR C,TYPE3 PUSH HL ;READ NEXT BLOCK PUSH BC CALL READF POP BC POP HL RET NZ ;ERROR? LD C,0 ;SET CHAR COUNT LD HL,TBUFF ;PT TO FIRST CHAR ; ; MAIN LOOP FOR PRINTING CHARS IN TBUFF ; TYPE3: LD A,(HL) ;GET NEXT CHAR AND 7FH ;MASK OUT MSB CP 1AH ;END OF FILE (^Z)? RET Z ;RESTART CPR IF SO ; ; OUTPUT CHAR TO CON: OR LST: DEVICE WITH TABULATION ; CP CR ;RESET TAB COUNT? JR Z,TYPE4 CP LF ;RESET TAB COUNT? JR Z,TYPE4 CP TAB ;TAB? JR Z,TYPE5 ; ; OUTPUT CHAR AND INCREMENT CHAR COUNT ; CALL LCOUT ;OUTPUT CHAR INC B ;INCREMENT TAB COUNT JR TYPE6 ; ; OUTPUT OR AND RESET TAB COUNT ; TYPE4: CALL LCOUT ;OUTPUT OR LD B,0 ;RESET TAB COUNTER JR TYPE6 ; ; TABULATE ; TYPE5: LD A,' ' ; CALL LCOUT INC B ;INCR POS COUNT LD A,B AND 7 JR NZ,TYPE5 ; ; CONTINUE PROCESSING ; TYPE6: INC C ;INCREMENT CHAR COUNT INC HL ;PT TO NEXT CHAR CALL BREAK ;CHECK FOR ABORT RET Z ;RESTART IF SO JR TYPE2 ; ENDIF ;LTON ; ;Section 5E ;Command: SAVE ;Function: To save the contents of the TPA onto disk as a file ;Forms: ; SAVE ; Save specified number of pages (start at 100H) ; from TPA into specified file; is in DEC ; SAVE S ; Like SAVE above, but numeric argument specifies ; number of sectors rather than pages ;Notes: ; The MULTCMD flag (Multiple Commands Allowed) expands the code slightly, ; but is required to support multiple commands with SAVE ; The SECTFLG defines the letter which indicates a sector count ; (S in the Forms section above) ; IF SAVEON ;SAVE ENABLED? ; SAVE: ; IF WSAVE ;WHEEL FACILITY? CALL WHLCHK ;CHECK FOR WHEEL BYTE ENDIF ;WSAVE ; CALL NUMBER ;EXTRACT NUMBER FROM COMMAND LINE LD L,A ;HL=PAGE COUNT LD H,0 PUSH HL ;SAVE PAGE COUNT LD HL,TFCB2 ;COPY 2ND FCB INTO POSITION OF FIRST LD DE,TFCB PUSH DE ;SAVE PTR TO FCB LD B,14 ;14 BYTES CALL LDIR POP DE ;GET PTR TO FCB CALL AMBCHK ;CHECK FOR AMBIGUOUS POP HL RET Z ;ABORT IF SO PUSH HL CALL EXTEST ;TEST FOR EXISTENCE OF FILE AND ABORT IF SO LD C,16H ;BDOS MAKE FILE CALL GRBDOS POP HL ;GET PAGE COUNT JR Z,SAVE3 ;ERROR? LD DE,TPA-128 ;PT TO START OF SAVE AREA (TPA) ADD HL,HL ;DOUBLE 256-BYTE BLOCK COUNT FOR SECTOR COUNT EX DE,HL ;DE IS COUNT, HL IS NEXT BLOCK - 128 BYTES SAVE1: LD A,D ;DONE WITH SAVE? OR E ;DE=0 IF SO JR Z,SAVE2 DEC DE ;COUNT DOWN ON SECTORS PUSH DE ;SAVE PTR TO BLOCK TO SAVE LD DE,128 ;128 BYTES PER SECTOR ADD HL,DE ;PT TO NEXT SECTOR PUSH HL ;SAVE ON STACK EX DE,HL ;DE IS ADDRESS CALL DMASET ;SET DMA ADDRESS FOR WRITE (ADDRESS IN DE) LD DE,TFCB ;WRITE SECTOR LD C,15H ;BDOS WRITE SECTOR CALL BDOSB ;SAVE BC POP HL ;GET PTR TO NEXT SECTOR IN HL POP DE ;GET SECTOR COUNT IN DE JR NZ,SAVE3 ;WRITE ERROR? JR SAVE1 ;CONTINUE SAVE2: LD DE,TFCB ;CLOSE SAVED FILE CALL CLOSE INC A ;ERROR? JR NZ,SAVE4 SAVE3: CALL PRNLE ;PRINT 'NO SPACE' ERROR SAVE4: JP DEFDMA ;SET DMA TO 0080 AND RESTART CPR ; ENDIF ;SAVEON ; IF LTON OR SAVEON OR RENON ;FOR LIST/TYPE, SAVE, AND REN FCTS ; ; TEST FCB PTED TO BY DE TO SEE IF ANY ? CHARS IN IT ; RETURN WITH Z IF SO, NZ IF NOT; DON'T AFFECT DE ; AMBCHK: PUSH DE INC DE ;PT TO FIRST CHAR LD B,11 ;11 CHARS AMB1: LD A,(DE) ;GET CHAR CP '?' ;ERROR? JR Z,AMB2 INC DE ;PT TO NEXT DJNZ AMB1 DEC B ;SET NZ POP DE ;RESTORE PTR RET AMB2: CALL PRINT DB CR,LF,'AFN Erro','r'+80H XOR A ;SET ZERO FLAG POP DE ;RESTORE PTR RET ; ENDIF ;LTON OR SAVEON ; ; Test File in FCB for existence, ask user to delete if so, and abort if he ; choses not to ; IF SAVEON OR RENON ;FOR SAVE AND REN FUNCTIONS ; EXTEST: LD DE,TFCB ;PT TO FCB PUSH DE ;SAVE PTR CALL FCBLOG ;LOG INTO DU CALL SEARF ;LOOK FOR SPECIFIED FILE POP DE ;GET PTR TO FCB RET Z ;OK IF NOT FOUND PUSH DE ;SAVE PTR TO FCB CALL PRINTC DB 'Erase',' '+80H LD HL,TFCB+1 ;PT TO FILE NAME FIELD CALL PRFN ;PRINT IT LD A,'?' ;PRINT QUESTION CALL CONOUT CALL CONIN ;GET RESPONSE POP DE ;GET PTR TO FCB CP 'Y' ;KEY ON YES JP NZ,ERR3 ;RESTART AS ERROR IF NO PUSH DE ;SAVE PTR TO FCB CALL DELETE ;DELETE FILE POP DE ;GET PTR TO FCB RET ; ENDIF ;SAVEON OR RENON ; ;Section 5F ;Command: REN ;Function: To change the name of an existing file ;Forms: ; REN = Perform function ; IF RENON ;REN ENABLED? ; REN: ; IF WREN ;WHEEL FACILITY? CALL WHLCHK ;CHECK FOR WHEEL BYTE ENDIF ;WREN ; LD DE,TFCB ;CHECK FOR AMBIGUITY IN FIRST FILE NAME CALL AMBCHK RET Z LD DE,TFCB2 ;CHECK FOR AMBIGUITY IN SECOND FILE NAME CALL AMBCHK RET Z CALL EXTEST ;TEST FOR FILE EXISTENCE AND RETURN ; IF FILE DOESN'T EXIST; ABORT IF IT DOES LD B,16 ;EXCHANGE NEW AND OLD FILE NAMES LD HL,TFCB ;PT TO NEW LD DE,TFCB2 ;PT TO OLD REN0: LD A,(DE) ;GET OLD LD C,A LD A,(HL) ;GET NEW LD (DE),A ;PUT NEW LD (HL),C ;PUT OLD INC HL ;ADVANCE INC DE DJNZ REN0 ; ; PERFORM RENAME FUNCTION ; LD DE,TFCB ;RENAME FILE XOR A LD (DE),A ;SET CURRENT DISK LD C,17H ;BDOS RENAME FCT CALL GRBDOS RET NZ JP PRNNF ;PRINT NO FILE MSG ; ENDIF ;RENON ; ;Section 5G ;Command: JUMP ;Function: To Call the program (subroutine) at the specified address ; without loading from disk ;Forms: ; JUMP Call at ; is in HEX ; IF JUMPON ;JUMP ENABLED? ; JUMP: ; IF WJUMP ;WHEEL FACILITY? CALL WHLCHK ;CHECK FOR WHEEL BYTE ENDIF ;WJUMP ; CALL HEXNUM ;GET LOAD ADDRESS IN HL JR CALLPROG ;PERFORM CALL ; ENDIF ;JUMPON ; ;Section 5H ;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 ; IF GOON ;GO ENABLED? ; GO: ; IF WGO ;WHEEL FACILITY? CALL WHLCHK ;CHECK FOR WHEEL BYTE ENDIF ;WGO ; LD HL,TPA ;Always to TPA JR CALLPROG ;Perform call ; ENDIF ;GOON ; ;Section 5I ;Command: COM file processing ;Function: To load the specified COM file from disk and execute it ;Forms: ;Notes: ; COM files are processed as follows -- ; 1. File name buffers are initialized and a preliminary ; error check is done ; 2. MLOAD is used to search for the file along the Path ; and load it into the TPA ; 3. CALLPROG is used to set up the buffers to be used by ; the transient (FCB at 5CH, FCB at 6CH, BUFF at 80H) ; and run the program ; The flag MULTCMD comes into play frequently here; it mainly serves ; to save space if MULTCMD is FALSE and enables Multiple ; Commands on the same line if MULTCMD is TRUE ; COMDIR: IF DRVPREFIX ; LD A,(FCBFN) ;ANY COMMAND? CP ' ' ;' ' MEANS COMMAND WAS 'DIR:' TO SWITCH JR NZ,COM ;NOT , SO MUST BE TRANSIENT OR ERROR ; ; ENTRY POINT TO SELECT USER/DISK VIA DIR: PREFIX ; IF WDU ;WHEEL FACILITY? CALL WHLCHK ;CHECK FOR WHEEL BYTE ENDIF ;WDU ; LD A,(FCBDN+13) ;GET SELECTED USER CP 16 ;OUT OF RANGE? JP NC,ERROR LD DE,FCBDN ;PT TO FCB CALL FCBLOG ;LOG INTO DU LD A,(TEMPUSR) ;GET TEMPORARY USER LD (CURUSR),A ;SET CURRENT USER (MAKE PERMANENT) LD A,(TEMPDR) ;GET SELECTED DISK OR A ;IF 0 (DEFAULT), NO CHANGE JR Z,COMDR DEC A ;ADJUST FOR LOGIN LD (CURDR),A ;SET CURRENT DRIVE COMDR: CALL SETUD ;SET UD BYTE JP RS1 ;RESUME COMMAND LINE PROCESSING ; ENDIF ;DRVPREFIX ; ; PROCESS COMMAND ; COM: ; IF CMDRUN ;COMMAND RUN FACILITY AVAILABLE? LD A,0FFH ;USE IT IF AVAILABLE (MLOAD INPUT) ENDIF ;CMDRUN ; ; ; SET EXECUTION AND LOAD ADDRESS ; LD HL,TPA ;TRANSIENT PROGRAM AREA PUSH HL ;SAVE TPA ADDRESS FOR EXECUTION CALL MLOAD ;LOAD MEMORY WITH FILE SPECIFIED IN CMD LINE POP HL ;GET EXECUTION ADDRESS; FALL THRU TO CALLPROG ; ; 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: CALL CRLF ;LEADING NEW LINE CALLP: LD (EXECADR),HL ;PERFORM IN-LINE CODE MODIFICATION ; ; COPY COMMAND TAIL INTO TBUFF ; TAILSV EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION LD HL,0 ;ADDRESS OF FIRST CHAR OF COMMAND TAIL LD DE,TBUFF ;PT TO TBUFF PUSH DE ;SAVE PTR LD B,0 ;SET COUNTER INC DE ;PT TO FIRST CHAR TAIL: LD A,(HL) ;GET CHAR CALL TSTEOL ;CHECK FOR EOL JR Z,TAIL1 LD (DE),A ;PUT CHAR INC HL ;PT TO NEXT INC DE INC B ;INCREMENT COUNT JR TAIL TAIL1: XOR A ;STORE ENDING ZERO LD (DE),A POP HL ;GET PTR LD (HL),B ;SAVE COUNT ; ; RUN LOADED TRANSIENT PROGRAM ; CALL DEFDMA ;SET DMA TO 0080 ; ; EXECUTION (CALL) OF PROGRAM (SUBROUTINE) OCCURS HERE ; EXECADR EQU $+1 ;CHANGE ADDRESS FOR IN-LINE CODE MODIFICATION CALL TPA ;CALL TRANSIENT ; ; RETURN FROM EXECUTION ; CALL DEFDMA ;SET DMA TO 0080, IN CASE PROG CHANGED IT JP RS1 ;RESTART CPR AND CONTINUE COMMAND PROCESSING ; ;Section 5J ;Command: GET ;Function: To load the specified file from disk to the specified address ;Forms: ; GET Load the specified file at the specified page; ; is in HEX ; IF GETON ;GET ENABLED? ; GET: ; IF WGET ;WHEEL ON? CALL WHLCHK ;CHECK WHEEL BYTE ENDIF ;WGET ; LD HL,TFCB2 ;COPY TFCB2 TO FCBDN FOR LOAD LD DE,FCBDN LD B,14 ;14 BYTES (INCLUDES DU) CALL LDIR CALL HEXNUM ;GET LOAD ADDRESS IN HL ; ; FALL THRU TO MLOAD ; IF CMDRUN ;COMMAND RUN FACILITY AVAILABLE? XOR A ;NO CMDRUN IF FACILITY IS THERE (MLOAD INPUT) ENDIF ;CMDRUN ; ENDIF ;GETON ; ; MEMORY LOAD SUBROUTINE ; ; LOAD MEMORY WITH THE FILE WHOSE NAME IS SPECIFIED IN THE COMMAND LINE ; ON INPUT, HL CONTAINS STARTING ADDRESS TO LOAD ; ; EXIT POINTS ARE A RETURN AND LOG IN CURRENT USER/DISK IF NO ERROR, ; A JMP TO ERROR IF COM FILE NOT FOUND OR A MESSAGE AND ABORT IF MEMORY FULL ; MLOAD: ; IF CMDRUN ;CMDRUN FACILITY? LD (CRFLAG),A ;SAVE FLAG ENDIF ;CMDRUN ; LD (LOADADR),HL ;SET LOAD ADDRESS EX DE,HL ;LOAD ADDRESS IN DE CALL DMASET ;SET DMA ADDRESS ; ; MLA is a reentry point for a non-standard CP/M Modification ; The PATH command-search is implemented by this routine ; MLA: ; ; Set attributes of COM files which match search ; LD A,COMATT ;CUSTOMIZER-SPECIFIED ATTRIBUTES LD (SYSTST),A ;SET FLAG ; ; Analyze current path, generating a minimal, optimal absolute ; path equivalent in the buffer MPATH ; IF MINPATH ;IF MINIMUM PATH SEARCH EMPLOYED XOR A LD (MPATH),A ;SET EMPTY PATH ; IF DRVPREFIX ;PAY ATTENTION TO DU:COM PREFIX? ; ; Convert DU in FCBDN into absolute expression in MPATH ; LD DE,MPATH ;BUILD MPATH BUFFER LD HL,FCBDN ;HL PTS TO FCB, DE PTS TO MPATH LD A,(HL) ;GET DRIVE OR A ;SELECT CURRENT JR NZ,MLAMPD LD A,(CURDR) ;SET CURRENT DRIVE INC A ;ADJUST FOR PATH MLAMPD: LD (DE),A ;SET DRIVE INC DE ;PT TO USER LD BC,13 ;PT TO USER ADD HL,BC LD A,(HL) ;GET USER LD (DE),A ;SAVE USER INC DE ;PT TO NEXT XOR A ;A=0 LD (DE),A ;STORE ENDING 0 IN MPATH ENDIF ;DRVPREFIX ; IF SCANCUR ;SCAN CURRENT DU AT ALL TIMES? LD A,(CURDR) ;GET CURRENT DRIVE INC A ;ADD 1 FOR A=1 LD B,A LD A,(CURUSR) ;GET CURRENT USER LD C,A ;BC=DU LD HL,PATH ;PT TO FIRST PATH ELEMENT JR MPATHBC ;PLACE ENTRY INTO MPATH ENDIF ;SCANCUR ; ; Convert symbolic path at PATH into absolute path at MPATH ; LD HL,PATH ;PT TO SYMBOLIC PATH MPATH1: LD A,(HL) ;CHECK FOR END OF SYMBOLIC PATH OR A ;0=END OF PATH JR Z,MPATH7 ; ; Place absolute form for current path element in BC ; AND 7FH ;MASK OUT SYSTEM BIT CP CURIND ;CHECK FOR CURRENT DRIVE JR NZ,MPATH2 LD A,(CURDR) ;GET CURRENT DRIVE INC A ;ADJUST FOR A=1 MPATH2: LD B,A ;DRIVE IN B (1=A) INC HL ;PT TO USER LD A,(HL) ;GET USER INC HL ;PT TO NEXT ELEMENT AND 7FH ;MASK OUT SYSTEM BIT CP CURIND ;CHECK FOR CURRENT USER JR NZ,MPATH3 LD A,(CURUSR) ;GET CURRENT USER MPATH3: LD C,A ;SET USER IN C ; ; Scan MPATH for DU element in BC ; MPATHBC: PUSH HL ;SAVE PTR TO NEXT PATH ELEMENT LD HL,MPATH ;PT TO MINIMUM PATH MPATH4: LD A,(HL) ;CHECK FOR END OF PATH OR A JR Z,MPATH6 INC HL ;PT TO USER CP B ;CHECK FOR DISK MATCH JR NZ,MPATH5 LD A,(HL) ;GET USER CP C ;CHECK FOR USER MATCH JR NZ,MPATH5 POP HL ;MATCH, SO BC IS DUPLICATE JR MPATH1 ;CONTINUE MPATH5: INC HL ;PT TO NEXT ELEMENT JR MPATH4 ; ; No match, so BC is a unique DU and store it in path ; MPATH6: LD (HL),B ;STORE DRIVE INC HL LD (HL),C ;STORE USER INC HL LD (HL),0 ;STORE ENDING 0 POP HL ;PT TO NEXT ENTRY JR MPATH1 ;CONTINUE ; ; MPATH now contains the minimal path ; MPATH7: ; ENDIF ;MINPATH ; ; Non-MINPATH Processing: ; If DRVPREFIX or SCANCUR are TRUE, look in DU in FCBDN ; IF [NOT MINPATH] AND [DRVPREFIX OR SCANCUR] LD DE,FCBDN ;LOOK FOR FILE CALL FCBLOG ;LOG INTO FCB CALL SEAR1 JP NZ,MLA4 ENDIF ;(NOT MINPATH) AND (DRVPREFIX OR SCANCUR) ; ; Select current disk at all times ; XOR A LD (FCBDN),A ;SET CURRENT DISK MLARUN: ; ; The following selects the path to be followed; if the Minimal Path is ; available, it is followed; else, the Symbolic Path is followed ; IF MINPATH ;IF MINIMAL PATH USED LD HL,MPATH ;PT TO MINIMAL PATH ELSE ;NOT MINPATH LD HL,PATH ;PT TO SYMBOLIC PATH ENDIF ;MINPATH ; ; This is the main path search loop; HL pts to the next path element ; MLA0: LD A,(HL) ;GET DRIVE OR A ;0=DONE=COMMAND NOT FOUND ; IF NOT CMDRUN ;ERROR ABORT IF NO COMMAND RUN FACILITY JP Z,ERROR ;PATH EXHAUSTED ; ELSE ;CONTINUE PROCESSING FOR COMMAND RUN ; ; CMDRUN Facility ; JR NZ,NOCRUN ;NOT READY FOR CMD RUN YET CRFLAG EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION LD A,0 ;CHECK CRFLAG OR A ;0=NO JP Z,ERROR ;PROCESS AS ERROR IF CMD RUN EXHAUSTED ; IF ROOTONLY ;ONLY LOOK FOR EXT COMMAND PROCESSOR AT ROOT PUSH HL ;SAVE PTR TO PATH END ENDIF ;ROOTONLY ; XOR A ;DO NOT REENTER THIS CODE LD (CRFLAG),A ;SET ZERO FOR NO ENTRY LD HL,CFCB ;SET CFCB AS COMMAND LD DE,FCBDN ;... BY COPYING IT INTO FCBDN LD B,12 ;ONLY 12 BYTES REQUIRED CALL LDIR LD HL,(CURCMD) ;GET PTR TO CURRENT COMMAND LINE CALL PARSET ;PARSE AS COMMAND TAIL ; IF ROOTONLY ;LOOK FOR EXT COMMAND PROCESSOR AT ROOT ONLY? JR MLA3RT ;PROCESS FROM PATH END ELSE ;FOLLOW PATH LOOKING FOR EXT COMMAND PROCESSOR ; JR MLARUN ;NOW TRY THE RUN FROM THE PATH ; ENDIF ;ROOTONLY ; CFCB: CMDFCB ;FCB DEFINING INITIAL COMMAND NOCRUN: ENDIF ;CMDRUN ; ; LOOK FOR COMMAND IN DIRECTORY PTED TO BY HL; DRIVE IN A ; IF NOT MINPATH CP CURIND ;CURRENT DRIVE SPECIFIED? JR NZ,MLA1 ;SKIP DEFAULT DRIVE SELECTION IF SO LD A,(CURDR) ;GET CURRENT DRIVE INC A ;SET A=1 ENDIF ;NOT MINPATH ; MLA1: LD (TEMPDR),A ;SELECT DIFFERENT DRIVE IF NOT CURRENT INC HL ;PT TO USER NUMBER LD A,(HL) ;GET USER NUMBER INC HL ;PT TO NEXT ENTRY IN PATH PUSH HL ;SAVE PTR ; IF NOT MINPATH AND 7FH ;MASK OUT SYSTEM BIT CP CURIND ;CURRENT USER SPECIFIED? JR NZ,MLA2 ;DO NOT SELECT CURRENT USER IF SO LD A,(CURUSR) ;GET CURRENT USER NUMBER MLA2: ENDIF ;NOT MINPATH ; LD (TEMPUSR),A ;SET TEMPORARY USER NUMBER CPL ;FLIP BITS SO SYSTEM BIT IS 0 IF SYS-ONLY AND 80H ;MASK FOR ONLY NOT OF SYSTEM BIT TO SHOW JR NZ,MLA3 ;DON'T SET FLAG IF ORIGINALLY SYSTEM BIT=0 LD (SYSTST),A ;TEST FLAG IS 0 FOR SYS-ONLY, 1 FOR BOTH MLA3: CALL SLOGIN ;LOG IN PATH-SPECIFIED USER/DISK MLA3RT: LD DE,FCBDN ;PT TO FCB CALL SEAR1 ;LOOK FOR FILE POP HL ;GET PTR TO NEXT PATH ENTRY JR Z,MLA0 ;CONTINUE PATH SEARCH IF SEARCH FAILED ;LOAD IF SEARCH SUCCEEDED ; ; FILE FOUND -- PERFORM SYSTEM TEST AND PROCEED IF APPROVED ; MLA4: PUSH HL ;SAVE PTR CALL GETSBIT ;CHECK SYSTEM BIT POP HL ;GET PTR JR Z,MLA0 ;CONTINUE IF NO MATCH CALL OPENF ;OPEN FILE FOR INPUT LOADADR EQU $+1 ;MEMORY LOAD ADDRESS (IN-LINE CODE MOD) LD HL,TPA ;SET START ADDRESS OF MEMORY LOAD MLA5: LD A,ENTRY/256-1 ;GET HIGH-ORDER ADR OF JUST BELOW CPR CP H ;ARE WE GOING TO OVERWRITE THE CPR? JR C,PRNLE ;ERROR IF SO PUSH HL ;SAVE ADDRESS OF NEXT SECTOR EX DE,HL ;... IN DE CALL DMASET ;SET DMA ADDRESS FOR LOAD LD DE,FCBDN ;READ NEXT SECTOR CALL READ POP HL ;GET ADDRESS OF NEXT SECTOR JR NZ,MLA6 ;READ ERROR OR EOF? LD DE,128 ;MOVE 128 BYTES PER SECTOR ADD HL,DE ;PT TO NEXT SECTOR IN HL JR MLA5 ; MLA6: DEC A ;LOAD COMPLETE JR NZ,PRNLE ;MEMORY FULL IF NZ ; ; RETURN TO CURRENT DIRECTORY ; DLOGIN: CURDR EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION LD A,0 ;PREP TO LOG IN CURRENT DRIVE CALL LOGIN ;LOGIN CURRENT DRIVE CURUSR EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION LD A,0 ;PREP TO LOG IN CURRENT USER NUMBER JP SETUSR ;LOG IN NEW USER ; ; LOAD ERROR ; PRNLE: CALL PRINTC DB 'Ful','l'+80H JP RESTRT ;RESTART ZCPR ;***** ; ; DEFAULT PATH USED FOR PATH COMMAND-SEARCH ; IF EXPATH EQ 0 ;USE THIS PATH? ; PATH: IPATH ;PATH DEFINED IN Z3HDR.LIB ; ENDIF ;INTPATH ; ;***** ; ; INTERNAL MINIMUM PATH ; IF MINPATH MPATH: DS EXPATHS+3 ;SIZE OF PATH, MAX ; (+2 FOR DU:COM PREFIX, +1 FOR ENDING 0) ENDIF ;MINPATH ;***** IF EXTSTK NE 0 ;EXTERNAL STACK STACK EQU EXTSTK+48 ;SET TOP-OF-STACK ADDRESS ELSE ; ; STACK AREA ; DS 48 ;STACK AREA STACK EQU $ ;TOP OF STACK ; ENDIF ;INTSTACK ; IF PWCHECK PWLIN EQU STACK-48 ;PLACE LINE AT BOTTOM OF STACK ENDIF ;PWCHECK ; ; The following will cause an error message to appear if ; the size of ZCPR3 is over 2K bytes. ; IF [$ GT CPRLOC+800H] ZCPR3ER EQU NOVALUE ;ZCPR3 IS LARGER THAN 2K BYTES ENDIF END