TITLE '"PASTOCPM" - Convert Pascal file to CP/M file' ;From DR. DOBB'S - August 1979 ;Copyright (C) 1979 Ronald G. Parsons ;Modified by T. Mueller 9/1/79 ; Changes include: ; Provisions for designating disk drives. ; Re-ordering calls to disk routines to be of the form: ; select disk, select track, select sector, read/write. ; Cleaned up handling of null codes in .TEXT files. ; Set up new stack area and data buffers. ; Changed exit to simple return, no re-boot. ; Guaranteed .TEXT file on CP/M disk ends in EOF. ; Memory size independance for BIOS calls. ;9/22/79 - Corrected handling of DLE as last byte of read block. ; ;Transfers a Pascal file to CP/M file. ; ;Syntax -- PASTOCPM <[d:]CP/M filename> <[d:]Pascal filename> ; ;Disk drive (d:) identifiers may be entered. If none are supplied ; defaults are: CP/M file on logged drive, Pascal file on drive B:. ; ;Transfers the Pascal filename on a Pascal disk ; to the CP/M filename on a CP/M disk. If the CP/M file already exists, ; you will be asked for permission to overwrite. ;If the Pascal file is a .TEXT file, then two blocks are skipped ; and tabs replaced by spaces. LF is added after each CR. ;If the Pascal file is a .CODE file, then one block is skipped. ;If file is neither .TEXT or .CODE, the copy is exact. ; ; DLE EQU 10H DENTSZ EQU 26 ;DIRECTORY ENTRY SIZE IN BYTES DTITLE EQU 6 ;OFFSET TO ENTRY TITLE ; ORG 100H START LXI H,0 DAD SP SHLD STACK LXI SP,STACK ;SET UP PRIVATE STACK ; MVI C,LOGGED ;GET LOGGED DISK DRIVE CALL BDOS STA LDRIVE LDA FCB ;GET CP/M DRIVE ORA A JNZ DOIT ;NOT LOGGED DRIVE LDA LDRIVE ;GET LOGGED DRIVE INR A STA FCB ;FORCE SELECTION OF DRIVE DOIT LXI H,BUFF ;GET PASCAL FILE NAME LXI D,SYSTLE+1 MVI A,1 STA RDRIVE ;SET PASCAL DEFAULT TO DRIVE B SCN1 CALL SCBLK ;FIND NON-BLANK JZ SCN1 SCN2 CALL SCBLK ;FIND BLANK JNZ SCN2 SCN3 CALL SCBLK ;FIND START OF SECOND PARM JZ SCN3 INX H MOV A,M CPI ':' ;CHECK IF DRIVE ENTERED DCX H JNZ SCN4 MOV A,M ;GET DRIVE SUI 'A' STA RDRIVE ;SAVE READ DRIVE INX H INX H ;SKIP DRIVE SCN4 PUSH H LXI H,RDRIVE LDA FCB DCR A CMP M ;CHECK IF READ AND WRITE DRIVES ARE SAME POP H JZ DRVERR MVI C,0 PFN2 MOV A,M ORA A JZ PFN3 STAX D INX H INX D INR C JMP PFN2 ; PFN3 MOV A,C ;GET FILENAME LENGTH STA SYSTLE ORA A JZ NOFLNM ;CHECK FOR .TEXT OR .CODE FILENAME LXI D,TEXT+6 DCX H ;HL POINTS TO END OF FILENAME PUSH H MVI C,5 TEXTLP LDAX D CMP M JNZ NOTEXT ;FILENAME DOES NOT END IN .TEXT DCX H DCX D DCR C JNZ TEXTLP LXI H,TXTFLG ;GOT .TEXT FILE MVI M,2 LXI D,TEXT MVI C,WRITECB CALL BDOS ; NOTEXT POP H ;POINT TO END OF FILENAME LXI D,CODE+6 MVI C,5 CODELP LDAX D CMP M JNZ NOTCODE ;FILENAME DOES NOT END IN .CODE DCX H DCX D DCR C JNZ CODELP LXI H,TXTFLG MVI M,1 ;GOT .CODE FILE LXI D,CODE MVI C,WRITECB CALL BDOS ; NOTCODE LXI D,FCB MVI C,OPENF ;OPEN FILE CALL BDOS CPI 0FFH ;NON-EXISTANT? JZ CREF ;YES - CREATE IT LXI D,PERMSG ;GET PERMISSION TO DELETE IT MVI C,WRITECB CALL BDOS ; RDCHR MVI C,READC ;READ CONSOLE CALL BDOS CPI ABORT JZ EXIT CPI CR JNZ RDCHR ;INVALID RESPONSE, TRY AGAIN MVI E,LF MVI C,WRITEC ;CHARACTER TO CONSOLE CALL BDOS LXI D,FCB MVI C,DELETEF ;KILL FILE CALL BDOS ; CREF LXI D,FCB MVI C,CREATEF ;CREATE FILE CALL BDOS CPI 0FFH ;ERROR? JZ CERROR ;YES ; ;INITIALIXE BUFFER POINTERS ; INIT LXI H,BUFF SHLD BOL LXI H,BUFF+127 SHLD EOB LXI H,BLKBUF+512 SHLD BUFADD ; LXI B,DIRTOP ;READ DIRECTORY INTO THIS CALL READ$DIR ; LXI H,DIRTOP ;SET DIRECTORY ENTRY POINTER LXI D,DENTSZ ; TO FIRST ENTRY AFTER VOLUME NAME DAD D SHLD DENTP ; CALL FIND$FILE ;FIND THE FILE ; LHLD DENTP ;START OF DIRECTORY ENTRY MOV E,M INX H MOV D,M PUSH D ;SAVE FIRST BLOCK INX H MOV E,M INX H MOV D,M XCHG ;LAST BLOCK+1 IN HL DAD H ;X2 DAD H ;X4 SHLD LSTLSN ;(LAST LSN + 1) * 4 POP H ;GET FIRST BLOCK LDA TXTFLG SKPBL1 DCR A ;SKIP BLOCKS DEPENDING ON JM SKPBL2 ; .TEXT OR .CODE INX H JMP SKPBL1 ; SKPBL2 DAD H ;X2 DAD H ;X4 SHLD LSN ;(FIRST LSN) * 4 ; LR80B CALL R80B ;READ 128 BYTES LDA EOFFLAG ORA A ;LAST PASCAL SECTOR READ? JNZ FILL1A ;YES CALL WB ;WRITE BUFFER JMP LR80B ; FILL1A CALL CT ;FILL BUFFER WITH EOF CALL WB ;WRITE BUFFER LDA TXTFLG CPI 2 ;.TEXT? JNZ FILL2 ;NO LHLD EOB MOV A,M CPI EOF ;CHECK IF LAST SECTOR WRITTEN HAS EOF JZ FILL2 LXI H,BUFF SHLD BOL JMP FILL1A FILL2 LXI D,FCB MVI C,CLOSEF ;CLOSE FILE CALL BDOS EXIT LXI D,BUFF MVI C,DMAADD CALL BDOS LDA LDRIVE ;GET LOGGED DRIVE MOV E,A MVI C,SELECTD ;RESTORE LOGGED DRIVE CALL BDOS LHLD STACK SPHL ;RESTORE SP RET ;JOB DONE - GO BACK ; ;********************************************************* ; ; SUBROUTINES ; ;********************************************************* ; ;READ DIRECTORY'S 4 BLOCKS TO BUFFER ;BUFFER ADDRESS IS ALREADY IN REG-BC ; READ$DIR: MVI E,4 ;DIRECTORY IS 4 BLOCKS LONG LXI H,2 ; AND STARTS AT BLOCK 2 CALL SYSRD ;GET IT RET ; ; FIND$FILE: MVI C,77 ;STOP AFTER THE 77'TH ENTRY LHLD DENTP ;GET STARTING ENTRY FI$SCH$LP: LXI D,DTITLE ;ADVANCE TO TILTE STRING DAD D LXI D,SYSTLE ;SET REG-DE TO COMPARISON STRING LDA SYSTLE ;COMPARISON LENGTH INR A ;COMPARE INCLUDES LENGTH BYTE MOV B,A FI$CMP$LP: LDAX D CMP M JNZ FI$CONT ;IT'S NOT THIS ONE INX D INX H DCR B ;CHECK FOR END OF STRING JNZ FI$CMP$LP ;NOT YET JMP FI$FOUND ;FOUND IT ; FI$CONT: LHLD DENTP ;ON TO THE NEXT ENTRY LXI D,DENTSZ DAD D SHLD DENTP DCR C ;IS THERE ANY DIRECTORY LEFT? JNZ FI$SCH$LP ;YES FI$HANG: JMP NOFILE ;FILE NOT THERE ; FI$FOUND: RET ;GOT IT ; ; ;READ BLOCKS FROM PASCAL DISKETTE ; SYSRD PUSH D ;SAVE BLOCK COUNT PUSH H ; AND BLOCK NUMBER CALL READ$RX ;BUFFER IS ADVANCED BY 512 BYTES POP H POP D INX H ;ADVANCE TO NEXT BLOCK DCR E ;SEE IF WE'RE DONE JNZ SYSRD RET ; ; ;READ A PASCAL BLOCK ; READ$RX: DAD H ;THERE ARE 4 SECTORS TO A BLOCK DAD H ;MULT LOGICAL BLOCK BY 4 MVI E,4 RR$LP PUSH B ;SET BUFFER ADDRESS PUSH D PUSH H CALL SETDMA POP H ;NOW COMPUTE TRACK/SECTOR PUSH H CALL MAP ;CONVERTS LOGICAL SECTOR IN HL PUSH H LDA RDRIVE MOV E,A MVI C,SELECTD ;SELECT READ DISK CALL BDOS POP H MOV C,H ; INTO TRACK H, SECTOR L PUSH H CALL SETTRK POP H MOV C,L CALL SETSEC CALL READ ORA A JNZ RWERR POP H POP D POP B PUSH H ;ADVANCE THE BUFFER ADDRESS LXI H,128 DAD B MOV B,H MOV C,L POP H INX H ;ADVANCE THE BLOCK COUNT DCR E ;SEE IF WE CONTINUE JNZ RR$LP ;YES RET ; ; ;READ SECTOR GIVEN BY LSN ; RDSEC MVI C,DMAADD CALL BDOS LHLD LSN CALL MAP ;CONVERT LOGICAL SECTOR # TO TRACK/SECTOR MOV C,H PUSH H CALL SETTRK POP H MOV C,L CALL SETSEC CALL READ ORA A JNZ RWERR LHLD LSN INX H SHLD LSN RET ; ;CLEAR TO END OF BUFFER ; CT LHLD EOB INX H XCHG LHLD BOL CT1 CALL EQUAL RZ MVI M,EOF INX H JMP CT1 ; EQUAL MOV A,L CMP E RNZ MOV A,H CMP D RET ;ZERO IF DE=HL ; ;READ A SECTOR TO BUFFER ; R80B MVI B,128 LXI H,BUFF R80B1 PUSH B PUSH H CALL RB POP H POP B PUSH PSW LDA EOFFLAG ORA A JZ R80B2 ;NOT EOF POP PSW SHLD BOL RET ; R80B2 POP PSW MOV M,A INX H DCR B JNZ R80B1 RET ; ;WRITE 128 BYTE BUFFER ; WB LXI D,BUFF MVI C,DMAADD CALL BDOS LXI D,FCB MVI C,WRITER CALL BDOS ORA A JNZ RWERR RET ; ;SCAN FOR BLANKS IN COMMAND LINE ; SCBLK INX H MOV A,M CPI 0 ;CHECK IF END OF INPUT LINE JZ NOFLNM CPI ' ' RET ; ;PROCESS LF AND TAB FILL, GET BYTE FROM READ BUFFER ; RB LDA TXTFLG CPI 2 JNZ RBFB ;NOT .TEXT RCCKLF LDA NLF ;NEED LF? ORA A JZ RBCKTB XRA A STA NLF MVI A,LF RET ; RBCKTB LDA NTB ;NEED TAB? ORA A JZ RBFB DCR A STA NTB MVI A,' ' RET ; ;GET BYTE FROM READ BUFFER, AND FILL IF NEEDED ; RBFB LHLD BUFADD LXI D,BLKBUF+512 CALL EQUAL ;CHECK FOR END OF BUFFER JZ RBLK LDA TXTFLG CPI 2 ;.TEXT? JNZ NOTEXT2 LDA DFLAG ;WAS LAST CHAR DLE? ORA A JNZ RBFBT ;YES MOV A,M ORA A INX H SHLD BUFADD JZ RBFB ;SKIP BYTE OF ZERO CPI CR JNZ CKDLE STA NLF ;PUT LF AFTER CR RET ;PROCESS BYTE FOLLOWING DLE ; RBFBT MOV A,M INX H SHLD BUFADD SUI 32 ;GET INDENTATION STA NTB ;SAVE NUMBER OF COLUMNS TO INDENT XRA A STA DFLAG ;CLEAR TAB FLAG JMP RBCKTB ;DO BLANK EXPANSION ; ;CHECK FOR DLE CODE - USED FOR INDENTATION ; CKDLE CPI DLE RNZ STA DFLAG ;SET FLAG FOR DLE FOUND JMP RBFB ;GET NEXT BYTE (COUNT) ; NOTEXT2 MOV A,M INX H SHLD BUFADD RET ; ;READ 4 SECTORS (A PASCAL BLOCK) ; RBLK LHLD LSN ;GET START LOGICAL SECTOR NUMBER XCHG LHLD LSTLSN CALL EQUAL JZ SETEOF ;FOUND LAST SECTOR LDA RDRIVE ;GET READ DRIVE NUMBER MOV E,A MVI C,SELECTD ;SELECT DISK CALL BDOS LXI D,BLKBUF ;READ 4 SECTORS CALL RDSEC LXI D,BLKBUF+128 CALL RDSEC LXI D,BLKBUF+256 CALL RDSEC LXI D,BLKBUF+384 CALL RDSEC LXI H,BLKBUF SHLD BUFADD ;RESET POINTER TO START OF BUFFER JMP RBFB ; SETEOF LXI H,EOFFLAG MVI M,1 ;LAST SECTOR ALREADY READ RET ; ;ERROR MESSAGES ; NOFLNM LXI D,NOFLNMSG JMP GENERR ; NOFILE LXI D,NOFMSG JMP GENERR ; RWERR ORI '0' ;MAKE IT ASCII STA WERMSG LXI D,WERMSG GENERR MVI C,WRITECB CALL BDOS JMP EXIT ; CERROR LXI D,ERRMSG ORI '0' STA ERRMSG JMP GENERR ; DRVERR LXI D,DERMSG JMP GENERR ; ;TURN LSN INTO TRACK/SECTOR ; ;NOTE - TRACK 0 IS NOT USED, SO BLOCK 0 IS AT TRACK 1 SECTOR 1 ; ;ON ENTRY - REG-HL HAS LOGICAL BLOCK # * 4 = LOGICAL SECTOR # ;ON EXIT - REG-H HAS PHYSICAL TRACK ; REG-L HAS PHYSICAL SECTOR ; MAP PUSH B PUSH D CALL DIV26 MOV A,L ADD A MOV B,A MVI A,12 CMP L JNC MAPC INR B MAPC MOV C,E XRA A MOV D,A MOV H,A MOV L,B MVI A,6 MAP$LOOP: DAD D DCR A JNZ MAP$LOOP PUSH B CALL DIV26 POP B INR L MOV H,C INR H POP D POP B RET ; ; DIV26 LXI B,-26 MVI E,0FFH DIVL INR E DAD B MOV A,H ORA A JP DIVL LXI B,26 DAD B RET ; ; ; ;BIOS ENTRIES ; SETTRK LHLD 1 MVI L,1EH PCHL ; SETSEC LHLD 1 MVI L,21H PCHL ; SETDMA LHLD 1 MVI L,24H PCHL ; READ LHLD 1 MVI L,27H PCHL ; NOFLNMSG DB CR,LF,'ERROR - Missing file name$' NOFMSG DB CR,LF,'"Pascal" file does not exist$' WERMSG DB ' Read/Write ERROR$' PERMSG DB CR,LF,'"CP/M" file already exists.' DB CR,LF,'C/R to continue, CTRL-C to abort$' ERRMSG DB ' ERROR in file Create or Open$' TEXT DB CR,LF,'.TEXT file being processed$' CODE DB CR,LF,'.CODE file being processed$' DERMSG DB CR,LF,'ERROR - Both files on same drive$' ; ; TXTFLG DB 0 DENTP DS 2 EOFFLAG DB 0 NLF DB 0 NTB DB 0 DFLAG DB 0 BUFADD DS 2 LSN DS 2 LSTLSN DS 2 BOL DS 2 EOB DS 2 SYSTLE DS 22 RDRIVE DS 1 ;DRIVE FOR READ LDRIVE DS 1 ;LOGGED DRIVE ON ENTRY ; DS 64 ;STACK AREA STACK DS 2 ;ENTRY SP BLKBUF DS 512 DIRTOP DS 2048 ; ; ;CP/M EQUATES ; BDOS EQU 5 FCB EQU 5CH BUFF EQU 80H READC EQU 1 ;READ CONSOLE CHARACTER WRITEC EQU 2 ;WRITE CONSOLE CHARACTER WRITECB EQU 9 ;WRITE CONSOLE BUFFER SELECTD EQU 14 ;SELECT DRIVE OPENF EQU 15 ;OPEN FILE CLOSEF EQU 16 ;CLOSE FILE DELETEF EQU 19 ;DELETE FILE WRITER EQU 21 ;WRITE RECORD CREATEF EQU 22 ;CREATE FILE LOGGED EQU 25 ;GET LOGGED DRIVE DMAADD EQU 26 ;SET DMA ADDRESS ; CR EQU 0DH LF EQU 0AH ABORT EQU 3 ;CRTL-C EOF EQU 1AH ; END START