tmi2_fluffos_v2/
tmi2_fluffos_v2/bin/
tmi2_fluffos_v2/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/ChangeLog.old/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/Win32/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/simuls/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/clone/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/command/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/data/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/master/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/log/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/compiler/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/efuns/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/operators/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/u/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/tmp/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/windows/
tmi2_fluffos_v2/lib/
tmi2_fluffos_v2/lib/adm/
tmi2_fluffos_v2/lib/adm/daemons/languages/
tmi2_fluffos_v2/lib/adm/daemons/network/I3/
tmi2_fluffos_v2/lib/adm/daemons/virtual/
tmi2_fluffos_v2/lib/adm/daemons/virtual/template/
tmi2_fluffos_v2/lib/adm/news/
tmi2_fluffos_v2/lib/adm/obj/
tmi2_fluffos_v2/lib/adm/obj/master/
tmi2_fluffos_v2/lib/adm/priv/
tmi2_fluffos_v2/lib/adm/shell/
tmi2_fluffos_v2/lib/adm/tmp/
tmi2_fluffos_v2/lib/cmds/
tmi2_fluffos_v2/lib/d/
tmi2_fluffos_v2/lib/d/Conf/
tmi2_fluffos_v2/lib/d/Conf/adm/
tmi2_fluffos_v2/lib/d/Conf/boards/
tmi2_fluffos_v2/lib/d/Conf/cmds/
tmi2_fluffos_v2/lib/d/Conf/data/
tmi2_fluffos_v2/lib/d/Conf/logs/
tmi2_fluffos_v2/lib/d/Conf/obj/
tmi2_fluffos_v2/lib/d/Conf/text/help/
tmi2_fluffos_v2/lib/d/Fooland/adm/
tmi2_fluffos_v2/lib/d/Fooland/data/
tmi2_fluffos_v2/lib/d/Fooland/data/attic/
tmi2_fluffos_v2/lib/d/Fooland/items/
tmi2_fluffos_v2/lib/d/TMI/
tmi2_fluffos_v2/lib/d/TMI/adm/
tmi2_fluffos_v2/lib/d/TMI/boards/
tmi2_fluffos_v2/lib/d/TMI/data/
tmi2_fluffos_v2/lib/d/TMI/rooms/
tmi2_fluffos_v2/lib/d/grid/
tmi2_fluffos_v2/lib/d/grid/adm/
tmi2_fluffos_v2/lib/d/grid/data/
tmi2_fluffos_v2/lib/d/std/
tmi2_fluffos_v2/lib/d/std/adm/
tmi2_fluffos_v2/lib/data/adm/
tmi2_fluffos_v2/lib/data/adm/daemons/
tmi2_fluffos_v2/lib/data/adm/daemons/doc_d/
tmi2_fluffos_v2/lib/data/adm/daemons/emoted/
tmi2_fluffos_v2/lib/data/adm/daemons/network/http/
tmi2_fluffos_v2/lib/data/adm/daemons/network/services/mail_q/
tmi2_fluffos_v2/lib/data/adm/daemons/network/smtp/
tmi2_fluffos_v2/lib/data/adm/daemons/news/archives/
tmi2_fluffos_v2/lib/data/attic/connection/
tmi2_fluffos_v2/lib/data/attic/user/
tmi2_fluffos_v2/lib/data/std/connection/b/
tmi2_fluffos_v2/lib/data/std/connection/l/
tmi2_fluffos_v2/lib/data/std/user/a/
tmi2_fluffos_v2/lib/data/std/user/b/
tmi2_fluffos_v2/lib/data/std/user/d/
tmi2_fluffos_v2/lib/data/std/user/f/
tmi2_fluffos_v2/lib/data/std/user/l/
tmi2_fluffos_v2/lib/data/std/user/x/
tmi2_fluffos_v2/lib/data/u/d/dm/working/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/smtp/
tmi2_fluffos_v2/lib/doc/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/interactive/
tmi2_fluffos_v2/lib/doc/driverdoc/concepts/
tmi2_fluffos_v2/lib/doc/driverdoc/driver/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/arrays/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/buffers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/compile/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/ed/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/filesystem/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/floats/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/functions/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/general/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/mappings/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/numbers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/parsing/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/constructs/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/preprocessor/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/types/
tmi2_fluffos_v2/lib/doc/driverdoc/platforms/
tmi2_fluffos_v2/lib/doc/mudlib/
tmi2_fluffos_v2/lib/ftp/
tmi2_fluffos_v2/lib/include/driver/
tmi2_fluffos_v2/lib/log/
tmi2_fluffos_v2/lib/log/driver/
tmi2_fluffos_v2/lib/obj/net/
tmi2_fluffos_v2/lib/obj/shells/
tmi2_fluffos_v2/lib/obj/tools/
tmi2_fluffos_v2/lib/std/adt/
tmi2_fluffos_v2/lib/std/board/
tmi2_fluffos_v2/lib/std/body/
tmi2_fluffos_v2/lib/std/fun/
tmi2_fluffos_v2/lib/std/living/
tmi2_fluffos_v2/lib/std/object/
tmi2_fluffos_v2/lib/std/shop/
tmi2_fluffos_v2/lib/std/socket/
tmi2_fluffos_v2/lib/std/user/
tmi2_fluffos_v2/lib/std/virtual/
tmi2_fluffos_v2/lib/student/
tmi2_fluffos_v2/lib/student/kalypso/
tmi2_fluffos_v2/lib/student/kalypso/armor/
tmi2_fluffos_v2/lib/student/kalypso/rooms/
tmi2_fluffos_v2/lib/student/kalypso/weapons/
tmi2_fluffos_v2/lib/u/l/leto/
tmi2_fluffos_v2/lib/u/l/leto/cmds/
tmi2_fluffos_v2/lib/www/errors/
tmi2_fluffos_v2/lib/www/gateways/
tmi2_fluffos_v2/lib/www/images/
tmi2_fluffos_v2/old/
tmi2_fluffos_v2/win32/
/*
// File:       hypertext.c
// Purpose:    a generic hypertext information storage device
// 93-07-25    Written by Douglas Reay (Pallando @ TMI-2)
//             The name "hypertext" is used in the sense of non-linear text,
//             a usage originating with Ted Nelson c1965.
//             See /obj/tools/memopad.c for an example of use.
// 93-08-28    Default option added by Pallando on idea by Grendel
// 93-09-17    Pallando changed option r to use more()
// 93-09-18    Pallando added version control and settable name of default item
// 93-09-19    Pallando made adding new item types easier
*/
#define HYPERTEXT_VERSION 930919

#include <uid.h>
#include <config.h>
#include <mudlib.h>

#define TEMP_FILE temp_file( query( "name" ) )

inherit OBJECT;

mapping data;
mapping options;
int hypertext_version;
static string index;
static string *history;

varargs int get_option( string option );

// Security.
int query_prevent_shadow() { return 1; }

// The previous object (the user) may read item <index>
varargs int valid_read( string arg )
{
    return 1;
}

// The previous object (the user) may alter item <index>
varargs int valid_write( string arg )
{
    return ( geteuid( this_object() ) != ROOT_UID ) &&
           ( geteuid( this_object() ) != "NONAME" );
}

// The file a particular user's copy of this object should save to.
string datafile()
{
    if( !previous_object() ) return TMP_DIR + query( "name" ) + "_noname";
    return TMP_DIR + query( "name" ) + "_" + geteuid( previous_object() );
}

int do_save()
{
    if( !valid_write() ) return 0;
    save_object( datafile() );
    return 1;
}

int remove()
{
    do_save();
    return ::remove();
}

void write_prompt()
{
    printf( "(%s) [%s] ", index, implode( keys( options ), "," ) );
}

void increment_history()
{
    if( query( "history" ) && ( index != history[0] ) )
        history = ( ({ index }) + history )[0..( query( "history" ) )];
}

// **************** START OF OPTIONS ******************* //

// Option: delete
// Effect: deletes item (arg)
varargs int option_d( string arg )
{
    // "sknil", you may notice, is "links" spelt backwards.
    mapping item, sknil, links;
    string *indexes, *names;
    int loop;

    if( !arg ) arg = index;
    if( arg == query( "home" ) )
    {
        write( "You may not delete the home item.\n" );
        return get_option();
    }
    if( !valid_write( arg ) )
    {
        write( "You may not alter item (" + arg + ")\n" );
        return get_option();
    }
    if( !mapp( item = data[arg] ) )
    {
        write( "There is no item (" + arg + ")\n" );
        return get_option();
    }
    if( arg == index ) index = query( "home" );
    increment_history();
    // Delete all links from this item.
    if( mapp( links = item["links"] ) &&
      ( loop = sizeof( names = keys( links ) ) ) )
        while( loop-- )
            if( mapp( data[links[names[loop]]] ) &&
              mapp( data[links[names[loop]]]["sknil"] ) )
                map_delete( data[links[names[loop]]]["sknil"], arg );
    // If other items have links to this item (the one to be deleted) then
    // delete this item from their links.
    if( mapp( sknil = item["sknil"] ) &&
      ( loop = sizeof( indexes = keys( sknil ) ) ) )
        while( loop-- )
            if( mapp( data[indexes[loop]] ) && 
              mapp( data[indexes[loop]]["links"] ) )
                map_delete( data[indexes[loop]]["links"],
                  sknil[indexes[loop]] );
    map_delete( data, arg );
    do_save();
    write( "Ok.\n" );
    return get_option();
}

// Option: edit
// Effect: create or alter an item
varargs int option_e( string arg )
{
    string filename, tmp;

    if( arg && ( sscanf( arg, "%s %s", tmp, filename ) == 2 ) )
    {
        if( !valid_write( tmp ) ) return get_option();
        filename = resolv_path( "cwd", filename );
        if( !file_exists( filename ) )
        {
            write( "There is no file called " + filename + "\n" );
            return get_option();
        }
        index = tmp;
        increment_history();
        if( !mapp( data[index] ) ) data[index] = ([ ]);
        data[index]["type"] = "file";
        data[index]["data"] = filename;
        data[index]["author"] = capitalize( geteuid( this_player() ) );
        data[index]["time"] = time();
        do_save();
        write( "Ok, item (" + index + ") is " + filename + "\n" );
        return get_option();
    }
    if( arg ) index = arg;
    if( !valid_write( index ) ) return get_option();
    increment_history();
    write( "Edit item (" + index + ")\n" );
    if( mapp( data[index] ) && 
        stringp( data[index]["data"] ) &&
        ( data[index]["type"] == "text" ) )
        write_file( TEMP_FILE, data[index]["data"] );
    this_player()-> edit( TEMP_FILE, "finish", this_object() );
    return 1;
}

// called by option_e if the body's edit() function is finished normally
void finish()
{
    mapping item;
    string text;

    text = read_file( TEMP_FILE );
    rm( TEMP_FILE );

    if( text )
    {
        if( !mapp( data[index] ) ) data[index] = ([ ]);
        data[index]["author"] = capitalize( geteuid( this_player() ) );
        data[index]["time"] = time();
        data[index]["data"] = text;
        data[index]["type"] = "text";
        write( "(" + index + ") changes saved.\n" );
    } else {
        write( "Changes not saved.  Use \"d\" if wish to delete item.\n" );
    }
    do_save();
    get_option();
}

// called by option_e if the body's edit() function is aborted
void abort()
{
    rm( TEMP_FILE );
    write( "Ok, edit abandoned.\n" );
    get_option();
}

// Option: help
// Effect: provides help on the hyper object and its functions.
varargs int option_h( string arg )
{
    if( arg )
    {
        if( query( "help/" + arg ) )
            write( query( "help/" + arg ) );
        else
            write( wrap( "Help is available on: " +
                implode( keys( query( "help" ) ), " " ) ) );
    } else {
        write( query( "help/options" ) );
    }
    return get_option();
}

// Option: index
// Effect: lists the indexes of all known items.
varargs int option_i( string arg )
{
    string *indexes;

    indexes = keys( data );
    if( arg )
    {
        indexes = regexp( indexes, arg );
        if( !sizeof( indexes ) )
        {
            write( "There are no indices matching the pattern " + arg + "\n" );
            return get_option();
        }
    }
    write( wrap( implode( indexes, "   " ) ) );
    return get_option();
}

// Option: unlink
// Effect: tries to remove a link {arg} from item (index)
//         If arg2 is passed (as when called by option_l) it is silent
varargs int option_u( string arg, int arg2 )
{
    mapping item, links;
    string indx;

    if( !arg )
    {
        write( "Syntax: u {name}\nEffect: unlinks the link {name}\n" );
        return get_option();
    }
    if( !mapp( item = data[index] ) || !mapp( links = item["links"] ) )
    {
        write( "(" + index + ") has no links.\n" );
        return get_option();
    }
    if( !( indx = links[arg] ) )
    {
        printf( "(%s) does not have a link {%s}\n", index, arg );
        return get_option();
    }
   if( mapp( data[indx] ) && mapp( data[indx]["sknil"] ) )
        map_delete( data[indx]["sknil"], index );
    map_delete( data[index]["links"], arg );
    if( arg2 ) return 1;
    printf( "Link {%s} to Item (%s) removed.\n", arg, indx );
    do_save();
    return get_option();
}

// Option: link
// Effect: makes a link from item <index>
varargs int option_l( string arg )
{
    int loop;
    mapping item, links;
    string indx, name, *names;

    if( arg )
    {
        if( !valid_write( index ) ) return get_option();
        if( sscanf( arg, "%s %s", name, indx ) != 2 )
        {
            write( "Syntax: l {name} (index)\n" );
            return get_option();
        }
        if( !mapp( data[indx] ) )
        {
            write( "You need to create item (" + indx + ") first.\n" );
            return get_option();
        }
        if( !mapp( data[index] ) ) data[index] = ([ ]);
        if( mapp( data[index]["links"] ) )
        {
            if( data[index]["links"][name] )
                option_u( name );
            data[index]["links"][name] = indx;
        } else {
            data[index]["links"] = ([ name : indx ]);
        }
        if( mapp( data[indx]["sknil"] ) )
            data[indx]["sknil"][index] = name;
        else
            data[indx]["sknil"] = ([ index : name]);
        write( "Ok.\n" );
        do_save();
        return get_option();
    }
    if( !mapp( item = data[index] ) || !mapp( links = item["links"] ) ||
      !( loop = sizeof( names = keys( links ) ) ) )
    {
        write( "Item " + index + " is not linked to any other items.\n" );
        return get_option();
    }
    write( "Item (" + index + ") has the links:\n" );
    printf( "%-15s\t%s\n", "{name}", "(index)" );
    while( loop-- ) printf( "%-15s\t%s\n", names[loop], links[names[loop]] );
    return get_option();
}

// Option: read
// Effect: displays item (arg)
varargs int option_r( string arg )
{
    string indx;
    mapping item;
    mixed more_data;

    if( !arg ) arg = index;
    item = data[arg];
    if( undefinedp( item ) )
    {
        write( "There is no item (" + arg + ")\n" );
        return get_option();
    }
    if( !valid_read( arg ) )
    {
        write( "Yoy may not read (" + arg + ")\n" );
        return get_option();
    }
    switch( item["type"] )
    {
        case "file":
        {
            write( "(" + arg + ") " + item["data"] + "\n" );
            more_data = item["data"];
            break;
        }
        case "text":
        {
            write( "(" + arg + ") by " + item["author"] +
                " at " + ctime( item["time"] ) + "\n" );
            more_data = explode( item["data"], "\n" );
            break;
        }
        default:
        {
            if( !stringp( item["type"] ) )
                write( "Error in item: no type.\n" );
            else
            if( !call_other( this_object(), "read_" + item["type"], arg ) )
                write( "Unknown data type: " + item["type"] + "\n" );
            return get_option();
        }
    }
    indx = index;
    index = arg;
    if( (int)this_player()-> more( more_data ) )
    {
        return 1;
    } else {
        index = indx;
        this_object()-> done_more();
        return 0;
    }
}

void done_more()
{
    mapping item, links;
    string *names;

    item = data[index];
    if( query( "show_links" ) && mapp( links = item["links"] ) &&
      sizeof( names = keys( links ) ) )
    {
        write( wrap( "Links: " + implode( names, "," ) ) );
    }
    increment_history();
    get_option();
}

// Option: previous
// Effect: lists previous items visited (ie a history function)
//         if integer <arg> is specified, if goes back to that item
varargs int option_p( string arg )
{
    int loop;

    if( arg )
    {
        if( sscanf( arg, "%d", loop ) )
        {
            if( ( loop < sizeof( history ) ) && history[loop] )
                return option_r( history[loop] );
            else
                write( "Your history doesn't go back that far.\n" );
        } else write( arg + " is not a number.\n" );
    } else write( "Item index history:\n" );
    for( loop = 0 ; history[loop] ; loop++ )
        printf( "%3d  %s\n", loop, history[loop] );
    return get_option();
}

// Option: quit
// Effect: only option not to do a return get_option()
varargs int option_q( string arg )
{
    write( "Ok.\n" );
    return 1;
}

// ****************** END OF OPTIONS ********************** //

varargs int get_option( string option )
{
    string tmp, arg;

    if( option == "" )
    {
        if( mapp( data[index] ) && mapp( data[index]["links"] ) &&
          stringp( data[index]["links"]["default"] ) )
        {
            if( data[index]["links"]["default"] != index )
                return option_r( data[index]["links"]["default"] );
        } else if( ( index != query( "default" ) ) &&
          mapp( data[query( "default" )] )     )
            return option_r( query( "default" ) );
    }
    if( !option || option == "" )
    {
        write_prompt();
        input_to( "get_option" );
        return 1;
    }

    if( sscanf( option, "%s %s", tmp, arg ) ) option = tmp;
    if( options[option] )
        return (int)call_other( this_object(), options[option], arg );
    if( arg )
    {
        write( "You may not specify \"" + option + "\" with an argument.\n" );
        return get_option();
    }
    if( mapp( data[index] ) && mapp( data[index]["links"] ) &&
      data[index]["links"][option] )
        return option_r( data[index]["links"][option] );
    return option_r( option );
}
        
int cmd_start( string arg )
{
    if( stringp( arg ) && data[arg] )
        return option_r( arg );
    return option_r( query( "home" ) );
}

void init()
{
    add_action( "cmd_start", query( "start" ) );
}

void set_up()
{
    options = ([
        "d" : "option_d",
        "e" : "option_e",
        "h" : "option_h",
        "i" : "option_i",
        "l" : "option_l",
        "p" : "option_p",
        "q" : "option_q",
        "r" : "option_r",
        "u" : "option_u",
    ]);
    set( "help/options", @EndText
HELP PAGE                                                   HELP PAGE
              Help on interactive hypertext options
This object contains a collection of text items, either as variables
in the object or as references to files in the mudlib.
Each item has an index - shown in () - a string with no spaces
such as "longsword", "12.4", "item1", "driver/bugs" or whatever
naming scheme you chose.
Items may have links - shown in {} - to other items.
Option:
EndText
+ @EndText
 l         - list the links from the current item.
 l {name} (index) - links the current item to item (index)
             typing "{name}" at the prompt will take you to the linked item.
 (index)   - displays item (index).
 r (index) - displays item (index).  Typing "r" will display the current item.
 e (index) - edit item (index).  Typing "e" will edit the current item.
 e (index) <filename> - set item (index) to refer to the file <filename>
 h         - help (this message)
 q         - quit
 i <pattern> - show all items who indexes match <pattern>
 p         - a history command.  display the indexes of your previous items.
 p <n>     - go to the <n>'th item in the history list.
 d (index) - deletes item (index)
 u {name}  - deletes the link {name}
EndText
    );
    set( "id", ({ "hypertext", "hypereader" }) );
    set( "name", "hypereader" );
    set( "home", "start" );
    set( "start", "hyper" );
    set( "default", "default" );
    set( "history", 20 );
    hypertext_version = HYPERTEXT_VERSION;
}

void check_version()
{
    string *indexes;
    int loop;

    if( hypertext_version == HYPERTEXT_VERSION ) return;
    if( stringp( hypertext_version ) )
        sscanf( hypertext_version, "%d", hypertext_version );
    if( hypertext_version < 930918 )
    {
        set( "default", "default" );
    }
    if( hypertext_version < 930919 )
    {
        loop = sizeof( indexes = keys( data ) );
        while( loop-- )
        {
            if( undefinedp( data[indexes[loop]]["filename"] ) )
            {
                data[indexes[loop]]["type"] = "text";
                data[indexes[loop]]["data"] = data[indexes[loop]]["text"];
                map_delete( data[indexes[loop]], "text" );
            } else {
                data[indexes[loop]]["type"] = "file";
                data[indexes[loop]]["data"] = data[indexes[loop]]["filename"];
                map_delete( data[indexes[loop]], "filename" );
            }
        }
    }
    hypertext_version = HYPERTEXT_VERSION;
    do_save();
}

// It is up to the inheriting object to ensure that a wizard can't clone this
// if they shouldn't have write access to the datafile
void create()
{
    data = ([ ]);
    set_up();
    if( !geteuid( this_object() ) )
        seteuid( ROOT_UID );
    if( !geteuid( this_object() ) )
        seteuid( getuid() );
    restore_object( datafile() );
    if( query( "history" ) )
        history = allocate( query( "history" ) + 2 );
    check_version();
}