/* help.c
   functions to support a multi-section help file */

     /*---------------------------------------------------------------*/
     /* Xgopher        version 1.1     20 April 1991                  */
     /*                version 1.0     04 March 1991                  */
     /* X window system client for the University of Minnesota        */
     /*                                Internet Gopher System.        */
     /* Allan Tuchman, University of Illinois at Urbana-Champaign     */
     /*                Computing Services Office                      */
     /* Copyright 1992 by                                             */
     /*           the Board of Trustees of the University of Illinois */
     /* Permission is granted to freely copy and redistribute this    */
     /* software with the copyright notice intact.                    */
     /*---------------------------------------------------------------*/

/* help file format is:
	++sec_name-1 : title1
	    :
	    :
	++sec_name-i : titlei
	    :
	    :
	<eof>
  Each section is started by a ++ at the beginning of the line, then
  a keyed section name up to the next colon or new-line character
  (or length limit).  The remainder of the line after the colon (if
  anything) is a title to be displayed with the help text.  The
  contents of that named section include all text starting after the
  new-line, up to the next ++ delimiter or end-of-file.

  Sections should be uniquely named.

  The structure below allows the first 20 characters of a section name
  to be saved (and to provide uniqueness).  A fixed length table is
  allocated.  Either of these limits may be made longer.

*/

#include <stdio.h>
#include <string.h>

#include "help.h"
#include "conf.h"
#include "gopher.h"
#include "gui.h"

#define HELP_SEC_NAME_LEN	20
#define HELP_INDEX_LENGTH	20

typedef struct _helpIndexStruct {
	char	sectionName[HELP_SEC_NAME_LEN];
	char	sectionTitle[HELP_SEC_TITLE_LEN];
	int	start;
	int	length;
	} helpIndexStruct;


/* variables global to this file */

static char		helpFileName[PATH_NAME_LEN] = "";
static helpIndexStruct helpIndex[HELP_INDEX_LENGTH];
static int		nSections=0;
static BOOLEAN		fileMsg = FALSE;
static BOOLEAN		indexBuilt = FALSE;


/* setHelpFile
   pass the file name of the help file to these routines for later use */

void
setHelpFile(fn)
char	*fn;
{
	strncpy(helpFileName, fn, PATH_NAME_LEN-1);
	helpFileName[PATH_NAME_LEN-1] = '\0';
}


/* openHelpFile
   open the help file and report an error (the first time) if unsuccessful. */

static FILE *
openHelpFile()
{
	char	message[MESSAGE_STRING_LEN];
	FILE	*fp;

	if ((fp = fopen(helpFileName, "r")) == NULL) {
		if (! fileMsg) {
			sprintf (message,
				"Unable to open the help file (%s)\n",
				helpFileName);
			showError(message);
			fileMsg = TRUE;
		}
	}

	return fp;
}


#ifdef DEBUG
/* printHelpIndex
   dump the help index table - debugging use */

void
printHelpIndex()
{
	int	i;

	fprintf (stderr, "Help index has %d sections.\n", nSections);
	fprintf (stderr, "              name          start   length\n");
	for (i=0; i<nSections; i++) {
		fprintf (stderr, "%2d: \'%20.20s\'  %5d   %5d\n", 
			i, helpIndex[i].sectionName,
			helpIndex[i].start, helpIndex[i].length);
	}
}
#endif


/* buildHelpIndex
   scan the help file and build the indices to the sections */

void
buildHelpIndex()
{
	enum	 {cp_bol, cp_plus, cp_plusplus, cp_other} state;
	FILE	*fp;
	int	n=0;
	
	indexBuilt = TRUE;
	if ((fp = openHelpFile()) == NULL) return;

	state = cp_bol;
	while ( TRUE ) {
		int	ich;
		char	ch;

		if ((ich = getc(fp)) == EOF) {
			if (nSections > 0) {
				helpIndex[nSections-1].length =
					n - helpIndex[nSections-1].start;
			}
			break;
		}

		ch = (char) ich;

		switch (state) {

		    case cp_bol:
			if (ch == '+') state = cp_plus;
			else   if (ch != '\n') state = cp_other;
			break;
		
		    case cp_plus:
			if (ch == '+') state = cp_plusplus;
			else if (ch == '\n') state = cp_bol;
			else state = cp_other;
			break;
		
		    case cp_plusplus:
			if (nSections != 0) {
				helpIndex[nSections-1].length =
					n - helpIndex[nSections-1].start - 2;
			}

			{
			int	i, limit, inTitle=FALSE;
			char	*p;

			i = 0;
			p = helpIndex[nSections].sectionName;
			limit = HELP_SEC_NAME_LEN - 1;
			helpIndex[nSections].sectionTitle[0] = '\0';
			    while (ich != EOF  &&  ich != '\n') {
				if (ich == ':'  &&  ! inTitle) {
					*p = '\0';
					i = 0;
					p = helpIndex[nSections].sectionTitle;
					limit = HELP_SEC_TITLE_LEN - 1;
					inTitle = TRUE;
				} else {
					if (i < limit) *(p++) = (char) ich;
					i++;
				}
				ich = getc(fp);
				n++;
			    }
			*p = '\0';
			}

			helpIndex[nSections].start = n+1;
			nSections++;
			state = cp_bol;
			break;
		
		    case cp_other:
			if (ch == '\n') state = cp_bol;
			break;
			
		}

		n++;
	}

	close(fp);
}


/* getHelpText
   retrieve the help text from the requested section of the file */

char	*
getHelpText(name, title)
char	*name;
char	*title;
{
	char	*string;
	int	i;
	FILE	*fp;
	char	*malloc();

	if (! indexBuilt) buildHelpIndex();
	
	string = NULL;
	title[0] = '\0';

	for (i=0; i<nSections; i++) {
		if (strncmp(name, helpIndex[i].sectionName, HELP_SEC_NAME_LEN)
								== 0) {
			if (helpIndex[i].length == 0) {
				/* no data in section */
				break;
			}
			if ((fp = openHelpFile()) == NULL) {
				/* can't open help file */
				break;
			}

			if ((string = malloc(helpIndex[i].length+1)) == NULL) {
				/* can't malloc string */
				break;
			}

			fseek(fp, helpIndex[i].start, 0);
			fread(string, sizeof (char), helpIndex[i].length, fp);

			string[helpIndex[i].length] = '\0';

			strncpy(title, helpIndex[i].sectionTitle,
							HELP_SEC_TITLE_LEN);

			break;
		}
	}
	close (fp);

	return string;
}
