title 'MAKE Utility RSX for CP/M Plus'
FALSE equ 0
TRUE equ NOT FALSE
EOF equ 1AH
CR equ 13
LF equ 10
TAB equ 9
; BDOS function calls
WBOOT equ 0 ; warm boot
CONOUT equ 2 ; output char to console
PRINTS equ 9 ; print string at console
RDCON equ 10 ; read console input buffer
CLOSEF equ 16 ; close disk file
SFIRST equ 17 ; search for first file match
READSQ equ 20 ; read sequential sector
SETDMA equ 26 ; set DMA address
SETUSR equ 32 ; set/get user number
SETMUL equ 44 ; set multi-sector-count
GETSCB equ 49 ; get/set system control block
GETPRC equ 108 ; get/set program return code
PARFCB equ 152 ; parse file name into FCB
cseg
; RSX- Header
serial: db 0,0,0,0,0,0
start: jmp ftest ; start of program
next: jmp 0 ; link to next RSX in chain
prev: dw 0 ; link to prev. RSX in chain
remove: db TRUE ; remove RSX on warm start (altered by MAKE.COM)
nonbank: db FALSE ; load in every CP/M Plus system
rname: db 'MAKERSX ' ; name of RSX (tested by MAKE.COM)
loader: db 0,0,0 ; reserved for LOADER module usage
; FCB of make file
make$fcb: ds 36 ; filled in from MAKE.COM
make$user: ds 1 ; "
; filter for BDOS 10 : read console input
ftest: mvi a,RDCON ; is it read console buffer ?
cmp c
jnz next ; no : jump to next RSX in chain
mov a,e ; is prewritten input used ?
ora d
jz next ; skip RSX, cannot handle, CCP don't use it
lda remove ; is RSX active ?
ora a
jnz next ; no: skip RSX (waiting for removal)
xchg ; save address of console buffer
shld rdcon$addr
mvi c,GETSCB ; is ccp executing ? (bit7 of 18H in SCB set)
lxi d,test$ccp
call next
ora a
jm trap$rdcon ; yes: trap RDCON call
; unfiltered BDOS 10 call
origin: lhld rdcon$addr ; restore registers
xchg
mvi c,RDCON
jmp next ; and reach call to next RSX in chain
; process valid read console call
trap$rdcon: mvi c,GETPRC ; get program return code
lxi d,0FFFFH ; ( NOT reset in CCP so far )
call next
inr h ; H = 0FFH?
jz abort$make ; because of faulty program execution
; save BDOS DMA address
mvi c,GETSCB ; get entry in SCB
lxi d,scb$dma
call next
shld user$dma ; because we need it
; save current user number
mvi c,SETUSR
mvi e,0FFH ; get user number code
call next
sta default$user
; get drive search chain out of SCB
mvi c,GETSCB
lxi d,scb$drive12
call next
shld drive1
mvi c,GETSCB
lxi d,scb$drive34
call next
shld drive3
; execute or skip subsequent command lines
test$next: call getc ; read char from make file
cpi EOF ; end of file reached ?
jz make$end ; yes: terminate make normaly
cpi ' ' ; space or TAB ?
jz test$condition ; yes: execute or skip tabbed line
cpi TAB
jz test$condition
cpi 20H ; other control char ?
jc test$next ; skip it
call ungetc ; char back into make file
; read object file name from makefile
make$next: mvi a,FALSE ; clear make-flag (default := no operation)
sta make$flag
sta EOL$flag ; end of line of make file not reached
sta EOF$flag ; end of make file not reached
call read$name ; read file name into name buffer
lda EOF$flag ; end of file ?
ora a
jz make$next1
lda name$buffer ; and name buffer empty ?
ora a
jz make$end ; yes: terminate make rsx
jmp EOF$error ; no : rapport EOF error
make$next1: lda name$buffer ; test first char of name buffer
ora a
jz test$next ; skip empty line
lda EOL$flag ; (unexpected) end of input line after file name?
ora a
jnz format$error ; yes: bad formatted make file
call parse$name ; parse file name into RSX$FCB
ora a ; parse error ?
jnz format$error ; yes: bad formatted make file
call search$first ; try to find this file
cpi 3 ; file not found or no time stamps ?
jnc make$object ; yes: make file
lda RSX$DMA+96 ; valid time stamp ?
cpi 21H
jnz make$object ; no: make file anyway
call get$date ; get date out of directory record (BC=date,DE=time)
mov a,b ; date =0 ? (stamp inactive)
ora c
jz make$object ; make file anyway
lxi h,obj$date ; store date & time of object file
mov m,c ; BC = date
inx h
mov m,b
inx h
mov m,d ; D = hour
inx h
mov m,e ; E = minute
jmp make$colon ; read colon after object filename
make$object: call set$makef ; set make flag
; read colon from makefile
make$colon: call read$name ; read over ':'
lda EOF$flag ; unexpected end of file ?
ora a
jnz EOF$error ; rapport error
lda name$buffer ; name buffer contains ':' ?
cpi ':'
jnz format$error ; no: bad formatted make file
lda EOL$flag ; (unexpected) end of input line after colon?
ora a
jnz format$error ; yes: bad formatted make file
; read list of dependency files
depend$list: lda EOL$flag ; end of input line reached ?
ora a
jnz test$condition ; yes: execute line if make$flag is set
call read$name ; read next file name
lda EOF$flag ; unexpected end of file ?
ora a
jnz EOF$error ; rapport error
lda name$buffer ; name buffer empty (=empty rest of line) ?
ora a
jz test$condition ; test & execute make line
call parse$name ; parse file name into RSX$FCB
ora a ; parse error ?
jnz format$error ; yes: bad formatted make file
lda make$flag ; nesessary to test file ?
ora a
jnz depend$list
call search$first ; try to find this file
cpi 0FFH ; file found ?
jnz test$date
lda RSX$FCB ; no: drive specified ?
ora a
jnz not$found ; ERROR: file not found, abort make
test$1: lda drive1 ; first drive in search chain
cpi 0FFH ; empty ?
jz test$2
ora a ; default drive ?
jz test$2
sta RSX$FCB ; drive ID into FCB
call search$first ; try to find this file
cpi 0FFH ; file found ?
jnz test$date
test$2: lda drive2 ; second drive in search chain
cpi 0FFH ; empty ?
jz test$3
ora a ; default drive ?
jz test$3
sta RSX$FCB ; drive ID into FCB
call search$first ; try to find this file
cpi 0FFH ; file found ?
jnz test$date
test$3: lda drive3 ; third drive in search chain
cpi 0FFH ; empty ?
jz test$4
ora a ; default drive ?
jz test$4
sta RSX$FCB ; drive ID into FCB
call search$first ; try to find this file
cpi 0FFH ; file found ?
jnz test$date
test$4: lda drive4 ; fourth drive in search chain
cpi 0FFH ; empty ?
jz not$found
ora a ; default drive ?
jz not$found
sta RSX$FCB ; drive ID into FCB
call search$first ; try to find this file
cpi 0FFH ; file found ?
jz not$found
test$date: cpi 3 ; directory without stamp ?
jz obj$older ; yes : set make flag
call get$date ; get date & time of dep. file
mov a,b ; stamp inactive ?
ora c
jz obj$older
lxi h,obj$date+1 ; compare with date & time of object file
mov a,m ; obj.date - dep.date
sub b ; high byte first
jc obj$older
jnz depend$list
dcx h ; then low byte
mov a,m
sub c
jc obj$older ; than dep. list
jnz depend$list ; object younger than dep. :
inx h ; obj.time - dep.time
inx h
mov a,m ; A = hour
sub d
jc obj$older ; than dep. list
jnz depend$list ; object younger than dep. :
inx h
mov a,m ; A = minute
sub e
jc obj$older ; than dep. list
jnz depend$list ; object younger than dep. :
obj$older: call set$makef ; set make flag
jmp depend$list ; continue with parsing
; test make$flag and execute/skip make command line
test$condition: lda make$flag ; is make$flag set ?
ora a
jz test$false
test$true: lhld rdcon$addr ; copy line into RDCON buffer
mov c,m ; max. count
inx h
inx h
mvi b,0
skip$loop: push b
push h
call getc ; into a
pop h
pop b
cpi CR ; end of line ?
jz term$line
cpi EOF
jz eof$line
cpi 21H
jc skip$loop
jmp insert$char
line$loop: push b
push h
call getc ; into a
pop h
pop b
cpi CR ; end of line ?
jz term$line
cpi EOF
jz eof$line
insert$char: mov m,a
mvi a,TRUE ; valid command line assumed
sta execute$flag
inx h
inr b
dcr c
jnz line$loop
term$line: lhld rdcon$addr ; store char count in buffer
inx h
mov m,b
inx h ; HL points to first buffer char
out$loop: mov e,m
push b
push h
mvi c,CONOUT
call next
pop h
pop b
inx h
dcr b
jnz out$loop
mvi c,CONOUT ; display cr
mvi e,CR
call next
call restore$dma
ret
eof$line: call set$remove ; this is the last call
jmp term$line
test$false: call getc ; get char in A
cpi EOF
jz make$end
cpi CR
jnz test$false
jmp test$next ; try next line of make file
; normal end of make file
make$end: lda execute$flag ; is at least one line executed ?
ora a
cz disp$done
call restore$dma
call set$remove
jmp origin ; original CCP RDCON call
; restore user dma address
restore$dma: mvi c,SETDMA ; set dma address to old value
lhld user$dma
xchg
call next
ret
; set remove flag in RSX
set$remove: mvi a,TRUE
sta remove
ret
; one character from back into make file
ungetc: sta char$store ; save char
mvi a,TRUE ; set flag
sta char$flag
ret
; read a character from make file into
getc: lda char$flag ; waiting char from ungetc ?
ora a
jnz getc$store ; yes : read char from storage
lda make$index ; index into record buffer
ora a ; exhausted
jm getc$more
mov e,a ; -> DE
mvi d,0
lxi h,MAKE$DMA
dad d ; HL points into make dma buffer
inr a ; update index
sta make$index
mov a,m ; char into
cpi EOF ; last char ?
rnz
getc$eof: mvi c,SETUSR ; set user number of make file
lda make$user
mov e,a
call next
mvi c,CLOSEF ; close make file
lxi d,MAKE$FCB
call next
mvi c,SETUSR ; restore default user number
lda default$user
mov e,a
call next
mvi a,EOF ; return EOF to caller
ret
getc$more: mvi c,SETDMA ; set DMA address to makefile buffer
lxi d,MAKE$DMA
call next
mvi c,GETSCB ; get active multi-sector-count
lxi d,scb$multio
call next
sta multio
mvi c,SETMUL ; reset multi-sector count
mvi e,1
call next
mvi c,SETUSR ; set user number of make file
lda make$user
mov e,a
call next
mvi c,READSQ ; read next sector of make file
lxi d,MAKE$FCB
call next
push psw
mvi c,SETUSR ; restore default user number
lda default$user
mov e,a
call next
mvi c,SETMUL
lda multio
mov e,a
call next
pop psw
ora a ; end of file ?
jnz getc$eof
sta make$index ; reset make file index
jmp getc ; try once again
getc$store: mvi a,FALSE ; clear storage flag
sta char$flag
lda char$store
ret
; abort MAKE:
abort$make: mvi c,PRINTS ; send error msg
lxi d,abort$msg
call next
abort$close: call getc$eof ; close make file
abort: call set$remove
mvi c,WBOOT
jmp next
EOF$error: mvi c,PRINTS ; send error msg
lxi d,EOF$msg
call next
jmp abort
disp$done: mvi c,PRINTS
lxi d,done$msg
jmp next
format$error: mvi c,PRINTS
lxi d,format$msg
call next
jmp abort$close
not$found: mvi c,PRINTS
lxi d,found$msg
call next
jmp abort$close
; read a sequence of characters from make file
read$name: lxi h,name$buffer ; let HL point into (empty) name buffer
mvi b,29 ; number of free chars in buffer
skip$lead$sp: push b ; save B, HL
push h
call getc ; from make file into A
pop h
pop b
cpi EOF ; end of file ?
jz read$name$EOF
cpi CR ; end of line ?
jz read$name$EOL
cpi 21H ; space or other control char ?
jc skip$lead$sp
cpi '\' ; line extender ?
jz skip$EOL
cpi ';' ; comment-line ?
jz skip$EOL
store$char: mov m,a ; store into buffer
inx h
dcr b ; free chars -1
jz format$error
next$char: push b
push h
call getc ; read subsequent chars
pop h
pop b
cpi EOF ; end of file ?
jz read$name$EOF
cpi CR ; end of line ?
jz read$name$EOL
cpi TAB ; tabulator ?
jz read$name$end
cpi 20H ; space ?
jz read$name$end
jc next$char ; skip control characters
cpi '\'
jz skip$EOL
jmp store$char ; else store character into buffer
read$name$EOF: mvi a,TRUE ; set EOF-Flag
sta EOF$flag
read$name$EOL: mvi a,TRUE ; set EOL-Flag
sta EOL$flag
read$name$end: mvi m,0 ; append NUL delimiter
ret
skip$EOL: push b ; save B, HL
push h
call getc ; from make file into A
pop h
pop b
cpi EOF ; end of file ?
jz read$name$EOF
cpi CR ; end of line ?
jz skip$lead$sp
jmp skip$EOL
; parse a filename in name buffer into RSX$FCB
parse$name: lxi h,name$buffer ; leading user number ?
mvi b,0 ; character count
search$colon: mov a,m ; colon ?
cpi ':'
jz colon$found
inx h
inr b
ora a ; end of buffer ?
jnz search$colon
set$default: lda default$user ; file user number = actual user number
sta RSX$user
lxi h,name$buffer ; parse from beginning
shld pfcb
jmp parse$file
colon$found: shld pfcb ; start parsing at first non-digit char
dcx h ; test char before colon
dcr b
jm set$default ; nothing before colon
mov a,m ; digit ?
sui '0'
jc colon$found
cpi 10
jnc colon$found
mov c,a ; store digit in c
dcx h ; test char before digit ?
dcr b
jm store$user ; nothing before this digit
mov a,m ; digit ?
sui '0'
jc parse$wrong ; no: format error
cpi 10
jnc parse$wrong
add a ; A := A * 10
mov b,a
add a
add a
add b
add c ; + c
mov c,a
store$user: lxi h,RSX$user ; store user number of tested file
mov m,c
parse$file: lhld pfcb ; skip colon
mov a,m
cpi ':'
jnz parse$it
inx h
shld pfcb
parse$it: mvi c,PARFCB ; parse filename
lxi d,pfcb
call next
mov a,l ; MUST be end code (HL=0)
ora h
ret
parse$wrong: mvi a,TRUE
ret
; search a file in RSX$FCB in directory
search$first: lxi h,RSX$FCB+1 ; check to find ? in file name/type
mvi a,'?'
mvi b,11
check$loop: cmp m ; '?' ?
jz ambig$error ; is not allowed in any file name
inx h
dcr b
jnz check$loop
search$next: mvi c,SETDMA
lxi d,RSX$DMA
call next
mvi c,SETUSR
lda RSX$user
mov e,a
call next
mvi c,SFIRST ; try to find this file
lxi d,RSX$FCB
call next
sta dir$index
mvi c,SETUSR
lda default$user
mov e,a
call next
lda dir$index
ret
ambig$error: mvi c,PRINTS
lxi d,ambig$msg
call next
jmp abort$close
; get update date&time stamp out of directory record
get$date: lda dir$index ; MUST be 0..2
add a ; * 10
mov b,a
add a
add a
add b
mov e,a
mvi d,0
lxi h,RSX$DMA+101
dad d ; HL points to update stamp
mov c,m ; BC := date
inx h
mov b,m
mov a,c ; valid stamp ?
ora b
cz get$create ; no:try create stamp
inx h
mov d,m ; D := hour
inx h
mov e,m ; E := minute
; call out$date
ret
get$create: lxi d,-5 ; to begin of create subfield
dad d
mov c,m ; BC := date
inx h
mov b,m
ret
;out$date: push b
; push d
; mvi a,' '
; call out$c
; pop d
; pop b
; push b
; push d
; mov a,b
; call out$hex
; pop d
; pop b
; push b
; push d
; mov a,c
; call out$hex
; mvi a,' '
; call out$c
; pop d
; pop b
; push b
; push d
; mov a,d
; call out$hex
; mvi a,':'
; call out$c
; pop d
; pop b
; push b
; push d
; mov a,e
; call out$hex
; pop d
; pop b
; ret
;
;out$hex: push psw
; rlc
; rlc
; rlc
; rlc
; call out$nib
; pop psw
;
;out$nib: ani 0Fh
; adi '0'
; cpi '9'+1
; cnc add$nib
;
;out$c: mvi c,CONOUT
; mov e,a
; jmp next
;
;add$nib: adi 'A'-'9'-1
; ret
; set make flag
set$makef: mvi a,TRUE
sta make$flag
sta execute$flag
ret
; data area :
scb$multio: db 4AH ; multi-sector count
db 0
scb$drive12: db 4CH ; get drive 1,2
db 0
scb$drive34: db 4EH ; get drive 3,4
db 0
test$ccp: db 18H ; offset of ccp running flag
db 0
scb$dma: db 3CH ; offset of current DMA address
db 0
pfcb: dw name$buffer ; address of name buffer
dw RSX$FCB ; address of directory FCB
make$index: db 128 ; index into make file record
make$flag: db FALSE ; is TRUE if make condition satisfied
execute$flag: db FALSE ; set if at least one make line executed
char$flag: db FALSE ; set if character waiting in char$store
abort$msg: db 'MAKE aborted by unsuccessfull program return',13,10,'$'
ambig$msg: db 'MAKE aborted by ambiguous file name',13,10,'$'
format$msg: db 'MAKE aborted by bad format of make file',13,10,'$'
EOF$msg: db 'MAKE aborted by wrong end of make file',13,10,'$'
found$msg: db 'MAKE aborted because file not found',13,10,'$'
done$msg: db 'DONE>$'
char$store: ds 1 ; waiting char for getc
rdcon$addr: ds 2 ; holds address of read console buffer
user$dma: ds 2 ; holds address of users dma buffer
name$buffer: ds 30 ; buffer for CP/M Plus filename
RSX$FCB: ds 36 ; FCB for directory search
RSX$DMA: ds 128 ; dma buffer for directory operations
MAKE$DMA: ds 128 ; dma buffer for make file
dir$index: ds 1 ; contains directory index from last SFIRST
obj$date: ds 2 ; date of object file
obj$time: ds 2 ; time of object file
EOF$flag: ds 1 ; TRUE if end of makefile reached
EOL$flag: ds 1 ; TRUE if end of line in makefile reached
drive1: ds 1 ; drive search chain
drive2: ds 1
drive3: ds 1
drive4: ds 1
multio: ds 1 ; multi-sector-count
default$user: ds 1 ; default (ccp) user number
RSX$user: ds 1 ; user number of currently parsed file
end