Metropoli BBS
VIEWER: fe.asm MODE: TEXT (ASCII)
;---------------------------------------------------------------------
;Font editor for EGA 8x14 fonts
;---------------------------------------------------------------------

O           equ <offset>
B           equ <byte ptr>
W           equ <word ptr>

.Model Tiny
.Code
.186
Org 100h

Start:      call Main               ;Call main procedure
            mov ah,4Ch              ;Exit to DOS
            int 21h

;---------------------------------------------------------------------

FError$     db 'Error accessing file$'
Title$      db ' EGA 8x14 Font Editor -- by Selenium Software $'

INSTRUC_LEN equ 47                  ;Length of Instruc... strings

Instruc1$   db ' Arrows(keypad or cursor)=Move around in grid $'
Instruc2$   db ' Shft-Arrows(keypad only),numbers 2468=Select $'
Instruc3$   db ' character    [+]=Next char    [-]=Prev. char $'
Instruc4$   db ' Q=Quit  Space=Toggle pixel  B=Copy BIOS char $'
Instruc5$   db ' S=Save  C=Copy  P=Paste  M+Arrow=Move bitmap $'
Instruc6$   db ' T=Switch to typing mode(Esc returns to edit) $'

Shift$      db ' Enter direction to shift: $'
CharStr$    db '  Current Char:  '
HexData     db '?? " "    $'

Ext$        db '.F14',0

CrossYList  db 1,2,3,4,5,6,6,7,8,8,9,9,10,10

;---------------------------------------------------------------------

FileHandle  dw 0                    ;File handle

X_SIZE      equ 32                  ;Size of grid squares
Y_SIZE      equ 24

CurFont     dw 0                    ;Current font
CurChar     dw 0                    ;Current character
XPos        dw 0                    ;X and Y position
YPos        dw 0

;---------------------------------------------------------------------
; Main procedure
;---------------------------------------------------------------------

Main        Proc

            mov dx,O(BiosFont)      ;DX = BIOS font buffer
            call GetFont            ;Copy font into buffer
            mov CurFont,dx          ;Set current font

            mov cx,1                ;CX = length
            add cl,[ds:80h]

            mov di,81h              ;DI = command line
            mov al,20h              ;Scan for non-space
            repe scasb
            lea si,[di-1]           ;Save position
            repne scasb             ;Scan for space
            mov byte ptr [di-1],0   ;Set to zero

            sub di,si               ;Copy to filename buffer
            mov cx,di
            mov di,O(FileName)
            rep movsb

;-------------------------------------------------

            mov si,O(FileName)      ;SI = filename

m_LenOLoop: mov di,si               ;DI = SI
            mov cx,-1               ;CX = -1
m_LenLoop:  inc cx                  ;Increment length
            lodsb                   ;Load byte
            cmp al,'\'              ;If it's a '\', start over
            je m_LenOLoop
            test al,al              ;Loop while not null
            jnz m_LenLoop

            mov al,'.'              ;If there is already an extension,
            repne scasb             ;then do nothing
            je m_NameOK

            mov si,O(Ext$)          ;DI now points to the null terminator
            mov cx,5                ;Copy the extension '.FNT' onto the
            rep movsb               ;end of the filename

;-------------------------------------------------

m_NameOK:   mov di,O(Buffer)        ;Clear the buffer
            mov cx,3584/2
            xor ax,ax
            rep stosw

            mov ax,3D02h            ;Open font file
            mov dx,O(FileName)
            int 21h
            jnc m_FileOK            ;If it does not exist, then

            mov ah,3Ch              ;create it (normal attr, etc.)
            xor cx,cx
            int 21h
            jc m_FError

m_FileOK:   mov FileHandle,ax       ;Save file handle
            xchg bx,ax              ;BX = handle

            mov ah,3Fh              ;Read 3584 bytes
            mov cx,3584
            mov dx,O(Buffer)
            int 21h
            jc m_UseBios            ;If an error occurred, then
            test ax,ax
            jnz m_Cont

m_UseBios:  mov si,O(BiosFont)      ;use the BIOS font
            mov di,O(Buffer)
            mov cx,3584
            rep movsb

;-------------------------------------------------

m_Cont:     call Initialize         ;Initialize display & variables
            call MainLoop           ;Go into main loop

;-------------------------------------------------

m_Done:     mov ax,3                ;Switch to text mode
            int 10h

            mov ax,4202h            ;Seek to end of file
            mov bx,FileHandle
            xor cx,cx
            xor dx,dx
            int 21h
            or dx,ax                ;DX = empty flag

            mov ah,3Eh              ;Close the file
            int 21h

            test dx,dx              ;If the file is still empty, then
            jnz m_Exit

            mov ah,41h              ;delete it
            mov dx,O(FileName)
            int 21h

m_Exit:     xor al,al               ;Return with error code 0
            ret

;-------------------------------------------------

m_FError:   mov ah,9                ;Output error string
            mov dx,O(FError$)
            int 21h
            mov al,1                ;Return with error code 1
            ret

Main        EndP

;---------------------------------------------------------------------
; MainLoop -- Main editing loop
;---------------------------------------------------------------------

MainLoop    Proc

            pusha                   ;Save all registers

x_KeyLoop:  call PutCursor          ;Show the cursor
            xor ah,ah               ;Wait for a key
            int 16h
            call PutCursor          ;Hide the cursor

x_KeyChk1:  cmp al,'a'              ;Make it uppercase
            jb $+4
            add al,'A'-'a'

            cmp al,'-'              ;[-] - Char Select Left?
            je x_CLeft
            cmp al,'+'              ;[+] - Char Select Right?
            je x_CRight
            cmp al,'4'              ;4 - Char Select Left?
            je x_CLeft
            cmp al,'6'              ;6 - Char Select Right?
            je x_CRight
            cmp al,'8'              ;8 - Char Select Up?
            je x_CUp
            cmp al,'2'              ;2 - Char Select Down?
            je x_CDown

            cmp al,' '              ;Space - Flip Pixel?
            je x_Flip
            cmp al,'B'              ;B - Get BIOS char?
            je x_Bios
            cmp al,'C'              ;C - Copy?
            je x_Copy
            cmp al,'P'              ;P - Paste?
            je x_Paste
            cmp al,'Q'              ;Q - Exit?
            je x_ExitJmp
            cmp al,'T'              ;T - Typing mode?
            je x_Type
            cmp al,'M'              ;M - Move bitmap?
            je x_Move
            cmp al,'S'              ;S - Save?
            je x_Save

            jmp x_KeyChk2           ;Jump to second key block
x_ExitJmp:  jmp x_Exit              ;Jump to exit

;-------------------------------------------------

x_CLeft:    mov al,-1               ;Moving back 1 character
            jmp x_NewChar           ;Display new character

;-------------------------------------------------

x_CRight:   mov al,1                ;Moving forward 1 character
            jmp x_NewChar           ;Display new character

;-------------------------------------------------

x_CUp:      mov al,-20h             ;Moving up 1 row
            jmp x_NewChar           ;Display new character

;-------------------------------------------------

x_CDown:    mov al,20h              ;Moving down 1 row
                                    ;Fall through...

;-------------------------------------------------

x_NewChar:  add al,B CurChar        ;Add in current character
            xchg al,B CurChar       ;Show old character
            call ShowChar
            mov ax,CurChar          ;Show new character
            call ShowChar
            jmp x_KeyLoop

;-------------------------------------------------

x_Flip:     mov bx,XPos             ;BX = X, CX = Y
            mov cx,YPos
            call FGetPixel          ;Flip the pixel
            xor al,1
            call FPutPixel
            jmp x_KeyLoop

;-------------------------------------------------

x_Bios:     imul si,CurChar,14      ;SI = BIOS font char
            add si,O(BiosFont)
            jmp x_CopyShow          ;Copy and show

;-------------------------------------------------

x_Copy:     imul si,CurChar,14      ;SI = working font char
            add si,O(Buffer)        ;DI = clipboard
            mov di,O(Clipboard)
            mov cx,14               ;Copy 14 bytes
            rep movsb
            jmp x_KeyJmp

;-------------------------------------------------

x_Paste:    mov si,O(Clipboard)     ;SI = clipboard
                                    ;Fall through...

;-------------------------------------------------

x_CopyShow: mov ax,CurChar          ;AX = current char
            imul di,ax,14           ;DI = working font char
            add di,O(Buffer)

            mov cx,14               ;Copy 14 bytes
            rep movsb

            call ShowChar           ;Redraw the character
            jmp x_KeyJmp

;-------------------------------------------------

x_Type:     call TypeMode           ;Call typing-mode loop
            jmp x_KeyJmp

;-------------------------------------------------

x_Move:     call Shift              ;Call shift-char procedure
            jmp x_KeyJmp

;-------------------------------------------------

x_Save:     mov bx,FileHandle       ;BX = file handle
            mov ax,4200h            ;Seek to beginning of file
            xor cx,cx
            xor dx,dx
            int 21h

            mov ah,40h              ;Write 3584 bytes to file
            mov dx,O(Buffer)
            mov cx,3584
            int 21h

            mov ah,40h              ;Truncate file at 3584 bytes
            xor cx,cx
            int 21h
            jmp x_KeyJmp

;-------------------------------------------------

x_KeyChk2:  xchg al,ah              ;Scan code in AL

            cmp al,53h              ;Del - Clear?
            je x_Clear

            cmp al,4Bh              ;Left?
            je x_Left
            cmp al,4Dh              ;Right?
            je x_Right
            cmp al,48h              ;Up?
            je x_Up
            cmp al,50h              ;Down?
            je x_Down

x_KeyJmp:   jmp x_KeyLoop           ;Invalid, loop

;-------------------------------------------------

x_Clear:    xor al,al               ;AL = 0
            imul di,CurChar,14      ;DI = working font char
            add di,O(Buffer)
            mov cx,14               ;Clear 14 bytes
            rep stosb

            mov ax,CurChar          ;Redraw the character
            call ShowChar
            jmp x_KeyLoop

;-------------------------------------------------

x_Left:     mov ax,XPos             ;Decrement XPos
            dec ax
            js x_KeyJmp             ;Don't save if < 0
            mov XPos,ax
            jmp x_KeyLoop

;-------------------------------------------------

x_Right:    mov ax,XPos             ;Increment XPos
            inc ax
            cmp al,7                ;Don't save if > 7
            jg x_KeyJmp
            mov XPos,ax
            jmp x_KeyLoop

;-------------------------------------------------

x_Up:       mov ax,YPos             ;Decrement YPos
            dec ax
            js x_KeyJmp             ;Don't save if < 0
            mov YPos,ax
            jmp x_KeyLoop

;-------------------------------------------------

x_Down:     mov ax,YPos             ;Increment XPos
            inc ax
            cmp al,13               ;Don't save if > 13
            jg x_KeyJmp
            mov YPos,ax
            jmp x_KeyLoop

;-------------------------------------------------

x_Exit:     popa                    ;Restore registers
            ret                     ;Return

MainLoop    EndP

;---------------------------------------------------------------------
; FillRect -- Draw a filled rectangle
;---------------------------------------------------------------------
; BX = X1, CX = Y1, SI = X2, DI = Y2, AL = color (0 or 1)

FillRect    Proc

            pusha                   ;Save all registers

            cmp cx,di               ;Put Y values in order
            jle $+4
            xchg cx,di

            mov dx,cx               ;BX = X1, CX = X2
            mov cx,si               ;DX = Y1

fr_loop:    call PutRow             ;Draw this row
            inc dx                  ;Next row
            cmp dx,di               ;Loop while not done
            jle fr_loop

            popa                    ;Restore registers
            ret                     ;Return

FillRect    EndP

;---------------------------------------------------------------------
; FlipPixel -- Flip the value of a pixel
;---------------------------------------------------------------------
; BX = X, CX = Y

FlipPixel   Proc

            pusha                   ;Save all registers
            push ds
            push 0A000h             ;DS = video memory
            pop ds

            mov dx,bx               ;DX = X
            imul bx,cx,80           ;BX = Y * 80 = row offset
            mov cx,dx               ;CX = X
            shr dx,3                ;DX = byte offset within row
            add bx,dx               ;BX = offset

            and cl,7                ;AL = bit mask
            mov al,80h
            shr al,cl

            xor [bx],al             ;Flip the pixel

            pop ds                  ;Restore registers
            popa
            ret                     ;Return

FlipPixel   EndP

;---------------------------------------------------------------------
; FGetPixel -- Read a pixel from the current character
;---------------------------------------------------------------------
; BX = X, CX = Y, returns AL = color (0 or 1)

FGetPixel   Proc

            push bx                 ;Save registers
            push cx
            push si

            imul si,CurChar,14      ;SI = offset
            add si,cx
            mov cx,bx               ;AL = bit mask
            mov al,80h
            shr al,cl

            and al,Buffer[si]       ;Read the pixel
            inc cx                  ;AL = 0 if off, 1 if on
            rol al,cl

            pop si                  ;Restore registers
            pop cx
            pop bx
            ret                     ;Return

FGetPixel   EndP

;---------------------------------------------------------------------
; FPutPixel -- Write a pixel to the current character
;---------------------------------------------------------------------
; BX = X, CX = Y, AL = color (0 or 1)

FPutPixel   Proc

            pusha                   ;Save registers

            mov si,bx               ;SI = X, DI = Y
            mov di,cx

            cmp al,1                ;BP = color (0 or 1)
            sbb bp,bp
            inc bp

            imul ax,CurChar,14      ;BX = offset
            add cx,ax               ;AL = bit mask
            xchg cx,bx
            mov al,80h
            shr al,cl

            test bp,bp              ;Jump if turning off
            jz fp_off

fp_on:      or Buffer[bx],al        ;Set the pixel
            jmp fp_cont

fp_off:     not al                  ;Clear the pixel
            and Buffer[bx],al

;-------------------------------------------------

fp_cont:    lea bx,[si+300]         ;Get position in small char display
            lea cx,[di+30]
            mov ax,bp               ;AX = color
            call PutPixel           ;Draw this pixel

            mov bx,CurChar          ;BX, CX = current char
            mov cx,bx
            and bx,1Fh              ;BX = X position
            imul bx,8               ;X = (ch MOD 16) * 8
            shr cx,5                ;CX = Y position
            imul cx,18              ;Y = (ch / 16) * 18

            lea bx,[bx+si+8]        ;Adjust for UL corner & pixel position
            add cx,di               ;now (BX, CX) is the position of the
            add cx,32               ;pixel on the screen

            call PutPixel           ;Draw this pixel

            imul si,X_SIZE          ;(BX, CX)-(SI, DI) = position on screen
            imul di,Y_SIZE          ;of rectangle in large char display
            lea bx,[si+380+1]
            lea cx,[di+1]
            add si,380+X_SIZE-1
            add di,Y_SIZE-1

            call FillRect           ;Fill the rectangle

            popa                    ;Restore registers
            ret                     ;Return

FPutPixel   EndP

;---------------------------------------------------------------------
; GetFont -- Copy BIOS 14-point font into buffer
;---------------------------------------------------------------------
; DX = offset of buffer

GetFont     Proc

            pusha                   ;Save all registers
            push ds
            push es

            push dx                 ;Save DX
            mov ax,1130h            ;Get BIOS 14-point font
            mov bh,02h
            int 10h

            push es                 ;DS = ES
            pop ds
            push cs                 ;ES = CS
            pop es

            mov dx,cx               ;DX = extra bytes  (needed if
            sub dx,14               ; this isn't a real 14-point font)

            mov bx,100h             ;BX = char count
            mov si,bp               ;SI = BIOS font
            pop di                  ;DI = buffer

gf_loop:    mov cx,14               ;Copy 14 bytes
            rep movsb
            add si,dx               ;Skip extra bytes
            dec bx                  ;Loop back
            jnz gf_loop

            pop es                  ;Restore registers
            pop ds
            popa
            ret                     ;Return

GetFont     EndP

;---------------------------------------------------------------------
; GetPixel -- Read the value of a pixel
;---------------------------------------------------------------------
; BX = X, CX = Y, returns AL = color (0 or 1)

GetPixel    Proc

            push bx                 ;Save registers
            push cx
            push dx
            push ds
            push 0A000h             ;DS = video memory
            pop ds

            mov dx,bx               ;DX = X
            imul bx,cx,80           ;BX = Y * 80 = row offset
            mov cx,dx               ;CX = X
            shr dx,3                ;DX = byte offset within row
            add bx,dx               ;BX = offset

            and cl,7                ;AL = bit mask
            mov al,80h
            shr al,cl

            and al,[bx]             ;Read the pixel
            inc cx                  ;AL = 0 if off, 1 if on
            rol al,cl

            pop ds                  ;Restore registers
            pop dx
            pop cx
            pop bx
            ret                     ;Return

GetPixel    EndP

;---------------------------------------------------------------------
; Initialize -- Initialize the display and variables
;---------------------------------------------------------------------

Initialize  Proc

            pusha                   ;Save all registers

            mov ax,10h              ;Switch to 640x350x16 EGA mode
            int 10h

            xor bx,bx               ;Display the title
            xor cx,cx
            mov dx,O(Title$)
            mov ah,0FFh
            call PutStr

            mov cx,250              ;Instructions box is at (0, 240)
            mov si,6                ;6 instruction lines
            mov dx,O(Instruc1$)     ;DX = offset of first string

in_loop1:   call PutStr             ;Display the instructions
            add dx,INSTRUC_LEN
            add cx,14
            dec si
            jnz in_loop1

;-------------------------------------------------

            mov al,1                ;Setting pixels here

            mov di,14               ;14 lines in grid
            xor cx,cx               ;Y starts at 0

in_loop2:   mov bx,380              ;X starts at 380
            mov si,(8*X_SIZE)/2     ;Width is 8*X_SIZE
in_iloop2:  call PutPixel           ;Draw this pixel
            add bx,2                ;Next pixel
            dec si                  ;Loop back
            jnl in_iloop2
            add cx,Y_SIZE           ;Next line
            dec di                  ;Loop back
            jnl in_loop2

            mov si,8                ;8 columns in grid
            mov bx,380              ;X starts at 380

in_loop3:   xor cx,cx               ;Y starts at 0
            mov di,(14*Y_SIZE)/2    ;Height is 8*X_SIZE
in_iloop3:  call PutPixel           ;Draw this pixel
            add cx,2                ;Next pixel
            dec di                  ;Loop back
            jnl in_iloop3
            add bx,X_SIZE           ;Next column
            dec si                  ;Loop back
            jnl in_loop3

;-------------------------------------------------

            xor ax,ax               ;Current character is 00
            mov CurChar,ax
            mov XPos,ax
            mov YPos,ax

in_loop4:   call ShowChar           ;Display the characters
            inc al
            jnz in_loop4

            popa                    ;Restore registers
            ret                     ;Return

Initialize  EndP

;---------------------------------------------------------------------
; PutChar -- Output a character to the screen
;---------------------------------------------------------------------
; BX = X, CX = Y, AL = char, AH = XOR mask (BX should be 0 mod 8)

PutChar     Proc

            pusha                   ;Save all registers
            push es
            push 0A000h             ;ES = video memory
            pop es

            shr bx,3                ;DI = offset in video memory
            imul di,cx,80
            add di,bx

            mov bl,al               ;SI = offset in font buffer
            imul si,bx,14           ;BH should be zero here
            add si,CurFont

            mov cx,14               ;14 rows
pc_loop:    lodsb                   ;Get font char
            xor al,ah               ;XOR with mask
            stosb                   ;Write to screen
            add di,79               ;Move to next row
            loop pc_loop            ;Loop back

            pop es                  ;Restore registers
            popa
            ret                     ;Return

PutChar     EndP

;---------------------------------------------------------------------
; PutCursor -- Draw or erase the cross cursor
;---------------------------------------------------------------------

PutCursor   Proc

            pusha                   ;Save registers

            imul di,XPos,X_SIZE     ;(DI, BP) = center of rectangle
            imul bp,YPos,Y_SIZE     ;in large char display
            add di,380+(X_SIZE/2)
            add bp,(Y_SIZE/2)

            mov bx,di               ;Flip the center pixel
            mov cx,bp
            call FlipPixel

            mov dx,(X_SIZE/2)-2     ;DX = distance from center to edge - 2
            mov si,O(CrossYList)    ;SI = Y position list
            mov bx,1                ;X position = 1
            xor cx,cx               ;Zero CX

pcr_loop:   lodsb                   ;CX = Y position
            mov cl,al

            neg bx                  ;Flip four pixels
            call pcr_draw
            neg cx
            call pcr_draw
            neg bx
            call pcr_draw
            neg cx
            call pcr_draw

            inc bx                  ;Next pixel
            dec dx                  ;Loop back
            jnz pcr_loop

            popa                    ;Restore registers
            ret                     ;Return

pcr_draw:   add bx,di               ;BX = X, CX = Y
            add cx,bp
            call FlipPixel          ;Flip this pixel
            sub bx,di               ;Fix BX, CX
            sub cx,bp
            ret                     ;Return

PutCursor   EndP

;---------------------------------------------------------------------
; PutPixel -- Set the value of a pixel
;---------------------------------------------------------------------
; BX = X, CX = Y, AL = color (0 or 1)

PutPixel    Proc

            pusha                   ;Save all registers
            push ds
            push 0A000h             ;DS = video memory
            pop ds

            mov dx,bx               ;DX = X
            imul bx,cx,80           ;BX = Y * 80 = row offset
            mov cx,dx               ;CX = X
            shr dx,3                ;DX = byte offset within row
            add bx,dx               ;BX = offset

            and cl,7                ;AH = bit mask
            mov ah,80h
            shr ah,cl

            test al,al              ;Check pixel color
            jz pp_off               ;Jump if turning off

pp_on:      or [bx],ah              ;Turn pixel on
            jmp pp_done

pp_off:     not ah                  ;Turn pixel off
            and [bx],ah

pp_done:    pop ds                  ;Restore registers
            popa
            ret                     ;Return

PutPixel    EndP

;---------------------------------------------------------------------
; PutRow -- Draw a row of pixels in the same color
;---------------------------------------------------------------------
; BX = X1, CX = X2, DX = Y, AL = color (0 or 1)

PutRow      Proc

            pusha                   ;Save all registers
            push es
            push 0A000h             ;ES = video memory
            pop es

            cmp bx,cx               ;Put them in order
            jng $+4
            xchg bx,cx

            cmp al,1                ;BP = color
            sbb bp,bp
            not bp

;-------------------------------------------------

            push dx cx dx bx        ;Store parameters

            xchg ax,cx              ;If it's all on
            shr ax,3                ;the same byte,
            shr bx,3                ;like 00111110,
            cmp ax,bx               ;then use the
            je pr_thin              ;other routine.

            pop cx bx               ;CX = x1, BX = y
            call pr_offs            ;Get offsets
            mov al,0FFh             ;Translate to the
            shr al,cl               ;multiple-pixel value
            call pr_partial         ;Write pixels
            mov dx,bx               ;Save offset

            pop cx bx               ;CX = x2, BX = y
            call pr_offs            ;Get offsets
            mov al,080h             ;Translate to the
            shr al,cl               ;multiple-pixel value
            neg al
            call pr_partial         ;Write pixels

            inc dx                  ;Start at second byte
            sub bx,dx               ;Byte length in BX
            jz pr_ret               ;Zero, nothing to do

            mov di,dx               ;DI = offset
            mov cx,bx               ;CX = count

            mov ax,bp               ;AX = color
            shr cx,1                ;Count in words
            rep stosw               ;Draw solid line
            adc cl,ch               ;Possible odd byte
            rep stosb

pr_ret:     pop es                  ;Restore registers
            popa
            ret                     ;Return

;-------------------------------------------------

pr_thin:    pop cx di               ;CX = x1, BX = y
            mov bx,dx
            call pr_offs            ;Get offsets
            mov ah,0FFh             ;0FFh for multiple pixels
            shr ah,cl               ;Get value

            pop cx di               ;CX = x2
            and cx,7
            mov al,080h             ;Translate to the
            shr al,cl               ;multiple-pixel value
            neg al

            and al,ah               ;Combine values
            push O(pr_ret)          ;Set return offset

;-------------------------------------------------

pr_partial: test bp,bp              ;Jump if turning on
            jnz pr_pon
pr_poff:    not al                  ;AL = AND mask
            and es:[bx],al          ;Turn pixels off
            ret                     ;Return
pr_pon:     or es:[bx],al           ;Turn pixels on
            ret                     ;Return

;-------------------------------------------------

pr_offs:    imul bx,80              ;Get offset in BX,
            ror cx,3                ;shift in CX
            add bl,cl
            adc bh,0
            shr cx,13
            ret

PutRow      EndP

;---------------------------------------------------------------------
; PutStr -- Output a string to the screen (like INT 21/09)
;---------------------------------------------------------------------
; BX = X, CX = Y, DS:DX = string (BX should be 0 mod 8)

PutStr      Proc

            pusha                   ;Save all registers
            mov si,dx               ;DS:SI = string

ps_loop:    lodsb                   ;Get a character
            cmp al,'$'              ;Exit if '$'
            je ps_done
            call PutChar            ;Draw the character
            add bx,8                ;Move right 8 pixels
            jmp ps_loop             ;Loop back

ps_done:    popa
            ret                     ;Return

PutStr      EndP

;---------------------------------------------------------------------
; RestoreScr -- Restore the screen
;---------------------------------------------------------------------

RestoreScr  Proc

            pusha                   ;Save all registers
            push ds
            push es

            push cs                 ;DS = CS
            pop ds
            push 0A000h             ;ES = video memory
            pop es

            mov si,O(ScreenBuf)     ;Copy ScreenBuf to the screen
            xor di,di
            mov cx,28000/2
            rep movsw

            pop es                  ;Restore registers
            pop ds
            popa
            ret                     ;Return

RestoreScr  EndP

;---------------------------------------------------------------------
; SaveScr -- Save & clear the screen
;---------------------------------------------------------------------

SaveScr     Proc

            pusha                   ;Save all registers
            push ds
            push es

            push 0A000h             ;DS = video memory
            pop ds
            push cs                 ;ES = CS
            pop es

            xor si,si               ;Copy the screen to ScreenBuf
            mov di,O(ScreenBuf)
            mov cx,28000/2
            rep movsw

            push ds                 ;ES = video memory
            pop es

            xor di,di               ;Clear the screen
            xor ax,ax
            mov cx,28000/2
            rep stosw

            pop es                  ;Restore registers
            pop ds
            popa
            ret                     ;Return

SaveScr     EndP

;---------------------------------------------------------------------
; Shift -- Shift the current character
;---------------------------------------------------------------------

Shift       Proc

            pusha                   ;Save all registers

            xor bx,bx               ;Display shift prompt
            mov cx,336
            mov dx,O(Shift$)
            mov ah,0FFh             ;Black on white
            call PutStr

            imul si,CurChar,14      ;SI = offset of char
            add si,O(Buffer)

            xor ah,ah               ;Get a key
            int 16h
            mov al,ah               ;AL = key

            cmp al,4Bh              ;Left?
            je sh_left
            cmp al,4Dh              ;Right?
            je sh_right
            cmp al,48h              ;Up?
            je sh_up
            cmp al,50h              ;Down?
            je sh_down

sh_done:    mov ax,CurChar          ;Re-display the character
            call ShowChar
            popa                    ;Restore registers
            ret                     ;Return

;-------------------------------------------------

sh_left:    mov cx,14               ;14 bytes
sh_lloop:   shl B [si],1            ;Shift left
            inc si                  ;Next byte
            loop sh_lloop           ;Loop back
            jmp sh_done

;-------------------------------------------------

sh_right:   mov cx,14               ;14 bytes
sh_rloop:   shr B [si],1            ;Shift right
            inc si                  ;Next byte
            loop sh_rloop           ;Loop back
            jmp sh_done

;-------------------------------------------------

sh_up:      mov di,si               ;Shift 13 bytes up
            inc si
            mov cx,13
            rep movsb
            mov B [di],0            ;Clear the bottom line
            jmp sh_done

;-------------------------------------------------

sh_down:    mov bx,13               ;13 bytes
sh_dloop:   mov al,[si+bx-1]        ;Shift one byte down
            mov [si+bx],al
            dec bx                  ;Next byte
            jnz sh_dloop            ;Loop back
            mov B [si],0            ;Clear the top line
            jmp sh_done

Shift       EndP

;---------------------------------------------------------------------
; ShowChar -- Display a font character on the screen
;---------------------------------------------------------------------
; AL = char

ShowChar    Proc

            pusha                   ;Save all registers

            xor ah,ah               ;Zero AH
            mov bp,ax               ;BP = char

            mov CurFont,O(Buffer)   ;Set working font

            mov bx,ax               ;BX = X position
            and bx,1Fh              ;X = (ch MOD 16) * 8
            imul bx,8
            mov cx,ax               ;CX = Y position
            shr cx,5                ;Y = (ch / 16) * 18
            imul cx,18

            add bx,8                ;Adjust for UL corner
            add cx,30

            lea si,[bx+7]           ;SI, DI = LR corner of rectangle
            mov di,cx
            add di,17
            xor al,al               ;Clear the rectangle
            call FillRect

            mov ax,bp               ;Display the char
            add cx,2
            call PutChar

            mov CurFont,O(BiosFont) ;Set BIOS font

            cmp bp,CurChar          ;If it is the current char, then:
            jne sc_done

;-------------------------------------------------

            mov al,1                ;Color is white
            mov dx,cx               ;BX = X1, CX = X2, DX = Y
            mov cx,si
            sub dx,2                ;Draw the top line
            call PutRow
            add dx,17               ;Draw the bottom line
            call PutRow

            xor cx,cx               ;Y = 0
sc_oloop:   xor bx,bx               ;X = 0
sc_iloop:   call FGetPixel          ;Read this pixel from the font
            call FPutPixel          ;Display it on screen
            inc bx                  ;Next pixel
            cmp bx,8                ;Loop while < 8
            jb sc_iloop
            inc cx                  ;Next row
            cmp cx,14               ;Loop while < 14
            jb sc_oloop

;-------------------------------------------------

            mov ax,CurChar          ;AH = first digit
            mov ah,al               ;AL = second digit
            and al,0Fh
            shr ah,4

            cmp al,0Ah              ;Convert AL to hex
            sbb al,69h
            das
            xchg al,ah              ;Switch AL, AH
            cmp al,0Ah              ;Convert AL to hex
            sbb al,69h
            das

            mov W HexData,ax        ;Set hex string

            xor bx,bx               ;Output the status string
            mov cx,336
            mov dx,O(CharStr$)
            xor ah,ah
            call PutStr

            mov bx,168              ;Display the character
            mov ax,CurChar
            call PutChar

sc_done:    popa                    ;Restore registers
            ret                     ;Return

ShowChar    EndP

;---------------------------------------------------------------------
; TypeMode -- Typing mode loop
;---------------------------------------------------------------------

TypeMode    Proc

            pusha                   ;Save all registers

            call SaveScr            ;Save & clear the screen

t_begin:    mov CurFont,O(Buffer)   ;Set working font
            xor ax,ax               ;Start with char 0
            mov cx,238              ;Y starts at 238
t_yloop:    mov bx,384              ;X starts at 384

t_xloop:    call PutChar            ;Display one character
            add bx,8                ;Move right one char
            inc ax                  ;Next character
            test al,1Fh             ;Loop until done 32 characters
            jnz t_xloop

            add cx,14               ;Move down one line
            test ah,ah              ;Loop until done 8 lines
            jz t_yloop

            xor bx,bx               ;Start at (0, 0)
            xor cx,cx

;-------------------------------------------------

t_keyloop:  mov CurFont,O(BiosFont) ;Set BIOS font
            mov ax,'_'              ;Display a cursor
            call PutChar

            int 16h                 ;Wait for a key (AH = 0)

            push ax                 ;Save AX
            mov ax,' '              ;Remove the cursor
            call PutChar
            pop ax                  ;Restore AX

            cmp al,20h              ;Character?
            jae t_char
            cmp al,1Bh              ;Escape?
            je t_done
            cmp al,0Dh              ;Enter?
            je t_enter
            cmp al,08h              ;Backspace?
            je t_bksp

            jmp t_keyloop           ;Invalid, loop

;-------------------------------------------------

t_char:     mov CurFont,O(Buffer)   ;Set working font
            xor ah,ah               ;Display this character
            call PutChar
            add bx,8                ;Move right one char
            cmp bx,640              ;Loop if not off the end
            jb t_keyloop            ;Otherwise, fall through...

t_enter:    add cx,14               ;Move down one line
            xor bx,bx               ;Move to the far left
            cmp cx,350              ;If we went off the bottom,
            jae t_begin             ;then restart typing mode
            jmp t_keyloop

t_bksp:     test bx,bx              ;If not already at the left, then
            jz t_keyloop
            sub bx,8                ;move left one char
            jmp t_keyloop

;-------------------------------------------------

t_done:     call RestoreScr         ;Restore the screen
            popa                    ;Restore registers
            ret                     ;Return

TypeMode    EndP

;---------------------------------------------------------------------

FileName    db 128 dup(?)           ;File name

Clipboard   db 14 dup(?)            ;Clipboard

Buffer      db 3584 dup(?)          ;Buffer for font
BiosFont    db 3584 dup(?)          ;EGA BIOS font

ScreenBuf   db 28000 dup(?)         ;Screen save buffer

End Start
[ RETURN TO DIRECTORY ]