#include <stdio.h>
#include <strings.h>
#include <dict_errs.h>
#include <dicterrors.h>
#include <ctype.h>
#include <errno.h>
#include <varargs.h>
#include <dictionary.h>

/*
 * The first line in a definition is the F: line.  The format is as
 * follows:
 *
 * F:FENTNAME;FHOMONO;FPREFSUF;FDOTSS;FACCMRKS;FPOS;FPOSJOIN;FPOS2
 *
 * FENTNAME is the word being defined.
 * FHOMONO is the homonym number of the word.  In other words, if
 * 	there are multiple words with the same definition in the
 * 	dictionary, each one has a different number in this space
 * 	(and, ideally, they should go in ascending order).
 * FPREFSUF contains 'p' if the word being defined is a prefix, 's' if
 * 	the word being defined is a suffix, or nothing otherwise.
 * FDOTSS contains the syllable information for the word.  The
 * 	first digit is the number of characters in the first syllable.
 * 	Subsequent digits record the number of characters in
 * 	subsequent syllables.
 * FACCMRKS contains accent-mark information for the word.
 * FPOS contains the part of speech of the word.
 * FPOSJOIN tells how two parts of speech should be joined, if there
 * 	are two (see the FPOS2 field).  If this field contains '2',
 * 	then they should be writen "POS (or POS2)".  If it contains
 * 	'_', they should be written "POS or POS2".
 * FPOS2 contains the second part of speech of the word, if any.  If
 * 	this field has data in it but the FPOSJOIN field above is
 * 	blank, then we fall back on writing the two figures of speech,
 * 	separated by commas.
 */

fixContinuationLines(definition)
char **definition;
{
     int len = 0;
     char *insert, *defn;

     insert = defn = *definition;
     
     while (*defn) {
	  if (*defn == '\n') {
	       if (*(defn + 1) == 'C') {
		    defn += 2;
		    if (len == 79)
			 *insert++ = ' ';
		    if (*defn != ':') {
			 dict_set_error(DICT_CORRUPT_ENTRY);
			 return(dict_error_code);
		    }
		    defn++;
		    len = 2;
	       }
	       else {
		    *insert++ = *defn++;
		    len = 0;
	       }
	  }
	  else {
	       *insert++ = *defn++;
	       len++;
	  }
     }

     *insert = '\0';
     return(0);
}


stringInsert(string, orig, size, ptr1, ptr2)
char *string, **orig, **ptr1, **ptr2;
int size;
{
     int buflen = strlen(*orig) + 1;
     int str_len = strlen(string);
     int ind1 = *ptr1 - *orig;
     int ind2 = *ptr2 - *orig;
     int diff = ind2 - ind1;
     extern char *realloc();
     
     if (diff >= str_len) {
	  strncpy(*ptr1, string, str_len);
	  *ptr1 += str_len;
	  return(0);
     }

     if (size) {
	  if (size < buflen + str_len - diff) {
	       dict_set_error(DICT_FIELD_TOO_LONG);
	       return(dict_error_code);
	  }
	  *ptr2 = *orig + ind2 + str_len - diff;
     }
     else {
	  *orig = realloc(*orig, (unsigned) (buflen + str_len - diff));
	  if (! *orig) {
	       dict_set_error(errno ? errno : -1);
	       return(dict_error_code);
	  }
	  *ptr1 = *orig + ind1;
	  *ptr2 = *orig + ind2 + str_len - diff;
     }
     
     bcopy(*orig + ind2, *ptr2, buflen - ind2);
     strncpy(*ptr1, string, str_len);
     *ptr1 += str_len;

     return(0);
}



/* char **String1, *stringa1, *stringa2, *stringa3, ..., 0 */
stringAppend(va_alist)
va_dcl
{
     extern char *realloc();
     va_list vars;
     int size = 0;
     char **orig, *str;
     
     va_start(vars);
     orig = va_arg(vars, char **);
     if (! orig)
	  return(0);
     size = strlen(*orig);
     while (str = va_arg(vars, char *)) {
	  size += strlen(str);
     }
     size++;
     va_end(vars);

     va_start(vars);
     orig = va_arg(vars, char **);
     if (! orig)
	  return(0);

     *orig = realloc(*orig, size);
     if (! *orig) {
	  dict_set_error(errno ? errno : -1);
	  return(dict_error_code);
     }
	  
     while (str = va_arg(vars, char *))
	  strcat(*orig, str);
     va_end(vars);
     
     return(0);
}

     
	  

/*
 * There is a lot of repeated code in this function, most notably the
 * default: switch cases to catch errors, but I'm leaving it all in
 * because I think it makes things clearer (and safer) rather than
 * forcing you to pore over the source to figure out when things fall
 * through and where they fall through to.
 *
 * Note that there are no break statements in the switches -- every
 * switch should execute one of its branches, which should result in
 * either the loop continuing or the function returning.
 *
 * If size is 0 below, then the string is assumed to be allocated with
 * malloc() and therefore available for reallocation.  Otherwise, it
 * is the maximum length the fixed string can be.
 */

dumbFixSpecialCharacters(definition, size, in_pronunciation)
char **definition; /* actually char * if size > 0 */
int size;
int in_pronunciation;
{
     char *insert, *defn;
     int retval;

     /*
      * This is really gross -- if size is non-zero, then the
      * definition argument is really a char *, not a char **, since
      * it's an array.  Blech.
      */

     if (size)
	  insert = defn = (char *) definition;
     else
	  insert = defn = *definition;

     while(*defn) {
	  switch(*defn) {
	  case '\010':
	       switch (*(defn - 1)) {
	       case '<':
		    switch (*(defn + 1)) {
		    case '(':
			 /* left curly brace */
			 *(insert - 1) = '{';
			 defn += 2;
			 continue;
		    case '\'':
			 /* single open quote */
			 *(insert - 1) = '`';
			 defn += 2;
			 continue;
		    case 'a':
		    case 'e':
		    case 'E':
			 /* grave accent (slanted down and to the right) */
			 *(insert - 1) = '\\';
			 *insert++ = '`';
			 *insert++ = *++defn;
			 defn++;
			 continue;
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       case '(':
		    switch (*(defn + 1)) {
		    case '|':
			 /* square left bracket */
			 *(insert - 1) = '[';
			 defn += 2;
			 continue;
		    case 'W':
			 /* Begin normal font */
		    case 'X':
			 /* Begin italics */
		    case 'Y':
			 /* Begin boldface */
		    case 'M':
			 /* Begin mini (small caps) */
		    case 'I':
			 /* Begin subscript */
		    case 'J':
			 /* Begin italic subscript */
		    case 'K':
			 /* Begin bold subscript */
		    case 'A':
			 /* Begin superscript */
		    case 'B':
			 /* Begin italic superscript */
		    case 'C':
			 /* Begin bold superscript */
			 insert--;
			 defn += 2;
			 continue;
		    case 'R':
			 /* APL characters */
			 if (! strncmp("->)\010R", defn + 2, 5)) {
			      *(insert - 1) = '-';
			      *insert++ = '>';
			      defn += 7;
			      continue;
			 }
			 else if (! strncmp("-X)\010R", defn + 2, 5)) {
			      *(insert - 1) = '*';
			      defn += 7;
			      continue;
			 }
			 else if (! strncmp("-/)\010R", defn + 2, 5)) {
			      *(insert - 1) = '\\';
			      defn += 7;
			      continue;
			 }
			 else if (! strncmp("\031)\010R", defn + 2, 4)) {
			      *(insert - 1) = '\\';
			      *insert++ = '\"';
			      defn += 6;
			      continue;
			 }
			 else if (! strncmp("@)\010R", defn + 2, 4)) {
			      *(insert - 1) = '~';
			      defn += 6;
			      continue;
			 }
			 else if (! strncmp("\032)\010R", defn + 2, 4)) {
			      *(insert - 1) = '^';
			      defn += 6;
			      continue;
			 }
			 else {
			      dict_set_error(DICT_BAD_ENCODING);
			      return(dict_error_code);
			 }
		    case 'G':
			 /* Greek characters */
			 switch (*(defn + 2)) {
			      char *str = NULL;
			      
			 case '/':
			      switch(isupper(*(defn + 3)) ?
				     tolower(*(defn + 3)) : *(defn + 3)) {
			      case 'a':
				   if (! str) str = "[alpha]";
			      case 'b':
				   if (! str) str = "[beta]";
			      case 'g':
				   if (! str) str = "[gamma]";
			      case 'd':
				   if (! str) str = "[delta]";
			      case 'e':
				   if (! str) str = "[epsilon]";
			      case 'z':
				   if (! str) str = "[zeta]";
			      case 'h':
				   if (! str) str = "[eta]";
			      case 'i':
				   if (! str) str = "[iota]";
			      case 'k':
				   if (! str) str = "[kappa]";
			      case 'l':
				   if (! str) str = "[lambda]";
			      case 'm':
				   if (! str) str = "[mu]";
			      case 'n':
				   if (! str) str = "[nu]";
			      case 'x':
				   if (! str) str = "[xi]";
			      case 'o':
				   if (! str) str = "[omicron]";
			      case 'p':
				   if (! str) str = "[pi]";
			      case 'r':
				   if (! str) str = "[rho]";
			      case 's':
				   if (! str) str = "[sigma]";
			      case 't':
				   if (! str) str = "[tau]";
			      case 'u':
				   if (! str) str = "[upsilon]";
			      case 'c':
				   if (! str) str = "[chi]";
			      case 'v':
				   if (! str) str = "[psi]";
			      case 'w':
				   if (! str) str = "[omega]";

				   if (isupper(*(defn + 3)))
					str[1] = toupper(str[1]);
				   insert--;
				   if (strncmp(")\010G", defn + 4, 3)) {
					dict_set_error(DICT_BAD_ENCODING);
					return(dict_error_code);
				   }
				   defn += 6;
				   retval = stringInsert(str, definition, size,
							 &insert, &defn);
				   if (retval)
					return(retval);
				   continue;
			      case 'f':
				   if ((! isupper(*(defn + 3))) ||
				       strncmp(")\010G", defn + 4, 3)) {
					dict_set_error(DICT_BAD_ENCODING);
					return(dict_error_code);
				   }
				   insert--;
				   defn += 6;
				   retval = stringInsert("[Phi]", definition,
							 size, &insert, &defn);
				   if (retval)
					return(retval);
				   continue;
			      default:
				   dict_set_error(DICT_BAD_ENCODING);
				   return(dict_error_code);
			      }
			 case '-':
			      if (! strncmp("0)\010G", defn + 3, 4)) {
				   insert--;
				   defn += 6;
				   retval = stringInsert("[theta]", definition,
							 size, &insert, &defn);
				   if (retval)
					return(retval);
				   continue;
			      }
			      else if (! strncmp("s)\010G", defn + 3, 4)) {
				   insert--;
				   defn += 6;
				   retval = stringInsert("[final sigma]", size,
							 definition, &insert,
							 &defn);
				   if (retval)
					return(retval);
				   continue;
			      }
			      else if (! strncmp("O)\010G", defn + 3, 4)) {
				   insert--;
				   defn += 6;
				   retval = stringInsert("[Theta]", definition,
							 size, &insert, &defn);
				   if (retval)
					return(retval);
				   continue;
			      }
			      else {
				   dict_set_error(DICT_BAD_ENCODING);
				   return(dict_error_code);
			      }
			 case '|':
			      if (strncmp("o)\010G", defn + 3, 4)) {
				   insert--;
				   defn += 6;
				   retval = stringInsert("[phi]", definition,
							 size, &insert, &defn);
				   if (retval)
					return(retval);
				   continue;
			      }
			      else {
				   dict_set_error(DICT_BAD_ENCODING);
				   return(dict_error_code);
			      }
			 default:
			      dict_set_error(DICT_BAD_ENCODING);
			      return(dict_error_code);
			 }
		    case 'Q':
			 /* Characters represented by their names -- */
			 /* just leave the name in for now	     */
			 *(insert - 1) = '[';
			 defn += 2;
			 continue;
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       case '+':
		    switch (*(defn + 1)) {
		    case '=':
			 /* plus/minus */
			 insert--;
			 defn += 2;
			 retval = stringInsert("plus/minus", definition,
					       size, &insert, &defn);
			 if (retval)
			      return(retval);
			 continue;
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       case '|':
		    switch (*(defn + 1)) {
			 char *str = NULL;
			 
		    case ')':
			 /* square right bracket */
			 *(insert - 1) = ']';
			 defn += 2;
			 continue;
		    case '-':
			 /* dagger */
			 if (! str) str = "[dagger]";
		    case '=':
			 /* double dagger */
			 if (! str) str = "[double dagger]";
		    case 'q':
			 /* paragraph symbol */
			 if (! str) str = "[paragraph]";
		    case 'S':
			 /* section symbol */
			 if (! str) str = "[section]";

			 insert--;
			 defn += 2;
			 retval = stringInsert(str, definition, &insert,
					       size, &defn);
			 if (retval)
			      return(retval);
			 continue;
		    case 'B':
			 /* backspace symbol, or actual backspace when */
			 /* in a pronunciation -- we just skip it in   */
			 /* that case				       */
			 insert--;
			 defn += 2;
			 if (in_pronunciation) {
			      continue;
			 }
			 else {
			      retval = stringInsert("[backspace]", definition,
						    size, &insert, &defn);
			      if (retval)
				   return(retval);
			      continue;
			 }
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       case ')':
		    switch (*(defn + 1)) {
		    case '>':
			 /* right curly brace */
			 *(insert - 1) = '}';
			 defn += 2;
			 continue;
		    case 'Q':
			 *(insert - 1) = ']';
			 defn += 2;
			 continue;
		    case 'W':
			 /* End normal font */
		    case 'X':
			 /* End italics */
		    case 'Y':
			 /* End boldface */
		    case 'M':
			 /* End mini (small caps) */
		    case 'I':
			 /* End subscript */
		    case 'J':
			 /* End italic subscript */
		    case 'K':
			 /* End bold subscript */
		    case 'A':
			 /* End superscript */
		    case 'B':
			 /* End italic superscript */
		    case 'C':
			 /* End bold superscript */
			 insert--;
			 defn += 2;
			 continue;
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       case ';':
		    switch (*(defn + 1)) {
		    case 'c':
		    case 'C':
			 /* cedilla */
			 *(insert - 1) = '\\';
			 *insert++ = 'c';
			 *insert++ = *++defn;
			 defn++;
			 continue;
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       case '~':
		    switch (*(defn + 1)) {
		    case 'a':
		    case 'e':
		    case 'i':
		    case 'o':
		    case 'u':
		    case 'E':
			 /* circumflex */
			 *(insert - 1) = '\\';
			 *insert++ = '~';
			 *insert++ = *++defn;
			 defn++;
			 continue;
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       case '-':
		    switch (*(defn + 1)) {
		    case ':':
			 /* division sign */
			 *(insert - 1) = '/';
			 defn += 2;
			 continue;
		    case 'm':
			 /* m dash */
			 *(insert - 1) = '-';
			 *insert++ = '-';
			 defn += 2;
			 continue;
		    case 'n':
			 /* n dash */
			 *(insert - 1) = '-';
			 defn += 2;
			 continue;
		    case '3':
			 /* ellipsis */
			 *(insert - 1) = '.';
			 *insert++ = '.';
			 *insert++ = '.';
			 defn += 2;
			 continue;
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       case '>':
		    switch (*(defn + 1)) {
		    case '\'':
			 /* single close quote */
			 *(insert - 1) = '\'';
			 defn += 2;
			 continue;
		    case 'a':
		    case 'e':
		    case 'u':
		    case 'E':
			 /* acute (slanted up and right) */
			 *(insert - 1) = '\\';
			 *insert++ = '\'';
			 *insert++ = *++defn;
			 defn++;
			 continue;
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       case '\'':
		    switch (*(defn + 1)) {
		    case '\"':
			 /* straight apostrophe */
			 *(insert - 1) = '\'';
			 defn += 2;
			 continue;
		    case 'b':
			 /* b with a crossed staff */;
			 insert--;
			 defn += 2;
			 retval = stringInsert("[crossed b]", definition,
					       size, &insert, &defn);
			 if (retval)
			      return(retval);
			 continue;
		    case 'o':
			 /* degree */
			 insert--;
			 defn += 2;
			 retval = stringInsert("[degree]", definition,
					       size, &insert, &defn);
			 if (retval)
			      return(retval);
			 continue;
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       case '=':
		    switch (*(defn + 1)) {
		    case 'S':
			 /* integral sign */
			 insert--;
			 defn += 2;
			 retval = stringInsert("[integral]", definition,
					       size, &insert, &defn);
			 if (retval)
			      return(retval);
			 continue;
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       case '\"':
		    switch (*(defn + 1)) {
		    case 'a':
		    case 'e':
		    case 'i':
		    case 'o':
		    case 'u':
		    case 'A':
		    case 'O':
		    case 'U':
			 /* umlaut */
			 *(insert - 1) = '\\';
			 *insert++ = '\"';
			 *insert++ = *++defn;
			 defn++;
			 continue;
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       case ':':
		    switch (*(defn + 1)) {
		    case ':':
			 /* bold colon */
			 *(insert - 1) = ':';
			 defn += 2;
			 continue;
		    default:
			 dict_set_error(DICT_BAD_ENCODING);
			 return(dict_error_code);
		    }
	       default:
		    dict_set_error(DICT_BAD_ENCODING);
		    return(dict_error_code);
	       }
	  default:
	       *insert++ = *defn++;
	       continue;
	  }
     }

     *insert = '\0';
     return(0);
}

getNextField(input, output, length, terminator)
char **input;
char *output;
int length;
char terminator;
{
     char *ptr = output;
     
     while ((**input) && (**input != terminator) && (**input != '\n') &&
	    (ptr - output < length))
	  *ptr++ = *(*input)++;

     if (ptr - output == length) {
	  dict_set_error(DICT_FIELD_TOO_LONG);
	  return(dict_error_code);
     }

     if (**input != terminator) {
	  dict_set_error(DICT_FIELD_UNTERMINATED);
	  return(dict_error_code);
     }

     *ptr = '\0';
     (*input)++;
     
     return(0);
}

charToIndex(chr, ind)
char chr;
int *ind;
{
     if (((chr < '0') && (chr > '9')) &&
	 (chr != '`') &&
	 (chr != '[') && (chr != ']') &&
	 (chr != '{') && (chr != '}') &&
	 (chr != '\010') && (chr != '\033')) {
	  dict_set_error(DICT_CORRUPT_ENTRY);
	  return(dict_error_code);
     }
     switch (chr) {
     case '`':
	  *ind = 10;
	  break;
     case '[':
	  *ind = 11;
	  break;
     case ']':
	  *ind = 12;
	  break;
     case '{':
	  *ind = 13;
	  break;
     case '}':
	  *ind = 14;
	  break;
     case '\001':
	  *ind = 15;
	  break;
     case '\010':
	  *ind = 16;
	  break;
     case '\033':
	  *ind = 18;
	  break;
     case '\036':
	  *ind = 20;
	  break;
     default:
	  *ind = chr - '0';
     }
     return(0);
}

     
dumbDotsAndAccents(word, dots, accents)
char *word;
char *dots;
char *accents;
{
     int i;
     char word2[DICTIONARYLINELENGTH];
     char *ptr, *ptr2;
     int dotind = -1, accind = -1;
     int retval = 0;
     
     /*
      * XXX no bounds checking on the length of the word with dots and
      * accents added
      */

     strcpy(word2, word);
     ptr = word2;
     ptr2 = word;

     if (*dots && (dotind < 0)) {
	  retval = charToIndex(*dots++, &dotind);
	  if (retval)
	       return(retval);
     }

     if (*accents && (accind < 0)) {
	  retval = charToIndex(*accents++, &accind);
	  if (retval)
	       return(retval);
	  accind--;
     }

     while (*ptr) {
	  
	  if (! accind) {
	       /* We've reached where we should drop in an accent */
	       accind = -1;
	       *ptr2++ = '\\';
	       switch (*accents) {
	       case ')':
		    /* accent grave */
		    *ptr2++ = '`';
		    break;
	       case '(':
		    /* accent acute */
		    *ptr2++ = '\'';
		    break;
	       case ':':
		    /* umlaut */
		    *ptr2++ = '\"';
		    break;
	       case '\'':
		    /* circumflex */
		    *ptr2++ = '^';
		    break;
	       case ',':
		    /* cedilla */
		    *ptr2++ = 'c';
		    break;
	       case '@':
		    /* twiddle */
		    *ptr2++ = '~';
		    break;
	       default:
		    dict_set_error(DICT_CORRUPT_ENTRY);
		    return(dict_error_code);
	       }
	       accents++;
	       if (*accents) {
		    retval = charToIndex(*accents++, &accind);
		    if (retval)
			 return(retval);
	       }
	  }

	  if (! dotind) {
	       /* A syllable dot goes here */
	       dotind = -1;
	       *ptr2++ = '.';
	       if (*dots) {
		    retval = charToIndex(*dots++, &dotind);
		    if (retval)
			 return(retval);
	       }
	  }
	  
	  *ptr2++ = *ptr++;
	  accind--, dotind--;
     }

     *ptr2 = '\0';
     return(0);
}



dumbFormat(string, retstr)
char *string;
char **retstr;
{
     char buf[DICTIONARYLINELENGTH*3];
     char word[DICTIONARYLINELENGTH];
     char homono[3];
     char prefsuf;
     char dots[DICTIONARYLINELENGTH];
     char accents[DICTIONARYLINELENGTH];
     char pos[5];
     char posjoin;
     char pos2[5];
     char *defn;
     char label[DICTIONARYLINELENGTH];
     int i;
     int defn_number = 0;
     char defn_letter = '\0';
     int defn_subno = 0;
     int retval;
     extern char *malloc();

     retval = fixContinuationLines(&string);
     if (retval)
	  return(retval);
	       
     *label = '\0';
     
     /*
      * F:FENTNAME;FHOMONO;FPREFSUF;FDOTSS;FACCMRKS;FPOS;FPOSJOIN;FPOS2
      */

     if (strncmp(string, "F:", 2)) {
	  dict_set_error(DICT_CORRUPT_ENTRY);
	  return(dict_error_code);
     }

     string += 2;
     
     retval = getNextField(&string, word, DICTIONARYLINELENGTH, ';');
     if (retval)
	  return(retval);

     retval = getNextField(&string, homono, 3, ';');
     if (retval)
	  return(retval);

     retval = getNextField(&string, buf, 2, ';');
     if (retval)
	  return(retval);

     prefsuf = *buf;
     if (prefsuf && (prefsuf != 'p') && (prefsuf != 's')) {
	  dict_set_error(DICT_CORRUPT_ENTRY);
	  return(dict_error_code);
     }

     retval = getNextField(&string, dots, DICTIONARYLINELENGTH, ';');
     if (retval)
	  return(retval);

     retval = getNextField(&string, accents, DICTIONARYLINELENGTH, ';');
     if (retval)
	  return(retval);

     retval = getNextField(&string, pos, 5, ';');
     if (retval)
	  return(retval);

     retval = getNextField(&string, buf, 2, ';');
     if (retval)
	  return(retval);

     posjoin = *buf;
     if (posjoin && (posjoin != '2') && (posjoin != '_')) {
	  dict_set_error(DICT_CORRUPT_ENTRY);
	  return(dict_error_code);
     }

     retval = getNextField(&string, pos2, 5, '\n');
     if (retval)
	  return(retval);

     defn = malloc((unsigned) 1);
     if (! defn) {
	  dict_set_error(errno ? errno : -1);
	  return(dict_error_code);
     }
     *defn = '\0';
     
     if (*homono) {
	  retval = stringAppend(&defn, homono, ". ", 0);
	  if (retval)
	       return(retval);
     }

     /*
      * Add the dots and accents to the word
      */

     retval = dumbDotsAndAccents(word, dots, accents);
     if (retval)
	  return(retval);

     retval = stringAppend(&defn, word, " ", 0);
     if (retval)
	  return(retval);

     /*
      * Next goes the part of speech
      */

     retval = dumbPartOfSpeech(&defn, pos, posjoin, pos2);
     if (retval)
	  return(retval);
     
     while (*string) {
	  if (string[1] != ':') {
	       dict_set_error(DICT_CORRUPT_ENTRY);
	       return(dict_error_code);
	  }
	  string += 2;
	  switch(*(string - 2)) {
	  case 'L':
	       /*
		* L:SNSNUMBER;SNSLETTER;SNSSUBNO;TEXT
		*/
	       retval = getNextField(&string, buf, 3, ';');
	       if (retval)
		    return(retval);
	       if (*buf)
		    /* Assume it goes with the next line in the file */
		    i = 1;
	       else
		    i = 0;
	       retval = getNextField(&string, buf, 3, ';');
	       if (retval)
		    return(retval);
	       retval = getNextField(&string, buf, 3, ';');
	       if (retval)
		    return(retval);
	       retval = getNextField(&string, label, sizeof(label), '\n');
	       if (retval)
		    return(retval);
	       retval = dumbFixSpecialCharacters(label, sizeof(label), 0);
	       if (retval)
		    return(retval);
	       if (i == 0) {
		    retval = stringAppend(&defn, label, " ", 0);
		    if (retval)
			 return(retval);
		    *label = '\0';
	       }
	       break;
	  case 'P':
	       retval = getNextField(&string, buf, sizeof(buf), '\n');
	       if (retval)
		    return(retval);
	       retval = dumbFixSpecialCharacters(buf, sizeof(buf), 1);
	       if (retval)
		    return(retval);
	       if (*label) {
		    retval = stringAppend(&defn, label, " \\", buf, "\\ ", 0);
		    *label = '\0';
	       }
	       else
		    retval = stringAppend(&defn, "\\", buf, "\\ ", 0);
	       if (retval)
		    return(retval);
	       break;
	  case 'E':
	       retval = getNextField(&string, buf, sizeof(buf), '\n');
	       if (retval)
		    return(retval);
	       retval = dumbFixSpecialCharacters(buf, sizeof(buf), 1);
	       if (retval)
		    return(retval);
	       if (*label) {
		    retval = stringAppend(&defn, label, " [", buf, "] ", 0);
		    *label = '\0';
	       }
	       else
		    retval = stringAppend(&defn, "[", buf, "] ", 0);
	       if (retval)
		    return(retval);
	       break;
	  case 'V':
	       retval = getNextField(&string, word, sizeof(word), ';');
	       if (retval)
		    return(retval);
	       retval = getNextField(&string, dots, sizeof(dots), ';');
	       if (retval)
		    return(retval);
	       retval = getNextField(&string, accents, sizeof(accents), ';');
	       if (retval)
		    return(retval);
	       retval = dumbDotsAndAccents(word, dots, accents);
	       if (retval)
		    return(retval);
	       retval = getNextField(&string, buf, 3, '\n');
	       if (retval)
		    return(retval);
	       if (*buf == '2') {
		    retval = stringAppend(&defn, "; ", 0);
		    if (retval)
			 return(retval);
	       }
	       else if ((*buf != '0') && (*buf != '1')) {
		    dict_set_error(DICT_CORRUPT_ENTRY);
		    return(dict_error_code);
	       }
	       if (*(buf + 1) == '1') {
		    retval = stringAppend(&defn, "or ", word, " ", 0);
		    if (retval)
			 return(retval);
	       }
	       else if (*(buf + 1) == '2') {
		    retval = stringAppend(&defn, "also ", word, " ", 0);
		    if (retval)
			 return(retval);
	       }
	       else {
		    dict_set_error(DICT_CORRUPT_ENTRY);
		    return(dict_error_code);
	       }
	       break;
	  case 'D':
	       retval = dumbDoDefinition(&string, &defn,
					 (*pos && *pos2) ? NULL : pos,
					 label, &defn_number,
					 &defn_letter, &defn_subno);
	       if (retval)
		    return(retval);
	       break;
	  case 'R':
	       /*
		* R:NAME;DOTS;ACCENTS;POS1;POSJOIN;POS2
		*/
	       retval = getNextField(&string, word, sizeof(word), ';');
	       if (retval)
		    return(retval);
	       retval = getNextField(&string, dots, sizeof(dots), ';');
	       if (retval)
		    return(retval);
	       retval = getNextField(&string, accents, sizeof(accents), ';');
	       if (retval)
		    return(retval);
	       retval = dumbDotsAndAccents(word, dots, accents);
	       if (retval)
		    return(retval);
	       retval = stringAppend(&defn, "-- ", word, " ", 0);
	       if (retval)
		    return(retval);
	       retval = getNextField(&string, pos, sizeof(pos), ';');
	       if (retval)
		    return(retval);
	       retval = getNextField(&string, buf, 2, ';');
	       if (retval)
		    return(retval);
	       posjoin = *buf;
	       retval = getNextField(&string, pos2, sizeof(pos2), '\n');
	       if (retval)
		    return(retval);
	       retval = dumbPartOfSpeech(&defn, pos, posjoin, pos2);
	       if (retval)
		    return(retval);
	       break;
	  case 'S':
	       retval = getNextField(&string, buf, sizeof(buf), '\n');
	       if (retval)
		    return(retval);
	       retval = dumbFixSpecialCharacters(buf, sizeof(buf), 0);
	       if (retval)
		    return(retval);
	       retval = stringAppend(&defn, buf, " ", 0);
	       if (retval)
		    return(retval);
	       break;
	  case 'X':
	       retval = dumbXRef(&string, &defn);
	       if (retval)
		    return(retval);
	       break;
	  default:
	       dict_set_error(DICT_CORRUPT_ENTRY);
	       return(dict_error_code);
	  }
     }

     *retstr = defn;
     return(0);
}

dumbDoDefinition(string, defn, pos, label, defn_number, defn_letter,
		 defn_subno)
char **string;
char **defn;
char *pos;
char *label;
int *defn_number;
char *defn_letter;
int *defn_subno;
{
     /*
      * D:SNSNUMBER;SNSLETTER;SNSSUBNO;POS;TEXT
      */

     char numbuf[3];
     char letbuf[2];
     char subnobuf[3];
     char buf[DICTIONARYLINELENGTH*16];
     int new_number = 0;
     char new_letter = '\0';
     int new_subno = 0;
     int retval;
     
     retval = getNextField(string, numbuf, sizeof(numbuf), ';');
     if (retval)
	  return(retval);
     if (*numbuf)
	  new_number = atoi(numbuf);

     retval = getNextField(string, letbuf, sizeof(letbuf), ';');
     if (retval)
	  return(retval);
     if (*letbuf)
	  new_letter = *letbuf;

     retval = getNextField(string, subnobuf, sizeof(subnobuf), ';');
     if (retval)
	  return(retval);
     if (*subnobuf)
	  new_subno = atoi(subnobuf);

     if (new_number) {
	  if (new_number != *defn_number) {
	       retval = stringAppend(defn, numbuf, " ", 0);
	       if (retval)
		    return(retval);
	       if (new_letter) {
		    retval = stringAppend(defn, letbuf, " ", 0);
		    if (retval)
			 return(retval);
		    if (new_subno) {
			 retval = stringAppend(defn, subnobuf, " ", 0);
			 if (retval) {
			      return(retval);
			 }
		    }
	       }
	  }
	  else if (new_letter) {
	       if (new_letter != *defn_letter) {
		    retval = stringAppend(defn, letbuf, " ", 0);
		    if (retval)
			 return(retval);
		    if (new_subno) {
			 retval = stringAppend(defn, subnobuf, " ", 0);
			 if (retval)
			      return(retval);
		    }
	       }
	       else if (new_subno) {
		    if (new_subno != *defn_subno) {
			 retval = stringAppend(defn, subnobuf, " ", 0);
			 if (retval)
			      return(retval);
		    }
	       }
	  }
     }

     *defn_number = new_number;
     *defn_letter = new_letter;
     *defn_subno = new_subno;

     if (*label) {
	  retval = stringAppend(defn, label, " ", 0);
	  if (retval)
	       return(retval);
	  *label = '\0';
     }
     
     retval = stringAppend(defn, ": ", 0);
     if (retval)
	  return(retval);

     retval = getNextField(string, buf, 10, ';');
     if (retval)
	  return(retval);
     if ((! pos) || strcmp(pos, buf)) {
	  retval = stringAppend(defn, buf, " ", 0);
	  if (retval)
	       return(retval);
     }

     retval = getNextField(string, buf, sizeof(buf), '\n');
     if (retval)
	  return(retval);
     retval = dumbFixSpecialCharacters(buf, sizeof(buf), 0);
     if (retval)
	  return(retval);
     
     retval = stringAppend(defn, buf, " ", 0);
     if (retval)
	  return(retval);

     return(0);
}


dumbPartOfSpeech(defn, pos, posjoin, pos2)
char **defn;
char *pos;
char posjoin;
char *pos2;
{
     int retval;
     
     if (pos && *pos) {
	  if (pos2 && *pos2) {
	       if (posjoin == '2') {
		    retval = stringAppend(defn, pos, ". (or ", pos2, ".) ", 0);
		    if (retval)
			 return(retval);
	       }
	       else if (posjoin == '_') {
		    retval = stringAppend(defn, pos, ". or ", pos2, ". ", 0);
		    if (retval)
			 return(retval);
	       }
	       else {
		    retval = stringAppend(defn, pos, "., ", pos2, ". ", 0);
		    if (retval)
			 return(retval);
	       }
	  }
	  else {
	       retval = stringAppend(defn, pos, ". ", 0);
	       if (retval)
		    return(retval);
	  }
     }

     return(0);
}
     


dumbXRef(string, defn)
char **string;
char **defn;
{
     /*
      * X:WORD;WRDSUPER;WRDSUBS;TYPE;WORD2
      */

     char word[DICTIONARYLINELENGTH];
     char word2[DICTIONARYLINELENGTH];
     char buf[5];
     int retval;

     retval = getNextField(string, word, sizeof(word), ';');
     if (retval)
	  return(retval);
     /* Skip the next two fields */
     retval = getNextField(string, buf, sizeof(buf), ';');
     if (retval)
	  return(retval);
     retval = getNextField(string, buf, sizeof(buf), ';');
     if (retval)
	  return(retval);
     retval = getNextField(string, buf, sizeof(buf), ';');
     if (retval)
	  return(retval);
     retval = getNextField(string, word2, sizeof(word2), '\n');
     if (retval)
	  return(retval);
     switch (*buf) {
     case '0':
	  retval = stringAppend(defn, "see \"", word, "\" ", 0);
	  if (retval)
	       return(retval);
	  break;
     case '1':
	  retval = stringAppend(defn, "see \"", word, "\" table ", 0);
	  if (retval)
	       return(retval);
	  break;
     case '3':
	  retval = stringAppend(defn, "see \"", word2, "\" at \"",
				word, "\" table ", 0);
	  if (retval)
	       return(retval);
	  break;
     case '4':
	  retval = stringAppend(defn, "compare \"", word, "\" ", 0);
	  if (retval)
	       return(retval);
	  break;
     case '5':
	  retval = stringAppend(defn, "compare \"", word, "\" table ",
				0);
	  if (retval)
	       return(retval);
	  break;
     case '6':
	  retval = stringAppend(defn, "called also \"", word, "\" ",
				0);
	  if (retval)
	       return(retval);
	  break;
     case '8':
	  retval = stringAppend(defn, "SYN see in addition \"",
				word, "\" ", 0);
	  if (retval)
	       return(retval);
	  break;
     case '9':
	  retval = stringAppend(defn, "SYN see \"", word, "\" ", 0);
	  if (retval)
	       return(retval);
	  break;
     default:
	  dict_set_error(DICT_CORRUPT_ENTRY);
	  return(dict_error_code);
     }
}
