179 lines
7.7 KiB
Markdown
179 lines
7.7 KiB
Markdown
------------------------ --------------------------------- --------------------
|
||
[Previous](05-02.html) [Table of Contents](index.html) [Next](05-04.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
**LISTING 5.1 SEARCH.C**
|
||
|
||
/* Program to search the file specified by the first command-line
|
||
* argument for the string specified by the second command-line
|
||
* argument. Performs the search by reading and searching blocks
|
||
* of size BLOCK_SIZE. */
|
||
|
||
#include <stdio.h>
|
||
#include <fcntl.h>
|
||
#include <string.h>
|
||
#include <alloc.h> /* alloc.h for Borland compilers,
|
||
malloc.h for Microsoft compilers */
|
||
|
||
#define BLOCK_SIZE 0x4000 /* we’ll process the file in 16K blocks */
|
||
|
||
/* Searches the specified number of sequences in the specified
|
||
buffer for matches to SearchString of SearchStringLength. Note
|
||
that the calling code should already have shortened SearchLength
|
||
if necessary to compensate for the distance from the end of the
|
||
buffer to the last possible start of a matching sequence in the
|
||
buffer.
|
||
*/
|
||
|
||
int SearchForString(unsigned char *Buffer, int SearchLength,
|
||
unsigned char *SearchString, int SearchStringLength)
|
||
{
|
||
unsigned char *PotentialMatch;
|
||
|
||
/* Search so long as there are potential-match locations
|
||
remaining */
|
||
while ( SearchLength ) {
|
||
/* See if the first character of SearchString can be found */
|
||
if ( (PotentialMatch =
|
||
memchr(Buffer, *SearchString, SearchLength)) == NULL ) {
|
||
break; /* No matches in this buffer */
|
||
}
|
||
/* The first character matches; see if the rest of the string
|
||
also matches */
|
||
if ( SearchStringLength == 1 ) {
|
||
return(1); /* That one matching character was the whole
|
||
search string, so we’ve got a match */
|
||
}
|
||
else {
|
||
/* Check whether the remaining characters match */
|
||
if ( !memcmp(PotentialMatch + 1, SearchString + 1,
|
||
SearchStringLength - 1) ) {
|
||
return(1); /* We’ve got a match */
|
||
}
|
||
}
|
||
/* The string doesn’t match; keep going by pointing past the
|
||
potential match location we just rejected */
|
||
SearchLength -= PotentialMatch - Buffer + 1;
|
||
Buffer = PotentialMatch + 1;
|
||
}
|
||
|
||
return(0); /* No match found */
|
||
}
|
||
|
||
main(int argc, char *argv[]) {
|
||
int Done; /* Indicates whether search is done */
|
||
int Handle; /* Handle of file being searched */
|
||
int WorkingLength; /* Length of current block */
|
||
int SearchStringLength; /* Length of string to search for */
|
||
int BlockSearchLength; /* Length to search in current block */
|
||
int Found; /* Indicates final search completion
|
||
status */
|
||
int NextLoadCount; /* # of bytes to read into next block,
|
||
accounting for bytes copied from the
|
||
last block */
|
||
unsigned char *WorkingBlock; /* Block storage buffer */
|
||
unsigned char *SearchString; /* Pointer to the string to search for */
|
||
unsigned char *NextLoadPtr; /* Offset at which to start loading
|
||
the next block, accounting for
|
||
bytes copied from the last block */
|
||
|
||
/* Check for the proper number of arguments */
|
||
if ( argc != 3 ) {
|
||
printf(“usage: search filename search-string\n”);
|
||
exit(1);
|
||
}
|
||
|
||
/* Try to open the file to be searched */
|
||
if ( (Handle = open(argv[1], O_RDONLY | O_BINARY)) == -1 ) {
|
||
printf(“Can’t open file: %s\n”, argv[1]);
|
||
exit(1);
|
||
}
|
||
/* Calculate the length of text to search for */
|
||
SearchString = argv[2];
|
||
SearchStringLength = strlen(SearchString);
|
||
/* Try to get memory in which to buffer the data */
|
||
if ( (WorkingBlock = malloc(BLOCK_SIZE)) == NULL ) {
|
||
printf(“Can’t get enough memory\n”);
|
||
exit(1);
|
||
}
|
||
|
||
/* Load the first block at the start of the buffer, and try to
|
||
fill the entire buffer */
|
||
NextLoadPtr = WorkingBlock;
|
||
NextLoadCount = BLOCK_SIZE;
|
||
Done = 0; /* Not done with search yet */
|
||
Found = 0; /* Assume we won’t find a match */
|
||
/* Search the file in BLOCK_SIZE chunks */
|
||
do {
|
||
/* Read in however many bytes are needed to fill out the block
|
||
(accounting for bytes copied over from the last block), or
|
||
the rest of the bytes in the file, whichever is less */
|
||
if ( (WorkingLength = read(Handle, NextLoadPtr,
|
||
NextLoadCount)) == -1 ) {
|
||
printf(“Error reading file %s\n”, argv[1]);
|
||
exit(1);
|
||
}
|
||
/* If we didn’t read all the bytes we requested, we’re done
|
||
after this block, whether we find a match or not */
|
||
if ( WorkingLength != NextLoadCount ) {
|
||
Done = 1;
|
||
}
|
||
|
||
/* Account for any bytes we copied from the end of the last
|
||
block in the total length of this block */
|
||
WorkingLength += NextLoadPtr - WorkingBlock;
|
||
/* Calculate the number of bytes in this block that could
|
||
possibly be the start of a matching sequence that lies
|
||
entirely in this block (sequences that run off the end of
|
||
the block will be transferred to the next block and found
|
||
when that block is searched)
|
||
*/
|
||
if ( (BlockSearchLength =
|
||
WorkingLength - SearchStringLength + 1) <= 0 ) {
|
||
Done = 1; /* Too few characters in this block for
|
||
there to be any possible matches, so this
|
||
is the final block and we’re done without
|
||
finding a match
|
||
*/
|
||
}
|
||
else {
|
||
/* Search this block */
|
||
if ( SearchForString(WorkingBlock, BlockSearchLength,
|
||
SearchString, SearchStringLength) ) {
|
||
Found = 1; /* We’ve found a match */
|
||
Done = 1;
|
||
}
|
||
else {
|
||
/* Copy any bytes from the end of the block that start
|
||
potentially-matching sequences that would run off
|
||
the end of the block over to the next block */
|
||
if ( SearchStringLength > 1 ) {
|
||
memcpy(WorkingBlock,
|
||
WorkingBlock+BLOCK_SIZE - SearchStringLength + 1,
|
||
SearchStringLength - 1);
|
||
}
|
||
/* Set up to load the next bytes from the file after the
|
||
bytes copied from the end of the current block */
|
||
NextLoadPtr = WorkingBlock + SearchStringLength - 1;
|
||
NextLoadCount = BLOCK_SIZE - SearchStringLength + 1;
|
||
}
|
||
}
|
||
} while ( !Done );
|
||
|
||
/* Report the results */
|
||
if ( Found ) {
|
||
printf(“String found\n”);
|
||
} else {
|
||
printf(“String not found\n”);
|
||
}
|
||
exit(Found); /* Return the found/not found status as the
|
||
DOS errorlevel */
|
||
}
|
||
|
||
------------------------ --------------------------------- --------------------
|
||
[Previous](05-02.html) [Table of Contents](index.html) [Next](05-04.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
* * * * *
|
||
|
||
Graphics Programming Black Book © 2001 Michael Abrash
|