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/
/**
 * Documentation system for removing documentation from source files.
 * <p>
 * The documentation will be created in the directory /doc/autodoc.  Extra
 * documentation should be placed into the other help directories and will
 * be accessed via the help system.  The html documentation will be placed
 * into the /www/autodoc directory.  The files in theses directories will
 * be named with the '/'s replaced with '.'s.  ie: /obj/handlers/room_handler.c
 * would be in the file /doc/autodoc/obj.handlers.room_handler.c and
 * /www/autodoc/obj.handlers.room_handler.c.html.  An index of the methods
 * and object names will be generated from the input files and linked into the
 * help system.  An alphabetical index will also be produced that is linked
 * to the html stuff.
 * <p>
 * The first comment which follows the comment format below and occurs right
 * before a function will be used as the documentation for that function.  The
 * comment must start with two '*'s to distinguish it from a normal comment.
 * A special tag at the start of one of the first comments in the file will
 * signify that it is a comment for the class.
 * <p>
 * Only comments before a real function declaration will be used, comments
 * before a predeclaration will be ignored.
 * <p>
 * Any function which is not declared as private and does not have the @ignore
 * tag in its description will be placed into the resulting documentation
 * file.  This will be done even if no comment was found.
 * <p>
 * In the text part of the comment the main section is a free form
 * documentation, it is merely a description of the whole function.  After
 * this several tags can be added to the comment which allows other things
 * to be documented.  All the text after the tag is taken as part of that
 * tags information.  The main tag should never actually be used, it
 * is implied as being the tag associated with the first section of
 * comment.
 * <p>
 * HTML tags will be used in the comments to allow certain things to
 * happen.  The tags 'p', 'b', 'i', 'code', 'ul', 'ol', 'dl', 'dd', 'dt', 'pre'
 * and 'li' will be supported.
 * <p>
 * The sequences '\\/', '\\\\' and '\<' will be processed by the comment
 * handling code so that they do not get placed into the output code.
 * <p>
 * White space is ignored...  Both html and roff format files will be
 * created from the documentation maker.
 * <p>
 * The supported tags are:
 * <dl>
 * <dt>@param
 * <dd>Specify the parameter and what it does.  This should be one short
 *     sentence only.  There needs to be one of these for every
 *     parameter, the first word of the sentence is the name of the
 *     parameter and the rest is the description.  There should be no full
 *     stop on the end of the sentance.
 * <dt>@member
 * <dd>This is used with classes and defines the members of the class.  The
 *     definition is the same as for the @param element above.
 * <dt>@return
 * <dd>Specify what the return value is.  This should be one short
 *     sentence only.  Theres should only be one of these in every
 *     function.  There should be no full stop on the end of the sentence.
 * <dt>@see
 *   <dd>Specify an object or function to see.  The format must be one of:
 *   <ul>
 *   <li> object_name<br><i>@see /global/new_parse</i>
 *   <li> function_name()<br><i>@see frog()</i>
 *   <li> object_name->function_name()<br><i>@see /global/new_parse->add_command()</i>
 *   <li> efun::name()<br><i>@see efun::sort_array()</i>
 *   <li> help::name<br><i>@see help::effects</i>
 *   </ul>
 * <dt>@ignore
 *   <dd>Do not document this function, the whole comment is ignored.
 * <dt>@main
 *   <dd>The main documentation section.
 * <dt>@classification
 *    <dd>Used in the effects files to classify the effect.  So a tree
 *      of the classifications can be derived.
 * <dt>@index
 *        <dd>Adds in a new index reference on this name.  This should be one
 *            word only.
 * <dt>@change
 *   <dd>Placed in the class documentation to reference a change list.
 *            First line after the tag is the date and the author and
 *            then follows a description of the change.
 * <dt>@example
 *   <dd>If you wish to embed an example in the code.
 * <dt>@started
 *   <dd>When the file was started.
 * <dt>@author
 *   <dd>The author of the file.
 * </dl>
 *
 * The output format will look something like the API documentation for
 * java.  If you have not seen this before, go to http://www.javasoft.com
 * and look in the JDK and then the API section.
 * <p>
 * Comment format:
 * <pre>
 * /\**
 *  *  <text>
 *  *    ..
 *  *  <text>
 *  *
 *  *\/
 * </pre>
 *
 * ie: it starts with a /\** and ends with a *\/ on a line by themselves and
 * every intervening line has a * at the start.  By using a \\ you can
 * make characters escaped.  This means they are not processed by
 * the internal system, so to make a end comment appear inside a
 * the text you go : *\\/
 *
 * @example
 * inherit "/std/object";
 *
 * /\**
 *  *   This class is a nice shade of blue and allows all other shades of
 *  *   green and yellow to mix well.
 *  * @see yellow
 *  * @see blue
 *  * @change 12/3/97 Pinkfish
 *  *    Pushed some of the yellow stuff down a hole and ate a bagel.
 *  *\/
 *
 * /\**
 *  * This method mixes the green in with our blue.
 *  * @param  green   the green object to mix.
 *  *\/
 * void mixGreen(object green) {
 *   /\* Something wild and exciting! *\/
 * } /\* mixGreen() *\/
 *
 * /\**
 *  * This method mixes the yellow in with our blue.
 *  * @param  yellow the yellow object to mix.
 *  * @return returns a TRUE or FALSE depending on if the mix succeeded.
 *  * @example
 *  *   mixYellow(12);
 *  *\/
 * int mixYellow(object yellow) {
 * } /\* mixYellow() *\/
 *
 * @index autodoc
 * @see autodoc_file
 * @see autodoc_nroff
 * @see autodoc_html
 * @author Pinkfish
 * @started Tue Oct 28 13:25:09 EST 1997
 *
 */

#include <autodoc.h>

/**
 * This defines the main save file of the handler.
 */
#define AUTODOC_SAVE_FILE      (AUTODOC_SAVE_DIR "main_rubbish")

/**
 * This defines the interval at which we force a save to store the file_pos.
 * Let's do this every 6 hours.
 */
#define SAVE_FILE_POS_INTERVAL (60*60*6)

string *files;
mapping help_map;
int file_pos, something_changed, last_created_index;

nosave int call_id, last_saved;
nosave mapping summary_map;
nosave mixed extra_indexes;
nosave string *exclude_methods;
nosave object *in_use, *recycled;

private void create_nroff_file( object ob );
private void create_html_index( mixed ob );
private void after_thingy( int no_index );
private void start_processing();
private void do_parse_next_file();
private void create_index();
private void add_to_index( object ob );
private void save();
string *query_files();
int remove_file( string fname );

/** @ignore yes */
void set_file_pos( int number ) { file_pos = number; }

void create() {
    seteuid(getuid());

    file_pos = 0;
    something_changed = 0;
    files = ({ });

    unguarded( (: restore_object( AUTODOC_SAVE_FILE ) :) );

    if( !mapp( help_map ) )
        help_map = ([ ]);

    exclude_methods = ({"create", "setup", "init", "reset", "dest_me"});
    in_use = recycled = ({ });

    last_saved = time();

    start_processing();

} /* create() */

/** @ignore yes */
private void create_nroff_file( object ob ) {
    string fname;

    // Now we create the nroff file.
    fname = replace( ob->query_file_name(), "/", ".");
    if( fname[0] == '.')
        fname = fname[1..];
    rm( NROFF_DOC_DIR + fname );
    event( users(), "inform", "Creating "+NROFF_DOC_DIR + fname, "autodoc");
    AUTODOC_NROFF->create_nroff_file( ob, NROFF_DOC_DIR + fname );

} /* create_nroff_file() */

/** @ignore yes */
private void create_html_index( mixed ob ) {
    string fname, letter;
    mixed stuff, tmp;
    mapping chars;

    // Create an index file.
    stuff = map( query_files(), function( string name ) {
                string *bits;

                bits = explode(name, "/");
                return ({ bits[sizeof(bits)-1], name, "", summary_map[name] });
            } );

    stuff = unique_array( ob + stuff, (: lower_case($1[0])[0] :));
    chars = ([ ]);

    foreach( tmp in stuff ) {
        letter = tmp[0][0][0..0];
        fname = "index_" + lower_case(letter) + ".html";
        AUTODOC_HTML->create_html_index_file( tmp, letter,
                                              HTML_DOC_DIR + fname );
        reset_eval_cost();
        chars[CAP(letter)] =  fname;
    }

    // The different sorts of indexes will be genertated in the html file.
    fname = HTML_DOC_DIR;;
    AUTODOC_HTML->create_main_index( chars, fname );

} /* create_html_file() */

/**
 * This method returns the autodoc parsers currently loaded.
 * @return the currently loaded autodoc parsers
 */
object *query_parsers_in_use() { return in_use; }

/**
 * This method returns the autodoc parsers currently recycled.
 * @return the recycled autodoc parsers
 */
object *query_parsers_recycled() { return recycled; }

/** @ignore yes */
private void recycle_parser( object ob ) {
    in_use -= ({ ob, 0 });

    // Maintain two parsers at most.
    if( sizeof( recycled -= ({ 0 }) ) > 2 ) {
        ob->dest_me();
    } else {
        reload_object(ob);
        recycled += ({ ob });
    }
} /* recycle_parser() */

/** @ignore yes */
private object get_parser() {
    object ob;

    if( sizeof( recycled -= ({ 0 }) ) ) {
        ob = recycled[0];
        recycled = recycled[1..];
    } else {
        ob = clone_object(AUTODOC_FILE);
    }

    in_use += ({ ob });

    return ob;

} /* get_parser() */

/** @ignore yes */
private void after_thingy( int no_index ) {
    if( member_array( PO->query_file_name(), files ) == -1 ) {
        call_out( (: recycle_parser :), 5, PO );
        return;
    }

    if( no_index )
        event( users(), "inform", "Autodoc: finished recreating the "
            "documentation for "+PO->query_file_name(), "autodoc");

    if( PO->query_changed() )
        something_changed = 1;

    event( users(), "inform", "Autodoc: \""+PO->query_file_name()+"\" "+
         ( PO->query_num_failed_tries() ? "failed to parse correctly!" :
         "parsed correctly." ), "autodoc");

    // This means that the file has been deleted...  Argh!  Auto remove it.
    // Delete PO->query_file_name(), not some file_pos - Sandoz.
    if( PO->query_num_failed_tries() > 1 )
        remove_file( PO->query_file_name() );
    else if( PO->query_changed() || no_index )
        call_out( (: create_nroff_file :), 0, PO );

    call_out( (: recycle_parser :), 5, PO );
    save();

} /* after_thingy() */

/**
 * This method queries whether or not the documentation
 * for the specified file has expired.
 * @param name the file name to check
 * @return 1 if an update is needed
 */
int query_update_needed( string name ) {
    int cur_change;
    string my_name, dotless;

    // No such file or directory.
    if( !sizeof( unguarded( (: stat($(name)) :) ) ) ) {
        remove_file( name );
        return 0;
    }

    // A directory - always update.
    if( dir_exists(name) )
        return 1;

    my_name = replace_string( name, "/", ".");
    dotless = ( my_name[0] == '.' ? my_name[1..] : my_name );

    if( my_name[<2..] == ".c" )
        my_name = my_name[0..<3];

    // No save file.
    if( !unguarded( (: file_exists($(AUTODOC_SAVE_DIR+my_name+".o")) :) ) )
        return 1;

    // No NROFF file.
    if( !unguarded( (: file_exists($(NROFF_DOC_DIR+dotless)) :) ) )
        return 1;

    cur_change = unguarded( (: stat($(name)) :) )[1];

    // The main file is outdated.
    if( cur_change > unguarded( (: stat($(AUTODOC_SAVE_DIR+my_name+".o")) :) )[1] )
        return 1;

    // The nroff docs are outdated.
    if( cur_change > unguarded( (: stat($(NROFF_DOC_DIR+dotless)) :) )[1] )
        return 1;

    return 0;

} /* query_update_needed() */

/** @ignore yes */
private void do_parse_next_file() {
    // Give it a minute to do this file.
    call_id = call_out( (: start_processing :), 60 );

    if( file_pos >= sizeof(files) ) {
        file_pos = 0;
        return;
    }

    if( query_update_needed(files[file_pos]) )
        get_parser()->parse_file( files[file_pos], (: after_thingy(0) :) );
    else
        event( users(), "inform", "Autodoc: Docs for \""+
            files[file_pos]+"\" already up to date", "autodoc");

    if( time() > last_saved + SAVE_FILE_POS_INTERVAL )
        save();

    file_pos++;

} /* do_parse_next_file() */

/** @ignore yes */
private void start_processing() {
    if( !sizeof(files) )
        return;

    // Ok, now we skip onto the next file and zoom it.
    if( last_created_index + SAVE_INDEX_DELAY < time() ) {
        if( something_changed )
            call_out( (: create_index :), 2 );
        something_changed = 0;
        save();
    }

    call_id = call_out( (: do_parse_next_file :), 180 );

} /* start_processing() */

/** @ignore yes */
private string query_short_args_def( mixed args ) {
    string ret;
    int i;

    ret = "";

    for( i = 0; i < sizeof(args); i += 2 ) {
       if( i != 0 )
           ret += ", ";
       ret += implode( args[AUTO_ARGS_TYPE], " ");
    }

    return "(" + ret + ")";

} /* query_short_args_def() */

/**
 * This method queries whether or not a function with the specified
 * name should be documented or not.
 * This prevents create, setup, reset, init and dest_me from
 * being documented.
 */
int exclude_method( string name ) {
    return member_array( name, exclude_methods ) != -1;
} /* exclude_method() */

/**
 * @ignore yes
 * This will add it into the help array stuff too.
 */
private string *process_stuff( string name, string fname, string fn,
                               mapping docs ) {
    string blue;
    int i, end;
    mixed ret;
    mapping fluff;

    if( !exclude_method(name) ) {
        if( help_map[name] )
            help_map[name] += ({ fn });
        else
            help_map[name] = ({ fn });
    }

    if( docs[name] ) {
        if( arrayp(docs[name]) ) {
            // Its a function!
            fluff = docs[name][AUTO_DOCS];
            ret =  ({ name, fname, query_short_args_def(docs[name][AUTO_ARGS]) });
        } else {
            ret = ({ name, fname, "" });
            fluff = docs[name];
        }
    } else {
        ret = ({ name, fname, "" });
        if( mapp(docs) ) {
            fluff = docs;
        } else {
            fluff = ([ ]);
        }
    }

    if( fluff["main"] ) {
        blue = implode( fluff["main"], "\n");
        end = strlen(blue);
        i = strsrch( blue, ".");
        if( i > 0 )
            end = i;
        i = strsrch( blue, "!");
        if( i > 0 && i < end )
            end = i;
        i = strsrch( blue, "?");
        if( i > 0 && i < end )
            end = i;
        blue = blue[0..end];
    }

    ret += ({ blue });

    if( fluff["index"] ) {
        foreach( blue in fluff["index"] ) {
            blue = replace( blue, ({ " ", "", "\n", "" }));
            if( help_map[blue] ) {
                help_map[blue] += ({ fn });
            } else {
                help_map[blue] = ({ fn });
            }
            extra_indexes += ({ ({ blue, fname, "", ret[AUTO_INDEX_SUMMARY] }) });
       }
    }

    return ret;

} /* process_stuff() */

/** @ignore yes */
private void create_index() {
    mixed index_stuff, rabbit;
    string fname, fn, *bits, file;
    object parse;

    // Build up the list.
    index_stuff = ({ });
    help_map = ([ ]);
    extra_indexes = ({ });
    summary_map = ([ ]);

    parse = get_parser();

    foreach( file in files ) {
        // Do not process it.  Merely load it from disk.
        parse->parse_file( file, 0, 1 );
        fname = parse->query_file_name();
        if( fname ) {
            fn = replace( fname, "/", ".");
            if( fn[0] == '.' )
                fn = fn[1..];
            fn = NROFF_DOC_DIR + fn;
            bits = explode( fname[0..strlen(fname)-3], "/");
            rabbit = process_stuff( bits[sizeof(bits) - 1], "", fn,
                                    parse->query_main_docs() );
            if( rabbit[AUTO_INDEX_SUMMARY] ) {
                summary_map[fname] = rabbit[AUTO_INDEX_SUMMARY];
            } else {
                map_delete( summary_map, fname );
            }

            // We loaded it...
            index_stuff += map( keys( parse->query_public_functions() ),
                                (: process_stuff( $1, $(fname), $(fn),
                                $(parse)->query_public_functions() ) :) );
            index_stuff += map( keys( parse->query_protected_functions() ),
                                (: process_stuff( $1, $(fname), $(fn),
                                $(parse)->query_protected_functions() ) :) );
            index_stuff += map( keys( parse->query_class_docs() ),
                                (: process_stuff( $1, $(fname), $(fn),
                                $(parse)->query_class_docs() ) :) );
            if( sscanf( fname, "%*s.h" ) == 1 ) {
                index_stuff += map( keys( parse->query_define_docs() ),
                                (: process_stuff( $1, $(fname), $(fn),
                                $(parse)->query_define_docs() ) :) );
            }
        }
        reset_eval_cost();
    }

    if( parse )
        recycle_parser(parse);

    index_stuff += extra_indexes;
    extra_indexes = ({ });

    // Don't call this out.  We would be copying huge arrays around.  Eeek.
//    catch( create_html_index( index_stuff ) );

    summary_map = ([ ]);
    last_created_index = time();
    save();

    event( users(), "inform", "Autodoc: Index generation successful",
        "autodoc");

} /* create_index() */

/**
 * Recreate documentation for one field immediately.  This does not update
 * the index, it merely creates the base files for this file.  It does it
 * at a random delay of up to 30 seconds.
 * @param fname the file name to update
 */
int recreate_documentation( string fname ) {
    if( member_array( fname, files ) != -1 ) {
        get_parser()->parse_file( fname, (: after_thingy(1) :) );
        return 1;
    }

    return 0;

} /* recreate_documentation() */

/**
 * Regenerate the index files.
 */
void recreate_indexes() {
     unguarded( (: create_index() :) );
} /* recreate_indexes() */

/**
 * Adds a file into the list of files to process for autodocumentation.
 * This file will be processed every time around in the autodocumentation
 * loop to check to see if it has been changed and the results will be
 * placed into the index.  It automaticly calls recreate_documentation
 * in random(60) seconds.
 * @see recreate_documentation()
 * @param fname the name of the file to add
 * @return 1 if the add succeeds, 0 otherwise.
 */
int add_file( string fname ) {

    fname = "/" + implode( explode( fname, "/" ) - ({ "" }), "/" );

    if( fname[0..2] == "/w/" || fname[0..2] == "/d/" )
        event( users(), "inform", "Autodoc: Adding \""+
            fname+"\" to autodoc handler!", "autodoc");

    if( member_array( fname, files ) == -1 ) {
        if( sizeof( unguarded( (: stat($(fname)) :) ) ) ) {
            files += ({ fname });
            save();
            if( sizeof(files) == 1 )
                start_processing();
            else
                call_out( (: recreate_documentation :), 20, fname );
            return 1;
        }
    }

    return 0;

} /* add_file() */

/**
 * Removes a file from the list of files to be processed
 * for autodocumentation.
 * @param fname the name of the file to remove
 * @return 1 if the remove succeeds, 0 otherwise.
 */
int remove_file( string fname ) {
    string fn, dfn, *our_files;
    int i;

    if( member_array( fname, files ) != -1 ) {
        files -= ({ fname });
        file_pos = 0;


        fn = replace_string( fname, "/", ".");
        dfn = ( fn[0] == '.' ? fn[1..] : fn );

        if( fn[<2..] == ".c" )
            fn = fn[0..<3];

        fn = AUTODOC_SAVE_DIR+fn+".o";

        // Delete the save file.
        unguarded( (: rm($(fn)) :) );

        // Delete the nroff files.
        unguarded( (: rm( NROFF_DOC_DIR+$(dfn) ) :) );

        // Delete the nroff single function files.
        fn = NROFF_DOC_SINGLE+( fname[0] == '/' ? fname[1..<3] :
                                                  fname[0..<3] )+"/";
        our_files = get_dir(fn);

        if( sizeof(our_files) )
            foreach( dfn in our_files )
                unguarded( (: rm($(fn+dfn)) :) );

        // Remove the directory if it exists.
        if( dir_exists(fn) )
            unguarded( (: rmdir($(fn)) :) );

        // Try to remove the next upper directory as well, if it's empty.
        if( ( i = strsrch( fn[0..<2], "/", -1 ) ) != -1 ) {
            fn = fn[0..i];
            if( dir_exists(fn) && !sizeof( get_dir(fn) ) )
                unguarded( (: rmdir($(fn)) :) );
        }

        save();

        if( !sizeof(files) )
            remove_call_out(call_id);

        event( users(), "inform", "Autodoc: removing \""+
            fname+"\""+( !file_exists(fname) ? " (doesn't exist)" :
            "")+" from the autodoc handler", "autodoc");

        return 1;

    }

    if( TP )
        tell_object( TP, "There is no such file in the autodoc "
            "handler.\n");
    return 0;

} /* remove_file() */

private void save() {
    last_saved = time();
    unguarded( (: save_object( AUTODOC_SAVE_FILE ) :) );
    event( users(), "inform", "Saving the Autodoc handler.", "autodoc");
} /* save() */

/**
 * Returns the list of files we are current processing.
 * @return an array of strings being the file names
 */
string *query_files() { return files; }

/**
 * Returns the help mapping.  This is the mapping from function names to
 * files.  Each element in the mapping referes to an array of file
 * names which contain the function or define.
 * @return a mapping of arrays of files
 */
mapping query_help_map() { return help_map; }

/**
 * Returns the number of functions in the help file mapping.
 * @return the number of functions
 */
int query_help_map_size() { return sizeof(help_map); }

/**
 * This method returns the array of help files with the
 * specified function in it.
 * @param func the name of the function to get the help files for
 * @return array of file names
 */
string *query_help_on_func( string func ) { return help_map[func]; }

/**
 * This method returns the file name of the help for the specified
 * function in the specified file.
 * @param file the file name to find the help in
 * @param func the function to look for help on in the file
 * @return the full path to the help file, 0 if it does not exist
 */
string query_help_on( string file, string func ) {
    if( file[0] == '/' )
        file = file[1..];
    if( sscanf(file, "%*s.c") == 1 )
        file = file[0..<3];
    file = NROFF_DOC_SINGLE + file + "/" + func;
    if( file_size(file) > 0 )
        return file;
    return 0;
} /* query_help_on() */

/**
 * Returns the mapping of file names to a summary.  This is only
 * valid during the index creation cycle of the documentation generation
 * system.  It is used to create a more useful index page.
 * @return the mapping of file names to summarys
 */
mapping query_summary_map() { return summary_map; }

/**
 * This method tells us if the file is currently in the autodoc set.
 * @return 1 if the file is found, 0 if not
 */
int is_autodoc_file(string name) {
    return member_array( name, files ) != -1;
} /* is_autodoc_file() */

/** @ignore yes */
mixed stats() {
    string str;
    int next, to_go;

    next = SAVE_FILE_POS_INTERVAL + last_saved;
    to_go = next - time();

    if( to_go <= 0 )
        str = "any time now";
    else
        str = sprintf("%s (%s)", ctime(next), time_string( to_go, 2 ) );

    return ({
        ({"parsers in use", sizeof(in_use) || "none"}),
        ({"parsers recycled", sizeof(recycled) || "none"}),
        ({"number of files", sizeof(files) }),
        ({"help map size", sizeof(help_map) }),
        ({"something changed", something_changed ? "yes" : "no"}),
        ({"current file", files[file_pos] }),
        ({"last created index", ctime(last_created_index) }),
        ({"last saved", ctime(last_saved) }),
        ({"next saving", str }),
    });

} /* stats() */