;====================================================================== ; 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