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