/* help.c - commands for giving help */
/* $Id: help.c,v 1.31 2004/02/23 04:35:14 rmg Exp $ */
#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "alloc.h" /* required by mudconf */
#include "flags.h" /* required by mudconf */
#include "htab.h" /* required by mudconf */
#include "mudconf.h" /* required by code */
#include "db.h" /* required by externs */
#include "externs.h" /* required by code */
#include "help.h" /* required by code */
int helpindex_read(htab, filename)
HASHTAB *htab;
char *filename;
{
help_indx entry;
char *p;
int count;
FILE *fp;
struct help_entry *htab_entry;
/* Let's clean out our hash table, before we throw it away. */
for (p = hash_firstkey(htab); p; p = hash_nextkey(htab)) {
if (!(hashfindflags(p, htab) & HASH_ALIAS)) {
htab_entry = (struct help_entry *)hashfind(p, htab);
XFREE(htab_entry, "helpindex_read.hent0");
}
}
hashflush(htab, 0);
if ((fp = tf_fopen(filename, O_RDONLY)) == NULL) {
STARTLOG(LOG_PROBLEMS, "HLP", "RINDX")
log_printf("Can't open %s for reading.", filename);
ENDLOG
return -1;
}
count = 0;
while ((fread((char *)&entry, sizeof(help_indx), 1, fp)) == 1) {
/* Lowercase the entry and add all leftmost substrings.
* Substrings already added will be rejected by hashadd.
*/
for (p = entry.topic; *p; p++)
*p = tolower(*p);
htab_entry = (struct help_entry *)XMALLOC(sizeof(struct help_entry),
"helpindex_read.hent1");
htab_entry->pos = entry.pos;
htab_entry->len = entry.len;
if (hashadd(entry.topic, (int *)htab_entry, htab, 0) == 0) {
count++;
while (p > (entry.topic + 1)) {
p--;
*p = '\0';
if (!isspace(*(p-1))) {
if (hashadd(entry.topic, (int *)htab_entry, htab, HASH_ALIAS) == 0) {
count++;
} else {
/* It didn't make it into the hash
* table
*/
break;
}
}
}
} else {
STARTLOG(LOG_ALWAYS, "HLP", "RINDX")
log_printf("Topic already exists: %s",
entry.topic);
ENDLOG
XFREE(htab_entry, "helpindex_read.hent1");
}
}
tf_fclose(fp);
hashreset(htab);
return count;
}
void helpindex_load(player)
dbref player;
{
int i;
char buf[SBUF_SIZE + 8];
if (!mudstate.hfiletab) {
if ((player != NOTHING) && !Quiet(player))
notify(player, "No indexed files have been configured.");
return;
}
for (i = 0; i < mudstate.helpfiles; i++) {
sprintf(buf, "%s.indx", mudstate.hfiletab[i]);
helpindex_read(&mudstate.hfile_hashes[i], buf);
}
if ((player != NOTHING) && !Quiet(player))
notify(player, "Indexed file cache updated.");
}
void NDECL(helpindex_init)
{
/* We do not need to do hashinits here, as this will already have
* been done by the add_helpfile() calls.
*/
helpindex_load(NOTHING);
}
void help_write(player, topic, htab, filename, eval)
dbref player;
char *topic, *filename;
HASHTAB *htab;
int eval;
{
FILE *fp;
char *p, *line, *result, *str, *bp;
int entry_offset, entry_length;
struct help_entry *htab_entry;
char matched;
char *topic_list, *buffp;
if (*topic == '\0')
topic = (char *)"help";
else
for (p = topic; *p; p++)
*p = tolower(*p);
htab_entry = (struct help_entry *)hashfind(topic, htab);
if (htab_entry) {
entry_offset = htab_entry->pos;
entry_length = htab_entry->len;
} else if (strpbrk(topic, "*?\\")) {
matched = 0;
for (result = hash_firstkey(htab); result != NULL;
result = hash_nextkey(htab)) {
if (!(hashfindflags(result, htab) & HASH_ALIAS) &&
quick_wild(topic, result)) {
if (matched == 0) {
matched = 1;
topic_list = alloc_lbuf("help_write");
buffp = topic_list;
}
safe_str(result, topic_list, &buffp);
safe_chr(' ', topic_list, &buffp);
safe_chr(' ', topic_list, &buffp);
}
}
if (matched == 0)
notify(player, tprintf("No entry for '%s'.", topic));
else {
notify(player, tprintf("Here are the entries which match '%s':", topic));
*buffp = '\0';
notify(player, topic_list);
free_lbuf(topic_list);
}
return;
} else {
notify(player, tprintf("No entry for '%s'.", topic));
return;
}
if ((fp = tf_fopen(filename, O_RDONLY)) == NULL) {
notify(player,
"Sorry, that function is temporarily unavailable.");
STARTLOG(LOG_PROBLEMS, "HLP", "OPEN")
log_printf("Can't open %s for reading.", filename);
ENDLOG
return;
}
if (fseek(fp, entry_offset, 0) < 0L) {
notify(player,
"Sorry, that function is temporarily unavailable.");
STARTLOG(LOG_PROBLEMS, "HLP", "SEEK")
log_printf("Seek error in file %s.", filename);
ENDLOG
tf_fclose(fp);
return;
}
line = alloc_lbuf("help_write");
if (eval) {
result = alloc_lbuf("help_write.2");
}
for (;;) {
if (fgets(line, LBUF_SIZE - 1, fp) == NULL)
break;
if (line[0] == '&')
break;
for (p = line; *p != '\0'; p++)
if (*p == '\n')
*p = '\0';
if (eval) {
str = line;
bp = result;
exec(result, &bp, 0, player, player,
EV_NO_COMPRESS | EV_FIGNORE | EV_EVAL, &str,
(char **)NULL, 0);
notify(player, result);
} else
notify(player, line);
}
tf_fclose(fp);
free_lbuf(line);
if (eval) {
free_lbuf(result);
}
}
/* ---------------------------------------------------------------------------
* help_helper: Write entry into a buffer for a function.
*/
void help_helper(player, hf_num, eval, topic, buff, bufc)
dbref player;
int hf_num, eval;
char *topic, *buff, **bufc;
{
char tbuf[SBUF_SIZE + 8];
char tname[LBUF_SIZE];
char *p, *q, *line, *result, *str, *bp;
struct help_entry *htab_entry;
int entry_offset, entry_length, count;
FILE *fp;
if (hf_num >= mudstate.helpfiles) {
STARTLOG(LOG_BUGS, "BUG", "HELP")
log_printf("Unknown help file number: %d", hf_num);
ENDLOG
safe_str((char *) "#-1 NOT FOUND", buff, bufc);
return;
}
if (!topic || !*topic) {
strcpy(tname, (char *) "help");
} else {
for (p = topic, q = tname; *p; p++, q++)
*q = tolower(*p);
*q = '\0';
}
htab_entry = (struct help_entry *) hashfind(tname,
&mudstate.hfile_hashes[hf_num]);
if (!htab_entry) {
safe_str((char *) "#-1 NOT FOUND", buff, bufc);
return;
}
entry_offset = htab_entry->pos;
entry_length = htab_entry->len;
sprintf(tbuf, "%s.txt", mudstate.hfiletab[hf_num]);
if ((fp = tf_fopen(tbuf, O_RDONLY)) == NULL) {
STARTLOG(LOG_PROBLEMS, "HLP", "OPEN")
log_printf("Can't open %s for reading.", tbuf);
ENDLOG
safe_str((char *) "#-1 ERROR", buff, bufc);
return;
}
if (fseek(fp, entry_offset, 0) < 0L) {
STARTLOG(LOG_PROBLEMS, "HLP", "SEEK")
log_printf("Seek error in file %s.", tbuf);
ENDLOG
tf_fclose(fp);
safe_str((char *) "#-1 ERROR", buff, bufc);
return;
}
line = alloc_lbuf("help_helper");
if (eval) {
result = alloc_lbuf("help_helper.2");
}
count = 0;
for (;;) {
if (fgets(line, LBUF_SIZE - 1, fp) == NULL)
break;
if (line[0] == '&')
break;
for (p = line; *p != '\0'; p++)
if (*p == '\n')
*p = '\0';
if (count > 0) {
safe_crlf(buff, bufc);
}
if (eval) {
str = line;
bp = result;
exec(result, &bp, 0, player, player,
EV_NO_COMPRESS | EV_FIGNORE | EV_EVAL, &str,
(char **)NULL, 0);
safe_str(result, buff, bufc);
} else {
safe_str(line, buff, bufc);
}
count++;
}
tf_fclose(fp);
free_lbuf(line);
if (eval) {
free_lbuf(result);
}
}
/* ---------------------------------------------------------------------------
* do_help: display information from new-format news and help files
*/
void do_help(player, cause, key, message)
dbref player, cause;
int key;
char *message;
{
char tbuf[SBUF_SIZE + 8];
int hf_num;
hf_num = key & ~HELP_RAWHELP;
if (hf_num >= mudstate.helpfiles) {
STARTLOG(LOG_BUGS, "BUG", "HELP")
log_printf("Unknown help file number: %d", hf_num);
ENDLOG
notify(player, "No such indexed file found.");
return;
}
sprintf(tbuf, "%s.txt", mudstate.hfiletab[hf_num]);
help_write(player, message, &mudstate.hfile_hashes[hf_num], tbuf,
(key & HELP_RAWHELP) ? 0 : 1);
}