TITLE 'NZCPR V 1.6 OF 08/03/82' ; ; CP/M Z80 Command Processor Replacement (CPR) Version 1.6 in ; the NZCPR line. ; ; CCPZ CREATED AND CUSTOMIZED FOR ARIES-II BY RLC ; ZCPR VERSION 1.0 CREATED FROM CCPZ VERSION 4.0 BY RLC IN ; A COORDINATED EFFORT WITH CCP-GROUP ; ; ZCPR is a group effort by CCP-GROUP, whose active membership involved ; in this project consists of the following: ; RLC - Richard Conn ; RGF - Ron Fowler ; KBP - Keith Peterson ; FJW - Frank Wancho ; The following individuals also provided a contribution: ; SBB - Steve Bogolub ; ; Since RLC has decided that ZCPR V1.0 is the last official version ; sanctioned by the CCPZ group, changes beyond that point are being ; called by consensus of a group of new changers "NZCPR Vx.x". The ; following individuals have put in their code or opinions: ; ; SBB - Steve Bogolub ; PST - Paul Traina ; HLB - Howard Booker ; CAF - Chuck Forsberg ; RAF - Bob Fischer ; BB - Ben Bronson ; PRG - Paul Grupp ; PJH - Paul Homchick ; HEW - Hal Walchli ; ; In an attempt to maintain a link to the past, changes between the ; current version of NZCPR are provided as both a difference file ; between NZCPR's (NZ14-16.DIF) and as a difference between the current ; version and the "official" ZCPR V1.0 (NZCPR-16.DIF). These changes ; are made and supported by individuals in contact with each other through ; the Hyde Park RCPM in Chicago. Make comments or complaints there, to ; SBB or PST or anyone else interested. ; ; The most obvious differences between NZCPR and ZCPR are the security ; features, controlled by additional conditional assembly flags. Such ; features restrict access to ZCPR intrinsic commands, add additional ; levels of .COM file searching, and prevent access to higher drives ; or user levels, with either internal or external password control of ; these features. Less obvious differences involve code optimization to ; gain space, and some minor bug fixes in the TYPE command. ; ;******** Structure Notes ******** ; ; This CPR is divided into a number of major sections. The following ; is an outline of these sections and the names of the major routines ; located therein. ; ; Section Function/Routines ; ------- ----------------- ; ; -- Opening Comments, Equates, and Macro Definitions ; ; 0 JMP Table into CPR ; ; 1 Buffers ; ; 2 CPR Starting Modules ; CPR1 CPR RESTRT RSTCPR RCPRNL ; PRNNF CMDTBL ; ; 3 Utilities ; CRLF CONOUT CONIN LCOUT LSTOUT ; READF READ BDOSB PRINTC PRINT ; GETDRV DEFDMA DMASET RESET BDOSJP ; LOGIN OPENF OPEN GRBDOS CLOSE ; SEARF SEAR1 SEARN SUBKIL DELETE ; RESETUSR GETUSR SETUSR PAGER UCASE ; NOECHO ; ; 4 CPR Utilities ; SETUD SETU0D REDBUF CNVBUF CMDSER ; BREAK USRNUM ERROR SDELM ADVAN ; SBLANK ADDAH NUMBER NUMERR HEXNUM ; DIRPTR SLOGIN DLOGIN COMLOG SCANER ; ; 5 CPR-Resident Commands and Functions ; 5A DIR DIRPR FILLQ ; 5B ERA ; 5C LIST ; 5D TYPE ; 5E SAVE ; 5F REN ; 5G USER ; 5H DFU ; 5I JUMP ; 5J GO ; 5K COM CALLPROG ERRLOG ERRJMP ; 5L GET MEMLOAD PRNLE ; 5M PASS NORM ; ; FALSE EQU 0 TRUE EQU NOT FALSE ; ; CUSTOMIZATION EQUATES ; ; The following equates may be used to customize this CPR for the user's ; system and integration technique. The following constants are provided: ; ; REL - TRUE if integration is to be done via MOVCPM ; - FALSE if integration is to be done via DDT and SYSGEN ; ; SECURE - TRUE to conditionally disable potentially-harmful ; commands (GO, ERA, SAVE, REN, DFU, GET, JUMP). Under ; SECURE, if WHEEL contains RESTRCT, do not accept those ; commands, and search for COM files under current user ; then user "DEFUSR" only. If WHEEL does not contain ; RESTRCT (presumably from passworded change), allow ; all commands, and search current user, then last user ; set by DFU (originally "RESUSR"), then user "DEFUSR" ; for COM files, giving access with password to an ; additional level of COM files. ; ; (Note: WHEEL must point to a safe place in memory that ; won't be overlayed) ; ; If you have chosen a SECURE system, all resident commands may be ; activated by entering: PASS Where is a sequence ; of characters placed at PASSID (if INPASS is true, otherwise, see ; documentation in PST's PASS.ASM). If the password is incorrect. the system ; will come back with PASS? as if it was looking for a COM file. ; NORM is the reverse of PASS, it will disable the WHEEL mode. ; ; INPASS - If in the SECURE mode, you wish to use a program similar ; to PST's PASS.ASM, set this false, otherwise, ZCPR will ; handle the PASSword coding with a built in command. ; ; DRUSER - Set this EQU false if you wish to disable RAF's neat hack ; that allows you the type B: 7 to move to drive B: user area ; seven. This also removes the USER command. Basically, set ; this equate false if you want to use USERPW or some other pgm. ; ; RAS - Remote-Access System; setting this equate to TRUE disables ; certain CPR commands that are considered harmful in a Remote- ; Access environment; use under Remote-Access Systems (RBBS) for ; security purposes. Note: SECURE is the direct enemy of RAS, ; DON'T define both equates or you will be VERY sorry. ; The advantage SECURE has over RAS is that by saying a magic ; word, all of the normal commands pop into existance. ; ; MAXDRIV - Maximum legal drive number stored in this location. ; (0 means only A:, etc.) 0000H disables this feature. ; The value MAXDR is stuffed into MAXDRIV at cold boot, ; and presumably will be changed later by a passworded ; program if desired. ; ; (This code is in addition to BIOS checks. It's needed here ; because X: can hang if X: is off line in some BIOS ; implementations. Personally, I think CAF and others should fix ; their BIOS instead. Mine works right...SBB). ; ; USRMAX - Maximum legal user # + 1 stored in this location. 0000H ; disables this feature, and uses the value of MAXUSR+1 instead. ; ; BASE - Base Address of user's CP/M system (normally 0 for DR version) ; This equate allows easy modification by non-standard CP/M (eg,H89) ; ; CPRLOC - Base Page Address of CPR; this value can be obtained by running ; the BDOSLOC program on your system, or by setting the ; MSIZE and BIOSEX equates to the system memory size in ; K-bytes and the "extra" memory required by your BIOS ; in K-bytes. BIOSEX is zero if your BIOS is normal size, ; and can be negative if your BIOS is in PROM or in ; non-contiguous memory. ; ; EPRMPT - Set TRUE to be prompted "OK?" after seeing what files will ; be erased. No, this is NOT for individual file prompting, ; it is just to confirm deletion of all selected files at once. ; ; Various individuals keep trying to yank out the TYPE, LIST, and DIR ; commands, either to use the space for other options or just because ; they prefer replacement COM files. To these individuals, I (SBB) say ; keep your paws off these commands. For compatibility with the stock ; CCP, intrinsic DIR and TYPE commands are required. And many users in ; MY neighborhood find it more convenient to use the intrinsic LIST ; command than to have a LIST/PRINT program on every disk. If you want ; to call a transient program by an intrinsic, then CHANGE THE INTRINSIC ; NAME IN THE TABLE. Even setting the name to blanks is fine to get ; rid of it. The point is, don't remove features others may want, just ; because you disagree, then throw it back in our laps. For those who ; simply MUST be rid of these commands, the following symbols control ; generation of the code in a CLEAN ACCEPTABLE fashion that allows ; others to have these features: ; ; CPRTYP - Set to TRUE to generate code for intrinsic TYPE command. ; ; WSTYPE - Set to TRUE to generate an extra three lines of code ; to correctly interpret the WordStar (tm) internal ; end of line hyphen for display, which is the ASCII ; NEWLINE code (1FH) and normally non-printing or ; troublemaking -- thanks to PJH for this one. CPRTYP ; must be TRUE, or this symbol will be ignored. ; ; CPRLST - Set to TRUE to generate code for intrinsic LIST command. ; Since almost all of the LIST code is common to the ; TYPE code, CPRTYP must be set TRUE as well, or this ; symbol will be ignored. ; ; CPRDIR - Set to TRUE to generate code for intrinsic DIR command. ; Note that unlike the various directory programs, a ; restricted DIR command here allows displaying the names ; of SYS file ONLY, so many RCPM operators WANT this code. ; ; Remember, you only get a total of 2048 (0800H) bytes of space for ; ALL of the generated code, or many other areas of your system ; generation will be affected. For example, to be fully SECURE, you ; would set SECURE to TRUE, and define MAXDRIV and USRMAX, and maybe ; use the internal password by setting INPASS to TRUE (external is ; MUCH recommended for easier modification). Those options absolutely ; generate too much code unless either CPRTYP or CPRDIR or both are ; set FALSE. A system with SECURE set to FALSE is right on the edge, ; and requires a give and take on options to fit, i.e. you can have ; MAXDRIV and USRMAX with DIR and TYPE if you leave out LIST and ; querying on ERASE, and so on. ; *************************************************************************** ** Be careful when playing with different combinations of these equates. ** ** You might not have enough memory to some combinations. Check this ** ** if you have problems, if they still persist, gripe to me (PST). ** *************************************************************************** ; REL EQU FALSE ;SET TO TRUE FOR MOVCPM INTEGRATION ; BASE EQU 0 ;BASE OF CP/M SYSTEM (SET FOR STANDARD CP/M) ; IF REL CPRLOC EQU 0 ;MOVCPM IMAGE ELSE ; ; If REL is FALSE, the value of CPRLOC may be set in one ; of two ways. The first way is to set MSIZE and BIOSEX ; as described above using the following three lines: ; MSIZE EQU 56 ;SIZE OF MEM IN K-BYTES BIOSEX EQU 2 ;EXTRA # K-BYTES IN BIOS CPRLOC EQU 3400H+(MSIZE-20-BIOSEX)*1024 ;CPR ORIGIN ; ; The second way is to obtain the origin of your current ; CPR using BDSLOC or its equivalent, then merely set CPRLOC ; to that value as in the following line: ; ;CPRLOC EQU 0DA00H ;FILL IN WITH BDOSLOC SUPPLIED VALUE ; ; Note that you should only use one method or the other. ; Do NOT define CPRLOC twice! ; ; The following gives the required offset to load the CPR into the ; CP/M SYSGEN Image through DDT (the Roffset command); Note that this ; value conforms with the standard value presented in the CP/M reference ; manuals, but it may not necessarily conform with the location of the ; CCP in YOUR CP/M system; several systems (Morrow Designs, P&T, Heath ; Org-0 to name a few) have the CCP located at a non-standard address in ; the SYSGEN Image ; ;CPRR EQU 0E00H-CPRLOC ;DDT LOAD OFFSET FOR APPLE SOFTCARD 56K CPRR EQU 0980H-CPRLOC ;DDT LOAD OFFSET ;CPRR EQU 1600H-CPRLOC ;DDT LOAD OFFSET FOR COMPUPRO DISK-1 ;CPRR EQU 1100H-CPRLOC ;DDT LOAD OFFSET FOR MORROW DESIGNS ENDIF ; RAS EQU FALSE ;SET TO TRUE IF CPR IS FOR A REMOTE-ACCESS SYSTEM ;AND YOU DON'T WANT TO RUN SECURE (FOO...) ; USRMAX EQU 0000H ;LOCATION OF BYTE IN MEMORY CONTAINING ; NUMBER OF HIGHEST ALLOWABLE USER CODE + 1 ; THIS VALUE IS SET BY CPR ON COLD BOOT, ; AND PRESUMABLY CONTROLLED AFTER THAT ; BY A PASSWORD PROGRAM. IF USRMAX=0, THEN ; MAXUSR BELOW IS USED FOR CHECKING ONLY. ; 03FH IS RECOMMENDED IF USED *** MAXUSR EQU 15 ;MAX ALLOWED USER NUMBER, THIS + 1 IS STUFFED ; INTO USRMAX ON COLD BOOT, OR USED DIRECTLY ; IF USRMAX=0 ; MAXDRIV EQU 0000H ;LOCATION THAT HAS MAX LEGAL DRIVE # ;SET IT TO ZERO TO DISABLE THIS CHECK ;03DH IS RECOMMENDED IF USED *** MAXDR EQU 1 ;MAX DRIVE # TO SET INTO MAXDRIV ON COLD BOOT ; SECURE EQU FALSE ;SET TRUE FOR SECURE ENVIRONMENT... ; DEFUSR EQU 0 ;DEFAULT USER FOR UNRESTRICTED COM FILES ; IF SECURE WHEEL EQU 3EH ;SET TO "RESTRCT" FOR LIMITED ACCESS RESTRCT EQU 0 ;WHEN (WHEEL)==RESTRCT, LIMIT COMMANDS RESUSR EQU 15 ;CHECK HERE FOR RESTRICTED ACCESS COM FILES (LIKE PIP) ; UNTIL CHANGED BY DFU OR WARM BOOT ENDIF ;SECURE ; INPASS EQU FALSE ;SET TRUE IF RUNNING SECURE AND NOT PASS.COM ; DRUSER EQU TRUE ;TRUE TO ALLOW USER COMMAND AND DRIVE/USER HACK ; EPRMPT EQU FALSE ;TRUE TO PROMPT BEFORE ERASING ALL FILES ; CPRTYP EQU TRUE ;TRUE TO GENERATE TYPE CODE WSTYPE EQU TRUE ;TRUE TO GENERATE WORDSTAR HYPHEN CHECK (CPRTYP ; MUST BE TRUE TOO) CPRLST EQU TRUE ;TRUE TO GENERATE LIST CODE (CPRTYP MUST BE TRUE TOO) CPRDIR EQU TRUE ;TRUE TO GENERATE DIR CODE ; ; *** Note to Apple Softcard Users *** ; ; In their infinite (?) wisdom (???), Microsoft decided that the way to ; get a two-column directory display instead of four-column (narrow 40-col ; screen, remember) was to have their BIOS poke CCP every time it was ; loaded, if there was no terminal interface card in I/O slot 3. ; Naturally, that will turn into a random poke on any non-standard ; CCP, like this one. The best way to get this CPR up on the Apple is to ; load it into CPM56.COM, at location 0E00H in the image. The BIOS code ; that pokes the CPR can also be modified at that time. The poke is done ; by "STA 0C8B2H", found at 24FEH in the CPM56 image. To keep this ; feature, change the 0C8B2H address in that instruction by hand to ; the value generated for the symbol TWOPOK in the DIR routine. If ; you have assembled out the DIR code by setting CPRDIR to FALSE, then ; disable this feature by changing the "STA" to "LDA", i.e. set the ; contents of location 24FEH from 32H to 3AH. If you wish to force ; a two-column display in all cases, set the TWOCOL switch below to a ; value of TRUE, and disable the poke. ; TWOCOL EQU FALSE ;TRUE IF TWO COL DIR INSTEAD OF FOUR ; ; The following is presented as an option, but is not generally user-customiz- ; able. A basic design choice had to be made in the design of ZCPR concerning ; the execution of SUBMIT files. The original CCP had a problem in this sense ; in that it ALWAYS looked for the SUBMIT file from drive A: and the SUBMIT ; program itself (SUBMIT.COM) would place the $$$.SUB file on the currently ; logged-in drive, so when the user was logged into B: and he issued a SUBMIT ; command, the $$$.SUB was placed on B: and did not execute because the CCP ; looked for it on A: and never found it. ; ; After much debate it was decided to have ZCPR perform the same type of ; function as CCP (look for the $$$.SUB file on A:), but the problem with ; SUBMIT.COM still exists. Hence, RGF designed SuperSUB and RLC took his ; SuperSUB and designed SUB from it; both programs are set up to allow the ; selection at assembly time of creating the $$$.SUB on the logged-in drive ; or on drive A:. ; ; A final definition of the Indirect Command File ($$$.SUB or SUBMIT ; File) is presented as follows: ; ; "An Indirect Command File is one which contains ; a series of commands exactly as they would be ; entered from a CP/M Console. The SUBMIT Command ; (or SUB Command) reads this files and transforms ; it for processing by the ZCPR (the $$$.SUB File). ; ZCPR will then execute the commands indicated ; EXACTLY as if they were typed at the Console." ; ; Hence, to permit this to happen, the $$$.SUB file must always ; be present on a specific drive, and A: is the choice for said drive. ; With this facility engaged as such, Indirect Command Files like: ; ; DIR ; A: ; DIR ; ; can be executed, even though the currently logged-in drive is changed ; during execution. If the $$$.SUB file was present on the currently ; logged-in drive, the above series of commands would not work since the ; ZCPR would be looking for $$$.SUB on the logged-in drive, and switching ; logged-in drives without moving the $$$.SUB file as well would cause ; processing to abort. ; SUBA EQU TRUE ; Set to TRUE to have $$$.SUB always on A: ; Set to FALSE to have $$$.SUB on the logged-in drive ; ; The following flag enables extended processing for user-program supplied ; command lines. This is for Command Level 3 of ZCPR. Under the current ; ZCPR philosophy, three command levels exist: ; ; (1) that command issued by the user from his console at the '>' prompt ; (2) that command issued by a $$$.SUB file at the '$' prompt ; (3) that command issued by a user program by placing the command into ; CIBUFF and setting the character count in CBUFF ; ; Setting CLEVEL3 to TRUE enables extended processing of the third level of ; ZCPR command. All the user program need do is to store the command line and ; set the character count; ZCPR will initialize the pointers properly, store ; the ending zero properly, and capitalize the command line for processing. ; Once the command line is properly stored, the user executes the command line ; by reentering the ZCPR through CPRLOC [NOTE: The C register MUST contain ; a valid User/Disk Flag (see location 4) at this time.] ; CLEVEL3 EQU TRUE ;ENABLE COMMAND LEVEL 3 PROCESSING ; ; ;*** TERMINAL AND 'TYPE' CUSTOMIZATION EQUATES ; NLINES EQU 24 ;NUMBER OF LINES ON CRT SCREEN WIDE EQU TRUE ;TRUE IF WIDE DIR DISPLAY FENCE EQU '|' ;SEP CHAR BETWEEN DIR FILES ; PGDFLT EQU TRUE ;SET TO FALSE TO DISABLE PAGING BY DEFAULT PGDFLG EQU 'P' ;FOR TYPE COMMAND: PAGE OR NOT (DEP ON PGDFLT) ; THIS FLAG REVERSES THE DEFAULT EFFECT ; SYSFLG EQU 'A' ;FOR DIR COMMAND: LIST $SYS AND $DIR ; SOFLG EQU 'S' ;FOR DIR COMMAND: LIST $SYS FILES ONLY ; SUPRES EQU TRUE ;SUPRESSES USER # REPORT FOR USER 0 ; SPRMPT EQU '$' ;CPR PROMPT INDICATING SUBMIT COMMAND CPRMPT EQU '>' ;CPR PROMPT INDICATING USER COMMAND ; NUMBASE EQU 'H' ;CHARACTER USED TO SWITCH FROM DEFAULT ; NUMBER BASE ; SECTFLG EQU 'S' ;OPTION CHAR FOR SAVE COMMAND TO SAVE SECTORS ; ; END OF CUSTOMIZATION SECTION ; CR EQU 0DH LF EQU 0AH TAB EQU 09H FFEED EQU 0CH BEL EQU 07H ; WBOOT EQU BASE+0000H ;CP/M WARM BOOT ADDRESS UDFLAG EQU BASE+0004H ;USER NUM IN HIGH NYBBLE, DISK IN LOW BDOS EQU BASE+0005H ;BDOS FUNCTION CALL ENTRY PT TFCB EQU BASE+005CH ;DEFAULT FCB BUFFER TBUFF EQU BASE+0080H ;DEFAULT DISK I/O BUFFER TPA EQU BASE+0100H ;BASE OF TPA ; ; ; MACROS TO PROVIDE Z80 EXTENSIONS ; MACROS INCLUDE: ; $-MACRO ;FIRST TURN OFF THE EXPANSIONS ; ; JR - JUMP RELATIVE ; JRC - JUMP RELATIVE IF CARRY ; JRNC - JUMP RELATIVE IF NO CARRY ; JRZ - JUMP RELATIVE IF ZERO ; JRNZ - JUMP RELATIVE IF NO ZERO ; DJNZ - DECREMENT B AND JUMP RELATIVE IF NO ZERO ; LDIR - MOV @HL TO @DE FOR COUNT IN BC ; LXXD - LOAD DOUBLE REG DIRECT ; SXXD - STORE DOUBLE REG DIRECT ; ; ; ; @GENDD MACRO USED FOR CHECKING AND GENERATING ; 8-BIT JUMP RELATIVE DISPLACEMENTS ; @GENDD MACRO ?DD ;;USED FOR CHECKING RANGE OF 8-BIT DISPLACEMENTS IF (?DD GT 7FH) AND (?DD LT 0FF80H) DB 100H ;Displacement Range Error on Jump Relative ELSE DB ?DD ENDIF ENDM ; ; ; Z80 MACRO EXTENSIONS ; JR MACRO ?N ;;JUMP RELATIVE DB 18H @GENDD ?N-$-1 ENDM ; JRC MACRO ?N ;;JUMP RELATIVE ON CARRY DB 38H @GENDD ?N-$-1 ENDM ; JRNC MACRO ?N ;;JUMP RELATIVE ON NO CARRY DB 30H @GENDD ?N-$-1 ENDM ; JRZ MACRO ?N ;;JUMP RELATIVE ON ZERO DB 28H @GENDD ?N-$-1 ENDM ; JRNZ MACRO ?N ;;JUMP RELATIVE ON NO ZERO DB 20H @GENDD ?N-$-1 ENDM ; DJNZ MACRO ?N ;;DECREMENT B AND JUMP RELATIVE ON NO ZERO DB 10H @GENDD ?N-$-1 ENDM ; LDIR MACRO ;;LDIR DB 0EDH,0B0H ENDM ; LDED MACRO ?N ;;LOAD DE DIRECT DB 0EDH,05BH DW ?N ENDM ; LBCD MACRO ?N ;;LOAD BC DIRECT DB 0EDH,4BH DW ?N ENDM ; SDED MACRO ?N ;;STORE DE DIRECT DB 0EDH,53H DW ?N ENDM ; SBCD MACRO ?N ;;STORE BC DIRECT DB 0EDH,43H DW ?N ENDM ; ; END OF Z80 MACRO EXTENSIONS ; ; ;**** Section 0 **** ; ORG CPRLOC ; ; ENTRY POINTS INTO ZCPR ; ; If the ZCPR is entered at location CPRLOC (at the JMP to CPR), then ; the default command in CIBUFF will be processed. If the ZCPR is entered ; at location CPRLOC+3 (at the JMP to CPR1), then the default command in ; CIBUFF will NOT be processed. ; ; NOTE: Entry into ZCPR in this way is permitted under this version, ; but in order for this to work, CIBUFF and CBUFF MUST be initialized properly ; AND the C register MUST contain a valid User/Disk Flag (see Location 4: the ; most significant nybble contains the User Number and the least significant ; nybble contains the Disk Number). ; ; Some user programs (such as SYNONYM3) attempt to use the default ; command facility. Under the original CCP, it was necessary to initialize ; the pointer after the reserved space for the command buffer to point to ; the first byte of the command buffer. Under current versions, this is ; no longer the case. The CIBPTR (Command Input Buffer PoinTeR) is located ; to be compatible with such programs (provided they determine the buffer ; length from the byte at MBUFF [CPRLOC + 6]), but under ZCPR this is ; no longer necessary, since this buffer pointer is automatically ; initialized in all cases. ; ENTRY: JMP CPR ; Process potential default command, and set ; USRMAX to MAXUSR default JMP CPR1 ; Do NOT process potential default command ; ;**** Section 1 **** ; BUFFERS ET AL ; ; INPUT COMMAND LINE AND DEFAULT COMMAND ; ; The command line to be executed is stored here. This command line ; is generated in one of three ways: ; ; (1) by the user entering it through the BDOS READLN function at ; the du> prompt [user input from keyboard] ; (2) by the SUBMIT File Facility placing it there from a $$$.SUB ; file ; (3) by an external program or user placing the required command ; into this buffer ; ; In all cases, the command line is placed into the buffer starting at ; CIBUFF. This command line is terminated by the last character (NOT Carriage ; Return), and a character count of all characters in the command line ; up to and including the last character is placed into location CBUFF ; (immediately before the command line at CIBUFF). The placed command line ; is then parsed, interpreted, and the indicated command is executed. ; If CLEVEL3 is permitted, a terminating zero is placed after the command ; (otherwise the user program has to place this zero) and the CIBPTR is ; properly initialized (otherwise the user program has to init this ptr). ; If the command is placed by a user program, entering at CPRLOC is enough ; to have the command processed. Again, under the current ZCPR, it is not ; necessary to store the pointer to CIBUFF in CIBPTR; ZCPR will do this for ; the calling program if CLEVEL3 is made TRUE. ; ; WARNING: The command line must NOT exceed BUFLEN characters in length. ; For user programs which load this command, the value of BUFLEN can be ; obtained by examining the byte at MBUFF (CPRLOC + 6). ; BUFLEN EQU 80 ;MAXIMUM BUFFER LENGTH MBUFF: DB BUFLEN ;MAXIMUM BUFFER LENGTH CBUFF: DB 0 ;NUMBER OF VALID CHARS IN COMMAND LINE CIBUFF: DB ' ' ;DEFAULT (COLD BOOT) COMMAND ; ; The copyright notice from Digital Research is genned into the ; stock CCP at this location. It should be maintained in ZCPR, ; since Digital Research grants permission for ZCPR to exist. ; DB ' COPYRIGHT (C) 1979, DIGITAL RESEARCH ' CIBUF: DB 0 ;COMMAND STRING TERMINATOR DB 'NZCPR V 1.6 of 08/03/82 ' ;ZCPR ID FOR DISK DUMP DS BUFLEN-($-CIBUFF)+1 ;TOTAL IS 'BUFLEN' BYTES ; CIBPTR: DW CIBUFF ;POINTER TO COMMAND INPUT BUFFER CIPTR: DW CIBUF ;POINTER TO CURR COMMAND FOR ; ERROR REPORTING ; DS 26 ;STACK AREA STACK EQU $ ;TOP OF STACK ; ; FILE TYPE FOR COMMAND ; COMMSG: DB 'COM' ; ; SUBMIT FILE CONTROL BLOCK ; SUBFCB: IF SUBA ;IF $$$.SUB ON A: DB 1 ;DISK NAME SET TO DEFAULT TO DRIVE A: ENDIF ; IF NOT SUBA ;IF $$$.SUB ON CURRENT DRIVE DB 0 ;DISK NAME SET TO DEFAULT TO CURRENT DRIVE ENDIF ; DB '$$$' ;FILE NAME DB ' ' DB 'SUB' ;FILE TYPE DB 0 ;EXTENT NUMBER DB 0 ;S1 SUBFS2: DS 1 ;S2 SUBFRC: DS 1 ;RECORD COUNT DS 16 ;DISK GROUP MAP SUBFCR: DS 1 ;CURRENT RECORD NUMBER ; COMMAND FILE CONTROL BLOCK ; FCBDN: DS 1 ;DISK NAME FCBFN: DS 8 ;FILE NAME FCBFT: DS 3 ;FILE TYPE DS 1 ;EXTENT NUMBER DS 2 ;S1 AND S2 DS 1 ;RECORD COUNT FCBDM: DS 16 ;DISK GROUP MAP FCBCR: DS 1 ;CURRENT RECORD NUMBER ; ; OTHER BUFFERS ; PAGCNT: DB NLINES-2 ;LINES LEFT ON PAGE CHRCNT: DB 0 ;CHAR COUNT FOR TYPE QMCNT: DB 0 ;QUESTION MARK COUNT FOR FCB TOKEN SCANNER ; ; ;**** Section 2 **** ; CPR STARTING POINTS. NOTE THAT SOME CP/M IMPLEMENTATIONS ; REQUIRE THE COLD START ADDRESS TO BE IN THE STARTING PAGE ; OF THE CPR, FOR DYNAMIC CCP LOADING. CMDTBL WAS MOVED FOR ; THIS REASON. ; ; SET USRMAX AND/OR MAXDRIV TO DEFAULT VALUES ON COLD BOOT ; IF REQUIRED. NOTE THAT SOME BIOS IMPLEMENTATIONS WILL END ; UP HERE INSTEAD OF AT THE WARM BOOT, DEFEATING PASSWORDING ; OF THESE OPTIONS. RECOMMEND SUCH A BIOS BE FIXED. ; IF USRMAX OR MAXDRIV CPR: IF USRMAX MVI A,MAXUSR+1 ;SET USRMAX ON COLD BOOT STA USRMAX ENDIF ;USRMAX ; IF MAXDRIV MVI A,MAXDR ;SET MAXDRIV ON COLD BOOT STA MAXDRIV ENDIF ;MAXDRIV ; JR CPR2 ; THEN PROCEED ENDIF ;USRMAX OR MAXDRIV ; ; START CPR AND DON'T PROCESS DEFAULT COMMAND STORED ; CPR1: XRA A ;SET NO DEFAULT COMMAND STA CBUFF ; ; START CPR AND POSSIBLY PROCESS DEFAULT COMMAND ; ; NOTE ON MODIFICATION BY RGF: BDOS RETURNS 0FFH IN ; ACCUMULATOR WHENEVER IT LOGS IN A DIRECTORY, IF ANY ; FILE NAME CONTAINS A '$' IN IT. THIS IS NOW USED AS ; A CLUE TO DETERMINE WHETHER OR NOT TO DO A SEARCH ; FOR SUBMIT FILE, IN ORDER TO ELIMINATE WASTEFUL SEARCHES. ; IF USRMAX OR MAXDRIV CPR2: ELSE CPR: ENDIF ;USRMAX OR MAXDRIV ; LXI SP,STACK ;RESET STACK PUSH B MOV A,C ;C=USER/DISK NUMBER (SEE LOC 4) RAR ;EXTRACT USER NUMBER RAR RAR RAR ANI 0FH MOV E,A ;SET USER NUMBER CALL SETUSR CALL RESET ;RESET DISK SYSTEM STA RNGSUB ;SAVE SUBMIT CLUE FROM DRIVE A: POP B MOV A,C ;C=USER/DISK NUMBER (SEE LOC 4) ANI 0FH ;EXTRACT DEFAULT DISK DRIVE STA TDRIVE ;SET IT JRZ NOLOG ;SKIP IF 0...ALREADY LOGGED CALL LOGIN ;LOG IN DEFAULT DISK ; IF NOT SUBA ;IF $$$.SUB IS ON CURRENT DRIVE STA RNGSUB ;BDOS '$' CLUE ENDIF ; NOLOG: LXI D,SUBFCB ;CHECK FOR $$$.SUB ON CURRENT DISK RNGSUB EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS THE RNGSUB FLAG ORA A ;SET FLAGS ON CLUE CMA ;PREPARE FOR COMING 'CMA' CNZ SEAR1 CMA ;0FFH IS RETURNED IF NO $$$.SUB, SO COMPLEMENT STA RNGSUB ;SET FLAG (0=NO $$$.SUB) LDA CBUFF ;EXECUTE DEFAULT COMMAND? ORA A ;0=NO JRNZ RS1 ; ; PROMPT USER AND INPUT COMMAND LINE FROM HIM ; RESTRT: LXI SP,STACK ;RESET STACK ; ; PRINT PROMPT (DU>) ; CALL CRLF ;PRINT PROMPT CALL GETDRV ;CURRENT DRIVE IS PART OF PROMPT ADI 'A' ;CONVERT TO ASCII A-P CALL CONOUT CALL GETUSR ;GET USER NUMBER ; IF SUPRES ;IF SUPPRESSING USR # REPORT FOR USR 0 ORA A JRZ RS000 ENDIF ; CPI 10 ;USER < 10? JRC RS00 SUI 10 ;SUBTRACT 10 FROM IT PUSH PSW ;SAVE IT MVI A,'1' ;OUTPUT 10'S DIGIT CALL CONOUT POP PSW RS00: ADI '0' ;OUTPUT 1'S DIGIT (CONVERT TO ASCII) CALL CONOUT ; ; READ INPUT LINE FROM USER OR $$$.SUB ; RS000: CALL REDBUF ;INPUT COMMAND LINE FROM USER (OR $$$.SUB) ; ; PROCESS INPUT LINE ; RS1: ; IF CLEVEL3 ;IF THIRD COMMAND LEVEL IS PERMITTED CALL CNVBUF ;CAPITALIZE COMMAND LINE, PLACE ENDING 0, ; AND SET CIBPTR VALUE ENDIF ; CALL DEFDMA ;SET TBUFF TO DMA ADDRESS CALL GETDRV ;GET DEFAULT DRIVE NUMBER STA TDRIVE ;SET IT CALL SCANER ;PARSE COMMAND NAME FROM COMMAND LINE CNZ ERROR ;ERROR IF COMMAND NAME CONTAINS A '?' LXI D,RSTCPR ;PUT RETURN ADDRESS OF COMMAND PUSH D ;ON THE STACK LDA TEMPDR ;IS COMMAND OF FORM 'D:COMMAND'? ORA A ;NZ=YES JNZ COM ; IMMEDIATELY CALL CMDSER ;SCAN FOR CPR-RESIDENT COMMAND JNZ COM ;NOT CPR-RESIDENT MOV A,M ;FOUND IT: GET LOW-ORDER PART INX H ;GET HIGH-ORDER PART MOV H,M ;STORE HIGH MOV L,A ;STORE LOW PCHL ;EXECUTE CPR ROUTINE ; ; ENTRY POINT FOR RESTARTING CPR AND LOGGING IN DEFAULT DRIVE ; RSTCPR: CALL DLOGIN ;LOG IN DEFAULT DRIVE ; ; ENTRY POINT FOR RESTARTING CPR WITHOUT LOGGING IN DEFAULT DRIVE ; RCPRNL: CALL SCANER ;EXTRACT NEXT TOKEN FROM COMMAND LINE LDA FCBFN ;GET FIRST CHAR OF TOKEN SUI ' ' ;ANY CHAR? LXI H,TEMPDR ORA M JNZ ERROR JR RESTRT ; ; No File Error Message ; PRNNF: CALL PRINTC ;NO FILE MESSAGE DB 'No Fil','e'+80H RET ; ; CPR BUILT-IN COMMAND TABLE ; NCHARS EQU 4 ;NUMBER OF CHARS/COMMAND ; ; CPR COMMAND NAME TABLE ; EACH TABLE ENTRY IS COMPOSED OF THE 4-BYTE COMMAND AND 2-BYTE ADDRESS ; CMDTBL: ; IF INPASS AND SECURE DB 'PASS' ;ENABLE WHEEL (SYSOP) MODE DW PASS ENDIF ;INPASS AND SECURE ; IF DRUSER DB 'USER' ;CHANGE USER AREAS DW USER ENDIF ;DRUSER ; IF CPRTYP DB 'TYPE' ;TYPE A FILE TO CON: DW TYPE ENDIF ;CPRTYP ; IF CPRDIR DB 'DIR ' ;PULL A DIRECTORY OF DISK FILES DW DIR ENDIF ;CPRDIR NRCMDS EQU ($-CMDTBL)/(NCHARS+2) ;PUT ANY COMMANDS THAT ARE OK TO ;RUN WHEN NOT UNDER WHEEL MODE ;IN FRONT OF THIS LABEL IF CPRLST AND CPRTYP DB 'LIST' ;LIST FILE TO PRINTER DW LIST ENDIF ;CPRLST AND CPRTYP ; IF INPASS AND SECURE DB 'NORM' ;DISABLE WHEEL MODE DW NORM ENDIF ;INPASS AND SECURE ; IF NOT RAS ;FOR NON-RAS DB 'GO ' ;JUMP TO 100H DW GO DB 'ERA ' ;ERASE FILE DW ERA DB 'SAVE' ;SAVE MEMORY IMAGE TO DISK DW SAVE DB 'REN ' ;RENAME FILE DW REN DB 'DFU ' ;SET DEFAULT USER DW DFU DB 'GET ' ;LOAD FILE INTO MEMORY DW GET DB 'JUMP' ;JUMP TO LOCATION IN MEMORY DW JUMP ENDIF ;RAS ; NCMNDS EQU ($-CMDTBL)/(NCHARS+2) ; ;**** Section 3 **** ; I/O UTILITIES ; ; OUTPUT CHAR IN REG A TO CONSOLE AND DON'T CHANGE BC ; ; ; OUTPUT ; CRLF: MVI A,CR CALL CONOUT MVI A,LF ;FALL THRU TO CONOUT ; CONOUT: PUSH B MVI C,02H OUTPUT: ANI 7FH ;PREVENT INADVERTANT GRAPHIC OUTPUT ; TO EPSON-TYPE PRINTERS MOV E,A PUSH H CALL BDOS POP H POP B RET ; CONIN: MVI C,01H ;GET CHAR FROM CON: WITH ECHO CALL BDOSB ; ; CONVERT CHAR IN A TO UPPER CASE ; UCASE: CPI 61H ;LOWER-CASE A RC CPI 7BH ;GREATER THAN LOWER-CASE Z? RNC ANI 5FH ;CAPITALIZE RET ; NOECHO: PUSH D ;SAVE D MVI C,6 ;DIRECT CONSOLE I/O MVI E,0FFH ;INPUT CALL BDOSB POP D ORA A ;DID WE GET A CHAR? JRZ NOECHO ;WAIT FOR IT IF NOT, IT'S EXPECTED RET ; IF CPRTYP LCOUT: ENDIF ;CPRTYP ; IF CPRTYP AND CPRLST PUSH PSW ;OUTPUT CHAR TO CON: OR LST: DEP ON PRFLG PRFLG EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS THE PRINT FLAG ORA A ;0=TYPE JRZ LC1 POP PSW ;GET CHAR ; ; OUTPUT CHAR IN REG A TO LIST DEVICE ; LSTOUT: PUSH B MVI C,05H JR OUTPUT LC1: POP PSW ;GET CHAR ENDIF ;CPRTYP AND CPRLST ; IF CPRTYP PUSH PSW CALL CONOUT ;OUTPUT TO CON: POP PSW CPI LF ;CHECK FOR PAGING RNZ ;DONE IF NOT EOL YET ; ; COUNT DOWN LINES AND PAUSE FOR INPUT (DIRECT) IF COUNT EXPIRES ; PUSH H LXI H,PAGCNT ;COUNT DOWN DCR M JRNZ PGBAK ;JUMP IF NOT END OF PAGE MVI M,NLINES-2 ;REFILL COUNTER ; PGFLG EQU $+1 ;POINTER TO IN-THE-CODE BUFFER PGFLG MVI A,0 ;0 MAY BE CHANGED BY PGFLG EQUATE CPI PGDFLG ;PAGE DEFAULT OVERRIDE OPTION WANTED? ; IF PGDFLT ;IF PAGING IS DEFAULT JRZ PGBAK ; PGDFLG MEANS NO PAGING, PLEASE ELSE ;IF PAGING NOT DEFAULT JRNZ PGBAK ; PGDFLG MEANS PLEASE PAGINATE ENDIF ; CALL NOECHO ;GET CHAR BUT DON'T ECHO TO SCREEN CPI 'C'-'@' ;^C JZ RSTCPR ;RESTART CPR PGBAK: POP H ;RESTORE HL RET ENDIF ;CPRTYP ; READF: LXI D,FCBDN ;FALL THRU TO READ READ: MVI C,14H ;FALL THRU TO BDOSB ; ; CALL BDOS AND SAVE BC ; BDOSB: PUSH B CALL BDOS POP B ORA A RET ; ; PRINT STRING ENDING WITH ZERO BYTE OR CHAR WITH HIGH BIT SET ; PT'ED TO BY RET ADDR, START WITH ; PRINTC: PUSH PSW ;SAVE FLAGS CALL CRLF ;NEW LINE POP PSW ; PRINT: XTHL ;GET PTR TO STRING PUSH PSW ;SAVE FLAGS CALL PRIN1 ;PRINT STRING POP PSW ;GET FLAGS XTHL ;RESTORE HL AND RET ADR RET ; ; PRINT STRING ENDING WITH ZERO BYTE OR CHAR WITH HIGH BIT SET ; PT'ED TO BY HL ; PRIN1: MOV A,M ;GET NEXT BYTE CALL CONOUT ;PRINT CHAR MOV A,M ;GET NEXT BYTE AGAIN FOR TEST INX H ;PT TO NEXT BYTE ORA A ;SET FLAGS RZ ;DONE IF ZERO RM ;DONE IF MSB SET JR PRIN1 ; ; BDOS FUNCTION ROUTINES ; ; ; RETURN NUMBER OF CURRENT DISK IN A ; GETDRV: MVI C,19H JR BDOSJP ; ; SET 80H AS DMA ADDRESS ; DEFDMA: LXI D,TBUFF ;80H=TBUFF DMASET: MVI C,1AH JR BDOSJP ; RESET: MVI C,0DH BDOSJP: JMP BDOS ; LOGIN: MOV E,A ;MOVE DESIRED # TO BDOS REG ; IF MAXDRIV LDA MAXDRIV ;CHECK FOR LEGAL DRIVE # CMP E JC ERROR ;DON'T DO IT IF TOO HIGH ENDIF ;MAXDRIV ; MVI C,0EH JR BDOSJP ;SAVE SOME CODE SPACE ; OPENF: XRA A STA FCBCR LXI D,FCBDN ;FALL THRU TO OPEN ; OPEN: MVI C,0FH ;FALL THRU TO GRBDOS ; GRBDOS: CALL BDOS INR A ;SET ZERO FLAG FOR ERROR RETURN RET ; CLOSE: MVI C,10H JR GRBDOS ; SEARF: LXI D,FCBDN ;SPECIFY FCB SEAR1: MVI C,11H JR GRBDOS ; SEARN: MVI C,12H JR GRBDOS ; ; CHECK FOR SUBMIT FILE IN EXECUTION AND ABORT IT IF SO ; SUBKIL: LXI H,RNGSUB ;CHECK FOR SUBMIT FILE IN EXECUTION MOV A,M ORA A ;0=NO RZ MVI M,0 ;ABORT SUBMIT FILE LXI D,SUBFCB ;DELETE $$$.SUB ; DELETE: MVI C,13H JR BDOSJP ;SAVE MORE SPACE ; ; RESET USER NUMBER IF CHANGED ; RESETUSR: TMPUSR EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS TMPUSR MOV E,A ;PLACE IN E JR SETUSR ;THEN GO SET USER GETUSR: MVI E,0FFH ;GET CURRENT USER NUMBER SETUSR: MVI C,20H ;SET USER NUMBER TO VALUE IN E (GET IF E=FFH) JR BDOSJP ;MORE SPACE SAVING ; ; END OF BDOS FUNCTIONS ; ; ;**** Section 4 **** ; CPR UTILITIES ; ; SET USER/DISK FLAG TO CURRENT USER AND DEFAULT DISK ; SETUD: CALL GETUSR ;GET NUMBER OF CURRENT USER ADD A ;PLACE IT IN HIGH NYBBLE ADD A ADD A ADD A LXI H,TDRIVE ;MASK IN DEFAULT DRIVE NUMBER (LOW NYBBLE) ORA M ;MASK IN STA UDFLAG ;SET USER/DISK NUMBER RET ; ; SET USER/DISK FLAG TO USER 0 AND DEFAULT DISK ; SETU0D: TDRIVE EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS TDRIVE STA UDFLAG ;SET USER/DISK NUMBER RET ; ; INPUT NEXT COMMAND TO CPR ; This routine determines if a SUBMIT file is being processed ; and extracts the command line from it if so or from the user's console ; REDBUF: LDA RNGSUB ;SUBMIT FILE CURRENTLY IN EXECUTION? ORA A ;0=NO JRZ RB1 ;GET LINE FROM CONSOLE IF NOT LXI D,SUBFCB ;OPEN $$$.SUB PUSH D ;SAVE DE CALL OPEN POP D ;RESTORE DE JRZ RB1 ;ERASE $$$.SUB IF END OF FILE AND GET CMND LDA SUBFRC ;GET VALUE OF LAST RECORD IN FILE DCR A ;PT TO NEXT TO LAST RECORD STA SUBFCR ;SAVE NEW VALUE OF LAST RECORD IN $$$.SUB CALL READ ;DE=SUBFCB JRNZ RB1 ;ABORT $$$.SUB IF ERROR IN READING LAST REC LXI D,CBUFF ;COPY LAST RECORD (NEXT SUBMIT CMND) TO CBUFF LXI H,TBUFF ; FROM TBUFF LXI B,BUFLEN ;NUMBER OF BYTES LDIR LXI H,SUBFS2 ;PT TO S2 OF $$$.SUB FCB MVI M,0 ;SET S2 TO ZERO INX H ;PT TO RECORD COUNT DCR M ;DECREMENT RECORD COUNT OF $$$.SUB LXI D,SUBFCB ;CLOSE $$$.SUB CALL CLOSE JRZ RB1 ;ABORT $$$.SUB IF ERROR MVI A,SPRMPT ;PRINT SUBMIT PROMPT CALL CONOUT LXI H,CIBUFF ;PRINT COMMAND LINE FROM $$$.SUB CALL PRIN1 CALL BREAK ;CHECK FOR ABORT (ANY CHAR) ; IF CLEVEL3 ;IF THIRD COMMAND LEVEL IS PERMITTED RZ ;IF (NO ABORT), RETURN TO CALLER AND RUN ENDIF ; IF NOT CLEVEL3 ;IF THIRD COMMAND LEVEL IS NOT PERMITTED JRZ CNVBUF ;IF (NO ABORT), CAPITALIZE COMMAND ENDIF ; CALL SUBKIL ;KILL $$$.SUB IF ABORT JMP RESTRT ;RESTART CPR ; ; INPUT COMMAND LINE FROM USER CONSOLE ; RB1: CALL SUBKIL ;ERASE $$$.SUB IF PRESENT CALL SETUD ;SET USER AND DISK MVI A,CPRMPT ;PRINT PROMPT CALL CONOUT MVI C,0AH ;READ COMMAND LINE FROM USER LXI D,MBUFF CALL BDOS ; IF CLEVEL3 ;IF THIRD COMMAND LEVEL IS PERMITTED JMP SETU0D ;SET CURRENT DISK NUMBER IN LOWER PARAMS ENDIF ; IF NOT CLEVEL3 ;IF THIRD COMMAND LEVEL IS NOT PERMITTED CALL SETU0D ;SET CURRENT DISK NUMBER IF LOWER PARAMS ; AND FALL THRU TO CNVBUF ENDIF ; ; CAPITALIZE STRING (ENDING IN 0) IN CBUFF AND SET PTR FOR PARSING ; CNVBUF: LXI H,CBUFF ;PT TO USER'S COMMAND MOV B,M ;CHAR COUNT IN B INR B ;ADD 1 IN CASE OF ZERO CB1: INX H ;PT TO 1ST VALID CHAR MOV A,M ;CAPITALIZE COMMAND CHAR CALL UCASE MOV M,A DJNZ CB1 ;CONTINUE TO END OF COMMAND LINE CB2: MVI M,0 ;STORE ENDING LXI H,CIBUFF ;SET COMMAND LINE PTR TO 1ST CHAR SHLD CIBPTR RET ; ; CHECK FOR ANY CHAR FROM USER CONSOLE;RET W/ZERO SET IF NONE ; BREAK: PUSH D ;SAVE DE MVI C,11 ;CSTS CHECK CALL BDOSB CNZ CONIN ;GET INPUT CHAR BRKBK: POP D RET ; ; GET THE REQUESTED USER NUMBER FROM THE COMMAND LINE AND VALIDATE IT. ; USRNUM: CALL NUMBER ; IF USRMAX LXI H,USRMAX ;PT TO MAXUSR + 1 CMP M ;NEW VALUE ALLOWED? ELSE CPI MAXUSR+1 ;NEW VALUE ALLOWED? ENDIF ;USRMAX ; RC ;RETURN TO CALLER IF SO, ; ELSE FLAG AS ERROR ; ; INVALID COMMAND -- PRINT IT ; ERROR: CALL CRLF ;NEW LINE LHLD CIPTR ;PT TO BEGINNING OF COMMAND LINE ERR2: MOV A,M ;GET CHAR CPI ' '+1 ;SIMPLE '?' IF OR LESS JRC ERR1 PUSH H ;SAVE PTR TO ERROR COMMAND CHAR CALL CONOUT ;PRINT COMMAND CHAR POP H ;GET PTR INX H ;PT TO NEXT JR ERR2 ;CONTINUE ERR1: CALL PRINT ;PRINT '?' DB '?'+80H CALL SUBKIL ;TERMINATE ACTIVE $$$.SUB IF ANY JMP RESTRT ;RESTART CPR ; ; CHECK TO SEE IF DE PTS TO DELIMITER; IF SO, RET W/ZERO FLAG SET ; SDELM: LDAX D ORA A ;0=DELIMITER RZ CPI ' ' ;ERROR IF < JRC ERROR RZ ;=DELIMITER CPI '=' ;'='=DELIMITER RZ CPI 5FH ;UNDERSCORE=DELIMITER RZ CPI '.' ;'.'=DELIMITER RZ CPI ':' ;':'=DELIMITER RZ CPI ';' ;';'=DELIMITER RZ CPI '<' ;'<'=DELIMITER RZ CPI '>' ;'>'=DELIMITER RET ; ; ADVANCE INPUT PTR TO FIRST NON-BLANK AND FALL THROUGH TO SBLANK ; ADVAN: LDED CIBPTR ; ; SKIP STRING PTED TO BY DE (STRING ENDS IN 0) UNTIL END OF STRING ; OR NON-BLANK ENCOUNTERED (BEGINNING OF TOKEN) ; SBLANK: LDAX D ORA A RZ CPI ' ' RNZ INX D JR SBLANK ; ; ADD A TO HL (HL=HL+A) ; ADDAH: ADD L MOV L,A RNC INR H RET ; ; EXTRACT DECIMAL NUMBER FROM COMMAND LINE ; RETURN WITH VALUE IN REG A;ALL REGISTERS MAY BE AFFECTED ; NUMBER: CALL SCANER ;PARSE NUMBER AND PLACE IN FCBFN LXI H,FCBFN+10 ;PT TO END OF TOKEN FOR CONVERSION MVI B,11 ;11 CHARS MAX ; ; CHECK FOR SUFFIX FOR HEXADECIMAL NUMBER ; NUMS: MOV A,M ;GET CHARS FROM END, SEARCHING FOR SUFFIX DCX H ;BACK UP CPI ' ' ;SPACE? JRNZ NUMS1 ;CHECK FOR SUFFIX DJNZ NUMS ;COUNT DOWN JR NUM0 ;BY DEFAULT, PROCESS NUMS1: CPI NUMBASE ;CHECK AGAINST BASE SWITCH FLAG JRZ HNUM0 ; ; PROCESS DECIMAL NUMBER ; NUM0: LXI H,FCBFN ;PT TO BEGINNING OF TOKEN LXI B,1100H ;C=ACCUMULATED VALUE, B=CHAR COUNT ; (C=0, B=11) NUM1: MOV A,M ;GET CHAR CPI ' ' ;DONE IF JRZ NUM2 INX H ;PT TO NEXT CHAR SUI '0' ;CONVERT TO BINARY (ASCII 0-9 TO BINARY) CPI 10 ;ERROR IF >= 10 JRNC NUMERR MOV D,A ;DIGIT IN D MOV A,C ;NEW VALUE = OLD VALUE * 10 RLC RLC RLC ADD C ;CHECK FOR RANGE ERROR JRC NUMERR ADD C ;CHECK FOR RANGE ERROR JRC NUMERR ADD D ;NEW VALUE = OLD VALUE * 10 + DIGIT JRC NUMERR ;CHECK FOR RANGE ERROR MOV C,A ;SET NEW VALUE DJNZ NUM1 ;COUNT DOWN ; ; RETURN FROM NUMBER ; NUM2: MOV A,C ;GET ACCUMULATED VALUE RET ; ; NUMBER ERROR ROUTINE FOR SPACE CONSERVATION ; NUMERR: JMP ERROR ;USE ERROR ROUTINE - THIS IS RELATIVE PT ; ; EXTRACT HEXADECIMAL NUMBER FROM COMMAND LINE ; RETURN WITH VALUE IN REG A; ALL REGISTERS MAY BE AFFECTED ; HEXNUM: CALL SCANER ;PARSE NUMBER AND PLACE IN FCBFN HNUM0: LXI H,FCBFN ;PT TO TOKEN FOR CONVERSION LXI D,0 ;DE=ACCUMULATED VALUE MVI B,11 ;B=CHAR COUNT HNUM1: MOV A,M ;GET CHAR CPI ' ' ;DONE? JRZ HNUM3 ;RETURN IF SO CPI NUMBASE ;DONE IF NUMBASE SUFFIX JRZ HNUM3 SUI '0' ;CONVERT TO BINARY JRC NUMERR ;RETURN AND DONE IF ERROR CPI 10 ;0-9? JRC HNUM2 SUI 7 ;A-F? CPI 10H ;ERROR? JRNC NUMERR HNUM2: INX H ;PT TO NEXT CHAR MOV C,A ;DIGIT IN C MOV A,D ;GET ACCUMULATED VALUE RLC ;EXCHANGE NYBBLES RLC RLC RLC ANI 0F0H ;MASK OUT LOW NYBBLE MOV D,A MOV A,E ;SWITCH LOW-ORDER NYBBLES RLC RLC RLC RLC MOV E,A ;HIGH NYBBLE OF E=NEW HIGH OF E, ; LOW NYBBLE OF E=NEW LOW OF D ANI 0FH ;GET NEW LOW OF D ORA D ;MASK IN HIGH OF D MOV D,A ;NEW HIGH BYTE IN D MOV A,E ANI 0F0H ;MASK OUT LOW OF E ORA C ;MASK IN NEW LOW MOV E,A ;NEW LOW BYTE IN E DJNZ HNUM1 ;COUNT DOWN ; ; RETURN FROM HEXNUM ; HNUM3: XCHG ;RETURNED VALUE IN HL MOV A,L ;LOW-ORDER BYTE IN A RET ; ; PT TO DIRECTORY ENTRY IN TBUFF WHOSE OFFSET IS SPECIFIED BY A AND C ; DIRPTR: LXI H,TBUFF ;PT TO TEMP BUFFER ADD C ;PT TO 1ST BYTE OF DIR ENTRY CALL ADDAH ;PT TO DESIRED BYTE IN DIR ENTRY MOV A,M ;GET DESIRED BYTE RET ; ; CHECK FOR SPECIFIED DRIVE AND LOG IT IN IF NOT DEFAULT ; SLOGIN: XRA A ;SET FCBDN FOR DEFAULT DRIVE STA FCBDN CALL COMLOG ;CHECK DRIVE RZ JR DLOG5 ;DO LOGIN OTHERWISE ; ; CHECK FOR SPECIFIED DRIVE AND LOG IN DEFAULT DRIVE IF SPECIFIED<>DEFAULT ; DLOGIN: CALL COMLOG ;CHECK DRIVE RZ ;ABORT IF SAME LDA TDRIVE ;LOG IN DEFAULT DRIVE ; DLOG5: JMP LOGIN ; ; ROUTINE COMMON TO BOTH LOGIN ROUTINES; ON EXIT, Z SET MEANS ABORT ; COMLOG: TEMPDR EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS TEMPDR ORA A ;0=NO RZ DCR A ;COMPARE IT AGAINST DEFAULT LXI H,TDRIVE CMP M RET ;ABORT IF SAME ; ; EXTRACT TOKEN FROM COMMAND LINE AND PLACE IT INTO FCBDN; ; FORMAT FCBDN FCB IF TOKEN RESEMBLES FILE NAME AND TYPE (FILENAME.TYP); ; ON INPUT, CIBPTR PTS TO CHAR AT WHICH TO START SCAN; ; ON OUTPUT, CIBPTR PTS TO CHAR AT WHICH TO CONTINUE AND ZERO FLAG IS RESET ; IF '?' IS IN TOKEN ; ; ENTRY POINTS: ; SCANER - LOAD TOKEN INTO FIRST FCB ; SCANX - LOAD TOKEN INTO FCB PTED TO BY HL ; SCANER: LXI H,FCBDN ;POINT TO FCBDN SCANX: XRA A ;SET TEMPORARY DRIVE NUMBER TO DEFAULT STA TEMPDR CALL ADVAN ;SKIP TO NON-BLANK OR END OF LINE SDED CIPTR ;SET PTR TO NON-BLANK OR END OF LINE LDAX D ;END OF LINE? ORA A ;0=YES JRZ SCAN2 SBI 'A'-1 ;CONVERT POSSIBLE DRIVE SPEC TO NUMBER MOV B,A ;STORE NUMBER (A:=0, B:=1, ETC) IN B INX D ;PT TO NEXT CHAR LDAX D ;SEE IF IT IS A COLON (:) CPI ':' JRZ SCAN3 ;YES, WE HAVE A DRIVE SPEC DCX D ;NO, BACK UP PTR TO FIRST NON-BLANK CHAR SCAN2: LDA TDRIVE ;SET 1ST BYTE OF FCBDN AS DEFAULT DRIVE MOV M,A JR SCAN4 SCAN3: MOV A,B ;WE HAVE A DRIVE SPEC STA TEMPDR ;SET TEMPORARY DRIVE MOV M,B ;SET 1ST BYTE OF FCBDN AS SPECIFIED DRIVE INX D ;PT TO BYTE AFTER ':' ; ; EXTRACT FILENAME FROM POSSIBLE FILENAME.TYP ; SCAN4: XRA A ;A=0 STA QMCNT ;INIT COUNT OF NUMBER OF QUESTION MARKS IN FCB MVI B,8 ;MAX OF 8 CHARS IN FILE NAME CALL SCANF ;FILL FCB FILE NAME ; ; EXTRACT FILE TYPE FROM POSSIBLE FILENAME.TYP ; MVI B,3 ;PREPARE TO EXTRACT TYPE CPI '.' ;IF (DE) DELIMITER IS A '.', WE HAVE A TYPE JRNZ SCAN15 ;FILL FILE TYPE BYTES WITH INX D ;PT TO CHAR IN COMMAND LINE AFTER '.' CALL SCANF ;FILL FCB FILE TYPE JR SCAN16 ;SKIP TO NEXT PROCESSING SCAN15: CALL SCANF4 ;SPACE FILL ; ; FILL IN EX, S1, S2, AND RC WITH ZEROES ; SCAN16: MVI B,4 ;4 BYTES SCAN17: INX H ;PT TO NEXT BYTE IN FCBDN MVI M,0 DJNZ SCAN17 ; ; SCAN COMPLETE -- DE PTS TO DELIMITER BYTE AFTER TOKEN ; SDED CIBPTR ; ; SET ZERO FLAG TO INDICATE PRESENCE OF '?' IN FILENAME.TYP ; LDA QMCNT ;GET NUMBER OF QUESTION MARKS ORA A ;SET ZERO FLAG TO INDICATE ANY '?' RET ; ; SCANF -- SCAN TOKEN PTED TO BY DE FOR A MAX OF B BYTES; PLACE IT INTO ; FILE NAME FIELD PTED TO BY HL; EXPAND AND INTERPRET WILD CARDS OF ; '*' AND '?'; ON EXIT, DE PTS TO TERMINATING DELIMITER ; SCANF: CALL SDELM ;DONE IF DELIMITER ENCOUNTERED - FILL JRZ SCANF4 INX H ;PT TO NEXT BYTE IN FCBDN CPI '*' ;IS (DE) A WILD CARD? JRNZ SCANF1 ;CONTINUE IF NOT MVI M,'?' ;PLACE '?' IN FCBDN AND DON'T ADVANCE DE IF SO CALL SCQ ;SCANNER COUNT QUESTION MARKS JR SCANF2 SCANF1: MOV M,A ;STORE FILENAME CHAR IN FCBDN INX D ;PT TO NEXT CHAR IN COMMAND LINE CPI '?' ;CHECK FOR QUESTION MARK (WILD) CZ SCQ ;SCANNER COUNT QUESTION MARKS SCANF2: DJNZ SCANF ;DECREMENT CHAR COUNT UNTIL 8 ELAPSED SCANF3: CALL SDELM ;8 CHARS OR MORE - SKIP UNTIL DELIMITER RZ ;ZERO FLAG SET IF DELIMITER FOUND INX D ;PT TO NEXT CHAR IN COMMAND LINE JR SCANF3 ; ; FILL MEMORY POINTED TO BY HL WITH SPACES FOR B BYTES ; SCANF4: INX H ;PT TO NEXT BYTE IN FCBDN MVI M,' ' ;FILL FILENAME PART WITH DJNZ SCANF4 RET ; ; INCREMENT QUESTION MARK COUNT FOR SCANNER ; THIS ROUTINE INCREMENTS THE COUNT OF THE NUMBER OF QUESTION MARKS IN ; THE CURRENT FCB ENTRY ; SCQ: LDA QMCNT ;GET COUNT INR A ;INCREMENT STA QMCNT ;PUT COUNT RET ; ; CMDTBL (COMMAND TABLE) SCANNER ; ON RETURN, HL PTS TO ADDRESS OF COMMAND IF CPR-RESIDENT ; ON RETURN, ZERO FLAG SET MEANS CPR-RESIDENT COMMAND ; CMDSER: LXI H,CMDTBL ;PT TO COMMAND TABLE ; IF SECURE MVI C,NRCMDS LDA WHEEL ;SEE IF NON-RESTRCTED CPI RESTRCT JRZ CMS1 ;PASS IF RESTRCTED ENDIF ;SECURE ; MVI C,NCMNDS ;SET COMMAND COUNTER CMS1: LXI D,FCBFN ;PT TO STORED COMMAND NAME MVI B,NCHARS ;NUMBER OF CHARS/COMMAND (8 MAX) CMS2: LDAX D ;COMPARE AGAINST TABLE ENTRY CMP M JRNZ CMS3 ;NO MATCH INX D ;PT TO NEXT CHAR INX H DJNZ CMS2 ;COUNT DOWN LDAX D ;NEXT CHAR IN INPUT COMMAND MUST BE CPI ' ' JRNZ CMS4 RET ;COMMAND IS CPR-RESIDENT (ZERO FLAG SET) CMS3: INX H ;SKIP TO NEXT COMMAND TABLE ENTRY DJNZ CMS3 CMS4: INX H ;SKIP ADDRESS INX H DCR C ;DECREMENT TABLE ENTRY NUMBER JRNZ CMS1 INR C ;CLEAR ZERO FLAG RET ;COMMAND IS DISK-RESIDENT (ZERO FLAG CLEAR) ; ;**** Section 5 **** ; CPR-Resident Commands ; ; ;Section 5A ;Command: DIR ;Function: To display a directory of the files on disk ;Forms: ; DIR Displays the DIR files ; DIR S Displays the SYS files ; DIR A Display both DIR and SYS files ; IF CPRDIR ; DIR: MVI A,80H ;SET SYSTEM BIT EXAMINATION PUSH PSW CALL SCANER ;EXTRACT POSSIBLE D:FILENAME.TYP TOKEN CALL SLOGIN ;LOG IN DRIVE IF NECESSARY LXI H,FCBFN ;MAKE FCB WILD (ALL '?') IF NO FILENAME.TYP MOV A,M ;GET FIRST CHAR OF FILENAME.TYP CPI ' ' ;IF , ALL WILD CZ FILLQ CALL ADVAN ;LOOK AT NEXT INPUT CHAR MVI B,0 ;SYS TOKEN DEFAULT JRZ DIR2 ;JUMP; THERE ISN'T ONE CPI SYSFLG ;SYSTEM FLAG SPECIFIER? JRZ GOTSYS ;GOT SYSTEM SPECIFIER CPI SOFLG ;SYS ONLY? JRNZ DIR2 MVI B,80H ;FLAG SYS ONLY GOTSYS: INX D SDED CIBPTR CPI SOFLG ;SYS ONLY SPEC? JRZ DIR2 ;THEN LEAVE BIT SPEC UNCHAGNED POP PSW ;GET FLAG XRA A ;SET NO SYSTEM BIT EXAMINATION PUSH PSW DIR2: POP PSW ;GET FLAG DIR2A: ;DROP INTO DIRPR TO PRINT DIRECTORY ; THEN RESTART CPR ENDIF ;CPRDIR ; ; DIRECTORY PRINT ROUTINE; ON ENTRY, MSB OF A IS 1 (80H) IF SYSTEM FILES ; EXCLUDED. THIS ROUTINE IS ALSO USED BY ERA. ; DIRPR: MOV D,A ;STORE SYSTEM FLAG IN D MVI E,0 ;SET COLUMN COUNTER TO ZERO PUSH D ;SAVE COLUMN COUNTER (E) AND SYSTEM FLAG (D) MOV A,B ;SYS ONLY SPECIFIER STA SYSTST CALL SEARF ;SEARCH FOR SPECIFIED FILE (FIRST OCCURRANCE) CZ PRNNF ;PRINT NO FILE MSG;REG A NOT CHANGED ; ; ENTRY SELECTION LOOP; ON ENTRY, A=OFFSET FROM SEARF OR SEARN ; DIR3: JRZ DIR11 ;DONE IF ZERO FLAG SET DCR A ;ADJUST TO RETURNED VALUE RRC ;CONVERT NUMBER TO OFFSET INTO TBUFF RRC RRC ANI 60H MOV C,A ;OFFSET INTO TBUFF IN C (C=OFFSET TO ENTRY) MVI A,10 ;ADD 10 TO PT TO SYSTEM FILE ATTRIBUTE BIT CALL DIRPTR POP D ;GET SYSTEM BIT MASK FROM D PUSH D ANA D ;MASK FOR SYSTEM BIT SYSTST EQU $+1 ;POINTER TO IN-THE-CODE BUFFER SYSTST CPI 0 JRNZ DIR10 POP D ;GET ENTRY COUNT (= COUNTER) MOV A,E ;ADD 1 TO IT INR E PUSH D ;SAVE IT ; IF TWOCOL ANI 01H ;OUTPUT IF 2 ENTRIES PRINTED IN LINE ENDIF ;TWOCOL ; IF NOT TWOCOL TWOPOK EQU $+1 ;FOR APPLE PATCHING ANI 03H ;OUTPUT IF 4 ENTRIES PRINTED IN LINE ENDIF ;NOT TWOCOL ; PUSH PSW JRNZ DIR4 CALL CRLF ;NEW LINE JR DIR5 DIR4: CALL PRINT ; IF WIDE DB ' ' ;2 SPACES DB FENCE ;THEN FENCE CHAR DB ' ',' '+80H ;THEN 2 MORE SPACES ENDIF ; IF NOT WIDE DB ' ' ;SPACE DB FENCE ;THEN FENCE CHAR DB ' '+80H ;THEN SPACE ENDIF ; DIR5: MVI B,01H ;PT TO 1ST BYTE OF FILE NAME DIR6: MOV A,B ;A=OFFSET CALL DIRPTR ;HL NOW PTS TO 1ST BYTE OF FILE NAME ANI 7FH ;MASK OUT MSB CPI ' ' ;NO FILE NAME? JRNZ DIR8 ;PRINT FILE NAME IF PRESENT POP PSW PUSH PSW CPI 03H JRNZ DIR7 MVI A,09H ;PT TO 1ST BYTE OF FILE TYPE CALL DIRPTR ;HL NOW PTS TO 1ST BYTE OF FILE TYPE ANI 7FH ;MASK OUT MSB CPI ' ' ;NO FILE TYPE? JRZ DIR9 ;CONTINUE IF SO DIR7: MVI A,' ' ;OUTPUT DIR8: CALL CONOUT ;PRINT CHAR INR B ;INCR CHAR COUNT MOV A,B CPI 12 ;END OF FILENAME.TYP? JRNC DIR9 ;CONTINUE IF SO CPI 09H ;END IF FILENAME ONLY? JRNZ DIR6 ;PRINT TYP IF SO MVI A,'.' ;PRINT DOT BETWEEN FILE NAME AND TYPE CALL CONOUT JR DIR6 DIR9: POP PSW DIR10: CALL BREAK ;CHECK FOR ABORT JRNZ DIR11 CALL SEARN ;SEARCH FOR NEXT FILE JR DIR3 ;CONTINUE DIR11: POP D ;RESTORE STACK RET ; ; FILL FCB @HL WITH '?' ; FILLQ: MVI B,11 ;NUMBER OF CHARS IN FN & FT FQLP: MVI M,'?' ;STORE '?' INX H DJNZ FQLP RET ; ;Section 5B ;Command: ERA ;Function: Erase files ;Forms: ; ERA Erase Specified files and print their names ; IF NOT RAS ;NOT FOR REMOTE-ACCESS SYSTEM ; ERA: CALL SCANER ;PARSE FILE SPECIFICATION CPI 11 ;ALL WILD (ALL FILES = 11 '?')? JRNZ ERA1 ;IF NOT, THEN DO ERASES CALL PRINTC DB 'All','?'+80H CALL CONIN ;GET REPLY CPI 'Y' ;YES? ERARJ: JNZ RESTRT ;RESTART CPR IF NOT CALL CRLF ;NEW LINE ERA1: CALL SLOGIN ;LOG IN SELECTED DISK IF ANY XRA A ;PRINT ALL FILES (EXAMINE SYSTEM BIT) MOV B,A ;NO SYS-ONLY OPT TO DIRPR CALL DIRPR ;PRINT DIRECTORY OF ERASED FILES ; IF EPRMPT ; ; QUERY USER AFTER FILES ARE SEEN, AND GIVE ONE LAST CHANCE TO BACK OUT ; MOV A,E ;HOW MANY FILES DISPLAYED? ORA A JZ RESTRT ;IF NONE, DON'T ASK OR DELETE CALL PRINTC ;PROMPT DB 'Ok','?'+80H CALL CONIN ;GET REPLY FOLDED CPI 'Y' ;YES? JRNZ ERARJ ;GET OUT IF NOT ENDIF ;EPRMPT ; LXI D,FCBDN ;DELETE FILE(S) SPECIFIED JMP DELETE ;RESTART CPR AFTER DELETE ; ENDIF ;RAS ; ;Section 5C ;Command: LIST ;Function: Print out specified file on the LST: Device ;Forms: ; LIST Print file (NO Paging) ; IF CPRLST LIST: MVI A,0FFH ;TURN ON PRINTER FLAG JR TYPE0 ENDIF ;CPRLST ; ;Section 5D ;Command: TYPE ;Function: Print out specified file on the CON: Device ;Forms: ; TYPE Print file ; TYPE P Print file with paging flag ; IF CPRTYP TYPE: ENDIF ;CPRTYP ; IF CPRTYP AND CPRLST XRA A ;TURN OFF PRINTER FLAG ; ; ENTRY POINT FOR CPR LIST FUNCTION (LIST) ; TYPE0: STA PRFLG ;SET FLAG ENDIF ;CPRTYP AND CPRLST ; IF CPRTYP CALL SCANER ;EXTRACT FILENAME.TYP TOKEN JNZ ERROR ;ERROR IF ANY QUESTION MARKS CALL ADVAN ;GET PGDFLG IF IT'S THERE STA PGFLG ;SAVE IT AS A FLAG JRZ NOSLAS ;JUMP IF INPUT ENDED INX D ;PUT NEW BUF POINTER XCHG SHLD CIBPTR NOSLAS: CALL SLOGIN ;LOG IN SELECTED DISK IF ANY CALL OPENF ;OPEN SELECTED FILE JZ TYPE4 ;ABORT IF ERROR CALL CRLF ;NEW LINE MVI A,NLINES-1 ;SET LINE COUNT STA PAGCNT LXI H,CHRCNT ;SET CHAR POSITION/COUNT MVI M,0FFH ;EMPTY LINE MVI B,0 ;SET TAB CHAR COUNTER TYPE1: LXI H,CHRCNT ;PT TO CHAR POSITION/COUNT MOV A,M ;END OF BUFFER? CPI 80H JRC TYPE2 PUSH H ;READ NEXT BLOCK CALL READF POP H JRNZ TYPE3 ;ERROR? XRA A ;RESET COUNT MOV M,A TYPE2: INR M ;INCREMENT CHAR COUNT LXI H,TBUFF ;PT TO BUFFER CALL ADDAH ;COMPUTE ADDRESS OF NEXT CHAR FROM OFFSET MOV A,M ;GET NEXT CHAR ANI 7FH ;MASK OUT MSB CPI 1AH ;END OF FILE (^Z)? RZ ;RESTART CPR IF SO ; ; OUTPUT CHAR TO CON: OR LST: DEVICE WITH TABULATION ; IF WSTYPE ;WORDSTAR HYPHEN CHECK CPI 1FH ;IS CHAR WORDSTAR EOL HYPHEN? JRNZ NOHYPH ;PASS IF NOT MVI A,'-' ;YES, MAKE IT A REAL HYPHEN NOHYPH: ENDIF ;WSTYPE ; CPI ' ' ;IS CHAR CONTROL CODE? JRNC PRT ;GO BOP CHAR COUNT AND PRINT IF NOT CPI CR ;IS CHAR A CR? JRZ YESCR ;IF SO, GO ZERO B THEN PRINT CPI FFEED ;FORM FEED? JRZ YESCR ;MANY PRINTERS RETURN CARRIAGE ON THIS CPI LF ;LINE FEED? JRZ NOBOP ;PRINT, BUT DON'T BOP B CPI BEL ;BELL? JRZ NOBOP ;GO RING BUT DON'T BOP B CPI TAB ;TAB? JRNZ TYPE2L ;IF NOT, NO OTHER CHOICES, TOSS CONTROL LTAB: MVI A,' ' ; CALL LCOUT INR B ;INCR POS COUNT MOV A,B ANI 7 JRNZ LTAB JR TYPE2L ; YESCR: MVI B,0FFH ;COMBINE WITH INC BELOW TO GET ZERO ; PRT: INR B ;INCREMENT CHAR COUNT NOBOP: CALL LCOUT ;PRINT IT ; ; CONTINUE PROCESSING ; ; TYPE2L: CALL BREAK ;CHECK FOR ABORT JRZ TYPE1 ;CONTINUE IF NO CHAR CPI 'C'-'@' ;^C? RZ ;RESTART IF SO JR TYPE1 TYPE3: DCR A ;NO ERROR? RZ ;RESTART CPR TYPE4: JMP ERRLOG ENDIF ;CPRTYP ; ;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 ; IF NOT RAS ;NOT FOR REMOTE-ACCESS SYSTEM ; SAVE: CALL NUMBER ;EXTRACT NUMBER FROM COMMAND LINE MOV L,A ;HL=PAGE COUNT MVI H,0 PUSH H ;SAVE PAGE COUNT CALL EXTEST ;TEST FOR EXISTENCE OF FILE AND ABORT IF SO MVI C,16H ;BDOS MAKE FILE CALL GRBDOS POP H ;GET PAGE COUNT JRZ SAVE3 ;ERROR? XRA A ;SET RECORD COUNT FIELD OF NEW FILE'S FCB STA FCBCR CALL ADVAN ;LOOK FOR 'S' FOR SECTOR OPTION INX D ;PT TO AFTER 'S' TOKEN CPI SECTFLG JRZ SAVE0 DCX D ;NO 'S' TOKEN, SO BACK UP DAD H ;DOUBLE IT FOR HL=SECTOR (128 BYTES) COUNT SAVE0: SDED CIBPTR ;SET PTR TO BAD TOKEN OR AFTER GOOD TOKEN LXI D,TPA ;PT TO START OF SAVE AREA (TPA) SAVE1: MOV A,H ;DONE WITH SAVE? ORA L ;HL=0 IF SO JRZ SAVE2 DCX H ;COUNT DOWN ON SECTORS PUSH H ;SAVE PTR TO BLOCK TO SAVE LXI H,128 ;128 BYTES PER SECTOR DAD D ;PT TO NEXT SECTOR PUSH H ;SAVE ON STACK CALL DMASET ;SET DMA ADDRESS FOR WRITE (ADDRESS IN DE) LXI D,FCBDN ;WRITE SECTOR MVI C,15H ;BDOS WRITE SECTOR CALL BDOSB ;SAVE BC POP D ;GET PTR TO NEXT SECTOR IN DE POP H ;GET SECTOR COUNT JRZ SAVE1 ;CONTINUE IF NO WRITE ERROR JR PRNLE ;GO PRINT ERROR AND RESET DMA SAVE2: LXI D,FCBDN ;CLOSE SAVED FILE CALL CLOSE INR A ;ERROR? JRNZ SAVE3 ;PASS IF OK ; ; PRNLE IS ALSO USED BY MEMLOAD FOR TPA FULL ERROR ; PRNLE: CALL PRINTC ;DISK OR MEM FULL DB 'Ful','l'+80H ; SAVE3: JMP DEFDMA ;SET DMA TO 0080 AND RESTART CPR ; OR RETURN TO MLERR ; ; Test File in FCB for existence, ask user to delete if so, and abort if he ; choses not to ; EXTEST: CALL SCANER ;EXTRACT FILE NAME JNZ ERROR ;'?' IS NOT PERMITTED CALL SLOGIN ;LOG IN SELECTED DISK CALL SEARF ;LOOK FOR SPECIFIED FILE LXI D,FCBDN ;PT TO FILE FCB RZ ;OK IF NOT FOUND PUSH D ;SAVE PTR TO FCB CALL PRINTC DB 'Delete File','?'+80H CALL CONIN ;GET RESPONSE POP D ;GET PTR TO FCB CPI 'Y' ;KEY ON YES JNZ RSTCPR ;RESTART IF NO, SP RESET EVENTUALLY PUSH D ;SAVE PTR TO FCB CALL DELETE ;DELETE FILE POP D ;GET PTR TO FCB RET ; ENDIF ;RAS ; ;Section 5F ;Command: REN ;Function: To change the name of an existing file ;Forms: ; REN = Perform function ; IF NOT RAS ;NOT FOR REMOTE-ACCESS SYSTEM ; REN: CALL EXTEST ;TEST FOR FILE EXISTENCE AND RETURN ; IF FILE DOESN'T EXIST; ABORT IF IT DOES LDA TEMPDR ;SAVE CURRENT DEFAULT DISK PUSH PSW ;SAVE ON STACK REN0: LXI H,FCBDN ;SAVE NEW FILE NAME LXI D,FCBDM LXI B,16 ;16 BYTES LDIR CALL ADVAN ;ADVANCE CIBPTR CPI '=' ;'=' OK JRNZ REN4 REN1: XCHG ;PT TO CHAR AFTER '=' IN HL INX H SHLD CIBPTR ;SAVE PTR TO OLD FILE NAME CALL SCANER ;EXTRACT FILENAME.TYP TOKEN JRNZ REN4 ;ERROR IF ANY '?' POP PSW ;GET OLD DEFAULT DRIVE MOV B,A ;SAVE IT LXI H,TEMPDR ;COMPARE IT AGAINST CURRENT DEFAULT DRIVE MOV A,M ;MATCH? ORA A JRZ REN2 CMP B ;CHECK FOR DRIVE ERROR MOV M,B JRNZ REN4 REN2: MOV M,B XRA A STA FCBDN ;SET DEFAULT DRIVE LXI D,FCBDN ;RENAME FILE MVI C,17H ;BDOS RENAME FCT CALL GRBDOS RNZ REN3: CALL PRNNF ;PRINT NO FILE MSG REN4: JMP ERRLOG ; ENDIF ;RAS ; ;Section 5G ;Command: USER ;Function: Change current USER number ;Forms: ; USER Select specified user number; is in DEC ; IF DRUSER ;IF DRIVE/USER CODE OK... USER: CALL USRNUM ;EXTRACT USER NUMBER FROM COMMAND LINE MOV E,A ;PLACE USER NUMBER IN E SUSER: CALL SETUSR ;SET SPECIFIED USER ENDIF ;DRUSER RSTJMP: JMP RCPRNL ;RESTART CPR ; ;Section 5H ;Command: DFU ;Function: Set the Default User Number for the command/file scanner ; (MEMLOAD) ; Note: When under SECURE mode, this will select the second ; user area to check for programs (normally user 15). ; ;Forms: ; DFU Select Default User Number; is in DEC ; IF NOT RAS ;NOT FOR REMOTE-ACCESS SYSTEM DFU: CALL USRNUM ;GET USER NUMBER STA DFUSR ;PUT IT AWAY JR RSTJMP ;RESTART CPR (NO DEFAULT LOGIN) ENDIF ;NOT RAS ; ;Section 5I ;Command: JUMP ;Function: To Call the program (subroutine) at the specified address ; without loading from disk ;Forms: ; JUMP Call at ; is in HEX ; IF NOT RAS ;NOT FOR REMOTE-ACCESS SYSTEM ; JUMP: CALL HEXNUM ;GET LOAD ADDRESS IN HL JR CALLPROG ;PERFORM CALL ; ENDIF ;RAS ; ;Section 5J ;Command: GO ;Function: To Call the program in the TPA without loading ; loading from disk. Same as JUMP 100H, but much ; more convenient, especially when used with ; parameters for programs like STAT. Also can be ; allowed on remote-access systems with no problems. ; ;Form: ; GO ; IF NOT RAS ;ONLY IF RAS ; GO: LXI H,TPA ;Always to TPA JR CALLPROG ;Perform call ; ENDIF ;END OF GO FOR RAS ; ;Section 5K ;Command: COM file processing ;Function: To load the specified COM file from disk and execute it ;Forms: ; ; COM: LDA FCBFN ;ANY COMMAND? CPI ' ' ;' ' MEANS COMMAND WAS 'D:' TO SWITCH JRNZ COM1 ;NOT , SO MUST BE TRANSIENT OR ERROR LDA TEMPDR ;LOOK FOR DRIVE SPEC ORA A ;IF ZERO, JUST BLANK JZ RCPRNL DCR A ;ADJUST FOR LOG IN STA TDRIVE ;SET DEFAULT DRIVE CALL SETU0D ;SET DRIVE WITH USER 0 CALL LOGIN ;LOG IN DRIVE ; IF DRUSER ;DRIVE/USER HACKERY OK? CALL USRNUM ;GET USER #, IF ANY MOV E,A ;GET IT READY FOR BDOS LDA FCBFN ;SEE IF # SPECIFIED CPI ' ' JRNZ SUSER ;SELECT IF WANTED ENDIF ;DRUSER ; JMP RCPRNL ;RESTART CPR COM1: LDA FCBFT ;FILE TYPE MUST BE BLANK CPI ' ' JNZ ERROR LXI H,COMMSG ;PLACE DEFAULT FILE TYPE (COM) INTO FCB LXI D,FCBFT ;COPY INTO FILE TYPE LXI B,3 ;3 BYTES LDIR LXI H,TPA ;SET EXECUTION/LOAD ADDRESS PUSH H ;SAVE FOR EXECUTION CALL MEMLOAD ;LOAD MEMORY WITH FILE SPECIFIED IN CMD LINE ; (NO RETURN IF ERROR OR TOO BIG) POP H ;GET EXECUTION ADDRESS ; ; CALLPROG IS THE ENTRY POINT FOR THE EXECUTION OF THE LOADED ; PROGRAM. ON ENTRY TO THIS ROUTINE, HL MUST CONTAIN THE EXECUTION ; ADDRESS OF THE PROGRAM (SUBROUTINE) TO EXECUTE ; CALLPROG: SHLD EXECADR ;PERFORM IN-LINE CODE MODIFICATION CALL DLOGIN ;LOG IN DEFAULT DRIVE CALL SCANER ;SEARCH COMMAND LINE FOR NEXT TOKEN LXI H,TEMPDR ;SAVE PTR TO DRIVE SPEC PUSH H MOV A,M ;SET DRIVE SPEC STA FCBDN LXI H,FCBDN+10H ;PT TO 2ND FILE NAME CALL SCANX ;SCAN FOR IT AND LOAD IT INTO FCBDN+16 POP H ;SET UP DRIVE SPECS MOV A,M STA FCBDM XRA A STA FCBCR LXI D,TFCB ;COPY TO DEFAULT FCB LXI H,FCBDN ;FROM FCBDN LXI B,33 ;SET UP DEFAULT FCB LDIR LXI H,CIBUFF-1 COM4: INX H MOV A,M ;SKIP TO END OF 2ND FILE NAME ORA A ;END OF LINE? JRZ COM5 CPI ' ' ;END OF TOKEN? JRNZ COM4 ; ; LOAD COMMAND LINE INTO TBUFF ; COM5: MVI B,-1 ;SET CHAR COUNT LXI D,TBUFF ;PT TO CHAR POS DCX H COM6: INR B ;INCR CHAR COUNT INX H ;PT TO NEXT INX D MOV A,M ;COPY COMMAND LINE TO TBUFF STAX D ORA A ;DONE IF ZERO JRNZ COM6 ; ; RUN LOADED TRANSIENT PROGRAM ; COM7: MOV A,B ;SAVE CHAR COUNT STA TBUFF CALL CRLF ;NEW LINE CALL DEFDMA ;SET DMA TO 0080 CALL SETUD ;SET USER/DISK ; ; EXECUTION (CALL) OF PROGRAM (SUBROUTINE) OCCURS HERE ; EXECADR EQU $+1 ;CHANGE ADDRESS FOR IN-LINE CODE MODIFICATION CALL TPA ;CALL TRANSIENT CALL DEFDMA ;SET DMA TO 0080, IN CASE ;PROG CHANGED IT ON US CALL SETU0D ;SET USER 0/DISK CALL LOGIN ;LOGIN DISK JMP RESTRT ;RESTART CPR ; ;Section 5L ;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 NOT RAS ;NOT FOR REMOTE-ACCESS SYSTEM ; GET: CALL HEXNUM ;GET LOAD ADDRESS IN HL PUSH H ;SAVE ADDRESS CALL SCANER ;GET FILE NAME POP H ;RESTORE ADDRESS JNZ ERROR ;MUST BE UNAMBIGUOUS ; ; FALL THRU TO MEMLOAD ; ENDIF ;RAS ; ; LOAD MEMORY WITH THE FILE WHOSE NAME IS SPECIFIED IN THE COMMAND LINE ; ON INPUT, HL CONTAINS STARTING ADDRESS TO LOAD ; ; EXIT BACK TO CALLER IF NO ERROR. IF COM FILE TOO BIG OR ; OTHER ERROR, EXIT DIRECTLY TO MLERR. ; MEMLOAD: SHLD LOADADR ;SET LOAD ADDRESS CALL GETUSR ;GET CURRENT USER NUMBER STA TMPUSR ;SAVE IT FOR LATER STA TSELUSR ;TEMP USER TO SELECT ; ; MLA is a reentry point for a non-standard CP/M Modification ; This is the return point for when the .COM (or GET) file is not found the ; first time, Drive A: is selected for a second attempt ; MLA: CALL SLOGIN ;LOG IN SPECIFIED DRIVE IF ANY CALL OPENF ;OPEN COMMAND.COM FILE JRNZ MLA1 ;FILE FOUND - LOAD IT ; IF SECURE ; ; IF SECURE ENABLED, SEARCH CURRENT DRIVE, CURRENT USER, THEN ; IF IN WHEEL MODE, SEARCH UNDER LAST USER SET BY DFU (ORIG ; "RESUSR" AFTER WARM BOOT) ON CURRENT DRIVE. IF NOT FOUND, OR ; NOT IN WHEEL MODE, THEN SEARCH ON CURRENT DRIVE, UNDER USER ; "DEFUSR". IF STILL NOT FOUND, LOOK AT SAME SERIES OF USERS ; ON DRIVE A. ; DFLAG EQU $+1 ;MARK IN-THE-CODE VARIABLE MVI A,0 ;HAVE WE CHECKED THIS DRIVE ALREADY? ORA A JRNZ MLA0 ;PASS IF SO TO GO TO DRIVE A: LDA WHEEL ;RESTRICTED PROGS ALLOWED? CPI RESTRCT JRZ MLA00 ;PASS IF NOT PUSH B ;PUSH BC LDA DFUSR ;LOAD DEFAULT USER MOV B,A ;PUT IT IN B LDA TSELUSR ;CHECK CURR USER DFUSR EQU $+1 ;DEFAULT USER LOCATION CPI RESUSR ;RESTRICTED USER? MOV A,B ;ASSUME NOT POP B ;RESTORE BC JRNZ SETTSE ;GO TRY IF NOT MLA00: ;SS IF NOT TSELUSR EQU $+1 ;MARK IN-THE-CODE VARIABLE MVI A,0 ;GET CURR USER SUI DEFUSR ;IS IT UNRESTRICTED COM AREA? JRZ MLA0 ;NO MORE CHOICES IF SO STA DFLAG ;MAKE DFLAG NON-ZERO IF NOT MVI A,DEFUSR ; AND TRY UNRESTRICTED COM AREA SETTSE: ENDIF ;SECURE ; IF NOT SECURE DFUSR EQU $+1 ;MARK IN-THE-CODE VARIABLE MVI A,DEFUSR ;GET DEFAULT USER TSELUSR EQU $+1 ;MARK IN-THE-CODE VARIABLE CPI DEFUSR ;CHECK FOR THE USER AREA.. JRZ MLA0 ;..EQUAL DEFAULT, AND JUMP IF SO ENDIF ;NOT SECURE ; STA TSELUSR ;PUT DOWN NEW ONE MOV E,A CALL SETUSR ;GO SET NEW USER NUMBER JR MLA ;AND TRY AGAIN ; ; ERROR ROUTINE TO SELECT DRIVE A: IF DEFAULT WAS ORIGINALLY SELECTED ; MLA0: LXI H,TEMPDR ;GET DRIVE FROM CURRENT COMMAND XRA A ;A=0 ; IF SECURE STA DFLAG ;ALLOW A: SEARCH ENDIF ;SECURE ; ORA M JNZ MLERR ;ERROR IF ALREADY DISK A: MVI M,1 ;SELECT DRIVE A: ; IF NOT SECURE JR MLA ENDIF ;NOT SECURE ; IF SECURE LDA TMPUSR ;GO TO 'CURRENT' USER CODE JR SETTSE ENDIF ;SECURE ; ; FILE FOUND -- PROCEED WITH LOAD ; MLA1: LOADADR EQU $+1 LXI H,TPA ML2: MVI A,ENTRY/256-1 ;GET HIGH-ORDER ADR OF JUST BELOW CPR CMP H ;ARE WE GOING TO OVERWRITE THE CPR? JRC ML4 ;ERROR IF SO PUSH H ;SAVE ADDRESS OF NEXT SECTOR XCHG ;... IN DE CALL DMASET ;SET DMA ADDRESS FOR LOAD LXI D,FCBDN ;READ NEXT SECTOR CALL READ POP H ;GET ADDRESS OF NEXT SECTOR JRNZ ML3 ;READ ERROR OR EOF? LXI D,128 ;MOVE 128 BYTES PER SECTOR DAD D ;PT TO NEXT SECTOR IN HL JR ML2 ; ML3: DCR A ;LOAD COMPLETE JZ RESETUSR ;IF ZERO, OK, GO RESET CORRECT USER # ; ON WAY OUT, ELSE FALL THRU TO PRNLE ; ; TPA FULL ; ML4: CALL PRNLE ;PRINT MSG AND RESET DEF DMA ; ; TRANSIENT LOAD ERROR ; MLERR: ;NOTE THAT THERE IS AN EXTRA RETURN ADDRESS ON ; THE STACK. IT WILL BE TOSSED WHEN ERROR EXITS ; TO RESTRT, WHICH RELOADS SP. CALL RESETUSR ;RESET CURRENT USER NUMBER ; RESET MUST BE DONE BEFORE LOGIN ERRLOG: CALL DLOGIN ;LOG IN DEFAULT DISK JMP ERROR ;FLAG ERROR ; ; ;Section: 5M ;PASS: Enable wheel mode. ;NORM: Disable wheel mode. ; ; Type PASS to CP/M prompt to enter wheel mode. ; This code can be replaced with PST's PASS.ASM which gives many ; nice little options like no keyboard echo, etc. ; IF INPASS ;WE WANT TO USE THIS CODE, NOT PASS.COM PASS: LXI H,PASSWD ;SET UP POINTERS LXI D,CIBUFF+NCHARS+1 MVI B,PRGEND-PASSWD ;B= LENGTH CKPASS: LDAX D ;TRIAL PW TO A CMP M ;CHECK FOR MATCH JNZ COM ;NOPE.. LOOK FOR PASS.COM INX H ;INCREMENT COUNTER INX D DJNZ CKPASS ;CONTINUE IF MORE MVI A,NOT RESTRCT ;WHEEL = NOT RESTRCT PWOUT: STA WHEEL JMP RESTRT ; NORM: MVI A,RESTRCT JR PWOUT ; PASSWD: DB 'YOURPW' ;YOUR PASSWORD PRGEND: EQU $ ;END OF PASSWORD ; ENDIF ;INPASS ; END