; SOFTEN.ASM ; ; ASCII to WordStar Filter ; ; Useage: ; ; A>soften ASCIIfile WSdocfile ; ; If the second character following a CR is a space, a tab or ; another CR the first CR is retained as a hard CR indicating ; the end of a paragraph. Otherwise, it is replaced with a ; soft CR. The resulting text can then be reformatted with ; WordStar's control-B command. Other characters go through ; unaffected. ; ; BDOS EQU 0005H ;basic equates FCB1 EQU 005CH FCB2 EQU 006CH TAIL EQU 0080H TAB EQU 09H CR EQU 0DH LF EQU 0AH ; ORG 0100H ;program starts here ; START: MVI C,9 ;select BDOS print string function LXI D,HELLO ; i.d. message CALL BDOS ; display it LDA TAIL ;check com tail count to see CPI 0 ; whether filenames were specified JNZ HERE ;yes, they were MVI C,9 ;no, so print directions LXI D,USAGE ; usage string CALL BDOS ; print it RET ;exit program, return to CCP ; USAGE DB CR,LF,'Usage:' DB CR,LF,' SOFTEN ASCIIfile WSdocfile',CR,LF,'$' HELLO DB CR,LF,'SOFTEN version 1.0 (2/2/88)',CR,LF,'$' EMSG DB 'SOFTEN I/O ERROR ... quitting',CR,LF,'$' ; HERE: LXI D,FCB1 ;point to 1st FCB ; (source file) CALL GCOPEN ;open it for reading JC IOERR ;complain if error LXI D,FCB2 ;point to 2nd FCB ; (destination) CALL PCOPEN ;open it for writing JC IOERR ;complain if error ; LOOP: CALL GETCH ;get a character JC IOERR ;complain if error CPI 1AH ;EOF? JZ DONE ;quit if at end of file CALL FILTER ;process it in some way JMP LOOP ;keep going ; DONE: CALL PCLOSE ;close the output file JC IOERR ;error? RET ;all finished ; IOERR: MVI C,9 ; BDOS print string function LXI D,EMSG ; error message CALL BDOS ; display it CALL PCLOSE ; close the output file RET ; ;Here is the ASCII to WordStar processing routine: ; FILTER: CPI CR ;is it a CR? JNZ FLT1 ;no, just go on CALL GETCH ;get the next char (LF?) JC FLTERR ;error? MOV D,A ;and save it CALL GETCH ;once more we want this one JC FLTERR ;error? MOV E,A ;save it too MOV A,D ;recover the first CALL UNGETC ;unget it MOV A,E ;now the second CALL UNGETC ;unget it too MOV A,E ;okay, here it is CPI CR ;here goes: is it a CR? JZ FLTH ;yes, make current CR HARD CPI ' ' ;or a space? JZ FLTH ;yes, HARD again CPI TAB ;or a tab? JZ FLTH ;yes, HARD again FLTS: MVI A,8DH ;no, use a SOFT CR here JMP FLT1 FLTH: MVI A,CR ;use a HARD CR FLT1: CALL PUTCH ;write the char out RNC ;return if all clear FLTERR: POP H ;ERROR, kill return to LOOP JMP IOERR ;and go here, instead RET ; ;Routine to get character from open file at GCFCB ;Returns char or EOF in A, and C for Error ;Modified for use with UNGETC ; GETCH: LDA BUFCNT ;check UNGETC buffer CPI 0 ;is it empty? JZ FGETCH ;if so go read file DCR A ;decrease count STA BUFCNT ;and put it back MOV E,A ;put count (less 1) in E MVI D,0 ;now D-E is 16-bit ; version LXI H,UGBUF ;point to buffer DAD D ;now HL points to eldest ; character MOV A,M ;get it STC CMC ;clear C flag RET ;and return FGETCH: ;put the old GETCH here PUSH H ;save registers PUSH D ; (so GETCH will be easy PUSH B ; to use) LDA GCFLG ;check EOF flag CPI 0 ;is it clear? JNZ GCEOF ;if not, at EOF LDA GCPOS ;get position count CPI 80H ;is it up to 128? JC GCCHR ;no, just go get char LXI D,GCDMA ;yes, need to read another record MVI C,26 ;set the DMA to GCDMA CALL BDOS ;ask BDOS to do it LXI D,GCFCB ;use the FCB at GCFCB MVI C,20 ;read a record sequentially CALL BDOS ;ask BDOS to do it CPI 1 ;check return code JZ GCEOF ;oops, 1: no more (end of file) JNC GCERR ;argh, >1: physical error STA GCPOS ;0: read successful, set GCPOS to 0 GCCHR: LXI H,GCDMA ;point to DMA with H-L MOV E,A ;move GCPOS into E MVI D,0 ;now D-E is 16-bit version of GCPOS DAD D ;GCPOS+DMA points to next char MOV A,M ;get that char into A LXI H,GCPOS ;point to GCPOS with H-L INR M ;increment GCPOS to point to next CPI 1AH ;is it ^Z? JZ GCEOF ;if so, record it STC CMC ;clear Carry JMP GCRET ;and return the character GCEOF: MVI A,1AH ;EOF, get a ^Z STA GCFLG ;set flag for future reference STC CMC ;clear Carry JMP GCRET ;return the ^Z GCERR: MVI A,1AH ;ERROR, get a ^Z STA GCFLG ;set flag STC ;and set Carry GCRET: POP B ;restore POP D ; the POP H ; registers RET ;and return GCFLG: DS 1 ;flag says EOF reached GCPOS: DS 1 ;keep track of position in record GCDMA: DS 128 ;DMA for GETCH, 128 bytes GCFCB: DS 36 ;FCB for GETCH ; ;Routine to UNGET a character, saving ; it for GETCH ; UNGETC: PUSH H ;save registers here PUSH D ;(if you don't do this, PUSH B ; UNGETCwill be a ; hassle to use) PUSH PSW ;save the character last LDA BUFCNT ;fetch buffer count CPI 5 ;already maximal? JNC UNG0 ;yes, leave it INR A ;no, increase it STA BUFCNT ;and put it back UNG0: LXI H,UGBUF+3 ;point from next-last LXI D,UGBUF+4 ;to last position MVI B,4 ;prepare to move 4 bytes UNGLP: MOV A,M ;get a byte STAX D ;move it up ahead DCX H ;back up DCX D ;to previous DCR B ;count down on B JNZ UNGLP ;loop if more to go POP PSW ;recover new character STA UGBUF ;put it at front of ; buffer POP B ;restore POP D ; the POP H ; registers RET BUFCNT: DB 0 ;count chars in UGBUF UGBUF: DS 5 ;room for 5 characters ; ;Routine to write character in A to open file at PCFCB ;Returns C for write Error ; PUTCH: PUSH H ;save registers PUSH D ; (so PUTCH will be PUSH B ; easy to use) MOV C,A ;save the character in C LDA PCPOS ;get position count CPI 80H ;is it up to 128? JC PCCHR ;no, just go write char PUSH B ;preserve character in C LXI D,PCDMA ;need to write the record out MVI C,26 ;set the DMA to PCDMA CALL BDOS ;ask BDOS to do it LXI D,PCFCB ;use the FCB at PCFCB MVI C,21 ;write a record sequentially CALL BDOS ;ask BDOS to do it POP B ;restore character in C CPI 0 ;check return code JNZ PCERR ;argh, >0: physical error STA PCPOS ;0: write successful, set PCPOS to 0 PCCHR: LXI H,PCDMA ;point to DMA with H-L MOV E,A ;move PCPOS into E MVI D,0 ;now D-E is 16-bit version of PCPOS DAD D ;PCPOS+DMA points to next char MOV M,C ;put outgoing char in its place LXI H,PCPOS ;point to PCPOS with H-L INR M ;increment PCPOS to point to next SUB A ;clear Carry flag, all is OK JMP PCRET PCERR: STC ;write error, set Carry PCRET: POP B ;restore POP D ; the POP H ; registers RET ;and return PCPOS: DS 1 ;keep track of position in record PCDMA: DS 128 ;DMA for PUTCH, 128 bytes PCFCB: DS 36 ;FCB for PUTCH ; ;Routine to open a file for GETCH (takes DE=FCB) ;Returns C if file not found ; GCOPEN: MVI A,80H ;initialize GCPOS to 80H STA GCPOS ;so first record will be read SUB A ;and zero the EOF flag STA GCFLG XCHG ;put FCB address in HL LXI D,GCFCB ;we'll move it into GCFCB MVI B,12 ;the drive/filename is 12 bytes GCL1: MOV A,M ;fetch a byte from FCB STAX D ;store it in GCFCB INX D ;point to next INX H ;in both places DCR B ;count down on 12 bytes JNZ GCL1 ;loop if more SUB A ;now get a 0 STAX D ;and put it into extent ("e") STA GCFCB+32 ;and also into record ("r") LXI D,GCFCB ;point to start of GCFCB again MVI C,15 ;function 15 opens a file CALL BDOS ;ask BDOS to do it CPI 0FFH ;check return code CMC ;now Carry is set if it was FFH RET ;return with Carry set if error ; ;Routine to make a file for PUTCH (takes DE=FCB) ;Returns C if cannot make file ; PCOPEN: SUB A ;initialize PCPOS to 0 STA PCPOS ;for beginning to write with PUTCH PUSH D ;preserve FCB address MVI C,19 ;function 19 ERASES a file CALL BDOS ;ask BDOS to do it POP H ;recover FCB address into HL LXI D,PCFCB ;we'll move it into PCFCB MVI B,12 ;the drive/filename is 12 bytes PCL1: MOV A,M ;fetch a byte from FCB STAX D ;store it in PCFCB INX D ;point to next INX H ;in both places DCR B ;count down on 12 bytes JNZ PCL1 ;loop if more SUB A ;now get a 0 STAX D ;and put it into extent ("e") LXI H,20 ;point ahead 20 bytes DAD D ;HL now points to record ("r") MOV M,A ;put 0 there, too LXI D,PCFCB ;point to start of GCFCB again MVI C,22 ;function 22 makes a file CALL BDOS ;ask BDOS to do it CPI 0FFH ;check return code CMC ;now Carry is set if it was FFH RET ;return with Carry set if error ; ;Routine to close a file for PUTCH (no arguments) ;Returns C if cannot close file ; PCLOSE: MVI A,1AH ;get a 1AH (EOF char) CALL PUTCH ;and write it to the file LDA PCPOS ;now look at position in PCDMA CPI 0 ;is it 00? JZ PCLFIL ;if so, no data, just close file LXI D,PCDMA ;need to write the last record out MVI C,26 ;set the DMA to PCDMA CALL BDOS ;ask BDOS to do it LXI D,PCFCB ;use the FCB at PCFCB MVI C,21 ;write a record sequentially CALL BDOS ;ask BDOS to do it CPI 0 ;check return code JNZ PCLERR ;warn if error PCLFIL: LXI D,PCFCB ;all set, point to the FCB MVI C,16 ;function 16 closes a file CALL BDOS ;ask BDOS to do it CPI 0FFH ;examine return code CMC ;Carry now set if was 0FFH RET ;return PCLERR: STC ;set Carry for write error RET ;and return END