; ; extend.asm: v1.0 ; usage: APPEND ; appends to end of file ; ; Intended mainly to illustrate a fast file-append ; algorythm, but may be useful as a quick-update ; notations file handler ; ; 09/13/81 Ron Fowler, Westland MI ; ; CHARACTER EQUATES ; CR EQU 13 ;CARRIAGE RETURN LF EQU 10 ;LINEFEED EOF EQU 1AH ;END OF FILE ; ; CPM EQUATES ; CPBASE EQU 0 ;SET TO 4200H FOR ALT CPM BDOS EQU CPBASE+5 ;BDOS ENTRY POINT PRINTF EQU 9 ;PRINT STRING FUNCTION OPENF EQU 15 ;OPEN FILE FUNCTION CLOSEF EQU 16 ;CLOSE FILE FUNCTION MAKEF EQU 22 ;MAKE NEW FILE FUNCTION READF EQU 20 ;READ RECORD WRITEF EQU 21 ;WRITE RECORD SDMAF EQU 26 ;SET DMA FUNCTION ; TPA EQU CPBASE+100H ;TRANSIENT PROGRAM AREA DFCB EQU CPBASE+5CH ;DEFAULT FILE CONTROL BLOCK DBUF EQU CPBASE+80H ;DEFAULT DISK BUFFER ; EX EQU 12 ;FCB EXTENT OFFSET FRC EQU 15 ;RECORD COUNT FCB OFFSET NR EQU 32 ;NEXT RECORD OFFSET ; ; PROGRAM CODE BEGINS HERE ; ORG TPA ; BASE: LXI H,0 ;SAVE THE STACK DAD SP SHLD STACK LXI SP,STACK MVI C,SDMAF ;SET DMA TO DBUF LXI D,DBUF CALL BDOS CALL MOVSTR ;MOVE THE STRING CALL ADVANC ;OPEN AND ADVANCE OUT FILE CALL WRLINE ;WRITE LINE TO OUTPUT FILE CALL CLOSE ;CLOSE OUTPUT FILE CALL ERRXIT ;EXIT WITH MESSAGE DB CR,LF DB '++ Done ++' DB CR,LF,'$' ERRXIT: POP D MVI C,PRINTF ;PRINT MESSAGE CALL BDOS EXIT: LHLD STACK ;RESTORE STACKPOINTER SPHL RET ; ; MOVE STRING INTO BUFFER ; MOVSTR: LXI H,DBUF+1 ;POINT TO START OF STRING CALL SCANB ;SKIP LEADING BLANKS CALL SCANC ;SKIP FILENAME CALL SCANB ;SKIP BLANKS AFTER FILENAME ; ; NOW AT STRING, TRANSFER TO BUFFER ; XCHG ;CMD LINE PTR IN DE LXI H,LINBUF ;POINT TO BUFFER MVLN: MVI M,EOF ;FIRST MARK POSSIBLE END LDAX D ;PICK UP BYTE OF LINE INX D ORA A ;TERMINATOR? RZ MOV M,A ;NO, MOVE IT INX H JMP MVLN ; ; SKIP BLANKS ; SCANB: MOV A,M ;GET CHAR ORA A ;TERMINATOR? RZ CPI ' ' ;BLANK? RNZ INX H JMP SCANB ;NO,SCAN MORE ; ; SKIP TO FIRST BLANK ; SCANC: MOV A,M ;GET CHAR ORA A ;TERMINATOR? RZ CPI ' ' ;GOT BLANK? RZ INX H JMP SCANC ;NO, SCAN MORE ; ; OPEN INPUT FILE AND ADVANCE TO END ; ADVANC: LXI D,DFCB MVI C,OPENF ;OPEN IT CALL BDOS INR A ;CHECK RESULT JNZ ADV1 ;EXISTS, GO SCAN IT MVI C,MAKEF ;DOESN'T EXIST, CREATE IT LXI D,DFCB CALL BDOS INR A ;TEST RESULT JNZ MAKEOK CALL ERRXIT ;BAD MAKE DB CR,LF DB '++ Can''t create file ++' DB CR,LF,'$' MAKEOK: MVI A,80H ;NEW FILE BUF POINTER STA BUFPTR RET ADV1: LDA DFCB+FRC ;GET RECORD COUNT CPI 80H ;FULL EXTENT? JNZ WIND LXI H,DFCB+EX ;YES, TRY NEXT INR M LXI D,DFCB ;OPEN NEW EXTENT MVI C,OPENF CALL BDOS INR A ;GOOD OPEN? JNZ ADV1 ;YES, KEEP SCANNING BACKEX: LXI H,DFCB+EX ;NO, RE-OPEN PREV DCR M JP BACKOK ;TEST CASE OF EMPTY FILE INR M ;GET BACK TO EXTENT 0 JMP MAKEOK ;AND PRETEND WE MADE IT BACKOK: MVI C,OPENF LXI D,DFCB CALL BDOS ;CAN'T GET AN ERROR HERE LDA DFCB+FRC WIND: DCR A ;MAKE ZERO RELATIVE JM BACKEX ;AN EXTENT WITH 0 RECS? STA DFCB+NR ;SET RECORD TO READ MVI C,READF ;NOW READ IT LXI D,DFCB CALL BDOS ;CAN'T GET ERROR HERE LDA DFCB+NR ;SEE IF NEW EXTENT ORA A JNZ FIXRC ;NO, GO RESET REC CNT LXI H,DFCB+EX ;SIGH...HAVE TO REOPEN PREV DCR M LXI D,DFCB MVI C,OPENF CALL BDOS ;CAN'T GET ERROR HERE LDA DFCB+FRC FIXRC: DCR A ;RESET NEXT REC STA DFCB+NR ; ; NOW SCAN SECTOR IN DBUF FOR EOF MARK ; LXI H,DBUF MVI B,128 ;SCAN LIMIT EOFSC: MOV A,M ;PICK UP A CHAR CPI EOF JZ GOTEOF INX H ;NOT YET DCR B JNZ EOFSC ;CONTINUE SCAN CALL ERRXIT ;??? NO EOF IN LAST SECTOR DB CR,LF DB '++ No EOF in last sector ++' DB CR,LF,'$' GOTEOF: MOV A,L ;USE LO BYTE FOR BUF PTR STA BUFPTR RET ; ; WRITE LINE TO OUTPUT FILE ; WRLINE: LXI H,LINBUF WRLP: MOV A,M CPI EOF ;LINE END? JZ WREND PUSH H ;SAVE LINE POINTER CALL WRBYTE ;WRITE IT POP H INX H JMP WRLP WREND: MVI A,CR ;WRITE TERMINATING CR/LF CALL WRBYTE MVI A,LF ; ; WRITE A BYTE TO THE OUTPUT FILE ; WRBYTE: PUSH PSW ;SAVE OUTPUT BYTE LDA BUFPTR ;GET BUFFER POINTER ORA A ;CHECK FOR WRAP CZ WRSEC ;WRAPPED, WRITE RECORD LXI H,DBUF ;GET ADDRESS OF DISK BUFFER MOV L,A ;OFFSET TO POINTER INR A ;BUMP POINTER STA BUFPTR POP PSW ;RETRIEVE OUTPUT BYTE MOV M,A ;STORE IT RET ; ; WRITE A DISK SECTOR ; WRSEC: MVI C,WRITEF ;BDOS WRITE SEC FUNCTION LXI D,DFCB CALL BDOS ORA A ;TEST RESULT MVI A,80H ;(LOAD NEW BUF PTR) RZ CALL ERRXIT ;PRINT DIAGNOSTIC AND EXIT DB CR,LF DB '++ Disk full ++' DB CR,LF,'$' ; ; PAD OUT THE EXISTING BUFFER WITH EOF'S, THEN CLOSE ; CLOSE: MVI A,EOF ;WRITE AN EOF CALL WRBYTE LDA BUFPTR ;CHECK FOR SECTOR PAD ORA A ;SPILLED TO NEXT SECTOR? JNZ CLOSE ;NOT, THEN KEEP PADDING MVI C,WRITEF ;WRITE THE LAST SECTOR LXI D,DFCB CALL BDOS MVI C,CLOSEF LXI D,DFCB ;DONE, CLOSE OUTPUT FILE CALL BDOS INR A ;CHECK RESULT RNZ CALL ERRXIT ;PRINT DIAGNOSTIC DB CR,LF DB '++ Can''t close output file ++' DB CR,LF,'$' ; ; DATA AREA ; LINBUF: DS 130 ;LINE BUFFER BUFPTR: DB 80H ;DISK BUFFER POINTER DS 128 ;STACK AREA STACK: DW 0 ;STACKPOINTER SAVE ; END BASE : DS 130 ;LINE BUFFER BUFPTR: DB 80H ;DISK BUFFER POINTER DS 128 ;STACK AREA STACK: DW 0 ;STACKPOINTER SAVE ;