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/
#define MAX_SIZE 50000
#define LOG_NAME(X) ((X[0] == '/') ? X : "/log/"+X)
// This define figures out the filename to log to.

#include <config.h>
#include <type.h>

#if !efun_defined(base_name)
inherit "/secure/simul_efun/base_name";
#endif
#if !efun_defined(reference_allowed)
inherit "/secure/simul_efun/reference_allowed";
#endif

string back_trace();

#if !efun_defined(event)
void event(mixed,string,mixed ...);
#endif

#if !efun_defined(add_action)
int _notify_fail(string);
int living(object ob);
object find_player(string);
#endif

private nosave int _callouttime;
private nosave mapping _calloutfunc = ([]);
private nosave mapping _log_file_info = ([ ]);
private nosave mapping _db_fds = ([ ]);
private nosave mapping _db_obs = ([ ]);
private nosave int _log_file_flush_id;

// Every 5 seconds.
#define DELAY_LOG_FLUSH 5

/**
 * Contains some simul_efuns.
 * @author Pinkfish
 */
/** @ignore yes */
varargs void say( string str, mixed avoid ) {
    if( !pointerp(avoid) ) {
        avoid = ({ TP, PO }) + ({ avoid });
    } else {
        avoid += ({ TP, PO });
    }

    if( !ENV(PO) ) {
        event( ( TP && ENV(TP) ? ENV(TP) : PO ), "say", str, avoid );
    } else {
        event( ( ENV(ENV(PO)) ? ENV(ENV(PO)) : ENV(PO) ), "say", str, avoid );
    }
} /* say()*/

/** @ignore yes */
varargs void tell_room( object ob, string str, mixed avoid ) {
    if( objectp(ob) ) {
        event( ob, "say", str, avoid );
        return;
    }

    if( PO && !ENV(PO) )
        return; // most likely an inherit, don't error.

    error("Specified room doesn't exist, or isn't an object.\n");

} /* tell_room() */

/** @ignore yes */
void tell_object( object ob, string str ) {
    if( objectp(ob) ) {
        ob->do_efun_write( str );
        return;
    }

    error("Specified object doesn't exist, or isn't an object.\n");

} /* tell_object() */

/** @ignore yes */
object find_living( string word ) {
    object thing;

    if( !word )
        return 0;

#if efun_defined(find_living)
    thing = efun::find_living( word );
#else
    thing = LIVING_H->find_living( word );
#endif

    if( !thing || !TP )
        return thing;

    if( reference_allowed( thing, TP ) )
        return thing;

    return 0;

} /* find_living() */

/** @ignore yes */
object find_player( string word ) {
    object thing;

    if( !word )
        return 0;

#if efun_defined(find_player)
    thing = efun::find_player( word );
#else
    thing = LIVING_H->find_player( word );
#endif

    if( !thing || !TP )
        return thing;

    if( reference_allowed( thing, TP ) )
        return thing;

    return 0;

} /* find_player() */

/** @ignore yes */
object *users() {
    if( !TP || PO == master() )
        return efun::users();

    return filter( efun::users(), (: reference_allowed( $1, $2 ) :), TP );

} /* users() */

/** @ignore yes */
object *named_livings() {
#if efun_defined(named_livings)
    if( !TP )
        return efun::named_livings();
    return filter( efun::named_livings(),
        (: reference_allowed( $1, $2 ) :), TP );
#else
    if( !TP )
        return LIVING_H->named_livings();
    return filter( LIVING_H->named_livings(),
        (: reference_allowed( $1, $2 ) :), TP );
#endif
} /* named_livings() */

/** @ignore yes */
object *livings() {
#if efun_defined(livings)
    if( !TP )
        return efun::livings();
    return filter( efun::livings(), (: reference_allowed( $1, $2 ) :), TP );
#else
    if( !TP )
        return efun::objects( (: living($1) :) );
    return efun::objects( (: living($1) && reference_allowed( $1, $(TP)) :) );
#endif
} /* named_livings() */

/** @ignore yes */
object *children( string name ) {
    if( strsrch( name, "global/creator") != -1 && TP )
        return filter( efun::children(name),
            (: reference_allowed( $1, $2 ) :), TP );

    return efun::children(name);

} /* children() */

/**
 * This method calls an event on all the users online.
 * It does not do any filtering, so it will send messages to people who
 * are earmuffed and ignoring or lord invisible or whatever.
 *
 * @param from the person it is from
 * @param name the name of the event
 * @param args the arguments to the event
 */
void user_event( mixed from, mixed first, mixed args ... ) {
    if( stringp( from ) )
        call_other( efun::users(), "event_"+from, PO, first, args ... );
    else if( objectp( from ) && stringp( first ) )
        call_other( efun::users(), "event_"+first, from, args ... );
} /* user_event() */

mixed unguarded( function f );

/**
 * This method flushes out all the buffered stuff for the log files.
 */
private void flush_log_files() {
    string fname, data;

    _log_file_flush_id = 0;
    foreach( fname, data in _log_file_info ) {
        if( file_size( LOG_NAME(fname) ) > MAX_SIZE ) {
            unguarded( (: rm, LOG_NAME(fname)+".old" :) );
            unguarded( (: rename, LOG_NAME(fname), LOG_NAME(fname)+".old" :) );
        }
        map_delete( _log_file_info, fname );
        unguarded( (: write_file, LOG_NAME(fname), data :) );
    }

    _log_file_info = ([ ]);

} /* flush_log_files() */

/**
 * This method writes a message out to a log file.  The log files are
 * normally in "/log".  If a file doesn't start with '/ then "/log/" will be
 * prepended to it.
 * This does automatic removal of the log files after they get over
 * a certain length.  The fmt and args parameters are used to print the
 * actual message.
 * <p>
 * If more than one argument is passed to this function, then sprintf will
 * be used to print out the results.
 * <p>
 * ie: log_file("ROGER", "%s: frog and %s\n", ctime(time()), query_gumboot());
 *
 * @param name the name of the log file
 * @param fmt the format string
 * @param args the arguments to the sprintf
 */
varargs void log_file(string name, string fmt, mixed *args ...) {
    /* five screens */
    if( strlen( fmt ) > 8000 )
        fmt = fmt[ 0 .. 7999 ] +"\n\nPlus more...\n\n";

    fmt = terminal_colour( fmt, ([ ]) );

    if( !_log_file_flush_id )
        _log_file_flush_id = call_out((: flush_log_files :), DELAY_LOG_FLUSH);

    if( !_log_file_info[name] )
        _log_file_info[name] = "";

    _log_file_info[name] += ( sizeof(args) ? sprintf( fmt, args ... ) : fmt );

} /* log_file() */

#if !efun_defined(mud_name)
#ifndef MUD_NAME
#define MUD_NAME "Broken Mud Name"
#endif
/**
 * This method returns the name of the mud.
 * @return the name of the mud
 */
string mud_name() { return MUD_NAME; }
#endif

/**
 * Write the file out to the screen.  This should  not be used if possible.
 * It is an interface to read_file and other things.  You should perhaps
 * look at using more_string ort more_file.
 *
 * @param file the file name to cat
 * @param start_line the line to start on
 * @param number the number of lines to print
 *
 * @see /global/more_string->more_string()
 * @see /global/more_file->more_file()
 */
void cat( string file, int start_line, int number ) {
    string bing;

    if( bing = read_file( file, start_line, number ) )
        printf("%s", bing );

//        printf("%s", bing[0..5000] );

} /* cat() */

#ifdef NEW_DRIVER
/**
 * This method tells us if the object is a wizard.
 * @return is the object a wizard
 */
int wizardp(mixed arg) {
    if( !objectp(arg) )
        return 0;

    return interactive(arg) && TO->creatorp(arg);

} /* wizardp() */
#endif

/** @ignore yes */
int exec( object to, object from ) {
    string s;
    object prev;

    if( file_name(PO)[0..12] == "/secure/login")
        return efun::exec( to, from );

    s = "";

    if( prev = TP )
        s += "TP:"+ sprintf("%8s ", prev->query_name() );

    if( prev = this_player(1) )
        s += "TP1:"+ sprintf("%8s ", prev->query_name() );

    s += "PO:"+ sprintf("%8s ", file_name( PO ) );

    log_file("ILLEGAL", "Exec: %-40s : %s\n", s, ctime( time() ) );
    return 0;

} /* exec() */

/** @ignore yes */
varargs int call_out( mixed fun, int delay, mixed *args ... ) {
    string func;

    if( _callouttime != time() ) {
        _callouttime = time();
        _calloutfunc = ([ ]);
    }

    if( delay == 0 ) {
        func = functionp(fun) ? "" + functionp(fun) : fun + file_name( PO );
        if( ++_calloutfunc[func] > 100 ) {
            delay = 2;
            log_file("CALL_OUT_LOG", ctime(time())+": Object %O (%s) seems "
                "to loop in function %O.\n", PO, ( stringp(PO->query_name()) ?
                PO->query_name() : file_name(PO) ), fun );
        }
    }

    return evaluate( bind(
        (: efun::call_out( $(fun), $(delay), $(args) ... ) :), PO ) );

} /* call_out() */

/**
 * This returns the current verb name.  This works if the verb ius used
 * through add_command or through add_action.
 * @return the name of the verb
 */
string query_verb() {
    string verb;

#if efun_defined(query_verb)
    verb = efun::query_verb();
#else
    verb = "";
#endif

    return ( verb != "" || !objectp( TP ) ? verb :
            (string)TP->query_current_verb() );

} /* query_verb() */

/**
 * Does a string compare...  But case insensitive...
 * @param str1 the string to compare
 * @param str2 the other string to compare
 * @return 0 if they are the same, <0 if they are less than each other, >0 if not
 * @see efun::strcmp()
 */
int strcasecmp( string str1, string str2 ) {
    return strcmp( lower_case(str1), lower_case(str2) );
} /* strcasecmp() */

#define COMPAT_TAIL
#ifdef COMPAT_TAIL
/* This version is strictly compatible with the old version */
/**
 * This will print the last bit of a file.
 * @param fname the file to read
 * @return 1 if it succeeded, 0 if it failed
 */
int tail(string fname) {
    int offset;
    string str;

    offset = file_size(fname);

    if( offset < 0 )
        return 0;

    offset -= 54 * 20;

    if( offset < 0 )
        offset = 0;

    if( !str = read_bytes( fname, offset, 1080 ) )
        return 0;

    if( offset )
        str = str[strsrch( str, "\n")+1..];

    write(str);
    return 1;

} /* tail() */
#else
/* This version is slightly extended and compatible in spirit, but doesn't
 * reproduce the oddities of the original tail() efun.  Note that it also
 * returns the string, so write(tail(fname)) is needed for strict
 * compatibility.
 */
/**
 * This will print the last bit of a file.
 * @param fname the file to read
 * @return 1 if it succeeded, 0 if it failed
 */
varargs string tail( string fname, int nlines ) {
    int chunk, offset, num_nl, p, skip;
    string str;

    chunk = nlines * 80;
    offset = file_size(fname);
    str = "";

    reset_eval_cost();

    while( offset > 0 && num_nl <= nlines ) {
        num_nl = 0;
        offset -= chunk;

        /* negative */
        if( offset < 0 ) {
            chunk += offset;
            offset = 0;
        }
        str = read_bytes( fname, offset, chunk ) + str;
        p = -1;
        while( p < sizeof(str)-1 && p = member_array('\n', str, p+1 ) )
            num_nl++;
    }

    skip = num_nl - nlines;
    p = -1;

    while( skip-- )
        p = member_array('\n', str, p+1 );

    return str[p..];

} /* tail() */
#endif

/** @ignore yes */
void write( mixed str ) {
    if( !TP )
        return;

    if( intp(str) )
        str = "" + str;

    TP->do_efun_write(str);

} /* write() */

/** @ignore yes */
int notify_fail( mixed stuff ) {
    if( functionp( stuff ) )
        stuff = evaluate( stuff );

    if( !stringp( stuff ) )
        return 0;

    TP->print_messages();

    /* for observer-dependent shorts */
    stuff = (string)TP->convert_message( stuff );
    /* for capitalisation and indentation */
    stuff = (string)TP->fit_message( stuff );
    /* for colour */
    stuff = (string)TP->fix_string( stuff );

#if efun_defined(notify_fail)
    return efun::notify_fail( stuff );
#else
    return _notify_fail( stuff );
#endif

} /* notify_fail() */

/**
 * Replaces all occurances of a set of strings in the input string.  Replaces
 * an individual or an array of strings with new values.  If the second
 * argument is an array of strings, then the 1st, 3rd, 5th...  elements will
 * be the strings to search for and the 2nd, 4th, 6th etc will be the strings
 * to replace with.  If three arguments are specified then the second is the string
 * to search for, the third the one to replace.
 * <p>
 * Eg:<br>
 * str = replace(str, ({ "search", "replace", "orange", "apple" });<p>
 * That will replace all occurances of "search" with "replace" and "orange"
 * with "apple".
 *
 * @param str the string to do the replacement in
 * @param bing the search or array argument
 * @param rep the replacement string, or null
 *
 * @return the string with all the replacements done
 */
varargs string replace( string str, mixed bing, string rep ) {
    int i;

    if( pointerp(bing) ) {
        for( i = 0; i < sizeof(bing); i += 2 ) {
            if( stringp(bing[i]) && stringp(bing[i+1]) )
                str = replace_string( str, bing[i], bing[i+1] );
        }
        return str;
    }

    return ( !stringp(str) || !stringp(rep) ? str :
             replace_string( str, bing, rep ) );

} /* replace() */

#if !efun_defined(uniq_array)
/**
 * This method will return an array that contains no duplicates.
 * Written by: Wodan
 * <p>
 * This function will return an array that contains no duplicates.
 * Gotta love them mappings. :)
 * @param arr the array to convert
 * @return an array with no duplicates
 */
mixed uniq_array( mixed arr ) { return keys( allocate_mapping( arr, 1 ) ); }
#endif

#if !efun_defined(distinct_array)
/**
 * This method removes any duplicates from an array while keeping
 * the order intact, this is more costly than uniq_array, so if the
 * order isn't important to you, don't use it, use uniq_array instead.
 * @param arr the array to remove duplicates from
 * @return the new array with no duplicates
 */
mixed distinct_array( mixed arr ) {
    mixed new_arr, tmp;

    new_arr = ({ });

    foreach( tmp in arr )
      if( member_array( tmp, new_arr ) == -1 )
          new_arr += ({ tmp });

    return new_arr;

} /* distinct_array() */
#endif

/**
 * This method sends a polite shout to everyone on line.  It checks
 * for earmuffs and all that sort of stuff.
 * @param words the message to shout
 * @param avoid who not to tell the message to
 */
varargs void shout( string words, object avoid ) {
    object thing, *things;

    things = efun::users();

    foreach( thing in things ) {
        if( thing && thing != avoid && thing != TP &&
            !thing->check_earmuffs("shout") )
            thing->event_say( PO, words, ({ }) );
    }

} /* shout() */

/** @ignore yes */
int reset_eval_cost() { return efun::reset_eval_cost(); }

/** @ignore yes */
int eval_cost() { return efun::eval_cost(); }

/** @ignore yes */
int set_eval_limit() { return efun::set_eval_limit(0); }

#if !efun_defined(event)
/** @ignore yes */
varargs int member_array( mixed item, mixed arr, int start, int flag ) {
    if( !flag )
        return efun::member_array( item, arr, start );

    if( stringp(item) )
        return efun::member_array( item, map( arr,
            (: $1[0..$(strlen(item)-1)] :) ), start );

} /* member_array() */

/** @ignore yes */
void event( mixed ob, string func, mixed rest ... ) {
    string name = "event_"+func;
    object origin = PO;

    if( arrayp(ob) ) {
        call_other( ob - ({ 0 }), name, origin, rest ... );
        return;
    }

    if( objectp(ob) ) {
        call_other( ob, name, origin, rest ... );
        call_other( INV(ob) - ({ 0, origin }), name, origin, rest ... );
    }

} /* event() */
#endif

#if !efun_defined(add_action)
/** @ignore yes */
void move_object( mixed dest ) {
    object tp, *obs, ob;

    if( stringp(dest) )
        dest = find_object(dest);

    evaluate( bind( (: efun::move_object( $(dest) ) :), PO ) );

    if( dest->no_init() )
        return;

    tp = TP;
    obs = INV(dest) - ({ PO });

    if( living(PO) ) {
        set_this_player(PO);
        dest->init();
        foreach( ob in obs )
            ob->init();
    }

    obs = filter( obs, (: living($1) :) );

    foreach( ob in obs ) {
        set_this_player(ob);
        PO->init();
    }

    if( living(dest) ) {
        set_this_player(dest);
        PO->init();
    }

    set_this_player(tp);

} /* move_object() */
#endif

#if efun_defined(db_exec)
/** @ignore yes */
varargs mixed db_exec( int fd, string fmt, mixed *args ... ) {
    _db_fds[fd] = time();
    if( !sizeof(args) )
        return efun::db_exec( fd, fmt );
    else
        return efun::db_exec( fd, sprintf( fmt, args ... ) );
} /* db_exec() */

/** @ignore yes */
varargs int db_connect( mixed args ... ) {
    int fd, i;
    string ob;

    ob = file_name(PO);

    switch( sizeof(args) ) {
      case 0..1:
        error("Not enough arguments to db_connect.");
      case 2:
        fd = efun::db_connect( args[0], args[1], CONFIG_DB_USER );
      break;
      case 3:
        fd = efun::db_connect( args[0], args[1], args[2] );
      break;
      default:
        error("Too many arguments to db_connect.");
    }

    _db_fds[fd] = time();
    _db_obs[fd] = ob;

    i = sizeof( keys( filter( _db_obs, (: $2 == $3 :), ob ) ) );

    if( i > 3 )
        log_file("FDS", "%s - %s: %i fds.\n", ctime(time()), ob, i );

    return fd;

} /* db_connect() */

/** @ignore yes */
mixed db_fetch( int fd, int row ) {
    _db_fds[fd] = time();
    return efun::db_fetch( fd, row );
} /* db_fetch() */

/** @ignore yes */
void db_close( int fd ) {
    map_delete( _db_fds, fd );
    map_delete( _db_obs, fd );
    efun::db_close(fd);
} /* db_close() */

/** @ignore yes */
string db_fds() {
    int *fds;

    fds = keys(_db_fds);

    return implode( fds, (: $1 + sprintf("FD: %d   Time: %s   Object: %s%s\n",
        $2, ctime( $(_db_fds)[$2] ), $(_db_obs)[$2],
        ( find_object($(_db_obs)[$2]) ? "" : "(destructed)" ) ) :), "");

} /* db_fds() */

#else
/** @ignore yes */
varargs int db_connect( mixed *args ... ) {
    error("No database installed.");
} /* db_connect() */

/** @ignore yes */
varargs string db_exec( int fd, string fmt, mixed *args ... ) {
    return "No database installed";
} /* db_exec() */

/** @ignore yes */
mixed db_fetch( int fd, int row ) {
    error("No database installed.");
} /* db_fetch() */

/** @ignore yes */
void db_close( int fd ) { }
#endif

/** @ignore yes */
void shutdown( int bing ) {
    if( PO != find_object(SHUTDOWN_H) && !TO->adminp(PO) ) {
        unguarded( (: write_file, "/secure/log/SHUTDOWN",
            sprintf("value %d\n%s", bing, back_trace() ) :) );
    }

    efun::shutdown(bing);

} /* shutdown() */

/** @ignore yes */
#if !efun_defined(real_time)
int real_time() { return time(); }
#endif

#if !efun_defined(choice)
/**
 * This method returns a random member of the specified array.
 * @param options the array to return a random member from
 * @return a random member of the specified array
 */
mixed choice( mixed options ) {
    mixed k;

    switch( typeof(options) ) {
      case STRING:
        return options[random(strlen(options))];
      case ARRAY:
        return options[random(sizeof(options))];
      case MAPPING:
        k = keys(options);
        return options[k[random(sizeof(k))]];
      default:
        error("Cannot use choice() on that type of input.");
      return 0;
    }
} /* choice() */
#endif

/** @ignore yes */
mixed asort( mixed strlist ) {
    return sort_array( strlist, (: strcmp( $1, $2 ) :) );
} /* asort() */

/** @ignore yes */
int interactive( object ob ) {
    if( objectp(ob) )
        return efun::interactive(ob);
    return 0;
} /* interactive() */

/** @ignore yes */
string pluralize( string str ) {
    mapping exceptions;

    exceptions = (["lotus"  : "lotuses",
                   "coif"   : "coifs",
                   "roof"   : "roofs",
                   "cliff"  : "cliffs",
                   "bacterium" : "bacteria",
                   "plus"   : "pluses",
                   "memo"   : "memos",
                   "studio" : "studios",
                   "folio"  : "folios",
                   ]);

    return exceptions[str] || efun::pluralize(str);

} /* pluralize() */

#if !efun_defined(verbalize)
/**
 * This method does $V$0=verbs,verb$V$ expansion on a word.
 * It does this by pluralizing the verb used.
 * If the optional single person argument is supplied,
 * then that is used for the single person version of the
 * word, and the verb argument is used for multiple people.
 * @param verb the verb to do the expansion on
 * @param single the optional singular argument
 * @return $V$0=verbs,verb$V$ expanded verb
 * @example verbalize("their", "his") returns $V$0=his,their+"$V$
 * @example verbalize("run") returns $V$0=runs,run+"$V$
 */
varargs string verbalize( string verb, string single ) {
    return "$V$0="+( single ? single : pluralize(verb) )+","+verb+"$V$";
} /* verbalize() */
#endif

#if !efun_defined(query_shadows)
/**
 * This method returns all the objects that are shadowing the input object.
 * @param ob the object to get the shadows list for
 * @return the objects shadowing us, or 0 if none are found
 * @author Sandoz
 */
object *query_shadows( object ob ) {
    object *obs, tmp;

    if( tmp = shadow( ob, 0 ) ) {
        obs = ({ ob = tmp });

        while( tmp = shadow( ob, 0 ) )
            obs += ({ ob = tmp });

        return obs;
    }

    return 0;

} /* query_shadows() */
#endif

#if !efun_defined(query_prime)
/**
 * This method queries whether the input number is a prime.
 * @param num the number to test for primeness
 * @return 1 if the number is a prime, 0 if not
 * @author Sandoz & Windy
 */
int query_prime( int num  ) {
    for( int div = 2; div <= num / 2; div++ )
        if( !( num % div ) )
            return 0;

    return 1;

} /* f_query_prime() */
#endif

/** @ignore yes */
string debug_info( int flag, object ob ) {
    if( flag == 2 && !TO->adminp( previous_object(-1) ) ) {
        write("Sorry, that is an admin only option.\n");
        return 0;
    }

    return efun::debug_info( flag, ob );

} /* debug_info() */

/** @ignore yes */
int memory_summary() { return 0; }