#include "portable.h"
#include <stdio.h>
#include <ac/ctype.h>
#include <ac/string.h>
#include <ac/socket.h>
#include <ac/time.h>
#include "slap.h"
#if !defined(SLAPD_METAPHONE) && !defined(SLAPD_PHONETIC)
#define SLAPD_METAPHONE
#endif
#define iswordbreak(x) (!isascii(x) || isspace((unsigned char) (x)) || \
ispunct((unsigned char) (x)) || \
isdigit((unsigned char) (x)) || (x) == '\0')
#if 0
static char *
first_word( char *s )
{
if ( s == NULL ) {
return( NULL );
}
while ( iswordbreak( *s ) ) {
if ( *s == '\0' ) {
return( NULL );
} else {
s++;
}
}
return( s );
}
static char *
next_word( char *s )
{
if ( s == NULL ) {
return( NULL );
}
while ( ! iswordbreak( *s ) ) {
s++;
}
while ( iswordbreak( *s ) ) {
if ( *s == '\0' ) {
return( NULL );
} else {
s++;
}
}
return( s );
}
static char *
word_dup( char *w )
{
char *s, *ret;
char save;
for ( s = w; !iswordbreak( *s ); s++ )
;
save = *s;
*s = '\0';
ret = ch_strdup( w );
*s = save;
return( ret );
}
#endif
#ifndef MAXPHONEMELEN
#define MAXPHONEMELEN 4
#endif
#if defined(SLAPD_PHONETIC)
char *
phonetic( char *s )
{
char code, adjacent, ch;
char *p;
int i;
char phoneme[MAXPHONEMELEN + 1];
p = s;
if ( p == NULL || *p == '\0' ) {
return( NULL );
}
adjacent = '0';
phoneme[0] = TOUPPER((unsigned char)*p);
phoneme[1] = '\0';
for ( i = 0; i < 99 && (! iswordbreak(*p)); p++ ) {
ch = TOUPPER ((unsigned char)*p);
code = '0';
switch (ch) {
case 'B':
case 'F':
case 'P':
case 'V':
code = (adjacent != '1') ? '1' : '0';
break;
case 'S':
case 'C':
case 'G':
case 'J':
case 'K':
case 'Q':
case 'X':
case 'Z':
code = (adjacent != '2') ? '2' : '0';
break;
case 'D':
case 'T':
code = (adjacent != '3') ? '3' : '0';
break;
case 'L':
code = (adjacent != '4') ? '4' : '0';
break;
case 'M':
case 'N':
code = (adjacent != '5') ? '5' : '0';
break;
case 'R':
code = (adjacent != '6') ? '6' : '0';
break;
default:
adjacent = '0';
}
if ( i == 0 ) {
adjacent = code;
i++;
} else if ( code != '0' ) {
if ( i == MAXPHONEMELEN )
break;
adjacent = phoneme[i] = code;
i++;
}
}
if ( i > 0 )
phoneme[i] = '\0';
return( ch_strdup( phoneme ) );
}
#elif defined(SLAPD_METAPHONE)
static const char vsvfn[26] = {
1, 16, 4, 16, 9, 2, 4, 16, 9, 2, 0, 2, 2,
2, 1, 4, 0, 2, 4, 4, 1, 0, 0, 0, 8, 0};
#define vowel(x) ((x) != '\0' && vsvfn[(x) - 'A'] & 1)
#define same(x) ((x) != '\0' && vsvfn[(x) - 'A'] & 2)
#define varson(x) ((x) != '\0' && vsvfn[(x) - 'A'] & 4)
#define frontv(x) ((x) != '\0' && vsvfn[(x) - 'A'] & 8)
#define noghf(x) ((x) != '\0' && vsvfn[(x) - 'A'] & 16)
char *
phonetic( char *Word )
{
char *n, *n_start, *n_end;
char *metaph_end;
char ntrans[40];
int KSflag;
char buf[MAXPHONEMELEN + 2];
char *Metaph;
for (n = ntrans + 4, n_end = ntrans + 35; !iswordbreak( *Word ) &&
n < n_end; Word++) {
if (isalpha((unsigned char)*Word))
*n++ = TOUPPER((unsigned char)*Word);
}
Metaph = buf;
*Metaph = '\0';
if (n == ntrans + 4) {
return( ch_strdup( buf ) );
}
n_end = n;
ntrans[0] = '\0';
ntrans[1] = '\0';
ntrans[2] = '\0';
ntrans[3] = '\0';
*n++ = 0;
*n++ = 0;
*n++ = 0;
*n = 0;
n = ntrans + 4;
switch (*n) {
case 'P':
case 'K':
case 'G':
if (*(n + 1) == 'N')
*n++ = 0;
break;
case 'A':
if (*(n + 1) == 'E')
*n++ = 0;
break;
case 'W':
if (*(n + 1) == 'R')
*n++ = 0;
else if (*(n + 1) == 'H') {
*(n + 1) = *n;
*n++ = 0;
}
break;
case 'X':
*n = 'S';
break;
}
KSflag = 0;
for (metaph_end = Metaph + MAXPHONEMELEN, n_start = n;
n <= n_end && Metaph < metaph_end; n++) {
if (KSflag) {
KSflag = 0;
*Metaph++ = 'S';
} else {
if (*(n - 1) == *n && *n != 'C')
continue;
if (same(*n) || (n == n_start && vowel(*n)))
*Metaph++ = *n;
else
switch (*n) {
case 'B':
if (n == (n_end - 1) && *(n - 1) != 'M')
*Metaph++ = *n;
break;
case 'C':
if (*(n - 1) != 'S' || !frontv(*(n + 1))) {
if (*(n + 1) == 'I' && *(n + 2) == 'A')
*Metaph++ = 'X';
else if (frontv(*(n + 1)))
*Metaph++ = 'S';
else if (*(n + 1) == 'H')
*Metaph++ = ((n == n_start && !vowel(*(n + 2)))
|| *(n - 1) == 'S')
? (char) 'K' : (char) 'X';
else
*Metaph++ = 'K';
}
break;
case 'D':
*Metaph++ = (*(n + 1) == 'G' && frontv(*(n + 2)))
? (char) 'J' : (char) 'T';
break;
case 'G':
if ((*(n + 1) != 'J' || vowel(*(n + 2))) &&
(*(n + 1) != 'N' || ((n + 1) < n_end &&
(*(n + 2) != 'E' || *(n + 3) != 'D'))) &&
(*(n - 1) != 'D' || !frontv(*(n + 1))))
*Metaph++ = (frontv(*(n + 1)) &&
*(n + 2) != 'G') ? (char) 'G' : (char) 'K';
else if (*(n + 1) == 'H' && !noghf(*(n - 3)) &&
*(n - 4) != 'H')
*Metaph++ = 'F';
break;
case 'H':
if (!varson(*(n - 1)) && (!vowel(*(n - 1)) ||
vowel(*(n + 1))))
*Metaph++ = 'H';
break;
case 'K':
if (*(n - 1) != 'C')
*Metaph++ = 'K';
break;
case 'P':
*Metaph++ = *(n + 1) == 'H' ?
(char) 'F' : (char) 'P';
break;
case 'Q':
*Metaph++ = 'K';
break;
case 'S':
*Metaph++ = (*(n + 1) == 'H' ||
(*(n + 1) == 'I' && (*(n + 2) == 'O' ||
*(n + 2) == 'A')))
? (char) 'X' : (char) 'S';
break;
case 'T':
if (*(n + 1) == 'I' && (*(n + 2) == 'O' ||
*(n + 2) == 'A'))
*Metaph++ = 'X';
else if (*(n + 1) == 'H')
*Metaph++ = '0';
else if (*(n + 1) != 'C' || *(n + 2) != 'H')
*Metaph++ = 'T';
break;
case 'V':
*Metaph++ = 'F';
break;
case 'W':
case 'Y':
if (vowel(*(n + 1)))
*Metaph++ = *n;
break;
case 'X':
if (n == n_start)
*Metaph++ = 'S';
else {
*Metaph++ = 'K';
KSflag = 1;
}
break;
case 'Z':
*Metaph++ = 'S';
break;
}
}
}
*Metaph = 0;
return( ch_strdup( buf ) );
}
#endif