;RAP.ASM Reroute all printer data into a diskfile. ;3/07/88 ; Copyright 1988, Logic Associates ; 1433 W. Thome, Chicago, IL 60660 ; ; Permission is hereby granted only for ; non-profit copying and distribution. ; All other rights reserved. ; vers equ 10h ;Version 1.0 ; ;-------------------------------------------------------- ; ; [] For CP/M 2.2. (Not tested with CP/M+.) ; ;==> [] Instructions on re-assembling RAP.ASM are in RAP.DOC. ; PLEASE READ THEM before attempting to re-assemble. ; ------ ---- ---- ; ;-------------------------------------------------------- if copy1 ********************************************************* * service/loader routines * ********************************************************* org 100h jmp begin ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; buffk equ 1 ;printer buffer size in K (1 - 32). no equ 0 yes equ 255 version db vers oldver db 0 ;version of already-installed (if any) RAP. pgplus6 db no ;force load point of module ; to page boundary+6? loadpnt dw 0 ;entry to module after loading. xtobdos dw 0 ;RAP exit target. bdosent dw 0 ;entry point to bdos. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;variables below this point need not be changed ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;equates reopen db no ;did log file already exist? progcode equ 'R' ;code that helps test if RAP already installed. boot equ 0 ;lowest address within CP/M bdos equ boot+5 ;bdos jump vector. fcb equ boot+5ch filsize equ fcb+33 tbuff equ boot+80h ;default buffer. fchrn equ 2 ;normal console out. flist equ 5 ;list to printer. fchrd equ 6 ;direct console i/o. pstr equ 9 ;print string. gvers equ 12 ;get version number. fdrst equ 13 ;disk reset. fslct equ 14 ;select disk. fopen equ 15 ;open file. fclos equ 16 ;close. fsrc1 equ 17 ;search first fsrc2 equ 18 ;search next fdelt equ 19 ;delete freds equ 20 ;read seq. fwseq equ 21 ;write seq. fmake equ 22 ;create frenm equ 23 ;rename. flogv equ 24 ;get login vector. fgetd equ 25 ;get disk name. fsdma equ 26 ;set dma frrov equ 29 ;get r/o vector. fattr equ 30 ;set file attr. fuser equ 32 ;set/get user. frran equ 33 ;read ran. fwran equ 34 ;write ran. fsize equ 35 ;compute file size. fwrnz equ 40 ;write ran with zero fill. wboff equ 03h ;displacement from bios start to various vecs. coutoff equ 0ch lsoff equ 0fh sdoff equ 24h dsoff equ 1bh ctlc equ 3 bell equ 7 bs equ 8 tab equ 9 cr equ 13 lf equ 10 ctlz equ 26 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;messages eom equ '$' mlogon db 0,0,0,0,0 ;leave room for "clear screen" string. db cr,lf db 'IIIIIIIIII IIIIIII IIIIIIIIII ',cr,lf db ' IIII IIII IIII III IIII IIII',cr,lf db ' IIII III IIII III IIII III',cr,lf db ' IIIIIIIIII IIIIIIIII IIIIIIIII ',cr,lf db ' IIII III IIII III IIII ',cr,lf db 'IIIIII IIII IIIII IIIII IIIIII ',cr,lf db cr,lf db 'Copyright 1988, Logic Associates, 60660',cr,lf db eom mlogon2: db 'RAP ' verloc: db 'x.x Installed at ' site1: db 'xxxx-' site2: db 'xxxx',cr,lf db cr,lf db 'Reroute/append printer data to a file. ',cr,lf db cr,lf db ' * Execute as-- RAP ',cr,lf db ' or as-- RAP filename ',cr,lf db cr,lf db ' * Creates file if absent. ',cr,lf db cr,lf db ' * De-installs itself at warmboot. ',cr,lf db '_______________________________________' db eom mnoccp db cr,lf db cr,lf db '** ABORT: Unable to locate CCP. ***' db bell,cr,lf,eom mbadcre: db cr,lf db cr,lf db '** ABORT: Cannot create printfile. ***' db bell,cr,lf,eom mdifver: db cr,lf db cr,lf db '*** ABORT: RAP versions conflict. ***' db bell,cr,lf,eom notinstm: db cr,lf db cr,lf db '** ABORT: Unknown error during install.' db bell,cr,lf,eom ;db '_______________________________________' ;39 chars. mstllon: db bell db ' already open on ' pdrive1: db 'A' punum1: db '00.*',cr,lf,eom ;db '* File PRINTER.LOG already open on A00.*' ;db '_______________________________________' ;39 chars. mreopnd: db ' reopened on ' pdrive2: db 'A' punum2: db '00. *',cr,lf,eom ;db '* File PRINTER.LOG reopened on A00. *' ;db '_______________________________________' ;39 chars. mopened: db ' opened on ' pdrive3: db 'A' punum3: db '00. *',cr,lf,eom ;db '* File PRINTER.LOG opened on A00. *' ;db '_______________________________________' ;39 chars. crlf: db cr,lf db eom ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;work areas bios dw 0 ;pointer to bios. ccp dw 0 ;pointer to ccp. ;values used in patching traps into bios jumptable. trapex dw 0 trapent dw 0 biosoff dw 0 deflt db 'PRINTER LOG' ;default print-file name. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; mainline ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; begin lxi h,0 dad sp shld stack lxi sp,stack call hskp ;initialize variables. jnz beginx ;error-free? no, quit. lda oldver ;is RAP being installed fresh? ora a cz install ; yes, install RAP. beginx: call dologon ;display logon message. lhld stack sphl ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; housekeeping ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;on exit, if error, z=no, (de)=error message. hskp: lxi d,mlogon ;display first part of logon message. call print xra a sta oldver ;clear version number of "old" RAP. lxi h,0 ;initialize for "CCP not found" msg. shld loadpnt lda fcb+1 ;print filename missing? sui ' ' cz defaultn ; yes, insert default name. call probe ;if RAP already active? jz hskp9 ; yes, exit. lhld boot+1 ;initialize bios pointer. call isbios ; 14 jmps in a row? jz hskp4 ; yes, that's bios. call isxsub ; no, test if XSUB is hiding it. call isbios lxi d,mnoccp ;bios found? jnz hskp9 ; no, abort. hskp4: shld bios call getload ;compute load address, validate if explicit. ; on return, if error, a<>0, z=no. hskp9: ret ; if error, z = "no" ;-------------------------------------------------- ;instert default name into fcb. defaultn: lxi b,11 lxi d,fcb+1 lxi h,deflt call move ret ;-------------------------------------------------- ;assume xsub is present: get real addr of true coldboot. ;on exit, if yes, hl = address of bios wboot entry. isxsub: lhld boot+1 dcx h ; get true warmboot into de, mov d,m dcx h mov e,m xchg ; then into hl. ret ;-------------------------------------------------- ;test if hl points to bios isbios dcx h dcx h dcx h push h lxi d,3 ;test from wboot to write disk. mvi c,14 isbios2: dad d mov a,m cpi jmp jz isbios4 cpi ret mvi a,1 jnz isbios9 isbios4: dcr c jnz isbios2 mov a,c isbios9: pop h ret ;if bios, z = yes, a=0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; compute load address ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;find bdos, then ccp, then adjust down for length of module. ;on exit, if error, z = no. getload: call locbdos ;find bdos. lxi b,mnoccp jnz getlod9 ; not found? abort. call locccp ;find ccp. lxi b,mnoccp jnz getlod9 ; not found? abort. lhld ccp ;point again to start of ccp. lda bdos+2 sub h ;ccp page < = address-5 page? jnc getlod1 ; yes, save ccp as tpatop lhld bdos+1 ; no, save location 5 as tpatop. getlod1: ;compute load point lxi d,-modlen dad d lda pgplus6 cpi no jz getlod2 lxi d,-6 dad d mvi l,6 getlod2: shld loadpnt ;tentative new loadpnt... lhld bdos+1 ; and tobdos. shld xtobdos xra a ;"no error" getlod9: ret ;on exit, z set. ;------------------------------------------------------- ;locate beginning instruction of bdos. ;on exit, if found, z = yes ; hl = bdos start (offset 6) locbdos: lhld bios lxi d,-100h mvi b,31h ;check for max of 3000h below bios locbd2: dcr b jz locbd6 ;exhausted search, no success: abort. mvi l,6 ;set for offset to bdos start. dad d ;compute bdos start shld bdosent ;save in case found mov a,m ;is this bdos location? cpi jmp ;at page plus 6, is there a "jmp"... jnz locbd2 inx h mov a,m cpi 11h jz locbd4 ; ...followed by an 11h (if CP/M)... ora a ; ...or a null (if bdos already patched)? jnz locbd2 ; no, try next lower page in memory. locbd4: mvi b,1 ; yes, set to "found" jmp locbd9 locbd6: lhld boot+6 ;points to offset 6? cpi 6 shld bdosent ; yes, assume it's bdos, since jz locbd4 ; other attempt failed. locbd9: dcr b ;set z flag to "yes" (found) or "no" (missing) mov a,b ret ;------------------------------------------------ ;check for ccp ;on exit, if ccp found, z = yes ; hl = ccpstart locccp: lhld bdosent mvi b,31h ;check no more than 3000h below bdos. lxi d,-100h loccp2: dcr b jz loccp9 mvi l,0 ;correct to bdos start. dad d ;advance to next lower page call isitjmp ;check for two jmp instructions. jnz loccp2 call isitjmp ;found? jnz loccp2 ; no, abort. call isitjmp ;a third found? jz loccp2 ; yes, abort. mvi l,0 ;correct to ccp start. shld ccp mvi b,1 ;set for "found" loccp9: dcr b ;set z flag. mov a,b ret ;--------------------------------------------------- ;check for jump instruction isitjmp: mov a,m cpi jmp inx h inx h inx h ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; install module ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;move it into place. ;if error, exit with z = no. install: call chgaddr ;convert to true addresses. call customz ;install runtime values. jnz installx ; exit if error call doprot ;patch this module in. call movemod ;move module to load address. call dopatch ;patch bios for moved module. call probe ;now detectably installed, as it should be? jz installx ; yes, exit. lxi d,notinstm ; no, say "unknown error." installx: ret ;if error, a<>0, z=no. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; convert module2 to true addresses ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; change pseudo addresses to true addresses chgaddr lxi b,loadlen lxi d,module2 lxi h,module1 truloop ldax d cmp m cnz convert inx h inx d dcx b mov a,b ora c jnz truloop ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; convert displacement into address ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; convert push b ;length of module not yet processed push h ;module1 character position ; get displacement from instruction, put into bc. ldax d mov b,a dcx d ldax d mov c,a lxi h,-module2 ;normalize displacement to zero dad b push h pop b lhld loadpnt ;add load point for true addr dad b ; move true address to instruction mov a,l stax d inx d mov a,h stax d pop h pop b ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; customize module2 at run time ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;on exit, if error, z = no, a<>0. customz: lxi h,0 shld fcb+12 shld fcb+14 shld fcb+16 call insertd ;insert drive name into module 2. call insertu ;insert user number into module 2. call tryreop ;file already there? mvi a,yes jz custmz4 ; yes, skip and say "reopened file." call trymake ;successful creation of new file? lxi d,mbadcre jnz custmzx ; no, abort mvi a,no ; yes, say "not reopened file." custmz4: sta reopen lxi b,36 lxi d,bfcb+module2 ;copy fcb to trap module. lxi h,fcb call move xra a ;no error custmzx: ret ;if error, a<>0, z=no. ;-------------------------------------------------- ;insert drive name into module 2. insertd: lda fcb sui 1 mvi c,fgetd ;get curdrv, put into fcb, if cc bdos ; fcb is asking for default drive. inr a sta fcb adi '@' ;store drive name in module. sta pdrive1 sta pdrive2 sta pdrive3 sta pdrive+module2 ret ;-------------------------------------------------- ;insert user number into module 2. insertu: mvi e,255 ;save current user number. mvi c,fuser ;(= user number for printfile). call bdos sta user+module2 mvi b,'0' ;default high-digit of unum. jmp instu6 instu4: inr b instu6: sui 10 ;unum < 10? jnc instu4 ; yes, skip adi 10+'0' ;compute low digit. mvi h,'.' ;initialize ascii unum, mov l,a ; in case unum < 10. mov a,b ;hi digit 0? cpi '0' mvi b,' ' jz instu8 ; yes, skip. mov h,l ; no, put it in front of lo digit. mov l,a mvi b,'.' instu8: shld punum+module2 ;update module 2. mov a,b sta punum+module2+2 shld punum1 ;update messages shld punum2 ; in loader section. shld punum3 sta punum1+2 sta punum2+2 sta punum3+2 ret ;-------------------------------------------------- ;reuse old log file, if any. tryreop: lxi d,fcb ;a successful reopen? mvi c,fopen call bdos ani 0f0h jnz tryreopx ; no, skip lxi d,fcb ;address the end of file. mvi c,fsize call bdos lhld filsize ;empty file? mov a,h ora l jz tryreopx ; yes, exit. dcx h shld filsize lxi d,fcb ; no, get last record in file. mvi c,frran call bdos lxi b,80h ;copy it to module2. lxi d,buffer+module2 lxi h,tbuff call move lxi h,buffer+module2 ;adjust buffer pointer mvi b,0 ; to point to terminal control-Z. tryreop4: mov a,m cpi ctlz ;got it? jz tryreop8 ; yes, skip. inx h inr b jp tryreop4 mvi m,ctlz ;make up for the missing control-z at end. tryreop8: mov l,b ;save the adjusted buffer-char pointer. mvi h,0 shld bptr+module2 xra a ;"file reopened". tryreopx: ret ;-------------------------------------------------- ;try to create a new log file. trymake: lxi d,fcb mvi c,fmake call bdos ani 0f0h ;successful? ret ;if yes, a=0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; set all traps ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;set trap for wboot (after module moved into place). dopatch: lxi b,trpwbx+1 ;warmboot vector. lxi d,trpwb lxi h,wboff call settrap lxi b,trpsdx+1 ;set-dma vector. lxi d,trpsd lxi h,sdoff call settrap lxi b,trplsx+1 ;list vector. lxi d,trpls lxi h,lsoff call settrap lxi b,trpdsx+1 ;drive select vector. lxi d,trpds lxi h,dsoff call settrap ret ;-------------------------------------------------------- ;set a trap ;on entry, bc=trapex ; de=trapent ; hl=biosoff settrap: shld biosoff xchg shld trapent mov h,b mov l,c shld trapex lhld loadpnt ;get address of moved module push h pop b ;save in bc lhld biosoff ;get displace for bios jmptable into de push h pop d ;get contents of bios jumptable entry lhld bios mvi l,0 dad d ;address bios jumptable entry inx h push h ;...save pointer to table entry mov e,m ;...and get contents inx h mov d,m ;store bios entry into trap savearea lhld trapex ;save bios contents into trap mod dad b mov m,e inx h mov m,d ;set bios entry to trap entry lhld trapent ;get addr of appropriate trap into de dad b xchg pop h ;store trap addr in bios jmptab mov m,e inx h mov m,d ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; move module into place ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; movemod: ;move module to load point. lxi b,loadlen+129 ;include potential last record of lhld loadpnt ; old prinfile + potential ctl-Z. xchg ;destination. lxi h,module2 ;source. call move ret ;-------------------------------------------------------- ;move block: source in hl, destination in de, length in bc. move0 mov a,m stax d inx d inx h dcx b move mov a,b ora c jnz move0 ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; install security, describe in message ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;move the new secured address to de, then store wherever needed ; secure the module doprot: lhld xtobdos shld tobdos+module2+1 lhld loadpnt shld bdos+1 ;protect module by altering location 5. xra a ;say "ok" ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; test if reinstallation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;is RAP already installed? ;on exit, if yes, z = yes, ; loadpnt is updated with addr of loaded module. probe: lxi d,0 ;initialize de to 0000. mvi c,flogv mvi b,progcode ;ask "RAP recursion?" call bdos ;"get login vector". mov a,d ;de still 0000? ora e ;("RAP uninstalled?") mvi a,1 jz probe9 ; yes, exit. xchg shld loadpnt mov a,b sta oldver ;save version number of old RAP. xra a ;say "already installed" probe9: ora a ret ;if z=yes, RAP installed. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; display messages ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; print0: push d call charout pop d inx d print: ldax d cpi eom jnz print0 ret ;.................................................... ;use direct console out, to allow ctrl-s. charout: ;display buffer char, save z-flag. ani 7fh mov e,a ;display the character. mvi c,fchrn call bdos ret ;.................................................... dologon: push psw call parm2m ;insert parmeters into logon message. lxi d,mlogon2 ;display logon message2. call print pop psw ;regular finish? jz dologon4 ; yes, display rest of normal-end message. lda oldver ;is this first execution of RAP since w-boot? ora a jz dologon9 ; yes, normal error: exit and print err msg. cpi vers ;old version same as this version? lxi d,mdifver ; no, say "mismatched versions." jnz dologon9 lhld loadpnt ;copy current printfile name to default name. lxi d,bfcb dad d lxi d,fcb lxi b,12 call move lhld loadpnt ;get unum of active file, lxi d,punum dad d mov e,m inx h mov d,m xchg shld punum1 ; store it in "still on" message. inx d ldax d ;get '.' or ' ', sta punum1+2 ; store it in "still on" message. lxi d,mstllon ;say "still on." jmp dologon6 dologon4: lda reopen ;display "opened" or "reopened", cpi yes ; as appropriate. lxi d,mreopnd jz dologon6 lxi d,mopened dologon6: push d call dispname ;display filename. pop d dologon9: call print dologonx: ret ;--------------------------------------------------------- ;display filename from fcb, including a "." if appropriate. dispname: lxi d,fileoff+module2 call print lxi h,fcb+1 mvi b,8 call segout mov a,m cpi ' ' jz dispnamx mvi a,'.' push h call charout pop h mvi b,3 call segout dispnamx: ret ;--------------------------------------------------------- segout: push h push b mov a,m cpi ' ' cnz charout pop b pop h inx h dcr b jnz segout ret ;--------------------------------------------------------- ;insert parms into message. ;install version number. parm2m: lhld version mov a,l ani 0fh ori '0' ;build and store lower digit of version number. sta verloc+2 mvi h,3 dad h dad h dad h dad h mov a,h ;build and store hi digit of version number. sta verloc lhld loadpnt lxi d,site1 ;loadpoint call hexinsrt lhld loadpnt ;endpoint (if loaded) xchg lxi h,modlen-1 dad d mov a,d ;loaded? ora e jnz parm2m2 ; yes, skip lxi h,0 ;set endpoint to 0 parm2m2: lxi d,site2 ;endpoint call hexinsrt ret ;--------------------------------------------------------- hexinsrt: mov a,h call nibsert1 mov a,h call nibsert2 mov a,l call nibsert1 mov a,l call nibsert2 ret nibsert1: rar rar rar rar nibsert2: ani 0fh adi '0' cpi '9'+1 jc nibsert3 adi 7 nibsert3: stax d inx d ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; stack ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ds 40 ;internal stack area. stack dw 0 ;savearea for CCP stack pointer. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; end of service routines ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; endif ********************************************************* ********************************************************* * beginning of movable module * ********************************************************* ********************************************************* org ($+0ffh)/100h*100h ;must be page boundary adjust set $ if copy1 module1 equ $ endif if not copy1 module2 equ $ endif ;-------------------------------------------------------- tentry equ $-adjust jmp trmain+adjust tobdos equ $-adjust jmp $-$ db '' ;locator for debugging. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; bdos trap ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;beginning of trap module. Uses a max of two levels of ; caller's stack. trmain equ $-adjust mov a,c cpi flogv ;trap login vector. jz trplog+adjust cpi fchrn ;trap normal conout. jz docl+adjust ; (control-P may be active.) cpi flist ;trap list-to-printer. jz docl+adjust cpi pstr ;trap "print-string." jz dops2+adjust cpi fsrc1 ;search first? jz dosrchf+adjust ; yes, go process. cpi fsrc2 ;search next? jz dosrchn+adjust ; yes, go process. jmp tobdos+adjust ; none of the above? exit to bios. ;-------------------------------------------------------------------- ;do conout or list. docl equ $-adjust lxi h,0 ;save caller's stack, dad sp ; use local stack. lxi sp,rstack+adjust push h call process+adjust ;output the char. pop h ;restore caller's stack, sphl ; then return. ret ;-------------------------------------------------------------------- ;do print-string function. dops2 equ $-adjust lxi h,0 ;save caller's stack, dad sp ; use local stack. lxi sp,rstack+adjust push h jmp dops6+adjust dops4 equ $-adjust push d mvi c,fchrn mov e,a call process+adjust ;output the char. pop d inx d dops6 equ $-adjust ldax d ;all done? cpi eom jnz dops4+adjust ; no, loop. pop h ;restore caller's stack, sphl ; then return. ret ;------------------------------------------------------------------ ;do "search first". dosrchf equ $-adjust xchg shld oldde+adjust ;save fcb. xchg lxi h,0 ;clear "search next" count. shld srchncnt+adjust lxi h,nwflush+adjust ;clear "fresh buffer activity" flag. mvi m,no call tobdos+adjust ;do the search. ret ;return with register a intact. ;------------------------------------------------------------------ ;do "search next". dosrchn equ $-adjust lhld srchncnt+adjust ;update count of "srch next" calls inx h ;since last "search first". shld srchncnt+adjust lda nwflush+adjust ;buffer flushed since latest "search first"? cpi yes jnz tobdos+adjust ; no, exit to bios. lxi h,0 ;save caller's stack, dad sp ; use local stack. lxi sp,rstack+adjust push h lhld oldde+adjust ;get fcb from latest "search first". xchg lhld srchncnt+adjust ;get current count of "srch next" calls mvi c,fsrc1 ;do one "search first"... inx h ;(don't count the "search first".) dosrchn4 equ $-adjust push h call tobdos+adjust ;(keep register a intact.) pop h mvi c,fsrc2 ; ...and repeat all the "search nexts"s. dcx h inr l dcr l jnz dosrchn4+adjust inr h dcr h jnz dosrchn4+adjust lxi h,nwflush+adjust ;clear "fresh buffer activity" flag. mvi m,no pop h ;restore caller's stack sphl ret ;return with register a intact. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;process character that may go into disk buffer. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; process equ $-adjust call tobdos+adjust ;output char to console or "list" device. lda bptr+adjust+1 ;get hi byte of buffer pointer. cpi bufflen/256 ;buffer full? cnc wrbuff+adjust ; yes, write out buffer and update ; directory entry. ret ;---------------------------------------------------------------------------- ;write used portion of buffer to disk. wrbuff equ $-adjust lda ok+adjust ;disk file still enabled? cpi yes jnz wrbuffx+adjust ; no, exit. mvi c,fuser ;get and save latest user number. mvi e,255 call tobdos+adjust sta olduser+adjust lda user+adjust ;set to printfile's user number. mov e,a mvi c,fuser call tobdos+adjust lxi h,nwflush+adjust ;set "fresh buffer activity" flag. mvi m,yes call testdir+adjust ;is the directory entry still there? jnz wrbuff9+adjust ; no, exit with printing disabled. lhld bptr+adjust ;get hi byte of buffer pointer. mov a,h cpi bufflen/256 ;buffer full? jnc wrbuff4+adjust ; yes, convert into records (no incr). ora l ;buffer empty? jnz wrbuff2+adjust ; no, increment by one record. lda buffer+adjust ;is buffer in pristine, unused state? ora a jz wrbuff9+adjust ; yes, exit, don't write any records. wrbuff2 equ $-adjust lxi d,128 ;"add" one record to buffer. dad d wrbuff4 equ $-adjust mvi a,0 dad h aci 0 mov b,a mov c,h ;allows up to a 64K buffer. wrbuff6 equ $-adjust push b lhld dma+adjust ;adjust buffer dma. xchg lxi h,128 dad d shld dma+adjust mov b,d ;set dma directly to bios, mov c,e ; bypassing update of "olddma." call trpsdx+adjust lxi d,bfcb+adjust ;write a record. mvi c,fwseq call tobdos+adjust pop b ora a ;error free? jnz wrbuff8+adjust ; no, abort dcx b mov a,b ora c jnz wrbuff6+adjust wrbuff8 equ $-adjust lxi d,badwmes+adjust cnz errmess+adjust ;if error, deactivate further printing. call closeb+adjust ;update disk directory. (ignore error.) lxi h,0 ;reset buffer char-count. shld bptr+adjust lxi h,buffer+adjust ;reset buffer dma. shld dma+adjust mvi m,ctlz ;insure initial control-z at buffhead. lhld olddma+adjust mov b,h ;restore caller's dma. mov c,l call trpsdx+adjust wrbuff9 equ $-adjust lda olduser+adjust ;restore caller's user number. mov e,a mvi c,fuser call tobdos+adjust wrbuffx equ $-adjust ret ;----------------------------------------------------------------------- ;close buffer closeb equ $-adjust lxi d,bfcb+adjust mvi c,fclos call tobdos+adjust push psw lda bs2+adjust ori 80h sta bs2+adjust pop psw ret ;----------------------------------------------------------------------- ;test if current directory entry on disk. ;on exit, if error, z = no. testdir equ $-adjust mvi b,32 ;copy current fcb to work area. lxi d,bfcb2+adjust lxi h,bfcb+adjust testdr2 equ $-adjust mov a,m stax d inx h inx d dcr b jnz testdr2+adjust lxi d,bfcb2+adjust ;is file's directory entry on disk? mvi c,fopen call tobdos+adjust ani 0f0h jnz testd9+adjust ; no, abort. mvi b,32 ;examine all but drive bytes for exact match. lxi d,bfcb+adjust lxi h,bfcb2+adjust testd2 equ $-adjust dcr b jz testd9+adjust inx h ;(ok to skip compare of the drive bytes.) inx d ldax d ;match? cmp m jz testd2+adjust ; yes, continue. testd9 equ $-adjust lxi d,badmmes+adjust cnz errmess+adjust ret ;----------------------------------------------------------------------- ;tell user disk file has been prematurely closed. errmess equ $-adjust mvi c,pstr call tobdos+adjust lxi d,dablmes+adjust mvi c,pstr call tobdos+adjust mvi a,no sta ok+adjust ori 1 ;say "error". ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;trap "get login vector", and make de point to old-RAP entry point. ;(Tells new RAP that old copy is already installed and operating.) trplog equ $-adjust mov a,b ; "RAP recursion?" cpi progcode jnz tobdos+adjust call tobdos+adjust mvi b,vers lxi d,tentry+adjust ;change to entry addr, to indicate RAP active. ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; bios traps ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;-------------------------------------------------------; ; trap bios warmboot ; ;-------------------------------------------------------; trpwb equ $-adjust lxi sp,tbuff+80h call tstpat+adjust ;patches available for removal? lxi d,filecon+adjust jnz trpwb9+adjust ; no, say "file active", try later. ; lda bptr+adjust ;is last record completely filled? ; ani 7fh ; jnz trpwb4+adjust ; no, skip. ; ; lhld bptr+adjust ; yes, make one more record, with ctlz. ; inx h ; shld bptr+adjust trpwb4 equ $-adjust call wrbuff+adjust ;flush buffer, update dir, ignore errs. call remtrps+adjust ;remove all traps. lxi d,fileoffx+adjust ;say "file closed." trpwb9 equ $-adjust call notify+adjust trpwbx equ $-adjust jmp $-$ ;----------------------------------------------------------------------- ;remove all bios traps. remtrps equ $-adjust lhld boot+1 xchg lhld trpwbx+1+adjust ;unpatch bios warmboot vector. mvi e,wboff call unpatch+adjust lhld trplsx+1+adjust ;unpatch bios list vector. mvi e,lsoff call unpatch+adjust lhld trpsdx+1+adjust ;unpatch bios setdma vector. mvi e,sdoff ;(do this one last, since it's call unpatch+adjust ; the one that provides protection. lhld trpdsx+1+adjust ;unpatch bios drive select. mvi e,dsoff ;(do this one last, since it's call unpatch+adjust ; the one that provides protection. ret ;----------------------------------------------------------------------- ;unpatch bios vector. unpatch equ $-adjust xchg inx h mov m,e inx h mov m,d xchg ret ;----------------------------------------------------------------------- ;say "file closed." or "file active." notify equ $-adjust push d lxi d,fileoff+adjust ;output "* File" mvi c,pstr call bdos call nameshow+adjust ;output file name. pop d ;output "closed on" or "active on" mvi c,pstr call bdos lxi d,pdrive+adjust ;output "on A0." mvi c,pstr call bdos ret ;----------------------------------------------------------------------- ;are patches available for removal? tstpat equ $-adjust lhld boot+1 ;make sure warmboot vector has not xchg ; been repatched by another program. lxi h,trpwb+adjust call tstvec+adjust mvi e,sdoff lxi h,trpsd+adjust cz tstvec+adjust mvi e,lsoff lxi h,trpls+adjust cz tstvec+adjust mvi e,dsoff lxi h,trpds+adjust cz tstvec+adjust ret ;if ok to remove, z = "yes." ;----------------------------------------------------------------------- ;does (de) = hl? tstvec equ $-adjust inx d ldax d ;still intact as we left it? sub l mov b,a inx d ldax d sbb h ora b ret ; set z = "yes" or "no". ;-------------------------------------------------------; ; trap bios "list output" ; ;-------------------------------------------------------; ;prevent any actual output to printer. ;on exit, bptr points to next empty byte position. trpls equ $-adjust lda ok+adjust ;disk file operational? cpi yes jnz trpls9+adjust ; no, ignore char. lhld bptr+adjust mov a,h cpi bufflen/256 ;buffer limit reached (full)? jnc trpls9+adjust ; yes, ignore char. xchg lxi h,buffer+adjust ;point to current unused buff-position. dad d mov a,c ;if ctl-z, convert to ctl-y. ani 7fh cpi ctlz jnz trpls4+adjust dcr c trpls4 equ $-adjust mov m,c inx h mvi m,ctlz ;insure ctlz at end of file. xchg inx h shld bptr+adjust ;point to new unused buff-position. trpls9 equ $-adjust ret ;-------------------------------------------------------- ;next instruction is used only when unpatching bios. trplsx equ $-adjust jmp $-$ ;-------------------------------------------------------; ; trap bios setdma ; ;-------------------------------------------------------; trpsd equ $-adjust mov h,b mov l,c shld olddma+adjust trpsdx equ $-adjust call $-$ call reprot+adjust ret ;-------------------------------------------------------- ;reprotect RAP if necessary. reprot equ $-adjust lxi d,trmain+adjust ;insure that trap module is protected. lhld bdos+1 mov a,e sub l mov a,d sbb h jnc reprotx+adjust xchg shld bdos+1 reprotx equ $-adjust ret ;-------------------------------------------------------; ; trap bios "select drive" ; ;-------------------------------------------------------; trpds equ $-adjust trpdsx equ $-adjust call $-$ push h call reprot+adjust ;reprotect RAP, if necessary. pop h ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; conout routines ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;display filename from fcb, including a "." if appropriate. nameshow equ $-adjust lxi h,bfcb+adjust+1 mvi b,8 call namseg+adjust mov a,m cpi ' ' jz nameshwx+adjust mvi a,'.' push h call outchar+adjust pop h mvi b,3 call namseg+adjust nameshwx equ $-adjust ret ;--------------------------------------------------------- namseg equ $-adjust push h push b mov a,m cpi ' ' cnz outchar+adjust pop b pop h inx h dcr b jnz namseg+adjust ret ;.................................................... outchar equ $-adjust ;display buffer char, save z-flag. ani 7fh mov e,a mvi c,fchrn call tobdos+adjust ret ********************************************************* ********************************************************* * data areas * ********************************************************* ok equ $-adjust ;is output file ok? db yes dma equ $-adjust dw buffer+adjust olddma equ $-adjust ;restore this after writing records to disk. dw 0 user equ $-adjust db 0 olduser equ $-adjust ;restore this after writing records to disk. db 0 nwflush equ $-adjust ;was buffer recently flushed? db no srchncnt equ $-adjust ;how many consecutive calls to "search next"? dw 0 oldde equ $-adjust ;fcb used in latest "search first" dw 0 ;------------------------------------------------------- badmmes equ $-adjust db cr,lf,bell db '>>ERROR: Printfile absent or altered<<',cr,lf,eom badwmes equ $-adjust db cr,lf,bell db '>>ERROR: Printfile disk is full. <<',cr,lf,eom dablmes equ $-adjust db '>> Printing is now disabled. <<',cr,lf,eom fileoff equ $-adjust db cr,lf db cr,lf db '* File ' db eom ;db 'xxxxyyyy.zzz' fileoffx equ $-adjust db ' closed on ',eom pdrive equ $-adjust db 'A' punum equ $-adjust db '00. *',cr,lf,eom ;db '* File PRINTER.LOG closed on A00. *' ;db '_______________________________________',cr,lf filecon equ $-adjust db ' active on ',eom ;------------------------------------------------------- ;fcbs bfcb equ $-adjust ;36 bytes dw 0,0,0,0,0,0,0,0 dw 0,0,0,0,0,0,0,0 dw 0,0 bs2 equ bfcb+14 brcnt equ bfcb+15 bfcb2 equ $-adjust ;36 bytes dw 0,0,0,0,0,0,0,0 dw 0,0,0,0,0,0,0,0 dw 0,0 ;------------------------------------------------------- ;buffer. bptr equ $-adjust ;pointer to next empty char in printer buff. dw 0 loadlen equ $-adjust+1 ;end of initialized ram for RAP module. buffer equ $-adjust db 0 ;if null, no printer data yet received. ; ds bufflen ;bufflen+1 leaves room for terminal control-Z. ; ;(adjusted for below). bufflen equ buffk*1024 buffend equ buffer+bufflen+1 ;------------------------------------------------------- rstack equ buffend+40 modend equ rstack modlen equ modend+6 ;total length of installed RAP module. ;(extra 6 bytes leaves space for CP/M ; serial #, which may be poked in by EX15.) ********************************************************* * end of relocatable routines * ********************************************************* ;flip the copy1/copy2 toggle copy1 set not copy1 ;link a second copy, if this was the first copy if not copy1 link RAP endif progend equ $ ;end of assembled program. end