/* Do not remove the headers from this file! see /USAGE for more info. */
#include <mudlib.h>
#include <driver/origin.h>
#include <security.h>
inherit M_ACCESS;
inherit M_INPUT;
inherit M_HISTORY;
inherit M_ALIAS;
inherit M_SHELLFUNCS;
inherit M_SAVE;
inherit M_SCROLLBACK;
private nosave object owner;
varargs void execute_command();
string query_shellname();
string query_save_path(string userid);
protected function arg_to_words_func = (: explode($1," ") :);
//### goofy fucking hack cuz the shell doesn't save for shit. only M_SAVE,
//### even though in the alias code it professes to "not require it to be
//### bound to M_SAVE" ... this is bunk...
private string save_info;
void setup_for_save()
{
/*
** This object has no variables to save, but many of the moduless do,
** so we must dispatch to them.
*/
alias::setup_for_save();
shellfuncs::setup_for_save();
}
void save_me()
{
if ( !owner ) /* probably the blueprint */
return;
setup_for_save();
save_info = save_to_string();
unguarded(1, (: save_object, query_save_path(owner->query_userid()) :));
}
protected void restore_me(string userid)
{
unguarded(1, (: restore_object, query_save_path(userid) :));
if ( save_info )
{
load_from_string(save_info, 0);
save_info = 0;
}
}
void remove()
{
if ( origin() != ORIGIN_LOCAL && owner && previous_object() != owner )
error("illegal attempt to remove shell object\n");
save_me();
destruct();
}
protected void shell_input(mixed input)
{
if ( input == -1 )
{
remove();
return;
}
/* we can safely remove leading and trailing whitespace */
input = trim_spaces(input);
if ( input == "" )
return;
/*
** ### WORK IN PROGRESS HERE
**
** Defined from the BASH shell
**
** Evaluation order:
** - history expansion
** - store in history
** - alias expansion
** - shell-defined expansion
** - TENTATIVELY: wish does: left-to-right: brace, tilde, parameter,
** variable, command, arithmetic, then word splitting, then
** pathname expansion
** - execution
**
** If the command uses parsed arguments (argv syntax), then the only
** expansion that can change the number of arguments are: brace
** expansion, word splitting, and pathname expansion. An exception
** is the expansion of $@.
*/
// is this history manipulation?
if ( input[0] == HISTORY_CHAR )
{
input = history_command(input);
if ( !input )
return;
}
add_history_item(input);
if ( input[0] == '\\' )
input = input[1..];
else
input = expand_alias(input);
if ( input != "" )
execute_command(input);
}
private void cmd_exit()
{
if(modal_stack_size() == 1)
{
//### I think we could just issue the quit command rather than force it
this_user()->force_me("quit");
return;
}
printf("Exiting %s\n", query_shellname());
modal_pop();
remove();
}
void create()
{
if ( !clonep() )
return;
owner = previous_object();
if ( owner != this_user() )
{
destruct();
error("illegal shell object creation\n");
}
if ( owner )
restore_me(owner->query_userid());
alias::create();
history::create();
}
/*
** This function is used internally to prepare a shell for operation.
** Subclasses will typically override to set up bindings and variables
** with shell_bind_if_undefined() or set_if_undefined(), respectively.
*/
protected void prepare_shell()
{
shell_bind_if_undefined("alias", (: cmd_alias :));
shell_bind_if_undefined("unalias", (: cmd_remove_alias($1,1) :));
shell_bind_if_undefined("history", (: cmd_history :));
shell_bind_if_undefined("scrollback", (: cmd_scrollback :));
// shell_bind_if_undefined("exit", (: cmd_exit :));
}
protected mixed what_prompt()
{
return "> ";
}
void start_shell()
{
if ( owner != this_user() || previous_object() != owner )
error("illegal attempt to take over shell\n");
modal_push((: shell_input :), what_prompt());
prepare_shell();
}
nomask object query_owner()
{
return owner;
}