/* #module    IdxGen    "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:	IdxGen
 *
 * Author:	R L Aurbach	CR&DS MIS Group    28-Apr-1986
 *
 * Function:
 *	Generate the text file used to actually generate the index text.
 *
 * Modification History:
 *
 * Version     Initials	   Date		Description
 * ------------------------------------------------------------------------
 * 1-001	RLA	28-Apr-1986	Original Code
 * 1-002	RLA	03-May-1986	Add support for page-no highlighting
 * 1-003	RLA	14-Jun-1986	Add support for the /TOC qualifier
 * 2-004	RLA	10-Apr-1987	Enhance the visual appearance of the
 *					  index and add support of a master 
 *					  index.
 * 2-005	RLA	11-Apr-1987	Fix spacing around each new group by
 *					  defining the \indexhead macro.
 * 2-006	RLA	14-Apr-1987	Support new page-no highlight option.
 * 2-007	RLA	16-Apr-1987	Add support for cross references.
 * 2-008	RLA	20-Apr-1987	Final formatting enhancements
 * 3-001	F.H.	17-May-1991	converted to portable C
 */

/*
 * Module IdxGen - 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 <stdio.h>
#include <ctype.h>
#include "IdxDef.h"
/*
 * Module Definitions:
 */
#define	    TRUE	1
#define	    FALSE	0
/*
 * Global Declarations:
 */
/*
 * Static Declarations:
 */
#ifdef MSDOS
void idx_generate(FILE *file, int toc_flag, int mst_flag);
void idx_preamble(FILE *file, int toc_flag, int mst_flag);
void idx_new_group(char *test_char, TREE_PTR node, FILE *file);
void idx_write(TREE_PTR node, char *intro_str, FILE *file, int mst_flag);
void idx_postamble(FILE *file);
#else
void idx_generate();
void idx_preamble();
void idx_new_group();
void idx_write();
void idx_postamble();
#endif
/*
 * External References:
 */
#ifdef MSDOS
extern void idx_build_range(TREE_PTR node);
#else
extern void idx_build_range();
#endif
extern TREE_PTR root;
/*
 * Functions Called:
 */
/*
 * Function Idx_Generate - Documentation Section
 *
 * Discussion:
 *	Generate the output file containing the appropriate LaTeX command lines
 *	to generate the index.
 *
 * Calling Synopsis:
 *	Call Idx_Generate (file, toc_flag, mst_flag)
 *
 * Inputs:
 *	file	    ->	is the file descriptor for the current output file.
 *			It is a pointer to FILE.
 *
 *	toc_flag    ->	is a flag indicating what kind of treatment should be
 *			applied to for table-of-contents processing.  It is an
 *			integer, passed by value.  Values are:
 *			    IDX_K_NONE	  - Do nothing.
 *			    IDX_K_ARTICLE - Add a section-oriented toc entry
 *			    IDX_K_REPORT  - Add a chapter-oriented toc entry
 *
 *	mst_flag    ->	is a flag which specifies whether a master index is
 *			being generated.  Volume labels are printed for the
 *			master index.
 *
 * Outputs:
 *	none
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	The Index Tree is used read-only.
 *
 * Files Used:
 *	The current output file is written.
 *
 * Assumed Entry State:
 *	The output file pointed to by the file variable is open.
 *
 * Normal Exit State:
 *	Output is written to the file.
 *
 * Error Conditions:
 *	Errors are ignored, in the sense that they don't generate output.
 *
 * Algorithm:
 *	A. Write pre-amble information.
 *	B. For each item in the primary list,
 *	    1. If the first letter of the entry changed,
 *		a. Output special formatting information.
 *	    2. Process the information for this item.
 *	    3. For each subitem,
 *		a. Process information for this subitem.
 *		b. For each subsubitem,
 *		    1. Process information for this subsubitem.
 *	C. Write post-amble information.
 *
 * Special Notes:
 *	none
 */
/*
 * Function Idx_Generate - Code Section
 */
void idx_generate (file, toc_flag, mst_flag)
     FILE   *file;
     int    toc_flag;
     int    mst_flag;
{
/*
 * Local Declarations
 */
  TREE_PTR  node_1;
  TREE_PTR  node_2;
  TREE_PTR  node_3;
  char	    first_letter;    
  int	    item_count = 0;
  int	    subitem_count = 0;
  int	    subsubitem_count = 0;
/*
 * Module Body
 */ 
/* Write the pre-amble.	*/
  idx_preamble(file, toc_flag, mst_flag);
  node_1 = root;
  first_letter = '+';
/* For each node of the primary tree, */
  while (node_1 != 0) {
    idx_new_group(&first_letter, node_1, file);
    idx_write (node_1, "\\item", file, mst_flag);
    item_count++;
    node_2 = node_1->subhead;
    while (node_2 != 0) {
      idx_write (node_2, "\\subitem", file, mst_flag);
      subitem_count++;
      node_3 = node_2->subhead;
      while (node_3 != 0) {
	idx_write (node_3, "\\subsubitem", file, mst_flag);
	subsubitem_count++;
	node_3 = node_3->link;
      }
      node_2 = node_2->link;
    }
    node_1 = node_1->link;
  }
/* Report the total counts of entries. */
  (void)printf("\nIndex processing statistics:\n");
  (void)printf("    Items:        %d\n",   item_count);
  (void)printf("    Subitems:     %d\n",   subitem_count);
  (void)printf("    Subsubitems:  %d\n\n", subsubitem_count); 
/* Write the post-amble	*/
  idx_postamble(file);
}

/*
 * Function Idx_PreAmble - Documentation Section
 *
 * Discussion:
 *	Write the pre-amble information to the output file.
 *
 * Calling Synopsis:
 *	Call Idx_PreAmble (file, toc_flag)
 *
 * Inputs:
 *	file	    ->	is the file descriptor for the output file.
 *
 *	toc_flag    ->	is a flag used to indicate what treatment should be
 *			performed for table-of-contents processing.  It is
 *			an integer passed by value.  Values are:
 *			    IDX_K_NONE     - Do nothing.
 *			    IDX_K_ARTICLE  - Add a section-oriented toc entry.
 *			    IDX_K_REPORT   - Add a chapter-oriented toc entry.
 *
 * Outputs:
 *	none
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	non
 *
 * Files Used:
 *	The file described by "file" is written.
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	none
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. Write pre-amble information.
 *
 * Special Notes:
 *	none
 */
/*
 * Function Idx_PreAmble - Code Section
 */
void idx_preamble (file, toc_flag, mst_flag)
     FILE   *file;
     int    toc_flag;
     int    mst_flag;
{
/*
 * Local Declarations
 */
/*
 * Module Body
 *
 * Define the \indexhead macro:
 *  \indexhead{BEFORESKIP}{AFTERSKIP}{HEADING} ==
 *	BEGIN
 *	    \par
 *	    IF @nobreak = TRUE
 *		THEN \everypar == null
 *		ELSE \addpenalty{\@secpanalty}
 *		     \addvspace{BEFORESKIP}	
 *	    FI
 *	    \begingroup
 *		\sl HEADING\par
 *	    \endgroup
 *	    \@xsect{AFTERSKIP}
 *	END
 */
  if (mst_flag)
    {
      (void)fprintf(file,"\\def\\indexname{\\masterindexname}\n");
	}
  (void)fprintf (file, "\\makeatletter\n");
  (void)fprintf (file, "\\def\\indexhead#1#2#3{\\par\\if@nobreak \\everypar{}\\else\n");
  (void)fprintf (file, "  \\addpenalty{\\@secpenalty}\\addvspace{#1}\\fi\n");
  (void)fprintf (file, "  \\begingroup \\large\\bf \\hfil #3 \\hfil\\par \\endgroup\n");
  (void)fprintf (file, "  \\@xsect{#2}}\n");
  (void)fprintf (file, "\\makeatother\n");
/*
 * Define the \indexindent macro:
 *  \indexindent == 
 *	\par \hangindent 50pt \hspace*{40pt}
 */
  (void)fprintf (file, "\\def\\indexindent{\\par\\hangindent 50pt\\hspace*{40pt}}\n");
/* Start the index */
  (void)fprintf (file, "\\begin{theindex} \\raggedright\n");
  if (toc_flag == IDX_K_NONE) 
    {
      if (mst_flag)
	{
	(void)fprintf(file, "\\typeout{Master Index.}\n");
         return;
      }
        return;
    }
  if (toc_flag == IDX_K_ARTICLE)
    {
      if (mst_flag)
	{
	  (void)fprintf (file,"\\addcontentsline{toc}{section}{\\masterindexname}\\typeout{Master Index.}\n");
	}
    else
      {    
(void)fprintf (file,"\\addcontentsline{toc}{section}{\\indexname}\\typeout{Index.}\n");
    }
 }
  if (toc_flag == IDX_K_REPORT)
    {
      if (mst_flag)
       (void)fprintf (file,"\\addcontentsline{toc}{chapter}{\\masterindexname}\\typeout{Index.}\n");
    else
    (void)fprintf (file,"\\addcontentsline{toc}{chapter}{\\indexname}\\typeout{Index.}\n");
    }
  (void)printf("\nA Table of Contents entry will be made for the Index.\n");
}

/*
 * Function Idx_New_Group - Documentation Section
 *
 * Discussion:
 *	Handle special processing at the boundaries between index entries 
 *	which begin with different letters.
 *
 * Calling Synopsis:
 *	Call Idx_New_Group (test_char, node, file)
 *
 * Inputs:
 *	test_char	    ->	is the character which is the first character
 *				of the current group. Passed by reference.
 *
 *	node		    ->	is the TREE_PTR for the current node.
 *
 *	file		    ->	is a file pointer for the output file.
 *
 * Outputs:
 *	test_char	    ->	if a new group is declared, the test character
 *				is updated.
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	The Index Tree is read.
 *
 * Files Used:
 *	If a new group is declared, records are written to the output file.
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	none
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. Current_Char is the first character of the Spell String of the
 *	   current node, or a space if the first character is not a letter.
 *	B. If Current_Char != Test_Char,
 *	    1. Generate commands.
 *	    2. Test_Char = Current_Char.
 *
 * Special Notes:
 *	none
 */
/*
 * Function Idx_New_Group - Code Section
 */
void idx_new_group (test_char, node, file)
     char    	*test_char;
     TREE_PTR	node;
     FILE    	*file;
{
/*
 * Local Declarations
 */ 
  char    current_char = ' ';
/*
 * Module Body
 */
  if ((strlen(node->spell)) > 0)
    current_char = node->spell[0];
  if (isalpha(current_char) == 0) current_char = ' ';
  if ((current_char > 'a') && (current_char < 'z'))
    current_char -= 32;
  if (*test_char != current_char) {
    if (current_char == ' ')
      (void)fprintf (file,
		     "\\indexhead{2em}{1em}{--- \\symbolsname ---}\n");
    else
      (void)fprintf (file, "\\indexhead{2em}{1em}{--- %c ---}\n",
		     current_char);
    *test_char = current_char;
  }
}

/*
 * Function Idx_Write - Documentation Section
 *
 * Discussion:
 *	Write the basic text line for the current entry.
 *
 * Calling Synopsis:
 *	Call Idx_Write (node, intro_str, file, mst_flag)
 *
 * Inputs:
 *	node	    ->	TREE_PTR of the node whose data is to be reported.
 *
 *	intro_str   ->	introductory character string, ASCIZ passed by ref.
 *
 *	file	    ->	file pointer for output file.
 *
 *	mst_flag    ->	flag indicates if a master index is being generated.
 *
 * Outputs:
 *	none
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	none
 *
 * Files Used:
 *	The output file is written.
 *
 * Assumed Entry State:
 *	none
 *
 * Normal Exit State:
 *	none
 *
 * Error Conditions:
 *	none
 *
 * Algorithm:
 *	A. Print the first part of the string, containing the item.
 *	B. If there is at least one page number specified,
 *	    1. Print the first page number (which is formatted specially).
 *	    2. For all remaining page numbers,
 *		a. Print them.
 *	C. If there is at least one cross reference specified,
 *	    1. Print the "see" or "see also" line.
 *	    2. For all cross references,
 *		a. Print them.
 *	D. Print the record trailer. 
 *
 * Special Notes:
 *	When printing page numbers, allow for page-no highlighting.  The
 *	highlight code is specified in the pgnode list element.  Recognized
 *	values are:
 *	    IDX_K_NONE	    - No highlighting
 *	    IDX_K_UNDERLINE - Underline the page number
 *	    IDX_K_ITALIC    - Italicize the page number
 *	    IDX_K_BOLD	    - Boldface the page number
 *	    IDX_K_FOLLOW    - ff follows the page number
 */
/*
 * Function Idx_Write - Code Section
 */
void idx_write (node, intro_str, file, mst_flag)
     TREE_PTR   node;
     char       *intro_str;
     FILE       *file;
     int	mst_flag;
{
/*
 * Local Declarations
 */
  char		string[256];
  int		length;
  PGNODE_PTR	pgnode;
  int		highlight;
  char          *old_vol;
/*
 * Module Body
 */
  length = strlen(intro_str) + strlen(node->item) + 1;
  (void)sprintf(string,"%s{%s",intro_str,node->item);
  if (node->pghead != 0) {
    idx_build_range(node);
    pgnode = node->pghead;
    if (mst_flag) {
      (void)sprintf(&string[length], 
		    "}\\indexindent{$\\bullet$ {\\sl %s}, ",
		    pgnode->vol);
      length += strlen(pgnode->vol)
	+ strlen("}\\indexindent{$\\bullet$ {\\sl }, ");
      old_vol = pgnode->vol;
    }
    else {
      (void)sprintf (&string[length], ", ");
      length += 2;
    }
    highlight = pgnode->highlight;
    switch (highlight) {
    case IDX_K_UNDERLINE :
      (void)sprintf (&string[length], 
		     "\\mbox{\\rm\\underline{%s}}",
		     pgnode->page_dsc);
      length += strlen(pgnode->page_dsc)
	+ strlen("\\mbox{\\rm\\underline{}}");
      break;
    case IDX_K_ITALIC :
      (void)sprintf (&string[length], "\\mbox{\\em %s}", 
		     pgnode->page_dsc);
      length += strlen(pgnode->page_dsc)
	+ strlen("\\mbox{\\em }");
      break;
    case IDX_K_BOLD :
      (void)sprintf (&string[length], "\\mbox{\\bf %s}", 
		     pgnode->page_dsc);
      length += strlen(pgnode->page_dsc)
	+ strlen("\\mbox{\\bf }");
      break;
    case IDX_K_FOLLOW :
      (void)sprintf (&string[length], "\\mbox{\\rm %s\\sf ff}",
		     pgnode->page_dsc);
      length += strlen(pgnode->page_dsc)
	+ strlen("\\mbox{\\rm \\sf ff}");
      break;
    default :
      (void)sprintf (&string[length], "\\mbox{\\rm %s}", 
		     pgnode->page_dsc);
      length += strlen(pgnode->page_dsc)
	+ strlen("\\mbox{\\rm }");
      break;
    }
    while ((pgnode = pgnode->link) != 0) {
      if (length > 62) {
	(void)fprintf (file, "%s%%\n", string);
	length = 0;
      }
      if (mst_flag) {
	if ((strcmp(old_vol,pgnode->vol)) != 0) {
	  (void)sprintf (&string[length], 
			 "}\\indexindent{$\\bullet$ {\\sl %s} ",
			 pgnode->vol);
	  length += strlen(pgnode->vol)
	    + strlen("}\\indexindent{$\\bullet$ {\\sl } ");
	  old_vol = pgnode->vol;
	}	
	else {
	  (void)sprintf (&string[length], ", ");
	  length += 2;
	}
      }
      else {
	(void)sprintf (&string[length], ", ");
	length += 2;
      }
      highlight = pgnode->highlight;
      switch (highlight) {
      case IDX_K_UNDERLINE :
	(void)sprintf (&string[length], 
		       "\\mbox{\\rm\\underline{%s}}", 
		       pgnode->page_dsc);
	length += strlen(pgnode->page_dsc)
	  + strlen("\\mbox{\\rm\\underline{}}");
	break;
      case IDX_K_ITALIC :
	(void)sprintf (&string[length], "\\mbox{\\em %s}", 
		       pgnode->page_dsc);
	length += strlen(pgnode->page_dsc)
	  + strlen("\\mbox{\\em ");
	break;
      case IDX_K_BOLD :
	(void)sprintf(&string[length], "\\mbox{\\bf %s}", 
		      pgnode->page_dsc);
	length += strlen(pgnode->page_dsc)
	  + strlen("\\mbox{\\bf ");
	break;
      case IDX_K_FOLLOW :
	(void)sprintf(&string[length],
		       "\\mbox{\\rm %s\\sf ff}",
		       pgnode->page_dsc);
	length += strlen(pgnode->page_dsc)
	  + strlen("\\mbox{\\rm \\sf ff}");
	break;
      default :
	(void)sprintf (&string[length], "\\mbox{\\rm %s}", 
		       pgnode->page_dsc);
	length += strlen(pgnode->page_dsc)
	  + strlen("\\mbox{\\rm }");
	break;
      }
    }
  }
  if (node->seehead != 0) {
    pgnode = node->seehead;
    if (mst_flag) {
      if (node->pghead == 0)
	(void)fprintf (file, "%s}\n\\indexindent{\\em \\seename", string);
      else
	(void)fprintf (file, "%s}\n\\indexindent{\\em \\alsoname",
		       string);
    }
    else {
      if (node->pghead == 0)
	(void)fprintf (file, "%s, {\\em \\seename}\n", string);
      else
	(void)fprintf (file, "%s; {\\em \\alsoname}\n", string);
    }
    length = 0;
    while (pgnode != 0)	{
      if (length > 62) {
	(void)fprintf (file, "%s%%\n", string);
	length = 0;
      }
      highlight = pgnode->highlight;
      switch(highlight) {
      case IDX_K_UNDERLINE :
	(void)sprintf (&string[length],
		       "}\\indexindent{\\ $\\bullet$ \\rm\\underline{%s}",
		       pgnode->page_dsc);
	length += strlen(pgnode->page_dsc)
	  + strlen("}\\indexindent{\\ $\\bullet$ \\rm\\underline{}");
	break;
      case IDX_K_ITALIC :
	(void)sprintf (&string[length],
		       "}\\indexindent{\\ $\\bullet$ {\\em %s}",
		       pgnode->page_dsc);
	length += strlen(pgnode->page_dsc)
	  + strlen("}\\indexindent{\\ $\\bullet$ {\\em }");
	break;
      case IDX_K_BOLD :
	(void)sprintf (&string[length],
		       "}\\indexindent{\\ $\\bullet$ {\\bf %s}",
		       pgnode->page_dsc);
	length += strlen(pgnode->page_dsc)
	  + strlen("}\\indexindent{\\ $\\bullet$ {\\bf }");
	break;
      default :
	(void)sprintf (&string[length], 
		       "}\\indexindent{\\ $\\bullet$ {\\rm %s}",
		       pgnode->page_dsc);
	length += strlen(pgnode->page_dsc)
	  + strlen("}\\indexindent{\\ $\\bullet$ {\\rm }");
	break;
      }
      pgnode=pgnode->link;
    }
  }
  (void)fprintf (file, "%s}\n", string);
}

/*
 * Function Idx_PostAmble - Documentation Sectionm
 *
 * Discussion:
 *	Write the lines which occur at the end of the file.
 *
 * Calling Synopsis:
 *	Call Idx_PostAmble (file);
 *
 * Inputs:
 *	file	    ->	is the file pointer for the output file.*
 *
 * Outputs:r
 *	none 
 *
 * Return Value:
 *	none
 *
 * Global Data:
 *	none
 *
 * Files Used:
 *	Output file is written.
 *
 * Assumed Entry State: 
 *	none 
 *
 * Normal Exit State: 
 *	none 
 *
 * Error Conditions:
 *	none 
 *
 * Algorithm: 
 *	A. Write the end-matter.
 *
 * Special Notes:
 *	none
 */
/*
 * Function Idx_PostAmble - Code Section
 */
void idx_postamble (file)
     FILE *file;
{
/*
 * Local Declarationst
 */
/*
 * Module Body
 */
  (void)fprintf (file, "\\end{theindex}\n");
}
