cdirt/ascii/
cdirt/data/BULL/
cdirt/data/ZONES/PENDING/
cdirt/pending/
cdirt/src/utils/
cdirt/utils/
/*******************************************************
   splotch.c a robot type thing Version 1.0

   7/17/1992 Duane Fields (dkf8117@tamsun.tamu.edu)
********************************************************/


#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include "kernel.h"

#define tolow(A) (isupper(A)?(tolower(A)):(A))

#define NAME      "Bob"        /* name of robot */
#define HISTORY   4            /* number of slots in old key queue */
#define TEMPLSIZ  2000         /* maximum number of templates */
#define DICTFILE  DATA_DIR "/main.dict"  /* name of dictionary file */
#define DEBUG 0                /* debug flag */
#define VERBOSE 0              /* verbose errors */
#define BLANK 040

struct template {
  long    toffset;           /* start of responses in file */
  char    tplate[400];       /* the template itself */
  int     priority;          /* how important key is 1=worst, 9=most */
  int     talts;             /* number of alternate replies (>0) */
  int     tnext;             /* next reply (1 <= tnext <= talts) */
}         templ[TEMPLSIZ];

char   response[400];        /* response to be returned */
char   my_nick[20];
char   words[400];           /* a template has been matched, this is % */
FILE   *dfile;               /* file pointer to main dictionary file */
int    maxtempl;             /* templ[maxtempl] is last entry */
int    oldkeywd[HISTORY];    /* queue of indices of most recent keys */

char *strcasestr();
char *phrasefind();
void ask(char *, char *);
void init(void);
void buildtempl(void);
void usetempl(int);
int grline(char *, char *);
void expand(char *);
void swap(char *, char *, char *);
void strlower(char *);
char *lower(char *);
void fixfile(char *);
extern char *strcasestr(char *, char *);
int trytempl(char *);
char *phrasefind(char *, char *);
void fix(void);
void gswap(char *, char *);
void shift(int, int);

/***************************************************************************
  ask(person, question) takes two null terminated strings, one is the 
  question and the other is the person who asked the question.  The function 
  returns the int value which represents the template used (0 or greater).
  if no match was found, a -1 is returned.  ask always sets the global 
  variable "response" to contain an appropriate response, or if no match was
  found, an reply from the last entry in the dictionary. (a default reply)
 ***************************************************************************/

void ask(person, question)
     char    person[20];            /* person who asked the question */
     char    question[400];         /* input line from user */

{
  int     i,j;
                                     /* expand also strlowers() */
  expand(question);                  /* swap word according to syn.dict file */

  if (DEBUG)
   fprintf(stderr, "<<expanded>>\n");

  i = trytempl(question);            /* look for a matching template */

  if (DEBUG)
    fprintf(stderr, "<<trytempl done, i=%i>>\n",i);


  if (i >=0)   {                     /* found a match, index=i */
    if (templ[i].priority == 6)  {    /* key words 6 */
      for (j=0; j < HISTORY-1; j++)  /* update history que */
        oldkeywd[j] = oldkeywd[j+1];
      oldkeywd[HISTORY-1]=i;
      }
    usetempl(i);                      /* build response */
    return;
  }              
  else {                              /* no match found */

    if ((random() % 100)+1)         /* HISTORY NOT IMPEMENTED! */
       usetempl(maxtempl);          /* use a neutral response */
    else {                            /* use an old key */ 
      i = (random() % HISTORY);
      i = oldkeywd[i];
      if (DEBUG)
	fprintf(stderr, "<<History used, i=%i>>\n",i);


      if (i < 0)                      /* no history yet */
	usetempl(maxtempl);
      else usetempl(i);
    }
  }
}



/***************************************************************************
  init() sets up the template, zeros variables. Must be called by main prg
 ***************************************************************************/

void init()
{
  int    i;
  
  /* initialization section, zero array, open files */
  
  for (i=0; i < HISTORY; i++)
    oldkeywd[i] = -1;                /* no previous keywords */

  dfile = FOPEN(DICTFILE, "r");
  if (dfile == NULL) {
    fprintf(stderr, "ERROR: unable to read %s\n",DICTFILE);
    exit(1);
  }
  
  if (DEBUG)
    fprintf(stderr, "<<using dict file %s>>>\n", DICTFILE);

  srandom(getpid());   /* randomize seed */
  buildtempl();    /* read the templates, make 1 entry per template */

  if (DEBUG)
    fprintf(stderr, "<<templates built, seed chosen>>\n");
}





/**************************************************************************
  buildtempl() reads the MAINDICT file and fills in the template table.
  Each entry in the template table refers to a single template and all of 
  its replies.
 ***************************************************************************/

void buildtempl()
{
  char    line[400];
  char    temp[400];
  int     i;
 
  
  i=0;   /* first template starts at zero */
  
  /* loop, one pass per template (including all replies) */
  while (!feof(dfile)) {
    fgets(line, sizeof(line), dfile);
    
    while (((line[0] == '#') || isspace(line[0])) && (!feof(dfile)))
      fgets(line, sizeof(line), dfile);
    
    if (feof(dfile))
      break;
    
    /* read in template */
    strcpy(templ[i].tplate, line);

    /* read priority */
    fgets(line, sizeof(line), dfile);

    if (atoi(line) == 0)  /* no entry */
      templ[i].priority = 9;                /* default priority */
    else
      templ[i].priority = atoi(line);
    
    /* set number of alternate replies to 0 */
    templ[i].talts = 0;
    
    /* count number or responses, start with asterisk */
    if (line[0] != '*')
      fgets(line, sizeof(line), dfile);

    /* where to find first response withing dictionary */
    templ[i].toffset = ftell(dfile) - strlen(line);

    while ((line[0] == '*') && !feof(dfile)) {
      templ[i].talts++;
      fgets(line, sizeof(line), dfile);
    }
    
    /* pick a random starting point for the responses */
    templ[i].tnext = 1 + (random() % (templ[i].talts));
    if (templ[i].tnext > templ[i].talts)
      templ[i].tnext = 1;

    strcpy(temp, templ[i].tplate);
    temp[strlen(temp)-1]='\0';

    if (VERBOSE)
      fprintf(stderr, "<<Template[%i]=:%s:>>\n",i,temp);
    

    i++;   /* next template */

    if (i >= TEMPLSIZ) {
      fprintf(stderr, "ERROR: template array too small\n");
      exit(1);
    }
    
  }
  
  /* all templates have been read and stored */
  maxtempl = i -1;
}

 


/**************************************************************************
 usetempl() a template has been sucessfully matched.  generate output 
**************************************************************************/
void usetempl(i)
     int     i;
{
  int     k, n, p1,p2;
  char    text[400];
  char    text2[400];
  char    add[400];
  char    filename[400];
  char    new[400];
  char    *p;
  char    *pp;

  if (DEBUG)
    fprintf(stderr, "<<entering usetempl>>\n");

  fseek(dfile, templ[i].toffset, 0);	/* seek the template */
  fgets(text, sizeof(text), dfile);
       
  if (templ[i].tnext > templ[i].talts)
    templ[i].tnext = 1;
  n = templ[i].tnext;
  templ[i].tnext++;
  
  /* skip to the proper alternative */
  for (k = 1; k < n; k++)
    fgets(text, sizeof(text), dfile);
  
  /* make reply using template */
  strcpy(response, text+1);
  if (response[strlen(response)-1] == '\n')
    response[strlen(response)-1]='\0';

  if (words[0] != '\0') {

    p=strstr(words, ",");          /* chop off trailing cluases */
    if (p != NULL)
       p[0]='\0';
    
    p=strstr(words, ". ");
    if (p != NULL)
      p[0]='\0';

    p=strstr(words, "...");
    if (p != NULL)
      p[0]='\0';

    p=strstr(words, "?");
    if (p != NULL)
      p[0]='\0';


    p=strstr(words, ";");                      
    if (p != NULL)
       p[0]='\0';

    p=strstr(words, "!");
    if (p != NULL)
       p[0]='\0';
    
    p=strstr(words, ":");
    if (p != NULL)
      p[0]='\0';

    sprintf(text, " %s", lower(my_nick));
    sprintf(text2,"than %s", lower(my_nick));
    pp=strstr(words, text2);
    p=strstr(words, text);                        
    if ((p != NULL) && (pp == NULL))
       p[0]='\0';

    p=strstr(words, " please");
    if(p != NULL)
      p[0]='\0';


    if (ispunct(words[strlen(words)-1]))
      words[strlen(words)-1]='\0';

    fix();                           /* fix grammer */
    
    swap (response, "%", words);
  }

  swap(response, lower(my_nick), "I");          /* should use NAME */
  swap(response, "%", " ");
  for (i=0; words[i] != '\0'; i++)
    words[i]=words[i] & 0177;

/* fix problems with grammer */

  gswap("i are", "I am");
  gswap("me have", "I have");
  gswap("me don't", "I don't");
  gswap("you am", "you are");
  gswap("me am", "I am");
  gswap("i", "I");
  gswap("did not be", "weren't");

  for (i=0; words[i] != '\0'; i++)
    words[i]=words[i] & 0177;


  /* do file insertians */

  while (strstr(response, "@") != NULL) {
    p1=0;
    p2=0;
    strcpy (filename, "\0");
    strcpy (new, "\0");
    strcpy (add, "\0");
    
    while (response[p1] != '@')
      new[p1]=response[p1++];   

    p1++;
    new[p1-1]='\0';
    while (! (response[p1] == '.') && response[p1] != '\0')
      filename[p2++]=response[p1++];
    filename[p2++]=response[p1++];
    filename[p2++]=response[p1++];
    filename[p2]='\0';
    if (! grline(filename, add)) {              /* problem reading file */
      strcpy (response, "hmmm");                /* error msg printed by */
      return;                                   /* grline()             */
    }
    
    if (response[p1] != '\0')
      sprintf(text, "%s%s%s", new, add, &response[p1]);
    else sprintf(text, "%s%s",new,add);
    strcpy(response, text); 
  } 
}





 
  
/*****************************/
/* gets random line from file*/
/*****************************/ 
int grline(infile,s1)
char infile[25], s1[256];
  
{
  int i,r,x;
  FILE *fp;
  char fname[25];
  
  sprintf(fname, "words/%s", infile);
  
  if ((fp=FOPEN(fname, "r")) == NULL)
    {
       fprintf(stderr, "\n ERROR! could not open :%s: \n",infile);
       return(0);
    }

  fgets (s1, 256, fp);
  while ((s1[0] == '#') || (isspace(s1[0])))
    fgets(s1, 256, fp);

  if (atoi(s1)==0)
  {
    FCLOSE(fp);
    fixfile(fname);
    fp=FOPEN(fname,"r");
    fgets(s1, 256, fp);
    while ((s1[0] == '#') || (isspace(s1[0])))
      fgets(s1, 256, fp);
  }

  x=atoi(s1);
  r=(random() % x)+1;
  for (i=1; i<=r && (! feof(fp)); i++)
      fgets(s1, 256, fp);
  s1[strlen(s1)-1]='\0';
  FCLOSE(fp);
  return(1);
  
}
 






/***************************************************************************
   expand() takes a string pointer.  Using they syn.dict file (format is
   given in the syn.dict file itself) it expands synonyms.
****************************************************************************/ 
void expand (s)
char *s;
{
   char *old;
   char *new;
   char line[255];
   FILE *fp;

   strcat(line, "#");
   strlower(s);
   fp=FOPEN("syn.dict","r");
   if (fp == NULL)
     {
        fprintf(stderr, "ERROR: Could not open the file syn.dict\n");
        return;
     }
   else
     {
       while(!feof(fp))
         {
           fgets(line,255,fp);
           while ((line[0] == '#') || (isspace(line[0])))
             fgets(line,255,fp);
           
           strlower(line);
           
           new = strtok (line, ":\n");
           old = strtok (NULL, ":\n");
           while (old != NULL)
             {
               swap(s,old,new);        
               old = strtok (NULL, ":\n");
             }
         }
       FCLOSE(fp);
     }
}              





/*********************************************************************
   swap() takes a string pointer and a two words.  All occurances of 
   the first word are replaced by the second word.
 *********************************************************************/
 
void swap(s, old, new)
char *s, *old, *new;
{
   char *n;
   char *n0;
   char *i;
   char *s0;
   char *new0;
  
   i=NULL;
   
   n=(char *)malloc(255);   
   n0=n;
   s0=s;
   new0=new;
   
   while ((i=strstr(s,old)) != NULL)
         {
            while (s != i)
            {
               *n=*s;
               s++;
               n++;
            }
            
            if ( (isspace(i[strlen(old)]) || ispunct(i[strlen(old)]) ||
                  i[strlen(old)] == '\0')  && 
               (s==s0 || isspace(s[-1]) || ispunct(s[-1])) )
               
               {
                  new = new0;
                  while (*new)
                        {
                           *n=*new;
                           new++;
                           n++;
                        }
                  s += strlen(old);       
               }      
            else
               {
                  *n=*s;
                  s++;
                  n++;
               }   
         } 
         

   strcpy(n,s);
   strcpy(s0,n0);
}





/*********************************************************************
   strlower() takes a string pointer and makes that string lowercase
 *********************************************************************/

void strlower(s)
char *s;
{
   register int i;
   
   for (i=0; s[i]; ++i)
       s[i] = tolower (s[i]);
     
}
 



char *lower(s)
char  *s;
{
  int i;
  static char tmp[400];
  
  for (i=0; s[i]; ++i)
    tmp[i] = tolower(s[i]);
  tmp[i]='\0';
  return(tmp);
    
}



/***************************************************************************
fixfile will count the non-blank lines in a file and put the count as the
first line of the file.  Uses a tmp file called "tmp"
***************************************************************************/

void fixfile(fname)
char fname[50];

{
  int count;
  FILE *tmpfp;
  FILE *fp;
  char line[255];
  char tline[255];

  count=0;

  fp=FOPEN(fname, "r");
  if (fp  == NULL)
    {
      fprintf(stderr, "ERROR: Could not open %s file\n",fname);
      return;
    }
  fgets(line,255,fp);
  while (!feof(fp))
    {
      if (!((line[0] == '#') || (isspace(line[0]))))
	count++;
      fgets(line,255,fp);
    }
  rewind(fp);
  tmpfp=FOPEN("tmp","w");
  if (tmpfp == NULL)
    {
      fprintf(stderr, "ERROR: Could not create tmp file\n");
      return;
    }
  fgets(line, 255, fp);
  
  while ((line[0] == '#') || (isspace(line[0])))
    {
      fputs(line,tmpfp);
      fgets(line,255,fp);
    }
  if (atoi(line)==0)
    {
      count=count-1;
      sprintf(tline, "%i\n",count);
      fputs(tline, tmpfp);
    }
  else
    {
      sprintf(tline, "%i\n",count);
      fputs(tline, tmpfp);
      fputs(line, tmpfp);
    }
  fgets(line,255,fp);
  while (!feof(fp))
    {
      fputs(line,tmpfp);
      fgets(line,255,fp);
    }
  FCLOSE(tmpfp);
  FCLOSE(fp);
  
  fp=FOPEN(fname, "w");
  tmpfp=FOPEN("tmp", "r");
  fgets(line,255,tmpfp);
  while (!feof(tmpfp))
    {
      fputs(line,fp);
      fgets(line,255,tmpfp);
    }
  FCLOSE(tmpfp);
  FCLOSE(fp);
}






/***************************************************************************
 trytempl() will try to match the current line to a template.  In turn, try
 all templates to see if if they find a match.
***************************************************************************/

int trytempl(question)
     char question[];
{
  int     i;
  char    t[400];
  int     found,done;
  char    *key;
  char    key1[400];                 /* first half of a % template */
  char    key2[400];                 /* second half of a % template */
  char    winwords[400];
  int     firstime;
  int     p,j;
  char    *p1,*p2;
  int     score;                     /* current highest priority */
  int     winner;                    /* current high scorer */

  winner=-1;
  found=0;
  done=0;
  score=0;
  key=0;
  words[0] = '\0';                    /* the % words */
  firstime=1;

  for (i=0; i <= maxtempl; i++) {     /* loop through all templates */
    done=0;
    strcpy(t, templ[i].tplate);
    firstime=1;

    while (done == 0) {
      if (firstime) {
	key = strtok(t, ":\n");
	firstime=0;
      }
      else
	 key=strtok(NULL, ":\n");
      if (key == NULL) {
	done=1;
	break;
      }
      switch (key[0]) {
      case '!': if (phrasefind(question, key+1) != NULL) {
	           found=0;
		   done=1;
		 }
	        break;
      case '&': if (phrasefind(question, key+1) == NULL) {
	           found=0;
		   done=1;
		 }
	        break;
      case '+': if (phrasefind(question, my_nick) == NULL) {  /* name */
                   found=0;
                   done=1;
                 }
                break;
      default:  if (!strstr(key, " %")) {    /* regular template, no % */
	           if (phrasefind(question, key))
		     found=1;
		   break;
		 }
	        else {     		  /* is a % in template */
		  key1[0]=key[0];
		  p=0;
		  j=0;
		  while ((key1[p++]=key[j++])!='\%');    
		  key1[p-2]='\0';

		  if ((key[p] != '\0') && (key[p] != '\n') )  { /* xxx % xxx */
		    strcpy(key2, &key[p+1]);
		    j=0;
		    p1=phrasefind(question, key1);
		    if (p1 != NULL)
		      if (!ispunct(p1[strlen(p1)-1])) {
			p2=phrasefind(p1+1, key2);
			if (p1 != NULL && p2 != NULL) {     /* both keys found */
			  found=1;
			  strcpy(words, p1+strlen(key1)+1);
			  words[p2-p1-strlen(key1)-2]='\0'; /* -2 for spaces */
			}
		      }
		  }
		  else {		    /* xxxx % */
		    p1=phrasefind(question, key1);
		    if ((p1 != NULL)&& p1[strlen(key1)] != '\0') 
		      {
		      /* if (!ispunct(p1[strlen(p1)-1])) { */
			found=1;
			strcpy(words, p1+strlen(key1)+1);
		      } 
		  }
		}
      }
    }
   
    if (found && done)
      {
        if (templ[i].priority >score) {
  	  winner=i; 
	  score=templ[i].priority;
	  strcpy(winwords, words);
/*	  printf ("the new template is %s\n",templ[i].tplate); */
	}
	  
	if (templ[i].priority == 9) {
	  strcpy(words, winwords);
	  return(winner);
	}
      }
    found=0;
    done=0;
  }
  strcpy(words, winwords);
  return(winner);
}








/**************************************************************************
 phrasefind()
**************************************************************************/
char *phrasefind(string, searchstring)
char *string;
char *searchstring;
{

        while (!isalnum(*string) && (*string != '\0')) string++;
        while (isalnum(*string))
        {
                if (!strncasecmp(string, searchstring, strlen(searchstring)) &&
                        !isalnum(*(string + strlen(searchstring))))
                        return string;
                while (isalnum(*string)) string++;
                while ((*string != '\0') && !isalnum(*string)) string++;
        }
        return NULL;
}

#if 0
int strncasecmp (a, b, n)
char *a;
char *b;
int   n;
{

        for (; (*a != '\0') && (*b != '\0') &&
                (tolow (*a) == tolow (*b)) && (n  > 0); a++, b++, n--);
        if (n == 0)
                return 0;
        return (tolow (*a) - tolow (*b));
}
#endif


void fix()
{
  int i;
  
  gswap("that you", "that I");
  gswap("my", "your");
  gswap("you", "me");
  gswap("your", "my");
  gswap("me", "you");
  gswap("mine", "yours");
  gswap("am", "are");
  gswap("yours", "mine");
  gswap("yourself", "myself");
  gswap("myself", "yourself");
  gswap("are", "am");
  gswap("i", "you");

  for (i=0; words[i] != '\0'; i++)
    words[i] = (words[i] & 0177);              /* readjust parity */
 
}



/*
scan the array "words" for the string OLD.  if it occurs,
replace it by NEW.  also set the parity bits on in the
replacement text to  mark them as already modified
*/
void gswap(old, new)
	char    old[], new[];
{     
	int     i, nlen, olen, flag, base, delim;
	olen = 0;
	while (old[olen] != 0)
		olen++;
	nlen = 0;
	while (new[nlen] != 0)
		nlen++;

	for (base = 0; words[base] != 0; base++) {
		flag = 1;
		for (i = 0; i < olen; i++)
			if (old[i] != words[base + i]) {
				flag = 0;
				break;
			}
		delim = words[base + olen];
		if (flag == 1 && (base == 0 || words[base - 1] == BLANK)
		    && (delim == BLANK || delim == '\n' || delim == 0)) {
			shift(base, nlen - olen);
			for (i = 0; i < nlen; i++)
				words[base + i] = new[i] + 128;
		}
	}
}



void shift(base, delta)
	int     base, delta;
{
	int     i, k;
	if (delta == 0)
		return;
	if (delta > 0) {
		k = base;
		while (words[k] != 0)
			k++;
		for (i = k; i >= base; i--)
			words[i + delta] = words[i];
	} else	/* delta <0 */
		for (i = 0; i == 0 || words[base + i - 1] != 0; i++)
			words[base + i] = words[base + i - delta];
}