title 'cp/m plus pip enhancer' page 58 ; purpose : to enhance the function of PIP.COM in the following points: ; a) if the source file has a byte count <>0, this byte count is transfered ; to the destination file. ; b) if the source file has the ARCHIVE bit set, the destination file ; will have its ARCHIVE bit set. ; c) if the source file has an UPDATE date&time stamp, this is copied ; as CREATE and UPDATE date&time stamp to the destination file. ; It's simple to copy the ARCHIVE bit and byte count, as CP/M Plus ; has functions to get/set these dates. In case of date&time stamps, ; we have to go the dirty way: disabling the BIOS-internal clock ; software and setting the desired date&time in the SCB will allow ; us to do this forbidden thing. NOTE: this procedure WILL NOT WORK ; in systems without clock or with interrupt-driven ticker, but works ; fine in systems with hardware clock using BIOS function 26: TIME. ; NOTE also that it is not possible to use PIPRSX within another RSX, ; which manipulates the WBOOT jump at location 0000h. ; Constants : FALSE equ 0 ; boolean definitions TRUE equ not FALSE TEST equ FALSE ; diagnostic printer output patch$loc1 equ 06CCh patch$loc2 equ 0E62h patch$loc3 equ 0E75h patch$loc4 equ 0E21h patch$loc5 equ 1871h patch$loc6 equ 0B69h patch$loc7 equ 195Ah source$fcb equ 22C7h dest$fcb equ 22F6h pip$buffer equ 237Dh attr$fcb equ 2325h page ; RSX header : cseg serial: db 0,0,0,0,0,0 ; serial number field start: jmp func$test ; jump to start of RSX next: jmp 0 ; link to BDOS prev: dw 0 ; link to previous RSX remove: db TRUE ; remove after operation nonbank: db FALSE ; loaded on every system RSX$name: db 'PIPRSX ' ; name of RSX loader: db 0 ; loader flag reserved: db 0,0 ; reserved area ; print macro: print macro string local str lxi h,str call pstring dseg str: db string db 13,10 db 0 cseg endm ; RSX function test : cseg func$test: mvi a,12 ; patch only on return version call cmp c jnz next patch$pip: mvi a,JMP ; patch some locations in PIP.COM lxi h,patch1 sta patch$loc1 shld patch$loc1+1 lxi h,patch2 sta patch$loc2 shld patch$loc2+1 lxi h,patch3 sta patch$loc3 shld patch$loc3+1 lxi h,patch4 sta patch$loc4 shld patch$loc4+1 lxi h,patch5 sta patch$loc5 shld patch$loc5+1 lxi h,patch6 sta patch$loc6 shld patch$loc6+1 lxi h,patch7 sta patch$loc7 shld patch$loc7+1 if TEST push b push d print 'PIP.COM patched' pop d pop b endif jmp next ;******************************************************************************* ; first patch: after getting input line. ; see if we can allow copy of attributes. cseg patch1: if TEST print 'PATCH 1 reached' endif xra a ; reset all RSX variables sta inhinbit ; no multiple source files call clear$vars call rest$date ; restore old system date&time mvi c,0 ; not between [] lxi h,pip$buffer ; test input line for multiple input file mov b,m ; B := char count inr b buffer$test: inx h ; character left? dcr b jz patch1$end mov a,c ; between []? ora a jnz buffer$option mvi a,',' ; test for multiple input files cmp m jz patch1$multi mvi a,'[' ; test for option start cmp m jnz buffer$test mvi c,TRUE ; set option flag jmp buffer$test patch1$multi: mvi a,TRUE sta inhinbit if TEST print 'MULTIPLE SOURCE FILES or CHANGING COPY' endif patch1$end: db 01h,25h,23h ; old code at patch$loc1 jmp patch$loc1+3 buffer$option: mov a,m ; get option char call UPCASE ; convert to upper case cpi ']' ; end of option ? jz option$end cpi 'D' jz patch1$multi cpi 'F' jz patch1$multi cpi 'I' jz patch1$multi cpi 'L' jz patch1$multi cpi 'N' jz patch1$multi cpi 'P' jz patch1$multi cpi 'Q' jz patch1$multi cpi 'S' jz patch1$multi cpi 'T' jz patch1$multi cpi 'U' jz patch1$multi cpi 'Z' jz patch1$multi jmp buffer$test option$end: mvi c,FALSE ; reset option flag jmp buffer$test ;******************************************************************************* ; second patch: before opening source file. ; force OPEN to return byte count of source file. cseg patch2: if TEST print 'PATCH 2 reached' endif lxi h,source$fcb+32 ; set FCB to get byte count mvi m,0FFh patch2$end: db 01h,0C7h,22h ; old code at patch$loc2 jmp patch$loc2+3 ;******************************************************************************* ; third patch: after successfull opening source file. ; save byte count, archive flag and date&time stamp. cseg patch3: if TEST print 'PATCH 3 reached' endif lxi h,source$fcb+32 ; get byte count of source file mov a,m sta byte$count mvi m,0 ; set CR field to (record = 0) if TEST ora a jz patch3$nocount print 'File has byte count' patch3$nocount: endif lxi h,source$fcb+11 ; get ARCHIVE bit of this file mov a,m ral ; boolean from bit 7 sbb a sta archive$flag if TEST ora a jz patch3$noarch print 'File has archive bit set' patch3$noarch: endif lxi h,source$fcb ; copy source fcb into internal buffer lxi d,int$fcb ; because BDOS 102 destroys FCB contents mvi b,36 patch3$move: mov a,m stax d inx h inx d dcr b jnz patch3$move lxi h,0 ; clear update date&time stamp shld update$date shld update$time lxi d,int$fcb ; get date and time stamps mvi c,102 call next ora a ; error ? jnz patch3$end ; yes: do not make date&time stamps lhld int$fcb+28 ; get update date stamp mov a,l ora h ; zero ? jz patch3$create shld update$date ; no: store it lhld int$fcb+30 ; update time stamp shld update$time if TEST print 'File has UPDATE stamp' endif jmp patch3$end patch3$create: lhld int$fcb+24 ; get create or access date and time stamp mov a,l ora h ; zero ? jz patch3$end shld update$date ; no: store it lhld int$fcb+26 ; create time stamp shld update$time if TEST print 'File has CREATE stamp' endif patch3$end: db 3Ah,12h,24h ; old code at patch$loc3 jmp patch$loc3+3 ;******************************************************************************* ; fourth patch : before making destination file. ; change system date&time. cseg patch4: if TEST print 'PATCH 4 reached' endif lda inhinbit ; is PIP copying single files ? ora a jnz patch4$end ; no: do nothing lhld update$date ; yes: has file update stamp? mov a,l ora h jz patch4$end ; no: do nothing call set$date ; set new date&time patch4$end: db 01h,0F6h,22h ; old code at patch$loc4 jmp patch$loc4+3 ;******************************************************************************* ; fifth patch : after closing destination file. ; restore system date&time. cseg patch5: if TEST print 'PATCH 5 reached' endif call rest$date patch5$end: db 3Ah,7Bh,23h ; old code at patch$loc5 jmp patch$loc5+3 ;******************************************************************************* ; sixth patch : within error handler. ; set RSX ready for next start. cseg patch6: if TEST print 'PATCH 6 reached' endif mvi a,TRUE ; reset all internal parameters sta inhinbit call clear$vars call rest$date patch6$end: db 3Ah,68h,23h ; old code at patch$loc6 jmp patch$loc6+3 ;******************************************************************************* ; seventh patch: before assigning file attributes. cseg patch7: if TEST print 'PATCH 7 reached' endif lda inhinbit ; is PIP copying single files ? ora a jnz patch7$end ; no: do nothing lda byte$count sta attr$fcb+32 ; set byte count into attribute fcb lxi h,attr$fcb+6 mvi a,10000000b ora m mov m,a lxi h,attr$fcb+11 ; set archive bit? lda archive$flag ani 10000000b ora m mov m,a call clear$vars call rest$date patch7$end: db 01h,25h,23h ; old code at patch$loc7 jmp patch$loc7+3 ;******************************************************************************* ; ; change system date$time : cseg set$date: lhld 1 ; get address of BIOS jump table lxi d,75 ; offset of TIME jump entry dad d mvi a,JMP cmp m ; test entry (must be JMP) rnz ; if not do nothing mvi m,RET ; patch with RET opcode lxi d,udate$pb ; set new date&time stamp mvi c,49 call next lxi d,utime$pb mvi c,49 call next lxi d,usec$pb ; seconds are zero mvi c,49 call next mvi a,TRUE sta date$changed if TEST print 'SYSTEM date&time changed' endif ret ;******************************************************************************* ; ; restore system date$time : cseg rest$date: lda date$changed ; was it changed? ora a rz ; no : do nothing lhld 1 ; get address of BIOS jump table lxi d,75 ; offset of TIME jump entry dad d mvi m,JMP ; restore JMP entry mvi a,FALSE sta date$changed if TEST print 'SYSTEM date&time restored' endif ret ;******************************************************************************* ; ; clear RSX variables : cseg clear$vars: xra a sta byte$count sta archive$flag sta update$date sta update$date+1 sta source$fcb+32 ret ;******************************************************************************* ; ; translate char in to upper case. uses cseg UPCASE: cpi 'a' ; < 'a' ? rc ; no translation performed cpi 'z'+1 ; > 'z' ? rnc ; no translation performed sui 'a'-'A' ; lower -> upper ret ;******************************************************************************* ; ; data area : dseg inhinbit: db TRUE ; is TRUE if PIP changes file contents byte$count: db 0 ; of source file archive$flag: db FALSE ; of source file date$changed: db FALSE ; is TRUE if system date&time is changed int$fcb: ds 36 ; copy of source file fcb udate$pb: db 58h ; parameter blocks for file date&time db 0FEh update$date: dw 0 utime$pb db 5Ah db 0FEh update$time: dw 0 usec$pb: db 5Ch db 0FFh db 0 ;******************************************************************************* if TEST cseg pstring: mov a,m inx h ora a rz call pbyte jmp pstring cseg pbyte: push h push b ani 7FH mov c,a lhld 1 lxi d,12 dad d call ipchl pop b pop h ret ipchl: pchl endif end