/* #module    GloBldLab    "2-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:       GloBldLab
 *
 * Author:      R L Aurbach     CR&DS MIS Group    18-Aug-1986
 *
 * Function:
 *      Build the list of labels seen in the input file.  Also, if a file
 *      entry is seen, add it to the filelist.
 *
 * Modification History:
 *
 * Version     Initials    Date         Description
 * ------------------------------------------------------------------------
 * 1-001        RLA     18-Aug-1986     Original Code
 * 1-002        RLA     26-Aug-1986     Fix problem with duplicate label
 *                                        detection.
 * 2-001        F.H.    17-May-1991     converted to portable C
 */

/*
 * $Id: globldlab.c 3.0.1.2 1994/04/04 22:42:59 steppler Exp $
 *
 * $Log: globldlab.c $
 * Revision 3.0.1.2  1994/04/04  22:42:59  steppler
 * real official release now
 *
 * Revision 3.0.1.1  1994/04/04  18:00:23  steppler
 * corrected use of prototypes
 *
 * Revision 3.0  1994/04/03  22:14:05  steppler
 * official release
 *
 * Revision 2.1.2.1  1994/04/03  19:00:28  steppler
 * upgrade to new revision only
 *
 * Revision 2.1.1.2  1994/04/03  18:24:51  steppler
 * Glo_Build_LabLst(): readded \glofile feature
 *
 * Revision 2.1.1.1  1994/04/02  18:55:58  steppler
 * use complete prototypes only
 *
 *
 */

/*
 * Module GloBldLab - Module-Wide Data Description Section
 *
 * Include Files:
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include "GloDef.h"
/*
 * Module Definitions:
 */
/*
 * Global Declarations:
 */
int Glo_Build_LabLst(void);
/*
 * Static Declarations:
 */
/*
 * External References:
 */
extern char infile[256];
extern STRING_PTR labels;
extern STRING_PTR filelist;
/*
 * Functions Called:
 */
static void glo_get_token(char *buffer, char *token);
static int glo_get_next_file(char *token, int *ptr, char *spec);
/*
 * Function Glo_Build_LabLst - Documentation Section
 *
 * Discussion:
 *      Read the input file and use its contents to build a list of labels for
 *      which glossary entries are needed.  If a file specification is seen
 *      during this operation, add the file to the filelist.
 *
 * Calling Synopsis:
 *      status = Glo_Build_LabLst ()
 *
 * Inputs:
 *      none
 *
 * Outputs:
 *      none
 *
 * Return Value:
 *      status      ->  is a status code for the operation.  It is a boolean
 *                      integer, passed by value.  If TRUE, the routine
 *                      completed normally.  If FALSE, an error occurred.
 *
 * Global Data:
 *      labels      ->  the list of labels is created by this routine.
 *
 *      filelist    ->  if one or more files are seen by the routine, they are
 *                      added to the file list.
 *
 * Files Used:
 *      The input file is read.
 *
 * Assumed Entry State:
 *      none
 *
 * Normal Exit State:
 *      status = TRUE   normal successful completion.
 *
 * Error Conditions:
 *      status = FALSE  an error occurred.  The reason for the error is written
 *                      to SYS$OUTPUT.
 *
 * Algorithm:
 *      A. Open the input file.
 *      B. For each record in the file,
 *          1. If it is an \indexentry,
 *             or If it is a \glossaryentry, (TeX 3.0)
 *              a. Parse out the label.
 *              b. If the label does not already appear in the label list,
 *                  1. Build a STRING to contain the label.
 *                  2. Chain it into the label list.
 *          2. If it is a \glofile,
 *              a. For each file in the list,
 *                  1. Parse out the file specification.
 *                  2. Build a STRING to contain the file specification.
 *                  3. Chain it into the file list.
 *          3. Else,
 *              a. Ignore the record.
 *      C. Close the input file.
 *
 * Special Notes:
 *      none
 */
/*
 * Function Glo_Build_LabLst - Code Section
 */
int Glo_Build_LabLst(void)
{
/*
 * Local Declarations
 */
    int status;
    FILE *file;
    char linebf[linesz];
    char label[linesz];
    int found;
    STRING_PTR new;
    STRING_PTR old;
    char spec[linesz];
    int ptr;
    char fname[256];
/*
 * Module Body
 */
/* Open the input file */
    (void) sprintf(fname, "%s.glo", infile);
    if ((file = fopen(fname, "r")) == NULL)
    {
        (void) printf("Could not open the input file\n");
        return (FALSE);
    }
/* For each record in the file, */
    status = TRUE;
    while (fgets(linebf, linesz, file) != 0)
    {
/*
 * If the record begins with \indexentry (or \glossaryentry), then it is
 * a record containing a label.  Process the label by parsing it out,
 * checking for duplicates, and if unique, building a label list entry for it.
 */
        if ((strncmp(linebf, "\\indexentry{", 12)) == 0)
        {
            glo_get_token(&linebf[12], label);
            if (strlen(label) == 0)
                continue;
            old = labels;
            found = FALSE;
            while (old != 0)
            {
                if (strcmp(label, old->desc) == 0)
                    found = TRUE;
                if (old->next == 0)
                    break;
                old = old->next;
            }
            if (!found)
            {
                new = (STRING_PTR) malloc(sizeof(STRING));
                if (new == 0)
                    continue;
                new->next = 0;
                new->desc = strdup(label);
                if (old == 0)
                    labels = new;
                else
                    old->next = new;
            }
        }
        else if ((strncmp(linebf, "\\glossaryentry{", 15)) == 0)
        {
            glo_get_token(&linebf[15], label);
            if (strlen(label) == 0)
                continue;
            old = labels;
            found = FALSE;
            while (old != 0)
            {
                if (strcmp(label, old->desc) == 0)
                    found = TRUE;
                if (old->next == 0)
                    break;
                old = old->next;
            }
            if (!found)
            {
                new = (STRING_PTR) malloc(sizeof(STRING));
                if (new == 0)
                    continue;
                new->next = 0;
                new->desc = strdup(label);
                if (old == 0)
                    labels = new;
                else
                    old->next = new;
            }
        }
/*
 * If the record begins with \glofile, then it is a record containing one or
 * more glossary definition file specifications.  For each specification, parse
 * it out and build a file list entry for it.
 */
        else if ((strncmp(linebf, "\\glofile{", 9)) == 0)
        {
            glo_get_token(&linebf[9], label);
            if (strlen(label) == 0)
                continue;
            ptr = 0;
            while (glo_get_next_file(label, &ptr, spec) != 0)
            {
                new = (STRING_PTR) malloc(sizeof(STRING));
                if (new == 0)
                    continue;
                new->next = 0;
                new->desc = strdup(spec);
                old = filelist;
                if (old == 0)
                    filelist = new;
                else
                {
                    while (old->next != 0)
                        old = old->next;
                    old->next = new;
                }
            }
        }
/*
 * If the record begins with anything else, ignore it.
 */
        else
            continue;
    }
    (void) fclose(file);
    return (status);
}

/*
 * Function Glo_Get_Token - Documentation Section
 *
 * Discussion:
 *      Parse a token from the command line.  The token begins at the first
 *      character position in the buffer and ends with a "}".
 *
 * Calling Synopsis:
 *      Call Glo_Get_Token (buffer, token)
 *
 * Inputs:
 *      buffer      ->  is an ASCIZ string containing the token to be found.
 *
 * Outputs:
 *      token       ->  is an ASCIZ string into which the token is copied.
 *
 * Return Value:
 *      none
 *
 * Global Data:
 *      none
 *
 * Files Used:
 *      none
 *
 * Assumed Entry State:
 *      none
 *
 * Normal Exit State:
 *      The token is returned.
 *
 * Error Conditions:
 *      none
 *
 * Algorithm:
 *      A. Locate the trailing "}" or end of string.
 *      B. Copy the substring starting at the beginning of the buffer to the
 *         end found to the token.
 *      C. Null terminate the string.
 *
 * Special Notes:
 *      none
 */
/*
 * Function Glo_Get_Token - Code Section
 */
static void glo_get_token(char *buffer, char *token)
{
/*
 * Local Declarations
 */
    int len;                    /* Length of the substring              */
/*
 * Module Body
 */
    len = strcspn(buffer, "}");
    (void) strncpy(token, buffer, len);
    token[len] = '\0';
}

/*
 * Function Glo_Get_Next_File - Documentation Section
 *
 * Discussion:
 *      Parse the next file specification out of the token list.  Files are
 *      separated by commas.  Return the length of the specification.
 *
 * Calling Synopsis:
 *      length = Glo_Get_Next_File (token, ptr, spec)
 *
 * Inputs:
 *      token       ->  is an ASCIZ string containing the list of files.
 *
 *      ptr         ->  is an integer (passed by reference) which is the
 *                      starting index in the token string for the search.
 *
 * Outputs:
 *      spec        ->  is an ASCIZ string containing the next file spec.
 *
 * Return Value:
 *      length      ->  is the length of the spec string.  A value of 0
 *                      indicates that there is no file spec.
 *
 * Global Data:
 *      none
 *
 * Files Used:
 *      none
 *
 * Assumed Entry State:
 *      none
 *
 * Normal Exit State:
 *      length != 0     spec contains a file spec.  ptr is updated to point
 *                      to the starting place for the next search.
 *      length == 0     no spec was found.
 *
 * Error Conditions:
 *      none
 *
 * Algorithm:
 *      A. Find the next "," in the string.
 *      B. Copy the substring into the output variable.
 *      C. Adjust the pointer.
 *      D. Return the length of the string.
 *
 * Special Notes:
 *      none
 */
/*
 * Function Glo_Get_Next_File - Code Section
 */
static int glo_get_next_file(char *token, int *ptr, char *spec)
{
/*
 * Local Declarations
 */
    int length;
/*
 * Module Body
 */
    length = strcspn(&token[*ptr], ",");
    if (length != 0)
    {
        (void) strncpy(spec, &token[*ptr], length);
        spec[length] = 0;
        (*ptr) += length;
        if (token[*ptr] == ',')
            (*ptr)++;
    }
    return (length);
}
