        NAME    WSTOVW
        PAGE    55,132
        TITLE   'WSTOVW --- FILTER WORDSTAR TEXT FILE FOR VOLKSWRITER'

;
; WSTOVW --- CONVERT WORDSTAR DOCUMENT FILE TO VOLKSWRITER.
;
; HIGH BIT OF ALL CHARACTERS STRIPPED.
; SOFT SPACES CONVERTED TO NORMAL.
; HARD CARRIAGE RETURNS CONVERTED TO VW PARAGRAPH MARKER FOLLOWED BY CR-LF.
; SOFT CARRIAGE RETURNS TURNED INTO NORMAL CARRIAGE RETURNS.
; TABS ARE EXPANDED.
;
; VERSION 1.0    11 DEC 83
;
; COPYRIGHT (C) 1983 BY RAY DUNCAN

CR      EQU     0DH             ;ASCII CARRIAGE RETURN
LF      EQU     0AH             ;ASCII LINE FEED
FF      EQU     0CH             ;ASCII FORM FEED
EOF     EQU     01AH            ;END OF FILE MARKER
TAB     EQU     09H             ;ASCII TAB CHARACTER

COMMAND EQU     80H             ;BUFFER FOR COMMAND TAIL

BLKSIZE EQU     1024            ;BLOCKING/DEBLOCKING SIZE


CSEG    SEGMENT PARA PUBLIC 'CODE'

        ASSUME  CS:CSEG,DS:DATA,ES:DATA,SS:STACK


CLEAN   PROC    FAR             ;ENTRY POINT FROM PC-DOS

        PUSH    DS              ;SAVE DS:0000 FOR FINAL
        XOR     AX,AX           ;RETURN TO PC-DOS
        PUSH    AX
        MOV     AX,DATA         ;MAKE OUR DATA SEGMENT
        MOV     ES,AX           ;ADDRESSABLE VIA ES REGISTER
        CALL    INFILE          ;GET PATH AND FILE SPEC.
                                ;FOR INPUT FILE
        MOV     AX,ES           ;SET DS=ES FOR REMAINDER
        MOV     DS,AX           ;OF PROGRAM
        JNC     CLEAN1          ;JUMP, GOT ACCEPTABLE NAME
        MOV     DX,OFFSET MSG4  ;MISSING OR ILLEGAL FILESPEC,
        JMP     CLEAN9          ;PRINT ERROR MESSAGE AND EXIT.

CLEAN1: CALL    OUTFILE         ;SET UP OUTPUT FILE NAME
        CALL    OPEN_INPUT      ;NOW TRY TO OPEN INPUT FILE
        JNC     CLEAN2          ;JUMP,OPENED INPUT OK
        MOV     DX,OFFSET MSG1  ;OPEN OF INPUT FILE FAILED,
        JMP     CLEAN9          ;PRINT ERROR MSG AND EXIT.

CLEAN2:
        CALL    OPEN_OUTPUT     ;TRY TO OPEN OUTPUT FILE.
        JNC     CLEAN25         ;JUMP,OPENED OK
        MOV     DX,OFFSET MSG2  ;OPEN OF OUTPUT FILE FAILED,
        JMP     CLEAN9          ;PRINT ERROR MESSAGE AND EXIT.

CLEAN25:                        ;ALL FILES OPENED SUCCESSFULLY,
        CALL    SIGN_ON         ;PRINT SIGN-ON MESSAGE AND
        CALL    INIT_BUFFS      ;SET UP BUFFERS.

CLEAN3:                         ;NOW FILTER THE FILE.
        CALL    GET_CHAR        ;READ 1 CHARACTER FROM INPUT.

        CMP     AL,CR OR 80H    ;IS IT A "SOFT CARRIAGE RETURN"?
        JNE     CLEAN31         ;NO,JUMP
        MOV     AL,CR           ;YES, WRITE NORMAL CR
        JMP     CLEAN35
CLEAN31:
        AND     AL,07FH         ;STRIP OFF THE HIGH BIT
        CMP     AL,20H          ;IS IT A CONTROL CODE?
        JAE     CLEAN4          ;NO, WRITE IT TO NEW FILE
                                ;IF CONTROL CODE,
        CMP     AL,EOF          ;IS IT END OF FILE MARKER?
        JE      CLEAN6          ;YES,JUMP TO CLOSE FILES.
        CMP     AL,CR           ;IS IT HARD CARRIAGE RETURN?
        JNE     CLEAN33         ;NO,JUMP
        MOV     AL,014H         ;YES,WRITE PARAGRAPH MARKER AND
        CALL    PUT_CHAR        ;TRAILING CR
        MOV     AL,CR           ;
        JMP     CLEAN35         ;WRITE IT TO FILE AND CLEAR COLUMN COUNT.
CLEAN33:
        CMP     AL,TAB          ;IS IT A TAB COMMAND?
        JZ      CLEAN5          ;YES,JUMP TO SPECIAL PROCESSING.
        CMP     AL,LF           ;IF LINE FEED WRITE IT TO FILE,
        JNE     CLEAN3          ;OTHERWISE DISCARD CONTROL CODE.
CLEAN35:                        ;IF IT IS CR OR LF,
        MOV     COLUMN,0        ;INCIDENTALLY INITIALIZE
        JMP     CLEAN45         ;COLUMN COUNT FOR TAB PROCESSOR.

CLEAN4:                         ;COUNT ALPHANUMERIC CHARS. SENT.
        INC     COLUMN

CLEAN45:                        ;WRITE THIS CHARACTER TO
        CALL    PUT_CHAR        ;OUTPUT FILE,
        JNC     CLEAN3          ;IF CY NOT SET, WRITE WAS
                                ;OK SO GO GET NEXT CHAR.
CLEAN47:
        CALL    CLOSE_INPUT     ;IF CY SET, DISK IS FULL
        CALL    CLOSE_OUTPUT    ;SO CLOSE FILES AND EXIT
        MOV     DX,OFFSET MSG5  ;WITH ERROR MESSAGE.
        JMP     CLEAN9

CLEAN5:                         ;PROCESS TAB CHARACTER
        MOV     AX,COLUMN       ;LET DX:AX=COLUMN COUNT
        CWD
        MOV     CX,8            ;DIVIDE IT BY EIGHT...
        IDIV    CX
        SUB     CX,DX           ;REMAINDER IS IN DX.
        ADD     COLUMN,CX       ;UPDATE COLUMN POINTER.
CLEAN55:                        ;8 MINUS THE REMAINDER
        PUSH    CX              ;GIVES US THE NUMBER OF
        MOV     AL,20H          ;SPACES TO SEND OUT TO
        CALL    PUT_CHAR        ;MOVE TO THE NEXT TAB POSITION
        POP     CX              ;RESTORE SPACE COUNT
        JC      CLEAN47         ;JUMP IF DISK IS FULL
        LOOP    CLEAN55
        JMP     CLEAN3          ;GET NEXT CHARACTER

CLEAN6:                         ;END OF FILE DETECTED,
        CALL    PUT_CHAR        ;WRITE END-OF-FILE MARKER,
        JC      CLEAN47         ;JUMP IF DISK WAS FULL
        CALL    FLUSH_BUFFS     ;WRITE REMAINING DATA TO DISK
        JC      CLEAN47         ;IF CY SET,DISK WAS FULL
                                ;OTHERWISE FILE WAS WRITTEN OK
        CALL    CLOSE_INPUT     ;CLOSE INPUT AND OUTPUT
        CALL    CLOSE_OUTPUT    ;FILES.
        MOV     DX,OFFSET MSG3  ;ADDR OF SUCCESS MESSAGE,

CLEAN9:                         ;PRINT MESSAGE AND RETURN
        MOV     AH,9            ;CONTROL TO PC-DOS
        INT     21H
        RET

CLEAN   ENDP


INFILE  PROC    NEAR            ;PROCESS NAME OF INPUT FILE
                                ;DS:SI <- ADDR COMMAND LINE
        MOV     SI,OFFSET COMMAND
                                ;ES:DI <- ADDR FILESPEC BUFFER
        MOV     DI,OFFSET INPUT_NAME
        CLD
        LODSB                   ;ANY COMMAND LINE PRESENT?
        OR      AL,AL           ;RETURN ERROR STATUS IF NOT.
        JZ      INFILE4
INFILE1:                        ;SCAN OVER LEADING BLANKS
        LODSB                   ;TO FILE NAME
        CMP     AL,CR           ;IF WE HIT CARRIAGE RETURN
        JZ      INFILE4         ;FILENAME IS MISSING.
        CMP     AL,20H          ;IS THIS A BLANK?
        JZ      INFILE1         ;IF SO KEEP SCANNING.

INFILE2:                        ;FOUND FIRST CHAR OF NAME,
        STOSB                   ;MOVE LAST CHAR. TO OUTPUT
                                ;FILE NAME BUFFER.
        LODSB                   ;CHECK NEXT CHARACTER, FOUND
        CMP     AL,CR           ;CARRIAGE RETURN YET?
        JE      INFILE3         ;YES,EXIT WITH SUCCESS CODE
        CMP     AL,20H          ;IS THIS A BLANK?
        JNE     INFILE2         ;IF NOT KEEP MOVING CHARS.

INFILE3:                        ;EXIT WITH CARRY =0
        CLC                     ;FOR SUCCESS FLAG
        RET

INFILE4:                        ;EXIT WITH CARRY =1
        STC                     ;FOR ERROR FLAG
        RET
INFILE  ENDP

OUTFILE PROC    NEAR            ;SET UP PATH AND FILE
        CLD                     ;NAME FOR OUTPUT FILE.
        MOV     CX,64           ;LENGTH TO MOVE
        MOV     SI,OFFSET INPUT_NAME  ;SOURCE ADDR
        MOV     DI,OFFSET OUTPUT_NAME ;DEST ADDR
        REP MOVSB               ;TRANSFER THE STRING
        MOV     DI,OFFSET OUTPUT_NAME
OUTFILE1:                       ;SCAN STRING LOOKING FOR
        MOV     AL,[DI]         ;"." MARKING START OF EXTENSION
        OR      AL,AL           ;OR ZERO BYTE MARKING NAME END.
        JZ      OUTFILE2        ;IF EITHER IS FOUND,JUMP.
        CMP     AL,'.'
        JE      OUTFILE2        ;BUMP STRING POINTER, LOOP
        INC     DI              ;IF NEITHER '.' OR ZERO FOUND.
        JMP     OUTFILE1
OUTFILE2:                       ;FOUND ZERO OR '.',FORCE THE
                                ;EXTENSION OF OUTPUT FILE TO '.VW'
        MOV     SI,OFFSET OUTFILE_EXT
        MOV     CX,4
        REP MOVSB
        RET                     ;BACK TO CALLER
OUTFILE ENDP

OPEN_INPUT PROC NEAR            ;OPEN INPUT FILE
                                ;DS:DX=ADDR FILENAME
        MOV     DX,OFFSET INPUT_NAME
        MOV     AL,0            ;AL=0 FOR READ ONLY
        MOV     AH,3DH          ;FUNCTION 3DH=OPEN
        INT     21H             ;HANDLE RETURNED IN AX,
        MOV     INPUT_HANDLE,AX ;SAVE IT FOR LATER.
        RET                     ;CY IS SET IF ERROR
OPEN_INPUT ENDP

OPEN_OUTPUT PROC NEAR           ;OPEN OUTPUT FILE
                                ;DS:DX=ADDR FILENAME
        MOV     DX,OFFSET OUTPUT_NAME
        MOV     AL,1            ;AL=1 FOR WRITE ONLY
        MOV     AH,3CH          ;FUNCTION 3CH=MAKE OR
        INT     21H             ;TRUNCATE EXISTING FILE
                                ;HANDLE RETURNED IN AX
        MOV     OUTPUT_HANDLE,AX;SAVE IT FOR LATER.
        RET                     ;RETURN CY=TRUE IF ERROR
OPEN_OUTPUT ENDP

CLOSE_INPUT PROC NEAR           ;CLOSE INPUT FILE
        MOV     BX,INPUT_HANDLE ;BX=HANDLE
        MOV     AH,3EH
        INT     21H
        RET
CLOSE_INPUT ENDP

CLOSE_OUTPUT PROC NEAR          ;CLOSE OUTPUT FILE
        MOV     BX,OUTPUT_HANDLE;BX=HANDLE
        MOV     AH,3EH
        INT     21H
        RET
CLOSE_OUTPUT ENDP

GET_CHAR PROC   NEAR            ;GET ONE CHARACTER FROM INPUT BUFFER
        MOV     BX,INPUT_PTR
        CMP     BX,BLKSIZE
        JNE     GET_CHAR1
        CALL    READ_BLOCK
        MOV     BX,0
GET_CHAR1:
        MOV     AL,[INPUT_BUFFER+BX]
        INC     BX
        MOV     INPUT_PTR,BX
        RET
GET_CHAR ENDP

PUT_CHAR PROC   NEAR            ;PUT ONE CHARACTER INTO OUTPUT BUFFER
        MOV     PREV_CHAR,AL    ;SAVE COPY OF MOST RECENT OUTPUT
        MOV     BX,OUTPUT_PTR
        MOV     [OUTPUT_BUFFER+BX],AL
        INC     BX
        MOV     OUTPUT_PTR,BX
        CMP     BX,BLKSIZE      ;BUFFER FULL YET?
        JNE     PUT_CHAR1       ;NO,JUMP
        CALL    WRITE_BLOCK     ;YES,WRITE THE BLOCK
        RET                     ;RETURN CY AS STATUS CODE
PUT_CHAR1:
        CLC                     ;RETURN CY CLEAR FOR OK STATU2
        RET
HAR ENDP

PUT_CHAR PROC   NEAR            ;PUT ONE CHAR