; OFILEOPS.MAC VERS: 01.19 DATE: 06/10/87 TIME: 21:07 ; COPYRIGHT 1987 William P.N. Smith - Commercial use prohibited! ; ;Output file operations for writing in single byte chunks. ; ; The OOPEN routine will open the output file. On entry, the DE holds a ;pointer to an FCB-like data structure. The first 16 bytes will be copied out ;into a private FCB and the file will be opened. If the file already exists, ;the operator will be given the option of deleting it or aborting the program. ;Note that OOPEN _must_ be called before making calls to PUTBYT. OOPEN will ;do anything it likes to your registers except tie them in knots, and it might ;do that if it feels like it. ; ; The PUTBYT routine will stuff bytes into the output file buffer and ;flush the buffer to disk when it fills up. If the disk fills up, an error ;message will be displayed and CP/M will be rebooted. The byte will be passed ;to the PUTBYT routine in the A register. No registers will be disturbed. ; ; The OCLOSE routine will fill the remainder of the output file buffer ;with zeros, flush the buffer to disk, and close the file. It must be called ;at the end of the main program to ensure that all data gets written to the ;output file. OCLOSE does not guarantee the safety of any registers. TRUE EQU 0FFH FALSE EQU 00H ZERO EQU 00H BOOT EQU 0000H ;reboot CP/M CR EQU 0DH LF EQU 0AH NULL EQU 00H BDOS EQU 0005H ;jump to BDOS DEBUG EQU FALSE ;quiet please! ;------------------------------------------------------------------------------ ; OOPEN open the output file OOPEN:: LD A,(OFIO) ;get 'file open' flag CP ZERO ;is it already open? JR Z,MOVFCB ;nope, ask him for the name FAO: LD DE,FAOERR ;tell the console CALL STROUT## LD DE,OFCB ;show him the file name CALL PFN## LD DE,FE2 ;tell him what went wrong CALL STROUT## JP BOOT ;and reboot CP/M FAOERR: DB CR,LF DB 'Programming error - file ' DB NULL,'$' FE2: DB ' already open in OOPEN module!' DB CR,LF,NULL,'$' MOVFCB: EX DE,HL ;source from passed parameter LD DE,OFCB ;destination is output file control block LD BC,16 ;16 bytes to move LDIR ;move them WLDCHK: LD HL,OFCB ;start at output FCB LD BC,16 ;check each of those bytes LD A,'?' ;look for wild card CPIR JR NZ,NOWILD ;if not found, skip the error message ISWILD: LD DE,OWERR ;tell the console CALL STROUT## JP BOOT ;and reboot CP/M OWERR: DB CR,LF DB 'Error - no wild cards allowed! Abort in OOPEN module.' DB CR,LF,NULL,'$' NOWILD: LD DE,OBUFR ;just somewhere to dump the directory buffer LD C,1AH CALL BDOS ;set up DMA area LD DE,OFCB ;point at the FCB LD C,11H ;search for first CALL BDOS CP 0FFH ;if not found, we will get FF JR Z,MAKFIL ;if not found, OK to make the file ISOLD: LD DE,CONF ;tell the operator there's a conflict CALL STROUT## LD DE,OFCB ;print file name of file CALL PFN## LD DE,QUERY ;ask him about it CALL STROUT## LD C,01H ;get console byte CALL BDOS RES 5,A ;convert to upper case CP 'Y' ;only if yes JP NZ,BOOT ;if anything else, restart CCP LD DE,OFCB ;kill the output file name CALL DELETE## JR MAKFIL ;and make a new file CONF: DB CR,LF DB 'File exists! Overwrite ' DB 00H,'$' QUERY: DB ' ? ' DB 00H,'$' MAKFIL: LD DE,OFCB ;point at the output file control block LD C,16H ;make_file command CALL BDOS CP 0FFH ;FF if no disk or directory space JR NZ,MADEIT MKFAIL: LD DE,MKERR ;tell the operator CALL STROUT## JP BOOT MKERR: DB CR,LF DB 'Fatal error - disk or directory full in OOPEN module!' DB CR,LF,NULL,'$' MADEIT: LD A,0FFH ;set the flag for Output File Is Open LD (OFIO),A LD A,00H ;set up write pointer LD (OPOINT),A RET ;and run along ;------------------------------------------------------------------------------ ; PUTBYT stuff a byte into the output file PUTBYT::PUSH AF ;save everything PUSH BC PUSH DE PUSH HL PUSH AF ;store the incoming byte a sec LD A,(OFIO) ;get file-is-open flag CP ZERO ;is it? JR NZ,WASOPN ;yes, continue NOTOP: LD DE,FNO ;tell the console CALL STROUT## JP BOOT ;and reboot CP/M FNO: DB CR,LF DB 'Programming error - ' DB 'file was not opened in PUTBYT module!' DB CR,LF,NULL,'$' WASOPN: LD HL,OBUFR ;point at the output buffer LD A,(OPOINT) ;get the pointer ADD A,L ;add them together LD L,A JR NC,PB2 ;if no carry, skip the increment INC H ;'add one' to upper byte PB2: POP AF ;get the byte back LD (HL),A ;stuff it into the buffer LD A,(OPOINT) ;get the pointer CP 127 ;did we just fill the buffer? JR Z,FLUSH ;yup, flush the buffer INC A ;else bump the pointer LD (OPOINT),A ;and put it back PBEX: POP HL ;recover everything POP DE POP BC POP AF RET ;and run along FLUSH: LD A,00H ;reset the pointer LD (OPOINT),A IF DEBUG LD E,'O' ;tell him you are writing another output sector LD C,02H CALL BDOS ENDIF LD DE,OBUFR ;point the default DMA area at the buffer LD C,1AH CALL BDOS LD DE,OFCB ;point at output FCB LD C,15H ;write_sequential command CALL BDOS CP 00H ;zero means no error JR Z,PBEX PBERR: LD DE,WRERR ;tell the operator CALL STROUT## JP BOOT ;and reboot CP/M WRERR: DB CR,LF DB 'Write error - Disk Full in PUTBYT module!' DB CR,LF,NULL,'$' ;------------------------------------------------------------------------------ ; OCLOSE close out the output file OCLOSE::LD A,(OFIO) ;get the 'file is open' flag CP ZERO ;is it? JR NZ,WSOPN ;yup, go ahead and close it LD DE,OFNO ;tell the console CALL STROUT## JP BOOT ;and reboot CP/M OFNO: DB CR,LF DB 'Programming error - ' DB 'file was not opened in OCLOSE module!' DB CR,LF,NULL,'$' WSOPN: LD A,(OPOINT) ;get number of bytes in the buffer CP ZERO ;empty? JR Z,OCLS ;yup, don't bother with the fill LD B,A ;hold onto that for a sec LD A,128 ;get size of buffer SUB B ;calculate number of bytes to go LD B,A ;put into magic counter ;make up the pointer LD HL,OBUFR ;point at the output buffer LD A,(OPOINT) ;get the pointer ADD A,L ;add them together LD L,A JR NC,CL3 ;if no carry, skip the increment INC H ;'add one' to upper byte CL3: LD A,00H ;stuff a zero OCLP: LD (HL),A ;stuff one byte INC HL ;bump the pointer DJNZ OCLP ;do that till buffer is full OCEX: LD DE,OBUFR ;point the default DMA area at the buffer LD C,1AH CALL BDOS LD DE,OFCB ;point at output FCB LD C,15H ;write_sequential command CALL BDOS CP 00H ;zero means no error JR Z,OCLS ;so close the file CLERR: LD DE,FLERR ;tell the operator CALL STROUT## JP BOOT ;and reboot CP/M FLERR: DB CR,LF DB 'Write error - Disk Full during flush in OCLOSE module!' DB CR,LF,NULL,'$' OCLS: LD DE,OFCB ;point at output FCB LD C,10H ;close_file command CALL BDOS CP 0FFH ;FF means error JR NZ,OCLX ;else everything's OK CLSFL: LD DE,CLSERR ;tell the console the close failed CALL STROUT## JP BOOT CLSERR: DB CR,LF DB 'Fatal error - File will not close in OCLOSE module!' DB CR,LF,NULL,'$' OCLX: LD A,ZERO ;mark file as not open LD (OFIO),A RET ;and run along ;------------------------------------------------------------------------------ ;some data areas. ; output file control block OFCB: DS 36 ;max size OFIO: DB 00H ;output file is open flag (open if FF) OBUFR: DS 128 ;128 byte sector buffer OPOINT: DB 00H ;pointer (offset) to next byte to write .REQUEST delete,strout,pfn END