9
« on: December 30, 2007, 07:13:53 pm »
The following code supports an Autodoc system. This has been modified to support Dead Souls lib.
To use it, you just make the daemon and call complete_rebuild() in it. Then it will run once a day. It scans the files on the mud that have changed since its last scan for the following comment tags. It then makes doc files in /doc/help/autodoc/ directory.
//:MODULE
//This is the description of this module.
//$$ Note: helpsys style directives can be included
//see: another_module
//:FUNCTION funcname
//This is the doc for function funcname
//:COMMAND
//This is the doc for the command
//:HOOK
//This documents a hook called with call_hooks
//:EXAMPLE
//This is an example to illustrate some code.
//:MUDNAME
// This adds MUDNAME code change to the mudlib
// MUDNAME is what is returned by upper_case(mud_name())
// (keep this line blank after comment to make comment file readable)
//:TODO
//What we'd like to do with this in the future
//### Something has to be fixed (take out the spaces between the / / # # # for the correct format)
//### This doesn't need to start at the left margin
Other tags of course could be added, and :HOOK is a coming change I plan to make available.
The main daemon should be named /secure/daemon/doc_d (or anything in /secure/daemon)
/* Do not remove the headers from this file! see /USAGE for more info. */
// DOC_D by Rust (rust@virginia.edu) 4-10-95
// Inspired by emacs on-line documentation, which is
// awesome once you know how to use it.... =)
// Some languages like Lisp and Python have doc strings.
// since it wasn't about to be built into the language,
// documentation is done via the preprocessor.
//
/* --------------------------------------------------------------
Rewritten by Beek, MonicaS; the equivalent of the above is now:
[Start the comment at the left margin; these are indented so this daemon
doesn't see these examples.]
//:MODULE
//This is the description of this module.
//$$ Note: helpsys style directives can be included
//see: another_module
//:FUNCTION funcname
//This is the doc for function funcname
//:COMMAND
//This is the doc for the command
//:HOOK
//This documents a hook called with call_hooks
//:EXAMPLE
//This is an example to illustrate some code.
//:MUDNAME
// This adds AUTODOC_MUDNAME code change to the mudlib
// MUDNAME is what is returned by upper_case(mud_name())
// (keep this line blank after comment to make comment file readable)
//:TODO
//What we'd like to do with this in the future
/ / # # # Something has to be fixed (take out the spaces between the / / # # # for the correct format)
/ / # # # This doesn't need to start at the left margin
Data is updated nightly and dumped to the /doc/help/autodoc directory
*/
// Modified to work with Dead Souls lib by Archaegeo on 12-30-07
#include <daemons.h>
//:MODULE
//The doc daemon handles finding source files which have been modified and
//updating the appropriate documentation in /doc/help/autodoc.
// Public functions --------------------------------------------------------
int pending() {if(event_pending(this_object())) return 1;return 0;}
private void continue_scan();
private int last_time;
private string *files_to_do, *dirs_to_do;
private void delete_directory(string directory)
{
mixed *file;
if(file_size(directory)==-1)
return;
foreach(file in get_dir(sprintf("%s/",directory),-1))
{
string target=sprintf("%s/%s",directory,file[0]);
if(file[1]==-2)
delete_directory(target);
else
rm(target);
}
rmdir(directory);
}
void make_directories()
{
/* Assume that if the filesize is -1 that a directory needs to be created */
if(file_size("/doc/help/autodoc")==-1)
mkdir("/doc/help/autodoc");
if(file_size("/doc/help/autodoc/FIXME")==-1)
mkdir("/doc/help/autodoc/FIXME");
if(file_size("/doc/help/autodoc/command")==-1)
mkdir("/doc/help/autodoc/command");
if(file_size("/doc/help/autodoc/examples")==-1)
mkdir("/doc/help/autodoc/examples");
if(file_size("/doc/help/autodoc/functions")==-1)
mkdir("/doc/help/autodoc/functions");
if(file_size("/doc/help/autodoc/hook")==-1)
mkdir("/doc/help/autodoc/hook");
if(file_size("/doc/help/autodoc/modules")==-1)
mkdir("/doc/help/autodoc/modules");
if(file_size("/doc/help/autodoc/todo")==-1)
mkdir("/doc/help/autodoc/todo");
if(file_size("/doc/help/autodoc/"+mud_name())==-1)
mkdir("/doc/help/autodoc/"+mud_name());
}
//:FUNCTION scan_mudlib
//
// Recursively searches the mudlib for files which have been changed
// since the last time the docs were updated, and recreates the documentation
// for those files.
void scan_mudlib() {
printf("Starting scan ...\n");
files_to_do = ({ });
dirs_to_do = ({ "/" });
if(!last_time)
{
delete_directory("/doc/help/autodoc");
make_directories();
}
continue_scan();
}
//:FUNCTION complete_rebuild
//
// Rebuild all the data, regardless of modification time
void complete_rebuild() {
last_time = 0;
scan_mudlib();
}
// Everything below here is
private:
// ---------------------------------------------------------------------
// This list are the directories NOT scanned.
private string * filtered_dirs = ({
"/realms/", "/news/", "/secure/log/", "/ftp/", "/doc/", "/include/", "/secure/upgrades/",
"/log/", "/estates/", "/open/", "/save/", "/tmp/", "/secure/save/", "/www/"
});
string mod_name(string foo) {
sscanf(foo, "%s.c", foo);
return foo[strsrch(foo, "/", -1) + 1..];
}
string func_name(string bar) {
sscanf(bar, "%s(", bar);
return bar;
}
void process_file(string fname) {
string file = read_file(fname);
string line;
string *lines, *match;
string outfile = 0;
int i;
/* If the file has not been modified since the last time that DOC_D
* scanned, there is no reason for it to be checked again -- Tigran */
if(last_time &&
get_dir(fname,-1)[0][2]<last_time)
return;
rm("/doc/help/autodoc/FIXME/" + mod_name(fname));
rm("/doc/help/autodoc/todo/" + mod_name(fname));
rm("/doc/help/autodoc/modules/" + mod_name(fname));
rm("/doc/help/autodoc/command/" + mod_name(fname));
rm("/doc/help/autodoc/hook/" + mod_name(fname));
rm("/doc/help/autodoc/"+mud_name()+"/"+ mod_name(fname));
delete_directory("/doc/help/autodoc/functions/" + mod_name(fname));
if (!file) return;
lines = explode(file, "\n");
while (i < sizeof(lines)) {
if (regexp(lines[i],"^[ \t]*//###")) {
outfile = "/doc/help/autodoc/FIXME/" + mod_name(fname);
write_file(outfile, "FIXME in file "+fname+" line "+(i+1)+":\n\n");
while (sscanf(lines[i], "%*(^[ \t]*//###)%s", line)) {
write_file(outfile, line+"\n");
// line = "";
i++;
}
write_file(outfile, "\nCode:\n"+implode(lines[i..i+3], "\n")+"\n");
printf("Writing to: %O\n", outfile);
}
else if (lines[i][0..2] == "//:") {
line = lines[i][3..];
i++;
if (line == "TODO") {
outfile = "/doc/help/autodoc/todo/" + mod_name(fname);
write_file(outfile, "TODO in file "+fname+" line "+i+":\n\n");
while (lines[i][0..1] == "//") {
write_file(outfile, lines[i][2..]+"\n");
i++;
}
}
else if (line == "MODULE") {
outfile = "/doc/help/autodoc/modules/" + mod_name(fname);
write_file(outfile, "Module "+mod_name(fname)+" (file: "+fname+"):\n\n");
while (lines[i][0..1] == "//") {
write_file(outfile, lines[i][2..]+"\n");
i++;
}
}
else if (line == "COMMAND") {
outfile = "/doc/help/autodoc/command/" + mod_name(fname);
write_file(outfile,"Command "+mod_name(fname)+" (file: "+fname+"):\n\n");
while (lines[i][0..1] == "//") {
write_file(outfile, lines[i][2..]+"\n");
i++;
}
}
else if (sscanf(line, "HOOK %s", line) == 1) {
outfile = "/doc/help/autodoc/hook/" + line;
write_file(outfile, "Hook "+line+":\nCalled by module "
+mod_name(fname)+" (file: "+fname+")\n\n");
while (lines[i][0..1] == "//") {
write_file(outfile, lines[i][2..]+"\n");
i++;
}
}
else if (sscanf(line, "FUNCTION %s", line) == 1) {
if (func_name(line) != line)
log_file("autodoc", "Bad function name: "+fname+" line " + i
+ ": " + line + "\n");
seteuid(geteuid());
mkdir("/doc/help/autodoc/functions/" + mod_name(fname));
outfile = "/doc/help/autodoc/functions/" + mod_name(fname) + "/" + func_name(line);
write_file(outfile, "Function "+line+":\nDefined in module "
+mod_name(fname)+" (file: "+fname+")\n\n");
while (lines[i][0..1] == "//") {
write_file(outfile, lines[i][2..]+"\n");
i++;
}
/* regexp() doesn't match any ";", had to replace_string() them */
match = regexp(map(lines[i..i+19], (: replace_string($1, ";", "#") :)), "\\<"+line+"\\>", 1);
}
else if (line == upper_case(mud_name())) {
outfile = "/doc/help/autodoc/"+mud_name()+"/" + mod_name(fname);
write_file(outfile,"**** "+fname+" ****\n\n");
while (lines[i][0..1] == "//") {
write_file(outfile, lines[i][2..]+"\n");
i++;
}
}
else {
log_file("autodoc", "Bad header tag: "+fname+" line "+i
+": " + line + "\n");
seteuid(geteuid());
}
printf("Writing to: %O\n", outfile);
}
else
i++;
}
}
void continue_scan() {
string *files;
mixed *item;
for (int i = 0; i < 10; i++) {
if (sizeof(dirs_to_do)) {
if(strsrch(dirs_to_do[0],".svn/")!=-1 || strsrch(dirs_to_do[0], "/bak") != -1) {
dirs_to_do[0..0] = ({ });
continue;
}
files = get_dir(dirs_to_do[0], -1);
foreach (item in files) {
if (item[1] == -2) {
string dir = dirs_to_do[0] + item[0] + "/";
if ( member_array(dir, filtered_dirs) != -1 )
continue;
printf("Scanning %s ...\n", dirs_to_do[0]);
dirs_to_do += ({ dir });
} else
if (item[2] > last_time && item[0][<2..<1] == ".c") {
files_to_do += ({ dirs_to_do[0] + item[0] });
}
}
dirs_to_do[0..0] = ({ });
} else
if (sizeof(files_to_do)) {
printf("Updating docs for %s ...\n", files_to_do[0]);
process_file(files_to_do[0]);
files_to_do[0..0] = ({ });
} else {
printf("Done.\n");
HELP_D->Reload();
last_time = time();
return;
}
}
call_out( (: continue_scan :), 1);
}
void
create()
{
if(pending()) return;
else
{
add_event(base_name(this_object()), base_name(this_object()), "scan_mudlib", ({}), 86400, 1);
return;
}
}
The following replaces the /daemon/help.c daemon, it is only necessary if you want the autodoc stuff to show on the help index. It works but I would like to see it support subindexes.
/* /verbs/common/help.c
* from the Dead Souls Object Library
* created by Descartes of Borg 951021
* Version: @(#) help.c 1.15@(#)
* Last Modified: 96/12/14
*/
#include <lib.h>
#include <dirs.h>
#include <daemons.h>
inherit LIB_DAEMON;
static private string Error, SeeAlso = "";
static private mapping Indices;
static private void LoadIndices();
string GetHelp(string str);
string GetHelpByIndex(string index, string topic);
string GetTopic(string index, string topic);
varargs string array GetIndices(string topic);
static void create() {
daemon::create();
SetNoClean(1);
Error = 0;
LoadIndices();
}
int CanAccess(object who, string index) {
switch(index) {
case "admin commands":
return archp(who);
case "creator commands": case "creator documents":
case "library objects": case "daemon objects":
return creatorp(who);
default:
return 1;
}
}
static private void LoadIndices() {
string array tmp, pmt;
function f;
string dir;
f = function(string str) { return str[0..<3]; };
Indices = ([]);
tmp = get_dir(DIR_ADMIN_VERBS + "/*.c") + get_dir(DIR_ADMIN_CMDS + "/*.c")
+ get_dir(DIR_SECURE_ADMIN_CMDS + "/*.c");
Indices["admin commands"] = map(tmp, f);
tmp = get_dir(DIR_COMMON_VERBS+"/*.c") +
get_dir(DIR_COMMON_CMDS + "/*.c") +
get_dir(DIR_SECURE_COMMON_CMDS + "/*.c") +
get_dir(DIR_ITEM_VERBS + "/*.c") +
get_dir(DIR_PLAYER_VERBS+"/*.c") +
get_dir(DIR_PLAYER_CMDS+"/*.c") +
get_dir(DIR_ROOM_VERBS + "/*.c") +
get_dir(DIR_SPELL_VERBS + "/*.c") +
get_dir(DIR_SECURE_PLAYER_CMDS + "/*.c");
Indices["commands"] = map(tmp, f);
tmp = get_dir(DIR_CREATOR_VERBS+"/*.c") + get_dir(DIR_CREATOR_CMDS+"/*.c")
+ get_dir(DIR_SECURE_CREATOR_CMDS + "/*.c");
Indices["creator commands"] = map(tmp, f);
tmp = get_dir(DIR_UNDEAD_VERBS "/*.c");
Indices["undead commands"] = map(tmp, f);
tmp = SOUL_D->GetEmotes();
Indices["feelings"] = tmp;
tmp = filter(map(get_dir(DIR_SPELLS "/*.c"),
function(string file) {
file = DIR_SPELLS "/" + file;
if( file->GetVerb() == "cast" ) {
return file->GetSpell();
}
return 0;
}), (: $1 :));
Indices["spells"] = tmp;
tmp = filter(map(get_dir(DIR_SPELLS "/*.c"),
function(string file) {
file = DIR_SPELLS "/" + file;
if( file->GetVerb() == "pray" ) {
return file->GetSpell();
}
return 0;
}), (: $1 :));
Indices["prayers"] = tmp;
if( tmp = get_dir(DIR_PLAYER_HELP + "/") )
Indices["player documents"] = tmp + ({ "soul" });
else Indices["player documents"] = ({ "soul" });
if( tmp = get_dir(DIR_CREATOR_HELP "/") )
Indices["creator documents"] = tmp;
else Indices["creator document"] = ({});
if( tmp = (string array)CLASSES_D->GetClasses() )
Indices["classes"] = tmp;
else Indices["classes"] = ({});
if( tmp = (string array)RACES_D->GetRaces(1) )
Indices["races"] = tmp;
else Indices["races"] = ({});
if( tmp = get_dir(DIR_LAW_HELP "/") )
Indices["law"] = tmp;
else Indices["law"] = ({});
if( tmp = get_dir(DIR_RELIGION_HELP "/") )
Indices["religion"] = tmp;
else Indices["religion"] = ({});
Indices["library objects"] = ({});
foreach(dir in ({ DIR_LIB, DIR_SECURE_LIB })){
if( !(tmp = get_dir(dir + "/*.c")) ) continue;
else Indices["library objects"] +=
map(tmp, (: $(dir)+"/"+$1[0..<3] :));
}
Indices["daemon objects"] = ({});
foreach(dir in ({ DIR_DAEMONS, DIR_SECURE_DAEMONS })) {
if( !(tmp = get_dir(dir + "/*.c")) ) continue;
else Indices["daemon objects"] +=
map(tmp, (: $(dir)+"/"+$1[0..<3] :));
}
Indices["Autodoc documents"] = ({});
pmt = get_dir("/doc/help/autodoc/");
foreach(dir in pmt) {
if(dir=="functions") continue;
tmp=get_dir("/doc/help/autodoc/"+dir+"/");
if( !tmp ) continue;
else if(sizeof(tmp)){
Indices["Autodoc documents"] += map(tmp, (: $(dir)+"/"+$1[0..] :));
}
}
Indices["Autodoc functions"] = ({});
pmt = get_dir("/doc/help/autodoc/functions/");
foreach(dir in pmt) {
tmp=get_dir("/doc/help/autodoc/functions/"+dir+"/");
if( !tmp ) continue;
else if(sizeof(tmp)){
Indices["Autodoc functions"] += map(tmp, (: $(dir)+"/"+$1[0..] :));
}
}
}
string GetHelp(string str) {
string *tmp, choice,ret ="";
string topic;
int x;
Error = 0;
if( !str || str == "" || str == "help" ) {
return ("Syntax: <help>\n"
" <help index>\n"
" <help TOPIC>\n"
" <help INDEX TOPIC>\n\n"
"The special topic, \"help index\", puts you into "
"a menu driven index of categories for which help exists.\n\n"
"For players, \"help commands\" will provide an index of "
"available player commands.\n "
"For creators, \"help creator commands\" provides an "
"index of available creator commands.\n\n "
"Try \"help commands\" "
"and \"help creator commands\" first. \n\n"
" ");
}
if(member_array(str, CHAT_D->GetChannels()) != -1 &&
str != "newbie"){
return "See: help channels";
}
if( sscanf(str, "adverbs %s", topic) || str == "adverbs" ) {
return (string)SOUL_D->GetHelp(str);
}
tmp = GetIndices(str);
if( sizeof(tmp) > 0){
if( sizeof(tmp) > 1){
if(member_array("admin commands",tmp) != -1) choice = "admin commands";
else if(member_array("creator commands",tmp) != -1) choice = "creator commands";
else if(member_array("player commands",tmp) != -1) choice = "player commands";
}
if(!choice) choice = tmp[0];
tmp -= ({ choice });
if(sizeof(tmp)) SeeAlso = "\nThere also exists help for \"" + str + "\" under the following "
"indices:\n" + implode(tmp, ", ");
ret = GetHelpByIndex(choice, str);
if(ret) ret += SeeAlso;
SeeAlso = "";
return ret;
}
topic = "";
str = trim(str);
while( (x = strsrch(str, " ")) != -1 ) {
if( topic != "" ) {
topic = topic + " " + str[0..(x-1)];
}
else {
topic = str[0..(x-1)];
}
str = str[(x+1)..];
if( Indices[topic] && strlen(str) ) {
return GetHelpByIndex(topic, str);
}
}
if(this_player() && adminp(this_player())){
Error = "Help for the topic \"" + str + "\" could not be found.";
}
else {
Error = "The search for help on the topic \"" + str + "\" yields you no results.";
}
return 0;
}
string GetHelpByIndex(string index, string topic) {
mixed array tmparr, fun;
mapping tmpmap;
object ob;
string help, file, tmpstr;
if( this_player() && !CanAccess(this_player(), index) ) {
Error = "You do not have access to that information.";
return 0;
}
switch(index) {
case "admin commands": case "creator commands": case "undead commands":
case "commands":
switch(index) {
case "admin commands":
if( file_exists( DIR_ADMIN_VERBS + "/" + topic + ".c") )
file = DIR_ADMIN_VERBS + "/" + topic;
else if( file_exists( DIR_ADMIN_CMDS + "/" + topic + ".c") )
file = DIR_ADMIN_CMDS + "/" + topic;
else file = DIR_SECURE_ADMIN_CMDS + "/" + topic;
break;
case "creator commands":
if( file_exists( DIR_CREATOR_VERBS + "/" + topic + ".c") )
file = DIR_CREATOR_VERBS + "/" + topic;
else if( file_exists(DIR_CREATOR_CMDS + "/" + topic + ".c") )
file = DIR_CREATOR_CMDS + "/" + topic;
else file = DIR_SECURE_CREATOR_CMDS + "/" + topic;
break;
case "commands":
foreach(string directory in ({ DIR_COMMON_VERBS,
DIR_COMMON_CMDS,
DIR_SECURE_COMMON_CMDS,
DIR_ITEM_VERBS,
DIR_PLAYER_VERBS,
DIR_PLAYER_CMDS,
DIR_SECURE_PLAYER_CMDS,
DIR_ROOM_VERBS,
DIR_SPELL_VERBS })) {
if( file_exists(directory + "/" + topic + ".c") ) {
file = directory + "/" + topic;
break;
}
}
break;
case "undead commands":
file = DIR_UNDEAD_VERBS + "/" + topic;
break;
}
if( !file_exists(file + ".c") ) {
Error = "No such " + index[0..<2] + " exists.";
return 0;
}
if( catch(help = file->GetHelp(topic)) ) {
Error = "An error occurred in attempting to access help.";
return 0;
}
if( !help ) {
string *syn, *pd;
string line;
pd = regexp(explode(parse_dump(), "\n"), file[1..]);
syn = ({});
foreach(line in pd) {
sscanf(line, "%*s"+file[1..]+") %s", tmpstr);
syn += ({ tmpstr });
}
if( !sizeof(syn) ) {
if( function_exists("help", load_object(file)) ) {
Error = " ";
file->help();
write(SeeAlso);
SeeAlso = "";
return 0;
}
Error = "Unable to locate any syntax information on " +
topic + ".";
return 0;
}
help = "Syntax: " + topic + " " + syn[0] + "\n";
if( sizeof(syn) == 1 ) help += "\n";
else {
foreach(line in syn[1..])
help += " " + topic + " " + line + "\n";
help += "\n";
}
help += "No detailed documentation exists for this command.";
}
help = "Index: %^GREEN%^" + index + "%^RESET%^\n" +
"Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help;
return help;
case "player documents": case "creator documents":
case "law": case "Autodoc documents": case "Autodoc functions":
switch(index) {
case "player documents":
if( topic == "soul" ) {
help = SOUL_D->GetHelp("soul");
help = "Index: %^GREEN%^" + index + "%^RESET%^\n" +
"Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help;
return help;
}
file = DIR_PLAYER_HELP "/" + topic;
break;
case "Autodoc documents":
file = "/doc/help/autodoc/" + topic;
break;
case "Autodoc functions":
file = "/doc/help/autodoc/functions/" + topic;
break;
case "creator documents":
file = DIR_CREATOR_HELP "/" + topic;
break;
case "law":
file = DIR_LAW_HELP "/" + topic;
break;
}
if( !file_exists(file) ) {
Error = "No such " + index[0..<2] + " is available.";
return 0;
}
if( !(help = read_file(file)) ) {
Error = "The document " + topic + " was empty.";
return 0;
}
help = "Index: %^GREEN%^" + index + "%^RESET%^\n" +
"Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help;
return help;
case "feelings":
help = SOUL_D->GetHelp(topic);
if( !help ) {
Error = "No such " + index[0..<2] + " is available.";
return 0;
}
help = "Index: %^GREEN%^" + index + "%^RESET%^\n" +
"Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help;
return help;;
case "library objects":
topic = GetTopic(index, topic);
if( !file_exists(topic+".c") ){
Error = "No such topic found.";
return 0;
}
if( catch(help = topic->GetHelp(topic)) ) {
Error = "An error occurred in attempting to access help.";
return 0;
}
if( !help ) {
help = "No synopsis available for this object.\n\n";
}
else {
help = "Synopsis:\n" + help + "\n\n";
}
tmparr = stat(topic + ".c");
tmpstr = "Object: " + topic + "\n"
"Last Modified: " + ctime(tmparr[1]) + "\n";
if( tmparr[2] ) {
tmpstr += "Last Loaded: " + ctime(tmparr[2]) + "\n\n";
}
tmparr = inherit_list(ob = find_object(topic));
if( !sizeof(tmparr) ) {
tmpstr += "No inherited objects\n\n";
}
else {
tmpstr += "Inherits:\n" + format_page(tmparr, 4) + "\n";
}
tmparr = functions(ob, 1);
tmpmap = ([]);
foreach(fun in tmparr) {
if( function_exists(fun[0], ob) != topic ) {
continue;
}
if( fun[0] == "#global_init#" ) {
continue;
}
if( tmpmap[fun[0]] ) {
continue;
}
else {
tmpmap[fun[0]] = ([ "type" : fun[2],
"args" : (fun[1] ? fun[3..] : ({})) ]);
}
}
help = tmpstr + help;
if( !sizeof(tmparr) ) {
help += "No functions\n\n";
}
else {
string fnc;
help += "Functions:\n";
tmparr = sort_array(keys(tmpmap), 1);
foreach(fnc in tmparr) {
help += tmpmap[fnc]["type"] + fnc + "(" +
implode(tmpmap[fnc]["args"], ", ") + ")\n";
}
}
help = "Index: %^GREEN%^" + index + "%^RESET%^\n" +
"Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help;
return help;
case "daemon objects":
topic = GetTopic(index, topic);
if( !topic || catch(help = topic->GetHelp(topic)) ) {
Error = "An error occurred in attempting to access help for that.";
return 0;
}
if( !help ) {
help = "No synopsis available for this object.\n\n";
}
else {
help = "Synopsis:\n" + help + "\n\n";
}
tmparr = stat(topic + ".c");
tmpstr = "Object: " + topic + "\n"
"Last Modified: " + ctime(tmparr[1]) + "\n";
if( tmparr[2] ) tmpstr += "Last Loaded: " + ctime(tmparr[2]) + "\n\n";
tmparr = inherit_list(ob = find_object(topic));
if( !sizeof(tmparr) ) tmpstr += "No inherited objects\n\n";
else tmpstr += "Inherits:\n" + format_page(tmparr, 4) + "\n";
tmparr = functions(ob, 1);
tmpmap = ([]);
foreach(fun in tmparr) {
if( function_exists(fun[0], ob) != topic ) continue;
if( fun[0] == "#global_init#" ) continue;
if( tmpmap[fun[0]] ) continue;
else tmpmap[fun[0]] = ([ "type" : fun[2],
"args" : (fun[1] ? fun[3..] : ({})) ]);
}
help = tmpstr + help;
if( !sizeof(tmparr) ) help += "No functions\n\n";
else {
string fnc;
help += "Functions:\n";
tmparr = sort_array(keys(tmpmap), 1);
foreach(fnc in tmparr)
help += tmpmap[fnc]["type"] + fnc + "(" +
implode(tmpmap[fnc]["args"], ", ") + ")\n";
}
help = "Index: %^GREEN%^" + index + "%^RESET%^\n" +
"Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help;
return help;
case "religons": case "religion":
if( file_exists(DIR_RELIGION_HELP "/" + topic) ) {
help = read_file(DIR_RELIGION_HELP "/" + topic);
help = "Index: %^GREEN%^" + index + "%^RESET%^\n" +
"Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help;
return help;
}
Error = "No such religion exists.";
return 0;
case "races":
if( help = (string)RACES_D->GetHelp(topic) ) {
help = "Index: %^GREEN%^" + index + "%^RESET%^\n" +
"Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help;
return help;
}
else if( file_exists(DIR_RACE_HELP + "/" + topic) ){
help = read_file(DIR_RACE_HELP + "/" + topic);
return help;
}
Error = "There is no such race.";
return 0;
case "spells": case "prayers":
ob = SPELLS_D->GetSpell(topic);
if( !ob ) {
Error = "No such spell exists.";
return 0;
}
if( !(help = ob->GetHelp(topic)) ) {
Error = "No help is available for that spell.";
return 0;
}
help = "Index: %^GREEN%^" + index + "%^RESET%^\n" +
"Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help;
return help;
case "classes":
if( help = (string)CLASSES_D->GetHelp(topic) ) {
help = "Index: %^GREEN%^" + index + "%^RESET%^\n" +
"Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help;
if( file_exists(DIR_CLASS_HELP + "/" + topic) )
help += read_file(DIR_CLASS_HELP + "/" + topic);
return help;
}
Error = "No such class exists.";
return 0;
default:
Error = "No help exists for the index " + index + ".";
return 0;
}
}
varargs string array GetIndices(string topic) {
string array topics, val;
string ind, tmp;
if( !topic ) {
return sort_array(keys(Indices), 1);
}
topics = ({});
foreach(ind, val in Indices) {
if( !CanAccess(this_player(), ind) ) {
continue;
}
tmp = GetTopic(ind, topic);
if( member_array(tmp, val) != -1 ) {
topics += ({ ind });
}
}
return sort_array(topics, 1);
}
string GetTopic(string index, string topic) {
string array dirlist;
string dir;
if( index != "library objects" && index != "daemon objects" ) {
return topic;
}
if( index == "library objects" ) {
dirlist = ({ DIR_LIB, DIR_SECURE_LIB });
}
else {
dirlist = ({ DIR_DAEMONS, DIR_SECURE_DAEMONS });
}
if( strlen(topic) > 2 && topic[<2..] == ".c" ) {
topic = topic[0..<3];
}
if( file_exists(topic + ".c") ) {
return topic;
}
foreach(dir in dirlist) {
if( file_exists(dir + "/" + topic + ".c") ) {
return dir + "/" + topic;
}
}
return 0;
}
string array GetTopics(string index) {
string array topics = Indices[index];
if( !topics ) {
return 0;
}
else {
return sort_array(topics, 1);
}
}
string GetLastError() {
return Error;
}
void Reload() {
LoadIndices();
}