home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
CPM
/
ZCPR2
/
LRUNZ.AQM
/
LRUNZ.ASM
Wrap
Assembly Source File
|
2000-06-30
|
26KB
|
1,198 lines
TITLE 'LRUNZ Library Run for ZCPR2 -- a utility for .LBR files'
VERSION EQU 1$0 ;82-08-06 Initial source release
PAGE 60
;
; Requires MAC for assembly. Due to the complexity of
; the relocation macros, this program may take a while
; to assemble. Be prepared for periods of no disk activity
; on both passes before pressing panic button. G.P.N.
;
;--------------------------NOTICE------------------------------
;
; (c) Copyright 1982 Gary P. Novosielski
; All rights reserved.
;
; The following features courtesy of Ron Fowler:
; 1) command line reparsing and repacking (this allows
; the former load-only program to become a load & run
; utility).
; 2) code necessary to actually execute the loaded file
; 3) the HELP facility (LRUN with no arguments)
; 4) modified error routines to avoid warm-boot delay
; (return to CCP directly instead)
;
; Permission to distribute this program in source or
; object form without prior written aproval is granted
; only under the following conditions.
;
; 1. No charge is imposed for the program.
; 2. Charges for incidental costs including
; but not limited to media, postage, tele-
; communications, and data storage do not
; exceed those costs actually incurred.
; 3. This Notice and any copright notices in
; the object code remain intact
;
; (signed) Gary P. Novosielski
;
;--------------------------------------------------------------
;
; LRUN is intended to be used in conjunction with libraries
; created with LU.COM, a library utility based upon the
; groundwork laid by Michael Rubenstien, with some additional
; inspiration from Leor Zolman's CLIB librarian for .CRL files.
;
; The user can place the less frequently used command (.COM)
; files in a library to save space, and still be able to run
; them when required, by typing:
; LRUN <normal command line>.
; The name of the library can be specified, but the greatest
; utility will be achieved by placing all commands in one
; library called COMMAND.LBR, or some locally defined name,
; and always letting LRUN use that name as the default.
;
;Syntax:
; LRUN [-<lbrname>] <command> [<parameters>]
;
;where:
;<lbrname> is the optional library name. In the
; distrubution version, this defaults to
; COMMAND.LBR. If the user wishes to use a
; different name for the default, the 8-byte
; literal at DFLTNAM below may be changed to
; suit local requirements. The current drive
; is searched for the .LBR file, and if not
; found there, the A: drive is searched.
; **Note that the leading minus sign (not a part
; of the name) is required to indicate an
; override library name is being entered.
;
;<command> is the name of the .COM file in the library
;
;<line> is the (possibly empty) set of parameters
; which are to be passed to <command>, as in
; normal CP/M syntax. Notice that if the
; library name is defaulted, the syntax is
; simply:
; LRUN <command line>
; which is just the normal command line with
; LRUN prefixed to it.
;
;
; MACROS TO PROVIDE Z80 EXTENSIONS
; MACROS INCLUDE:
;
$-MACRO ;FIRST TURN OFF THE EXPANSIONS
;
; JR - JUMP RELATIVE
; JRC - JUMP RELATIVE IF CARRY
; JRNC - JUMP RELATIVE IF NO CARRY
; JRZ - JUMP RELATIVE IF ZERO
; JRNZ - JUMP RELATIVE IF NO ZERO
; DJNZ - DECREMENT B AND JUMP RELATIVE IF NO ZERO
; LDIR - MOV @HL TO @DE FOR COUNT IN BC
; LXXD - LOAD DOUBLE REG DIRECT
; SXXD - STORE DOUBLE REG DIRECT
;
;
;
; @GENDD MACRO USED FOR CHECKING AND GENERATING
; 8-BIT JUMP RELATIVE DISPLACEMENTS
;
@GENDD MACRO ?DD ;;USED FOR CHECKING RANGE OF 8-BIT DISPLACEMENTS
IF (?DD GT 7FH) AND (?DD LT 0FF80H)
DB 100H ;Displacement Range Error on Jump Relative
ELSE
DB ?DD
ENDIF
ENDM
;
;
; Z80 MACRO EXTENSIONS
;
JR MACRO ?N ;;JUMP RELATIVE
DB 18H
@GENDD ?N-$-1
ENDM
;
JRC MACRO ?N ;;JUMP RELATIVE ON CARRY
DB 38H
@GENDD ?N-$-1
ENDM
;
JRNC MACRO ?N ;;JUMP RELATIVE ON NO CARRY
DB 30H
@GENDD ?N-$-1
ENDM
;
JRZ MACRO ?N ;;JUMP RELATIVE ON ZERO
DB 28H
@GENDD ?N-$-1
ENDM
;
JRNZ MACRO ?N ;;JUMP RELATIVE ON NO ZERO
DB 20H
@GENDD ?N-$-1
ENDM
;
DJNZ MACRO ?N ;;DECREMENT B AND JUMP RELATIVE ON NO ZERO
DB 10H
@GENDD ?N-$-1
ENDM
;
LDIR MACRO ;;LDIR
DB 0EDH,0B0H
ENDM
;
LDED MACRO ?N ;;LOAD DE DIRECT
DB 0EDH,05BH
DW ?N
ENDM
;
LBCD MACRO ?N ;;LOAD BC DIRECT
DB 0EDH,4BH
DW ?N
ENDM
;
SDED MACRO ?N ;;STORE DE DIRECT
DB 0EDH,53H
DW ?N
ENDM
;
SBCD MACRO ?N ;;STORE BC DIRECT
DB 0EDH,43H
DW ?N
ENDM
;
; END OF Z80 MACRO EXTENSIONS
;
@SYS SET 0
@KEY SET 1
@CON SET 2
@RDR SET 3
@PUN SET 4
@LST SET 5
@DIO SET 6
@RIO SET 7
@SIO SET 8
@MSG SET 9
@INP SET 10
@RDY SET 11
@VER SET 12
@LOG SET 13
@DSK SET 14
@OPN SET 15
@CLS SET 16
@DIR SET 17
@NXT SET 18
@DEL SET 19
@FRD SET 20
@FWR SET 21
@MAK SET 22
@REN SET 23
@CUR SET 25
@DMA SET 26
@CHG SET 30
@USR SET 32
@RRD SET 33
@RWR SET 34
@SIZ SET 35
@REC SET 36
@LOGV SET 37 ;2.2 only
@RWR0 SET 40 ;2.2 only
;
CPMBASE EQU 0
BOOT SET CPMBASE
BDOS SET BOOT+5
TFCB EQU BOOT+5CH
TFCB1 EQU TFCB
TFCB2 EQU TFCB+16
TBUFF EQU BOOT+80H
TPA EQU BOOT+100H
CTRL EQU ' '-1 ;Ctrl char mask
CR SET CTRL AND 'M'
LF SET CTRL AND 'J'
TAB SET CTRL AND 'I'
FF SET CTRL AND 'L'
BS SET CTRL AND 'H'
FALSE SET 0
TRUE SET NOT FALSE
;
CPM MACRO FUNC,OPERAND,CONDTN
LOCAL PAST
IF NOT NUL CONDTN
DB ( J&CONDTN ) XOR 8
DW PAST
ENDIF ;;of not nul condtn
IF NOT NUL OPERAND
LXI D,OPERAND
ENDIF ;;of not nul operand
IF NOT NUL FUNC
MVI C,@&FUNC
ENDIF
CALL BDOS
PAST:
ENDM
;
BLKMOV MACRO DEST,SRCE,LEN,COND
LOCAL PAST
JMP PAST
@BMVSBR:
MOV A,B
ORA C
RZ
DCX B
MOV A,M
INX H
STAX D
INX D
JMP @BMVSBR
BLKMOV MACRO DST,SRC,LN,CC
LOCAL PST
IF NOT NUL CC
DB ( J&CC ) XOR 8
DW PST
ENDIF
IF NOT NUL DST
LXI D,DST
ENDIF
IF NOT NUL SRC
LXI H,SRC
ENDIF
IF NOT NUL LN
LXI B,LN
ENDIF
CALL @BMVSBR
IF NOT NUL CC
PST:
ENDIF
ENDM
PAST: BLKMOV DEST,SRCE,LEN,COND
ENDM
;
OVERLAY SET 0
; Macro Definitions
;
RTAG MACRO LBL
??R&LBL EQU $+2-@BASE
ENDM
;
RGRND MACRO LBL
??R&LBL EQU 0FFFFH
ENDM
;
R MACRO INST
@RLBL SET @RLBL+1
RTAG %@RLBL
INST-@BASE
ENDM
;
NXTRLD MACRO NN
@RLD SET ??R&NN
@NXTRLD SET @NXTRLD + 1
ENDM
;
;
; Enter here from Console Command Processor (CCP)
;
ORG TPA
CCPIN:
;
; Branch to Start of Program
;
jmp start
;
;******************************************************************
;
; SINSFORM -- ZCPR2 Utility Standard General Purpose Initialization Format
;
; This data block precisely defines the data format for
; initial features of a ZCPR2 system which are required for proper
; initialization of the ZCPR2-Specific Routines in SYSLIB.
;
;
; EXTERNAL PATH DATA
;
EPAVAIL:
DB 0FFH ; IS EXTERNAL PATH AVAILABLE? (0=NO, 0FFH=YES)
EPADR:
DW 40H ; ADDRESS OF EXTERNAL PATH IF AVAILABLE
;
; INTERNAL PATH DATA
;
INTPATH:
DB 0,0 ; DISK, USER FOR FIRST PATH ELEMENT
; DISK = 1 FOR A, '$' FOR CURRENT
; USER = NUMBER, '$' FOR CURRENT
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0
DB 0,0 ; DISK, USER FOR 8TH PATH ELEMENT
DB 0 ; END OF PATH
;
; MULTIPLE COMMAND LINE BUFFER DATA
;
MCAVAIL:
DB 0FFH ; IS MULTIPLE COMMAND LINE BUFFER AVAILABLE?
MCADR:
DW 0FF00H ; ADDRESS OF MULTIPLE COMMAND LINE BUFFER IF AVAILABLE
;
; DISK/USER LIMITS
;
MDISK:
DB 4 ; MAXIMUM NUMBER OF DISKS
MUSER:
DB 31 ; MAXIMUM USER NUMBER
;
; FLAGS TO PERMIT LOG IN FOR DIFFERENT USER AREA OR DISK
;
DOK:
DB 0FFH ; ALLOW DISK CHANGE? (0=NO, 0FFH=YES)
UOK:
DB 0FFH ; ALLOW USER CHANGE? (0=NO, 0FFH=YES)
;
; PRIVILEGED USER DATA
;
PUSER:
DB 10 ; BEGINNING OF PRIVILEGED USER AREAS
PPASS:
DB 'chdir',0 ; PASSWORD FOR MOVING INTO PRIV USER AREAS
DS 41-($-PPASS) ; 40 CHARS MAX IN BUFFER + 1 for ending NULL
;
; CURRENT USER/DISK INDICATOR
;
CINDIC:
DB '$' ; USUAL VALUE (FOR PATH EXPRESSIONS)
;
; DMA ADDRESS FOR DISK TRANSFERS
;
DMADR:
DW 80H ; TBUFF AREA
;
; NAMED DIRECTORY INFORMATION
;
NDRADR:
DW 00000H ; ADDRESS OF MEMORY-RESIDENT NAMED DIRECTORY
NDNAMES:
DB 64 ; MAX NUMBER OF DIRECTORY NAMES
DNFILE:
DB 'NAMES ' ; NAME OF DISK NAME FILE
DB 'DIR' ; TYPE OF DISK NAME FILE
;
; REQUIREMENTS FLAGS
;
EPREQD:
DB 0FFH ; EXTERNAL PATH?
MCREQD:
DB 000H ; MULTIPLE COMMAND LINE?
MXREQD:
DB 000H ; MAX USER/DISK?
UDREQD:
DB 000H ; ALLOW USER/DISK CHANGE?
PUREQD:
DB 000H ; PRIVILEGED USER?
CDREQD:
DB 0FFH ; CURRENT INDIC AND DMA?
NDREQD:
DB 000H ; NAMED DIRECTORIES?
Z2CLASS:
DB 5 ; CLASS 5
DB 'ZCPR2'
DS 10 ; RESERVED
;
; END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA
;
;******************************************************************
;
DFLTNAM:
DB 'COMMAND ' ; <---change this if you like---
LBRLIT:
DB 'LBR'
;
SIGNON:
DB 'LRUNZ Version ' ;Signon message
DB VERSION/10+'0'
DB '.'
DB VERSION MOD 10+'0'
DB CR,LF
DB '$',CTRL AND 'Z'
DB ' Copyright (c) 1982 Gary P. Novosielski '
DB CR,LF
DB ' Modified for Use Under ZCPR2 by Richard Conn'
DB '$',CTRL AND 'Z'
;
; START OF PROGRAM
;
START:
LXI H,0 ;get the CCP entry stackpointer
DAD SP ;(used only if HELP request
SHLD SPSAVE ; is encountered)
CPM MSG,SIGNON; ;Display signon
CALL SETUP ;initialize.
LHLD BDOS+1 ;find top of memory
MOV A,H ;page address
;Form destination...
SUI PAGES ;...address in
MOV D,A ;DE pair.
MVI E,0
PUSH D ;save on stack
;
BLKMOV ,@BASE,SEGLEN ;Move the active segment.
;
;The segment is now moved to high memory, but not
;properly relocated. The bit table which specifies
;which addresses need to be adjusted is located
;just after the last byte of the source segment,
;so (HL) is now pointing at it.
POP D ;beginning of newly moved code.
LXI B,SEGLEN;length of segment
PUSH H ;save pointer to reloc info
MOV H,D ;offset page address
;
;Scan through the newly moved code, and adjust any
;page addresses by adding (H) to them. The word on
;top of the stack points to the next byte of the
;relocation bit table. Each bit in the table
;corresponds to one byte in the destination code.
;A value of 1 indicates the byte is to be adjusted.
;A value of 0 indicates the byte is to be unchanged.
;
;Thus one byte of relocation information serves to
;mark 8 bytes of object code. The bits which have
;not been used yet are saved in L until all 8
;are used.
;
FIXLOOP:
MOV A,B
ORA C ;test if finished
JRZ FIXDONE
DCX B ;count down
MOV A,E
ANI 07H ;on 8-byte boundry?
JRNZ NEXTBIT
;
NEXTBYT:
;Get another byte of relocation bits
XTHL
MOV A,M
INX H
XTHL
MOV L,A ;save in register L
;
NEXTBIT:
MOV A,L ;remaining bits from L
RAL ;next bit to CARRY
MOV L,A ;save the rest
JRNC NEXTADR
;
;CARRY was = 1. Fix this byte.
LDAX D
ADD H ;(H) is the page offset
STAX D
;
NEXTADR:
INX D
JR FIXLOOP
;
;Finished. Jump to the first address in the new
;segment in high memory.
;
;First adjust the stack. One garbage word was
;left by fixloop.
;
FIXDONE:
INX SP
INX SP
;
;(HL) still has the page address
;
MOV L,A ;move zero to l
;
; Set User/Disk for Return
;
LDA CDISK ;Set Disk
MOV B,A
LDA CUSER ;Set User
MOV C,A
PCHL ;Stack is valid
;
;Any one-shot initialization code goes here.
;
SETUP:
LXI H,NOLOAD
SHLD CCPIN+1 ;Prevent reentry
;
CALL REPARS ;Re-parse command line
;
LXI D,MEMBER+9 ;Check member filetype
LDAX D
CPI ' ' ;If blank,
BLKMOV ,COMLIT,3,Z ; default to COM.
;
LXI D,LBRFIL+9 ;Check library filetype
LDAX D
CPI ' ' ;If blank,
BLKMOV ,LBRLIT,3,Z ; default to LBR
;
LXI D,LBRFIL+1 ;Check name
LDAX D
CPI ' ' ;If blank,
BLKMOV ,DFLTNAM,8,Z ; use default name.
;
; Set Current Disk and User and then Search Along ZCPR2 Path for
; the Library File
;
CPM CUR ;Get Current Disk
STA CDISK ;Save It
CPM USR,0FFH ;Get Current User
STA CUSER ;Save It
CPM OPN,LBRFIL ;Try to Open Library File Now
INR A ;Zero Means Not Found
JRNZ DIROK ;Process if Found
XRA A ;Set to Select Current Disk
STA LBRFIL
LXI H,INTPATH ;Point to Internal Path
LDA EPAVAIL ;External Path Available?
ORA A ;Zero = No
JRZ INPATH
LHLD EPADR ;Get Address of External Path
INPATH:
MOV A,M ;Get Drive
ORA A ;0=Command Not Found
JZ NODIR ;Not Found
ANI 7FH ;Mask MSB
MOV B,A ;Save in B for a While
LDA CINDIC ;Get Current Indicator
CMP B ;Compare for Current
JRNZ INPATH1 ;Good Disk In B
LDA CDISK ;Get Current Disk
INR A ;Add 1 to be good
MOV B,A ;Disk In B
INPATH1:
DCR B ;Disk in Range 0-15
INX H ;Pt to User Number
MOV A,M ;Get User Number
INX H ;Pt to Next Disk
PUSH H ;Save Ptr
ANI 7FH ;Mask User Number
MOV C,A ;User in C for now
LDA CINDIC ;Compare to Current Indicator
CMP C ;See if Current User
JRNZ INPATH2 ;Good User In C
LDA CUSER ;User Current User
MOV C,A ;User in C
INPATH2:
MOV E,B ;Select Disk
PUSH B ;Save User in C
CPM DSK ;Set Disk
POP D ;Get User in E
CPM USR ;Set User
CPM DIR,LBRFIL ;See if File Exists in this Directory
POP H ;Restore Path Pointer
INR A ;Error Code (Not Found) is Zero
JRZ INPATH ;Continue Thru Path
DIROPN:
CPM OPN,LBRFIL ;Open for directory read.
DIROK:
CPM DMA,TBUFF ;Set DMA for Block Read
FINDMBR:
CPM FRD,LBRFIL ;Read the directory
ORA A
JNZ FISHY ;Empty file, Give up.
LXI H,TBUFF
MOV A,M
ORA A
JNZ FISHY ;Directory not active??
MVI B,8+3 ;Check for blanks
MVI A,' '
VALIDLOOP:
INX H
CMP M
JNZ FISHY
DCR B
JRNZ VALIDLOOP
;
LHLD TBUFF+1+8+3 ;Index must be 0000
MOV A,H
ORA L
JNZ FISHY
;
LHLD TBUFF+1+8+3+2 ;Get directory size
DCX H ;We already read one.
PUSH H ;Save on stack
JR FINDMBRN ;Jump into loop
FINDMBRL:
POP H ;Read sector count from TOS
MOV A,H
ORA L ;0 ?
JZ NOMEMB ;Member not found in library
DCX H ;Count down
PUSH H ;and put it back.
CPM FRD,LBRFIL ;Get next directory sector
ORA A
JNZ FISHY
FINDMBRN:
LXI H,TBUFF ;Point to buffer.
MVI C,128/32 ;Number of directory entries
;
FINDMBR1:
CALL COMPARE ;Check if found yet.
JZ GETLOC ;Found member in .DIR
DCR C
JRZ FINDMBRL
;
LXI D,32 ;No match, point to next one.
DAD D
JR FINDMBR1
;
GETLOC: ;The name was found now get index and length
POP B ;Clear stack garbage
XCHG ;Pointer to sector address.
MOV E,M ;Get First
INX H
MOV D,M
XCHG
SHLD INDEX ;Save it
XCHG
INX H ;Get Size to DE
MOV E,M
INX H
MOV D,M
XCHG ; Size to HL
SHLD LENX
CALL PACKUP ;Repack command line arguments
CPM CON,CR ;do <cr> only (look like CCP)
RET
; End of setup.
;
; Utility subroutines
NEGDE: ;DE = -DE
MOV A,D
CMA
MOV D,A
;
MOV A,E
CMA
MOV E,A
INX D
RET
;
; REPARSE re-parses the fcbs from the command line,
; to allow the "-" character to prefix the library name
;
REPARS:
LXI D,MEMBER ;first reinitialize both fcbs
CALL NITF
LXI D,LBRFIL
CALL NITF
LXI H,TBUFF ;store a null at the end of
MOV E,M ; the command line (this is
MVI D,0 ; done by CP/M usually, except
XCHG ; in the case of a full com-
DAD D ; mand line
INX H
MVI M,0
XCHG ;tbuff pointer back in hl
SCANBK:
INX H ;bump to next char position
MOV A,M ;fetch next char
ORA A ;reached a null? (no arguments)
JZ HELP ;interpret as a call for help
CPI ' ' ;not null, skip blanks
JRZ SCANBK
CPI '-' ;library name specifier?
JRNZ NOTLBR ;skip if not
INX H ;it is, skip over flag character
LXI D,LBRFIL ;parse library name into FCB
CALL GETFN
NOTLBR:
LXI D,MEMBER ;now parse the command name
CALL GETFN
LXI D,HOLD+1 ;pnt to temp storage for rest of cmd line
MVI B,-1 ;init a counter
CLSAVE:
INR B ;bump up counter
MOV A,M ;fetch a char
STAX D ;move it to hold area
INX H ;bump pointers
INX D
ORA A ;test whether char was a terminator
JRNZ CLSAVE ;continue moving line if not
MOV A,B ;it was, get count
STA HOLD ;save it in hold area
RET
;
; PACKUP retrieves the command line stored at
; HOLD and moves it back to tbuff, then reparses
; the default file control blocks so the command
; will never know it was run from a library
;
PACKUP:
LXI H,HOLD ;point to length byte of HOLD
MOV C,M ;get length in BC
MVI B,0
INX B ;bump up to because length byte doesn't
INX B ; include itself or null terminator
BLKMOV TBUFF ;moving everybody to Tbuff
LXI H,TBUFF+1 ;point to the command tail
LXI D,TFCB1 ;first parse out tfcb1
CALL GETFN
LXI D,TFCB2 ;then tfcb2
CALL GETFN
RET
;
; Here when HELP is requested (indicated
; by LRUN with no arguments)
;
HELP:
CPM MSG,HLPMSG ;print the HELP message
EXIT:
LHLD SPSAVE ;find CCP re-entry adrs
SPHL ;fix & return
RET
;
; the HELP message
;
HLPMSG:
DB CR,LF,'Correct syntax is:'
DB CR,LF
DB LF,TAB,'LRUN [-<lbrname>] <command line>'
DB CR,LF
DB LF,'Where <lbrname> is the optional library name'
DB CR,LF,'(Note the preceding "-". ) If omitted,'
DB CR,LF,'the default command library is used.'
DB LF
DB CR,LF,'<command line> is the name and parameters'
DB CR,LF,'of the command being run from the library,'
DB CR,LF,'just as if a separate .COM file were being run.'
DB CR,LF,'$'
;
;
COMPARE: ;Test status, name and type of
PUSH H ;a directory entry.
MVI B,1+8+3
XCHG ;with the one we're
LXI H,MEMBER ;looking for.
COMPAR1:
LDAX D
CMP M
JRNZ COMPEXIT
INX D
INX H
DCR B
JRNZ COMPAR1
COMPEXIT: ;Return with DE pointing to
POP H ;last match + 1, and HL still
RET ;pointing to beginning.
;
;
; File name parsing subroutines
;
; getfn gets a file name from text pointed to by reg hl into
; an fcb pointed to by reg de. leading delimeters are
; ignored.
; entry hl first character to be scanned
; de first byte of fcb
; exit hl character following file name
;
;
;
GETFN:
CALL NITF ;init 1st half of fcb
CALL GSTART ;scan to first character of name
RZ ;end of line was found - leave fcb blank
CALL GETDRV ;get drive spec. if present
CALL GETPS ;get primary and secondary name
RET
;
; nitf fills the fcb with dflt info - 0 in drive field
; all-blank in name field, and 0 in ex,s1,s2 and rc flds
;
NITF:
PUSH D ;save fcb loc
XCHG ;move it to hl
MVI M,0 ;zap dr field
INX H ;bump to name field
MVI B,11 ;zap all of name fld
NITLP1:
MVI M,' '
INX H
DJNZ NITLP1
MVI B,4 ;zero others
NITLP2:
MVI M,0
INX H
DJNZ NITLP2
XCHG ;restore hl
POP D ;restore fcb pointer
RET
;
; gstart advances the text pointer (reg hl) to the first
; non delimiter character (i.e. ignores blanks). returns a
; flag if end of line (00h or ';') is found while scaning.
; exit hl pointing to first non delimiter
; a clobbered
; zero set if end of line was found
;
GSTART:
CALL GETCH ;see if pointing to delim?
RNZ ;nope - return
CPI ';' ;end of line?
RZ ;yup - return w/flag
ORA A
RZ ;yup - return w/flag
INX H ;nope - move over it
JR GSTART ;and try next char
;
; getdrv checks for the presence of a drive spec at the text
; pointer, and if present formats it into the fcb and
; advances the text pointer over it.
; entry hl text pointer
; de pointer to first byte of fcb
; exit hl possibly updated text pointer
; de pointer to second (primary name) byte of fcb
;
GETDRV:
INX D ;point to name if spec not found
INX H ;look ahead to see if ':' present
MOV A,M
DCX H ;put back in case not present
CPI ':' ;is a drive spec present?
RNZ ;nope - return
MOV A,M ;yup - get the ascii drive name
SUI 'A'-1 ;convert to fcb drive spec
DCX D ;point back to drive spec byte
STAX D ;store spec into fcb
INX D ;point back to name
INX H ;skip over drive name
INX H ;and over ':'
RET
;
; getps gets the primary and secondary names into the fcb.
; entry hl text pointer
; exit hl character following secondary name (if present)
;
GETPS:
MVI C,8 ;max length of primary name
CALL GETNAM ;pack primary name into fcb
MOV A,M ;see if terminated by a period
CPI '.'
RNZ ;nope - secondary name not given
;return default (blanks)
INX H ;yup - move text pointer over period
FTPOINT:
MOV A,C ;yup - update fcb pointer to secondary
ORA A
JRZ GETFT
INX D
DCR C
JR FTPOINT
GETFT:
MVI C,3 ;max length of secondary name
CALL GETNAM ;pack secondary name into fcb
RET
;
; getnam copies a name from the text pointer into the fcb for
; a given maximum length or until a delimiter is found, which
; ever occurs first. if more than the maximum number of
; characters is present, characters are ignored until a
; a delimiter is found.
; entry hl first character of name to be scaned
; de pointer into fcb name field
; c maximum length
; exit hl pointing to terminating delimiter
; de next empty byte in fcb name field
; c max length - number of characters transfered
;
GETNAM:
CALL GETCH ;are we pointing to a delimiter yet?
RZ ;if so, name is transfered
INX H ;if not, move over character
CPI '*' ;ambigious file reference?
JRZ AMBIG ;if so, fill the rest of field with '?'
STAX D ;if not, just copy into name field
INX D ;increment name field pointer
DCR C ;if name field full?
JRNZ GETNAM ;nope - keep filling
JR GETDEL ;yup - ignore until delimiter
AMBIG:
MVI A,'?' ;fill character for wild card match
QFILL:
STAX D ;fill until field is full
INX D
DCR C
JRNZ QFILL ;fall thru to ingore rest of name
GETDEL:
CALL GETCH ;pointing to a delimiter?
RZ ;yup - all done
INX H ;nope - ignore antoher one
JR GETDEL
;
; getch gets the character pointed to by the text pointer
; and sets the zero flag if it is a delimiter.
; entry hl text pointer
; exit hl preserved
; a character at text pointer
; z set if a delimiter
;
GETCH:
MOV A,M ;get the character
CPI '.'
RZ
CPI ','
RZ
CPI ';'
RZ
CPI ' '
RZ
CPI ':'
RZ
CPI '='
RZ
CPI '<'
RZ
CPI '>'
RZ
ORA A ;Set zero flag on end of text
RET
;
;
; Error routines:
;
NODIR:
CALL ABEND
DB 'Library not found'
DB '$'
FISHY:
CALL ABEND
DB 'Name after "-" isn''t a library'
DB '$'
NOMEMB:
LXI H,MEMBER+1 ;Pt to first char of Command Name
MVI B,8 ;Print 8 Chars
NOMEMBL:
MOV E,M ;Print Char
INX H ;Pt to Next
PUSH H ;Save Ptr and Count
PUSH B
CPM CON
POP B
POP H
DJNZ NOMEMBL
CALL ABEND1 ;No Initial New Line
DB ' -- Command not in directory'
DB '$'
NOLOAD:
CALL ABEND
DB 'No program in memory'
DB '$'
NOFIT:
POP B ;Clear Stack
CALL ABEND
DB 'Program too large to load'
DB '$'
;
COMLIT:
DB 'COM'
;
ABEND:
CPM MSG,NEWLIN
ABEND1:
POP D
CPM MSG
CPM DEL,SUBFILE
CPM MSG,ABTMSG
JMP EXIT
ABTMSG:
DB ' -- Aborting$'
NEWLIN:
DB CR,LF,'$'
CDISK:
DS 1 ;CURRENT DISK BUFFER
CUSER:
DS 1 ;CURRENT USER BUFFER
SPSAVE:
DS 2 ;stack pointer save
;
PAGE
;Adjust location counter to next 256-byte boundry
@BASE ORG ($ + 0FFH) AND 0FF00H
@RLBL SET 0
;
; The segment to be relocated goes here.
; Any position dependent (3-byte) instructions
; are handled by the "R" macro.
;*************************************************
;
PUSH B ;Save Original User/Disk
R <LHLD LENX> ;Get length of .COM member to load.
MVI A,TPA/128
ADD L ;Calculate highest address
MOV L,A ;To see if it will fit in
ADC H ;available memory
SUB L
MOV H,A
REPT 7
DAD H
ENDM
XCHG
CALL NEGDE ;IT'S STILL IN LOW MEMORY
R <LXI H,PROTECT>
DAD D
JNC NOFIT ;Haven't overwritten it yet.
;
; The library file is still open. The open FCB has been
; moved up here into high memory with the loader code.
;
LBROPN:
R <LHLD INDEX> ;Set up for random reads
R <SHLD RANDOM>
XRA A
R <STA RANDOM+2>
;
LXI H,TPA
R <SHLD LOADDR>
;
; This high memory address and above, including CCP, must be
; protected from being overlaid by loaded program
;
PROTECT:
;
LOADLOOP: ;Load that sucker.
R <LHLD LENX> ;See if done yet.
MOV A,L
ORA H
JRZ LOADED
DCX H
R <SHLD LENX>
;
R <LHLD LOADDR> ;Increment for next time
MOV D,H
MOV E,L
LXI B,80H
DAD B
R <SHLD LOADDR>
CPM DMA ;but use old value (DE)
;
R <LXI D,LBRFIL>
CPM RRD ;Read the sector
ORA A ;Ok?
JRNZ ERR ;No, bail out.
;
R <LHLD RANDOM> ;Increment random record field
INX H
R <SHLD RANDOM>
;
JR LOADLOOP ;Until done.
;
ERR:
MVI A,( JMP ) ;Prevent execution of bad code
STA TPA
LXI H,BOOT
SHLD TPA+1
;
R <LXI D,LDMSG>
CPM MSG
R <LXI D,SUBFILE> ;Abort SUBMIT if in progress
CPM DEL
LOADED:
CPM DMA,TBUFF ;Restore DMA adrs for user pgm
CPM CON,LF ;Turn up a new line on console
POP B ;Restore Current User/Disk
PUSH B ;Save it again
MOV E,B ;Restore Disk
CPM DSK ;Log In Disk
POP D ;E=USER
CPM USR ;Log In User
JMP TPA
;
LDMSG:
DB CR,LF,'Bad Load$'
INDEX:
DW 0
LENX:
DW 0
SUBFILE:
DB 1,'$$$ SUB',0,0,0,0
;If used, this FCB will clobber the following one.
;but it's only used on a fatal error, anyway.
LBRFIL:
DS 32 ;Name placed here at setup
DB 0 ;Normal FCB plus...
OVERLAY SET $ ;(Nothing past here but DS's)
RANDOM:
DS 3 ;...Random access bytes
MAXMEM:
DS 2
LOADDR:
DS 2
;*************************************************
;End of segment to be relocated.
IF OVERLAY EQ 0
OVERLAY SET $
ENDIF
;
PAGES EQU ($-@BASE+0FFH)/256+8
;
SEGLEN EQU OVERLAY-@BASE
ORG @BASE+SEGLEN
PAGE
; Build the relocation information into a
; bit table immediately following.
;
@X SET 0
@BITCNT SET 0
@RLD SET ??R1
@NXTRLD SET 2
RGRND %@RLBL+1 ;define one more label
;
REPT SEGLEN+8
IF @BITCNT>@RLD
NXTRLD %@NXTRLD ;next value
ENDIF
IF @BITCNT=@RLD
@X SET @X OR 1 ;mark a bit
ENDIF
@BITCNT SET @BITCNT + 1
IF @BITCNT MOD 8 = 0
DB @X
@X SET 0 ;clear hold variable for more
ELSE
@X SET @X SHL 1 ;not 8 yet. move over.
ENDIF
ENDM
;
DB 0
HOLD:
DB 0,0 ;0 length, null terminator
DS 128-2 ;rest of HOLD area
MEMBER:
DS 16
;
END CCPIN