;CONV/ASM - Convert TRSDOS 1.2, 1.3 Disks TITLE ; HOME EQU 1CH CLR EQU 1FH ETX EQU 03H CR EQU 0DH LF EQU 10 ; FLAG EQU 01000000B ABB EQU 00010000B ; *GET SVCMAC:3 ;SVC Macro equivalents *GET COPYCOM:3 ;Copyright message ; ORG 2600H ; BEGIN IF @BLD631 LD (STACK),SP ;<631>Save entry stack @@CKBRKC ;<631>Check for break JR NZ,$ABORT ;<631>abort ELSE @@CKBRKC JR Z,BEGINA ;Continue if no break LD HL,-1 RET ; else abort ; BEGINA LD (STACK),SP ;Save entry stack ENDIF PUSH HL ;Save ptr to CMD buffer @@DSPLY HELLO$ ;Display the signon LD HL,0 ;Set up to get HIGH$ LD B,L @@FLAGS ;IY => flag table base BIT 1,(IY+'C'-'A') ;OK if not CMDR JR Z,NOTCMDR ;Use LOW$ otherwise INC B NOTCMDR @@HIGH$ ;P/u HIGH$/LOW$ LD (MYHIGH),HL ;Store away PUSH IY ;Trans to HL POP DE LD HL,'K'-'A' ;Offset to KFLAG$ ADD HL,DE ;HL=>KFLAG$ LD (KFLG),HL ;Store pointer RES 0,(HL) ;Kick break bit off LD HL,'S'-'A' ;SFLAG$ offset ADD HL,DE LD (SFLG),HL ;Store away POP HL ;Restore cmd pointer CALL PGRM ; and continue ; ; Exit routines ; $EXIT LD HL,0 ;Init to no error $QUIT @@CKBRKC ;Clear out break bit LD SP,$-$ ;P/u original stack STACK EQU $-2 RET ; $ABORT LD HL,-1 ;Set abort code JR $QUIT ; and quit ; IF @BLD631 $CR LD A,CR ;<631> ENDIF $DSP PUSH BC ;Display a character, LD C,A ; saving BC @@DSP POP BC RET ; ; Pick up drive numbers and partial filespec ; PGRM: LD A,(HL) ;Check for NOT filespec CP '-' ; char used JR NZ,MVNAM1 ;Go if not NOT LD A,0FFH ;TRUE value LD (NOTPRM),A ;Set if specified INC HL MVNAM1 LD DE,PATTRN ;Point to possible partspec LD B,8 ;Max 8 chars in name CALL SKIPSP ;Skip spaces CALL MOVELT ;Move letters/digits/$ CALL SKIPLT ;Skip letters/digits/$ LD A,(HL) ;Check for extension CP '/' JR NZ,NOEXT ;Go if none INC HL LD DE,PATEXT ;Point to ext field LD B,3 ;Max 3 chars in ext CALL MOVELT ;Move letters/digits/$ CALL SKIPLT ;Skip letters/digits/$ NOEXT CALL GETDRV ;Get source drive # LD (SDRIVE),A ;Store drive # AND A ;Be sure not drive 0 LD DE,NOT0 ;Error msg EX DE,HL JP Z,PERR1 ;Param error source is 0 EX DE,HL ;Restore cmd line ptr CALL SKIPSP ;Skip spaces CALL GETDRV2 ;Get destination drive LD (DDRIVE),A ;0FFH if no dest drv CALL SKIPSP ;Move to '(' ; ; Scan parameters ; LD DE,PRMTBL$ ;Check parameters entered @@PARAM JP NZ,PRMERR ;Quit on parm error DPARM LD HL,$-$ ;DIR only? LD A,H OR L JR Z,SPARM ;Go if not LD A,0FFH ;Set flag at DDRIVE LD (DDRIVE),A ;If dest is ff, read DIR SPARM LD HL,$-$ ;Check if no parms S,I,V VPARM LD DE,$-$ IPARM LD BC,$-$ LD A,L OR E OR C LD (SIV+1),A ;Save S!I!V QPARM LD HL,0FFFFH ;P/u Q,N,O parms NPARM LD DE,0 OPARM LD BC,0 LD A,E ;Form N!O OR C LD (NORO+1),A ;Save that ; ; Save old DCT ; LD A,(SDRIVE) ;Pick up source drive # LD C,A ;Move to C reg LD A,(DDRIVE) ;Be sure not single drive CP C LD HL,NOTONE ;=>error msg JP Z,PERR1 ;Go if same @@GTDCT ;Point to DCT PUSH BC ;Save drive # PUSH IY ;Move DCT to HL reg POP HL LD DE,SAVDCT ;Point to save area LD BC,10 LDIR ;Move it POP BC ; ; Find directory track ; LD DE,0001 ;Track 0, sector 1 LD HL,DBUFF ;Buffer for sector @@RDSEC JR Z,OK0 ;Go if no error CP 6 ;Was it DAM error? JP NZ,IOERR ;Go if some other CALL CKEARLY ;Can we do this type? OK0 INC HL ;Point to dir cyl # LD D,(HL) ;Get it INC H ;Point to TRSDOS DEC HL ; version number DEC HL DEC HL LD A,(HL) ;Pick it up LD (TRSDOS+1),A ;Save for later ; ; Read directory records into memory ; LD E,3 ;Skip GAT and HIT LD B,16 ;Read 16 sectors LD HL,DBUFF DREAD LD (IY+7),18 ;Chg # sectors/trk for @@RDSEC ; TRSDOS & Read a sector JR Z,OK1 ;Go if no error CP 6 ;Ignore record type JP NZ,IOERR ;Go if error OK1 INC H ;Bump buffer pointer INC E ;Bump sector number DJNZ DREAD ;Loop till done ; ; Loop through all entries ; LD HL,DBUFF ;Point to first entry ELOOP EQU $ LD A,($-$) ;Check system break bit KFLG EQU $-2 ;Address of KFLAG BIT 0,A JP NZ,$ABORT ;Abort if set LD B,(HL) ;P/U attributes PUSH HL POP IX PUSH HL BIT 4,B ;Alive? JP Z,SKIPIT ;Skip it if dead BIT 7,B ;FXDE? JP NZ,SKIPIT ;Skip it if so ; ; Check file's attributes ; SIV LD A,$-$ ;S, I, or V given? AND A JR Z,NOSIV ;Go if none given BIT 6,B ;SYS file? JR Z,NOTSYS ;Go if not LD A,(SPARM+1) ;S parm given? AND A JP Z,SKIPIT ;Skip file if not JR NOSIV ; else possible match NOTSYS BIT 3,B ;Visible or invisible? JR NZ,INV ;Go if inv LD A,(VPARM+1) ;V parm given? AND A JP Z,SKIPIT ;Skip file if not JR NOSIV ; else possible match INV LD A,(IPARM+1) ;I parm given? AND A JP Z,SKIPIT ;Skip file if not ; ; Check if name matches wildcard ; NOSIV LD DE,5 ;Offset to name field ADD HL,DE PUSH HL ;Compare with pattern LD DE,PATTRN ; of user partspec LD B,11 CPLOOP LD A,(DE) ;P/U pattern byte INC DE CP '$' ;Matchall? JR Z,MATCH CP (HL) ;Match? JR NZ,NMATCH ;Go if not MATCH INC HL DJNZ CPLOOP NMATCH POP HL ;Z if match, NZ if not CALL NOTCHK ;Reverse flag if NOT entered JP NZ,SKIPIT ;Skip file if no match ; LD DE,FCB ;Point to FCB LD B,8 MVNAME LD A,(HL) ;Move name CP ' ' ;Space? JR Z,GOTNAM ;Go if hit one INC HL LD (DE),A ;Put to FCB INC DE DJNZ MVNAME GOTNAM LD C,B ;Offset to ext field LD B,0 ADD HL,BC LD A,(HL) ;No extension? CP ' ' JR Z,GOTEXT ;Go if so LD A,'/' ;Put in slash LD (DE),A INC DE LD B,3 EXLOOP LD A,(HL) ;Move extension INC HL CP ' ' ;Finished? JR Z,GOTEXT LD (DE),A INC DE DJNZ EXLOOP ;Loop till done ; IF @BLD631 GOTEXT: PUSH DE ;<631>Save current spot in FCB LD HL,FNAME ;<631>Move name to buffer CALL CPYFCB ;<631>Do 32 byte LDIR ELSE GOTEXT LD A,ETX ;Put ETX at end for dsply LD (DE),A PUSH DE ;Save current spot in FCB LD HL,FCB ;Move name to buffer LD DE,FNAME ; for printing LD BC,32 LDIR ENDIF POP DE ;Get back where we were ; ;Print filenames if no destination drive (DDRIVE=0FFH) ; LD A,(DDRIVE) ;Check for just printing DIR INC A ;Set Z if FF JR NZ,MOVING ;Go if not FF CALL SHOW ;Print entry JP SKIPIT ; and go on to next ; ; Check if file exists on destination disk ; MOVING LD A,':' ;Now put the drive separator LD (DE),A ; in the FCB INC DE LD A,(DDRIVE) ;Put in drive spec OR '0' ;Change number to ASCII LD (DE),A INC DE IF @BLD631 LD HL,FCB2 ;<631>Copy into 2nd FCB PUSH HL ;<631> CALL CPYFCB ;<631> POP DE ;<631> LD HL,TBUFF ;Point to transfer buffer ELSE LD A,ETX ;Put in ETX to end LD (DE),A LD HL,FCB ;Copy into 2nd FCB LD DE,FCB2 LD BC,32 LDIR LD DE,FCB2 ;Point to start of FCB LD HL,TBUFF ;Point to transfer buffer LD B,0 ;LRL=256 ENDIF PUSH HL LD HL,$-$ ;HL => SFLAG SFLG EQU $-2 SET 0,(HL) ;Set the open inhibit bit POP HL @@OPEN ;Do the open LD B,A ;Save return code JR Z,NORO ;Go if opened okay CP 18H ;File not found? JP NZ,IOERR ; else an error ; ; Check New and Old parms ; NORO LD A,0 ;N or O specified? AND A JR Z,CHECKQ ;Go if neither LD A,(OPARM+1) ;O parm given? AND A JR Z,CKNEW ;Go if not XOR A OR B ;Did file exist? JR Z,CHECKQ ;Go if so (ok) CKNEW LD A,(NPARM+1) ;N parm given? AND A IF @BLD631 JR Z,TOSKIP1 ;<631>Skip file if not ELSE JP Z,SKIPIT ;Skip file if not ENDIF XOR A OR B ;Be sure it was new IF @BLD631 TOSKIP1: ;<631> ENDIF JP Z,SKIPIT ;Go if it wasn't ; ; Ask question if Q parm was given ; CHECKQ LD A,(QPARM+1) ;Check Q parm AND A JR NZ,QUERY ;Query if so LD HL,CONVS ;"Converting..." @@DSPLY LD HL,FNAME ;Filename @@DSPLY IF @BLD631 CALL $CR ;<631>Display carriage return ELSE LD A,CR ;Carriage return CALL $DSP ENDIF JR TAKEIT1 ;Go & move it ; QUERY LD HL,CONVQ ;"Convert file @@DSPLY ;Display it LD HL,QMARK ;"?" @@DSPLY LD HL,ABUFF ;Get answer LD BC,3<8 ;3 char max @@KEYIN JP C,$ABORT ;Abort if BREAK hit LD A,(HL) ;Check for 'Y' RES 5,A ;Force upper case CP 'Y' JP NZ,SKIPIT ;Skip it if not 'Y' ; ; If file exists, query user ; LD A,(FCB2) ;Was file opened ok? BIT 7,A ;Z = not found JR Z,TAKEIT1 ;Go if it does not exist LD HL,EXISTQ ;"File exists, replace? @@DSPLY ;Print question LD HL,ABUFF LD BC,3<8 @@KEYIN ;Get answer JP C,$ABORT ;Abort if break LD A,(HL) ;Check answer RES 5,A ;Force uppercase CP 'Y' JP NZ,SKIPIT ;Skip if 'no' ; ; Init file if it didn't exist ; TAKEIT1 LD DE,FCB2 LD A,(DE) ;Was file opened? BIT 7,A ;Z = not opened JR Z,$+5 ;Remove existing file @@REMOV ; for new LRL LD DE,FCB ;Use other FCB now LD HL,TBUFF ;Create file LD B,(IX+4) ;P/U Mod III LRL @@INIT ;Create the file IF @BLD631 JR NZ,TOIOERR ;<631>Go if error ELSE JP NZ,IOERR ;Go if error ENDIF PUSH DE ;Change LRL to 0 for copy EX (SP),IX ;IX to FCB start RES 7,(IX+1) ;Show full sector ops LD (IX+9),0 ;Show LRL=0 EX (SP),IX ;Switch back POP DE ; ; Initialize to read from source file ; TAKEIT2 POP HL ;Point to dir entry PUSH HL LD DE,20 ;Point to ERN ADD HL,DE LD E,(HL) ;P/U ERN INC HL LD D,(HL) INC HL ;Leave ptg to extents TRSDOS LD A,0 ;1.3 or later? CP 13H JR C,EARLY ;Go if earlier than 1.3 LD A,(IX+3) ;Pick up EOF offset AND A ;Zero? JR Z,EARLY ;No adjustment if so INC DE ;If nonzero, adjust ERN EARLY LD B,0 ;# sectors left in extent PUSH DE ;Save ERN EXX ;Switch to alternate regs ; ; Preallocate file ; POP BC LD A,B ;Empty file? OR C JR Z,READ ;Go if so DEC BC LD DE,FCB ;Point to FCB @@POSN ;Position to last sector JR Z,OK3 CP 1CH ;Ignore EOF errors JR Z,OK3 CP 1DH ; or past end errors IF @BLD631 TOIOERR: ENDIF JP NZ,IOERR ;Quit on any others OK3 @@WRITE ;Write it IF @BLD631 JR NZ,TOIOERR ;<631>Quit on write error ELSE JP NZ,IOERR ;Quit on write error ENDIF @@REW ;Position to start IF @BLD631 JR NZ,TOIOERR ;<631> ELSE JP NZ,IOERR ENDIF ; ; Read sectors ; IF @BLD631 READ LD HL,TBUFF ;<631>Point to transfer buffer LD B,L ;<631>Count sectors read (L=0) ELSE READ LD B,0 ;Count sectors read LD HL,TBUFF ;Point to transfer buffer ENDIF LD DE,$-$ MYHIGH EQU $-2 ;Stuff HIGH$ value DEC D ;256 bytes back GETONE CALL GETSEC ;Get next sector JR NZ,WRITE ;Go if EOF INC B ;Count sector INC H ;Point to next spot CALL CPHLDE ;Compare HL and DE LD A,0 ;No error code JR NC,WRITE ;Go if mem full JR GETONE ; else loop for more ; ; Write sectors to destination file ; WRITE PUSH AF ;Save completion type LD DE,FCB ;Point to file fcb LD HL,TBUFF ;Point to transfer buffer WRLOOP LD (FCB+3),HL ;Point FCB to buffer LD A,B ;Zero to write? AND A JR Z,WRDUN ;Go if so @@WRITE ;Write to file IF @BLD631 JR NZ,TOIOER2 ;<631>Quit on write error ELSE JP NZ,IOERR ;Quit on write error ENDIF INC H DJNZ WRLOOP ;Loop till done ; ; Were we at EOF? ; WRDUN POP AF ;Restore completion type AND A ;At end of file? JR Z,READ ;Go if not ; ; Copy over EOF offset ; LD A,(IX+3) ;P/U offset from dir LD (FCB+8),A ;Put into FCB @@CLOSE ; and close the file IF @BLD631 TOIOER2:JR NZ,IOERR ;<631>Quit on close error ELSE JP NZ,IOERR ;Quit on close error ENDIF ; ; Increment to next entry and loop if not done ; SKIPIT POP HL LD DE,48 ;48 bytes per entry ADD HL,DE LD A,L ;End of sector? CP 0F0H JR NZ,NOTEOS ;Go if not INC H IF @BLD631 LD L,D ;<631>D==0 ELSE LD L,0 ENDIF NOTEOS LD DE,TBUFF ;Done? CALL CPHLDE ;CP HL,DE JP C,ELOOP ;Loop back if not done ; ; Finished ; IF @BLD631 CALL $CR ;<631>Blank line ELSE LD A,CR ;Blank line CALL $DSP ENDIF CALL BYEBYE ;Restore DCT JP $EXIT ; QUIT CALL BYEBYE ;Restore DCT IF @BLD631 JR TOABORT ;<631> ELSE JP $ABORT ENDIF ; ; Error routines ; IOERR CALL BYEBYE ;Restore DCT IOERR1 LD L,A ;Entry from PRMERR LD H,0 OR 0C0H ;Abbrev, return LD C,A ;Error code to C @@ERROR ; for error display JP $QUIT ; BYEBYE PUSH IY ;Move back DCT POP DE LD HL,SAVDCT ;Point to save area LD BC,10 LDIR RET ; PRMERR LD A,44 ;Init "parameter error JR IOERR1 PERR1 @@LOGOT ;Display and log IF @BLD631 TOABORT: ;<631> ENDIF JP $ABORT ; ; Sector read routine ; GETSEC EXX ;P/U alt registers LD A,D ;Any records left? OR E JR NZ,NOTEND ;Go if so BDEXT EXX LD A,1CH ;EOF code AND A ;Set NZ condition RET ; NOTEND XOR A ;Check if used up ext OR B JR NZ,MORE ;Go if not used up LD A,(HL) ;Check next trk# CP 0FFH ;Non-allocated? JR Z,BDEXT ;Then consider EOF PUSH DE ;Save DE' LD D,(HL) ;P/U track number INC HL LD B,(HL) ;P/U other stuff INC HL LD A,B ;Get starting gran RLCA RLCA ;Move to bits 0-2 RLCA AND 7 ;Mask off other garbage LD E,A ;Multiply by 3 RLCA ADD A,E INC A ;Offset from 0 LD E,A ; and move to E reg LD (TRKSEC),DE ;Save for later POP DE ;Restore DE' LD A,B ;Get number of grans AND 1FH LD B,A ;Multiply by 3 RLCA ADD A,B LD B,A ;And put in B reg ; ; Read sector ; MORE DEC B ;Count down # sec in ext DEC DE ;Count down # records EXX ;Restore primary set PUSH DE ;Save DE PUSH BC ;Save BC LD DE,(TRKSEC) ;P/U track and sector # LD A,(SDRIVE) ;P/U source drive LD C,A LD (IY+7),18 ;Reset sec/trk each time @@RDSEC ;Read sector to (HL) JR Z,OK2 ;Go if no errors CP 6 ; or address mark differs JP NZ,IOERR ;Quit on any other OK2 INC E ;Step to next sector LD A,E CP 19D ;End of track? JR NZ,NOTEOT ;Go if not LD E,1 ;Reset to sector 1 INC D ;Next track NOTEOT LD (TRKSEC),DE POP BC POP DE XOR A RET ; ; Parsing subroutines ; GETDRV2 LD A,(HL) CP ':' LD A,0FFH ;'Not entered' value RET NZ ;If no second drive, give DIR ; GETDRV LD A,(HL) ;Parse drivespec CP ':' JR NZ,PRMERR ;Go if missing INC HL LD A,(HL) ;P/U drivespec IF @BLD631 SUB '0' ;<631> CP 7+1 ;<631>Be sure it is a digit JR NC,PRMERR ;<631> INC HL ;<631>Bump cmdline ptr ELSE CP '0' ;Be sure digit JR C,PRMERR CP '7'+1 JR NC,PRMERR INC HL ;Bump cmdline ptr AND 7 ;Make drive # binary ENDIF RET ; SKIPSP LD A,(HL) ;Skip spaces CP ' ' RET NZ INC HL JR SKIPSP ; SKIPLT LD A,(HL) ;Skip letters/digits/$ CALL CHKLET ;Check letter/digit/$ RET NZ INC HL JR SKIPLT ; MOVELT LD A,(HL) ;Move letters/digits/$ CALL CHKLET RET NZ INC HL ;Inc from buffer LD (DE),A ;Store INC DE ;Inc to buffer JR MOVELT ; CHKLET BIT 7,A ;Graphic? RET NZ CP 'a' ;Lowercase? JR C,NOTLC ;Go if not RES 5,A ; else make upper case NOTLC CP '$' ;Dollar sign? RET Z CP '0' ;Digit? RET C ;Return (NZ) if less CP '9'+1 JR NC,NOTDIG ;Go if not digit CP A ;Mark as letter/digit/$ RET NOTDIG CP 'A' ;Letter? RET C ;Return (NZ) if less CP 'Z' RET NC ;Z if =Z, NZ if >Z CP A ;Z if name NMDSP LD A,(HL) ;Get a character CP ETX ;Are we done? JR Z,NMEND ;Finish if so CALL $DSP ;Print this char INC C ;Count it INC HL ;=>next char JR NMDSP ;Until ETX ; NMEND LD HL,$-$ ;P/u line/char count CCOUNT EQU $-2 LD A,C ;Count for this entry ADD A,L ;Add to previous LD L,A ;Save posn LD A,16 ;Spaces for entry SUB C ;Less used LD B,A ;Remaining to B SPLP LD A,' ' ;Pad remaining w/spaces CALL $DSP INC L ;Count it LD A,L ;Check char posn CP 78 ;End of line? JR Z,ELINE ;Then print CR DJNZ SPLP ; else keep going ; ESHOW LD (CCOUNT),HL ;Save line/char posn POP BC ;Restore regs POP DE POP HL RET ;Done w/entry ; IF @BLD631 ELINE: CALL $CR ;<631>Hit end of line ELSE ELINE LD A,CR ;Hit end of line CALL $DSP ENDIF INC H ;Bump line posn LD L,0 ;Start on next LD A,23 ;Max lines CP H ;There yet? JR NZ,ESHOW ;Nope @@KEY ;Wait for a key IF @BLD631 LD A,HOME ;<631>Cursor home CALL $DSP ;<631> LD A,CLR ;<631>Clear to end-of-frame CALL $DSP ;<631> ELSE CALL $CLS ;Clear the display ENDIF LD HL,0 ;Restart count JR ESHOW ; IF @BLD631 ELSE $CLS LD A,HOME ;Cursor home CALL $DSP LD A,CLR ;Clear to end-of-frame JP $DSP ENDIF ; CKEARLY DB 0 LD A,(DBUFF+22H) ;Get type byte CP 0FFH ;Do we know this one? RET Z ;OK to continue LD A,(DDRIVE) ;Doesn't matter if INC A ; only doing DIR RET Z LD HL,EARLYD ;Err msg JP PERR1 ;Quit ; IF @BLD631 CPYFCB: LD A,ETX ;<631> LD (DE),A ;<631> EX DE,HL ;<631> LD HL,FCB ;<631> LD BC,32 ;<631> LDIR ;<631> RET ;<631> ; ENDIF PRMTBL$ DB 80H DB ABB!FLAG!5 DB 'QUERY',0 DW QPARM+1 DB ABB!FLAG!3 DB 'SYS',0 DW SPARM+1 DB ABB!FLAG!3 DB 'INV',0 DW IPARM+1 DB ABB!FLAG!3 DB 'VIS',0 DW VPARM+1 DB ABB!FLAG!3 DB 'OLD',0 DW OPARM+1 DB ABB!FLAG!3 DB 'NEW',0 DW NPARM+1 DB ABB!FLAG!3 DB 'DIR',0 DW DPARM+1 NOP ; ; Messages and buffers ; NOTPRM DB 0 PATTRN DB '$$$$$$$$' PATEXT DB '$$$' HELLO$ DB 'CONV' *GET CLIENT:3 NOTONE DB 'Source and Destination drives are the same',CR NOT0 DB 'Source cannot be drive 0',CR IF @BLD631 EARLYD DB 'Can''t CONV Protected Disk',CR ELSE EARLYD DB 'Cannot CONV Protected Diskette',CR ENDIF IF @BLD631 EXISTQ DB ' File exists -- replace it' ;<631> QMARK DB '? ',ETX ;<631> ELSE QMARK DB '? ',ETX EXISTQ DB ' File exists -- replace it? ',ETX ENDIF CONVS DB 'Converting file: ',ETX CONVQ DB 'Convert file ' FNAME DS 32 ;Must follow CONVQ FCB DS 32 ;For INIT/WRITE FCB2 DS 32 ;For OPEN (test for already existing) SDRIVE DS 1 DDRIVE DS 1 TRKSEC DS 2 ABUFF DS 5 SAVDCT DS 10 ORG $<-8+1<8 DBUFF DS 1000H ;16 sectors of directory TBUFF EQU $ ;To end of memory ; END BEGIN