home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
500-599
/
ff502.lzh
/
CELLS
/
CELLSSource.lzh
/
cHelp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-20
|
20KB
|
777 lines
/*
* CELLS An Implementation of the WireWorld cellular automata
* as described in Scientific American, Jan 1990.
*
* Copyright 1990 by Davide P. Cervone.
* You may use this code, provided this copyright notice is kept intact.
* See the CELLS.HELP file for complete information on distribution conditions.
*/
/*
* File: cHelp.c Handles the HELP file system
*/
#include "cGadget.h"
#include "cRequest.h"
#include "cHelp.h"
#include "cReqHelp.h"
#include <stdio.h>
#define MAXERROR 8
#define ABTTEXT ABTRequest.er_Request.ReqText
#define HLPGADGET HLPRequest.er_Request.ReqGadget
extern int HelpActive;
static FILE *HelpFile; /* the HELP file handle */
static char HelpName[] = "HELP:Cells.Help"; /* the name of the file */
#define HELPNAME &(HelpName[5]) /* HelpName without 'HELP:' */
static long LineCount; /* number of lines read */
static char Line[MAXBUFFER]; /* the current line of text */
static int noError; /* TRUE if no errors so far */
static int EndOfFile; /* TRUE if at end of file */
static int CurrentLevel; /* help topic level */
static HELPITEM *CurrentNode; /* current help topic node */
static int TextNotReported; /* TRUE if no error for text */
static int EndHelpSeen; /* TRUE if ENDHELP exists */
static int ErrorCount; /* number of errors found */
/*
* Main help topic tree
*/
HELPITEM HelpRoot =
{NULL,NULL, NULL,0, HLP_STATIC, NULL, 0, NULL,NULL,NULL, 0};
/*
* HelpError()
*
* Set up the message string, and do the error requester
* Count the error, and if enough have already been reported,
* ask if the user wants to keep looking at the file
* Inform him that we are still loading the file
*/
static void HelpError(s,x1,x2,x3,x4)
char *s,*x1,*x2,*x3,*x4;
{
char Message[80];
sprintf(Message,s,x1,x2,x3,x4);
sprintf(&Message[strlen(Message)]," at line %d",LineCount);
DoError(Message);
ErrorCount++;
if (ErrorCount == MAXERROR)
{
noError = DoQuestion("%d Errors: Continue Loading?",ErrorCount);
ErrorCount = 0;
}
DoInfoMessage("Continuing to Load Help...");
}
/*
* FreeHelpItem()
*
* If an topic was given,
* Free its name, if any, and its title text, if any
* If the topic is not a static one, free it
*/
static void FreeHelpItem(theItem)
HELPITEM *theItem;
{
if (theItem)
{
if (theItem->Name && theItem->NameLen)
FREECHAR(theItem->Name,theItem->NameLen);
if (theItem->Title && theItem->TitleLen)
FREECHAR(theItem->Title,theItem->TitleLen);
if ((theItem->Flags & HLP_STATIC) == 0) FREESTRUCT(HelpItem,theItem);
}
}
/*
* FreeLineList()
*
* For each line in the list,
* if the line has text, free it
* if the line is not static, free it
*/
static void FreeLineList(theLine)
HELPLINE *theLine;
{
HELPLINE *tmpLine;
while (theLine)
{
tmpLine = theLine;
theLine = theLine->Next;
if (tmpLine->Text && tmpLine->TextLen)
FREECHAR(tmpLine->Text,tmpLine->TextLen);
if ((tmpLine->Flags & HLP_STATIC) == 0) FREESTRUCT(HelpLine,tmpLine);
}
}
/*
* FreeHelpList()
*
* while ther are more topics in the list,
* Free an subtopics of the topic
* Free any help lines of the topic
* Free the topic itself
*/
static void FreeHelpList(theItem)
HELPITEM *theItem;
{
HELPITEM *tmpItem;
while (theItem)
{
FreeHelpList(theItem->SubTopics);
FreeLineList(theItem->Text);
tmpItem = theItem;
theItem = theItem->Next;
FreeHelpItem(tmpItem);
}
}
/*
* ClearHelp()
*
* If the default help was changed by the file,
* free the (new) default help and reset the default to the standard one
* Free all topics in the help tree
* If the help file is open, close it and mare it as unopen
*/
void ClearHelp()
{
if (DefaultHelpTopic != &DefaultHelp)
{
FreeHelpList(DefaultHelpTopic);
DefaultHelpTopic = &DefaultHelp;
}
FreeHelpList(&HelpRoot);
if (HelpFile) fclose(HelpFile);
HelpFile = NULL;
}
/*
* CanClearText()
*
* While there are more topics
* if the topic is not in use and its text is loaded
* if the topic has text
* free the lines of text and clear the pointer
* mark the topic as not having its text loaded
* indicate that lines have been freed
* if the topic has sub-topics,
* do the same for the sub-topics
* otherwise
* while there are no more topics in the current list, go on to the parent
* go on to the next topic
*/
static int CanClearText(theItem)
HELPITEM *theItem;
{
int status = FALSE;
while (theItem)
{
if ((theItem->Flags & (HLP_INUSE|HLP_LOADED)) == HLP_LOADED)
{
if (theItem->Text)
{
FreeLineList(theItem->Text);
theItem->Text = NULL;
theItem->Flags &= ~HLP_LOADED;
status = TRUE;
}
}
if (theItem->SubTopics)
{
theItem = theItem->SubTopics;
} else {
while (theItem->Next == NULL && theItem->Parent)
theItem = theItem->Parent;
theItem = theItem->Next;
}
}
return(status);
}
/*
* CanClearHelpLines()
*
* Try to clear lines of text from the main help tree and the default help
* tree, and return TRUE if memory was freed.
*/
int CanClearHelpLines()
{
int status = FALSE;
status = CanClearText(&HelpRoot);
if (DefaultHelpTopic != &DefaultHelp)
status |= CanClearText(DefaultHelpTopic);
return(status);
}
/*
* CanClearHelpTopics()
*
* If the help system is not active,
* if there are lines of text in the miain list, or topics in the main list
* or the main list has a title,
* Clear all the help topics, and close the file
* Set the pointers to NULL.
* indicate that the clear was successful
*/
int CanClearHelpTopics()
{
int status = FALSE;
if (!HelpActive)
{
if (HelpRoot.Text || HelpRoot.SubTopics || HelpRoot.Title)
{
ClearHelp();
HelpRoot.Text = NULL;
HelpRoot.SubTopics = NULL;
HelpRoot.Title = NULL;
status = TRUE;
}
}
return(status);
}
/*
* NewHelpItem()
*
* Get a new help topic structure; if successful
* If there is a name for the topic,
* try to allocate space for the name
* if successful, copy the name, otherwise free the help item
* otherwise clera the name area
* If the help item was allocated OK,
* determine its file position and parent
* mark the fact that text errors have not be reported for this item
*/
static HELPITEM *NewHelpItem(s)
char *s;
{
HELPITEM *theItem;
if (NEWSTRUCT(HelpItem,theItem))
{
if (s)
{
theItem->NameLen = strlen(s);
if (NEWCHAR(theItem->Name,theItem->NameLen))
{
strcpy(theItem->Name,s);
} else {
FREESTRUCT(HelpItem,theItem);
theItem = NULL;
}
} else {
theItem->NameLen = 0;
theItem->Name = NULL;
}
if (theItem)
{
theItem->FilePos = ftell(HelpFile);
theItem->Parent = CurrentNode;
TextNotReported = TRUE;
}
}
return(theItem);
}
/*
* NewHelpLine()
*
* Allocate a new help line structure; if successful,
* get space for the line of text (remove the trailing new-line), and
* copy the line of text.
*/
static HELPLINE *NewHelpLine(s)
char *s;
{
HELPLINE *theLine;
short len;
if (NEWSTRUCT(HelpLine,theLine))
{
len = strlen(s);
if (len > 0 && s[len-1] == '\n') s[--len] = 0;
if (NEWCHAR(theLine->Text,len))
{
strcpy(theLine->Text,s);
theLine->TextLen = len;
} else {
FREESTRUCT(HelpLine,theLine);
theLine = NULL;
}
}
return(theLine);
}
/*
* ReadHelpLine()
*
* If there have been no file errors,
* If we can read the next line from the file
* increment the line count
* Otherwise
* if we're at the end of the file, indicate that
* otherwise report the error that occured
*/
static void ReadHelpLine()
{
if (noError)
{
if (fgets(Line,MAXBUFFER,HelpFile))
{
LineCount++;
} else {
if (feof(HelpFile))
{
EndOfFile = TRUE;
} else {
DosError("Read","Help Line");
noError = FALSE;
}
}
} else {
EndOfFile = TRUE;
}
}
/*
* OpenHelp()
*
* Go back to the initial directory for a moment and try to open the
* help file there. If unsuccessful, try to open the file in HELP:
*
* If the file was found,
* clear the line count, and other flags, and start at the top of the tree
* read the first line of the file
* Otherwise report the trouble openning the file
*/
static int OpenHelp()
{
SwapLocks(); HelpFile = fopen(HELPNAME,"r"); SwapLocks();
if (HelpFile == NULL) HelpFile = fopen(HelpName,"r");
if (HelpFile)
{
LineCount = 0;
EndOfFile = FALSE; EndHelpSeen = FALSE;
noError = TRUE; TextNotReported = TRUE; ErrorCount = 0;
CurrentLevel = 0;
CurrentNode = &HelpRoot;
ReadHelpLine();
} else {
DosError("Open",HelpName);
}
return(HelpFile != NULL);
}
/*
* The valid help file commands
*/
static char *HelpCommand[] = {"Title:","Link:","Help:","EndHelp:"};
#define HT_UNKNOWN 0
#define HT_LEVEL 1
#define HT_TITLE 2
#define HT_LINK 3
#define HT_HELP 4
#define HT_END 5
#define HT_COUNT 4
/*
* ParseHelp()
*
* Find the end of the first word on the line, and separate it
* Clear the trailing new-line character, if any
* If the first character is a digit
* calculate the level that is specified
* if there are non-digits following the level number,
* set up for an error
* otherwise
* indicate that a valid level was provided
* move the string pointer on to the beginning of the topic name
* Otherwise (not a digit)
* see if the first word on the line matches one of the commands
* if so, indicate which one, and set the string pointer to the beginning
* of parameterfor the command
*/
static int ParseHelp(Level,s)
int *Level;
char **s;
{
int HelpType = HT_UNKNOWN;
short i;
char *s1;
*s = s1 = &Line[1];
while (*s1 > ' ') s1++;
*s1++ = 0;
while (*s1 && *s1 != '\n') s1++;
*s1++ = 0; *s1 = 0;
if (**s >= '0' && **s <= '9')
{
*Level = 0;
while (**s >= '0' && **s <= '9')
{
*Level = (*Level) * 10 + (**s) - '0';
(*s)++;
}
if (**s)
{
*s = &Line[1];
} else {
HelpType = HT_LEVEL;
(*s)++;
}
} else {
for (i=0; i<HT_COUNT && HelpType == HT_UNKNOWN; i++)
{
if (stricmp(HelpCommand[i],*s) == 0)
{
HelpType = i + HT_TITLE;
*s += strlen(*s) + 1;
}
}
}
return(HelpType);
}
/*
* DoHelpLine()
*
* Find the type of command that was given and do the right thing:
*
* LEVEL:
* if the specified level is not the next lower level or is too small,
* give an error message
* otherwise
* find the help node that is the parent of the required topic level
* get a new topic structure; if successful
* link it into the topic list of the parent topic
* set the current node and level
* otherwise give an error
*
* TITLE:
* if the current topic is linked give an error
* otherwise if the current topic already has a title, give an error
* otherwise
* if a title was supplied as a parameter,
* make a copy of the title, if possible (error if not)
* otherwise report the missing title parameter
*
* LINK:
* if the topic already has a link, report an error
* otherwise, if the topic already has text lines, give an error
* otherwise
* if the topic has a title, warn that it will be ignored, and free it.
* copy the link string to the title area, if possible.
*
* HELP:
* if the default help has not already been changed,
* get a new help topic; if successful
* set up the new item as the new default help root
* otherwise report an error
* otherwise report that HELP has already appeared in the file
*
* END:
* check for proper use of ENDHELP, and if OK, go back to
* using the main help tree at the top level.
*/
static void DoHelpLine()
{
int Level;
char *s;
HELPITEM *theItem;
switch(ParseHelp(&Level,&s))
{
case HT_LEVEL:
if (Level > CurrentLevel+1 || Level < 1)
{
HelpError("Invalid Help Topic Level '%d'",Level);
} else {
while (Level <= CurrentLevel && CurrentNode->Parent)
{
CurrentNode = CurrentNode->Parent;
CurrentLevel--;
}
theItem = NewHelpItem(s);
if (theItem)
{
theItem->Prev = NULL;
theItem->Next = CurrentNode->SubTopics;
if (theItem->Next) theItem->Next->Prev = theItem;
CurrentNode->SubTopics = theItem;
CurrentNode = theItem;
CurrentLevel++;
} else {
HelpError("Can't Get Memory for Help Topic");
}
}
break;
case HT_TITLE:
if (CurrentNode->Flags & HLP_LINKED)
{
HelpError("LINKed Topics can not have TITLES");
} else if (CurrentNode->Title) {
HelpError("Topic already has a TITLE");
} else {
CurrentNode->TitleLen = strlen(s);
if (CurrentNode->TitleLen)
{
if (NEWCHAR(CurrentNode->Title,CurrentNode->TitleLen))
strcpy(CurrentNode->Title,s);
else
HelpError("Can't Get Memory for Topic Title");
} else {
HelpError("TITLE Text String is Blank");
}
}
break;
case HT_LINK:
if (CurrentNode->Flags & HLP_LINKED)
{
HelpError("Topic Already has a LINK");
} else if (CurrentNode->Flags & HLP_HASTEXT) {
HelpError("Topics with Text can not be LINKed");
} else {
if (CurrentNode->Title)
{
HelpError("LINK will cause TITLE to be Ignored");
FREECHAR(CurrentNode->Title,CurrentNode->TitleLen);
}
CurrentNode->TitleLen = strlen(s);
if (CurrentNode->TitleLen)
{
if (NEWCHAR(CurrentNode->Title,CurrentNode->TitleLen))
{
strcpy(CurrentNode->Title,s);
CurrentNode->Flags |= HLP_LINKED;
} else {
HelpError("Can't Get Memory for LINK");
}
} else {
HelpError("LINK String is Blank");
}
}
break;
case HT_HELP:
if (DefaultHelpTopic == &DefaultHelp)
{
theItem = NewHelpItem(NULL);
if (theItem)
{
theItem->Next = theItem->Prev = NULL;
theItem->Parent = NULL;
CurrentNode->SubTopics = NULL;
CurrentNode = theItem;
CurrentLevel = 0;
DefaultHelpTopic = theItem;
} else {
HelpError("Can't Get Memory for Default Help Topic");
}
} else {
HelpError("Duplicate HELP Command Ignored");
}
break;
case HT_END:
if (DefaultHelpTopic == &DefaultHelp)
{
HelpError("ENDHELP Before HELP");
} else if (EndHelpSeen) {
HelpError("Duplicate ENDHELP Command Ignored");
} else {
CurrentNode = &HelpRoot;
CurrentLevel = 0;
EndHelpSeen = TRUE;
}
break;
case HT_UNKNOWN:
HelpError("Unknown HELP Command '%s'",s);
break;
}
}
/*
* LoadHelp()
*
* If the help file is already open, return OK
* otherwise
* put up the info message
* and try to open the help file; if OK
* while there are more lines in the file,
* if the line starts with the command symbol
* do the command it specifies
* otherwise
* if the current topic is linked report the error
* otherwise mark the topic as having text
* read the next line frlom the file
* if an error occured, indicate that the file was not all read
* clear the info message
*/
int LoadHelp()
{
int status = FALSE;
if (HelpFile)
{
status = TRUE;
} else {
DoInfoMessage("Loading Help Topics");
if (OpenHelp())
{
while (!EndOfFile)
{
if (Line[0] == '*' && Line[1] != '*')
{
DoHelpLine();
} else if (Line[0] != '!') {
if ((CurrentNode->Flags & HLP_LINKED) && TextNotReported)
{
HelpError("LINKed Topics can not have Text");
TextNotReported = FALSE;
} else {
CurrentNode->Flags |= HLP_HASTEXT;
}
}
ReadHelpLine();
}
if (noError = FALSE) DoError("Help Topics Not Completely Loaded");
status = TRUE;
}
ClearInfoMessage();
}
return(status);
}
/*
* LoadItem()
*
* If the specified topic is not already loaded and it has text to be loaded
* find the start of the topic in the help file,
* if that was not possible, give an error
* otherwise
* while we're not done with the topic,
* read the next line of text
* if we reached the end of file, we're done,
* otherwise
* if the line is not a command or a comment
* skip duplicate '*' ('**' means '*' as first character of line)
* get a new text line structure
* if allocated OK,
* link the text line into the topics text list
* otherwise give an error and quit
* otherwise if the line is a command
* check whether it is one that ends the help topic
* mark the topic as having its text loaded
* let the user know if it was not completely loaded
*/
void LoadItem(theItem)
HELPITEM *theItem;
{
int NotDone = TRUE;
int Level;
char *s;
HELPLINE *theLine;
if ((theItem->Flags & (HLP_LOADED|HLP_HASTEXT)) == HLP_HASTEXT)
{
if (fseek(HelpFile,theItem->FilePos,0) == -1)
{
DosError("Find","Help Text");
} else {
noError = TRUE;
EndOfFile = FALSE;
EndHelpSeen = FALSE;
while (NotDone)
{
ReadHelpLine(); s = &Line[0];
if (EndOfFile)
{
NotDone = FALSE;
} else {
if ((Line[0] != '*' || Line[1] == '*') && Line[0] != '!')
{
if (Line[0] == '*') s++;
theLine = NewHelpLine(s);
if (theLine)
{
theLine->Prev = NULL;
theLine->Next = theItem->Text;
if (theLine->Next) theLine->Next->Prev = theLine;
theItem->Text = theLine;
} else {
DoError("Can't Get Memory for Help Text");
NotDone = FALSE; noError = FALSE;
}
} else if (Line[0] == '*') {
switch(ParseHelp(&Level,&s))
{
case HT_LEVEL:
case HT_HELP:
case HT_END:
NotDone = FALSE;
break;
}
}
}
}
theItem->Flags |= HLP_LOADED;
if (noError == FALSE) DoError("Text Not Completely Loaded");
}
}
}