dos_compilers/Microsoft MASM v5/SAMPLES/PAGER.ASM

434 lines
11 KiB
NASM
Raw Permalink Normal View History

2024-06-30 15:49:30 +02:00
PAGE 60,132
.MODEL small
.DATA
EXTRN statatr:BYTE,scrnatr:BYTE,sbuffer:WORD,pbuffer:WORD
EXTRN fsize:WORD,cell:WORD,statline:BYTE,linenum:WORD
EXTRN rows:WORD,vidadr:WORD,cga:BYTE
.CODE
PUBLIC Pager,isEGA
; Procedure Pager
; Purpose Displays status and text lines
; Input Stack variable: lines to scroll (negative up, positive down)
; Global variables: "sbuffer", "pbuffer", "linenum"
; Output To screen
Pager PROC
push bp
mov bp,sp
mov es,sbuffer ; Initialize buffer position
mov di,pbuffer
mov cx,[bp+4] ; Get count argument
mov ax,10 ; Search for linefeed
or cx,cx ; Argument 0?
jg forward ; If above, forward
jl backward ; If below, backward
jmp SHORT show ; If equal, done
backward: call GoBack ; Adjust backward
jmp SHORT show ; Show screen
forward: call GoForwd ; Adjust forward
; Write line number to status line
show: cld ; Go forward
push di
push es
push ds ; Load DS to ES
pop es
; BinToStr (linenum,OFFSET statline[7])
push linenum ; Arg 1
mov ax,OFFSET statline[7]
push ax ; Arg 2
call BinToStr ; Convert to string
; Fill in status line
mov cx,7 ; Seven spaces to fill
sub cx,ax ; Subtract those already done
mov al," " ; Fill with space
rep stosb
pop es
mov bl,statatr ; Load status attribute
mov BYTE PTR cell[1],bl
; CellWrt (DS,OFFSET statline,0,cell)
push ds ; Arg 1
mov ax,OFFSET statline ; Arg 2
push ax
sub ax,ax ; Arg 3
push ax
push cell ; Arg 4
call CellWrt ; Write status line
pop di
mov bl,scrnatr ; Load screen attribute
mov BYTE PTR cell[1],bl
mov si,di ; Update position
mov cx,rows ; Lines per screen
show1: mov bx,rows ; Lines of text
inc bx ; Adjust for 0
sub bx,cx ; Calculate current row
push cx ; Save line number
; CellWrt (sbuffer,position,line,cell)
push sbuffer ; Arg 1
push si ; Arg 2
push bx ; Arg 3
push cell ; Arg 4
call cellwrt ; Write line
push ss ; Restore DS from SS
pop ds
pop cx ; Restore line number
mov si,ax ; Get returned position
cmp ax,fsize ; Beyond end of file?
jae fillout ; Yes? Fill screen with spaces
loop show1 ; else next line
jmp SHORT pagedone ; Get out if done
; Fill the rest with spaces
fillout: dec cx ; Adjust
jcxz pagedone
mov al,80 ; Columns times remaining lines
mul cl
; CellFil (sbuffer,count,cell)
push sbuffer ; Arg 1
push ax ; Arg 2
push cell ; Arg 3
call CellFil ; Fill screen with spaces
push ss ; Restore DS from SS
pop ds
pagedone: pop bp
ret 2
Pager ENDP
; Procedure CellWrt (segment,offset,line,cell)
; Purpose Writes a line to screen buffer
; Input Stack variables: 1 - segment of line
; 2 - offset
; 3 - line number
; 4 - attribute
; Output Line to screen buffer
CellWrt PROC
push bp
mov bp,sp
sub dx,dx ; Clear as flag for scan
cmp cga,1 ; CGA?
jne noscan
mov dx,03DAh ; Load port #
noscan: mov es,vidadr ; Load screen buffer segment
mov ds,[bp+10] ; Buffer segment
mov si,[bp+8] ; Buffer position
mov cx,80 ; Cells per row
mov ax,[bp+6] ; Starting row
mov bx,80*2 ; Bytes per row
mul bl ; Figure columns per row
mov di,ax ; Load as destination
mov bx,di ; Save start for tab calculation
mov ax,[bp+4] ; Attribute
movechar: lodsb ; Get character
cmp al,13 ; CR?
je fillspc
cmp al,9 ; Tab?
jne notab
call filltab ; Yes? fill with spaces
jcxz nextline ; If beyond limit done
jmp SHORT movechar
notab: or dx,dx ; CGA?
je notab2
call Retrace ; Yes? Write during retrace
loop movechar
jmp SHORT nextline
notab2: stosw ; Write
loop movechar
jmp SHORT nextline ; Done
fillspc: mov al," " ; Fill with space
or dx,dx ; CGA?
je space2
space1: call Retrace ; Yes? Write during retrace
loop space1
inc si ; Adjust
jmp SHORT exit ; Done
space2: rep stosw ; Write
inc si ; Adjust for LF
jmp SHORT exit ; Done
nextline: mov ah,10 ; Search for next line feed
chklf: lodsb ; Load and compare
cmp al,ah
loopne chklf
exit: mov ax,si ; Return position
pop bp
ret 8
CellWrt ENDP
; Procedure CellFil (segment,count,cell)
; Purpose Fills screen with character
; Input Stack variables: 1 - segment of text (offset 0)
; 2 - number of characters
; 3 - attribute and character
; Output Characters to screen buffer
CellFil PROC
push bp
mov bp,sp
sub dx,dx ; Clear as flag for scan
cmp cga,1 ; CGA?
jne noscan2
mov dx,03DAh ; Load port #
noscan2: mov es,vidadr ; Load screen buffer segment
mov ds,[bp+8] ; Buffer segment (position 0)
mov cx,[bp+6] ; Characters to fill
mov ax,[bp+4] ; Attribute
or dx,dx ; CGA?
je fillem2
fillem1: call Retrace ; Yes? Write during retrace
loop fillem1
jmp SHORT filled ; Done
fillem2: rep stosw ; Write
filled: pop bp
ret 6
CellFil ENDP
; Procedure FillTab
; Purpose Writes spaces for tab to screen
; Input BX points to start of line, DI points to current position
; Output Spaces to screen buffer
FillTab PROC
push bx
push cx
sub bx,di ; Get current position in line
neg bx
shr bx,1 ; Divide by 2 bytes per character
mov cx,8 ; Default count 8
and bx,7 ; Get modulus
sub cx,bx ; Subtract
mov bx,cx ; Save modulus
mov al," " ; Spaces
or dx,dx ; CGA?
je tabem2
tabem1: call Retrace ; Yes? Write during retrace
loop tabem1
jmp SHORT tabbed
tabem2: rep stosw ; Write
tabbed: pop cx
sub cx,bx ; Adjust count
jns nomore ; Make negative count 0
sub cx,cx
nomore: pop bx
ret
FillTab ENDP
; Procedure GoBack
; Purpose Searches backward through buffer
; Input CX has number of lines; ES:DI has buffer position
; Output Updates "linenum" and "pbuffer"
GoBack PROC
std ; Go backward
neg cx ; Make count positive
mov dx,cx ; Save a copy
inc cx ; One extra to go up one
or di,di ; Start of file?
je exback ; If so, ignore
findb: push cx ; else save count
mov cx,0FFh ; Load maximum character count
cmp cx,di ; Near start of buffer?
jl notnear ; No? Continue
mov cx,di ; else search only to start
notnear: repne scasb ; Find last previous LF
jcxz atstart ; If not found, must be at start
pop cx
loop findb
cmp linenum,0FFFFh ; End of file flag?
jne notend ; No? Continue
add di,2 ; Adjust for cr/lf
mov pbuffer,di ; Save position
call EndCount ; Count back to get line number
ret
notend: sub linenum,dx ; Calculate line number
jg positive
mov linenum,1 ; Set to 1 if negative
positive: add di,2 ; Adjust for cr/lf
mov pbuffer,di ; Save position
ret
atstart: pop cx
sub di,di ; Load start of file
mov linenum,1 ; Line 1
mov pbuffer,di ; Save position
exback: ret
GoBack ENDP
; Procedure GoForwd
; Purpose Searches forward through a buffer
; Input CX has number of lines; ES:DI has buffer position
; Output Updates "linenum" and "pbuffer"
GoForwd PROC
cld ; Go forward
mov dx,cx ; Copy count
findf: push cx ; Save count
mov cx,0FFh ; Load maximum character count
repne scasb ; Find next LF
jcxz atend ; If not found, must be at end
cmp di,fsize ; Beyond end?
jae atend
pop cx
loop findf
add linenum,dx ; Calulate line number
mov pbuffer,di ; Save position
ret
atend: pop cx
mov di,pbuffer ; Restore position
ret
GoForwd ENDP
; Procedure EndCount
; Purpose Counts backward to count lines in file
; Input ES:DI has buffer position
; Output Modifies "linenum"
EndCount PROC
push di
mov al,13 ; Search for CR
mov linenum,0 ; Initialize
findstrt: inc linenum ; Adjust count
mov cx,0FFh ; Load maximum character count
cmp cx,di ; Near start of buffer?
jl notnear2 ; No? Continue
mov cx,di ; else search only to start
notnear2: repne scasb ; Find last previous cr
jcxz found ; If not found, must be at start
jmp SHORT findstrt
found: pop di
ret
EndCount ENDP
; Procedure isEGA
; Purpose Determines if an EGA is active
; Input None
; Output 0 if no; lines per screen if yes
isEGA PROC
push bp
push es
mov ah,12h ; Call EGA status function
mov bl,10h
sub cx,cx ; Clear status bits
int 10h
sub ax,ax ; Segment 0 and assume no EGA
jcxz noega ; If status still clear, no EGA
mov es,ax ; ES=0
test BYTE PTR es:[487h],1000b ; Test active bit
jnz noega ; If set, not active
mov ax,1130h ; Get EGA information
int 10h
mov al,dl ; Return lines per screen
cbw
noega: pop es
pop bp
ret
isEGA ENDP
; Procedure BinToStr (number,address)
; Purpose Converts integer to string
; Input Stack arguments: 1 - Number to convert; 2 - Near address for write
; Output AX has characters written
BinToStr PROC
push bp
mov bp,sp
mov ax,[bp+6] ; Arg 1
mov di,[bp+4] ; Arg 2
sub cx,cx ; Clear counter
mov bx,10 ; Divide by 10
; Convert and save on stack backwards
getdigit: sub dx,dx ; Clear top
div bx ; Divide to get last digit as remainder
add dl,"0" ; Convert to ASCII
push dx ; Save on stack
or ax,ax ; Quotient 0?
loopnz getdigit ; No? Get another
; Take off the stack and store forward
neg cx ; Negate and save count
mov dx,cx
putdigit: pop ax ; Get character
stosb ; Store it
loop putdigit
mov ax,dx ; Return digit count
pop bp
ret 4
BinToStr ENDP
; Procedure Retrace
; Purpose Writes cell during horizontal retrace (CGA)
; Input ES:DI has screen buffer position, AX has cell
; Output Character to screen buffer
Retrace PROC
push bx
mov bx,ax ; Save character
lscan2: in al,dx ; Look in the port
shr al,1 ; until it goes low
jc lscan2
cli
hscan2: in al,dx ; Look in the port
shr al,1 ; until it goes high
jnc hscan2
mov ax,bx ; Restore and write it
stosw
sti
pop bx
ret
Retrace ENDP
END