skylib_fluffos_v3/
skylib_fluffos_v3/bin/
skylib_fluffos_v3/bin/db/
skylib_fluffos_v3/fluffos-2.9-ds2.04/
skylib_fluffos_v3/fluffos-2.9-ds2.04/ChangeLog.old/
skylib_fluffos_v3/fluffos-2.9-ds2.04/Win32/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/simuls/
skylib_fluffos_v3/fluffos-2.9-ds2.04/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/clone/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/command/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/data/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/etc/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/master/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/log/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/compiler/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/efuns/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/operators/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/u/
skylib_fluffos_v3/fluffos-2.9-ds2.04/tmp/
skylib_fluffos_v3/fluffos-2.9-ds2.04/windows/
skylib_fluffos_v3/mudlib/
skylib_fluffos_v3/mudlib/cmds/
skylib_fluffos_v3/mudlib/cmds/admin/
skylib_fluffos_v3/mudlib/cmds/guild-race/
skylib_fluffos_v3/mudlib/cmds/living/broken/
skylib_fluffos_v3/mudlib/cmds/player/group_cmds/
skylib_fluffos_v3/mudlib/cmds/playtester/
skylib_fluffos_v3/mudlib/d/admin/
skylib_fluffos_v3/mudlib/d/admin/room/
skylib_fluffos_v3/mudlib/d/admin/room/we_care/
skylib_fluffos_v3/mudlib/d/admin/save/
skylib_fluffos_v3/mudlib/d/admin/text/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/buildings/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/map/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/roads/
skylib_fluffos_v3/mudlib/d/learning/chars/
skylib_fluffos_v3/mudlib/d/learning/functions/
skylib_fluffos_v3/mudlib/d/learning/handlers/
skylib_fluffos_v3/mudlib/d/learning/help_topics/
skylib_fluffos_v3/mudlib/d/learning/help_topics/npcs/
skylib_fluffos_v3/mudlib/d/learning/help_topics/objects/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/crowd/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/situations/
skylib_fluffos_v3/mudlib/d/learning/save/
skylib_fluffos_v3/mudlib/d/learning/school/
skylib_fluffos_v3/mudlib/d/learning/school/add_sc/
skylib_fluffos_v3/mudlib/d/learning/school/characters/
skylib_fluffos_v3/mudlib/d/learning/school/general/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/basic_commands/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/edtutor/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_fluffos_v3/mudlib/d/learning/school/items/
skylib_fluffos_v3/mudlib/d/learning/school/npc_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/room_basic/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/situations/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_fluffos_v3/mudlib/d/learning/text/
skylib_fluffos_v3/mudlib/d/liaison/
skylib_fluffos_v3/mudlib/d/mudlib/
skylib_fluffos_v3/mudlib/d/mudlib/changes/
skylib_fluffos_v3/mudlib/d/playtesters/
skylib_fluffos_v3/mudlib/d/playtesters/effects/
skylib_fluffos_v3/mudlib/d/playtesters/handlers/
skylib_fluffos_v3/mudlib/d/playtesters/items/
skylib_fluffos_v3/mudlib/d/sage/
skylib_fluffos_v3/mudlib/doc/
skylib_fluffos_v3/mudlib/doc/creator/
skylib_fluffos_v3/mudlib/doc/driver/
skylib_fluffos_v3/mudlib/doc/driver/efuns/arrays/
skylib_fluffos_v3/mudlib/doc/driver/efuns/buffers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/calls/
skylib_fluffos_v3/mudlib/doc/driver/efuns/compile/
skylib_fluffos_v3/mudlib/doc/driver/efuns/filesystem/
skylib_fluffos_v3/mudlib/doc/driver/efuns/floats/
skylib_fluffos_v3/mudlib/doc/driver/efuns/functions/
skylib_fluffos_v3/mudlib/doc/driver/efuns/general/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mappings/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mixed/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mudlib/
skylib_fluffos_v3/mudlib/doc/driver/efuns/numbers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/parsing/
skylib_fluffos_v3/mudlib/doc/login/
skylib_fluffos_v3/mudlib/doc/lpc/basic_manual/
skylib_fluffos_v3/mudlib/doc/lpc/intermediate/
skylib_fluffos_v3/mudlib/doc/new/add_command/
skylib_fluffos_v3/mudlib/doc/new/events/
skylib_fluffos_v3/mudlib/doc/new/handlers/
skylib_fluffos_v3/mudlib/doc/new/living/race/
skylib_fluffos_v3/mudlib/doc/new/living/spells/
skylib_fluffos_v3/mudlib/doc/new/object/
skylib_fluffos_v3/mudlib/doc/new/player/
skylib_fluffos_v3/mudlib/doc/new/room/guild/
skylib_fluffos_v3/mudlib/doc/new/room/outside/
skylib_fluffos_v3/mudlib/doc/new/room/storeroom/
skylib_fluffos_v3/mudlib/doc/object/
skylib_fluffos_v3/mudlib/doc/playtesters/
skylib_fluffos_v3/mudlib/doc/policy/
skylib_fluffos_v3/mudlib/doc/weapons/
skylib_fluffos_v3/mudlib/global/
skylib_fluffos_v3/mudlib/global/creator/
skylib_fluffos_v3/mudlib/handlers/
skylib_fluffos_v3/mudlib/include/casino/
skylib_fluffos_v3/mudlib/include/cmds/
skylib_fluffos_v3/mudlib/include/effects/
skylib_fluffos_v3/mudlib/include/npc/
skylib_fluffos_v3/mudlib/include/room/
skylib_fluffos_v3/mudlib/include/shops/
skylib_fluffos_v3/mudlib/net/daemon/
skylib_fluffos_v3/mudlib/net/daemon/chars/
skylib_fluffos_v3/mudlib/net/inherit/
skylib_fluffos_v3/mudlib/net/obj/
skylib_fluffos_v3/mudlib/net/obj/BACKUPS/
skylib_fluffos_v3/mudlib/obj/amulets/
skylib_fluffos_v3/mudlib/obj/armours/plate/
skylib_fluffos_v3/mudlib/obj/b_day/
skylib_fluffos_v3/mudlib/obj/clothes/transport/horse/
skylib_fluffos_v3/mudlib/obj/faith/symbols/
skylib_fluffos_v3/mudlib/obj/fungi/
skylib_fluffos_v3/mudlib/obj/gatherables/
skylib_fluffos_v3/mudlib/obj/instruments/
skylib_fluffos_v3/mudlib/obj/media/
skylib_fluffos_v3/mudlib/obj/misc/player_shop/
skylib_fluffos_v3/mudlib/obj/monster/godmother/
skylib_fluffos_v3/mudlib/obj/monster/transport/
skylib_fluffos_v3/mudlib/obj/rings/
skylib_fluffos_v3/mudlib/obj/scabbards/
skylib_fluffos_v3/mudlib/obj/spells/
skylib_fluffos_v3/mudlib/obj/stationery/
skylib_fluffos_v3/mudlib/obj/stationery/envelopes/
skylib_fluffos_v3/mudlib/obj/toys/
skylib_fluffos_v3/mudlib/obj/vessels/
skylib_fluffos_v3/mudlib/obj/weapons/axes/
skylib_fluffos_v3/mudlib/obj/weapons/chains/
skylib_fluffos_v3/mudlib/obj/weapons/maces/BACKUPS/
skylib_fluffos_v3/mudlib/save/autodoc/
skylib_fluffos_v3/mudlib/save/book_handler/
skylib_fluffos_v3/mudlib/save/books/history/calarien/
skylib_fluffos_v3/mudlib/save/mail/
skylib_fluffos_v3/mudlib/save/new_soul/data/
skylib_fluffos_v3/mudlib/save/parcels/
skylib_fluffos_v3/mudlib/save/playerinfo/
skylib_fluffos_v3/mudlib/save/players/d/
skylib_fluffos_v3/mudlib/save/players/s/
skylib_fluffos_v3/mudlib/save/random_names/
skylib_fluffos_v3/mudlib/save/random_names/data/
skylib_fluffos_v3/mudlib/save/terrains/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_desert/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_grassy_field/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_mountain/
skylib_fluffos_v3/mudlib/save/todo_lists/
skylib_fluffos_v3/mudlib/secure/
skylib_fluffos_v3/mudlib/secure/cmds/admin/
skylib_fluffos_v3/mudlib/secure/cmds/lord/
skylib_fluffos_v3/mudlib/secure/config/
skylib_fluffos_v3/mudlib/secure/handlers/autodoc/
skylib_fluffos_v3/mudlib/secure/handlers/intermud/
skylib_fluffos_v3/mudlib/secure/include/global/
skylib_fluffos_v3/mudlib/secure/save/
skylib_fluffos_v3/mudlib/secure/save/handlers/
skylib_fluffos_v3/mudlib/secure/std/
skylib_fluffos_v3/mudlib/secure/std/classes/
skylib_fluffos_v3/mudlib/secure/std/modules/
skylib_fluffos_v3/mudlib/std/creator/
skylib_fluffos_v3/mudlib/std/dom/
skylib_fluffos_v3/mudlib/std/effects/
skylib_fluffos_v3/mudlib/std/effects/external/
skylib_fluffos_v3/mudlib/std/effects/fighting/
skylib_fluffos_v3/mudlib/std/effects/magic/
skylib_fluffos_v3/mudlib/std/effects/magic/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/other/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/priest/
skylib_fluffos_v3/mudlib/std/effects/room/
skylib_fluffos_v3/mudlib/std/environ/
skylib_fluffos_v3/mudlib/std/guilds/
skylib_fluffos_v3/mudlib/std/guilds/old/
skylib_fluffos_v3/mudlib/std/languages/
skylib_fluffos_v3/mudlib/std/liquids/
skylib_fluffos_v3/mudlib/std/npc/
skylib_fluffos_v3/mudlib/std/npc/goals/
skylib_fluffos_v3/mudlib/std/npc/goals/basic/
skylib_fluffos_v3/mudlib/std/npc/goals/misc/
skylib_fluffos_v3/mudlib/std/npc/plans/
skylib_fluffos_v3/mudlib/std/npc/plans/basic/
skylib_fluffos_v3/mudlib/std/npc/types/
skylib_fluffos_v3/mudlib/std/npc/types/helper/
skylib_fluffos_v3/mudlib/std/npcs/
skylib_fluffos_v3/mudlib/std/outsides/
skylib_fluffos_v3/mudlib/std/races/shadows/
skylib_fluffos_v3/mudlib/std/room/basic/BACKUPS/
skylib_fluffos_v3/mudlib/std/room/basic/topography/
skylib_fluffos_v3/mudlib/std/room/controller/
skylib_fluffos_v3/mudlib/std/room/inherit/topography/
skylib_fluffos_v3/mudlib/std/room/topography/area/
skylib_fluffos_v3/mudlib/std/room/topography/iroom/
skylib_fluffos_v3/mudlib/std/room/topography/milestone/
skylib_fluffos_v3/mudlib/std/shadows/curses/
skylib_fluffos_v3/mudlib/std/shadows/disease/
skylib_fluffos_v3/mudlib/std/shadows/fighting/
skylib_fluffos_v3/mudlib/std/shadows/healing/
skylib_fluffos_v3/mudlib/std/shadows/magic/
skylib_fluffos_v3/mudlib/std/shadows/poison/
skylib_fluffos_v3/mudlib/std/shadows/room/
skylib_fluffos_v3/mudlib/std/shops/controllers/
skylib_fluffos_v3/mudlib/std/shops/objs/
skylib_fluffos_v3/mudlib/std/shops/player_shop/
skylib_fluffos_v3/mudlib/std/socket/
skylib_fluffos_v3/mudlib/std/soul/d/
skylib_fluffos_v3/mudlib/std/soul/e/
skylib_fluffos_v3/mudlib/std/soul/i/
skylib_fluffos_v3/mudlib/std/soul/j/
skylib_fluffos_v3/mudlib/std/soul/k/
skylib_fluffos_v3/mudlib/std/soul/l/
skylib_fluffos_v3/mudlib/std/soul/n/
skylib_fluffos_v3/mudlib/std/soul/o/
skylib_fluffos_v3/mudlib/std/soul/q/
skylib_fluffos_v3/mudlib/std/soul/r/
skylib_fluffos_v3/mudlib/std/soul/u/
skylib_fluffos_v3/mudlib/std/soul/v/
skylib_fluffos_v3/mudlib/std/soul/y/
skylib_fluffos_v3/mudlib/std/soul/z/
skylib_fluffos_v3/mudlib/std/stationery/
skylib_fluffos_v3/mudlib/w/
skylib_fluffos_v3/mudlib/w/default/
skylib_fluffos_v3/mudlib/w/default/armour/
skylib_fluffos_v3/mudlib/w/default/clothes/
skylib_fluffos_v3/mudlib/w/default/item/
skylib_fluffos_v3/mudlib/w/default/npc/
skylib_fluffos_v3/mudlib/w/default/room/
skylib_fluffos_v3/mudlib/w/default/weapon/
skylib_fluffos_v3/mudlib/www/
skylib_fluffos_v3/mudlib/www/java/
skylib_fluffos_v3/mudlib/www/secure/
skylib_fluffos_v3/mudlib/www/secure/lpc/advanced/
skylib_fluffos_v3/mudlib/www/secure/lpc/intermediate/
skylib_fluffos_v3/win32/
/**
 * The automatic document generator.  It takes source files from various
 * directories and creates help files from the comments embedded in the
 * code.
 *
 * @see /secure/handlers/autodoc/autodoc_handler
 * @author Pinkfish
 * @started Fri Oct 24 16:03:57 EDT 1997
 */

#include <autodoc.h>

#define EOF -1

nosave mapping private_functions;

mapping public_functions,
        protected_functions,
        inherits,
        main_docs,
        define_docs,
        includes,
        class_docs;

string file_name;

int last_changed, num_failed_tries;

// Temporary.
nosave string current_comment, current_file;
nosave int current_position, changed;

// We will only handle simple defines.  Function ones we will ignore.
nosave mapping defines;

private mapping parse_comment( string stuff );
private void do_parse_file( function func );
private int query_file_position();
private void handle_inherit( mixed bits );

/** @ignore yes */
private void setup() {
    changed = 0;
    main_docs = 0;
    file_name = "";
    private_functions = ([ ]);
    public_functions = ([ ]);
    protected_functions = ([ ]);
    inherits = ([ ]);
    defines = ([ ]);
    define_docs = ([ ]);
    includes = ([ ]);
    class_docs = ([ ]);
    current_comment = 0;
    current_file = "";
    current_position = 0;
    last_changed = 0;
} /* setup() */

/** @ignore yes */
void create() {
    seteuid(getuid());
    setup();
} /* create() */

/** @ignore yes */
private int query_file_position() { return current_position; }

/** @ignore yes */
private int lookahead_character( int num ) {
    if( current_position + num - 1 < strlen(current_file) )
        return current_file[ current_position + num - 1 ];
    return EOF;
} /* lookahead_character() */

/** @ignore yes */
private int next_character() {
    if( current_position < strlen(current_file) )
        return current_file[current_position++];
    return EOF;
} /* next_character() */

/** @ignore yes */
private int pop_character( int num ) { current_position += num; }

/**
 * @ignore yes
 * Throw away everything to the end of the line.
 */
private void skip_to_end_of_line() {
    int ch;

    do {
        ch = next_character();
    } while( ch != '\r' && ch != '\n' && ch != EOF );

} /* skip_to_end_of_line() */

/**
 * @ignore yes
 * Throw away all the characters until the end of the comment.
 */
private string skip_to_end_of_comment() {
    string data;
    int ch, ok;

    // This will pull all the stuff out of a comment and stick them into
    // a nice string.  Wheeee!
    data = "";
    do {
        ok = 1;
        ch = next_character();
        if( ch == '*' && lookahead_character(1) == '/' ) {
            // End of comment.
            ok = 0;
            pop_character(1);
        } else if( ch == '\r' || ch == '\n' ) {
            data += "\n";
            if( lookahead_character(1) == ' ' )
                pop_character(1);
            if( lookahead_character(1) == '*' && lookahead_character(2) != '/' ) {
                pop_character(1);
                if( lookahead_character(1) == ' ' )
                    pop_character(1);
            }
        } else if( ch == EOF ) {
            ok = 0;
        } else if( ch == '\\' && (
            lookahead_character(1) == '/' ||
            lookahead_character(1) == '*' ||
            lookahead_character(1) == '\\' ) ) {
            // Build up our comment stuff.
        } else {
            data += sprintf("%c", ch );
        }
    } while( ok );

    return data;

} /* skip_to_end_of_comment() */

/**
 * @ignore yes
 * Skips all the spaces and comments that are in our way.
 */
private void skip_spaces_and_comments() {
    int ok;

    do {
        switch( lookahead_character(1) ) {
            case ' ' :
            case '\t' :
            case '\n' :
            case '\r' :
              ok = 1;
              // Move our index up one.
              pop_character(1);
            break;
            case '/' :
              // Could be a comment.
              if( lookahead_character(2) == '/' ) {
                  ok = 1;
                  skip_to_end_of_line();
              } else if( lookahead_character(2) == '*' ) {
                  ok = 1;
                  if( lookahead_character(3) != '*' ||
                      lookahead_character(4) == '*' ) {
                      // Make sure it is not a code comment.
                      pop_character(2);
                      skip_to_end_of_comment();
                      current_comment = 0;
                  } else {
                      pop_character(3);
                      if( lookahead_character(1) == ' ' )
                          pop_character(1);
                      if( !main_docs )
                          main_docs = parse_comment( skip_to_end_of_comment() );
                      else
                          current_comment = skip_to_end_of_comment();
                  }
              } else {
                  ok = 0;
              }
            break;
            default :
              ok = 0;
              break;
        }
    } while (ok);

} /* skip_spaces_and_comments() */

/**
 * @ignore yes
 * Expands the defines...
 */
private string expand_token( string token ) { return defines[token]; }

/**
 * @ignore yes
 * Gets the next token...
 */
private string get_word() {
   string data;
   int ok;
   int ch;

   skip_spaces_and_comments();
   ok = 1;
   data = "";
   ch = lookahead_character(1);
   if( ( ch >= 'a' && ch <= 'z') ||
       ( ch >= 'A' && ch <= 'Z') ||
       ( ch == '_') ) {
       do {
          ch = lookahead_character(1);
          if ((ch >= 'a' && ch <= 'z') ||
              (ch >= 'A' && ch <= 'Z') ||
              (ch >= '0' && ch <= '9') ||
              (ch == '_')) {
             ch = next_character();
             data += sprintf("%c", ch);
          } else {
             ok = 0;
          }
       } while (ok);

       if( expand_token(data) ) {
           current_file = expand_token(data) + current_file[current_position..];
           current_position = 0;
           return get_word();
       }
   } else if( ( ch >= '0' && ch <= '9') || ch == '-') {
      if( ch == '-')
          data += sprintf("%c", next_character() );

      // Number, only search for number bits.
      do {
         ch = lookahead_character(1);
         if( ( ch >= '0' && ch <= '9') ||
             ( ch >= '.') ) {
             ch = next_character();
             data += sprintf("%c", ch);
         } else {
             ok = 0;
         }
      } while (ok);
   } else if( ch == '\"' || ch == '\'') {
      int end_ch;

      end_ch = ch;
      ch = next_character();
      data += sprintf("%c", ch);
      do {
         ch = next_character();
         if (ch == end_ch) {
            ok = 0;
            data += sprintf("%c", ch);
         } else if (ch == '\\') {
            // Skip the next character.
            ch = next_character();
            data += sprintf("\\%c", ch);
         } else if (ch == EOF) {
            ok = 0;
         } else {
            data += sprintf("%c", ch);
         }
      } while (ok);
   } else if (ch == '(') {
      if (lookahead_character(2) == '{' ||
          lookahead_character(2) == '[') {
         return sprintf("%c%c", next_character(), next_character());
      }
      return sprintf("%c", next_character());
   } else if (ch == '}' || ch == ']') {
      if (lookahead_character(2) == ')') {
         return sprintf("%c%c", next_character(), next_character());
      }
      return sprintf("%c", next_character());
   } else if (ch == ';' ||
              ch == ')' ||
              ch == '=' ||
              ch == '{' ||
              ch == '}') {
      // open brace, semi colon, close brace... is a special thingy.
      return sprintf("%c", next_character());
   } else if (ch == EOF) {
      return "";
   } else {
      // All non-space, non alphanumeric...  Dump together...
      do {
         ch = lookahead_character(1);
         if ((ch >= 'a' && ch <= 'z') ||
             (ch >= 'A' && ch <= 'Z') ||
             (ch >= '0' && ch <= '9') ||
             (ch == '_') ||
             (ch == ' ') ||
             (ch == '\t') ||
             (ch == '\n') ||
             (ch == '(') ||
             (ch == ')') ||
             (ch == EOF) ||
             (ch == ';') ||
             (ch == '=') ||
             (ch == '{') ||
             (ch == '}') ||
             (ch == '\'') ||
             (ch == '\"') ||
             (ch == '\r')) {
            ok = 0;
         } else {
            ch = next_character();
            data += sprintf("%c", ch);
         }
      } while (ok);
   }

   return data;

} /* get_word() */

/*
 * Attempts to get a complete statement...
 */
private mixed get_statement(string start) {
   mixed bits;
   string curr;
   int depth;
   string temp_comment;
   int last_pos;
   int in_class;

   // If it starts with the class keyword, then is must be a class.
   // We rip until a semi colon or an open brace.
   // If we find a semi colon...  Then it is a predef or an inherit
   // statement.
   bits = ({ start });
   do {
      last_pos = query_file_position();
      curr = get_word();
      bits += ({ curr });
      if( last_pos != query_file_position() ) {
          // Make sure it is doing something.
          reset_eval_cost();
      }
   } while (curr != ";" && curr != "{" && curr != "");

   if( curr == "{") {
      if( member_array("class", bits ) != -1 &&
          member_array("(", bits ) == -1 ) {
          // We have a class, now we need to parse this in a useful way.
          // Sadly this cannot fit into the normal way of parsing.  It is an
          // exception to one of those rules :)
          in_class = 1;
      }

      // Grab the rest...  but ignore it.
      // Keep the current comment though.
      temp_comment = current_comment;
      depth = 1;
      do {
        last_pos = query_file_position();
        curr = get_word();
        if (curr == "{") {
           depth++;
        } else if (curr == "}") {
           depth--;
        } else if (curr == "") {
           // End of file.
           depth = 0;
        }

        if( last_pos != query_file_position() ) {
            // Make sure it is doing something.
            reset_eval_cost();
        }
        if (in_class) {
           bits += ({ curr });
        }
      } while (depth > 0);
      current_comment = temp_comment;
   }

   return bits;
} /* get_statement() */

/*
 * This parses the comment into the appropriate bits...
 */
private mapping parse_comment(string stuff) {
   string *bits;
   int i;
   mapping frog;
   string name;
   int j;
   int rabbit;

   if( !stuff )
       return ([ ]);

   if( stuff[0] == '@') {
       stuff = "\n" + stuff;
   } else {
       stuff = "\n@main " + stuff;
   }

   bits = explode(stuff, "\n@");
   frog = ([ ]);

   for( i = 0; i < sizeof(bits); i++ ) {
      j = strsrch( bits[i], " ");
      rabbit = strsrch( bits[i], "\n");
      if( j == -1 || ( rabbit != -1 && rabbit < j ) ) {
          j = rabbit;
      }

      if( j > 0 ) {
         name = bits[i][0..j - 1];
         stuff = bits[i][j+1..];

         if( !frog[name] ) {
             frog[name] = ({ stuff });
         } else {
             frog[name] += ({ stuff });
         }
      }
   }

   return frog;

} /* parse_comment() */

/*
 * Handles a class...
 */
private void handle_class( mixed bits ) {
   string name;
   int i;
   string *types;
   mapping comm;

   name = bits[1];
   types = ({ });

   i = member_array("{", bits );

   if( i != -1 ) {
       // Ok, figure out all the elements and types.
       bits = bits[i + 1..];
       while( sizeof(bits) ) {
          i = member_array(";", bits);
          if( i != -1 ) {
              types += ({ ({ bits[i - 1], bits[0..i - 2] }) });
              bits = bits[i + 1..];
          } else {
              bits = ({ });
          }
       }

       comm = parse_comment(current_comment);
       if( !comm["ignore"] )
           class_docs[name] = ({ 0, types, parse_comment(current_comment) });
   }

} /* handle_class() */

/*
 * Handles an inherit...  Sticks all the needed stuff in like the
 * thing being inherited and the state of it and stuff.
 */
private void handle_inherit( mixed bits ) {
   int pos;
   string name;

   pos = member_array("inherit", bits );
   if( pos >= 0 ) {
       // Need to strip off the last thingy which should be a semi colon.
       name = implode( map( bits[pos+1.. sizeof(bits)-2],
           function( string str ) {
               if( str[0] == '\"') {
                   sscanf( str, "\"%s\"", str );
                   return str;
               }
               if( str = string_to_define(str) )
                   return str;
               return "";
           } ), "");
       inherits[name] = bits[0..pos-1];
   }
} /* handle_inherit() */

/*
 * We have found a function definition...  Create the information
 * we need from it.
 */
private void handle_function_definition(mixed bits) {
   int pos, end_pos, new_pos;
   string name, *type;
   mapping comm;
   mixed args;

   pos = member_array("(", bits );

   if( pos > 0 ) {
       name = bits[pos-1];
       if( !AUTODOC_H->exclude_method(name) ) {
           type = bits[0..pos-2];
           if( !sizeof(type) )
               type = ({"int"});
           end_pos = member_array(")", bits, pos );
           args = ({ });
           if( end_pos > pos + 1 ) {
               // Whoo, there are some arguments.
               pos++;
               while( member_array(",", bits, pos ) != -1 ) {
                   new_pos = member_array(",", bits, pos );
                   args += ({ bits[pos..new_pos-2], bits[new_pos-1] });
                   pos = new_pos + 1;
               }
               args += ({ bits[pos..end_pos -2], bits[end_pos-1] });
           }
           comm = parse_comment(current_comment);
           if( !comm["ignore"] ) {
               if( member_array("private", type ) != -1 ) {
                   type -= ({"private"});
                   private_functions[name] = ({ type, args, comm });
               } else if( member_array("protected", type ) != -1 ) {
                   type -= ({"protected"});
                   protected_functions[name] = ({ type, args, comm });
               } else {
                   type -= ({"public"});
                   public_functions[name] = ({ type, args, comm });
               }
           }
       }
       current_comment = 0;
   }
} /* handle_function_definition() */

/*
 * Gets the rest of the line.  Mostly used by the hash stuff...
 */
private string get_rest_of_line() {
   string value;
   int ch;
   int last_pos;

   value = "";
   // Skip the spaces at the start.
   ch = lookahead_character(1);
   while (ch == ' ' || ch == '\t') {
      pop_character(1);
      ch = lookahead_character(1);
   }

   // Get the whole definition.
   do {
      last_pos = query_file_position();
      ch = next_character();
      if (ch == '\\') {
         // Skip one!  This is escaped...
         ch = next_character();
         if (ch == '\r' && lookahead_character(1) == '\n') {
            // Handle MSDOS sillyness.
            ch = next_character();
         }
         ch = ' ';
      }
      if (last_pos != query_file_position()) {
         reset_eval_cost();
      }
      value += sprintf("%c", ch);
   } while (ch != '\n' && ch != '\r' && ch != EOF);

   return value;

} /* get_rest_of_line() */

/*
 * Handles the hairy #define's and #includes.
 */
private void handle_hash() {
   int i;
   string token;
   string name;
   string value;
   string *bits;
   string stuff;
   string inc_name;
   string curr_comm;
   mapping comm;

   token = get_word();

   // Not really sure what to do about these right now.
   switch (token) {
      case "define" :
      case "defin" :
         // Ok, with a define...  we... get a name and a substitution value.
         curr_comm = current_comment;
         value = get_rest_of_line();
         if (sscanf(value, "%s %s", name, value) == 2) {
            defines[name] = value;
            if (token == "define") {
               comm = parse_comment(curr_comm);
               if (!comm["ignore"]) {
                  define_docs[name] = comm;
               }
               current_comment = 0;
            }
         }
         break;
      case "include" :
         // Eeeek!  This will be evil... At the moment assume they don't
         // do arithmetic in the #include line...
         value = get_rest_of_line();
         if (value[0] == '\"') {
            // This means a local inherit...
            bits = explode(file_name, "/");
            sscanf(value, "\"%s\"", name);
            stuff = read_file(implode(bits[0..<2], "/") +
                              "/" + name);
            if (stuff) {
               inc_name = "/" + implode(bits[0..<2], "/") +
                              "/" + name;
            }
         } else if (value[0] == '<') {
            // This means it could be a global inherit...
            sscanf(value, "<%s>", name);
         }

         if( name[0] == '/') {
             stuff = read_file(name);
             if( stuff )
                 inc_name = name;
         }

         bits = master()->define_include_dirs();

         while( !stuff && i < sizeof(bits) ) {
            stuff = read_file( sprintf(bits[i], name ) );
            if( stuff ) {
               // Remove all the autodoc comments from the include file...
               stuff = replace_string( stuff, "/**", "/* ");
               // Ignore included classes.
               stuff = replace_string( stuff, "class ", "clas ");
               stuff = replace_string( stuff, "#define ", "#defin ");
               inc_name = sprintf( bits[i], name );
            }
            i++;
         }

         if( inc_name ) {
            // Zap double '//'s
            inc_name = replace( inc_name, "//", "/");
            if( inc_name[0] != '/')
                inc_name = "/" + inc_name;
         }

         if( stuff ) {
             // We found it!  Stick the include bit in where it is needed.
             if( !includes[inc_name] ) {
                 current_file = stuff + current_file[current_position..];
                 current_position = 0;
             }
             // Update the time as well.
             includes[inc_name] = unguarded( (: stat($(inc_name)) :) )[1];
         }
         break;
      default :
         // Pragma's and other silly hash things.
         skip_to_end_of_line();
         break;
   }
} /* handle_hash() */

/*
 * Gets the next token...  This is state dependant, we need to know
 * what state we are in to figure out what sort of token we are probably
 * looking for...
 */
private void next_statement() {
   string token;
   string *bits;

   token = get_word();
   // A hash directive.
   if( token[0] == '#') {
       return handle_hash();
   } else if (token == ";") {
       return ;
   } else if (token != "") {
       bits = get_statement(token);
       if( member_array("inherit", bits) != -1 ) {
           // An inherit statement.
           return handle_inherit(bits);
       } else if( bits[0] == "class" && member_array("(", bits) == -1 ) {
           return handle_class(bits);
       } else if( bits[sizeof(bits) - 1] == "{" &&
           member_array("=", bits) == -1 ) {
           return handle_function_definition(bits);
       } else {
           // It was a predef or a variable declaration.
           return;
       }
   }
} /* next_statement() */

/**
 * Loads up the currently set file name from the archives.
 */
void load_file() {
   unguarded( (: restore_object( AUTODOC_SAVE_DIR +
                 replace_string(file_name, "/", ".") ) :) );

   if( !includes )
       includes = ([ ]);
   if( !class_docs )
       class_docs = ([ ]);

} /* load_file() */

/**
 * Saves the current file name to the archives.
 */
void save_file() {
   unguarded( (: save_object( AUTODOC_SAVE_DIR +
                 replace_string(file_name, "/", ".") ) :) );
} /* save_file() */

/**
 * Parses the input file figuring out all the documentation bits of it.
 * @param name the name of the file to parse
 * @param func the function to call when the parsing is finished
 * @param only_load a flag telling us to only load the information
 */
void parse_file( string name, function func, int only_load ) {
   int curr_change, reload;
   string my_name, new_file;

   setup();
   file_name = name;
   load_file();

   if( !only_load ) {
       if( sizeof( unguarded( (: stat($(name)) :) ) ) ) {
           if( file_size(name) != -2 ) {
               curr_change = unguarded( (: stat($(name)) :) )[1];
           } else {
               AUTODOC_H->remove_file(name);
               if( name[<1] != '/')
                   name += "/";
               foreach( new_file in unguarded( (: stat($(name)) :) ) ) {
                   if( file_size(name+new_file) != -2 &&
                       new_file[sizeof(new_file)-2..sizeof(new_file)] )
                       AUTODOC_H->add_file(name+new_file);
               }
               if( func )
                   call_out( (: evaluate($1) :), 2, func );
               return;
           }

           reload = curr_change > last_changed || file_name(PO) == AUTODOC_H;

           if( !reload ) {
               // Check to see if the include files have changed.
               foreach( my_name in keys(includes) ) {
                   if( unguarded( (: file_exists($(my_name)) :) ) ) {
                       new_file = AUTODOC_SAVE_DIR +
                                  replace_string(my_name, "/", ".")+".o";

                       // Add all missing includes to the handler.
                       if( !unguarded( (: file_exists($(new_file)) :) ) ) {
                           event( users(), "inform", "Autodoc: Adding \""+
                               my_name+"\"", "autodoc");
                           AUTODOC_H->add_file(my_name);
                           reload = 1;
                           continue;
                       }

                       if( unguarded( (: stat($(my_name)) :) )[1] >
                           unguarded( (: stat($(new_file)) :) )[1] ) {
                           event( users(), "inform", "Autodoc: Updating \""+
                               my_name+"\" - \""+new_file+"\" outdated",
                               "autodoc");
                           reload = 1;
                           break;
                       }
                   }
               }
           }

           if( reload ) {
               setup();
               num_failed_tries = 0;
               file_name = name;
               changed = 1;
               last_changed = curr_change;
               current_file = read_file(name);
               current_position = 0;
               event( users(), "inform", "Autodoc: Parsing \""+file_name+"\"",
                   "autodoc");
               if( catch( do_parse_file(func) ) )
                   evaluate(func);
           } else {
               if( num_failed_tries ) {
                   num_failed_tries = 0;
                   save_file();
               }
               event( users(), "inform", "Autodoc: Skipping \""+file_name+"\"",
                   "autodoc");
               if( func )
                   call_out( (: evaluate($1) :), 2, func );
           }
       } else {
           event( users(), "inform", "Autodoc: No file \""+file_name+"\"",
               "autodoc");
           num_failed_tries++;
           save_file();
           if( func )
               call_out( (: evaluate($1) :), 2, func );
       }
   } else {
       if( func )
           call_out( (: evaluate($1) :), 2, func );
   }

} /* parse_file() */

/** @ignore yes */
private void do_parse_file( function func ) {
   int num;

   // Darn, changed while we were reading it.
   if( file_size(file_name) != -2 &&
       unguarded( (: stat(file_name) :) )[1] > last_changed )
       return parse_file( file_name, func, 0 );

   num = 0;

   while( lookahead_character(1) != EOF && num < 2 ) {
       next_statement();
       num++;
   }

   if( lookahead_character(1) == EOF ) {
       save_file();
       if( func )
           call_out( (: evaluate($1) :), 2, func );
   } else {
       call_out( (: do_parse_file :), 1, func );
   }

} /* do_parse_file() */

/**
 * Returns the inherits mapping of the system.  This returns a mapping of the
 * form ([ inherit_name : ({ flags }) ]).  Where the name of the inherit is
 * something like "/std/object" and the flags are things you can apply to
 * an inherit, like "protected" or "private".  If there are no flags then
 * the flags will be an empty array.
 * @return a mapping of things inherited by this file
 */
mapping query_inherits() { return inherits; }

/**
 * The mapping of private functions.
 * The mapping is of the form ([ func_name : ({ type, args, docs }) ]).
 * The type bit is an array of the type name, ie: ({ "int" }) or
 * ({ "mixed", "*" }).  The args bit looks like ({ "name", type }),
 * where the type is the same as in the previous array.  The docs is
 * a mapping of the form ([ "tag" : ({ data }) ]), where each reference
 * to a tag creates a new element in the data array.
 * @return a mapping containing the private functions
 */
mapping query_private_functions() { return private_functions; }

/**
 * The mapping of public functions.
 * The mapping is of the form ([ func_name : ({ type, args, docs }) ]).
 * The type bit is an array of the type name, ie: ({ "int" }) or
 * ({ "mixed", "*" }).  The args bit looks like ({ "name", type }),
 * where the type is the same as in the previous array.  The docs is
 * a mapping of the form ([ "tag" : ({ data }) ]), where each reference
 * to a tag creates a new element in the data array.
 * @return a mapping containing the public functions
 */
mapping query_public_functions() { return public_functions; }

/**
 * The mapping of protected functions.
 * The mapping is of the form ([ func_name : ({ type, args, docs }) ]).
 * The type bit is an array of the type name, ie: ({ "int" }) or
 * ({ "mixed", "*" }).  The args bit looks like ({ "name", type }),
 * where the type is the same as in the previous array.  The docs is
 * a mapping of the form ([ "tag" : ({ data }) ]), where each reference
 * to a tag creates a new element in the data array.
 * @return a mapping containing the protected functions
 */
mapping query_protected_functions() { return protected_functions; }

/**
 * Returns the main docs for the class.  The mapping is of
 * the form ([ "tag" : ({ data }) ]), where each reference
 * to a tag creates a new element in the data array.
 * @return a mapping containing the main docs for the file
 */
mapping query_main_docs() { return main_docs || ([ ]); }

/**
 * The file name being processed.
 * @return the name of the file being processed
 */
string query_file_name() { return file_name; }

/**
 * The defines which were setup in the class.  This is the mapping of the
 * defines which were processed.  The format of the mapping is
 * ([ "name" : "value" ]), where the name is the name of the define and
 * the value is what to replace it with.
 * @return the mapping of defines
 */
mapping query_defines() { return defines; }

/**
 * Did the file change?  Checks to see if the file changed since it
 * was last read.
 * @return 1 if it changed, 0 if it has not changed
 */
int query_changed() { return changed; }

/**
 * This method returns the number of times the file was attempted to
 * be read and it was discovered not to exist at all.
 * @return the number of times it was unable to be read
 */
int query_num_failed_tries() { return num_failed_tries; }

/**
 * The files included by this one.
 * @return an array of included files
 */
string *query_includes() { return keys(includes); }

/** @ignore yes */
mapping query_all_includes() { return includes; }

/**
 * The documentation for the defines.  This is mostly used by the include
 * file documentation system.
 * @return the mapping of define names to documentation
 */
mapping query_define_docs() { return define_docs; }

/**
 * The documentation for the classes.
 * @return the mapping of the class names to documentation
 */
mapping query_class_docs() { return class_docs; }

/** @ignore yes */
void dest_me() { destruct(TO); }