$-print ; ; ZCMD 8080 - an 8080 translation. See below. ; ; ZCMD29 - Z80 CCP replacement - 09/01/86 ; ; ZCMD2 is ZCPR2 modified with special features for RCPM use. ; ;----------------------------------------------------------------------- ; ; ZCMD2 is based on ZCPR2, written by by Richard Conn. It includes ; enhancements of interest primarily for use on RCPM systems, such ; as special time clock printouts to remind remote users how long ; they have been on, extra security features, extended flow path ; control, etc. Any commercial use of ZCMD2 is prohibited. ; ; This program requires a Z80 processor. It can be assembled with ; either MAC.COM or RMAC.COM. It contains special Z80 macros. ; ;----------------------------------------------------------------------- ; ; NOTE: If the AUTO option is set YES, ZCMD2 will auto- ; tically bring up the BYE.COM program on A0: ; This assumes your computer boots itself back ; to CP/M upon a power loss. If you want to not ; activate BYE.COM on power-up, leave the option ; set NO, or temporarily rename the BYE.COM pgm ; to some other name, such as BBYE.COM. Other- ; wise the feature works almost "too well" and a ; simple CTL-C, followed by CR will still bring ; up BYE again, since that does a cold reboot. ; This uses the extended BSOS call 32 that all ; current versions of BYE support. This feature ; permits RCPM systems to resume normal operation ; in the event of a momentary power failure, etc. ; It obsoletes special Submit files formerly used. ; ;---------------------- 8080 Implementation Note -------------------------- ; ; Note: ZCPR has been translated to 8080 code; this version will ; run on 8080/8085 CPU's. All Z80 relative jumps were converted to ; absolute jumps; the balance of Z80 opcodes used were translated to ; short 8080 code routines, each of which is clearly commented. The ; translation requires expansion of the CCP and in the tested implemen- ; tation, submit processing was turned off as was mutiple command line ; buffer, and CMDRUN. Internal stack, internal FCB and internal path ; specification were enabled, however some of the internal commands were ; disabled. You will have to find your own balance between features and size. ; ; Dave Chapman ; April 5, 1987 ; ; Thanks to Charles H. Strom for the idea in his 8080 translation of ZCPR2. ; All code changes in ZCMD29-8080 are pretty well clones of Mr. Strom's ; alterations to ZCPR2. ; ; Also in this release, the file loaded by the AUTO function can be changed ; in the configuration section. This is the file loaded by ZCMD on a cold ; boot if AUTO is YES. Formerly this was 'hard wired' in the buffer section ; of ZCMD. Now it is defined in the configuration section in a macro by just ; entering the number of bytes that will be in the command and the command ; itself in the appropriate lines. ; ; A command to clear the terminal screen was added in this release. The ; string that will clear the screen is entered at CLSDAT in the macro ; below. This will cause the screen to clear when the command CLS is ; executed. ; ; Another alteration here is the path followed when the WHEEL byte is ON. ; Previously there was only one extra drive and user area available. Now ; there is a separate path selected if the WHEEL is ON. See the documen- ; tation in the path area below. ; ; Also added is the ability to passord protect your system. On a cold boot ; you will be asked for a password. If you get it right things will proceed ; normally. If not, the machine sits there & does nothing. ; ; An ECHO command (a la MS-DOS), LPT command, similar to ECHO, but it sends ; the string to the LST: device, and a Q)uick repeat command have been added. ; ; 09/11/87 ; Dave Chapman ; ;-------------------------------------------------------------------------- ; Update History ; ; 09/01/86 Autoload can be used to bring up the system automatically ; v29 in case of a power loss. Set AUTO to YES. This looks to ; see if BYE is already present, if not, brings it up. Re- ; stored normal format once again. Tom Brady loves to chop ; things up. Submit files for autoload on restart will now ; be a thing of the past. Best of all, this change doesn't ; add any extra bytes. - Irv Hoff PRACSA RCPM ; PRACSA RCPM ; ; 07/22/86 Added HBCON and HBLST equates and related code for files ; v28 with high bit set. - Tom Brady ; Decibel Music Group RCPM ; ; 06/08/86 Sets the WHEEL byte and MAXDRV/MAXUSR default values only ; v26 if BYE is NOT present. If BYE is present it (or the BBS) ; will set those values. This eliminates a potential secur- ; ity breach since nearly all BIOS systems jump to the cold ; boot entry point rather than the warm boot entry at CCP+3. ; - Wayne Masters ; Potpourri RCPM ; ; 06/01/86 (Comments/changes superceeded by version 26) ; v25 - Irv Hoff ; ; 01/28/86 Conflict with the Z80 alternate registers and the Osborne ; v24 OS-1 operating system resolved. Acoomplished by replacing ; the Z80 EXX macro with normal PUSH/POP. Read the note for ; Osborne users for more information. Many thanks to Kevin ; Murphy and Roy Ronbinson for their help in defining this ; problem. - Wayne Masters ; Potpourri RCPM ; ; 01/21/86 Corrected serious bug for TRS-80 submit function. Option ; v23 to show 'A0}' if WHEEL byte is on, rather than 'A0>'. ; - Wayne Masters ; Potpourri RCPM ; ; 12/07/85 (Summary) - Options to show time remaining at CP/M prompt. ; v22 One will show wall clock time, one will show time left on ; system (minutes only) and will show total time on system ; with wheel byte set or for users allowed unlimited time. ; ; 10/30/85 (Summary) RMAC can now make a .SPR file. Internal flow ; v21 path expanded an extral level. ; - Wayne Masters ; Potpourri RCPM ; ;----------------------------------------------------------------------- ; ; ; Extensive documentation on ZCPR2 and the utilities in the ZCPR2 system ; can be found in the following manuals: ; ; ZCPR2 Concepts Manual ; ZCPR2 Installation Manual ; ZCPR2 User's Guide ; ZCPR2 Rationale ; ; ******** Structure Notes ******** ; ; ZCMD2 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 ZCMD2 ; 1 Buffers ; 2 CPR Starting Modules ; 3 Utilities ; 4 CPR Utilities ; 5 CPR-Resident Commands and Functions ; ;------------------------------------------------------------------------------ ; CR EQU 0DH LF EQU 0AH TAB EQU 09H ; WBOOT EQU 0000H ; CP/M warm boot address UDFLAG EQU 0004H ; User num in high nybble, disk in low BDOS EQU 0005H ; BDOS function call entry point TFCB EQU 005CH ; Default FCB buffer TBUFF EQU 0080H ; Default disk I/O buffer TPA EQU 0100H ; Base of TPA ; MACLIB Z8080HDR ; User configuration ; ;------------------------------------------------------------------------------ ; **** Section 0 **** ; ; Entry point into ZCMD2 ; ; IF MULTCMD (MULTIPLE COMMANDS ON ONE LINE) is NO: If ZCMD2 is entered ; at location CCPLOC (at the JMP to CPR), then the default command in ; CMDLIN will be processed. If ZCMD2 is entered at location CCPLOC+3 ; (at the JMP to CPR1), then the default command in CMDLIN will NOT be ; processed. NOTE: Entry into ZCMD2 at CCPLOC 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). Some user ; programs (such as SYNONYM3) attempt to use the default command fa- ; cility. Under the original CPR, it was necessary to initialize the ; pointer after the reserved space for the command buffer to point to ; the first byte of the command buffer. The NXTCHR (NeXT CHaRacter ; pointer) is located to be compatable with such programs (if they de- ; termine the buffer length from the byte at BUFSIZ [CCPLOC + 6]), but ; under ZCMD2 this is no longer necessary. ZCMD2 automatically initial- ; izes this buffer pointer in all cases if MULTCMD is not enabled. ; ; IF MULTCMD is YES: Entry at CPR or CPR1 has the same effect. Multiple ; command processing will still continue. Hence, if MULTCMD is NO, 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 exe- ; cuted. If MULTCMD is YES, a user program must load this buffer as be- ; fore, 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 ; it is worth the sacrifice. The ZCMD2 utilities of STARTUP and MENU ; require multiple commands, and this feature also permits simple chaining ; of programs to be possible under the ZCMD2 environment. ; IF NOT MAKESPR ORG CCPLOC ENDIF ; ; ENTRY: ; ; Comes here on a cold boot (RESTART or RESET). If 'AUTO' option above ; is set 'YES', checks to see if 'BYE.COM' is already in use, if not, ; autoloads BYE.COM. This would not be needed if the BIOS was written ; to correctly jump to CCP+3 on a warm boot, but very few BIOS will do ; that properly - nearly all jump only to CCP+0 for warm or cold boots. ; IF OZFLOP JMP BOOTJMP ; Used to properly set the Osborne CCP. ; If using ZCMD2 from the floppy disk ; system tracks, the first two bytes ; must be C3H, 5CH ENDIF ; OZFLOP IF NOT OZFLOP JMP CPR ; Process potential default command ENDIF ; NOT OZFLOP ; ; ; Should come here (CCP+3) on a warm boot, but very few CP/M BIOS are ; written to jump to this address at any time for any reason. This is ; why the 'AUTO' option is necessary, to autoload BYE.COM for RCPM use. ; This precludes using .SUB files and setting the SUBON option. ; JMP CPR1 ; Do not process potential default cmd ; ;----------------------------------------------------------------------- ; **** 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 3 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 ; CMDLIN. This command line is terminated by a binary zero. ZCMD2 then ; parses, interprets, and executes the command line. Case is not signi- ; ficant in the command line. ZCMD2 converts all lower-case letters to ; upper-case. If MULTCMD is YES, then the user must set a pointer to ; the first character of the command line into the buffer NXTCHR. If ; MULTCMD is NO, no action other than placing a zero-terminated command ; line into the buffer starting at CMDLIN is required on the part of the ; user. For multiple commands, the command line buffer (CMDLIN) is lo- ; cated external to ZCMD2 so that it is not overlayed during warm boots; ; the same is YES 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. ; IF MULTCMD AND EXCBUF NXTCHR EQU CLBASE ; 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) ENDIF ; MULTCMD AND EXCBUF ; ; ; These buffers are left internal to ZCMD2 so that the original CCP ; command line facility (as used by programs like SYNONYM3) can be left ; intact. ; IF AUTO AND NOT EXCBUF BUFLEN EQU 80 ; Maximum buffer length BUFSIZ: DB BUFLEN ; Maximum buffer length AUTOCMD ; Auto load command from macro above DB 0 ; Command string terminator DS BUFLEN-($-CMDLIN)+1 ; Total is 'BUFLEN' bytes NXTCHR: DW CMDLIN ; Pointer to command input buffer ENDIF ; AUTO AND NOT EXCBUF ; IF NOT AUTO AND NOT EXCBUF 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 ; NOT AUTO AND NOT EXCBUF ; ; ; File type for command ; COMMSG: COMTYP ; Use macro from ZCMDHDR.LIB ; ; ; Submit file control block ; IF SUBON ; If submit facility enabled ... SUBFCB: DB 1 ; Disk name set to default to drive A: DB '$$$' ; File name DB ' ' SUBTYP ; Use macro from ZCMDHDR.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 ; ; ; Command file control block ; IF EXTFCB ; May be placed external to ZCMD2 FCBDN EQU FCBADR ; 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 ENDIF ; EXTFCB ; IF NOT EXTFCB 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 ; NOT EXTFCB ; ; ; Line count buffer ; PAGCNT: DB NLINES-2 ; Lines left on page ; ; CPR command name table - each table entry is composed of the four-byte ; command and two-byte address. ; CMDTBL: CTABLE ; Define command table via macro in ; ; ZCMDHDR.LIB file NCMNDS EQU ($-CMDTBL)/(NCHARS+2) ; ;----------------------------------------------------------------------- ; **** Section 2 **** ; ; ZCMD2 starting points. ; ; CPR: LXI SP,STACK ; Set the stack ; ; Prompt user for password & verify. If password ok then proceed normally. ; If incorrect password entry then sit there & look stupid. ; This code plagerized from Irv Hoff's WHEEL.ASM. 27/05/87 - dlc ; IF PWDON PUSH B PUSH D LXI H,PWDMSG CALL PRIN1 ASK0: LXI D,INPASS ; Put password here for compare ASK1: PUSH D MVI C,6 ; Direct console I/O MVI E,0FFH ; Ask for character CALL BDOS POP D ; Get password address back ORA A JZ ASK1 CALL UCASE ; Put their answer in upper case CPI CR ; Are they finished? JZ CHECK ; Yes, go check password STAX D ; Not done, store character INX D ; Bump pointer JMP ASK1 ; Get the next character ; CHECK: LXI H,INPASS ; Point to their entry LXI D,PSSWRD ; Point to actual password CHECK1: LDAX D ; Get character ORA A ; Done? JZ ALLOK ; Yes, carry on with ZCMD ANI 7FH ; Not done, strip parity CMP M ; Compare JNZ ASK0 ; Invalid char, get password entry again XRA A ; Character ok. now zero it STAX D ; in the password buffers MOV M,A INX H ; Point to the next entry INX D JMP CHECK1 ; Do the next compare ; ALLOK: POP D ; Restore registers POP B LXI SP,STACK ; Restore stack ; IF INTPWD PWDMSG: DB CR,LF ; Prompt for password DB 'Password:',' '+80H PSSWRD: PWD ; Password from ZCMDHDR.LIB DB 0 ; Terminating null INPASS: DS 0FH ; User's entry stored here ENDIF ; INTPWD ENDIF ; PWDON ;..... ; ; ; Now see if BYE is running. ; PUSH B PUSH D MVI A,CR CALL CONOUT ; This is required to make BYE's BDCHEK MVI C,32 ; Reset locations 6 and 7 after warmboot MVI E,241 CALL BDOS ; Call BYE's BDOS POP D POP B CPI 77 ; BYE up and running? ; IF AUTO JZ CPR1 ; BYE5 already running, zero cmdline ENDIF ; AUTO ; IF NOT AUTO JZ CPR2 ; Yes, continue without setting defaults ENDIF ; NOT AUTO ; IF USRMAX MVI A,MAXUSR+1 ; Set USRMAX on cold boot STA USRMAX ENDIF ; USRMAX ; IF DRVMAX MVI A,MAXDISK-1 ; Set DRVMAX on cold boot STA DRVMAX ENDIF ; DRVMAX ; IF USRMAX OR DRVMAX MVI A,0FFH STA WHLADR ; Set WHEEL ENDIF ; USRMAX OR DRVMAX ; JMP CPR2 ; On to coldboot routine ; ; Start ZCMD2 and don't process default command stored if multiple com- ; mands are not allowed. This is the warmboot entry. ; CPR1: IF NOT MULTCMD ; If multiple commands not allowed XRA A ; For no default command STA CMDLIN ; First char of buffer ENDIF ; Not multcmd ; ; ; Start ZCMD2 and possibly process default command ; ; NOTE: BDOS returns 0FFH in A-register 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. ; CPR2: ; Process default command if present ; This is the cold boot entry LXI SP,STACK ; Reset stack ; IF NOT MULTCMD ; Only one command permitted LXI H,CMDLIN ; Set ptr to beginning of command line SHLD NXTCHR ENDIF ; NOT MULTCMD ; PUSH B MOV A,C ; C=user/disk number (see loc 4) RAR ; Extract user number RAR RAR RAR ANI 0FH STA CURUSR ; Set user CALL SETUSR CALL RESET ; Reset disk system ; IF SUBON ; If submit facility enabled STA RNGSUB ; Save submit clue from drive A: ENDIF ; SUBON ; IF MAKESPR BIOS EQU 0 ; So we don't get assembler errors PUSH H LHLD 0000H+1 ; Get BIOS vector LXI B,3 DAD B ; Point to BIOS+6 (console status) SHLD BIOCAL2+1 DAD B ; Point to BIOS+9 (console input) SHLD BIOCAL1+1 SHLD BIOCAL3+1 SHLD BIOCAL4+1 POP H ; This was missing from v2.0 < wm > ENDIF ; MAKESPR ; POP B MOV A,C ; C=user/disk number (see loc 4) ANI 0FH ; Extract current disk drive STA CURDR ; Set it CALL LOGIN ; Log in default disk CALL SETUD ; Set user/disk flag CALL DEFDMA ; Set default dma address ; IF SUBON ; Check for $$$.SUB 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) ORA A ; Set flags on clue CNZ SEAR1 STA RNGSUB ; Set flag (0=no $$$.SUB) ENDIF ; SUBON ; ; ; Test for next command in continuous loop if multiple command line buf- ; fer is enabled. ; IF MULTCMD CONT: ENDIF ; MULTCMD ; LHLD NXTCHR ; Point to next character to process MOV A,M ; Get it CPI 3 ; Restart if CTL-C JZ RESTRT ORA A ; 0 if no command line present JNZ RS1 ; ; ; Test for any default command before continuous loop entered if mul- ; tiple command line buffer is disabled. ; IF NOT MULTCMD CONT: ENDIF ; NOT MULTCMD ; ; ; Prompt user and input command line from him. ; RESTRT: LXI SP,STACK ; Reset stack ; ; Print prompt: DU>. ; CALL CRLF ; Print prompt ; IF B5CLOCK OR B5TLOS MVI C,32 MVI E,241 CALL BDOS CPI 77 ; Is BYE5 running? CZ TIME ; Yes, display [HH:MM] or [NN] LDA CURUSR CALL SETUSR ; Fixes the submit function for TRS-80 ENDIF ; B5CLOCK OR B5TLOS ; LDA CURDR ; Current drive is part of prompt ADI 'A' ; Convert to ASCII A-P CALL CONOUT LDA CURUSR ; Get user number ; IF SUPRES ORA A JZ RS000 ENDIF ; SUPRES ; CPI 10 ; User < 10? JC 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: LXI H,CMDLIN ; Set pointer to first character SHLD NXTCHR ; Pointer to next character to process MVI M,0 ; Zero out command line PUSH H ; Save pointer CALL REDBUF ; Input command line from user POP H ; Get pointer MOV A,M ; Check for comment line CPI COMMENT ; Begins with comment character? JZ RESTRT ; Input another line if so ORA A ; No input? JZ RESTRT ; ; ; Process input line - HL points to first letter of command. ; RS1: LXI SP,STACK ; Reset stack ; IF MULTCMD ; Multiple commands allowed? MOV A,M ; Get first char of command CPI CMDSEP ; Is it a command separator? JNZ RS2 INX H ; Skip it if it is SHLD NXTCHR ; Set pointer back ENDIF ; MULTCMD ; ; ; Set pointer for multiple command line processing to first character of ; new command. ; RS2: SHLD CMDCH1 ; Set pointer to first character ; ; ; Capitalize command line ; CAPBUF: MOV A,M ; Capitalize command character CALL UCASE MOV M,A INX H ; Point to next character ORA A ; EOL? JNZ CAPBUF NOUP: CALL SCANER ; Parse command name from command line JNZ ERROR ; Error if command name contains a '?' LXI D,RSTCPR ; Put return address of command PUSH D ; On the stack ; COLON EQU $+1 ; Flag for in-the-code modification MVI A,0 ; Command of the form 'DU:command'? ORA A ; 0=no JNZ COM ; Process as COM file if not 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 current user/disk ; ; ; 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 CPI ' ' ; Any char? JZ CONT ; Continue with next command if no error ; ; ; Invalid command - print it. ; ERROR: CALL CRLF ; New line ; CURTOK EQU $+1 ; Pointer for in-the-code modification LXI H,0 ; Point to beginning of command line ; ERR1: MOV A,M ; Get character CPI ' '+1 ; Simple '?' if or less JC ERR2 CALL CONOUT ; Print command char INX H ; Point to next char JMP ERR1 ; Continue ; ERR2: CALL PRINT ; Print '?' DB '?'+80H ; ERR3: CALL DLOGIN ; Panic restore of default user/disk ; IF SUBON ; If submit facility is on CALL SUBKIL ; Terminate active $$$.SUB if any ENDIF ; SUBON ; JMP RESTRT ; Restart CPR ;..... ; ; ; No File Error Message. ; PRNNF: CALL PRINTC ; No file message DB 'No Fil','e'+80H RET ;..... ; ; ;----------------------------------------------------------------------- ; **** Section 3 **** ; I/O utilities ; ; Output character in A-register to CRT and don't change BC. ; ; Output ; CRLF: MVI A,CR CALL CONOUT MVI A,LF JMP CONOUT ; CONIN: MVI C,1 ; Input character CALL BDOS ; Get input character with ^S JMP UCASE ; Capitalize ; CONOUT: PUSH B PUSH D PUSH H MVI C,2 ; OUTPUT: MOV E,A CALL BDOS POP H POP D POP B RET ;..... ; ; LCOUT: PUSH PSW ; Output character to CRT ; PRFLG EQU $+1 ; Pointer for in-the-code modification MVI A,0 ; 2nd byte (immediate argument) ORA A ; 0=type JZ LC1 POP PSW ; Get character ; ; ; Output character in A-register to list device. ; LSTOUT: PUSH B ; Save regs PUSH D PUSH H MVI C,5 JMP OUTPUT ; LC1: POP PSW ; Get character PUSH PSW CALL CONOUT ; Output to CRT POP PSW CPI LF ; Check for paging RNZ ; ; ; Paging routines - PAGER counts down lines and pauses for direct input ; if count expires, PAGSET sets lines per page count. ; PAGER: PUSH H LXI H,PAGCNT ; Count down DCR M JNZ PAGER1 ; 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 PGDFLG equate CPI PGDFLG ; Page default override option wanted? ; IF PGDFLT ; If paging is default JZ PAGER1 ; PGDFLG means no paging, please ENDIF ; PGDFLT ; IF NOT PGDFLT JNZ PAGER1 ; PGDFLG means please paginate ENDIF ; NOT PGDFLT ; PUSH B ; Save registers ; BIOCAL1:CALL BIOS+9 ; BIOS console input routine POP B ; Get register CPI 'C'-'@' ; ^C JZ RSTCPR ; Restart CPR ; PAGER1: POP H ; Restore HL RET ;..... ; ; ; Read file block function. ; READF: LXI D,FCBDN ; Fall through to read ; READ: MVI C,14H ; Fall through to BDOSB ; ; ; Call BDOS and save BC. ; BDOSB: PUSH B CALL BDOS POP B ORA A RET ;..... ; ; ; Print string (ending in character with MSB set) pointed to by return ; address - start with . ; PRINTC: CALL CRLF ; New line ; PRINT: XTHL ; Get pointer to string CALL PRIN1 ; Print string XTHL ; Restore HL and return address RET ;..... ; ; ; Print string (ending in 0 or byte with MSB set) pointed to by HL. ; PRIN1: MOV A,M ; Get next byte INX H ; Point to next byte ORA A ; End of string? RZ ; String terminated by binary 0 PUSH PSW ; Save flags ANI 7FH ; Mask out MSG CALL CONOUT ; Print character POP PSW ; Get flags RM ; String terminated by MSB set JMP PRIN1 ;..... ; ; ; BDOS function routines. ; ; ; Return number of current disk in A. ; GETDRV: MVI C,19H JMP BDOSJP ;..... ; ; ; Set 80H as DMA address. ; DEFDMA: LXI D,TBUFF ; 80H=TBUFF ; DMASET: MVI C,1AH JMP BDOSJP ; RESET: MVI C,0DH ; BDOSJP: JMP BDOS ;..... ; ; LOGIN: MOV E,A MVI C,0EH JMP BDOSJP ; Save some code space ;..... ; ; OPENF: XRA A STA FCBCR LXI D,FCBDN ; Fall thrrough to OPEN ; OPEN: MVI C,0FH ; Fall through to GRBDOS ; GRBDOS: CALL BDOS INR A ; Set zero flag for error return RET ;..... ; ; CLOSE: MVI C,10H JMP GRBDOS ;..... ; ; SEARF: LXI D,FCBDN ; Specify FCB ; SEAR1: MVI C,11H JMP GRBDOS ;..... ; ; SEARN: MVI C,12H JMP GRBDOS ;..... ; ; ; Check for submit file in execution and abort if so. ; IF SUBON ; Enable if submit facility is enabled 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 ENDIF ; SUBON ; DELETE: MVI C,13H JMP BDOSJP ; Save more space ;..... ; ; ; Get/set user number. ; GETUSR: MVI A,0FFH ; Get current user number ; SETUSR: MOV E,A ; User number in E MVI C,20H ; Set user number to value in E JMP BDOSJP ; More space saving ;..... ; ; ; end of BDOS Functions ;----------------------------------------------------------------------- ; **** Section 4 **** ; ZCMD2 utilities. ; ; Set user/disk flag to current user and default disk. ; SETUD: CALL GETUSR ; Get number of current user ANI 0FH ; Mask sure 4 bits ADD A ; Place it in high nybble ADD A ADD A ADD A LXI H,CURDR ; Mask in current drive number ORA M ; Mask in STA UDFLAG ; Set user/disk number RET ;..... ; ; ; Convert character in A to upper-case. ; UCASE: ANI 7FH ; Mask out MSB CPI 61H ; Lower-case 'a' RC CPI 7BH ; Greater than lower-case 'z' RNC ANI 5FH ; Capitalize RET ;..... ; ; ; Input next command to CPR - This routine determines if a SUBMIT file ; is being processed and extracts the command line from it if so or from ; the user's console. ; REDBUF: IF SUBON ; Check for submit facility enabled LDA RNGSUB ; Submit file currently in execution? ORA A ; 0=no JZ RB1 ; Get line from console if not LXI D,SUBFCB ; Open $$$.SUB PUSH D ; Save DE CALL OPEN POP D ; Restore DE JZ RB1 ; Erase $$$.SUB if end of file LDA SUBFRC ; Get value of last record in file DCR A ; Pt to next to last record STA SUBFCR ; New value of last record in $$$.SUB CALL READ ; DE=SUBFCB JNZ RB1 ; Abort $$$.SUB if error LXI D,CHRCNT ; Copy last record (next submit cmnd) LXI H,TBUFF ; From TBUFF LXI B,BUFLEN ; Number of bytes CALL LDIRS ; LDIR substitute LXI H,SUBFS2 ; Point to S2 of $$$.SUB FCB MVI M,0 ; Set S2 to zero INX H ; Point to record count DCR M ; Decrement record count of $$$.SUB LXI D,SUBFCB ; Close $$$.SUB CALL CLOSE JZ RB1 ; Abort $$$.SUB if error MVI A,SPRMPT ; Print submit prompt CALL CONOUT LXI H,CMDLIN ; Print command line from $$$.SUB CALL PRIN1 CALL BREAK ; Check for abort (any char) RNZ ; If no ^C, return to caller and run CALL SUBKIL ; Kill $$$.SUB if abort JMP RESTRT ; Restart CPR ;.... ; ; ; Input command line from user console. ; RB1: CALL SUBKIL ; Erase $$$.SUB if present ENDIF ; SUBON ; IF NOT WHEEL MVI A,CPRMPT ; Print prompt ENDIF ; NOT WHEEL ; IF WHEEL LDA WHLADR ORA A ; WHEEL on? MVI A,CPRMPT ; Normal prompt JZ RB2 ; No, continue with normal prompt MVI A,WCPRMPT ; Else, select alternate prompt ENDIF ; WHEEL ; RB2: CALL CONOUT B3: MVI C,0AH ; Read command line from user LXI D,BUFSIZ CALL BDOS ; ; ; Store zero at end of command line. ; LXI H,CHRCNT ; Point to character count MOV A,M ; Get character count INX H ; Point to first character of command line IF QON PUSH H ; Save it ENDIF ; QON CALL ADDAH ; Point to after last char of command line MVI M,0 ; Store ending zero ; IF QON ; If repeat command POP H ; Restore first character pointer MOV A,M ; Get the character CALL UCASE CPI 'Q' ; Is it a repeat command? JNZ COPYR ; No, carry on INX H ; Its a 'Q'; is it MOV A,M ; a repeat command request? ORA A JNZ COPYR ; Nope, carry on CALL PRINT DB 0CH,0CH,0CH+80H LXI H,EQBASE + 4 ; They want to repeat the last command CALL PRIN1 ; Print it for them LXI H,EQBASE ; Get the preserved command line LXI D,CLBASE ; And the CPR command buffer JMP MOVE1 ENDIF ; QON ; IF ECHON OR QON OR LPTON ; Copy the command to the second (EQ) buffer. ; ; Instead of writing our own routine to move the commands between buffers ; until the terminatng null is encountered we'll use the LDIRS subroutine ; and copy the entire buffer. This will waste a little bit of time but save ; a few bytes. Space is getting tight here. Lets hope they kept EQLEN equal ; to BUFLEN. ; COPYR: LXI H,CLBASE ; Start of command buffer LXI D,EQBASE ; Start of EQ buffer LXI B,BUFLEN ; Count for move JMP LDIRS ; Return from LDIRS ELSE ; IF NOT (ECHON OR QON OR LPTON) RET ; Return from here ENDIF ; ECHON OR QON OR LPTON ;..... ; ; ; Check for any character from user console, return with zero set if ; none. ; BREAK: PUSH B ; Save registers PUSH D PUSH H ; BIOCAL2:CALL BIOS+6 ; Console status check ORA A ; Set flags ; BIOCAL3:CNZ BIOS+9 ; Get input char with ^S processing CPI 'S'-'@' ; Pause if ^S ; BIOCAL4:CZ BIOS+9 ; Get next character POP H ; Restore registers POP D POP B CPI 'C'-'@' ; Check for abort RET ;..... ; ; ; Check to see if DE points to delimiter, if so return with zero flag ; set. ; SDELM: LDAX D ORA A ; 0=delimiter RZ CPI ' '+1 ; Delim if <= JC ZERO CPI '=' ; '='=delimiter RZ CPI 5FH ; Underscore=delimiter RZ CPI '.' ; '.'=delimiter RZ CPI ':' ; ':'=delimiter RZ CPI ',' ; ','=delimiter RZ CPI ';' ; ';'=delimiter RZ CPI '<' ; '<'=delimiter RZ CPI '>' ; '>'=delimiter ; IF MULTCMD ; Multiple commands allowed? RZ CPI CMDSEP ; Command separator ENDIF ; MULTCMD ; RET ; ZERO: XRA A ; Set zero flag RET ;..... ; ; ; Advance input pointer to first non-blank and fall through to SBLANK. ; ADVAN: XCHG ; LDED replacement LHLD NXTCHR ; Point to next character XCHG ; End LDED replacement ; ; ; Skip string pointed to by DE (string ends in 0 OR CMDSEP) until end of ; string or non-delimited encountered (beginning of token). ; SBLANK: LDAX D ; Get character ORA A ; Zero? RZ ; IF MULTCMD ; Multiple commands allowed? CPI CMDSEP ; Command separator? RZ ENDIF ; MULTCMD ; CALL SDELM ; Skip over delimiter RNZ INX D ; Advance to next char JMP SBLANK ;..... ; ; ; Add A ro HL (HL=HL+A). ; ADDAH: ADD L MOV L,A RNC INR H RET ;..... ; ; ; Extract decimal number from command line - return with value in A-reg. ; 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 characters maximum ; ; ; Check for suffix for hexadecimal number. ; NUMS: MOV A,M ; Get character from end DCX H ; Back up CPI ' ' ; Space? JNZ NUMS1 ; Check for suffix DCR B ; DJNZ replacement JNZ NUMS JMP NUM0 ; By default, process ; NUMS1: CPI NUMBASE ; Check against base switch flag JZ HNUM0 ; ; ; Process decimal number. ; NUM0: LXI H,FCBFN ; Point to beginning of token ; NUM0A: LXI B,1100H ; C=accumulated value, B=char count ; ; (C=0, B=11) NUM1: MOV A,M ; Get character CPI ' ' ; Done if JZ NUM2 CPI ':' ; Done if colon JZ NUM2 INX H ; Pt to next char SUI '0' ; Convert to binary CPI 10 ; Error if >= 10 JNC NUMERR MOV D,A ; Digit in D MOV A,C ; New value = old value * 10 RLC ; *2 JC NUMERR RLC ; *4 JC NUMERR RLC ; *8 JC NUMERR ADD C ; *9 JC NUMERR ADD C ; *10 JC NUMERR ADD D ; New value = old value * 10 + digit JC NUMERR ; Check for range error MOV C,A ; Set new value DCR B ; DJNZ replacement JNZ NUM1 ; ; ; Return from number. ; NUM2: MOV A,C ; Get accumulated value RET ;..... ; ; ; Number error routine for space conservation. ; NUMERR: JMP ERROR ; Use error routine ;..... ; ; ; Extract hexadecimal number from command line - return with value in ; A-reg, all registers may be affected. ; HEXNUM: CALL SCANER ; Parse number and place in FCBFN ; HNUM0: LXI H,FCBFN ; Point to token for conversion LXI D,0 ; De=accumulated value MVI B,11 ; B=character ; HNUM1: MOV A,M ; Get character CPI ' ' ; Done? JZ HNUM3 ; Return if so CPI NUMBASE ; Done if numbase suffix JZ HNUM3 SUI '0' ; Convert to binary JC NUMERR ; Return and done if error CPI 10 ; 0-9? JC HNUM2 SUI 7 ; A-F? CPI 10H ; Error? JNC NUMERR ; HNUM2: INX H ; Point to next characer 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 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 DCR B ; DJNZ replacement JNZ HNUM1 ; ; ; Return from HEXNUM. ; HNUM3: XCHG ; Returned value in HL MOV A,L ; Low-order byte in A RET ;..... ; ; ; Point to directory entry in TBUFF whose offset is specified by A and C. ; DIRPTR: LXI H,TBUFF ; Point to temporary buffer ADD C ; Point to 1st byte of directory entry CALL ADDAH ; Point to desired byte in dir entry MOV A,M ; Get desired byte RET ;..... ; ; ; Check for specified drive and log it in. ; SLOGIN: XRA A ; A=0 for default disk STA FCBDN ; Select default disk since user/disk ; TEMPDR EQU $+1 ; Pointer for in-the-code modification MVI A,0 ; 2nd byte (immediate arg) is TEMPDR ORA A ; 0=current drive JNZ SLOG1 LDA CURDR ; Log in current drive INR A ; Add 1 for next DCR ; SLOG1: DCR A ; Adjust for proper disk number (A:=0) CALL LOGIN ; Log in new drive ; TEMPUSR EQU $+1 ; Pointer for in-the-code modification MVI A,0 ; 2nd byte is user to be selected JMP SETUSR ; Log in new user ;..... ; ; ; Check for specified drive and log in default drive. ; DLOGIN: DS 0 ; CURDR EQU $+1 ; Pointer for in-the-code modification MVI A,0 ; Prep to log in current drive ; CALL LOGIN ; Login current drive ; CURUSR EQU $+1 ; Pointer for in-the-code modification MVI A,0 ; Prep to log in current user number JMP 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: LDA WHLADR ; Get wheel byte ORA A ; Zero? RNZ ; Ok if not JMP ERROR ; Process as error ENDIF ; WHEEL ;..... ; ; ; Extract token from command line and place it into FCBDN, format FCBDN ; FCB if token resembles file name and type (FILENAME.TYP). On input, ; NXTCHR points to character at which to start scan. On output, NXTCHR ; points to character at which to continue and zero flag is reset if ; if '?' is in token ; ; Entry points: ; SCANLOG - load token into first FCB and log in temp user/disk ; SCANER - load token into first FCB ; SCANX - load token into FCB pointed to by 'HL' ; SCANLOG:CALL SCANER ; Do scan PUSH PSW ; Save flag CALL SLOGIN ; Log in temporary user/disk POP PSW ; Get flag RET ;..... ; ; SCANER: LXI H,FCBDN ; Point to FCBDN ; SCANX: XRA A ; A=0 STA TEMPDR ; Set temporary drive number to default MOV M,A ; Set first byte of FCBDN STA COLON ; Set no colon flag LDA CURUSR ; Get current user STA TEMPUSR ; Set tempusr CALL ADVAN ; Skip to non-blank or end of line XCHG ; SDED replacement SHLD CURTOK ; Set ptr to non-blank or end of line XCHG ; End of SDED replacement MVI B,11 ; Prep for possible space fill JZ SCAN4 ; Done if EOL ; ; ; Scan token for DU: form, which means we have a user/disk specification ; DE points to next character in line, HL points ro FCBDN. ; PUSH D ; Save pointer to first character CALL SDELM ; Check for delimiter and get first char CPI 'A' ; In letter range? JC SCAN1 CPI 'P'+1 ; In letter range? JC SCAN1A ; SCAN1: CPI '0' ; Check for digit range JC SCAN2 CPI '9'+1 ; In digit range? JNC SCAN2 ; SCAN1A: INX D ; Point to next character CALL SDELM ; Check for delimiter, else digit JMP SCAN1 ; SCAN2: POP D ; Restore ptr to first char CPI ':' ; Was delimiter a colon? JNZ SCAN3 ; Done if no colon STA COLON ; Set colon found ; ; ; Scan for and extract user/disk info - on entry, HL point to FCBDN, DE ; points to first character and A-register contains the first character. ; LDAX D ; Get first character CPI 'A' ; Convert possible drive spec to number JC SUD1 ; If less than 'a', must be digit ; ; ; Set disk number (A=1). ; SUI 'A'-1 ; IF DRVMAX PUSH B ; Save 'BC' PUSH PSW ; Save drive request LDA DRVMAX ; Get maximum legal drive ADI 2 ; Bump it two for the compare MOV B,A ; Save maximum drive in 'B' POP PSW ; Restore drive request CMP B ; See if illegal drive POP B ; Restore BC ENDIF ; DRVMAX ; IF NOT DRVMAX CPI MAXDISK+1 ; Within range? ENDIF ; NOT DRVMAX ; JNC ERROR ; Invalid disk number STA TEMPDR ; Set temporary drive number MOV M,A ; Set FCBDN INX D ; Pt to next char LDAX D ; See if it is a colon (:) CPI ':' JZ SUD2 ; Done if no user number (it is a colon) ; ; ; Set user number. ; SUD1: PUSH H ; Save pointer to FCBDN XCHG ; HL pts to first digit CALL NUM0A ; Get number XCHG ; DE pts to terminating colon ; IF USRMAX LXI H,USRMAX CMP M ENDIF ; USRMAX ; IF NOT USRMAX CPI MAXUSR+1 ; Within limit? ENDIF ; NOT USRMAX ; POP H ; Get pointer to FCBDN JNC ERROR ; IF USERON ; Allow user change if user is allowed STA TEMPUSR ; Save user number ENDIF ; USERON ; SUD2: INX D ; Point to character after colon ; ; ; Extract filename from possible FILENAME.TYP - DE points to next char- ; acter to process, HL points tao FCBDN. ; SCAN3: XRA A ; A=0 STA QMCNT ; Init question mark count 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 LDAX D ; Get last char which stopped scan CPI '.' ; Have a type if de) delimiter is a '.' JNZ SCAN4 ; Fill file type bytes with INX D ; Pt to char in command line after '.' CALL SCANF ; Fill FCB file type JMP SCAN5 ; Skip to next processing ; SCAN4: CALL SCANF4 ; Space fill ; ; ; Fill in EX, S1, S2, and RC with zeroes. ; SCAN5: MVI B,4 ; 4 bytes XRA A ; A=0 CALL SCANF5 ; Fill with zeroes ; ; ; Scan complete -- DE points to delimiter byte after token. ; XCHG ; SDED replacement SHLD NXTCHR XCHG ; End SDED replacement ; ; ; Set zero flag to indicate presence of '?' in FILENAME.TYPE. ; QMCNT EQU $+1 ; Pointer for in-the-code modification MVI A,0 ; Number of question marks ORA A ; Set zero flag to indicate any '?' RET ;..... ; ; ; Scan token pointed to by DE for a max of B bytes; place it into file ; name field pointed to by HL; expand and interpret wild cards of '*' ; '?'; on exit, DE points to terminating delimiter. ; SCANF: CALL SDELM ; Done if delimiter encountered JZ SCANF4 INX H ; Point to next byte in FCBDN CPI '*' ; Is (DE) a wild card? JNZ SCANF1 ; Continue if not MVI M,'?' ; Place '?' in FCB CALL SCQ ; Scanner count question marks JMP SCANF2 ; SCANF1: MOV M,A ; Store filename char in FCB INX D ; Pt to next char in command line CPI '?' ; Check for question mark (wild) CZ SCQ ; Scanner count question marks ; SCANF2: DCR B ; DJNZ replacement JNZ 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 JMP SCANF3 ; ; ; Fill memory pointed to by HL with spaces for B bytes. ; SCANF4: MVI A,' ' ; Fill with spaces ; SCANF5: INX H ; Point to next byte in FCB MOV M,A ; Fill with byte in A-reg. DCR B ; DJNZ replacement JNZ SCANF5 RET ;..... ; ; ; Increment question mark count for scanner - this routine increments ; the count of the number of question marks in the current FCB entry. ; SCQ: PUSH H ; Save HL LXI H,QMCNT ; Get count INR M ; Increment POP H ; Get HL RET ;..... ; ; ; CMDTBL (command table) scanner. ; On return, HL points to address of command if CPR-resident. ; On return, zero flag set means CPR-resident command. ; CMDSER: LXI H,CMDTBL ; Point to command table MVI C,NCMNDS ; Set command counter MOV A,C ; Check number of commands ORA A ; If none, then abort JZ CMS5 ; CMS1: LXI D,FCBFN ; Point to stored command name MVI B,NCHARS ; Number of chars/command (8 max) ; CMS2: LDAX D ; Compare against table entry CMP M JNZ CMS3 ; No match INX D ; Point to next character INX H DCR B ; DJNZ replacement JNZ CMS2 ; Count down LDAX D ; Next char must be a space CPI ' ' JNZ CMS4 RET ; Command is CPR-resident ; ; CMS3: INX H ; Skip to next command table entry DCR B ; DJNZ replacement JNZ CMS3 ; CMS4: INX H ; Skip address INX H DCR C ; Decrement table entry number JNZ CMS1 ; CMS5: INR C ; Clear zero flag RET ; Command is disk-resident ;..... ; ; ;----------------------------------------------------------------------- ; **** Section 5 **** ; ; CPR-resident commands. ; ; ; ; Section: 5A.2 ; Command: LPT ; Function: To echo a string to the list device. ; ; Forms: LPT ; ; Notes: is a string of ASCII characters typed at the console. The ; length of the string is limited to EQLEN - 9. ; IF LPTON LPT: IF WLPT CALL WHLCHK ENDIF ; WLPT MVI A,CR ; Set up printer CALL LSTOUT LXI H,EQBASE + 8 ; Point to string LPT1: MOV A,M ; Fetch character ORA A ; Done ? JZ LPT2 ; Yes, finish up CALL LSTOUT ; Not done, print char INX H ; Bump character pointer JMP LPT1 ; And get the next char LPT2: MVI A,CR ; Force print CALL LSTOUT MVI A,LF ; Send a line feed CALL LSTOUT XRA A ; Zero command line STA CMDLIN + 4 RET ENDIF ; LPTON ;..... ; ; ; Section: 5A.3 ; Command: ECHO ; Function: To echo a string to the console device. ; ; Forms: ECHO ; ; Notes: is a string of ASCII characters typed at the console. The ; The length of the string is limited to EQLEN - 10. ; IF ECHON ECHO: IF WECHO CALL WHLCHK ENDIF ; WECHO CALL CRLF ; New line LXI H,EQBASE + 9 ; Point to string CALL PRIN1 XRA A STA CMDLIN + 5 ; Zero command line RET ENDIF ; ECHON ;..... ; ; ; Section: 5A.4 ; Command: CLS ; Function: To clear the screen of the CRT. Added 05/04/87 - dlc. ; ; Forms: CLS ; IF CLSON CLS: IF WCLS CALL WHLCHK ENDIF ; WCLS CALL PRINT CLSDAT ; Clear screen data from macro above DB 0 ; Terminating zero RET ; Back to ZCPR ENDIF ; CLSON ;..... ; ; ; 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=YES) for 80-col screens. ; ; The flag FENCE defines the character used to separate the file ; names. ; IF DIRON ; DIR enabled DIR: CALL SCANLOG ; Extract possible D:FILENAME.TYP token LXI H,FCBFN ; Make FCB wild (all '?') if no NAME.TYP MOV A,M ; Get first chararacter of NAME.TYPE CPI ' ' ; If space, all wild CZ FILLQ CALL ADVAN ; Look at next input char MVI B,80H ; Prepare for DIR-only selection JZ DIRDN ; There is no flag, so DIR only MVI B,1 ; Set for both DIR and SYS files CPI SYSFLG ; System and DIR flag specifier? JZ GOTFLG ; Got system specifier CPI SOFLG ; SYS only? JNZ DIRDN DCR B ; B=0 for SYS files only ; GOTFLG: INX D ; Pt to char after flag ; DIRDN: XCHG ; SDED replacement SHLD NXTCHR ; Set pointer for next pass then drop ; DIRPR to print directory and go ; restart CPR XCHG ; End SDED replacement 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: MOV A,B ; Get flag STA SYSTST ; Set system test flag MVI E,0 ; Set column counter to zero PUSH D ; Save column counter (E) CALL SEARF ; Search for specified file JNZ DIR3 CALL PRNNF ; Print no file msg; reg A not changed XRA A ; Set zero flag POP D ; Restore de RET ;..... ; ; ; Entry selection loop; on entry, A=offset from SEARF or SEARN ; DIR3: CALL GETSBIT ; Get and test for type of files JZ DIR6 POP D ; Get entry count (= counter) MOV A,E ; Add 1 to it INR E PUSH D ; Save it ANI 03H ; Output if 4 entries printed JNZ DIR4 CALL CRLF ; New line JMP DIR5 ; DIR4: CALL PRINT ; IF WIDE DB ' ' ; 2 spaces DB FENCE ; Then fence char DB ' ',' '+80H ; Then 2 more spaces ENDIF ; WIDE ; IF NOT WIDE DB ' ' ; Space DB FENCE ; Then fence char DB ' '+80H ; Then space ENDIF ; NOT WIDE ; DIR5: MVI B,01H ; Pt to 1st byte of file name MOV A,B ; A=offset CALL DIRPTR ; HL now pts to 1st byte of file name CALL PRFN ; Print file name ; DIR6: CALL BREAK ; Check for abort JZ DIR7 CALL SEARN ; Search for next file JNZ DIR3 ; Continue if file found ; DIR7: POP D ; Restore stack MVI A,0FFH ; Set NZ flag ORA A RET ENDIF ; DIRON OR ERAON ;..... ; ; ; Print file name pointed to by HL. ; PRFN: MVI B,8 ; 8 chars CALL PRFN1 MVI A,'.' ; Dot CALL CONOUT MVI B,3 ; 3 chars ; PRFN1: MOV A,M ; Get char INX H ; Pt to next CALL CONOUT ; Print char DCR B ; Count down JNZ PRFN1 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 re- ; quired by the calling program: ; ; System byte: x 0 0 0 0 0 0 0 after 80H mask, x=1 if SYS ; ; 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 for both ; GETSBIT:DCR A ; Adjust to returned value RRC ; Convert number to offset into TBUFF RRC RRC ANI 60H MOV C,A ; Offset into TBUFF in C MVI A,10 ; Add 10 to point to SYS file attribute CALL DIRPTR ; A=system byte ANI 80H ; Look at only system bit ; SYSTST EQU $+1 ; In-the-code variable XRI 0 ; If SYSTST=0, SYS only; if =80H, DIR RET ; NZ if ok, Z if not ok ;..... ; ; ; Fill FCB @HL with '?'. ; FILLQ: MVI B,11 ; Number of characters in FN & FT ; FQLP: MVI M,'?' ; Store '?' INX H DCR B ; DJNZ replacement JNZ FQLP RET ;..... ; ; ; 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 yes, the V- option is enabled, and the char- ; acter which turns it on (the V) is defined by ; ERDFLG. ; ; ERACK - if yes, the ok? prompt is enabled: ; ; If ERAO is NO, the verification feature is ; disabled regardless of what value ERAV has ; ; If ERAOK is yes, then: ; ; If ERAV is yes, verification is request- ; ed only if the V-flag (actual letter ; defined by ERDFLG) is in the cmd line ; ; If ERAV is NO, verification is always ; requested, and a V-flag in the com- ; mand 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 ; CALL SCANLOG ; Parse file specification ; IF ERAV AND ERAOK ; V-flag and ok? enabled? CALL ADVAN ; Get ERAFLG if it's there STA ERAFLG ; Save it as a flag JZ ERA1 ; Jump if input ended INX D ; Put new buffer pointer ; ERA1: XCHG ; Put pointer into HL SHLD NXTCHR ; Set pointer to byte for next command ENDIF ; ERAV AND ERAOK ; MVI B,1 ; Display all matching files CALL DIRPR ; Print directory of erased files RZ ; Abort if no files ; IF ERAOK ; Print prompt IF ERAV ; Test verify flag ERAFLG EQU $+1 ; Address of flag MVI A,0 ; 2nd byte is flag CPI ERDFLG ; Is it a verify option? JNZ ERA2 ; Skip prompt if it is not ENDIF ; ERAV ; CALL PRINTC DB 'OK to Erase','?'+80H CALL CONIN ; Get reply CPI 'Y' ; Yes? RNZ ; Abort if not ENDIF ; ERAOK ; ERA2: LXI D,FCBDN ; Delete file specified CALL DELETE RET ; Reenter CPR 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: MVI A,0FFH ; Turn on printer flag JMP 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=YES if type pages by default); combined with ; PGDFLG, the following events occur: ; ; If PGDFLT = YES, PGDFLG turns off paging. ; ; If PGDFLT = NO, PGDFLG turns on paging. ; TYPE: XRA A ; Turn off printer flag ; ; ; Entry point for CPR list function (LIST). ; TYPE0: STA PRFLG ; Set flag ; IF WLT ; Wheel on? CALL WHLCHK ; Check wheel byte ENDIF ; WLT ; CALL SCANLOG ; Extract FILENAME.TYP toden JNZ ERROR ; Error if any question marks CALL ADVAN ; Get PGDFLG if it's there STA PGFLG ; Save it as a flag JZ TYPE1 ; Jump if input ended INX D ; Put new buf pointer ; TYPE1: XCHG ; SDED replacement SHLD NXTCHR ; Set pointer for next command XCHG ; End SDED replacement CALL OPENF ; Open selected file JZ ERROR ; Abort if error CALL CRLF ; New line MVI A,NLINES-1 ; Set line count STA PAGCNT LXI B,080H ; Set character position and tab count ; ; ; Main loop for loading next block. ; TYPE2: MOV A,C ; Get character count CPI 80H JC TYPE3 PUSH H ; Read next block PUSH B CALL READF POP B POP H JNZ TYPE7 ; Error? MVI C,0 ; Set character count LXI H,TBUFF ; Point to first character ; ; ; Main loop for printing character in TBUFF. ; TYPE3: MOV A,M ; Get next char ANI 7FH ; Mask out MSB CPI 1AH ; End of file (^Z)? RZ ; Restart CPR if so ; ; ; Output character to CRT or list device with tabulation. ; CPI CR ; Reset tab count? JZ TYPE4 CPI LF ; Reset tab count? JZ TYPE4 CPI TAB ; Tab? JZ TYPE5 ; ; ; Output character and increment character count. ; CALL LCOUT ; Output char INR B ; Increment tab count JMP TYPE6 ; ; ; Output or and reset tab count. ; TYPE4: CALL LCOUT ; Output or MVI B,0 ; Reset tab counter JMP TYPE6 ; ; ; Tabulate. ; TYPE5: MVI A,' ' ; Space CALL LCOUT INR B ; Increment position count MOV A,B ANI 7 JNZ TYPE5 ; ; ; Continue processing. ; TYPE6: INR C ; Increment char count INX H ; Pt to next char CALL BREAK ; Check for abort RZ ; Restart if so JMP TYPE2 ; TYPE7: DCR A ; No error? RZ ; Restart CPR JMP ERROR 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; 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 MOV L,A ; HL=page count MVI H,0 PUSH H ; Save page count CALL EXTEST ; Test for existence of file MVI C,16H ; BDOS make file CALL GRBDOS POP H ; Get page count JZ SAVE3 ; Error? XRA A ; Set record count field STA FCBCR CALL ADVAN ; Look for 'S' for sector option INX D ; Pt to after 'S' token CPI SECTFLG JZ SAVE0 DCX D ; No 'S' token, so back up DAD H ; Double it for HL=record (128 bytes) ; SAVE0: XCHG ; SDED replaacement SHLD NXTCHR ; Set pointer to bad token XCHG ; End SDED replacement LXI D,TPA ; Point to start of SAVE area (TPA) ; SAVE1: MOV A,H ; Done with SAVE? ORA L ; HL=0 if so JZ SAVE2 DCX H ; Count down on record PUSH H ; Save pointer to block to save LXI H,128 ; 128 bytes per record DAD D ; Point to next record PUSH H ; Save on stack CALL DMASET ; Set DMA address for write (addr in DE) LXI D,FCBDN ; Write record MVI C,15H ; BDOS write record CALL BDOSB ; Save BC POP D ; Get ptr to next record in DE POP H ; Get record count JNZ SAVE3 ; Write error? JMP SAVE1 ; Continue ; SAVE2: LXI D,FCBDN ; Close saved file CALL CLOSE INR A ; Error? JNZ SAVE4 ; SAVE3: CALL PRNLE ; Print 'No Space' error ; SAVE4: JMP DEFDMA ; Set DMA to 80H and restart CPR ENDIF ; SAVEON ;..... ; ; ; Test file in FCB for existence, ask user to delete if so, and abort if ; he chooses not to. ; IF SAVEON OR RENON ; For SAVE and REN functions EXTEST: CALL SCANLOG ; Extract file name and log in user/disk JNZ ERROR ; '?' is not permitted CALL SEARF ; Look for specified file LXI D,FCBDN ; Point to file FCB RZ ; Ok if not found PUSH D ; Save pointer to FCB CALL PRINTC DB 'Erase',' '+80H LXI H,FCBFN ; Point to file name field CALL PRFN ; Print it MVI A,'?' ; Print question CALL CONOUT CALL CONIN ; Get response POP D ; Get ptr to FCB CPI 'Y' ; Key on yes JNZ ERR3 ; Restart as error if no PUSH D ; Save ptr to FCB CALL DELETE ; Delete file POP D ; 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 ; CALL EXTEST ; Test for file existence and return LDA TEMPDR ; Save selected disk PUSH PSW ; Save on stack ; REN0: LXI H,FCBDN ; Save new file name LXI D,FCBDM LXI B,16 ; 16 bytes CALL LDIRS ; LDIR substitute CALL ADVAN ; Advance to next character (non-delim) JZ REN4 ; Error if none ; ; ; Perform rename function. ; REN1: XCHG ; SDED replacement SHLD NXTCHR ; Save pointer to old file name XCHG ; End SDED replacement CALL SCANER ; Extract FILENAME.TYP token JNZ REN4 ; Error if any '?' POP PSW ; Get old default drive MOV B,A ; Save it LXI H,TEMPDR ; Compare it against selected drive MOV A,M ; Default? ORA A JZ REN2 CMP B ; Check for drive error JNZ 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 message ; REN4: JMP ERROR ENDIF ; RENON ; RSTJMP: JMP RCPRNL ; Restart CPR ;..... ; ; ; Section: 5G ; Command: JUMP ; Function: To call the program (subroutine) at the specified address ; without loading from disk. ; Forms: ; JMMP 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 JMP CALLPROG ; Perform call ENDIF ; JUMPON ;..... ; ; ; Section: 5H ; Command: GO ; Function: To call the program in the TPA without 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. ; Form: ; GO . ; IF GOON ; GO enabled? GO: IF WGO ; Wheel facility? CALL WHLCHK ; Check for wheel byte ENDIF ; WGO ; LXI H,TPA ; Always to TPA JMP 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, TBUFF at ; 80H) and run the program. ; ; The flag MULTCMD comes into play frequently here; it mainly ; serves to save space if MULTCMD is NO and and enables ; multiple commands on the same line if MULTCMD is YES. ; COM: LDA FCBFN ; Any command? CPI ' ' ; ' ' means command was 'D:' to switch JNZ COM1 ; Must be transient or error ; ; ; Entry point to select user/disk. ; IF WDU ; Wheel facility? CALL WHLCHK ; Check for wheel byte ENDIF ; WDU ; LDA COLON ; Look for colon flag ORA A ; If zero, just blank RZ ; Return to main routine ; ; ; Command is DU:, so log in user/disk. ; LDA TEMPUSR ; Get selected user CPI 10H ; Make sure 4 bits JNC ERROR ; Range error? STA CURUSR ; Set current user CALL SLOGIN ; Log in user/disk as if temporarily ; ; ; Now, make login permanent. ; LDA TEMPDR ; Get selected drive ORA A ; If 0 (default), no change JZ COM0 DCR A ; Adjust for log in STA CURDR ; Set current drive ; COM0: JMP SETUD ; Set current user/disk ;..... ; ; ; Process command. ; COM1: LXI D,FCBFT ; Point to file type LDAX D ; Get first character of file type CPI ' ' ; Must be blank, or error JNZ ERROR LXI H,COMMSG ; Place default file type (COM) into FCB LXI B,3 ; 3 bytes CALL LDIRS ; LDIR substitute LXI H,TPA ; Set execution/load address PUSH H ; Save for execution ; IF CMDRUN ; Command run facility available? MVI A,0FFH ; Use it if available ENDIF ; CMDRUN ; CALL MLOAD ; Load memory with file specified POP H ; Get execution address ; ; ; Entry point for the execution of the loaded program; on entry to this ; routine, HL must contain the execution address of the program (subrou- ; tine) to execute. ; CALLPROG: SHLD EXECADR ; Perform in-line code modification CALL SCANER ; Search command line for next token LXI H,TEMPDR ; Save pointer to drive specification PUSH H MOV A,M ; Set drive specification STA FCBDN LXI H,FCBDN+10H ; Pt to 2nd file name CALL SCANX ; Scan for it and load it into FCB+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 CALL LDIRS ; LDIR substitute ; CMDCH1 EQU $+1 ; In-the-code buffer address of 1st char LXI H,CMDLIN ; CALLP1: MOV A,M ; Skip to end of 2nd file name ORA A ; End of line? JZ CALLP2 ; IF MULTCMD ; Multiple commands allowed? CPI CMDSEP ; Command separator? JZ CALLP2 ENDIF ; MULTCMD ; CPI ' ' ; End of token? JZ CALLP2 INX H JMP CALLP1 ; ; ; Load command line into TBUFF. ; CALLP2: MVI B,0 ; Set character count LXI D,TBUFF+1 ; Point to character position ; CALLP3: MOV A,M ; Copy command line to TBUFF STAX D ORA A ; Done if zero JZ CALLP5 ; IF MULTCMD ; Multiple commands allowed? CPI CMDSEP ; Done if command separator JZ CALLP4 ENDIF ; MULTCMD ; INR B ; Increment character count INX H ; Point to next INX D JMP CALLP3 ; IF MULTCMD ; Multiple commands allowed? CALLP4: XRA A ; Store ending zero STAX D ; Instead of CMDSEP ENDIF ; MULTCMD ; ; ; Run loaded transient program. ; CALLP5: IF MULTCMD ; Multiple commands allowed? SHLD NXTCHR ; Save pointer to continue processing ENDIF ; MULTCMD ; MOV A,B ; Save character count STA TBUFF CALL CRLF ; New line CALL DEFDMA ; Set DMA to 80H ; ; ; Execution (call) of program (subroutine) occurs here. ; EXECADR EQU $+1 ; Change address for in-line code mod. CALL TPA ; Call transient CALL DEFDMA ; Set DMA to 0080 in case it was changed CALL DLOGIN ; Login current user/disk JMP CONT ; Restart CPR and continue command ;..... ; ; ; 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 ; 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 through to MLOAD ; IF CMDRUN ; Command run facility available? XRA A ; No cmdrun if facility is there 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 re- ; turn 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? STA CRFLAG ; Save flag ENDIF ; CMDRUN ; SHLD LOADADR ; Set load address ; ; ; Reentry point for a non-standard CP/M modification. The path command- ; search is implemented by this routine. ; MLA: IF DRVPREFIX ; If drive prefix allowed ... MVI A,DRVPFATT ; Set flag per user spec for SYS/non-SYS STA SYSTST ; Test flag in getsbit CALL SLOGIN ; Look under temporary user/disk CALL SEARF ; Look for file ; MLARUN: LXI H,PATH ; Point to path for failure possibility JNZ MLA4 ; Found it -- load it and run ENDIF ; DRVPREFIX ; IF NOT DRVPREFIX MLARUN: LXI H,PATH ; Point to path ENDIF ; DRVPREFIX ; ; Check WHEEL to see which path to take. ; This is Dave Schmitt's patch from ZCPR2. ; IF WHEEL AND SYSPATH LDA WHLADR ; Fetch WHEEL ORA A ; Is it on? JZ MLA0 ; Nope, use secure path LXI H,WHLPTH ; WHEEL on, change to sysop's path ENDIF ; WHEEL AND SYSPATH ; MLA0: MOV A,M ; Get drive ORA A ; 0=done=command not found ; IF CMDRUN ; Command run facility JNZ NOCRUN ; Not ready for cmd run yet ; CRFLAG EQU $+1 ; Pointer for in-the-code modification MVI A,0 ; Check crflag ORA A ; 0=no JZ ERROR ; Process as error ; IF ROOTONLY ; Only look for external command PUSH H ENDIF ; ROOTONLY ; XRA A ; Do not reenter this code STA CRFLAG ; Set zero for no entry LHLD CMDCH1 ; Get pointer to first char of command DCX H ; Pt to char count MVI M,' ' ; Store leading space SHLD CMDCH1 ; Point to leading space as first char SHLD NXTCHR ; Next char is first char of command LXI H,CFCB ; Set CFCB as command LXI D,FCBDN ; By copying it into FCBDN LXI B,12 ; Only 12 bytes required CALL LDIRS ; LDIR substitute ; IF ROOTONLY ; Look for external command JMP MLA3RT ENDIF ; ROOTONLY ; IF NOT ROOTONLY XRA A ; A=0 JMP MLARUN ; Now try the run ENDIF ; NOT ROOTONLY ; CFCB: CMDFCB ; FCB defining initial command ; NOCRUN: ENDIF ; CMDRUN ; IF NOT CMDRUN JZ ERROR ; Transient load error -- file not found ENDIF ; NOT CMDRUN ; ; ; Look for command in directory pointed to by HL; drive in A. ; CPI CURIND ; Current drive specified? JNZ MLA1 ; Skip default drive selection if so LDA CURDR ; Get current drive INR A ; Set A=1 ; MLA1: STA TEMPDR ; Select different drive if not current MVI A,1 ; Accept both SYS and DIR files STA SYSTST ; Test flag is 1 for both INX H ; Point to user number MOV A,M ; Get user number INX H ; Point to next entry in path PUSH H ; Save pointer ANI 7FH ; Mask out system bit CPI CURIND ; Current user specified? JNZ MLA2 ; Do not select current user if so LDA CURUSR ; Get current user number ; MLA2: STA TEMPUSR ; Set temporary user number CMA ; System bit is 0 if SYS-only ANI 80H JNZ MLA3 ; Flag not set if system bit=0 STA SYSTST ; Flag is 0 for SYS-only, 1 for both ; MLA3: CALL SLOGIN ; Log in path-specified user/disk ; MLA3RT: CALL SEARF ; Look for file POP H ; Get pointer to next path entry JZ MLA0 ; Continue path search if search failed ; Load if search succeeded ; ; File found -- perform system test and proceed if approved. ; MLA4: PUSH H ; Save pointer CALL GETSBIT ; Check system bit POP H ; Get pointer JZ MLA0 ; Continue if no match CALL OPENF ; Open file for input ; LOADADR EQU $+1 ; Memory load address (in-line code mod) LXI H,TPA ; Set start address of memory load ; MLA5: IF NOT MAKESPR ; Can't reconcile the MVI if SPR MVI A,ENTRY/256-1 ; Get high-order adr of just below CPR ENDIF ; NOT MAKESPR ; IF MAKESPR ; Do different way PUSH B LXI B,ENTRY MOV A,B ; Put high order address in A DCR A ; Minus 1 POP B ; Restore B ENDIF ; MAKESPR ; CMP H ; Are we going to overwrite the CPR? JC PRNLE ; Error if so PUSH H ; Save address of next sector XCHG ; In DE CALL DMASET ; Set DMA address for load LXI D,FCBDN ; Read next sector CALL READ POP H ; Get address of next sector JNZ MLA6 ; Read error or EOF? LXI D,128 ; Move 128 bytes per sector DAD D ; Point to next sector in HL JMP MLA5 ; MLA6: DCR A ; Load complete JZ DLOGIN ; Ok if zero, else fall thru to PRNLE ; ; ; Load error ; PRNLE: CALL PRINTC DB 'Ful','l'+80H CALL DLOGIN ; Restore current user/disk JMP RESTRT ; Restart ZCMD ;..... ; ; ; The following routine will fetch HHMM from BYE5 and display it. ; IF B5CLOCK AND (NOT B5TLOS) TIME: MVI C,79 CALL BDOS ; Get BYE's RTC address MOV A,M ; Get HH (it's in BCD) PUSH H ; Save address LXI H,ANSHH ; Storage location CALL ASCII ; Convert and store ASCII POP H ; Get address back INX H MOV A,M ; Get MM, also in BCD LXI H,ANSMM ; Storage location CALL ASCII ; Convert and store ASCII LXI H,TMSG JMP PRIN1 ; And print it, return from PRIN1 ;..... ; ; ASCII: PUSH PSW ; Save BCD pair RAR RAR RAR RAR ANI 0FH ; Get MSB of BCD pair ADI '0' ; Make ASCII MOV M,A ; Store it INX H ; Point to next store location POP PSW ANI 0FH ; Get LSB of BCD pair ADI '0' ; Convert to ASCII MOV M,A ; Store it RET ;..... ; ; TMSG: DB '[' ANSHH: DB '00:' ANSMM: DB '00] ',0 ENDIF ; B5CLOCK AND (NOT B5TLOS) ;..... ; ; ; The following routine will display [NN] before the DU>, where NN is ; time-left-on-system or, if wheel byte is on or MAXTIME=0 NN will indi- ; cate time-on-system. ; IF B5TLOS AND (NOT B5CLOCK) TIME: MVI C,79 CALL BDOS ; Get current time-on-system PUSH PSW ; And save it MVI C,81 MVI E,255 ; Get maxtime allowed CALL BDOS MOV B,A ; Put it in B ORA A JZ TIME1 ; User has unlimited time LDA WHLADR ORA A JNZ TIME1 ; Wheel byte is on POP PSW ; TOS in A-reg MOV C,A ; Now in C-reg MOV A,B ; MAXTIME in A-reg SUB C ; MAXTIME-TOS=TLOS JMP TIME2 ; TIME1: POP PSW ; Get TOS for wheel or unlimited time ; TIME2: LXI H,TLOS ; Storage area CALL DEC8 ; Convert/store to ASCII LXI H,TLOSM CALL PRIN1 ; Print first part LXI H,TLOS1 JMP PRIN1 ; And second part, exit from PRIN1 ;..... ; ; TLOSM: DB '[' TLOS: DB ' ',0 ; Buffer for TLOS or TOS TLOS1: DB '] ',0 ;..... ; ; ;----------------------------------------------------------------------- ; ; DEC8 will convert an 8-bit binary number in a to three ASCII bytes. ; HL points to the MSB location where the ASCII bytes will be stored. ; Leading zeros are suppressed. ; DEC8: PUSH PSW PUSH H XRA A MOV M,A ; Clear destination INX H MOV M,A INX H MOV M,A POP H POP PSW PUSH B PUSH D MVI E,0 ; Leading zero flag MVI D,100 ; DEC81: MVI C,'0'-1 ; DEC82: INR C SUB D ; 100 or 10 JNC DEC82 ; Still + ADD D ; Now add it back MOV B,A ; Remainder MOV A,C ; Get 100/10 CPI '1' ; Zero? JNC DEC84 ; Yes MOV A,E ; Check flag ORA A ; Reset? MOV A,C ; Restore byte JZ DEC85 ; Leading zeros are skipped ; DEC84: MOV M,A ; Store it in buffer pointed at by HL INX H ; Increment storage location MVI E,0FFH ; Set zero flag ; DEC85: MOV A,D SUI 90 ; 100 to 10 MOV D,A MOV A,B ; Remainder JNC DEC81 ; Do it again ADI '0' ; Make ASCII MOV M,A ; And store it POP D POP B RET ENDIF ; B5TLOS AND (NOT B5CLOCK) ;..... ; ; ;----------------------------------------------------------------------- ; ; This subroutine is a substitute for the Z80 LDIR instruction. - 03/04/87 dlc LDIRS: PUSH PSW ; Save flags LDIR1: MOV A,M ; Fetch the byte STAX D ; Poke it INX H ; Increment pointers INX D DCX B ; Decrement counter MOV A,B ; Check the counter to ORA C ; see if we are done JNZ LDIR1 ; Not done? POP PSW ; Finished RET ; End of LDIR replacement subroutine ; ;----------------------------------------------------------------------- ; ; Default path used for path command-search. ; IF INTPATH ; Use this path? PATH: IPATH ; Macro defined up front DB 0 ; Terminating 0 for last pair ; IF WHEEL AND SYSPATH WHLPTH: WPATH ; Alternate path for WHEEL use DB 0 ; Terminating 0 for last pair ENDIF ; WHEEL AND SYSPATH ENDIF ; INTPATH ; ; ; Stack area. ; IF INTSTACK ; Internal stack REPT 48 ; Stack initialized to 00s makes it DB 0 ; easier to examine paths in memory. ENDM ; STACK EQU $ ; Top of stack ENDIF ; INTSTACK ; ;..... ; $+print ENDZ EQU $ ; Show them where it ends ; SPARE EQU (CCPLOC + 0800H) - ENDZ ; And how much is left ; IF SPARE GT 0 REPT SPARE ; Fill remaining space with nulls DB 0 ENDM ENDIF ; SPARE GT 0 ; ; The following will cause an error message to appear if the size of ; ZCMD2 is over 2k bytes. ; IF NOT MAKESPR IF ($ GT CCPLOC+800H) ZCMD2ER EQU NOVALUE ; WARNING, ZCMD2 IS LARGER THAN 2K ENDIF ; ($ GT CCPLOC+800H) ENDIF ; NOT MAKESPR ;..... ; An error message to be printed at assembly time if the WHEEL path is ; implemented without the WHEEL byte being used. - 02/04/87 - dlc ; IF (NOT WHEEL) AND SYSPATH ERROR!! YOU ARE USING THE WHEEL PATH BUT ARE NOT UTILIZING THE WHEEL BYTE! ENDIF ; IF PWDON AND BPWDON ERROR!! YOU ARE USING BOTH INTERNAL AND EXTERNAL PASSWORD ROUTINES!!! ENDIF ; END