;======================================================================
; HEXEDIT * 1.00 Copyright (c) 1992, Robert L. Hummel
; PC Magazine Assembly Language Lab Notes
;----------------------------------------------------------------------
CSEG SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
ORG 100H ;COM file format
ENTPT: JMP MAIN
;======================================================================
; Program data area.
;----------------------------------------------------------------------
CR EQU 13 ;ASCII carriage return
LF EQU 10 ;ASCII line feed
BLANK EQU 32 ;ASCII blank
RARROW EQU 4DH ;Move forward 1 char
DARROW EQU 50H ;Move forward 1 row
PGDN EQU 51H ;Move forward 1 screen
LARROW EQU 4BH ;Move backward 1 char
UARROW EQU 48H ;Move backward 1 row
PGUP EQU 49H ;Move backward 1 screen
F7KEY EQU 41H ;Exit the editor
F8KEY EQU 42H ;Switch between HEX and ASCII displays
;----------------------------------------------------------------------
; Messages.
;----------------------------------------------------------------------
COPYRIGHT$ DB CR,LF,"HEXEDIT 1.00 ",254," Copyright (c) 1992"
DB ", Robert L. Hummel",CR,LF
DB "PC Magazine Assembly Language Lab Notes",LF
CRLF$ DB CR,LF,"$"
USAGE$ DB "Usage: HEXEDIT [d:][path]filename.ext$"
CONFIRM$ DB "Exiting. Make changes permanent? (Y/N) $"
ERR_VIDEO$ DB "Video mode must be text, 80 or more columns$"
ERR_MEM$ DB "There's not enough memory to execute$"
ERR_DRIVE$ DB "Drive is invalid$"
ERR_FIND$ DB "Can't find the file$"
ERR_TMP$ DB "Trouble with HEXEDIT~.@@@ scratch file$"
ERR_SRC$ DB "Trouble reading/writing the file$"
ERR_REN$ DB "Can't rename file. Changes in HEXEDIT~.@@@$"
;----------------------------------------------------------------------
; File data.
;----------------------------------------------------------------------
SRC_HANDLE DW 0 ;Source file handle
SRC_NAME DW 0 ;Pointer to file name
TMP_NAMEZ DB "HEXEDIT~.@@@",0 ;Scratch file name
TMP_HANDLE DW 0 ;Scratch file handle
;----------------------------------------------------------------------
; Buffer and display window data.
;----------------------------------------------------------------------
FILE_ALTERED DB 0 ;>0 if changes were made to file
BUF_ANCHOR DD 0 ;Pos in file of 1st byte of buffer
BUF_ANCHOR_MAX DD 0 ;Furthest forward buffer can start
BUF_SIZE DW 0 ;Maximum number bytes buffer can hold
BUF_BYTES DW 0 ;# valid bytes in buffer
FULLY_BUFFERED DB 0 ;>0 if entire file fits in buffer
BUF_ALTERED DB 0 ;>0 if buffer has been altered
REDO_BUF DB 0 ;>0 if buffer has moved wrt file
GRID_ANCHOR DW 0 ;Offset into buffer of 1st dislay byte
REDO_GRID DB 0 ;Non-zero if need to redraw grid fm buf
GRIDROW DB 0 ;Current grid row
GRIDROWMAX EQU 15
GRIDCOL DB 0 ;Current grid column
GRIDCOLMAX EQU 15
GRID_LEN EQU (GRIDCOLMAX + 1)*(GRIDROWMAX+1)
LEFT EQU 0F0H ;HEX mode, left digit
RIGHT EQU 00FH ;HEX mode, right digit
MODE_MASK EQU 13H ;Tri-state mask
MODE DB 0 ;Mode, 0 = ASCII
;----------------------------------------------------------------------
; Video data.
;----------------------------------------------------------------------
ROW_0 EQU 5 ;Screen row for grid row 0
OFF_COL EQU 2 ;Starting screen column for offset
HEX_COL EQU 12 ;Starting screen column for hex display
ASC_COL EQU 61 ;Starting screen column for ASCII chars
VPAGE DB 0 ;Active video page
VATTR DB 07H ;Attribute for display (mono default)
ATTR_COLOR EQU 17H ;Attribute for color displays
VCURSOR DW 0 ;Holds row/column for screen cursor
;======================================================================
; MAIN procedure.
;----------------------------------------------------------------------
MAIN PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
;----------------------------------------------------------------------
; Initialize.
;----------------------------------------------------------------------
CLD ;String moves forward
MOV CL,AL ;Save drive status
;----------------------------------------------------------------------
; Check the video mode and initialize the display variables.
;----------------------------------------------------------------------
CALL VIDEO_SETUP ;Examine video hardware
MOV DX,OFFSET ERR_VIDEO$ ;Assume an error
JC M_1
;----------------------------------------------------------------------
; Make sure there's enough room for the stack and relocate it to the
; end of the code.
;----------------------------------------------------------------------
MOV DX,OFFSET ERR_MEM$ ;Assume error
MOV AX,OFFSET STACK_TOP ;We want stack here
CMP SP,AX ;Are we beyond it?
JBE M_1
CLI ;Disable interrupts
XCHG AX,SP ; and re-position stack
STI ;Allow interrupts
;----------------------------------------------------------------------
; Determine how many bytes can be allocated in the remainder of the
; segment. We must have at least 512 bytes.
;----------------------------------------------------------------------
SUB AX,SP ;Free bytes
CMP AX,512 ;Minimum allowed
JB M_1
AND AL,0FEH ;Make number even
MOV [BUF_SIZE],AX ;Save buffer size
;----------------------------------------------------------------------
; Check if an invalid drive was specified on the command line.
;----------------------------------------------------------------------
MOV DX,OFFSET ERR_DRIVE$ ;Assume an error
INC CL ;If was FF, now 00
JNZ M_2
;----------------------------------------------------------------------
; Exit the program, displaying the message passed in DX and the
; copyright notice.
;----------------------------------------------------------------------
M_1:
MOV AH,9 ;Display string
INT 21H ; thru DOS
M_EXIT:
MOV AH,9 ;Display string
MOV DX,OFFSET CRLF$ ;New line
INT 21H ; thru DOS
MOV AH,9 ;Display string fn
MOV DX,OFFSET COPYRIGHT$ ; located here
INT 21H ; thru DOS
MOV AH,4CH ;Terminate process
INT 21H ; thru DOS
;----------------------------------------------------------------------
; If no characters are in the command tail, show the usage message.
;----------------------------------------------------------------------
M_2:
MOV DX,OFFSET USAGE$ ;Assume no characters
MOV SI,80H ;Point to tail length
LODSB ;Get length in AL
OR AL,AL ;Any chars?
JZ M_1
CBW ;Change length to word
MOV DI,SI ;Starting offset
ADD DI,AX ; + length = end offset
MOV [DI],AH ;Convert to ASCIIZ
;----------------------------------------------------------------------
; Find the first non-blank char. If it's a zero, show usage message.
;----------------------------------------------------------------------
M_3A:
LODSB ;Get char in AL
CMP AL,BLANK ;Leading blank?
JE M_3A
OR AL,AL ;If 0, no chars
JZ M_1
DEC SI ;Point to 1st non-blank
MOV DI,SI ;Save it in DI
;----------------------------------------------------------------------
; Find the end of the string as indicated by a blank or the zero.
;----------------------------------------------------------------------
M_3B:
LODSB ;Get next char
OR AL,AL ;Stop if zero
JZ M_3C
CMP AL,BLANK ;Continue unless blank
JNE M_3B
M_3C:
DEC SI ;Point to last char
MOV [SI],AH ;Make ASCIIZ
MOV [SRC_NAME],DI ;Save pointer to name
;----------------------------------------------------------------------
; Attempt to open the file found on the command line.
;----------------------------------------------------------------------
MOV AX,3D00H ;Open file for reading
MOV DX,DI ;Point DS:DX to name
INT 21H ; thru DOS
MOV DX,OFFSET ERR_FIND$ ;Assume error
JC M_1
MOV [SRC_HANDLE],AX ;Save source handle
;----------------------------------------------------------------------
; Create a scratch file and copy the file over.
;----------------------------------------------------------------------
MOV AH,3CH ;Create file
SUB CX,CX ;Normal attributes
MOV DX,OFFSET TMP_NAMEZ ;This name
INT 21H ; thru DOS
MOV DX,OFFSET ERR_TMP$ ;Assume error
JC M_1
MOV [TMP_HANDLE],AX ;Save file handle
;----------------------------------------------------------------------
; Read data from the source file and write it to the destination file
; until the entire file has been copied.
;----------------------------------------------------------------------
M_4A:
MOV AH,3FH ;Read file
MOV BX,[SRC_HANDLE] ; from this handle
MOV CX,[BUF_SIZE] ; CX bytes
MOV DX,OFFSET BUFFER ;Put data here
INT 21H ; thru DOS
JNC M_4C
M_4B:
MOV DX,OFFSET ERR_SRC$ ;Error reading file
JMP M_1
M_4C:
OR AX,AX ;No bytes read?
JZ M_4F
MOV CX,AX ;Write the same #
MOV AH,40H ;Write file
MOV BX,[TMP_HANDLE] ; to this handle
INT 21H ; thru DOS
JNC M_4A
M_4D:
MOV DX,OFFSET ERR_TMP$ ;Error writing file
M_4E:
JMP M_1
M_4F:
;----------------------------------------------------------------------
; Close the source file; we won't need it again.
;----------------------------------------------------------------------
MOV AH,3EH ;Close handle fn
MOV BX,[SRC_HANDLE] ;Handle for source file
INT 21H ; thru DOS
JC M_4B
;----------------------------------------------------------------------
; Get the size of the file by seeking to the end of the file.
;----------------------------------------------------------------------
MOV AX,4202H ;Seek, offset from end
MOV BX,[TMP_HANDLE] ;Handle for the file
SUB CX,CX ;CX:DX =
SUB DX,DX ; offset from end
INT 21H ; thru DOS
JC M_4D
;----------------------------------------------------------------------
; If the number of bytes in the file is smaller or equal to the number
; of bytes the buffer can hold, all moves can be handled in the buffer.
;----------------------------------------------------------------------
MOV BX,[BUF_SIZE] ;Buffer capacity
OR DX,DX ;If not 0, file > 64k
JNZ M_5A
CMP AX,BX ;Fit in buffer?
JA M_5A
INC [FULLY_BUFFERED] ;Yes, set flag
JMP SHORT M_5B
;----------------------------------------------------------------------
; If the file is larger than the buffer, calculate the maximum buffer
; anchor value so we don't have to do it repeatedly later.
;----------------------------------------------------------------------
M_5A:
PUSH AX ;Save file length
PUSH DX ; in DX:AX
SUB AX,BX ;Figure max anchor
SBB DX,CX ;(CX is 0)
MOV WORD PTR [BUF_ANCHOR_MAX][0],AX ;Max BUF_ANCHOR
MOV WORD PTR [BUF_ANCHOR_MAX][2],DX ; position
POP DX ;Restore file length
POP AX
M_5B:
;----------------------------------------------------------------------
; Draw the graphics characters that make up the window background.
;----------------------------------------------------------------------
CALL DRAW_BKGND
;----------------------------------------------------------------------
; Invoke the editor. If it returns with the carry flag set, a file
; error was encountered. Print a message and abort the edit.
;----------------------------------------------------------------------
CALL EDIT ;Edit the file
JC M_4E
;----------------------------------------------------------------------
; Close the temporary file to commit the changes to disk.
;----------------------------------------------------------------------
MOV AH,3EH ;Close file handle
MOV BX,[TMP_HANDLE] ;This handle
INT 21H ; thru DOS
JC M_4D
;----------------------------------------------------------------------
; Clear the screen and position the cursor to the top left corner.
;----------------------------------------------------------------------
MOV AX,0700H ;Scroll window fn
MOV BH,[VATTR] ; clear to this color
SUB CX,CX ;Topleft row,col
MOV DX,(24 SHL 8 + 79) ;Lowright row,col
INT 10H ; thru BIOS
MOV AH,2 ;Position cursor
MOV BH,[VPAGE] ;On this video page
SUB DX,DX ;Row 0, col 0
INT 10H ; thru BIOS
;----------------------------------------------------------------------
; If changes were made to the file, ask if they should be permanent.
;----------------------------------------------------------------------
CMP [FILE_ALTERED],0 ;Flag 0 if no changes
JE M_7
MOV AH,9 ;Display string fn
MOV DX,OFFSET CONFIRM$ ;Make permanent?
INT 21H ; thru DOS
M_6:
MOV AH,8 ;Get a key
INT 21H ; thru DOS
AND AL,NOT 20H ;Capitalize it
CMP AL,"Y" ;If Yes, jump
JE M_8A
CMP AL,"N" ;If not No, try again
JNE M_6
;----------------------------------------------------------------------
; Don't save the changes, just delete the temporary file and exit.
;----------------------------------------------------------------------
M_7:
MOV AH,41H ;Delete file handle
MOV DX,OFFSET TMP_NAMEZ ;This name
INT 21H ; thru DOS
JNC M_8D
JMP M_4D
;----------------------------------------------------------------------
; Make the changes permanent. Delete the original file. If the original
; file can't be renamed, leave the temporary file intact.
;----------------------------------------------------------------------
M_8A:
MOV AH,41H ;Delete file handle
MOV DX,[SRC_NAME] ;This name
INT 21H ; thru DOS
JNC M_8C
M_8B:
MOV AH,9 ;Display string fn
MOV DX,OFFSET CRLF$ ;Go to new line
INT 21H ; thru DOS
MOV DX,OFFSET ERR_REN$ ;Renaming error
JMP M_1
;----------------------------------------------------------------------
; Rename the temp file to the original name.
;----------------------------------------------------------------------
M_8C:
MOV AH,56H ;Rename file
MOV DX,OFFSET TMP_NAMEZ ;Old name at DS:DX
MOV DI,[SRC_NAME] ;New name at ES:DI
INT 21H ; thru DOS
JC M_8B
M_8D:
JMP M_EXIT
MAIN ENDP
;======================================================================
; VIDEO_SETUP (Near)
;
; This procedure ensures that we're in a text mode and that the number
; of columns on the screen is 80 or greater and gets the current video
; page. It also adjusts the screen attribute for monochrome screens. It
; will allow the program to run in graphics mode, but won't guarantee a
; pretty screen. Return with carry set if display is in an incompatible
; mode.
;----------------------------------------------------------------------
; Entry: None
; Exit:
; NC = Video mode and screen size is okay
; CY = Can't use this video mode or not enough columns
;----------------------------------------------------------------------
; Changes: AX BX
;----------------------------------------------------------------------
VIDEO_SETUP PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING, SS:CSEG
MOV AH,0FH ;Get video mode
INT 10H ; thru BIOS
;----------------------------------------------------------------------
; Now make sure we're in a text mode.
;----------------------------------------------------------------------
CMP AL,7 ;7 = monochrome
JE VS_1
MOV [VATTR],ATTR_COLOR ;Assume color mode
CMP AL,4 ;Carry clear if NG
JNB VS_2
VS_1:
;----------------------------------------------------------------------
; Make sure there are at least 80 columns.
;----------------------------------------------------------------------
CMP AH,80 ;Enough columns?
JB VS_EXIT ;JB=JC=carry set
MOV [VPAGE],BH ;Save current page
STC ;Set carry...
VS_2:
CMC ;...then reverse it
VS_EXIT:
RET
VIDEO_SETUP ENDP
;======================================================================
; DRAW_BKGND (Near)
;
; Clear the screen and draw the framework for the editing window.
;----------------------------------------------------------------------
; Entry: None
; Exit : None
;----------------------------------------------------------------------
; Changes: AX BX CX DX SI
;----------------------------------------------------------------------
TITLE$ DB "HEXEDIT 1.00 ",254," PC Magazine Assembly "
DB "Language Lab Notes ",254," Robert L. Hummel$"
TITLE_LEN EQU $-OFFSET TITLE$
HELP$ DB "Editing Keys: ",27,32,32,26,32,32,24,32,32,25
DB " PgUp PgDn F7 = Save/Abort F8=Hex/ASCII$"
HELP_LEN EQU $-OFFSET HELP$
OFFSET$ DB "OFFSET$"
OFFSET_POS EQU 0303H
HEX$ DB "HEX DATA$"
HEX_POS EQU 0320H
ASCII$ DB "ASCII DATA$"
ASCII_POS EQU 0340H
WIN_CHARS DB 1,201,205,205,187
DB 1,186, 32, 32,186
DB 1,199,196,194,182
DB 18,186, 32,179,186
DB 1,199,196,193,182
DB 2,186, 32, 32,186
DB 1,200,205,205,188
DB -1
DRAW_BKGND PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING, SS:CSEG
;----------------------------------------------------------------------
; Clear the box area to set the attribute for the characters.
;----------------------------------------------------------------------
MOV AX,0700H ;Scroll window fn
MOV BH,[VATTR] ;Clear to this color
SUB CX,CX ;Topleft row,col
MOV DX,(24 SHL 8 + 79) ;Lowright row,col
INT 10H ; thru BIOS
;----------------------------------------------------------------------
; Prepare to draw the screen.
;----------------------------------------------------------------------
MOV BH,[VPAGE] ;Get active page
MOV SI,OFFSET WIN_CHARS ;Point to array
SUB DH,DH ;Starting row = 0
;----------------------------------------------------------------------
; The first byte indicates how many rows to draw with this set of
; characters. If -1, we're done.
;----------------------------------------------------------------------
DB_1:
LODSB ;Get # rows to draw
OR AL,AL ;Check if -1
JS DB_3
CBW ;Convert count to word
MOV CX,AX ;Put in count register
;----------------------------------------------------------------------
; Repeat this procedure once for each row.
;----------------------------------------------------------------------
DB_2:
PUSH CX ;Save row counter
;----------------------------------------------------------------------
; Position to the current row, column 0 and write the leftmost char.
; Write TTY automatically advances the cursor.
;----------------------------------------------------------------------
MOV AH,2 ;Position cursor
SUB DL,DL ; to column 0
INT 10H ; thru BIOS
MOV AL,[SI] ;Get leftmost char
MOV AH,0EH ;Write 1 char TTY
INT 10H ; thru BIOS
;----------------------------------------------------------------------
; Fill the middle 78 chars with the next char in the array.
;----------------------------------------------------------------------
MOV AL,[SI+1] ;Get middle char
MOV AH,0AH ;Write repeated char
MOV CX,78 ; this many
INT 10H ; thru BIOS
;----------------------------------------------------------------------
; Position the cursor to the two interior partition spots and draw the
; character required.
;----------------------------------------------------------------------
MOV AH,2 ;Position cursor
MOV DL,10 ; to first partition
INT 10H ; thru BIOS
MOV AL,[SI+2] ;Get partition char
MOV AH,0EH ;Write 1 char TTY
INT 10H ; thru BIOS
MOV AH,2 ;Position cursor
MOV DL,60 ; to first partition
INT 10H ; thru BIOS
MOV AH,0EH ;Write 1 char TTY
INT 10H ; thru BIOS
;----------------------------------------------------------------------
; Position to the right side of the screen and draw the final character
; for this row. Don't use Write TTY because it scrolls the screen.
;----------------------------------------------------------------------
MOV AH,2 ;Position cursor
MOV DL,79 ; to far right
INT 10H ; thru BIOS
MOV AL,[SI+3] ;Get rightmost char
MOV AH,0AH ;Write char
MOV CX,1 ;1 copy
INT 10H ; thru BIOS
INC DH ;Next row
POP CX ;Restore counter
LOOP DB_2
;----------------------------------------------------------------------
; Move to the next array row and continue.
;----------------------------------------------------------------------
ADD SI,4
JMP DB_1
;----------------------------------------------------------------------
; Display the title, column headings, and help prompt.
;----------------------------------------------------------------------
DB_3:
MOV AH,2 ;Position cursor
MOV DX,100H+(80-TITLE_LEN)/2 ; to this row,col
INT 10H ; thru BIOS
MOV AH,9 ;Display string
MOV DX,OFFSET TITLE$ ; showing title
INT 21H ; thru DOS
MOV AH,2 ;Position cursor
MOV DX,OFFSET_POS
INT 10H ; thru BIOS
MOV AH,9 ;Display string
MOV DX,OFFSET OFFSET$ ;Offset heading
INT 21H ; thru DOS
MOV AH,2 ;Position cursor
MOV DX,HEX_POS
INT 10H ; thru BIOS
MOV AH,9 ;Display string
MOV DX,OFFSET HEX$ ;Hex data heading
INT 21H ; thru DOS
MOV AH,2 ;Position cursor
MOV DX,ASCII_POS
INT 10H ; thru BIOS
MOV AH,9 ;Display string
MOV DX,OFFSET ASCII$ ;ASCII data heading
INT 21H ; thru DOS
MOV AH,2 ;Position cursor
MOV DX,1700H+(80-HELP_LEN)/2 ; to this row/col
INT 10H ; thru BIOS
MOV AH,9 ;Display string
MOV DX,OFFSET HELP$ ; showing help
INT 21H ; thru DOS
RET
DRAW_BKGND ENDP
;======================================================================
; EDIT (Near)
;
; On entry, the background editing screen has been drawn and the buffer
; has been initialized to hold the first portion of the file.
;----------------------------------------------------------------------
; Entry: None
; Exit :
; CY - indicates a file error occurred while buffering
; NC - everything went okay
;----------------------------------------------------------------------
; Changes: AX BX CX DX
;----------------------------------------------------------------------
EDIT PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
;----------------------------------------------------------------------
; Set the flags so the buffer will be filled and the display updated.
;----------------------------------------------------------------------
INC [REDO_BUF] ;Fill buffer
INC [REDO_GRID] ;Draw display
JMP SHORT EDIT_0B
;----------------------------------------------------------------------
; The move couldn't be performed within the grid. Move the grid so
; that the desired byte is visible.
;----------------------------------------------------------------------
EDIT_0A:
CALL MOVE_GRID
JNC EDIT_0B
;----------------------------------------------------------------------
; If MOVE_GRID returned with CY, a file error occurred.
;----------------------------------------------------------------------
EDIT_EXIT:
RET
;----------------------------------------------------------------------
; If required, FILL_BUFFER will refresh the buffer.
;----------------------------------------------------------------------
EDIT_0B:
CALL FILL_BUFFER ;Refresh the buffer
JC EDIT_EXIT ;Exit if error
;----------------------------------------------------------------------
; If required, translate the visible portion of the buffer to the screen.
;----------------------------------------------------------------------
EDIT_0C:
CALL DISPLAY_GRID ;Refresh screen
;----------------------------------------------------------------------
; Set the cursor so it appears under the correct screen character.
;----------------------------------------------------------------------
EDIT_0D:
CALL SET_CURSOR ;Place cursor
;----------------------------------------------------------------------
; Get a key from the keyboard and act on it.
;----------------------------------------------------------------------
EDIT_1A:
SUB AH,AH ;Fetch a key
INT 16H ; thru BIOS
OR AL,AL ;If AL=0, is extended
JZ EDIT_1B
JMP EDIT_11
EDIT_1B:
;----------------------------------------------------------------------
; *** Right arrow.
;----------------------------------------------------------------------
CMP AH,RARROW ;Right arrow
JNE EDIT_3A
EDIT_1C:
TEST [MODE],MODE_MASK ;Check hex/ascii
JZ EDIT_2C ;Jump if ASCII
JPE EDIT_2B ;Jump if RIGHT
;----------------------------------------------------------------------
; HEX mode. If cursor is on left hex digit, move to right hex digit.
;----------------------------------------------------------------------
NOT [MODE] ;Mode = right hex digit
MOV AL,1 ;Move right 1 column
EDIT_2A:
CALL MOVE_CURSOR ;Move cursor
JMP EDIT_0C
;----------------------------------------------------------------------
; If cursor is on right hex digit, move to left hex digit, then...
;----------------------------------------------------------------------
EDIT_2B:
MOV [MODE],LEFT ;Change to left digit
;----------------------------------------------------------------------
; Move to next grid byte.
;----------------------------------------------------------------------
EDIT_2C:
CMP [GRIDCOL],GRIDCOLMAX ;Are we at far right?
JE EDIT_2E
INC [GRIDCOL] ;No - move to next byte
JMP EDIT_0C ;Recalc cursor
EDIT_2E:
CMP [GRIDROW],GRIDROWMAX ;Are we at bottom?
JE EDIT_2G
MOV [GRIDCOL],0 ;Move to first byte
EDIT_2F:
INC [GRIDROW] ; in next row
JMP EDIT_0C ;Recalc cursor
EDIT_2G:
MOV AX,1 ;Move buffer +1 byte
JMP EDIT_0A ;Redo buffer
;----------------------------------------------------------------------
; *** Down arrow.
;----------------------------------------------------------------------
EDIT_3A:
CMP AH,DARROW
JNE EDIT_4A
CMP [GRIDROW],GRIDROWMAX ;Are we at bottom?
JNE EDIT_2F
MOV AX,16 ;Move 1 row
JMP EDIT_0A ;Redo buffer
;----------------------------------------------------------------------
; *** PgDn.
;----------------------------------------------------------------------
EDIT_4A:
CMP AH,PGDN
JNE EDIT_5A
MOV AX,GRID_LEN ;Move 1 full screen
JMP EDIT_0A ;Redo buffer
;----------------------------------------------------------------------
; *** Left arrow.
;----------------------------------------------------------------------
EDIT_5A:
CMP AH,LARROW ;Left arrow
JNE EDIT_6A
TEST [MODE],MODE_MASK ;Check hex/ascii
JZ EDIT_5C ;Jump if ASCII
JPO EDIT_5B ;Jump if LEFT
;----------------------------------------------------------------------
; If cursor is on right hex digit, move to left hex digit.
;----------------------------------------------------------------------
NOT [MODE] ;Change to left digit
MOV AL,-1 ;Back up cursor 1 col
JMP EDIT_2A
;----------------------------------------------------------------------
; If cursor is on left hex digit, move to right hex digit, then...
;----------------------------------------------------------------------
EDIT_5B:
MOV [MODE],RIGHT ;Reset to right digit
;----------------------------------------------------------------------
; Move to previous grid byte.
;----------------------------------------------------------------------
EDIT_5C:
CMP [GRIDCOL],0 ;Far left column?
JE EDIT_5D
DEC [GRIDCOL] ;No - back up
JMP EDIT_0C ;Recalc cursor
EDIT_5D:
CMP [GRIDROW],0 ;Top of grid?
JE EDIT_5F
MOV [GRIDCOL],GRIDCOLMAX ;No - back around
EDIT_5E:
DEC [GRIDROW] ;Previous row
JMP EDIT_0C ;Recalc cursor
EDIT_5F:
MOV AX,-1 ;Back up buffer 1 byte
JMP EDIT_0A ;Redo buffer
;----------------------------------------------------------------------
; *** Up arrow.
;----------------------------------------------------------------------
EDIT_6A:
CMP AH,UARROW
JNE EDIT_7A
CMP [GRIDROW],0 ;At top row?
JNE EDIT_5E
MOV AX,-16 ;Back up 16 bytes
JMP EDIT_0A ;Redo buffer
;----------------------------------------------------------------------
; *** PgUp.
;----------------------------------------------------------------------
EDIT_7A:
CMP AH,PGUP
JNE EDIT_8A
MOV AX,-(GRID_LEN) ;Back up 1 screen
JMP EDIT_0A ;Redo buffer
;----------------------------------------------------------------------
; F8 - switch modes.
;----------------------------------------------------------------------
EDIT_8A:
CMP AH,F8KEY
JNE EDIT_9
SUB AL,AL ;Create 0 (ascii mode)
CMP AL,[MODE] ;Is mode 0 (ascii)?
JNE EDIT_8B
MOV AL,LEFT ;Make hex
EDIT_8B:
MOV [MODE],AL ;Save mode
JMP EDIT_0D ;Recalc cursor
;----------------------------------------------------------------------
; F7 - Exit the editor.
;----------------------------------------------------------------------
EDIT_9:
CMP AH,F7KEY
JNE EDIT_10
CALL COMMIT_BUFFER ;Flush if needed
JMP EDIT_EXIT
;----------------------------------------------------------------------
; If here, was not a recognized keystroke. Ignore it and continue.
;----------------------------------------------------------------------
EDIT_10:
JMP EDIT_1A
;----------------------------------------------------------------------
; Key dispatch for non-extended keys.
; If HEX mode, only 0-9 and A-F are accepted.
; In ASCII mode, anything goes!
;
; First, determine the offset into the buffer of the active grid byte.
;----------------------------------------------------------------------
EDIT_11:
MOV DL,AL ;Put char in DL
MOV AL,[GRIDROW] ;Current row
MOV AH,GRIDCOLMAX+1 ;* row length
MUL AH
ADD AL,[GRIDCOL] ;+ current column
MOV BX,[GRID_ANCHOR] ;+ anchor
ADD BX,AX ;= offset of byte
ADD BX,OFFSET BUFFER ;= addr of byte
MOV CH,[MODE] ;Save mode
OR CH,CH
JNZ EDIT_12B
;----------------------------------------------------------------------
; ASCII mode. Substitute the character in DL for the current byte.
; The byte will always be in the buffer, even if not visible!
;----------------------------------------------------------------------
MOV [BX],DL ;Place char in buf
EDIT_12A:
MOV [BUF_ALTERED],1 ;Say buffer is changed
INC [REDO_GRID] ;Request redraw
JMP EDIT_1C ;Goto right arrow
;----------------------------------------------------------------------
; HEX MODE: Check if character is a hex digit.
;----------------------------------------------------------------------
EDIT_12B:
CMP DL,"0" ;Below this, leave
JB EDIT_10
CMP DL,"9" ;Above this, check A-F
JA EDIT_12D
SUB DL,"0" ;Convert char to number
;----------------------------------------------------------------------
; Mask the digit in the lower 4 bits of DL into the current byte.
;----------------------------------------------------------------------
EDIT_12C:
MOV CL,4
MOV DH,DL
SHL DH,CL
OR DL,DH
AND DL,CH ;Mask appropriate bit
NOT CH ;Reverse mask
AND [BX],CH ;Clear old digit
OR [BX],DL ; and substitute new
JMP EDIT_12A
;----------------------------------------------------------------------
; See if A-F.
;----------------------------------------------------------------------
EDIT_12D:
OR DL,20H ;Make lowercase
CMP DL,"a" ;Ignore if below "a"
JB EDIT_10
CMP DL,"f" ; or above "f"
JA EDIT_10
SUB DL,57H ;Convert to digit
JMP EDIT_12C
EDIT ENDP
;======================================================================
; MOVE_GRID (Near)
;
; This routine moves the grid so that the desired data is visible.
;----------------------------------------------------------------------
; Entry:
; AX = integer number of bytes to move the grid
; Exit :
; CY - file error during I/O
; NC - no file errors
;----------------------------------------------------------------------
; Changes: AX BX CX DX SI DI BP
;----------------------------------------------------------------------
MOVE_GRID PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING, SS:CSEG
;----------------------------------------------------------------------
; Load some needed values into registers for speed.
;----------------------------------------------------------------------
MOV BX,[BUF_BYTES] ;Bytes in buffer
MOV BP,[GRID_ANCHOR] ;Grid anchor
MOV SI,WORD PTR [BUF_ANCHOR][0] ;Buffer anchor
MOV DI,WORD PTR [BUF_ANCHOR][2]
;----------------------------------------------------------------------
; If the entire file is smaller than 1 grid, we can just leave now as
; no buffer movement is possible.
;----------------------------------------------------------------------
CMP BX,GRID_LEN ;File < 1 display?
JBE MG_2
;----------------------------------------------------------------------
; Branch depending on the direction of the move.
;----------------------------------------------------------------------
OR AX,AX ;Which direction?
JS MG_1A
;----------------------------------------------------------------------
; FWD: Can this move be performed within the current buffer?
;----------------------------------------------------------------------
SUB BX,GRID_LEN ;Max grid anchor
ADD BP,AX ;Desired grid anchor
CMP BP,BX ;Desired <= maximum?
JBE MG_1D
;----------------------------------------------------------------------
; The desired grid anchor exceeds the maximum grid anchor.
; If file is larger than the buffer, jump to the more complex
; buffer-moving routines. Otherwise, just use the maximum anchor.
;----------------------------------------------------------------------
CMP [FULLY_BUFFERED],0 ;0=larger than buffer
JE MG_3A ;Go to buffer routines
MOV BP,BX ;Use max anchor
JMP SHORT MG_1D
;----------------------------------------------------------------------
; Determine if this backward move can be performed within the buffer.
; (Backing up is hard to do...)
;----------------------------------------------------------------------
MG_1A:
NEG AX ;Make AX positive
CMP AX,BP ;Back up past anchor?
JA MG_1B
SUB BP,AX ;No, set new anchor
JMP SHORT MG_1D
MG_1B:
;----------------------------------------------------------------------
; If the file is larger than the buffer, jump to the more complex
; buffer-moving routines. Otherwise, just move to the buffer start.
;----------------------------------------------------------------------
CMP [FULLY_BUFFERED],0 ;0 = larger than buffer
JNE MG_1C
JMP SHORT MG_4A ;Go to buffer routines
MG_1C:
OR BP,BP ;If already at start
JZ MG_2 ; do no more
SUB BP,BP ;Else go to start
;----------------------------------------------------------------------
; If we're not moving the anchor, just ignore the request.
;----------------------------------------------------------------------
MG_1D:
CMP BP,[GRID_ANCHOR]
JE MG_2
MOV [GRID_ANCHOR],BP ;Set new anchor
MG_1E:
INC [REDO_GRID] ;Request grid redraw
;----------------------------------------------------------------------
; Exit to caller.
;----------------------------------------------------------------------
MG_2:
CLC ;Signal success
U_EXIT:
RET
;----------------------------------------------------------------------
; If we get here, we know:
; 1. we've been asked to move forward past the end of the buffer.
; 2. the file size is greater than the buffer size.
; 3. the buffer is filled to capacity.
;----------------------------------------------------------------------
MG_3A:
MOV DX,WORD PTR [BUF_ANCHOR_MAX][0] ;Get value
MOV CX,WORD PTR [BUF_ANCHOR_MAX][2] ; in registers
;----------------------------------------------------------------------
; If the current buffer anchor is as far forward as it can go, we can't
; move it any farther forward.
;----------------------------------------------------------------------
CMP DI,CX ;Test hi offset
JNE MG_3B
CMP SI,DX ; and lo offset
JNE MG_3B
;----------------------------------------------------------------------
; The end of the buffer is already at the EOF. Move the grid anchor so
; the last byte in the buffer is the last byte shown on the grid.
;----------------------------------------------------------------------
CMP BX,[GRID_ANCHOR] ;Are we already there?
JE MG_2
MOV [GRID_ANCHOR],BX ;Move to last
JMP MG_1E
;----------------------------------------------------------------------
; The buffer anchor is not at its maximum forward point and is
; definitely going to be moved forward.
;
; We can move the buffer forward BUF_SIZE/2 bytes only if:
; BUF_ANCHOR + BUF_SIZE/2 < BUF_ANCHOR_MAX
;----------------------------------------------------------------------
MG_3B:
MOV BX,[BUF_SIZE] ;Get BUF_SIZE
SHR BX,1 ; and divide by 2
ADD SI,BX ;Calc new 32-bit
ADC DI,0 ; buf anchor
CMP DI,CX ;Test hi offset
JA MG_3C
JB MG_3D
CMP SI,DX ; and lo offset
JBE MG_3D
MG_3C:
;----------------------------------------------------------------------
; The new anchor would be beyond the maximum. Set it to the maximum
; and exit.
;----------------------------------------------------------------------
MOV DI,CX ;Set to maximum
MOV SI,DX ; buffer anchor
;----------------------------------------------------------------------
; Save the new buffer anchor.
;----------------------------------------------------------------------
MG_3D:
MOV CX,DI ;Save new anchor
MOV DX,SI ; in CX:DX
XCHG SI,WORD PTR [BUF_ANCHOR][0] ;Get old anchor
XCHG DI,WORD PTR [BUF_ANCHOR][2] ; in DI:SI
SUB CX,DI ;Figure difference
SBB DX,SI
;----------------------------------------------------------------------
; If we didn't move as far as requested, maximize the grid anchor.
;----------------------------------------------------------------------
CMP AX,DX ;Request <= move?
JBE MG_3E
MOV AX,[BUF_BYTES] ;Bytes in buffer
SUB AX,GRID_LEN ;-bytes on screen
MOV [GRID_ANCHOR],AX ;is new anchor
INC [REDO_BUF] ;Request buffer fill
JMP MG_1E
MG_3E:
SUB DX,AX ;Account for DISP
SUB [GRID_ANCHOR],DX ;Adjust anchor
INC [REDO_BUF] ;Refill buffer
JMP MG_1E
;----------------------------------------------------------------------
; If we get here, we know:
; 1. we've been asked to move back past the beginning of the buffer.
; 2. the file size is greater than the buffer size.
; 3. the buffer is filled to capacity.
;----------------------------------------------------------------------
MG_4A:
;----------------------------------------------------------------------
; If the current buffer anchor is as far back as it can go (0:0), we
; can't move the buffer.
;----------------------------------------------------------------------
OR DI,DI ;Test hi offset
JNZ MG_4B
;----------------------------------------------------------------------
; After this, we know that DI is 0; so we work only with SI.
;----------------------------------------------------------------------
OR SI,SI ;And lo
JNZ MG_4E
;----------------------------------------------------------------------
; The start of the buffer is at 0:0 (BOF). Move the grid anchor so the
; first byte in the buffer is the first byte shown on the grid.
;----------------------------------------------------------------------
CMP [GRID_ANCHOR],0 ;Already at 0?
JE MG_2
MOV [GRID_ANCHOR],0 ;Make it 0
JMP MG_1E
;----------------------------------------------------------------------
; Backing up is easy to do when the buf anchor > 64k.
;----------------------------------------------------------------------
MG_4B:
SUB SI,BX ;Back up 1/2 buffer
SBB DI,0 ; (32-bit)
MG_4C:
SUB BX,AX ;Now move the disp
ADD [GRID_ANCHOR],BX ; and save new anchor
MG_4D:
MOV WORD PTR [BUF_ANCHOR][0],SI ;Save new
MOV WORD PTR [BUF_ANCHOR][2],DI ; buf anchor
INC [REDO_BUF] ;Request buffer refill
JMP MG_1E
;----------------------------------------------------------------------
; The buffer anchor is not at the start of the file, so we can move the
; buffer backward in the file.
;
; Move to either SI-BX or 0, whichever is farther forward in the file.
;----------------------------------------------------------------------
MG_4E:
SHR BX,1 ;BUF_BYTES/2
CMP SI,BX ;Buf anchor > buf/2?
JAE MG_4F
;----------------------------------------------------------------------
; Since we can't back up the full amount, back up to BOF.
;----------------------------------------------------------------------
SUB SI,SI ;Zero lower anchor
MOV [GRID_ANCHOR],SI ;Set anchor to 0
JMP MG_4D
;----------------------------------------------------------------------
; If the current buffer anchor is > buffer size/2, back it up by
; buffer size/2.
;----------------------------------------------------------------------
MG_4F:
SUB SI,BX ;SI = new buf anchor
JMP MG_4C
MOVE_GRID ENDP
;======================================================================
; FILL_BUFFER (Near)
;
; Copies data from the file to the buffer. Up to BUF_SIZE bytes are
; copied from the file beginning at offset BUF_ANCHOR.
;----------------------------------------------------------------------
; Entry: None
; Exit :
; CY - if file error
; NC - no file error
;----------------------------------------------------------------------
; Changes: AX BX CX DX
;----------------------------------------------------------------------
FILL_BUFFER PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING, SS:CSEG
SUB CX,CX ;Create a zero
XCHG CL,[REDO_BUF] ;Swap for flag
JCXZ FB_EXIT ;Exit if 0
;----------------------------------------------------------------------
; If the current buffer data has changed, write it out to the file.
;----------------------------------------------------------------------
CALL COMMIT_BUFFER
JC FB_EXIT
;----------------------------------------------------------------------
; Position the scratch file to the byte specified in BUF_ANCHOR.
;----------------------------------------------------------------------
FB_2A:
MOV AX,4200H ;Position file pointer
MOV BX,[TMP_HANDLE] ; for this handle
MOV DX,WORD PTR [BUF_ANCHOR][0] ;Lo word
MOV CX,WORD PTR [BUF_ANCHOR][2] ;Hi word
INT 21H ; thru DOS
JC FB_EXIT
;----------------------------------------------------------------------
; Attempt to fill the buffer from the file.
;----------------------------------------------------------------------
MOV AH,3FH ;Read file
MOV BX,[TMP_HANDLE] ; from this handle
MOV CX,[BUF_SIZE] ; this many bytes
MOV DX,OFFSET BUFFER ;Put data here
INT 21H ; thru DOS
;----------------------------------------------------------------------
; After a successful read, AX contains the number of bytes actually
; read. If carry set, the calling program just ignores it.
;----------------------------------------------------------------------
MOV [BUF_BYTES],AX ;Save # bytes in buffer
FB_EXIT:
RET
FILL_BUFFER ENDP
;======================================================================
; COMMIT_BUFFER (Near)
;
; If the data in the buffer has been changed, write the buffer back to
; the file beginning at offset BUF_ANCHOR.
;----------------------------------------------------------------------
; Entry: None
; Exit :
; CY - if file error
; NC - no file error
;----------------------------------------------------------------------
; Changes: AX BX CX DX
;----------------------------------------------------------------------
COMMIT_BUFFER PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING, SS:CSEG
SUB CX,CX ;Create a zero
XCHG CL,[BUF_ALTERED] ;Fetch/clear flag
JCXZ CB_EXIT
MOV [FILE_ALTERED],CL ;Non-zero = altered
;----------------------------------------------------------------------
; Position the scratch file to the byte specified in BUF_ANCHOR.
;----------------------------------------------------------------------
MOV AX,4200H ;Position file pointer
MOV BX,[TMP_HANDLE] ; for this handle
MOV DX,WORD PTR [BUF_ANCHOR][0] ;Lo word
MOV CX,WORD PTR [BUF_ANCHOR][2] ;Hi word
INT 21H ; thru DOS
JC CB_EXIT
;----------------------------------------------------------------------
; Write the buffer contents to the file.
;----------------------------------------------------------------------
MOV AH,40H ;Write to file fn
MOV BX,[TMP_HANDLE] ;To this handle
MOV CX,[BUF_BYTES] ;This many bytes
MOV DX,OFFSET BUFFER ;Get data from here
INT 21H ; thru DOS
JC CB_EXIT
;----------------------------------------------------------------------
; After a successful write, AX contains the number of bytes actually
; written. If it doesn't match the number we tried to write, error.
;----------------------------------------------------------------------
CMP AX,CX ;Write them all?
JB CB_EXIT ;JB = JC = carry set
CB_EXIT:
RET
COMMIT_BUFFER ENDP
;======================================================================
; DISPLAY_GRID (Near)
;
; Starting with the current pointer into the buffer, put as many chars
; as possible on the screen.
;----------------------------------------------------------------------
; Entry: None
; Exit : None
;----------------------------------------------------------------------
; Changes: CX DX
;----------------------------------------------------------------------
DISPLAY_GRID PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING, SS:CSEG
SUB CX,CX ;Create a zero
XCHG CL,[REDO_GRID] ;Get/reset flag
JCXZ DG_EXIT
;----------------------------------------------------------------------
; Draw rows 0 through 15 on the screen
;----------------------------------------------------------------------
MOV CX,16 ;Row counter
SUB DX,DX ;Row # to draw
DG_1:
CALL DISPLAY_ROW ;Display row
INC DX ;Next row, please
LOOP DG_1
DG_EXIT:
RET
DISPLAY_GRID ENDP
;======================================================================
; DISPLAY_ROW (Near)
;
; Display one row of the grid on the display.
;----------------------------------------------------------------------
; Entry:
; DX = # of row to display
; Exit: None
;----------------------------------------------------------------------
; Changes: AX BX SI DI BP
;----------------------------------------------------------------------
DISPLAY_ROW PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING, SS:CSEG
PUSH CX ;Save used registers
PUSH DX
MOV BH,[VPAGE] ;Active video page
;----------------------------------------------------------------------
; From the row number, figure out how far we are into the display
; buffer. From that figure out how far we are into the file buffer.
;----------------------------------------------------------------------
MOV SI,DX ;Put row in SI and
MOV CL,4 ; multiply by 16
SHL SI,CL ; offset into display
ADD SI,[GRID_ANCHOR] ; -> offset into buffer
MOV CX,SI ;Save in CX
MOV BP,OFFSET BUFFER ;Addr of buffer in mem
ADD SI,BP ;SI -> memory addr
MOV DI,SI ;Save it in DI
ADD BP,[BUF_BYTES] ;BP -> last valid byte
;----------------------------------------------------------------------
; Calculate the current screen row.
;----------------------------------------------------------------------
ADD DL,ROW_0 ;Bias by screen row
MOV BL,DL ; and save it
;----------------------------------------------------------------------
; Position the cursor to display the offset.
;----------------------------------------------------------------------
MOV DH,OFF_COL ;Column for OFFSET
XCHG DH,DL ;Row,col order
MOV AH,2 ;Position cursor
INT 10H ; thru BIOS
;----------------------------------------------------------------------
; Does the first byte in this row point to a byte that is actually
; part of the file? If not, just blank out this entire row.
;----------------------------------------------------------------------
CMP SI,BP ;Current < invalid?
JBE DR_1A
MOV AX,0A00H+254 ;Write repeated char
MOV CX,8 ; this many
INT 10H ; thru BIOS
JMP SHORT DR_1B
;----------------------------------------------------------------------
; Calculate and show the file offset of the first byte in this row.
;----------------------------------------------------------------------
DR_1A:
MOV DX,WORD PTR [BUF_ANCHOR][0] ;Get buffer
MOV AX,WORD PTR [BUF_ANCHOR][2] ; offset
ADD DX,CX ;Add current byte
ADC AX,0 ; to 32-bit #
CALL HEX4 ;Display high part
MOV AX,DX ; and
CALL HEX4 ;Display low part
DR_1B:
;----------------------------------------------------------------------
; Display the hex bytes for this row.
;----------------------------------------------------------------------
MOV AH,2 ;Position cursor
MOV DH,BL ;To row
MOV DL,HEX_COL ; and column
INT 10H ; thru BIOS
MOV CX,16 ;Bytes in a row
DR_2A:
CMP SI,BP ;Past valid bytes?
JBE DR_2B
MOV AX,0E00H+254 ;Put a block
INT 10H ; thru BIOS
MOV AX,0E00H+254 ; and again
INT 10H ; also thru BIOS
JMP SHORT DR_2C
DR_2B:
LODSB ;Get hex byte
CALL HEX2 ;Display it TTY
DR_2C:
MOV AX,0E00H+BLANK ;Write a blank
INT 10H ; thru BIOS
LOOP DR_2A ;Repeat
;----------------------------------------------------------------------
; Display the ASCII characters for this row.
;----------------------------------------------------------------------
MOV DH,BL ;To row
MOV DL,ASC_COL ; and column
MOV SI,DI ;Point to start of row
MOV CX,16 ;Bytes in a row
DR_3A:
MOV AH,2 ;Position cursor
INT 10H ; thru BIOS
CMP SI,BP ;Past valid bytes?
JBE DR_3B
MOV AX,0E00H+BLANK ;Write a blank
INT 10H ; thru BIOS
JMP SHORT DR_3C
DR_3B:
PUSH CX
MOV AH,0AH ;Write char at cursor
LODSB ;Get hex byte
MOV CX,1 ;Write 1 copy
INT 10H ; thru BIOS
POP CX
INC DL ;Next column
DR_3C:
LOOP DR_3A ;Repeat
;----------------------------------------------------------------------
; Return to caller
;----------------------------------------------------------------------
POP DX ;Restore registers
POP CX
RET
DISPLAY_ROW ENDP
;======================================================================
; HEX4 (Near)
;
; Write AX as 4 hex digits using BIOS Write TTY.
;----------------------------------------------------------------------
; Entry:
; AX = value to display
; Exit : None
;----------------------------------------------------------------------
; CHANGES: None
;----------------------------------------------------------------------
HEX4 PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING, SS:CSEG
PUSH CX ;Save used registers
PUSH DX
MOV CX,4 ;Number of digits
JMP SHORT H_1
;======================================================================
; HEX2 (Near, nested)
;
; Write AX as 2 hex digits using BIOS Write TTY.
;----------------------------------------------------------------------
; Entry:
; AL = value to display
; Exit : None
;----------------------------------------------------------------------
; CHANGES: AX
;----------------------------------------------------------------------
HEX2 PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING, SS:CSEG
PUSH CX ;Save used registers
PUSH DX
MOV AH,AL ;Put byte in AH
MOV CX,2 ;Number of digits
H_1:
PUSH CX ;(Save count)
MOV CL,4 ;Shift count
ROL AX,CL ;Rotate into position
POP CX ;(Restore count)
PUSH AX ;Preserve digits
AND AL,0FH ;Mask off single digit
ADD AL,90H ;Convert digit to ASCII
DAA ; using a small
ADC AL,40H ; code sequence
DAA ; that's tricky
MOV AH,2 ;Display char
MOV DL,AL ; in DL
INT 21H ; thru DOS
POP AX ;Restore digits
LOOP H_1 ;Repeat until done
POP DX ;Restore registers
POP CX
RET
HEX2 ENDP
HEX4 ENDP
;======================================================================
; MOVE_CURSOR (Near)
;
; Move the screen cursor the number of columns specified in AL. If AL>0
; cursor is moved to the right. Result is not checked.
;----------------------------------------------------------------------
; Entry:
; AL = columns to move
; Exit:
; None
;----------------------------------------------------------------------
; Changes: AX BX DX
;----------------------------------------------------------------------
MOVE_CURSOR PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING, SS:CSEG
ADD BYTE PTR [VCURSOR],AL ;Adjust columns
MOV AH,2 ;Position cursor
MOV BH,[VPAGE] ; on this page
MOV DX,[VCURSOR] ; to these coordinates
INT 10H ; thru BIOS
RET
MOVE_CURSOR ENDP
;======================================================================
; SET_CURSOR (Near)
;
; Position the cursor under the correct character on the screen.
;----------------------------------------------------------------------
; Entry: None
; Exit : None
;----------------------------------------------------------------------
; Changes: AX BX DX
;----------------------------------------------------------------------
SET_CURSOR PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING, SS:CSEG
;----------------------------------------------------------------------
; Figure the screen column based on whether the mode is hex or ascii.
;----------------------------------------------------------------------
MOV DL,[GRIDCOL] ;Get grid column
TEST [MODE],MODE_MASK ;Check flag for mode
JNZ SC_2A
ADD DL,ASC_COL ;Bias for ASCII column
SC_1:
;----------------------------------------------------------------------
; Figure the screen row.
;----------------------------------------------------------------------
MOV DH,[GRIDROW] ;Get grid row
ADD DH,ROW_0 ;Bias to screen row
MOV [VCURSOR],DX ;Save current cursor
MOV BH,[VPAGE] ;Use current page
MOV AH,2 ;Set cursor position
INT 10H ; thru BIOS
RET
;----------------------------------------------------------------------
; Figure the column for the hex display.
;----------------------------------------------------------------------
SC_2A:
MOV AL,DL ;Grid column
ADD DL,DL ; *2
ADD DL,AL ; total is *3
ADD DL,HEX_COL ;Add start of hex cols
CMP [MODE],LEFT ;What digit?
JE SC_1
INC DL ;Add 1 if right digit
JMP SC_1
SET_CURSOR ENDP
;======================================================================
; Allocated after program loads.
;----------------------------------------------------------------------
PC = $ ;End of code
PC = PC + 512
STACK_TOP = PC ;Top of stack
BUFFER = PC ;Bottom of buffer
CSEG ENDS
END ENTPT