lima-1.0b5/
lima-1.0b5/driver/
lima-1.0b5/driver/ChangeLog.old/
lima-1.0b5/driver/Win32/
lima-1.0b5/driver/compat/
lima-1.0b5/driver/include/
lima-1.0b5/driver/testsuite/
lima-1.0b5/driver/testsuite/clone/
lima-1.0b5/driver/testsuite/command/
lima-1.0b5/driver/testsuite/data/
lima-1.0b5/driver/testsuite/etc/
lima-1.0b5/driver/testsuite/include/
lima-1.0b5/driver/testsuite/inherit/
lima-1.0b5/driver/testsuite/inherit/master/
lima-1.0b5/driver/testsuite/log/
lima-1.0b5/driver/testsuite/single/
lima-1.0b5/driver/testsuite/single/tests/compiler/
lima-1.0b5/driver/testsuite/single/tests/efuns/
lima-1.0b5/driver/testsuite/single/tests/operators/
lima-1.0b5/driver/testsuite/u/
lima-1.0b5/driver/tmp/
lima-1.0b5/etc/
lima-1.0b5/lib/WWW/help/
lima-1.0b5/lib/cmds/
lima-1.0b5/lib/cmds/create/
lima-1.0b5/lib/cmds/player/attic/
lima-1.0b5/lib/contrib/bboard/
lima-1.0b5/lib/contrib/boards/
lima-1.0b5/lib/contrib/marriage/
lima-1.0b5/lib/contrib/roommaker/
lima-1.0b5/lib/contrib/transient_effect/
lima-1.0b5/lib/daemons/channel/
lima-1.0b5/lib/daemons/imud/
lima-1.0b5/lib/data/
lima-1.0b5/lib/data/config/
lima-1.0b5/lib/data/links/
lima-1.0b5/lib/data/news/
lima-1.0b5/lib/data/players/
lima-1.0b5/lib/data/secure/
lima-1.0b5/lib/domains/
lima-1.0b5/lib/domains/std/2.4.5/maze1/
lima-1.0b5/lib/domains/std/2.4.5/npc/
lima-1.0b5/lib/domains/std/2.4.5/post_dir/
lima-1.0b5/lib/domains/std/2.4.5/sub/
lima-1.0b5/lib/domains/std/camera/
lima-1.0b5/lib/domains/std/config/
lima-1.0b5/lib/domains/std/cult/
lima-1.0b5/lib/domains/std/effects/
lima-1.0b5/lib/domains/std/misc/
lima-1.0b5/lib/domains/std/monsters/
lima-1.0b5/lib/domains/std/recorder/
lima-1.0b5/lib/domains/std/rooms/
lima-1.0b5/lib/domains/std/rooms/beach/
lima-1.0b5/lib/domains/std/rooms/labyrinth/
lima-1.0b5/lib/domains/std/school/
lima-1.0b5/lib/domains/std/school/O/
lima-1.0b5/lib/domains/std/spells/
lima-1.0b5/lib/domains/std/spells/stock-mage/
lima-1.0b5/lib/domains/std/spells/stock-priest/
lima-1.0b5/lib/help/
lima-1.0b5/lib/help/admin/
lima-1.0b5/lib/help/hints/General_Questions/
lima-1.0b5/lib/help/hints/Pirate_Quest/
lima-1.0b5/lib/help/player/
lima-1.0b5/lib/help/player/bin/
lima-1.0b5/lib/help/player/quests/
lima-1.0b5/lib/help/wizard/
lima-1.0b5/lib/help/wizard/coding/guilds/
lima-1.0b5/lib/help/wizard/coding/rooms/
lima-1.0b5/lib/help/wizard/lib/daemons/
lima-1.0b5/lib/help/wizard/lib/lfun/
lima-1.0b5/lib/help/wizard/lib/std/
lima-1.0b5/lib/help/wizard/mudos_doc/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/interactive/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/concepts/
lima-1.0b5/lib/help/wizard/mudos_doc/driver/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/arrays/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/buffers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/compile/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/filesystem/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/floats/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/functions/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/general/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mappings/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mixed/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/numbers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/constructs/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/types/
lima-1.0b5/lib/include/driver/
lima-1.0b5/lib/log/
lima-1.0b5/lib/obj/admtool/
lima-1.0b5/lib/obj/admtool/internal/
lima-1.0b5/lib/obj/admtool/mudinfo/
lima-1.0b5/lib/obj/admtool/secure/
lima-1.0b5/lib/obj/secure/
lima-1.0b5/lib/obj/secure/cmd/
lima-1.0b5/lib/obj/secure/mailers/
lima-1.0b5/lib/obj/secure/shell/
lima-1.0b5/lib/obj/secure/shell/classes/
lima-1.0b5/lib/obj/tasktool/
lima-1.0b5/lib/obj/tasktool/internal/
lima-1.0b5/lib/open/
lima-1.0b5/lib/secure/
lima-1.0b5/lib/secure/cgi/
lima-1.0b5/lib/secure/modules/
lima-1.0b5/lib/secure/simul_efun/
lima-1.0b5/lib/std/adversary/
lima-1.0b5/lib/std/adversary/advancement/
lima-1.0b5/lib/std/adversary/armor/
lima-1.0b5/lib/std/adversary/blows/
lima-1.0b5/lib/std/adversary/death/
lima-1.0b5/lib/std/adversary/formula/
lima-1.0b5/lib/std/adversary/health/
lima-1.0b5/lib/std/adversary/pulse/
lima-1.0b5/lib/std/adversary/wield/
lima-1.0b5/lib/std/classes/event_info/
lima-1.0b5/lib/std/container/
lima-1.0b5/lib/std/living/
lima-1.0b5/lib/std/modules/contrib/
lima-1.0b5/lib/std/patterns/
lima-1.0b5/lib/std/race/
lima-1.0b5/lib/std/race/restricted/
lima-1.0b5/lib/std/room/
lima-1.0b5/lib/tmp/
lima-1.0b5/lib/trans/
lima-1.0b5/lib/trans/admincmds/
lima-1.0b5/lib/trans/obj/
lima-1.0b5/lib/wiz/
/* 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.
//
// at the top of a module, do:
// DOC_MODULE("this is the doc string explaining my module.");
//
// On top of every function in the mudlib, do (right before the function):
// DOC(funcname, "this is the doc for function funcname");
//
// On top of every command anywhere in the lib do:
// DOC_COMMAND("this is the documentation for the foo command.");

/* --------------------------------------------------------------

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 (wiz) command

 //:PLAYER_COMMAND
 //This is the doc for the player command

 //:HOOK
 //This documents a hook called with call_hooks

 //:EXAMPLE
 //This is an example to illustrate some code.

 //:AUTODOC_MUDNAME
 // This adds AUTODOC_MUDNAME code change to the mudlib
 // AUTODOC_MUDNAME is set in config.h
 // (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
 //### This doesn't need to start at the left margin

Data is updated nightly and dumped to the /help/autodoc directory
*/

#include <security.h>
#include <log.h>

inherit M_REGEX;
inherit M_DAEMON_DATA;

//:MODULE
//The doc daemon handles finding source files which have been modified and
//updating the appropriate documentation in /help/autodoc.

// Public functions --------------------------------------------------------


private void continue_scan();
private int last_time;
private array files_to_do, dirs_to_do;

private void delete_directory(string directory)
{
  if(file_size(directory)==-1)
    return;
  foreach(mixed array 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);
}

private void make_directories()
{
/* Assume that if the filesize is -1 that a directory needs to be created */
  if(file_size("/help/autodoc")==-1)
    mkdir("/help/autodoc");
  if(file_size("/help/autodoc/FIXME")==-1)
    mkdir("/help/autodoc/FIXME");
  if(file_size("/help/autodoc/command")==-1)
    mkdir("/help/autodoc/command");
  if(file_size("/help/player/command")==-1)
    mkdir("/help/player/command");
  if(file_size("/help/admin/command")==-1)
    mkdir("/help/admin/command");
  if(file_size("/help/autodoc/examples")==-1)
    mkdir("/help/autodoc/examples");
  if(file_size("/help/autodoc/functions")==-1)
    mkdir("/help/autodoc/functions");
  if(file_size("/help/autodoc/hook")==-1)
    mkdir("/help/autodoc/hook");
  if(file_size("/help/autodoc/modules")==-1)
    mkdir("/help/autodoc/modules");
  if(file_size("/help/autodoc/todo")==-1)
    mkdir("/help/autodoc/todo");
  if(file_size(sprintf("/help/autodoc/%s",MUD_AUTODOC_DIR))==-1)
    mkdir(sprintf("/help/autodoc/%s",MUD_AUTODOC_DIR));
}

//: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("/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:
// ---------------------------------------------------------------------

nosave private string * filtered_dirs = ({
  "/data/", "/ftp/", "/help/", "/include/",
  "/log/", "/open/", "/tmp/", "/user/", "/wiz/",
  "/contrib/",
});

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, prototype;
  array 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("/help/autodoc/FIXME/" + mod_name(fname));
  rm("/help/autodoc/todo/" + mod_name(fname));
  rm("/help/autodoc/modules/" + mod_name(fname));
  rm("/help/autodoc/command/" + mod_name(fname));
  rm("/help/player/command/" + mod_name(fname));
  rm("/help/autodoc/hook/" + mod_name(fname));
  rm("/help/autodoc/" + MUD_AUTODOC_DIR + "/" + mod_name(fname));
  delete_directory("/help/autodoc/functions/" + mod_name(fname));

  if (!file)
    return;
  lines = explode(file, "\n");

  while (i < sizeof(lines))
  {
    if (regexp(lines[i],"^[ \t]*//###"))
    {
	    outfile = "/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 = "/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 = "/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 = "/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 (line == "PLAYERCOMMAND") {
        outfile = "/help/player/command/" + mod_name(fname);
        while (lines[i][0..1] == "//")
        {
          write_file(outfile, lines[i][2..]+"\n");
          i++;
        }
      } else if (line == "ADMINCOMMAND") {
        outfile = "/help/admin/command/" + mod_name(fname);
        while (lines[i][0..1] == "//")
        {
          write_file(outfile, lines[i][2..]+"\n");
          i++;
        }
      } else if (sscanf(line, "HOOK %s", line) == 1) {
        outfile = "/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_D->log(LOG_AUTODOC, "Bad function name: "+fname+" line " + i
              + ": " + line + "\n");
        mkdir("/help/autodoc/functions/" + mod_name(fname));
        outfile = "/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 ((i<sizeof(lines)) && (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);
        if (sizeof(match) > 0)
        {
          if (sscanf(implode(lines[i+match[1]-1..i+match[1]+3], "\n"),
              "%([ \t]*([a-zA-Z_][a-zA-Z0-9_* \t\n]*|)\\<"+line
              +"\\>[ \t\n]*\\([ \t\na-zA-Z_0-9*,.]*(\\)|))",
              prototype))
          {
            write_file(outfile, "\nPrototype:\n"+prototype+";\n");
          }
        }
      } else if (line == AUTODOC_MUDNAME) {
        outfile = "/help/autodoc/"+MUD_AUTODOC_DIR+"/" + mod_name(fname);
        write_file(outfile,"**** "+fname+" ****\n\n");
        while (lines[i][0..1] == "//")
        {
          write_file(outfile, lines[i][2..]+"\n");
          i++;
        }
      } else {
        LOG_D->log(LOG_AUTODOC, "Bad header tag: "+fname+" line "+i
            +": " + line + "\n");
      }
      printf("Writing to: %O\n", outfile);
    }	else
	    i++;
  }
}

void continue_scan()
{
  array files;
  array item;

  for (int i = 0; i < 10; i++)
  {
    if (sizeof(dirs_to_do))
    {
      printf("Scanning %s ...\n", dirs_to_do[0]);
      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;
          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]);
/*
 ** We need an unguarded() for any writes that may occur... there
 ** is no user object, so protection checks will always fail.  This
 ** will terminate the checking at this daemon rather than fall
 ** off the stack and fail.  Note that we don't actually hit priv
 ** 1, but the maximum allowed.
 */
	    unguarded(1, (: process_file, files_to_do[0] :));
	    files_to_do[0..0] = ({ });
    } else {
      printf("Done.\n");
      last_time = time();
      save_me();
      HELP_D->rebuild_data();
      return;
    }
  }	    
  call_out( (: continue_scan :), 1);
}

void do_sweep()
{
  scan_mudlib();
  call_out( (: do_sweep :), 86400);
}

void create()
{
  if(clonep())
  {
    destruct(this_object());
    return;
  }	    
  ::create();
  if ( !last_time )
    do_sweep();
  else
    call_out( (: do_sweep :), 86400);
}