home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1990
/
11
/
fbrowse.pm
< prev
next >
Wrap
Text File
|
1990-02-05
|
17KB
|
519 lines
;********************************************************************
;* *
;* PROT - A 386 protected mode DOS extender *
;* Copyright (C) 1989, by Al Williams *
;* All rights reserved. *
;* *
;* Permission is granted for non-commercial use of this software *
;* subject to certain conditions (see PROT.ASM). *
;* *
;* This file is: FBROWSE.PM, a file browser. *
;* To assemble: PMASM FBROWSE *
;* or: MASM /DPROGRAM=FBROWSE PROT.ASM,FBROWSE.OBJ,FBROWSE.LST; *
;* *
;********************************************************************
; If this equate is 0, use direct screen output else use DOS
DOSOUT EQU 0
; This program displays a file. The file is stored as strings
; starting at the top of memory (the heap) and growing downward.
; At the start of memory is an array of pointers to lines in the
; heap.
PROT_DATA
BASE DD 0 ; top screen line
PTRPTR DD 0 ; pointer to end of line pointers
HEAPPTR DD ? ; pointer to empty heap entry
FHANDLE DW ? ; file handle
LBUF DB 81 DUP(?) ; line buffer
FBUFP DD 0 ; pointer to character in fbuf
FBUFL DW 0 ; # of char's in fbuf
FBUF DB 512 DUP(?) ; file buffer
; help message
UMSG DB 'Usage: FBROWSE filename',13,10,'$'
; error messages
NFMSG DB 'Can''t open file',13,10,'$'
FEMSG DB 'File error!',13,10,'$'
OMMSG DB 'Out of memory',13,10,'$'
; copyright message
CPYMSG DB 'FBROWSE - Protected Mode File Browser (C) 1989'
DB ' by Al Williams'
IF DOSOUT
DB '$' ; end of string for DOS function 9
ELSE
DB 0 ; end of string for PROT
ENDIF
; bios call frame
BINTFRAME VM86BLK <>
PROT_DATA_END
PROT_CODE
; This routine catches ^BREAK's and forces program termination
ONBREAK PROC FAR
MOV AX,SEL_UDATA
MOV DS,AX
JMP32S USTOP0
ONBREAK ENDP
; Main program
USER PROC NEAR
; Enable Break handling
MOV AX,SEL_UCODE
MOV BRK_SEG,AX
MOV EAX,OFFSET ONBREAK
MOV BRK_OFF,EAX
; clear the screen
CALL32F SEL_CODE32,CLS
; Set up CALL86 parameter blocks (pintframe & bintframe)
MOV AX,SEG SSINT1
MOV PINTFRAME.VMSS,EAX
MOV BINTFRAME.VMSS,EAX
MOV AX,SEG USERDATA
MOV PINTFRAME.VMDS,EAX
MOV EAX, OFFSET SSINT1
MOV PINTFRAME.VMESP,EAX
MOV BINTFRAME.VMESP,EAX
; Pintframe will be used for INT 21
MOV EAX,21H
MOV PINTFRAME.VMINT,EAX
; get command line
MOV CX,SEL_PSP
MOV FS,CX
ASSUME FS:NOTHING
XOR EBX,EBX
MOV BL,FS:[80H]
OR BL,BL
JNZ SHORT OPENFILE
; No command line - Print usage message
MOV AH,9
MOV EDX,OFFSET UMSG
MOV EBX,OFFSET PINTFRAME
VM86CALL
MOV AL,1
JMP32S USTOP ; back to DOS
; Open file for reading
OPENFILE:
XOR AX,AX ; null terminate file name
MOV FS:[81H+BX],AX
MOV AX,_PSP
MOV PINTFRAME.VMDS,EAX
MOV EDX,80H
; skip spaces
SPACSKIP:
INC DX
CMP BYTE PTR FS:[EDX],' '
JZ SHORT SPACSKIP
MOV AX,3D00H
MOV EBX,OFFSET PINTFRAME
VM86CALL ; open file
MOV BX,SEG USERDATA
MOV PINTFRAME.VMDS,EBX
JNC SHORT FOPENED
; Couldn't open file -- print error
MOV EDX,OFFSET NFMSG
MOV AH,9
MOV EBX,OFFSET PINTFRAME
VM86CALL ; can't open file
MOV AL,1
JMP32S USTOP ; back to DOS
; File opened OK
FOPENED:
MOV FHANDLE,AX ; save file handle
; See if extended memory present
MOV AX,SEL_EXT
LSL EBX,EAX
OR EBX,EBX
JNZ SHORT USE_EXTMEM
; No extended memory present -- use DOS memory
MOV AX,SEL_FREE
USE_EXTMEM:
MOV GS,AX ; memory segment --> GS
; Set heap pointer to top of availble memory
LSL EAX,EAX
MOV HEAPPTR,EAX
MOV EDX,EAX
XOR EBX,EBX
REREAD:
MOV EAX,EBX ; check for heap overflow
SHL EAX,2
CMP EAX,EDX
JB SHORT HEAPOK
; No more memory -- Print error message
MOV AH,9
MOV EDX,OFFSET OMMSG
MOV EBX,OFFSET PINTFRAME
VM86CALL ; out of memory
MOV AL,1
JMP32S USTOP ; back to DOS
HEAPOK:
; Put heap pointer in lines array
MOV GS:[EBX*4],EDX
; read line to heap in reverse order. Each line ends in CR
CALL SHORT READLINE
PUSHFD
; point to next line in lines array
INC EBX
POPFD
JNZ SHORT REREAD ; not end of file?
; here at end of file
MOV PTRPTR,EBX ; end of lines array
MOV BX,FHANDLE
MOV PINTFRAME.VMEBX,EBX
MOV AH,3EH
MOV EBX,OFFSET PINTFRAME
VM86CALL ; close file
MOV DX,1800H
CALL SHORT SETCP ; set cursor position
; write copyright message
IF DOSOUT
MOV AH,9
MOV EDX,OFFSET CPYMSG
MOV EBX,OFFSET PINTFRAME
VM86CALL ; print copyright
ELSE
; If not BIOS output then get rid of BIOS cursor
MOV DX,0FFFFH
CALL32S DOSSETCP ; hide cursor
MOV EBX,OFFSET CPYMSG
CALL32F SEL_CODE32,MESSOUT
ENDIF
; inverse video the bottom line
PUSH DS
MOV AX,SEL_VIDEO
MOV DS,AX
MOV CL,80
MOV EDX,24*160+1 ; bottom line
INVLOOP:
MOV BYTE PTR [EDX],70H
INC EDX
INC EDX
DEC CL
JNZ SHORT INVLOOP
POP DS
JMP SHORT HK0 ; skip over home key processing
; Home key processing
HOMEKEY: OR BASE,0 ; don't do home if already there
JZ SHORT KEYLOOP
HK0:
XOR EAX,EAX ; Set screen start to 0
MOV BASE,EAX
; Come here to display a page starting at base
PAGEDISP:
CALL SHORT DISPLAY
; read a key and act on it
KEYLOOP: MOV AX,16H
MOV BINTFRAME.VMINT,EAX
XOR AH,AH
PUSH ES
MOV BX,SEL_UDATA
MOV ES,BX
MOV EBX,OFFSET BINTFRAME
VM86CALL ; read a key
POP ES
CMP AL,27 ; escape key?
JZ NEAR PTR USTOP0
CMP AL,3 ; break key
JZ NEAR PTR USTOP0
OR AL,AL
JNZ SHORT KEYERR ; special key?
; test for function keys
CMP AH,48H ; up arrow
JCC32 Z, UPARROW
CMP AH,47H ; home key
JZ SHORT HOMEKEY
CMP AH,4FH ; end key
JCC32 Z,ENDKEY
CMP AH,49H ; page up
JCC32 Z,PGUP
CMP AH,51H ; page down
JCC32 Z,PGDN
CMP AH,50H ; down arrow
JZ SHORT DNARROW
; Come here if you don't know what that key was!
KEYERR:
PUSH EDX
MOV DL,7 ; bell character
MOV AH,2
MOV EBX,OFFSET PINTFRAME
VM86CALL
POP EDX
JMP SHORT KEYLOOP
; down arrow processing
DNARROW:
MOV EAX,BASE ; don't go down if at end
ADD EAX,24
CMP EAX,PTRPTR
JCC32 AE,KEYLOOP
INC BASE ; top of screen + 1
MOV AX,0601H ; scroll screen
CALL SHORT SCROLL
MOV DX,1700H ; position cursor
CALL SHORT SETCP
MOV EDX,BASE ; print bottom line
ADD EDX,23
CALL SHORT PLINE
JMP32S KEYLOOP
; up arrow processing
UPARROW:
OR BASE,0 ; don't go up if at top
JCC32 Z,KEYLOOP
DEC BASE ; adjust top of screen
MOV AX,0701H ; scroll screen
CALL SHORT SCROLL
XOR DX,DX ; position cursor
CALL SHORT SETCP
MOV EDX,BASE ; print top line
CALL SHORT PLINE
JMP32S KEYLOOP
; End key processing
ENDKEY: MOV EAX,BASE ; Don't do end if already there
ADD EAX,24
CMP EAX,PTRPTR
JCC32 AE,KEYLOOP
MOV EAX,PTRPTR ; get last line
SUB EAX,24 ; find top of screen
MOV BASE,EAX
JMP32S PAGEDISP ; display page
; Page Up processing
PGUP: MOV EAX,BASE ; Don't do pgup if at top
OR EAX,EAX
JCC32 Z,KEYLOOP
CMP EAX,24
JBE SHORT PGUP0 ; if near the top.. go pgup0
SUB EAX,24 ; find new line
JMP SHORT PGUP1
PGUP0: XOR EAX,EAX ; 1st line
PGUP1: MOV BASE,EAX
JMP32S PAGEDISP
; Page down processing
PGDN: MOV EAX,BASE ; If at bottom, skip
ADD EAX,24
CMP EAX,PTRPTR
JCC32 AE,KEYLOOP
MOV BASE,EAX ; find new line
JMP32S PAGEDISP
; Exit FBROWSE
USTOP0:
; clear screen
CALL32F SEL_CODE32,CLS
XOR AL,AL ; zero return code
PUSH EAX
XOR DX,DX ; home cursor
CALL SHORT DOSSETCP
POP EAX
USTOP:
BACK2DOS
USER ENDP
; Read a line from the file
; lines end in 0AH unless they are long in which case they
; end in 0DH
READLINE PROC NEAR
PUSH ECX
MOV CX,80
RLINE0:
CALL SHORT GFCHAR ; get character
MOV GS:[EDX],AL ; store it
PUSHFD
DEC EDX
POPFD ; end of line?
JZ SHORT RLINEXIT
CMP AL,0AH ; end of line?
JZ SHORT RLINEEOL
DEC CX
JNZ SHORT RLINE0 ; 80 char line?
; compare last character with 0ah -- if true pass it
CALL SHORT GFCHAR
CMP AL,0AH
; if so, line exactly 80 chars
JZ SHORT LONGLINE
DEC FBUFP ; unget character
LONGLINE:
MOV AL,0DH ; mark long line
MOV GS:[EDX],AL ; save end marker
DEC EDX
RLINEEOL: CMP AL,0FFH ; set NZ flag
RLINEXIT:
POP ECX
RET
READLINE ENDP
; scroll screen using BIOS
SCROLL PROC NEAR
PUSH ES
MOV BX,SEL_UDATA
MOV ES,BX
MOV BX,0700H
MOV BINTFRAME.VMEBX,EBX
MOV BX,10H
MOV BINTFRAME.VMINT,EBX
XOR ECX,ECX
MOV DX,174FH
MOV EBX,OFFSET BINTFRAME
VM86CALL
POP ES
RET
SCROLL ENDP
; position the cursor
DOSSETCP PROC NEAR
PUSH EBX
PUSH ES
MOV AX,SEL_UDATA
MOV ES,AX
MOV BX,10H
MOV BINTFRAME.VMINT,EBX
MOV BINTFRAME.VMEBX,EBX
MOV AH,2
MOV EBX,OFFSET BINTFRAME
VM86CALL
POP ES
POP EBX
RET
DOSSETCP ENDP
SETCP PROC NEAR
IF DOSOUT
CALL32S DOSSETCP
ELSE
PUSH ES
MOV AX,SEL_DATA
MOV ES,AX
MOV EAX,80
MUL DH
XOR DH,DH
ADD AX,DX
MOV ES:CURSOR,EAX
POP ES
RET
ENDIF
SETCP ENDP
; display a screen full
DISPLAY PROC NEAR
MOV AX,0600H
CALL32S SCROLL ; clear screen
XOR DX,DX
CALL32S SETCP ; home cursor
MOV CX,24
MOV EDX,BASE
DISP0:
PUSH EDX
CALL SHORT PLINE ; print lines
POP EDX
INC EDX
CMP EDX,PTRPTR
JZ DISP00
DEC CX
JNZ SHORT DISP0
DISP00:
RET
DISPLAY ENDP
; print a line pointed to by [edx] going backwards to \n
PLINE PROC NEAR
; get line ptr
MOV EDX,GS:[EDX*4]
PLINE0:
MOV AL,GS:[EDX] ; get char fm str
DEC DX
CMP AL,0DH ; Long line?
JZ SHORT PLINE2
CALL SHORT OOUCH ; Output character
CMP AL,0AH ; End of string
JNZ SHORT PLINE0
PLINE1:
MOV AL,0DH ; Output CR
CALL SHORT OOUCH
PLINE2:
RET
PLINE ENDP
; get a character from the file
GFCHAR PROC NEAR
PUSH EBX
PUSH EDX
PUSH ECX
GFSKIP:
OR FBUFL,0 ; buffer empty?
JZ SHORT FILLBUFF
MOV EAX,FBUFP ; buffer used up?
CMP AX,FBUFL
JNZ SHORT FMBUFF
FILLBUFF:
MOV AX,FHANDLE ; read from file
MOV PINTFRAME.VMEBX,EAX
MOV ECX,512
MOV EDX,OFFSET FBUF
MOV AH,3FH
MOV EBX,OFFSET PINTFRAME
VM86CALL ; read buffer
JNC SHORT NOFERR
; file error here
MOV AH,9
MOV EDX,OFFSET FEMSG
VM86CALL
JMP32S USTOP ; back to DOS
NOFERR: OR AX,AX
MOV FBUFL,AX ; store buffer length
MOV AL,0AH
JZ SHORT GFCEOF ; End of file?
XOR EAX,EAX ; clear buffer pointer
MOV FBUFP,EAX
; This is where the character is read from a good buffer
FMBUFF:
MOV EBX,FBUFP
MOV AL,FBUF[EBX]
INC EBX
MOV FBUFP,EBX
CMP AL,0DH ; skip CR
JCC32 Z,GFSKIP
GFCEOF:
POP ECX
POP EDX
POP EBX
RET
GFCHAR ENDP
; output character in al
OOUCH PROC NEAR
IF DOSOUT
PUSHAD
PUSH ES
ASSUME ES:DAT32
MOV BX,SEL_DATA
MOV ES,BX
MOV AH,2
MOV DL,AL
MOV EBX,OFFSET PINTFRAME
VM86CALL
POP ES
POPAD
RET
ELSE
CALL32F SEL_CODE32,OUCH
RET
ENDIF
OOUCH ENDP
PROT_CODE_END