Category : File Managers
Archive   : SEARCH22.ZIP
Filename : SEARCH2.ASM

 
Output of file : SEARCH2.ASM contained in archive : SEARCH22.ZIP
;
; * * * * * * * * * * * * * * * * * * *
; * Search2.Asm -- Text File Searcher *
; * By Joseph J. Tamburino *
; * Copyright (c) 1990 by *
; * Sourcecraft Publ. Corp. *
; * * * * * * * * * * * * * * * * * * *
;
; Revision History:

; Before 12/15/90: SEARCH1 created but never released.
; 12/16/90: SEARCH1 was changed to SEARCH2 to reflect
; the addition of read-ahead routines to speed
; up the I/O of floppy drives and cacheless hard drives
; 12/16/90: Two bugs were observed by Channel 1 staff. They were:
; 1) more than 5 or 6 files searched at one sitting
; crashed the program due to unnecessary
; re-allocating of memory buffers.
; 2) ANSI drivers such as VANSI.SYS interfered with
; the program due to their improper use of
; video pages.
; The program's name was changed from Super Search to
; Quick Search to protect a program by Tom Price
; 12/17/90: Input buffering, program exiting fixed (no CLS).

code segment
assume cs:code,ds:code
org 100h
main proc
jmp StartPro

WelcomeMsg db ' *** Quick Search ***',13,10,10,'$'
FileMsg db 13,10,10,'File to search (wildcards accepted): $'
SearchMsg db 'SEARCH.COM works by conducting an initial search on the first keyword you',13,10
db 'type and then successively narrowing down the search with the rest of the ',13,10
db 'words that were input. Separate keywords with spaces when entering them.',13,10,10
db 'Keywords to search: $'
MemMsg db 13,10,7,'SEARCH.COM needs more memory.',13,10,'$'
MemMsg2 db 13,10,7,'Look up table overflow -- too many matching words.',13,10,'$'
FileErMsg db 13,10,7,'File read error.',13,10,'$'
TitleMsg db 'SEARCH, by Joseph J. Tamburino. Copyright (c) 1990 by SourceCraft Publ. Corp.',0
HelpLineMsg db 'Esc-Exit PgUp/PgDn-Select Item ',24,'/',25,'-Scroll File',0
StatusLineMsg db 'Offset: '
FilePosHex db 'XXXXXXXXh'
db ' Item '
CitationNum db 'XXXXX'
db ' of '
CitationNumOf db 'XXXXX',0
FirstWordMsg db 'Searching ...',13,10,10
db 'Number of occurances of "$'
FirstWordMsg2 db '": 0$'
RestWordMsg db 'The remainder of the search words narrow total to: ?$'
NumToDisp db 'XXXXX.$'
WorkingOnMsg db 'Searching file: $'
NewFileMsg db 'Continue file search (y/n): $'
SearchCompleteMsg db 'Search complete.',13,10,'$'

; Variables & Equates:
CompletedOneFile db 0 ; Flags after 1 search complete
NoRealDisplay db 1 ; If 1, text sent to inactive page
WholeLine db 0 ; If 1, entire line gets highlighted
SubjectPos dw 0 ; Addr of "subject" (current) item in buffer
SubjectPos2 dw 0 ; Addr of "subject" item on screen
EOFflag db 0 ; If 1, file is at EOF marker
EOFflag2 db 0 ; Same, but for cache
x1 db 0 ; These coordinate
y1 db 0 ; variables are used for
x2 db 0 ; displaying the ongoing
y2 db 0 ; count during intial search.
YminSearch dw Ymin ; Screen pos to start search
YmaxSearch dw Ymax ; Screen pos to end search
YminDisplay equ 160*2
YmaxDisplay equ 160*24
Ymin equ 160*9
Ymax equ 160*15
SeekLo dw 0 ; Temp storage of file pointers:
SeekHi dw 0
Digits db '0123456789ABCDEF' ; For Display PROC
TableSize equ 60000 ; Size of table for found items
BufferLen dw 10000 ; Variable size of file buffer
Case db 0 ; 0=lower,1=upper search case
AfterBufferLen dw 128 ; Variable size of 2ndary file buffer
NormalBufferLen dw 0 ; Current size of file buffer
OldAX dw 0 ; Temporary AX storage
OldDI dw 0 ; Temporary DI storage
OldCX dw 0 ; Temporary CX storage
MaxSize db 255 ; 3-field structure for
RealSize db 0 ; reading FileSpec:
FileSpec db 255 dup(0)
CommandLine db 256 dup(0)
PathName db 128 dup(0) ; Single name derived from FileSpec
Path db 128 dup(0) ; Path from which all files reside
DTA db 30 dup(0) ; DTA for FindFirst,FindNext:
FileName db 13 dup(0) ; Name part of DTA
Zero db 0 ; For use by GetName,Search
Handle dw 0 ; Handle for current file
Found db 0 ; For use by SearchScreen
WordsFound db 0 ; For use by SearchScreen
ItemNo dw 0 ; Current # to display
MaxChars db 255 ; 3-field structure for
TextToSearchLen db 0 ; reading search string:
TextToSearch db 255 dup(0)
TextPos dw offset TextToSearch ; Next word to get
SearchString db 128 dup(0) ; Current word for SearchScreen
TableLocation dw 0 ; Segment of "found entries" table
TablePtr dw 0 ; Rel offset of last table entry
TotalCitations dw 0 ; # of citations found
LastTotal dw 0 ; To see if last file was fruitful
dw 256 dup(0) ; Our stack
Stack label word ; TOS (top of stack)
CRprefix db 12 dup (13) ; Files ALWAYS have 12 fake CR's
SearchBuffer db 10000 dup(0); Our 10000 (max) file buffer
AfterBuffer db 128 dup(0) ; And 128 extra for search overflow
CacheLocation dw 0 ; Segment of 64K cache
CacheSize dw 0 ; Current size of cache
CachePtrLo dw 0 ; File ptr at pos 0 of cache
CachePtrHi dw 0 ; Hi portion of this ptr

SetCursPos macro x,y,page
mov ah,2
mov bh,page
mov dh,y
mov dl,x
int 10h
endm

KP proc near
push ax
mov ax,40h
mov es,ax
mov al,es:[62h]
xor ah,ah
mov si,ax
mov cl,12
shl si,cl
xor di,di
mov cx,800h
mov ax,0b800h
mov es,ax
mov ds,ax
cld
rep movsw
mov ax,0500h
int 10h
SetCursPos 0,7,0
pop ax
add ax,4c00h
int 21h
KP endp

KillProcess macro ExitCode
mov ax,ExitCode
jmp KP
endm

SO proc near
push es
push ax
mov ax,40h
mov es,ax
mov bh,es:[62h]
pop ax
pop es
mov ah,0eh
int 10h
ret
SO endp

SOBS proc near
cmp al,8
jz TTYBS
call SO
ret
TTYBS: call SO
mov al,' '
call SO
mov al,8
call SO
ret
SOBS endp

StdOut macro ASCIIchar ; character outputter (DOS)
mov al,ASCIIchar
call SOBS
endm

STO proc near
NextSTO: mov bx,dx
mov al,[bx]
cmp al,'$'
jz DoneStSTO
call SO
inc dx
jmp short NextSTO
DoneStSTO: ret
STO endp

StringOut macro ASCII$String
lea dx,ASCII$String
call STO
endm

CrLf proc near
StdOut 13
StdOut 10
ret
CrLf endp

BuffInp proc near
; Emulates DOS's buffered input
push di
mov di,dx
xor bx,bx
GetChar16: mov ah,0
int 16h
cmp al,13
jz CRdetect
cmp al,8
jz BSdetect
mov [di+bx+2],al
inc bx
cmp bx,[di]
jae TooMuchStuff
push bx
StdOut al
pop bx
jmp short GetChar16
CRdetect: mov [di+1],bl
pop di
ret
BSdetect: or bx,bx
jz GetChar16
dec bx
push bx
StdOut al
pop bx
jmp short GetChar16
TooMuchStuff: push bx
StdOut 7
pop bx
jmp short GetChar16
BuffInp endp

BufferedInp macro InpBuffer
lea dx,InpBuffer
call BuffInp
endm

DisplayNum macro N,Base,NumSpaces,LeadingZeros,Buffer
mov ax,n
push ax
mov ax,Base
push ax
mov ax,NumSpaces
push ax
mov ax,LeadingZeros
push ax
push cs
lea ax,Buffer
push ax
call Display
endm

SetFilePointer macro Method,lsb,msb
mov ax,4200h+Method
mov bx,Handle
mov cx,msb
mov dx,lsb
int 21h
endm

InitCache proc near
; Initialize the cache used while reading file.
mov EOFflag2,0
cmp CacheLocation,0
jnz AlreadyAllocated
mov ah,48h
mov bx,4096
int 21h
jnc SuccessCache
StringOut MemMsg
KillProcess 1
SuccessCache: mov CacheLocation,ax
AlreadyAllocated: mov ah,3fh
mov bx,Handle
mov cx,0ffffh
xor dx,dx
push ds
mov ds,CacheLocation
int 21h
pop ds
mov CacheSize,ax
SetFilePointer 0,0,0
ret
InitCache endp

ReadFromCache proc near
; Read from the psuedocache. The calling sequence is the same as DOS's
; function #3fh.
push cx
push dx
SetFilePointer 1,0,0
mov si,dx
mov di,ax
cmp CachePtrHi,dx
ja NoGood
jc IsGood
cmp CachePtrLo,ax
ja NoGood
IsGood: sub ax,CachePtrLo
mov cx,ax
sbb dx,CachePtrHi
jnz NoGood
pop dx
pop bx
push bx
push dx
mov ax,CacheSize
sub ax,cx
cmp bx,ax
jbe BufferInCache
cmp EOFflag2,1
jnz NoGood
jmp DoEOF2
BufferInCache: add sp,4
push si
push di
mov si,cx
mov di,dx
cld
mov cx,bx
mov ax,ds
mov es,ax
push ds
mov ds,CacheLocation
rep movsb
pop ds
pop di
pop si
push bx
add di,bx
adc si,0
SetFilePointer 0,di,si
pop ax
clc
ret
NoGood: pop dx
pop cx
mov ah,3fh
mov bx,Handle
int 21h
push ax
SetFilePointer 1,0,0
mov si,dx
mov di,ax
SetFilePointer 1,0b1e0h,0ffffh
cmp dx,0ffffh
jnz NotNegRead
SetFilePointer 0,0,0
NotNegRead: mov CachePtrHi,dx
mov CachePtrLo,ax
mov ah,3fh
mov bx,Handle
mov cx,0ffffh
xor dx,dx
mov EOFflag2,0
push ds
mov ds,CacheLocation
int 21h
pop ds
mov CacheSize,ax
cmp ax,0ffffh
jz NotAtEOF2
mov EOFflag2,1
NotAtEOF2: SetFilePointer 0,di,si
pop ax
clc
ret
DoEOF2: mov bx,ax
jmp BufferInCache
ReadFromCache endp

DOSread macro BytesToRead,OffsetBuf
mov cx,BytesToRead
lea dx,OffsetBuf
call ReadFromCache
endm

InitName proc near
; Initializes the filename in FileSpec so that successive calls to GetName
; return pathnames related to FileSpec in the PathName variable.

; First, isolate the Path so that it can later be appended by GetName:
mov ax,cs
mov es,ax
mov cl,RealSize
xor ch,ch
lea di,FileSpec
add di,cx
std
mov al,'\'
inc cx
repne scasb
jz PathFound
cmp RealSize,2
jae CheckDrive
NoPathOrDrive: mov Path,0 ; No path or drive
jmp short BeginInit
CheckDrive: cmp FileSpec[1],':'
jnz NoPathOrDrive
mov Path,2
mov al,FileSpec
mov Path[1],al
mov Path[2],':'
jmp short BeginInit
PathFound: lea ax,FileSpec
sub ax,2
sub di,ax
mov cx,di
mov Path,cl
lea si,FileSpec
lea di,Path[1]
cld
rep movsb

; Now, call DOS FindFirst
BeginInit: mov ah,1ah
lea dx,DTA
int 21h
mov ah,4eh
mov cx,0
lea dx,FileSpec
mov bl,RealSize
xor bh,bh
mov FileSpec[bx],0
int 21h
jc NoMoreFoundF
ret
NoMoreFoundF: mov Zero,1
ret
InitName endp

GetName proc near
; Returns a PathName from FileSpec. Returns a PathName of zero-length
; if there are no more left.
cmp Zero,1
jnz NotZero
mov PathName,0
ret
NotZero: mov cl,Path
xor ch,ch
lea di,PathName
or cl,cl
jz NoPathToAppend
lea si,Path[1]
cld
rep movsb
NoPathToAppend: xor si,si
AppendLoop: cmp FileName[si],0
jz DoneAppending
mov al,FileName[si]
mov [di],al
inc di
inc si
jmp short AppendLoop
DoneAppending: mov [di],byte ptr 0
mov ah,4fh
int 21h
jc NoMoreFound
ret
NoMoreFound: mov Zero,1
ret
GetName endp

OpenFile proc near
; Opens file pointed to by PathName. (if a file is already open, close it 1st)
cmp Handle,0
jz DoNotClose
mov ah,3eh
mov bx,Handle
int 21h
DoNotClose: mov ah,3dh
mov al,2
lea dx,PathName
int 21h
mov Handle,ax
ret
OpenFile endp

ReadFile proc near
; Reads file into SearchBuffer & AfterBuffer (in that order).
; SearchBuffer's presence is for text that overflows the search buffer.
mov ax,cs
mov es,ax
cld
lea si,AfterBuffer
lea di,SearchBuffer
mov cx,64
rep movsw
mov ax,AfterBufferLen
mov NormalBufferLen,ax
cmp AfterBufferLen,128
pushf
mov AfterBufferLen,0
popf
jb SkipReadFile
DOSread 10000-128,SearchBuffer[128]
push ax
DOSread 128,AfterBuffer
mov AfterBufferLen,ax
pop ax
pushf
add ax,128
mov NormalBufferLen,ax
popf
ExitReadFile: ret
SkipReadFile: clc
jmp short ExitReadFile
ReadFile endp

InitAfterBuffer proc near
; Puts the first 128 bytes of the current handle "after" the search buffer
; so that ReadFile has something to transfer into SearchBuffer before reading
; the rest of the file. An "AfterBuffer" is used for search text which
; jumps over the bottom edge of the buffer.
DOSread 128,AfterBuffer
mov AfterBufferLen,ax
ret
InitAfterBuffer endp

ToLower proc near
; Converts AL to lower case
cmp al,'A'
jb NonApp
cmp al,'Z'
ja NonApp
add al,'z'-'Z'
NonApp: ret
ToLower endp

ToUpper proc near
; Converts AL to upper case
cmp al,'z'
ja NonApp2
cmp al,'a'
jb NonApp2
sub al,'z'-'Z'
NonApp2: ret
ToUpper endp

Search proc near
; Searches file for text in TextToSearch. Builds a table of file pointers
; for each occurence of the text. All entries are searched first using
; an initial lowercase letter, then uppercase. In other words, the buffer
; is searched twice. It may seem slower, but this method allows use of
; REPNE SCASB so is really faster.
mov Case,0
mov BufferLen,10000
call InitAfterBuffer
jnc FileOk
jmp ReadError
FileOk: call ReadFile
jnc FileOk2
jmp ReadError
FileOk2: mov cx,NormalBufferLen
or cx,cx
jnz NonZeroBuffer
jmp ExitSearch

; Start of actual search:
NonZeroBuffer: mov ax,cs
mov es,ax
lea di,SearchBuffer
mov al,TextToSearch
call ToLower
cld
StartSearch: repne scasb
jz CharFound
jmp short TryNextCase

; Compare rest of characters (REPNE SCASB only searched first character)
CharFound: mov bx,1
mov OldDI,di
mov OldAX,ax
mov OldCX,cx
LoopCompare: mov al,TextToSearch[bx]
cmp al,' '
jz FoundText
call ToLower
mov cl,al
mov al,[di]
call ToLower
cmp cl,al
jnz StartNewSearch
inc di
inc bx
jmp short LoopCompare

; Search more of the buffer
StartNewSearch: mov di,OldDI
mov ax,OldAX
mov cx,OldCX
jmp short StartSearch

; Start again at buffer start, but use uppercase, or read more if done.
TryNextCase: inc Case
cmp Case,2
jnz NextCase
jmp NextBuffer
NextCase: mov cx,NormalBufferLen
lea di,SearchBuffer
mov al,TextToSearch
call ToUpper
jmp StartSearch

; Text has been found; add file offset to table of entries.
FoundText: SetFilePointer 1,0,0
mov bx,dx
mov cx,OldDI
sub cx,offset SearchBuffer
mov dx,NormalBufferLen
sub dx,cx
inc dx
add dx,AfterBufferLen
sub ax,dx
sbb bx,0
push es
mov si,TablePtr
mov es,TableLocation
mov es:[si],ax
mov es:[si+2],bx
inc TotalCitations
add TablePtr,4
cmp TablePtr,TableSize
jae MemOverflow

; Update screen so as to reveal that a new item is found.
DisplayNum TotalCitations,10,5,0,NumToDisp
SetCursPos x1,y1,1
StringOut NumToDisp
pop es
mov ax,OldAX
mov di,OldDI
mov cx,OldCX
jmp StartSearch

; This buffer has been totally searched; resume search on a new buffer.
NextBuffer: mov Case,0
jmp FileOk
ExitSearch: ret

; Too many entries have been found (>14999) so report this and quit.
MemOverflow: StringOut MemMsg2
DoErr: KillProcess 1

; There seems to be a problem reading the file. Report & quit.
ReadError: lea dx,FileErMsg
jmp short DoErr
Search endp


DispName proc near
; Display the current file being worked on. To show it off, display in yellow.
mov ax,0920h
mov bx,010eh
mov cx,79
int 10h
StdOut 13
StringOut WorkingOnMsg
cmp PathName,0
jz DoneDisp
xor di,di
DispLoop: cmp PathName[di],0
jz DoneString
StdOut PathName[di]
inc di
jmp short DispLoop
DoneString: call CrLf
DoneDisp: ret
DispName endp

DoText proc near
; Plots text at the specified x,y location with the specified attribute.
; Uses conventional stack-type parameter passing.
x equ byte ptr [bp+10]
y equ byte ptr [bp+8]
Attrib equ byte ptr [bp+6]
TextBuf equ word ptr [bp+4]
push bp
mov bp,sp
mov al,160
mul y
mov bl,x
xor bh,bh
shl bx,1
add ax,bx
mov di,ax
mov ah,Attrib
mov si,TextBuf
LoopDisp: lodsb
cmp al,0
jz DoneDoText
stosw
jmp short LoopDisp
DoneDoText: pop bp
ret 8
DoText endp

InfoBar macro y,Attrib
; Make a solid bar across the screen at the specified y position and Attribute
mov ax,y
mov bx,160
mul bx
mov di,ax
mov cx,80
mov ah,Attrib
xor al,al
rep stosw
endm

ColorText Macro x,y,Attrib,Loc
; Display a string of text residing at Loc using (x,y) coordinates and Attrib.
mov ax,x
push ax
mov ax,y
push ax
mov ax,Attrib
push ax
lea ax,Loc
push ax
call DoText
endm

MakeScreen proc near
; Draw the main program screen
mov ax,0b800h
mov es,ax
xor di,di
mov ax,1000h
mov cx,2048
rep stosw ; Color screen blue
InfoBar 0,70h
InfoBar 24,70h
ColorText 1,0,70h,TitleMsg
ColorText 12,24,70h,HelpLineMsg
ret
MakeScreen endp

ExtractWord proc near
; Using TextPos, extract the next word from TextToSearch and put it into
; SearchString using Pascal string notation. Returns AX=1 if no more text.
mov si,TextPos
cmp [si],byte ptr 0
jz NoMoreLeft
lea di,SearchString[1]
mov ax,cs
mov es,ax
mov cl,0
cld
DoExtract: lodsb
cmp al,' '
jz DoneExtract
inc cl
stosb
jmp short DoExtract
DoneExtract: mov SearchString,cl
mov TextPos,si
xor ax,ax
ret
NoMoreLeft: mov ax,1
ret
ExtractWord endp

DoWordSearch proc near
; Performs the search required by SearchScreen.
; SI has already been pointed to the start of next character to search.
; SI will return with pointer to word on screen.
; AX is zero upon return if found, or 1 if not found.
mov ax,0b800h ; Segment of mode 3
mov es,ax ; Point to screen
NextTry: mov ax,es:[si] ; AX < - - Char,Attrib
add si,2 ; Advance to next char
call ToLower ; Convert case, if needed
mov ah,al
mov al,SearchString[1]
call ToLower
cmp al,ah ; Do 1st characters match?
jz FirstCharMatch; Then go compare the rest
cmp si,YmaxSearch; At last line?
jae ExitSearchScr; Then leave with AX=1
jmp short NextTry; Or else, look at next char
FirstCharMatch: mov cl,SearchString; Get string length
xor ch,ch
cmp cl,1 ; If 1, we are done
jz SingleChar
dec cx ; Otherwise do remaining chars
mov di,si ; Save original SI
mov bx,offset SearchString+2
SearchScrLoop: mov al,[bx] ; AL < - - next inputted char
call ToLower
mov dl,al
mov al,es:[si] ; AL < - - next screen char
call ToLower ; Convert case of AL if needed
cmp dl,al ; Are the characters equal?
jnz TryAgain ; If not equal, restart search
inc bx ; Advance search string index
add si,2 ; Advance screen index
loop SearchScrLoop; Compare every character
xor ax,ax ; Found! Clear AX
mov si,di ; Set SI to first character:
SingleChar: sub si,2
ret
ExitSearchScr: mov ax,1 ; No match found
ret
TryAgain: mov si,di ; Reset SI & restart
jmp NextTry
DoWordSearch endp

SearchScreen proc near
; Searches the text screen for any of the found text and highlights it.
; The area of the screen to search is marked by YminSearch & YmaxSearch
mov TextPos,offset TextToSearch
mov WordsFound,1
mov Found,1
SearchWord: cmp Found,1
jz WordsWereFound
mov WordsFound,0
WordsWereFound: mov Found,0
call ExtractWord ; Extract word from list
cmp ax,1 ; If 1 then no words are left
jz DoneWordSearch; So exit routine
mov si,YminSearch; Start at third line
AnotherOccurance: call DoWordSearch; Search for word occurance
cmp ax,1 ; If 1, word was not found
jz NextWordSearch; So go on to next word
mov Found,1
mov cl,SearchString; Otherwise highlight it:
xor ch,ch ; CX < - - String length
LoopAlterText: mov es:[si+1],byte ptr 70h ; Black on White
add si,2 ; Next character
loop LoopAlterText; Highlight entire word
jmp short AnotherOccurance; Find another occurance
NextWordSearch: jmp short SearchWord; Extract new search term
DoneWordSearch: ret
SearchScreen endp

Display proc near
; Format: Display(Number: word; Base,Spaces: byte; PrefixWithZeros: boolean; Storage: pointer);
;
; Displays a number of the base specified (can be no larger than the number
; of digits in the Digits variable). All output is sent to the STORAGE buffer.
; Spaces is the number of spaces to use to print the number. Use 0 if the
; number of spaces should be equal to the number of characters.
; Right justification is always used. Set PrefixWithZeros to TRUE (1) to
; use character "0" to pad extra blank spaces. Otherwise the space character
; will be used.

Storage equ [bp+4]
PrefixWithZeros equ byte ptr [bp+8]
Spaces equ byte ptr [bp+10]
Base equ word ptr [bp+12]
Number equ word ptr [bp+14]

push bp
mov bp,sp
push es
push ds
pop es

lea bx,Base
mov ss:[bx+1],byte ptr 0
mov cx,0
mov bx,Number
mov di,(offset AfterBuffer)+15
std
DoDigit: mov ax,bx
xor dx,dx
div Base
mov bx,ax
or dx,dx
jnz StillMore
or ax,ax
jz NoMore
StillMore: mov si,dx
mov al,Digits[si]
inc cx
stosb
jmp short DoDigit

NoMore: cmp di,(offset AfterBuffer)+15
jnz NonZero
mov al,'0'
inc cx
stosb
NonZero: mov si,di
sub Spaces,cl
cmp Spaces,0
jg RoomLeft
inc si
jmp short DisplayIt
RoomLeft: cmp PrefixWithZeros,1
jz Use0
mov al,' '
jmp short UsedSpace
Use0: mov al,'0'
UsedSpace: mov [si],al
inc cx
dec si
dec Spaces
jnz UsedSpace
inc si

DisplayIt: cld
les di,Storage
rep movsb

pop es
pop bp
ret 12
Display endp


DisplayStatus proc near
; Displays information about the current file offset and citation.
DisplayNum SeekHi,16,4,1,FilePosHex
DisplayNum SeekLo,16,4,1,FilePosHex[4]
DisplayNum ItemNo,10,5,1,CitationNum
DisplayNum TotalCitations,10,5,1,CitationNumOf
mov ax,0b800h
mov es,ax
ColorText 4,1,17h,StatusLineMsg
ColorText 47,1,17h,PathName
ret
DisplayStatus endp

DisplayFile proc near
; Positions the found text approximatly in the middle of the screen
; and displays it along with the rest of the file.
; The position of the text is at SeekLo / SeekHi
; After display, call SearchScreen to highlight all search words. Then
; find and place file marker (either a box or a line).
; If output is to a non-displayed screen page (NoRealDisplay=1), skip
; unnecessary output to improve speed.
cmp NoRealDisplay,1
jz SkipDisplayStatus
call DisplayStatus

; Clear screen buffer with 1ah (EOF marker). Note: uses SearchBuffer
; which is not required by Search at this time.
SkipDisplayStatus: mov EOFflag,0
mov ax,cs
mov es,ax
lea di,SearchBuffer
cld
mov ax,1a1ah
mov cx,3000
rep stosw

; Read the file. File must be read 1000 bytes BEFORE highlighted item so
; as to try to get it in the middle. If highlighted item is<1000 bytes
; into file, read from BOF. SubjectPos is set to contain the offset
; of the highlighted item.
mov si,SeekLo
mov dx,SeekLo
mov cx,SeekHi
mov SeekLo,1000
sub dx,1000
sbb cx,0
mov SubjectPos,1000
cmp cx,0ffffh
jnz NotNegative
neg dx
sub SeekLo,dx
mov SubjectPos,si
mov dx,0
mov cx,0
NotNegative: add SubjectPos,offset SearchBuffer
SetFilePointer 0,dx,cx
DOSread 6000,SearchBuffer

; Search back an appropriate # of CRLF sequences (12) to start display
mov di,0 ; Count
mov bx,SeekLo
lea si,SearchBuffer[bx]
std
CountCRs: lodsb
cmp al,13
jz FoundCR
cmp si,(offset CRprefix-1)
ja CountCRs
jmp short StartDisplay
FoundCR: inc di
cmp di,10
jb CountCRs

; Start transferring text to the screen:
StartDisplay: mov dl,2 ; Line position
cld
lodsb ; Bypass 1st 2 bytes
lodsb
mov ax,cs
mov es,ax
StartNewLine: lea di,AfterBuffer
mov cx,40
mov ax,2020h
rep stosw
mov al,0
stosb
mov dh,0 ; Chars in line
lea di,AfterBuffer

; If "real" display, see if buffer pointer=SubjectPos. If so, calculate
; the position into the display at which the text will be storage and
; keep it in SubjectPos2 for use later to highlight this item.
ReadNext: cmp NoRealDisplay,1
jz NotSubjectPos
cmp si,SubjectPos
ja NotSubjectPos
mov al,160
mul dl
push dx
shl dh,1
add al,dh
adc ah,0
pop dx
mov SubjectPos2,ax

; This, finally, is the section that does the buffer-to-screen transfer.
; Each line is accumulated in AfterBuffer (not needed by Search now) and
; sent out all at once by ColorText. Conveniently, AfterBuffer already
; contains a ColorText-ready string of spaces so we only need to fill
; as much text that there is and yet wipe out the whole line at once.
NotSubjectPos: lodsb
cmp al,26
jnz NotEOF
mov al,' '
mov EOFflag,1
NotEOF: cmp al,10
jz ReadNext
cmp al,13
jz DoneLine
stosb
inc dh
cmp dh,79
jz DoneLine
jmp short ReadNext
DoneLine: push dx
push es
mov ax,0b800h
mov es,ax
push si
ColorText 0,dx,1eh,AfterBuffer

pop si
pop es
pop dx
inc dl
cmp dl,24
jz DoneAllLines
jmp StartNewLine

; If necessary, highlight the current text item. If in PgUp,PgDn mode,
; a single cell will do. If in up/dn arrow mode, highlight a line.
DoneAllLines: call SearchScreen
cmp NoRealDisplay,1
jz QuitDispF
mov bx,SubjectPos2
cmp WholeLine,1
jz HighLightLine
mov es:[bx+1],byte ptr 07h
ret
HighLightLine: mov ax,bx
xor dx,dx
mov bx,160
div bx
mul bx
mov di,ax
mov ah,0fh
mov cx,80
LoopHighlight: mov al,es:[di]
stosw
loop LoopHighlight
mov WholeLine,0
QuitDispF: ret
DisplayFile endp



FindAllKeywords proc near
; By now, Search has created a table of found entries. Now, "display"
; each occurance in page 0 which is inactive and use SearchScreen to
; find screens that contain all search words "near" the first search word.
call ExtractWord
or ax,ax
jnz LeaveFA
call ExtractWord
or ax,ax
jnz LeaveFA
mov bx,-4
FindThem: add bx,4
cmp bx,TablePtr
jae LeaveFA
mov es,TableLocation
mov ax,es:[bx]
mov SeekLo,ax
mov ax,es:[bx+2]
mov SeekHi,ax
push bx
call DisplayFile
pop bx
mov es,TableLocation
cmp WordsFound,1
jz FindThem
dec TotalCitations
mov es:[bx],word ptr 0ffffh
mov es:[bx+2],word ptr 0ffffh
push bx
DisplayNum TotalCitations,10,5,0,NumToDisp
SetCursPos x2,y2,1
StringOut NumToDisp
pop bx
jmp short FindThem
LeaveFA: ret
FindAllKeywords endp

IsBXempty proc near
; See if the table-entry pointed to be BX is empty (invalid) or not.
mov ax,1
cmp es:[bx],word ptr 0ffffh
jnz IsNotEmpty
cmp es:[bx+2],word ptr 0ffffh
jnz IsNotEmpty
ret
IsNotEmpty: xor ax,ax
ret
IsBXempty endp

FindNextDown proc near
; Traverse the table downwards to find the next available address.
mov dx,bx
FindNextDn: mov es,TableLocation
add bx,4
cmp bx,TablePtr
jae ReachedLimitDn
call IsBXempty
or ax,ax
jz BingoDn
jmp short FindNextDn
BingoDn: inc ItemNo
ret
ReachedLimitDn: mov bx,dx
ret
FindNextDown endp

FindNextUp proc near
; Traverse the table upwards to find the next available address.
mov dx,bx
FindNextU: mov es,TableLocation
sub bx,4
cmp bx,0
jl ReachedLimitUp
call IsBXempty
or ax,ax
jz BingoUp
jmp short FindNextU
BingoUp: dec ItemNo
ret
ReachedLimitUp: mov bx,dx
ret
FindNextUp endp

PromptUser proc near
; At least one file may have been fruitful. See if user still wants
; to search the rest of the files. (Will never be called if user hasn't
; supplied wildcards).
cmp LastTotal,0
jz Yes
SetCursPos 0,14h,1
cmp CompletedOneFile,0
jz Yes
StringOut NewFileMsg
GetKeyAgain: mov ax,0
int 16h
call ToLower
cmp al,'y'
jz Yes
cmp al,'n'
jz No
jmp GetKeyAgain
Yes: mov CompletedOneFile,1
StdOut 13
mov ax,0920h
mov bx,0107h
mov cx,79
int 10h
mov ax,1
ret
No: mov ax,3
int 10h
mov ax,0
ret
PromptUser endp

ShowStatusScreen proc near
; Display text for screen that will display an ongoing count of citations
; as they are found and then later narrowed. Store the (x,y) position
; of the endings of two strings which will be where the counts are displayed.
StringOut FirstWordMsg
lea si,TextToSearch
cld
DispFirstWord: lodsb
cmp al,' '
jz DoneLoopFirstW
StdOut al
jmp short DispFirstWord
DoneLoopFirstW: StringOut FirstWordMsg2
mov ah,3
mov bh,1
int 10h
dec dl
mov x1,dl
mov y1,dh
call CrLf
StringOut RestWordMsg
mov ah,3
mov bh,1
int 10h
dec dl
mov x2,dl
mov y2,dh
call CrLf
call CrLf
ret
ShowStatusScreen endp

DoSearch proc near
; This is the main entry point of the program. This procedure is responsible
; for displaying initial status info, searching & building the table, then
; narrowing down the search, displaying any matching screens, and getting
; directions from the user as to PgUp, PgDn, Up, Dn, and Esc keypresses.

; First, initialize some variables:
mov YminSearch,Ymin
mov YmaxSearch,Ymax
mov TextPos,offset TextToSearch
mov ax,TotalCitations
mov LastTotal,ax
mov TotalCitations,0
mov TablePtr,0

; Put up screen status sentences and get the first file:
call ShowStatusScreen
call GetName
cmp PathName,0
jnz FileExists
jmp QuitProg2

; Display current filename in yellow. Prompt user to continue if necessary:
FileExists: call DispName
call PromptUser
or ax,ax
jnz DoO_F
ret

; Open and search the file for the first word, then narrow down the count
; by searching the rest of the string. Finally, flip to page 0 so we
; can show are finds to the user:
DoO_F: call OpenFile
call InitCache
call Search
mov NoRealDisplay,1
call FindAllKeywords
mov NoRealDisplay,0
mov ax,0500h
int 10h
mov YminSearch,YminDisplay
mov YmaxSearch,YmaxDisplay
mov ItemNo,0
cmp TotalCitations,0
ja AtLeastOneFound
jmp QuitProg

; Make the main screen, start at the first entry, then display the entry:
AtLeastOneFound: call MakeScreen
mov bx,-4
call FindNextDown
ShowEverything: mov es,TableLocation
mov ax,es:[bx]
mov SeekLo,ax
mov ax,es:[bx+2]
mov SeekHi,ax
ShowFile: push bx
push SeekLo
call DisplayFile
pop SeekLo

; Get and operate on the user's keypress:
GetKey: xor ah,ah
int 16h
pop bx
cmp al,27
jz QuitProg
cmp ax,4900h
jz PgUp
cmp ax,5100h
jz PgDn
cmp ax,4800h
jz Up
cmp ax,5000h
jz Down
push bx
jmp short GetKey
QuitProg: mov ax,3
int 10h
mov ax,0501h
int 10h
jmp DoSearch
QuitProg2: mov ax,3
int 10h
ret
PgUp: call FindNextUp
jmp ShowEverything
PgDn: call FindNextDown
jmp ShowEverything
Up: mov WholeLine,1
sub SeekLo,80
sbb SeekHi,0
cmp SeekHi,0ffffh
jz InitToZero
jmp ShowFile
Down: mov WholeLine,1
cmp EOFflag,1
jnz NoEOFyet
jmp ShowFile
NoEOFyet: add SeekLo,80
adc SeekHi,0
jmp ShowFile
InitToZero: mov SeekLo,0
mov SeekHi,0
jmp ShowFile
DoSearch endp

ExtractCommand proc near
; Extract the next portion of the command line into CommandLine.
; If AX=1, extract the entire rest of the line.
mov di,ax
mov bx,cs
mov es,bx
mov bx,80h
cmp es:[bx],byte ptr 0
jz EmptyLine
SkipThisChar: inc bx
cmp es:[bx],byte ptr ' '
jz SkipThisChar
mov si,1
LoadCommandLine: mov al,es:[bx]
cmp al,13
jz CommandEOL
cmp di,1
jz SkipTestForSpace
cmp al,' '
jz CommandEOL
SkipTestForSpace: mov CommandLine[si],al
mov es:[bx],byte ptr ' '
inc si
inc bx
jmp short LoadCommandLine
EmptyLine: mov CommandLine,0
ret
CommandEOL: mov ax,si
dec al
mov CommandLine,al
ret
ExtractCommand endp

GetCommand proc near
; Gets command from either command line or keyboard depending of
; whether or not there is a command present in the command line.
; Input: AX=1 if the whole rest of the line should be used as a command.
; DS:DI = address of buffer to store command
; DS:SI = address of message to display if there is no command in the
; command line
push si
push di
call ExtractCommand
pop di
pop si
cmp CommandLine,0
jz AskForInfo
mov cl,CommandLine
lea si,CommandLine
xor ch,ch
inc cl
cld
mov ax,ds
mov es,ax
rep movsb
ret
AskForInfo: StringOut [si]
BufferedInp [di-1]
cmp [di],byte ptr 0
jz OkQuit
ret
OkQuit: KillProcess 0
GetCommand endp

; ***********************************************************************
; ** SEARCH entry point **
; ***********************************************************************

StartPro: lea sp,Stack ; Use our own stack
mov ah,4ah
mov bx,400h
int 21h ; Reserve 16K for code & data
mov ah,48h
mov bx,TableSize/16
int 21h ; Allocate 60K bytes for table
jc NotEnoughMem
mov TableLocation,ax
mov ax,3
int 10h
mov ax,0501h
int 10h ; Do all output on page 1
StringOut WelcomeMsg ; Display welcome message
lea si,FileMsg
lea di,MaxSize[1]
xor ax,ax
call GetCommand ; get command from keyb or PSP
call CrLf
call CrLf
lea si,SearchMsg
lea di,MaxChars[1]
mov ax,1
call GetCommand ; get command from keyb or PSP
call CrLf
mov bl,TextToSearchLen
xor bh,bh
mov TextToSearch[bx],word ptr ' '
call InitName ; Initialize the filespec
call DoSearch ; Call main routine
StringOut SearchCompleteMsg

ExitCOM: KillProcess 0

NotEnoughMem: StringOut MemMsg
jmp short ExitCOM

Main endp
Code ends
end Main


  3 Responses to “Category : File Managers
Archive   : SEARCH22.ZIP
Filename : SEARCH2.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/