/* #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>
#ifndef AMIGA
extern char *sprintf();
#endif
#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");
}
