home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: OtherApp
/
OtherApp.zip
/
phone1.zip
/
PHONE.C
next >
Wrap
Text File
|
1987-04-09
|
11KB
|
432 lines
/*
* phone.c
*
* Search a phone book file for an entry
*
* Author: Martin Minow
* MSDOS version: J. Anthony Movshon
* 7 August 1984
*/
#include <stdio.h>
#include <ctype.h>
#ifdef isprint
#ifndef isgraph
#define isgraph(c) (isprint(c) && c != ' ')
#endif
#endif
#define TRUE 1
#define FALSE 0
#define EOS 0
#define NFIELDS 100
#define LINESIZE 257
char *search[NFIELDS]; /* search text */
char *word[NFIELDS]; /* file text split up */
int issoundex[NFIELDS]; /* TRUE for soundex */
unsigned int hash[NFIELDS]; /* soundex hash value */
char line[LINESIZE]; /* text line as read */
char work[LINESIZE]; /* text line in words */
char argtext[LINESIZE]; /* prompted text */
FILE *fd; /* Phone book file */
/*
* This search list is used to locate the phone book.
*/
static char *searchlist[] = {
"phone.txt",
"\\etc\\phone.txt",
"e:\\etc\\phone.txt",
NULL
};
/*
* Usage message
*/
static char *helpmessage[] = {
"Search phone book for an argument string:",
" '*' in a string matches any string of characters",
" '?' in a string matches any non-null character",
"Any left-most match succeeds and multiple search arguments are permitted.",
"Names that sound similar will be reported if '*' and '?' are not used.",
NULL,
};
main(argc, argv)
int argc;
char *argv[];
{
openphonebook(argc, argv);
if (argc > 1) {
findargs(argc, argv);
setsoundexflag();
findmatch();
}
else {
/*
* No arguments were given. Prompt and read
* arguments from standard input.
*/
fprintf(stderr,
"Phonebook search program, <return> for help\n");
while (!feof(stdin)) {
fprintf(stderr, "Search: ");
fflush(stderr);
if (gets(argtext) == NULL)
break;
if (argtext[0] == EOS) {
usage();
}
else {
packtext(argtext, search);
setsoundexflag();
findmatch();
rewind(fd);
}
}
}
}
openphonebook(argc, argv)
int argc; /* Arg count from operating system */
register char *argv[]; /* Arg vector from operating system */
/*
* Open the phone book file -- exit to system if failure.
*/
{
register char **namep;
register char *cp;
while (--argc > 0) {
cp = *++argv;
if (*cp++ == '-') {
if ((*cp == 'f' || *cp == 'F') && cp[1] == EOS) {
*argv++ = NULL;
cp = *argv;
if (--argc <= 0) {
fprintf(stderr, "-f must be followed by a file name\n");
exit(1);
}
else if ((fd = fopen(cp, "r")) == NULL) {
perror(cp);
fprintf(stderr, "phone: can't open your phonebook\n");
exit(1);
}
else {
*argv = NULL;
return;
}
}
}
}
/*
* On VMS, RSTS, RSX, or whathaveyou, try the search list
*/
for (namep = searchlist; *namep != NULL; namep++) {
if (openit(*namep, FALSE))
return;
}
fprintf(stderr, "phone: can't locate phonebook phone.txt\n");
exit(1);
}
static int
openit(filename, fatal)
char *filename; /* Actual filename to open */
int fatal; /* TRUE if failure is fatal */
/*
* Open the indicated file. Return TRUE if success. If failure and
* fatal is TRUE, exit to the operating system with an appropriate
* error message, else, return FALSE.
*/
{
if ((fd = fopen(filename, "r")) != NULL)
return (TRUE);
else if (!fatal)
return (FALSE);
else {
perror(filename);
fprintf(stderr, "phone: can't open phonebook\n");
exit(1);
}
}
findargs(argc, argv)
int argc; /* Arg count from operating system */
char *argv[]; /* Arg vector from operating system */
/*
* Build the search arguments in field[].
*/
{
register char *cp;
register int fieldindex;
register char c;
fieldindex = 0;
while (--argc > 0) {
cp = *++argv;
if (cp == NULL)
continue;
search[fieldindex] = cp;
while ((c = *cp) != EOS) {
*cp++ = tolower(c);
}
fieldindex++;
}
search[fieldindex] = NULL; /* terminate the list */
setsoundexflag();
}
setsoundexflag()
/*
* Examine the search arguments (in search[]), setting issoundex[]
* appropriately. If this argument should be "soundex'ed", calculate
* the hash value.
*/
{
register char *cp;
register int fieldindex;
register char c;
extern unsigned int soundex();
for (fieldindex = 0; (cp = search[fieldindex]) != NULL; fieldindex++) {
issoundex[fieldindex] = TRUE;
while ((c = *cp++) != EOS) {
if (c == '*' || c == '?') {
issoundex[fieldindex] = FALSE;
break;
}
}
if (issoundex[fieldindex])
hash[fieldindex] = soundex(search[fieldindex]);
}
}
findmatch()
/*
* Read the file, print matching lines.
*/
{
register int fieldindex; /* Field pointer */
register char **wp; /* Word pointer */
register int matchcount; /* Counts matches */
extern unsigned int soundex();
matchcount = 0;
line[0] = EOS;
for (;;) {
if (line[0] == EOS && fgets(line, sizeof (line), fd) == NULL)
break;
if (isspace(line[0])) {
line[0] = EOS; /* Force read next time */
continue;
}
strcpy(work, line);
packtext(work, word);
for (fieldindex = 0; search[fieldindex] != NULL; fieldindex++) {
for (wp = word; *wp != NULL; wp++) {
if (issoundex[fieldindex] != FALSE
&& soundex(*wp) == hash[fieldindex])
goto gotcha;
if (matchtest(*wp, search[fieldindex]))
goto gotcha;
}
}
line[0] = EOS; /* Force read next time */
continue; /* Not found */
gotcha: matchcount++;
do {
fputs(line, stdout);
if (fgets(line, sizeof (line), fd) == NULL)
goto done;
} while (isspace(line[0]));
}
done: if (matchcount == 0)
fprintf(stderr,"phone: no match found\n");
}
packtext(text, wordlist)
register char *text; /* This text line is packed */
register char **wordlist; /* Into this array of words */
/*
* Build wordlist. Modifies text.
*/
{
register char c;
c = *text;
while (c != EOS) {
while ((c = *text) != EOS && !isgraph(c))
++text; /* Skip over whitespace */
if (c == EOS)
break;
*wordlist++ = text; /* Start of new word */
while ((c = *text), isgraph(c))
*text++ = tolower(c);
*text++ = EOS; /* Terminate the word */
}
*wordlist = NULL;
}
int
matchtest(name, pattern)
register char *name; /* What to look for */
register char *pattern; /* May have wildcard */
/*
* Recursive routine to match "name" against "pattern".
* Returns TRUE if successful, FALSE if failure.
*
* pattern follows Dec filename wildcard conventions: '*' matches any
* string (even null), '?' matches any single (non-null) byte.
*
*/
{
register char pattbyte;
for (;;) {
/* fprintf(stderr, "(%s) (%s), namebyte = '%c', pattbyte = '%c'\n",
name, pattern, *name, *pattern);
*/
/*
* Assume that patterns are terminated -- implicitly --
* by '*', allowing all left-matches to succeed.
*/
if ((pattbyte = *pattern++) == EOS
|| (pattbyte == '*' && *pattern == EOS))
return (TRUE);
/*
* Not at end of the name string.
*/
switch (pattbyte) {
case '*': /* Wild card means "advance" */
do {
if (matchtest(name, pattern))
return (TRUE);
} while (*name++ != EOS);
return (FALSE); /* Did our best */
case '?': /* One byte joker */
break; /* succeeds with this byte */
default: /* Others much match exactly */
if (*name != pattbyte)
return (FALSE);
break;
}
name++; /* Advance name byte */
}
}
/*
* soundex(string)
*
* Return the soundex hash value for the argument string.
* S_V should be zero for efficiency.
*/
#define S_V 0 /* Vowels: a e i o u (maybe y, h, w) */
#define S_SK 1 /* "hard" consonants: s c z x k q */
#define S_TD 2 /* Dental stops: t d */
#define S_FV 3 /* f v */
#define S_GJ 4 /* g j */
#define S_B 5 /* b */
#define S_L 6 /* l */
#define S_M 7 /* m */
#define S_N 8 /* n */
#define S_P 9 /* p */
#define S_R 10 /* r */
#define S_MAX 11 /* "radix" of soundex values */
/*
* The following are the hash values for each letter.
*/
static char sx_letters[] = {
/* a b c d e f g h */
S_V, S_B, S_SK, S_TD, S_V, S_FV, S_GJ, S_V,
/* i j k l m n o p */
S_V, S_GJ, S_SK, S_L, S_M, S_N, S_V, S_P,
/* q r s t u v w x */
S_SK, S_R, S_SK, S_TD, S_V, S_FV, S_V, S_SK,
/* y z */
S_V, S_SK,
};
/*
* The first letter of the following consonant pairs is silent.
*/
static char *sx_leading_silent = "tstzghknpnptpf";
unsigned int
soundex(string)
register char *string;
/*
* Compute the soundex hash for the argument string.
* -- somewhat modified from the original algorithm.
* "Margaret K. Odell and Robert C. Russell. U.S.
* patents 1261167 (1918) and 1435663 (1922)." as
* reprinted in Donald Knuth, Sorting and Searching.
*/
{
register int c; /* Current character */
register char *sxp; /* -> leading silent string */
int last; /* Previous character for doubles */
int next; /* Next character in the string */
int value; /* Soundex value */
int temp; /* Hash for this character */
int count; /* Want only three digits */
while (c = *string++, !isalpha(c)) {
if (c == EOS)
return (0);
}
last = c = tolower(c);
value = c - 'a' + 1; /* Initial hash == first letter value */
next = *string++;
next = tolower(next);
count = 3; /* Maximum times through this loop */
while (--count >= 0 && (c = next) != EOS) {
next = *string++;
next = tolower(next);
if (next != EOS) {
/*
* Ignore the first letter in a silent-pair.
*/
for (sxp = sx_leading_silent; *sxp != EOS; sxp++) {
if (*sxp++ == c && *sxp == next) {
goto reject; /* reject silent first letter */
}
}
/*
* Change 'ph' to 'f'
*/
if (c == 'p' && next == 'h') {
c = 'f';
next = *string++;
next = tolower(next);
}
}
if (islower(c)) {
if ((temp = sx_letters[c - 'a']) != S_V && c != last) {
value *= S_MAX;
value += temp;
}
last = c;
}
reject: ; /* Jump here on silent pairs */
}
while (--count >= 0) /* Finish off the hash code */
value *= S_MAX;
return (value);
}
usage()
/*
* Help message
*/
{
register char **hp;
for (hp = helpmessage; *hp != NULL; hp++) {
fprintf(stderr, "%s\n", *hp);
}
}