; ; ZCMD30B - Z80 CCP replacement - BETA CODE VERSION ; ; ZCMD3 is ZCMD2 with extensions for command history buffering ; and editing and support for an external Resident Command Processor. ; It also enables line recall/editing for any transient that uses ; the BDOS READLN (0Ah) call. ; ;------------------------------------------------------------------------ ; ; ZCMD30B is a super set of ZCMD29 and every feature that was available ; is still available. It also brings back the SHOW conditional from ; ZCMD28. ; ; *** BIG NOTE *** ; Generation of an SPR type of file has not been tested and probably ; will not work because of lack of critical equates. ; This only applies if the new functions are turned on!! ; ;------------------------------------------------------------------------ ; ; PREDESESOR History: ; ;------------------------------------------------------------------------ ; ; 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" 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. ; ;----------------------------------------------------------------------- ; ; To install: ; 1) Use your editor to change the appropriate equates. The two ; important ones are CCPLOC for your normal CCP address and ; MAXDISK for number of disk drives. ; ; 2) Assemble with MAC.COM (or RMAC.COM) to get a .HEX file. ; ; 3) The following is a typical floppy disk installation, most ; of the lower-case entries are those typed by the user: ; ; ; B0}sysgen ; SYSGEN Version 2.4 ; Copyright (c) 1983, Lifeboat Associates ; for DATAPOINT 1560. ; ; Source drive NAME (or RETURN to skip) a ; Place SOURCE disk on A:, then type RETURN ; Function complete ; Destination drive NAME (or RETURN to reboot) ; ; B0}save 48 image.com ; B0}ddt image.com ; DDT VERS 2.2 ; NEXT PC ; 3100 0100 ; -h0980,c800 ; calculate the offset ; D180 4180 ; -izcmd29.hex ; -r4180 ; use the offset ; NEXT PC ; 3100 0000 ; -g0 ; exit DDT ; ; B0}sysgen ; SYSGEN Version 2.4 ; Copyright (c) 1983, Lifeboat Associates ; for DATAPOINT 1560. ; ; Source drive NAME (or RETURN to skip) ; ; Destination drive NAME (or RETURN to reboot) b ; Place DESTINATION disk on B:, then type RETURN ; Function complete ; Destination drive NAME (or RETURN to reboot) ; ; B0} ; ; ; 4) Hard disk systems vary considerably in how ZCMD2 would be ; installed. Some use a program called PUTSYS. Not all ; SYSGEN systems put the mirror image of CCP at 0980h, but ; most do. A few use 0A00h. Substitute that for 0980h in ; determining the offset in the "H" line of DDT above. The ; second figure on that line is the normal address of CCP. ; This detailed illustration should make installtion simple. ; ;----------------------------------------------------------------------- ; 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 ; 6 Command Line Recall/Editing ; NO EQU 0 YES EQU NOT NO ; ; ; ;---------------------------------------------------------------------- ; ; Relevant new equates for customization: ; ;--------------------------------------------------------------------- ; ; BETA source code for a ZCMD30 ; that allows command line editing and recall from the CCP or ; any routine that makes use of the BDOS READLN(0Ah) ftn. ; ; Relevant equates and constants are: ; ; CLINER - enable the edit/recall ftns ; CPM22 - helps tell system where the code resides inside BDOS ; for the READLN ftn ; ALWRCP - equate to enable the companion resident command processor ; BDOSLOC - addr of BDOS in memory, based Upon equate CCPLOC ; READLNL - offset from BDOSLOC to where BDOS READLN code is ; PRTTOGF - flag to enable CTRL-P processing ; PRTTOGL - offset from BDOSLOC to where BDOS store CTRL-P flag ; CLRBUFON- Equate to enable extended BDOS call CLRBUF for ; clearing the recall buffer ; FULEDITF- Equate to enable the added editing capabilities of ; move by word foreward/backward ; EXTCBUF - equate to steal from TPA for recall buffer or ; use external buffer ; CCHKSUM - use to calc if the recall buffer should be initialized ; ; NOTE:: if assembled as is with only a change to CCPLOC, then ; the length will be 7F6h bytes!!! ; ; The equates as set will: ; ; ENABLE cmdlin recall and edit ; ASSUME CPM2.2 ; USE the memory inside BDOS where the READLN ftn code was for it's ; stack and FCB (INTSTACK=NO, EXTFCB=YES) ; STEAL memory from the TPA for the recall buffer ; USE an internal CCP command line buffer of length 80 bytes and AUTO=NO ; MULTCMD =YES ; CMDRUN =YES ; JUMPON =YES ( WITH WHEEL ONLY) ; B5TLOS =YES ; SHOW =YES ; DRVMAX and USRMAX are at 3Dh,3Fh and WHEEL is at 3Eh ; ; ALWRCP=NO, CANNOT use the RCP ; CLRBUFON=YES, BDOS call 0FEh will clear recall buffer ; PRTTOGF =NO, NO CTRL-P FOR LPT: ECHO (REQUIRES WHEEL if YES) ; FULEDITF=YES, editing extended to forward/backward word ; ; ; SUGGESTION: assemble it as is with only changing CCPLOC and BDOSLOC ; (if required) and give it a whirl!!! ; ; ; EUGENE S. NOLAN 2/28/88 ; Please direct all comments to E-mail on the ; DHN* BBS at 1-215-623-4040 care of myself ; ;----------------------------------------------------------------------- ; ; The following equates may be used to customize this CPR for the user's ; system and integration technique. It provides these constants: ; ; REL - YES if integration is to be done via MOVCPM ; - NO if integration is to be done via DDT and SYSGEN ; ; CCPLOC - 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. ; ; REL EQU NO ; Set to YES for MOVCPM integration MAKESPR EQU NO ; Set to YES for SPR generation OZFLOP EQU NO ; Set to YES if booting Ozzie-1 from ; floppy disk system tracks. Set NO ; if using MAKESPR. Read OZZIE-1.NOT ; IF NOT MAKESPR IF REL CCPLOC EQU 0 ; MOVCPM image BDOSLOC EQU 0 ; fill in base addr of your bdos ENDIF ; REL ; ; ; To set CCPLOC, obtain the origin of your current CPR using TELL or its ; equivalent, then merely set CCPLOC to that value as as in the follow- ; ing line: ; IF NOT OZFLOP CCPLOC EQU 0CA00H ;*Fill in with normal CCP address BDOSLOC EQU CCPLOC+0800H ;BDOS is 800h bytes above CCP ENDIF ; not ozflop IF OZFLOP CCPLOC EQU 0000H ; Ozzie-1 floppy disk default CCP ; location is here BDOSLOC EQU 0 ; Fill in addr of your bdos here ENDIF ; ; ; CLINER is the equate that enables command line buffer recal and editing ; ; CLINER EQU YES ; ; ; CPM22 is the equate that tells the system that you are running an ; unmodified BDOS from CPM version 2.2 ; ; ; Set CPM22 to yes if you are running stock BDOS. ; It will be used to specify the byte addr of the LPT: echo flag(ctl-P) ; inside BDOS and also the addr of the READ LINE(0ah) code that will ; be overlayed with our stack and external FCB. ; So to save space if CLINER is yes, SET INTSTACK=NO,EXTFCB=YES ; (requires about 84 bytes contigious from READLNL) CPM22 EQU YES IF CPM22 ;the following are offsets from bdosloc READLNL EQU 1EAH ;offset from bdosloc of bdos routine ; for READLN(0AH) PRTTOGL EQU 30DH ;offset from BDOSLOC of bios flag for ; CTRL-P LPT: ECHO (REQUIRES WHEEL) ;LENGTH OF READLN IS 231 BYTES ENDIF ;CPM22 IF NOT CPM22 PRTTOGL EQU 0 ;fill in byte addr used by your BDOS READLNL EQU 0 ;addr of BDOS routine for READLN(0AH) ENDIF ;NOT CPM22 ; ; ; Note that you should only use one method or the other. Do NOT define ; CCPLOC 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 man- ; uals, but it may not necessarily conform with the location of the CPR ; in YOUR CP/M system; several systems (Morrow Designs, P&T, Heath ORG-0 ; to name a few) have the CPR located at a non-standard address in the ; SYSGEN Image ; IF NOT REL CPRR EQU 0980H-CCPLOC ; DDT load offset for normal systems ;;CPRR EQU 1100H-CCPLOC ; DDT load offset for Morrow Designs ENDIF ; NOT REL ; ; ; The following equate identifies the location of the BIOS. This equate ; (as provided in the release copy of ZCMDHDR) assumes the standard ; sizes of 800H for ZCMD2 and 0E00H for BDOS and does not need to be ; modified if the user is running a standard CP/M configuration. ; BIOS EQU CCPLOC+800H+0E00H ; Address of BIOS ENDIF ; NOT MAKESPR ; ; ; The following macros define the file types of the command object files ; (.COM files under CP/M 2.2) to be loaded when a non-resident ZCMD2 ; command is given and of the indirect command files (SUB files under ; CP/M 2.2) to be used to extract commands from when the indirect com- ; mand facility is invoked. ; COMTYP MACRO DB 'COM' ; File type of command file ENDM ; SUBTYP MACRO DB 'SUB' ; File type of indirect command file ENDM ; ; ; The following flag enables or disables the ability of ZCMD2 to auto- ; matically bring up a file specified in the command buffer with a cold ; boot. (Sometimes called a RESTART or RESET.) This is useful for RCPM ; use as it can bring up BYE.COM should there be a momentary power loss. ; Not all systems have boot systems that bring up CP/M automatically in ; which case this option would be quite limited in its value. ; AUTO EQU NO ; Yes to autoload BYE.COM with cold boot ; ; ; The following flag enables or disables the ability of ZCMD2 to process ; SUBMIT files (command files of the form $$$.SUB). If SUBON is YES, ; then ZCMD2 will process such files like CP/M's CCP normally does; if ; SUBON is NO, ZCMD2 will not process such files (ignore them). In such ; a case only indirect command file facilities like ZEX will work. ; SUBON EQU no ; Set it to YES to enable processing of ; $$$.SUB. This is a large code eater ; so beware of size. It's a good one ; to set NO if size >800H. ; ; The following flag allows ZCMD2 to accept commands like: "DU:CMND". ; If DRVPREFIX is YES, this form is accepted; if NO, this form is not ; accepted. This flag has the additional side effect of automatically ; selecting files in the current disk/current user if the command if of ; the form "CMND". The DRVPFATT determines the attributes of selected ; files if DRVPREFIX is YES. ; DRVPREFIX EQU YES ; YES to enable prefix. NO for a more ; secure RCP/M system. ; ; The following flag allows the user to select the attributes of the ; files in the current disk/current user to be examined if the DRVPREFIX ; flag YES. The following values are defined: ; ; DRVPFATT Files Selected ; 0 System ; 80H Directory ; 1 Both System and Directory ; DRVPFATT EQU 1 ; Select both system and directory ; ; ; The following flag enables or disables the ability to switch user ; areas. For a more secure system, it is recommended that this ability ; be disabled and the CD.COM facility be employed instead. ; USERON EQU YES ; Enable user specification SUPRES EQU NO ; Yes to supress user # 0 report ; No to see A0> instead of A> ; ; ; The following flags enable or disable various ZCMD2-resident commands. ; The user may invoke these as desired, but should keep in mind the size ; of the resulting ZCMD2 and make sure it does not exceed the required ; limits. ; DIRON EQU NO ; DIR LTON EQU NO ; LIST, TYPE GOON EQU NO ; GO ERAON EQU NO ; ERA SAVEON EQU no ; SAVE RENON EQU NO ; REN GETON EQU no ; GET JUMPON EQU YES ; JUMP ; ; ; The following equate specifies the address of the PATH to be followed ; for the PATH command-search if the PATH is to be initialized by the ; BIOS and set by the user via a PATH.COM program. The value of PATH ; should be the address of the PATH data area in memory. If the in- ; ternalal PATH provided by ZCMD2 is to be used, then INTPATH should be ; equated to YES, which selects the PATH defined by the IPATH MACRO and ; the SYSOP path (WHEEL). If the external PATH is to be used, then ; INTPATH should be equated to NO and an equate value for the address of ; the PATH should be provided. A PATH is a series of byte-pairs, termi- ; nated by a binary 0. The first byte of each pair is the disk number ; (1-16 for disks A-P), and the second byte of each pair is the user ; number (0-31). The special character '$' indicates the current user ; or current disk. For example, the path from current disk/current user ; to current disk/user 0 to disk A/user 0 is selected by the following ; sequence: ; DB '$$' ; Current disk/user ; DB '$',0 ; Current disk/user 0 ; DB 1,0 ; Disk A/user 0 ; DB 0 ; End of path ; ; NOTE: If DRVPREFIX is YES, then current disk/user is automatically ; searched, and including it in the command search path causes it to be ; searched twice, wasting time (and space in the path). Since many en- ; virons will run with DRVPREFIX = YES, then a good command search path ; would not include the current disk/user. ; INTPATH EQU YES ; NO to use external ZCMD2 path ; IF INTPATH IPATH MACRO DB '$$' ; Current drive/user DB 'A'-'@',0 ; Drive A, user 0. Set as many pairs as ENDM ; you like, but leave off terminating 0. ; That last 0 is provided elsewhere. ; ; ; The following equates define the extra path to search if the Wheel ; byte is ON, and INTPATH is YES. ; SYSDRV EQU 'A'-'@' ; Search this drive if wheel byte on SYSUSR EQU 15 ; User area of SYSDRV to find SYSOP's ; .COM files. ENDIF ; INTPATH ; ; ; This equate defines the base address of the external path ; IF NOT INTPATH ; External path selected PATH EQU 40H ; External ZCMD2 path at CBIOS buffer ; area ENDIF ; NOT INTPATH ; ; ; The following equate causes ERA to confirm on the files to be erased ; before it goes ahead and erases them. If ERAOK is YES, then the user ; will be prompted each time; if it is NO, then the user will not be ; prompted. ; ERAOK EQU YES ; YES for prompt ; ; ; If ERAOK is YES, the following equate adds a Verify option to the ERA ; command which causes the user to be prompted only if the Verify option ; letter, defined by ERDFLG, is given after the file name. If ERAV is ; NO then the user will be asked to verify only when ERDFLG is contained ; in the command line; if ERAV is NO, the user will always be asked to ; verify. ; ERAV EQU NO ; Enable verify option ERDFLG EQU 'V' ; Set option letter ; ; ; The following equate enables the appearance of [HH:MM] before the DU> ; prompt if BYE5 is running with a clock. A check is made to see if ; BYE5 is running and skips the clock read if it's not. ; B5CLOCK EQU NO ;*YES, if BYE5 has a clock installed and ; you want the [HH:MM] displayed be- ; fore the DU> PRIDRIV must be NO for ; this to work B5TLOS EQU yes ;*YES, if BYE5 has a clock installed and ; you want the [NN] displayed before ; the DU>, where nn will indicate ; Time-left-on-system. B5CLOCK must ; be NO (select only one option). SHOW EQU yes ;*Yes, if WHEEL is set, or user has ; unlimited time and you wish to show ; time-on-system as: '[On:nn]'. ; NO, if you want to disable display when ; WHEEL is set or user has unlimited time. ; ; WARNING...B5TLOS takes more code than B5CLOCK, I had to assemble with ; SUBON EQU NO to keep size below 800H. ; ; The MULTCMD equate enables the feature of having more than one command ; on the same line, separated by a separation character which is defined ; by the CMDSEP equate. ; MULTCMD EQU YES ; Multiple commands permitted? CMDSEP EQU ';' ; Command separator ; ; ; The following equate allows selection of using an internal or an ex- ; ternal command buffer. ; EXCBUF EQU NO ; YES to use external command buffer ; IF MULTCMD AND EXCBUF CLBASE EQU 0FA00H ; Base address of buffer BUFLEN EQU 80 ; 80 bytes in input buffer ENDIF IF NOT MULTCMD AND EXCBUF CLBASE EQU BDOSLOC + READLNL + 100 ;overlay some of BDOS readln code with our external buffer BUFLEN EQU 80 ; Maximum buffer length ENDIF ; ; ; The Wheel equate table enables the WHEEL facility of ZCMD2. With this ; facility, a WHEEL BYTE, which exists somewhere in memory, is examined ; before a set of installer-selected commands are executed. If this ; byte is not zero, then the command proceeds. If it is zero, then the ; command is not allowed to proceed and is exited with an error message. ; ; The following set of equates make each of the indicated commands se- ; lectable to respond to the Wheel Byte or not. If WERA=YES, then it ; responds to the Wheel Byte; if WERA=NO, it does not. ; WHLADR EQU 3EH ; Address of byte to examine WERA EQU YES ; Make ERA a wheel-oriented command WREN EQU YES ; " REN " " " " WLT EQU YES ; " TYPE " " " " WGO EQU YES ; " GO " " " " WSAVE EQU YES ; " SAVE " " " " WGET EQU YES ; " GET " " " " WJUMP EQU YES ; " JUMP " " " " WDU EQU NO ; " DU: " " " " WHEEL EQU WERA OR WREN OR WLT OR WGO OR WSAVE OR WGET OR WJUMP OR WDU ; ; ; The INTSTACK equate is used to specify if the stack is internal or ; external to ZCMD2. Naturally, quite a bit of space is saved if the ; stack is placed external to ZCMD2. If such is the case, the user ; should set the STKBASE equate to the beginning of the stack area ; (bottom of the stack). ; ; NOTE: THIS IS THE BOTTOM OF THE STACK, NOT THE TOP OF THE STACK. ; ; If INTSTACK is YES, the stack is internal to ZCMD2. If INTSTACK is NO ; the stack is external to ZCMD2, and the base of the stack (bottom of ; the stack) is located at STKBASE. ; INTSTACK EQU NO ; Enable or disable internal stack ; IF NOT INTSTACK AND NOT CLINER STKBASE EQU 0F980H ; Address of bottom of external stack STACK EQU STKBASE+48 ; Address of top of stack ; ; Stack size should be at least 48 bytes ENDIF ; NOT INSTACK AND NOT CLINER IF NOT INTSTACK AND CLINER STKBASE EQU BDOSLOC + READLNL ;Overlay readln ftn with our stack STACK EQU STKBASE+48 ;Address of top of stack ENDIF ; NOT INTSTACK AND CLINER ; ; ; *** Terminal and 'type' customization equates ; NLINES EQU 24 ; Number of lines on CRT screen WIDE EQU YES ; YES for normal directory display FENCE EQU ':' ; Separation character between files HBCON EQU YES ; YES, ok to send characters with Hi bit ; set i.e. file attribute bits, to ; screen unchanged. HBLST EQU YES ; YES, ok to send characters with Hi bit ; set to LST device unchanged. PGDFLT EQU YES ; YES to pause each CRT page PGDFLG EQU 'P' ; For type command: page or not (dep on ; ; ; *** Miscellaneous equates ; USRMAX EQU 003FH ; Location of byte in memory containing ; number of highest allowable user ; code +1. This is set to MAXUSR if BYE ; is not present, and after that it is con- ; trolled by system programs. Then if ; USRMAX=0 then MAXUSR cannot be ; dynamically changed, and should be ; permanently set. 03FH is recommend- ; ed for USRMAX if used. MAXUSR EQU 15 ; Maximum user number accessable ; 15= allow user area 0 thru 15 DRVMAX EQU 003DH ; Location of byte in memory containing ; maximum legal drive, this value is ; set to MAXDISK if BYE is not present ; After that controlled by system programs. ; If DRVMAX=0 then MAXDISK cannot be ; changed by external programs, and ; should be permanently set. 03DH is ; recommended if used. MAXDISK EQU 12 ;*Maximum number of disks accessable ; 1=A, etc. SYSFLG EQU 'A' ; For dir command: list $SYS and $DIR SOFLG EQU 'S' ; For dir command: list $SYS files only SPRMPT EQU '$' ; CPR prompt indicating submit command CPRMPT EQU '>' ; CPR prompt indicating user command ;;CPRMPT EQU '>'+80H ; Use this line with ZEX, sets high bit ; The high bit is set (+80H) for ZEX. ; WARNING, the +80H will cause inverse ; video on some systems such as the ; Osborne-1 and TRS-80's. Just remove ; the +80H from the above equate. WCPRMPT EQU '}' ; CPR prompt if WHEEL byte is ON ;;WCPRMPT EQU '}'+80H ; Use this line with ZEX, sets high bit ; Set to > if you want both the same NUMBASE EQU 'H' ; Switches from default to number base SECTFLG EQU 'S' ; Option character for save command CURIND EQU '$' ; Symbol for current disk or user COMMENT EQU ';' ; Depicts comment lines ; ; ; CPR command name table - each table entry is composed of the 4-byte ; command and 2-byte address ; NCHARS EQU 4 ; Number of chars/command ; CTABLE MACRO ; IF DIRON DB 'ODIR' DW DIR ; Directory display command ENDIF ; DIRON ; IF LTON DB 'LIST' DW LIST ; List file on printer command DB 'TYPE' DW TYPE ; Type file on console command ENDIF ; LTON ; IF GOON DB 'GO ' DW GO ; Execute current tpa command ENDIF ; GOON ; IF ERAON DB 'ERA ' DW ERA ; Erase files command ENDIF ; ERAON ; IF SAVEON DB 'SAVE' DW SAVE ; Save tpa command ENDIF ; SAVEON ; IF RENON DB 'REN ' DW REN ; Rename files command ENDIF ; RENON ; IF GETON DB 'GET ' DW GET ; Load file into TPA command ENDIF ; GETON ; IF JUMPON DB 'JUMP' DW JUMP ; Jump to any memory location command ENDIF ; JUMPON ENDM ; MACRO ; ; ; This equate determines if the ZCMD2 FCB is located internal to or ex- ; ternal to ZCMD2. If EXTFCB is YES, FCBADR defines where it is found. ; Placing the ZCMD2 FCB external to ZCMD2, more space is left for other ; uses within ZCMD2. ; EXTFCB EQU YES ; Allow external FCB ; IF EXTFCB AND NOT CLINER FCBADR EQU 0F980H ; Address of external FCB ENDIF ;EXTFCB AND NOT CLINER IF EXTFCB AND CLINER FCBADR EQU BDOSLOC+READLNL+50 ;Address of external FCB will ;overlay READLN ftn of BDOS ;The 50 is to skip over the ;extrn stack overlay in first 50 bytes ENDIF ;EXTFCB AND CLINER ; ; ; CMDRUN - ZCMD2 Extended Command Processing Facility ; ; This equate enables the ZCMD2 CMDRUN facility. If CMDRUN is YES, then ; another stage of command processing is invoked should ZCMD2 fail to ; find a COM file when the user gives a command. This stage involves ; invoking the .COM file specified by CMDFCB and giving it the current ; command line as an argument. In this way, if, say, M80 PROG2 fails as ; a command, a new command like LRUNZ M80 PROG2, SUB M80 PROG2, or ZEX ; M80 PROG2 may be processed. If the new command fails, an appropriate ; error message is given. ; ; The ROOTONLY option causes ZCMD2 to only look at the Root (bottom of ; path) for the Extended Command Processor if it is set to YES. If it ; is set to NO, the path is searched for the Extended Command Processor. ; The tradeoff here is that ROOTONLY = YES is less flexible but somewhat ; faster than ROOTONLY = NO. ; CMDRUN EQU YES ; Enable the facility ; IF CMDRUN ROOTONLY EQU YES ; True if look at root only for extended ; command processor, NO if look along ; path CMDFCB MACRO DB 0 DB 'CMDRUN ' ; Name of program DB 'COM' ; File type ENDM ENDIF ; CMDRUN ; ; ; end of customization section ;----------------------------------------------------------------------- ; 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 ; ; ; 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 ; CPIR - WHILE(A<>(HL) AND BC<>0):A-(HL),BC-1:ENDWHILE ; LDIR - MOV @HL TO @DE FOR COUNT IN BC ; LXXD - LOAD DOUBLE REG DIRECT ; SXXD - STORE DOUBLE REG DIRECT ; SBCDE - HL=HL-DE-CY ; ; @GENDD macro used for checking and generating ; 8-bit jump relative displacements. ; @GENDD MACRO ?DD ; ; Checks range of 8-bit displacements ; IF (?DD GT 7FH) AND (?DD LT 0FF80H) DB 100H ; Displacement range error on jump rel. ELSE DB ?DD ENDIF ; ; Range error ENDM ; ; MACRO ; ; ;----------------------------------------------------------------------- ; 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 DB 10H @GENDD ?N-$-1 ENDM ; CPIR MACRO ; ; CPIR DB 0EDH,0B1H 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 ; SBCDE MACRO ; ; SBC HL,DE DB 0EDH,52H ENDM ; ; end of Z80 macro extensions ;----------------------------------------------------------------------- ; **** 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 CHRCNT: DB 3 ; Number of valid chars in command line CMDLIN: DB 'BYE' ; 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 EXCBUF AND NOT AUTO ; 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 EXCBUF AND NOT AUTO ; ; If the folloing condition is met , the cliner init will ; copy the following to clbase, which,with the equates now set, ; will overlay into the bdos readln ftn, therby providing auto and ; excbuf without external code to set it up. IF (AUTO AND EXCBUF) AND CLINER CNXTCHR: DW CMDLIN ; Pointer to command input buffer CBUFSIZ: DB BUFLEN ; Maximum buffer length CCHRCNT: DB 3 ; Number of valid chars in command line CCMDLIN: DB 'BYE' ; Default (cold boot) command DB 0 ; Command string terminator CLBUFS EQU ($-CNXTCHR)+1 ; Total in bytes ENDIF ; AUTO AND EXCBUF AND CLINER ; ; 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 ; IF LTON ;LIST OR TYPE ON? PAGCNT: DB NLINES-2 ; Lines left on page ENDIF ;LTON ; ; ; CLINER SUPPORT AND BUFFERS ; MAXLIN EQU 7 ;max line number in recall buffeR, ; counting from 0 ;MUST!! be 3,7,f,1f,,, for internal calcs CCHKSUM EQU 36 ;check sum of ;((MAXLIN+1)+(MAXLIN)+(MAXLIN-1)++1) ;used to check reentrance ;MAXLIN=3,=10 ;MAXLIN=7,=36 ; Set EXTCBUF to yes if you want to place the recall buffer someplace ; and not steal memory form the TPA automatically. Set it to NO if ; you want the code to allocate the buffer below the CCP and steal ; from the TPA. EXTCBUF EQU NO ;SET TO YES FOR NON TPA RECALL BUF ; ; ALWRCP is the equate that enables the support for the external ; Resident Command Processor. This is implemented by ; Execute the RCP as a transient program ; It will then relocate itself to under the CCP, revector the ; the BDOS vector at 6 to itself, and the vector itself to ; the BDOS revector of the CCP. ; Then it will fill in a jump to it's entry address to the address ISGO ; immediatly above the CCP BDOS revector, and then above that load ; the offset of its BDOS revector so that the CCP, upon a warm boot, can ; determine if the RCP had been previously loaded by checking the ; addr specified by RCPRELOC to see if it points to it's BDOS revector, ; and if it does, to vector loc 6 to the address specified by RCPRELOC. ; When ZCMD then parses the command entered by the user or thru a SUBMIT file, ; the routine CMDSER will check to see if (ISGO) is non-zero, and if ; it is, make a CALL ISGO, which will jump to the entry point of the RCP, ; which will then check to see if it can handle the command. ; The RCP will then return NZ if it can't, or one of the following: ; B register non-zero, which means C register contains DU information, ; which will cause CMDSER to jump to CPR2, and login the DU as specified. ; Z flag set, which means it can handle the command but needs the default ; FCB's parsed and the command tail placed at the default DMA location. ; This is done by the RCP placing the required execution address UNDER ; it's INITIAL CALL ISGO entry on the stack and return to CMDSER which ; will then ; return to the caller with HL pointing to memory that specifies the ; location JUMP1 to be the 'internal' routine to execute. ; JUMP1 will then POP the stack which will contain the RCP code address ; and 'JUMP' to CALLPROG. ALWRCP EQU NO ; TEMP is the amount of mem to take away from the tpa for use by line ; recall code buffers/variables and/or bdos revector IF NOT EXTCBUF TEMP EQU CCPLOC-(MAXLIN+1)*BUFLEN-3-1-2-1-1-1 ; TEMP=(base of ccp)-(total # lines in recall buf)*(chars/line) ; -(3 bytes for bdos revector)-(1 byte to hold current line) ; -(2 bytes to hold pointer to buffer passed to bdos readln) ; -(1 byte to hold insert/overstrike flag) ; -(1 byte to hold a temp during bdos intercept) ; -(1 byte to hold max chars to read) ; MORESPC is extra memory you want to take away from the tpa for own use IF NOT ALWRCP MORESPC EQU 0 ;dont steal any more ENDIF ;NOT ALWRCP IF ALWRCP MORESPC EQU 5 ;for rcp local variables ENDIF ;ALWRCP ENDIF ;NOT EXTCBUF IF EXTCBUF TEMP EQU CCPLOC-3 ;only need to steal 3 bytes for the BDOS IF NOT ALWRCP MORESPC EQU 0 ENDIF ;NOT ALWRCP IF ALWRCP MORESPC EQU 5 ;rcp local variables ENDIF ;NOT ALWRCP ENDIF ;EXTCBUF BUFSPAC EQU TEMP-MORESPC ; CBUFFER is where we start storing the recall local variables and buffer IF NOT EXTCBUF IF NOT ALWRCP CBUFFER EQU BUFSPAC+3 ;stolen from TPA ENDIF ;NOT ALWRCP IF ALWRCP ISGO EQU BUFSPAC+3 RCPENTRY EQU ISGO+1 RCPRELOC EQU RCPENTRY+2 CBUFFER EQU RCPRELOC+2 ;stolen from TPA after RCP variables ENDIF ;ALWRCP ENDIF ;NOT EXTCBUF IF EXTCBUF ISGO EQU BUFSPAC+3 RCPENTRY EQU ISGO+1 RCPRELOC EQU RCPENTRY+2 CBUFFER EQU 0FD00H ;Not stolen from TPA but external to CPM ENDIF ;EXTCBUF AND NOT ALWRCP INSFLG EQU CBUFFER ;holds insert/overstrike flag SAVEAS EQU INSFLG+1 ;holds a temporarily during BDOS intercept GBUFLEN EQU SAVEAS+1 ;holds MIN(our BUFLEN,BDOS READLN LENGTH) LINPNT EQU GBUFLEN+1 ;holds pointer to address of buffer as passed ;to READLN (+1) CURLIN EQU LINPNT+2 ;holds current line # in recall buf LINBUF EQU CURLIN+1 ;base of recall buffer ; ; 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 ; ; Now see if BYE is running ; CPR: LXI SP,STACK ; Set the stack PUSH B PUSH D IF CLINER IF AUTO AND EXCBUF LXI H,CNXTCHR ;move internal default cmd def to LXI D,CLBASE ;external storage LXI B,CLBUFS LDIR ENDIF ;AUTO AND EXCBUF CALL CHKVEC ; put bdos revector in place ENDIF ;CLINER 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 JRZ CPR1A ; BYE5 already running, zero cmdline ENDIF ; AUTO ; IF NOT AUTO JRZ CPR2 ; Yes, continue without setting defaults ENDIF ; NOT AUTO ; LXI H,DRVMAX ; REORDER THE FOLLOWING TO SAVE ALL SPACE ; WE CAN ; ; only will work if contigious increasing ; addr's for drvmax,whladr,usrmax IF DRVMAX ; MVI A,MAXDISK-1 ; Set DRVMAX on cold boot ; STA DRVMAX MVI M,MAXDISK-1 ENDIF ; DRVMAX ; INX H IF USRMAX OR DRVMAX ; MVI A,0FFH ; STA WHLADR ; Set WHEEL MVI M,0FFH ENDIF ; USRMAX OR DRVMAX ; INX H IF USRMAX ; MVI A,MAXUSR+1 ; Set USRMAX on cold boot ; STA USRMAX MVI M,MAXUSR+1 ENDIF ; USRMAX ; IF CLINER PUSH B ;save default disk/user in c reg ; first we will check if this is first time or after a wboot ; this will be done by doing checksum test of the bytes stored in the ; bufsiz field of the individual lines in the buffer, if they don't ; match the sum of the number of lines summed, then this is a cold boot ; (hopefully they wont match on a cold boot???) ; Perform checksum test on buffer XRA A ;current checksum LXI H,LINBUF ;point to buffer LXI D,BUFLEN ;chars/line MVI B,MAXLIN+1 ;max num lines in recall buffer CLINCHK: ADD M ;a holds current checksum DAD D ;point to next line DJNZ CLINCHK CPI CCHKSUM ;check sums match? JRZ DCLINIT ;z=yes,dont zero chrcnt's XRA A STA CURLIN ;set up CURLIN=0 on cold boot ; Recall buffer needs initialization LXI H,LINBUF LXI D,BUFLEN-1 MVI B,MAXLIN+1 CLININIT: MOV M,B ;save a line number INX H MOV M,A ;CHRCNT DAD D DJNZ CLININIT DCLINIT: POP B ENDIF ;CLINER JR CPR2 ; On to coldboot routine ; First check to see if RCP has been loaded, if it has then re-enable it ; and don't bother setting up recall buffer because we know it was done ; already. IF CLINER CHKVEC: IF ALWRCP LHLD RCPRELOC ;the rcp will put the addr of its ;relocation vector here(after the jmp) PUSH H MOV E,M ;find out where it points to INX H MOV D,M LXI H,BUFSPAC XRA A ;cy flag=0 SBCDE ;does it = BUFSPAC? POP H JRNZ NORCP ;DOESN'T point to us, no RCP DCX H ;point at the jmp instr SHLD 6 ;yes, put its reloc vector at 6 JR DCHKVC NORCP: STA ISGO ;RCP allowed but hasnt been loaded ENDIF ;ALWRCP ; Revector the BDOS to our intercept LXI H,BUFSPAC ;point to stolen mem SHLD 6 ;vector to here ; Vector our intercept to our replacement READLN code MVI M,0C3H ;put a jmp instr in LXI H,READINP ;put the vector addr in SHLD BUFSPAC+1 ; DCHKVC: RET ENDIF ;CLINER ; ; Start ZCMD2 , revector BDOS call, and don't process default ; command stored if multiple com mands are not allowed. ; This is the warmboot entry. ; IF CLINER CPR1: LXI SP,STACK PUSH B ; Save disk number in C CALL CHKVEC POP B ENDIF ;CLINER CPR1A: 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) IF LTON SHLD BIOCAL1+1 ENDIF ;LTON SHLD BIOCAL3+1 SHLD BIOCAL4+1 IF CLINER SHLD BIOCAL5+1 ENDIF ; CLINER 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 JRZ RESTRT ORA A ; 0 if no command line present JRNZ 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 ; ; ; Ppompt user and input command line from him ; RESTRT: LXI SP,STACK ; Reset stack ; ; ; The following code added by < wm > to dynamically set INTPATH to extra ; search level if Wheel is on, and reset that level if Wheel is off. ; IF WHEEL AND INTPATH LDA WHLADR ; Get wheel byte ORA A MVI A,0 ; Reset search path if off JZ $+5 MVI A,SYSDRV ; Set search drive if wheel on STA WHLPTH ; Into the search path ENDIF ; WHEEL AND INTPATH ; ; ; 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 JRZ RS000 ENDIF ; SUPRES ; 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: 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? JRZ RESTRT ; Input another line if so ORA A ; No input? JRZ 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? JRNZ RS2 INX H ; Skip it if it is SHLD NXTCHR ; Set pointer back ENDIF ; MULTCMD ; ; ; Set pointer fro 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? JRNZ CAPBUF CALL SCANER ; Parse command name from command line JRNZ 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 ; ; ; Invalie command - print it ; ERROR: CALL CRLF ; New line ; CURTOK EQU $+1 ; Pointer for in-the-code modification LXI H,0 ; Pt to beginning of command line ; ERR1: MOV A,M ; Get character CPI ' '+1 ; Simple '?' if or less JRC ERR2 CALL CONOUT ; Print command char INX H ; Pt to next char JR 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 ; IF (DIRON OR ERAON) OR RENON PRNNF: CALL PRINTC ; No file message DB 'No Fil','e'+80H RET ENDIF ;DIRON OR ERAON OR RENON ;..... ; ; ;----------------------------------------------------------------------- ; * Section 3 **** ; I/O utilities ; ; Output character in A-register to CRT and don't change 'BC' ; ; CONIN: MVI C,1 ; Input character CALL BDOS ; Get input character with ^S JMP UCASE ; Capitalize ; Output ; CRLF: MVI A,CR CALL CONOUT MVI A,LF ; JR CONOUT ; Re-ordered to fall into conout(2 more bytes) ; CONOUT: PUSH B PUSH D PUSH H MVI C,2 ; OUTPUT: MOV E,A CALL BDOS POP H POP D POP B RET ;..... ; ; IF LTON ;LIST OR TYPE ON? 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 JRZ 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 JR 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 JRNZ 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 pgflg equate CPI PGDFLG ; Page default override option wanted? ; IF PGDFLT ; If paging is default JRZ PAGER1 ; PGDFLG means no paging, please ENDIF ; PGDFLT ; IF NOT PGDFLT JRNZ 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 ENDIF ;LTON ;..... ; ; ; 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 ptointer 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 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 MVI C,0EH JR 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 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 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 JR 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' JR 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 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 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 JRNZ 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 LDIR LXI H,SUBFS2 ; Point to S2 of $$$.SUB FCB ; MVI M,0 ; Set S2 to zero MOV M,C ; Set S2 to zero and save a byte INX H ; Point 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,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 JRZ RB2 ; No, continue with normal prompt MVI A,WCPRMPT ; Else, select alternate prompt ENDIF ; WHEEL ; RB2: CALL CONOUT LXI D,BUFSIZ IF EXCBUF MVI A,BUFLEN STAX D ENDIF ;EXCBUF MVI C,0AH ; Read command line from user CALL BDOS ; ; ; Store zero at end of command line ; LXI H,CHRCNT ; Point to character count MOV A,M ; Get character count INX H ; Pt to first character of command line CALL ADDAH ; Pt to after last char of command line MVI M,0 ; Store ending zero RET ;..... ; ; ; Check for any character from user console, return with zero set if ; none. ; IF (SUBON OR DIRON) OR (ERAON OR LTON) 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 ENDIF ;(SUBON OR DIRON) OR (ERAON OR LTON) ;..... ; ; ; 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 <= JRC 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 ; Doing it this way will save us 3(6) bytes (6 if multcmd) PUSH H ; SAVE PUSH B LXI H,DELMARY ; point to delimiter array LXI B,DELMCNT ; count of number of delimeters CPIR ; compare them ; Ret Z=1 if a match found POP B POP H RET ; ZERO: XRA A ; Set zero flag RET DELMARY: DB '=_.:,;<>' IF MULTCMD DB CMDSEP ENDIF ;MULTCMD DELMCNT EQU $ - DELMARY ;Count of Number of delimeters to check ;..... ; ; ; Advance input pointer to first non-blank and fall through to SBLANK ; ADVAN: LDED NXTCHR ; Point to next character ; ; ; Skip string pointed to by DE (string ends in 0 OR CMDSEP) until end of ; string or non-delimited encounterd (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 JR 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. ; IF SAVEON 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? 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 ; Point to beginning of token ENDIF ;SAVEON ; NUM0A: LXI B,1100H ; C=accumulated value, b=char count ; ; (c=0, b=11) NUM1: MOV A,M ; Get character CPI ' ' ; Done if JRZ NUM2 CPI ':' ; Done if colon JRZ NUM2 INX H ; Pt to next char SUI '0' ; Convert to binary CPI 10 ; Error if >= 10 JRNC NUMERR MOV D,A ; Digit in d MOV A,C ; New value = old value * 10 RLC ; *2 JRC NUMERR RLC ; *4 JRC NUMERR RLC ; *8 JRC NUMERR ADD C ; *9 JRC NUMERR ADD C ; *10 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 ;..... ; ; ; Extract hexadecimal number from command line - return with value in ; A-reg, all registers may be affected. ; IF (JUMPON OR GETON) OR SAVEON 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? 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 ; 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 DJNZ HNUM1 ; Count down ; ; ; Return from HEXNUM ; HNUM3: XCHG ; Returned value in hl MOV A,L ; Low-order byte in a RET ENDIF ;SAVON OR JUMPON OR GETON ;..... ; ; ; 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 JRNZ 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, ; MXTCHR 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 SDED CURTOK ; Set ptr to non-blank or end of line MVI B,11 ; Prep for possible space fill JRZ 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 to FCBDN. ; PUSH D ; Save pointer to first character CALL SDELM ; Check for delimiter and get first char CPI 'A' ; In letter range? JRC SCAN1 CPI 'P'+1 ; In letter range? JRC SCAN1A ; SCAN1: CPI '0' ; Check for digit range JRC SCAN2 CPI '9'+1 ; In digit range? JRNC SCAN2 ; SCAN1A: INX D ; Pt to next char CALL SDELM ; Check for delimiter, else digit JR SCAN1 ; SCAN2: POP D ; Restore ptr to first char CPI ':' ; Was delimiter a colon? JRNZ 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 JRC 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 ':' JRZ 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 '.' JRNZ SCAN4 ; Fill file type bytes with INX D ; Pt to char in command line after '.' CALL SCANF ; Fill fcb file type JR 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 ; SDED NXTCHR ; ; ; 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 JRZ SCANF4 INX H ; Point to next byte in FCBDN CPI '*' ; Is (DE) a wild card? JRNZ SCANF1 ; Continue if not MVI M,'?' ; Place '?' in FCB CALL SCQ ; Scanner count question marks JR 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: 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: MVI A,' ' ; Fill with spaces ; SCANF5: INX H ; Point to next byte in FCB MOV M,A ; Fill with byte in A-reg. DJNZ 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 JRZ 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 JRNZ CMS3 ; No match INX D ; Point to next character INX H DJNZ CMS2 ; Count down LDAX D ; Next char must be a space CPI ' ' JRNZ CMS4 RET ; Command is CPR-resident ; ; 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 ; CMS5: IF ALWRCP ; ALLOW RCP LDA ISGO ORA A JRNZ CMS6 ENDIF ;ALWRCP INR A ; Clear zero flag RET ; Command is disk-resident IF ALWRCP CMS6: LXI D,FCBFN ; Point to defcb so the RCP can scan ; the cmd entered CALL ISGO RNZ ; 0=RCP can take command ORA B JZ CMS7 JMP CPR2 CMS7: LXI H,JUMPTO RET ; If RCP can handle command, return: ; Z flag ; (stack+2)= addr in mem of code addr ; that will be popped by JUMP1: JUMPTO: DW JUMP1 ENDIF ;ALWRCP ;..... ; ; ;----------------------------------------------------------------------- ; **** section 5 **** ; ; CPR-resident commands ; ; Section: 5A ; Command: DIR ; Function: To display a directory of the files on disk ; Forms: ; DIR displays the DIR files ; DIR s displays the SYS files ; DIR a display both DIR and SYS files ; ; NOTES: ; the flag SYSFLG defines the letter used to display both DIR and ; SYS files (A in the above forms section) ; the flag SOFLG defines the letter used to display only the SYS ; files (S in the above forms section) ; the flag WIDE determines if the file names are spaced further ; apart (wide=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 JRZ 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? JRZ GOTFLG ; Got system specifier CPI SOFLG ; Sys only? JRNZ DIRDN DCR B ; B=0 for sys files only ; GOTFLG: INX D ; Pt to char after flag ; DIRDN: SDED NXTCHR ; Set pointer for next pass then drop ; DIRRPR to print directory and go ; restart CPR ENDIF ; DIRON ; ; ; Directory print routine; on entry, B- reg is set as follows: ; 0 for only system files, 80H for only DIR files, 1 for both ; IF DIRON OR ERAON DIRPR: 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 JRNZ 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 JRZ 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 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 ; 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 JRZ DIR7 CALL SEARN ; Search for next file JRNZ 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 ; IF (SAVEON OR DIRON) OR (RENON OR ERAON) 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 JRNZ PRFN1 RET ENDIF ;SAVEON OR DIRON OR RENON OR ERAON ;..... ; ; ; 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 80Hh 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 IF DIRON OR ERAON ;..... ; ; ; Fill FCB @HL with '?' ; FILLQ: MVI B,11 ; Number of characters in FN & FT ; FQLP: MVI M,'?' ; Store '?' INX H DJNZ FQLP RET ENDIF ;DIRON OR ERAON ;..... ; ; ; 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 JRZ 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? JRNZ 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 ; Fforms: ; 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 JR TYPE0 ;..... ; ; ; Section: 5D ; Command: TYPE ; Function: Print out specified file on the con: device ; Forms: ; TYPE print file ; TYPE P print file with paging flag ; ;NOTES: ; The flag PGDFLG defines the letter which toggles the paging ; facility (P in the forms section above) ; The flag PGDFLT determines if type is to page by default ; (PGDFLT=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 JRZ TYPE1 ; Jump if input ended INX D ; Put new buf pointer ; TYPE1: SDED NXTCHR ; Set pointer for next command 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 JRC TYPE3 PUSH H ; Read next block PUSH B CALL READF POP B POP H JRNZ TYPE7 ; Error? MVI C,0 ; Set character count LXI H,TBUFF ; Poin 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? JRZ TYPE4 CPI LF ; Reset tab count? JRZ TYPE4 CPI TAB ; Tab? JRZ TYPE5 ; ; ; Output character and increment character count ; CALL LCOUT ; Output char INR B ; Increment tab count JR TYPE6 ; ; ; Output or and reset tab count ; TYPE4: CALL LCOUT ; Output or MVI B,0 ; Reset tab counter JR TYPE6 ; ; ; Tabulate ; TYPE5: MVI A,' ' ; Space CALL LCOUT INR B ; Increment position count MOV A,B ANI 7 JRNZ TYPE5 ; ; ; Continue processing ; TYPE6: INR C ; Increment char count INX H ; Pt to next char CALL BREAK ; Check for abort RZ ; Restart if so JR 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 JRZ 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 JRZ SAVE0 DCX D ; No 's' token, so back up DAD H ; Double it for HL=record (128 bytes) ; SAVE0: SDED NXTCHR ; Set pointer to bad token LXI D,TPA ; Point 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 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 JRNZ SAVE3 ; Write error? JR SAVE1 ; Continue ; SAVE2: LXI D,FCBDN ; Close saved file CALL CLOSE INR A ; Error? JRNZ SAVE4 ; SAVE3: CALL PRNLE ; Print 'no space' error ; SAVE4: JMP DEFDMA ; Set DMA to 0080 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 LDIR CALL ADVAN ; Advance to next character (non-delim) JRZ REN4 ; Error if none ; ; ; Perform rename function ; REN1: SDED NXTCHR ; Save pointer 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 selected drive MOV A,M ; Default? ORA A JRZ REN2 CMP B ; Check for drive error 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 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 ENDIF ; JUMPON IF ALWRCP OR JUMPON PUSH H JUMP1: POP H ; will get here if RCP can handle ; command(see cmdser:) JR CALLPROG ; Perform call ENDIF ; ALWRCP OR 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 JR CALLPROG ; Perform call ENDIF ; GOON ;..... ; ; ; Section: 5I ; Command: COM file processing ; Function: To load the specified .COM file from disk and execute it ; Forms: ; NOTES: .COM files are processed as follows -- ; 1. file name buffers are initialized and a preliminary ; error check is done ; 2. MLOAD is used to search for the file along the path ; and load it into the TPA ; 3. CALLPROG is used to set up the buffers to be used by ; the transient (FCB at 5CH, FCB at 6CH, 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 JRNZ 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 JRZ 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 LDIR 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 LDIR ; 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? JRZ CALLP2 ; IF MULTCMD ; Multiple commands allowed? CPI CMDSEP ; Command separator? JRZ CALLP2 ENDIF ; MULTCMD ; CPI ' ' ; End of token? JRZ CALLP2 INX H JR 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 JRZ CALLP5 ; IF MULTCMD ; Multiple commands allowed? CPI CMDSEP ; Done if command separator JRZ CALLP4 ENDIF ; MULTCMD ; INR B ; Increment character count INX H ; Point to next INX D JR 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 0080 ; ; ; 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 JRNZ MLA4 ; Found it -- load it and run ENDIF ; DRVPREFIX ; IF NOT DRVPREFIX MLARUN: LXI H,PATH ; Point to path ENDIF ; DRVPREFIX ; MLA0: MOV A,M ; Get drive ORA A ; 0=done=command not found ; IF CMDRUN ; Command run facility JRNZ 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 LDIR ; IF ROOTONLY ; Look for external command JR MLA3RT ENDIF ; ROOTONLY ; IF NOT ROOTONLY XRA A ; A=0 JR 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? JRNZ 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 ; Poin to next entry in path PUSH H ; Save pointer ANI 7FH ; Mask out system bit CPI CURIND ; Current user specified? JRNZ 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 JRNZ 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 ptr to next path entry JRZ 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 JRZ 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? JRC 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 JRNZ MLA6 ; Read error or EOF? LXI D,128 ; Move 128 bytes per sector DAD D ; Point to next sector in HL JR 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 [Left:nn] or [On:nn], depending ; on your equate settings (BYTLOS and SHOW). Normal users will be ; shown their time-left-on-system (i.e. [Left:nn]), while those with ; WHEEL privileges or unlimited time will be shown their time-on-system ; (i.e. [On:nn]). ; 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 JRZ TIME1 ; User has unlimited time LDA WHLADR ORA A JRNZ TIME1 ; Wheel byte is on POP PSW ; TOS in A MOV C,A ; Now in C MOV A,B ; Maxtime in A SUB C ; Maxtime-TOS=TLOS LXI H,TLOS ; Storage area CALL DEC8 ; Convert/store to ascii LXI H,TLOSM CALL PRIN1 ; Print first part LXI H,TLOS2 JMP PRIN1 ; And second part, exit from prin1 ; TIME1: POP PSW ; Get TOS for wheel or unlimited time users ; IF NOT SHOW RET ENDIF ; IF SHOW LXI H,TLOS1 ; Storage area CALL DEC8 ; Convert/ store to ascii LXI H,TLOSM1 CALL PRIN1 ; Print first part [On:xx LXI H,TLOS2 JMP PRIN1 ; second part, then exit from prin1 ENDIF ; TLOSM: DB '[Left:' TLOS: DB ' ',0 ; Buffer for tlos or tos ; IF SHOW TLOSM1: DB '[On:' TLOS1: DB ' ',0 ; Buffer for tlos or tos ENDIF ; TLOS2: 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 JRNC DEC82 ; Still + ADD D ; Now add it back MOV B,A ; Remainder MOV A,C ; Get 100/10 CPI '1' ; Zero? JRNC DEC84 ; Yes MOV A,E ; Check flag ORA A ; Reset? MOV A,C ; Restore byte JRZ 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 JRNC DEC81 ; Do it again ADI '0' ; Make ASCII MOV M,A ; And store it POP D POP B RET ENDIF ; B5TLOS AND NOT B5CLOCK ;..... ; ; ;----------------------------------------------------------------------- ; ; Default path used for path command-search ; IF INTPATH ; Use this path? PATH: IPATH ; Macro defined up front ; IF WHEEL WHLPTH: DB 0,SYSUSR ; Filled dynamically based on wheel byte ENDIF ; WHEEL ; DB 0 ; Terminating 0 for last pair ENDIF ; INTPATH ; ;----------------------------------------------------------------------- ; **** Section 6 **** ; ; COMMAND LINE RECALL/EDIT CODE ; ; ; Standard wordstar key strokes move you around(up,down,left,right) in ; either the current line or the buffer ; del,ctl-h,ctl-g work at the end of the line on the previous character, while ; inside the line they erase the character under the cursor ; For each new line ins/overstrike defaults to over strike ; , toggled by ctrl-v ; ctrl-u clears the current line ; ctrl-c at the beginning of the line resets disk subsystem and causes warmboot ; ctrl-p toggles lpt: echo if wheel is on ; ctrl-a backs you up to the character after the previous delimiter ( or bol ) ; ctrl-f moves you foreward to the character after the next delimiter ( or eol) IF CLINER ;these are equated to the word star cursor control codes PREVLINC EQU 'E'-'@' ;char to rec to back up a line NEXTLINC EQU 'X'-'@' ; " " " " move up a line PREVCHRC EQU 'S'-'@' ; " " " " back up a char NEXTCHRC EQU 'D'-'@' ; " " " " move forw a char BACKSPC EQU 'H'-'@' ; " " " " cause dest char delete DELCHRC EQU 7FH ; " " " " cause dest char delete DELCHRG EQU 'G'-'@' ; " " " " cause dest char delete INSOVRC EQU 'V'-'@' ; " " " " tog ins/overstrike ABOLINC EQU 'U'-'@' ; " " " " abort current line input PRTTOGC EQU 'P'-'@' ; " " " " tog echo to lpt: WRDBCKC EQU 'A'-'@' ; " " " " back up a word WRDFORC EQU 'F'-'@' ; " " " " move foreward a word ;PRTTOGF controls the emulation of the CTRL-P in CPM, set ; to yes to enable(if wheel) simultaneous LPT: echo. PRTTOGF EQU NO ;FULEDITF enables the extended editing control of cursor back/fore ward ; a delimiter at a time FULEDITF EQU YES ;these are set for use on an adm terminal CURFORE EQU 0CH ;char to send to move cursor foreward CURBACK EQU 08H ;char to send to move cursor backward READLN EQU 0AH ;bdos ftn num read line ; CLRBUFON if yes enables extended BDOS call CLRBUF to allow a routine ; to clear the recall buffer, used in clearing buffer for next caller ; in an RCPM CLRBUFON EQU YES CLRBUF EQU 0FEH ;extended bdos ftn to clear recall buffer ;for next caller READINP: MOV A,C ;get bdos ftn call number IF CLRBUFON CPI CLRBUF ;=our clear JRNZ CHKRDLN LXI H,LINBUF+1 ;point to chrcnt field of first line LXI D,BUFLEN ;length of line MVI B,MAXLIN+1 ;total lines(count from 0) XRA A CLRRBUF: MOV M,A ;clear chrcnt field DAD D ;next line DJNZ CLRRBUF RET ENDIF ;CLRBUFON CHKRDLN: CPI READLN ;BDOS FTN=READLN? BDOSJMP EQU $+1 ;pointer for in line code modification JNZ bdosloc+6 ;nz=no XCHG MVI A,BUFLEN-2 CMP M ;recall buff only buflen bytes/line JRC OKLEN ;c=theirs bigger than ours,clip to ours MOV A,M ;theirs less,only read that many OKLEN: STA GBUFLEN ;save max to read(ours or thiers) INX H XRA A MOV M,A STA INSFLG ;start out in overstrike mode SHLD LINPNT XCHG RINP1: PUSH D ;DE=(addr-1) of next place to put input ; char BIOCAL5:CALL BIOS+9 ;get char via direct bios call POP D ;current place back LHLD LINPNT CPI PREVLINC ;=prev line? JZ PREVLIN CPI NEXTLINC ;=next line? JZ NEXTLIN CPI PREVCHRC ;=prev char? JZ PREVCHR CPI NEXTCHRC ;=next char? JZ NEXTCHR CPI ABOLINC ;=abort line? JZ ABOLIN CPI BACKSPC ;=back space? JZ DELCHR CPI DELCHRC ;=delete? JZ DELCHR CPI DELCHRG ;=delete in line? JZ DELCHR IF PRTTOGF ;printer ctrl-p enabled? CPI PRTTOGC JZ PRTTOG ENDIF ;PRTTOGF IF FULEDITF ;FORWARD/BACKWARD word enabled? CPI WRDBCKC ;code for back a word? JZ WRDBCK CPI WRDFORC ;code for fore a word? JZ WRDFOR ENDIF ;FULEDITF CPI INSOVRC ;=tog insert/overstrike? JZ TINSOVR CPI CR ;=cr? JRZ DONINP CPI 03 ;=ctrl-c JRZ CTRLCDO PUSH PSW ;save chr LDA INSFLG ;ins/overstrike ORA A JRZ RDINP3 ;z=overstrike CALL ENDLINQ ;at end of line? CNZ INSCHR ;z=yes,go insert it RDINP3: POP PSW BCKREAD: INX D ;store ctrl char in array CALL DOHAT ;store chr,display char or ^ if ctrl CALL ENDLINQ JRNC RDINP4 INR M ;up char count RDINP4: MOV C,M ;get cnt LDA GBUFLEN CMP C JRNZ RINP1 ; this line done,copy to recall buffer DONINP: MOV C,M ;get chr cnt MOV A,C ;if just a cr, dont wipe curlin in ;recall buffer, just keep it around ORA A JRZ DONINP1 PUSH H ;save addr of chrcnt PUSH B CALL CALCLIN ;get offset into buf for curlin line XCHG ;DE=offset of destination now POP B POP H ;source of move MVI B,0 INX B LDIR ;do it DONINP1: MVI A,0DH CALL CONOUT ; up recall buffer line pointer and keep in bounds UPLINEC: LDA CURLIN ;this line filled in INR A ; enter with a as current line and mask to bounds INBOUNDS: ANI MAXLIN STA CURLIN ;move on to next RET ;* back up in the line PREVCHR: CALL GOBCK ;use common routine JRINP1: JMP RINP1 ;* go foreward in the input array NEXTCHR: CALL GOFORE ;Move cursor to next char(stop at EOL) JR JRINP1 ;* delete char behind cursor DELCHR: CALL DELCHR1 ;use common routine JR JRINP1 ;* ctrl c entered, reset disk system CTRLCDO: MOV A,M ;if at begining of line do a drive reset ORA A JNZ BCKREAD ;nz=not beginning CALL RESET ;clear disk subsystem JMP 0 ;wboot ;* line was aborted ABOLIN: CALL ABOLIN1 ;use routine to delete line JRINP11: JR JRINP1 ;* toggle print/noprint IF PRTTOGF PRTTOG: LDA WHLADR ;make sure wheel is on to allow ftn ORA A JRZ JRINP11 ;z=no wheel LDA BDOSLOC+PRTTOGL ;addr of byte inside BDOS for simul LPT: CMA STA BDOSLOC+PRTTOGL JR JRINP11 ENDIF ;PRTTOGF ;* toggle insert/overstrike mode TINSOVR: LDA INSFLG CMA ;complement it STA INSFLG JR JRINP11 ;* previous line was requested PREVLIN: LDA CURLIN ;get current line DCR A CALL INBOUNDS ;mask to boundary CALL MOVLIN ;move from recal buf to bufsiz and echo it JR JRINP11 ;* next line was requested NEXTLIN: CALL UPLINEC ;inc curlin, keep in bounds CALL MOVLIN ;move from recall buf to bufsiz and echo it JRINP12: JR JRINP11 IF FULEDITF ;* move backwards to prev delimiter WRDBCK: CALL GOBCK ;back up the cursor JRZ JRINP12 ;z=beginning of the line CALL SDELM ;are we at a delimiter? JRNZ WRDBCK ;nz=no JR JRINP12 ;yes,stop here ;* move forward to next delimiter WRDFOR: CALL GOFORE ;at the end of line JRZ JRINP12 ;z=yes,done CALL SDELM ;are we at a delimiter? JRNZ WRDFOR ;nz=no JR JRINP12 ENDIF ;FULEDITF ;* char entered in middle of line and we are in insert mode INSCHR: MOV A,M CPI BUFLEN-2 RZ PUSH H ;save ptr to chr cnt PUSH D ;save addr-1 of next char loc PUSH D INSCHR1: CALL GOFORE ;move cursor to end of the line JRNZ INSCHR1 POP H ;we will back up to this addr PUSH D ;point to last char loc POP B INX B ;point to last+1 INSCHR2: LDAX D STAX B CALL DOHAT0 ;display chr or ^ if ctrl DCX B PUSH B CALL GOBCK ;move cursor back PUSH PSW ;need the flags INX D ;GOBCK dcx'ed it CALL GOBCK POP PSW POP B JRNZ INSCHR2 ;z if DE=HL INSCHR3: POP D POP H INR M RET ;***** SUBROUTINE SECTION ; move from line spec'ed by curlin in recall buff to current input line MOVLIN: CALL ABOLIN1 ;delete current line on screen CALL CALCLIN ;calc mem addr for line in recall buf ;HL=ADDR LDED LINPNT ;addr of buffer to put chars in MOV A,M ;get length MOV B,A STAX D ;save it ORA A ;z=none(chrcnt=0 this line) RZ MOVLIN1: INX H INX D MOV A,M ;get data CALL DOHAT ;put up char or ^ if ctrl DJNZ MOVLIN1 ;DE=addr of last char in buf,next free=DE+1 RET ; calc mem addr in recall buf ; enter with a=line# offset to calc CALCLIN: LDA CURLIN ;get current line # CALLIN0: LXI H,LINBUF+1 ;point to chrcnt field of first line in recall ;buffer LXI D,BUFLEN ;chars/line+chrcnt byte+bufsiz byte CALLIN1: ORA A RZ ;z=done DAD D ;point to next line DCR A JR CALLIN1 ; move cursor foreward on screen, point to next char in mem ; ret z if eol,nz if not GOFORE: CALL ENDLINQ ;returns z=at end of line RZ MVI A,CURFORE ;code to move cursor foreward CALL CONOUT INX D ;point to right place XRA A DCR A RET ; store at current loc, put char to console or ^ if ctrl char DOHAT: STAX D ;save chr in a DOHAT0: CPI 20H ;>space JRNC DOHAT1 ;nc=yes MVI A,'^' ;put up a ^ DOHAT1: CALL CONOUT RET ; common routine for deleting char on crt DELCHR1: CALL ENDLINQ ;are we at end of line JRNZ DELINLN ;nz=no DELCHR2: CALL GOBCK ;move back if can(cursor with it) RZ ;z=begin of line MVI A,' ' ;send space to erase char CALL CONOUT INX D ;point to right place(gobck clobbered it) CALL GOBCK ;move cursor DCR M ;dec char count RET DELINLN: PUSH H ;save pointer to chrcnt PUSH D ;save last loaded char pos in CMDLIN PUSH D DELINL1: INX D CALL ENDLINQ ;are we at end of the line? JRZ DELINL2 ;z=yes PUSH D ;shift character ahead of cursor pos to POP B ;the cursor position INX B LDAX B STAX D CALL DOHAT ;display it JR DELINL1 DELINL2: DCX D CALL GOFORE ;delete the last char typed in old line CALL DELCHR2 POP H ;HL now points to where cursor was DELINL3: CALL GOBCK ;back up to there JRNZ DELINL3 ;NZ=not yet POP D POP H RET ; common routine for going backwards in the line GOBCK: MOV A,L ;HL=addr to move cursor to CMP E ;does de point there? RZ ;z=yes MVI A,CURBACK ;send out backspace code CALL CONOUT DCX D ;point to input array loc XRA A DCR A ;set nz on return RET ; check if de points to very last input char, returns z flag if so ENDLINQ: PUSH H MOV C,M ;get cnt from (HL) MVI B,0 DAD B MOV A,L ;check if at end of line CMP E POP H RET ; delete all chars to the prompt ABOLIN1: CALL GOFORE ;move to the end of the line JRNZ ABOLIN1 ;nz=not there yet ABOLIN2: CALL DELCHR2 ;erase line one char at a time JRNZ ABOLIN2 ;nz=not at begin yet RET ENDIF ; CLINER ; ; Stack area ; IF INTSTACK ; Internal stack DS 48 ; Stack area ; STACK EQU $ ; Top of stack ENDIF ; INTSTACK ; ; ; 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 ;..... ; ; END