; Program to swap IBM PC text graphics
; characters for something more printable.
;
VECTORS         segment at 0h           ; Interrupt Vector Area
        org     17h*4                   ; IBM PC Printer is Int 17H
PR_INT_VECTOR   label   dword           ; Double Word Offset:Segment pointer
VECTORS         ends                    ; to Int 17H
;
CODE_SEG        segment para public 'code'
        assume  ds:CODE_SEG, cs:CODE_SEG, es:CODE_SEG, ss:NOTHING
        org     100h                    ; COM program format
;
BEGIN:  jmp     SWAP_VECTORS            ; Initialize vectors and
                                        ; attach PRSWAP to DOS
ROM_PR_INT      dd      0               ; Double word to save address of
                                        ; ROM-BIOS printer interrupt
;
; Swap table to translate (XLAT) characters to be printed
;
SWAP_TABLE      db      '&'             ; Char 176      Graphic Fill
                db      '%'             ; Char 177      Graphic Fill
                db      '@'             ; Char 178      Graphic Fill
                db      4 dup ('|')     ; Char 179-182  Vertical
                db      2 dup ('*')     ; Char 183-184  Corner
                db      2 dup ('|')     ; Char 185-186  Vertical
                db      6 dup ('*')     ; Char 187-192  Corner
                db      2 dup ('-')     ; Char 193-194  Horizontal
                db      '|'             ; Char 195      Vertical
                db      '-'             ; Char 196      Horizontal
                db      '+'             ; Char 197      Intersection
                db      2 dup ('|')     ; Char 198-199  Vertical
                db      2 dup ('*')     ; Char 200-201  Corner
                db      2 dup ('-')     ; Char 202-203  Horizontal
                db      '|'             ; Char 204      Vertical
                db      '-'             ; Char 205      Horizontal
                db      '+'             ; Char 206      Intersection
                db      4 dup ('-')     ; Char 207-210  Horizontal
                db      4 dup ('*')     ; Char 211-214  Corner
                db      2 dup ('+')     ; Char 215-216  Intersection
                db      2 dup ('*')     ; Char 217-218  Corner
                db      '#'             ; Char 219      Graphic Fill
                db      '.'             ; Char 220      Graphic Fill
                db      '{'             ; Char 221      Graphic Fill
                db      '}'             ; Char 222      Graphic Fill
                db      '^'             ; Char 223      Graphic Fill
;
; Miscellaneous equates
;
PRINT_CHAR      equ     0               ; Int 17H print char function number
LOWEST_CHAR     equ     176             ; Lowest graphic char in table
HIGHEST_CHAR    equ     223             ; Highest graphic char in table
LOZENGE         equ     254             ; Lozenge character position
;
PRSWAP  proc    near                    ; Work begins here
        push    cx                      ; Save CX on stack
        xor     cx,cx                   ; Clear CX so flag works
        push    ds                      ; Save caller's DS on stack
        push    cs                      ; Push CS, then pop it as DS
        pop     ds                      ; to establish addressability
                                        ; of PRSWAP's data
        cmp     ah,PRINT_CHAR           ; Is call for printing a char?
        ja      CALL_INT_17H            ; No, go to normal interrupt 17H
        cmp     al,LOWEST_CHAR          ; Is char to print below table range?
        jb      CALL_INT_17H            ; Yes, go to normal interrupt 17H
        cmp     al,HIGHEST_CHAR         ; Is char to print above table range
        ja      CHECK_LOZENGE           ; Yes, check for lozenge char
        mov     cl,al                   ; Save char in AL register in CL
        push    bx                      ; Save BX on stack
        mov     bx,offset SWAP_TABLE    ; Point to translate table with BX
        sub     al,LOWEST_CHAR          ; Adjust AL for bias into table
        xlat                            ; Translate to PRSWAP's character
        pop     bx                      ; Restore BX
        jmp     CALL_INT_17H            ; Go call interrupt 17H
CHECK_LOZENGE:                          ; Check for char 254
        cmp     al,LOZENGE              ; Is char to print the lozenge?
        jne     CALL_INT_17H            ; No, go to normal interrupt 17H
        mov     cl,al                   ; Save char in AL register in CL
        mov     al,'='                  ; Make it a '='
CALL_INT_17H:                           ; Go call Int 17H as subroutine
        pushf                           ; Push flags for fake interrupt 17H
        call    ROM_PR_INT              ; Call interrupt 17H as subroutine
        cmp     cl,0                    ; Check to see if PRSWAP did anything
        je      RETURN                  ; If not, just return
        mov     al,cl                   ; Restore original char to AL
RETURN:                                 ; Return to caller
        pop     ds                      ; Restore caller's DS register
        pop     cx                      ; Restore caller's CX register
        iret                            ; Interrupt return to caller
        PRSWAP  endp                    ; That's all for resident routine
;
INITIAL_DATA:                           ; Messages for initialization code
;
COPYRIGHT       db      'PRSWAP (C) 1985, Dickinson Associates Inc.',13,10,'$'
FINISH_MSG      db      13,10,'Resident Portion of PRSWAP Loaded',13,10,10,'$'
;
SWAP_VECTORS:                           ; Initialization Code
        assume  ds:CODE_SEG             ; Address into this segment
        mov     dx,offset COPYRIGHT     ; Set up to print copyright notice
        mov     ah,9h                   ; Request DOS to display string
        int     21h                     ; Call DOS
        push    ds                      ; Save this segment
        assume  ds:VECTORS              ; Address into VECTORS segment
        mov     ax,VECTORS              ; Establish DS as VECTORS
        mov     ds,ax
        cli                                     ; Disable interrupts
        mov     ax,word ptr PR_INT_VECTOR       ; Store addresses
        mov     word ptr es:ROM_PR_INT,ax       ; of BIOS Int 17H program
        mov     ax,word ptr PR_INT_VECTOR[2]
        mov     word ptr es:ROM_PR_INT[2],ax
        mov     word ptr PR_INT_VECTOR, offset PRSWAP   ; Substitute PRSWAP
        mov     word ptr PR_INT_VECTOR[2],cs            ; and this segment
        sti                             ; Enable interrupts
        pop     ds                      ; Re-establish this segment
        assume  ds:CODE_SEG             ; as DS
        mov     dx,offset FINISH_MSG    ; Set up to display finish message
        mov     ah,9h                   ; Request DOS to display string
        int     21h                     ; Call DOS
        mov     dx,offset INITIAL_DATA  ; End of PRSWAP program
        int     27h                     ; Terminate, stay resident
CODE_SEG        ends                    ; End of Segment
        end     BEGIN                   ; End of Everything
