home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
msdos
/
info
/
help_7n1.arc
/
HELP.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-10-02
|
22KB
|
816 lines
;from VOL7N1.ARC, PC Magazine Jan 88?
; Help.asm
; Resident help facility
; Format: HELP filespec [... filespec][/Nn][/P][/Hn] | [/U]
; defaults: pages = 4; hot key = Alt H
CODE SEGMENT ;********************************;
ASSUME CS:CODE,DS:CODE ;* *;
ORG 100H ;* Requires MASM 2.0 or later *;
;* Remember to EXE2BIN *;
START: JMP BEGINNING ;* *;
;********************************;
; DATA AREA
; ---------
COPYRIGHT DB "HELP 1.0 (c) 1987 Ziff Communications Co.",13,10
DB "Successfully installed",13,10
ALT_COMBO DB "Press Alt H to activate",10,0,26
PROGRAMMER DB "Michael J. Mefford"
OLD_KEYBOARD DD ?
CRT_COLS DW ?
STATUS_REG DW ?
SCREEN_SEG DW 0B000H
LINE_COUNT DB 25
IMMEDIATE_FLAG DB 0
BUSY DB 0
IMMEDIATE DW POP_IT
DATA_SEG DW ?
DATA_INT DB 0
INSTALLED_FLAG DB 0
POPUP_FLAG DB 0
HOT_KEY DB 35
FILENAME DW ?
ERROR_LEVEL DB 0
CURRENT_PAGE DB 1
RESERVED_PAGES DB 4
ACTIVE_PAGES DB 0
PAGE_COUNT DB 0
DELIMITERS DB 9,32,13,44,";","/"
SYNTAX LABEL BYTE
DB 10,"Usage: HELP filespec [... filespec][/Nn][/Hn][/P] | [/U]",13,10,10
DB "/Nn where n = number of reserved pages (1-14); default = 4",13,10
DB "/Hn where n = Alt hot key combo (A-Z,0-9,",34,45,34,44,34,61,34
DB "); default = H",13,10
DB "/P = immediate pop-up",13,10
DB "/U = uninstall",13,10,10
DB "Use: PgUp PgDn Home End to navigate through HELP",13,10
DB 5 DUP(32),"ESC or hot key to exit",10,0
ACTIVE_MSG DB " active page(s)",13,10,0
RESERVED_MSG DB " total page(s)",13,10,10,0
UNLOAD_MSG DB 10,"HELP can't be uninstalled.",13,10
DB "Uninstall resident programs in reverse order.",10,0
UNINSTALL_MSG DB 10,"HELP uninstalled",10,0
NO_FREE DB "Too many resident programs",0
NOT_FOUND DB 32,"not found",13,10,0
NOT_ENOUGH DB "Not enough memory",0
ALLOCATE_MSG DB "Memory allocation error",13,10,0
SCAN_CODES LABEL BYTE
DB 45,130,48,129,49,120,50,121,51,122,52,123,53,124
DB 54,125,55,126,56,127,57,128,61,131,65,30,66,48,67
DB 46,68,32,69,18,70,33,71,34,72,35,73,23,74,36,75,37
DB 76,38,77,50,78,49,79,24,80,25,81,16,82,19,83,31
DB 84,20,85,22,86,47,87,17,88,45,89,21,90,44
; SCAN CODES FOR ALT COMBO
;
; Code Key Code Key Code Key Code Key
; 16 Q 30 A 44 Z 120 1
; 17 W 31 S 45 X 121 2
; 18 E 32 D 46 C 122 3
; 19 R 33 F 47 V 123 4
; 20 T 34 G 48 B 124 5
; 21 Y 35 H 49 N 125 6
; 22 U 36 J 50 M 126 7
; 23 I 37 K 127 8
; 24 O 38 L 128 9
; 25 P 129 0
; 130 -
; Default is 35 (Alt H) 131 =
;************* KEYBOARD INTERCEPTOR *************;
NEW_KEYBOARD:
STI
PUSHF ;Simulate an interrupt
CALL CS:OLD_KEYBOARD ; by pushing flags and far call.
POP_IT: PUSHF ;On return save all registers
PUSH DS ; that will be used.
PUSH ES
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH BP
PUSH CS ;Point to our data.
POP DS
CLD ;Moves in forward direction.
MOV AX,40H ;Point to ROM BIOS data area
MOV ES,AX
MOV AX,ES:[4AH] ;Get number of columns on screen
MOV CRT_COLS,AX ; and store.
MOV AX,ES:[63H] ;Get base address of video card.
ADD AX,6 ;Convert to status register
MOV STATUS_REG,AX ; and store.
CMP AX,3BAH ;Is it mono card?
JZ MONO ;If yes, use b800h.
MOV SCREEN_SEG,0B800H ; else point to color card.
MONO: MOV AL,ES:[49H] ;Retrieve video mode.
CMP AL,3 ;Is it text mode?
JBE GOOD_MODE ;If yes, OK.
CMP AL,7
JNZ DONE_HERE ;Exit if graphics
GOOD_MODE:
CMP IMMEDIATE_FLAG,1 ;Is there a pop-up request?
JZ NOW ;If yes, pop-up right now.
CMP BUSY,1 ;If the window is already popped
JZ DONE_HERE ; exit Int 9 back to window.
MOV AH,1 ;Is an ASCII character ready?
INT 16H
JZ DONE_HERE ;If it's just a key release, exit.
CMP AL,0 ;Is it extended code?
JNZ DONE_HERE ;If no, exit.
CMP AH,HOT_KEY ;Else, see if our Alt key combo.
JZ OPEN_WINDOW ;If yes, open window
DONE_HERE:
JMP SHORT EXIT_KEYBOARD ; else exit.
;------------------------------------;
; Save screen so we can pop up HELP. ;
;------------------------------------;
OPEN_WINDOW:
MOV AH,0 ;Retrieve and discard hot key
INT 16H ; character from keyboard buffer.
NOW: MOV BUSY,1 ;Flag that window is open.
MOV IMMEDIATE_FLAG,0 ;Restore immediate flag.
CALL STORE_SCREEN ;Store screen.
;-----------------------------------------;
; Loop here looking for valid keystrokes. ;
;-----------------------------------------;
READ_KEY:
MOV CL,CURRENT_PAGE ;Get current page.
DEC CL ;Adjust for starting offset.
CALL PAGE_SIZE ;Get offset.
MOV SI,DX
CALL WRITE_SCREEN ;Update the screen.
MOV AH,0 ;Wait for a character.
INT 16H
CMP AH,1 ;Is it Esc?
JZ EXIT_WINDOW ;If yes, exit window.
CMP AH,BYTE PTR HOT_KEY ;Is it our key combo?
JZ EXIT_WINDOW ;If yes, exit window.
MOV CL,CURRENT_PAGE ;Get current page.
CMP AH,49H ;Is it PgUp?
JNZ CK_PGDN
CMP CL,1 ;If yes, is it already page one?
JZ END_KEY
DEC CL ;If no, decrement page.
CK_PGDN:
CMP AH,51H ;Is it PgDn?
JNZ CK_HOME
CMP CL,ACTIVE_PAGES ;If yes, are we already last page?
JZ END_KEY
INC CL ;If no, increment page.
CK_HOME:
CMP AH,47H ;Is it Home?
JNZ CK_END
MOV CL,1 ;If yes, move to page one.
CK_END: CMP AH,4FH ;Is it End?
JNZ END_KEY
MOV CL,ACTIVE_PAGES ;If yes, move to last page.
END_KEY:
MOV CURRENT_PAGE,CL ;Store new current page.
JMP SHORT READ_KEY
;----------------------------------;
; This is the window exit routine. ;
;----------------------------------;
EXIT_WINDOW:
MOV SI,OFFSET SCREEN_BUFFER ;Point to the stored screen
CALL WRITE_SCREEN ; and restore the screen.
MOV IMMEDIATE_FLAG,0 ;Reset the pop-up flag.
MOV BUSY,0 ;Flag done with window.
EXIT_KEYBOARD:
POP BP ;Restore all registers.
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
POPF
IRET ;Return from interrupt.
;************* FILE LOADING AND INSTALL PROCEDURE *************;
BEGINNING:
CLD
PUSH CS
POP DATA_SEG ;Store our segment.
CMP SP,65533 ;Do we have 64K?
JA CK_PARA
MOV SI,OFFSET NOT_ENOUGH ;If no, exit with message.
JMP ERROR_EXIT
CK_PARA:
CMP BYTE PTR DS:[80H],0 ;Any parameters?
JNZ CK_FREE
OPTIONS:
MOV SI,OFFSET SYNTAX ;If no, exit with syntax message.
JMP ERROR_EXIT
;----------------------------------------------------------------------;
; Check user vectors to see if we are installed or if one is available ;
;----------------------------------------------------------------------;
CK_FREE:
MOV AL,60H - 1 ;Available vectors are 60H - 67H.
FREE_USER_INT:
INC AL
MOV AH,35H ;Get vector address.
INT 21H
CMP BX,0 ;Is offset being used?
JNZ CK_SIGNATURE ;If yes, see if it's us.
MOV DX,ES
or dx,dx ;CMP DX,0 ;Is segment being used?
JNZ CK_SIGNATURE ;If yes, see if it's us.
MOV DATA_INT,AL ;If available, save INT number.
NEXT_USER:
CMP AL,67H ;Have we checked all 7?
JNZ FREE_USER_INT ;If no, next one.
JMP SHORT CK_SWITCHES
CK_SIGNATURE:
MOV DI,BX ;See if INT has our signature.
MOV SI,100H
MOV CX,30/2
REPZ CMPSW
JNZ NEXT_USER ;If yes, already installed.
MOV DATA_SEG,ES ;Save segment.
MOV INSTALLED_FLAG,1
;--------------------------------------------;
; Check the command line for switch options. ;
;--------------------------------------------;
CK_SWITCHES:
PUSH DATA_SEG ;First point to installed segment.
POP ES
MOV SI,81H ;First parameter.
NEXT_SWITCH:
LODSB ;Get a byte.
CMP AL,13 ;Is it carriage return?
JZ CK_FILENAMES ;If yes, done here.
CMP AL,"/" ;Is it switch character?
JNZ NEXT_SWITCH ;If no, get next byte
LODSB ; else get switch.
CMP AL,13 ;Is it carriage return?
JZ CK_FILENAMES ;If yes, done here
CALL CAPITALIZE ; else capitalize.
CMP AL,"U" ;Is it "U"?
JNZ CK_N
CMP INSTALLED_FLAG,1 ;If yes, are we installed?
JNZ NEXT_SWITCH
JMP UNINSTALL ;If yes, uninstall.
CK_N:
CMP AL,"N" ;Is it "N"?
JNZ CK_P
CMP INSTALLED_FLAG,1 ;If yes, are we installed?
JZ NEXT_SWITCH ;If yes, can't change reserved.
CALL DEC_TO_HEX ;Else, convert decimal to hex.
CMP BL,14 ;Request greater than 14 pages
JA NEXT_SWITCH ; or equal to zero?
CMP BL,0
JZ NEXT_SWITCH ;If yes, ignore.
MOV RESERVED_PAGES,BL ;Else, store reserved pages.
JMP SHORT NEXT_SWITCH
CK_P: CMP AL,"P" ;Is it "P"?
JNZ CK_H
MOV POPUP_FLAG,1 ;If yes, flag to pop-up immediate.
CK_H: CMP AL,"H" ;Is it "H"?
JNZ NEXT_SWITCH
LODSB
DEC SI ;Adjust in case it's just CR.
CALL CAPITALIZE
MOV DI,OFFSET SCAN_CODES
MOV CX,38 ;38 possible Alt key combos.
NEXT_ALT:
SCASB ;Do we have a match?
JZ GOT_ALT
INC DI ;If no, bump pointer to next byte.
LOOP NEXT_ALT
JMP SHORT NEXT_SWITCH
GOT_ALT:
MOV ALT_COMBO + 10,AL ;Store Alt key.
MOV AL,[DI] ;Get scan code
MOV ES:HOT_KEY,AL ; and store.
JMP SHORT NEXT_SWITCH
;-----------------------------------------------------;
; This routine parses the command line for filenames. ;
;-----------------------------------------------------;
CK_FILENAMES:
MOV SI,81H ;Point to first parameter.
NEXT_FILENAME:
CALL CK_DELIMITER ;Is it a delimiter?
JC CK_CR ;If yes, see if end.
MOV FILENAME,SI ;Else, store filename start.
FIND_END:
CALL CK_DELIMITER ;Look for delimiter to mark end.
JNC FIND_END
PUSH SI ;Save pointer and delimiter.
PUSH AX
CALL READ_FILE ;Read the file in.
POP AX
POP SI ;Restore pointers.
CK_CR: CMP AL,13 ;Is it carriage return?
JZ END_FILENAMES ;If yes, done here.
CMP AL,"/" ;Is it switch character?
JNZ NEXT_FILENAME ;If no, get next filename.
FIND_SWITCH:
CALL CK_DELIMITER ;Else, look for delimiter.
JNC FIND_SWITCH
JMP SHORT CK_CR ;And check if carriage return.
END_FILENAMES:
MOV AL,PAGE_COUNT ;Retrieve page count.
CMP INSTALLED_FLAG,1 ;Are we installed?
JZ STORE_ACTIVE ;If yes, check pages read.
CMP AL,RESERVED_PAGES ;Pages read greater than reserved?
JBE STORE_ACTIVE
MOV RESERVED_PAGES,AL ;If yes, store as reserved.
STORE_ACTIVE:
CMP AL,0 ;Did we read any pages?
JZ CK_INSTALLED1 ;If no, check if installed.
MOV ES:ACTIVE_PAGES,AL ;Else, store active pages.
MOV ES:CURRENT_PAGE,1 ;Reset the current page to one.
JMP SHORT CK_POPUP ;Check popup request.
CK_INSTALLED1:
CMP INSTALLED_FLAG,1 ;Are we installed?
JNZ CK_INSTALLED2 ;If no, exit.
;----------------------------------------;
; This routine does an immediate pop-up. ;
;----------------------------------------;
CK_POPUP:
CMP POPUP_FLAG,1 ;Is there a popup request?
JNZ CK_INSTALLED2 ;If no, check pages read.
MOV ES:IMMEDIATE_FLAG,1 ;Else, flag keyboard routine.
PUSHF ;Simulate an interrupt.
CALL DWORD PTR IMMEDIATE
MOV BL,0 ;Error level of zero.
CMP AL,0 ;Any pages read?
JZ EXIT ;If no, done here.
;--------------------------------------------------;
; This routine checks to see if we are to install. ;
;--------------------------------------------------;
CK_INSTALLED2:
CMP AL,0 ;Did we fail to open a file?
MOV SI,OFFSET SYNTAX ;If yes, exit with syntax message.
JZ ERROR_EXIT
PUSH AX
MOV CL,AL ;Save active pages.
MOV DL,10
CALL WRITE_IT ;Display linefeed.
CALL WRITE_NUMBER ;Display active pages.
MOV SI,OFFSET ACTIVE_MSG
CALL DISPLAY_TEXT
POP AX
CMP INSTALLED_FLAG,1 ;Are we already installed?
MOV BL,ERROR_LEVEL
JZ EXIT ;If yes, done here
CK_INT:
CMP DATA_INT,0 ;Did we find a free user interrupt?
JNZ INSTALL ;If yes, install
MOV SI,OFFSET NO_FREE ;Else, exit with message.
;-------------------;
; This is the exit. ;
;-------------------;
ERROR_EXIT:
MOV BL,1 ;Error code of one.
MSG_EXIT:
CALL DISPLAY_TEXT
EXIT: MOV AL,BL
MOV AH,4CH ;Return with error code.
INT 21H ;Terminate.
;--------------------------------;
; This is the install procedure. ;
;--------------------------------;
INSTALL:
MOV AX,DS:[2CH] ;Get environment segment.
MOV ES,AX
MOV AH,49H ;Free up environment.
INT 21H
MOV SI,OFFSET ALLOCATE_MSG
JC ERROR_EXIT ;If error, exit with message.
MOV DX,100H ;Install user interrupt as
MOV AL,DATA_INT ; pointer to residency.
MOV AH,25H
INT 21H
MOV AX,3509H ;Get keyboard interrupt.
INT 21H
MOV WORD PTR OLD_KEYBOARD,BX ;Save old interrupt.
MOV WORD PTR OLD_KEYBOARD[2],ES
MOV DX,OFFSET NEW_KEYBOARD ;Install new interrupt.
MOV AX,2509H
INT 21H
MOV CL,RESERVED_PAGES ;Display reserved pages.
CALL WRITE_NUMBER
MOV SI,OFFSET RESERVED_MSG
CALL DISPLAY_TEXT
MOV SI,OFFSET COPYRIGHT ;Display install message.
CALL DISPLAY_TEXT
CALL PAGE_SIZE ;Convert reserved pages to offset.
MOV CL,4
SHR DX,CL ;Convert to paragraphs.
INC DX ;Round up one.
MOV AX,3100H ;Return error code of zero.
INT 21H ;Terminate but stay resident.
;*************;
; SUBROUTINES ;
;*************;
;-----------------------------------------------;
; This subroutine uninstalls the resident help. ;
;-----------------------------------------------;
UNINSTALL:
MOV AX,3509H ;Get keyboard interrupt.
INT 21H
CMP BX,OFFSET NEW_KEYBOARD ;Is the offset vector same?
MOV SI,OFFSET UNLOAD_MSG ;Error message if INT 9h changed.
MOV BL,1 ;Error code of one if fails.
JNZ MSG_EXIT
MOV AX,ES ;Is segment vector same?
CMP AX,DATA_SEG
JNZ MSG_EXIT ;If no, exit with error.
MOV ES,DATA_SEG ;Point to resident segment.
MOV AH,49H ;And return memory to system pool.
INT 21H
MOV SI,OFFSET ALLOCATE_MSG
JNC DEALLOCATED ;Display message if problem.
CALL DISPLAY_TEXT
DEALLOCATED:
MOV DX,ES:WORD PTR OLD_KEYBOARD ;Restore old INT 9.
MOV DS,ES:WORD PTR OLD_KEYBOARD[2]
MOV AX,2509H
INT 21H
MOV AL,ES:DATA_INT ;Retrieve user interrupt.
XOR DX,DX
MOV DS,DX ;Return vector to nulls.
MOV AH,25H
INT 21H
PUSH CS
POP DS
MOV SI,OFFSET UNINSTALL_MSG ;Display uninstall message.
MOV BL,0 ;Error code of zero.
JMP MSG_EXIT ;And exit.
;-----------------------------------------;
; These subroutines display the messages. ;
;-----------------------------------------;
WRITE_NUMBER:
MOV BL,CL ;Retrieve number.
CMP BL,10 ;Is it greater than ten?
JB ONES
MOV DL,"1" ;If yes, display a one.
CALL WRITE_IT
SUB BL,10
ONES: MOV DL,BL
ADD DL,"0" ;Convert to decimal.
CALL WRITE_IT ;Display one's digit.
RET
;----------------------------------------;
WRITE_IT:
MOV AH,2 ;Display byte via DOS.
INT 21H
RET
;----------------------------------------;
DISPLAY_IT:
CALL WRITE_IT
DISPLAY_TEXT:
LODSB ;Get a byte
MOV DL,AL
CMP DL,0 ;Zero marks end of string.
JNZ DISPLAY_IT
RET
;-------------------------------------------------------------;
; This subroutine opens files if there is room to store them. ;
;-------------------------------------------------------------;
READ_FILE:
CALL CK_SPACE ;Is there room for help?
JC END_READ
MOV DX,FILENAME ;If yes, open file.
DEC DX
MOV AX,3D00H
INT 21H
JNC GOT_FILE
MOV ERROR_LEVEL,1 ;Else, indicate had a problem.
MOV SI,DX ;Display filename and message
CALL DISPLAY_TEXT ; if file not found.
MOV SI,OFFSET NOT_FOUND
CALL DISPLAY_TEXT
RET
GOT_FILE:
MOV BX,AX ;Filehandle in BX.
NEXT_READ:
CALL READ_IT ;Read it.
JC CLOSE_FILE ;Done here if nothing read.
CALL CK_SPACE ;If room, read balance, if any,
JNC NEXT_READ ; into next page.
CLOSE_FILE:
MOV AH,3EH ;Close file.
INT 21H
END_READ:
RET
;--------------------------------------------------------------------;
; This subroutine does the actual reading of help files into storage ;
;--------------------------------------------------------------------;
READ_IT:
MOV CL,PAGE_COUNT ;Retrieve page count.
CALL PAGE_SIZE ;Convert to offset.
PUSH ES
POP DS ;Point to storage segment.
MOV CX,4000 ;Read 4000 bytes.
MOV AH,3FH
INT 21H
JC READ_END
or ax,ax ;Did we read anything?
JZ READ_END
INC CS:PAGE_COUNT ;If yes, increment page count.
SUB CX,AX ;Was it a full page?
JZ SKIP_PAD
MOV DI,DX ;If no, pad balance with nulls.
ADD DI,AX
XOR AL,AL
REP STOSB
SKIP_PAD:
CLC ;Indicate read something.
JMP SHORT RESTORE_DS
READ_END:
STC ;Indicate nothing read.
RESTORE_DS:
PUSH CS ;Restore data segment.
POP DS
RET
;------------------------------------------------;
; This subroutine checks for free storage space. ;
;------------------------------------------------;
CK_SPACE:
CMP PAGE_COUNT,14 ;Already a full 14 pages?
JZ NO_SPACE ;If yes, no space.
CMP INSTALLED_FLAG,1 ;Are we installed.
JNZ SPACE
MOV AL,ES:RESERVED_PAGES ;If yes, are reserved pages full?
CMP AL,PAGE_COUNT
JZ NO_SPACE ;If yes, no space.
SPACE: CLC ;Else, there is space.
RET
NO_SPACE:
STC
RET
;-------------------------------------------------------;
; This subroutine calculates the page offsets. ;
; Enter with CL = multiplicand; Return with DX = offset ;
;-------------------------------------------------------;
PAGE_SIZE:
MOV AX,4000 ;Multiply by 4000 bytes.
XOR DX,DX
XOR CH,CH
MUL CX
MOV DX,OFFSET PAGE_BUFFER ;Add to page buffer offset.
ADD DX,AX
RET
;------------------------------------------;
; This subroutine converts decimal to hex. ;
;------------------------------------------;
DEC_TO_HEX:
XOR BL,BL ;Start with zero.
NEXT_NUMBER:
LODSB ;Get a byte.
CMP AL,"0" ;Is it a number?
JB END_NUMBER
CMP AL,"9"
JA END_NUMBER
SUB AL,"0" ;If yes convert to hex.
XCHG AL,BL ;Save it.
XOR AH,AH ;Multiply previous by 10.
MOV DL,10
MUL DL
XCHG AL,BL ;Retrieve current number.
ADD BL,AL ;And add to total.
JMP SHORT NEXT_NUMBER
END_NUMBER:
DEC SI ;Adjust pointer.
RET
;---------------------------------------------------------;
; This subroutine checks the command line for delimiters. ;
;---------------------------------------------------------;
CK_DELIMITER:
LODSB ;Get a byte.
MOV DI,OFFSET DELIMITERS ;Point to delimiters.
MOV CX,6
REPNZ SCASB ;And see if match.
JNZ NO_DELIMITER
MOV BYTE PTR [SI-1],0 ;If yes, convert to ASCIIZ.
STC
RET
NO_DELIMITER:
CLC
RET
;-------------------------------------------------;
; This subroutine capitalizes the character in AL ;
;-------------------------------------------------;
CAPITALIZE:
CMP AL,"a"
JB END_CAPS
CMP AL,"z"
JA END_CAPS
AND AL,5FH
END_CAPS:
RET
;------------------------------------------------------------------;
; This subroutine stores the screen so it can be restored on exit. ;
;------------------------------------------------------------------;
STORE_SCREEN:
MOV LINE_COUNT,25 ;25 lines to save.
MOV DX,STATUS_REG ;Retrieve status register.
MOV AX,SCREEN_SEG ;Point to screen buffer.
MOV DS,AX
PUSH CS ;Point to storage segment.
POP ES
XOR SI,SI ;Top left corner.
MOV DI,OFFSET SCREEN_BUFFER ;Point to storage offset.
NEXT_LINE1:
MOV BP,ES:CRT_COLS ;Retrieve screen columns.
MOV CX,80 ;Save maximum of 80 columns.
HORZ_RET1:
IN AL,DX ;Get status.
TEST AL,1 ;Is it low?
JNZ HORZ_RET1 ;If no, wait until it is.
CLI ;No more interrupts.
WAIT1: IN AL,DX ;Get status
TEST AL,1 ;Is it high?
JZ WAIT1 ;If no, wait until it is.
LODSW ;Retrieve a word.
STI ;Interrupts back on.
STOSW ;Store the character/attribute.
DEC BP ;Decrement screen column count.
JZ SHORT_COLS1 ;Was it less than 80?
LOOP HORZ_RET1 ;If no, loop until row done.
SHL BP,1 ;Convert balance to a word.
ADD SI,BP ;Add to screen offset.
JMP SHORT CK_LINES1
SHORT_COLS1:
DEC CX ;Adjust balance.
SHL CX,1 ;Convert to a word.
ADD DI,CX ;Add to storage offset.
CK_LINES1:
DEC ES:LINE_COUNT ;Do all 25 lines.
JNZ NEXT_LINE1
PUSH CS ;Restore data segment.
POP DS
RET ;Return.
;---------------------------------------------;
; This subroutine writes to the screen buffer ;
;---------------------------------------------;
WRITE_SCREEN:
MOV LINE_COUNT,25 ;25 lines to save.
MOV DX,STATUS_REG ;Retrieve status register.
MOV AX,SCREEN_SEG ;Point to screen buffer.
MOV ES,AX
XOR DI,DI ;Top left corner.
NEXT_LINE2:
MOV BP,CRT_COLS ;Retrieve screen columns.
MOV CX,80 ;Write maximum of 80 columns.
NEXT_BYTE:
LODSW ;Get a byte.
MOV BX,AX ;Store it in AX.
HORZ_RET2:
IN AL,DX ;Get status.
TEST AL,1 ;Is it low?
JNZ HORZ_RET2 ;If no, wait until it is.
CLI ;No more interrupts.
WAIT2: IN AL,DX ;Get status.
TEST AL,1 ;Is it high?
JZ WAIT2 ;If no, wait until it is.
MOV AX,BX ;Retrieve the word
STOSW ; and store it.
STI ;Interrupts back on.
DEC BP ;Decrement screen column count.
JZ SHORT_COLS2 ;Was it less than 80?
LOOP NEXT_BYTE ;If no, loop until row done.
SHL BP,1 ;Convert balance to a word.
ADD DI,BP ;Add to storage offset.
JMP SHORT CK_LINES2
SHORT_COLS2:
DEC CX ;Adjust balance.
SHL CX,1 ;Convert to a word.
ADD SI,CX ;Add to screen offset.
CK_LINES2:
DEC LINE_COUNT ;Do all 25 lines.
JNZ NEXT_LINE2
RET
SCREEN_BUFFER LABEL BYTE
PAGE_BUFFER EQU SCREEN_BUFFER + ( 2 * 80 * 25 )
CODE ENDS
END START