/* kimmo.c -- interface between lisp and PC-Kimmo */



/********************************************************************/
/* modification history:                                            */
/*  10/15/91 -- started by ms.  Works with KCL on SunOS 4.1.1       */
/*  10/21/91 -- BJD got the PCKIMMO interface to work with Lucid    */
/*  11/27/91 -- ms, added tracing support to do_generation and      */
/*              do_recognition                                      */
/*  11/27/91 -- ms, added the ability to load just the rules file   */
/*              or just the lexicon file for a particular language  */
/*  11/27/91 -- ms, the languages linked list now recycles entries  */
/*              if a language's information is loaded more than     */
/*              once                                                */
/*                                                                  */
/* notes:                                                           */
/*   * need to free the previous LANGUAGE structure when a          */
/*     language is loaded a second time.  Is there a way to free    */
/*     just the rules or lexicon portion of a LANGUAGE structure    */
/*     when just rules or lexicon are loaded a second time?         */
/*   * when calling the PC-Kimmo generate() and recognize()         */
/*     functions, should the previous RESULT structure be freed?    */
/*     If so, how is this done?                                     */
/*                                                                  */
/********************************************************************/


/* these are all the include files needed by all the C files in the */
/* PC-Kimmo system */
#include <stdio.h>
#include <ctype.h>
#include <varargs.h>
#include <setjmp.h>
#include <errno.h>
#include <string.h>
#include <memory.h>
/* #include <malloc.h>  *** commented out for Athena. -- sgr */
extern int errno;
#include "pckimmo.h"


/* here we include all the PC-Kimmo C files */
#include "pckfuncs.c"
#include "lexicon.c"
#include "rules.c"
#include "generate.c"
#include "recogniz.c"


/* miscellaneous definitions */
#define FALSE   0
#define TRUE    1
#define SUCCESS 0
#define FAILURE -1


/* comment character in the kimmo rules and lexicon files */
#define COMMENT_CHARACTER ((unsigned char) ';')

#define RULES_FILE    0
#define LEXICON_FILE  1


/* Limit_flag was previously defined in pckimmo.c, so we need to */
/* define it here */
int Limit_flag = 0;


/* element in the languages' linked list */
typedef struct LanguageListElementTag {
  char * language;
  LANGUAGE * langStruct;
  struct LanguageListElementTag * next;
} LanguageListElement;

static LanguageListElement * languageList = NULL; /* the linked list */
static RESULT * resultGlobal = NULL; /* result of the recognize() and */
				     /* generate() functions */



/********************************************************************/
/*                                                                  */
/* load_language -- loads the 'rules' and 'lexicon' files for a     */
/*    particular language                                           */
/*                                                                  */
/* parameters:                                                      */
/*    char * language -- name of the language to load               */
/*    char * rule_file -- path to the language's rule file          */
/*    char * lexicon_file -- path to the language's lexicon file    */
/*                                                                  */
/* returns: SUCCESS or error code                                   */
/*                                                                  */
/********************************************************************/

int load_language (language, rule_file, lexicon_file)
char * language;
char * rule_file;
char * lexicon_file;
{
  int RC;                            /* function return code */

  RC = load_kimmo_rules (language, rule_file);

  if (RC != SUCCESS)
    return RC;

  RC = load_kimmo_lexicon (language, lexicon_file);

  return RC;

}



/********************************************************************/
/*                                                                  */
/* load_kimmo_rules -- loads the 'rules' file for a particular      */
/*    language                                                      */
/*                                                                  */
/* parameters:                                                      */
/*    char * language -- name of the language to load               */
/*    char * rule_file -- path to the language's rule file          */
/*                                                                  */
/* returns: SUCCESS or error code                                   */
/*                                                                  */
/********************************************************************/

int load_kimmo_rules (language, rule_file)
char * language;
char * rule_file;
{
  int RC;                            /* function return code */

  RC = load_kimmo_file (language, rule_file, RULES_FILE);

  return RC;

}



/********************************************************************/
/*                                                                  */
/* load_kimmo_lexicon -- loads the 'lexicon' file for a particular  */
/*    language                                                      */
/*                                                                  */
/* parameters:                                                      */
/*    char * language -- name of the language to load               */
/*    char * lexicon_file -- path to the language's lexicon file    */
/*                                                                  */
/* returns: SUCCESS or error code                                   */
/*                                                                  */
/********************************************************************/

int load_kimmo_lexicon (language, lexicon_file)
char * language;
char * lexicon_file;
{
  int RC;                            /* function return code */

  RC = load_kimmo_file (language, lexicon_file, LEXICON_FILE);

  return RC;

}



/********************************************************************/
/*                                                                  */
/* load_kimmo_file -- loads either a lexicon or rules file for a    */
/*    particular language                                           */
/*                                                                  */
/* parameters:                                                      */
/*    char * language -- name of the language to load               */
/*    char * file_name -- path to the language's rules or lexicon   */
/*       file to load                                               */
/*    int rulesOrLexicon -- which file to load                      */
/*                                                                  */
/* returns: SUCCESS or error code                                   */
/*                                                                  */
/********************************************************************/

int load_kimmo_file (language, file_name, rulesOrLexicon)
char * language;
char * file_name;
int rulesOrLexicon;
{
  LANGUAGE * langStruct;             /* language structure */
  int RC;                            /* function return code */
  int alreadyThere = TRUE;           /* is the language already in the */
				     /* linked list of languages? */

  /* get the language's LANGUAGE structure */
  RC = find_lang_struct (language, &langStruct);

  if (RC != SUCCESS) {

    alreadyThere = FALSE;
    /* allocate memory for a LANGUAGE data structure */
    langStruct = myalloc (sizeof (LANGUAGE));

    if (langStruct == NULL)
      return FAILURE;
  }

  if (rulesOrLexicon == RULES_FILE)
    RC = load_rules (file_name, langStruct, COMMENT_CHARACTER);
  else
    RC = load_lexicons (file_name, langStruct, COMMENT_CHARACTER);

  if (RC != 0) {
    if (!alreadyThere)
      myfree (langStruct);
    return FAILURE;
  }

  /* if the language was not already in the language linked list, put */
  /* it there */
  if (!alreadyThere) {

    RC = add_to_language_list (language, langStruct);

    if (RC != SUCCESS) {
      myfree (langStruct);
      return FAILURE;
    }
  }

  return SUCCESS;

}



/********************************************************************/
/*                                                                  */
/* do_recognition -- invokes the PC-Kimmo 'recognize' function      */
/*                                                                  */
/* parameters:                                                      */
/*    char * language -- name of the language to use                */
/*    char * surfaceForm -- surface form of the word to recognize   */
/*                                                                  */
/* returns: SUCCESS or error code                                   */
/*                                                                  */
/********************************************************************/

int do_recognition (language, surfaceForm, trace)
char * language;
char * surfaceForm;
int trace;
{
  int RC;                            /* function return code */
  LanguageListElement * langStruct;  /* steps through the languages to */
				     /* find the proper one */

  /* find the langauge -- go through the linked list of languages, */
  /* looking for the language with the specified name */
  langStruct = languageList;
  while (langStruct) {
    if (!strcmp (langStruct -> language, language))
      break;
    langStruct = langStruct -> next;
  }

  if (!langStruct)
    return FAILURE;

  /* hopefully 'stdout' will print to the screen in all lisp */
  /* implementations */
  resultGlobal = recognizer (surfaceForm, langStruct -> langStruct, 0,
			     trace, stdout);

  if (resultGlobal == NULL)
    return FAILURE;

#ifdef PRINT_DIAGNOSTICS
  /* go through the resultGlobal list and print out the resultGlobals */
  while (resultGlobal) {
    printf ("Result     : %s\n", resultGlobal -> str);
    printf ("   features: %s\n", resultGlobal -> feat);
    printf ("   okay    : %d\n", resultGlobal -> okay);
    printf ("\n");
    resultGlobal = resultGlobal -> link;
  }
#endif

  return SUCCESS;

}



/********************************************************************/
/*                                                                  */
/* do_generation -- invokes the PC-Kimmo 'generate' function        */
/*                                                                  */
/* parameters:                                                      */
/*    char * language -- name of the language to use                */
/*    char * lexicalForm -- lexical form of the word to generate    */
/*                                                                  */
/* returns: SUCCESS or error code                                   */
/*                                                                  */
/********************************************************************/

int do_generation (language, lexicalForm, trace)
char * language;
char * lexicalForm;
int trace;
{
  int RC;                            /* function return code */
  LanguageListElement * langStruct;  /* steps through the language */
				     /* list to find the proper one */

  /* find the langauge -- go through the linked list of languages, */
  /* looking for the language with the specified name */
  langStruct = languageList;
  while (langStruct) {
    if (!strcmp (langStruct -> language, language))
      break;
    langStruct = langStruct -> next;
  }

  if (!langStruct)
    return FAILURE;

  /* hopefully 'stdout' will print to the screen in all lisp */
  /* implementations */
  resultGlobal = generator (lexicalForm, langStruct -> langStruct, 0,
			    trace, stdout);

  if (resultGlobal == NULL)
    return FAILURE;

#ifdef PRINT_DIAGNOSTICS
  /* go through the resultGlobal list and print out the resultGlobals */
  while (resultGlobal) {
    printf ("Result     : %s\n", resultGlobal -> str);
    printf ("   features: %s\n", resultGlobal -> feat);
    printf ("   okay    : %d\n", resultGlobal -> okay);
    printf ("\n");
    resultGlobal = resultGlobal -> link;
  }
#endif

  return SUCCESS;

}


/********************************************************************/
/*                                                                  */
/* get_result_str1 -- returns the string form of the current        */
/*    result                                                        */
/*                                                                  */
/* parameters: none                                                 */
/*                                                                  */
/* returns: string form of the current result                       */
/*                                                                  */
/********************************************************************/

unsigned char * get_result_str1 ()
{
  unsigned char * string;            /* holds the return value */

  if (!resultGlobal || resultGlobal -> okay)
    return (unsigned char *) "";

  /* return the resultGlobal's string */
  string = resultGlobal -> str;

  return string;

}



/********************************************************************/
/*                                                                  */
/* get_result_str2 -- returns the features string for the current   */
/*    result                                                        */
/*                                                                  */
/* parameters: none                                                 */
/*                                                                  */
/* returns: features string from the current result                 */
/*                                                                  */
/********************************************************************/

unsigned char * get_result_str2 ()
{
  unsigned char * string;            /* holds the return value */

  if (!resultGlobal || resultGlobal -> okay)
    return (unsigned char *) "";

  /* return the resultGlobal's string */
  string = resultGlobal -> feat;

  return string;

}



/********************************************************************/
/*                                                                  */
/* increment_result -- increments the current result, allowing the  */
/*    caller to step through multiple results of a recognition or   */
/*    generation operation                                          */
/*                                                                  */
/* parameters: none                                                 */
/*                                                                  */
/* returns: TRUE if another result was found, FALSE if no more      */
/*    results                                                       */
/*                                                                  */
/********************************************************************/

int increment_result ()
{

  if (!resultGlobal)
    return FALSE;

  resultGlobal = resultGlobal -> link;

  if (!resultGlobal)
    return FALSE;

  return TRUE;

}



/********************************************************************/
/*                                                                  */
/* find_lang_struct -- tries to find a specific language in the     */
/*    linked list of languages.  If the language is found, it       */
/*    returns a pointer to the language's LanguageListElement       */
/*    structure                                                     */
/*                                                                  */
/* parameters:                                                      */
/*    char * language -- name of the language to use                */
/*    LANGUAGE ** langStruct -- returns a pointer to the language's */
/*       LANGUAGE structure in the linked list if the language is   */
/*       indeed in the linked list                                  */
/*                                                                  */
/* returns: SUCCESS or error code                                   */
/*                                                                  */
/********************************************************************/

int find_lang_struct (language, langStruct)
char * language;
LANGUAGE ** langStruct;
{
  LanguageListElement * listPointer;    /* linked list element */

  /* find the langauge -- go through the linked list of languages, */
  /* looking for the language with the specified name */
  listPointer = languageList;
  while (listPointer) {
    if (!strcmp (listPointer -> language, language))
      break;
    listPointer = listPointer -> next;
  }

  if (!listPointer)
    return FAILURE;

  *langStruct = listPointer -> langStruct;
  return SUCCESS;

}



/********************************************************************/
/*                                                                  */
/* add_to_language_list -- adds a language to the linked list of    */
/*    languages                                                     */
/*                                                                  */
/* parameters:                                                      */
/*    char * lafguage -- name of the language to add                */
/*    LANGUAGE * langStruct -- points to the new language's         */
/*       LANGUAGE structure                                         */
/*                                                                  */
/* returns: SUCCESS or error code                                   */
/*                                                                  */
/********************************************************************/

int add_to_language_list (language, langStruct)
char * language;
LANGUAGE * langStruct;
{
  LanguageListElement * newListElement; /* linked list element */

  newListElement = myalloc (sizeof (LanguageListElement));

  if (newListElement == NULL)
    return FAILURE;

  newListElement -> next = languageList;
  newListElement -> langStruct = langStruct;
  newListElement -> language = myalloc (strlen (language) + 1);
  if (newListElement -> language == NULL)
    return FAILURE;
  strcpy (newListElement -> language, language);

  languageList = newListElement;

  return SUCCESS;

}

