home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C!T ROM 2
/
ctrom_ii_b.zip
/
ctrom_ii_b
/
PROGRAM
/
BASIC
/
BCC101
/
XPRINT
/
XPRINT.ASM
next >
Wrap
Assembly Source File
|
1993-03-20
|
17KB
|
423 lines
comment|
This source code is for QB NEAR STRINGS only. MASM 5.1 compatible.
Written by Brian McLaughlin. Released into the public domain 3/5/93.
WARNING: Before *ANY* of the working routines in this group can be called
safely from your program, the routine XInit must be called once. (No
further calls to XInit are needed.)
XInit sets several internal variables and default behaviors. It sets the
active display page and visible display page to zero. It also detects if a
CGA monitor is in use and sets a flag to suppress snow. This behavior can
be overridden by setting the IgnoreSnow% variable to a non-zero value. In
that case the presence of a CGA is ignored and fast printing is used.
XInit also sets the initial viewport to cover the entire screen (25x80),
and sets the default colors to white on black. It puts the cursor in the
first column of the row where it finds the cursor. The only display size
supported by these routines is 25x80. (The 43/50 line options are not
supported.)
XPrint prints only strings. Numbers MUST be converted to strings before
printing them (by using STR$ or a similar routine). XPrint uses the current
colors defined by XColor. It prints at the current cursor position. When
the variable NumScrolls% is set to 0, XPrint will behave like PRINT with a
trailing semicolon, and the cursor will not be advanced beyond the space
following the end of the printed string. When NumScrolls% is set to 1,
Xprint will behave like PRINT with no semicolon, and the cursor will be
advanced to the beginning of the next line. If NumScrolls% is greater than
1, the cursor will be advanced until that number of carriage returns and
line feeds are performed, much like PRINT: PRINT: PRINT. Scrolling is
automatic when printing on the last line of the viewport.
XViewPort is similar to VIEW PRINT, except it allows column as well as row
arguments. Screen coordinates follow BASIC convention, so that the upper
left corner is 1,1 and the lower right is 25,80. If it is passed an illegal
argument (for example a column or row less than 1 or a top row beneath the
bottom row) then it defaults to a viewport consisting of the entire screen
(25x80). When XViewPort is called and the cursor is detected outside the
viewport's boundaries then the cursor will be brought into the viewport and
placed at the top left corner, no matter where it was before.
XLocate works a lot like LOCATE X%,Y%. You must always pass both the row
and column arguments. When passed an illegal coordinate (outside the
current viewport) XLocate will place the cursor as near to the requested
position as it can, while keeping it within the viewport. IMPORTANT: Row
and column arguments are numbered relative to the whole screen, so that the
position 1,1 is ALWAYS the top left corner of the screen, which is NOT
necessarily the top left corner of the current viewport. If the defined
viewport does not include screen position 1,1 then those coordinates are
illegal.
XCursorOn turns the cursor on (when it is off) and controls its shape. It
accepts one argument, telling it whether the cursor should appear as a
block (non-zero value) or an underline (zero value). XCursorOff makes the
cursor invisible, if it is visible.
XColor sets the current foreground and background colors. It follows the
QuickBASIC conventions: allowable background colors are 0-7. Foreground
colors of 0-7 are normal, 8-15 are high intensity, and blinking is
obtained by adding 16 to the desired foreground color (16-31).
XCls clears the currently defined viewport to the current colors and puts
the cursor in the top left corner.
XCsrLin% returns the current cursor row, like CSRLIN. XPos% returns the
current cursor column, like POS(0).
end comment|
.MODEL MEDIUM, BASIC
.DATA
ViewportTopRow DB 0 ; initial viewport is whole screen
ViewportTopCol DB 0
ViewportBotRow DB 24 ; 0-24 = 25 rows total
ViewportBotCol DB 79 ; 0-79 = 80 columns total
ColorAttr DB 7 ; default to white on black
CursorRow DB 0 ; zero-based coordinate
CursorCol DB 0 ; zero-based coordinate
SnowFlag DB 0 ; default = no snow suppression
VidPort DW 03BAh ; monochrome port default
VidSeg DW 0B000h ; monochrome segment default
VidOffset DW 0
.CODE
; these variables are stored in code segment, rather than DGROUP
CursorTopLine DB 0Bh ; monochrome default cursor
CursorEndLine DB 0Ch ; monochrome default cursor
XInit PROC FAR, IgnoreSnow:WORD
Mov AX, 0500h ; set display page to 0
Int 10h ; using the BIOS
Xor BH, BH
Mov AH, 03h ; discover current cursor row
Int 10h ; using the BIOS
Mov CursorRow, DH ; and save that row
Call $SetVideoOffset ; and calculate new offset
Xor AX, AX
Mov ES, AX
Mov AX, ES:[0463h] ; get the CRT port address
Cmp AL, 0B4h ; and look at it
Je GotMon ; it's mono, the default
Mov VidSeg, 0B800h ; otherwise, set up for color monitor
Mov VidPort, 03DAh ;
Mov CS:CursorTopLine, 06h
Mov CS:CursorEndLine, 07h
Mov BL, 10h ; now let's look for EGA/VGA installed
Mov AH, 12h ; using BIOS service 12
Int 10h ; call BIOS
Cmp BL, 10h ; if BL changes there's an EGA/VGA
Jne GotMon ; and we assume EGA/VGA
Mov BX, IgnoreSnow ; so, did the user abort snow suppresion?
Mov AX, [BX] ; let's see!
Or AX, AX ; were we passed a zero?
Jz GotMon ; a non-zero means *don't* suppress snow
Mov SnowFlag, 1 ; otherwise, assume snow problems
GotMon:
Ret
XInit ENDP
XPrint PROC FAR USES ES DI SI, String:WORD, NumScrolls:WORD
Mov DI, String ; get address of descriptor
Mov CX, [DI] ; get string's length in bytes
Jcxz NullString ; String was null
Mov SI, [DI+2] ;DS:SI points to String in memory
Mov AX, VidSeg ; can't put VidSeg into ES directly
Mov ES, AX ;ES = video segment
Mov DI, VidOffset ;ES:DI points to current cursor position
Mov AH, ColorAttr ; AL holds the character, AH the attribute
Mov DX, VidPort ; We'll need this for snow suppression
Mov BH, SnowFlag ; get snow flag
Mov BL, CursorCol
Cld ; clear direction flag for forward write
WriteCharLoop:
Or BH, BH ; check for snow flag
Jz FastWrite
WaitHere:
In AL, DX ; get video status byte into AL
Test AL, 1 ; test the retrace bit
Jnz WaitHere ; wait until it zeros
Cli ; disable interrupts
WaitAgain:
In AL, DX ; test again
Test AL, 1
Jz WaitAgain
FastWrite:
Lodsb ; loads char into AL
Stosw ; put char+attribute into video buffer
Sti ; enable interrupts again
Inc BL ; keep track of cursor position
Mov AL, ViewportBotCol ; AL is only temporarily available
Cmp AL, BL ; is cursor inside viewport boundary
Jae InBounds
Call $ResetCursor ; reset cursor to first col, scroll if need be
Mov DI, VidOffset ; reset DI to correct offset
Mov BL, CursorCol ; reset BL to new CursorCol
InBounds:
Loop WriteCharLoop
Mov CursorCol, BL ; save final cursor column
NullString:
Mov SI, NumScrolls ; take care of NumScrolls scrolling now
Mov CX, [SI] ; get the value into CX
Jcxz NoCRLF
CRLoop:
Call $ResetCursor ; let this PROC do the work
Loop CRLoop ; however many times its needed
NoCRLF:
Call $SetCursorPosition ; set the cursor where desired
Call $SetVideoOffset ; calculate offset where cursor ended up
Ret
XPrint ENDP
XCsrLin PROC FAR
Mov AL, CursorRow ; put the value in AL
Inc AL ; revert to 1-based coordinates
Cbw
Ret
XCsrLin ENDP
Xpos PROC FAR
Mov AL, CursorCol ; put the value in AL
Inc AL ; return a 1-based coordinate
Cbw
Ret
XPos ENDP
XCls PROC FAR
Xor AL, AL
Call $ScrollWin ; sending zero in AL clears the screen
Mov AL, ViewportTopRow
Mov CursorRow, AL
Mov AL, ViewportTopCol
Mov CursorCol, AL
Call $SetCursorPosition ; move cursor to top corner
Call $SetVideoOffset ; recalculate video offset
Ret
XCls ENDP
XLocate PROC, Row:WORD, Col:WORD
Mov BX, Row
Mov AL, Byte Ptr [BX]
Dec AL ; convert to zero-based coordinates
Cmp AL, ViewportTopRow
Jl RowTooLow
Cmp AL, ViewPortBotRow
Jg RowTooHigh
RowRight:
Mov CursorRow, AL ; save row coordinate
Mov BX, Col
Mov AL, Byte Ptr [BX]
Dec AL ; convert to zero-based coordinates
Cmp AL, ViewportTopCol
Jl ColTooLow
Cmp AL, ViewportBotCol
Jg ColTooHigh
ColRight:
Mov CursorCol, AL ; save column coordinate
Call $SetCursorPosition ; move cursor into place
Call $SetVideoOffset ; recalculate current offset
Ret
RowTooLow:
Mov AL, ViewportTopRow ; keep row in viewport boundary
Jmp SHORT RowRight
RowTooHigh:
Mov AL, ViewportBotRow ; keep row in viewport boundary
Jmp SHORT RowRight
ColTooLow:
Mov AL, ViewportTopCol ; keep column in viewport boundary
Jmp SHORT ColRight
ColTooHigh:
Mov AL, ViewportBotCol ; keep column in viewport boundary
Jmp SHORT ColRight
XLocate ENDP
XColor PROC FAR, Fore:WORD, Back:WORD
Xor DL, DL ; put a zero into DL
Mov BX, Fore ; get address of Fore
Mov AX, [BX] ; put FG color into bits 0-4 of AX
Test AX, 10h ; is bit 4 set? (blinking requested?)
Jnz SetBlink ; if it is, then go arrange for blink
SetColor:
Mov BX, Back
Mov AH, Byte Ptr [BX] ; put BG color into AH
And AH, 7 ; only keep bits 0-2
Mov CL, 4
Shl AH, CL ; shift bits 0-2 into bits 4-6
Or AL, AH ; introduce BG value into bits 4-6 of AL
Or AL, DL ; sets bit 7 of AL, if blinking requested
Mov ColorAttr, AL ; save the result internally
Ret
SetBlink:
And AL, 0Fh ; keep bits 0-3 of AL, discard 4-7
Mov DL, 0F0h ; set bit 7 in DL
Jmp SHORT SetColor
XColor ENDP
XViewPort PROC FAR, TopRow:WORD, TopCol:WORD, BotRow:WORD, BotCol:WORD
Mov BX, TopRow ; get address
Mov AL, Byte Ptr [BX] ; get value
Dec AL ; convert to zero-based coordinates
Cmp AL, 0
Jl Abort ; signed comparisons throughout
Cmp AL, 24
Jg Abort
Mov DL, AL ; DL = TopRow
Mov BX, TopCol ; get address
Mov AL, Byte Ptr [BX] ; get value
Dec AL ; convert to zero-based coordinates
Cmp AL, 0
Jl Abort ; trap an illegal value
Cmp AL, 79
Jg Abort ; trap an illegal value
Mov DH, AL ; DH = TopCol
Mov BX, BotRow ; get address
Mov AL, Byte Ptr [BX] ; get value
Dec AL ; convert to zero-based coordinates
Cmp AL, DL ; compare to TopRow
Jl Abort ; trap an illegal value
Cmp AL, 24
Jg Abort ; trap an illegal value
Mov CL, AL ; CL = BotRow
Mov BX, BotCol ; get address
Mov AL, Byte Ptr [BX] ; get value
Dec AL ; convert to zero-based coordinates
Cmp AL, DH ; compare to TopCol
Jl Abort ; trap an illegal value
Cmp AL, 79
Jg Abort ; trap an illegal value
Cmp CursorRow, DL ; is the cursor inside the viewport?
Jb PutCursInside ; if not, move it in
Cmp CursorRow, CL
Ja PutCursInside ; if not, move it in
Cmp CursorCol, DH
Jb PutCursInside ; if not, move it in
Cmp CursorCol, AL
Ja PutCursInside ; if not, move it in
SaveVars:
Mov ViewportTopRow, DL
Mov ViewportTopCol, DH
Mov ViewportBotRow, CL
Mov ViewportBotCol, AL
Ret
Abort:
Xor DX, DX ; set top corner to 0, 0
Mov CL, 24 ; set bottom corner to 24, 79
Mov AL, 79
Jmp SHORT SaveVars
PutCursInside:
Mov CursorRow, DL ; move the cursor to top left
Mov CursorCol, DH
Call $SetCursorPosition ; make it all official
Call $SetVideoOffset
Jmp SHORT SaveVars
XViewPort ENDP
XCursorOn PROC FAR, BigFlag:WORD
Mov CL, CS:CursorEndLine
Mov BX, BigFlag
Mov AX, [BX]
Or AX, AX
Jnz Big
Mov CH, CS:CursorTopLine ;makes an underline cursor
Ready:
Mov AH, 01h
Int 10h
Ret
Big:
Xor CH, CH ; change top line to zero
Jmp SHORT Ready ; for a big cursor
XCursorOn ENDP
XCursorOff PROC FAR
Mov CX, 2000h ; should force invisible cursor
Mov AH, 01h
Int 10h
Ret
XCursorOff ENDP
$ResetCursor PROC NEAR
Push AX ; preserve AX to free a working register
Mov AL, CursorRow ; get what row we're in
Mov AH, ViewportBotRow ; get the bottom row of text window
Cmp AL, AH ; see if they match
Je InBotRow ; if they do, we need to scroll a line
Inc CursorRow ; if not, show we moved a row down
ResumeReset:
Mov AL, ViewportTopCol ; and adjust column to leftmost one
Mov CursorCol, AL
Call $SetVideoOffset ; recalculate VidOffset
Pop AX ; restore AX to previous value
Ret
InBotRow:
Mov AL, 1 ; ask for a one-line scroll
Call $ScrollWin ; do it
Jmp SHORT ResumeReset ; go back to do the rest
$ResetCursor ENDP
$ScrollWin PROC NEAR ;call with AL = lines to scroll (0 means clear it)
Push AX
Push BX
Push CX
Push DX
Mov AH, 06h
Mov BH, ColorAttr
Mov CH, ViewPortTopRow
Mov CL, ViewPortTopCol
Mov DH, ViewPortBotRow
Mov DL, ViewPortBotCol
Int 10h
Pop DX
Pop CX
Pop BX
Pop AX
Ret
$ScrollWin ENDP
$SetCursorPosition PROC NEAR ;call this with CursorRow/CursorCol set properly
Push DX
Push AX
Xor BH, BH ; display page zero
Mov DH, CursorRow
Mov DL, CursorCol
Mov AH, 02h
Int 10h
Pop AX
Pop DX
Ret
$SetCursorPosition ENDP
$SetVideoOffset PROC NEAR ;call with CursorRow/CursorCol set properly
Push AX
Push BX
Push CX
Xor AH, AH
Xor BH, BH
Mov AL, CursorRow ; what row are we at?
Mov BL, AL ; make a second copy
Mov CL, 5
Shl AX, CL ; multiply row * 32 into AX
Mov CL, 7
Shl BX, CL ; multiply row * 128 into BX
Add BX, AX ; BX = row * 160 bytes (each char is 2)
Xor AH, AH
Mov AL, CursorCol
Shl AX, 1 ; AX = col * 2
Add AX, BX ; AX = correct offset in video memory
Mov VidOffset, AX ; save it
Pop CX
Pop BX
Pop AX
Ret
$SetVideoOffset ENDP
END