home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume15
/
look_rac
/
part01
/
look.c
next >
Wrap
C/C++ Source or Header
|
1990-12-16
|
4KB
|
185 lines
/*
* look - search a sorted file for lines beginning with string
* Roger Cornelius (rac@sherpa.uucp)
* Fri Oct 26 13:13:54 EDT 1990
* public domain
*/
#define _USE_MACROS /* for SCO UNIX, see ctype.h */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <ctype.h>
#define ERR 2
extern void exit();
int dstrncmp();
off_t backup();
FILE *fopen();
int fold = 0;
int dict = 0;
int (*compare)();
main(argc, argv)
register int argc;
register char **argv;
{
extern int optind;
char *file = "/usr/dict/words";
char *string;
int ch;
while ((ch = getopt(argc, argv, "df?")) != -1)
switch(ch) {
case 'd': dict = 1; break;
case 'f': fold = 1; break;
case '?': goto usage;
}
argc -= optind;
argv += optind;
if (argc < 1 || argc > 2) {
usage: (void)fputs("Usage: look [-df] string [file]\n", stderr);
exit(ERR);
}
string = *argv;
if (*++argv)
file = *argv;
else
fold = dict = 1;
return search(string, file);
}
/*
* search --
* search a sorted file for lines beginning with string
* adapted from binsearch(), K&R 2nd ed.
*/
static
search(string, file)
char *string;
char *file;
{
FILE *fp;
char buf[BUFSIZ], save[BUFSIZ];
off_t low, mid, high, savemid = -1;
off_t found = -1;
register char *t;
struct stat sbuf;
size_t slen = strlen(string);
int n, res = 1; /* not found */
if ((fp = freopen(file, "r", stdin)) == NULL
|| stat(file, &sbuf) != 0) {
/* avoid the printf kitchen sink */
(void) fputs("look: can't access ", stderr);
(void) fputs(file, stderr);
(void) fputs("\n", stderr);
return ERR;
}
low = 0;
high = sbuf.st_size;
compare = dict ? dstrncmp : strncmp;
if (fold)
for (t=string; *t; *t = tolower(*t), t++)
;
while (low < high) {
mid = (low+high) / 2;
if (backup(&low, &mid, &high) == -1 || mid == savemid)
break;
savemid = mid;
if (fseek(fp, mid, 0) != 0 || gets(buf) == NULL)
return ERR;
if (fold)
for (t=buf; *t; *t = tolower(*t), t++)
;
n = (*compare)(string, buf, slen);
if (n < 0)
high = mid - 1;
else if (n > 0)
low = mid + 1;
else {
found = mid; /* save offset of found string */
high = mid - 1;
if (strlen(buf) == slen)
break;
}
}
if (found >= 0) {
if (fseek(fp, found, 0) != 0)
return ERR;
while (gets(buf) != NULL) {
if (fold) {
(void)strcpy(save, buf);
for (t=buf; *t; *t = tolower(*t), t++)
;
}
if ((*compare)(string, buf, slen) != 0)
break;
(void)puts(fold ? save : buf);
}
res = 0; /* found */
}
(void)fclose(fp);
return res;
}
/*
* backup --
* search backwards for newline - if none found
* then reverse direction and start over
*/
static off_t
backup(low, offset, high)
register off_t *low, *offset, *high;
{
register int c;
register int inc = -1;
off_t save = *offset;
if (*offset == 0)
return(*offset);
for (; *offset < *high && fseek(stdin, *offset, 0) == 0; *offset += inc) {
c = getchar();
if (c == '\n' || *offset == 0)
return (*offset == 0) ? *offset : (*offset)++;
else if (c == EOF) /* should never happen */
break;
if (*offset <= *low) { /* start over, reversing direction */
*offset = save;
inc = 1;
}
}
return -1L;
}
/*
* dstrncmp --
* dictionary strncmp() - only alpha characters,
* digits, blanks and tabs participate in comparisons
*/
static
dstrncmp(s1, s2, n)
register char *s1, *s2;
register size_t n;
{
for (; n--; s1++, s2++) {
while (*s1 && !(isalpha(*s1) || isdigit(*s1) || isspace(*s1)))
s1++;
if (*s1 == '\0')
break;
while (*s2 && !(isalpha(*s2) || isdigit(*s2) || isspace(*s2)))
s2++;
if (*s1 != *s2)
return *s1 - *s2;
}
return 0;
}
/* end of look.c */