/* help.c */ #include "config.h" /* * This file is part of TeenyMUD II. * Copyright(C) 1993, 1994, 1995 by Jason Downs. * All rights reserved. * * TeenyMUD II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * TeenyMUD II is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file 'COPYING'); if not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. * */ #include <stdio.h> #include <sys/types.h> #ifdef HAVE_STRING_H #include <string.h> #else #include <strings.h> #endif /* HAVE_STRING_H */ #include <ctype.h> #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #else #include <time.h> #endif /* HAVE_SYS_TIME_H */ #include <sys/stat.h> #include "conf.h" #include "teeny.h" #include "commands.h" #include "externs.h" #include "hash/hash.h" /* * The TeenyMUD help system is implemented by scanning the file(s) and * building an associative array (hash table), resolving subjects to * file offsets. It hadles both ``old fashioned'' 32bit offsets, and * newer, large, file offsets. * * The table(s) are rebuilt automatically, if the time stamp on the file(s) * change. */ static Hash_Table HelpTable; static Hash_Table NewsTable; static int HelpTableInited = 0; static int NewsTableInited = 0; static char buffer[128]; static struct stat sbuf; static char *Mod_Entry = "FMODTIME"; static void init_table _ANSI_ARGS_((FILE *, Hash_Table *)); static void free_help _ANSI_ARGS_((Hash_Table *)); static void init_table(fd, table) FILE *fd; Hash_Table *table; { register char *p; Hash_Entry *hash; int new; #if (SIZEOF_OFF_T > SIZEOF_INT_P) register int *offset; off_t where; #endif Hash_InitTable(table, 0, HASH_STRCASE_KEYS); while (!feof(fd) && (fgets(buffer, sizeof(buffer), fd) != NULL)) { if ((buffer[0] == '&') && buffer[1]) { remove_newline(buffer); for (p = buffer; p[0] && !isspace(p[0]); p++); for (; p[0] && isspace(p[0]); p++); if (!p[0]) continue; hash = Hash_CreateEntry(table, p, &new); #if (SIZEOF_OFF_T > SIZEOF_INT_P) offset = (int *)ty_malloc(sizeof(off_t), "init_table"); where = ftell(fd); bcopy((VOID *)&where, (VOID *)offset, sizeof(off_t)); Hash_SetValue(hash, offset); #else Hash_SetValue(hash, (int *) ftell(fd)); #endif } } } void help_init() { Hash_Entry *hash; int new; FILE *fd; if (!HelpTableInited) { if ((stat(mudconf.help_file, &sbuf) != 0) || ((fd = fopen(mudconf.help_file, "r")) == NULL)) { logfile(LOG_ERROR, "help_init: couldn't open help file, %s\n", mudconf.help_file); } else { init_table(fd, &HelpTable); fclose(fd); HelpTableInited = 1; hash = Hash_CreateEntry(&HelpTable, Mod_Entry, &new); Hash_SetValue(hash, (int *) sbuf.st_mtime); } } if (!NewsTableInited) { if ((stat(mudconf.news_file, &sbuf) != 0) || ((fd = fopen(mudconf.news_file, "r")) == NULL)) { logfile(LOG_ERROR, "help_init: couldn't open news file, %s\n", mudconf.news_file); } else { init_table(fd, &NewsTable); fclose(fd); NewsTableInited = 1; hash = Hash_CreateEntry(&NewsTable, Mod_Entry, &new); Hash_SetValue(hash, (int *) sbuf.st_mtime); } } } static void free_help(table) Hash_Table *table; { #if (SIZEOF_OFF_T > SIZEOF_INT_P) Hash_Entry *entry; Hash_Search srch; for(entry = Hash_EnumFirst(table, &srch); entry != (Hash_Entry *)NULL; entry = Hash_EnumNext(&srch)) { ty_free((VOID *)Hash_GetValue(entry)); } #endif Hash_DeleteTable(table); } VOID do_help(player, cause, switches, argone) int player, cause, switches; char *argone; { FILE *fd; Hash_Entry *hash; time_t last; char buf[MEDBUFFSIZ]; char *topic; #if (SIZEOF_OFF_T > SIZEOF_INT_P) register off_t *optr; #endif int err; if (switches & HELP_RELOAD) { HelpTableInited = 0; free_help(&HelpTable); help_init(); if (!(switches & CMD_QUIET)) notify_player(player, cause, player, "Help file reloaded.", NOT_QUIET); return; } if ((argone == (char *)NULL) || (argone[0] == '\0') || strcmp(argone, Mod_Entry) == 0) topic = "summary"; else topic = argone; if (!HelpTableInited || mudconf.hfile_autoload) { err = ((stat(mudconf.help_file, &sbuf) != 0) || (fd = fopen(mudconf.help_file, "r")) == NULL); } else { err = ((fd = fopen(mudconf.help_file, "r")) == NULL); } if (err) { if(!(switches & CMD_QUIET)) { snprintf(buf, sizeof(buf), "Sorry, %s seems to be broken.", mudconf.help_file); notify_player(player, cause, player, buf, NOT_QUIET); } return; } if (!HelpTableInited || ((hash = Hash_FindEntry(&HelpTable, Mod_Entry)) == NULL)) { help_init(); last = sbuf.st_mtime; } else { last = (time_t) Hash_GetValue(hash); } if (mudconf.hfile_autoload) { if (sbuf.st_mtime > last) { HelpTableInited = 0; free_help(&HelpTable); help_init(); } } if (strcasecmp(topic, "-summary") == 0) { Hash_Search srch; for(hash = Hash_EnumFirst(&HelpTable, &srch); hash != NULL; hash = Hash_EnumNext(&srch)) notify_player(player, cause, player, Hash_GetKey(&HelpTable, hash), 0); return; } if ((hash = Hash_FindEntry(&HelpTable, topic)) == NULL) { if(!(switches & CMD_QUIET)) { snprintf(buf, sizeof(buf), "No help available for %s.", topic); notify_player(player, cause, player, buf, NOT_QUIET); } fclose(fd); return; } #if (SIZEOF_OFF_T > SIZEOF_INT_P) optr = (off_t *)Hash_GetValue(hash); fseek(fd, *optr, 0); #else fseek(fd, (off_t) Hash_GetValue(hash), 0); #endif while (!feof(fd) && (fgets(buffer, sizeof(buffer), fd) != NULL)) { if (!strncmp(buffer, "@@@@", 4)) break; if (buffer[0] != '&') { remove_newline(buffer); notify_player(player, cause, player, (buffer[0]) ? buffer : " ", 0); } } fclose(fd); } VOID do_news(player, cause, switches, argone) int player, cause, switches; char *argone; { FILE *fd; Hash_Entry *hash; time_t last; char buf[MEDBUFFSIZ]; char *topic; #if (SIZEOF_OFF_T > SIZEOF_INT_P) register off_t *optr; #endif int err; if (switches & NEWS_RELOAD) { NewsTableInited = 0; free_help(&NewsTable); help_init(); if (!(switches & CMD_QUIET)) notify_player(player, cause, player, "News file reloaded.", NOT_QUIET); return; } if ((argone == (char *)NULL) || (argone[0] == '\0') || strcmp(argone, Mod_Entry) == 0) topic = "summary"; else topic = argone; if (!NewsTableInited || mudconf.hfile_autoload) { err = ((stat(mudconf.news_file, &sbuf) != 0) || (fd = fopen(mudconf.news_file, "r")) == NULL); } else { err = ((fd = fopen(mudconf.news_file, "r")) == NULL); } if (err) { if(!(switches & CMD_QUIET)) { snprintf(buf, sizeof(buf), "Sorry, %s seems to be broken.", mudconf.news_file); notify_player(player, cause, player, buf, NOT_QUIET); } return; } if (!NewsTableInited || ((hash = Hash_FindEntry(&NewsTable, Mod_Entry)) == NULL)) { help_init(); last = sbuf.st_mtime; } else { last = (time_t) Hash_GetValue(hash); } if (mudconf.hfile_autoload) { if (sbuf.st_mtime > last) { NewsTableInited = 0; free_help(&NewsTable); help_init(); } } if (strcasecmp(topic, "-summary") == 0) { Hash_Search srch; for(hash = Hash_EnumFirst(&NewsTable, &srch); hash != NULL; hash = Hash_EnumNext(&srch)) notify_player(player, cause, player, Hash_GetKey(&NewsTable, hash), 0); return; } if ((hash = Hash_FindEntry(&NewsTable, topic)) == NULL) { if(!(switches & CMD_QUIET)) { snprintf(buf, sizeof(buf), "No news available for %s.", topic); notify_player(player, cause, player, buf, NOT_QUIET); } fclose(fd); return; } #if (SIZEOF_OFF_T > SIZEOF_INT_P) optr = (off_t *)Hash_GetValue(hash); fseek(fd, *optr, 0); #else fseek(fd, (off_t) Hash_GetValue(hash), 0); #endif while (!feof(fd) && (fgets(buffer, sizeof(buffer), fd) != NULL)) { if (!strncmp(buffer, "@@@@", 4)) break; if (buffer[0] != '&') { remove_newline(buffer); notify_player(player, cause, player, (buffer[0]) ? buffer : " ", 0); } } fclose(fd); } /* * Display the news file last modification time to a player. */ void check_news(player) int player; { char buf[MEDBUFFSIZ]; if (stat(mudconf.news_file, &sbuf) == 0) { strftime(buf, BUFFSIZ, "News file last updated: %a %b %e %H:%M:%S %Z %Y", localtime(&sbuf.st_mtime)); notify_player(player, player, player, buf, 0); } }