home *** CD-ROM | disk | FTP | other *** search
Text File | 1987-10-30 | 124.1 KB | 4,074 lines |
- ; PROGRAM: ZCPR
- ; VERSION: 3.3
- ; DERIVATION: ZCPR30
- ; AUTHOR: Jay Sage
- ; DATE: May 28, 1987
-
- ; ZCPR33 is copyright 1987 by Echelon, Inc. All rights reserved. End-user
- ; distribution and duplication permitted for non-commercial purposes only.
- ; Any commercial use of ZCPR33, defined as any situation where the duplicator
- ; recieves revenue by duplicating or distributing ZCPR33 by itself or in
- ; conjunction with any hardware or software product, is expressly prohibited
- ; unless authorized in writing by Echelon.
- ;
- ; Echelon specifically disclaims any warranties, expressed or implied,
- ; including but not limited to implied warranties of merchantability and
- ; fitness for a particular purpose. In no event will Echelon be liable for
- ; any loss of profit or any other commercial damage, including but not limited
- ; to special, incidental, consequential, or other damages.
- ;
- ; Echelon can be contacted at:
- ; Echelon, Inc.
- ; 885 N. San Antonio Road
- ; Los Altos, California USA 94022
- ; (415) 948-3820
-
-
- ;-----------------------------------------------------------------------------
- ;
- ; A C K N O W L E D G M E N T S
- ;
- ;-----------------------------------------------------------------------------
-
- ; Many people have played a role in the development of ZCPR in general and
- ; ZCPR33 in particular. It all started when "The CCP Group," including
- ; Richard Conn, Ron Fowler, Keith Petersen, Frank Wancho, Charlie Strom, and
- ; Bob Mathias decided that by rewriting the CP/M command processor to take
- ; advantage of Zilog-specific opcodes they could save enough code to enhance
- ; some of the features. Richard Conn then extended that development through
- ; ZCPR2 to ZCPR3 (3.0). Just a little over two years ago, I took the first
- ; step to enhance ZCPR3 by making it get the maximum drive and user values
- ; from the environment instead of hard coding them in. This version was
- ; distributed privately as ZCPR31. Along the way to what is now ZCPR
- ; version 3.3 a number of others have made valuable contributions: Steve
- ; Kitahata, Michael Bate, Bruce Morgen, Roger Warren, Dreas Nielsen, Bob Freed,
- ; Al Hawley, Howard Goldstein, and many others who have stimulated developments
- ; by pointing out problems or asking questions.
-
- ; I would like particularly to acknowledge two people who have played a very
- ; significant role in these developments. One is Al Hawley. He introduced
- ; the idea of having the DUOK flag in the environment control how the CPR
- ; would respond to the DU: form of directory reference. He also originated
- ; the idea of using the high bit of the first character of each command name
- ; to control whether or not it would be wheel restricted. Finally, he
- ; contributed the basic structure of the highly efficient, elegant, and more
- ; general number evaluation routines in the code.
-
- ; My biggest debt of gratitude is to Howard Goldstein. His role in the
- ; development of ZCPR33 goes back about a year, when he contributed the first
- ; correct implementation of the minpath feature. More recently, during the
- ; period of intense development since Echelon expressed its interest in my
- ; writing the official 3.3 version, he and I have shared an especially
- ; enjoyable and fruitful relationship. Most of the newest ideas have been
- ; worked out jointly, and Howard has done a great deal to keep my code and
- ; concepts on track. He discovered many ways to pare the code down and, more
- ; importantly, uncovered numerous subtle bugs. He recoded the SAVE command
- ; to make it more compact and reliable.
- ;
- ; Jay Sage
- ; May 28,1987
-
- ;-----------------------------------------------------------------------------
- ;
- ; U S E R C O N F I G U R A T I O N
- ;
- ;-----------------------------------------------------------------------------
-
- ; The following MACLIB statements load all the user-selected equates
- ; which are used to customize ZCPR33 for the user's working environment.
- ; NOTE -- TRUE & FALSE are defined in Z3BASE.
-
- maclib z3base.lib
- maclib z33hdr.lib
-
- ; Check that the configuration includes the required facilities
-
- ; A ZCPR33 system is assumed to include certain minimal features, including
- ; an external file control block, external path, shell stack, message buffer,
- ; external environment descriptor, multiple command line, and external stack.
- ; If wheel checking is enabled in the Z33HDR.LIB file, then there must be
- ; an address defined for the wheel byte in the Z3BASE.LIB file.
-
- errflag defl extfcb eq 0 ; External command FCB
- errflag defl errflag or [ expath eq 0 ] ; Symbolic path
- errflag defl errflag or [ shstk eq 0 ] ; Shell stack
- errflag defl errflag or [ z3msg eq 0 ] ; Message buffer
- errflag defl errflag or [ z3env eq 0 ] ; Environment descriptor
- errflag defl errflag or [ z3cl eq 0 ] ; Multiple command line
- errflag defl errflag or [ extstk eq 0 ] ; External stack
- if wheel or wdu or wpass or wprefix or whldir
- errflag defl errflag or [ z3whl eq 0 ] ; Wheel byte
- endif ;wheel or wdu or wpass or wprefix or whldir
-
- if errflag
-
- *** NOT ALL REQUIRED ZCPR3 FACILITIES ARE SUPPORTED ***
-
- else ; go ahead with the assembly
-
-
- ;-----------------------------------------------------------------------------
- ;
- ; D E F I N I T I O N S S E C T I O N
- ;
- ;-----------------------------------------------------------------------------
-
-
- ; ---------- Macro definitions
-
- maclib z33mac.lib ; Library of macros for ZCPR33
-
-
- ; ---------- ASCII definitions
-
- ctrlc equ 03h
- bell equ 07h
- tab equ 09h
- lf equ 0ah
- cr equ 0dh
-
-
- ; ---------- Operating system addresses
-
- wboot equ base+0000h ; CP/M warm boot address
- udflag equ base+0004h ; User number in high nybble, disk in low
- bdos equ base+0005h ; BDOS function call entry point
- tfcb equ base+005ch ; Default FCB buffer
- tfcb2 equ tfcb+16 ; 2nd FCB
- tbuff equ base+0080h ; Default disk I/O buffer
- tpa equ base+0100h ; Base of TPA
- bios equ ccp+0800h+0e00h ; BIOS location
-
-
- ; ---------- Error codes
-
- ; ZCPR33 uses the error byte at the beginning of the message buffer as a flag
- ; to show what kind of error occurred. Advanced error handlers will be able
- ; to help the user further by suggesting the possible cause of the error.
- ; Error code 6 for an ECP error is determined by the code and cannot be
- ; changed (without increasing code length).
-
- ecduchg equ 1 ; Directory change error -- attempt to change
- ; ..logged directory when under control of
- ; ..wheel byte and wheel is off
-
- ecbaddir equ 2 ; Bad directory specification -- logging of
- ; ..user number beyond legal range,
- ; ..nonexistent named directory
-
- ecbadpass equ 3 ; Bad password -- incorrect password entered
-
-
- ecbadcmd equ 5 ; Bad command form -- wildcard or file type
- ; ..present in command verb
-
- ececperr equ 6 ; ECP error -- command could not be executed
- ; ..by ECP, error handling was forced by a
- ; ..transient for its own reasons
- ; (DO NOT CHANGE FROM 6)
-
- ecnocmd equ 7 ; Command file not found -- command that skips
- ; ..ECP could not be executed, GET could not
- ; ..find file to load
-
- ecambig equ 8 ; Ambiguous file specification where not
- ; ..allowed (SAVE, GET, REN)
-
- ecbadnum equ 9 ; Bad numerical value -- not a number where
- ; ..number expected, number out of range
-
- ecnofile equ 10 ; File not found -- REN, TYPE, LIST could not
- ; ..find a specified file
-
- ecdiskfull equ 11 ; Disk directory or data area full
-
- ectpafull equ 12 ; TPA overflow error
-
-
- ; ---------- Multiple command line equates
-
- ; The multiple command line buffer is located in a protected area in memory so
- ; that it is not overwritten during warm boots. It includes some pointers so
- ; that when ZCPR33 starts it can tell where to start reading the command line.
- ; BUFSIZ and CHRCNT are not used by ZCPR33 but are provided so that the BDOS
- ; line input function can be used to read in a command line.
-
- nxtchr equ z3cl ; Address where pointer to next command to
- ; ..process is kept
- bufsiz equ z3cl+2 ; Address where size of buffer is kept
- chrcnt equ z3cl+3 ; Address where length of string actually in
- ; ..the buffer is kept (not always reliable)
- cmdlin equ z3cl+4 ; Address of beginning of command line buffer
- buflen equ z3cls ; Length of command line buffer
-
-
- ; ---------- Command file control block
-
- ; In ZCPR33 the file control block for commands must be located in protected
- ; memory. This not only frees up valuable space in the command processor for
- ; code but also makes it possible for programs to determine by what name they
- ; were invoked.
-
- cmdfcb equ extfcb
-
-
- ; ---------- External CPR stack
-
- stack equ extstk+48 ; Set top-of-stack address
- pwlin equ extstk ; Place line at bottom of stack
-
-
- ; ---------- Environment
-
- quietfl equ z3env+28h ; Quiet flag
- maxdrenv equ z3env+2ch ; Maximum drive value
- maxusrenv equ z3env+2dh ; Maximum user value
- duokfl equ z3env+2eh ; Flag indicating acceptance of DU: form
- crttxt0 equ z3env+33h ; Address of number of lines of text on the
- ; ..screen of CRT0
-
-
- ; ---------- Message buffer
-
- ecflag equ z3msg ; Error return code flag
- ifptrfl equ z3msg+1 ; Pointer to current IF level
- ifstatfl equ z3msg+2 ; Flow control status byte
- cmdstatfl equ z3msg+3 ; Command status flag
- cmdptr equ z3msg+4 ; Pointer to currently running command
- zexinpfl equ z3msg+7 ; ZEX input status/control flag
- zexrunfl equ z3msg+8 ; ZEX running flag
- errcmd equ z3msg+10h ; Error handling command line
- xsubflag equ z3msg+2ch ; XSUB input redirection flag
- subflag equ z3msg+2dh ; Submit running flag
- curusr equ z3msg+2eh ; Currently logged user
- curdr equ z3msg+2fh ; Currently logged drive
-
-
- ;-----------------------------------------------------------------------------
- ;
- ; C O D E M O D U L E S S E C T I O N
- ;
- ;-----------------------------------------------------------------------------
-
- page
-
- ; ZCPR33-1.Z80
-
- ;=============================================================================
- ;
- ; E N T R Y P O I N T S A N D H E A D E R S T R U C T U R E
- ;
- ;=============================================================================
-
- if not rel ; If generating absolute code
- org ccp
- endif ;not rel
-
-
- ; ENTRY POINTS INTO ZCPR33
- ;
- ; For compatibility with CP/M, two entry points are provided here. In
- ; standard CP/M if the code is entered from the first entry point, then the
- ; command in the resident command buffer is executed; if entered from the
- ; second entry point, the command line is flushed. With ZCPR33 and its
- ; multiple command line buffer, these two entry points function identically
- ; and go to the same address.
- ;
- ; We have kept the entry points in their standard locations but have used a
- ; relative jump for the second entry point and replaced the last byte with the
- ; version number. In this way the version number occupies a position that
- ; would otherwise contain the page number at which the CPR runs. It will
- ; always be possible, therefore, to distinguish ZCPR33 and later versions
- ; from other command processors. The first jump is kept as an absolute jump
- ; so that 1) the code will be compatible with Z-COM and Z3-DOT-COM and 2) the
- ; execution address of a CPR module can always be determined.
-
- entry:
- jp zcpr
-
- jr zcpr
-
- version:
- defb 33h ; Version ID squeezed in here (offset = 5)
-
- ;-----------------------------------------------------------------------------
-
- ; Configuration information
-
- options: ; (offset = 6)
- optflag badduecp,rootonly,ndrenv,fcpenv,rcpenv,inclenv,aduenv,duenv
- optflag highuser,drvprefix,scancur,incldir,incldu,dufirst,accptdir,accptdu
- optflag no,pwcheck,pwnoecho,wdu,wpass,wprefix,fastecp,skippath
-
- attdir defl [ comatt eq 80h ] or [ comatt eq 01h ] or [ not attchk ]
- attsys defl [ comatt eq 00h ] or [ comatt eq 01h ] or [ not attchk ]
- subquiet defl [ subnoise eq 1 ]
- subecho defl [ subnoise gt 1 ]
-
- optflag shellif,attsys,attdir,attchk,subecho,subquiet,subclue,subon
-
- ; Byte with information about the alternate colon option. If the byte is
- ; zero, the option is not supported. Otherwise the byte contains the
- ; prefix character that serves as an alias for a colon prefix. Offset = 10.
-
- if altcolon
- defb altchar
- else
- defb 0
- endif ;altcolon
-
- ; Byte with information about the FASTECP implementation (option bit above
- ; indicates whether the feature is enabled at all). If no character appears
- ; here (zero byte), then only a leading space can be used. Otherwise, the
- ; first seven bits contain the character, and the high bit, if set, indicates
- ; that ONLY this character will be recognized and not a space. Offset = 11.
-
- if fastecp and altspace
- if altonly
- defb ecpchar + 80h
- else ;not altonly
- defb ecpchar
- endif ;altonly
- else ;no alternate character
- defb 0
- endif ;fastecp and altspace
-
- defb 0,0,0,0 ; Space reserved for expansion
-
- ;-----------------------------------------------------------------------------
-
- ; Entry points to file name parsing code.
-
- ; Entry point REPARSE. A call to this point can be used to parse a command
- ; line tail into the default file control blocks at 5CH and 6CH. Each time
- ; the parser is called it leaves the starting address of the second token in
- ; the PARESPTR address below so that successive calls to the routine reparse
- ; the command tail one token later. A program can load its own pointer into
- ; PARSEPTR as well. Offset = 16 (10h).
-
- reparse:
- parseptr equ $+1 ; Pointer for in-the-code modification
- ld hl,0
- jp parsetail
-
- ; Entry point SCAN. A call to this point can be used to parse a single token
- ; pointed to by HL into the FCB pointed to by DE. Offset 22 (16h).
-
- scan:
- jp scanner
-
- ;-----------------------------------------------------------------------------
-
- ; BUFFERS
- ;
- ; In this area various data items are kept. First comes the list of commands
- ; supported by ZCPR33; then comes the name of the extended command processor
- ; (ECP). By putting these items here, an 'H' command in the RCP or a utility
- ; like SHOW.COM can find this information and report it to the user.
-
-
- ; ---------- RESIDENT COMMAND TABLE
-
- ; The command table entry is structured as follows: First there is a byte
- ; which indicates the number of characters in each command. Then there is a
- ; series of entries comprising the name of a command followed by the address
- ; of the entry point to the code for carrying out that command. Finally,
- ; there is a null byte (00h) to mark the end of the table. Offset = 25 (19h).
-
-
- cmdtbl:
- defb cmdsize ; Length of command names
- ctable ; Define table via macro in Z33HDR.LIB
- defb 0 ; End of table
-
- ; ---------- NAME FOR EXTENDED COMMAND PROCESSOR
-
- ; The name of the extended command processor is placed here after the command
- ; table so that utilities like SHOW or an RCP 'H' command can find it.
-
- ecpfcb:
- ecpname ; From Z33HDR.LIB
-
-
- ; ---------- FILE TYPE FOR TRANSIENT COMMANDS (usually COM)
-
- ; This file type also applies to the extended command processor name.
-
- commsg:
- comtyp ; From Z33HDR.LIB
-
-
-
- ; ---------- SUBMIT FILE CONTROL BLOCK
-
- if subon ; If submit facility enabled ...
-
- subfcb:
- defb subdrv-'A'+1 ; Explicit drive for submit file
- defb '$$$ ' ; File name
- subtyp ; From Z33HDR.LIB
- defb 0 ; Extent number
- defb 0 ; S1 (user number 0)
- subfs2:
- defs 1 ; S2
- subfrc:
- defs 1 ; Record count
- defs 16 ; Disk group map
- subfcr:
- defs 1 ; Current record number
-
- endif ; subon
-
- ; End ZCPR33-1.Z80
-
- page
-
- ; ZCPR33-2.Z80
-
- ;=============================================================================
- ;
- ; C O M M A N D L I N E P R O C E S S I N G C O D E
- ;
- ;=============================================================================
-
- ; MAIN ENTRY POINT TO CPR
-
- ; This is the main entry point to the command processor. On entry the C
- ; register must contain the value of the user/drive to be used as the current
- ; directory.
-
- zcpr:
- ld sp,stack ; Reset stack
-
- if pwnoecho
- ld a,0c3h ; Reenable BIOS conout routine
- ld (bios+0ch),a ; ..after a warmboot
- endif ;pwnoecho
-
- ld b,0fh ; Keep nibble mask in B
-
- ; If the HIGHUSER option is enabled, we compare the user/drive in the login
- ; byte in C to the values stored in the message buffer. If, ignoring bit 4
- ; of the user number, they match, then we remain in the current area, which
- ; may be a user area above 15.
-
- if highuser
-
- ld a,c ; Copy user/drive byte to A
- and b ; Isolate drive
- ld d,a ; ..and move to D
- ld a,c ; Get full byte back
- swap ; Swap nibbles
- and b ; Isolate user number
- ld e,a ; ..and move to E
- ld hl,(curusr) ; Get old curdr/curusr into HL
- sbc hl,de ; Subtract new values from old (carry is clear)
- ex de,hl ; Switch new values into HL, diff into DE
- ld a,d ; Combine two parts of difference
- or e
- and b ; Ignore bit for high user numbers
- jr z,zcpr1 ; Skip update if no change in DU
- ld (curusr),hl ; Update values of current drive and user
- zcpr1:
-
- else ;not highuser
-
- ld a,c ; Copy user/drive byte to A
- and b ; Isolate drive
- ld h,a ; ..and move to H
- ld a,c ; Get full byte back
- swap ; Swap nibbles
- and b ; Isolate user number
- ld l,a ; ..and move to L
- ld (curusr),hl ; ..and save them
-
- endif ;highuser
-
- ; This block of code is executed when submit processing is enabled. We log
- ; into user area 0, where the submit file is kept, and we search the
- ; designated drive for the file. The result is kept in SUBFLAG. This code
- ; only has to be executed on reentry to the command processor at the main
- ; entry point. Commands that do not reboot but simply return to the CPR will
- ; execute without the disk reset and file search required here. Ron Fowler
- ; pointed out a shortcut based on the fact that after a disk reset, the A
- ; regiser contains a value of 0 if there is no file on drive A with a '$' in
- ; the file name and 0FFH if there is such a file. Thus if A = 0, there can
- ; be no '$$$.SUB' file on drive A. This trick is, unfortunately, not reliable
- ; under some versions of ZRDOS. Therefore, an option has been included to
- ; use or not use this shortcut.
-
- if subon ; If submit facility enabled ..
-
- call defltdma ; Set DMA address to 80H
- ld a,0 ; Log into user area 0
- call setuser
- ld c,0dh ; Reset disk system (returns 0FFH if a $$$.SUB
- call bdossave ; ..file might exist in user 0)
- ld de,subfcb ; Point to submit file FCB with explicit drive
-
- if subclue
- call nz,srchfst ; Search only if flag says it could exist
- else ;not subclue
- call srchfst ; Search for the file unconditionally
- endif ;subclue
-
- ld (subflag),a ; Set flag for result (0 = no $$$.SUB)
-
- else ;not subon
-
- ld c,0dh ; Reset disk system
- call bdossave
-
- endif ; subon
-
- jr nextcmd ; Go to entry point for processing next command
-
-
- ;-----------------------------------------------------------------------------
-
- ; NEW COMMAND LINE ENTRY POINT
-
- ; This entry point is used when ZCPR33 finds the command line empty. A call to
- ; READBUF gets the next command line from the following possible sources in
- ; this order:
- ; 1) a running ZEX script
- ; 2) the submit file $$$.SUB (if enabled)
- ; 3) the shell stack
- ; 4) the user
- ; If the line comes from the shell stack, then the shell bit in the command
- ; status flag is set.
-
- restart:
- ld sp,stack ; Reset stack
- xor a
- ld (cmdstatfl),a ; Reset ZCPR3 command status flag
- inc a ; Set ZEX message byte to 1 to
- ld (zexinpfl),a ; ..indicate command prompt
- if subon
- ld (xsubflag),a ; Ditto for XSUB flag
- endif ;subon
- ld hl,cmdlin ; HL --> beginning of command line buffer
- ld (nxtchr),hl ; Save as pointer to next character to process
- ld (hl),0 ; Zero out command line (in case of warm boot)
- push hl ; Save pointer to command line
- call readbuf ; Input command line (ZEX, submit, shell,
- ; ..or user)
- pop hl ; Get back pointer to command line
- ld a,(hl) ; Check for comment line
- cp comment ; Begins with comment character?
- jr z,restart ; If so, go back for another line
- ; Otherwise, fall through
-
- ;-----------------------------------------------------------------------------
-
- ; COMMAND CONTINUATION PROCESSING ENTRY POINT
-
- ; This is the entry point for continuing the processing of an existing command
- ; line. The current drive and user values as known to the CPR are combined
- ; and made into the user/drive byte that CP/M keeps at location 0004. If the
- ; HIGHUSER option is enabled, the user number for this byte is forced to be
- ; in the range 0..15. Next the command status flag is processed. The error
- ; and ECP bits in the actual flag are reset, and the original flag is checked
- ; for an ECP error return (both ECP bit and error bit set). In that case,
- ; control is transferred to the error handler.
-
- nextcmd:
- ld hl,(curusr) ; Get currently logged drive and user
- ld a,l ; Work on user number
- if highuser
- and 0fh ; Keep value modulo 16
- endif ;highuser
- swap ; Get user into high nibble
- or h ; ..and drive into low nibble
- ld (udflag),a ; Set user/disk flag in page 0
-
- ld a,2 ; Turn ZEX input redirection off
- ld (zexinpfl),a
- if subon
- ld (xsubflag),a ; Turn off XSUB input redirection
- endif ;subon
-
- ld hl,cmdstatfl ; Point to the command status flag (CSF)
- ld a,(hl) ; Get a copy into register A
- res 1,(hl) ; Reset the actual error bit
- res 2,(hl) ; Reset the actual ECP bit
- and 110b ; Select ECP and error bits in original flag
- cp 110b ; Test for an ECP error
- jp z,error ; Process ECP error with error handler
-
- nextcmd1:
- ld sp,stack ; Reset stack
- call logcurrent ; Return to default directory
- ld hl,(nxtchr) ; Point to first character of next command
- push hl ; Save pointer to next character to process
-
- ; We have to capitalize the command line each time because an alias or other
- ; command line generator may have stuck some new text in. The code is shorter
- ; if we simply capitalize the entire command rather than trying to capitalize
- ; only the one command we are about to execute.
-
- capbuf: ; Capitalize the command line
- ld a,(hl) ; Get character
- call ucase ; Convert to upper case
- ld (hl),a ; Put it back
- inc hl ; Point to next one
- or a ; See if end of line (marked with null)
- jr nz,capbuf ; If not, loop back
-
- pop hl ; Restore pointer to next character to process
-
- nextcmd3:
-
- ; ZCPR33 provides a convenience feature to make it easier to enter a leading
- ; colon to force the current directory to be scanned and to make the CPR skip
- ; resident commands. If ALTCOLON is active, an alternate character can be
- ; entered as the first character of a command. The default (and recommended)
- ; alternative character is the period (it could not have any other meaning
- ; here). If FASTECP (see below) is not enabled or if ALTONLY is enabled,
- ; leading spaces on the command line are skipped before looking for the
- ; alternate character for the colon
-
- if [ not fastecp ] or [ fastecp and altonly ]
- call sksp
- endif ;[ not fastecp ] or [ fastecp and altonly ]
-
- if altcolon ; If allowing alias character for leading colon
- ; Set B = ':' and C = alias character ('.')
- ld bc,':' shl 8 + altchar
- ld a,(hl) ; Get first character in new command line
- cp c ; If first character is ALTCHAR, treat as ':'
- jr nz,nextcmd3a ; Branch if not '.'
- ld (hl),b ; Else replace with colon
- nextcmd3a:
- endif ;altcolon
-
-
- ; ZCPR33 supports three new options that can speed up command processing.
- ; FASTECP allows commands with a leading space to bypass the search for
- ; resident commands or transient commands (COM files) along the path and go
- ; directly to the extended command processor. With SKIPPATH enabled, when
- ; a command is prefixed by an explicit directory specification (but not a
- ; lone colon), searching of the path and invocation of the ECP are disabled.
- ; If the command is not found in the specified directory, the error handler
- ; is invoked immediately. Finally, if BADDUECP is enabled, when an attempt
- ; is made to log into an invalid directory, the command is sent directly to
- ; the ECP, which can provide special handling. To implement these three
- ; features, the first actual character of the command line is saved as a
- ; flag in FIRSTCHAR. My apologies for the complexity of these nested
- ; conditionals.
-
- if fastecp or skippath or badduecp
-
- ; With FASTECP we store the first actual
- ; ..character and then skip over spaces (unless ALTONLY is
- ; ..enabled, in which case we skipped spaces above)
-
- if fastecp
-
- if altspace ; If allowing alias character for leading space
- ; Set B = ' ' and C = alias character ('/')
- ld bc,' ' shl 8 + ecpchar
- ld a,(hl) ; Get first character in new command line
- cp c ; If first character is ECPCHAR treat as ' '
- jr nz,nextcmd3b ; Branch if not '/' (alternate character)
- ld (hl),b ; Else replace with space
- nextcmd3b:
- endif ;altspace
-
- ld a,(hl) ; Get first character in command line
- ld (firstchar),a ; Save it in flag
- call sksp ; Then skip leading spaces
- endif ;fastecp
-
- ; With SKIPPATH but not FASTECP we store the first
- ; ..character of the command (spaces were skipped above)
-
- if [ not fastecp ] and skippath
- ld (firstchar),a ; Store first nonspace character
- endif ;[ not fastecp ] and skippath
-
- ; With only BADDUECP (and neither SKIPPATH nor FASTECP)
- ; ..we store a null in the FIRSTCHAR flag
-
- if [ not fastecp ] and [ not skippath ]
- xor a
- ld (firstchar),a
- endif ;[ not fastecp ] and [ not skippath ]
-
- endif ;fastecp or skippath or badduecp
-
- ; Resume processing of the command line
-
- or a ; Now at end of line?
- jr z,restart ; If so, get a new command line
- cp ctrlc ; Flush ^C to prevent error-handler
- jr z,restart ; ..invocation on warm boots
-
- cp cmdsep ; Is it a command separator?
- jr nz,nextcmd4 ; If not, skip ahead to process the command
- inc hl ; If it is, skip over it
- jr nextcmd3 ; ..and process next command
-
- nextcmd4:
-
- ; Unless we are now running the external error handler, the following code
- ; saves the address of the current command in Z3MSG+4 for use by programs
- ; to determine the command line with which they were invoked.
-
- ld a,(cmdstatfl) ; Get command status flag
- bit 1,a ; Test for error handler invocation
- jr nz,nextcmd5 ; If so, skip over next instruction
- ld (cmdptr),hl
-
- nextcmd5:
- call parser ; Parse entire command line, then look for
- ; ..the command
-
-
- ;=============================================================================
-
- ; C O M M A N D S E A R C H C O D E
-
- ;=============================================================================
-
- ; CODE FOR FINDING AND RUNNING THE COMMAND
-
- ; Here is the code for running a command. Commands are searched for and
- ; processed in the following order:
- ;
- ; 1) flow control package (FCP) commands and IF state testing
- ; 2) resident command package (RCP)
- ; 3) command processor (CPR)
- ; 4) transient (COM file or extended command processor)
- ; 5) external error handler
- ; 6) internal error message and processing
- ;
- ; Special notes:
- ;
- ; a) If the current command is a shell command, special handling of flow
- ; control is required. If SHELLIF is enabled so that flow commands are
- ; allowed in shell alias scripts, then we reset the flow state to its
- ; initial condition (none) with each shell invocation (and after each
- ; command is run, we reset the shell bit in the code after CALLPROG).
- ; In this case shells will run regardless of flow state, and residual
- ; conditionals from the last running of the shell are flushed. Each
- ; shell input sequence begins afresh. On the other hand, if SHELLIF is
- ; off, flow control commands inside a shell script must be flushed so
- ; that they do not interfere with user entered commands.
- ; b) Directory prefixes are ignored for flow commands, since all flow control
- ; processing must pass through the FCP (the command must run even when
- ; the current flow state is false).
- ; c) If the command is not found in the FCP, then the current flow state is
- ; tested. If it is false, the command is flushed and the code branches
- ; back to get the next command.
- ; d) If the command had a directory prefix (a colon alone is sufficient),
- ; then steps #2 and #3 are skipped over,and the command is processed
- ; immediately as a transient program.
- ; e) In ZCPR33, unlike ZCPR30, RCP commands are scanned before CPR commands.
- ; This has been done so that more powerful RCP commands can supercede
- ; CPR commands.
- ; f) If the SKIPPATH option is enabled, when an explicit directory is
- ; specified with a command (but not just a colon), searching of the path
- ; is bypassed. If the FASTECP option is enabled, commands with leading
- ; spaces are sent directly to the ECP for processing.
- ; g) If no external command can be found, ZCPR33 performs extensive error
- ; handling. If the command error occurred while looking for a shell
- ; program, then the shell stack is popped. Otherwise, ZCPR33 tries to
- ; invoke an external, user-specified error handling command line. If
- ; none was specified or if the error handler invoked by that command
- ; line cannot be found, the internal error message (step #6) is displayed.
-
-
- ;-----------------------------------------------------------------------------
-
- runcmd:
- if shellif ; If shells reininitialize flow control...
- ld a,(cmdstatfl) ; Get command status flag
- bit 0,a ; Shell bit set?
- jr z,fcpcmd ; If not a shell, process command
- xor a ; Otherwise, shell is running, so
- ld (ifptrfl),a ; ..reinitialize the IF system and continue
- endif ;shellif
-
-
- ; ---------- Module <<1>>: Flow Control Processing
-
- ; An option is supported here to allow the address of the FCP to be obtained
- ; from the environment descriptor. This is logically consistent with the
- ; pholosopy of the Z-System and is useful when one wants to have a single block
- ; of FCP/RCP memory that can be allocated dynamically between FCP and RCP
- ; functions.
-
- fcpcmd:
-
- if fcp ne 0 ; Omit code if FCP not implemented
-
- if fcpenv ; If getting FCP address from Z3ENV
-
- ld e,12h ; Offset in Z3ENV to FCP address
- call pkgoff ; Set HL to FCP+5
- jr z,runcmd1 ; Skip if no FCP present
-
- else ; using fixed FCP address
-
- ld hl,fcp+5 ; Get address from Z3BASE.LIB
-
- endif ;fcpenv
-
-
- ; If flow control processing is not allowed in shell aliases (scripts running
- ; as shell commands), then we have to make sure that we flush any flow control
- ; commmands, otherwise the CPR will attempt to execute them as transients,
- ; with dire consequences. In the code below we check the shell bit. If it
- ; is not set, we proceed normally. If it is set, we scan for flow commands
- ; and then jump past the flow testing to RUNFCP2, where the code will flush
- ; the command if it was a flow command and execute it unconditionally if not.
-
- if not shellif
- ld a,(cmdstatfl) ; Get command status flag
- bit 0,a ; If shell bit not set,
- jr z,runfcp1 ; ..we do normal processing
- call cmdscan ; Otherwise, check for flow command
- jr runfcp2 ; ..and flush if so using code below
- endif ;not shellif
-
- runfcp1:
- call cmdscan ; Scan command table in the module
- jr z,callprog ; Run if found (with no leading CRLF)
-
- ; This is where we test the current IF state. If it is false, we skip this
- ; command.
-
- call iftest ; Check current IF status
-
- runfcp2: ; If false, skip this command and go on to next
- if drvprefix ; If DRVPREFIX we can use code below
- jr z,jpnextcmd ; ..to save a byte
- else ; Otherwise, we have to do an
- jp z,nextcmd ; ..absolute jump
- endif ;drvprefix
-
- endif ;fcp ne 0
-
-
- runcmd1:
- if fastecp or badduecp
- ld a,(firstchar) ; If FIRSTCHAR flag set for ECP invocation,
- cp ' ' ; ..then go straight to transient processing
- jr z,com
- endif ;fastecp or badduecp
-
- colon equ $+1 ; Flag for in-the-code modification
- ld a,0 ; If command had a directory prefix (even just
- or a ; ..a colon) then skip over resident commands
- jr nz,comdir
-
-
- ; ---------- Module <<2>>: RCP Processing
-
- ; An option is supported here to allow the address of the RCP to be obtained
- ; from the environment descriptor. This is logically consistent with the
- ; pholosopy of the Z-System and is useful when one wants to have a single block
- ; of FCP/RCP memory that can be allocated dynamically between FCP and RCP
- ; functions.
-
- if rcp ne 0 ; Omit code if RCP not implemented
-
- rcpcmd:
-
- if rcpenv ; If getting address of rcp from Z3ENV
-
- ld e,0ch ; Offset in Z3ENV to RCP address
- call pkgoff ; Set HL to address of RCP+5
- jr z,cprcmd ; Skip if no RCP
-
- else ; using fixed RCP address
-
- ld hl,rcp+5 ; Get address from Z3BASE.LIB
-
- endif ; rcpenv
-
- call cmdscan ; Check for command in RCP
- jr z,callproglf ; If so, run it (with leading CRLF)
-
- endif ;rcp ne 0
-
-
- ; ---------- Module <<3>>: CPR-Resident Command Processing
-
- cprcmd:
-
- ld hl,cmdtbl ; Point to CPR-resident command table
- call cmdscan ; ..and scan for the command
- jr z,callprog ; If found, run it (with no leading CRLF)
-
-
-
- ; ---------- Module <<4>>: Transient Command Processing
-
- comdir: ; Test for DU: or DIR: only (directory change)
-
- if drvprefix
-
- ld a,(cmdfcb+1) ; Any command name?
- cp ' '
- jr nz,com ; If so, must be transient or error
-
- ; Entry point for change of directory only
-
- if wdu ; If controlled by wheel..
-
- ld a,(z3whl) ; Get wheel byte
- or a ; If wheel on, go on ahead
- jr nz,comdir1
-
- if badduecp
- ld (colon),a ; Pretend there is no colon
- ld a,' ' ; Force invocation of ECP
- ld (firstchar),a
- jr com
- else ;not badduecp
- ld a,ecduchg
- jr z,error
- endif ;badduecp
-
- endif ; wdu
-
- comdir1:
- ld hl,(tempusr) ; Get temporary drive and user bytes
-
- if not highuser ; If only users 0..15 can be logged
- ld a,l ; Get user number and
- cp 16 ; ..make sure not above 15
- jr nc,baddirerr ; If out of range, invoke error handling
- endif ;not highuser
-
- dec h ; Shift drive to range 0..15
- ld (curusr),hl ; Make the temporary DU into the current DU
- call logcurrent ; Log into the new current directory
- jpnextcmd:
- jp nextcmd ; Resume command line processing
-
- else ;not drvprefix
-
- if badduecp
- xor a ; Pretend there is no colon
- ld (colon),a
- ld a,' ' ; Force invocation of ECP
- ld (firstchar),a
- else ;not badduecp
- ld a,ecduchg
- jr z,error
- endif ;badduecp
-
- endif ;drvprefix
-
-
- com: ; Process transient command
-
- ld a,(cmdstatfl) ; Check command status flag to see if
- and 2 ; ..error handler is running
- ld (zexinpfl),a ; Store result in ZEX control flag (2 will turn
- ; ..ZEX input redirection off (0 = on)
- if subon
- ld (xsubflag),a ; Turn off XSUB input redirection also
- endif ;subon
-
- ld hl,tpa ; Set default execution/load address
- ld a,3 ; Dynamically load type-3 and above ENVs
- call mload ; Load memory with file specified in cmd line
- ld a,(cmdstatfl) ; Check command status flag to see if
- and 100b ; ..ECP running (and suppress leading CRLF)
-
- ; CALLPROG is the entry point for the execution of the loaded program. At
- ; alternate entry point CALLPROGLF if the zero flag is set, a CRLF is sent to
- ; the console before running the program.
-
- callproglf:
- call z,crlf ; Leading new line
-
- callprog:
- ; Copy command tail into TBUFF
-
- tailsv equ $+1 ; Pointer for in-the-code modification
- ld hl,0 ; Address of first character of command tail
- ld de,tbuff ; Point to TBUFF
- push de ; Save pointer
- ld bc,7e00h ; C=0 (byte counter) and B=7E (max bytes)
- inc de ; Point to first char
- tail:
- ld a,(hl) ; Get character from tail
- call tsteol ; Check for EOL
- jr z,tail1 ; Jump if we are done
- ld (de),a ; Put character into TBUFF
- inc hl ; Advance pointers
- inc de
- inc c ; Increment character count
- djnz tail ; If room for more characters, continue
- call print ; Display overflow message
- db bell ; ..ring bell
- db 'Ovf','l'+80h ; ..then continue anyway
- tail1:
- xor a ; Store ending zero
- ld (de),a
- pop hl ; Get back pointer to character count byte
- ld (hl),c ; Store the count
-
- ; Run loaded transient program
-
- call defltdma ; Set DMA to 0080h standard value
-
- ; Perform automatic installation of Z3 programs (unless type-2 environment)
-
- ld hl,(execadr) ; Get current execution address
- call z3chk ; See if file is a Z3 program
- jr nz,noinstall ; Branch if not
-
- cp 2 ; If type-2 (internal) environment
- jr z,noinstall ; ..do not perform installation
-
- inc hl ; Advance to place for ENV address
- ld (hl),low z3env ; Put in low byte of environment address
- inc hl
- ld (hl),high z3env ; Put in high byte
-
- noinstall:
-
- ; Execution of the program occurs here by calling it as a subroutine
-
- ld hl,z3env ; Pass environment address to program in HL
- execadr equ $+1 ; Pointer for in-line code modification
- call 0 ; Call transient
-
- ; Return from execution
-
- if shellif ; If flow processing allowed in shells...
- ld hl,cmdstatfl ; Reset the shell bit in the command status
- res 0,(hl) ; ..flag so multiple-command shells will work
- endif ;shellif
-
- ; Continue command processing
- if drvprefix ; If DRVPREFIX we can save a byte by
- jr jpnextcmd ; ..doing a two-step relative jump
- else ; Otherwise, we just have to do
- jp nextcmd ; ..the absolute jump
- endif ;drvprefix
-
-
- ; ---------- Module <<5>>: External Error Handler Processing
-
- baddirerr:
- ld a,ecbaddir ; Error code for bad directory specification
-
- error:
-
- ; If we are returning from an external command to process an error, we want
- ; to leave the error return code as it was set by the transient program.
-
- ld hl,cmdstatfl ; Point to command status flag
- bit 3,(hl) ; Check transient error flag bit
- jr nz,error1 ; If set, leave error code as set externally
- ld (ecflag),a ; Otherwise, save error code from A register
-
- error1:
- res 2,(hl) ; Reset the ECP bit to prevent recursion of
- ; ..error handler by programs that don't
- ; ..clear the bit
- bit 0,(hl) ; Was error in attempting to run a shell?
- jr nz,errsh ; If so, pop shell stack
-
- ; The following code is included to avoid a catastrophic infinite loop when
- ; the external error handler cannot be found. After one unsuccessful try,
- ; the internal code is invoked.
-
- bit 1,(hl) ; Was an error handler already called?
- jr nz,errintrnl ; If so, use internal error handler
-
- ; If the current IF state is false, we would like to ignore the error and just
- ; go on with the next command. Unfortunately, for some errors (e.g., a bad
- ; command format such as a command with a wildcard character) the error handler
- ; is invoked before the pointer in the multiple command line buffer is set up
- ; to the next command. In that case, we fall into an infinite loop. We also
- ; must not allow the external error handler to run, since it will not run and
- ; we will again fall into an infinite loop. The present code is not so bad, of
- ; course, since even a command in a false part of a command sequence should not
- ; have a true error in it. We have already put in code to bypass password
- ; checking during a false IF state, since a command with a password is not an
- ; invalid command.
-
- if fcp ne 0
- call iftest ; If we are in a false IF state, external
- jr z,errintrnl ; ..handler will not run, so use built-in
- endif ;fcp ne 0
-
- set 1,(hl) ; Set command status flag for error invocation
- ld hl,errcmd ; Point to error handler command line
- ld a,(hl) ; Check first byte for presence of an
- or a ; ..error command line
- jr z,errintrnl ; If no error handler, use built-in one
- ld (nxtchr),hl ; Else, use error command line as next command
- jp nextcmd1 ; Run command without resetting status flag
-
-
- ; ---------- Module <<6>>: Resident Error Handler Code
-
- ; If the error is with the invocation of a shell command, we pop the bad shell
- ; command off the stack to prevent recursion of the error. We then use the
- ; the internal error handler to echo the bad shell command.
-
- errsh:
-
- ld de,shstk ; Point to current entry in shell stack
- ld hl,shstk+shsize ; Point to next entry in stack
- ld bc,[shstks-1]*shsize ; Bytes to move
- ldir ; Pop the stack
- xor a ; Clear the last entry position
- ld (de),a
-
- errintrnl:
- if subon
- call subkil ; Terminate active submit file if any
- endif ;subon
-
- call crlf ; New line
- ld hl,(cmdptr) ; Point to beginning of bad command
- call printhl ; Echo it to console
- call print ; Print '?'
- defb '?'+80h
- jp restart ; Restart CPR
-
- ; End ZCPR33-2.Z80
-
- page
-
- ; ZCPR33-3.Z80
-
- ;=============================================================================
- ;
- ; C O M M A N D L I N E P A R S I N G C O D E
- ;
- ;=============================================================================
-
- ; This code parses the command line pointed to by HL. The command verb is
- ; parsed, placing the requested program name into the command file control
- ; block. The drive and user bytes are set. If an explicit DU or DIR was
- ; given, the COLON flag is set so that the processor knows about this later
- ; when the command search path is built.
-
- parser:
-
- ld de,cmdfcb ; Point to the command FCB
- push de
- call initfcb ; Initialize the FCB
- pop de
- ld (duerrflag),a ; Store zero (INITFCB ends with A=0) into flag
- call scanner ; Parse first token on command line into FCB
- jr nz,badcmd ; Invoke error handler if '?' in command
-
- duerrflag equ $+1 ; Pointer for in-the-code modification
- ld a,0 ; See if bad DU/DIR specified with command verb
- or a
-
- if badduecp
- jr z,parser1 ; If DU/DIR is OK, skip ahead
- ld a,(cmdstatfl) ; If ECP already running
- bit 2,a ; ..skip ahead
- jr nz,parser1
- ld a,(cmdfcb+1) ; If not a directory change command
- sub ' ' ; ..invoke error handler
- jr nz,baddirerr
- ; If bad directory change attempt,
- ld (tmpcolon),a ; ..pretend there is no colon (A=0)
- ld a,' ' ; ..and force immediate ECP invocation
- ld (firstchar),a ; ..when command is processed
- else ; If errors not processed by ECP then
- jr nz,baddirerr ; ..invoke error handler
- endif ; badduecp
-
- parser1:
- ld de,cmdfcb+9 ; Make sure no explicit file type was given
- ld a,(de) ; Get first character of file type
- cp ' ' ; Must be blank
- badcmd:
- ld a,ecbadcmd ; Error code for illegal command form
- jr nz,error ; If not, invoke error handler
-
- push hl ; Save pointer to next byte of command
- ld hl,commsg ; Place default file type (COM) into FCB
- ld bc,3
- ldir
- pop hl ; Get command line pointer back
-
- ; The following block of code is arranged so that the COLON flag is set only
- ; when an explicit directory specification is detected in the command verb.
- ; Other parses also change the TMPCOLON flag, but only when passing here does
- ; the flag get transferred to COLON.
-
- tmpcolon equ $+1 ; Pointer for in-the-code modification
- ld a,0 ; ..by SCANNER routine
- ld (colon),a ; If explicit DU/DIR, set COLON flag
-
- ; Find the end of this command and set up the pointer to the next command.
-
- push hl ; Save command line pointer
- dec hl ; Adjust for preincrementing below
- parser2: ; Find end of this command
- inc hl ; Point to next character
- ld a,(hl) ; ..and get it
- call tsteol ; Test for end of command
- jr nz,parser2 ; Keep looping if not
-
- ld (nxtchr),hl ; Set pointer to next command
- pop hl ; Get back pointer to current command tail
-
- ; This block of code parses two tokens in the command line into the two
- ; default FCBs at 5Ch and 6Ch. It also sets a pointer to the command tail
- ; for later copying into the command tail buffer at 80h. This code is used
- ; first when attempting to parse a normal command line and possibly again
- ; later when the entire user's command is treated as a tail to the extended
- ; command processor. The resident JUMP and SAVE commands use it also, and
- ; the entry point is available at location CCP+9 for use by other programs.
-
- parsetail:
- ld (tailsv),hl ; Save pointer to command tail
-
- ; Process first token
-
- ld de,tfcb ; Point to first default FCB
- push de ; Save pointer while initializing
- call initfcb ; Initialize both default FCBs
- pop de
- call sksp ; Skip over spaces in command line
- call nz,scanner ; If not end of line, parse the token
- ; ..into first FCB
- ld (parseptr),hl ; Save pointer to second token for reparsing
-
- ; Process second token
-
- call sksp ; Skip over spaces
- ret z ; Done if end of line or end of command
- ld de,tfcb2 ; Point to second default FCB
- ; ..and fall through to SCANNER routine
-
- ;-----------------------------------------------------------------------------
-
- ; This routine processes a command line token pointed to by HL. It attempts
- ; to interpret the token according to the form [DU:|DIR:]NAME.TYP and places
- ; the corresponding values into the FCB pointed to by DE. On exit, HL points
- ; to the delimiter encountered at the end of the token. The Z flag is set if
- ; a wild card was detected in the token.
-
- scanner:
- xor a ; Initialize various flags
- ld (tmpcolon),a ; Set no colon
- ld bc,(curusr) ; Get current drive and user into BC
- inc b ; Shift drive range from 0..15 to 1..16
- ld (tempusr),bc ; Initialize temporary DU
-
- call scanfld8 ; Extract possible file name
- cp ':' ; Was terminating character a colon?
- jr nz,scantype ; If not, go on to extract file type
- ld (tmpcolon),a ; Otherwise, set colon and process DU/DIR
- inc hl ; Point to character after colon
-
- ; Code for resolving directory specifications (macro RESOLVE is defined in
- ; Z33MAC.LIB). RESOLVE returns with a nonzero value and a NZ flag setting
- ; if the DU/DIR specification cannot be resolved. There are quite a few
- ; possibilities here.
-
- ; Case where both forms are accepted
-
- if accptdir and accptdu
- if dufirst
- resolve du,dir ; Check DU: form before DIR: form
- else
- resolve dir,du ; Check DIR: form before DU: form
- endif ;dufirst
- endif ;accptdir and accptdu
-
- ; Cases of only one form accepted
-
- if accptdu and not accptdir
- resolve du, ; Check only DU: form
- endif ;accptdu and not accptdir
-
- if accptdir and not accptdu
- resolve dir, ; Check only DIR: form
- endif ;accptdir and not accptdu
-
- ; Case of neither form accepted
-
- if not accptdir and not accptdu
- push hl ; Save pointer to command string
- inc de ; Point to first character of name
- ld a,(de) ; Get it
- dec de ; Restore the pointer
- sub ' ' ; If no name is there, A=0 and Z flag set
- endif ;not accptdir and not accptdu
-
- push de ; Save pointer to FCB again
- push af ; Save bad directory flag
- ld a,(tempdr) ; Set designated drive
- ld (de),a ; ..into FCB
- inc de ; Point to file name field
- call ifcb ; Perform partial init (set user code)
- pop af ; Get bad directory flag back
- ld (duerrflag),a ; Save flag in parser code
- jr z,scanner1 ; Branch if valid directory specified
- dec de ; Back up to record count byte
- dec de
- ld (de),a ; Store error flag there (NZ if error)
- scanner1:
- pop de ; Get FCB pointer back
- pop hl ; Restore pointer to command string
- call scanfld8 ; Scan for file name
-
- ; This code processes the file type specification in the token
-
- scantype:
- ld a,(hl) ; Get ending character of file name field
- ex de,hl ; Switch FCB pointer into HL
- ld bc,8 ; Offset to file type field
- add hl,bc
- ex de,hl ; Switch pointers back
-
- ld b,3 ; Maximum characters in file type
- cp '.' ; See if file type specified
- jr nz,scantype2 ; If not, skip over file type parsing
-
- inc hl ; Point to character after '.'
- push de ; Save pointer to FCB file type
- call scanfield ; Parse file type into FCB
- pop de
-
- scantype2:
- ex de,hl ; Swap pointers again
- ld bc,5 ; Offset from file type to S1 field in FCB
- add hl,bc
- ex de,hl ; Swap pointers back
- ld a,(tempusr) ; Get specified user number
- ld (de),a ; ..and store in S1 byte of FCB
-
- scan3: ; Skip to space character, character after an
- ; ..equal sign, or to end of command
- ld a,(hl) ; Get next character
- cp ' '+1 ; Done if less than space
- jr c,scan4
- call tsteol ; Done if end of line or end of command
- jr z,scan4
- inc hl ; Skip on to next character
- cp '=' ; If not equal sign
- jr nz,scan3 ; ..keep scanning
-
- scan4: ; Set zero flag if '?' in filename.typ
-
- qmcnt equ $+1 ; Pointer for in-the-code modification
- ld a,0 ; Number of question marks
- or a ; Set zero flag
- ret
-
- ; This routine invokes SCANFIELD for a file name field. It initializes the
- ; question mark count and preserves the FCB pointer.
-
- scanfld8:
- xor a ; Initialize question mark count
- ld (qmcnt),a
- push de ; Save pointer to FCB
- ld b,8 ; Scan up to 8 characters
- call scanfield
- pop de ; Restore pointer to FCB
- ret
-
- ; This routine scans a command-line token pointed to by HL for a field whose
- ; maximum length is given by the contents of the B register. The result is
- ; placed into the FCB buffer pointed to by DE. The FCB must have had its name
- ; and type fields initialized before this routine is called. Wild cards of
- ; '?' and '*' are expanded. On exit, HL points to the terminating delimiter.
-
- scanfield:
- call sdelm ; Done if delimiter encountered
- ret z
- inc de ; Point to next byte in FCB
- cp '*' ; Is character a wild card?
- jr nz,scanfld1 ; Continue if not
-
- ld a,'?' ; Process '*' by filling with '?'s
- ld (de),a
- call qcountinc ; Increment count of question marks
- jr scanfld2 ; Skip so HL pointer left on '*'
-
- scanfld1: ; Not wildcard character '*'
- ld (de),a ; Store character in FCB
- inc hl ; Point to next character in command line
- cp '?' ; Check for question mark (wild)
- call z,qcountinc ; Increment question mark count
- scanfld2:
- djnz scanfield ; Decrement char count until limit reached
- scanfld3:
- call sdelm ; Skip until delimiter
- ret z ; Zero flag set if delimiter found
- inc hl ; Pt to next char in command line
- jr scanfld3
-
-
- ; Subroutine to increment the count of question mark characters in the
- ; parsed file name.
-
- qcountinc:
- push hl
- ld hl,qmcnt ; Point to count
- inc (hl) ; Increment it
- pop hl
- ret
-
- ;-----------------------------------------------------------------------------
-
- ; Validate the password pointed to by HL. Prompt user for password entry
- ; and return zero if it is correct.
-
- if pwcheck
-
- passck:
- push hl ; Save pointer to password
- call printC ; Prompt user
- defb 'PW?',' '+80h
- ld hl,pwlin ; Set up buffer for user input
- ld bc,90ah ; Set 0ah (BDOS readln function) in C
- ld (hl),b ; ..and 9 (max character count) in B
- ex de,hl ; Switch buffer pointer to DE
-
- if pwnoecho
- ld a,0c9h ; Disable BIOS conout routine to
- ld (bios+0ch),a ; ..suppress password echoing
- call bdossave ; Get user input
- ld a,0c3h ; Reenable BIOS conout routine
- ld (bios+0ch),a
- else ;not pwnoecho
- call bdossave ; Get user input
- endif ;pwnoecho
-
- ex de,hl ; Restore pointer to HL
- inc hl ; Point to count of characters entered
- ld a,(hl) ; Get character count
- inc hl ; Point to first character
- push hl ; Save pointer while marking end of input
- call addah ; Advance HL to just past last character
- ld (hl),' ' ; Place space there
- pop de ; Restore pointer to beginning of user input
- pop hl ; Restore pointer to password from NDR
- ld b,8 ; Maximum characters to compare
- pwck:
- ld a,(de) ; Get next user character
- call ucase ; Capitalize it
- cp (hl) ; Compare to NDR
- ret nz ; No match
- cp ' ' ; If last user character matched space in
- ret z ; ..NDR, then we have a complete match
- inc hl ; If not done, point to next characters
- inc de
- djnz pwck ; (flags not affected by DJNZ)
- xor a ; Set zero flag and
- ret ; ..return Z to show success
-
- endif ; pwcheck
-
- ;-----------------------------------------------------------------------------
-
- ; This code attempts to interpret the token in the FCB pointed to by register
- ; pair DE as a DIR (named directory) prefix. If it is successful, the drive
- ; and user values are stored in TEMPDR and TEMPUSR, the zero flag is set, and
- ; a value of zero is returned in register A.
- ;
- ; If the named directory is found to be password restricted, then the user is
- ; asked for the password (unless the directory is the one currently logged or
- ; the current IF state is false). If an incorrect password is entered, the
- ; error handler is generally invoked directly. The exception to this is when
- ; the transient program bit is set in the command status flag (this bit would
- ; be set by a non-CPR program that calls REPARSE). In this case the default
- ; directory is returned, the zero flag is reset, and a nonzero value in
- ; returned in register A to show a bad directory. In addition, the code in
- ; SCANNER will set record-count byte in the FCB to a nonzero value so that
- ; the calling program can detect the error. [Note: if DU processing is also
- ; allowed and it follows DIR processing, DUSCAN will also be called. Unless
- ; there is a passworded directory with a DU form, this will cause no trouble.]
-
- if accptdir
-
- dirscan:
-
- ; If the DU form is not allowed, we have to detect a colon-only condition here.
- ; Otherwise DUSCAN will take care of it.
-
- inc de ; Point to first byte of directory form
-
- if not accptdu
- ld a,(de) ; Get first character of directory
- sub ' ' ; If it is a blank space
- ret z ; ..we have a successful directory resolution
- endif ;not accptdu
-
- ex de,hl ; Switch pointer to FCB to HL
-
- if ndrenv ; If getting NDR address for Z3ENV
- ld e,15h ; Offset to NDR address
- push hl ; Preserve pointer to FCB
- call pkgoff ; Get NDR address from ENV into DE
- pop hl
- jr z,direrr ; Branch if no NDR implemented
- else ; using fixed address of NDR buffer
- ld de,z3ndir ; Point to first entry in NDR
- endif ; ndrenv
-
- dirscan1:
- ld a,(de) ; Get next character
- or a ; Zero if end of NDR
- jr z,direrr
- inc de ; Point to name of directory
- inc de
- push hl ; Save pointer to name we are looking for
- push de ; Save pointer to NDR entry
- ld b,8 ; Number of characters to compare
-
- dirscan2:
- ld a,(de)
- cp (hl)
- jr nz,dirscan3 ; If no match, quit and go on to next DIR
- inc hl ; Point to next characters to compare
- inc de
- djnz dirscan2 ; Count down
-
- dirscan3:
- pop de ; Restore pointers
- pop hl
- jr z,dirscan4 ; Branch if we have good match
-
- ex de,hl ; Advance to next entry in NDR
- ld bc,16 ; 8 bytes for name + 8 bytes for password
- add hl,bc
- ex de,hl
- jr dirscan1 ; Continue comparing
-
- ; If ACCPTDU is enabled, we can share similar code in DUSCAN and do not need
- ; the code here.
-
- if not accptdu
- direrr: ; No match found
- dec a
- ret
- endif ;not accptdu
-
- dirscan4: ; Match found
- ex de,hl ; Switch pointer to NDR entry into HL
- push hl ; ..and save it for later
- dec hl ; Point to user corresponding to the DIR
- ld c,(hl) ; Get user value into C
- dec hl ; Point to drive
- ld b,(hl) ; Get it into B
-
- if pwcheck
-
- ld hl,(curusr) ; Get current drive/user into HL
- inc h ; Shift drive to range 1..16
- xor a ; Clear carry flag
- sbc hl,bc ; Compare
- pop hl ; Restore pointer to NDR entry
- jr z,setdu ; If same, accept values without PW checking
-
- ; If WPASS is set, then password checking is bypassed when the wheel byte is
- ; set.
-
- if wpass
- ld a,(z3whl) ; Get wheel byte
- or a ; If wheel byte set
- jr nz,setdu ; ..skip checking passwords
- endif ;wpass
-
- ; This code is a bit tricky. We do not want to be asked for passwords for
- ; named directory references in commands when the current IF state is false.
- ; So, first we check to see if there is a password on the directory. If not,
- ; we proceed to set the temporary DU to the specified directory. If there is
- ; a password, we check the current IF state. If it is false, we do not check
- ; passwords and pretend there was no password. However, we leave the current
- ; directory in effect. This will work properly in all but one rare
- ; circumstance. When the command is an 'OR' command with a reference to a
- ; passworded named directory (e.g., "OR EXIST SECRET:FN.FT"), the password
- ; will not be requested and the current directory will be used instead of the
- ; specified one.
-
- push bc ; Save requested drive/user
- ld bc,8 ; Point to password in NDR
- add hl,bc
- ld a,(hl) ; Get first character of password
- cp ' ' ; Is there a password?
-
- if fcp eq 0 ; If FCP not implemented ...
-
- call nz,passck ; Perform password checking if pw present
-
- else ;fcp ne 0 ; FCP implemented ...
-
- jr z,dirscan5 ; If no pw, skip ahead
- call iftest ; Otherwise, test current IF state
- pop bc ; Restore BC in case we return now
- ret z ; If false IF in effect, fake success without
- ; ..checking password (but TEMPDR/TEMPUSR not
- ; ..set)
- push bc ; Otherwise, save BC again
- call passck ; Perform password checking
-
- endif ;fcp eq 0
-
- dirscan5:
- pop bc ; Restore requested drive/user
- jr z,setdu ; If not bad password, set it up
- ld a,(cmdstatfl) ; See if external invocation (disable
- bit 3,a ; ..error handling if so)
- ret nz ; Return NZ to show bad directory
- ld a,ecbadpass ; Error code for bad password
- jp error
-
- else ;not pwcheck
-
- pop hl ; Clean up stack
- if accptdu ; If we cannot fall through, branch
- jr setdu
- endif ;accptdu
-
- endif ;pwcheck
-
- if not accptdu ; If NOT ACCPTDU, we have to supply code here
- setdu:
- ld (tempusr),bc
- xor a ; Set Z to flag success
- ret
- endif ;not accptdu
-
- endif ;accptdir
-
- ;-----------------------------------------------------------------------------
-
- ; This code attempts to interpret the token in the FCB pointed to by register
- ; pair DE as a DU (drive/user) prefix. If it is successful, the drive and
- ; user values are stored in TEMPDR and TEMPUSR, the zero flag is set, and a
- ; value of zero is returned in register A. Otherwise the zero flag is reset
- ; and a nonzero value is returned in register A.
- ;
- ; The ADUENV option allows acceptance of the DU form to be controlled by the
- ; DUOK flag in the environment descriptor. An additional feature of this code
- ; when the ADUENV option is enabled is that a DU value is always accepted,
- ; even if DUOK is off and even if it is outside the normally allowed range,
- ; if it corresponds to a named directory with no password. The currently
- ; logged directory is unconditionally acceptable (if you got there once, you
- ; can stay as long as you like without further hassles).
-
- if accptdu ; Allow DU: form
-
- direrr: ; This code may do double duty for DIRSCAN
- ; ..above
- duerr:
- xor a ; Return NZ to show failure
- dec a
- ret
-
- duscan:
- ex de,hl ; Switch FCB pointer to HL
- inc hl ; Point to first byte of file name in FCB
-
- ld bc,(curusr) ; Preset C to current user, B to current drive
- ld a,(hl) ; Get possible drive specification
- sub 'A' ; Otherwise convert to number 0..15
- jr c,duscan1 ; If < 0, leave B as is
- cp 16
- jr nc,duscan1 ; If > 15, leave B as is
- ld b,a ; Otherwise use value given
- inc hl ; ..and point to next character
-
- duscan1:
- inc b ; Shift drive to range 1..16
- ld a,(hl) ; Get possible user specification
- cp ' '
- jr z,duscan2 ; If none present, leave C as is
- push bc ; Save DU values in BC
- call decimal1 ; Get specified decimal user number into BC
- pop hl ; Restore values to HL
- jr c,duerr ; Return NZ if invalid decimal conversion
- ld a,b ; Get high byte of result
- or a ; Make sure it is zero
- ret nz ; If not, return NZ to show bad user number
- ld b,h ; DU value is now in BC
-
- ; If the specified directory is the currently logged directory, accept it
- ; even if it is out of range and/or password protected.
-
- duscan2:
- ld hl,(curusr) ; Get current drive/user into HL
- inc h ; Shift drive to range 1..16
- xor a ; Clear carry flag
- sbc hl,bc ; Compare values
- jr z,setdu
-
- ; If the specified DU corresponds to a named directory with no password, or
- ; if WPASS is enabled so that password checking is not performed when the
- ; wheel byte is set, then accept it.
-
- if z3ndir ne 0
-
- call du2dir ; See if there is a matching named directory
- jr z,duscan3 ; If not, skip on
-
- if pwcheck ; If passwords are being checked...
-
- if wpass
- ld a,(z3whl) ; Get wheel byte
- or a ; If wheel byte set, skip checking passwords
- jr nz,setdu ; ..and accept the DU values
- endif ;wpass
-
- ld de,9 ; Advance to password
- add hl,de
- ld a,(hl) ; Get first character of password
- cp ' '
- jr z,setdu ; If none, we have a valid DU
-
- else ;not pwcheck
-
- jr setdu ; Set the DU
-
- endif ;pwcheck
-
- endif ;z3ndir ne 0
-
- duscan3:
- if aduenv ; Check DUOK flag in ENV
- ld a,(duokfl) ; Get flag
- or a ; If DU not accepted
- jr z,duerr ; ..skip over the DU scan
- endif ;aduenv
-
- if duenv ; If getting max drive and user from ENV
- ld hl,(maxdrenv) ; Get max drive into L and max user into H
- ld a,l ; Test drive value
- cp b
- jr c,duerr
- ld a,h ; Test user value
- cp c
- jr c,duerr
- else ; Using fixed values of max DU
- ld a,maxdisk
- cp b
- jr c,duerr
- ld a,maxusr
- cp c
- jr c,duerr
- endif ;duenv
-
- setdu:
- ld (tempusr),bc
- xor a ; Set Z to flag success
- ret
-
- endif ; accptdu
-
- ; End ZCPR33-3.Z80
-
- page
-
- ; ZCPR33-4.Z80
-
- ;=============================================================================
- ;
- ; G E N E R A L S U B R O U T I N E S S E C T I O N
- ;
- ;=============================================================================
-
-
- ;-----------------------------------------------------------------------------
- ;
- ; CHARACTER I/O BDOS ROUTINES
- ;
- ;-----------------------------------------------------------------------------
-
- ; Get uppercase character from console (with ^S processing). Registers B,
- ; D, H, and L are preserved. The character is returned in A.
-
- conin:
- ld c,1 ; BDOS conin function
- call bdossave
- ; Fall through to UCASE
-
- ;--------------------
-
- ; Convert character in A to upper case. All registers except A are preserved.
-
- ucase:
- and 7fh ; Mask out msb
- cp 61h ; Less than lower-case 'a'?
- ret c ; If so, return
- cp 7bh ; Greater than lower-case 'z'?
- ret nc ; If so, return
- and 5fh ; Otherwise capitalize
- ret
-
- ;----------------------------------------
-
- ; Output CRLF
-
- crlf:
- call print
- db cr
- db lf or 80h
- ret
-
- ;----------------------------------------
-
- ; Output character in A to the console. All registers are preserved.
-
- conout:
- push de
- push bc
- ld c,2 ; BDOS conout function
- output: ; Entry point for LCOUT below
- ld e,a
- call bdossave
- pop bc
- pop de
- ret
-
- ;----------------------------------------
-
- ; Print the character string immediately following the call to this routine.
- ; The string terminates with a character whose high bit is set or with a null.
- ; At entry point PRINTC the string is automatically preceded by a
- ; carriage-return-linefeed sequence. All registers are preserved except A.
-
- printc:
- call crlf ; New line
-
- print:
- ex (sp),hl ; Get pointer to string
- call printhl ; Print string
- ex (sp),hl ; Restore HL and set return address
- ret
-
- ;----------------------------------------
-
- ; Print the character string pointed to by HL. Terminate on character with
- ; the high bit set or on a null character. On return HL points to the byte
- ; after the last character displayed. All other registers except A are
- ; preserved.
-
- printhl:
- ld a,(hl) ; Get a character
- inc hl ; Point to next byte
- or a ; End of string null?
- ret z
- push af ; Save flags
- and 7fh ; Mask out msb
- call conout ; Print character
- pop af ; Get flags
- ret m ; String terminated by msb set
- jr printhl
-
-
- ;-----------------------------------------------------------------------------
- ;
- ; FILE I/O BDOS ROUTINES
- ;
- ;-----------------------------------------------------------------------------
-
- ; Read a record from a file to be listed or typed
-
- if lton ; Only needed for LIST and TYPE functions
-
- readf:
- ld de,tfcb
- jr read
-
- endif ; lton
-
- ;----------------------------------------
-
- ; Read a record from the command file named in CMDFCB
-
- readcmd:
- ld de,cmdfcb
-
- ; Read a record from file whose FCB is pointed to by DE
-
- read:
- ld c,14h ; Read-sequential function
- ; Fall through to BDOSSAVE
-
- ;--------------------
-
- ; Call BDOS for read and write operations. The flags are set appropriately.
- ; The BC, DE, and HL registers are preserved.
-
- bdossave:
- putreg
- call bdos
- getreg
- or a ; Set flags
- note: ; This return is used for NOTE command, too
- ret
-
-
- ;-----------------------------------------------------------------------------
- ;
- ; MISCELLANEOUS BDOS ROUTINES
- ;
- ;-----------------------------------------------------------------------------
-
- ; Set DMA address. At the entry point DEFLTDMA the address is set to the
- ; default value of 80H. At the entry point DMASET it is set to the value
- ; passed in the DE registers.
-
- defltdma:
- ld de,tbuff
- dmaset:
- ld c,1ah
- jr bdossave
-
- ;----------------------------------------
-
- ; Log in the drive value passed in the A register (A=0).
-
- setdrive:
- ld e,a
- ld c,0eh
- jr bdossave
-
- ;----------------------------------------
-
- ; Open a file. At entry point OPENCMD the file is the one specified in
- ; CMDFCB, and the current record is set to zero. At entry point OPEN
- ; the file whose FCB is pointed to by DE is used.
-
- opencmd:
- xor a ; Set current record to 0
- ld (cmdfcb+32),a
- ld de,cmdfcb ; Command file control block
- ; Fall through to open
-
- open:
- ld c,0fh ; BDOS open function
- ; Fall through to BDOSTEST
-
- ;--------------------
-
- ; Invoke BDOS for disk functions. This routine increments the return code in
- ; register A so that the zero flag is set if there was an error. Registers
- ; BC, DE, and HL are preserved.
-
- bdostest:
- call bdossave
- inc a ; Set zero flag for error return
- ret
-
- ;----------------------------------------
-
- ; Close file whose FCB is pointed to by DE.
-
- if saveon or subon
- close:
- ld c,10h
- jr bdostest
- endif ;saveon or subon
-
- ;----------------------------------------
-
- ; Search for first matching file. At entry point SRCHFST1 the first default FCB
- ; is used. At entry point SRCHFST the FCB pointed to by DE is used.
-
- if diron or eraon or renon or saveon
- srchfst1:
- ld de,tfcb ; Use first default FCB
- endif ;diron or eraon or renon or saveon
-
- srchfst:
- ld c,11h
- jr bdostest
-
- ;-----------------------------------------------------------------------------
-
- ; Search for next matching file whose FCB is pointed to by DE.
-
- if diron or eraon ; Only needed by DIR and ERA functions
- srchnxt:
- ld c,12h
- jr bdostest
- endif ; diron or eraon
-
- ;-----------------------------------------------------------------------------
-
- ; Kill any submit file that is executing.
-
- if subon
-
- subkil:
- ld hl,subflag ; Check for submit file in execution
- ld a,(hl)
- or a ; 0=no
- ret z ; If none executing, return now
- ; Kill submit file
- xor a
- ld (hl),a ; Zero submit flag
- call setuser ; Log in user 0
- ld de,subfcb ; Delete submit file
- ; ..by falling through to delete routine
-
- endif ; subon
-
- ;--------------------
-
- ; Delete file whose FCB is pointed to by DE.
-
- if eraon or renon or saveon or subon
- delete:
- ld c,13h
- jr bdossave
- endif ;eraon or renon or saveon or subon
-
- ;-----------------------------------------------------------------------------
-
- ; Get and set user number. Registers B, D, H, and L are preserved. Register
- ; E is also preserved at entry point SETUSER1.
-
- getuser:
- ld a,0ffh ; Get current user number
- setuser:
- ld e,a ; User number in E
- setuser1:
- ld c,20h ; Get/Set BDOS function
- jr bdossave
-
-
- ;-----------------------------------------------------------------------------
- ;
- ; GENERAL UTILITY ROUTINES
- ;
- ;-----------------------------------------------------------------------------
-
-
- ; This subroutine checks to see if a program loaded at an address given by HL
- ; has a Z3ENV header. If the header is not present, the zero flag is reset.
- ; If it is present, the zero flag is set, and on return HL points to the
- ; environment-type byte and A contains that byte.
-
- z3chk:
- ld de,z3env+3 ; Point to 'Z3ENV' string in ENV
- inc hl ; Advance three bytes to possible program
- inc hl ; ..header
- inc hl
- ld b,5 ; Characters to compare
- z3chk1: ; Check for Z3 ID header
- ld a,(de) ; Get character from ENV descriptor
- cp (hl) ; Compare it to loaded file
- ret nz ; Quit now if mismatch
- inc hl ; If same, advance to next characters
- inc de ; ..and continue comparing
- djnz z3chk1 ; (flags not affected by DJNZ)
- ld a,(hl) ; Return the environment type in A
- ret ; Return Z if all 5 characters match
-
- ;----------------------------------------
-
- ; Subroutine to skip over spaces in the buffer pointed to by HL. On return,
- ; the zero flag is set if we encountered the end of the line or a command
- ; separator character.
-
- sksp:
- ld a,(hl) ; Get next character
- inc hl ; Point to the following character
- cp ' ' ; Space?
- jr z,sksp ; If so, keep skipping
- dec hl ; Back up to non-space
- ; ..and fall through
-
- ;--------------------
-
- ; Subroutine to check if character is the command separator or marks the end
- ; of the line.
-
- tsteol:
- or a ; End of command line?
- ret z ; Return with zero flag set
- cp cmdsep ; Command separator?
- ret ; Return with flag set appropriately
-
- ;----------------------------------------
-
- ; Initialize complete FCB pointed to by DE
-
- initfcb:
- xor a
- ld (de),a ; Set default disk (dn byte is 0)
- inc de ; Point to file name field
- call ifcb ; Fill 1st part of FCB
- ; Fall through to IFCB to run again
-
- ;--------------------
-
- ; Initialize part of FCB whose file name field is pointed to by DE on entry.
- ; The file name and type are set to space characters; the EX, S2, RC, and the
- ; following CR (current record ) or DN (disk number) fields are set to zero.
- ; The S1 byte is set to the current user number. On exit, DE points to the
- ; byte at offset 17 in the FCB (two bytes past the record count byte).
-
- ifcb:
- ld b,11 ; Store 11 spaces for file name and type
- ld a,' '
- call fill
- xor a
- ld (de),a ; Set extent byte to zero
- inc de
- ld a,(curusr)
- ld (de),a ; Set S1 byte to current user
- inc de
- ld b,3 ; Store 3 zeroes
- xor a ; Fall thru to fill
-
- ;--------------------
-
- ; Fill memory pointed to by DE with character in A for B bytes
-
- fill:
- ld (de),a ; Fill with byte in A
- inc de ; Point to next
- djnz fill
- ret
-
- ;----------------------------------------
-
- ; Subroutine to display the 'no file' error message for the built-in
- ; commands DIR, ERA, LIST, TYPE, and/or REN.
-
- if diron or eraon
-
- prnnf:
- call printc ; No file message
- defb 'No Fil','e'+80h
- ret
- endif ; diron or eraon
-
- ;----------------------------------------
-
- ; Calculate address of command table in package from Z3ENV. On entry, E
- ; contains the offset to the address of the package in the environment. On
- ; exit, DE points to the beginning of the package and HL points to the fifth
- ; byte (where the command table starts in the RCP and FCP modules). The zero
- ; flag is set on return if the package is not supported.
-
- if fcpenv or rcpenv or ndrenv
- pkgoff:
- ld hl,z3env ; Point to beginning of ENV descriptor
- ld d,0 ; Make DE have offset
- add hl,de ; ..and add it
- ld a,(hl) ; Get low byte of package address
- inc hl ; Point to high byte
- ld h,(hl) ; ..and get it
- ld l,a ; Move full address into HL
- or h ; Set zero flag if no package
- ld de,5 ; Offset to start of table
- ex de,hl ; Preserve start address of package in DE
- add hl,de ; Pointer to 5th byte of package in HL
- ret ; Return with zero flag set appropriately
-
- endif ;fcpenv or rcpenv or ndrenv
-
- ;----------------------------------------
-
- ; This subroutine checks to see if we are in a false IF state. If that is
- ; the case, the routine returns with the zero flag set. If there is not active
- ; IF state or if it is true, then the zero flag is reset.
-
- if fcp ne 0 ; Omit code if FCP not implemented
-
- iftest:
- ld bc,(ifptrfl) ; Current IF pointer into C, IF status into B
- ld a,c ; See if any IF in effect
- or a
- jr z,iftest1 ; Branch if no IF state is active
- and b ; Mask the current IF status
- ret
- iftest1:
- dec a ; Reset the zero flag
- ret
-
- endif ;fcp ne 0
-
- ;----------------------------------------
-
- ; Print the command prompt with the time
-
- IF TIMEON ; If time in prompt line
- CONVRT: ld L,'0'-1
- TENS:
- inc L ; This routine is moved from the USER # area
- sub 10 ; and called by both TIMEON and USER #
- jr nc,TENS
- add a,10+'0'
- ld H,a
- ld a,L
- RET
- ENDIF
-
- prompt:
- IF TIMEON ; If time in prompt line
- LD BC,0F486H ; N*'s TSS/C time HH:MM (point to min. first)
- LD A,(BC) ; Load hour
- CALL CONVRT ; Convert BCD to ASCII
- LD (TIME+1),HL ; Store hours in prompt time string
- INC BC ; Point to min.
- LD A,(BC)
- CALL CONVRT
- LD (TIME+4),HL
- CALL PRINTC
- TIME: DEFB '(00:00)',' '+80H ; Time string
- ELSE
- call crlf
- ENDIF ; Time on
-
- ; Print the command prompt with DU and/or DIR (but without any trailing
- ; character). This is also the code in which the current drive and user
- ; will be stored. The conditional assemblies are somewhat involved because
- ; of the possibilities of either or both of the DU or DIR forms being omitted
- ; from the prompt.
-
- if incldu ; If drive/user in prompt
-
- ld BC,(curusr) ; Get current drive/user into BC
- PUSH BC ; Save for later
-
- ; If INCLENV is enabled, the drive and user (DU) will be included in the
- ; prompt based on the state of the DUOK flag in the environment. If INCLENV
- ; is disabled, the DU form will always be included if INCLDU is on.
-
- if inclenv
- ld a,(duokfl) ; If ENV disallows DU,
- or a ; ..then don't show it in
- jr z,prompt2 ; ..the prompt, either
- endif ;inclenv
-
- ld a,B ; Get current drive
- add a,'A' ; Convert to ascii A-P
- call conout
- ld a,C ; Get current user
-
- if supres ; If suppressing user # report for user 0
- or a
- jr z,prompt2
- endif
-
- if highuser AND NOT TIMEON ; If allowing users 16..31 and NOT TIME
-
- CONVRT:
- ld L,'0'-1
- prompt0:
- inc L
- sub 10
- jr nc,prompt0
- add a,10+'0'
- ld H,a
- ld a,L
- ENDIF ;not time and highuser
-
- IF HIGHUSER OR TIMEON
- IF TIMEON
- CALL CONVRT
- ENDIF
-
- CP '0'
- CALL NZ,CONOUT
- LD A,H
- ENDIF
-
- IF NOT HIGHUSER AND NOT TIMEON
- ;using only standard user numbers 0..15
-
- cp 10 ; User < 10?
- jr c,UNITS
- sub 10 ; Subtract 10 from user number
- LD H,A ; Save low digit
- call print ; Display a '1' for tens digit
- defb '1' or 80h
- LD A,H
-
- UNITS:
- add a,'0' ; Output 1's digit (convert to ascii)
- ENDIF
- call conout
- prompt2:
- endif ; incldu
-
- ; Display named directory
-
- if incldir
-
- if incldu
- POP BC ; Get drive/user
- else
- ld bc,(curusr) ; Get current drive and user into BC
- endif ;incldu
-
- inc b ; Switch drive to range 1..16
- call du2dir ; See if there is a corresponding DIR form
- ret z ; If not, return now
-
- if incldu ; Separate DU and DIR with colon
-
- if inclenv
- ld a,(duokfl) ; If not displaying DU, then
- or a ; ..don't send separator, either
- ld a,':' ; Make the separator
- call nz,conout ; ..and send if permitted
- else
- call print ; Put in colon separator
- defb ':' or 80h
- endif ;inclenv
-
- endif ; incldu
-
- ld b,8 ; Max of 8 chars in DIR name
- prompt3:
- inc hl ; Point to next character in DIR name
- ld a,(hl) ; ..and get it
- cp ' ' ; Done if space
- ret z
- call conout ; Print character
- djnz prompt3 ; Count down
-
- endif ; incldir
-
- ret
-
- ;-----------------------------------------------------------------------------
-
- ; Subroutine to convert DU value in BC into pointer to a matching entry in
- ; the NDR. If there is no match, the routine returns with the zero flag set.
- ; If a match is found, the zero flag is reset, and the code returns with HL
- ; pointing to the byte before the directory name.
-
- if z3ndir ne 0
-
- du2dir:
-
- if ndrenv ; If getting NDR address from environment
- ld e,15h ; Offset to NDR in Z3ENV
- call pkgoff ; Get address of NDR into DE
- ex de,hl ; ..and switch into HL
- ret z ; If no NDR, return with zero flag set
- jr du2dir2
- else
- ld hl,z3ndir-17 ; Scan directory for match
- endif ;ndrenv
-
- du2dir1: ; Advance to next entry in NDR
- ld de,16+1 ; Skip user (1 byte) and name/pw (16 bytes)
- add hl,de
-
- du2dir2:
- ld a,(hl) ; End of NDR?
- or a
- ret z ; If so, return with zero flag set
-
- inc hl ; Point to user number in NDR entry
- cp b ; Compare drive values
- jr nz,du2dir1 ; If mismatch, back for another try
- ld a,(hl) ; Get user number
- sub c ; ..and compare
- jr nz,du2dir1 ; If mismatch, back for another try
- dec a ; Force NZ to show successful match
- ret
-
- endif ;z3ndir ne 0
-
- ;-----------------------------------------------------------------------------
-
- ; This routine gets the next line of input for the command buffer. The
- ; following order of priority is followed:
- ; If ZEX is active, the next line is obtained from ZEX
- ; If a submit file is running, its last record provides the input
- ; If there is a command line on the shell stack, use it
- ; Finally, if none of the above, the input is obtained from the user
-
- readbuf:
-
- ld a,(zexrunfl) ; Get ZEX-running flag
- or a
- jr nz,userinput ; If ZEX running, go directly to user input
-
- if subon ; If submit facility is enabled, check for it
-
- ld a,(subflag) ; Test for submit file running
- or a
- jr z,shellinput ; If not, go on to possible shell input
-
- xor a ; Log into user 0
- call setuser
- call defltdma ; Initialize DMA pointer
- ld de,subfcb ; Point to submit file FCB
- call open ; Try to open file
- jr z,readbuf1 ; Branch if open failed
-
- ld hl,subfrc ; Point to record count in submit FCB
- ld a,(hl) ; Get the number of records in file
- dec a ; Reduce to number of last record
- ld (subfcr),a ; ..and put into current record field
- call read ; Attempt to read submit file
- jr nz,readbuf1 ; Branch if read failed
-
- dec (hl) ; Reduce file record cound
- dec hl ; Point to S2 byte of FCB (yes, this is req'd!)
- ld (hl),a ; Stuff a zero in there (A=0 from call to READ)
- call close ; Close the submit file one record smaller
- jr z,readbuf1 ; Branch if close failed
-
- ; Now we copy the line read from the file into the multiple command line
- ; buffer
-
- ld de,chrcnt ; Point to command length byte in command buffer
- ld hl,tbuff ; Point to sector read in from submit file
-
- if buflen gt 7fh ; If command line buffer is longer than record,
- ld bc,80h ; ..then copy entire record from $$$.SUB file
- else ;buflen le 7fh ; Otherwise copy only enough to fill
- ld bc,buflen+1 ; ..the command line buffer
- endif ;buflen gt 7fh
-
- ldir ; Transfer line from submit file to buffer
-
- ; We now deal with various options that control the display of commands fed
- ; to the command processor from a submit file.
-
- if subnoise gt 0 ; If subnoise = 0 we omit all this display code
-
- if subnoise eq 1 ; If subnoise = 1 we follow the quiet flag
- ld a,(quietfl)
- or a
- jr nz,readbuf0 ; If quiet, skip echoing the command
- endif ;subnoise eq 1
-
- call prompt ; Print prompt
- call print ; Print submit prompt trailer
- defb sprmpt or 80h
- ld hl,cmdlin ; Print command line
- call printhl
-
- endif ;subnoise gt 0
-
- readbuf0:
- call break ; Check for abort (any char)
- ret nz ; If no ^C, return to caller and run
-
- readbuf1:
- call subkil ; Kill submit file and abort
- jp restart ; Restart CPR
-
- endif ; subon
-
- shellinput:
- ld hl,shstk ; Point to shell stack
- ld a,(hl) ; Check first byte
- cp ' '+1 ; See if any entry
- jr c,userinput ; Get user input if none
-
- ld de,cmdlin ; Point to first character of command line
- ld bc,shsize ; Copy shell line into command line buffer
- ldir ; Do copy
- ex de,hl ; HL points to end of line
- ld a,1 ; Set command status flag to show
- ld (cmdstatfl),a ; ..that a shell has been invoked
- jr readbuf3 ; Store ending zero and exit
-
- userinput:
- call prompt ; Print prompt
- call print ; Print prompt trailer
- defb cprmpt or 80h
- ld c,0ah ; Read command line from user
- ld de,bufsiz ; Point to buffer size byte of command line
- call bdos
-
- ; Store null at end of line
-
- ld hl,chrcnt ; Point to character count
- ld a,(hl) ; ..and get its value
- inc hl ; Point to first character of command line
- call addah ; Make pointer to byte past end of command line
- readbuf3:
- ld (hl),0 ; Store ending zero
- ret
-
- ;-----------------------------------------------------------------------------
-
- ; Check for any character from the user console. Return with the character
- ; in A. If the character is a control-C, then the zero flag will be set.
-
- if subon or diron or eraon or lton
-
- break:
- ld c,0bh ; BDOS console status function
- call bdossave ; Call BDOS and set flags
- call nz,conin ; Get input character if there is one
- cp 'C'-'@' ; Check for abort
- ret
-
- endif ; subon or diron or eraon or lton
-
- ;-----------------------------------------------------------------------------
-
- ; Add A to HL (HL=HL+A)
-
- addah:
- add a,l
- ld l,a
- ret nc
- inc h
- ret
-
- ;-----------------------------------------------------------------------------
-
- ; The routine NUMBER evaluates a string in the first FCB as either a decimal
- ; or, if terminated with the NUMBASE hexadecimal marker, a HEX number. If the
- ; conversion is successful, the value is returned as a 16-bit quantity in BC.
- ; If an invalid character is encountered in the string, the routine returns
- ; with the carry flag set and HL pointing to the offending character.
-
- if saveon
-
- number:
- ld hl,tfcb+8 ; Set pointer to end of number string
- ld bc,8 ; Number of characters to scan
- ld a,numbase ; Scan for HEX identifier
- cpdr ; Do the search
- jr nz,decimal ; Branch if HEX identifier not found
-
- inc hl ; Point to HEX marker
- ld (hl),' ' ; Replace HEX marker with valid terminator
- ; ..and fall through to HEXNUM
-
- endif ;saveon
-
- ;----------------------------------------
-
- ; At this entry point the character string in the first default FCB is
- ; converted as a hexadecimal number (there must NOT be a HEX marker).
-
- hexnum:
- ld hl,tfcb+1 ; Point to string in first FCB
-
- ; At this entry point the character string pointed to by HL is converted
- ; as a hexadecimal number (there must be NO HEX marker at the end).
-
- hexnum1:
- ld de,16 ; HEX radix base
- jr radbin ; Invoke the generalized conversion routine
-
- ;----------------------------------------
-
- ; This entry point performs decimal conversion of the string in the first
- ; default FCB.
-
- decimal:
- ld hl,tfcb+1 ; Set pointer to number string
-
- ; This entry point performs decimal conversion of the string pointed to
- ; by HL.
-
- decimal1:
- ld de,10 ; Decimal radix base
- ; Fall through to generalized
- ; ..radix conversion routine
-
- ; This routine converts the string pointed to by HL using the radix passed in
- ; DE. If the conversion is successful, the value is returned in BC. HL points
- ; to the character that terminated the number, and A contains that character.
- ; If an invalid character is encountered, the routine returns with the carry
- ; flag set, and HL points to the offending character.
-
- radbin:
- ld bc,0 ; Initialize result
- radbin1:
- or a ; Make sure carry is reset
- call sdelm ; Test for delimiter (returns Z if delimiter)
- ret z ; Return if delimiter encountered
-
- sub '0' ; See if less than '0'
- ret c ; Return with carry set if so
- cp 10 ; See if in range '0'..'9'
- jr c,radbin2 ; Branch if it is valid
- cp 'A'-'0' ; Bad character if < 'A'
- ret c ; ..so we return with carry set
- sub 7 ; Convert to range 10..15
- radbin2:
- cp e ; Compare to radix in E
- ccf ; Carry should be set; this will clear it
- ret c ; If carry now set, we have an error
-
- inc hl ; Point to next character
- push bc ; Push the result we are forming onto the stack
- ex (sp),hl ; Now HL=result, (sp)=source pointer
- call mpy16 ; HLBC = previous$result * radix
- ld h,0 ; Discard high 16 bits and
- ld l,a ; ..move current digit into HL
- add hl,bc ; Form new result
- ld c,l ; Move it into BC
- ld b,h
- pop hl ; Get string pointer back
- jr radbin1 ; Loop until delimiter
-
- ;-----------------------------------------------------------------------------
-
- ; This routine multiplies the 16-bit values in DE and HL and returns the
- ; 32-bit result in HLBC (HL has high 16 bits; BC has low 16 bits). Register
- ; pair AF is preserved.
-
- mpy16:
- ex af,af' ; Save AF
- ld a,h ; Transfer factor in HL to A and C
- ld c,l
- ld hl,0 ; Initialize product
- ld b,16 ; Set bit counter
- rra ; Shift AC right so first multiplier bit
- rr c ; ..is in carry flag
- mp161:
- jr nc,mp162 ; If carry not set, skip the addition
- add hl,de ; Add multiplicand
- mp162:
- rr h ; Rotate HL right, low bit into carry
- rr l
- rra ; Continue rotating through AC, with
- rr c ; ..next multiplier bit moving into carry
- djnz mp161 ; Loop through 16 bits
-
- ld b,a ; Move A to B so result is in HLBC
- ex af,af' ; Restore original AF registers
- ret
-
- ;-----------------------------------------------------------------------------
-
- ; This routine checks for a delimiter character pointed to by HL. It returns
- ; with the character in A and the zero flag set if it is a delimiter. All
- ; registers are preserved except A.
-
- sdelm:
- ld a,(hl) ; Get the character
- exx ; Use alternate register set (shorter code)
- ld hl,deldat ; Point to delimiter list
- ld bc,delend-deldat; Length of delimiter list
- cpir ; Scan for match
- exx ; Restore registers
- ret ; Returns Z if delimiter
-
- deldat: ; List of delimiter characters
- db ' '
- db '='
- db '_'
- db '.'
- db ':'
- db ';'
- db '<'
- db '>'
- db ','
- db 0
- if cmdsep ne ';'
- db cmdsep
- endif ;cmdsep ne ';'
- delend:
-
- ;-----------------------------------------------------------------------------
-
- ; Log into DU contained in FCB pointed to by DE. Registers DE are preserved;
- ; all others are changed. Explicit values for the temporary drive and user
- ; are extracted from the FCB. If the record-count byte has an FF in it, that
- ; is a signal that the directory specification was invalid. We then invoke
- ; the error handler.
-
- if diron or eraon or lton or renon or saveon
-
- fcblog:
- push de ; Save pointer to FCB
- ex de,hl
- ld a,(hl) ; Get drive
- ld bc,13 ; Offset to S1 field
- add hl,bc
- ld c,(hl) ; Get user into C
- or a ; See if drive value was 0
- jr nz,fcblog1 ; If not, branch ahead
- ld a,(curdr) ; Otherwise substitute current drive
- inc a ; ..shifted to range 1..16
- fcblog1:
- ld b,a ; Get drive into B
- ld (tempusr),bc ; Set up temporary DU values
- call logtemp ; ..and log into it
- pop de ; Restore pointer to FCB
-
- ; Now check to make sure that the directory specification was valid.
-
- inc hl ; Advance pointer to record-count byte
- inc hl
- ld a,(hl) ; See if it is nonzero
- or a
- jp nz,baddirerr ; If so, invoke error handler
-
- ret ; Otherwise return
-
- endif ;diron or eraon or lton or renon or saveon
-
- ;-----------------------------------------------------------------------------
-
- ; Log into the temporary directory. Registers B, H, and L are preserved.
-
- logtemp:
- ld de,(tempusr) ; Set D = tempdr, E = tempusr
- call setuser1 ; Register D is preserved during this call
- ld a,d ; Move drive into A
- dec a ; Adjust for drive range 0..15
- jp setdrive ; Log in new drive and return
-
- ;-----------------------------------------------------------------------------
-
- ; This routine scans the command table pointed to by HL for the command name
- ; stored in the command FCB. If the command is not found, the routine returns
- ; with the zero flag reset. If the command is found, the address vector is
- ; stored in EXECADR and the zero flag is set.
-
- cmdscan:
- ld b,(hl) ; Get length of each command
- inc hl ; Point to first command name
-
- scannext:
- ld a,(hl) ; Check for end of table
- or a
- jr z,scanend ; Branch if end
-
- ld de,cmdfcb+1 ; Point to name of requested command
- push bc ; Save size of commands in table
-
- if wheel
- ; Ignore commands with high bit set in first
- ; ..char of command name if wheel is false
- ld a,(z3whl) ; Get the wheel byte
- or a
- ld c,0ffh ; Make a mask that passes all characters
- jr z,scancmp ; Use this mask if wheel not set
-
- endif ; wheel
-
- ld c,7fh ; Use mask to block high bit if wheel set
- ; ..or not in use
-
- scancmp:
- ld a,(de) ; Compare against table entry
-
- xor (hl)
- and c ; Mask high bit of comparison
- jr nz,scanskip ; No match, so skip rest of command name
-
- inc de ; Advance to next characters to compare
- inc hl
- res 7,c ; Mask out high bit on characters after first
- djnz scancmp ; Count down
-
- ld a,(de) ; See if next character in input command
- cp ' ' ; ..is a space
- jr nz,scanbad ; If not, user command is longer than commands
- ; ..in the command table
-
- ; Matching command found
-
- pop bc ; Clear stack
- ld a,(hl) ; Get address from table into HL
- inc hl
- ld h,(hl)
- ld l,a
- ld (execadr),hl ; Set execution address
- xor a ; Set zero flag to show that command found
- ret
-
- scanskip:
- inc hl ; Skip to next command table entry
- djnz scanskip
-
- scanbad:
- pop bc ; Get back size of each command
- inc hl ; Skip over address vector
- inc hl
- jr scannext ; Try scanning next entry in table
-
- scanend:
- xor a ; Reset zero flag to show
- dec a ; ..that command was not found
- ret
-
- ; End ZCPR33-4.Z80
-
- page
-
- ; ZCPR33-5.Z80
-
- ;=============================================================================
- ;
- ; R E S I D E N T C O M M A N D C O D E
- ;
- ;=============================================================================
-
- ; Command: DIR
- ; Function: To display a directory of the files on disk
- ; Forms:
- ; DIR <afn> Displays the DIR-attribute files
- ; DIR Same as DIR *.*
- ; DIR <afn> S Displays the SYS-attribute files
- ; DIR /S Same as DIR *.* S
- ; DIR <afn> A Display both DIR and SYS files
- ; DIR /A Same as DIR *.* A
-
- if diron
-
- dir:
- ld de,tfcb ; Point to target FCB
- push de ; ..and save the pointer for later
- inc de ; Point to file name
- ld a,(de) ; Get first character
-
- if slashfl ; If allowing "DIR /S" and "DIR /A" formats
- cp '/' ; If name does not start with '/'
- jr nz,dir1 ; ..branch and process normally
- inc de ; Point to second character
- ld a,(de) ; Get option character after slash
- ld (tfcb2+1),a ; ..and put it into second FCB
- dec de ; Back to first character
- ld a,' ' ; Simulate empty FCB
- endif ;slashfl
-
- dir1:
- cp ' ' ; If space, make all wild
- jr nz,dir2
- ld b,11
- ld a,'?'
- call fill
-
- dir2:
- pop de ; Restore pointer to FCB
- call fcblog ; Log in the specified directory
-
- if whldir
- ld a,(z3whl) ; Check wheel status
- or a ; If not set, then ignore options
- jr z,dir2a
- endif ;whldir
-
- ld a,(tfcb2+1) ; Check for any option letter
- ld b,1 ; Flag for both DIR and SYS files
- cp allchar ; See if all (SYS and DIR) option letter
- jr z,dirpr ; Branch if so
- dec b ; B = 0 for SYS files only
- cp syschar ; See if SYS-only option letter
- jr z,dirpr ; Branch if so
- dir2a:
- ld b,80h ; Flag for DIR-only selection
- ; Drop into DIRPR to print directory
-
- endif ; diron
-
- ;--------------------
-
- ; Directory display routine
-
- ; On entry, if attribute checking is required, the B register is
- ; set as follows:
- ; 00H for SYS files only
- ; 80H for DIR files only
- ; 01H for both
-
- if diron or eraon
-
- dirpr:
- if diron ; Attribute checking needed only for DIR
- ld a,b ; Get flag
- ld (systst),a ; Set system test flag
- endif
-
- ld e,0 ; Set column counter to zero
- push de ; Save column counter (E)
- call srchfst1 ; Search for specified file (first occurrence)
- jr nz,dir3
- call prnnf ; Print no-file message
- pop de ; Restore DE
- xor a ; Set Z to show no files found
- ret
-
- ; Entry selection loop. On entering this code, A contains the offset in the
- ; directory block as returned by the search-first or search-next call.
-
- dir3:
- if diron ; Attribute checking needed only for DIR cmd
-
- call getsbit ; Get and test for type of files
- jr z,dir6
-
- else ;not diron
-
- dec a ; Adjust returned value from 1..4 to 0..3
- rrca ; Multiply by 32 to convert number to
- rrca ; ..offset into TBUFF
- rrca
- ld c,a ; C = offset to entry in TBUFF
-
- endif ;diron
-
- pop de ; Restore count of
- ld a,e ; ..entries displayed
- inc e ; Increment entry counter
- push de ; Save it
- and 03h ; Output CRLF if 4 entries printed in line
- jr nz,dir4
- call crlf ; New line
- jr dir5
- dir4:
- call print
-
- if wide
-
- defb ' ' ; 2 spaces
- defb fence ; Then fence char
- defb ' ',' '+80h ; Then 2 more spaces
-
- else ;not wide
-
- defb ' ' ; Space
- defb fence ; Then fence char
- defb ' '+80h ; Then space
-
- endif ; wide
-
- dir5:
- ld a,1
- call dirptr ; HL now points to 1st byte of file name
- call prfn ; Print file name
- dir6:
- call break ; Check for abort
- jr z,dir7
- call srchnxt ; Search for next file
- jr nz,dir3 ; Continue if file found
-
- dir7:
- pop de ; Restore stack
- dec a ; Set NZ flag
- ret
-
- endif ; diron or eraon
-
- ;-----------------------------------------------------------------------------
-
- if diron or attchk or eraon
-
- ; This routine returns a pointer in HL to the directory entry in TBUFF that
- ; corresponds to the offset specified in registers C (file offset) and C
- ; (byte offset within entry).
-
- dirptr:
- ld hl,tbuff
- add a,c ; Add the two offset contributions
- call addah ; Set pointer to desired byte
- ld a,(hl) ; Get the desired byte
- ret
-
- endif ; diron or attchk or eraon
-
- ;-----------------------------------------------------------------------------
-
- ; Test File in FCB for existence, ask user to delete if so, and abort if he
- ; choses not to
-
- if saveon or renon
-
- extest:
- ld de,tfcb ; Point to FCB
- push de ; ..and save it for later
- call fcblog ; Log into specified directory
- call srchfst1 ; Look for specified file
- pop de ; Restore pointer
- ret z ; OK if not found, so return
- call printc
- if bellfl
- defb bell
- endif ;bellfl
- defb 'Erase',' '+80h
- ld hl,tfcb+1 ; Point to file name field
- call prfn ; Print it
- call print ; Add question mark
- defb '?' or 80h
- call conin ; Get user response
- cp 'Y' ; Test for permission to erase file
- jp nz,restart ; If not, flush the entire command line
- jp delete ; Delete the file
-
- endif ; saveon or renon
-
- ;-----------------------------------------------------------------------------
-
- ; Print file name pointed to by HL
-
- if diron or renon or saveon
-
- prfn:
- ld b,8 ; Display 8 characters in name
- call prfn1
- call print ; Put in dot
- defb '.' or 80h
- ld b,3 ; Display 3 characters in type
- prfn1:
- ld a,(hl) ; Get character
- inc hl ; Point to next
- call conout ; Print character
- djnz prfn1 ; Loop through them all
- ret
-
- endif ;diron or renon or saveon
-
- ;-----------------------------------------------------------------------------
-
- ; This routine returns NZ if the file has the required attributes and Z if
- ; it does not. It works by performing the 'exclusive or' of the mask passed
- ; in register A and the filename attribute obtained by masking out all but
- ; the highest bit of the character. For the 'both' case, setting any bit
- ; in the mask other than bit 7 will guarantee a nonzero result.
- ;
- ; File name: : X 0 0 0 0 0 0 0 (After 80H mask, X=1 if SYS, 0 if DIR)
- ;
- ; SYS-ONLY : 0 0 0 0 0 0 0 0 (XOR gives 00H if X=0 and 80H if X=1)
- ; DIR-ONLY : 1 0 0 0 0 0 0 0 (XOR gives 80H if X=0 and 00H if X=1)
- ; BOTH : 0 0 0 0 0 0 0 1 (XOR gives 01H if X=0 and 81H if X=1)
-
- if diron or attchk
-
- getsbit:
- dec a ; Adjust to returned value from 1..4 to 0..3
- rrca ; Multiply by 32 to convert number to
- rrca ; ..offset into TBUFF
- rrca
- ld c,a ; Save offset in TBUFF in C
- ld a,10 ; Add 10 to point to SYS attribute bit
- call dirptr ; A = SYS byte
- and 80h ; Look only at attribute bit
- systst equ $+1 ; In-the-code variable
- xor 0 ; If SYSTST=0, SYS only; if SYSTST=80H, DIR
- ; ..only; if SYSTST=1, both SYS and DIR
- ret ; NZ if OK, Z if not OK
-
- endif ;diron or attchk
-
- ;-----------------------------------------------------------------------------
-
- ; Command: REN
- ; Function: To change the name of an existing file
- ; Forms: REN <New UFN>=<Old UFN>
- ; Notes: If either file spec is ambiguous, or if the source file does
- ; not exist, the error handler will be entered. If a file with
- ; the new name already exists, the user is prompted for deletion
- ; and ZEX is turned off during the prompt.
-
- if renon
-
- ren:
- ld hl,tfcb ; Check for ambiguity in first file name
- call ambchk
- call fcblog ; Login to fcb
- ld hl,tfcb2 ; Check for ambiguity in second file name
- call ambchk
- xor a ; Use current drive for 2nd file
- ld (de),a
- call srchfst ; Check for old file's existence
- jr nz,ren0a ; Branch if file exists
- jpnofile:
- ld a,ecnofile ; Set error code for file not found
- jp error ; ..and invoke error handler
- ren0a:
- call extest ; Test for file existence and return if not
- ld b,12 ; Exchange new and old file names
- push de ; Save pointer to FCB
- ld hl,tfcb2 ; Point to FCB for old file name
- ren0:
- ld a,(de) ; Get character of old name
- ld c,a ; ..into C register
- ld a,(hl) ; Get character of new name
- ld (de),a ; ..into place in old name
- ld (hl),c ; Put character of old name into new name
- inc hl ; Advance pointers
- inc de
- djnz ren0
-
- ; Perform rename function
-
- pop de ; Restore pointer to FCB
- ld c,17h ; BDOS rename function
- jp bdostest
-
- endif ;renon
-
- ;-----------------------------------------------------------------------------
-
- ; Command: ERA
- ; Function: Erase files
- ; Forms:
- ; ERA <afn> Erase specified files and dislay their names
- ; ERA <afn> I Display names of files to be erased and prompt for
- ; inspection before erase is performed. (Character 'I'
- ; is defined by INSPCH in Z33HDR.LIB; if it is ' ', then
- ; any character triggers inspection.)
-
- if eraon
-
- era:
- if inspfl and eraok; 'I' flag and verification enabled?
- ld a,(tfcb2+1) ; Get flag, if any, entered by user
- ld (eraflg),a ; Save it in code below
- endif ;erav and eraok
-
- ld de,tfcb ; Point to target FCB
- call fcblog ; ..and log into the specified directory
-
- if diron or attchk ; Attribute checking only in these cases
- ld b,1 ; Display all matching files
- endif ;diron or attchk
-
- call dirpr ; Print directory of erased files
- ret z ; Abort if no files
-
- if eraok ; Print prompt
-
- if inspfl ; Test verify flag
-
- eraflg equ $+1 ; Address of flag (in-the-code modification)
- ld a,0
- cp inspch ; Is it an inspect option?
-
- if inspch ne ' ' ; If an explicit inspect character is specified
- jr nz,era2 ; ..skip prompt if it is not that character
- else ; If INSPCH is the space character
- jr z,era2 ; ..then skip prompt only if FCB has a space
- endif ;inspch ne ' '
-
- endif ;inspfl
-
- call printc
- defb 'OK to Erase','?'+80h
- call conin ; Get reply
- cp 'Y' ; Yes?
- ret nz ; Abort if not
-
- endif ; eraok
-
- era2:
- ld de,tfcb
- jp delete ; Delete files and return
-
- endif ; Eraon
-
- ;-----------------------------------------------------------------------------
-
- ; Command: LIST
- ; Function: Print out specified file on the LST: device
- ; Forms: LIST <ufn> Print file (No Paging)
- ; Notes: The flags which apply to TYPE do not take effect with LIST
-
- if lton
-
- list:
- ld a,0ffh ; Turn on printer flag
- jr type0
-
- ;-----------------------------------------------------------------------------
-
- ; Command: TYPE
- ; Function: Print out specified file on the CON: Device
- ; Forms: TYPE <ufn> Print file with default paging option
- ; TYPE <ufn> P Print file with paging option reversed
-
- type:
- xor a ; Turn off printer flag
-
- ; Common entry point for LIST and TYPE functions
-
- type0:
- ld (prflg),a ; Set printer/console flag
- ld a,(tfcb2+1) ; Check for user page toggle ('P') option
- ld (pgflg),a ; Save it as a flag in code below
- ld hl,tfcb ; Point to target file FCB
- call ambchk ; Check for ambiguous file spec (vectors to
- ; ..error handler if so)
- call fcblog ; Log into specified directory
- call open ; Open the file
-
- if renon ; If REN on, share code
- jr z,jpnofile
- else ;not renon ; Otherwise repeat code here
- ld a,ecnofile
- jp z,error
- endif ;renon
-
- call crlf ; New line
- ld a,(crttxt0) ; Set line count using value from the
- ; ..environment for CRT0
- inc a ; One extra the first time through
- ld (pagcnt),a
- ld bc,080h ; Set character position and tab count
- ; (B = 0 = tab, C = 080h = char position)
-
- ; Main loop for loading next block
-
- type2:
- ld a,c ; Get character count
- cp 80h ; If not end of disk record
- jr c,type3 ; ..then skip
-
- call readf ; Read next record of file
- ret nz ; Quit if end of file
-
- ld c,0 ; Reset character count
- ld hl,tbuff ; Point to first character
-
- ; Main loop for printing characters in TBUFF
-
- type3:
- ld a,(hl) ; Get next character
- and 7fh ; Mask out MSB
- cp 1ah ; Check for end of file (^z)
- ret z ; Quit if so
-
- ; Output character to CON: or LST: device with tabulation
-
- cp cr ; If carriage return,
- jr z,type4 ; ..branch to reset tab count
- cp lf ; If line feed, then output
- jr z,type4a ; ..with no change in tab count
- cp tab ; If tab
- jr z,type5 ; ..expand to spaces
-
- ; Output character and increment character count
-
- call lcout ; Output character
- inc b ; Increment tab count
- jr type6
-
- ; Output CR and reset tab count
-
- type4:
- ld b,0 ; Reset tab counter
-
- ; Output LF and leave tab count as is
-
- type4a:
- call lcout ; Output <cr> or <lf>
- jr type6
-
- ; Process tab character
-
- type5:
- ld a,' ' ; Space
- call lcout
- inc b ; Increment tab count
- ld a,b
- and 7
- jr nz,type5 ; Loop until column = n * 8 + 7
-
- ; Continue processing
-
- type6:
- inc c ; Increment character count
- inc hl ; Point to next character
- push bc
- call break ; Check for user abort
- pop bc
- ret z ; Quit if so
- jr type2 ; Else back for more
-
- ;--------------------
-
- ; Output character in A to console or list device depending on a flag.
- ; Registers are preserved. This code is used only by the LIST and TYPE
- ; commands.
-
- lcout:
- push af ; Save character
- prflg equ $+1 ; Pointer for in-the-code modification
- ld a,0 ; ..to determine destination (CON or LST)
- or a ; Z=type, NZ=list
- jr z,lc1
-
- ; Output to list device
-
- pop af ; Get character back
- push de
- push bc
- ld c,5 ; LISTOUT function
- jp output
-
- ; Output to console with paging
-
- lc1:
- pop af ; Get character back
- push af ; Save it again for page check
- call conout ; Output to console
- pop af ; Get character back again
- cp lf ; Check for new line (paging)
- ret nz ; If not new line, we are done
-
- ; Paging routines
-
- pager:
- push hl
- ld hl,pagcnt ; Decrement lines remaining on screen
- dec (hl)
- jr nz,pager1 ; Jump if not end of page
-
- ; New page
- ld a,(crttxt0) ; Get full page count from environment
- ld (hl),a ; Reset count to a full page
- pgflg equ $+1 ; Pointer to in-the-code buffer pgflg
- ld a,0
- cp pagech ; Page default override option wanted?
-
- if pagech ne ' ' ; If using explicit character for page toggle
-
- if pagefl ; If paging is default
- jr z,pager1 ; ..PAGECH means no paging
- else ; If paging not default
- jr nz,pager1 ; ..PAGECH means please paginate
- endif ;pagefl
-
- else ; Any character toggles paging
-
- if pagefl ; If paging is default
- jr nz,pager1 ; ..any character means no paging
- else ; If paging not default
- jr z,pager1 ; ..any character means please paginate
- endif ;pagefl
-
- endif ;pagech ne ' '
-
- ; End of page
- push bc
- call bios+9 ; Wait for user input (BIOS console input)
- pop bc
- cp 'C'-'@' ; Did user enter control-c?
- jp z,nextcmd ; If so, terminate this command
-
- pager1:
- pop hl ; Restore HL
- ret
-
- endif ; lton
-
- ;-----------------------------------------------------------------------------
-
- ; Command: SAVE
- ; Function: To save the contents of the TPA onto disk as a file
- ; Forms:
- ; SAVE <Number of Pages> <ufn>
- ; Save specified number of pages (starting at 100H) from TPA
- ; into specified file
- ;
- ; SAVE <Number of Sectors> <ufn> <S>
- ; Like SAVE above, but numeric argument specifies
- ; number of sectors rather than pages
-
- if saveon
-
- ; Entry point for SAVE command
-
- save:
- call number ; Extract number from command line
- jr c,badnumber ; Invoke error handler if bad number
- push bc ; Save the number
- call reparse ; Reparse tail after number of sectors/pages
- pop hl ; Get sector/page count back into HL
- ld a,(tfcb2+1) ; Check sector flag in second FCB
- cp sectch
-
- if sectch ne ' ' ; If using a specific character, then jump
- jr z,save0 ; ..if it is that character
- else ; If allowing any character (SECTCH=' ')
- jr nz,save0 ; ..jump if it is anything other than space
- endif ;sectch ne ' '
-
- add hl,hl ; Double page count to get sector count
- save0:
- ld a,1 ; Maximum allowed value in H
- cp h ; Make sure sector count < 512 (64K)
- jr c,badnumber ; If >511, invoke error handler
-
- push hl ; Save sector count
- ld hl,tfcb
- call ambchk ; Check for ambiguous file spec (vectors to
- ; ..error handler if so)
-
- call extest ; Test for existence of file and abort if so
- ld c,16h ; BDOS make file function
- call bdostest
- jr z,save3 ; Branch if error in creating file
-
- pop bc ; Get sector count into BC
- ld hl,tpa-80h ; Set pointer to one record before TPA
-
- save1:
- ld a,b ; Check for BC = 0
- or c
- dec bc ; Count down on sectors (flags unchanged,
- ; ..B=0FFH if all records written successfully)
- jr z,save2 ; If BC=0, save is done so branch
-
- push bc ; Save sector count
- ld de,80h ; Advance address by one record
- add hl,de
- push hl ; Save address on stack
- ex de,hl ; Put address into DE for BDOS call
- call dmaset ; Set DMA address for write
- ld de,tfcb ; Write sector
- ld c,15h ; BDOS write sector function
- call bdossave
- pop hl ; Get address back into HL
- pop bc ; Get sector count back into BC
- jr z,save1 ; If write successful, go back for more
-
- ld b,0 ; B=0 if write failed
-
- save2:
- call close ; Close file even if last write failed
- and b ; Combine close return code with
- ; ..write success flag
- ret nz ; Return if all ok
-
- save3: ; Disk must be full
- ld a,ecdiskfull ; Disk full error code
- jr jperror
-
- endif ; saveon
-
- ;-----------------------------------------------------------------------------
-
- if lton or saveon or renon or geton
-
- ; Check file control block pointed to by HL for any wildcard characters ('?').
- ; Return to calling program if none found. Otherwise branch to error handler.
- ; The routine also treats an empty file name as ambiguous.
-
- ambchk:
- push hl ; Save pointer to FCB
- inc hl ; Point to first character in file name
- ld a,(hl) ; See if first character is a space
- cp ' '
- jr z,ambchk1 ; If so, branch to error return
-
- ld a,'?' ; Set up for scan for question mark
- ld bc,11 ; Scan 11 characters
- cpir
- pop de ; Restore pointer to FCB in DE
- ret nz ; Return if no '?' found
- ambchk1:
- ld a,ecambig ; Error code for ambiguous file name
- jr jperror
-
- endif ;lton or renon or saveon or geton
-
- if lton or renon or saveon or geton or jumpon
-
- badnumber:
- ld a,ecbadnum ; Error code for bad number value
- jperror: ; Local entry point for relative jump
- jp error ; ..to go to error handler
-
- endif ;lton or renon or saveon or geton or jumpon
-
- ;-----------------------------------------------------------------------------
-
- ; Command: JUMP
- ; Function: To execute a program already loaded into some specified memory
- ; address
- ; Forms: JUMP <adr> <tail>
- ; The address is in hex; the tail will be parsed as usual
-
- if jumpon
-
- jump:
- call hexnum ; Get load address into BC
- jr c,badnumber ; If bad number, invoke error handling
- push bc ; ..and save it
- call reparse ; Reparse tail after address value
- pop hl ; Restore execution address to HL
- jr getproglf ; Perform call via code below
-
- endif ;jumpon
-
- ;-----------------------------------------------------------------------------
-
- ; Command: GO
- ; Function: To Call the program in the TPA without loading
- ; loading from disk. Same as JUMP 100H, but much
- ; more convenient, especially when used with
- ; parameters for programs like STAT. Also can be
- ; allowed on remote-access systems with no problems.
- ;
- ;Form: GO <tail>
-
- if goon
-
- go:
- ld hl,tpa ; Set up TPA as the execution address
-
- endif ; goon
-
- if jumpon or goon ; Common code
-
- getproglf:
- ld (execadr),hl
- xor a ; Set zero flag to enable leading CRLF
- jp callproglf ; Perform call (with leading CRLF)
-
- endif ;jumpon or goon
-
- ;-----------------------------------------------------------------------------
-
- ; Command: GET
- ; Function: To load the specified file from disk to the specified address
- ; Forms: GET <adr> <ufn>
- ; Loads the specified file to the specified hexadecimal address
- ; Note that the normal file search path is used to find the file.
- ; If SCANCUR is off, the file may not be found in the current
- ; directory unless a colon is included in the file spec.
-
- if geton
-
- get:
-
- ; TMPCOLON was set when the file name was parsed. We use that as the colon
- ; flag so that the file will be loaded from a directory just as if it had
- ; been entered as the command name.
-
- if drvprefix and [not scancur]
- ld a,(tmpcolon) ; Allow GET to load from specified
- ld (colon),a ; directory
- endif ;drvprefix and [not scancur]
-
- ld hl,tfcb2 ; Copy TFCB2 to CMDFCB for load
- push hl
- ld de,cmdfcb
- ld bc,14
- ldir
- pop hl
- call ambchk ; Make sure file is not ambiguous (vectors
- ; ..to error handler if so)
-
- ; If GET fails to find the specified file along the search path, we do not
- ; want the ECP to be engaged. To prevent that, we fool the command processor
- ; by telling it that the ECP is already engaged.
-
- ld hl,cmdstatfl ; Point to command status flag
- set 2,(hl) ; Turn on ECP flag to prevent use of ECP
- call hexnum ; Get load address into BC
- jr c,badnumber ; If invalid number, invoke error handler
-
- if not fullget
- ld a,b ; If trying to load into base page
- or a ; ..treat as error
- jr z,badnumber
- endif ;not fullget
-
- ld h,b ; Move address into HL
- ld l,c
- ld a,0ffh ; Disable dynamic loading
- ; Fall through to mload
-
- endif ; geton
-
- ; End ZCPR33-5.Z80
-
- page
-
- ; ZCPR33-6.Z80
-
- ;=============================================================================
- ;
- ; P A T H S E A R C H A N D F I L E L O A D I N G C O D E
- ;
- ;=============================================================================
-
- ; This block of code loads a file into memory. The normal address at which
- ; loading is to begin is passed to the routine in the HL register. The name
- ; of the file to load is passed in the command file control block.
- ;
- ; This code supports an advanced option that loads files to a dynamic address
- ; specified in the header to the file using a new type-3 environment. In a
- ; type-3 environment, the execution/load address is stored in the word
- ; following the environment descriptor address. A value is passed to MLOAD in
- ; the A register that controls this dynamic loading mechanism. The value
- ; specifies the lowest environment type value for which dynamic loading will
- ; be performed. This value will be 3 when MLOAD is called for normal COM file
- ; execution and will be 0FFH when chained to from the GET command. In the
- ; latter case, the user-specified load address must be used.
- ;
- ; MLOAD guards against loading a file over the operating system. It computes
- ; the lower of the following two addresses: 1) the CPR entry point; 2) the
- ; bottom of protected memory as indicated by the DOS entry address stored at
- ; address 0006H. If the load would exceed this limit, error handling is
- ; engaged (except for the GET command when FULLGET is enabled).
-
- mload:
- ld (envtype),a ; Set up in-the-code modification below
- ld (execadr),hl ; Set up execution/load address
- call defltdma ; Set DMA address to 80H for file searches
-
-
- ; This code sets the attributes of COM files which are acceptable. If both
- ; SYS and DIR type files are acceptable, there is no need to include this code,
- ; and ATTCHK can be set to false.
-
- if attchk ; Only if attribute checking enabled
- ld a,comatt ; Attributes specified in Z33HDR.LIB
- ld (systst),a ; Set flag
- endif ;attchk
-
- ;-----------------------------------------------------------------------------
-
- ; PATH BUILDING CODE
-
- ; In ZCPR33 the minpath feature, optional in ZCPR30, is always used. To
- ; minimize the size of the CPR code, however, there is an option to place the
- ; minpath in an external buffer (outside the CPR). If the path is short
- ; enough, the minpath can be placed at the bottom of the system stack.
-
- ld de,path ; Point to first element in user's symbolic path
- ld hl,mpath ; Point to minpath buffer
- xor a
- ld (hl),a ; Initialize to empty minpath
-
-
- ; If DRVPREFIX is enabled, the CPR will recognize an explicit directory
- ; reference in a command. The first element of the path will then be this
- ; explicit directory. If no explicit directory was given in the command,
- ; then no entry is made into the search path. If the WPREFIX option is
- ; on, explicit directory prefixes will be recognized only when the wheel
- ; byte is on.
-
- if drvprefix ; Pay attention to du:com prefix?
-
- ld a,(colon) ; See if colon was present in command
- or a
- jr z,makepath2 ; If not, skip ahead
-
- if wprefix
- ld a,(z3whl) ; See if wheel byte is on
- or a
- jr z,makepath2 ; If not, skip ahead
- endif ;wprefix
-
- ld a,(cmdfcb) ; Get drive from command FCB
- ld (hl),a ; Put drive into minpath
- inc hl ; Advance pointer
- ld a,(cmdfcb+13) ; Get user number from command FCB
- ld (hl),a ; Put it into minpath
- inc hl ; Advance pointer to next path element
- xor a ; A=0
- ld (hl),a ; Store ending 0 in mpath
- makepath2:
- endif ; drvprefix
-
-
- ; If SCANCUR is enabled in Z33HDR.LIB, then we always include the current
- ; directory automatically, even without a '$$' element in the user's path.
- ; If WPREFIX is enabled, however, we do not want to allow the current
- ; directory to be included, but we must make sure that it is included in
- ; the building of the root path, in case the user's symbolic path is empty.
-
- if scancur ; Scan current directory at all times?
-
- ld bc,(curusr) ; C = current user, B = current drive
- inc b ; Set drive to range 1..16
-
- if wprefix
-
- ld a,(z3whl) ; See if wheel byte is on
- or a
- jr nz,addpath ; If it is, add element to path; if not,
- ; ..fall through to MAKEPATH3
- else ;not wprefix
-
- jr addpath ; Begin loop of placing entries into mpath
-
- endif ;wprefix
-
- else ;not scancur
-
- ; If SCANCUR is off and ROOTONLY is in effect, we have to make sure that some
- ; directory values are put into the root path in the case where the user's
- ; path is completely empty. To do so, we preset BC for directory A0.
-
- if rootonly
- ld bc,0100h ; Setup for drive A (B=1), user 0 (C=0)
- endif ;rootonly
-
- endif ;scancur
-
-
- ; Convert symbolic entries in user's path into absolute DU values in minpath.
- ; Entries are read one-by-one from the symbolic path. If the 'current' drive
- ; or user indicator is present (default symbol is '$'), then the current
- ; drive or user value is fetched. Otherwise the explicit binary value from the
- ; path is used. After each absolute DU value is formed, the minpath as it
- ; exists so far is scanned to see if this DU value is already there. If it is
- ; not, then the DU value is appended to the path. Otherwise it is ignored.
-
- makepath3:
- ld a,(de) ; Get next symbolic path entry
- or a ; If 0, we are at end of path
- jr z,makepath6
-
- ld bc,(curusr) ; C = current user, B = current drive
- inc b ; Set drive to range 1..16
- cp curind ; Check for current drive symbol (default '$')
- jr z,makepath4 ; If so, leave current drive in B
- ld b,a ; Else move specified drive into B
- makepath4:
- inc de ; Point to user value in symbolic path
- ld a,(de) ; Get user
- inc de ; Point to next element in symbolic path
- cp curind ; Check for current user symbol (default '$')
- jr z,makepath5 ; If so, leave current drive in C
- ld c,a ; Else move specified user into C
- makepath5:
-
- ; At this point in the code we have a potential path element in BC. We first
- ; have to scan the minpath we have so far to see if that element is already
- ; there. In that case we ignore it; otherwise we add it to the end of the path.
-
- addpath:
- ; Skip path if directory given explicitly
-
- if skippath
-
- if wprefix
- ld a,(z3whl) ; See if wheel byte is on
- or a
- call nz,skipchk ; If not, fall through
- else ;not wprefix
- call skipchk ; See if path should be skipped
- endif ;wprefix
-
- jr nz,makepath3 ; If so, branch out of ADDPATH
-
- endif ;skippath
-
- ld hl,mpath ; Point to beginning of minpath
-
- addpath1: ; Point of reentry
- ld a,(hl) ; Get drive value
- or a ; Check for end of minpath
- jr z,addpath2 ; If end, jump and add BC to minpath
-
- inc hl ; Increment pointer to user
- cp b ; Check for drive match
- ld a,(hl) ; Get user from minpath
- inc hl ; Point to next minpath entry
- jr nz,addpath1 ; If drive was different, loop back again
- cp c ; Check for user match
- jr nz,addpath1 ; If user is different, loop back again
- jr makepath3 ; Branch if we have a duplicate
-
- ; We have a new DU; add it to minpath
-
- addpath2:
- ld (hl),b ; Store drive
- inc hl
- ld (hl),c ; Store user
- inc hl
- ld (hl),0 ; Store ending 0
- jr makepath3 ; Continue scanning user's path
-
- ; If the ECP facility is set up to use the root directory, then create a
- ; root path. BC presently contains the proper DU.
-
- makepath6:
-
- if rootonly
- ld hl,rootpth ; Point to special path to contain root
- ld (hl),b ; Store disk
- inc hl
- ld (hl),c ; Store user
- endif ;rootonly
-
- ;-----------------------------------------------------------------------------
-
- ; This is the code for loading the specified file by searching the minpath.
-
- xor a ; Always use current disk specification in the
- ld (cmdfcb),a ; ..command FCB
-
- mload1:
-
- ld hl,mpath ; Point to beginning of minpath
-
- mload2:
-
- ; Either the FASTECP or BADDUECP option may have set FIRSTCHAR to a space
- ; character as a signal to go directly to extended command processing. If
- ; neither option is enabled but SKIPPATH is, then the FIRSTCHAR data is
- ; stored in the routine below where path skipping is implemented.
-
- if fastecp or badduecp
-
- ld a,(cmdstatfl) ; If ECP is running
- bit 2,a ; ..we branch to look for ECP along path
- jr nz,mload2a
- firstchar equ $+1 ; Pointer for in-the-code modification
- ld a,0
- cp ' ' ; Was command invoked with leading space?
- jr z,ecprun ; If so, go directly to ECP code
-
- endif ;fastecp or badduecp
-
- mload2a:
- ld a,(hl) ; Get drive from path
- or a ; If end of path, command not found
- jr nz,mload3 ; If not end of path, skip over ECP code
-
- ;-----------------------------------------------------------------------------
-
- ; EXTENDED COMMAND PROCESSING
-
- ; At this point we have exhausted the search path. We now engage the
- ; extended command processor.
-
- ecprun:
- if skippath
- call skipchk ; See if path should be skipped
- jr nz,jnzerror ; If so, invoke error handler
- endif ;skippath
-
- ld hl,cmdstatfl ; Point to command status flag
- ld a,(hl) ; ..and get value
- and 110b ; Isolate ECP and error handler bits
- jnzerror: ; If either is set,
- ld a,ecnocmd ; Error code for command not found
- jp nz,error ; ..process as an error
-
- set 2,(hl) ; Set ECP bit
-
- ld hl,ecpfcb ; Copy name of ECP to command FCB
- ld de,cmdfcb
- ld bc,12 ; Only 12 bytes required
- ldir
-
- ld hl,(cmdptr) ; Get pointer to current command line
- call parsetail ; Parse entire command as the command tail
-
- if rootonly ; Look for ECP in root directory only
- ld hl,rootpth ; Point to path containing root directory only
- jr mload2 ; Search for command
- else ; not rootonly
- jr mload1 ; Search the entire minpath for the ECP
- endif ; rootonly
-
- ;-----------------------------------------------------------------------------
-
- mload3:
- ld b,a ; Drive into B
- inc hl ; Point to user number
- ld c,(hl) ; User into C
- ld (tempusr),bc ; Save the values
- inc hl ; Point to next entry in path
- call logtemp ; Log in path-specified user/drive
-
- if attchk ; If allowing execution only of COM files with
- ; ..specific attributes
-
- ld de,cmdfcb ; Point to command FCB
- call srchfst ; Look for directory entry for file
- jr z,mload2a ; Continue path search if file not found
- push hl ; Save path pointer
- call getsbit ; Check system attribute bit
- pop hl ; Restore path pointer
- jr z,mload2a ; Continue if attributes do not match
- call opencmd ; Open file for input
- jr z,mload2a ; If open failed, back to next path element
-
- else ;not attchk
-
- call opencmd ; Open file for input
- jr z,mload2a ; If open failed, back to next path element
-
- endif ; attchk
-
- call readcmd ; Read first record into default DMA address
- jr nz,mload5 ; Branch if zero-length file
- xor a ; Set file current record back to zero
- ld (cmdfcb+20h),a
- ld hl,80h ; Pointer to start of code
- call z3chk
- jr nz,mload3a ; If not Z3 file, branch
-
- ; The following test is modified by earlier code. For normal COM file loading,
- ; a 3 is inserted for the minimum environment type for dynamic load address
- ; determination. For the GET command, where the user-specified address should
- ; be used, a value of 0FFH is put in here so the carry flag will always be set.
-
- envtype equ $+1 ; Pointer for in-the-code modification
- cp 3 ; See if no higher than a type-3 environment
- jr c,mload3a ; If higher than type 3, branch
-
- inc hl ; Advance to load address word
- inc hl
- inc hl
- ld a,(hl) ; Get load address into HL
- inc hl
- ld h,(hl)
- ld l,a
- ld (execadr),hl ; Set new execution/load address
-
- mload3a:
- ld hl,(execadr) ; Get initial loading address
-
- ; Load the file, making sure neither CPR nor protected memory is overwritten
-
- mload4:
- if fullget
- ld a,(envtype) ; If ENVTYPE is FF (from GET command)
- inc a ; ..then skip memory limit checking
- jr z,mload4b
- endif ;fullget
-
- if rel
- ld bc,entry ; We have to use a relocatable form to get
- dec b ; ..highest page below the CPR
- else ;not rel
- ld b,high entry - 1 ; We can use shorter code for absolute form
- endif ;rel
-
- ld a,(0007h) ; Get highest page below
- dec a ; ..protected memory
- cp b ; If A is lower value,
- jr c,mload4a ; ..branch
- ld a,b ; Otherwise use lower value in B
- mload4a:
- cp h ; Are we going to overwrite protected memory?
- ld a,ectpafull ; Get ready with TPA overflow error code
- jp c,error ; Error if about to overwrite protected memory
- mload4b:
- push hl ; Save this load address
- ex de,hl ; Set DMA address
- call dmaset
- call readcmd
- pop hl ; Get last load address back
- jr nz,mload5 ; Read error or eof?
- ld de,128 ; Increment load address by 128
- add hl,de
- jr mload4 ; Continue loading
-
- ; In case a program would like to find out in what directory the command
- ; processor found the program, temporary DU is stored in bytes 13 (user) and
- ; 14 (drive) in the command FCB.
-
- mload5:
-
- tempusr equ $+1 ; Pointers for in-the-code modification
- tempdr equ $+2
- ld hl,0
- ld (cmdfcb+13),hl
-
- logcurrent: ; Return to original logged directory
- ld hl,(curusr) ; Set L = current user, H = current drive
- ld a,h
- call setdrive ; Login current drive
- ld a,l
- jp setuser ; Log in new user and return from MLOAD
-
- ;----------------------------------------
-
- ; This routine checks to see if building the path or running the ECP should
- ; be skipped. If there is a colon in the command (an explicit directory
- ; given) but it was not a lone colon (indicating desire to skip resident
- ; commands), then the routine returns with the zero flag reset.
-
- if skippath
-
- skipchk:
- ld a,(colon) ; Was there a colon in the command?
- or a
- ret z ; Return with zero flag set if not
-
- if fastecp or badduecp
- ld a,(firstchar) ; See if the first character was the colon
- else
- firstchar equ $+1 ; Put data here if other two options are
- ld a,0 ; ..false (in-the-code modification)
- endif ;fastecp or badduecp
-
- cp ':'
- ret ; Return: Z if lone colon, NZ otherwise
-
- endif ;skippath
-
-
- ; End ZCPR33-6.Z80
-
- page
-
- ;-----------------------------------------------------------------------------
- ;
- ; D A T A A R E A D E F I N I T I O N S
- ;
- ;-----------------------------------------------------------------------------
-
- ; ---------- Page line count buffer
-
- if lton ; Needed only if TYPE command included
-
- pagcnt:
- defs 1 ; Lines left on page (filled in by code)
-
- endif ;lton
-
-
- ; ---------- Minpath/Rootpth buffers
-
- if extmpath
-
- mpath equ extmpathadr ; Assign external minpath address
-
- else
-
- mpath:
- if drvprefix
- defs 2 ; Two bytes for specified DU
- endif
-
- if scancur
- defs 2 ; Two bytes for current DU
- endif
-
- defs 2 * expaths ; Space for path from path buffer
-
- defs 1 ; One byte for ending null
-
- endif ; not extmpath
-
-
- if rootonly
- rootpth:
- defs 2 ; Special path for root dir only
- defb 0 ; End of path
- endif ; rootonly
-
- ;-----------------------------------------------------------------------------
-
- ; The following will cause an error message to appear if
- ; the size of ZCPR33 is over 2K bytes.
-
- if [ $ - entry ] gt 800h
- *** ZCPR33 IS LARGER THAN 2K BYTES ***
- endif
-
- endif ;errflag
-
- end ; ZCPR33