home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS - Coast to Coast
/
simteldosarchivecoasttocoast.iso
/
pcmag
/
vol7n12.zip
/
FSB.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-03-23
|
30KB
|
992 lines
;------------------------------------------------
; FSB.ASM -- "File Search and Browse" for OS/2
; (c) 1988, Ziff Communications Co.
; PC Magazine * Charles Petzold, 3/88
;------------------------------------------------
.286P
;-----------------------------------------------------------
; Macro to call OS/2 functions without declaring them first
;-----------------------------------------------------------
OS2Call MACRO fnctname
IFNDEF fnctname
EXTRN fnctname:FAR
ENDIF
Call Far Ptr fnctname
ENDM
;-----------------------------------
; Structures used in OS/2 functions
;-----------------------------------
FileFindBufStr STRUC
create_date dw ?
create_time dw ?
access_date dw ?
access_time dw ?
write_date dw ?
write_time dw ?
file_size dd ?
falloc_size dd ?
attributes dw ?
string_len db ?
file_name db 13 dup (?)
FileFindBufStr ENDS
KeyDataStruc STRUC
char_code db ?
scan_code db ?
status db ?
nls_shift db ?
shift_state dw ?
time dd ?
KeyDataStruc ENDS
ModeDataStruc STRUC
md_length dw ?
md_type db ?
color db ?
col dw ?
row dw ?
hres dw ?
vres dw ?
ModeDataStruc ENDS
;--------------------------------
; Define all segments and DGROUP
;--------------------------------
_TEXT SEGMENT WORD PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
_BSS SEGMENT WORD PUBLIC 'BSS'
_BSS ENDS
STACK SEGMENT PARA STACK 'STACK'
dw 1024 dup (?)
STACK ENDS
DGROUP GROUP _DATA, _BSS, STACK
ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP, ES:DGROUP
;--------------------------
; Initialized Data Segment
;--------------------------
_DATA SEGMENT
SyntaxMsg db 13, 10, "Syntax: FSB filespec"
db 13, 10
db 13, 10, "File Search and Browse "
db "(c) 1988, Ziff Communications Co."
db 13, 10, "PC Magazine ", 254," Charles Petzold, 3/88"
CRLF db 13, 10, 0
DriveError db "FSB: Invalid disk drive", 0
StartDirError db "FSB: Invalid directory", 0
FileFindError db "FSB: Invalid file spec", 0
PipeError db "FSB: Cannot not create pipe", 0
ThreadError db "FSB: Cannot not create second thread", 0
FileOpenError db 9, "FSB: Cannot open file for reading", 13, 10, 0
VideoModeError db 9, "FSB: Unsupported video mode", 13, 10, 0
RootDir db "\", 0
Delimiters db 9, ' ,;=', 0
DoBrowse db 1
_DATA ENDS
;----------------------------
; Uninitialized Data Segment
;----------------------------
_BSS SEGMENT
FileSpec dw ?, ?
LastBackSlash dw ?
PipeReadHandle dw ?
PipeWriteHandle dw ?
ThreadID dw ?
ThreadStack dw 1024 dup (?)
FullFileName db 80 dup (?)
BytesRead dw ?
BytesWritten dw ?
_BSS ENDS
;--------------
; Code Segment
;--------------
_TEXT SEGMENT
;----------------------------------------------
; Parse command line to get file specification
;----------------------------------------------
Entry: Push DS ; Data segment selector
Pop ES ; Transfer it to ES
Mov DS, AX ; DS = Environment selector
Mov SI, BX ; SI = Start of command line
SkipProgName: Lodsb ; Pull a command line byte
Or AL, AL ; Check if it's zero
Jnz SkipProgName ; If not, continue
SkipDelim: Lodsb ; Get command line byte
Or AL, AL ; See if it's zero
Jnz CheckDelim ; If not, check for delimiter
Jmp DoSyntaxMsg ; If so, display message
CheckDelim: Mov CX, 5 ; Five delimiters
Mov DI, Offset Delimiters ; pointer to them
Repne Scasb ; scan for delimiter
Jz SkipDelim ; if delimiter, loop around
Cmp Byte Ptr [SI], ':' ; Check if a drive present
Jnz NoDiskDrive ; If not, skip section
And AL, 0DFh ; Capitalize it
Sub AL, '@' ; Change from A to 1, etc
Sub AH, AH ; Zero out top byte
Push AX ; Change to that drive
OS2Call DosSelectDisk ; by calling OS/2
Mov DX, Offset DriveError
Or AX, AX ; If AX not zero,
Jnz ErrorExit ; display message and exit
Add SI, 2 ; Skip past drive
NoDiskDrive: Dec SI ; First character of rest
Mov ES:[FileSpec], SI ; Save the address
Mov ES:[FileSpec + 2], DS
FindEnd: Lodsb ; Get a byte
Cmp AL, '\' ; Check if it's a backslash
Jnz NotBackSlash ; If not, continue
Mov ES:[LastBackSlash], SI ; If so, save the address
NotBackSlash: Mov CX, 6 ; now six delimiters
Mov DI, Offset Delimiters ; pointer to delimiters
Repne Scasb ; scan them
Jnz FindEnd ; if not delimiter, loop around
Mov Byte Ptr [SI-1], 0 ; terminate with zero
DoChangeDir: Mov SI, ES:[LastBackSlash] ; Address of last back slash
Or SI, SI ; See if any at all
Jz NoChangeDir ; If none, skip this section
Dec SI ; Points to last backslash now
Cmp SI, ES:[FileSpec] ; Check if at beginning
Jnz ChangeToDir ; If not, use directory
Inc Word Ptr ES:[FileSpec] ; Skip past initial backslash
Push DGROUP ; Segment of new dir
Push Offset RootDir ; Offset of new dir
Jmp Short CallChangeDir ; Change to root directory
ChangeToDir: Mov Byte Ptr [SI], 0 ; Terinate dir name with zero
Push Word Ptr ES:[FileSpec + 2] ; This is segment
Push Word Ptr ES:[FileSpec] ; This is offset
Inc SI ; Save address of filename
Mov ES:[FileSpec], SI ; in FileSpec
CallChangeDir: Push 0 ; Reserved bytes
Push 0
OS2Call DosChdir ; Change directory
Mov DX, Offset StartDirError
Or AX, AX ; If non-zero return code,
Jnz ErrorExit ; display message and leave
NoChangeDir: Push ES ; Set DS to data segment
Pop DS
Call MainRoutine ; Go!
Push 1 ; All threads to terminate
Push 0 ; Return code
OS2Call DosExit ; End the program
;-------------------------------------
; Error Exit: DX is pointer to string
;-------------------------------------
DoSyntaxMsg: Mov DX, Offset SyntaxMsg
ErrorExit: Mov AX, DGROUP ; Set DS to data segment
Mov DS, AX
Mov BX, 2 ; Standard Error handle
Call StringLen ; Get length of DX string
Mov CX, AX ; Move it to CX
Call MyDosWrite ; Display error message
Push 1 ; All threads to terminate
Push 1 ; Error return code
OS2Call DosExit ; End the program
;----------------------------------------------------------------
; Main Routine, create pipe, start second thread, and do browses
;----------------------------------------------------------------
MainRoutine: Push DS ; Address for read handle
Push Offset PipeReadHandle
Push DS ; Address for write handle
Push Offset PipeWriteHandle
Push 16384 ; Size of pipe
OS2Call DosMakePipe ; Create it
Mov DX, Offset PipeError
Or AX, AX ; If non-zero return code,
Jnz ErrorExit ; depart from program
Push CS ; Address of second thread
Push Offset SecondThread
Push DS ; Address for thread ID
Push Offset ThreadID
Push DS ; Top of thread stack
Push Offset ThreadStack + 2048
OS2Call DosCreateThread ; Create the thread
Mov DX, Offset ThreadError
Or AX, AX ; Again, if error code,
Jnz ErrorExit ; get out of this place
StartPipeRead: Mov CX, 80 ; Read 80 chars from pipe
Mov DX, Offset FullFileName ; Store it here
ReadPipe: Mov BX, [PipeReadHandle] ; Pipe handle
Call MyDosRead ; Read it
Cmp [BytesRead], 0 ; Check if read no bytes
Jz NothingLeft ; If so, pipe is empty
Add DX, [BytesRead] ; Increment destination ptr
Sub CX, [BytesRead] ; Decrement counter
Jnz ReadPipe ; If not 80 bytes, read again
Mov DX, Offset FileFindError
Cmp [FullFileName], 0 ; See if file name present
Jz ErrorExit ; If not, thread had problem
NoErrFromThread:Mov BX, 1 ; Standard output handle
Mov DX, Offset FullFileName ; Full file name
Call StringLen ; Get its length
Mov CX, AX ; Store in CX
Call MyDosWrite ; Write to standard output
Mov CX, 2 ; Two bytes
Mov DX, Offset CRLF ; for carriage ret/line feed
Call MyDosWrite ; Write that out also
Cmp [DoBrowse], 1 ; See if still doing browse
Jnz StartPipeRead ; If not, skip the call
Call Browse ; Browse the file
Or AX, AX ; If zero returned, continue
Jz StartPipeRead
Cmp AX, -1 ; If -1, Esc pressed -->
Jz NothingLeft ; terminate gracefully
Cmp AX, Offset VideoModeError
Jnz ShowBrowseErr ; If video mode error,
Mov [DoBrowse], 0 ; don't try browse again
ShowBrowseErr: Mov BX, 2 ; Standard error output
Mov DX, AX ; Address of error message
Call StringLen ; Find length
Mov CX, AX ; and save in CX
Call MyDosWrite ; Dispay the string
Jmp StartPipeRead ; And get another file name
NothingLeft: Ret ; Return when all done
;--------------------------------------------------------------------------
; DosRead and DosWrite routines (BX is handle, DX is buffer, CX is length)
;--------------------------------------------------------------------------
MyDosRead: Push BX ; Input handle
Push DS ; Segment of buffer
Push DX ; Offset of buffer
Push CX ; Number of bytes to write
Push DS ; Segment for bytes read
Push Offset BytesRead ; Offset for bytes read
OS2Call DosRead ; Read
Ret
MyDosWrite: Push BX ; Output handle
Push DS ; Segment of buffer
Push DX ; Offset of buffer
Push CX ; Number of bytes to write
Push DS ; Segment for bytes written
Push Offset BytesWritten ; Offset for bytes written
OS2Call DosWrite ; Write
Ret
;------------------------------------------------------------
; StringLen routine (DS:DX points to string, AX is returned)
;------------------------------------------------------------
StringLen: Push ES ; Save some registers
Push DI
Push CX
Push DS
Pop ES ; Set ES to DS
Mov DI, DX ; Set DI to address of string
Mov CX, -1 ; Initialize CX to big number
Sub AL, AL ; Search for zero
Repnz Scasb ; Do the scan
Not CX ; Invert CX
Dec CX ; Take away one
Mov AX, CX ; That's the length
Pop CX ; Restore saved registers
Pop DI
Pop ES
Ret
_TEXT ENDS
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; SECOND THREAD section to search for files and write to pipe
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
_DATA SEGMENT
BackDir db "..", 0
StarDotStar db "*.*", 0
_DATA ENDS
_BSS SEGMENT
FileFindBuf FileFindBufStr <>
FileFindBufLen equ $ - FileFindBuf
FullPathName Label Byte
CurrentDisk db ?, ?, ?
CurrentDir db 64 dup (?)
CurrDirLen dw ?
Zeroes db 80 dup (?)
DriveMap dd ?
_BSS ENDS
;---------------------------------------------------------
; Second Thread -- Calls FindThem, closes pipe, and exits
;---------------------------------------------------------
_TEXT SEGMENT
SecondThread: Push DS ; Variable to receive
Push Offset CurrentDisk ; current drive
Push DS ; Variable to receive
Push Offset DriveMap ; drive map
OS2Call DosQCurDisk
Add [CurrentDisk], '@' ; Convert to letter
Mov [CurrentDisk + 1], ':' ; Follow by colon
Mov [CurrentDisk + 2], '\' ; and backslash
Call FindThem ; Do the finds
TerminateThread:Push [PipeWriteHandle] ; Close the pipe for writing
OS2Call DosClose
Push 0 ; Terminate this thread only
Push 0 ; Result code (ignored)
OS2Call DosExit
SearchError: Mov BX, [PipeWriteHandle] ; If error,
Mov DX, Offset Zeroes ; write zeroes to
Mov CX, 80 ; pipe
Call MyDosWrite
Jmp TerminateThread ; and terminate
;----------------------------------------------------------------
; Find Them -- Recursive routine to find files fitting file spec
;----------------------------------------------------------------
FindThem: Enter 4, 0 ; Dir Handle is [BP - 2]
; Search Count is [BP - 4]
;------------------------------------
; Get current directory for printing
;------------------------------------
Mov [CurrDirLen], 64 ; Len for current dir
Push 0 ; Current disk drive
Push DS
Push Offset CurrentDir ; Space for current dir
Push DS
Push Offset CurrDirLen
OS2Call DosQCurDir ; Get current dir
Mov DX, Offset FullPathName ; Find length of it
Call StringLen
Cmp AX, 3 ; See if root
Jz NoMoreSlashes ; If so, skip next part
Mov SI, DX ; Add a slash
Add SI, AX ; at end of directory
Mov Byte Ptr [SI], '\'
Mov Byte Ptr [SI + 1], 0
Inc AX
NoMoreSlashes: Mov [CurrDirLen], AX ; Save total length
;----------------------
; Search for the files
;----------------------
Mov Word Ptr [BP - 2], -1 ; Initial directory Handle
Mov Word Ptr [BP - 4], 1 ; Search for one file
Push [FileSpec + 2] ; segment of find file name
Push [FileSpec] ; offset of find file name
Push SS ; segment of directory handle
Lea AX, [BP - 2] ; offset of directory handle
Push AX
Push 07h ; attribute
Push DS ; segment of buffer
Push Offset FileFindBuf ; offset of buffer
Push FileFindBufLen ; length of buffer
Push DS ; segment of search count
Lea AX, [BP - 4] ; offset of search count
Push AX
Push 0 ; Reserved
Push 0
OS2Call DosFindFirst ; Find first file
FindResult1: Or AX, AX ; See if error
Jz NoFindError1 ; If not skip next
Cmp AX, 18 ; See if no more files
Jz FindAllDone1 ; If so, done with search
Jmp SearchError ; Process error
NoFindError1: Cmp Word Ptr [BP - 4], 0 ; See if zero files found
Jz FindAllDone1 ; If so, done with search
Mov BX, [PipeWriteHandle] ; Write drive and
Mov DX, Offset FullPathName ; directory path
Mov CX, [CurrDirLen] ; to pipe
Mov SI, CX
Call MyDosWrite
Mov DX, Offset FileFindBuf.file_name
Mov CL, [FileFindBuf.string_len] ; Write file name
Sub CH, CH ; to pipe
Add SI, CX
Call MyDosWrite
Mov DX, Offset Zeroes ; Pad with zeroes
Mov CX, 80 ; written to pipe
Sub CX, SI
Call MyDosWrite
Push [BP - 2] ; Directory Handle
Push DS ; segment of buffer
Push Offset FileFindBuf ; offset of buffer
Push FileFindBufLen ; length of buffer
Push DS ; segment of count
Lea AX, [BP - 4] ; offset of count
Push AX
OS2Call DosFindNext ; Find next file
Jmp FindResult1 ; Loop around
FindAllDone1: Push [BP - 2] ; directory handle
OS2Call DosFindClose ; close it
;-------------------------------
; Now search for subdirectories
;-------------------------------
Mov Word Ptr [BP - 2], -1 ; Initial directory handle
Mov Word Ptr [BP - 4], 1 ; Search for one directory
Push DS ; segment of spec
Push Offset StarDotStar ; offset of spec
Push SS ; segment of handle
Lea AX, [BP - 2] ; offset of handle
Push AX
Push 10h ; attribute (dirs only)
Push DS ; segment of buffer
Push Offset FileFindBuf ; offset of buffer
Push FileFindBufLen ; length of buffer
Push DS ; segment of count
Lea AX, [BP - 4] ; offset of count
Push AX
Push 0 ; reserved
Push 0
OS2Call DosFindFirst ; Find first dir
FindResult2: Or AX, AX ; Check if error
Jz NoFindError2
Cmp AX, 18 ; Check if all finished
Jz FindAllDone2
Jmp SearchError
NoFindError2: Cmp Word Ptr [BP - 4], 0 ; Check if no dirs found
Jz FindAllDone2
Test [FileFindBuf.attributes], 10h ; See if directory
Jz FindTheNext
Cmp [FileFindBuf.file_name], '.' ; Exclude '.' and '..'
Jz FindTheNext
Push DS ; Change the directory
Push Offset FileFindBuf.file_name
Push 0
Push 0
OS2Call DosChdir
Call FindThem ; Recursive call
Push DS ; Change to '..' directory
Push Offset BackDir
Push 0
Push 0
OS2Call DosChdir
FindTheNext: Push [BP - 2] ; search handle
Push DS ; segment of buffer
Push Offset FileFindBuf ; offset of buffer
Push FileFindBufLen ; length of buffer
Push DS ; segment of count
Lea AX, [BP - 4] ; offset of count
Push AX
OS2Call DosFindNext ; Find next directory
Jmp FindResult2
FindAllDone2: Push [BP - 2] ; directory handle
OS2Call DosFindClose ; close it
Leave
Ret
_TEXT ENDS
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; BROWSE section to display files after names are read from pipe
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
_DATA SEGMENT
db 'ATTR1='
Attribute1 db 1Eh ; Attribute for file text
db 'ATTR2='
Attribute2 db 4Fh ; Attribute for file name
db 'SHIFT='
ShiftHoriz db 8 ; Horizontal shift screen default
FileOffset dw -1, -1
Dispatch dw Home, Up, PgUp, Dummy, Left
dw Dummy, Right, Dummy, EndKey, Down, PgDn
_DATA ENDS
_BSS SEGMENT
ModeData ModeDataStruc <>
KeyData KeyDataStruc <>
Buffer db 16384 dup (?)
BufferMid db 16384 dup (?)
BufferEnd Label Byte
ScreenSize dw ?
ScreenStart dw ?
EndOfFile dw ?
HorizOffset dw ?
RightMargin dw ?
ScreenAddr Label DWord
ScreenOff dw ?
ScreenSeg dw ?
FileHandle dw ?
OpenAction dw ?
NewPointer dd ?
ScreenSaveSel dw ?
_BSS ENDS
;---------------------------
; Open the File for reading
;---------------------------
_TEXT SEGMENT
Browse: Mov [FileOffset], -1 ; Initialize these pointers
Mov [FileOffset + 2], -1
Push DS ; segment of name
Push Offset FullFileName ; offset of name
Push DS ; segment for handle
Push Offset FileHandle ; offset for handle
Push DS ; segment for 'action'
Push Offset OpenAction ; offset for 'acton'
Sub AX, AX
Push AX ; high size (ignored)
Push AX ; low size (ignored)
Push AX ; attribute (ignored)
Push 1 ; open if file exists
Push 0A0h ; read only / deny write
Push AX ; reserved
Push AX ; reserved
OS2Call DosOpen ; Open File
Or AX, AX ; Check if error
Jz GotTheFile ; If not, continue
Mov AX, Offset FileOpenError
Ret
GotTheFile:
;-----------------------------
; Get Screen Mode Information
;-----------------------------
Mov [ModeData.md_length], 12 ; length of structure
Push DS ; segment of structure
Push Offset ModeData ; offset of structure
Push 0 ; reserved
OS2Call VioGetMode ; get video mode
Or AX, AX ; See if error (only if
Jz NotDetached ; program is detached)
VideoError: Mov AX, Offset VideoModeError
Ret
NotDetached: Test [ModeData.md_type], 2 ; See if graphics mode
Jnz VideoError ; If so, do not continue
Mov AX, [ModeData.col] ; character columns
Mul [ModeData.row] ; character rows
Jc VideoError ; Leave if exceeds 64K
Add AX, AX ; Ditto here
Jc VideoError
Mov [ScreenSize], AX ; Save screen size in bytes
Push DS ; Segment for address
Push Offset ScreenAddr ; Offset for address
Push DS ; Segment for size
Push Offset ScreenSize ; Offset for size
Push 0 ; Reserved
OS2Call VioGetBuf ; Get logical video buffer
Or AX, AX ; Leave if an error
Jnz VideoError
;---------------------------------------
; Allocate memory and save screen in it
;---------------------------------------
Push [ScreenSize] ; Size of segment
Push DS ; Segment for selector
Push Offset ScreenSaveSel ; Offset for selector
Push 0 ; No sharing
OS2Call DosAllocSeg ; Allocate segment
Or AX, AX ; If error, leave
Jnz VideoError
Push [ScreenSaveSel] ; Segment for destination
Sub AX, AX
Push AX ; Offset for destination
Push DS ; Segment of screen size
Push Offset ScreenSize ; Offset of screen size
Push AX ; Starting row
Push AX ; Starting column
Push AX ; Reserved
OS2Call VioReadCellStr ; Save the screen
Call SetExitList ; Will restore on exit
;---------------------------------------
; Get keyboard key and decide on action
;---------------------------------------
Call Home ; Read file in
Mov [ScreenStart],SI ; Set buffer address
KeyLoop: Push ThreadID ; Don't let the search
OS2Call DosSuspendThread ; slow down the update
Call UpDateScreen ; Update the screen
Push ThreadID
OS2Call DosResumeThread ; Let the search resume
GetKey: Push DS ; Segment of structure
Push Offset KeyData ; Offset of structure
Push 0 ; Wait for key
Push 0 ; Reserved
OS2Call KbdCharIn ; Read key
Mov AL, [KeyData.char_code] ; Get character code
Cmp AL, ' ' ; A space means do next
Je SpaceLeave ; file
Cmp AL,27 ; Check if ESC
Je EscLeave ; If so, terminate
Cmp AL, 0E0h ; E0 for enhanced keyboard
Jz ScanCode ; extended keys
Or AL, AL ; Check if extended
Jnz GetKey ; If not, try again
ScanCode: Mov AL, [KeyData.scan_code] ; Get scan code
Sub AL,71 ; Subtract Home key value
Jb GetKey ; If below that, not valid
Cmp AL,(81 - 71) ; Check if above PgDn
Ja GetKey ; If so, ignore it
Sub AH,AH ; Zero out top byte
Add AX,AX ; Double for word access
Mov BX,AX ; Offset in dispatch table
Mov SI,[ScreenStart] ; Set current buffer pointer
Call [Dispatch + BX] ; Do the call
Mov [ScreenStart],SI ; Set new buffer pointer
Jmp KeyLoop ; And update the screen
;--------------------------------------------
; Terminate -- Restore screen and close file
;--------------------------------------------
SpaceLeave: Call ExitRoutine ; Restore screen
Call UnsetExitList ; Take away exit list
Sub AX, AX ; 0 means continue with files
Ret ; Return
EscLeave: Call ExitRoutine ; Restore screen
Call UnsetExitList ; Take away exit list
Mov AX, -1 ; -1 means stop program
Ret ; Return
;-------------------------------------
; Exit List Processing for Ctrl-Break
;-------------------------------------
SetExitList: Push 1 ; Set an exit list
Push CS ; Segment of routine
Push Offset ExitList ; Offset of routine
OS2Call DosExitList
Ret
UnsetExitList: Push 2 ; Unset an exit list
Push CS ; Segment of routine
Push Offset ExitList ; Offset of routine
OS2Call DosExitList
Ret
ExitRoutine: Push [ScreenSaveSel] ; Segment of saved screen
Push 0 ; Offset of saved screen
Push [ScreenSize] ; Length of saved screen
Push 0 ; Starting row
Push 0 ; Starting column
Push 0 ; Reserved
OS2Call VioWrtCellStr ; Restore screen
Push [FileHandle] ; File handle
OS2Call DosClose ; Close it
Ret
ExitList: Call ExitRoutine ; Do exit routine
Push 3 ; Then continue exiting
Push 0
Push 0
OS2Call DosExitList
;---------------------
; Cursor Key Routines
;---------------------
Home: Sub BX,BX ; For zeroing out values
Mov AX,[FileOffset] ; Check if read in file
Or AX,[FileOffset + 2]
Mov [FileOffset],BX ; Zero out file address
Mov [FileOffset + 2],BX
Mov [HorizOffset],BX ; Zero out horizontal offset
Mov SI,Offset Buffer ; Reset buffer pointer
Jz Dummy ; Skip file read if in already
Mov DX,Offset Buffer ; Area to read file in
Mov CX,32768 ; Number of bytes to read
Call FileRead ; Read in file
Dummy: Ret
Up: Call GetPrevChar ; Get previous char in buffer
Jc UpDone ; If none available, finish
UpLoop: Call GetPrevChar ; Get previous char again
Jc UpDone ; if none, we're done
Cmp AL,10 ; Check if line feed
Jnz UpLoop ; If not, try again
Call GetNextChar ; Get char after line feed
UpDone: Ret
PgUp: Mov CX,Word Ptr [ModeData.row] ; Number of lines
Dec CX ; less title line
PgUpLoop: Call Up ; Do UP that many times
Loop PgUpLoop
Ret
Left: Mov [HorizOffset],0 ; Reset Horizontal Offset
Ret
Right: Mov AL,[ShiftHoriz] ; Get places to shift
Sub AH,AH
Add [HorizOffset],AX ; Move that many right
Ret
EndKey: Mov BX,SI ; Save buffer pointer
Call PgDn ; Go page down
Cmp BX,SI ; Check if we did so
Jnz EndKey ; If so, do it again
Ret
Down: Call GetNextChar ; Get next character
Jc NoMoreDown ; If no more, we're done
DownLoop: Call GetNextChar ; Get one again
Jc UpLoop ; If no more, find prev LF
Cmp AL,10 ; See if line feed
Jnz DownLoop ; If not, continue
NoMoreDown: Ret
PgDn: Mov CX,Word Ptr [ModeData.row] ; Number of lines
Dec CX ; less title line
PgDnLoop: Call Down ; Do DOWN that many times
Loop PgDnLoop
Ret
;---------------
; Update Screen
;---------------
UpdateScreen: Push ES
Les DI,[ScreenAddr] ; Address of display
Mov CX,ScreenSize ; Number of bytes in screen
Shr CX,1 ; Half for number of chars
Mov AL,' ' ; Will blank screen
Mov AH,[Attribute1] ; With screen attribute
Rep Stosw ; Blank it
Mov CX, [ModeData.col] ; Number of character cols
Mov DI, [ScreenOff] ; Offset of screen
Mov SI, Offset FullFileName ; File name
DisplayName: Lodsb ; Get character
Or AL, AL ; See if end
Jz EndOfName
Mov AH, [Attribute2] ; Use second attribute
Stosw ; Display it
Loop DisplayName
EndOfName: Mov SI,[ScreenStart] ; Address of data in buffer
Mov DL, 1 ; Start with second line
Mov AL, Byte Ptr [ModeData.col] ; Length of row
Sub AH,AH
Add AX,[HorizOffset] ; Add Horizontal Offset
Mov [RightMargin],AX ; That's right display margin
LineLoop: Sub BX,BX ; Column Number
Mov AL, Byte Ptr [ModeData.col] ; Use Line Length
Mul DL ; and Line Number
Add AX,AX ; to recalculate
Mov DI,AX ; display destination
Add DI,[ScreenOff] ; Add beginning address
CharLoop: Call GetNextChar ; Get next character
Jc EndOfScreen ; If no more, we're done
Cmp AL,13 ; Check for carriage return
Je CharLoop ; Do nothing if so
Cmp AL,10 ; Check for line feed
Je LineFeed ; Do routine if so
Cmp AL,9 ; Check for tab
Je Tab ; Do routine if so
Mov CX,1 ; Just 1 char to display
PrintChar: Cmp BX,[HorizOffset] ; See if we can print it
Jb NoPrint
Cmp BX,[RightMargin] ; See if within margin
Jae NoPrint
Mov AH,[Attribute1] ; Attribute for display
WriteIt: Stosw ; Write without retrace wait
NoPrint: Inc BX ; Bump up line counter
Loop PrintChar ; Do it CX times
Jmp CharLoop ; Then go back to top
Tab: Mov AX,BX ; Current column number
And AX,07h ; Take lower three bits
Mov CX,8
Sub CX,AX ; Subtract from 8
Mov AL,' ' ; Will print CX blanks
Jmp PrintChar
LineFeed: Inc DL ; Next line
Cmp DL,Byte Ptr [ModeData.row] ; See if down at bottom
Jb LineLoop ; If not, continue
EndOfScreen: Push 0 ; Offset of buffer
Push [ScreenSize] ; Size of buffer
Push 0 ; Reserved
OS2Call VioShowBuf ; Update the screen
Pop ES ; All done -- leave
Ret
;--------------------------------
; Get Next Character from buffer
;--------------------------------
; (Input is SI pointing to buffer, Returns AL, CY if no more)
GetNextChar: Cmp SI, [EndOfFile] ; See if at end of file
Jae NoMoreNext ; If so, no more chars
Cmp SI, Offset BufferEnd ; See if at end of buffer
Jb CanGetNext ; If not, just get character
Push CX ; Otherwise save registers
Push DX
Push DI
Push ES
Push DS ; Set ES to DS
Pop ES ; (could be different)
Mov SI,Offset BufferMid ; Move 2nd buffer half
Mov DI,Offset Buffer ; to 1st buffer half
Mov CX,16384
Sub [ScreenStart],CX ; New buffer pointer
Rep Movsb ; Move them
Mov SI,DI ; SI also buffer pointer
Add [FileOffset],32768 ; Adjust file addr to read
Adc [FileOffset + 2],0
Mov DX,Offset BufferMid ; Place to read file
Mov CX,16384 ; Number of bytes
Call FileRead ; Read the file
Sub [FileOffset],16384 ; Now adjust so reflects
Sbb [FileOffset + 2],0 ; 1st half of buffer
Pop ES ; Get back registers
Pop DI
Pop DX
Pop CX
Jmp GetNextChar ; And try again to get char
CanGetNext: Lodsb ; Get the character
And AL, 7Fh
Stc
NoMoreNext: Cmc ; So CY set if no more
Ret
;------------------------------------
; Get Previous Character from buffer
;------------------------------------
GetPrevChar: Cmp SI,Offset Buffer ; See if at top of buffer
Ja CanGetPrev ; If not, just get character
Mov AX,[FileOffset] ; See if at top of file
Or AX,[FileOffset + 2]
Jz AtTopAlready ; If so, can't get anymore
Push CX ; Save some registers
Push DX
Push ES
Push DS
Pop ES
Mov SI,Offset Buffer ; Move 1st half of buffer
Mov DI,Offset BufferMid ; to 2nd half of buffer
Mov CX, 16384
Add [ScreenStart], CX ; New buffer pointer
Rep Movsb ; Do the move
Sub [FileOffset], 16384 ; Adjust file addr for read
Sbb [FileOffset + 2], 0
Mov DX, Offset Buffer ; Area to read file into
Mov CX, 16384 ; Number of bytes
Call FileRead ; Read the file
Pop ES
Pop DX ; Get back registers
Pop CX
CanGetPrev: Dec SI ; Move pointer back
Mov AL,[SI] ; Get the character
And AL, 7Fh ; Wipe out high byte
Stc ; CY flag reset for success
AtTopAlready: Cmc ; CY flag set for no more
Ret
;--------------------------------------------
; Read CX bytes from the file into DX buffer
;--------------------------------------------
FileRead: Push AX ; Save some registers
Push BX
Mov [EndOfFile], -1 ; Initialize this
Push [FileHandle] ; File handle
Push [FileOffset + 2] ; New pointer (high)
Push [FileOffset] ; New pointer (low)
Push 0 ; Action
Push DS ; Segment for new pointer
Push Offset NewPointer ; Offset for new pointer
OS2Call DosChgFilePtr
Mov BX, [FileHandle] ; Read from the file
Call MyDosRead
Or AX, AX ; See if error
Mov AX, [BytesRead]
Jz NoReadError ; If no error, continue
Sub AX, AX ; Otherwise read zero bytes
NoReadError: Cmp AX,CX ; See if 32K has been read
Je GotItAll ; If so, we're home free
Add AX,DX ; Otherwise add to buffer addr
Mov [EndOfFile],AX ; And save as end of file
GotItAll: Pop BX
Pop AX
Ret
_TEXT ENDS
END Entry