home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Guide
/
c-cplusplus-interactive-guide.iso
/
c_ref
/
csource5
/
334_01
/
help.c
< prev
next >
Wrap
Text File
|
1991-02-06
|
16KB
|
599 lines
#include <stdio.h>
extern int errno;
extern int strcmp();
extern int strlen();
extern char *strcpy();
extern char *strncpy();
extern char *strcat();
extern char *strncat();
extern char *getenv();
extern FILE *fopen();
extern char *malloc();
extern int instring();
#define SAME 0 /* for strcmp() */
#include "help.h" /* values passed back */
/* help -- help subsystem that understands defined keywords
**
** Looks for the desired keyword in the help file at runtime, so you
** can give extra help or supply local customizations by merely editing
** the help file.
**
** The original (single-file) idea and algorithm is by John D. Johnson,
** Hewlett-Packard Company. Thanx and a tip of the Hatlo hat!
**
** Much extension by David Kotz for use in gnutex, and then in gnuplot.
** Added output paging support, both unix and builtin. Rewrote completely
** to read helpfile into memory, avoiding reread of help file. 12/89.
**
** The help file looks like this (the question marks are really in column 1):
**
** ?topic
** This line is printed when the user wants help on "topic".
** ?keyword
** ?Keyword
** ?KEYWORD
** These lines will be printed on the screen if the user wanted
** help on "keyword", "Keyword", or "KEYWORD". No casefolding is
** done on the keywords.
** ?subject
** ?alias
** This line is printed for help on "subject" and "alias".
** ?
** ??
** Since there is a null keyword for this line, this section
** is printed when the user wants general help (when a help
** keyword isn't given). A command summary is usually here.
** Notice that the null keyword is equivalent to a "?" keyword
** here, because of the '?' and '??' topic lines above.
** If multiple keywords are given, the first is considered the
** 'primary' keyword. This affects a listing of available topics.
** ?last-subject
** Note that help sections are terminated by the start of the next
** '?' entry or by EOF. So you can't have a leading '?' on a line
** of any help section. You can re-define the magic character to
** recognize in column 1, though, if '?' is too useful. (Try ^A.)
*/
#define KEYFLAG '?' /* leading char in help file topic lines */
/*
** Calling sequence:
** int result; # 0 == success
** char *keyword; # topic to give help on
** char *pathname; # path of help file
** result = help(keyword, pathname);
** Sample:
** cmd = "search\n";
** helpfile = "/usr/local/lib/program/program.help";
** if (help(cmd, helpfile) != H_FOUND)
** printf("Sorry, no help for %s", cmd);
**
**
** Speed this up by replacing the stdio calls with open/close/read/write.
*/
#ifdef WDLEN
# define PATHSIZE WDLEN
#else
# define PATHSIZE BUFSIZ
#endif
typedef int boolean;
#ifndef TRUE
#define TRUE (1)
#define FALSE (0)
#endif
typedef struct line_s LINEBUF;
struct line_s {
char *line; /* the text of this line */
LINEBUF *next; /* the next line */
};
typedef struct linkey_s LINKEY;
struct linkey_s {
char *key; /* the name of this key */
LINEBUF *text; /* the text for this key */
boolean primary; /* TRUE -> is a primary name for a text block */
LINKEY *next; /* the next key in linked list */
};
typedef struct key_s KEY;
struct key_s {
char *key; /* the name of this key */
LINEBUF *text; /* the text for this key */
boolean primary; /* TRUE -> is a primary name for a text block */
};
static LINKEY *keylist; /* linked list of keys */
static KEY *keys = NULL; /* array of keys */
static int keycount = 0; /* number of keys */
static int LoadHelp();
static void sortkeys();
static int keycomp();
static LINEBUF *storeline();
static void storekey();
static KEY *FindHelp();
static boolean Ambiguous();
/* Help output */
static void PrintHelp();
static void ShowSubtopics();
static void StartOutput();
static void OutLine();
static void EndOutput();
static FILE *outfile; /* for unix pager, if any */
static int pagelines; /* count for builtin pager */
#define SCREENSIZE 24 /* lines on screen (most have at least 24) */
/* help:
* print a help message
* also print available subtopics, if subtopics is TRUE
*/
help(keyword, path, subtopics)
char *keyword; /* on this topic */
char *path; /* from this file */
boolean *subtopics; /* (in) - subtopics only? */
/* (out) - are there subtopics? */
{
static char oldpath[PATHSIZE] = ""; /* previous help file */
char *oldpathp = oldpath; /* pointer to same */
int status; /* result of LoadHelp */
KEY *key; /* key that matches keyword */
/*
** Load the help file if necessary (say, first time we enter this routine,
** or if the help file changes from the last time we were called).
** Also may occur if in-memory copy was freed.
** Calling routine may access errno to determine cause of H_ERROR.
*/
errno = 0;
if (strncmp(oldpathp, path, sizeof oldpath) != SAME)
FreeHelp();
if (keys == NULL) {
status = LoadHelp(path);
if (status == H_ERROR)
return(status);
/* save the new path in oldpath */
if (strlen(path) < sizeof oldpath)
(void) strcpy(oldpathp, path);
else { /* not enough room in oldpath, sigh */
(void) strncpy(oldpathp, path, sizeof oldpath);
oldpath[sizeof oldpath] = NULL;
}
}
/* look for the keyword in the help file */
key = FindHelp(keyword);
if (key != NULL) {
/* found the keyword: print help and return */
PrintHelp(key, subtopics);
status = H_FOUND;
} else {
status = H_NOTFOUND;
}
return(status);
}
/* we only read the file once, into memory */
static int
LoadHelp(path)
char *path;
{
FILE *helpfp = NULL;
char buf[BUFSIZ]; /* line from help file */
LINEBUF *head; /* head of text list */
boolean primary; /* first ? line of a set is primary */
if ((helpfp = fopen(path, "r")) == NULL) {
/* can't open help file, so error exit */
return (H_ERROR);
}
/*
** The help file is open. Look in there for the keyword.
*/
(void) fgets(buf, sizeof buf, helpfp);
while (!feof(helpfp)) {
/*
** Make an entry for each synonym keyword, pointing
** to same buffer.
*/
head = storeline( (char *)NULL ); /* make a dummy text entry */
primary = TRUE;
while (buf[0] == KEYFLAG) {
storekey(buf+1, head, primary); /* store this key */
primary = FALSE;
if (fgets(buf, sizeof buf, helpfp) == (char *)NULL)
break;
}
/*
** Now store the text for this entry.
** buf already contains the first line of text.
*/
while (buf[0] != KEYFLAG) {
/* save text line */
head->next = storeline(buf);
head = head->next;
if (fgets(buf, sizeof buf, helpfp) == (char *)NULL)
break;
}
}
(void) fclose(helpfp);
/* we sort the keys so we can use binary search later */
sortkeys();
return(H_FOUND); /* ok */
}
/* make a new line buffer and save this string there */
static LINEBUF *
storeline(text)
char *text;
{
LINEBUF *new;
new = (LINEBUF *)malloc(sizeof(LINEBUF));
if (new == NULL)
int_error("not enough memory to store help file", -1);
if (text != NULL) {
new->line = (char *) malloc((unsigned int)(strlen(text)+1));
if (new->line == NULL)
int_error("not enough memory to store help file", -1);
(void) strcpy(new->line, text);
} else
new->line = NULL;
new->next = NULL;
return(new);
}
/* Add this keyword to the keys list, with the given text */
static void
storekey(key, buffer, primary)
char *key;
LINEBUF *buffer;
boolean primary;
{
LINKEY *new;
key[strlen(key)-1] = '\0'; /* cut off \n */
new = (LINKEY *)malloc(sizeof(LINKEY));
if (new == NULL)
int_error("not enough memory to store help file", -1);
new->key = (char *) malloc((unsigned int)(strlen(key)+1));
if (new->key == NULL)
int_error("not enough memory to store help file", -1);
(void) strcpy(new->key, key);