/* #module    IdxSpell	"3-001"
 ***********************************************************************
 *                                                                     *
 * The software was developed at the Monsanto Company and is provided  *
 * "as-is".  Monsanto Company and the auther disclaim all warranties   *
 * on the software, including without limitation, all implied warran-  *
 * ties of merchantabilitiy and fitness.                               *
 *                                                                     *
 * This software does not contain any technical data or information    *
 * that is proprietary in nature.  It may be copied, modified, and     *
 * distributed on a non-profit basis and with the inclusion of this    *
 * notice.                                                             *
 *                                                                     *
 ***********************************************************************
 */
/*
 * Module Name:	IdxSpell
 *
 * Author:	R L Aurbach	CR&DS MIS Group    07-May-1986
 *
 * Function:
 *	Build the Spell String for an index term, properly handling LaTeX
 *	syntax and commands.
 *
 * Modification History:
 *
 * Version     Initials	   Date		Description
 * ------------------------------------------------------------------------
 * 1-001	RLA	07-May-1986	Original Code
 * 1-002	RLA	17-Mar-1987	Fix \verb error
 * 1-003	RLA	06-Apr-1987	Fix error processing emphasis
 * 2-004	RLA	16-Apr-1987	Honor the \verb environment in spelling
 * 2-005	RLA	20-Apr-1987	Enhance at-sign string
 * 3-001	F.H.	17-May-1991	converted to portable C
 */
/*
 * Module IdxSpell - Module-Wide Data Description Section
 *
 * Include Files:
 */
#ifdef MSDOS
#include <stdlib.h>
#include <io.h>
#define F_OK		0	/* access(): File exists */
#else
#include <sys/file.h>
extern char *sprintf();
#endif
#include <string.h>
#include <ctype.h>
#include "IdxDef.h"
/*
 * Module Definitions:
 */
#define		    TRUE	1
#define		    FALSE	0
/*
 * Global Declarations:
 */
/*
 * Static Declarations:
 */
#ifdef MSDOS
void idx_build_spell_string(char *desc);
void idx_replace_string(char *string, int start, int length, char *replace);
void idx_collapse_string(char *string);
void idx_process_accent(char *string);
void idx_process_groups(char *string);
int idx_process_verb(char *string);
void idx_process_backslash(char *string);
void idx_process_emphasis(char *string);
int idx_is_verbatim(char *desc, int *ctx, int *index);
void strupcase(char *in, char *out);
void strprefix(char *str, char prefix);
int strposition(char *str, char *e_array, int st);
int chrposition(char str, char *e_array);
#else
void idx_build_spell_string();
void idx_replace_string();
void idx_collapse_string();
void idx_process_accent();
void idx_process_groups();
int idx_process_verb();
void idx_process_backslash();
void idx_process_emphasis();
int idx_is_verbatim();
void strupcase();
void strprefix();
int strposition();
int chrposition();
#endif
static char *accent_set = "`'^\"~=.uvHtcdb";
#define	   emphasis_array_count	    18
    static char *emphasis_array[emphasis_array_count] = {
      "\\rm",
      "\\em",
      "\\bf",
      "\\it",
      "\\sf",
      "\\sl",
      "\\sc",
      "\\tt",
      "\\normalsize",
      "\\small",
      "\\tiny",
      "\\footnotesize",
      "\\large",
      "\\Large",
      "\\LARGE",
      "\\huge",
      "\\Huge",
      "\\cal"};
static char at_sign = '@';
static char *verb = "\\verb";
/*
 * External References:
 */
/*
 * Functions Called:
 */
/*
 * Function Idx_Build_Spell_String - Documentation Section
 *
 * Discussion:
 *	Create a string which can be used to put the token in the right place
 *	in a list of tokens.  The string will be UPPERCASE, will exclude 
 *	internal LaTeX commands which are included for emphasis, and will have
 *	whitespace collapsed into single spaces.
 *
 * Calling Synopsis:
 *	Call Idx_Build_Spell_String (token, desc)
 *
 * Inputs:
 *	token	    ->	is the token to be processed.  ASCIZ string passed by
 *			reference.
 *
 * Outputs:
 *	desc	    ->	is the "Spell String", properly formulated.  Passed by
 *			dynamic string descriptor.
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	none
 *
 * Files Used:
 *	none
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	none
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. Copy the token into a dynamic string.
 *	B. Process Accent commands in the string.
 *	C. Process emphasis commands in the string.
 *	D. Remove grouping characters in the string.
 *	E. Remove backslashes in the string.
 *	F. Process \verb commands in the string.
 *	G. Clean up the string.
 *	    1. Convert it to upper case.
 *	    2. Collapse the string -- i.e., remove non-essential whitespace.
 *	    3. If the string begins with a \, remove it.
 *	    4. Make sure that all strings beginning with symbols are in the
 *	       right place.
 *
 * Special Notes:
 *	none
 */

/*
 * Function Idx_Build_Spell_String - Code Section
 */
void idx_build_spell_string (desc)
    char *desc;
{
/*
 * Local Declarations
 */
/*
 * Module Body
 */
/* Copy the token string into a dynamic string for processing */
/* Process accent strings */
  idx_process_accent(desc);
/* Process emphasis commands */
  idx_process_emphasis(desc);
/* Remove grouping characters */
  idx_process_groups(desc);
/* Remove backslashes */
  idx_process_backslash(desc);
/* Process \verb commands */
  while (idx_process_verb(desc))	    ;
/* Clean up the string */
  strupcase(desc, desc);
  idx_collapse_string (desc);
  if (desc[0] == '\\') idx_replace_string(desc, 1, 1, (char *)0);
  if (desc[0] > 'Z') strprefix(desc, at_sign);
}

/*
 * Function Idx_Replace_String - Documentation Section
 *
 * Discussion:
 *	This function replaces a specified substring in a dynamic string with
 *	a specified replacement string.
 *
 * Calling Synopsis:
 *	Call Idx_Replace_String (string, start, length, replace)
 *
 * Inputs:
 *	string	    ->	is the string to be updated.  The string is a dynamic
 *			string, passed by descriptor.
 *
 *	start	    ->	is the starting position in the string.  The first
 *			position in the string is position 1.  Integer passed
 *			by value.
 *
 *	length	    ->	is the number of characters in the substring to be
 *			replaced.  Integer passed by value.
 *
 *	replace	    ->	is the replacement text.  ASCIZ string passed by 
 *			reference.
 *
 * Outputs:
 *	string	    ->	is the updated string.  It is a dynamic string, passed
 *			by descriptor.
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	none
 *
 * Files Used:
 *	none
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	none
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. Copy the characters up to the first character in the substring to
 *	   be replaced into a temporary string.
 *	B. Copy the replacement string into the temporary string.
 *	C. Copy the remainder of the initial string into the temporary string. 
 *	D. Update the initial string.
 *
 * Special Notes:
 *	It is assumed that the updated string will be no more than 132 
 *	characters long.
 */

/*
 * Function Idx_Replace_String - Code Section
 */
void idx_replace_string (string, start, length, replace)
    char *string;
    int  start;
    int  length;
    char *replace;
{
/*
 * Local Declarations
 */
  int  new_length;	    /* length of new string	    */
  int  rpl_length;	    /* length of the replace string */
  int  left;		    /* number of characters left    */
  char temp[133];	    /* temporary string		    */
/*
 * Module Body
 */
  new_length = 0;
  if (start > 1) {
    (void)strncpy(temp, string, start-1);
    new_length = start-1;
  }
  if (replace != 0) {
    rpl_length = strlen(replace);
    if (rpl_length > 0) {
      (void)strncpy(&temp[new_length], replace, rpl_length);
      new_length += rpl_length;
    }
  }
  left = strlen(string) - (start - 1) - length;
  if (left > 0) {
    (void)strncpy(&temp[new_length], &string[start+length-1], left);
    new_length += left;
  }
  temp[new_length] = '\0';
  string = strcpy(string, temp);
}

/*
 * Function Idx_Collapse_String - Documentation Section
 *
 * Discussion:
 *	Replace the string with a new string which as all extraneous whitespace
 *	removed.  That is, there is no whitespace at the beginning or end of
 *	the string and every internal occurrence of whitespace is collapsed to
 *	a single space character.
 *
 * Calling Synopsis:
 *	Call Idx_Collapse_String (string)
 *
 * Inputs:
 *	string	    ->	is the input string.  It is a dynamic string, passed by
 *			descriptor.
 *
 * Outputs:
 *	string	    ->	is the output string.  It is a dynamic string, passed by
 *			descriptor.
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	none
 *
 * Files Used:
 *	none
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	none
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. For all characters in the input string,
 *	    1. If the character is whitespace,
 *		a. If no characters have been transferred,
 *		    1. Ignore it.
 *		b. If the previous character transferred was a space,
 *		    1. Ignore it.
 *		c. Else,
 *		    1. Copy a space to the output string.
 *	    2. Else,
 *		a. Copy the character to the output string.
 *	B. If the last character in the output string is a space,
 *	    1. Remove it.
 *	C. Update the dynamic string.
 *
 * Special Notes:
 *	It is assumed that the collapsed string will be no more than 132 
 *	characters long.
 */

/*
 * Function Idx_Collapse_String - Code Section
 */
void idx_collapse_string (string)
char *string;
{
/*
 * Local Declarations
 */
  char temp[133];	    /* Working output string	    */
  char copy;		    /* Working character	    */
  int  i;		    /* Array index in input string  */
  int  j;		    /* Array index in temp string   */
/*
 * Module Body
 */
  for (i=0, j=0; i<strlen(string); i++) {
    copy = string[i];
    if (isspace(copy) != 0) {
      if (j == 0) continue;
      else {
	if (temp[j-1] == ' ') continue;
	else temp[j++] = ' ';
      }
    }
    else temp[j++] = copy;
  }
/* Check to see if the temporary string is terminated by whitespace */
  if ((j > 0) && (temp[j-1] == ' ')) j--;
/* Now copy the result to the output string */
  temp[j] = '\0';
  (void)strcpy(string, temp);
}

/*
 * Function Idx_Process_Accents - Documentation Section
 *
 * Discussion:
 *	This routine processes the spell string to remove all LaTeX commands
 *	which generate accents, without changing the spelling.  For example,
 *	the string "se\~{n}or" is translated to "senor".  Without special
 *	accent processing, the spell-string algorithm would produce "se n or",
 *	which might not appear in the proper place in the alphabetical listing.
 *
 * Calling Synopsis:
 *	call Idx_Process_Accents (string)
 *
 * Inputs:
 *	string	    ->	is the spell-string to be processed.  It is a dynamic
 *			string, passed by descriptor.
 *
 * Outputs:
 *	string	    ->	is the resultant spell-string.  It is a dynamic string,
 *			passed by descriptor.
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	none
 *
 * Files Used:
 *	none
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	none
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:.
 *	A. Search the string for an accent pattern:
 *	    1. The first character in the pattern is "\".
 *	    2. The next character in the pattern is one of the characters in
 *	       the accent_set.
 *	    3. The next character in the pattern is "{".
 *	B. Mark the pattern and find the terminating "}".
 *	C. Replace the pattern with the string located within the braces.
 *
 * Special Notes:
 *	none
 */
/*
 * Function Idx_Process_Accent - Code Section
 */ 
void idx_process_accent(string)
char *string;
{
/*
 * Local Declarations
 */
  char   accent_str = '\0';
  int    start;	            /* Start of string to replace   */
  char   *replace;	    /* Replacement string	    */
  int    i;		    /* Loop index		    */
  int    ctx = 0;	    /* context variable		    */
/*
 * Module Body
 */
  for (i = 0; i < strlen(string); i++) {
    if (string[i] != '\\') continue;
    start = ++i;
    accent_str = string[i];
    if (chrposition(accent_str, accent_set) == 0) continue;
    if (string[++i] != '{') continue;
    if (idx_is_verbatim(string, &ctx, &i)) continue;
    replace = &string[++i];
    while (i < strlen(string)) {
      if (string[i++] != '}') continue;
      string[i-1] = '\0';
      break;
    }
    idx_replace_string (string, start, i-start+1, replace);
  }
}

/*
 * Function Idx_Process_Groups - Documentation Section
 *
 * Discussion:
 *	Process the characters which delimit groups ('{', '}', and '$') in the
 *	spell string.  These characters are removed unless they are quoted
 *	(e.g., "{" is removed but "\{" is not).
 *
 * Calling Synopsis:
 *	Call Idx_Process_Groups (String)
 *
 * Inputs:
 *	string	    ->	is the spell string.  It is a dynamic string passed by
 *			descriptor.
 *
 * Outputs:
 *	string	    ->	is the spell string.  It is a dynamic string passed by
 *			descriptor.
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	none
 *
 * Files Used:
 *	none
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	returns with spell string possibly modified.
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. For all characters in the spell string,
 *	    1. If the character is '{', '}', or '$' and the preceeding
 *	       character is not a '\',
 *		a. Remove the character.
 *
 * Special Notes:
 *	none
 */

/*
 * Function Idx_Process_Groups - Code Section
 */ 
void idx_process_groups(string)
char *string;
{
/*
 * Local Declarations
 */
  int    i;		/* Loop index	    */
  int    ctx = 0;	/* Context variable */
/*
 * Module Body
 */
  for (i = 0; i < strlen(string); i++) {
    if ((string[i] == '{')||(string[i] == '}')||(string[i] == '$')) {
      if ((i == 0) || (string[i-1] != '\\')) {
	if (idx_is_verbatim(string, &ctx, &i)) continue;
	idx_replace_string(string, i+1, 1, (char *)0);	
	i--;
      }
    }
  }
}

/*
 * Function Idx_Process_Verb - Documentation Section
 *
 * Discussion:
 *	Process LaTeX \verb and \verb* commands in the spell string.  This is
 *	done by removing the \verb command from the spell string.
 *
 * Calling Synopsis:
 *	status = Idx_Process_Verb (string)
 *
 * Inputs:
 *	string	    ->	Spell string.  A dynamic string passed by descriptor.
 *
 * Outputs:
 *	string	    ->	Spell string.  A dynamic string passed by descriptor.
 *
 * Return Value:
 *	status	    ->	is a boolean integer passed by value.  It indicates
 *			whether or not a \verb command was found in the spell
 *			string.
 *
 * Global Data:
 *	none
 *
 * Files Used:
 *	none
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	status = TRUE	A \verb command was processed in the string.
 *	status = FALSE	No \verb command was processed.
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. Search the string for a \verb command:
 *	    1. \verb [optionally followed by a *]
 *	    2. Next character is not alphabetic
 *	B. Mark the pattern and find the terminating character.
 *	C. Replace the pattern with its argument.
 *
 * Special Notes:
 *	none
 */

/*
 * Function Idx_Process_Verb - Code Section
 */
int idx_process_verb(string)
char *string;
{
/*
 * Local Declarations
 */
  int    i;	        /* Loop index			    */
  int    start; 	/* Start of pattern		    */
  char   delim; 	/* Delimiter character		    */ 
  char   *replace;	/* Pointer to replacement string    */
/*
 * Module Body
 */ 
  if ((strlen(string)) < 7) return (FALSE);
  for (i = 0; i < (strlen(string)-7); i++) { 
    if (strncmp(&string[i], "\\verb", 5) != 0) continue;
    start = i + 1;
    i += 5;
    if (string[i] == '*') i++;
    delim = string[i++]; 
    if (isalpha(delim) != 0) continue;
    replace = &string[i];
    while (i < strlen(string)) {
      if (string[i++] != delim) continue;
      if (i < (strlen(string)-1)) {
	i = strlen(string);
	string[i-1] = delim;
	string[i] = '\0';
	i++;
      }
      else string[i-1] = '\0'; 
      break; 
    }
    idx_replace_string (string, start, i-start+1, replace); 
    return (TRUE);
  } 
  return (FALSE); 
} 

/*
 * Function Idx_Process_Backslash - Documentation Section
 *
 * Discussion:
 *	Remove all '\' characters.
 *
 * Calling Synopsis:
 *	Call Idx_Process_Backslash (string)
 *
 * Inputs:
 *	string	    ->	Spell String.  Dynamic string passed by descriptor.
 *
 * Outputs:
 *	string	    ->	Spell String.  Dynamic string passed by descriptor.
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	none
 *
 * Files Used:
 *	none
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	return
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. For all characters in the spell string,
 *	    1. If the character is a '\',
 *		a. Remove it.
 *
 * Special Notes:
 *	none
 */

/*
 * Function Idx_Process_Backslash - Code Section
 */
void idx_process_backslash(string)
char *string;
{
/*
 * Local Declarations
 */
  int    i;		/* Loop index	    */
  int    ctx = 0;	/* Context variable */
/*
 * Module Body
 */
  for (i = 0; i < strlen(string); i++) {
    if (string[i] == '\\') {
      if (idx_is_verbatim(string, &ctx, &i)) continue;
      idx_replace_string(string, i+1, 1, (char *)0); 
      i--;
    }
  }
}

/*
 * Function Idx_Process_Emphasis - Documentation Section
 *
 * Discussion:
 *	Remove the normal LaTeX emphasis strings (\rm, \em, \bf, \it, \sf,
 *	\sl, \tt, \normalsize, \small, \tiny, \footnotesize, \large, \Large,
 *	\LARGE, \huge, \Huge, \cal).
 *
 * Calling Synopsis:
 *	call Idx_Process_Emphasis (string)
 *
 * Inputs:
 *	string	    ->	Spell string.  Dynamic string passed by descriptor.
 *
 * Outputs:,
 *	string	    ->	Spell string.  Dynamic string passed by descriptor.
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	none 
 *
 * Files Used:
 *	none 
 *
 * Assumed Entry State: 
 *	nones
 *
 * Normal Exit State:
 *	none
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. For each of the listed special commands,
 *	    1. For each occurence of the string which is not part of a word, 
 *		a. Remove it.
 *
 * Special Notes:
 *	none
 */ 
/*
 * Function Idx_Process_Emphasis - Code Sections
 */
void idx_process_emphasis(string)
char *string;
{
/*
 * Local Declarations
 */
  int    i;		/* emphasis_array index		    */
  int    start;		/* starting position		    */
  int    length;	/* length of substring		    */
  int    ctx;		/* context variable		    */
  int    index;		/* string index			    */
  int    rpl_start;	/* start of string to replace	    */
/*
 * Module Body
 */
  for (i = 0; i < emphasis_array_count; i++) {
    ctx = 0;
    start = 0;
    while ((start = strposition(string, emphasis_array[i], start))
	   != -1) {
      rpl_start = start+1;
      index = start;
      length = strlen(emphasis_array[i]); 
      start += length;
/*@@@      if (((start) <= strlen(string)) &&
	  (isalpha(string[start-1]) != 0)) continue;*/
      if (idx_is_verbatim(string, &ctx, &index)) continue;
      idx_replace_string(string, rpl_start, length, (char *)0);
    }
  }
}

/*
 * Function Idx_Is_Verbatim - Documentation Sectione
 *
 * Discussion:
 *	Deterimine if the current string index is within a \verb or \verb*     
 *	range. 
 *
 * Calling Synopsis:
 *	boolean = Idx_Is_Verbatim (desc, ctx, index)
 *
 * Inputs:
 *	desc	    ->	is the character string descriptor being processed.
 *
 *	ctx	    ->	is a context variable, passed by ref.  Internally,
 *			it is the current starting value for the search. 
 *
 *	index	    ->	is the string index being tested. 
 *
 * Outputs:
 *	ctx	    ->	is the value of the first character to follow the	
 *			\verb or \verb* string.
 *
 *	index	    ->	is the new value of the string index.  If the index)
 *			is not in a verbatim, then the value is unchanged. 
 *			If it is in the string, then the index is updated to
 *			the end of the verbatim range.
 *
 * Return Value:
 *	boolean	    ->	is a boolean value.
 *
 * Global Data:
 *	none
 *
 * Files Used:
 *	none
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	boolean = TRUE	    Input index is within the range of a verbatim.
 *			    Index is updated.  Ctx may be updated.
 *	boolean = FALSE	    Input string is not within the range of a verbatim.
 *			    Index and Ctx are unchanged.
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. If index < ctx, then we know that we aren't in a verbatim.
 *	    1. Return FALSE.
 *	B. Find the next verbatim range.  Save the start and end (= ctx).
 *	C. If index < start,
 *	    1. Return FALSE,
 *	D. Else,
 *	    1. Index = end of range.
 *	    2. Return TRUE.
 *
 * Special Notes:
 *	none
 */

/*
 * Function Idx_Is_Verbatim - Code Section
 */
int idx_is_verbatim(desc, ctx, index)
char *desc;
int  *ctx;
int  *index;
{
/*
 * Local Declarationsn
 */
  int    start;
  int    i;
  char   delim;
/*
 * Module Body
 */
  if (*index < *ctx) return(FALSE);
/*
 * Find the next verbatim range.  If there are less than seven characters left
 * in the string, then the remainder of the string cannot contain a \verb 
 * command (because there isn't room).  Set the ctx variable to point to the
 * end of the string and report that we are not within a verbatim.
 */
  if ((strlen(desc) - *ctx) < 7) {
    *ctx = strlen(desc);
    return (FALSE);
  }
/*
 * Search for the next \verb string.  Note that the STR$POSITION routine uses
 * the convention that the first character of the string is position 1 (not 0).
 * If no string was found, then set the ctx to the end of the string and report
 * that we aren't in a verbatim.
 */
  i = *ctx;
  start = strposition(desc, verb, i);
  i = *ctx + 1;
  if (start == -1) { 
    *ctx = strlen(desc);
    return (FALSE);
  }
/*
 * There may be a verbatim in the string.  Its potential starting position is
 * "start" (adjusted to index the string from 0 rather than 1).  If this is
 * the case, then the delimiter character will not be an alpha.
 */
/*  start--;*/
  i = start + 5;
  if (desc[i] == '*')  i++;
  delim = desc[i];
/*
 * If the delimiter is an alpha, then we have not found a verbatim string (it
 * is something else).  If the index we are checking is within the range we've
 * looked at, then we know that it isn't in a verbatim and we can so report.
 *
 * On the other hand, if we haven't gotten far enough into the string yet to
 * know, we must keep looking.  We do this by calling this routine recursively.
 */
  if (isalpha(delim) != 0) {
    *ctx = i;
    if (*index < i) return (FALSE);
    else return(idx_is_verbatim(desc, ctx, index));
  }
/*
 * We have found a real verbatim string.  We search for its end.
 */
  while (i < strlen(desc)) if (desc[++i] == delim) break;
  *ctx = ++i;
/*
 * Now we can check to see if we're ok.  If the index is before the start of
 * the verbatim string, we aren't in it.  If it is in the middle, we are.
 * If it's after the end, we still don't know and have to call ourselves
 * recursively to find out.
 */
  if (*index < start) return(FALSE);
  if (*index < *ctx) {
    *index = *ctx - 1;
    return(TRUE);
  }
  else return(idx_is_verbatim(desc, ctx, index));
}

int strposition(str, e_array, st)
char *str;
char *e_array;
int st;
{
  int i, slen, elen, found;
  slen = strlen(str);
  elen = strlen(e_array);
  found = -1;
  for (i=st; i < (slen-elen); i++) {
    if (strncmp(&str[i],e_array,elen) == 0) {
      found = i;
      break;
    }
  }
  return(found);
}

int chrposition(str, e_array)
char str;
char *e_array;
{
  int i, elen, found;
  elen = strlen(e_array);
  found = 1;
  for (i=0; i < elen; i++)
    if (e_array[i] == str) {
      found = 0;
      break;
    }
  return(found);
}

void strupcase(in,out)
char *in,*out;
{
  int i,len;
  len = strlen(in);
  for (i=0;i<len;i++)
    if ((in[i] >= 'a') && (in[i] <= 'z')) out[i] = in[i]-32;
}

void strprefix(str,prefix)
char *str;
char prefix;
{
  int i,len;
  char tmp,tmp2;
  len = strlen(str);
  i = 0;
  tmp = str[i];
  str[i] = prefix;
  for (i=1;i<=len;i++) {
    tmp2 = str[i+1];
    str[i] = tmp;
    tmp = tmp2;
  }
  str[i] = tmp;
}
