[comp.sources.misc] v05i007: Public domain look

campbell@redsox.UUCP (Larry Campbell) (10/28/88)

Posting-number: Volume 5, Issue 7
Submitted-by: "Larry Campbell" <campbell@redsox.UUCP>
Archive-name: s5look

Here's a quickie public domain implementation of look.  It's not blazingly
fast, but it sure beats grep, it lints cleanly, and the price is right.

/*
 * look.c
 *
 *	<-xtx-*> cc -o look -O -s look.c
 *
 *	An implementation of the V7/Berkeley look(1) utility, which
 *	is annoyingly lacking from System V.  This code is in the public
 *	public domain.  You may use this code for any purpose, commercial
 *	or noncommercial, as long as you don't try to claim you wrote it.
 *
 *	This code hasn't been tuned;  it runs about half the speed of the
 *	V7 version.  That's good enough for me.
 *
 *	If you find bugs, please send me the fixes.
 *
 * Written October, 1988 by:
 *
 *	Larry Campbell
 *	The Boston Software Works, Inc.
 *	120 Fulton Street, Boston, MA 02109
 *	campbell@bsw.com
 ******************************************************************
 * usage:
 *
 *	look [-f] words file
 *
 *	Conducts a binary search in <file>, which must be sorted,
 *	for a line beginning with <words>.  The -f switch means
 *	ignore (fold) case.
 *
 *	If the input file is not sorted, the results are unpredictable.
 */

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

extern void
    perror(),
    exit();

char
    *words,
    *filename,
    buf[BUFSIZ];

int
    fold_flag,
    length;

FILE
    *f;

long
    left_offset,
    offset,
    right_offset,
    size,
    step;

/* Forward declarations */

void
    search(),
    start_of_line(),
    strlwr(),
    usage();

main(argc, argv)
char *argv[];
{
int
    i;

struct stat
    statb;

if (argc < 3 || argc > 4)
    usage();
fold_flag = 0;
if (argc == 4) 
    if (argv[1][0] == '-' && argv[1][1] == 'f')
	fold_flag = 1;
    else
	usage();
i = argc - 2;
words = argv[i];
length = strlen(words);
if (fold_flag)
    strlwr(words);

filename = argv[i + 1];

f = fopen(filename, "r");
if (f == NULL)
    perror("can't open input file");

if (fstat(fileno(f), &statb) < 0)
    perror("stat failed on input file");

size = statb.st_size;
if (size == 0)
    exit(0);

offset = size / 2;
step = offset / 2;
search();
return 0;
}

void
search()
{
int
    compare;

char
    buf2[BUFSIZ];

for (;;)
    {
    if (fseek(f, offset, 0) == -1)
	perror("fseek");
    start_of_line();
    compare = strncmp(words, buf, length);
    if (compare == 0)
	{
	while (offset > 0L)	/* back up to first nonmatching line */
	    {
	    offset -= left_offset;
	    start_of_line();
	    compare = strncmp(words, buf, length);
	    if (compare != 0)
		{
		if (fseek(f, ++offset, 0) == -1) /* skip nonmatching line */
		    perror("fseek");
		if (fgets(buf, BUFSIZ, f) == 0)	/* reload matching line */
		    perror("fgets");
		break;
		}
	    }
	for (;;)
	    {
	    (void) fputs(buf, stdout);
	    if (fgets(buf, BUFSIZ, f) == 0)
		break;
	    (void) strcpy(buf2, buf);
	    if (fold_flag)
		strlwr(buf2);
	    if (strncmp(words, buf2, length) != 0)
		break;
	    }
	exit(0);
	}

    if (step == 0)
	exit(1);
    if (compare < 0)
	{
	if (step < left_offset)
	    offset -= left_offset;
	else
	    offset -= step;
	if (offset <= 0L)
	    exit(1);
	}
    else
	{
	if (step < right_offset)
	    offset += right_offset;
	else
	    offset += step;
	if (offset > size)
	    exit(1);
	}
    step = step / 2;
    }
}

void
start_of_line()
{
int
    c;

long
    toffset;

if (offset <= 0L)
    return;
toffset = offset;
while (toffset > 0L)
    {
    c = fgetc(f);
    if (c == '\n')
	break;
    if (fseek(f, --toffset, 0) == -1)
	perror("fseek");
    }
if (fgets(buf, BUFSIZ, f) == 0)
    perror("prev_line: fgets");
if (fold_flag)
    strlwr(buf);
left_offset = offset - toffset;
right_offset = (strlen(buf) - left_offset) + 1;
}


void
usage()
{
(void) fprintf(stderr, "usage: look [-f] string file\n");
exit(2);
}


/*
 * This function is in ANSI C but AT&T is still behind the times.
 */

void
strlwr(s)
char *s;
{
register char
    c;

while (c = *s)
    {
    if (isupper(c))
	*s = tolower(c);
    s++;
    }
}
-- 
Larry Campbell                          The Boston Software Works, Inc.
campbell@bsw.com                        120 Fulton Street
wjh12!redsox!campbell                   Boston, MA 02146