//eliza.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "eliza.hpp"
void eliza::reducespaces(char *m)
{
int len=strlen(m),space,count=0;
for(int x=0;x<len;x++) if(m[x]< 32) m[x]=32;
}
int subst(char start[],char sub1[],char sub2[])
{
int ln1=strlen(sub1),changed=0;
char s[MAXSIZE];
while((start=strstr(start,sub1))!=NULL)
{
changed=1;
for(int i=0;i<ln1;i++)
start[i]=' ';
strcpy(s,start);
//printf("1'%s'",start);
sprintf(start,"%s%s",sub2,s);
//printf("2'%s'",start);
}
return changed;
}
int fggetword(char*& input,char* outword,char& outother) //0 if done
{
outword[0]=0;
char *outword0=outword;
int curchar;
curchar=input[0];
while( isalpha(curchar) )
{
*outword=curchar;
outword++;
input++;
// printf(",%c;",*input); //debug
curchar=*input;
}
if(*input!= '\0') input++;
*outword='\0';
outother=curchar;
if( curchar == 0 && outword0[0]==0 ) return 0;
return 1;
}
char* substit(char *in)
{
static const char pairs[][10]=
{"am","are",
"I","you",
"mine","yours",
"my","your",
"me","you",
"myself","yourself",
//swapped order:
"you","I",
"yours","mine",
"your","my",
"yourself","myself",
"",""};
for(int i=0;pairs[i*2][0]!='\0';i++)
{
if(strcasecmp(in,pairs[i*2])==0)
{
return (char*)pairs[i*2+1];
}
}
return in;
}
#include <unistd.h>
void fixgrammer(char s[])
{
char newsent[MAXSIZE+20];
newsent[0]='\0';
char aword[MAXSIZE+3];
char* theinput;
theinput=s;
char otherch;
char ministr[]=" ";
while( fggetword(theinput,aword,otherch))
{
#ifdef DEBUG
printf(">%s'%s' : '%s' , %d\n",newsent,theinput,aword,otherch);
#endif
ministr[0]=otherch;
strcat(newsent,substit(aword));
strcat(newsent,ministr);
}
strcpy(s,newsent);
}
void old_fixgrammer(char s[])
{
int ln=strlen(s);
s[ln]=' ';
s[ln+1]='\0';
//printf("'%s'",s);
subst(s," I'll "," I will ");
subst(s,"I ",":you: ");
subst(s,"are you ","am I ");
subst(s,"you ",":I: ");
subst(s,":you: am ",":you: are ");
subst(s,":I: are "," :I: am ");
subst(s," mine "," :yours: ");
subst(s," yours "," :mine: ");
subst(s," your "," :my: ");
subst(s," my "," :your: ");
subst(s," you're "," I'm ");
subst(s," you'll "," I'll ");
subst(s," :yours: "," yours ");
subst(s," :mine: "," mine ");
subst(s,":I: "," I ");
subst(s,":you: "," you ");
//puts(s);
}
char* eliza::process(char*message)
{
static char replied[MAXSIZE*2];
char *rep=NULL;
if(strlen(message)>MAXSIZE) return "You talk too much.";
strcpy(replied,"I dont really know much about that, say more.");
reducespaces(message);
thekeys.reset();
while(thekeys.curr()!=NULL)
{
int i=0,rest=0;
if(match(thekeys.curr()->key.getlogic(),message,i,rest))
{
rep=thekeys.curr()->key.getrndreply();
fixgrammer(&message[rest]);
sprintf(replied,rep,&message[rest]);
reducespaces(replied);
return replied;
}
thekeys.advance();
}
return replied;
}
void eliza::adds(char ss[])
{
int len=strlen(ss),in=0;
char s[MAXSIZE];
strcpy(s,ss);
for(int i=0;i<len;i++)
{
if(s[i]=='%')
{
ss[in++]='%';
ss[in++]='s';
} else
ss[in++]=s[i];
}
ss[in]=0;
#ifdef DEBUG
//puts(s);
#endif
}
bool eliza::loaddata(char file[])
{
FILE *data;
char str[MAXSIZE];
if((data=fopen(file,"rt"))==NULL)
{
#ifdef DEBUG
puts("File error!");
#endif
return false;
}
int linecount=0;
while(fgets(str,MAXSIZE-1,data)!=NULL)
{
linecount++;
#ifdef DEBUG
puts(str);
#endif
if(strlen(str)>0)
{
if(str[0]>='1' && str[0]<='9')
{
adds(str);
thekeys.curr()->key.addreply(str[0]-'0',&(str[1]));
#ifdef DEBUG
//puts("reply found");
#endif
} else switch(str[0])
{
case '(':
thekeys.addkey();
thekeys.curr()->key.addlogic(str);
#ifdef DEBUG
//puts("logic found");
#endif
break;
case '#':
#ifdef DEBUG
puts("rem");
#endif
break;
case '"':
fputs(&str[1],stderr);
break;
case '\'':
fputs(&str[1],stdout);
break;
}
}
}
//fprintf(stderr,"%d lines read from data file\n",linecount);
fclose(data);
return true;
}
char* eliza::trim(char str[])
{
int i,a,ln=strlen(str);
for(;(ln>0) && (str[ln-1]==' ');ln--);
str[ln]=0;
for(i=0;(i<ln) && (str[i]==' ');i++);
if(i>0)
for(ln-=i,a=0;a<=ln;a++)
str[a]=str[a+i];
#ifdef DEBUG
//printf("'%s'\n",str);
#endif
return str;
}
int eliza::doop(char op,int a,int b)
{
switch(op)
{
case '\0':
case '&': return a && b;
case '|': return a || b;
case '~': return a && !b;
default:
#ifdef DEBUG
printf("Errored Op! %c\n",op);
#endif
return 0;
}
}
int eliza::lowcase(char ch)
{
if(ch>='A' && ch<='Z') return ch+32;
return ch;
}
int eliza::strpos(char *s,char *sub)
{
int i,a,lns=strlen(s),lnsub=strlen(sub),run,space=1;
if(sub[0]=='=') {// = exact equality operator
return strcasecmp(&sub[1],s) ? 0 : lns;
}
if(sub[0]=='^'){ // match start operator
return strncasecmp(&sub[1],s,lnsub-1) ? 0 : lns;
}
if(lnsub>lns) return 0;
run=lns-lnsub;
for(i=0;i<=run;i++)
{
if(space)
{
for(a=0;a<lnsub && (lowcase(s[i+a])==sub[a]);a++);
#ifdef DEBUG
//printf("hey %d r:%d",a,i+a);
#endif
if(a==lnsub) return (i+a);
}
space=s[i]==' ';
}
return 0;
}
#define encounterop \
trim(ph); \
if(strlen(ph)) \
{ \
a=strpos(m,ph); \
if(a>0) rest=a; \
res=doop(op,res,a); \
} \
len=ph[0]=0;
int eliza::match(char s[],char m[],int& in,int& rest)
{
int l=strlen(s),res=1,op='\0',a;
char ph[MAXSIZE];
int len=0;
ph[0]=0;
#ifdef DEBUG
//puts(s);
//puts(m);
#endif
while(s[in]!='(') in++;
in++;
for(;in<l;in++)
{
switch(s[in])
{
case '(':
#ifdef DEBUG
//printf("in %d into...\n",in);
#endif
a=match(s,m,in,rest);
if(op=='\0') res=a;
else
res=doop(op,res,a);
break;
case '&':
encounterop
op='&';
break;
case '|':
encounterop
op='|';
break;
case '~':
encounterop
op='~';
break;
case ')':
#ifdef DEBUG
//printf("p:'%s'\n",ph);
#endif
trim(ph);
if(strlen(ph))
{
a=strpos(m,ph);
if(a>0) rest=a;
return doop(op,res,a);
} else return res;
break;
default:
ph[len++]=s[in];
ph[len]='\0';
}
}
return res;
}