/* #module    IdxParse    "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:	IdxParse
 *
 * Author:	R L Aurbach	CR&DS MIS Group    26-Apr-1986
 *
 * Function:
 *	Parse an input line produced by LaTeX \index command into a form usable
 *	for the generation of an automatic index.
 *
 * Modification History:
 *
 * Version     Initials	   Date		Description
 * ------------------------------------------------------------------------
 * 1-001	RLA	26-Apr-1986	Original Code
 * 2-002	RLA	10-Apr-1987	Add support for the Idx_Extract routine.
 * 2-003	RLA	15-Apr-1987	Add support for cross-referencing
 * 2-004	RLA	20-Apr-1987	Change the cross reference symbol to 
 * 3-001	F.H.	17-May-1991	converted to portable C
 */
/*
 * Module IdxParse - 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 <stdio.h>
#include <string.h>
#include "IdxDef.h"
/*
 * Module Definitions:
 */
#define   TRUE	1
#define   FALSE	0
/*
 * Global Declarations:
 */
/*
 * Static Declarations:
 */
#ifdef MSDOS
void idx_parse(char *linebf, char *token_1, char *token_2,
	char *token_3, char *page_no, int *token_ct, int *flag);
int idx_extract(char *string, int *start, int *length);
#else
void idx_parse();
int idx_extract();
#endif
/*
 * External References:
 */
/*
 * Functions Called:
 */
/*
 * Function Idx_Parse - Documentation Section
 *
 * Discussion:
 *	Parse an input line which is of the general form
 *	    \indexentry{token_1>token_2>token_3}{page_no}
 *	into tokens for "token_1", "token_2", "token_3", and "page_no".
 *	Handle missing tokens and allow for imbedded LaTeX commands.
 *
 * Calling Synopsis:
 *	Call Idx_Parse (linebf, token_1, token_2, token_3, page_no, token_ct, 
 *									flag)
 *
 * Inputs:
 *	linebf	    ->	is the input string containing the line to parse.  
 *			ASCIZ string passed by reference.
 *
 * Outputs:
 *	token_1	    ->	is the first token seen (if any).
 *			ASCIZ string passed by reference.
 *
 *	token_2	    ->	is the second token seen (if any).
 *			ASCIZ string passed by reference.
 *
 *	token_3	    ->	is the third token seen (if any).
 *			ASCIZ string passed by reference.
 *
 *	page_no	    ->	is the page number token (should always be present).
 *			ASCIZ string passed by refernce.
 *
 *	token_ct    ->	is the number of tokens seen.
 *			Integer passed by reference.
 *
 *	flag	    ->	indicates if the page reference is a cross-reference.
 *			Boolean passed by reference.
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	none
 *
 * Files Used:
 *	none
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	returns with the record processed.
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. Initialize variables.
 *	B. Verify that the line begins with \indexentry.
 *	C. Extract the index item substring.
 *	D. Parse it into tokens.
 *	E. Extract the page reference substring.
 *
 * Special Notes:
 *	This logic is designed to:
 *	    * copy sequences such as \{, \}, and $>$ from the input stream
 *	      into tokens without recognizing them as token delimiters.
 *	    * allow sequences such as {\bf text} in token without recognizing
 *	      the special characters as delimiters.
 *	    * allow up to three levels of index and one level of page-no,
 *	      ignoring all other characters (which shouldn't exist...)
 */
/*
 * Function Idx_Parse - Code Section
 */
void idx_parse(linebf,token_1,token_2,token_3,page_no,token_ct,flag)
     char *linebf;	    /* Input string to be parsed	*/
     char *token_1;	    /* First token string		*/
     char *token_2;	    /* Second token string		*/
     char *token_3;	    /* Third token string		*/
     char *page_no;	    /* Page number token string		*/
     int *token_ct;	    /* Number of item tokens seen	*/
     int *flag;		    /* Cross-Reference flag		*/
{
/*
 * Local Declarations
 */
  int	i;		    /* linebf counter			*/
  int	next;		    /* beginning of next substring	*/
  int	len;		    /* length of substring		*/
  int	math_mode = FALSE;  /* math-mode flag			*/
  char	*ptr;		    /* pointer to token buffer		*/
  int	index;		    /* index into token buffer		*/
  int	end;		    /* end of substring			*/
  int dummy;
/*
 * Module Body
 */
/* Initialize assorted variables, flags, etc. */
  token_1[0] = '\0';
  token_2[0] = '\0';
  token_3[0] = '\0';
  page_no[0] = '\0';
  *token_ct  = 0;
  *flag	   = FALSE;
  ptr = token_1;
  index = 0;
/* Verify that the string begins with \indexentry */
  if (strncmp(linebf, "\\indexentry{", 12) != 0) return;
/* Locate the first substring. */
  i = 11;
  next = idx_extract(linebf, &i, &len);
  if (len == 0)	return;
  *token_ct = 1;
  end = i + len;
/* For all characters in the substring, parse out the tokens. */
  for ( ; i < end; i++) {
    switch (linebf[i]) {
    case '$' :
      if (linebf[i-1] != '\\') {
	if (math_mode)  math_mode = FALSE;
	else		math_mode = TRUE;
      }
      ptr[index++] = linebf[i];
      break;
    case '>' :
      if (math_mode)  ptr[index++] = linebf[i];
      else {
	if (index == 0)	break;
	ptr[index] = '\0';
	index = 0;
	switch (*token_ct) {
	case 1 :
	  ptr = token_2;  *token_ct = 2; break;
	case 2 :
	  ptr = token_3;  *token_ct = 3; break;
	}
      }
      break;
    case '&' :
      if (linebf[i-1] == '\\') {
	ptr[index++] = linebf[i];
	break;
      }
      ptr[index] = '\0';
      dummy = end-i;
      (void)sprintf(page_no, "\\indexentry{%.*s}{}", 
		    dummy, &linebf[++i]);
      *flag = TRUE;
      return;
    default :
      ptr[index++] = linebf[i]; break;
    }
  }
  ptr[index] = '\0';
/* Now parse the second substring and copy it to the page-ref. */
  i = next;
  next = idx_extract(linebf, &i, &len);
  (void)strncpy (page_no, &linebf[i], len);
  page_no[len] = '\0';
}

/*
 * Function Idx_Extract - Documentation Section
 *
 * Discussion:
 *	Extract a string contained within a {} pair, which may contain imbedded
 *	LaTeX commands.
 *
 * Calling Synopsis:
 *	next = Idx_Extract (string, start, length)
 *
 * Inputs:
 *	string	    ->	is an ASCIZ string containing a substring enclosed in
 *			matching braces ({}).
 *
 *	start	    ->	is the string index of the first character of the
 *			string to be searched.  It is passed by reference.
 *
 * Outputs:
 *	start	    ->	is the string index of the first character of the
 *			substring, passed by reference.
 *
 *	length	    ->	is the number of characters in the substring, passed by
 *			reference.
 *
 * Return Value:
 *	next	    ->	is the string index of the first character after the
 *			'}' which terminates the substring.  If the substring
 *			is not terminated by '}', next is the string index of
 *			the '\0' character.
 *
 * Global Data:
 *	none
 *
 * Files Used:
 *	none
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	none
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. Scan the string for the first '{'.
 *	B. For all succeeding characters in the string,
 *	    1. If the character is '{' (not preceeded by '\\'),
 *		a. Increment the brace count.
 *	    2. If the character is '}' (not preceeded by '\\'),
 *		a. Decrement the brace count.
 *		b. If the brace count = 0,
 *		    1. Return the start and length of the substring.
 *
 * Special Notes:
 *	none
 */
/*
 * Function Idx_Extract - Code Section
 */
int idx_extract (string, start, length)
     char   *string;
     int    *start;
     int    *length;
{
/*
 * Local Declarations
 */
  int	    i;		    /* string index */
  int	    brace_ct = 0;   /* brace count  */
/*
 * Module Body
 */
/*
 * Scan the string for the first occurrence of a '{' character which is not
 * preceeded by a '\\'.  The next character marks the beginning of the 
 * substring to be extracted.
 */
  for (i = *start; string[i] != '\0'; i++) {
    if (string[i] != '{') continue;
    if (i > 0) if (string[i-1] == '\\')    continue;
    *start = i + 1;
    brace_ct++;
    break;
  }
/*
 * If brace_ct == 0, no leading { was found.  This is an error.  Return
 * start = next = end-of-string and length = 0.
 */
  if (brace_ct == 0) {
    *start = sizeof(string);
    *length = 0;
    return (sizeof(string));
  }
/*
 * Now search the string for a matching }.
 */
  for (i = *start; string[i] != '\0'; i++) {
    if ((string[i] == '{') && (string[i-1] != '\\')) brace_ct++;
    if ((string[i] == '}') && (string[i-1] != '\\')) {
      brace_ct--;
      if (brace_ct == 0) {
	*length = i - *start;
	return (i + 1);
      }
    }
  }
/*
 * If we get here, no closing } was found.  Treat the end of string as a
 * matching }.
 */
  *length = sizeof(string) - *start;
  return (sizeof(string));
}
