; ; Library: ZSLIB ; Version: 2.0 ; Module: ZSSSTPCP ; Version: 1.0 ; Author: Carson Wilson ; Date: 16 Dec 89 ; ; Purpose: Set file datestamp to CP/M Plus. ; ; Derived from UN33.MAC 02/27/86 by Wolfenbarger/Saeks/Hoff ; Works on CP/M+ systems with logical sector sizes of up to 1024 bytes. ; ;----------------------------------------------------------------------- ; ; Addresses ; BDOS equ 05h ; BDOS vector address ; ; BDOS functions ; SELDSK equ 14 ; Select disk DIRCALL equ 32h ; CP/M 3.0 direct BIOS call GETCUR equ 19h ; Get currently logged in disk GETUSR equ 20h ; Get current user public SSTPCP extrn BCD2JUL, DOSTYP, CPMVER ; ZSLIB ;----------------------------------------------------------------------- ; ; SSTPCP - Set file datestamp to CP/M Plus from 128-byte buffer. ; ; Entry: - points to file's FCB. ; - points to 128-byte datestamp buffer. ; - points to 1024-byte DMA buffer. ; Exit: - zero flag set and A=0 if stamp set. ; - zero flag reset (NZ) if error, error in : ; FF - file not found. ; 06 - not CP/M Plus. ; 05 - no stamps on disk. ; 04 - BIOS sector size > 1024 bytes. ; 03 - drive invalid. ; 02 - BIOS read error. ; 01 - BIOS write error. ; Uses: ; Notes: The datestamp buffer should be filled on entry to BCD ; yy,mm,dd,hh,min of file creation, last access, and ; last modification, respectively. If valid, (month <> 0) ; the BCD creation field is copied to the CP/M Plus ; Create/Access field. Otherwise, the BCD last access ; field is used, or the CP/M Plus Create/Access field is ; zeroed if neither are valid. Similarly, the BCD last ; modification field is copied to the CP/M Plus Update field, ; or the Update field is zeroed if the BCD stamp is invalid. ; The file whose stamp is to be set must either be on the ; current drive or at the drive specified by FCB byte 0. ; Only files at the current user number will be matched. ; No wildcards allowed. SSTPCP: ld (SAVEIX),ix ld (DMAPTR),bc ld (FCBPTR),de ld (STPPTR),hl ; Test for CP/M Plus call DOSTYP ; Test if CP/M Plus jp nz,DOSER ; Abort if extended BDOS ld a,(CPMVER) cp 30h ; Plus? jp c,DOSER ; No xor a ld (CHGFLG),a ; Say no changes ld (SECTOR),a ; ; Set BIOS DMA to ours, get DPH address from BIOS ; push de ; Save FCB pointer ld (BCREG),bc ld a,12 ; Set BIOS DMA to our buffer ld (FUNC),a call CALLBIOS pop hl ; FCB pointer ld a,(hl) or a ; Disk specified? jr nz,DSKPR1 ld c,GETCUR ; No, get current disk call BDOS inc a DSKPR1: dec a ld (DRVCOD),a ; Save code for later ld e,a ld c,SELDSK call BDOS ; Keep BDOS happy ld a,(DRVCOD) ld c,a ld b,0 ; Disk number ld e,b ; Flag initial select ld (BCREG),bc ; BIOS select disk function ld (DEREG),de ld hl,0 ld (HLREG),hl ; Required by Morrow BIOS (bug?) ld a,9 ; 'SELDSK' ld (FUNC),a call CALLBIOS ld a,h or l ; Check for drive error jp z,DRVER ; Quit if so ld e,(hl) ; Get DPH address inc hl ld d,(hl) ld (XLTADD),de ; Save address of XLT ld bc,11 add hl,bc ; HL --> .DPB ld e,(hl) inc hl ld d,(hl) ; DE --> DPB ex de,hl ld e,(hl) ; Get logical SPT inc hl ld d,(hl) ld (SPT),de ld de,3 ; Offset to EXM (# of extents/entries-1) add hl,de ; Add offset ld a,(hl) ; Get EXM ld (EXM),a ld de,3 ; Offset to DRM (# of directory entries) add hl,de ; Add offset ld e,(hl) ; Get DRM inc hl ld d,(hl) push de ; Save DRM push hl ; Save .highDRM ld de,7 ; Point to PSH add hl,de ld a,(hl) ; Get it ld (PSH),a ; Save it pop de ; Get .highDRM pop hl ; Get DRM inc hl ; Add 1 for total directory entries ld a,(PSH) cp 4 jp nc,PHYSER ; Physical sector size > 1024 inc a inc a ld b,a call DIVHLB ld (DVD),a ld a,l ; Save # of directory sectors ld (DIRSEC),a ld hl,(SPT) ; Logical sectors per track ld a,(PSH) ld b,a call DIVHLB ld a,l ; PHSPT = SPT for 128 byte sectors ld (PHSPT),a ; Physical sectors per track ld hl,5 ; Add offset to # of reserved tracks add hl,de ld e,(hl) ; Get number of reserved tracks inc hl ld d,(hl) ld (RESTKS),de ; Save reserved tracks for later ld c,GETUSR ld e,0FFh ; Get call BDOS ld hl,(FCBPTR) ld (hl),a ; Stuff to match dir. entry ; ; Now translate BCD stamp buffer to CP/M+ format & store. ; ld hl,STPBUF ; First zero out STPBUF ld d,h ld e,l inc de ld (hl),0 ld bc,7 ; First 8 only ldir ld bc,5 ld ix,(STPPTR) ; Caller's BCD stamp call JULIX ; Date OK? jr z,SETACC ; No ld (CREDAT),hl ; Yes, store it ld a,(ix+3) ld (CREHR),a ld a,(ix+4) ld (CREMIN),a add ix,bc jr SETUPD SETACC: add ix,bc call JULIX ; Date OK? jr z,SETUPD ; No ld (CREDAT),hl ; Yes, store it ld a,(ix+3) ld (CREHR),a ld a,(ix+4) ld (CREMIN),a SETUPD: add ix,bc call JULIX ; Date OK? jr z,GETDIR ; No ld (UPDDAT),hl ; Yes, store it ld a,(ix+3) ld (UPDHR),a ld a,(ix+4) ld (UPDMIN),a ; ; GETDIR - Read a physical sector of the directory to our buffer ; GETDIR: ld a,(DIRSEC) ; Get # of directory sectors remaining or a jp z,EXIT ; Return if none call PHSECTRK ; Compute cur. physical sector and track ld bc,(RESTKS) ; Get number of reserved tracks in BC ld h,0 ; Get physical track number in HL ld a,(PHTRK) ld l,a add hl,bc ; Directory track in HL ld (BCREG),hl ; Set track to directory ld a,10 ; SETTRK ld (FUNC),a call CALLBIOS ld a,(PHSECT) ; Get current physical sector ld c,a call TRNSEC ; Translate sector if necessary ld b,0 ld (BCREG),bc ; Point to current sector ld a,11 ; SETSEC ld (FUNC),a call CALLBIOS ld a,13 ; Read sector of directory ld (FUNC),a call CALLBIOS or a jp nz,RDERR ; Read error ; ; Check entries for match. Modify and write back if match found. ; xor a ; Zero flag ld (RECFLG),a ld (OFFSET),a ; Offset of entry in directory record ld a,(DVD) ; Get number of dir. entries per sector ld b,a ld hl,(DMAPTR) CKNXT: push bc ld de,(FCBPTR) call COMP12 ; Match? jp nz,GETNXT ; No ; HL points to buffer location of our entry push hl push bc ld a,(OFFSET) add a,a add a,a add a,a add a,a add a,a ; x32 ld b,0 ld c,a sbc hl,bc ; HL --> start of record ld bc,60h add hl,bc ; Now find stamp in record ld a,(OFFSET) add a,a ld b,a add a,a add a,a add a,b ; *10 inc a ; +1 ld b,0 ld c,a add hl,bc ; HL --> our file's stamp ld de,STPBUF ex de,hl ld bc,8 ldir ; Copy STPBUF --> SECTOR pop bc pop hl ld a,1 ; Set changed flag ld (RECFLG),a ld (CHGFLG),a GETNXT: ld a,(OFFSET) inc a GETNX1: ld (OFFSET),a ld de,32 ; Advance to next entry add hl,de ld a,(hl) cp '!' ; Stamp? jr nz,GETNX2 ; No pop bc ; Yes, skip dec b ; Decrement entry count jr z,GETNX3 ; Stop if done push bc xor a ; Reset OFFSET jr GETNX1 GETNX2: pop bc ld a,(OFFSET) cp 3 jp nc,NOSTER ; No stamps if 4 consecutive entries lack '!' djnz CKNXT ; Decrement counter GETNX3: ld a,(RECFLG) ; Check for changed entry or a ; Write? jr nz,WRTSEC ; Yes, finish up ld a,(DIRSEC) ; Nope, decrement physical directory sectors dec a ld (DIRSEC),a ld a,(SECTOR) ; Increment sector inc a ld (SECTOR),a jp GETDIR ; Back for another ; ; Write sector back to disk and quit ; WRTSEC: ld bc,1 ; Non-deferred write ld (BCREG),bc ld a,14 ; Write ld (FUNC),a call CALLBIOS ; Update directory or a ; Check for write error jp nz,WRTER ld a,(DRVCOD) ; Reset drive (0..15) ld hl,1 and a ; Ready if drive A jr z,RESET ld b,a ADDHL: add hl,hl ; Else calculate vector djnz ADDHL RESET: ex de,hl ld c,37 ; Log out drive call BDOS jp EXIT ; Done. ; ; ============================================ ; SUBROUTINES COMP12: ; Compare 12 bytes directory entry @HL push de ; ..with FCB @DE push hl push bc ld b,12 COMP12A: ld a,(de) cp (hl) jr nz,COMPX inc hl inc de djnz COMP12A ; RETURN (Z) if match ld a,(EXM) ; Make sure we're at first entry cp (hl) ld a,0 jr nc,COMP12B ; At first if <= EXM ld a,0FFh ; Otherwise no match COMP12B:or a COMPX: pop bc pop hl pop de ret ; ; Divide HL by 2^B, A = 2^B on exit ; DIVHLB: ld a,1 DIVHL1: add a,a ; Double A, zero (C) rr h rr l djnz DIVHL1 ret ; PHSECTRK: ld c,0 ; Set 'PHTRK' to 0 ld a,(PHSPT) ld b,a ; Phys SPT in 'B' ld a,(SECTOR) ; Logical directory sector CKPHTRK: cp b ; Compute PHSECT = sectors mod PHSPT jr c,STSECTRK ; And PHTRK = (sectors - PHSECT)/PHSPT sub b inc c jr CKPHTRK STSECTRK: ld (PHSECT),a ld a,c ld (PHTRK),a ret ; ; TRNSEC: ld hl,(XLTADD) ; Get translate table address ld (DEREG),hl ld (BCREG),bc ld a,16 ; SECTRAN ld (FUNC),a call CALLBIOS ld c,l ret ; ; CALLBIOS: ; CP/M v3.0 direct BIOS call ld c,DIRCALL ld de,FUN50 call BDOS ret ; Translate date at IX to Julian, return in HL JULIX: ld a,(ix+1) or a ; Month = 0? ret z ; Yes push ix ; No, xlate pop hl call BCD2JUL ; "Create" to Julian or 0FFh ret ; EXIT ROUTINE DOSER: ld a,7 ; Not CP/M+ jr EXIT1 NOSTER: ld a,6 ; No stamps jr EXIT1 PHYSER: ld a,5 ; Sector size > 1024 jr EXIT1 DRVER: ld a,4 ; Drive invalid jr EXIT1 RDERR: ld a,3 ; BIOS read error jr EXIT1 WRTER: ld a,2 ; BIOS write error jr EXIT1 EXIT: ld a,(CHGFLG) EXIT1: dec a ; (NZ) means error ld bc,(DMAPTR) ld de,(FCBPTR) ld hl,(STPPTR) ld ix,(SAVEIX) ret ;----------------------------------------------------------------------- ; ; Data area ; DSEG FUN50: FUNC: ds 1 AREG: ds 1 BCREG: ds 2 DEREG: ds 2 HLREG: ds 2 ; STPBUF: CREDAT: ds 2 CREHR: ds 1 CREMIN: ds 1 UPDDAT: ds 2 UPDHR: ds 1 UPDMIN: ds 1 CHGFLG: ds 1 OFFSET: ds 1 DMAPTR: ds 2 FCBPTR: ds 2 STPPTR: ds 2 SAVEIX: ds 2 DRVCOD: ds 1 XLTADD: ds 2 DIRSEC: ds 1 RESTKS: ds 2 SECTOR: ds 1 RECFLG: ds 1 PSH: ds 1 DVD: ds 1 SPT: ds 2 EXM: ds 1 PHSPT: ds 1 PHSECT: ds 1 PHTRK: ds 1 end ; End ZSSTPCP.Z80